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; + } + +}