Subversion Repositories AndroidProjects

Rev

Rev 1712 | Blame | Compare with Previous | Last modification | View Log | RSS feed

package com.gebauz.bauzoid2.graphics.shader;

import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.utils.BufferUtils;
import com.gebauz.bauzoid2.game.Engine;
import com.gebauz.bauzoid2.graphics.geometry.VertexAttribute;
import com.gebauz.bauzoid2.math.Matrix3;
import com.gebauz.bauzoid2.math.Matrix4;

public class ShaderProgram
{
        private static List<ShaderProgram> mManagedShaders = new ArrayList<ShaderProgram>();
       
        public static String ATTRIB_POSITION = "aPosition";
        public static String ATTRIB_COLOR = "aColor";
        public static String ATTRIB_NORMAL= "aNormal";
        public static String ATTRIB_TEXCOORD0 = "aTexCoord0";
        public static String ATTRIB_TEXCOORD1 = "aTexCoord1";
        public static String ATTRIB_BLENDINDICES = "aBlendIndex";
        public static String ATTRIB_BLENDWEIGHTS = "aBlendWeight";
       
        public static String UNIFORM_MVP_MATRIX = "uMVPMatrix";
    public static String UNIFORM_NORMAL_MATRIX = "uNormalMatrix";
       
        public class Shader
        {
                private int mShaderID = 0;
                private int mShaderType;
                private String mShaderCode;
               
                public Shader(int shaderType)
                {
                        mShaderType = shaderType;
                }
               
                public void loadShader(String shaderCode)
                {
                        ShaderUtil.log("Loading " + (mShaderType == GL20.GL_VERTEX_SHADER ? "Vertex" : "Fragment") + " Shader");
                       
                        mShaderCode = shaderCode;
                       
                        if (mShaderID != 0)
                                unloadShader();
                       
                        mShaderID = Gdx.gl20.glCreateShader(mShaderType);
                       
                        Gdx.gl20.glShaderSource(mShaderID, mShaderCode);
                        Gdx.gl20.glCompileShader(mShaderID);
                       
                        Gdx.gl20.glGetShaderiv(mShaderID, GL20.GL_COMPILE_STATUS, COMPILESTATUS);
                       
                        if (COMPILESTATUS.get(0) != GL20.GL_TRUE)
                        {
                                ShaderUtil.logError("Shader Error: " + Gdx.gl20.glGetShaderInfoLog(mShaderID));
                                return;
                        }
                       
                        ShaderUtil.log("Shader loading successful!");
                }
               
                public void reloadShader()
                {                      
                        mShaderID = 0;
                        loadShader(mShaderCode);
                }
               
                public void unloadShader()
                {
                        Gdx.gl20.glDeleteShader(mShaderID);
                        mShaderID = 0;
                        mShaderCode = "";
                }
        };
       
        private static final IntBuffer COMPILESTATUS = BufferUtils.newIntBuffer(1);

        private Shader mVertexShader = null;
        private Shader mFragmentShader = null;
        private int mProgramID = 0;
       
        // Standard uniforms
        private ShaderUniform mModelViewProjectionHandle = null;
        private Matrix4 mModelViewProjectionMatrix = new Matrix4();

    private ShaderUniform mNormalHandle = null;
    private Matrix3 mNormalMatrix = new Matrix3();
       
        public ShaderProgram()
        {
                mVertexShader = new Shader(GL20.GL_VERTEX_SHADER);
                mFragmentShader = new Shader(GL20.GL_FRAGMENT_SHADER);
        }
       
        public void loadShaderProgram(String vertexShaderCode, String fragmentShaderCode)
        {
                mVertexShader.loadShader(vertexShaderCode);
                mFragmentShader.loadShader(fragmentShaderCode);
               
                mProgramID = Gdx.gl20.glCreateProgram();
               
                Gdx.gl20.glAttachShader(mProgramID, mVertexShader.mShaderID);
                Gdx.gl20.glAttachShader(mProgramID, mFragmentShader.mShaderID);
               
                // default attrib locations
                /*GLES20.glBindAttribLocation(mProgramID, SimpleGeometry.COORD_ATTRIB_INDEX, "vPosition");
                GLES20.glBindAttribLocation(mProgramID, SimpleGeometry.COLOR_ATTRIB_INDEX, "vColor");
                GLES20.glBindAttribLocation(mProgramID, SimpleGeometry.NORMAL_ATTRIB_INDEX, "vNormal");
                GLES20.glBindAttribLocation(mProgramID, SimpleGeometry.TEX_COORD_ATTRIB_INDEX, "vTexCoord");*/

               
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.POSITION, ATTRIB_POSITION);
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.COLOR, ATTRIB_COLOR);
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.NORMAL, ATTRIB_NORMAL);
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.TEXCOORD0, ATTRIB_TEXCOORD0);
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.TEXCOORD1, ATTRIB_TEXCOORD1);
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.BLENDINDICES, ATTRIB_BLENDINDICES);
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.BLENDWEIGHTS, ATTRIB_BLENDWEIGHTS);
               
                Gdx.gl20.glLinkProgram(mProgramID);

        Engine.log(Gdx.gl20.glGetProgramInfoLog(mProgramID));
               
                // obtain uniforms for standard names
                mModelViewProjectionHandle = getStandardUniform(UNIFORM_MVP_MATRIX);
        mNormalHandle = getStandardUniform(UNIFORM_NORMAL_MATRIX);
               
                mManagedShaders.add(this);
        }
       
        public ShaderUniform getStandardUniform(String uniformName)
        {
                if (existsUniform(uniformName))
                        return getUniform(uniformName);

                return null;
        }
       
        public void reloadShaderProgram()
        {
                mVertexShader.reloadShader();
                mFragmentShader.reloadShader();
               
                mProgramID = Gdx.gl20.glCreateProgram();
               
                Gdx.gl20.glAttachShader(mProgramID, mVertexShader.mShaderID);
                Gdx.gl20.glAttachShader(mProgramID, mFragmentShader.mShaderID);
               
                // default attrib locations
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.POSITION, ATTRIB_POSITION);
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.COLOR, ATTRIB_COLOR);
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.NORMAL, ATTRIB_NORMAL);
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.TEXCOORD0, ATTRIB_TEXCOORD0);
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.TEXCOORD1, ATTRIB_TEXCOORD1);
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.BLENDINDICES, ATTRIB_BLENDINDICES);
                Gdx.gl20.glBindAttribLocation(mProgramID, VertexAttribute.BLENDWEIGHTS, ATTRIB_BLENDWEIGHTS);
               
                Gdx.gl20.glLinkProgram(mProgramID);
        }
       
        public void dispose()
        {
                mManagedShaders.remove(this);
               
                Gdx.gl20.glDeleteProgram(mProgramID);  
               
                mVertexShader.unloadShader();
                mFragmentShader.unloadShader();
               
                mProgramID = 0;
        }
       
        public void activate()
        {
                // TODO: state management!
                Gdx.gl20.glUseProgram(mProgramID);
               
                // apply standard uniforms
                if (mModelViewProjectionHandle != null)
                {
                        Engine.graphics.renderStates.getModelViewProjection(mModelViewProjectionMatrix);
                        mModelViewProjectionHandle.set(mModelViewProjectionMatrix);
                }
        if (mNormalHandle != null)
        {
            Engine.graphics.renderStates.getModelViewProjection(mModelViewProjectionMatrix);

            mNormalMatrix = mModelViewProjectionMatrix.toMatrix3().getInverse().getTranspose();
            mNormalHandle.set(mNormalMatrix);
        }
        }
       
        public void deactivate()
        {
                Gdx.gl20.glUseProgram(0);
        }
       
        public ShaderUniform getUniform(String uniformName)
        {
                if (mProgramID == 0)
                        return null;
               
                int handle = getUniformHandle(uniformName);
               
                if (handle == -1)
                {
                        ShaderUtil.logError("Error getting uniform '" + uniformName + "'!");
                        return null;
                }
               
                return new ShaderUniform(this, uniformName);
        }
       
        public boolean existsUniform(String uniformName)
        {
                if (mProgramID == 0)
                        return false;
               
                return (getUniformHandle(uniformName) != -1);
        }
       
        public int getUniformHandle(String uniformName)
        {
                return Gdx.gl20.glGetUniformLocation(mProgramID, uniformName);
        }

        public Shader getVertexShader()
        {
                return mVertexShader;
        }
       
        public Shader getFragmentShader()
        {
                return mFragmentShader;
        }
       
        public static void reloadManagedShaders()
        {
                for (int i = 0; i < mManagedShaders.size(); i++)
                {
                        ShaderProgram shader = mManagedShaders.get(i);
                        shader.reloadShaderProgram();
                        ShaderUtil.log("ShaderProgram reloaded!");
                }
        }
}