Back to project page Processing-Android-Eclipse-Demos.
The source code is released under:
MIT License
If you think the Android project Processing-Android-Eclipse-Demos listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */ //w w w . j a v a 2 s . c om /* Part of the Processing project - http://processing.org Copyright (c) 2011-13 Ben Fry and Casey Reas This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.processing.opengl; import java.net.URL; import java.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.HashMap; import com.processing.core.*; /** * This class encapsulates a GLSL shader program, including a vertex * and a fragment shader. Based on the GLSLShader class from GLGraphics, which * in turn was originally based in the code by JohnG: * http://processing.org/discourse/beta/num_1159494801.html * * @webref rendering:shaders */ public class PShader implements PConstants { static protected final int POINT = 0; static protected final int LINE = 1; static protected final int POLY = 2; static protected final int COLOR = 3; static protected final int LIGHT = 4; static protected final int TEXTURE = 5; static protected final int TEXLIGHT = 6; static protected String pointShaderAttrRegexp = "attribute *vec2 *offset"; static protected String lineShaderAttrRegexp = "attribute *vec4 *direction"; static protected String pointShaderDefRegexp = "#define *PROCESSING_POINT_SHADER"; static protected String lineShaderDefRegexp = "#define *PROCESSING_LINE_SHADER"; static protected String colorShaderDefRegexp = "#define *PROCESSING_COLOR_SHADER"; static protected String lightShaderDefRegexp = "#define *PROCESSING_LIGHT_SHADER"; static protected String texShaderDefRegexp = "#define *PROCESSING_TEXTURE_SHADER"; static protected String texlightShaderDefRegexp = "#define *PROCESSING_TEXLIGHT_SHADER"; static protected String polyShaderDefRegexp = "#define *PROCESSING_POLYGON_SHADER"; static protected String triShaderAttrRegexp = "#define *PROCESSING_TRIANGLES_SHADER"; static protected String quadShaderAttrRegexp = "#define *PROCESSING_QUADS_SHADER"; protected PApplet parent; // The main renderer associated to the parent PApplet. //protected PGraphicsOpenGL pgMain; // We need a reference to the renderer since a shader might // be called by different renderers within a single application // (the one corresponding to the main surface, or other offscreen // renderers). protected PGraphicsOpenGL pg; protected PGL pgl; protected int context; // The context that created this shader. // The shader type: POINT, LINE, POLY, etc. protected int type; public int glProgram; public int glVertex; public int glFragment; protected URL vertexURL; protected URL fragmentURL; protected String vertexFilename; protected String fragmentFilename; protected String[] vertexShaderSource; protected String[] fragmentShaderSource; protected boolean bound; protected HashMap<Integer, UniformValue> uniformValues = null; protected HashMap<Integer, Texture> textures; protected HashMap<Integer, Integer> texUnits; // Direct buffers to pass shader data to GL protected IntBuffer intBuffer; protected FloatBuffer floatBuffer; // Uniforms common to all shader types protected int transformMatLoc; protected int modelviewMatLoc; protected int projectionMatLoc; protected int bufferLoc; protected int bufferUnit; protected int viewportLoc; // Uniforms only for lines and points protected int perspectiveLoc; protected int scaleLoc; // Lighting uniforms protected int lightCountLoc; protected int lightPositionLoc; protected int lightNormalLoc; protected int lightAmbientLoc; protected int lightDiffuseLoc; protected int lightSpecularLoc; protected int lightFalloffLoc; protected int lightSpotLoc; // Texturing uniforms protected Texture texture; protected int texUnit; protected int textureLoc; protected int texMatrixLoc; protected int texOffsetLoc; protected float[] tcmat; // Vertex attributes protected int vertexLoc; protected int colorLoc; protected int normalLoc; protected int texCoordLoc; protected int normalMatLoc; protected int directionLoc; protected int offsetLoc; protected int ambientLoc; protected int specularLoc; protected int emissiveLoc; protected int shininessLoc; public PShader() { parent = null; pgl = null; context = -1; this.vertexURL = null; this.fragmentURL = null; this.vertexFilename = null; this.fragmentFilename = null; glProgram = 0; glVertex = 0; glFragment = 0; intBuffer = PGL.allocateIntBuffer(1); floatBuffer = PGL.allocateFloatBuffer(1); bound = false; type = -1; } public PShader(PApplet parent) { this(); this.parent = parent; pgl = PGraphicsOpenGL.pgl; context = pgl.createEmptyContext(); } /** * Creates a shader program using the specified vertex and fragment * shaders. * * @param parent the parent program * @param vertFilename name of the vertex shader * @param fragFilename name of the fragment shader */ public PShader(PApplet parent, String vertFilename, String fragFilename) { this.parent = parent; pgl = PGraphicsOpenGL.pgl; this.vertexURL = null; this.fragmentURL = null; this.vertexFilename = vertFilename; this.fragmentFilename = fragFilename; fragmentShaderSource = pgl.loadFragmentShader(fragFilename); vertexShaderSource = pgl.loadVertexShader(vertFilename); glProgram = 0; glVertex = 0; glFragment = 0; intBuffer = PGL.allocateIntBuffer(1); floatBuffer = PGL.allocateFloatBuffer(1); int vertType = getShaderType(vertexShaderSource, -1); int fragType = getShaderType(fragmentShaderSource, -1); if (vertType == -1 && fragType == -1) { type = PShader.POLY; } else if (vertType == -1) { type = fragType; } else if (fragType == -1) { type = vertType; } else if (fragType == vertType) { type = vertType; } else { PGraphics.showWarning(PGraphicsOpenGL.INCONSISTENT_SHADER_TYPES); } } /** * @param vertURL network location of the vertex shader * @param fragURL network location of the fragment shader */ public PShader(PApplet parent, URL vertURL, URL fragURL) { this.parent = parent; pgl = PGraphicsOpenGL.pgl; this.vertexURL = vertURL; this.fragmentURL = fragURL; this.vertexFilename = null; this.fragmentFilename = null; fragmentShaderSource = pgl.loadFragmentShader(fragURL); vertexShaderSource = pgl.loadVertexShader(vertURL); glProgram = 0; glVertex = 0; glFragment = 0; intBuffer = PGL.allocateIntBuffer(1); floatBuffer = PGL.allocateFloatBuffer(1); int vertType = getShaderType(vertexShaderSource, -1); int fragType = getShaderType(fragmentShaderSource, -1); if (vertType == -1 && fragType == -1) { type = PShader.POLY; } else if (vertType == -1) { type = fragType; } else if (fragType == -1) { type = vertType; } else if (fragType == vertType) { type = vertType; } else { PGraphics.showWarning(PGraphicsOpenGL.INCONSISTENT_SHADER_TYPES); } } public PShader(PApplet parent, String[] vertSource, String[] fragSource) { this.parent = parent; pgl = PGraphicsOpenGL.pgl; this.vertexURL = null; this.fragmentURL = null; this.vertexFilename = null; this.fragmentFilename = null; vertexShaderSource = vertSource; fragmentShaderSource = fragSource; glProgram = 0; glVertex = 0; glFragment = 0; intBuffer = PGL.allocateIntBuffer(1); floatBuffer = PGL.allocateFloatBuffer(1); int vertType = getShaderType(vertexShaderSource, -1); int fragType = getShaderType(fragmentShaderSource, -1); if (vertType == -1 && fragType == -1) { type = PShader.POLY; } else if (vertType == -1) { type = fragType; } else if (fragType == -1) { type = vertType; } else if (fragType == vertType) { type = vertType; } else { PGraphics.showWarning(PGraphicsOpenGL.INCONSISTENT_SHADER_TYPES); } } @Override protected void finalize() throws Throwable { try { if (glVertex != 0) { PGraphicsOpenGL.finalizeGLSLVertShaderObject(glVertex, context); } if (glFragment != 0) { PGraphicsOpenGL.finalizeGLSLFragShaderObject(glFragment, context); } if (glProgram != 0) { PGraphicsOpenGL.finalizeGLSLProgramObject(glProgram, context); } } finally { super.finalize(); } } public void setVertexShader(String vertFilename) { this.vertexFilename = vertFilename; vertexShaderSource = pgl.loadFragmentShader(vertFilename); } public void setVertexShader(URL vertURL) { this.vertexURL = vertURL; vertexShaderSource = pgl.loadVertexShader(vertURL); } public void setVertexShader(String[] vertSource) { vertexShaderSource = vertSource; } public void setFragmentShader(String fragFilename) { this.fragmentFilename = fragFilename; fragmentShaderSource = pgl.loadVertexShader(fragFilename); } public void setFragmentShader(URL fragURL) { this.fragmentURL = fragURL; fragmentShaderSource = pgl.loadVertexShader(fragURL); } public void setFragmentShader(String[] fragSource) { fragmentShaderSource = fragSource; } /** * Initializes (if needed) and binds the shader program. */ public void bind() { init(); if (!bound) { pgl.useProgram(glProgram); bound = true; consumeUniforms(); bindTextures(); } if (hasType()) bindTyped(); } /** * Unbinds the shader program. */ public void unbind() { if (hasType()) unbindTyped(); if (bound) { unbindTextures(); pgl.useProgram(0); bound = false; } } /** * Returns true if the shader is bound, false otherwise. */ public boolean bound() { return bound; } /** * @webref rendering:shaders * @brief Sets a variable within the shader * @param name the name of the uniform variable to modify * @param x first component of the variable to modify */ public void set(String name, int x) { setUniformImpl(name, UniformValue.INT1, new int[] { x }); } /** * @param y second component of the variable to modify. The variable has to be declared with an array/vector type in the shader (i.e.: int[2], vec2) */ public void set(String name, int x, int y) { setUniformImpl(name, UniformValue.INT2, new int[] { x, y }); } /** * @param z third component of the variable to modify. The variable has to be declared with an array/vector type in the shader (i.e.: int[3], vec3) */ public void set(String name, int x, int y, int z) { setUniformImpl(name, UniformValue.INT3, new int[] { x, y, z }); } /** * @param w fourth component of the variable to modify. The variable has to be declared with an array/vector type in the shader (i.e.: int[4], vec4) */ public void set(String name, int x, int y, int z, int w) { setUniformImpl(name, UniformValue.INT4, new int[] { x, y, z, w }); } public void set(String name, float x) { setUniformImpl(name, UniformValue.FLOAT1, new float[] { x }); } public void set(String name, float x, float y) { setUniformImpl(name, UniformValue.FLOAT2, new float[] { x, y }); } public void set(String name, float x, float y, float z) { setUniformImpl(name, UniformValue.FLOAT3, new float[] { x, y, z }); } public void set(String name, float x, float y, float z, float w) { setUniformImpl(name, UniformValue.FLOAT4, new float[] { x, y, z, w }); } /** * @param vec modifies all the components of an array/vector uniform variable. PVector can only be used if the type of the variable is vec3. */ public void set(String name, PVector vec) { setUniformImpl(name, UniformValue.FLOAT3, new float[] { vec.x, vec.y, vec.z }); } public void set(String name, boolean x) { setUniformImpl(name, UniformValue.INT1, new int[] { (x)?1:0 }); } public void set(String name, boolean x, boolean y) { setUniformImpl(name, UniformValue.INT2, new int[] { (x)?1:0, (y)?1:0 }); } public void set(String name, boolean x, boolean y, boolean z) { setUniformImpl(name, UniformValue.INT3, new int[] { (x)?1:0, (y)?1:0, (z)?1:0 }); } public void set(String name, boolean x, boolean y, boolean z, boolean w) { setUniformImpl(name, UniformValue.INT4, new int[] { (x)?1:0, (y)?1:0, (z)?1:0, (w)?1:0 }); } public void set(String name, int[] vec) { set(name, vec, 1); } /** * @param ncoords number of coordinates per element, max 4 */ public void set(String name, int[] vec, int ncoords) { if (ncoords == 1) { setUniformImpl(name, UniformValue.INT1VEC, vec); } else if (ncoords == 2) { setUniformImpl(name, UniformValue.INT2VEC, vec); } else if (ncoords == 3) { setUniformImpl(name, UniformValue.INT3VEC, vec); } else if (ncoords == 4) { setUniformImpl(name, UniformValue.INT4VEC, vec); } else if (4 < ncoords) { PGraphics.showWarning("Only up to 4 coordinates per element are " + "supported."); } else { PGraphics.showWarning("Wrong number of coordinates: it is negative!"); } } public void set(String name, float[] vec) { set(name, vec, 1); } public void set(String name, float[] vec, int ncoords) { if (ncoords == 1) { setUniformImpl(name, UniformValue.FLOAT1VEC, vec); } else if (ncoords == 2) { setUniformImpl(name, UniformValue.FLOAT2VEC, vec); } else if (ncoords == 3) { setUniformImpl(name, UniformValue.FLOAT3VEC, vec); } else if (ncoords == 4) { setUniformImpl(name, UniformValue.FLOAT4VEC, vec); } else if (4 < ncoords) { PGraphics.showWarning("Only up to 4 coordinates per element are " + "supported."); } else { PGraphics.showWarning("Wrong number of coordinates: it is negative!"); } } public void set(String name, boolean[] vec) { set(name, vec, 1); } public void set(String name, boolean[] boolvec, int ncoords) { int[] vec = new int[boolvec.length]; for (int i = 0; i < boolvec.length; i++) { vec[i] = (boolvec[i])?1:0; } set(name, vec, ncoords); } /** * @param mat matrix of values */ public void set(String name, PMatrix2D mat) { float[] matv = { mat.m00, mat.m01, mat.m10, mat.m11 }; setUniformImpl(name, UniformValue.MAT2, matv); } public void set(String name, PMatrix3D mat) { set(name, mat, false); } /** * @param use3x3 enforces the matrix is 3 x 3 */ public void set(String name, PMatrix3D mat, boolean use3x3) { if (use3x3) { float[] matv = { mat.m00, mat.m01, mat.m02, mat.m10, mat.m11, mat.m12, mat.m20, mat.m21, mat.m22 }; setUniformImpl(name, UniformValue.MAT3, matv); } else { float[] matv = { mat.m00, mat.m01, mat.m02, mat.m03, mat.m10, mat.m11, mat.m12, mat.m13, mat.m20, mat.m21, mat.m22, mat.m23, mat.m30, mat.m31, mat.m32, mat.m33 }; setUniformImpl(name, UniformValue.MAT4, matv); } } /** * @param tex sets the sampler uniform variable to read from this image texture */ public void set(String name, PImage tex) { setUniformImpl(name, UniformValue.SAMPLER2D, tex); } /** * Extra initialization method that can be used by subclasses, called after * compiling and attaching the vertex and fragment shaders, and before * linking the shader program. * */ protected void setup() { } protected void draw(int idxId, int count, int offset) { pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, idxId); pgl.drawElements(PGL.TRIANGLES, count, PGL.INDEX_TYPE, offset * PGL.SIZEOF_INDEX); pgl.bindBuffer(PGL.ELEMENT_ARRAY_BUFFER, 0); } /** * Returns the ID location of the attribute parameter given its name. * * @param name String * @return int */ protected int getAttributeLoc(String name) { init(); return pgl.getAttribLocation(glProgram, name); } /** * Returns the ID location of the uniform parameter given its name. * * @param name String * @return int */ protected int getUniformLoc(String name) { init(); return pgl.getUniformLocation(glProgram, name); } protected void setAttributeVBO(int loc, int vboId, int size, int type, boolean normalized, int stride, int offset) { if (-1 < loc) { pgl.bindBuffer(PGL.ARRAY_BUFFER, vboId); pgl.vertexAttribPointer(loc, size, type, normalized, stride, offset); } } protected void setUniformValue(int loc, int x) { if (-1 < loc) { pgl.uniform1i(loc, x); } } protected void setUniformValue(int loc, int x, int y) { if (-1 < loc) { pgl.uniform2i(loc, x, y); } } protected void setUniformValue(int loc, int x, int y, int z) { if (-1 < loc) { pgl.uniform3i(loc, x, y, z); } } protected void setUniformValue(int loc, int x, int y, int z, int w) { if (-1 < loc) { pgl.uniform4i(loc, x, y, z, w); } } protected void setUniformValue(int loc, float x) { if (-1 < loc) { pgl.uniform1f(loc, x); } } protected void setUniformValue(int loc, float x, float y) { if (-1 < loc) { pgl.uniform2f(loc, x, y); } } protected void setUniformValue(int loc, float x, float y, float z) { if (-1 < loc) { pgl.uniform3f(loc, x, y, z); } } protected void setUniformValue(int loc, float x, float y, float z, float w) { if (-1 < loc) { pgl.uniform4f(loc, x, y, z, w); } } protected void setUniformVector(int loc, int[] vec, int ncoords, int length) { if (-1 < loc) { updateIntBuffer(vec); if (ncoords == 1) { pgl.uniform1iv(loc, length, intBuffer); } else if (ncoords == 2) { pgl.uniform2iv(loc, length, intBuffer); } else if (ncoords == 3) { pgl.uniform3iv(loc, length, intBuffer); } else if (ncoords == 4) { pgl.uniform3iv(loc, length, intBuffer); } } } protected void setUniformVector(int loc, float[] vec, int ncoords, int length) { if (-1 < loc) { updateFloatBuffer(vec); if (ncoords == 1) { pgl.uniform1fv(loc, length, floatBuffer); } else if (ncoords == 2) { pgl.uniform2fv(loc, length, floatBuffer); } else if (ncoords == 3) { pgl.uniform3fv(loc, length, floatBuffer); } else if (ncoords == 4) { pgl.uniform4fv(loc, length, floatBuffer); } } } protected void setUniformMatrix(int loc, float[] mat) { if (-1 < loc) { updateFloatBuffer(mat); if (mat.length == 4) { pgl.uniformMatrix2fv(loc, 1, false, floatBuffer); } else if (mat.length == 9) { pgl.uniformMatrix3fv(loc, 1, false, floatBuffer); } else if (mat.length == 16) { pgl.uniformMatrix4fv(loc, 1, false, floatBuffer); } } } protected void setUniformTex(int loc, Texture tex) { if (texUnits != null) { Integer unit = texUnits.get(loc); if (unit != null) { pgl.activeTexture(PGL.TEXTURE0 + unit); tex.bind(); } else { throw new RuntimeException("Cannot find unit for texture " + tex); } } } protected void setUniformImpl(String name, int type, Object value) { int loc = getUniformLoc(name); if (-1 < loc) { if (uniformValues == null) { uniformValues = new HashMap<Integer, UniformValue>(); } uniformValues.put(loc, new UniformValue(type, value)); } else { PGraphics.showWarning("The shader doesn't have a uniform called \"" + name + "\""); } } protected void consumeUniforms() { if (uniformValues != null && 0 < uniformValues.size()) { int unit = 0; for (Integer loc: uniformValues.keySet()) { UniformValue val = uniformValues.get(loc); if (val.type == UniformValue.INT1) { int[] v = ((int[])val.value); pgl.uniform1i(loc, v[0]); } else if (val.type == UniformValue.INT2) { int[] v = ((int[])val.value); pgl.uniform2i(loc, v[0], v[1]); } else if (val.type == UniformValue.INT3) { int[] v = ((int[])val.value); pgl.uniform3i(loc, v[0], v[1], v[2]); } else if (val.type == UniformValue.INT4) { int[] v = ((int[])val.value); pgl.uniform4i(loc, v[0], v[1], v[2], v[3]); } else if (val.type == UniformValue.FLOAT1) { float[] v = ((float[])val.value); pgl.uniform1f(loc, v[0]); } else if (val.type == UniformValue.FLOAT2) { float[] v = ((float[])val.value); pgl.uniform2f(loc, v[0], v[1]); } else if (val.type == UniformValue.FLOAT3) { float[] v = ((float[])val.value); pgl.uniform3f(loc, v[0], v[1], v[2]); } else if (val.type == UniformValue.FLOAT4) { float[] v = ((float[])val.value); pgl.uniform4f(loc, v[0], v[1], v[2], v[3]); } else if (val.type == UniformValue.INT1VEC) { int[] v = ((int[])val.value); updateIntBuffer(v); pgl.uniform1iv(loc, v.length, intBuffer); } else if (val.type == UniformValue.INT2VEC) { int[] v = ((int[])val.value); updateIntBuffer(v); pgl.uniform2iv(loc, v.length / 2, intBuffer); } else if (val.type == UniformValue.INT3VEC) { int[] v = ((int[])val.value); updateIntBuffer(v); pgl.uniform3iv(loc, v.length / 3, intBuffer); } else if (val.type == UniformValue.INT4VEC) { int[] v = ((int[])val.value); updateIntBuffer(v); pgl.uniform4iv(loc, v.length / 4, intBuffer); } else if (val.type == UniformValue.FLOAT1VEC) { float[] v = ((float[])val.value); updateFloatBuffer(v); pgl.uniform1fv(loc, v.length, floatBuffer); } else if (val.type == UniformValue.FLOAT2VEC) { float[] v = ((float[])val.value); updateFloatBuffer(v); pgl.uniform2fv(loc, v.length / 2, floatBuffer); } else if (val.type == UniformValue.FLOAT3VEC) { float[] v = ((float[])val.value); updateFloatBuffer(v); pgl.uniform3fv(loc, v.length / 3, floatBuffer); } else if (val.type == UniformValue.FLOAT4VEC) { float[] v = ((float[])val.value); updateFloatBuffer(v); pgl.uniform4fv(loc, v.length / 4, floatBuffer); } else if (val.type == UniformValue.MAT2) { float[] v = ((float[])val.value); updateFloatBuffer(v); pgl.uniformMatrix2fv(loc, 1, false, floatBuffer); } else if (val.type == UniformValue.MAT3) { float[] v = ((float[])val.value); updateFloatBuffer(v); pgl.uniformMatrix3fv(loc, 1, false, floatBuffer); } else if (val.type == UniformValue.MAT4) { float[] v = ((float[])val.value); updateFloatBuffer(v); pgl.uniformMatrix4fv(loc, 1, false, floatBuffer); } else if (val.type == UniformValue.SAMPLER2D) { PImage img = (PImage)val.value; Texture tex = PGraphicsOpenGL.pgPrimary.getTexture(img); if (textures == null) textures = new HashMap<Integer, Texture>(); textures.put(loc, tex); if (texUnits == null) texUnits = new HashMap<Integer, Integer>(); if (texUnits.containsKey(loc)) { unit = texUnits.get(loc); pgl.uniform1i(loc, unit); } else { texUnits.put(loc, unit); pgl.uniform1i(loc, unit); } unit++; } } uniformValues.clear(); } } protected void updateIntBuffer(int[] vec) { intBuffer = PGL.updateIntBuffer(intBuffer, vec, false); } protected void updateFloatBuffer(float[] vec) { floatBuffer = PGL.updateFloatBuffer(floatBuffer, vec, false); } protected void bindTextures() { if (textures != null && texUnits != null) { for (int loc: textures.keySet()) { Texture tex = textures.get(loc); Integer unit = texUnits.get(loc); if (unit != null) { pgl.activeTexture(PGL.TEXTURE0 + unit); tex.bind(); } else { throw new RuntimeException("Cannot find unit for texture " + tex); } } } } protected void unbindTextures() { if (textures != null && texUnits != null) { for (int loc: textures.keySet()) { Texture tex = textures.get(loc); Integer unit = texUnits.get(loc); if (unit != null) { pgl.activeTexture(PGL.TEXTURE0 + unit); tex.unbind(); } else { throw new RuntimeException("Cannot find unit for texture " + tex); } } pgl.activeTexture(PGL.TEXTURE0); } } protected void init() { if (glProgram == 0 || contextIsOutdated()) { context = pgl.getCurrentContext(); glProgram = PGraphicsOpenGL.createGLSLProgramObject(context); boolean vertRes = true; if (hasVertexShader()) { vertRes = compileVertexShader(); } else { PGraphics.showException("Doesn't have a vertex shader"); } boolean fragRes = true; if (hasFragmentShader()) { fragRes = compileFragmentShader(); } else { PGraphics.showException("Doesn't have a fragment shader"); } if (vertRes && fragRes) { pgl.attachShader(glProgram, glVertex); pgl.attachShader(glProgram, glFragment); setup(); pgl.linkProgram(glProgram); pgl.getProgramiv(glProgram, PGL.LINK_STATUS, intBuffer); boolean linked = intBuffer.get(0) == 0 ? false : true; if (!linked) { PGraphics.showException("Cannot link shader program:\n" + pgl.getProgramInfoLog(glProgram)); } pgl.validateProgram(glProgram); pgl.getProgramiv(glProgram, PGL.VALIDATE_STATUS, intBuffer); boolean validated = intBuffer.get(0) == 0 ? false : true; if (!validated) { PGraphics.showException("Cannot validate shader program:\n" + pgl.getProgramInfoLog(glProgram)); } } } } protected boolean contextIsOutdated() { boolean outdated = !pgl.contextIsCurrent(context); if (outdated) { PGraphicsOpenGL.removeGLSLProgramObject(glProgram, context); PGraphicsOpenGL.removeGLSLVertShaderObject(glVertex, context); PGraphicsOpenGL.removeGLSLFragShaderObject(glFragment, context); glProgram = 0; glVertex = 0; glFragment = 0; } return outdated; } protected boolean hasVertexShader() { return vertexShaderSource != null && 0 < vertexShaderSource.length; } protected boolean hasFragmentShader() { return fragmentShaderSource != null && 0 < fragmentShaderSource.length; } /** * @param shaderSource a string containing the shader's code */ protected boolean compileVertexShader() { glVertex = PGraphicsOpenGL.createGLSLVertShaderObject(context); pgl.shaderSource(glVertex, PApplet.join(vertexShaderSource, "\n")); pgl.compileShader(glVertex); pgl.getShaderiv(glVertex, PGL.COMPILE_STATUS, intBuffer); boolean compiled = intBuffer.get(0) == 0 ? false : true; if (!compiled) { PGraphics.showException("Cannot compile vertex shader:\n" + pgl.getShaderInfoLog(glVertex)); return false; } else { return true; } } /** * @param shaderSource a string containing the shader's code */ protected boolean compileFragmentShader() { glFragment = PGraphicsOpenGL.createGLSLFragShaderObject(context); pgl.shaderSource(glFragment, PApplet.join(fragmentShaderSource, "\n")); pgl.compileShader(glFragment); pgl.getShaderiv(glFragment, PGL.COMPILE_STATUS, intBuffer); boolean compiled = intBuffer.get(0) == 0 ? false : true; if (!compiled) { PGraphics.showException("Cannot compile fragment shader:\n" + pgl.getShaderInfoLog(glFragment)); return false; } else { return true; } } protected void dispose() { if (glVertex != 0) { PGraphicsOpenGL.deleteGLSLVertShaderObject(glVertex, context); glVertex = 0; } if (glFragment != 0) { PGraphicsOpenGL.deleteGLSLFragShaderObject(glFragment, context); glFragment = 0; } if (glProgram != 0) { PGraphicsOpenGL.deleteGLSLProgramObject(glProgram, context); glProgram = 0; } } static protected int getShaderType(String[] source, int defaultType) { for (int i = 0; i < source.length; i++) { String line = source[i].trim(); if (PApplet.match(line, pointShaderAttrRegexp) != null) return PShader.POINT; else if (PApplet.match(line, lineShaderAttrRegexp) != null) return PShader.LINE; else if (PApplet.match(line, pointShaderDefRegexp) != null) return PShader.POINT; else if (PApplet.match(line, lineShaderDefRegexp) != null) return PShader.LINE; else if (PApplet.match(line, colorShaderDefRegexp) != null) return PShader.COLOR; else if (PApplet.match(line, lightShaderDefRegexp) != null) return PShader.LIGHT; else if (PApplet.match(line, texShaderDefRegexp) != null) return PShader.TEXTURE; else if (PApplet.match(line, texlightShaderDefRegexp) != null) return PShader.TEXLIGHT; else if (PApplet.match(line, polyShaderDefRegexp) != null) return PShader.POLY; else if (PApplet.match(line, triShaderAttrRegexp) != null) return PShader.POLY; else if (PApplet.match(line, quadShaderAttrRegexp) != null) return PShader.POLY; } return defaultType; } // *************************************************************************** // // Processing specific protected int getType() { return type; } protected void setType(int type) { this.type = type; } protected boolean hasType() { return POINT <= type && type <= TEXLIGHT; } protected boolean isPointShader() { return type == POINT; } protected boolean isLineShader() { return type == LINE; } protected boolean isPolyShader() { return POLY <= type && type <= TEXLIGHT; } protected boolean checkPolyType(int type) { if (getType() == PShader.POLY) return true; if (getType() != type) { if (type == TEXLIGHT) { PGraphics.showWarning(PGraphicsOpenGL.NO_TEXLIGHT_SHADER_ERROR); } else if (type == LIGHT) { PGraphics.showWarning(PGraphicsOpenGL.NO_LIGHT_SHADER_ERROR); } else if (type == TEXTURE) { PGraphics.showWarning(PGraphicsOpenGL.NO_TEXTURE_SHADER_ERROR); } else if (type == COLOR) { PGraphics.showWarning(PGraphicsOpenGL.NO_COLOR_SHADER_ERROR); } return false; } return true; } protected int getLastTexUnit() { return texUnits == null ? -1 : texUnits.size() - 1; } protected void setRenderer(PGraphicsOpenGL pg) { this.pg = pg; } boolean loadedAttributes = false; protected void loadAttributes() { if (loadedAttributes) return; vertexLoc = getAttributeLoc("vertex"); if (vertexLoc == -1) vertexLoc = getAttributeLoc("position"); colorLoc = getAttributeLoc("color"); texCoordLoc = getAttributeLoc("texCoord"); normalLoc = getAttributeLoc("normal"); ambientLoc = getAttributeLoc("ambient"); specularLoc = getAttributeLoc("specular"); emissiveLoc = getAttributeLoc("emissive"); shininessLoc = getAttributeLoc("shininess"); directionLoc = getAttributeLoc("direction"); offsetLoc = getAttributeLoc("offset"); directionLoc = getAttributeLoc("direction"); offsetLoc = getAttributeLoc("offset"); loadedAttributes = true; } boolean loadedUniforms = false; protected void loadUniforms() { if (loadedUniforms) return; transformMatLoc = getUniformLoc("transform"); if (transformMatLoc == -1) transformMatLoc = getUniformLoc("transformMatrix"); modelviewMatLoc = getUniformLoc("modelview"); if (modelviewMatLoc == -1) modelviewMatLoc = getUniformLoc("modelviewMatrix"); projectionMatLoc = getUniformLoc("projection"); if (projectionMatLoc == -1) projectionMatLoc = getUniformLoc("projectionMatrix"); viewportLoc = getUniformLoc("viewport"); bufferLoc = getUniformLoc("buffer"); normalMatLoc = getUniformLoc("normalMatrix"); lightCountLoc = getUniformLoc("lightCount"); lightPositionLoc = getUniformLoc("lightPosition"); lightNormalLoc = getUniformLoc("lightNormal"); lightAmbientLoc = getUniformLoc("lightAmbient"); lightDiffuseLoc = getUniformLoc("lightDiffuse"); lightSpecularLoc = getUniformLoc("lightSpecular"); lightFalloffLoc = getUniformLoc("lightFalloff"); lightSpotLoc = getUniformLoc("lightSpot"); textureLoc = getUniformLoc("texture"); if (textureLoc == -1) { textureLoc = getUniformLoc("texMap"); } texMatrixLoc = getUniformLoc("texMatrix"); texOffsetLoc = getUniformLoc("texOffset"); perspectiveLoc = getUniformLoc("perspective"); scaleLoc = getUniformLoc("scale"); loadedUniforms = true; } protected void setCommonUniforms() { if (-1 < transformMatLoc) { pg.updateGLProjmodelview(); setUniformMatrix(transformMatLoc, pg.glProjmodelview); } if (-1 < modelviewMatLoc) { pg.updateGLModelview(); setUniformMatrix(modelviewMatLoc, pg.glModelview); } if (-1 < projectionMatLoc) { pg.updateGLProjection(); setUniformMatrix(projectionMatLoc, pg.glProjection); } if (-1 < viewportLoc) { float x = pg.viewport.get(0); float y = pg.viewport.get(1); float w = pg.viewport.get(2); float h = pg.viewport.get(3); setUniformValue(viewportLoc, x, y, w, h); } if (-1 < bufferLoc) { bufferUnit = getLastTexUnit() + 1; setUniformValue(bufferLoc, bufferUnit); pgl.activeTexture(PGL.TEXTURE0 + bufferUnit); pg.bindFrontTexture(); } else { bufferUnit = -1; } } protected void bindTyped() { if (pg == null) { setRenderer(PGraphicsOpenGL.pgCurrent); loadAttributes(); loadUniforms(); } setCommonUniforms(); if (-1 < vertexLoc) pgl.enableVertexAttribArray(vertexLoc); if (-1 < colorLoc) pgl.enableVertexAttribArray(colorLoc); if (-1 < texCoordLoc) pgl.enableVertexAttribArray(texCoordLoc); if (-1 < normalLoc) pgl.enableVertexAttribArray(normalLoc); if (-1 < normalMatLoc) { pg.updateGLNormal(); setUniformMatrix(normalMatLoc, pg.glNormal); } if (-1 < ambientLoc) pgl.enableVertexAttribArray(ambientLoc); if (-1 < specularLoc) pgl.enableVertexAttribArray(specularLoc); if (-1 < emissiveLoc) pgl.enableVertexAttribArray(emissiveLoc); if (-1 < shininessLoc) pgl.enableVertexAttribArray(shininessLoc); int count = pg.lightCount; setUniformValue(lightCountLoc, count); if (0 < count) { setUniformVector(lightPositionLoc, pg.lightPosition, 4, count); setUniformVector(lightNormalLoc, pg.lightNormal, 3, count); setUniformVector(lightAmbientLoc, pg.lightAmbient, 3, count); setUniformVector(lightDiffuseLoc, pg.lightDiffuse, 3, count); setUniformVector(lightSpecularLoc, pg.lightSpecular, 3, count); setUniformVector(lightFalloffLoc, pg.lightFalloffCoefficients, 3, count); setUniformVector(lightSpotLoc, pg.lightSpotParameters, 2, count); } if (-1 < directionLoc) pgl.enableVertexAttribArray(directionLoc); if (-1 < offsetLoc) pgl.enableVertexAttribArray(offsetLoc); if (-1 < perspectiveLoc) { if (pg.getHint(ENABLE_STROKE_PERSPECTIVE) && pg.nonOrthoProjection()) { setUniformValue(perspectiveLoc, 1); } else { setUniformValue(perspectiveLoc, 0); } } if (-1 < scaleLoc) { if (pg.getHint(DISABLE_OPTIMIZED_STROKE)) { setUniformValue(scaleLoc, 1.0f, 1.0f, 1.0f); } else { float f = PGL.STROKE_DISPLACEMENT; if (pg.orthoProjection()) { setUniformValue(scaleLoc, 1, 1, f); } else { setUniformValue(scaleLoc, f, f, f); } } } } protected void unbindTyped() { if (-1 < offsetLoc) pgl.disableVertexAttribArray(offsetLoc); if (-1 < directionLoc) pgl.disableVertexAttribArray(directionLoc); if (-1 < textureLoc && texture != null) { pgl.activeTexture(PGL.TEXTURE0 + texUnit); texture.unbind(); pgl.activeTexture(PGL.TEXTURE0); texture = null; } if (-1 < ambientLoc) pgl.disableVertexAttribArray(ambientLoc); if (-1 < specularLoc) pgl.disableVertexAttribArray(specularLoc); if (-1 < emissiveLoc) pgl.disableVertexAttribArray(emissiveLoc); if (-1 < shininessLoc) pgl.disableVertexAttribArray(shininessLoc); if (-1 < vertexLoc) pgl.disableVertexAttribArray(vertexLoc); if (-1 < colorLoc) pgl.disableVertexAttribArray(colorLoc); if (-1 < texCoordLoc) pgl.disableVertexAttribArray(texCoordLoc); if (-1 < normalLoc) pgl.disableVertexAttribArray(normalLoc); if (-1 < bufferLoc) { pgl.requestFBOLayer(); pgl.activeTexture(PGL.TEXTURE0 + bufferUnit); pg.unbindFrontTexture(); pgl.activeTexture(PGL.TEXTURE0); } pgl.bindBuffer(PGL.ARRAY_BUFFER, 0); } protected void setTexture(Texture tex) { texture = tex; float scaleu = 1; float scalev = 1; float dispu = 0; float dispv = 0; if (tex != null) { if (tex.invertedX()) { scaleu = -1; dispu = 1; } if (tex.invertedY()) { scalev = -1; dispv = 1; } scaleu *= tex.maxTexcoordU(); dispu *= tex.maxTexcoordU(); scalev *= tex.maxTexcoordV(); dispv *= tex.maxTexcoordV(); setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height); if (-1 < textureLoc) { texUnit = -1 < bufferUnit ? bufferUnit + 1 : getLastTexUnit() + 1; setUniformValue(textureLoc, texUnit); pgl.activeTexture(PGL.TEXTURE0 + texUnit); tex.bind(); } } if (-1 < texMatrixLoc) { if (tcmat == null) { tcmat = new float[16]; } tcmat[0] = scaleu; tcmat[4] = 0; tcmat[ 8] = 0; tcmat[12] = dispu; tcmat[1] = 0; tcmat[5] = scalev; tcmat[ 9] = 0; tcmat[13] = dispv; tcmat[2] = 0; tcmat[6] = 0; tcmat[10] = 0; tcmat[14] = 0; tcmat[3] = 0; tcmat[7] = 0; tcmat[11] = 0; tcmat[15] = 0; setUniformMatrix(texMatrixLoc, tcmat); } } protected boolean supportsTexturing() { return -1 < textureLoc; } protected boolean supportLighting() { return -1 < lightCountLoc || -1 < lightPositionLoc || -1 < lightNormalLoc; } protected boolean accessTexCoords() { return -1 < texCoordLoc; } protected boolean accessNormals() { return -1 < normalLoc; } protected boolean accessLightAttribs() { return -1 < ambientLoc || -1 < specularLoc || -1 < emissiveLoc || -1 < shininessLoc; } protected void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { setAttributeVBO(vertexLoc, vboId, size, type, false, stride, offset); } protected void setColorAttribute(int vboId, int size, int type, int stride, int offset) { setAttributeVBO(colorLoc, vboId, size, type, true, stride, offset); } protected void setNormalAttribute(int vboId, int size, int type, int stride, int offset) { setAttributeVBO(normalLoc, vboId, size, type, false, stride, offset); } protected void setTexcoordAttribute(int vboId, int size, int type, int stride, int offset) { setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset); } protected void setAmbientAttribute(int vboId, int size, int type, int stride, int offset) { setAttributeVBO(ambientLoc, vboId, size, type, true, stride, offset); } protected void setSpecularAttribute(int vboId, int size, int type, int stride, int offset) { setAttributeVBO(specularLoc, vboId, size, type, true, stride, offset); } protected void setEmissiveAttribute(int vboId, int size, int type, int stride, int offset) { setAttributeVBO(emissiveLoc, vboId, size, type, true, stride, offset); } protected void setShininessAttribute(int vboId, int size, int type, int stride, int offset) { setAttributeVBO(shininessLoc, vboId, size, type, false, stride, offset); } protected void setLineAttribute(int vboId, int size, int type, int stride, int offset) { setAttributeVBO(directionLoc, vboId, size, type, false, stride, offset); } protected void setPointAttribute(int vboId, int size, int type, int stride, int offset) { setAttributeVBO(offsetLoc, vboId, size, type, false, stride, offset); } // *************************************************************************** // // Class to store a user-specified value for a uniform parameter // in the shader protected class UniformValue { static final int INT1 = 0; static final int INT2 = 1; static final int INT3 = 2; static final int INT4 = 3; static final int FLOAT1 = 4; static final int FLOAT2 = 5; static final int FLOAT3 = 6; static final int FLOAT4 = 7; static final int INT1VEC = 8; static final int INT2VEC = 9; static final int INT3VEC = 10; static final int INT4VEC = 11; static final int FLOAT1VEC = 12; static final int FLOAT2VEC = 13; static final int FLOAT3VEC = 14; static final int FLOAT4VEC = 15; static final int MAT2 = 16; static final int MAT3 = 17; static final int MAT4 = 18; static final int SAMPLER2D = 19; int type; Object value; UniformValue(int type, Object value) { this.type = type; this.value = value; } } }