diff --git a/android/core/src/processing/core/PConstants.java b/android/core/src/processing/core/PConstants.java index 50d23caf4..0927bca1d 100644 --- a/android/core/src/processing/core/PConstants.java +++ b/android/core/src/processing/core/PConstants.java @@ -35,24 +35,7 @@ import android.view.KeyEvent; * as possible. For instance, the constant is TIFF instead of * FILE_TYPE_TIFF. We'll do this as long as we can get away with it. */ -public interface PConstants { - // render & flush modes (in P3D) - - static public final int IMMEDIATE = 0; - static public final int RETAINED = 1; - - static public final int FLUSH_CONTINUOUSLY = 0; - static public final int FLUSH_WHEN_FULL = 1; - - // shaders - - static public final int FILL_SHADER_SIMPLE = 0; - static public final int FILL_SHADER_LIT = 1; - static public final int FILL_SHADER_TEX = 2; - static public final int FILL_SHADER_FULL = 3; - static public final int LINE_SHADER = 4; - static public final int POINT_SHADER = 5; - +public interface PConstants { // vertex fields static public final int X = 0; // model coords xyz (formerly MX/MY/MZ) @@ -398,7 +381,8 @@ public interface PConstants { // PTexture - /** 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; /** This constant identifies the nearest texture filter (point sampling) */ @@ -406,21 +390,14 @@ public interface PConstants { /** This constant identifies the linear texture filter, usually called bilinear sampling */ public static final int BILINEAR = 3; /** This constant identifies the linear/linear function to build mipmaps */ - public static final int TRILINEAR = 4; - - // Point sprites distance attenuation functions - public static final int LINEAR = 0; - public static final int QUADRATIC = 1; - + public static final int TRILINEAR = 4; /** 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; - - /** This constant identifies the modulate texture environment mode */ - public static final int MODULATE = 1; - // PShape3D + + // vbos /** Static usage mode for PShape3D (vertices won't be updated after creation). */ public static final int STATIC = 0; @@ -429,6 +406,17 @@ public interface PConstants { /** Dynamic usage mode for PShape3D (vertices will be updated at every frame). */ public static final int STREAM = 2; + + // shaders + + static public final int FILL_SHADER_SIMPLE = 0; + static public final int FILL_SHADER_LIT = 1; + static public final int FILL_SHADER_TEX = 2; + static public final int FILL_SHADER_FULL = 3; + static public final int LINE_SHADER = 4; + static public final int POINT_SHADER = 5; + + // stroke modes static final int SQUARE = 1 << 0; // called 'butt' in the svg spec diff --git a/android/core/src/processing/opengl/PGraphicsOpenGL.java b/android/core/src/processing/opengl/PGraphicsOpenGL.java index bdd3be716..1b55a37b4 100644 --- a/android/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/android/core/src/processing/opengl/PGraphicsOpenGL.java @@ -26,6 +26,7 @@ import java.nio.*; import java.util.*; import processing.core.*; +import processing.opengl.PGraphicsOpenGL.Tessellator.TessellatorCallback; // drawPixels is missing...calls to glDrawPixels are commented out @@ -35,24 +36,39 @@ import processing.core.*; * OpenGL renderer. * */ -public class PGraphicsOpenGL extends PGraphics { +public class PGraphicsOpenGL extends PGraphics { /** Interface between Processing and OpenGL */ public PGL pgl; - + /** The PApplet renderer. For the primary surface, pg == this. */ protected PGraphicsOpenGL pg; - // ........................................................ + // ........................................................ + + // Basic rendering parameters: + + /** Flush modes: continuously (geometry is flushed after each call to + * endShape) when-full (geometry is accumulated until a maximum size is + * reached. */ + static protected final int FLUSH_CONTINUOUSLY = 0; + static protected final int FLUSH_WHEN_FULL = 1; - // Basic rendering parameters: - - protected int flushMode = FLUSH_WHEN_FULL; - protected int vboMode = PGL.GL_STATIC_DRAW; - - // ........................................................ - - // VBOs for immediate rendering: + /** Type of geometry: immediate is that generated with beginShape/vertex/ + * endShape, retained is the result of creating a PShape3D object with + * createShape. */ + static protected final int IMMEDIATE = 0; + static protected final int RETAINED = 1; + + /** Current flush mode. */ + protected int flushMode = FLUSH_WHEN_FULL; + /** VBO storage mode. */ + protected int vboMode = PGL.GL_STATIC_DRAW; + + // ........................................................ + + // VBOs for immediate rendering: + public int glFillVertexBufferID; public int glFillColorBufferID; public int glFillNormalBufferID; @@ -60,83 +76,83 @@ public class PGraphicsOpenGL extends PGraphics { public int glFillAmbientBufferID; public int glFillSpecularBufferID; public int glFillEmissiveBufferID; - public int glFillShininessBufferID; - public int glFillIndexBufferID; + public int glFillShininessBufferID; + public int glFillIndexBufferID; protected boolean fillVBOsCreated = false; - + public int glLineVertexBufferID; public int glLineColorBufferID; public int glLineDirWidthBufferID; - public int glLineIndexBufferID; + public int glLineIndexBufferID; protected boolean lineVBOsCreated = false; - + public int glPointVertexBufferID; public int glPointColorBufferID; public int glPointSizeBufferID; - public int glPointIndexBufferID; + public int glPointIndexBufferID; protected boolean pointVBOsCreated = false; - - // ........................................................ - + + // ........................................................ + // GL parameters - + static protected boolean glParamsRead = false; - + /** Extensions used by Processing */ static public boolean npotTexSupported; static public boolean mipmapGeneration; static public boolean fboMultisampleSupported; static public boolean packedDepthStencilSupported; - static public boolean blendEqSupported; - - /** Some hardware limits */ + static public boolean blendEqSupported; + + /** Some hardware limits */ static public int maxTextureSize; static public int maxSamples; static public float maxPointSize; static public float maxLineWidth; static public int depthBits; static public int stencilBits; - + /** OpenGL information strings */ static public String OPENGL_VENDOR; static public String OPENGL_RENDERER; - static public String OPENGL_VERSION; + static public String OPENGL_VERSION; static public String OPENGL_EXTENSIONS; - - // ........................................................ - + + // ........................................................ + // GL objects: - + static protected HashMap glTextureObjects = new HashMap(); static protected HashMap glVertexBuffers = new HashMap(); static protected HashMap glFrameBuffers = new HashMap(); - static protected HashMap glRenderBuffers = new HashMap(); + static protected HashMap glRenderBuffers = new HashMap(); static protected HashMap glslPrograms = new HashMap(); static protected HashMap glslVertexShaders = new HashMap(); static protected HashMap glslFragmentShaders = new HashMap(); - + // ........................................................ - - // Shaders - + + // Shaders + static protected URL defFillShaderVertSimpleURL = PGraphicsOpenGL.class.getResource("FillShaderVertSimple.glsl"); static protected URL defFillShaderVertTexURL = PGraphicsOpenGL.class.getResource("FillShaderVertTex.glsl"); static protected URL defFillShaderVertLitURL = PGraphicsOpenGL.class.getResource("FillShaderVertLit.glsl"); - static protected URL defFillShaderVertFullURL = PGraphicsOpenGL.class.getResource("FillShaderVertFull.glsl"); + static protected URL defFillShaderVertFullURL = PGraphicsOpenGL.class.getResource("FillShaderVertFull.glsl"); static protected URL defFillShaderFragNoTexURL = PGraphicsOpenGL.class.getResource("FillShaderFragNoTex.glsl"); - static protected URL defFillShaderFragTexURL = PGraphicsOpenGL.class.getResource("FillShaderFragTex.glsl"); + static protected URL defFillShaderFragTexURL = PGraphicsOpenGL.class.getResource("FillShaderFragTex.glsl"); static protected URL defLineShaderVertURL = PGraphicsOpenGL.class.getResource("LineShaderVert.glsl"); static protected URL defLineShaderFragURL = PGraphicsOpenGL.class.getResource("LineShaderFrag.glsl"); static protected URL defPointShaderVertURL = PGraphicsOpenGL.class.getResource("PointShaderVert.glsl"); static protected URL defPointShaderFragURL = PGraphicsOpenGL.class.getResource("PointShaderFrag.glsl"); - + static protected FillShaderSimple defFillShaderSimple; static protected FillShaderTex defFillShaderTex; static protected FillShaderLit defFillShaderLit; static protected FillShaderFull defFillShaderFull; static protected LineShader defLineShader; static protected PointShader defPointShader; - + protected FillShaderSimple fillShaderSimple; protected FillShaderTex fillShaderTex; protected FillShaderLit fillShaderLit; @@ -145,19 +161,19 @@ public class PGraphicsOpenGL extends PGraphics { protected PointShader pointShader; // ........................................................ - - // Tessellator, geometry - + + // Tessellator, geometry + protected InGeometry inGeo; protected TessGeometry tessGeo; protected int firstTexIndex; protected TexCache texCache; - protected Tessellator tessellator; - - // ........................................................ + protected Tessellator tessellator; + + // ........................................................ // Camera: - + /** Camera field of view. */ public float cameraFOV; @@ -167,53 +183,53 @@ public class PGraphicsOpenGL extends PGraphics { public float cameraNear, cameraFar; /** Aspect ratio of camera's view. */ public float cameraAspect; - + /** Distance between the camera eye and aim point. */ - protected float cameraDepth; - + protected float cameraDepth; + /** Actual position of the camera. */ - protected float cameraEyeX, cameraEyeY, cameraEyeZ; - + protected float cameraEyeX, cameraEyeY, cameraEyeZ; + /** Flag to indicate that we are inside beginCamera/endCamera block. */ protected boolean manipulatingCamera; - + // ........................................................ // All the matrices required for camera and geometry transformations. - public PMatrix3D projection; + public PMatrix3D projection; public PMatrix3D camera; - public PMatrix3D cameraInv; + public PMatrix3D cameraInv; public PMatrix3D modelview; public PMatrix3D modelviewInv; - public PMatrix3D projmodelview; - + public PMatrix3D projmodelview; + // To pass to shaders protected float[] glProjection; protected float[] glModelview; protected float[] glProjmodelview; protected float[] glNormal; - + protected boolean matricesAllocated = false; - - /** - * Marks when changes to the size have occurred, so that the camera + + /** + * Marks when changes to the size have occurred, so that the camera * will be reset in beginDraw(). */ - protected boolean sizeChanged; - + protected boolean sizeChanged; + /** Modelview matrix stack **/ - protected Stack modelviewStack; + protected Stack modelviewStack; /** Inverse modelview matrix stack **/ - protected Stack modelviewInvStack; - + protected Stack modelviewInvStack; + /** Projection matrix stack **/ protected Stack projectionStack; // ........................................................ - // Lights: - + // Lights: + public boolean lights; public int lightCount = 0; @@ -229,23 +245,23 @@ public class PGraphicsOpenGL extends PGraphics { /** * Ambient colors for lights. */ - public float[] lightAmbient; - + public float[] lightAmbient; + /** * Diffuse colors for lights. */ - public float[] lightDiffuse; - + public float[] lightDiffuse; + /** * Specular colors for lights. Internally these are stored as numbers between * 0 and 1. */ public float[] lightSpecular; - + /** Light falloff */ public float[] lightFalloffCoefficients; - /** Light spot parameters: Cosine of light spot angle + /** Light spot parameters: Cosine of light spot angle * and concentration */ public float[] lightSpotParameters; @@ -257,75 +273,75 @@ public class PGraphicsOpenGL extends PGraphics { public float currentLightFalloffLinear; public float currentLightFalloffQuadratic; - protected boolean lightsAllocated = false; - + protected boolean lightsAllocated = false; + // ........................................................ - + // Blending: - - protected int blendMode; - + + protected int blendMode; + // ........................................................ - - // Clipping - - protected boolean clip = false; - + + // Clipping + + protected boolean clip = false; + // ........................................................ // Text: - + /** Font texture of currently selected font. */ PFontTexture textTex; - + // ....................................................... - + // Framebuffer stack: - + static protected Stack fbStack; static protected PFramebuffer screenFramebuffer; - static protected PFramebuffer currentFramebuffer; - + static protected PFramebuffer currentFramebuffer; + // ....................................................... - + // Offscreen rendering: - + protected PFramebuffer offscreenFramebuffer; protected PFramebuffer offscreenFramebufferMultisample; protected boolean offscreenMultisample; - - protected boolean offscreenNotCurrent; - + + protected boolean offscreenNotCurrent; + // ........................................................ - + // Screen surface: - /** A handy reference to the PTexture bound to the drawing surface + /** A handy reference to the PTexture bound to the drawing surface * (off or on-screen) */ protected PTexture texture; - + /** IntBuffer wrapping the pixels array. */ protected IntBuffer pixelBuffer; - + /** Array to store pixels in OpenGL format. */ protected int[] rgbaPixels; - - /** Flag to indicate if the user is manipulating the + + /** Flag to indicate if the user is manipulating the * pixels array through the set()/get() methods */ protected boolean setgetPixels; - + // ........................................................ - - // Bezier and Catmull-Rom curves + + // Bezier and Catmull-Rom curves protected boolean bezierInited = false; public int bezierDetail = 20; - protected PMatrix3D bezierDrawMatrix; + protected PMatrix3D bezierDrawMatrix; protected boolean curveInited = false; protected int curveDetail = 20; public float curveTightness = 0; - + // catmull-rom basis matrix, perhaps with optional s parameter protected PMatrix3D curveBasisMatrix; protected PMatrix3D curveDrawMatrix; @@ -334,7 +350,7 @@ public class PGraphicsOpenGL extends PGraphics { protected PMatrix3D curveToBezierMatrix; protected float curveVertices[][]; - protected int curveVertexCount; + protected int curveVertexCount; // used by both curve and bezier, so just init here protected PMatrix3D bezierBasisMatrix = @@ -342,52 +358,52 @@ public class PGraphicsOpenGL extends PGraphics { 3, -6, 3, 0, -3, 3, 0, 0, 1, 0, 0, 0); - - // ........................................................ - + + // ........................................................ + // Utility variables: - + /** True if we are inside a beginDraw()/endDraw() block. */ - protected boolean drawing = false; - + 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 clearColorBuffer; + protected boolean clearColorBuffer0; + protected boolean openContour = false; protected boolean breakShape = false; protected boolean defaultEdges = false; - protected PImage textureImage0; - - protected boolean perspectiveCorrectedLines = false; - - ////////////////////////////////////////////////////////////// - + protected PImage textureImage0; + + protected boolean perspectiveCorrectedLines = false; + + ////////////////////////////////////////////////////////////// + // INIT/ALLOCATE/FINISH - - + + public PGraphicsOpenGL() { pgl = new PGL(this); pg = null; - + tessellator = new Tessellator(); - + inGeo = newInGeometry(IMMEDIATE); tessGeo = newTessGeometry(IMMEDIATE); texCache = newTexCache(); - + glFillVertexBufferID = 0; glFillColorBufferID = 0; glFillNormalBufferID = 0; @@ -395,52 +411,52 @@ public class PGraphicsOpenGL extends PGraphics { glFillAmbientBufferID = 0; glFillSpecularBufferID = 0; glFillEmissiveBufferID = 0; - glFillShininessBufferID = 0; + glFillShininessBufferID = 0; glFillIndexBufferID = 0; - + glLineVertexBufferID = 0; glLineColorBufferID = 0; glLineDirWidthBufferID = 0; glLineIndexBufferID = 0; - + glPointVertexBufferID = 0; glPointColorBufferID = 0; glPointSizeBufferID = 0; glPointIndexBufferID = 0; - } + } + - //public void setParent(PApplet parent) // PGraphics public void setPrimary(boolean primary) { super.setPrimary(primary); - format = ARGB; - } + format = ARGB; + } //public void setPath(String path) // PGraphics - - + + //public void setAntiAlias(int samples) // PGraphics - - - public void setFrameRate(float framerate) { - pgl.setFramerate(framerate); + + + public void setFrameRate(float framerate) { + pgl.setFramerate(framerate); } - - + + public void setSize(int iwidth, int iheight) { resized = (0 < width && width != iwidth) || (0 < height && height != iwidth); - + width = iwidth; height = iheight; - width1 = width - 1; - height1 = height - 1; - +// width1 = width - 1; +// height1 = height - 1; + allocate(); reapplySettings(); - + // init perspective projection based on new dimensions cameraFOV = 60 * DEG_TO_RAD; // at least for now cameraX = width / 2.0f; @@ -450,10 +466,10 @@ public class PGraphicsOpenGL extends PGraphics { cameraFar = cameraZ * 10.0f; cameraAspect = (float) width / (float) height; cameraDepth = cameraZ; // eye is at (cameraX, cameraY, cameraZ), aiming at (cameraX, cameraY, 0) - + // set this flag so that beginDraw() will do an update to the camera. - sizeChanged = true; - + sizeChanged = true; + // Forces a restart of OpenGL so the canvas has the right size. pgl.initialized = false; } @@ -467,7 +483,7 @@ public class PGraphicsOpenGL extends PGraphics { */ protected void allocate() { super.allocate(); - + if (!matricesAllocated) { projection = new PMatrix3D(); camera = new PMatrix3D(); @@ -492,50 +508,49 @@ public class PGraphicsOpenGL extends PGraphics { } } - - public void dispose() { // PGraphics - super.dispose(); - deleteFinalizedGLResources(); - } - - // Only for debugging purposes. - public void setFlushMode(int mode) { + public void dispose() { // PGraphics + super.dispose(); + deleteFinalizedGLResources(); + } + + + protected void setFlushMode(int mode) { flushMode = mode; } - + ////////////////////////////////////////////////////////////// // RESOURCE HANDLING - - + + // Texture Objects ------------------------------------------- - + protected int createTextureObject() { deleteFinalizedTextureObjects(); - + int[] temp = new int[1]; pgl.glGenTextures(1, temp, 0); int id = temp[0]; - + if (glTextureObjects.containsKey(id)) { showWarning("Adding same texture twice"); - } else { + } else { glTextureObjects.put(id, false); } - + return id; } - + protected void deleteTextureObject(int id) { if (glTextureObjects.containsKey(id)) { int[] temp = { id }; pgl.glDeleteTextures(1, temp, 0); - glTextureObjects.remove(id); + glTextureObjects.remove(id); } - } - + } + protected void deleteAllTextureObjects() { for (Integer id : glTextureObjects.keySet()) { int[] temp = { id.intValue() }; @@ -543,7 +558,7 @@ public class PGraphicsOpenGL extends PGraphics { } glTextureObjects.clear(); } - + // This is synchronized because it is called from the GC thread. synchronized protected void finalizeTextureObject(int id) { if (glTextureObjects.containsKey(id)) { @@ -552,10 +567,10 @@ public class PGraphicsOpenGL extends PGraphics { showWarning("Trying to finalize non-existing texture"); } } - + protected void deleteFinalizedTextureObjects() { Set finalized = new HashSet(); - + for (Integer id : glTextureObjects.keySet()) { if (glTextureObjects.get(id)) { finalized.add(id); @@ -563,47 +578,47 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glDeleteTextures(1, temp, 0); } } - + for (Integer id : finalized) { - glTextureObjects.remove(id); + glTextureObjects.remove(id); } } - - + + // Vertex Buffer Objects ---------------------------------------------- - + protected int createVertexBufferObject() { deleteFinalizedVertexBufferObjects(); - + int[] temp = new int[1]; pgl.glGenBuffers(1, temp, 0); int id = temp[0]; - + if (glVertexBuffers.containsKey(id)) { showWarning("Adding same VBO twice"); - } else { + } else { glVertexBuffers.put(id, false); } - + return id; } - + protected void deleteVertexBufferObject(int id) { if (glVertexBuffers.containsKey(id)) { int[] temp = { id }; pgl.glDeleteBuffers(1, temp, 0); - glVertexBuffers.remove(id); + glVertexBuffers.remove(id); } } - + protected void deleteAllVertexBufferObjects() { for (Integer id : glVertexBuffers.keySet()) { int[] temp = { id.intValue() }; pgl.glDeleteBuffers(1, temp, 0); } glVertexBuffers.clear(); - } - + } + // This is synchronized because it is called from the GC thread. synchronized protected void finalizeVertexBufferObject(int id) { if (glVertexBuffers.containsKey(id)) { @@ -612,10 +627,10 @@ public class PGraphicsOpenGL extends PGraphics { showWarning("Trying to finalize non-existing VBO"); } } - + protected void deleteFinalizedVertexBufferObjects() { Set finalized = new HashSet(); - + for (Integer id : glVertexBuffers.keySet()) { if (glVertexBuffers.get(id)) { finalized.add(id); @@ -623,47 +638,47 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glDeleteBuffers(1, temp, 0); } } - + for (Integer id : finalized) { - glVertexBuffers.remove(id); + glVertexBuffers.remove(id); } } - - + + // FrameBuffer Objects ----------------------------------------- protected int createFrameBufferObject() { deleteFinalizedFrameBufferObjects(); - + int[] temp = new int[1]; pgl.glGenFramebuffers(1, temp, 0); int id = temp[0]; - + if (glFrameBuffers.containsKey(id)) { showWarning("Adding same FBO twice"); - } else { + } else { glFrameBuffers.put(id, false); } - + return id; } - + protected void deleteFrameBufferObject(int id) { if (glFrameBuffers.containsKey(id)) { int[] temp = { id }; pgl.glDeleteFramebuffers(1, temp, 0); - glFrameBuffers.remove(id); + glFrameBuffers.remove(id); } - } - + } + protected void deleteAllFrameBufferObjects() { for (Integer id : glFrameBuffers.keySet()) { int[] temp = { id.intValue() }; pgl.glDeleteFramebuffers(1, temp, 0); } glFrameBuffers.clear(); - } - + } + // This is synchronized because it is called from the GC thread. synchronized protected void finalizeFrameBufferObject(int id) { if (glFrameBuffers.containsKey(id)) { @@ -672,10 +687,10 @@ public class PGraphicsOpenGL extends PGraphics { showWarning("Trying to finalize non-existing FBO"); } } - + protected void deleteFinalizedFrameBufferObjects() { Set finalized = new HashSet(); - + for (Integer id : glFrameBuffers.keySet()) { if (glFrameBuffers.get(id)) { finalized.add(id); @@ -683,47 +698,47 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glDeleteFramebuffers(1, temp, 0); } } - + for (Integer id : finalized) { - glFrameBuffers.remove(id); + glFrameBuffers.remove(id); } } - + // RenderBuffer Objects ----------------------------------------------- - + protected int createRenderBufferObject() { deleteFinalizedRenderBufferObjects(); - + int[] temp = new int[1]; pgl.glGenRenderbuffers(1, temp, 0); int id = temp[0]; - + if (glRenderBuffers.containsKey(id)) { showWarning("Adding same renderbuffer twice"); - } else { + } else { glRenderBuffers.put(id, false); } - + return id; } - + protected void deleteRenderBufferObject(int id) { if (glRenderBuffers.containsKey(id)) { - int[] temp = { id }; + int[] temp = { id }; pgl.glDeleteRenderbuffers(1, temp, 0); - glRenderBuffers.remove(id); + glRenderBuffers.remove(id); } - } - + } + protected void deleteAllRenderBufferObjects() { for (Integer id : glRenderBuffers.keySet()) { int[] temp = { id.intValue() }; pgl.glDeleteRenderbuffers(1, temp, 0); } glRenderBuffers.clear(); - } - + } + // This is synchronized because it is called from the GC thread. synchronized protected void finalizeRenderBufferObject(int id) { if (glRenderBuffers.containsKey(id)) { @@ -732,10 +747,10 @@ public class PGraphicsOpenGL extends PGraphics { showWarning("Trying to finalize non-existing renderbuffer"); } } - + protected void deleteFinalizedRenderBufferObjects() { Set finalized = new HashSet(); - + for (Integer id : glRenderBuffers.keySet()) { if (glRenderBuffers.get(id)) { finalized.add(id); @@ -743,43 +758,43 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glDeleteRenderbuffers(1, temp, 0); } } - + for (Integer id : finalized) { - glRenderBuffers.remove(id); + glRenderBuffers.remove(id); } } - - + + // GLSL Program Objects ----------------------------------------------- - + protected int createGLSLProgramObject() { deleteFinalizedGLSLProgramObjects(); - + int id = pgl.glCreateProgram(); - + if (glslPrograms.containsKey(id)) { showWarning("Adding same glsl program twice"); - } else { + } else { glslPrograms.put(id, false); } - + return id; } - + protected void deleteGLSLProgramObject(int id) { if (glslPrograms.containsKey(id)) { pgl.glDeleteProgram(id); - glslPrograms.remove(id); + glslPrograms.remove(id); } - } - + } + protected void deleteAllGLSLProgramObjects() { for (Integer id : glslPrograms.keySet()) { pgl.glDeleteProgram(id); } glslPrograms.clear(); - } - + } + // This is synchronized because it is called from the GC thread. synchronized protected void finalizeGLSLProgramObject(int id) { if (glslPrograms.containsKey(id)) { @@ -788,53 +803,53 @@ public class PGraphicsOpenGL extends PGraphics { showWarning("Trying to finalize non-existing glsl program"); } } - + protected void deleteFinalizedGLSLProgramObjects() { Set finalized = new HashSet(); - + for (Integer id : glslPrograms.keySet()) { if (glslPrograms.get(id)) { finalized.add(id); pgl.glDeleteProgram(id); } } - + for (Integer id : finalized) { - glslPrograms.remove(id); + glslPrograms.remove(id); } } - + // GLSL Vertex Shader Objects ----------------------------------------------- - + protected int createGLSLVertShaderObject() { deleteFinalizedGLSLVertShaderObjects(); - + int id = pgl.glCreateShader(PGL.GL_VERTEX_SHADER); - + if (glslVertexShaders.containsKey(id)) { showWarning("Adding same glsl vertex shader twice"); - } else { + } else { glslVertexShaders.put(id, false); } - + return id; } - + protected void deleteGLSLVertShaderObject(int id) { if (glslVertexShaders.containsKey(id)) { pgl.glDeleteShader(id); - glslVertexShaders.remove(id); + glslVertexShaders.remove(id); } - } - + } + protected void deleteAllGLSLVertShaderObjects() { for (Integer id : glslVertexShaders.keySet()) { pgl.glDeleteShader(id); } glslVertexShaders.clear(); - } - + } + // This is synchronized because it is called from the GC thread. synchronized protected void finalizeGLSLVertShaderObject(int id) { if (glslVertexShaders.containsKey(id)) { @@ -843,53 +858,53 @@ public class PGraphicsOpenGL extends PGraphics { showWarning("Trying to finalize non-existing glsl vertex shader"); } } - + protected void deleteFinalizedGLSLVertShaderObjects() { Set finalized = new HashSet(); - + for (Integer id : glslVertexShaders.keySet()) { if (glslVertexShaders.get(id)) { finalized.add(id); pgl.glDeleteShader(id); } } - + for (Integer id : finalized) { - glslVertexShaders.remove(id); + glslVertexShaders.remove(id); } } - - - // GLSL Fragment Shader Objects ----------------------------------------------- - + + + // GLSL Fragment Shader Objects ----------------------------------------------- + protected int createGLSLFragShaderObject() { deleteFinalizedGLSLFragShaderObjects(); - - int id = pgl.glCreateShader(PGL.GL_FRAGMENT_SHADER); - + + int id = pgl.glCreateShader(PGL.GL_FRAGMENT_SHADER); + if (glslFragmentShaders.containsKey(id)) { showWarning("Adding same glsl fragment shader twice"); - } else { + } else { glslFragmentShaders.put(id, false); } - + return id; } - + protected void deleteGLSLFragShaderObject(int id) { if (glslFragmentShaders.containsKey(id)) { pgl.glDeleteShader(id); - glslFragmentShaders.remove(id); + glslFragmentShaders.remove(id); } - } - + } + protected void deleteAllGLSLFragShaderObjects() { for (Integer id : glslFragmentShaders.keySet()) { pgl.glDeleteShader(id); } glslFragmentShaders.clear(); - } - + } + // This is synchronized because it is called from the GC thread. synchronized protected void finalizeGLSLFragShaderObject(int id) { if (glslFragmentShaders.containsKey(id)) { @@ -898,23 +913,23 @@ public class PGraphicsOpenGL extends PGraphics { showWarning("Trying to finalize non-existing glsl fragment shader"); } } - + protected void deleteFinalizedGLSLFragShaderObjects() { Set finalized = new HashSet(); - + for (Integer id : glslFragmentShaders.keySet()) { if (glslFragmentShaders.get(id)) { finalized.add(id); pgl.glDeleteShader(id); } } - + for (Integer id : finalized) { - glslFragmentShaders.remove(id); + glslFragmentShaders.remove(id); } - } - - + } + + protected void deleteFinalizedGLResources() { deleteFinalizedTextureObjects(); deleteFinalizedVertexBufferObjects(); @@ -924,8 +939,8 @@ public class PGraphicsOpenGL extends PGraphics { deleteFinalizedGLSLVertShaderObjects(); deleteFinalizedGLSLFragShaderObjects(); } - - + + protected void deleteAllGLResources() { deleteAllTextureObjects(); deleteAllVertexBufferObjects(); @@ -933,26 +948,26 @@ public class PGraphicsOpenGL extends PGraphics { deleteAllRenderBufferObjects(); deleteAllGLSLProgramObjects(); deleteAllGLSLVertShaderObjects(); - deleteAllGLSLFragShaderObjects(); + deleteAllGLSLFragShaderObjects(); } - - + + ////////////////////////////////////////////////////////////// // FRAMEBUFFERS - - + + public void pushFramebuffer() { fbStack.push(currentFramebuffer); } - + public void setFramebuffer(PFramebuffer fbo) { currentFramebuffer = fbo; currentFramebuffer.bind(); } - + public void popFramebuffer() { try { currentFramebuffer.finish(); @@ -962,13 +977,13 @@ public class PGraphicsOpenGL extends PGraphics { PGraphics.showWarning("P3D: Empty framebuffer stack"); } } - - + + ////////////////////////////////////////////////////////////// // FRAME RENDERING - - + + protected void releaseResources() { // First, releasing the resources used by // the renderer itself. @@ -976,7 +991,7 @@ public class PGraphicsOpenGL extends PGraphics { texture.release(); texture = null; } - + if (defFillShaderSimple != null) { defFillShaderSimple.release(); defFillShaderSimple = null; @@ -985,141 +1000,141 @@ public class PGraphicsOpenGL extends PGraphics { if (defFillShaderLit != null) { defFillShaderLit.release(); defFillShaderLit = null; - } + } if (defFillShaderTex != null) { defFillShaderTex.release(); defFillShaderTex = null; - } + } if (defFillShaderFull != null) { defFillShaderFull.release(); defFillShaderFull = null; - } - + } + if (defLineShader != null) { defLineShader.release(); defLineShader = null; } - + if (defPointShader != null) { defPointShader.release(); defPointShader = null; - } - + } + if (fillShaderSimple != null) { fillShaderSimple.release(); fillShaderSimple = null; } - + if (fillShaderTex != null) { fillShaderTex.release(); fillShaderTex = null; } - + if (fillShaderLit != null) { fillShaderLit.release(); fillShaderLit = null; } - + if (fillShaderFull != null) { fillShaderFull.release(); fillShaderFull = null; } - + if (lineShader != null) { lineShader.release(); lineShader = null; } - + if (pointShader != null) { pointShader.release(); pointShader = null; } - + if (fillVBOsCreated) { releaseFillBuffers(); fillVBOsCreated = false; } - + if (lineVBOsCreated) { releaseLineBuffers(); lineVBOsCreated = false; } - + if (pointVBOsCreated) { releasePointBuffers(); pointVBOsCreated = false; } - - // Now, releasing the remaining resources + + // Now, releasing the remaining resources // (from user's objects). - deleteAllGLResources(); + deleteAllGLResources(); } - + protected void createFillBuffers() { int sizef = PGL.MAX_TESS_VERTICES * PGL.SIZEOF_FLOAT; int sizei = PGL.MAX_TESS_VERTICES * PGL.SIZEOF_INT; int sizex = PGL.MAX_TESS_INDICES * PGL.SIZEOF_INDEX; - - glFillVertexBufferID = createVertexBufferObject(); + + glFillVertexBufferID = createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillVertexBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 3 * sizef, null, vboMode); - + glFillColorBufferID = createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillColorBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, null, vboMode); - + glFillNormalBufferID = createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillNormalBufferID); - pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 3 * sizef, null, vboMode); - + pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 3 * sizef, null, vboMode); + glFillTexCoordBufferID = createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillTexCoordBufferID); - pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 2 * sizef, null, vboMode); - - glFillAmbientBufferID = pg.createVertexBufferObject(); + pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 2 * sizef, null, vboMode); + + glFillAmbientBufferID = pg.createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillAmbientBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, null, vboMode); - + glFillSpecularBufferID = pg.createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillSpecularBufferID); - pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, null, vboMode); - + pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, null, vboMode); + glFillEmissiveBufferID = pg.createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillEmissiveBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, null, vboMode); - + glFillShininessBufferID = pg.createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillShininessBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizef, null, vboMode); - + pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, 0); - - glFillIndexBufferID = createVertexBufferObject(); + + glFillIndexBufferID = createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, glFillIndexBufferID); pgl.glBufferData(PGL.GL_ELEMENT_ARRAY_BUFFER, sizex, null, vboMode); pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, 0); } - - + + protected void updateFillBuffers(boolean lit, boolean tex) { int size = tessGeo.fillVertexCount; int sizef = size * PGL.SIZEOF_FLOAT; int sizei = size * PGL.SIZEOF_INT; - + pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillVertexBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 3 * sizef, FloatBuffer.wrap(tessGeo.fillVertices, 0, 3 * size), vboMode); - + pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillColorBufferID); - pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, IntBuffer.wrap(tessGeo.fillColors, 0, size), vboMode); - + pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, IntBuffer.wrap(tessGeo.fillColors, 0, size), vboMode); + if (lit) { pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillNormalBufferID); - pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 3 * sizef, FloatBuffer.wrap(tessGeo.fillNormals, 0, 3 * size), vboMode); - + pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 3 * sizef, FloatBuffer.wrap(tessGeo.fillNormals, 0, 3 * size), vboMode); + pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillAmbientBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, IntBuffer.wrap(tessGeo.fillAmbient, 0, size), vboMode); @@ -1128,87 +1143,87 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillEmissiveBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, IntBuffer.wrap(tessGeo.fillEmissive, 0, size), vboMode); - - + + pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillShininessBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizef, FloatBuffer.wrap(tessGeo.fillShininess, 0, size), vboMode); } - + if (tex) { pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glFillTexCoordBufferID); - pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 2 * sizef, FloatBuffer.wrap(tessGeo.fillTexcoords, 0, 2 * size), vboMode); + pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 2 * sizef, FloatBuffer.wrap(tessGeo.fillTexcoords, 0, 2 * size), vboMode); } - + pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, glFillIndexBufferID); - pgl.glBufferData(PGL.GL_ELEMENT_ARRAY_BUFFER, tessGeo.fillIndexCount * PGL.SIZEOF_INDEX, - ShortBuffer.wrap(tessGeo.fillIndices, 0, tessGeo.fillIndexCount), vboMode); - } - - + pgl.glBufferData(PGL.GL_ELEMENT_ARRAY_BUFFER, tessGeo.fillIndexCount * PGL.SIZEOF_INDEX, + ShortBuffer.wrap(tessGeo.fillIndices, 0, tessGeo.fillIndexCount), vboMode); + } + + protected void unbindFillBuffers() { pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, 0); pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, 0); - } - - + } + + protected void releaseFillBuffers() { deleteVertexBufferObject(glFillVertexBufferID); glFillVertexBufferID = 0; - + deleteVertexBufferObject(glFillColorBufferID); glFillColorBufferID = 0; deleteVertexBufferObject(glFillNormalBufferID); - glFillNormalBufferID = 0; - + glFillNormalBufferID = 0; + deleteVertexBufferObject(glFillTexCoordBufferID); glFillTexCoordBufferID = 0; - + deleteVertexBufferObject(glFillAmbientBufferID); glFillAmbientBufferID = 0; - + deleteVertexBufferObject(glFillSpecularBufferID); glFillSpecularBufferID = 0; deleteVertexBufferObject(glFillEmissiveBufferID); - glFillEmissiveBufferID = 0; - + glFillEmissiveBufferID = 0; + deleteVertexBufferObject(glFillShininessBufferID); - glFillShininessBufferID = 0; - + glFillShininessBufferID = 0; + deleteVertexBufferObject(glFillIndexBufferID); - glFillIndexBufferID = 0; + glFillIndexBufferID = 0; } - + protected void createLineBuffers() { int sizef = PGL.MAX_TESS_VERTICES * PGL.SIZEOF_FLOAT; int sizex = PGL.MAX_TESS_INDICES * PGL.SIZEOF_INDEX; - int sizei = PGL.MAX_TESS_INDICES * PGL.SIZEOF_INT; - + int sizei = PGL.MAX_TESS_INDICES * PGL.SIZEOF_INT; + glLineVertexBufferID = createVertexBufferObject(); - + pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glLineVertexBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 3 * sizef, null, vboMode); - + glLineColorBufferID = createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glLineColorBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, null, vboMode); - + glLineDirWidthBufferID = createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glLineDirWidthBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 4 * sizef, null, vboMode); - + pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, 0); - - glLineIndexBufferID = createVertexBufferObject(); + + glLineIndexBufferID = createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, glLineIndexBufferID); pgl.glBufferData(PGL.GL_ELEMENT_ARRAY_BUFFER, sizex, null, vboMode); - + pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, 0); - } - - + } + + protected void updateLineBuffers() { int size = tessGeo.lineVertexCount; int sizef = size * PGL.SIZEOF_FLOAT; @@ -1219,64 +1234,64 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glLineColorBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, IntBuffer.wrap(tessGeo.lineColors, 0, size), vboMode); - + pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glLineDirWidthBufferID); - pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 4 * sizef, FloatBuffer.wrap(tessGeo.lineDirWidths, 0, 4 * size), vboMode); - + pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 4 * sizef, FloatBuffer.wrap(tessGeo.lineDirWidths, 0, 4 * size), vboMode); + pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, glLineIndexBufferID); - pgl.glBufferData(PGL.GL_ELEMENT_ARRAY_BUFFER, tessGeo.lineIndexCount * PGL.SIZEOF_INDEX, + pgl.glBufferData(PGL.GL_ELEMENT_ARRAY_BUFFER, tessGeo.lineIndexCount * PGL.SIZEOF_INDEX, ShortBuffer.wrap(tessGeo.lineIndices, 0, tessGeo.lineIndexCount), vboMode); } - - + + protected void unbindLineBuffers() { pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, 0); - pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, 0); - } - - + pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, 0); + } + + protected void releaseLineBuffers() { deleteVertexBufferObject(glLineVertexBufferID); glLineVertexBufferID = 0; - + deleteVertexBufferObject(glLineColorBufferID); glLineColorBufferID = 0; deleteVertexBufferObject(glLineDirWidthBufferID); glLineDirWidthBufferID = 0; - + deleteVertexBufferObject(glLineIndexBufferID); - glLineIndexBufferID = 0; + glLineIndexBufferID = 0; } - + protected void createPointBuffers() { int sizef = PGL.MAX_TESS_VERTICES * PGL.SIZEOF_FLOAT; int sizex = PGL.MAX_TESS_INDICES * PGL.SIZEOF_INDEX; int sizei = PGL.MAX_TESS_INDICES * PGL.SIZEOF_INT; - - glPointVertexBufferID = createVertexBufferObject(); + + glPointVertexBufferID = createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glPointVertexBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 3 * sizef, null, vboMode); - + glPointColorBufferID = createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glPointColorBufferID); - pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, null, vboMode); - + pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, null, vboMode); + glPointSizeBufferID = createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glPointSizeBufferID); - pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 2 * sizef, null, vboMode); - + pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 2 * sizef, null, vboMode); + pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, 0); - - glPointIndexBufferID = createVertexBufferObject(); + + glPointIndexBufferID = createVertexBufferObject(); pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, glPointIndexBufferID); pgl.glBufferData(PGL.GL_ELEMENT_ARRAY_BUFFER, sizex, null, vboMode); - + pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, 0); - } - - + } + + protected void updatePointBuffers() { int size = tessGeo.pointVertexCount; int sizef = size * PGL.SIZEOF_FLOAT; @@ -1284,40 +1299,40 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glPointVertexBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 3 * sizef, FloatBuffer.wrap(tessGeo.pointVertices, 0, 3 * size), vboMode); - + pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glPointColorBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, sizei, IntBuffer.wrap(tessGeo.pointColors, 0, size), vboMode); - pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glPointSizeBufferID); + pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, glPointSizeBufferID); pgl.glBufferData(PGL.GL_ARRAY_BUFFER, 2 * sizef, FloatBuffer.wrap(tessGeo.pointSizes, 0, 2 * size), vboMode); - + pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, glPointIndexBufferID); - pgl.glBufferData(PGL.GL_ELEMENT_ARRAY_BUFFER, tessGeo.pointIndexCount * PGL.SIZEOF_INDEX, - ShortBuffer.wrap(tessGeo.pointIndices, 0, tessGeo.pointIndexCount), vboMode); + pgl.glBufferData(PGL.GL_ELEMENT_ARRAY_BUFFER, tessGeo.pointIndexCount * PGL.SIZEOF_INDEX, + ShortBuffer.wrap(tessGeo.pointIndices, 0, tessGeo.pointIndexCount), vboMode); } - - + + protected void unbindPointBuffers() { pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, 0); - pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, 0); + pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, 0); } - - + + protected void releasePointBuffers() { deleteVertexBufferObject(glPointVertexBufferID); glPointVertexBufferID = 0; - + deleteVertexBufferObject(glPointColorBufferID); - glPointColorBufferID = 0; - + glPointColorBufferID = 0; + deleteVertexBufferObject(glPointSizeBufferID); - glPointSizeBufferID = 0; - - deleteVertexBufferObject(glPointIndexBufferID); + glPointSizeBufferID = 0; + + deleteVertexBufferObject(glPointIndexBufferID); glPointIndexBufferID = 0; } - - + + /** * OpenGL cannot draw until a proper native peer is available, so this * returns the value of PApplet.isDisplayable() (inherited from Component). @@ -1326,37 +1341,37 @@ public class PGraphicsOpenGL extends PGraphics { return pgl.canDraw(); } - - public void requestDraw() { + + public void requestDraw() { if (primarySurface) { if (pgl.initialized) { - pgl.requestDraw(); + pgl.requestDraw(); } else { - initPrimary(); + initPrimary(); } } } - - + + public void beginDraw() { if (drawing) { showWarning("P3D: Already called beginDraw()."); return; - } - - if (!glParamsRead) { - getGLParameters(); } - + + if (!glParamsRead) { + getGLParameters(); + } + if (!settingsInited) { defaultSettings(); - } - + } + if (primarySurface) { pgl.updatePrimary(); } else { if (!pgl.initialized) { - initOffscreen(); + initOffscreen(); } else { boolean outdated = offscreenFramebuffer != null && offscreenFramebuffer.contextIsOutdated(); boolean outdatedMulti = offscreenFramebufferMultisample != null && offscreenFramebufferMultisample.contextIsOutdated(); @@ -1365,34 +1380,34 @@ public class PGraphicsOpenGL extends PGraphics { initOffscreen(); } } - + pushFramebuffer(); if (offscreenMultisample) { - setFramebuffer(offscreenFramebufferMultisample); + setFramebuffer(offscreenFramebufferMultisample); } else { setFramebuffer(offscreenFramebuffer); - } + } pgl.glDrawBuffer(PGL.GL_COLOR_ATTACHMENT0); pgl.updateOffscreen(pg.pgl); } - + // We are ready to go! - - report("top beginDraw()"); - + + report("top beginDraw()"); + inGeo.clear(); tessGeo.clear(); texCache.clear(); - - // Each frame starts with textures disabled. + + // Each frame starts with textures disabled. super.noTexture(); - + // Screen blend is needed for alpha (i.e. fonts) to work. // Using setDefaultBlend() instead of blendMode() because // the latter will set the blend mode only if it is different // from current. setDefaultBlend(); - + // this is necessary for 3D drawing if (hints[DISABLE_DEPTH_TEST]) { pgl.glDisable(PGL.GL_DEPTH_TEST); @@ -1403,17 +1418,17 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glDepthFunc(PGL.GL_LEQUAL); if (hints[ENABLE_ACCURATE_2D]) { - flushMode = FLUSH_CONTINUOUSLY; + flushMode = FLUSH_CONTINUOUSLY; } else { flushMode = FLUSH_WHEN_FULL; } - + if (primarySurface) { int[] temp = { 0 }; pgl.glGetIntegerv(PGL.GL_SAMPLES, temp, 0); if (antialias != temp[0] && 1 < temp[0] && 1 < antialias) { antialias = temp[0]; - } + } } if (antialias < 2) { pgl.glDisable(PGL.GL_MULTISAMPLE); @@ -1421,13 +1436,13 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glEnable(PGL.GL_LINE_SMOOTH); pgl.glEnable(PGL.GL_POLYGON_SMOOTH); } else { - pgl.glEnable(PGL.GL_MULTISAMPLE); + pgl.glEnable(PGL.GL_MULTISAMPLE); pgl.glDisable(PGL.GL_POINT_SMOOTH); pgl.glDisable(PGL.GL_LINE_SMOOTH); - pgl.glDisable(PGL.GL_POLYGON_SMOOTH); - } - - // setup opengl viewport. + pgl.glDisable(PGL.GL_POLYGON_SMOOTH); + } + + // setup opengl viewport. viewport[0] = 0; viewport[1] = 0; viewport[2] = width; viewport[3] = height; pgl.glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); if (resized) { @@ -1435,198 +1450,198 @@ public class PGraphicsOpenGL extends PGraphics { // in the case background is not called in draw(). background(0); if (texture != null) { - // The screen texture should be deleted because it + // The screen texture should be deleted because it // corresponds to the old window size. this.removeCache(pg); this.removeParams(pg); texture = null; loadTexture(); - } - resized = false; + } + resized = false; } - + if (sizeChanged) { // defaults to perspective, if the user has setup up their // own projection, they'll need to fix it after resize anyway. // this helps the people who haven't set up their own projection. perspective(); - + // set up the default camera and initializes modelview matrix. camera(); - + // clear the flag sizeChanged = false; } else { // The camera and projection matrices, saved when calling camera() and frustrum() // are set as the current modelview and projection matrices. This is done to // remove any additional modelview transformation (and less likely, projection - // transformations) applied by the user after setting the camera and/or projection + // transformations) applied by the user after setting the camera and/or projection modelview.set(camera); modelviewInv.set(cameraInv); calcProjmodelview(); } - + noLights(); lightFalloff(1, 0, 0); lightSpecular(0, 0, 0); - + // because y is flipped pgl.glFrontFace(PGL.GL_CW); - + // Processing uses only one texture unit. pgl.glActiveTexture(PGL.GL_TEXTURE0); - + // 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); pgl.glClear(PGL.GL_DEPTH_BUFFER_BIT | PGL.GL_STENCIL_BUFFER_BIT); - + if (primarySurface) { - pgl.beginOnscreenDraw(clearColorBuffer); + pgl.beginOnscreenDraw(clearColorBuffer); } else { pgl.beginOffscreenDraw(pg.clearColorBuffer); - + // Just in case the texture was recreated (in a resize event for example) - offscreenFramebuffer.setColorBuffer(texture); + offscreenFramebuffer.setColorBuffer(texture); } if (hints[DISABLE_DEPTH_MASK]) { pgl.glDepthMask(false); } else { pgl.glDepthMask(true); - } - + } + drawing = true; pixelsOp = OP_NONE; - + modified = false; setgetPixels = false; - + clearColorBuffer0 = clearColorBuffer; clearColorBuffer = false; - + report("bot beginDraw()"); } public void endDraw() { report("top endDraw()"); - + 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 +// // 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 +// // manipulating individual pixels. If that's +// // the case we need to update the screen with // // the changes in the pixels array. -// updatePixels(); +// updatePixels(); // } - - // TODO: Implement depth sorting (http://code.google.com/p/processing/issues/detail?id=51) + + // TODO: Implement depth sorting (http://code.google.com/p/processing/issues/detail?id=51) //if (hints[ENABLE_DEPTH_SORT]) { // flush(); - //} + //} } - + if (!drawing) { showWarning("P3D: Cannot call endDraw() before beginDraw()."); return; } - + if (primarySurface) { - pgl.endOnscreenDraw(clearColorBuffer0); + pgl.endOnscreenDraw(clearColorBuffer0); pgl.glFlush(); } else { if (offscreenMultisample) { - offscreenFramebufferMultisample.copy(offscreenFramebuffer); + offscreenFramebufferMultisample.copy(offscreenFramebuffer); } popFramebuffer(); - + pgl.endOffscreenDraw(pg.clearColorBuffer0); - + pg.restoreGL(); - } - - drawing = false; - - report("bot endDraw()"); + } + + drawing = false; + + report("bot endDraw()"); } - + public PGL beginPGL() { return pgl; } - + public void endPGL() { restoreGL(); } - - + + public void restartPGL() { - pgl.initialized = false; + pgl.initialized = false; } - - + + protected void restoreGL() { - blendMode(blendMode); - + blendMode(blendMode); + if (hints[DISABLE_DEPTH_TEST]) { pgl.glDisable(PGL.GL_DEPTH_TEST); } else { pgl.glEnable(PGL.GL_DEPTH_TEST); } - pgl.glDepthFunc(PGL.GL_LEQUAL); - + pgl.glDepthFunc(PGL.GL_LEQUAL); + if (antialias < 2) { pgl.glDisable(PGL.GL_MULTISAMPLE); pgl.glEnable(PGL.GL_POINT_SMOOTH); pgl.glEnable(PGL.GL_LINE_SMOOTH); - pgl.glEnable(PGL.GL_POLYGON_SMOOTH); + pgl.glEnable(PGL.GL_POLYGON_SMOOTH); } else { - pgl.glEnable(PGL.GL_MULTISAMPLE); + pgl.glEnable(PGL.GL_MULTISAMPLE); pgl.glDisable(PGL.GL_POINT_SMOOTH); pgl.glDisable(PGL.GL_LINE_SMOOTH); - pgl.glDisable(PGL.GL_POLYGON_SMOOTH); - } - + pgl.glDisable(PGL.GL_POLYGON_SMOOTH); + } + pgl.glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); - + pgl.glFrontFace(PGL.GL_CW); - + pgl.glActiveTexture(PGL.GL_TEXTURE0); - + if (hints[DISABLE_DEPTH_MASK]) { pgl.glDepthMask(false); } else { pgl.glDepthMask(true); - } + } } - - - protected void beginPixelsOp(int op) { + + + protected void beginPixelsOp(int op) { if (primarySurface) { if (op == OP_READ) { pgl.glReadBuffer(PGL.GL_FRONT); } else { pgl.glDrawBuffer(PGL.GL_BACK); } - offscreenNotCurrent = false; + 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 + // 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. + // the pixels are affected. if (op == OP_READ) { // We always read the screen pixels from the color FBO. offscreenNotCurrent = offscreenFramebuffer != currentFramebuffer; @@ -1643,14 +1658,14 @@ public class PGraphicsOpenGL extends PGraphics { offscreenNotCurrent = offscreenFramebufferMultisample != currentFramebuffer; } else { offscreenNotCurrent = offscreenFramebuffer != currentFramebuffer; - } + } if (offscreenNotCurrent) { pushFramebuffer(); if (offscreenMultisample) { - setFramebuffer(offscreenFramebufferMultisample); + setFramebuffer(offscreenFramebufferMultisample); } else { setFramebuffer(offscreenFramebuffer); - } + } pgl.updateOffscreen(pg.pgl); } pgl.glDrawBuffer(PGL.GL_COLOR_ATTACHMENT0); @@ -1659,25 +1674,25 @@ public class PGraphicsOpenGL extends PGraphics { pixelsOp = op; } - - protected void endPixelsOp() { + + 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); + offscreenFramebufferMultisample.copy(offscreenFramebuffer); } popFramebuffer(); } pixelsOp = OP_NONE; - } - - + } + + protected void updateGLProjection() { if (glProjection == null) { glProjection = new float[16]; } - + glProjection[0] = projection.m00; glProjection[1] = projection.m10; glProjection[2] = projection.m20; @@ -1699,12 +1714,12 @@ public class PGraphicsOpenGL extends PGraphics { glProjection[15] = projection.m33; } - + protected void updateGLModelview() { if (glModelview == null) { glModelview = new float[16]; } - + glModelview[0] = modelview.m00; glModelview[1] = modelview.m10; glModelview[2] = modelview.m20; @@ -1723,21 +1738,21 @@ public class PGraphicsOpenGL extends PGraphics { glModelview[12] = modelview.m03; glModelview[13] = modelview.m13; glModelview[14] = modelview.m23; - glModelview[15] = modelview.m33; - } - - + glModelview[15] = modelview.m33; + } + + protected void calcProjmodelview() { projmodelview.set(projection); - projmodelview.apply(modelview); + projmodelview.apply(modelview); } - - + + protected void updateGLProjmodelview() { if (glProjmodelview == null) { glProjmodelview = new float[16]; } - + glProjmodelview[0] = projmodelview.m00; glProjmodelview[1] = projmodelview.m10; glProjmodelview[2] = projmodelview.m20; @@ -1758,80 +1773,80 @@ public class PGraphicsOpenGL extends PGraphics { glProjmodelview[14] = projmodelview.m23; glProjmodelview[15] = projmodelview.m33; } - - + + protected void updateGLNormal() { if (glNormal == null) { glNormal = new float[9]; } - + // The normal matrix is the transpose of the inverse of the - // modelview (remember that gl matrices are column-major, + // modelview (remember that gl matrices are column-major, // meaning that elements 0, 1, 2 are the first column, // 3, 4, 5 the second, etc.: - glNormal[0] = modelviewInv.m00; - glNormal[1] = modelviewInv.m01; + glNormal[0] = modelviewInv.m00; + glNormal[1] = modelviewInv.m01; glNormal[2] = modelviewInv.m02; - - glNormal[3] = modelviewInv.m10; - glNormal[4] = modelviewInv.m11; + + glNormal[3] = modelviewInv.m10; + glNormal[4] = modelviewInv.m11; glNormal[5] = modelviewInv.m12; - - glNormal[6] = modelviewInv.m20; - glNormal[7] = modelviewInv.m21; - glNormal[8] = modelviewInv.m22; + + glNormal[6] = modelviewInv.m20; + glNormal[7] = modelviewInv.m21; + glNormal[8] = modelviewInv.m22; } - - - ////////////////////////////////////////////////////////////// - + + + ////////////////////////////////////////////////////////////// + // SETTINGS // protected void checkSettings() - + protected void defaultSettings() { super.defaultSettings(); manipulatingCamera = false; - + clearColorBuffer = false; - + if (fbStack == null) { fbStack = new Stack(); screenFramebuffer = new PFramebuffer(parent, width, height, true); setFramebuffer(screenFramebuffer); - } - + } + if (modelviewStack == null) { modelviewStack = new Stack(); } if (modelviewInvStack == null) { modelviewInvStack = new Stack(); - } + } if (projectionStack == null) { projectionStack = new Stack(); } - + // easiest for beginners textureMode(IMAGE); - + // Default material properties ambient(80); specular(125); emissive(0); - shininess(1); + shininess(1); } - - + + // reapplySettings ////////////////////////////////////////////////////////////// // HINTS - + public void hint(int which) { boolean oldValue = hints[PApplet.abs(which)]; super.hint(which); @@ -1840,7 +1855,7 @@ public class PGraphicsOpenGL extends PGraphics { if (oldValue == newValue) { return; } - + if (which == DISABLE_DEPTH_TEST) { flush(); pgl.glDisable(PGL.GL_DEPTH_TEST); @@ -1852,15 +1867,15 @@ public class PGraphicsOpenGL extends PGraphics { pgl.glDepthMask(false); } else if (which == ENABLE_DEPTH_MASK) { flush(); - pgl.glDepthMask(true); + pgl.glDepthMask(true); } else if (which == DISABLE_ACCURATE_2D) { flush(); - setFlushMode(FLUSH_WHEN_FULL); + setFlushMode(FLUSH_WHEN_FULL); } else if (which == ENABLE_ACCURATE_2D) { flush(); - setFlushMode(FLUSH_CONTINUOUSLY); + setFlushMode(FLUSH_CONTINUOUSLY); } else if (which == DISABLE_TEXTURE_CACHE) { - flush(); + flush(); } else if (which == DISABLE_PERSPECTIVE_CORRECTED_LINES) { if (0 < tessGeo.lineVertexCount && 0 < tessGeo.lineIndexCount) { // We flush the geometry using the previous line setting. @@ -1876,17 +1891,17 @@ public class PGraphicsOpenGL extends PGraphics { } } - + ////////////////////////////////////////////////////////////// // SHAPE CREATORS - - + + public PShape createShape() { return createShape(POLYGON); } - - + + public PShape createShape(int type) { PShape3D shape = null; if (type == PShape.GROUP) { @@ -1903,7 +1918,7 @@ public class PGraphicsOpenGL extends PGraphics { } else if (type == TRIANGLE_FAN) { shape = new PShape3D(parent, PShape.GEOMETRY); shape.setKind(TRIANGLE_FAN); - } else if (type == TRIANGLE_STRIP) { + } else if (type == TRIANGLE_STRIP) { shape = new PShape3D(parent, PShape.GEOMETRY); shape.setKind(TRIANGLE_STRIP); } else if (type == QUADS || type == QUADS) { @@ -1914,23 +1929,23 @@ public class PGraphicsOpenGL extends PGraphics { shape.setKind(QUAD_STRIP); } else if (type == POLYGON) { shape = new PShape3D(parent, PShape.GEOMETRY); - shape.setKind(POLYGON); + shape.setKind(POLYGON); } return shape; } - - + + public PShape createShape(int kind, float... p) { PShape3D shape = null; int len = p.length; - + if (kind == POINT) { if (len != 2) { showWarning("Wrong number of parameters"); return null; } shape = new PShape3D(parent, PShape.PRIMITIVE); - shape.setKind(POINT); + shape.setKind(POINT); } else if (kind == LINE) { if (len != 4) { showWarning("Wrong number of parameters"); @@ -1956,169 +1971,169 @@ public class PGraphicsOpenGL extends PGraphics { if (len != 4 && len != 5 && len != 8) { showWarning("Wrong number of parameters"); return null; - } + } shape = new PShape3D(parent, PShape.PRIMITIVE); - shape.setKind(RECT); + shape.setKind(RECT); } else if (kind == ELLIPSE) { if (len != 4) { showWarning("Wrong number of parameters"); return null; - } + } shape = new PShape3D(parent, PShape.PRIMITIVE); - shape.setKind(ELLIPSE); + shape.setKind(ELLIPSE); } else if (kind == ARC) { if (len != 6) { showWarning("Wrong number of parameters"); return null; - } + } shape = new PShape3D(parent, PShape.PRIMITIVE); shape.setKind(ARC); } else if (kind == BOX) { if (len != 1 && len != 3) { showWarning("Wrong number of parameters"); return null; - } + } shape = new PShape3D(parent, PShape.PRIMITIVE); - shape.setKind(BOX); + shape.setKind(BOX); } else if (kind == SPHERE) { if (len != 1) { showWarning("Wrong number of parameters"); return null; } shape = new PShape3D(parent, PShape.PRIMITIVE); - shape.setKind(SPHERE); + shape.setKind(SPHERE); } - + if (shape != null) { shape.setParams(p); } - + return shape; } - - + + ////////////////////////////////////////////////////////////// // VERTEX SHAPES - - + + public void beginShape(int kind) { shape = kind; - + inGeo.clear(); - - breakShape = false; + + breakShape = false; defaultEdges = true; - + textureImage0 = textureImage; // The superclass method is called to avoid an early flush. super.noTexture(); - + normalMode = NORMAL_MODE_AUTO; } - + public void endShape(int mode) { - if (flushMode == FLUSH_WHEN_FULL && hints[DISABLE_TEXTURE_CACHE] && + if (flushMode == FLUSH_WHEN_FULL && hints[DISABLE_TEXTURE_CACHE] && textureImage0 != null && textureImage == null) { // The previous shape had a texture and this one doesn't. So we need to flush // the textured geometry. textureImage = textureImage0; flush(); - textureImage = null; + textureImage = null; } - + tessellate(mode); - - if (flushMode == FLUSH_CONTINUOUSLY || + + if (flushMode == FLUSH_CONTINUOUSLY || (flushMode == FLUSH_WHEN_FULL && tessGeo.isFull())) { - + if (flushMode == FLUSH_WHEN_FULL && tessGeo.isOverflow()) { PGraphics.showWarning("P3D: tessellated arrays are overflowing"); } - + flush(); } } - + public void texture(PImage image) { - if (flushMode == FLUSH_WHEN_FULL && hints[DISABLE_TEXTURE_CACHE] && + if (flushMode == FLUSH_WHEN_FULL && hints[DISABLE_TEXTURE_CACHE] && image != textureImage0) { // Changing the texture image, so we need to flush the // tessellated geometry accumulated until now, so that // textures are not mixed. - textureImage = textureImage0; - flush(); + textureImage = textureImage0; + flush(); } super.texture(image); } - - + + public void noTexture() { if (flushMode == FLUSH_WHEN_FULL && hints[DISABLE_TEXTURE_CACHE] && null != textureImage0) { // Changing the texture image, so we need to flush the // tessellated geometry accumulated until now, so that - // textures are not mixed. + // textures are not mixed. textureImage = textureImage0; - flush(); - } + flush(); + } super.noTexture(); } - - + + public void beginContour() { if (openContour) { showWarning("P3D: Already called beginContour()."); return; - } + } openContour = true; } - - + + public void endContour() { if (!openContour) { showWarning("P3D: Need to call beginContour() first."); - return; + return; } openContour = false; breakShape = true; - } - - + } + + public void vertex(float x, float y) { vertex(x, y, 0, 0, 0); } - - public void vertex(float x, float y, float u, float v) { - vertex(x, y, 0, u, v); - } - - - public void vertex(float x, float y, float z) { - vertex(x, y, z, 0, 0); - } - + public void vertex(float x, float y, float u, float v) { + vertex(x, y, 0, u, v); + } + + + public void vertex(float x, float y, float z) { + vertex(x, y, z, 0, 0); + } + + public void vertex(float x, float y, float z, float u, float v) { - vertexImpl(x, y, z, u, v, VERTEX); - } - - + vertexImpl(x, y, z, u, v, VERTEX); + } + + protected void vertexImpl(float x, float y, float z, float u, float v, int code) { if (inGeo.isFull()) { PGraphics.showWarning("P3D: Too many vertices, try creating smaller shapes"); return; } - + boolean textured = textureImage != null; int fcolor = 0x00; if (fill || textured) { if (!textured) { fcolor = fillColor; - } else { + } else { if (tint) { fcolor = tintColor; } else { @@ -2126,35 +2141,35 @@ public class PGraphicsOpenGL extends PGraphics { } } } - + int scolor = 0x00; float sweight = 0; if (stroke) { scolor = strokeColor; sweight = strokeWeight; - } + } if (breakShape) { code = PShape.BREAK; breakShape = false; - } - + } + if (textured && textureMode == IMAGE) { u = PApplet.min(1, u / textureImage.width); v = PApplet.min(1, v / textureImage.height); } - - inGeo.addVertex(x, y, z, - fcolor, + + inGeo.addVertex(x, y, z, + fcolor, normalX, normalY, normalZ, - u, v, + u, v, scolor, sweight, ambientColor, specularColor, emissiveColor, shininess, - code); + code); } - - - public void clip(float a, float b, float c, float d) { + + + public void clip(float a, float b, float c, float d) { if (imageMode == CORNER) { if (c < 0) { // reset a negative width a += c; c = -c; @@ -2174,7 +2189,7 @@ public class PGraphicsOpenGL extends PGraphics { } clipImpl(a, b, c, d); - + } else if (imageMode == CENTER) { // c and d are width/height if (c < 0) c = -c; @@ -2183,39 +2198,39 @@ public class PGraphicsOpenGL extends PGraphics { float y1 = b - d/2; clipImpl(x1, y1, x1 + c, y1 + d); - } + } } - + protected void clipImpl(float x1, float y1, float x2, float y2) { flush(); pgl.glEnable(PGL.GL_SCISSOR_TEST); - + float h = y2 - y1; pgl.glScissor((int)x1, (int)(height - y1 - h), (int)(x2 - x1), (int)h); - + clip = true; } - + public void noClip() { if (clip) { flush(); pgl.glDisable(PGL.GL_SCISSOR_TEST); clip = false; } - } - - + } + + ////////////////////////////////////////////////////////////// // RENDERING // protected void render() - // protected void sort() - - + // protected void sort() + + protected void tessellate(int mode) { tessellator.setInGeometry(inGeo); tessellator.setTessGeometry(tessGeo); @@ -2224,13 +2239,13 @@ public class PGraphicsOpenGL extends PGraphics { tessellator.setStrokeWeight(strokeWeight); tessellator.setStrokeCap(strokeCap); tessellator.setStrokeJoin(strokeJoin); - + setFirstTexIndex(tessGeo.fillIndexCount); - + if (shape == POINTS) { - tessellator.tessellatePoints(); + tessellator.tessellatePoints(); } else if (shape == LINES) { - tessellator.tessellateLines(); + tessellator.tessellateLines(); } else if (shape == TRIANGLE || shape == TRIANGLES) { if (stroke && defaultEdges) inGeo.addTrianglesEdges(); if (normalMode == NORMAL_MODE_AUTO) inGeo.calcTrianglesNormals(); @@ -2240,8 +2255,8 @@ public class PGraphicsOpenGL extends PGraphics { if (normalMode == NORMAL_MODE_AUTO) inGeo.calcTriangleFanNormals(); tessellator.tessellateTriangleFan(); } else if (shape == TRIANGLE_STRIP) { - if (stroke && defaultEdges) inGeo.addTriangleStripEdges(); - if (normalMode == NORMAL_MODE_AUTO) inGeo.calcTriangleStripNormals(); + if (stroke && defaultEdges) inGeo.addTriangleStripEdges(); + if (normalMode == NORMAL_MODE_AUTO) inGeo.calcTriangleStripNormals(); tessellator.tessellateTriangleStrip(); } else if (shape == QUAD || shape == QUADS) { if (stroke && defaultEdges) inGeo.addQuadsEdges(); @@ -2253,71 +2268,71 @@ public class PGraphicsOpenGL extends PGraphics { tessellator.tessellateQuadStrip(); } else if (shape == POLYGON) { if (stroke && defaultEdges) inGeo.addPolygonEdges(mode == CLOSE); - tessellator.tessellatePolygon(false, mode == CLOSE, normalMode == NORMAL_MODE_AUTO); + tessellator.tessellatePolygon(false, mode == CLOSE, normalMode == NORMAL_MODE_AUTO); } - + setLastTexIndex(tessGeo.lastFillIndex); } - - + + protected void setFirstTexIndex(int first) { firstTexIndex = first; } - - - protected void setLastTexIndex(int last) { + + + protected void setLastTexIndex(int last) { if (textureImage0 != textureImage || texCache.count == 0) { texCache.addTexture(textureImage, firstTexIndex, last); } else { texCache.setLastIndex(last); - } + } } - - - public void flush() { + + + public void flush() { 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. + // 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 + // The modelview transformation has been applied already to the // tessellated vertices, so we set the OpenGL modelview matrix as // the identity to avoid applying the model transformations twice. pushMatrix(); resetMatrix(); } - + if (hasFill) { renderFill(); } - + if (hasPoints) { renderPoints(); - } + } if (hasLines) { renderLines(); - } - + } + if (flushMode == FLUSH_WHEN_FULL && !hints[DISABLE_TRANSFORM_CACHE]) { popMatrix(); } } - - tessGeo.clear(); - texCache.clear(); + + tessGeo.clear(); + texCache.clear(); } - + protected void renderPixels() { int mi1 = my1 * width + mx1; @@ -2329,137 +2344,137 @@ public class PGraphicsOpenGL extends PGraphics { 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); + + //PApplet.arrayCopy(pixels, rgbaPixels); //PGL.javaToNativeARGB(rgbaPixels, width, height); - + // Copying pixel buffer to screen texture... - pgl.copyToTexture(texture.glTarget, texture.glFormat, texture.glID, + 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 + // 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. + // should be done updating the (off)screen buffer. beginPixelsOp(OP_WRITE); - drawTexture(mx1, my1, mw, mh); + drawTexture(mx1, my1, mw, mh); endPixelsOp(); } - - modified = false; + + modified = false; } - - + + protected void renderPoints() { if (!pointVBOsCreated) { createPointBuffers(); pointVBOsCreated = true; } updatePointBuffers(); - + PointShader shader = getPointShader(); - shader.start(); - shader.setVertexAttribute(glPointVertexBufferID, 3, PGL.GL_FLOAT, 0, 0); - shader.setColorAttribute(glPointColorBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); + shader.start(); + shader.setVertexAttribute(glPointVertexBufferID, 3, PGL.GL_FLOAT, 0, 0); + shader.setColorAttribute(glPointColorBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); shader.setSizeAttribute(glPointSizeBufferID, 2, PGL.GL_FLOAT, 0, 0); - pgl.glDrawElements(PGL.GL_TRIANGLES, tessGeo.pointIndexCount, PGL.INDEX_TYPE, 0); - + pgl.glDrawElements(PGL.GL_TRIANGLES, tessGeo.pointIndexCount, PGL.INDEX_TYPE, 0); + shader.stop(); unbindPointBuffers(); - } - - + } + + protected void renderLines() { if (!lineVBOsCreated) { createLineBuffers(); lineVBOsCreated = true; } updateLineBuffers(); - + LineShader shader = getLineShader(); - shader.start(); - - shader.setVertexAttribute(glLineVertexBufferID, 3, PGL.GL_FLOAT, 0, 0); - shader.setColorAttribute(glLineColorBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); + shader.start(); + + shader.setVertexAttribute(glLineVertexBufferID, 3, PGL.GL_FLOAT, 0, 0); + shader.setColorAttribute(glLineColorBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); shader.setDirWidthAttribute(glLineDirWidthBufferID, 4, PGL.GL_FLOAT, 0, 0); - - pgl.glDrawElements(PGL.GL_TRIANGLES, tessGeo.lineIndexCount, PGL.INDEX_TYPE, 0); - + + pgl.glDrawElements(PGL.GL_TRIANGLES, tessGeo.lineIndexCount, PGL.INDEX_TYPE, 0); + shader.stop(); unbindLineBuffers(); - } - - + } + + protected void renderFill() { if (!fillVBOsCreated) { createFillBuffers(); fillVBOsCreated = true; - } + } updateFillBuffers(lights, texCache.hasTexture); - - texCache.beginRender(); + + texCache.beginRender(); for (int i = 0; i < texCache.count; i++) { - PTexture tex = texCache.getTexture(i); - - FillShader shader = getFillShader(lights, tex != null); + PTexture tex = texCache.getTexture(i); + + FillShader shader = getFillShader(lights, tex != null); shader.start(); - - shader.setVertexAttribute(glFillVertexBufferID, 3, PGL.GL_FLOAT, 0, 0); - shader.setColorAttribute(glFillColorBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); - + + shader.setVertexAttribute(glFillVertexBufferID, 3, PGL.GL_FLOAT, 0, 0); + shader.setColorAttribute(glFillColorBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); + if (lights) { shader.setNormalAttribute(glFillNormalBufferID, 3, PGL.GL_FLOAT, 0, 0); shader.setAmbientAttribute(glFillAmbientBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); shader.setSpecularAttribute(glFillSpecularBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); - shader.setEmissiveAttribute(glFillEmissiveBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); + shader.setEmissiveAttribute(glFillEmissiveBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); shader.setShininessAttribute(glFillShininessBufferID, 1, PGL.GL_FLOAT, 0, 0); } - + if (tex != null) { shader.setTexCoordAttribute(glFillTexCoordBufferID, 2, PGL.GL_FLOAT, 0, 0); shader.setTexture(tex); } - + int offset = texCache.firstIndex[i]; int size = texCache.lastIndex[i] - texCache.firstIndex[i] + 1; pgl.glDrawElements(PGL.GL_TRIANGLES, size, PGL.INDEX_TYPE, offset * PGL.SIZEOF_INDEX); - + shader.stop(); - } - texCache.endRender(); - unbindFillBuffers(); + } + texCache.endRender(); + unbindFillBuffers(); } - + // Utility function to render current tessellated geometry, under the assumption that // the texture is already bound. protected void renderTexFill(PTexture tex) { if (!fillVBOsCreated) { createFillBuffers(); fillVBOsCreated = true; - } + } updateFillBuffers(lights, true); - - FillShader shader = getFillShader(lights, true); + + FillShader shader = getFillShader(lights, true); shader.start(); - - shader.setVertexAttribute(glFillVertexBufferID, 3, PGL.GL_FLOAT, 0, 0); + + shader.setVertexAttribute(glFillVertexBufferID, 3, PGL.GL_FLOAT, 0, 0); shader.setColorAttribute(glFillColorBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); shader.setTexCoordAttribute(glFillTexCoordBufferID, 2, PGL.GL_FLOAT, 0, 0); shader.setTexture(tex); - + if (lights) { shader.setNormalAttribute(glFillNormalBufferID, 3, PGL.GL_FLOAT, 0, 0); shader.setAmbientAttribute(glFillAmbientBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); shader.setSpecularAttribute(glFillSpecularBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); - shader.setEmissiveAttribute(glFillEmissiveBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); + shader.setEmissiveAttribute(glFillEmissiveBufferID, 4, PGL.GL_UNSIGNED_BYTE, 0, 0); shader.setShininessAttribute(glFillShininessBufferID, 1, PGL.GL_FLOAT, 0, 0); } @@ -2467,18 +2482,18 @@ public class PGraphicsOpenGL extends PGraphics { int sizex = size * PGL.SIZEOF_INDEX; pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, glFillIndexBufferID); pgl.glBufferData(PGL.GL_ELEMENT_ARRAY_BUFFER, sizex, ShortBuffer.wrap(tessGeo.fillIndices, 0, size), vboMode); - pgl.glDrawElements(PGL.GL_TRIANGLES, size, PGL.INDEX_TYPE, 0); + pgl.glDrawElements(PGL.GL_TRIANGLES, size, PGL.INDEX_TYPE, 0); pgl.glBindBuffer(PGL.GL_ELEMENT_ARRAY_BUFFER, 0); - + shader.stop(); } - + ////////////////////////////////////////////////////////////// // BEZIER CURVE VERTICES - + public void bezierDetail(int detail) { bezierDetail = detail; @@ -2492,18 +2507,18 @@ public class PGraphicsOpenGL extends PGraphics { // multiply the basis and forward diff matrices together // saves much time since this needn't be done for each curve bezierDrawMatrix.apply(pg.bezierBasisMatrix); - } - - + } + + public void bezierVertex(float x2, float y2, float x3, float y3, float x4, float y4) { - bezierVertex(x2, y2, 0, - x3, y3, 0, - x4, y4, 0); + bezierVertex(x2, y2, 0, + x3, y3, 0, + x4, y4, 0); } - - + + public void bezierVertex(float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4) { @@ -2532,17 +2547,17 @@ public class PGraphicsOpenGL extends PGraphics { y1 += yplot1; yplot1 += yplot2; yplot2 += yplot3; z1 += zplot1; zplot1 += zplot2; zplot2 += zplot3; vertexImpl(x1, y1, z1, 0, 0, BEZIER_VERTEX); - } + } } - - + + public void quadraticVertex(float cx, float cy, float x3, float y3) { quadraticVertex(cx, cy, 0, x3, y3, 0); } - - + + public void quadraticVertex(float cx, float cy, float cz, float x3, float y3, float z3) { float x1 = inGeo.getLastVertexX(); @@ -2554,21 +2569,21 @@ public class PGraphicsOpenGL extends PGraphics { x3, y3, z3); } - + protected void bezierInitCheck() { if (!bezierInited) { bezierInit(); } } - + protected void bezierInit() { // overkill to be broken out, but better parity with the curve stuff below bezierDetail(bezierDetail); bezierInited = true; - } - - + } + + protected void bezierVertexCheck() { if (shape != POLYGON) { throw new RuntimeException("beginShape() or beginShape(POLYGON) " + @@ -2578,31 +2593,31 @@ public class PGraphicsOpenGL extends PGraphics { throw new RuntimeException("vertex() must be used at least once" + "before bezierVertex() or quadraticVertex()"); } - } + } + - ////////////////////////////////////////////////////////////// - // CATMULL-ROM CURVE VERTICES + // CATMULL-ROM CURVE VERTICES + - public void curveDetail(int detail) { curveDetail = detail; curveInit(); } - - + + public void curveTightness(float tightness) { curveTightness = tightness; curveInit(); - } - - + } + + public void curveVertex(float x, float y) { curveVertex(x, y, 0); - } + } + - public void curveVertex(float x, float y, float z) { curveVertexCheck(); float[] vertex = curveVertices[curveVertexCount]; @@ -2626,16 +2641,16 @@ public class PGraphicsOpenGL extends PGraphics { curveVertices[curveVertexCount-1][Y], curveVertices[curveVertexCount-1][Z]); } - - } - - protected void curveVertexCheck() { + } + + + protected void curveVertexCheck() { if (shape != POLYGON) { throw new RuntimeException("You must use createGeometry() or " + "createGeometry(POLYGON) before curveVertex()"); } - + // to improve code init time, allocate on first use. if (curveVertices == null) { curveVertices = new float[128][3]; @@ -2649,15 +2664,15 @@ public class PGraphicsOpenGL extends PGraphics { } curveInitCheck(); } - - + + protected void curveInitCheck() { if (!curveInited) { curveInit(); } } - - + + protected void curveInit() { // allocate only if/when used to save startup time if (curveDrawMatrix == null) { @@ -2689,9 +2704,9 @@ public class PGraphicsOpenGL extends PGraphics { // multiply the basis and forward diff matrices together // saves much time since this needn't be done for each curve curveDrawMatrix.apply(curveBasisMatrix); - } - - + } + + /** * Handle emitting a specific segment of Catmull-Rom curve. This can be * overridden by subclasses that need more efficient rendering options. @@ -2725,14 +2740,14 @@ public class PGraphicsOpenGL extends PGraphics { z0 += zplot1; zplot1 += zplot2; zplot2 += zplot3; vertexImpl(x0, y0, z0, 0, 0, CURVE_VERTEX); } - } + } + - ////////////////////////////////////////////////////////////// // SPLINE UTILITY FUNCTIONS (used by both Bezier and Catmull-Rom) - + /** * Setup forward-differencing matrix to be used for speedy * curve rendering. It's based on using a specific number @@ -2751,8 +2766,8 @@ public class PGraphicsOpenGL extends PGraphics { fff, ff, f, 0, 6*fff, 2*ff, 0, 0, 6*fff, 0, 0, 0); - } - + } + ////////////////////////////////////////////////////////////// @@ -2792,18 +2807,18 @@ public class PGraphicsOpenGL extends PGraphics { // public void ellipseMode(int mode) - + public void ellipse(float a, float b, float c, float d) { - beginShape(TRIANGLE_FAN); + beginShape(TRIANGLE_FAN); defaultEdges = false; - inGeo.generateEllipse(ellipseMode, a, b, c, d, - fill, fillColor, + inGeo.generateEllipse(ellipseMode, a, b, c, d, + fill, fillColor, stroke, strokeColor, strokeWeight, ambientColor, specularColor, emissiveColor, shininess); endShape(); } - - + + // public void ellipse(float a, float b, float c, float d) // public void arc(float a, float b, float c, float d, @@ -2812,8 +2827,8 @@ public class PGraphicsOpenGL extends PGraphics { ////////////////////////////////////////////////////////////// // ARC - - + + protected void arcImpl(float x, float y, float w, float h, float start, float stop) { float hr = w / 2f; @@ -2875,7 +2890,7 @@ public class PGraphicsOpenGL extends PGraphics { } } - + ////////////////////////////////////////////////////////////// // BOX @@ -2963,56 +2978,56 @@ public class PGraphicsOpenGL extends PGraphics { ////////////////////////////////////////////////////////////// // SMOOTH - - + + public void smooth() { smooth(2); } - - + + public void smooth(int level) { smooth = true; - + if (maxSamples < level) { PGraphics.showWarning("Smooth level " + level + " is not supported by the hardware. Using " + maxSamples + " instead."); - level = maxSamples; + level = maxSamples; } - - if (antialias != level) { + + if (antialias != level) { antialias = level; if (antialias == 1) { antialias = 0; } // This will trigger a surface restart next time // requestDraw() is called. - pgl.initialized = false; + pgl.initialized = false; } } - + public void noSmooth() { smooth = false; - + if (1 < antialias) { antialias = 0; // This will trigger a surface restart next time // requestDraw() is called. - pgl.initialized = false; + pgl.initialized = false; } - } - - + } + + ////////////////////////////////////////////////////////////// // SHAPE // public void shapeMode(int mode) - - + + 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) { @@ -3027,12 +3042,12 @@ public class PGraphicsOpenGL extends PGraphics { 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 flush(); - + pushMatrix(); if (shapeMode == CENTER) { @@ -3058,7 +3073,7 @@ public class PGraphicsOpenGL extends PGraphics { popMatrix(); } } - + ////////////////////////////////////////////////////////////// @@ -3092,32 +3107,32 @@ public class PGraphicsOpenGL extends PGraphics { // protected float textWidthImpl(char buffer[], int start, int stop) - + ////////////////////////////////////////////////////////////// // TEXT IMPL - + // protected void textLineAlignImpl(char buffer[], int start, int stop, // float x, float y) - + /** * Implementation of actual drawing for a line of text. */ protected void textLineImpl(char buffer[], int start, int stop, float x, float y) { - textTex = (PFontTexture)textFont.getCache(pg); + textTex = (PFontTexture)textFont.getCache(pg); if (textTex == null) { textTex = new PFontTexture(parent, textFont, maxTextureSize, maxTextureSize); - textFont.setCache(this, textTex); + textFont.setCache(this, textTex); } else { if (textTex.contextIsOutdated()) { - textTex = new PFontTexture(parent, textFont, PApplet.min(PGL.MAX_FONT_TEX_SIZE, maxTextureSize), + textTex = new PFontTexture(parent, textFont, PApplet.min(PGL.MAX_FONT_TEX_SIZE, maxTextureSize), PApplet.min(PGL.MAX_FONT_TEX_SIZE, maxTextureSize)); textFont.setCache(this, textTex); } - } - textTex.setFirstTexture(); - + } + textTex.setFirstTexture(); + // Saving style parameters modified by text rendering. int savedTextureMode = textureMode; boolean savedStroke = stroke; @@ -3127,20 +3142,20 @@ public class PGraphicsOpenGL extends PGraphics { boolean savedTint = tint; int savedTintColor = tintColor; int savedBlendMode = blendMode; - + // Setting style used in text rendering. - textureMode = NORMAL; - stroke = false; + textureMode = NORMAL; + stroke = false; normalX = 0; normalY = 0; - normalZ = 1; + normalZ = 1; tint = true; tintColor = fillColor; - + blendMode(BLEND); - + super.textLineImpl(buffer, start, stop, x, y); - + // Restoring original style. textureMode = savedTextureMode; stroke = savedStroke; @@ -3149,7 +3164,7 @@ public class PGraphicsOpenGL extends PGraphics { normalZ = savedNormalZ; tint = savedTint; tintColor = savedTintColor; - + // Note that if the user is using a blending mode different from // BLEND, and has a bunch of continuous text rendering, the performance // won't be optimal because at the end of each text() call the geometry @@ -3157,19 +3172,19 @@ public class PGraphicsOpenGL extends PGraphics { blendMode(savedBlendMode); } - + protected void textCharImpl(char ch, float x, float y) { PFont.Glyph glyph = textFont.getGlyph(ch); - - if (glyph != null) { + + if (glyph != null) { PFontTexture.TextureInfo tinfo = textTex.getTexInfo(glyph); - + if (tinfo == null) { // Adding new glyph to the font texture. tinfo = textTex.addToTexture(glyph); } - - if (textMode == MODEL) { + + if (textMode == MODEL) { float high = glyph.height / (float) textFont.getSize(); float bwidth = glyph.width / (float) textFont.getSize(); float lextent = glyph.leftExtent / (float) textFont.getSize(); @@ -3181,7 +3196,7 @@ public class PGraphicsOpenGL extends PGraphics { float y2 = y1 + high * textSize; textCharModelImpl(tinfo, x1, y1, x2, y2); - } + } } } @@ -3190,75 +3205,75 @@ public class PGraphicsOpenGL extends PGraphics { float x1, float y1) { if (textTex.currentTex != info.texIndex) { textTex.setTexture(info.texIndex); - } + } PImage tex = textTex.getCurrentTexture(); - + beginShape(QUADS); - texture(tex); + texture(tex); vertex(x0, y0, info.u0, info.v0); vertex(x1, y0, info.u1, info.v0); vertex(x1, y1, info.u1, info.v1); vertex(x0, y1, info.u0, info.v1); - endShape(); + endShape(); } - - + + ////////////////////////////////////////////////////////////// // MATRIX STACK - + public void pushMatrix() { modelviewStack.push(new PMatrix3D(modelview)); modelviewInvStack.push(new PMatrix3D(modelviewInv)); } - + public void popMatrix() { if (hints[DISABLE_TRANSFORM_CACHE]) { - flush(); + flush(); } PMatrix3D mat; - + mat = modelviewStack.pop(); modelview.set(mat); - + mat = modelviewInvStack.pop(); modelviewInv.set(mat); - + calcProjmodelview(); } - - + + ////////////////////////////////////////////////////////////// // MATRIX TRANSFORMATIONS - + public void translate(float tx, float ty) { translate(tx, ty, 0); } - + public void translate(float tx, float ty, float tz) { if (hints[DISABLE_TRANSFORM_CACHE]) { - flush(); + flush(); } - - modelview.translate(tx, ty, tz); - invTranslate(modelviewInv, tx, ty, tz); - projmodelview.translate(tx, ty, tz); + + modelview.translate(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 @@ -3269,29 +3284,29 @@ public class PGraphicsOpenGL extends PGraphics { rotateZ(angle); } - + public void rotateX(float angle) { rotate(angle, 1, 0, 0); } - + public void rotateY(float angle) { rotate(angle, 0, 1, 0); } - + public void rotateZ(float angle) { rotate(angle, 0, 0, 1); } - + /** * Rotate around an arbitrary vector, similar to glRotate(), except that it * takes radians (instead of degrees). */ public void rotate(float angle, float v0, float v1, float v2) { if (hints[DISABLE_TRANSFORM_CACHE]) { - flush(); + flush(); } modelview.rotate(angle, v0, v1, v2); @@ -3299,7 +3314,7 @@ public class PGraphicsOpenGL extends PGraphics { 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 @@ -3311,9 +3326,9 @@ 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). */ @@ -3321,7 +3336,7 @@ public class PGraphicsOpenGL extends PGraphics { scale(s, s, s); } - + /** * Same as scale(sx, sy, 1). */ @@ -3329,89 +3344,89 @@ public class PGraphicsOpenGL extends PGraphics { scale(sx, sy, 1); } - + /** * Scale in three dimensions. */ public void scale(float sx, float sy, float sz) { if (hints[DISABLE_TRANSFORM_CACHE]) { - flush(); + flush(); } modelview.scale(sx, sy, sz); - invScale(modelviewInv, sx, sy, sz); - projmodelview.scale(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); } - + public void shearX(float angle) { float t = (float) Math.tan(angle); - applyMatrix(1, t, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, + applyMatrix(1, t, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1); } - + public void shearY(float angle) { float t = (float) Math.tan(angle); - applyMatrix(1, 0, 0, 0, - t, 1, 0, 0, - 0, 0, 1, 0, + applyMatrix(1, 0, 0, 0, + t, 1, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1); } - + ////////////////////////////////////////////////////////////// // MATRIX MORE! - + public void resetMatrix() { modelview.reset(); modelviewInv.reset(); projmodelview.set(projection); } - + public void applyMatrix(PMatrix2D source) { - applyMatrix(source.m00, source.m01, source.m02, + applyMatrix(source.m00, source.m01, source.m02, source.m10, source.m11, source.m12); } - - public void applyMatrix(float n00, float n01, float n02, + + public void applyMatrix(float n00, float n01, float n02, float n10, float n11, float n12) { - applyMatrix(n00, n01, n02, 0, - n10, n11, n12, 0, - 0, 0, 1, 0, + applyMatrix(n00, n01, n02, 0, + n10, n11, n12, 0, + 0, 0, 1, 0, 0, 0, 0, 1); } - + public void applyMatrix(PMatrix3D source) { - applyMatrix(source.m00, source.m01, source.m02, source.m03, - source.m10, source.m11, source.m12, source.m13, - source.m20, source.m21, source.m22, source.m23, + applyMatrix(source.m00, source.m01, source.m02, source.m03, + source.m10, source.m11, source.m12, source.m13, + source.m20, source.m21, source.m22, source.m23, source.m30, source.m31, source.m32, source.m33); } - + /** * Apply a 4x4 transformation matrix to the modelview stack. */ public void applyMatrix(float n00, float n01, float n02, float n03, - float n10, float n11, float n12, float n13, - float n20, float n21, float n22, float n23, + float n10, float n11, float n12, float n13, + float n20, float n21, float n22, float n23, float n30, float n31, float n32, float n33) { if (hints[DISABLE_TRANSFORM_CACHE]) { - flush(); - } + flush(); + } modelview.apply(n00, n01, n02, n03, n10, n11, n12, n13, n20, n21, n22, n23, @@ -3424,41 +3439,41 @@ public class PGraphicsOpenGL extends PGraphics { /* protected void loadProjection() { - pgl.setProjectionMode(); + pgl.setProjectionMode(); loadMatrix(projection); pgl.setModelviewMode(); } - - + + protected void loadCamera() { pgl.setModelviewMode(); loadMatrix(camera); } - - + + protected void loadModelview() { pgl.setModelviewMode(); - loadMatrix(modelview); + loadMatrix(modelview); } - + protected void loadMatrix(PMatrix3D pMatrix) { - modelview.set(pMatrix); - } + modelview.set(pMatrix); + } */ - + ////////////////////////////////////////////////////////////// // MATRIX GET/SET/PRINT - + public PMatrix getMatrix() { - return modelview.get(); + return modelview.get(); } - + // public PMatrix2D getMatrix(PMatrix2D target) - + public PMatrix3D getMatrix(PMatrix3D target) { if (target == null) { target = new PMatrix3D(); @@ -3467,16 +3482,16 @@ public class PGraphicsOpenGL extends PGraphics { return target; } - + // public void setMatrix(PMatrix source) - + public void setMatrix(PMatrix2D source) { resetMatrix(); applyMatrix(source); } - + /** * Set the current transformation to the contents of the specified source. */ @@ -3485,41 +3500,41 @@ public class PGraphicsOpenGL extends PGraphics { applyMatrix(source); } - + /** * Print the current model (or "transformation") matrix. */ - public void printMatrix() { - modelview.print(); + public void printMatrix() { + modelview.print(); } - - + + ////////////////////////////////////////////////////////////// // PROJECTION - - + + public void pushProjection() { projectionStack.push(new PMatrix3D(projection)); } - - + + public void popProjection() { PMatrix3D mat = projectionStack.pop(); - projection.set(mat); + projection.set(mat); } - + public void applyProjection(PMatrix3D mat) { projection.apply(mat); } - + public void setProjection(PMatrix3D mat) { projection.set(mat); - } - - + } + + ////////////////////////////////////////////////////////////// // CAMERA @@ -3546,25 +3561,25 @@ public class PGraphicsOpenGL extends PGraphics { * setup(), and we expect it to hold through draw(). So we don't reset the * camera transform matrix at the top of draw(). That means that an * innocuous-looking clause like - * + * *
    * beginCamera();
    * translate(0, 0, 10);
    * endCamera();
    * 
- * + * * at the top of draw(), will result in a runaway camera that shoots * infinitely out of the screen over time. In order to prevent this, it is * necessary to call some function that does a hard reset of the camera * transform matrix inside of begin/endCamera. Two options are - * + * *
    * camera(); // sets up the nice default camera transform
    * resetMatrix(); // sets up the identity camera transform
    * 
- * + * * So to rotate a camera a constant amount, you might try - * + * *
    * beginCamera();
    * camera();
@@ -3578,10 +3593,10 @@ public class PGraphicsOpenGL extends PGraphics {
           + "before endCamera()");
     } else {
       manipulatingCamera = true;
-    }    
+    }
   }
-  
-  
+
+
   /**
    * Record the current settings into the camera matrix, and set the matrix mode
    * back to the current transformation matrix.
@@ -3595,10 +3610,10 @@ public class PGraphicsOpenGL extends PGraphics {
       throw new RuntimeException("Cannot call endCamera() "
           + "without first calling beginCamera()");
     }
-    
+
     camera.set(modelview);
     cameraInv.set(modelviewInv);
-    
+
     // all done
     manipulatingCamera = false;
   }
@@ -3642,18 +3657,18 @@ public class PGraphicsOpenGL extends PGraphics {
     camera(cameraX, cameraY, cameraZ, cameraX, cameraY, 0, 0, 1, 0);
   }
 
-  
+
   /**
    * More flexible method for dealing with camera().
    * 

* The actual call is like gluLookat. Here's the real skinny on what does * what: - * + * *

    * camera(); or
    * camera(ex, ey, ez, cx, cy, cz, ux, uy, uz);
    * 
- * + * * do not need to be called from with beginCamera();/endCamera(); That's * because they always apply to the camera transformation, and they always * totally replace it. That means that any coordinate transforms done before @@ -3667,45 +3682,45 @@ public class PGraphicsOpenGL extends PGraphics { * any coordinate system transforms that occur before them in draw(), but they * will not automatically wipe out the camera transform. This means that they * should be at the top of draw(). It also means that the following: - * + * *
    * beginCamera();
    * rotateY(PI / 8);
    * endCamera();
    * 
- * + * * will result in a camera that spins without stopping. If you want to just * rotate a small constant amount, try this: - * + * *
    * beginCamera();
    * camera(); // sets up the default view
    * rotateY(PI / 8);
    * endCamera();
    * 
- * + * * That will rotate a little off of the default view. Note that this is * entirely equivalent to - * + * *
    * camera(); // sets up the default view
    * beginCamera();
    * rotateY(PI / 8);
    * endCamera();
    * 
- * + * * because camera() doesn't care whether or not it's inside a begin/end * clause. Basically it's safe to use camera() or camera(ex, ey, ez, cx, cy, * cz, ux, uy, uz) as naked calls because they do all the matrix resetting * automatically. */ - public void camera(float eyeX, float eyeY, float eyeZ, - float centerX, float centerY, float centerZ, + public void camera(float eyeX, float eyeY, float eyeZ, + float centerX, float centerY, float centerZ, float upX, float upY, float upZ) { if (hints[DISABLE_TRANSFORM_CACHE]) { - flush(); + flush(); } - + // Calculating Z vector float z0 = eyeX - centerX; float z1 = eyeY - centerY; @@ -3720,7 +3735,7 @@ public class PGraphicsOpenGL extends PGraphics { cameraEyeY = eyeY; cameraEyeZ = eyeZ; cameraDepth = mag; - + // Calculating Y vector float y0 = upX; float y1 = upY; @@ -3756,35 +3771,35 @@ public class PGraphicsOpenGL extends PGraphics { y0, y1, y2, 0, z0, z1, z2, 0, 0, 0, 0, 1); - + float tx = -eyeX; float ty = -eyeY; float tz = -eyeZ; modelview.translate(tx, ty, tz); modelviewInv.set(modelview); - modelviewInv.invert(); - + modelviewInv.invert(); + camera.set(modelview); cameraInv.set(modelviewInv); - + calcProjmodelview(); } - - + + /** * Print the current camera matrix. */ public void printCamera() { camera.print(); } - - + + ////////////////////////////////////////////////////////////// // PROJECTION - - + + /** * Calls ortho() with the proper parameters for Processing's standard * orthographic projection. @@ -3793,17 +3808,17 @@ public class PGraphicsOpenGL extends PGraphics { ortho(0, width, 0, height, -500, 500); } - + /** * Calls ortho() with the specified size of the viewing volume along * the X and Z directions. - */ - public void ortho(float left, float right, + */ + public void ortho(float left, float right, float bottom, float top) { ortho(left, right, bottom, top, -500, 500); - } - - + } + + /** * Sets orthographic projection. The left, right, bottom and top * values refer to the top left corner of the screen, not to the @@ -3811,23 +3826,23 @@ public class PGraphicsOpenGL extends PGraphics { * it relative to the camera is not very intuitive if we think * of the perspective function, which is also independent of the * camera position. - * + * */ - public void ortho(float left, float right, + public void ortho(float left, float right, float bottom, float top, float near, float far) { // Flushing geometry with a different perspective configuration. flush(); - + left -= width/2; right -= width/2; - + bottom -= height/2; top -= height/2; - + near += cameraDepth; far += cameraDepth; - + float x = 2.0f / (right - left); float y = 2.0f / (top - bottom); float z = -2.0f / (far - near); @@ -3835,7 +3850,7 @@ public class PGraphicsOpenGL extends PGraphics { float tx = -(right + left) / (right - left); float ty = -(top + bottom) / (top - bottom); float tz = -(far + near) / (far - near); - + // The minus sign is needed to invert the Y axis. projection.set(x, 0, 0, tx, 0, -y, 0, ty, @@ -3843,7 +3858,7 @@ public class PGraphicsOpenGL extends PGraphics { 0, 0, 0, 1); } - + /** * Calls perspective() with Processing's standard coordinate projection. *

@@ -3868,7 +3883,7 @@ public class PGraphicsOpenGL extends PGraphics { perspective(cameraFOV, cameraAspect, cameraNear, cameraFar); } - + /** * Similar to gluPerspective(). Implementation based on Mesa's glu.c */ @@ -3880,7 +3895,7 @@ public class PGraphicsOpenGL extends PGraphics { frustum(xmin, xmax, ymin, ymax, zNear, zFar); } - + /** * Same as glFrustum(), except that it wipes out (rather than multiplies * against) the current perspective matrix. @@ -3891,7 +3906,7 @@ public class PGraphicsOpenGL extends PGraphics { float znear, float zfar) { // Flushing geometry with a different perspective configuration. flush(); - + float temp, temp2, temp3, temp4; temp = 2.0f * znear; temp2 = right - left; @@ -3903,33 +3918,33 @@ public class PGraphicsOpenGL extends PGraphics { 0, -temp / temp3, (top + bottom) / temp3, 0, 0, 0, (-zfar - znear) / temp4, (-temp * zfar) / temp4, 0, 0, -1, 1); - - calcProjmodelview(); + + calcProjmodelview(); } - + /** * Print the current projection matrix. */ public void printProjection() { projection.print(); - } - - + } + + ////////////////////////////////////////////////////////////// // SCREEN AND MODEL COORDS - + public float screenX(float x, float y) { return screenX(x, y, 0); } - + public float screenY(float x, float y) { return screenY(x, y, 0); } - + public float screenX(float x, float y, float z) { float ax = modelview.m00 * x + modelview.m01 * y + modelview.m02 * z + modelview.m03; @@ -3939,7 +3954,7 @@ public class PGraphicsOpenGL extends PGraphics { float ox = projection.m00 * ax + projection.m01 * ay + projection.m02 * az + projection.m03 * aw; float ow = projection.m30 * ax + projection.m31 * ay + projection.m32 * az + projection.m33 * aw; - + if (ow != 0) { ox /= ow; } @@ -3947,34 +3962,34 @@ public class PGraphicsOpenGL extends PGraphics { return sx; } - - public float screenY(float x, float y, float z) { + + public float screenY(float x, float y, float z) { float ax = modelview.m00 * x + modelview.m01 * y + modelview.m02 * z + modelview.m03; float ay = modelview.m10 * x + modelview.m11 * y + modelview.m12 * z + modelview.m13; float az = modelview.m20 * x + modelview.m21 * y + modelview.m22 * z + modelview.m23; float aw = modelview.m30 * x + modelview.m31 * y + modelview.m32 * z + modelview.m33; - + float oy = projection.m10 * ax + projection.m11 * ay + projection.m12 * az + projection.m13 * aw; float ow = projection.m30 * ax + projection.m31 * ay + projection.m32 * az + projection.m33 * aw; - + if (ow != 0) { oy /= ow; - } + } float sy = height * (1 + oy) / 2.0f; // Turning value upside down because of Processing's inverted Y axis. sy = height - sy; return sy; } - - public float screenZ(float x, float y, float z) { + + public float screenZ(float x, float y, float z) { float ax = modelview.m00 * x + modelview.m01 * y + modelview.m02 * z + modelview.m03; float ay = modelview.m10 * x + modelview.m11 * y + modelview.m12 * z + modelview.m13; float az = modelview.m20 * x + modelview.m21 * y + modelview.m22 * z + modelview.m23; float aw = modelview.m30 * x + modelview.m31 * y + modelview.m32 * z + modelview.m33; - + float oz = projection.m20 * ax + projection.m21 * ay + projection.m22 * az + projection.m23 * aw; - float ow = projection.m30 * ax + projection.m31 * ay + projection.m32 * az + projection.m33 * aw; + float ow = projection.m30 * ax + projection.m31 * ay + projection.m32 * az + projection.m33 * aw; if (ow != 0) { oz /= ow; @@ -3983,39 +3998,39 @@ public class PGraphicsOpenGL extends PGraphics { return sz; } - + public float modelX(float x, float y, float z) { float ax = modelview.m00 * x + modelview.m01 * y + modelview.m02 * z + modelview.m03; float ay = modelview.m10 * x + modelview.m11 * y + modelview.m12 * z + modelview.m13; float az = modelview.m20 * x + modelview.m21 * y + modelview.m22 * z + modelview.m23; float aw = modelview.m30 * x + modelview.m31 * y + modelview.m32 * z + modelview.m33; - + float ox = cameraInv.m00 * ax + cameraInv.m01 * ay + cameraInv.m02 * az + cameraInv.m03 * aw; - float ow = cameraInv.m30 * ax + cameraInv.m31 * ay + cameraInv.m32 * az + cameraInv.m33 * aw; - + float ow = cameraInv.m30 * ax + cameraInv.m31 * ay + cameraInv.m32 * az + cameraInv.m33 * aw; + return (ow != 0) ? ox / ow : ox; } - + public float modelY(float x, float y, float z) { float ax = modelview.m00 * x + modelview.m01 * y + modelview.m02 * z + modelview.m03; float ay = modelview.m10 * x + modelview.m11 * y + modelview.m12 * z + modelview.m13; float az = modelview.m20 * x + modelview.m21 * y + modelview.m22 * z + modelview.m23; float aw = modelview.m30 * x + modelview.m31 * y + modelview.m32 * z + modelview.m33; - + float oy = cameraInv.m10 * ax + cameraInv.m11 * ay + cameraInv.m12 * az + cameraInv.m13 * aw; float ow = cameraInv.m30 * ax + cameraInv.m31 * ay + cameraInv.m32 * az + cameraInv.m33 * aw; return (ow != 0) ? oy / ow : oy; } - + public float modelZ(float x, float y, float z) { float ax = modelview.m00 * x + modelview.m01 * y + modelview.m02 * z + modelview.m03; float ay = modelview.m10 * x + modelview.m11 * y + modelview.m12 * z + modelview.m13; float az = modelview.m20 * x + modelview.m21 * y + modelview.m22 * z + modelview.m23; float aw = modelview.m30 * x + modelview.m31 * y + modelview.m32 * z + modelview.m33; - + float oz = cameraInv.m20 * ax + cameraInv.m21 * ay + cameraInv.m22 * az + cameraInv.m23 * aw; float ow = cameraInv.m30 * ax + cameraInv.m31 * ay + cameraInv.m32 * az + cameraInv.m33 * aw; @@ -4029,7 +4044,7 @@ public class PGraphicsOpenGL extends PGraphics { // public void style(PStyle) // public PStyle getStyle() // public void getStyle(PStyle) - + ////////////////////////////////////////////////////////////// // COLOR MODE @@ -4055,21 +4070,21 @@ public class PGraphicsOpenGL extends PGraphics { // STROKE CAP/JOIN/WEIGHT - + public void strokeWeight(float weight) { this.strokeWeight = weight; } - + public void strokeJoin(int join) { this.strokeJoin = join; } - + public void strokeCap(int cap) { this.strokeCap = cap; } - + ////////////////////////////////////////////////////////////// @@ -4084,9 +4099,9 @@ public class PGraphicsOpenGL extends PGraphics { // default ambient color when the user doesn't specify // it explicitly. ambientFromCalc(); - } - + } + ////////////////////////////////////////////////////////////// // LIGHTING @@ -4094,7 +4109,7 @@ public class PGraphicsOpenGL extends PGraphics { /** * Sets up an ambient and directional light using OpenGL. API taken from * PGraphics3D. - * + * *

    * The Lighting Skinny:
    * The way lighting works is complicated enough that it's worth
@@ -4202,11 +4217,11 @@ public class PGraphicsOpenGL extends PGraphics {
 
     ambientLight(colorModeX * 0.5f, colorModeY * 0.5f, colorModeZ * 0.5f);
     directionalLight(colorModeX * 0.5f, colorModeY * 0.5f, colorModeZ * 0.5f, 0, 0, -1);
-    
+
     colorMode = colorModeSaved;
   }
 
-  
+
   /**
    * Disables lighting.
    */
@@ -4215,7 +4230,7 @@ public class PGraphicsOpenGL extends PGraphics {
     lightCount = 0;
   }
 
-  
+
   /**
    * Add an ambient light based on the current color mode.
    */
@@ -4223,7 +4238,7 @@ public class PGraphicsOpenGL extends PGraphics {
     ambientLight(r, g, b, 0, 0, 0);
   }
 
-  
+
   /**
    * Add an ambient light based on the current color mode. This version includes
    * an (x, y, z) position for situations where the falloff distance is used.
@@ -4233,102 +4248,102 @@ public class PGraphicsOpenGL extends PGraphics {
     if (lightCount == PGL.MAX_LIGHTS) {
       throw new RuntimeException("can only create " + PGL.MAX_LIGHTS + " lights");
     }
-    
+
     lightType[lightCount] = AMBIENT;
-    
+
     lightPosition(lightCount, x, y, z, false);
     lightNormal(lightCount, 0, 0, 0);
-        
+
     lightAmbient(lightCount, r, g, b);
     noLightDiffuse(lightCount);
     noLightSpecular(lightCount);
     noLightSpot(lightCount);
-    lightFalloff(lightCount, currentLightFalloffConstant, 
-                             currentLightFalloffLinear, 
+    lightFalloff(lightCount, currentLightFalloffConstant,
+                             currentLightFalloffLinear,
                              currentLightFalloffQuadratic);
-    
+
     lightCount++;
   }
-  
 
-  public void directionalLight(float r, float g, float b, 
+
+  public void directionalLight(float r, float g, float b,
                                float dx, float dy, float dz) {
     enableLighting();
     if (lightCount == PGL.MAX_LIGHTS) {
       throw new RuntimeException("can only create " + PGL.MAX_LIGHTS + " lights");
     }
-    
+
     lightType[lightCount] = DIRECTIONAL;
 
     lightPosition(lightCount, 0, 0, 0, true);
     lightNormal(lightCount, dx, dy, dz);
-        
+
     noLightAmbient(lightCount);
     lightDiffuse(lightCount, r, g, b);
-    lightSpecular(lightCount, currentLightSpecular[0], 
-                              currentLightSpecular[1], 
-                              currentLightSpecular[2]);        
+    lightSpecular(lightCount, currentLightSpecular[0],
+                              currentLightSpecular[1],
+                              currentLightSpecular[2]);
     noLightSpot(lightCount);
     noLightFalloff(lightCount);
 
     lightCount++;
   }
 
-  
-  public void pointLight(float r, float g, float b, 
+
+  public void pointLight(float r, float g, float b,
                          float x, float y, float z) {
-    enableLighting();   
+    enableLighting();
     if (lightCount == PGL.MAX_LIGHTS) {
       throw new RuntimeException("can only create " + PGL.MAX_LIGHTS + " lights");
     }
-    
+
     lightType[lightCount] = POINT;
 
     lightPosition(lightCount, x, y, z, false);
     lightNormal(lightCount, 0, 0, 0);
-    
+
     noLightAmbient(lightCount);
     lightDiffuse(lightCount, r, g, b);
-    lightSpecular(lightCount, currentLightSpecular[0], 
-                              currentLightSpecular[1], 
+    lightSpecular(lightCount, currentLightSpecular[0],
+                              currentLightSpecular[1],
                               currentLightSpecular[2]);
     noLightSpot(lightCount);
-    lightFalloff(lightCount, currentLightFalloffConstant, 
-                             currentLightFalloffLinear, 
+    lightFalloff(lightCount, currentLightFalloffConstant,
+                             currentLightFalloffLinear,
                              currentLightFalloffQuadratic);
-    
+
     lightCount++;
   }
 
-  
-  public void spotLight(float r, float g, float b, 
+
+  public void spotLight(float r, float g, float b,
                         float x, float y, float z,
-                        float dx, float dy, float dz, 
+                        float dx, float dy, float dz,
                         float angle, float concentration) {
-    enableLighting();  
+    enableLighting();
     if (lightCount == PGL.MAX_LIGHTS) {
       throw new RuntimeException("can only create " + PGL.MAX_LIGHTS + " lights");
     }
-    
+
     lightType[lightCount] = SPOT;
 
     lightPosition(lightCount, x, y, z, false);
     lightNormal(lightCount, dx, dy, dz);
-        
+
     noLightAmbient(lightCount);
     lightDiffuse(lightCount, r, g, b);
-    lightSpecular(lightCount, currentLightSpecular[0], 
-                              currentLightSpecular[1], 
+    lightSpecular(lightCount, currentLightSpecular[0],
+                              currentLightSpecular[1],
                               currentLightSpecular[2]);
-    lightSpot(lightCount, angle, concentration);    
-    lightFalloff(lightCount, currentLightFalloffConstant, 
-                             currentLightFalloffLinear, 
-                             currentLightFalloffQuadratic);    
-    
+    lightSpot(lightCount, angle, concentration);
+    lightFalloff(lightCount, currentLightFalloffConstant,
+                             currentLightFalloffLinear,
+                             currentLightFalloffQuadratic);
+
     lightCount++;
   }
 
-  
+
   /**
    * Set the light falloff rates for the last light that was created. Default is
    * lightFalloff(1, 0, 0).
@@ -4339,7 +4354,7 @@ public class PGraphicsOpenGL extends PGraphics {
     currentLightFalloffQuadratic = quadratic;
   }
 
-  
+
   /**
    * Set the specular color of the last light created.
    */
@@ -4350,54 +4365,54 @@ public class PGraphicsOpenGL extends PGraphics {
     currentLightSpecular[2] = calcB;
   }
 
-  
+
   protected void enableLighting() {
-    if (!lights) {      
-      flush(); // Flushing non-lit geometry.      
+    if (!lights) {
+      flush(); // Flushing non-lit geometry.
       lights = true;
     }
   }
-  
+
 
   protected void disableLighting() {
-    if (lights) {      
-      flush(); // Flushing lit geometry.      
+    if (lights) {
+      flush(); // Flushing lit geometry.
       lights = false;
     }
-  }  
-  
-  
+  }
+
+
   protected void lightPosition(int num, float x, float y, float z, boolean dir) {
     lightPosition[4 * num + 0] = x * modelview.m00 + y * modelview.m01 + z * modelview.m02 + modelview.m03;
     lightPosition[4 * num + 1] = x * modelview.m10 + y * modelview.m11 + z * modelview.m12 + modelview.m13;
     lightPosition[4 * num + 2] = x * modelview.m20 + y * modelview.m21 + z * modelview.m22 + modelview.m23;
-    
+
     // Used to inicate if the light is directional or not.
     lightPosition[4 * num + 3] = dir ? 1: 0;
-  }  
+  }
+
 
-  
   protected void lightNormal(int num, float dx, float dy, float dz) {
     // Applying normal matrix to the light direction vector, which is the transpose of the inverse of the
     // modelview.
     float nx = dx * modelviewInv.m00 + dy * modelviewInv.m10 + dz * modelviewInv.m20;
     float ny = dx * modelviewInv.m01 + dy * modelviewInv.m11 + dz * modelviewInv.m21;
-    float nz = dx * modelviewInv.m02 + dy * modelviewInv.m12 + dz * modelviewInv.m22;    
-    
+    float nz = dx * modelviewInv.m02 + dy * modelviewInv.m12 + dz * modelviewInv.m22;
+
     float invn = 1.0f / PApplet.dist(0, 0, 0, nx, ny, nz);
     lightNormal[3 * num + 0] = invn * nx;
     lightNormal[3 * num + 1] = invn * ny;
     lightNormal[3 * num + 2] = invn * nz;
   }
-  
-  
-  protected void lightAmbient(int num, float r, float g, float b) {       
+
+
+  protected void lightAmbient(int num, float r, float g, float b) {
     colorCalc(r, g, b);
     lightAmbient[3 * num + 0] = calcR;
     lightAmbient[3 * num + 1] = calcG;
     lightAmbient[3 * num + 2] = calcB;
   }
-  
+
 
   protected void noLightAmbient(int num) {
     lightAmbient[3 * num + 0] = 0;
@@ -4405,14 +4420,14 @@ public class PGraphicsOpenGL extends PGraphics {
     lightAmbient[3 * num + 2] = 0;
   }
 
-  
+
   protected void lightDiffuse(int num, float r, float g, float b) {
     colorCalc(r, g, b);
     lightDiffuse[3 * num + 0] = calcR;
     lightDiffuse[3 * num + 1] = calcG;
     lightDiffuse[3 * num + 2] = calcB;
   }
-  
+
 
   protected void noLightDiffuse(int num) {
     lightDiffuse[3 * num + 0] = 0;
@@ -4420,52 +4435,52 @@ public class PGraphicsOpenGL extends PGraphics {
     lightDiffuse[3 * num + 2] = 0;
   }
 
-  
+
   protected void lightSpecular(int num, float r, float g, float b) {
     lightSpecular[3 * num + 0] = r;
     lightSpecular[3 * num + 1] = g;
     lightSpecular[3 * num + 2] = b;
   }
 
-  
+
   protected void noLightSpecular(int num) {
     lightSpecular[3 * num + 0] = 0;
     lightSpecular[3 * num + 1] = 0;
     lightSpecular[3 * num + 2] = 0;
-  }  
-  
-  
+  }
+
+
   protected void lightFalloff(int num, float c0, float c1, float c2) {
     lightFalloffCoefficients[3 * num + 0] = c0;
     lightFalloffCoefficients[3 * num + 1] = c1;
     lightFalloffCoefficients[3 * num + 2] = c2;
   }
 
-  
+
   protected void noLightFalloff(int num) {
     lightFalloffCoefficients[3 * num + 0] = 1;
     lightFalloffCoefficients[3 * num + 1] = 0;
     lightFalloffCoefficients[3 * num + 2] = 0;
   }
-  
-  
+
+
   protected void lightSpot(int num, float angle, float exponent) {
     lightSpotParameters[2 * num + 0] = Math.max(0, PApplet.cos(angle));
     lightSpotParameters[2 * num + 1] = exponent;
   }
-  
-  
+
+
   protected void noLightSpot(int num) {
     lightSpotParameters[2 * num + 0] = 0;
     lightSpotParameters[2 * num + 1] = 0;
   }
-  
-  
+
+
   //////////////////////////////////////////////////////////////
 
   // BACKGROUND
 
-  
+
   protected void backgroundImpl(PImage image) {
     backgroundImpl();
     set(0, 0, image);
@@ -4474,28 +4489,28 @@ public class PGraphicsOpenGL extends PGraphics {
     }
   }
 
-  
+
   protected void backgroundImpl() {
-    tessGeo.clear();  
+    tessGeo.clear();
     texCache.clear();
-    
+
     pgl.glDepthMask(true);
     pgl.glClearColor(0, 0, 0, 0);
-    pgl.glClear(PGL.GL_DEPTH_BUFFER_BIT);    
+    pgl.glClear(PGL.GL_DEPTH_BUFFER_BIT);
     if (hints[DISABLE_DEPTH_MASK]) {
       pgl.glDepthMask(false);
     } else {
       pgl.glDepthMask(true);
-    }   
-    
+    }
+
     pgl.glClearColor(backgroundR, backgroundG, backgroundB, 1);
     pgl.glClear(PGL.GL_COLOR_BUFFER_BIT);
     if (0 < parent.frameCount) {
       clearColorBuffer = true;
     }
-  }  
-  
-  
+  }
+
+
   //////////////////////////////////////////////////////////////
 
   // COLOR MODE
@@ -4534,7 +4549,7 @@ public class PGraphicsOpenGL extends PGraphics {
   // WARNINGS and EXCEPTIONS
 
   // showWarning() and showException() available from PGraphics.
-  
+
   /**
    * Report on anything from glError().
    * Don't use this inside glBegin/glEnd otherwise it'll
@@ -4550,8 +4565,8 @@ public class PGraphicsOpenGL extends PGraphics {
       }
     }
   }
-  
-  
+
+
   //////////////////////////////////////////////////////////////
 
   // RENDERER SUPPORT QUERIES
@@ -4559,28 +4574,28 @@ public class PGraphicsOpenGL extends PGraphics {
   // public boolean displayable()
 
   // public boolean dimensional() // from P3D
-  
-  
+
+
   /**
    * Return true if this renderer supports 2D drawing. Defaults to true.
    */
   public boolean is2D() {
     return true;
   }
-  
+
 
   /**
    * Return true if this renderer supports 2D drawing. Defaults to false.
    */
   public boolean is3D() {
     return true;
-  }  
+  }
+
 
-  
   public boolean isGL() {
     return true;
-  }  
-  
+  }
+
 
   //////////////////////////////////////////////////////////////
 
@@ -4590,190 +4605,190 @@ 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() {
     if (!setgetPixels) {
-      // Draws any remaining geometry in case the user is still not 
+      // Draws any remaining geometry in case the user is still not
       // setting/getting new pixels.
-      flush();         
+      flush();
     }
-    
+
     if ((pixels == null) || (pixels.length != width * height)) {
-      pixels = new int[width * height];      
-      pixelBuffer = IntBuffer.wrap(pixels);      
+      pixels = new int[width * height];
+      pixelBuffer = IntBuffer.wrap(pixels);
     }
-    
+
     if (!setgetPixels) {
-      beginPixelsOp(OP_READ);        
+      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);      
-      
+      endPixelsOp();
+
+      PGL.nativeToJavaARGB(pixels, width, height);
+
       if (primarySurface) {
         loadTextureImpl(POINT);
         pixelsToTexture();
       }
     }
   }
-  
+
 
   //////////////////////////////////////////////////////////////
 
   // GET/SET PIXELS
-  
-  
+
+
   public int get(int x, int y) {
     loadPixels();
     setgetPixels = true;
     return super.get(x, y);
   }
 
-  
+
   protected PImage getImpl(int x, int y, int w, int h) {
     loadPixels();
     setgetPixels = true;
     return super.getImpl(x, y, w, h);
   }
 
-  
+
   public void set(int x, int y, int argb) {
     loadPixels();
-    setgetPixels = true;  
+    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) {
-      loadTextureImpl(POINT);      
-      loadPixels();      
+      loadTextureImpl(POINT);
+      loadPixels();
       pixelsToTexture();
     }
   }
-    
-  
+
+
   // Draws wherever it is in the screen texture right now to the screen.
   public void updateTexture() {
-    flush();    
+    flush();
     beginPixelsOp(OP_WRITE);
-    drawTexture();    
-    endPixelsOp();   
+    drawTexture();
+    endPixelsOp();
   }
-  
-  
+
+
   protected void loadTextureImpl(int sampling) {
     if (width == 0 || height == 0) return;
     if (texture == null || texture.contextIsOutdated()) {
       PTexture.Parameters params = PTexture.newParameters(ARGB, sampling);
-      texture = new PTexture(parent, width, height, params);      
+      texture = new PTexture(parent, width, height, params);
       texture.setFlippedY(true);
       this.setCache(pg, texture);
       this.setParams(pg, params);
     }
-  }   
-  
-  
+  }
+
+
   protected void drawTexture() {
-    pgl.drawTexture(texture.glTarget, texture.glID, 
+    pgl.drawTexture(texture.glTarget, texture.glID,
                     texture.glWidth, texture.glHeight,
                     0, 0, width, height);
   }
 
-  
+
   protected void drawTexture(int x, int y, int w, int h) {
-    pgl.drawTexture(texture.glTarget, texture.glID, 
+    pgl.drawTexture(texture.glTarget, texture.glID,
                     texture.glWidth, texture.glHeight,
                     x, y, x + w, y + h);
   }
-  
-  
-  protected void pixelsToTexture() {    
+
+
+  protected void pixelsToTexture() {
     texture.set(pixels);
   }
-  
-  
+
+
   protected void textureToPixels() {
     texture.get(pixels);
   }
-  
-  
+
+
   //////////////////////////////////////////////////////////////
 
   // IMAGE CONVERSION
-  
-  
+
+
   static public void nativeToJavaRGB(PImage image) {
     if (image.pixels != null) {
-      PGL.nativeToJavaRGB(image.pixels, image.width, image.height);  
-    }    
+      PGL.nativeToJavaRGB(image.pixels, image.width, image.height);
+    }
   }
 
 
   static public void nativeToJavaARGB(PImage image) {
     if (image.pixels != null) {
-      PGL.nativeToJavaARGB(image.pixels, image.width, image.height);  
-    }    
+      PGL.nativeToJavaARGB(image.pixels, image.width, image.height);
+    }
   }
-  
+
 
   static public void javaToNativeRGB(PImage image) {
     if (image.pixels != null) {
-      PGL.javaToNativeRGB(image.pixels, image.width, image.height);  
-    } 
-  }
-  
-  
-  static public void javaToNativeARGB(PImage image) {
-    if (image.pixels != null) {
-      PGL.javaToNativeARGB(image.pixels, image.width, image.height);  
-    } 
+      PGL.javaToNativeRGB(image.pixels, image.width, image.height);
+    }
   }
 
-  
+
+  static public void javaToNativeARGB(PImage image) {
+    if (image.pixels != null) {
+      PGL.javaToNativeARGB(image.pixels, image.width, image.height);
+    }
+  }
+
+
   //////////////////////////////////////////////////////////////
 
   // MASK
 
-  
+
   public void mask(int alpha[]) {
     PGraphics.showMethodWarning("mask");
   }
-  
+
 
   public void mask(PImage alpha) {
     PGraphics.showMethodWarning("mask");
   }
 
-  
+
   //////////////////////////////////////////////////////////////
 
   // FILTER
 
-  
+
   /**
    * This is really inefficient and not a good idea in OpenGL. Use get() and
    * set() with a smaller image area, or call the filter on an image instead,
@@ -4785,7 +4800,7 @@ public class PGraphicsOpenGL extends PGraphics {
     set(0, 0, temp);
   }
 
-  
+
   /**
    * This is really inefficient and not a good idea in OpenGL. Use get() and
    * set() with a smaller image area, or call the filter on an image instead,
@@ -4797,7 +4812,7 @@ public class PGraphicsOpenGL extends PGraphics {
     set(0, 0, temp);
   }
 
-  
+
   //////////////////////////////////////////////////////////////
 
   /**
@@ -4816,7 +4831,7 @@ public class PGraphicsOpenGL extends PGraphics {
   // int sx1, int sy1, int sx2, int sy2,
   // int dx1, int dy1, int dx2, int dy2)
 
-  
+
   //////////////////////////////////////////////////////////////
 
   // BLEND
@@ -4828,7 +4843,7 @@ public class PGraphicsOpenGL extends PGraphics {
   // set(dx, dy, PImage.blendColor(src.get(sx, sy), get(dx, dy), mode));
   // }
 
-  
+
   /**
    * Extremely slow and not optimized, should use GL methods instead. Currently
    * calls a beginPixels() on the whole canvas, then does the copy, then it
@@ -4851,7 +4866,7 @@ public class PGraphicsOpenGL extends PGraphics {
   // updatePixels();
   // }
 
-  
+
   /**
    * Allows to set custom blend modes for the entire scene, using openGL.
    * Reference article about blending modes:
@@ -4862,13 +4877,13 @@ public class PGraphicsOpenGL extends PGraphics {
       // Flushing any remaining geometry that uses a different blending
       // mode.
       flush();
-    
+
       blendMode = mode;
       pgl.glEnable(PGL.GL_BLEND);
-      
+
       if (mode == REPLACE) {
-        if (blendEqSupported) { 
-          pgl.glBlendEquation(PGL.GL_FUNC_ADD);          
+        if (blendEqSupported) {
+          pgl.glBlendEquation(PGL.GL_FUNC_ADD);
         }
         pgl.glBlendFunc(PGL.GL_ONE, PGL.GL_ZERO);
       } else if (mode == BLEND) {
@@ -4887,7 +4902,7 @@ public class PGraphicsOpenGL extends PGraphics {
         }
         pgl.glBlendFunc(PGL.GL_ONE_MINUS_DST_COLOR, PGL.GL_ZERO);
       } else if (mode == LIGHTEST) {
-        if (blendEqSupported) { 
+        if (blendEqSupported) {
           pgl.glBlendEquation(PGL.GL_FUNC_MAX);
         } else {
           PGraphics.showWarning("This blend mode is not supported");
@@ -4900,7 +4915,7 @@ public class PGraphicsOpenGL extends PGraphics {
         } else {
           PGraphics.showWarning("This blend mode is not supported");
           return;
-        }        
+        }
         pgl.glBlendFunc(PGL.GL_SRC_ALPHA, PGL.GL_DST_ALPHA);
       } else if (mode == DIFFERENCE) {
         if (blendEqSupported) {
@@ -4908,7 +4923,7 @@ public class PGraphicsOpenGL extends PGraphics {
         } else {
           PGraphics.showWarning("This blend mode is not supported");
           return;
-        }        
+        }
         pgl.glBlendFunc(PGL.GL_ONE, PGL.GL_ONE);
       } else if (mode == EXCLUSION) {
         if (blendEqSupported) {
@@ -4925,14 +4940,14 @@ public class PGraphicsOpenGL extends PGraphics {
           pgl.glBlendEquation(PGL.GL_FUNC_ADD);
         }
         pgl.glBlendFunc(PGL.GL_ONE_MINUS_DST_COLOR, PGL.GL_ONE);
-      }  
+      }
       // HARD_LIGHT, SOFT_LIGHT, OVERLAY, DODGE, BURN modes cannot be implemented
       // in fixed-function pipeline because they require conditional blending and
       // non-linear blending equations.
     }
   }
 
-  
+
   protected void setDefaultBlend() {
     blendMode = BLEND;
     pgl.glEnable(PGL.GL_BLEND);
@@ -4941,83 +4956,83 @@ public class PGraphicsOpenGL extends PGraphics {
     }
     pgl.glBlendFunc(PGL.GL_SRC_ALPHA, PGL.GL_ONE_MINUS_SRC_ALPHA);
   }
-  
-  
+
+
   //////////////////////////////////////////////////////////////
 
   // SAVE
 
   // public void save(String filename) // PImage calls loadPixels()
 
-  
+
   //////////////////////////////////////////////////////////////
-  
-  // SHAPE I/O  
-  
-  
+
+  // SHAPE I/O
+
+
   protected String[] getSupportedShapeFormats() {
     return new String[] { "obj" };
   }
-    
-  
+
+
   protected PShape loadShape(String filename, Object params) {
     return null;
     //return new PShape3D(parent, filename, (PShape3D.Parameters)params);
   }
-  
-  
+
+
   protected PShape createShape(int size, Object params) {
     return null;
     //return new PShape3D(parent, size, (PShape3D.Parameters)params);
   }
-  
-  
-  //////////////////////////////////////////////////////////////
-  
-  // TEXTURE UTILS  
 
-  
+
+  //////////////////////////////////////////////////////////////
+
+  // TEXTURE UTILS
+
+
   /**
    * This utility method returns the texture associated to the renderer's.
    * drawing surface, making sure is updated to reflect the current contents
    * off the screen (or offscreen drawing surface).
-   */    
-  public PTexture getTexture() {    
+   */
+  public PTexture getTexture() {
     loadTexture();
     return texture;
   }
-  
-  
+
+
   /**
    * 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) {
     PTexture tex = (PTexture)img.getCache(pg);
     if (tex == null) {
-      tex = addTexture(img);      
-    } else {       
+      tex = addTexture(img);
+    } else {
       if (tex.contextIsOutdated()) {
         tex = addTexture(img);
       }
-      
+
       if (img.isModified()) {
         if (img.width != tex.width || img.height != tex.height) {
           tex.init(img.width, img.height);
         }
-        updateTexture(img, tex);        
+        updateTexture(img, tex);
       }
-            
+
       if (tex.hasBuffers()) {
         tex.bufferUpdate();
-      }      
+      }
     }
     return tex;
   }
 
-  
+
   /**
    * This utility method creates a texture for the provided image, and adds it
    * to the metadata cache of the image.
@@ -5028,73 +5043,73 @@ public class PGraphicsOpenGL extends PGraphics {
     if (params == null) {
       params = PTexture.newParameters();
       img.setParams(pg, params);
-    }    
-    PTexture tex = new PTexture(img.parent, img.width, img.height, params);    
-    img.loadPixels();    
+    }
+    PTexture tex = new PTexture(img.parent, img.width, img.height, params);
+    img.loadPixels();
     if (img.pixels != null) tex.set(img.pixels);
     img.setCache(pg, tex);
     return tex;
   }
-  
-  
+
+
   protected PImage wrapTexture(PTexture tex) {
     // We don't use the PImage(int width, int height, int mode) constructor to
     // avoid initializing the pixels array.
     PImage img = new PImage();
     img.parent = parent;
-    img.width = tex.width; 
+    img.width = tex.width;
     img.height = tex.height;
-    img.format = ARGB;    
+    img.format = ARGB;
     img.setCache(pg, tex);
     return img;
   }
-    
-  
-  protected void updateTexture(PImage img, PTexture tex) {    
+
+
+  protected void updateTexture(PImage img, PTexture tex) {
     if (tex != null) {
       int x = img.getModifiedX1();
       int y = img.getModifiedY1();
       int w = img.getModifiedX2() - x + 1;
-      int h = img.getModifiedY2() - y + 1;      
+      int h = img.getModifiedY2() - y + 1;
       tex.set(img.pixels, x, y, w, h, img.format);
     }
     img.setModified(false);
   }
-  
-  
+
+
   //////////////////////////////////////////////////////////////
 
   // RESIZE
 
-  
+
   public void resize(int wide, int high) {
     PGraphics.showMethodWarning("resize");
   }
-  
-  
+
+
   //////////////////////////////////////////////////////////////
-  
-  // INITIALIZATION ROUTINES    
-  
+
+  // INITIALIZATION ROUTINES
+
 
   protected void initPrimary() {
     if (pg != null) {
       releaseResources();
     }
-    
+
     pgl.initPrimarySurface(antialias);
     pg = this;
   }
-  
-  
+
+
   protected void initOffscreen() {
     // Getting the context and capabilities from the main renderer.
     pg = (PGraphicsOpenGL)parent.g;
     pgl.initOffscreenSurface(pg.pgl);
-    
+
     pgl.updateOffscreen(pg.pgl);
     loadTextureImpl(BILINEAR);
-        
+
     // In case of reinitialization (for example, when the smooth level
     // is changed), we make sure that all the OpenGL resources associated
     // to the surface are released by calling delete().
@@ -5104,81 +5119,81 @@ public class PGraphicsOpenGL extends PGraphics {
     if (offscreenFramebufferMultisample != null) {
       offscreenFramebufferMultisample.release();
     }
-    
+
     if (PGraphicsOpenGL.fboMultisampleSupported && 1 < antialias) {
-      offscreenFramebufferMultisample = new PFramebuffer(parent, texture.glWidth, texture.glHeight, antialias, 0, 
-                                                         depthBits, stencilBits, 
+      offscreenFramebufferMultisample = new PFramebuffer(parent, texture.glWidth, texture.glHeight, antialias, 0,
+                                                         depthBits, stencilBits,
                                                          depthBits == 24 && stencilBits == 8 && packedDepthStencilSupported, false);
-      
+
       offscreenFramebufferMultisample.clear();
       offscreenMultisample = true;
-      
+
       // The offscreen framebuffer where the multisampled image is finally drawn to doesn't
       // need depth and stencil buffers since they are part of the multisampled framebuffer.
-      offscreenFramebuffer = new PFramebuffer(parent, texture.glWidth, texture.glHeight, 1, 1, 
+      offscreenFramebuffer = new PFramebuffer(parent, texture.glWidth, texture.glHeight, 1, 1,
                                               0, 0,
                                               false, false);
-            
+
     } else {
       antialias = 0;
-      offscreenFramebuffer = new PFramebuffer(parent, texture.glWidth, texture.glHeight, 1, 1, 
+      offscreenFramebuffer = new PFramebuffer(parent, texture.glWidth, texture.glHeight, 1, 1,
                                               depthBits, stencilBits,
                                               depthBits == 24 && stencilBits == 8 && packedDepthStencilSupported, false);
       offscreenMultisample = false;
     }
-    
+
     offscreenFramebuffer.setColorBuffer(texture);
-    offscreenFramebuffer.clear(); 
+    offscreenFramebuffer.clear();
   }
 
-  
+
   protected void getGLParameters() {
-    OPENGL_VENDOR     = pgl.glGetString(PGL.GL_VENDOR);  
+    OPENGL_VENDOR     = pgl.glGetString(PGL.GL_VENDOR);
     OPENGL_RENDERER   = pgl.glGetString(PGL.GL_RENDERER);
-    OPENGL_VERSION    = pgl.glGetString(PGL.GL_VERSION);    
+    OPENGL_VERSION    = pgl.glGetString(PGL.GL_VERSION);
     OPENGL_EXTENSIONS = pgl.glGetString(PGL.GL_EXTENSIONS);
-    
+
     npotTexSupported            = -1 < OPENGL_EXTENSIONS.indexOf("texture_non_power_of_two");
     mipmapGeneration            = -1 < OPENGL_EXTENSIONS.indexOf("generate_mipmap");
     fboMultisampleSupported     = -1 < OPENGL_EXTENSIONS.indexOf("framebuffer_multisample");
-    packedDepthStencilSupported = -1 < OPENGL_EXTENSIONS.indexOf("packed_depth_stencil");   
-    
-    try {      
+    packedDepthStencilSupported = -1 < OPENGL_EXTENSIONS.indexOf("packed_depth_stencil");
+
+    try {
       pgl.glBlendEquation(PGL.GL_FUNC_ADD);
       blendEqSupported = true;
     } catch (UnsupportedOperationException e) {
       blendEqSupported = false;
     }
-    
+
     int temp[] = new int[2];
-    
-    pgl.glGetIntegerv(PGL.GL_MAX_TEXTURE_SIZE, temp, 0);    
-    maxTextureSize = temp[0];  
+
+    pgl.glGetIntegerv(PGL.GL_MAX_TEXTURE_SIZE, temp, 0);
+    maxTextureSize = temp[0];
 
     pgl.glGetIntegerv(PGL.GL_MAX_SAMPLES, temp, 0);
-    maxSamples = temp[0];    
-    
-    pgl.glGetIntegerv(PGL.GL_ALIASED_LINE_WIDTH_RANGE, temp, 0);    
+    maxSamples = temp[0];
+
+    pgl.glGetIntegerv(PGL.GL_ALIASED_LINE_WIDTH_RANGE, temp, 0);
     maxLineWidth = temp[1];
-    
+
     pgl.glGetIntegerv(PGL.GL_ALIASED_POINT_SIZE_RANGE, temp, 0);
-    maxPointSize = temp[1];        
-    
-    pgl.glGetIntegerv(PGL.GL_DEPTH_BITS, temp, 0);    
+    maxPointSize = temp[1];
+
+    pgl.glGetIntegerv(PGL.GL_DEPTH_BITS, temp, 0);
     depthBits = temp[0];
-    
-    pgl.glGetIntegerv(PGL.GL_STENCIL_BITS, temp, 0);    
+
+    pgl.glGetIntegerv(PGL.GL_STENCIL_BITS, temp, 0);
     stencilBits = temp[0];
-    
+
     glParamsRead = true;
   }
-  
-   
+
+
   //////////////////////////////////////////////////////////////
-  
+
   // SHADER HANDLING
 
-  
+
   public PShader loadShader(String vertFilename, String fragFilename, int kind) {
     if (kind == FILL_SHADER_SIMPLE) {
       return new FillShaderSimple(parent, vertFilename, fragFilename);
@@ -5190,15 +5205,15 @@ public class PGraphicsOpenGL extends PGraphics {
       return new FillShaderFull(parent, vertFilename, fragFilename);
     } else if (kind == LINE_SHADER) {
       return new LineShader(parent, vertFilename, fragFilename);
-    } else if (kind == POINT_SHADER) {      
+    } else if (kind == POINT_SHADER) {
       return new PointShader(parent, vertFilename, fragFilename);
     } else {
       PGraphics.showWarning("Wrong shader type");
       return null;
     }
   }
-  
-  
+
+
   public PShader loadShader(String fragFilename, int kind) {
     PShader shader;
     if (kind == FILL_SHADER_SIMPLE) {
@@ -5224,12 +5239,12 @@ public class PGraphicsOpenGL extends PGraphics {
       return null;
     }
     shader.setFragmentShader(fragFilename);
-    return shader;    
-  }  
-  
+    return shader;
+  }
+
 
   public void setShader(PShader shader, int kind) {
-    if (kind == FILL_SHADER_SIMPLE) {      
+    if (kind == FILL_SHADER_SIMPLE) {
       fillShaderSimple = (FillShaderSimple) shader;
     } else if (kind == FILL_SHADER_LIT) {
       fillShaderLit = (FillShaderLit) shader;
@@ -5239,67 +5254,67 @@ public class PGraphicsOpenGL extends PGraphics {
       fillShaderFull = (FillShaderFull) shader;
     } else if (kind == LINE_SHADER) {
       lineShader = (LineShader) shader;
-    } else if (kind == POINT_SHADER) {      
+    } else if (kind == POINT_SHADER) {
       pointShader = (PointShader) shader;
     } else {
       PGraphics.showWarning("Wrong shader type");
-    }    
+    }
   }
 
-  
+
   public void resetShader(int kind) {
     if (kind == FILL_SHADER_SIMPLE) {
       if (defFillShaderSimple == null) {
-        defFillShaderSimple = new FillShaderSimple(parent, defFillShaderVertSimpleURL, defFillShaderFragNoTexURL);       
-      }      
+        defFillShaderSimple = new FillShaderSimple(parent, defFillShaderVertSimpleURL, defFillShaderFragNoTexURL);
+      }
       fillShaderSimple = defFillShaderSimple;
     } else if (kind == FILL_SHADER_LIT) {
       if (defFillShaderLit == null) {
         defFillShaderLit = new FillShaderLit(parent, defFillShaderVertLitURL, defFillShaderFragNoTexURL);
-      }      
+      }
       fillShaderLit = defFillShaderLit;
     } else if (kind == FILL_SHADER_TEX) {
       if (defFillShaderTex == null) {
         defFillShaderTex = new FillShaderTex(parent, defFillShaderVertTexURL, defFillShaderFragTexURL);
-      }      
+      }
       fillShaderTex = defFillShaderTex;
     } else if (kind == FILL_SHADER_FULL) {
       if (defFillShaderFull == null) {
         defFillShaderFull = new FillShaderFull(parent, defFillShaderVertFullURL, defFillShaderFragTexURL);
-      }      
+      }
       fillShaderFull = defFillShaderFull;
     } else if (kind == LINE_SHADER) {
       if (defLineShader == null) {
-        defLineShader = new LineShader(parent, defLineShaderVertURL, defLineShaderFragURL);        
-      }      
+        defLineShader = new LineShader(parent, defLineShaderVertURL, defLineShaderFragURL);
+      }
       lineShader = defLineShader;
     } else if (kind == POINT_SHADER) {
       if (defPointShader == null) {
-        defPointShader = new PointShader(parent, defPointShaderVertURL, defPointShaderFragURL);        
-      }      
+        defPointShader = new PointShader(parent, defPointShaderVertURL, defPointShaderFragURL);
+      }
       pointShader = defPointShader;
     } else {
       PGraphics.showWarning("Wrong shader type");
-    }     
+    }
   }
-  
-  
-  protected FillShader getFillShader(boolean lit, boolean tex) {    
+
+
+  protected FillShader getFillShader(boolean lit, boolean tex) {
     FillShader shader;
     if (lit) {
       if (tex) {
         if (defFillShaderFull == null) {
           defFillShaderFull = new FillShaderFull(parent, defFillShaderVertFullURL, defFillShaderFragTexURL);
-        }         
+        }
         if (fillShaderFull == null) {
           fillShaderFull = defFillShaderFull;
         }
-        shader = fillShaderFull;  
+        shader = fillShaderFull;
       } else {
         if (defFillShaderLit == null) {
           defFillShaderLit = new FillShaderLit(parent, defFillShaderVertLitURL, defFillShaderFragNoTexURL);
         }
-        if (fillShaderLit == null) { 
+        if (fillShaderLit == null) {
           fillShaderLit = defFillShaderLit;
         }
         shader = fillShaderLit;
@@ -5308,32 +5323,32 @@ public class PGraphicsOpenGL extends PGraphics {
       if (tex) {
         if (defFillShaderTex == null) {
           defFillShaderTex = new FillShaderTex(parent, defFillShaderVertTexURL, defFillShaderFragTexURL);
-        }        
+        }
         if (fillShaderTex == null) {
           fillShaderTex = defFillShaderTex;
         }
         shader = fillShaderTex;
       } else {
         if (defFillShaderSimple == null) {
-          defFillShaderSimple = new FillShaderSimple(parent, defFillShaderVertSimpleURL, defFillShaderFragNoTexURL);            
-        }          
+          defFillShaderSimple = new FillShaderSimple(parent, defFillShaderVertSimpleURL, defFillShaderFragNoTexURL);
+        }
         if (fillShaderSimple == null) {
           fillShaderSimple = defFillShaderSimple;
         }
         shader = fillShaderSimple;
-      }      
-    }    
+      }
+    }
     shader.setRenderer(this);
     shader.loadAttributes();
-    shader.loadUniforms();    
+    shader.loadUniforms();
     return shader;
   }
-  
-  
+
+
   protected LineShader getLineShader() {
     if (defLineShader == null) {
       defLineShader = new LineShader(parent, defLineShaderVertURL, defLineShaderFragURL);
-    }    
+    }
     if (lineShader == null) {
       lineShader = defLineShader;
     }
@@ -5343,138 +5358,138 @@ public class PGraphicsOpenGL extends PGraphics {
     return lineShader;
   }
 
-  
+
   protected PointShader getPointShader() {
     if (defPointShader == null) {
       defPointShader = new PointShader(parent, defPointShaderVertURL, defPointShaderFragURL);
-    }    
-    if (pointShader == null) {      
+    }
+    if (pointShader == null) {
       pointShader = defPointShader;
-    }    
+    }
     pointShader.setRenderer(this);
     pointShader.loadAttributes();
     pointShader.loadUniforms();
-    return pointShader;    
-  }  
-  
-  
+    return pointShader;
+  }
+
+
   protected class FillShader extends PShader {
     // We need a reference to the renderer since a shader might
     // be called by different renderers within a single application
     // (the one corresponding to the main surface, or other offscreen
     // renderers).
     protected PGraphicsOpenGL renderer;
-    
+
     public FillShader(PApplet parent) {
       super(parent);
     }
-    
+
     public FillShader(PApplet parent, String vertFilename, String fragFilename) {
       super(parent, vertFilename, fragFilename);
     }
-    
+
     public FillShader(PApplet parent, URL vertURL, URL fragURL) {
       super(parent, vertURL, fragURL);
-    }   
-    
+    }
+
     public void setRenderer(PGraphicsOpenGL pg) {
       this.renderer = pg;
-    }    
-    
-    public void loadAttributes() { }    
+    }
+
+    public void loadAttributes() { }
     public void loadUniforms() { }
-    
+
     public void setAttribute(int loc, int vboId, int size, int type, boolean normalized, int stride, int offset) {
       if (-1 < loc) {
         pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, vboId);
         pgl.glVertexAttribPointer(loc, size, type, normalized, stride, offset);
       }
     }
-    
-    public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { }    
+
+    public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { }
     public void setColorAttribute(int vboId, int size, int type, int stride, int offset) { }
     public void setNormalAttribute(int vboId, int size, int type, int stride, int offset) { }
     public void setAmbientAttribute(int vboId, int size, int type, int stride, int offset) { }
     public void setSpecularAttribute(int vboId, int size, int type, int stride, int offset) { }
     public void setEmissiveAttribute(int vboId, int size, int type, int stride, int offset) { }
     public void setShininessAttribute(int vboId, int size, int type, int stride, int offset) { }
-    public void setTexCoordAttribute(int vboId, int size, int type, int stride, int offset) { }    
+    public void setTexCoordAttribute(int vboId, int size, int type, int stride, int offset) { }
     public void setTexture(PTexture tex) { }
   }
-  
-  
+
+
   protected class FillShaderSimple extends FillShader {
     protected int projmodelviewMatrixLoc;
-    
+
     protected int inVertexLoc;
     protected int inColorLoc;
-    
+
     public FillShaderSimple(PApplet parent) {
       super(parent);
-    }    
+    }
 
     public FillShaderSimple(PApplet parent, String vertFilename, String fragFilename) {
       super(parent, vertFilename, fragFilename);
     }
-    
+
     public FillShaderSimple(PApplet parent, URL vertURL, URL fragURL) {
       super(parent, vertURL, fragURL);
-    }    
-    
+    }
+
     public void loadAttributes() {
       inVertexLoc = getAttribLocation("inVertex");
       inColorLoc = getAttribLocation("inColor");
     }
-    
-    public void loadUniforms() { 
+
+    public void loadUniforms() {
       projmodelviewMatrixLoc = getUniformLocation("projmodelviewMatrix");
     }
-    
-    public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { 
+
+    public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) {
       setAttribute(inVertexLoc, vboId, size, type, false, stride, offset);
-    } 
-    
-    public void setColorAttribute(int vboId, int size, int type, int stride, int offset) { 
-      setAttribute(inColorLoc, vboId, size, type, true, stride, offset); 
-    }  
-    
+    }
+
+    public void setColorAttribute(int vboId, int size, int type, int stride, int offset) {
+      setAttribute(inColorLoc, vboId, size, type, true, stride, offset);
+    }
+
     public void start() {
       super.start();
 
       if (-1 < inVertexLoc) pgl.glEnableVertexAttribArray(inVertexLoc);
       if (-1 < inColorLoc)  pgl.glEnableVertexAttribArray(inColorLoc);
-      
+
       if (renderer != null) {
         renderer.updateGLProjmodelview();
         set4x4MatUniform(projmodelviewMatrixLoc, renderer.glProjmodelview);
       }
     }
 
-    public void stop() {      
+    public void stop() {
       if (-1 < inVertexLoc) pgl.glDisableVertexAttribArray(inVertexLoc);
       if (-1 < inColorLoc)  pgl.glDisableVertexAttribArray(inColorLoc);
-      
+
       pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, 0);
-      
+
       super.stop();
     }
   }
 
-  
+
   protected class FillShaderLit extends FillShader {
     protected int projmodelviewMatrixLoc;
-    protected int modelviewMatrixLoc;    
+    protected int modelviewMatrixLoc;
     protected int normalMatrixLoc;
-    
-    protected int lightCountLoc;  
+
+    protected int lightCountLoc;
     protected int lightPositionLoc;
     protected int lightNormalLoc;
     protected int lightAmbientLoc;
     protected int lightDiffuseLoc;
     protected int lightSpecularLoc;
     protected int lightFalloffCoefficientsLoc;
-    protected int lightSpotParametersLoc;      
-    
+    protected int lightSpotParametersLoc;
+
     protected int inVertexLoc;
     protected int inColorLoc;
     protected int inNormalLoc;
@@ -5482,36 +5497,36 @@ public class PGraphicsOpenGL extends PGraphics {
     protected int inAmbientLoc;
     protected int inSpecularLoc;
     protected int inEmissiveLoc;
-    protected int inShineLoc;    
-    
+    protected int inShineLoc;
+
     public FillShaderLit(PApplet parent) {
       super(parent);
-    }      
-    
+    }
+
     public FillShaderLit(PApplet parent, String vertFilename, String fragFilename) {
       super(parent, vertFilename, fragFilename);
     }
-    
+
     public FillShaderLit(PApplet parent, URL vertURL, URL fragURL) {
       super(parent, vertURL, fragURL);
-    }    
-    
+    }
+
     public void loadAttributes() {
       inVertexLoc = getAttribLocation("inVertex");
-      inColorLoc = getAttribLocation("inColor");      
+      inColorLoc = getAttribLocation("inColor");
       inNormalLoc = getAttribLocation("inNormal");
-      
+
       inAmbientLoc = getAttribLocation("inAmbient");
       inSpecularLoc = getAttribLocation("inSpecular");
       inEmissiveLoc = getAttribLocation("inEmissive");
       inShineLoc = getAttribLocation("inShine");
     }
-    
-    public void loadUniforms() { 
-      projmodelviewMatrixLoc = getUniformLocation("projmodelviewMatrix");      
+
+    public void loadUniforms() {
+      projmodelviewMatrixLoc = getUniformLocation("projmodelviewMatrix");
       modelviewMatrixLoc = getUniformLocation("modelviewMatrix");
       normalMatrixLoc = getUniformLocation("normalMatrix");
-      
+
       lightCountLoc = getUniformLocation("lightCount");
       lightPositionLoc = getUniformLocation("lightPosition");
       lightNormalLoc = getUniformLocation("lightNormal");
@@ -5519,60 +5534,60 @@ public class PGraphicsOpenGL extends PGraphics {
       lightDiffuseLoc = getUniformLocation("lightDiffuse");
       lightSpecularLoc = getUniformLocation("lightSpecular");
       lightFalloffCoefficientsLoc = getUniformLocation("lightFalloffCoefficients");
-      lightSpotParametersLoc = getUniformLocation("lightSpotParameters");      
-    }    
-    
-    public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { 
-      setAttribute(inVertexLoc, vboId, size, type, false, stride, offset);
-    } 
-    
-    public void setColorAttribute(int vboId, int size, int type, int stride, int offset) { 
-      setAttribute(inColorLoc, vboId, size, type, true, stride, offset); 
-    } 
+      lightSpotParametersLoc = getUniformLocation("lightSpotParameters");
+    }
 
-    public void setNormalAttribute(int vboId, int size, int type, int stride, int offset) { 
+    public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) {
+      setAttribute(inVertexLoc, vboId, size, type, false, stride, offset);
+    }
+
+    public void setColorAttribute(int vboId, int size, int type, int stride, int offset) {
+      setAttribute(inColorLoc, vboId, size, type, true, stride, offset);
+    }
+
+    public void setNormalAttribute(int vboId, int size, int type, int stride, int offset) {
       setAttribute(inNormalLoc, vboId, size, type, false, stride, offset);
     }
-    
-    public void setAmbientAttribute(int vboId, int size, int type, int stride, int offset) { 
+
+    public void setAmbientAttribute(int vboId, int size, int type, int stride, int offset) {
       setAttribute(inAmbientLoc, vboId, size, type, true, stride, offset);
     }
-    
-    public void setSpecularAttribute(int vboId, int size, int type, int stride, int offset) { 
+
+    public void setSpecularAttribute(int vboId, int size, int type, int stride, int offset) {
       setAttribute(inSpecularLoc, vboId, size, type, true, stride, offset);
     }
-    
-    public void setEmissiveAttribute(int vboId, int size, int type, int stride, int offset) { 
+
+    public void setEmissiveAttribute(int vboId, int size, int type, int stride, int offset) {
       setAttribute(inEmissiveLoc, vboId, size, type, true, stride, offset);
     }
-    
-    public void setShininessAttribute(int vboId, int size, int type, int stride, int offset) { 
+
+    public void setShininessAttribute(int vboId, int size, int type, int stride, int offset) {
       setAttribute(inShineLoc, vboId, size, type, false, stride, offset);
-    }       
-    
+    }
+
     public void start() {
       super.start();
-      
+
       if (-1 < inVertexLoc) pgl.glEnableVertexAttribArray(inVertexLoc);
-      if (-1 < inColorLoc)  pgl.glEnableVertexAttribArray(inColorLoc);      
+      if (-1 < inColorLoc)  pgl.glEnableVertexAttribArray(inColorLoc);
       if (-1 < inNormalLoc) pgl.glEnableVertexAttribArray(inNormalLoc);
-      
+
       if (-1 < inAmbientLoc)  pgl.glEnableVertexAttribArray(inAmbientLoc);
       if (-1 < inSpecularLoc) pgl.glEnableVertexAttribArray(inSpecularLoc);
       if (-1 < inEmissiveLoc) pgl.glEnableVertexAttribArray(inEmissiveLoc);
-      if (-1 < inShineLoc)    pgl.glEnableVertexAttribArray(inShineLoc);         
-      
+      if (-1 < inShineLoc)    pgl.glEnableVertexAttribArray(inShineLoc);
+
       if (renderer != null) {
         renderer.updateGLProjmodelview();
         set4x4MatUniform(projmodelviewMatrixLoc, renderer.glProjmodelview);
-        
+
         renderer.updateGLModelview();
         set4x4MatUniform(modelviewMatrixLoc, renderer.glModelview);
-        
+
         renderer.updateGLNormal();
         set3x3MatUniform(normalMatrixLoc, renderer.glNormal);
-        
-        setIntUniform(lightCountLoc, renderer.lightCount);      
+
+        setIntUniform(lightCountLoc, renderer.lightCount);
         set4FloatVecUniform(lightPositionLoc, renderer.lightPosition);
         set3FloatVecUniform(lightNormalLoc, renderer.lightNormal);
         set3FloatVecUniform(lightAmbientLoc, renderer.lightAmbient);
@@ -5583,61 +5598,61 @@ public class PGraphicsOpenGL extends PGraphics {
       }
     }
 
-    public void stop() {                  
+    public void stop() {
       if (-1 < inVertexLoc) pgl.glDisableVertexAttribArray(inVertexLoc);
-      if (-1 < inColorLoc)  pgl.glDisableVertexAttribArray(inColorLoc);      
+      if (-1 < inColorLoc)  pgl.glDisableVertexAttribArray(inColorLoc);
       if (-1 < inNormalLoc) pgl.glDisableVertexAttribArray(inNormalLoc);
-      
+
       if (-1 < inAmbientLoc)  pgl.glDisableVertexAttribArray(inAmbientLoc);
       if (-1 < inSpecularLoc) pgl.glDisableVertexAttribArray(inSpecularLoc);
       if (-1 < inEmissiveLoc) pgl.glDisableVertexAttribArray(inEmissiveLoc);
-      if (-1 < inShineLoc)    pgl.glDisableVertexAttribArray(inShineLoc);        
-      
+      if (-1 < inShineLoc)    pgl.glDisableVertexAttribArray(inShineLoc);
+
       pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, 0);
-      
+
       super.stop();
-    }    
+    }
   }
-  
-  
+
+
   protected class FillShaderTex extends FillShaderSimple {
     protected int inTexcoordLoc;
-    
+
     protected int texcoordMatrixLoc;
     protected int texcoordOffsetLoc;
-    
+
     protected float[] tcmat;
-    
+
     public FillShaderTex(PApplet parent) {
       super(parent);
-    }        
-    
-    public FillShaderTex(PApplet parent, String vertFilename, String fragFilename) {
-      super(parent, vertFilename, fragFilename);      
     }
-    
+
+    public FillShaderTex(PApplet parent, String vertFilename, String fragFilename) {
+      super(parent, vertFilename, fragFilename);
+    }
+
     public FillShaderTex(PApplet parent, URL vertURL, URL fragURL) {
       super(parent, vertURL, fragURL);
-    }        
-    
+    }
+
     public void loadUniforms() {
       super.loadUniforms();
-      
+
       texcoordMatrixLoc = getUniformLocation("texcoordMatrix");
-      texcoordOffsetLoc = getUniformLocation("texcoordOffset");        
+      texcoordOffsetLoc = getUniformLocation("texcoordOffset");
     }
-    
+
     public void loadAttributes() {
       super.loadAttributes();
-      
+
       inTexcoordLoc = getAttribLocation("inTexcoord");
-    }    
-    
-    public void setTexCoordAttribute(int vboId, int size, int type, int stride, int offset) { 
+    }
+
+    public void setTexCoordAttribute(int vboId, int size, int type, int stride, int offset) {
       setAttribute(inTexcoordLoc, vboId, size, type, false, stride, offset);
-    }     
-    
-    public void setTexture(PTexture tex) { 
+    }
+
+    public void setTexture(PTexture tex) {
       float scaleu = 1;
       float scalev = 1;
       float dispu = 0;
@@ -5646,83 +5661,83 @@ public class PGraphicsOpenGL extends PGraphics {
       if (tex.isFlippedX()) {
         scaleu = -1;
         dispu = 1;
-      }      
-      
+      }
+
       if (tex.isFlippedY()) {
         scalev = -1;
         dispv = 1;
       }
 
-      scaleu *= tex.maxTexCoordU;      
+      scaleu *= tex.maxTexCoordU;
       dispu *= tex.maxTexCoordU;
       scalev *= tex.maxTexCoordV;
       dispv *= tex.maxTexCoordV;
 
       if (tcmat == null) {
         tcmat = new float[16];
-      }      
-      
+      }
+
       tcmat[0] = scaleu; tcmat[4] = 0;      tcmat[ 8] = 0; tcmat[12] = dispu;
       tcmat[1] = 0;      tcmat[5] = scalev; tcmat[ 9] = 0; tcmat[13] = dispv;
       tcmat[2] = 0;      tcmat[6] = 0;      tcmat[10] = 0; tcmat[14] = 0;
-      tcmat[3] = 0;      tcmat[7] = 0;      tcmat[11] = 0; tcmat[15] = 0;      
-      set4x4MatUniform(texcoordMatrixLoc, tcmat);      
-      
+      tcmat[3] = 0;      tcmat[7] = 0;      tcmat[11] = 0; tcmat[15] = 0;
+      set4x4MatUniform(texcoordMatrixLoc, tcmat);
+
       set2FloatUniform(texcoordOffsetLoc, 1.0f / tex.width, 1.0f / tex.height);
     }
-    
+
     public void start() {
       super.start();
-      
+
       if (-1 < inTexcoordLoc) pgl.glEnableVertexAttribArray(inTexcoordLoc);
-    }    
-    
-    public void stop() {      
+    }
+
+    public void stop() {
       if (-1 < inTexcoordLoc) pgl.glDisableVertexAttribArray(inTexcoordLoc);
-      
+
       super.stop();
-    }    
-  }  
-  
-  
+    }
+  }
+
+
   protected class FillShaderFull extends FillShaderLit {
     protected int inTexcoordLoc;
-    
+
     protected int texcoordMatrixLoc;
     protected int texcoordOffsetLoc;
-    
+
     protected float[] tcmat;
-    
+
     public FillShaderFull(PApplet parent) {
       super(parent);
-    } 
-    
+    }
+
     public FillShaderFull(PApplet parent, String vertFilename, String fragFilename) {
       super(parent, vertFilename, fragFilename);
     }
-    
+
     public FillShaderFull(PApplet parent, URL vertURL, URL fragURL) {
       super(parent, vertURL, fragURL);
-    }     
+    }
 
     public void loadUniforms() {
       super.loadUniforms();
-      
+
       texcoordMatrixLoc = getUniformLocation("texcoordMatrix");
-      texcoordOffsetLoc = getUniformLocation("texcoordOffset");      
+      texcoordOffsetLoc = getUniformLocation("texcoordOffset");
     }
-    
+
     public void loadAttributes() {
       super.loadAttributes();
-      
+
       inTexcoordLoc = getAttribLocation("inTexcoord");
-    }    
-    
-    public void setTexCoordAttribute(int vboId, int size, int type, int stride, int offset) { 
+    }
+
+    public void setTexCoordAttribute(int vboId, int size, int type, int stride, int offset) {
       setAttribute(inTexcoordLoc, vboId, size, type, false, stride, offset);
-    }     
-    
-    public void setTexture(PTexture tex) { 
+    }
+
+    public void setTexture(PTexture tex) {
       float scaleu = 1;
       float scalev = 1;
       float dispu = 0;
@@ -5731,48 +5746,48 @@ public class PGraphicsOpenGL extends PGraphics {
       if (tex.isFlippedX()) {
         scaleu = -1;
         dispu = 1;
-      }      
-      
+      }
+
       if (tex.isFlippedY()) {
         scalev = -1;
         dispv = 1;
       }
 
-      scaleu *= tex.maxTexCoordU;      
+      scaleu *= tex.maxTexCoordU;
       dispu *= tex.maxTexCoordU;
       scalev *= tex.maxTexCoordV;
       dispv *= tex.maxTexCoordV;
 
       if (tcmat == null) {
         tcmat = new float[16];
-      }      
-      
+      }
+
       tcmat[0] = scaleu; tcmat[4] = 0;      tcmat[ 8] = 0; tcmat[12] = dispu;
       tcmat[1] = 0;      tcmat[5] = scalev; tcmat[ 9] = 0; tcmat[13] = dispv;
       tcmat[2] = 0;      tcmat[6] = 0;      tcmat[10] = 0; tcmat[14] = 0;
-      tcmat[3] = 0;      tcmat[7] = 0;      tcmat[11] = 0; tcmat[15] = 0;      
-      set4x4MatUniform(texcoordMatrixLoc, tcmat);      
-      
+      tcmat[3] = 0;      tcmat[7] = 0;      tcmat[11] = 0; tcmat[15] = 0;
+      set4x4MatUniform(texcoordMatrixLoc, tcmat);
+
       set2FloatUniform(texcoordOffsetLoc, 1.0f / tex.width, 1.0f / tex.height);
     }
-    
+
     public void start() {
       super.start();
-      
+
       if (-1 < inTexcoordLoc) pgl.glEnableVertexAttribArray(inTexcoordLoc);
     }
-    
-    public void stop() {      
+
+    public void stop() {
       if (-1 < inTexcoordLoc) pgl.glDisableVertexAttribArray(inTexcoordLoc);
-      
+
       super.stop();
-    }    
-  } 
-  
-  
+    }
+  }
+
+
   protected class LineShader extends PShader {
     protected PGraphicsOpenGL renderer;
-    
+
     protected int projectionMatrixLoc;
     protected int modelviewMatrixLoc;
 
@@ -5782,147 +5797,147 @@ public class PGraphicsOpenGL extends PGraphics {
     protected int inVertexLoc;
     protected int inColorLoc;
     protected int inDirWidthLoc;
-    
+
     public LineShader(PApplet parent) {
       super(parent);
     }
-    
+
     public LineShader(PApplet parent, String vertFilename, String fragFilename) {
       super(parent, vertFilename, fragFilename);
     }
-    
+
     public LineShader(PApplet parent, URL vertURL, URL fragURL) {
       super(parent, vertURL, fragURL);
-    }       
-    
+    }
+
     public void setRenderer(PGraphicsOpenGL pg) {
       this.renderer = pg;
-    }      
-    
+    }
+
     public void loadAttributes() {
       inVertexLoc = getAttribLocation("inVertex");
       inColorLoc = getAttribLocation("inColor");
-      inDirWidthLoc = getAttribLocation("inDirWidth");      
-    } 
-    
-    public void loadUniforms() { 
-      projectionMatrixLoc = getUniformLocation("projectionMatrix");      
+      inDirWidthLoc = getAttribLocation("inDirWidth");
+    }
+
+    public void loadUniforms() {
+      projectionMatrixLoc = getUniformLocation("projectionMatrix");
       modelviewMatrixLoc = getUniformLocation("modelviewMatrix");
-      
+
       viewportLoc = getUniformLocation("viewport");
       perspectiveLoc = getUniformLocation("perspective");
     }
-    
+
     public void setAttribute(int loc, int vboId, int size, int type, boolean normalized, int stride, int offset) {
       pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, vboId);
-      pgl.glVertexAttribPointer(loc, size, type, normalized, stride, offset);       
+      pgl.glVertexAttribPointer(loc, size, type, normalized, stride, offset);
     }
-    
-    public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { 
-      setAttribute(inVertexLoc, vboId, size, type, false, stride, offset);
-    } 
-    
-    public void setColorAttribute(int vboId, int size, int type, int stride, int offset) { 
-      setAttribute(inColorLoc, vboId, size, type, true, stride, offset); 
-    }  
 
-    public void setDirWidthAttribute(int vboId, int size, int type, int stride, int offset) { 
-      setAttribute(inDirWidthLoc, vboId, size, type, false, stride, offset); 
+    public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) {
+      setAttribute(inVertexLoc, vboId, size, type, false, stride, offset);
     }
-    
+
+    public void setColorAttribute(int vboId, int size, int type, int stride, int offset) {
+      setAttribute(inColorLoc, vboId, size, type, true, stride, offset);
+    }
+
+    public void setDirWidthAttribute(int vboId, int size, int type, int stride, int offset) {
+      setAttribute(inDirWidthLoc, vboId, size, type, false, stride, offset);
+    }
+
     public void start() {
       super.start();
-      
+
       if (-1 < inVertexLoc)   pgl.glEnableVertexAttribArray(inVertexLoc);
       if (-1 < inColorLoc)    pgl.glEnableVertexAttribArray(inColorLoc);
-      if (-1 < inDirWidthLoc) pgl.glEnableVertexAttribArray(inDirWidthLoc);      
-      
+      if (-1 < inDirWidthLoc) pgl.glEnableVertexAttribArray(inDirWidthLoc);
+
       if (renderer != null) {
         renderer.updateGLProjection();
         set4x4MatUniform(projectionMatrixLoc, renderer.glProjection);
 
         renderer.updateGLModelview();
-        set4x4MatUniform(modelviewMatrixLoc, renderer.glModelview);      
-        
+        set4x4MatUniform(modelviewMatrixLoc, renderer.glModelview);
+
         set4FloatUniform(viewportLoc, renderer.viewport[0], renderer.viewport[1], renderer.viewport[2], renderer.viewport[3]);
       }
-      
+
       setIntUniform(perspectiveLoc, perspectiveCorrectedLines ? 1 : 0);
     }
 
-    public void stop() {      
+    public void stop() {
       if (-1 < inVertexLoc)   pgl.glDisableVertexAttribArray(inVertexLoc);
       if (-1 < inColorLoc)    pgl.glDisableVertexAttribArray(inColorLoc);
-      if (-1 < inDirWidthLoc) pgl.glDisableVertexAttribArray(inDirWidthLoc);     
-      
+      if (-1 < inDirWidthLoc) pgl.glDisableVertexAttribArray(inDirWidthLoc);
+
       pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, 0);
-      
+
       super.stop();
     }
   }
-  
-  
+
+
   protected class PointShader extends PShader {
     protected PGraphicsOpenGL renderer;
-    
+
     protected int projectionMatrixLoc;
     protected int modelviewMatrixLoc;
-     
+
     protected int inVertexLoc;
     protected int inColorLoc;
     protected int inSizeLoc;
-    
+
     public PointShader(PApplet parent) {
       super(parent);
-    }    
+    }
 
     public PointShader(PApplet parent, String vertFilename, String fragFilename) {
       super(parent, vertFilename, fragFilename);
     }
-    
+
     public PointShader(PApplet parent, URL vertURL, URL fragURL) {
       super(parent, vertURL, fragURL);
-    }        
-    
+    }
+
     public void setRenderer(PGraphicsOpenGL pg) {
       this.renderer = pg;
-    }      
-    
+    }
+
     public void loadAttributes() {
       inVertexLoc = getAttribLocation("inVertex");
       inColorLoc = getAttribLocation("inColor");
-      inSizeLoc = getAttribLocation("inSize");      
-    } 
-    
-    public void loadUniforms() { 
-      projectionMatrixLoc = getUniformLocation("projectionMatrix");      
+      inSizeLoc = getAttribLocation("inSize");
+    }
+
+    public void loadUniforms() {
+      projectionMatrixLoc = getUniformLocation("projectionMatrix");
       modelviewMatrixLoc = getUniformLocation("modelviewMatrix");
     }
-    
+
     public void setAttribute(int loc, int vboId, int size, int type, boolean normalized, int stride, int offset) {
       pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, vboId);
-      pgl.glVertexAttribPointer(loc, size, type, normalized, stride, offset);       
+      pgl.glVertexAttribPointer(loc, size, type, normalized, stride, offset);
     }
-    
-    public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) { 
-      setAttribute(inVertexLoc, vboId, size, type, false, stride, offset);
-    } 
-    
-    public void setColorAttribute(int vboId, int size, int type, int stride, int offset) { 
-      setAttribute(inColorLoc, vboId, size, type, true, stride, offset); 
-    }  
 
-    public void setSizeAttribute(int vboId, int size, int type, int stride, int offset) { 
-      setAttribute(inSizeLoc, vboId, size, type, false, stride, offset); 
+    public void setVertexAttribute(int vboId, int size, int type, int stride, int offset) {
+      setAttribute(inVertexLoc, vboId, size, type, false, stride, offset);
     }
-    
+
+    public void setColorAttribute(int vboId, int size, int type, int stride, int offset) {
+      setAttribute(inColorLoc, vboId, size, type, true, stride, offset);
+    }
+
+    public void setSizeAttribute(int vboId, int size, int type, int stride, int offset) {
+      setAttribute(inSizeLoc, vboId, size, type, false, stride, offset);
+    }
+
     public void start() {
       super.start();
-      
+
       if (-1 < inVertexLoc) pgl.glEnableVertexAttribArray(inVertexLoc);
       if (-1 < inColorLoc)  pgl.glEnableVertexAttribArray(inColorLoc);
-      if (-1 < inSizeLoc)   pgl.glEnableVertexAttribArray(inSizeLoc);      
-      
+      if (-1 < inSizeLoc)   pgl.glEnableVertexAttribArray(inSizeLoc);
+
       if (renderer != null) {
         renderer.updateGLProjection();
         set4x4MatUniform(projectionMatrixLoc, renderer.glProjection);
@@ -5932,39 +5947,39 @@ public class PGraphicsOpenGL extends PGraphics {
       }
     }
 
-    public void stop() {      
+    public void stop() {
       if (-1 < inVertexLoc) pgl.glDisableVertexAttribArray(inVertexLoc);
       if (-1 < inColorLoc)  pgl.glDisableVertexAttribArray(inColorLoc);
       if (-1 < inSizeLoc)   pgl.glDisableVertexAttribArray(inSizeLoc);
-      
+
       pgl.glBindBuffer(PGL.GL_ARRAY_BUFFER, 0);
-      
+
       super.stop();
-    }    
+    }
   }
 
-    
-  
+
+
   //////////////////////////////////////////////////////////////
-  
-  // Input (raw) and Tessellated geometry, tessellator.        
-    
-  
+
+  // Input (raw) and Tessellated geometry, tessellator.
+
+
   public InGeometry newInGeometry(int mode) {
-    return new InGeometry(mode); 
+    return new InGeometry(mode);
   }
-  
-  
+
+
   protected TessGeometry newTessGeometry(int mode) {
     return new TessGeometry(mode);
   }
-  
-  
+
+
   protected TexCache newTexCache() {
     return new TexCache();
-  }  
-  
-  
+  }
+
+
   // Holds an array of textures and the range of vertex
   // indices each texture applies to.
   public class TexCache {
@@ -5974,11 +5989,11 @@ public class PGraphicsOpenGL extends PGraphics {
     protected int[] lastIndex;
     protected boolean hasTexture;
     protected PTexture tex0;
-    
+
     public TexCache() {
       allocate();
     }
-    
+
     public void allocate() {
       textures = new PImage[PGL.DEFAULT_IN_TEXTURES];
       firstIndex = new int[PGL.DEFAULT_IN_TEXTURES];
@@ -5986,19 +6001,19 @@ public class PGraphicsOpenGL extends PGraphics {
       count = 0;
       hasTexture = false;
     }
-    
+
     public void clear() {
       java.util.Arrays.fill(textures, 0, count, null);
       count = 0;
       hasTexture = false;
     }
-    
+
     public void dispose() {
       textures = null;
       firstIndex = null;
-      lastIndex = null;      
+      lastIndex = null;
     }
-    
+
     public void beginRender() {
       tex0 = null;
     }
@@ -6006,31 +6021,31 @@ public class PGraphicsOpenGL extends PGraphics {
     public PTexture getTexture(int i) {
       PImage img = textures[i];
       PTexture tex = null;
-      
-      if (img != null) {        
-        tex = pg.getTexture(img);        
-        if (tex != null) {                   
-          tex.bind();          
+
+      if (img != null) {
+        tex = pg.getTexture(img);
+        if (tex != null) {
+          tex.bind();
           tex0 = tex;
         }
       }
       if (tex == null && tex0 != null) {
         tex0.unbind();
-        pgl.disableTexturing(tex0.glTarget);        
+        pgl.disableTexturing(tex0.glTarget);
       }
-      
+
       return tex;
     }
-    
+
     public void endRender() {
       if (hasTexture) {
-        // Unbinding all the textures in the cache.      
+        // Unbinding all the textures in the cache.
         for (int i = 0; i < count; i++) {
           PImage img = textures[i];
           if (img != null) {
             PTexture tex = pg.getTexture(img);
             if (tex != null) {
-              tex.unbind();  
+              tex.unbind();
             }
           }
         }
@@ -6042,94 +6057,94 @@ public class PGraphicsOpenGL extends PGraphics {
             PTexture tex = pg.getTexture(img);
             if (tex != null) {
               pgl.disableTexturing(tex.glTarget);
-            }          
+            }
           }
         }
-      }      
-    }    
-    
+      }
+    }
+
     public void addTexture(PImage img, int first, int last) {
       textureCheck();
-      
+
       textures[count] = img;
       firstIndex[count] = first;
       lastIndex[count] = last;
-      
+
       // At least one non-null texture since last reset.
       hasTexture |= img != null;
-      
+
       count++;
     }
-    
+
     public void setLastIndex(int last) {
       lastIndex[count - 1] = last;
     }
-    
+
     public void textureCheck() {
       if (count == textures.length) {
-        int newSize = count << 1;  
+        int newSize = count << 1;
 
         expandTextures(newSize);
         expandFirstIndex(newSize);
         expandLastIndex(newSize);
       }
     }
-    
+
     public void expandTextures(int n) {
-      PImage[] temp = new PImage[n];      
+      PImage[] temp = new PImage[n];
       PApplet.arrayCopy(textures, 0, temp, 0, count);
-      textures = temp;          
+      textures = temp;
     }
-        
+
     public void expandFirstIndex(int n) {
-      int[] temp = new int[n];      
+      int[] temp = new int[n];
       PApplet.arrayCopy(firstIndex, 0, temp, 0, count);
-      firstIndex = temp;      
+      firstIndex = temp;
     }
-    
+
     public void expandLastIndex(int n) {
-      int[] temp = new int[n];      
+      int[] temp = new int[n];
       PApplet.arrayCopy(lastIndex, 0, temp, 0, count);
-      lastIndex = temp;      
-    }    
+      lastIndex = temp;
+    }
   }
-  
-  // Holds the input vertices: xyz coordinates, fill/tint color, 
+
+  // Holds the input vertices: xyz coordinates, fill/tint color,
   // normal, texture coordinates and stroke color and weight.
   public class InGeometry {
     int renderMode;
     public int vertexCount;
     public int edgeCount;
-    
-    // Range of vertices that will be processed by the 
+
+    // Range of vertices that will be processed by the
     // tessellator. They can be used in combination with the
     // edges array to have the tessellator using only a specific
     // range of vertices to generate fill geometry, while the
     // line geometry will be read from the edge vertices, which
-    // could be completely different.    
+    // could be completely different.
     public int firstVertex;
-    public int lastVertex;    
+    public int lastVertex;
 
     public int firstEdge;
-    public int lastEdge;    
-    
+    public int lastEdge;
+
     public int[] codes;
-    public float[] vertices;  
+    public float[] vertices;
     public int[] colors;
     public float[] normals;
     public float[] texcoords;
     public int[] scolors;
     public float[] sweights;
-    
+
     // Material properties
     public int[] ambient;
     public int[] specular;
     public int[] emissive;
     public float[] shininess;
-    
+
     // TODO: this should probably go in the TessGeometry class
     public int[][] edges;
-    
+
     // For later, to be used by libraries...
     //public float[][] mtexcoords;
     //public float[][] attributes;
@@ -6137,27 +6152,27 @@ public class PGraphicsOpenGL extends PGraphics {
     public InGeometry(int mode) {
       renderMode = mode;
       allocate();
-    }    
-    
+    }
+
     public void clear() {
-      vertexCount = firstVertex = lastVertex = 0; 
+      vertexCount = firstVertex = lastVertex = 0;
       edgeCount = firstEdge = lastEdge = 0;
     }
-    
-    
+
+
     public void clearEdges() {
       edgeCount = firstEdge = lastEdge = 0;
     }
-    
-    
-    public void allocate() {      
+
+
+    public void allocate() {
       codes = new int[PGL.DEFAULT_IN_VERTICES];
       vertices = new float[3 * PGL.DEFAULT_IN_VERTICES];
-      colors = new int[PGL.DEFAULT_IN_VERTICES];      
+      colors = new int[PGL.DEFAULT_IN_VERTICES];
       normals = new float[3 * PGL.DEFAULT_IN_VERTICES];
       texcoords = new float[2 * PGL.DEFAULT_IN_VERTICES];
       scolors = new int[PGL.DEFAULT_IN_VERTICES];
-      sweights = new float[PGL.DEFAULT_IN_VERTICES];      
+      sweights = new float[PGL.DEFAULT_IN_VERTICES];
       ambient = new int[PGL.DEFAULT_IN_VERTICES];
       specular = new int[PGL.DEFAULT_IN_VERTICES];
       emissive = new int[PGL.DEFAULT_IN_VERTICES];
@@ -6165,7 +6180,7 @@ public class PGraphicsOpenGL extends PGraphics {
       edges = new int[PGL.DEFAULT_IN_EDGES][3];
       clear();
     }
-    
+
     public void trim() {
       if (0 < vertexCount && vertexCount < vertices.length / 3) {
         trimVertices();
@@ -6173,22 +6188,22 @@ public class PGraphicsOpenGL extends PGraphics {
         trimNormals();
         trimTexcoords();
         trimStrokeColors();
-        trimStrokeWeights();        
+        trimStrokeWeights();
         trimAmbient();
         trimSpecular();
         trimEmissive();
-        trimShininess();        
-      } 
-      
-      if (0 < edgeCount && edgeCount < edges.length) { 
+        trimShininess();
+      }
+
+      if (0 < edgeCount && edgeCount < edges.length) {
         trimEdges();
       }
     }
-    
+
     public void dispose() {
       codes = null;
       vertices = null;
-      colors = null;      
+      colors = null;
       normals = null;
       texcoords = null;
       scolors = null;
@@ -6196,80 +6211,80 @@ public class PGraphicsOpenGL extends PGraphics {
       ambient = null;
       specular = null;
       emissive = null;
-      shininess = null;      
+      shininess = null;
       edges = null;
     }
 
     public float getVertexX(int idx) {
-      return vertices[3 * idx + 0];  
+      return vertices[3 * idx + 0];
     }
-    
+
     public float getVertexY(int idx) {
       return vertices[3 * idx + 1];
-    }    
-    
+    }
+
     public float getVertexZ(int idx) {
       return vertices[3 * idx + 2];
-    }    
-    
-    public float getLastVertexX() {
-      return vertices[3 * (vertexCount - 1) + 0];  
     }
-    
+
+    public float getLastVertexX() {
+      return vertices[3 * (vertexCount - 1) + 0];
+    }
+
     public float getLastVertexY() {
       return vertices[3 * (vertexCount - 1) + 1];
-    }    
-    
+    }
+
     public float getLastVertexZ() {
       return vertices[3 * (vertexCount - 1) + 2];
     }
-    
+
     public boolean isFull() {
       return PGL.MAX_TESS_VERTICES <= vertexCount;
     }
 
-    
-    public int addVertex(float x, float y, 
+
+    public int addVertex(float x, float y,
                          int fcolor,
                          float u, float v,
                          int scolor, float sweight,
                          int am, int sp, int em, float shine,
                          int code) {
-      return addVertex(x, y, 0, 
+      return addVertex(x, y, 0,
                        fcolor,
-                       0, 0, 1, 
-                       u, v, 
-                       scolor, sweight, 
+                       0, 0, 1,
+                       u, v,
+                       scolor, sweight,
                        am, sp, em, shine,
-                       code);      
+                       code);
     }
 
-    public int addVertex(float x, float y, 
+    public int addVertex(float x, float y,
                          int fcolor,
                          int scolor, float sweight,
                          int am, int sp, int em, float shine,
                          int code) {
-      return addVertex(x, y, 0, 
+      return addVertex(x, y, 0,
                        fcolor,
-                       0, 0, 1, 
-                       0, 0, 
+                       0, 0, 1,
+                       0, 0,
                        scolor, sweight,
                        am, sp, em, shine,
-                       code);   
-    }    
-    
-    public int addVertex(float x, float y, float z, 
+                       code);
+    }
+
+    public int addVertex(float x, float y, float z,
                          int fcolor,
                          float nx, float ny, float nz,
                          float u, float v,
-                         int scolor, float sweight, 
+                         int scolor, float sweight,
                          int am, int sp, int em, float shine,
                          int code) {
       vertexCheck();
       int index;
 
-      codes[vertexCount] = code;      
-      
+      codes[vertexCount] = code;
+
       index = 3 * vertexCount;
       vertices[index++] = x;
       vertices[index++] = y;
@@ -6280,8 +6295,8 @@ public class PGraphicsOpenGL extends PGraphics {
       index = 3 * vertexCount;
       normals[index++] = nx;
       normals[index++] = ny;
-      normals[index  ] = nz;      
-      
+      normals[index  ] = nz;
+
       index = 2 * vertexCount;
       texcoords[index++] = u;
       texcoords[index  ] = v;
@@ -6293,13 +6308,13 @@ public class PGraphicsOpenGL extends PGraphics {
       specular[vertexCount] = javaToNativeARGB(sp);
       emissive[vertexCount] = javaToNativeARGB(em);
       shininess[vertexCount] = shine;
-      
-      lastVertex = vertexCount; 
+
+      lastVertex = vertexCount;
       vertexCount++;
-      
-      return lastVertex; 
+
+      return lastVertex;
     }
-        
+
     public int javaToNativeARGB(int color) {
       if (PGL.BIG_ENDIAN) {
         return ((color >> 24) & 0xff) | ((color << 8) & 0xffffff00);
@@ -6307,9 +6322,9 @@ public class PGraphicsOpenGL extends PGraphics {
         return (color & 0xff000000)
                | ((color << 16) & 0xff0000) | (color & 0xff00)
                | ((color >> 16) & 0xff);
-      }     
+      }
     }
-    
+
     public void vertexCheck() {
       if (vertexCount == vertices.length / 3) {
         int newSize = vertexCount << 1;
@@ -6318,7 +6333,7 @@ public class PGraphicsOpenGL extends PGraphics {
         expandVertices(newSize);
         expandColors(newSize);
         expandNormals(newSize);
-        expandTexcoords(newSize);      
+        expandTexcoords(newSize);
         expandStrokeColors(newSize);
         expandStrokeWeights(newSize);
         expandAmbient(newSize);
@@ -6326,11 +6341,11 @@ public class PGraphicsOpenGL extends PGraphics {
         expandEmissive(newSize);
         expandShininess(newSize);
       }
-    }  
-    
+    }
+
     public void calcTriangleNormal(int i0, int i1, int i2) {
       int index;
-      
+
       index = 3 * i0;
       float x0 = vertices[index++];
       float y0 = vertices[index++];
@@ -6345,25 +6360,25 @@ public class PGraphicsOpenGL extends PGraphics {
       float x2 = vertices[index++];
       float y2 = vertices[index++];
       float z2 = vertices[index  ];
-      
+
       float v12x = x2 - x1;
       float v12y = y2 - y1;
       float v12z = z2 - z1;
-      
+
       float v10x = x0 - x1;
       float v10y = y0 - y1;
       float v10z = z0 - z1;
-      
+
       // n = v10 x v12 (so the normal points out following the
       // clockwise direction along the vertices of the triangle).
       float nx = v10y * v12z - v12y * v10z;
       float ny = v10z * v12x - v12z * v10x;
       float nz = v10x * v12y - v12x * v10y;
       float d = PApplet.sqrt(nx * nx + ny * ny + nz * nz);
-      nx /= d;
-      ny /= d;
-      nz /= d;
-      
+      nx /= -d;
+      ny /= -d;
+      nz /= -d;
+
       index = 3 * i0;
       normals[index++] = nx;
       normals[index++] = ny;
@@ -6377,195 +6392,195 @@ public class PGraphicsOpenGL extends PGraphics {
       index = 3 * i2;
       normals[index++] = nx;
       normals[index++] = ny;
-      normals[index  ] = nz;      
+      normals[index  ] = nz;
     }
-        
+
     public int addEdge(int i, int j, boolean start, boolean end) {
       edgeCheck();
-      
+
       int[] edge = edges[edgeCount];
       edge[0] = i;
       edge[1] = j;
-      
+
       // Possible values for state:
       // 0 = middle edge (not start, not end)
       // 1 = start edge (start, not end)
       // 2 = end edge (not start, end)
-      // 3 = isolated edge (start, end)      
+      // 3 = isolated edge (start, end)
       edge[2] = (start ? 1 : 0) + 2 * (end ? 1 : 0);
-      
-      lastEdge = edgeCount; 
+
+      lastEdge = edgeCount;
       edgeCount++;
-      
+
       return lastEdge;
     }
-    
+
     public void edgeCheck() {
       if (edgeCount == edges.length) {
         int newLen = edgeCount << 1;
-        
+
         int temp[][] = new int[newLen][3];
         PApplet.arrayCopy(edges, 0, temp, 0, edgeCount);
-        edges = temp;        
+        edges = temp;
       }
     }
-    
+
     protected void expandCodes(int n) {
-      int temp[] = new int[n];      
+      int temp[] = new int[n];
       PApplet.arrayCopy(codes, 0, temp, 0, vertexCount);
-      codes = temp;    
+      codes = temp;
     }
 
     protected void expandVertices(int n) {
-      float temp[] = new float[3 * n];      
+      float temp[] = new float[3 * n];
       PApplet.arrayCopy(vertices, 0, temp, 0, 3 * vertexCount);
-      vertices = temp;    
+      vertices = temp;
     }
 
     protected void expandColors(int n) {
-      int temp[] = new int[n];      
+      int temp[] = new int[n];
       PApplet.arrayCopy(colors, 0, temp, 0, vertexCount);
-      colors = temp;  
+      colors = temp;
     }
 
     protected void expandNormals(int n) {
-      float temp[] = new float[3 * n];      
+      float temp[] = new float[3 * n];
       PApplet.arrayCopy(normals, 0, temp, 0, 3 * vertexCount);
-      normals = temp;    
-    }    
-    
-    protected void expandTexcoords(int n) {
-      float temp[] = new float[2 * n];      
-      PApplet.arrayCopy(texcoords, 0, temp, 0, 2 * vertexCount);
-      texcoords = temp;    
+      normals = temp;
     }
-        
+
+    protected void expandTexcoords(int n) {
+      float temp[] = new float[2 * n];
+      PApplet.arrayCopy(texcoords, 0, temp, 0, 2 * vertexCount);
+      texcoords = temp;
+    }
+
     protected void expandStrokeColors(int n) {
-      int temp[] = new int[n];      
+      int temp[] = new int[n];
       PApplet.arrayCopy(scolors, 0, temp, 0, vertexCount);
       scolors = temp;
     }
 
     protected void expandStrokeWeights(int n) {
-      float temp[] = new float[n];      
+      float temp[] = new float[n];
       PApplet.arrayCopy(sweights, 0, temp, 0, vertexCount);
       sweights = temp;
-    }    
-    
+    }
+
     protected void expandAmbient(int n) {
-      int temp[] = new int[n];      
+      int temp[] = new int[n];
       PApplet.arrayCopy(ambient, 0, temp, 0, vertexCount);
-      ambient = temp;          
+      ambient = temp;
     }
-    
+
     protected void expandSpecular(int n) {
-      int temp[] = new int[n];      
+      int temp[] = new int[n];
       PApplet.arrayCopy(specular, 0, temp, 0, vertexCount);
-      specular = temp;       
+      specular = temp;
     }
-    
+
     protected void expandEmissive(int n) {
-      int temp[] = new int[n];      
+      int temp[] = new int[n];
       PApplet.arrayCopy(emissive, 0, temp, 0, vertexCount);
-      emissive = temp;      
+      emissive = temp;
     }
-    
+
     protected void expandShininess(int n) {
-      float temp[] = new float[n];      
+      float temp[] = new float[n];
       PApplet.arrayCopy(shininess, 0, temp, 0, vertexCount);
-      shininess = temp;       
+      shininess = temp;
     }
-    
+
     protected void trimVertices() {
-      float temp[] = new float[3 * vertexCount];      
+      float temp[] = new float[3 * vertexCount];
       PApplet.arrayCopy(vertices, 0, temp, 0, 3 * vertexCount);
-      vertices = temp;      
+      vertices = temp;
     }
-    
+
     protected void trimColors() {
-      int temp[] = new int[vertexCount];      
+      int temp[] = new int[vertexCount];
       PApplet.arrayCopy(colors, 0, temp, 0, vertexCount);
-      colors = temp;        
+      colors = temp;
     }
 
     protected void trimNormals() {
-      float temp[] = new float[3 * vertexCount];      
+      float temp[] = new float[3 * vertexCount];
       PApplet.arrayCopy(normals, 0, temp, 0, 3 * vertexCount);
-      normals = temp;          
+      normals = temp;
     }
-    
+
     protected void trimTexcoords() {
-      float temp[] = new float[2 * vertexCount];      
+      float temp[] = new float[2 * vertexCount];
       PApplet.arrayCopy(texcoords, 0, temp, 0, 2 * vertexCount);
-      texcoords = temp;    
+      texcoords = temp;
     }
-        
+
     protected void trimStrokeColors() {
-      int temp[] = new int[vertexCount];      
+      int temp[] = new int[vertexCount];
       PApplet.arrayCopy(scolors, 0, temp, 0, vertexCount);
       scolors = temp;
-    }    
+    }
 
     protected void trimStrokeWeights() {
-      float temp[] = new float[vertexCount];      
+      float temp[] = new float[vertexCount];
       PApplet.arrayCopy(sweights, 0, temp, 0, vertexCount);
       sweights = temp;
-    }        
-    
+    }
+
     protected void trimAmbient() {
       int temp[] = new int[vertexCount];
       PApplet.arrayCopy(ambient, 0, temp, 0, vertexCount);
-      ambient = temp;      
+      ambient = temp;
     }
-    
+
     protected void trimSpecular() {
       int temp[] = new int[vertexCount];
       PApplet.arrayCopy(specular, 0, temp, 0, vertexCount);
-      specular = temp;      
+      specular = temp;
     }
-        
+
     protected void trimEmissive() {
       int temp[] = new int[vertexCount];
       PApplet.arrayCopy(emissive, 0, temp, 0, vertexCount);
-      emissive = temp; 
+      emissive = temp;
     }
-    
+
     protected void trimShininess() {
       float temp[] = new float[vertexCount];
       PApplet.arrayCopy(shininess, 0, temp, 0, vertexCount);
-      shininess = temp;      
+      shininess = temp;
     }
 
     protected void trimEdges() {
       int temp[][] = new int[edgeCount][3];
       PApplet.arrayCopy(edges, 0, temp, 0, edgeCount);
-      edges = temp;        
-    }
-        
-    public int getNumLineVertices() {
-      return 4 *(lastEdge - firstEdge + 1);      
+      edges = temp;
     }
 
-    public int getNumLineIndices() {      
+    public int getNumLineVertices() {
+      return 4 *(lastEdge - firstEdge + 1);
+    }
+
+    public int getNumLineIndices() {
       return 6 *(lastEdge - firstEdge + 1);
-    }    
+    }
 
     public void calcTrianglesNormals() {
       for (int i = 0; i < (lastVertex - firstVertex + 1) / 3; i++) {
         int i0 = 3 * i + 0;
         int i1 = 3 * i + 1;
         int i2 = 3 * i + 2;
-        
+
         calcTriangleNormal(i0, i1, i2);
-      }      
-    }    
-    
+      }
+    }
+
     public void addTrianglesEdges() {
       for (int i = 0; i < (lastVertex - firstVertex + 1) / 3; i++) {
         int i0 = 3 * i + 0;
         int i1 = 3 * i + 1;
         int i2 = 3 * i + 2;
-        
+
         addEdge(i0, i1,  true, false);
         addEdge(i1, i2, false, false);
         addEdge(i2, i0, false,  true);
@@ -6577,100 +6592,100 @@ public class PGraphicsOpenGL extends PGraphics {
         int i0 = firstVertex;
         int i1 = i;
         int i2 = i + 1;
-        
+
         calcTriangleNormal(i0, i1, i2);
       }
     }
-    
-    public void addTriangleFanEdges() {      
+
+    public void addTriangleFanEdges() {
       for (int i = firstVertex + 1; i < lastVertex; i++) {
         int i0 = firstVertex;
         int i1 = i;
         int i2 = i + 1;
-        
+
         addEdge(i0, i1,  true, false);
         addEdge(i1, i2, false, false);
-        addEdge(i2, i0, false,  true);        
+        addEdge(i2, i0, false,  true);
       }
     }
-    
+
     public void calcTriangleStripNormals() {
       for (int i = firstVertex + 1; i < lastVertex; i++) {
         int i1 = i;
         int i0, i2;
         if (i % 2 == 0) {
           i0 = i + 1;
-          i2 = i - 1;                  
+          i2 = i - 1;
         } else {
           i0 = i - 1;
-          i2 = i + 1;             
+          i2 = i + 1;
         }
         calcTriangleNormal(i0, i1, i2);
-      }      
+      }
     }
-    
+
     public void addTriangleStripEdges() {
       for (int i = firstVertex + 1; i < lastVertex; i++) {
         int i0 = i;
         int i1, i2;
         if (i % 2 == 0) {
           i1 = i - 1;
-          i2 = i + 1;        
+          i2 = i + 1;
         } else {
           i1 = i + 1;
-          i2 = i - 1;        
+          i2 = i - 1;
         }
-        
+
         addEdge(i0, i1,  true, false);
         addEdge(i1, i2, false, false);
-        addEdge(i2, i0, false,  true);        
+        addEdge(i2, i0, false,  true);
       }
     }
-    
+
     public void calcQuadsNormals() {
       for (int i = 0; i < (lastVertex - firstVertex + 1) / 4; i++) {
         int i0 = 4 * i + 0;
         int i1 = 4 * i + 1;
         int i2 = 4 * i + 2;
         int i3 = 4 * i + 3;
-        
+
         calcTriangleNormal(i0, i1, i2);
         calcTriangleNormal(i2, i3, i0);
       }
     }
-    
+
     public void addQuadsEdges() {
       for (int i = 0; i < (lastVertex - firstVertex + 1) / 4; i++) {
         int i0 = 4 * i + 0;
         int i1 = 4 * i + 1;
         int i2 = 4 * i + 2;
         int i3 = 4 * i + 3;
-        
+
         addEdge(i0, i1,  true, false);
         addEdge(i1, i2, false, false);
         addEdge(i2, i3, false,  false);
         addEdge(i3, i0, false,  true);
-      }        
-    }      
-    
+      }
+    }
+
     public void calcQuadStripNormals() {
       for (int qd = 1; qd < (lastVertex - firstVertex + 1) / 2; qd++) {
         int i0 = firstVertex + 2 * (qd - 1);
         int i1 = firstVertex + 2 * (qd - 1) + 1;
         int i2 = firstVertex + 2 * qd + 1;
-        int i3 = firstVertex + 2 * qd;     
+        int i3 = firstVertex + 2 * qd;
 
         calcTriangleNormal(i0, i1, i3);
         calcTriangleNormal(i3, i2, i0);
       }
     }
-      
+
     public void addQuadStripEdges() {
       for (int qd = 1; qd < (lastVertex - firstVertex + 1) / 2; qd++) {
         int i0 = firstVertex + 2 * (qd - 1);
         int i1 = firstVertex + 2 * (qd - 1) + 1;
         int i2 = firstVertex + 2 * qd + 1;
-        int i3 = firstVertex + 2 * qd;     
+        int i3 = firstVertex + 2 * qd;
 
         addEdge(i0, i1,  true, false);
         addEdge(i1, i2, false, false);
@@ -6678,24 +6693,24 @@ public class PGraphicsOpenGL extends PGraphics {
         addEdge(i3, i0, false,  true);
       }
     }
-    
+
     public void addPolygonEdges(boolean closed) {
-      // Count number of edge segments in the perimeter.      
+      // Count number of edge segments in the perimeter.
       int edgeCount = 0;
       int lnMax = lastVertex - firstVertex + 1;
-      int first = firstVertex;      
+      int first = firstVertex;
       int contour0 = first;
       if (!closed) lnMax--;
       for (int ln = 0; ln < lnMax; ln++) {
         int i = first + ln + 1;
         if ((i == lnMax || codes[i] == PShape.BREAK) && closed) {
           i = first + ln;
-        }            
+        }
         if (codes[i] != PShape.BREAK) {
           edgeCount++;
-        }      
+        }
       }
-      
+
       if (0 < edgeCount) {
         boolean begin = true;
         contour0 = first;
@@ -6704,31 +6719,31 @@ public class PGraphicsOpenGL extends PGraphics {
           int i1 = first + ln + 1;
           if (codes[i0] == PShape.BREAK) contour0 = i0;
           if (i1 == lnMax || codes[i1] == PShape.BREAK) {
-            // We are at the end of a contour. 
+            // We are at the end of a contour.
             if (closed) {
               // Draw line to the first vertex of the current contour,
               // if the polygon is closed.
               i0 = first + ln;
-              i1 = contour0;            
+              i1 = contour0;
               addEdge(i0, i1, begin, true);
             } else if (codes[i1] != PShape.BREAK) {
               addEdge(i0, i1, begin, false);
             }
             // We might start a new contour in the next iteration.
-            begin = true;            
+            begin = true;
           } else if (codes[i1] != PShape.BREAK) {
             addEdge(i0, i1, begin, false);
           }
-        }    
+        }
       }
-    }    
-    
+    }
+
     // Primitive generation
-    
-    public void generateEllipse(int ellipseMode, float a, float b, float c, float d, 
-                                boolean fill, int fillColor, 
+
+    public void generateEllipse(int ellipseMode, float a, float b, float c, float d,
+                                boolean fill, int fillColor,
                                 boolean stroke, int strokeColor, float strokeWeight,
-                                int ambient, int specular, int emissive, float shininess) {      
+                                int ambient, int specular, int emissive, float shininess) {
       float x = a;
       float y = b;
       float w = c;
@@ -6758,7 +6773,7 @@ public class PGraphicsOpenGL extends PGraphics {
         y += h;
         h = -h;
       }
-      
+
       float radiusH = w / 2;
       float radiusV = h / 2;
 
@@ -6773,11 +6788,11 @@ public class PGraphicsOpenGL extends PGraphics {
       int accuracy = (int) (TWO_PI * PApplet.dist(sx1, sy1, sx2, sy2) / 20);
       if (accuracy < 6) {
         accuracy = 6;
-      }      
+      }
       float inc = (float) PGraphicsOpenGL.SINCOS_LENGTH / accuracy;
-      
+
       if (fill) {
-        addVertex(centerX, centerY, 
+        addVertex(centerX, centerY,
                   fillColor, strokeColor, strokeWeight,
                   ambient, specular, emissive, shininess,
                   VERTEX);
@@ -6786,104 +6801,104 @@ public class PGraphicsOpenGL extends PGraphics {
       idx0 = pidx = idx = 0;
       float val = 0;
       for (int i = 0; i < accuracy; i++) {
-        idx = addVertex(centerX + PGraphicsOpenGL.cosLUT[(int) val] * radiusH, 
-                        centerY + PGraphicsOpenGL.sinLUT[(int) val] * radiusV, 
+        idx = addVertex(centerX + PGraphicsOpenGL.cosLUT[(int) val] * radiusH,
+                        centerY + PGraphicsOpenGL.sinLUT[(int) val] * radiusV,
                         fillColor, strokeColor, strokeWeight,
                         ambient, specular, emissive, shininess,
                         VERTEX);
         val = (val + inc) % PGraphicsOpenGL.SINCOS_LENGTH;
-        
+
         if (0 < i) {
           if (stroke) addEdge(pidx, idx, i == 1, false);
         } else {
-          idx0 = idx;  
+          idx0 = idx;
         }
-        
+
         pidx = idx;
       }
       // Back to the beginning
-      addVertex(centerX + PGraphicsOpenGL.cosLUT[0] * radiusH, 
-                centerY + PGraphicsOpenGL.sinLUT[0] * radiusV, 
+      addVertex(centerX + PGraphicsOpenGL.cosLUT[0] * radiusH,
+                centerY + PGraphicsOpenGL.sinLUT[0] * radiusV,
                 fillColor, strokeColor, strokeWeight,
                 ambient, specular, emissive, shininess,
                 VERTEX);
       if (stroke) addEdge(idx, idx0, false, true);
     }
-    
+
   }
-  
+
   // Holds tessellated data for fill, line and point geometry.
   public class TessGeometry {
     int renderMode;
-    
+
     // Tessellated fill data
     public int fillVertexCount;
     public int firstFillVertex;
-    public int lastFillVertex;    
+    public int lastFillVertex;
     public float[] fillVertices;
     public int[] fillColors;
     public float[] fillNormals;
     public float[] fillTexcoords;
-    
+
     // Fill material properties (fillColor is used
     // as the diffuse color when lighting is enabled)
     public int[] fillAmbient;
     public int[] fillSpecular;
     public int[] fillEmissive;
     public float[] fillShininess;
-        
+
     public int fillIndexCount;
     public int firstFillIndex;
-    public int lastFillIndex;    
+    public int lastFillIndex;
     public short[] fillIndices;
-    
-    // Tessellated line data    
+
+    // Tessellated line data
     public int lineVertexCount;
     public int firstLineVertex;
-    public int lastLineVertex;    
+    public int lastLineVertex;
     public float[] lineVertices;
     public int[] lineColors;
-    public float[] lineDirWidths;    
-    
+    public float[] lineDirWidths;
+
     public int lineIndexCount;
     public int firstLineIndex;
-    public int lastLineIndex;  
-    public short[] lineIndices;  
-    
+    public int lastLineIndex;
+    public short[] lineIndices;
+
     // Tessellated point data
     public int pointVertexCount;
     public int firstPointVertex;
-    public int lastPointVertex;    
+    public int lastPointVertex;
     public float[] pointVertices;
     public int[] pointColors;
-    public float[] pointSizes;  
+    public float[] pointSizes;
 
     public int pointIndexCount;
     public int firstPointIndex;
-    public int lastPointIndex;  
+    public int lastPointIndex;
     public short[] pointIndices;
-    
+
     public boolean isStroked;
 
     public TessGeometry(int mode) {
       renderMode = mode;
-      allocate();      
-    }    
-    
+      allocate();
+    }
+
     public void clear() {
       firstFillVertex = lastFillVertex = fillVertexCount = 0;
       firstFillIndex = lastFillIndex = fillIndexCount = 0;
-      
+
       firstLineVertex = lastLineVertex = lineVertexCount = 0;
-      firstLineIndex = lastLineIndex = lineIndexCount = 0;     
-      
+      firstLineIndex = lastLineIndex = lineIndexCount = 0;
+
       firstPointVertex = lastPointVertex = pointVertexCount = 0;
-      firstPointIndex = lastPointIndex = pointIndexCount = 0;  
-      
+      firstPointIndex = lastPointIndex = pointIndexCount = 0;
+
       isStroked = false;
     }
-      
-    public void allocate() {     
+
+    public void allocate() {
       fillVertices = new float[3 * PGL.DEFAULT_TESS_VERTICES];
       fillColors = new int[PGL.DEFAULT_TESS_VERTICES];
       fillNormals = new float[3 * PGL.DEFAULT_TESS_VERTICES];
@@ -6891,22 +6906,22 @@ public class PGraphicsOpenGL extends PGraphics {
       fillAmbient = new int[PGL.DEFAULT_TESS_VERTICES];
       fillSpecular = new int[PGL.DEFAULT_TESS_VERTICES];
       fillEmissive = new int[PGL.DEFAULT_TESS_VERTICES];
-      fillShininess = new float[PGL.DEFAULT_TESS_VERTICES];      
-      fillIndices = new short[PGL.DEFAULT_TESS_VERTICES];        
-      
+      fillShininess = new float[PGL.DEFAULT_TESS_VERTICES];
+      fillIndices = new short[PGL.DEFAULT_TESS_VERTICES];
+
       lineVertices = new float[3 * PGL.DEFAULT_TESS_VERTICES];
       lineColors = new int[PGL.DEFAULT_TESS_VERTICES];
       lineDirWidths = new float[4 * PGL.DEFAULT_TESS_VERTICES];
-      lineIndices = new short[PGL.DEFAULT_TESS_VERTICES];       
-      
+      lineIndices = new short[PGL.DEFAULT_TESS_VERTICES];
+
       pointVertices = new float[3 * PGL.DEFAULT_TESS_VERTICES];
       pointColors = new int[PGL.DEFAULT_TESS_VERTICES];
       pointSizes = new float[2 * PGL.DEFAULT_TESS_VERTICES];
       pointIndices = new short[PGL.DEFAULT_TESS_VERTICES];
-      
+
       clear();
     }
-    
+
     public void trim() {
       if (0 < fillVertexCount && fillVertexCount < fillVertices.length / 3) {
         trimFillVertices();
@@ -6918,134 +6933,134 @@ public class PGraphicsOpenGL extends PGraphics {
         trimFillEmissive();
         trimFillShininess();
       }
-      
+
       if (0 < fillIndexCount && fillIndexCount < fillIndices.length) {
-        trimFillIndices();  
+        trimFillIndices();
       }
-            
+
       if (0 < lineVertexCount && lineVertexCount < lineVertices.length / 3) {
         trimLineVertices();
         trimLineColors();
         trimLineAttributes();
       }
-      
+
       if (0 < lineIndexCount && lineIndexCount < lineIndices.length) {
-        trimLineIndices();  
+        trimLineIndices();
       }
-      
+
       if (0 < pointVertexCount && pointVertexCount < pointVertices.length / 3) {
         trimPointVertices();
         trimPointColors();
         trimPointAttributes();
       }
-      
+
       if (0 < pointIndexCount && pointIndexCount < pointIndices.length) {
-        trimPointIndices();  
-      }       
-    }    
-    
+        trimPointIndices();
+      }
+    }
+
     protected void trimFillVertices() {
-      float temp[] = new float[3 * fillVertexCount];      
+      float temp[] = new float[3 * fillVertexCount];
       PApplet.arrayCopy(fillVertices, 0, temp, 0, 3 * fillVertexCount);
-      fillVertices = temp;       
+      fillVertices = temp;
     }
 
     protected void trimFillColors() {
-      int temp[] = new int[fillVertexCount];      
+      int temp[] = new int[fillVertexCount];
       PApplet.arrayCopy(fillColors, 0, temp, 0, fillVertexCount);
       fillColors = temp;
     }
-    
+
     protected void trimFillNormals() {
-      float temp[] = new float[3 * fillVertexCount];      
+      float temp[] = new float[3 * fillVertexCount];
       PApplet.arrayCopy(fillNormals, 0, temp, 0, 3 * fillVertexCount);
-      fillNormals = temp;       
+      fillNormals = temp;
     }
-    
+
     protected void trimFillTexcoords() {
-      float temp[] = new float[2 * fillVertexCount];      
+      float temp[] = new float[2 * fillVertexCount];
       PApplet.arrayCopy(fillTexcoords, 0, temp, 0, 2 * fillVertexCount);
       fillTexcoords = temp;
     }
-    
+
     protected void trimFillAmbient() {
       int temp[] = new int[fillVertexCount];
       PApplet.arrayCopy(fillAmbient, 0, temp, 0, fillVertexCount);
-      fillAmbient = temp;      
+      fillAmbient = temp;
     }
-    
+
     protected void trimFillSpecular() {
       int temp[] = new int[fillVertexCount];
       PApplet.arrayCopy(fillSpecular, 0, temp, 0, fillVertexCount);
-      fillSpecular = temp;      
+      fillSpecular = temp;
     }
-        
+
     protected void trimFillEmissive() {
       int temp[] = new int[fillVertexCount];
       PApplet.arrayCopy(fillEmissive, 0, temp, 0, fillVertexCount);
-      fillEmissive = temp; 
+      fillEmissive = temp;
     }
-    
+
     protected void trimFillShininess() {
       float temp[] = new float[fillVertexCount];
       PApplet.arrayCopy(fillShininess, 0, temp, 0, fillVertexCount);
-      fillShininess = temp;      
+      fillShininess = temp;
     }
-    
+
     public void trimFillIndices() {
-      short temp[] = new short[fillIndexCount];      
+      short temp[] = new short[fillIndexCount];
       PApplet.arrayCopy(fillIndices, 0, temp, 0, fillIndexCount);
-      fillIndices = temp;      
-    }    
-    
+      fillIndices = temp;
+    }
+
     protected void trimLineVertices() {
-      float temp[] = new float[3 * lineVertexCount];      
+      float temp[] = new float[3 * lineVertexCount];
       PApplet.arrayCopy(lineVertices, 0, temp, 0, 3 * lineVertexCount);
-      lineVertices = temp;  
+      lineVertices = temp;
     }
-    
+
     protected void trimLineColors() {
-      int temp[] = new int[lineVertexCount];      
+      int temp[] = new int[lineVertexCount];
       PApplet.arrayCopy(lineColors, 0, temp, 0, lineVertexCount);
-      lineColors = temp;      
+      lineColors = temp;
     }
-    
+
     protected void trimLineAttributes() {
-      float temp[] = new float[4 * lineVertexCount];      
+      float temp[] = new float[4 * lineVertexCount];
       PApplet.arrayCopy(lineDirWidths, 0, temp, 0, 4 * lineVertexCount);
-      lineDirWidths = temp;      
-    }      
-    
+      lineDirWidths = temp;
+    }
+
     protected void trimLineIndices() {
-      short temp[] = new short[lineIndexCount];      
+      short temp[] = new short[lineIndexCount];
       PApplet.arrayCopy(lineIndices, 0, temp, 0, lineIndexCount);
-      lineIndices = temp;        
-    }    
-    
+      lineIndices = temp;
+    }
+
     protected void trimPointVertices() {
-      float temp[] = new float[3 * pointVertexCount];      
+      float temp[] = new float[3 * pointVertexCount];
       PApplet.arrayCopy(pointVertices, 0, temp, 0, 3 * pointVertexCount);
-      pointVertices = temp;  
+      pointVertices = temp;
     }
-    
+
     protected void trimPointColors() {
-      int temp[] = new int[pointVertexCount];      
+      int temp[] = new int[pointVertexCount];
       PApplet.arrayCopy(pointColors, 0, temp, 0, pointVertexCount);
-      pointColors = temp;      
+      pointColors = temp;
     }
-    
+
     protected void trimPointAttributes() {
-      float temp[] = new float[2 * pointVertexCount];      
+      float temp[] = new float[2 * pointVertexCount];
       PApplet.arrayCopy(pointSizes, 0, temp, 0, 2 * pointVertexCount);
-      pointSizes = temp;      
+      pointSizes = temp;
     }
-    
+
     protected void trimPointIndices() {
-      short temp[] = new short[pointIndexCount];      
+      short temp[] = new short[pointIndexCount];
       PApplet.arrayCopy(pointIndices, 0, temp, 0, pointIndexCount);
-      pointIndices = temp;        
-    }    
-    
+      pointIndices = temp;
+    }
+
     public void dipose() {
       fillVertices = null;
       fillColors = null;
@@ -7054,22 +7069,22 @@ public class PGraphicsOpenGL extends PGraphics {
       fillAmbient = null;
       fillSpecular = null;
       fillEmissive = null;
-      fillShininess = null;      
-      fillIndices = null;        
-      
+      fillShininess = null;
+      fillIndices = null;
+
       lineVertices = null;
       lineColors = null;
       lineDirWidths = null;
-      lineIndices = null;       
-      
+      lineIndices = null;
+
       pointVertices = null;
       pointColors = null;
       pointSizes = null;
       pointIndices = null;
     }
-    
+
     public boolean isFull() {
-      return PGL.MAX_TESS_VERTICES <= fillVertexCount || 
+      return PGL.MAX_TESS_VERTICES <= fillVertexCount ||
              PGL.MAX_TESS_VERTICES <= lineVertexCount ||
              PGL.MAX_TESS_VERTICES <= pointVertexCount ||
              PGL.MAX_TESS_INDICES  <= fillIndexCount ||
@@ -7078,152 +7093,152 @@ public class PGraphicsOpenGL extends PGraphics {
     }
 
     public boolean isOverflow() {
-      return PGL.MAX_TESS_VERTICES < fillVertexCount || 
+      return PGL.MAX_TESS_VERTICES < fillVertexCount ||
              PGL.MAX_TESS_VERTICES < lineVertexCount ||
              PGL.MAX_TESS_VERTICES < pointVertexCount ||
              PGL.MAX_TESS_INDICES  < fillIndexCount ||
              PGL.MAX_TESS_INDICES  < fillIndexCount ||
              PGL.MAX_TESS_INDICES  < fillIndexCount;
     }
-    
+
     public void addCounts(TessGeometry other) {
       fillVertexCount += other.fillVertexCount;
       fillIndexCount += other.fillIndexCount;
-      
+
       lineVertexCount += other.lineVertexCount;
-      lineIndexCount += other.lineIndexCount;        
+      lineIndexCount += other.lineIndexCount;
 
       pointVertexCount += other.pointVertexCount;
-      pointIndexCount += other.pointIndexCount;          
+      pointIndexCount += other.pointIndexCount;
     }
-    
+
     public void setFirstFill(TessGeometry other) {
       firstFillVertex = other.firstFillVertex;
       firstFillIndex = other.firstFillIndex;
     }
-    
+
     public void setLastFill(TessGeometry other) {
       lastFillVertex = other.lastFillVertex;
-      lastFillIndex = other.lastFillIndex;      
+      lastFillIndex = other.lastFillIndex;
     }
 
     public void setFirstLine(TessGeometry other) {
       firstLineVertex = other.firstLineVertex;
       firstLineIndex = other.firstLineIndex;
     }
-    
+
     public void setLastLine(TessGeometry other) {
       lastLineVertex = other.lastLineVertex;
-      lastLineIndex = other.lastLineIndex;      
-    }  
+      lastLineIndex = other.lastLineIndex;
+    }
 
     public void setFirstPoint(TessGeometry other) {
       firstPointVertex = other.firstPointVertex;
       firstPointIndex = other.firstPointIndex;
     }
-    
+
     public void setLastPoint(TessGeometry other) {
       lastPointVertex = other.lastPointVertex;
-      lastPointIndex = other.lastPointIndex;      
-    }    
-    
+      lastPointIndex = other.lastPointIndex;
+    }
+
     public int setFillVertex(int offset) {
       firstFillVertex = 0;
       if (0 < offset) {
-        firstFillVertex = offset + 1; 
+        firstFillVertex = offset + 1;
       }
-      lastFillVertex = firstFillVertex + fillVertexCount - 1;      
-      return lastFillVertex;         
+      lastFillVertex = firstFillVertex + fillVertexCount - 1;
+      return lastFillVertex;
     }
-    
+
     public int setFillIndex(int voffset, int ioffset) {
       firstFillIndex = 0;
       if (0 < ioffset) {
-        firstFillIndex = ioffset + 1; 
+        firstFillIndex = ioffset + 1;
       }
-      
+
       if (0 < voffset) {
-        // The indices are update to take into account all the previous 
+        // The indices are update to take into account all the previous
         // shapes in the hierarchy, as the entire geometry will be stored
         // contiguously in a single VBO in the root node.
         for (int i = 0; i < fillIndexCount; i++) {
           fillIndices[i] += voffset;
         }
       }
-      
-      lastFillIndex = firstFillIndex + fillIndexCount - 1;        
-      return lastFillIndex; 
+
+      lastFillIndex = firstFillIndex + fillIndexCount - 1;
+      return lastFillIndex;
     }
-    
+
     public int setLineVertex(int offset) {
       firstLineVertex = 0;
       if (0 < offset) {
-        firstLineVertex = offset + 1; 
-      }        
+        firstLineVertex = offset + 1;
+      }
       lastLineVertex = firstLineVertex + lineVertexCount - 1;
-      return lastLineVertex;      
+      return lastLineVertex;
     }
-    
-    public int setLineIndex(int voffset, int ioffset) {      
+
+    public int setLineIndex(int voffset, int ioffset) {
       firstLineIndex = 0;
       if (0 < ioffset) {
-        firstLineIndex = ioffset + 1; 
-      }        
-      
+        firstLineIndex = ioffset + 1;
+      }
+
       if (0 < voffset) {
-        // The indices are update to take into account all the previous 
+        // The indices are update to take into account all the previous
         // shapes in the hierarchy, as the entire geometry will be stored
         // contiguously in a single VBO in the root node.
         for (int i = 0; i < lineIndexCount; i++) {
           lineIndices[i] += voffset;
         }
       }
-      
+
       lastLineIndex = firstLineIndex + lineIndexCount - 1;
-      return lastLineIndex;      
+      return lastLineIndex;
     }
-    
+
     public int setPointVertex(int offset) {
       firstPointVertex = 0;
       if (0 < offset) {
-        firstPointVertex = offset + 1; 
-      }        
+        firstPointVertex = offset + 1;
+      }
       lastPointVertex = firstPointVertex + pointVertexCount - 1;
-      return lastPointVertex;      
+      return lastPointVertex;
     }
-    
-    public int setPointIndex(int voffset, int ioffset) { 
+
+    public int setPointIndex(int voffset, int ioffset) {
       firstPointIndex = 0;
       if (0 < ioffset) {
-        firstPointIndex = ioffset + 1; 
-      }        
-      
+        firstPointIndex = ioffset + 1;
+      }
+
       if (0 < voffset) {
-        // The indices are update to take into account all the previous 
+        // The indices are update to take into account all the previous
         // shapes in the hierarchy, as the entire geometry will be stored
         // contiguously in a single VBO in the root node.
         for (int i = 0; i < pointIndexCount; i++) {
           pointIndices[i] += voffset;
-        }        
+        }
       }
 
       lastPointIndex = firstPointIndex + pointIndexCount - 1;
       return lastPointIndex;
     }
-    
+
     public void fillIndexCheck() {
       if (fillIndexCount == fillIndices.length) {
         int newSize = fillIndexCount << 1;
         expandFillIndices(newSize);
       }
-    }    
-    
-    public void expandFillIndices(int n) {
-      short temp[] = new short[n];      
-      PApplet.arrayCopy(fillIndices, 0, temp, 0, fillIndexCount);
-      fillIndices = temp;      
     }
-    
+
+    public void expandFillIndices(int n) {
+      short temp[] = new short[n];
+      PApplet.arrayCopy(fillIndices, 0, temp, 0, fillIndexCount);
+      fillIndices = temp;
+    }
+
     public void addFillIndex(int idx) {
       fillIndexCheck();
       fillIndices[fillIndexCount] = PGL.makeIndex(idx);
@@ -7233,7 +7248,7 @@ public class PGraphicsOpenGL extends PGraphics {
 
     public void calcFillNormal(int i0, int i1, int i2) {
       int index;
-      
+
       index = 3 * i0;
       float x0 = fillVertices[index++];
       float y0 = fillVertices[index++];
@@ -7248,15 +7263,15 @@ public class PGraphicsOpenGL extends PGraphics {
       float x2 = fillVertices[index++];
       float y2 = fillVertices[index++];
       float z2 = fillVertices[index  ];
-      
+
       float v12x = x2 - x1;
       float v12y = y2 - y1;
       float v12z = z2 - z1;
-      
+
       float v10x = x0 - x1;
       float v10y = y0 - y1;
       float v10z = z0 - z1;
-      
+
       float nx = v12y * v10z - v10y * v12z;
       float ny = v12z * v10x - v10z * v12x;
       float nz = v12x * v10y - v10x * v12y;
@@ -7264,7 +7279,7 @@ public class PGraphicsOpenGL extends PGraphics {
       nx /= d;
       ny /= d;
       nz /= d;
-      
+
       index = 3 * i0;
       fillNormals[index++] = nx;
       fillNormals[index++] = ny;
@@ -7278,30 +7293,14 @@ public class PGraphicsOpenGL extends PGraphics {
       index = 3 * i2;
       fillNormals[index++] = nx;
       fillNormals[index++] = ny;
-      fillNormals[index  ] = nz;      
-      
+      fillNormals[index  ] = nz;
+
     }
-    
+
     public void fillVertexCheck() {
       if (fillVertexCount == fillVertices.length / 3) {
-        int newSize = fillVertexCount << 1; 
-      
-        expandFillVertices(newSize);
-        expandFillColors(newSize);              
-        expandFillNormals(newSize);
-        expandFillTexcoords(newSize);
-        expandFillAmbient(newSize);
-        expandFillSpecular(newSize);
-        expandFillEmissive(newSize);
-        expandFillShininess(newSize);
-      }
-    }
-    
-    public void addFillVertices(int count) {
-      int oldSize = fillVertices.length / 3;
-      if (fillVertexCount + count > oldSize) {
-        int newSize = expandVertSize(oldSize, fillVertexCount + count); 
-                
+        int newSize = fillVertexCount << 1;
+
         expandFillVertices(newSize);
         expandFillColors(newSize);
         expandFillNormals(newSize);
@@ -7311,194 +7310,210 @@ public class PGraphicsOpenGL extends PGraphics {
         expandFillEmissive(newSize);
         expandFillShininess(newSize);
       }
-                  
+    }
+
+    public void addFillVertices(int count) {
+      int oldSize = fillVertices.length / 3;
+      if (fillVertexCount + count > oldSize) {
+        int newSize = expandVertSize(oldSize, fillVertexCount + count);
+
+        expandFillVertices(newSize);
+        expandFillColors(newSize);
+        expandFillNormals(newSize);
+        expandFillTexcoords(newSize);
+        expandFillAmbient(newSize);
+        expandFillSpecular(newSize);
+        expandFillEmissive(newSize);
+        expandFillShininess(newSize);
+      }
+
       firstFillVertex = fillVertexCount;
       fillVertexCount += count;
       lastFillVertex = fillVertexCount - 1;
     }
-    
+
     public void addFillIndices(int count) {
       int oldSize = fillIndices.length;
       if (fillIndexCount + count > oldSize) {
-        int newSize = expandIndSize(oldSize, fillIndexCount + count);    
-        
+        int newSize = expandIndSize(oldSize, fillIndexCount + count);
+
         expandFillIndices(newSize);
       }
-     
+
       firstFillIndex = fillIndexCount;
-      fillIndexCount += count;            
-      lastFillIndex = fillIndexCount - 1;   
-    }     
-    
+      fillIndexCount += count;
+      lastFillIndex = fillIndexCount - 1;
+    }
+
     protected void expandFillVertices(int n) {
-      float temp[] = new float[3 * n];      
+      float temp[] = new float[3 * n];
       PApplet.arrayCopy(fillVertices, 0, temp, 0, 3 * fillVertexCount);
-      fillVertices = temp;       
+      fillVertices = temp;
     }
 
     protected void expandFillColors(int n) {
-      int temp[] = new int[n];      
+      int temp[] = new int[n];
       PApplet.arrayCopy(fillColors, 0, temp, 0, fillVertexCount);
       fillColors = temp;
     }
-    
+
     protected void expandFillNormals(int n) {
-      float temp[] = new float[3 * n];      
+      float temp[] = new float[3 * n];
       PApplet.arrayCopy(fillNormals, 0, temp, 0, 3 * fillVertexCount);
-      fillNormals = temp;       
+      fillNormals = temp;
     }
-    
+
     protected void expandFillTexcoords(int n) {
-      float temp[] = new float[2 * n];      
+      float temp[] = new float[2 * n];
       PApplet.arrayCopy(fillTexcoords, 0, temp, 0, 2 * fillVertexCount);
       fillTexcoords = temp;
     }
-    
+
     protected void expandFillAmbient(int n) {
-      int temp[] = new int[n];      
+      int temp[] = new int[n];
       PApplet.arrayCopy(fillAmbient, 0, temp, 0, fillVertexCount);
-      fillAmbient = temp;          
+      fillAmbient = temp;
     }
-    
+
     protected void expandFillSpecular(int n) {
-      int temp[] = new int[n];      
+      int temp[] = new int[n];
       PApplet.arrayCopy(fillSpecular, 0, temp, 0, fillVertexCount);
-      fillSpecular = temp;       
+      fillSpecular = temp;
     }
-    
+
     protected void expandFillEmissive(int n) {
-      int temp[] = new int[n];      
+      int temp[] = new int[n];
       PApplet.arrayCopy(fillEmissive, 0, temp, 0, fillVertexCount);
-      fillEmissive = temp;      
+      fillEmissive = temp;
     }
-    
+
     protected void expandFillShininess(int n) {
-      float temp[] = new float[n];      
+      float temp[] = new float[n];
       PApplet.arrayCopy(fillShininess, 0, temp, 0, fillVertexCount);
-      fillShininess = temp;       
-    }    
-    
+      fillShininess = temp;
+    }
+
     public void addLineVertices(int count) {
       int oldSize = lineVertices.length / 3;
       if (lineVertexCount + count > oldSize) {
         int newSize = expandVertSize(oldSize, lineVertexCount + count);
-        
+
         expandLineVertices(newSize);
         expandLineColors(newSize);
         expandLineAttributes(newSize);
       }
-      
+
       firstLineVertex = lineVertexCount;
-      lineVertexCount += count;            
+      lineVertexCount += count;
       lastLineVertex = lineVertexCount - 1;
     }
 
     protected void expandLineVertices(int n) {
-      float temp[] = new float[3 * n];      
+      float temp[] = new float[3 * n];
       PApplet.arrayCopy(lineVertices, 0, temp, 0, 3 * lineVertexCount);
-      lineVertices = temp;  
+      lineVertices = temp;
     }
-    
+
     protected void expandLineColors(int n) {
-      int temp[] = new int[n];      
+      int temp[] = new int[n];
       PApplet.arrayCopy(lineColors, 0, temp, 0, lineVertexCount);
-      lineColors = temp;      
+      lineColors = temp;
     }
-    
+
     protected void expandLineAttributes(int n) {
-      float temp[] = new float[4 * n];      
+      float temp[] = new float[4 * n];
       PApplet.arrayCopy(lineDirWidths, 0, temp, 0, 4 * lineVertexCount);
-      lineDirWidths = temp;      
-    }      
-    
+      lineDirWidths = temp;
+    }
+
     public void addLineIndices(int count) {
       int oldSize = lineIndices.length;
       if (lineIndexCount + count > oldSize) {
         int newSize = expandIndSize(oldSize, lineIndexCount + count);
-        
+
         expandLineIndices(newSize);
       }
-     
+
       firstLineIndex = lineIndexCount;
-      lineIndexCount += count;      
-      lastLineIndex = lineIndexCount - 1;   
-    }   
-    
-    protected void expandLineIndices(int n) {
-      short temp[] = new short[n];      
-      PApplet.arrayCopy(lineIndices, 0, temp, 0, lineIndexCount);
-      lineIndices = temp;        
+      lineIndexCount += count;
+      lastLineIndex = lineIndexCount - 1;
     }
-    
+
+    protected void expandLineIndices(int n) {
+      short temp[] = new short[n];
+      PApplet.arrayCopy(lineIndices, 0, temp, 0, lineIndexCount);
+      lineIndices = temp;
+    }
+
     public void addPointVertices(int count) {
       int oldSize = pointVertices.length / 3;
       if (pointVertexCount + count > oldSize) {
         int newSize = expandVertSize(oldSize, pointVertexCount + count);
-        
+
         expandPointVertices(newSize);
         expandPointColors(newSize);
         expandPointAttributes(newSize);
       }
-      
+
       firstPointVertex = pointVertexCount;
-      pointVertexCount += count;      
+      pointVertexCount += count;
       lastPointVertex = pointVertexCount - 1;
     }
 
     protected void expandPointVertices(int n) {
-      float temp[] = new float[3 * n];      
+      float temp[] = new float[3 * n];
       PApplet.arrayCopy(pointVertices, 0, temp, 0, 3 * pointVertexCount);
-      pointVertices = temp;  
+      pointVertices = temp;
     }
-    
+
     protected void expandPointColors(int n) {
-      int temp[] = new int[n];      
+      int temp[] = new int[n];
       PApplet.arrayCopy(pointColors, 0, temp, 0, pointVertexCount);
-      pointColors = temp;      
+      pointColors = temp;
     }
-    
+
     protected void expandPointAttributes(int n) {
-      float temp[] = new float[2 * n];      
+      float temp[] = new float[2 * n];
       PApplet.arrayCopy(pointSizes, 0, temp, 0, 2 * pointVertexCount);
-      pointSizes = temp;      
+      pointSizes = temp;
     }
-    
+
     public void addPointIndices(int count) {
       int oldSize = pointIndices.length;
       if (pointIndexCount + count > oldSize) {
         int newSize = expandIndSize(oldSize, pointIndexCount + count);
-        
+
         expandPointIndices(newSize);
       }
-     
+
       firstPointIndex = pointIndexCount;
-      pointIndexCount += count;      
-      lastPointIndex = pointIndexCount - 1;   
-    }   
-    
-    protected void expandPointIndices(int n) {
-      short temp[] = new short[n];      
-      PApplet.arrayCopy(pointIndices, 0, temp, 0, pointIndexCount);
-      pointIndices = temp;        
+      pointIndexCount += count;
+      lastPointIndex = pointIndexCount - 1;
     }
-    
-    public void addFillVertex(float x, float y, float z, 
+
+    protected void expandPointIndices(int n) {
+      short temp[] = new short[n];
+      PApplet.arrayCopy(pointIndices, 0, temp, 0, pointIndexCount);
+      pointIndices = temp;
+    }
+
+    public void addFillVertex(float x, float y, float z,
                               int rgba,
-                              float nx, float ny, float nz, 
-                              float u, float v, 
+                              float nx, float ny, float nz,
+                              float u, float v,
                               int am, int sp, int em, float shine) {
       fillVertexCheck();
       int index;
-      
+
       if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL && !hints[DISABLE_TRANSFORM_CACHE]) {
         PMatrix3D mm = modelview;
         PMatrix3D nm = modelviewInv;
-        
+
         index = 3 * fillVertexCount;
         fillVertices[index++] = x * mm.m00 + y * mm.m01 + z * mm.m02 + mm.m03;
         fillVertices[index++] = x * mm.m10 + y * mm.m11 + z * mm.m12 + mm.m13;
         fillVertices[index  ] = x * mm.m20 + y * mm.m21 + z * mm.m22 + mm.m23;
-        
+
         index = 3 * fillVertexCount;
         fillNormals[index++] = nx * nm.m00 + ny * nm.m10 + nz * nm.m20;
         fillNormals[index++] = nx * nm.m01 + ny * nm.m11 + nz * nm.m21;
@@ -7512,59 +7527,59 @@ public class PGraphicsOpenGL extends PGraphics {
         index = 3 * fillVertexCount;
         fillNormals[index++] = nx;
         fillNormals[index++] = ny;
-        fillNormals[index  ] = nz;        
+        fillNormals[index  ] = nz;
       }
-      
+
       fillColors[fillVertexCount] = rgba;
-      
+
       index = 2 * fillVertexCount;
       fillTexcoords[index++] = u;
-      fillTexcoords[index  ] = v;      
-      
+      fillTexcoords[index  ] = v;
+
       fillAmbient[fillVertexCount] = am;
       fillSpecular[fillVertexCount] = sp;
       fillEmissive[fillVertexCount] = em;
       fillShininess[fillVertexCount] = shine;
-      
+
       fillVertexCount++;
-    }    
+    }
 
     public void addFillVertices(InGeometry in) {
       int index;
       int i0 = in.firstVertex;
       int i1 = in.lastVertex;
       int nvert = i1 - i0 + 1;
-      
+
       addFillVertices(nvert);
-      
+
       if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL && !hints[DISABLE_TRANSFORM_CACHE]) {
         PMatrix3D mm = modelview;
         PMatrix3D nm = modelviewInv;
-        
+
         for (int i = 0; i < nvert; i++) {
           int inIdx = i0 + i;
           int tessIdx = firstFillVertex + i;
-          
+
           index = 3 * inIdx;
           float x = in.vertices[index++];
           float y = in.vertices[index++];
           float z = in.vertices[index  ];
-          
+
           index = 3 * inIdx;
           float nx = in.normals[index++];
           float ny = in.normals[index++];
           float nz = in.normals[index  ];
-          
+
           index = 3 * tessIdx;
           fillVertices[index++] = x * mm.m00 + y * mm.m01 + z * mm.m02 + mm.m03;
           fillVertices[index++] = x * mm.m10 + y * mm.m11 + z * mm.m12 + mm.m13;
           fillVertices[index  ] = x * mm.m20 + y * mm.m21 + z * mm.m22 + mm.m23;
-          
+
           index = 3 * tessIdx;
           fillNormals[index++] = nx * nm.m00 + ny * nm.m10 + nz * nm.m20;
           fillNormals[index++] = nx * nm.m01 + ny * nm.m11 + nz * nm.m21;
           fillNormals[index  ] = nx * nm.m02 + ny * nm.m12 + nz * nm.m22;
-        }        
+        }
       } else {
         if (nvert <= PGL.MIN_ARRAYCOPY_SIZE) {
           // Copying elements one by one instead of using arrayCopy is more efficient for
@@ -7577,28 +7592,28 @@ public class PGraphicsOpenGL extends PGraphics {
             float x = in.vertices[index++];
             float y = in.vertices[index++];
             float z = in.vertices[index  ];
-            
+
             index = 3 * inIdx;
             float nx = in.normals[index++];
             float ny = in.normals[index++];
             float nz = in.normals[index  ];
-            
+
             index = 3 * tessIdx;
             fillVertices[index++] = x;
             fillVertices[index++] = y;
             fillVertices[index  ] = z;
-            
+
             index = 3 * tessIdx;
             fillNormals[index++] = nx;
             fillNormals[index++] = ny;
             fillNormals[index  ] = nz;
-          }     
-        } else {          
+          }
+        } else {
           PApplet.arrayCopy(in.vertices, 3 * i0, fillVertices, 3 * firstFillVertex, 3 * nvert);
-          PApplet.arrayCopy(in.normals, 3 * i0, fillNormals, 3 * firstFillVertex, 3 * nvert);                  
+          PApplet.arrayCopy(in.normals, 3 * i0, fillNormals, 3 * firstFillVertex, 3 * nvert);
         }
       }
-        
+
       if (nvert <= PGL.MIN_ARRAYCOPY_SIZE) {
         for (int i = 0; i < nvert; i++) {
           int inIdx = i0 + i;
@@ -7607,28 +7622,28 @@ public class PGraphicsOpenGL extends PGraphics {
           index = 2 * inIdx;
           float u = in.texcoords[index++];
           float v = in.texcoords[index  ];
-          
+
           fillColors[tessIdx] = in.colors[inIdx];
-          
+
           index = 2 * tessIdx;
           fillTexcoords[index++] = u;
           fillTexcoords[index  ] = v;
-          
+
           fillAmbient[tessIdx] = in.ambient[inIdx];
           fillSpecular[tessIdx] = in.specular[inIdx];
           fillEmissive[tessIdx] = in.emissive[inIdx];
-          fillShininess[tessIdx] = in.shininess[inIdx];          
+          fillShininess[tessIdx] = in.shininess[inIdx];
         }
       } else {
-        PApplet.arrayCopy(in.colors, i0, fillColors, firstFillVertex, nvert);      
-        PApplet.arrayCopy(in.texcoords, 2 * i0, fillTexcoords, 2 * firstFillVertex, 2 * nvert);        
+        PApplet.arrayCopy(in.colors, i0, fillColors, firstFillVertex, nvert);
+        PApplet.arrayCopy(in.texcoords, 2 * i0, fillTexcoords, 2 * firstFillVertex, 2 * nvert);
         PApplet.arrayCopy(in.ambient, i0, fillAmbient, firstFillVertex, nvert);
         PApplet.arrayCopy(in.specular, i0, fillSpecular, firstFillVertex, nvert);
         PApplet.arrayCopy(in.emissive, i0, fillEmissive, firstFillVertex, nvert);
-        PApplet.arrayCopy(in.shininess, i0, fillShininess, firstFillVertex, nvert);        
+        PApplet.arrayCopy(in.shininess, i0, fillShininess, firstFillVertex, nvert);
       }
-    }     
-    
+    }
+
     public void putLineVertex(InGeometry in, int inIdx0, int inIdx1, int tessIdx, int rgba) {
       int index;
 
@@ -7636,44 +7651,44 @@ public class PGraphicsOpenGL extends PGraphics {
       float x0 = in.vertices[index++];
       float y0 = in.vertices[index++];
       float z0 = in.vertices[index  ];
-      
+
       index = 3 * inIdx1;
       float x1 = in.vertices[index++];
       float y1 = in.vertices[index++];
-      float z1 = in.vertices[index  ];        
-      
+      float z1 = in.vertices[index  ];
+
       if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL && !hints[DISABLE_TRANSFORM_CACHE]) {
         PMatrix3D mm = modelview;
-        
+
         index = 3 * tessIdx;
         lineVertices[index++] = x0 * mm.m00 + y0 * mm.m01 + z0 * mm.m02 + mm.m03;
         lineVertices[index++] = x0 * mm.m10 + y0 * mm.m11 + z0 * mm.m12 + mm.m13;
         lineVertices[index  ] = x0 * mm.m20 + y0 * mm.m21 + z0 * mm.m22 + mm.m23;
-        
+
         index = 4 * tessIdx;
         lineDirWidths[index++] = x1 * mm.m00 + y1 * mm.m01 + z1 * mm.m02 + mm.m03;
         lineDirWidths[index++] = x1 * mm.m10 + y1 * mm.m11 + z1 * mm.m12 + mm.m13;
-        lineDirWidths[index  ] = x1 * mm.m20 + y1 * mm.m21 + z1 * mm.m22 + mm.m23;        
+        lineDirWidths[index  ] = x1 * mm.m20 + y1 * mm.m21 + z1 * mm.m22 + mm.m23;
       } else {
         index = 3 * tessIdx;
         lineVertices[index++] = x0;
         lineVertices[index++] = y0;
         lineVertices[index  ] = z0;
-        
+
         index = 4 * tessIdx;
         lineDirWidths[index++] = x1;
         lineDirWidths[index++] = y1;
         lineDirWidths[index  ] = z1;
-      }      
-      
+      }
+
       lineColors[tessIdx] = rgba;
     }
 
-    public void putLineVertex(InGeometry in, int inIdx0, int inIdx1, int tessIdx) {      
+    public void putLineVertex(InGeometry in, int inIdx0, int inIdx1, int tessIdx) {
       putLineVertex(in, inIdx0, inIdx1, tessIdx, in.scolors[inIdx0]);
-    }        
-    
-    
+    }
+
+
     public void putPointVertex(InGeometry in, int inIdx, int tessIdx) {
       int index;
 
@@ -7681,43 +7696,43 @@ public class PGraphicsOpenGL extends PGraphics {
       float x = in.vertices[index++];
       float y = in.vertices[index++];
       float z = in.vertices[index ];
-      
+
       if (renderMode == IMMEDIATE && flushMode == FLUSH_WHEN_FULL && !hints[DISABLE_TRANSFORM_CACHE]) {
         PMatrix3D mm = modelview;
-        
+
         index = 3 * tessIdx;
         pointVertices[index++] = x * mm.m00 + y * mm.m01 + z * mm.m02 + mm.m03;
         pointVertices[index++] = x * mm.m10 + y * mm.m11 + z * mm.m12 + mm.m13;
-        pointVertices[index  ] = x * mm.m20 + y * mm.m21 + z * mm.m22 + mm.m23;        
+        pointVertices[index  ] = x * mm.m20 + y * mm.m21 + z * mm.m22 + mm.m23;
       } else {
         index = 3 * tessIdx;
         pointVertices[index++] = x;
         pointVertices[index++] = y;
         pointVertices[index  ] = z;
-      }      
-      
+      }
+
       pointColors[tessIdx] = in.scolors[inIdx];
     }
-    
+
     public int expandVertSize(int currSize, int newMinSize) {
-      int newSize = currSize; 
+      int newSize = currSize;
       while (newSize < newMinSize) {
-        newSize <<= 1;        
+        newSize <<= 1;
       }
       return newSize;
     }
 
     public int expandIndSize(int currSize, int newMinSize) {
-      int newSize = currSize; 
+      int newSize = currSize;
       while (newSize < newMinSize) {
         newSize <<= 1;
       }
       return newSize;
-    }    
-    
+    }
+
     public void center(float cx, float cy) {
       int index;
-      
+
       // Computing current center
       float cx0 = 0;
       float cy0 = 0;
@@ -7734,53 +7749,53 @@ public class PGraphicsOpenGL extends PGraphics {
       for (int i = 0; i < pointVertexCount; i++) {
         index = 3 * i;
         cx0 += pointVertices[index++];
-        cy0 += pointVertices[index  ];          
-      }      
+        cy0 += pointVertices[index  ];
+      }
       int nt = fillVertexCount + lineVertexCount + pointVertexCount;
-      if (0 < nt) { 
+      if (0 < nt) {
         cx0 /= nt;
         cy0 /= nt;
       }
 
       float tx = cx - cx0;
       float ty = cy - cy0;
-      
+
       if (0 < fillVertexCount) {
         for (int i = 0; i < fillVertexCount; i++) {
           index = 3 * i;
           fillVertices[index++] += tx;
           fillVertices[index  ] += ty;
-        }        
+        }
       }
-      
+
       if (0 < lineVertexCount) {
         for (int i = 0; i < lineVertexCount; i++) {
           index = 3 * i;
           lineVertices[index++] += tx;
           lineVertices[index  ] += ty;
-          
+
           index = 4 * i;
           lineDirWidths[index++] += tx;
-          lineDirWidths[index  ] += ty;           
+          lineDirWidths[index  ] += ty;
         }
       }
-      
+
       if (0 < pointVertexCount) {
         for (int i = 0; i < pointVertexCount; i++) {
           index = 3 * i;
           pointVertices[index++] += tx;
           pointVertices[index  ] += ty;
-        }        
-      }      
+        }
+      }
     }
-    
+
     public void center(float cx, float cy, float cz) {
       int index;
-      
+
       // Computing current center
       float cx0 = 0;
       float cy0 = 0;
-      float cz0 = 0;      
+      float cz0 = 0;
       for (int i = 0; i < fillVertexCount; i++) {
         index = 3 * i;
         cx0 += fillVertices[index++];
@@ -7791,16 +7806,16 @@ public class PGraphicsOpenGL extends PGraphics {
         index = 3 * i;
         cx0 += lineVertices[index++];
         cy0 += lineVertices[index++];
-        cz0 += lineVertices[index  ];        
+        cz0 += lineVertices[index  ];
       }
       for (int i = 0; i < pointVertexCount; i++) {
         index = 3 * i;
         cx0 += pointVertices[index++];
         cy0 += pointVertices[index++];
-        cz0 += pointVertices[index  ];          
-      }      
+        cz0 += pointVertices[index  ];
+      }
       int nt = fillVertexCount + lineVertexCount + pointVertexCount;
-      if (0 < nt) { 
+      if (0 < nt) {
         cx0 /= nt;
         cy0 /= nt;
         cz0 /= nt;
@@ -7808,41 +7823,41 @@ public class PGraphicsOpenGL extends PGraphics {
 
       float tx = cx - cx0;
       float ty = cy - cy0;
-      float tz = cz - cz0;      
-      
+      float tz = cz - cz0;
+
       if (0 < fillVertexCount) {
         for (int i = 0; i < fillVertexCount; i++) {
           index = 3 * i;
           fillVertices[index++] += tx;
           fillVertices[index++] += ty;
           fillVertices[index  ] += tz;
-        }        
+        }
       }
-      
+
       if (0 < lineVertexCount) {
         for (int i = 0; i < lineVertexCount; i++) {
           index = 3 * i;
           lineVertices[index++] += tx;
           lineVertices[index++] += ty;
           lineVertices[index  ] += tz;
-          
+
           index = 4 * i;
           lineDirWidths[index++] += tx;
           lineDirWidths[index++] += ty;
-          lineDirWidths[index  ] += tz;           
+          lineDirWidths[index  ] += tz;
         }
       }
-      
+
       if (0 < pointVertexCount) {
         for (int i = 0; i < pointVertexCount; i++) {
           index = 3 * i;
           pointVertices[index++] += tx;
           pointVertices[index++] += ty;
           pointVertices[index  ] += tz;
-        }        
+        }
       }
     }
-    
+
     public int getCenter(PVector v) {
       int index;
       for (int i = 0; i < fillVertexCount; i++) {
@@ -7855,26 +7870,26 @@ public class PGraphicsOpenGL extends PGraphics {
         index = 3 * i;
         v.x += lineVertices[index++];
         v.y += lineVertices[index++];
-        v.z += lineVertices[index  ];        
+        v.z += lineVertices[index  ];
       }
       for (int i = 0; i < pointVertexCount; i++) {
         index = 3 * i;
         v.x += pointVertices[index++];
         v.y += pointVertices[index++];
-        v.z += pointVertices[index  ];          
-      }      
+        v.z += pointVertices[index  ];
+      }
       return fillVertexCount + lineVertexCount + pointVertexCount;
     }
-    
+
     public void applyMatrix(PMatrix2D tr) {
       if (0 < fillVertexCount) {
         int index;
-          
+
         for (int i = 0; i < fillVertexCount; i++) {
           index = 3 * i;
           float x = fillVertices[index++];
           float y = fillVertices[index  ];
-        
+
           index = 3 * i;
           float nx = fillNormals[index++];
           float ny = fillNormals[index  ];
@@ -7882,60 +7897,60 @@ public class PGraphicsOpenGL extends PGraphics {
           index = 3 * i;
           fillVertices[index++] = x * tr.m00 + y * tr.m01 + tr.m02;
           fillVertices[index  ] = x * tr.m10 + y * tr.m11 + tr.m12;
-        
+
           index = 3 * i;
           fillNormals[index++] = nx * tr.m00 + ny * tr.m01;
-          fillNormals[index  ] = nx * tr.m10 + ny * tr.m11;          
+          fillNormals[index  ] = nx * tr.m10 + ny * tr.m11;
         }
       }
 
       if (0 < lineVertexCount) {
         int index;
-        
+
         for (int i = 0; i < lineVertexCount; i++) {
           index = 3 * i;
           float x = lineVertices[index++];
           float y = lineVertices[index  ];
-        
+
           index = 4 * i;
           float xa = lineDirWidths[index++];
           float ya = lineDirWidths[index  ];
-                    
+
           index = 3 * i;
           lineVertices[index++] = x * tr.m00 + y * tr.m01 + tr.m02;
           lineVertices[index  ] = x * tr.m10 + y * tr.m11 + tr.m12;
-        
+
           index = 4 * i;
           lineDirWidths[index++] = xa * tr.m00 + ya * tr.m01 + tr.m02;
-          lineDirWidths[index  ] = xa * tr.m10 + ya * tr.m11 + tr.m12;              
-        }   
-      }      
-      
+          lineDirWidths[index  ] = xa * tr.m10 + ya * tr.m11 + tr.m12;
+        }
+      }
+
       if (0 < pointVertexCount) {
         int index;
-       
+
         for (int i = 0; i < pointVertexCount; i++) {
           index = 3 * i;
           float x = pointVertices[index++];
           float y = pointVertices[index  ];
-        
+
           index = 3 * i;
           pointVertices[index++] = x * tr.m00 + y * tr.m01 + tr.m02;
           pointVertices[index  ] = x * tr.m10 + y * tr.m11 + tr.m12;
-        } 
-      }       
+        }
+      }
     }
-    
+
     public void applyMatrix(PMatrix3D tr) {
       if (0 < fillVertexCount) {
         int index;
-          
+
         for (int i = 0; i < fillVertexCount; i++) {
           index = 3 * i;
           float x = fillVertices[index++];
           float y = fillVertices[index++];
           float z = fillVertices[index  ];
-        
+
           index = 3 * i;
           float nx = fillNormals[index++];
           float ny = fillNormals[index++];
@@ -7945,59 +7960,59 @@ public class PGraphicsOpenGL extends PGraphics {
           fillVertices[index++] = x * tr.m00 + y * tr.m01 + z * tr.m02 + tr.m03;
           fillVertices[index++] = x * tr.m10 + y * tr.m11 + z * tr.m12 + tr.m13;
           fillVertices[index  ] = x * tr.m20 + y * tr.m21 + z * tr.m22 + tr.m23;
-        
+
           index = 3 * i;
           fillNormals[index++] = nx * tr.m00 + ny * tr.m01 + nz * tr.m02;
           fillNormals[index++] = nx * tr.m10 + ny * tr.m11 + nz * tr.m12;
-          fillNormals[index  ] = nx * tr.m20 + ny * tr.m21 + nz * tr.m22;          
+          fillNormals[index  ] = nx * tr.m20 + ny * tr.m21 + nz * tr.m22;
         }
       }
 
       if (0 < lineVertexCount) {
         int index;
-        
+
         for (int i = 0; i < lineVertexCount; i++) {
           index = 3 * i;
           float x = lineVertices[index++];
           float y = lineVertices[index++];
           float z = lineVertices[index  ];
-        
+
           index = 4 * i;
           float xa = lineDirWidths[index++];
           float ya = lineDirWidths[index++];
           float za = lineDirWidths[index  ];
-                    
+
           index = 3 * i;
           lineVertices[index++] = x * tr.m00 + y * tr.m01 + z * tr.m02 + tr.m03;
           lineVertices[index++] = x * tr.m10 + y * tr.m11 + z * tr.m12 + tr.m13;
           lineVertices[index  ] = x * tr.m20 + y * tr.m21 + z * tr.m22 + tr.m23;
-        
+
           index = 4 * i;
           lineDirWidths[index++] = xa * tr.m00 + ya * tr.m01 + za * tr.m02 + tr.m03;
           lineDirWidths[index++] = xa * tr.m10 + ya * tr.m11 + za * tr.m12 + tr.m13;
-          lineDirWidths[index  ] = xa * tr.m20 + ya * tr.m21 + za * tr.m22 + tr.m23;              
-        }   
-      }      
-      
+          lineDirWidths[index  ] = xa * tr.m20 + ya * tr.m21 + za * tr.m22 + tr.m23;
+        }
+      }
+
       if (0 < pointVertexCount) {
         int index;
-       
+
         for (int i = 0; i < pointVertexCount; i++) {
           index = 3 * i;
           float x = pointVertices[index++];
           float y = pointVertices[index++];
           float z = pointVertices[index  ];
-        
+
           index = 3 * i;
           pointVertices[index++] = x * tr.m00 + y * tr.m01 + z * tr.m02 + tr.m03;
           pointVertices[index++] = x * tr.m10 + y * tr.m11 + z * tr.m12 + tr.m13;
           pointVertices[index  ] = x * tr.m20 + y * tr.m21 + z * tr.m22 + tr.m23;
-        } 
-      }      
-    }    
+        }
+      }
+    }
   }
 
-  final static protected int MIN_ACCURACY = 6; 
+  final static protected int MIN_ACCURACY = 6;
   final static protected float sinLUT[];
   final static protected float cosLUT[];
   final static protected float SINCOS_PRECISION = 0.5f;
@@ -8008,24 +8023,24 @@ public class PGraphicsOpenGL extends PGraphics {
     for (int i = 0; i < SINCOS_LENGTH; i++) {
       sinLUT[i] = (float) Math.sin(i * DEG_TO_RAD * SINCOS_PRECISION);
       cosLUT[i] = (float) Math.cos(i * DEG_TO_RAD * SINCOS_PRECISION);
-    }      
-  }  
+    }
+  }
   final protected float[][] QUAD_SIGNS = { {-1, +1}, {-1, -1}, {+1, -1}, {+1, +1} };
-  
-  // Generates tessellated geometry given a batch of input vertices.  
-  public class Tessellator {    
-    InGeometry in; 
+
+  // Generates tessellated geometry given a batch of input vertices.
+  public class Tessellator {
+    InGeometry in;
     TessGeometry tess;
     PGL.Tessellator gluTess;
     TessellatorCallback callback;
-    
+
     boolean fill;
     boolean stroke;
     float strokeWeight;
     int strokeJoin;
     int strokeCap;
     int bezierDetil = 20;
-    
+
     public Tessellator() {
       callback = new TessellatorCallback();
       gluTess = pgl.createTessellator(callback);
@@ -8039,42 +8054,42 @@ public class PGraphicsOpenGL extends PGraphics {
     public void setTessGeometry(TessGeometry tess) {
       this.tess = tess;
     }
-    
+
     public void setFill(boolean fill) {
       this.fill = fill;
-    }    
-    
+    }
+
     public void setStroke(boolean stroke) {
       this.stroke = stroke;
     }
-    
+
     public void setStrokeWeight(float weight) {
       this.strokeWeight = weight;
     }
-    
-    public void setStrokeJoin(int strokeJoin) { 
+
+    public void setStrokeJoin(int strokeJoin) {
       this.strokeJoin = strokeJoin;
     }
-    
-    public void setStrokeCap(int strokeCap) { 
+
+    public void setStrokeCap(int strokeCap) {
       this.strokeCap = strokeCap;
     }
-    
+
     public void tessellatePoints() {
       if (strokeCap == ROUND) {
         tessellateRoundPoints();
       } else {
         tessellateSquarePoints();
       }
-    }    
+    }
 
     protected void tessellateRoundPoints() {
       int nInVert = in.lastVertex - in.firstVertex + 1;
-      
+
       if (stroke && 1 <= nInVert) {
         tess.isStroked = true;
-        
-        // Each point generates a separate triangle fan. 
+
+        // Each point generates a separate triangle fan.
         // The number of triangles of each fan depends on the
         // stroke weight of the point.
         int nvertTot = 0;
@@ -8083,29 +8098,29 @@ public class PGraphicsOpenGL extends PGraphics {
           int perim = PApplet.max(MIN_ACCURACY, (int) (TWO_PI * strokeWeight / 20));
           // Number of points along the perimeter plus the center point.
           int nvert = perim + 1;
-          nvertTot += nvert; 
+          nvertTot += nvert;
           nindTot += 3 * (nvert - 1);
         }
-     
+
         checkForFlush(tess.lineVertexCount + nvertTot, tess.lineIndexCount + nindTot);
-        
+
         tess.addPointVertices(nvertTot);
         tess.addPointIndices(nindTot);
         int vertIdx = tess.firstPointVertex;
         int attribIdx = tess.firstPointVertex;
-        int indIdx = tess.firstPointIndex;      
-        int firstVert = tess.firstPointVertex;      
+        int indIdx = tess.firstPointIndex;
+        int firstVert = tess.firstPointVertex;
         for (int i = in.firstVertex; i <= in.lastVertex; i++) {
           // Creating the triangle fan for each input vertex.
           int perim = PApplet.max(MIN_ACCURACY, (int) (TWO_PI * strokeWeight / 20));
           int nvert = perim + 1;
-          
+
           // All the tessellated vertices are identical to the center point
           for (int k = 0; k < nvert; k++) {
             tess.putPointVertex(in, i, vertIdx);
-            vertIdx++; 
-          }       
-          
+            vertIdx++;
+          }
+
           // The attributes for each tessellated vertex are the displacement along
           // the circle perimeter. The point shader will read these attributes and
           // displace the vertices in screen coordinates so the circles are always
@@ -8114,14 +8129,14 @@ public class PGraphicsOpenGL extends PGraphics {
           tess.pointSizes[2 * attribIdx + 1] = 0;
           attribIdx++;
           float val = 0;
-          float inc = (float) SINCOS_LENGTH / perim;      
+          float inc = (float) SINCOS_LENGTH / perim;
           for (int k = 0; k < perim; k++) {
             tess.pointSizes[2 * attribIdx + 0] = 0.5f * cosLUT[(int) val] * strokeWeight;
             tess.pointSizes[2 * attribIdx + 1] = 0.5f * sinLUT[(int) val] * strokeWeight;
-            val = (val + inc) % SINCOS_LENGTH;                
-            attribIdx++;           
+            val = (val + inc) % SINCOS_LENGTH;
+            attribIdx++;
           }
-          
+
           // Adding vert0 to take into account the triangles of all
           // the preceding points.
           for (int k = 1; k < nvert - 1; k++) {
@@ -8132,59 +8147,59 @@ public class PGraphicsOpenGL extends PGraphics {
           // Final triangle between the last and first point:
           tess.pointIndices[indIdx++] = PGL.makeIndex(firstVert + 0);
           tess.pointIndices[indIdx++] = PGL.makeIndex(firstVert + 1);
-          tess.pointIndices[indIdx++] = PGL.makeIndex(firstVert + nvert - 1);      
-          
+          tess.pointIndices[indIdx++] = PGL.makeIndex(firstVert + nvert - 1);
+
           firstVert = vertIdx;
-        } 
+        }
       }
     }
-    
+
     protected void tessellateSquarePoints() {
       int nInVert = in.lastVertex - in.firstVertex + 1;
-      
+
       if (stroke && 1 <= nInVert) {
         tess.isStroked = true;
-        
+
         // Each point generates a separate quad.
         int quadCount = nInVert;
-        
+
         // Each quad is formed by 5 vertices, the center one
-        // is the input vertex, and the other 4 define the 
+        // is the input vertex, and the other 4 define the
         // corners (so, a triangle fan again).
         int nvertTot = 5 * quadCount;
         // So the quad is formed by 4 triangles, each requires
         // 3 indices.
         int nindTot = 12 * quadCount;
-        
-        checkForFlush(tess.lineVertexCount + nvertTot, tess.lineIndexCount + nindTot);     
-        
+
+        checkForFlush(tess.lineVertexCount + nvertTot, tess.lineIndexCount + nindTot);
+
         tess.addPointVertices(nvertTot);
         tess.addPointIndices(nindTot);
         int vertIdx = tess.firstPointVertex;
         int attribIdx = tess.firstPointVertex;
-        int indIdx = tess.firstPointIndex;      
-        int firstVert = tess.firstPointVertex;      
+        int indIdx = tess.firstPointIndex;
+        int firstVert = tess.firstPointVertex;
         for (int i = in.firstVertex; i <= in.lastVertex; i++) {
           int nvert = 5;
-          
+
           for (int k = 0; k < nvert; k++) {
             tess.putPointVertex(in, i, vertIdx);
-            vertIdx++; 
-          }       
-          
+            vertIdx++;
+          }
+
           // The attributes for each tessellated vertex are the displacement along
           // the quad corners. The point shader will read these attributes and
           // displace the vertices in screen coordinates so the quads are always
           // camera facing (bilboards)
           tess.pointSizes[2 * attribIdx + 0] = 0;
           tess.pointSizes[2 * attribIdx + 1] = 0;
-          attribIdx++;            
+          attribIdx++;
           for (int k = 0; k < 4; k++) {
             tess.pointSizes[2 * attribIdx + 0] = 0.5f * QUAD_SIGNS[k][0] * strokeWeight;
-            tess.pointSizes[2 * attribIdx + 1] = 0.5f * QUAD_SIGNS[k][1] * strokeWeight;               
-            attribIdx++;           
+            tess.pointSizes[2 * attribIdx + 1] = 0.5f * QUAD_SIGNS[k][1] * strokeWeight;
+            attribIdx++;
           }
-          
+
           // Adding firstVert to take into account the triangles of all
           // the preceding points.
           for (int k = 1; k < nvert - 1; k++) {
@@ -8195,33 +8210,33 @@ public class PGraphicsOpenGL extends PGraphics {
           // Final triangle between the last and first point:
           tess.pointIndices[indIdx++] = PGL.makeIndex(firstVert + 0);
           tess.pointIndices[indIdx++] = PGL.makeIndex(firstVert + 1);
-          tess.pointIndices[indIdx++] = PGL.makeIndex(firstVert + nvert - 1);  
-          
+          tess.pointIndices[indIdx++] = PGL.makeIndex(firstVert + nvert - 1);
+
           firstVert = vertIdx;
         }
       }
     }
-    
+
     public void tessellateLines() {
       int nInVert = in.lastVertex - in.firstVertex + 1;
-      
+
       if (stroke && 2 <= nInVert) {
         tess.isStroked = true;
-        
+
         int lineCount = nInVert / 2;
         int first = in.firstVertex;
 
-        // Lines are made up of 4 vertices defining the quad. 
+        // Lines are made up of 4 vertices defining the quad.
         // Each vertex has its own offset representing the stroke weight.
         int nvert = lineCount * 4;
         // Each stroke line has 4 vertices, defining 2 triangles, which
         // require 3 indices to specify their connectivities.
         int nind = lineCount * 2 * 3;
 
-        checkForFlush(tess.lineVertexCount + nvert, tess.lineIndexCount + nvert);        
-        
+        checkForFlush(tess.lineVertexCount + nvert, tess.lineIndexCount + nvert);
+
         tess.addLineVertices(nvert);
-        tess.addLineIndices(nind);      
+        tess.addLineIndices(nind);
         int vcount = tess.firstLineVertex;
         int icount = tess.firstLineIndex;
         for (int ln = 0; ln < lineCount; ln++) {
@@ -8229,68 +8244,68 @@ public class PGraphicsOpenGL extends PGraphics {
           int i1 = first + 2 * ln + 1;
           addLine(i0, i1, vcount, icount); vcount += 4; icount += 6;
         }
-      }  
+      }
     }
-    
+
     public void tessellateTriangles() {
-      int nInVert = in.lastVertex - in.firstVertex + 1;      
-      
-      if (fill && 3 <= nInVert) {        
+      int nInVert = in.lastVertex - in.firstVertex + 1;
+
+      if (fill && 3 <= nInVert) {
         int nInInd = nInVert;
         checkForFlush(tess.fillVertexCount + nInVert, tess.fillIndexCount + nInInd);
-        
+
         tess.addFillVertices(in);
-        
+
         tess.addFillIndices(nInVert);
         int idx0 = tess.firstFillIndex;
         int offset = tess.firstFillVertex;
         for (int i = in.firstVertex; i <= in.lastVertex; i++) {
           tess.fillIndices[idx0 + i] = PGL.makeIndex(offset + i);
-        }        
+        }
       }
 
       if (stroke) {
         tess.isStroked = true;
-        tessellateEdges();        
-      }      
+        tessellateEdges();
+      }
     }
-    
+
     public void tessellateTriangleFan() {
       int nInVert = in.lastVertex - in.firstVertex + 1;
-            
+
       if (fill && 3 <= nInVert) {
-        int nInInd = 3 * (nInVert - 2); 
+        int nInInd = 3 * (nInVert - 2);
         checkForFlush(tess.fillVertexCount + nInVert, tess.fillIndexCount + nInInd);
-        
+
         tess.addFillVertices(in);
 
         tess.addFillIndices(nInInd);
         int idx = tess.firstFillIndex;
-        int offset = tess.firstFillVertex; 
+        int offset = tess.firstFillVertex;
         for (int i = in.firstVertex + 1; i < in.lastVertex; i++) {
           tess.fillIndices[idx++] = PGL.makeIndex(offset + in.firstVertex);
           tess.fillIndices[idx++] = PGL.makeIndex(offset + i);
           tess.fillIndices[idx++] = PGL.makeIndex(offset + i + 1);
         }
       }
-      
+
       if (stroke) {
         tess.isStroked = true;
         tessellateEdges();
       }
     }
-        
+
     public void tessellateTriangleStrip() {
       int nInVert = in.lastVertex - in.firstVertex + 1;
-      
+
       if (fill && 3 <= nInVert) {
         int triCount = nInVert - 2;
         int nInInd = 3 * triCount;
-        
+
         checkForFlush(tess.fillVertexCount + nInVert, tess.fillIndexCount + nInInd);
-        
+
         tess.addFillVertices(in);
-        
+
         // Each vertex, except the first and last, defines a triangle.
         tess.addFillIndices(nInInd);
         int idx = tess.firstFillIndex;
@@ -8298,15 +8313,15 @@ public class PGraphicsOpenGL extends PGraphics {
         for (int i = in.firstVertex + 1; i < in.lastVertex; i++) {
           tess.fillIndices[idx++] = PGL.makeIndex(offset + i);
           if (i % 2 == 0) {
-            tess.fillIndices[idx++] = PGL.makeIndex(offset + i - 1);  
+            tess.fillIndices[idx++] = PGL.makeIndex(offset + i - 1);
             tess.fillIndices[idx++] = PGL.makeIndex(offset + i + 1);
           } else {
-            tess.fillIndices[idx++] = PGL.makeIndex(offset + i + 1);  
+            tess.fillIndices[idx++] = PGL.makeIndex(offset + i + 1);
             tess.fillIndices[idx++] = PGL.makeIndex(offset + i - 1);
           }
-        }              
-      }      
-      
+        }
+      }
+
       if (stroke) {
         tess.isStroked = true;
         tessellateEdges();
@@ -8315,136 +8330,136 @@ public class PGraphicsOpenGL extends PGraphics {
 
     public void tessellateQuads() {
       int nInVert = in.lastVertex - in.firstVertex + 1;
-      
+
       if (fill && 4 <= nInVert) {
         int quadCount = nInVert / 4;
         int nInInd = 6 * quadCount;
-        
+
         checkForFlush(tess.fillVertexCount + nInVert, tess.fillIndexCount + nInInd);
         tess.addFillVertices(in);
-        
+
         tess.addFillIndices(nInInd);
         int idx = tess.firstFillIndex;
-        int offset = tess.firstFillVertex; 
-        for (int qd = 0; qd < quadCount; qd++) {        
+        int offset = tess.firstFillVertex;
+        for (int qd = 0; qd < quadCount; qd++) {
           int i0 = offset + 4 * qd + 0;
           int i1 = offset + 4 * qd + 1;
           int i2 = offset + 4 * qd + 2;
           int i3 = offset + 4 * qd + 3;
-          
+
           tess.fillIndices[idx++] = PGL.makeIndex(i0);
           tess.fillIndices[idx++] = PGL.makeIndex(i1);
           tess.fillIndices[idx++] = PGL.makeIndex(i3);
-          
+
           tess.fillIndices[idx++] = PGL.makeIndex(i1);
           tess.fillIndices[idx++] = PGL.makeIndex(i2);
           tess.fillIndices[idx++] = PGL.makeIndex(i3);
-        }              
+        }
       }
-      
+
       if (stroke) {
         tess.isStroked = true;
         tessellateEdges();
       }
     }
-    
-    
+
+
     public void tessellateQuadStrip() {
       int nInVert = in.lastVertex - in.firstVertex + 1;
-      
+
       if (fill && 4 <= nInVert) {
         int quadCount = nInVert / 2 - 1;
         int nInInd = 6 * quadCount;
-        
+
         checkForFlush(tess.fillVertexCount + nInVert, tess.fillIndexCount + nInInd);
-        tess.addFillVertices(in);        
-        
+        tess.addFillVertices(in);
+
         tess.addFillIndices(nInInd);
         int idx = tess.firstFillIndex;
-        int offset = tess.firstFillVertex; 
-        for (int qd = 1; qd < nInVert / 2; qd++) {        
+        int offset = tess.firstFillVertex;
+        for (int qd = 1; qd < nInVert / 2; qd++) {
           int i0 = offset + 2 * (qd - 1);
           int i1 = offset + 2 * (qd - 1) + 1;
           int i2 = offset + 2 * qd + 1;
-          int i3 = offset + 2 * qd;      
-          
+          int i3 = offset + 2 * qd;
+
           tess.fillIndices[idx++] = PGL.makeIndex(i0);
           tess.fillIndices[idx++] = PGL.makeIndex(i1);
           tess.fillIndices[idx++] = PGL.makeIndex(i3);
-          
+
           tess.fillIndices[idx++] = PGL.makeIndex(i1);
           tess.fillIndices[idx++] = PGL.makeIndex(i2);
           tess.fillIndices[idx++] = PGL.makeIndex(i3);
-        }              
+        }
       }
- 
+
       if (stroke) {
         tess.isStroked = true;
         tessellateEdges();
       }
-    }  
-    
+    }
+
     public void tessellatePolygon(boolean solid, boolean closed, boolean calcNormals) {
       int nInVert = in.lastVertex - in.firstVertex + 1;
-      
+
       callback.calcNormals = calcNormals;
-      
+
       if (fill && 3 <= nInVert) {
         checkForFlush(nInVert);
-        
+
         gluTess.beginPolygon();
-        
+
         if (solid) {
           // Using NONZERO winding rule for solid polygons.
-          gluTess.setWindingRule(PGL.GLU_TESS_WINDING_NONZERO);          
+          gluTess.setWindingRule(PGL.GLU_TESS_WINDING_NONZERO);
         } else {
           // Using ODD winding rule to generate polygon with holes.
           gluTess.setWindingRule(PGL.GLU_TESS_WINDING_ODD);
         }
 
-        gluTess.beginContour();    
-        
+        gluTess.beginContour();
+
         // Now, iterate over all input data and send to GLU tessellator..
         for (int i = in.firstVertex; i <= in.lastVertex; i++) {
-          boolean breakPt = in.codes[i] == PShape.BREAK;      
+          boolean breakPt = in.codes[i] == PShape.BREAK;
           if (breakPt) {
             gluTess.endContour();
             gluTess.beginContour();
           }
-                    
+
           // Separting colors into individual rgba components for interpolation.
           int fa = (in.colors[i] >> 24) & 0xFF;
           int fr = (in.colors[i] >> 16) & 0xFF;
-          int fg = (in.colors[i] >>  8) & 0xFF; 
+          int fg = (in.colors[i] >>  8) & 0xFF;
           int fb = (in.colors[i] >>  0) & 0xFF;
-          
+
           int aa = (in.ambient[i] >> 24) & 0xFF;
           int ar = (in.ambient[i] >> 16) & 0xFF;
-          int ag = (in.ambient[i] >>  8) & 0xFF; 
+          int ag = (in.ambient[i] >>  8) & 0xFF;
           int ab = (in.ambient[i] >>  0) & 0xFF;
 
           int sa = (in.specular[i] >> 24) & 0xFF;
           int sr = (in.specular[i] >> 16) & 0xFF;
-          int sg = (in.specular[i] >>  8) & 0xFF; 
-          int sb = (in.specular[i] >>  0) & 0xFF; 
-          
+          int sg = (in.specular[i] >>  8) & 0xFF;
+          int sb = (in.specular[i] >>  0) & 0xFF;
+
           int ea = (in.emissive[i] >> 24) & 0xFF;
           int er = (in.emissive[i] >> 16) & 0xFF;
-          int eg = (in.emissive[i] >>  8) & 0xFF; 
-          int eb = (in.emissive[i] >>  0) & 0xFF; 
-          
+          int eg = (in.emissive[i] >>  8) & 0xFF;
+          int eb = (in.emissive[i] >>  0) & 0xFF;
+
           // Vertex data includes coordinates, colors, normals, texture coordinates, and material properties.
           double[] vertex = new double[] { in.vertices [3 * i + 0], in.vertices [3 * i + 1], in.vertices[3 * i + 2],
                                            fa, fr, fg, fb,
                                            in.normals  [3 * i + 0], in.normals  [3 * i + 1], in.normals [3 * i + 2],
                                            in.texcoords[2 * i + 0], in.texcoords[2 * i + 1],
-                                           aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb, 
+                                           aa, ar, ag, ab, sa, sr, sg, sb, ea, er, eg, eb,
                                            in.shininess[i] };
-          
+
           gluTess.addVertex(vertex);
-        }        
+        }
         gluTess.endContour();
-        
+
         gluTess.endPolygon();
       }
 
@@ -8453,94 +8468,94 @@ public class PGraphicsOpenGL extends PGraphics {
         tessellateEdges();
       }
     }
-    
+
     // Adding the data that defines a quad starting at vertex i0 and
     // ending at i1.
     protected void addLine(int i0, int i1, int vcount, int icount) {
       tess.putLineVertex(in, i0, i1, vcount);
-   
+
       tess.lineDirWidths[4 * vcount + 3] = +strokeWeight;
       tess.lineIndices[icount++] = PGL.makeIndex(vcount);
-      
+
       vcount++;
       tess.putLineVertex(in, i0, i1, vcount);
       tess.lineDirWidths[4 * vcount + 3] = -strokeWeight;
       tess.lineIndices[icount++] = PGL.makeIndex(vcount);
-      
+
       vcount++;
       tess.putLineVertex(in, i1, i0, vcount);
       tess.lineDirWidths[4 * vcount + 3] = -strokeWeight;
       tess.lineIndices[icount++] = PGL.makeIndex(vcount);
-      
+
       // Starting a new triangle re-using prev vertices.
       tess.lineIndices[icount++] = PGL.makeIndex(vcount);
       tess.lineIndices[icount++] = PGL.makeIndex(vcount - 1);
-      
+
       vcount++;
-      tess.putLineVertex(in, i1, i0, vcount);      
+      tess.putLineVertex(in, i1, i0, vcount);
       tess.lineDirWidths[4 * vcount + 3] = +strokeWeight;
       tess.lineIndices[icount++] = PGL.makeIndex(vcount);
     }
-    
+
     public void tessellateEdges() {
       int nInVert = in.getNumLineVertices();
-      int nInInd = in.getNumLineIndices();     
-      
+      int nInInd = in.getNumLineIndices();
+
       checkForFlush(tess.lineVertexCount + nInVert, tess.lineIndexCount + nInInd);
-      
+
       tess.addLineVertices(nInVert);
       tess.addLineIndices(nInInd);
       int vcount = tess.firstLineVertex;
-      int icount = tess.firstLineIndex;          
+      int icount = tess.firstLineIndex;
       for (int i = in.firstEdge; i <= in.lastEdge; i++) {
         int[] edge = in.edges[i];
         addLine(edge[0], edge[1], vcount, icount); vcount += 4; icount += 6;
-      }    
+      }
     }
-    
+
     protected void checkForFlush(int vertCount) {
       if (tess.renderMode == IMMEDIATE && PGL.MAX_TESS_VERTICES < vertCount) {
         setLastTexIndex(tess.lastFillIndex);
         flush();
         setFirstTexIndex(0);
-      }      
-    }     
-    
+      }
+    }
+
     protected void checkForFlush(int vertCount, int indCount) {
-      if (tess.renderMode == IMMEDIATE && (PGL.MAX_TESS_VERTICES < vertCount ||  
+      if (tess.renderMode == IMMEDIATE && (PGL.MAX_TESS_VERTICES < vertCount ||
                                            PGL.MAX_TESS_INDICES  < indCount)) {
         setLastTexIndex(tess.lastFillIndex);
         flush();
         setFirstTexIndex(0);
-      }      
-    }    
-        
+      }
+    }
+
     protected boolean startEdge(int edge) {
       return edge % 2 != 0;
     }
-    
+
     protected boolean endEdge(int edge) {
       return 1 < edge;
-    }    
-    
+    }
+
     protected class TessellatorCallback implements PGL.TessellatorCallback {
       public boolean calcNormals;
       protected int tessFirst;
       protected int tessCount;
       protected int tessType;
-      
+
       public void begin(int type) {
         tessFirst = tess.fillVertexCount;
         tessCount = 0;
-        
+
         switch (type) {
-        case PGL.GL_TRIANGLE_FAN: 
+        case PGL.GL_TRIANGLE_FAN:
           tessType = TRIANGLE_FAN;
           break;
-        case PGL.GL_TRIANGLE_STRIP: 
+        case PGL.GL_TRIANGLE_STRIP:
           tessType = TRIANGLE_STRIP;
           break;
-        case PGL.GL_TRIANGLES: 
+        case PGL.GL_TRIANGLES:
           tessType = TRIANGLES;
           break;
         }
@@ -8548,15 +8563,15 @@ public class PGraphicsOpenGL extends PGraphics {
 
       public void end() {
         switch (tessType) {
-        case TRIANGLE_FAN: 
+        case TRIANGLE_FAN:
           for (int i = 1; i < tessCount - 1; i++) {
             addIndex(0);
             addIndex(i);
             addIndex(i + 1);
             if (calcNormals) calcTriNormal(0, i, i + 1);
-          }       
+          }
           break;
-        case TRIANGLE_STRIP: 
+        case TRIANGLE_STRIP:
           for (int i = 1; i < tessCount - 1; i++) {
             addIndex(i);
             if (i % 2 == 0) {
@@ -8567,12 +8582,12 @@ public class PGraphicsOpenGL extends PGraphics {
               addIndex(i + 1);
               addIndex(i - 1);
               if (calcNormals) calcTriNormal(i - 1, i, i + 1);
-            }            
-          }        
+            }
+          }
           break;
-        case TRIANGLES: 
+        case TRIANGLES:
           for (int i = 0; i < tessCount; i++) {
-            addIndex(i);          
+            addIndex(i);
           }
           if (calcNormals) {
             for (int tr = 0; tr < tessCount / 3; tr++) {
@@ -8581,11 +8596,11 @@ public class PGraphicsOpenGL extends PGraphics {
               int i2 = 3 * tr + 2;
               calcTriNormal(i0, i1, i2);
             }
-          }            
+          }
           break;
         }
       }
-      
+
       protected void addIndex(int tessIdx) {
         if (tess.fillVertexCount < PGL.MAX_TESS_INDICES) {
           tess.addFillIndex(tessFirst + tessIdx);
@@ -8593,38 +8608,38 @@ public class PGraphicsOpenGL extends PGraphics {
           throw new RuntimeException("P3D: the tessellator is generating too many indices, reduce complexity of shape.");
         }
       }
-      
+
       protected void calcTriNormal(int tessIdx0, int tessIdx1, int tessIdx2) {
         tess.calcFillNormal(tessFirst + tessIdx0, tessFirst + tessIdx1, tessFirst + tessIdx2);
       }
-      
+
       public void vertex(Object data) {
         if (data instanceof double[]) {
           double[] d = (double[]) data;
           if (d.length < 25) {
             throw new RuntimeException("TessCallback vertex() data is not of length 25");
           }
-          
+
           if (tess.fillVertexCount < PGL.MAX_TESS_VERTICES) {
 
             // Combining individual rgba components back into int color values
-            int fcolor = ((int) d[ 3] << 24) | ((int) d[ 4] << 16) | ((int) d[ 5] << 8) | (int) d[ 6];          
-            int acolor = ((int) d[12] << 24) | ((int) d[13] << 16) | ((int) d[14] << 8) | (int) d[15];  
+            int fcolor = ((int) d[ 3] << 24) | ((int) d[ 4] << 16) | ((int) d[ 5] << 8) | (int) d[ 6];
+            int acolor = ((int) d[12] << 24) | ((int) d[13] << 16) | ((int) d[14] << 8) | (int) d[15];
             int scolor = ((int) d[16] << 24) | ((int) d[17] << 16) | ((int) d[18] << 8) | (int) d[19];
             int ecolor = ((int) d[20] << 24) | ((int) d[21] << 16) | ((int) d[22] << 8) | (int) d[23];
-                    
+
             tess.addFillVertex((float) d[ 0],  (float) d[ 1], (float) d[ 2],
                                fcolor,
                                (float) d[ 7],  (float) d[ 8], (float) d[ 9],
                                (float) d[10], (float) d[11],
-                               acolor, scolor, ecolor, 
+                               acolor, scolor, ecolor,
                                (float) d[24]);
-            
-            tessCount++;            
+
+            tessCount++;
           } else {
             throw new RuntimeException("P3D: the tessellator is generating too many vertices, reduce complexity of shape.");
-          }          
-          
+          }
+
         } else {
           throw new RuntimeException("TessCallback vertex() data not understood");
         }
@@ -8634,7 +8649,7 @@ public class PGraphicsOpenGL extends PGraphics {
         String estring = pgl.gluErrorString(errnum);
         PGraphics.showWarning("Tessellation Error: " + estring);
       }
-      
+
       /**
        * Implementation of the GLU_TESS_COMBINE callback.
        * @param coords is the 3-vector of the new vertex
@@ -8656,9 +8671,9 @@ public class PGraphicsOpenGL extends PGraphics {
         vertex[2] = coords[2];
 
         // Here w e need to use separate rgba components for correct interpolation...
-        
+
         // Calculating the rest of the vertex parameters (color,
-        // normal, texcoords) as the linear combination of the 
+        // normal, texcoords) as the linear combination of the
         // combined vertices.
         for (int i = 3; i < 25; i++) {
           vertex[i] = 0;
@@ -8669,18 +8684,18 @@ public class PGraphicsOpenGL extends PGraphics {
             }
           }
         }
-        
-        // Normalizing normal vector, since the weighted 
-        // combination of normal vectors is not necessarily 
+
+        // Normalizing normal vector, since the weighted
+        // combination of normal vectors is not necessarily
         // normal.
-        double sum = vertex[7] * vertex[7] + 
-                     vertex[8] * vertex[8] + 
+        double sum = vertex[7] * vertex[7] +
+                     vertex[8] * vertex[8] +
                      vertex[9] * vertex[9];
-        double len = Math.sqrt(sum);      
-        vertex[7] /= len; 
+        double len = Math.sqrt(sum);
+        vertex[7] /= len;
         vertex[8] /= len;
-        vertex[9] /= len;  
-        
+        vertex[9] /= len;
+
         outData[0] = vertex;
       }
     }
diff --git a/android/core/src/processing/opengl/PShape3D.java b/android/core/src/processing/opengl/PShape3D.java
index 6b4b2e93d..0040a9a8a 100644
--- a/android/core/src/processing/opengl/PShape3D.java
+++ b/android/core/src/processing/opengl/PShape3D.java
@@ -267,9 +267,9 @@ public class PShape3D extends PShape {
     this.tessellated = false;
     
     if (family == GEOMETRY || family == PRIMITIVE || family == PATH) {
-      in = pg.newInGeometry(RETAINED);      
+      in = pg.newInGeometry(PGraphicsOpenGL.RETAINED);      
     }    
-    tess = pg.newTessGeometry(RETAINED);
+    tess = pg.newTessGeometry(PGraphicsOpenGL.RETAINED);
     fillIndexData = new ArrayList();
     lineIndexData = new ArrayList();
     pointIndexData = new ArrayList();
diff --git a/core/src/processing/core/PConstants.java b/core/src/processing/core/PConstants.java
index 3ee63c694..a8e536c21 100644
--- a/core/src/processing/core/PConstants.java
+++ b/core/src/processing/core/PConstants.java
@@ -38,23 +38,6 @@ import java.awt.event.KeyEvent;
  * @usage Web & Application
  */
 public interface PConstants {
-  // render & flush modes (in P3D)
-
-  static public final int IMMEDIATE = 0;
-  static public final int RETAINED  = 1;
-
-  static public final int FLUSH_CONTINUOUSLY = 0;
-  static public final int FLUSH_WHEN_FULL    = 1;
-
-  // shaders
-
-  static public final int FILL_SHADER_SIMPLE = 0;
-  static public final int FILL_SHADER_LIT = 1;
-  static public final int FILL_SHADER_TEX = 2;
-  static public final int FILL_SHADER_FULL = 3;
-  static public final int LINE_SHADER = 4;
-  static public final int POINT_SHADER = 5;
-
   // vertex fields
 
   static public final int X = 0;  // model coords xyz (formerly MX/MY/MZ)
@@ -142,8 +125,6 @@ public interface PConstants {
   static final String PDF    = "processing.pdf.PGraphicsPDF";
   static final String DXF    = "processing.dxf.RawDXF";
 
-  static final String LWJGL  = "processing.lwjgl.PGraphicsLWJGL";
-
   // platform IDs for PApplet.platform
 
   static final int OTHER   = 0;
@@ -451,9 +432,10 @@ public interface PConstants {
   // text alignment modes
   // are inherited from LEFT, CENTER, RIGHT
 
-  // PTexture
+  // textures
 
-  /** 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;
 
   /** This constant identifies the nearest texture filter (point sampling) */
@@ -462,18 +444,13 @@ public interface PConstants {
   public static final int BILINEAR = 3;
   /** This constant identifies the linear/linear function to build mipmaps  */
   public static final int TRILINEAR = 4;
-
   /** 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;
 
-  /** Point sprite distance attenuation functions */
-  public static final int LINEAR = 0;
-  public static final int QUADRATIC = 1;
 
-
-  // PShape3D
+  // vbos
 
   /**  Static usage mode for PShape3D (vertices won't be updated after creation).  */
   public static final int STATIC = 0;
@@ -482,7 +459,17 @@ public interface PConstants {
   /**  Dynamic usage mode for PShape3D (vertices will be updated at every frame). */
   public static final int STREAM = 2;
 
+  
+  // shaders
 
+  static public final int FILL_SHADER_SIMPLE = 0;
+  static public final int FILL_SHADER_LIT = 1;
+  static public final int FILL_SHADER_TEX = 2;
+  static public final int FILL_SHADER_FULL = 3;
+  static public final int LINE_SHADER = 4;
+  static public final int POINT_SHADER = 5;
+  
+  
   // stroke modes
 
   static final int SQUARE   = 1 << 0;  // called 'butt' in the svg spec
diff --git a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java
index 2847329aa..d135c64d2 100644
--- a/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java
+++ b/java/libraries/opengl/src/processing/opengl/PGraphicsOpenGL.java
@@ -44,7 +44,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;
 
@@ -55,7 +55,22 @@ public class PGraphicsOpenGL extends PGraphics {
 
   // Basic rendering parameters:
 
+  /** Flush modes: continuously (geometry is flushed after each call to
+   * endShape) when-full (geometry is accumulated until a maximum size is
+   * reached.  */
+  static protected final int FLUSH_CONTINUOUSLY = 0;
+  static protected final int FLUSH_WHEN_FULL    = 1;     
+  
+  /** Type of geometry: immediate is that generated with beginShape/vertex/
+   * endShape, retained is the result of creating a PShape3D object with
+   * createShape. */
+  static protected final int IMMEDIATE = 0;
+  static protected final int RETAINED  = 1;
+
+  /** Current flush mode. */
   protected int flushMode = FLUSH_WHEN_FULL;
+  
+  /** VBO storage mode. */
   protected int vboMode = PGL.GL_STATIC_DRAW;
 
   // ........................................................
@@ -507,12 +522,11 @@ public class PGraphicsOpenGL extends PGraphics {
     deleteFinalizedGLResources();
   }
 
-
-  // Only for debugging purposes.
-  public void setFlushMode(int mode) {
-    flushMode = mode;
+  
+  protected void setFlushMode(int mode) {
+    flushMode = mode;    
   }
-
+  
 
   //////////////////////////////////////////////////////////////
 
@@ -6369,9 +6383,9 @@ public class PGraphicsOpenGL extends PGraphics {
       float ny = v10z * v12x - v12z * v10x;
       float nz = v10x * v12y - v12x * v10y;
       float d = PApplet.sqrt(nx * nx + ny * ny + nz * nz);
-      nx /= d;
-      ny /= d;
-      nz /= d;
+      nx /= -d;
+      ny /= -d;
+      nz /= -d;
 
       index = 3 * i0;
       normals[index++] = nx;
diff --git a/java/libraries/opengl/src/processing/opengl/PShape3D.java b/java/libraries/opengl/src/processing/opengl/PShape3D.java
index c9ff4b33d..f72e06d9b 100644
--- a/java/libraries/opengl/src/processing/opengl/PShape3D.java
+++ b/java/libraries/opengl/src/processing/opengl/PShape3D.java
@@ -278,9 +278,9 @@ public class PShape3D extends PShape {
     this.tessellated = false;
     
     if (family == GEOMETRY || family == PRIMITIVE || family == PATH) {
-      in = pg.newInGeometry(RETAINED);      
+      in = pg.newInGeometry(PGraphicsOpenGL.RETAINED);      
     }    
-    tess = pg.newTessGeometry(RETAINED);
+    tess = pg.newTessGeometry(PGraphicsOpenGL.RETAINED);
     fillIndexData = new ArrayList();
     lineIndexData = new ArrayList();
     pointIndexData = new ArrayList();