From 0562ca34205694b02afb0273e8ef808b45af773b Mon Sep 17 00:00:00 2001 From: codeanticode Date: Mon, 16 Jul 2012 06:30:06 +0000 Subject: [PATCH] flush before changing projection matrix, fixed load pixels in GL --- android/core/src/processing/core/PImage.java | 21 ++++ android/core/src/processing/opengl/PGL.java | 4 + .../processing/opengl/PGraphicsOpenGL.java | 103 +++++++++------- .../core/src/processing/opengl/Texture.java | 112 ++++++++++++++++-- core/src/processing/core/PGraphics.java | 9 -- core/src/processing/core/PImage.java | 42 +++---- .../opengl/src/processing/opengl/PGL.java | 58 ++++++--- .../processing/opengl/PGraphicsOpenGL.java | 103 +++++++++------- .../opengl/src/processing/opengl/Texture.java | 109 +++++++++++++++-- .../video/src/processing/video/Capture.java | 6 +- .../video/src/processing/video/Movie.java | 2 - .../video/src/processing/video/Video.java | 2 +- 12 files changed, 415 insertions(+), 156 deletions(-) diff --git a/android/core/src/processing/core/PImage.java b/android/core/src/processing/core/PImage.java index 549ff327f..fa16bb4bd 100644 --- a/android/core/src/processing/core/PImage.java +++ b/android/core/src/processing/core/PImage.java @@ -350,6 +350,27 @@ public class PImage implements PConstants, Cloneable { if (bitmap != null) { bitmap.getPixels(pixels, 0, width, 0, 0, width, height); } + + + if (cacheMap != null) { + for (PGraphics pg: cacheMap.keySet()) { + Object obj = cacheMap.get(pg); + + Method loadPixelsMethod = null; + try { + loadPixelsMethod = obj.getClass().getMethod("loadPixels", new Class[] { int[].class }); + } catch (Exception e) { + } + + if (loadPixelsMethod != null) { + try { + loadPixelsMethod.invoke(obj, new Object[] { pixels }); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } } diff --git a/android/core/src/processing/opengl/PGL.java b/android/core/src/processing/opengl/PGL.java index 9e023af17..f41d80065 100644 --- a/android/core/src/processing/opengl/PGL.java +++ b/android/core/src/processing/opengl/PGL.java @@ -414,6 +414,10 @@ public class PGL { } + public void setToolkit(int toolkit) { + } + + public void initPrimarySurface(int antialias) { // We do the initialization in updatePrimary() because // at the moment initPrimarySurface() gets called we diff --git a/android/core/src/processing/opengl/PGraphicsOpenGL.java b/android/core/src/processing/opengl/PGraphicsOpenGL.java index 804cb2ca8..156057374 100644 --- a/android/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/android/core/src/processing/opengl/PGraphicsOpenGL.java @@ -489,7 +489,12 @@ public class PGraphicsOpenGL extends PGraphics { pgl.setFramerate(framerate); } + + public void setToolkit(int toolkit) { + pgl.setToolkit(toolkit); + } + public void setSize(int iwidth, int iheight) { resized = (0 < width && width != iwidth) || (0 < height && height != iwidth); @@ -1693,7 +1698,9 @@ public class PGraphicsOpenGL extends PGraphics { } popFramebuffer(); - + + texture.updateTexels(); // Mark all texels in screen texture as modified. + pgl.endOffscreenDraw(pgPrimary.clearColorBuffer0); pgPrimary.restoreGL(); @@ -3743,6 +3750,8 @@ public class PGraphicsOpenGL extends PGraphics { public void popProjection() { + flush(); // The geometry with the old projection matrix needs to be drawn now + if (projectionStackDepth == 0) { throw new RuntimeException(ERROR_PUSHMATRIX_UNDERFLOW); } @@ -3752,11 +3761,13 @@ public class PGraphicsOpenGL extends PGraphics { public void applyProjection(PMatrix3D mat) { + flush(); projection.apply(mat); } public void setProjection(PMatrix3D mat) { + flush(); projection.set(mat); } @@ -4947,7 +4958,7 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glReadPixels(0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, pixelBuffer); endPixelsOp(); - PGL.nativeToJavaARGB(pixels, width, height); + PGL.nativeToJavaARGB(pixels, width, height); } @@ -5026,22 +5037,52 @@ public class PGraphicsOpenGL extends PGraphics { // array, and then the pixels array into the screen texture. public void loadTexture() { if (primarySurface) { - loadTextureImpl(POINT, false); + loadTextureImpl(Texture.POINT, false); loadPixels(); pixelsToTexture(); } } - - // Draws wherever it is in the screen texture right now to the screen. - public void updateTexture() { + + // Draws wherever it is in the screen texture right now to the display. + public void updateDisplay() { flush(); beginPixelsOp(OP_WRITE); drawTexture(); endPixelsOp(); } + + // Uses the texture in img as the color buffer for this surface. + public void setTexture(PImage img) { + if (width != img.width || height != img.height) { + PGraphics.showWarning("Resolution of image is different from PGraphics object"); + return; + } + + if (texture == null || texture != img.getCache(pgPrimary)) { + Texture.Parameters params; + if (primarySurface) { + params = new Texture.Parameters(ARGB, Texture.POINT, false); + } else { + params = new Texture.Parameters(ARGB, Texture.BILINEAR, false); + } + + texture = addTexture(img, params); + + texture.setFlippedY(true); + this.setCache(pgPrimary, texture); + this.setParams(pgPrimary, params); + + if (!primarySurface && offscreenFramebuffer != null) { + // Attach as the color buffer for this offscreen surface + offscreenFramebuffer.setColorBuffer(texture); + offscreenFramebuffer.clear(); + } + } + } + protected void loadTextureImpl(int sampling, boolean mipmap) { if (width == 0 || height == 0) return; if (texture == null || texture.contextIsOutdated()) { @@ -5052,8 +5093,8 @@ public class PGraphicsOpenGL extends PGraphics { this.setParams(pgPrimary, params); } } - - + + protected void drawTexture() { pgl.drawTexture(texture.glTarget, texture.glID, texture.glWidth, texture.glHeight, @@ -5348,41 +5389,6 @@ public class PGraphicsOpenGL extends PGraphics { return tex; } - - /** - * Copies the contents of the texture bound to img to its pixels array. - * @param img the image to have a texture metadata associated to it - */ - /* - public void loadPixels(PImage img) { - if (img.pixels == null) { - img.pixels = new int[img.width * img.height]; - } - - Texture tex = (Texture)img.getCache(pgPrimary); - if (tex == null) { - tex = addTexture(img); - } else { - if (tex.contextIsOutdated()) { - tex = addTexture(img); - } - - if (tex.hasBuffers()) { - // Updates the texture AND the pixels - // array of the image at the same time, - // getting the pixels directly from the - // buffer data (avoiding expenive transfer - // beteeen video and main memory). - tex.bufferUpdate(img.pixels); - } - - if (tex.isModified()) { - // Regular pixel copy from texture. - tex.get(img.pixels); - } - } - } - */ /** * This utility method creates a texture for the provided image, and adds it @@ -5419,7 +5425,18 @@ public class PGraphicsOpenGL extends PGraphics { return tex; } + + protected Texture addTexture(PImage img, Texture.Parameters params) { + Texture tex = new Texture(img.parent, img.width, img.height, params); + if (img.pixels == null) { + img.loadPixels(); + } + if (img.pixels != null) tex.set(img.pixels); + img.setCache(pgPrimary, tex); + return tex; + } + protected PImage wrapTexture(Texture tex) { // We don't use the PImage(int width, int height, int mode) constructor to // avoid initializing the pixels array. diff --git a/android/core/src/processing/opengl/Texture.java b/android/core/src/processing/opengl/Texture.java index 763e84d64..c00e1fc1c 100644 --- a/android/core/src/processing/opengl/Texture.java +++ b/android/core/src/processing/opengl/Texture.java @@ -96,8 +96,9 @@ public class Texture implements PConstants { protected FrameBuffer tempFbo = null; - /** modified portion of the texture */ + /** Modified portion of the texture */ protected boolean modified; + protected int mx1, my1, mx2, my2; protected Object bufferSource; protected LinkedList bufferCache = null; @@ -355,7 +356,9 @@ public class Texture implements PConstants { } pgl.glBindTexture(glTarget, 0); - pgl.disableTexturing(glTarget); + pgl.disableTexturing(glTarget); + + updateTexels(x, y, w, h); } @@ -395,6 +398,28 @@ public class Texture implements PConstants { } + /** + * Copies the contents of the texture to the pixels array. + * @param pixels + */ + public void loadPixels(int[] pixels) { + if (hasBuffers()) { + // Updates the texture AND the pixels array of the image at the same time, + // getting the pixels directly from the buffer data (and thus avoiding expensive + // transfer between video and main memory). + bufferUpdate(pixels); + } + + if (isModified()) { + PApplet.println("Getting pixels from texture..."); + // Regular pixel copy from texture. + get(pixels); + } + + setModified(false); + } + + //////////////////////////////////////////////////////////// // Put methods (the source texture is not resized to cover the entire @@ -481,16 +506,19 @@ public class Texture implements PConstants { // Bind/unbind + public void bind() { pgl.enableTexturing(glTarget); pgl.glBindTexture(glTarget, glID); } + public void unbind() { pgl.enableTexturing(glTarget); pgl.glBindTexture(glTarget, 0); } + ////////////////////////////////////////////////////////////// // Modified flag @@ -509,7 +537,64 @@ public class Texture implements PConstants { public void setModified(boolean m) { modified = m; } + + public int getModifiedX1() { + return mx1; + } + + + public int getModifiedX2() { + return mx2; + } + + + public int getModifiedY1() { + return my1; + } + + + public int getModifiedY2() { + return my2; + } + + + public void updateTexels() { + updateTexelsImpl(0, 0, width, height); + } + + + public void updateTexels(int x, int y, int w, int h) { + updateTexelsImpl(x, y, w, h); + } + + + protected void updateTexelsImpl(int x, int y, int w, int h) { + int x2 = x + w; + int y2 = y + h; + + if (!modified) { + mx1 = PApplet.max(0, x); + mx2 = PApplet.min(width - 1, x2); + my1 = PApplet.max(0, y); + my2 = PApplet.min(height - 1, y2); + modified = true; + + } else { + if (x < mx1) mx1 = PApplet.max(0, x); + if (x > mx2) mx2 = PApplet.min(width - 1, x); + if (y < my1) my1 = PApplet.max(0, y); + if (y > my2) my2 = y; + + if (x2 < mx1) mx1 = PApplet.max(0, x2); + if (x2 > mx2) mx2 = PApplet.min(width - 1, x2); + if (y2 < my1) my1 = PApplet.max(0, y2); + if (y2 > my2) my2 = PApplet.min(height - 1, y2); + } + + PApplet.println("Marking texels @" + x + "," + y + " " + w + "x" + h + " as updated"); + } + //////////////////////////////////////////////////////////// @@ -538,11 +623,13 @@ public class Texture implements PConstants { } } } - + + public boolean hasBufferSource() { return bufferSource != null; } + public boolean hasBuffers() { return bufferSource != null && bufferCache != null && 0 < bufferCache.size(); } @@ -571,10 +658,9 @@ public class Texture implements PConstants { return false; } } - - + + protected boolean bufferUpdate(int[] pixels) { - //PApplet.println("buffer update with pix"); BufferData data = null; try { data = bufferCache.remove(0); @@ -600,6 +686,7 @@ public class Texture implements PConstants { return false; } } + protected void getSourceMethods() { try { @@ -609,6 +696,7 @@ public class Texture implements PConstants { } } + //////////////////////////////////////////////////////////// // Utilities @@ -933,6 +1021,7 @@ public class Texture implements PConstants { return outdated; } + /////////////////////////////////////////////////////////// // Utilities. @@ -969,24 +1058,32 @@ public class Texture implements PConstants { x, y, w, h, x, y, w, h); } pg.popFramebuffer(); + updateTexels(x, y, w, h); } + protected void setTexels(int[] pix, int x, int y, int w, int h) { setTexels(pix, 0, x, y, w, h); } + protected void setTexels(int[] pix, int level, int x, int y, int w, int h) { pgl.glTexSubImage2D(glTarget, level, x, y, w, h, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, IntBuffer.wrap(pix)); + updateTexels(x, y, w, h); } + protected void setTexels(IntBuffer buffer, int x, int y, int w, int h) { setTexels(buffer, 0, x, y, w, h); } + protected void setTexels(IntBuffer buffer, int level, int x, int y, int w, int h) { pgl.glTexSubImage2D(glTarget, level, x, y, w, h, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, buffer); + updateTexels(x, y, w, h); } + protected void copyObject(Texture 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. @@ -1014,7 +1111,8 @@ public class Texture implements PConstants { flippedX = src.flippedX; flippedY = src.flippedY; } - + + /////////////////////////////////////////////////////////// // Parameter handling diff --git a/core/src/processing/core/PGraphics.java b/core/src/processing/core/PGraphics.java index 960affbf9..98e5c9886 100644 --- a/core/src/processing/core/PGraphics.java +++ b/core/src/processing/core/PGraphics.java @@ -7316,15 +7316,6 @@ public class PGraphics extends PImage implements PConstants { } return 0; } - - ////////////////////////////////////////////////////////////// - - // IMAGE PIXELS - - /* - public void loadPixels(PImage img) { // ignore - } - */ ////////////////////////////////////////////////////////////// diff --git a/core/src/processing/core/PImage.java b/core/src/processing/core/PImage.java index 25de0e818..b69c30a41 100644 --- a/core/src/processing/core/PImage.java +++ b/core/src/processing/core/PImage.java @@ -475,25 +475,37 @@ public class PImage implements PConstants, Cloneable { * @usage web_application */ public void loadPixels() { // ignore - /* - if (cacheMap == null) { - if (parent != null) { - parent.g.loadPixels(this); - } else { - PGraphics.showWarning("Cannot load pixels because this image object doesn't have a parent"); - } - } else { + if (pixels == null) { + pixels = new int[width * height]; + } + + if (cacheMap != null) { for (PGraphics pg: cacheMap.keySet()) { - pg.loadPixels(this); + Object obj = cacheMap.get(pg); + + Method loadPixelsMethod = null; + try { + loadPixelsMethod = obj.getClass().getMethod("loadPixels", new Class[] { int[].class }); + } catch (Exception e) { + } + + if (loadPixelsMethod != null) { + try { + loadPixelsMethod.invoke(obj, new Object[] { pixels }); + } catch (Exception e) { + e.printStackTrace(); + } + } } } - */ } + public void updatePixels() { // ignore updatePixelsImpl(0, 0, width, height); } + /** * ( begin auto-generated from PImage_updatePixels.xml ) * @@ -526,16 +538,6 @@ public class PImage implements PConstants, Cloneable { * @param h height */ public void updatePixels(int x, int y, int w, int h) { // ignore -// if (imageMode == CORNER) { // x2, y2 are w/h -// x2 += x1; -// y2 += y1; -// -// } else if (imageMode == CENTER) { -// x1 -= x2 / 2; -// y1 -= y2 / 2; -// x2 += x1; -// y2 += y1; -// } updatePixelsImpl(x, y, w, h); } diff --git a/java/libraries/opengl/src/processing/opengl/PGL.java b/java/libraries/opengl/src/processing/opengl/PGL.java index 98a86aa5c..fa1579ce1 100644 --- a/java/libraries/opengl/src/processing/opengl/PGL.java +++ b/java/libraries/opengl/src/processing/opengl/PGL.java @@ -63,8 +63,6 @@ public class PGL { public static final int AWT = 0; // http://jogamp.org/wiki/index.php/Using_JOGL_in_AWT_SWT_and_Swing public static final int NEWT = 1; // http://jogamp.org/jogl/doc/NEWT-Overview.html - public static int toolkit = AWT; - /** Size of a short (in bytes). */ public static final int SIZEOF_SHORT = Short.SIZE / 8; @@ -321,6 +319,9 @@ public class PGL { /** Whether OpenGL has been initialized or not */ public boolean initialized; + /** Windowing toolkit */ + public static int toolkit = AWT; + /** Selected GL profile */ public GLProfile profile; @@ -349,7 +350,7 @@ public class PGL { protected PGLListener listener; /** Animator to drive the rendering thread in NEWT */ - protected GLAnimator animator; + protected PGLAnimator animator; /** Desired target framerate */ protected float targetFramerate = 60; @@ -500,6 +501,14 @@ public class PGL { } + public void setToolkit(int toolkit) { + if (PGL.toolkit != toolkit) { + PGL.toolkit = toolkit; + this.initialized = false; + } + } + + public void initPrimarySurface(int antialias) { if (ENABLE_OSX_SCREEN_FBO) { needScreenFBO = false; @@ -527,11 +536,15 @@ public class PGL { profile = GLProfile.getDefault(); } else { // Restarting... - if (toolkit == AWT) { + if (canvasAWT != null) { + // TODO: Even if the GLCanvas is put inside an animator, the rendering runs + // inside the EDT, ask the JOGL guys about this. +// animator.stop(); +// animator.remove(canvasAWT); canvasAWT.removeGLEventListener(listener); pg.parent.removeListeners(canvasAWT); pg.parent.remove(canvasAWT); - } else if (toolkit == NEWT) { + } else if (canvasNEWT != null) { animator.stop(); animator.remove(window); window.removeGLEventListener(listener); @@ -565,9 +578,12 @@ public class PGL { listener = new PGLListener(); canvasAWT.addGLEventListener(listener); - +// animator = new PGLAnimator(canvasAWT); +// animator.start(); + capabilities = canvasAWT.getChosenGLCapabilities(); canvas = canvasAWT; + canvasNEWT = null; } else if (toolkit == NEWT) { window = GLWindow.create(caps); canvasNEWT = new NewtCanvasAWT(window); @@ -579,11 +595,12 @@ public class PGL { listener = new PGLListener(); window.addGLEventListener(listener); - animator = new GLAnimator(window); + animator = new PGLAnimator(window); animator.start(); capabilities = window.getChosenGLCapabilities(); canvas = canvasNEWT; + canvasAWT = null; } initialized = true; @@ -829,11 +846,14 @@ public class PGL { public void requestDraw() { if (initialized) { + //animator.requestDisplay(); + if (toolkit == AWT) { canvasAWT.display(); } else if (toolkit == NEWT) { animator.requestDisplay(); } + } } @@ -2350,20 +2370,20 @@ public class PGL { /** Animator subclass to drive render loop when using NEWT. **/ - protected static class GLAnimator extends AnimatorBase { -// private static int count = 0; + protected static class PGLAnimator extends AnimatorBase { + private static int count = 0; private Timer timer = null; private TimerTask task = null; private volatile boolean shouldRun; protected String getBaseName(String prefix) { - return prefix + "PGLAnimator" ; + return prefix + "PGLAnimator"; } /** Creates an CustomAnimator with an initial drawable to * animate. */ - public GLAnimator(GLAutoDrawable drawable) { + public PGLAnimator(GLAutoDrawable drawable) { if (drawable != null) { add(drawable); } @@ -2397,15 +2417,15 @@ public class PGL { } task = new TimerTask() { -// private boolean firstRun = true; + private boolean firstRun = true; public void run() { -// if (firstRun) { -// Thread.currentThread().setName("NEWT-RenderQueue-" + count); -// firstRun = false; -// count++; -// } - if (GLAnimator.this.shouldRun) { - GLAnimator.this.animThread = Thread.currentThread(); + if (firstRun) { + Thread.currentThread().setName("PGL-RenderQueue-" + count); + firstRun = false; + count++; + } + if (PGLAnimator.this.shouldRun) { + PGLAnimator.this.animThread = Thread.currentThread(); // display impl. uses synchronized block on the animator instance display(); synchronized (this) { diff --git a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java index 804cb2ca8..156057374 100644 --- a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java +++ b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java @@ -489,7 +489,12 @@ public class PGraphicsOpenGL extends PGraphics { pgl.setFramerate(framerate); } + + public void setToolkit(int toolkit) { + pgl.setToolkit(toolkit); + } + public void setSize(int iwidth, int iheight) { resized = (0 < width && width != iwidth) || (0 < height && height != iwidth); @@ -1693,7 +1698,9 @@ public class PGraphicsOpenGL extends PGraphics { } popFramebuffer(); - + + texture.updateTexels(); // Mark all texels in screen texture as modified. + pgl.endOffscreenDraw(pgPrimary.clearColorBuffer0); pgPrimary.restoreGL(); @@ -3743,6 +3750,8 @@ public class PGraphicsOpenGL extends PGraphics { public void popProjection() { + flush(); // The geometry with the old projection matrix needs to be drawn now + if (projectionStackDepth == 0) { throw new RuntimeException(ERROR_PUSHMATRIX_UNDERFLOW); } @@ -3752,11 +3761,13 @@ public class PGraphicsOpenGL extends PGraphics { public void applyProjection(PMatrix3D mat) { + flush(); projection.apply(mat); } public void setProjection(PMatrix3D mat) { + flush(); projection.set(mat); } @@ -4947,7 +4958,7 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glReadPixels(0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, pixelBuffer); endPixelsOp(); - PGL.nativeToJavaARGB(pixels, width, height); + PGL.nativeToJavaARGB(pixels, width, height); } @@ -5026,22 +5037,52 @@ public class PGraphicsOpenGL extends PGraphics { // array, and then the pixels array into the screen texture. public void loadTexture() { if (primarySurface) { - loadTextureImpl(POINT, false); + loadTextureImpl(Texture.POINT, false); loadPixels(); pixelsToTexture(); } } - - // Draws wherever it is in the screen texture right now to the screen. - public void updateTexture() { + + // Draws wherever it is in the screen texture right now to the display. + public void updateDisplay() { flush(); beginPixelsOp(OP_WRITE); drawTexture(); endPixelsOp(); } + + // Uses the texture in img as the color buffer for this surface. + public void setTexture(PImage img) { + if (width != img.width || height != img.height) { + PGraphics.showWarning("Resolution of image is different from PGraphics object"); + return; + } + + if (texture == null || texture != img.getCache(pgPrimary)) { + Texture.Parameters params; + if (primarySurface) { + params = new Texture.Parameters(ARGB, Texture.POINT, false); + } else { + params = new Texture.Parameters(ARGB, Texture.BILINEAR, false); + } + + texture = addTexture(img, params); + + texture.setFlippedY(true); + this.setCache(pgPrimary, texture); + this.setParams(pgPrimary, params); + + if (!primarySurface && offscreenFramebuffer != null) { + // Attach as the color buffer for this offscreen surface + offscreenFramebuffer.setColorBuffer(texture); + offscreenFramebuffer.clear(); + } + } + } + protected void loadTextureImpl(int sampling, boolean mipmap) { if (width == 0 || height == 0) return; if (texture == null || texture.contextIsOutdated()) { @@ -5052,8 +5093,8 @@ public class PGraphicsOpenGL extends PGraphics { this.setParams(pgPrimary, params); } } - - + + protected void drawTexture() { pgl.drawTexture(texture.glTarget, texture.glID, texture.glWidth, texture.glHeight, @@ -5348,41 +5389,6 @@ public class PGraphicsOpenGL extends PGraphics { return tex; } - - /** - * Copies the contents of the texture bound to img to its pixels array. - * @param img the image to have a texture metadata associated to it - */ - /* - public void loadPixels(PImage img) { - if (img.pixels == null) { - img.pixels = new int[img.width * img.height]; - } - - Texture tex = (Texture)img.getCache(pgPrimary); - if (tex == null) { - tex = addTexture(img); - } else { - if (tex.contextIsOutdated()) { - tex = addTexture(img); - } - - if (tex.hasBuffers()) { - // Updates the texture AND the pixels - // array of the image at the same time, - // getting the pixels directly from the - // buffer data (avoiding expenive transfer - // beteeen video and main memory). - tex.bufferUpdate(img.pixels); - } - - if (tex.isModified()) { - // Regular pixel copy from texture. - tex.get(img.pixels); - } - } - } - */ /** * This utility method creates a texture for the provided image, and adds it @@ -5419,7 +5425,18 @@ public class PGraphicsOpenGL extends PGraphics { return tex; } + + protected Texture addTexture(PImage img, Texture.Parameters params) { + Texture tex = new Texture(img.parent, img.width, img.height, params); + if (img.pixels == null) { + img.loadPixels(); + } + if (img.pixels != null) tex.set(img.pixels); + img.setCache(pgPrimary, tex); + return tex; + } + protected PImage wrapTexture(Texture tex) { // We don't use the PImage(int width, int height, int mode) constructor to // avoid initializing the pixels array. diff --git a/java/libraries/opengl/src/processing/opengl/Texture.java b/java/libraries/opengl/src/processing/opengl/Texture.java index 763e84d64..1e532d2ca 100644 --- a/java/libraries/opengl/src/processing/opengl/Texture.java +++ b/java/libraries/opengl/src/processing/opengl/Texture.java @@ -96,8 +96,9 @@ public class Texture implements PConstants { protected FrameBuffer tempFbo = null; - /** modified portion of the texture */ + /** Modified portion of the texture */ protected boolean modified; + protected int mx1, my1, mx2, my2; protected Object bufferSource; protected LinkedList bufferCache = null; @@ -355,7 +356,9 @@ public class Texture implements PConstants { } pgl.glBindTexture(glTarget, 0); - pgl.disableTexturing(glTarget); + pgl.disableTexturing(glTarget); + + updateTexels(x, y, w, h); } @@ -395,6 +398,27 @@ public class Texture implements PConstants { } + /** + * Copies the contents of the texture to the pixels array. + * @param pixels + */ + public void loadPixels(int[] pixels) { + if (hasBuffers()) { + // Updates the texture AND the pixels array of the image at the same time, + // getting the pixels directly from the buffer data (and thus avoiding expensive + // transfer between video and main memory). + bufferUpdate(pixels); + } + + if (isModified()) { + // Regular pixel copy from texture. + get(pixels); + } + + setModified(false); + } + + //////////////////////////////////////////////////////////// // Put methods (the source texture is not resized to cover the entire @@ -481,16 +505,19 @@ public class Texture implements PConstants { // Bind/unbind + public void bind() { pgl.enableTexturing(glTarget); pgl.glBindTexture(glTarget, glID); } + public void unbind() { pgl.enableTexturing(glTarget); pgl.glBindTexture(glTarget, 0); } + ////////////////////////////////////////////////////////////// // Modified flag @@ -509,7 +536,62 @@ public class Texture implements PConstants { public void setModified(boolean m) { modified = m; } + + public int getModifiedX1() { + return mx1; + } + + + public int getModifiedX2() { + return mx2; + } + + + public int getModifiedY1() { + return my1; + } + + + public int getModifiedY2() { + return my2; + } + + + public void updateTexels() { + updateTexelsImpl(0, 0, width, height); + } + + + public void updateTexels(int x, int y, int w, int h) { + updateTexelsImpl(x, y, w, h); + } + + + protected void updateTexelsImpl(int x, int y, int w, int h) { + int x2 = x + w; + int y2 = y + h; + + if (!modified) { + mx1 = PApplet.max(0, x); + mx2 = PApplet.min(width - 1, x2); + my1 = PApplet.max(0, y); + my2 = PApplet.min(height - 1, y2); + modified = true; + + } else { + if (x < mx1) mx1 = PApplet.max(0, x); + if (x > mx2) mx2 = PApplet.min(width - 1, x); + if (y < my1) my1 = PApplet.max(0, y); + if (y > my2) my2 = y; + + if (x2 < mx1) mx1 = PApplet.max(0, x2); + if (x2 > mx2) mx2 = PApplet.min(width - 1, x2); + if (y2 < my1) my1 = PApplet.max(0, y2); + if (y2 > my2) my2 = PApplet.min(height - 1, y2); + } + } + //////////////////////////////////////////////////////////// @@ -538,11 +620,13 @@ public class Texture implements PConstants { } } } - + + public boolean hasBufferSource() { return bufferSource != null; } + public boolean hasBuffers() { return bufferSource != null && bufferCache != null && 0 < bufferCache.size(); } @@ -571,10 +655,9 @@ public class Texture implements PConstants { return false; } } - - + + protected boolean bufferUpdate(int[] pixels) { - //PApplet.println("buffer update with pix"); BufferData data = null; try { data = bufferCache.remove(0); @@ -600,6 +683,7 @@ public class Texture implements PConstants { return false; } } + protected void getSourceMethods() { try { @@ -609,6 +693,7 @@ public class Texture implements PConstants { } } + //////////////////////////////////////////////////////////// // Utilities @@ -933,6 +1018,7 @@ public class Texture implements PConstants { return outdated; } + /////////////////////////////////////////////////////////// // Utilities. @@ -969,24 +1055,32 @@ public class Texture implements PConstants { x, y, w, h, x, y, w, h); } pg.popFramebuffer(); + updateTexels(x, y, w, h); } + protected void setTexels(int[] pix, int x, int y, int w, int h) { setTexels(pix, 0, x, y, w, h); } + protected void setTexels(int[] pix, int level, int x, int y, int w, int h) { pgl.glTexSubImage2D(glTarget, level, x, y, w, h, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, IntBuffer.wrap(pix)); + updateTexels(x, y, w, h); } + protected void setTexels(IntBuffer buffer, int x, int y, int w, int h) { setTexels(buffer, 0, x, y, w, h); } + protected void setTexels(IntBuffer buffer, int level, int x, int y, int w, int h) { pgl.glTexSubImage2D(glTarget, level, x, y, w, h, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, buffer); + updateTexels(x, y, w, h); } + protected void copyObject(Texture 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. @@ -1014,7 +1108,8 @@ public class Texture implements PConstants { flippedX = src.flippedX; flippedY = src.flippedY; } - + + /////////////////////////////////////////////////////////// // Parameter handling diff --git a/java/libraries/video/src/processing/video/Capture.java b/java/libraries/video/src/processing/video/Capture.java index 8648f58fc..acecff4ff 100644 --- a/java/libraries/video/src/processing/video/Capture.java +++ b/java/libraries/video/src/processing/video/Capture.java @@ -338,10 +338,6 @@ public class Capture extends PImage implements PConstants { * @usage web_application */ public synchronized void read() { -// if (pixels == null) { -// pixels = new int[width * height]; -// } - if (useBufferSink) { // The native buffer from gstreamer is copied to the buffer sink. if (natBuffer == null) { return; @@ -349,7 +345,6 @@ public class Capture extends PImage implements PConstants { if (firstFrame) { super.init(bufWidth, bufHeight, ARGB); - //loadPixels(); firstFrame = false; } @@ -365,6 +360,7 @@ public class Capture extends PImage implements PConstants { ByteBuffer byteBuffer = natBuffer.getByteBuffer(); try { + PApplet.println("copy buffer to sink..."); sinkCopyMethod.invoke(bufferSink, new Object[] { natBuffer, byteBuffer, bufWidth, bufHeight }); } catch (Exception e) { e.printStackTrace(); diff --git a/java/libraries/video/src/processing/video/Movie.java b/java/libraries/video/src/processing/video/Movie.java index ca84bd10b..53bcfabef 100644 --- a/java/libraries/video/src/processing/video/Movie.java +++ b/java/libraries/video/src/processing/video/Movie.java @@ -536,7 +536,6 @@ public class Movie extends PImage implements PConstants { if (firstFrame) { super.init(bufWidth, bufHeight, ARGB); - //loadPixels(); firstFrame = false; } @@ -564,7 +563,6 @@ public class Movie extends PImage implements PConstants { } if (firstFrame) { - //resize(bufWidth, bufHeight); super.init(bufWidth, bufHeight, RGB); firstFrame = false; } diff --git a/java/libraries/video/src/processing/video/Video.java b/java/libraries/video/src/processing/video/Video.java index bfd7319b6..bd9173769 100644 --- a/java/libraries/video/src/processing/video/Video.java +++ b/java/libraries/video/src/processing/video/Video.java @@ -73,7 +73,7 @@ public class Video implements PConstants { // can improve performance significantly, since the video frames are automatically // copied into the texture without passing through the pixels arrays, as well as // having the color conversion into RGBA handled natively by gstreamer. - public static boolean useGLBufferSink = false; + public static boolean useGLBufferSink = true; // Path that the video library will use to load the gstreamer native libs from. // It is buit either from the system or local paths.