Patch #18462: Fisheye (Dome) and Spherical Panoramic mode in BGE.

User guide:
http://wiki.blender.org/index.php/Dev:Source/GameEngine/Fisheye_Dome_Camera

Fixed two bugs from original patch:
- deleting a text will clear the warp field from Game framing settings
- removed spurious black dots along the edge of the cube map in the gameplayer 

Known limitation:
- resizing of the screen doesn't work in the gameplayer

Known bugs:
- Texture with reflexion are not rendered correctly
- Spurious problems with light
This commit is contained in:
Benoit Bolsee
2009-04-08 15:06:20 +00:00
parent 4b77f9504c
commit 2074128fad
16 changed files with 2227 additions and 9 deletions

View File

@@ -41,7 +41,7 @@ struct ListBase;
struct MemFile;
#define BLENDER_VERSION 248
#define BLENDER_SUBVERSION 3
#define BLENDER_SUBVERSION 4
#define BLENDER_MINVERSION 245
#define BLENDER_MINSUBVERSION 15

View File

@@ -86,5 +86,7 @@ int get_render_child_particle_number(struct RenderData *r, int num);
int get_render_shadow_samples(struct RenderData *r, int samples);
float get_render_aosss_error(struct RenderData *r, float error);
void free_dome_warp_text(struct Text *txt);
#endif

View File

@@ -230,6 +230,11 @@ Scene *add_scene(char *name)
sce->r.threads= 1;
sce->r.stereomode = 1; // no stereo
sce->r.domeangle = 180;
sce->r.domemode = 1;
sce->r.domesize = 1.0f;
sce->r.domeres = 4;
sce->r.domeresbuf = 1.0f;
sce->r.simplify_subsurf= 6;
sce->r.simplify_particles= 1.0f;
@@ -775,3 +780,14 @@ float get_render_aosss_error(RenderData *r, float error)
return error;
}
void free_dome_warp_text(struct Text *txt)
{
Scene *scene;
scene = G.main->scene.first;
while(scene) {
if (scene->r.dometext == txt)
scene->r.dometext = NULL;
scene = scene->id.next;
}
}

View File

@@ -3531,7 +3531,9 @@ static void lib_link_scene(FileData *fd, Main *main)
srl->mat_override= newlibadr_us(fd, sce->id.lib, srl->mat_override);
srl->light_override= newlibadr_us(fd, sce->id.lib, srl->light_override);
}
/*Game Settings: Dome Warp Text*/
sce->r.dometext= newlibadr_us(fd, sce->id.lib, sce->r.dometext);
sce->id.flag -= LIB_NEEDLINK;
}
@@ -8035,6 +8037,24 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
if (main->versionfile < 248 || (main->versionfile == 248 && main->subversionfile < 4)) {
Scene *sce;
World *wrld;
/* Dome (Fisheye) default parameters */
for (sce= main->scene.first; sce; sce= sce->id.next) {
sce->r.domeangle = 180;
sce->r.domemode = 1;
sce->r.domesize = 1.0f;
sce->r.domeres = 4;
sce->r.domeresbuf = 1.0f;
}
/* DBVT culling by default */
for(wrld=main->world.first; wrld; wrld= wrld->id.next) {
wrld->mode |= WO_DBVT_CAMERA_CULLING;
}
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */
@@ -8841,7 +8861,9 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
expand_doit(fd, mainvar, srl->mat_override);
expand_doit(fd, mainvar, srl->light_override);
}
if(sce->r.dometext)
expand_doit(fd, mainvar, sce->r.dometext);
}
static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)

View File

@@ -45,6 +45,7 @@ struct World;
struct Scene;
struct Image;
struct Group;
struct Text;
struct bNodeTree;
typedef struct Base {
@@ -314,6 +315,14 @@ typedef struct RenderData {
/* jpeg2000 */
short jp2_preset, jp2_depth;
int rpad3;
/* Dome variables */
short domeres, domemode;
short domeangle, pad9;
float domesize;
float domeresbuf;
struct Text *dometext;
} RenderData;
/* control render convert and shading engine */

View File

@@ -1766,13 +1766,13 @@ static uiBlock *edge_render_menu(void *arg_unused)
static uiBlock *framing_render_menu(void *arg_unused)
{
uiBlock *block;
short yco = 190, xco = 0;
short yco = 267, xco = 0;
int randomcolorindex = 1234;
block= uiNewBlock(&curarea->uiblocks, "framing_options", UI_EMBOSS, UI_HELV, curarea->win);
/* use this for a fake extra empy space around the buttons */
uiDefBut(block, LABEL, 0, "", -5, -10, 295, 224, NULL, 0, 0, 0, 0, "");
uiDefBut(block, LABEL, 0, "", -5, -10, 295, 300, NULL, 0, 0, 0, 0, "");
uiDefBut(block, LABEL, 0, "Framing:", xco, yco, 68,19, 0, 0, 0, 0, 0, "");
uiBlockBeginAlign(block);
@@ -1814,6 +1814,7 @@ static uiBlock *framing_render_menu(void *arg_unused)
* RAS_STEREO_ANAGLYPH 5
* RAS_STEREO_SIDEBYSIDE 6
* RAS_STEREO_VINTERLACE 7
* RAS_STEREO_DOME 8
*/
uiBlockBeginAlign(block);
uiDefButS(block, ROW, 0, "No Stereo", xco, yco-=30, 88, 19, &(G.scene->r.stereomode), 7.0, 1.0, 0, 0, "Disables stereo");
@@ -1825,6 +1826,18 @@ static uiBlock *framing_render_menu(void *arg_unused)
uiBlockEndAlign(block);
uiBlockBeginAlign(block);
uiDefButS(block, ROW, 0, "Dome", xco-=180, yco-=30, 88, 19, &(G.scene->r.stereomode), 7.0, 8.0, 0, 0, "Enables dome camera");
uiDefButS(block, NUM, 0, "Ang:", xco+=90, yco, 88, 19, &G.scene->r.domeangle, 90.0, 250.0, 0, 0, "Angle (Aperture) of the Dome - it only works in mode 1");
uiDefButS(block, NUM, 0, "Mode:", xco+=90, yco, 88, 19, &G.scene->r.domemode, 1.0, 3.0, 0, 0, "Dome mode - 1 fisheye, 2 truncated, 3 spherical panoramic");
uiDefButF(block, NUM, 0, "Size:", xco-=180, yco-=21, 88, 19, &G.scene->r.domesize, 0.5, 3.5, 0, 0, "Size adjustments");
uiDefButS(block, NUM, 0, "Tes:", xco+=90, yco, 88, 19, &G.scene->r.domeres, 1.0, 8.0, 0, 0, "Tesselation level - 1 to 8");
uiDefButF(block, NUM, 0, "Res:", xco+=90, yco, 88, 19, &G.scene->r.domeresbuf, 0.1, 1.0, 0, 0, "Buffer Resolution - decrease it to increase speed");
uiDefIDPoinBut(block, test_scriptpoin_but, ID_SCRIPT, 1, "Warp Data: ", xco-180,yco-=21,268, 19, &G.scene->r.dometext, "Custom Warp Mesh data file");
uiBlockEndAlign(block);
uiBlockSetDirection(block, UI_TOP);
return block;

View File

@@ -173,6 +173,7 @@ void do_text_buttons(unsigned short event)
BPY_clear_bad_scriptlinks(text);
BPY_free_pyconstraint_links(text);
free_text_controllers(text);
free_dome_warp_text(text);
#endif
unlink_text(text);
free_libblock(&G.main->text, text);

View File

@@ -373,6 +373,10 @@ extern "C" void StartKetsjiShell(struct ScrArea *area,
initVideoTexture();
#endif
//initialize Dome Settings
if(blscene->r.stereomode == RAS_IRasterizer::RAS_STEREO_DOME)
ketsjiengine->InitDome(blscene->r.domesize, blscene->r.domeres, blscene->r.domemode, blscene->r.domeangle, blscene->r.domeresbuf, blscene->r.dometext);
if (sceneconverter)
{
// convert and add scene

View File

@@ -693,6 +693,11 @@ bool GPG_Application::startEngine(void)
#ifdef WITH_FFMPEG
initVideoTexture();
#endif
//initialize Dome Settings
if(m_startScene->r.stereomode == RAS_IRasterizer::RAS_STEREO_DOME)
m_ketsjiengine->InitDome(m_startScene->r.domesize, m_startScene->r.domeres, m_startScene->r.domemode, m_startScene->r.domeangle, m_startScene->r.domeresbuf, m_startScene->r.dometext);
// Set the GameLogic.globalDict from marshal'd data, so we can
// load new blend files and keep data in GameLogic.globalDict
loadGamePythonConfig(m_pyGlobalDictString, m_pyGlobalDictString_Length);

View File

@@ -0,0 +1,1820 @@
/* $Id$
-----------------------------------------------------------------------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.
Contributor(s): Dalai Felinto
This code is originally inspired on some of the ideas and codes from Paul Bourke.
Developed as part of a Research and Development project for SAT - La Soci<63>t<EFBFBD> des arts technologiques.
-----------------------------------------------------------------------------
*/
#include "KX_Dome.h"
#include <structmember.h>
#include <float.h>
#include <math.h>
#include "DNA_scene_types.h"
#include "RAS_CameraData.h"
#include "BLI_arithb.h"
#include "GL/glew.h"
#include "GL/glu.h"
// constructor
KX_Dome::KX_Dome (
RAS_ICanvas* canvas,
/// rasterizer
RAS_IRasterizer* rasterizer,
/// render tools
RAS_IRenderTools* rendertools,
/// engine
KX_KetsjiEngine* engine,
float size, //size for adjustments
short res, //resolution of the mesh
short mode, //mode - fisheye, truncated, warped, panoramic, ...
short angle,
float resbuf, //size adjustment of the buffer
struct Text* warptext
):
m_canvas(canvas),
m_rasterizer(rasterizer),
m_rendertools(rendertools),
m_engine(engine),
m_drawingmode(engine->GetDrawType()),
m_size(size),
m_resolution(res),
m_mode(mode),
m_angle(angle),
m_resbuffer(resbuf),
canvaswidth(-1), canvasheight(-1),
dlistSupported(false)
{
warp.usemesh = false;
if (mode >= DOME_NUM_MODES)
m_mode = DOME_FISHEYE;
if (warptext) // it there is a text data try to warp it
{
char *buf;
buf = txt_to_buf(warptext);
if (buf)
{
warp.usemesh = ParseWarpMesh(STR_String(buf));
MEM_freeN(buf);
}
}
//setting the viewport size
GLuint viewport[4]={0};
glGetIntegerv(GL_VIEWPORT,(GLint *)viewport);
SetViewPort(viewport);
switch(m_mode){
case DOME_FISHEYE:
if (m_angle <= 180){
cubetop.resize(1);
cubebottom.resize(1);
cubeleft.resize(2);
cuberight.resize(2);
CreateMeshDome180();
m_numfaces = 4;
}else if (m_angle > 180){
cubetop.resize(2);
cubebottom.resize(2);
cubeleft.resize(2);
cubefront.resize(2);
cuberight.resize(2);
CreateMeshDome250();
m_numfaces = 5;
} break;
case DOME_TRUNCATED:
cubetop.resize(1);
cubebottom.resize(1);
cubeleft.resize(2);
cuberight.resize(2);
m_angle = 180;
CreateMeshDome180();
m_numfaces = 4;
break;
case DOME_PANORAM_SPH:
cubeleft.resize(2);
cubeleftback.resize(2);
cuberight.resize(2);
cuberightback.resize(2);
cubetop.resize(2);
cubebottom.resize(2);
m_angle = 360;
CreateMeshPanorama();
m_numfaces = 6;
break;
}
m_numimages =(warp.usemesh?m_numfaces+1:m_numfaces);
CalculateCameraOrientation();
CreateGLImages();
dlistSupported = CreateDL();
}
// destructor
KX_Dome::~KX_Dome (void)
{
GLuint m_numimages = m_numfaces;
ClearGLImages();
if(dlistSupported)
glDeleteLists(dlistId, (GLsizei) m_numimages);
}
void KX_Dome::SetViewPort(GLuint viewport[4])
{
if(canvaswidth != m_canvas->GetWidth() || canvasheight != m_canvas->GetHeight())
{
m_viewport.SetLeft(viewport[0]);
m_viewport.SetBottom(viewport[1]);
m_viewport.SetRight(viewport[2]);
m_viewport.SetTop(viewport[3]);
CalculateImageSize();
}
}
void KX_Dome::CreateGLImages(void)
{
glGenTextures(m_numimages, (GLuint*)&domefacesId);
for (int j=0;j<m_numfaces;j++){
glBindTexture(GL_TEXTURE_2D, domefacesId[j]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, m_imagesize, m_imagesize, 0, GL_RGB8,
GL_UNSIGNED_BYTE, 0);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, m_imagesize, m_imagesize, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
if(warp.usemesh){
glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, warp.imagewidth, warp.imageheight, 0, GL_RGB8,
GL_UNSIGNED_BYTE, 0);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, warp.imagewidth, warp.imageheight, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}
void KX_Dome::ClearGLImages(void)
{
glDeleteTextures(m_numimages, (GLuint*)&domefacesId);
/*
for (int i=0;i<m_numimages;i++)
if(glIsTexture(domefacesId[i]))
glDeleteTextures(1, (GLuint*)&domefacesId[i]);
*/
}
void KX_Dome::CalculateImageSize(void)
{
/*
- determine the minimum buffer size
- reduce the buffer for better performace
- create a power of 2 texture bigger than the buffer
*/
canvaswidth = m_canvas->GetWidth();
canvasheight = m_canvas->GetHeight();
m_buffersize = (canvaswidth > canvasheight?canvasheight:canvaswidth);
m_buffersize *= m_resbuffer; //reduce buffer size for better performance
int i = 0;
while ((1 << i) <= m_buffersize)
i++;
m_imagesize = (1 << i);
if (warp.usemesh){
warp.bufferwidth = canvaswidth;
warp.bufferheight = canvasheight;
i = 0;
while ((1 << i) <= warp.bufferwidth)
i++;
warp.imagewidth = (1 << i);
i = 0;
while ((1 << i) <= warp.bufferheight)
i++;
warp.imageheight = (1 << i);
}
}
bool KX_Dome::CreateDL(){
int i,j;
dlistId = glGenLists((GLsizei) m_numimages);
if (dlistId != 0) {
if(m_mode == DOME_FISHEYE || m_mode == DOME_TRUNCATED){
glNewList(dlistId, GL_COMPILE);
GLDrawTriangles(cubetop, nfacestop);
glEndList();
glNewList(dlistId+1, GL_COMPILE);
GLDrawTriangles(cubebottom, nfacesbottom);
glEndList();
glNewList(dlistId+2, GL_COMPILE);
GLDrawTriangles(cubeleft, nfacesleft);
glEndList();
glNewList(dlistId+3, GL_COMPILE);
GLDrawTriangles(cuberight, nfacesright);
glEndList();
if (m_angle > 180){
glNewList(dlistId+4, GL_COMPILE);
GLDrawTriangles(cubefront, nfacesfront);
glEndList();
}
}
else if (m_mode == DOME_PANORAM_SPH)
{
glNewList(dlistId, GL_COMPILE);
GLDrawTriangles(cubetop, nfacestop);
glEndList();
glNewList(dlistId+1, GL_COMPILE);
GLDrawTriangles(cubebottom, nfacesbottom);
glEndList();
glNewList(dlistId+2, GL_COMPILE);
GLDrawTriangles(cubeleft, nfacesleft);
glEndList();
glNewList(dlistId+3, GL_COMPILE);
GLDrawTriangles(cuberight, nfacesright);
glEndList();
glNewList(dlistId+4, GL_COMPILE);
GLDrawTriangles(cubeleftback, nfacesleftback);
glEndList();
glNewList(dlistId+5, GL_COMPILE);
GLDrawTriangles(cuberightback, nfacesrightback);
glEndList();
}
if(warp.usemesh){
glNewList((dlistId + m_numfaces), GL_COMPILE);
GLDrawWarpQuads();
glEndList();
}
//clearing the vectors
cubetop.clear();
cubebottom.clear();
cuberight.clear();
cubeleft.clear();
cubefront.clear();
cubeleftback.clear();
cuberightback.clear();
warp.nodes.clear();
} else // genList failed
return false;
return true;
}
void KX_Dome::GLDrawTriangles(vector <DomeFace>& face, int nfaces)
{
int i,j;
glBegin(GL_TRIANGLES);
for (i=0;i<nfaces;i++) {
for (j=0;j<3;j++) {
glTexCoord2f(face[i].u[j],face[i].v[j]);
glVertex3f((GLfloat)face[i].verts[j][0],(GLfloat)face[i].verts[j][1],(GLfloat)face[i].verts[j][2]);
}
}
glEnd();
}
void KX_Dome::GLDrawWarpQuads(void)
{
int i, j, i2;
float uv_width = (float)(warp.bufferwidth-1) / warp.imagewidth;
float uv_height = (float)(warp.bufferheight-1) / warp.imageheight;
if(warp.mode ==2 ){
glBegin(GL_QUADS);
for (i=0;i<warp.n_height-1;i++) {
for (j=0;j<warp.n_width-1;j++) {
if(warp.nodes[i][j].i < 0 || warp.nodes[i+1][j].i < 0 || warp.nodes[i+1][j+1].i < 0 || warp.nodes[i][j+1].i < 0)
continue;
glColor3f(warp.nodes[i][j].i, warp.nodes[i][j].i, warp.nodes[i][j].i);
glTexCoord2f((warp.nodes[i][j].u * uv_width), (warp.nodes[i][j].v * uv_height));
glVertex3f(warp.nodes[i][j].x, warp.nodes[i][j].y,0.0);
glColor3f(warp.nodes[i+1][j].i, warp.nodes[i+1][j].i, warp.nodes[i+1][j].i);
glTexCoord2f((warp.nodes[i+1][j].u * uv_width), (warp.nodes[i+1][j].v * uv_height));
glVertex3f(warp.nodes[i+1][j].x, warp.nodes[i+1][j].y,0.0);
glColor3f(warp.nodes[i+1][j+1].i, warp.nodes[i+1][j+1].i, warp.nodes[i+1][j+1].i);
glTexCoord2f((warp.nodes[i+1][j+1].u * uv_width), (warp.nodes[i+1][j+1].v * uv_height));
glVertex3f(warp.nodes[i+1][j+1].x, warp.nodes[i+1][j+1].y,0.0);
glColor3f(warp.nodes[i][j+1].i, warp.nodes[i][j+1].i, warp.nodes[i][j+1].i);
glTexCoord2f((warp.nodes[i][j+1].u * uv_width), (warp.nodes[i][j+1].v * uv_height));
glVertex3f(warp.nodes[i][j+1].x, warp.nodes[i][j+1].y,0.0);
}
}
glEnd();
}
else if (warp.mode == 1){
glBegin(GL_QUADS);
for (i=0;i<warp.n_height-1;i++) {
for (j=0;j<warp.n_width-1;j++) {
i2 = (i+1) % warp.n_width; // Wrap around, i = warp.n_width = 0
if (warp.nodes[i][j].i < 0 || warp.nodes[i2][j].i < 0 || warp.nodes[i2][j+1].i < 0 || warp.nodes[i][j+1].i < 0)
continue;
glColor3f(warp.nodes[i][j].i,warp.nodes[i][j].i,warp.nodes[i][j].i);
glTexCoord2f((warp.nodes[i][j].u * uv_width), (warp.nodes[i][j].v * uv_height));
glVertex3f(warp.nodes[i][j].x,warp.nodes[i][j].y,0.0);
glColor3f(warp.nodes[i2][j].i,warp.nodes[i2][j].i,warp.nodes[i2][j].i);
glTexCoord2f((warp.nodes[i2][j].u * uv_width), (warp.nodes[i2][j].v * uv_height));
glVertex3f(warp.nodes[i2][j].x,warp.nodes[i2][j].y,0.0);
glColor3f(warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i);
glTexCoord2f((warp.nodes[i2][j+1].u * uv_width), (warp.nodes[i2][j+1].v * uv_height));
glVertex3f(warp.nodes[i2][j+1].x,warp.nodes[i2][j+1].y,0.0);
glColor3f(warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i);
glTexCoord2f((warp.nodes[i2][j+1].u * uv_width), (warp.nodes[i2][j+1].v * uv_height));
glVertex3f(warp.nodes[i2][j+1].x,warp.nodes[i2][j+1].y,0.0);
}
}
glEnd();
} else{
printf("Error: Warp Mode unsupported. Try 1 for Polar Mesh or 2 for Fisheye.\n");
}
}
bool KX_Dome::ParseWarpMesh(STR_String text)
{
/*
//Notes about the supported data format:
File example::
mode
width height
n0_x n0_y n0_u n0_v n0_i
n1_x n1_y n1_u n1_v n1_i
n2_x n1_y n2_u n2_v n2_i
n3_x n3_y n3_u n3_v n3_i
(...)
First line is the image type the mesh is support to be applied to: 2 = fisheye, 1=radial
Tthe next line has the mesh dimensions
Rest of the lines are the nodes of the mesh. Each line has x y u v i
(x,y) are the normalised screen coordinates
(u,v) texture coordinates
i a multiplicative intensity factor
x varies from -screen aspect to screen aspect
y varies from -1 to 1
u and v vary from 0 to 1
i ranges from 0 to 1, if negative don't draw that mesh node
*/
int i,j,k;
int nodeX=0, nodeY=0;
vector<STR_String> columns, lines;
lines = text.Explode('\n');
if(lines.size() < 6){
printf("Error: Warp Mesh File with insufficient data!\n");
return false;
}
columns = lines[1].Explode(' ');
if(columns.size() !=2){
printf("Error: Warp Mesh File incorrect. The second line should contain: width height.\n");
return false;
}
warp.mode = atoi(lines[0]);// 1 = radial, 2 = fisheye
warp.n_width = atoi(columns[0]);
warp.n_height = atoi(columns[1]);
if (lines.size() < 2 + (warp.n_width * warp.n_height)){
printf("Error: Warp Mesh File with insufficient data!\n");
return false;
}else{
warp.nodes = vector<vector <WarpMeshNode>> (warp.n_height, vector<WarpMeshNode>(warp.n_width));
for(i=2; i-2 < (warp.n_width*warp.n_height); i++){
columns = lines[i].Explode(' ');
if (columns.size() == 5){
nodeX = (i-2)%warp.n_width;
nodeY = ((i-2) - nodeX) / warp.n_width;
warp.nodes[nodeY][nodeX].x = atof(columns[0]);
warp.nodes[nodeY][nodeX].y = atof(columns[1]);
warp.nodes[nodeY][nodeX].u = atof(columns[2]);
warp.nodes[nodeY][nodeX].v = atof(columns[3]);
warp.nodes[nodeY][nodeX].i = atof(columns[4]);
}
else{
warp.nodes.clear();
printf("Error: Warp Mesh File with wrong number of fields. You should use 5: x y u v i.\n");
return false;
}
}
}
return true;
}
void KX_Dome::CreateMeshDome180(void)
{
/*
1)- Define the faces of half of a cube
- each face is made out of 2 triangles
2) Subdivide the faces
- more resolution == more curved lines
3) Spherize the cube
- normalize the verts
4) Flatten onto xz plane
- transform it onto an equidistant spherical projection techniques to transform the sphere onto a dome image
*/
int i,j;
float sqrt_2 = sqrt(2.0);
float uv_ratio = (float)(m_buffersize-1) / m_imagesize;
m_radangle = m_angle * M_PI/180.0;//calculates the radians angle, used for flattening
//creating faces for the env mapcube 180<38> Dome
// Top Face - just a triangle
cubetop[0].verts[0][0] = -sqrt_2 / 2.0;
cubetop[0].verts[0][1] = 0.0;
cubetop[0].verts[0][2] = 0.5;
cubetop[0].u[0] = 0.0;
cubetop[0].v[0] = uv_ratio;
cubetop[0].verts[1][0] = 0.0;
cubetop[0].verts[1][1] = sqrt_2 / 2.0;
cubetop[0].verts[1][2] = 0.5;
cubetop[0].u[1] = 0.0;
cubetop[0].v[1] = 0.0;
cubetop[0].verts[2][0] = sqrt_2 / 2.0;
cubetop[0].verts[2][1] = 0.0;
cubetop[0].verts[2][2] = 0.5;
cubetop[0].u[2] = uv_ratio;
cubetop[0].v[2] = 0.0;
nfacestop = 1;
/* Bottom face - just a triangle */
cubebottom[0].verts[0][0] = -sqrt_2 / 2.0;
cubebottom[0].verts[0][1] = 0.0;
cubebottom[0].verts[0][2] = -0.5;
cubebottom[0].u[0] = uv_ratio;
cubebottom[0].v[0] = 0.0;
cubebottom[0].verts[1][0] = sqrt_2 / 2.0;
cubebottom[0].verts[1][1] = 0;
cubebottom[0].verts[1][2] = -0.5;
cubebottom[0].u[1] = 0.0;
cubebottom[0].v[1] = uv_ratio;
cubebottom[0].verts[2][0] = 0.0;
cubebottom[0].verts[2][1] = sqrt_2 / 2.0;
cubebottom[0].verts[2][2] = -0.5;
cubebottom[0].u[2] = 0.0;
cubebottom[0].v[2] = 0.0;
nfacesbottom = 1;
/* Left face - two triangles */
cubeleft[0].verts[0][0] = -sqrt_2 / 2.0;
cubeleft[0].verts[0][1] = .0;
cubeleft[0].verts[0][2] = -0.5;
cubeleft[0].u[0] = 0.0;
cubeleft[0].v[0] = 0.0;
cubeleft[0].verts[1][0] = 0.0;
cubeleft[0].verts[1][1] = sqrt_2 / 2.0;
cubeleft[0].verts[1][2] = -0.5;
cubeleft[0].u[1] = uv_ratio;
cubeleft[0].v[1] = 0.0;
cubeleft[0].verts[2][0] = -sqrt_2 / 2.0;
cubeleft[0].verts[2][1] = 0.0;
cubeleft[0].verts[2][2] = 0.5;
cubeleft[0].u[2] = 0.0;
cubeleft[0].v[2] = uv_ratio;
//second triangle
cubeleft[1].verts[0][0] = -sqrt_2 / 2.0;
cubeleft[1].verts[0][1] = 0.0;
cubeleft[1].verts[0][2] = 0.5;
cubeleft[1].u[0] = 0.0;
cubeleft[1].v[0] = uv_ratio;
cubeleft[1].verts[1][0] = 0.0;
cubeleft[1].verts[1][1] = sqrt_2 / 2.0;
cubeleft[1].verts[1][2] = -0.5;
cubeleft[1].u[1] = uv_ratio;
cubeleft[1].v[1] = 0.0;
cubeleft[1].verts[2][0] = 0.0;
cubeleft[1].verts[2][1] = sqrt_2 / 2.0;
cubeleft[1].verts[2][2] = 0.5;
cubeleft[1].u[2] = uv_ratio;
cubeleft[1].v[2] = uv_ratio;
nfacesleft = 2;
/* Right face - two triangles */
cuberight[0].verts[0][0] = 0.0;
cuberight[0].verts[0][1] = sqrt_2 / 2.0;
cuberight[0].verts[0][2] = -0.5;
cuberight[0].u[0] = 0.0;
cuberight[0].v[0] = 0.0;
cuberight[0].verts[1][0] = sqrt_2 / 2.0;
cuberight[0].verts[1][1] = 0.0;
cuberight[0].verts[1][2] = -0.5;
cuberight[0].u[1] = uv_ratio;
cuberight[0].v[1] = 0.0;
cuberight[0].verts[2][0] = sqrt_2 / 2.0;
cuberight[0].verts[2][1] = 0.0;
cuberight[0].verts[2][2] = 0.5;
cuberight[0].u[2] = uv_ratio;
cuberight[0].v[2] = uv_ratio;
//second triangle
cuberight[1].verts[0][0] = 0.0;
cuberight[1].verts[0][1] = sqrt_2 / 2.0;
cuberight[1].verts[0][2] = -0.5;
cuberight[1].u[0] = 0.0;
cuberight[1].v[0] = 0.0;
cuberight[1].verts[1][0] = sqrt_2 / 2.0;
cuberight[1].verts[1][1] = 0.0;
cuberight[1].verts[1][2] = 0.5;
cuberight[1].u[1] = uv_ratio;
cuberight[1].v[1] = uv_ratio;
cuberight[1].verts[2][0] = 0.0;
cuberight[1].verts[2][1] = sqrt_2 / 2.0;
cuberight[1].verts[2][2] = 0.5;
cuberight[1].u[2] = 0.0;
cuberight[1].v[2] = uv_ratio;
nfacesright = 2;
//Refine a triangular mesh by bisecting each edge forms 3 new triangles for each existing triangle on each iteration
//Could be made more efficient for drawing if the triangles were ordered in a fan. Not that important since we are using DisplayLists
for(i=0;i<m_resolution;i++){
cubetop.resize(4*nfacestop);
SplitFace(cubetop,&nfacestop);
cubebottom.resize(4*nfacesbottom);
SplitFace(cubebottom,&nfacesbottom);
cubeleft.resize(4*nfacesleft);
SplitFace(cubeleft,&nfacesleft);
cuberight.resize(4*nfacesright);
SplitFace(cuberight,&nfacesright);
}
// Turn into a hemisphere
for(j=0;j<3;j++){
for(i=0;i<nfacestop;i++)
cubetop[i].verts[j].normalize();
for(i=0;i<nfacesbottom;i++)
cubebottom[i].verts[j].normalize();
for(i=0;i<nfacesleft;i++)
cubeleft[i].verts[j].normalize();
for(i=0;i<nfacesright;i++)
cuberight[i].verts[j].normalize();
}
//flatten onto xz plane
for(i=0;i<nfacestop;i++)
FlattenDome(cubetop[i].verts);
for(i=0;i<nfacesbottom;i++)
FlattenDome(cubebottom[i].verts);
for(i=0;i<nfacesleft;i++)
FlattenDome(cubeleft[i].verts);
for(i=0;i<nfacesright;i++)
FlattenDome(cuberight[i].verts);
}
void KX_Dome::CreateMeshDome250(void)
{
/*
1)- Define the faces of a cube without the back face
- each face is made out of 2 triangles
2) Subdivide the faces
- more resolution == more curved lines
3) Spherize the cube
- normalize the verts
4) Flatten onto xz plane
- transform it onto an equidistant spherical projection techniques to transform the sphere onto a dome image
*/
int i,j;
float uv_height, uv_base;
float verts_height;
float rad_ang = m_angle * MT_PI / 180.0;
float uv_ratio = (float)(m_buffersize-1) / m_imagesize;
m_radangle = m_angle * M_PI/180.0;//calculates the radians angle, used for flattening
/*
verts_height is the exactly needed height of the cube faces (not always 1.0).
When we want some horizontal information (e.g. for horizontal 220<32> domes) we don't need to create and tesselate the whole cube.
Therefore the lateral cube faces could be small, and the tesselate mesh would be completely used.
(if we always worked with verts_height = 1.0, we would be discarding a lot of the calculated and tesselated geometry).
So I came out with this formula:
verts_height = tan((rad_ang/2) - (MT_PI/2))*sqrt(2.0);
Here we take half the sphere(rad_ang/2) and subtract a quarter of it (MT_PI/2)
Therefore we have the lenght in radians of the dome/sphere over the horizon.
Once we take the tangent of that angle, you have the verts coordinate corresponding to the verts on the side faces.
Then we need to multiply it by sqrt(2.0) to get the coordinate of the verts on the diagonal of the original cube.
*/
verts_height = tan((rad_ang/2) - (MT_PI/2))*sqrt(2.0);
uv_height = uv_ratio * ((verts_height/2) + 0.5);
uv_base = uv_ratio * (1.0 - ((verts_height/2) + 0.5));
//creating faces for the env mapcube 180<38> Dome
// Front Face - 2 triangles
cubefront[0].verts[0][0] =-1.0;
cubefront[0].verts[0][1] = 1.0;
cubefront[0].verts[0][2] =-1.0;
cubefront[0].u[0] = 0.0;
cubefront[0].v[0] = 0.0;
cubefront[0].verts[1][0] = 1.0;
cubefront[0].verts[1][1] = 1.0;
cubefront[0].verts[1][2] = 1.0;
cubefront[0].u[1] = uv_ratio;
cubefront[0].v[1] = uv_ratio;
cubefront[0].verts[2][0] =-1.0;
cubefront[0].verts[2][1] = 1.0;
cubefront[0].verts[2][2] = 1.0;
cubefront[0].u[2] = 0.0;
cubefront[0].v[2] = uv_ratio;
//second triangle
cubefront[1].verts[0][0] = 1.0;
cubefront[1].verts[0][1] = 1.0;
cubefront[1].verts[0][2] = 1.0;
cubefront[1].u[0] = uv_ratio;
cubefront[1].v[0] = uv_ratio;
cubefront[1].verts[1][0] =-1.0;
cubefront[1].verts[1][1] = 1.0;
cubefront[1].verts[1][2] =-1.0;
cubefront[1].u[1] = 0.0;
cubefront[1].v[1] = 0.0;
cubefront[1].verts[2][0] = 1.0;
cubefront[1].verts[2][1] = 1.0;
cubefront[1].verts[2][2] =-1.0;
cubefront[1].u[2] = uv_ratio;
cubefront[1].v[2] = 0.0;
nfacesfront = 2;
// Left Face - 2 triangles
cubeleft[0].verts[0][0] =-1.0;
cubeleft[0].verts[0][1] = 1.0;
cubeleft[0].verts[0][2] =-1.0;
cubeleft[0].u[0] = uv_ratio;
cubeleft[0].v[0] = 0.0;
cubeleft[0].verts[1][0] =-1.0;
cubeleft[0].verts[1][1] =-verts_height;
cubeleft[0].verts[1][2] = 1.0;
cubeleft[0].u[1] = uv_base;
cubeleft[0].v[1] = uv_ratio;
cubeleft[0].verts[2][0] =-1.0;
cubeleft[0].verts[2][1] =-verts_height;
cubeleft[0].verts[2][2] =-1.0;
cubeleft[0].u[2] = uv_base;
cubeleft[0].v[2] = 0.0;
//second triangle
cubeleft[1].verts[0][0] =-1.0;
cubeleft[1].verts[0][1] =-verts_height;
cubeleft[1].verts[0][2] = 1.0;
cubeleft[1].u[0] = uv_base;
cubeleft[1].v[0] = uv_ratio;
cubeleft[1].verts[1][0] =-1.0;
cubeleft[1].verts[1][1] = 1.0;
cubeleft[1].verts[1][2] =-1.0;
cubeleft[1].u[1] = uv_ratio;
cubeleft[1].v[1] = 0.0;
cubeleft[1].verts[2][0] =-1.0;
cubeleft[1].verts[2][1] = 1.0;
cubeleft[1].verts[2][2] = 1.0;
cubeleft[1].u[2] = uv_ratio;
cubeleft[1].v[2] = uv_ratio;
nfacesleft = 2;
// right Face - 2 triangles
cuberight[0].verts[0][0] = 1.0;
cuberight[0].verts[0][1] = 1.0;
cuberight[0].verts[0][2] = 1.0;
cuberight[0].u[0] = 0.0;
cuberight[0].v[0] = uv_ratio;
cuberight[0].verts[1][0] = 1.0;
cuberight[0].verts[1][1] =-verts_height;
cuberight[0].verts[1][2] =-1.0;
cuberight[0].u[1] = uv_height;
cuberight[0].v[1] = 0.0;
cuberight[0].verts[2][0] = 1.0;
cuberight[0].verts[2][1] =-verts_height;
cuberight[0].verts[2][2] = 1.0;
cuberight[0].u[2] = uv_height;
cuberight[0].v[2] = uv_ratio;
//second triangle
cuberight[1].verts[0][0] = 1.0;
cuberight[1].verts[0][1] =-verts_height;
cuberight[1].verts[0][2] =-1.0;
cuberight[1].u[0] = uv_height;
cuberight[1].v[0] = 0.0;
cuberight[1].verts[1][0] = 1.0;
cuberight[1].verts[1][1] = 1.0;
cuberight[1].verts[1][2] = 1.0;
cuberight[1].u[1] = 0.0;
cuberight[1].v[1] = uv_ratio;
cuberight[1].verts[2][0] = 1.0;
cuberight[1].verts[2][1] = 1.0;
cuberight[1].verts[2][2] =-1.0;
cuberight[1].u[2] = 0.0;
cuberight[1].v[2] = 0.0;
nfacesright = 2;
// top Face - 2 triangles
cubetop[0].verts[0][0] =-1.0;
cubetop[0].verts[0][1] = 1.0;
cubetop[0].verts[0][2] = 1.0;
cubetop[0].u[0] = 0.0;
cubetop[0].v[0] = 0.0;
cubetop[0].verts[1][0] = 1.0;
cubetop[0].verts[1][1] =-verts_height;
cubetop[0].verts[1][2] = 1.0;
cubetop[0].u[1] = uv_ratio;
cubetop[0].v[1] = uv_height;
cubetop[0].verts[2][0] =-1.0;
cubetop[0].verts[2][1] =-verts_height;
cubetop[0].verts[2][2] = 1.0;
cubetop[0].u[2] = 0.0;
cubetop[0].v[2] = uv_height;
//second triangle
cubetop[1].verts[0][0] = 1.0;
cubetop[1].verts[0][1] =-verts_height;
cubetop[1].verts[0][2] = 1.0;
cubetop[1].u[0] = uv_ratio;
cubetop[1].v[0] = uv_height;
cubetop[1].verts[1][0] =-1.0;
cubetop[1].verts[1][1] = 1.0;
cubetop[1].verts[1][2] = 1.0;
cubetop[1].u[1] = 0.0;
cubetop[1].v[1] = 0.0;
cubetop[1].verts[2][0] = 1.0;
cubetop[1].verts[2][1] = 1.0;
cubetop[1].verts[2][2] = 1.0;
cubetop[1].u[2] = uv_ratio;
cubetop[1].v[2] = 0.0;
nfacestop = 2;
// bottom Face - 2 triangles
cubebottom[0].verts[0][0] =-1.0;
cubebottom[0].verts[0][1] =-verts_height;
cubebottom[0].verts[0][2] =-1.0;
cubebottom[0].u[0] = 0.0;
cubebottom[0].v[0] = uv_base;
cubebottom[0].verts[1][0] = 1.0;
cubebottom[0].verts[1][1] = 1.0;
cubebottom[0].verts[1][2] =-1.0;
cubebottom[0].u[1] = uv_ratio;
cubebottom[0].v[1] = uv_ratio;
cubebottom[0].verts[2][0] =-1.0;
cubebottom[0].verts[2][1] = 1.0;
cubebottom[0].verts[2][2] =-1.0;
cubebottom[0].u[2] = 0.0;
cubebottom[0].v[2] = uv_ratio;
//second triangle
cubebottom[1].verts[0][0] = 1.0;
cubebottom[1].verts[0][1] = 1.0;
cubebottom[1].verts[0][2] =-1.0;
cubebottom[1].u[0] = uv_ratio;
cubebottom[1].v[0] = uv_ratio;
cubebottom[1].verts[1][0] =-1.0;
cubebottom[1].verts[1][1] =-verts_height;
cubebottom[1].verts[1][2] =-1.0;
cubebottom[1].u[1] = 0.0;
cubebottom[1].v[1] = uv_base;
cubebottom[1].verts[2][0] = 1.0;
cubebottom[1].verts[2][1] =-verts_height;
cubebottom[1].verts[2][2] =-1.0;
cubebottom[1].u[2] = uv_ratio;
cubebottom[1].v[2] = uv_base;
nfacesbottom = 2;
//Refine a triangular mesh by bisecting each edge forms 3 new triangles for each existing triangle on each iteration
//It could be made more efficient for drawing if the triangles were ordered in a strip!
for(i=0;i<m_resolution;i++){
cubefront.resize(4*nfacesfront);
SplitFace(cubefront,&nfacesfront);
cubetop.resize(4*nfacestop);
SplitFace(cubetop,&nfacestop);
cubebottom.resize(4*nfacesbottom);
SplitFace(cubebottom,&nfacesbottom);
cubeleft.resize(4*nfacesleft);
SplitFace(cubeleft,&nfacesleft);
cuberight.resize(4*nfacesright);
SplitFace(cuberight,&nfacesright);
}
// Turn into a hemisphere/sphere
for(j=0;j<3;j++){
for(i=0;i<nfacesfront;i++)
cubefront[i].verts[j].normalize();
for(i=0;i<nfacestop;i++)
cubetop[i].verts[j].normalize();
for(i=0;i<nfacesbottom;i++)
cubebottom[i].verts[j].normalize();
for(i=0;i<nfacesleft;i++)
cubeleft[i].verts[j].normalize();
for(i=0;i<nfacesright;i++)
cuberight[i].verts[j].normalize();
}
//flatten onto xz plane
for(i=0;i<nfacesfront;i++)
FlattenDome(cubefront[i].verts);
for(i=0;i<nfacestop;i++)
FlattenDome(cubetop[i].verts);
for(i=0;i<nfacesbottom;i++)
FlattenDome(cubebottom[i].verts);
for(i=0;i<nfacesleft;i++)
FlattenDome(cubeleft[i].verts);
for(i=0;i<nfacesright;i++)
FlattenDome(cuberight[i].verts);
}
void KX_Dome::CreateMeshPanorama(void)
{
/*
1)- Define the faces of a cube without the top and bottom faces
- each face is made out of 2 triangles
2) Subdivide the faces
- more resolution == more curved lines
3) Spherize the cube
- normalize the verts t
4) Flatten onto xz plane
- use spherical projection techniques to transform the sphere onto a flat panorama
*/
int i,j;
float sqrt_2 = sqrt(2.0);
float uv_ratio = (float)(m_buffersize-1) / m_imagesize;
/* Top face - two triangles */
cubetop[0].verts[0][0] = -sqrt_2;
cubetop[0].verts[0][1] = 0.0;
cubetop[0].verts[0][2] = 1.0;
cubetop[0].u[0] = 0.0;
cubetop[0].v[0] = uv_ratio;
cubetop[0].verts[1][0] = 0.0;
cubetop[0].verts[1][1] = sqrt_2;
cubetop[0].verts[1][2] = 1.0;
cubetop[0].u[1] = 0.0;
cubetop[0].v[1] = 0.0;
//second triangle
cubetop[0].verts[2][0] = sqrt_2;
cubetop[0].verts[2][1] = 0.0;
cubetop[0].verts[2][2] = 1.0;
cubetop[0].u[2] = uv_ratio;
cubetop[0].v[2] = 0.0;
cubetop[1].verts[0][0] = sqrt_2;
cubetop[1].verts[0][1] = 0.0;
cubetop[1].verts[0][2] = 1.0;
cubetop[1].u[0] = uv_ratio;
cubetop[1].v[0] = 0.0;
cubetop[1].verts[1][0] = 0.0;
cubetop[1].verts[1][1] = -sqrt_2;
cubetop[1].verts[1][2] = 1.0;
cubetop[1].u[1] = uv_ratio;
cubetop[1].v[1] = uv_ratio;
cubetop[1].verts[2][0] = -sqrt_2;
cubetop[1].verts[2][1] = 0.0;
cubetop[1].verts[2][2] = 1.0;
cubetop[1].u[2] = 0.0;
cubetop[1].v[2] = uv_ratio;
nfacestop = 2;
/* Bottom face - two triangles */
cubebottom[0].verts[0][0] = -sqrt_2;
cubebottom[0].verts[0][1] = 0.0;
cubebottom[0].verts[0][2] = -1.0;
cubebottom[0].u[0] = uv_ratio;
cubebottom[0].v[0] = 0.0;
cubebottom[0].verts[1][0] = sqrt_2;
cubebottom[0].verts[1][1] = 0.0;
cubebottom[0].verts[1][2] = -1.0;
cubebottom[0].u[1] = 0.0;
cubebottom[0].v[1] = uv_ratio;
cubebottom[0].verts[2][0] = 0.0;
cubebottom[0].verts[2][1] = sqrt_2;
cubebottom[0].verts[2][2] = -1.0;
cubebottom[0].u[2] = 0.0;
cubebottom[0].v[2] = 0.0;
//second triangle
cubebottom[1].verts[0][0] = sqrt_2;
cubebottom[1].verts[0][1] = 0.0;
cubebottom[1].verts[0][2] = -1.0;
cubebottom[1].u[0] = 0.0;
cubebottom[1].v[0] = uv_ratio;
cubebottom[1].verts[1][0] = -sqrt_2;
cubebottom[1].verts[1][1] = 0.0;
cubebottom[1].verts[1][2] = -1.0;
cubebottom[1].u[1] = uv_ratio;
cubebottom[1].v[1] = 0.0;
cubebottom[1].verts[2][0] = 0.0;
cubebottom[1].verts[2][1] = -sqrt_2;
cubebottom[1].verts[2][2] = -1.0;
cubebottom[1].u[2] = uv_ratio;
cubebottom[1].v[2] = uv_ratio;
nfacesbottom = 2;
/* Left Back (135<33>) face - two triangles */
cubeleftback[0].verts[0][0] = 0;
cubeleftback[0].verts[0][1] = -sqrt_2;
cubeleftback[0].verts[0][2] = -1.0;
cubeleftback[0].u[0] = 0;
cubeleftback[0].v[0] = 0;
cubeleftback[0].verts[1][0] = -sqrt_2;
cubeleftback[0].verts[1][1] = 0;
cubeleftback[0].verts[1][2] = -1.0;
cubeleftback[0].u[1] = uv_ratio;
cubeleftback[0].v[1] = 0;
cubeleftback[0].verts[2][0] = 0;
cubeleftback[0].verts[2][1] = -sqrt_2;
cubeleftback[0].verts[2][2] = 1.0;
cubeleftback[0].u[2] = 0;
cubeleftback[0].v[2] = uv_ratio;
//second triangle
cubeleftback[1].verts[0][0] = 0;
cubeleftback[1].verts[0][1] = -sqrt_2;
cubeleftback[1].verts[0][2] = 1.0;
cubeleftback[1].u[0] = 0;
cubeleftback[1].v[0] = uv_ratio;
cubeleftback[1].verts[1][0] = -sqrt_2;
cubeleftback[1].verts[1][1] = 0;
cubeleftback[1].verts[1][2] = -1.0;
cubeleftback[1].u[1] = uv_ratio;
cubeleftback[1].v[1] = 0;
cubeleftback[1].verts[2][0] = -sqrt_2;
cubeleftback[1].verts[2][1] = 0;
cubeleftback[1].verts[2][2] = 1.0;
cubeleftback[1].u[2] = uv_ratio;
cubeleftback[1].v[2] = uv_ratio;
nfacesleftback = 2;
/* Left face - two triangles */
cubeleft[0].verts[0][0] = -sqrt_2;
cubeleft[0].verts[0][1] = 0;
cubeleft[0].verts[0][2] = -1.0;
cubeleft[0].u[0] = 0;
cubeleft[0].v[0] = 0;
cubeleft[0].verts[1][0] = 0;
cubeleft[0].verts[1][1] = sqrt_2;
cubeleft[0].verts[1][2] = -1.0;
cubeleft[0].u[1] = uv_ratio;
cubeleft[0].v[1] = 0;
cubeleft[0].verts[2][0] = -sqrt_2;
cubeleft[0].verts[2][1] = 0;
cubeleft[0].verts[2][2] = 1.0;
cubeleft[0].u[2] = 0;
cubeleft[0].v[2] = uv_ratio;
//second triangle
cubeleft[1].verts[0][0] = -sqrt_2;
cubeleft[1].verts[0][1] = 0;
cubeleft[1].verts[0][2] = 1.0;
cubeleft[1].u[0] = 0;
cubeleft[1].v[0] = uv_ratio;
cubeleft[1].verts[1][0] = 0;
cubeleft[1].verts[1][1] = sqrt_2;
cubeleft[1].verts[1][2] = -1.0;
cubeleft[1].u[1] = uv_ratio;
cubeleft[1].v[1] = 0;
cubeleft[1].verts[2][0] = 0;
cubeleft[1].verts[2][1] = sqrt_2;
cubeleft[1].verts[2][2] = 1.0;
cubeleft[1].u[2] = uv_ratio;
cubeleft[1].v[2] = uv_ratio;
nfacesleft = 2;
/* Right face - two triangles */
cuberight[0].verts[0][0] = 0;
cuberight[0].verts[0][1] = sqrt_2;
cuberight[0].verts[0][2] = -1.0;
cuberight[0].u[0] = 0;
cuberight[0].v[0] = 0;
cuberight[0].verts[1][0] = sqrt_2;
cuberight[0].verts[1][1] = 0;
cuberight[0].verts[1][2] = -1.0;
cuberight[0].u[1] = uv_ratio;
cuberight[0].v[1] = 0;
cuberight[0].verts[2][0] = sqrt_2;
cuberight[0].verts[2][1] = 0;
cuberight[0].verts[2][2] = 1.0;
cuberight[0].u[2] = uv_ratio;
cuberight[0].v[2] = uv_ratio;
//second triangle
cuberight[1].verts[0][0] = 0;
cuberight[1].verts[0][1] = sqrt_2;
cuberight[1].verts[0][2] = -1.0;
cuberight[1].u[0] = 0;
cuberight[1].v[0] = 0;
cuberight[1].verts[1][0] = sqrt_2;
cuberight[1].verts[1][1] = 0;
cuberight[1].verts[1][2] = 1.0;
cuberight[1].u[1] = uv_ratio;
cuberight[1].v[1] = uv_ratio;
cuberight[1].verts[2][0] = 0;
cuberight[1].verts[2][1] = sqrt_2;
cuberight[1].verts[2][2] = 1.0;
cuberight[1].u[2] = 0;
cuberight[1].v[2] = uv_ratio;
nfacesright = 2;
/* Right Back (-135<33>) face - two triangles */
cuberightback[0].verts[0][0] = sqrt_2;
cuberightback[0].verts[0][1] = 0;
cuberightback[0].verts[0][2] = -1.0;
cuberightback[0].u[0] = 0;
cuberightback[0].v[0] = 0;
cuberightback[0].verts[1][0] = 0;
cuberightback[0].verts[1][1] = -sqrt_2;
cuberightback[0].verts[1][2] = -1.0;
cuberightback[0].u[1] = uv_ratio;
cuberightback[0].v[1] = 0;
cuberightback[0].verts[2][0] = 0;
cuberightback[0].verts[2][1] = -sqrt_2;
cuberightback[0].verts[2][2] = 1.0;
cuberightback[0].u[2] = uv_ratio;
cuberightback[0].v[2] = uv_ratio;
//second triangle
cuberightback[1].verts[0][0] = sqrt_2;
cuberightback[1].verts[0][1] = 0;
cuberightback[1].verts[0][2] = -1.0;
cuberightback[1].u[0] = 0;
cuberightback[1].v[0] = 0;
cuberightback[1].verts[1][0] = 0;
cuberightback[1].verts[1][1] = -sqrt_2;
cuberightback[1].verts[1][2] = 1.0;
cuberightback[1].u[1] = uv_ratio;
cuberightback[1].v[1] = uv_ratio;
cuberightback[1].verts[2][0] = sqrt_2;
cuberightback[1].verts[2][1] = 0;
cuberightback[1].verts[2][2] = 1.0;
cuberightback[1].u[2] = 0;
cuberightback[1].v[2] = uv_ratio;
nfacesrightback = 2;
// Subdivide the faces
for(i=0;i<m_resolution;i++)
{
cubetop.resize(4*nfacestop);
SplitFace(cubetop,&nfacestop);
cubebottom.resize(4*nfacesbottom);
SplitFace(cubebottom,&nfacesbottom);
cubeleft.resize(4*nfacesleft);
SplitFace(cubeleft,&nfacesleft);
cuberight.resize(4*nfacesright);
SplitFace(cuberight,&nfacesright);
cubeleftback.resize(4*nfacesleftback);
SplitFace(cubeleftback,&nfacesleftback);
cuberightback.resize(4*nfacesrightback);
SplitFace(cuberightback,&nfacesrightback);
}
// Spherize the cube
for(j=0;j<3;j++)
{
for(i=0;i<nfacestop;i++)
cubetop[i].verts[j].normalize();
for(i=0;i<nfacesbottom;i++)
cubebottom[i].verts[j].normalize();
for(i=0;i<nfacesleftback;i++)
cubeleftback[i].verts[j].normalize();
for(i=0;i<nfacesleft;i++)
cubeleft[i].verts[j].normalize();
for(i=0;i<nfacesright;i++)
cuberight[i].verts[j].normalize();
for(i=0;i<nfacesrightback;i++)
cuberightback[i].verts[j].normalize();
}
//Flatten onto xz plane
for(i=0;i<nfacesleftback;i++)
FlattenPanorama(cubeleftback[i].verts);
for(i=0;i<nfacesleft;i++)
FlattenPanorama(cubeleft[i].verts);
for(i=0;i<nfacesright;i++)
FlattenPanorama(cuberight[i].verts);
for(i=0;i<nfacesrightback;i++)
FlattenPanorama(cuberightback[i].verts);
for(i=0;i<nfacestop;i++)
FlattenPanorama(cubetop[i].verts);
for(i=0;i<nfacesbottom;i++)
FlattenPanorama(cubebottom[i].verts);
}
void KX_Dome::FlattenDome(MT_Vector3 verts[3])
{
double phi, r;
for (int i=0;i<3;i++){
r = atan2(sqrt(verts[i][0]*verts[i][0] + verts[i][2]*verts[i][2]), verts[i][1]);
r /= m_radangle/2;
phi = atan2(verts[i][2], verts[i][0]);
verts[i][0] = r * cos(phi);
verts[i][1] = 0;
verts[i][2] = r * sin(phi);
if (r > 1.0){
//round the border
verts[i][0] = cos(phi);
verts[i][1] = -3.0;
verts[i][2] = sin(phi);
}
}
}
void KX_Dome::FlattenPanorama(MT_Vector3 verts[3])
{
// it creates a full spherical panoramic (360<36>)
int i;
double phi;
bool edge=false;
for (i=0;i<3;i++){
phi = atan2(verts[i][1], verts[i][0]);
phi *= -1.0; //flipping
if (phi == -MT_PI) //It's on the edge
edge=true;
verts[i][0] = phi / MT_PI;
verts[i][1] = 0;
verts[i][2] = atan2(verts[i][2], 1.0);
verts[i][2] /= MT_PI / 2;
}
if(edge){
bool right=false;
for (i=0;i<3;i++){
if(fmod(verts[i][0],1.0) > 0.0){
right=true;
break;
}
}
if(right){
for (i=0;i<3;i++){
if(verts[i][0] < 0.0)
verts[i][0] *= -1.0;
}
}
}
}
void KX_Dome::SplitFace(vector <DomeFace>& face, int *nfaces)
{
int i;
int n1, n2;
n1 = n2 = *nfaces;
for(i=0;i<n1;i++){
face[n2].verts[0] = (face[i].verts[0] + face[i].verts[1]) /2;
face[n2].verts[1] = face[i].verts[1];
face[n2].verts[2] = (face[i].verts[1] + face[i].verts[2]) /2;
face[n2].u[0] = (face[i].u[0] + face[i].u[1]) /2;
face[n2].u[1] = face[i].u[1];
face[n2].u[2] = (face[i].u[1] + face[i].u[2]) /2;
face[n2].v[0] = (face[i].v[0] + face[i].v[1]) /2;
face[n2].v[1] = face[i].v[1];
face[n2].v[2] = (face[i].v[1] + face[i].v[2]) /2;
face[n2+1].verts[0] = (face[i].verts[1] + face[i].verts[2]) /2;
face[n2+1].verts[1] = face[i].verts[2];
face[n2+1].verts[2] = (face[i].verts[2] + face[i].verts[0]) /2;
face[n2+1].u[0] = (face[i].u[1] + face[i].u[2]) /2;
face[n2+1].u[1] = face[i].u[2];
face[n2+1].u[2] = (face[i].u[2] + face[i].u[0]) /2;
face[n2+1].v[0] = (face[i].v[1] + face[i].v[2]) /2;
face[n2+1].v[1] = face[i].v[2];
face[n2+1].v[2] = (face[i].v[2] + face[i].v[0]) /2;
face[n2+2].verts[0] = (face[i].verts[0] + face[i].verts[1]) /2;
face[n2+2].verts[1] = (face[i].verts[1] + face[i].verts[2]) /2;
face[n2+2].verts[2] = (face[i].verts[2] + face[i].verts[0]) /2;
face[n2+2].u[0] = (face[i].u[0] + face[i].u[1]) /2;
face[n2+2].u[1] = (face[i].u[1] + face[i].u[2]) /2;
face[n2+2].u[2] = (face[i].u[2] + face[i].u[0]) /2;
face[n2+2].v[0] = (face[i].v[0] + face[i].v[1]) /2;
face[n2+2].v[1] = (face[i].v[1] + face[i].v[2]) /2;
face[n2+2].v[2] = (face[i].v[2] + face[i].v[0]) /2;
//face[i].verts[0] = face[i].verts[0] ;
face[i].verts[1] = (face[i].verts[0] + face[i].verts[1]) /2;
face[i].verts[2] = (face[i].verts[0] + face[i].verts[2]) /2;
//face[i].u[0] = face[i].u[0];
face[i].u[1] = (face[i].u[0] + face[i].u[1]) /2;
face[i].u[2] = (face[i].u[0] + face[i].u[2]) /2;
//face[i].v[0] = face[i].v[0] ;
face[i].v[1] = (face[i].v[0] + face[i].v[1]) /2;
face[i].v[2] = (face[i].v[0] + face[i].v[2]) /2;
n2 += 3; // number of faces
}
*nfaces = n2;
}
void KX_Dome::CalculateFrustum(KX_Camera * cam)
{
/*
// manually creating a 90<39> Field of View Frustum
the original formula:
top = tan(fov*3.14159/360.0) * near [for fov in degrees]
fov*0.5 = arctan ((top-bottom)*0.5 / near) [for fov in radians]
bottom = -top
left = aspect * bottom
right = aspect * top
// the equivalent GLU call is:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.0,1.0,cam->GetCameraNear(),cam->GetCameraFar());
*/
RAS_FrameFrustum m_frustrum; //90 deg. Frustum
m_frustrum.camnear = cam->GetCameraNear();
m_frustrum.camfar = cam->GetCameraFar();
// float top = tan(90.0*MT_PI/360.0) * m_frustrum.camnear;
float top = m_frustrum.camnear; // for deg = 90<39>, tan = 1
m_frustrum.x1 = -top;
m_frustrum.x2 = top;
m_frustrum.y1 = -top;
m_frustrum.y2 = top;
m_projmat = m_rasterizer->GetFrustumMatrix(
m_frustrum.x1, m_frustrum.x2, m_frustrum.y1, m_frustrum.y2, m_frustrum.camnear, m_frustrum.camfar);
}
void KX_Dome::CalculateCameraOrientation()
{
/*
Uses 4 cameras for angles up to 180<38>
Uses 5 cameras for angles up to 250<35>
Uses 6 cameras for angles up to 360<36>
*/
float deg45 = MT_PI / 4;
MT_Scalar c = cos(deg45);
MT_Scalar s = sin(deg45);
if ((m_mode == DOME_FISHEYE && m_angle <= 180)|| m_mode == DOME_TRUNCATED){
m_locRot[0] = MT_Matrix3x3( // 90<39> - Top
c, -s, 0.0,
0.0,0.0, -1.0,
s, c, 0.0);
m_locRot[1] = MT_Matrix3x3( // 90<39> - Bottom
-s, c, 0.0,
0.0,0.0, 1.0,
s, c, 0.0);
m_locRot[2] = MT_Matrix3x3( // 45<34> - Left
c, 0.0, s,
0, 1.0, 0.0,
-s, 0.0, c);
m_locRot[3] = MT_Matrix3x3( // 45<34> - Right
c, 0.0, -s,
0.0, 1.0, 0.0,
s, 0.0, c);
} else if ((m_mode == DOME_FISHEYE && m_angle > 180)){
m_locRot[0] = MT_Matrix3x3( // 90<39> - Top
1.0, 0.0, 0.0,
0.0, 0.0,-1.0,
0.0, 1.0, 0.0);
m_locRot[1] = MT_Matrix3x3( // 90<39> - Bottom
1.0, 0.0, 0.0,
0.0, 0.0, 1.0,
0.0,-1.0, 0.0);
m_locRot[2] = MT_Matrix3x3( // -90<39> - Left
0.0, 0.0, 1.0,
0.0, 1.0, 0.0,
-1.0, 0.0, 0.0);
m_locRot[3] = MT_Matrix3x3( // 90<39> - Right
0.0, 0.0,-1.0,
0.0, 1.0, 0.0,
1.0, 0.0, 0.0);
m_locRot[4] = MT_Matrix3x3( // 0<> - Front
1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0);
m_locRot[5] = MT_Matrix3x3( // 180<38> - Back - NOT USING
-1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0,-1.0);
} else if (m_mode == DOME_PANORAM_SPH){
m_locRot[0] = MT_Matrix3x3( // Top
c, s, 0.0,
0.0,0.0, -1.0,
-s, c, 0.0);
m_locRot[1] = MT_Matrix3x3( // Bottom
c, s, 0.0,
0.0 ,0.0, 1.0,
s, -c, 0.0);
m_locRot[2] = MT_Matrix3x3( // 45<34> - Left
-s, 0.0, c,
0, 1.0, 0.0,
-c, 0.0, -s);
m_locRot[3] = MT_Matrix3x3( // 45<34> - Right
c, 0.0, s,
0, 1.0, 0.0,
-s, 0.0, c);
m_locRot[4] = MT_Matrix3x3( // 135<33> - LeftBack
-s, 0.0, -c,
0.0, 1.0, 0.0,
c, 0.0, -s);
m_locRot[5] = MT_Matrix3x3( // 135<33> - RightBack
c, 0.0, -s,
0.0, 1.0, 0.0,
s, 0.0, c);
}
}
void KX_Dome::RotateCamera(KX_Camera* cam, int i)
{
// I'm not using it, I'm doing inline calls for these commands
// but it's nice to have it here in case I need it
MT_Matrix3x3 camori = cam->GetSGNode()->GetLocalOrientation();
cam->NodeSetLocalOrientation(camori*m_locRot[i]);
cam->NodeUpdateGS(0.f);
MT_Transform camtrans(cam->GetWorldToCamera());
MT_Matrix4x4 viewmat(camtrans);
m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(),
cam->GetCameraLocation(), cam->GetCameraOrientation());
cam->SetModelviewMatrix(viewmat);
// restore the original orientation
cam->NodeSetLocalOrientation(camori);
cam->NodeUpdateGS(0.f);
}
void KX_Dome::Draw(void)
{
switch(m_mode){
case DOME_FISHEYE:
DrawDomeFisheye();
break;
case DOME_TRUNCATED:
DrawDomeFisheye();
break;
case DOME_PANORAM_SPH:
DrawPanorama();
break;
}
if(warp.usemesh)
{
glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_viewport.GetLeft(), m_viewport.GetBottom(), warp.bufferwidth, warp.bufferheight);
DrawDomeWarped();
}
}
void KX_Dome::DrawDomeFisheye(void)
{
int i,j;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Making the viewport always square
int can_width = m_viewport.GetRight();
int can_height = m_viewport.GetTop();
float ortho_width, ortho_height;
if (warp.usemesh)
glOrtho((-1.0), 1.0, (-1.0), 1.0, -20.0, 10.0); //stretch the image to reduce resolution lost
else if(m_mode == DOME_TRUNCATED){
ortho_width = 1.0;
ortho_height = 2 * ((float)can_height/can_width) - 1.0 ;
ortho_width /= m_size;
ortho_height /= m_size;
glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_width, -20.0, 10.0);
} else {
if (can_width < can_height){
ortho_width = 1.0;
ortho_height = (float)can_height/can_width;
}else{
ortho_width = (float)can_width/can_height;
ortho_height = 1.0;
}
ortho_width /= m_size;
ortho_height /= m_size;
glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0);
}
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,-1.0,0.0, 0.0,0.0,0.0, 0.0,0.0,1.0);
if(m_drawingmode == RAS_IRasterizer::KX_WIREFRAME)
glPolygonMode(GL_FRONT, GL_LINE);
else
glPolygonMode(GL_FRONT, GL_FILL);
glShadeModel(GL_SMOOTH);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glColor3f(1.0,1.0,1.0);
if (dlistSupported){
for(i=0;i<m_numfaces;i++){
glBindTexture(GL_TEXTURE_2D, domefacesId[i]);
glCallList(dlistId+i);
}
}
else { // DisplayLists not supported
// top triangle
glBindTexture(GL_TEXTURE_2D, domefacesId[0]);
GLDrawTriangles(cubetop, nfacestop);
// bottom triangle
glBindTexture(GL_TEXTURE_2D, domefacesId[1]);
GLDrawTriangles(cubebottom, nfacesbottom);
// left triangle
glBindTexture(GL_TEXTURE_2D, domefacesId[2]);
GLDrawTriangles(cubeleft, nfacesleft);
// right triangle
glBindTexture(GL_TEXTURE_2D, domefacesId[3]);
GLDrawTriangles(cuberight, nfacesright);
if (m_angle > 180){
// front triangle
glBindTexture(GL_TEXTURE_2D, domefacesId[4]);
GLDrawTriangles(cubefront, nfacesfront);
}
}
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
}
void KX_Dome::DrawPanorama(void)
{
int i,j;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Making the viewport always square
int can_width = m_viewport.GetRight();
int can_height = m_viewport.GetTop();
float ortho_height = 1.0;
float ortho_width = 1.0;
if (warp.usemesh)
glOrtho((-1.0), 1.0, (-0.5), 0.5, -20.0, 10.0); //stretch the image to reduce resolution lost
else {
//using all the screen
if ((can_width / 2) <= (can_height)){
ortho_width = 1.0;
ortho_height = (float)can_height/can_width;
}else{
ortho_width = (float)can_width/can_height * 0.5;
ortho_height = 0.5;
}
ortho_width /= m_size;
ortho_height /= m_size;
glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0);
}
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0,-1.0,0.0, 0.0,0.0,0.0, 0.0,0.0,1.0);
if(m_drawingmode == RAS_IRasterizer::KX_WIREFRAME)
glPolygonMode(GL_FRONT, GL_LINE);
else
glPolygonMode(GL_FRONT, GL_FILL);
glShadeModel(GL_SMOOTH);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glColor3f(1.0,1.0,1.0);
if (dlistSupported){
for(i=0;i<m_numfaces;i++){
glBindTexture(GL_TEXTURE_2D, domefacesId[i]);
glCallList(dlistId+i);
}
}
else {
// domefacesId[4] => (top)
glBindTexture(GL_TEXTURE_2D, domefacesId[0]);
GLDrawTriangles(cubetop, nfacestop);
// domefacesId[5] => (bottom)
glBindTexture(GL_TEXTURE_2D, domefacesId[1]);
GLDrawTriangles(cubebottom, nfacesbottom);
// domefacesId[1] => -45<34> (left)
glBindTexture(GL_TEXTURE_2D, domefacesId[2]);
GLDrawTriangles(cubeleft, nfacesleft);
// domefacesId[2] => 45<34> (right)
glBindTexture(GL_TEXTURE_2D, domefacesId[3]);
GLDrawTriangles(cuberight, nfacesright);
// domefacesId[0] => -135<33> (leftback)
glBindTexture(GL_TEXTURE_2D, domefacesId[4]);
GLDrawTriangles(cubeleftback, nfacesleftback);
// domefacesId[3] => 135<33> (rightback)
glBindTexture(GL_TEXTURE_2D, domefacesId[5]);
GLDrawTriangles(cuberightback, nfacesrightback);
}
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
}
void KX_Dome::DrawDomeWarped(void)
{
int i,j;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// Making the viewport always square
int can_width = m_viewport.GetRight();
int can_height = m_viewport.GetTop();
double screen_ratio = can_width/ (double) can_height;
screen_ratio /= m_size;
glOrtho(-screen_ratio,screen_ratio,-1.0,1.0,-20.0,10.0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0, 0.0, 1.0, 0.0,0.0,0.0, 0.0,1.0,0.0);
if(m_drawingmode == RAS_IRasterizer::KX_WIREFRAME)
glPolygonMode(GL_FRONT, GL_LINE);
else
glPolygonMode(GL_FRONT, GL_FILL);
glShadeModel(GL_SMOOTH);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glColor3f(1.0,1.0,1.0);
float uv_width = (float)(warp.bufferwidth-1) / warp.imagewidth;
float uv_height = (float)(warp.bufferheight-1) / warp.imageheight;
if (dlistSupported){
glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]);
glCallList(dlistId + m_numfaces);
}
else{
glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]);
GLDrawWarpQuads();
}
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
}
void KX_Dome::BindImages(int i)
{
glBindTexture(GL_TEXTURE_2D, domefacesId[i]);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_viewport.GetLeft(), m_viewport.GetBottom(), m_buffersize, m_buffersize);
}
void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i)
{
if (!cam)
return;
m_canvas->SetViewPort(0,0,m_buffersize-1,m_buffersize-1);
// m_rasterizer->SetAmbient();
m_rasterizer->DisplayFog();
CalculateFrustum(cam); //calculates m_projmat
cam->SetProjectionMatrix(m_projmat);
m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix());
// Dome_RotateCamera(cam,i);
MT_Matrix3x3 camori = cam->GetSGNode()->GetLocalOrientation();
cam->NodeSetLocalOrientation(camori*m_locRot[i]);
cam->NodeUpdateGS(0.f);
MT_Transform camtrans(cam->GetWorldToCamera());
MT_Matrix4x4 viewmat(camtrans);
m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(),
cam->GetCameraLocation(), cam->GetCameraOrientation());
cam->SetModelviewMatrix(viewmat);
scene->CalculateVisibleMeshes(m_rasterizer,cam);
scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
// restore the original orientation
cam->NodeSetLocalOrientation(camori);
cam->NodeUpdateGS(0.f);
}

View File

@@ -0,0 +1,183 @@
/* $Id$
-----------------------------------------------------------------------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.
Contributor(s): Dalai Felinto
This source uses some of the ideas and code from Paul Bourke.
Developed as part of a Research and Development project for SAT - La Soci<63>t<EFBFBD> des arts technologiques.
-----------------------------------------------------------------------------
*/
#if !defined KX_DOME_H
#define KX_DOME_H
#include "KX_Scene.h"
#include "KX_Camera.h"
#include "DNA_screen_types.h"
#include "RAS_ICanvas.h"
#include "RAS_IRasterizer.h"
#include "RAS_IRenderTools.h"
#include "KX_KetsjiEngine.h"
#include <BIF_gl.h>
#include <vector>
#include "MEM_guardedalloc.h"
#include "BKE_text.h"
//#include "BLI_blenlib.h"
//Dome modes: limit hardcoded in buttons_scene.c
#define DOME_FISHEYE 1
#define DOME_TRUNCATED 2
#define DOME_PANORAM_SPH 3
#define DOME_NUM_MODES 4
/// class for render 3d scene
class KX_Dome
{
public:
/// constructor
KX_Dome (
RAS_ICanvas* m_canvas,
/// rasterizer
RAS_IRasterizer* m_rasterizer,
/// render tools
RAS_IRenderTools* m_rendertools,
/// engine
KX_KetsjiEngine* m_engine,
float size,
short res,
short mode,
short angle,
float resbuf,
struct Text* warptext
);
/// destructor
virtual ~KX_Dome (void);
//openGL checks:
bool dlistSupported;
//openGL names:
GLuint domefacesId[7]; // ID of the images -- room for 7 images, using only 4 for 180<38> x 360<36> dome, 6 for panoramic and +1 for warp mesh
GLuint dlistId; // ID of the Display Lists of the images (used as an offset)
typedef struct {
double u[3], v[3];
MT_Vector3 verts[3]; //three verts
} DomeFace;
//mesh warp functions
typedef struct {
double x, y, u, v, i;
} WarpMeshNode;
struct {
bool usemesh;
int mode;
int n_width, n_height; //nodes width and height
int imagewidth, imageheight;
int bufferwidth, bufferheight;
vector <vector <WarpMeshNode> > nodes;
} warp;
bool ParseWarpMesh(STR_String text);
vector <DomeFace> cubetop, cubebottom, cuberight, cubeleft, cubefront, cubeback; //for fisheye
vector <DomeFace> cubeleftback, cuberightback; //for panorama
int nfacestop, nfacesbottom, nfacesleft, nfacesright, nfacesfront, nfacesback;
int nfacesleftback, nfacesrightback;
int GetNumberRenders(){return m_numfaces;};
void RenderDome(void);
void RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i);
void BindImages(int i);
void SetViewPort(GLuint viewport[4]);
void CalculateFrustum(KX_Camera* cam);
void RotateCamera(KX_Camera* cam, int i);
//Mesh Creating Functions
void CreateMeshDome180(void);
void CreateMeshDome250(void);
void CreateMeshPanorama(void);
void SplitFace(vector <DomeFace>& face, int *nfaces);
void FlattenDome(MT_Vector3 verts[3]);
void FlattenPanorama(MT_Vector3 verts[3]);
//Draw functions
void GLDrawTriangles(vector <DomeFace>& face, int nfaces);
void GLDrawWarpQuads(void);
void Draw(void);
void DrawDomeFisheye(void);
void DrawPanorama(void);
void DrawDomeWarped(void);
//setting up openGL
void CreateGLImages(void);
void ClearGLImages(void);//called on resize
bool CreateDL(void); //create Display Lists
void ClearDL(void); //remove Display Lists
void CalculateCameraOrientation();
void CalculateImageSize(); //set m_imagesize
int canvaswidth;
int canvasheight;
protected:
int m_drawingmode;
int m_imagesize;
int m_buffersize; // canvas small dimension
int m_numfaces; // 4 to 6 depending on the kind of dome image
int m_numimages; //numfaces +1 if we have warp mesh
float m_size; // size to adjust
short m_resolution; //resolution to tesselate the mesh
short m_mode; // the mode (truncated, warped, panoramic,...)
short m_angle; //the angle of the fisheye
float m_radangle; //the angle of the fisheye in radians
float m_resbuffer; //the resolution of the buffer
RAS_Rect m_viewport;
MT_Matrix4x4 m_projmat;
MT_Matrix3x3 m_locRot [6];// the rotation matrix
/// rendered scene
KX_Scene * m_scene;
/// canvas
RAS_ICanvas* m_canvas;
/// rasterizer
RAS_IRasterizer* m_rasterizer;
/// render tools
RAS_IRenderTools* m_rendertools;
/// engine
KX_KetsjiEngine* m_engine;
};
#endif

View File

@@ -55,6 +55,7 @@
#include "KX_Scene.h"
#include "MT_CmMatrix4x4.h"
#include "KX_Camera.h"
#include "KX_Dome.h"
#include "KX_Light.h"
#include "KX_PythonInit.h"
#include "KX_PyConstraintBinding.h"
@@ -144,6 +145,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_stereo(false),
m_curreye(0),
m_usedome(false),
m_logger(NULL),
// Set up timing info display variables
@@ -179,6 +182,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
KX_KetsjiEngine::~KX_KetsjiEngine()
{
delete m_logger;
if(m_usedome)
delete m_dome;
}
@@ -256,7 +261,124 @@ void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter* sceneconverter)
m_sceneconverter = sceneconverter;
}
void KX_KetsjiEngine::InitDome(float size, short res, short mode, short angle, float resbuf, struct Text* text)
{
m_dome = new KX_Dome(m_canvas, m_rasterizer, m_rendertools,this, size, res, mode, angle, resbuf, text);
m_usedome = true;
}
void KX_KetsjiEngine::RenderDome()
{
GLuint viewport[4]={0};
glGetIntegerv(GL_VIEWPORT,(GLint *)viewport);
// unsigned int m_viewport[4] = {viewport[0], viewport[1], viewport[2], viewport[3]};
m_dome->SetViewPort(viewport);
KX_Scene* firstscene = *m_scenes.begin();
const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
// hiding mouse cursor each frame
// (came back when going out of focus and then back in again)
if (m_hideCursor)
m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
// clear the entire game screen with the border color
// only once per frame
m_canvas->BeginDraw();
// BeginFrame() sets the actual drawing area. You can use a part of the window
if (!BeginFrame())
return;
int n_renders=m_dome->GetNumberRenders();// usually 4 or 6
KX_SceneList::iterator sceneit;
for (int i=0;i<n_renders;i++){
m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
// for each scene, call the proceed functions
{
KX_Scene* scene = *sceneit;
KX_Camera* cam = scene->GetActiveCamera();
m_rendertools->BeginFrame(m_rasterizer);
// pass the scene's worldsettings to the rasterizer
SetWorldSettings(scene->GetWorldInfo());
// shadow buffers
if (i == 0){
RenderShadowBuffers(scene);
scene->UpdateMeshTransformations();//I need to run it somewherelse, otherwise Im overrunning it
}
// Avoid drawing the scene with the active camera twice when it's viewport is enabled
if(cam && !cam->GetViewport())
{
if (scene->IsClearingZBuffer())
m_rasterizer->ClearDepthBuffer();
m_rendertools->SetAuxilaryClientInfo(scene);
// do the rendering
m_dome->RenderDomeFrame(scene,cam, i);
}
list<class KX_Camera*>* cameras = scene->GetCameras();
// Draw the scene once for each camera with an enabled viewport
list<KX_Camera*>::iterator it = cameras->begin();
while(it != cameras->end())
{
if((*it)->GetViewport())
{
if (scene->IsClearingZBuffer())
m_rasterizer->ClearDepthBuffer();
m_rendertools->SetAuxilaryClientInfo(scene);
// do the rendering
m_dome->RenderDomeFrame(scene, (*it),i);
}
it++;
}
}
m_dome->BindImages(i);
}
// m_dome->Dome_PostRender(scene, cam, stereomode);
m_canvas->EndFrame();//XXX do we really need that?
m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
if (m_overrideFrameColor) //XXX why do we want
{
// Do not use the framing bar color set in the Blender scenes
m_canvas->ClearColor(
m_overrideFrameColorR,
m_overrideFrameColorG,
m_overrideFrameColorB,
1.0
);
}
else
{
// Use the framing bar color set in the Blender scenes
m_canvas->ClearColor(
framesettings.BarRed(),
framesettings.BarGreen(),
framesettings.BarBlue(),
1.0
);
}
m_dome->Draw();
//run 2dfilters
EndFrame();
}
/**
* Ketsji Init(), Initializes datastructures and converts data from
@@ -631,6 +753,10 @@ else
void KX_KetsjiEngine::Render()
{
if(m_usedome){
RenderDome();
return;
}
KX_Scene* firstscene = *m_scenes.begin();
const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
@@ -1699,4 +1825,3 @@ void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const
}

View File

@@ -74,6 +74,7 @@ private:
PyObject* m_pythondictionary;
class SCA_IInputDevice* m_keyboarddevice;
class SCA_IInputDevice* m_mousedevice;
class KX_Dome* m_dome; // dome stereo mode
/** Lists of scenes scheduled to be removed at the end of the frame. */
std::set<STR_String> m_removingScenes;
@@ -208,6 +209,12 @@ public:
RAS_ICanvas* GetCanvas(){return m_canvas;};
RAS_IRenderTools* GetRenderTools(){return m_rendertools;};
/// Dome functions
void InitDome(float size, short res, short mode, short angle, float resbuf, struct Text* text);
void EndDome();
void RenderDome();
bool m_usedome;
///returns true if an update happened to indicate -> Render
bool NextFrame();
void Render();
@@ -234,6 +241,8 @@ public:
void GetSceneViewport(KX_Scene* scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport);
void SetDrawType(int drawingtype);
int GetDrawType(){return m_drawingmode;};
void SetCameraZoom(float camzoom);
void EnableCameraOverride(const STR_String& forscene);

View File

@@ -113,6 +113,7 @@ public:
RAS_STEREO_ANAGLYPH,
RAS_STEREO_SIDEBYSIDE,
RAS_STEREO_VINTERLACE,
RAS_STEREO_DOME,
RAS_STEREO_MAXSTEREO
};

View File

@@ -436,7 +436,7 @@ RAS_IRasterizer::StereoMode RAS_OpenGLRasterizer::GetStereoMode()
bool RAS_OpenGLRasterizer::Stereo()
{
if(m_stereomode == RAS_STEREO_NOSTEREO)
if(m_stereomode == RAS_STEREO_NOSTEREO || m_stereomode == RAS_STEREO_DOME)
return false;
else
return true;
@@ -803,7 +803,7 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix(
double mat[16];
// correction for stereo
if(m_stereomode != RAS_STEREO_NOSTEREO)
if(Stereo())
{
float near_div_focallength;
// next 2 params should be specified on command line and in Blender publisher
@@ -846,7 +846,7 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Vecto
m_viewmatrix = mat;
// correction for stereo
if(m_stereomode != RAS_STEREO_NOSTEREO)
if(Stereo())
{
MT_Matrix3x3 camOrientMat3x3(camOrientQuat);
MT_Vector3 unitViewDir(0.0, -1.0, 0.0); // minus y direction, Blender convention