//----------------------------------------------------------------------------- // Copyright (c) 2013 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- // // AndroidGL2ES.mm // TGE // // Created by Puap Puap on 7/31/08. // Copyright 2008 Pick Up And Play. All rights reserved. // #include "AndroidGL2ES.h" #include "platform/platformAssert.h" #include "AndroidOGLVideo.h" #include "math/mMatrix.h" #include "math/mPoint.h" #define INV_255 0.0039215686f #define INV_32767 3.0518509476e-5f /* EAGL and GL functions calling wrappers that log on error */ #define CALL_EAGL_FUNCTION(__FUNC__, ...) ({ EAGLError __error = __FUNC__( __VA_ARGS__ ); if(__error != kEAGLErrorSuccess) Con::printf("%s() called from %s returned error %i\n", #__FUNC__, __FUNCTION__, __error); (__error ? 0 : 1); }) #define CHECK_GL_ERROR() ({ int __error = glGetError(); if(__error) Con::printf("OpenGL error 0x%04X in %s\n", __error, __FUNCTION__); (__error ? 0 : 1); }) // define this to print out glErrors, un-define to get rid of it #define TEST_FOR_OPENGL_ERRORS CHECK_GL_ERROR(); ///////////////////////////////////////////////////////////////////////////// // // Wrapper around the matrix stack ops, to see if ever have over/underflow // extern "C" { static GLenum currentMatrixMode = GL_MODELVIEW; static int currentProjStackDepth = 0; static GLfloat projStack[256]; static int currentTexStackDepth = 0; static GLfloat texStack[256]; static int currentModelStackDepth = 0; static GLfloat modStack[256]; #undef glPushMatrix // temporarily void AndroidGLPushMatrix() { GLint depth; switch (currentMatrixMode) { case GL_MODELVIEW: if (currentModelStackDepth > 15) { AssertFatal( 0, "ModelView Stack overflow" ); } else { glGetFloatv( GL_MODELVIEW_MATRIX, &modStack[currentModelStackDepth*16] ); currentModelStackDepth++; glGetIntegerv( GL_MODELVIEW_STACK_DEPTH, &depth ); // AssertWarn( (currentModelStackDepth > depth), "Native ModelView stack depth has been exceeded" ); } break; case GL_PROJECTION: if (currentProjStackDepth > 15) { AssertFatal( 0, "Projection Stack overflow" ); } else { glGetFloatv( GL_PROJECTION_MATRIX, &projStack[currentProjStackDepth*16] ); currentProjStackDepth++; glGetIntegerv( GL_PROJECTION_STACK_DEPTH, &depth ); // AssertWarn( (currentProjStackDepth > depth), "Native Projection stack depth has been exceeded" ); } break; case GL_TEXTURE: if (currentTexStackDepth > 15) { AssertFatal( 0, "Texture Stack overflow" ); } else { glGetFloatv( GL_TEXTURE_MATRIX, &texStack[currentTexStackDepth*16] ); currentTexStackDepth++; glGetIntegerv( GL_TEXTURE_STACK_DEPTH, &depth ); // AssertWarn( (currentTexStackDepth > depth), "Native Texture stack depth has been exceeded" ); } break; default: glPushMatrix(); GLenum err; err = glGetError(); AssertFatal( !(err == GL_STACK_OVERFLOW), "GL Stack overflow" ); break; } } #define glPushMatrix AndroidGLPushMatrix #undef glPopMatrix // temporarily void AndroidGLPopMatrix() { switch (currentMatrixMode) { case GL_MODELVIEW: if (currentModelStackDepth <= 0) { AssertFatal( 0, "ModelView Stack underflow" ); } else { currentModelStackDepth--; glLoadMatrixf( &modStack[currentModelStackDepth*16] ); } break; case GL_PROJECTION: if (currentProjStackDepth <= 0) { AssertFatal( 0, "Projection Stack underflow" ); } else { currentProjStackDepth--; glLoadMatrixf( &projStack[currentProjStackDepth*16] ); } break; case GL_TEXTURE: if (currentTexStackDepth <= 0) { AssertFatal( 0, "Texture Stack underflow" ); } else { currentTexStackDepth--; glLoadMatrixf( &texStack[currentTexStackDepth*16] ); } break; default: glPopMatrix(); GLenum err; err = glGetError(); AssertFatal( !(err == GL_STACK_UNDERFLOW), "GL Stack underflow" ); break; } } #define glPopMatrix AndroidGLPopMatrix #undef glMatrixMode // temporarily void AndroidGLMatrixMode( GLenum mode ) { currentMatrixMode = mode; glMatrixMode( mode ); } #define glMatrixMode AndroidGLMatrixMode // redefine for everyone else } ///////////////////////////////////////////////////////////////////////////// // // The following API functions are wrappers to add opengl functionality to opengl-es // static GLint beginEndMode = -1; // tex coord array static GLfloat * beginEndTexCoord2f = NULL; // 2 entries per coord static int beginEndTexCoord2f_alloc = 0; // number of bytes allocated to the array static int beginEndTexCoord2f_size = 0; // number of coords in the array // vertex array static GLfloat * beginEndVertex = NULL; // 4 entries per vertex static int beginEndVertex_alloc = 0; // number of bytes allocated to the array static int beginEndVertex_size = 0; // number of vertexes in the array // color array -- needed if glColor is called inside begin/end static GLfloat * beginEndColor = NULL; // 4 entries per color static int beginEndColor_size = 0; // number of colors in the array // normal array static GLfloat * beginEndNormal = NULL; // 3 entries per normal static int beginEndNormal_alloc = 0; // number of bytes allocated to the array static int beginEndNormal_size = 0; // number of normals in the array // macros to handle re-sizing the arrays as needed #define CHECK_ARRAY_SIZE( ppArray, pAlloc, pSize, nType, nGroup ) \ if (*ppArray == NULL) { \ *pAlloc = 32 * sizeof(nType) * nGroup; \ *ppArray = (nType*)dMalloc( 32 * sizeof(nType) * nGroup ); \ } \ if (*pSize >= *pAlloc / (nGroup * sizeof(nType))) { \ *ppArray = (nType*)dRealloc( *ppArray, 2 * (*pAlloc) ); \ *pAlloc *= 2; \ } void glBegin( GLint mode ) { if (beginEndMode >= 0) { AssertFatal(0, "glBegin(): called without a glEnd"); } beginEndMode = mode; beginEndTexCoord2f_size = 0; beginEndVertex_size = 0; beginEndColor_size = 0; beginEndNormal_size = 0; int glError; glError = TEST_FOR_OPENGL_ERRORS } void glEnd() { if (beginEndMode < 0) { AssertFatal(0, "glEnd(): called without a glBegin"); } if (beginEndVertex_size > 0) { glEnableClientState( GL_VERTEX_ARRAY ); glVertexPointer( 4, GL_FLOAT, 4*sizeof(GL_FLOAT), beginEndVertex ); } if (beginEndNormal_size > 0) { glEnableClientState( GL_NORMAL_ARRAY ); glNormalPointer( GL_FLOAT, 3*sizeof(GL_FLOAT), beginEndNormal ); } if (beginEndColor_size > 0) { glEnableClientState( GL_COLOR_ARRAY ); glColorPointer( 4, GL_FLOAT, 4*sizeof(GL_FLOAT), beginEndColor ); } if (beginEndTexCoord2f_size > 0) { glEnableClientState( GL_TEXTURE_COORD_ARRAY ); glTexCoordPointer( 2, GL_FLOAT, 2*sizeof(GL_FLOAT), beginEndTexCoord2f ); } switch (beginEndMode) { case GL_POINTS: glDrawArrays( GL_POINTS, 0, beginEndVertex_size ); break; case GL_LINES: glDrawArrays( GL_LINES, 0, beginEndVertex_size ); break; case GL_LINE_STRIP: glDrawArrays( GL_LINE_STRIP, 0, beginEndVertex_size ); break; case GL_LINE_LOOP: glDrawArrays( GL_LINE_LOOP, 0, beginEndVertex_size ); break; case GL_TRIANGLES: glDrawArrays( GL_TRIANGLES, 0, beginEndVertex_size ); break; case GL_TRIANGLE_STRIP: glDrawArrays( GL_TRIANGLE_STRIP, 0, beginEndVertex_size ); break; case GL_TRIANGLE_FAN: glDrawArrays( GL_TRIANGLE_FAN, 0, beginEndVertex_size ); break; case GL_QUADS: #if 1 // %%PUAP%% TESTING // for now, just draw a couple lines to indicate the edges of the quads glDrawArrays( GL_LINES, 0, beginEndVertex_size ); #else // draw these as individual pairs of triangle_strips glDrawArrays( GL_TRIANGLE_STRIP, 0, beginEndVertex_size ); #endif break; case GL_QUAD_STRIP: #if 1 // %%PUAP%% TESTING glDrawArrays( GL_LINES, 0, beginEndVertex_size ); #endif break; case GL_POLYGON: // see if it is really just a triangle... if (beginEndVertex_size == 3) { glDrawArrays( GL_TRIANGLES, 0, 3 ); } else // see if it is really just a quad... if (beginEndVertex_size == 4) { glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 ); } else AssertFatal( 0, "glBegin(GL_POLYGON): this method call needs to be implemented"); break; } if (beginEndVertex_size > 0) { glDisableClientState( GL_VERTEX_ARRAY ); } if (beginEndNormal_size > 0) { glDisableClientState( GL_NORMAL_ARRAY ); } if (beginEndColor_size > 0) { glDisableClientState( GL_COLOR_ARRAY ); } if (beginEndTexCoord2f_size > 0) { glDisableClientState( GL_TEXTURE_COORD_ARRAY ); } beginEndMode = -1; int glError; glError = TEST_FOR_OPENGL_ERRORS } void glTexCoord2f( GLfloat x, GLfloat y) { AssertFatal( (beginEndMode >= 0), "glTexCoord2f(): called outside glBegin/glEnd"); CHECK_ARRAY_SIZE( &beginEndTexCoord2f, &beginEndTexCoord2f_alloc, &beginEndTexCoord2f_size, GLfloat, 2 ); beginEndTexCoord2f[ beginEndTexCoord2f_size*2 ] = x; beginEndTexCoord2f[ beginEndTexCoord2f_size*2+1 ] = y; beginEndTexCoord2f_size++; int glError; glError = TEST_FOR_OPENGL_ERRORS } void glVertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w) { AssertFatal( (beginEndMode >= 0), "glVertex3f(): called outside glBegin/glEnd"); CHECK_ARRAY_SIZE( &beginEndVertex, &beginEndVertex_alloc, &beginEndVertex_size, GLfloat, 4 ); beginEndVertex[ beginEndVertex_size*4 ] = x; beginEndVertex[ beginEndVertex_size*4+1 ] = y; beginEndVertex[ beginEndVertex_size*4+2 ] = z; beginEndVertex[ beginEndVertex_size*4+3 ] = w; beginEndVertex_size++; int glError; glError = TEST_FOR_OPENGL_ERRORS } void glVertex2f( GLfloat x, GLfloat y ) { AssertFatal( (beginEndMode >= 0), "glVertex2f(): called outside glBegin/glEnd"); glVertex4f( x, y, 0.0f, 1.0f ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glVertex3f( GLfloat x, GLfloat y, GLfloat z ) { AssertFatal( (beginEndMode >= 0), "glVertex3f(): called outside glBegin/glEnd"); glVertex4f( x, y, z, 1.0f ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glVertex2fv( const F32 * pv ) { AssertFatal( (beginEndMode >= 0), "glVertex2fv(): called outside glBegin/glEnd"); glVertex4f( pv[0], pv[1], 0.0f, 1.0f ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glVertex2i( GLint x, GLint y) { AssertFatal( (beginEndMode >= 0), "glVertex2i(): called outside glBegin/glEnd"); glVertex4f( GLfloat(x), GLfloat(y), 0.0f, 1.0f ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glVertex3fv( const F32 * pv ) { AssertFatal( (beginEndMode >= 0), "glVertex3fv(): called outside glBegin/glEnd"); glVertex4f( pv[0], pv[1], pv[2], 1.0f ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glVertex4fv( const F32 * pv ) { AssertFatal( (beginEndMode >= 0), "glVertex3fv(): called outside glBegin/glEnd"); glVertex4f( pv[0], pv[1], pv[2], pv[3] ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glNormal3f( GLfloat x, GLfloat y, GLfloat z, GLfloat w) { AssertFatal( (beginEndMode >= 0), "glNormal3f(): called outside glBegin/glEnd"); CHECK_ARRAY_SIZE( &beginEndNormal, &beginEndNormal_alloc, &beginEndNormal_size, GLfloat, 3 ); beginEndNormal[ beginEndNormal_size*3 ] = x; beginEndNormal[ beginEndNormal_size*3+1 ] = y; beginEndNormal[ beginEndNormal_size*3+2 ] = z; beginEndNormal_size++; int glError; glError = TEST_FOR_OPENGL_ERRORS } void glNormal3fv( const F32 * pv) { AssertFatal( (beginEndMode >= 0), "glNormal3fv(): called outside glBegin/glEnd"); glNormal3f( pv[0], pv[1], pv[2] ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glColor3fv( const F32 * pv) { glColor4f( pv[0], pv[1], pv[2], 1.0f ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glColor4fv( const F32 * pv) { glColor4f( pv[0], pv[1], pv[2], pv[3] ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glActiveTextureARB( GLint index ) { glActiveTexture( index ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glMultiTexCoord2fARB( GLint, GLfloat, GLfloat) { AssertWarn( 0, "glMultiTexCoord2fARB(): this method call needs to be implemented"); } void glPushAttrib( GLint ) { AssertWarn( 0, "glPushAttrib(): this method call needs to be implemented"); } void glPopAttrib() { AssertWarn( 0, "glPopAttrib(): this method call needs to be implemented"); } //void glOrtho( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar) //{ // GLfloat tx = -(right+left)/(right-left); // GLfloat ty = -(top+bottom)/(top-bottom); // GLfloat tz = -(zFar+zNear)/(zFar-zNear); // MatrixF m = MatrixF(true); // ((F32*)m)[0] = 2.0f/(right-left); // ((F32*)m)[3] = tx; // ((F32*)m)[5] = 2.0f/(top-bottom); // ((F32*)m)[7] = ty; // ((F32*)m)[10] = -2.0f/(zFar-zNear); // ((F32*)m)[11] = tz; // // glMultMatrixf( (F32*)(m.transpose())); // make col major for opengl //} //void glFrustum( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar ) //{ // MatrixF m = MatrixF(true); // ((F32*)m)[0] = 2.0f*zNear/(right-left); // ((F32*)m)[2] = (right+left)/(right-left); // ((F32*)m)[5] = 2.0f*zNear/(top-bottom); // ((F32*)m)[6] = (top+bottom)/(top-bottom); // ((F32*)m)[10] = -(zFar+zNear)/(zFar-zNear); // ((F32*)m)[11] = -2.0f*zFar*zNear/(zFar-zNear); // ((F32*)m)[14] = -1.0f; // ((F32*)m)[15] = 0.0f; // // glMultMatrixf( (F32*)(m.transpose())); // make col major for opengl //} void glReadBuffer( GLint ) { AssertWarn( 0, "glReadBuffer(): this method call needs to be implemented"); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glClientActiveTextureARB( GLint texture ) { glClientActiveTexture( texture ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glColor3i( GLint r, GLint g, GLint b ) { glColor4f( ((GLfloat)r) * INV_32767, ((GLfloat)g) * INV_32767, ((GLfloat)b) * INV_32767, 1.0f ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glColor3ubv( const GLubyte *v ) { glColor4f( ((GLfloat)v[0]) * INV_255, ((GLfloat)v[1]) * INV_255, ((GLfloat)v[2]) * INV_255, 1.0f ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glColor4ubv( const GLubyte *v ) { glColor4f( ((GLfloat)v[0]) * INV_255, ((GLfloat)v[1]) * INV_255, ((GLfloat)v[2]) * INV_255, ((GLfloat)v[3]) * INV_255 ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glRecti( GLint x1, GLint y1, GLint x2, GLint y2 ) { AssertFatal( beginEndMode<0, "glRecti(): called inside glBegin/glEnd"); glBegin(GL_LINE_LOOP); glVertex2i(x1, y1); glVertex2i(x2, y1); glVertex2i(x2, y2); glVertex2i(x1, y2); glEnd(); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glGetDoublev( GLint pname, GLdouble * params ) { int i; GLfloat fparams[16]; glGetFloatv( pname, fparams ); AssertFatal((glGetError() == GL_NO_ERROR), "glGetDoublev parameter invalid"); params[0] = (double)fparams[0]; if ((pname == GL_ALIASED_POINT_SIZE_RANGE) || (pname == GL_ALIASED_LINE_WIDTH_RANGE) || (pname == GL_DEPTH_RANGE) || (pname == GL_MAX_VIEWPORT_DIMS) || (pname == GL_SMOOTH_LINE_WIDTH_RANGE) || (pname == GL_SMOOTH_POINT_SIZE_RANGE)) { // 2 items params[1] = (double)fparams[1]; return; } if ((pname == GL_COLOR_CLEAR_VALUE) || (pname == GL_COLOR_WRITEMASK) || (pname == GL_FOG_COLOR) || (pname == GL_LIGHT_MODEL_AMBIENT) || (pname == GL_SCISSOR_BOX) || (pname == GL_VIEWPORT) ) { // 4 items params[1] = (double)fparams[1]; params[2] = (double)fparams[2]; params[3] = (double)fparams[3]; return; } if ((pname == GL_PROJECTION_MATRIX) || //Luma: Added MODDELVIEW support (pname == GL_MODELVIEW_MATRIX) || //(pname == GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS) || //(pname == GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS) || (pname == GL_TEXTURE_MATRIX) ) { // 16 items for (i=1; i<16; i++) { params[i] = (double)fparams[i]; } return; } } void glPolygonMode( GLint, GLint ) { //AssertFatal( 0, "glPolygonMode(): this method call needs to be implemented"); } void glLockArraysEXT( GLint, GLint ) { AssertFatal( 0, "glLockArraysEXT(): this method call needs to be implemented"); } void glUnlockArraysEXT() { AssertFatal( 0, "glUnlockArraysEXT(): this method call needs to be implemented"); } void glColor3ub( GLint r, GLint g, GLint b ) { glColor4f( ((GLfloat)r) * INV_255, ((GLfloat)g) * INV_255, ((GLfloat)b) * INV_255, 1.0f ); int glError; glError = TEST_FOR_OPENGL_ERRORS } void glFogi( GLint pname, GLint param ) { glFogf( pname, (GLfloat)param ); int glError; glError = TEST_FOR_OPENGL_ERRORS } /* -Mat note: only guiCanvas uses this, and before adding this GL2ES stuff we didn't need to use it (it was one of the first things if'ed out) void glDrawBuffer( GLint buffid ) { ((EAGLView *)platState.ctx).currentRenderBuffer = buffid; TEST_FOR_OPENGL_ERRORS } */ void glColorTableEXT( GLint, GLint, GLint, GLint, GLint, const ColorI * ) { AssertFatal( 0, "glColorTableEXT(): this method call needs to be implemented"); } void glBlendColorEXT( GLfloat, GLfloat, GLfloat, GLfloat ) { AssertFatal( 0, "glBlendColorEXT(): this method call needs to be implemented"); } void glBlendEquationEXT( GLint ) { AssertFatal( 0, "glBlendEquationEXT(): this method call needs to be implemented"); } void glArrayElement( GLint ) { AssertFatal( 0, "glArrayElement(): this method call needs to be implemented"); } void glFogCoordPointerEXT(GLenum, GLsizei, void *) { AssertFatal( 0, "glFogCoordPointerEXT(): this method call needs to be implemented"); } //void glDepthRange( GLfloat, GLfloat ) //{ // AssertFatal( 0, "glDepthRange(): this method call needs to be implemented"); //} void glTexGeni( GLenum coord, GLenum pname, GLint param ) { AssertFatal( 0, "glTexGeni(): this method call needs to be implemented"); } void glTexGenfv( GLenum coord, GLenum pname, const GLfloat *params ) { AssertFatal( 0, "glTexGenfv(): this method call needs to be implemented"); } void glClipPlane( GLuint plane, GLdouble * equation ) { GLfloat fequ[4]; fequ[0] = (GLfloat)equation[0]; fequ[1] = (GLfloat)equation[1]; fequ[2] = (GLfloat)equation[2]; fequ[3] = (GLfloat)equation[3]; glClipPlanef( plane, fequ ); int glError; glError = TEST_FOR_OPENGL_ERRORS } GLboolean glAreTexturesResident( GLsizei, const GLuint *, GLboolean*) { int glError; glError = TEST_FOR_OPENGL_ERRORS return GL_FALSE; } void gluOrtho2D( GLfloat left, GLfloat right, GLfloat bottom, GLfloat top ) { glOrtho( left, right, bottom, top, -1.0f, 1.0f ); int glError; glError = TEST_FOR_OPENGL_ERRORS // GLfloat zNear = -1.0f; // GLfloat zFar = 1.0f; // GLfloat tx = -(right+left)/(right-left); // GLfloat ty = -(top+bottom)/(top-bottom); // GLfloat tz = -(zFar+zNear)/(zFar-zNear); // MatrixF m = MatrixF(true); // ((F32*)m)[0] = 2.0f/(right-left); // ((F32*)m)[3] = tx; // ((F32*)m)[5] = 2.0f/(top-bottom); // ((F32*)m)[7] = ty; // ((F32*)m)[10] = -2.0f/(zFar-zNear); // ((F32*)m)[11] = tz; // // glMultMatrixf( (F32*)(m.transpose())); // make col major for opengl } GLint gluProject( GLdouble objx, GLdouble objy, GLdouble objz, const F64 *model, const F64 * proj, const GLint * vp, F64 * winx, F64 * winy, F64 * winz ) { Vector4F v = Vector4F( objx, objy, objz, 1.0f ); MatrixF pmat = MatrixF( false ); for (int i=0; i<16; i++) { ((F32*)pmat)[i] = (float)proj[i]; } MatrixF mmat = MatrixF( false ); for (int i=0; i<16; i++) { ((F32*)mmat)[i] = (float)model[i]; } //Luma: Projection fix mmat.transpose(); pmat.transpose(); (pmat.mul(mmat)).mul(v); //Luma: Projection fix if(v.w == 0.0f) { return GL_FALSE; } F32 invW = 1.0f / v.w; v.x *= invW; v.y *= invW; v.z *= invW; *winx = (GLfloat)vp[0] + (GLfloat)vp[2] * (v.x + 1.0f) * 0.5f; *winy = (GLfloat)vp[1] + (GLfloat)vp[3] * (v.y + 1.0f) * 0.5f; *winz = (v.z + 1.0f) * 0.5f; int glError; glError = TEST_FOR_OPENGL_ERRORS return GL_TRUE; } GLint gluUnProject( GLdouble winx, GLdouble winy, GLdouble winz, const F64 *model, const F64 * proj, const GLint * vp, F64 * x, F64 * y, F64 * z ) { Vector4F v = Vector4F( 2.0f*(winx-vp[0])/vp[2] - 1.0f, 2.0f*(winy-vp[1])/vp[2] - 1.0f, 2.0f*vp[2] - 1.0f, 1.0f ); MatrixF pmat = MatrixF( false ); for (int i=0; i<16; i++) { ((F32*)pmat)[i] = (float)proj[i]; } MatrixF mmat = MatrixF( false ); for (int i=0; i<16; i++) { ((F32*)mmat)[i] = (float)model[i]; } mmat = pmat.mul(mmat); mmat = mmat.inverse(); mmat.mul( v ); *x = v.x; *y = v.y; *z = v.z; int glError; glError = TEST_FOR_OPENGL_ERRORS return GL_TRUE; }