/*
 * 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 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;

    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 = GLPointerFuncUtil.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.useProgram(gl, true);

        shaderState.enableVertexAttribArray(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.useProgram(gl, true);

        shaderState.disableVertexAttribArray(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.useProgram(gl, true);
        shaderState.vertexAttribPointer(gl, data);
    }

    public void glColorPointer(GL2ES2 gl, GLArrayData data) {
        shaderState.useProgram(gl, true);
        shaderState.vertexAttribPointer(gl, data);
    }

    public void glColor4fv(GL2ES2 gl, FloatBuffer data ) {
        shaderState.useProgram(gl, true);
        GLUniformData ud = shaderState.getUniform(mgl_ColorStatic);
        if(null!=ud) {
            ud.setData(data);
            shaderState.uniform(gl, ud);
        }
    }

    public void glNormalPointer(GL2ES2 gl, GLArrayData data) {
        shaderState.useProgram(gl, true);
        shaderState.vertexAttribPointer(gl, data);
    }

    public void glTexCoordPointer(GL2ES2 gl, GLArrayData data) {
        shaderState.useProgram(gl, true);
        data.setName( getArrayIndexName(data.getIndex()) );
        shaderState.vertexAttribPointer(gl, data);
    }

    public void glLightfv(GL2ES2 gl, int light, int pname, 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:
                    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.uniform(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.useProgram(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.uniform(gl, ud);
        }
    }

    public void glShadeModel(GL2ES2 gl, int mode) {
        shaderState.useProgram(gl, true);
        GLUniformData ud = shaderState.getUniform(mgl_ShadeModel);
        if(null!=ud) {
            ud.setData(mode);
            shaderState.uniform(gl, ud);
        }
    }

    public void glActiveTexture(GL2ES2 gl, int textureUnit) {
        textureUnit -= GL.GL_TEXTURE0;
        if(0 <= textureUnit && textureUnit<MAX_TEXTURE_UNITS) {
            shaderState.useProgram(gl, true);
            GLUniformData ud;
            ud = shaderState.getUniform(mgl_ActiveTexture);
            if(null!=ud) {
                ud.setData(textureUnit);
                shaderState.uniform(gl, ud);
            }
            ud = shaderState.getUniform(mgl_ActiveTextureIdx);
            if(null!=ud) {
                ud.setData(textureUnit);
                shaderState.uniform(gl, ud);
            }
            activeTextureUnit = textureUnit;
        } else {
            throw new GLException("glActivateTexture textureUnit not within GL_TEXTURE0 + [0.."+MAX_TEXTURE_UNITS+"]: "+textureUnit);
        }
    }

    /**
     * @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(GL2ES2 gl, int cap, boolean enable) {
        switch(cap) {
            case GL.GL_TEXTURE_2D:
                textureEnabled=enable;
                return true;
            case GLLightingFunc.GL_LIGHTING:
                lightingEnabled=enable;
                return false;
            case GL.GL_CULL_FACE:
                cullFace=Math.abs(cullFace);
                if(!enable) {
                    cullFace*=-1;
                }
                return true;
        }

        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;
            }
        }
        return true; // pass it on ..
    }

    public void glCullFace(GL2ES2 gl, int faceName) {
        switch(faceName) {
            case GL.GL_FRONT:
                faceName = 1; break;
            case GL.GL_BACK:
                faceName = 2; break;
            case GL.GL_FRONT_AND_BACK:
                faceName = 3; break;
        }
        if(0>cullFace) {
            faceName *= -1;
        }
        cullFace = faceName;
    }

    public void validate(GL2ES2 gl) {
        shaderState.useProgram(gl, true);
        GLUniformData ud;
        if(pmvMatrix.update()) {
            ud = shaderState.getUniform(mgl_PMVMatrix);
            if(null!=ud) {
                // same data object ..
                shaderState.uniform(gl, ud);
            } else {
                throw new GLException("Failed to update: mgl_PMVMatrix");
            }
        }
        ud = shaderState.getUniform(mgl_ColorEnabled);
        if(null!=ud) {
            int ca = (shaderState.isVertexAttribArrayEnabled(GLPointerFuncUtil.mgl_Color)==true)?1:0;
            if(ca!=ud.intValue()) {
                ud.setData(ca);
                shaderState.uniform(gl, ud);
            }
        }
        ud = shaderState.getUniform(mgl_CullFace);
        if(null!=ud) {
            if(cullFace!=ud.intValue()) {
                ud.setData(cullFace);
                shaderState.uniform(gl, ud);
            }
        }

        if(lightsEnabledDirty) {
            ud = shaderState.getUniform(mgl_LightsEnabled);
            if(null!=ud) {
                // same data object 
                shaderState.uniform(gl, ud);
            }
            lightsEnabledDirty=false;
        }

        if(textureCoordsEnabledDirty) {
            ud = shaderState.getUniform(mgl_TexCoordEnabled);
            if(null!=ud) {
                // same data object 
                shaderState.uniform(gl, ud);
            }
            textureCoordsEnabledDirty=false;
        }

        if(textureEnabled) {
            if(lightingEnabled) {
                shaderState.attachShaderProgram(gl, shaderProgramColorTextureLight, true);
            } else {
                shaderState.attachShaderProgram(gl, shaderProgramColorTexture, true);
            }
        } else {
            if(lightingEnabled) {
                shaderState.attachShaderProgram(gl, shaderProgramColorLight, true);
            } else {
                shaderState.attachShaderProgram(gl, shaderProgramColor, true);
            }
        }
        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, shaderRootClass, shaderSrcRoot,
                                         shaderBinRoot, vertexColorFile, false);

        vertexColorLight = ShaderCode.create( gl, gl.GL_VERTEX_SHADER, shaderRootClass, shaderSrcRoot,
                                           shaderBinRoot, vertexColorLightFile, false);

        fragmentColor = ShaderCode.create( gl, gl.GL_FRAGMENT_SHADER, shaderRootClass, shaderSrcRoot,
                                           shaderBinRoot, fragmentColorFile, false);

        fragmentColorTexture = ShaderCode.create( gl, gl.GL_FRAGMENT_SHADER, shaderRootClass, shaderSrcRoot,
                                                  shaderBinRoot, fragmentColorTextureFile, false);

        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, 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, zero4f));
        shaderState.uniform(gl, new GLUniformData(mgl_TexCoordEnabled,  1, textureCoordsEnabled));
        shaderState.uniform(gl, new GLUniformData(mgl_ActiveTexture, activeTextureUnit));
        shaderState.uniform(gl, new GLUniformData(mgl_ActiveTextureIdx, activeTextureUnit));
        shaderState.uniform(gl, new GLUniformData(mgl_ShadeModel, 0));
        shaderState.uniform(gl, new GLUniformData(mgl_CullFace, cullFace));
        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, defDiffuse));
            shaderState.uniform(gl, new GLUniformData(mgl_LightSource+"["+i+"].specular", 4, defSpecular));
            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_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);
    }

    protected static final boolean DEBUG=false;
    protected boolean verbose=false;

    protected boolean textureEnabled=false;
    protected IntBuffer textureCoordsEnabled = Buffers.newDirectIntBuffer(new int[] { 0, 0, 0, 0, 0, 0, 0, 0 });
    protected boolean textureCoordsEnabledDirty = false;
    protected int     activeTextureUnit=0;

    protected int cullFace=-2; // <=0 disabled, 1: front, 2: back (default, but disabled), 3: front & back

    protected boolean lightingEnabled=false;
    protected IntBuffer lightsEnabled = Buffers.newDirectIntBuffer(new int[] { 0, 0, 0, 0, 0, 0, 0, 0 });
    protected boolean   lightsEnabledDirty = false;

    protected PMVMatrix pmvMatrix;
    protected ShaderState shaderState;
    protected ShaderProgram shaderProgramColor;
    protected ShaderProgram shaderProgramColorTexture;
    protected ShaderProgram shaderProgramColorLight;
    protected ShaderProgram shaderProgramColorTextureLight;

    // uniforms ..
    protected static final String mgl_PMVMatrix        = "mgl_PMVMatrix";       // m4fv[4] - P, Mv, Mvi and Mvit
    protected static final String mgl_ColorEnabled     = "mgl_ColorEnabled";    //  1i
    protected static final String mgl_ColorStatic      = "mgl_ColorStatic";     //  4fv

    protected static final String mgl_LightSource      = "mgl_LightSource";     //  struct mgl_LightSourceParameters[MAX_LIGHTS]
    protected static final String mgl_FrontMaterial    = "mgl_FrontMaterial";   //  struct mgl_MaterialParameters
    protected static final String mgl_LightsEnabled    = "mgl_LightsEnabled";   //  int mgl_LightsEnabled[MAX_LIGHTS];

    protected static final String mgl_ShadeModel       = "mgl_ShadeModel";      //  1i

    protected static final String mgl_TexCoordEnabled  = "mgl_TexCoordEnabled"; //  int mgl_TexCoordEnabled[MAX_TEXTURE_UNITS];
    protected static final String mgl_ActiveTexture    = "mgl_ActiveTexture";   //  1i
    protected static final String mgl_ActiveTextureIdx = "mgl_ActiveTextureIdx";//  1i

    protected static final String mgl_CullFace         = "mgl_CullFace";   //  1i

    protected static final FloatBuffer zero4f     = Buffers.newDirectFloatBuffer(new float[] { 0.0f, 0.0f, 0.0f, 0.0f });

    public static final FloatBuffer defAmbient = Buffers.newDirectFloatBuffer(new float[] { 0f, 0f, 0f, 1f });
    public static final FloatBuffer defDiffuse = zero4f;
    public static final FloatBuffer defSpecular= zero4f;
    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 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= Buffers.newDirectFloatBuffer(new float[] { 0f, 0f, 0f, 1f});
    public static final FloatBuffer defMatEmission= Buffers.newDirectFloatBuffer(new float[] { 0f, 0f, 0f, 1f});
    public static final float       defMatShininess = 0f;

    protected static final String vertexColorFileDef          = "FixedFuncColor";
    protected static final String vertexColorLightFileDef    = "FixedFuncColorLight";
    protected static final String fragmentColorFileDef        = "FixedFuncColor";
    protected static final String fragmentColorTextureFileDef = "FixedFuncColorTexture";
    protected static final String shaderSrcRootDef = "shaders" ;
    protected static final String shaderBinRootDef = "shaders/bin" ;
}