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!");
}
}
}