diff --git a/android/core/src/processing/opengl/FrameBuffer.java b/android/core/src/processing/opengl/FrameBuffer.java index 49ceb13ce..d59acec18 100644 --- a/android/core/src/processing/opengl/FrameBuffer.java +++ b/android/core/src/processing/opengl/FrameBuffer.java @@ -206,7 +206,7 @@ public class FrameBuffer implements PConstants { public void getPixels(int[] pixels) { if (pixelBuffer != null) { - pixelBuffer.get(pixels); + pixelBuffer.get(pixels, 0, pixels.length); pixelBuffer.rewind(); } } diff --git a/android/core/src/processing/opengl/PGraphicsOpenGL.java b/android/core/src/processing/opengl/PGraphicsOpenGL.java index 103deb427..dcee2bd77 100644 --- a/android/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/android/core/src/processing/opengl/PGraphicsOpenGL.java @@ -31,6 +31,7 @@ import processing.core.PMatrix2D; import processing.core.PMatrix3D; import processing.core.PShape; import processing.core.PVector; +import processing.opengl.PGraphicsOpenGL.Tessellator.TessellatorCallback; import java.net.URL; import java.nio.*; @@ -46,7 +47,7 @@ import java.util.Stack; * OpenGL renderer. * */ -public class PGraphicsOpenGL extends PGraphics { +public class PGraphicsOpenGL extends PGraphics { /** Interface between Processing and OpenGL */ public PGL pgl; @@ -293,7 +294,7 @@ public class PGraphicsOpenGL extends PGraphics { // Texturing: public int textureWrap = Texture.CLAMP; - public int textureQuality = Texture.BEST; + public int textureQuality = Texture.BEST; // ........................................................ @@ -2056,8 +2057,8 @@ public class PGraphicsOpenGL extends PGraphics { public void textureQuality(int quality) { this.textureQuality = quality; } - - + + public void texture(PImage image) { if (flushMode == FLUSH_WHEN_FULL && hints[DISABLE_TEXTURE_CACHE] && image != textureImage0) { @@ -5196,7 +5197,42 @@ 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 @@ -5234,7 +5270,9 @@ public class PGraphicsOpenGL extends PGraphics { img.parent = parent; } Texture tex = new Texture(img.parent, img.width, img.height, params); - img.loadPixels(); + if (img.pixels == null) { + img.loadPixels(); + } if (img.pixels != null) tex.set(img.pixels); img.setCache(pgPrimary, tex); return tex; @@ -9136,9 +9174,10 @@ public class PGraphicsOpenGL extends PGraphics { if (PGL.MAX_VERTEX_INDEX1 <= nPtVert) { throw new RuntimeException("P3D: error in point tessellation."); } + updateTex(); int nvertTot = nPtVert * nInVert; int nindTot = 3 * (nPtVert - 1) * nInVert; - if (is3D) { + if (is3D) { tessellateRoundPoints3D(nvertTot, nindTot, nPtVert); } else if (is2D) { beginNoTex(); @@ -9258,7 +9297,8 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateSquarePoints() { int nInVert = in.lastVertex - in.firstVertex + 1; - if (stroke && 1 <= nInVert) { + if (stroke && 1 <= nInVert) { + updateTex(); int quadCount = nInVert; // Each point generates a separate quad. // Each quad is formed by 5 vertices, the center one // is the input vertex, and the other 4 define the @@ -9267,8 +9307,8 @@ public class PGraphicsOpenGL extends PGraphics { // So the quad is formed by 4 triangles, each requires // 3 indices. int nindTot = 12 * quadCount; - if (is3D) { - tessellateSquarePoints3D(nvertTot, nindTot); + if (is3D) { + tessellateSquarePoints3D(nvertTot, nindTot); } else if (is2D) { beginNoTex(); tessellateSquarePoints2D(nvertTot, nindTot); @@ -9381,12 +9421,12 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateLines() { int nInVert = in.lastVertex - in.firstVertex + 1; if (stroke && 2 <= nInVert) { - // Each individual line is formed by two consecutive input vertices. - int lineCount = nInVert / 2; - if (is3D) { + updateTex(); + int lineCount = nInVert / 2; // Each individual line is formed by two consecutive input vertices. + if (is3D) { tessellateLines3D(lineCount); } else if (is2D) { - beginNoTex(); + beginNoTex(); // Line geometry in 2D are stored in the poly array next to the fill triangles, but w/out textures. tessellateLines2D(lineCount); endNoTex(); } @@ -9445,8 +9485,9 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateLineStrip() { int nInVert = in.lastVertex - in.firstVertex + 1; if (stroke && 2 <= nInVert) { + updateTex(); int lineCount = nInVert - 1; - if (is3D) { + if (is3D) { tessellateLineStrip3D(lineCount); } else if (is2D) { beginNoTex(); @@ -9506,8 +9547,9 @@ public class PGraphicsOpenGL extends PGraphics { void tessellateLineLoop() { int nInVert = in.lastVertex - in.firstVertex + 1; if (stroke && 2 <= nInVert) { + updateTex(); int lineCount = nInVert; - if (is3D) { + if (is3D) { tessellateLineLoop3D(lineCount); } else if (is2D) { beginNoTex(); @@ -9810,7 +9852,7 @@ public class PGraphicsOpenGL extends PGraphics { // Polygon primitives tessellation void tessellateTriangles() { - setFirstTexIndex(tess.polyIndexCount, tess.polyIndexCache.size - 1); + beginTex(); int nInVert = in.lastVertex - in.firstVertex + 1; if (fill && 3 <= nInVert) { int nInInd = nInVert; @@ -9821,12 +9863,12 @@ public class PGraphicsOpenGL extends PGraphics { } partitionRawIndices(); } - setLastTexIndex(tess.lastPolyIndex, tess.polyIndexCache.size - 1); + endTex(); tessellateEdges(); } void tessellateTriangles(int[] indices) { - setFirstTexIndex(tess.polyIndexCount, tess.polyIndexCache.size - 1); + beginTex(); int nInVert = in.lastVertex - in.firstVertex + 1; if (fill && 3 <= nInVert) { int nInInd = indices.length; @@ -9834,12 +9876,12 @@ public class PGraphicsOpenGL extends PGraphics { PApplet.arrayCopy(indices, rawIndices, nInInd); partitionRawIndices(); } - setLastTexIndex(tess.lastPolyIndex, tess.polyIndexCache.size - 1); + endTex(); tessellateEdges(); } void tessellateTriangleFan() { - setFirstTexIndex(tess.polyIndexCount, tess.polyIndexCache.size - 1); + beginTex(); int nInVert = in.lastVertex - in.firstVertex + 1; if (fill && 3 <= nInVert) { int nInInd = 3 * (nInVert - 2); @@ -9852,12 +9894,12 @@ public class PGraphicsOpenGL extends PGraphics { } partitionRawIndices(); } - setLastTexIndex(tess.lastPolyIndex, tess.polyIndexCache.size - 1); + endTex(); tessellateEdges(); } void tessellateTriangleStrip() { - setFirstTexIndex(tess.polyIndexCount, tess.polyIndexCache.size - 1); + beginTex(); int nInVert = in.lastVertex - in.firstVertex + 1; if (fill && 3 <= nInVert) { int nInInd = 3 * (nInVert - 2); @@ -9875,12 +9917,12 @@ public class PGraphicsOpenGL extends PGraphics { } partitionRawIndices(); } - setLastTexIndex(tess.lastPolyIndex, tess.polyIndexCache.size - 1); + endTex(); tessellateEdges(); } void tessellateQuads() { - setFirstTexIndex(tess.polyIndexCount, tess.polyIndexCache.size - 1); + beginTex(); int nInVert = in.lastVertex - in.firstVertex + 1; if (fill && 4 <= nInVert) { int quadCount = nInVert / 4; @@ -9903,12 +9945,12 @@ public class PGraphicsOpenGL extends PGraphics { } partitionRawIndices(); } - setLastTexIndex(tess.lastPolyIndex, tess.polyIndexCache.size - 1); + endTex(); tessellateEdges(); } void tessellateQuadStrip() { - setFirstTexIndex(tess.polyIndexCount, tess.polyIndexCache.size - 1); + beginTex(); int nInVert = in.lastVertex - in.firstVertex + 1; if (fill && 4 <= nInVert) { int quadCount = nInVert / 2 - 1; @@ -9931,7 +9973,7 @@ public class PGraphicsOpenGL extends PGraphics { } partitionRawIndices(); } - setLastTexIndex(tess.lastPolyIndex, tess.polyIndexCache.size - 1); + endTex(); tessellateEdges(); } @@ -10059,6 +10101,29 @@ public class PGraphicsOpenGL extends PGraphics { rawIndices = temp; } + void beginTex() { + setFirstTexIndex(tess.polyIndexCount, tess.polyIndexCache.size - 1); + } + + void endTex() { + setLastTexIndex(tess.lastPolyIndex, tess.polyIndexCache.size - 1); + } + + void beginNoTex() { + prevTexImage = newTexImage; + newTexImage = null; + setFirstTexIndex(tess.polyIndexCount, tess.polyIndexCache.size - 1); + } + + void endNoTex() { + setLastTexIndex(tess.lastPolyIndex, tess.polyIndexCache.size - 1); + } + + void updateTex() { + beginTex(); + endTex(); + } + void setFirstTexIndex(int firstIndex, int firstCache) { if (texCache != null) { firstTexIndex = firstIndex; @@ -10074,24 +10139,14 @@ public class PGraphicsOpenGL extends PGraphics { texCache.setLastIndex(lastIndex, lastCache); } } - } - - void beginNoTex() { - prevTexImage = newTexImage; - newTexImage = null; - setFirstTexIndex(tess.polyIndexCount, tess.polyIndexCache.size - 1); - } - - void endNoTex() { - setLastTexIndex(tess.lastPolyIndex, tess.polyIndexCache.size - 1); - } + } // ----------------------------------------------------------------- // // Polygon tessellation void tessellatePolygon(boolean solid, boolean closed, boolean calcNormals) { - setFirstTexIndex(tess.polyIndexCount, tess.polyIndexCache.size - 1); + beginTex(); int nInVert = in.lastVertex - in.firstVertex + 1; @@ -10154,8 +10209,8 @@ public class PGraphicsOpenGL extends PGraphics { gluTess.endPolygon(); } - - setLastTexIndex(tess.lastPolyIndex, tess.polyIndexCache.size - 1); + endTex(); + tessellateEdges(); } diff --git a/android/core/src/processing/opengl/PShader.java b/android/core/src/processing/opengl/PShader.java index 43563be75..ca8f682f4 100644 --- a/android/core/src/processing/opengl/PShader.java +++ b/android/core/src/processing/opengl/PShader.java @@ -24,6 +24,7 @@ package processing.opengl; import processing.core.*; + import java.io.IOException; import java.net.URL; @@ -33,7 +34,7 @@ import java.net.URL; * (http://www.hardcorepawn.com/) */ public class PShader { - // shaders constants + // shaders constants static public final int FLAT = 0; static public final int LIT = 1; static public final int TEXTURED = 2; diff --git a/android/core/src/processing/opengl/Texture.java b/android/core/src/processing/opengl/Texture.java index b725fcb85..534f119fd 100644 --- a/android/core/src/processing/opengl/Texture.java +++ b/android/core/src/processing/opengl/Texture.java @@ -39,12 +39,11 @@ import java.util.NoSuchElementException; * */ public class Texture implements PConstants { - public int width, height; - // texture constants - - /** This constant identifies the texture target GL_TEXTURE_2D, that is, - * textures with normalized coordinates */ + /** + * This constant identifies the texture target GL_TEXTURE_2D, that is, + * textures with normalized coordinates + */ public static final int TEXTURE2D = 0; /** Texture quality constants */ @@ -70,13 +69,10 @@ public class Texture implements PConstants { /** This constant identifies the clamp-to-edge wrapping mode */ public static final int CLAMP = 0; /** This constant identifies the repeat wrapping mode */ - public static final int REPEAT = 1; - - protected PApplet parent; // The Processing applet - protected PGraphicsOpenGL pg; // The main renderer - protected PGL pgl; // The interface between Processing and OpenGL. - protected PGL.Context context; // The context that created this texture. - + public static final int REPEAT = 1; + + public int width, height; + // These are public but use at your own risk! public int glID; public int glTarget; @@ -86,7 +82,12 @@ public class Texture implements PConstants { public int glWrapS; public int glWrapT; public int glWidth; - public int glHeight; + public int glHeight; + + protected PApplet parent; // The Processing applet + protected PGraphicsOpenGL pg; // The main renderer + protected PGL pgl; // The interface between Processing and OpenGL. + protected PGL.Context context; // The context that created this texture. protected boolean usingMipmaps; protected float maxTexcoordU; @@ -95,9 +96,11 @@ public class Texture implements PConstants { protected boolean flippedX; protected boolean flippedY; - protected int[] tempPixels = null; protected FrameBuffer tempFbo = null; - + + /** modified portion of the texture */ + protected boolean modified; + protected Object bufferSource; protected LinkedList bufferCache = null; protected Method disposeBufferMethod; @@ -209,7 +212,6 @@ public class Texture implements PConstants { // Nullifying some utility objects so they are recreated with the appropriate // size when needed. - tempPixels = null; tempFbo = null; } @@ -368,13 +370,12 @@ public class Texture implements PConstants { * Copy texture to pixels. Involves video memory to main memory transfer (slow). */ public void get(int[] pixels) { - // TODO: here is ok to create a new pixels array, or an error/warning - // should be thrown instead? - if ((pixels == null) || (pixels.length != width * height)) { - pixels = new int[width * height]; + if (pixels == null) { + throw new RuntimeException("Trying to copy texture to null pixels array"); + } + if (pixels.length != width * height) { + throw new RuntimeException("Trying to copy texture to pixels array of wrong size"); } - - int size = glWidth * glHeight; if (tempFbo == null) { tempFbo = new FrameBuffer(parent, glWidth, glHeight); @@ -388,12 +389,9 @@ public class Texture implements PConstants { tempFbo.readPixels(); pg.popFramebuffer(); - if (tempPixels == null) { - tempPixels = new int[size]; - } - tempFbo.getPixels(tempPixels); + tempFbo.getPixels(pixels); + convertToARGB(pixels); - convertToARGB(tempPixels, pixels); if (flippedX) flipArrayOnX(pixels, 1); if (flippedY) flipArrayOnY(pixels, 1); } @@ -495,6 +493,26 @@ public class Texture implements PConstants { pgl.glBindTexture(glTarget, 0); } + ////////////////////////////////////////////////////////////// + + // Modified flag + + + public boolean isModified() { + return modified; + } + + + public void setModified() { + modified = true; + } + + + public void setModified(boolean m) { + modified = m; + } + + //////////////////////////////////////////////////////////// // Buffer sink interface. @@ -522,7 +540,10 @@ public class Texture implements PConstants { } } } - + + public boolean hasBufferSource() { + return bufferSource != null; + } public boolean hasBuffers() { return bufferSource != null && bufferCache != null && 0 < bufferCache.size(); @@ -541,7 +562,7 @@ public class Texture implements PConstants { if ((data.w != width) || (data.h != height)) { init(data.w, data.h); } - bind(); + bind(); setTexels(data.rgbBuf, 0, 0, width, height); unbind(); @@ -554,6 +575,34 @@ public class Texture implements PConstants { } + protected boolean bufferUpdate(int[] pixels) { + //PApplet.println("buffer update with pix"); + BufferData data = null; + try { + data = bufferCache.remove(0); + } catch (NoSuchElementException ex) { + PGraphics.showWarning("PTexture: don't have pixel data to copy to texture"); + } + + if (data != null) { + if ((data.w != width) || (data.h != height)) { + init(data.w, data.h); + } + bind(); + setTexels(data.rgbBuf, 0, 0, width, height); + unbind(); + + data.rgbBuf.get(pixels); + convertToARGB(pixels); + + data.dispose(); + + return true; + } else { + return false; + } + } + protected void getSourceMethods() { try { disposeBufferMethod = bufferSource.getClass().getMethod("disposeBuffer", new Class[] { Object.class }); @@ -713,7 +762,8 @@ public class Texture implements PConstants { * @param intArray int[] * @param intArray int[] * @param arrayFormat int - */ + */ + /* protected void convertToARGB(int[] intArray, int[] tIntArray, int arrayFormat) { int t = 0; int p = 0; @@ -758,15 +808,14 @@ public class Texture implements PConstants { } } - +*/ /** - * Reorders an OpenGL pixel array (RGBA) into ARGB. The input array must be - * of size glWidth * glHeight, while the resulting array of size width * height. - * @param intArray int[] + * Reorders an OpenGL pixel array (RGBA) into ARGB. The array must be + * of size width * height. * @param intArray int[] */ - protected void convertToARGB(int[] intArray, int[] tIntArray) { + protected void convertToARGB(int[] intArray) { int t = 0; int p = 0; if (PGL.BIG_ENDIAN) { @@ -776,9 +825,8 @@ public class Texture implements PConstants { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int pixel = intArray[p++]; - tIntArray[t++] = (pixel >> 8) | ((pixel << 24) & 0xFF000000); + intArray[t++] = (pixel >> 8) | ((pixel << 24) & 0xFF000000); } - p += glWidth - width; } } else { @@ -788,16 +836,15 @@ public class Texture implements PConstants { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int pixel = intArray[p++]; - tIntArray[t++] = ((pixel & 0xFF) << 16) | + intArray[t++] = ((pixel & 0xFF) << 16) | ((pixel & 0xFF0000) >> 16) | (pixel & 0xFF00FF00); } - p += glWidth - width; } - } } + /////////////////////////////////////////////////////////// @@ -979,7 +1026,7 @@ public class Texture implements PConstants { Parameters res = new Parameters(); if (glTarget == PGL.GL_TEXTURE_2D) { - res.target = TEXTURE2D; + res.target = TEXTURE2D; } if (glFormat == PGL.GL_RGB) { @@ -1061,7 +1108,7 @@ public class Texture implements PConstants { glMagFilter = PGL.GL_LINEAR; glMinFilter = params.mipmaps && PGL.MIPMAPS_ENABLED ? PGL.GL_LINEAR_MIPMAP_LINEAR : PGL.GL_LINEAR; } else { - throw new RuntimeException("Unknown texture filtering mode"); + throw new RuntimeException("Unknown texture filtering mode"); } if (params.wrapU == CLAMP) { @@ -1165,7 +1212,7 @@ public class Texture implements PConstants { this.mipmaps = mipmaps; this.wrapU = CLAMP; this.wrapV = CLAMP; - } + } public Parameters(Parameters src) { set(src);