/** Macromedia Flash OpenGl renderer implementation. Copyright (C) 2005 Christophe Choquet (cchoquet@users.sourceforge.net) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA **/ #include "ogl_renderer.hh" #define VALGRIND false // In case we have very old OpenGL headers #if 0 // blfXXXXX: #ifndef GL_FRAGMENT_PROGRAM_ARB #define GL_FRAGMENT_PROGRAM_ARB 0x8804 GLAPI void APIENTRY glGenProgramsARB (GLsizei, GLuint *) {} GLAPI void APIENTRY glBindProgramARB (GLenum, GLuint) { } GLAPI void APIENTRY glProgramStringARB (GLenum, GLenum, GLsizei, const GLvoid *) {} GLAPI void APIENTRY glProgramLocalParameter4fvARB (GLenum, GLuint, const GLfloat *) {} #endif #endif /** * The constructor **/ OglRenderer::OglRenderer(BaseTexture *texture) : BaseRenderer(texture) { hasVertexArrayCompile= false; lastTextureId = 0; lastPixelShader = 0; detectCapababilities(); texture->sethasFullTextureOnBoard(hasGL_ARB_fragment_shader); pixelShadersLoaded = false; } /** * The destructor **/ OglRenderer::~OglRenderer() { } /** * Clear current window **/ void OglRenderer::clearWindow(){ if (VALGRIND) return; glClearColor(float(backGroundColor.red)/255.0,float(backGroundColor.green)/255.0,float(backGroundColor.blue)/255.0,0); glDisable(GL_STENCIL_TEST); glClearStencil(0); glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); //blfXXXX: if (!pixelShadersLoaded) loadPixelShaders(); lastTextureId = 0; lastPixelShader = 0; } /** * Flush the display **/ void OglRenderer::flush() { if (VALGRIND) return; glFlush(); } /** * Render a DrawingSequence (eg Character) **/ void OglRenderer::renderCharacter(ListDrawingSequence *dr,int clipDepth) { if (VALGRIND) return; if (dr == NULL) return; this->clipDepth = clipDepth; for (ListDrawingSequence::iterator it=dr->begin();it != dr->end(); it++) { DrawingSequence *d = (*it); if (d->getMatrix() != NULL) applyMatrix(d->getMatrix()); doRenderCharacterNoCompile(d,true); } } /** * Display a shape fragment **/ void OglRenderer::doRenderCharacterNoCompile(DrawingSequence *d, bool isSecondPass){ glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(2,GL_FLOAT,0,d->getVertices()); for (list::iterator it= d->getDrawingEntries()->begin(); it != d->getDrawingEntries()->end(); it++) { DrawingEntry *de = *it; glEnableClientState(GL_INDEX_ARRAY); glIndexPointer(GL_INT,0,de->getIndexes()); setupTexture(d,de); if (clipDepth != 0) { #if 0 // blfXXXXX: if (hasGL_ARB_fragment_shader) { glDisable( GL_FRAGMENT_PROGRAM_ARB); lastPixelShader= 0;} #endif glDisable(GL_TEXTURE_1D); glDisable(GL_TEXTURE_2D); lastTextureId = 0; glDisableClientState(GL_TEXTURE_COORD_ARRAY); glEnable(GL_STENCIL_TEST); glColorMask(0,0,0,0); glStencilFunc(GL_ALWAYS, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); } switch (de->drawingType) { case DrawingTriangles: { glDrawElements(GL_TRIANGLES,3*de->nbElements,GL_UNSIGNED_INT,de->getIndexes()); break; } case DrawingLines: { glLineWidth(de->lineWidth*lineRatio); glEnable(GL_LINE_SMOOTH); glDrawElements(GL_LINES,2*de->nbElements,GL_UNSIGNED_INT,de->getIndexes()); glPointSize(de->lineWidth*0.7*lineRatio); glDrawElements(GL_POINTS,2*de->nbElements,GL_UNSIGNED_INT,de->getIndexes()); glDisable(GL_LINE_SMOOTH); glDisable(GL_POINT_SMOOTH); break; } case DrawingFontChars: { RGBA c = de->charColor; float red,green,blue,alpha; #if 0 // blfXXXXX: if (hasGL_ARB_fragment_shader) { glDisable( GL_FRAGMENT_PROGRAM_ARB); lastPixelShader= 0; } #endif if (hasCxAlpha) { red = float(c.red) * cxAlpha[0] + secondPassColor[0]; green = float(c.green) * cxAlpha[1] + secondPassColor[1]; blue = float(c.blue) * cxAlpha[2] + secondPassColor[2]; alpha = float (c.alpha)* cxAlpha[3] + secondPassColor[3]; } else { red = float(c.red) / 256.0; green = float(c.green) / 256.0; blue = float(c.blue) / 256.0; alpha = float (c.alpha)/ 256.0; } glColor4f(red,green,blue,alpha); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glDrawElements(GL_TRIANGLES,6*de->nbElements,GL_UNSIGNED_INT,de->getIndexes()); lastTextureId = 0; break; } } glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_INDEX_ARRAY); } glDisableClientState(GL_VERTEX_ARRAY); if (clipDepth != 0) { glColorMask(1,1,1,1); glStencilFunc(GL_EQUAL, 1, 1); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); } glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); } /** * Setup texture rendering * The doc is not completly true..... * The add color is the sum of: * - the constant R,G,B * - the alpha multiplied component of original color **/ void OglRenderer::setupTexture(DrawingSequence *d, DrawingEntry *de) { // Alloc secondary texture if needeed and don't change the pointers if (hasCxAlpha && !hasGL_ARB_fragment_shader) { if (newTexCoords != NULL) free(newTexCoords); int texDim = 2; if (de->fillType == 0x10 || de->fillType == 0x12) texDim = 1; newTexCoords = (float*) malloc(texDim*d->getNbPoints()*sizeof(GLfloat)); updateTextureNoShader(d,de, de->fillType > 0, texDim); } switch (de->fillType) { case 0x00: { if (hasGL_ARB_fragment_shader) { // Opengl 1.3 support #if 0 // blfXXXXX: if (lastPixelShader != 2) { glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, vp2D); glEnable( GL_FRAGMENT_PROGRAM_ARB); lastPixelShader = 2; } #endif if (lastTextureId != de->texNum) { glActiveTextureARB( GL_TEXTURE0_ARB ); glClientActiveTextureARB( GL_TEXTURE0_ARB ); glDisable(GL_TEXTURE_1D); glBindTexture(GL_TEXTURE_2D, de->texNum); glEnable(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); lastTextureId = de->texNum; } glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(2,GL_FLOAT,0,de->getTexCoords()); #if 0 // blfXXXXX: glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, cxAlpha ); glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 1, secondPassColor ); #endif } else { // No Vertex Shader glDisable(GL_TEXTURE_1D); glBindTexture(GL_TEXTURE_2D, de->texNum); glEnable(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); lastTextureId = de->texNum; glEnableClientState(GL_TEXTURE_COORD_ARRAY); hasCxAlpha ? glTexCoordPointer(2,GL_FLOAT,0,newTexCoords) : glTexCoordPointer(2,GL_FLOAT,0,de->getTexCoords()); glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE); } break; } case 0x10: case 0x12: { if (hasGL_ARB_fragment_shader) { #if 0 // blfXXXXX: if (lastPixelShader != 1) { glEnable( GL_FRAGMENT_PROGRAM_ARB); glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, vp1D); lastPixelShader = 1; } #endif if (lastTextureId != de->texNum) { glActiveTextureARB( GL_TEXTURE0_ARB ); glClientActiveTextureARB( GL_TEXTURE0_ARB ); glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_1D, de->texNum); glEnable(GL_TEXTURE_1D); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); lastTextureId = de->texNum; } glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(1,GL_FLOAT,0,de->getTexCoords()); #if 0 // blfXXXXX: glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, cxAlpha ); glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 1, secondPassColor ); #endif } else { if (hasCxAlpha) { glDisable(GL_TEXTURE_1D); glBindTexture(GL_TEXTURE_2D, 1); glEnable(GL_TEXTURE_2D); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); lastTextureId = 1; glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(1,GL_FLOAT,0,newTexCoords); } else { glDisable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_1D, de->texNum); glEnable(GL_TEXTURE_1D); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); lastTextureId = de->texNum; glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(1,GL_FLOAT,0,de->getTexCoords()); } glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE); } break; } case 0x40: // bitmap case 0x41: // clipped bitmap fill case 0x42: // non smoothed repeting bitmap case 0x43: { // non smoothed clipped bitmap if (hasGL_ARB_fragment_shader) { #if 0 // blfXXXXX: if (lastPixelShader != 2) { glEnable( GL_FRAGMENT_PROGRAM_ARB); glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, vp2D); lastPixelShader = 2; } #endif glActiveTextureARB( GL_TEXTURE0_ARB ); glClientActiveTextureARB( GL_TEXTURE0_ARB ); glDisable(GL_TEXTURE_1D); glBindTexture(GL_TEXTURE_2D, de->texNum); lastTextureId = 0; glEnable(GL_TEXTURE_2D); glEnableClientState(GL_TEXTURE_COORD_ARRAY); if (de->fillType == 0x40 || de->fillType == 0x42) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); } if (de->fillType == 0x40 || de->fillType == 0x41) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } glTexCoordPointer(2,GL_FLOAT,0,de->getTexCoords()); #if 0 // blfXXXXX: glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 0, cxAlpha ); glProgramLocalParameter4fvARB(GL_FRAGMENT_PROGRAM_ARB, 1, secondPassColor ); #endif } else { glDisable(GL_TEXTURE_1D); glBindTexture(GL_TEXTURE_2D, de->texNum); glEnable(GL_TEXTURE_2D); glEnableClientState(GL_TEXTURE_COORD_ARRAY); if (de->fillType == 0x40 || de->fillType == 0x42) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); } if (de->fillType == 0x40 || de->fillType == 0x41) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } lastTextureId = de->texNum; //glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_MODULATE); //glTexCoordPointer(2,GL_FLOAT,0,de->getTexCoords()); glEnableClientState(GL_TEXTURE_COORD_ARRAY); hasCxAlpha ? glTexCoordPointer(2,GL_FLOAT,0,newTexCoords) : glTexCoordPointer(2,GL_FLOAT,0,de->getTexCoords()); glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE); } break; } } //glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); //------- TEST } /** * Apply a transformation matrix. * A transformation matrix is given by: * x' = x * ScaleX + y * RotateSkew1 + TranslateX * y' = x * RotateSkew0 + y * ScaleY + TranslateY * * We create here a transform matrix, and multiply it on the stack **/ void OglRenderer::applyMatrix(MATRIX *m){ if (VALGRIND) return; GLfloat mat[16]; applyMatrixMaths(mat,m); glMultMatrixf(mat); } /** * Start rendering something: reset the model view tfx matrix **/ void OglRenderer::initCharacter() { if (VALGRIND) return; glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glColor4f(1,1,1,1); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); hasCxAlpha = false; cxAlpha[0]=cxAlpha[1]=cxAlpha[2]=cxAlpha[3]=1.0/256.0; secondPassColor[0]=secondPassColor[1]=secondPassColor[2]=secondPassColor[3]=0.0; lineRatio = 1; } /** * Detect OpenGL extensions support **/ void OglRenderer::detectCapababilities() { glGetIntegerv(GL_STENCIL_BITS,&stencilDepth); printf("HARDWARE: Stencil depth :%d\n",stencilDepth); char *ext = (char*)glGetString(GL_EXTENSIONS); if (checkExtension(ext,"GL_ARB_multisample")) { hasGL_ARB_multisample = true; glEnable(GL_MULTISAMPLE_ARB); puts("HARDWARE: GL_ARB_multisample -> ok"); } else { hasGL_ARB_multisample = false; } if (checkExtension(ext,"GL_ARB_fragment_shader")) { hasGL_ARB_fragment_shader= true; puts("HARDWARE: GL_ARB_fragment_shader -> ok"); } else { hasGL_ARB_fragment_shader = false; puts("HARDWARE: NO GL_ARB_fragment_shader -> Emulate pixel shader"); } } /** * Unload / reload pixel shaders * With Radeon hardware, they can't be shared by multiple context * **/ void OglRenderer::loadPixelShaders() { #if 0 // blfXXXX: glGenProgramsARB( 1, &vp2D); glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, vp2D); string program = buildPixelShaderProgram("2"); glProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, program.size(), program.c_str()); if (glGetError() != 0) { int lineno; //printf("%s\n", glGetString(GL_PROGRAM_ERROR_STRING_ARB)); glGetIntegerv( GL_PROGRAM_ERROR_POSITION_ARB, &lineno); //printf(" @%d\n", lineno); } glGenProgramsARB( 1, &vp1D); glBindProgramARB( GL_FRAGMENT_PROGRAM_ARB, vp1D); program = buildPixelShaderProgram("1"); glProgramStringARB( GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, program.size(), program.c_str()); pixelShadersLoaded = true; #endif } /** * Check OpenGL supported extension **/ bool OglRenderer::checkExtension(char *p,char *extName ) { char *end; int extNameLen; extNameLen = strlen(extName); end = p + strlen(p); while (p < end) { int n = strcspn(p, " "); if ((extNameLen == n) && (strncmp(extName, p, n) == 0)) { return true; } p += (n + 1); } return false; } /** * Display current caret **/ bool OglRenderer::displayCaret(Caret c) { //TODO: FIX COLOR PROBLEM glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glLineWidth(2); glColor4f(1.0,0.0,1.0,1.0); glDisable(GL_BLEND); glBegin(GL_LINES); glVertex2f(c.x,c.y+40); glVertex2f(c.x,c.y+c.height+40); glEnd(); return true; } /** * Define the Color transform pixel shader * explanation: * We get the texture color of TEXTURE0. * Then we multiply it by the CxColor Mult coef, and then add the CxColor Add member. **/ string OglRenderer::buildPixelShaderProgram(char *dim) { string res = "!!ARBfp1.0\n"; res += "TEMP color;\n"; res += "TEX color, fragment.texcoord[0], texture[0], "+string(dim)+"D;\n"; res += "MAD result.color,color,program.local[0],program.local[1];\n"; res += "END"; return res; }