diff --git a/java/libraries/opengl/src/processing/opengl/PFramebuffer.java b/java/libraries/opengl/src/processing/opengl/PFramebuffer.java index e857b6edf..221e39123 100644 --- a/java/libraries/opengl/src/processing/opengl/PFramebuffer.java +++ b/java/libraries/opengl/src/processing/opengl/PFramebuffer.java @@ -50,6 +50,13 @@ public class PFramebuffer implements PConstants { public int glColorBufferMultisampleID; public int width; public int height; + + protected int depthBits; + protected int stencilBits; + protected boolean combinedDepthStencil; + + protected boolean multisample; + protected int nsamples; protected int numColorBuffers; protected int[] colorBufferAttchPoints; @@ -58,41 +65,36 @@ public class PFramebuffer implements PConstants { protected boolean screenFb; protected boolean noDepth; - protected boolean fboMode; - - protected boolean multisample; - protected int nsamples; + protected boolean fboMode; protected PTexture backupTexture; protected IntBuffer pixelBuffer; - PFramebuffer(PApplet parent) { - this(parent, 0, 0, false); + PFramebuffer(PApplet parent, int w, int h) { + this(parent, w, h, 1, 1, 0, 0, false, false); } - PFramebuffer(PApplet parent, int w, int h) { - this(parent, w, h, false); - } - PFramebuffer(PApplet parent, int w, int h, boolean screen) { + this(parent, w, h, 1, 1, 0, 0, false, screen); + } + + PFramebuffer(PApplet parent, int w, int h, int samples, int colorBuffers, + int depthBits, int stencilBits, boolean combinedDepthStencil, + boolean screen) { this.parent = parent; ogl = (PGraphicsOpenGL)parent.g; glFboID = 0; glDepthBufferID = 0; glStencilBufferID = 0; - glDepthStencilBufferID = 0; + glDepthStencilBufferID = 0; glColorBufferMultisampleID = 0; - - screenFb = screen; - noDepth = false; - fboMode = PGraphicsOpenGL.fboSupported; - numColorBuffers = 0; - multisample = false; - nsamples = 0; + fboMode = PGraphicsOpenGL.fboSupported; - createFramebuffer(w, h); + allocate(w, h, samples, colorBuffers, depthBits, stencilBits, + combinedDepthStencil, screen); + noDepth = false; pixelBuffer = null; @@ -102,11 +104,11 @@ public class PFramebuffer implements PConstants { // buffer to the texture bound as color buffer to this PFramebuffer object and then drawing // the backup texture back on the screen. backupTexture = new PTexture(parent, width, height, new PTexture.Parameters(ARGB, POINT)); - } + } } - + public void delete() { - deleteFramebuffer(); + release(); } public void clear() { @@ -124,181 +126,6 @@ public class PFramebuffer implements PConstants { GL.GL_COLOR_BUFFER_BIT, GL.GL_NEAREST); } - public void setColorBuffer(PTexture tex) { - setColorBuffers(new PTexture[] { tex }, 1); - } - - public void setColorBuffers(PTexture[] textures) { - setColorBuffers(textures, textures.length); - } - - public void setColorBuffers(PTexture[] textures, int n) { - if (screenFb) return; - - if (fboMode) { - ogl.pushFramebuffer(); - ogl.setFramebuffer(this); - - // Making sure nothing is attached. - for (int i = 0; i < numColorBuffers; i++) { - getGl().glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0 + i, - GL.GL_TEXTURE_2D, 0, 0); - } - - numColorBuffers = PApplet.min(n, textures.length); - colorBufferAttchPoints = new int[numColorBuffers]; - glColorBufferTargets = new int[numColorBuffers]; - glColorBufferIDs = new int[numColorBuffers]; - - for (int i = 0; i < numColorBuffers; i++) { - colorBufferAttchPoints[i] = GL.GL_COLOR_ATTACHMENT0 + i; - glColorBufferTargets[i] = textures[i].glTarget; - glColorBufferIDs[i] = textures[i].glID; - getGl().glFramebufferTexture2D(GL.GL_FRAMEBUFFER, colorBufferAttchPoints[i], - glColorBufferTargets[i], glColorBufferIDs[i], 0); - } - - if (validFbo() && textures != null && 0 < textures.length) { - width = textures[0].glWidth; - height = textures[0].glHeight; - } - - ogl.popFramebuffer(); - } else { - numColorBuffers = PApplet.min(n, textures.length); - glColorBufferTargets = new int[numColorBuffers]; - glColorBufferIDs = new int[numColorBuffers]; - for (int i = 0; i < numColorBuffers; i++) { - glColorBufferTargets[i] = textures[i].glTarget; - glColorBufferIDs[i] = textures[i].glID; - } - } - } - - public void addColorBufferMultisample(int samples) { - if (screenFb) return; - - if (fboMode) { - ogl.pushFramebuffer(); - ogl.setFramebuffer(this); - - multisample = true; - nsamples = samples; - - numColorBuffers = 1; - colorBufferAttchPoints = new int[numColorBuffers]; - colorBufferAttchPoints[0] = GL.GL_COLOR_ATTACHMENT0; - - glColorBufferMultisampleID = ogl.createGLResource(PGraphicsOpenGL.GL_RENDER_BUFFER); - getGl().glBindRenderbuffer(GL.GL_RENDERBUFFER, glColorBufferMultisampleID); - getGl2().glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, nsamples, - GL.GL_RGBA8, width, height); - getGl().glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, colorBufferAttchPoints[0], - GL.GL_RENDERBUFFER, glColorBufferMultisampleID); - - ogl.popFramebuffer(); - } - } - - public void addDepthStencilBuffer() { - if (screenFb) return; - - if (width == 0 || height == 0) { - throw new RuntimeException("PFramebuffer: size undefined."); - } - - if (fboMode) { - ogl.pushFramebuffer(); - ogl.setFramebuffer(this); - - glDepthStencilBufferID = ogl.createGLResource(PGraphicsOpenGL.GL_RENDER_BUFFER); - getGl().glBindRenderbuffer(GL.GL_RENDERBUFFER, glDepthStencilBufferID); - - if (multisample) { - getGl2().glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, nsamples, GL.GL_DEPTH24_STENCIL8, width, height); - } else { - getGl().glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH24_STENCIL8, width, height); - } - - getGl().glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, - GL.GL_RENDERBUFFER, glDepthStencilBufferID); - getGl().glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, - GL.GL_RENDERBUFFER, glDepthStencilBufferID); - - ogl.popFramebuffer(); - } - } - - public void addDepthBuffer(int bits) { - if (screenFb) return; - - if (width == 0 || height == 0) { - throw new RuntimeException("PFramebuffer: size undefined."); - } - - if (fboMode) { - ogl.pushFramebuffer(); - ogl.setFramebuffer(this); - - glDepthBufferID = ogl.createGLResource(PGraphicsOpenGL.GL_RENDER_BUFFER); - getGl().glBindRenderbuffer(GL.GL_RENDERBUFFER, glDepthBufferID); - - int glConst = GL.GL_DEPTH_COMPONENT16; - if (bits == 16) { - glConst = GL.GL_DEPTH_COMPONENT16; - } else if (bits == 24) { - glConst = GL.GL_DEPTH_COMPONENT24; - } else if (bits == 32) { - glConst = GL.GL_DEPTH_COMPONENT32; - } - - if (multisample) { - getGl2().glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, nsamples, glConst, width, height); - } else { - getGl().glRenderbufferStorage(GL.GL_RENDERBUFFER, glConst, width, height); - } - - getGl().glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, - GL.GL_RENDERBUFFER, glDepthBufferID); - - ogl.popFramebuffer(); - } - } - - public void addStencilBuffer(int bits) { - if (screenFb) return; - - if (width == 0 || height == 0) { - throw new RuntimeException("PFramebuffer: size undefined."); - } - - if (fboMode) { - ogl.pushFramebuffer(); - ogl.setFramebuffer(this); - - glStencilBufferID = ogl.createGLResource(PGraphicsOpenGL.GL_RENDER_BUFFER); - getGl().glBindRenderbuffer(GL.GL_RENDERBUFFER, glStencilBufferID); - - int glConst = GL.GL_STENCIL_INDEX1; - if (bits == 1) { - glConst = GL.GL_STENCIL_INDEX1; - } else if (bits == 4) { - glConst = GL.GL_STENCIL_INDEX4; - } else if (bits == 8) { - glConst = GL.GL_STENCIL_INDEX8; - } - if (multisample) { - getGl2().glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, nsamples, glConst, width, height); - } else { - getGl().glRenderbufferStorage(GL.GL_RENDERBUFFER, glConst, width, height); - } - getGl().glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, - GL.GL_RENDERBUFFER, glStencilBufferID); - - ogl.popFramebuffer(); - } - } - public void bind() { if (screenFb) { if (PGraphicsOpenGL.fboSupported) { @@ -354,7 +181,7 @@ public class PFramebuffer implements PConstants { // Saves content of the screen into the backup texture. public void backupScreen() { - if (pixelBuffer == null) allocatePixelBuffer(); + if (pixelBuffer == null) createPixelBuffer(); getGl().glReadPixels(0, 0, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, pixelBuffer); copyToTexture(pixelBuffer, backupTexture.glID, backupTexture.glTarget); } @@ -366,7 +193,7 @@ public class PFramebuffer implements PConstants { // Copies current content of screen to color buffers. public void copyToColorBuffers() { - if (pixelBuffer == null) allocatePixelBuffer(); + if (pixelBuffer == null) createPixelBuffer(); getGl().glReadPixels(0, 0, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, pixelBuffer); for (int i = 0; i < numColorBuffers; i++) { copyToTexture(pixelBuffer, glColorBufferIDs[i], glColorBufferTargets[i]); @@ -374,7 +201,7 @@ public class PFramebuffer implements PConstants { } public void readPixels() { - if (pixelBuffer == null) allocatePixelBuffer(); + if (pixelBuffer == null) createPixelBuffer(); getGl().glReadPixels(0, 0, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, pixelBuffer); } @@ -389,26 +216,113 @@ public class PFramebuffer implements PConstants { return pixelBuffer; } - // Internal copy to texture method. - protected void copyToTexture(IntBuffer buffer, int glid, int gltarget) { - getGl().glEnable(gltarget); - getGl().glBindTexture(gltarget, glid); - getGl().glTexSubImage2D(gltarget, 0, 0, 0, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, buffer); - getGl().glBindTexture(gltarget, 0); - getGl().glDisable(gltarget); + public boolean hasDepthBuffer() { + return 0 < depthBits; + } + + public boolean hasStencilBuffer() { + return 0 < stencilBits; } - protected void allocatePixelBuffer() { - pixelBuffer = IntBuffer.allocate(width * height); - pixelBuffer.rewind(); + /////////////////////////////////////////////////////////// + + // Color buffer setters. + + public void setColorBuffer(PTexture tex) { + setColorBuffers(new PTexture[] { tex }, 1); + } + + public void setColorBuffers(PTexture[] textures) { + setColorBuffers(textures, textures.length); } - protected void createFramebuffer(int w, int h) { - deleteFramebuffer(); // Just in the case this object is being re-initialized. + public void setColorBuffers(PTexture[] textures, int n) { + if (screenFb) return; + + if (numColorBuffers != PApplet.min(n, textures.length)) { + throw new RuntimeException("Wrong number of textures to set the color buffers."); + } + + if (fboMode) { + ogl.pushFramebuffer(); + ogl.setFramebuffer(this); + + // Making sure nothing is attached. + for (int i = 0; i < numColorBuffers; i++) { + getGl().glFramebufferTexture2D(GL.GL_FRAMEBUFFER, GL.GL_COLOR_ATTACHMENT0 + i, + GL.GL_TEXTURE_2D, 0, 0); + } + + for (int i = 0; i < numColorBuffers; i++) { + glColorBufferTargets[i] = textures[i].glTarget; + glColorBufferIDs[i] = textures[i].glID; + getGl().glFramebufferTexture2D(GL.GL_FRAMEBUFFER, colorBufferAttchPoints[i], + glColorBufferTargets[i], glColorBufferIDs[i], 0); + } + + if (validFbo() && textures != null && 0 < textures.length) { + width = textures[0].glWidth; + height = textures[0].glHeight; + } + + ogl.popFramebuffer(); + } else { + for (int i = 0; i < numColorBuffers; i++) { + glColorBufferTargets[i] = textures[i].glTarget; + glColorBufferIDs[i] = textures[i].glID; + } + } + } + + /////////////////////////////////////////////////////////// + + // Allocate/release framebuffer. + + + protected void allocate(int w, int h, int samples, int colorBuffers, + int depthBits, int stencilBits, boolean combinedDepthStencil, + boolean screen) { + release(); // Just in the case this object is being re-initialized. width = w; height = h; - + + if (1 < samples) { + multisample = true; + nsamples = samples; + } else { + multisample = false; + nsamples = 1; + } + + numColorBuffers = colorBuffers; + colorBufferAttchPoints = new int[numColorBuffers]; + glColorBufferTargets = new int[numColorBuffers]; + glColorBufferIDs = new int[numColorBuffers]; + for (int i = 0; i < numColorBuffers; i++) { + colorBufferAttchPoints[i] = GL.GL_COLOR_ATTACHMENT0 + i; + } + + if (depthBits < 1 && stencilBits < 1) { + this.depthBits = 0; + this.stencilBits = 0; + this.combinedDepthStencil = false; + } else { + if (combinedDepthStencil) { + // When combined depth/stencil format is required, the depth and stencil bits + // are overriden and the 24/8 combination for a 32 bits surface is used. + this.depthBits = 24; + this.stencilBits = 8; + this.combinedDepthStencil = true; + } else { + this.depthBits = depthBits; + this.stencilBits = stencilBits; + this.combinedDepthStencil = false; + } + } + + screenFb = screen; + if (screenFb) { glFboID = 0; } else if (fboMode) { @@ -416,37 +330,219 @@ public class PFramebuffer implements PConstants { } else { glFboID = 0; } + + // create the rest of the stuff... + if (multisample) { + createColorBufferMultisample(); + } + + if (combinedDepthStencil) { + createCombinedDepthStencilBuffer(); + } else { + if (0 < depthBits) { + createDepthBuffer(); + } + if (0 < stencilBits) { + createStencilBuffer(); + } + } + } - protected void deleteFramebuffer() { + + protected void release() { + deleteFbo(); + deleteDepthBuffer(); + deleteStencilBuffer(); + deleteCombinedDepthStencilBuffer(); + deleteColorBufferMultisample(); + width = height = 0; + } + + + protected void deleteFbo() { if (glFboID != 0) { ogl.deleteGLResource(glFboID, PGraphicsOpenGL.GL_FRAME_BUFFER); glFboID = 0; - } - + } + } + + + protected void deleteDepthBuffer() { if (glDepthBufferID != 0) { ogl.deleteGLResource(glDepthBufferID, PGraphicsOpenGL.GL_RENDER_BUFFER); glDepthBufferID = 0; } - + } + + + protected void deleteStencilBuffer() { if (glStencilBufferID != 0) { ogl.deleteGLResource(glStencilBufferID, PGraphicsOpenGL.GL_RENDER_BUFFER); glStencilBufferID = 0; - } - + } + } + + + protected void deleteColorBufferMultisample() { if (glColorBufferMultisampleID != 0) { ogl.deleteGLResource(glColorBufferMultisampleID, PGraphicsOpenGL.GL_RENDER_BUFFER); glColorBufferMultisampleID = 0; - } - + } + } + + + protected void deleteCombinedDepthStencilBuffer() { if (glDepthStencilBufferID != 0) { ogl.deleteGLResource(glDepthStencilBufferID, PGraphicsOpenGL.GL_RENDER_BUFFER); glDepthStencilBufferID = 0; } - - width = height = 0; } + + protected void createColorBufferMultisample() { + if (screenFb) return; + + if (fboMode) { + ogl.pushFramebuffer(); + ogl.setFramebuffer(this); + + numColorBuffers = 1; + colorBufferAttchPoints = new int[numColorBuffers]; + colorBufferAttchPoints[0] = GL.GL_COLOR_ATTACHMENT0; + + glColorBufferMultisampleID = ogl.createGLResource(PGraphicsOpenGL.GL_RENDER_BUFFER); + getGl().glBindRenderbuffer(GL.GL_RENDERBUFFER, glColorBufferMultisampleID); + getGl2().glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, nsamples, + GL.GL_RGBA8, width, height); + getGl().glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, colorBufferAttchPoints[0], + GL.GL_RENDERBUFFER, glColorBufferMultisampleID); + + ogl.popFramebuffer(); + } + } + + + protected void createCombinedDepthStencilBuffer() { + if (screenFb) return; + + if (width == 0 || height == 0) { + throw new RuntimeException("PFramebuffer: size undefined."); + } + + if (fboMode) { + ogl.pushFramebuffer(); + ogl.setFramebuffer(this); + + glDepthStencilBufferID = ogl.createGLResource(PGraphicsOpenGL.GL_RENDER_BUFFER); + getGl().glBindRenderbuffer(GL.GL_RENDERBUFFER, glDepthStencilBufferID); + + if (multisample) { + getGl2().glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, nsamples, GL.GL_DEPTH24_STENCIL8, width, height); + } else { + getGl().glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH24_STENCIL8, width, height); + } + + getGl().glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, + GL.GL_RENDERBUFFER, glDepthStencilBufferID); + getGl().glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, + GL.GL_RENDERBUFFER, glDepthStencilBufferID); + + ogl.popFramebuffer(); + } + } + + + protected void createDepthBuffer() { + if (screenFb) return; + + if (width == 0 || height == 0) { + throw new RuntimeException("PFramebuffer: size undefined."); + } + + if (fboMode) { + ogl.pushFramebuffer(); + ogl.setFramebuffer(this); + + glDepthBufferID = ogl.createGLResource(PGraphicsOpenGL.GL_RENDER_BUFFER); + getGl().glBindRenderbuffer(GL.GL_RENDERBUFFER, glDepthBufferID); + + int glConst = GL.GL_DEPTH_COMPONENT16; + if (depthBits == 16) { + glConst = GL.GL_DEPTH_COMPONENT16; + } else if (depthBits == 24) { + glConst = GL.GL_DEPTH_COMPONENT24; + } else if (depthBits == 32) { + glConst = GL.GL_DEPTH_COMPONENT32; + } + + if (multisample) { + getGl2().glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, nsamples, glConst, width, height); + } else { + getGl().glRenderbufferStorage(GL.GL_RENDERBUFFER, glConst, width, height); + } + + getGl().glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, + GL.GL_RENDERBUFFER, glDepthBufferID); + + ogl.popFramebuffer(); + } + } + + + protected void createStencilBuffer() { + if (screenFb) return; + + if (width == 0 || height == 0) { + throw new RuntimeException("PFramebuffer: size undefined."); + } + + if (fboMode) { + ogl.pushFramebuffer(); + ogl.setFramebuffer(this); + + glStencilBufferID = ogl.createGLResource(PGraphicsOpenGL.GL_RENDER_BUFFER); + getGl().glBindRenderbuffer(GL.GL_RENDERBUFFER, glStencilBufferID); + + int glConst = GL.GL_STENCIL_INDEX1; + if (stencilBits == 1) { + glConst = GL.GL_STENCIL_INDEX1; + } else if (stencilBits == 4) { + glConst = GL.GL_STENCIL_INDEX4; + } else if (stencilBits == 8) { + glConst = GL.GL_STENCIL_INDEX8; + } + if (multisample) { + getGl2().glRenderbufferStorageMultisample(GL.GL_RENDERBUFFER, nsamples, glConst, width, height); + } else { + getGl().glRenderbufferStorage(GL.GL_RENDERBUFFER, glConst, width, height); + } + getGl().glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, + GL.GL_RENDERBUFFER, glStencilBufferID); + + ogl.popFramebuffer(); + } + } + + + protected void createPixelBuffer() { + pixelBuffer = IntBuffer.allocate(width * height); + pixelBuffer.rewind(); + } + + /////////////////////////////////////////////////////////// + + // Utilities. + + // Internal copy to texture method. + protected void copyToTexture(IntBuffer buffer, int glid, int gltarget) { + getGl().glEnable(gltarget); + getGl().glBindTexture(gltarget, glid); + getGl().glTexSubImage2D(gltarget, 0, 0, 0, width, height, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, buffer); + getGl().glBindTexture(gltarget, 0); + getGl().glDisable(gltarget); + } + public boolean validFbo() { int status = getGl().glCheckFramebufferStatus(GL.GL_FRAMEBUFFER); if (status == GL.GL_FRAMEBUFFER_COMPLETE) { diff --git a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java index 84ecf2e41..bf5bc80e6 100644 --- a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java +++ b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java @@ -715,6 +715,8 @@ public class PGraphicsOpenGL extends PGraphics { /* protected int createGLResource(int type, Object obj) { + pTextureObjects.add(obj); + glTextureObjects.add(new Texture(id, obj)); } @@ -724,7 +726,20 @@ public class PGraphicsOpenGL extends PGraphics { } */ + public void recreateGLResources() { + + + } + + protected void registerGLObject(Object obj) { + + } + protected void unregisterGLObject(Object obj) { + + } + + protected int createGLResource(int type) { int id = 0; if (type == GL_TEXTURE_OBJECT) { @@ -732,11 +747,13 @@ public class PGraphicsOpenGL extends PGraphics { gl.glGenTextures(1, temp, 0); id = temp[0]; glTextureObjects.add(id); + //pTextureObjects.add((PTexture)obj); } else if (type == GL_VERTEX_BUFFER) { int[] temp = new int[1]; gl.glGenBuffers(1, temp, 0); id = temp[0]; glVertexBuffers.add(id); + //pTextureObjects.add((PTexture)obj); } else if (type == GL_FRAME_BUFFER) { int[] temp = new int[1]; gl.glGenFramebuffers(1, temp, 0); @@ -6990,10 +7007,7 @@ return width * (1 + ox) / 2.0f; boolean opengl2X = !hints[DISABLE_OPENGL_2X_SMOOTH]; boolean opengl4X = hints[ENABLE_OPENGL_4X_SMOOTH]; - - offscreenMultisample = false; - offscreenFramebuffer = new PFramebuffer(parent, texture.glWidth, texture.glHeight, false); - + // We need the GL2GL3 profile to access the glRenderbufferStorageMultisample // function used in multisampled (antialiased) offscreen rendering. if (PGraphicsOpenGL.fboMultisampleSupported && gl2x != null && (opengl2X || opengl4X)) { @@ -7003,15 +7017,37 @@ return width * (1 + ox) / 2.0f; } else if (opengl4X) { nsamples = 4; } - offscreenFramebufferMultisample = new PFramebuffer(parent, texture.glWidth, texture.glHeight, false); + offscreenFramebufferMultisample = new PFramebuffer(parent, texture.glWidth, texture.glHeight, nsamples, 0, + offscreenDepthBits, offscreenStencilBits, + offscreenDepthBits == 24 && offscreenStencilBits == 8, false); + /* try { offscreenFramebufferMultisample.addColorBufferMultisample(nsamples); offscreenMultisample = true; } catch (GLException e) { PGraphics.showWarning("Unable to create antialised offscreen surface."); - } + } + */ + offscreenFramebufferMultisample.clear(); + offscreenMultisample = true; + + // The offscreen framebuffer where the multisampled image is finally drawn to doesn't + // need depth and stencil buffers since they are part of the multisampled framebuffer. + offscreenFramebuffer = new PFramebuffer(parent, texture.glWidth, texture.glHeight, 1, 1, + 0, 0, + false, false); + } else { + offscreenFramebuffer = new PFramebuffer(parent, texture.glWidth, texture.glHeight, 1, 1, + offscreenDepthBits, offscreenStencilBits, + offscreenDepthBits == 24 && offscreenStencilBits == 8, false); + offscreenMultisample = false; } + + offscreenFramebuffer.setColorBuffer(texture); + offscreenFramebuffer.clear(); + + /* if (offscreenMultisample) { // We have multisampling. The fbo with the depth and stencil buffers is the // multisampled fbo, not the regular one. This is because the actual drawing @@ -7049,17 +7085,14 @@ return width * (1 + ox) / 2.0f; } } } + */ - offscreenFramebuffer.clear(); + } protected void getGLObjects() { gl = context.getGL(); - //PApplet.println("GL:\n" + gl.getClass()); - //PApplet.println("GL3:\n" + gl.getGL4bc()); - - if (pipeline == PROG_GL4) { gl4p = gl.getGL4(); gl3p = gl4p; diff --git a/java/libraries/opengl/src/processing/opengl/PShape3D.java b/java/libraries/opengl/src/processing/opengl/PShape3D.java index 820fee977..b8b87e52c 100644 --- a/java/libraries/opengl/src/processing/opengl/PShape3D.java +++ b/java/libraries/opengl/src/processing/opengl/PShape3D.java @@ -224,11 +224,7 @@ public class PShape3D extends PShape { public void delete() { if (root != this) return; // Can be done only from the root shape. - deleteVertexBuffer(); - deleteColorBuffer(); - deleteTexCoordBuffer(); - deleteNormalBuffer(); - deleteIndexBuffer(); + release(); } //////////////////////////////////////////////////////////// @@ -2103,7 +2099,7 @@ public class PShape3D extends PShape { //////////////////////////////////////////////////////////// - // Data allocation, deletion. + // Init methods. public void init() { if (root != this) return; // Can be done only from the root shape. @@ -2133,7 +2129,7 @@ public class PShape3D extends PShape { } setParameters(params); - allocateShape(numVert); + allocate(numVert); updateElement = -1; resetBounds(); @@ -2174,15 +2170,22 @@ public class PShape3D extends PShape { // field, although the actual geometry hasn't been sent to the VBOs yet. vertexCount = objVertices.size(); } + + /////////////////////////////////////////////////////////// + + // Allocate/release shape. + + + protected void allocate(int numVert) { + release(); // Just in the case this object is being re-initialized. - protected void allocateShape(int numVert) { vertexCount = numVert; numTexBuffers = 1; firstVertex = 0; lastVertex = numVert - 1; initVertexData(); - createVertexBuffer(); + createVertexBuffer(); initColorData(); createColorBuffer(); initNormalData(); @@ -2193,19 +2196,30 @@ public class PShape3D extends PShape { initChildrenData(); } - protected void initChildrenData() { - children = null; - vertexChild = new PShape3D[vertexCount]; + protected void reallocate() { + allocate(vertexCount); } + protected void release() { + deleteVertexBuffer(); + deleteColorBuffer(); + deleteTexCoordBuffer(); + deleteNormalBuffer(); + deleteIndexBuffer(); + } + + + //////////////////////////////////////////////////////////// + + // Data creation, deletion. + + protected void initVertexData() { vertices = new float[vertexCount * 3]; } protected void createVertexBuffer() { - deleteVertexBuffer(); // Just in the case this object is being re-initialized. - glVertexBufferID = ogl.createGLResource(PGraphicsOpenGL.GL_VERTEX_BUFFER); getGl().glBindBuffer(GL.GL_ARRAY_BUFFER, glVertexBufferID); final int bufferSize = vertexCount * 3 * PGraphicsOpenGL.SIZEOF_FLOAT; @@ -2223,8 +2237,6 @@ public class PShape3D extends PShape { protected void createColorBuffer() { - deleteColorBuffer(); - glColorBufferID = ogl.createGLResource(PGraphicsOpenGL.GL_VERTEX_BUFFER); getGl().glBindBuffer(GL.GL_ARRAY_BUFFER, glColorBufferID); final int bufferSize = vertexCount * 4 * PGraphicsOpenGL.SIZEOF_FLOAT; @@ -2239,8 +2251,6 @@ public class PShape3D extends PShape { protected void createNormalBuffer() { - deleteNormalBuffer(); - glNormalBufferID = ogl.createGLResource(PGraphicsOpenGL.GL_VERTEX_BUFFER); getGl().glBindBuffer(GL.GL_ARRAY_BUFFER, glNormalBufferID); final int bufferSize = vertexCount * 3 * PGraphicsOpenGL.SIZEOF_FLOAT; @@ -2261,8 +2271,6 @@ public class PShape3D extends PShape { if (glTexCoordBufferID == null) { glTexCoordBufferID = new int[PGraphicsOpenGL.MAX_TEXTURES]; java.util.Arrays.fill(glTexCoordBufferID, 0); - } else { - deleteTexCoordBuffer(); } glTexCoordBufferID[0] = ogl.createGLResource(PGraphicsOpenGL.GL_VERTEX_BUFFER); @@ -2302,6 +2310,7 @@ public class PShape3D extends PShape { updateTexBuffers(); } + protected void updateTexBuffers() { if (family == GROUP) { for (int i = 0; i < childCount; i++) { @@ -2314,6 +2323,7 @@ public class PShape3D extends PShape { } } + protected void deleteVertexBuffer() { if (glVertexBufferID != 0) { ogl.deleteGLResource(glVertexBufferID, PGraphicsOpenGL.GL_VERTEX_BUFFER); @@ -2345,6 +2355,7 @@ public class PShape3D extends PShape { } } + protected void deleteTexCoordBuffer() { for (int i = 0; i < numTexBuffers; i++) { deleteTexCoordBuffer(i); @@ -2358,8 +2369,14 @@ public class PShape3D extends PShape { glTexCoordBufferID[idx] = 0; } } - + + protected void initChildrenData() { + children = null; + vertexChild = new PShape3D[vertexCount]; + } + + /////////////////////////////////////////////////////////// // These methods are not available in PShape3D. @@ -3045,7 +3062,7 @@ public class PShape3D extends PShape { } // Allocate space for the geometry that the triangulator has generated from the OBJ model. - allocateShape(ogl.recordedVertices.size()); + allocate(ogl.recordedVertices.size()); updateElement = -1; width = height = depth = 0; diff --git a/java/libraries/opengl/src/processing/opengl/PTexture.java b/java/libraries/opengl/src/processing/opengl/PTexture.java index 0c1c7cc40..a81df98e2 100644 --- a/java/libraries/opengl/src/processing/opengl/PTexture.java +++ b/java/libraries/opengl/src/processing/opengl/PTexture.java @@ -96,7 +96,7 @@ public class PTexture implements PConstants { glID = 0; setParameters((Parameters)params); - createTexture(width, height); + allocate(width, height); } @@ -130,7 +130,7 @@ public class PTexture implements PConstants { public void delete() { - deleteTexture(); + release(); } //////////////////////////////////////////////////////////// @@ -171,7 +171,7 @@ public class PTexture implements PConstants { this.width = width; this.height = height; setParameters(params); - createTexture(width, height); + allocate(width, height); } @@ -256,7 +256,7 @@ public class PTexture implements PConstants { } if (glID == 0) { - createTexture(width, height); + allocate(width, height); } getGl().glEnable(glTarget); @@ -682,16 +682,16 @@ public class PTexture implements PConstants { /////////////////////////////////////////////////////////// - // Create/delete texture. + // Allocate/release texture. /** - * Creates the opengl texture object. + * Allocates the opengl texture object. * @param w int * @param h int */ - protected void createTexture(int w, int h) { - deleteTexture(); // Just in the case this object is being re-initialized. + protected void allocate(int w, int h) { + release(); // Just in the case this object is being re-initialized. if (PGraphicsOpenGL.npotTexSupported) { glWidth = w; @@ -711,15 +711,15 @@ public class PTexture implements PConstants { usingMipmaps = glMinFilter == GL.GL_LINEAR_MIPMAP_LINEAR; getGl().glEnable(glTarget); - glID = ogl.createGLResource(PGraphicsOpenGL.GL_TEXTURE_OBJECT); + glID = ogl.createGLResource(PGraphicsOpenGL.GL_TEXTURE_OBJECT); getGl().glBindTexture(glTarget, glID); getGl().glTexParameteri(glTarget, GL.GL_TEXTURE_MIN_FILTER, glMinFilter); getGl().glTexParameteri(glTarget, GL.GL_TEXTURE_MAG_FILTER, glMagFilter); getGl().glTexParameteri(glTarget, GL.GL_TEXTURE_WRAP_S, glWrapS); getGl().glTexParameteri(glTarget, GL.GL_TEXTURE_WRAP_T, glWrapT); - //First, we use glTexImage2D to set the full size of the texture (glW/H might be diff from - // w/h in the case that the GPU doesn't support NPOT textures) + // First, we use glTexImage2D to set the full size of the texture (glW/glH might be diff + // from w/h in the case that the GPU doesn't support NPOT textures) getGl().glTexImage2D(glTarget, 0, glFormat, glWidth, glHeight, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, null); @@ -744,17 +744,25 @@ public class PTexture implements PConstants { maxTexCoordV = (float)h / glHeight; } - + protected void reallocate() { + allocate(width, height); + } + /** * Deletes the opengl texture object. */ - protected void deleteTexture() { + protected void release() { if (glID != 0) { ogl.deleteGLResource(glID, PGraphicsOpenGL.GL_TEXTURE_OBJECT); glID = 0; } } + /////////////////////////////////////////////////////////// + + // Utilities. + + // Copies source texture tex into this. protected void copyTexels(PTexture tex, int x, int y, int w, int h, boolean scale) { if (tex == null) { @@ -796,7 +804,7 @@ public class PTexture implements PConstants { protected void copyObject(PTexture src) { // The OpenGL texture of this object is replaced with the one from the source object, // so we delete the former to avoid resource wasting. - deleteTexture(); + release(); width = src.width; height = src.height;