Commits

Michael Ludwig committed 60583c9

Restrict available texture types in FFP renderer.
Fix offsets bug in setUniformArray() for ivec3's.
Update fragment shader to use corrected texture access.
Properly reset the viewport during reset() in the FFP emulator.

Comments (0)

Files changed (5)

ferox-renderer/src/main/java/com/ferox/renderer/FixedFunctionRenderer.java

  * <p/>
  * The FixedFunctionRenderer describes a Renderer that exposes the majority of useful state described by the
  * fixed-function pipeline of pre-3.1 OpenGL implementations. Although the OpenGL versions between 2.0 and 3.0
- * had support for GLSL shaders (and even earlier using extensions), this Renderer does not expose that since
+ * have support for GLSL shaders (and even earlier using extensions), this Renderer does not expose that since
  * it's more robust to completely separate fixed and programmable pipelines.
  * <p/>
- * For the purposes of lighting, the renderer supports 8 simultaneous lights. For the purposes of texturing,
- * the renderer supports 4 simultaneous textures. Lighting is computed using the Blinn-Phong model adopted by
- * OpenGL and will use single-sided lighting, separate specular colors, and smooth shading.
+ * To support easy shader emulation, the renderer imposes slightly more restrictions than the actual
+ * fixed-function specification of OpenGL.  Hardware that does not even meet these restrictions will not work
+ * with Ferox at all. For the purposes of lighting, the renderer supports 8 simultaneous lights.  Lighting is
+ * computed using the Blinn-Phong model adopted by OpenGL and will use single-sided lighting, separate
+ * specular colors, and smooth shading. For the purposes of texturing, the renderer supports 4 simultaneous
+ * textures. Only {@link Texture1D}, {@link Texture2D}, {@link TextureCubeMap} and {@link DepthMap2D} can be
+ * used.
  *
  * @author Michael Ludwig
  */
      * @param tex   The texture unit
      * @param image The Texture to be bound to tex
      *
-     * @throws IllegalArgumentException  if tex is less than 0
-     * @throws IndexOutOfBoundsException if tex is greater than or equal to 4, or if tex is less than 0
+     * @throws IllegalArgumentException      if tex is less than 0
+     * @throws IndexOutOfBoundsException     if tex is greater than or equal to 4, or if tex is less than 0
+     * @throws UnsupportedOperationException if image is not a Texture1D, Texture2D, TextureCubeMap or
+     *                                       DepthMap2D
      */
     public void setTexture(int tex, Sampler image);
 

ferox-renderer/src/main/java/com/ferox/renderer/impl/AbstractFixedFunctionRenderer.java

             if (image.isDestroyed()) {
                 throw new ResourceException("Cannot use a destroyed resource");
             }
+            if (!(image instanceof Texture1D) && !(image instanceof Texture2D) &&
+                !(image instanceof TextureCubeMap) && !(image instanceof DepthMap2D)) {
+                throw new UnsupportedOperationException(
+                        image.getClass() + " cannot be used in a FixedFunctionRenderer");
+            }
 
             TextureImpl.TextureHandle newImage = ((TextureImpl) image).getHandle();
             enableTexture(tex, newImage);

ferox-renderer/src/main/java/com/ferox/renderer/impl/AbstractGlslRenderer.java

         if (!u.initialized || u.intValues.get(offset) != v1 || u.intValues.get(offset + 1) != v2 ||
             u.intValues.get(offset + 2) != v3) {
             u.initialized = true;
-            u.intValues.put(0, v1);
-            u.intValues.put(1, v2);
-            u.intValues.put(2, v3);
+            u.intValues.put(offset, v1);
+            u.intValues.put(offset + 1, v2);
+            u.intValues.put(offset + 2, v3);
 
             glUniform(ix(u, index), u.getType(), u.intValues);
         }

ferox-renderer/src/main/java/com/ferox/renderer/impl/ShaderFixedFunctionEmulator.java

     private Shader shader;
     private ContextState<GlslRenderer> defaultState;
 
+    // the getCurrentState() records the valid viewport dimensions of the original surface, which
+    // we don't want to preserve so we remember the surface dimensions in activate() and apply them in reset()
+    private int resetSurfaceWidth;
+    private int resetSurfaceHeight;
+
     /*
      * Vertex shader uniforms
      */
 
     private Shader.Uniform sampler1D; // sampler1D[4]
     private Shader.Uniform sampler2D; // sampler2D[4]
-    private Shader.Uniform sampler3D; // sampler3D[4]
     private Shader.Uniform samplerCube; // samplerCube[4]
+    private Shader.Uniform sampler2DShadow; // sampler2DShadow[4]
     private Shader.Uniform texConfig; // int[4]
-    private Shader.Uniform depthComparison; // int[4]
 
     private Shader.Uniform combineSrcAlpha; // ivec3[4]
     private Shader.Uniform combineSrcRGB; // ivec3[4]
     @Override
     public void reset() {
         glsl.setCurrentState(defaultState);
+        glsl.setViewport(0, 0, resetSurfaceWidth, resetSurfaceHeight);
     }
 
     @Override
 
     @Override
     public void setTexture(int tex, Sampler image) {
-        // FIXME set others to null?
         if (image instanceof Texture1D) {
             glsl.setUniformArray(sampler1D, tex, image);
             glsl.setUniformArray(texConfig, tex, 0);
-            glsl.setUniformArray(depthComparison, tex, -1);
         } else if (image instanceof Texture2D) {
             glsl.setUniformArray(sampler2D, tex, image);
             glsl.setUniformArray(texConfig, tex, 1);
-            glsl.setUniformArray(depthComparison, tex, -1);
-        } else if (image instanceof Texture3D) {
-            glsl.setUniformArray(sampler3D, tex, image);
-            glsl.setUniformArray(texConfig, tex, 2);
-            glsl.setUniformArray(depthComparison, tex, -1);
         } else if (image instanceof TextureCubeMap) {
             glsl.setUniformArray(samplerCube, tex, image);
-            glsl.setUniformArray(texConfig, tex, 3);
-            glsl.setUniformArray(depthComparison, tex, -1);
+            glsl.setUniformArray(texConfig, tex, 2);
         } else if (image instanceof DepthMap2D) {
-            glsl.setUniformArray(sampler2D, tex, image);
-            glsl.setUniformArray(texConfig, tex, 1);
+            DepthMap2D map = (DepthMap2D) image;
 
-            DepthMap2D map = (DepthMap2D) image;
-            int compare = (map.getDepthComparison() == null ? -1 : map.getDepthComparison().ordinal());
-            glsl.setUniformArray(depthComparison, tex, compare);
+            if (map.getDepthComparison() != null) {
+                // use shadow sampler
+                glsl.setUniformArray(sampler2DShadow, tex, image);
+                glsl.setUniformArray(texConfig, tex, 3);
+            } else {
+                // treat it like its a regular 2d texture
+                glsl.setUniformArray(sampler2D, tex, image);
+                glsl.setUniformArray(texConfig, tex, 1);
+            }
+        } else if (image != null) {
+            throw new UnsupportedOperationException(
+                    image.getClass() + " not supported in FixedFunctionRenderer");
         } else {
             glsl.setUniformArray(texConfig, tex, -1);
         }
             loadVariables();
             loadDefaultState();
         }
+
+        resetSurfaceWidth = surface.getWidth();
+        resetSurfaceHeight = surface.getHeight();
     }
 
     private void loadVariables() {
 
         sampler1D = shader.getUniform("uTex1D");
         sampler2D = shader.getUniform("uTex2D");
-        sampler3D = shader.getUniform("uTex3D");
+        sampler2DShadow = shader.getUniform("uTexShadow");
         samplerCube = shader.getUniform("uTexCube");
         texConfig = shader.getUniform("uTexConfig");
-        depthComparison = shader.getUniform("uDepthComparison");
 
         combineSrcAlpha = shader.getUniform("uCombineSrcAlpha");
         combineSrcRGB = shader.getUniform("uCombineSrcRGB");
         glsl.bindAttribute(vertices, new Vector4(0, 0, 0, 1));
         glsl.bindAttribute(normals, new Vector3(0, 0, 1));
 
-
         defaultState = glsl.getCurrentState();
     }
 

ferox-renderer/src/main/resources/com/ferox/renderer/impl/ffp.frag

 // is the minimum required for OpenGL 3
 uniform sampler1D uTex1D[4];
 uniform sampler2D uTex2D[4];
-uniform sampler3D uTex3D[4];
 uniform samplerCube uTexCube[4];
-uniform int uTexConfig[4]; // neg. value is disabled, 0 = 1D, 1 = 2D, 2 = 3D, 3 = cube
-uniform int uDepthComparison[4]; // -1 for disabled, otherwise ordinal of Comparison
+uniform sampler2DShadow uTexShadow[4];
+uniform int uTexConfig[4]; // neg. value is disabled, 0 = 1D, 1 = 2D, 2 = cube, 3 = 2D shadow
 
 uniform ivec3 uCombineSrcAlpha[4]; // xyz represent 0,1,2 arguments to the functions
 uniform ivec3 uCombineSrcRGB[4]; // values are ordinal of CombineSource and CombineOperand
 vec4 sampleTexture(const int tex) {
     switch(uTexConfig[tex]) {
         case 0: // 1D
-            float coord1 = vTexCoord[tex].s / vTexCoord[tex].q;
-            return texture(uTex1D[tex], coord1);
+            return texture(uTex1D[tex], vTexCoord[tex].s / vTexCoord[tex].q);
             //return vec4(1.0, 0.0, 0.0, 1.0);
         case 1: // 2D
-            if (uDepthComparison[tex] >= 0) {
-                // depth comparison
-                vec3 coord = vTexCoord[tex].stp / vTexCoord[tex].q;
-                float d = texture(uTex2D[tex], coord.st).r;
-
-                if (compare(d, coord.p, uDepthComparison[tex])) {
-                    return vec4(1.0);
-                } else {
-                    return vec4(0.0);
-                }
-                //return vec4(0.0, 0.5, 0.5, 1.0);
-            } else {
-                // regular texture
-                vec2 coord = vTexCoord[tex].st / vTexCoord[tex].q;
-                return texture(uTex2D[tex], coord);
-                //return vec4(0.0, 1.0, 0.0, 1.0);
-            }
-        case 2: // 3D
-            vec3 coord3 = vTexCoord[tex].stp / vTexCoord[tex].q;
-            return texture(uTex3D[tex], coord3);
-            //return vec4(0.0, 0.0, 1.0, 1.0);
-        case 3: // CUBE
-            vec3 coord4 = vTexCoord[tex].stp; // no divide needed for cube maps
-            return texture(uTexCube[tex], coord4);
+            return texture(uTex2D[tex], vTexCoord[tex].st / vTexCoord[tex].q);
+            //return vec4(0.0, 1.0, 0.0, 1.0);
+        case 2: // CUBE
+            return texture(uTexCube[tex], vTexCoord[tex].stp); // no divide needed for cube maps
             //return vec4(1.0, 1.0, 0.0, 1.0);
+        case 4: // 2D Shadow
+            return vec4(texture(uTexShadow[tex], vTexCoord[tex].stp / vTexCoord[tex].q));
         default: // disabled
-            return vec4(1.0, 0.0, 1.0, 1.0);
+            return vec4(0.0, 0.0, 0.0, 1.0);
     }
 }
 
-vec4 select(const vec4 tex0, const vec4 tex1, const vec4 tex2, const vec4 tex3,
-            const vec4 currTex, const vec4 prevTex, const vec4 primary, const vec4 constant,
-            const int srcRGB, const int opRGB, const int srcAlpha, const int opAlpha) {
+vec4 select(const int arg, const int unit, const vec4 tex[4], const vec4 prevTex) {
     vec4 selectRGB = vec4(0.0, 0.0, 0.0, 1.0);
     float selectAlpha = 0.0;
     vec3 postRGB = vec3(0.0, 0.0, 0.0);
     float postAlpha = 0.0;
 
     // compute postRGB = opRGB(srcRBG)
-    switch(srcRGB) {
+    switch(uCombineSrcRGB[unit][arg]) {
         case 0: // CURR_TEX
-            selectRGB = currTex;
+            selectRGB = tex[unit];
             break;
         case 1: // PREV_TEX
             selectRGB = prevTex;
             break;
         case 2: // CONSTANT
-            selectRGB = constant;
+            selectRGB = uCombineColor[unit];
             break;
         case 3: // PRIMARY
-            selectRGB = primary;
+            selectRGB = vPrimaryColor;
             break;
         case 4: // TEX0
-            selectRGB = tex0;
+            selectRGB = tex[0];
             break;
         case 5: // TEX1
-            selectRGB = tex1;
+            selectRGB = tex[1];
             break;
         case 6: // TEX2
-            selectRGB = tex2;
+            selectRGB = tex[2];
+            break;
         case 7: // TEX3
-            selectRGB = tex3;
+            selectRGB = tex[3];
+            break;
     }
-    switch(opRGB) {
+    switch(uCombineOpRGB[unit][arg]) {
         case 0: // COLOR
             postRGB = selectRGB.rgb;
             break;
     }
 
     // compute postAlpha = opAlpha(srcAlpha)
-    switch(srcAlpha) {
+    switch(uCombineSrcAlpha[unit][arg]) {
         case 0: // CURR_TEX
-            selectAlpha = currTex.a;
+            selectAlpha = tex[0].a;
             break;
         case 1: // PREV_TEX
             selectAlpha = prevTex.a;
             break;
         case 2: // CONSTANT
-            selectAlpha = constant.a;
+            selectAlpha = uCombineColor[unit].a;
             break;
         case 3: // PRIMARY
-            selectAlpha = primary.a;
+            selectAlpha = vPrimaryColor.a;
             break;
         case 4: // TEX0
-            selectAlpha = tex0.a;
+            selectAlpha = tex[0].a;
             break;
         case 5: // TEX1
-            selectAlpha = tex1.a;
+            selectAlpha = tex[1].a;
             break;
         case 6: // TEX2
-            selectAlpha = tex2.a;
+            selectAlpha = tex[2].a;
             break;
         case 7: // TEX3
-            selectAlpha = tex3.a;
+            selectAlpha = tex[3].a;
             break;
     }
-    switch(opAlpha) {
+    switch(uCombineOpAlpha[unit][arg]) {
         case 1: // ALPHA
             postAlpha = selectAlpha;
             break;
 }
 
 vec4 evaluateUnit(const int unit, const vec4 tex[4], const vec4 prevColor) {
-    ivec3 srcRGB = uCombineSrcRGB[unit];
-    ivec3 srcAlpha = uCombineSrcAlpha[unit];
-    ivec3 opRGB = uCombineOpRGB[unit];
-    ivec3 opAlpha = uCombineOpAlpha[unit];
-
-    vec4 arg0 = select(tex[0], tex[1], tex[2], tex[3], tex[unit], prevColor, vPrimaryColor, uCombineColor[unit],
-                       srcRGB.x, opRGB.x, srcAlpha.x, opAlpha.x);
-    vec4 arg1 = select(tex[0], tex[1], tex[2], tex[3], tex[unit], prevColor, vPrimaryColor, uCombineColor[unit],
-                       srcRGB.y, opRGB.y, srcAlpha.y, opAlpha.y);
-    vec4 arg2 = select(tex[0], tex[1], tex[2], tex[3], tex[unit], prevColor, vPrimaryColor, uCombineColor[unit],
-                       srcRGB.z, opRGB.z, srcAlpha.z, opAlpha.z);
+    vec4 arg0 = select(0, unit, tex, prevColor);
+    vec4 arg1 = select(1, unit, tex, prevColor);
+    vec4 arg2 = select(2, unit, tex, prevColor);
 
     float alpha = 0.0;
     switch(uCombineFuncAlpha[unit]) {