/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * 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été des arts technologiques. * * ***** END GPL LICENSE BLOCK ***** */ /** \file gameengine/Ketsji/KX_Dome.cpp * \ingroup ketsji */ #include "KX_Dome.h" #ifdef WITH_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, /// 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_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 const int *viewport = m_canvas->GetViewPort(); 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(const int 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(); m_buffersize = (canvaswidth > canvasheight?canvasheight:canvaswidth); m_buffersize = (int)(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 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; } } 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 = DEG2RADF(m_angle); //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.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;im_radangle / 2.0; 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 (360deg) int i; double phi, theta; 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; theta = asin(verts[i][2]); verts[i][2] = theta / MT_PI; } 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()); #endif 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.0f * ((float)can_height / can_width) - 1.0f; 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.0f * ((float)can_height / can_width) - 1.0f; 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.5f; ortho_height = 0.5f; } 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); }