Version 2 shader support.
This is more complex and different from the basic Xith shader support. Basically I have a base class
ShaderSupport that provide support and abstract methods. The
PulseShader class the extends this and provides settings for shader parameters and calculations for how the shader parameters updates etc. Go ahead and ask questions if you need to.
package hawk.shader;
import hawk.util.DebugLogger;
import hawk.util.HawkInterval;
import hawk.world.WorldManager;
import org.xith3d.base.Xith3DEnvironment;
import org.xith3d.loaders.shaders.impl.glsl.GLSLShaderLoader;
import org.xith3d.loop.UpdatingThread.TimingMode;
import org.xith3d.loop.opscheduler.Interval;
import org.xith3d.resources.ResourceLocator;
import org.xith3d.scenegraph.GLSLContext;
import org.xith3d.scenegraph.GLSLFragmentShader;
import org.xith3d.scenegraph.GLSLShaderProgram;
import org.xith3d.scenegraph.GLSLVertexShader;
import org.xith3d.scenegraph.Shape3D;
public abstract class ShaderSupport {
String vertexProgram = "per-pixel-lighting.glslvert";
String fragmentProgram = "per-pixel-lighting.glslvert";
Interval myInterval = null;
GLSLContext shaderProgram = null;
Shape3D shape = null;
public ShaderSupport(Shape3D shp) {
GLSLContext.setDebuggingEnabled(true);
shape = shp;
String msg = "start ShaderSupport ";
DebugLogger.getInstance().log(this.getClass().getName(), msg);
}
private GLSLContext loadShader(ResourceLocator resLoc) throws Exception {
// we will enable shader debugging to get some output in case of a
// shader bug...
GLSLContext.setDebuggingEnabled(true);
// to use shader programs we need to create
// GLSL{Vertex|Fragment}Shader's
// this time we'll use a Vertex Shader
GLSLVertexShader waverShader = GLSLShaderLoader.getInstance()
.loadVertexShader(resLoc.getResource(vertexProgram));
// very simple right?
// but that wasn't all ... we need to add this vertex shader to
// a GLSLShaderProgram to use it
GLSLContext shaderProg = new GLSLContext(new GLSLShaderProgram());
shaderProg.getProgram().addShader(waverShader);
// we'll load a fragmentshader too ... it's the very same procedure
GLSLFragmentShader heightcolorShader = GLSLShaderLoader.getInstance()
.loadFragmentShader(resLoc.getResource(fragmentProgram));
shaderProg.getProgram().addShader(heightcolorShader);
shaderProgram = shaderProg;
addVariables();
return (shaderProg);
}
public void createShaderProgramx() {
try {
shaderProgram = loadShader(ResourceLocator.getInstance());
// Appearance app = new Appearance();
// shape.setAppearance(app);
shape.getAppearance().setShaderProgramContext(shaderProgram);
} catch (Exception e) {
e.printStackTrace();
}
}
public void createShaderProgram() {
GLSLContext.setDebuggingEnabled(true);
shaderProgram = new GLSLContext(new GLSLShaderProgram());
GLSLShaderLoader loader = GLSLShaderLoader.getInstance();
try {
shaderProgram.getProgram().addShader(
loader.loadVertexShader(ResourceLocator.getInstance()
.getResource(vertexProgram)));
shaderProgram.getProgram().addShader(
loader.loadFragmentShader(ResourceLocator.getInstance()
.getResource(fragmentProgram)));
shaderProgram.getUniformParameters().setUniformVar("time", 10f);
shape.getAppearance().setShaderProgramContext(shaderProgram);
} catch (Exception e) {
e.printStackTrace();
}
}
public String getFragmentProgram() {
return fragmentProgram;
}
public void setFragmentProgram(String fragmentProgram) {
this.fragmentProgram = fragmentProgram;
}
public String getVertexProgram() {
return vertexProgram;
}
public void setVertexProgram(String vertexProgram) {
this.vertexProgram = vertexProgram;
}
public GLSLContext getShaderProgram() {
return shaderProgram;
}
public void setShaderProgram(GLSLContext shaderProgram) {
this.shaderProgram = shaderProgram;
}
//used for logging events
static int textCounter = 0;
public static String getNewIntervalID() {
String intervalName = "Shade-" + Integer.toString(textCounter++);
return intervalName;
}
abstract public void run() ;
public void run(final long delta) {
Xith3DEnvironment env = WorldManager.getInstance().getEnv();
env.getOperationScheduler().addInterval(
myInterval = new HawkInterval( env.getRenderLoop()
.getTimingMode().getFromMilliSeconds(delta),getNewIntervalID()) {
@Override
protected void onIntervalHit(long gameTime,
long frameTime, TimingMode timingMode) {
code(gameTime, frameTime, timingMode);
System.out.println("code "+delta+" "+frameTime);
}
});
}
//use implement this method to add parameters to shader
abstract public void addVariables();
//use this methos to process data to be used as shader parameter values
abstract public void code(long gameTime, long frameTime,
TimingMode timingMode);
}
PulseShader extends
ShaderSupport, defines parameter "
time" and "
baseMap". "
time" increments and affects the pulsing effect, "
baseMap" set set to "
0" which points to the base texture unit. The
code method updates "
time" from an interval, which is render safe. The constructor sets the fragment and vertex shader programs. Whereever you place these programs needs to be accessable to your resource support. See how this is done in the Xith shader examples.
package hawk.shader;
import hawk.util.DebugLogger;
import hawk.util.HawkInterval;
import hawk.world.WorldManager;
import java.util.ArrayList;
import java.util.Iterator;
import org.xith3d.base.Xith3DEnvironment;
import org.xith3d.loop.UpdatingThread.TimingMode;
import org.xith3d.scenegraph.Shape3D;
/*
* Pulsing shader to highlight mouse over shape
*/
public class PulseShader extends ShaderSupport {
//* color option, eah requires a unique shader at this point
public static final int RED = 1;
public static final int BLUE = 2;
/*
* active shader list used for cleanup
*/
static Object syncObject = new Object();
static ArrayList<PulseShader> shaders = new ArrayList<PulseShader>();
public PulseShader(int color, Shape3D shape) {
super(shape);
DebugLogger.getInstance().log("Pulse Shader ", "new shader");
//set vrtex shader
setVertexProgram("shader/hawkwind/pulse.glslvert");
//set fragment shader based on color
if (color == RED)
setFragmentProgram("shader/hawkwind/redpulse.glslfrag");
if (color == BLUE)
setFragmentProgram("shader/hawkwind/bluepulse.glslfrag");
//NOTE using "x" shader support
createShaderProgramx();
addToList(this);
}
/*
* track active shaders,
* set common value for shader parameters,
* and start shader operation
*/
private void addToList(PulseShader shd) {
if (shaders.size() == 0) {
shaders.add(shd);
run();
}
synchronized (syncObject) {
shaders.add(shd);
}
}
/*
* override shadersupport run(non-Javadoc)
* @see hawk.shader.ShaderSupport#run()
*/
public void run() {
Xith3DEnvironment env = WorldManager.getInstance().getEnv();
env.getOperationScheduler().addInterval(
myInterval = new HawkInterval(env.getRenderLoop()
.getTimingMode().getFromMilliSeconds(60L),
getNewIntervalID()) {
@Override
protected void onIntervalHit(long gameTime, long frameTime,
TimingMode timingMode) {
for (Iterator iterator = shaders.iterator(); iterator
.hasNext();) {
ShaderSupport shader = (ShaderSupport) iterator
.next();
shader.code(gameTime, frameTime, timingMode);
}
}
});
}
/*
* override shadersupport
* (non-Javadoc)
* @see hawk.shader.ShaderSupport#code(long, long, org.xith3d.loop.UpdatingThread.TimingMode)
*/
public void code(long gameTime, long frameTime, TimingMode timingMode) {
//this shader uses "time" parameterfor its effect
final float gameSeconds = timingMode.getSecondsAsFloat(gameTime);
shaderProgram.getUniformParameters().setUniformVar("time",
gameSeconds * 2);
}
@Override
public void addVariables() {
// here we'll send a variable to the shader to make our waves move
// notice that all setUniformVars use dynamic parameter lists
// we could set 20 floats here ... and would be able to aquire
// them in the shader
shaderProgram.getUniformParameters().setUniformVar("time", 0f);
shaderProgram.getUniformParameters().setUniformVar("baseMap", 0);
}
}
Vertex program "
shader/hawkwind/pulse.glslvert");
varying float y;
varying vec2 texCoord;
void main(void)
{
texCoord = gl_MultiTexCoord0.xy;
// get our y position
y = gl_Vertex.x;
// transform our vertex
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
Fragment programs, two ones that set different colors
"shader/hawkwind/redpulse.glslfrag"
varying float y;
uniform float time;
uniform sampler2D baseMap;
varying vec2 texCoord;
#define RATE_SCALE 10.0
void main(void)
{
float intensity;
intensity = sin( y + (time * RATE_SCALE));
intensity = clamp( intensity, 0.0, 1.0);
vec4 base = texture2D(baseMap, texCoord);
// vary color from white to green by varying red & blue
gl_FragColor = vec4( intensity,intensity, 1.0, 1.0);
}
"
shader/hawkwind/bluepulse.glslfrag"
varying float y;
uniform float time;
uniform sampler2D baseMap;
varying vec2 texCoord;
#define RATE_SCALE 10.0
void main(void)
{
float intensity;
intensity = sin( y + (time * RATE_SCALE));
intensity = clamp( intensity, 0.0, 1.0);
vec4 base = texture2D(baseMap, texCoord);
// vary color from white to green by varying red & blue
gl_FragColor = vec4( 1.0, 1.0, intensity,intensity );
}