forked from bartvdbraak/blender
e9e08a1d12
Levels of detail can be added and modified in the object panel. The object panel also contains new tools for generating levels of detail, setting up levels of detail based on object names (useful for importing), and clearing an object's level of detail settings. This is meant as a game engine feature, though the level of details settings can be previewed in the viewport. Reviewed By: moguri, nexyon, brecht Differential Revision: http://developer.blender.org/D109
2053 lines
54 KiB
C++
2053 lines
54 KiB
C++
/*
|
|
* ***** 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 <structmember.h>
|
|
#endif
|
|
|
|
#include <float.h>
|
|
#include <math.h>
|
|
|
|
#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;j<m_numfaces;j++) {
|
|
glBindTexture(GL_TEXTURE_2D, domefacesId[j]);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, m_imagesize, m_imagesize, 0, GL_RGB8,
|
|
GL_UNSIGNED_BYTE, NULL);
|
|
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, m_imagesize, m_imagesize, 0);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
}
|
|
if (warp.usemesh) {
|
|
glBindTexture(GL_TEXTURE_2D, domefacesId[m_numfaces]);
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, warp.imagesize, warp.imagesize, 0, GL_RGB8,
|
|
GL_UNSIGNED_BYTE, NULL);
|
|
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, warp.imagesize, warp.imagesize, 0);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
}
|
|
}
|
|
|
|
void KX_Dome::ClearGLImages(void)
|
|
{
|
|
glDeleteTextures(m_numimages, (GLuint*)&domefacesId);
|
|
#if 0
|
|
for (int i=0;i<m_numimages;i++)
|
|
if (glIsTexture(domefacesId[i]))
|
|
glDeleteTextures(1, (GLuint*)&domefacesId[i]);
|
|
#endif
|
|
}
|
|
|
|
void KX_Dome::CalculateImageSize(void)
|
|
{
|
|
/*
|
|
* - determine the minimum buffer size
|
|
* - reduce the buffer for better performance
|
|
* - create a power of 2 texture bigger than the buffer
|
|
*/
|
|
canvaswidth = m_canvas->GetWidth();
|
|
canvasheight = m_canvas->GetHeight();
|
|
|
|
m_buffersize = (canvaswidth > canvasheight?canvasheight:canvaswidth);
|
|
m_buffersize = (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 <DomeFace>& face, int nfaces)
|
|
{
|
|
int i,j;
|
|
glBegin(GL_TRIANGLES);
|
|
for (i=0;i<nfaces;i++) {
|
|
for (j=0;j<3;j++) {
|
|
glTexCoord2f(face[i].u[j],face[i].v[j]);
|
|
glVertex3f((GLfloat)face[i].verts[j][0],(GLfloat)face[i].verts[j][1],(GLfloat)face[i].verts[j][2]);
|
|
}
|
|
}
|
|
glEnd();
|
|
}
|
|
|
|
void KX_Dome::GLDrawWarpQuads(void)
|
|
{
|
|
int i, j, i2;
|
|
|
|
float uv_width = (float)(warp.bufferwidth) / warp.imagesize;
|
|
float uv_height = (float)(warp.bufferheight) / warp.imagesize;
|
|
|
|
if (warp.mode ==2 ) {
|
|
glBegin(GL_QUADS);
|
|
for (i=0;i<warp.n_height-1;i++) {
|
|
for (j=0;j<warp.n_width-1;j++) {
|
|
if (warp.nodes[i][j].i < 0 || warp.nodes[i+1][j].i < 0 || warp.nodes[i+1][j+1].i < 0 || warp.nodes[i][j+1].i < 0)
|
|
continue;
|
|
|
|
glColor3f(warp.nodes[i][j+1].i, warp.nodes[i][j+1].i, warp.nodes[i][j+1].i);
|
|
glTexCoord2f((warp.nodes[i][j+1].u * uv_width), (warp.nodes[i][j+1].v * uv_height));
|
|
glVertex3f(warp.nodes[i][j+1].x, warp.nodes[i][j+1].y,0.0);
|
|
|
|
glColor3f(warp.nodes[i+1][j+1].i, warp.nodes[i+1][j+1].i, warp.nodes[i+1][j+1].i);
|
|
glTexCoord2f((warp.nodes[i+1][j+1].u * uv_width), (warp.nodes[i+1][j+1].v * uv_height));
|
|
glVertex3f(warp.nodes[i+1][j+1].x, warp.nodes[i+1][j+1].y,0.0);
|
|
|
|
glColor3f(warp.nodes[i+1][j].i, warp.nodes[i+1][j].i, warp.nodes[i+1][j].i);
|
|
glTexCoord2f((warp.nodes[i+1][j].u * uv_width), (warp.nodes[i+1][j].v * uv_height));
|
|
glVertex3f(warp.nodes[i+1][j].x, warp.nodes[i+1][j].y,0.0);
|
|
|
|
glColor3f(warp.nodes[i][j].i, warp.nodes[i][j].i, warp.nodes[i][j].i);
|
|
glTexCoord2f((warp.nodes[i][j].u * uv_width), (warp.nodes[i][j].v * uv_height));
|
|
glVertex3f(warp.nodes[i][j].x, warp.nodes[i][j].y,0.0);
|
|
}
|
|
}
|
|
glEnd();
|
|
}
|
|
else if (warp.mode == 1) {
|
|
glBegin(GL_QUADS);
|
|
for (i=0;i<warp.n_height-1;i++) {
|
|
for (j=0;j<warp.n_width-1;j++) {
|
|
i2 = (i+1) % warp.n_width; // Wrap around, i = warp.n_width = 0
|
|
|
|
if (warp.nodes[i][j].i < 0 || warp.nodes[i2][j].i < 0 || warp.nodes[i2][j+1].i < 0 || warp.nodes[i][j+1].i < 0)
|
|
continue;
|
|
|
|
glColor3f(warp.nodes[i][j].i,warp.nodes[i][j].i,warp.nodes[i][j].i);
|
|
glTexCoord2f((warp.nodes[i][j].u * uv_width), (warp.nodes[i][j].v * uv_height));
|
|
glVertex3f(warp.nodes[i][j].x,warp.nodes[i][j].y,0.0);
|
|
|
|
glColor3f(warp.nodes[i2][j].i,warp.nodes[i2][j].i,warp.nodes[i2][j].i);
|
|
glTexCoord2f((warp.nodes[i2][j].u * uv_width), (warp.nodes[i2][j].v * uv_height));
|
|
glVertex3f(warp.nodes[i2][j].x,warp.nodes[i2][j].y,0.0);
|
|
|
|
glColor3f(warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i);
|
|
glTexCoord2f((warp.nodes[i2][j+1].u * uv_width), (warp.nodes[i2][j+1].v * uv_height));
|
|
glVertex3f(warp.nodes[i2][j+1].x,warp.nodes[i2][j+1].y,0.0);
|
|
|
|
glColor3f(warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i,warp.nodes[i2][j+1].i);
|
|
glTexCoord2f((warp.nodes[i2][j+1].u * uv_width), (warp.nodes[i2][j+1].v * uv_height));
|
|
glVertex3f(warp.nodes[i2][j+1].x,warp.nodes[i2][j+1].y,0.0);
|
|
|
|
}
|
|
}
|
|
glEnd();
|
|
}
|
|
else {
|
|
printf("Dome Error: Warp Mode %d unsupported. Try 1 for Polar Mesh or 2 for Fisheye.\n", warp.mode);
|
|
}
|
|
}
|
|
|
|
|
|
bool KX_Dome::ParseWarpMesh(STR_String text)
|
|
{
|
|
/*
|
|
* //Notes about the supported data format:
|
|
* File example::
|
|
* mode
|
|
* width height
|
|
* n0_x n0_y n0_u n0_v n0_i
|
|
* n1_x n1_y n1_u n1_v n1_i
|
|
* n2_x n1_y n2_u n2_v n2_i
|
|
* n3_x n3_y n3_u n3_v n3_i
|
|
* (...)
|
|
* First line is the image type the mesh is support to be applied to: 2 = fisheye, 1=radial
|
|
* The next line has the mesh dimensions
|
|
* Rest of the lines are the nodes of the mesh. Each line has x y u v i
|
|
* (x,y) are the normalized screen coordinates
|
|
* (u,v) texture coordinates
|
|
* i a multiplicative intensity factor
|
|
*
|
|
* x varies from -screen aspect to screen aspect
|
|
* y varies from -1 to 1
|
|
* u and v vary from 0 to 1
|
|
* i ranges from 0 to 1, if negative don't draw that mesh node
|
|
*/
|
|
int i;
|
|
int nodeX=0, nodeY=0;
|
|
|
|
vector<STR_String> 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<vector<WarpMeshNode> > (warp.n_height, vector<WarpMeshNode>(warp.n_width));
|
|
|
|
for (i=2; i-2 < (warp.n_width*warp.n_height); i++) {
|
|
columns = lines[i].Explode(' ');
|
|
if (columns.size() == 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;i<m_resolution;i++) {
|
|
cubetop.resize(4*nfacestop);
|
|
SplitFace(cubetop,&nfacestop);
|
|
cubebottom.resize(4*nfacesbottom);
|
|
SplitFace(cubebottom,&nfacesbottom);
|
|
cubeleft.resize(4*nfacesleft);
|
|
SplitFace(cubeleft,&nfacesleft);
|
|
cuberight.resize(4*nfacesright);
|
|
SplitFace(cuberight,&nfacesright);
|
|
}
|
|
|
|
// Turn into a hemisphere
|
|
for (j=0;j<3;j++) {
|
|
for (i=0;i<nfacestop;i++)
|
|
cubetop[i].verts[j].normalize();
|
|
for (i=0;i<nfacesbottom;i++)
|
|
cubebottom[i].verts[j].normalize();
|
|
for (i=0;i<nfacesleft;i++)
|
|
cubeleft[i].verts[j].normalize();
|
|
for (i=0;i<nfacesright;i++)
|
|
cuberight[i].verts[j].normalize();
|
|
}
|
|
|
|
//flatten onto xz plane
|
|
for (i=0;i<nfacestop;i++)
|
|
FlattenDome(cubetop[i].verts);
|
|
for (i=0;i<nfacesbottom;i++)
|
|
FlattenDome(cubebottom[i].verts);
|
|
for (i=0;i<nfacesleft;i++)
|
|
FlattenDome(cubeleft[i].verts);
|
|
for (i=0;i<nfacesright;i++)
|
|
FlattenDome(cuberight[i].verts);
|
|
|
|
}
|
|
|
|
void KX_Dome::CreateMeshDome250(void)
|
|
{
|
|
/*
|
|
* 1)- Define the faces of a cube without the back face
|
|
* - each face is made out of 2 triangles
|
|
* 2) Subdivide the faces
|
|
* - more resolution == more curved lines
|
|
* 3) Spherize the cube
|
|
* - normalize the verts
|
|
* 4) Flatten onto xz plane
|
|
* - transform it onto an equidistant spherical projection techniques to transform the sphere onto a dome image
|
|
*/
|
|
|
|
int i,j;
|
|
float uv_height, uv_base;
|
|
float verts_height;
|
|
|
|
float rad_ang = m_angle * MT_PI / 180.0;
|
|
float uv_ratio = (float)(m_buffersize-1) / m_imagesize;
|
|
|
|
m_radangle = m_angle * M_PI/180.0;//calculates the radians angle, used for flattening
|
|
/*
|
|
* verts_height is the exactly needed height of the cube faces (not always 1.0).
|
|
* When we want some horizontal information (e.g. for horizontal 220deg domes) we don't need to create and tessellate the whole cube.
|
|
* Therefore the lateral cube faces could be small, and the tessellate mesh would be completely used.
|
|
* (if we always worked with verts_height = 1.0, we would be discarding a lot of the calculated and tessellated geometry).
|
|
*
|
|
* So I came out with this formula:
|
|
* verts_height = tan((rad_ang/2) - (MT_PI/2))*sqrt(2.0);
|
|
*
|
|
* Here we take half the sphere(rad_ang/2) and subtract a quarter of it (MT_PI/2)
|
|
* Therefore we have the length in radians of the dome/sphere over the horizon.
|
|
* Once we take the tangent of that angle, you have the verts coordinate corresponding to the verts on the side faces.
|
|
* Then we need to multiply it by sqrt(2.0) to get the coordinate of the verts on the diagonal of the original cube.
|
|
*/
|
|
verts_height = tanf((rad_ang / 2.0f) - (float)(MT_PI / 2.0)) * (float)M_SQRT2;
|
|
|
|
uv_height = uv_ratio * ( (verts_height / 2.0f) + 0.5f);
|
|
uv_base = uv_ratio * (1.0 - ((verts_height / 2.0f) + 0.5f));
|
|
|
|
//creating faces for the env mapcube 180deg Dome
|
|
// Front Face - 2 triangles
|
|
cubefront[0].verts[0][0] =-1.0;
|
|
cubefront[0].verts[0][1] = 1.0;
|
|
cubefront[0].verts[0][2] =-1.0;
|
|
cubefront[0].u[0] = 0.0;
|
|
cubefront[0].v[0] = 0.0;
|
|
|
|
cubefront[0].verts[1][0] = 1.0;
|
|
cubefront[0].verts[1][1] = 1.0;
|
|
cubefront[0].verts[1][2] = 1.0;
|
|
cubefront[0].u[1] = uv_ratio;
|
|
cubefront[0].v[1] = uv_ratio;
|
|
|
|
cubefront[0].verts[2][0] =-1.0;
|
|
cubefront[0].verts[2][1] = 1.0;
|
|
cubefront[0].verts[2][2] = 1.0;
|
|
cubefront[0].u[2] = 0.0;
|
|
cubefront[0].v[2] = uv_ratio;
|
|
|
|
//second triangle
|
|
cubefront[1].verts[0][0] = 1.0;
|
|
cubefront[1].verts[0][1] = 1.0;
|
|
cubefront[1].verts[0][2] = 1.0;
|
|
cubefront[1].u[0] = uv_ratio;
|
|
cubefront[1].v[0] = uv_ratio;
|
|
|
|
cubefront[1].verts[1][0] =-1.0;
|
|
cubefront[1].verts[1][1] = 1.0;
|
|
cubefront[1].verts[1][2] =-1.0;
|
|
cubefront[1].u[1] = 0.0;
|
|
cubefront[1].v[1] = 0.0;
|
|
|
|
cubefront[1].verts[2][0] = 1.0;
|
|
cubefront[1].verts[2][1] = 1.0;
|
|
cubefront[1].verts[2][2] =-1.0;
|
|
cubefront[1].u[2] = uv_ratio;
|
|
cubefront[1].v[2] = 0.0;
|
|
|
|
nfacesfront = 2;
|
|
|
|
// Left Face - 2 triangles
|
|
cubeleft[0].verts[0][0] =-1.0;
|
|
cubeleft[0].verts[0][1] = 1.0;
|
|
cubeleft[0].verts[0][2] =-1.0;
|
|
cubeleft[0].u[0] = uv_ratio;
|
|
cubeleft[0].v[0] = 0.0;
|
|
|
|
cubeleft[0].verts[1][0] =-1.0;
|
|
cubeleft[0].verts[1][1] =-verts_height;
|
|
cubeleft[0].verts[1][2] = 1.0;
|
|
cubeleft[0].u[1] = uv_base;
|
|
cubeleft[0].v[1] = uv_ratio;
|
|
|
|
cubeleft[0].verts[2][0] =-1.0;
|
|
cubeleft[0].verts[2][1] =-verts_height;
|
|
cubeleft[0].verts[2][2] =-1.0;
|
|
cubeleft[0].u[2] = uv_base;
|
|
cubeleft[0].v[2] = 0.0;
|
|
|
|
//second triangle
|
|
cubeleft[1].verts[0][0] =-1.0;
|
|
cubeleft[1].verts[0][1] =-verts_height;
|
|
cubeleft[1].verts[0][2] = 1.0;
|
|
cubeleft[1].u[0] = uv_base;
|
|
cubeleft[1].v[0] = uv_ratio;
|
|
|
|
cubeleft[1].verts[1][0] =-1.0;
|
|
cubeleft[1].verts[1][1] = 1.0;
|
|
cubeleft[1].verts[1][2] =-1.0;
|
|
cubeleft[1].u[1] = uv_ratio;
|
|
cubeleft[1].v[1] = 0.0;
|
|
|
|
cubeleft[1].verts[2][0] =-1.0;
|
|
cubeleft[1].verts[2][1] = 1.0;
|
|
cubeleft[1].verts[2][2] = 1.0;
|
|
cubeleft[1].u[2] = uv_ratio;
|
|
cubeleft[1].v[2] = uv_ratio;
|
|
|
|
nfacesleft = 2;
|
|
|
|
// right Face - 2 triangles
|
|
cuberight[0].verts[0][0] = 1.0;
|
|
cuberight[0].verts[0][1] = 1.0;
|
|
cuberight[0].verts[0][2] = 1.0;
|
|
cuberight[0].u[0] = 0.0;
|
|
cuberight[0].v[0] = uv_ratio;
|
|
|
|
cuberight[0].verts[1][0] = 1.0;
|
|
cuberight[0].verts[1][1] =-verts_height;
|
|
cuberight[0].verts[1][2] =-1.0;
|
|
cuberight[0].u[1] = uv_height;
|
|
cuberight[0].v[1] = 0.0;
|
|
|
|
cuberight[0].verts[2][0] = 1.0;
|
|
cuberight[0].verts[2][1] =-verts_height;
|
|
cuberight[0].verts[2][2] = 1.0;
|
|
cuberight[0].u[2] = uv_height;
|
|
cuberight[0].v[2] = uv_ratio;
|
|
|
|
//second triangle
|
|
cuberight[1].verts[0][0] = 1.0;
|
|
cuberight[1].verts[0][1] =-verts_height;
|
|
cuberight[1].verts[0][2] =-1.0;
|
|
cuberight[1].u[0] = uv_height;
|
|
cuberight[1].v[0] = 0.0;
|
|
|
|
cuberight[1].verts[1][0] = 1.0;
|
|
cuberight[1].verts[1][1] = 1.0;
|
|
cuberight[1].verts[1][2] = 1.0;
|
|
cuberight[1].u[1] = 0.0;
|
|
cuberight[1].v[1] = uv_ratio;
|
|
|
|
cuberight[1].verts[2][0] = 1.0;
|
|
cuberight[1].verts[2][1] = 1.0;
|
|
cuberight[1].verts[2][2] =-1.0;
|
|
cuberight[1].u[2] = 0.0;
|
|
cuberight[1].v[2] = 0.0;
|
|
|
|
nfacesright = 2;
|
|
|
|
// top Face - 2 triangles
|
|
cubetop[0].verts[0][0] =-1.0;
|
|
cubetop[0].verts[0][1] = 1.0;
|
|
cubetop[0].verts[0][2] = 1.0;
|
|
cubetop[0].u[0] = 0.0;
|
|
cubetop[0].v[0] = 0.0;
|
|
|
|
cubetop[0].verts[1][0] = 1.0;
|
|
cubetop[0].verts[1][1] =-verts_height;
|
|
cubetop[0].verts[1][2] = 1.0;
|
|
cubetop[0].u[1] = uv_ratio;
|
|
cubetop[0].v[1] = uv_height;
|
|
|
|
cubetop[0].verts[2][0] =-1.0;
|
|
cubetop[0].verts[2][1] =-verts_height;
|
|
cubetop[0].verts[2][2] = 1.0;
|
|
cubetop[0].u[2] = 0.0;
|
|
cubetop[0].v[2] = uv_height;
|
|
|
|
//second triangle
|
|
cubetop[1].verts[0][0] = 1.0;
|
|
cubetop[1].verts[0][1] =-verts_height;
|
|
cubetop[1].verts[0][2] = 1.0;
|
|
cubetop[1].u[0] = uv_ratio;
|
|
cubetop[1].v[0] = uv_height;
|
|
|
|
cubetop[1].verts[1][0] =-1.0;
|
|
cubetop[1].verts[1][1] = 1.0;
|
|
cubetop[1].verts[1][2] = 1.0;
|
|
cubetop[1].u[1] = 0.0;
|
|
cubetop[1].v[1] = 0.0;
|
|
|
|
cubetop[1].verts[2][0] = 1.0;
|
|
cubetop[1].verts[2][1] = 1.0;
|
|
cubetop[1].verts[2][2] = 1.0;
|
|
cubetop[1].u[2] = uv_ratio;
|
|
cubetop[1].v[2] = 0.0;
|
|
|
|
nfacestop = 2;
|
|
|
|
// bottom Face - 2 triangles
|
|
cubebottom[0].verts[0][0] =-1.0;
|
|
cubebottom[0].verts[0][1] =-verts_height;
|
|
cubebottom[0].verts[0][2] =-1.0;
|
|
cubebottom[0].u[0] = 0.0;
|
|
cubebottom[0].v[0] = uv_base;
|
|
|
|
cubebottom[0].verts[1][0] = 1.0;
|
|
cubebottom[0].verts[1][1] = 1.0;
|
|
cubebottom[0].verts[1][2] =-1.0;
|
|
cubebottom[0].u[1] = uv_ratio;
|
|
cubebottom[0].v[1] = uv_ratio;
|
|
|
|
cubebottom[0].verts[2][0] =-1.0;
|
|
cubebottom[0].verts[2][1] = 1.0;
|
|
cubebottom[0].verts[2][2] =-1.0;
|
|
cubebottom[0].u[2] = 0.0;
|
|
cubebottom[0].v[2] = uv_ratio;
|
|
|
|
//second triangle
|
|
cubebottom[1].verts[0][0] = 1.0;
|
|
cubebottom[1].verts[0][1] = 1.0;
|
|
cubebottom[1].verts[0][2] =-1.0;
|
|
cubebottom[1].u[0] = uv_ratio;
|
|
cubebottom[1].v[0] = uv_ratio;
|
|
|
|
cubebottom[1].verts[1][0] =-1.0;
|
|
cubebottom[1].verts[1][1] =-verts_height;
|
|
cubebottom[1].verts[1][2] =-1.0;
|
|
cubebottom[1].u[1] = 0.0;
|
|
cubebottom[1].v[1] = uv_base;
|
|
|
|
cubebottom[1].verts[2][0] = 1.0;
|
|
cubebottom[1].verts[2][1] =-verts_height;
|
|
cubebottom[1].verts[2][2] =-1.0;
|
|
cubebottom[1].u[2] = uv_ratio;
|
|
cubebottom[1].v[2] = uv_base;
|
|
|
|
nfacesbottom = 2;
|
|
|
|
//Refine a triangular mesh by bisecting each edge forms 3 new triangles for each existing triangle on each iteration
|
|
//It could be made more efficient for drawing if the triangles were ordered in a strip!
|
|
|
|
for (i=0;i<m_resolution;i++) {
|
|
cubefront.resize(4*nfacesfront);
|
|
SplitFace(cubefront,&nfacesfront);
|
|
cubetop.resize(4*nfacestop);
|
|
SplitFace(cubetop,&nfacestop);
|
|
cubebottom.resize(4*nfacesbottom);
|
|
SplitFace(cubebottom,&nfacesbottom);
|
|
cubeleft.resize(4*nfacesleft);
|
|
SplitFace(cubeleft,&nfacesleft);
|
|
cuberight.resize(4*nfacesright);
|
|
SplitFace(cuberight,&nfacesright);
|
|
}
|
|
|
|
// Turn into a hemisphere/sphere
|
|
for (j=0;j<3;j++) {
|
|
for (i=0;i<nfacesfront;i++)
|
|
cubefront[i].verts[j].normalize();
|
|
for (i=0;i<nfacestop;i++)
|
|
cubetop[i].verts[j].normalize();
|
|
for (i=0;i<nfacesbottom;i++)
|
|
cubebottom[i].verts[j].normalize();
|
|
for (i=0;i<nfacesleft;i++)
|
|
cubeleft[i].verts[j].normalize();
|
|
for (i=0;i<nfacesright;i++)
|
|
cuberight[i].verts[j].normalize();
|
|
}
|
|
|
|
//flatten onto xz plane
|
|
for (i=0;i<nfacesfront;i++)
|
|
FlattenDome(cubefront[i].verts);
|
|
for (i=0;i<nfacestop;i++)
|
|
FlattenDome(cubetop[i].verts);
|
|
for (i=0;i<nfacesbottom;i++)
|
|
FlattenDome(cubebottom[i].verts);
|
|
for (i=0;i<nfacesleft;i++)
|
|
FlattenDome(cubeleft[i].verts);
|
|
for (i=0;i<nfacesright;i++)
|
|
FlattenDome(cuberight[i].verts);
|
|
}
|
|
|
|
void KX_Dome::CreateMeshPanorama(void)
|
|
{
|
|
/*
|
|
* 1)- Define the faces of a cube without the top and bottom faces
|
|
* - each face is made out of 2 triangles
|
|
* 2) Subdivide the faces
|
|
* - more resolution == more curved lines
|
|
* 3) Spherize the cube
|
|
* - normalize the verts t
|
|
* 4) Flatten onto xz plane
|
|
* - use spherical projection techniques to transform the sphere onto a flat panorama
|
|
*/
|
|
int i,j;
|
|
|
|
float uv_ratio = (float)(m_buffersize-1) / m_imagesize;
|
|
|
|
/* Top face - two triangles */
|
|
cubetop[0].verts[0][0] = -M_SQRT2;
|
|
cubetop[0].verts[0][1] = 0.0;
|
|
cubetop[0].verts[0][2] = 1.0;
|
|
cubetop[0].u[0] = 0.0;
|
|
cubetop[0].v[0] = uv_ratio;
|
|
|
|
cubetop[0].verts[1][0] = 0.0;
|
|
cubetop[0].verts[1][1] = M_SQRT2;
|
|
cubetop[0].verts[1][2] = 1.0;
|
|
cubetop[0].u[1] = 0.0;
|
|
cubetop[0].v[1] = 0.0;
|
|
|
|
//second triangle
|
|
cubetop[0].verts[2][0] = M_SQRT2;
|
|
cubetop[0].verts[2][1] = 0.0;
|
|
cubetop[0].verts[2][2] = 1.0;
|
|
cubetop[0].u[2] = uv_ratio;
|
|
cubetop[0].v[2] = 0.0;
|
|
|
|
cubetop[1].verts[0][0] = M_SQRT2;
|
|
cubetop[1].verts[0][1] = 0.0;
|
|
cubetop[1].verts[0][2] = 1.0;
|
|
cubetop[1].u[0] = uv_ratio;
|
|
cubetop[1].v[0] = 0.0;
|
|
|
|
cubetop[1].verts[1][0] = 0.0;
|
|
cubetop[1].verts[1][1] = -M_SQRT2;
|
|
cubetop[1].verts[1][2] = 1.0;
|
|
cubetop[1].u[1] = uv_ratio;
|
|
cubetop[1].v[1] = uv_ratio;
|
|
|
|
cubetop[1].verts[2][0] = -M_SQRT2;
|
|
cubetop[1].verts[2][1] = 0.0;
|
|
cubetop[1].verts[2][2] = 1.0;
|
|
cubetop[1].u[2] = 0.0;
|
|
cubetop[1].v[2] = uv_ratio;
|
|
|
|
nfacestop = 2;
|
|
|
|
/* Bottom face - two triangles */
|
|
cubebottom[0].verts[0][0] = -M_SQRT2;
|
|
cubebottom[0].verts[0][1] = 0.0;
|
|
cubebottom[0].verts[0][2] = -1.0;
|
|
cubebottom[0].u[0] = uv_ratio;
|
|
cubebottom[0].v[0] = 0.0;
|
|
|
|
cubebottom[0].verts[1][0] = M_SQRT2;
|
|
cubebottom[0].verts[1][1] = 0.0;
|
|
cubebottom[0].verts[1][2] = -1.0;
|
|
cubebottom[0].u[1] = 0.0;
|
|
cubebottom[0].v[1] = uv_ratio;
|
|
|
|
cubebottom[0].verts[2][0] = 0.0;
|
|
cubebottom[0].verts[2][1] = M_SQRT2;
|
|
cubebottom[0].verts[2][2] = -1.0;
|
|
cubebottom[0].u[2] = 0.0;
|
|
cubebottom[0].v[2] = 0.0;
|
|
|
|
//second triangle
|
|
cubebottom[1].verts[0][0] = M_SQRT2;
|
|
cubebottom[1].verts[0][1] = 0.0;
|
|
cubebottom[1].verts[0][2] = -1.0;
|
|
cubebottom[1].u[0] = 0.0;
|
|
cubebottom[1].v[0] = uv_ratio;
|
|
|
|
cubebottom[1].verts[1][0] = -M_SQRT2;
|
|
cubebottom[1].verts[1][1] = 0.0;
|
|
cubebottom[1].verts[1][2] = -1.0;
|
|
cubebottom[1].u[1] = uv_ratio;
|
|
cubebottom[1].v[1] = 0.0;
|
|
|
|
cubebottom[1].verts[2][0] = 0.0;
|
|
cubebottom[1].verts[2][1] = -M_SQRT2;
|
|
cubebottom[1].verts[2][2] = -1.0;
|
|
cubebottom[1].u[2] = uv_ratio;
|
|
cubebottom[1].v[2] = uv_ratio;
|
|
|
|
nfacesbottom = 2;
|
|
|
|
/* Left Back (135deg) face - two triangles */
|
|
|
|
cubeleftback[0].verts[0][0] = 0;
|
|
cubeleftback[0].verts[0][1] = -M_SQRT2;
|
|
cubeleftback[0].verts[0][2] = -1.0;
|
|
cubeleftback[0].u[0] = 0;
|
|
cubeleftback[0].v[0] = 0;
|
|
|
|
cubeleftback[0].verts[1][0] = -M_SQRT2;
|
|
cubeleftback[0].verts[1][1] = 0;
|
|
cubeleftback[0].verts[1][2] = -1.0;
|
|
cubeleftback[0].u[1] = uv_ratio;
|
|
cubeleftback[0].v[1] = 0;
|
|
|
|
cubeleftback[0].verts[2][0] = 0;
|
|
cubeleftback[0].verts[2][1] = -M_SQRT2;
|
|
cubeleftback[0].verts[2][2] = 1.0;
|
|
cubeleftback[0].u[2] = 0;
|
|
cubeleftback[0].v[2] = uv_ratio;
|
|
|
|
//second triangle
|
|
cubeleftback[1].verts[0][0] = 0;
|
|
cubeleftback[1].verts[0][1] = -M_SQRT2;
|
|
cubeleftback[1].verts[0][2] = 1.0;
|
|
cubeleftback[1].u[0] = 0;
|
|
cubeleftback[1].v[0] = uv_ratio;
|
|
|
|
cubeleftback[1].verts[1][0] = -M_SQRT2;
|
|
cubeleftback[1].verts[1][1] = 0;
|
|
cubeleftback[1].verts[1][2] = -1.0;
|
|
cubeleftback[1].u[1] = uv_ratio;
|
|
cubeleftback[1].v[1] = 0;
|
|
|
|
cubeleftback[1].verts[2][0] = -M_SQRT2;
|
|
cubeleftback[1].verts[2][1] = 0;
|
|
cubeleftback[1].verts[2][2] = 1.0;
|
|
cubeleftback[1].u[2] = uv_ratio;
|
|
cubeleftback[1].v[2] = uv_ratio;
|
|
|
|
nfacesleftback = 2;
|
|
|
|
/* Left face - two triangles */
|
|
|
|
cubeleft[0].verts[0][0] = -M_SQRT2;
|
|
cubeleft[0].verts[0][1] = 0;
|
|
cubeleft[0].verts[0][2] = -1.0;
|
|
cubeleft[0].u[0] = 0;
|
|
cubeleft[0].v[0] = 0;
|
|
|
|
cubeleft[0].verts[1][0] = 0;
|
|
cubeleft[0].verts[1][1] = M_SQRT2;
|
|
cubeleft[0].verts[1][2] = -1.0;
|
|
cubeleft[0].u[1] = uv_ratio;
|
|
cubeleft[0].v[1] = 0;
|
|
|
|
cubeleft[0].verts[2][0] = -M_SQRT2;
|
|
cubeleft[0].verts[2][1] = 0;
|
|
cubeleft[0].verts[2][2] = 1.0;
|
|
cubeleft[0].u[2] = 0;
|
|
cubeleft[0].v[2] = uv_ratio;
|
|
|
|
//second triangle
|
|
cubeleft[1].verts[0][0] = -M_SQRT2;
|
|
cubeleft[1].verts[0][1] = 0;
|
|
cubeleft[1].verts[0][2] = 1.0;
|
|
cubeleft[1].u[0] = 0;
|
|
cubeleft[1].v[0] = uv_ratio;
|
|
|
|
cubeleft[1].verts[1][0] = 0;
|
|
cubeleft[1].verts[1][1] = M_SQRT2;
|
|
cubeleft[1].verts[1][2] = -1.0;
|
|
cubeleft[1].u[1] = uv_ratio;
|
|
cubeleft[1].v[1] = 0;
|
|
|
|
cubeleft[1].verts[2][0] = 0;
|
|
cubeleft[1].verts[2][1] = M_SQRT2;
|
|
cubeleft[1].verts[2][2] = 1.0;
|
|
cubeleft[1].u[2] = uv_ratio;
|
|
cubeleft[1].v[2] = uv_ratio;
|
|
|
|
nfacesleft = 2;
|
|
|
|
/* Right face - two triangles */
|
|
cuberight[0].verts[0][0] = 0;
|
|
cuberight[0].verts[0][1] = M_SQRT2;
|
|
cuberight[0].verts[0][2] = -1.0;
|
|
cuberight[0].u[0] = 0;
|
|
cuberight[0].v[0] = 0;
|
|
|
|
cuberight[0].verts[1][0] = M_SQRT2;
|
|
cuberight[0].verts[1][1] = 0;
|
|
cuberight[0].verts[1][2] = -1.0;
|
|
cuberight[0].u[1] = uv_ratio;
|
|
cuberight[0].v[1] = 0;
|
|
|
|
cuberight[0].verts[2][0] = M_SQRT2;
|
|
cuberight[0].verts[2][1] = 0;
|
|
cuberight[0].verts[2][2] = 1.0;
|
|
cuberight[0].u[2] = uv_ratio;
|
|
cuberight[0].v[2] = uv_ratio;
|
|
|
|
//second triangle
|
|
cuberight[1].verts[0][0] = 0;
|
|
cuberight[1].verts[0][1] = M_SQRT2;
|
|
cuberight[1].verts[0][2] = -1.0;
|
|
cuberight[1].u[0] = 0;
|
|
cuberight[1].v[0] = 0;
|
|
|
|
cuberight[1].verts[1][0] = M_SQRT2;
|
|
cuberight[1].verts[1][1] = 0;
|
|
cuberight[1].verts[1][2] = 1.0;
|
|
cuberight[1].u[1] = uv_ratio;
|
|
cuberight[1].v[1] = uv_ratio;
|
|
|
|
cuberight[1].verts[2][0] = 0;
|
|
cuberight[1].verts[2][1] = M_SQRT2;
|
|
cuberight[1].verts[2][2] = 1.0;
|
|
cuberight[1].u[2] = 0;
|
|
cuberight[1].v[2] = uv_ratio;
|
|
|
|
nfacesright = 2;
|
|
|
|
/* Right Back (-135deg) face - two triangles */
|
|
cuberightback[0].verts[0][0] = M_SQRT2;
|
|
cuberightback[0].verts[0][1] = 0;
|
|
cuberightback[0].verts[0][2] = -1.0;
|
|
cuberightback[0].u[0] = 0;
|
|
cuberightback[0].v[0] = 0;
|
|
|
|
cuberightback[0].verts[1][0] = 0;
|
|
cuberightback[0].verts[1][1] = -M_SQRT2;
|
|
cuberightback[0].verts[1][2] = -1.0;
|
|
cuberightback[0].u[1] = uv_ratio;
|
|
cuberightback[0].v[1] = 0;
|
|
|
|
cuberightback[0].verts[2][0] = 0;
|
|
cuberightback[0].verts[2][1] = -M_SQRT2;
|
|
cuberightback[0].verts[2][2] = 1.0;
|
|
cuberightback[0].u[2] = uv_ratio;
|
|
cuberightback[0].v[2] = uv_ratio;
|
|
|
|
//second triangle
|
|
cuberightback[1].verts[0][0] = M_SQRT2;
|
|
cuberightback[1].verts[0][1] = 0;
|
|
cuberightback[1].verts[0][2] = -1.0;
|
|
cuberightback[1].u[0] = 0;
|
|
cuberightback[1].v[0] = 0;
|
|
|
|
cuberightback[1].verts[1][0] = 0;
|
|
cuberightback[1].verts[1][1] = -M_SQRT2;
|
|
cuberightback[1].verts[1][2] = 1.0;
|
|
cuberightback[1].u[1] = uv_ratio;
|
|
cuberightback[1].v[1] = uv_ratio;
|
|
|
|
cuberightback[1].verts[2][0] = M_SQRT2;
|
|
cuberightback[1].verts[2][1] = 0;
|
|
cuberightback[1].verts[2][2] = 1.0;
|
|
cuberightback[1].u[2] = 0;
|
|
cuberightback[1].v[2] = uv_ratio;
|
|
|
|
nfacesrightback = 2;
|
|
|
|
// Subdivide the faces
|
|
for (i=0;i<m_resolution;i++)
|
|
{
|
|
cubetop.resize(4*nfacestop);
|
|
SplitFace(cubetop,&nfacestop);
|
|
|
|
cubebottom.resize(4*nfacesbottom);
|
|
SplitFace(cubebottom,&nfacesbottom);
|
|
|
|
cubeleft.resize(4*nfacesleft);
|
|
SplitFace(cubeleft,&nfacesleft);
|
|
|
|
cuberight.resize(4*nfacesright);
|
|
SplitFace(cuberight,&nfacesright);
|
|
|
|
cubeleftback.resize(4*nfacesleftback);
|
|
SplitFace(cubeleftback,&nfacesleftback);
|
|
|
|
cuberightback.resize(4*nfacesrightback);
|
|
SplitFace(cuberightback,&nfacesrightback);
|
|
}
|
|
|
|
// Spherize the cube
|
|
for (j=0;j<3;j++)
|
|
{
|
|
for (i=0;i<nfacestop;i++)
|
|
cubetop[i].verts[j].normalize();
|
|
|
|
for (i=0;i<nfacesbottom;i++)
|
|
cubebottom[i].verts[j].normalize();
|
|
|
|
for (i=0;i<nfacesleftback;i++)
|
|
cubeleftback[i].verts[j].normalize();
|
|
|
|
for (i=0;i<nfacesleft;i++)
|
|
cubeleft[i].verts[j].normalize();
|
|
|
|
for (i=0;i<nfacesright;i++)
|
|
cuberight[i].verts[j].normalize();
|
|
|
|
for (i=0;i<nfacesrightback;i++)
|
|
cuberightback[i].verts[j].normalize();
|
|
}
|
|
|
|
//Flatten onto xz plane
|
|
for (i=0;i<nfacesleftback;i++)
|
|
FlattenPanorama(cubeleftback[i].verts);
|
|
|
|
for (i=0;i<nfacesleft;i++)
|
|
FlattenPanorama(cubeleft[i].verts);
|
|
|
|
for (i=0;i<nfacesright;i++)
|
|
FlattenPanorama(cuberight[i].verts);
|
|
|
|
for (i=0;i<nfacesrightback;i++)
|
|
FlattenPanorama(cuberightback[i].verts);
|
|
|
|
for (i=0;i<nfacestop;i++)
|
|
FlattenPanorama(cubetop[i].verts);
|
|
|
|
for (i=0;i<nfacesbottom;i++)
|
|
FlattenPanorama(cubebottom[i].verts);
|
|
}
|
|
|
|
void KX_Dome::FlattenDome(MT_Vector3 verts[3])
|
|
{
|
|
double phi, r;
|
|
|
|
for (int i=0;i<3;i++) {
|
|
r = atan2(sqrt(verts[i][0]*verts[i][0] + verts[i][2]*verts[i][2]), verts[i][1]);
|
|
r /= (double)this->m_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 <DomeFace>& face, int *nfaces)
|
|
{
|
|
int i;
|
|
int n1, n2;
|
|
|
|
n1 = n2 = *nfaces;
|
|
|
|
for (i=0;i<n1;i++) {
|
|
|
|
face[n2].verts[0] = (face[i].verts[0] + face[i].verts[1]) /2;
|
|
face[n2].verts[1] = face[i].verts[1];
|
|
face[n2].verts[2] = (face[i].verts[1] + face[i].verts[2]) /2;
|
|
face[n2].u[0] = (face[i].u[0] + face[i].u[1]) /2;
|
|
face[n2].u[1] = face[i].u[1];
|
|
face[n2].u[2] = (face[i].u[1] + face[i].u[2]) /2;
|
|
face[n2].v[0] = (face[i].v[0] + face[i].v[1]) /2;
|
|
face[n2].v[1] = face[i].v[1];
|
|
face[n2].v[2] = (face[i].v[1] + face[i].v[2]) /2;
|
|
|
|
face[n2+1].verts[0] = (face[i].verts[1] + face[i].verts[2]) /2;
|
|
face[n2+1].verts[1] = face[i].verts[2];
|
|
face[n2+1].verts[2] = (face[i].verts[2] + face[i].verts[0]) /2;
|
|
face[n2+1].u[0] = (face[i].u[1] + face[i].u[2]) /2;
|
|
face[n2+1].u[1] = face[i].u[2];
|
|
face[n2+1].u[2] = (face[i].u[2] + face[i].u[0]) /2;
|
|
face[n2+1].v[0] = (face[i].v[1] + face[i].v[2]) /2;
|
|
face[n2+1].v[1] = face[i].v[2];
|
|
face[n2+1].v[2] = (face[i].v[2] + face[i].v[0]) /2;
|
|
|
|
face[n2+2].verts[0] = (face[i].verts[0] + face[i].verts[1]) /2;
|
|
face[n2+2].verts[1] = (face[i].verts[1] + face[i].verts[2]) /2;
|
|
face[n2+2].verts[2] = (face[i].verts[2] + face[i].verts[0]) /2;
|
|
face[n2+2].u[0] = (face[i].u[0] + face[i].u[1]) /2;
|
|
face[n2+2].u[1] = (face[i].u[1] + face[i].u[2]) /2;
|
|
face[n2+2].u[2] = (face[i].u[2] + face[i].u[0]) /2;
|
|
face[n2+2].v[0] = (face[i].v[0] + face[i].v[1]) /2;
|
|
face[n2+2].v[1] = (face[i].v[1] + face[i].v[2]) /2;
|
|
face[n2+2].v[2] = (face[i].v[2] + face[i].v[0]) /2;
|
|
|
|
//face[i].verts[0] = face[i].verts[0];
|
|
face[i].verts[1] = (face[i].verts[0] + face[i].verts[1]) /2;
|
|
face[i].verts[2] = (face[i].verts[0] + face[i].verts[2]) /2;
|
|
//face[i].u[0] = face[i].u[0];
|
|
face[i].u[1] = (face[i].u[0] + face[i].u[1]) /2;
|
|
face[i].u[2] = (face[i].u[0] + face[i].u[2]) /2;
|
|
//face[i].v[0] = face[i].v[0];
|
|
face[i].v[1] = (face[i].v[0] + face[i].v[1]) /2;
|
|
face[i].v[2] = (face[i].v[0] + face[i].v[2]) /2;
|
|
|
|
n2 += 3; // number of faces
|
|
}
|
|
*nfaces = n2;
|
|
}
|
|
|
|
void KX_Dome::CalculateFrustum(KX_Camera *cam)
|
|
{
|
|
#if 0
|
|
// manually creating a 90deg Field of View Frustum
|
|
|
|
// the original formula:
|
|
top = tan(fov*3.14159/360.0) * near [for fov in degrees]
|
|
fov*0.5 = arctan ((top-bottom)*0.5 / near) [for fov in radians]
|
|
bottom = -top
|
|
left = aspect * bottom
|
|
right = aspect * top
|
|
|
|
// the equivalent GLU call is:
|
|
glMatrixMode(GL_PROJECTION);
|
|
glLoadIdentity();
|
|
gluPerspective(90.0,1.0,cam->GetCameraNear(),cam->GetCameraFar());
|
|
#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<m_numfaces;i++) {
|
|
glBindTexture(GL_TEXTURE_2D, domefacesId[i]);
|
|
glCallList(dlistId+i);
|
|
}
|
|
}
|
|
else { // DisplayLists not supported
|
|
// top triangle
|
|
glBindTexture(GL_TEXTURE_2D, domefacesId[0]);
|
|
GLDrawTriangles(cubetop, nfacestop);
|
|
|
|
// bottom triangle
|
|
glBindTexture(GL_TEXTURE_2D, domefacesId[1]);
|
|
GLDrawTriangles(cubebottom, nfacesbottom);
|
|
|
|
// left triangle
|
|
glBindTexture(GL_TEXTURE_2D, domefacesId[2]);
|
|
GLDrawTriangles(cubeleft, nfacesleft);
|
|
|
|
// right triangle
|
|
glBindTexture(GL_TEXTURE_2D, domefacesId[3]);
|
|
GLDrawTriangles(cuberight, nfacesright);
|
|
|
|
if (m_angle > 180) {
|
|
// front triangle
|
|
glBindTexture(GL_TEXTURE_2D, domefacesId[4]);
|
|
GLDrawTriangles(cubefront, nfacesfront);
|
|
}
|
|
}
|
|
glDisable(GL_TEXTURE_2D);
|
|
glEnable(GL_DEPTH_TEST);
|
|
}
|
|
|
|
void KX_Dome::DrawPanorama(void)
|
|
{
|
|
int i;
|
|
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<m_numfaces;i++) {
|
|
glBindTexture(GL_TEXTURE_2D, domefacesId[i]);
|
|
glCallList(dlistId+i);
|
|
}
|
|
}
|
|
else {
|
|
// domefacesId[4] => (top)
|
|
glBindTexture(GL_TEXTURE_2D, domefacesId[0]);
|
|
GLDrawTriangles(cubetop, nfacestop);
|
|
|
|
// domefacesId[5] => (bottom)
|
|
glBindTexture(GL_TEXTURE_2D, domefacesId[1]);
|
|
GLDrawTriangles(cubebottom, nfacesbottom);
|
|
|
|
// domefacesId[1] => -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);
|
|
|
|
// update levels of detail
|
|
scene->UpdateObjectLods();
|
|
}
|
|
|