diff --git a/java/libraries/lwjgl/.classpath b/java/libraries/lwjgl/.classpath
new file mode 100644
index 000000000..9e3626c94
--- /dev/null
+++ b/java/libraries/lwjgl/.classpath
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/java/libraries/lwjgl/.project b/java/libraries/lwjgl/.project
new file mode 100644
index 000000000..c83f47a87
--- /dev/null
+++ b/java/libraries/lwjgl/.project
@@ -0,0 +1,17 @@
+
+
+ processing-lwjgl
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PGL.java
new file mode 100644
index 000000000..1ed465de0
--- /dev/null
+++ b/java/libraries/lwjgl/src/processing/lwjgl/PGL.java
@@ -0,0 +1,3263 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2011-12 Ben Fry and Casey Reas
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ Boston, MA 02111-1307 USA
+*/
+
+package processing.lwjgl;
+
+import java.awt.BorderLayout;
+import java.awt.Canvas;
+import java.awt.Color;
+import java.nio.Buffer;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import java.util.Arrays;
+
+import org.lwjgl.BufferUtils;
+import org.lwjgl.LWJGLException;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.opengl.Display;
+import org.lwjgl.opengl.EXTFramebufferObject;
+import org.lwjgl.opengl.EXTTextureFilterAnisotropic;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.GL12;
+import org.lwjgl.opengl.GL13;
+import org.lwjgl.opengl.GL14;
+import org.lwjgl.opengl.GL15;
+import org.lwjgl.opengl.GL20;
+import org.lwjgl.opengl.GL30;
+import org.lwjgl.opengl.GL31;
+import org.lwjgl.util.glu.GLU;
+import org.lwjgl.util.glu.GLUtessellator;
+import org.lwjgl.util.glu.GLUtessellatorCallbackAdapter;
+import org.lwjgl.opengl.PixelFormat;
+
+import processing.core.PApplet;
+import processing.core.PConstants;
+import processing.event.Event;
+import processing.event.KeyEvent;
+import processing.event.MouseEvent;
+import processing.opengl.PGraphicsOpenGL;
+import processing.opengl.Texture;
+
+/**
+ * Processing-OpenGL abstraction layer.
+ *
+ * Warnings are suppressed for static access because presumably on Android,
+ * the GL2 vs GL distinctions are necessary, whereas on desktop they are not.
+ *
+ * This version of PGL uses LWJGL, see some issues with it:
+ * http://lwjgl.org/forum/index.php/topic,4711.0.html
+ * http://www.java-gaming.org/topics/cannot-add-mouselistener-to-java-awt-canvas-with-lwjgl-on-windows/24650/view.html
+ *
+ */
+@SuppressWarnings("static-access")
+public class PGL {
+
+ ///////////////////////////////////////////////////////////
+
+ // Parameters
+
+ public static boolean FORCE_SCREEN_FBO = false;
+ public static final boolean USE_DIRECT_BUFFERS = true;
+ public static final int MIN_DIRECT_BUFFER_SIZE = 16;
+ public static final boolean SAVE_SURFACE_TO_PIXELS = true;
+
+ /** Enables/disables mipmap use. **/
+ protected static final boolean MIPMAPS_ENABLED = true;
+
+ /** Initial sizes for arrays of input and tessellated data. */
+ protected static final int DEFAULT_IN_VERTICES = 64;
+ protected static final int DEFAULT_IN_EDGES = 128;
+ protected static final int DEFAULT_IN_TEXTURES = 64;
+ protected static final int DEFAULT_TESS_VERTICES = 64;
+ protected static final int DEFAULT_TESS_INDICES = 128;
+
+ /** Maximum lights by default is 8, the minimum defined by OpenGL. */
+ protected static final int MAX_LIGHTS = 8;
+
+ /** Maximum index value of a tessellated vertex. GLES restricts the vertex
+ * indices to be of type unsigned short. Since Java only supports signed
+ * shorts as primitive type we have 2^15 = 32768 as the maximum number of
+ * vertices that can be referred to within a single VBO. */
+ protected static final int MAX_VERTEX_INDEX = 32767;
+ protected static final int MAX_VERTEX_INDEX1 = MAX_VERTEX_INDEX + 1;
+
+ /** Count of tessellated fill, line or point vertices that will
+ * trigger a flush in the immediate mode. It doesn't necessarily
+ * be equal to MAX_VERTEX_INDEX1, since the number of vertices can
+ * be effectively much large since the renderer uses offsets to
+ * refer to vertices beyond the MAX_VERTEX_INDEX limit.
+ */
+ protected static final int FLUSH_VERTEX_COUNT = MAX_VERTEX_INDEX1;
+
+ /** Maximum dimension of a texture used to hold font data. **/
+ protected static final int MAX_FONT_TEX_SIZE = 1024;
+
+ /** Minimum stroke weight needed to apply the full path stroking
+ * algorithm that properly generates caps and joins.
+ */
+ protected static final float MIN_CAPS_JOINS_WEIGHT = 2f;
+
+ /** Maximum length of linear paths to be stroked with the
+ * full algorithm that generates accurate caps and joins.
+ */
+ protected static final int MAX_CAPS_JOINS_LENGTH = 5000;
+
+ /** Minimum array size to use arrayCopy method(). **/
+ protected static final int MIN_ARRAYCOPY_SIZE = 2;
+
+ protected static int request_depth_bits = 24;
+ protected static int request_stencil_bits = 8;
+ protected static int request_alpha_bits = 8;
+
+ protected static final int SIZEOF_SHORT = Short.SIZE / 8;
+ protected static final int SIZEOF_INT = Integer.SIZE / 8;
+ protected static final int SIZEOF_FLOAT = Float.SIZE / 8;
+ protected static final int SIZEOF_BYTE = Byte.SIZE / 8;
+ protected static final int SIZEOF_INDEX = SIZEOF_SHORT;
+ protected static final int INDEX_TYPE = GL11.GL_UNSIGNED_SHORT;
+
+ /** Machine Epsilon for float precision. **/
+ protected static float FLOAT_EPS = Float.MIN_VALUE;
+ // Calculation of the Machine Epsilon for float precision. From:
+ // http://en.wikipedia.org/wiki/Machine_epsilon#Approximation_using_Java
+ static {
+ float eps = 1.0f;
+
+ do {
+ eps /= 2.0f;
+ } while ((float)(1.0 + (eps / 2.0)) != 1.0);
+
+ FLOAT_EPS = eps;
+ }
+
+ /**
+ * Set to true if the host system is big endian (PowerPC, MIPS, SPARC), false
+ * if little endian (x86 Intel for Mac or PC).
+ */
+ protected static boolean BIG_ENDIAN =
+ ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
+
+ protected static final String SHADER_PREPROCESSOR_DIRECTIVE =
+ "#ifdef GL_ES\n" +
+ "precision mediump float;\n" +
+ "precision mediump int;\n" +
+ "#endif\n";
+
+ ///////////////////////////////////////////////////////////
+
+ // OpenGL constants
+
+ public static final int FALSE = GL11.GL_FALSE;
+ public static final int TRUE = GL11.GL_TRUE;
+
+ public static final int LESS = GL11.GL_LESS;
+ public static final int LEQUAL = GL11.GL_LEQUAL;
+
+ public static final int CCW = GL11.GL_CCW;
+ public static final int CW = GL11.GL_CW;
+
+ public static final int CULL_FACE = GL11.GL_CULL_FACE;
+ public static final int FRONT = GL11.GL_FRONT;
+ public static final int BACK = GL11.GL_BACK;
+ public static final int FRONT_AND_BACK = GL11.GL_FRONT_AND_BACK;
+
+ public static final int VIEWPORT = GL11.GL_VIEWPORT;
+
+ public static final int SCISSOR_TEST = GL11.GL_SCISSOR_TEST;
+ public static final int DEPTH_TEST = GL11.GL_DEPTH_TEST;
+ public static final int DEPTH_WRITEMASK = GL11.GL_DEPTH_WRITEMASK;
+
+ public static final int COLOR_BUFFER_BIT = GL11.GL_COLOR_BUFFER_BIT;
+ public static final int DEPTH_BUFFER_BIT = GL11.GL_DEPTH_BUFFER_BIT;
+ public static final int STENCIL_BUFFER_BIT = GL11.GL_STENCIL_BUFFER_BIT;
+
+ public static final int FUNC_ADD = GL14.GL_FUNC_ADD;
+ public static final int FUNC_MIN = GL14.GL_MIN;
+ public static final int FUNC_MAX = GL14.GL_MAX;
+ public static final int FUNC_REVERSE_SUBTRACT = GL14.GL_FUNC_REVERSE_SUBTRACT;
+
+ public static final int TEXTURE_2D = GL11.GL_TEXTURE_2D;
+ public static final int TEXTURE_RECTANGLE = GL31.GL_TEXTURE_RECTANGLE;
+
+ public static final int TEXTURE_BINDING_2D = GL11.GL_TEXTURE_BINDING_2D;
+ public static final int TEXTURE_BINDING_RECTANGLE =
+ GL31.GL_TEXTURE_BINDING_RECTANGLE;
+
+ public static final int RGB = GL11.GL_RGB;
+ public static final int RGBA = GL11.GL_RGBA;
+ public static final int ALPHA = GL11.GL_ALPHA;
+ public static final int UNSIGNED_INT = GL11.GL_UNSIGNED_INT;
+ public static final int UNSIGNED_BYTE = GL11.GL_UNSIGNED_BYTE;
+ public static final int UNSIGNED_SHORT = GL11.GL_UNSIGNED_SHORT;
+ public static final int FLOAT = GL11.GL_FLOAT;
+
+ public static final int NEAREST = GL11.GL_NEAREST;
+ public static final int LINEAR = GL11.GL_LINEAR;
+ public static final int LINEAR_MIPMAP_NEAREST = GL11.GL_LINEAR_MIPMAP_NEAREST;
+ public static final int LINEAR_MIPMAP_LINEAR = GL11.GL_LINEAR_MIPMAP_LINEAR;
+
+ public static final int TEXTURE_MAX_ANISOTROPY =
+ EXTTextureFilterAnisotropic.GL_TEXTURE_MAX_ANISOTROPY_EXT;
+ public static final int MAX_TEXTURE_MAX_ANISOTROPY =
+ EXTTextureFilterAnisotropic.GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT;
+
+ public static final int CLAMP_TO_EDGE = GL12.GL_CLAMP_TO_EDGE;
+ public static final int REPEAT = GL11.GL_REPEAT;
+
+ public static final int RGBA8 = GL11.GL_RGBA8;
+ public static final int DEPTH24_STENCIL8 = GL30.GL_DEPTH24_STENCIL8;
+
+ public static final int DEPTH_COMPONENT = GL11.GL_DEPTH_COMPONENT;
+ public static final int DEPTH_COMPONENT16 = GL14.GL_DEPTH_COMPONENT16;
+ public static final int DEPTH_COMPONENT24 = GL14.GL_DEPTH_COMPONENT24;
+ public static final int DEPTH_COMPONENT32 = GL14.GL_DEPTH_COMPONENT32;
+
+ public static final int STENCIL_INDEX = GL11.GL_STENCIL_INDEX;
+ public static final int STENCIL_INDEX1 = GL30.GL_STENCIL_INDEX1;
+ public static final int STENCIL_INDEX4 = GL30.GL_STENCIL_INDEX4;
+ public static final int STENCIL_INDEX8 = GL30.GL_STENCIL_INDEX8;
+
+ public static final int ARRAY_BUFFER = GL15.GL_ARRAY_BUFFER;
+ public static final int ELEMENT_ARRAY_BUFFER = GL15.GL_ELEMENT_ARRAY_BUFFER;
+
+ public static final int SAMPLES = GL13.GL_SAMPLES;
+
+ public static final int FRAMEBUFFER_COMPLETE =
+ GL30.GL_FRAMEBUFFER_COMPLETE;
+ public static final int FRAMEBUFFER_INCOMPLETE_ATTACHMENT =
+ GL30.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ public static final int FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT =
+ GL30.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+ public static final int FRAMEBUFFER_INCOMPLETE_DIMENSIONS =
+ EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
+ public static final int FRAMEBUFFER_INCOMPLETE_FORMATS =
+ EXTFramebufferObject.GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT;
+ public static final int FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER =
+ GL30.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER;
+ public static final int FRAMEBUFFER_INCOMPLETE_READ_BUFFER =
+ GL30.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER;
+ public static final int FRAMEBUFFER_UNSUPPORTED =
+ GL30.GL_FRAMEBUFFER_UNSUPPORTED;
+
+ public static final int STATIC_DRAW = GL15.GL_STATIC_DRAW;
+ public static final int DYNAMIC_DRAW = GL15.GL_DYNAMIC_DRAW;
+ public static final int STREAM_DRAW = GL15.GL_STREAM_DRAW;
+
+ public static final int READ_ONLY = GL15.GL_READ_ONLY;
+ public static final int WRITE_ONLY = GL15.GL_WRITE_ONLY;
+ public static final int READ_WRITE = GL15.GL_READ_WRITE;
+
+ public static final int TRIANGLE_FAN = GL11.GL_TRIANGLE_FAN;
+ public static final int TRIANGLE_STRIP = GL11.GL_TRIANGLE_STRIP;
+ public static final int TRIANGLES = GL11.GL_TRIANGLES;
+
+ public static final int VENDOR = GL11.GL_VENDOR;
+ public static final int RENDERER = GL11.GL_RENDERER;
+ public static final int VERSION = GL11.GL_VERSION;
+ public static final int EXTENSIONS = GL11.GL_EXTENSIONS;
+ public static final int SHADING_LANGUAGE_VERSION =
+ GL20.GL_SHADING_LANGUAGE_VERSION;
+
+ public static final int MAX_TEXTURE_SIZE = GL11.GL_MAX_TEXTURE_SIZE;
+ public static final int MAX_SAMPLES = GL30.GL_MAX_SAMPLES;
+ public static final int ALIASED_LINE_WIDTH_RANGE =
+ GL12.GL_ALIASED_LINE_WIDTH_RANGE;
+ public static final int ALIASED_POINT_SIZE_RANGE =
+ GL12.GL_ALIASED_POINT_SIZE_RANGE;
+ public static final int DEPTH_BITS = GL11.GL_DEPTH_BITS;
+ public static final int STENCIL_BITS = GL11.GL_STENCIL_BITS;
+
+ public static final int TESS_WINDING_NONZERO = GLU.GLU_TESS_WINDING_NONZERO;
+ public static final int TESS_WINDING_ODD = GLU.GLU_TESS_WINDING_ODD;
+
+ public static final int TEXTURE0 = GL13.GL_TEXTURE0;
+ public static final int TEXTURE1 = GL13.GL_TEXTURE1;
+ public static final int TEXTURE2 = GL13.GL_TEXTURE2;
+ public static final int TEXTURE3 = GL13.GL_TEXTURE3;
+ public static final int TEXTURE_MIN_FILTER = GL11.GL_TEXTURE_MIN_FILTER;
+ public static final int TEXTURE_MAG_FILTER = GL11.GL_TEXTURE_MAG_FILTER;
+ public static final int TEXTURE_WRAP_S = GL11.GL_TEXTURE_WRAP_S;
+ public static final int TEXTURE_WRAP_T = GL11.GL_TEXTURE_WRAP_T;
+
+ public static final int BLEND = GL11.GL_BLEND;
+ public static final int ONE = GL11.GL_ONE;
+ public static final int ZERO = GL11.GL_ZERO;
+ public static final int SRC_ALPHA = GL11.GL_SRC_ALPHA;
+ public static final int DST_ALPHA = GL11.GL_DST_ALPHA;
+ public static final int ONE_MINUS_SRC_ALPHA = GL11.GL_ONE_MINUS_SRC_ALPHA;
+ public static final int ONE_MINUS_DST_COLOR = GL11.GL_ONE_MINUS_DST_COLOR;
+ public static final int ONE_MINUS_SRC_COLOR = GL11.GL_ONE_MINUS_SRC_COLOR;
+ public static final int DST_COLOR = GL11.GL_DST_COLOR;
+ public static final int SRC_COLOR = GL11.GL_SRC_COLOR;
+
+ public static final int FRAMEBUFFER = GL30.GL_FRAMEBUFFER;
+ public static final int COLOR_ATTACHMENT0 = GL30.GL_COLOR_ATTACHMENT0;
+ public static final int COLOR_ATTACHMENT1 = GL30.GL_COLOR_ATTACHMENT1;
+ public static final int COLOR_ATTACHMENT2 = GL30.GL_COLOR_ATTACHMENT2;
+ public static final int COLOR_ATTACHMENT3 = GL30.GL_COLOR_ATTACHMENT3;
+ public static final int RENDERBUFFER = GL30.GL_RENDERBUFFER;
+ public static final int DEPTH_ATTACHMENT = GL30.GL_DEPTH_ATTACHMENT;
+ public static final int STENCIL_ATTACHMENT = GL30.GL_STENCIL_ATTACHMENT;
+ public static final int READ_FRAMEBUFFER = GL30.GL_READ_FRAMEBUFFER;
+ public static final int DRAW_FRAMEBUFFER = GL30.GL_DRAW_FRAMEBUFFER;
+
+ public static final int VERTEX_SHADER = GL20.GL_VERTEX_SHADER;
+ public static final int FRAGMENT_SHADER = GL20.GL_FRAGMENT_SHADER;
+ public static final int INFO_LOG_LENGTH = GL20.GL_INFO_LOG_LENGTH;
+ public static final int SHADER_SOURCE_LENGTH = GL20.GL_SHADER_SOURCE_LENGTH;
+ public static final int COMPILE_STATUS = GL20.GL_COMPILE_STATUS;
+ public static final int LINK_STATUS = GL20.GL_LINK_STATUS;
+ public static final int VALIDATE_STATUS = GL20.GL_VALIDATE_STATUS;
+
+ public static final int MULTISAMPLE = GL13.GL_MULTISAMPLE;
+ public static final int POINT_SMOOTH = GL11.GL_POINT_SMOOTH;
+ public static final int LINE_SMOOTH = GL11.GL_LINE_SMOOTH;
+ public static final int POLYGON_SMOOTH = GL11.GL_POLYGON_SMOOTH;
+
+ /** GLU interface **/
+ public static GLU glu;
+
+ /** The canvas where OpenGL rendering takes place */
+ public static Canvas canvas;
+
+ /** OpenGL thread */
+ protected static Thread glThread;
+
+ /** Just holds a unique ID */
+ protected static DummyContext context;
+
+ /** The PGraphics object using this interface */
+ protected PGraphicsOpenGL pg;
+
+ /** Poller threads to get the keyboard/mouse events from LWJGL */
+ protected static KeyPoller keyPoller;
+ protected static MousePoller mousePoller;
+
+ /** Which texturing targets are enabled */
+ protected static boolean[] texturingTargets = { false, false };
+
+ /** Which textures are bound to each target */
+ protected static int[] boundTextures = { 0, 0 };
+
+ ///////////////////////////////////////////////////////////
+
+ // FBO layer
+
+ protected static boolean fboLayerByDefault = FORCE_SCREEN_FBO;
+ protected static boolean fboLayerCreated = false;
+ protected static boolean fboLayerInUse = false;
+ protected static boolean firstFrame = true;
+ protected static int reqNumSamples;
+ protected static int numSamples;
+ protected static IntBuffer glColorFbo;
+ protected static IntBuffer glMultiFbo;
+ protected static IntBuffer glColorBuf;
+ protected static IntBuffer glColorTex;
+ protected static IntBuffer glDepthStencil;
+ protected static IntBuffer glDepth;
+ protected static IntBuffer glStencil;
+ protected static int fboWidth, fboHeight;
+ protected static int backTex, frontTex;
+
+ protected static boolean needToClearBuffers;
+
+ ///////////////////////////////////////////////////////////
+
+ // Texture rendering
+
+ protected static boolean loadedTex2DShader = false;
+ protected static int tex2DShaderProgram;
+ protected static int tex2DVertShader;
+ protected static int tex2DFragShader;
+ protected static DummyContext tex2DShaderContext;
+ protected static int tex2DVertLoc;
+ protected static int tex2DTCoordLoc;
+
+ protected static boolean loadedTexRectShader = false;
+ protected static int texRectShaderProgram;
+ protected static int texRectVertShader;
+ protected static int texRectFragShader;
+ protected static DummyContext texRectShaderContext;
+ protected static int texRectVertLoc;
+ protected static int texRectTCoordLoc;
+
+ protected static float[] texCoords = {
+ // X, Y, U, V
+ -1.0f, -1.0f, 0.0f, 0.0f,
+ +1.0f, -1.0f, 1.0f, 0.0f,
+ -1.0f, +1.0f, 0.0f, 1.0f,
+ +1.0f, +1.0f, 1.0f, 1.0f
+ };
+ protected static FloatBuffer texData;
+
+ protected static String texVertShaderSource =
+ "attribute vec2 inVertex;" +
+ "attribute vec2 inTexcoord;" +
+ "varying vec2 vertTexcoord;" +
+ "void main() {" +
+ " gl_Position = vec4(inVertex, 0, 1);" +
+ " vertTexcoord = inTexcoord;" +
+ "}";
+
+ protected static String tex2DFragShaderSource =
+ SHADER_PREPROCESSOR_DIRECTIVE +
+ "uniform sampler2D textureSampler;" +
+ "varying vec2 vertTexcoord;" +
+ "void main() {" +
+ " gl_FragColor = texture2D(textureSampler, vertTexcoord.st);" +
+ "}";
+
+ protected static String texRectFragShaderSource =
+ SHADER_PREPROCESSOR_DIRECTIVE +
+ "uniform sampler2DRect textureSampler;" +
+ "varying vec2 vertTexcoord;" +
+ "void main() {" +
+ " gl_FragColor = texture2DRect(textureSampler, vertTexcoord.st);" +
+ "}";
+
+ ///////////////////////////////////////////////////////////
+
+ // Utilities
+
+ protected ByteBuffer byteBuffer;
+ protected IntBuffer intBuffer;
+
+ protected IntBuffer colorBuffer;
+ protected FloatBuffer depthBuffer;
+ protected ByteBuffer stencilBuffer;
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Initialization, finalization
+
+
+ public PGL(PGraphicsOpenGL pg) {
+ this.pg = pg;
+ if (glu == null) {
+ glu = new GLU();
+ }
+ if (glColorTex == null) {
+ glColorTex = allocateIntBuffer(2);
+ glColorFbo = allocateIntBuffer(1);
+ glMultiFbo = allocateIntBuffer(1);
+ glColorBuf = allocateIntBuffer(1);
+ glDepthStencil = allocateIntBuffer(1);
+ glDepth = allocateIntBuffer(1);
+ glStencil = allocateIntBuffer(1);
+
+ fboLayerCreated = false;
+ fboLayerInUse = false;
+ firstFrame = false;
+ needToClearBuffers = false;
+ }
+
+ byteBuffer = allocateByteBuffer(1);
+ intBuffer = allocateIntBuffer(1);
+ }
+
+
+ protected void setFrameRate(float framerate) {
+ }
+
+
+ protected void initSurface(int antialias) {
+ if (canvas != null) {
+ keyPoller.requestStop();
+ mousePoller.requestStop();
+
+ try {
+ Display.setParent(null);
+ } catch (LWJGLException e) {
+ e.printStackTrace();
+ }
+ Display.destroy();
+ pg.parent.remove(canvas);
+ }
+
+ canvas = new Canvas();
+ canvas.setBounds(0, 0, pg.parent.width, pg.parent.height);
+ canvas.setFocusable(true);
+ canvas.requestFocus();
+ canvas.setIgnoreRepaint(true);
+ canvas.setBackground(Color.BLACK);
+
+ pg.parent.setLayout(new BorderLayout());
+ pg.parent.add(canvas, BorderLayout.CENTER);
+
+ try {
+ Display.setParent(canvas);
+ PixelFormat format = new PixelFormat(32, request_alpha_bits,
+ request_depth_bits,
+ request_stencil_bits, 0);
+ Display.create(format);
+ Display.setVSyncEnabled(true);
+ } catch (LWJGLException e) {
+ e.printStackTrace();
+ }
+
+ context = new DummyContext(Display.getDrawable().hashCode());
+
+ keyPoller = new KeyPoller(pg.parent);
+ keyPoller.start();
+
+ mousePoller = new MousePoller(pg.parent);
+ mousePoller.start();
+
+ reqNumSamples = qualityToSamples(antialias);
+ fboLayerCreated = false;
+ fboLayerInUse = false;
+ firstFrame = true;
+ needToClearBuffers = true;
+ }
+
+
+ protected void deleteSurface() {
+ if (glColorTex != null) {
+ deleteTextures(2, glColorTex);
+ deleteFramebuffers(1, glColorFbo);
+ deleteFramebuffers(1, glMultiFbo);
+ deleteRenderbuffers(1, glColorBuf);
+ deleteRenderbuffers(1, glDepthStencil);
+ deleteRenderbuffers(1, glDepth);
+ deleteRenderbuffers(1, glStencil);
+ }
+ fboLayerCreated = false;
+ fboLayerInUse = false;
+ firstFrame = false;
+ needToClearBuffers = false;
+ }
+
+
+ protected void update() {
+ if (!fboLayerCreated) {
+ String ext = getString(EXTENSIONS);
+ if (-1 < ext.indexOf("texture_non_power_of_two")) {
+ fboWidth = pg.width;
+ fboHeight = pg.height;
+ } else {
+ fboWidth = nextPowerOfTwo(pg.width);
+ fboHeight = nextPowerOfTwo(pg.height);
+ }
+
+ if (-1 < ext.indexOf("_framebuffer_multisample")) {
+ numSamples = reqNumSamples;
+ } else {
+ numSamples = 1;
+ }
+ boolean multisample = 1 < numSamples;
+
+ boolean packed = ext.indexOf("packed_depth_stencil") != -1;
+ int depthBits = getDepthBits();
+ int stencilBits = getStencilBits();
+
+ genTextures(2, glColorTex);
+ for (int i = 0; i < 2; i++) {
+ bindTexture(TEXTURE_2D, glColorTex.get(i));
+ texParameteri(TEXTURE_2D, TEXTURE_MIN_FILTER, NEAREST);
+ texParameteri(TEXTURE_2D, TEXTURE_MAG_FILTER, NEAREST);
+ texParameteri(TEXTURE_2D, TEXTURE_WRAP_S, CLAMP_TO_EDGE);
+ texParameteri(TEXTURE_2D, TEXTURE_WRAP_T, CLAMP_TO_EDGE);
+ texImage2D(TEXTURE_2D, 0, RGBA, fboWidth, fboHeight, 0,
+ RGBA, UNSIGNED_BYTE, null);
+ initTexture(TEXTURE_2D, RGBA, fboWidth, fboHeight);
+ }
+ bindTexture(TEXTURE_2D, 0);
+
+ backTex = 0;
+ frontTex = 1;
+
+ genFramebuffers(1, glColorFbo);
+ bindFramebuffer(FRAMEBUFFER, glColorFbo.get(0));
+ framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_2D,
+ glColorTex.get(backTex), 0);
+
+ if (multisample) {
+ // Creating multisampled FBO
+ genFramebuffers(1, glMultiFbo);
+ bindFramebuffer(FRAMEBUFFER, glMultiFbo.get(0));
+
+ // color render buffer...
+ genRenderbuffers(1, glColorBuf);
+ bindRenderbuffer(RENDERBUFFER, glColorBuf.get(0));
+ renderbufferStorageMultisample(RENDERBUFFER, numSamples,
+ RGBA8, fboWidth, fboHeight);
+ framebufferRenderbuffer(FRAMEBUFFER, COLOR_ATTACHMENT0,
+ RENDERBUFFER, glColorBuf.get(0));
+ }
+
+ // Creating depth and stencil buffers
+ if (packed && depthBits == 24 && stencilBits == 8) {
+ // packed depth+stencil buffer
+ genRenderbuffers(1, glDepthStencil);
+ bindRenderbuffer(RENDERBUFFER, glDepthStencil.get(0));
+ if (multisample) {
+ renderbufferStorageMultisample(RENDERBUFFER, numSamples,
+ DEPTH24_STENCIL8, fboWidth, fboHeight);
+ } else {
+ renderbufferStorage(RENDERBUFFER, DEPTH24_STENCIL8,
+ fboWidth, fboHeight);
+ }
+ framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, RENDERBUFFER,
+ glDepthStencil.get(0));
+ framebufferRenderbuffer(FRAMEBUFFER, STENCIL_ATTACHMENT, RENDERBUFFER,
+ glDepthStencil.get(0));
+ } else {
+ // separate depth and stencil buffers
+ if (0 < depthBits) {
+ int depthComponent = DEPTH_COMPONENT16;
+ if (depthBits == 32) {
+ depthComponent = DEPTH_COMPONENT32;
+ } else if (depthBits == 24) {
+ depthComponent = DEPTH_COMPONENT24;
+ } else if (depthBits == 16) {
+ depthComponent = DEPTH_COMPONENT16;
+ }
+
+ genRenderbuffers(1, glDepth);
+ bindRenderbuffer(RENDERBUFFER, glDepth.get(0));
+ if (multisample) {
+ renderbufferStorageMultisample(RENDERBUFFER, numSamples,
+ depthComponent, fboWidth, fboHeight);
+ } else {
+ renderbufferStorage(RENDERBUFFER, depthComponent,
+ fboWidth, fboHeight);
+ }
+ framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT,
+ RENDERBUFFER, glDepth.get(0));
+ }
+
+ if (0 < stencilBits) {
+ int stencilIndex = STENCIL_INDEX1;
+ if (stencilBits == 8) {
+ stencilIndex = STENCIL_INDEX8;
+ } else if (stencilBits == 4) {
+ stencilIndex = STENCIL_INDEX4;
+ } else if (stencilBits == 1) {
+ stencilIndex = STENCIL_INDEX1;
+ }
+
+ genRenderbuffers(1, glStencil);
+ bindRenderbuffer(RENDERBUFFER, glStencil.get(0));
+ if (multisample) {
+ renderbufferStorageMultisample(RENDERBUFFER, numSamples,
+ stencilIndex, fboWidth, fboHeight);
+ } else {
+ renderbufferStorage(RENDERBUFFER, stencilIndex,
+ fboWidth, fboHeight);
+ }
+ framebufferRenderbuffer(FRAMEBUFFER, STENCIL_ATTACHMENT,
+ RENDERBUFFER, glStencil.get(0));
+ }
+ }
+
+ validateFramebuffer();
+
+ // Clear all buffers.
+ clearDepth(1);
+ clearStencil(0);
+ clearColor(0, 0, 0, 0);
+ clear(DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT | COLOR_BUFFER_BIT);
+
+ bindFramebuffer(FRAMEBUFFER, 0);
+
+ fboLayerCreated = true;
+ }
+ }
+
+
+ protected int getReadFramebuffer() {
+ if (fboLayerInUse) {
+ return glColorFbo.get(0);
+ } else {
+ return 0;
+ }
+ }
+
+
+ protected int getDrawFramebuffer() {
+ if (fboLayerInUse) {
+ if (1 < numSamples) {
+ return glMultiFbo.get(0);
+ } else {
+ return glColorFbo.get(0);
+ }
+ } else {
+ return 0;
+ }
+ }
+
+
+ protected int getDefaultDrawBuffer() {
+ if (fboLayerInUse) {
+ return COLOR_ATTACHMENT0;
+ } else {
+ return BACK;
+ }
+ }
+
+
+ protected int getDefaultReadBuffer() {
+ if (fboLayerInUse) {
+ return COLOR_ATTACHMENT0;
+ } else {
+ return FRONT;
+ }
+ }
+
+
+ protected boolean isFBOBacked() {
+ return fboLayerInUse;
+ }
+
+
+ protected void needFBOLayer() {
+ FORCE_SCREEN_FBO = true;
+ }
+
+
+ protected boolean isMultisampled() {
+ return 1 < numSamples;
+ }
+
+
+ protected int getDepthBits() {
+ intBuffer.rewind();
+ getIntegerv(DEPTH_BITS, intBuffer);
+ return intBuffer.get(0);
+ }
+
+
+ protected int getStencilBits() {
+ intBuffer.rewind();
+ getIntegerv(STENCIL_BITS, intBuffer);
+ return intBuffer.get(0);
+ }
+
+
+ protected boolean getDepthTest() {
+ intBuffer.rewind();
+ getBooleanv(DEPTH_TEST, intBuffer);
+ return intBuffer.get(0) == 0 ? false : true;
+ }
+
+
+ protected boolean getDepthWriteMask() {
+ intBuffer.rewind();
+ getBooleanv(DEPTH_WRITEMASK, intBuffer);
+ return intBuffer.get(0) == 0 ? false : true;
+ }
+
+
+ protected Texture wrapBackTexture() {
+ Texture tex = new Texture(pg.parent);
+ tex.init(pg.width, pg.height,
+ glColorTex.get(backTex), TEXTURE_2D, RGBA,
+ fboWidth, fboHeight, NEAREST, NEAREST,
+ CLAMP_TO_EDGE, CLAMP_TO_EDGE);
+ tex.invertedY(true);
+ tex.colorBufferOf(pg);
+ pg.setCache(pg, tex);
+ return tex;
+ }
+
+
+ protected Texture wrapFrontTexture() {
+ Texture tex = new Texture(pg.parent);
+ tex.init(pg.width, pg.height,
+ glColorTex.get(frontTex), TEXTURE_2D, RGBA,
+ fboWidth, fboHeight, NEAREST, NEAREST,
+ CLAMP_TO_EDGE, CLAMP_TO_EDGE);
+ tex.invertedY(true);
+ tex.colorBufferOf(pg);
+ return tex;
+ }
+
+
+ int getBackTextureName() {
+ return glColorTex.get(backTex);
+ }
+
+
+ int getFrontTextureName() {
+ return glColorTex.get(frontTex);
+ }
+
+
+ protected void bindFrontTexture() {
+ if (!texturingIsEnabled(TEXTURE_2D)) {
+ enableTexturing(TEXTURE_2D);
+ }
+ bindTexture(TEXTURE_2D, glColorTex.get(frontTex));
+ }
+
+
+ protected void unbindFrontTexture() {
+ if (textureIsBound(TEXTURE_2D, glColorTex.get(frontTex))) {
+ // We don't want to unbind another texture
+ // that might be bound instead of this one.
+ if (!texturingIsEnabled(TEXTURE_2D)) {
+ enableTexturing(TEXTURE_2D);
+ bindTexture(TEXTURE_2D, 0);
+ disableTexturing(TEXTURE_2D);
+ } else {
+ bindTexture(TEXTURE_2D, 0);
+ }
+ }
+ }
+
+
+ protected void syncBackTexture() {
+ if (1 < numSamples) {
+ bindFramebuffer(READ_FRAMEBUFFER, glMultiFbo.get(0));
+ bindFramebuffer(DRAW_FRAMEBUFFER, glColorFbo.get(0));
+ blitFramebuffer(0, 0, fboWidth, fboHeight,
+ 0, 0, fboWidth, fboHeight,
+ COLOR_BUFFER_BIT, NEAREST);
+ }
+ }
+
+
+ protected int qualityToSamples(int quality) {
+ if (quality <= 1) {
+ return 1;
+ } else {
+ // Number of samples is always an even number:
+ int n = 2 * (quality / 2);
+ return n;
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Frame rendering
+
+
+ protected void beginDraw(boolean clear0) {
+ if (fboLayerInUse(clear0)) {
+ bindFramebuffer(FRAMEBUFFER, glColorFbo.get(0));
+ framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0,
+ TEXTURE_2D, glColorTex.get(backTex), 0);
+
+ if (1 < numSamples) {
+ bindFramebuffer(FRAMEBUFFER, glMultiFbo.get(0));
+ }
+
+ if (firstFrame) {
+ // No need to draw back color buffer because we are in the first frame.
+ clearColor(0, 0, 0, 0);
+ clear(COLOR_BUFFER_BIT);
+ } else if (!clear0) {
+ // Render previous back texture (now is the front) as background,
+ // because no background() is being used ("incremental drawing")
+ drawTexture(TEXTURE_2D, glColorTex.get(frontTex),
+ fboWidth, fboHeight, 0, 0, pg.width, pg.height,
+ 0, 0, pg.width, pg.height);
+ }
+
+ fboLayerInUse = true;
+ } else {
+ fboLayerInUse = false;
+ }
+
+ if (firstFrame) {
+ firstFrame = false;
+ }
+
+ if (!fboLayerByDefault) {
+ // The result of this assignment is the following: if the user requested
+ // at some point the use of the FBO layer, but subsequently didn't do
+ // request it again, then the rendering won't use the FBO layer if not
+ // needed, since it is slower than simple onscreen rendering.
+ FORCE_SCREEN_FBO = false;
+ }
+ }
+
+
+ protected void endDraw(boolean clear0) {
+ if (fboLayerInUse) {
+ syncBackTexture();
+
+ // Draw the contents of the back texture to the screen framebuffer.
+ bindFramebuffer(FRAMEBUFFER, 0);
+
+ clearDepth(1);
+ clearColor(0, 0, 0, 0);
+ clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT);
+
+ // Render current back texture to screen, without blending.
+ disable(BLEND);
+ drawTexture(TEXTURE_2D, glColorTex.get(backTex),
+ fboWidth, fboHeight, 0, 0, pg.width, pg.height,
+ 0, 0, pg.width, pg.height);
+
+ // Swapping front and back textures.
+ int temp = frontTex;
+ frontTex = backTex;
+ backTex = temp;
+ }
+ flush();
+ }
+
+
+ protected boolean canDraw() {
+ return pg.initialized && pg.parent.isDisplayable();
+ }
+
+
+ protected void requestDraw() {
+ if (pg.initialized) {
+ glThread = Thread.currentThread();
+ pg.parent.handleDraw();
+ Display.update();
+ }
+ }
+
+
+ protected static boolean glThreadIsCurrent() {
+ return Thread.currentThread() == glThread;
+ }
+
+
+ protected boolean fboLayerInUse(boolean clear0) {
+ boolean cond = !clear0 || FORCE_SCREEN_FBO || 1 < numSamples;
+ return cond && glColorFbo.get(0) != 0;
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Caps query
+
+
+ public String getString(int name) {
+ return GL11.glGetString(name);
+ }
+
+
+ public void getIntegerv(int name, IntBuffer values) {
+ if (-1 < name) {
+ GL11.glGetInteger(name, values);
+ } else {
+ fillIntBuffer(values, 0, values.capacity() - 1, 0);
+ }
+ }
+
+
+ public void getFloatv(int name, FloatBuffer values) {
+ if (-1 < name) {
+ GL11.glGetFloat(name, values);
+ } else {
+ fillFloatBuffer(values, 0, values.capacity() - 1, 0);
+ }
+ }
+
+
+ public void getBooleanv(int name, IntBuffer values) {
+ if (-1 < name) {
+ if (byteBuffer.capacity() < values.capacity()) {
+ byteBuffer = allocateDirectByteBuffer(values.capacity());
+ }
+ GL11.glGetBoolean(name, byteBuffer);
+ for (int i = 0; i < values.capacity(); i++) {
+ values.put(i, byteBuffer.get(i));
+ }
+ } else {
+ fillIntBuffer(values, 0, values.capacity() - 1, 0);
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Enable/disable caps
+
+
+ public void enable(int cap) {
+ if (-1 < cap) {
+ GL11.glEnable(cap);
+ }
+ }
+
+
+ public void disable(int cap) {
+ if (-1 < cap) {
+ GL11.glDisable(cap);
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Render control
+
+
+ public void flush() {
+ GL11.glFlush();
+ }
+
+
+ public void finish() {
+ GL11.glFinish();
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Error handling
+
+
+ public int getError() {
+ return GL11.glGetError();
+ }
+
+
+ public String errorString(int err) {
+ return glu.gluErrorString(err);
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Rendering options
+
+
+ public void frontFace(int mode) {
+ GL11.glFrontFace(mode);
+ }
+
+
+ public void cullFace(int mode) {
+ GL11.glCullFace(mode);
+ }
+
+
+ public void depthMask(boolean flag) {
+ GL11.glDepthMask(flag);
+ }
+
+
+ public void depthFunc(int func) {
+ GL11.glDepthFunc(func);
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Textures
+
+
+ public void genTextures(int n, IntBuffer ids) {
+ GL11.glGenTextures(ids);
+ }
+
+
+ public void deleteTextures(int n, IntBuffer ids) {
+ GL11.glDeleteTextures(ids);
+ }
+
+
+ public void activeTexture(int unit) {
+ GL13.glActiveTexture(unit);
+ }
+
+
+ public void bindTexture(int target, int id) {
+ GL11.glBindTexture(target, id);
+ if (target == TEXTURE_2D) {
+ boundTextures[0] = id;
+ } else if (target == TEXTURE_RECTANGLE) {
+ boundTextures[1] = id;
+ }
+ }
+
+
+ public void texImage2D(int target, int level, int internalFormat,
+ int width, int height, int border, int format,
+ int type, Buffer data) {
+ GL11.glTexImage2D(target, level, internalFormat,
+ width, height, border, format, type, (IntBuffer)data);
+ }
+
+
+ public void texSubImage2D(int target, int level, int xOffset, int yOffset,
+ int width, int height, int format,
+ int type, Buffer data) {
+ GL11.glTexSubImage2D(target, level, xOffset, yOffset,
+ width, height, format, type, (IntBuffer)data);
+ }
+
+
+ public void texParameteri(int target, int param, int value) {
+ GL11.glTexParameteri(target, param, value);
+ }
+
+
+ public void texParameterf(int target, int param, float value) {
+ GL11.glTexParameterf(target, param, value);
+ }
+
+
+ public void getTexParameteriv(int target, int param, IntBuffer values) {
+ GL11.glGetTexParameter(target, param, values);
+ }
+
+
+ public void generateMipmap(int target) {
+ GL30.glGenerateMipmap(target);
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Vertex Buffers
+
+
+ public void genBuffers(int n, IntBuffer ids) {
+ GL15.glGenBuffers(ids);
+ }
+
+
+ public void deleteBuffers(int n, IntBuffer ids) {
+ GL15.glDeleteBuffers(ids);
+ }
+
+
+ public void bindBuffer(int target, int id) {
+ GL15.glBindBuffer(target, id);
+ }
+
+
+ public void bufferData(int target, int size, Buffer data, int usage) {
+ if (data == null) {
+ FloatBuffer empty = BufferUtils.createFloatBuffer(size);
+ GL15.glBufferData(target, empty, usage);
+ } else {
+ if (data instanceof ByteBuffer) {
+ GL15.glBufferData(target, (ByteBuffer)data, usage);
+ } else if (data instanceof ShortBuffer) {
+ GL15.glBufferData(target, (ShortBuffer)data, usage);
+ } else if (data instanceof IntBuffer) {
+ GL15.glBufferData(target, (IntBuffer)data, usage);
+ } else if (data instanceof FloatBuffer) {
+ GL15.glBufferData(target, (FloatBuffer)data, usage);
+ }
+ }
+ }
+
+
+ public void bufferSubData(int target, int offset, int size, Buffer data) {
+ if (data instanceof ByteBuffer) {
+ GL15.glBufferSubData(target, offset, (ByteBuffer)data);
+ } else if (data instanceof ShortBuffer) {
+ GL15.glBufferSubData(target, offset, (ShortBuffer)data);
+ } else if (data instanceof IntBuffer) {
+ GL15.glBufferSubData(target, offset, (IntBuffer)data);
+ } else if (data instanceof FloatBuffer) {
+ GL15.glBufferSubData(target, offset, (FloatBuffer)data);
+ }
+ }
+
+
+ public void drawArrays(int mode, int first, int count) {
+ GL11.glDrawArrays(mode, first, count);
+ }
+
+
+ public void drawElements(int mode, int count, int type, int offset) {
+ GL11.glDrawElements(mode, count, type, offset);
+ }
+
+
+ public void enableVertexAttribArray(int loc) {
+ GL20.glEnableVertexAttribArray(loc);
+ }
+
+
+ public void disableVertexAttribArray(int loc) {
+ GL20.glDisableVertexAttribArray(loc);
+ }
+
+
+ public void vertexAttribPointer(int loc, int size, int type,
+ boolean normalized, int stride, int offset) {
+ GL20.glVertexAttribPointer(loc, size, type, normalized, stride, offset);
+ }
+
+
+ public void vertexAttribPointer(int loc, int size, int type,
+ boolean normalized, int stride, Buffer data) {
+ if (type == UNSIGNED_INT) {
+ GL20.glVertexAttribPointer(loc, size, true, normalized, stride, (IntBuffer)data);
+ } else if (type == UNSIGNED_BYTE) {
+ GL20.glVertexAttribPointer(loc, size, true, normalized, stride, (ByteBuffer)data);
+ } else if (type == UNSIGNED_SHORT) {
+ GL20.glVertexAttribPointer(loc, size, true, normalized, stride, (ShortBuffer)data);
+ } else if (type == FLOAT) {
+ GL20.glVertexAttribPointer(loc, size, normalized, stride, (FloatBuffer)data);
+ }
+ }
+
+
+ public ByteBuffer mapBuffer(int target, int access) {
+ return GL15.glMapBuffer(target, access, null);
+ }
+
+
+ public ByteBuffer mapBufferRange(int target, int offset, int length,
+ int access) {
+ return GL30.glMapBufferRange(target, offset, length, access, null);
+ }
+
+
+ public void unmapBuffer(int target) {
+ GL15.glUnmapBuffer(target);
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Framebuffers, renderbuffers
+
+
+ public void genFramebuffers(int n, IntBuffer ids) {
+ GL30.glGenFramebuffers(ids);
+ }
+
+
+ public void deleteFramebuffers(int n, IntBuffer ids) {
+ GL30.glDeleteFramebuffers(ids);
+ }
+
+
+ public void genRenderbuffers(int n, IntBuffer ids) {
+ GL30.glGenRenderbuffers(ids);
+ }
+
+
+ public void deleteRenderbuffers(int n, IntBuffer ids) {
+ GL30.glDeleteRenderbuffers(ids);
+ }
+
+
+ public void bindFramebuffer(int target, int id) {
+ GL30.glBindFramebuffer(target, id);
+ }
+
+
+ public void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1,
+ int dstX0, int dstY0, int dstX1, int dstY1,
+ int mask, int filter) {
+ GL30.glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1, mask, filter);
+ }
+
+
+ public void framebufferTexture2D(int target, int attachment, int texTarget,
+ int texId, int level) {
+ GL30.glFramebufferTexture2D(target, attachment, texTarget, texId, level);
+ }
+
+
+ public void bindRenderbuffer(int target, int id) {
+ GL30.glBindRenderbuffer(target, id);
+ }
+
+
+ public void renderbufferStorageMultisample(int target, int samples,
+ int format, int width, int height){
+ GL30.glRenderbufferStorageMultisample(target, samples, format,
+ width, height);
+ }
+
+
+ public void renderbufferStorage(int target, int format,
+ int width, int height) {
+ GL30.glRenderbufferStorage(target, format, width, height);
+ }
+
+
+ public void framebufferRenderbuffer(int target, int attachment,
+ int rendbufTarget, int rendbufId) {
+ GL30.glFramebufferRenderbuffer(target, attachment, rendbufTarget, rendbufId);
+ }
+
+
+ public int checkFramebufferStatus(int target) {
+ return GL30.glCheckFramebufferStatus(target);
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Shaders
+
+
+ public int createProgram() {
+ return GL20.glCreateProgram();
+ }
+
+
+ public void deleteProgram(int id) {
+ GL20.glDeleteProgram(id);
+ }
+
+
+ public int createShader(int type) {
+ return GL20.glCreateShader(type);
+ }
+
+
+ public void deleteShader(int id) {
+ GL20.glDeleteShader(id);
+ }
+
+
+ public void linkProgram(int prog) {
+ GL20.glLinkProgram(prog);
+ }
+
+
+ public void validateProgram(int prog) {
+ GL20.glValidateProgram(prog);
+ }
+
+
+ public void useProgram(int prog) {
+ GL20.glUseProgram(prog);
+ }
+
+
+ public int getAttribLocation(int prog, String name) {
+ return GL20.glGetAttribLocation(prog, name);
+ }
+
+
+ public int getUniformLocation(int prog, String name) {
+ return GL20.glGetUniformLocation(prog, name);
+ }
+
+
+ public void uniform1i(int loc, int value) {
+ GL20.glUniform1i(loc, value);
+ }
+
+
+ public void uniform2i(int loc, int value0, int value1) {
+ GL20.glUniform2i(loc, value0, value1);
+ }
+
+
+ public void uniform3i(int loc, int value0, int value1, int value2) {
+ GL20.glUniform3i(loc, value0, value1, value2);
+ }
+
+
+ public void uniform4i(int loc, int value0, int value1, int value2,
+ int value3) {
+ GL20.glUniform4i(loc, value0, value1, value2, value3);
+ }
+
+
+ public void uniform1f(int loc, float value) {
+ GL20.glUniform1f(loc, value);
+ }
+
+
+ public void uniform2f(int loc, float value0, float value1) {
+ GL20.glUniform2f(loc, value0, value1);
+ }
+
+
+ public void uniform3f(int loc, float value0, float value1, float value2) {
+ GL20.glUniform3f(loc, value0, value1, value2);
+ }
+
+
+ public void uniform4f(int loc, float value0, float value1, float value2,
+ float value3) {
+ GL20.glUniform4f(loc, value0, value1, value2, value3);
+ }
+
+
+ public void uniform1iv(int loc, int count, IntBuffer v) {
+ GL20.glUniform1(loc, v);
+ }
+
+
+ public void uniform2iv(int loc, int count, IntBuffer v) {
+ GL20.glUniform2(loc, v);
+ }
+
+
+ public void uniform3iv(int loc, int count, IntBuffer v) {
+ GL20.glUniform3(loc, v);
+ }
+
+
+ public void uniform4iv(int loc, int count, IntBuffer v) {
+ GL20.glUniform4(loc, v);
+ }
+
+
+ public void uniform1fv(int loc, int count, FloatBuffer v) {
+ GL20.glUniform1(loc, v);
+ }
+
+
+ public void uniform2fv(int loc, int count, FloatBuffer v) {
+ GL20.glUniform2(loc, v);
+ }
+
+
+ public void uniform3fv(int loc, int count, FloatBuffer v) {
+ GL20.glUniform3(loc, v);
+ }
+
+
+ public void uniform4fv(int loc, int count, FloatBuffer v) {
+ GL20.glUniform4(loc, v);
+ }
+
+
+ public void uniformMatrix2fv(int loc, int count, boolean transpose,
+ FloatBuffer mat) {
+ GL20.glUniformMatrix2(loc, transpose, mat);
+ }
+
+
+ public void uniformMatrix3fv(int loc, int count, boolean transpose,
+ FloatBuffer mat) {
+ GL20.glUniformMatrix3(loc, transpose, mat);
+ }
+
+
+ public void uniformMatrix4fv(int loc, int count, boolean transpose,
+ FloatBuffer mat) {
+ GL20.glUniformMatrix4(loc, transpose, mat);
+ }
+
+
+ public void vertexAttrib1f(int loc, float value) {
+ GL20.glVertexAttrib1f(loc, value);
+ }
+
+
+ public void vertexAttrib2f(int loc, float value0, float value1) {
+ GL20.glVertexAttrib2f(loc, value0, value1);
+ }
+
+
+ public void vertexAttrib3f(int loc, float value0, float value1, float value2){
+ GL20.glVertexAttrib3f(loc, value0, value1, value2);
+ }
+
+
+ public void vertexAttrib4f(int loc, float value0, float value1, float value2,
+ float value3) {
+ GL20.glVertexAttrib4f(loc, value0, value1, value2, value3);
+ }
+
+
+ public void shaderSource(int id, String source) {
+ GL20.glShaderSource(id, source);
+ }
+
+
+ public void compileShader(int id) {
+ GL20.glCompileShader(id);
+ }
+
+
+ public void attachShader(int prog, int shader) {
+ GL20.glAttachShader(prog, shader);
+ }
+
+
+ public void getShaderiv(int shader, int pname, IntBuffer params) {
+ GL20.glGetShader(shader, pname, params);
+ }
+
+
+ public String getShaderInfoLog(int shader) {
+ int len = GL20.glGetShaderi(shader, GL20.GL_INFO_LOG_LENGTH);
+ return GL20.glGetShaderInfoLog(shader, len);
+ }
+
+
+ public void getProgramiv(int prog, int pname, IntBuffer params) {
+ GL20.glGetProgram(prog, pname, params);
+ }
+
+
+ public String getProgramInfoLog(int prog) {
+ int len = GL20.glGetProgrami(prog, GL20.GL_INFO_LOG_LENGTH);
+ return GL20.glGetProgramInfoLog(prog, len);
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Viewport
+
+
+ public void viewport(int x, int y, int width, int height) {
+ GL11.glViewport(x, y, width, height);
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Clipping (scissor test)
+
+
+ public void scissor(int x, int y, int w, int h) {
+ GL11.glScissor(x, y, w, h);
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Blending
+
+
+ public void blendEquation(int eq) {
+ GL14.glBlendEquation(eq);
+ }
+
+
+ public void blendFunc(int srcFactor, int dstFactor) {
+ GL11.glBlendFunc(srcFactor, dstFactor);
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Pixels
+
+
+ public void readBuffer(int buf) {
+ GL11.glReadBuffer(buf);
+ }
+
+
+ public void readPixels(int x, int y, int width, int height, int format,
+ int type, Buffer buffer) {
+
+ GL11.glReadPixels(x, y, width, height, format, type, (IntBuffer)buffer);
+ }
+
+
+ public void drawBuffer(int buf) {
+ GL11.glDrawBuffer(buf);
+ }
+
+
+ public void clearDepth(float d) {
+ GL11.glClearDepth(d);
+ }
+
+
+ public void clearStencil(int s) {
+ GL11.glClearStencil(s);
+ }
+
+
+ public void colorMask(boolean wr, boolean wg, boolean wb, boolean wa) {
+ GL11.glColorMask(wr, wg, wb, wa);
+ }
+
+
+ public void clearColor(float r, float g, float b, float a) {
+ GL11.glClearColor(r, g, b, a);
+ }
+
+
+ public void clear(int mask) {
+ GL11.glClear(mask);
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Context interface
+
+
+ protected Context createEmptyContext() {
+ return new Context();
+ }
+
+
+ protected Context getCurrentContext() {
+ return new Context(context);
+ }
+
+
+ protected class Context {
+ protected int id;
+
+ Context() {
+ id = -1;
+ }
+
+ Context(DummyContext context) {
+ if (context != null) {
+ id = context.hashCode();
+ } else {
+ id = -1;
+ }
+ }
+
+ boolean current() {
+ return equal(context);
+ }
+
+ boolean equal(DummyContext context) {
+ if (id == -1 || context == null) {
+ // A null context means a still non-created resource,
+ // so it is considered equal to the argument.
+ return true;
+ } else {
+ return id == context.hashCode();
+ }
+ }
+
+ int id() {
+ return id;
+ }
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Tessellator interface
+
+
+ protected Tessellator createTessellator(TessellatorCallback callback) {
+ return new Tessellator(callback);
+ }
+
+
+ protected class Tessellator {
+ protected GLUtessellator tess;
+ protected TessellatorCallback callback;
+ protected GLUCallback gluCallback;
+
+ public Tessellator(TessellatorCallback callback) {
+ this.callback = callback;
+ tess = GLU.gluNewTess();
+ gluCallback = new GLUCallback();
+
+ tess.gluTessCallback(GLU.GLU_TESS_BEGIN, gluCallback);
+ tess.gluTessCallback(GLU.GLU_TESS_END, gluCallback);
+ tess.gluTessCallback(GLU.GLU_TESS_VERTEX, gluCallback);
+ tess.gluTessCallback(GLU.GLU_TESS_COMBINE, gluCallback);
+ tess.gluTessCallback(GLU.GLU_TESS_ERROR, gluCallback);
+ }
+
+ public void beginPolygon() {
+ tess.gluTessBeginPolygon(null);
+ }
+
+ public void endPolygon() {
+ tess.gluTessEndPolygon();
+ }
+
+ public void setWindingRule(int rule) {
+ tess.gluTessProperty(GLU.GLU_TESS_WINDING_RULE, rule);
+ }
+
+ public void beginContour() {
+ tess.gluTessBeginContour();
+ }
+
+ public void endContour() {
+ tess.gluTessEndContour();
+ }
+
+ public void addVertex(double[] v) {
+ tess.gluTessVertex(v, 0, v);
+ }
+
+ protected class GLUCallback extends GLUtessellatorCallbackAdapter {
+ @Override
+ public void begin(int type) {
+ callback.begin(type);
+ }
+
+ @Override
+ public void end() {
+ callback.end();
+ }
+
+ @Override
+ public void vertex(Object data) {
+ callback.vertex(data);
+ }
+
+ @Override
+ public void combine(double[] coords, Object[] data,
+ float[] weight, Object[] outData) {
+ callback.combine(coords, data, weight, outData);
+ }
+
+ @Override
+ public void error(int errnum) {
+ callback.error(errnum);
+ }
+ }
+ }
+
+
+ protected String tessError(int err) {
+ return glu.gluErrorString(err);
+ }
+
+ protected interface TessellatorCallback {
+ public void begin(int type);
+ public void end();
+ public void vertex(Object data);
+ public void combine(double[] coords, Object[] data,
+ float[] weight, Object[] outData);
+ public void error(int errnum);
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Utility functions
+
+
+ protected boolean contextIsCurrent(Context other) {
+ return other == null || other.current();
+ }
+
+
+ protected void enableTexturing(int target) {
+ enable(target);
+ if (target == TEXTURE_2D) {
+ texturingTargets[0] = true;
+ } else if (target == TEXTURE_RECTANGLE) {
+ texturingTargets[1] = true;
+ }
+ }
+
+
+ protected void disableTexturing(int target) {
+ disable(target);
+ if (target == TEXTURE_2D) {
+ texturingTargets[0] = false;
+ } else if (target == TEXTURE_RECTANGLE) {
+ texturingTargets[1] = false;
+ }
+ }
+
+
+ protected boolean texturingIsEnabled(int target) {
+ if (target == TEXTURE_2D) {
+ return texturingTargets[0];
+ } else if (target == TEXTURE_RECTANGLE) {
+ return texturingTargets[1];
+ } else {
+ return false;
+ }
+ }
+
+
+ protected boolean textureIsBound(int target, int id) {
+ if (target == TEXTURE_2D) {
+ return boundTextures[0] == id;
+ } else if (target == TEXTURE_RECTANGLE) {
+ return boundTextures[1] == id;
+ } else {
+ return false;
+ }
+ }
+
+
+ protected void initTexture(int target, int format, int width, int height) {
+ IntBuffer texels = PGL.allocateDirectIntBuffer(16 * 16);
+ for (int y = 0; y < height; y += 16) {
+ int h = PApplet.min(16, height - y);
+ for (int x = 0; x < width; x += 16) {
+ int w = PApplet.min(16, width - x);
+ texSubImage2D(target, 0, x, y, w, h, format, UNSIGNED_BYTE, texels);
+ }
+ }
+ }
+
+
+ protected void copyToTexture(int target, int format, int id, int x, int y,
+ int w, int h, IntBuffer buffer) {
+ activeTexture(TEXTURE0);
+ boolean enabledTex = false;
+ if (!texturingIsEnabled(target)) {
+ enableTexturing(target);
+ enabledTex = true;
+ }
+ bindTexture(target, id);
+ texSubImage2D(target, 0, x, y, w, h, format, UNSIGNED_BYTE, buffer);
+ bindTexture(target, 0);
+ if (enabledTex) {
+ disableTexturing(target);
+ }
+ }
+
+
+ protected void drawTexture(int target, int id, int width, int height,
+ int X0, int Y0, int X1, int Y1) {
+ drawTexture(target, id, width, height, X0, Y0, X1, Y1, X0, Y0, X1, Y1);
+ }
+
+
+ protected void drawTexture(int target, int id, int width, int height,
+ int texX0, int texY0, int texX1, int texY1,
+ int scrX0, int scrY0, int scrX1, int scrY1) {
+ if (target == TEXTURE_2D) {
+ drawTexture2D(id, width, height,
+ texX0, texY0, texX1, texY1,
+ scrX0, scrY0, scrX1, scrY1);
+ } else if (target == TEXTURE_RECTANGLE) {
+ drawTextureRect(id, width, height,
+ texX0, texY0, texX1, texY1,
+ scrX0, scrY0, scrX1, scrY1);
+ }
+ }
+
+
+ protected void drawTexture2D(int id, int width, int height,
+ int texX0, int texY0, int texX1, int texY1,
+ int scrX0, int scrY0, int scrX1, int scrY1) {
+ if (!loadedTex2DShader ||
+ tex2DShaderContext.hashCode() != context.hashCode()) {
+ tex2DVertShader = createShader(VERTEX_SHADER, texVertShaderSource);
+ tex2DFragShader = createShader(FRAGMENT_SHADER, tex2DFragShaderSource);
+ if (0 < tex2DVertShader && 0 < tex2DFragShader) {
+ tex2DShaderProgram = createProgram(tex2DVertShader, tex2DFragShader);
+ }
+ if (0 < tex2DShaderProgram) {
+ tex2DVertLoc = getAttribLocation(tex2DShaderProgram, "inVertex");
+ tex2DTCoordLoc = getAttribLocation(tex2DShaderProgram, "inTexcoord");
+ }
+ loadedTex2DShader = true;
+ tex2DShaderContext = context;
+ }
+
+ if (texData == null) {
+ texData = allocateDirectFloatBuffer(texCoords.length);
+ }
+
+ if (0 < tex2DShaderProgram) {
+ // The texture overwrites anything drawn earlier.
+ boolean depthTest = getDepthTest();
+ disable(DEPTH_TEST);
+
+ // When drawing the texture we don't write to the
+ // depth mask, so the texture remains in the background
+ // and can be occluded by anything drawn later, even if
+ // if it is behind it.
+ boolean depthMask = getDepthWriteMask();
+ depthMask(false);
+
+ useProgram(tex2DShaderProgram);
+
+ enableVertexAttribArray(tex2DVertLoc);
+ enableVertexAttribArray(tex2DTCoordLoc);
+
+ // Vertex coordinates of the textured quad are specified
+ // in normalized screen space (-1, 1):
+ // Corner 1
+ texCoords[ 0] = 2 * (float)scrX0 / pg.width - 1;
+ texCoords[ 1] = 2 * (float)scrY0 / pg.height - 1;
+ texCoords[ 2] = (float)texX0 / width;
+ texCoords[ 3] = (float)texY0 / height;
+ // Corner 2
+ texCoords[ 4] = 2 * (float)scrX1 / pg.width - 1;
+ texCoords[ 5] = 2 * (float)scrY0 / pg.height - 1;
+ texCoords[ 6] = (float)texX1 / width;
+ texCoords[ 7] = (float)texY0 / height;
+ // Corner 3
+ texCoords[ 8] = 2 * (float)scrX0 / pg.width - 1;
+ texCoords[ 9] = 2 * (float)scrY1 / pg.height - 1;
+ texCoords[10] = (float)texX0 / width;
+ texCoords[11] = (float)texY1 / height;
+ // Corner 4
+ texCoords[12] = 2 * (float)scrX1 / pg.width - 1;
+ texCoords[13] = 2 * (float)scrY1 / pg.height - 1;
+ texCoords[14] = (float)texX1 / width;
+ texCoords[15] = (float)texY1 / height;
+
+ texData.rewind();
+ texData.put(texCoords);
+
+ activeTexture(TEXTURE0);
+ boolean enabledTex = false;
+ if (!texturingIsEnabled(TEXTURE_2D)) {
+ enableTexturing(TEXTURE_2D);
+ enabledTex = true;
+ }
+ bindTexture(TEXTURE_2D, id);
+
+ bindBuffer(ARRAY_BUFFER, 0); // Making sure that no VBO is bound at this point.
+
+ texData.position(0);
+ vertexAttribPointer(tex2DVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT,
+ texData);
+ texData.position(2);
+ vertexAttribPointer(tex2DTCoordLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT,
+ texData);
+
+ drawArrays(TRIANGLE_STRIP, 0, 4);
+
+ bindTexture(TEXTURE_2D, 0);
+ if (enabledTex) {
+ disableTexturing(TEXTURE_2D);
+ }
+
+ disableVertexAttribArray(tex2DVertLoc);
+ disableVertexAttribArray(tex2DTCoordLoc);
+
+ useProgram(0);
+
+ if (depthTest) {
+ enable(DEPTH_TEST);
+ } else {
+ disable(DEPTH_TEST);
+ }
+ depthMask(depthMask);
+ }
+ }
+
+
+ protected void drawTextureRect(int id, int width, int height,
+ int texX0, int texY0, int texX1, int texY1,
+ int scrX0, int scrY0, int scrX1, int scrY1) {
+ if (!loadedTexRectShader ||
+ texRectShaderContext.hashCode() != context.hashCode()) {
+ texRectVertShader = createShader(VERTEX_SHADER, texVertShaderSource);
+ texRectFragShader = createShader(FRAGMENT_SHADER, texRectFragShaderSource);
+ if (0 < texRectVertShader && 0 < texRectFragShader) {
+ texRectShaderProgram = createProgram(texRectVertShader,
+ texRectFragShader);
+ }
+ if (0 < texRectShaderProgram) {
+ texRectVertLoc = getAttribLocation(texRectShaderProgram, "inVertex");
+ texRectTCoordLoc = getAttribLocation(texRectShaderProgram, "inTexcoord");
+ }
+ loadedTexRectShader = true;
+ texRectShaderContext = context;
+ }
+
+ if (texData == null) {
+ texData = allocateDirectFloatBuffer(texCoords.length);
+ }
+
+ if (0 < texRectShaderProgram) {
+ // The texture overwrites anything drawn earlier.
+ boolean depthTest = getDepthTest();
+ disable(DEPTH_TEST);
+
+ // When drawing the texture we don't write to the
+ // depth mask, so the texture remains in the background
+ // and can be occluded by anything drawn later, even if
+ // if it is behind it.
+ boolean depthMask = getDepthWriteMask();
+ depthMask(false);
+
+ useProgram(texRectShaderProgram);
+
+ enableVertexAttribArray(texRectVertLoc);
+ enableVertexAttribArray(texRectTCoordLoc);
+
+ // Vertex coordinates of the textured quad are specified
+ // in normalized screen space (-1, 1):
+ // Corner 1
+ texCoords[ 0] = 2 * (float)scrX0 / pg.width - 1;
+ texCoords[ 1] = 2 * (float)scrY0 / pg.height - 1;
+ texCoords[ 2] = texX0;
+ texCoords[ 3] = texY0;
+ // Corner 2
+ texCoords[ 4] = 2 * (float)scrX1 / pg.width - 1;
+ texCoords[ 5] = 2 * (float)scrY0 / pg.height - 1;
+ texCoords[ 6] = texX1;
+ texCoords[ 7] = texY0;
+ // Corner 3
+ texCoords[ 8] = 2 * (float)scrX0 / pg.width - 1;
+ texCoords[ 9] = 2 * (float)scrY1 / pg.height - 1;
+ texCoords[10] = texX0;
+ texCoords[11] = texY1;
+ // Corner 4
+ texCoords[12] = 2 * (float)scrX1 / pg.width - 1;
+ texCoords[13] = 2 * (float)scrY1 / pg.height - 1;
+ texCoords[14] = texX1;
+ texCoords[15] = texY1;
+
+ texData.rewind();
+ texData.put(texCoords);
+
+ activeTexture(TEXTURE0);
+ boolean enabledTex = false;
+ if (!texturingIsEnabled(TEXTURE_RECTANGLE)) {
+ enableTexturing(TEXTURE_RECTANGLE);
+ enabledTex = true;
+ }
+ bindTexture(TEXTURE_RECTANGLE, id);
+
+ bindBuffer(ARRAY_BUFFER, 0); // Making sure that no VBO is bound at this point.
+
+ texData.position(0);
+ vertexAttribPointer(texRectVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT,
+ texData);
+ texData.position(2);
+ vertexAttribPointer(texRectTCoordLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT,
+ texData);
+
+ drawArrays(TRIANGLE_STRIP, 0, 4);
+
+ bindTexture(TEXTURE_RECTANGLE, 0);
+ if (enabledTex) {
+ disableTexturing(TEXTURE_RECTANGLE);
+ }
+
+ disableVertexAttribArray(texRectVertLoc);
+ disableVertexAttribArray(texRectTCoordLoc);
+
+ useProgram(0);
+
+ if (depthTest) {
+ enable(DEPTH_TEST);
+ } else {
+ disable(DEPTH_TEST);
+ }
+ depthMask(depthMask);
+ }
+ }
+
+
+ protected int getColorValue(int scrX, int scrY) {
+ if (colorBuffer == null) {
+ colorBuffer = IntBuffer.allocate(1);
+ }
+ colorBuffer.rewind();
+ readPixels(scrX, pg.height - scrY - 1, 1, 1, RGBA, UNSIGNED_BYTE,
+ colorBuffer);
+ return colorBuffer.get();
+ }
+
+
+ protected float getDepthValue(int scrX, int scrY) {
+ if (depthBuffer == null) {
+ depthBuffer = FloatBuffer.allocate(1);
+ }
+ depthBuffer.rewind();
+ readPixels(scrX, pg.height - scrY - 1, 1, 1, DEPTH_COMPONENT, FLOAT,
+ depthBuffer);
+ return depthBuffer.get(0);
+ }
+
+
+ protected byte getStencilValue(int scrX, int scrY) {
+ if (stencilBuffer == null) {
+ stencilBuffer = ByteBuffer.allocate(1);
+ }
+ readPixels(scrX, pg.height - scrY - 1, 1, 1, STENCIL_INDEX,
+ UNSIGNED_BYTE, stencilBuffer);
+ return stencilBuffer.get(0);
+ }
+
+
+ // bit shifting this might be more efficient
+ protected static int nextPowerOfTwo(int val) {
+ int ret = 1;
+ while (ret < val) {
+ ret <<= 1;
+ }
+ return ret;
+ }
+
+
+ /**
+ * Converts input native OpenGL value (RGBA on big endian, ABGR on little
+ * endian) to Java ARGB.
+ */
+ protected static int nativeToJavaARGB(int color) {
+ if (BIG_ENDIAN) { // RGBA to ARGB
+ return (color & 0xff000000) |
+ ((color >> 8) & 0x00ffffff);
+ } else { // ABGR to ARGB
+ return (color & 0xff000000) |
+ ((color << 16) & 0xff0000) |
+ (color & 0xff00) |
+ ((color >> 16) & 0xff);
+ }
+ }
+
+
+ /**
+ * Converts input array of native OpenGL values (RGBA on big endian, ABGR on
+ * little endian) representing an image of width x height resolution to Java
+ * ARGB. It also rearranges the elements in the array so that the image is
+ * flipped vertically.
+ */
+ protected static void nativeToJavaARGB(int[] pixels, int width, int height) {
+ int index = 0;
+ int yindex = (height - 1) * width;
+ for (int y = 0; y < height / 2; y++) {
+ if (BIG_ENDIAN) { // RGBA to ARGB
+ for (int x = 0; x < width; x++) {
+ int temp = pixels[index];
+ pixels[index] = (pixels[yindex] & 0xff000000) |
+ ((pixels[yindex] >> 8) & 0x00ffffff);
+ pixels[yindex] = (temp & 0xff000000) |
+ ((temp >> 8) & 0x00ffffff);
+ index++;
+ yindex++;
+ }
+ } else { // ABGR to ARGB
+ for (int x = 0; x < width; x++) {
+ int temp = pixels[index];
+ pixels[index] = (pixels[yindex] & 0xff000000) |
+ ((pixels[yindex] << 16) & 0xff0000) |
+ (pixels[yindex] & 0xff00) |
+ ((pixels[yindex] >> 16) & 0xff);
+ pixels[yindex] = (temp & 0xff000000) |
+ ((temp << 16) & 0xff0000) |
+ (temp & 0xff00) |
+ ((temp >> 16) & 0xff);
+ index++;
+ yindex++;
+ }
+ }
+ yindex -= width * 2;
+ }
+
+ // Flips image
+ if ((height % 2) == 1) {
+ index = (height / 2) * width;
+ if (BIG_ENDIAN) { // RGBA to ARGB
+ for (int x = 0; x < width; x++) {
+ pixels[index] = (pixels[index] & 0xff000000) |
+ ((pixels[index] >> 8) & 0x00ffffff);
+ index++;
+ }
+ } else { // ABGR to ARGB
+ for (int x = 0; x < width; x++) {
+ pixels[index] = (pixels[index] & 0xff000000) |
+ ((pixels[index] << 16) & 0xff0000) |
+ (pixels[index] & 0xff00) |
+ ((pixels[index] >> 16) & 0xff);
+ index++;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Converts input native OpenGL value (RGBA on big endian, ABGR on little
+ * endian) to Java RGB, so that the alpha component of the result is set
+ * to opaque (255).
+ */
+ protected static int nativeToJavaRGB(int color) {
+ if (BIG_ENDIAN) { // RGBA to ARGB
+ return ((color << 8) & 0xffffff00) | 0xff;
+ } else { // ABGR to ARGB
+ return 0xff000000 | ((color << 16) & 0xff0000) |
+ (color & 0xff00) |
+ ((color >> 16) & 0xff);
+ }
+ }
+
+
+ /**
+ * Converts input array of native OpenGL values (RGBA on big endian, ABGR on
+ * little endian) representing an image of width x height resolution to Java
+ * RGB, so that the alpha component of all pixels is set to opaque (255). It
+ * also rearranges the elements in the array so that the image is flipped
+ * vertically.
+ */
+ protected static void nativeToJavaRGB(int[] pixels, int width, int height) {
+ int index = 0;
+ int yindex = (height - 1) * width;
+ for (int y = 0; y < height / 2; y++) {
+ if (BIG_ENDIAN) { // RGBA to ARGB
+ for (int x = 0; x < width; x++) {
+ int temp = pixels[index];
+ pixels[index] = 0xff000000 | ((pixels[yindex] >> 8) & 0x00ffffff);
+ pixels[yindex] = 0xff000000 | ((temp >> 8) & 0x00ffffff);
+ index++;
+ yindex++;
+ }
+ } else { // ABGR to ARGB
+ for (int x = 0; x < width; x++) {
+ int temp = pixels[index];
+ pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) |
+ (pixels[yindex] & 0xff00) |
+ ((pixels[yindex] >> 16) & 0xff);
+ pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) |
+ (temp & 0xff00) |
+ ((temp >> 16) & 0xff);
+ index++;
+ yindex++;
+ }
+ }
+ yindex -= width * 2;
+ }
+
+ // Flips image
+ if ((height % 2) == 1) {
+ index = (height / 2) * width;
+ if (BIG_ENDIAN) { // RGBA to ARGB
+ for (int x = 0; x < width; x++) {
+ pixels[index] = 0xff000000 | ((pixels[index] >> 8) & 0x00ffffff);
+ index++;
+ }
+ } else { // ABGR to ARGB
+ for (int x = 0; x < width; x++) {
+ pixels[index] = 0xff000000 | ((pixels[index] << 16) & 0xff0000) |
+ (pixels[index] & 0xff00) |
+ ((pixels[index] >> 16) & 0xff);
+ index++;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Converts input Java ARGB value to native OpenGL format (RGBA on big endian,
+ * BGRA on little endian).
+ */
+ protected static int javaToNativeARGB(int color) {
+ if (BIG_ENDIAN) { // ARGB to RGBA
+ return ((color >> 24) & 0xff) |
+ ((color << 8) & 0xffffff00);
+ } else { // ARGB to ABGR
+ return (color & 0xff000000) |
+ ((color << 16) & 0xff0000) |
+ (color & 0xff00) |
+ ((color >> 16) & 0xff);
+ }
+ }
+
+
+ /**
+ * Converts input array of Java ARGB values representing an image of width x
+ * height resolution to native OpenGL format (RGBA on big endian, BGRA on
+ * little endian). It also rearranges the elements in the array so that the
+ * image is flipped vertically.
+ */
+ protected static void javaToNativeARGB(int[] pixels, int width, int height) {
+ int index = 0;
+ int yindex = (height - 1) * width;
+ for (int y = 0; y < height / 2; y++) {
+ if (BIG_ENDIAN) { // ARGB to RGBA
+ for (int x = 0; x < width; x++) {
+ int temp = pixels[index];
+ pixels[index] = ((pixels[yindex] >> 24) & 0xff) |
+ ((pixels[yindex] << 8) & 0xffffff00);
+ pixels[yindex] = ((temp >> 24) & 0xff) |
+ ((temp << 8) & 0xffffff00);
+ index++;
+ yindex++;
+ }
+
+ } else { // ARGB to ABGR
+ for (int x = 0; x < width; x++) {
+ int temp = pixels[index];
+ pixels[index] = (pixels[yindex] & 0xff000000) |
+ ((pixels[yindex] << 16) & 0xff0000) |
+ (pixels[yindex] & 0xff00) |
+ ((pixels[yindex] >> 16) & 0xff);
+ pixels[yindex] = (pixels[yindex] & 0xff000000) |
+ ((temp << 16) & 0xff0000) |
+ (temp & 0xff00) |
+ ((temp >> 16) & 0xff);
+ index++;
+ yindex++;
+ }
+ }
+ yindex -= width * 2;
+ }
+
+ // Flips image
+ if ((height % 2) == 1) {
+ index = (height / 2) * width;
+ if (BIG_ENDIAN) { // ARGB to RGBA
+ for (int x = 0; x < width; x++) {
+ pixels[index] = ((pixels[index] >> 24) & 0xff) |
+ ((pixels[index] << 8) & 0xffffff00);
+ index++;
+ }
+ } else { // ARGB to ABGR
+ for (int x = 0; x < width; x++) {
+ pixels[index] = (pixels[index] & 0xff000000) |
+ ((pixels[index] << 16) & 0xff0000) |
+ (pixels[index] & 0xff00) |
+ ((pixels[index] >> 16) & 0xff);
+ index++;
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Converts input Java ARGB value to native OpenGL format (RGBA on big endian,
+ * BGRA on little endian), setting alpha component to opaque (255).
+ */
+ protected static int javaToNativeRGB(int color) {
+ if (BIG_ENDIAN) { // ARGB to RGBA
+ return ((color << 8) & 0xffffff00) | 0xff;
+ } else { // ARGB to ABGR
+ return 0xff000000 | ((color << 16) & 0xff0000) |
+ (color & 0xff00) |
+ ((color >> 16) & 0xff);
+ }
+ }
+
+
+ /**
+ * Converts input array of Java ARGB values representing an image of width x
+ * height resolution to native OpenGL format (RGBA on big endian, BGRA on
+ * little endian), while setting alpha component of all pixels to opaque
+ * (255). It also rearranges the elements in the array so that the image is
+ * flipped vertically.
+ */
+ protected static void javaToNativeRGB(int[] pixels, int width, int height) {
+ int index = 0;
+ int yindex = (height - 1) * width;
+ for (int y = 0; y < height / 2; y++) {
+ if (BIG_ENDIAN) { // ARGB to RGBA
+ for (int x = 0; x < width; x++) {
+ int temp = pixels[index];
+ pixels[index] = ((pixels[yindex] << 8) & 0xffffff00) | 0xff;
+ pixels[yindex] = ((temp << 8) & 0xffffff00) | 0xff;
+ index++;
+ yindex++;
+ }
+
+ } else {
+ for (int x = 0; x < width; x++) { // ARGB to ABGR
+ int temp = pixels[index];
+ pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) |
+ (pixels[yindex] & 0xff00) |
+ ((pixels[yindex] >> 16) & 0xff);
+ pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) |
+ (temp & 0xff00) |
+ ((temp >> 16) & 0xff);
+ index++;
+ yindex++;
+ }
+ }
+ yindex -= width * 2;
+ }
+
+ // Flips image
+ if ((height % 2) == 1) { // ARGB to RGBA
+ index = (height / 2) * width;
+ if (BIG_ENDIAN) {
+ for (int x = 0; x < width; x++) {
+ pixels[index] = ((pixels[index] << 8) & 0xffffff00) | 0xff;
+ index++;
+ }
+ } else { // ARGB to ABGR
+ for (int x = 0; x < width; x++) {
+ pixels[index] = 0xff000000 | ((pixels[index] << 16) & 0xff0000) |
+ (pixels[index] & 0xff00) |
+ ((pixels[index] >> 16) & 0xff);
+ index++;
+ }
+ }
+ }
+ }
+
+
+ protected int createShader(int shaderType, String source) {
+ int shader = createShader(shaderType);
+ if (shader != 0) {
+ shaderSource(shader, source);
+ compileShader(shader);
+ if (!compiled(shader)) {
+ System.err.println("Could not compile shader " + shaderType + ":");
+ System.err.println(getShaderInfoLog(shader));
+ deleteShader(shader);
+ shader = 0;
+ }
+ }
+ return shader;
+ }
+
+
+ protected int createProgram(int vertexShader, int fragmentShader) {
+ int program = createProgram();
+ if (program != 0) {
+ attachShader(program, vertexShader);
+ attachShader(program, fragmentShader);
+ linkProgram(program);
+ if (!linked(program)) {
+ System.err.println("Could not link program: ");
+ System.err.println(getProgramInfoLog(program));
+ deleteProgram(program);
+ program = 0;
+ }
+ }
+ return program;
+ }
+
+
+ protected boolean compiled(int shader) {
+ intBuffer.rewind();
+ getShaderiv(shader, COMPILE_STATUS, intBuffer);
+ return intBuffer.get(0) == 0 ? false : true;
+ }
+
+
+ protected boolean linked(int program) {
+ intBuffer.rewind();
+ getProgramiv(program, LINK_STATUS, intBuffer);
+ return intBuffer.get(0) == 0 ? false : true;
+ }
+
+
+ protected boolean validateFramebuffer() {
+ int status = checkFramebufferStatus(FRAMEBUFFER);
+ if (status == FRAMEBUFFER_COMPLETE) {
+ return true;
+ } else if (status == FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
+ throw new RuntimeException(
+ "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT (" +
+ Integer.toHexString(status) + ")");
+ } else if (status == FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) {
+ throw new RuntimeException(
+ "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT (" +
+ Integer.toHexString(status) + ")");
+ } else if (status == FRAMEBUFFER_INCOMPLETE_DIMENSIONS) {
+ throw new RuntimeException("GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS (" +
+ Integer.toHexString(status) + ")");
+ } else if (status == FRAMEBUFFER_INCOMPLETE_FORMATS) {
+ throw new RuntimeException("GL_FRAMEBUFFER_INCOMPLETE_FORMATS (" +
+ Integer.toHexString(status) + ")");
+ } else if (status == FRAMEBUFFER_UNSUPPORTED) {
+ throw new RuntimeException("GL_FRAMEBUFFER_UNSUPPORTED" +
+ Integer.toHexString(status));
+ } else {
+ throw new RuntimeException("unknown framebuffer error (" +
+ Integer.toHexString(status) + ")");
+ }
+ }
+
+
+ protected int[] getGLVersion() {
+ String version = getString(VERSION).trim();
+ int[] res = {0, 0, 0};
+ String[] parts = version.split(" ");
+ for (int i = 0; i < parts.length; i++) {
+ if (0 < parts[i].indexOf(".")) {
+ String nums[] = parts[i].split("\\.");
+ try {
+ res[0] = Integer.parseInt(nums[0]);
+ } catch (NumberFormatException e) { }
+ if (1 < nums.length) {
+ try {
+ res[1] = Integer.parseInt(nums[1]);
+ } catch (NumberFormatException e) { }
+ }
+ if (2 < nums.length) {
+ try {
+ res[2] = Integer.parseInt(nums[2]);
+ } catch (NumberFormatException e) { }
+ }
+ break;
+ }
+ }
+ return res;
+ }
+
+
+ protected static ByteBuffer allocateDirectByteBuffer(int size) {
+ int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_BYTE;
+ return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder());
+ }
+
+
+ protected static ByteBuffer allocateByteBuffer(int size) {
+ if (USE_DIRECT_BUFFERS) {
+ return allocateDirectByteBuffer(size);
+ } else {
+ return ByteBuffer.allocate(size);
+ }
+ }
+
+
+ protected static ByteBuffer allocateByteBuffer(byte[] arr) {
+ if (USE_DIRECT_BUFFERS) {
+ return PGL.allocateDirectByteBuffer(arr.length);
+ } else {
+ return ByteBuffer.wrap(arr);
+ }
+ }
+
+
+ protected static ByteBuffer updateByteBuffer(ByteBuffer buf, byte[] arr,
+ boolean wrap) {
+ if (USE_DIRECT_BUFFERS) {
+ if (buf == null || buf.capacity() < arr.length) {
+ buf = PGL.allocateDirectByteBuffer(arr.length);
+ }
+ buf.position(0);
+ buf.put(arr);
+ buf.rewind();
+ } else {
+ if (wrap) {
+ buf = ByteBuffer.wrap(arr);
+ } else {
+ if (buf == null || buf.capacity() < arr.length) {
+ buf = ByteBuffer.allocate(arr.length);
+ }
+ buf.position(0);
+ buf.put(arr);
+ buf.rewind();
+ }
+ }
+ return buf;
+ }
+
+
+ protected static void getByteArray(ByteBuffer buf, byte[] arr) {
+ if (!buf.hasArray() || buf.array() != arr) {
+ buf.position(0);
+ buf.get(arr);
+ buf.rewind();
+ }
+ }
+
+
+ protected static void putByteArray(ByteBuffer buf, byte[] arr) {
+ if (!buf.hasArray() || buf.array() != arr) {
+ buf.position(0);
+ buf.put(arr);
+ buf.rewind();
+ }
+ }
+
+
+ protected static void fillByteBuffer(ByteBuffer buf, int i0, int i1,
+ byte val) {
+ int n = i1 - i0;
+ byte[] temp = new byte[n];
+ Arrays.fill(temp, 0, n, val);
+ buf.position(i0);
+ buf.put(temp, 0, n);
+ buf.rewind();
+ }
+
+
+ protected static ShortBuffer allocateDirectShortBuffer(int size) {
+ int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_SHORT;
+ return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).
+ asShortBuffer();
+ }
+
+
+ protected static ShortBuffer allocateShortBuffer(int size) {
+ if (USE_DIRECT_BUFFERS) {
+ return allocateDirectShortBuffer(size);
+ } else {
+ return ShortBuffer.allocate(size);
+ }
+ }
+
+
+ protected static ShortBuffer allocateShortBuffer(short[] arr) {
+ if (USE_DIRECT_BUFFERS) {
+ return PGL.allocateDirectShortBuffer(arr.length);
+ } else {
+ return ShortBuffer.wrap(arr);
+ }
+ }
+
+
+ protected static ShortBuffer updateShortBuffer(ShortBuffer buf, short[] arr,
+ boolean wrap) {
+ if (USE_DIRECT_BUFFERS) {
+ if (buf == null || buf.capacity() < arr.length) {
+ buf = PGL.allocateDirectShortBuffer(arr.length);
+ }
+ buf.position(0);
+ buf.put(arr);
+ buf.rewind();
+ } else {
+ if (wrap) {
+ buf = ShortBuffer.wrap(arr);
+ } else {
+ if (buf == null || buf.capacity() < arr.length) {
+ buf = ShortBuffer.allocate(arr.length);
+ }
+ buf.position(0);
+ buf.put(arr);
+ buf.rewind();
+ }
+ }
+ return buf;
+ }
+
+
+ protected static void getShortArray(ShortBuffer buf, short[] arr) {
+ if (!buf.hasArray() || buf.array() != arr) {
+ buf.position(0);
+ buf.get(arr);
+ buf.rewind();
+ }
+ }
+
+
+ protected static void putShortArray(ShortBuffer buf, short[] arr) {
+ if (!buf.hasArray() || buf.array() != arr) {
+ buf.position(0);
+ buf.put(arr);
+ buf.rewind();
+ }
+ }
+
+
+ protected static void fillShortBuffer(ShortBuffer buf, int i0, int i1,
+ short val) {
+ int n = i1 - i0;
+ short[] temp = new short[n];
+ Arrays.fill(temp, 0, n, val);
+ buf.position(i0);
+ buf.put(temp, 0, n);
+ buf.rewind();
+ }
+
+
+ protected static IntBuffer allocateDirectIntBuffer(int size) {
+ int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_INT;
+ return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).
+ asIntBuffer();
+ }
+
+
+ protected static IntBuffer allocateIntBuffer(int size) {
+ if (USE_DIRECT_BUFFERS) {
+ return allocateDirectIntBuffer(size);
+ } else {
+ return IntBuffer.allocate(size);
+ }
+ }
+
+
+ protected static IntBuffer allocateIntBuffer(int[] arr) {
+ if (USE_DIRECT_BUFFERS) {
+ return PGL.allocateDirectIntBuffer(arr.length);
+ } else {
+ return IntBuffer.wrap(arr);
+ }
+ }
+
+
+ protected static IntBuffer updateIntBuffer(IntBuffer buf, int[] arr,
+ boolean wrap) {
+ if (USE_DIRECT_BUFFERS) {
+ if (buf == null || buf.capacity() < arr.length) {
+ buf = PGL.allocateDirectIntBuffer(arr.length);
+ }
+ buf.position(0);
+ buf.put(arr);
+ buf.rewind();
+ } else {
+ if (wrap) {
+ buf = IntBuffer.wrap(arr);
+ } else {
+ if (buf == null || buf.capacity() < arr.length) {
+ buf = IntBuffer.allocate(arr.length);
+ }
+ buf.position(0);
+ buf.put(arr);
+ buf.rewind();
+ }
+ }
+ return buf;
+ }
+
+
+ protected static void getIntArray(IntBuffer buf, int[] arr) {
+ if (!buf.hasArray() || buf.array() != arr) {
+ buf.position(0);
+ buf.get(arr);
+ buf.rewind();
+ }
+ }
+
+
+ protected static void putIntArray(IntBuffer buf, int[] arr) {
+ if (!buf.hasArray() || buf.array() != arr) {
+ buf.position(0);
+ buf.put(arr);
+ buf.rewind();
+ }
+ }
+
+
+ protected static void fillIntBuffer(IntBuffer buf, int i0, int i1, int val) {
+ int n = i1 - i0;
+ int[] temp = new int[n];
+ Arrays.fill(temp, 0, n, val);
+ buf.position(i0);
+ buf.put(temp, 0, n);
+ buf.rewind();
+ }
+
+
+ protected static FloatBuffer allocateDirectFloatBuffer(int size) {
+ int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_FLOAT;
+ return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).
+ asFloatBuffer();
+ }
+
+
+ protected static FloatBuffer allocateFloatBuffer(int size) {
+ if (USE_DIRECT_BUFFERS) {
+ return allocateDirectFloatBuffer(size);
+ } else {
+ return FloatBuffer.allocate(size);
+ }
+ }
+
+
+ protected static FloatBuffer allocateFloatBuffer(float[] arr) {
+ if (USE_DIRECT_BUFFERS) {
+ return PGL.allocateDirectFloatBuffer(arr.length);
+ } else {
+ return FloatBuffer.wrap(arr);
+ }
+ }
+
+
+ protected static FloatBuffer updateFloatBuffer(FloatBuffer buf, float[] arr,
+ boolean wrap) {
+ if (USE_DIRECT_BUFFERS) {
+ if (buf == null || buf.capacity() < arr.length) {
+ buf = PGL.allocateDirectFloatBuffer(arr.length);
+ }
+ buf.position(0);
+ buf.put(arr);
+ buf.rewind();
+ } else {
+ if (wrap) {
+ buf = FloatBuffer.wrap(arr);
+ } else {
+ if (buf == null || buf.capacity() < arr.length) {
+ buf = FloatBuffer.allocate(arr.length);
+ }
+ buf.position(0);
+ buf.put(arr);
+ buf.rewind();
+ }
+ }
+ return buf;
+ }
+
+
+ protected static void getFloatArray(FloatBuffer buf, float[] arr) {
+ if (!buf.hasArray() || buf.array() != arr) {
+ buf.position(0);
+ buf.get(arr);
+ buf.rewind();
+ }
+ }
+
+
+ protected static void putFloatArray(FloatBuffer buf, float[] arr) {
+ if (!buf.hasArray() || buf.array() != arr) {
+ buf.position(0);
+ buf.put(arr);
+ buf.rewind();
+ }
+ }
+
+
+ protected static void fillFloatBuffer(FloatBuffer buf, int i0, int i1,
+ float val) {
+ int n = i1 - i0;
+ float[] temp = new float[n];
+ Arrays.fill(temp, 0, n, val);
+ buf.position(i0);
+ buf.put(temp, 0, n);
+ buf.rewind();
+ }
+
+
+ ///////////////////////////////////////////////////////////
+
+ // Java specific stuff
+
+
+ protected class KeyPoller extends Thread {
+ protected PApplet parent;
+ protected boolean stopRequested;
+ protected boolean[] pressedKeys;
+ protected char[] charCheys;
+
+ KeyPoller(PApplet parent) {
+ this.parent = parent;
+ stopRequested = false;
+ }
+
+ @Override
+ public void run() {
+ pressedKeys = new boolean[256];
+ charCheys = new char[256];
+ Keyboard.enableRepeatEvents(true);
+ while (true) {
+ if (stopRequested) break;
+
+ Keyboard.poll();
+ while (Keyboard.next()) {
+ if (stopRequested) break;
+
+ long millis = Keyboard.getEventNanoseconds() / 1000000L;
+ char keyChar = Keyboard.getEventCharacter();
+ int keyCode = Keyboard.getEventKey();
+
+ if (keyCode >= pressedKeys.length) continue;
+
+ int modifiers = 0;
+ if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) ||
+ Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) {
+ modifiers |= Event.SHIFT;
+ }
+ if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) ||
+ Keyboard.isKeyDown(Keyboard.KEY_RCONTROL)) {
+ modifiers |= Event.CTRL;
+ }
+ if (Keyboard.isKeyDown(Keyboard.KEY_LMETA) ||
+ Keyboard.isKeyDown(Keyboard.KEY_RMETA)) {
+ modifiers |= Event.META;
+ }
+ if (Keyboard.isKeyDown(Keyboard.KEY_LMENU) ||
+ Keyboard.isKeyDown(Keyboard.KEY_RMENU)) {
+ // LWJGL maps the menu key and the alt key to the same value.
+ modifiers |= Event.ALT;
+ }
+
+ int keyPCode = LWJGLtoAWTCode(keyCode);
+ if (keyChar == 0) {
+ keyChar = PConstants.CODED;
+ }
+
+ int action = 0;
+ if (Keyboard.getEventKeyState()) {
+ action = KeyEvent.PRESS;
+ KeyEvent ke = new KeyEvent(null, millis,
+ action, modifiers,
+ keyChar, keyPCode);
+ parent.postEvent(ke);
+ pressedKeys[keyCode] = true;
+ charCheys[keyCode] = keyChar;
+ keyPCode = 0;
+ action = KeyEvent.TYPE;
+ } else if (pressedKeys[keyCode]) {
+ keyChar = charCheys[keyCode];
+ pressedKeys[keyCode] = false;
+ action = KeyEvent.RELEASE;
+ }
+
+ KeyEvent ke = new KeyEvent(null, millis,
+ action, modifiers,
+ keyChar, keyPCode);
+ parent.postEvent(ke);
+ }
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void requestStop() {
+ stopRequested = true;
+ }
+ }
+
+
+ protected class MousePoller extends Thread {
+ protected PApplet parent;
+ protected boolean stopRequested;
+ protected boolean pressed;
+ protected boolean inside;
+ protected long startedClickTime;
+ protected int startedClickButton;
+
+ MousePoller(PApplet parent) {
+ this.parent = parent;
+ stopRequested = false;
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ if (stopRequested) break;
+
+ Mouse.poll();
+ while (Mouse.next()) {
+ if (stopRequested) break;
+
+ long millis = Mouse.getEventNanoseconds() / 1000000L;
+
+ int modifiers = 0;
+ if (Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) ||
+ Keyboard.isKeyDown(Keyboard.KEY_RSHIFT)) {
+ modifiers |= Event.SHIFT;
+ }
+ if (Keyboard.isKeyDown(Keyboard.KEY_LCONTROL) ||
+ Keyboard.isKeyDown(Keyboard.KEY_RCONTROL)) {
+ modifiers |= Event.CTRL;
+ }
+ if (Keyboard.isKeyDown(Keyboard.KEY_LMETA) ||
+ Keyboard.isKeyDown(Keyboard.KEY_RMETA)) {
+ modifiers |= Event.META;
+ }
+ if (Keyboard.isKeyDown(Keyboard.KEY_LMENU) ||
+ Keyboard.isKeyDown(Keyboard.KEY_RMENU)) {
+ // LWJGL maps the menu key and the alt key to the same value.
+ modifiers |= Event.ALT;
+ }
+
+ int x = Mouse.getX();
+ int y = parent.height - Mouse.getY();
+ int button = 0;
+ if (Mouse.isButtonDown(0)) {
+ button = PConstants.LEFT;
+ } else if (Mouse.isButtonDown(1)) {
+ button = PConstants.RIGHT;
+ } else if (Mouse.isButtonDown(2)) {
+ button = PConstants.CENTER;
+ }
+
+ int action = 0;
+ if (button != 0) {
+ if (pressed) {
+ action = MouseEvent.DRAG;
+ } else {
+ action = MouseEvent.PRESS;
+ pressed = true;
+ }
+ } else if (pressed) {
+ action = MouseEvent.RELEASE;
+ pressed = false;
+ } else {
+ action = MouseEvent.MOVE;
+ }
+
+ if (inside) {
+ if (!Mouse.isInsideWindow()) {
+ inside = false;
+ action = MouseEvent.EXIT;
+ }
+ } else {
+ if (Mouse.isInsideWindow()) {
+ inside = true;
+ action = MouseEvent.ENTER;
+ }
+ }
+
+ int count = 0;
+ if (Mouse.getEventButtonState()) {
+ startedClickTime = millis;
+ startedClickButton = button;
+ } else {
+ if (action == MouseEvent.RELEASE) {
+ boolean clickDetected = millis - startedClickTime < 500;
+ if (clickDetected) {
+ // post a RELEASE event, in addition to the CLICK event.
+ MouseEvent me = new MouseEvent(null, millis, action, modifiers,
+ x, y, button, count);
+ parent.postEvent(me);
+ action = MouseEvent.CLICK;
+ count = 1;
+ }
+ }
+ }
+
+ MouseEvent me = new MouseEvent(null, millis, action, modifiers,
+ x, y, button, count);
+ parent.postEvent(me);
+ }
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void requestStop() {
+ stopRequested = true;
+ }
+ }
+
+ protected class DummyContext {
+ int id;
+ DummyContext(int id) {
+ this.id = id;
+ }
+ }
+
+ // To complete later...
+ // http://docs.oracle.com/javase/6/docs/api/java/awt/event/KeyEvent.html
+ // http://processing.org/reference/keyCode.html
+ protected int LWJGLtoAWTCode(int code) {
+ switch (code) {
+ case Keyboard.KEY_0:
+ return java.awt.event.KeyEvent.VK_0;
+ case Keyboard.KEY_1:
+ return java.awt.event.KeyEvent.VK_1;
+ case Keyboard.KEY_2:
+ return java.awt.event.KeyEvent.VK_2;
+ case Keyboard.KEY_3:
+ return java.awt.event.KeyEvent.VK_3;
+ case Keyboard.KEY_4:
+ return java.awt.event.KeyEvent.VK_4;
+ case Keyboard.KEY_5:
+ return java.awt.event.KeyEvent.VK_5;
+ case Keyboard.KEY_6:
+ return java.awt.event.KeyEvent.VK_6;
+ case Keyboard.KEY_7:
+ return java.awt.event.KeyEvent.VK_7;
+ case Keyboard.KEY_8:
+ return java.awt.event.KeyEvent.VK_8;
+ case Keyboard.KEY_9:
+ return java.awt.event.KeyEvent.VK_9;
+ case Keyboard.KEY_A:
+ return java.awt.event.KeyEvent.VK_A;
+ case Keyboard.KEY_B:
+ return java.awt.event.KeyEvent.VK_B;
+ case Keyboard.KEY_C:
+ return java.awt.event.KeyEvent.VK_C;
+ case Keyboard.KEY_D:
+ return java.awt.event.KeyEvent.VK_D;
+ case Keyboard.KEY_E:
+ return java.awt.event.KeyEvent.VK_E;
+ case Keyboard.KEY_F:
+ return java.awt.event.KeyEvent.VK_F;
+ case Keyboard.KEY_G:
+ return java.awt.event.KeyEvent.VK_G;
+ case Keyboard.KEY_H:
+ return java.awt.event.KeyEvent.VK_H;
+ case Keyboard.KEY_I:
+ return java.awt.event.KeyEvent.VK_I;
+ case Keyboard.KEY_J:
+ return java.awt.event.KeyEvent.VK_J;
+ case Keyboard.KEY_K:
+ return java.awt.event.KeyEvent.VK_K;
+ case Keyboard.KEY_L:
+ return java.awt.event.KeyEvent.VK_L;
+ case Keyboard.KEY_M:
+ return java.awt.event.KeyEvent.VK_M;
+ case Keyboard.KEY_N:
+ return java.awt.event.KeyEvent.VK_N;
+ case Keyboard.KEY_O:
+ return java.awt.event.KeyEvent.VK_O;
+ case Keyboard.KEY_P:
+ return java.awt.event.KeyEvent.VK_P;
+ case Keyboard.KEY_Q:
+ return java.awt.event.KeyEvent.VK_Q;
+ case Keyboard.KEY_R:
+ return java.awt.event.KeyEvent.VK_R;
+ case Keyboard.KEY_S:
+ return java.awt.event.KeyEvent.VK_S;
+ case Keyboard.KEY_T:
+ return java.awt.event.KeyEvent.VK_T;
+ case Keyboard.KEY_U:
+ return java.awt.event.KeyEvent.VK_U;
+ case Keyboard.KEY_V:
+ return java.awt.event.KeyEvent.VK_V;
+ case Keyboard.KEY_W:
+ return java.awt.event.KeyEvent.VK_W;
+ case Keyboard.KEY_X:
+ return java.awt.event.KeyEvent.VK_X;
+ case Keyboard.KEY_Y:
+ return java.awt.event.KeyEvent.VK_Y;
+ case Keyboard.KEY_Z:
+ return java.awt.event.KeyEvent.VK_Z;
+ case Keyboard.KEY_ADD:
+ return java.awt.event.KeyEvent.VK_ADD;
+ case Keyboard.KEY_APOSTROPHE:
+ return java.awt.event.KeyEvent.VK_ASTERISK;
+ case Keyboard.KEY_AT:
+ return java.awt.event.KeyEvent.VK_AT;
+ case Keyboard.KEY_BACK:
+ return java.awt.event.KeyEvent.VK_BACK_SPACE;
+ case Keyboard.KEY_BACKSLASH:
+ return java.awt.event.KeyEvent.VK_BACK_SLASH;
+ case Keyboard.KEY_CAPITAL:
+ return java.awt.event.KeyEvent.VK_CAPS_LOCK;
+ case Keyboard.KEY_CIRCUMFLEX:
+ return java.awt.event.KeyEvent.VK_CIRCUMFLEX;
+ case Keyboard.KEY_COLON:
+ return java.awt.event.KeyEvent.VK_COLON;
+ case Keyboard.KEY_COMMA:
+ return java.awt.event.KeyEvent.VK_COMMA;
+ case Keyboard.KEY_CONVERT:
+ return java.awt.event.KeyEvent.VK_CONVERT;
+ case Keyboard.KEY_DECIMAL:
+ return java.awt.event.KeyEvent.VK_DECIMAL;
+ case Keyboard.KEY_DELETE:
+ return java.awt.event.KeyEvent.VK_DELETE;
+ case Keyboard.KEY_DIVIDE:
+ return java.awt.event.KeyEvent.VK_DIVIDE;
+ case Keyboard.KEY_DOWN:
+ return java.awt.event.KeyEvent.VK_DOWN;
+ case Keyboard.KEY_END:
+ return java.awt.event.KeyEvent.VK_END;
+ case Keyboard.KEY_EQUALS:
+ return java.awt.event.KeyEvent.VK_EQUALS;
+ case Keyboard.KEY_ESCAPE:
+ return java.awt.event.KeyEvent.VK_ESCAPE;
+ case Keyboard.KEY_F1:
+ return java.awt.event.KeyEvent.VK_F1;
+ case Keyboard.KEY_F10:
+ return java.awt.event.KeyEvent.VK_F10;
+ case Keyboard.KEY_F11:
+ return java.awt.event.KeyEvent.VK_F11;
+ case Keyboard.KEY_F12:
+ return java.awt.event.KeyEvent.VK_F12;
+ case Keyboard.KEY_F13:
+ return java.awt.event.KeyEvent.VK_F13;
+ case Keyboard.KEY_F14:
+ return java.awt.event.KeyEvent.VK_F14;
+ case Keyboard.KEY_F15:
+ return java.awt.event.KeyEvent.VK_F15;
+ case Keyboard.KEY_F2:
+ return java.awt.event.KeyEvent.VK_F2;
+ case Keyboard.KEY_F3:
+ return java.awt.event.KeyEvent.VK_F3;
+ case Keyboard.KEY_F4:
+ return java.awt.event.KeyEvent.VK_F4;
+ case Keyboard.KEY_F5:
+ return java.awt.event.KeyEvent.VK_F5;
+ case Keyboard.KEY_F6:
+ return java.awt.event.KeyEvent.VK_F6;
+ case Keyboard.KEY_F7:
+ return java.awt.event.KeyEvent.VK_F7;
+ case Keyboard.KEY_F8:
+ return java.awt.event.KeyEvent.VK_F8;
+ case Keyboard.KEY_F9:
+ return java.awt.event.KeyEvent.VK_F9;
+// case Keyboard.KEY_GRAVE:
+ case Keyboard.KEY_HOME:
+ return java.awt.event.KeyEvent.VK_HOME;
+ case Keyboard.KEY_INSERT:
+ return java.awt.event.KeyEvent.VK_INSERT;
+ case Keyboard.KEY_LBRACKET:
+ return java.awt.event.KeyEvent.VK_BRACELEFT;
+ case Keyboard.KEY_LCONTROL:
+ return java.awt.event.KeyEvent.VK_CONTROL;
+ case Keyboard.KEY_LEFT:
+ return java.awt.event.KeyEvent.VK_LEFT;
+ case Keyboard.KEY_LMENU:
+ return java.awt.event.KeyEvent.VK_ALT;
+ case Keyboard.KEY_LMETA:
+ return java.awt.event.KeyEvent.VK_META;
+ case Keyboard.KEY_LSHIFT:
+ return java.awt.event.KeyEvent.VK_SHIFT;
+ case Keyboard.KEY_MINUS:
+ return java.awt.event.KeyEvent.VK_MINUS;
+ case Keyboard.KEY_MULTIPLY:
+ return java.awt.event.KeyEvent.VK_MULTIPLY;
+// case Keyboard.KEY_NEXT:
+ case Keyboard.KEY_NUMLOCK:
+ return java.awt.event.KeyEvent.VK_NUM_LOCK;
+ case Keyboard.KEY_NUMPAD0:
+ return java.awt.event.KeyEvent.VK_NUMPAD0;
+ case Keyboard.KEY_NUMPAD1:
+ return java.awt.event.KeyEvent.VK_NUMPAD1;
+ case Keyboard.KEY_NUMPAD2:
+ return java.awt.event.KeyEvent.VK_NUMPAD2;
+ case Keyboard.KEY_NUMPAD3:
+ return java.awt.event.KeyEvent.VK_NUMPAD3;
+ case Keyboard.KEY_NUMPAD4:
+ return java.awt.event.KeyEvent.VK_NUMPAD4;
+ case Keyboard.KEY_NUMPAD5:
+ return java.awt.event.KeyEvent.VK_NUMPAD5;
+ case Keyboard.KEY_NUMPAD6:
+ return java.awt.event.KeyEvent.VK_NUMPAD6;
+ case Keyboard.KEY_NUMPAD7:
+ return java.awt.event.KeyEvent.VK_NUMPAD7;
+ case Keyboard.KEY_NUMPAD8:
+ return java.awt.event.KeyEvent.VK_NUMPAD8;
+ case Keyboard.KEY_NUMPAD9:
+ return java.awt.event.KeyEvent.VK_NUMPAD9;
+// case Keyboard.KEY_NUMPADCOMMA:
+// case Keyboard.KEY_NUMPADENTER:
+// case Keyboard.KEY_NUMPADEQUALS:
+ case Keyboard.KEY_PAUSE:
+ return java.awt.event.KeyEvent.VK_PAUSE;
+ case Keyboard.KEY_PERIOD:
+ return java.awt.event.KeyEvent.VK_PERIOD;
+// case Keyboard.KEY_POWER:
+// case Keyboard.KEY_PRIOR:
+ case Keyboard.KEY_RBRACKET:
+ return java.awt.event.KeyEvent.VK_BRACERIGHT;
+ case Keyboard.KEY_RCONTROL:
+ return java.awt.event.KeyEvent.VK_CONTROL;
+ case Keyboard.KEY_RETURN:
+ return java.awt.event.KeyEvent.VK_ENTER;
+ case Keyboard.KEY_RIGHT:
+ return java.awt.event.KeyEvent.VK_RIGHT;
+// case Keyboard.KEY_RMENU:
+ case Keyboard.KEY_RMETA:
+ return java.awt.event.KeyEvent.VK_META;
+ case Keyboard.KEY_RSHIFT:
+ return java.awt.event.KeyEvent.VK_SHIFT;
+// case Keyboard.KEY_SCROLL:
+ case Keyboard.KEY_SEMICOLON:
+ return java.awt.event.KeyEvent.VK_SEMICOLON;
+ case Keyboard.KEY_SLASH:
+ return java.awt.event.KeyEvent.VK_SLASH;
+// case Keyboard.KEY_SLEEP:
+ case Keyboard.KEY_SPACE:
+ return java.awt.event.KeyEvent.VK_SPACE;
+ case Keyboard.KEY_STOP:
+ return java.awt.event.KeyEvent.VK_STOP;
+ case Keyboard.KEY_SUBTRACT:
+ return java.awt.event.KeyEvent.VK_SUBTRACT;
+ case Keyboard.KEY_TAB:
+ return java.awt.event.KeyEvent.VK_TAB;
+// case Keyboard.KEY_UNDERLINE:
+ case Keyboard.KEY_UP:
+ return java.awt.event.KeyEvent.VK_UP;
+ default:
+ return 0;
+ }
+ }
+}
diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java
new file mode 100644
index 000000000..86d9fc330
--- /dev/null
+++ b/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java
@@ -0,0 +1,59 @@
+/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
+
+/*
+ Part of the Processing project - http://processing.org
+
+ Copyright (c) 2004-12 Ben Fry and Casey Reas
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ Boston, MA 02111-1307 USA
+ */
+
+package processing.lwjgl;
+
+import processing.core.*;
+import processing.opengl.PGraphicsOpenGL;
+
+/**
+ * LWJGL renderer.
+ *
+ */
+public class PGraphicsLWJGL extends PGraphicsOpenGL {
+ /** Interface between Processing and OpenGL */
+ public PGL pgl;
+
+ //////////////////////////////////////////////////////////////
+
+ // INIT/ALLOCATE/FINISH
+
+
+ public PGraphicsLWJGL() {
+ pgl = new PGL(this);
+
+ if (tessellator == null) {
+ tessellator = new Tessellator();
+ }
+
+ intBuffer = PGL.allocateIntBuffer(2);
+ floatBuffer = PGL.allocateFloatBuffer(2);
+ viewport = PGL.allocateIntBuffer(4);
+
+ inGeo = newInGeometry(IMMEDIATE);
+ tessGeo = newTessGeometry(IMMEDIATE);
+ texCache = newTexCache();
+
+ initialized = false;
+ }
+
+}