/**
* Copyright (C) 2012 J.W.Marsden <jmarsden@plural.cc>
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package cc.plural.graphics;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL20;
/**
* @deprecated
*/
public class ShaderProgram {
boolean compiled;
String vertexShaderSource;
String fragmentShaderSource;
int vertexShaderHandle = -1;
int fragmentShaderHandle = -1;
int programHandle = -1;
String[] attributeNames;
List<ShaderProperty> shaderAttributes;
String[] uniformNames;
List<ShaderProperty> shaderUniforms;
public static final String DEFAULT_VERTEX_SHADER = "#version 120\r\n"
+ "\r\n"
+ "uniform mat4 projectionMatrix;\r\n"
+ "uniform mat4 viewMatrix;\r\n"
+ "uniform mat4 modelMatrix;\r\n"
+ "\r\n"
+ "in vec4 in_Position;\r\n"
+ "in vec4 in_Color;\r\n"
+ "in vec2 in_TextureCoord;\r\n"
+ "\r\n"
+ "out vec4 pass_Color;\r\n"
+ "out vec2 pass_TextureCoord;\r\n"
+ "\r\n"
+ "void main() {\r\n"
+ " gl_Position = in_Position;\r\n"
+ " gl_Position = projectionMatrix * viewMatrix * modelMatrix * in_Position;\r\n"
+ " \r\n"
+ " pass_Color = in_Color;\r\n"
+ " pass_TextureCoord = in_TextureCoord;\r\n"
+ "}\r\n";
public static final String DEFAULT_FRAGMENT_SHADER = "#version 120\r\n"
+ "\r\n"
+ "uniform sampler2D textureDiffuse;\r\n"
+ "\r\n"
+ "in vec4 pass_Color;\r\n"
+ "in vec2 pass_TextureCoord;\r\n"
+ "\r\n"
+ "out vec4 out_Color;\r\n"
+ "\r\n"
+ "void main() {\r\n"
+ " out_Color = pass_Color;\r\n"
+ " out_Color = texture2D(textureDiffuse, pass_TextureCoord);\r\n"
+ "}\r\n";
public ShaderProgram() {
compiled = false;
shaderAttributes = null;
shaderUniforms = null;
}
/**
* @return the programHandle
*/
public int getProgramHandle() {
return programHandle;
}
public int createShaderProgram(String vertexShaderSource, String fragmentShaderSource) {
this.vertexShaderSource = vertexShaderSource;
this.fragmentShaderSource = fragmentShaderSource;
// TODO: if already made then clean up before remake.
vertexShaderHandle = compileShader(GL20.GL_VERTEX_SHADER, vertexShaderSource);
fragmentShaderHandle = compileShader(GL20.GL_FRAGMENT_SHADER, fragmentShaderSource);
programHandle = GL20.glCreateProgram();
if(programHandle == 0) {
throw new NullPointerException("Program Create Error?");
}
GL20.glAttachShader(programHandle, vertexShaderHandle);
GL20.glAttachShader(programHandle, fragmentShaderHandle);
GL20.glLinkProgram(programHandle);
ByteBuffer tmp = ByteBuffer.allocateDirect(4);
tmp.order(ByteOrder.nativeOrder());
IntBuffer result = tmp.asIntBuffer();
GL20.glGetProgram(programHandle, GL20.GL_LINK_STATUS, result);
int linked = result.get(0);
if(linked == 0) {
System.out.println("Error with shader Compile:\r\n" + GL20.glGetProgramInfoLog(programHandle, 100));
return -1;
}
compiled = true;
identifyAttributes();
identifyUniforms();
return programHandle;
}
public int createDefaultShaderProgram() {
return createShaderProgram(DEFAULT_VERTEX_SHADER, DEFAULT_FRAGMENT_SHADER);
}
private int compileShader(int type, String shader) {
IntBuffer result = BufferUtils.createIntBuffer(1);
programHandle = GL20.glCreateShader(type);
GL20.glShaderSource(programHandle, shader);
GL20.glCompileShader(programHandle);
GL20.glGetShader(programHandle, GL20.GL_COMPILE_STATUS, result);
int compiledResult = result.get(0);
if(compiledResult == 0) {
System.out.println("Error with shader Compile:\r\n" + GL20.glGetShaderInfoLog(vertexShaderHandle, 100));
}
return programHandle;
}
private void identifyAttributes() {
IntBuffer result = BufferUtils.createIntBuffer(1);
IntBuffer type = BufferUtils.createIntBuffer(2);
GL20.glGetProgram(programHandle, GL20.GL_ACTIVE_ATTRIBUTES, result);
int numAttributes = result.get(0);
attributeNames = new String[numAttributes];
shaderAttributes = new ArrayList<ShaderProperty>(numAttributes);
for(int i = 0; i < numAttributes; i++) {
//result.clear();
//result.put(0, 256);
type.clear();
String name = GL20.glGetActiveAttrib(programHandle, i, 100, type);
int location = GL20.glGetAttribLocation(programHandle, name);
ShaderProperty attribute = new ShaderProperty(location, type.get(0), name);
shaderAttributes.add(attribute);
attributeNames[i] = name;
}
}
private void identifyUniforms() {
IntBuffer result = BufferUtils.createIntBuffer(1);
IntBuffer type = BufferUtils.createIntBuffer(2);
GL20.glGetProgram(programHandle, GL20.GL_ACTIVE_UNIFORMS, result);
int numUniforms = result.get(0);
uniformNames = new String[numUniforms];
shaderUniforms = new ArrayList<ShaderProperty>(numUniforms);
for(int i = 0; i < numUniforms; i++) {
type.clear();
String name = GL20.glGetActiveUniform(programHandle, i, 100, type);
int location = GL20.glGetUniformLocation(programHandle, name);
ShaderProperty attribute = new ShaderProperty(location, type.get(0), name);
shaderUniforms.add(attribute);
uniformNames[i] = name;
}
}
public boolean hasUnform(String name) {
boolean found = false;
for(int i = 0; i < uniformNames.length; i++) {
if(uniformNames[i].equals(name)) {
found = true;
break;
}
}
return found;
}
public int getUnformLocation(String name) {
int location = -1;
for(int i = 0; i < uniformNames.length; i++) {
if(uniformNames[i].equals(name)) {
location = i;
break;
}
}
return location;
}
public void setUniformMatrix4f(String name, boolean transpose, FloatBuffer bufferMatrix) {
if(!hasUnform(name)) {
throw new RuntimeException("No Uniform " + name);
}
GL20.glUniformMatrix4(getUnformLocation(name), transpose, bufferMatrix);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("ShaderProgram:\r\n");
builder.append("=== Vertex Shader Begin ===\r\n\t");
builder.append(vertexShaderSource.replace("\n", "\n\t"));
builder.append("\r\n=== Vertex Shader End ===\r\n");
builder.append("=== Fragment Shader Begin ===\r\n\t");
builder.append(fragmentShaderSource.replace("\n", "\n\t"));
builder.append("\r\n=== Fragment Shader End ===\r\n");
builder.append("=== Vertex Attributes ===\r\n");
if(shaderAttributes != null) {
for(ShaderProperty prop : shaderAttributes) {
builder.append("\t").append(prop).append("\r\n");
}
}
builder.append("=== Uniforms ===\r\n");
if(shaderUniforms != null) {
for(ShaderProperty prop : shaderUniforms) {
builder.append("\t").append(prop).append("\r\n");
}
}
return builder.toString();
}
/**
* Disposes all resources associated with this shader. Must be called when the shader is no longer used.
*/
public void dispose() {
/*
* GL20 gl = Gdx.graphics.getGL20();
* gl.glUseProgram(0);
* gl.glDeleteShader(vertexShaderHandle);
* gl.glDeleteShader(fragmentShaderHandle);
* gl.glDeleteProgram(program);
* if (shaders.get(Gdx.app) != null) shaders.get(Gdx.app).remove(this);
*/
}
}