package jogamp.opengl.util.glsl.fixedfunc; import com.jogamp.common.nio.Buffers; import javax.media.opengl.*; import javax.media.opengl.fixedfunc.*; import com.jogamp.opengl.util.*; import com.jogamp.opengl.util.glsl.*; import java.nio.*; public class FixedFuncPipeline { public static final int MAX_TEXTURE_UNITS = 8; public static final int MAX_LIGHTS = 8; // We can't have any dependencies on the FixedFuncUtil class for build bootstrapping reasons public static final String mgl_Vertex = "mgl_Vertex"; public static final String mgl_Normal = "mgl_Normal"; public static final String mgl_Color = "mgl_Color"; public static final String mgl_MultiTexCoord = "mgl_MultiTexCoord" ; public static String getPredefinedArrayIndexName(int glArrayIndex) { switch(glArrayIndex) { case GLPointerFunc.GL_VERTEX_ARRAY: return mgl_Vertex; case GLPointerFunc.GL_NORMAL_ARRAY: return mgl_Normal; case GLPointerFunc.GL_COLOR_ARRAY: return mgl_Color; case GLPointerFunc.GL_TEXTURE_COORD_ARRAY: return mgl_MultiTexCoord; } return null; } public FixedFuncPipeline(GL2ES2 gl, PMVMatrix pmvMatrix) { init(gl, pmvMatrix, FixedFuncPipeline.class, shaderSrcRootDef, shaderBinRootDef, vertexColorFileDef, vertexColorLightFileDef, fragmentColorFileDef, fragmentColorTextureFileDef); } public FixedFuncPipeline(GL2ES2 gl, PMVMatrix pmvMatrix, Class shaderRootClass, String shaderSrcRoot, String shaderBinRoot, String vertexColorFile, String vertexColorLightFile, String fragmentColorFile, String fragmentColorTextureFile) { init(gl, pmvMatrix, shaderRootClass, shaderSrcRoot, shaderBinRoot, vertexColorFile, vertexColorLightFile, fragmentColorFile, fragmentColorTextureFile); } public boolean verbose() { return verbose; } public void setVerbose(boolean v) { verbose=v; } public boolean isValid() { return shaderState.linked(); } public ShaderState getShaderState() { return shaderState; } public int getActiveTextureUnit() { return activeTextureUnit; } public String getArrayIndexName(int glArrayIndex) { String name = getPredefinedArrayIndexName(glArrayIndex); switch(glArrayIndex) { case GLPointerFunc.GL_VERTEX_ARRAY: case GLPointerFunc.GL_NORMAL_ARRAY: case GLPointerFunc.GL_COLOR_ARRAY: break; case GLPointerFunc.GL_TEXTURE_COORD_ARRAY: name = name + activeTextureUnit; } return name; } public void destroy(GL2ES2 gl) { shaderProgramColor.release(gl, true); shaderProgramColorLight.release(gl, true); shaderProgramColorTexture.release(gl, true); shaderProgramColorTextureLight.release(gl, true); shaderState.destroy(gl); } public void glEnableClientState(GL2ES2 gl, int glArrayIndex) { shaderState.glUseProgram(gl, true); shaderState.glEnableVertexAttribArray(gl, getArrayIndexName(glArrayIndex)); // textureCoordsEnabled |= (1 << activeTextureUnit); if ( textureCoordsEnabled.get(activeTextureUnit) != 1 ) { textureCoordsEnabled.put(activeTextureUnit, 1); textureCoordsEnabledDirty = true; } } public void glDisableClientState(GL2ES2 gl, int glArrayIndex) { shaderState.glUseProgram(gl, true); shaderState.glDisableVertexAttribArray(gl, getArrayIndexName(glArrayIndex)); // textureCoordsEnabled &= ~(1 << activeTextureUnit); if ( textureCoordsEnabled.get(activeTextureUnit) != 0 ) { textureCoordsEnabled.put(activeTextureUnit, 0); textureCoordsEnabledDirty = true; } } public void glVertexPointer(GL2ES2 gl, GLArrayData data) { shaderState.glUseProgram(gl, true); shaderState.glVertexAttribPointer(gl, data); } public void glColorPointer(GL2ES2 gl, GLArrayData data) { shaderState.glUseProgram(gl, true); shaderState.glVertexAttribPointer(gl, data); } public void glColor4fv(GL2ES2 gl, FloatBuffer data ) { shaderState.glUseProgram(gl, true); GLUniformData ud = shaderState.getUniform(mgl_ColorStatic); if(null!=ud) { ud.setData(data); shaderState.glUniform(gl, ud); } } public void glNormalPointer(GL2ES2 gl, GLArrayData data) { shaderState.glUseProgram(gl, true); shaderState.glVertexAttribPointer(gl, data); } public void glTexCoordPointer(GL2ES2 gl, GLArrayData data) { shaderState.glUseProgram(gl, true); data.setName( getArrayIndexName(data.getIndex()) ); shaderState.glVertexAttribPointer(gl, data); } public void glLightfv(GL2ES2 gl, int light, int pname, java.nio.FloatBuffer params) { shaderState.glUseProgram(gl, true); light -=GLLightingFunc.GL_LIGHT0; if(0 <= light && light < MAX_LIGHTS) { GLUniformData ud = null; switch(pname) { case GLLightingFunc.GL_AMBIENT: ud = shaderState.getUniform(mgl_LightSource+"["+light+"].ambient"); break; case GLLightingFunc.GL_DIFFUSE: ud = shaderState.getUniform(mgl_LightSource+"["+light+"].diffuse"); break; case GLLightingFunc.GL_SPECULAR: ud = shaderState.getUniform(mgl_LightSource+"["+light+"].specular"); break; case GLLightingFunc.GL_POSITION: ud = shaderState.getUniform(mgl_LightSource+"["+light+"].position"); break; case GLLightingFunc.GL_SPOT_DIRECTION: ud = shaderState.getUniform(mgl_LightSource+"["+light+"].spotDirection"); break; case GLLightingFunc.GL_SPOT_EXPONENT: ud = shaderState.getUniform(mgl_LightSource+"["+light+"].spotExponent"); break; case GLLightingFunc.GL_SPOT_CUTOFF: ud = shaderState.getUniform(mgl_LightSource+"["+light+"].spotCutoff"); break; case GLLightingFunc.GL_CONSTANT_ATTENUATION: ud = shaderState.getUniform(mgl_LightSource+"["+light+"].constantAttenuation"); break; case GLLightingFunc.GL_LINEAR_ATTENUATION: ud = shaderState.getUniform(mgl_LightSource+"["+light+"].linearAttenuation"); break; case GLLightingFunc.GL_QUADRATIC_ATTENUATION: ud = shaderState.getUniform(mgl_LightSource+"["+light+"].quadraticAttenuation"); break; default: if(verbose) { System.err.println("glLightfv pname not within [GL_AMBIENT GL_DIFFUSE GL_SPECULAR GL_POSITION GL_SPOT_DIRECTION]: "+pname); } return; } if(null!=ud) { ud.setData(params); shaderState.glUniform(gl, ud); } } else if(verbose) { System.err.println("glLightfv light not within [0.."+MAX_LIGHTS+"]: "+light); } } public void glMaterialfv(GL2ES2 gl, int face, int pname, java.nio.FloatBuffer params) { shaderState.glUseProgram(gl, true); switch (face) { case GL.GL_FRONT: case GL.GL_FRONT_AND_BACK: break; case GL.GL_BACK: if(verbose) { System.err.println("glMaterialfv face GL_BACK currently not supported"); } break; default: } GLUniformData ud = null; switch(pname) { case GLLightingFunc.GL_AMBIENT: ud = shaderState.getUniform(mgl_FrontMaterial+".ambient"); break; case GLLightingFunc.GL_AMBIENT_AND_DIFFUSE: glMaterialfv(gl, face, GLLightingFunc.GL_AMBIENT, params); // fall through intended .. case GLLightingFunc.GL_DIFFUSE: ud = shaderState.getUniform(mgl_FrontMaterial+".diffuse"); break; case GLLightingFunc.GL_SPECULAR: ud = shaderState.getUniform(mgl_FrontMaterial+".specular"); break; case GLLightingFunc.GL_EMISSION: ud = shaderState.getUniform(mgl_FrontMaterial+".emission"); break; case GLLightingFunc.GL_SHININESS: ud = shaderState.getUniform(mgl_FrontMaterial+".shininess"); break; default: if(verbose) { System.err.println("glMaterialfv pname not within [GL_AMBIENT GL_DIFFUSE GL_SPECULAR GL_EMISSION GL_SHININESS]: "+pname); } return; } if(null!=ud) { ud.setData(params); shaderState.glUniform(gl, ud); } } public void glShadeModel(GL2ES2 gl, int mode) { shaderState.glUseProgram(gl, true); GLUniformData ud = shaderState.getUniform(mgl_ShadeModel); if(null!=ud) { ud.setData(mode); shaderState.glUniform(gl, ud); } } public void glActiveTexture(GL2ES2 gl, int textureUnit) { textureUnit -= GL.GL_TEXTURE0; if(0 <= textureUnit && textureUnitcullFace) { faceName *= -1; } cullFace = faceName; } public void validate(GL2ES2 gl) { shaderState.glUseProgram(gl, true); GLUniformData ud; if(pmvMatrix.update()) { ud = shaderState.getUniform(mgl_PMVMatrix); if(null!=ud) { // same data object .. shaderState.glUniform(gl, ud); } else { throw new GLException("Failed to update: mgl_PMVMatrix"); } ud = shaderState.getUniform(mgl_NormalMatrix); if(null!=ud) { // same data object .. shaderState.glUniform(gl, ud); } } ud = shaderState.getUniform(mgl_ColorEnabled); if(null!=ud) { int ca = (shaderState.isVertexAttribArrayEnabled(mgl_Color)==true)?1:0; if(ca!=ud.intValue()) { ud.setData(ca); shaderState.glUniform(gl, ud); } } ud = shaderState.getUniform(mgl_CullFace); if(null!=ud) { if(cullFace!=ud.intValue()) { ud.setData(cullFace); shaderState.glUniform(gl, ud); } } if(lightsEnabledDirty) { ud = shaderState.getUniform(mgl_LightsEnabled); if(null!=ud) { // same data object shaderState.glUniform(gl, ud); } lightsEnabledDirty=false; } if(textureCoordsEnabledDirty) { ud = shaderState.getUniform(mgl_TexCoordEnabled); if(null!=ud) { // same data object shaderState.glUniform(gl, ud); } textureCoordsEnabledDirty=false; } if(textureEnabled) { if(lightingEnabled) { shaderState.attachShaderProgram(gl, shaderProgramColorTextureLight); } else { shaderState.attachShaderProgram(gl, shaderProgramColorTexture); } } else { if(lightingEnabled) { shaderState.attachShaderProgram(gl, shaderProgramColorLight); } else { shaderState.attachShaderProgram(gl, shaderProgramColor); } } if(DEBUG) { System.err.println("validate: "+this); } } public String toString() { return "FixedFuncPipeline[pmv: "+pmvMatrix+ ", textureEnabled: "+textureEnabled+ ", textureCoordsEnabled: "+textureCoordsEnabled+ ", lightingEnabled: "+lightingEnabled+ ", lightsEnabled: "+lightsEnabled+ "\n\t, shaderProgramColor: "+shaderProgramColor+ "\n\t, shaderProgramColorTexture: "+shaderProgramColorTexture+ "\n\t, shaderProgramColorLight: "+shaderProgramColorLight+ "\n\t, shaderProgramColorTextureLight: "+shaderProgramColorTextureLight+ "\n\t, ShaderState: "+shaderState+ "]"; } protected void init(GL2ES2 gl, PMVMatrix pmvMatrix, Class shaderRootClass, String shaderSrcRoot, String shaderBinRoot, String vertexColorFile, String vertexColorLightFile, String fragmentColorFile, String fragmentColorTextureFile) { if(null==pmvMatrix) { throw new GLException("PMVMatrix is null"); } this.pmvMatrix=pmvMatrix; this.shaderState=new ShaderState(); this.shaderState.setVerbose(verbose); ShaderCode vertexColor, vertexColorLight, fragmentColor, fragmentColorTexture; vertexColor = ShaderCode.create( gl, gl.GL_VERTEX_SHADER, 1, shaderRootClass, shaderSrcRoot, shaderBinRoot, vertexColorFile); vertexColorLight = ShaderCode.create( gl, gl.GL_VERTEX_SHADER, 1, shaderRootClass, shaderSrcRoot, shaderBinRoot, vertexColorLightFile); fragmentColor = ShaderCode.create( gl, gl.GL_FRAGMENT_SHADER, 1, shaderRootClass, shaderSrcRoot, shaderBinRoot, fragmentColorFile); fragmentColorTexture = ShaderCode.create( gl, gl.GL_FRAGMENT_SHADER, 1, shaderRootClass, shaderSrcRoot, shaderBinRoot, fragmentColorTextureFile); shaderProgramColor = new ShaderProgram(); shaderProgramColor.add(vertexColor); shaderProgramColor.add(fragmentColor); if(!shaderProgramColor.link(gl, System.err)) { throw new GLException("Couldn't link VertexColor program: "+shaderProgramColor); } shaderProgramColorTexture = new ShaderProgram(); shaderProgramColorTexture.add(vertexColor); shaderProgramColorTexture.add(fragmentColorTexture); if(!shaderProgramColorTexture.link(gl, System.err)) { throw new GLException("Couldn't link VertexColorTexture program: "+shaderProgramColorTexture); } shaderProgramColorLight = new ShaderProgram(); shaderProgramColorLight.add(vertexColorLight); shaderProgramColorLight.add(fragmentColor); if(!shaderProgramColorLight.link(gl, System.err)) { throw new GLException("Couldn't link VertexColorLight program: "+shaderProgramColorLight); } shaderProgramColorTextureLight = new ShaderProgram(); shaderProgramColorTextureLight.add(vertexColorLight); shaderProgramColorTextureLight.add(fragmentColorTexture); if(!shaderProgramColorTextureLight.link(gl, System.err)) { throw new GLException("Couldn't link VertexColorLight program: "+shaderProgramColorTextureLight); } shaderState.attachShaderProgram(gl, shaderProgramColor); shaderState.glUseProgram(gl, true); // mandatory .. if(!shaderState.glUniform(gl, new GLUniformData(mgl_PMVMatrix, 4, 4, pmvMatrix.glGetPMvMviMatrixf()))) { throw new GLException("Error setting PMVMatrix in shader: "+this); } // optional parameter .. shaderState.glUniform(gl, new GLUniformData(mgl_NormalMatrix, 3, 3, pmvMatrix.glGetNormalMatrixf())); shaderState.glUniform(gl, new GLUniformData(mgl_ColorEnabled, 0)); shaderState.glUniform(gl, new GLUniformData(mgl_ColorStatic, 4, zero4f)); shaderState.glUniform(gl, new GLUniformData(mgl_TexCoordEnabled, 1, textureCoordsEnabled)); shaderState.glUniform(gl, new GLUniformData(mgl_ActiveTexture, activeTextureUnit)); shaderState.glUniform(gl, new GLUniformData(mgl_ActiveTextureIdx, activeTextureUnit)); shaderState.glUniform(gl, new GLUniformData(mgl_ShadeModel, 0)); shaderState.glUniform(gl, new GLUniformData(mgl_CullFace, cullFace)); for(int i=0; i