blender/source/gameengine/Ketsji/KX_Dome.cpp
Benoit Bolsee 40f1c4f343 BGE: Various render improvements.
bge.logic.setRender(flag) to enable/disable render.
    The render pass is enabled by default but it can be disabled with
    bge.logic.setRender(False).
    Once disabled, the render pass is skipped and a new logic frame starts
    immediately. Note that VSync no longer limits the fps when render is off
    but the 'Use Frame Rate' option in the Render Properties still does.
    To run as many frames as possible, untick the option
    This function is useful when you don't need the default render, e.g.
    when doing offscreen render to an alternate device than the monitor.
    Note that without VSync, you must limit the frame rate by other means.

fbo = bge.render.offScreenCreate(width,height,[,samples=0][,target=bge.render.RAS_OFS_RENDER_BUFFER])
    Use this method to create an offscreen buffer of given size, with given MSAA
    samples and targetting either a render buffer (bge.render.RAS_OFS_RENDER_BUFFER)
    or a texture (bge.render.RAS_OFS_RENDER_TEXTURE). Use the former if you want to
    retrieve the frame buffer on the host and the latter if you want to pass the render
    to another context (texture are proper OGL object, render buffers aren't)
    The object created by this function can only be used as a parameter of the
    bge.texture.ImageRender() constructor to send the the render to the FBO rather
    than to the frame buffer. This is best suited when you want to create a render
    of specific size, or if you need an image with an alpha channel.

bge.texture.<imagetype>.refresh(buffer=None, format="RGBA", ts=-1.0)
    Without arg, the refresh method of the image objects is pretty much a no-op, it
    simply invalidates the image so that on next texture refresh, the image will
    be recalculated.
    It is now possible to pass an optional buffer object to transfer the image (and
    recalculate it if it was invalid) to an external object. The object must implement
    the 'buffer protocol'. The image will be transfered as "RGBA" or "BGRA" pixels
    depending on format argument (only those 2 formats are supported) and ts is an
    optional timestamp in the image depends on it (e.g. VideoFFmpeg playing a video file).
    With this function you don't need anymore to link the image object to a Texture
    object to use: the image object is self-sufficient.

bge.texture.ImageRender(scene, camera, fbo=None)
    Render to buffer is possible by passing a FBO object (see offScreenCreate).

bge.texture.ImageRender.render()
    Allows asynchronous render: call this method to render the scene but without
    extracting the pixels yet. The function returns as soon as the render commands
    have been send to the GPU. The render will proceed asynchronously in the GPU
    while the host can perform other tasks.
    To complete the render, you can either call refresh() directly of refresh the texture
    to which this object is the source. Asynchronous render is useful to achieve optimal
    performance: call render() on frame N and refresh() on frame N+1 to give as much as
    time as possible to the GPU to render the frame while the game engine can perform other tasks.

Support negative scale on camera.
    Camera scale was previously ignored in the BGE.
    It is now injected in the modelview matrix as a vertical or horizontal flip
    of the scene (respectively if scaleY<0 and scaleX<0).
    Note that the actual value of the scale is not used, only the sign.
    This allows to flip the image produced by ImageRender() without any performance
    degradation: the flip is integrated in the render itself.

Optimized image transfer from ImageRender to buffer.
    Previously, images that were transferred to the host were always going through
    buffers in VideoTexture. It is now possible to transfer ImageRender
    images to external buffer without intermediate copy (i.e. directly from OGL to buffer)
    if the attributes of the ImageRender objects are set as follow:
       flip=False, alpha=True, scale=False, depth=False, zbuff=False.
       (if you need to flip the image, use camera negative scale)
2016-06-11 22:05:20 +02:00

2052 lines
55 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 "glew-mx.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(rasterizer->GetDrawingMode()),
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.0f);
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.0f);
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.0f);
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.0f);
}
}
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.0f);
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.0f);
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.0f);
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.0f);
}
}
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] = (float)(-M_SQRT2) / 2.0f;
cubetop[0].verts[0][1] = 0.0f;
cubetop[0].verts[0][2] = 0.5f;
cubetop[0].u[0] = 0.0;
cubetop[0].v[0] = uv_ratio;
cubetop[0].verts[1][0] = 0.0f;
cubetop[0].verts[1][1] = (float)M_SQRT2 / 2.0f;
cubetop[0].verts[1][2] = 0.5f;
cubetop[0].u[1] = 0.0;
cubetop[0].v[1] = 0.0;
cubetop[0].verts[2][0] = (float)M_SQRT2 / 2.0f;
cubetop[0].verts[2][1] = 0.0f;
cubetop[0].verts[2][2] = 0.5f;
cubetop[0].u[2] = uv_ratio;
cubetop[0].v[2] = 0.0;
nfacestop = 1;
/* Bottom face - just a triangle */
cubebottom[0].verts[0][0] = (float)(-M_SQRT2) / 2.0f;
cubebottom[0].verts[0][1] = 0.0f;
cubebottom[0].verts[0][2] = -0.5f;
cubebottom[0].u[0] = uv_ratio;
cubebottom[0].v[0] = 0.0;
cubebottom[0].verts[1][0] = (float)M_SQRT2 / 2.0f;
cubebottom[0].verts[1][1] = 0;
cubebottom[0].verts[1][2] = -0.5f;
cubebottom[0].u[1] = 0.0;
cubebottom[0].v[1] = uv_ratio;
cubebottom[0].verts[2][0] = 0.0f;
cubebottom[0].verts[2][1] = (float)M_SQRT2 / 2.0f;
cubebottom[0].verts[2][2] = -0.5f;
cubebottom[0].u[2] = 0.0;
cubebottom[0].v[2] = 0.0;
nfacesbottom = 1;
/* Left face - two triangles */
cubeleft[0].verts[0][0] = (float)(-M_SQRT2) / 2.0f;
cubeleft[0].verts[0][1] = 0.0f;
cubeleft[0].verts[0][2] = -0.5f;
cubeleft[0].u[0] = 0.0;
cubeleft[0].v[0] = 0.0;
cubeleft[0].verts[1][0] = 0.0f;
cubeleft[0].verts[1][1] = (float)M_SQRT2 / 2.0f;
cubeleft[0].verts[1][2] = -0.5f;
cubeleft[0].u[1] = uv_ratio;
cubeleft[0].v[1] = 0.0;
cubeleft[0].verts[2][0] = (float)(-M_SQRT2) / 2.0f;
cubeleft[0].verts[2][1] = 0.0f;
cubeleft[0].verts[2][2] = 0.5f;
cubeleft[0].u[2] = 0.0;
cubeleft[0].v[2] = uv_ratio;
//second triangle
cubeleft[1].verts[0][0] = (float)(-M_SQRT2) / 2.0f;
cubeleft[1].verts[0][1] = 0.0f;
cubeleft[1].verts[0][2] = 0.5f;
cubeleft[1].u[0] = 0.0;
cubeleft[1].v[0] = uv_ratio;
cubeleft[1].verts[1][0] = 0.0f;
cubeleft[1].verts[1][1] = (float)M_SQRT2 / 2.0f;
cubeleft[1].verts[1][2] = -0.5f;
cubeleft[1].u[1] = uv_ratio;
cubeleft[1].v[1] = 0.0;
cubeleft[1].verts[2][0] = 0.0f;
cubeleft[1].verts[2][1] = (float)M_SQRT2 / 2.0f;
cubeleft[1].verts[2][2] = 0.5f;
cubeleft[1].u[2] = uv_ratio;
cubeleft[1].v[2] = uv_ratio;
nfacesleft = 2;
/* Right face - two triangles */
cuberight[0].verts[0][0] = 0.0f;
cuberight[0].verts[0][1] = (float)M_SQRT2 / 2.0f;
cuberight[0].verts[0][2] = -0.5f;
cuberight[0].u[0] = 0.0;
cuberight[0].v[0] = 0.0;
cuberight[0].verts[1][0] = (float)M_SQRT2 / 2.0f;
cuberight[0].verts[1][1] = 0.0f;
cuberight[0].verts[1][2] = -0.5f;
cuberight[0].u[1] = uv_ratio;
cuberight[0].v[1] = 0.0;
cuberight[0].verts[2][0] = (float)M_SQRT2 / 2.0f;
cuberight[0].verts[2][1] = 0.0f;
cuberight[0].verts[2][2] = 0.5f;
cuberight[0].u[2] = uv_ratio;
cuberight[0].v[2] = uv_ratio;
//second triangle
cuberight[1].verts[0][0] = 0.0f;
cuberight[1].verts[0][1] = (float)M_SQRT2 / 2.0f;
cuberight[1].verts[0][2] = -0.5f;
cuberight[1].u[0] = 0.0;
cuberight[1].v[0] = 0.0;
cuberight[1].verts[1][0] = (float)M_SQRT2 / 2.0f;
cuberight[1].verts[1][1] = 0.0f;
cuberight[1].verts[1][2] = 0.5f;
cuberight[1].u[1] = uv_ratio;
cuberight[1].v[1] = uv_ratio;
cuberight[1].verts[2][0] = 0.0f;
cuberight[1].verts[2][1] = (float)M_SQRT2 / 2.0f;
cuberight[1].verts[2][2] = 0.5f;
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.0f;
float uv_ratio = (float)(m_buffersize-1) / m_imagesize;
m_radangle = m_angle * (float)M_PI/180.0f;//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) - (MT_PI / 2.0f)) * (float)M_SQRT2;
uv_height = uv_ratio * ( (verts_height / 2.0f) + 0.5f);
uv_base = uv_ratio * (1.0f - ((verts_height / 2.0f) + 0.5f));
//creating faces for the env mapcube 180deg Dome
// Front Face - 2 triangles
cubefront[0].verts[0][0] =-1.0f;
cubefront[0].verts[0][1] = 1.0f;
cubefront[0].verts[0][2] =-1.0f;
cubefront[0].u[0] = 0.0;
cubefront[0].v[0] = 0.0;
cubefront[0].verts[1][0] = 1.0f;
cubefront[0].verts[1][1] = 1.0f;
cubefront[0].verts[1][2] = 1.0f;
cubefront[0].u[1] = uv_ratio;
cubefront[0].v[1] = uv_ratio;
cubefront[0].verts[2][0] =-1.0f;
cubefront[0].verts[2][1] = 1.0f;
cubefront[0].verts[2][2] = 1.0f;
cubefront[0].u[2] = 0.0;
cubefront[0].v[2] = uv_ratio;
//second triangle
cubefront[1].verts[0][0] = 1.0f;
cubefront[1].verts[0][1] = 1.0f;
cubefront[1].verts[0][2] = 1.0f;
cubefront[1].u[0] = uv_ratio;
cubefront[1].v[0] = uv_ratio;
cubefront[1].verts[1][0] =-1.0f;
cubefront[1].verts[1][1] = 1.0f;
cubefront[1].verts[1][2] =-1.0f;
cubefront[1].u[1] = 0.0;
cubefront[1].v[1] = 0.0;
cubefront[1].verts[2][0] = 1.0f;
cubefront[1].verts[2][1] = 1.0f;
cubefront[1].verts[2][2] =-1.0f;
cubefront[1].u[2] = uv_ratio;
cubefront[1].v[2] = 0.0;
nfacesfront = 2;
// Left Face - 2 triangles
cubeleft[0].verts[0][0] =-1.0f;
cubeleft[0].verts[0][1] = 1.0f;
cubeleft[0].verts[0][2] =-1.0f;
cubeleft[0].u[0] = uv_ratio;
cubeleft[0].v[0] = 0.0;
cubeleft[0].verts[1][0] =-1.0f;
cubeleft[0].verts[1][1] =-verts_height;
cubeleft[0].verts[1][2] = 1.0f;
cubeleft[0].u[1] = uv_base;
cubeleft[0].v[1] = uv_ratio;
cubeleft[0].verts[2][0] =-1.0f;
cubeleft[0].verts[2][1] =-verts_height;
cubeleft[0].verts[2][2] =-1.0f;
cubeleft[0].u[2] = uv_base;
cubeleft[0].v[2] = 0.0;
//second triangle
cubeleft[1].verts[0][0] =-1.0f;
cubeleft[1].verts[0][1] =-verts_height;
cubeleft[1].verts[0][2] = 1.0f;
cubeleft[1].u[0] = uv_base;
cubeleft[1].v[0] = uv_ratio;
cubeleft[1].verts[1][0] =-1.0f;
cubeleft[1].verts[1][1] = 1.0f;
cubeleft[1].verts[1][2] =-1.0f;
cubeleft[1].u[1] = uv_ratio;
cubeleft[1].v[1] = 0.0;
cubeleft[1].verts[2][0] =-1.0f;
cubeleft[1].verts[2][1] = 1.0f;
cubeleft[1].verts[2][2] = 1.0f;
cubeleft[1].u[2] = uv_ratio;
cubeleft[1].v[2] = uv_ratio;
nfacesleft = 2;
// right Face - 2 triangles
cuberight[0].verts[0][0] = 1.0f;
cuberight[0].verts[0][1] = 1.0f;
cuberight[0].verts[0][2] = 1.0f;
cuberight[0].u[0] = 0.0;
cuberight[0].v[0] = uv_ratio;
cuberight[0].verts[1][0] = 1.0f;
cuberight[0].verts[1][1] =-verts_height;
cuberight[0].verts[1][2] =-1.0f;
cuberight[0].u[1] = uv_height;
cuberight[0].v[1] = 0.0;
cuberight[0].verts[2][0] = 1.0f;
cuberight[0].verts[2][1] =-verts_height;
cuberight[0].verts[2][2] = 1.0f;
cuberight[0].u[2] = uv_height;
cuberight[0].v[2] = uv_ratio;
//second triangle
cuberight[1].verts[0][0] = 1.0f;
cuberight[1].verts[0][1] =-verts_height;
cuberight[1].verts[0][2] =-1.0f;
cuberight[1].u[0] = uv_height;
cuberight[1].v[0] = 0.0;
cuberight[1].verts[1][0] = 1.0f;
cuberight[1].verts[1][1] = 1.0f;
cuberight[1].verts[1][2] = 1.0f;
cuberight[1].u[1] = 0.0;
cuberight[1].v[1] = uv_ratio;
cuberight[1].verts[2][0] = 1.0f;
cuberight[1].verts[2][1] = 1.0f;
cuberight[1].verts[2][2] =-1.0f;
cuberight[1].u[2] = 0.0;
cuberight[1].v[2] = 0.0;
nfacesright = 2;
// top Face - 2 triangles
cubetop[0].verts[0][0] =-1.0f;
cubetop[0].verts[0][1] = 1.0f;
cubetop[0].verts[0][2] = 1.0f;
cubetop[0].u[0] = 0.0;
cubetop[0].v[0] = 0.0;
cubetop[0].verts[1][0] = 1.0f;
cubetop[0].verts[1][1] =-verts_height;
cubetop[0].verts[1][2] = 1.0f;
cubetop[0].u[1] = uv_ratio;
cubetop[0].v[1] = uv_height;
cubetop[0].verts[2][0] =-1.0f;
cubetop[0].verts[2][1] =-verts_height;
cubetop[0].verts[2][2] = 1.0f;
cubetop[0].u[2] = 0.0;
cubetop[0].v[2] = uv_height;
//second triangle
cubetop[1].verts[0][0] = 1.0f;
cubetop[1].verts[0][1] =-verts_height;
cubetop[1].verts[0][2] = 1.0f;
cubetop[1].u[0] = uv_ratio;
cubetop[1].v[0] = uv_height;
cubetop[1].verts[1][0] =-1.0f;
cubetop[1].verts[1][1] = 1.0f;
cubetop[1].verts[1][2] = 1.0f;
cubetop[1].u[1] = 0.0;
cubetop[1].v[1] = 0.0;
cubetop[1].verts[2][0] = 1.0f;
cubetop[1].verts[2][1] = 1.0f;
cubetop[1].verts[2][2] = 1.0f;
cubetop[1].u[2] = uv_ratio;
cubetop[1].v[2] = 0.0;
nfacestop = 2;
// bottom Face - 2 triangles
cubebottom[0].verts[0][0] =-1.0f;
cubebottom[0].verts[0][1] =-verts_height;
cubebottom[0].verts[0][2] =-1.0f;
cubebottom[0].u[0] = 0.0;
cubebottom[0].v[0] = uv_base;
cubebottom[0].verts[1][0] = 1.0f;
cubebottom[0].verts[1][1] = 1.0f;
cubebottom[0].verts[1][2] =-1.0f;
cubebottom[0].u[1] = uv_ratio;
cubebottom[0].v[1] = uv_ratio;
cubebottom[0].verts[2][0] =-1.0f;
cubebottom[0].verts[2][1] = 1.0f;
cubebottom[0].verts[2][2] =-1.0f;
cubebottom[0].u[2] = 0.0;
cubebottom[0].v[2] = uv_ratio;
//second triangle
cubebottom[1].verts[0][0] = 1.0f;
cubebottom[1].verts[0][1] = 1.0f;
cubebottom[1].verts[0][2] =-1.0f;
cubebottom[1].u[0] = uv_ratio;
cubebottom[1].v[0] = uv_ratio;
cubebottom[1].verts[1][0] =-1.0f;
cubebottom[1].verts[1][1] =-verts_height;
cubebottom[1].verts[1][2] =-1.0f;
cubebottom[1].u[1] = 0.0;
cubebottom[1].v[1] = uv_base;
cubebottom[1].verts[2][0] = 1.0f;
cubebottom[1].verts[2][1] =-verts_height;
cubebottom[1].verts[2][2] =-1.0f;
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] = (float)(-M_SQRT2);
cubetop[0].verts[0][1] = 0.0f;
cubetop[0].verts[0][2] = 1.0f;
cubetop[0].u[0] = 0.0;
cubetop[0].v[0] = uv_ratio;
cubetop[0].verts[1][0] = 0.0f;
cubetop[0].verts[1][1] = (float)M_SQRT2;
cubetop[0].verts[1][2] = 1.0f;
cubetop[0].u[1] = 0.0;
cubetop[0].v[1] = 0.0;
//second triangle
cubetop[0].verts[2][0] = (float)M_SQRT2;
cubetop[0].verts[2][1] = 0.0f;
cubetop[0].verts[2][2] = 1.0f;
cubetop[0].u[2] = uv_ratio;
cubetop[0].v[2] = 0.0;
cubetop[1].verts[0][0] = (float)M_SQRT2;
cubetop[1].verts[0][1] = 0.0f;
cubetop[1].verts[0][2] = 1.0f;
cubetop[1].u[0] = uv_ratio;
cubetop[1].v[0] = 0.0;
cubetop[1].verts[1][0] = 0.0f;
cubetop[1].verts[1][1] = (float)(-M_SQRT2);
cubetop[1].verts[1][2] = 1.0f;
cubetop[1].u[1] = uv_ratio;
cubetop[1].v[1] = uv_ratio;
cubetop[1].verts[2][0] = (float)(-M_SQRT2);
cubetop[1].verts[2][1] = 0.0f;
cubetop[1].verts[2][2] = 1.0f;
cubetop[1].u[2] = 0.0;
cubetop[1].v[2] = uv_ratio;
nfacestop = 2;
/* Bottom face - two triangles */
cubebottom[0].verts[0][0] = (float)(-M_SQRT2);
cubebottom[0].verts[0][1] = 0.0f;
cubebottom[0].verts[0][2] = -1.0f;
cubebottom[0].u[0] = uv_ratio;
cubebottom[0].v[0] = 0.0;
cubebottom[0].verts[1][0] = (float)M_SQRT2;
cubebottom[0].verts[1][1] = 0.0f;
cubebottom[0].verts[1][2] = -1.0f;
cubebottom[0].u[1] = 0.0;
cubebottom[0].v[1] = uv_ratio;
cubebottom[0].verts[2][0] = 0.0f;
cubebottom[0].verts[2][1] = (float)M_SQRT2;
cubebottom[0].verts[2][2] = -1.0f;
cubebottom[0].u[2] = 0.0;
cubebottom[0].v[2] = 0.0;
//second triangle
cubebottom[1].verts[0][0] = (float)M_SQRT2;
cubebottom[1].verts[0][1] = 0.0f;
cubebottom[1].verts[0][2] = -1.0f;
cubebottom[1].u[0] = 0.0;
cubebottom[1].v[0] = uv_ratio;
cubebottom[1].verts[1][0] = (float)(-M_SQRT2);
cubebottom[1].verts[1][1] = 0.0f;
cubebottom[1].verts[1][2] = -1.0f;
cubebottom[1].u[1] = uv_ratio;
cubebottom[1].v[1] = 0.0;
cubebottom[1].verts[2][0] = 0.0f;
cubebottom[1].verts[2][1] = (float)(-M_SQRT2);
cubebottom[1].verts[2][2] = -1.0f;
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.0f;
cubeleftback[0].verts[0][1] = (float)(-M_SQRT2);
cubeleftback[0].verts[0][2] = -1.0f;
cubeleftback[0].u[0] = 0.0;
cubeleftback[0].v[0] = 0.0;
cubeleftback[0].verts[1][0] = (float)(-M_SQRT2);
cubeleftback[0].verts[1][1] = 0.0f;
cubeleftback[0].verts[1][2] = -1.0f;
cubeleftback[0].u[1] = uv_ratio;
cubeleftback[0].v[1] = 0.0;
cubeleftback[0].verts[2][0] = 0.0f;
cubeleftback[0].verts[2][1] = (float)(-M_SQRT2);
cubeleftback[0].verts[2][2] = 1.0f;
cubeleftback[0].u[2] = 0.0;
cubeleftback[0].v[2] = uv_ratio;
//second triangle
cubeleftback[1].verts[0][0] = 0.0f;
cubeleftback[1].verts[0][1] = (float)(-M_SQRT2);
cubeleftback[1].verts[0][2] = 1.0f;
cubeleftback[1].u[0] = 0.0;
cubeleftback[1].v[0] = uv_ratio;
cubeleftback[1].verts[1][0] = (float)(-M_SQRT2);
cubeleftback[1].verts[1][1] = 0.0f;
cubeleftback[1].verts[1][2] = -1.0f;
cubeleftback[1].u[1] = uv_ratio;
cubeleftback[1].v[1] = 0.0;
cubeleftback[1].verts[2][0] = (float)(-M_SQRT2);
cubeleftback[1].verts[2][1] = 0.0f;
cubeleftback[1].verts[2][2] = 1.0f;
cubeleftback[1].u[2] = uv_ratio;
cubeleftback[1].v[2] = uv_ratio;
nfacesleftback = 2;
/* Left face - two triangles */
cubeleft[0].verts[0][0] = (float)(-M_SQRT2);
cubeleft[0].verts[0][1] = 0.0f;
cubeleft[0].verts[0][2] = -1.0f;
cubeleft[0].u[0] = 0.0;
cubeleft[0].v[0] = 0.0;
cubeleft[0].verts[1][0] = 0.0f;
cubeleft[0].verts[1][1] = (float)M_SQRT2;
cubeleft[0].verts[1][2] = -1.0f;
cubeleft[0].u[1] = uv_ratio;
cubeleft[0].v[1] = 0.0;
cubeleft[0].verts[2][0] = (float)(-M_SQRT2);
cubeleft[0].verts[2][1] = 0.0f;
cubeleft[0].verts[2][2] = 1.0f;
cubeleft[0].u[2] = 0.0;
cubeleft[0].v[2] = uv_ratio;
//second triangle
cubeleft[1].verts[0][0] = (float)(-M_SQRT2);
cubeleft[1].verts[0][1] = 0.0f;
cubeleft[1].verts[0][2] = 1.0f;
cubeleft[1].u[0] = 0.0;
cubeleft[1].v[0] = uv_ratio;
cubeleft[1].verts[1][0] = 0.0f;
cubeleft[1].verts[1][1] = (float)M_SQRT2;
cubeleft[1].verts[1][2] = -1.0f;
cubeleft[1].u[1] = uv_ratio;
cubeleft[1].v[1] = 0.0;
cubeleft[1].verts[2][0] = 0.0f;
cubeleft[1].verts[2][1] = (float)M_SQRT2;
cubeleft[1].verts[2][2] = 1.0f;
cubeleft[1].u[2] = uv_ratio;
cubeleft[1].v[2] = uv_ratio;
nfacesleft = 2;
/* Right face - two triangles */
cuberight[0].verts[0][0] = 0.0f;
cuberight[0].verts[0][1] = (float)M_SQRT2;
cuberight[0].verts[0][2] = -1.0f;
cuberight[0].u[0] = 0.0;
cuberight[0].v[0] = 0.0;
cuberight[0].verts[1][0] = (float)M_SQRT2;
cuberight[0].verts[1][1] = 0.0f;
cuberight[0].verts[1][2] = -1.0f;
cuberight[0].u[1] = uv_ratio;
cuberight[0].v[1] = 0.0;
cuberight[0].verts[2][0] = (float)M_SQRT2;
cuberight[0].verts[2][1] = 0.0f;
cuberight[0].verts[2][2] = 1.0f;
cuberight[0].u[2] = uv_ratio;
cuberight[0].v[2] = uv_ratio;
//second triangle
cuberight[1].verts[0][0] = 0.0f;
cuberight[1].verts[0][1] = (float)M_SQRT2;
cuberight[1].verts[0][2] = -1.0f;
cuberight[1].u[0] = 0.0;
cuberight[1].v[0] = 0.0;
cuberight[1].verts[1][0] = (float)M_SQRT2;
cuberight[1].verts[1][1] = 0.0f;
cuberight[1].verts[1][2] = 1.0f;
cuberight[1].u[1] = uv_ratio;
cuberight[1].v[1] = uv_ratio;
cuberight[1].verts[2][0] = 0.0f;
cuberight[1].verts[2][1] = (float)M_SQRT2;
cuberight[1].verts[2][2] = 1.0f;
cuberight[1].u[2] = 0.0f;
cuberight[1].v[2] = uv_ratio;
nfacesright = 2;
/* Right Back (-135deg) face - two triangles */
cuberightback[0].verts[0][0] = (float)M_SQRT2;
cuberightback[0].verts[0][1] = 0.0f;
cuberightback[0].verts[0][2] = -1.0f;
cuberightback[0].u[0] = 0.0;
cuberightback[0].v[0] = 0.0;
cuberightback[0].verts[1][0] = 0.0f;
cuberightback[0].verts[1][1] = (float)(-M_SQRT2);
cuberightback[0].verts[1][2] = -1.0f;
cuberightback[0].u[1] = uv_ratio;
cuberightback[0].v[1] = 0.0;
cuberightback[0].verts[2][0] = 0.0f;
cuberightback[0].verts[2][1] = (float)(-M_SQRT2);
cuberightback[0].verts[2][2] = 1.0f;
cuberightback[0].u[2] = uv_ratio;
cuberightback[0].v[2] = uv_ratio;
//second triangle
cuberightback[1].verts[0][0] = (float)M_SQRT2;
cuberightback[1].verts[0][1] = 0.0f;
cuberightback[1].verts[0][2] = -1.0f;
cuberightback[1].u[0] = 0.0;
cuberightback[1].v[0] = 0.0;
cuberightback[1].verts[1][0] = 0.0f;
cuberightback[1].verts[1][1] = (float)(-M_SQRT2);
cuberightback[1].verts[1][2] = 1.0f;
cuberightback[1].u[1] = uv_ratio;
cuberightback[1].v[1] = uv_ratio;
cuberightback[1].verts[2][0] = (float)M_SQRT2;
cuberightback[1].verts[2][1] = 0.0f;
cuberightback[1].verts[2][2] = 1.0f;
cuberightback[1].u[2] = 0.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.0f;
verts[i][2] = r * sin(phi);
if (r > 1.0) {
//round the border
verts[i][0] = cos(phi);
verts[i][1] = -3.0f;
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.0f;
theta = asin(verts[i][2]);
verts[i][2] = theta / MT_PI;
}
if (edge) {
bool right=false;
for (i=0;i<3;i++) {
if (fmodf(verts[i][0],1.0f) > 0.0f) {
right=true;
break;
}
}
if (right) {
for (i=0;i<3;i++) {
if (verts[i][0] < 0.0f)
verts[i][0] *= -1.0f;
}
}
}
}
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.14159f/30.0f)) * near [for fov in degrees]
fov*0.5f = arctan ((top-bottom)*0.5f / near) [for fov in radians]
bottom = -top
left = aspect * bottom
right = aspect * top
// the equivalent GLU call is:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.0f,1.0f,cam->GetCameraNear(),cam->GetCameraFar());
#endif
RAS_FrameFrustum m_frustum; //90 deg. Frustum
m_frustum.camnear = cam->GetCameraNear();
m_frustum.camfar = cam->GetCameraFar();
// float top = tan(90.0f*MT_PI/360.0f) * m_frustum.camnear;
float top = m_frustum.camnear; // for deg = 90deg, tan = 1
m_frustum.x1 = -top;
m_frustum.x2 = top;
m_frustum.y1 = -top;
m_frustum.y2 = top;
m_projmat = m_rasterizer->GetFrustumMatrix(
m_frustum.x1, m_frustum.x2, m_frustum.y1, m_frustum.y2, m_frustum.camnear, m_frustum.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.0f;
MT_Scalar c = cosf(deg45);
MT_Scalar s = sinf(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.0f,
0.0f,0.0f, -1.0f,
s, c, 0.0f);
m_locRot[1] = MT_Matrix3x3( // 90deg - Bottom
-s, c, 0.0f,
0.0f,0.0f, 1.0f,
s, c, 0.0f);
m_locRot[2] = MT_Matrix3x3( // 45deg - Left
c, 0.0f, s,
0, 1.0f, 0.0f,
-s, 0.0f, c);
m_locRot[3] = MT_Matrix3x3( // 45deg - Right
c, 0.0f, -s,
0.0f, 1.0f, 0.0f,
s, 0.0f, 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.0f, 0.0f, 0.0f,
0.0f, 0.0f,-1.0f,
0.0f, 1.0f, 0.0f);
m_locRot[1] = MT_Matrix3x3( // 90deg - Bottom
1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f,-1.0f, 0.0f);
m_locRot[2] = MT_Matrix3x3( // -90deg - Left
0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f,
-1.0f, 0.0f, 0.0f);
m_locRot[3] = MT_Matrix3x3( // 90deg - Right
0.0f, 0.0f,-1.0f,
0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 0.0f);
m_locRot[4] = MT_Matrix3x3( // 0deg - Front
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f);
m_locRot[5] = MT_Matrix3x3( // 180deg - Back - USED for ENVMAP only
-1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f,-1.0f);
} else if (m_mode == DOME_PANORAM_SPH) {
m_locRot[0] = MT_Matrix3x3( // Top
c, s, 0.0f,
0.0f,0.0f, -1.0f,
-s, c, 0.0f);
m_locRot[1] = MT_Matrix3x3( // Bottom
c, s, 0.0f,
0.0f, 0.0f, 1.0f,
s, -c, 0.0f);
m_locRot[2] = MT_Matrix3x3( // 45deg - Left
-s, 0.0f, c,
0, 1.0f, 0.0f,
-c, 0.0f, -s);
m_locRot[3] = MT_Matrix3x3( // 45deg - Right
c, 0.0f, s,
0, 1.0f, 0.0f,
-s, 0.0f, c);
m_locRot[4] = MT_Matrix3x3( // 135deg - LeftBack
-s, 0.0f, -c,
0.0f, 1.0f, 0.0f,
c, 0.0f, -s);
m_locRot[5] = MT_Matrix3x3( // 135deg - RightBack
c, 0.0f, -s,
0.0f, 1.0f, 0.0f,
s, 0.0f, c);
}
// rotating the camera in horizontal axis
if (m_tilt)
{
float tiltdeg = ((m_tilt % 360) * 2 * MT_PI) / 360;
c = cosf(tiltdeg);
s = sinf(tiltdeg);
MT_Matrix3x3 tilt_mat = MT_Matrix3x3(
1.0f, 0.0f, 0.0f,
0.0f, c, -s,
0.0f, 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->NodeGetLocalScaling(), 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, 0.0, 0.0); //stretch the image to reduce resolution lost
else {
if (can_width/3 <= can_height/2) {
ortho_width = 1.0f;
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.0f, 10.0f);
}
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0f,0.0f,1.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f);
glPolygonMode(GL_FRONT, GL_FILL);
glShadeModel(GL_SMOOTH);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glColor3f(1.0f,1.0f,1.0f);
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.0f,uv_ratio);
glVertex3f(-onebythree, 0.0f, 3.0f);
glTexCoord2f(0.0f,0.0f);
glVertex3f(-onebythree,-2 * onebythree, 3.0f);
glTexCoord2f(uv_ratio,0.0f);
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.0f,uv_ratio);
glVertex3f(-1.0f, 0.0f, 3.0f);
glTexCoord2f(0.0f,0.0f);
glVertex3f(-1.0f,-2 * onebythree, 3.0f);
glTexCoord2f(uv_ratio,0.0f);
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.0f,uv_ratio);
glVertex3f(-1.0f, 2 * onebythree, 3.0f);
glTexCoord2f(0.0f,0.0f);
glVertex3f(-1.0f, 0.0f, 3.0f);
glTexCoord2f(uv_ratio,0.0f);
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.0f,uv_ratio);
glVertex3f( onebythree, 2 * onebythree, 3.0f);
glTexCoord2f(0.0f,0.0f);
glVertex3f( onebythree, 0.0f, 3.0f);
glTexCoord2f(uv_ratio,0.0f);
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.0f,uv_ratio);
glVertex3f( onebythree, 0.0f, 3.0f);
glTexCoord2f(0.0f,0.0f);
glVertex3f( onebythree,-2 * onebythree, 3.0f);
glTexCoord2f(uv_ratio,0.0f);
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.0f,uv_ratio);
glVertex3f(-onebythree, 2 * onebythree, 3.0f);
glTexCoord2f(0.0f,0.0f);
glVertex3f(-onebythree, 0.0f, 3.0f);
glTexCoord2f(uv_ratio,0.0f);
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.0f), 1.0f, (-1.0f), 1.0f, -20.0f, 10.0f); //stretch the image to reduce resolution lost
else {
if (can_width < can_height) {
ortho_width = 1.0f;
ortho_height = (float)can_height/can_width;
}
else {
ortho_width = (float)can_width/can_height;
ortho_height = 1.0f;
}
glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_height, -20.0f, 10.0f);
}
}
else if (m_mode == DOME_TRUNCATED_FRONT)
{
ortho_width = 1.0f;
ortho_height = 2.0f * ((float)can_height / can_width) - 1.0f;
glOrtho((-ortho_width), ortho_width, (-ortho_height), ortho_width, -20.0f, 10.0f);
}
else { //m_mode == DOME_TRUNCATED_REAR
ortho_width = 1.0f;
ortho_height = 2.0f * ((float)can_height / can_width) - 1.0f;
glOrtho((-ortho_width), ortho_width, (-ortho_width), ortho_height, -20.0f, 10.0f);
}
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0f,-1.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f);
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.0f,1.0f,1.0f);
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.0f;
float ortho_width = 1.0f;
if (warp.usemesh)
glOrtho((-1.0f), 1.0f, (-0.5f), 0.5f, -20.0f, 10.0f); //stretch the image to reduce resolution lost
else {
//using all the screen
if ((can_width / 2) <= (can_height)) {
ortho_width = 1.0f;
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.0f, 10.0f);
}
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0f,-1.0f,0.0f, 0.0f,0.0f,0.0f, 0.0f,0.0f,1.0f);
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.0f,1.0f,1.0f);
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.0f,1.0f,-20.0f,10.0f);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0f, 0.0f, 1.0f, 0.0f,0.0f,0.0f, 0.0f,1.0f,0.0f);
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.0f,1.0f,1.0f);
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(), cam->NodeGetLocalScaling(), 1.0f);
cam->SetModelviewMatrix(viewmat);
// restore the original orientation
cam->NodeSetLocalOrientation(camori);
cam->NodeUpdateGS(0.f);
scene->CalculateVisibleMeshes(m_rasterizer,cam);
m_engine->UpdateAnimations(scene);
scene->RenderBuckets(camtrans, m_rasterizer);
}