aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java387
1 files changed, 294 insertions, 93 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
//