summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoreteq <[email protected]>2006-08-17 05:01:11 +0000
committereteq <[email protected]>2006-08-17 05:01:11 +0000
commit84f386bc10ea1023ec267b12d994f9ad77520741 (patch)
tree10293a10f7e66a6b321360b6c940befb06ee7b8c
parent153642f820fd00444d651207e4a8b4bc75a6765b (diff)
Added Phong Shader to Light in lighting package (does not yet implement spotlight or actual location lighting)
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/svn-server-sync/joglutils/trunk@11 83d24430-9974-4f80-8418-2cc3294053b9
-rw-r--r--src/net/java/joglutils/lighting/Light.java523
1 files changed, 480 insertions, 43 deletions
diff --git a/src/net/java/joglutils/lighting/Light.java b/src/net/java/joglutils/lighting/Light.java
index 87b8f63..a12371e 100644
--- a/src/net/java/joglutils/lighting/Light.java
+++ b/src/net/java/joglutils/lighting/Light.java
@@ -1,21 +1,21 @@
/*
* Copyright (c) 2006 Erik Tollerud ([email protected]) All Rights Reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
- *
+ *
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
- *
+ *
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- *
+ *
* The names of Erik Tollerud, Sun Microsystems, Inc. or the names of
* contributors may not be used to endorse or promote products derived from
* this software without specific prior written permission.
- *
+ *
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
@@ -23,12 +23,12 @@
* SUN MICROSYSTEMS, INC. ("SUN"), AND SUN'S LICENSORS SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL ERIK
- * TOLLERUD, SUN, OR SUN'S LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
+ * TOLLERUD, SUN, OR SUN'S LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
* OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF ERIK
* TOLLERUD OR SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- *
+ *
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
@@ -52,10 +52,13 @@ import java.nio.*;
* @author Erik J. Tollerud
*/
public class Light {
- GL attachedGL;
- int lightNumber;
static HashMap<GL,boolean[]> assignedLights = new HashMap<GL,boolean[]>();
+ static HashMap<GL,Boolean> shaderBuiltin = new HashMap<GL,Boolean>();
+ static HashMap<GL,Integer> shaderProgNums = new HashMap<GL,Integer>();
+
+ private GL attachedGL;
+ private int lightNumber;
//Light defaults are determined by constructor
private float[] ambient;
@@ -70,6 +73,11 @@ public class Light {
private float linearAttenuation;
private float quadraticAttenuation;
+ private boolean phongShaded;
+ private boolean phongDiffColorMat;
+ private boolean phongAmbColorMat;
+
+
/**
* Creates a new instance of Light with the default settings.
*/
@@ -93,12 +101,15 @@ public class Light {
constantAttenuation = 1;
linearAttenuation = 0;
quadraticAttenuation = 0;
+ phongShaded = false;
+ phongDiffColorMat = false;
+ phongAmbColorMat = false;
+
}
/**
* Creates a new instance of Light with default settings attached to the specified {@link GL} Context
- *
* @param gl the OpenGL context to attach the light to
- * @throws sddm.lighting.LightingException if all lights in the specified OpenGL context are already attached. Light is detached from any OpenGL Context.
+ * @throws net.java.joglutils.lighting.LightingException if the light number is invalid or is already in use by another Light. Light is detached from any OpenGL Context.
*/
public Light(GL gl) throws LightingException {
this();
@@ -117,7 +128,7 @@ public class Light {
* Creates a new instance of Light with default settings attached to the specified {@link GL} Context with an explicit light number
* @param gl the OpenGL context to attach the light to
* @param lightNumber the light number to be used (must be on [0,7])
- * @throws sddm.lighting.LightingException if the light number is invalid or is already in use by another Light. Light is detached from any OpenGL Context.
+ * @throws net.java.joglutils.lighting.LightingException if the light number is invalid or is already in use by another Light. Light is detached from any OpenGL Context.
*/
public Light(GL gl, int lightNumber) throws LightingException {
this();
@@ -133,6 +144,7 @@ public class Light {
retrieve();
}
+
protected void finalize() {
//Must free light number if this Light is destroyed
if (this.attachedGL != null)
@@ -159,7 +171,7 @@ public class Light {
/**
* Sets the number of the OpenGL light to use in subsequent method calls
* @param lightNumber the light number to apply to this Light (must be on [0,7])
- * @throws sddm.lighting.LightingException if the light number is invalid or is already in use by another Light object on the attached OpenGL Context. Light is detached from any OpenGL Context.
+ * @throws net.java.joglutils.lighting.LightingException in use by another Light object on the attached OpenGL Context. Light is detached from any OpenGL Context.
*/
public void setLightNumber(int lightNumber) throws LightingException {
if(lightNumber < 0 || lightNumber > 7)
@@ -178,7 +190,7 @@ public class Light {
/**
* Sets the OpenGL light to use in subsequent method calls from a GL identifier
* @param lightID the OpenGL light ID (must be of the GL_LIGHTn family)
- * @throws sddm.lighting.LightingException if the input is not a valid light or the light is in use by another Light on the attached OpenGL Context. Light is detached from any OpenGL Context.
+ * @throws net.java.joglutils.lighting.LightingException if the input is not a valid light or the light is in use by another Light on the attached OpenGL Context. Light is detached from any OpenGL Context.
*/
public void setLightID(int lightID) throws LightingException {
setLightNumber(this.idToNum(lightID));
@@ -186,9 +198,8 @@ public class Light {
/**
* Attached the specified OpenGL context to this object
- *
* @param gl the OpenGL context to attach this to
- * @throws sddm.lighting.LightingException if the specified context has no free lights. Light is detached from any OpenGL Context.
+ * @throws net.java.joglutils.lighting.LightingException if the specified context has no free lights. Light is detached from any OpenGL Context.
*/
public void setAttachedGL(GL gl) throws LightingException {
this.unassignLightNumber(this.attachedGL,this.lightNumber);
@@ -200,6 +211,10 @@ public class Light {
this.lightNumber = findAndAssignFreeLightNumber(gl);
this.attachedGL = gl;
+ if (this.phongShaded) {
+ if(!this.shaderBuiltin.containsKey(gl))
+ this.initializePhongShader(gl);
+ }
}
/**
@@ -229,14 +244,15 @@ public class Light {
/**
* Applies the settings on this Light to the attached {@link GL} Context.
+ * Note that this will not apply Phong Shader settings.
*/
public void apply() {
apply(this.attachedGL,this.lightNumber);
}
/**
- * Reconfigure the settings for this Light from the state of the
- * attached {@link GL} Context.
+ * Reconfigure the settings for this Light from the state of the attached
+ * {@link GL} Context. Note that this will not retrieve Phong Shader settings.
*/
public void retrieve() {
retrieve(this.attachedGL,this.lightNumber);
@@ -254,19 +270,19 @@ public class Light {
disable(this.attachedGL,this.lightNumber);
}
/**
- * Applies the settings on this Light to the specified OpenGL context,
- * using the light number stored in the Light.
+ * Applies the settings on this Light to the specified OpenGL context,
+ * using the light number stored in the Light. Note that this will not apply Phong Shader settings.
* @param gl the OpenGL context to use.
- * @throws sddm.lighting.LightingException if the light number stored in this Light is invalid on the specified context.
+ * @throws net.java.joglutils.lighting.LightingException if the light number stored in this Light is invalid on the specified context.
*/
public void apply(GL gl) throws LightingException {
apply(gl,this.lightNumber);
}
/**
- * Reconfigures the settings on this Light from the state of the specified
- * OpenGL context, using the light number stored in the Light.
+ * Reconfigures the settings on this Light from the state of the specified
+ * OpenGL context, using the light number stored in the Light. Note that this will not retrieve Phong Shader settings.
* @param gl the OpenGL context to use.
- * @throws sddm.lighting.LightingException if the light number stored in this Light is invalid on the specified context.
+ * @throws net.java.joglutils.lighting.LightingException if the light number stored in this Light is invalid on the specified context.
*/
public void retrieve(GL gl) throws LightingException {
retrieve(gl,this.lightNumber);
@@ -275,7 +291,7 @@ public class Light {
/**
* Enables the light number stored in this Light on the specified OpenGL Context.
* @param gl the OpenGL context to use.
- * @throws sddm.lighting.LightingException if the light number stored in this Light is invalid on the specified context.
+ * @throws net.java.joglutils.lighting.LightingException if the light number stored in this Light is invalid on the specified context.
*/
public void enable(GL gl) throws LightingException {
enable(gl,this.lightNumber);
@@ -283,19 +299,19 @@ public class Light {
/**
* Disables the light number stored in this Light on the specified OpenGL Context.
* @param gl the OpenGL context to use.
- * @throws sddm.lighting.LightingException if the light number stored in this Light is invalid on the specified context.
+ * @throws net.java.joglutils.lighting.LightingException if the light number stored in this Light is invalid on the specified context.
*/
public void disable(GL gl) throws LightingException {
disable(gl,this.lightNumber);
}
/**
- * Applies the settings on this Light to the specified OpenGL context,
- * using the requested light number.
+ * Applies the settings on this Light to the specified OpenGL context,
+ * using the requested light number. Note that this will not apply Phong Shader settings.
* @param gl the OpenGL context to use.
* @param lightNumber the number of the light to use (should be on [0,7]).
- * @throws sddm.lighting.LightingException if the requested light is not valid on the specified context.
+ * @throws net.java.joglutils.lighting.LightingException if the requested light is not valid on the specified context.
*/
- public void apply(GL gl, int lightNumber) throws LightingException{
+ public void apply(GL gl, int lightNumber) throws LightingException {
if(!this.isLightNumberValid(gl, lightNumber))
throw new LightingException("attempted to apply Light settings to invalid lightNumber for the requested OpenGL context");
@@ -320,14 +336,14 @@ public class Light {
gl.glLightf(lightID,GL.GL_LINEAR_ATTENUATION,linearAttenuation);
gl.glLightf(lightID,GL.GL_QUADRATIC_ATTENUATION,quadraticAttenuation);
- this.lightNumber = lightNumber;
+ this.lightNumber = lightNumber;
}
/**
- * Reconfigures the settings on this Light from the state of the specified
- * OpenGL context, using the requested light number.
+ * Reconfigures the settings on this Light from the state of the specified
+ * OpenGL context, using the requested light number. Note that this will not retrieve Phong Shader settings.
* @param gl the OpenGL context to use.
* @param lightNumber the number of the light to use (should be on [0,7]).
- * @throws sddm.lighting.LightingException if the requested light is not valid on the specified context.
+ * @throws net.java.joglutils.lighting.LightingException if the requested light is not valid on the specified context.
*/
public void retrieve(GL gl, int lightNumber) throws LightingException{
if(!this.isLightNumberValid(gl, lightNumber))
@@ -342,7 +358,7 @@ public class Light {
gl.glGetLightfv(lightID,GL.GL_SPECULAR,buff);
//get light position - 4 (including distance)
gl.glGetLightfv(lightID,GL.GL_POSITION,buff);
- //get spot direction- 3
+ //get spot direction- 3
gl.glGetLightfv(lightID,GL.GL_SPOT_DIRECTION,buff);
//get individual floats - 1 each
gl.glGetLightfv(lightID,GL.GL_SPOT_CUTOFF,buff);
@@ -373,25 +389,78 @@ public class Light {
* Enables the requested light on the specified OpenGL Context.
* @param gl the OpenGL context to use.
* @param lightNumber the number of the light to use (should be on [0,7]).
- * @throws sddm.lighting.LightingException if the requested light is not valid on the specified context.
+ * @throws net.java.joglutils.lighting.LightingException if the requested light is not valid on the specified context.
*/
public void enable(GL gl, int lightNumber) throws LightingException {
if(!this.isLightNumberValid(gl, lightNumber))
throw new LightingException("attempted to enable Light on with an invalid lightNumber for the requested OpenGL context");
gl.glEnable(numToID(lightNumber));
this.lightNumber = lightNumber;
+
+ if(this.phongShaded) {
+ //TODO:link in shader as just another one?
+ if(!shaderBuiltin.containsKey(gl))
+ initializePhongShader(gl);
+
+ if(shaderBuiltin.get(gl)) {
+ int progID = shaderProgNums.get(gl);
+
+ int diffMatCol = gl.glGetUniformLocation(progID,"diffMatCol");
+ int ambMatCol = gl.glGetUniformLocation(progID,"ambMatCol");
+
+ gl.glUniform1i(diffMatCol,phongDiffColorMat ? 1 : 0);
+ gl.glUniform1i(ambMatCol,phongAmbColorMat ? 1 : 0);
+
+ gl.glUseProgram(progID);
+
+ gl.glUseProgram(progID+lightNumber);
+ /*for light one program
+ int progID = shaderProgNums.get(gl);
+
+ int lightNumUniform = gl.glGetUniformLocation(progID,"lightNumber");
+ gl.glUniform1i(lightNumUniform,lightNumber);
+
+ gl.glUseProgram(progID);
+ */
+ } else {
+ int progID = shaderProgNums.get(gl);
+
+ int diffMatCol = gl.glGetUniformLocationARB(progID,"diffMatCol");
+ int ambMatCol = gl.glGetUniformLocationARB(progID,"ambMatCol");
+
+ gl.glUniform1iARB(diffMatCol,phongDiffColorMat ? GL.GL_TRUE : GL.GL_FALSE);
+ gl.glUniform1iARB(ambMatCol,phongAmbColorMat ? GL.GL_TRUE : GL.GL_FALSE);
+
+ gl.glUseProgramObjectARB(progID+lightNumber);
+ /*for light one program
+ int progID = shaderProgNums.get(gl);
+
+ int lightNumUniform = gl.glGetUniformLocationARB(progID,"lightNumber");
+ gl.glUniform1iARB(lightNumUniform,lightNumber);
+
+ gl.glUseProgramObjectARB(progID);
+ */
+ }
+ }
}
/**
* Disables the requested light on the specified OpenGL Context.
* @param gl the OpenGL context to use.
* @param lightNumber the number of the light to use (should be on [0,7]).
- * @throws sddm.lighting.LightingException if the requested light is not valid on the specified context.
+ * @throws net.java.joglutils.lighting.LightingException if the requested light is not valid on the specified context.
*/
public void disable(GL gl, int lightNumber) throws LightingException {
if(!this.isLightNumberValid(gl, lightNumber))
throw new LightingException("attempted to disable Light on with an invalid lightNumber for the requested OpenGL context");
gl.glDisable(numToID(lightNumber));
this.lightNumber = lightNumber;
+
+ if (this.phongShaded) {
+ if(gl.isFunctionAvailable("glUseProgram"))
+ gl.glUseProgram(0);
+ else if(gl.isFunctionAvailable("glUseProgramObjectARB"))
+ gl.glUseProgramObjectARB(0);
+ }
}
//-----------------Setters and Getters-----------------
@@ -453,7 +522,7 @@ public class Light {
}
/**
- * Specifies the direction vector for this Light.
+ * Specifies the direction vector for this Light.
* (i.e. this the first 3 components specified when setting GL_POSITION with glLight)
* Default is {0,0,1}.
* @param lightPosition an array of three components in {x,y,z} format to be copied into the Light.
@@ -471,7 +540,7 @@ public class Light {
}
/**
- * Specifies the direction vector for this Light.
+ * Specifies the direction vector for this Light.
* (i.e. this the first 3 components specified when setting GL_POSITION with glLight)
* Default is {0,0,1}.
* @param lightx the x component of the light position
@@ -661,9 +730,9 @@ public class Light {
/**
* Converts the specified OpenGL light ID number to a number
- * @param lightID the OpenGL ID (should be one of GL_LIGHTn where n is on [0,7])
- * @throws sddm.lighting.LightingException if the supplied lightID is not an OpenGL light ID
* @return the appropriate light number (on [0,7])
+ * @param lightID the OpenGL ID (should be one of GL_LIGHTn where n is on [0,7])
+ * @throws net.java.joglutils.lighting.LightingException if the supplied lightID is not an OpenGL light ID
*/
public static int idToNum(int lightID) throws LightingException {
int retNum = -1;
@@ -701,9 +770,9 @@ public class Light {
/**
* Determines the OpenGL ID for the specified light number
- * @param lightNum a number on [0,7] specifying the a light
- * @throws sddm.lighting.LightingException if the input is invalid
* @return the OpenGL ID for that light number (from the GL_LIGHTn family)
+ * @param lightNum a number on [0,7] specifying the a light
+ * @throws net.java.joglutils.lighting.LightingException if the supplied lightID is not an OpenGL light ID
*/
public static int numToID(int lightNum) throws LightingException {
int retID = -1;
@@ -754,6 +823,320 @@ public class Light {
return false;
}
+ /**
+ * Sets if phong per-fragment shading (as opposed to fixed-functionality per-vertex shading) is to be used with this Light. Must come before the light is enabled.
+ * This uses a vertex and fragment shader, so the fixed-functionality pipeline will not function normally.
+ * @param usePhongShading if Phong should be used. If true and this Light is attached to a GL Context, initializes on this Light's context
+ * @throws net.java.joglutils.lighting.LightingException if the current OpenGL context does not support GLSL shaders or the shader did not sucessfully compile and link
+ */
+ public void setPhongShaded(boolean usePhongShading) throws LightingException {
+ if (this.attachedGL != null)
+ initializePhongShader(this.attachedGL);
+
+ this.phongShaded = usePhongShading;
+ }
+
+ /**
+ * Tells if this Light is using Phong shading
+ * @return true if this Light is in Phong shading mode
+ */
+ public boolean isPhongShaded() {
+ return this.phongShaded;
+ }
+
+ /**
+ * Sets whether or not the opengl color should be used for the phong color shader
+ * @param ambient the ambient color material mode
+ * @param diffuse the diffuse color material mode
+ */
+ public void setPhongColorMaterial(boolean ambient, boolean diffuse) {
+ this.phongAmbColorMat = ambient;
+ this.phongDiffColorMat = diffuse;
+ }
+
+ /**
+ * Determines if color material is used for ambient in the Phong shader
+ * @return true if color material is used for the phong ambient shader
+ */
+ public boolean isAmbientPhongColorMaterial() {
+ return this.phongAmbColorMat;
+ }
+
+ /**
+ * Determines if color material is used for diffuse in the Phong shader
+ * @return true if color material is used for the phong diffuse shader
+ */
+ public boolean isDiffusePhongColorMaterial() {
+ return this.phongDiffColorMat;
+ }
+
+ /**
+ * Initializes Phong shading mode for this Light (instead of the fixed functionality Gouraud shading) on the current OpenGL context. Must be called before Phong shading can be activated.
+ * @throws net.java.joglutils.lighting.LightingException if the OpenGL context does not support GLSL shaders or the shader did not sucessfully compile and link
+ */
+ public static void initializePhongShader() throws LightingException {
+ initializePhongShader(javax.media.opengl.glu.GLU.getCurrentGL());
+ }
+
+ /**
+ * Initializes Phong shading mode for this Light (instead of the fixed functionality Gouraud shading). Must be called on the context before Phong shading can be activated.
+ * @param gl the openGL context on which to initialize the shader
+ * @throws net.java.joglutils.lighting.LightingException if the OpenGL context does not support GLSL shaders or the shader did not sucessfully compile and link
+ */
+ public static void initializePhongShader(GL gl) throws LightingException {
+ /* Old way that only works for light zero
+ //program source
+ final String[] fragSource = {
+ "varying vec3 normalEye;\n",
+ "varying vec3 positionEye;\n",
+ "uniform int lightNum;\n",
+ "\n",
+ "void main()\n",
+ "{\n",
+ "\n",
+ "vec3 N = normalize (normalEye);\n",
+ "vec3 L = normalize (gl_LightSource[0].position.xyz);\n",
+ "vec3 E = normalize (-positionEye);\n",
+ "vec3 H = normalize (L + E);\n",
+ "\n",
+ "vec4 ambientColor = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;\n",
+ "vec4 diffuseColor = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse * max (dot (N, L), 0.0);\n",
+ "vec4 specularColor = gl_FrontMaterial.specular * gl_LightSource[0]. specular * pow (max (dot (N, H), 0.0), gl_FrontMaterial.shininess);\n",
+ "gl_FragColor = ambientColor + diffuseColor + specularColor;\n",
+ "}\n"
+ };
+ final String[] vertSource={
+ "varying vec3 normalEye;\n",
+ "varying vec3 positionEye;\n",
+ "\n",
+ "void main()\n",
+ "{\n",
+ "normalEye = gl_NormalMatrix * gl_Normal;\n",
+ "positionEye = (gl_ModelViewMatrix * gl_Vertex).xyz;\n",
+ "gl_Position = ftransform ();\n",
+ "}\n"
+ };
+
+ int[] vertLengths = new int[vertSource.length];
+ for (int i=0; i < vertLengths.length;++i)
+ vertLengths[i] = vertSource[i].length();
+ int[] fragLengths = new int[fragSource.length];
+ for (int i=0; i < fragLengths.length;++i)
+ fragLengths[i] = fragSource[i].length();
+
+
+ boolean builtin;
+ int progID;
+
+ if(gl.isFunctionAvailable("glCreateProgram"))
+ builtin = true;
+ else if (gl.isFunctionAvailable("glCreateProgramObjectARB"))
+ builtin = false;
+ else
+ throw new LightingException("Could not generate Shader for Light - GLSL Shaders not supported by this GL Context");
+
+ if(builtin) {
+ progID = gl.glCreateProgram();
+ int vertID = gl.glCreateShader(GL.GL_VERTEX_SHADER);
+ int fragID = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
+
+ gl.glShaderSource(vertID,vertSource.length,vertSource,vertLengths,0);
+ gl.glShaderSource(fragID,fragSource.length,fragSource,fragLengths,0);
+
+ gl.glCompileShader(vertID);
+ gl.glCompileShader(fragID);
+
+ gl.glAttachShader(progID,vertID);
+ gl.glAttachShader(progID,fragID);
+
+ gl.glLinkProgram(progID);
+
+ int[] getProgArray = new int[1];
+ gl.glGetProgramiv(progID,GL.GL_LINK_STATUS,getProgArray,0);
+ if (getProgArray[0] == GL.GL_FALSE) {
+ gl.glGetProgramiv(progID,GL.GL_INFO_LOG_LENGTH,getProgArray,0);
+ int logLength = getProgArray[0];
+ byte[] logArray = new byte[logLength];
+ gl.glGetProgramInfoLog(progID,logLength,getProgArray,0,logArray,0);
+ String log = new String(logArray);
+ throw new LightingException("Shader Program could not link. Log:\n"+log);
+ }
+
+ } else {
+ progID = gl.glCreateProgramObjectARB();
+ int vertID = gl.glCreateShaderObjectARB(GL.GL_VERTEX_SHADER_ARB);
+ int fragID = gl.glCreateShaderObjectARB(GL.GL_FRAGMENT_SHADER_ARB);
+
+ gl.glShaderSourceARB(vertID,vertSource.length,vertSource,vertLengths,0);
+ gl.glShaderSourceARB(fragID,fragSource.length,fragSource,fragLengths,0);
+
+ gl.glCompileShaderARB(vertID);
+ gl.glCompileShaderARB(fragID);
+
+ gl.glAttachObjectARB(progID,vertID);
+ gl.glAttachObjectARB(progID,fragID);
+
+ gl.glLinkProgramARB(progID);
+
+ int[] getProgArray = new int[1];
+ gl.glGetObjectParameterivARB(progID,GL.GL_OBJECT_LINK_STATUS_ARB,getProgArray,0);
+ if (getProgArray[0] == GL.GL_FALSE) {
+ gl.glGetObjectParameterivARB(progID,GL.GL_OBJECT_INFO_LOG_LENGTH_ARB,getProgArray,0);
+ int logLength = getProgArray[0];
+ byte[] logArray = new byte[logLength];
+ gl.glGetInfoLogARB(progID,logLength,getProgArray,0,logArray,0);
+ String log = new String(logArray);
+ throw new LightingException("Shader Program could not link. Log:\n"+log);
+ }
+ }
+ */
+
+ boolean builtin;
+ int progID;
+
+ if(gl.isFunctionAvailable("glCreateProgram"))
+ builtin = true;
+ else if (gl.isFunctionAvailable("glCreateProgramObjectARB"))
+ builtin = false;
+ else
+ throw new LightingException("Could not generate Shader for Light - GLSL Shaders not supported by this GL Context");
+
+ if(builtin) {
+ progID = gl.glCreateProgram();
+ //generate the other 7 shaders so that the numbers are in order
+ for (int currID = 1+progID; currID < (progID+8); ++currID) {
+ int result = gl.glCreateProgram();
+ if (result != currID)
+ throw new LightingException("Couldn't generate shader programs in numerical order - can't use Phong Shading");
+ }
+
+ int vertID = gl.glCreateShader(GL.GL_VERTEX_SHADER);
+ String[] vertSource = generatePhongVertexShaderSource();
+ gl.glShaderSource(vertID,vertSource.length,vertSource,generateShaderLengths(vertSource),0);
+
+
+ //generate program for each light and compile and link
+ for (int currID = progID;currID < (8+progID);++currID) {
+
+ int fragID = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
+ String[] fragSource = generatePhongFragmentShaderSource(currID-progID);
+ gl.glShaderSource(fragID,fragSource.length,fragSource,generateShaderLengths(fragSource),0);
+
+ gl.glCompileShader(vertID);
+ gl.glCompileShader(fragID);
+
+ gl.glAttachShader(currID,vertID);
+ gl.glAttachShader(currID,fragID);
+
+ gl.glLinkProgram(currID);
+
+ int[] getProgArray = new int[1];
+ gl.glGetProgramiv(currID,GL.GL_LINK_STATUS,getProgArray,0);
+ if (getProgArray[0] == GL.GL_FALSE) {
+ gl.glGetProgramiv(currID,GL.GL_INFO_LOG_LENGTH,getProgArray,0);
+ int logLength = getProgArray[0];
+ byte[] logArray = new byte[logLength];
+ gl.glGetProgramInfoLog(currID,logLength,getProgArray,0,logArray,0);
+ String log = new String(logArray);
+ throw new LightingException("Shader Program could not link. Log:\n"+log);
+ }
+ }
+ } else {
+ progID = gl.glCreateProgramObjectARB();
+ //generate the other 7 shaders so that the numbers are in order
+ for (int currID = 1+progID; currID < (progID+8); ++currID) {
+ int result = gl.glCreateProgramObjectARB();
+ if (result != currID)
+ throw new LightingException("Couldn't generate shader programs in numerical order - can't use Phong Shading");
+ }
+
+ int vertID = gl.glCreateShaderObjectARB(GL.GL_VERTEX_SHADER_ARB);
+ String[] vertSource = generatePhongVertexShaderSource();
+ gl.glShaderSourceARB(vertID,vertSource.length,vertSource,generateShaderLengths(vertSource),0);
+
+ //TODO: do this in a way that doesn't depend on the numbers being in order
+ //generate program for each light and compile and link
+ for (int currID = progID;currID < (8+progID);++currID) {
+
+ int fragID = gl.glCreateShaderObjectARB(GL.GL_FRAGMENT_SHADER_ARB);
+ String[] fragSource = generatePhongFragmentShaderSource(currID-progID);
+ gl.glShaderSourceARB(fragID,fragSource.length,fragSource,generateShaderLengths(fragSource),0);
+
+ gl.glCompileShaderARB(vertID);
+ gl.glCompileShaderARB(fragID);
+
+ gl.glAttachObjectARB(currID,vertID);
+ gl.glAttachObjectARB(currID,fragID);
+
+ gl.glLinkProgramARB(currID);
+
+ int[] getProgArray = new int[1];
+ gl.glGetObjectParameterivARB(currID,GL.GL_OBJECT_LINK_STATUS_ARB,getProgArray,0);
+ if (getProgArray[0] == GL.GL_FALSE) {
+ gl.glGetObjectParameterivARB(currID,GL.GL_OBJECT_INFO_LOG_LENGTH_ARB,getProgArray,0);
+ int logLength = getProgArray[0];
+ byte[] logArray = new byte[logLength];
+ gl.glGetInfoLogARB(currID,logLength,getProgArray,0,logArray,0);
+ String log = new String(logArray);
+ throw new LightingException("Shader Program could not link. Log:\n"+log);
+ }
+ }
+ }
+
+ shaderProgNums.put(gl,progID);
+ shaderBuiltin.put(gl, builtin);
+ }
+
+ /**
+ * Removes the Phong Shader program from the current GL Context
+ *
+ * @throws net.java.joglutils.lighting.LightingException if there is no Phong Shader
+ **/
+
+ public static void removePhongShader() throws LightingException {
+ removePhongShader(javax.media.opengl.glu.GLU.getCurrentGL());
+ }
+
+ /**
+ * Removes the Phong Shader program from the specified GL Context
+ *
+ * @param gl the OpenGL context to remove the Phong shader program from
+ * @throws net.java.joglutils.lighting.LightingException if there is no Phong Shader initialized on this context
+ */
+ public static void removePhongShader(GL gl) throws LightingException {
+ if (shaderBuiltin.containsKey(gl)) {
+ int progID = shaderProgNums.remove(gl);
+ if(shaderBuiltin.remove(gl)) {
+ java.nio.IntBuffer intBuff = java.nio.IntBuffer.allocate(3);
+ for (int currID = progID; currID < (8+progID); ++currID) {
+ gl.glGetAttachedShaders(currID,2,intBuff,intBuff);
+ if (intBuff.get() != 2)
+ throw new LightingException("More than 2 shaders attached to the Light phong shader program. Program ID Number:"+progID);
+
+ gl.glDeleteShader(intBuff.get());
+ gl.glDeleteShader(intBuff.get());
+
+ gl.glDeleteProgram(currID);
+ intBuff.clear();
+ }
+ } else {
+ java.nio.IntBuffer intBuff = java.nio.IntBuffer.allocate(3);
+ for (int currID = progID; currID < (8+progID); ++currID) {
+ gl.glGetAttachedObjectsARB(currID,2,intBuff,intBuff);
+ if (intBuff.get() != 2)
+ throw new LightingException("More than 2 shaders attached to the Light phong shader program. Program ID Number:"+progID);
+
+ gl.glDeleteObjectARB(intBuff.get());
+ gl.glDeleteObjectARB(intBuff.get());
+
+ gl.glDeleteObjectARB(currID);
+ intBuff.clear();
+ }
+ }
+ } else
+ throw new LightingException("Tried to remove Light phong shader on a GL Context with no phong shader");
+ }
+
//----------- Private internal functions/methods below this point------------
private static boolean isLightNumberValid(GL gl ,int lightNumber) {
return (lightNumber > -1 && lightNumber < maxNumberOfLightsInGL(gl));
@@ -767,6 +1150,7 @@ public class Light {
return (!lights[lightNumber]);
}
+
private static int findAndAssignFreeLightNumber(GL gl) {
boolean[] lights = assignedLights.get(gl);
if (lights == null) {
@@ -800,6 +1184,7 @@ public class Light {
assignedLights.put(gl,lights);
}
+
private static void unassignLightNumber(GL gl, int lightNumber) {
//No range checking
boolean[] lights = assignedLights.get(gl);
@@ -807,4 +1192,56 @@ public class Light {
assignedLights.put(gl,lights);
}
+ private static String[] generatePhongFragmentShaderSource(int lightNumber) {
+ String[] fragSource = {
+ "varying vec3 normalEye;\n",
+ "varying vec3 positionEye;\n",
+ "uniform bool ambMatCol;\n",
+ "uniform bool diffMatCol;\n",
+ "\n",
+ "void main()\n",
+ "{\n",
+ "\n",
+ "vec3 N = normalize (normalEye);\n",
+ "vec3 L = normalize (gl_LightSource["+lightNumber+"].position.xyz);\n",
+ "vec3 E = normalize (-positionEye);\n",
+ "vec3 H = normalize (L + E);\n",
+ "\n",
+ "vec4 ambientColor = (ambMatCol ? gl_Color : gl_FrontMaterial.ambient ) * (gl_LightSource["+lightNumber+"].ambient+gl_LightModel.ambient);\n",
+ "vec4 diffuseColor = (diffMatCol ? gl_Color : gl_FrontMaterial.diffuse ) * gl_LightSource["+lightNumber+"].diffuse * max (dot (N, L), 0.0);\n",
+ //"vec4 ambientColor = gl_FrontMaterial.ambient * (gl_LightSource["+lightNumber+"].ambient+gl_LightModel.ambient);\n",
+ //"vec4 diffuseColor = gl_FrontMaterial.diffuse * gl_LightSource["+lightNumber+"].diffuse * max (dot (N, L), 0.0);\n",
+ //"vec4 ambientColor = gl_Color * (gl_LightSource["+lightNumber+"].ambient+gl_LightModel.ambient);\n",
+ //"vec4 diffuseColor = gl_Color * gl_LightSource["+lightNumber+"].diffuse * max (dot (N, L), 0.0);\n",
+ "vec4 specularColor = gl_FrontMaterial.specular * gl_LightSource["+lightNumber+"]. specular * pow (max (dot (N, H), 0.0), gl_FrontMaterial.shininess);\n",
+ "gl_FragColor = ambientColor + diffuseColor + specularColor;\n",
+ "}\n"
+ };
+ return fragSource;
+ }
+
+ private static String[] generatePhongVertexShaderSource() {
+ final String[] vertSource={
+ "varying vec3 normalEye;\n",
+ "varying vec3 positionEye;\n",
+ "\n",
+ "void main()\n",
+ "{\n",
+ "normalEye = gl_NormalMatrix * gl_Normal;\n",
+ "positionEye = (gl_ModelViewMatrix * gl_Vertex).xyz;\n",
+ "gl_Position = ftransform ();\n",
+ "gl_FrontColor = gl_Color;\n",
+ "}\n"
+ };
+ return vertSource;
+ }
+
+ private static int[] generateShaderLengths(String[] shaderSource) {
+ int[] vertLengths = new int[shaderSource.length];
+ for (int i=0; i < vertLengths.length;++i)
+ vertLengths[i] = shaderSource[i].length();
+
+ return vertLengths;
+ }
+
}