/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.glview.libgdx.graphics.glutils;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import android.os.Build;
import com.glview.App;
import com.glview.libgdx.graphics.Color;
import com.glview.libgdx.graphics.math.Matrix3;
import com.glview.libgdx.graphics.math.Matrix4;
import com.glview.libgdx.graphics.math.Vector2;
import com.glview.libgdx.graphics.math.Vector3;
import com.glview.libgdx.graphics.opengl.GL20;
import com.glview.libgdx.graphics.utils.Disposable;
import com.glview.libgdx.graphics.utils.ObjectIntMap;
import com.glview.utils.BufferUtils;
/** <p>
* A shader program encapsulates a vertex and fragment shader pair linked to form a shader program useable with OpenGL ES 2.0.
* </p>
*
* <p>
* After construction a ShaderProgram can be used to draw {@link Mesh_GL10}. To make the GPU use a specific ShaderProgram the programs
* {@link ShaderProgram#begin()} method must be used which effectively binds the program.
* </p>
*
* <p>
* When a ShaderProgram is bound one can set uniforms, vertex attributes and attributes as needed via the respective methods.
* </p>
*
* <p>
* A ShaderProgram can be unbound with a call to {@link ShaderProgram#end()}
* </p>
*
* <p>
* A ShaderProgram must be disposed via a call to {@link ShaderProgram#dispose()} when it is no longer needed
* </p>
*
* <p>
* ShaderPrograms are managed. In case the OpenGL context is lost all shaders get invalidated and have to be reloaded. This
* happens on Android when a user switches to another application or receives an incoming call. Managed ShaderPrograms are
* automatically reloaded when the OpenGL context is recreated so you don't have to do this manually.
* </p>
*
* @author mzechner */
public class ShaderProgram implements Disposable {
/** default name for position attributes **/
public static final String POSITION_ATTRIBUTE = "a_position";
/** default name for normal attribtues **/
public static final String NORMAL_ATTRIBUTE = "a_normal";
/** default name for color attributes **/
public static final String COLOR_ATTRIBUTE = "a_color";
/** default name for texcoords attributes, append texture unit number **/
public static final String TEXCOORD_ATTRIBUTE = "a_texCoord";
/** default name for tangent attribute **/
public static final String TANGENT_ATTRIBUTE = "a_tangent";
/** default name for binormal attribute **/
public static final String BINORMAL_ATTRIBUTE = "a_binormal";
/** flag indicating whether attributes & uniforms must be present at all times **/
public static boolean pedantic = true;
/** the log **/
private String log = "";
/** whether this program compiled succesfully **/
private boolean isCompiled;
/** uniform lookup **/
private final ObjectIntMap<String> uniforms = new ObjectIntMap<String>();
/** uniform types **/
private final ObjectIntMap<String> uniformTypes = new ObjectIntMap<String>();
/** uniform sizes **/
private final ObjectIntMap<String> uniformSizes = new ObjectIntMap<String>();
/** uniform names **/
private String[] uniformNames;
/** attribute lookup **/
private final ObjectIntMap<String> attributes = new ObjectIntMap<String>();
/** attribute types **/
private final ObjectIntMap<String> attributeTypes = new ObjectIntMap<String>();
/** attribute sizes **/
private final ObjectIntMap<String> attributeSizes = new ObjectIntMap<String>();
/** attribute names **/
private String[] attributeNames;
/** program handle **/
private int program;
/** vertex shader handle **/
private int vertexShaderHandle;
/** fragment shader handle **/
private int fragmentShaderHandle;
/** matrix float buffer **/
private final FloatBuffer matrix;
/** vertex shader source **/
private final String vertexShaderSource;
/** fragment shader source **/
private final String fragmentShaderSource;
/** whether this shader was invalidated **/
private boolean invalidated;
/** direct buffer for passing float and int uniform arrays **/
private ByteBuffer buffer = null;
private FloatBuffer floatBuffer = null;
private IntBuffer intBuffer = null;
/** reference count **/
private int refCount = 0;
/** Construcs a new ShaderProgram and immediately compiles it.
*
* @param vertexShader the vertex shader
* @param fragmentShader the fragment shader */
public ShaderProgram (String vertexShader, String fragmentShader) {
if (vertexShader == null) throw new IllegalArgumentException("vertex shader must not be null");
if (fragmentShader == null) throw new IllegalArgumentException("fragment shader must not be null");
this.vertexShaderSource = vertexShader;
this.fragmentShaderSource = fragmentShader;
this.matrix = BufferUtils.newFloatBuffer(16);
compile();
}
public boolean compile() {
if (!isCompiled()) {
compileShaders(vertexShaderSource, fragmentShaderSource);
if (isCompiled()) {
fetchAttributes();
fetchUniforms();
}
if (!isCompiled()) {
throw new IllegalArgumentException("Error compiling shader: " + getLog());
}
}
return true;
}
public int getProgram() {
compile();
return program;
}
/** Loads and compiles the shaders, creates a new program and links the shaders.
*
* @param vertexShader
* @param fragmentShader */
private void compileShaders (String vertexShader, String fragmentShader) {
vertexShaderHandle = loadShader(GL20.GL_VERTEX_SHADER, vertexShader);
fragmentShaderHandle = loadShader(GL20.GL_FRAGMENT_SHADER, fragmentShader);
if (vertexShaderHandle == -1 || fragmentShaderHandle == -1) {
isCompiled = false;
return;
}
program = linkProgram();
if (program == -1) {
isCompiled = false;
return;
}
isCompiled = true;
}
private int loadShader (int type, String source) {
GL20 gl = App.getGL20();
int shader = gl.glCreateShader(type);
if (shader == 0) return -1;
IntBuffer intbuf = BufferUtils.newIntBuffer(1);
gl.glShaderSource(shader, source);
gl.glCompileShader(shader);
gl.glGetShaderiv(shader, GL20.GL_COMPILE_STATUS, intbuf);
int compiled = intbuf.get(0);
if (compiled == 0) {
// gl.glGetShaderiv(shader, GL20.GL_INFO_LOG_LENGTH, intbuf);
// int infoLogLength = intbuf.get(0);
// if (infoLogLength > 1) {
String infoLog = gl.glGetShaderInfoLog(shader);
log += infoLog;
// }
return -1;
}
return shader;
}
private int linkProgram () {
GL20 gl = App.getGL20();
int program = gl.glCreateProgram();
if (program == 0) return -1;
gl.glAttachShader(program, vertexShaderHandle);
gl.glAttachShader(program, fragmentShaderHandle);
gl.glLinkProgram(program);
ByteBuffer tmp = ByteBuffer.allocateDirect(4);
tmp.order(ByteOrder.nativeOrder());
IntBuffer intbuf = tmp.asIntBuffer();
gl.glGetProgramiv(program, GL20.GL_LINK_STATUS, intbuf);
int linked = intbuf.get(0);
if (linked == 0) {
// App.getGL20().glGetProgramiv(program, GL20.GL_INFO_LOG_LENGTH, intbuf);
// int infoLogLength = intbuf.get(0);
// if (infoLogLength > 1) {
log = App.getGL20().glGetProgramInfoLog(program);
// }
return -1;
}
return program;
}
final static IntBuffer intbuf = BufferUtils.newIntBuffer(1);
/** @return the log info for the shader compilation and program linking stage. The shader needs to be bound for this method to
* have an effect. */
public String getLog () {
if (isCompiled) {
// App.getGL20().glGetProgramiv(program, GL20.GL_INFO_LOG_LENGTH, intbuf);
// int infoLogLength = intbuf.get(0);
// if (infoLogLength > 1) {
log = App.getGL20().glGetProgramInfoLog(program);
// }
return log;
} else {
return log;
}
}
/** @return whether this ShaderProgram compiled successfully. */
public boolean isCompiled () {
return isCompiled;
}
public int fetchAttributeLocation(HandleInfo handle){
if(!handle.checkLocationValid()){
checkManaged();
int location = fetchAttributeLocation (handle.name);
handle.location = location;
}
return handle.location;
}
private int fetchAttributeLocation (String name) {
GL20 gl = App.getGL20();
// -2 == not yet cached
// -1 == cached but not found
int location;
if ((location = attributes.get(name, -2)) == -2) {
location = gl.glGetAttribLocation(program, name);
attributes.put(name, location);
}
return location;
}
private int fetchUniformLocation (HandleInfo handle) {
if(!handle.checkLocationValid()){
checkManaged();
int location = fetchUniformLocation (handle.name);
handle.location = location;
}
return handle.location;
}
private int fetchUniformLocation (String name) {
return fetchUniformLocation(name, pedantic);
}
public int fetchUniformLocation (String name, boolean pedantic) {
GL20 gl = App.getGL20();
// -2 == not yet cached
// -1 == cached but not found
int location;
if ((location = uniforms.get(name, -2)) == -2) {
location = gl.glGetUniformLocation(program, name);
if (location == -1 && pedantic) throw new IllegalArgumentException("no uniform with name '" + name + "' in shader");
uniforms.put(name, location);
}
return location;
}
/** Sets the uniform with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param value the value */
public void setUniformi (String name, int value) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
gl.glUniform1i(location, value);
}
public void setUniformi (int location, int value) {
GL20 gl = App.getGL20();
checkManaged();
gl.glUniform1i(location, value);
}
public void setUniformi (HandleInfo handle, int value) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniformi (location, value);
}
/** Sets the uniform with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param value1 the first value
* @param value2 the second value */
public void setUniformi (String name, int value1, int value2) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
gl.glUniform2i(location, value1, value2);
}
public void setUniformi (int location, int value1, int value2) {
GL20 gl = App.getGL20();
checkManaged();
gl.glUniform2i(location, value1, value2);
}
public void setUniformi (HandleInfo handle, int value1, int value2) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniformf (location, value1, value2);
}
/** Sets the uniform with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param value1 the first value
* @param value2 the second value
* @param value3 the third value */
public void setUniformi (String name, int value1, int value2, int value3) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
gl.glUniform3i(location, value1, value2, value3);
}
public void setUniformi (int location, int value1, int value2, int value3) {
GL20 gl = App.getGL20();
checkManaged();
gl.glUniform3i(location, value1, value2, value3);
}
public void setUniformi (HandleInfo handle, int value1, int value2, int value3) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniformf (location, value1, value2, value3);
}
/** Sets the uniform with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param value1 the first value
* @param value2 the second value
* @param value3 the third value
* @param value4 the fourth value */
public void setUniformi (String name, int value1, int value2, int value3, int value4) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
gl.glUniform4i(location, value1, value2, value3, value4);
}
public void setUniformi (int location, int value1, int value2, int value3, int value4) {
GL20 gl = App.getGL20();
checkManaged();
gl.glUniform4i(location, value1, value2, value3, value4);
}
public void setUniformi (HandleInfo handle, int value1, int value2, int value3, int value4) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniformf (location, value1, value2, value3, value4);
}
/** Sets the uniform with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param value the value */
public void setUniformf (String name, float value) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
gl.glUniform1f(location, value);
}
public void setUniformf (int location, float value) {
GL20 gl = App.getGL20();
checkManaged();
gl.glUniform1f(location, value);
}
public void setUniformf (HandleInfo handle, float value) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniformf (location, value);
}
/** Sets the uniform with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param value1 the first value
* @param value2 the second value */
public void setUniformf (String name, float value1, float value2) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
gl.glUniform2f(location, value1, value2);
}
public void setUniformf (int location, float value1, float value2) {
GL20 gl = App.getGL20();
checkManaged();
gl.glUniform2f(location, value1, value2);
}
public void setUniformf (HandleInfo handle, float value1, float value2) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniformf (location, value1, value2);
}
/** Sets the uniform with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param value1 the first value
* @param value2 the second value
* @param value3 the third value */
public void setUniformf (String name, float value1, float value2, float value3) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
gl.glUniform3f(location, value1, value2, value3);
}
public void setUniformf (int location, float value1, float value2, float value3) {
GL20 gl = App.getGL20();
checkManaged();
gl.glUniform3f(location, value1, value2, value3);
}
public void setUniformf (HandleInfo handle, float value1, float value2, float value3) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniformf (location, value1, value2, value3);
}
/** Sets the uniform with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param value1 the first value
* @param value2 the second value
* @param value3 the third value
* @param value4 the fourth value */
public void setUniformf (String name, float value1, float value2, float value3, float value4) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
gl.glUniform4f(location, value1, value2, value3, value4);
}
public void setUniformf (int location, float value1, float value2, float value3, float value4) {
GL20 gl = App.getGL20();
checkManaged();
gl.glUniform4f(location, value1, value2, value3, value4);
}
public void setUniformf (HandleInfo handle, float value1, float value2, float value3, float value4) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniformf (location, value1, value2, value3, value4);
}
public void setUniform1fv (String name, float[] values, int offset, int length) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
ensureBufferCapacity(length << 2);
floatBuffer.clear();
BufferUtils.copy(values, floatBuffer, length, offset);
gl.glUniform1fv(location, length, floatBuffer);
}
public void setUniform1fv (int location, float[] values, int offset, int length) {
GL20 gl = App.getGL20();
checkManaged();
ensureBufferCapacity(length << 2);
floatBuffer.clear();
BufferUtils.copy(values, floatBuffer, length, offset);
gl.glUniform1fv(location, length, floatBuffer);
}
public void setUniform1fv (HandleInfo handle, float[] values, int offset, int length) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniform1fv(location, values, offset, length);
}
public void setUniform2fv (String name, float[] values, int offset, int length) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
ensureBufferCapacity(length << 2);
floatBuffer.clear();
BufferUtils.copy(values, floatBuffer, length, offset);
gl.glUniform2fv(location, length / 2, floatBuffer);
}
public void setUniform2fv (int location, float[] values, int offset, int length) {
GL20 gl = App.getGL20();
checkManaged();
ensureBufferCapacity(length << 2);
floatBuffer.clear();
BufferUtils.copy(values, floatBuffer, length, offset);
gl.glUniform2fv(location, length / 2, floatBuffer);
}
public void setUniform2fv (HandleInfo handle, float[] values, int offset, int length) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniform2fv(location, values, offset, length);
}
public void setUniform3fv (String name, float[] values, int offset, int length) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
ensureBufferCapacity(length << 2);
floatBuffer.clear();
BufferUtils.copy(values, floatBuffer, length, offset);
gl.glUniform3fv(location, length / 3, floatBuffer);
}
public void setUniform3fv (int location, float[] values, int offset, int length) {
GL20 gl = App.getGL20();
checkManaged();
ensureBufferCapacity(length << 2);
floatBuffer.clear();
BufferUtils.copy(values, floatBuffer, length, offset);
gl.glUniform3fv(location, length / 3, floatBuffer);
}
public void setUniform3fv (HandleInfo handle, float[] values, int offset, int length) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniform3fv(location, values, offset, length);
}
public void setUniform4fv (String name, float[] values, int offset, int length) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
ensureBufferCapacity(length << 2);
floatBuffer.clear();
BufferUtils.copy(values, floatBuffer, length, offset);
gl.glUniform4fv(location, length / 4, floatBuffer);
}
public void setUniform4fv (int location, float[] values, int offset, int length) {
GL20 gl = App.getGL20();
checkManaged();
ensureBufferCapacity(length << 2);
floatBuffer.clear();
BufferUtils.copy(values, floatBuffer, length, offset);
gl.glUniform4fv(location, length / 4, floatBuffer);
}
public void setUniform4fv (HandleInfo handle, float[] values, int offset, int length) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniform4fv(location, values, offset, length);
}
/** Sets the uniform matrix with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param matrix the matrix */
public void setUniformMatrix (String name, Matrix4 matrix) {
setUniformMatrix(name, matrix, false);
}
/** Sets the uniform matrix with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param matrix the matrix
* @param transpose whether the matrix shouls be transposed */
public void setUniformMatrix (String name, Matrix4 matrix, boolean transpose) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
this.matrix.clear();
BufferUtils.copy(matrix.val, this.matrix, matrix.val.length, 0);
gl.glUniformMatrix4fv(location, 1, transpose, this.matrix);
}
public void setUniformMatrix (int location, Matrix4 matrix) {
setUniformMatrix(location, matrix, false);
}
public void setUniformMatrix (HandleInfo handle, Matrix4 matrix) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniformMatrix(location, matrix, false);
}
public void setUniformMatrix (int location, Matrix4 matrix, boolean transpose) {
GL20 gl = App.getGL20();
checkManaged();
this.matrix.clear();
BufferUtils.copy(matrix.val, this.matrix, matrix.val.length, 0);
gl.glUniformMatrix4fv(location, 1, transpose, this.matrix);
}
public void setUniformMatrix (HandleInfo handle, Matrix4 matrix, boolean transpose) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniformMatrix(location, matrix, transpose);
}
/** Sets the uniform matrix with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param matrix the matrix */
public void setUniformMatrix (String name, Matrix3 matrix) {
setUniformMatrix(name, matrix, false);
}
/** Sets the uniform matrix with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param matrix the matrix
* @param transpose whether the uniform matrix should be transposed */
public void setUniformMatrix (String name, Matrix3 matrix, boolean transpose) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchUniformLocation(name);
float[] vals = matrix.getValues();
this.matrix.clear();
BufferUtils.copy(vals, this.matrix, vals.length, 0);
gl.glUniformMatrix3fv(location, 1, transpose, this.matrix);
}
public void setUniformMatrix (int location, Matrix3 matrix) {
setUniformMatrix(location, matrix, false);
}
public void setUniformMatrix (HandleInfo handle, Matrix3 matrix) {
setUniformMatrix(handle, matrix, false);
}
public void setUniformMatrix (int location, Matrix3 matrix, boolean transpose) {
GL20 gl = App.getGL20();
checkManaged();
float[] vals = matrix.getValues();
this.matrix.clear();
BufferUtils.copy(vals, this.matrix, vals.length, 0);
gl.glUniformMatrix3fv(location, 1, transpose, this.matrix);
}
public void setUniformMatrix (HandleInfo handle, Matrix3 matrix, boolean transpose) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniformMatrix(location, matrix, transpose);
}
/** Sets an array of uniform matrices with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param buffer buffer containing the matrix data
* @param transpose whether the uniform matrix should be transposed */
public void setUniformMatrix3fv (String name, FloatBuffer buffer, int count, boolean transpose) {
GL20 gl = App.getGL20();
checkManaged();
buffer.position(0);
int location = fetchUniformLocation(name);
gl.glUniformMatrix3fv(location, count, transpose, buffer);
}
/** Sets an array of uniform matrices with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param buffer buffer containing the matrix data
* @param transpose whether the uniform matrix should be transposed */
public void setUniformMatrix4fv (String name, FloatBuffer buffer, int count, boolean transpose) {
GL20 gl = App.getGL20();
checkManaged();
buffer.position(0);
int location = fetchUniformLocation(name);
gl.glUniformMatrix4fv(location, count, transpose, buffer);
}
public void setUniformMatrix4fv (int location, float[] values, int offset, int length) {
GL20 gl = App.getGL20();
checkManaged();
ensureBufferCapacity(length << 2);
floatBuffer.clear();
BufferUtils.copy(values, floatBuffer, length, offset);
gl.glUniformMatrix4fv(location, length / 16, false, floatBuffer);
}
public void setUniformMatrix4fv (String name, float[] values, int offset, int length) {
GL20 gl = App.getGL20();
checkManaged();
ensureBufferCapacity(length << 2);
floatBuffer.clear();
BufferUtils.copy(values, floatBuffer, length, offset);
int location = fetchUniformLocation(name);
gl.glUniformMatrix4fv(location, length / 16, false, floatBuffer);
}
public void setUniformMatrix4fv (HandleInfo handle, float[] values, int offset, int length) {
checkManaged();
int location = fetchUniformLocation(handle);
setUniformMatrix4fv (location, values, offset, length);
}
/** Sets the uniform with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param values x and y as the first and second values respectively */
public void setUniformf (String name, Vector2 values) {
setUniformf(name, values.x, values.y);
}
public void setUniformf (int location, Vector2 values) {
setUniformf(location, values.x, values.y);
}
public void setUniformf (HandleInfo handle, Vector2 values) {
setUniformf(handle, values.x, values.y);
}
/** Sets the uniform with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param values x, y and z as the first, second and third values respectively */
public void setUniformf (String name, Vector3 values) {
setUniformf(name, values.x, values.y, values.z);
}
public void setUniformf (int location, Vector3 values) {
setUniformf(location, values.x, values.y, values.z);
}
public void setUniformf (HandleInfo handle, Vector3 values) {
setUniformf(handle, values.x, values.y, values.z);
}
/** Sets the uniform with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the name of the uniform
* @param values r, g, b and a as the first through fourth values respectively */
public void setUniformf (String name, Color values) {
setUniformf(name, values.r, values.g, values.b, values.a);
}
public void setUniformf (int location, Color values) {
setUniformf(location, values.r, values.g, values.b, values.a);
}
public void setUniformf (HandleInfo handle, Color values) {
setUniformf(handle, values.r, values.g, values.b, values.a);
}
/** Sets the vertex attribute with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the attribute name
* @param size the number of components, must be >= 1 and <= 4
* @param type the type, must be one of GL20.GL_BYTE, GL20.GL_UNSIGNED_BYTE, GL20.GL_SHORT,
* GL20.GL_UNSIGNED_SHORT,GL20.GL_FIXED, or GL20.GL_FLOAT. GL_FIXED will not work on the desktop
* @param normalize whether fixed point data should be normalized. Will not work on the desktop
* @param stride the stride in bytes between successive attributes
* @param buffer the buffer containing the vertex attributes. */
public void setVertexAttribute (String name, int size, int type, boolean normalize, int stride, Buffer buffer) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchAttributeLocation(name);
if (location == -1) return;
gl.glVertexAttribPointer(location, size, type, normalize, stride, buffer);
}
public void setVertexAttribute (int location, int size, int type, boolean normalize, int stride, Buffer buffer) {
GL20 gl = App.getGL20();
checkManaged();
gl.glVertexAttribPointer(location, size, type, normalize, stride, buffer);
}
public void setVertexAttribute (HandleInfo handle, int size, int type, boolean normalize, int stride, Buffer buffer) {
checkManaged();
int location = fetchAttributeLocation(handle);
setVertexAttribute (location, size, type, normalize, stride, buffer);
}
/** Sets the vertex attribute with the given name. Throws an IllegalArgumentException in case it is not called in between a
* {@link #begin()}/{@link #end()} block.
*
* @param name the attribute name
* @param size the number of components, must be >= 1 and <= 4
* @param type the type, must be one of GL20.GL_BYTE, GL20.GL_UNSIGNED_BYTE, GL20.GL_SHORT,
* GL20.GL_UNSIGNED_SHORT,GL20.GL_FIXED, or GL20.GL_FLOAT. GL_FIXED will not work on the desktop
* @param normalize whether fixed point data should be normalized. Will not work on the desktop
* @param stride the stride in bytes between successive attributes
* @param offset byte offset into the vertex buffer object bound to GL20.GL_ARRAY_BUFFER. */
public void setVertexAttribute (String name, int size, int type, boolean normalize, int stride, int offset) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchAttributeLocation(name);
if (location == -1) return;
gl.glVertexAttribPointer(location, size, type, normalize, stride, offset);
}
public void setVertexAttribute (int location, int size, int type, boolean normalize, int stride, int offset) {
GL20 gl = App.getGL20();
checkManaged();
gl.glVertexAttribPointer(location, size, type, normalize, stride, offset);
}
public void setVertexAttribute (HandleInfo handle, int size, int type, boolean normalize, int stride, int offset) {
checkManaged();
int location = fetchAttributeLocation(handle);
setVertexAttribute(location, size, type, normalize, stride, offset);
}
/** Disposes all resources associated with this shader. Must be called when the shader is no longer used. */
public void dispose () {
GL20 gl = App.getGL20();
gl.glDeleteShader(vertexShaderHandle);
gl.glDeleteShader(fragmentShaderHandle);
gl.glDeleteProgram(program);
isCompiled = false;
}
/** Disables the vertex attribute with the given name
*
* @param name the vertex attribute name */
public void disableVertexAttribute (String name) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchAttributeLocation(name);
if (location == -1) return;
gl.glDisableVertexAttribArray(location);
}
public void disableVertexAttribute (int location) {
GL20 gl = App.getGL20();
checkManaged();
gl.glDisableVertexAttribArray(location);
}
public void disableVertexAttribute (HandleInfo handle) {
checkManaged();
int location = fetchAttributeLocation(handle);
disableVertexAttribute(location);
}
/** Enables the vertex attribute with the given name
*
* @param name the vertex attribute name */
public void enableVertexAttribute (String name) {
GL20 gl = App.getGL20();
checkManaged();
int location = fetchAttributeLocation(name);
if (location == -1) return;
gl.glEnableVertexAttribArray(location);
}
public void enableVertexAttribute (int location) {
GL20 gl = App.getGL20();
checkManaged();
gl.glEnableVertexAttribArray(location);
}
public void enableVertexAttribute (HandleInfo handle) {
checkManaged();
int location = fetchAttributeLocation(handle);
enableVertexAttribute (location);
}
private void checkManaged () {
if (invalidated) {
compileShaders(vertexShaderSource, fragmentShaderSource);
invalidated = false;
}
}
/** Sets the given attribute
*
* @param name the name of the attribute
* @param value1 the first value
* @param value2 the second value
* @param value3 the third value
* @param value4 the fourth value */
public void setAttributef (String name, float value1, float value2, float value3, float value4) {
GL20 gl = App.getGL20();
int location = fetchAttributeLocation(name);
gl.glVertexAttrib4f(location, value1, value2, value3, value4);
}
private void ensureBufferCapacity (int numBytes) {
if (buffer == null || buffer.capacity() < numBytes) {
buffer = BufferUtils.newByteBuffer(numBytes);
floatBuffer = buffer.asFloatBuffer();
intBuffer = buffer.asIntBuffer();
}
}
IntBuffer params = BufferUtils.newIntBuffer(1);
IntBuffer type = BufferUtils.newIntBuffer(1);
static final int[] lengthArray = new int[1];
static final int[] sizeArray = new int[1];
static final int[] typeArray = new int[1];
static final byte[] nameArray = new byte[500];
private void fetchUniforms () {
params.clear();
App.getGL20().glGetProgramiv(program, GL20.GL_ACTIVE_UNIFORMS, params);
int numUniforms = params.get(0);
uniformNames = new String[numUniforms];
for (int i = 0; i < numUniforms; i++) {
String name = getActiveUniform(i);
int location = App.getGL20().glGetUniformLocation(program, name);
uniforms.put(name, location);
uniformTypes.put(name, type.get(0));
uniformSizes.put(name, params.get(0));
uniformNames[i] = name;
}
}
private String getActiveUniform(int index) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
params.clear();
params.put(0, 1);
type.clear();
String name = App.getGL20().glGetActiveUniform(program, index, params, type);
return name;
} else {
params.clear();
type.clear();
App.getGL20().glGetActiveUniform(program, index, 500, lengthArray, 0, sizeArray, 0, typeArray, 0, nameArray, 0);
String name = new String(nameArray, 0, lengthArray[0]);
type.put(0, typeArray[0]);
params.put(0, sizeArray[0]);
return name;
}
}
private void fetchAttributes () {
params.clear();
App.getGL20().glGetProgramiv(program, GL20.GL_ACTIVE_ATTRIBUTES, params);
int numAttributes = params.get(0);
attributeNames = new String[numAttributes];
for (int i = 0; i < numAttributes; i++) {
String name = getActiveAttrib(i);
int location = App.getGL20().glGetAttribLocation(program, name);
attributes.put(name, location);
attributeTypes.put(name, type.get(0));
attributeSizes.put(name, params.get(0));
attributeNames[i] = name;
}
}
private String getActiveAttrib(int index) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
params.clear();
params.put(0, 1);
type.clear();
String name = App.getGL20().glGetActiveAttrib(program, index, params, type);
return name;
} else {
params.clear();
type.clear();
App.getGL20().glGetActiveAttrib(program, index, 200, lengthArray, 0, sizeArray, 0, typeArray, 0, nameArray, 0);
String name = new String(nameArray, 0, lengthArray[0]);
type.put(0, typeArray[0]);
params.put(0, sizeArray[0]);
return name;
}
}
/** @param name the name of the attribute
* @return whether the attribute is available in the shader */
public boolean hasAttribute (String name) {
return attributes.containsKey(name);
}
/** @param name the name of the attribute
* @return the type of the attribute, one of {@link GL20#GL_FLOAT}, {@link GL20#GL_FLOAT_VEC2} etc. */
public int getAttributeType (String name) {
return attributeTypes.get(name, 0);
}
/** @param name the name of the attribute
* @return the location of the attribute or -1. */
public int getAttributeLocation (String name) {
return attributes.get(name, -1);
}
/** @param name the name of the attribute
* @return the size of the attribute or 0. */
public int getAttributeSize (String name) {
return attributeSizes.get(name, 0);
}
/** @param name the name of the uniform
* @return whether the uniform is available in the shader */
public boolean hasUniform (String name) {
return uniforms.containsKey(name);
}
/** @param name the name of the uniform
* @return the type of the uniform, one of {@link GL20#GL_FLOAT}, {@link GL20#GL_FLOAT_VEC2} etc. */
public int getUniformType (String name) {
return uniformTypes.get(name, 0);
}
/** @param name the name of the uniform
* @return the location of the uniform or -1. */
public int getUniformLocation (String name) {
return uniforms.get(name, -1);
}
/** @param name the name of the uniform
* @return the size of the uniform or 0. */
public int getUniformSize (String name) {
return uniformSizes.get(name, 0);
}
/** @return the attributes */
public String[] getAttributes () {
return attributeNames;
}
/** @return the uniforms */
public String[] getUniforms () {
return uniformNames;
}
/**
* @return the source of the vertex shader
*/
public String getVertexShaderSource() {
return vertexShaderSource;
}
/**
* @return the source of the fragment shader
*/
public String getFragmentShaderSource() {
return fragmentShaderSource;
}
static public class HandleInfo{
public String name;
public static final int INVALID = -1;
public int location = INVALID;
public boolean checkLocationValid(){
return location == INVALID ? false : true;
}
public HandleInfo(String name){
this.name = name;
}
public void setInvalide(){
this.location = INVALID;
}
}
}