diff --git a/android/core/src/processing/opengl/FillShaderFragNoTex.glsl b/android/core/src/processing/opengl/FillShaderFragNoTex.glsl index e5dfc17df..8c22a6ac5 100644 --- a/android/core/src/processing/opengl/FillShaderFragNoTex.glsl +++ b/android/core/src/processing/opengl/FillShaderFragNoTex.glsl @@ -19,7 +19,10 @@ Boston, MA 02111-1307 USA */ +#ifdef GL_ES precision mediump float; +precision mediump int; +#endif varying vec4 vertColor; diff --git a/android/core/src/processing/opengl/FillShaderFragTex.glsl b/android/core/src/processing/opengl/FillShaderFragTex.glsl index 829dab39f..d20d96d2a 100644 --- a/android/core/src/processing/opengl/FillShaderFragTex.glsl +++ b/android/core/src/processing/opengl/FillShaderFragTex.glsl @@ -19,7 +19,10 @@ Boston, MA 02111-1307 USA */ +#ifdef GL_ES precision mediump float; +precision mediump int; +#endif uniform sampler2D textureSampler; diff --git a/android/core/src/processing/opengl/LineShaderFrag.glsl b/android/core/src/processing/opengl/LineShaderFrag.glsl index e5dfc17df..8c22a6ac5 100644 --- a/android/core/src/processing/opengl/LineShaderFrag.glsl +++ b/android/core/src/processing/opengl/LineShaderFrag.glsl @@ -19,7 +19,10 @@ Boston, MA 02111-1307 USA */ +#ifdef GL_ES precision mediump float; +precision mediump int; +#endif varying vec4 vertColor; diff --git a/android/core/src/processing/opengl/PFontTexture.java b/android/core/src/processing/opengl/PFontTexture.java index 8b3aa5a61..0be1a5367 100644 --- a/android/core/src/processing/opengl/PFontTexture.java +++ b/android/core/src/processing/opengl/PFontTexture.java @@ -247,7 +247,7 @@ class PFontTexture implements PConstants { int[] rgba = new int[w * h]; int t = 0; int p = 0; - if (PGraphicsOpenGL.BIG_ENDIAN) { + if (PGL.BIG_ENDIAN) { java.util.Arrays.fill(rgba, 0, w, 0xFFFFFF00); // Set the first row to blank pixels. t = w; for (int y = 0; y < glyph.height; y++) { diff --git a/android/core/src/processing/opengl/PGL.java b/android/core/src/processing/opengl/PGL.java index 66acb2e68..ec7dc7b34 100644 --- a/android/core/src/processing/opengl/PGL.java +++ b/android/core/src/processing/opengl/PGL.java @@ -92,6 +92,34 @@ public class PGL { /** Maximum dimension of a texture used to hold font data. **/ public static final int MAX_FONT_TEX_SIZE = 256; + /** Minimum array size to use arrayCopy method(). **/ + static protected final int MIN_ARRAYCOPY_SIZE = 2; + + /** Machine Epsilon for float precision. **/ + static public float FLOAT_EPS = Float.MIN_VALUE; + // Calculation of the Machine Epsilon for float precision. From: + // http://en.wikipedia.org/wiki/Machine_epsilon#Approximation_using_Java + static { + float eps = 1.0f; + + do { + eps /= 2.0f; + } while ((float)(1.0 + (eps / 2.0)) != 1.0); + + FLOAT_EPS = eps; + } + + /** + * Set to true if the host system is big endian (PowerPC, MIPS, SPARC), false + * if little endian (x86 Intel for Mac or PC). + */ + static public boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; + + protected static final String SHADER_PREPROCESSOR_DIRECTIVE = "#ifdef GL_ES\n" + + "precision mediump float;\n" + + "precision mediump int;\n" + + "#endif\n"; + /////////////////////////////////////////////////////////////////////////////////// // OpenGL constants @@ -143,10 +171,12 @@ public class PGL { public static final int GL_RGBA8 = -1; public static final int GL_DEPTH24_STENCIL8 = 0x88F0; + public static final int GL_DEPTH_COMPONENT = GLES20.GL_DEPTH_COMPONENT; public static final int GL_DEPTH_COMPONENT16 = GLES20.GL_DEPTH_COMPONENT16; public static final int GL_DEPTH_COMPONENT24 = 0x81A6; public static final int GL_DEPTH_COMPONENT32 = 0x81A7; + public static final int GL_STENCIL_INDEX = GLES20.GL_STENCIL_INDEX; public static final int GL_STENCIL_INDEX1 = 0x8D46; public static final int GL_STENCIL_INDEX4 = 0x8D47; public static final int GL_STENCIL_INDEX8 = GLES20.GL_STENCIL_INDEX8; @@ -297,7 +327,7 @@ public class PGL { " vertTexcoord = inTexcoord;" + "}"; - protected String texFragShaderSource = "precision mediump float;" + + protected String texFragShaderSource = SHADER_PREPROCESSOR_DIRECTIVE + "uniform sampler2D textureSampler;" + "varying vec2 vertTexcoord;" + "void main() {" + @@ -330,7 +360,7 @@ public class PGL { " gl_Position = vec4(inVertex, 0, 1);" + "}"; - protected String rectFragShaderSource = "precision mediump float;" + + protected String rectFragShaderSource = SHADER_PREPROCESSOR_DIRECTIVE + "uniform vec4 rectColor;" + "void main() {" + " gl_FragColor = rectColor;" + @@ -338,6 +368,14 @@ public class PGL { /////////////////////////////////////////////////////////////////////////////////// + // 1-pixel color, depth, stencil buffers + + protected IntBuffer colorBuffer; + protected FloatBuffer depthBuffer; + protected ByteBuffer stencilBuffer; + + /////////////////////////////////////////////////////////////////////////////////// + // Intialization, finalization @@ -388,7 +426,7 @@ public class PGL { GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, texWidth, texHeight, 0, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, null); - initTexture(GLES20.GL_TEXTURE_2D, texWidth, texHeight, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE); + initTexture(GLES20.GL_TEXTURE_2D, PGL.GL_RGBA, texWidth, texHeight); } GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); @@ -1165,7 +1203,7 @@ public class PGL { } - public void initTexture(int target, int width, int height, int format, int type) { + public void initTexture(int target, int format, int width, int height) { // Doing in patches of 16x16 pixels to avoid creating a (potentially) // very large transient array which in certain situations (memory- // constrained android devices) might lead to an out-of-memory error. @@ -1174,12 +1212,27 @@ public class PGL { int h = PApplet.min(16, height - y); for (int x = 0; x < width; x += 16) { int w = PApplet.min(16, width - x); - GLES20.glTexSubImage2D(target, 0, x, y, w, h, format, type, IntBuffer.wrap(texels)); + glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, IntBuffer.wrap(texels)); } } } - + + public void copyToTexture(int target, int format, int id, int x, int y, int w, int h, IntBuffer buffer) { + enableTexturing(target); + glBindTexture(target, id); + glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, buffer); + glBindTexture(target, 0); + disableTexturing(target); + } + + + public void drawTexture(int target, int id, int width, int height, + int X0, int Y0, int X1, int Y1) { + drawTexture(target, id, width, height, X0, Y0, X1, Y1, X0, Y0, X1, Y1); + } + + public void drawTexture(int target, int id, int width, int height, int texX0, int texY0, int texX1, int texY1, int scrX0, int scrY0, int scrX1, int scrY1) { @@ -1333,6 +1386,27 @@ public class PGL { } + public int getColorValue(int scrX, int scrY) { + if (colorBuffer == null) { + colorBuffer = IntBuffer.allocate(1); + } + colorBuffer.rewind(); + glReadPixels(scrX, pg.height - scrY - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, colorBuffer); + return colorBuffer.get(); + } + + + public float getDepthValue(int scrX, int scrY) { + // http://stackoverflow.com/questions/2596682/opengl-es-2-0-read-depth-buffer + return 0; + } + + + public byte getStencilValue(int scrX, int scrY) { + return 0; + } + + // bit shifting this might be more efficient static public int nextPowerOfTwo(int val) { int ret = 1; @@ -1343,6 +1417,238 @@ public class PGL { } + /** + * Convert native OpenGL format into palatable ARGB format. This function + * leaves alone (ignores) the alpha component. Also flips the image + * vertically, since images are upside-down in GL. + */ + static public void nativeToJavaRGB(int[] pixels, int width, int height) { + int index = 0; + int yindex = (height - 1) * width; + for (int y = 0; y < height / 2; y++) { + if (BIG_ENDIAN) { + for (int x = 0; x < width; x++) { + int temp = pixels[index]; + // ignores alpha component, just sets it opaque + pixels[index] = 0xff000000 | ((pixels[yindex] >> 8) & 0x00ffffff); + pixels[yindex] = 0xff000000 | ((temp >> 8) & 0x00ffffff); + index++; + yindex++; + } + } else { // LITTLE_ENDIAN, convert ABGR to ARGB + for (int x = 0; x < width; x++) { + int temp = pixels[index]; + // identical to endPixels because only two + // components are being swapped + pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) | + (pixels[yindex] & 0xff00) | + ((pixels[yindex] >> 16) & 0xff); + pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) | + (temp & 0xff00) | + ((temp >> 16) & 0xff); + index++; + yindex++; + } + } + yindex -= width * 2; + } + + // When height is an odd number, the middle line needs to be + // endian swapped, but not y-swapped. + // http://dev.processing.org/bugs/show_bug.cgi?id=944 + if ((height % 2) == 1) { + index = (height / 2) * width; + if (BIG_ENDIAN) { + for (int x = 0; x < width; x++) { + pixels[index] = 0xff000000 | ((pixels[index] >> 8) & 0x00ffffff); + index++; + } + } else { + for (int x = 0; x < width; x++) { + pixels[index] = 0xff000000 | ((pixels[index] << 16) & 0xff0000) | + (pixels[index] & 0xff00) | + ((pixels[index] >> 16) & 0xff); + index++; + } + } + } + } + + + /** + * Convert native OpenGL format into palatable ARGB format. This function + * leaves alone (ignores) the alpha component. Also flips the image + * vertically, since images are upside-down in GL. + */ + static public void nativeToJavaARGB(int[] pixels, int width, int height) { + int index = 0; + int yindex = (height - 1) * width; + for (int y = 0; y < height / 2; y++) { + if (BIG_ENDIAN) { + for (int x = 0; x < width; x++) { + int temp = pixels[index]; + // ignores alpha component, just sets it opaque + pixels[index] = (pixels[yindex] & 0xff000000) | + ((pixels[yindex] >> 8) & 0x00ffffff); + pixels[yindex] = (temp & 0xff000000) | + ((temp >> 8) & 0x00ffffff); + index++; + yindex++; + } + } else { // LITTLE_ENDIAN, convert ABGR to ARGB + for (int x = 0; x < width; x++) { + int temp = pixels[index]; + pixels[index] = (pixels[yindex] & 0xff000000) | + ((pixels[yindex] << 16) & 0xff0000) | + (pixels[yindex] & 0xff00) | + ((pixels[yindex] >> 16) & 0xff); + pixels[yindex] = (temp & 0xff000000) | + ((temp << 16) & 0xff0000) | + (temp & 0xff00) | + ((temp >> 16) & 0xff); + index++; + yindex++; + } + } + yindex -= width * 2; + } + + if ((height % 2) == 1) { + index = (height / 2) * width; + if (BIG_ENDIAN) { + for (int x = 0; x < width; x++) { + pixels[index] = (pixels[index] & 0xff000000) | + ((pixels[index] >> 8) & 0x00ffffff); + index++; + } + } else { + for (int x = 0; x < width; x++) { + pixels[index] = (pixels[index] & 0xff000000) | + ((pixels[index] << 16) & 0xff0000) | + (pixels[index] & 0xff00) | + ((pixels[index] >> 16) & 0xff); + index++; + } + } + } + } + + + /** + * Convert ARGB (Java/Processing) data to native OpenGL format. This function + * leaves alone (ignores) the alpha component. Also flips the image + * vertically, since images are upside-down in GL. + */ + static public void javaToNativeRGB(int[] pixels, int width, int height) { + int index = 0; + int yindex = (height - 1) * width; + for (int y = 0; y < height / 2; y++) { + if (BIG_ENDIAN) { + // and convert ARGB back to opengl RGBA components (big endian) + for (int x = 0; x < width; x++) { + int temp = pixels[index]; + pixels[index] = ((pixels[yindex] << 8) & 0xffffff00) | 0xff; + pixels[yindex] = ((temp << 8) & 0xffffff00) | 0xff; + index++; + yindex++; + } + + } else { + // convert ARGB back to native little endian ABGR + for (int x = 0; x < width; x++) { + int temp = pixels[index]; + pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) | + (pixels[yindex] & 0xff00) | + ((pixels[yindex] >> 16) & 0xff); + pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) | + (temp & 0xff00) | + ((temp >> 16) & 0xff); + index++; + yindex++; + } + } + yindex -= width * 2; + } + + if ((height % 2) == 1) { + index = (height / 2) * width; + if (BIG_ENDIAN) { + for (int x = 0; x < width; x++) { + pixels[index] = ((pixels[index] << 8) & 0xffffff00) | 0xff; + index++; + } + } else { + for (int x = 0; x < width; x++) { + pixels[index] = 0xff000000 | ((pixels[index] << 16) & 0xff0000) | + (pixels[index] & 0xff00) | + ((pixels[index] >> 16) & 0xff); + index++; + } + } + } + } + + + /** + * Convert Java ARGB to native OpenGL format. Also flips the image vertically, + * since images are upside-down in GL. + */ + static public void javaToNativeARGB(int[] pixels, int width, int height) { + int index = 0; + int yindex = (height - 1) * width; + for (int y = 0; y < height / 2; y++) { + if (BIG_ENDIAN) { + // and convert ARGB back to opengl RGBA components (big endian) + for (int x = 0; x < width; x++) { + int temp = pixels[index]; + pixels[index] = ((pixels[yindex] >> 24) & 0xff) | + ((pixels[yindex] << 8) & 0xffffff00); + pixels[yindex] = ((temp >> 24) & 0xff) | + ((temp << 8) & 0xffffff00); + index++; + yindex++; + } + + } else { + // convert ARGB back to native little endian ABGR + for (int x = 0; x < width; x++) { + int temp = pixels[index]; + pixels[index] = (pixels[yindex] & 0xff000000) | + ((pixels[yindex] << 16) & 0xff0000) | + (pixels[yindex] & 0xff00) | + ((pixels[yindex] >> 16) & 0xff); + pixels[yindex] = (pixels[yindex] & 0xff000000) | + ((temp << 16) & 0xff0000) | + (temp & 0xff00) | + ((temp >> 16) & 0xff); + index++; + yindex++; + } + } + yindex -= width * 2; + } + + if ((height % 2) == 1) { + index = (height / 2) * width; + if (BIG_ENDIAN) { + for (int x = 0; x < width; x++) { + pixels[index] = ((pixels[index] >> 24) & 0xff) | + ((pixels[index] << 8) & 0xffffff00); + index++; + } + } else { + for (int x = 0; x < width; x++) { + pixels[index] = (pixels[index] & 0xff000000) | + ((pixels[index] << 16) & 0xff0000) | + (pixels[index] & 0xff00) | + ((pixels[index] >> 16) & 0xff); + index++; + } + } + } + } + + public int createShader(int shaderType, String source) { int shader = glCreateShader(shaderType); if (shader != 0) { diff --git a/android/core/src/processing/opengl/PGraphicsOpenGL.java b/android/core/src/processing/opengl/PGraphicsOpenGL.java index 84da76704..e5faea60b 100644 --- a/android/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/android/core/src/processing/opengl/PGraphicsOpenGL.java @@ -24,7 +24,9 @@ package processing.opengl; import java.net.URL; import java.nio.*; import java.util.*; + import processing.core.*; +import processing.opengl.PGraphicsOpenGL.Tessellator.TessellatorCallback; // drawPixels is missing...calls to glDrawPixels are commented out @@ -184,16 +186,8 @@ public class PGraphicsOpenGL extends PGraphics { public PMatrix3D cameraInv; public PMatrix3D modelview; public PMatrix3D modelviewInv; -// public PromiscuousMatrix3D modelviewInv; // temporary type until we sort things out public PMatrix3D projmodelview; -// class PromiscuousMatrix3D extends PMatrix3D { -// public void invTranslate(float tx, float ty, float tz) { -// super.invTranslate(tx, ty, tz); -// } -// } - - // To pass to shaders protected float[] glProjection; protected float[] glModelview; @@ -301,46 +295,25 @@ public class PGraphicsOpenGL extends PGraphics { protected PFramebuffer offscreenFramebufferMultisample; protected boolean offscreenMultisample; - // ........................................................ - - // Utility variables: - - /** True if we are inside a beginDraw()/endDraw() block. */ - protected boolean drawing = false; - - /** Used to detect the occurrence of a frame resize event. */ - protected boolean resized = false; - - /** Viewport dimensions. */ - protected int[] viewport = {0, 0, 0, 0}; - - /** Used to register calls to glClear. */ - protected boolean clearColorBuffer; - protected boolean clearColorBuffer0; - - protected boolean openContour = false; - protected boolean breakShape = false; - protected boolean defaultEdges = false; - protected PImage textureImage0; + protected boolean offscreenNotCurrent; // ........................................................ - // Drawing surface: + // Screen surface: - /** A handy reference to the PTexture bound to the drawing surface (off or on-screen) */ + /** A handy reference to the PTexture bound to the drawing surface + * (off or on-screen) */ protected PTexture texture; - /** The crop rectangle for texture. It should always be {0, 0, width, height}. */ - protected int[] texCrop; - - /** IntBuffer to go with the pixels[] array. */ + /** IntBuffer wrapping the pixels array. */ protected IntBuffer pixelBuffer; - /** 1-pixel get/set buffer. */ - protected IntBuffer getsetBuffer; + /** Array to store pixels in OpenGL format. */ + protected int[] rgbaPixels; - /** 1-pixel get/set texture. */ - protected PTexture getsetTexture; + /** Flag to indicate if the user is manipulating the + * pixels array through the set()/get() methods */ + protected boolean setgetPixels; // ........................................................ @@ -369,33 +342,37 @@ public class PGraphicsOpenGL extends PGraphics { new PMatrix3D(-1, 3, -3, 1, 3, -6, 3, 0, -3, 3, 0, 0, - 1, 0, 0, 0); - - // ........................................................ + 1, 0, 0, 0); - // Constants + // ........................................................ - static protected final int MIN_ARRAYCOPY_SIZE = 2; - - static public float FLOAT_EPS = Float.MIN_VALUE; - // Calculation of the Machine Epsilon for float precision. From: - // http://en.wikipedia.org/wiki/Machine_epsilon#Approximation_using_Java - static { - float eps = 1.0f; - - do { - eps /= 2.0f; - } while ((float)(1.0 + (eps / 2.0)) != 1.0); - - FLOAT_EPS = eps; - } + // Utility variables: - /** - * Set to true if the host system is big endian (PowerPC, MIPS, SPARC), false - * if little endian (x86 Intel for Mac or PC). - */ - static public boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; + /** True if we are inside a beginDraw()/endDraw() block. */ + protected boolean drawing = false; + /** Type of pixels operation. */ + static protected final int OP_NONE = 0; + static protected final int OP_READ = 1; + static protected final int OP_WRITE = 2; + protected int pixelsOp = OP_NONE; + + /** Used to detect the occurrence of a frame resize event. */ + protected boolean resized = false; + + /** Viewport dimensions. */ + protected int[] viewport = {0, 0, 0, 0}; + + /** Used to register calls to glClear. */ + protected boolean clearColorBuffer; + protected boolean clearColorBuffer0; + + protected boolean openContour = false; + protected boolean breakShape = false; + protected boolean defaultEdges = false; + protected PImage textureImage0; + + protected boolean perspectiveCorrectedLines = false; ////////////////////////////////////////////////////////////// @@ -983,7 +960,7 @@ public class PGraphicsOpenGL extends PGraphics { currentFramebuffer = fbStack.pop(); currentFramebuffer.bind(); } catch (EmptyStackException e) { - PGraphics.showWarning(": Empty framebuffer stack"); + PGraphics.showWarning("P3D: Empty framebuffer stack"); } } @@ -1392,12 +1369,11 @@ public class PGraphicsOpenGL extends PGraphics { pushFramebuffer(); if (offscreenMultisample) { - setFramebuffer(offscreenFramebufferMultisample); - pgl.glDrawBuffer(PGL.GL_COLOR_ATTACHMENT0); + setFramebuffer(offscreenFramebufferMultisample); } else { setFramebuffer(offscreenFramebuffer); - } - + } + pgl.glDrawBuffer(PGL.GL_COLOR_ATTACHMENT0); pgl.updateOffscreen(pg.pgl); } @@ -1504,6 +1480,8 @@ public class PGraphicsOpenGL extends PGraphics { // The current normal vector is set to be parallel to the Z axis. normalX = normalY = normalZ = 0; + perspectiveCorrectedLines = hints[ENABLE_PERSPECTIVE_CORRECTED_LINES]; + // Clear depth and stencil buffers. pgl.glDepthMask(true); pgl.glClearColor(0, 0, 0, 0); @@ -1523,8 +1501,12 @@ public class PGraphicsOpenGL extends PGraphics { } else { pgl.glDepthMask(true); } - + drawing = true; + pixelsOp = OP_NONE; + + modified = false; + setgetPixels = false; clearColorBuffer0 = clearColorBuffer; clearColorBuffer = false; @@ -1539,6 +1521,17 @@ public class PGraphicsOpenGL extends PGraphics { if (flushMode == FLUSH_WHEN_FULL) { // Flushing any remaining geometry. flush(); + +// if (settingPixels) { +// // Drawing the pixels array. We can only get +// // here if there was no geometry to flush at +// // the end of draw, and the user has been +// // manipulating individual pixels. If that's +// // the case we need to update the screen with +// // the changes in the pixels array. +// updatePixels(); +// } + // TODO: Implement depth sorting (http://code.google.com/p/processing/issues/detail?id=51) //if (hints[ENABLE_DEPTH_SORT]) { // flush(); @@ -1621,19 +1614,66 @@ public class PGraphicsOpenGL extends PGraphics { } - // Utility function to get ready OpenGL for a specific - // operation, such as grabbing the contents of the color - // buffer. - protected void beginGLOp() { - pgl.updateOffscreen(pg.pgl); + protected void beginPixelsOp(int op) { + if (primarySurface) { + if (op == OP_READ) { + pgl.glReadBuffer(PGL.GL_FRONT); + } else { + pgl.glDrawBuffer(PGL.GL_BACK); + } + offscreenNotCurrent = false; + } else { + // Making sure that the offscreen FBO is current. This allows to do calls + // like loadPixels(), set() or get() without enclosing them between + // beginDraw()/endDraw() when working with a PGraphics object. We don't + // need the rest of the surface initialization/finalization, since only + // the pixels are affected. + if (op == OP_READ) { + // We always read the screen pixels from the color FBO. + offscreenNotCurrent = offscreenFramebuffer != currentFramebuffer; + if (offscreenNotCurrent) { + pushFramebuffer(); + setFramebuffer(offscreenFramebuffer); + pgl.updateOffscreen(pg.pgl); + } + pgl.glReadBuffer(PGL.GL_COLOR_ATTACHMENT0); + } else { + // We can write directly to the color FBO, or to the multisample FBO + // if multisampling is enabled. + if (offscreenMultisample) { + offscreenNotCurrent = offscreenFramebufferMultisample != currentFramebuffer; + } else { + offscreenNotCurrent = offscreenFramebuffer != currentFramebuffer; + } + if (offscreenNotCurrent) { + pushFramebuffer(); + if (offscreenMultisample) { + setFramebuffer(offscreenFramebufferMultisample); + } else { + setFramebuffer(offscreenFramebuffer); + } + pgl.updateOffscreen(pg.pgl); + } + pgl.glDrawBuffer(PGL.GL_COLOR_ATTACHMENT0); + } + } + pixelsOp = op; } - // Pairs-up with beginGLOp(). - protected void endGLOp() { - } + protected void endPixelsOp() { + if (offscreenNotCurrent) { + if (pixelsOp == OP_WRITE && offscreenMultisample) { + // We were writing to the multisample FBO, so we need + // to blit its contents to the color FBO. + offscreenFramebufferMultisample.copy(offscreenFramebuffer); + } + popFramebuffer(); + } + pixelsOp = OP_NONE; + } + - protected void updateGLProjection() { if (glProjection == null) { glProjection = new float[16]; @@ -1824,12 +1864,16 @@ public class PGraphicsOpenGL extends PGraphics { flush(); } else if (which == DISABLE_PERSPECTIVE_CORRECTED_LINES) { if (0 < tessGeo.lineVertexCount && 0 < tessGeo.lineIndexCount) { + // We flush the geometry using the previous line setting. flush(); - } + } + perspectiveCorrectedLines = false; } else if (which == ENABLE_PERSPECTIVE_CORRECTED_LINES) { if (0 < tessGeo.lineVertexCount && 0 < tessGeo.lineIndexCount) { + // We flush the geometry using the previous line setting. flush(); - } + } + perspectiveCorrectedLines = true; } } @@ -2235,9 +2279,17 @@ public class PGraphicsOpenGL extends PGraphics { boolean hasPoints = 0 < tessGeo.pointVertexCount && 0 < tessGeo.pointIndexCount; boolean hasLines = 0 < tessGeo.lineVertexCount && 0 < tessGeo.lineIndexCount; boolean hasFill = 0 < tessGeo.fillVertexCount && 0 < tessGeo.fillIndexCount; + boolean hasPixels = modified && pixels != null; + + if (hasPixels) { + // If the user has been manipulating individual pixels, + // the changes need to be copied to the screen before + // drawing any new geometry. + renderPixels(); + setgetPixels = false; + } if (hasPoints || hasLines || hasFill) { - if (flushMode == FLUSH_WHEN_FULL && !hints[DISABLE_TRANSFORM_CACHE]) { // The modelview transformation has been applied already to the // tessellated vertices, so we set the OpenGL modelview matrix as @@ -2263,11 +2315,48 @@ public class PGraphicsOpenGL extends PGraphics { } } - tessGeo.clear(); - texCache.clear(); + tessGeo.clear(); + texCache.clear(); } + protected void renderPixels() { + int mi1 = my1 * width + mx1; + int mi2 = my2 * width + mx2; + int mw = mx2 - mx1 + 1; + int mh = my2 - my1 + 1; + int mlen = mi2 - mi1 + 1; + + if (rgbaPixels == null || rgbaPixels.length < mlen) { + rgbaPixels = new int[mlen]; + } + + PApplet.arrayCopy(pixels, mi1, rgbaPixels, 0, mlen); + PGL.javaToNativeARGB(rgbaPixels, mw, mh); + + //PApplet.arrayCopy(pixels, rgbaPixels); + //PGL.javaToNativeARGB(rgbaPixels, width, height); + + // Copying pixel buffer to screen texture... + pgl.copyToTexture(texture.glTarget, texture.glFormat, texture.glID, + mx1, my1, mw, mh, IntBuffer.wrap(rgbaPixels)); + + if (primarySurface || offscreenMultisample) { + // ...and drawing the texture to screen... but only + // if we are on the primary surface or we have + // multisampled FBO. Why? Because in the case of non- + // multisampled FBO, texture is actually the color buffer + // used by the color FBO, so with the copy operation we + // should be done updating the (off)screen buffer. + beginPixelsOp(OP_WRITE); + drawTexture(mx1, my1, mw, mh); + endPixelsOp(); + } + + modified = false; + } + + protected void renderPoints() { if (!pointVBOsCreated) { createPointBuffers(); @@ -2384,59 +2473,6 @@ public class PGraphicsOpenGL extends PGraphics { shader.stop(); } - - - ////////////////////////////////////////////////////////////// - - // PSHAPE RENDERING IN 3D - - - public void shape(PShape shape, float x, float y, float z) { - if (shape.isVisible()) { // don't do expensive matrix ops if invisible - pushMatrix(); - - if (shapeMode == CENTER) { - translate(x - shape.getWidth() / 2, y - shape.getHeight() / 2, z - - shape.getDepth() / 2); - - } else if ((shapeMode == CORNER) || (shapeMode == CORNERS)) { - translate(x, y, z); - } - shape.draw(this); - - popMatrix(); - } - } - - - public void shape(PShape shape, float x, float y, float z, float c, float d, - float e) { - if (shape.isVisible()) { // don't do expensive matrix ops if invisible - pushMatrix(); - - if (shapeMode == CENTER) { - // x, y and z are center, c, d and e refer to a diameter - translate(x - c / 2f, y - d / 2f, z - e / 2f); - scale(c / shape.getWidth(), d / shape.getHeight(), e / shape.getDepth()); - - } else if (shapeMode == CORNER) { - translate(x, y, z); - scale(c / shape.getWidth(), d / shape.getHeight(), e / shape.getDepth()); - - } else if (shapeMode == CORNERS) { - // c, d, e are x2/y2/z2, make them into width/height/depth - c -= x; - d -= y; - e -= z; - // then same as above - translate(x, y, z); - scale(c / shape.getWidth(), d / shape.getHeight(), e / shape.getDepth()); - } - shape.draw(this); - - popMatrix(); - } - } ////////////////////////////////////////////////////////////// @@ -2972,27 +3008,58 @@ public class PGraphicsOpenGL extends PGraphics { // SHAPE // public void shapeMode(int mode) - - public void shape(PShape3D shape) { - shape.draw(this); + + public void shape(PShape shape, float x, float y, float z) { + if (shape.isVisible()) { // don't do expensive matrix ops if invisible + flush(); + + pushMatrix(); + + if (shapeMode == CENTER) { + translate(x - shape.getWidth() / 2, y - shape.getHeight() / 2, z + - shape.getDepth() / 2); + + } else if ((shapeMode == CORNER) || (shapeMode == CORNERS)) { + translate(x, y, z); + } + shape.draw(this); + + popMatrix(); + } } - - public void shape(PShape3D shape, float x, float y) { - shape(shape, x, y, 0); + + public void shape(PShape shape, float x, float y, float z, float c, float d, float e) { + if (shape.isVisible()) { // don't do expensive matrix ops if invisible + flush(); + + pushMatrix(); + + if (shapeMode == CENTER) { + // x, y and z are center, c, d and e refer to a diameter + translate(x - c / 2f, y - d / 2f, z - e / 2f); + scale(c / shape.getWidth(), d / shape.getHeight(), e / shape.getDepth()); + + } else if (shapeMode == CORNER) { + translate(x, y, z); + scale(c / shape.getWidth(), d / shape.getHeight(), e / shape.getDepth()); + + } else if (shapeMode == CORNERS) { + // c, d, e are x2/y2/z2, make them into width/height/depth + c -= x; + d -= y; + e -= z; + // then same as above + translate(x, y, z); + scale(c / shape.getWidth(), d / shape.getHeight(), e / shape.getDepth()); + } + shape.draw(this); + + popMatrix(); + } } - - public void shape(PShape3D shape, float x, float y, float z) { - pushMatrix(); - translate(x, y, z); - shape.draw(this); - popMatrix(); - } - - - // public void shape(PShape shape, float x, float y, float c, float d) ////////////////////////////////////////////////////////////// @@ -3180,19 +3247,19 @@ public class PGraphicsOpenGL extends PGraphics { } modelview.translate(tx, ty, tz); - invTranslate(modelviewInv, tx, ty, tz); + invTranslate(modelviewInv, tx, ty, tz); projmodelview.translate(tx, ty, tz); } - + static protected void invTranslate(PMatrix3D matrix, float tx, float ty, float tz) { matrix.preApply(1, 0, 0, -tx, 0, 1, 0, -ty, 0, 0, 1, -tz, 0, 0, 0, 1); } - - + + /** * Two dimensional rotation. Same as rotateZ (this is identical to a 3D * rotation along the z-axis) but included for clarity -- it'd be weird for @@ -3229,11 +3296,10 @@ public class PGraphicsOpenGL extends PGraphics { } modelview.rotate(angle, v0, v1, v2); -// modelviewInv.invRotate(angle, v0, v1, v2); invRotate(modelviewInv, angle, v0, v1, v2); calcProjmodelview(); // Possibly cheaper than doing projmodelview.rotate() } - + static private void invRotate(PMatrix3D matrix, float angle, float v0, float v1, float v2) { //TODO should make sure this vector is normalized @@ -3246,8 +3312,8 @@ public class PGraphicsOpenGL extends PGraphics { (t*v0*v1) + (s*v2), (t*v1*v1) + c, (t*v1*v2) - (s*v0), 0, (t*v0*v2) - (s*v1), (t*v1*v2) + (s*v0), (t*v2*v2) + c, 0, 0, 0, 0, 1); - } - + } + /** * Same as scale(s, s, s). @@ -3274,10 +3340,10 @@ public class PGraphicsOpenGL extends PGraphics { } modelview.scale(sx, sy, sz); - invScale(modelviewInv, sx, sy, sz); + invScale(modelviewInv, sx, sy, sz); projmodelview.scale(sx, sy, sz); } - + static protected void invScale(PMatrix3D matrix, float x, float y, float z) { matrix.preApply(1/x, 0, 0, 0, 0, 1/y, 0, 0, 0, 0, 1/z, 0, 0, 0, 0, 1); @@ -4509,378 +4575,99 @@ public class PGraphicsOpenGL extends PGraphics { // setCache, getCache, removeCache // isModified, setModified + ////////////////////////////////////////////////////////////// // LOAD/UPDATE PIXELS + // Initializes the pixels array, copying the current contents of the + // color buffer into it. public void loadPixels() { - flush(); + if (!setgetPixels) { + // Draws any remaining geometry in case the user is still not + // setting/getting new pixels. + flush(); + } if ((pixels == null) || (pixels.length != width * height)) { pixels = new int[width * height]; - pixelBuffer = IntBuffer.allocate(pixels.length); - } - - boolean outsideDraw = primarySurface && !drawing; - if (outsideDraw) { - beginGLOp(); + pixelBuffer = IntBuffer.wrap(pixels); } - boolean notCurrent = !primarySurface && offscreenFramebuffer != currentFramebuffer; - - if (notCurrent) { - pushFramebuffer(); - setFramebuffer(offscreenFramebuffer); - } - - pixelBuffer.rewind(); - if (primarySurface) { - pgl.glReadBuffer(PGL.GL_FRONT); - } - pgl.glReadPixels(0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, pixelBuffer); - - if (notCurrent) { - popFramebuffer(); - } - - pixelBuffer.get(pixels); - - // flip vertically (opengl stores images upside down), - // and swap RGBA components to ARGB (big endian) - int index = 0; - int yindex = (height - 1) * width; - for (int y = 0; y < height / 2; y++) { - if (BIG_ENDIAN) { - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - // ignores alpha component, just sets it opaque - pixels[index] = 0xff000000 | ((pixels[yindex] >> 8) & 0x00ffffff); - pixels[yindex] = 0xff000000 | ((temp >> 8) & 0x00ffffff); - - index++; - yindex++; - } - } else { // LITTLE_ENDIAN, convert ABGR to ARGB - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - - // identical to endPixels because only two - // components are being swapped - pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) - | (pixels[yindex] & 0xff00) | ((pixels[yindex] >> 16) & 0xff); - - pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) - | (temp & 0xff00) | ((temp >> 16) & 0xff); - - index++; - yindex++; - } + if (!setgetPixels) { + beginPixelsOp(OP_READ); + pixelBuffer.rewind(); + pgl.glReadPixels(0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, pixelBuffer); + endPixelsOp(); + + PGL.nativeToJavaARGB(pixels, width, height); + + if (primarySurface) { + loadTextureImpl(POINT); + pixelsToTexture(); } - yindex -= width * 2; - } - - // When height is an odd number, the middle line needs to be - // endian swapped, but not y-swapped. - // http://dev.processing.org/bugs/show_bug.cgi?id=944 - if ((height % 2) == 1) { - index = (height / 2) * width; - if (BIG_ENDIAN) { - for (int x = 0; x < width; x++) { - // ignores alpha component, just sets it opaque - pixels[index] = 0xff000000 | ((pixels[index] >> 8) & 0x00ffffff); - } - } else { - for (int x = 0; x < width; x++) { - pixels[index] = 0xff000000 | ((pixels[index] << 16) & 0xff0000) - | (pixels[index] & 0xff00) | ((pixels[index] >> 16) & 0xff); - } - } - } - - if (primarySurface) { - // Load texture. - loadTextureImpl(POINT); - pixelsToTexture(); - } - - if (outsideDraw) { - endGLOp(); - } - } - - - /** - * Convert native OpenGL format into palatable ARGB format. This function - * leaves alone (ignores) the alpha component. Also flips the image - * vertically, since images are upside-down in GL. - */ - static public void nativeToJavaRGB(PImage image) { - int index = 0; - int yindex = (image.height - 1) * image.width; - for (int y = 0; y < image.height / 2; y++) { - if (BIG_ENDIAN) { - for (int x = 0; x < image.width; x++) { - int temp = image.pixels[index]; - // ignores alpha component, just sets it opaque - image.pixels[index] = 0xff000000 | ((image.pixels[yindex] >> 8) & 0x00ffffff); - image.pixels[yindex] = 0xff000000 | ((temp >> 8) & 0x00ffffff); - index++; - yindex++; - } - } else { // LITTLE_ENDIAN, convert ABGR to ARGB - for (int x = 0; x < image.width; x++) { - int temp = image.pixels[index]; - - // identical to endPixels because only two - // components are being swapped - image.pixels[index] = 0xff000000 - | ((image.pixels[yindex] << 16) & 0xff0000) - | (image.pixels[yindex] & 0xff00) - | ((image.pixels[yindex] >> 16) & 0xff); - - image.pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) - | (temp & 0xff00) | ((temp >> 16) & 0xff); - - index++; - yindex++; - } - } - yindex -= image.width * 2; } } - /** - * Convert native OpenGL format into palatable ARGB format. This function - * leaves alone (ignores) the alpha component. Also flips the image - * vertically, since images are upside-down in GL. - */ - static public void nativeToJavaARGB(PImage image) { - int index = 0; - int yindex = (image.height - 1) * image.width; - for (int y = 0; y < image.height / 2; y++) { - if (BIG_ENDIAN) { - for (int x = 0; x < image.width; x++) { - int temp = image.pixels[index]; - // ignores alpha component, just sets it opaque - image.pixels[index] = (image.pixels[yindex] & 0xff000000) - | ((image.pixels[yindex] >> 8) & 0x00ffffff); - image.pixels[yindex] = (temp & 0xff000000) - | ((temp >> 8) & 0x00ffffff); - index++; - yindex++; - } - } else { // LITTLE_ENDIAN, convert ABGR to ARGB - for (int x = 0; x < image.width; x++) { - int temp = image.pixels[index]; + ////////////////////////////////////////////////////////////// - // identical to endPixels because only two - // components are being swapped - image.pixels[index] = (image.pixels[yindex] & 0xff000000) - | ((image.pixels[yindex] << 16) & 0xff0000) - | (image.pixels[yindex] & 0xff00) - | ((image.pixels[yindex] >> 16) & 0xff); - - image.pixels[yindex] = (temp & 0xff000000) - | ((temp << 16) & 0xff0000) | (temp & 0xff00) - | ((temp >> 16) & 0xff); - - index++; - yindex++; - } - } - yindex -= image.width * 2; - } - } + // GET/SET PIXELS - - /** - * Convert ARGB (Java/Processing) data to native OpenGL format. This function - * leaves alone (ignores) the alpha component. Also flips the image - * vertically, since images are upside-down in GL. - */ - static public void javaToNativeRGB(PImage image) { - int width = image.width; - int height = image.height; - int pixels[] = image.pixels; - - int index = 0; - int yindex = (height - 1) * width; - for (int y = 0; y < height / 2; y++) { - if (BIG_ENDIAN) { - // and convert ARGB back to opengl RGBA components (big endian) - for (int x = 0; x < image.width; x++) { - int temp = pixels[index]; - /* - * pixels[index] = ((pixels[yindex] >> 24) & 0xff) | ((pixels[yindex] - * << 8) & 0xffffff00); pixels[yindex] = ((temp >> 24) & 0xff) | - * ((temp << 8) & 0xffffff00); - */ - pixels[index] = ((pixels[yindex] << 8) & 0xffffff00) | 0xff; - pixels[yindex] = ((temp << 8) & 0xffffff00) | 0xff; - - index++; - yindex++; - } - - } else { - // convert ARGB back to native little endian ABGR - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - - pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) - | (pixels[yindex] & 0xff00) | ((pixels[yindex] >> 16) & 0xff); - - pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) - | (temp & 0xff00) | ((temp >> 16) & 0xff); - - index++; - yindex++; - } - } - yindex -= width * 2; - } + + public int get(int x, int y) { + loadPixels(); + setgetPixels = true; + return super.get(x, y); } - /** - * Convert Java ARGB to native OpenGL format. Also flips the image vertically, - * since images are upside-down in GL. - */ - static public void javaToNativeARGB(PImage image) { - int width = image.width; - int height = image.height; - int pixels[] = image.pixels; - - int index = 0; - int yindex = (height - 1) * width; - for (int y = 0; y < height / 2; y++) { - if (BIG_ENDIAN) { - // and convert ARGB back to opengl RGBA components (big endian) - for (int x = 0; x < image.width; x++) { - int temp = pixels[index]; - pixels[index] = ((pixels[yindex] >> 24) & 0xff) - | ((pixels[yindex] << 8) & 0xffffff00); - pixels[yindex] = ((temp >> 24) & 0xff) | ((temp << 8) & 0xffffff00); - - index++; - yindex++; - } - - } else { - // convert ARGB back to native little endian ABGR - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - - pixels[index] = (pixels[yindex] & 0xff000000) - | ((pixels[yindex] << 16) & 0xff0000) | (pixels[yindex] & 0xff00) - | ((pixels[yindex] >> 16) & 0xff); - - pixels[yindex] = (pixels[yindex] & 0xff000000) - | ((temp << 16) & 0xff0000) | (temp & 0xff00) - | ((temp >> 16) & 0xff); - - index++; - yindex++; - } - } - yindex -= width * 2; - } + protected PImage getImpl(int x, int y, int w, int h) { + loadPixels(); + setgetPixels = true; + return super.getImpl(x, y, w, h); } - public void updatePixels() { - // flip vertically (opengl stores images upside down), - - int index = 0; - int yindex = (height - 1) * width; - for (int y = 0; y < height / 2; y++) { - if (BIG_ENDIAN) { - // and convert ARGB back to opengl RGBA components (big endian) - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - - pixels[index] = ((pixels[yindex] << 8) & 0xffffff00) | 0xff; - pixels[yindex] = ((temp << 8) & 0xffffff00) | 0xff; - - index++; - yindex++; - } - - } else { - // convert ARGB back to native little endian ABGR - for (int x = 0; x < width; x++) { - int temp = pixels[index]; - - pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) - | (pixels[yindex] & 0xff00) | ((pixels[yindex] >> 16) & 0xff); - - pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) - | (temp & 0xff00) | ((temp >> 16) & 0xff); - - index++; - yindex++; - } - } - yindex -= width * 2; - } - - pixelBuffer.rewind(); - pixelBuffer.put(pixels); - - boolean outsideDraw = primarySurface && !drawing; - if (outsideDraw) { - beginGLOp(); - } - - // Copying pixel buffer to screen texture... - copyToTexture(pixelBuffer); - - // ...and drawing the texture to screen. - - boolean notCurrent = !primarySurface && offscreenFramebuffer != currentFramebuffer; - if (notCurrent) { - // If this is an offscreen surface that is not current, then the offscreen framebuffer - // is bound so the texture is drawn to it instead to the main surface. Even if the - // surface in antialiased we don't need to bind the multisample framebuffer, we - // just draw to the regular offscreen framebuffer. - pushFramebuffer(); - setFramebuffer(offscreenFramebuffer); - } - - drawTexture(); - - if (notCurrent) { - popFramebuffer(); - } - - if (outsideDraw) { - endGLOp(); - } + public void set(int x, int y, int argb) { + loadPixels(); + setgetPixels = true; + super.set(x, y, argb); } + + protected void setImpl(int dx, int dy, int sx, int sy, int sw, int sh, + PImage src) { + loadPixels(); + setgetPixels = true; + super.setImpl(dx, dy, sx, sy, sw, sh, src); + } + ////////////////////////////////////////////////////////////// // LOAD/UPDATE TEXTURE + // Copies the contents of the color buffer into the pixels + // array, and then the pixels array into the screen texture. public void loadTexture() { if (primarySurface) { - if (!drawing) { - beginGLOp(); - } - loadTextureImpl(POINT); loadPixels(); pixelsToTexture(); - - if (!drawing) { - endGLOp(); - } } } + + + // Draws wherever it is in the screen texture right now to the screen. + public void updateTexture() { + flush(); + beginPixelsOp(OP_WRITE); + drawTexture(); + endPixelsOp(); + } protected void loadTextureImpl(int sampling) { @@ -4891,58 +4678,21 @@ public class PGraphicsOpenGL extends PGraphics { texture.setFlippedY(true); this.setCache(pg, texture); this.setParams(pg, params); - - texCrop = new int[4]; - texCrop[0] = 0; - texCrop[1] = 0; - texCrop[2] = width; - texCrop[3] = height; } } - // Draws wherever it is in the screen texture right now to the screen. - public void updateTexture() { - flush(); - - boolean outsideDraw = primarySurface && !drawing; - if (outsideDraw) { - beginGLOp(); - } - - boolean notCurrent = !primarySurface && offscreenFramebuffer != currentFramebuffer; - if (notCurrent) { - pushFramebuffer(); - setFramebuffer(offscreenFramebuffer); - } - - drawTexture(); - - if (notCurrent) { - popFramebuffer(); - } - - if (outsideDraw) { - endGLOp(); - } - } - - protected void drawTexture() { - drawTexture(texture, texCrop, 0, 0, width, height); + pgl.drawTexture(texture.glTarget, texture.glID, + texture.glWidth, texture.glHeight, + 0, 0, width, height); } + - - protected void copyToTexture(IntBuffer buffer) { - copyToTexture(texture, buffer, 0, 0, width, height); - } - - - protected void copyFrameToTexture() { - // Make sure that the execution off all the openGL commands is - // finished before loading the texture. - pgl.glFinish(); - loadTexture(); + protected void drawTexture(int x, int y, int w, int h) { + pgl.drawTexture(texture.glTarget, texture.glID, + texture.glWidth, texture.glHeight, + x, y, x + w, y + h); } @@ -4955,159 +4705,40 @@ public class PGraphicsOpenGL extends PGraphics { texture.get(pixels); } - + ////////////////////////////////////////////////////////////// - // RESIZE - - - public void resize(int wide, int high) { - PGraphics.showMethodWarning("resize"); - } - - - ////////////////////////////////////////////////////////////// - - // GET/SET + // IMAGE CONVERSION - public int get(int x, int y) { - flush(); - - if (getsetBuffer == null) { - getsetBuffer = IntBuffer.allocate(1); - } - - boolean outsideDraw = primarySurface && !drawing; - if (outsideDraw) { - beginGLOp(); - } - - boolean notCurrent = !primarySurface && offscreenFramebuffer != currentFramebuffer; - if (notCurrent) { - // If the surface is not primary and multisampling is on, then the framebuffer - // will be switched momentarily from offscreenFramebufferMultisample to offscreenFramebuffer. - // This is in fact correct, because the glReadPixels() function doesn't work with - // multisample framebuffer attached as the read buffer. - pushFramebuffer(); - setFramebuffer(offscreenFramebuffer); - } - - getsetBuffer.rewind(); - if (primarySurface) { - pgl.glReadBuffer(PGL.GL_FRONT); - } - pgl.glReadPixels(x, height - y - 1, 1, 1, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, getsetBuffer); - - if (notCurrent) { - popFramebuffer(); - } - - int getset = getsetBuffer.get(0); - - if (outsideDraw) { - endGLOp(); + static public void nativeToJavaRGB(PImage image) { + if (image.pixels != null) { + PGL.nativeToJavaRGB(image.pixels, image.width, image.height); } - - if (BIG_ENDIAN) { - return 0xff000000 | ((getset >> 8) & 0x00ffffff); - - } else { - return 0xff000000 | ((getset << 16) & 0xff0000) | (getset & 0xff00) - | ((getset >> 16) & 0xff); - } } - - // public PImage get(int x, int y, int w, int h) - - protected PImage getImpl(int x, int y, int w, int h) { - flush(); - - PImage newbie = parent.createImage(w, h, ARGB); - - IntBuffer newbieBuffer = IntBuffer.allocate(w * h); - - boolean notCurrent = !primarySurface && offscreenFramebuffer != currentFramebuffer; - if (notCurrent) { - pushFramebuffer(); - setFramebuffer(offscreenFramebuffer); + static public void nativeToJavaARGB(PImage image) { + if (image.pixels != null) { + PGL.nativeToJavaARGB(image.pixels, image.width, image.height); } + } + - newbieBuffer.rewind(); - if (primarySurface) { - pgl.glReadBuffer(PGL.GL_FRONT); - } - - pgl.glReadPixels(x, height - y - h, w, h, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, newbieBuffer); - - if (notCurrent) { - popFramebuffer(); - } - - newbie.loadPixels(); - newbieBuffer.get(newbie.pixels); - nativeToJavaARGB(newbie); - return newbie; + static public void javaToNativeRGB(PImage image) { + if (image.pixels != null) { + PGL.javaToNativeRGB(image.pixels, image.width, image.height); + } } - public PImage get() { - return get(0, 0, width, height); + static public void javaToNativeARGB(PImage image) { + if (image.pixels != null) { + PGL.javaToNativeARGB(image.pixels, image.width, image.height); + } } - public void set(int x, int y, int argb) { - flush(); - - float a = ((argb >> 24) & 0xFF) / 255.0f; - float r = ((argb >> 16) & 0xFF) / 255.0f; - float g = ((argb >> 8) & 0xFF) / 255.0f; - float b = ((argb >> 0) & 0xFF) / 255.0f; - - pgl.drawRectangle(r, g, b, a, x, y, x + 1, y + 1); - } - - - /** - * Set an image directly to the screen. - * - */ - public void set(int x, int y, PImage source) { - flush(); - - PTexture tex = getTexture(source); - if (tex != null) { - int w = source.width; - int h = source.height; - - boolean outsideDraw = primarySurface && !drawing; - if (outsideDraw) { - beginGLOp(); - } - - boolean notCurrent = !primarySurface && offscreenFramebuffer != currentFramebuffer; - if (notCurrent) { - pushFramebuffer(); - setFramebuffer(offscreenFramebuffer); - } - - // The crop region and draw rectangle are given like this to take into account - // inverted y-axis in Processin with respect to OpenGL. - drawTexture(tex, 0, 0, w, h, x, height - y, w, -h); - - if (notCurrent) { - popFramebuffer(); - } - - if (outsideDraw) { - endGLOp(); - } - } - } - - ////////////////////////////////////////////////////////////// // MASK @@ -5345,6 +4976,7 @@ public class PGraphicsOpenGL extends PGraphics { /** * This utility method returns the texture associated to the image. * creating and/or updating it if needed. + * * @param img the image to have a texture metadata associated to it */ public PTexture getTexture(PImage img) { @@ -5371,17 +5003,6 @@ public class PGraphicsOpenGL extends PGraphics { } - /** - * This utility method returns the texture associated to the image, - * but it doesn't create a new texture if the image has no texture. - * @param img the image to have a texture metadata associated to it - */ - protected PTexture queryTexture(PImage img) { - PTexture tex = (PTexture)img.getCache(pg); - return tex; - } - - /** * This utility method creates a texture for the provided image, and adds it * to the metadata cache of the image. @@ -5426,139 +5047,16 @@ public class PGraphicsOpenGL extends PGraphics { } - /** Utility function to render texture. */ - protected void drawTexture(PTexture tex, int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) { - int[] crop = {x1, y1, w1, h1}; - drawTexture(tex, crop, x2, y2, w2, h2); + ////////////////////////////////////////////////////////////// + + // RESIZE + + + public void resize(int wide, int high) { + PGraphics.showMethodWarning("resize"); } - /** Utility function to render texture. */ - protected void drawTexture(PTexture tex, int[] crop, int x, int y, int w, int h) { - drawTexture(tex.glTarget, tex.glID, tex.glWidth, tex.glHeight, crop, x, y, w, h); - } - - - /** Utility function to render texture. */ - protected void drawTexture(int target, int id, int w, int h, int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) { - int[] crop = {x1, y1, w1, h1}; - drawTexture(target, id, w, h, crop, x2, y2, w2, h2); - } - - - /** Utility function to render texture without blend. */ - protected void drawTexture(int target, int id, int tw, int th, int[] crop, int x, int y, int w, int h) { - pgl.enableTexturing(target); - pgl.glBindTexture(target, id); - - int savedBlendMode = blendMode; - blendMode(REPLACE); - - // The texels of the texture replace the color of wherever is on the screen. -// texEnvMode = REPLACE; - - drawTexture(tw, th, crop, x, y, w, h); - - // Returning to the default texture environment mode, MODULATE. - // This allows tinting a texture with the current fragment color. -// texEnvMode = MODULATE; - - pgl.glBindTexture(target, 0); - pgl.disableTexturing(target); - - blendMode(savedBlendMode); - } - - - protected void drawTexture(int w, int h, int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2) { - int[] crop = {x1, y1, w1, h1}; - drawTexture(w, h, crop, x2, y2, w2, h2); - } - - - /** - * Utility function to render currently bound texture using current blend mode. - * Equivalent to: - * glTexParameteriv(GL10.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, crop, 0); - * glDrawTexiOES(x, y, 0, w, h); - * in OpenGL ES. - */ - protected void drawTexture(int tw, int th, int[] crop, int x, int y, int w, int h) { - flush(); - - pgl.glDepthMask(false); - - // TODO: finish this! - /* - - pgl.setProjectionMode(); - pgl.pushMatrix(); - pgl.loadIdentity(); - pgl.setOrthographicProjection(0, width, 0, height, -1, 1); - - pgl.setModelviewMode(); - pgl.pushMatrix(); - pgl.loadIdentity(); - - pgl.translate(x, y, 0); - pgl.scale(w, h, 1); - // Rendering the quad with the appropriate texture coordinates needed for the - // specified crop region - float s0 = (float)crop[0] / tw; - float s1 = (float)(crop[0] + crop[2]) / tw; - float t0 = (float)crop[1] / th; - float t1 = (float)(crop[1] + crop[3]) / th; - drawTexQuad(s0, t0, s1, t1); - - // Restoring matrices. - pgl.setProjectionMode(); - pgl.popMatrix(); - pgl.setModelviewMode(); - pgl.popMatrix(); - - if (hintEnabled(ENABLE_DEPTH_MASK)) { - pgl.enableDepthMask(); - } - - */ - } - - - protected void drawTexQuad() { - drawTexQuad(0, 0, 1, 1); - } - - - /** - * Pushes a normalized (1x1) textured quad to the GPU. - */ - protected void drawTexQuad(float u0, float v0, float u1, float v1) { - // TODO: need to fix null thing, test... - stroke = false; - beginShape(QUAD); - vertex(0, 0, u0, v0); - vertex(1, 0, u1, v0); - vertex(1, 1, u1, v1); - vertex(0, 1, u0, v1); - endShape(); - tessellate(OPEN); - renderTexFill(null); // we need the texture object here... - } - - - /** - * Utility function to copy buffer to texture. - */ - protected void copyToTexture(PTexture tex, IntBuffer buffer, int x, int y, int w, int h) { - buffer.rewind(); - pgl.enableTexturing(tex.glTarget); - pgl.glBindTexture(tex.glTarget, tex.glID); - pgl.glTexSubImage2D(tex.glTarget, 0, x, y, w, h, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, buffer); - pgl.glBindTexture(tex.glTarget, 0); - pgl.disableTexturing(tex.glTarget); - } - - ////////////////////////////////////////////////////////////// // INITIALIZATION ROUTINES @@ -5629,7 +5127,7 @@ public class PGraphicsOpenGL extends PGraphics { mipmapGeneration = -1 < OPENGL_EXTENSIONS.indexOf("generate_mipmap"); fboMultisampleSupported = -1 < OPENGL_EXTENSIONS.indexOf("framebuffer_multisample"); packedDepthStencilSupported = -1 < OPENGL_EXTENSIONS.indexOf("packed_depth_stencil"); - + try { pgl.glBlendEquation(PGL.GL_FUNC_ADD); blendEqSupported = true; @@ -5655,7 +5153,7 @@ public class PGraphicsOpenGL extends PGraphics { depthBits = temp[0]; pgl.glGetIntegerv(PGL.GL_STENCIL_BITS, temp, 0); - stencilBits = temp[0]; + stencilBits = temp[0]; glParamsRead = true; } @@ -6334,11 +5832,7 @@ public class PGraphicsOpenGL extends PGraphics { set4FloatUniform(viewportLoc, renderer.viewport[0], renderer.viewport[1], renderer.viewport[2], renderer.viewport[3]); } - if (hints[ENABLE_PERSPECTIVE_CORRECTED_LINES]) { - setIntUniform(perspectiveLoc, 1); - } else { - setIntUniform(perspectiveLoc, 0); - } + setIntUniform(perspectiveLoc, perspectiveCorrectedLines ? 1 : 0); } public void stop() { @@ -6785,7 +6279,7 @@ public class PGraphicsOpenGL extends PGraphics { } public int javaToNativeARGB(int color) { - if (BIG_ENDIAN) { + if (PGL.BIG_ENDIAN) { return ((color >> 24) & 0xff) | ((color << 8) & 0xffffff00); } else { return (color & 0xff000000) @@ -8050,7 +7544,7 @@ public class PGraphicsOpenGL extends PGraphics { fillNormals[index ] = nx * nm.m02 + ny * nm.m12 + nz * nm.m22; } } else { - if (nvert <= MIN_ARRAYCOPY_SIZE) { + if (nvert <= PGL.MIN_ARRAYCOPY_SIZE) { // Copying elements one by one instead of using arrayCopy is more efficient for // few vertices... for (int i = 0; i < nvert; i++) { @@ -8083,7 +7577,7 @@ public class PGraphicsOpenGL extends PGraphics { } } - if (nvert <= MIN_ARRAYCOPY_SIZE) { + if (nvert <= PGL.MIN_ARRAYCOPY_SIZE) { for (int i = 0; i < nvert; i++) { int inIdx = i0 + i; int tessIdx = firstFillVertex + i; diff --git a/android/core/src/processing/opengl/PShape3D.java b/android/core/src/processing/opengl/PShape3D.java index 21684dc19..694965e60 100644 --- a/android/core/src/processing/opengl/PShape3D.java +++ b/android/core/src/processing/opengl/PShape3D.java @@ -3942,7 +3942,7 @@ public class PShape3D extends PShape { expand(newSize); } - if (dataSize <= PGraphicsOpenGL.MIN_ARRAYCOPY_SIZE) { + if (dataSize <= PGL.MIN_ARRAYCOPY_SIZE) { // Copying elements one by one instead of using arrayCopy is more efficient for // few vertices... for (int i = 0; i < dataSize; i++) { @@ -3985,7 +3985,7 @@ public class PShape3D extends PShape { expand(newSize); } - if (dataSize <= PGraphicsOpenGL.MIN_ARRAYCOPY_SIZE) { + if (dataSize <= PGL.MIN_ARRAYCOPY_SIZE) { // Copying elements one by one instead of using arrayCopy is more efficient for // few vertices... for (int i = 0; i < dataSize; i++) { diff --git a/android/core/src/processing/opengl/PTexture.java b/android/core/src/processing/opengl/PTexture.java index d9db47a0c..cf41cd7af 100644 --- a/android/core/src/processing/opengl/PTexture.java +++ b/android/core/src/processing/opengl/PTexture.java @@ -43,7 +43,7 @@ public class PTexture implements PConstants { public int width, height; protected PApplet parent; // The Processing applet - protected PGraphicsOpenGL pg; // The main renderer + 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. @@ -479,7 +479,7 @@ public class PTexture implements PConstants { //////////////////////////////////////////////////////////// // Utilities - + /** * Flips intArray along the X axis. @@ -543,7 +543,7 @@ public class PTexture implements PConstants { * @param h int */ protected void convertToRGBA(int[] intArray, int[] tIntArray, int arrayFormat, int w, int h) { - if (PGraphicsOpenGL.BIG_ENDIAN) { + if (PGL.BIG_ENDIAN) { switch (arrayFormat) { case ALPHA: @@ -683,7 +683,7 @@ public class PTexture implements PConstants { protected void convertToARGB(int[] intArray, int[] tIntArray) { int t = 0; int p = 0; - if (PGraphicsOpenGL.BIG_ENDIAN) { + if (PGL.BIG_ENDIAN) { // RGBA to ARGB conversion: shifting RGB 8 bits to the right, // and placing A 24 bits to the left. @@ -820,12 +820,15 @@ public class PTexture implements PConstants { if (scale) { // Rendering tex into "this", and scaling the source rectangle // to cover the entire destination region. - pg.drawTexture(tex, x, y, w, h, 0, 0, width, height); + pgl.drawTexture(tex.glTarget, tex.glID, tex.glWidth, tex.glHeight, + x, y, w, h, 0, 0, width, height); + } else { // Rendering tex into "this" but without scaling so the contents // of the source texture fall in the corresponding texels of the // destination. - pg.drawTexture(tex, x, y, w, h, x, y, w, h); + pgl.drawTexture(tex.glTarget, tex.glID, tex.glWidth, tex.glHeight, + x, y, w, h, x, y, w, h); } pg.popFramebuffer(); } diff --git a/android/core/src/processing/opengl/PointShaderFrag.glsl b/android/core/src/processing/opengl/PointShaderFrag.glsl index e5dfc17df..8c22a6ac5 100644 --- a/android/core/src/processing/opengl/PointShaderFrag.glsl +++ b/android/core/src/processing/opengl/PointShaderFrag.glsl @@ -19,7 +19,10 @@ Boston, MA 02111-1307 USA */ +#ifdef GL_ES precision mediump float; +precision mediump int; +#endif varying vec4 vertColor;