X-Git-Url: https://ecere.com/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ecere%2Fsrc%2Fgfx%2Fdrivers%2FOpenGLDisplayDriver.ec;h=289d9817f3f0510d0dba905199251f5dc22b47dd;hb=8d4a267a681da78408bf758106ca32be3a021dd7;hp=febc30358355008f793494eeddf9f0066528a9d0;hpb=8e045ef05f51fb0893bbabf3dd312dd14c3b8adc;p=sdk diff --git a/ecere/src/gfx/drivers/OpenGLDisplayDriver.ec b/ecere/src/gfx/drivers/OpenGLDisplayDriver.ec index febc303..289d981 100644 --- a/ecere/src/gfx/drivers/OpenGLDisplayDriver.ec +++ b/ecere/src/gfx/drivers/OpenGLDisplayDriver.ec @@ -10,7 +10,7 @@ import "Display" import "glab" import "immediate" import "matrixStack" -import "shading" +import "defaultShader" namespace gfx::drivers; @@ -320,7 +320,7 @@ public void GLSetupTexturing(bool enable) { #if ENABLE_GL_SHADERS if(glCaps_shaders) - shader_texturing(enable); + defaultShader.texturing(enable); #endif #if ENABLE_GL_FFP @@ -333,7 +333,7 @@ public void GLSetupFog(bool enable) { #if ENABLE_GL_SHADERS if(glCaps_shaders) - shader_fog(enable); + defaultShader.fog(enable); #endif #if ENABLE_GL_FFP @@ -349,7 +349,7 @@ public void GLSetupLighting(bool enable) lightingEnabled = enable; #if ENABLE_GL_SHADERS if(glCaps_shaders) - shader_lighting(enable); + defaultShader.lighting(enable); #endif #if ENABLE_GL_FFP @@ -361,6 +361,8 @@ public void GLSetupLighting(bool enable) /*static */GLuint lastBlitTex; +Shader activeShader; + static int displayWidth, displayHeight; #define GL_CLAMP_TO_EDGE 0x812F @@ -368,6 +370,17 @@ static int displayWidth, displayHeight; static bool useSingleGLContext = false; class OGLDisplay : struct { + GLCapabilities capabilities, originalCapabilities; + bool compat; + int version; + + ColorAlpha * flippingBuffer; + int flipBufH, flipBufW; + bool depthWrite; + int x, y; + uint vao; + int maxTMU; + #if defined(__WIN32__) HDC hdc; HGLRC glrc; @@ -397,27 +410,12 @@ class OGLDisplay : struct Pixmap shapePixmap; X11Picture shapePicture; #endif - - GLCapabilities capabilities, originalCapabilities; - bool compat; - int version; - - ColorAlpha * flippingBuffer; - int flipBufH, flipBufW; - bool depthWrite; - int x, y; - uint vao; }; class OGLSystem : struct { int maxTextureSize; bool loadingFont; -#if ENABLE_GL_SHADERS - int shadingProgram; - int vertexShader; - int fragmentShader; -#endif #if defined(__WIN32__) PIXELFORMATDESCRIPTOR pfd; int format; @@ -455,6 +453,8 @@ class OGLMesh : struct { GLAB vertices; GLAB normals; + GLAB tangents; + GLAB lightVectors; GLAB texCoords; GLAB texCoords2; GLAB colors; @@ -665,7 +665,7 @@ class OpenGLDisplayDriver : DisplayDriver { GLCapabilities capabilities; #if !defined(_GLES2) - const char * extensions = (canCheckExtensions && oglDisplay.compat) ? (const char *)glGetString(GL_EXTENSIONS) : null; + const char * extensions = (canCheckExtensions && (!oglDisplay || oglDisplay.compat)) ? (const char *)glGetString(GL_EXTENSIONS) : null; #endif #ifdef DIAGNOSTICS printf("extensions: %s\n", extensions); @@ -705,7 +705,7 @@ class OpenGLDisplayDriver : DisplayDriver vao = glBindVertexArray != null && !oglDisplay.compat; #endif #if ENABLE_GL_FBO - shaders = glBindFramebuffer != null; + frameBuffer = glBindFramebuffer != null; #endif vertexBuffer = glBindBuffer != null; // mapBuffer = glMapBuffer != null; @@ -987,12 +987,8 @@ class OpenGLDisplayDriver : DisplayDriver } #if ENABLE_GL_SHADERS - if(oglSystem.shadingProgram) - glDeleteProgram(oglSystem.shadingProgram); - if(oglSystem.fragmentShader) - glDeleteShader(oglSystem.fragmentShader); - if(oglSystem.vertexShader) - glDeleteShader(oglSystem.vertexShader); + defaultShader.free(); + activeShader = null; #endif delete oglSystem.shortBDBuffer; @@ -1022,6 +1018,8 @@ class OpenGLDisplayDriver : DisplayDriver XFree(oglSystem.visualInfo); #endif } + if(oglSystem.glContext) + glXDestroyContext(xGlobalDisplay, oglSystem.glContext); if(oglSystem.glxDrawable) { @@ -1043,12 +1041,6 @@ class OpenGLDisplayDriver : DisplayDriver if(loadExtensions && ogl_LoadFunctions() == ogl_LOAD_FAILED) PrintLn("ogl_LoadFunctions() failed!"); CheckCapabilities(oglSystem, oglDisplay, canCheckExtensions); - #ifdef GL_DEBUGGING - if(oglDisplay.capabilities.debug) - setupDebugging(); - #else - oglDisplay.capabilities.debug = false; - #endif #endif { @@ -1093,6 +1085,13 @@ class OpenGLDisplayDriver : DisplayDriver oglSystem.capabilities = oglDisplay.capabilities; } + #ifdef GL_DEBUGGING + if(oglDisplay.capabilities.debug) + setupDebugging(); + #else + oglDisplay.capabilities.debug = false; + #endif + #if ENABLE_GL_VAO if(oglDisplay.capabilities.vao) { @@ -1116,7 +1115,7 @@ class OpenGLDisplayDriver : DisplayDriver glDisableClientState(GL_COLOR_ARRAY); } #endif - loadShaders(display.displaySystem, "<:ecere>shaders/fixed.vertex", "<:ecere>shaders/fixed.frag"); + defaultShader.select(); } #if ENABLE_GL_LEGACY else @@ -1125,7 +1124,11 @@ class OpenGLDisplayDriver : DisplayDriver glDisableVertexAttribArray(GLBufferContents::normal); glDisableVertexAttribArray(GLBufferContents::texCoord); glDisableVertexAttribArray(GLBufferContents::vertex); + glDisableVertexAttribArray(GLBufferContents::tangent1); + glDisableVertexAttribArray(GLBufferContents::tangent2); +#if ENABLE_GL_VAO glBindVertexArray(0); +#endif glUseProgram(0); } #endif @@ -1169,10 +1172,10 @@ class OpenGLDisplayDriver : DisplayDriver if(!glCaps_shaders) { glShadeModel(GL_FLAT); - /* + #define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 GLLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); - */ + #if !defined(_GLES) ;//GLLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); #endif @@ -1711,6 +1714,9 @@ class OpenGLDisplayDriver : DisplayDriver #endif GLABBindBuffer(GL_ARRAY_BUFFER, 0); GLABBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +#if ENABLE_GL_SHADERS + activeProgram = 0; +#endif } void EndUpdate(Display display) @@ -1892,12 +1898,14 @@ class OpenGLDisplayDriver : DisplayDriver return result; } - bool MakeDDBitmap(DisplaySystem displaySystem, Bitmap bitmap, bool mipMaps) + bool MakeDDBitmap(DisplaySystem displaySystem, Bitmap bitmap, bool mipMaps, uint cubeMapFace) { bool result = false; OGLSystem oglSystem = displaySystem.driverData; GLCapabilities capabilities = oglSystem.capabilities; Bitmap convBitmap = bitmap; + bool oldStyleCubeMap = (cubeMapFace >> 3) != 0; + int face = (cubeMapFace & 7) - 1; if(bitmap.keepData) { convBitmap = { }; @@ -1909,7 +1917,8 @@ class OpenGLDisplayDriver : DisplayDriver { int c, level; uint w = bitmap.width, h = bitmap.height; - GLuint glBitmap = 0; + GLuint glBitmap = cubeMapFace && face > 0 ? (GLuint)(uintptr)bitmap.driverData : 0; + int target = cubeMapFace ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; if(!capabilities.nonPow2Textures) { w = pow2i(w); @@ -1927,7 +1936,8 @@ class OpenGLDisplayDriver : DisplayDriver // Switch ARGB to RGBA //if(bitmap.format != pixelFormatRGBA) { - for(c=0; cm[3][0], mat->m[3][1], mat->m[3][2] }; + if(display.display3D && display.display3D.camera) + l.Subtract(l, display.display3D.camera.cPosition); - position[0] = positionVector.x; - position[1] = positionVector.y; - position[2] = positionVector.z; - - glDisable(GL_LIGHTING); - glDisable(GL_DEPTH_TEST); - glColor3f(1,1,0); - glPointSize(10); - glBegin(GL_POINTS); - glVertex3fv(position); - glEnd(); - glEnable(GL_DEPTH_TEST); - glEnable(GL_LIGHTING); - */ + position[0] = (float)l.x, position[1] = (float)l.y, position[2] = (float)l.z, position[3] = 1; if(light.flags.attenuation) { @@ -2949,34 +2958,104 @@ class OpenGLDisplayDriver : DisplayDriver glLightf(GL_LIGHT0 + id, GL_LINEAR_ATTENUATION, light.Kl); glLightf(GL_LIGHT0 + id, GL_QUADRATIC_ATTENUATION, light.Kq); } + else + { + glLightf(GL_LIGHT0 + id, GL_CONSTANT_ATTENUATION, 1); + glLightf(GL_LIGHT0 + id, GL_LINEAR_ATTENUATION, 0); + glLightf(GL_LIGHT0 + id, GL_QUADRATIC_ATTENUATION, 0); + } - if(light.flags.spot) + if((light.flags.spot && light.fallOff < 360) || (lightObject && (light.direction.x || light.direction.y || light.direction.z))) { - float exponent = 0; + // Figure out exponent out of the hot spot #define MAXLIGHT 0.9 + float exponent = light.flags.spot ? (float)(log(MAXLIGHT) / log(cos(light.hotSpot / 2))) : 1; + Degrees cutOff = light.flags.spot ? light.fallOff/2 : 90; float direction[4] = { (float)light.direction.x, (float)light.direction.y, (float)light.direction.z, 1 }; - // Figure out exponent out of the hot spot - exponent = (float)(log(MAXLIGHT) / log(cos((light.hotSpot / 2)))); glLightfv(GL_LIGHT0 + id, GL_SPOT_DIRECTION, direction); - glLightf(GL_LIGHT0 + id, GL_SPOT_CUTOFF, (float)(light.fallOff / 2)); + glLightf(GL_LIGHT0 + id, GL_SPOT_CUTOFF, (float)cutOff); glLightf(GL_LIGHT0 + id, GL_SPOT_EXPONENT, exponent); } + else + { + float d[4] = { 0, 0, 1, 0 }; + glLightfv(GL_LIGHT0 + id, GL_SPOT_DIRECTION, d); + glLightf(GL_LIGHT0 + id, GL_SPOT_CUTOFF, 180); + glLightf(GL_LIGHT0 + id, GL_SPOT_EXPONENT, 1); + } + + /* + if(lightObject) + { + // Display Light Position + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glColor3f(1,1,1); + glPointSize(10); + glBegin(GL_POINTS); + glVertex3fv(position); + glEnd(); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + + + // Display Target + if(lightObject.flags.root || !lightObject.parent) + { + positionVector = light.target.transform.position; + positionVector.Subtract(positionVector, display.camera.cPosition); + } + else + { + positionVector.MultMatrix(light.target.transform.position, + lightObject.light.target.parent.matrix); + positionVector.Subtract(positionVector, display.camera.cPosition); + } + + position[0] = positionVector.x; + position[1] = positionVector.y; + position[2] = positionVector.z; + + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + glColor3f(1,1,0); + glPointSize(10); + glBegin(GL_POINTS); + glVertex3fv(position); + glEnd(); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + } + */ } else { - Vector3Df vector { 0,0,-1 }; - Vector3Df direction; + // Directional Light + Vector3D vector { 0,0,-1 }; + Vector3D direction; Matrix mat; - mat.RotationQuaternion(light.orientation); direction.MultMatrix(vector, mat); - - position[0] = direction.x; - position[1] = direction.y; - position[2] = direction.z; - - glLightfv(GL_LIGHT0 + id, GL_POSITION, position); + l.Normalize(direction); + position[0] = (float)l.x, position[1] = (float)l.y, position[2] = (float)l.z, position[3] = 0; + } + glLightfv(GL_LIGHT0 + id, GL_POSITION, position); + if(display.display3D) + { + Matrix m; + Vector3Df v { position[0], position[1], position[2] }; + Vector3Df l; + float * lp = display.display3D.light0Pos; + if(display.display3D.camera) + m = display.display3D.camera.viewMatrix; + else + m.Identity(); + l.MultMatrix(v, m); + lp[0] = l.x; + lp[1] =-l.y; + lp[2] =-l.z; + lp[3] = position[3]; } } else @@ -3005,6 +3084,11 @@ class OpenGLDisplayDriver : DisplayDriver // *** ViewPort *** glViewport(x, y, w, h); + GLMatrixMode(MatrixMode::texture); + if(!display.display3D.camera) + GLPushMatrix(); + GLLoadIdentity(); + // *** Projection Matrix *** GLMatrixMode(MatrixMode::projection); if(!display.display3D.camera) @@ -3049,6 +3133,14 @@ class OpenGLDisplayDriver : DisplayDriver // *** View Matrix *** GLMultMatrixd(camera.viewMatrix.array); +#if ENABLE_GL_SHADERS + if(glCaps_shaders) + { + defaultShader.select(); + defaultShader.setCamera(camera); + } +#endif + // *** Lights *** // ... @@ -3075,15 +3167,66 @@ class OpenGLDisplayDriver : DisplayDriver glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); + GLDisableClientState(COLORS); +#if ENABLE_GL_SHADERS + if(glCaps_shaders) + { + GLDisableClientState(TANGENTS1); + GLDisableClientState(TANGENTS2); + } +#endif + GLDisableClientState(NORMALS); +#if ENABLE_GL_FFP + if(!glCaps_shaders) + GLDisableClientState(LIGHTVECTORS); +#endif + + // *** Restore 2D MODELVIEW Matrix *** + GLMatrixMode(MatrixMode::modelView); + GLPopMatrix(); + + // *** Restore 2D TEXTURE Matrix *** + GLMatrixMode(MatrixMode::texture); + GLPopMatrix(); + + // *** Restore 2D PROJECTION Matrix *** + GLMatrixMode(MatrixMode::projection); + GLPopMatrix(); + + // NOTE: We expect the 2D projection matrix to be the active one for GetSurface to call glOrtho() + +#if ENABLE_GL_SHADERS + if(glCaps_shaders) + defaultShader.select(); +#endif + +#if ENABLE_GL_FFP + if(!glCaps_shaders) + { + disableRemainingTMUs(display, 0); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glDisable(GL_TEXTURE_CUBE_MAP); + #if _GLES + glDisable(GL_TEXTURE_GEN_STR); + #else + glDisable(GL_TEXTURE_GEN_R); + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + #endif + } +#endif + GLSetupTexturing(false); GLSetupLighting(false); GLSetupFog(false); - GLDisableClientState(COLORS); - #if ENABLE_GL_SHADERS if(glCaps_shaders) - shader_setPerVertexColor(false); + { + defaultShader.setPerVertexColor(false); + defaultShader.setMaterial(null, 0); + } #endif #if ENABLE_GL_FFP @@ -3094,25 +3237,31 @@ class OpenGLDisplayDriver : DisplayDriver #if !defined(__EMSCRIPTEN__) glDisable(GL_MULTISAMPLE); #endif - - // *** Restore 2D MODELVIEW Matrix *** - GLPopMatrix(); - - // *** Restore 2D PROJECTION Matrix *** - GLMatrixMode(MatrixMode::projection); - GLPopMatrix(); } - } void ApplyMaterial(Display display, Material material, Mesh mesh) { + Shader shader = material.shader ? material.shader : defaultShader; + MaterialFlags flags = material.flags; +#if ENABLE_GL_FFP + static int lastSeparate = 0; + int tmu = 0; + bool normalMapped = false; + OGLMesh oglMesh = mesh ? mesh.data : null; +#endif + +#if ENABLE_GL_SHADERS + if(glCaps_shaders && shader) + shader.select(); +#endif + // Basic Properties - if(material.flags.doubleSided) + if(flags.doubleSided) { #if ENABLE_GL_FFP if(!glCaps_shaders) - GLLightModeli(GL_LIGHT_MODEL_TWO_SIDE, !material.flags.singleSideLight); + GLLightModeli(GL_LIGHT_MODEL_TWO_SIDE, !flags.singleSideLight); #endif glDisable(GL_CULL_FACE); } @@ -3126,43 +3275,413 @@ class OpenGLDisplayDriver : DisplayDriver } // Fog - GLSetupFog(!material.flags.noFog); + GLSetupFog(!flags.noFog); + +#if ENABLE_GL_SHADERS + if(glCaps_shaders) + activeShader.setMaterial(material, mesh.flags); +#endif + +#if ENABLE_GL_FFP + if(!glCaps_shaders) + { + if(material.bumpMap && mesh.lightVectors) + { + float color[4] = { 1,1,1,1 }; + glActiveTexture(GL_TEXTURE0 + tmu); + glClientActiveTexture(GL_TEXTURE0 + tmu++); + glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr)material.bumpMap.driverData); + glDisable(GL_TEXTURE_CUBE_MAP); + glEnable(GL_TEXTURE_2D); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + + if(0) //((DefaultShaderBits)defaultShader.state).debugging) + { + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color ); + } + #if _GLES + glDisable(GL_TEXTURE_GEN_STR); + #else + glDisable(GL_TEXTURE_GEN_R); + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + #endif + glDisable(GL_LIGHTING); + lightingEnabled = false; + + GLMatrixMode(GL_TEXTURE); + GLLoadIdentity(); + if(material.uScale && material.vScale) + GLScalef(material.uScale, material.vScale, 1); + GLMatrixMode(MatrixMode::modelView); + + if(flags.tile) + { + 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_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + + glActiveTexture(GL_TEXTURE0 + tmu); + glClientActiveTexture(GL_TEXTURE0 + tmu); + + normalMapped = true; + + // Modulate base color + if(material.diffuse.r < 1 || material.diffuse.g < 1 || material.diffuse.b < 1) + { + tmu++; + glDisable(GL_TEXTURE_CUBE_MAP); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr)material.bumpMap.driverData); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); + + color[0] = material.diffuse.r, color[1] = material.diffuse.g, color[2] = material.diffuse.b, color[3] = 1.0; + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color ); + glActiveTexture(GL_TEXTURE0 + tmu); + glClientActiveTexture(GL_TEXTURE0 + tmu); + } + + // Add ambient light + { + ColorRGB ambient { material.ambient.r * 0.2f, material.ambient.g * 0.2f, material.ambient.g * 0.2f }; + if(ambient.r > 0 || ambient.g > 0 || ambient.b > 0) + { + tmu++; + glDisable(GL_TEXTURE_CUBE_MAP); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr)material.bumpMap.driverData); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); + + color[0] = ambient.r, color[1] = ambient.g, color[2] = ambient.b, color[3] = 1.0; + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color ); + glActiveTexture(GL_TEXTURE0 + tmu); + glClientActiveTexture(GL_TEXTURE0 + tmu); + } + } + } + else + { + GLDisableClientState(LIGHTVECTORS); + if(!lightingEnabled) + { + glEnable(GL_LIGHTING); + lightingEnabled = true; + } + } + } +#endif // Maps - if(material.baseMap && (mesh.texCoords || mesh.flags.texCoords1)) + if(flags.cubeMap || (material.baseMap && (mesh.texCoords || mesh.flags.texCoords1))) { Bitmap map = material.baseMap; - GLSetupTexturing(true); - glBindTexture(GL_TEXTURE_2D, (GLuint)(uintptr)map.driverData); + int diffuseTarget = flags.cubeMap ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D; + +#if ENABLE_GL_FFP + if(!glCaps_shaders) + { + glActiveTexture(GL_TEXTURE0 + tmu); + glClientActiveTexture(GL_TEXTURE0 + tmu++); + glEnable(diffuseTarget); + glDisable(flags.cubeMap ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP); + } +#endif + +#if ENABLE_GL_SHADERS + if(glCaps_shaders && !flags.cubeMap) + GLSetupTexturing(true); +#endif + + glBindTexture(diffuseTarget, (GLuint)(uintptr)map.driverData); + +#if ENABLE_GL_FFP + if(!glCaps_shaders) + { + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + /* // This did not have the desired effect with a GL_ALPHA texture + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); + */ + + if(flags.cubeMap) + { + #if _GLES + glEnable(GL_TEXTURE_GEN_STR); + // GL_OBJECT_LINEAR: No extension support? + // glTexGeni(GL_TEXTURE_GEN_STR_OES, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + #else + GLfloat xPlane[] = { 1.0f, 0.0f, 0.0f, 0 }; + GLfloat yPlane[] = { 0.0f,-1.0f, 0.0f, 0 }; + GLfloat zPlane[] = { 0.0f, 0.0f,-1.0f, 0 }; + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); + glTexGenfv(GL_R, GL_OBJECT_PLANE, zPlane); + glTexGenfv(GL_S, GL_OBJECT_PLANE, xPlane); + glTexGenfv(GL_T, GL_OBJECT_PLANE, yPlane); + + glEnable(GL_TEXTURE_GEN_R); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + #endif + + GLDisableClientState(TEXCOORDS); + } + else + { + #if _GLES + glDisable(GL_TEXTURE_GEN_STR); + #else + glDisable(GL_TEXTURE_GEN_R); + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); + #endif + + if(tmu > 1) + oglMesh.texCoords.use(texCoord, 2, GL_FLOAT, 0, oglMesh.texCoords.buffer ? null : mesh.texCoords); + GLEnableClientState(TEXCOORDS); + } + glClientActiveTexture(GL_TEXTURE0); + } +#endif + if(flags.tile) + { + glTexParameteri(diffuseTarget, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(diffuseTarget, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + else + { + glTexParameteri(diffuseTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(diffuseTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + } + else + { + GLSetupTexturing(false); + } +#if ENABLE_GL_FFP && !defined(_GLES) + if(!glCaps_shaders) + { + int separate = material.flags.separateSpecular ? GL_SEPARATE_SPECULAR_COLOR : GL_SINGLE_COLOR; + if(separate != lastSeparate) + { + GLLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, separate); + lastSeparate = separate; + } + } +#endif + + if((flags.cubeMap && material.baseMap) || + (mesh.texCoords && (material.baseMap || material.bumpMap || material.specularMap || material.reflectMap))) + { +#if ENABLE_GL_FFP + if(!glCaps_shaders) + { + glActiveTexture(GL_TEXTURE0 + tmu - 1); + glClientActiveTexture(GL_TEXTURE0 + tmu - 1); + } +#endif GLMatrixMode(GL_TEXTURE); GLLoadIdentity(); if(material.uScale && material.vScale) GLScalef(material.uScale, material.vScale, 1); GLMatrixMode(MatrixMode::modelView); +#if ENABLE_GL_FFP + if(!glCaps_shaders) + { + glActiveTexture(GL_TEXTURE0); + glClientActiveTexture(GL_TEXTURE0); + } +#endif + } - if(material.flags.tile) +#if ENABLE_GL_FFP + if(!glCaps_shaders) + { + if(material.envMap && material.refractiveIndex) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + float color[4] = { material.opacity, material.opacity, material.opacity, 1.0 }; + glActiveTexture(GL_TEXTURE0 + tmu); + glClientActiveTexture(GL_TEXTURE0 + tmu++); + glBindTexture(GL_TEXTURE_CUBE_MAP, (GLuint)(uintptr)material.envMap.driverData); + glEnable(GL_TEXTURE_CUBE_MAP); + #if _GLES + glEnable(GL_TEXTURE_GEN_STR); + glTexGeni(GL_TEXTURE_GEN_STR_OES, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + #else + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glEnable(GL_TEXTURE_GEN_R); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + #endif + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + + if(normalMapped) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + else + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); + + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); + + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); + + if(!normalMapped) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_ALPHA, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA); + } + + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color ); + + GLMatrixMode(MatrixMode::texture); + { + double * s = display.display3D.camera.viewMatrix.array; + double k = 2.0; + Matrix m + { { + k*s[0],-k*s[4],-k*s[8], 0, + k*s[1],-k*s[5],-k*s[9], 0, + k*s[2],-k*s[6],-k*s[10],0, + 0,0,0,1 + } }; + GLLoadMatrixd(m.array); + } + GLMatrixMode(MatrixMode::modelView); } - else + + if(material.envMap && material.reflectivity) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + float color[4] = { 1.0f - material.reflectivity, 1.0f - material.reflectivity, 1.0f - material.reflectivity, 1.0 }; + glActiveTexture(GL_TEXTURE0 + tmu); + glClientActiveTexture(GL_TEXTURE0 + tmu++); + glBindTexture(GL_TEXTURE_CUBE_MAP, (GLuint)(uintptr)material.envMap.driverData); + glEnable(GL_TEXTURE_CUBE_MAP); + #if _GLES + glEnable(GL_TEXTURE_GEN_STR); + glTexGeni(GL_TEXTURE_GEN_STR_OES, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + #else + glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); + glEnable(GL_TEXTURE_GEN_R); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); + #endif + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + + if(normalMapped) + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + else + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); + + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA); + + if(!normalMapped) + { + glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_ALPHA, GL_CONSTANT); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA); + } + + glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color ); + + GLMatrixMode(MatrixMode::texture); + { + double * s = display.display3D.camera.inverseTranspose.array; + Matrix m + { { + s[0],s[1],-s[2],0, + s[4],-s[5],-s[6],0, + -s[8],s[9],s[10],0, + 0,0,0,1 + } }; + GLLoadMatrixd(m.array); + } + GLMatrixMode(MatrixMode::modelView); } } - else - GLSetupTexturing(false); - -#if ENABLE_GL_SHADERS - if(glCaps_shaders) - shader_setMaterial(material, mesh.flags.colors); #endif #if ENABLE_GL_FFP if(!glCaps_shaders) { + disableRemainingTMUs(display, tmu); + if(mesh.flags.colors) { GLColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); @@ -3180,15 +3699,20 @@ class OpenGLDisplayDriver : DisplayDriver glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, color); } } + if(material.power > 0.1) { float color[4] = { material.specular.r, material.specular.g, material.specular.b, 0 }; glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color); } + else + { + float color[4] = { 0,0,0,0 }; + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, color); + } { float color[4] = { material.emissive.r, material.emissive.g, material.emissive.b, 0 }; glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, color); } - glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, &material.power); } #endif @@ -3200,30 +3724,42 @@ class OpenGLDisplayDriver : DisplayDriver if(oglMesh) { OGLSystem oglSystem = displaySystem.driverData; + GLCapabilities caps = glCaps; SETCAPS(oglSystem.capabilities); + if(!mesh.flags.vertices) { - oglMesh.vertices.free(glCaps_vertexBuffer); + oglMesh.vertices.free(); delete mesh.vertices; } if(!mesh.flags.normals) { - oglMesh.normals.free(glCaps_vertexBuffer); + oglMesh.normals.free(); delete mesh.normals; } + if(!mesh.flags.tangents) + { + oglMesh.tangents.free(); + delete mesh.tangents; + } + if(!mesh.flags.lightVectors) + { + oglMesh.lightVectors.free(); + delete mesh.lightVectors; + } if(!mesh.flags.texCoords1) { - oglMesh.texCoords.free(glCaps_vertexBuffer); + oglMesh.texCoords.free(); delete mesh.texCoords; } if(!mesh.flags.texCoords2) { - oglMesh.texCoords2.free(glCaps_vertexBuffer); + oglMesh.texCoords2.free(); // delete mesh.texCoords2; } if(!mesh.flags.colors) { - oglMesh.colors.free(glCaps_vertexBuffer); + oglMesh.colors.free(); delete mesh.colors; } if(!mesh.flags) @@ -3231,6 +3767,7 @@ class OpenGLDisplayDriver : DisplayDriver delete oglMesh; mesh.data = null; } + SETCAPS(caps); } } @@ -3265,6 +3802,14 @@ class OpenGLDisplayDriver : DisplayDriver else mesh.normals = new Vector3Df[nVertices]; } + if(!mesh.flags.tangents && flags.tangents) + { + mesh.tangents = new Vector3Df[2*nVertices]; + } + if(!mesh.flags.lightVectors && flags.lightVectors) + { + mesh.lightVectors = new ColorRGB[nVertices]; + } if(!mesh.flags.texCoords1 && flags.texCoords1) { mesh.texCoords = new Pointf[nVertices]; @@ -3305,6 +3850,14 @@ class OpenGLDisplayDriver : DisplayDriver { mesh.colors = renew mesh.colors ColorRGBAf[nVertices]; } + if(flags.tangents) + { + mesh.tangents = renew mesh.tangents Vector3Df[2 * nVertices]; + } + if(flags.lightVectors) + { + mesh.lightVectors = renew mesh.lightVectors ColorRGB[nVertices]; + } } result = true; } @@ -3314,7 +3867,9 @@ class OpenGLDisplayDriver : DisplayDriver void UnlockMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags) { OGLSystem oglSystem = displaySystem.driverData; + GLCapabilities caps = glCaps; SETCAPS(oglSystem.capabilities); + if(glCaps_vertexBuffer) { OGLMesh oglMesh = mesh.data; @@ -3334,7 +3889,14 @@ class OpenGLDisplayDriver : DisplayDriver if(flags.colors) oglMesh.colors.allocate( mesh.nVertices * sizeof(ColorRGBAf), mesh.colors, staticDraw); + + if(flags.tangents) + oglMesh.tangents.allocate(mesh.nVertices * 2*sizeof(Vector3Df), mesh.tangents, staticDraw); + + if(flags.lightVectors) + oglMesh.lightVectors.allocate(mesh.nVertices * sizeof(ColorRGB), mesh.lightVectors, staticDraw); } + SETCAPS(caps); } bool LockMesh(DisplaySystem displaySystem, Mesh mesh, MeshFeatures flags) @@ -3347,13 +3909,16 @@ class OpenGLDisplayDriver : DisplayDriver void FreeIndices(DisplaySystem displaySystem, OGLIndices oglIndices) { OGLSystem oglSystem = displaySystem.driverData; + GLCapabilities caps = glCaps; SETCAPS(oglSystem.capabilities); + if(oglIndices) { - oglIndices.buffer.free(glCaps_vertexBuffer); + oglIndices.buffer.free(); delete oglIndices.indices; delete oglIndices; } + SETCAPS(caps); } void * AllocateIndices(DisplaySystem displaySystem, int nIndices, bool indices32bit) @@ -3370,7 +3935,9 @@ class OpenGLDisplayDriver : DisplayDriver void UnlockIndices(DisplaySystem displaySystem, OGLIndices oglIndices, bool indices32bit, int nIndices) { OGLSystem oglSystem = displaySystem.driverData; + GLCapabilities caps = glCaps; SETCAPS(oglSystem.capabilities); + if(glCaps_vertexBuffer) { if(!glCaps_intAndDouble && indices32bit) @@ -3401,6 +3968,7 @@ class OpenGLDisplayDriver : DisplayDriver nIndices * (indices32bit ? sizeof(uint32) : sizeof(uint16)), oglIndices.indices, staticDraw); } + SETCAPS(caps); } uint16 * LockIndices(DisplaySystem displaySystem, OGLIndices oglIndices) @@ -3437,6 +4005,25 @@ class OpenGLDisplayDriver : DisplayDriver else GLDisableClientState(NORMALS); +#if ENABLE_GL_SHADERS + if(glCaps_shaders) + { + // *** Tangents Stream *** + if(mesh.tangents || mesh.flags.tangents) + { + GLEnableClientState(TANGENTS1); + GLEnableClientState(TANGENTS2); + oglMesh.tangents.use(tangent1, 3, GL_FLOAT, sizeof(Vector3Df)*2, oglMesh.tangents.buffer ? null : mesh.tangents); + oglMesh.tangents.use(tangent2, 3, GL_FLOAT, sizeof(Vector3Df)*2, oglMesh.tangents.buffer ? (void *)sizeof(Vector3Df) : mesh.tangents+1); + } + else + { + GLDisableClientState(TANGENTS1); + GLDisableClientState(TANGENTS2); + } + } +#endif + // *** Texture Coordinates Stream *** if(mesh.texCoords || mesh.flags.texCoords1) { @@ -3446,6 +4033,20 @@ class OpenGLDisplayDriver : DisplayDriver else GLDisableClientState(TEXCOORDS); +#if ENABLE_GL_FFP + if(!glCaps_shaders) + { + // *** Normal Map Aligned Light Vector *** + if(mesh.lightVectors || mesh.flags.lightVectors) + { + GLEnableClientState(LIGHTVECTORS); + oglMesh.lightVectors.use(lightVector, 3, GL_FLOAT, 0, oglMesh.lightVectors.buffer ? null : mesh.lightVectors); + } + else + GLDisableClientState(LIGHTVECTORS); + } + else +#endif // *** Color Stream *** if(mesh.colors || mesh.flags.colors) { @@ -3465,6 +4066,24 @@ class OpenGLDisplayDriver : DisplayDriver } else GLDisableClientState(NORMALS); +#if ENABLE_GL_SHADERS + if(glCaps_shaders) + { + if((mesh.tangents || mesh.flags.tangents) && !display.display3D.collectingHits) + { + GLEnableClientState(TANGENTS1); + GLEnableClientState(TANGENTS2); + noAB.use(tangent1, 3, GL_FLOAT, sizeof(Vector3Df)*2, mesh.tangents); + noAB.use(tangent2, 3, GL_FLOAT, sizeof(Vector3Df)*2, mesh.tangents+1); + } + else + { + GLDisableClientState(TANGENTS1); + GLDisableClientState(TANGENTS2); + } + } +#endif + if((mesh.texCoords || mesh.flags.texCoords1) && !display.display3D.collectingHits) { GLEnableClientState(TEXCOORDS); @@ -3472,6 +4091,20 @@ class OpenGLDisplayDriver : DisplayDriver } else GLDisableClientState(TEXCOORDS); + +#if ENABLE_GL_FFP + if(!glCaps_shaders) + { + if((mesh.lightVectors || mesh.flags.lightVectors) && !display.display3D.collectingHits) + { + GLEnableClientState(LIGHTVECTORS); + noAB.use(lightVector, 3, GL_FLOAT, sizeof(ColorRGB), mesh.lightVectors); + } + else + GLDisableClientState(LIGHTVECTORS); + } + else +#endif if((mesh.colors || mesh.flags.colors) && !display.display3D.collectingHits) { GLEnableClientState(COLORS);