I’m trying to shoehorn JOGL into doing some 2D compositing for me. The clear operation works correctly; unfortunately, whenever I render to my frame buffer object after that, instead of an overlay operation occuring it seems a multiply is done instead. I’ve fiddled with lots of parameters, but can’t stop this.
The depth test should always pass, so there really isn’t a need for a depth buffer, but the problem happens with or without it. The blend function should be glBlend(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
What’s the right way to draw new images over top of whatever’s in my back buffer?
public class FBOPanel extends javax.swing.JPanel implements GLEventListener
{
private GLCanvas canvas;
int frameBufferId;
int depthId;
int texId;
int destWidth = 512;
int destHeight = 256;
/** Creates new form TexRectanglePanel */
public FBOPanel()
{
initComponents();
}
public void addNotify()
{
super.addNotify();
canvas = new GLCanvas(new GLCapabilities());
canvas.addGLEventListener(this);
add(canvas, BorderLayout.CENTER);
}
public void init(GLAutoDrawable gLAutoDrawable)
{
GL gl = gLAutoDrawable.getGL();
//-----------------------------------------------
IntBuffer ibuf = BufferUtil.newIntBuffer(1);
gl.glGenFramebuffersEXT(1, ibuf);
frameBufferId = ibuf.get(0);
ibuf.rewind();
gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, frameBufferId);
gl.glGenRenderbuffersEXT(1, ibuf);
depthId = ibuf.get(0);
ibuf.rewind();
gl.glGenTextures(1, ibuf);
texId = ibuf.get(0);
ibuf.rewind();
gl.glBindRenderbufferEXT(GL.GL_RENDERBUFFER_EXT, depthId);
gl.glRenderbufferStorageEXT(GL.GL_RENDERBUFFER_EXT, GL.GL_DEPTH_COMPONENT,
destWidth, destHeight);
gl.glFramebufferRenderbufferEXT(GL.GL_FRAMEBUFFER_EXT,
GL.GL_DEPTH_ATTACHMENT_EXT, GL.GL_RENDERBUFFER_EXT, depthId);
ByteBuffer imgData = BufferUtil.newByteBuffer(destWidth * destHeight * 4);
gl.glEnable(GL.GL_TEXTURE_RECTANGLE_ARB);
gl.glBindTexture(GL.GL_TEXTURE_RECTANGLE_ARB, texId);
//Create empty texture
gl.glTexImage2D(GL.GL_TEXTURE_RECTANGLE_ARB, 0, GL.GL_RGBA,
destWidth, destHeight,
0, GL.GL_RGBA,
GL.GL_UNSIGNED_BYTE, imgData);
//Attach texture back buffer
gl.glFramebufferTexture2DEXT(GL.GL_FRAMEBUFFER_EXT,
GL.GL_COLOR_ATTACHMENT0_EXT, GL.GL_TEXTURE_RECTANGLE_ARB, texId, 0);
// gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE);
int status = gl.glCheckFramebufferStatusEXT (GL.GL_FRAMEBUFFER_EXT);
switch (status)
{
case GL.GL_FRAMEBUFFER_COMPLETE_EXT:
System.out.println("FrameBuffer Created");
break;
case GL.GL_FRAMEBUFFER_UNSUPPORTED_EXT:
System.out.println("FBO configuration unsupported");
break;
default:
System.out.println( "FBO programmer error" );
break;
}
}
public void display(GLAutoDrawable gLAutoDrawable)
{
GL gl = gLAutoDrawable.getGL();
gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, frameBufferId);
gl.glPushAttrib(GL.GL_ALL_ATTRIB_BITS);
gl.glViewport(0, 0, destWidth, destHeight);
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL.GL_PROJECTION);
{
gl.glLoadIdentity();
gl.glFrustum(-1, 1, -1, 1, 1.5, 20);
}
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glColor3f(1, 0, 1);
gl.glLoadIdentity();
GLU glu = new GLU();
glu.gluLookAt(0, 0, 5, 0, 0, 0, 0, 1, 0);
gl.glScalef(1.0f, 2.0f, 1.0f);
GLUT glut = new GLUT();
glut.glutWireCube(1);
gl.glFlush();
gl.glPopAttrib();
gl.glBindFramebufferEXT(GL.GL_FRAMEBUFFER_EXT, 0);
//Save image
ByteBuffer imgData = BufferUtil.newByteBuffer(destWidth * destHeight * 4);
gl.glGetTexImage(GL.GL_TEXTURE_RECTANGLE_ARB,
0, //Mipmap level
GL.GL_RGBA, GL.GL_UNSIGNED_BYTE,
imgData);
BufferedImage img = new BufferedImage(destWidth, destHeight, BufferedImage.TYPE_INT_ARGB);
imgData.rewind();
WritableRaster raster = img.getRaster();
for (int j = raster.getHeight() - 1; j >= 0; j--)
{
for (int i = 0; i < raster.getWidth(); i++)
{
raster.setSample(i, j, 0, imgData.get());
raster.setSample(i, j, 1, imgData.get());
raster.setSample(i, j, 2, imgData.get());
raster.setSample(i, j, 3, imgData.get());
}
}
try
{
ImageIO.write(img, "png", new File("fboImage.png"));
}
catch (IOException ex)
{
ex.printStackTrace();
}
}
public void reshape(GLAutoDrawable gLAutoDrawable, int i, int i0, int i1, int i2)
{
}
public void displayChanged(GLAutoDrawable gLAutoDrawable, boolean b, boolean b0)
{
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
private void initComponents()
{
setLayout(new java.awt.BorderLayout());
}// </editor-fold>
}