/**
* Copyright 2010 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions 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.
*
* THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation are those of the
* authors and should not be interpreted as representing official policies, either expressed
* or implied, of JogAmp Community.
*/
package com.jogamp.opengl.util.glsl;
import java.security.AccessController;
import java.util.HashMap;
import java.util.HashSet;
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.util.IntObjectHashMap;
import com.jogamp.opengl.util.GLArrayDataEditable;
public class ShaderState {
public static final boolean DEBUG = Debug.isPropertyDefined("jogl.debug.GLSLState", true, AccessController.getContext());
public ShaderState() {
}
public boolean verbose() { return verbose; }
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#glUseProgram(GL2ES2, boolean)
* @see com.jogamp.opengl.util.glsl.ShaderState#getShaderState(GL)
* @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState()
*/
public static synchronized ShaderState getCurrentShaderState() {
return getShaderState(GLContext.getCurrentGL());
}
/**
* Fetches the shader state from the GL object's GLContext
*
* @param gl the GL object referencing the GLContext
*
* @see com.jogamp.opengl.util.glsl.ShaderState#glUseProgram(GL2ES2, boolean)
* @see com.jogamp.opengl.util.glsl.ShaderState#getShaderState(GL)
* @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState()
*/
public static synchronized ShaderState getShaderState(GL gl) {
return (ShaderState) gl.getContext().getAttachedObject(ShaderState.class.getName());
}
/**
* Returns the attached user object for the given name to this ShaderState.
*/
public final Object getAttachedObject(String name) {
return attachedObjectsByString.get(name);
}
/**
* 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) {
return attachedObjectsByString.put(name, obj);
}
/**
* @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.
* Puts this ShaderState to to the thread local storage (TLS),
* if on
is true
.
*
* @throws GLException if no program is attached
* @throws GLException if no program is not linked
*
* @see com.jogamp.opengl.util.glsl.ShaderState#glUseProgram(GL2ES2, boolean)
* @see com.jogamp.opengl.util.glsl.ShaderState#getShaderState(GL)
* @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState()
*/
public synchronized void glUseProgram(GL2ES2 gl, boolean on) {
if(null==shaderProgram) { throw new GLException("No program is attached"); }
if(on) {
shaderProgram.glUseProgram(gl, true);
// update the current ShaderState to the TLS ..
gl.getContext().attachObject(ShaderState.class.getName(), this);
if(resetAllShaderData) {
resetAllShaderData = false;
glResetAllVertexAttributes(gl);
glResetAllUniforms(gl);
}
} else {
shaderProgram.glUseProgram(gl, false);
}
}
public synchronized void glUseProgram(GL2ES2 gl, ShaderProgram prog, boolean on) {
}
public boolean linked() {
return (null!=shaderProgram)?shaderProgram.linked():false;
}
public boolean inUse() {
return (null!=shaderProgram)?shaderProgram.inUse():false;
}
/**
* Attach or switch a shader program
*
* Attaching a shader program the first time,
* as well as switching to another program on the fly,
* while managing all attribute and uniform data.
*/
public synchronized void attachShaderProgram(GL2ES2 gl, ShaderProgram prog) {
boolean prgInUse = false; // earmarked state
if(DEBUG) {
int curId = (null!=shaderProgram)?shaderProgram.id():-1;
int newId = (null!=prog)?prog.id():-1;
System.err.println("Info: attachShaderProgram: "+curId+" -> "+newId+"\n\t"+shaderProgram+"\n\t"+prog);
if(verbose) {
Throwable tX = new Throwable("Info: attachShaderProgram: Trace");
tX.printStackTrace();
}
}
if(null!=shaderProgram) {
if(shaderProgram.equals(prog)) {
// nothing to do ..
if(DEBUG) {
System.err.println("Info: attachShaderProgram: NOP: equal id: "+shaderProgram.id());
}
return;
}
prgInUse = shaderProgram.inUse();
glUseProgram(gl, false);
resetAllShaderData = true;
}
// register new one
shaderProgram = prog;
if(null!=shaderProgram) {
// reinstall all data ..
if(shaderProgram.linked()) {
glUseProgram(gl, true);
if(!prgInUse) {
shaderProgram.glUseProgram(gl, false);
}
}
}
if(DEBUG) {
System.err.println("Info: attachShaderProgram: END");
}
}
public ShaderProgram shaderProgram() { return shaderProgram; }
/**
* Calls release(gl, true, true)
*
* @see #glReleaseAllVertexAttributes
* @see #glReleaseAllUniforms
* @see #release(GL2ES2, boolean, boolean)
*/
public synchronized void destroy(GL2ES2 gl) {
release(gl, true, true);
attachedObjectsByString.clear();
attachedObjectsByInt.clear();
}
/**
* Calls release(gl, false, false)
*
* @see #glReleaseAllVertexAttributes
* @see #glReleaseAllUniforms
* @see #release(GL2ES2, boolean, boolean)
*/
public synchronized void releaseAllData(GL2ES2 gl) {
release(gl, false, false);
}
/**
* @see #glReleaseAllVertexAttributes
* @see #glReleaseAllUniforms
* @see ShaderProgram#release(GL2ES2, boolean)
*/
public synchronized void release(GL2ES2 gl, boolean releaseProgramToo, boolean releaseShaderToo) {
boolean prgInUse = false;
if(null!=shaderProgram) {
prgInUse = shaderProgram.inUse();
if(!prgInUse) {
shaderProgram.glUseProgram(gl, true);
}
}
glReleaseAllVertexAttributes(gl);
glReleaseAllUniforms(gl);
if(null!=shaderProgram) {
if(releaseProgramToo) {
shaderProgram.release(gl, releaseShaderToo);
} else if(!prgInUse) {
shaderProgram.glUseProgram(gl, false);
}
}
}
//
// Shader attribute handling
//
/**
* Gets the cached location of a shader attribute.
*
* @return -1 if there is no such attribute available,
* otherwise >= 0
*
* @see #glBindAttribLocation(GL2ES2, int, String)
* @see #glBindAttribLocation(GL2ES2, int, GLArrayData)
* @see #glGetAttribLocation(GL2ES2, String)
* @see GL2ES2#glGetAttribLocation(int, String)
*/
public int getAttribLocation(String name) {
Integer idx = (Integer) attribMap2Location.get(name);
return (null!=idx)?idx.intValue():-1;
}
/**
* Get the previous cached vertex attribute data.
*
* @return the GLArrayData object, null if not previously set.
*
* @see #bindAttribute(GLArrayData)
*
* @see #glEnableVertexAttribArray
* @see #glDisableVertexAttribArray
* @see #glVertexAttribPointer
* @see #getVertexAttribPointer
* @see #glReleaseAllVertexAttributes
* @see #glResetAllVertexAttributes
* @see ShaderProgram#glReplaceShader
*/
public GLArrayData getAttribute(String name) {
return (GLArrayData) vertexAttribMap2Data.get(name);
}
/**
* Bind the {@link GLArrayData} to this ShaderState.
* If an attribute location is cached (ie {@link #glBindAttribLocation(GL2ES2, int, String)})
* it is promoted to the {@link GLArrayData} instance.
* To bind a {@link GLArrayData} with a given location
* {@link #glBindAttribLocation(GL2ES2, int, GLArrayData)} shall be used.
*
* @param data the {@link GLArrayData} to be processed
* @see #glBindAttribLocation(GL2ES2, int, String)
* @see #getAttribute(String)
*/
public void bindAttribute(GLArrayData data) {
final int location = getAttribLocation(data.getName());
if(0<=location) {
data.setLocation(location);
}
vertexAttribMap2Data.put(data.getName(), data);
}
/**
* Binds a shader attribute to a location.
* Multiple names can be bound to one location.
* The value will be cached and can be retrieved via {@link #getAttribLocation(String)}
* before or after linking.
*
* @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 #glGetAttribLocation(GL2ES2, String)
* @see #getAttribLocation(String)
*/
public void glBindAttribLocation(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");
final Integer loc = new Integer(location);
attribMap2Location.put(name, loc);
gl.glBindAttribLocation(shaderProgram.program(), location, name);
}
/**
* Binds a shader {@link GLArrayData} attribute to a location.
* Multiple names can be bound to one location.
* The value will be cached and can be retrieved via {@link #getAttribLocation(String)}
* and {@link #getAttribute(String)}before or after linking.
* The {@link GLArrayData}'s location will be set as well.
*
* @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 #glGetAttribLocation(GL2ES2, String)
* @see #getAttribLocation(String)
* @see #getAttribute(String)
*/
public void glBindAttribLocation(GL2ES2 gl, int location, GLArrayData data) {
glBindAttribLocation(gl, location, data.getName());
data.setLocation(location);
vertexAttribMap2Data.put(data.getName(), data);
}
/**
* Gets the location of a shader attribute,
* either the cached value {@link #getAttribLocation(String)} if valid or
* the retrieved one {@link GL2ES2#glGetAttribLocation(int, String)}.
* In the latter case the value will be cached.
*
* @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.
*
* @see #getAttribLocation(String)
* @see #glBindAttribLocation(GL2ES2, int, GLArrayData)
* @see #glBindAttribLocation(GL2ES2, int, String)
* @see GL2ES2#glGetAttribLocation(int, String)
*/
public int glGetAttribLocation(GL2ES2 gl, String name) {
if(null==shaderProgram) throw new GLException("No program is attached");
int location = getAttribLocation(name);
if(0>location) {
if(!shaderProgram.linked()) throw new GLException("Program is not linked");
location = gl.glGetAttribLocation(shaderProgram.program(), name);
if(0<=location) {
Integer idx = new Integer(location);
attribMap2Location.put(name, idx);
if(DEBUG) {
System.err.println("Info: glGetAttribLocation: "+name+", loc: "+location);
}
} else if(verbose) {
Throwable tX = new Throwable("Info: glGetAttribLocation failed, no location for: "+name+", loc: "+location);
tX.printStackTrace();
}
}
return location;
}
/**
* Gets the location of a shader attribute,
* either the cached value {@link #getAttribLocation(String)} if valid or
* the retrieved one {@link GL2ES2#glGetAttribLocation(int, String)}.
* In the latter case the value will be cached.
* The {@link GLArrayData}'s location will be set as well.
*
* @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.
*
* @see #getAttribLocation(String)
* @see #glBindAttribLocation(GL2ES2, int, GLArrayData)
* @see #glBindAttribLocation(GL2ES2, int, String)
* @see GL2ES2#glGetAttribLocation(int, String)
* @see #getAttribute(String)
*/
public int glGetAttribLocation(GL2ES2 gl, GLArrayData data) {
int location = glGetAttribLocation(gl, data.getName());
data.setLocation(location);
vertexAttribMap2Data.put(data.getName(), data);
return location;
}
//
// Enabled Vertex Arrays and its data
//
/**
* @return true if the named attribute is enable
*/
public final boolean isVertexAttribArrayEnabled(String name) {
return enabledVertexAttribArraySet.contains(name);
}
/**
* @return true if the {@link GLArrayData} attribute is enable
*/
public final boolean isVertexAttribArrayEnabled(GLArrayData data) {
return isVertexAttribArrayEnabled(data.getName());
}
private boolean glEnableVertexAttribArray(GL2ES2 gl, String name, int location) {
enabledVertexAttribArraySet.add(name);
if(0>location) {
location = glGetAttribLocation(gl, name);
if(0>location) {
if(verbose) {
Throwable tX = new Throwable("Info: glEnableVertexAttribArray failed, no index for: "+name);
tX.printStackTrace();
}
return false;
}
}
if(DEBUG) {
System.err.println("Info: glEnableVertexAttribArray: "+name+", loc: "+location);
}
gl.glEnableVertexAttribArray(location);
return true;
}
/**
* Enables a vertex attribute array.
*
* This method retrieves the the location via {@link #glGetAttribLocation(GL2ES2, GLArrayData)}
* hence {@link #glEnableVertexAttribArray(GL2ES2, GLArrayData)} shall be preferred.
*
* Even if the attribute is not found in the current shader,
* it is marked enabled in this state.
*
* @return false, if the name is not found, 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
* @see #getVertexAttribPointer
*/
public boolean glEnableVertexAttribArray(GL2ES2 gl, String name) {
return glEnableVertexAttribArray(gl, name, -1);
}
/**
* Enables a vertex attribute array, usually invoked by {@link GLArrayDataEditable#enableBuffer(GL, boolean)}.
*
* This method uses the {@link GLArrayData}'s location if set
* and is the preferred alternative to {@link #glEnableVertexAttribArray(GL2ES2, String)}.
* If data location is unset it will be retrieved via {@link #glGetAttribLocation(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.
*
* @return false, if the name is not found, 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
* @see #getVertexAttribPointer
* @see GLArrayDataEditable#enableBuffer(GL, boolean)
*/
public boolean glEnableVertexAttribArray(GL2ES2 gl, GLArrayData data) {
if(null==shaderProgram) throw new GLException("No program is attached");
if(0 > data.getLocation()) {
glGetAttribLocation(gl, data);
}
return glEnableVertexAttribArray(gl, data.getName(), data.getLocation());
}
private boolean glDisableVertexAttribArray(GL2ES2 gl, String name, int location) {
enabledVertexAttribArraySet.remove(name);
if(0>location) {
location = glGetAttribLocation(gl, name);
if(0>location) {
if(verbose) {
Throwable tX = new Throwable("Info: glDisableVertexAttribArray failed, no index for: "+name);
tX.printStackTrace();
}
return false;
}
}
if(DEBUG) {
System.err.println("Info: glDisableVertexAttribArray: "+name);
}
gl.glDisableVertexAttribArray(location);
return true;
}
/**
* Disables a vertex attribute array
*
* This method retrieves the the location via {@link #glGetAttribLocation(GL2ES2, GLArrayData)}
* hence {@link #glDisableVertexAttribArray(GL2ES2, GLArrayData)} shall be preferred.
*
* Even if the attribute is not found in the current shader,
* it is removed from this state enabled list.
*
* @return false, if the name is not found, 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
* @see #getVertexAttribPointer
*/
public boolean glDisableVertexAttribArray(GL2ES2 gl, String name) {
return glDisableVertexAttribArray(gl, name, -1);
}
/**
* Disables a vertex attribute array
*
* This method uses the {@link GLArrayData}'s location if set
* and is the preferred alternative to {@link #glDisableVertexAttribArray(GL2ES2, String)}.
* If data location is unset it will be retrieved via {@link #glGetAttribLocation(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.
*
* @return false, if the name is not found, 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
* @see #getVertexAttribPointer
*/
public boolean glDisableVertexAttribArray(GL2ES2 gl, GLArrayData data) {
if(null==shaderProgram) throw new GLException("No program is attached");
if(0 > data.getLocation()) {
glGetAttribLocation(gl, data);
}
return glDisableVertexAttribArray(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 #glGetAttribLocation(GL2ES2, GLArrayData)}, set
* and cached in this state.
*
* @return false, if the location could not be determined, otherwise true
*
* @throws GLException if the program is not in use
*
* @see #glEnableVertexAttribArray
* @see #glDisableVertexAttribArray
* @see #glVertexAttribPointer
* @see #getVertexAttribPointer
*/
public boolean glVertexAttribPointer(GL2ES2 gl, GLArrayData data) {
if(null==shaderProgram) throw new GLException("No program is attached");
// if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
if(0 > data.getLocation()) {
glGetAttribLocation(gl, data);
}
if(0 <= data.getLocation()) {
// only pass the data, if the attribute exists in the current shader
if(DEBUG) {
System.err.println("Info: glVertexAttribPointer: "+data);
}
gl.glVertexAttribPointer(data);
return true;
}
return false;
}
/**
* Releases all mapped vertex attribute data,
* disables all enabled attributes and loses all indices
*
* @throws GLException is the program is not in use but the shaderProgram is set
*
* @see #glEnableVertexAttribArray
* @see #glDisableVertexAttribArray
* @see #glVertexAttribPointer
* @see #getVertexAttribPointer
* @see #glReleaseAllVertexAttributes
* @see #glResetAllVertexAttributes
* @see #glResetAllVertexAttributes
* @see ShaderProgram#glReplaceShader
*/
public void glReleaseAllVertexAttributes(GL2ES2 gl) {
if(null!=shaderProgram) {
if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
for(Iterator iter = vertexAttribMap2Data.values().iterator(); iter.hasNext(); ) {
if(!glDisableVertexAttribArray(gl, iter.next())) {
throw new GLException("Internal Error: mapped vertex attribute couldn't be disabled");
}
}
for(Iterator iter = enabledVertexAttribArraySet.iterator(); iter.hasNext(); ) {
if(!glDisableVertexAttribArray(gl, (String) iter.next())) {
throw new GLException("Internal Error: prev enabled vertex attribute couldn't be disabled");
}
}
}
vertexAttribMap2Data.clear();
enabledVertexAttribArraySet.clear();
attribMap2Location.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.
*
* @throws GLException is the program is not in use but the shaderProgram is set
*
* @see #glEnableVertexAttribArray
* @see #glDisableVertexAttribArray
* @see #glVertexAttribPointer
* @see #getVertexAttribPointer
* @see #glReleaseAllVertexAttributes
* @see #glResetAllVertexAttributes
* @see #glResetAllVertexAttributes
* @see ShaderProgram#glReplaceShader
*/
public void glDisableAllVertexAttributeArrays(GL2ES2 gl, boolean removeFromState) {
if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
for(Iterator iter = enabledVertexAttribArraySet.iterator(); iter.hasNext(); ) {
String name = (String) iter.next();
if(removeFromState) {
enabledVertexAttribArraySet.remove(name);
}
int index = glGetAttribLocation(gl, name);
if(0<=index) {
gl.glDisableVertexAttribArray(index);
}
}
}
/**
* Reset all previously enabled mapped vertex attribute data.
*
* Attribute data is bound to the GL state
* Attribute location is bound to the program
*
* However, since binding an attribute to a location via {@link #glBindAttribLocation(GL2ES2, int, GLArrayData)}
* must happen before linking and we try to promote the attributes to the new program,
* we have to gather the probably new location etc.
*
* @throws GLException is the program is not in use
*
* @see #attachShaderProgram(GL2ES2, ShaderProgram)
*/
public void glResetAllVertexAttributes(GL2ES2 gl) {
if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
attribMap2Location.clear();
for(Iterator iter = vertexAttribMap2Data.values().iterator(); iter.hasNext(); ) {
GLArrayData data = iter.next();
// get new location ..
String name = data.getName();
int loc = glGetAttribLocation(gl, name);
data.setLocation(loc);
if(0>loc) {
// not used in shader
continue;
}
if(enabledVertexAttribArraySet.contains(name)) {
// enable attrib, VBO and pass location/data
gl.glEnableVertexAttribArray(loc);
}
if( data.isVBO() ) {
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, data.getVBOName());
}
gl.glVertexAttribPointer(data);
}
}
//
// Shader Uniform handling
//
/**
* Gets the index of a shader uniform.
* This must be done when the program is in use !
*
* @return -1 if there is no such attribute available,
* otherwise >= 0
* @throws GLException is the program is not linked
*
* @see #glGetUniformLocation
* @see javax.media.opengl.GL2ES2#glGetUniformLocation
* @see #getUniformLocation
* @see ShaderProgram#glReplaceShader
*/
protected int glGetUniformLocation(GL2ES2 gl, String name) {
if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
int location = getUniformLocation(name);
if(0>location) {
location = gl.glGetUniformLocation(shaderProgram.program(), name);
if(0<=location) {
Integer idx = new Integer(location);
uniformMap2Location.put(name, idx);
} else if(verbose) {
Throwable tX = new Throwable("Info: glUniform failed, no location for: "+name+", index: "+location);
tX.printStackTrace();
}
}
return location;
}
protected int getUniformLocation(String name) {
Integer idx = (Integer) uniformMap2Location.get(name);
return (null!=idx)?idx.intValue():-1;
}
/**
* 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
*
* @throws GLException if the program is not in use
*
* @see #glGetUniformLocation
* @see javax.media.opengl.GL2ES2#glGetUniformLocation
* @see #getUniformLocation
* @see ShaderProgram#glReplaceShader
*/
public boolean glUniform(GL2ES2 gl, GLUniformData data) {
if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
int location = glGetUniformLocation(gl, data.getName());
data.setLocation(location);
uniformMap2Data.put(data.getName(), data);
if(0<=location) {
// only pass the data, if the uniform exists in the current shader
if(DEBUG) {
System.err.println("Info: glUniform: "+data);
}
gl.glUniform(data);
}
return true;
}
/**
* Get the uniform data, previously set.
*
* @return the GLUniformData object, null if not previously set.
*/
public GLUniformData getUniform(String name) {
return uniformMap2Data.get(name);
}
/**
* Releases all mapped uniform data
* and loses all indices
*
* @throws GLException is the program is not in use
*/
public void glReleaseAllUniforms(GL2ES2 gl) {
uniformMap2Data.clear();
uniformMap2Location.clear();
}
/**
* Reset all previously mapped uniform data
*
* Uniform data and location is bound to the program,
* hence both are updated here
*
* @throws GLException is the program is not in use
*
* @see #attachShaderProgram(GL2ES2, ShaderProgram)
*/
public void glResetAllUniforms(GL2ES2 gl) {
if(!shaderProgram.inUse()) throw new GLException("Program is not in use");
uniformMap2Location.clear();
for(Iterator iter = uniformMap2Data.values().iterator(); iter.hasNext(); ) {
glUniform(gl, iter.next());
}
}
public StringBuilder toString(StringBuilder sb) {
if(null==sb) {
sb = new StringBuilder();
}
sb.append("ShaderState[");
sb.append(shaderProgram.toString());
sb.append(",EnabledStates: [");
for(Iterator iter = enabledVertexAttribArraySet.iterator(); iter.hasNext(); ) {
sb.append("\n ");
sb.append((String)iter.next());
}
sb.append("], [");
for(Iterator iter = vertexAttribMap2Data.values().iterator(); iter.hasNext(); ) {
GLArrayData data = iter.next();
if(data.getLocation()>=0) {
sb.append("\n ");
sb.append(data);
}
}
sb.append("], [");
for(Iterator iter=uniformMap2Data.values().iterator(); iter.hasNext(); ) {
GLUniformData data = iter.next();
if(data.getLocation()>=0) {
sb.append("\n ");
sb.append(data);
}
}
sb.append("]");
return sb;
}
@Override
public String toString() {
return toString(null).toString();
}
protected boolean verbose = false;
protected ShaderProgram shaderProgram=null;
protected HashSet enabledVertexAttribArraySet = new HashSet();
protected HashMap attribMap2Location = new HashMap();
protected HashMap vertexAttribMap2Data = new HashMap();
protected HashMap uniformMap2Location = new HashMap();
protected HashMap uniformMap2Data = new HashMap();
private HashMap attachedObjectsByString = new HashMap();
private IntObjectHashMap attachedObjectsByInt = new IntObjectHashMap();
private boolean resetAllShaderData = false;
}