diff --git a/core/src/processing/opengl/FrameBuffer.java b/core/src/processing/opengl/FrameBuffer.java index 27e0f87f5..21472a20c 100644 --- a/core/src/processing/opengl/FrameBuffer.java +++ b/core/src/processing/opengl/FrameBuffer.java @@ -76,13 +76,17 @@ public class FrameBuffer implements PConstants { this(parent, w, h, 1, 1, 0, 0, false, screen); } - FrameBuffer(PApplet parent, int w, int h, int samples, int colorBuffers, - int depthBits, int stencilBits, boolean packedDepthStencil, - boolean screen) { + FrameBuffer(PApplet parent) { this.parent = parent; pg = (PGraphicsOpenGL)parent.g; pgl = pg.pgl; context = pgl.createEmptyContext(); + } + + FrameBuffer(PApplet parent, int w, int h, int samples, int colorBuffers, + int depthBits, int stencilBits, boolean packedDepthStencil, + boolean screen) { + this(parent); glFbo = 0; glDepth = 0; @@ -230,6 +234,15 @@ public class FrameBuffer implements PConstants { return 0 < stencilBits; } + public static FrameBuffer wrap(PApplet parent, int id, int w, int h) { + FrameBuffer res = new FrameBuffer(parent); + res.glFbo = id; + res.width = w; + res.height = h; + res.screenFb = true; + return res; + } + /////////////////////////////////////////////////////////// // Color buffer setters. diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index ff3bc2b5a..c75571602 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -46,6 +46,7 @@ import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; import javax.media.opengl.GLEventListener; import javax.media.opengl.GLException; +import javax.media.opengl.GLFBODrawable; import javax.media.opengl.GLProfile; import javax.media.opengl.awt.GLCanvas; import javax.media.opengl.glu.GLU; @@ -57,6 +58,7 @@ import processing.core.PConstants; import com.jogamp.newt.awt.NewtCanvasAWT; import com.jogamp.newt.opengl.GLWindow; +import com.jogamp.opengl.FBObject; import com.jogamp.opengl.util.AnimatorBase; /** @@ -397,6 +399,10 @@ public class PGL { // FBO for anti-aliased rendering + protected int fboFrontTex; + protected int fboFrontTexWidth, fboFrontTexHeight; + + /* protected static final boolean ENABLE_OSX_SCREEN_FBO = false; protected static final int MIN_OSX_VER_FOR_SCREEN_FBO = 6; protected static final int MIN_SAMPLES_FOR_SCREEN_FBO = 1; @@ -414,6 +420,7 @@ public class PGL { protected int[] glDepthBuffer = { 0 }; protected int[] glStencilBuffer = { 0 }; protected int contextHashCode; +*/ /////////////////////////////////////////////////////////// @@ -514,30 +521,6 @@ public class PGL { protected void initPrimarySurface(int antialias) { - /* - if (ENABLE_OSX_SCREEN_FBO) { - needScreenFBO = false; - glColorFbo[0] = 0; - String osName = System.getProperty("os.name"); - if (osName.equals("Mac OS X")) { - String version = System.getProperty("os.version"); - String[] parts = version.split("\\."); - if (2 <= parts.length) { - int num = Integer.parseInt(parts[1]); - if (MIN_OSX_VER_FOR_SCREEN_FBO <= num && - MIN_SAMPLES_FOR_SCREEN_FBO <= qualityToSamples(pg.quality)) { - // Using an FBO for screen drawing works better than the - // screen framebuffer. - // This fixes the problem of antialiasing on Lion or newer, - // the flickering associated to glReadPixels calls on - // 10.6+, and it is in fact faster. - needScreenFBO = true; - } - } - } - } - */ - if (profile == null) { profile = GLProfile.getDefault(); } else { @@ -558,7 +541,7 @@ public class PGL { // Setting up the desired GL capabilities; GLCapabilities caps = new GLCapabilities(profile); - if (1 < antialias && !needScreenFBO) { + if (1 < antialias) { caps.setSampleBuffers(true); caps.setNumSamples(antialias); } else { @@ -590,8 +573,6 @@ public class PGL { pg.parent.removeListeners(pg.parent); pg.parent.addListeners(canvasAWT); - - listener = new PGLListener(); canvasAWT.addGLEventListener(listener); capabilities = canvasAWT.getChosenGLCapabilities(); @@ -637,183 +618,8 @@ public class PGL { if (!setFramerate) { setFrameRate(targetFramerate); } - - if (needScreenFBO && glColorFbo[0] == 0) { - - - String ext = gl.glGetString(GL.GL_EXTENSIONS); - if (-1 < ext.indexOf("texture_non_power_of_two")) { - fboWidth = pg.width; - fboHeight = pg.height; - } else { - fboWidth = PGL.nextPowerOfTwo(pg.width); - fboHeight = PGL.nextPowerOfTwo(pg.height); - } - - if (-1 < ext.indexOf("_framebuffer_multisample")) { - numSamples = qualityToSamples(pg.quality); - } else { - numSamples = 1; - } - multisample = 1 < numSamples; - - if (multisample && gl2x == null) { - throw new RuntimeException("Doesn't have the OpenGL extensions " + - "necessary for multisampling."); - } - packedDepthStencil = ext.indexOf("packed_depth_stencil") != -1; - - contextHashCode = context.hashCode(); - - // Create the color texture... - gl.glGenTextures(2, glColorTex, 0); -// for (int i = 0; i < 2; i++) { // Don't create back-buffer for now. - for (int i = 0; i < 1; i++) { - gl.glBindTexture(GL.GL_TEXTURE_2D, glColorTex[i]); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, - GL.GL_NEAREST); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, - GL.GL_NEAREST); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, - GL.GL_CLAMP_TO_EDGE); - gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, - GL.GL_CLAMP_TO_EDGE); - gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, fboWidth, fboHeight, - 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, null); - initTexture(GL.GL_TEXTURE_2D, PGL.RGBA, fboWidth, fboHeight); - } - gl.glBindTexture(GL.GL_TEXTURE_2D, 0); - - // ...and attach to the color framebuffer. - gl.glGenFramebuffers(1, glColorFbo, 0); - gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, glColorFbo[0]); - gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, - GL.GL_TEXTURE_2D, glColorTex[0], 0); - - if (multisample) { - // Now, creating mutisampled FBO with packed depth and stencil buffers. - gl.glGenFramebuffers(1, glMultiFbo, 0); - gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, glMultiFbo[0]); - - // color render buffer... - gl.glGenRenderbuffers(1, glColorRenderBuffer, 0); - gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glColorRenderBuffer[0]); - gl2x.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, numSamples, - GL.GL_RGBA8, fboWidth, fboHeight); - gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0, - GL.GL_RENDERBUFFER, glColorRenderBuffer[0]); - - if (packedDepthStencil) { - // packed depth+stencil buffer... - gl.glGenRenderbuffers(1, glPackedDepthStencil, 0); - gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glPackedDepthStencil[0]); - gl2x.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, numSamples, - GL.GL_DEPTH24_STENCIL8, - fboWidth, fboHeight); - gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, - GL.GL_DEPTH_ATTACHMENT, - GL.GL_RENDERBUFFER, - glPackedDepthStencil[0]); - gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, - GL.GL_STENCIL_ATTACHMENT, - GL.GL_RENDERBUFFER, - glPackedDepthStencil[0]); - } else { - // Separate depth and stencil buffers... - gl.glGenRenderbuffers(1, glDepthBuffer, 0); - gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glDepthBuffer[0]); - gl2x.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, numSamples, - GL.GL_DEPTH_COMPONENT24, - fboWidth, fboHeight); - gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, - GL.GL_DEPTH_ATTACHMENT, - GL.GL_RENDERBUFFER, - glDepthBuffer[0]); - - // Some hardware doesn't support distinct depth and stencil buffers: - // http://lists.apple.com/archives/mac-opengl/2008/Aug/msg00089.html - // which just results in an unsupported framebuffer error. - gl.glGenRenderbuffers(1, glStencilBuffer, 0); - gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glStencilBuffer[0]); - gl2x.glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, numSamples, - GL.GL_STENCIL_INDEX8, - fboWidth, fboHeight); - gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, - GL.GL_STENCIL_ATTACHMENT, - GL.GL_RENDERBUFFER, - glStencilBuffer[0]); - } - validateFramebuffer(); - - // Clear all the buffers in the multisample FBO - gl.glClearDepth(1); - gl.glClearStencil(0); - gl.glClearColor(0, 0, 0, 0); - gl.glClear(GL.GL_DEPTH_BUFFER_BIT | - GL.GL_STENCIL_BUFFER_BIT | - GL.GL_COLOR_BUFFER_BIT); - - // All set with multisampled FBO! - gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, glColorFbo[0]); - } else { - if (packedDepthStencil) { - // packed depth+stencil buffer... - gl.glGenRenderbuffers(1, glPackedDepthStencil, 0); - gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glPackedDepthStencil[0]); - gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH24_STENCIL8, - fboWidth, fboHeight); - gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, - GL.GL_DEPTH_ATTACHMENT, - GL.GL_RENDERBUFFER, - glPackedDepthStencil[0]); - gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, - GL.GL_STENCIL_ATTACHMENT, - GL.GL_RENDERBUFFER, - glPackedDepthStencil[0]); - } else { - // Separate depth and stencil buffers... - gl.glGenRenderbuffers(1, glDepthBuffer, 0); - gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glDepthBuffer[0]); - gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH_COMPONENT24, - fboWidth, fboHeight); - gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, - GL.GL_DEPTH_ATTACHMENT, - GL.GL_RENDERBUFFER, - glDepthBuffer[0]); - - gl.glGenRenderbuffers(1, glStencilBuffer, 0); - gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, glStencilBuffer[0]); - gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_STENCIL_INDEX8, - fboWidth, fboHeight); - gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, - GL.GL_STENCIL_ATTACHMENT, - GL.GL_RENDERBUFFER, glStencilBuffer[0]); - } - validateFramebuffer(); - - // Clear the depth and stencil buffers in the color FBO. There is no - // need to clear the color buffers because the textures attached were - // properly initialized blank. - gl.glClearDepth(1); - gl.glClearStencil(0); - gl.glClear(GL.GL_DEPTH_BUFFER_BIT | GL.GL_STENCIL_BUFFER_BIT); - } - - // The screen framebuffer is the color FBO just created. We need - // to update the screenFramebuffer object so when the framebuffer - // is popped back to the screen, the correct id is set. - PGraphicsOpenGL.screenFramebuffer.glFbo = glColorFbo[0]; - - backTex = 1; - frontTex = 0; - } else { - // To make sure that the default screen buffer is used, specially after - // doing screen rendering on an FBO. - PGraphicsOpenGL.screenFramebuffer.glFbo = 0; - } } - protected void updateOffscreen(PGL primary) { gl = primary.gl; gl2 = primary.gl2; @@ -830,8 +636,6 @@ public class PGL { } protected int primaryDrawFramebuffer() { - - if (capabilities.isFBO()) { return context.getDefaultDrawFramebuffer(); } else { @@ -840,19 +644,6 @@ public class PGL { } protected int primaryDrawBuffer() { -// if (glColorFbo[0] == 0) { -// return GL.GL_BACK; -// } else { -// return GL.GL_COLOR_ATTACHMENT0; -// } - //int draw = context.getDefaultDrawFramebuffer(); - //int read = context.getDefaultReadFramebuffer(); - //System.out.println(draw + " " + read); - - //System.out.println((GLFBODrawable)drawable); - - - if (capabilities.isFBO()) { return GL.GL_COLOR_ATTACHMENT0; } else { @@ -860,41 +651,35 @@ public class PGL { } } -/* - protected boolean primaryIsDoubleBuffered() { - // When using the multisampled FBO, the color - // FBO is single buffered as it has only one - // texture bound to it. - //return glColorFbo[0] == 0; - return true; + protected int primaryReadBuffer() { + if (capabilities.isFBO()) { + return GL.GL_COLOR_ATTACHMENT0; + } else { + return GL.GL_BACK; + } } -*/ protected boolean primaryIsFboBacked() { return capabilities.isFBO(); } - protected int getFboTexTarget() { return GL.GL_TEXTURE_2D; } - protected int getFboTexName() { - return glColorTex[0]; + return fboFrontTex; } - protected int getFboWidth() { - return fboWidth; + return fboFrontTexWidth; } - protected int getFboHeight() { - return fboHeight; + return fboFrontTexHeight; } - + /* protected void bindPrimaryColorFBO() { if (multisample) { // Blit the contents of the multisampled FBO into the color FBO, @@ -940,7 +725,7 @@ public class PGL { gl.glDeleteRenderbuffers(1, glColorRenderBuffer, 0); } } - +*/ protected int qualityToSamples(int quality) { if (quality <= 1) { @@ -952,15 +737,19 @@ public class PGL { } } + protected void bindBackBufferTex() { + /* if (!texturingIsEnabled(GL.GL_TEXTURE_2D)) { enableTexturing(GL.GL_TEXTURE_2D); } gl.glBindTexture(GL.GL_TEXTURE_2D, glColorTex[backTex]); + */ } protected void unbindBackBufferTex() { + /* if (textureIsBound(GL.GL_TEXTURE_2D, glColorTex[backTex])) { // We don't want to unbind another texture // that might be bound instead of this one. @@ -972,6 +761,7 @@ public class PGL { gl.glBindTexture(GL.GL_TEXTURE_2D, 0); } } + */ } @@ -981,6 +771,7 @@ public class PGL { protected void beginOnscreenDraw(boolean clear) { + /* if (glColorFbo[0] != 0) { gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, glColorFbo[0]); gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER, @@ -1001,10 +792,12 @@ public class PGL { PGraphicsOpenGL.screenFramebuffer.glFbo = glColorFbo[0]; } } + */ } protected void endOnscreenDraw(boolean clear0) { + /* if (glColorFbo[0] != 0) { if (multisample) { // Blit the contents of the multisampled FBO into the color FBO: @@ -1053,6 +846,7 @@ public class PGL { // frontTex = backTex; // backTex = temp; } + */ } @@ -1700,7 +1494,11 @@ public class PGL { public void readPixels(int x, int y, int width, int height, int format, int type, Buffer buffer) { + + gl.glReadPixels(x, y, width, height, format, type, buffer); + + } @@ -2643,10 +2441,31 @@ public class PGL { // Java specific stuff - protected class PGLListener implements GLEventListener { @Override public void display(GLAutoDrawable adrawable) { + GLFBODrawable fboDrawable = null; + if (toolkit == AWT) { + GLCanvas drCanvas = (GLCanvas)adrawable; + fboDrawable = (GLFBODrawable)drCanvas.getDelegatedDrawable(); +// FBObject fboFront = dr.getFBObject(GL.GL_FRONT); +// FBObject.Colorbuffer colorBuf = fboFront.getColorbuffer(0); +// FBObject.TextureAttachment texFront = (FBObject.TextureAttachment) colorBuf; +// System.out.println("front texture: " + texFront.getName()); + } else { + GLWindow drWindow = (GLWindow)adrawable; + fboDrawable = (GLFBODrawable)drWindow.getDelegatedDrawable(); + } + FBObject.TextureAttachment texAttach = null; + if (fboDrawable != null) { + texAttach = fboDrawable.getTextureBuffer(GL.GL_FRONT); + } + if (texAttach != null) { + fboFrontTex = texAttach.getName(); + fboFrontTexWidth = texAttach.getWidth(); + fboFrontTexHeight = texAttach.getHeight(); + } + drawable = adrawable; context = adrawable.getContext(); gl = context.getGL(); @@ -2690,11 +2509,13 @@ public class PGL { drawable = adrawable; context = adrawable.getContext(); + /* if (glColorFbo[0] != 0) { // The screen FBO hack needs the FBO to be recreated when starting // and after resizing. glColorFbo[0] = 0; } + */ } } diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index 266bf126e..2769edaa7 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -363,7 +363,9 @@ public class PGraphicsOpenGL extends PGraphics { static protected int fbStackDepth; static protected FrameBuffer[] fbStack = new FrameBuffer[FB_STACK_DEPTH]; - static protected FrameBuffer screenFramebuffer; + //static protected FrameBuffer screenFramebuffer; + static protected FrameBuffer drawFramebuffer; + static protected FrameBuffer readFramebuffer; static protected FrameBuffer currentFramebuffer; // ....................................................... @@ -1547,9 +1549,12 @@ public class PGraphicsOpenGL extends PGraphics { getGLParameters(); } - if (screenFramebuffer == null) { - screenFramebuffer = new FrameBuffer(parent, width, height, true); - setFramebuffer(screenFramebuffer); + if (drawFramebuffer == null || readFramebuffer == null) { + //screenFramebuffer = new FrameBuffer(parent, width, height, true); + //setFramebuffer(screenFramebuffer); + drawFramebuffer = FrameBuffer.wrap(parent, pgl.primaryDrawFramebuffer(), width, height); + readFramebuffer = FrameBuffer.wrap(parent, pgl.primaryReadFramebuffer(), width, height); + setFramebuffer(drawFramebuffer); } if (primarySurface) { @@ -1863,9 +1868,32 @@ public class PGraphicsOpenGL extends PGraphics { } + + protected void beginPixelsOp(int op) { if (primarySurface) { + // We read or write from the back buffer, where all the + // drawing in the current frame is taking place. + pushFramebuffer(); + if (op == OP_READ) { + setFramebuffer(readFramebuffer); + pgl.readBuffer(pgl.primaryDrawBuffer()); + } else { + setFramebuffer(drawFramebuffer); + pgl.drawBuffer(pgl.primaryDrawBuffer()); + } + offscreenNotCurrent = false; + + /* if (pgl.primaryIsFboBacked()) { + if (op == OP_READ) { + + } else { + + } + } + */ + /* if (op == OP_READ) { // We read from the color FBO, but the multisample FBO is currently // bound, so: @@ -1877,6 +1905,9 @@ public class PGraphicsOpenGL extends PGraphics { offscreenNotCurrent = false; pgl.drawBuffer(pgl.primaryDrawBuffer()); } + + pgl.drawBuffer(pgl.primaryDrawBuffer()); + } else { // We read or write from the back buffer, where all the // drawing in the current frame is taking place. @@ -1887,6 +1918,9 @@ public class PGraphicsOpenGL extends PGraphics { } offscreenNotCurrent = false; } + */ + + } else { // Making sure that the offscreen FBO is current. This allows to do calls // like loadPixels(), set() or get() without enclosing them between @@ -1928,6 +1962,17 @@ public class PGraphicsOpenGL extends PGraphics { protected void endPixelsOp() { + if (offscreenNotCurrent) { + if (pixelsOp == OP_WRITE && offscreenMultisample) { + // We were writing to the multisample FBO, so we need + // to blit its contents to the color FBO. + offscreenFramebufferMultisample.copy(offscreenFramebuffer); + } + } + popFramebuffer(); + pixelsOp = OP_NONE; + + /* if (offscreenNotCurrent) { if (primarySurface) { pgl.bindPrimaryMultiFBO(); @@ -1941,6 +1986,7 @@ public class PGraphicsOpenGL extends PGraphics { } } pixelsOp = OP_NONE; + */ } @@ -5298,7 +5344,6 @@ public class PGraphicsOpenGL extends PGraphics { pgl.readPixels(0, 0, width, height, PGL.RGBA, PGL.UNSIGNED_BYTE, pixelBuffer); endPixelsOp(); - PGL.nativeToJavaARGB(pixels, width, height); } @@ -5394,6 +5439,9 @@ public class PGraphicsOpenGL extends PGraphics { loadTextureImpl(Texture.POINT, false); if (pgl.primaryIsFboBacked()) { + // TODO: need to find how to blit the multisampled back-buffer into the + // front buffer in JOGL: + /* pgl.bindPrimaryColorFBO(); // Copy the contents of the FBO used by the primary surface into // texture, this copy operation is very fast because it is resolved @@ -5401,6 +5449,8 @@ public class PGraphicsOpenGL extends PGraphics { texture.set(pgl.getFboTexTarget(), pgl.getFboTexName(), pgl.getFboWidth(), pgl.getFboHeight(), width, height); pgl.bindPrimaryMultiFBO(); + */ + PGraphics.showWarning("Cannot load contents of screen into texture"); } else { // Here we go the slow route: we first copy the contents of the color // buffer into a pixels array (but we keep it in native format) and @@ -5927,7 +5977,7 @@ public class PGraphicsOpenGL extends PGraphics { protected void bindBackTexture() { if (primarySurface) { - pgl.bindBackBufferTex(); + //pgl.bindBackBufferTex(); } else { } @@ -5936,7 +5986,7 @@ public class PGraphicsOpenGL extends PGraphics { protected void unbindBackTexture() { if (primarySurface) { - pgl.unbindBackBufferTex(); + //pgl.unbindBackBufferTex(); } else { }