package com.mbien.engine.glsl; import java.util.ArrayList; import java.util.logging.Logger; import javax.media.opengl.GL; import javax.media.opengl.GL2GL3; /** * Created on 27. August 2006, 13:40 * @author Michael Bien */ public class GLSLProgram { private int handle = -1; private final ArrayList<GLSLShader> shaders; /** Creates a new instance of GLSLProgram */ public GLSLProgram() { shaders = new ArrayList<GLSLShader>(); } public void createProgram(GL2GL3 gl) { handle = gl.glCreateProgram(); } /** * creates a program, attaches all shaders to it and finally links the shaders */ public void initProgram(GL2GL3 gl, GLSLShader... shaders) throws GLSLLinkException { this.shaders.clear(); if(handle == -1) createProgram(gl); for(int i = 0; i < shaders.length; i++) attachShader(gl, shaders[i]); linkProgram(gl); checkProgram(gl); } /** * deletes the program * @param deleteShaders - if true all previously attached shaders will be deleted too */ public void deinitProgram(GL2GL3 gl, boolean deleteShaders) { gl.glDeleteProgram(handle); if(deleteShaders) { while(!shaders.isEmpty()) shaders.remove(0).deleteShader(gl); } handle = -1; } public void attachShader(GL2GL3 gl, GLSLShader shader) { gl.glAttachShader(handle, shader.getID()); // mark shader to delete; this will be done if the program will be deleted by the application // TODO test detach behavior if marked as delete //gl.glDeleteObjectARB(shader.getID()); shaders.add(shader); } public void detachShader(GL2GL3 gl, GLSLShader shader) { gl.glDetachShader(handle, shader.getID()); shaders.remove(shader); } public void linkProgram(GL2GL3 gl) { gl.glLinkProgram(handle); } public int allocateUniform(GL2GL3 gl, String name) { int uniform = gl.glGetUniformLocation(handle, name); if(uniform == -1){ getLog().severe("uniform "+name+" not found in program"); throw new IllegalArgumentException(); } return uniform; } /** * enables this shader program */ public void enable(GL2GL3 gl) { gl.glUseProgram(handle); } /** * returns to GL2 fixed function pipeline (shader is disabled) */ public void disable(GL2GL3 gl) { gl.glUseProgram(0); } public void checkProgram(GL2GL3 gl) throws GLSLLinkException { boolean linked = true; boolean valid = true; int[] buffer = new int[1]; // check link status gl.glGetProgramiv(handle, GL2GL3.GL_LINK_STATUS, buffer, 0); if(buffer[0] == GL.GL_FALSE) {// 1 or 0 linked = false; // getLog().warning("error linking program"); } // validate program gl.glValidateProgram(handle); gl.glGetProgramiv(handle, GL2GL3.GL_VALIDATE_STATUS, buffer, 0); if(buffer[0] == GL.GL_FALSE) { valid = false; // getLog().warning("program validation reports error"); } // dump log gl.glGetProgramiv(handle, GL2GL3.GL_INFO_LOG_LENGTH, buffer, 0); byte[] log = new byte[buffer[0]]; gl.glGetProgramInfoLog(handle, buffer[0], buffer, 0, log, 0); // if(log[0] != 0) // 0 if empty // getLog().warning("linker info log:\n"+new String(log)); if(!linked || !valid) { ArrayList<String> allNames = new ArrayList<String>(); for(int i = 0; i < shaders.size(); i++) { GLSLShader shader = shaders.get(i); for(int n = 0; n < shader.shaderNames.length; n++) allNames.add(shader.shaderNames[n]); } throw new GLSLLinkException(this, new String(log, 0, log.length-1).split("\n")); } } private final Logger getLog() { return Logger.getLogger(this.getClass().getPackage().getName()); } public GLSLShader[] getShaders() { return shaders.toArray(new GLSLShader[shaders.size()]); } }