Subversion Repositories AndroidProjects

Rev

Blame | Last modification | View Log | RSS feed

package com.gebauz.bauzoid.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.bauzoid.app.Consts;
import com.gebauz.bauzoid.graphics.Graphics;
import com.gebauz.bauzoid.graphics.GraphicsObject;
import com.gebauz.bauzoid.graphics.model.VertexAttribute;
import com.gebauz.bauzoid.math.Matrix4;

public class ShaderProgram extends GraphicsObject
{
        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 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(Consts.LOG_TAG, "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.log(Consts.LOG_TAG, Gdx.gl20.glGetShaderInfoLog(mShaderID));
                                return;
                        }
                       
                        ShaderUtil.log(Consts.LOG_TAG, "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 mModelViewProjection = null;
        private Matrix4 mModelViewProjectionMatrix = new Matrix4();
       
        public ShaderProgram(Graphics graphics)
        {
                super(graphics);
               
                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);
               
                // obtain uniforms for standard names
                mModelViewProjection = getUniform("uMVPMatrix");
               
                mManagedShaders.add(this);
        }
       
        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 (mModelViewProjection != null)
                {
                        getRenderStates().getModelViewProjection(mModelViewProjectionMatrix);
                        mModelViewProjection.set(mModelViewProjectionMatrix);
                }
        }
       
        public void deactivate()
        {
                Gdx.gl20.glUseProgram(0);
        }
       
        public ShaderUniform getUniform(String uniformName)
        {
                if (mProgramID == 0)
                        return null;
               
                int handle = getUniformHandle(uniformName);
               
                if (handle == -1)
                {
                        //Log.e(Consts.LOG_TAG, "Error getting uniform '" + uniformName + "'!");
                        return null;
                }
               
                return new ShaderUniform(this, uniformName);
        }
       
        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(Consts.LOG_TAG, "ShaderProgram reloaded!");
                }
        }
}