2 -----------------------------------------------------------------------------
4 This program is free software; you can redistribute it and/or modify it under
5 the terms of the GNU Lesser General Public License as published by the Free Software
6 Foundation; either version 2 of the License, or (at your option) any later
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
13 You should have received a copy of the GNU Lesser General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
16 http://www.gnu.org/copyleft/lesser.txt.
18 Contributor(s): Dalai Felinto
20 This code is originally inspired on some of the ideas and codes from Paul Bourke.
21 Developed as part of a Research and Development project for SAT - La Société des arts technologiques.
22 -----------------------------------------------------------------------------
27 #include <structmember.h>
31 #include "DNA_scene_types.h"
32 #include "RAS_CameraData.h"
33 #include "BLI_arithb.h"
42 RAS_IRasterizer* rasterizer,
44 RAS_IRenderTools* rendertools,
46 KX_KetsjiEngine* engine,
48 float size, //size for adjustments
49 short res, //resolution of the mesh
50 short mode, //mode - fisheye, truncated, warped, panoramic, ...
52 float resbuf, //size adjustment of the buffer
57 m_rasterizer(rasterizer),
58 m_rendertools(rendertools),
60 m_drawingmode(engine->GetDrawType()),
66 canvaswidth(-1), canvasheight(-1),
71 if (mode >= DOME_NUM_MODES)
72 m_mode = DOME_FISHEYE;
74 if (warptext) // it there is a text data try to warp it
77 buf = txt_to_buf(warptext);
80 warp.usemesh = ParseWarpMesh(STR_String(buf));
85 //setting the viewport size
86 GLuint viewport[4]={0};
87 glGetIntegerv(GL_VIEWPORT,(GLint *)viewport);
89 SetViewPort(viewport);
101 }else if (m_angle > 180){
103 cubebottom.resize(2);
113 cubebottom.resize(1);
121 case DOME_PANORAM_SPH:
123 cubeleftback.resize(2);
125 cuberightback.resize(2);
127 cubebottom.resize(2);
130 CreateMeshPanorama();
135 m_numimages =(warp.usemesh?m_numfaces+1:m_numfaces);
137 CalculateCameraOrientation();
141 dlistSupported = CreateDL();
145 KX_Dome::~KX_Dome (void)
147 GLuint m_numimages = m_numfaces;
152 glDeleteLists(dlistId, (GLsizei) m_numimages);
155 void KX_Dome::SetViewPort(GLuint viewport[4])
157 if(canvaswidth != m_canvas->GetWidth() || canvasheight != m_canvas->GetHeight())
159 m_viewport.SetLeft(viewport[0]);
160 m_viewport.SetBottom(viewport[1]);
161 m_viewport.SetRight(viewport[2]);
162 m_viewport.SetTop(viewport[3]);
164 CalculateImageSize();
168 void KX_Dome::CreateGLImages(void)
170 glGenTextures(m_numimages, (GLuint*)&domefacesId);
172 for (int j=0;j<m_numfaces;j++){
173 glBindTexture(GL_TEXTURE_2D, domefacesId[j]);
174 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, m_imagesize, m_imagesize, 0, GL_RGB8,
175 GL_UNSIGNED_BYTE, 0);
176 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, m_imagesize, m_imagesize, 0);
177 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
178 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
179 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
180 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
183 glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]);
184 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, warp.imagewidth, warp.imageheight, 0, GL_RGB8,
185 GL_UNSIGNED_BYTE, 0);
186 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, warp.imagewidth, warp.imageheight, 0);
187 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
188 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
189 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
190 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
194 void KX_Dome::ClearGLImages(void)
196 glDeleteTextures(m_numimages, (GLuint*)&domefacesId);
198 for (int i=0;i<m_numimages;i++)
199 if(glIsTexture(domefacesId[i]))
200 glDeleteTextures(1, (GLuint*)&domefacesId[i]);
204 void KX_Dome::CalculateImageSize(void)
207 - determine the minimum buffer size
208 - reduce the buffer for better performace
209 - create a power of 2 texture bigger than the buffer
212 canvaswidth = m_canvas->GetWidth();
213 canvasheight = m_canvas->GetHeight();
215 m_buffersize = (canvaswidth > canvasheight?canvasheight:canvaswidth);
216 m_buffersize *= m_resbuffer; //reduce buffer size for better performance
219 while ((1 << i) <= m_buffersize)
221 m_imagesize = (1 << i);
224 warp.bufferwidth = canvaswidth;
225 warp.bufferheight = canvasheight;
228 while ((1 << i) <= warp.bufferwidth)
230 warp.imagewidth = (1 << i);
233 while ((1 << i) <= warp.bufferheight)
235 warp.imageheight = (1 << i);
239 bool KX_Dome::CreateDL(){
242 dlistId = glGenLists((GLsizei) m_numimages);
244 if(m_mode == DOME_FISHEYE || m_mode == DOME_TRUNCATED){
245 glNewList(dlistId, GL_COMPILE);
246 GLDrawTriangles(cubetop, nfacestop);
249 glNewList(dlistId+1, GL_COMPILE);
250 GLDrawTriangles(cubebottom, nfacesbottom);
253 glNewList(dlistId+2, GL_COMPILE);
254 GLDrawTriangles(cubeleft, nfacesleft);
257 glNewList(dlistId+3, GL_COMPILE);
258 GLDrawTriangles(cuberight, nfacesright);
262 glNewList(dlistId+4, GL_COMPILE);
263 GLDrawTriangles(cubefront, nfacesfront);
267 else if (m_mode == DOME_PANORAM_SPH)
269 glNewList(dlistId, GL_COMPILE);
270 GLDrawTriangles(cubetop, nfacestop);
273 glNewList(dlistId+1, GL_COMPILE);
274 GLDrawTriangles(cubebottom, nfacesbottom);
277 glNewList(dlistId+2, GL_COMPILE);
278 GLDrawTriangles(cubeleft, nfacesleft);
281 glNewList(dlistId+3, GL_COMPILE);
282 GLDrawTriangles(cuberight, nfacesright);
285 glNewList(dlistId+4, GL_COMPILE);
286 GLDrawTriangles(cubeleftback, nfacesleftback);
289 glNewList(dlistId+5, GL_COMPILE);
290 GLDrawTriangles(cuberightback, nfacesrightback);
295 glNewList((dlistId + m_numfaces), GL_COMPILE);
300 //clearing the vectors
306 cubeleftback.clear();
307 cuberightback.clear();
310 } else // genList failed
316 void KX_Dome::GLDrawTriangles(vector <DomeFace>& face, int nfaces)
319 glBegin(GL_TRIANGLES);
320 for (i=0;i<nfaces;i++) {
322 glTexCoord2f(face[i].u[j],face[i].v[j]);
323 glVertex3f((GLfloat)face[i].verts[j][0],(GLfloat)face[i].verts[j][1],(GLfloat)face[i].verts[j][2]);
329 void KX_Dome::GLDrawWarpQuads(void)
332 float uv_width = (float)(warp.bufferwidth-1) / warp.imagewidth;
333 float uv_height = (float)(warp.bufferheight-1) / warp.imageheight;
337 for (i=0;i<warp.n_height-1;i++) {
338 for (j=0;j<warp.n_width-1;j++) {
339 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)
342 glColor3f(warp.nodes[i][j].i, warp.nodes[i][j].i, warp.nodes[i][j].i);
343 glTexCoord2f((warp.nodes[i][j].u * uv_width), (warp.nodes[i][j].v * uv_height));
344 glVertex3f(warp.nodes[i][j].x, warp.nodes[i][j].y,0.0);
346 glColor3f(warp.nodes[i+1][j].i, warp.nodes[i+1][j].i, warp.nodes[i+1][j].i);
347 glTexCoord2f((warp.nodes[i+1][j].u * uv_width), (warp.nodes[i+1][j].v * uv_height));
348 glVertex3f(warp.nodes[i+1][j].x, warp.nodes[i+1][j].y,0.0);
350 glColor3f(warp.nodes[i+1][j+1].i, warp.nodes[i+1][j+1].i, warp.nodes[i+1][j+1].i);
351 glTexCoord2f((warp.nodes[i+1][j+1].u * uv_width), (warp.nodes[i+1][j+1].v * uv_height));
352 glVertex3f(warp.nodes[i+1][j+1].x, warp.nodes[i+1][j+1].y,0.0);
354 glColor3f(warp.nodes[i][j+1].i, warp.nodes[i][j+1].i, warp.nodes[i][j+1].i);
355 glTexCoord2f((warp.nodes[i][j+1].u * uv_width), (warp.nodes[i][j+1].v * uv_height));
356 glVertex3f(warp.nodes[i][j+1].x, warp.nodes[i][j+1].y,0.0);
361 else if (warp.mode == 1){
363 for (i=0;i<warp.n_height-1;i++) {
364 for (j=0;j<warp.n_width-1;j++) {
365 i2 = (i+1) % warp.n_width; // Wrap around, i = warp.n_width = 0
367 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)
370 glColor3f(warp.nodes[i][j].i,warp.nodes[i][j].i,warp.nodes[i][j].i);
371 glTexCoord2f((warp.nodes[i][j].u * uv_width), (warp.nodes[i][j].v * uv_height));
372 glVertex3f(warp.nodes[i][j].x,warp.nodes[i][j].y,0.0);
374 glColor3f(warp.nodes[i2][j].i,warp.nodes[i2][j].i,warp.nodes[i2][j].i);
375 glTexCoord2f((warp.nodes[i2][j].u * uv_width), (warp.nodes[i2][j].v * uv_height));
376 glVertex3f(warp.nodes[i2][j].x,warp.nodes[i2][j].y,0.0);
378 glColor3f(warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i);
379 glTexCoord2f((warp.nodes[i2][j+1].u * uv_width), (warp.nodes[i2][j+1].v * uv_height));
380 glVertex3f(warp.nodes[i2][j+1].x,warp.nodes[i2][j+1].y,0.0);
382 glColor3f(warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i);
383 glTexCoord2f((warp.nodes[i2][j+1].u * uv_width), (warp.nodes[i2][j+1].v * uv_height));
384 glVertex3f(warp.nodes[i2][j+1].x,warp.nodes[i2][j+1].y,0.0);
390 printf("Error: Warp Mode unsupported. Try 1 for Polar Mesh or 2 for Fisheye.\n");
395 bool KX_Dome::ParseWarpMesh(STR_String text)
398 //Notes about the supported data format:
402 n0_x n0_y n0_u n0_v n0_i
403 n1_x n1_y n1_u n1_v n1_i
404 n2_x n1_y n2_u n2_v n2_i
405 n3_x n3_y n3_u n3_v n3_i
407 First line is the image type the mesh is support to be applied to: 2 = fisheye, 1=radial
408 Tthe next line has the mesh dimensions
409 Rest of the lines are the nodes of the mesh. Each line has x y u v i
410 (x,y) are the normalised screen coordinates
411 (u,v) texture coordinates
412 i a multiplicative intensity factor
414 x varies from -screen aspect to screen aspect
415 y varies from -1 to 1
416 u and v vary from 0 to 1
417 i ranges from 0 to 1, if negative don't draw that mesh node
420 int nodeX=0, nodeY=0;
422 vector<STR_String> columns, lines;
424 lines = text.Explode('\n');
425 if(lines.size() < 6){
426 printf("Error: Warp Mesh File with insufficient data!\n");
429 columns = lines[1].Explode(' ');
431 if(columns.size() !=2){
432 printf("Error: Warp Mesh File incorrect. The second line should contain: width height.\n");
436 warp.mode = atoi(lines[0]);// 1 = radial, 2 = fisheye
438 warp.n_width = atoi(columns[0]);
439 warp.n_height = atoi(columns[1]);
441 if (lines.size() < 2 + (warp.n_width * warp.n_height)){
442 printf("Error: Warp Mesh File with insufficient data!\n");
445 warp.nodes = vector<vector <WarpMeshNode>> (warp.n_height, vector<WarpMeshNode>(warp.n_width));
447 for(i=2; i-2 < (warp.n_width*warp.n_height); i++){
448 columns = lines[i].Explode(' ');
450 if (columns.size() == 5){
451 nodeX = (i-2)%warp.n_width;
452 nodeY = ((i-2) - nodeX) / warp.n_width;
454 warp.nodes[nodeY][nodeX].x = atof(columns[0]);
455 warp.nodes[nodeY][nodeX].y = atof(columns[1]);
456 warp.nodes[nodeY][nodeX].u = atof(columns[2]);
457 warp.nodes[nodeY][nodeX].v = atof(columns[3]);
458 warp.nodes[nodeY][nodeX].i = atof(columns[4]);
462 printf("Error: Warp Mesh File with wrong number of fields. You should use 5: x y u v i.\n");
470 void KX_Dome::CreateMeshDome180(void)
473 1)- Define the faces of half of a cube
474 - each face is made out of 2 triangles
475 2) Subdivide the faces
476 - more resolution == more curved lines
478 - normalize the verts
479 4) Flatten onto xz plane
480 - transform it onto an equidistant spherical projection techniques to transform the sphere onto a dome image
483 float sqrt_2 = sqrt(2.0);
484 float uv_ratio = (float)(m_buffersize-1) / m_imagesize;
486 m_radangle = m_angle * M_PI/180.0;//calculates the radians angle, used for flattening
488 //creating faces for the env mapcube 180º Dome
489 // Top Face - just a triangle
490 cubetop[0].verts[0][0] = -sqrt_2 / 2.0;
491 cubetop[0].verts[0][1] = 0.0;
492 cubetop[0].verts[0][2] = 0.5;
493 cubetop[0].u[0] = 0.0;
494 cubetop[0].v[0] = uv_ratio;
496 cubetop[0].verts[1][0] = 0.0;
497 cubetop[0].verts[1][1] = sqrt_2 / 2.0;
498 cubetop[0].verts[1][2] = 0.5;
499 cubetop[0].u[1] = 0.0;
500 cubetop[0].v[1] = 0.0;
502 cubetop[0].verts[2][0] = sqrt_2 / 2.0;
503 cubetop[0].verts[2][1] = 0.0;
504 cubetop[0].verts[2][2] = 0.5;
505 cubetop[0].u[2] = uv_ratio;
506 cubetop[0].v[2] = 0.0;
510 /* Bottom face - just a triangle */
511 cubebottom[0].verts[0][0] = -sqrt_2 / 2.0;
512 cubebottom[0].verts[0][1] = 0.0;
513 cubebottom[0].verts[0][2] = -0.5;
514 cubebottom[0].u[0] = uv_ratio;
515 cubebottom[0].v[0] = 0.0;
517 cubebottom[0].verts[1][0] = sqrt_2 / 2.0;
518 cubebottom[0].verts[1][1] = 0;
519 cubebottom[0].verts[1][2] = -0.5;
520 cubebottom[0].u[1] = 0.0;
521 cubebottom[0].v[1] = uv_ratio;
523 cubebottom[0].verts[2][0] = 0.0;
524 cubebottom[0].verts[2][1] = sqrt_2 / 2.0;
525 cubebottom[0].verts[2][2] = -0.5;
526 cubebottom[0].u[2] = 0.0;
527 cubebottom[0].v[2] = 0.0;
531 /* Left face - two triangles */
533 cubeleft[0].verts[0][0] = -sqrt_2 / 2.0;
534 cubeleft[0].verts[0][1] = .0;
535 cubeleft[0].verts[0][2] = -0.5;
536 cubeleft[0].u[0] = 0.0;
537 cubeleft[0].v[0] = 0.0;
539 cubeleft[0].verts[1][0] = 0.0;
540 cubeleft[0].verts[1][1] = sqrt_2 / 2.0;
541 cubeleft[0].verts[1][2] = -0.5;
542 cubeleft[0].u[1] = uv_ratio;
543 cubeleft[0].v[1] = 0.0;
545 cubeleft[0].verts[2][0] = -sqrt_2 / 2.0;
546 cubeleft[0].verts[2][1] = 0.0;
547 cubeleft[0].verts[2][2] = 0.5;
548 cubeleft[0].u[2] = 0.0;
549 cubeleft[0].v[2] = uv_ratio;
552 cubeleft[1].verts[0][0] = -sqrt_2 / 2.0;
553 cubeleft[1].verts[0][1] = 0.0;
554 cubeleft[1].verts[0][2] = 0.5;
555 cubeleft[1].u[0] = 0.0;
556 cubeleft[1].v[0] = uv_ratio;
558 cubeleft[1].verts[1][0] = 0.0;
559 cubeleft[1].verts[1][1] = sqrt_2 / 2.0;
560 cubeleft[1].verts[1][2] = -0.5;
561 cubeleft[1].u[1] = uv_ratio;
562 cubeleft[1].v[1] = 0.0;
564 cubeleft[1].verts[2][0] = 0.0;
565 cubeleft[1].verts[2][1] = sqrt_2 / 2.0;
566 cubeleft[1].verts[2][2] = 0.5;
567 cubeleft[1].u[2] = uv_ratio;
568 cubeleft[1].v[2] = uv_ratio;
572 /* Right face - two triangles */
573 cuberight[0].verts[0][0] = 0.0;
574 cuberight[0].verts[0][1] = sqrt_2 / 2.0;
575 cuberight[0].verts[0][2] = -0.5;
576 cuberight[0].u[0] = 0.0;
577 cuberight[0].v[0] = 0.0;
579 cuberight[0].verts[1][0] = sqrt_2 / 2.0;
580 cuberight[0].verts[1][1] = 0.0;
581 cuberight[0].verts[1][2] = -0.5;
582 cuberight[0].u[1] = uv_ratio;
583 cuberight[0].v[1] = 0.0;
585 cuberight[0].verts[2][0] = sqrt_2 / 2.0;
586 cuberight[0].verts[2][1] = 0.0;
587 cuberight[0].verts[2][2] = 0.5;
588 cuberight[0].u[2] = uv_ratio;
589 cuberight[0].v[2] = uv_ratio;
592 cuberight[1].verts[0][0] = 0.0;
593 cuberight[1].verts[0][1] = sqrt_2 / 2.0;
594 cuberight[1].verts[0][2] = -0.5;
595 cuberight[1].u[0] = 0.0;
596 cuberight[1].v[0] = 0.0;
598 cuberight[1].verts[1][0] = sqrt_2 / 2.0;
599 cuberight[1].verts[1][1] = 0.0;
600 cuberight[1].verts[1][2] = 0.5;
601 cuberight[1].u[1] = uv_ratio;
602 cuberight[1].v[1] = uv_ratio;
604 cuberight[1].verts[2][0] = 0.0;
605 cuberight[1].verts[2][1] = sqrt_2 / 2.0;
606 cuberight[1].verts[2][2] = 0.5;
607 cuberight[1].u[2] = 0.0;
608 cuberight[1].v[2] = uv_ratio;
612 //Refine a triangular mesh by bisecting each edge forms 3 new triangles for each existing triangle on each iteration
613 //Could be made more efficient for drawing if the triangles were ordered in a fan. Not that important since we are using DisplayLists
615 for(i=0;i<m_resolution;i++){
616 cubetop.resize(4*nfacestop);
617 SplitFace(cubetop,&nfacestop);
618 cubebottom.resize(4*nfacesbottom);
619 SplitFace(cubebottom,&nfacesbottom);
620 cubeleft.resize(4*nfacesleft);
621 SplitFace(cubeleft,&nfacesleft);
622 cuberight.resize(4*nfacesright);
623 SplitFace(cuberight,&nfacesright);
626 // Turn into a hemisphere
628 for(i=0;i<nfacestop;i++)
629 cubetop[i].verts[j].normalize();
630 for(i=0;i<nfacesbottom;i++)
631 cubebottom[i].verts[j].normalize();
632 for(i=0;i<nfacesleft;i++)
633 cubeleft[i].verts[j].normalize();
634 for(i=0;i<nfacesright;i++)
635 cuberight[i].verts[j].normalize();
638 //flatten onto xz plane
639 for(i=0;i<nfacestop;i++)
640 FlattenDome(cubetop[i].verts);
641 for(i=0;i<nfacesbottom;i++)
642 FlattenDome(cubebottom[i].verts);
643 for(i=0;i<nfacesleft;i++)
644 FlattenDome(cubeleft[i].verts);
645 for(i=0;i<nfacesright;i++)
646 FlattenDome(cuberight[i].verts);
650 void KX_Dome::CreateMeshDome250(void)
653 1)- Define the faces of a cube without the back face
654 - each face is made out of 2 triangles
655 2) Subdivide the faces
656 - more resolution == more curved lines
658 - normalize the verts
659 4) Flatten onto xz plane
660 - transform it onto an equidistant spherical projection techniques to transform the sphere onto a dome image
664 float uv_height, uv_base;
667 float rad_ang = m_angle * MT_PI / 180.0;
668 float uv_ratio = (float)(m_buffersize-1) / m_imagesize;
670 m_radangle = m_angle * M_PI/180.0;//calculates the radians angle, used for flattening
672 verts_height is the exactly needed height of the cube faces (not always 1.0).
673 When we want some horizontal information (e.g. for horizontal 220º domes) we don't need to create and tesselate the whole cube.
674 Therefore the lateral cube faces could be small, and the tesselate mesh would be completely used.
675 (if we always worked with verts_height = 1.0, we would be discarding a lot of the calculated and tesselated geometry).
677 So I came out with this formula:
678 verts_height = tan((rad_ang/2) - (MT_PI/2))*sqrt(2.0);
680 Here we take half the sphere(rad_ang/2) and subtract a quarter of it (MT_PI/2)
681 Therefore we have the lenght in radians of the dome/sphere over the horizon.
682 Once we take the tangent of that angle, you have the verts coordinate corresponding to the verts on the side faces.
683 Then we need to multiply it by sqrt(2.0) to get the coordinate of the verts on the diagonal of the original cube.
685 verts_height = tan((rad_ang/2) - (MT_PI/2))*sqrt(2.0);
687 uv_height = uv_ratio * ((verts_height/2) + 0.5);
688 uv_base = uv_ratio * (1.0 - ((verts_height/2) + 0.5));
690 //creating faces for the env mapcube 180º Dome
691 // Front Face - 2 triangles
692 cubefront[0].verts[0][0] =-1.0;
693 cubefront[0].verts[0][1] = 1.0;
694 cubefront[0].verts[0][2] =-1.0;
695 cubefront[0].u[0] = 0.0;
696 cubefront[0].v[0] = 0.0;
698 cubefront[0].verts[1][0] = 1.0;
699 cubefront[0].verts[1][1] = 1.0;
700 cubefront[0].verts[1][2] = 1.0;
701 cubefront[0].u[1] = uv_ratio;
702 cubefront[0].v[1] = uv_ratio;
704 cubefront[0].verts[2][0] =-1.0;
705 cubefront[0].verts[2][1] = 1.0;
706 cubefront[0].verts[2][2] = 1.0;
707 cubefront[0].u[2] = 0.0;
708 cubefront[0].v[2] = uv_ratio;
711 cubefront[1].verts[0][0] = 1.0;
712 cubefront[1].verts[0][1] = 1.0;
713 cubefront[1].verts[0][2] = 1.0;
714 cubefront[1].u[0] = uv_ratio;
715 cubefront[1].v[0] = uv_ratio;
717 cubefront[1].verts[1][0] =-1.0;
718 cubefront[1].verts[1][1] = 1.0;
719 cubefront[1].verts[1][2] =-1.0;
720 cubefront[1].u[1] = 0.0;
721 cubefront[1].v[1] = 0.0;
723 cubefront[1].verts[2][0] = 1.0;
724 cubefront[1].verts[2][1] = 1.0;
725 cubefront[1].verts[2][2] =-1.0;
726 cubefront[1].u[2] = uv_ratio;
727 cubefront[1].v[2] = 0.0;
731 // Left Face - 2 triangles
732 cubeleft[0].verts[0][0] =-1.0;
733 cubeleft[0].verts[0][1] = 1.0;
734 cubeleft[0].verts[0][2] =-1.0;
735 cubeleft[0].u[0] = uv_ratio;
736 cubeleft[0].v[0] = 0.0;
738 cubeleft[0].verts[1][0] =-1.0;
739 cubeleft[0].verts[1][1] =-verts_height;
740 cubeleft[0].verts[1][2] = 1.0;
741 cubeleft[0].u[1] = uv_base;
742 cubeleft[0].v[1] = uv_ratio;
744 cubeleft[0].verts[2][0] =-1.0;
745 cubeleft[0].verts[2][1] =-verts_height;
746 cubeleft[0].verts[2][2] =-1.0;
747 cubeleft[0].u[2] = uv_base;
748 cubeleft[0].v[2] = 0.0;
751 cubeleft[1].verts[0][0] =-1.0;
752 cubeleft[1].verts[0][1] =-verts_height;
753 cubeleft[1].verts[0][2] = 1.0;
754 cubeleft[1].u[0] = uv_base;
755 cubeleft[1].v[0] = uv_ratio;
757 cubeleft[1].verts[1][0] =-1.0;
758 cubeleft[1].verts[1][1] = 1.0;
759 cubeleft[1].verts[1][2] =-1.0;
760 cubeleft[1].u[1] = uv_ratio;
761 cubeleft[1].v[1] = 0.0;
763 cubeleft[1].verts[2][0] =-1.0;
764 cubeleft[1].verts[2][1] = 1.0;
765 cubeleft[1].verts[2][2] = 1.0;
766 cubeleft[1].u[2] = uv_ratio;
767 cubeleft[1].v[2] = uv_ratio;
771 // right Face - 2 triangles
772 cuberight[0].verts[0][0] = 1.0;
773 cuberight[0].verts[0][1] = 1.0;
774 cuberight[0].verts[0][2] = 1.0;
775 cuberight[0].u[0] = 0.0;
776 cuberight[0].v[0] = uv_ratio;
778 cuberight[0].verts[1][0] = 1.0;
779 cuberight[0].verts[1][1] =-verts_height;
780 cuberight[0].verts[1][2] =-1.0;
781 cuberight[0].u[1] = uv_height;
782 cuberight[0].v[1] = 0.0;
784 cuberight[0].verts[2][0] = 1.0;
785 cuberight[0].verts[2][1] =-verts_height;
786 cuberight[0].verts[2][2] = 1.0;
787 cuberight[0].u[2] = uv_height;
788 cuberight[0].v[2] = uv_ratio;
791 cuberight[1].verts[0][0] = 1.0;
792 cuberight[1].verts[0][1] =-verts_height;
793 cuberight[1].verts[0][2] =-1.0;
794 cuberight[1].u[0] = uv_height;
795 cuberight[1].v[0] = 0.0;
797 cuberight[1].verts[1][0] = 1.0;
798 cuberight[1].verts[1][1] = 1.0;
799 cuberight[1].verts[1][2] = 1.0;
800 cuberight[1].u[1] = 0.0;
801 cuberight[1].v[1] = uv_ratio;
803 cuberight[1].verts[2][0] = 1.0;
804 cuberight[1].verts[2][1] = 1.0;
805 cuberight[1].verts[2][2] =-1.0;
806 cuberight[1].u[2] = 0.0;
807 cuberight[1].v[2] = 0.0;
811 // top Face - 2 triangles
812 cubetop[0].verts[0][0] =-1.0;
813 cubetop[0].verts[0][1] = 1.0;
814 cubetop[0].verts[0][2] = 1.0;
815 cubetop[0].u[0] = 0.0;
816 cubetop[0].v[0] = 0.0;
818 cubetop[0].verts[1][0] = 1.0;
819 cubetop[0].verts[1][1] =-verts_height;
820 cubetop[0].verts[1][2] = 1.0;
821 cubetop[0].u[1] = uv_ratio;
822 cubetop[0].v[1] = uv_height;
824 cubetop[0].verts[2][0] =-1.0;
825 cubetop[0].verts[2][1] =-verts_height;
826 cubetop[0].verts[2][2] = 1.0;
827 cubetop[0].u[2] = 0.0;
828 cubetop[0].v[2] = uv_height;
831 cubetop[1].verts[0][0] = 1.0;
832 cubetop[1].verts[0][1] =-verts_height;
833 cubetop[1].verts[0][2] = 1.0;
834 cubetop[1].u[0] = uv_ratio;
835 cubetop[1].v[0] = uv_height;
837 cubetop[1].verts[1][0] =-1.0;
838 cubetop[1].verts[1][1] = 1.0;
839 cubetop[1].verts[1][2] = 1.0;
840 cubetop[1].u[1] = 0.0;
841 cubetop[1].v[1] = 0.0;
843 cubetop[1].verts[2][0] = 1.0;
844 cubetop[1].verts[2][1] = 1.0;
845 cubetop[1].verts[2][2] = 1.0;
846 cubetop[1].u[2] = uv_ratio;
847 cubetop[1].v[2] = 0.0;
851 // bottom Face - 2 triangles
852 cubebottom[0].verts[0][0] =-1.0;
853 cubebottom[0].verts[0][1] =-verts_height;
854 cubebottom[0].verts[0][2] =-1.0;
855 cubebottom[0].u[0] = 0.0;
856 cubebottom[0].v[0] = uv_base;
858 cubebottom[0].verts[1][0] = 1.0;
859 cubebottom[0].verts[1][1] = 1.0;
860 cubebottom[0].verts[1][2] =-1.0;
861 cubebottom[0].u[1] = uv_ratio;
862 cubebottom[0].v[1] = uv_ratio;
864 cubebottom[0].verts[2][0] =-1.0;
865 cubebottom[0].verts[2][1] = 1.0;
866 cubebottom[0].verts[2][2] =-1.0;
867 cubebottom[0].u[2] = 0.0;
868 cubebottom[0].v[2] = uv_ratio;
871 cubebottom[1].verts[0][0] = 1.0;
872 cubebottom[1].verts[0][1] = 1.0;
873 cubebottom[1].verts[0][2] =-1.0;
874 cubebottom[1].u[0] = uv_ratio;
875 cubebottom[1].v[0] = uv_ratio;
877 cubebottom[1].verts[1][0] =-1.0;
878 cubebottom[1].verts[1][1] =-verts_height;
879 cubebottom[1].verts[1][2] =-1.0;
880 cubebottom[1].u[1] = 0.0;
881 cubebottom[1].v[1] = uv_base;
883 cubebottom[1].verts[2][0] = 1.0;
884 cubebottom[1].verts[2][1] =-verts_height;
885 cubebottom[1].verts[2][2] =-1.0;
886 cubebottom[1].u[2] = uv_ratio;
887 cubebottom[1].v[2] = uv_base;
891 //Refine a triangular mesh by bisecting each edge forms 3 new triangles for each existing triangle on each iteration
892 //It could be made more efficient for drawing if the triangles were ordered in a strip!
894 for(i=0;i<m_resolution;i++){
895 cubefront.resize(4*nfacesfront);
896 SplitFace(cubefront,&nfacesfront);
897 cubetop.resize(4*nfacestop);
898 SplitFace(cubetop,&nfacestop);
899 cubebottom.resize(4*nfacesbottom);
900 SplitFace(cubebottom,&nfacesbottom);
901 cubeleft.resize(4*nfacesleft);
902 SplitFace(cubeleft,&nfacesleft);
903 cuberight.resize(4*nfacesright);
904 SplitFace(cuberight,&nfacesright);
907 // Turn into a hemisphere/sphere
909 for(i=0;i<nfacesfront;i++)
910 cubefront[i].verts[j].normalize();
911 for(i=0;i<nfacestop;i++)
912 cubetop[i].verts[j].normalize();
913 for(i=0;i<nfacesbottom;i++)
914 cubebottom[i].verts[j].normalize();
915 for(i=0;i<nfacesleft;i++)
916 cubeleft[i].verts[j].normalize();
917 for(i=0;i<nfacesright;i++)
918 cuberight[i].verts[j].normalize();
921 //flatten onto xz plane
922 for(i=0;i<nfacesfront;i++)
923 FlattenDome(cubefront[i].verts);
924 for(i=0;i<nfacestop;i++)
925 FlattenDome(cubetop[i].verts);
926 for(i=0;i<nfacesbottom;i++)
927 FlattenDome(cubebottom[i].verts);
928 for(i=0;i<nfacesleft;i++)
929 FlattenDome(cubeleft[i].verts);
930 for(i=0;i<nfacesright;i++)
931 FlattenDome(cuberight[i].verts);
934 void KX_Dome::CreateMeshPanorama(void)
937 1)- Define the faces of a cube without the top and bottom faces
938 - each face is made out of 2 triangles
939 2) Subdivide the faces
940 - more resolution == more curved lines
942 - normalize the verts t
943 4) Flatten onto xz plane
944 - use spherical projection techniques to transform the sphere onto a flat panorama
948 float sqrt_2 = sqrt(2.0);
949 float uv_ratio = (float)(m_buffersize-1) / m_imagesize;
951 /* Top face - two triangles */
952 cubetop[0].verts[0][0] = -sqrt_2;
953 cubetop[0].verts[0][1] = 0.0;
954 cubetop[0].verts[0][2] = 1.0;
955 cubetop[0].u[0] = 0.0;
956 cubetop[0].v[0] = uv_ratio;
958 cubetop[0].verts[1][0] = 0.0;
959 cubetop[0].verts[1][1] = sqrt_2;
960 cubetop[0].verts[1][2] = 1.0;
961 cubetop[0].u[1] = 0.0;
962 cubetop[0].v[1] = 0.0;
965 cubetop[0].verts[2][0] = sqrt_2;
966 cubetop[0].verts[2][1] = 0.0;
967 cubetop[0].verts[2][2] = 1.0;
968 cubetop[0].u[2] = uv_ratio;
969 cubetop[0].v[2] = 0.0;
971 cubetop[1].verts[0][0] = sqrt_2;
972 cubetop[1].verts[0][1] = 0.0;
973 cubetop[1].verts[0][2] = 1.0;
974 cubetop[1].u[0] = uv_ratio;
975 cubetop[1].v[0] = 0.0;
977 cubetop[1].verts[1][0] = 0.0;
978 cubetop[1].verts[1][1] = -sqrt_2;
979 cubetop[1].verts[1][2] = 1.0;
980 cubetop[1].u[1] = uv_ratio;
981 cubetop[1].v[1] = uv_ratio;
983 cubetop[1].verts[2][0] = -sqrt_2;
984 cubetop[1].verts[2][1] = 0.0;
985 cubetop[1].verts[2][2] = 1.0;
986 cubetop[1].u[2] = 0.0;
987 cubetop[1].v[2] = uv_ratio;
991 /* Bottom face - two triangles */
992 cubebottom[0].verts[0][0] = -sqrt_2;
993 cubebottom[0].verts[0][1] = 0.0;
994 cubebottom[0].verts[0][2] = -1.0;
995 cubebottom[0].u[0] = uv_ratio;
996 cubebottom[0].v[0] = 0.0;
998 cubebottom[0].verts[1][0] = sqrt_2;
999 cubebottom[0].verts[1][1] = 0.0;
1000 cubebottom[0].verts[1][2] = -1.0;
1001 cubebottom[0].u[1] = 0.0;
1002 cubebottom[0].v[1] = uv_ratio;
1004 cubebottom[0].verts[2][0] = 0.0;
1005 cubebottom[0].verts[2][1] = sqrt_2;
1006 cubebottom[0].verts[2][2] = -1.0;
1007 cubebottom[0].u[2] = 0.0;
1008 cubebottom[0].v[2] = 0.0;
1011 cubebottom[1].verts[0][0] = sqrt_2;
1012 cubebottom[1].verts[0][1] = 0.0;
1013 cubebottom[1].verts[0][2] = -1.0;
1014 cubebottom[1].u[0] = 0.0;
1015 cubebottom[1].v[0] = uv_ratio;
1017 cubebottom[1].verts[1][0] = -sqrt_2;
1018 cubebottom[1].verts[1][1] = 0.0;
1019 cubebottom[1].verts[1][2] = -1.0;
1020 cubebottom[1].u[1] = uv_ratio;
1021 cubebottom[1].v[1] = 0.0;
1023 cubebottom[1].verts[2][0] = 0.0;
1024 cubebottom[1].verts[2][1] = -sqrt_2;
1025 cubebottom[1].verts[2][2] = -1.0;
1026 cubebottom[1].u[2] = uv_ratio;
1027 cubebottom[1].v[2] = uv_ratio;
1031 /* Left Back (135º) face - two triangles */
1033 cubeleftback[0].verts[0][0] = 0;
1034 cubeleftback[0].verts[0][1] = -sqrt_2;
1035 cubeleftback[0].verts[0][2] = -1.0;
1036 cubeleftback[0].u[0] = 0;
1037 cubeleftback[0].v[0] = 0;
1039 cubeleftback[0].verts[1][0] = -sqrt_2;
1040 cubeleftback[0].verts[1][1] = 0;
1041 cubeleftback[0].verts[1][2] = -1.0;
1042 cubeleftback[0].u[1] = uv_ratio;
1043 cubeleftback[0].v[1] = 0;
1045 cubeleftback[0].verts[2][0] = 0;
1046 cubeleftback[0].verts[2][1] = -sqrt_2;
1047 cubeleftback[0].verts[2][2] = 1.0;
1048 cubeleftback[0].u[2] = 0;
1049 cubeleftback[0].v[2] = uv_ratio;
1052 cubeleftback[1].verts[0][0] = 0;
1053 cubeleftback[1].verts[0][1] = -sqrt_2;
1054 cubeleftback[1].verts[0][2] = 1.0;
1055 cubeleftback[1].u[0] = 0;
1056 cubeleftback[1].v[0] = uv_ratio;
1058 cubeleftback[1].verts[1][0] = -sqrt_2;
1059 cubeleftback[1].verts[1][1] = 0;
1060 cubeleftback[1].verts[1][2] = -1.0;
1061 cubeleftback[1].u[1] = uv_ratio;
1062 cubeleftback[1].v[1] = 0;
1064 cubeleftback[1].verts[2][0] = -sqrt_2;
1065 cubeleftback[1].verts[2][1] = 0;
1066 cubeleftback[1].verts[2][2] = 1.0;
1067 cubeleftback[1].u[2] = uv_ratio;
1068 cubeleftback[1].v[2] = uv_ratio;
1072 /* Left face - two triangles */
1074 cubeleft[0].verts[0][0] = -sqrt_2;
1075 cubeleft[0].verts[0][1] = 0;
1076 cubeleft[0].verts[0][2] = -1.0;
1077 cubeleft[0].u[0] = 0;
1078 cubeleft[0].v[0] = 0;
1080 cubeleft[0].verts[1][0] = 0;
1081 cubeleft[0].verts[1][1] = sqrt_2;
1082 cubeleft[0].verts[1][2] = -1.0;
1083 cubeleft[0].u[1] = uv_ratio;
1084 cubeleft[0].v[1] = 0;
1086 cubeleft[0].verts[2][0] = -sqrt_2;
1087 cubeleft[0].verts[2][1] = 0;
1088 cubeleft[0].verts[2][2] = 1.0;
1089 cubeleft[0].u[2] = 0;
1090 cubeleft[0].v[2] = uv_ratio;
1093 cubeleft[1].verts[0][0] = -sqrt_2;
1094 cubeleft[1].verts[0][1] = 0;
1095 cubeleft[1].verts[0][2] = 1.0;
1096 cubeleft[1].u[0] = 0;
1097 cubeleft[1].v[0] = uv_ratio;
1099 cubeleft[1].verts[1][0] = 0;
1100 cubeleft[1].verts[1][1] = sqrt_2;
1101 cubeleft[1].verts[1][2] = -1.0;
1102 cubeleft[1].u[1] = uv_ratio;
1103 cubeleft[1].v[1] = 0;
1105 cubeleft[1].verts[2][0] = 0;
1106 cubeleft[1].verts[2][1] = sqrt_2;
1107 cubeleft[1].verts[2][2] = 1.0;
1108 cubeleft[1].u[2] = uv_ratio;
1109 cubeleft[1].v[2] = uv_ratio;
1113 /* Right face - two triangles */
1114 cuberight[0].verts[0][0] = 0;
1115 cuberight[0].verts[0][1] = sqrt_2;
1116 cuberight[0].verts[0][2] = -1.0;
1117 cuberight[0].u[0] = 0;
1118 cuberight[0].v[0] = 0;
1120 cuberight[0].verts[1][0] = sqrt_2;
1121 cuberight[0].verts[1][1] = 0;
1122 cuberight[0].verts[1][2] = -1.0;
1123 cuberight[0].u[1] = uv_ratio;
1124 cuberight[0].v[1] = 0;
1126 cuberight[0].verts[2][0] = sqrt_2;
1127 cuberight[0].verts[2][1] = 0;
1128 cuberight[0].verts[2][2] = 1.0;
1129 cuberight[0].u[2] = uv_ratio;
1130 cuberight[0].v[2] = uv_ratio;
1133 cuberight[1].verts[0][0] = 0;
1134 cuberight[1].verts[0][1] = sqrt_2;
1135 cuberight[1].verts[0][2] = -1.0;
1136 cuberight[1].u[0] = 0;
1137 cuberight[1].v[0] = 0;
1139 cuberight[1].verts[1][0] = sqrt_2;
1140 cuberight[1].verts[1][1] = 0;
1141 cuberight[1].verts[1][2] = 1.0;
1142 cuberight[1].u[1] = uv_ratio;
1143 cuberight[1].v[1] = uv_ratio;
1145 cuberight[1].verts[2][0] = 0;
1146 cuberight[1].verts[2][1] = sqrt_2;
1147 cuberight[1].verts[2][2] = 1.0;
1148 cuberight[1].u[2] = 0;
1149 cuberight[1].v[2] = uv_ratio;
1153 /* Right Back (-135º) face - two triangles */
1154 cuberightback[0].verts[0][0] = sqrt_2;
1155 cuberightback[0].verts[0][1] = 0;
1156 cuberightback[0].verts[0][2] = -1.0;
1157 cuberightback[0].u[0] = 0;
1158 cuberightback[0].v[0] = 0;
1160 cuberightback[0].verts[1][0] = 0;
1161 cuberightback[0].verts[1][1] = -sqrt_2;
1162 cuberightback[0].verts[1][2] = -1.0;
1163 cuberightback[0].u[1] = uv_ratio;
1164 cuberightback[0].v[1] = 0;
1166 cuberightback[0].verts[2][0] = 0;
1167 cuberightback[0].verts[2][1] = -sqrt_2;
1168 cuberightback[0].verts[2][2] = 1.0;
1169 cuberightback[0].u[2] = uv_ratio;
1170 cuberightback[0].v[2] = uv_ratio;
1173 cuberightback[1].verts[0][0] = sqrt_2;
1174 cuberightback[1].verts[0][1] = 0;
1175 cuberightback[1].verts[0][2] = -1.0;
1176 cuberightback[1].u[0] = 0;
1177 cuberightback[1].v[0] = 0;
1179 cuberightback[1].verts[1][0] = 0;
1180 cuberightback[1].verts[1][1] = -sqrt_2;
1181 cuberightback[1].verts[1][2] = 1.0;
1182 cuberightback[1].u[1] = uv_ratio;
1183 cuberightback[1].v[1] = uv_ratio;
1185 cuberightback[1].verts[2][0] = sqrt_2;
1186 cuberightback[1].verts[2][1] = 0;
1187 cuberightback[1].verts[2][2] = 1.0;
1188 cuberightback[1].u[2] = 0;
1189 cuberightback[1].v[2] = uv_ratio;
1191 nfacesrightback = 2;
1193 // Subdivide the faces
1194 for(i=0;i<m_resolution;i++)
1196 cubetop.resize(4*nfacestop);
1197 SplitFace(cubetop,&nfacestop);
1199 cubebottom.resize(4*nfacesbottom);
1200 SplitFace(cubebottom,&nfacesbottom);
1202 cubeleft.resize(4*nfacesleft);
1203 SplitFace(cubeleft,&nfacesleft);
1205 cuberight.resize(4*nfacesright);
1206 SplitFace(cuberight,&nfacesright);
1208 cubeleftback.resize(4*nfacesleftback);
1209 SplitFace(cubeleftback,&nfacesleftback);
1211 cuberightback.resize(4*nfacesrightback);
1212 SplitFace(cuberightback,&nfacesrightback);
1215 // Spherize the cube
1218 for(i=0;i<nfacestop;i++)
1219 cubetop[i].verts[j].normalize();
1221 for(i=0;i<nfacesbottom;i++)
1222 cubebottom[i].verts[j].normalize();
1224 for(i=0;i<nfacesleftback;i++)
1225 cubeleftback[i].verts[j].normalize();
1227 for(i=0;i<nfacesleft;i++)
1228 cubeleft[i].verts[j].normalize();
1230 for(i=0;i<nfacesright;i++)
1231 cuberight[i].verts[j].normalize();
1233 for(i=0;i<nfacesrightback;i++)
1234 cuberightback[i].verts[j].normalize();
1237 //Flatten onto xz plane
1238 for(i=0;i<nfacesleftback;i++)
1239 FlattenPanorama(cubeleftback[i].verts);
1241 for(i=0;i<nfacesleft;i++)
1242 FlattenPanorama(cubeleft[i].verts);
1244 for(i=0;i<nfacesright;i++)
1245 FlattenPanorama(cuberight[i].verts);
1247 for(i=0;i<nfacesrightback;i++)
1248 FlattenPanorama(cuberightback[i].verts);
1250 for(i=0;i<nfacestop;i++)
1251 FlattenPanorama(cubetop[i].verts);
1253 for(i=0;i<nfacesbottom;i++)
1254 FlattenPanorama(cubebottom[i].verts);
1257 void KX_Dome::FlattenDome(MT_Vector3 verts[3])
1261 for (int i=0;i<3;i++){
1262 r = atan2(sqrt(verts[i][0]*verts[i][0] + verts[i][2]*verts[i][2]), verts[i][1]);
1265 phi = atan2(verts[i][2], verts[i][0]);
1267 verts[i][0] = r * cos(phi);
1269 verts[i][2] = r * sin(phi);
1273 verts[i][0] = cos(phi);
1275 verts[i][2] = sin(phi);
1280 void KX_Dome::FlattenPanorama(MT_Vector3 verts[3])
1282 // it creates a full spherical panoramic (360º)
1288 phi = atan2(verts[i][1], verts[i][0]);
1289 phi *= -1.0; //flipping
1291 if (phi == -MT_PI) //It's on the edge
1294 verts[i][0] = phi / MT_PI;
1297 verts[i][2] = atan2(verts[i][2], 1.0);
1298 verts[i][2] /= MT_PI / 2;
1304 if(fmod(verts[i][0],1.0) > 0.0){
1311 if(verts[i][0] < 0.0)
1312 verts[i][0] *= -1.0;
1318 void KX_Dome::SplitFace(vector <DomeFace>& face, int *nfaces)
1327 face[n2].verts[0] = (face[i].verts[0] + face[i].verts[1]) /2;
1328 face[n2].verts[1] = face[i].verts[1];
1329 face[n2].verts[2] = (face[i].verts[1] + face[i].verts[2]) /2;
1330 face[n2].u[0] = (face[i].u[0] + face[i].u[1]) /2;
1331 face[n2].u[1] = face[i].u[1];
1332 face[n2].u[2] = (face[i].u[1] + face[i].u[2]) /2;
1333 face[n2].v[0] = (face[i].v[0] + face[i].v[1]) /2;
1334 face[n2].v[1] = face[i].v[1];
1335 face[n2].v[2] = (face[i].v[1] + face[i].v[2]) /2;
1337 face[n2+1].verts[0] = (face[i].verts[1] + face[i].verts[2]) /2;
1338 face[n2+1].verts[1] = face[i].verts[2];
1339 face[n2+1].verts[2] = (face[i].verts[2] + face[i].verts[0]) /2;
1340 face[n2+1].u[0] = (face[i].u[1] + face[i].u[2]) /2;
1341 face[n2+1].u[1] = face[i].u[2];
1342 face[n2+1].u[2] = (face[i].u[2] + face[i].u[0]) /2;
1343 face[n2+1].v[0] = (face[i].v[1] + face[i].v[2]) /2;
1344 face[n2+1].v[1] = face[i].v[2];
1345 face[n2+1].v[2] = (face[i].v[2] + face[i].v[0]) /2;
1347 face[n2+2].verts[0] = (face[i].verts[0] + face[i].verts[1]) /2;
1348 face[n2+2].verts[1] = (face[i].verts[1] + face[i].verts[2]) /2;
1349 face[n2+2].verts[2] = (face[i].verts[2] + face[i].verts[0]) /2;
1350 face[n2+2].u[0] = (face[i].u[0] + face[i].u[1]) /2;
1351 face[n2+2].u[1] = (face[i].u[1] + face[i].u[2]) /2;
1352 face[n2+2].u[2] = (face[i].u[2] + face[i].u[0]) /2;
1353 face[n2+2].v[0] = (face[i].v[0] + face[i].v[1]) /2;
1354 face[n2+2].v[1] = (face[i].v[1] + face[i].v[2]) /2;
1355 face[n2+2].v[2] = (face[i].v[2] + face[i].v[0]) /2;
1357 //face[i].verts[0] = face[i].verts[0] ;
1358 face[i].verts[1] = (face[i].verts[0] + face[i].verts[1]) /2;
1359 face[i].verts[2] = (face[i].verts[0] + face[i].verts[2]) /2;
1360 //face[i].u[0] = face[i].u[0];
1361 face[i].u[1] = (face[i].u[0] + face[i].u[1]) /2;
1362 face[i].u[2] = (face[i].u[0] + face[i].u[2]) /2;
1363 //face[i].v[0] = face[i].v[0] ;
1364 face[i].v[1] = (face[i].v[0] + face[i].v[1]) /2;
1365 face[i].v[2] = (face[i].v[0] + face[i].v[2]) /2;
1367 n2 += 3; // number of faces
1372 void KX_Dome::CalculateFrustum(KX_Camera * cam)
1375 // manually creating a 90º Field of View Frustum
1377 the original formula:
1378 top = tan(fov*3.14159/360.0) * near [for fov in degrees]
1379 fov*0.5 = arctan ((top-bottom)*0.5 / near) [for fov in radians]
1381 left = aspect * bottom
1382 right = aspect * top
1384 // the equivalent GLU call is:
1385 glMatrixMode(GL_PROJECTION);
1387 gluPerspective(90.0,1.0,cam->GetCameraNear(),cam->GetCameraFar());
1390 RAS_FrameFrustum m_frustrum; //90 deg. Frustum
1392 m_frustrum.camnear = cam->GetCameraNear();
1393 m_frustrum.camfar = cam->GetCameraFar();
1395 // float top = tan(90.0*MT_PI/360.0) * m_frustrum.camnear;
1396 float top = m_frustrum.camnear; // for deg = 90º, tan = 1
1398 m_frustrum.x1 = -top;
1399 m_frustrum.x2 = top;
1400 m_frustrum.y1 = -top;
1401 m_frustrum.y2 = top;
1403 m_projmat = m_rasterizer->GetFrustumMatrix(
1404 m_frustrum.x1, m_frustrum.x2, m_frustrum.y1, m_frustrum.y2, m_frustrum.camnear, m_frustrum.camfar);
1408 void KX_Dome::CalculateCameraOrientation()
1411 Uses 4 cameras for angles up to 180º
1412 Uses 5 cameras for angles up to 250º
1413 Uses 6 cameras for angles up to 360º
1415 float deg45 = MT_PI / 4;
1416 MT_Scalar c = cos(deg45);
1417 MT_Scalar s = sin(deg45);
1419 if ((m_mode == DOME_FISHEYE && m_angle <= 180)|| m_mode == DOME_TRUNCATED){
1421 m_locRot[0] = MT_Matrix3x3( // 90º - Top
1426 m_locRot[1] = MT_Matrix3x3( // 90º - Bottom
1431 m_locRot[2] = MT_Matrix3x3( // 45º - Left
1436 m_locRot[3] = MT_Matrix3x3( // 45º - Right
1441 } else if ((m_mode == DOME_FISHEYE && m_angle > 180)){
1443 m_locRot[0] = MT_Matrix3x3( // 90º - Top
1448 m_locRot[1] = MT_Matrix3x3( // 90º - Bottom
1453 m_locRot[2] = MT_Matrix3x3( // -90º - Left
1458 m_locRot[3] = MT_Matrix3x3( // 90º - Right
1463 m_locRot[4] = MT_Matrix3x3( // 0º - Front
1468 m_locRot[5] = MT_Matrix3x3( // 180º - Back - NOT USING
1473 } else if (m_mode == DOME_PANORAM_SPH){
1475 m_locRot[0] = MT_Matrix3x3( // Top
1480 m_locRot[1] = MT_Matrix3x3( // Bottom
1485 m_locRot[2] = MT_Matrix3x3( // 45º - Left
1490 m_locRot[3] = MT_Matrix3x3( // 45º - Right
1495 m_locRot[4] = MT_Matrix3x3( // 135º - LeftBack
1500 m_locRot[5] = MT_Matrix3x3( // 135º - RightBack
1507 void KX_Dome::RotateCamera(KX_Camera* cam, int i)
1509 // I'm not using it, I'm doing inline calls for these commands
1510 // but it's nice to have it here in case I need it
1512 MT_Matrix3x3 camori = cam->GetSGNode()->GetLocalOrientation();
1514 cam->NodeSetLocalOrientation(camori*m_locRot[i]);
1515 cam->NodeUpdateGS(0.f);
1517 MT_Transform camtrans(cam->GetWorldToCamera());
1518 MT_Matrix4x4 viewmat(camtrans);
1519 m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(),
1520 cam->GetCameraLocation(), cam->GetCameraOrientation());
1521 cam->SetModelviewMatrix(viewmat);
1523 // restore the original orientation
1524 cam->NodeSetLocalOrientation(camori);
1525 cam->NodeUpdateGS(0.f);
1528 void KX_Dome::Draw(void)
1535 case DOME_TRUNCATED:
1538 case DOME_PANORAM_SPH:
1545 glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]);
1546 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_viewport.GetLeft(), m_viewport.GetBottom(), warp.bufferwidth, warp.bufferheight);
1551 void KX_Dome::DrawDomeFisheye(void)
1555 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1556 glMatrixMode(GL_PROJECTION);
1559 // Making the viewport always square
1561 int can_width = m_viewport.GetRight();
1562 int can_height = m_viewport.GetTop();
1564 float ortho_width, ortho_height;
1567 glOrtho((-1.0), 1.0, (-1.0), 1.0, -20.0, 10.0); //stretch the image to reduce resolution lost
1569 else if(m_mode == DOME_TRUNCATED){
1571 ortho_height = 2 * ((float)can_height/can_width) - 1.0 ;
1573 ortho_width /= m_size;
1574 ortho_height /= m_size;
1576 glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_width, -20.0, 10.0);
1578 if (can_width < can_height){
1580 ortho_height = (float)can_height/can_width;
1582 ortho_width = (float)can_width/can_height;
1586 ortho_width /= m_size;
1587 ortho_height /= m_size;
1589 glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0);
1592 glMatrixMode(GL_TEXTURE);
1594 glMatrixMode(GL_MODELVIEW);
1596 gluLookAt(0.0,-1.0,0.0, 0.0,0.0,0.0, 0.0,0.0,1.0);
1598 if(m_drawingmode == RAS_IRasterizer::KX_WIREFRAME)
1599 glPolygonMode(GL_FRONT, GL_LINE);
1601 glPolygonMode(GL_FRONT, GL_FILL);
1603 glShadeModel(GL_SMOOTH);
1604 glDisable(GL_LIGHTING);
1605 glDisable(GL_DEPTH_TEST);
1607 glEnable(GL_TEXTURE_2D);
1608 glColor3f(1.0,1.0,1.0);
1610 if (dlistSupported){
1611 for(i=0;i<m_numfaces;i++){
1612 glBindTexture(GL_TEXTURE_2D, domefacesId[i]);
1613 glCallList(dlistId+i);
1616 else { // DisplayLists not supported
1618 glBindTexture(GL_TEXTURE_2D, domefacesId[0]);
1619 GLDrawTriangles(cubetop, nfacestop);
1622 glBindTexture(GL_TEXTURE_2D, domefacesId[1]);
1623 GLDrawTriangles(cubebottom, nfacesbottom);
1626 glBindTexture(GL_TEXTURE_2D, domefacesId[2]);
1627 GLDrawTriangles(cubeleft, nfacesleft);
1630 glBindTexture(GL_TEXTURE_2D, domefacesId[3]);
1631 GLDrawTriangles(cuberight, nfacesright);
1635 glBindTexture(GL_TEXTURE_2D, domefacesId[4]);
1636 GLDrawTriangles(cubefront, nfacesfront);
1639 glDisable(GL_TEXTURE_2D);
1640 glEnable(GL_DEPTH_TEST);
1643 void KX_Dome::DrawPanorama(void)
1646 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1647 glMatrixMode(GL_PROJECTION);
1650 // Making the viewport always square
1652 int can_width = m_viewport.GetRight();
1653 int can_height = m_viewport.GetTop();
1655 float ortho_height = 1.0;
1656 float ortho_width = 1.0;
1659 glOrtho((-1.0), 1.0, (-0.5), 0.5, -20.0, 10.0); //stretch the image to reduce resolution lost
1662 //using all the screen
1663 if ((can_width / 2) <= (can_height)){
1665 ortho_height = (float)can_height/can_width;
1667 ortho_width = (float)can_width/can_height * 0.5;
1671 ortho_width /= m_size;
1672 ortho_height /= m_size;
1674 glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0, 10.0);
1677 glMatrixMode(GL_TEXTURE);
1679 glMatrixMode(GL_MODELVIEW);
1681 gluLookAt(0.0,-1.0,0.0, 0.0,0.0,0.0, 0.0,0.0,1.0);
1683 if(m_drawingmode == RAS_IRasterizer::KX_WIREFRAME)
1684 glPolygonMode(GL_FRONT, GL_LINE);
1686 glPolygonMode(GL_FRONT, GL_FILL);
1688 glShadeModel(GL_SMOOTH);
1689 glDisable(GL_LIGHTING);
1690 glDisable(GL_DEPTH_TEST);
1692 glEnable(GL_TEXTURE_2D);
1693 glColor3f(1.0,1.0,1.0);
1695 if (dlistSupported){
1696 for(i=0;i<m_numfaces;i++){
1697 glBindTexture(GL_TEXTURE_2D, domefacesId[i]);
1698 glCallList(dlistId+i);
1702 // domefacesId[4] => (top)
1703 glBindTexture(GL_TEXTURE_2D, domefacesId[0]);
1704 GLDrawTriangles(cubetop, nfacestop);
1706 // domefacesId[5] => (bottom)
1707 glBindTexture(GL_TEXTURE_2D, domefacesId[1]);
1708 GLDrawTriangles(cubebottom, nfacesbottom);
1710 // domefacesId[1] => -45º (left)
1711 glBindTexture(GL_TEXTURE_2D, domefacesId[2]);
1712 GLDrawTriangles(cubeleft, nfacesleft);
1714 // domefacesId[2] => 45º (right)
1715 glBindTexture(GL_TEXTURE_2D, domefacesId[3]);
1716 GLDrawTriangles(cuberight, nfacesright);
1718 // domefacesId[0] => -135º (leftback)
1719 glBindTexture(GL_TEXTURE_2D, domefacesId[4]);
1720 GLDrawTriangles(cubeleftback, nfacesleftback);
1722 // domefacesId[3] => 135º (rightback)
1723 glBindTexture(GL_TEXTURE_2D, domefacesId[5]);
1724 GLDrawTriangles(cuberightback, nfacesrightback);
1726 glDisable(GL_TEXTURE_2D);
1727 glEnable(GL_DEPTH_TEST);
1730 void KX_Dome::DrawDomeWarped(void)
1734 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1735 glMatrixMode(GL_PROJECTION);
1738 // Making the viewport always square
1739 int can_width = m_viewport.GetRight();
1740 int can_height = m_viewport.GetTop();
1742 double screen_ratio = can_width/ (double) can_height;
1743 screen_ratio /= m_size;
1745 glOrtho(-screen_ratio,screen_ratio,-1.0,1.0,-20.0,10.0);
1748 glMatrixMode(GL_TEXTURE);
1750 glMatrixMode(GL_MODELVIEW);
1752 gluLookAt(0.0, 0.0, 1.0, 0.0,0.0,0.0, 0.0,1.0,0.0);
1754 if(m_drawingmode == RAS_IRasterizer::KX_WIREFRAME)
1755 glPolygonMode(GL_FRONT, GL_LINE);
1757 glPolygonMode(GL_FRONT, GL_FILL);
1759 glShadeModel(GL_SMOOTH);
1760 glDisable(GL_LIGHTING);
1761 glDisable(GL_DEPTH_TEST);
1763 glEnable(GL_TEXTURE_2D);
1764 glColor3f(1.0,1.0,1.0);
1767 float uv_width = (float)(warp.bufferwidth-1) / warp.imagewidth;
1768 float uv_height = (float)(warp.bufferheight-1) / warp.imageheight;
1770 if (dlistSupported){
1771 glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]);
1772 glCallList(dlistId + m_numfaces);
1775 glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]);
1778 glDisable(GL_TEXTURE_2D);
1779 glEnable(GL_DEPTH_TEST);
1782 void KX_Dome::BindImages(int i)
1784 glBindTexture(GL_TEXTURE_2D, domefacesId[i]);
1785 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_viewport.GetLeft(), m_viewport.GetBottom(), m_buffersize, m_buffersize);
1788 void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i)
1793 m_canvas->SetViewPort(0,0,m_buffersize-1,m_buffersize-1);
1795 // m_rasterizer->SetAmbient();
1796 m_rasterizer->DisplayFog();
1798 CalculateFrustum(cam); //calculates m_projmat
1799 cam->SetProjectionMatrix(m_projmat);
1800 m_rasterizer->SetProjectionMatrix(cam->GetProjectionMatrix());
1801 // Dome_RotateCamera(cam,i);
1803 MT_Matrix3x3 camori = cam->GetSGNode()->GetLocalOrientation();
1805 cam->NodeSetLocalOrientation(camori*m_locRot[i]);
1806 cam->NodeUpdateGS(0.f);
1808 MT_Transform camtrans(cam->GetWorldToCamera());
1809 MT_Matrix4x4 viewmat(camtrans);
1810 m_rasterizer->SetViewMatrix(viewmat, cam->NodeGetWorldPosition(),
1811 cam->GetCameraLocation(), cam->GetCameraOrientation());
1812 cam->SetModelviewMatrix(viewmat);
1814 scene->CalculateVisibleMeshes(m_rasterizer,cam);
1815 scene->RenderBuckets(camtrans, m_rasterizer, m_rendertools);
1817 // restore the original orientation
1818 cam->NodeSetLocalOrientation(camori);
1819 cam->NodeUpdateGS(0.f);