No promises on my code being 100% correct but it works on my system. And Ken if you wanted to include this code or any derivative of it into the jogl demos by all means feel free to.
import java.awt.*;
import java.awt.event.*;
import java.nio.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
import com.sun.opengl.util.*;
public class SimpleFBODemo implements GLEventListener
{
private static Frame frame;
private static GLCanvas canvas;
private static int height = 600;
private static int width = 800;
private IntBuffer texture;
private IntBuffer fbo;
private IntBuffer depth;
public static void main(String args[])
{
frame = new Frame("Super Simple JOGL FBO Demo");
frame.setSize(width, height);
SimpleFBODemo dc = new SimpleFBODemo();
canvas = new GLCanvas();
canvas.addGLEventListener(dc);
frame.add(canvas);
frame.setVisible(true);
final Animator animator = new Animator(canvas);
frame.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{animator.stop(); System.exit(0);}
});
animator.start();
}
public SimpleFBODemo(){}
public void displayChanged(GLAutoDrawable drawable, boolean arg1, boolean arg2){}
public void reshape(GLAutoDrawable drawable, int arg1, int arg2, int arg3, int arg4){}
public void init(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
GLU glu = new GLU();
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(75.0f, 1.0, 1.0f, 100.0f);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
initializeFBO(drawable);
}
public void initializeFBO(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
fbo = BufferUtil.newIntBuffer(1);
depth = BufferUtil.newIntBuffer(1);
texture = BufferUtil.newIntBuffer(1);
gl.glGenFramebuffersEXT(1, fbo);
gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, fbo.get(0));
// !!! Don't mess with stencil or combined depth/stencil
// !!! until you really know what you're doing.
// !!! They're poorly supported at the moment.
gl.glGenRenderbuffersEXT(1, depth);
gl.glBindRenderbufferEXT(GL.GL_RENDERBUFFER_EXT, depth.get(0));
gl.glRenderbufferStorageEXT(GL.GL_RENDERBUFFER_EXT, GL.GL_DEPTH_COMPONENT24, width, height);
gl.glBindRenderbufferEXT(GL.GL_RENDERBUFFER_EXT, 0);
gl.glFramebufferRenderbufferEXT(GL.GL_FRAMEBUFFER_EXT, GL.GL_DEPTH_ATTACHMENT_EXT, GL.GL_RENDERBUFFER_EXT, depth.get(0));
gl.glGenTextures(1, texture);
gl.glBindTexture(GL.GL_TEXTURE_2D, texture.get(0));
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, width, height, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, null);
//Just for good measure, not actually used yet
gl.glFramebufferTexture2DEXT(GL.GL_FRAMEBUFFER_EXT, GL.GL_COLOR_ATTACHMENT0_EXT, GL.GL_TEXTURE_2D, texture.get(0), 0);
gl.glBindTexture(GL.GL_TEXTURE_2D, 0);
int status = gl.glCheckFramebufferStatusEXT(GL.GL_FRAMEBUFFER_EXT);
if(status != 0x8CD5)
{
if(status == 0x8CD6)
{
System.err.println("FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT");
}
else if(status == 0x8CD7)
{
System.err.println("FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT");
}
else if(status == 0x8CD9)
{
System.err.println("FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT");
}
else if(status == 0x8CDA)
{
System.err.println("FRAMEBUFFER_INCOMPLETE_FORMATS_EXT");
}
else if(status == 0x8CDB)
{
System.err.println("FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT");
}
else if(status == 0x8CDC)
{
System.err.println("FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT");
}
else if(status == 0x8CDD)
{
System.err.println("FRAMEBUFFER_UNSUPPORTED_EXT");
}
else
{
System.err.println("Unknown framebuffer error: " + Integer.toHexString(status));
}
}
//Bind back to the primary display
gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);
}
public void display(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
drawToFBO(drawable);
drawToPrimary(drawable);
}
public void drawToFBO(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
GLUT glut = new GLUT();
//Need to disable the texture, and either approach works
gl.glDisable(GL.GL_TEXTURE_2D);//Disable texturing
//gl.glBindTexture(GL.GL_TEXTURE_2D, 0);//Bind to a different texture
gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, fbo.get(0));
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);//Black
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
//Can actually do what ever drawing you wanted here
//but I'm trying to keep it simple
gl.glLineWidth(5.0f);//Make the sphere a little easier to see
gl.glColor3f(1.0f, 1.0f, 0.0f);
//Actual drawing
gl.glPushMatrix();
gl.glTranslatef(0.0f, 0.0f, -4.0f);
glut.glutWireSphere(2.5f, 20, 20);
gl.glPopMatrix();
}
public void drawToPrimary(GLAutoDrawable drawable)
{
GL gl = drawable.getGL();
gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);
gl.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);//Blue
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glPushMatrix();
gl.glTranslatef(0.0f, 0.0f, -4.0f);
gl.glRotatef(45.0f, 0.0f, 1.0f, 0.0f);//Just to illustrate that it's texturing
//Need to bind and enable the texture as per normal
gl.glBindTexture(GL.GL_TEXTURE_2D, texture.get(0));
gl.glEnable(GL.GL_TEXTURE_2D);
//Can actually do what ever drawing you wanted here
//but I'm trying to keep it simple
gl.glBegin(GL.GL_QUADS);
gl.glColor3f(0.0f, 1.0f, 0.0f);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, 0.0f);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex3f(1.0f, -1.0f, 0.0f);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex3f(1.0f, 1.0f, 0.0f);
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex3f(-1.0f, 1.0f, 0.0f);
gl.glEnd();
gl.glPopMatrix();
}
}