/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* 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 jogamp.opengl.util.glsl.fixedfunc;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import com.jogamp.opengl.GL;
import com.jogamp.opengl.GL2;
import com.jogamp.opengl.GL2ES1;
import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GL2GL3;
import com.jogamp.opengl.GLArrayData;
import com.jogamp.opengl.GLES2;
import com.jogamp.opengl.GLException;
import com.jogamp.opengl.GLRunnable2;
import com.jogamp.opengl.GLUniformData;
import com.jogamp.opengl.fixedfunc.GLLightingFunc;
import com.jogamp.opengl.fixedfunc.GLPointerFunc;
import com.jogamp.opengl.fixedfunc.GLPointerFuncUtil;
import jogamp.opengl.Debug;
import com.jogamp.common.nio.Buffers;
import com.jogamp.common.util.IntIntHashMap;
import com.jogamp.common.util.PropertyAccess;
import com.jogamp.opengl.util.PMVMatrix;
import com.jogamp.opengl.util.glsl.ShaderCode;
import com.jogamp.opengl.util.glsl.ShaderProgram;
import com.jogamp.opengl.util.glsl.ShaderState;
import com.jogamp.opengl.util.glsl.fixedfunc.ShaderSelectionMode;
/**
*
* <p>
* Note: Certain GL FFP state values (e.g.: alphaTestFunc and cullFace)
* are mapped to a lower number range so they can be stored in low precision storage,
* i.e. in a 'lowp int' (GL ES2).
* </p>
*/
public class FixedFuncPipeline {
protected static final boolean DEBUG;
static {
Debug.initSingleton();
DEBUG = PropertyAccess.isPropertyDefined("jogl.debug.FixedFuncPipeline", true);
}
/** The maximum texture units which could be used, depending on {@link ShaderSelectionMode}. */
public static final int MAX_TEXTURE_UNITS = 8;
public static final int MAX_LIGHTS = 8;
public FixedFuncPipeline(final GL2ES2 gl, final ShaderSelectionMode mode, final PMVMatrix pmvMatrix) {
shaderRootClass = FixedFuncPipeline.class;
shaderSrcRoot = shaderSrcRootDef;
shaderBinRoot = shaderBinRootDef;
vertexColorFile = vertexColorFileDef;
vertexColorLightFile = vertexColorLightFileDef;
fragmentColorFile = fragmentColorFileDef;
fragmentColorTextureFile = fragmentColorTextureFileDef;
init(gl, mode, pmvMatrix);
}
public FixedFuncPipeline(final GL2ES2 gl, final ShaderSelectionMode mode, final PMVMatrix pmvMatrix,
final Class<?> shaderRootClass, final String shaderSrcRoot,
final String shaderBinRoot,
final String vertexColorFile, final String vertexColorLightFile,
final String fragmentColorFile, final String fragmentColorTextureFile) {
this.shaderRootClass = shaderRootClass;
this.shaderSrcRoot = shaderSrcRoot;
this.shaderBinRoot = shaderBinRoot;
this.vertexColorFile = vertexColorFile;
this.vertexColorLightFile = vertexColorLightFile;
this.fragmentColorFile = fragmentColorFile;
this.fragmentColorTextureFile = fragmentColorTextureFile;
init(gl, mode, pmvMatrix);
}
public ShaderSelectionMode getShaderSelectionMode() { return requestedShaderSelectionMode; }
public void setShaderSelectionMode(final ShaderSelectionMode mode) { requestedShaderSelectionMode=mode; }
public ShaderSelectionMode getCurrentShaderSelectionMode() { return currentShaderSelectionMode; }
public boolean verbose() { return verbose; }
public void setVerbose(final boolean v) { verbose = DEBUG || v; }
public boolean isValid() {
return shaderState.linked();
}
public ShaderState getShaderState() {
return shaderState;
}
public int getActiveTextureUnit() {
return activeTextureUnit;
}
public void destroy(final GL2ES2 gl) {
if(null != shaderProgramColor) {
shaderProgramColor.release(gl, true);
}
if(null != shaderProgramColorLight) {
shaderProgramColorLight.release(gl, true);
}
if(null != shaderProgramColorTexture2) {
shaderProgramColorTexture2.release(gl, true);
}
if(null != shaderProgramColorTexture4) {
shaderProgramColorTexture4.release(gl, true);
}
if(null != shaderProgramColorTexture4) {
shaderProgramColorTexture4.release(gl, true);
}
if(null != shaderProgramColorTexture8Light) {
shaderProgramColorTexture8Light.release(gl, true);
}
shaderState.destroy(gl);
}
//
// Simple Globals
//
public void glColor4f(final GL2ES2 gl, final float red, final float green, final float blue, final float alpha) {
colorStatic.put(0, red);
colorStatic.put(1, green);
colorStatic.put(2, blue);
colorStatic.put(3, alpha);
shaderState.useProgram(gl, true);
final GLUniformData ud = shaderState.getUniform(mgl_ColorStatic);
if(null!=ud) {
// same data object ..
shaderState.uniform(gl, ud);
} else {
throw new GLException("Failed to update: mgl_ColorStatic");
}
}
//
// Arrays / States
//
public void glEnableClientState(final GL2ES2 gl, final int glArrayIndex) {
glToggleClientState(gl, glArrayIndex, true);
}
public void glDisableClientState(final GL2ES2 gl, final int glArrayIndex) {
glToggleClientState(gl, glArrayIndex, false);
}
private void glToggleClientState(final GL2ES2 gl, final int glArrayIndex, final boolean enable) {
final String arrayName = GLPointerFuncUtil.getPredefinedArrayIndexName(glArrayIndex, clientActiveTextureUnit);
if(null == arrayName) {
throw new GLException("arrayIndex "+toHexString(glArrayIndex)+" unknown");
}
shaderState.useProgram(gl, true);
if(enable) {
shaderState.enableVertexAttribArray(gl, arrayName );
} else {
shaderState.disableVertexAttribArray(gl, arrayName );
}
switch( glArrayIndex ) {
case GLPointerFunc.GL_TEXTURE_COORD_ARRAY:
final int enableV = enable ? 1 : 0;
// enable-bitwise: textureCoordsEnabled |= (1 << clientActiveTextureUnit);
// disable-bitwise: textureCoordsEnabled &= ~(1 << clientActiveTextureUnit);
if ( textureCoordEnabled.get(clientActiveTextureUnit) != enableV) {
textureCoordEnabled.put(clientActiveTextureUnit, enableV);
textureCoordEnabledDirty = true;
}
break;
case GLPointerFunc.GL_COLOR_ARRAY:
colorVAEnabledDirty = true;
break;
}
}
public void glVertexPointer(final GL2ES2 gl, final GLArrayData data) {
shaderState.useProgram(gl, true);
shaderState.vertexAttribPointer(gl, data);
}
public void glColorPointer(final GL2ES2 gl, final GLArrayData data) {
shaderState.useProgram(gl, true);
shaderState.vertexAttribPointer(gl, data);
}
public void glNormalPointer(final GL2ES2 gl, final GLArrayData data) {
shaderState.useProgram(gl, true);
shaderState.vertexAttribPointer(gl, data);
}
//
// MULTI-TEXTURE
//
/** Enables/Disables the named texture unit (if changed), returns previous state */
private boolean glEnableTexture(final boolean enable, final int unit) {
final boolean isEnabled = 0 != ( textureEnabledBits & ( 1 << activeTextureUnit ) );
if( isEnabled != enable ) {
if(enable) {
textureEnabledBits |= ( 1 << unit );
textureEnabled.put(unit, 1);
} else {
textureEnabledBits &= ~( 1 << unit );
textureEnabled.put(unit, 0);
}
textureEnabledDirty=true;
}
return isEnabled;
}
public void glClientActiveTexture(int textureUnit) {
textureUnit -= GL.GL_TEXTURE0;
if(0 <= textureUnit && textureUnit<MAX_TEXTURE_UNITS) {
clientActiveTextureUnit = textureUnit;
} else {
throw new GLException("glClientActiveTexture textureUnit not within GL_TEXTURE0 + [0.."+MAX_TEXTURE_UNITS+"]: "+textureUnit);
}
}
public void glActiveTexture(int textureUnit) {
textureUnit -= GL.GL_TEXTURE0;
if(0 <= textureUnit && textureUnit<MAX_TEXTURE_UNITS) {
activeTextureUnit = textureUnit;
} else {
throw new GLException("glActivateTexture textureUnit not within GL_TEXTURE0 + [0.."+MAX_TEXTURE_UNITS+"]: "+textureUnit);
}
}
public void glTexCoordPointer(final GL2ES2 gl, final GLArrayData data) {
if( GLPointerFunc.GL_TEXTURE_COORD_ARRAY != data.getIndex() ) {
throw new GLException("Invalid GLArrayData Index "+toHexString(data.getIndex())+", "+data);
}
shaderState.useProgram(gl, true);
data.setName( GLPointerFuncUtil.getPredefinedArrayIndexName(data.getIndex(), clientActiveTextureUnit) ) ;
shaderState.vertexAttribPointer(gl, data);
}
public void glBindTexture(final int target, final int texture) {
if(GL.GL_TEXTURE_2D == target) {
if( texture != boundTextureObject[activeTextureUnit] ) {
boundTextureObject[activeTextureUnit] = texture;
textureFormatDirty = true;
}
} else {
System.err.println("FixedFuncPipeline: Unimplemented glBindTexture for target "+toHexString(target)+". Texture name "+toHexString(texture));
}
}
public void glTexImage2D(final int target, /* int level, */ final int internalformat, /*, int width, int height, int border, */
final int format /*, int type, Buffer pixels */) {
final int ifmt;
if(GL.GL_TEXTURE_2D == target) {
switch(internalformat) {
case 3:
case GL.GL_RGB:
case GL.GL_RGB565:
case GL.GL_RGB8:
case GL.GL_RGB10:
ifmt = 3;
break;
case 4:
case GL.GL_RGBA:
case GL.GL_RGB5_A1:
case GL.GL_RGBA4:
case GL.GL_RGBA8:
case GL.GL_RGB10_A2:
ifmt = 4;
break;
default:
System.err.println("FixedFuncPipeline: glTexImage2D TEXTURE_2D: Unimplemented internalformat "+toHexString(internalformat));
ifmt = 4;
break;
}
if( ifmt != texID2Format.put(boundTextureObject[activeTextureUnit], ifmt) ) {
textureFormatDirty = true;
// System.err.println("glTexImage2D TEXTURE_2D: internalformat ifmt "+toHexString(internalformat)+" fmt "+toHexString(format)+" -> "+toHexString(ifmt));
}
} else {
System.err.println("FixedFuncPipeline: Unimplemented glTexImage2D: target "+toHexString(target)+", internalformat "+toHexString(internalformat));
}
}
/*
public void glTexImage2D(int target, int level, int internalformat, int width, int height, int border,
int format, int type, long pixels_buffer_offset) {
textureFormat.put(activeTextureUnit, internalformat);
textureFormatDirty = true;
}*/
public void glTexEnvi(final int target, final int pname, final int value) {
if(GL2ES1.GL_TEXTURE_ENV == target && GL2ES1.GL_TEXTURE_ENV_MODE == pname) {
final int mode;
switch( value ) {
case GL2ES1.GL_ADD:
mode = 1;
break;
case GL2ES1.GL_MODULATE:
mode = 2;
break;
case GL2ES1.GL_DECAL:
mode = 3;
break;
case GL.GL_BLEND:
mode = 4;
break;
case GL.GL_REPLACE:
mode = 5;
break;
case GL2ES1.GL_COMBINE:
mode = 2; // FIXME
System.err.println("FixedFuncPipeline: glTexEnv GL_TEXTURE_ENV_MODE: unimplemented mode: "+toHexString(value));
break;
default:
throw new GLException("glTexEnv GL_TEXTURE_ENV_MODE: invalid mode: "+toHexString(value));
}
setTextureEnvMode(mode);
} else if(verbose) {
System.err.println("FixedFuncPipeline: Unimplemented TexEnv: target "+toHexString(target)+", pname "+toHexString(pname)+", mode: "+toHexString(value));
}
}
private void setTextureEnvMode(final int value) {
if( value != textureEnvMode.get(activeTextureUnit) ) {
textureEnvMode.put(activeTextureUnit, value);
textureEnvModeDirty = true;
}
}
public void glGetTexEnviv(final int target, final int pname, final IntBuffer params) { // FIXME
System.err.println("FixedFuncPipeline: Unimplemented glGetTexEnviv: target "+toHexString(target)+", pname "+toHexString(pname));
}
public void glGetTexEnviv(final int target, final int pname, final int[] params, final int params_offset) { // FIXME
System.err.println("FixedFuncPipeline: Unimplemented glGetTexEnviv: target "+toHexString(target)+", pname "+toHexString(pname));
}
//
// Point Sprites
//
public void glPointSize(final float size) {
pointParams.put(0, size);
pointParamsDirty = true;
}
public void glPointParameterf(final int pname, final float param) {
switch(pname) {
case GL2ES1.GL_POINT_SIZE_MIN:
pointParams.put(2, param);
break;
case GL2ES1.GL_POINT_SIZE_MAX:
pointParams.put(3, param);
break;
case GL.GL_POINT_FADE_THRESHOLD_SIZE:
pointParams.put(4+3, param);
break;
}
pointParamsDirty = true;
}
public void glPointParameterfv(final int pname, final float[] params, final int params_offset) {
switch(pname) {
case GL2ES1.GL_POINT_DISTANCE_ATTENUATION:
pointParams.put(4+0, params[params_offset + 0]);
pointParams.put(4+1, params[params_offset + 1]);
pointParams.put(4+2, params[params_offset + 2]);
break;
}
pointParamsDirty = true;
}
public void glPointParameterfv(final int pname, final java.nio.FloatBuffer params) {
final int o = params.position();
switch(pname) {
case GL2ES1.GL_POINT_DISTANCE_ATTENUATION:
pointParams.put(4+0, params.get(o + 0));
pointParams.put(4+1, params.get(o + 1));
pointParams.put(4+2, params.get(o + 2));
break;
}
pointParamsDirty = true;
}
// private int[] pointTexObj = new int[] { 0 };
private void glDrawPoints(final GL2ES2 gl, final GLRunnable2<Object,Object> glDrawAction, final Object args) {
if(gl.isGL2GL3()) {
gl.glEnable(GL2GL3.GL_VERTEX_PROGRAM_POINT_SIZE);
}
if(gl.isGL2ES1()) {
gl.glEnable(GL2ES1.GL_POINT_SPRITE);
}
loadShaderPoints(gl);
shaderState.attachShaderProgram(gl, shaderProgramPoints, true);
validate(gl, false); // sync uniforms
glDrawAction.run(gl, args);
if(gl.isGL2ES1()) {
gl.glDisable(GL2ES1.GL_POINT_SPRITE);
}
if(gl.isGL2GL3()) {
gl.glDisable(GL2GL3.GL_VERTEX_PROGRAM_POINT_SIZE);
}
shaderState.attachShaderProgram(gl, selectShaderProgram(gl, currentShaderSelectionMode), true);
}
private static final GLRunnable2<Object, Object> glDrawArraysAction = new GLRunnable2<Object,Object>() {
@Override
public Object run(final GL gl, final Object args) {
final int[] _args = (int[])args;
gl.glDrawArrays(GL.GL_POINTS, _args[0], _args[1]);
return null;
}
};
private final void glDrawPointArrays(final GL2ES2 gl, final int first, final int count) {
glDrawPoints(gl, glDrawArraysAction, new int[] { first, count });
}
//
// Lighting
//
public void glLightfv(final GL2ES2 gl, int light, final int pname, final java.nio.FloatBuffer params) {
shaderState.useProgram(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:
throw new GLException("glLightfv invalid pname: "+toHexString(pname));
}
if(null!=ud) {
ud.setData(params);
shaderState.uniform(gl, ud);
}
} else {
throw new GLException("glLightfv light not within [0.."+MAX_LIGHTS+"]: "+light);
}
}
public void glMaterialfv(final GL2ES2 gl, final int face, final int pname, final java.nio.FloatBuffer params) {
shaderState.useProgram(gl, true);
switch (face) {
case GL.GL_FRONT:
case GL.GL_FRONT_AND_BACK:
break;
case GL.GL_BACK:
System.err.println("FixedFuncPipeline: Unimplemented glMaterialfv GL_BACK face");
return;
default:
}
GLUniformData ud = null;
switch(pname) {
case GLLightingFunc.GL_AMBIENT:
ud = shaderState.getUniform(mgl_FrontMaterial+".ambient");
break;
case GLLightingFunc.GL_AMBIENT_AND_DIFFUSE:
{
ud = shaderState.getUniform(mgl_FrontMaterial+".ambient");
if(null!=ud) {
ud.setData(params);
shaderState.uniform(gl, ud);
}
}
// 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:
throw new GLException("glMaterialfv invalid pname: "+toHexString(pname));
}
if(null!=ud) {
ud.setData(params);
shaderState.uniform(gl, ud);
} else if(verbose) {
}
}
//
// Misc States
//
public void glShadeModel(final GL2ES2 gl, final int mode) {
shaderState.useProgram(gl, true);
final GLUniformData ud = shaderState.getUniform(mgl_ShadeModel);
if(null!=ud) {
ud.setData(mode);
shaderState.uniform(gl, ud);
}
}
/** ES2 supports CullFace implicit
public void glCullFace(int faceName) {
int _cullFace;
switch(faceName) {
case GL.GL_FRONT:
_cullFace = 1;
break;
case GL.GL_BACK:
_cullFace = 2;
break;
case GL.GL_FRONT_AND_BACK:
_cullFace = 3;
break;
default:
throw new GLException("glCullFace invalid faceName: "+toHexString(faceName));
}
if(0 < _cullFace) {
if(0>cullFace) {
_cullFace *= -1;
}
if(cullFace != _cullFace) {
cullFace = _cullFace;
cullFaceDirty=true;
}
}
} */
public void glAlphaFunc(final int func, final float ref) {
int _func;
switch(func) {
case GL.GL_NEVER:
_func = 1;
break;
case GL.GL_LESS:
_func = 2;
break;
case GL.GL_EQUAL:
_func = 3;
break;
case GL.GL_LEQUAL:
_func = 4;
break;
case GL.GL_GREATER:
_func = 5;
break;
case GL.GL_NOTEQUAL:
_func = 6;
break;
case GL.GL_GEQUAL:
_func = 7;
break;
case GL.GL_ALWAYS:
_func = 8;
break;
default:
throw new GLException("glAlphaFunc invalid func: "+toHexString(func));
}
if(0 < _func) {
if(0>alphaTestFunc) {
_func *= -1;
}
if( alphaTestFunc != _func || alphaTestRef != ref ) {
alphaTestFunc = _func;
alphaTestRef = ref;
alphaTestDirty=true;
}
}
}
/**
* @return false if digested in regard to GL2ES2 spec,
* eg this call must not be passed to an underlying ES2 implementation.
* true if this call shall be passed to an underlying GL2ES2/ES2 implementation as well.
*/
public boolean glEnable(final int cap, final boolean enable) {
switch(cap) {
case GL.GL_BLEND:
case GL.GL_DEPTH_TEST:
case GL.GL_DITHER:
case GL.GL_POLYGON_OFFSET_FILL:
case GL.GL_SAMPLE_ALPHA_TO_COVERAGE:
case GL.GL_SAMPLE_COVERAGE:
case GL.GL_SCISSOR_TEST:
case GL.GL_STENCIL_TEST:
return true;
case GL.GL_CULL_FACE:
/** ES2 supports CullFace implicit
final int _cullFace;
if(0>cullFace && enable || 0<cullFace && !enable) {
_cullFace = cullFace * -1;
} else {
_cullFace = cullFace;
}
if(_cullFace != cullFace) {
cullFaceDirty=true;
cullFace=_cullFace;
} */
return true;
case GL.GL_TEXTURE_2D:
glEnableTexture(enable, activeTextureUnit);
return false;
case GLLightingFunc.GL_LIGHTING:
lightingEnabled=enable;
return false;
case GL2ES1.GL_ALPHA_TEST:
final int _alphaTestFunc;
if(0>alphaTestFunc && enable || 0<alphaTestFunc && !enable) {
_alphaTestFunc = alphaTestFunc * -1;
} else {
_alphaTestFunc = alphaTestFunc;
}
if(_alphaTestFunc != alphaTestFunc) {
alphaTestDirty=true;
alphaTestFunc=_alphaTestFunc;
}
return false;
case GL2ES1.GL_POINT_SMOOTH:
pointParams.put(1, enable ? 1.0f : 0.0f);
pointParamsDirty = true;
return false;
case GL2ES1.GL_POINT_SPRITE:
// gl_PointCoord always enabled
return false;
}
final int light = cap - GLLightingFunc.GL_LIGHT0;
if(0 <= light && light < MAX_LIGHTS) {
if ( (lightsEnabled.get(light)==1) != enable ) {
lightsEnabled.put(light, enable?1:0);
lightsEnabledDirty = true;
return false;
}
}
System.err.println("FixedFunctionPipeline: "+(enable ? "glEnable" : "glDisable")+" "+toHexString(cap)+" not handled in emulation and not supported in ES2");
return false; // ignore!
}
//
// Draw
//
public void glDrawArrays(final GL2ES2 gl, int mode, final int first, final int count) {
switch(mode) {
case GL2.GL_QUAD_STRIP:
mode=GL.GL_TRIANGLE_STRIP;
break;
case GL2.GL_POLYGON:
mode=GL.GL_TRIANGLE_FAN;
break;
case GL.GL_POINTS:
glDrawPointArrays(gl, first, count);
return;
}
validate(gl, true);
if ( GL2GL3.GL_QUADS == mode && !gl.isGL2() ) {
for (int j = first; j < count - 3; j += 4) {
gl.glDrawArrays(GL.GL_TRIANGLE_FAN, j, 4);
}
} else {
gl.glDrawArrays(mode, first, count);
}
}
public void glDrawElements(final GL2ES2 gl, final int mode, final int count, final int type, final java.nio.Buffer indices) {
validate(gl, true);
if ( GL2GL3.GL_QUADS == mode && !gl.isGL2() ) {
final int idx0 = indices.position();
if( GL.GL_UNSIGNED_BYTE == type ) {
final ByteBuffer b = (ByteBuffer) indices;
for (int j = 0; j < count; j++) {
gl.glDrawArrays(GL.GL_TRIANGLE_FAN, 0x000000ff & b.get(idx0+j), 4);
}
} else if( GL.GL_UNSIGNED_SHORT == type ){
final ShortBuffer b = (ShortBuffer) indices;
for (int j = 0; j < count; j++) {
gl.glDrawArrays(GL.GL_TRIANGLE_FAN, 0x0000ffff & b.get(idx0+j), 4);
}
} else {
final IntBuffer b = (IntBuffer) indices;
for (int j = 0; j < count; j++) {
gl.glDrawArrays(GL.GL_TRIANGLE_FAN, 0xffffffff & b.get(idx0+j), 4);
}
}
} else {
// FIXME: Impl. VBO usage .. or unroll (see above)!
if( !gl.getContext().isCPUDataSourcingAvail() ) {
throw new GLException("CPU data sourcing n/a w/ "+gl.getContext());
}
// if( GL.GL_POINTS != mode ) {
((GLES2)gl).glDrawElements(mode, count, type, indices);
/* } else {
// FIXME GL_POINTS !
((GLES2)gl).glDrawElements(mode, count, type, indices);
} */
}
}
public void glDrawElements(final GL2ES2 gl, final int mode, final int count, final int type, final long indices_buffer_offset) {
validate(gl, true);
if ( GL2GL3.GL_QUADS == mode && !gl.isGL2() ) {
throw new GLException("Cannot handle indexed QUADS on !GL2 w/ VBO due to lack of CPU index access");
} else /* if( GL.GL_POINTS != mode ) */ {
gl.glDrawElements(mode, count, type, indices_buffer_offset);
} /* else {
// FIXME GL_POINTS !
gl.glDrawElements(mode, count, type, indices_buffer_offset);
} */
}
private final int textureEnabledCount() {
int n=0;
for(int i=MAX_TEXTURE_UNITS-1; i>=0; i--) {
if( 0 != textureEnabled.get(i) ) {
n++;
}
}
return n;
}
public void validate(final GL2ES2 gl, final boolean selectShader) {
if( selectShader ) {
if( ShaderSelectionMode.AUTO == requestedShaderSelectionMode) {
final ShaderSelectionMode newMode;
// pre-validate shader switch
if( 0 != textureEnabledBits ) {
if(lightingEnabled) {
newMode = ShaderSelectionMode.COLOR_TEXTURE8_LIGHT_PER_VERTEX;
} else {
final int n = textureEnabledCount();
if( 4 < n ) {
newMode = ShaderSelectionMode.COLOR_TEXTURE8;
} else if ( 2 < n ) {
newMode = ShaderSelectionMode.COLOR_TEXTURE4;
} else {
newMode = ShaderSelectionMode.COLOR_TEXTURE2;
}
}
} else {
if(lightingEnabled) {
newMode = ShaderSelectionMode.COLOR_LIGHT_PER_VERTEX;
} else {
newMode = ShaderSelectionMode.COLOR;
}
}
shaderState.attachShaderProgram(gl, selectShaderProgram(gl, newMode), true); // enables shader-program implicit
} else {
shaderState.useProgram(gl, true);
}
}
GLUniformData ud;
if( pmvMatrix.update() ) {
ud = shaderState.getUniform(mgl_PMVMatrix);
if(null!=ud) {
final FloatBuffer m;
if(ShaderSelectionMode.COLOR_TEXTURE8_LIGHT_PER_VERTEX == currentShaderSelectionMode ||
ShaderSelectionMode.COLOR_LIGHT_PER_VERTEX== currentShaderSelectionMode ) {
m = pmvMatrix.glGetPMvMvitMatrixf();
} else {
m = pmvMatrix.glGetPMvMatrixf();
}
if(m != ud.getBuffer()) {
ud.setData(m);
}
// same data object ..
shaderState.uniform(gl, ud);
} else {
throw new GLException("Failed to update: mgl_PMVMatrix");
}
}
if(colorVAEnabledDirty) {
ud = shaderState.getUniform(mgl_ColorEnabled);
if(null!=ud) {
final int ca = true == shaderState.isVertexAttribArrayEnabled(GLPointerFuncUtil.mgl_Color) ? 1 : 0 ;
if(ca!=ud.intValue()) {
ud.setData(ca);
shaderState.uniform(gl, ud);
}
} else {
throw new GLException("Failed to update: mgl_ColorEnabled");
}
colorVAEnabledDirty = false;
}
/** ES2 supports CullFace implicit
if(cullFaceDirty) {
ud = shaderState.getUniform(mgl_CullFace);
if(null!=ud) {
ud.setData(cullFace);
shaderState.uniform(gl, ud);
}
cullFaceDirty = false;
} */
if(alphaTestDirty) {
ud = shaderState.getUniform(mgl_AlphaTestFunc);
if(null!=ud) {
ud.setData(alphaTestFunc);
shaderState.uniform(gl, ud);
}
ud = shaderState.getUniform(mgl_AlphaTestRef);
if(null!=ud) {
ud.setData(alphaTestRef);
shaderState.uniform(gl, ud);
}
alphaTestDirty = false;
}
if(pointParamsDirty) {
ud = shaderState.getUniform(mgl_PointParams);
if(null!=ud) {
// same data object
shaderState.uniform(gl, ud);
}
pointParamsDirty = false;
}
if(lightsEnabledDirty) {
ud = shaderState.getUniform(mgl_LightsEnabled);
if(null!=ud) {
// same data object
shaderState.uniform(gl, ud);
}
lightsEnabledDirty=false;
}
if(textureCoordEnabledDirty) {
ud = shaderState.getUniform(mgl_TexCoordEnabled);
if(null!=ud) {
// same data object
shaderState.uniform(gl, ud);
}
textureCoordEnabledDirty=false;
}
if(textureEnvModeDirty) {
ud = shaderState.getUniform(mgl_TexEnvMode);
if(null!=ud) {
// same data object
shaderState.uniform(gl, ud);
}
textureEnvModeDirty = false;
}
if(textureFormatDirty) {
for(int i = 0; i<MAX_TEXTURE_UNITS; i++) {
textureFormat.put(i, texID2Format.get(boundTextureObject[i]));
}
ud = shaderState.getUniform(mgl_TexFormat);
if(null!=ud) {
// same data object
shaderState.uniform(gl, ud);
}
textureFormatDirty = false;
}
if(textureEnabledDirty) {
ud = shaderState.getUniform(mgl_TextureEnabled);
if(null!=ud) {
// same data object
shaderState.uniform(gl, ud);
}
textureEnabledDirty=false;
}
if(verbose) {
System.err.println("validate: "+toString(null, DEBUG).toString());
}
}
public StringBuilder toString(StringBuilder sb, final boolean alsoUnlocated) {
if(null == sb) {
sb = new StringBuilder();
}
sb.append("FixedFuncPipeline[");
sb.append(", textureEnabled: "+toHexString(textureEnabledBits)+", "); Buffers.toString(sb, null, textureEnabled);
sb.append("\n\t, textureCoordEnabled: "); Buffers.toString(sb, null, textureCoordEnabled);
sb.append("\n\t lightingEnabled: "+lightingEnabled);
sb.append(", lightsEnabled: "); Buffers.toString(sb, null, lightsEnabled);
sb.append("\n\t, shaderProgramColor: "+shaderProgramColor);
sb.append("\n\t, shaderProgramColorTexture2: "+shaderProgramColorTexture2);
sb.append("\n\t, shaderProgramColorTexture4: "+shaderProgramColorTexture4);
sb.append("\n\t, shaderProgramColorTexture8: "+shaderProgramColorTexture8);
sb.append("\n\t, shaderProgramColorLight: "+shaderProgramColorLight);
sb.append("\n\t, shaderProgramColorTexture8Light: "+shaderProgramColorTexture8Light);
sb.append("\n\t, ShaderState: ");
shaderState.toString(sb, alsoUnlocated);
sb.append("]");
return sb;
}
@Override
public String toString() {
return toString(null, DEBUG).toString();
}
private static final String constMaxTextures0 = "#define MAX_TEXTURE_UNITS 0\n";
private static final String constMaxTextures2 = "#define MAX_TEXTURE_UNITS 2\n";
private static final String constMaxTextures4 = "#define MAX_TEXTURE_UNITS 4\n";
private static final String constMaxTextures8 = "#define MAX_TEXTURE_UNITS 8\n";
private final void customizeShader(final GL2ES2 gl, final ShaderCode vp, final ShaderCode fp, final String maxTextureDefine) {
final int rsVpPos = vp.defaultShaderCustomization(gl, true, true);
final int rsFpPos = fp.defaultShaderCustomization(gl, true, true);
vp.insertShaderSource(0, rsVpPos, maxTextureDefine);
fp.insertShaderSource(0, rsFpPos, maxTextureDefine);
}
private final void loadShaderPoints(final GL2ES2 gl) {
if( null != shaderProgramPoints ) {
return;
}
final ShaderCode vp = ShaderCode.create( gl, GL2ES2.GL_VERTEX_SHADER, shaderRootClass, shaderSrcRoot,
shaderBinRoot, shaderPointFileDef, true);
final ShaderCode fp = ShaderCode.create( gl, GL2ES2.GL_FRAGMENT_SHADER, shaderRootClass, shaderSrcRoot,
shaderBinRoot, shaderPointFileDef, true);
customizeShader(gl, vp, fp, constMaxTextures2);
shaderProgramPoints = new ShaderProgram();
shaderProgramPoints.add(vp);
shaderProgramPoints.add(fp);
if(!shaderProgramPoints.link(gl, System.err)) {
throw new GLException("Couldn't link VertexColor program: "+shaderProgramPoints);
}
}
private final void loadShader(final GL2ES2 gl, final ShaderSelectionMode mode) {
final boolean loadColor = ShaderSelectionMode.COLOR == mode;
final boolean loadColorTexture2 = ShaderSelectionMode.COLOR_TEXTURE2 == mode;
final boolean loadColorTexture4 = ShaderSelectionMode.COLOR_TEXTURE4 == mode;
final boolean loadColorTexture8 = ShaderSelectionMode.COLOR_TEXTURE8 == mode;
final boolean loadColorTexture = loadColorTexture2 || loadColorTexture4 || loadColorTexture8 ;
final boolean loadColorLightPerVertex = ShaderSelectionMode.COLOR_LIGHT_PER_VERTEX == mode;
final boolean loadColorTexture8LightPerVertex = ShaderSelectionMode.COLOR_TEXTURE8_LIGHT_PER_VERTEX == mode;
if( null != shaderProgramColor && loadColor ||
null != shaderProgramColorTexture2 && loadColorTexture2 ||
null != shaderProgramColorTexture4 && loadColorTexture4 ||
null != shaderProgramColorTexture8 && loadColorTexture8 ||
null != shaderProgramColorLight && loadColorLightPerVertex ||
null != shaderProgramColorTexture8Light && loadColorTexture8LightPerVertex ) {
return;
}
if( loadColor ) {
final ShaderCode vp = ShaderCode.create( gl, GL2ES2.GL_VERTEX_SHADER, shaderRootClass, shaderSrcRoot,
shaderBinRoot, vertexColorFile, true);
final ShaderCode fp = ShaderCode.create( gl, GL2ES2.GL_FRAGMENT_SHADER, shaderRootClass, shaderSrcRoot,
shaderBinRoot, fragmentColorFile, true);
customizeShader(gl, vp, fp, constMaxTextures0);
shaderProgramColor = new ShaderProgram();
shaderProgramColor.add(vp);
shaderProgramColor.add(fp);
if(!shaderProgramColor.link(gl, System.err)) {
throw new GLException("Couldn't link VertexColor program: "+shaderProgramColor);
}
} else if( loadColorTexture ) {
final ShaderCode vp = ShaderCode.create( gl, GL2ES2.GL_VERTEX_SHADER, shaderRootClass, shaderSrcRoot, shaderBinRoot, vertexColorFile, true);
final ShaderCode fp = ShaderCode.create( gl, GL2ES2.GL_FRAGMENT_SHADER, shaderRootClass, shaderSrcRoot,
shaderBinRoot, fragmentColorTextureFile, true);
if( loadColorTexture2 ) {
customizeShader(gl, vp, fp, constMaxTextures2);
shaderProgramColorTexture2 = new ShaderProgram();
shaderProgramColorTexture2.add(vp);
shaderProgramColorTexture2.add(fp);
if(!shaderProgramColorTexture2.link(gl, System.err)) {
throw new GLException("Couldn't link VertexColorTexture2 program: "+shaderProgramColorTexture2);
}
} else if( loadColorTexture4 ) {
customizeShader(gl, vp, fp, constMaxTextures4);
shaderProgramColorTexture4 = new ShaderProgram();
shaderProgramColorTexture4.add(vp);
shaderProgramColorTexture4.add(fp);
if(!shaderProgramColorTexture4.link(gl, System.err)) {
throw new GLException("Couldn't link VertexColorTexture4 program: "+shaderProgramColorTexture4);
}
} else if( loadColorTexture8 ) {
customizeShader(gl, vp, fp, constMaxTextures8);
shaderProgramColorTexture8 = new ShaderProgram();
shaderProgramColorTexture8.add(vp);
shaderProgramColorTexture8.add(fp);
if(!shaderProgramColorTexture8.link(gl, System.err)) {
throw new GLException("Couldn't link VertexColorTexture8 program: "+shaderProgramColorTexture8);
}
}
} else if( loadColorLightPerVertex ) {
final ShaderCode vp = ShaderCode.create( gl, GL2ES2.GL_VERTEX_SHADER, shaderRootClass, shaderSrcRoot,
shaderBinRoot, vertexColorLightFile, true);
final ShaderCode fp = ShaderCode.create( gl, GL2ES2.GL_FRAGMENT_SHADER, shaderRootClass, shaderSrcRoot,
shaderBinRoot, fragmentColorFile, true);
customizeShader(gl, vp, fp, constMaxTextures0);
shaderProgramColorLight = new ShaderProgram();
shaderProgramColorLight.add(vp);
shaderProgramColorLight.add(fp);
if(!shaderProgramColorLight.link(gl, System.err)) {
throw new GLException("Couldn't link VertexColorLight program: "+shaderProgramColorLight);
}
} else if( loadColorTexture8LightPerVertex ) {
final ShaderCode vp = ShaderCode.create( gl, GL2ES2.GL_VERTEX_SHADER, shaderRootClass, shaderSrcRoot,
shaderBinRoot, vertexColorLightFile, true);
final ShaderCode fp = ShaderCode.create( gl, GL2ES2.GL_FRAGMENT_SHADER, shaderRootClass, shaderSrcRoot,
shaderBinRoot, fragmentColorTextureFile, true);
customizeShader(gl, vp, fp, constMaxTextures8);
shaderProgramColorTexture8Light = new ShaderProgram();
shaderProgramColorTexture8Light.add(vp);
shaderProgramColorTexture8Light.add(fp);
if(!shaderProgramColorTexture8Light.link(gl, System.err)) {
throw new GLException("Couldn't link VertexColorLight program: "+shaderProgramColorTexture8Light);
}
}
}
private ShaderProgram selectShaderProgram(final GL2ES2 gl, ShaderSelectionMode newMode) {
if(ShaderSelectionMode.AUTO == newMode) {
newMode = ShaderSelectionMode.COLOR;
}
loadShader(gl, newMode);
final ShaderProgram sp;
switch(newMode) {
case COLOR_LIGHT_PER_VERTEX:
sp = shaderProgramColorLight;
break;
case COLOR_TEXTURE2:
sp = shaderProgramColorTexture2;
break;
case COLOR_TEXTURE4:
sp = shaderProgramColorTexture4;
break;
case COLOR_TEXTURE8:
sp = shaderProgramColorTexture8;
break;
case COLOR_TEXTURE8_LIGHT_PER_VERTEX:
sp = shaderProgramColorTexture8Light;
break;
case COLOR:
default:
sp = shaderProgramColor;
}
currentShaderSelectionMode = newMode;
return sp;
}
private void init(final GL2ES2 gl, final ShaderSelectionMode mode, final PMVMatrix pmvMatrix) {
if(null==pmvMatrix) {
throw new GLException("PMVMatrix is null");
}
this.pmvMatrix=pmvMatrix;
this.requestedShaderSelectionMode = mode;
this.shaderState=new ShaderState();
this.shaderState.setVerbose(verbose);
shaderState.attachShaderProgram(gl, selectShaderProgram(gl, requestedShaderSelectionMode), true);
// mandatory ..
if(!shaderState.uniform(gl, new GLUniformData(mgl_PMVMatrix, 4, 4, pmvMatrix.glGetPMvMvitMatrixf()))) {
throw new GLException("Error setting PMVMatrix in shader: "+this);
}
shaderState.uniform(gl, new GLUniformData(mgl_ColorEnabled, 0));
shaderState.uniform(gl, new GLUniformData(mgl_ColorStatic, 4, colorStatic));
texID2Format.setKeyNotFoundValue(0);
shaderState.uniform(gl, new GLUniformData(mgl_TexCoordEnabled, 1, textureCoordEnabled));
shaderState.uniform(gl, new GLUniformData(mgl_TexEnvMode, 1, textureEnvMode));
shaderState.uniform(gl, new GLUniformData(mgl_TexFormat, 1, textureFormat));
shaderState.uniform(gl, new GLUniformData(mgl_TextureEnabled, 1, textureEnabled));
for(int i=0; i<MAX_TEXTURE_UNITS; i++) {
shaderState.uniform(gl, new GLUniformData(mgl_Texture+i, i));
}
shaderState.uniform(gl, new GLUniformData(mgl_ShadeModel, 0));
/** ES2 supports CullFace implicit
shaderState.uniform(gl, new GLUniformData(mgl_CullFace, cullFace)); */
shaderState.uniform(gl, new GLUniformData(mgl_AlphaTestFunc, alphaTestFunc));
shaderState.uniform(gl, new GLUniformData(mgl_AlphaTestRef, alphaTestRef));
shaderState.uniform(gl, new GLUniformData(mgl_PointParams, 4, pointParams));
for(int i=0; i<MAX_LIGHTS; i++) {
shaderState.uniform(gl, new GLUniformData(mgl_LightSource+"["+i+"].ambient", 4, defAmbient));
shaderState.uniform(gl, new GLUniformData(mgl_LightSource+"["+i+"].diffuse", 4, 0==i ? one4f : defDiffuseN));
shaderState.uniform(gl, new GLUniformData(mgl_LightSource+"["+i+"].specular", 4, 0==i ? one4f : defSpecularN));
shaderState.uniform(gl, new GLUniformData(mgl_LightSource+"["+i+"].position", 4, defPosition));
shaderState.uniform(gl, new GLUniformData(mgl_LightSource+"["+i+"].spotDirection", 3, defSpotDir));
shaderState.uniform(gl, new GLUniformData(mgl_LightSource+"["+i+"].spotExponent", defSpotExponent));
shaderState.uniform(gl, new GLUniformData(mgl_LightSource+"["+i+"].spotCutoff", defSpotCutoff));
shaderState.uniform(gl, new GLUniformData(mgl_LightSource+"["+i+"].constantAttenuation", defConstantAtten));
shaderState.uniform(gl, new GLUniformData(mgl_LightSource+"["+i+"].linearAttenuation", defLinearAtten));
shaderState.uniform(gl, new GLUniformData(mgl_LightSource+"["+i+"].quadraticAttenuation", defQuadraticAtten));
}
shaderState.uniform(gl, new GLUniformData(mgl_LightModel+".ambient", 4, defLightModelAmbient));
shaderState.uniform(gl, new GLUniformData(mgl_LightsEnabled, 1, lightsEnabled));
shaderState.uniform(gl, new GLUniformData(mgl_FrontMaterial+".ambient", 4, defMatAmbient));
shaderState.uniform(gl, new GLUniformData(mgl_FrontMaterial+".diffuse", 4, defMatDiffuse));
shaderState.uniform(gl, new GLUniformData(mgl_FrontMaterial+".specular", 4, defMatSpecular));
shaderState.uniform(gl, new GLUniformData(mgl_FrontMaterial+".emission", 4, defMatEmission));
shaderState.uniform(gl, new GLUniformData(mgl_FrontMaterial+".shininess", defMatShininess));
shaderState.useProgram(gl, false);
if(verbose) {
System.err.println("init: "+toString(null, DEBUG).toString());
}
}
private String toHexString(final int i) {
return "0x"+Integer.toHexString(i);
}
protected boolean verbose = DEBUG;
private final FloatBuffer colorStatic = Buffers.copyFloatBuffer(one4f);
private int activeTextureUnit=0;
private int clientActiveTextureUnit=0;
private final IntIntHashMap texID2Format = new IntIntHashMap();
private final int[] boundTextureObject = new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }; // per unit
private int textureEnabledBits = 0;
private final IntBuffer textureEnabled = Buffers.newDirectIntBuffer(new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }); // per unit
private boolean textureEnabledDirty = false;
private final IntBuffer textureCoordEnabled = Buffers.newDirectIntBuffer(new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }); // per unit
private boolean textureCoordEnabledDirty = false;
// textureEnvMode: 1 GL_ADD, 2 GL_MODULATE (default), 3 GL_DECAL, 4 GL_BLEND, 5 GL_REPLACE, 6 GL_COMBINE
private final IntBuffer textureEnvMode = Buffers.newDirectIntBuffer(new int[] { 2, 2, 2, 2, 2, 2, 2, 2 });
private boolean textureEnvModeDirty = false;
private final IntBuffer textureFormat = Buffers.newDirectIntBuffer(new int[] { 0, 0, 0, 0, 0, 0, 0, 0 }); // per unit
private boolean textureFormatDirty = false;
/** ES2 supports CullFace implicit
private int cullFace=-2; // <=0 disabled, 1 GL_FRONT, 2 GL_BACK (default) and 3 GL_FRONT_AND_BACK
private boolean cullFaceDirty = false;
private static final String mgl_CullFace = "mgl_CullFace"; // 1i (lowp int) */
private boolean colorVAEnabledDirty = false;
private boolean lightingEnabled=false;
private final IntBuffer lightsEnabled = Buffers.newDirectIntBuffer(new int[] { 0, 0, 0, 0, 0, 0, 0, 0 });
private boolean lightsEnabledDirty = false;
private boolean alphaTestDirty=false;
private int alphaTestFunc=-8; // <=0 disabled; 1 GL_NEVER, 2 GL_LESS, 3 GL_EQUAL, 4 GL_LEQUAL, 5 GL_GREATER, 6 GL_NOTEQUAL, 7 GL_GEQUAL, and 8 GL_ALWAYS (default)
private float alphaTestRef=0f;
private boolean pointParamsDirty = false;
/** ( pointSize, pointSmooth, attn. pointMinSize, attn. pointMaxSize ) , ( attenuation coefficients 1f 0f 0f, attenuation fade theshold 1f ) */
private final FloatBuffer pointParams = Buffers.newDirectFloatBuffer(new float[] { 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f });
private PMVMatrix pmvMatrix;
private ShaderState shaderState;
private ShaderProgram shaderProgramColor;
private ShaderProgram shaderProgramColorTexture2, shaderProgramColorTexture4, shaderProgramColorTexture8;
private ShaderProgram shaderProgramColorLight;
private ShaderProgram shaderProgramColorTexture8Light;
private ShaderProgram shaderProgramPoints;
private ShaderSelectionMode requestedShaderSelectionMode = ShaderSelectionMode.AUTO;
private ShaderSelectionMode currentShaderSelectionMode = requestedShaderSelectionMode;
// uniforms ..
private static final String mgl_PMVMatrix = "mgl_PMVMatrix"; // m4fv[4] - P, Mv, Mvi and Mvit
private static final String mgl_ColorEnabled = "mgl_ColorEnabled"; // 1i
private static final String mgl_ColorStatic = "mgl_ColorStatic"; // 4fv
private static final String mgl_LightModel = "mgl_LightModel"; // struct mgl_LightModelParameters
private static final String mgl_LightSource = "mgl_LightSource"; // struct mgl_LightSourceParameters[MAX_LIGHTS]
private static final String mgl_FrontMaterial = "mgl_FrontMaterial"; // struct mgl_MaterialParameters
private static final String mgl_LightsEnabled = "mgl_LightsEnabled"; // int mgl_LightsEnabled[MAX_LIGHTS];
private static final String mgl_AlphaTestFunc = "mgl_AlphaTestFunc"; // 1i (lowp int)
private static final String mgl_AlphaTestRef = "mgl_AlphaTestRef"; // 1f
private static final String mgl_ShadeModel = "mgl_ShadeModel"; // 1i
private static final String mgl_PointParams = "mgl_PointParams"; // vec4[2]: { (sz, smooth, attnMinSz, attnMaxSz), (attnCoeff(3), attnFadeTs) }
private static final String mgl_TextureEnabled = "mgl_TextureEnabled"; // int mgl_TextureEnabled[MAX_TEXTURE_UNITS];
private static final String mgl_Texture = "mgl_Texture"; // sampler2D mgl_Texture<0..7>
private static final String mgl_TexCoordEnabled = "mgl_TexCoordEnabled"; // int mgl_TexCoordEnabled[MAX_TEXTURE_UNITS];
private static final String mgl_TexEnvMode = "mgl_TexEnvMode"; // int mgl_TexEnvMode[MAX_TEXTURE_UNITS];
private static final String mgl_TexFormat = "mgl_TexFormat"; // int mgl_TexFormat[MAX_TEXTURE_UNITS];
// private static final FloatBuffer zero4f = Buffers.newDirectFloatBuffer(new float[] { 0.0f, 0.0f, 0.0f, 0.0f });
private static final FloatBuffer neut4f = Buffers.newDirectFloatBuffer(new float[] { 0.0f, 0.0f, 0.0f, 1.0f });
private static final FloatBuffer one4f = Buffers.newDirectFloatBuffer(new float[] { 1.0f, 1.0f, 1.0f, 1.0f });
public static final FloatBuffer defAmbient = neut4f;
public static final FloatBuffer defDiffuseN = neut4f;
public static final FloatBuffer defSpecularN = neut4f;
public static final FloatBuffer defPosition = Buffers.newDirectFloatBuffer(new float[] { 0f, 0f, 1f, 0f });
public static final FloatBuffer defSpotDir = Buffers.newDirectFloatBuffer(new float[] { 0f, 0f, -1f });
public static final float defSpotExponent = 0f;
public static final float defSpotCutoff = 180f;
public static final float defConstantAtten = 1f;
public static final float defLinearAtten = 0f;
public static final float defQuadraticAtten = 0f;
public static final FloatBuffer defLightModelAmbient = Buffers.newDirectFloatBuffer(new float[] { 0.2f, 0.2f, 0.2f, 1.0f });
public static final FloatBuffer defMatAmbient = Buffers.newDirectFloatBuffer(new float[] { 0.2f, 0.2f, 0.2f, 1.0f });
public static final FloatBuffer defMatDiffuse = Buffers.newDirectFloatBuffer(new float[] { 0.8f, 0.8f, 0.8f, 1.0f });
public static final FloatBuffer defMatSpecular = neut4f;
public static final FloatBuffer defMatEmission = neut4f;
public static final float defMatShininess = 0f;
private static final String vertexColorFileDef = "FixedFuncColor";
private static final String vertexColorLightFileDef = "FixedFuncColorLight";
private static final String fragmentColorFileDef = "FixedFuncColor";
private static final String fragmentColorTextureFileDef = "FixedFuncColorTexture";
private static final String shaderPointFileDef = "FixedFuncPoints";
private static final String shaderSrcRootDef = "shaders" ;
private static final String shaderBinRootDef = "shaders/bin" ;
private final Class<?> shaderRootClass;
private final String shaderSrcRoot;
private final String shaderBinRoot;
private final String vertexColorFile;
private final String vertexColorLightFile;
private final String fragmentColorFile;
private final String fragmentColorTextureFile;
}