aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp/opengl/util/glsl
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-02-23 14:51:06 +0100
committerSven Gothel <[email protected]>2014-02-23 14:51:06 +0100
commit3352601e0860584509adf2b76f993d03893ded4b (patch)
tree974fccc8c0eb2f5ad9d4ffd741dfc35869ed67b5 /src/jogl/classes/com/jogamp/opengl/util/glsl
parentf51933f0ebe9ae030c26c066e59a728ce08b8559 (diff)
parentc67de337a8aaf52e36104c3f13e273aa19d21f1f (diff)
Merge branch 'master' into stash_glyphcache
Conflicts: make/scripts/tests.sh src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java src/jogl/classes/com/jogamp/graph/curve/Region.java src/jogl/classes/com/jogamp/graph/curve/opengl/GLRegion.java src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java src/jogl/classes/com/jogamp/graph/font/Font.java src/jogl/classes/com/jogamp/opengl/math/VectorUtil.java src/jogl/classes/jogamp/graph/curve/text/GlyphShape.java src/jogl/classes/jogamp/graph/curve/text/GlyphString.java src/jogl/classes/jogamp/graph/font/typecast/TypecastFont.java src/jogl/classes/jogamp/graph/font/typecast/TypecastGlyph.java src/jogl/classes/jogamp/graph/font/typecast/TypecastRenderer.java
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl/util/glsl')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java387
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java86
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java524
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java99
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/fixedfunc/FixedFuncUtil.java50
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/fixedfunc/ShaderSelectionMode.java27
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java7
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShaderNVidia.java4
8 files changed, 762 insertions, 422 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java
index f6b686d7e..6a64edeb5 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java
@@ -45,13 +45,16 @@ import java.util.Set;
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GL3;
import javax.media.opengl.GLES2;
+import javax.media.opengl.GLContext;
import javax.media.opengl.GLException;
import jogamp.opengl.Debug;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.util.IOUtil;
+import com.jogamp.common.util.VersionNumber;
/**
* Convenient shader code class to use and instantiate vertex or fragment programs.
@@ -59,33 +62,38 @@ import com.jogamp.common.util.IOUtil;
* A documented example of how to use this code is available
* {@link #create(GL2ES2, int, Class, String, String, String, boolean) here} and
* {@link #create(GL2ES2, int, int, Class, String, String[], String, String) here}.
- * </p>
+ * </p>
*/
public class ShaderCode {
- public static final boolean DEBUG = Debug.debug("GLSLCode");
public static final boolean DEBUG_CODE = Debug.isPropertyDefined("jogl.debug.GLSLCode", true);
/** Unique resource suffix for {@link GL2ES2#GL_VERTEX_SHADER} in source code: <code>vp</code> */
public static final String SUFFIX_VERTEX_SOURCE = "vp" ;
-
+
/** Unique resource suffix for {@link GL2ES2#GL_VERTEX_SHADER} in binary: <code>bvp</code> */
public static final String SUFFIX_VERTEX_BINARY = "bvp" ;
-
+
+ /** Unique resource suffix for {@link GL3#GL_GEOMETRY_SHADER} in source code: <code>gp</code> */
+ public static final String SUFFIX_GEOMETRY_SOURCE = "gp" ;
+
+ /** Unique resource suffix for {@link GL3#GL_GEOMETRY_SHADER} in binary: <code>bgp</code> */
+ public static final String SUFFIX_GEOMETRY_BINARY = "bgp" ;
+
/** Unique resource suffix for {@link GL2ES2#GL_FRAGMENT_SHADER} in source code: <code>fp</code> */
public static final String SUFFIX_FRAGMENT_SOURCE = "fp" ;
-
+
/** Unique resource suffix for {@link GL2ES2#GL_FRAGMENT_SHADER} in binary: <code>bfp</code> */
public static final String SUFFIX_FRAGMENT_BINARY = "bfp" ;
-
+
/** Unique relative path for binary shader resources for {@link GLES2#GL_NVIDIA_PLATFORM_BINARY_NV NVIDIA}: <code>nvidia</code> */
public static final String SUB_PATH_NVIDIA = "nvidia" ;
/**
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER} or {@link GL2ES2#GL_FRAGMENT_SHADER}
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
* @param count number of shaders
* @param source CharSequence array containing the shader sources, organized as <code>source[count][strings-per-shader]</code>.
* May be either an immutable <code>String</code> - or mutable <code>StringBuilder</code> array.
- *
+ *
* @throws IllegalArgumentException if <code>count</count> and <code>source.length</code> do not match
*/
public ShaderCode(int type, int count, CharSequence[][] source) {
@@ -95,6 +103,7 @@ public class ShaderCode {
switch (type) {
case GL2ES2.GL_VERTEX_SHADER:
case GL2ES2.GL_FRAGMENT_SHADER:
+ case GL3.GL_GEOMETRY_SHADER:
break;
default:
throw new GLException("Unknown shader type: "+type);
@@ -113,14 +122,15 @@ public class ShaderCode {
}
/**
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER} or {@link GL2ES2#GL_FRAGMENT_SHADER}
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
* @param count number of shaders
- * @param binary binary buffer containing the shader binaries,
+ * @param binary binary buffer containing the shader binaries,
*/
public ShaderCode(int type, int count, int binFormat, Buffer binary) {
switch (type) {
case GL2ES2.GL_VERTEX_SHADER:
case GL2ES2.GL_FRAGMENT_SHADER:
+ case GL3.GL_GEOMETRY_SHADER:
break;
default:
throw new GLException("Unknown shader type: "+type);
@@ -136,19 +146,19 @@ public class ShaderCode {
/**
* Creates a complete {@link ShaderCode} object while reading all shader source of <code>sourceFiles</code>,
* which location is resolved using the <code>context</code> class, see {@link #readShaderSource(Class, String)}.
- *
+ *
* @param gl current GL object to determine whether a shader compiler is available. If null, no validation is performed.
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER} or {@link GL2ES2#GL_FRAGMENT_SHADER}
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
* @param count number of shaders
* @param context class used to help resolving the source location
* @param sourceFiles array of source locations, organized as <code>sourceFiles[count]</code>
* @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
- * which can be edited later on at the costs of a String conversion when passing to
+ * which can be edited later on at the costs of a String conversion when passing to
* {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
* If <code>false</code> method returns an immutable <code>String</code> instance,
* which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
* at no additional costs.
- *
+ *
* @throws IllegalArgumentException if <code>count</count> and <code>sourceFiles.length</code> do not match
* @see #readShaderSource(Class, String)
*/
@@ -181,16 +191,16 @@ public class ShaderCode {
/**
* Creates a complete {@link ShaderCode} object while reading the shader binary of <code>binaryFile</code>,
* which location is resolved using the <code>context</code> class, see {@link #readShaderBinary(Class, String)}.
- *
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER} or {@link GL2ES2#GL_FRAGMENT_SHADER}
+ *
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
* @param count number of shaders
* @param context class used to help resolving the source location
* @param binFormat a valid native binary format as they can be queried by {@link ShaderUtil#getShaderBinaryFormats(GL)}.
* @param sourceFiles array of source locations, organized as <code>sourceFiles[count]</code>
- *
+ *
* @see #readShaderBinary(Class, String)
* @see ShaderUtil#getShaderBinaryFormats(GL)
- */
+ */
public static ShaderCode create(int type, int count, Class<?> context, int binFormat, String binaryFile) {
ByteBuffer shaderBinary = null;
if(null!=binaryFile && 0<=binFormat) {
@@ -214,16 +224,18 @@ public class ShaderCode {
* <ul>
* <li>Source<ul>
* <li>{@link GL2ES2#GL_VERTEX_SHADER vertex}: {@link #SUFFIX_VERTEX_SOURCE}</li>
- * <li>{@link GL2ES2#GL_FRAGMENT_SHADER fragment}: {@link #SUFFIX_FRAGMENT_SOURCE}</li></ul></li>
+ * <li>{@link GL2ES2#GL_FRAGMENT_SHADER fragment}: {@link #SUFFIX_FRAGMENT_SOURCE}</li>
+ * <li>{@link GL3#GL_GEOMETRY_SHADER geometry}: {@link #SUFFIX_GEOMETRY_SOURCE}</li></ul></li>
* <li>Binary<ul>
* <li>{@link GL2ES2#GL_VERTEX_SHADER vertex}: {@link #SUFFIX_VERTEX_BINARY}</li>
- * <li>{@link GL2ES2#GL_FRAGMENT_SHADER fragment}: {@link #SUFFIX_FRAGMENT_BINARY}</li></ul></li>
- * </ul>
- * @param binary true for a binary resource, false for a source resource
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER} or {@link GL2ES2#GL_FRAGMENT_SHADER}
- *
+ * <li>{@link GL2ES2#GL_FRAGMENT_SHADER fragment}: {@link #SUFFIX_FRAGMENT_BINARY}</li>
+ * <li>{@link GL3#GL_GEOMETRY_SHADER geometry}: {@link #SUFFIX_GEOMETRY_BINARY}</li></ul></li>
+ * </ul>
+ * @param binary true for a binary resource, false for a source resource
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
+ *
* @throws GLException if <code>type</code> is not supported
- *
+ *
* @see #create(GL2ES2, int, Class, String, String, String, boolean)
*/
public static String getFileSuffix(boolean binary, int type) {
@@ -232,21 +244,23 @@ public class ShaderCode {
return binary?SUFFIX_VERTEX_BINARY:SUFFIX_VERTEX_SOURCE;
case GL2ES2.GL_FRAGMENT_SHADER:
return binary?SUFFIX_FRAGMENT_BINARY:SUFFIX_FRAGMENT_SOURCE;
+ case GL3.GL_GEOMETRY_SHADER:
+ return binary?SUFFIX_GEOMETRY_BINARY:SUFFIX_GEOMETRY_SOURCE;
default:
throw new GLException("illegal shader type: "+type);
}
}
- /**
+ /**
* Returns a unique relative path for binary shader resources as follows:
* <ul>
* <li>{@link GLES2#GL_NVIDIA_PLATFORM_BINARY_NV NVIDIA}: {@link #SUB_PATH_NVIDIA}</li>
* </ul>
- *
+ *
* @throws GLException if <code>binFormat</code> is not supported
- *
+ *
* @see #create(GL2ES2, int, Class, String, String, String, boolean)
- */
+ */
public static String getBinarySubPath(int binFormat) {
switch (binFormat) {
case GLES2.GL_NVIDIA_PLATFORM_BINARY_NV:
@@ -257,42 +271,42 @@ public class ShaderCode {
}
/**
- * Convenient creation method for instantiating a complete {@link ShaderCode} object
- * either from source code using {@link #create(GL2ES2, int, int, Class, String[])},
+ * Convenient creation method for instantiating a complete {@link ShaderCode} object
+ * either from source code using {@link #create(GL2ES2, int, int, Class, String[])},
* or from a binary code using {@link #create(int, int, Class, int, String)},
* whatever is available first.
* <p>
- * The source and binary location names are expected w/o suffixes which are
+ * The source and binary location names are expected w/o suffixes which are
* resolved and appended using {@link #getFileSuffix(boolean, int)}.
* </p>
* <p>
* Additionally, the binary resource is expected within a subfolder of <code>binRoot</code>
* which reflects the vendor specific binary format, see {@link #getBinarySubPath(int)}.
* All {@link ShaderUtil#getShaderBinaryFormats(GL)} are being iterated
- * using the binary subfolder, the first existing resource is being used.
+ * using the binary subfolder, the first existing resource is being used.
* </p>
- *
+ *
* Example:
* <pre>
* Your std JVM layout (plain or within a JAR):
- *
+ *
* org/test/glsl/MyShaderTest.class
* org/test/glsl/shader/vertex.vp
* org/test/glsl/shader/fragment.fp
* org/test/glsl/shader/bin/nvidia/vertex.bvp
* org/test/glsl/shader/bin/nvidia/fragment.bfp
- *
+ *
* Your Android APK layout:
- *
+ *
* classes.dex
* assets/org/test/glsl/shader/vertex.vp
* assets/org/test/glsl/shader/fragment.fp
* assets/org/test/glsl/shader/bin/nvidia/vertex.bvp
* assets/org/test/glsl/shader/bin/nvidia/fragment.bfp
* ...
- *
+ *
* Your invocation in org/test/glsl/MyShaderTest.java:
- *
+ *
* ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, this.getClass(),
* "shader", new String[] { "vertex" }, "shader/bin", "vertex");
* ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, this.getClass(),
@@ -303,14 +317,14 @@ public class ShaderCode {
* st.attachShaderProgram(gl, sp0, true);
* </pre>
* A simplified entry point is {@link #create(GL2ES2, int, Class, String, String, String, boolean)}.
- *
+ *
* <p>
* The location is finally being resolved using the <code>context</code> class, see {@link #readShaderBinary(Class, String)}.
* </p>
- *
+ *
* @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used),
* or to determine the shader binary format (if <code>binary</code> is used).
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER} or {@link GL2ES2#GL_FRAGMENT_SHADER}
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
* @param count number of shaders
* @param context class used to help resolving the source and binary location
* @param srcRoot relative <i>root</i> path for <code>srcBasenames</code>
@@ -318,22 +332,22 @@ public class ShaderCode {
* @param binRoot relative <i>root</i> path for <code>binBasenames</code>
* @param binBasename basename w/o path or suffix relative to <code>binRoot</code> for the shader's binary code
* @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
- * which can be edited later on at the costs of a String conversion when passing to
+ * which can be edited later on at the costs of a String conversion when passing to
* {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
* If <code>false</code> method returns an immutable <code>String</code> instance,
* which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
* at no additional costs.
- *
+ *
* @throws IllegalArgumentException if <code>count</count> and <code>srcBasenames.length</code> do not match
- *
+ *
* @see #create(GL2ES2, int, int, Class, String[])
* @see #create(int, int, Class, int, String)
* @see #readShaderSource(Class, String)
* @see #getFileSuffix(boolean, int)
* @see ShaderUtil#getShaderBinaryFormats(GL)
* @see #getBinarySubPath(int)
- */
- public static ShaderCode create(GL2ES2 gl, int type, int count, Class<?> context,
+ */
+ public static ShaderCode create(GL2ES2 gl, int type, int count, Class<?> context,
String srcRoot, String[] srcBasenames, String binRoot, String binBasename,
boolean mutableStringBuilder) {
ShaderCode res = null;
@@ -376,28 +390,28 @@ public class ShaderCode {
/**
* Simplified variation of {@link #create(GL2ES2, int, int, Class, String, String[], String, String)}.
* <br>
- *
+ *
* Example:
* <pre>
* Your std JVM layout (plain or within a JAR):
- *
+ *
* org/test/glsl/MyShaderTest.class
* org/test/glsl/shader/vertex.vp
* org/test/glsl/shader/fragment.fp
* org/test/glsl/shader/bin/nvidia/vertex.bvp
* org/test/glsl/shader/bin/nvidia/fragment.bfp
- *
+ *
* Your Android APK layout:
- *
+ *
* classes.dex
* assets/org/test/glsl/shader/vertex.vp
* assets/org/test/glsl/shader/fragment.fp
* assets/org/test/glsl/shader/bin/nvidia/vertex.bvp
* assets/org/test/glsl/shader/bin/nvidia/fragment.bfp
* ...
- *
+ *
* Your invocation in org/test/glsl/MyShaderTest.java:
- *
+ *
* ShaderCode vp0 = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, this.getClass(),
* "shader", "shader/bin", "vertex");
* ShaderCode fp0 = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, this.getClass(),
@@ -407,10 +421,10 @@ public class ShaderCode {
* sp0.add(gl, fp0, System.err);
* st.attachShaderProgram(gl, sp0, true);
* </pre>
- *
+ *
* @param gl current GL object to determine whether a shader compiler is available (if <code>source</code> is used),
* or to determine the shader binary format (if <code>binary</code> is used).
- * @param type either {@link GL2ES2#GL_VERTEX_SHADER} or {@link GL2ES2#GL_FRAGMENT_SHADER}
+ * @param type either {@link GL2ES2#GL_VERTEX_SHADER}, {@link GL2ES2#GL_FRAGMENT_SHADER} or {@link GL3#GL_GEOMETRY_SHADER}
* @param context class used to help resolving the source and binary location
* @param srcRoot relative <i>root</i> path for <code>basename</code>
* @param binRoot relative <i>root</i> path for <code>basename</code>
@@ -418,20 +432,20 @@ public class ShaderCode {
* @param basenames basename w/o path or suffix relative to <code>srcRoot</code> and <code>binRoot</code>
* for the shader's source and binary code.
* @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
- * which can be edited later on at the costs of a String conversion when passing to
+ * which can be edited later on at the costs of a String conversion when passing to
* {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
* If <code>false</code> method returns an immutable <code>String</code> instance,
* which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
* at no additional costs.
* @throws IllegalArgumentException if <code>count</count> is not 1
- *
+ *
* @see #create(GL2ES2, int, int, Class, String, String[], String, String)
- */
- public static ShaderCode create(GL2ES2 gl, int type, Class<?> context,
+ */
+ public static ShaderCode create(GL2ES2 gl, int type, Class<?> context,
String srcRoot, String binRoot, String basename, boolean mutableStringBuilder) {
- return create(gl, type, 1, context, srcRoot, new String[] { basename }, binRoot, basename, mutableStringBuilder );
+ return create(gl, type, 1, context, srcRoot, new String[] { basename }, binRoot, basename, mutableStringBuilder );
}
-
+
/**
* returns the uniq shader id as an integer
*/
@@ -440,12 +454,14 @@ public class ShaderCode {
public int shaderType() { return shaderType; }
public String shaderTypeStr() { return shaderTypeStr(shaderType); }
- public static String shaderTypeStr(int type) {
+ public static String shaderTypeStr(int type) {
switch (type) {
case GL2ES2.GL_VERTEX_SHADER:
return "VERTEX_SHADER";
case GL2ES2.GL_FRAGMENT_SHADER:
return "FRAGMENT_SHADER";
+ case GL3.GL_GEOMETRY_SHADER:
+ return "GEOMETRY_SHADER";
}
return "UNKNOWN_SHADER";
}
@@ -467,6 +483,7 @@ public class ShaderCode {
// Create & Compile the vertex/fragment shader objects
if(null!=shaderSource) {
if(DEBUG_CODE) {
+ System.err.println("ShaderCode.compile:");
dumpShaderSource(System.err);
}
valid=ShaderUtil.createAndCompileShader(gl, shader, shaderType,
@@ -497,6 +514,7 @@ public class ShaderCode {
id=-1;
}
+ @Override
public boolean equals(Object obj) {
if(this==obj) { return true; }
if(obj instanceof ShaderCode) {
@@ -504,9 +522,11 @@ public class ShaderCode {
}
return false;
}
+ @Override
public int hashCode() {
return id;
}
+ @Override
public String toString() {
StringBuilder buf = new StringBuilder("ShaderCode[id="+id+", type="+shaderTypeStr()+", valid="+valid+", shader: ");
for(int i=0; i<shader.remaining(); i++) {
@@ -536,7 +556,7 @@ public class ShaderCode {
} else {
CharSequence[] src = shaderSource[i];
int lineno=0;
-
+
for(int j=0; j<src.length; j++) {
out.printf("%4d: // Segment %d/%d: \n", lineno, j, src.length);
final BufferedReader reader = new BufferedReader(new StringReader(src[j].toString()));
@@ -552,19 +572,19 @@ public class ShaderCode {
out.println("--------------------------------------------------------------");
}
}
-
+
/**
* Adds <code>data</code> after the line containing <code>tag</code>.
* <p>
* Note: The shader source to be edit must be created using a mutable StringBuilder.
* </p>
- *
+ *
* @param shaderIdx the shader index to be used.
* @param tag search string
* @param fromIndex start search <code>tag</code> begininig with this index
* @param data the text to be inserted. Shall end with an EOL '\n' character.
* @return index after the inserted <code>data</code>
- *
+ *
* @throws IllegalStateException if the shader source's CharSequence is immutable, i.e. not of type <code>StringBuilder</code>
*/
public int insertShaderSource(int shaderIdx, String tag, int fromIndex, CharSequence data) {
@@ -578,7 +598,7 @@ public class ShaderCode {
final int sourceCount = (null!=shaderSource)?shaderSource.length:0;
if(shaderIdx>=sourceCount) {
throw new IndexOutOfBoundsException("shaderIdx not within source bounds [0.."+(sourceCount-1)+"]: "+shaderIdx);
- }
+ }
final CharSequence[] src = shaderSource[shaderIdx];
int curEndIndex = 0;
for(int j=0; j<src.length; j++) {
@@ -586,8 +606,8 @@ public class ShaderCode {
throw new IllegalStateException("shader source not a mutable StringBuilder, but CharSequence of type: "+src[j].getClass().getName());
}
final StringBuilder sb = (StringBuilder)src[j];
- curEndIndex += sb.length();
- if(fromIndex < curEndIndex) {
+ curEndIndex += sb.length();
+ if(fromIndex < curEndIndex) {
int insertIdx = sb.indexOf(tag, fromIndex);
if(0<=insertIdx) {
insertIdx += tag.length();
@@ -613,15 +633,15 @@ public class ShaderCode {
* Replaces <code>oldName</code> with <code>newName</code> in all shader sources.
* <p>
* In case <code>oldName</code> and <code>newName</code> are equal, no action is performed.
- * </p>
+ * </p>
* <p>
* Note: The shader source to be edit must be created using a mutable StringBuilder.
* </p>
- *
+ *
* @param oldName the to be replace string
* @param newName the replacement string
* @return the number of replacements
- *
+ *
* @throws IllegalStateException if the shader source's CharSequence is immutable, i.e. not of type <code>StringBuilder</code>
*/
public int replaceInShaderSource(String oldName, String newName) {
@@ -658,18 +678,18 @@ public class ShaderCode {
}
return num;
}
-
+
/**
* Adds <code>data</code> at <code>offset</code> in shader source for shader <code>shaderIdx</code>.
* <p>
* Note: The shader source to be edit must be created using a mutable StringBuilder.
* </p>
- *
+ *
* @param shaderIdx the shader index to be used.
* @param position in shader source segments of shader <code>shaderIdx</code>
- * @param data the text to be inserted. Shall end with an EOL '\n' character.
+ * @param data the text to be inserted. Shall end with an EOL '\n' character
* @return index after the inserted <code>data</code>
- *
+ *
* @throws IllegalStateException if the shader source's CharSequence is immutable, i.e. not of type <code>StringBuilder</code>
*/
public int insertShaderSource(int shaderIdx, int position, CharSequence data) {
@@ -683,7 +703,7 @@ public class ShaderCode {
final int sourceCount = (null!=shaderSource)?shaderSource.length:0;
if(shaderIdx>=sourceCount) {
throw new IndexOutOfBoundsException("shaderIdx not within source bounds [0.."+(sourceCount-1)+"]: "+shaderIdx);
- }
+ }
final CharSequence[] src = shaderSource[shaderIdx];
int curEndIndex = 0;
for(int j=0; j<src.length; j++) {
@@ -691,8 +711,8 @@ public class ShaderCode {
throw new IllegalStateException("shader source not a mutable StringBuilder, but CharSequence of type: "+src[j].getClass().getName());
}
final StringBuilder sb = (StringBuilder)src[j];
- curEndIndex += sb.length();
- if(position < curEndIndex) {
+ curEndIndex += sb.length();
+ if(position < curEndIndex) {
sb.insert(position, data);
return position+data.length();
}
@@ -700,6 +720,7 @@ public class ShaderCode {
return -1;
}
+ @SuppressWarnings("resource")
private static int readShaderSource(Class<?> context, URLConnection conn, StringBuilder result, int lineno) throws IOException {
if(DEBUG_CODE) {
if(0 == lineno) {
@@ -716,12 +737,12 @@ public class ShaderCode {
if (line.startsWith("#include ")) {
String includeFile = line.substring(9).trim();
URLConnection nextConn = null;
-
+
// Try relative of current shader location
nextConn = IOUtil.openURL(IOUtil.getRelativeOf(conn.getURL(), includeFile), "ShaderCode.relativeOf ");
if (nextConn == null) {
// Try relative of class and absolute
- nextConn = IOUtil.getResource(context, includeFile);
+ nextConn = IOUtil.getResource(context, includeFile);
}
if (nextConn == null) {
// Fail
@@ -739,7 +760,7 @@ public class ShaderCode {
}
/**
- *
+ *
* @param context
* @param conn
* @param result
@@ -748,7 +769,7 @@ public class ShaderCode {
public static void readShaderSource(Class<?> context, URLConnection conn, StringBuilder result) throws IOException {
readShaderSource(context, conn, result, 0);
}
-
+
/**
* Reads shader source located in <code>path</code>,
* either relative to the <code>context</code> class or absolute <i>as-is</i>.
@@ -756,21 +777,21 @@ public class ShaderCode {
* Final location lookup is performed via {@link ClassLoader#getResource(String)} and {@link ClassLoader#getSystemResource(String)},
* see {@link IOUtil#getResource(Class, String)}.
* </p>
- *
+ *
* @param context class used to help resolve the source location
* @param path location of shader source
* @param mutableStringBuilder if <code>true</code> method returns a mutable <code>StringBuilder</code> instance
- * which can be edited later on at the costs of a String conversion when passing to
+ * which can be edited later on at the costs of a String conversion when passing to
* {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}.
* If <code>false</code> method returns an immutable <code>String</code> instance,
* which can be passed to {@link GL2ES2#glShaderSource(int, int, String[], IntBuffer)}
* at no additional costs.
- * @throws IOException
- *
+ * @throws IOException
+ *
* @see IOUtil#getResource(Class, String)
- */
+ */
public static CharSequence readShaderSource(Class<?> context, String path, boolean mutableStringBuilder) throws IOException {
- URLConnection conn = IOUtil.getResource(context, path);
+ URLConnection conn = IOUtil.getResource(context, path);
if (conn == null) {
return null;
}
@@ -780,17 +801,17 @@ public class ShaderCode {
}
/**
- * Reads shader binary located in <code>path</code>,
+ * Reads shader binary located in <code>path</code>,
* either relative to the <code>context</code> class or absolute <i>as-is</i>.
* <p>
* Final location lookup is perfomed via {@link ClassLoader#getResource(String)} and {@link ClassLoader#getSystemResource(String)},
* see {@link IOUtil#getResource(Class, String)}.
* </p>
- *
+ *
* @param context class used to help resolve the source location
* @param path location of shader binary
- * @throws IOException
- *
+ * @throws IOException
+ *
* @see IOUtil#getResource(Class, String)
*/
public static ByteBuffer readShaderBinary(Class<?> context, String path) throws IOException {
@@ -806,6 +827,186 @@ public class ShaderCode {
}
}
+ // Shall we use: #ifdef GL_FRAGMENT_PRECISION_HIGH .. #endif for using highp in fragment shader if avail ?
+ /** Default precision of {@link GL#isGLES2() ES2} for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader}: {@value #es2_default_precision_vp} */
+ public static final String es2_default_precision_vp = "\nprecision highp float;\nprecision highp int;\n/*precision lowp sampler2D;*/\n/*precision lowp samplerCube;*/\n";
+ /** Default precision of {@link GL#isGLES2() ES2} for {@link GL2ES2#GL_FRAGMENT_SHADER fragment-shader}: {@value #es2_default_precision_fp} */
+ public static final String es2_default_precision_fp = "\nprecision mediump float;\nprecision mediump int;\n/*precision lowp sampler2D;*/\n/*precision lowp samplerCube;*/\n";
+
+ /** Default precision of {@link GL#isGLES3() ES3} for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader}: {@value #es3_default_precision_vp} */
+ public static final String es3_default_precision_vp = es2_default_precision_vp;
+ /** Default precision of {@link GL#isGLES3() ES3} for {@link GL2ES2#GL_FRAGMENT_SHADER fragment-shader}: {@value #es3_default_precision_fp} */
+ public static final String es3_default_precision_fp = es2_default_precision_fp;
+
+ /** Default precision of GLSL &ge; 1.30 as required until &lt; 1.50 for {@link GL2ES2#GL_VERTEX_SHADER vertex-shader} or {@link GL3#GL_GEOMETRY_SHADER geometry-shader}: {@value #gl3_default_precision_vp_gp}. See GLSL Spec 1.30-1.50 Section 4.5.3. */
+ public static final String gl3_default_precision_vp_gp = "\nprecision highp float;\nprecision highp int;\n";
+ /** Default precision of GLSL &ge; 1.30 as required until &lt; 1.50 for {@link GL2ES2#GL_FRAGMENT_SHADER fragment-shader}: {@value #gl3_default_precision_fp}. See GLSL Spec 1.30-1.50 Section 4.5.3. */
+ public static final String gl3_default_precision_fp = "\nprecision highp float;\nprecision mediump int;\n/*precision mediump sampler2D;*/\n";
+
+ /** <i>Behavior</i> for GLSL extension directive, see {@link #createExtensionDirective(String, String)}, value {@value}. */
+ public static final String REQUIRE = "require";
+ /** <i>Behavior</i> for GLSL extension directive, see {@link #createExtensionDirective(String, String)}, value {@value}. */
+ public static final String ENABLE = "enable";
+ /** <i>Behavior</i> for GLSL extension directive, see {@link #createExtensionDirective(String, String)}, value {@value}. */
+ public static final String DISABLE = "disable";
+ /** <i>Behavior</i> for GLSL extension directive, see {@link #createExtensionDirective(String, String)}, value {@value}. */
+ public static final String WARN = "warn";
+
+ /**
+ * Creates a GLSL extension directive.
+ * <p>
+ * Prefer {@link #ENABLE} over {@link #REQUIRE}, since the latter will force a failure if not supported.
+ * </p>
+ *
+ * @param extensionName
+ * @param behavior shall be either {@link #REQUIRE}, {@link #ENABLE}, {@link #DISABLE} or {@link #WARN}
+ * @return the complete extension directive
+ */
+ public static String createExtensionDirective(String extensionName, String behavior) {
+ return "#extension " + extensionName + " : " + behavior;
+ }
+
+ /**
+ * Add GLSL version at the head of this shader source code.
+ * <p>
+ * Note: The shader source to be edit must be created using a mutable StringBuilder.
+ * </p>
+ * @param gl a GL context, which must have been made current once
+ * @return the index after the inserted data, maybe 0 if nothing has be inserted.
+ */
+ public final int addGLSLVersion(GL2ES2 gl) {
+ return insertShaderSource(0, 0, gl.getContext().getGLSLVersionString());
+ }
+
+ /**
+ * Adds default precision to source code at given position if required, i.e.
+ * {@link #es2_default_precision_vp}, {@link #es2_default_precision_fp},
+ * {@link #gl3_default_precision_vp_gp}, {@link #gl3_default_precision_fp} or none,
+ * depending on the {@link GLContext#getGLSLVersionNumber() GLSL version} being used.
+ * <p>
+ * Note: The shader source to be edit must be created using a mutable StringBuilder.
+ * </p>
+ * @param gl a GL context, which must have been made current once
+ * @param pos position within this mutable shader source.
+ * @return the index after the inserted data, maybe 0 if nothing has be inserted.
+ */
+ public final int addDefaultShaderPrecision(GL2ES2 gl, int pos) {
+ final String defaultPrecision;
+ if( gl.isGLES2() ) {
+ switch ( shaderType ) {
+ case GL2ES2.GL_VERTEX_SHADER:
+ defaultPrecision = es2_default_precision_vp; break;
+ case GL2ES2.GL_FRAGMENT_SHADER:
+ defaultPrecision = es2_default_precision_fp; break;
+ default:
+ defaultPrecision = null;
+ break;
+ }
+ } else if( gl.isGLES3() ) {
+ switch ( shaderType ) {
+ case GL2ES2.GL_VERTEX_SHADER:
+ defaultPrecision = es3_default_precision_vp; break;
+ case GL2ES2.GL_FRAGMENT_SHADER:
+ defaultPrecision = es3_default_precision_fp; break;
+ default:
+ defaultPrecision = null;
+ break;
+ }
+ } else if( requiresGL3DefaultPrecision(gl) ) {
+ // GLSL [ 1.30 .. 1.50 [ needs at least fragement float default precision!
+ switch ( shaderType ) {
+ case GL2ES2.GL_VERTEX_SHADER:
+ case GL3.GL_GEOMETRY_SHADER:
+ defaultPrecision = gl3_default_precision_vp_gp; break;
+ case GL2ES2.GL_FRAGMENT_SHADER:
+ defaultPrecision = gl3_default_precision_fp; break;
+ default:
+ defaultPrecision = null;
+ break;
+ }
+ } else {
+ defaultPrecision = null;
+ }
+ if( null != defaultPrecision ) {
+ pos = insertShaderSource(0, pos, defaultPrecision);
+ }
+ return pos;
+ }
+
+ /** Returns true, if GLSL version requires default precision, i.e. ES2 or GLSL [1.30 .. 1.50[. */
+ public static final boolean requiresDefaultPrecision(GL2ES2 gl) {
+ if( gl.isGLES() ) {
+ return true;
+ }
+ return requiresGL3DefaultPrecision(gl);
+ }
+
+ /** Returns true, if GL3 GLSL version requires default precision, i.e. GLSL [1.30 .. 1.50[. */
+ public static final boolean requiresGL3DefaultPrecision(GL2ES2 gl) {
+ if( gl.isGL3() ) {
+ final VersionNumber glslVersion = gl.getContext().getGLSLVersionNumber();
+ return glslVersion.compareTo(GLContext.Version130) >= 0 && glslVersion.compareTo(GLContext.Version150) < 0 ;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Default customization of this shader source code.
+ * <p>
+ * Note: The shader source to be edit must be created using a mutable StringBuilder.
+ * </p>
+ * @param gl a GL context, which must have been made current once
+ * @param preludeVersion if true {@link GLContext#getGLSLVersionString()} is preluded, otherwise not.
+ * @param addDefaultPrecision if <code>true</code> default precision source code line(s) are added, i.e.
+ * {@link #es2_default_precision_vp}, {@link #es2_default_precision_fp},
+ * {@link #gl3_default_precision_vp_gp}, {@link #gl3_default_precision_fp} or none,
+ * depending on the {@link GLContext#getGLSLVersionNumber() GLSL version} being used.
+ * @return the index after the inserted data, maybe 0 if nothing has be inserted.
+ * @see #addGLSLVersion(GL2ES2)
+ * @see #addDefaultShaderPrecision(GL2ES2, int)
+ */
+ public final int defaultShaderCustomization(GL2ES2 gl, boolean preludeVersion, boolean addDefaultPrecision) {
+ int pos;
+ if( preludeVersion ) {
+ pos = addGLSLVersion(gl);
+ } else {
+ pos = 0;
+ }
+ if( addDefaultPrecision ) {
+ pos = addDefaultShaderPrecision(gl, pos);
+ }
+ return pos;
+ }
+
+ /**
+ * Default customization of this shader source code.
+ * <p>
+ * Note: The shader source to be edit must be created using a mutable StringBuilder.
+ * </p>
+ * @param gl a GL context, which must have been made current once
+ * @param preludeVersion if true {@link GLContext#getGLSLVersionString()} is preluded, otherwise not.
+ * @param esDefaultPrecision optional default precision source code line(s) preluded if not null and if {@link GL#isGLES()}.
+ * You may use {@link #es2_default_precision_fp} for fragment shader and {@link #es2_default_precision_vp} for vertex shader.
+ * @return the index after the inserted data, maybe 0 if nothing has be inserted.
+ * @see #addGLSLVersion(GL2ES2)
+ * @see #addDefaultShaderPrecision(GL2ES2, int)
+ */
+ public final int defaultShaderCustomization(GL2ES2 gl, boolean preludeVersion, String esDefaultPrecision) {
+ int pos;
+ if( preludeVersion ) {
+ pos = addGLSLVersion(gl);
+ } else {
+ pos = 0;
+ }
+ if( gl.isGLES() && null != esDefaultPrecision ) {
+ pos = insertShaderSource(0, pos, esDefaultPrecision);
+ } else {
+ pos = addDefaultShaderPrecision(gl, pos);
+ }
+ return pos;
+ }
+
//----------------------------------------------------------------------
// Internals only below this point
//
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java
index 14ea7d2b8..b289b41e2 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java
@@ -37,7 +37,7 @@ import java.util.Iterator;
import java.io.PrintStream;
public class ShaderProgram {
-
+
public ShaderProgram() {
id = getNextID();
}
@@ -50,6 +50,7 @@ public class ShaderProgram {
return programInUse;
}
+ /** Returns the shader program name, which is non zero if valid. */
public int program() { return shaderProgram; }
/**
@@ -84,7 +85,9 @@ public class ShaderProgram {
* If <code>destroyShaderCode</code> is true it destroys the shader codes as well.
*/
public synchronized void release(GL2ES2 gl, boolean destroyShaderCode) {
- useProgram(gl, false);
+ if( programLinked ) {
+ useProgram(gl, false);
+ }
for(Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) {
ShaderCode shaderCode = iter.next();
if(attachedShaderCode.remove(shaderCode)) {
@@ -96,9 +99,9 @@ public class ShaderProgram {
}
allShaderCode.clear();
attachedShaderCode.clear();
- if(0<=shaderProgram) {
+ if( 0 != shaderProgram ) {
gl.glDeleteProgram(shaderProgram);
- shaderProgram=-1;
+ shaderProgram=0;
}
}
@@ -108,7 +111,7 @@ public class ShaderProgram {
/**
* Adds a new shader to this program.
- *
+ *
* <p>This command does not compile and attach the shader,
* use {@link #add(GL2ES2, ShaderCode)} for this purpose.</p>
*/
@@ -119,7 +122,7 @@ public class ShaderProgram {
public synchronized boolean contains(ShaderCode shaderCode) {
return allShaderCode.contains(shaderCode);
}
-
+
/**
* Warning slow O(n) operation ..
* @param id
@@ -140,30 +143,33 @@ public class ShaderProgram {
//
/**
- * Creates the empty GL program object using {@link GL2ES2#glCreateProgram()}
- *
+ * Creates the empty GL program object using {@link GL2ES2#glCreateProgram()},
+ * if not already created.
+ *
* @param gl
+ * @return true if shader program is valid, i.e. not zero
*/
- public synchronized final void init(GL2ES2 gl) {
- if(0>shaderProgram) {
+ public synchronized final boolean init(GL2ES2 gl) {
+ if( 0 == shaderProgram ) {
shaderProgram = gl.glCreateProgram();
}
+ return 0 != shaderProgram;
}
-
+
/**
* Adds a new shader to a this non running program.
*
* <p>Compiles and attaches the shader, if not done yet.</p>
- *
+ *
* @return true if the shader was successfully added, false if compilation failed.
*/
public synchronized boolean add(GL2ES2 gl, ShaderCode shaderCode, PrintStream verboseOut) {
- init(gl);
+ if( !init(gl) ) { return false; }
if( allShaderCode.add(shaderCode) ) {
- if(!shaderCode.compile(gl, verboseOut)) {
+ if( !shaderCode.compile(gl, verboseOut) ) {
return false;
}
- if(attachedShaderCode.add(shaderCode)) {
+ if( attachedShaderCode.add(shaderCode) ) {
ShaderUtil.attachShader(gl, shaderProgram, shaderCode.shader());
}
}
@@ -173,11 +179,11 @@ public class ShaderProgram {
/**
* Replace a shader in a program and re-links the program.
*
- * @param gl
+ * @param gl
* @param oldShader the to be replace Shader
* @param newShader the new ShaderCode
* @param verboseOut the optional verbose output stream
- *
+ *
* @return true if all steps are valid, shader compilation, attachment and linking; otherwise false.
*
* @see ShaderState#glEnableVertexAttribArray
@@ -190,31 +196,29 @@ public class ShaderProgram {
* @see ShaderState#glResetAllVertexAttributes
*/
public synchronized boolean replaceShader(GL2ES2 gl, ShaderCode oldShader, ShaderCode newShader, PrintStream verboseOut) {
- init(gl);
-
- if(!newShader.compile(gl, verboseOut)) {
+ if(!init(gl) || !newShader.compile(gl, verboseOut)) {
return false;
}
-
+
boolean shaderWasInUse = inUse();
if(shaderWasInUse) {
useProgram(gl, false);
}
-
+
if(null != oldShader && allShaderCode.remove(oldShader)) {
if(attachedShaderCode.remove(oldShader)) {
ShaderUtil.detachShader(gl, shaderProgram, oldShader.shader());
}
}
-
+
add(newShader);
if(attachedShaderCode.add(newShader)) {
ShaderUtil.attachShader(gl, shaderProgram, newShader.shader());
}
-
+
gl.glLinkProgram(shaderProgram);
-
- programLinked = ShaderUtil.isProgramLinkStatusValid(gl, shaderProgram, System.err);
+
+ programLinked = ShaderUtil.isProgramLinkStatusValid(gl, shaderProgram, verboseOut);
if ( programLinked && shaderWasInUse ) {
useProgram(gl, true);
}
@@ -223,23 +227,27 @@ public class ShaderProgram {
/**
* Links the shader code to the program.
- *
+ *
* <p>Compiles and attaches the shader code to the program if not done by yet</p>
- *
+ *
* <p>Within this process, all GL resources (shader and program objects) are created if necessary.</p>
- *
+ *
* @param gl
* @param verboseOut
* @return true if program was successfully linked and is valid, otherwise false
- *
+ *
* @see #init(GL2ES2)
*/
public synchronized boolean link(GL2ES2 gl, PrintStream verboseOut) {
- init(gl);
+ if( !init(gl) ) {
+ programLinked = false; // mark unlinked due to user attempt to [re]link
+ return false;
+ }
for(Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) {
final ShaderCode shaderCode = iter.next();
if(!shaderCode.compile(gl, verboseOut)) {
+ programLinked = false; // mark unlinked due to user attempt to [re]link
return false;
}
if(attachedShaderCode.add(shaderCode)) {
@@ -250,11 +258,12 @@ public class ShaderProgram {
// Link the program
gl.glLinkProgram(shaderProgram);
- programLinked = ShaderUtil.isProgramLinkStatusValid(gl, shaderProgram, System.err);
+ programLinked = ShaderUtil.isProgramLinkStatusValid(gl, shaderProgram, verboseOut);
return programLinked;
}
+ @Override
public boolean equals(Object obj) {
if(this == obj) { return true; }
if(obj instanceof ShaderProgram) {
@@ -263,6 +272,7 @@ public class ShaderProgram {
return false;
}
+ @Override
public int hashCode() {
return id;
}
@@ -279,7 +289,8 @@ public class ShaderProgram {
sb.append("]");
return sb;
}
-
+
+ @Override
public String toString() {
return toString(null).toString();
}
@@ -291,17 +302,20 @@ public class ShaderProgram {
public synchronized boolean validateProgram(GL2ES2 gl, PrintStream verboseOut) {
return ShaderUtil.isProgramExecStatusValid(gl, shaderProgram, verboseOut);
}
-
+
public synchronized void useProgram(GL2ES2 gl, boolean on) {
if(!programLinked) { throw new GLException("Program is not linked"); }
if(programInUse==on) { return; }
- gl.glUseProgram(on?shaderProgram:0);
+ if( 0 == shaderProgram ) {
+ on = false;
+ }
+ gl.glUseProgram( on ? shaderProgram : 0 );
programInUse = on;
}
protected boolean programLinked = false;
protected boolean programInUse = false;
- protected int shaderProgram=-1;
+ protected int shaderProgram = 0; // non zero is valid!
protected HashSet<ShaderCode> allShaderCode = new HashSet<ShaderCode>();
protected HashSet<ShaderCode> attachedShaderCode = new HashSet<ShaderCode>();
protected int id = -1;
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java
index 62082aacd..f60cb6088 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java
@@ -35,66 +35,40 @@ import java.util.Iterator;
import javax.media.opengl.GL;
import javax.media.opengl.GL2ES2;
import javax.media.opengl.GLArrayData;
-import javax.media.opengl.GLContext;
import javax.media.opengl.GLException;
import javax.media.opengl.GLUniformData;
import jogamp.opengl.Debug;
import com.jogamp.common.os.Platform;
-import com.jogamp.common.util.IntObjectHashMap;
import com.jogamp.opengl.util.GLArrayDataEditable;
+/**
+ * ShaderState allows to sharing data between shader programs,
+ * while updating the attribute and uniform locations when switching.
+ * <p>
+ * This allows seamless switching of programs using <i>almost</i> same data
+ * but performing different artifacts.
+ * </p>
+ * <p>
+ * A {@link #useProgram(GL2ES2, boolean) used} ShaderState is attached to the current GL context
+ * and can be retrieved via {@link #getShaderState(GL)}.
+ * </p>
+ */
public class ShaderState {
- public static final boolean DEBUG = Debug.isPropertyDefined("jogl.debug.GLSLState", true);
- private static final String currentStateKey = "jogamp.opengl.glsl.ShaderState" ;
-
- public ShaderState() {
- }
-
- public boolean verbose() { return verbose; }
+ public static final boolean DEBUG;
- public void setVerbose(boolean v) { verbose=v; }
-
- /**
- * Fetches the current shader state from this thread (TLS) current GLContext
- *
- * @see com.jogamp.opengl.util.glsl.ShaderState#useProgram(GL2ES2, boolean)
- * @see com.jogamp.opengl.util.glsl.ShaderState#getShaderState(GL)
- * @see com.jogamp.opengl.util.glsl.ShaderState#setShaderState(GL)
- * @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState()
- */
- public static ShaderState getCurrentShaderState() {
- return getShaderState(GLContext.getCurrentGL());
+ static {
+ Debug.initSingleton();
+ DEBUG = Debug.isPropertyDefined("jogl.debug.GLSLState", true);
}
- /**
- * Gets the shader state attached to the GL object's GLContext
- *
- * @param gl the GL object referencing the GLContext
- *
- * @see com.jogamp.opengl.util.glsl.ShaderState#useProgram(GL2ES2, boolean)
- * @see com.jogamp.opengl.util.glsl.ShaderState#getShaderState(GL)
- * @see com.jogamp.opengl.util.glsl.ShaderState#setShaderState(GL)
- * @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState()
- */
- public static ShaderState getShaderState(GL gl) {
- return (ShaderState) gl.getContext().getAttachedObject(currentStateKey);
+ public ShaderState() {
}
- /**
- * Attaches the shader state to the GL object's GLContext
- *
- * @param gl the GL object referencing the GLContext
- *
- * @see com.jogamp.opengl.util.glsl.ShaderState#useProgram(GL2ES2, boolean)
- * @see com.jogamp.opengl.util.glsl.ShaderState#getShaderState(GL)
- * @see com.jogamp.opengl.util.glsl.ShaderState#setShaderState(GL)
- * @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState()
- */
- public final ShaderState setShaderState(GL gl) {
- return (ShaderState) gl.getContext().attachObject(currentStateKey, this);
- }
+ public boolean verbose() { return verbose; }
+
+ public void setVerbose(boolean v) { verbose = DEBUG || v; }
/**
* Returns the attached user object for the given name to this ShaderState.
@@ -106,7 +80,7 @@ public class ShaderState {
/**
* Attach user object for the given name to this ShaderState.
* Returns the previously set object or null.
- *
+ *
* @return the previous mapped object or null if none
*/
public final Object attachObject(String name, Object obj) {
@@ -115,54 +89,30 @@ public class ShaderState {
/**
* @param name name of the mapped object to detach
- *
+ *
* @return the previous mapped object or null if none
*/
public final Object detachObject(String name) {
return attachedObjectsByString.remove(name);
- }
-
- /**
- * Returns the attached user object for the given name to this ShaderState.
- */
- public final Object getAttachedObject(int name) {
- return attachedObjectsByInt.get(name);
- }
-
- /**
- * Attach user object for the given name to this ShaderState.
- * Returns the previously set object or null.
- */
- public final Object attachObject(int name, Object obj) {
- return attachedObjectsByInt.put(name, obj);
}
- public final Object detachObject(int name) {
- return attachedObjectsByInt.remove(name);
- }
-
/**
* Turns the shader program on or off.<br>
- * Puts this ShaderState to to the thread local storage (TLS),
- * if <code>on</code> is <code>true</code>.
*
* @throws GLException if no program is attached
*
* @see com.jogamp.opengl.util.glsl.ShaderState#useProgram(GL2ES2, boolean)
- * @see com.jogamp.opengl.util.glsl.ShaderState#getShaderState(GL)
- * @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState()
*/
public synchronized void useProgram(GL2ES2 gl, boolean on) throws GLException {
- if(null==shaderProgram) { throw new GLException("No program is attached"); }
+ if(null==shaderProgram) { throw new GLException("No program is attached"); }
if(on) {
- setShaderState(gl);
if(shaderProgram.linked()) {
shaderProgram.useProgram(gl, true);
if(resetAllShaderData) {
resetAllAttributes(gl);
resetAllUniforms(gl);
}
- } else {
+ } else {
if(resetAllShaderData) {
setAllAttributes(gl);
}
@@ -174,7 +124,7 @@ public class ShaderState {
resetAllUniforms(gl);
}
}
- resetAllShaderData = false;
+ resetAllShaderData = false;
} else {
shaderProgram.useProgram(gl, false);
}
@@ -191,34 +141,38 @@ public class ShaderState {
/**
* Attach or switch a shader program
*
- * <p>Attaching a shader program the first time,
+ * <p>Attaching a shader program the first time,
* as well as switching to another program on the fly,
* while managing all attribute and uniform data.</p>
- *
+ *
* <p>[Re]sets all data and use program in case of a program switch.</p>
- *
+ *
* <p>Use program, {@link #useProgram(GL2ES2, boolean)},
* if <code>enable</code> is <code>true</code>.</p>
- *
+ *
+ * @return true if shader program was attached, otherwise false (already attached)
+ *
* @throws GLException if program was not linked and linking fails
*/
- public synchronized void attachShaderProgram(GL2ES2 gl, ShaderProgram prog, boolean enable) throws GLException {
- if(DEBUG) {
+ public synchronized boolean attachShaderProgram(GL2ES2 gl, ShaderProgram prog, boolean enable) throws GLException {
+ if(verbose) {
int curId = (null!=shaderProgram)?shaderProgram.id():-1;
int newId = (null!=prog)?prog.id():-1;
- System.err.println("Info: attachShaderProgram: "+curId+" -> "+newId+" (enable: "+enable+")\n\t"+shaderProgram+"\n\t"+prog);
- if(verbose) {
- Throwable tX = new Throwable("Info: attachShaderProgram: Trace");
- tX.printStackTrace();
+ System.err.println("ShaderState: attachShaderProgram: "+curId+" -> "+newId+" (enable: "+enable+")\n\t"+shaderProgram+"\n\t"+prog);
+ if(DEBUG) {
+ Thread.dumpStack();
}
}
if(null!=shaderProgram) {
if(shaderProgram.equals(prog)) {
- // nothing to do ..
- if(DEBUG) {
- System.err.println("Info: attachShaderProgram: NOP: equal id: "+shaderProgram.id());
+ if(enable) {
+ useProgram(gl, true);
+ }
+ // nothing else to do ..
+ if(verbose) {
+ System.err.println("ShaderState: attachShaderProgram: No switch, equal id: "+shaderProgram.id()+", enabling "+enable);
}
- return;
+ return false;
}
if(shaderProgram.inUse()) {
if(null != prog && enable) {
@@ -236,7 +190,7 @@ public class ShaderState {
shaderProgram = prog;
if(null!=shaderProgram) {
- // [re]set all data and use program if switching program,
+ // [re]set all data and use program if switching program,
// or use program if program is linked
if(resetAllShaderData || enable) {
useProgram(gl, true); // may reset all data
@@ -248,6 +202,7 @@ public class ShaderState {
if(DEBUG) {
System.err.println("Info: attachShaderProgram: END");
}
+ return true;
}
public ShaderProgram shaderProgram() { return shaderProgram; }
@@ -261,8 +216,7 @@ public class ShaderState {
*/
public synchronized void destroy(GL2ES2 gl) {
release(gl, true, true, true);
- attachedObjectsByString.clear();
- attachedObjectsByInt.clear();
+ attachedObjectsByString.clear();
}
/**
@@ -282,13 +236,13 @@ public class ShaderState {
* @see ShaderProgram#release(GL2ES2, boolean)
*/
public synchronized void release(GL2ES2 gl, boolean destroyBoundAttributes, boolean destroyShaderProgram, boolean destroyShaderCode) {
- if(null!=shaderProgram) {
+ if(null!=shaderProgram && shaderProgram.linked() ) {
shaderProgram.useProgram(gl, false);
}
if(destroyBoundAttributes) {
for(Iterator<GLArrayData> iter = managedAttributes.iterator(); iter.hasNext(); ) {
iter.next().destroy(gl);
- }
+ }
}
releaseAllAttributes(gl);
releaseAllUniforms(gl);
@@ -304,7 +258,7 @@ public class ShaderState {
/**
* Gets the cached location of a shader attribute.
*
- * @return -1 if there is no such attribute available,
+ * @return -1 if there is no such attribute available,
* otherwise >= 0
*
* @see #bindAttribLocation(GL2ES2, int, String)
@@ -316,7 +270,7 @@ public class ShaderState {
Integer idx = activeAttribLocationMap.get(name);
return (null!=idx)?idx.intValue():-1;
}
-
+
/**
* Get the previous cached vertex attribute data.
*
@@ -335,23 +289,30 @@ public class ShaderState {
public GLArrayData getAttribute(String name) {
return activeAttribDataMap.get(name);
}
-
+
+ public boolean isActiveAttribute(GLArrayData attribute) {
+ return attribute == activeAttribDataMap.get(attribute.getName());
+ }
+
/**
* Binds or unbinds the {@link GLArrayData} lifecycle to this ShaderState.
- *
+ *
* <p>If an attribute location is cached (ie {@link #bindAttribLocation(GL2ES2, int, String)})
* it is promoted to the {@link GLArrayData} instance.</p>
- *
- * <p>The attribute will be destroyed with {@link #destroy(GL2ES2)}
+ *
+ * <p>The attribute will be destroyed with {@link #destroy(GL2ES2)}
* and it's location will be reset when switching shader with {@link #attachShaderProgram(GL2ES2, ShaderProgram)}.</p>
- *
+ *
* <p>The data will not be transfered to the GPU, use {@link #vertexAttribPointer(GL2ES2, GLArrayData)} additionally.</p>
- *
+ *
+ * <p>The data will also be {@link GLArrayData#associate(Object, boolean) associated} with this ShaderState.</p>
+ *
* @param attribute the {@link GLArrayData} which lifecycle shall be managed
* @param own true if <i>owning</i> shall be performs, false if <i>disowning</i>.
- *
+ *
* @see #bindAttribLocation(GL2ES2, int, String)
* @see #getAttribute(String)
+ * @see GLArrayData#associate(Object, boolean)
*/
public void ownAttribute(GLArrayData attribute, boolean own) {
if(own) {
@@ -363,12 +324,13 @@ public class ShaderState {
} else {
managedAttributes.remove(attribute);
}
+ attribute.associate(this, own);
}
-
+
public boolean ownsAttribute(GLArrayData attribute) {
return managedAttributes.contains(attribute);
}
-
+
/**
* Binds a shader attribute to a location.
* Multiple names can be bound to one location.
@@ -377,14 +339,14 @@ public class ShaderState {
*
* @throws GLException if no program is attached
* @throws GLException if the program is already linked
- *
+ *
* @see javax.media.opengl.GL2ES2#glBindAttribLocation(int, int, String)
* @see #getAttribLocation(GL2ES2, String)
* @see #getCachedAttribLocation(String)
*/
public void bindAttribLocation(GL2ES2 gl, int location, String name) {
if(null==shaderProgram) throw new GLException("No program is attached");
- if(shaderProgram.linked()) throw new GLException("Program is already linked");
+ if(shaderProgram.linked()) throw new GLException("Program is already linked");
final Integer loc = new Integer(location);
activeAttribLocationMap.put(name, loc);
gl.glBindAttribLocation(shaderProgram.program(), location, name);
@@ -399,25 +361,28 @@ public class ShaderState {
*
* @throws GLException if no program is attached
* @throws GLException if the program is already linked
- *
+ *
* @see javax.media.opengl.GL2ES2#glBindAttribLocation(int, int, String)
* @see #getAttribLocation(GL2ES2, String)
* @see #getCachedAttribLocation(String)
* @see #getAttribute(String)
*/
public void bindAttribLocation(GL2ES2 gl, int location, GLArrayData data) {
- bindAttribLocation(gl, location, data.getName());
- data.setLocation(location);
+ if(null==shaderProgram) throw new GLException("No program is attached");
+ if(shaderProgram.linked()) throw new GLException("Program is already linked");
+ final String name = data.getName();
+ activeAttribLocationMap.put(name, new Integer(location));
+ data.setLocation(gl, shaderProgram.program(), location);
activeAttribDataMap.put(data.getName(), data);
}
/**
- * Gets the location of a shader attribute.<br>
+ * Gets the location of a shader attribute with given <code>name</code>.<br>
* Uses either the cached value {@link #getCachedAttribLocation(String)} if valid,
* or the GLSL queried via {@link GL2ES2#glGetAttribLocation(int, String)}.<br>
* The location will be cached.
*
- * @return -1 if there is no such attribute available,
+ * @return -1 if there is no such attribute available,
* otherwise >= 0
* @throws GLException if no program is attached
* @throws GLException if the program is not linked and no location was cached.
@@ -434,14 +399,15 @@ public class ShaderState {
if(!shaderProgram.linked()) throw new GLException("Program is not linked");
location = gl.glGetAttribLocation(shaderProgram.program(), name);
if(0<=location) {
- Integer idx = new Integer(location);
- activeAttribLocationMap.put(name, idx);
+ activeAttribLocationMap.put(name, new Integer(location));
if(DEBUG) {
- System.err.println("Info: glGetAttribLocation: "+name+", loc: "+location);
+ System.err.println("ShaderState: glGetAttribLocation: "+name+", loc: "+location);
}
} else if(verbose) {
- Throwable tX = new Throwable("Info: glGetAttribLocation failed, no location for: "+name+", loc: "+location);
- tX.printStackTrace();
+ System.err.println("ShaderState: glGetAttribLocation failed, no location for: "+name+", loc: "+location);
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
}
}
return location;
@@ -449,14 +415,14 @@ public class ShaderState {
/**
* Validates and returns the location of a shader attribute.<br>
- * Uses either the cached value {@link #getCachedAttribLocation(String)} if valid,
+ * Uses either the cached value {@link #getCachedAttribLocation(String)} if valid,
* or the GLSL queried via {@link GL2ES2#glGetAttribLocation(int, String)}.<br>
- * The location will be cached and set in the
+ * The location will be cached and set in the
* {@link GLArrayData} object.
*
- * @return -1 if there is no such attribute available,
+ * @return -1 if there is no such attribute available,
* otherwise >= 0
- *
+ *
* @throws GLException if no program is attached
* @throws GLException if the program is not linked and no location was cached.
*
@@ -467,12 +433,31 @@ public class ShaderState {
* @see #getAttribute(String)
*/
public int getAttribLocation(GL2ES2 gl, GLArrayData data) {
- int location = getAttribLocation(gl, data.getName());
- data.setLocation(location);
+ if(null==shaderProgram) throw new GLException("No program is attached");
+ final String name = data.getName();
+ int location = getCachedAttribLocation(name);
+ if(0<=location) {
+ data.setLocation(location);
+ } else {
+ if(!shaderProgram.linked()) throw new GLException("Program is not linked");
+ location = data.setLocation(gl, shaderProgram.program());
+ if(0<=location) {
+ Integer idx = new Integer(location);
+ activeAttribLocationMap.put(name, idx);
+ if(DEBUG) {
+ System.err.println("ShaderState: glGetAttribLocation: "+name+", loc: "+location);
+ }
+ } else if(verbose) {
+ System.err.println("ShaderState: glGetAttribLocation failed, no location for: "+name+", loc: "+location);
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
+ }
+ }
activeAttribDataMap.put(data.getName(), data);
return location;
}
-
+
//
// Enabled Vertex Arrays and its data
//
@@ -484,38 +469,40 @@ public class ShaderState {
final Boolean v = activedAttribEnabledMap.get(name);
return null != v && v.booleanValue();
}
-
+
/**
* @return true if the {@link GLArrayData} attribute is enable
*/
public final boolean isVertexAttribArrayEnabled(GLArrayData data) {
return isVertexAttribArrayEnabled(data.getName());
}
-
+
private boolean enableVertexAttribArray(GL2ES2 gl, String name, int location) {
activedAttribEnabledMap.put(name, Boolean.TRUE);
if(0>location) {
location = getAttribLocation(gl, name);
if(0>location) {
if(verbose) {
- Throwable tX = new Throwable("Info: glEnableVertexAttribArray failed, no index for: "+name);
- tX.printStackTrace();
+ System.err.println("ShaderState: glEnableVertexAttribArray failed, no index for: "+name);
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
}
return false;
}
}
if(DEBUG) {
- System.err.println("Info: glEnableVertexAttribArray: "+name+", loc: "+location);
+ System.err.println("ShaderState: glEnableVertexAttribArray: "+name+", loc: "+location);
}
gl.glEnableVertexAttribArray(location);
return true;
}
-
+
/**
* Enables a vertex attribute array.
- *
+ *
* This method retrieves the the location via {@link #getAttribLocation(GL2ES2, GLArrayData)}
- * hence {@link #enableVertexAttribArray(GL2ES2, GLArrayData)} shall be preferred.
+ * hence {@link #enableVertexAttribArray(GL2ES2, GLArrayData)} shall be preferred.
*
* Even if the attribute is not found in the current shader,
* it is marked enabled in this state.
@@ -523,7 +510,7 @@ public class ShaderState {
* @return false, if the name is not found, otherwise true
*
* @throws GLException if the program is not linked and no location was cached.
- *
+ *
* @see #glEnableVertexAttribArray
* @see #glDisableVertexAttribArray
* @see #glVertexAttribPointer
@@ -532,7 +519,7 @@ public class ShaderState {
public boolean enableVertexAttribArray(GL2ES2 gl, String name) {
return enableVertexAttribArray(gl, name, -1);
}
-
+
/**
* Enables a vertex attribute array, usually invoked by {@link GLArrayDataEditable#enableBuffer(GL, boolean)}.
@@ -541,7 +528,7 @@ public class ShaderState {
* and is the preferred alternative to {@link #enableVertexAttribArray(GL2ES2, String)}.
* If data location is unset it will be retrieved via {@link #getAttribLocation(GL2ES2, GLArrayData)} set
* and cached in this state.
- *
+ *
* Even if the attribute is not found in the current shader,
* it is marked enabled in this state.
*
@@ -560,36 +547,38 @@ public class ShaderState {
getAttribLocation(gl, data);
} else {
// ensure data is the current bound one
- activeAttribDataMap.put(data.getName(), data);
+ activeAttribDataMap.put(data.getName(), data);
}
return enableVertexAttribArray(gl, data.getName(), data.getLocation());
}
-
+
private boolean disableVertexAttribArray(GL2ES2 gl, String name, int location) {
activedAttribEnabledMap.put(name, Boolean.FALSE);
if(0>location) {
location = getAttribLocation(gl, name);
if(0>location) {
if(verbose) {
- Throwable tX = new Throwable("Info: glDisableVertexAttribArray failed, no index for: "+name);
- tX.printStackTrace();
+ System.err.println("ShaderState: glDisableVertexAttribArray failed, no index for: "+name);
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
}
return false;
}
}
if(DEBUG) {
- System.err.println("Info: glDisableVertexAttribArray: "+name);
+ System.err.println("ShaderState: glDisableVertexAttribArray: "+name);
}
gl.glDisableVertexAttribArray(location);
return true;
}
-
+
/**
* Disables a vertex attribute array
*
* This method retrieves the the location via {@link #getAttribLocation(GL2ES2, GLArrayData)}
* hence {@link #disableVertexAttribArray(GL2ES2, GLArrayData)} shall be preferred.
- *
+ *
* Even if the attribute is not found in the current shader,
* it is removed from this state enabled list.
*
@@ -614,7 +603,7 @@ public class ShaderState {
* and is the preferred alternative to {@link #disableVertexAttribArray(GL2ES2, String)}.
* If data location is unset it will be retrieved via {@link #getAttribLocation(GL2ES2, GLArrayData)} set
* and cached in this state.
- *
+ *
* Even if the attribute is not found in the current shader,
* it is removed from this state enabled list.
*
@@ -634,19 +623,20 @@ public class ShaderState {
}
return disableVertexAttribArray(gl, data.getName(), data.getLocation());
}
-
+
/**
- * Set the {@link GLArrayData} vertex attribute data.
- *
- * This method uses the {@link GLArrayData}'s location if set.
- * If data location is unset it will be retrieved via {@link #getAttribLocation(GL2ES2, GLArrayData)}, set
- * and cached in this state.
- *
+ * Set the {@link GLArrayData} vertex attribute data, if it's location is valid, i.e. &ge; 0.
+ * <p>
+ * This method uses the {@link GLArrayData}'s location if valid, i.e. &ge; 0.<br/>
+ * If data's location is invalid, it will be retrieved via {@link #getAttribLocation(GL2ES2, GLArrayData)},
+ * set and cached in this state.
+ * </p>
+ *
* @return false, if the location could not be determined, otherwise true
*
* @throws GLException if no program is attached
* @throws GLException if the program is not linked and no location was cached.
- *
+ *
* @see #glEnableVertexAttribArray
* @see #glDisableVertexAttribArray
* @see #glVertexAttribPointer
@@ -656,11 +646,11 @@ public class ShaderState {
int location = data.getLocation();
if(0 > location) {
location = getAttribLocation(gl, data);
- }
+ }
if(0 <= location) {
// only pass the data, if the attribute exists in the current shader
if(DEBUG) {
- System.err.println("Info: glVertexAttribPointer: "+data);
+ System.err.println("ShaderState: glVertexAttribPointer: "+data);
}
gl.glVertexAttribPointer(data);
return true;
@@ -693,16 +683,16 @@ public class ShaderState {
activeAttribDataMap.clear();
activedAttribEnabledMap.clear();
activeAttribLocationMap.clear();
- managedAttributes.clear();
+ managedAttributes.clear();
}
-
+
/**
* Disables all vertex attribute arrays.
*
* Their enabled stated will be removed from this state only
* if 'removeFromState' is true.
*
- * This method purpose is more for debugging.
+ * This method purpose is more for debugging.
*
* @see #glEnableVertexAttribArray
* @see #glDisableVertexAttribArray
@@ -727,34 +717,45 @@ public class ShaderState {
}
private final void relocateAttribute(GL2ES2 gl, GLArrayData attribute) {
- // get new location ..
+ // get new location .. note: 'activeAttribLocationMap' is cleared before
final String name = attribute.getName();
- final int loc = getAttribLocation(gl, name);
- attribute.setLocation(loc);
-
+ final int loc = attribute.setLocation(gl, shaderProgram.program());
if(0<=loc) {
+ activeAttribLocationMap.put(name, new Integer(loc));
+ if(DEBUG) {
+ System.err.println("ShaderState: relocateAttribute: "+name+", loc: "+loc);
+ }
if(isVertexAttribArrayEnabled(name)) {
// enable attrib, VBO and pass location/data
gl.glEnableVertexAttribArray(loc);
}
-
+
if( attribute.isVBO() ) {
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, attribute.getVBOName());
- }
-
- gl.glVertexAttribPointer(attribute);
+ gl.glVertexAttribPointer(attribute);
+ gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
+ } else {
+ gl.glVertexAttribPointer(attribute);
+ }
}
}
-
+
/**
* Reset all previously enabled mapped vertex attribute data.
- *
- * <p>Attribute data is bound to the GL state</p>
- * <p>Attribute location is bound to the program</p>
- *
- * <p>However, since binding an attribute to a location via {@link #bindAttribLocation(GL2ES2, int, GLArrayData)}
- * <i>must</i> happen before linking <b>and</b> we try to promote the attributes to the new program,
- * we have to gather the probably new location etc.</p>
+ *
+ * <p>
+ * Attribute data is bound to the GL state, i.e. VBO data itself will not be updated.
+ * </p>
+ *
+ * <p>
+ * Attribute location and it's data assignment is bound to the program,
+ * hence both are updated.
+ * </p>
+ *
+ * <p>
+ * Note: Such update could only be prevented,
+ * if tracking am attribute/program dirty flag.
+ * </p>
*
* @throws GLException is the program is not linked
*
@@ -763,9 +764,9 @@ public class ShaderState {
private final void resetAllAttributes(GL2ES2 gl) {
if(!shaderProgram.linked()) throw new GLException("Program is not linked");
activeAttribLocationMap.clear();
-
- for(Iterator<GLArrayData> iter = managedAttributes.iterator(); iter.hasNext(); ) {
- iter.next().setLocation(-1);
+
+ for(int i=0; i<managedAttributes.size(); i++) {
+ ((GLArrayData)managedAttributes.get(i)).setLocation(-1);
}
for(Iterator<GLArrayData> iter = activeAttribDataMap.values().iterator(); iter.hasNext(); ) {
relocateAttribute(gl, iter.next());
@@ -778,21 +779,23 @@ public class ShaderState {
final int loc = attribute.getLocation();
if(0<=loc) {
- this.bindAttribLocation(gl, loc, name);
-
+ bindAttribLocation(gl, loc, name);
+
if(isVertexAttribArrayEnabled(name)) {
// enable attrib, VBO and pass location/data
gl.glEnableVertexAttribArray(loc);
}
-
+
if( attribute.isVBO() ) {
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, attribute.getVBOName());
- }
-
- gl.glVertexAttribPointer(attribute);
+ gl.glVertexAttribPointer(attribute);
+ gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
+ } else {
+ gl.glVertexAttribPointer(attribute);
+ }
}
}
-
+
/**
* preserves the attribute location .. (program not linked)
*/
@@ -809,7 +812,7 @@ public class ShaderState {
/**
* Gets the cached location of the shader uniform.
*
- * @return -1 if there is no such uniform available,
+ * @return -1 if there is no such uniform available,
* otherwise >= 0
*/
public final int getCachedUniformLocation(String name) {
@@ -819,38 +822,38 @@ public class ShaderState {
/**
* Bind the {@link GLUniform} lifecycle to this ShaderState.
- *
+ *
* <p>If a uniform location is cached it is promoted to the {@link GLUniformData} instance.</p>
- *
- * <p>The attribute will be destroyed with {@link #destroy(GL2ES2)}
+ *
+ * <p>The attribute will be destroyed with {@link #destroy(GL2ES2)}
* and it's location will be reset when switching shader with {@link #attachShaderProgram(GL2ES2, ShaderProgram)}.</p>
- *
+ *
* <p>The data will not be transfered to the GPU, use {@link #uniform(GL2ES2, GLUniformData)} additionally.</p>
- *
+ *
* @param uniform the {@link GLUniformData} which lifecycle shall be managed
- *
+ *
* @see #getUniform(String)
*/
public void ownUniform(GLUniformData uniform) {
final int location = getCachedUniformLocation(uniform.getName());
if(0<=location) {
uniform.setLocation(location);
- }
+ }
activeUniformDataMap.put(uniform.getName(), uniform);
- managedUniforms.add(uniform);
+ managedUniforms.add(uniform);
}
-
+
public boolean ownsUniform(GLUniformData uniform) {
return managedUniforms.contains(uniform);
}
-
+
/**
- * Gets the location of a shader uniform.<br>
+ * Gets the location of a shader uniform with given <code>name</code>.<br>
* Uses either the cached value {@link #getCachedUniformLocation(String)} if valid,
* or the GLSL queried via {@link GL2ES2#glGetUniformLocation(int, String)}.<br>
* The location will be cached.
* <p>
- * The current shader program ({@link #attachShaderProgram(GL2ES2, ShaderProgram)})
+ * The current shader program ({@link #attachShaderProgram(GL2ES2, ShaderProgram)})
* must be in use ({@link #useProgram(GL2ES2, boolean) }) !</p>
*
* @return -1 if there is no such attribute available,
@@ -867,13 +870,16 @@ public class ShaderState {
if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
int location = getCachedUniformLocation(name);
if(0>location) {
+ if(!shaderProgram.linked()) throw new GLException("Program is not linked");
location = gl.glGetUniformLocation(shaderProgram.program(), name);
if(0<=location) {
Integer idx = new Integer(location);
activeUniformLocationMap.put(name, idx);
} else if(verbose) {
- Throwable tX = new Throwable("Info: glUniform failed, no location for: "+name+", index: "+location);
- tX.printStackTrace();
+ System.err.println("ShaderState: glUniform failed, no location for: "+name+", index: "+location);
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
}
}
return location;
@@ -883,10 +889,10 @@ public class ShaderState {
* Validates and returns the location of a shader uniform.<br>
* Uses either the cached value {@link #getCachedUniformLocation(String)} if valid,
* or the GLSL queried via {@link GL2ES2#glGetUniformLocation(int, String)}.<br>
- * The location will be cached and set in the
+ * The location will be cached and set in the
* {@link GLUniformData} object.
* <p>
- * The current shader program ({@link #attachShaderProgram(GL2ES2, ShaderProgram)})
+ * The current shader program ({@link #attachShaderProgram(GL2ES2, ShaderProgram)})
* must be in use ({@link #useProgram(GL2ES2, boolean) }) !</p>
*
* @return -1 if there is no such attribute available,
@@ -900,26 +906,36 @@ public class ShaderState {
* @see ShaderProgram#glReplaceShader
*/
public int getUniformLocation(GL2ES2 gl, GLUniformData data) {
- int location = getUniformLocation(gl, data.getName());
- data.setLocation(location);
- activeUniformDataMap.put(data.getName(), data);
+ if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
+ final String name = data.getName();
+ int location = getCachedUniformLocation(name);
+ if(0<=location) {
+ data.setLocation(location);
+ } else {
+ if(!shaderProgram.linked()) throw new GLException("Program is not linked");
+ location = data.setLocation(gl, shaderProgram.program());
+ if(0<=location) {
+ activeUniformLocationMap.put(name, new Integer(location));
+ } else if(verbose) {
+ System.err.println("ShaderState: glUniform failed, no location for: "+name+", index: "+location);
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
+ }
+ }
+ activeUniformDataMap.put(name, data);
return location;
}
-
+
/**
- * Set the uniform data.
- *
- * Even if the uniform is not found in the current shader,
- * it is stored in this state.
- *
- * @param data the GLUniforms's name must match the uniform one,
- * it's index will be set with the uniforms's location,
- * if found.
- *
- *
- * @return false, if the name is not found, otherwise true
+ * Set the uniform data, if it's location is valid, i.e. &ge; 0.
+ * <p>
+ * This method uses the {@link GLUniformData}'s location if valid, i.e. &ge; 0.<br/>
+ * If data's location is invalid, it will be retrieved via {@link #getUniformLocation(GL2ES2, GLUniformData)},
+ * set and cached in this state.
+ * </p>
*
- * @throws GLException if the program is not in use
+ * @return false, if the location could not be determined, otherwise true
*
* @see #glGetUniformLocation
* @see javax.media.opengl.GL2ES2#glGetUniformLocation
@@ -936,11 +952,12 @@ public class ShaderState {
if(0<=location) {
// only pass the data, if the uniform exists in the current shader
if(DEBUG) {
- System.err.println("Info: glUniform: "+data);
+ System.err.println("ShaderState: glUniform: "+data);
}
gl.glUniform(data);
+ return true;
}
- return true;
+ return false;
}
/**
@@ -961,37 +978,49 @@ public class ShaderState {
activeUniformLocationMap.clear();
managedUniforms.clear();
}
-
+
/**
* Reset all previously mapped uniform data
- *
+ * <p>
* Uniform data and location is bound to the program,
- * hence both are updated here
+ * hence both are updated.
+ * </p>
+ * <p>
+ * Note: Such update could only be prevented,
+ * if tracking a uniform/program dirty flag.
+ * </p>
*
* @throws GLException is the program is not in use
- *
+ *
* @see #attachShaderProgram(GL2ES2, ShaderProgram)
*/
private final void resetAllUniforms(GL2ES2 gl) {
- if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
+ if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
activeUniformLocationMap.clear();
for(Iterator<GLUniformData> iter = managedUniforms.iterator(); iter.hasNext(); ) {
iter.next().setLocation(-1);
- }
+ }
for(Iterator<GLUniformData> iter = activeUniformDataMap.values().iterator(); iter.hasNext(); ) {
- final GLUniformData uniform = iter.next();
- uniform.setLocation(-1);
- uniform(gl, uniform);
+ final GLUniformData data = iter.next();
+ final int loc = data.setLocation(gl, shaderProgram.program());
+ if( 0 <= loc ) {
+ // only pass the data, if the uniform exists in the current shader
+ activeUniformLocationMap.put(data.getName(), new Integer(loc));
+ if(DEBUG) {
+ System.err.println("ShaderState: resetAllUniforms: "+data);
+ }
+ gl.glUniform(data);
+ }
}
}
- public StringBuilder toString(StringBuilder sb) {
+ public StringBuilder toString(StringBuilder sb, boolean alsoUnlocated) {
if(null==sb) {
sb = new StringBuilder();
}
-
+
sb.append("ShaderState[ ");
-
+
sb.append(Platform.getNewline()).append(" ");
if(null != shaderProgram) {
shaderProgram.toString(sb);
@@ -1008,43 +1037,54 @@ public class ShaderState {
}
sb.append(Platform.getNewline()).append(" ],").append(" activeAttributes [");
for(Iterator<GLArrayData> iter = activeAttribDataMap.values().iterator(); iter.hasNext(); ) {
- sb.append(Platform.getNewline()).append(" ").append(iter.next());
+ final GLArrayData ad = iter.next();
+ if( alsoUnlocated || 0 <= ad.getLocation() ) {
+ sb.append(Platform.getNewline()).append(" ").append(ad);
+ }
}
sb.append(Platform.getNewline()).append(" ],").append(" managedAttributes [");
for(Iterator<GLArrayData> iter = managedAttributes.iterator(); iter.hasNext(); ) {
- sb.append(Platform.getNewline()).append(" ").append(iter.next());
+ final GLArrayData ad = iter.next();
+ if( alsoUnlocated || 0 <= ad.getLocation() ) {
+ sb.append(Platform.getNewline()).append(" ").append(ad);
+ }
}
sb.append(Platform.getNewline()).append(" ],").append(" activeUniforms [");
for(Iterator<GLUniformData> iter=activeUniformDataMap.values().iterator(); iter.hasNext(); ) {
- sb.append(Platform.getNewline()).append(" ").append(iter.next());
+ final GLUniformData ud = iter.next();
+ if( alsoUnlocated || 0 <= ud.getLocation() ) {
+ sb.append(Platform.getNewline()).append(" ").append(ud);
+ }
}
sb.append(Platform.getNewline()).append(" ],").append(" managedUniforms [");
for(Iterator<GLUniformData> iter = managedUniforms.iterator(); iter.hasNext(); ) {
- sb.append(Platform.getNewline()).append(" ").append(iter.next());
+ final GLUniformData ud = iter.next();
+ if( alsoUnlocated || 0 <= ud.getLocation() ) {
+ sb.append(Platform.getNewline()).append(" ").append(ud);
+ }
}
sb.append(Platform.getNewline()).append(" ]").append(Platform.getNewline()).append("]");
return sb;
}
-
+
@Override
public String toString() {
- return toString(null).toString();
+ return toString(null, DEBUG).toString();
}
-
- private boolean verbose = DEBUG ? true : false;
+
+ private boolean verbose = DEBUG;
private ShaderProgram shaderProgram=null;
-
+
private HashMap<String, Boolean> activedAttribEnabledMap = new HashMap<String, Boolean>();
private HashMap<String, Integer> activeAttribLocationMap = new HashMap<String, Integer>();
private HashMap<String, GLArrayData> activeAttribDataMap = new HashMap<String, GLArrayData>();
private ArrayList<GLArrayData> managedAttributes = new ArrayList<GLArrayData>();
-
+
private HashMap<String, Integer> activeUniformLocationMap = new HashMap<String, Integer>();
private HashMap<String, GLUniformData> activeUniformDataMap = new HashMap<String, GLUniformData>();
private ArrayList<GLUniformData> managedUniforms = new ArrayList<GLUniformData>();
-
- private HashMap<String, Object> attachedObjectsByString = new HashMap<String, Object>();
- private IntObjectHashMap attachedObjectsByInt = new IntObjectHashMap();
+
+ private HashMap<String, Object> attachedObjectsByString = new HashMap<String, Object>();
private boolean resetAllShaderData = false;
}
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java
index 40c052498..5cd384c58 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java
@@ -1,21 +1,21 @@
/*
* Copyright (c) 2009 Sun Microsystems, Inc. All Rights Reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -28,7 +28,7 @@
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
*/
package com.jogamp.opengl.util.glsl;
@@ -40,6 +40,7 @@ import java.util.*;
import javax.media.opengl.*;
import com.jogamp.common.nio.Buffers;
+import com.jogamp.opengl.GLExtensions;
public class ShaderUtil {
public static String getShaderInfoLog(GL _gl, int shaderObj) {
@@ -116,11 +117,11 @@ public class ShaderUtil {
}
return true;
}
-
+
/**
* Performs {@link GL2ES2#glValidateProgram(int)}
* <p>
- * One shall only call this method while debugging and only if all required
+ * One shall only call this method while debugging and only if all required
* resources by the shader are set.
* </p>
* <p>
@@ -149,7 +150,7 @@ public class ShaderUtil {
}
/**
- * If supported, queries the natively supported shader binary formats using
+ * If supported, queries the natively supported shader binary formats using
* {@link GL2ES2#GL_NUM_SHADER_BINARY_FORMATS} and {@link GL2ES2#GL_SHADER_BINARY_FORMATS}
* via {@link GL2ES2#glGetIntegerv(int, int[], int)}.
*/
@@ -159,15 +160,21 @@ public class ShaderUtil {
if(null == info.shaderBinaryFormats) {
info.shaderBinaryFormats = new HashSet<Integer>();
if (gl.isGLES2Compatible()) {
- final int[] param = new int[1];
- gl.glGetIntegerv(GL2ES2.GL_NUM_SHADER_BINARY_FORMATS, param, 0);
- int numFormats = param[0];
- if(numFormats>0) {
- int[] formats = new int[numFormats];
- gl.glGetIntegerv(GL2ES2.GL_SHADER_BINARY_FORMATS, formats, 0);
- for(int i=0; i<numFormats; i++) {
- info.shaderBinaryFormats.add(new Integer(formats[i]));
+ try {
+ final int[] param = new int[1];
+ gl.glGetIntegerv(GL2ES2.GL_NUM_SHADER_BINARY_FORMATS, param, 0);
+ final int err = gl.glGetError();
+ final int numFormats = GL.GL_NO_ERROR == err ? param[0] : 0;
+ if(numFormats>0) {
+ int[] formats = new int[numFormats];
+ gl.glGetIntegerv(GL2ES2.GL_SHADER_BINARY_FORMATS, formats, 0);
+ for(int i=0; i<numFormats; i++) {
+ info.shaderBinaryFormats.add(new Integer(formats[i]));
+ }
}
+ } catch (GLException gle) {
+ System.err.println("Catched Exception on thread "+Thread.currentThread().getName());
+ gle.printStackTrace();
}
}
}
@@ -180,17 +187,28 @@ public class ShaderUtil {
final ProfileInformation info = getProfileInformation(gl);
if(null==info.shaderCompilerAvailable) {
if(gl.isGLES2()) {
- final byte[] param = new byte[1];
- gl.glGetBooleanv(GL2ES2.GL_SHADER_COMPILER, param, 0);
- boolean v = param[0]!=(byte)0x00;
- if(!v) {
- final Set<Integer> bfs = getShaderBinaryFormats(gl);
- if(bfs.size()==0) {
- // no supported binary formats, hence a compiler must be available!
- v = true;
+ boolean queryOK = false;
+ try {
+ final byte[] param = new byte[1];
+ gl.glGetBooleanv(GL2ES2.GL_SHADER_COMPILER, param, 0);
+ final int err = gl.glGetError();
+ boolean v = GL.GL_NO_ERROR == err && param[0]!=(byte)0x00;
+ if(!v) {
+ final Set<Integer> bfs = getShaderBinaryFormats(gl);
+ if(bfs.size()==0) {
+ // no supported binary formats, hence a compiler must be available!
+ v = true;
+ }
}
+ info.shaderCompilerAvailable = new Boolean(v);
+ queryOK = true;
+ } catch (GLException gle) {
+ System.err.println("Catched Exception on thread "+Thread.currentThread().getName());
+ gle.printStackTrace();
+ }
+ if(!queryOK) {
+ info.shaderCompilerAvailable = new Boolean(true);
}
- info.shaderCompilerAvailable = new Boolean(v);
} else if( gl.isGL2ES2() ) {
info.shaderCompilerAvailable = new Boolean(true);
} else {
@@ -200,6 +218,13 @@ public class ShaderUtil {
return info.shaderCompilerAvailable.booleanValue();
}
+ /** Returns true if GeometryShader is supported, i.e. whether GLContext is &ge; 3.2 or ARB_geometry_shader4 extension is available. */
+ public static boolean isGeometryShaderSupported(GL _gl) {
+ final GLContext ctx = _gl.getContext();
+ return ctx.getGLVersionNumber().compareTo(GLContext.Version320) >= 0 ||
+ ctx.isExtensionAvailable(GLExtensions.ARB_geometry_shader4);
+ }
+
public static void shaderSource(GL _gl, int shader, CharSequence[] source)
{
final GL2ES2 gl = _gl.getGL2ES2();
@@ -215,7 +240,7 @@ public class ShaderUtil {
IntBuffer lengths = Buffers.newDirectIntBuffer(count);
for(int i=0; i<count; i++) {
lengths.put(i, source[i].length());
- }
+ }
if(source instanceof String[]) {
// rare case ..
gl.glShaderSource(shader, count, (String[])source, lengths);
@@ -224,10 +249,10 @@ public class ShaderUtil {
for(int i = source.length - 1; i>=0; i--) {
final CharSequence csq = source[i];
if(csq instanceof String) {
- // if ShaderCode.create(.. mutableStringBuffer == false )
+ // if ShaderCode.create(.. mutableStringBuilder == false )
tmp[i] = (String) csq;
} else {
- // if ShaderCode.create(.. mutableStringBuffer == true )
+ // if ShaderCode.create(.. mutableStringBuilder == true )
tmp[i] = source[i].toString();
}
}
@@ -313,7 +338,7 @@ public class ShaderUtil {
}
createShader(gl, shaderType, shader);
- err = gl.glGetError();
+ err = gl.glGetError();
if(err!=GL.GL_NO_ERROR) {
throw new GLException("createAndLoadShader: CreateShader failed, GL Error: 0x"+Integer.toHexString(err));
}
@@ -328,7 +353,7 @@ public class ShaderUtil {
}
public static boolean createAndCompileShader(GL _gl, IntBuffer shader, int shaderType,
- CharSequence[][] sources,
+ CharSequence[][] sources,
PrintStream verboseOut)
{
final GL2ES2 gl = _gl.getGL2ES2();
@@ -338,32 +363,32 @@ public class ShaderUtil {
}
createShader(gl, shaderType, shader);
- err = gl.glGetError();
+ err = gl.glGetError();
if(err!=GL.GL_NO_ERROR) {
throw new GLException("createAndCompileShader: CreateShader failed, GL Error: 0x"+Integer.toHexString(err));
}
shaderSource(gl, shader, sources);
- err = gl.glGetError();
+ err = gl.glGetError();
if(err!=GL.GL_NO_ERROR) {
throw new GLException("createAndCompileShader: ShaderSource failed, GL Error: 0x"+Integer.toHexString(err));
}
compileShader(gl, shader);
- err = gl.glGetError();
+ err = gl.glGetError();
if(err!=GL.GL_NO_ERROR && null!=verboseOut) {
verboseOut.println("createAndCompileShader: CompileShader failed, GL Error: 0x"+Integer.toHexString(err));
}
return isShaderStatusValid(gl, shader, GL2ES2.GL_COMPILE_STATUS, verboseOut) && err == GL.GL_NO_ERROR;
}
-
+
private static final String implObjectKey = "com.jogamp.opengl.util.glsl.ShaderUtil" ;
-
+
private static class ProfileInformation {
Boolean shaderCompilerAvailable = null;
Set<Integer> shaderBinaryFormats = null;
- }
+ }
private static ProfileInformation getProfileInformation(GL gl) {
final GLContext context = gl.getContext();
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/fixedfunc/FixedFuncUtil.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/fixedfunc/FixedFuncUtil.java
index d92a7aa22..2f8884a3a 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/fixedfunc/FixedFuncUtil.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/fixedfunc/FixedFuncUtil.java
@@ -4,26 +4,45 @@
package com.jogamp.opengl.util.glsl.fixedfunc;
-import javax.media.opengl.*;
-import javax.media.opengl.fixedfunc.*;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES1;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLException;
+import javax.media.opengl.fixedfunc.GLPointerFuncUtil;
+
+import jogamp.opengl.util.glsl.fixedfunc.FixedFuncHook;
+import jogamp.opengl.util.glsl.fixedfunc.FixedFuncImpl;
+import jogamp.opengl.util.glsl.fixedfunc.FixedFuncPipeline;
+
+import com.jogamp.opengl.util.PMVMatrix;
-import jogamp.opengl.util.glsl.fixedfunc.*;
/**
* Tool to pipeline GL2ES2 into a fixed function emulation implementing GL2ES1.
*/
public class FixedFuncUtil {
/**
+ * @param gl
+ * @param mode one of the {@link ShaderSelectionMode}s
+ * @param pmvMatrix optional pass through PMVMatrix for the {@link FixedFuncHook} and {@link FixedFuncPipeline}
* @return If gl is a GL2ES1 and force is false, return the type cast object,
* otherwise create a fixed function emulation pipeline using the given GL2ES2 impl
* and hook it to the GLContext via {@link GLContext#setGL(GL)}.
* @throws GLException if the GL object is neither GL2ES1 nor GL2ES2
+ *
+ * @see ShaderSelectionMode#AUTO
+ * @see ShaderSelectionMode#COLOR
+ * @see ShaderSelectionMode#COLOR_LIGHT_PER_VERTEX
+ * @see ShaderSelectionMode#COLOR_TEXTURE
+ * @see ShaderSelectionMode#COLOR_TEXTURE_LIGHT_PER_VERTEX
*/
- public static final GL2ES1 wrapFixedFuncEmul(GL gl, boolean force) {
+ public static final GL2ES1 wrapFixedFuncEmul(GL gl, ShaderSelectionMode mode, PMVMatrix pmvMatrix, boolean force, boolean verbose) {
if(gl.isGL2ES2() && ( !gl.isGL2ES1() || force ) ) {
- GL2ES2 es2 = gl.getGL2ES2();
- FixedFuncHook hook = new FixedFuncHook(es2);
- FixedFuncImpl impl = new FixedFuncImpl(es2, hook);
+ final GL2ES2 es2 = gl.getGL2ES2();
+ final FixedFuncHook hook = new FixedFuncHook(es2, mode, pmvMatrix);
+ hook.setVerbose(verbose);
+ final FixedFuncImpl impl = new FixedFuncImpl(es2, hook);
gl.getContext().setGL(impl);
return impl;
} else if(gl.isGL2ES1()) {
@@ -33,21 +52,30 @@ public class FixedFuncUtil {
}
/**
+ * @param gl
+ * @param mode one of the {@link ShaderSelectionMode}s
+ * @param pmvMatrix optional pass through PMVMatrix for the {@link FixedFuncHook} and {@link FixedFuncPipeline}
* @return If gl is a GL2ES1, return the type cast object,
* otherwise create a fixed function emulation pipeline using the GL2ES2 impl.
* and hook it to the GLContext via {@link GLContext#setGL(GL)}.
* @throws GLException if the GL object is neither GL2ES1 nor GL2ES2
+ *
+ * @see ShaderSelectionMode#AUTO
+ * @see ShaderSelectionMode#COLOR
+ * @see ShaderSelectionMode#COLOR_LIGHT_PER_VERTEX
+ * @see ShaderSelectionMode#COLOR_TEXTURE
+ * @see ShaderSelectionMode#COLOR_TEXTURE_LIGHT_PER_VERTEX
*/
- public static final GL2ES1 wrapFixedFuncEmul(GL gl) {
- return wrapFixedFuncEmul(gl, false);
+ public static final GL2ES1 wrapFixedFuncEmul(GL gl, ShaderSelectionMode mode, PMVMatrix pmvMatrix) {
+ return wrapFixedFuncEmul(gl, mode, null, false, false);
}
/**
- * Mapping fixed function (client) array indices to
+ * Mapping fixed function (client) array indices to
* GLSL array attribute names.
*
* Useful for uniq mapping of canonical array index names as listed.
- *
+ *
* @see #mgl_Vertex
* @see javax.media.opengl.fixedfunc.GLPointerFunc#GL_VERTEX_ARRAY
* @see #mgl_Normal
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/fixedfunc/ShaderSelectionMode.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/fixedfunc/ShaderSelectionMode.java
new file mode 100644
index 000000000..426fb0d85
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/fixedfunc/ShaderSelectionMode.java
@@ -0,0 +1,27 @@
+package com.jogamp.opengl.util.glsl.fixedfunc;
+
+/**
+ * Shader selection mode
+ *
+ * @see ShaderSelectionMode#AUTO
+ * @see ShaderSelectionMode#COLOR
+ * @see ShaderSelectionMode#COLOR_LIGHT_PER_VERTEX
+ * @see ShaderSelectionMode#COLOR_TEXTURE
+ * @see ShaderSelectionMode#COLOR_TEXTURE_LIGHT_PER_VERTEX
+ */
+public enum ShaderSelectionMode {
+ /** Auto shader selection, based upon FFP states. */
+ AUTO,
+ /** Fixed shader selection: Simple color. */
+ COLOR,
+ /** Fixed shader selection: Multi-Textured color. 2 texture units. */
+ COLOR_TEXTURE2,
+ /** Fixed shader selection: Multi-Textured color. 4 texture units. */
+ COLOR_TEXTURE4,
+ /** Fixed shader selection: Multi-Textured color. 8 texture units. */
+ COLOR_TEXTURE8,
+ /** Fixed shader selection: Color with vertex-lighting. */
+ COLOR_LIGHT_PER_VERTEX,
+ /** Fixed shader selection: Multi-Textured color with vertex-lighting. 8 texture units.*/
+ COLOR_TEXTURE8_LIGHT_PER_VERTEX
+} \ No newline at end of file
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java
index a5b1c6687..44fbf1c6d 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShader.java
@@ -55,8 +55,8 @@ public abstract class CompileShader {
URL resourceURL = IOUtil.getResource(null, resourceName).getURL();
String dirName = dirname(resourceURL.getPath());
- outName = dirName + File.separator + "bin" + File.separator +
- ShaderCode.getBinarySubPath(getBinaryFormat()) + File.separator +
+ outName = dirName + File.separator + "bin" + File.separator +
+ ShaderCode.getBinarySubPath(getBinaryFormat()) + File.separator +
outName;
processOneShader(resourceName, outName, type);
}
@@ -137,7 +137,7 @@ public abstract class CompileShader {
}
String dirname;
if (lastSlash < 0) {
- dirname = new String();
+ dirname = "";
} else {
dirname = path.substring(0, lastSlash + 1);
}
@@ -161,6 +161,7 @@ public abstract class CompileShader {
new Thread(this, "Output Reader Thread").start();
}
+ @Override
public void run()
{
byte[] buffer = new byte[4096];
diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShaderNVidia.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShaderNVidia.java
index 8eb9ef579..215cf592b 100644
--- a/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShaderNVidia.java
+++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/sdk/CompileShaderNVidia.java
@@ -21,10 +21,12 @@ public class CompileShaderNVidia extends CompileShader {
}
}
+ @Override
public int getBinaryFormat() {
return GLES2.GL_NVIDIA_PLATFORM_BINARY_NV;
}
+ @Override
public File getSDKCompilerDir() {
File compilerDir = new File( NVAPSDK + File.separator + "tools" + File.separator );
File compilerFile = new File( compilerDir, getVertexShaderCompiler());
@@ -39,10 +41,12 @@ public class CompileShaderNVidia extends CompileShader {
return compilerDir;
}
+ @Override
public String getVertexShaderCompiler() {
return "glslv.bat";
}
+ @Override
public String getFragmentShaderCompiler() {
return "glslf.bat";
}