package org.newdawn.slick.tests.shader;
import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Image;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.opengl.shader.ShaderProgram;
import org.newdawn.slick.util.Log;
/**
* A simple shader test that blurs an image.
* @author davedes
*/
public class ShaderTestAdvanced extends BasicGame {
public static void main(String[] args) throws SlickException {
new AppGameContainer(new ShaderTestAdvanced(), 800, 600, false).start();
}
public ShaderTestAdvanced() {
super("Advanced Shader Test");
}
private Image logo;
private ShaderProgram blurHoriz, blurVert;
private String log;
private boolean shaderWorks, useBlur=true;
private boolean supported = false;
private float rot, radius=1.2f;
private GameContainer container;
private Image postImageA, postImageB;
private Graphics postGraphicsA, postGraphicsB;
@Override
public void init(GameContainer container) throws SlickException {
this.container = container;
logo = new Image("testdata/logo.png");
container.setClearEachFrame(false);
supported = ShaderProgram.isSupported();
if (supported) {
try {
//first we will try to create our offscreen image
//this may fail in very very rare cases if the user has no FBO/PBuffer support
postImageA = Image.createOffscreenImage(container.getWidth(), container.getHeight());
postGraphicsA = postImageA.getGraphics();
postImageB = Image.createOffscreenImage(container.getWidth(), container.getHeight());
postGraphicsB = postImageB.getGraphics();
String h = "testdata/shaders/hblur.frag";
String v = "testdata/shaders/vblur.frag";
String vert = "testdata/shaders/blur.vert";
blurHoriz = ShaderProgram.loadProgram(vert, h);
blurVert = ShaderProgram.loadProgram(vert, v);
shaderWorks = true;
//good idea to print/display the log anyways incase there are warnings..
log = blurHoriz.getLog()+"\n"+blurVert.getLog();
//note that strict mode is ENABLED so these uniforms must be active in shader
//set up our uniforms for horizontal blur...
blurHoriz.bind();
blurHoriz.setUniform1i("tex0", 0); //texture 0
blurHoriz.setUniform1f("resolution", container.getWidth()); //width of img
blurHoriz.setUniform1f("radius", radius);
//set up our uniforms for vertical blur...
blurVert.bind();
blurVert.setUniform1i("tex0", 0); //texture 0
blurVert.setUniform1f("resolution", container.getHeight()); //height of img
blurVert.setUniform1f("radius", radius);
ShaderProgram.unbindAll();
} catch (SlickException e) {
log = e.getMessage();
Log.error(log);
shaderWorks = false;
}
}
}
public void renderScene(GameContainer container, Graphics g) throws SlickException {
logo.setRotation(0f);
g.drawImage(logo, 100, 300);
logo.setRotation(rot);
g.drawImage(logo, 400, 200);
g.setColor(Color.white);
g.fillRect(450, 350, 100, 100);
}
@Override
public void render(GameContainer container, Graphics screenGraphics) throws SlickException {
screenGraphics.clear();
//for sake of example, only bother rendering if shader works
if (shaderWorks && useBlur) {
//1. first we render our scene without blur into an off-screen buffer
// this is just to be safe when using multiple contexts
Graphics.setCurrent(postGraphicsA);
postGraphicsA.clear();
// this is where we'd draw sprites, entities, etc.
renderScene(container, postGraphicsA);
// flush it after drawing
postGraphicsA.flush();
//if we were using a single pass (i.e. only horizontal blur) then we could render
//directly into the screen at this point. but since we are using two passes, we first need to
//sample from the normal texture, then blur it horizontally onto to another texture, then sample
//from the blurred texture as we blur it again (vertically) onto the screen.
//2. enable our first shader, the horizontal blur
blurHoriz.bind();
blurHoriz.setUniform1f("radius", radius);
//3. sample from A, render to B
Graphics.setCurrent(postGraphicsB);
postGraphicsB.clear();
postGraphicsB.fillRect(0, 0, 800, 600);
postGraphicsB.drawImage(postImageA, 0f, 0f);
postGraphicsB.flush();
blurHoriz.unbind();
//4. enable our second shader, the vertical blur
blurVert.bind();
blurVert.setUniform1f("radius", radius);
//5. sample from B, render to screen
Graphics.setCurrent(screenGraphics);
screenGraphics.drawImage(postImageB, 0, 0);
//flushing the screen graphics doesn't do anything, so it's unnecessary
//screenGraphics.flush();
//stop using shaders
ShaderProgram.unbindAll();
} else {
//simply render the scene to the screen
renderScene(container, screenGraphics);
}
screenGraphics.setColor(Color.white);
//now we can render on top of post processing (on screen)
if (shaderWorks)
screenGraphics.drawString("B to toggle blur" + (useBlur?" (enabled)":"") +
"\nUP/DOWN to change radius: "+radius, 10, 25);
else if (!supported)
screenGraphics.drawString("Your drivers do not support OpenGL Shaders, sorry!", 10, 25);
else
screenGraphics.drawString("Oops, shader didn't load!", 10, 25);
if (log!=null && log.trim().length()!=0)
screenGraphics.drawString("Shader Log:\n"+log, 10, 75);
}
@Override
public void update(GameContainer container, int delta) throws SlickException {
if (container.getInput().isKeyPressed(Input.KEY_B))
useBlur = !useBlur;
if (container.getInput().isKeyDown(Input.KEY_DOWN)) {
radius = Math.max(0.0f, radius-0.0003f*delta);
} else if (container.getInput().isKeyDown(Input.KEY_UP)) {
radius = Math.min(5f, radius+0.0003f*delta);
}
rot += 0.03f*delta;
}
}