/**
* This package provides classes to facilitate the handling of opengl textures, glsl shaders and
* off-screen rendering in Processing.
* @author Andres Colubri
* @version 0.9.1
*
* Copyright (c) 2008 Andres Colubri
*
* This source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This code is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* A copy of the GNU General Public License is available on the World
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also
* obtain it by writing to the Free Software Foundation,
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package codeanticode.glgraphics;
import processing.core.*;
import processing.opengl.*;
import javax.media.opengl.*;
import com.sun.opengl.util.*;
import java.io.IOException;
import java.net.URL;
import java.nio.*;
// ToDo:
// Add support for CG shaders (they work on Intel X3100 GPUs).
// Define an abstract base GLShader from which GLSLShader and GLCGShader class are derived.
/**
* This class encapsulates a glsl shader. Based in the code by JohnG (http://www.hardcorepawn.com/)
*/
public class GLSLShader
{
/**
* Creates an instance of GLSLShader.
* @param parent PApplet
*/
public GLSLShader(PApplet parent)
{
this.parent = parent;
pgl = (PGraphicsOpenGL)parent.g;
gl = pgl.gl;
programObject = gl.glCreateProgramObjectARB();
vertexShader = -1;
geometryShader = -1;
fragmentShader = -1;
}
/**
* Loads and compiles the vertex shader contained in file.
* @param file String
*/
public void loadVertexShader(String file)
{
String shaderSource = PApplet.join(parent.loadStrings(file), "\n");
attachVertexShader(shaderSource, file);
}
/**
* Loads and compiles the vertex shader contained in the URL.
* @param file String
*/
public void loadVertexShader(URL url)
{
String shaderSource;
try {
shaderSource = PApplet.join(PApplet.loadStrings(url.openStream()),"\n");
attachVertexShader(shaderSource, url.getFile());
} catch (IOException e) {
System.err.println("Cannot load file " + url.getFile() );
}
}
/**
* @invisible
* @param shaderSource a string containing the shader's code
* @param filename the shader's filename, used to print error log information
*/
private void attachVertexShader(String shaderSource, String file)
{
vertexShader = gl.glCreateShaderObjectARB(GL.GL_VERTEX_SHADER_ARB);
gl.glShaderSourceARB(vertexShader, 1, new String[]{shaderSource}, (int[]) null, 0);
gl.glCompileShaderARB(vertexShader);
checkLogInfo("Vertex shader " + file + " compilation: ", vertexShader);
gl.glAttachObjectARB(programObject, vertexShader);
}
/**
* Loads and compiles the geometry shader contained in file.
* @param file String
*/
public void loadGeometryShader(String file)
{
String shaderSource = PApplet.join(parent.loadStrings(file), "\n");
attachGeometryShader(shaderSource, file);
}
/**
* Loads and compiles the geometry shader contained in the URL
* @param url URL
*/
public void loadGeometryShader(URL url)
{
String shaderSource;
try {
shaderSource = PApplet.join(PApplet.loadStrings(url.openStream()),"\n");
attachGeometryShader(shaderSource, url.getFile());
} catch (IOException e) {
System.err.println("Cannot load file " + url.getFile() );
}
}
/**
* @invisible
* @param shaderSource a string containing the shader's code
* @param filename the shader's filename, used to print error log information
*/
private void attachGeometryShader(String shaderSource, String file)
{
geometryShader = gl.glCreateShaderObjectARB(GL.GL_GEOMETRY_SHADER_EXT);
gl.glShaderSourceARB(geometryShader, 1, new String[]{shaderSource},(int[]) null, 0);
gl.glCompileShaderARB(geometryShader);
checkLogInfo("Geometry shader " + file + " compilation: ", geometryShader);
gl.glAttachObjectARB(geometryShader, geometryShader);
}
/**
* Loads and compiles the fragment shader contained in file.
* @param file String
*/
public void loadFragmentShader(String file)
{
String shaderSource = PApplet.join(parent.loadStrings(file), "\n");
attachFragmentShader(shaderSource, file);
}
/**
* Loads and compiles the fragment shader contained in the URL.
* @param url URL
*/
public void loadFragmentShader(URL url)
{
String shaderSource;
try {
shaderSource = PApplet.join(PApplet.loadStrings(url.openStream()),"\n");
attachFragmentShader(shaderSource, url.getFile());
} catch (IOException e) {
System.err.println("Cannot load file " + url.getFile() );
}
}
/**
* @invisible
* @param shaderSource a string containing the shader's code
* @param filename the shader's filename, used to print error log information
*/
private void attachFragmentShader(String shaderSource, String file)
{
fragmentShader = gl.glCreateShaderObjectARB(GL.GL_FRAGMENT_SHADER_ARB);
gl.glShaderSourceARB(fragmentShader, 1, new String[]{shaderSource},(int[]) null, 0);
gl.glCompileShaderARB(fragmentShader);
checkLogInfo("Fragment shader " + file + " compilation: ", fragmentShader);
gl.glAttachObjectARB(programObject, fragmentShader);
}
/**
* Returns the ID location of the attribute parameter given its name.
* @param name String
* @return int
*/
public int getAttribLocation(String name)
{
return(gl.glGetAttribLocationARB(programObject, name));
}
/**
* Returns the ID location of the uniform parameter given its name.
* @param name String
* @return int
*/
public int getUniformLocation(String name)
{
return(gl.glGetUniformLocationARB(programObject, name));
}
/**
* Configures the geometry shader by setting the primitive types that it will take as input
* and return as output, and the maximum number of vertices that will generate. This method
* needs to be called after creating the geometry shader and before linking the program.
* @param inGeoPrim String
* @param outGeoPrim String
* @param maxNumOutVert int
*/
public void setupGeometryShader(String inGeoPrim, String outGeoPrim, int maxNumOutVert)
{
// Setting up the geometry shader.
int inGeo = GLUtils.parsePrimitiveType(inGeoPrim);
int outGeo = GLUtils.parsePrimitiveType(outGeoPrim);
// First, what type of primitive this shader will accept.
gl.glProgramParameteriEXT(programObject, GL.GL_GEOMETRY_INPUT_TYPE_EXT, inGeo);
// Second, what type of primitive this shader will output.
gl.glProgramParameteriEXT(programObject, GL.GL_GEOMETRY_OUTPUT_TYPE_EXT, outGeo);
// Third, setting the maximum number of vertices that the shader can output.
// Using the maximum allowed value if the parameter is 0 or invalid.
IntBuffer buf = IntBuffer.allocate(1);
int n;
gl.glGetIntegerv(GL.GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, buf);
n = buf.get(0);
if ((0 < maxNumOutVert) && (maxNumOutVert < n)) n = maxNumOutVert;
gl.glProgramParameteriEXT(programObject, GL.GL_GEOMETRY_VERTICES_OUT_EXT, n);
}
/**
* Links the shader program and validates it.
*/
public void linkProgram()
{
gl.glLinkProgramARB(programObject);
gl.glValidateProgramARB(programObject);
checkLogInfo("GLSL program validation: ", programObject);
}
/**
* Starts the execution of the shader program.
*/
public void start()
{
gl.glUseProgramObjectARB(programObject);
}
/**
* Stops the execution of the shader program.
*/
public void stop()
{
gl.glUseProgramObjectARB(0);
}
/**
* @invisible
* Check the log error for the opengl object obj. Prints error message if needed.
*/
protected void checkLogInfo(String title, int obj)
{
IntBuffer iVal = BufferUtil.newIntBuffer(1);
gl.glGetObjectParameterivARB(obj, GL.GL_OBJECT_INFO_LOG_LENGTH_ARB, iVal);
int length = iVal.get();
if (length <= 1)
{
return;
}
// Some error ocurred...
ByteBuffer infoLog = BufferUtil.newByteBuffer(length);
iVal.flip();
gl.glGetInfoLogARB(obj, length, iVal, infoLog);
byte[] infoBytes = new byte[length];
infoLog.get(infoBytes);
System.err.println(title);
System.err.println(new String(infoBytes));
}
/**
* @invisible
*/
protected PApplet parent;
/**
* @invisible
*/
protected GL gl;
/**
* @invisible
*/
protected PGraphicsOpenGL pgl;
/**
* @invisible
*/
protected int programObject;
/**
* @invisible
*/
protected int vertexShader;
/**
* @invisible
*/
protected int geometryShader;
/**
* @invisible
*/
protected int fragmentShader;
}