diff --git a/android/core/src/processing/opengl/PGL.java b/android/core/src/processing/opengl/PGL.java index 800f80f2a..a65e1c970 100644 --- a/android/core/src/processing/opengl/PGL.java +++ b/android/core/src/processing/opengl/PGL.java @@ -316,12 +316,10 @@ public class PGL { // FBO for incremental drawing protected boolean firstOnscreenFrame = true; - protected int[] textures = { 0, 0 }; - protected int[] fbo = { 0 }; - protected int[] depth = { 0 }; - protected int[] stencil = { 0 }; protected int texWidth, texHeight; - protected int backTex, frontTex; + protected int backTex, frontTex; + protected int[] colorTex = { 0, 0 }; + protected int[] colorFBO = { 0 }; /////////////////////////////////////////////////////////////////////////////////// @@ -431,6 +429,9 @@ public class PGL { public void updatePrimary() { if (!initialized) { + int[] depth = { 0 }; + int[] stencil = { 0 }; + String ext = GLES20.glGetString(GLES20.GL_EXTENSIONS); if (-1 < ext.indexOf("texture_non_power_of_two")) { texWidth = pg.width; @@ -443,9 +444,9 @@ public class PGL { // We create the GL resources we need to draw incrementally, ie: not clearing // the screen in each frame. Because the way Android handles double buffering // we need to handle our own custom buffering using FBOs. - GLES20.glGenTextures(2, textures, 0); + GLES20.glGenTextures(2, colorTex, 0); for (int i = 0; i < 2; i++) { - GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[i]); + GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, colorTex[i]); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); @@ -455,10 +456,10 @@ public class PGL { } GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); - GLES20.glGenFramebuffers(1, fbo, 0); + GLES20.glGenFramebuffers(1, colorFBO, 0); GLES20.glGenRenderbuffers(1, depth, 0); - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo[0]); + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, colorFBO[0]); GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depth[0]); GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, texWidth, texHeight); @@ -483,7 +484,7 @@ public class PGL { // to update the screenFramebuffer object so when the // framebuffer is popped back to the screen, the correct // id is set. - PGraphicsOpenGL.screenFramebuffer.glFboID = fbo[0]; + PGraphicsOpenGL.screenFramebuffer.glFboID = colorFBO[0]; initialized = true; } @@ -496,10 +497,27 @@ public class PGL { public boolean primaryIsDoubleBuffered() { - return true; + return colorFBO[0] == 0; } + public boolean usingPrimaryFBO() { + return colorFBO[0] != 0; + } + + + public void bindPrimaryColorFBO() { + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, colorFBO[0]); + PGraphicsOpenGL.screenFramebuffer.glFboID = colorFBO[0]; + } + + + public void bindPrimaryMultiFBO() { + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, colorFBO[0]); + PGraphicsOpenGL.screenFramebuffer.glFboID = colorFBO[0]; + } + + /////////////////////////////////////////////////////////////////////////////////// // Frame rendering @@ -513,8 +531,8 @@ public class PGL { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); PGraphicsOpenGL.screenFramebuffer.glFboID = 0; } else { - GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo[0]); - GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textures[frontTex], 0); + GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, colorFBO[0]); + GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, colorTex[frontTex], 0); validateFramebuffer(); // We need to save the color buffer after finishing with the rendering of this frame, @@ -526,9 +544,9 @@ public class PGL { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); } else { // Render previous draw texture as background. - drawTexture(GLES20.GL_TEXTURE_2D, textures[backTex], texWidth, texHeight, 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height); + drawTexture(GLES20.GL_TEXTURE_2D, colorTex[backTex], texWidth, texHeight, 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height); } - PGraphicsOpenGL.screenFramebuffer.glFboID = fbo[0]; + PGraphicsOpenGL.screenFramebuffer.glFboID = colorFBO[0]; } if (firstOnscreenFrame) { @@ -543,11 +561,12 @@ public class PGL { // contents of the front buffer needs to be used in the next frame as the background. GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0); + GLES20.glClearDepthf(1); GLES20.glClearColor(0, 0, 0, 0); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); // Render current front texture to screen. - drawTexture(GLES20.GL_TEXTURE_2D, textures[frontTex], texWidth, texHeight, 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height); + drawTexture(GLES20.GL_TEXTURE_2D, colorTex[frontTex], texWidth, texHeight, 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height); // Swapping front and back textures. int temp = frontTex; diff --git a/android/core/src/processing/opengl/PGraphicsOpenGL.java b/android/core/src/processing/opengl/PGraphicsOpenGL.java index 3cdb4e7b0..8aeb5681f 100644 --- a/android/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/android/core/src/processing/opengl/PGraphicsOpenGL.java @@ -488,6 +488,11 @@ public class PGraphicsOpenGL extends PGraphics { height = iheight; // width1 = width - 1; // height1 = height - 1; + + if (pixels != null) { + // The user is using the pixels array, so we need to resize accordingly + allocatePixels(); + } allocate(); reapplySettings(); @@ -500,7 +505,7 @@ public class PGraphicsOpenGL extends PGraphics { cameraNear = cameraZ / 10.0f; cameraFar = cameraZ * 10.0f; cameraAspect = (float) width / (float) height; - + // set this flag so that beginDraw() will do an update to the camera. sizeChanged = true; @@ -1756,8 +1761,19 @@ public class PGraphicsOpenGL extends PGraphics { } else { pgl.glDrawBuffer(PGL.GL_BACK); } - } - offscreenNotCurrent = false; + offscreenNotCurrent = false; + } else if (pgl.usingPrimaryFBO()) { + if (op == OP_READ) { + // We read from the color FBO, but the multisample FBO is currently bound, so: + offscreenNotCurrent = true; + pgl.bindPrimaryColorFBO(); + pgl.glReadBuffer(PGL.GL_COLOR_ATTACHMENT0); + } else { + // We write directly to the multisample FBO. + offscreenNotCurrent = false; + pgl.glDrawBuffer(PGL.GL_COLOR_ATTACHMENT0); + } + } } else { // Making sure that the offscreen FBO is current. This allows to do calls // like loadPixels(), set() or get() without enclosing them between @@ -1799,12 +1815,16 @@ 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); + if (primarySurface) { + pgl.bindPrimaryMultiFBO(); + } else { + 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(); } - popFramebuffer(); } pixelsOp = OP_NONE; } @@ -4816,10 +4836,10 @@ public class PGraphicsOpenGL extends PGraphics { } allocatePixels(); - + if (!setgetPixels) { readPixels(); - + if (primarySurface) { loadTextureImpl(POINT, false); pixelsToTexture(); @@ -4852,9 +4872,9 @@ public class PGraphicsOpenGL extends PGraphics { protected void readPixels() { - beginPixelsOp(OP_READ); + beginPixelsOp(OP_READ); pixelBuffer.rewind(); - pgl.glReadPixels(0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, pixelBuffer); + pgl.glReadPixels(0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, pixelBuffer); endPixelsOp(); PGL.nativeToJavaARGB(pixels, width, height); @@ -4869,16 +4889,16 @@ public class PGraphicsOpenGL extends PGraphics { rgbaPixels = new int[len]; } - PApplet.arrayCopy(pixels, i0, rgbaPixels, 0, len); + PApplet.arrayCopy(pixels, i0, rgbaPixels, 0, len); PGL.javaToNativeARGB(rgbaPixels, w, h); // Copying pixel buffer to screen texture... if (primarySurface) { loadTextureImpl(POINT, false); // (first making sure that the screen texture is valid). - } + } pgl.copyToTexture(texture.glTarget, texture.glFormat, texture.glID, x, y, w, h, IntBuffer.wrap(rgbaPixels)); - + if (primarySurface || offscreenMultisample) { // ...and drawing the texture to screen... but only // if we are on the primary surface or we have diff --git a/java/libraries/opengl/src/processing/opengl/PGL.java b/java/libraries/opengl/src/processing/opengl/PGL.java index 7553411af..627b28021 100644 --- a/java/libraries/opengl/src/processing/opengl/PGL.java +++ b/java/libraries/opengl/src/processing/opengl/PGL.java @@ -501,7 +501,7 @@ public class PGL { if (ENABLE_SMOOTH_LION_HACK) { needScreenFBO = false; if (colorFBO[0] != 0) { - releaseFBO(); + releaseScreenFBO(); colorFBO[0] = 0; } String osName = System.getProperty("os.name"); @@ -689,7 +689,24 @@ public class PGL { } - protected void releaseFBO() { + public boolean usingPrimaryFBO() { + return colorFBO[0] != 0; + } + + + public void bindPrimaryColorFBO() { + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, colorFBO[0]); + PGraphicsOpenGL.screenFramebuffer.glFboID = colorFBO[0]; + } + + + public void bindPrimaryMultiFBO() { + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, multiFBO[0]); + PGraphicsOpenGL.screenFramebuffer.glFboID = multiFBO[0]; + } + + + protected void releaseScreenFBO() { gl.glDeleteTextures(1, colorTex, 0); gl.glDeleteFramebuffers(1, colorFBO, 0); gl.glDeleteFramebuffers(1, multiFBO, 0); diff --git a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java index 3cdb4e7b0..8aeb5681f 100644 --- a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java +++ b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java @@ -488,6 +488,11 @@ public class PGraphicsOpenGL extends PGraphics { height = iheight; // width1 = width - 1; // height1 = height - 1; + + if (pixels != null) { + // The user is using the pixels array, so we need to resize accordingly + allocatePixels(); + } allocate(); reapplySettings(); @@ -500,7 +505,7 @@ public class PGraphicsOpenGL extends PGraphics { cameraNear = cameraZ / 10.0f; cameraFar = cameraZ * 10.0f; cameraAspect = (float) width / (float) height; - + // set this flag so that beginDraw() will do an update to the camera. sizeChanged = true; @@ -1756,8 +1761,19 @@ public class PGraphicsOpenGL extends PGraphics { } else { pgl.glDrawBuffer(PGL.GL_BACK); } - } - offscreenNotCurrent = false; + offscreenNotCurrent = false; + } else if (pgl.usingPrimaryFBO()) { + if (op == OP_READ) { + // We read from the color FBO, but the multisample FBO is currently bound, so: + offscreenNotCurrent = true; + pgl.bindPrimaryColorFBO(); + pgl.glReadBuffer(PGL.GL_COLOR_ATTACHMENT0); + } else { + // We write directly to the multisample FBO. + offscreenNotCurrent = false; + pgl.glDrawBuffer(PGL.GL_COLOR_ATTACHMENT0); + } + } } else { // Making sure that the offscreen FBO is current. This allows to do calls // like loadPixels(), set() or get() without enclosing them between @@ -1799,12 +1815,16 @@ 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); + if (primarySurface) { + pgl.bindPrimaryMultiFBO(); + } else { + 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(); } - popFramebuffer(); } pixelsOp = OP_NONE; } @@ -4816,10 +4836,10 @@ public class PGraphicsOpenGL extends PGraphics { } allocatePixels(); - + if (!setgetPixels) { readPixels(); - + if (primarySurface) { loadTextureImpl(POINT, false); pixelsToTexture(); @@ -4852,9 +4872,9 @@ public class PGraphicsOpenGL extends PGraphics { protected void readPixels() { - beginPixelsOp(OP_READ); + beginPixelsOp(OP_READ); pixelBuffer.rewind(); - pgl.glReadPixels(0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, pixelBuffer); + pgl.glReadPixels(0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, pixelBuffer); endPixelsOp(); PGL.nativeToJavaARGB(pixels, width, height); @@ -4869,16 +4889,16 @@ public class PGraphicsOpenGL extends PGraphics { rgbaPixels = new int[len]; } - PApplet.arrayCopy(pixels, i0, rgbaPixels, 0, len); + PApplet.arrayCopy(pixels, i0, rgbaPixels, 0, len); PGL.javaToNativeARGB(rgbaPixels, w, h); // Copying pixel buffer to screen texture... if (primarySurface) { loadTextureImpl(POINT, false); // (first making sure that the screen texture is valid). - } + } pgl.copyToTexture(texture.glTarget, texture.glFormat, texture.glID, x, y, w, h, IntBuffer.wrap(rgbaPixels)); - + if (primarySurface || offscreenMultisample) { // ...and drawing the texture to screen... but only // if we are on the primary surface or we have