/* $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 Socidegtdeg des arts technologiques. ----------------------------------------------------------------------------- */ #include "KX_Dome.h" #ifndef DISABLE_PYTHON #include #endif #include #include #include "DNA_scene_types.h" #include "RAS_CameraData.h" #include "BLI_math.h" #include "GL/glew.h" // constructor KX_Dome::KX_Dome ( RAS_ICanvas* canvas, /// rasterizer RAS_IRasterizer* rasterizer, /// render tools RAS_IRenderTools* rendertools, /// engine KX_KetsjiEngine* engine, short res, //resolution of the mesh short mode, //mode - fisheye, truncated, warped, panoramic, ... short angle, float resbuf, //size adjustment of the buffer short tilt, struct Text* warptext ): dlistSupported(false), canvaswidth(-1), canvasheight(-1), m_drawingmode(engine->GetDrawType()), m_resolution(res), m_mode(mode), m_angle(angle), m_resbuffer(resbuf), m_tilt(tilt), m_canvas(canvas), m_rasterizer(rasterizer), m_rendertools(rendertools), m_engine(engine) { warp.usemesh = false; fboSupported = 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_ENVMAP: m_angle = 360; m_numfaces = 6; 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; default: //DOME_TRUNCATED_FRONT and DOME_TRUNCATED_REAR 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; } m_numimages =(warp.usemesh?m_numfaces+1:m_numfaces); CalculateCameraOrientation(); CreateGLImages(); if(warp.usemesh) fboSupported = CreateFBO(); dlistSupported = CreateDL(); } // destructor KX_Dome::~KX_Dome (void) { ClearGLImages(); if(fboSupported) glDeleteFramebuffersEXT(1, &warp.fboId); if(dlistSupported) glDeleteLists(dlistId, (GLsizei) m_numimages); } void KX_Dome::SetViewPort(GLuint viewport[4]) { if(canvaswidth != m_viewport.GetWidth() || canvasheight != m_viewport.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;jGetWidth(); canvasheight = m_canvas->GetHeight(); bool fullscreen(false); //XXX HACK fullscreen = (canvaswidth != m_viewport.GetWidth()); m_buffersize = (canvaswidth > canvasheight?canvasheight:canvaswidth); m_buffersize = (int)(m_buffersize*m_resbuffer); //reduce buffer size for better performance if (fullscreen) //XXX HACK m_buffersize --; int i = 0; while ((1 << i) <= m_buffersize) i++; m_imagesize = (1 << i); if (warp.usemesh){ // warp FBO needs to be up to twice as big as m_buffersize to get more resolution warp.imagesize = m_imagesize; if (m_buffersize == m_imagesize) warp.imagesize *= 2; //if FBO is not working/supported, we use the canvas dimension as buffer warp.bufferwidth = canvaswidth; warp.bufferheight = canvasheight; } //XXX HACK canvaswidth = m_viewport.GetWidth(); canvasheight = m_viewport.GetHeight(); } bool KX_Dome::CreateDL(){ dlistId = glGenLists((GLsizei) m_numimages); if (dlistId != 0) { if(m_mode == DOME_FISHEYE || m_mode == DOME_TRUNCATED_FRONT || m_mode == DOME_TRUNCATED_REAR){ 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; } bool KX_Dome::CreateFBO(void) { if (!GLEW_EXT_framebuffer_object) { printf("Dome Error: FrameBuffer unsupported. Using low resolution warp image."); return false; } glGenFramebuffersEXT(1, &warp.fboId); if(warp.fboId==0) { printf("Dome Error: Invalid frame buffer object. Using low resolution warp image."); return false; } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, warp.fboId); glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, domefacesId[m_numfaces], 0); GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); if(status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) { printf("Dome Error: FrameBuffer settings unsupported. Using low resolution warp image."); return false; } else if(status != GL_FRAMEBUFFER_COMPLETE_EXT) { glDeleteFramebuffersEXT(1, &warp.fboId); return false; } glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); //nothing failed: we can use the whole FBO as buffersize warp.bufferwidth = warp.bufferheight = warp.imagesize; return true; } void KX_Dome::GLDrawTriangles(vector & face, int nfaces) { int i,j; glBegin(GL_TRIANGLES); for (i=0;i columns, lines; lines = text.Explode('\n'); if(lines.size() < 6){ printf("Dome Error: Warp Mesh File with insufficient data!\n"); return false; } columns = lines[1].Explode(' '); if(columns.size() == 1) columns = lines[1].Explode('\t'); if(columns.size() !=2){ printf("Dome 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 ((int)lines.size() < 2 + (warp.n_width * warp.n_height)){ printf("Dome Error: Warp Mesh File with insufficient data!\n"); return false; }else{ warp.nodes = vector > (warp.n_height, vector(warp.n_width)); for(i=2; i-2 < (warp.n_width*warp.n_height); i++){ columns = lines[i].Explode(' '); if(columns.size() == 1) columns = lines[i].Explode('\t'); 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("Dome 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 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 180deg Dome // Top Face - just a triangle cubetop[0].verts[0][0] = -M_SQRT2 / 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] = M_SQRT2 / 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] = M_SQRT2 / 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] = -M_SQRT2 / 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] = M_SQRT2 / 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] = M_SQRT2 / 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] = -M_SQRT2 / 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] = M_SQRT2 / 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] = -M_SQRT2 / 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] = -M_SQRT2 / 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] = M_SQRT2 / 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] = M_SQRT2 / 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] = M_SQRT2 / 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] = M_SQRT2 / 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] = M_SQRT2 / 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] = M_SQRT2 / 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] = M_SQRT2 / 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] = M_SQRT2 / 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 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 (360deg) 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 & face, int *nfaces) { int i; int n1, n2; n1 = n2 = *nfaces; for(i=0;iGetCameraNear(),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 = 90deg, 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 180deg Uses 5 cameras for angles up to 250deg Uses 6 cameras for angles up to 360deg */ int i; float deg45 = MT_PI / 4; MT_Scalar c = cos(deg45); MT_Scalar s = sin(deg45); if (m_angle <= 180 && (m_mode == DOME_FISHEYE || m_mode == DOME_TRUNCATED_FRONT || m_mode == DOME_TRUNCATED_REAR)){ m_locRot[0] = MT_Matrix3x3( // 90deg - Top c, -s, 0.0, 0.0,0.0, -1.0, s, c, 0.0); m_locRot[1] = MT_Matrix3x3( // 90deg - Bottom -s, c, 0.0, 0.0,0.0, 1.0, s, c, 0.0); m_locRot[2] = MT_Matrix3x3( // 45deg - Left c, 0.0, s, 0, 1.0, 0.0, -s, 0.0, c); m_locRot[3] = MT_Matrix3x3( // 45deg - Right c, 0.0, -s, 0.0, 1.0, 0.0, s, 0.0, c); } else if (m_mode == DOME_ENVMAP || (m_angle > 180 && (m_mode == DOME_FISHEYE || m_mode == DOME_TRUNCATED_FRONT || m_mode == DOME_TRUNCATED_REAR))){ m_locRot[0] = MT_Matrix3x3( // 90deg - Top 1.0, 0.0, 0.0, 0.0, 0.0,-1.0, 0.0, 1.0, 0.0); m_locRot[1] = MT_Matrix3x3( // 90deg - Bottom 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0,-1.0, 0.0); m_locRot[2] = MT_Matrix3x3( // -90deg - Left 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, -1.0, 0.0, 0.0); m_locRot[3] = MT_Matrix3x3( // 90deg - Right 0.0, 0.0,-1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0); m_locRot[4] = MT_Matrix3x3( // 0deg - Front 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0); m_locRot[5] = MT_Matrix3x3( // 180deg - Back - USED for ENVMAP only -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( // 45deg - Left -s, 0.0, c, 0, 1.0, 0.0, -c, 0.0, -s); m_locRot[3] = MT_Matrix3x3( // 45deg - Right c, 0.0, s, 0, 1.0, 0.0, -s, 0.0, c); m_locRot[4] = MT_Matrix3x3( // 135deg - LeftBack -s, 0.0, -c, 0.0, 1.0, 0.0, c, 0.0, -s); m_locRot[5] = MT_Matrix3x3( // 135deg - RightBack c, 0.0, -s, 0.0, 1.0, 0.0, s, 0.0, c); } // rotating the camera in horizontal axis if (m_tilt) { float tiltdeg = ((m_tilt % 360) * 2 * MT_PI) / 360; c = cos(tiltdeg); s = sin(tiltdeg); MT_Matrix3x3 tilt_mat = MT_Matrix3x3( 1.0, 0.0, 0.0, 0.0, c, -s, 0.0, s, c ); for (i =0;i<6;i++) m_locRot[i] = tilt_mat * m_locRot[i]; } } 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->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), cam->GetCameraData()->m_perspective); cam->SetModelviewMatrix(viewmat); // restore the original orientation cam->NodeSetLocalOrientation(camori); cam->NodeUpdateGS(0.f); } void KX_Dome::Draw(void) { if (fboSupported){ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, warp.fboId); glViewport(0,0,warp.imagesize, warp.imagesize); glScissor(0,0,warp.imagesize, warp.imagesize); } switch(m_mode){ case DOME_FISHEYE: DrawDomeFisheye(); break; case DOME_ENVMAP: DrawEnvMap(); break; case DOME_PANORAM_SPH: DrawPanorama(); break; case DOME_TRUNCATED_FRONT: DrawDomeFisheye(); break; case DOME_TRUNCATED_REAR: DrawDomeFisheye(); break; } if(warp.usemesh) { if(fboSupported) { m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight()); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } else { 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::DrawEnvMap(void) { 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, (-0.66), 0.66, -20.0, 10.0); //stretch the image to reduce resolution lost else { if (can_width/3 <= can_height/2){ ortho_width = 1.0; ortho_height = (float)can_height/can_width; }else{ ortho_height = 2.0f / 3; ortho_width = (float)can_width/can_height * ortho_height; } glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -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); 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_ratio = (float)(m_buffersize-1) / m_imagesize; double onebythree = 1.0f / 3; // domefacesId[0] => (top) glBindTexture(GL_TEXTURE_2D, domefacesId[0]); glBegin(GL_QUADS); glTexCoord2f(uv_ratio,uv_ratio); glVertex3f( onebythree, 0.0f, 3.0f); glTexCoord2f(0.0,uv_ratio); glVertex3f(-onebythree, 0.0f, 3.0f); glTexCoord2f(0.0,0.0); glVertex3f(-onebythree,-2 * onebythree, 3.0f); glTexCoord2f(uv_ratio,0.0); glVertex3f(onebythree,-2 * onebythree, 3.0f); glEnd(); // domefacesId[1] => (bottom) glBindTexture(GL_TEXTURE_2D, domefacesId[1]); glBegin(GL_QUADS); glTexCoord2f(uv_ratio,uv_ratio); glVertex3f(-onebythree, 0.0f, 3.0f); glTexCoord2f(0.0,uv_ratio); glVertex3f(-1.0f, 0.0f, 3.0f); glTexCoord2f(0.0,0.0); glVertex3f(-1.0f,-2 * onebythree, 3.0f); glTexCoord2f(uv_ratio,0.0); glVertex3f(-onebythree,-2 * onebythree, 3.0f); glEnd(); // domefacesId[2] => -90deg (left) glBindTexture(GL_TEXTURE_2D, domefacesId[2]); glBegin(GL_QUADS); glTexCoord2f(uv_ratio,uv_ratio); glVertex3f(-onebythree, 2 * onebythree, 3.0f); glTexCoord2f(0.0,uv_ratio); glVertex3f(-1.0f, 2 * onebythree, 3.0f); glTexCoord2f(0.0,0.0); glVertex3f(-1.0f, 0.0f, 3.0f); glTexCoord2f(uv_ratio,0.0); glVertex3f(-onebythree, 0.0f, 3.0f); glEnd(); // domefacesId[3] => 90deg (right) glBindTexture(GL_TEXTURE_2D, domefacesId[3]); glBegin(GL_QUADS); glTexCoord2f(uv_ratio,uv_ratio); glVertex3f( 1.0f, 2 * onebythree, 3.0f); glTexCoord2f(0.0,uv_ratio); glVertex3f( onebythree, 2 * onebythree, 3.0f); glTexCoord2f(0.0,0.0); glVertex3f( onebythree, 0.0f, 3.0f); glTexCoord2f(uv_ratio,0.0); glVertex3f(1.0f, 0.0f, 3.0f); glEnd(); // domefacesId[4] => 0deg (front) glBindTexture(GL_TEXTURE_2D, domefacesId[4]); glBegin(GL_QUADS); glTexCoord2f(uv_ratio,uv_ratio); glVertex3f( 1.0f, 0.0f, 3.0f); glTexCoord2f(0.0,uv_ratio); glVertex3f( onebythree, 0.0f, 3.0f); glTexCoord2f(0.0,0.0); glVertex3f( onebythree,-2 * onebythree, 3.0f); glTexCoord2f(uv_ratio,0.0); glVertex3f(1.0f, -2 * onebythree, 3.0f); glEnd(); // domefacesId[5] => 180deg (back) glBindTexture(GL_TEXTURE_2D, domefacesId[5]); glBegin(GL_QUADS); glTexCoord2f(uv_ratio,uv_ratio); glVertex3f( onebythree, 2 * onebythree, 3.0f); glTexCoord2f(0.0,uv_ratio); glVertex3f(-onebythree, 2 * onebythree, 3.0f); glTexCoord2f(0.0,0.0); glVertex3f(-onebythree, 0.0f, 3.0f); glTexCoord2f(uv_ratio,0.0); glVertex3f(onebythree, 0.0f, 3.0f); glEnd(); glDisable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); } void KX_Dome::DrawDomeFisheye(void) { int i; 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(m_mode == DOME_FISHEYE) { 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 (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; } glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0); } } else if(m_mode == DOME_TRUNCATED_FRONT) { ortho_width = 1.0; ortho_height = 2 * ((float)can_height/can_width) - 1.0 ; glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_width, -20.0, 10.0); } else { //m_mode == DOME_TRUNCATED_REAR ortho_width = 1.0; ortho_height = 2 * ((float)can_height/can_width) - 1.0 ; glOrtho((-ortho_width), ortho_width, (-ortho_width), 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 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; 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; } 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 (top) glBindTexture(GL_TEXTURE_2D, domefacesId[0]); GLDrawTriangles(cubetop, nfacestop); // domefacesId[5] => (bottom) glBindTexture(GL_TEXTURE_2D, domefacesId[1]); GLDrawTriangles(cubebottom, nfacesbottom); // domefacesId[1] => -45deg (left) glBindTexture(GL_TEXTURE_2D, domefacesId[2]); GLDrawTriangles(cubeleft, nfacesleft); // domefacesId[2] => 45deg (right) glBindTexture(GL_TEXTURE_2D, domefacesId[3]); GLDrawTriangles(cuberight, nfacesright); // domefacesId[0] => -135deg (leftback) glBindTexture(GL_TEXTURE_2D, domefacesId[4]); GLDrawTriangles(cubeleftback, nfacesleftback); // domefacesId[3] => 135deg (rightback) glBindTexture(GL_TEXTURE_2D, domefacesId[5]); GLDrawTriangles(cuberightback, nfacesrightback); } glDisable(GL_TEXTURE_2D); glEnable(GL_DEPTH_TEST); } void KX_Dome::DrawDomeWarped(void) { 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; 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); 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->NodeGetWorldOrientation(), cam->NodeGetWorldPosition(), 1.0); cam->SetModelviewMatrix(viewmat); // restore the original orientation cam->NodeSetLocalOrientation(camori); cam->NodeUpdateGS(0.f); scene->CalculateVisibleMeshes(m_rasterizer,cam); scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools); }