Hey,
I found out some strange behaviour, shaders in my code work kind of wierd when you release them with ARBShaderObjects.glUseProgramObjectARB(0). In the example below after 2k ticks it starts releasing the shader in the render cycle, and as that happens, it wont apply the shaders at all even retroactively on the quad that already has been glEnded(in this case, no image is drawn on the quad). This is kind of wierd considering releasing after glEnd is suggested in most shader guides (e.g. http://lwjgl.org/wiki/index.php?title=GLSL_Shaders_with_LWJGL).
What is even more interesting but isnt demonstrated in my code here is, when i draw multiple objects with shaders and dont ever release them with ARBShaderObjects.glUseProgramObjectARB(0), just bind them, it works all good.
So, what exactly does ARBShaderObjects.glUseProgramObjectARB(0) do? Do I use it correctly? What causes this strange behaviour?
The first class is the main class that runs everything. Then I have a few utility classes that i wont post here (ShaderLoader,ImageLoader, I think you know what they do). The second class is the Shader class which is capable of loading and compiling the Shader, and some utility methods for setting up the shader and binding it.
package cz.witzany.gamev2.twlgui;
import static org.lwjgl.opengl.GL11.*;
import java.awt.Rectangle;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;
import cz.witzany.gamev2.graphics.shaders.Shader;
import cz.witzany.gamev2.graphics.shaders.ShaderLoader;
import cz.witzany.gamev2.graphics.shaders.SimpleImage;
import cz.witzany.gamev2.graphics.utils.ImageLoader;
public class TestCase implements Runnable {
int texture;
Shader shader;
int timeout = 0;
public static void main(String[] args) {
new TestCase().run();
}
@Override
public void run() {
initGL();
initObjects();
while (!Display.isCloseRequested()) {
glClear(GL11.GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-400, 400, -300, 300, 10, -10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
shader.bind();
shader.setTexture("colorMap", 0, texture);
shader.setUniformF("tx", 1/90.0f);
shader.setUniformF("ty", 1/90.0f);
shader.setUniformF("meshScale", 1.0f);
glScaled(90, -90, 1);
glBegin(GL11.GL_QUADS);
glTexCoord2f(0, 0);
glVertex2d(0, 0);
glTexCoord2f(1, 0);
glVertex2d(1, 0);
glTexCoord2f(1, 1);
glVertex2d(1, 1);
glTexCoord2f(0, 1);
glVertex2d(0, 1);
glEnd();
if(timeout > 2000)
shader.unbind();
timeout++;
Display.update();
}
}
private void initObjects() {
shader = ShaderLoader.loadShader("Data/Shaders/Sprite");
texture = ImageLoader.loadImage("Data/Textures/Sprites/Creeper/Creeper.png", new Rectangle());
}
private void initGL() {
try {
Display.setDisplayMode(new DisplayMode(800, 600));
Display.create();
} catch (LWJGLException e) {
e.printStackTrace();
System.exit(0);
}
glShadeModel(GL_SMOOTH);
glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT
| GL_STENCIL_BUFFER_BIT);
glDepthRange(1.0f, 0.0f);
glAlphaFunc(GL_GREATER, 0x00);
glDepthFunc(GL_GREATER);
glStencilFunc(GL_NEVER, 0x0, 0xFFFFFFFF);
glBlendFunc(GL_ZERO, GL_SRC_COLOR);
GL11.glViewport(0, 0, Display.getWidth(), Display.getHeight());
}
}
package cz.witzany.gamev2.graphics.shaders;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.ARBFragmentShader;
import org.lwjgl.opengl.ARBShaderObjects;
import org.lwjgl.opengl.ARBVertexShader;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL20;
public class Shader {
private static int activeShader = -1;
public int shader;
public int vertShader;
public int fragShader;
private boolean useShader;
public Shader(String shaderDir) {
File sDir = new File(shaderDir);
useShader = true;
if (!sDir.exists() || !sDir.isDirectory()) {
useShader = false;
return;
}
File vShader = new File(sDir, sDir.getName() + ".vert");
File fShader = new File(sDir, sDir.getName() + ".frag");
if (!vShader.exists() || !fShader.exists()) {
useShader = false;
return;
}
shader = ARBShaderObjects.glCreateProgramObjectARB();
if (shader == 0) {
useShader = false;
return;
}
vertShader = createShader(vShader.getAbsolutePath(),
ARBVertexShader.GL_VERTEX_SHADER_ARB);
fragShader = createShader(fShader.getAbsolutePath(),
ARBFragmentShader.GL_FRAGMENT_SHADER_ARB);
if (vertShader == 0 || fragShader == 0) {
useShader = false;
return;
}
ARBShaderObjects.glAttachObjectARB(shader, vertShader);
ARBShaderObjects.glAttachObjectARB(shader, fragShader);
ARBShaderObjects.glLinkProgramARB(shader);
if (GL20.glGetShader(shader, GL20.GL_LINK_STATUS) == GL11.GL_FALSE) {
printLogInfo(shaderDir, shader);
useShader = false;
return;
}
ARBShaderObjects.glValidateProgramARB(shader);
if (GL20.glGetShader(shader, GL20.GL_VALIDATE_STATUS) == GL11.GL_FALSE) {
printLogInfo(shaderDir, shader);
useShader = false;
return;
}
useShader = true;
System.out.println("Loaded shader " + shaderDir);
}
private int createShader(String filename, int type) {
int nshader = ARBShaderObjects.glCreateShaderObjectARB(type);
if (nshader == 0) {
return 0;
}
String code = "";
String line;
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
while ((line = reader.readLine()) != null) {
code += line + "\n";
}
reader.close();
} catch (Exception e) {
System.out.println("Fail reading vertex shading code");
return 0;
}
ARBShaderObjects.glShaderSourceARB(nshader, code);
ARBShaderObjects.glCompileShaderARB(nshader);
printLogInfo(filename, nshader);
if (GL20.glGetShader(nshader, GL20.GL_COMPILE_STATUS) == GL11.GL_FALSE)
return 0;
return nshader;
}
private boolean printLogInfo(String name, int obj) {
IntBuffer iVal = BufferUtils.createIntBuffer(1);
ARBShaderObjects.glGetObjectParameterARB(obj,
ARBShaderObjects.GL_OBJECT_INFO_LOG_LENGTH_ARB, iVal);
int length = iVal.get();
if (length > 1) {
// We have some info we need to output.
ByteBuffer infoLog = BufferUtils.createByteBuffer(length);
iVal.flip();
ARBShaderObjects.glGetInfoLogARB(obj, iVal, infoLog);
byte[] infoBytes = new byte[length];
infoLog.get(infoBytes);
String out = new String(infoBytes);
System.out.println(name + " log:\n" + out);
}
return true;
}
private int getUniformLocation(String name) {
int location = ARBShaderObjects.glGetUniformLocationARB(shader, name);
if (location == -1)
throw new RuntimeException(name + " not available");
return location;
}
public void setTexture(String name, int index, int pointer) {
int location = getUniformLocation(name);
GL13.glActiveTexture(GL13.GL_TEXTURE0 + index);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, pointer);
ARBShaderObjects.glUniform1iARB(location, index);
}
public synchronized void bind() {
if (activeShader == shader)
return;
if (useShader) {
//unbind();
ARBShaderObjects.glUseProgramObjectARB(shader);
activeShader = shader;
} else
System.out.println("warning, shader not used");
}
public void unbind() {
ARBShaderObjects.glUseProgramObjectARB(0);
}
public void setUniformF(String name, Float value){
int location = getUniformLocation(name);
ARBShaderObjects.glUniform1fARB(location, value);
}
}