diff --git a/examples/02.Quake3Map/main.cpp b/examples/02.Quake3Map/main.cpp index d574bed2..f37b95dd 100644 --- a/examples/02.Quake3Map/main.cpp +++ b/examples/02.Quake3Map/main.cpp @@ -57,22 +57,24 @@ int main() video::E_DRIVER_TYPE driverType; printf("Please select the driver you want for this example:\n"\ - " (a) OpenGL 1.5\n (b) Direct3D 9.0c\n (c) Direct3D 8.1\n"\ - " (d) OpenGL-ES1\n (e) Burning's Software Renderer\n (f) Software Renderer\n"\ - " (g) NullDevice\n (otherKey) exit\n\n"); + " (a) OpenGL ES 2.x\n (b) OpenGL ES 1.x\n (c) OpenGL 1.x-4.x\n"\ + " (d) Direct3D 9.0c\n (e) Direct3D 8.1\n"\ + " (f) Burning's Software Renderer\n (g) Software Renderer\n"\ + " (h) NullDevice\n (otherKey) exit\n\n"); char i; std::cin >> i; switch(i) { - case 'a': driverType = video::EDT_OPENGL; break; - case 'b': driverType = video::EDT_DIRECT3D9;break; - case 'c': driverType = video::EDT_DIRECT3D8;break; - case 'd': driverType = video::EDT_OGLES1; break; - case 'e': driverType = video::EDT_BURNINGSVIDEO;break; - case 'f': driverType = video::EDT_SOFTWARE; break; - case 'g': driverType = video::EDT_NULL; break; + case 'a': driverType = video::EDT_OGLES2; break; + case 'b': driverType = video::EDT_OGLES1; break; + case 'c': driverType = video::EDT_OPENGL; break; + case 'd': driverType = video::EDT_DIRECT3D9;break; + case 'e': driverType = video::EDT_DIRECT3D8;break; + case 'f': driverType = video::EDT_BURNINGSVIDEO;break; + case 'g': driverType = video::EDT_SOFTWARE; break; + case 'h': driverType = video::EDT_NULL; break; default: return 1; } diff --git a/include/EDriverTypes.h b/include/EDriverTypes.h index 10e21e9b..0acc7c70 100644 --- a/include/EDriverTypes.h +++ b/include/EDriverTypes.h @@ -52,9 +52,13 @@ namespace video primitives. */ EDT_OPENGL, - //! OpenGL-ES device, for embedded and mobile systems + //! OpenGL-ES 1.x driver, for embedded and mobile systems EDT_OGLES1, + //! OpenGL-ES 2.x driver, for embedded and mobile systems + /** Supports shaders etc. */ + EDT_OGLES2, + //! No driver, just for counting the elements EDT_COUNT }; diff --git a/include/EVertexAttributes.h b/include/EVertexAttributes.h new file mode 100644 index 00000000..79260766 --- /dev/null +++ b/include/EVertexAttributes.h @@ -0,0 +1,38 @@ +#ifndef __E_VERTEX_ATTRIBUTES_H_INCLUDED__ +#define __E_VERTEX_ATTRIBUTES_H_INCLUDED__ + +namespace irr +{ +namespace video +{ + +//! Enumeration for all vertex attibutes there are. +enum E_VERTEX_ATTRIBUTES +{ + EVA_POSITION = 0, + EVA_NORMAL, + EVA_COLOR, + EVA_TCOORD0, + EVA_TCOORD1, + EVA_TANGENT, + EVA_BINORMAL, + EVA_COUNT +}; + +//! Array holding the built in vertex attribute names +const char* const sBuiltInVertexAttributeNames[] = +{ + "inVertexPosition", + "inVertexNormal", + "inVertexColor", + "inTexCoord0", + "inTexCoord1", + "inVertexTangent", + "inVertexBinormal", + 0 +}; + +} // end namespace video +} // end namespace irr + +#endif //__E_VERTEX_ATTRIBUTES_H_INCLUDED__ \ No newline at end of file diff --git a/include/IMaterialRenderer.h b/include/IMaterialRenderer.h index b9396d57..7c164432 100644 --- a/include/IMaterialRenderer.h +++ b/include/IMaterialRenderer.h @@ -69,6 +69,7 @@ public: actually done in D3D8 and D3D9 when using a normal mapped material with a vertex type other than EVT_TANGENTS. */ virtual bool OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) { return true; } + virtual bool PostRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) { return true;}; //! Called by the IVideoDriver to unset this material. /** Called during the IVideoDriver::setMaterial() call before the new diff --git a/include/IShaderConstantSetCallBack.h b/include/IShaderConstantSetCallBack.h index 84469710..6931e0f3 100644 --- a/include/IShaderConstantSetCallBack.h +++ b/include/IShaderConstantSetCallBack.h @@ -74,6 +74,9 @@ public: \param userData: Userdata int which can be specified when creating the shader. */ virtual void OnSetConstants(IMaterialRendererServices* services, s32 userData) = 0; + + virtual void OnSetAttribute(IMaterialRendererServices* services, s32 userData) {} + virtual void OnUnSetAttribute(IMaterialRendererServices* services, s32 userData) {} }; diff --git a/include/IrrCompileConfig.h b/include/IrrCompileConfig.h index 3fe5a254..7d8009ae 100644 --- a/include/IrrCompileConfig.h +++ b/include/IrrCompileConfig.h @@ -135,7 +135,7 @@ headers, e.g. Summer 2004. This is a Microsoft issue, not an Irrlicht one. //! Define _IRR_COMPILE_WITH_OPENGL_ to compile the Irrlicht engine with OpenGL. /** If you do not wish the engine to be compiled with OpenGL, comment this define out. */ -//#define _IRR_COMPILE_WITH_OPENGL_ +#define _IRR_COMPILE_WITH_OPENGL_ //! Define _IRR_COMPILE_WITH_OGLES1_ to compile the Irrlicht engine with OpenGL-ES 1.x. /** If you do not wish the engine to be compiled with OpenGL-ES 1.x, comment @@ -144,7 +144,16 @@ You should only use this define if you really need the OpenGL-ES driver, and it should be usually the only HW accelerated one. OpenGL is currently disabled if using this driver, to avoid problems with the ogl-es emulators. */ -#define _IRR_COMPILE_WITH_OGLES1_ +//#define _IRR_COMPILE_WITH_OGLES1_ + +//! Define _IRR_COMPILE_WITH_OGLES2_ to compile the Irrlicht engine with OpenGL-ES 2.x. +/** If you do not wish the engine to be compiled with OpenGL-ES 2.x, comment +this define out. +You should only use this define if you really need the OpenGL-ES driver, and +it should be usually the only HW accelerated one. OpenGL is currently disabled +if using this driver, to avoid problems with the ogl-es emulators. +*/ +//#define _IRR_COMPILE_WITH_OGLES2_ //! Define _IRR_COMPILE_WITH_SOFTWARE_ to compile the Irrlicht engine with software driver /** If you do not need the software driver, or want to use Burning's Video instead, @@ -535,8 +544,13 @@ precision will be lower but speed higher. currently X86 only #endif // OpenGL-ES usually interferes with OpenGL +#ifdef _IRR_COMPILE_WITH_OGLES2_ + #undef _IRR_COMPILE_WITH_OPENGL_ + #undef _IRR_COMPILE_WITH_OGLES1_ +#endif #ifdef _IRR_COMPILE_WITH_OGLES1_ #undef _IRR_COMPILE_WITH_OPENGL_ + #undef _IRR_COMPILE_WITH_OGLES2_ #endif #ifndef _IRR_WINDOWS_API_ diff --git a/include/driverChoice.h b/include/driverChoice.h index 785e4120..bde459e6 100644 --- a/include/driverChoice.h +++ b/include/driverChoice.h @@ -14,7 +14,10 @@ namespace irr //! ask user for driver static irr::video::E_DRIVER_TYPE driverChoiceConsole(bool allDrivers=true) { - const char* const names[] = {"NullDriver","Software Renderer","Burning's Video","Direct3D 8.1","Direct3D 9.0c","OpenGL 1.x/2.x/3.x","OpenGL-ES 1.x"}; + const char* const names[] = + {"NullDriver","Software Renderer","Burning's Video", + "Direct3D 8.1","Direct3D 9.0c", + "OpenGL 1.x/2.x/3.x","OpenGL-ES 1.x","OpenGL-ES 2.x"}; printf("Please select the driver you want:\n"); irr::u32 i=0; for (i=irr::video::EDT_COUNT; i>0; --i) diff --git a/media/Shaders/COGLES2FixedPipeline.fsh b/media/Shaders/COGLES2FixedPipeline.fsh new file mode 100644 index 00000000..5475b786 --- /dev/null +++ b/media/Shaders/COGLES2FixedPipeline.fsh @@ -0,0 +1,182 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#define MAX_TEXTURE_UNITS 4 +#define FOG_EXP 1 +#define FOG_LINEAR 2 + +#define TwoD 24 +#define Solid 0 +#define Solid2Layer 1 +#define LightMap 2 +#define DetailMap 9 +#define SphereMap 10 +#define Reflection2Layer 11 +#define TransparentAlphaChannel 13 +#define TransparentVertexAlpha 15 + +precision mediump float; + +vec4 red = vec4(1.0, 0.0, 0.0, 1.0); +vec4 green = vec4(0.0, 1.0, 0.0, 1.0); +vec4 blue = vec4(0.0, 0.0, 1.0, 1.0); + + +/* Varyings */ + +varying vec4 varTexCoord[MAX_TEXTURE_UNITS]; +varying vec4 varVertexColor; +varying float eyeDist; +varying float varClipDist; + +/* Uniforms */ + +uniform int uRenderMode; + +uniform bool uAlphaTest; +uniform float uAlphaValue; + +/* Fog Uniforms */ + +uniform bool uFog; +uniform int uFogType; +uniform vec4 uFogColor; +uniform float uFogStart; +uniform float uFogEnd; +uniform float uFogDensity; + +/* Texture Uniforms */ + +uniform sampler2D uTextureUnit0; +uniform sampler2D uTextureUnit1; +uniform bool uUseTexture [MAX_TEXTURE_UNITS]; + +vec4 render2D(void) +{ + vec4 color = varVertexColor; + vec4 texel = texture2D(uTextureUnit0, varTexCoord[0].xy); + if(uUseTexture[0]) + { + color *= texel; + } + return color; +} + +vec4 renderSolid(void) +{ + vec4 color = varVertexColor; + vec4 texel = texture2D(uTextureUnit0, varTexCoord[0].xy); + if(uUseTexture[0]) + color *= texel; + return color; +} + +vec4 renderTransparentVertexAlpha(void) +{ + vec4 color = renderSolid(); + color.a = varVertexColor.a; + return color; +} + +vec4 renderTransparentAlphaChannel(void) +{ + vec4 texel = texture2D(uTextureUnit0, varTexCoord[0].xy); + vec4 color = texel * varVertexColor; + color.a = texel.a; + return color; +} + +vec4 render2LayerSolid(void) +{ + float blendFactor = varVertexColor.a; + vec4 texel0 = texture2D(uTextureUnit0, varTexCoord[0].xy); + vec4 texel1 = texture2D(uTextureUnit1, varTexCoord[1].xy); + vec4 color = texel0 * blendFactor + texel1 * ( 1.0 - blendFactor ); + return color; +} + +vec4 renderLightMap(void) +{ + vec4 texel0 = texture2D(uTextureUnit0, varTexCoord[0].xy); + vec4 texel1 = texture2D(uTextureUnit1, varTexCoord[1].xy); + vec4 color = texel0 * texel1 * 4.0; + color.a = texel0.a * texel0.a; + return color; +} + +vec4 renderDetailMap(void) +{ + vec4 texel0 = texture2D(uTextureUnit0, varTexCoord[0].xy); + vec4 texel1 = texture2D(uTextureUnit1, varTexCoord[1].xy); + vec4 color = texel0; + color += texel1 - 0.5; + return color; +} + +vec4 renderReflection2Layer(void) +{ + vec4 color = varVertexColor; + vec4 texel0 = texture2D(uTextureUnit0, varTexCoord[0].xy); + vec4 texel1 = texture2D(uTextureUnit1, varTexCoord[1].xy); + color *= texel0 * texel1; + return color; +} + +float ComputeFog() +{ + float factor = 1.0; + if(uFogType == FOG_LINEAR) + { + factor = (uFogEnd - eyeDist) / (uFogEnd - uFogStart); + } + else if(uFogType == FOG_EXP) + { + factor = exp(-(eyeDist * uFogDensity)); + } + else //uFogType == FOG_EXP2 + { + factor = eyeDist * uFogDensity; + factor = exp(-(factor * factor)) ; + } + factor = clamp(factor, 0.0, 1.0); + return factor; +} + +void main (void) +{ + if(varClipDist < 0.0) + discard; + + if( uRenderMode == TwoD) + gl_FragColor = render2D(); + else if( uRenderMode == Solid) + gl_FragColor = renderSolid(); + else if(uRenderMode == LightMap) + gl_FragColor = renderLightMap(); + else if(uRenderMode == DetailMap) + gl_FragColor = renderDetailMap(); + else if(uRenderMode == SphereMap) + gl_FragColor = renderSolid(); + else if(uRenderMode == Reflection2Layer) + gl_FragColor = renderReflection2Layer(); + else if(uRenderMode == TransparentVertexAlpha) + gl_FragColor = renderTransparentVertexAlpha(); + else if(uRenderMode == TransparentAlphaChannel) + gl_FragColor = renderTransparentAlphaChannel(); + else + gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0); + + //gl_FragColor = varVertexColor; + + if(uFog) + { + float fogFactor = ComputeFog(); + gl_FragColor = gl_FragColor * fogFactor + uFogColor * (1.0 - fogFactor); + } + + if(uAlphaTest && uAlphaValue > gl_FragColor.a) + discard; + +} diff --git a/media/Shaders/COGLES2FixedPipeline.vsh b/media/Shaders/COGLES2FixedPipeline.vsh new file mode 100644 index 00000000..42b48518 --- /dev/null +++ b/media/Shaders/COGLES2FixedPipeline.vsh @@ -0,0 +1,245 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#define MAX_TEXTURE_UNITS 4 +#define MAX_LIGHTS 8 + +#define SphereMap 10 +#define Reflection2Layer 11 + +const vec4 red = vec4(1.0, 0.0, 0.0, 1.0); +const vec4 green = vec4(0.0, 1.0, 0.0, 1.0); +const vec4 blue = vec4(0.0, 0.0, 1.0, 1.0); +const vec4 white = vec4(1.0); +const vec4 black = vec4(0.0); + +/* Vertex Attributes */ + +attribute vec4 inVertexPosition; +attribute vec4 inVertexColor; +attribute vec4 inTexCoord0; +attribute vec4 inTexCoord1; +attribute vec3 inVertexNormal; + +uniform int uRenderMode; + +/* Matrix Uniforms */ + +uniform mat4 uMvpMatrix; +uniform mat4 uWorldMatrix; + +uniform bool uNormalize; +uniform vec3 uEyePos; + +/* Light Uniforms */ + +uniform bool uUseLight [MAX_LIGHTS]; +uniform vec4 uLightPosition [MAX_LIGHTS]; +uniform vec4 uLightAmbient [MAX_LIGHTS]; +uniform vec4 uLightDiffuse [MAX_LIGHTS]; +#ifdef USE_SPECULAR +uniform vec4 uLightSpecular [MAX_LIGHTS]; +#endif +#ifdef USE_LIGHT_CUTOFF +uniform vec3 uLightDirection [MAX_LIGHTS]; +uniform float uLightCutoff [MAX_LIGHTS]; +uniform float uLightExponent [MAX_LIGHTS]; +#endif +uniform vec3 uLightAttenuation [MAX_LIGHTS]; +uniform vec4 uAmbientColor; +uniform bool uLighting; + +/* Material Uniforms */ +uniform vec4 uMaterialAmbient; +uniform vec4 uMaterialEmission; +uniform vec4 uMaterialDiffuse; +uniform vec4 uMaterialSpecular; +uniform float uMaterialShininess; +uniform int uColorMaterial; + +#define ECM_NONE 0 +#define ECM_DIFFUSE 1 +#define ECM_AMBIENT 2 +#define ECM_EMISSIVE 3 +#define ECM_SPECULAR 4 +#define ECM_DIFFUSE_AND_AMBIENT 5 + +/* Texture Uniforms */ +uniform bool uUseTexture [MAX_TEXTURE_UNITS]; +uniform mat4 uTextureMatrix [MAX_TEXTURE_UNITS]; +uniform bool uUseTexMatrix [MAX_TEXTURE_UNITS]; + +/* Clip Plane Uniforms */ +uniform bool uClip; +uniform vec4 uClipPlane; +varying float varClipDist; + +/* Varyings */ + +varying vec4 varTexCoord[MAX_TEXTURE_UNITS]; +varying vec4 varVertexColor; +varying float eyeDist; + +/* shader variables */ + +vec3 gNormal; +vec3 gWorldPos; +vec4 gColor; + +struct material { + vec4 Ambient; + vec4 Diffuse; + vec4 Specular; + vec4 Emission; + float Shininess; +} ; + +material gMaterial; + +vec4 lightEquation(int lidx) +{ + vec4 color = vec4(0.0); + + float att = 1.0; + vec3 lightDir; + + + if( uLightPosition[lidx].w == 0.0) // Directional light + { + lightDir = -uLightPosition[lidx].xyz; + } + else + { + lightDir = uLightPosition[lidx].xyz - inVertexPosition.xyz; + att = 1.0 / (uLightAttenuation[lidx].y * length(lightDir)); + lightDir = normalize(lightDir); + +#ifdef USE_LIGHT_CUTOFF + if(uLightCutoff[lidx] < 180.0) + { + // compute spot factor + float spotEffect = dot(-lightDir, uLightDirection[lidx]); + if( spotEffect >= cos( radians( uLightCutoff[lidx]))) + spotEffect = pow( spotEffect, uLightExponent[lidx]); + else + spotEffect = 0.0; + att *= spotEffect; + } +#endif + } + + if(att >= 0.0 ) + { + color += uLightAmbient[lidx] * gMaterial.Ambient; + + //Compute cos(Light, Normal) + float NdotL = max(dot(normalize(gNormal), lightDir), 0.0); + color += NdotL * uLightDiffuse[lidx] * gMaterial.Diffuse; + + //Compute cos(hvec, Normal) +#ifdef USE_SPECULAR + vec3 hvec = normalize(lightDir + vec3(0.0, 0.0, 1.0)); + float NdotH = dot(gNormal, hvec); + if(NdotH > 0.0) + { + color += pow(NdotH, uMaterialShininess) * uLightSpecular[lidx] * gMaterial.Specular; + } +#endif + color *= att; + } + return color; +} + +vec4 computeLighting(void) +{ + vec4 color = gMaterial.Emission + gMaterial.Ambient * uAmbientColor; + + for ( int i = 0 ; i < MAX_LIGHTS; ++i) + { + if ( uUseLight[i] ) + { + color += lightEquation(i) ; + } + } + color.a = gMaterial.Diffuse.a; + return color; +} + +void ReplaceColorMaterial(void) +{ + gMaterial.Ambient = uMaterialAmbient; + gMaterial.Diffuse = uMaterialDiffuse; + gMaterial.Emission = uMaterialEmission; + gMaterial.Specular = uMaterialSpecular; + gMaterial.Shininess = uMaterialShininess; + + if(uColorMaterial == ECM_DIFFUSE) + gMaterial.Diffuse = gColor; + else if(uColorMaterial == ECM_AMBIENT) + gMaterial.Ambient = gColor; + else if(uColorMaterial == ECM_DIFFUSE_AND_AMBIENT) + { + gMaterial.Diffuse = gColor; + gMaterial.Ambient = gColor; + } + else if(uColorMaterial == ECM_EMISSIVE) + gMaterial.Emission = gColor; + else if(uColorMaterial == ECM_SPECULAR) + gMaterial.Specular = gColor; +} + +void main(void) +{ + gl_Position = uMvpMatrix * inVertexPosition; + + gWorldPos = (uWorldMatrix * inVertexPosition).xyz; + + gColor = inVertexColor.bgra; + + gNormal = inVertexNormal.xyz; + if(uNormalize) + gNormal = normalize(gNormal); + + ReplaceColorMaterial(); + if(uLighting) + varVertexColor = computeLighting(); + else + varVertexColor = gColor; + + for(int i = 0; i < MAX_TEXTURE_UNITS; ++i) + varTexCoord[i] = vec4(0.0); + + if( uUseTexture[0]) + { + if(uRenderMode == SphereMap || uRenderMode == Reflection2Layer) + { + vec3 eyeDir = normalize(inVertexPosition.xyz - uEyePos); + vec3 reflection = reflect(eyeDir, gNormal); + float m = 2.0 * sqrt(reflection.x * reflection.x + + reflection.y * reflection.y + + (reflection.z + 1.0) * (reflection.z + 1.0)); + varTexCoord[0] = vec4((reflection.x / m + 0.5), (reflection.y / m + 0.5), 0.0, 0.0); + } + else + { + varTexCoord[0] = inTexCoord0; + if(uUseTexMatrix[0]) + varTexCoord[0] *= uTextureMatrix[0]; + } + } + if(uUseTexture[1]) + { + varTexCoord[1] = inTexCoord1; + if(uUseTexMatrix[1]) + varTexCoord[1] *= uTextureMatrix[1]; + } + + eyeDist = length(uEyePos); + + varClipDist = uClip ? dot(gWorldPos, uClipPlane.xyz)-uClipPlane.w : 0.0; + + varVertexColor.rgb = clamp(varVertexColor.rgb, 0.0, 1.0); + varVertexColor.a = gColor.a; +} diff --git a/media/Shaders/COGLES2NormalMap.fsh b/media/Shaders/COGLES2NormalMap.fsh new file mode 100644 index 00000000..5b2374a2 --- /dev/null +++ b/media/Shaders/COGLES2NormalMap.fsh @@ -0,0 +1,36 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#define MAX_LIGHTS 2 + +precision mediump float; + +uniform sampler2D texture0; +uniform sampler2D texture1; + +varying vec4 varTexCoord; +varying vec3 varLightVector[MAX_LIGHTS]; +varying vec4 varLightColor[MAX_LIGHTS]; + +varying vec4 debug; + +void main(void) +{ + // fetch color and normal map + vec4 normalMap = texture2D(texture1, varTexCoord.xy) * 2.0 - 1.0; + vec4 colorMap = texture2D(texture0, varTexCoord.xy); + + // calculate color of light 0 + vec4 color = clamp(varLightColor[0], 0.0, 1.0) * dot(normalMap.xyz, normalize(varLightVector[0].xyz)); + + // calculate color of light 1 + color += clamp(varLightColor[1], 0.0, 1.0) * dot(normalMap.xyz, normalize(varLightVector[1].xyz)); + + //luminance * base color + color *= colorMap; + color.a = varLightColor[0].a; + + gl_FragColor = color; +} \ No newline at end of file diff --git a/media/Shaders/COGLES2NormalMap.vsh b/media/Shaders/COGLES2NormalMap.vsh new file mode 100644 index 00000000..8afa09da --- /dev/null +++ b/media/Shaders/COGLES2NormalMap.vsh @@ -0,0 +1,69 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#define MAX_LIGHTS 2 + +attribute vec4 inVertexPosition; +attribute vec4 inVertexColor; +attribute vec4 inTexCoord0; +attribute vec3 inVertexNormal; +attribute vec3 inVertexTangent; +attribute vec3 inVertexBinormal; + +uniform mat4 uMvpMatrix; +uniform vec4 uLightPos[MAX_LIGHTS]; +uniform vec4 uLightColor[MAX_LIGHTS]; + +varying vec4 varTexCoord; +varying vec3 varLightVector[MAX_LIGHTS]; +varying vec4 varLightColor[MAX_LIGHTS]; + +varying vec4 debug; + +void main(void) +{ + debug = vec4(inVertexNormal, 1.0); + // transform position to clip space + gl_Position = uMvpMatrix * inVertexPosition; + + // vertex - lightpositions + vec4 tempLightVector0 = uLightPos[0] - inVertexPosition; + vec4 tempLightVector1 = uLightPos[1] - inVertexPosition; + + // transform the light vector 1 with U, V, W + varLightVector[0].x = dot(inVertexTangent, tempLightVector0.xyz); + varLightVector[0].y = dot(inVertexBinormal, tempLightVector0.xyz); + varLightVector[0].z = dot(inVertexNormal, tempLightVector0.xyz); + + + // transform the light vector 2 with U, V, W + varLightVector[1].x = dot(inVertexTangent, tempLightVector1.xyz); + varLightVector[1].y = dot(inVertexBinormal, tempLightVector1.xyz); + varLightVector[1].z = dot(inVertexNormal, tempLightVector1.xyz); + + // calculate attenuation of light 0 + varLightColor[0].w = 0.0; + varLightColor[0].x = dot(tempLightVector0, tempLightVector0); + varLightColor[0].x *= uLightColor[0].w; + varLightColor[0] = vec4(inversesqrt(varLightColor[0].x)); + varLightColor[0] *= uLightColor[0]; + + // normalize light vector 0 + varLightVector[0] = normalize(varLightVector[0]); + + // calculate attenuation of light 1 + varLightColor[1].w = 0.0; + varLightColor[1].x = dot(tempLightVector1, tempLightVector1); + varLightColor[1].x *= uLightColor[1].w; + varLightColor[1] = vec4(inversesqrt(varLightColor[1].x)); + varLightColor[1] *= uLightColor[1]; + + // normalize light vector 1 + varLightVector[1] = normalize(varLightVector[1]); + + // move out texture coordinates and original alpha value + varTexCoord = inTexCoord0; + varLightColor[0].a = inVertexColor.a; +} \ No newline at end of file diff --git a/media/Shaders/COGLES2ParallaxMap.fsh b/media/Shaders/COGLES2ParallaxMap.fsh new file mode 100644 index 00000000..40294e3f --- /dev/null +++ b/media/Shaders/COGLES2ParallaxMap.fsh @@ -0,0 +1,49 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#define MAX_LIGHTS 2 + +precision mediump float; + +uniform sampler2D texture0; +uniform sampler2D texture1; + +//uniform vec4 uLightDiffuse[MAX_LIGHTS]; +uniform float uHeightScale; + +varying vec4 varTexCoord; +varying vec3 varLightVector[MAX_LIGHTS]; +varying vec4 varLightColor[MAX_LIGHTS]; +varying vec3 varEyeVector; + +varying vec4 debug; + +void main(void) +{ + // fetch color and normal map + vec4 normalMap = texture2D(texture1, varTexCoord.xy) * 2.0 - 1.0; + + // height = height * scale + normalMap *= uHeightScale; + + // calculate new texture coord: height * eye + oldTexCoord + vec2 offset = varEyeVector.xy * normalMap.w + varTexCoord.xy; + + // fetch new textures + vec4 colorMap = texture2D(texture0, offset); + normalMap = normalize(texture2D(texture1, offset) * 2.0 - 1.0); + + // calculate color of light 0 + vec4 color = clamp(varLightColor[0], 0.0, 1.0) * dot(normalMap.xyz, normalize(varLightVector[0].xyz)); + + // calculate color of light 1 + color += clamp(varLightColor[1], 0.0, 1.0) * dot(normalMap.xyz, normalize(varLightVector[1].xyz)); + + //luminance * base color + color *= colorMap; + color.a = varLightColor[0].a; + + gl_FragColor = color; +} diff --git a/media/Shaders/COGLES2ParallaxMap.vsh b/media/Shaders/COGLES2ParallaxMap.vsh new file mode 100644 index 00000000..eefc6c3b --- /dev/null +++ b/media/Shaders/COGLES2ParallaxMap.vsh @@ -0,0 +1,81 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#define MAX_LIGHTS 2 + +attribute vec4 inVertexPosition; +attribute vec4 inVertexColor; +attribute vec4 inTexCoord0; +attribute vec3 inVertexNormal; +attribute vec3 inVertexTangent; +attribute vec3 inVertexBinormal; + +uniform mat4 uMvpMatrix; +uniform vec4 uLightPos[MAX_LIGHTS]; +uniform vec4 uLightColor[MAX_LIGHTS]; +uniform vec3 uEyePos; + +varying vec4 varTexCoord; +varying vec3 varLightVector[MAX_LIGHTS]; +varying vec4 varLightColor[MAX_LIGHTS]; +varying vec3 varEyeVector; + +varying vec4 debug; + +void main(void) +{ + debug = vec4(inVertexNormal, 1.0); + // transform position to clip space + gl_Position = uMvpMatrix * inVertexPosition; + + // vertex - lightpositions + vec4 tempLightVector0 = uLightPos[0] - inVertexPosition; + vec4 tempLightVector1 = uLightPos[1] - inVertexPosition; + + // eye vector + vec4 Temp = vec4(uEyePos, 1.0) - inVertexPosition; + + // transform the light vector 1 with U, V, W + varLightVector[0].x = dot(inVertexTangent, tempLightVector0.xyz); + varLightVector[0].y = dot(inVertexBinormal, tempLightVector0.xyz); + varLightVector[0].z = dot(inVertexNormal, tempLightVector0.xyz); + + + // transform the light vector 2 with U, V, W + varLightVector[1].x = dot(inVertexTangent, tempLightVector1.xyz); + varLightVector[1].y = dot(inVertexBinormal, tempLightVector1.xyz); + varLightVector[1].z = dot(inVertexNormal, tempLightVector1.xyz); + + // transform the eye vector with U, V, W + varEyeVector.x = dot(inVertexTangent, Temp.xyz); + varEyeVector.y = dot(inVertexBinormal, Temp.xyz); + varEyeVector.z = dot(inVertexNormal, Temp.xyz); + varEyeVector *= vec3(1.0,-1.0, -1.0); + varEyeVector = normalize(varEyeVector); + + // calculate attenuation of light 0 + varLightColor[0].w = 0.0; + varLightColor[0].x = dot(tempLightVector0, tempLightVector0); + varLightColor[0].x *= uLightColor[0].w; + varLightColor[0] = vec4(inversesqrt(varLightColor[0].x)); + varLightColor[0] *= uLightColor[0]; + + // normalize light vector 0 + varLightVector[0] = normalize(varLightVector[0]); + + // calculate attenuation of light 1 + varLightColor[1].w = 0.0; + varLightColor[1].x = dot(tempLightVector1, tempLightVector1); + varLightColor[1].x *= uLightColor[1].w; + varLightColor[1] = vec4(inversesqrt(varLightColor[1].x)); + varLightColor[1] *= uLightColor[1]; + + // normalize light vector 1 + varLightVector[1] = normalize(varLightVector[1]); + + // move out texture coordinates and original alpha value + varTexCoord = inTexCoord0; + varLightColor[0].a = inVertexColor.a; +} \ No newline at end of file diff --git a/media/Shaders/COGLES2Renderer2D.fsh b/media/Shaders/COGLES2Renderer2D.fsh new file mode 100644 index 00000000..11a10689 --- /dev/null +++ b/media/Shaders/COGLES2Renderer2D.fsh @@ -0,0 +1,29 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +precision mediump float; + +uniform bool uUseTexture; +uniform sampler2D uTextureUnit; +uniform bool uAlphaTest; +uniform float uAlphaValue; + +varying vec4 varVertexColor; +varying vec4 varTexCoord; + +void main(void) +{ + vec4 color = varVertexColor; + vec4 texel = texture2D(uTextureUnit, varTexCoord.xy); + if(uUseTexture) + { + color *= texel; + } + + if(uAlphaTest && !(color.a > uAlphaValue)) + discard; + + gl_FragColor = color; +} diff --git a/media/Shaders/COGLES2Renderer2D.vsh b/media/Shaders/COGLES2Renderer2D.vsh new file mode 100644 index 00000000..d1bab525 --- /dev/null +++ b/media/Shaders/COGLES2Renderer2D.vsh @@ -0,0 +1,20 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +attribute vec4 inVertexPosition; +attribute vec4 inVertexColor; +attribute vec4 inTexCoord0; + +uniform mat4 uOrthoMatrix; + +varying vec4 varVertexColor; +varying vec4 varTexCoord; + +void main(void) +{ + gl_Position = uOrthoMatrix * inVertexPosition; + varVertexColor = inVertexColor.bgra; + varTexCoord = inTexCoord0; +} diff --git a/source/Irrlicht/CIrrDeviceWin32.cpp b/source/Irrlicht/CIrrDeviceWin32.cpp index 0054c0c5..9878ae61 100644 --- a/source/Irrlicht/CIrrDeviceWin32.cpp +++ b/source/Irrlicht/CIrrDeviceWin32.cpp @@ -43,6 +43,10 @@ namespace irr #ifdef _IRR_COMPILE_WITH_OGLES1_ IVideoDriver* createOGLES1Driver(const SIrrlichtCreationParameters& params, video::SExposedVideoData& data, io::IFileSystem* io); #endif + + #ifdef _IRR_COMPILE_WITH_OGLES2_ + IVideoDriver* createOGLES2Driver(const SIrrlichtCreationParameters& params, video::SExposedVideoData& data, io::IFileSystem* io); + #endif } } // end namespace irr @@ -737,6 +741,25 @@ void CIrrDeviceWin32::createDriver() #endif break; + case video::EDT_OGLES2: + #ifdef _IRR_COMPILE_WITH_OGLES2_ + { + video::SExposedVideoData data; + data.OpenGLWin32.HWnd=HWnd; + + switchToFullScreen(); + + VideoDriver = video::createOGLES2Driver(CreationParams, data, FileSystem); + if (!VideoDriver) + { + os::Printer::log("Could not create OpenGL-ES2 driver.", ELL_ERROR); + } + } + #else + os::Printer::log("OpenGL-ES2 driver was not compiled in.", ELL_ERROR); + #endif + break; + case video::EDT_SOFTWARE: #ifdef _IRR_COMPILE_WITH_SOFTWARE_ diff --git a/source/Irrlicht/CNullDriver.cpp b/source/Irrlicht/CNullDriver.cpp index 1455c3c0..96dd322e 100644 --- a/source/Irrlicht/CNullDriver.cpp +++ b/source/Irrlicht/CNullDriver.cpp @@ -2239,7 +2239,7 @@ s32 CNullDriver::addShaderMaterialFromFiles(const io::path& vertexShaderProgramF //! Creates a render target texture. ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d& size, - const io::path&name, const ECOLOR_FORMAT format) + const io::path& name, const ECOLOR_FORMAT format) { return 0; } diff --git a/source/Irrlicht/COGLES2Driver.cpp b/source/Irrlicht/COGLES2Driver.cpp new file mode 100644 index 00000000..08f77a77 --- /dev/null +++ b/source/Irrlicht/COGLES2Driver.cpp @@ -0,0 +1,2709 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#include "COGLES2Driver.h" +// needed here also because of the create methods' parameters +#include "CNullDriver.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "COGLES2Texture.h" +#include "COGLES2MaterialRenderer.h" +#include "COGLES2NormalMapRenderer.h" +#include "COGLES2ParallaxMapRenderer.h" +#include "COGLES2Renderer2D.h" +#include "CImage.h" +#include "os.h" + +#include +#include + +#ifndef GL_BGRA +// we need to do this for the IMG_BGRA8888 extension +int GL_BGRA = GL_RGBA; +#endif + +namespace irr +{ + namespace video + { + +//! constructor and init code + COGLES2Driver::COGLES2Driver( const SIrrlichtCreationParameters& params, + const SExposedVideoData& data, io::IFileSystem* io +#if defined(_IRR_COMPILE_WITH_IPHONE_DEVICE_) + , const MIrrIPhoneDevice& device +#endif + ) + : CNullDriver( io, params.WindowSize ), COGLES2ExtensionHandler(), + CurrentRenderMode( ERM_NONE ), ResetRenderStates( true ), + Transformation3DChanged( true ), AntiAlias( params.AntiAlias ), + RenderTargetTexture( 0 ), CurrentRendertargetSize( 0, 0 ), ColorFormat( ECF_R8G8B8 ), + EglDisplay( EGL_NO_DISPLAY ) +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) + , HDc( 0 ) +#elif defined(_IRR_COMPILE_WITH_IPHONE_DEVICE_) + , ViewFramebuffer( 0 ) + , ViewRenderbuffer( 0 ) + , ViewDepthRenderbuffer( 0 ) +#endif + , NoHighLevelShader( true ) + , BlendEnabled( false ) + , SourceFactor( EBF_ZERO ) + , DestFactor( EBF_ZERO ) + { +#ifdef _DEBUG + setDebugName( "COGLES2Driver" ); +#endif + ExposedData = data; +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) + EglWindow = ( NativeWindowType )data.OpenGLWin32.HWnd; + HDc = GetDC(( HWND )EglWindow ); + EglDisplay = eglGetDisplay(( NativeDisplayType )HDc ); +#elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) + EglWindow = ( NativeWindowType )ExposedData.OpenGLLinux.X11Window; + EglDisplay = eglGetDisplay(( NativeDisplayType )ExposedData.OpenGLLinux.X11Display ); +#elif defined(_IRR_COMPILE_WITH_IPHONE_DEVICE_) + Device = device; +#endif + if ( EglDisplay == EGL_NO_DISPLAY ) + { + os::Printer::log( "Getting OpenGL-ES2 display." ); + EglDisplay = eglGetDisplay(( NativeDisplayType ) EGL_DEFAULT_DISPLAY ); + } + if ( EglDisplay == EGL_NO_DISPLAY ) + { + os::Printer::log( "Could not get OpenGL-ES2 display." ); + } + + EGLint majorVersion, minorVersion; + if ( !eglInitialize( EglDisplay, &majorVersion, &minorVersion ) ) + { + os::Printer::log( "Could not initialize OpenGL-ES2 display." ); + } + else + { + char text[64]; + sprintf( text, "EglDisplay initialized. Egl version %d.%d\n", majorVersion, minorVersion ); + os::Printer::log( text ); + } + + EGLint attribs[] = + { + EGL_RED_SIZE, 5, + EGL_GREEN_SIZE, 5, + EGL_BLUE_SIZE, 5, + EGL_ALPHA_SIZE, params.WithAlphaChannel ? 1 : 0, + EGL_BUFFER_SIZE, 16,//params.Bits, + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + //EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, + EGL_DEPTH_SIZE, params.ZBufferBits, + EGL_STENCIL_SIZE, params.Stencilbuffer, + EGL_SAMPLE_BUFFERS, params.AntiAlias ? 1 : 0, + EGL_SAMPLES, params.AntiAlias, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE, 0 + }; + /*EGLint attribs[] = + { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_NONE, 0 + };*/ + + EGLint contextAttrib[] = + { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE, 0 + }; + + + EGLConfig config; + EGLint num_configs; + if ( !eglChooseConfig( EglDisplay, attribs, &config, 1, &num_configs ) ) + { + os::Printer::log( "Could not get config for OpenGL-ES2 display." ); + } + else + { + char log[64]; + snprintf( log, 64, "Got %d configs.\n", num_configs ); + os::Printer::log( log ); + } + os::Printer::log( " Creating EglSurface with nativeWindow..." ); + EglSurface = eglCreateWindowSurface( EglDisplay, config, EglWindow, NULL ); + if ( EGL_NO_SURFACE == EglSurface ) + { + os::Printer::log( "FAILED\n" ); + EglSurface = eglCreateWindowSurface( EglDisplay, config, NULL, NULL ); + os::Printer::log( "Creating EglSurface without nativeWindows..." ); + } + else + os::Printer::log( "SUCCESS\n" ); + if ( EGL_NO_SURFACE == EglSurface ) + { + os::Printer::log( "FAILED\n" ); + os::Printer::log( "Could not create surface for OpenGL-ES2 display." ); + } + else + os::Printer::log( "SUCCESS\n" ); + +#ifdef EGL_VERSION_1_2 + eglBindAPI( EGL_OPENGL_ES_API ); +#endif + os::Printer::log( "Creating EglContext..." ); + EglContext = eglCreateContext( EglDisplay, config, EGL_NO_CONTEXT, contextAttrib ); + if ( testEGLError() ) + { + os::Printer::log( "FAILED\n" ); + os::Printer::log( "Could not create Context for OpenGL-ES2 display." ); + } + + eglMakeCurrent( EglDisplay, EglSurface, EglSurface, EglContext ); + if ( testEGLError() ) + { + os::Printer::log( "Could not make Context current for OpenGL-ES2 display." ); + } + + genericDriverInit( params.WindowSize, params.Stencilbuffer ); + + // set vsync + if ( params.Vsync ) + eglSwapInterval( EglDisplay, 1 ); + } + + +//! destructor + COGLES2Driver::~COGLES2Driver() + { + deleteMaterialRenders(); + deleteAllTextures(); + + // HACK : the following is commented because destroying the context crashes under Linux ( Thibault 04-feb-10 ) + /*eglMakeCurrent( EGL_NO_DISPLAY, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT ); + eglDestroyContext( EglDisplay, EglContext ); + eglDestroySurface( EglDisplay, EglSurface );*/ + eglTerminate( EglDisplay ); + +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) + if ( HDc ) + ReleaseDC(( HWND )EglWindow, HDc ); +#endif + + delete TwoDRenderer; + delete FixedPipeline; + } + +// ----------------------------------------------------------------------- +// METHODS +// ----------------------------------------------------------------------- + + bool COGLES2Driver::genericDriverInit( const core::dimension2d& screenSize, bool stencilBuffer ) + { + Name = glGetString( GL_VERSION ); + printVersion(); + + os::Printer::log( eglQueryString( EglDisplay, EGL_CLIENT_APIS ) ); + + // print renderer information + vendorName = glGetString( GL_VENDOR ); + os::Printer::log( vendorName.c_str(), ELL_INFORMATION ); + + u32 i; + for ( i = 0; i < MATERIAL_MAX_TEXTURES; ++i ) + CurrentTexture[i] = 0; + // load extensions + initExtensions( this, + EglDisplay, + stencilBuffer ); + + StencilBuffer = stencilBuffer; + + FixedPipeline = new COGLES2FixedPipelineShader( this, FileSystem ); + FixedPipeline->useProgram(); //For setting the default uniforms (Alpha) + + TwoDRenderer = new COGLES2Renderer2d( this, FileSystem ); + + glPixelStorei( GL_PACK_ALIGNMENT, 2 ); + + // Reset The Current Viewport + glViewport( 0, 0, screenSize.Width, screenSize.Height ); + + setAmbientLight( SColorf( 0.0f, 0.0f, 0.0f, 0.0f ) ); +#ifdef GL_separate_specular_color + if ( FeatureAvailable[IRR_separate_specular_color] ) + glLightModeli( GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR ); +#endif + glClearDepthf( 1.0f ); + + //TODO : OpenGL ES 2.0 Port : GL_PERSPECTIVE_CORRECTION_HINT + //glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); + glHint( GL_GENERATE_MIPMAP_HINT, GL_FASTEST ); + glDepthFunc( GL_LEQUAL ); + glFrontFace( GL_CW ); + + UserClipPlane.reallocate( 0 ); + + // create material renderers + createMaterialRenderers(); + + // set the renderstates + setRenderStates3DMode(); + + // set fog mode + setFog( FogColor, FogType, FogStart, FogEnd, FogDensity, PixelFog, RangeFog ); + + // create matrix for flipping textures + TextureFlipMatrix.buildTextureTransform( 0.0f, core::vector2df( 0, 0 ), core::vector2df( 0, 1.0f ), core::vector2df( 1.0f, -1.0f ) ); + + // We need to reset once more at the beginning of the first rendering. + // This fixes problems with intermediate changes to the material during texture load. + ResetRenderStates = true; + + glUseProgram( 0 ); + testGLError(); + + return true; + } + + + void COGLES2Driver::createMaterialRenderers() + { + // create OGLES1 material renderers + + addAndDropMaterialRenderer( new COGLES2MaterialRenderer_SOLID( this ) ); + addAndDropMaterialRenderer( new COGLES2MaterialRenderer_SOLID_2_LAYER( this ) ); + + // add the same renderer for all lightmap types + COGLES2MaterialRenderer_LIGHTMAP* lmr = new COGLES2MaterialRenderer_LIGHTMAP( this ); + addMaterialRenderer( lmr ); // for EMT_LIGHTMAP: + addMaterialRenderer( lmr ); // for EMT_LIGHTMAP_ADD: + addMaterialRenderer( lmr ); // for EMT_LIGHTMAP_M2: + addMaterialRenderer( lmr ); // for EMT_LIGHTMAP_M4: + addMaterialRenderer( lmr ); // for EMT_LIGHTMAP_LIGHTING: + addMaterialRenderer( lmr ); // for EMT_LIGHTMAP_LIGHTING_M2: + addMaterialRenderer( lmr ); // for EMT_LIGHTMAP_LIGHTING_M4: + lmr->drop(); + + // add remaining material renderer + addAndDropMaterialRenderer( new COGLES2MaterialRenderer_DETAIL_MAP( this ) ); + addAndDropMaterialRenderer( new COGLES2MaterialRenderer_SPHERE_MAP( this ) ); + addAndDropMaterialRenderer( new COGLES2MaterialRenderer_REFLECTION_2_LAYER( this ) ); + addAndDropMaterialRenderer( new COGLES2MaterialRenderer_TRANSPARENT_ADD_COLOR( this ) ); + addAndDropMaterialRenderer( new COGLES2MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL( this ) ); + addAndDropMaterialRenderer( new COGLES2MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF( this ) ); + addAndDropMaterialRenderer( new COGLES2MaterialRenderer_TRANSPARENT_VERTEX_ALPHA( this ) ); + addAndDropMaterialRenderer( new COGLES2MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER( this ) ); + + // add normal map renderers + s32 tmp = 0; + video::IMaterialRenderer* renderer = 0; + renderer = new COGLES2NormalMapRenderer( this, FileSystem, tmp, MaterialRenderers[EMT_SOLID].Renderer ); + renderer->drop(); + renderer = new COGLES2NormalMapRenderer( this, FileSystem, tmp, MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer ); + renderer->drop(); + renderer = new COGLES2NormalMapRenderer( this, FileSystem, tmp, MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer ); + renderer->drop(); + + // add parallax map renderers + renderer = new COGLES2ParallaxMapRenderer( this, FileSystem, tmp, MaterialRenderers[EMT_SOLID].Renderer ); + renderer->drop(); + renderer = new COGLES2ParallaxMapRenderer( this, FileSystem, tmp, MaterialRenderers[EMT_TRANSPARENT_ADD_COLOR].Renderer ); + renderer->drop(); + renderer = new COGLES2ParallaxMapRenderer( this, FileSystem, tmp, MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer ); + renderer->drop(); + + // add basic 1 texture blending + addAndDropMaterialRenderer( new COGLES2MaterialRenderer_ONETEXTURE_BLEND( this ) ); + } + + +//! presents the rendered scene on the screen, returns false if failed + bool COGLES2Driver::endScene() + { + CNullDriver::endScene(); + + eglSwapBuffers( EglDisplay, EglSurface ); + EGLint g = eglGetError(); + if ( EGL_SUCCESS != g ) + { + if ( EGL_CONTEXT_LOST == g ) + { + // o-oh, ogl-es has lost contexts... + os::Printer::log( "Context lost, please restart your app." ); + } + else + os::Printer::log( "Could not swap buffers for OpenGL-ES2 driver." ); + return false; + } + return true; + } + + +//! clears the zbuffer + bool COGLES2Driver::beginScene( bool backBuffer, bool zBuffer, SColor color, + const SExposedVideoData& videoData, core::rect* sourceRect ) + { + CNullDriver::beginScene( backBuffer, zBuffer, color ); + + GLbitfield mask = 0; + + if ( backBuffer ) + { + const f32 inv = 1.0f / 255.0f; + glClearColor( color.getRed() * inv, color.getGreen() * inv, + color.getBlue() * inv, color.getAlpha() * inv ); + + mask |= GL_COLOR_BUFFER_BIT; + } + + if ( zBuffer ) + { + glDepthMask( GL_TRUE ); + LastMaterial.ZWriteEnable = true; + mask |= GL_DEPTH_BUFFER_BIT; + } + + glClear( mask ); + testGLError(); + return true; + } + + +//! Returns the transformation set by setTransform + const core::matrix4& COGLES2Driver::getTransform( E_TRANSFORMATION_STATE state ) const + { + return Matrices[state]; + } + + +//! sets transformation + void COGLES2Driver::setTransform( E_TRANSFORMATION_STATE state, const core::matrix4& mat ) + { + Matrices[state] = mat; + Transformation3DChanged = true; + } + + bool COGLES2Driver::updateVertexHardwareBuffer( SHWBufferLink_opengl *HWBuffer ) + { + if ( !HWBuffer ) + return false; + + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + const void* vertices = mb->getVertices(); + const u32 vertexCount = mb->getVertexCount(); + const E_VERTEX_TYPE vType = mb->getVertexType(); + const u32 vertexSize = getVertexPitchFromType( vType ); + + //buffer vertex data, and convert colours... + core::array buffer( vertexSize * vertexCount ); + memcpy( buffer.pointer(), vertices, vertexSize * vertexCount ); + + //get or create buffer + bool newBuffer = false; + if ( !HWBuffer->vbo_verticesID ) + { + glGenBuffers( 1, &HWBuffer->vbo_verticesID ); + if ( !HWBuffer->vbo_verticesID ) return false; + newBuffer = true; + } + else if ( HWBuffer->vbo_verticesSize < vertexCount*vertexSize ) + { + newBuffer = true; + } + + glBindBuffer( GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID ); + + //copy data to graphics card + glGetError(); // clear error storage + if ( !newBuffer ) + glBufferSubData( GL_ARRAY_BUFFER, 0, vertexCount * vertexSize, buffer.const_pointer() ); + else + { + HWBuffer->vbo_verticesSize = vertexCount * vertexSize; + + if ( HWBuffer->Mapped_Vertex == scene::EHM_STATIC ) + glBufferData( GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_STATIC_DRAW ); + else + glBufferData( GL_ARRAY_BUFFER, vertexCount * vertexSize, buffer.const_pointer(), GL_DYNAMIC_DRAW ); + } + + glBindBuffer( GL_ARRAY_BUFFER, 0 ); + + return ( glGetError() == GL_NO_ERROR ); + } + + + bool COGLES2Driver::updateIndexHardwareBuffer( SHWBufferLink_opengl *HWBuffer ) + { + if ( !HWBuffer ) + return false; + + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + + const void* indices = mb->getIndices(); + u32 indexCount = mb->getIndexCount(); + + GLenum indexSize; + switch ( mb->getIndexType() ) + { + case( EIT_16BIT ): + { + indexSize = sizeof( u16 ); + break; + } + case( EIT_32BIT ): + { + indexSize = sizeof( u32 ); + break; + } + default: + { + return false; + } + } + + + //get or create buffer + bool newBuffer = false; + if ( !HWBuffer->vbo_indicesID ) + { + glGenBuffers( 1, &HWBuffer->vbo_indicesID ); + if ( !HWBuffer->vbo_indicesID ) return false; + newBuffer = true; + } + else if ( HWBuffer->vbo_indicesSize < indexCount*indexSize ) + { + newBuffer = true; + } + + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID ); + + //copy data to graphics card + glGetError(); // clear error storage + if ( !newBuffer ) + glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, 0, indexCount * indexSize, indices ); + else + { + HWBuffer->vbo_indicesSize = indexCount * indexSize; + + if ( HWBuffer->Mapped_Index == scene::EHM_STATIC ) + glBufferData( GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_STATIC_DRAW ); + else + glBufferData( GL_ELEMENT_ARRAY_BUFFER, indexCount * indexSize, indices, GL_DYNAMIC_DRAW ); + } + + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); + + return ( glGetError() == GL_NO_ERROR ); + } + + +//! updates hardware buffer if needed + bool COGLES2Driver::updateHardwareBuffer( SHWBufferLink *HWBuffer ) + { + if ( !HWBuffer ) + return false; + + if ( HWBuffer->Mapped_Vertex != scene::EHM_NEVER ) + { + if ( HWBuffer->ChangedID_Vertex != HWBuffer->MeshBuffer->getChangedID_Vertex() + || !(( SHWBufferLink_opengl* )HWBuffer )->vbo_verticesID ) + { + + HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex(); + + if ( !updateVertexHardwareBuffer(( SHWBufferLink_opengl* )HWBuffer ) ) + return false; + } + } + + if ( HWBuffer->Mapped_Index != scene::EHM_NEVER ) + { + if ( HWBuffer->ChangedID_Index != HWBuffer->MeshBuffer->getChangedID_Index() + || !(( SHWBufferLink_opengl* )HWBuffer )->vbo_indicesID ) + { + + HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index(); + + if ( !updateIndexHardwareBuffer(( SHWBufferLink_opengl* )HWBuffer ) ) + return false; + } + } + + return true; + } + + +//! Create hardware buffer from meshbuffer + COGLES2Driver::SHWBufferLink *COGLES2Driver::createHardwareBuffer( const scene::IMeshBuffer* mb ) + { + if ( !mb || ( mb->getHardwareMappingHint_Index() == scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex() == scene::EHM_NEVER ) ) + return 0; + + SHWBufferLink_opengl *HWBuffer = new SHWBufferLink_opengl( mb ); + + //add to map + HWBufferMap.insert( HWBuffer->MeshBuffer, HWBuffer ); + + HWBuffer->ChangedID_Vertex = HWBuffer->MeshBuffer->getChangedID_Vertex(); + HWBuffer->ChangedID_Index = HWBuffer->MeshBuffer->getChangedID_Index(); + HWBuffer->Mapped_Vertex = mb->getHardwareMappingHint_Vertex(); + HWBuffer->Mapped_Index = mb->getHardwareMappingHint_Index(); + HWBuffer->LastUsed = 0; + HWBuffer->vbo_verticesID = 0; + HWBuffer->vbo_indicesID = 0; + HWBuffer->vbo_verticesSize = 0; + HWBuffer->vbo_indicesSize = 0; + + if ( !updateHardwareBuffer( HWBuffer ) ) + { + deleteHardwareBuffer( HWBuffer ); + return 0; + } + + return HWBuffer; + } + + + void COGLES2Driver::deleteHardwareBuffer( SHWBufferLink *_HWBuffer ) + { + if ( !_HWBuffer ) + return; + + SHWBufferLink_opengl *HWBuffer = ( SHWBufferLink_opengl* )_HWBuffer; + if ( HWBuffer->vbo_verticesID ) + { + glDeleteBuffers( 1, &HWBuffer->vbo_verticesID ); + HWBuffer->vbo_verticesID = 0; + } + if ( HWBuffer->vbo_indicesID ) + { + glDeleteBuffers( 1, &HWBuffer->vbo_indicesID ); + HWBuffer->vbo_indicesID = 0; + } + + CNullDriver::deleteHardwareBuffer( _HWBuffer ); + } + + +//! Draw hardware buffer + void COGLES2Driver::drawHardwareBuffer( SHWBufferLink *_HWBuffer ) + { + if ( !_HWBuffer ) + return; + + SHWBufferLink_opengl *HWBuffer = ( SHWBufferLink_opengl* )_HWBuffer; + + updateHardwareBuffer( HWBuffer ); //check if update is needed + + HWBuffer->LastUsed = 0;//reset count + + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; + const void *vertices = mb->getVertices(); + const void *indexList = mb->getIndices(); + + if ( HWBuffer->Mapped_Vertex != scene::EHM_NEVER ) + { + glBindBuffer( GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID ); + vertices = 0; + } + + if ( HWBuffer->Mapped_Index != scene::EHM_NEVER ) + { + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, HWBuffer->vbo_indicesID ); + indexList = 0; + } + + + drawVertexPrimitiveList( vertices, mb->getVertexCount(), indexList, + mb->getIndexCount() / 3, mb->getVertexType(), + scene::EPT_TRIANGLES, mb->getIndexType() ); + + if ( HWBuffer->Mapped_Vertex != scene::EHM_NEVER ) + glBindBuffer( GL_ARRAY_BUFFER, 0 ); + + if ( HWBuffer->Mapped_Index != scene::EHM_NEVER ) + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 ); + } + + +// small helper function to create vertex buffer object adress offsets + static inline u8* buffer_offset( const long offset ) + { + return (( u8* )0 + offset ); + } + + + //! draws a vertex primitive list + void COGLES2Driver::drawVertexPrimitiveList( const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType ) + { + testGLError(); + if ( !checkPrimitiveCount( primitiveCount ) ) + return; + + setRenderStates3DMode(); + + drawVertexPrimitiveList2d3d( vertices, vertexCount, ( const u16* )indexList, primitiveCount, vType, pType, iType ); + + if ( static_cast( Material.MaterialType ) < MaterialRenderers.size() ) + MaterialRenderers[Material.MaterialType].Renderer->PostRender( this, video::EVT_STANDARD ); + } + + + void COGLES2Driver::drawVertexPrimitiveList2d3d( const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType, bool threed ) + { + if ( !primitiveCount || !vertexCount ) + return; + + if ( !threed && !checkPrimitiveCount( primitiveCount ) ) + return; + + CNullDriver::drawVertexPrimitiveList( vertices, vertexCount, indexList, primitiveCount, vType, pType, iType ); + + //TODO: treat #ifdef GL_OES_point_size_array outside this if + if ( NoHighLevelShader ) + { + glEnableVertexAttribArray( EVA_COLOR ); + glEnableVertexAttribArray( EVA_POSITION ); + if (( pType != scene::EPT_POINTS ) && ( pType != scene::EPT_POINT_SPRITES ) ) + { + glEnableVertexAttribArray( EVA_TCOORD0 ); + } +#ifdef GL_OES_point_size_array + else if ( FeatureAvailable[IRR_OES_point_size_array] && ( Material.Thickness == 0.0f ) ) + glEnableClientState( GL_POINT_SIZE_ARRAY_OES ); +#endif + if ( threed && ( pType != scene::EPT_POINTS ) && ( pType != scene::EPT_POINT_SPRITES ) ) + { + glEnableVertexAttribArray( EVA_NORMAL ); + } + + switch ( vType ) + { + case EVT_STANDARD: + if ( vertices ) + { +#ifdef GL_OES_point_size_array + if (( pType == scene::EPT_POINTS ) || ( pType == scene::EPT_POINT_SPRITES ) ) + { + if ( FeatureAvailable[IRR_OES_point_size_array] && ( Material.Thickness == 0.0f ) ) + glPointSizePointerOES( GL_FLOAT, sizeof( S3DVertex ), &( static_cast( vertices ) )[0].Normal.X ); + } + else +#endif + glVertexAttribPointer( EVA_POSITION, ( threed ? 3 : 2 ), GL_FLOAT, false, sizeof( S3DVertex ), &( static_cast( vertices ) )[0].Pos ); + if ( threed ) + glVertexAttribPointer( EVA_NORMAL, 3, GL_FLOAT, false, sizeof( S3DVertex ), &( static_cast( vertices ) )[0].Normal ); + glVertexAttribPointer( EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof( S3DVertex ), &( static_cast( vertices ) )[0].Color ); + glVertexAttribPointer( EVA_TCOORD0, 2, GL_FLOAT, false, sizeof( S3DVertex ), &( static_cast( vertices ) )[0].TCoords ); + + } + else + { + glVertexAttribPointer( EVA_POSITION, 3, GL_FLOAT, false, sizeof( S3DVertex ), 0 ); + glVertexAttribPointer( EVA_NORMAL, 3, GL_FLOAT, false, sizeof( S3DVertex ), buffer_offset( 12 ) ); + glVertexAttribPointer( EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof( S3DVertex ), buffer_offset( 24 ) ); + glVertexAttribPointer( EVA_TCOORD0, 2, GL_FLOAT, false, sizeof( S3DVertex ), buffer_offset( 28 ) ); + } + + if ( CurrentTexture[1] ) + { + // There must be some optimisation here as it uses the same texture coord ! + glEnableVertexAttribArray( EVA_TCOORD1 ); + if ( vertices ) + glVertexAttribPointer( EVA_TCOORD1, 2, GL_FLOAT, false, sizeof( S3DVertex ), &( static_cast( vertices ) )[0].TCoords ); + else + glVertexAttribPointer( EVA_TCOORD1, 2, GL_FLOAT, false, sizeof( S3DVertex ), buffer_offset( 28 ) ); + } + break; + case EVT_2TCOORDS: + glEnableVertexAttribArray( EVA_TCOORD1 ); + if ( vertices ) + { + glVertexAttribPointer( EVA_POSITION, ( threed ? 3 : 2 ), GL_FLOAT, false, sizeof( S3DVertex2TCoords ), &( static_cast( vertices ) )[0].Pos ); + if ( threed ) + glVertexAttribPointer( EVA_NORMAL, 3, GL_FLOAT, false, sizeof( S3DVertex2TCoords ), &( static_cast( vertices ) )[0].Normal ); + glVertexAttribPointer( EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof( S3DVertex2TCoords ), &( static_cast( vertices ) )[0].Color ); + glVertexAttribPointer( EVA_TCOORD0, 2, GL_FLOAT, false, sizeof( S3DVertex2TCoords ), &( static_cast( vertices ) )[0].TCoords ); + glVertexAttribPointer( EVA_TCOORD1, 2, GL_FLOAT, false, sizeof( S3DVertex2TCoords ), &( static_cast( vertices ) )[0].TCoords2 ); + } + else + { + glVertexAttribPointer( EVA_POSITION, 3, GL_FLOAT, false, sizeof( S3DVertex2TCoords ), buffer_offset( 0 ) ); + glVertexAttribPointer( EVA_NORMAL, 3, GL_FLOAT, false, sizeof( S3DVertex2TCoords ), buffer_offset( 12 ) ); + glVertexAttribPointer( EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof( S3DVertex2TCoords ), buffer_offset( 24 ) ); + glVertexAttribPointer( EVA_TCOORD0, 2, GL_FLOAT, false, sizeof( S3DVertex2TCoords ), buffer_offset( 28 ) ); + glVertexAttribPointer( EVA_TCOORD1, 2, GL_FLOAT, false, sizeof( S3DVertex2TCoords ), buffer_offset( 36 ) ); + + } + break; + case EVT_TANGENTS: + glEnableVertexAttribArray( EVA_TANGENT ); + glEnableVertexAttribArray( EVA_BINORMAL ); + if ( vertices ) + { + glVertexAttribPointer( EVA_POSITION, ( threed ? 3 : 2 ), GL_FLOAT, false, sizeof( S3DVertexTangents ), &( static_cast( vertices ) )[0].Pos ); + if ( threed ) + glVertexAttribPointer( EVA_NORMAL, 3, GL_FLOAT, false, sizeof( S3DVertexTangents ), &( static_cast( vertices ) )[0].Normal ); + glVertexAttribPointer( EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof( S3DVertexTangents ), &( static_cast( vertices ) )[0].Color ); + glVertexAttribPointer( EVA_TCOORD0, 2, GL_FLOAT, false, sizeof( S3DVertexTangents ), &( static_cast( vertices ) )[0].TCoords ); + glVertexAttribPointer( EVA_TANGENT, 3, GL_FLOAT, false, sizeof( S3DVertexTangents ), &( static_cast( vertices ) )[0].Tangent ); + glVertexAttribPointer( EVA_BINORMAL, 3, GL_FLOAT, false, sizeof( S3DVertexTangents ), &( static_cast( vertices ) )[0].Binormal ); + } + else + { + glVertexAttribPointer( EVA_POSITION, 3, GL_FLOAT, false, sizeof( S3DVertexTangents ), buffer_offset( 0 ) ); + glVertexAttribPointer( EVA_NORMAL, 3, GL_FLOAT, false, sizeof( S3DVertexTangents ), buffer_offset( 12 ) ); + glVertexAttribPointer( EVA_COLOR, 4, GL_UNSIGNED_BYTE, true, sizeof( S3DVertexTangents ), buffer_offset( 24 ) ); + glVertexAttribPointer( EVA_TCOORD0, 2, GL_FLOAT, false, sizeof( S3DVertexTangents ), buffer_offset( 28 ) ); + glVertexAttribPointer( EVA_TANGENT, 3, GL_FLOAT, false, sizeof( S3DVertexTangents ), buffer_offset( 36 ) ); + glVertexAttribPointer( EVA_BINORMAL, 3, GL_FLOAT, false, sizeof( S3DVertexTangents ), buffer_offset( 48 ) ); + } + break; + } + } + + // draw everything + GLenum indexSize = 0; + + switch ( iType ) + { + case( EIT_16BIT ): + { + indexSize = GL_UNSIGNED_SHORT; + break; + } + case( EIT_32BIT ): + { +#ifdef GL_OES_element_index_uint +#ifndef GL_UNSIGNED_INT +#define GL_UNSIGNED_INT 0x1405 +#endif + if ( FeatureAvailable[IRR_OES_element_index_uint] ) + indexSize = GL_UNSIGNED_INT; + else +#endif + indexSize = GL_UNSIGNED_SHORT; + break; + } + } + + switch ( pType ) + { + case scene::EPT_POINTS: + case scene::EPT_POINT_SPRITES: + { +#ifdef GL_OES_point_sprite + if ( pType == scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_OES_point_sprite] ) + glEnable( GL_POINT_SPRITE_OES ); +#endif + // if ==0 we use the point size array + if ( Material.Thickness != 0.f ) + { +// float quadratic[] = {0.0f, 0.0f, 10.01f}; + //TODO : OpenGL ES 2.0 Port GL_POINT_DISTANCE_ATTENUATION + //glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, quadratic); +// float maxParticleSize = 1.0f; + //TODO : OpenGL ES 2.0 Port GL_POINT_SIZE_MAX + //glGetFloatv(GL_POINT_SIZE_MAX, &maxParticleSize); +// maxParticleSize=maxParticleSize& pos, + const core::rect& sourceRect, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture ) + { + if ( !texture ) + return; + + if ( !sourceRect.isValid() ) + return; + + core::position2d targetPos( pos ); + core::position2d sourcePos( sourceRect.UpperLeftCorner ); + core::dimension2d sourceSize( sourceRect.getSize() ); + if ( clipRect ) + { + if ( targetPos.X < clipRect->UpperLeftCorner.X ) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if ( sourceSize.Width <= 0 ) + return; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if ( targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X ) + { + sourceSize.Width -= ( targetPos.X + sourceSize.Width ) - clipRect->LowerRightCorner.X; + if ( sourceSize.Width <= 0 ) + return; + } + + if ( targetPos.Y < clipRect->UpperLeftCorner.Y ) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if ( sourceSize.Height <= 0 ) + return; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if ( targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y ) + { + sourceSize.Height -= ( targetPos.Y + sourceSize.Height ) - clipRect->LowerRightCorner.Y; + if ( sourceSize.Height <= 0 ) + return; + } + } + + // clip these coordinates + + if ( targetPos.X < 0 ) + { + sourceSize.Width += targetPos.X; + if ( sourceSize.Width <= 0 ) + return; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if ( targetPos.X + sourceSize.Width > ( s32 )renderTargetSize.Width ) + { + sourceSize.Width -= ( targetPos.X + sourceSize.Width ) - renderTargetSize.Width; + if ( sourceSize.Width <= 0 ) + return; + } + + if ( targetPos.Y < 0 ) + { + sourceSize.Height += targetPos.Y; + if ( sourceSize.Height <= 0 ) + return; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if ( targetPos.Y + sourceSize.Height > ( s32 )renderTargetSize.Height ) + { + sourceSize.Height -= ( targetPos.Y + sourceSize.Height ) - renderTargetSize.Height; + if ( sourceSize.Height <= 0 ) + return; + } + + // ok, we've clipped everything. + // now draw it. + + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const core::dimension2d& ss = texture->getOriginalSize(); + const f32 invW = 1.f / static_cast( ss.Width ); + const f32 invH = 1.f / static_cast( ss.Height ); + const core::rect tcoords( + sourcePos.X * invW, + ( isRTT ? ( sourcePos.Y + sourceSize.Height ) : sourcePos.Y ) * invH, + ( sourcePos.X + sourceSize.Width ) * invW, + ( isRTT ? sourcePos.Y : ( sourcePos.Y + sourceSize.Height ) ) * invH ); + + const core::rect poss( targetPos, sourceSize ); + + disableTextures( 1 ); + if ( !setTexture( 0, texture ) ) + return; + setRenderStates2DMode( color.getAlpha() < 255, true, useAlphaChannelOfTexture ); + + u16 indices[] = {0, 1, 2, 3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(( f32 )poss.UpperLeftCorner.X, ( f32 )poss.UpperLeftCorner.Y, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y ); + vertices[1] = S3DVertex(( f32 )poss.LowerRightCorner.X, ( f32 )poss.UpperLeftCorner.Y, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y ); + vertices[2] = S3DVertex(( f32 )poss.LowerRightCorner.X, ( f32 )poss.LowerRightCorner.Y, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y ); + vertices[3] = S3DVertex(( f32 )poss.UpperLeftCorner.X, ( f32 )poss.LowerRightCorner.Y, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y ); + drawVertexPrimitiveList2d3d( vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false ); + } + + void COGLES2Driver::draw2DImageBatch( const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect, + SColor color, + bool useAlphaChannelOfTexture ) + { + if ( !texture ) + return; + + if ( !setTexture( 0, const_cast( texture ) ) ) + return; + + const irr::u32 drawCount = core::min_( positions.size(), sourceRects.size() ); + + core::array vtx( drawCount * 4 ); + core::array indices( drawCount * 6 ); + + for ( u32 i = 0; i < drawCount; i++ ) + { + core::position2d targetPos = positions[i]; + core::position2d sourcePos = sourceRects[i].UpperLeftCorner; + // This needs to be signed as it may go negative. + core::dimension2d sourceSize( sourceRects[i].getSize() ); + + if ( clipRect ) + { + if ( targetPos.X < clipRect->UpperLeftCorner.X ) + { + sourceSize.Width += targetPos.X - clipRect->UpperLeftCorner.X; + if ( sourceSize.Width <= 0 ) + continue; + + sourcePos.X -= targetPos.X - clipRect->UpperLeftCorner.X; + targetPos.X = clipRect->UpperLeftCorner.X; + } + + if ( targetPos.X + ( s32 )sourceSize.Width > clipRect->LowerRightCorner.X ) + { + sourceSize.Width -= ( targetPos.X + sourceSize.Width ) - clipRect->LowerRightCorner.X; + if ( sourceSize.Width <= 0 ) + continue; + } + + if ( targetPos.Y < clipRect->UpperLeftCorner.Y ) + { + sourceSize.Height += targetPos.Y - clipRect->UpperLeftCorner.Y; + if ( sourceSize.Height <= 0 ) + continue; + + sourcePos.Y -= targetPos.Y - clipRect->UpperLeftCorner.Y; + targetPos.Y = clipRect->UpperLeftCorner.Y; + } + + if ( targetPos.Y + ( s32 )sourceSize.Height > clipRect->LowerRightCorner.Y ) + { + sourceSize.Height -= ( targetPos.Y + sourceSize.Height ) - clipRect->LowerRightCorner.Y; + if ( sourceSize.Height <= 0 ) + continue; + } + } + + // clip these coordinates + + if ( targetPos.X < 0 ) + { + sourceSize.Width += targetPos.X; + if ( sourceSize.Width <= 0 ) + continue; + + sourcePos.X -= targetPos.X; + targetPos.X = 0; + } + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + + if ( targetPos.X + sourceSize.Width > ( s32 )renderTargetSize.Width ) + { + sourceSize.Width -= ( targetPos.X + sourceSize.Width ) - renderTargetSize.Width; + if ( sourceSize.Width <= 0 ) + continue; + } + + if ( targetPos.Y < 0 ) + { + sourceSize.Height += targetPos.Y; + if ( sourceSize.Height <= 0 ) + continue; + + sourcePos.Y -= targetPos.Y; + targetPos.Y = 0; + } + + if ( targetPos.Y + sourceSize.Height > ( s32 )renderTargetSize.Height ) + { + sourceSize.Height -= ( targetPos.Y + sourceSize.Height ) - renderTargetSize.Height; + if ( sourceSize.Height <= 0 ) + continue; + } + + // ok, we've clipped everything. + // now draw it. + + core::rect tcoords; + tcoords.UpperLeftCorner.X = ((( f32 )sourcePos.X ) ) / texture->getOriginalSize().Width ; + tcoords.UpperLeftCorner.Y = ((( f32 )sourcePos.Y ) ) / texture->getOriginalSize().Height; + tcoords.LowerRightCorner.X = tcoords.UpperLeftCorner.X + (( f32 )( sourceSize.Width ) / texture->getOriginalSize().Width ); + tcoords.LowerRightCorner.Y = tcoords.UpperLeftCorner.Y + (( f32 )( sourceSize.Height ) / texture->getOriginalSize().Height ); + + const core::rect poss( targetPos, sourceSize ); + + setRenderStates2DMode( color.getAlpha() < 255, true, useAlphaChannelOfTexture ); + + vtx.push_back( S3DVertex(( f32 )poss.UpperLeftCorner.X, ( f32 )poss.UpperLeftCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y ) ); + vtx.push_back( S3DVertex(( f32 )poss.LowerRightCorner.X, ( f32 )poss.UpperLeftCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y ) ); + vtx.push_back( S3DVertex(( f32 )poss.LowerRightCorner.X, ( f32 )poss.LowerRightCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y ) ); + vtx.push_back( S3DVertex(( f32 )poss.UpperLeftCorner.X, ( f32 )poss.LowerRightCorner.Y, 0.0f, + 0.0f, 0.0f, 0.0f, color, + tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y ) ); + + const u32 curPos = vtx.size() - 4; + indices.push_back( 0 + curPos ); + indices.push_back( 1 + curPos ); + indices.push_back( 2 + curPos ); + + indices.push_back( 0 + curPos ); + indices.push_back( 2 + curPos ); + indices.push_back( 3 + curPos ); + } + + if ( vtx.size() ) + { + drawVertexPrimitiveList2d3d( vtx.pointer(), + vtx.size(), indices.pointer(), + indices.size() / 3, + EVT_STANDARD, + scene::EPT_TRIANGLES, + EIT_16BIT, + false ); + } + } + + +//! The same, but with a four element array of colors, one for each vertex + void COGLES2Driver::draw2DImage( const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect, + const video::SColor* const colors, bool useAlphaChannelOfTexture ) + { + if ( !texture ) + return; + + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const core::dimension2du& ss = texture->getOriginalSize(); + const f32 invW = 1.f / static_cast( ss.Width ); + const f32 invH = 1.f / static_cast( ss.Height ); + const core::rect tcoords( + sourceRect.UpperLeftCorner.X * invW, + ( isRTT ? sourceRect.LowerRightCorner.Y : sourceRect.UpperLeftCorner.Y ) * invH, + sourceRect.LowerRightCorner.X * invW, + ( isRTT ? sourceRect.UpperLeftCorner.Y : sourceRect.LowerRightCorner.Y ) *invH ); + + const video::SColor temp[4] = + { + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF, + 0xFFFFFFFF + }; + + const video::SColor* const useColor = colors ? colors : temp; + + disableTextures( 1 ); + setTexture( 0, texture ); + setRenderStates2DMode( useColor[0].getAlpha() < 255 || useColor[1].getAlpha() < 255 || + useColor[2].getAlpha() < 255 || useColor[3].getAlpha() < 255, + true, useAlphaChannelOfTexture ); + + if ( clipRect ) + { + if ( !clipRect->isValid() ) + return; + + glEnable( GL_SCISSOR_TEST ); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + glScissor( clipRect->UpperLeftCorner.X, renderTargetSize.Height - clipRect->LowerRightCorner.Y, + clipRect->getWidth(), clipRect->getHeight() ); + } + + u16 indices[] = {0, 1, 2, 3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(( f32 )destRect.UpperLeftCorner.X, ( f32 )destRect.UpperLeftCorner.Y, 0, 0, 0, 1, useColor[0], tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y ); + vertices[1] = S3DVertex(( f32 )destRect.LowerRightCorner.X, ( f32 )destRect.UpperLeftCorner.Y, 0, 0, 0, 1, useColor[3], tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y ); + vertices[2] = S3DVertex(( f32 )destRect.LowerRightCorner.X, ( f32 )destRect.LowerRightCorner.Y, 0, 0, 0, 1, useColor[2], tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y ); + vertices[3] = S3DVertex(( f32 )destRect.UpperLeftCorner.X, ( f32 )destRect.LowerRightCorner.Y, 0, 0, 0, 1, useColor[1], tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y ); + drawVertexPrimitiveList2d3d( vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false ); + + if ( clipRect ) + glDisable( GL_SCISSOR_TEST ); + testGLError(); + } + + +//! draws a set of 2d images, using a color and the alpha channel + void COGLES2Driver::draw2DImageBatch( const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, s32 kerningWidth, + const core::rect* clipRect, SColor color, + bool useAlphaChannelOfTexture ) + { + if ( !texture ) + return; + + disableTextures( 1 ); + if ( !setTexture( 0, texture ) ) + return; + setRenderStates2DMode( color.getAlpha() < 255, true, useAlphaChannelOfTexture ); + + if ( clipRect ) + { + if ( !clipRect->isValid() ) + return; + + glEnable( GL_SCISSOR_TEST ); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + glScissor( clipRect->UpperLeftCorner.X, renderTargetSize.Height - clipRect->LowerRightCorner.Y, + clipRect->getWidth(), clipRect->getHeight() ); + } + + const core::dimension2du& ss = texture->getOriginalSize(); + core::position2d targetPos( pos ); + // texcoords need to be flipped horizontally for RTTs + const bool isRTT = texture->isRenderTarget(); + const f32 invW = 1.f / static_cast( ss.Width ); + const f32 invH = 1.f / static_cast( ss.Height ); + + core::array vertices; + core::array quadIndices; + vertices.reallocate( indices.size()*4 ); + quadIndices.reallocate( indices.size()*3 ); + for ( u32 i = 0; i < indices.size(); ++i ) + { + const s32 currentIndex = indices[i]; + if ( !sourceRects[currentIndex].isValid() ) + break; + + const core::rect tcoords( + sourceRects[currentIndex].UpperLeftCorner.X * invW, + ( isRTT ? sourceRects[currentIndex].LowerRightCorner.Y : sourceRects[currentIndex].UpperLeftCorner.Y ) * invH, + sourceRects[currentIndex].LowerRightCorner.X * invW, + ( isRTT ? sourceRects[currentIndex].UpperLeftCorner.Y : sourceRects[currentIndex].LowerRightCorner.Y ) * invH ); + + const core::rect poss( targetPos, sourceRects[currentIndex].getSize() ); + + vertices.push_back( S3DVertex(( f32 )poss.UpperLeftCorner.X, ( f32 )poss.UpperLeftCorner.Y, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y ) ); + vertices.push_back( S3DVertex(( f32 )poss.LowerRightCorner.X, ( f32 )poss.UpperLeftCorner.Y, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.UpperLeftCorner.Y ) ); + vertices.push_back( S3DVertex(( f32 )poss.LowerRightCorner.X, ( f32 )poss.LowerRightCorner.Y, 0, 0, 0, 1, color, tcoords.LowerRightCorner.X, tcoords.LowerRightCorner.Y ) ); + vertices.push_back( S3DVertex(( f32 )poss.UpperLeftCorner.X, ( f32 )poss.LowerRightCorner.Y, 0, 0, 0, 1, color, tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y ) ); + + targetPos.X += sourceRects[currentIndex].getWidth(); + } + drawVertexPrimitiveList2d3d( vertices.pointer(), 4, quadIndices.pointer(), 2*indices.size(), video::EVT_STANDARD, scene::EPT_TRIANGLES, EIT_16BIT, false ); + if ( clipRect ) + glDisable( GL_SCISSOR_TEST ); + testGLError(); + } + + +//! draw a 2d rectangle + void COGLES2Driver::draw2DRectangle( SColor color, const core::rect& position, + const core::rect* clip ) + { + disableTextures(); + setRenderStates2DMode( color.getAlpha() < 255, false, false ); + + core::rect pos = position; + + if ( clip ) + pos.clipAgainst( *clip ); + + if ( !pos.isValid() ) + return; + + u16 indices[] = {0, 1, 2, 3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(( f32 )pos.UpperLeftCorner.X, ( f32 )pos.UpperLeftCorner.Y, 0, 0, 0, 1, color, 0, 0 ); + vertices[1] = S3DVertex(( f32 )pos.LowerRightCorner.X, ( f32 )pos.UpperLeftCorner.Y, 0, 0, 0, 1, color, 0, 0 ); + vertices[2] = S3DVertex(( f32 )pos.LowerRightCorner.X, ( f32 )pos.LowerRightCorner.Y, 0, 0, 0, 1, color, 0, 0 ); + vertices[3] = S3DVertex(( f32 )pos.UpperLeftCorner.X, ( f32 )pos.LowerRightCorner.Y, 0, 0, 0, 1, color, 0, 0 ); + drawVertexPrimitiveList2d3d( vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false ); + } + + +//! draw an 2d rectangle + void COGLES2Driver::draw2DRectangle( const core::rect& position, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip ) + { + core::rect pos = position; + + if ( clip ) + pos.clipAgainst( *clip ); + + if ( !pos.isValid() ) + return; + + disableTextures(); + + setRenderStates2DMode( colorLeftUp.getAlpha() < 255 || + colorRightUp.getAlpha() < 255 || + colorLeftDown.getAlpha() < 255 || + colorRightDown.getAlpha() < 255, false, false ); + + u16 indices[] = {0, 1, 2, 3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex(( f32 )pos.UpperLeftCorner.X, ( f32 )pos.UpperLeftCorner.Y, 0, 0, 0, 1, colorLeftUp, 0, 0 ); + vertices[1] = S3DVertex(( f32 )pos.LowerRightCorner.X, ( f32 )pos.UpperLeftCorner.Y, 0, 0, 0, 1, colorRightUp, 0, 0 ); + vertices[2] = S3DVertex(( f32 )pos.LowerRightCorner.X, ( f32 )pos.LowerRightCorner.Y, 0, 0, 0, 1, colorRightDown, 0, 0 ); + vertices[3] = S3DVertex(( f32 )pos.UpperLeftCorner.X, ( f32 )pos.LowerRightCorner.Y, 0, 0, 0, 1, colorLeftDown, 0, 0 ); + drawVertexPrimitiveList2d3d( vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false ); + } + + +//! Draws a 2d line. + void COGLES2Driver::draw2DLine( const core::position2d& start, + const core::position2d& end, + SColor color ) + { + disableTextures(); + setRenderStates2DMode( color.getAlpha() < 255, false, false ); + + u16 indices[] = {0, 1}; + S3DVertex vertices[2]; + vertices[0] = S3DVertex(( f32 )start.X, ( f32 )start.Y, 0, 0, 0, 1, color, 0, 0 ); + vertices[1] = S3DVertex(( f32 )end.X, ( f32 )end.Y, 0, 0, 0, 1, color, 1, 1 ); + drawVertexPrimitiveList2d3d( vertices, 2, indices, 1, video::EVT_STANDARD, scene::EPT_LINES, EIT_16BIT, false ); + } + + + + bool COGLES2Driver::setTexture( u32 stage, const video::ITexture* texture ) + { + if ( stage >= MaxTextureUnits ) + return false; + + if ( CurrentTexture[stage] == texture ) + return true; + + glActiveTexture( GL_TEXTURE0 + stage ); + + CurrentTexture[stage] = texture; + + if ( !texture ) + { + return true; + } + else + { + if ( texture->getDriverType() != EDT_OGLES2 ) + { + os::Printer::log( "Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR ); + return false; + } + glBindTexture( GL_TEXTURE_2D, + static_cast( texture )->getOGLES2TextureName() ); + } + testGLError(); + return true; + } + + +//! disables all textures beginning with the optional fromStage parameter. + bool COGLES2Driver::disableTextures( u32 fromStage ) + { + bool result = true; + for ( u32 i = fromStage; i < MaxTextureUnits; ++i ) + result &= setTexture( i, 0 ); + return result; + } + + +//! creates a matrix in supplied GLfloat array to pass to OGLES1 + inline void COGLES2Driver::createGLMatrix( float gl_matrix[16], const core::matrix4& m ) + { + memcpy( gl_matrix, m.pointer(), 16 * sizeof( f32 ) ); + } + + +//! creates a opengltexturematrix from a D3D style texture matrix + inline void COGLES2Driver::createGLTextureMatrix( float *o, const core::matrix4& m ) + { + o[0] = m[0]; + o[1] = m[1]; + o[2] = 0.f; + o[3] = 0.f; + + o[4] = m[4]; + o[5] = m[5]; + o[6] = 0.f; + o[7] = 0.f; + + o[8] = 0.f; + o[9] = 0.f; + o[10] = 1.f; + o[11] = 0.f; + + o[12] = m[8]; + o[13] = m[9]; + o[14] = 0.f; + o[15] = 1.f; + } + + + //! returns a device dependent texture from a software surface (IImage) + video::ITexture* COGLES2Driver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData) + { + return new COGLES2Texture( surface, name, this ); + } + + + //! Sets a material. + void COGLES2Driver::setMaterial( const SMaterial& material ) + { + Material = material; + OverrideMaterial.apply( Material ); + + for ( s32 i = MaxTextureUnits - 1; i >= 0; --i ) + { + setTexture( i, Material.getTexture( i ) ); + setTransform(( E_TRANSFORMATION_STATE )( ETS_TEXTURE_0 + i ), + Material.getTextureMatrix( i ) ); + } + } + + //! prints error if an error happened. + bool COGLES2Driver::testGLError() + { +#ifdef _DEBUG + GLenum g = glGetError(); + switch ( g ) + { + case GL_NO_ERROR: + return false; + case GL_INVALID_ENUM: + os::Printer::log( "GL_INVALID_ENUM", ELL_ERROR ); + break; + case GL_INVALID_VALUE: + os::Printer::log( "GL_INVALID_VALUE", ELL_ERROR ); + break; + case GL_INVALID_OPERATION: + os::Printer::log( "GL_INVALID_OPERATION", ELL_ERROR ); + break; + case GL_OUT_OF_MEMORY: + os::Printer::log( "GL_OUT_OF_MEMORY", ELL_ERROR ); + break; + }; + return true; +#else + return false; +#endif + } + + + bool COGLES2Driver::testEGLError() + { +#if defined(EGL_VERSION_1_0) && defined(_DEBUG) + EGLint g = eglGetError(); + switch ( g ) + { + case EGL_SUCCESS: + return false; + case EGL_NOT_INITIALIZED : + os::Printer::log( "Not Initialized", ELL_ERROR ); + break; + case EGL_BAD_ACCESS: + os::Printer::log( "Bad Access", ELL_ERROR ); + break; + case EGL_BAD_ALLOC: + os::Printer::log( "Bad Alloc", ELL_ERROR ); + break; + case EGL_BAD_ATTRIBUTE: + os::Printer::log( "Bad Attribute", ELL_ERROR ); + break; + case EGL_BAD_CONTEXT: + os::Printer::log( "Bad Context", ELL_ERROR ); + break; + case EGL_BAD_CONFIG: + os::Printer::log( "Bad Config", ELL_ERROR ); + break; + case EGL_BAD_CURRENT_SURFACE: + os::Printer::log( "Bad Current Surface", ELL_ERROR ); + break; + case EGL_BAD_DISPLAY: + os::Printer::log( "Bad Display", ELL_ERROR ); + break; + case EGL_BAD_SURFACE: + os::Printer::log( "Bad Surface", ELL_ERROR ); + break; + case EGL_BAD_MATCH: + os::Printer::log( "Bad Match", ELL_ERROR ); + break; + case EGL_BAD_PARAMETER: + os::Printer::log( "Bad Parameter", ELL_ERROR ); + break; + case EGL_BAD_NATIVE_PIXMAP: + os::Printer::log( "Bad Native Pixmap", ELL_ERROR ); + break; + case EGL_BAD_NATIVE_WINDOW: + os::Printer::log( "Bad Native Window", ELL_ERROR ); + break; + case EGL_CONTEXT_LOST: + os::Printer::log( "Context Lost", ELL_ERROR ); + break; + }; + return true; +#else + return false; +#endif + } + + + //! sets the needed renderstates + void COGLES2Driver::setRenderStates3DMode() + { + if ( CurrentRenderMode != ERM_3D ) + { + // Reset Texture Stages + if ( BlendEnabled ) + { + glDisable( GL_BLEND ); + BlendEnabled = false; + } + + ResetRenderStates = true; + } + + if ( ResetRenderStates || LastMaterial != Material ) + { + // unset old material + + if ( LastMaterial.MaterialType != Material.MaterialType && + static_cast( LastMaterial.MaterialType ) < MaterialRenderers.size() ) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + + // set new material. + if ( static_cast( Material.MaterialType ) < MaterialRenderers.size() ) + MaterialRenderers[Material.MaterialType].Renderer->OnSetMaterial( + Material, LastMaterial, ResetRenderStates, this ); + + LastMaterial = Material; + ResetRenderStates = false; + } + + if ( static_cast( Material.MaterialType ) < MaterialRenderers.size() ) + MaterialRenderers[Material.MaterialType].Renderer->OnRender( this, video::EVT_STANDARD ); + + testGLError(); + + CurrentRenderMode = ERM_3D; + } + + + GLint COGLES2Driver::getTextureWrapMode(u8 clamp) const + { + switch (clamp) + { + case ETC_CLAMP: + // mode=GL_CLAMP; not supported in ogl-es + return GL_CLAMP_TO_EDGE; + case ETC_CLAMP_TO_EDGE: + return GL_CLAMP_TO_EDGE; + case ETC_CLAMP_TO_BORDER: + // mode=GL_CLAMP_TO_BORDER; not supported in ogl-es + return GL_CLAMP_TO_EDGE; + case ETC_MIRROR: + #ifdef GL_OES_texture_mirrored_repeat + if ( FeatureAvailable[IRR_OES_texture_mirrored_repeat] ) + return GL_MIRRORED_REPEAT_OES; + else + #endif + return GL_REPEAT; + default: + return GL_REPEAT; + } + } + + + void COGLES2Driver::setWrapMode( const SMaterial& material ) + { + testGLError(); + // texture address mode + // Has to be checked always because it depends on the textures + for ( u32 u = 0; u < MaxTextureUnits; ++u ) + { + if (MultiTextureExtension) + glActiveTexture(GL_TEXTURE0 + u); + else if (u>0) + break; // stop loop + + // the APPLE npot restricted extension needs some care as it only supports CLAMP_TO_EDGE + if (queryFeature(EVDF_TEXTURE_NPOT) && !FeatureAvailable[IRR_OES_texture_npot] && + CurrentTexture[u] && (CurrentTexture[u]->getSize() != CurrentTexture[u]->getOriginalSize())) + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + else + { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[u].TextureWrapU)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[u].TextureWrapV)); + } + } + } + + + //! Can be called by an IMaterialRenderer to make its work easier. + void COGLES2Driver::setBasicRenderStates( const SMaterial& material, const SMaterial& lastmaterial, + bool resetAllRenderStates ) + { + testGLError(); + // Texture filter + // Has to be checked always because it depends on the textures + // Filtering has to be set for each texture layer + for ( u32 i = 0; i < MaxTextureUnits; ++i ) + { + //Thibault : strange Blue artifact on textures in exemple 02 + glActiveTexture( GL_TEXTURE0 + i ); + + if ( material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter ) + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + } + else + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + } + + if ( material.getTexture( i ) && material.getTexture( i )->hasMipMaps() ) + { + if ( material.TextureLayer[i].TrilinearFilter ) + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); + } + else if ( material.TextureLayer[i].BilinearFilter ) + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST ); + } + else + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST ); + } + } + else if ( material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter ) + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + } + else + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + } + +#ifdef GL_EXT_texture_filter_anisotropic + if ( FeatureAvailable[IRR_EXT_texture_filter_anisotropic] ) + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, + static_cast( material.TextureLayer[i].AnisotropicFilter > 1 ? core::min_( MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter ) : 1 ) ); +#endif + } + testGLError(); + +// TODO ogl-es + // fillmode +// if (resetAllRenderStates || (lastmaterial.Wireframe != material.Wireframe) || (lastmaterial.PointCloud != material.PointCloud)) +// glPolygonMode(GL_FRONT_AND_BACK, material.Wireframe ? GL_LINE : material.PointCloud? GL_POINT : GL_FILL); + + // shademode + if ( resetAllRenderStates || ( lastmaterial.GouraudShading != material.GouraudShading ) ) + { + //TODO : OpenGL ES 2.0 Port glShadeModel + //if (material.GouraudShading) + // glShadeModel(GL_SMOOTH); + //else + // glShadeModel(GL_FLAT); + } + testGLError(); + + // zbuffer + if ( resetAllRenderStates || lastmaterial.ZBuffer != material.ZBuffer ) + { + switch ( material.ZBuffer ) + { + case ECFN_NEVER: + glDisable( GL_DEPTH_TEST ); + break; + case ECFN_LESSEQUAL: + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_LEQUAL ); + break; + case ECFN_EQUAL: + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_EQUAL ); + break; + case ECFN_LESS: + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_LESS ); + break; + case ECFN_NOTEQUAL: + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_NOTEQUAL ); + break; + case ECFN_GREATEREQUAL: + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_GEQUAL ); + break; + case ECFN_GREATER: + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_GREATER ); + break; + case ECFN_ALWAYS: + glEnable( GL_DEPTH_TEST ); + glDepthFunc( GL_ALWAYS ); + break; + } + } + testGLError(); + + // zwrite +// if (resetAllRenderStates || lastmaterial.ZWriteEnable != material.ZWriteEnable) + { + if ( material.ZWriteEnable && ( AllowZWriteOnTransparent || !material.isTransparent() ) ) + { + glDepthMask( GL_TRUE ); + } + else + glDepthMask( GL_FALSE ); + } + + // back face culling + if ( resetAllRenderStates || ( lastmaterial.FrontfaceCulling != material.FrontfaceCulling ) || ( lastmaterial.BackfaceCulling != material.BackfaceCulling ) ) + { + if (( material.FrontfaceCulling ) && ( material.BackfaceCulling ) ) + { + glCullFace( GL_FRONT_AND_BACK ); + glEnable( GL_CULL_FACE ); + } + else if ( material.BackfaceCulling ) + { + glCullFace( GL_BACK ); + glEnable( GL_CULL_FACE ); + } + else if ( material.FrontfaceCulling ) + { + glCullFace( GL_FRONT ); + glEnable( GL_CULL_FACE ); + } + else + glDisable( GL_CULL_FACE ); + } + testGLError(); + + // Color Mask + if ( resetAllRenderStates || lastmaterial.ColorMask != material.ColorMask ) + { + glColorMask( + ( material.ColorMask & ECP_RED ) ? GL_TRUE : GL_FALSE, + ( material.ColorMask & ECP_GREEN ) ? GL_TRUE : GL_FALSE, + ( material.ColorMask & ECP_BLUE ) ? GL_TRUE : GL_FALSE, + ( material.ColorMask & ECP_ALPHA ) ? GL_TRUE : GL_FALSE ); + } + testGLError(); + + // thickness + if ( resetAllRenderStates || lastmaterial.Thickness != material.Thickness ) + { + //TODO : OpenGL ES 2.0 Port glPointSize + //glPointSize(material.Thickness); + glLineWidth( material.Thickness == 0 ? 1 : material.Thickness ); + //glLineWidth with 0 generate GL_INVALID_VALUE on real hardware. + } + testGLError(); + + // Anti aliasing + if ( resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing ) + { +// if (FeatureAvailable[IRR_ARB_multisample]) + { + if ( material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE ) + glEnable( GL_SAMPLE_ALPHA_TO_COVERAGE ); + else if ( lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE ) + glDisable( GL_SAMPLE_ALPHA_TO_COVERAGE ); + + //TODO : OpenGL ES 2.0 Port GL_MULTISAMPLE + //if ((AntiAlias >= 2) && (material.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY))) + // glEnable(GL_MULTISAMPLE); + //else + // glDisable(GL_MULTISAMPLE); + } + if ( AntiAlias >= 2 ) + { + //TODO : OpenGL ES 2.0 Port GL_LINE_SMOOTH + //if (material.AntiAliasing & EAAM_LINE_SMOOTH) + // glEnable(GL_LINE_SMOOTH); + //else if (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH) + // glDisable(GL_LINE_SMOOTH); + //if (material.AntiAliasing & EAAM_POINT_SMOOTH) + // // often in software, and thus very slow + // glEnable(GL_POINT_SMOOTH); + //else if (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH) + // glDisable(GL_POINT_SMOOTH); + } + } + testGLError(); + + setWrapMode( material ); + + //Thibault : Strange blue Artifact in exemple 01 + glActiveTexture( GL_TEXTURE0 ); + testGLError(); + } + + +//! sets the needed renderstates + void COGLES2Driver::setRenderStates2DMode( bool alpha, bool texture, bool alphaChannel ) + { + if ( CurrentRenderMode != ERM_2D || Transformation3DChanged ) + { + // unset last 3d material + if ( CurrentRenderMode == ERM_3D ) + { + if ( static_cast( LastMaterial.MaterialType ) < MaterialRenderers.size() ) + MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); + SMaterial mat; + mat.ZBuffer = ECFN_NEVER; + mat.Lighting = false; + mat.TextureLayer[0].BilinearFilter = false; + mat.ColorMaterial = 0; + setBasicRenderStates( mat, mat, true ); + LastMaterial = mat; + } + + TwoDRenderer->useProgram(); //Fixed Pipeline Shader needed to render 2D + + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + core::matrix4 m; + m.buildProjectionMatrixOrthoLH( f32( renderTargetSize.Width ), f32( -( s32 )( renderTargetSize.Height ) ), -1.0, 1.0 ); + m.setTranslation( core::vector3df( -1, 1, 0 ) ); + + TwoDRenderer->setOrthoMatrix( m ); + + Transformation3DChanged = false; + } + + if ( alphaChannel || alpha ) + { + if ( ! BlendEnabled ) + { + glEnable( GL_BLEND ); + BlendEnabled = true; + } + blendFunc( EBF_SRC_ALPHA, EBF_ONE_MINUS_SRC_ALPHA ); + TwoDRenderer->useAlphaTest( true ); + TwoDRenderer->setAlphaTestValue( 0.f ); + } + else + { + if ( BlendEnabled ) + { + glDisable( GL_BLEND ); + BlendEnabled = false; + } + TwoDRenderer->useAlphaTest( false ); + } + + if ( texture ) + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); + glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); + + TwoDRenderer->useTexture( true ); + } + else + TwoDRenderer->useTexture( false ); + + CurrentRenderMode = ERM_2D; + testGLError(); + } + + + //! \return Returns the name of the video driver. + const wchar_t* COGLES2Driver::getName() const + { + return Name.c_str(); + } + + + //! deletes all dynamic lights there are + void COGLES2Driver::deleteAllDynamicLights() + { + RequestedLights.clear(); + CNullDriver::deleteAllDynamicLights(); + } + + + //! adds a dynamic light + s32 COGLES2Driver::addDynamicLight( const SLight& light ) + { + CNullDriver::addDynamicLight( light ); + + RequestedLights.push_back( RequestedLight( light ) ); + + u32 newLightIndex = RequestedLights.size() - 1; + + return ( s32 )newLightIndex; + } + + //! Turns a dynamic light on or off + //! \param lightIndex: the index returned by addDynamicLight + //! \param turnOn: true to turn the light on, false to turn it off + void COGLES2Driver::turnLightOn( s32 lightIndex, bool turnOn ) + { + if ( lightIndex < 0 || lightIndex >= ( s32 )RequestedLights.size() ) + return; + + RequestedLight & requestedLight = RequestedLights[lightIndex]; + requestedLight.DesireToBeOn = turnOn; + } + + + //! returns the maximal amount of dynamic lights the device can handle + u32 COGLES2Driver::getMaximalDynamicLightAmount() const + { + return MaxLights; + } + + + //! Sets the dynamic ambient light color. + void COGLES2Driver::setAmbientLight( const SColorf& color ) + { + AmbientLight = color; + } + + //! returns the dynamic ambient light color. + const SColorf& COGLES2Driver::getAmbientLight() const + { + return AmbientLight; + } + + // this code was sent in by Oliver Klems, thank you + void COGLES2Driver::setViewPort( const core::rect& area ) + { + core::rect vp = area; + core::rect rendert( 0, 0, getCurrentRenderTargetSize().Width, getCurrentRenderTargetSize().Height ); + vp.clipAgainst( rendert ); + + if ( vp.getHeight() > 0 && vp.getWidth() > 0 ) + glViewport( vp.UpperLeftCorner.X, + getCurrentRenderTargetSize().Height - vp.UpperLeftCorner.Y - vp.getHeight(), + vp.getWidth(), vp.getHeight() ); + + ViewPort = vp; + testGLError(); + } + + + //! Draws a shadow volume into the stencil buffer. + void COGLES2Driver::drawStencilShadowVolume( const core::vector3df* triangles, s32 count, bool zfail ) + { + if ( !StencilBuffer || !count ) + return; + + // unset last 3d material + if ( CurrentRenderMode == ERM_3D && + static_cast( Material.MaterialType ) < MaterialRenderers.size() ) + { + MaterialRenderers[Material.MaterialType].Renderer->OnUnsetMaterial(); + ResetRenderStates = true; + } + + // store current OGLES state + const GLboolean cullFaceEnabled = glIsEnabled( GL_CULL_FACE ); + GLint cullFaceMode; + glGetIntegerv( GL_CULL_FACE_MODE, &cullFaceMode ); + GLint depthFunc; + glGetIntegerv( GL_DEPTH_FUNC, &depthFunc ); + GLboolean depthMask; + glGetBooleanv( GL_DEPTH_WRITEMASK, &depthMask ); + + glDepthFunc( GL_LEQUAL ); + glDepthMask( GL_FALSE ); // no depth buffer writing + glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); // no color buffer drawing + glEnable( GL_STENCIL_TEST ); + glEnable( GL_POLYGON_OFFSET_FILL ); + glPolygonOffset( 0.0f, 1.0f ); + + glEnableVertexAttribArray( EVA_POSITION ); + + glVertexAttribPointer( EVA_POSITION, 3, GL_FLOAT, false, sizeof( core::vector3df ), &triangles[0] ); + glStencilMask( ~0 ); + glStencilFunc( GL_ALWAYS, 0, ~0 ); + + GLenum decr = GL_DECR; + GLenum incr = GL_INCR; +#if defined(GL_OES_stencil_wrap) + if ( FeatureAvailable[IRR_OES_stencil_wrap] ) + { + decr = GL_DECR_WRAP_OES; + incr = GL_INCR_WRAP_OES; + } +#endif + glEnable( GL_CULL_FACE ); + if ( !zfail ) + { + // ZPASS Method + + glCullFace( GL_BACK ); + glStencilOp( GL_KEEP, GL_KEEP, incr ); + glDrawArrays( GL_TRIANGLES, 0, count ); + + glCullFace( GL_FRONT ); + glStencilOp( GL_KEEP, GL_KEEP, decr ); + glDrawArrays( GL_TRIANGLES, 0, count ); + } + else + { + // ZFAIL Method + + glStencilOp( GL_KEEP, incr, GL_KEEP ); + glCullFace( GL_FRONT ); + glDrawArrays( GL_TRIANGLES, 0, count ); + + glStencilOp( GL_KEEP, decr, GL_KEEP ); + glCullFace( GL_BACK ); + glDrawArrays( GL_TRIANGLES, 0, count ); + } + + glDisableVertexAttribArray( EVA_POSITION ); + glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + glDisable( GL_STENCIL_TEST ); + if ( cullFaceEnabled ) + glEnable( GL_CULL_FACE ); + else + glDisable( GL_CULL_FACE ); + glCullFace( cullFaceMode ); + glDepthFunc( depthFunc ); + glDepthMask( depthMask ); + testGLError(); + } + + + void COGLES2Driver::drawStencilShadow( bool clearStencilBuffer, video::SColor leftUpEdge, + video::SColor rightUpEdge, video::SColor leftDownEdge, video::SColor rightDownEdge ) + { + if ( !StencilBuffer ) + return; + + disableTextures(); + + // store attributes + GLboolean depthMask; + glGetBooleanv( GL_DEPTH_WRITEMASK, &depthMask ); +// GLint shadeModel; + //TODO : OpenGL ES 2.0 Port glGetIntegerv + //glGetIntegerv(GL_SHADE_MODEL, &shadeModel); +// GLint blendSrc, blendDst; + //TODO : OpenGL ES 2.0 Port glGetIntegerv + //glGetIntegerv(GL_BLEND_SRC, &blendSrc); + //glGetIntegerv(GL_BLEND_DST, &blendDst); + + + glDepthMask( GL_FALSE ); + + //TODO : OpenGL ES 2.0 Port glShadeModel + //glShadeModel( GL_FLAT ); + glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + + if ( ! BlendEnabled ) + glEnable( GL_BLEND ); + + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + glEnable( GL_STENCIL_TEST ); + glStencilFunc( GL_NOTEQUAL, 0, ~0 ); + glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP ); + + // draw a shadow rectangle covering the entire screen using stencil buffer + //Wrapper->glMatrixMode(GL_MODELVIEW); + //TODO : OpenGL ES 2.0 Port glPushMatrix + //glPushMatrix(); + //Wrapper->glLoadIdentity(); + //Wrapper->glMatrixMode(GL_PROJECTION); + //TODO : OpenGL ES 2.0 Port glPushMatrix + //glPushMatrix(); + //Wrapper->glLoadIdentity(); + + u16 indices[] = {0, 1, 2, 3}; + S3DVertex vertices[4]; + vertices[0] = S3DVertex( -1.f, -1.f, 0.9f, 0, 0, 1, leftDownEdge, 0, 0 ); + vertices[1] = S3DVertex( -1.f, 1.f, 0.9f, 0, 0, 1, leftUpEdge, 0, 0 ); + vertices[2] = S3DVertex( 1.f, 1.f, 0.9f, 0, 0, 1, rightUpEdge, 0, 0 ); + vertices[3] = S3DVertex( 1.f, -1.f, 0.9f, 0, 0, 1, rightDownEdge, 0, 0 ); + drawVertexPrimitiveList2d3d( vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLE_FAN, EIT_16BIT, false ); + + if ( clearStencilBuffer ) + glClear( GL_STENCIL_BUFFER_BIT ); + + // restore settings + //TODO : OpenGL ES 2.0 Port glPopMatrix + //glPopMatrix(); + //Wrapper->glMatrixMode(GL_MODELVIEW); + //TODO : OpenGL ES 2.0 Port glPopMatrix + //glPopMatrix(); + glDisable( GL_STENCIL_TEST ); + + glDepthMask( depthMask ); + //TODO : OpenGL ES 2.0 Port glShadeModel + //glShadeModel(shadeModel); + if ( ! BlendEnabled ) + glDisable( GL_BLEND ); + //TODO : + //glBlendFunc(blendSrc, blendDst); + testGLError(); + } + + + //! Draws a 3d line. + void COGLES2Driver::draw3DLine( const core::vector3df& start, + const core::vector3df& end, SColor color ) + { + setRenderStates3DMode(); + + u16 indices[] = {0, 1}; + S3DVertex vertices[2]; + vertices[0] = S3DVertex( start.X, start.Y, start.Z, 0, 0, 1, color, 0, 0 ); + vertices[1] = S3DVertex( end.X, end.Y, end.Z, 0, 0, 1, color, 0, 0 ); + drawVertexPrimitiveList2d3d( vertices, 2, indices, 1, video::EVT_STANDARD, scene::EPT_LINES ); + } + + +//! Only used by the internal engine. Used to notify the driver that +//! the window was resized. + void COGLES2Driver::OnResize( const core::dimension2d& size ) + { + CNullDriver::OnResize( size ); + glViewport( 0, 0, size.Width, size.Height ); + testGLError(); + } + + +//! Returns type of video driver + E_DRIVER_TYPE COGLES2Driver::getDriverType() const + { + return EDT_OGLES2; + } + + +//! returns color format + ECOLOR_FORMAT COGLES2Driver::getColorFormat() const + { + return ColorFormat; + } + + +//! Sets a vertex shader constant. + void COGLES2Driver::setVertexShaderConstant( const f32* data, s32 startRegister, s32 constantAmount ) + { +#ifdef GL_vertex_program + for ( s32 i = 0; i < constantAmount; ++i ) + glProgramLocalParameter4fv( GL_VERTEX_PROGRAM, startRegister + i, &data[i*4] ); +#endif + } + +//! Sets a pixel shader constant. + void COGLES2Driver::setPixelShaderConstant( const f32* data, s32 startRegister, s32 constantAmount ) + { +#ifdef GL_fragment_program + for ( s32 i = 0; i < constantAmount; ++i ) + glProgramLocalParameter4fv( GL_FRAGMENT_PROGRAM, startRegister + i, &data[i*4] ); +#endif + } + +//! Sets a constant for the vertex shader based on a name. + bool COGLES2Driver::setVertexShaderConstant( const c8* name, const f32* floats, int count ) + { + //pass this along, as in GLSL the same routine is used for both vertex and fragment shaders + return setPixelShaderConstant( name, floats, count ); + } + +//! Sets a constant for the pixel shader based on a name. + bool COGLES2Driver::setPixelShaderConstant( const c8* name, const f32* floats, int count ) + { + os::Printer::log( "Error: Please call services->setPixelShaderConstant(), not VideoDriver->setPixelShaderConstant()." ); + return false; + } + +//! Sets a vertex pointer the vertex shader based on a name. + bool COGLES2Driver::setVertexShaderPointer( const c8*, const void*, s32, bool, u16 ) + { + os::Printer::log( "Error: Please call services->setVertexPointer(), not VideoDriver->setVertexPointer()." ); + return false; + } + + + +//! Adds a new material renderer to the VideoDriver, using pixel and/or +//! vertex shaders to render geometry. + s32 COGLES2Driver::addShaderMaterial( const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, s32 userData ) + { + os::Printer::log( "No shader support." ); + return -1; + } + + +//! Adds a new material renderer to the VideoDriver, using GLSL to render geometry. + s32 COGLES2Driver::addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName, + E_VERTEX_SHADER_TYPE vsCompileTarget, + const c8* pixelShaderProgram, + const c8* pixelShaderEntryPointName, + E_PIXEL_SHADER_TYPE psCompileTarget, + const c8* geometryShaderProgram, + const c8* geometryShaderEntryPointName, + E_GEOMETRY_SHADER_TYPE gsCompileTarget, + scene::E_PRIMITIVE_TYPE inType, + scene::E_PRIMITIVE_TYPE outType, + u32 verticesOut, + IShaderConstantSetCallBack* callback, + E_MATERIAL_TYPE baseMaterial, + s32 userData) + { + s32 nr = -1; + COGLES2SLMaterialRenderer* r = new COGLES2SLMaterialRenderer( + this, nr, vertexShaderProgram, + pixelShaderProgram, + callback, getMaterialRenderer( baseMaterial ), userData ); + + r->drop(); + return nr; + } + +//! Returns a pointer to the IVideoDriver interface. (Implementation for +//! IMaterialRendererServices) + IVideoDriver* COGLES2Driver::getVideoDriver() + { + return this; + } + + +//! Returns pointer to the IGPUProgrammingServices interface. + IGPUProgrammingServices* COGLES2Driver::getGPUProgrammingServices() + { + return this; + } + + + ITexture* COGLES2Driver::addRenderTargetTexture( const core::dimension2d& size, + const io::path& name, + const ECOLOR_FORMAT format ) + { + //disable mip-mapping + const bool generateMipLevels = getTextureCreationFlag( ETCF_CREATE_MIP_MAPS ); + setTextureCreationFlag( ETCF_CREATE_MIP_MAPS, false ); + + video::ITexture* rtt = 0; + +#if defined(GL_OES_framebuffer_object) + // if driver supports FrameBufferObjects, use them + if ( queryFeature( EVDF_FRAMEBUFFER_OBJECT ) ) + { + rtt = new COGLES2FBOTexture( size, name, this, format ); + if ( rtt ) + { + addTexture( rtt ); + ITexture* tex = createDepthTexture( rtt ); + if ( tex ) + { + static_cast( tex )->attach( rtt ); + tex->drop(); + } + rtt->drop(); + } + } + else +#endif + { + // the simple texture is only possible for size <= screensize + // we try to find an optimal size with the original constraints + core::dimension2du destSize( core::min_( size.Width, ScreenSize.Width ), core::min_( size.Height, ScreenSize.Height ) ); + destSize = destSize.getOptimalSize(( size == size.getOptimalSize() ), false, false ); + rtt = addTexture( destSize, name, ECF_A8R8G8B8 ); + if ( rtt ) + static_cast( rtt )->setIsRenderTarget( true ); + } + + //restore mip-mapping + setTextureCreationFlag( ETCF_CREATE_MIP_MAPS, generateMipLevels ); + + return rtt; + } + + +//! Returns the maximum amount of primitives + u32 COGLES2Driver::getMaximalPrimitiveCount() const + { + return 65535; + } + + +//! set or reset render target + bool COGLES2Driver::setRenderTarget( video::ITexture* texture, bool clearBackBuffer, + bool clearZBuffer, SColor color ) + { + // check for right driver type + + if ( texture && texture->getDriverType() != EDT_OGLES2 ) + { + os::Printer::log( "Fatal Error: Tried to set a texture not owned by this driver.", ELL_ERROR ); + return false; + } + + // check if we should set the previous RT back + + setTexture( 0, 0 ); + ResetRenderStates = true; + if ( RenderTargetTexture != 0 ) + { + RenderTargetTexture->unbindRTT(); + } + + if ( texture ) + { + // we want to set a new target. so do this. + RenderTargetTexture = static_cast( texture ); + RenderTargetTexture->bindRTT(); + CurrentRendertargetSize = texture->getSize(); + } + else + { + glViewport( 0, 0, ScreenSize.Width, ScreenSize.Height ); + RenderTargetTexture = 0; + CurrentRendertargetSize = core::dimension2d( 0, 0 ); + } + + GLbitfield mask = 0; + if ( clearBackBuffer ) + { + const f32 inv = 1.0f / 255.0f; + glClearColor( color.getRed() * inv, color.getGreen() * inv, + color.getBlue() * inv, color.getAlpha() * inv ); + + mask |= GL_COLOR_BUFFER_BIT; + } + if ( clearZBuffer ) + { + glDepthMask( GL_TRUE ); + LastMaterial.ZWriteEnable = true; + mask |= GL_DEPTH_BUFFER_BIT; + } + + glClear( mask ); + testGLError(); + + return true; + } + + +// returns the current size of the screen or rendertarget + const core::dimension2d& COGLES2Driver::getCurrentRenderTargetSize() const + { + if ( CurrentRendertargetSize.Width == 0 ) + return ScreenSize; + else + return CurrentRendertargetSize; + } + + +//! Clears the ZBuffer. + void COGLES2Driver::clearZBuffer() + { + GLboolean enabled = GL_TRUE; + glGetBooleanv( GL_DEPTH_WRITEMASK, &enabled ); + + glDepthMask( GL_TRUE ); + glClear( GL_DEPTH_BUFFER_BIT ); + + glDepthMask( enabled ); + testGLError(); + } + + +//! Returns an image created from the last rendered frame. +// We want to read the front buffer to get the latest render finished. +// This is not possible under ogl-es, though, so one has to call this method +// outside of the render loop only. + IImage* COGLES2Driver::createScreenShot() + { + int format = GL_RGBA; + int type = GL_UNSIGNED_BYTE; + if ( FeatureAvailable[IRR_IMG_read_format] || FeatureAvailable[IRR_OES_read_format] ) + { +#ifdef GL_IMPLEMENTATION_COLOR_READ_TYPE_OES + glGetIntegerv( GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &format ); + glGetIntegerv( GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &type ); +#endif + // there's a format we don't support ATM + if ( GL_UNSIGNED_SHORT_4_4_4_4 == type ) + type = GL_UNSIGNED_SHORT_5_5_5_1; + } + + IImage* newImage = 0; + if ( GL_RGBA == format ) + { + if ( GL_UNSIGNED_BYTE == type ) + newImage = new CImage( ECF_A8R8G8B8, ScreenSize ); + else + newImage = new CImage( ECF_A1R5G5B5, ScreenSize ); + } + else + { + if ( GL_UNSIGNED_BYTE == type ) + newImage = new CImage( ECF_R8G8B8, ScreenSize ); + else + newImage = new CImage( ECF_R5G6B5, ScreenSize ); + } + + u8* pixels = static_cast( newImage->lock() ); + if ( !pixels ) + { + newImage->drop(); + return 0; + } + + glReadPixels( 0, 0, ScreenSize.Width, ScreenSize.Height, format, type, pixels ); + + // opengl images are horizontally flipped, so we have to fix that here. + const s32 pitch = newImage->getPitch(); + u8* p2 = pixels + ( ScreenSize.Height - 1 ) * pitch; + u8* tmpBuffer = new u8[pitch]; + for ( u32 i = 0; i < ScreenSize.Height; i += 2 ) + { + memcpy( tmpBuffer, pixels, pitch ); + memcpy( pixels, p2, pitch ); + memcpy( p2, tmpBuffer, pitch ); + pixels += pitch; + p2 -= pitch; + } + delete [] tmpBuffer; + + newImage->unlock(); + + if ( testGLError() ) + { + newImage->drop(); + return 0; + } + testGLError(); + return newImage; + } + + +//! get depth texture for the given render target texture + ITexture* COGLES2Driver::createDepthTexture( ITexture* texture, bool shared ) + { + if (( texture->getDriverType() != EDT_OGLES2 ) || ( !texture->isRenderTarget() ) ) + return 0; + COGLES2Texture* tex = static_cast( texture ); + + if ( !tex->isFrameBufferObject() ) + return 0; + + if ( shared ) + { + for ( u32 i = 0; i < DepthTextures.size(); ++i ) + { + if ( DepthTextures[i]->getSize() == texture->getSize() ) + { + DepthTextures[i]->grab(); + return DepthTextures[i]; + } + } + DepthTextures.push_back( new COGLES2FBODepthTexture( texture->getSize(), "depth1", this ) ); + return DepthTextures.getLast(); + } + return ( new COGLES2FBODepthTexture( texture->getSize(), "depth1", this ) ); + } + + + void COGLES2Driver::removeDepthTexture( ITexture* texture ) + { + for ( u32 i = 0; i < DepthTextures.size(); ++i ) + { + if ( texture == DepthTextures[i] ) + { + DepthTextures.erase( i ); + return; + } + } + } + + void COGLES2Driver::reloadShaders() + { + FixedPipeline->reload(); + } + + void COGLES2Driver::deleteFramebuffers( s32 n, const u32 *framebuffers ) + { + glDeleteFramebuffers( n, framebuffers ); + } + + void COGLES2Driver::deleteRenderbuffers( s32 n, const u32 *renderbuffers ) + { + glDeleteRenderbuffers( n, renderbuffers ); + } + + void COGLES2Driver::enableBlend() + { + if ( ! BlendEnabled ) + { + BlendEnabled = true; + glEnable( GL_BLEND ); + } + } + + void COGLES2Driver::disableBlend() + { + if ( BlendEnabled ) + { + BlendEnabled = false; + glDisable( GL_BLEND ); + } + } + + u32 getGLBlend( E_BLEND_FACTOR factor ) + { + u32 r = 0; + switch ( factor ) + { + case EBF_ZERO: + r = GL_ZERO; + break; + case EBF_ONE: + r = GL_ONE; + break; + case EBF_DST_COLOR: + r = GL_DST_COLOR; + break; + case EBF_ONE_MINUS_DST_COLOR: + r = GL_ONE_MINUS_DST_COLOR; + break; + case EBF_SRC_COLOR: + r = GL_SRC_COLOR; + break; + case EBF_ONE_MINUS_SRC_COLOR: + r = GL_ONE_MINUS_SRC_COLOR; + break; + case EBF_SRC_ALPHA: + r = GL_SRC_ALPHA; + break; + case EBF_ONE_MINUS_SRC_ALPHA: + r = GL_ONE_MINUS_SRC_ALPHA; + break; + case EBF_DST_ALPHA: + r = GL_DST_ALPHA; + break; + case EBF_ONE_MINUS_DST_ALPHA: + r = GL_ONE_MINUS_DST_ALPHA; + break; + case EBF_SRC_ALPHA_SATURATE: + r = GL_SRC_ALPHA_SATURATE; + break; + } + return r; + } + + void COGLES2Driver::blendFunc( E_BLEND_FACTOR sFactor, E_BLEND_FACTOR dFactor ) + { + if ( sFactor != SourceFactor || dFactor != DestFactor ) + { + SourceFactor = sFactor; + DestFactor = dFactor; + glBlendFunc( getGLBlend( sFactor ), getGLBlend( dFactor ) ); + } + } + + +//! Set/unset a clipping plane. + bool COGLES2Driver::setClipPlane( u32 index, const core::plane3df& plane, bool enable ) + { + if ( index >= UserClipPlane.size() ) + UserClipPlane.push_back( SUserClipPlane() ); + + UserClipPlane[index].Plane = plane; + UserClipPlane[index].Enabled = enable; + return true; + } + +//! Enable/disable a clipping plane. + void COGLES2Driver::enableClipPlane( u32 index, bool enable ) + { + if ( index >= MaxUserClipPlanes ) + return; + + UserClipPlane[index].Enabled = enable; + } + +//! Get the ClipPlane Count + u32 COGLES2Driver::getClipPlaneCount() const + { + return UserClipPlane.size(); + } + + const core::plane3df& COGLES2Driver::getClipPlane( irr::u32 index ) const + { + if ( index < UserClipPlane.size() ) + return UserClipPlane[index].Plane; + else + return *(( core::plane3df* )0 ); + } + + core::dimension2du COGLES2Driver::getMaxTextureSize() const + { + return core::dimension2du(MaxTextureSize, MaxTextureSize); + } + + + } // end namespace +} // end namespace + +#endif // _IRR_COMPILE_WITH_OGLES2_ + +namespace irr +{ + namespace video + { + +// ----------------------------------- +// WINDOWS VERSION +// ----------------------------------- +#if defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_SDL_DEVICE_) || defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) || defined(_IRR_COMPILE_WITH_CONSOLE_DEVICE_) + IVideoDriver* createOGLES2Driver( const SIrrlichtCreationParameters& params, + video::SExposedVideoData& data, io::IFileSystem* io ) + { +#ifdef _IRR_COMPILE_WITH_OGLES2_ + return new COGLES2Driver( params, data, io ); +#else + return 0; +#endif // _IRR_COMPILE_WITH_OGLES2_ + } +#endif + +// ----------------------------------- +// MACOSX VERSION +// ----------------------------------- +#if defined(_IRR_COMPILE_WITH_OSX_DEVICE_) + IVideoDriver* createOGLES2Driver( const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceMacOSX *device ) + { +#ifdef _IRR_COMPILE_WITH_OGLES2_ + return new COGLES2Driver( params, io, device ); +#else + return 0; +#endif // _IRR_COMPILE_WITH_OGLES2_ + } +#endif // _IRR_COMPILE_WITH_OSX_DEVICE_ + +// ----------------------------------- +// IPHONE VERSION +// ----------------------------------- +#if defined(_IRR_COMPILE_WITH_IPHONE_DEVICE_) + IVideoDriver* createOGLES2Driver( const SIrrlichtCreationParameters& params, + video::SExposedVideoData& data, io::IFileSystem* io, + MIrrIPhoneDevice const & device ) + { +#ifdef _IRR_COMPILE_WITH_OGLES2_ + return new COGLES2Driver( params, data, io, device ); +#else + return 0; +#endif // _IRR_COMPILE_WITH_OGLES2_ + } +#endif // _IRR_COMPILE_WITH_IPHONE_DEVICE_ + + } // end namespace +} // end namespace diff --git a/source/Irrlicht/COGLES2Driver.h b/source/Irrlicht/COGLES2Driver.h new file mode 100644 index 00000000..5e08fe7f --- /dev/null +++ b/source/Irrlicht/COGLES2Driver.h @@ -0,0 +1,470 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#ifndef __C_OGLES2_DRIVER_H_INCLUDED__ +#define __C_OGLES2_DRIVER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#if defined(_IRR_WINDOWS_API_) +// include windows headers for HWND +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#elif defined(_IRR_COMPILE_WITH_OSX_DEVICE_) +#include "MacOSX/CIrrDeviceMacOSX.h" +#elif defined(_IRR_COMPILE_WITH_IPHONE_DEVICE_) +#include "CIrrDeviceIPhone.h" +#endif + +#include "SIrrCreationParameters.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include +#ifndef GL_BGRA +// we need to do this for the IMG_BGRA8888 extension +extern int GL_BGRA; +#endif + +#include "CNullDriver.h" +#include "IMaterialRendererServices.h" +#include "EDriverFeatures.h" +#include "fast_atof.h" + +#ifdef _MSC_VER +#pragma comment(lib, "libEGL.lib") +#pragma comment(lib, "libGLESv2.lib") +#endif +#include "COGLES2ExtensionHandler.h" + +namespace irr +{ + namespace video + { + class COGLES2Texture; + class COGLESWrapper; + class COGLES2FixedPipelineShader; + class COGLES2Renderer2d; + + class COGLES2Driver : public CNullDriver, public IMaterialRendererServices, public COGLES2ExtensionHandler + { + public: +#if defined(_IRR_COMPILE_WITH_X11_DEVICE_) || defined(_IRR_COMPILE_WITH_SDL_DEVICE_) || defined(_IRR_WINDOWS_API_) || defined(_IRR_COMPILE_WITH_CONSOLE_DEVICE_) + COGLES2Driver( const SIrrlichtCreationParameters& params, + const SExposedVideoData& data, + io::IFileSystem* io ); +#endif + +#ifdef _IRR_COMPILE_WITH_OSX_DEVICE_ + COGLES2Driver( const SIrrlichtCreationParameters& params, + io::IFileSystem* io, CIrrDeviceMacOSX *device ); +#endif + +#if defined(_IRR_COMPILE_WITH_IPHONE_DEVICE_) + COGLES2Driver( const SIrrlichtCreationParameters& params, + const SExposedVideoData& data, + io::IFileSystem* io, MIrrIPhoneDevice const & device ); +#endif + + //! destructor + virtual ~COGLES2Driver(); + + //! clears the zbuffer + virtual bool beginScene( bool backBuffer = true, bool zBuffer = true, + SColor color = SColor( 255, 0, 0, 0 ), + const SExposedVideoData& videoData=SExposedVideoData(), + core::rect* sourceRect = 0 ); + + //! presents the rendered scene on the screen, returns false if failed + virtual bool endScene(); + + //! sets transformation + virtual void setTransform( E_TRANSFORMATION_STATE state, const core::matrix4& mat ); + + + struct SHWBufferLink_opengl : public SHWBufferLink + { + SHWBufferLink_opengl( const scene::IMeshBuffer *_MeshBuffer ): SHWBufferLink( _MeshBuffer ), vbo_verticesID( 0 ), vbo_indicesID( 0 ) {} + + u32 vbo_verticesID; //tmp + u32 vbo_indicesID; //tmp + + u32 vbo_verticesSize; //tmp + u32 vbo_indicesSize; //tmp + + }; + + bool updateVertexHardwareBuffer( SHWBufferLink_opengl *HWBuffer ); + bool updateIndexHardwareBuffer( SHWBufferLink_opengl *HWBuffer ); + + //! updates hardware buffer if needed + virtual bool updateHardwareBuffer( SHWBufferLink *HWBuffer ); + + //! Create hardware buffer from mesh + virtual SHWBufferLink *createHardwareBuffer( const scene::IMeshBuffer* mb ); + + //! Delete hardware buffer (only some drivers can) + virtual void deleteHardwareBuffer( SHWBufferLink *HWBuffer ); + + //! Draw hardware buffer + virtual void drawHardwareBuffer( SHWBufferLink *HWBuffer ); + + //! draws a vertex primitive list + virtual void drawVertexPrimitiveList( const void* vertices, u32 vertexCount, + const void* indexList, u32 primitiveCount, + E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType ); + + //! draws a vertex primitive list in 2d +// virtual void draw2DVertexPrimitiveList(const void* vertices, u32 vertexCount, +// const void* indexList, u32 primitiveCount, +// E_VERTEX_TYPE vType=EVT_STANDARD, scene::E_PRIMITIVE_TYPE pType=scene::EPT_TRIANGLES, E_INDEX_TYPE iType=EIT_16BIT); + + void drawVertexPrimitiveList2d3d( const void* vertices, u32 vertexCount, const void* indexList, + u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, + E_INDEX_TYPE iType = EIT_16BIT, bool threed = true ); + + //! queries the features of the driver, returns true if feature is available + virtual bool queryFeature( E_VIDEO_DRIVER_FEATURE feature ) const + { + return FeatureEnabled[feature] && COGLES2ExtensionHandler::queryFeature(feature); + } + + //! Sets a material. + virtual void setMaterial( const SMaterial& material ); + + //! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted. + virtual void draw2DImage( const video::ITexture* texture, const core::position2d& destPos, + const core::rect& sourceRect, const core::rect* clipRect = 0, + SColor color = SColor( 255, 255, 255, 255 ), bool useAlphaChannelOfTexture = false ); + + //! draws a set of 2d images + virtual void draw2DImageBatch( const video::ITexture* texture, + const core::position2d& pos, + const core::array >& sourceRects, + const core::array& indices, + s32 kerningWidth = 0, + const core::rect* clipRect = 0, + SColor color = SColor( 255, 255, 255, 255 ), + bool useAlphaChannelOfTexture = false ); + + //! Draws a part of the texture into the rectangle. + virtual void draw2DImage( const video::ITexture* texture, const core::rect& destRect, + const core::rect& sourceRect, const core::rect* clipRect = 0, + const video::SColor* const colors = 0, bool useAlphaChannelOfTexture = false ); + + void draw2DImageBatch( const video::ITexture* texture, + const core::array >& positions, + const core::array >& sourceRects, + const core::rect* clipRect, + SColor color, + bool useAlphaChannelOfTexture ); + + //! draw an 2d rectangle + virtual void draw2DRectangle( SColor color, const core::rect& pos, + const core::rect* clip = 0 ); + + //!Draws an 2d rectangle with a gradient. + virtual void draw2DRectangle( const core::rect& pos, + SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, + const core::rect* clip = 0 ); + + //! Draws a 2d line. + virtual void draw2DLine( const core::position2d& start, + const core::position2d& end, + SColor color = SColor( 255, 255, 255, 255 ) ); + + //! Draws a 3d line. + virtual void draw3DLine( const core::vector3df& start, + const core::vector3df& end, + SColor color = SColor( 255, 255, 255, 255 ) ); + + //! Draws a pixel +// virtual void drawPixel(u32 x, u32 y, const SColor & color); + + //! Returns the name of the video driver. + virtual const wchar_t* getName() const; + + //! deletes all dynamic lights there are + virtual void deleteAllDynamicLights(); + + //! adds a dynamic light + virtual s32 addDynamicLight( const SLight& light ); + + //! Turns a dynamic light on or off + //! \param lightIndex: the index returned by addDynamicLight + //! \param turnOn: true to turn the light on, false to turn it off + virtual void turnLightOn( s32 lightIndex, bool turnOn ); + + //! returns the maximal amount of dynamic lights the device can handle + virtual u32 getMaximalDynamicLightAmount() const; + + //! Sets the dynamic ambient light color. + virtual void setAmbientLight( const SColorf& color ); + + //! return the dynamic ambient light color. + const SColorf& getAmbientLight() const; + + //! Returns the maximum texture size supported. + virtual core::dimension2du getMaxTextureSize() const; + + //! Draws a shadow volume into the stencil buffer. + virtual void drawStencilShadowVolume( const core::vector3df* triangles, s32 count, bool zfail ); + + //! Fills the stencil shadow with color. + virtual void drawStencilShadow( bool clearStencilBuffer = false, + video::SColor leftUpEdge = video::SColor( 0, 0, 0, 0 ), + video::SColor rightUpEdge = video::SColor( 0, 0, 0, 0 ), + video::SColor leftDownEdge = video::SColor( 0, 0, 0, 0 ), + video::SColor rightDownEdge = video::SColor( 0, 0, 0, 0 ) ); + + //! sets a viewport + virtual void setViewPort( const core::rect& area ); + + //! Only used internally by the engine + virtual void OnResize( const core::dimension2d& size ); + + //! Returns type of video driver + virtual E_DRIVER_TYPE getDriverType() const; + + //! get color format of the current color buffer + virtual ECOLOR_FORMAT getColorFormat() const; + + //! Returns the transformation set by setTransform + virtual const core::matrix4& getTransform( E_TRANSFORMATION_STATE state ) const; + + //! Can be called by an IMaterialRenderer to make its work easier. + virtual void setBasicRenderStates( const SMaterial& material, const SMaterial& lastmaterial, + bool resetAllRenderstates ); + + //! Sets a vertex shader constant. + virtual void setVertexShaderConstant( const f32* data, s32 startRegister, s32 constantAmount = 1 ); + + //! Sets a pixel shader constant. + virtual void setPixelShaderConstant( const f32* data, s32 startRegister, s32 constantAmount = 1 ); + + //! Sets a constant for the vertex shader based on a name. + virtual bool setVertexShaderConstant( const c8* name, const f32* floats, int count ); + + //! Sets a constant for the pixel shader based on a name. + virtual bool setPixelShaderConstant( const c8* name, const f32* floats, int count ); + + //! Sets a vertex pointer the vertex shader based on a name. + virtual bool setVertexShaderPointer( const c8* name, const void* pointer, s32 size = 3, bool normalized = false, u16 stride = 0 ); + + //! sets the current Texture + bool setTexture( u32 stage, const video::ITexture* texture ); + + //! disables all textures beginning with fromStage. + bool disableTextures( u32 fromStage = 0 ); + + //! Adds a new material renderer to the VideoDriver + virtual s32 addShaderMaterial( const c8* vertexShaderProgram, const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, E_MATERIAL_TYPE baseMaterial, s32 userData ); + + //! Adds a new material renderer to the VideoDriver + virtual s32 addHighLevelShaderMaterial( + const c8* vertexShaderProgram, + const c8* vertexShaderEntryPointName = 0, + E_VERTEX_SHADER_TYPE vsCompileTarget = EVST_VS_1_1, + const c8* pixelShaderProgram = 0, + const c8* pixelShaderEntryPointName = 0, + E_PIXEL_SHADER_TYPE psCompileTarget = EPST_PS_1_1, + const c8* geometryShaderProgram = 0, + const c8* geometryShaderEntryPointName = "main", + E_GEOMETRY_SHADER_TYPE gsCompileTarget = EGST_GS_4_0, + scene::E_PRIMITIVE_TYPE inType = scene::EPT_TRIANGLES, + scene::E_PRIMITIVE_TYPE outType = scene::EPT_TRIANGLE_STRIP, + u32 verticesOut = 0, + IShaderConstantSetCallBack* callback = 0, + E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, + s32 userData=0); + + //! Returns pointer to the IGPUProgrammingServices interface. + virtual IGPUProgrammingServices* getGPUProgrammingServices(); + + //! Returns a pointer to the IVideoDriver interface. + virtual IVideoDriver* getVideoDriver(); + + //! Returns the maximum amount of primitives + virtual u32 getMaximalPrimitiveCount() const; + + virtual ITexture* addRenderTargetTexture( const core::dimension2d& size, + const io::path& name, const ECOLOR_FORMAT format = ECF_UNKNOWN ); + virtual bool setRenderTarget( video::ITexture* texture, bool clearBackBuffer, + bool clearZBuffer, SColor color ); + + //! set or reset special render targets +// virtual bool setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget, +// bool clearZBuffer, SColor color); + + //! Sets multiple render targets +// virtual bool setRenderTarget(const core::array& texture, +// bool clearBackBuffer=true, bool clearZBuffer=true, SColor color=SColor(0,0,0,0)); + + //! Clears the ZBuffer. + virtual void clearZBuffer(); + + //! Returns an image created from the last rendered frame. + virtual IImage* createScreenShot(); + + //! checks if an OpenGL error has happend and prints it + bool testGLError(); + + //! checks if an OGLES1 error has happend and prints it + bool testEGLError(); + + //! Set/unset a clipping plane. + virtual bool setClipPlane( u32 index, const core::plane3df& plane, bool enable = false ); + + //! returns the current amount of user clip planes set. + u32 getClipPlaneCount() const; + + //! returns the 0 indexed Plane + const core::plane3df& getClipPlane( u32 index ) const; + + //! Enable/disable a clipping plane. + virtual void enableClipPlane( u32 index, bool enable ); + + //! Returns the graphics card vendor name. + virtual core::stringc getVendorInfo() + { + return vendorName; + }; + + ITexture* createDepthTexture( ITexture* texture, bool shared = true ); + void removeDepthTexture( ITexture* texture ); + + void renderHighLevelShader( bool state = true ) + { + NoHighLevelShader = !state; + } + + COGLES2FixedPipelineShader* fixedPipeline() + { + return FixedPipeline; + } + + virtual void reloadShaders(); + + //native ogles2 which was ogles1 extensions. + + void deleteFramebuffers( s32 n, const u32 *framebuffers ); + void deleteRenderbuffers( s32 n, const u32 *renderbuffers ); + + void enableBlend(); + void disableBlend(); + void blendFunc( E_BLEND_FACTOR sFactor, E_BLEND_FACTOR dFactor ); + + private: + + void uploadClipPlane( u32 index ); + + //! inits the opengl-es driver + bool genericDriverInit( const core::dimension2d& screenSize, bool stencilBuffer ); + + //! returns a device dependent texture from a software surface (IImage) + virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData); + + //! creates a transposed matrix in supplied GLfloat array to pass to OGLES1 + inline void createGLMatrix( float gl_matrix[16], const core::matrix4& m ); + + inline void createGLTextureMatrix( float gl_matrix[16], const core::matrix4& m ); + + //! Map Irrlicht wrap mode to OpenGL enum + GLint getTextureWrapMode(u8 clamp) const; + + //! Set GL pipeline to desired texture wrap modes of the material + void setWrapMode( const SMaterial& material ); + + //! sets the needed renderstates + void setRenderStates3DMode(); + + //! sets the needed renderstates + void setRenderStates2DMode( bool alpha, bool texture, bool alphaChannel ); + + // returns the current size of the screen or rendertarget + virtual const core::dimension2d& getCurrentRenderTargetSize() const; + + void createMaterialRenderers(); + + core::stringw Name; + core::matrix4 Matrices[ETS_COUNT]; + + //! enumeration for rendering modes such as 2d and 3d for minizing the switching of renderStates. + enum E_RENDER_MODE + { + ERM_NONE = 0, // no render state has been set yet. + ERM_2D, // 2d drawing rendermode + ERM_3D // 3d rendering mode + }; + + E_RENDER_MODE CurrentRenderMode; + //! bool to make all renderstates reset if set to true. + bool ResetRenderStates; + bool Transformation3DChanged; + u8 AntiAlias; + + SMaterial Material, LastMaterial; + COGLES2Texture* RenderTargetTexture; + const ITexture* CurrentTexture[MATERIAL_MAX_TEXTURES]; + core::array DepthTextures; + + struct SUserClipPlane + { + core::plane3df Plane; + bool Enabled; + }; + + core::array UserClipPlane; + + core::dimension2d CurrentRendertargetSize; + + core::stringc vendorName; + + core::matrix4 TextureFlipMatrix; + + //! Color buffer format + ECOLOR_FORMAT ColorFormat; + + //! All the lights that have been requested; a hardware limited + //! number of them will be used at once. + struct RequestedLight + { + RequestedLight( SLight const & lightData ) + : LightData( lightData ), DesireToBeOn( true ) { } + + SLight LightData; + bool DesireToBeOn; + }; + + core::array RequestedLights; + SColorf AmbientLight; + + +#ifdef _IRR_COMPILE_WITH_WINDOWS_DEVICE_ + HDC HDc; +#endif + NativeWindowType EglWindow; + void* EglDisplay; + void* EglSurface; + void* EglContext; + + COGLES2FixedPipelineShader* FixedPipeline; + COGLES2Renderer2d* TwoDRenderer; + bool NoHighLevelShader; + + bool BlendEnabled; + E_BLEND_FACTOR SourceFactor; + E_BLEND_FACTOR DestFactor; + }; + + } // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_OPENGL_ + +#endif diff --git a/source/Irrlicht/COGLES2ExtensionHandler.cpp b/source/Irrlicht/COGLES2ExtensionHandler.cpp new file mode 100644 index 00000000..c4b3c34c --- /dev/null +++ b/source/Irrlicht/COGLES2ExtensionHandler.cpp @@ -0,0 +1,189 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "COGLES2ExtensionHandler.h" +#include "COGLES2Driver.h" +#include "fast_atof.h" +#include "irrString.h" + +namespace irr +{ + namespace video + { + + static const char* const OGLES2FeatureStrings[COGLES2ExtensionHandler::IRR_OGLES2_Feature_Count] = + { + "GL_AMD_compressed_3DC_texture", + "GL_AMD_compressed_ATC_texture", + "GL_AMD_performance_monitor", + "GL_AMD_program_binary_Z400", + "GL_ARB_texture_env_combine", + "GL_ARB_texture_env_dot3", + "GL_EXT_multi_draw_arrays", + "GL_EXT_texture_compression_dxt1", + "GL_EXT_texture_filter_anisotropic", + "GL_EXT_texture_format_BGRA8888", + "GL_EXT_texture_type_2_10_10_10_REV", + "GL_IMG_read_format", + "GL_IMG_texture_compression_pvrtc", + "GL_IMG_texture_env_enhanced_fixed_function", + "GL_IMG_texture_format_BGRA8888", + "GL_IMG_user_clip_planes", + "GL_IMG_vertex_program", + "GL_NV_fence", + "GL_OES_blend_equation_separate", + "GL_OES_blend_func_separate", + "GL_OES_blend_subtract", + "GL_OES_byte_coordinates", + "GL_OES_compressed_ETC1_RGB8_texture", + "GL_OES_compressed_paletted_texture", + "GL_OES_depth24", + "GL_OES_depth32", + "GL_OES_depth_texture", + "GL_OES_draw_texture", + "GL_OES_EGL_image", + "GL_OES_element_index_uint", + "GL_OES_extended_matrix_palette", + "GL_OES_fbo_render_mipmap", + "GL_OES_fixed_point", + "GL_OES_fragment_precision_high", + "GL_OES_framebuffer_object", + "GL_OES_get_program_binary", + "GL_OES_mapbuffer", + "GL_OES_matrix_get", + "GL_OES_matrix_palette", + "GL_OES_packed_depth_stencil", + "GL_OES_point_size_array", + "GL_OES_point_sprite", + "GL_OES_query_matrix", + "GL_OES_read_format", + "GL_OES_rgb8_rgba8", + "GL_OES_single_precision", + "GL_OES_standard_derivatives", + "GL_OES_stencil1", + "GL_OES_stencil4", + "GL_OES_stencil8", + "GL_OES_stencil_wrap", + "GL_OES_texture_3D", + "GL_OES_texture_cube_map", + "GL_OES_texture_env_crossbar", + "GL_OES_texture_float", + "GL_OES_texture_float_linear", + "GL_OES_texture_half_float", + "GL_OES_texture_half_float_linear", + "GL_OES_texture_mirrored_repeat", + "GL_OES_texture_npot", + "GL_OES_vertex_half_float", + "GL_OES_vertex_type_10_10_10_2", + "GL_QCOM_driver_control", + "GL_QCOM_performance_monitor_global_mode" + }; + + + COGLES2ExtensionHandler::COGLES2ExtensionHandler() : + EGLVersion( 0 ), Version( 0 ), MaxTextureUnits( 0 ), MaxLights( 0 ), MaxAnisotropy( 1 ), + MaxUserClipPlanes( 1 ), MaxTextureSize(1), CommonProfile( false ), MultiTextureExtension( false ), + MultiSamplingExtension( false ), StencilBuffer( false ) + { + for ( u32 i = 0; i < IRR_OGLES2_Feature_Count; ++i ) + FeatureAvailable[i] = false; + } + + + void COGLES2ExtensionHandler::dump() const + { + for ( u32 i = 0; i < IRR_OGLES2_Feature_Count; ++i ) + os::Printer::log( OGLES2FeatureStrings[i], FeatureAvailable[i] ? " true" : " false" ); + } + + + void COGLES2ExtensionHandler::initExtensions( COGLES2Driver* driver, +#ifdef EGL_VERSION_1_0 + EGLDisplay display, +#endif + bool withStencil ) + { +#ifdef EGL_VERSION_1_0 + const f32 egl_ver = core::fast_atof( reinterpret_cast( eglQueryString( display, EGL_VERSION ) ) ); + EGLVersion = static_cast( core::floor32( egl_ver ) * 100 + core::round32( core::fract( egl_ver ) * 10.0f ) ); + core::stringc eglExtensions = eglQueryString( display, EGL_EXTENSIONS ); + os::Printer::log( eglExtensions.c_str() ); +#endif + const core::stringc stringVer( glGetString( GL_VERSION ) ); + //CommonProfile = ( stringVer[11] == 'M' ); + const f32 ogl_ver = core::fast_atof( stringVer.c_str() + 13 ); + Version = static_cast( core::floor32( ogl_ver ) * 100 + core::round32( core::fract( ogl_ver ) * 10.0f ) ); + core::stringc extensions = glGetString( GL_EXTENSIONS ); + os::Printer::log( extensions.c_str() ); + { + const u32 size = extensions.size() + 1; + c8* str = new c8[size]; + strncpy( str, extensions.c_str(), extensions.size() ); + str[extensions.size()] = ' '; + c8* p = str; + + for ( u32 i = 0; i < size; ++i ) + { + if ( str[i] == ' ' ) + { + str[i] = 0; + if ( *p ) + for ( u32 j = 0; j < IRR_OGLES2_Feature_Count; ++j ) + { + if ( !strcmp( OGLES2FeatureStrings[j], p ) ) + { + FeatureAvailable[j] = true; + break; + } + } + + p = p + strlen( p ) + 1; + } + } + + delete [] str; + } +#ifndef GL_BGRA + // whoa, pretty badly implemented extension... + if ( FeatureAvailable[IRR_IMG_texture_format_BGRA8888] || FeatureAvailable[IRR_EXT_texture_format_BGRA8888] ) + GL_BGRA = 0x80E1; + else + GL_BGRA = GL_RGBA; +#endif + + GLint val = 0; + glGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS, &val ); + MaxTextureUnits = core::min_( MATERIAL_MAX_TEXTURES, static_cast( val ) ); + MultiTextureExtension = true; + //TODO : OpenGL ES 2.0 Port + //glGetIntegerv(GL_MAX_LIGHTS, &val); + MaxLights = static_cast( val ); +#ifdef GL_EXT_texture_filter_anisotropic + if ( FeatureAvailable[GL_EXT_texture_filter_anisotropic] ) + { + glGetIntegerv( GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &val ); + MaxAnisotropy = static_cast( val ); + } +#endif + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &val); + MaxTextureSize=static_cast(val); + if (( Version > 100 ) || FeatureAvailable[IRR_IMG_user_clip_planes] ) + { + //TODO : OpenGL ES 2.0 Port + //glGetIntegerv(GL_MAX_CLIP_PLANES, &val); + val = 6; + MaxUserClipPlanes = static_cast( val ); + } + } + + } // end namespace video +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_OGLES21_ diff --git a/source/Irrlicht/COGLES2ExtensionHandler.h b/source/Irrlicht/COGLES2ExtensionHandler.h new file mode 100644 index 00000000..040cf0c8 --- /dev/null +++ b/source/Irrlicht/COGLES2ExtensionHandler.h @@ -0,0 +1,156 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#ifndef __C_OGLES2_EXTENSION_HANDLER_H_INCLUDED__ +#define __C_OGLES2_EXTENSION_HANDLER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ +#include "os.h" +#include "EDriverFeatures.h" + +#include +#include +#include + +namespace irr +{ + namespace video + { + class COGLES2Driver; + class COGLES2ExtensionHandler + { + public: + enum EOGLES2Features + { + IRR_AMD_compressed_3DC_texture = 0, //39 + IRR_AMD_compressed_ATC_texture, //40 + IRR_AMD_performance_monitor, //50 + IRR_AMD_program_binary_Z400, //48 + IRR_ARB_texture_env_combine, //ogl, IMG simulator + IRR_ARB_texture_env_dot3, //ogl, IMG simulator + IRR_EXT_multi_draw_arrays, //ogl, IMG simulator + IRR_EXT_texture_compression_dxt1, //49 + IRR_EXT_texture_filter_anisotropic, //41 + IRR_EXT_texture_format_BGRA8888, //51 + IRR_EXT_texture_type_2_10_10_10_REV, //42 + IRR_IMG_read_format, //53 + IRR_IMG_texture_compression_pvrtc, //54 + IRR_IMG_texture_env_enhanced_fixed_function, // non-standard + IRR_IMG_texture_format_BGRA8888, // replaced by EXT version + IRR_IMG_user_clip_planes, // non-standard + IRR_IMG_vertex_program, // non-standard + IRR_NV_fence, //52 + IRR_OES_blend_equation_separate, //1 + IRR_OES_blend_func_separate, //2 + IRR_OES_blend_subtract, //3 + IRR_OES_byte_coordinates, //4 + IRR_OES_compressed_ETC1_RGB8_texture, //5 + IRR_OES_compressed_paletted_texture, //6 + IRR_OES_depth24, //24 + IRR_OES_depth32, //25 + IRR_OES_depth_texture, //43 + IRR_OES_draw_texture, //7 + IRR_OES_EGL_image, //23 + IRR_OES_element_index_uint, //26 + IRR_OES_extended_matrix_palette, //8 + IRR_OES_fbo_render_mipmap, //27 + IRR_OES_fixed_point, //9 + IRR_OES_fragment_precision_high, //28 + IRR_OES_framebuffer_object, //10 + IRR_OES_get_program_binary, //47 + IRR_OES_mapbuffer, //29 + IRR_OES_matrix_get, //11 + IRR_OES_matrix_palette, //12 + IRR_OES_packed_depth_stencil, //44 + IRR_OES_point_size_array, //14 + IRR_OES_point_sprite, //15 + IRR_OES_query_matrix, //16 + IRR_OES_read_format, //17 + IRR_OES_rgb8_rgba8, //30 + IRR_OES_single_precision, //18 + IRR_OES_standard_derivatives, //45 + IRR_OES_stencil1, //31 + IRR_OES_stencil4, //32 + IRR_OES_stencil8, //33 + IRR_OES_stencil_wrap, //19 + IRR_OES_texture_3D, //34 + IRR_OES_texture_cube_map, //20 + IRR_OES_texture_env_crossbar, //21 + IRR_OES_texture_float, //36 + IRR_OES_texture_float_linear, //35 + IRR_OES_texture_half_float, //36 + IRR_OES_texture_half_float_linear, //35 + IRR_OES_texture_mirrored_repeat, //22 + IRR_OES_texture_npot, //37 + IRR_OES_vertex_half_float, //38 + IRR_OES_vertex_type_10_10_10_2, //46 + IRR_QCOM_driver_control, //55 + IRR_QCOM_performance_monitor_global_mode, //56 + + IRR_OGLES2_Feature_Count + }; + + //! queries the features of the driver, returns true if feature is available + bool queryOpenGLFeature( EOGLES2Features feature ) const + { + return FeatureAvailable[feature]; + } + + + protected: + COGLES2ExtensionHandler(); + + bool queryFeature( video::E_VIDEO_DRIVER_FEATURE feature ) const + { + switch ( feature ) + { + case EVDF_RENDER_TO_TARGET: + return true; + case EVDF_MULTITEXTURE: + return MultiTextureExtension; + case EVDF_BILINEAR_FILTER: + return true; + case EVDF_MIP_MAP: + return true; + case EVDF_MIP_MAP_AUTO_UPDATE: + return Version > 100; // Supported in version 1.1 + case EVDF_STENCIL_BUFFER: + return StencilBuffer; + case EVDF_TEXTURE_NSQUARE: + return true; // non-square is always supported + default: + return false; + } + } + + void dump() const; + + void initExtensions( COGLES2Driver* driver, + void* display, + bool withStencil ); + + protected: + u16 EGLVersion; + u16 Version; + u8 MaxTextureUnits; + u8 MaxLights; + u8 MaxAnisotropy; + u8 MaxUserClipPlanes; + u32 MaxTextureSize; + bool CommonProfile; + bool MultiTextureExtension; + bool MultiSamplingExtension; + bool StencilBuffer; + bool FeatureAvailable[IRR_OGLES2_Feature_Count]; + }; + + } // end namespace video +} // end namespace irr + + +#endif // _IRR_COMPILE_WITH_OGLES21_ +#endif diff --git a/source/Irrlicht/COGLES2FixedPipelineShader.cpp b/source/Irrlicht/COGLES2FixedPipelineShader.cpp new file mode 100644 index 00000000..3aa0a1a4 --- /dev/null +++ b/source/Irrlicht/COGLES2FixedPipelineShader.cpp @@ -0,0 +1,322 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#include "COGLES2FixedPipelineShader.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "COGLES2SLMaterialRenderer.h" +#include "COGLES2Utils.h" + +namespace irr +{ + namespace video + { + + const char* const COGLES2FixedPipelineShader::sBuiltInShaderUniformNames[] = + { + "uRenderMode", + "uMvpMatrix", + "uWorldMatrix", + "uNormalize", + "uEyePos", + "uUseLight", + "uLightPosition", + "uLightAmbient", + "uLightDiffuse", + "uLightSpecular", + "uLightDirection", + "uLightAttenuation", + "uLightExponent", + "uLightCutoff", + "uAmbientColor", + "uLighting", + "uMaterialAmbient", + "uMaterialEmission", + "uMaterialDiffuse", + "uMaterialSpecular", + "uMaterialShininess", + "uColorMaterial", + "uUseTexture", + "uTextureMatrix", + "uUseTexMatrix", + "uClip", + "uClipPlane", + "uAlphaTest", + "uAlphaValue", + "uFog", + "uFogType", + "uFogColor", + "uFogStart", + "uFogEnd", + "uFogDensity", + "uTextureUnit0", + "uTextureUnit1", + 0 + }; + + const c8 VertexShaderFile[] = "../../media/Shaders/COGLES2FixedPipeline.vsh"; + const c8 FragmentShaderFile[] = "../../media/Shaders/COGLES2FixedPipeline.fsh"; + + COGLES2FixedPipelineShader::COGLES2FixedPipelineShader( video::COGLES2Driver *driver, io::IFileSystem* fs ) + : COGLES2SLMaterialRenderer( driver, fs, 0, 0, sBuiltInShaderUniformNames, UNIFORM_COUNT ), Normalize( 0 ), AlphaTest( 0 ), AlphaValue( 0.f ), + AlphaFunction( ALPHA_GREATER ), Lighting( 0 ), Fog( 0 ), FogType( 0 ), FogStart( 0.f ), FogEnd( 0.f ), FogDensity( 0.f ), + ColorMaterial( 0 ), MaterialShininess( 0.f ), RenderMode( EMT_SOLID ) + { + s32 dummy; + initFromFiles( dummy, VertexShaderFile, FragmentShaderFile, false ); + initData(); + }; + + void COGLES2FixedPipelineShader::reload() + { + reloadFromFiles( VertexShaderFile, FragmentShaderFile ); + //initData(); + } + + void COGLES2FixedPipelineShader::initData() + { + for ( size_t i = 0; i < MAX_TEXTURE_UNITS; ++i ) + TextureUnits[i] = i; + memset( UseTexture, 0, sizeof( UseTexture ) ); + memset( UseTexMatrix, 0, sizeof( UseTexMatrix ) ); + memset( UseLight, 0, sizeof( UseLight ) ); + memset( LightPosition, 0, sizeof( LightPosition ) ); + memset( LightAmbient, 0, sizeof( LightAmbient ) ); + memset( LightDiffuse, 0, sizeof( LightDiffuse ) ); + memset( LightSpecular, 0, sizeof( LightSpecular ) ); + memset( LightDirection, 0, sizeof( LightDirection ) ); + memset( LightAttenuation, 0, sizeof( LightAttenuation ) ); + memset( LightExponent, 0, sizeof( LightExponent ) ); + memset( LightCutoff, 0, sizeof( LightCutoff ) ); + memset( &AmbientColor, 0, sizeof( AmbientColor ) ); + memset( FogColor, 0, sizeof( FogColor ) ); + memset( &ClipPlane, 0, sizeof( ClipPlane ) ); + memset( &MaterialAmbient, 0, sizeof( MaterialAmbient ) ); + memset( &MaterialEmission, 0, sizeof( MaterialEmission ) ); + memset( &MaterialDiffuse, 0, sizeof( MaterialDiffuse ) ); + memset( &MaterialSpecular, 0, sizeof( MaterialSpecular ) ); + } + + bool COGLES2FixedPipelineShader::OnRender( IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype ) + { + Driver->testGLError(); + bool statusOk = true; + + /* Matrices Upload */ + core::matrix4 world = Driver->getTransform( ETS_WORLD ); + //statusOk &= setVertexShaderConstant( "uWorldMatrix", world.pointer(), 16 ); + //glUniformMatrix4fv(locWorldMatrix, 1, false, world.pointer() ); + setUniform( WORLD_MATRIX, world.pointer() ); + + core::matrix4 worldViewProj = Driver->getTransform( video::ETS_PROJECTION ); + worldViewProj *= Driver->getTransform( video::ETS_VIEW ); + worldViewProj *= Driver->getTransform( ETS_WORLD ); + //statusOk &= setVertexShaderConstant( "uMvpMatrix", worldViewProj.pointer(), 16 ); + //glUniformMatrix4fv(locMvpMatrix, 1, false, worldViewProj.pointer()); + setUniform( MVP_MATRIX, worldViewProj.pointer() ); + + /* Textures Upload */ + //statusOk &= setVertexShaderConstant("uTextureUnit", (f32*)TextureUnits, MAX_TEXTURE_UNITS); + //statusOk &= setVertexShaderConstant( "uTextureUnit0", ( f32* ) & TextureUnits[0], 1 ); + setUniform( TEXTURE_UNIT0, &TextureUnits[0] ); + //statusOk &= setVertexShaderConstant( "uTextureUnit1", ( f32* ) & TextureUnits[1], 1 ); + setUniform( TEXTURE_UNIT1, &TextureUnits[1] ); + + //statusOk &= setVertexShaderConstant( "uUseTexture", ( f32* )UseTexture, MAX_TEXTURE_UNITS ); + setUniform( USE_TEXTURE, UseTexture, MAX_TEXTURE_UNITS ); + //statusOk &= setVertexShaderConstant( "uUseTexMatrix", ( f32* )UseTexMatrix, MAX_TEXTURE_UNITS ); + setUniform( USE_TEXTURE_MATRIX, UseTexMatrix, MAX_TEXTURE_UNITS ); + //statusOk &= setVertexShaderConstant( "uTextureMatrix", ( f32* )TextureMatrix, MAX_TEXTURE_UNITS * 16 ); + setUniform( TEXTURE_MATRIX, TextureMatrix, MAX_TEXTURE_UNITS ); + core::matrix4 invWorld; + + /* Lights (in Object Space) Upload */ + if ( Lighting ) + { + u32 cnt = Driver->getDynamicLightCount(); + Driver->getTransform( ETS_WORLD ).getInverse( invWorld ); + for ( size_t i = 0; i < MAX_LIGHTS; ++i ) + { + + if ( i < cnt ) + { + UseLight[i] = 1; + video::SLight light; + light = Driver->getDynamicLight( i ); + + switch ( light.Type ) + { + case ELT_DIRECTIONAL: + invWorld.rotateVect(( f32* )&LightPosition[i], light.Direction ); + LightPosition[i].data[4] = 0.0; + break; + case ELT_SPOT: + invWorld.rotateVect( LightDirection[i], light.Direction ); + LightExponent[i] = light.Falloff; + LightCutoff[i] = light.OuterCone; + //no break on purpose ! + case ELT_POINT: + invWorld.transformVect(( f32* )&LightPosition[i], light.Position ); + LightPosition[i].data[4] = 1.0; + LightAttenuation[i] = light.Attenuation; + break; + + default: + UseLight[i] = 0; + break; + } + + LightAmbient[i] = light.AmbientColor; + LightDiffuse[i] = light.DiffuseColor; + LightSpecular[i] = light.SpecularColor; + LightAttenuation[i] = light.Attenuation; + } + else + { + UseLight[i] = 0; + } + } + //statusOk &= setVertexShaderConstant( "uLighting", ( f32* ) & Lighting, 1 ); + //statusOk &= setVertexShaderConstant( "uUseLight", ( f32* )UseLight, MAX_LIGHTS ); + setUniform( USE_LIGHT, UseLight, MAX_LIGHTS ); + //statusOk &= setVertexShaderConstant( "uLightPosition", ( f32* )LightPosition, MAX_LIGHTS * 4 ); + setUniform( LIGHT_POSITION, LightPosition, MAX_LIGHTS ); + //statusOk &= setVertexShaderConstant( "uLightDirection", ( f32* )LightDirection, MAX_LIGHTS * 3 ); + setUniform( LIGHT_DIRECTION, LightDirection, MAX_LIGHTS ); + //statusOk &= setVertexShaderConstant( "uLightAmbient", ( f32* )LightAmbient, MAX_LIGHTS * 4 ); + setUniform( LIGHT_AMBIENT, LightAmbient, MAX_LIGHTS ); + //statusOk &= setVertexShaderConstant( "uLightDiffuse", ( f32* )LightDiffuse, MAX_LIGHTS * 4 ); + setUniform( LIGHT_DIFFUSE, LightDiffuse, MAX_LIGHTS ); + //statusOk &= setVertexShaderConstant( "uLightSpecular", ( f32* )LightSpecular, MAX_LIGHTS * 4 ); + setUniform( LIGHT_SPECULAR, LightSpecular, MAX_LIGHTS ); + //statusOk &= setVertexShaderConstant( "uLightAttenuation", ( f32* )LightAttenuation, MAX_LIGHTS * 3 ); + setUniform( LIGHT_ATTENUATION, LightAttenuation, MAX_LIGHTS ); + //statusOk &= setVertexShaderConstant( "uLightExponent", LightExponent, MAX_LIGHTS ); + setUniform( LIGHT_EXPONENT, LightExponent, MAX_LIGHTS ); + //statusOk &= setVertexShaderConstant( "uLightCutoff", LightCutoff, MAX_LIGHTS ); + setUniform( LIGHT_CUTOFF, LightCutoff, MAX_LIGHTS ); + + AmbientColor = Driver->getAmbientLight(); + setUniform( LIGHT_AMBIENT, &AmbientColor ); + } + + /* Fog */ + /* statusOk &= setVertexShaderConstant( "uFog", ( f32* ) & Fog, 1 ); + statusOk &= setVertexShaderConstant( "uFogType", ( f32* ) & FogType, 1 ); + statusOk &= setVertexShaderConstant( "uFogColor", FogColor, 4 ); + statusOk &= setVertexShaderConstant( "uFogStart", &FogStart, 1 ); + statusOk &= setVertexShaderConstant( "uFogEnd", &FogEnd, 1 ); + statusOk &= setVertexShaderConstant( "uFogDensity", &FogDensity, 1 );*/ + + /* Clip Plane */ + u32 cnt = Driver->getClipPlaneCount(); + if ( cnt > 0 ) + { + Clip = 1; + ClipPlane = Driver->getClipPlane( 0 ); + } + else + { + Clip = 0; + } + + /* Eye/Camera Position in ObjectSpace */ + if ( Clip || RenderMode == 10 || RenderMode == 11 ) // Need clipping or reflection + { + if ( !Lighting ) + Driver->getTransform( ETS_WORLD ).getInverse( invWorld ); + core::vector3df viewPos( 0.0f, 0.0f, 0.0f ); + core::matrix4 inverseView; + Driver->getTransform( video::ETS_VIEW ).getInverse( inverseView ); + inverseView.transformVect( viewPos ); + invWorld.transformVect( viewPos ); + //setVertexShaderConstant( "uEyePos", &viewPos.X, 3 ); + setUniform( EYE_POSITION, &viewPos.X ); + } + + //statusOk &= setVertexShaderConstant( "uClip", ( f32* ) & Clip ); + setUniform( CLIP, &Clip ); + //statusOk &= setVertexShaderConstant( "uClipPlane", ( f32* ) & ClipPlane ); + setUniform( CLIP_PLANE, &ClipPlane ); + //statusOk &= setVertexShaderConstant( "uRenderMode", ( f32* ) & RenderMode ); + setUniform( RENDER_MODE, &RenderMode ); + //statusOk &= setVertexShaderConstant( "uNormalize", ( f32* ) & Normalize, 1 ); + + return statusOk ; + }; + + void COGLES2FixedPipelineShader::setMaterial( const SMaterial &material ) + { + if (Fog != static_cast(material.FogEnable)) + { + Fog = material.FogEnable; + setUniform( FOG, &Fog ); + } + if (Lighting != static_cast(material.Lighting)) + { + Lighting = material.Lighting; + setUniform( LIGHTING, &Lighting ); + } + + if (Normalize != static_cast(material.NormalizeNormals)) + { + Normalize = material.NormalizeNormals; + setUniform( NORMALIZE, &Normalize ); + } + + for ( size_t i = 0; i < MAX_TEXTURE_UNITS; ++i ) + { + UseTexture[i] = material.getTexture( i ) != 0; + if ( UseTexture[i] ) + { + UseTexMatrix[i] = false; + core::matrix4 texMat = material.getTextureMatrix( i ); + if ( !texMat.isIdentity() ) + { + UseTexMatrix[i] = true; + memcpy( &TextureMatrix[i], texMat.pointer(), sizeof( mat4 ) ); + } + } + } + + + if ( ColorMaterial != material.ColorMaterial ) + { + ColorMaterial = material.ColorMaterial; + setUniform( COLOR_MATERIAL, &ColorMaterial ); + + } + if ( MaterialAmbient != material.AmbientColor ) + { + MaterialAmbient = material.AmbientColor; + setUniform( MATERIAL_AMBIENT, &MaterialAmbient ); + } + if ( MaterialEmission != material.EmissiveColor ) + { + MaterialEmission = material.EmissiveColor; + setUniform( MATERIAL_EMISSION, &MaterialEmission ); + } + if ( MaterialDiffuse != material.DiffuseColor ) + { + MaterialDiffuse = material.DiffuseColor; + setUniform( MATERIAL_DIFFUSE, &MaterialDiffuse ); + } + if ( MaterialSpecular != material.SpecularColor ) + { + MaterialSpecular = material.SpecularColor; + setUniform( MATERIAL_SPECULAR, &MaterialSpecular ); + } + if ( MaterialShininess != material.Shininess ) + { + MaterialShininess = material.Shininess; + setUniform( MATERIAL_SHININESS, &MaterialShininess ); + } + } + + } +} + +#endif //_IRR_COMPILE_WITH_OGLES2_ diff --git a/source/Irrlicht/COGLES2FixedPipelineShader.h b/source/Irrlicht/COGLES2FixedPipelineShader.h new file mode 100644 index 00000000..48027e8f --- /dev/null +++ b/source/Irrlicht/COGLES2FixedPipelineShader.h @@ -0,0 +1,196 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#ifndef __C_OGLES2_FIXED_PIPELINE_SHADER_H_INCLUDED__ +#define __C_OGLES2_FIXED_PIPELINE_SHADER_H_INCLUDED__ + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "COGLES2Driver.h" +#include "COGLES2SLMaterialRenderer.h" +#include "EVertexAttributes.h" + +namespace irr +{ + namespace video + { +#define MAX_LIGHTS 8 +#define MAX_TEXTURE_UNITS 4 + + enum AlphaFunc + { + ALPHA_GREATER = 0 + }; + + class COGLES2FixedPipelineShader : public COGLES2SLMaterialRenderer + { + + public: + + COGLES2FixedPipelineShader( video::COGLES2Driver* driver, io::IFileSystem* fs ); + + void updateMatrices(); + void bindTexture(); + virtual bool OnRender( IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype ); + + public: + /*void enableNormalize() { Normalize = true; } + void disableNormalize() { Normalize = false; }*/ + + void enableAlphaTest() + { + AlphaTest = true; + } + void disableAlphaTest() + { + AlphaTest = false; + } + void setAlphaValue( float value ) + { + AlphaValue = value; + } + + /*void enableLighting() { Lighting = true; } + void disableLighting() { Lighting = false; } + bool isLightingEnabled() { return (Lighting == 1); }*/ + void setAmbientLight( const SColorf& color ); + + void enableFog() + { + Fog = true; + } + void disableFog() + { + Fog = false; + } + bool isFogEnabled() + { + return ( Fog == 1 ); + } + void setFog( E_FOG_TYPE type, const SColor& color, f32 start, f32 end, f32 density ); + + void setMaterial( const SMaterial& material ); + + void setRenderMode( E_MATERIAL_TYPE mode ) + { + RenderMode = mode; + } + + void reload(); + + private: + + void initData(); + + private: + + struct vec3 + { + float data[3]; + }; + struct vec4 + { + float data[4]; + }; + struct mat4 + { + float data[16]; + }; + + float Normalize; + + + int TextureUnits[MAX_TEXTURE_UNITS]; + int UseTexture[MAX_TEXTURE_UNITS]; + mat4 TextureMatrix[MAX_TEXTURE_UNITS]; + int UseTexMatrix[MAX_TEXTURE_UNITS]; + + + float AlphaTest; + float AlphaValue; + AlphaFunc AlphaFunction; + + int Lighting; + int UseLight[MAX_LIGHTS]; + vec4 LightPosition [MAX_LIGHTS]; + SColorf LightAmbient [MAX_LIGHTS]; + SColorf LightDiffuse [MAX_LIGHTS]; + SColorf LightSpecular [MAX_LIGHTS]; + core::vector3df LightDirection[MAX_LIGHTS]; + core::vector3df LightAttenuation[MAX_LIGHTS]; + float LightExponent [MAX_LIGHTS]; + float LightCutoff [MAX_LIGHTS]; + SColorf AmbientColor; + + int Fog; + int FogType; + float FogColor[4]; + float FogStart; + float FogEnd; + float FogDensity; + + int Clip; + core::plane3df ClipPlane; + + u32 ColorMaterial; + SColorf MaterialAmbient; + SColorf MaterialEmission; + SColorf MaterialDiffuse; + SColorf MaterialSpecular; + float MaterialShininess; + + E_MATERIAL_TYPE RenderMode; + private : + enum SHADER_UNIFORM + { + RENDER_MODE = 0, + MVP_MATRIX, + WORLD_MATRIX, + NORMALIZE, + EYE_POSITION, + USE_LIGHT, + LIGHT_POSITION, + LIGHT_AMBIENT, + LIGHT_DIFFUSE, + LIGHT_SPECULAR, + LIGHT_DIRECTION, + LIGHT_ATTENUATION, + LIGHT_EXPONENT, + LIGHT_CUTOFF, + AMBIENT_COLOR, + LIGHTING, + MATERIAL_AMBIENT, + MATERIAL_EMISSION, + MATERIAL_DIFFUSE, + MATERIAL_SPECULAR, + MATERIAL_SHININESS, + COLOR_MATERIAL, + USE_TEXTURE, + TEXTURE_MATRIX, + USE_TEXTURE_MATRIX, + CLIP, + CLIP_PLANE, + ALPHA_TEST, + ALPHA_VALUE, + FOG, + FOG_TYPE, + FOG_COLOR, + FOG_START, + FOG_END, + FOG_DENSITY, + TEXTURE_UNIT0, + TEXTURE_UNIT1, + UNIFORM_COUNT + }; + static const char* const sBuiltInShaderUniformNames[]; + }; + } +} + +#endif //_IRR_COMPILE_WITH_OGLES2_ + +#endif //__C_OGLES2_FIXED_PIPELINE_SHADER_H_INCLUDED__ diff --git a/source/Irrlicht/COGLES2MaterialRenderer.h b/source/Irrlicht/COGLES2MaterialRenderer.h new file mode 100644 index 00000000..a8029fd1 --- /dev/null +++ b/source/Irrlicht/COGLES2MaterialRenderer.h @@ -0,0 +1,598 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#ifndef __C_OGLES2_MATERIAL_RENDERER_H_INCLUDED__ +#define __C_OGLES2_MATERIAL_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "COGLES2SLMaterialRenderer.h" +#include "COGLES2FixedPipelineShader.h" + +namespace irr +{ + namespace video + { + + //! Base class for all internal OGLES2 material renderers + class COGLES2MaterialRenderer : public IMaterialRenderer + { + public: + + //! Constructor + COGLES2MaterialRenderer( video::COGLES2Driver* driver ) : + Driver( driver ), + FixedPipeline( driver->fixedPipeline() ) + { + } + + virtual bool OnRender( IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype ) + { + return FixedPipeline->OnRender( service, vtxtype ); + } + + protected: + + video::COGLES2Driver* Driver; + COGLES2FixedPipelineShader* FixedPipeline; + }; + +//! Solid material renderer + class COGLES2MaterialRenderer_SOLID : public COGLES2MaterialRenderer + { + public: + + COGLES2MaterialRenderer_SOLID( video::COGLES2Driver* d ) : + COGLES2MaterialRenderer( d ) + { + } + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ) + { + if ( resetAllRenderstates || ( material.MaterialType != lastMaterial.MaterialType ) ) + { + FixedPipeline->useProgram(); + FixedPipeline->setRenderMode( EMT_SOLID ); + } + FixedPipeline->setMaterial( material ); + Driver->disableTextures( 1 ); + Driver->setTexture( 0, material.getTexture( 0 ) ); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + + + } + }; + + +//! Generic Texture Blend + class COGLES2MaterialRenderer_ONETEXTURE_BLEND : public COGLES2MaterialRenderer + { + public: + + COGLES2MaterialRenderer_ONETEXTURE_BLEND( video::COGLES2Driver* d ) + : COGLES2MaterialRenderer( d ) {} + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ) + { + Driver->disableTextures( 1 ); + Driver->setTexture( 0, material.getTexture( 0 ) ); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + FixedPipeline->setMaterial( material ); + FixedPipeline->useProgram(); + +// if (material.MaterialType != lastMaterial.MaterialType || +// material.MaterialTypeParam != lastMaterial.MaterialTypeParam || +// resetAllRenderstates) + { + E_BLEND_FACTOR srcFact, dstFact; + E_MODULATE_FUNC modulate; + u32 alphaSource; + unpack_texureBlendFunc( srcFact, dstFact, modulate, alphaSource, material.MaterialTypeParam ); + + //TODO : OpenGL ES 2.0 Port glTexEnvf + //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + //glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + //glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE); + //glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS); + //rgbModulatePreviousTexture + + //glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, (f32) modulate ); + + //glBlendFunc( getGLBlend(srcFact), getGLBlend(dstFact) ); + FixedPipeline->enableAlphaTest(); + FixedPipeline->setAlphaValue( 0.f ); + Driver->enableBlend(); + Driver->blendFunc( srcFact, dstFact ); + + if ( textureBlendFunc_hasAlpha( srcFact ) || textureBlendFunc_hasAlpha( dstFact ) ) + { + //TODO : OpenGL ES 2.0 Port glTexEnvf + //glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + //glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE); + + //glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR); + } + } + } + + virtual void OnUnsetMaterial() + { + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + //glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 1.f ); + //glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS); + + Driver->disableBlend(); + FixedPipeline->disableAlphaTest(); + } + + //! Returns if the material is transparent. + /** Is not always transparent, but mostly. */ + virtual bool isTransparent() const + { + return true; + } + }; + + +//! Solid 2 layer material renderer + class COGLES2MaterialRenderer_SOLID_2_LAYER : public COGLES2MaterialRenderer + { + public: + + COGLES2MaterialRenderer_SOLID_2_LAYER( video::COGLES2Driver* d ) + : COGLES2MaterialRenderer( d ) {} + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ) + { + Driver->disableTextures( 2 ); + Driver->setTexture( 1, material.getTexture( 1 ) ); + Driver->setTexture( 0, material.getTexture( 0 ) ); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + + if ( material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates ) + { + if ( Driver->queryFeature( EVDF_MULTITEXTURE ) ) + { + //Driver->extGlActiveTexture(GL_TEXTURE1); + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + //glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE); + //glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PRIMARY_COLOR); + //glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE); + //glTexEnvf(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + //glTexEnvf(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + //glTexEnvf(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PRIMARY_COLOR); + //glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA); + } + } + } + + virtual void OnUnsetMaterial() + { + if ( Driver->queryFeature( EVDF_MULTITEXTURE ) ) + { + //Driver->extGlActiveTexture(GL_TEXTURE1); + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + //glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR); + //Driver->extGlActiveTexture(GL_TEXTURE0); + } + } + }; + + +//! Transparent add color material renderer + class COGLES2MaterialRenderer_TRANSPARENT_ADD_COLOR : public COGLES2MaterialRenderer + { + public: + + COGLES2MaterialRenderer_TRANSPARENT_ADD_COLOR( video::COGLES2Driver* d ) + : COGLES2MaterialRenderer( d ) {} + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ) + { + if (( material.MaterialType != lastMaterial.MaterialType ) || resetAllRenderstates ) + { + Driver->blendFunc( EBF_ONE, EBF_ONE_MINUS_SRC_COLOR ); + Driver->enableBlend(); + FixedPipeline->useProgram(); + FixedPipeline->setRenderMode( EMT_SOLID ); + } + FixedPipeline->setMaterial( material ); + Driver->disableTextures( 1 ); + Driver->setTexture( 0, material.getTexture( 0 ) ); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + } + + virtual void OnUnsetMaterial() + { + Driver->disableBlend(); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const + { + return true; + } + }; + + +//! Transparent vertex alpha material renderer + class COGLES2MaterialRenderer_TRANSPARENT_VERTEX_ALPHA : public COGLES2MaterialRenderer + { + public: + + COGLES2MaterialRenderer_TRANSPARENT_VERTEX_ALPHA( video::COGLES2Driver* d ) + : COGLES2MaterialRenderer( d ) {} + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ) + { + if ( material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates ) + { + Driver->blendFunc( EBF_ONE, EBF_ONE_MINUS_SRC_ALPHA ); + Driver->enableBlend(); + FixedPipeline->useProgram(); + FixedPipeline->setRenderMode( EMT_TRANSPARENT_VERTEX_ALPHA ); + } + FixedPipeline->setMaterial( material ); + Driver->disableTextures( 1 ); + Driver->setTexture( 0, material.getTexture( 0 ) ); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + } + + virtual void OnUnsetMaterial() + { + Driver->disableBlend(); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const + { + return true; + } + }; + + +//! Transparent alpha channel material renderer + class COGLES2MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL : public COGLES2MaterialRenderer + { + public: + + COGLES2MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL( video::COGLES2Driver* d ) + : COGLES2MaterialRenderer( d ) {} + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ) + { + Driver->disableTextures( 1 ); + Driver->setTexture( 0, material.getTexture( 0 ) ); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + + if ( material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates + || material.MaterialTypeParam != lastMaterial.MaterialTypeParam ) + { + Driver->blendFunc( EBF_SRC_ALPHA, EBF_ONE_MINUS_SRC_ALPHA ); + Driver->enableBlend(); + FixedPipeline->useProgram(); + FixedPipeline->setMaterial( material ); + FixedPipeline->enableAlphaTest(); + + FixedPipeline->setAlphaValue( material.MaterialTypeParam ); + FixedPipeline->setRenderMode( EMT_TRANSPARENT_ALPHA_CHANNEL ); + } + } + + virtual void OnUnsetMaterial() + { + FixedPipeline->disableAlphaTest(); + Driver->disableBlend(); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const + { + return true; + } + }; + + + +//! Transparent alpha channel material renderer + class COGLES2MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF : public COGLES2MaterialRenderer + { + public: + + COGLES2MaterialRenderer_TRANSPARENT_ALPHA_CHANNEL_REF( video::COGLES2Driver* d ) + : COGLES2MaterialRenderer( d ) {} + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ) + { + Driver->disableTextures( 1 ); + Driver->setTexture( 0, material.getTexture( 0 ) ); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + + if ( material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates ) + { + FixedPipeline->enableAlphaTest(); + FixedPipeline->setAlphaValue( 0.5f ); + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + } + } + + virtual void OnUnsetMaterial() + { + FixedPipeline->disableAlphaTest(); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const + { + return false; // this material is not really transparent because it does no blending. + } + }; + + +//! material renderer for all kinds of lightmaps + class COGLES2MaterialRenderer_LIGHTMAP : public COGLES2MaterialRenderer + { + public: + + COGLES2MaterialRenderer_LIGHTMAP( video::COGLES2Driver* d ) + : COGLES2MaterialRenderer( d ) {} + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ) + { + if ( material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates ) + { + FixedPipeline->useProgram(); + FixedPipeline->setRenderMode( EMT_LIGHTMAP ); + } + FixedPipeline->setMaterial( material ); + Driver->disableTextures( 2 ); + Driver->setTexture( 1, material.getTexture( 1 ) ); + Driver->setTexture( 0, material.getTexture( 0 ) ); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + + if ( material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates ) + { + // diffuse map + + switch ( material.MaterialType ) + { + case EMT_LIGHTMAP_LIGHTING: + case EMT_LIGHTMAP_LIGHTING_M2: + case EMT_LIGHTMAP_LIGHTING_M4: + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + break; + case EMT_LIGHTMAP_ADD: + case EMT_LIGHTMAP: + case EMT_LIGHTMAP_M2: + case EMT_LIGHTMAP_M4: + default: + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + break; + } + + if ( Driver->queryFeature( EVDF_MULTITEXTURE ) ) + { + // lightmap + + //Driver->extGlActiveTexture(GL_TEXTURE1); + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + + if ( material.MaterialType == EMT_LIGHTMAP_ADD ) + { + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD_SIGNED); + } + else + { + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + } + + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + //glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + + //glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); + //glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS); + //glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_PREVIOUS); + + switch ( material.MaterialType ) + { + case EMT_LIGHTMAP_M4: + case EMT_LIGHTMAP_LIGHTING_M4: + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 4.0f); + break; + case EMT_LIGHTMAP_M2: + case EMT_LIGHTMAP_LIGHTING_M2: + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 2.0f); + break; + default: + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 1.0f); + break; + } + } + } + } + + virtual void OnUnsetMaterial() + { + if ( Driver->queryFeature( EVDF_MULTITEXTURE ) ) + { + //Driver->extGlActiveTexture(GL_TEXTURE1); + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE, 1.f ); + //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + //Driver->extGlActiveTexture(GL_TEXTURE0); + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } + } + }; + + + +//! detail map material renderer + class COGLES2MaterialRenderer_DETAIL_MAP : public COGLES2MaterialRenderer + { + public: + + COGLES2MaterialRenderer_DETAIL_MAP( video::COGLES2Driver* d ) + : COGLES2MaterialRenderer( d ) {} + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ) + { + if ( material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates ) + { + FixedPipeline->useProgram(); + FixedPipeline->setRenderMode( EMT_DETAIL_MAP ); + } + FixedPipeline->setMaterial( material ); + Driver->disableTextures( 2 ); + Driver->setTexture( 1, material.getTexture( 1 ) ); + Driver->setTexture( 0, material.getTexture( 0 ) ); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + } + }; + + +//! sphere map material renderer + class COGLES2MaterialRenderer_SPHERE_MAP : public COGLES2MaterialRenderer + { + public: + + COGLES2MaterialRenderer_SPHERE_MAP( video::COGLES2Driver* d ) + : COGLES2MaterialRenderer( d ) {} + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ) + { + if ( material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates ) + { + FixedPipeline->useProgram(); + FixedPipeline->setRenderMode( EMT_SPHERE_MAP ); + } + FixedPipeline->setMaterial( material ); + Driver->disableTextures( 1 ); + Driver->setTexture( 0, material.getTexture( 0 ) ); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + } + + virtual void OnUnsetMaterial() + { + } + }; + + +//! reflection 2 layer material renderer + class COGLES2MaterialRenderer_REFLECTION_2_LAYER : public COGLES2MaterialRenderer + { + public: + + COGLES2MaterialRenderer_REFLECTION_2_LAYER( video::COGLES2Driver* d ) + : COGLES2MaterialRenderer( d ) {} + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ) + { + if ( material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates ) + { + FixedPipeline->useProgram(); + FixedPipeline->setRenderMode( EMT_REFLECTION_2_LAYER ); + } + FixedPipeline->setMaterial( material ); + Driver->disableTextures( 2 ); + Driver->setTexture( 0, material.getTexture( 1 ) ); + Driver->setTexture( 1, material.getTexture( 0 ) ); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + } + }; + + +//! reflection 2 layer material renderer + class COGLES2MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER : public COGLES2MaterialRenderer + { + public: + + COGLES2MaterialRenderer_TRANSPARENT_REFLECTION_2_LAYER( video::COGLES2Driver* d ) + : COGLES2MaterialRenderer( d ) {} + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ) + { + Driver->disableTextures( 2 ); + Driver->setTexture( 1, material.getTexture( 1 ) ); + Driver->setTexture( 0, material.getTexture( 0 ) ); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + + if ( material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates ) + { + if ( Driver->queryFeature( EVDF_MULTITEXTURE ) ) + { + //Driver->extGlActiveTexture(GL_TEXTURE1); + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE); + //glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE); + //glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS); + //glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE); + } +// glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); +// glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); +// glEnable(GL_TEXTURE_GEN_S); +// glEnable(GL_TEXTURE_GEN_T); + + Driver->blendFunc( EBF_ONE, EBF_ONE_MINUS_SRC_ALPHA ); + Driver->enableBlend(); + } + } + + virtual void OnUnsetMaterial() + { + if ( Driver->queryFeature( EVDF_MULTITEXTURE ) ) + { + //Driver->extGlActiveTexture(GL_TEXTURE1); + //TODO : OpenGL ES 2.0 Port glTexEnv + //glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + } +// glDisable(GL_TEXTURE_GEN_S); +// glDisable(GL_TEXTURE_GEN_T); + if ( Driver->queryFeature( EVDF_MULTITEXTURE ) ) + { + //Driver->extGlActiveTexture(GL_TEXTURE0); + } + Driver->disableBlend(); + } + + //! Returns if the material is transparent. + virtual bool isTransparent() const + { + return true; + } + }; + + } // end namespace video +} // end namespace irr + +#endif +#endif diff --git a/source/Irrlicht/COGLES2NormalMapRenderer.cpp b/source/Irrlicht/COGLES2NormalMapRenderer.cpp new file mode 100644 index 00000000..9324ed43 --- /dev/null +++ b/source/Irrlicht/COGLES2NormalMapRenderer.cpp @@ -0,0 +1,163 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "COGLES2NormalMapRenderer.h" +#include "IGPUProgrammingServices.h" +#include "IShaderConstantSetCallBack.h" +#include "IVideoDriver.h" +#include "os.h" +#include "COGLES2Driver.h" +#include "COGLES2Utils.h" + +#define MAX_LIGHTS 2 + +namespace irr +{ + namespace video + { + + const char* const COGLES2NormalMapRenderer::sBuiltInShaderUniformNames[] = + { + "uMvpMatrix", + "uLightPos", + "uLightColor", + "texture0", + "texture1", + 0 + }; + +// Irrlicht Engine OGLES2 render path normal map vertex shader + const c8 VertexShaderFile[] = "../../media/Shaders/COGLES2NormalMap.vsh"; + const c8 FragmentShaderFile[] = "../../media/Shaders/COGLES2NormalMap.fsh"; + + +//! Constructor + COGLES2NormalMapRenderer::COGLES2NormalMapRenderer( video::COGLES2Driver* driver, + io::IFileSystem* fs, s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial ) + : COGLES2SLMaterialRenderer( driver, fs, 0, baseMaterial, sBuiltInShaderUniformNames, UNIFORM_COUNT ), CompiledShaders( true ) + { + +#ifdef _DEBUG + setDebugName( "COGLES2NormalMapRenderer" ); +#endif + + // set this as callback. We could have done this in + // the initialization list, but some compilers don't like it. + + CallBack = this; + + // check if already compiled normal map shaders are there. + + video::IMaterialRenderer* renderer = driver->getMaterialRenderer( EMT_NORMAL_MAP_SOLID ); + + if ( renderer ) + { + // use the already compiled shaders + video::COGLES2NormalMapRenderer* nmr = reinterpret_cast( renderer ); + CompiledShaders = false; + + Program = nmr->Program; + + UniformInfo = nmr->UniformInfo; + AttributeInfo = nmr->AttributeInfo; + + outMaterialTypeNr = driver->addMaterialRenderer( this ); + } + else + { + // compile shaders on our own + initFromFiles( outMaterialTypeNr, VertexShaderFile, FragmentShaderFile ); + useProgram(); + int dummy = 0; + setUniform( TEXTURE_UNIT0, &dummy ); + dummy = 1; + setUniform( TEXTURE_UNIT1, &dummy ); + } + + // fallback if compilation has failed + if ( -1 == outMaterialTypeNr ) + outMaterialTypeNr = driver->addMaterialRenderer( this ); + } + + COGLES2NormalMapRenderer::~COGLES2NormalMapRenderer() + { + if ( CallBack == this ) + CallBack = 0; + if ( !CompiledShaders ) + { + // prevent this from deleting shaders we did not create + Program = 0; + } + } + +//! Returns the render capability of the material. + s32 COGLES2NormalMapRenderer::getRenderCapability() const + { + if ( Driver->queryFeature( video::EVDF_ARB_FRAGMENT_PROGRAM_1 ) && + Driver->queryFeature( video::EVDF_ARB_VERTEX_PROGRAM_1 ) ) + return 0; + + return 1; + } + + +//! Called by the engine when the vertex and/or pixel shader constants for an +//! material renderer should be set. + void COGLES2NormalMapRenderer::OnSetConstants( IMaterialRendererServices* services, s32 userData ) + { + video::IVideoDriver* driver = services->getVideoDriver(); + + // set transposed worldViewProj matrix + core::matrix4 worldViewProj( driver->getTransform( video::ETS_PROJECTION ) ); + worldViewProj *= driver->getTransform( video::ETS_VIEW ); + worldViewProj *= driver->getTransform( video::ETS_WORLD ); + setUniform( MVP_MATRIX, worldViewProj.pointer() ); + + // here we fetch the fixed function lights from the driver + // and set them as constants + + u32 cnt = driver->getDynamicLightCount(); + + // Load the inverse world matrix. + core::matrix4 invWorldMat; + driver->getTransform( video::ETS_WORLD ).getInverse( invWorldMat ); + + float lightPosition[4*MAX_LIGHTS]; + float lightColor[4*MAX_LIGHTS]; + + for ( u32 i = 0; i < MAX_LIGHTS; ++i ) + { + video::SLight light; + + if ( i < cnt ) + light = driver->getDynamicLight( i ); + else + { + light.DiffuseColor.set( 0, 0, 0 ); // make light dark + light.Radius = 1.0f; + } + + light.DiffuseColor.a = 1.0f / ( light.Radius * light.Radius ); // set attenuation + + // Transform the light by the inverse world matrix to get it into object space. + invWorldMat.transformVect( light.Position ); + + memcpy( lightPosition + i*4, &light.Position, sizeof( float )*4 ); + memcpy( lightColor + i*4, &light.DiffuseColor, sizeof( float )*4 ); + } + setUniform( LIGHT_POSITION, lightPosition, MAX_LIGHTS ); + setUniform( LIGHT_COLOR, lightColor, MAX_LIGHTS ); + } + + + } // end namespace video +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/COGLES2NormalMapRenderer.h b/source/Irrlicht/COGLES2NormalMapRenderer.h new file mode 100644 index 00000000..432ea677 --- /dev/null +++ b/source/Irrlicht/COGLES2NormalMapRenderer.h @@ -0,0 +1,62 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#ifndef __C_OGLES2_NORMAL_MAP_RENDERER_H_INCLUDED__ +#define __C_OGLES2_NORMAL_MAP_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "COGLES2SLMaterialRenderer.h" +#include "IShaderConstantSetCallBack.h" + +namespace irr +{ + namespace video + { + +//! Class for rendering normal maps with OGLES2 + class COGLES2NormalMapRenderer : public COGLES2SLMaterialRenderer, public IShaderConstantSetCallBack + { + public: + + //! Constructor + COGLES2NormalMapRenderer( video::COGLES2Driver* driver, io::IFileSystem* fs, + s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial ); + + //! Destructor + virtual ~COGLES2NormalMapRenderer(); + + //! Called by the engine when the vertex and/or pixel shader constants for an + //! material renderer should be set. + virtual void OnSetConstants( IMaterialRendererServices* services, s32 userData ); + + //! Returns the render capability of the material. + virtual s32 getRenderCapability() const; + + protected: + + bool CompiledShaders; + + private: + enum SHADER_UNIFORM + { + MVP_MATRIX = 0, + LIGHT_POSITION, + LIGHT_COLOR, + TEXTURE_UNIT0, + TEXTURE_UNIT1, + UNIFORM_COUNT + }; + static const char* const sBuiltInShaderUniformNames[]; + }; + + + } // end namespace video +} // end namespace irr + +#endif +#endif + diff --git a/source/Irrlicht/COGLES2ParallaxMapRenderer.cpp b/source/Irrlicht/COGLES2ParallaxMapRenderer.cpp new file mode 100644 index 00000000..c78e5dd6 --- /dev/null +++ b/source/Irrlicht/COGLES2ParallaxMapRenderer.cpp @@ -0,0 +1,190 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "COGLES2ParallaxMapRenderer.h" +#include "COGLES2Driver.h" +#include "IGPUProgrammingServices.h" +#include "IShaderConstantSetCallBack.h" +#include "IVideoDriver.h" +#include "os.h" + +#define MAX_LIGHTS 2 + +namespace irr +{ + namespace video + { + + const char * const COGLES2ParallaxMapRenderer::sBuiltInShaderUniformNames[] = + { + "uMvpMatrix", + "uLightPos", + "uLightColor", + "uEyePos", + "texture0", + "texture1", + "uLightDiffuse", + "uHeightScale", + 0 + }; + +// Irrlicht Engine OGLES2 render path normal map vertex shader + const c8 VertexShaderFile[] = "../../media/Shaders/COGLES2ParallaxMap.vsh"; + const c8 FragmentShaderFile[] = "../../media/Shaders/COGLES2ParallaxMap.fsh"; + +//! Constructor + COGLES2ParallaxMapRenderer::COGLES2ParallaxMapRenderer( video::COGLES2Driver* driver, + io::IFileSystem* fs, s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial ) + : COGLES2SLMaterialRenderer( driver, fs, 0, baseMaterial, sBuiltInShaderUniformNames, UNIFORM_COUNT ), CompiledShaders( true ) + { + +#ifdef _DEBUG + setDebugName( "COGLES2ParallaxMapRenderer" ); +#endif + + // set this as callback. We could have done this in + // the initialization list, but some compilers don't like it. + + CallBack = this; + + // basically, this simply compiles the hard coded shaders if the + // hardware is able to do them, otherwise it maps to the base material + + // check if already compiled normal map shaders are there. + + video::IMaterialRenderer* renderer = driver->getMaterialRenderer( EMT_PARALLAX_MAP_SOLID ); + + if ( renderer ) + { + // use the already compiled shaders + video::COGLES2ParallaxMapRenderer* pmr = reinterpret_cast( renderer ); + CompiledShaders = false; + + Program = pmr->Program; + + UniformInfo = pmr->UniformInfo; + AttributeInfo = pmr->AttributeInfo; + + outMaterialTypeNr = driver->addMaterialRenderer( this ); + } + else + { + // compile shaders on our own + initFromFiles( outMaterialTypeNr, VertexShaderFile, FragmentShaderFile ); + useProgram(); + int dummy = 0; + setUniform( TEXTURE_UNIT0, &dummy ); + dummy = 1; + setUniform( TEXTURE_UNIT1, &dummy ); + } + + // fallback if compilation has failed + if ( -1 == outMaterialTypeNr ) + outMaterialTypeNr = driver->addMaterialRenderer( this ); + } + + +//! Destructor + COGLES2ParallaxMapRenderer::~COGLES2ParallaxMapRenderer() + { + if ( CallBack == this ) + CallBack = 0; + + if ( !CompiledShaders ) + { + // prevent this from deleting shaders we did not create + Program = 0; + } + } + + + void COGLES2ParallaxMapRenderer::OnSetMaterial( const video::SMaterial& material, + const video::SMaterial& lastMaterial, + bool resetAllRenderstates, video::IMaterialRendererServices* services ) + { + COGLES2SLMaterialRenderer::OnSetMaterial( material, lastMaterial, + resetAllRenderstates, services ); + + CurrentScale = material.MaterialTypeParam; + } + +//! Called by the engine when the vertex and/or pixel shader constants for an +//! material renderer should be set. + void COGLES2ParallaxMapRenderer::OnSetConstants( IMaterialRendererServices* services, s32 userData ) + { + video::IVideoDriver* driver = services->getVideoDriver(); + + // set transposed worldViewProj matrix + core::matrix4 worldViewProj( driver->getTransform( video::ETS_PROJECTION ) ); + worldViewProj *= driver->getTransform( video::ETS_VIEW ); + worldViewProj *= driver->getTransform( video::ETS_WORLD ); + + setUniform( MVP_MATRIX, worldViewProj.pointer() ); + + + // here we fetch the fixed function lights from the driver + // and set them as constants + + u32 cnt = driver->getDynamicLightCount(); + + // Load the inverse world matrix. + core::matrix4 invWorldMat; + driver->getTransform( video::ETS_WORLD ).getInverse( invWorldMat ); + + float lightPosition[4*MAX_LIGHTS]; + float lightColor[4*MAX_LIGHTS]; + + for ( u32 i = 0; i < 2; ++i ) + { + video::SLight light; + + if ( i < cnt ) + light = driver->getDynamicLight( i ); + else + { + light.DiffuseColor.set( 0, 0, 0 ); // make light dark + light.Radius = 1.0f; + } + + light.DiffuseColor.a = 1.0f / ( light.Radius * light.Radius ); // set attenuation + + // Transform the light by the inverse world matrix to get it into object space. + invWorldMat.transformVect( light.Position ); + + memcpy( lightPosition + i*4, &light.Position, sizeof( float )*4 ); + memcpy( lightColor + i*4, &light.DiffuseColor, sizeof( float )*4 ); + } + + setUniform( LIGHT_POSITION, lightPosition, MAX_LIGHTS ); + setUniform( LIGHT_COLOR, lightColor, MAX_LIGHTS ); + + // Obtain the view position by transforming 0,0,0 by the inverse view matrix + // and then multiply this by the inverse world matrix. + core::vector3df viewPos( 0.0f, 0.0f, 0.0f ); + core::matrix4 inverseView; + driver->getTransform( video::ETS_VIEW ).getInverse( inverseView ); + inverseView.transformVect( viewPos ); + invWorldMat.transformVect( viewPos ); + setUniform( EYE_POSITION, &viewPos.X ); + + // set scale factor + f32 factor = 0.02f; // default value + if ( CurrentScale != 0.0f ) + factor = CurrentScale; + + setUniform( HEIGHT_SCALE, &factor ); + } + + + } // end namespace video +} // end namespace irr + + +#endif + diff --git a/source/Irrlicht/COGLES2ParallaxMapRenderer.h b/source/Irrlicht/COGLES2ParallaxMapRenderer.h new file mode 100644 index 00000000..ad69dcf0 --- /dev/null +++ b/source/Irrlicht/COGLES2ParallaxMapRenderer.h @@ -0,0 +1,69 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#ifndef __C_OGLES2_PARALLAX_MAP_RENDERER_H_INCLUDED__ +#define __C_OGLES2_PARALLAX_MAP_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "COGLES2SLMaterialRenderer.h" +#include "IShaderConstantSetCallBack.h" + +namespace irr +{ + namespace video + { + +//! Class for rendering normal maps with OGLES2 + class COGLES2ParallaxMapRenderer : public COGLES2SLMaterialRenderer, public IShaderConstantSetCallBack + { + public: + + //! Constructor + COGLES2ParallaxMapRenderer( video::COGLES2Driver* driver, io::IFileSystem* fs, + s32& outMaterialTypeNr, IMaterialRenderer* baseMaterial ); + + //! Destructor + virtual ~COGLES2ParallaxMapRenderer(); + + //! Called by the engine when the vertex and/or pixel shader constants for an + //! material renderer should be set. + virtual void OnSetConstants( IMaterialRendererServices* services, s32 userData ); + + virtual void OnSetMaterial( const SMaterial& material ) { } + virtual void OnSetMaterial( const video::SMaterial& material, + const video::SMaterial& lastMaterial, + bool resetAllRenderstates, video::IMaterialRendererServices* services ); + + protected: + + bool CompiledShaders; + f32 CurrentScale; + + private: + enum SHADER_UNIFORM + { + MVP_MATRIX = 0, + LIGHT_POSITION, + LIGHT_COLOR, + EYE_POSITION, + TEXTURE_UNIT0, + TEXTURE_UNIT1, + LIGHT_DIFFUSE, + HEIGHT_SCALE, + UNIFORM_COUNT + }; + static const char* const sBuiltInShaderUniformNames[]; + }; + + + } // end namespace video +} // end namespace irr + +#endif +#endif + diff --git a/source/Irrlicht/COGLES2Renderer2D.cpp b/source/Irrlicht/COGLES2Renderer2D.cpp new file mode 100644 index 00000000..058ae797 --- /dev/null +++ b/source/Irrlicht/COGLES2Renderer2D.cpp @@ -0,0 +1,80 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#include "COGLES2Renderer2D.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +namespace irr +{ + namespace video + { + + const char* const COGLES2Renderer2d::sBuiltInShaderUniformNames[] = + { + "uOrthoMatrix", + "uUseTexture", + "uTextureUnit", + "uAlphaTest", + "uAlphaValue", + 0 + }; + + static const char* vertexShaderFile = "../../media/Shaders/COGLES2Renderer2D.vsh"; + static const char* fragmentShaderFile = "../../media/Shaders/COGLES2Renderer2D.fsh"; + + COGLES2Renderer2d::COGLES2Renderer2d( irr::video::COGLES2Driver *driver, irr::io::IFileSystem *fs ) + : COGLES2SLMaterialRenderer( driver, fs, 0, 0, sBuiltInShaderUniformNames, UNIFORM_COUNT ) + { +#ifdef _DEBUG + setDebugName( "COGLES2Renderer2d" ); +#endif + s32 dummy = -1; + initFromFiles( dummy, vertexShaderFile, fragmentShaderFile, false ); + useProgram(); + int texUnit = 0; + setUniform( TEXTURE_UNIT, &texUnit ); + } + + void COGLES2Renderer2d::useTexture( bool param ) + { + if ( param != UseTexture ) + { + UseTexture = param; + int dummy = param ? 1 : 0; + setUniform( USE_TEXTURE, &dummy ); + } + } + + void COGLES2Renderer2d::useAlphaTest( bool param ) + { + if ( param != UseAlphaTest ) + { + UseAlphaTest = param; + int dummy = param ? 1 : 0; + setUniform( ALPHA_TEST, &dummy ); + } + } + + void COGLES2Renderer2d::setAlphaTestValue( float value ) + { + if ( value != AlphaTestValue ) + { + AlphaTestValue = value; + setUniform( ALPHA_VALUE, &AlphaTestValue ); + } + } + + void COGLES2Renderer2d::setOrthoMatrix( const core::matrix4 &matrix ) + { + if ( matrix != OrthoMatrix ) + { + OrthoMatrix = matrix; + setUniform( ORTHO_MATRIX, OrthoMatrix.pointer() ); + } + } + } +} +#endif diff --git a/source/Irrlicht/COGLES2Renderer2D.h b/source/Irrlicht/COGLES2Renderer2D.h new file mode 100644 index 00000000..6b6ee761 --- /dev/null +++ b/source/Irrlicht/COGLES2Renderer2D.h @@ -0,0 +1,54 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#ifndef __C_OGLES2_RENDERER_2D_H_INCLUDED__ +#define __C_OGLES2_RENDERER_2D_H_INCLUDED__ + +#include "COGLES2SLMaterialRenderer.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +namespace irr +{ + namespace io + { + class IFileSystem; + } + namespace video + { + class COGLES2Driver; + + class COGLES2Renderer2d : public COGLES2SLMaterialRenderer + { + public: + COGLES2Renderer2d( COGLES2Driver* driver, io::IFileSystem* fs ); + virtual ~COGLES2Renderer2d() {}; + + void useTexture( bool param ); + void useAlphaTest( bool param ); + void setAlphaTestValue( float param ); + void setOrthoMatrix( const core::matrix4& matrix ); + private : + bool UseTexture; + bool UseAlphaTest; + float AlphaTestValue; + core::matrix4 OrthoMatrix; + private: + enum SHADER_UNIFORM + { + ORTHO_MATRIX = 0, + USE_TEXTURE, + TEXTURE_UNIT, + ALPHA_TEST, + ALPHA_VALUE, + UNIFORM_COUNT + }; + static const char* const sBuiltInShaderUniformNames[]; + }; + + } +} +#endif +#endif diff --git a/source/Irrlicht/COGLES2SLMaterialRenderer.cpp b/source/Irrlicht/COGLES2SLMaterialRenderer.cpp new file mode 100644 index 00000000..86c567df --- /dev/null +++ b/source/Irrlicht/COGLES2SLMaterialRenderer.cpp @@ -0,0 +1,545 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "COGLES2SLMaterialRenderer.h" +#include "IGPUProgrammingServices.h" +#include "IShaderConstantSetCallBack.h" +#include "IMaterialRendererServices.h" +#include "IVideoDriver.h" +#include "os.h" +#include "COGLES2Driver.h" +#include "EVertexAttributes.h" +#include "COGLES2Texture.h" + +#include + +namespace irr +{ + namespace video + { + + //! Constructor + COGLES2SLMaterialRenderer::COGLES2SLMaterialRenderer( video::COGLES2Driver* driver, + s32& outMaterialTypeNr, const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, + video::IMaterialRenderer* baseMaterial, + s32 userData ) + : Driver( driver ), CallBack( callback ), BaseMaterial( baseMaterial ), FileSystem( 0 ), + Program( 0 ), UserData( userData ), UniformStringTable( 0 ), UniformCount( 0 ) + { +#ifdef _DEBUG + setDebugName( "COGLES2SLMaterialRenderer" ); +#endif + + //entry points must always be main, and the compile target isn't selectable + //it is fine to ignore what has been asked for, as the compiler should spot anything wrong + //just check that GLSL is available + + if ( BaseMaterial ) + BaseMaterial->grab(); + + if ( CallBack ) + CallBack->grab(); + + init( outMaterialTypeNr, vertexShaderProgram, pixelShaderProgram ); + } + + + //! constructor only for use by derived classes who want to + //! create a fall back material for example. + COGLES2SLMaterialRenderer::COGLES2SLMaterialRenderer( COGLES2Driver* driver, + io::IFileSystem* fs, + IShaderConstantSetCallBack* callback, + IMaterialRenderer* baseMaterial, + const char* const * uniformStringTable, + const u32& uniformCount, + s32 userData ) + : Driver( driver ), CallBack( callback ), BaseMaterial( baseMaterial ), FileSystem( fs ), + Program( 0 ), UserData( userData ), UniformStringTable( uniformStringTable ), + UniformCount( uniformCount ) + { + if ( BaseMaterial ) + BaseMaterial->grab(); + + if ( CallBack ) + CallBack->grab(); + } + + + //! Destructor + COGLES2SLMaterialRenderer::~COGLES2SLMaterialRenderer() + { + if ( CallBack ) + CallBack->drop(); + + if ( Program ) + { + glDeleteProgram( Program ); + Program = 0; + } + + UniformInfo.clear(); + + AttributeInfo.clear(); + + if ( BaseMaterial ) + BaseMaterial->drop(); + } + + void COGLES2SLMaterialRenderer::init( s32& outMaterialTypeNr, + const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + bool registerMaterial ) + { + outMaterialTypeNr = -1; + + if ( Program == 0 && !createProgram() ) + return; + + if ( vertexShaderProgram ) + if ( !createShader( GL_VERTEX_SHADER, vertexShaderProgram, "" ) ) + return; + + if ( pixelShaderProgram ) + if ( !createShader( GL_FRAGMENT_SHADER, pixelShaderProgram, "" ) ) + return; + + if ( !linkProgram() ) + return; + + // register myself as new material + if ( registerMaterial ) + outMaterialTypeNr = Driver->addMaterialRenderer( this ); + } + + void COGLES2SLMaterialRenderer::initFromFiles( s32 &outMaterialTypeNr, + const c8 *vertexShaderFile, + const c8 *pixelShaderFile, + bool registerMaterial ) + { + if ( !createProgram() ) + { + os::Printer::log( "Could not create shader program.", ELL_ERROR ); + } + + if ( !readVertexShader( vertexShaderFile ) ) + { + os::Printer::log( "Error reading fixed pipeline vertex shader.", ELL_ERROR ); + } + + if ( !readFragmentShader( pixelShaderFile ) ) + { + os::Printer::log( "Error reading fixed pipeline fragment shader.", ELL_ERROR ); + } + + for ( size_t i = 0; i < EVA_COUNT; ++i ) + glBindAttribLocation( Program, i, sBuiltInVertexAttributeNames[i] ); + + if ( !linkProgram() ) + { + os::Printer::log( "Error linking fixed pipeline shader program.", ELL_ERROR ); + } + + if ( registerMaterial ) + outMaterialTypeNr = Driver->addMaterialRenderer( this ); + } + + void COGLES2SLMaterialRenderer::reloadFromFiles( const c8 *vertexShaderFile, + const c8 *pixelShaderFile ) + { + GLsizei shaderCount; + GLuint shaderHandles[2]; + glGetAttachedShaders( Program, 2, &shaderCount, shaderHandles ); + glDetachShader( Program, shaderHandles[0] ); + glDeleteShader( shaderHandles[0] ); + glDetachShader( Program, shaderHandles[1] ); + glDeleteShader( shaderHandles[1] ); + if ( !readVertexShader( vertexShaderFile ) ) + { + os::Printer::log( "Error reading fixed pipeline vertex shader.", ELL_ERROR ); + } + + if ( !readFragmentShader( pixelShaderFile ) ) + { + os::Printer::log( "Error reading fixed pipeline fragment shader.", ELL_ERROR ); + } + + if ( !linkProgram() ) + { + os::Printer::log( "Error linking fixed pipeline shader program.", ELL_ERROR ); + } + } + + bool COGLES2SLMaterialRenderer::readShader( GLenum shaderType, const c8* shaderFile ) + { + wchar_t buf[512]; + io::IReadFile* file = 0; + file = FileSystem->createAndOpenFile( shaderFile ); + if ( !file ) + { + swprintf( buf, 512, L"Could not open shader file : %S", shaderFile ); + os::Printer::log( buf, ELL_ERROR ); + return false; + } + const long size = file->getSize(); + if ( !size ) + { + swprintf( buf, 512, L"%S shader file is empty", shaderFile ); + os::Printer::log( buf, ELL_ERROR ); + file->drop(); + return false; + } + + c8* shader = new c8[size+1]; + file->read( shader, size ); + shader[size] = 0; + + bool success = createShader( shaderType, shader, shaderFile ); + file->drop(); + delete shader; + return success; + } + + bool COGLES2SLMaterialRenderer::readVertexShader( const c8 *vertexShaderFile ) + { + return readShader( GL_VERTEX_SHADER, vertexShaderFile ); + } + + bool COGLES2SLMaterialRenderer::readFragmentShader( const c8 *fragmentShaderFile ) + { + return readShader( GL_FRAGMENT_SHADER, fragmentShaderFile ); + } + + bool COGLES2SLMaterialRenderer::OnRender( IMaterialRendererServices* service, + E_VERTEX_TYPE vtxtype ) + { + // call callback to set shader constants and attributes + if ( CallBack && Program ) + { + CallBack->OnSetAttribute( this, UserData ); + CallBack->OnSetConstants( this, UserData ); + } + + return true; + } + + + bool COGLES2SLMaterialRenderer::PostRender( IMaterialRendererServices* service, + E_VERTEX_TYPE vtxtype ) + { + // call callback to unset shader attributes + if ( CallBack && Program ) + CallBack->OnUnSetAttribute( this, UserData ); + + return true; + } + + void COGLES2SLMaterialRenderer::OnSetMaterial( const video::SMaterial& material, + const video::SMaterial& lastMaterial, + bool resetAllRenderstates, + video::IMaterialRendererServices* services ) + { + if ( material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates ) + { + if ( Program ) + glUseProgram( Program ); + + //let callback know used material + if ( CallBack ) + CallBack->OnSetMaterial( material ); + } + //if (BaseMaterial) + //BaseMaterial->OnSetMaterial(material, material, true, this); + + //for (u32 i=0; isetActiveTexture(i, material.getTexture(i)); + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + } + + + void COGLES2SLMaterialRenderer::OnUnsetMaterial() + { + glUseProgram( 0 ); + + //if (BaseMaterial) + // BaseMaterial->OnUnsetMaterial(); + } + + //! Returns if the material is transparent. + bool COGLES2SLMaterialRenderer::isTransparent() const + { + return BaseMaterial ? BaseMaterial->isTransparent() : false; + } + + bool COGLES2SLMaterialRenderer::createProgram() + { + Program = glCreateProgram(); + return true; + } + + bool COGLES2SLMaterialRenderer::createShader( GLenum shaderType, const char* shader, const char* shaderFile ) + { + GLuint shaderHandle = glCreateShader( shaderType ); + + os::Printer::log("Loading shader", shaderFile); + glShaderSource( shaderHandle, 1, &shader, NULL ); + glCompileShader( shaderHandle ); + + int status = 0; + + glGetShaderiv( shaderHandle, GL_COMPILE_STATUS, &status ); + + if ( !status ) + { + wchar_t buf[512]; + swprintf( buf, 512, L"GLSL shader failed to compile : %S", shaderFile ); + os::Printer::log( buf, ELL_ERROR ); + + // check error message and log it + int maxLength = 0; + GLsizei length; + + glGetShaderiv( shaderHandle, GL_INFO_LOG_LENGTH, &maxLength ); + + char *pInfoLog = new char[maxLength]; + glGetShaderInfoLog( shaderHandle, maxLength, &length, pInfoLog ); + os::Printer::log( reinterpret_cast( pInfoLog ), ELL_ERROR ); + delete [] pInfoLog; + + return false; + } + + glAttachShader( Program, shaderHandle ); + + return true; + } + + bool COGLES2SLMaterialRenderer::linkProgram() + { + glLinkProgram( Program ); + + int status = 0; + + glGetProgramiv( Program, GL_LINK_STATUS, &status ); + + if ( !status ) + { + os::Printer::log( "GLSL shader program failed to link", ELL_ERROR ); + // check error message and log it + int maxLength = 0; + GLsizei length; + + glGetProgramiv( Program, GL_INFO_LOG_LENGTH, &maxLength ); + + char *pInfoLog = new char[maxLength]; + glGetProgramInfoLog( Program, maxLength, &length, pInfoLog ); + os::Printer::log( reinterpret_cast( pInfoLog ), ELL_ERROR ); + delete [] pInfoLog; + + return false; + } + + // get uniforms information + + int num = 0; + + glGetProgramiv( Program, GL_ACTIVE_UNIFORMS, &num ); + + int maxlen = 0; + + glGetProgramiv( Program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxlen ); + + if ( maxlen == 0 && num != 0 ) + { + os::Printer::log( "GLSL: failed to retrieve uniform information", ELL_ERROR ); + return false; + } + + c8 *buf = new c8[maxlen]; + + UniformInfo.clear(); + UniformInfo.reallocate( num ); + + core::array names( num ); + core::array uni( num ); + + for ( int i = 0; i < num; ++i ) + { + memset( buf, 0, maxlen ); + GLint size; + SUniformInfo ui; + glGetActiveUniform( Program, i, maxlen, 0, &size, &ui.type, reinterpret_cast( buf ) ); + ui.location = glGetUniformLocation( Program, buf ); + uni.push_back( ui ); + names.push_back( buf ); + } + + delete [] buf; + + for ( int i = 0; i < UniformCount; ++i ) + { + int j; + for ( j = 0; j < num; ++j ) + { + if ( names[j] == UniformStringTable[i] ) + break; + } + if ( j < num ) + { + UniformInfo.push_back( uni[j] ); + } + else + { + wchar_t buf[512]; + swprintf( buf, 512, L"Unable to find uniform : %S", UniformStringTable[i] ); + os::Printer::log( buf, ELL_WARNING ); + SUniformInfo blank; + blank.location = -1; + blank.type = GL_INVALID_ENUM; + UniformInfo.push_back( blank ); + } + } + + return true; + } + + + void COGLES2SLMaterialRenderer::setBasicRenderStates( const SMaterial& material, + const SMaterial& lastMaterial, + bool resetAllRenderstates ) + { + // forward + Driver->setBasicRenderStates( material, lastMaterial, resetAllRenderstates ); + } + + + bool COGLES2SLMaterialRenderer::setVertexShaderConstant( const c8* name, const f32* floats, int count ) + { + return setPixelShaderConstant( name, floats, count ); + } + + + void COGLES2SLMaterialRenderer::setVertexShaderConstant( const f32* data, s32 startRegister, s32 constantAmount ) + { + os::Printer::log( "Cannot set constant, please use high level shader call instead.", ELL_WARNING ); + } + + bool COGLES2SLMaterialRenderer::setVertexShaderPointer( const c8* name, const void* pointer, + s32 size, bool normalized, u16 stride ) + { + os::Printer::log( "Cannot set constant, use high level shader call.", ELL_WARNING ); + + return false; + } + + void COGLES2SLMaterialRenderer::enableVertexShaderPointer( const c8* name ) + { + os::Printer::log( "Cannot set constant, use high level shader call.", ELL_WARNING ); + } + + void COGLES2SLMaterialRenderer::disableVertexShaderPointer( const c8* name ) + { + os::Printer::log( "Cannot set constant, use high level shader call.", ELL_WARNING ); + } + + bool COGLES2SLMaterialRenderer::setPixelShaderConstant( const c8* name, const f32* floats, int count ) + { + os::Printer::log( "Cannot set constant, use high level shader call.", ELL_WARNING ); + return false; + } + + bool COGLES2SLMaterialRenderer::setUniform( int index, const void* data, int count ) + { + SUniformInfo& ui = UniformInfo[index]; + if ( ui.location == -1 ) + return false; + switch ( ui.type ) + { + case GL_FLOAT: + glUniform1fv( ui.location, count, static_cast( data ) ); + break; + case GL_FLOAT_VEC2: + glUniform2fv( ui.location, count, static_cast( data ) ); + break; + case GL_FLOAT_VEC3: + glUniform3fv( ui.location, count, static_cast( data ) ); + break; + case GL_FLOAT_VEC4: + glUniform4fv( ui.location, count, static_cast( data ) ); + break; + case GL_FLOAT_MAT2: + glUniformMatrix2fv( ui.location, count, false, static_cast( data ) ); + break; + case GL_FLOAT_MAT3: + glUniformMatrix3fv( ui.location, count, false, static_cast( data ) ); + break; + case GL_FLOAT_MAT4: + glUniformMatrix4fv( ui.location, count, false, static_cast( data ) ); + break; + default: + glUniform1iv( ui.location, count, static_cast( data ) ); + break; + } + return !Driver->testGLError(); + } + + bool COGLES2SLMaterialRenderer::setTextureUnit( const c8* name, int unit ) + { + os::Printer::log( "Cannot set constant, use high level shader call.", ELL_WARNING ); + return false; + } + + bool COGLES2SLMaterialRenderer::enableMaterialTexture( const c8* name, int materialId ) + { + ITexture * t = Driver->getTextureByIndex( materialId ); + COGLES2Texture * tex = reinterpret_cast( t ); + if ( !tex ) + return false; + int unit = tex->getOGLES2TextureName(); + + glActiveTexture( GL_TEXTURE0 + unit ); + glBindTexture( GL_TEXTURE_2D, unit ); + + return setTextureUnit( name, unit ); + } + + bool COGLES2SLMaterialRenderer::disableMaterialTexture( int materialId ) + { + COGLES2Texture * tex = reinterpret_cast( Driver->getTextureByIndex( materialId ) ); + if ( !tex ) + return false; + + int unit = tex->getOGLES2TextureName(); + + glActiveTexture( GL_TEXTURE0 + unit ); + glBindTexture( GL_TEXTURE_2D, 0 ); + + return true; + } + + void COGLES2SLMaterialRenderer::setPixelShaderConstant( const f32* data, s32 startRegister, s32 constantAmount ) + { + os::Printer::log( "Cannot set constant, use high level shader call.", ELL_WARNING ); + } + + IVideoDriver* COGLES2SLMaterialRenderer::getVideoDriver() + { + return Driver; + } + + void COGLES2SLMaterialRenderer::useProgram() + { + glUseProgram( Program ); + } + + } // end namespace video +} // end namespace irr + +#endif //_IRR_COMPILE_WITH_OPENGLES2_ diff --git a/source/Irrlicht/COGLES2SLMaterialRenderer.h b/source/Irrlicht/COGLES2SLMaterialRenderer.h new file mode 100644 index 00000000..c0f581aa --- /dev/null +++ b/source/Irrlicht/COGLES2SLMaterialRenderer.h @@ -0,0 +1,141 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#ifndef __C_OGLES2_SL_MATERIAL_RENDERER_H_INCLUDED__ +#define __C_OGLES2_SL_MATERIAL_RENDERER_H_INCLUDED__ + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "IMaterialRenderer.h" +#include "IMaterialRendererServices.h" +#include "IGPUProgrammingServices.h" +#include "irrArray.h" +#include "irrString.h" + +namespace irr +{ + namespace io + { + class IFileSystem; + } + namespace video + { + + class COGLES2Driver; + class IShaderConstantSetCallBack; + +//! Class for using GLSL shaders with OpenGL +//! Please note: This renderer implements its own IMaterialRendererServices + class COGLES2SLMaterialRenderer : public IMaterialRenderer, public IMaterialRendererServices + { + protected: + struct SUniformInfo + { + u32 type; + s32 location; + }; + typedef SUniformInfo SAttributeInfo; + public: + + //! Constructor + COGLES2SLMaterialRenderer( + COGLES2Driver* driver, + s32& outMaterialTypeNr, + const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + IShaderConstantSetCallBack* callback, + IMaterialRenderer* baseMaterial, + s32 userData ); + + //! Destructor + virtual ~COGLES2SLMaterialRenderer(); + + virtual void OnSetMaterial( const SMaterial& material, const SMaterial& lastMaterial, + bool resetAllRenderstates, IMaterialRendererServices* services ); + + virtual bool OnRender( IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype ); + virtual bool PostRender( IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype ); + + virtual void OnUnsetMaterial(); + + //! Returns if the material is transparent. + virtual bool isTransparent() const; + + // implementations for the render services + virtual void setBasicRenderStates( const SMaterial& material, const SMaterial& lastMaterial, bool resetAllRenderstates ); + virtual bool setVertexShaderConstant( const c8* name, const f32* floats, int count ); + virtual void setVertexShaderConstant( const f32* data, s32 startRegister, s32 constantAmount = 1 ); + virtual bool setPixelShaderConstant( const c8* name, const f32* floats, int count ); + virtual void setPixelShaderConstant( const f32* data, s32 startRegister, s32 constantAmount = 1 ); + + bool setUniform( int index, const void* data, int count = 1 ); + + virtual bool setVertexShaderPointer( const c8* name, const void* pointer, s32 size = 3, bool normalized = false, u16 stride = 0 ); + virtual void enableVertexShaderPointer( const c8* name ); + virtual void disableVertexShaderPointer( const c8* name ); + + bool setTextureUnit( const c8* name, int unit ); + + virtual bool enableMaterialTexture( const c8* name, int materialId ); + virtual bool disableMaterialTexture( int materialId ); + + virtual IVideoDriver* getVideoDriver(); + + void useProgram(); + + protected: + + //! constructor only for use by derived classes who want to + //! create a fall back material for example. + COGLES2SLMaterialRenderer( COGLES2Driver* driver, + io::IFileSystem* fs, + IShaderConstantSetCallBack* callback, + IMaterialRenderer* baseMaterial, + const char* const* uniformStringTable, + const u32& uniformCount, + s32 userData = 0 ); + + void init( s32& outMaterialTypeNr, + const c8* vertexShaderProgram, + const c8* pixelShaderProgram, + bool registerMaterial = true ); + + void initFromFiles( s32& outMaterialTypeNr, + const c8* vertexShaderFile, + const c8* pixelShaderFile, + bool registerMaterial = true ); + + void reloadFromFiles( const c8* vertexShaderFile, + const c8* pixelShaderFile ); + + bool readVertexShader( const c8* vertexShaderFile ); + bool readFragmentShader( const c8* fragmentShaderFile ); + bool readShader( u32 shaderType, const c8* shaderFile ); + + bool createProgram(); + bool createShader( u32 shaderType, const char* shader, const char* shaderFile ); + bool linkProgram(); + + COGLES2Driver* Driver; + IShaderConstantSetCallBack* CallBack; + IMaterialRenderer* BaseMaterial; + io::IFileSystem* FileSystem; + + u32 Program; + + core::array UniformInfo; + core::array AttributeInfo; + s32 UserData; + + const char* const* UniformStringTable; + const int UniformCount; + }; + + } // end namespace video +} // end namespace irr + +#endif //_IRR_COMPILE_WITH_OPENGLES2_ +#endif //__C_OPEN_GL_ES2_SL_MATERIAL_RENDERER_H_INCLUDED__ diff --git a/source/Irrlicht/COGLES2Texture.cpp b/source/Irrlicht/COGLES2Texture.cpp new file mode 100644 index 00000000..d7515581 --- /dev/null +++ b/source/Irrlicht/COGLES2Texture.cpp @@ -0,0 +1,738 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h + +#include "IrrCompileConfig.h" + +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +#include "irrTypes.h" +#include "COGLES2Texture.h" +#include "COGLES2Driver.h" +#include "os.h" +#include "CImage.h" +#include "CColorConverter.h" +#include "irrString.h" + +#include +#include +#include + +namespace irr +{ + namespace video + { + +//! constructor for usual textures + COGLES2Texture::COGLES2Texture( IImage* origImage, const io::path& name, COGLES2Driver* driver ) + : ITexture( name ), Driver( driver ), Image( 0 ), + TextureName( 0 ), InternalFormat( GL_RGBA ), PixelFormat( GL_RGBA ), + // TODO ogl-es + // PixelFormat(GL_BGRA), + PixelType( GL_UNSIGNED_BYTE ), + HasMipMaps( true ), IsRenderTarget( false ), AutomaticMipmapUpdate( false ), + UseStencil( false ), ReadOnlyLock( false ) + { +#ifdef _DEBUG + setDebugName( "COGLES2Texture" ); +#endif + + HasMipMaps = Driver->getTextureCreationFlag( ETCF_CREATE_MIP_MAPS ); + getImageData( origImage ); + + if ( Image ) + { + glGenTextures( 1, &TextureName ); + copyTexture(); + } + } + + +//! constructor for basic setup (only for derived classes) + COGLES2Texture::COGLES2Texture( const io::path& name, COGLES2Driver* driver ) + : ITexture( name ), Driver( driver ), Image( 0 ), + TextureName( 0 ), InternalFormat( GL_RGBA ), PixelFormat( GL_RGBA ), + PixelType( GL_UNSIGNED_BYTE ), + HasMipMaps( true ), IsRenderTarget( false ), AutomaticMipmapUpdate( false ), + ReadOnlyLock( false ) + { +#ifdef _DEBUG + setDebugName( "COGLES2Texture" ); +#endif + } + + +//! destructor + COGLES2Texture::~COGLES2Texture() + { + glDeleteTextures( 1, &TextureName ); + if ( Image ) + Image->drop(); + } + + + ECOLOR_FORMAT COGLES2Texture::getBestColorFormat( ECOLOR_FORMAT format ) + { + ECOLOR_FORMAT destFormat = ECF_A8R8G8B8; + switch ( format ) + { + case ECF_A1R5G5B5: + if ( !Driver->getTextureCreationFlag( ETCF_ALWAYS_32_BIT ) ) + destFormat = ECF_A1R5G5B5; + break; + case ECF_R5G6B5: + if ( !Driver->getTextureCreationFlag( ETCF_ALWAYS_32_BIT ) ) + destFormat = ECF_A1R5G5B5; + break; + case ECF_A8R8G8B8: + if ( Driver->getTextureCreationFlag( ETCF_ALWAYS_16_BIT ) || + Driver->getTextureCreationFlag( ETCF_OPTIMIZED_FOR_SPEED ) ) + destFormat = ECF_A1R5G5B5; + break; + case ECF_R8G8B8: + if ( Driver->getTextureCreationFlag( ETCF_ALWAYS_16_BIT ) || + Driver->getTextureCreationFlag( ETCF_OPTIMIZED_FOR_SPEED ) ) + destFormat = ECF_A1R5G5B5; + break; + default: + destFormat = ECF_A8R8G8B8; + break; + } + if ( Driver->getTextureCreationFlag( ETCF_NO_ALPHA_CHANNEL ) ) + { + switch ( destFormat ) + { + case ECF_A1R5G5B5: + destFormat = ECF_R5G6B5; + break; + case ECF_A8R8G8B8: + destFormat = ECF_R8G8B8; + break; + default: + break; + } + } + return destFormat; + } + + + void COGLES2Texture::getImageData( IImage* image ) + { + if ( !image ) + { + os::Printer::log( "No image for OGLES2 texture.", ELL_ERROR ); + return; + } + + ImageSize = image->getDimension(); + + if ( !ImageSize.Width || !ImageSize.Height ) + { + os::Printer::log( "Invalid size of image for OGLES2 Texture.", ELL_ERROR ); + return; + } + + const core::dimension2d nImageSize = ImageSize.getOptimalSize( !Driver->queryFeature( EVDF_TEXTURE_NPOT ) ); + const ECOLOR_FORMAT destFormat = getBestColorFormat( image->getColorFormat() ); + + Image = new CImage( destFormat, nImageSize ); + // copy texture + image->copyToScaling( Image ); + } + + +//! copies the the texture into an open gl texture. + void COGLES2Texture::copyTexture( bool newTexture ) + { + if ( !Image ) + { + os::Printer::log( "No image for OGLES2 texture to upload", ELL_ERROR ); + return; + } + + void( *convert )( const void*, s32, void* ) = 0; + switch ( Image->getColorFormat() ) + { + case ECF_A1R5G5B5: + InternalFormat = GL_RGBA; + PixelFormat = GL_RGBA; + PixelType = GL_UNSIGNED_SHORT_5_5_5_1; + convert = CColorConverter::convert_A1R5G5B5toR5G5B5A1; + break; + case ECF_R5G6B5: + InternalFormat = GL_RGB; + PixelFormat = GL_RGB; + PixelType = GL_UNSIGNED_SHORT_5_6_5; + break; + case ECF_R8G8B8: + InternalFormat = GL_RGB; + PixelFormat = GL_RGB; + PixelType = GL_UNSIGNED_BYTE; + convert = CColorConverter::convert_R8G8B8toB8G8R8; + break; + case ECF_A8R8G8B8: + PixelType = GL_UNSIGNED_BYTE; + if ( !Driver->queryOpenGLFeature( COGLES2ExtensionHandler::IRR_IMG_texture_format_BGRA8888 ) && !Driver->queryOpenGLFeature( COGLES2ExtensionHandler::IRR_EXT_texture_format_BGRA8888 ) ) + { + convert = CColorConverter::convert_A8R8G8B8toA8B8G8R8; + InternalFormat = GL_RGBA; + PixelFormat = GL_RGBA; + } + else + { + InternalFormat = GL_BGRA; + PixelFormat = GL_BGRA; + } + break; + default: + os::Printer::log( "Unsupported texture format", ELL_ERROR ); + break; + } + + glBindTexture( GL_TEXTURE_2D, TextureName ); + if ( Driver->testGLError() ) + os::Printer::log( "Could not bind Texture", ELL_ERROR ); + + if ( newTexture ) + { +#ifndef DISABLE_MIPMAPPING + { + AutomaticMipmapUpdate = false; + regenerateMipMapLevels(); + } +#else + HasMipMaps = false; + os::Printer::log( "Did not create OGLES2 texture mip maps.", ELL_ERROR ); +#endif + { + // enable bilinear filter without mipmaps + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + } + } + + void* source = 0; + IImage* tmpImage = 0; + source = Image->lock(); + if ( convert ) + { + tmpImage = new CImage( Image->getColorFormat(), Image->getDimension() ); + void* dest = tmpImage->lock(); + convert( source, Image->getDimension().getArea(), dest ); + Image->unlock(); + source = dest; + } + if ( newTexture ) + glTexImage2D( GL_TEXTURE_2D, 0, InternalFormat, Image->getDimension().Width, + Image->getDimension().Height, 0, PixelFormat, PixelType, source ); + else + glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, Image->getDimension().Width, + Image->getDimension().Height, PixelFormat, PixelType, source ); + if ( convert ) + { + tmpImage->unlock(); + tmpImage->drop(); + } + else + Image->unlock(); + + if ( Driver->testGLError() ) + os::Printer::log( "Could not glTexImage2D", ELL_ERROR ); + } + + + //! lock function + /** TODO: support miplevel */ + void* COGLES2Texture::lock( bool readOnly, u32 mipmapLevel ) + { + ReadOnlyLock |= readOnly; + + if ( !Image ) + Image = new CImage( ECF_A8R8G8B8, ImageSize ); + if ( IsRenderTarget ) + { + u8* pPixels = static_cast( Image->lock() ); + if ( !pPixels ) + { + return 0; + } + // we need to keep the correct texture bound... + GLint tmpTexture; + glGetIntegerv( GL_TEXTURE_BINDING_2D, &tmpTexture ); + glBindTexture( GL_TEXTURE_2D, TextureName ); + + // TODO ogl-es + // glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, pPixels); + + // opengl images are horizontally flipped, so we have to fix that here. + const u32 pitch = Image->getPitch(); + u8* p2 = pPixels + ( ImageSize.Height - 1 ) * pitch; + u8* tmpBuffer = new u8[pitch]; + for ( u32 i = 0; i < ImageSize.Height; i += 2 ) + { + memcpy( tmpBuffer, pPixels, pitch ); + memcpy( pPixels, p2, pitch ); + memcpy( p2, tmpBuffer, pitch ); + pPixels += pitch; + p2 -= pitch; + } + delete [] tmpBuffer; + Image->unlock(); + + //reset old bound texture + glBindTexture( GL_TEXTURE_2D, tmpTexture ); + } + return Image->lock(); + } + + +//! unlock function + void COGLES2Texture::unlock() + { + Image->unlock(); + if ( !ReadOnlyLock ) + copyTexture( false ); + ReadOnlyLock = false; + } + + +//! Returns size of the original image. + const core::dimension2d& COGLES2Texture::getOriginalSize() const + { + return ImageSize; + } + + +//! Returns size of the texture. + const core::dimension2d& COGLES2Texture::getSize() const + { + if ( Image ) + return Image->getDimension(); + else + return ImageSize; + } + + +//! returns driver type of texture, i.e. the driver, which created the texture + E_DRIVER_TYPE COGLES2Texture::getDriverType() const + { + return EDT_OGLES2; + } + + +//! returns color format of texture + ECOLOR_FORMAT COGLES2Texture::getColorFormat() const + { + if ( Image ) + return Image->getColorFormat(); + else + return ECF_A8R8G8B8; + } + + +//! returns pitch of texture (in bytes) + u32 COGLES2Texture::getPitch() const + { + if ( Image ) + return Image->getPitch(); + else + return 0; + } + + +//! return open gl texture name + GLuint COGLES2Texture::getOGLES2TextureName() const + { + return TextureName; + } + + +//! Returns whether this texture has mipmaps + bool COGLES2Texture::hasMipMaps() const + { + return HasMipMaps; + } + + +//! Regenerates the mip map levels of the texture. + void COGLES2Texture::regenerateMipMapLevels(void* mipmapData) + { + if ( AutomaticMipmapUpdate || !HasMipMaps ) + return; + if (( Image->getDimension().Width == 1 ) && ( Image->getDimension().Height == 1 ) ) + return; + + // Manually create mipmaps + u32 width = Image->getDimension().Width; + u32 height = Image->getDimension().Height; + u32 i = 0; + u8* target = new u8[Image->getImageDataSizeInBytes()]; + do + { + if ( width > 1 ) + width >>= 1; + if ( height > 1 ) + height >>= 1; + ++i; + Image->copyToScaling( target, width, height, Image->getColorFormat() ); + glTexImage2D( GL_TEXTURE_2D, i, InternalFormat, width, height, + 0, PixelFormat, PixelType, target ); + } + while ( width != 1 || height != 1 ); + delete [] target; + Image->unlock(); + } + + + bool COGLES2Texture::isRenderTarget() const + { + return IsRenderTarget; + } + + + bool COGLES2Texture::isFrameBufferObject() const + { + return false; + } + + + void COGLES2Texture::setIsRenderTarget( bool isTarget ) + { + IsRenderTarget = isTarget; + } + + +//! Bind Render Target Texture + void COGLES2Texture::bindRTT() + { + glViewport( 0, 0, getSize().Width, getSize().Height ); + } + + +//! Unbind Render Target Texture + void COGLES2Texture::unbindRTT() + { + glBindTexture( GL_TEXTURE_2D, getOGLES2TextureName() ); + + // Copy Our ViewPort To The Texture + glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, getSize().Width, getSize().Height ); + } + + /* FBO Textures */ + +#ifdef GL_OES_framebuffer_object +// helper function for render to texture + static bool checkFBOStatus( COGLES2Driver* Driver ); +#endif + + +//! RTT ColorFrameBuffer constructor + COGLES2FBOTexture::COGLES2FBOTexture( const core::dimension2d& size, + const io::path& name, + COGLES2Driver* driver, ECOLOR_FORMAT format ) + : COGLES2Texture( name, driver ), DepthTexture( 0 ), ColorFrameBuffer( 0 ) + { +#ifdef _DEBUG + setDebugName( "COGLES2Texture_FBO" ); +#endif + + ECOLOR_FORMAT col = getBestColorFormat( format ); + switch ( col ) + { + case ECF_A8R8G8B8: +#ifdef GL_OES_rgb8_rgba8 + if ( driver->queryOpenGLFeature( video::COGLES2ExtensionHandler::IRR_OES_rgb8_rgba8 ) ) + InternalFormat = GL_RGBA8_OES; + else +#endif + InternalFormat = GL_RGB5_A1; + break; + case ECF_R8G8B8: +#ifdef GL_OES_rgb8_rgba8 + if ( driver->queryOpenGLFeature( video::COGLES2ExtensionHandler::IRR_OES_rgb8_rgba8 ) ) + InternalFormat = GL_RGB8_OES; + else +#endif + InternalFormat = GL_RGB565; + break; + case ECF_A1R5G5B5: + InternalFormat = GL_RGB5_A1; + break; + case ECF_R5G6B5: + InternalFormat = GL_RGB565; + break; + default: + os::Printer::log( "color format not handled", ELL_WARNING ); + break; + } + PixelFormat = GL_RGBA; + PixelType = GL_UNSIGNED_BYTE; + ImageSize = size; + HasMipMaps = false; + IsRenderTarget = true; + +#ifdef GL_OES_framebuffer_object + // generate frame buffer + Driver->extGlGenFramebuffers( 1, &ColorFrameBuffer ); + Driver->extGlBindFramebuffer( GL_FRAMEBUFFER_OES, ColorFrameBuffer ); + + // generate color texture + glGenTextures( 1, &TextureName ); + glBindTexture( GL_TEXTURE_2D, TextureName ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_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 ); + glTexImage2D( GL_TEXTURE_2D, 0, InternalFormat, ImageSize.Width, + ImageSize.Height, 0, PixelFormat, PixelType, 0 ); + + // attach color texture to frame buffer + Driver->extGlFramebufferTexture2D( GL_FRAMEBUFFER_OES, + GL_COLOR_ATTACHMENT0_OES, + GL_TEXTURE_2D, + TextureName, + 0 ); +#endif + unbindRTT(); + } + + +//! destructor + COGLES2FBOTexture::~COGLES2FBOTexture() + { + if ( DepthTexture ) + if ( DepthTexture->drop() ) + Driver->removeDepthTexture( DepthTexture ); + if ( ColorFrameBuffer ) + Driver->deleteFramebuffers( 1, &ColorFrameBuffer ); + } + + + bool COGLES2FBOTexture::isFrameBufferObject() const + { + return true; + } + + +//! Bind Render Target Texture + void COGLES2FBOTexture::bindRTT() + { +#ifdef GL_OES_framebuffer_object + if ( ColorFrameBuffer != 0 ) + Driver->extGlBindFramebuffer( GL_FRAMEBUFFER_OES, ColorFrameBuffer ); +#endif + } + + +//! Unbind Render Target Texture + void COGLES2FBOTexture::unbindRTT() + { +#ifdef GL_OES_framebuffer_object + if ( ColorFrameBuffer != 0 ) + Driver->extGlBindFramebuffer( GL_FRAMEBUFFER_OES, 0 ); +#endif + } + + + /* FBO Depth Textures */ + +//! RTT DepthBuffer constructor + COGLES2FBODepthTexture::COGLES2FBODepthTexture( + const core::dimension2d& size, + const io::path& name, + COGLES2Driver* driver, + bool useStencil ) + : COGLES2FBOTexture( size, name, driver ), DepthRenderBuffer( 0 ), + StencilRenderBuffer( 0 ), UseStencil( useStencil ) + { +#ifdef _DEBUG + setDebugName( "COGLES2TextureFBO_Depth" ); +#endif + + ImageSize = size; +#ifdef GL_OES_depth24 + InternalFormat = GL_DEPTH_COMPONENT24_OES; +#elif defined(GL_OES_depth32) + InternalFormat = GL_DEPTH_COMPONENT32_OES; +#else + InternalFormat = GL_DEPTH_COMPONENT16_OES; +#endif + + PixelFormat = GL_RGBA; + PixelType = GL_UNSIGNED_BYTE; + HasMipMaps = false; + + if ( useStencil ) + { +#ifdef GL_OES_packed_depth_stencil + glGenTextures( 1, &DepthRenderBuffer ); + glBindTexture( GL_TEXTURE_2D, DepthRenderBuffer ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_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 ( Driver->queryOpenGLFeature( COGLES2ExtensionHandler::IRR_OES_packed_depth_stencil ) ) + { + // generate packed depth stencil texture + glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_STENCIL_OES, ImageSize.Width, + ImageSize.Height, 0, GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES, 0 ); + StencilRenderBuffer = DepthRenderBuffer; // stencil is packed with depth + return; + } +#endif +#if defined(GL_OES_framebuffer_object) && (defined(GL_OES_stencil1) || defined(GL_OES_stencil4) || defined(GL_OES_stencil8)) + // generate stencil buffer + Driver->extGlGenRenderbuffers( 1, &StencilRenderBuffer ); + Driver->extGlBindRenderbuffer( GL_RENDERBUFFER_OES, StencilRenderBuffer ); + Driver->extGlRenderbufferStorage( GL_RENDERBUFFER_OES, +#if defined(GL_OES_stencil8) + GL_STENCIL_INDEX8_OES, +#elif defined(GL_OES_stencil4) + GL_STENCIL_INDEX4_OES, +#elif defined(GL_OES_stencil1) + GL_STENCIL_INDEX1_OES, +#endif + ImageSize.Width, ImageSize.Height ); +#endif + } +#ifdef GL_OES_framebuffer_object + // generate depth buffer + Driver->extGlGenRenderbuffers( 1, &DepthRenderBuffer ); + Driver->extGlBindRenderbuffer( GL_RENDERBUFFER_OES, DepthRenderBuffer ); + Driver->extGlRenderbufferStorage( GL_RENDERBUFFER_OES, + InternalFormat, ImageSize.Width, ImageSize.Height ); +#endif + } + + +//! destructor + COGLES2FBODepthTexture::~COGLES2FBODepthTexture() + { + if ( DepthRenderBuffer && UseStencil ) + glDeleteTextures( 1, &DepthRenderBuffer ); + else + Driver->deleteRenderbuffers( 1, &DepthRenderBuffer ); + if ( StencilRenderBuffer && StencilRenderBuffer != DepthRenderBuffer ) + glDeleteTextures( 1, &StencilRenderBuffer ); + } + + +//combine depth texture and rtt + void COGLES2FBODepthTexture::attach( ITexture* renderTex ) + { + if ( !renderTex ) + return; + video::COGLES2FBOTexture* rtt = static_cast( renderTex ); + rtt->bindRTT(); +#ifdef GL_OES_framebuffer_object + if ( UseStencil ) + { + // attach stencil texture to stencil buffer + Driver->extGlFramebufferTexture2D( GL_FRAMEBUFFER_OES, + GL_STENCIL_ATTACHMENT_OES, + GL_TEXTURE_2D, + StencilRenderBuffer, + 0 ); + + // attach depth texture to depth buffer + Driver->extGlFramebufferTexture2D( GL_FRAMEBUFFER_OES, + GL_DEPTH_ATTACHMENT_OES, + GL_TEXTURE_2D, + DepthRenderBuffer, + 0 ); + } + else + { + // attach depth renderbuffer to depth buffer + Driver->extGlFramebufferRenderbuffer( GL_FRAMEBUFFER_OES, + GL_DEPTH_ATTACHMENT_OES, + GL_RENDERBUFFER_OES, + DepthRenderBuffer ); + } + // check the status + if ( !checkFBOStatus( Driver ) ) + os::Printer::log( "FBO incomplete" ); +#endif + rtt->DepthTexture = this; + grab(); // grab the depth buffer, not the RTT + rtt->unbindRTT(); + } + + +//! Bind Render Target Texture + void COGLES2FBODepthTexture::bindRTT() + { + } + + +//! Unbind Render Target Texture + void COGLES2FBODepthTexture::unbindRTT() + { + } + + +#ifdef GL_OES_framebuffer_object + bool checkFBOStatus( COGLES2Driver* Driver ) + { + GLenum status = Driver->extGlCheckFramebufferStatus( GL_FRAMEBUFFER_OES ); + + switch ( status ) + { + //Our FBO is perfect, return true + case GL_FRAMEBUFFER_COMPLETE_OES: + return true; + + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES: + os::Printer::log( "FBO has one or several incomplete image attachments", ELL_ERROR ); + break; + + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES: + os::Printer::log( "FBO missing an image attachment", ELL_ERROR ); + break; + + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES: + os::Printer::log( "FBO has one or several image attachments with different dimensions", ELL_ERROR ); + break; + + case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES: + os::Printer::log( "FBO has one or several image attachments with different internal formats", ELL_ERROR ); + break; + +// not part of all implementations +#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_OES: + os::Printer::log( "FBO has invalid draw buffer", ELL_ERROR ); + break; +#endif + +// not part of all implementations +#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_OES: + os::Printer::log( "FBO has invalid read buffer", ELL_ERROR ); + break; +#endif + +// not part of fbo_object anymore, but won't harm as it is just a return value +#ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_OES + case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_OES: + os::Printer::log( "FBO has a duplicate image attachment", ELL_ERROR ); + break; +#endif + + case GL_FRAMEBUFFER_UNSUPPORTED_OES: + os::Printer::log( "FBO format unsupported", ELL_ERROR ); + break; + + default: + break; + } + os::Printer::log( "FBO error", ELL_ERROR ); + return false; + } +#endif + + } // end namespace video +} // end namespace irr + +#endif // _IRR_COMPILE_WITH_OGLES21_ + diff --git a/source/Irrlicht/COGLES2Texture.h b/source/Irrlicht/COGLES2Texture.h new file mode 100644 index 00000000..7ab73ab3 --- /dev/null +++ b/source/Irrlicht/COGLES2Texture.h @@ -0,0 +1,163 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#ifndef __C_OGLES2_TEXTURE_H_INCLUDED__ +#define __C_OGLES2_TEXTURE_H_INCLUDED__ + +#include "ITexture.h" +#include "IImage.h" + +#include "IrrCompileConfig.h" +#ifdef _IRR_COMPILE_WITH_OGLES2_ + +namespace irr +{ + namespace video + { + + class COGLES2Driver; +//! OGLES21 texture. + class COGLES2Texture : public ITexture + { + public: + + //! constructor + COGLES2Texture( IImage* surface, const io::path& name, COGLES2Driver* driver = 0 ); + + //! destructor + virtual ~COGLES2Texture(); + + //! lock function + virtual void* lock( bool readOnly=false, u32 mipmapLevel=0 ); + + //! unlock function + virtual void unlock(); + + //! Returns original size of the texture (image). + virtual const core::dimension2d& getOriginalSize() const; + + //! Returns size of the texture. + virtual const core::dimension2d& getSize() const; + + //! returns driver type of texture (=the driver, that created it) + virtual E_DRIVER_TYPE getDriverType() const; + + //! returns color format of texture + virtual ECOLOR_FORMAT getColorFormat() const; + + //! returns pitch of texture (in bytes) + virtual u32 getPitch() const; + + //! return open gl texture name + u32 getOGLES2TextureName() const; + + //! return whether this texture has mipmaps + virtual bool hasMipMaps() const; + + //! Regenerates the mip map levels of the texture. + virtual void regenerateMipMapLevels(void* mipmapData=0); + + //! Is it a render target? + virtual bool isRenderTarget() const; + + //! Is it a FrameBufferObject? + virtual bool isFrameBufferObject() const; + + //! Bind RenderTargetTexture + void bindRTT(); + + //! Unbind RenderTargetTexture + void unbindRTT(); + + //! sets whether this texture is intended to be used as a render target. + void setIsRenderTarget( bool isTarget ); + + protected: + + //! protected constructor with basic setup, no GL texture name created, for derived classes + COGLES2Texture( const io::path& name, COGLES2Driver* driver ); + + //! get the desired color format based on texture creation flags and the input format. + ECOLOR_FORMAT getBestColorFormat( ECOLOR_FORMAT format ); + + //! convert the image into an internal image with better properties for this driver. + void getImageData( IImage* image ); + + //! copies the the texture into an open gl texture. + void copyTexture( bool newTexture = true ); + + core::dimension2d ImageSize; + COGLES2Driver* Driver; + IImage* Image; + + u32 TextureName; + s32 InternalFormat; + u32 PixelFormat; + u32 PixelType; + + bool HasMipMaps; + bool IsRenderTarget; + bool AutomaticMipmapUpdate; + bool UseStencil; + bool ReadOnlyLock; + }; + + +//! OGLES21 FBO texture. + class COGLES2FBOTexture : public COGLES2Texture + { + public: + + //! FrameBufferObject constructor + COGLES2FBOTexture( const core::dimension2d& size, const io::path& name, COGLES2Driver* driver = 0, ECOLOR_FORMAT format = ECF_UNKNOWN ); + + //! destructor + virtual ~COGLES2FBOTexture(); + + //! Is it a FrameBufferObject? + virtual bool isFrameBufferObject() const; + + //! Bind RenderTargetTexture + virtual void bindRTT(); + + //! Unbind RenderTargetTexture + virtual void unbindRTT(); + + ITexture* DepthTexture; + protected: + u32 ColorFrameBuffer; + }; + + +//! OGLES21 FBO depth texture. + class COGLES2FBODepthTexture : public COGLES2FBOTexture + { + public: + //! FrameBufferObject depth constructor + COGLES2FBODepthTexture( const core::dimension2d& size, const io::path& name, COGLES2Driver* driver = 0, bool useStencil = false ); + + //! destructor + virtual ~COGLES2FBODepthTexture(); + + //! Bind RenderTargetTexture + virtual void bindRTT(); + + //! Unbind RenderTargetTexture + virtual void unbindRTT(); + + void attach( ITexture* ); + + protected: + u32 DepthRenderBuffer; + u32 StencilRenderBuffer; + bool UseStencil; + }; + + + } // end namespace video +} // end namespace irr + +#endif +#endif // _IRR_COMPILE_WITH_OGLES2_ diff --git a/source/Irrlicht/COGLES2Utils.h b/source/Irrlicht/COGLES2Utils.h new file mode 100644 index 00000000..7b883f95 --- /dev/null +++ b/source/Irrlicht/COGLES2Utils.h @@ -0,0 +1,58 @@ +// Copyright (C) 2009-2010 Amundis +// Heavily based on the OpenGL driver implemented by Nikolaus Gebhardt +// and OpenGL ES driver implemented by Christian Stehno +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in Irrlicht.h +#ifndef __OGLES2_UTILS_H_INCLUDED__ +#define __OGLES2_UTILS_H_INCLUDED__ + +namespace irr +{ + namespace video + { + + inline void scolorfToRGBAfloat4( const SColorf& inColor, float* outColor ) + { + outColor[0] = inColor.r; + outColor[1] = inColor.g; + outColor[2] = inColor.b; + outColor[3] = inColor.a; + } + + inline void vector3dfToFloat4( const core::vector3df& inVector, float* outVector, float inW ) + { + outVector[0] = inVector.X; + outVector[1] = inVector.Y; + outVector[2] = inVector.Z; + outVector[3] = inW; + } + + inline void vector3dfToFloat3( const core::vector3df& inVector, float* outVector ) + { + outVector[0] = inVector.X; + outVector[1] = inVector.Y; + outVector[2] = inVector.Z; + } + + inline void scolortoFloat4( const SColor &irrColor, float *glColor ) + { + const float inv = 1.f / 255.f; + glColor[0] = irrColor.getRed() * inv; + glColor[1] = irrColor.getGreen() * inv; + glColor[2] = irrColor.getBlue() * inv; + glColor[3] = irrColor.getAlpha() * inv; + } + + inline bool operator!=( const SColorf& a, const SColorf& b ) + { + if ( a.r != b.r ) return true; + if ( a.g != b.g ) return true; + if ( a.b != b.b ) return true; + if ( a.a != b.a ) return true; + return false; + } + + } // end namespace video +} // end namespace irr + +#endif //__OGLES2_UTILS_H_INCLUDED__ diff --git a/source/Irrlicht/Irrlicht9.0.vcproj b/source/Irrlicht/Irrlicht9.0.vcproj index 892809c5..941827fe 100644 --- a/source/Irrlicht/Irrlicht9.0.vcproj +++ b/source/Irrlicht/Irrlicht9.0.vcproj @@ -2668,6 +2668,82 @@ > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +