aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java524
1 files changed, 282 insertions, 242 deletions
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;
}