Class:
import java.nio.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.GLU;
import com.sun.opengl.util.BufferUtil;
public class Texture2DProblem implements GLEventListener{
public static void main(String[] argv) throws Exception{
System.out.println("\nresults of GL_TEXTURE_RECTANGLE_ARB: ");
System.out.println("============================");
Texture2DProblem card = new Texture2DProblem(false);
card.pBuffer.display();
card.pBuffer.destroy();
System.out.println("\nresults of GL_TEXTURE_2D: ");
System.out.println("============================");
card = new Texture2DProblem(true);
card.pBuffer.display();
card.pBuffer.destroy();
}
final int textureTarget;
final String texUniform;
final String texFunc;
final GLPbuffer pBuffer;
static final int WDITH = 10; // changing this, changes the amount of screw-up
static final int HEIGHT = 1;
static final int TEX_UNIT_NO = 0; // texture units sequential, so offset
static final int FBO_ATTACHMENT = GL.GL_COLOR_ATTACHMENT0_EXT;
public Texture2DProblem(boolean isNPO2){
if (isNPO2) {
textureTarget = GL.GL_TEXTURE_2D;
texUniform = " sampler2D ";
texFunc = "texture2D";
} else {
textureTarget = GL.GL_TEXTURE_RECTANGLE_ARB;
texUniform = " sampler2DRect ";
texFunc = "texture2DRect";
}
GLCapabilities caps = new GLCapabilities();
caps.setDoubleBuffered(false);
// using fbo for all rendering, so get minimum sized pbuffer
pBuffer = GLDrawableFactory.getFactory().createGLPbuffer(caps, null, 1, 1, null);
// not thread safe to let 'this' escape in constructor, do not do in production
pBuffer.addGLEventListener(this);
}
public void init(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
// gl = new TraceGL(gl, System.err);
int shaderId = createFragmentShader(gl,
"uniform " + texUniform + " texNm;" +
"\nvoid main() {" +
"\n vec4 tCoords = floor(gl_TexCoord[0]);" +
"\n vec4 texture = " + texFunc + "(texNm, vec2(tCoords) );" +
"\n texture.x = tCoords.x;" +
"\n gl_FragColor = texture;"+
"\n}",
true);
int prgmId = createAttachLinkUseProgram(gl, new int[]{shaderId});
// load identity texture, and associate with sampler & bind to texture unit
int texId = loadTexture(gl, get4ElementIdentityBuffer(WDITH, HEIGHT) );
associateTexture(gl, prgmId, TEX_UNIT_NO, "texNm", texId);
// create and assign FBO to above texture, can get away with only 1 fbo,
// since only reading the same texel as writing
int[] fb = new int[1];
gl.glGenFramebuffersEXT(1, fb, 0);
gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, fb[0]);
gl.glFramebufferTexture2DEXT(GL.GL_FRAMEBUFFER_EXT, FBO_ATTACHMENT, textureTarget, texId, 0);
}
public void display(GLAutoDrawable drawable) {
GL gl = drawable.getGL();
// gl = new TraceGL(gl, System.err);
renderQuad(gl, FBO_ATTACHMENT, WDITH, HEIGHT);
// copy Attachment to a float buffer
FloatBuffer buf = BufferUtil.newFloatBuffer(4 * WDITH * HEIGHT);
gl.glReadBuffer (FBO_ATTACHMENT);
gl.glReadPixels(0, 0, WDITH, HEIGHT, GL.GL_RGBA, GL.GL_FLOAT, buf);
// read thru float buffer and display results
String coord = "Frag X coord : ";
String value = "Texture Value: ";
float[] pix = new float[4];
for (int w = 0; w < WDITH; w++) {
buf.get(pix);
coord += ((w> 0) ? ", " : "") + pix[0];
value += ((w> 0) ? ", " : "") + pix[1];
}
System.out.println(coord);
System.out.println(value);
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {}
public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}
int createFragmentShader(GL gl, String source, boolean display){
int shaderID = gl.glCreateShader(GL.GL_FRAGMENT_SHADER);
String[] srcArray = source.split("\n");
int count = srcArray.length;
int[] lengths = new int[count];
for (int i = 0; i < count; i++) {
if (display) System.out.println(srcArray[i]);
lengths[i] = srcArray[i].length();
}
gl.glShaderSource(shaderID, count, srcArray, lengths, 0);
gl.glCompileShader(shaderID);
return shaderID;
}
int createAttachLinkUseProgram(GL gl, int[] shaderIDs){
// create the program
int prgmID = gl.glCreateProgram();
// attach each of the shaders
for(int i = 0; i < shaderIDs.length; i++){
gl.glAttachShader(prgmID, shaderIDs[i] );
}
//link & use the program
gl.glLinkProgram(prgmID);
gl.glUseProgram(prgmID);
return prgmID;
}
int loadTexture(GL gl, FloatBuffer buf){
int[] texID = new int[1];
// create a new texture name
gl.glGenTextures(1, texID, 0);
// bind the texture name to a texture target
gl.glBindTexture(textureTarget, texID[0]);
gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MIN_FILTER, GL.GL_NEAREST);
gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST);
gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP);
gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP);
gl.glTexImage2D(textureTarget, 0, GL.GL_RGBA32F_ARB, WDITH, HEIGHT, 0, GL.GL_RGBA, GL.GL_FLOAT, buf);
gl.glEnable(textureTarget);
return texID[0];
}
void associateTexture(GL gl, int prgmID, int unitNo, String samplerNm, int textureID) {
int sampler = gl.glGetUniformLocation(prgmID, samplerNm);
gl.glUniform1i(sampler, unitNo);
gl.glActiveTexture(GL.GL_TEXTURE0 + unitNo);
gl.glBindTexture(textureTarget, textureID );
}
FloatBuffer get4ElementIdentityBuffer(int width, int height) {
int nTexels = width * height;
int tVals = 4 * nTexels;
FloatBuffer buffer = BufferUtil.newFloatBuffer(tVals);
for (int i = 0; i < nTexels; i++)
buffer.put(new float[] {i, i, i, i} );
buffer.rewind();
return buffer;
}
void renderQuad(GL gl, int buffer, int width, int height){
gl.glViewport(0, 0, width, height);
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
(new GLU()).gluOrtho2D(0, width, 0, height);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
// assign buffer to render
gl.glDrawBuffer(buffer);
// ensure Texture unit 0 has the coordinates, explicitly
gl.glBegin(GL.GL_QUADS);
gl.glTexCoord2i(0 , 0 ); gl.glVertex2i(0 , 0 );
gl.glTexCoord2i(width, 0 ); gl.glVertex2i(width, 0 );
gl.glTexCoord2i(width, height); gl.glVertex2i(width, height);
gl.glTexCoord2i(0 , height); gl.glVertex2i(0 , height);
gl.glEnd();
}
}