There are some minor problems in your code. For starters, your glShaderSourceARB arguments are wrong. You have to give the number of strings in the String[] as second argument and I don’t know if you can use null as fourth argument, since this assumes, that the strings are null-terminated (which java strings afaik aren’t).
Another problem might be samplerRect/textureRect, because they don’t appear in the GLSL standard (you’ll need an NPOT extension).
The next problem is that you are trying to set the uniform variable “test”, which isn’t defined in your shader (it is called BaseImage in shader[0]).
At last, you might need to bind a texture to the desired texture units before rendering your quad.
Here is a working template:
package net.highteq.jogl;
import com.sun.opengl.util.Animator;
import com.sun.opengl.util.texture.Texture;
import com.sun.opengl.util.texture.TextureIO;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import static javax.media.opengl.GL.*;
/**
* SimpleShaderTemplate.java
* @author Mathias 'cylab' Henze
*/
public class SimpleShaderTemplate implements GLEventListener
{
private GLU glu = new GLU();
// Hold the shader program for later use
private int program;
// Holds the texture object for later use
private int textureID;
public static void main(String[] args)
{
Frame frame = new Frame("Simple JOGL Application");
GLCanvas canvas = new GLCanvas();
canvas.addGLEventListener(new SimpleShaderTemplate());
frame.add(canvas);
frame.setSize(640, 480);
final Animator animator = new Animator(canvas);
frame.addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent e)
{
// Run this on another thread than the AWT event queue
// so that Animator.stop() completes before exiting
new Thread(new Runnable()
{
public void run()
{
animator.stop();
System.exit(0);
}
}).start();
}
});
frame.setLocationRelativeTo(null);
frame.setVisible(true);
animator.start();
}
public void init(GLAutoDrawable drawable)
{
// drawable.setGL(new DebugGL(drawable.getGL()));
GL gl = drawable.getGL();
// You won't get far without error checking ;)
String errors = null;
try
{
// Load some texture
Texture texture = TextureIO.newTexture(SimpleShaderTemplate.class.getResource("texture.png"), false, "png");
// Store the OpenGL texture object ID for later use
textureID = texture.getTextureObject();
}
catch (Exception ex)
{
Logger.getLogger(SimpleShaderTemplate.class.getName()).log(Level.SEVERE, null, ex);
}
// This is the shader source. For simplicity just use a single concatenated string
String[] shader =
{
// This variable specifies the texture unit to use, called "sampler" in GLSL
"uniform sampler2D texUnit;\n" +
// main() is called for every pixel on screen (called "fragment" in GLSL) while rasterizing
"void main(void)\n" +
"{\n" +
// The gl_TexCoord array is a build in GLSL variable that holds the glTexCoordXX() values
" vec2 texCoord = gl_TexCoord[0].xy;\n" +
// texture2D() gets a texel from the texture unit at the given location
" vec4 texel = texture2D(texUnit, texCoord);\n" +
// Now assign the texel to be the current pixels output color.
// Mask out green, to see that the shader is indeed used (vec4 is r,g,b,a)
" gl_FragColor = texel * vec4(1.0, 0.0, 1.0, 1.0);\n" +
"}\n"
};
// Since java Strings aren't 0-terminated, store the length for submission to glShaderSource
// (maybe this unnecessary and JOGL implicitly 0-terminates the Strings, but you never know)
int[] lengths = { shader[0].length() };
// Create and store a shader program
program = gl.glCreateProgramObjectARB();
// Create the fragment shader object
int frag = gl.glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
// Tell the shader program to use the fragment shader
gl.glAttachObjectARB(program, frag);
// Copy the shader source to GL implementation.
// You need the amount of Strings, the String[] and an array of the Strings lenghts
gl.glShaderSourceARB(frag, shader.length, shader, lengths, 0);
// Compile the shader
gl.glCompileShaderARB(frag);
// Check for compile errors
if ((errors = getGLErrorLog(gl, frag)) != null)
throw new RuntimeException("Compile error\n" + errors);
// Link the program
gl.glLinkProgramARB(program);
// Check for link errors
if ((errors = getGLErrorLog(gl, program)) != null)
throw new RuntimeException("Link error\n" + errors);
// Use the program, to be able to assign values to the uniforms
gl.glUseProgramObjectARB(program);
// Get the location of the texUnit uniform, so we can assign a value to it
int texUnit = gl.glGetUniformLocationARB(program, "texUnit");
// Assign the GL_TEXTURE0 unit to the uniform variable
// CAUTION: you need to set the plain texture _unit_ _number_,
// not the GL constant nor the textur object here!!!
gl.glUniform1iARB(texUnit, 0);
// Enable VSync
gl.setSwapInterval(1);
// Setup the clear color
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}
public void display(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
// Clear the drawing area
gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset the current matrix to the "identity"
gl.glLoadIdentity();
// Move the "drawing cursor" around
gl.glTranslatef(0.0f, 0.0f, -3.0f);
// Choose the current texture unit
gl.glActiveTexture(GL_TEXTURE0);
// Bind a texture to the current texture unit
gl.glBindTexture(GL_TEXTURE_2D, textureID);
// Enable the shader program
gl.glUseProgramObjectARB(program);
// Draw a quad to be textured
gl.glBegin(GL_QUADS);
{
gl.glTexCoord2f(0, 0);
gl.glVertex3f(-1, -1, 0);
gl.glTexCoord2f(1, 0);
gl.glVertex3f(1, -1, 0);
gl.glTexCoord2f(1, 1);
gl.glVertex3f(1, 1, 0);
gl.glTexCoord2f(0, 1);
gl.glVertex3f(-1, 1, 0);
}
gl.glEnd();
// Disable all shaders
gl.glUseProgramObjectARB(0);
// Flush all drawing operations to the graphics card
gl.glFlush();
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
{
GL gl = drawable.getGL();
if (height <= 0)
{ // avoid a divide by zero error!
height = 1;
}
final float h = (float) width / (float) height;
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(45.0f, h, 1.0, 20.0);
gl.glMatrixMode(GL_MODELVIEW);
gl.glLoadIdentity();
}
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged)
{
}
// Checks for arbitrary GL errors. Could also be accomplished by enabling the DebugGL pipeline
private String getGLError(GL gl)
{
boolean hasError = false;
String message = "";
for (int glErr = gl.glGetError(); glErr != GL.GL_NO_ERROR; glErr = gl.glGetError())
{
message += (hasError ? "\n" : "") + glu.gluErrorString(glErr);
hasError = true;
}
return hasError ? message : null;
}
// Checks the info log for compile/link errors
private String getGLErrorLog(GL gl, int obj)
{
boolean hasError = false;
int[] infologLength = {0};
int[] charsWritten = {0};
byte[] infoLog;
String message = "";
String error = getGLError(gl);
if (error != null)
{
message += error;
hasError = true;
}
gl.glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB, infologLength, 0);
error = getGLError(gl);
if (error != null)
{
message += (hasError ? "\n" : "") + error;
hasError = true;
}
if (infologLength[0] > 1)
{
infoLog = new byte[infologLength[0]];
gl.glGetInfoLogARB(obj, infologLength[0], charsWritten, 0, infoLog, 0);
message += (hasError ? "\n" : "") + "InfoLog:\n" + new String(infoLog);
hasError = true;
}
error = getGLError(gl);
if (error != null)
{
message += (hasError ? "\n" : "") + error;
hasError = true;
}
return hasError ? message : null;
}
}
Just put a texture.png beside the java class and off you go.
Edit: forgot to remove my failure-test :