diff --git a/core/src/processing/opengl/PGL.java b/core/src/processing/opengl/PGL.java index bdf3f3bb8..cc8962534 100644 --- a/core/src/processing/opengl/PGL.java +++ b/core/src/processing/opengl/PGL.java @@ -32,27 +32,36 @@ import java.nio.IntBuffer; import java.nio.ShortBuffer; import java.util.Arrays; - /** - * Processing-OpenGL abstraction layer. + * Processing-OpenGL abstraction layer. Needs to be implemented by subclasses + * using specific OpenGL-Java bindings. + * + * It includes a full GLES 2.0 interface. * - * Warnings are suppressed for static access because presumably on Android, - * the GL2 vs GL distinctions are necessary, whereas on desktop they are not. */ public abstract class PGL { + // ........................................................ - - + // Basic fields /** The PGraphics object using this interface */ protected PGraphicsOpenGL pg; - protected static int contextID; + /** OpenGL thread */ + protected static Thread glThread; - /////////////////////////////////////////////////////////// + /** ID of the GL context associated to the surface **/ + protected static int glContext; + + // ........................................................ // Parameters + protected static boolean USE_FBOLAYER_BY_DEFAULT = false; + protected static int REQUESTED_DEPTH_BITS = 24; + protected static int REQUESTED_STENCIL_BITS = 8; + protected static int REQUESTED_ALPHA_BITS = 8; + /** Switches between the use of regular and direct buffers. */ protected static boolean USE_DIRECT_BUFFERS = true; protected static int MIN_DIRECT_BUFFER_SIZE = 1; @@ -114,50 +123,31 @@ public abstract class PGL { * order to make sure the lines are always on top of the fill geometry */ protected static float STROKE_DISPLACEMENT = 0.999f; + // ........................................................ + // FBO layer + protected static boolean fboLayerRequested = false; + 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; - /** Size of different types in bytes */ - protected static int SIZEOF_SHORT = Short.SIZE / 8; - protected static int SIZEOF_INT = Integer.SIZE / 8; - protected static int SIZEOF_FLOAT = Float.SIZE / 8; - protected static int SIZEOF_BYTE = Byte.SIZE / 8; - protected static int SIZEOF_INDEX = SIZEOF_SHORT; - protected static int INDEX_TYPE = 0x1403; // GL_UNSIGNED_SHORT + /** Flags used to handle the creation of a separate front texture */ + protected boolean usingFrontTex = false; + protected boolean needSepFrontTex = false; - /** 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"; - - - - - /////////////////////////////////////////////////////////// + // ........................................................ // Texture rendering @@ -186,6 +176,12 @@ public abstract class PGL { }; protected static FloatBuffer texData; + protected static final String SHADER_PREPROCESSOR_DIRECTIVE = + "#ifdef GL_ES\n" + + "precision mediump float;\n" + + "precision mediump int;\n" + + "#endif\n"; + protected static String texVertShaderSource = "attribute vec2 inVertex;" + "attribute vec2 inTexcoord;" + @@ -211,9 +207,25 @@ public abstract class PGL { " gl_FragColor = texture2DRect(textureSampler, vertTexcoord.st);" + "}"; - /////////////////////////////////////////////////////////// + /** Which texturing targets are enabled */ + protected static boolean[] texturingTargets = { false, false }; - // Utilities + /** Used to keep track of which textures are bound to each target */ + protected static int maxTexUnits; + protected static int activeTexUnit = 0; + protected static int[][] boundTextures; + + // ........................................................ + + // Framerate handling + + protected float targetFps = 60; + protected float currentFps = 60; + protected boolean setFps = false; + + // ........................................................ + + // Utility buffers protected ByteBuffer byteBuffer; protected IntBuffer intBuffer; @@ -223,7 +235,7 @@ public abstract class PGL { protected FloatBuffer depthBuffer; protected ByteBuffer stencilBuffer; - /////////////////////////////////////////////////////////// + // ........................................................ // Error messages @@ -245,69 +257,48 @@ public abstract class PGL { protected static final String TEXUNIT_ERROR = "Number of texture units not supported by this hardware (or driver)" + WIKI; + // ........................................................ + // Constants + /** Size of different types in bytes */ + protected static int SIZEOF_SHORT = Short.SIZE / 8; + protected static int SIZEOF_INT = Integer.SIZE / 8; + protected static int SIZEOF_FLOAT = Float.SIZE / 8; + protected static int SIZEOF_BYTE = Byte.SIZE / 8; + protected static int SIZEOF_INDEX = SIZEOF_SHORT; + protected static int INDEX_TYPE = 0x1403; // 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; - protected static boolean USE_FBOLAYER_BY_DEFAULT; + do { + eps /= 2.0f; + } while ((float)(1.0 + (eps / 2.0)) != 1.0); + FLOAT_EPS = eps; + } - - - - - - - - - - /** Which texturing targets are enabled */ - protected static boolean[] texturingTargets = { false, false }; - - /** Used to keep track of which textures are bound to each target */ - protected static int maxTexUnits; - protected static int activeTexUnit = 0; - protected static int[][] boundTextures; - - /////////////////////////////////////////////////////////// - - // FBO layer - - protected static boolean fboLayerRequested = false; - 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; - - - - /** Flags used to handle the creation of a separate front texture */ - protected boolean usingFrontTex = false; - protected boolean needSepFrontTex = false; - - /** Flag used to do request final display() call to make sure that the - * buffers are properly swapped. + /** + * Set to true if the host system is big endian (PowerPC, MIPS, SPARC), false + * if little endian (x86 Intel for Mac or PC). */ - protected boolean prevCanDraw = false; + protected static boolean BIG_ENDIAN = + ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN; - - /////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////// // Initialization, finalization + public PGL() { } + public PGL(PGraphicsOpenGL pg) { this.pg = pg; if (glColorTex == null) { @@ -329,9 +320,12 @@ public abstract class PGL { viewBuffer = allocateIntBuffer(4); } - protected void setFps(float fps) { } - protected void initSurface(int antialias) { } + protected abstract void setFps(float fps); + + + protected abstract void initSurface(int antialias); + protected void deleteSurface() { if (threadIsCurrent() && fboLayerCreated) { @@ -349,29 +343,57 @@ public abstract class PGL { firstFrame = false; } - protected int getReadFramebuffer() { return 0; } - protected int getDrawFramebuffer() { return 0; } - - protected int getDefaultDrawBuffer() { return 0; } - - protected int getDefaultReadBuffer() { return 0; } + protected int getReadFramebuffer() { + return fboLayerInUse ? glColorFbo.get(0) : 0; + } - protected boolean isFBOBacked() { return false; } + protected int getDrawFramebuffer() { + if (fboLayerInUse) return 1 < numSamples ? glMultiFbo.get(0) : + glColorFbo.get(0); + else return 0; + } + + + protected int getDefaultDrawBuffer() { + return fboLayerInUse ? COLOR_ATTACHMENT0 : FRONT; + } + + + protected int getDefaultReadBuffer() { + return fboLayerInUse ? COLOR_ATTACHMENT0 : FRONT; + } + + + protected boolean isFBOBacked() { + return fboLayerInUse; + } protected void requestFBOLayer() { fboLayerRequested = true; } + protected boolean isMultisampled() { return 1 < numSamples; } - protected int getDepthBits() { return 0; } - protected int getStencilBits() { return 0; } + 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(); @@ -379,21 +401,82 @@ public abstract class PGL { 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 texture) { return null; } - protected Texture wrapFrontTexture(Texture texture) { return null; } + protected Texture wrapBackTexture(Texture texture) { + if (texture == null) { + texture = new Texture(); + texture.init(pg.width, pg.height, + glColorTex.get(backTex), TEXTURE_2D, RGBA, + fboWidth, fboHeight, NEAREST, NEAREST, + CLAMP_TO_EDGE, CLAMP_TO_EDGE); + texture.invertedY(true); + texture.colorBuffer(true); + pg.setCache(pg, texture); + } else { + texture.glName = glColorTex.get(backTex); + } + return texture; + } - protected void bindFrontTexture() { } - protected void unbindFrontTexture() { } + protected Texture wrapFrontTexture(Texture texture) { + if (texture == null) { + texture = new Texture(); + texture.init(pg.width, pg.height, + glColorTex.get(frontTex), TEXTURE_2D, RGBA, + fboWidth, fboHeight, NEAREST, NEAREST, + CLAMP_TO_EDGE, CLAMP_TO_EDGE); + texture.invertedY(true); + texture.colorBuffer(true); + } else { + texture.glName = glColorTex.get(frontTex); + } + return texture; + } + + + protected void bindFrontTexture() { + usingFrontTex = true; + 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 (usingFrontTex) needSepFrontTex = true; + 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 void syncBackTexture() { } protected int qualityToSamples(int quality) { if (quality <= 1) { @@ -628,21 +711,23 @@ public abstract class PGL { } - - protected void requestFocus() { } - - protected boolean canDraw() { return pg.initialized && pg.parent.isDisplayable(); } - protected void requestDraw() { } - - protected void swapBuffers() { } + protected abstract void requestFocus(); - protected boolean threadIsCurrent() { return false; } + protected abstract void requestDraw(); + + + protected abstract void swapBuffers(); + + + protected boolean threadIsCurrent() { + return Thread.currentThread() == glThread; + } protected boolean needFBOLayer(boolean clear0) { @@ -667,95 +752,17 @@ public abstract class PGL { protected int getCurrentContext() { - return contextID; + return glContext; } - - - - - - - - - - - /////////////////////////////////////////////////////////// - - // Tessellator interface - - - protected Tessellator createTessellator(TessellatorCallback callback) { - return null; - } - - protected interface Tessellator { - public void beginPolygon(); - public void endPolygon(); - public void setWindingRule(int rule); - public void beginContour(); - public void endContour(); - public void addVertex(double[] v); - } - - 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); - } - - protected String tessError(int err) { - return ""; - } - - - /////////////////////////////////////////////////////////// - - // FontOutline interface - - - protected static boolean SHAPE_TEXT_SUPPORTED; - - protected static int SEG_MOVETO; - protected static int SEG_LINETO; - protected static int SEG_QUADTO; - protected static int SEG_CUBICTO; - protected static int SEG_CLOSE; - - protected FontOutline createFontOutline(char ch, Object font) { - return null; - } - - protected interface FontOutline { - public boolean isDone(); - public int currentSegment(float coords[]); - public void next(); - } - - - - - - - - - - - - - - /////////////////////////////////////////////////////////// // Utility functions protected boolean contextIsCurrent(int other) { - return other == -1 || other == contextID; + return other == -1 || other == glContext; } @@ -874,7 +881,7 @@ public abstract class PGL { protected void drawTexture2D(int id, int texW, int texH, int scrW, int scrH, int texX0, int texY0, int texX1, int texY1, int scrX0, int scrY0, int scrX1, int scrY1) { - if (!loadedTex2DShader || tex2DShaderContext != contextID) { + if (!loadedTex2DShader || tex2DShaderContext != glContext) { tex2DVertShader = createShader(VERTEX_SHADER, texVertShaderSource); tex2DFragShader = createShader(FRAGMENT_SHADER, tex2DFragShaderSource); if (0 < tex2DVertShader && 0 < tex2DFragShader) { @@ -885,7 +892,7 @@ public abstract class PGL { tex2DTCoordLoc = getAttribLocation(tex2DShaderProgram, "inTexcoord"); } loadedTex2DShader = true; - tex2DShaderContext = contextID; + tex2DShaderContext = glContext; } if (texData == null) { @@ -985,7 +992,7 @@ public abstract class PGL { protected void drawTextureRect(int id, int texW, int texH, int scrW, int scrH, int texX0, int texY0, int texX1, int texY1, int scrX0, int scrY0, int scrX1, int scrY1) { - if (!loadedTexRectShader || texRectShaderContext != contextID) { + if (!loadedTexRectShader || texRectShaderContext != glContext) { texRectVertShader = createShader(VERTEX_SHADER, texVertShaderSource); texRectFragShader = createShader(FRAGMENT_SHADER, texRectFragShaderSource); if (0 < texRectVertShader && 0 < texRectFragShader) { @@ -997,7 +1004,7 @@ public abstract class PGL { texRectTCoordLoc = getAttribLocation(texRectShaderProgram, "inTexcoord"); } loadedTexRectShader = true; - texRectShaderContext = contextID; + texRectShaderContext = glContext; } if (texData == null) { @@ -1479,10 +1486,10 @@ public abstract class PGL { int major = getGLVersion()[0]; if (major < 2) { String ext = getString(EXTENSIONS); - return ext.indexOf("_framebuffer_object") != -1 && - ext.indexOf("_vertex_shader") != -1 && - ext.indexOf("_shader_objects") != -1 && - ext.indexOf("_shading_language") != -1; + return ext.indexOf("_framebuffer_object") != -1 && + ext.indexOf("_vertex_shader") != -1 && + ext.indexOf("_shader_objects") != -1 && + ext.indexOf("_shading_language") != -1; } else { return true; } @@ -1874,7 +1881,60 @@ public abstract class PGL { } + /////////////////////////////////////////////////////////// + // Tessellator interface + + + protected abstract Tessellator createTessellator(TessellatorCallback callback); + + + protected interface Tessellator { + public void beginPolygon(); + public void endPolygon(); + public void setWindingRule(int rule); + public void beginContour(); + public void endContour(); + public void addVertex(double[] v); + } + + + 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); + } + + + protected String tessError(int err) { + return ""; + } + + + /////////////////////////////////////////////////////////// + + // FontOutline interface + + + protected static boolean SHAPE_TEXT_SUPPORTED; + protected static int SEG_MOVETO; + protected static int SEG_LINETO; + protected static int SEG_QUADTO; + protected static int SEG_CUBICTO; + protected static int SEG_CLOSE; + + + protected abstract FontOutline createFontOutline(char ch, Object font); + + + protected interface FontOutline { + public boolean isDone(); + public int currentSegment(float coords[]); + public void next(); + } ////////////////////////////////////////////////////////////////////////////// @@ -1901,7 +1961,7 @@ public abstract class PGL { // Constants // Very important note: set the GL constants in your PGL subclass by using an - // initialization block as follows: + // static initialization block as follows: // static { // FALSE = SUPER_DUPER_JAVA_OPENGL_BINDINGS.GL_FALSE; // TRUE = SUPER_DUPER_JAVA_OPENGL_BINDINGS.GL_TRUE; diff --git a/core/src/processing/opengl/PGraphicsOpenGL.java b/core/src/processing/opengl/PGraphicsOpenGL.java index be369e530..592f12b71 100644 --- a/core/src/processing/opengl/PGraphicsOpenGL.java +++ b/core/src/processing/opengl/PGraphicsOpenGL.java @@ -1583,7 +1583,7 @@ public class PGraphicsOpenGL extends PGraphics { @Override public void requestFocus() { // ignore - //pgl.requestFocus(); + pgl.requestFocus(); } @@ -1700,7 +1700,7 @@ public class PGraphicsOpenGL extends PGraphics { // Factory method - static public PGL createPGL(PGraphicsOpenGL pg) { + protected PGL createPGL(PGraphicsOpenGL pg) { return new PJOGL(pg); } diff --git a/core/src/processing/opengl/PJOGL.java b/core/src/processing/opengl/PJOGL.java index e4d7a413c..5aa314ff1 100644 --- a/core/src/processing/opengl/PJOGL.java +++ b/core/src/processing/opengl/PJOGL.java @@ -47,14 +47,12 @@ import java.awt.geom.PathIterator; import javax.media.opengl.glu.GLUtessellator; import javax.media.opengl.glu.GLUtessellatorCallbackAdapter; -@SuppressWarnings("static-access") public class PJOGL extends PGL { - static { - INDEX_TYPE = GL.GL_UNSIGNED_SHORT; - } + // The two windowing toolkits available to use in JOGL: + public static final int AWT = 0; // http://jogamp.org/wiki/index.php/Using_JOGL_in_AWT_SWT_and_Swing + public static final int NEWT = 1; // http://jogamp.org/jogl/doc/NEWT-Overview.html - - /////////////////////////////////////////////////////////// + // ........................................................ // Public members to access the underlying GL objects and context @@ -73,20 +71,22 @@ public class PJOGL extends PGL { /** Selected GL profile */ public static GLProfile profile; + // ........................................................ - /** JOGL's windowing toolkit */ - // The two windowing toolkits available to use in JOGL: - protected static final int AWT = 0; // http://jogamp.org/wiki/index.php/Using_JOGL_in_AWT_SWT_and_Swing - protected static final int NEWT = 1; // http://jogamp.org/jogl/doc/NEWT-Overview.html + // Additional parameters + /** Time that the Processing's animation thread will wait for JOGL's rendering + * thread to be done with a single frame. + */ + protected static int DRAW_TIMEOUT_MILLIS = 500; + + // ........................................................ + + // OS-specific configuration - /** OS-specific configuration */ protected static int WINDOW_TOOLKIT; protected static int EVENTS_TOOLKIT; protected static boolean USE_JOGL_FBOLAYER; - protected static int REQUESTED_DEPTH_BITS = 24; - protected static int REQUESTED_STENCIL_BITS = 8; - protected static int REQUESTED_ALPHA_BITS = 8; static { if (PApplet.platform == PConstants.WINDOWS) { // Using AWT on Windows because NEWT displays a black background while @@ -99,57 +99,28 @@ public class PJOGL extends PGL { EVENTS_TOOLKIT = AWT; USE_FBOLAYER_BY_DEFAULT = false; USE_JOGL_FBOLAYER = false; - REQUESTED_DEPTH_BITS = 24; - REQUESTED_STENCIL_BITS = 8; - REQUESTED_ALPHA_BITS = 8; } else if (PApplet.platform == PConstants.MACOSX) { // Note: The JOGL FBO layer (in 2.0.2) seems incompatible with NEWT. WINDOW_TOOLKIT = AWT; EVENTS_TOOLKIT = AWT; USE_FBOLAYER_BY_DEFAULT = true; USE_JOGL_FBOLAYER = true; - REQUESTED_DEPTH_BITS = 24; - REQUESTED_STENCIL_BITS = 8; - REQUESTED_ALPHA_BITS = 8; } else if (PApplet.platform == PConstants.LINUX) { WINDOW_TOOLKIT = AWT; EVENTS_TOOLKIT = AWT; USE_FBOLAYER_BY_DEFAULT = false; USE_JOGL_FBOLAYER = false; - REQUESTED_DEPTH_BITS = 24; - REQUESTED_STENCIL_BITS = 8; - REQUESTED_ALPHA_BITS = 8; } else if (PApplet.platform == PConstants.OTHER) { WINDOW_TOOLKIT = NEWT; // NEWT works on the Raspberry pi? EVENTS_TOOLKIT = NEWT; USE_FBOLAYER_BY_DEFAULT = false; USE_JOGL_FBOLAYER = false; - REQUESTED_DEPTH_BITS = 24; - REQUESTED_STENCIL_BITS = 8; - REQUESTED_ALPHA_BITS = 8; } } - /** Time that the Processing's animation thread will wait for JOGL's rendering - * thread to be done with a single frame. - */ - protected static int DRAW_TIMEOUT_MILLIS = 500; + // ........................................................ - - - /** Desired target framerate */ - protected float targetFps = 60; - protected float currentFps = 60; - protected boolean setFps = false; - protected int fcount, lastm; - protected int fint = 3; - - - - - - /** OpenGL thread */ - protected static Thread glThread; + // Protected JOGL-specific objects needed to access the GL profiles /** The capabilities of the OpenGL rendering surface */ protected static GLCapabilitiesImmutable capabilities; @@ -180,11 +151,14 @@ public class PJOGL extends PGL { * Processing's drawing thread and JOGL's rendering thread */ protected CountDownLatch drawLatch; + /** Flag used to do request final display() call to make sure that the + * buffers are properly swapped. + */ + protected boolean prevCanDraw = false; + // ........................................................ - protected float[] projMatrix; - protected float[] mvMatrix; - + // JOGL's FBO-layer /** Back (== draw, current frame) buffer */ protected static FBObject backFBO; @@ -195,6 +169,30 @@ public class PJOGL extends PGL { protected static FBObject.TextureAttachment backTexAttach; protected static FBObject.TextureAttachment frontTexAttach; + protected boolean changedFrontTex = false; + protected boolean changedBackTex = false; + + // ........................................................ + + // Utility arrays to copy projection/modelview matrices to GL + + protected float[] projMatrix; + protected float[] mvMatrix; + + // ........................................................ + + // Static initialization for some parameters that need to be different for + // JOGL + + static { + MIN_DIRECT_BUFFER_SIZE = 2; + INDEX_TYPE = GL.GL_UNSIGNED_SHORT; + } + + + /////////////////////////////////////////////////////////////// + + // Initialization, finalization public PJOGL(PGraphicsOpenGL pg) { @@ -239,9 +237,9 @@ public class PJOGL extends PGL { // Setting up the desired capabilities; GLCapabilities caps = new GLCapabilities(profile); + caps.setAlphaBits(REQUESTED_ALPHA_BITS); caps.setDepthBits(REQUESTED_DEPTH_BITS); caps.setStencilBits(REQUESTED_STENCIL_BITS); - caps.setAlphaBits(REQUESTED_ALPHA_BITS); caps.setBackgroundOpaque(true); caps.setOnscreen(true); @@ -329,7 +327,6 @@ public class PJOGL extends PGL { fboLayerCreated = false; fboLayerInUse = false; firstFrame = true; - setFps = false; } @@ -406,31 +403,21 @@ public class PJOGL extends PGL { @Override protected boolean isFBOBacked() { - return fboLayerInUse || capabilities.isFBO(); + return super.isFBOBacked() || capabilities.isFBO(); } @Override protected int getDepthBits() { - if (USE_JOGL_FBOLAYER) { - return capabilities.getDepthBits(); - } else { - intBuffer.rewind(); - getIntegerv(DEPTH_BITS, intBuffer); - return intBuffer.get(0); - } + if (USE_JOGL_FBOLAYER) return capabilities.getDepthBits(); + else return super.getDepthBits(); } @Override protected int getStencilBits() { - if (USE_JOGL_FBOLAYER) { - return capabilities.getStencilBits(); - } else { - intBuffer.rewind(); - getIntegerv(STENCIL_BITS, intBuffer); - return intBuffer.get(0); - } + if (USE_JOGL_FBOLAYER) return capabilities.getStencilBits(); + else return super.getStencilBits(); } @@ -448,20 +435,13 @@ public class PJOGL extends PGL { texture.colorBuffer(true); pg.setCache(pg, texture); } else { - texture = new Texture(); - texture.init(pg.width, pg.height, - glColorTex.get(backTex), TEXTURE_2D, RGBA, - fboWidth, fboHeight, NEAREST, NEAREST, - CLAMP_TO_EDGE, CLAMP_TO_EDGE); - texture.invertedY(true); - texture.colorBuffer(true); - pg.setCache(pg, texture); + texture = super.wrapBackTexture(null); } } else { if (USE_JOGL_FBOLAYER) { texture.glName = backTexAttach.getName(); } else { - texture.glName = glColorTex.get(backTex); + texture = super.wrapBackTexture(texture); } } return texture; @@ -481,19 +461,13 @@ public class PJOGL extends PGL { texture.invertedY(true); texture.colorBuffer(true); } else { - texture = new Texture(); - texture.init(pg.width, pg.height, - glColorTex.get(frontTex), TEXTURE_2D, RGBA, - fboWidth, fboHeight, NEAREST, NEAREST, - CLAMP_TO_EDGE, CLAMP_TO_EDGE); - texture.invertedY(true); - texture.colorBuffer(true); + texture = super.wrapFrontTexture(null); } } else { if (USE_JOGL_FBOLAYER) { texture.glName = frontTexAttach.getName(); } else { - texture.glName = glColorTex.get(frontTex); + texture = super.wrapFrontTexture(texture); } } return texture; @@ -502,18 +476,13 @@ public class PJOGL extends PGL { @Override protected void bindFrontTexture() { - usingFrontTex = true; if (USE_JOGL_FBOLAYER) { + usingFrontTex = true; if (!texturingIsEnabled(TEXTURE_2D)) { enableTexturing(TEXTURE_2D); } bindTexture(TEXTURE_2D, frontTexAttach.getName()); - } else { - if (!texturingIsEnabled(TEXTURE_2D)) { - enableTexturing(TEXTURE_2D); - } - bindTexture(TEXTURE_2D, glColorTex.get(frontTex)); - } + } else super.bindFrontTexture(); } @@ -531,39 +500,19 @@ public class PJOGL extends PGL { bindTexture(TEXTURE_2D, 0); } } - } else { - 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); - } - } - } + } else super.unbindFrontTexture(); } @Override protected void syncBackTexture() { - if (usingFrontTex) needSepFrontTex = true; if (USE_JOGL_FBOLAYER) { + if (usingFrontTex) needSepFrontTex = true; if (1 < numSamples) { backFBO.syncSamplingSink(gl); backFBO.bind(gl); } - } else { - 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); - } - } + } else super.syncBackTexture(); } @@ -597,12 +546,10 @@ public class PJOGL extends PGL { } } + @Override - protected void requestFocus() { - if (canvas != null) { - canvas.requestFocus(); - } - } + protected void requestFocus() { } + @Override protected void requestDraw() { @@ -635,6 +582,7 @@ public class PJOGL extends PGL { } } + @Override protected void swapBuffers() { if (WINDOW_TOOLKIT == AWT) { @@ -644,11 +592,6 @@ public class PJOGL extends PGL { } } - @Override - protected boolean threadIsCurrent() { - return Thread.currentThread() == glThread; - } - @Override protected void beginGL() { @@ -697,18 +640,432 @@ public class PJOGL extends PGL { gl2x.glLoadMatrixf(mvMatrix, 0); } + @Override protected boolean hasFBOs() { if (context.hasBasicFBOSupport()) return true; else return super.hasFBOs(); } + @Override protected boolean hasShaders() { if (context.hasGLSL()) return true; else return super.hasShaders(); } + + /////////////////////////////////////////////////////////// + + // JOGL event listeners + + + protected class PGLListener implements GLEventListener { + public PGLListener() {} + + @Override + public void display(GLAutoDrawable glDrawable) { + drawable = glDrawable; + context = glDrawable.getContext(); + glContext = context.hashCode(); + + glThread = Thread.currentThread(); + + gl = context.getGL(); + gl2 = gl.getGL2ES2(); + try { + gl2x = gl.getGL2(); + } catch (javax.media.opengl.GLException e) { + gl2x = null; + } + + if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { + // The onscreen drawing surface is backed by an FBO layer. + GLFBODrawable fboDrawable = null; + + if (WINDOW_TOOLKIT == AWT) { + GLCanvas glCanvas = (GLCanvas)glDrawable; + fboDrawable = (GLFBODrawable)glCanvas.getDelegatedDrawable(); + } else { + GLWindow glWindow = (GLWindow)glDrawable; + fboDrawable = (GLFBODrawable)glWindow.getDelegatedDrawable(); + } + + if (fboDrawable != null) { + backFBO = fboDrawable.getFBObject(GL.GL_BACK); + if (1 < numSamples) { + if (needSepFrontTex) { + // When using multisampled FBO, the back buffer is the MSAA + // surface so it cannot be read from. The sink buffer contains + // the readable 2D texture. + // In this case, we create an auxiliary "front" buffer that it is + // swapped with the sink buffer at the beginning of each frame. + // In this way, we always have a readable copy of the previous + // frame in the front texture, while the back is synchronized + // with the contents of the MSAA back buffer when requested. + if (frontFBO == null) { + // init + frontFBO = new FBObject(); + frontFBO.reset(gl, pg.width, pg.height); + frontFBO.attachTexture2D(gl, 0, true); + sinkFBO = backFBO.getSamplingSinkFBO(); + changedFrontTex = changedBackTex = true; + } else { + // swap + FBObject temp = sinkFBO; + sinkFBO = frontFBO; + frontFBO = temp; + backFBO.setSamplingSink(sinkFBO); + changedFrontTex = changedBackTex = false; + } + backTexAttach = (FBObject.TextureAttachment) sinkFBO. + getColorbuffer(0); + frontTexAttach = (FBObject.TextureAttachment)frontFBO. + getColorbuffer(0); + } else { + // Default setting (to save resources): the front and back + // textures are the same. + sinkFBO = backFBO.getSamplingSinkFBO(); + backTexAttach = (FBObject.TextureAttachment) sinkFBO. + getColorbuffer(0); + frontTexAttach = backTexAttach; + } + + } else { + // w/out multisampling, rendering is done on the back buffer. + frontFBO = fboDrawable.getFBObject(GL.GL_FRONT); + + backTexAttach = fboDrawable.getTextureBuffer(GL.GL_BACK); + frontTexAttach = fboDrawable.getTextureBuffer(GL.GL_FRONT); + } + } + } + + pg.parent.handleDraw(); + drawLatch.countDown(); + } + + @Override + public void dispose(GLAutoDrawable adrawable) { + } + + @Override + public void init(GLAutoDrawable adrawable) { + drawable = adrawable; + context = adrawable.getContext(); + glContext = context.hashCode(); + capabilities = adrawable.getChosenGLCapabilities(); + gl = context.getGL(); + + if (!hasFBOs()) { + throw new RuntimeException(MISSING_FBO_ERROR); + } + if (!hasShaders()) { + throw new RuntimeException(MISSING_GLSL_ERROR); + } + if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { + int maxs = maxSamples(); + numSamples = PApplet.min(capabilities.getNumSamples(), maxs); + } + } + + @Override + public void reshape(GLAutoDrawable adrawable, int x, int y, int w, int h) { + drawable = adrawable; + context = adrawable.getContext(); + glContext = context.hashCode(); + } + } + + protected void nativeMouseEvent(com.jogamp.newt.event.MouseEvent nativeEvent, + int peAction) { + int modifiers = nativeEvent.getModifiers(); + int peModifiers = modifiers & + (InputEvent.SHIFT_MASK | + InputEvent.CTRL_MASK | + InputEvent.META_MASK | + InputEvent.ALT_MASK); + + int peButton = 0; + if ((modifiers & InputEvent.BUTTON1_MASK) != 0) { + peButton = PConstants.LEFT; + } else if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { + peButton = PConstants.CENTER; + } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { + peButton = PConstants.RIGHT; + } + + if (PApplet.platform == PConstants.MACOSX) { + //if (nativeEvent.isPopupTrigger()) { + if ((modifiers & InputEvent.CTRL_MASK) != 0) { + peButton = PConstants.RIGHT; + } + } + + int peCount = 0; + if (peAction == MouseEvent.WHEEL) { + peCount = nativeEvent.isShiftDown() ? (int)nativeEvent.getRotation()[0] : + (int)nativeEvent.getRotation()[1]; + } else { + peCount = nativeEvent.getClickCount(); + } + + MouseEvent me = new MouseEvent(nativeEvent, nativeEvent.getWhen(), + peAction, peModifiers, + nativeEvent.getX(), nativeEvent.getY(), + peButton, + peCount); + + pg.parent.postEvent(me); + } + + protected void nativeKeyEvent(com.jogamp.newt.event.KeyEvent nativeEvent, + int peAction) { + int peModifiers = nativeEvent.getModifiers() & + (InputEvent.SHIFT_MASK | + InputEvent.CTRL_MASK | + InputEvent.META_MASK | + InputEvent.ALT_MASK); + + char keyChar; + if ((int)nativeEvent.getKeyChar() == 0) { + keyChar = PConstants.CODED; + } else { + keyChar = nativeEvent.getKeyChar(); + } + + KeyEvent ke = new KeyEvent(nativeEvent, nativeEvent.getWhen(), + peAction, peModifiers, + keyChar, + nativeEvent.getKeyCode()); + + pg.parent.postEvent(ke); + } + + class NEWTWindowListener implements com.jogamp.newt.event.WindowListener { + @Override + public void windowGainedFocus(com.jogamp.newt.event.WindowEvent arg0) { + pg.parent.focusGained(null); + } + + @Override + public void windowLostFocus(com.jogamp.newt.event.WindowEvent arg0) { + pg.parent.focusLost(null); + } + + @Override + public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent arg0) { + } + + @Override + public void windowDestroyed(com.jogamp.newt.event.WindowEvent arg0) { + } + + @Override + public void windowMoved(com.jogamp.newt.event.WindowEvent arg0) { + } + + @Override + public void windowRepaint(com.jogamp.newt.event.WindowUpdateEvent arg0) { + } + + @Override + public void windowResized(com.jogamp.newt.event.WindowEvent arg0) { } + } + + // NEWT mouse listener + class NEWTMouseListener extends com.jogamp.newt.event.MouseAdapter { + @Override + public void mousePressed(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.PRESS); + } + @Override + public void mouseReleased(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.RELEASE); + } + @Override + public void mouseClicked(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.CLICK); + } + @Override + public void mouseDragged(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.DRAG); + } + @Override + public void mouseMoved(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.MOVE); + } + @Override + public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.WHEEL); + } + @Override + public void mouseEntered(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.ENTER); + } + @Override + public void mouseExited(com.jogamp.newt.event.MouseEvent e) { + nativeMouseEvent(e, MouseEvent.EXIT); + } + } + + // NEWT key listener + class NEWTKeyListener extends com.jogamp.newt.event.KeyAdapter { + @Override + public void keyPressed(com.jogamp.newt.event.KeyEvent e) { + nativeKeyEvent(e, KeyEvent.PRESS); + } + @Override + public void keyReleased(com.jogamp.newt.event.KeyEvent e) { + nativeKeyEvent(e, KeyEvent.RELEASE); + } + public void keyTyped(com.jogamp.newt.event.KeyEvent e) { + nativeKeyEvent(e, KeyEvent.TYPE); + } + } + + + /////////////////////////////////////////////////////////// + + // Tessellator + + + @Override + protected Tessellator createTessellator(TessellatorCallback callback) { + return new Tessellator(callback); + } + + + protected class Tessellator implements PGL.Tessellator { + protected GLUtessellator tess; + protected TessellatorCallback callback; + protected GLUCallback gluCallback; + + public Tessellator(TessellatorCallback callback) { + this.callback = callback; + tess = GLU.gluNewTess(); + gluCallback = new GLUCallback(); + + GLU.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, gluCallback); + GLU.gluTessCallback(tess, GLU.GLU_TESS_END, gluCallback); + GLU.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, gluCallback); + GLU.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, gluCallback); + GLU.gluTessCallback(tess, GLU.GLU_TESS_ERROR, gluCallback); + } + + @Override + public void beginPolygon() { + GLU.gluTessBeginPolygon(tess, null); + } + + @Override + public void endPolygon() { + GLU.gluTessEndPolygon(tess); + } + + @Override + public void setWindingRule(int rule) { + GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, rule); + } + + @Override + public void beginContour() { + GLU.gluTessBeginContour(tess); + } + + @Override + public void endContour() { + GLU.gluTessEndContour(tess); + } + + @Override + public void addVertex(double[] v) { + GLU.gluTessVertex(tess, 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); + } + } + } + + + @Override + protected String tessError(int err) { + return glu.gluErrorString(err); + } + + + /////////////////////////////////////////////////////////// + + // Font outline + + + static { + SHAPE_TEXT_SUPPORTED = true; + SEG_MOVETO = PathIterator.SEG_MOVETO; + SEG_LINETO = PathIterator.SEG_LINETO; + SEG_QUADTO = PathIterator.SEG_QUADTO; + SEG_CUBICTO = PathIterator.SEG_CUBICTO; + SEG_CLOSE = PathIterator.SEG_CLOSE; + } + + + @Override + protected FontOutline createFontOutline(char ch, Object font) { + return new FontOutline(ch, font); + } + + + protected class FontOutline implements PGL.FontOutline { + PathIterator iter; + + public FontOutline(char ch, Object font) { + char textArray[] = new char[] { ch }; + Graphics2D graphics = (Graphics2D) pg.parent.getGraphics(); + FontRenderContext frc = graphics.getFontRenderContext(); + GlyphVector gv = ((Font)font).createGlyphVector(frc, textArray); + Shape shp = gv.getOutline(); + iter = shp.getPathIterator(null); + } + + public boolean isDone() { + return iter.isDone(); + } + + public int currentSegment(float coords[]) { + return iter.currentSegment(coords); + } + + public void next() { + iter.next(); + } + } + + /////////////////////////////////////////////////////////// // Constants @@ -997,7 +1354,6 @@ public class PJOGL extends PGL { POLYGON_SMOOTH = GL2GL3.GL_POLYGON_SMOOTH; } - /////////////////////////////////////////////////////////// // Special Functions @@ -1657,7 +2013,7 @@ public class PJOGL extends PGL { @Override public String getProgramInfoLog(int program) { int[] val = { 0 }; - gl2.glGetShaderiv(program, GL2.GL_INFO_LOG_LENGTH, val, 0); + gl2.glGetShaderiv(program, GL2ES2.GL_INFO_LOG_LENGTH, val, 0); int length = val[0]; if (0 < length) { @@ -1885,410 +2241,4 @@ public class PJOGL extends PGL { gl2x.glDrawBuffer(buf); } } - - - - - - /////////////////////////////////////////////////////////// - - // JOGL Event listeners - - protected boolean changedFrontTex = false; - protected boolean changedBackTex = false; - - protected class PGLListener implements GLEventListener { - public PGLListener() {} - - @Override - public void display(GLAutoDrawable glDrawable) { - drawable = glDrawable; - context = glDrawable.getContext(); - contextID = context.hashCode(); - - glThread = Thread.currentThread(); - - gl = context.getGL(); - gl2 = gl.getGL2ES2(); - try { - gl2x = gl.getGL2(); - } catch (javax.media.opengl.GLException e) { - gl2x = null; - } - - if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { - // The onscreen drawing surface is backed by an FBO layer. - GLFBODrawable fboDrawable = null; - - if (WINDOW_TOOLKIT == AWT) { - GLCanvas glCanvas = (GLCanvas)glDrawable; - fboDrawable = (GLFBODrawable)glCanvas.getDelegatedDrawable(); - } else { - GLWindow glWindow = (GLWindow)glDrawable; - fboDrawable = (GLFBODrawable)glWindow.getDelegatedDrawable(); - } - - if (fboDrawable != null) { - backFBO = fboDrawable.getFBObject(GL.GL_BACK); - if (1 < numSamples) { - if (needSepFrontTex) { - // When using multisampled FBO, the back buffer is the MSAA - // surface so it cannot be read from. The sink buffer contains - // the readable 2D texture. - // In this case, we create an auxiliary "front" buffer that it is - // swapped with the sink buffer at the beginning of each frame. - // In this way, we always have a readable copy of the previous - // frame in the front texture, while the back is synchronized - // with the contents of the MSAA back buffer when requested. - if (frontFBO == null) { - // init - frontFBO = new FBObject(); - frontFBO.reset(gl, pg.width, pg.height); - frontFBO.attachTexture2D(gl, 0, true); - sinkFBO = backFBO.getSamplingSinkFBO(); - changedFrontTex = changedBackTex = true; - } else { - // swap - FBObject temp = sinkFBO; - sinkFBO = frontFBO; - frontFBO = temp; - backFBO.setSamplingSink(sinkFBO); - changedFrontTex = changedBackTex = false; - } - backTexAttach = (FBObject.TextureAttachment) sinkFBO. - getColorbuffer(0); - frontTexAttach = (FBObject.TextureAttachment)frontFBO. - getColorbuffer(0); - } else { - // Default setting (to save resources): the front and back - // textures are the same. - sinkFBO = backFBO.getSamplingSinkFBO(); - backTexAttach = (FBObject.TextureAttachment) sinkFBO. - getColorbuffer(0); - frontTexAttach = backTexAttach; - } - - } else { - // w/out multisampling, rendering is done on the back buffer. - frontFBO = fboDrawable.getFBObject(GL.GL_FRONT); - - backTexAttach = fboDrawable.getTextureBuffer(GL.GL_BACK); - frontTexAttach = fboDrawable.getTextureBuffer(GL.GL_FRONT); - } - } - } - - pg.parent.handleDraw(); -// clearColor(1, 0, 0, 1); -// clear(COLOR_BUFFER_BIT); - drawLatch.countDown(); - } - - @Override - public void dispose(GLAutoDrawable adrawable) { - } - - @Override - public void init(GLAutoDrawable adrawable) { - drawable = adrawable; - context = adrawable.getContext(); - contextID = context.hashCode(); - capabilities = adrawable.getChosenGLCapabilities(); - gl = context.getGL(); - - if (!hasFBOs()) { - throw new RuntimeException(MISSING_FBO_ERROR); - } - if (!hasShaders()) { - throw new RuntimeException(MISSING_GLSL_ERROR); - } - if (USE_JOGL_FBOLAYER && capabilities.isFBO()) { - int maxs = maxSamples(); - numSamples = PApplet.min(capabilities.getNumSamples(), maxs); - } - } - - @Override - public void reshape(GLAutoDrawable adrawable, int x, int y, int w, int h) { - drawable = adrawable; - context = adrawable.getContext(); - contextID = context.hashCode(); - } - } - - protected void nativeMouseEvent(com.jogamp.newt.event.MouseEvent nativeEvent, - int peAction) { - int modifiers = nativeEvent.getModifiers(); - int peModifiers = modifiers & - (InputEvent.SHIFT_MASK | - InputEvent.CTRL_MASK | - InputEvent.META_MASK | - InputEvent.ALT_MASK); - - int peButton = 0; - if ((modifiers & InputEvent.BUTTON1_MASK) != 0) { - peButton = PConstants.LEFT; - } else if ((modifiers & InputEvent.BUTTON2_MASK) != 0) { - peButton = PConstants.CENTER; - } else if ((modifiers & InputEvent.BUTTON3_MASK) != 0) { - peButton = PConstants.RIGHT; - } - - if (PApplet.platform == PConstants.MACOSX) { - //if (nativeEvent.isPopupTrigger()) { - if ((modifiers & InputEvent.CTRL_MASK) != 0) { - peButton = PConstants.RIGHT; - } - } - - int peCount = 0; - if (peAction == MouseEvent.WHEEL) { - peCount = nativeEvent.isShiftDown() ? (int)nativeEvent.getRotation()[0] : - (int)nativeEvent.getRotation()[1]; - } else { - peCount = nativeEvent.getClickCount(); - } - - MouseEvent me = new MouseEvent(nativeEvent, nativeEvent.getWhen(), - peAction, peModifiers, - nativeEvent.getX(), nativeEvent.getY(), - peButton, - peCount); - - pg.parent.postEvent(me); - } - - protected void nativeKeyEvent(com.jogamp.newt.event.KeyEvent nativeEvent, - int peAction) { - int peModifiers = nativeEvent.getModifiers() & - (InputEvent.SHIFT_MASK | - InputEvent.CTRL_MASK | - InputEvent.META_MASK | - InputEvent.ALT_MASK); - - char keyChar; - if ((int)nativeEvent.getKeyChar() == 0) { - keyChar = PConstants.CODED; - } else { - keyChar = nativeEvent.getKeyChar(); - } - - KeyEvent ke = new KeyEvent(nativeEvent, nativeEvent.getWhen(), - peAction, peModifiers, - keyChar, - nativeEvent.getKeyCode()); - - pg.parent.postEvent(ke); - } - - class NEWTWindowListener implements com.jogamp.newt.event.WindowListener { - @Override - public void windowGainedFocus(com.jogamp.newt.event.WindowEvent arg0) { - pg.parent.focusGained(null); - } - - @Override - public void windowLostFocus(com.jogamp.newt.event.WindowEvent arg0) { - pg.parent.focusLost(null); - } - - @Override - public void windowDestroyNotify(com.jogamp.newt.event.WindowEvent arg0) { - } - - @Override - public void windowDestroyed(com.jogamp.newt.event.WindowEvent arg0) { - } - - @Override - public void windowMoved(com.jogamp.newt.event.WindowEvent arg0) { - } - - @Override - public void windowRepaint(com.jogamp.newt.event.WindowUpdateEvent arg0) { - } - - @Override - public void windowResized(com.jogamp.newt.event.WindowEvent arg0) { } - } - - // NEWT mouse listener - class NEWTMouseListener extends com.jogamp.newt.event.MouseAdapter { - @Override - public void mousePressed(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.PRESS); - } - @Override - public void mouseReleased(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.RELEASE); - } - @Override - public void mouseClicked(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.CLICK); - } - @Override - public void mouseDragged(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.DRAG); - } - @Override - public void mouseMoved(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.MOVE); - } - @Override - public void mouseWheelMoved(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.WHEEL); - } - @Override - public void mouseEntered(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.ENTER); - } - @Override - public void mouseExited(com.jogamp.newt.event.MouseEvent e) { - nativeMouseEvent(e, MouseEvent.EXIT); - } - } - - // NEWT key listener - class NEWTKeyListener extends com.jogamp.newt.event.KeyAdapter { - @Override - public void keyPressed(com.jogamp.newt.event.KeyEvent e) { - nativeKeyEvent(e, KeyEvent.PRESS); - } - @Override - public void keyReleased(com.jogamp.newt.event.KeyEvent e) { - nativeKeyEvent(e, KeyEvent.RELEASE); - } - public void keyTyped(com.jogamp.newt.event.KeyEvent e) { - nativeKeyEvent(e, KeyEvent.TYPE); - } - } - - - - - @Override - protected Tessellator createTessellator(TessellatorCallback callback) { - return new Tessellator(callback); - } - - protected class Tessellator implements PGL.Tessellator { - protected GLUtessellator tess; - protected TessellatorCallback callback; - protected GLUCallback gluCallback; - - public Tessellator(TessellatorCallback callback) { - this.callback = callback; - tess = GLU.gluNewTess(); - gluCallback = new GLUCallback(); - - GLU.gluTessCallback(tess, GLU.GLU_TESS_BEGIN, gluCallback); - GLU.gluTessCallback(tess, GLU.GLU_TESS_END, gluCallback); - GLU.gluTessCallback(tess, GLU.GLU_TESS_VERTEX, gluCallback); - GLU.gluTessCallback(tess, GLU.GLU_TESS_COMBINE, gluCallback); - GLU.gluTessCallback(tess, GLU.GLU_TESS_ERROR, gluCallback); - } - - @Override - public void beginPolygon() { - GLU.gluTessBeginPolygon(tess, null); - } - - @Override - public void endPolygon() { - GLU.gluTessEndPolygon(tess); - } - - @Override - public void setWindingRule(int rule) { - GLU.gluTessProperty(tess, GLU.GLU_TESS_WINDING_RULE, rule); - } - - @Override - public void beginContour() { - GLU.gluTessBeginContour(tess); - } - - @Override - public void endContour() { - GLU.gluTessEndContour(tess); - } - - @Override - public void addVertex(double[] v) { - GLU.gluTessVertex(tess, 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); - } - } - } - - @Override - protected String tessError(int err) { - return glu.gluErrorString(err); - } - - static { - SHAPE_TEXT_SUPPORTED = true; - SEG_MOVETO = PathIterator.SEG_MOVETO; - SEG_LINETO = PathIterator.SEG_LINETO; - SEG_QUADTO = PathIterator.SEG_QUADTO; - SEG_CUBICTO = PathIterator.SEG_CUBICTO; - SEG_CLOSE = PathIterator.SEG_CLOSE; - } - - @Override - protected FontOutline createFontOutline(char ch, Object font) { - return new FontOutline(ch, font); - } - - protected class FontOutline implements PGL.FontOutline { - PathIterator iter; - - public FontOutline(char ch, Object font) { - char textArray[] = new char[] { ch }; - Graphics2D graphics = (Graphics2D) pg.parent.getGraphics(); - FontRenderContext frc = graphics.getFontRenderContext(); - GlyphVector gv = ((Font)font).createGlyphVector(frc, textArray); - Shape shp = gv.getOutline(); - iter = shp.getPathIterator(null); - } - - public boolean isDone() { - return iter.isDone(); - } - - public int currentSegment(float coords[]) { - return iter.currentSegment(coords); - } - - public void next() { - iter.next(); - } - } - } diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PGraphics2D.java b/java/libraries/lwjgl/src/processing/lwjgl/PGraphics2D.java new file mode 100644 index 000000000..501de2ba0 --- /dev/null +++ b/java/libraries/lwjgl/src/processing/lwjgl/PGraphics2D.java @@ -0,0 +1,10 @@ +package processing.lwjgl; + +import processing.opengl.PGL; +import processing.opengl.PGraphicsOpenGL; + +public class PGraphics2D extends processing.opengl.PGraphics2D { + protected PGL createPGL(PGraphicsOpenGL pg) { + return new PLWJGL(pg); + } +} diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PGraphics3D.java b/java/libraries/lwjgl/src/processing/lwjgl/PGraphics3D.java new file mode 100644 index 000000000..14bbc5c31 --- /dev/null +++ b/java/libraries/lwjgl/src/processing/lwjgl/PGraphics3D.java @@ -0,0 +1,10 @@ +package processing.lwjgl; + +import processing.opengl.PGL; +import processing.opengl.PGraphicsOpenGL; + +public class PGraphics3D extends processing.opengl.PGraphics3D { + protected PGL createPGL(PGraphicsOpenGL pg) { + return new PLWJGL(pg); + } +} diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java index baf0f1f0e..b34d4d2a3 100644 --- a/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java +++ b/java/libraries/lwjgl/src/processing/lwjgl/PGraphicsLWJGL.java @@ -30,8 +30,7 @@ import processing.opengl.PGraphicsOpenGL; * */ public class PGraphicsLWJGL extends PGraphicsOpenGL { - - static public PGL createPGL(PGraphicsOpenGL pg) { + protected PGL createPGL(PGraphicsOpenGL pg) { return new PLWJGL(pg); } } diff --git a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java index 5fe122c86..e3b54272e 100644 --- a/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java +++ b/java/libraries/lwjgl/src/processing/lwjgl/PLWJGL.java @@ -26,14 +26,18 @@ package processing.lwjgl; import java.awt.BorderLayout; import java.awt.Canvas; import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.PathIterator; 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; @@ -64,24 +68,19 @@ import processing.event.KeyEvent; import processing.event.MouseEvent; import processing.opengl.PGL; import processing.opengl.PGraphicsOpenGL; -import processing.opengl.Texture; /** - * Processing-OpenGL abstraction layer. + * Processing-OpenGL abstraction layer. LWJGL implementation. * - * 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: + * Some issues: * 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 PLWJGL extends PGL { - /////////////////////////////////////////////////////////// + // ........................................................ - // Public members to access the underlying GL objects and context + // Public members to access the underlying GL objects and canvas /** GLU interface **/ public static GLU glu; @@ -89,230 +88,30 @@ public class PLWJGL extends PGL { /** The canvas where OpenGL rendering takes place */ public static Canvas canvas; - /////////////////////////////////////////////////////////// - - // Parameters - - protected static boolean FORCE_SCREEN_FBO = false; - protected static final boolean USE_DIRECT_BUFFERS = true; - protected static final int MIN_DIRECT_BUFFER_SIZE = 16; - protected 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; - - /** Minimum/maximum dimensions of a texture used to hold font data. **/ - protected static final int MIN_FONT_TEX_SIZE = 256; - 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; - - /** Factor used to displace the stroke vertices towards the camera in - * order to make sure the lines are always on top of the fill geometry **/ - protected static final float STROKE_DISPLACEMENT = 0.999f; + // ........................................................ + + // Event handling - 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 thread */ - protected static Thread glThread; - - /** Just holds a unique ID */ - protected static int 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; - /** Desired target framerate */ - protected float targetFps = 60; - protected float currentFps = 60; - protected boolean setFps = false; - protected int fcount, lastm; - protected int fint = 3; + // ........................................................ - /** Which texturing targets are enabled */ - protected static boolean[] texturingTargets = { false, false }; - - /** Used to keep track of which textures are bound to each target */ - protected static int maxTexUnits; - protected static int activeTexUnit = 0; - protected static int[][] boundTextures; - - /////////////////////////////////////////////////////////// - - // 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 int 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 int 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; - - - /////////////////////////////////////////////////////////// - - // Error messages - - protected static final String MISSING_FBO_ERROR = - "Framebuffer objects are not supported by this hardware (or driver)"; - - protected static final String MISSING_GLSL_ERROR = - "GLSL shaders are not supported by this hardware (or driver)"; - - protected static final String MISSING_GLFUNC_ERROR = - "GL function %1$s is not available on this hardware (or driver)"; + // Utility buffers to copy projection/modelview matrices to GL + + protected FloatBuffer projMatrix; + protected FloatBuffer mvMatrix; + + // ........................................................ + + // Static initialization for some parameters that need to be different for + // LWJGL + + static { + MIN_DIRECT_BUFFER_SIZE = 16; + INDEX_TYPE = GL11.GL_UNSIGNED_SHORT; + } /////////////////////////////////////////////////////////// @@ -321,27 +120,8 @@ public class PLWJGL extends PGL { public PLWJGL(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); + super(pg); + if (glu == null) glu = new GLU(); } @@ -390,9 +170,21 @@ public class PLWJGL extends PGL { for (int i = 0; i < modes.length; i++) { bpp = PApplet.max(modes[i].getBitsPerPixel(), bpp); } - PixelFormat format = new PixelFormat(bpp, request_alpha_bits, - request_depth_bits, - request_stencil_bits, 1); + + PixelFormat format; + if (USE_FBOLAYER_BY_DEFAULT) { + format = new PixelFormat(bpp, REQUESTED_ALPHA_BITS, + REQUESTED_DEPTH_BITS, + REQUESTED_STENCIL_BITS, 1); + reqNumSamples = qualityToSamples(antialias); + fboLayerRequested = true; + } else { + format = new PixelFormat(bpp, REQUESTED_ALPHA_BITS, + REQUESTED_DEPTH_BITS, + REQUESTED_STENCIL_BITS, antialias); + fboLayerRequested = false; + } + Display.setDisplayMode(new DisplayMode(pg.parent.width, pg.parent.height)); int argb = pg.backgroundColor; float r = ((argb >> 16) & 0xff) / 255.0f; @@ -412,7 +204,7 @@ public class PLWJGL extends PGL { e.printStackTrace(); } - context = Display.getDrawable().hashCode(); + glContext = Display.getDrawable().hashCode(); keyPoller = new KeyPoller(pg.parent); keyPoller.start(); @@ -420,440 +212,21 @@ public class PLWJGL extends PGL { mousePoller = new MousePoller(pg.parent); mousePoller.start(); - reqNumSamples = qualityToSamples(antialias); + fboLayerCreated = false; fboLayerInUse = false; firstFrame = true; - needToClearBuffers = true; - setFps = false; } - 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 (!setFps) setFps(targetFps); - - if (!fboLayerCreated) { - if (!hasFBOs()) { - throw new RuntimeException("Framebuffer objects are not supported by this hardware (or driver)"); - } - if (!hasShaders()) { - throw new RuntimeException("GLSL shaders are not supported by this hardware (or driver)"); - } - - 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, pg.backgroundColor); - } - 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); - int argb = pg.backgroundColor; - float a = ((argb >> 24) & 0xff) / 255.0f; - float r = ((argb >> 16) & 0xff) / 255.0f; - float g = ((argb >> 8) & 0xff) / 255.0f; - float b = ((argb) & 0xff) / 255.0f; - clearColor(r, g, b, a); - 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 requestFBOLayer() { - 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(); - 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.colorBuffer(true); - pg.setCache(pg, tex); - return tex; - } - - - protected Texture wrapFrontTexture() { - Texture tex = new Texture(); - 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.colorBuffer(true); - return tex; - } - - - protected int getBackTextureName() { - return glColorTex.get(backTex); - } - - - protected 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 (needFBOLayer(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. - int argb = pg.backgroundColor; - float a = ((argb >> 24) & 0xff) / 255.0f; - float r = ((argb >> 16) & 0xff) / 255.0f; - float g = ((argb >> 8) & 0xff) / 255.0f; - float b = ((argb) & 0xff) / 255.0f; - clearColor(r, g, b, a); - 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; - } - - // call (gl)finish() only if the rendering of each frame is taking too long, - // to make sure that commands are not accumulating in the GL command queue. - fcount += 1; - int m = pg.parent.millis(); - if (m - lastm > 1000 * fint) { - currentFps = (float)(fcount) / fint; - fcount = 0; - lastm = m; - } - if (currentFps < 0.5f * targetFps) { - finish(); - } - } - - - protected boolean canDraw() { - return pg.initialized && pg.parent.isDisplayable(); - } - + protected void requestFocus() { } + protected void requestDraw() { if (pg.initialized) { @@ -863,1234 +236,96 @@ public class PLWJGL extends PGL { } } - - protected boolean threadIsCurrent() { - return Thread.currentThread() == glThread; + + protected void swapBuffers() { + try { + Display.swapBuffers(); + } catch (LWJGLException e) { + e.printStackTrace(); + } } - protected boolean needFBOLayer(boolean clear0) { - boolean cond = !clear0 || FORCE_SCREEN_FBO || 1 < numSamples; - return cond && glColorFbo.get(0) != 0; + @Override + protected void beginGL() { + if (projMatrix == null) { + projMatrix = allocateFloatBuffer(16); + } + GL11.glMatrixMode(GL11.GL_PROJECTION); + projMatrix.rewind(); + projMatrix.put(pg.projection.m00); + projMatrix.put(pg.projection.m10); + projMatrix.put(pg.projection.m20); + projMatrix.put(pg.projection.m30); + projMatrix.put(pg.projection.m01); + projMatrix.put(pg.projection.m11); + projMatrix.put(pg.projection.m21); + projMatrix.put(pg.projection.m31); + projMatrix.put(pg.projection.m02); + projMatrix.put(pg.projection.m12); + projMatrix.put(pg.projection.m22); + projMatrix.put(pg.projection.m32); + projMatrix.put(pg.projection.m03); + projMatrix.put(pg.projection.m13); + projMatrix.put(pg.projection.m23); + projMatrix.put(pg.projection.m33); + projMatrix.rewind(); + GL11.glLoadMatrix(projMatrix); + + if (mvMatrix == null) { + mvMatrix = allocateFloatBuffer(16); + } + GL11.glMatrixMode(GL11.GL_MODELVIEW); + mvMatrix.rewind(); + mvMatrix.put(pg.modelview.m00); + mvMatrix.put(pg.modelview.m10); + mvMatrix.put(pg.modelview.m20); + mvMatrix.put(pg.modelview.m30); + mvMatrix.put(pg.modelview.m01); + mvMatrix.put(pg.modelview.m11); + mvMatrix.put(pg.modelview.m21); + mvMatrix.put(pg.modelview.m31); + mvMatrix.put(pg.modelview.m02); + mvMatrix.put(pg.modelview.m12); + mvMatrix.put(pg.modelview.m22); + mvMatrix.put(pg.modelview.m32); + mvMatrix.put(pg.modelview.m03); + mvMatrix.put(pg.modelview.m13); + mvMatrix.put(pg.modelview.m23); + mvMatrix.put(pg.modelview.m33); + mvMatrix.rewind(); + GL11.glLoadMatrix(mvMatrix); } - - - /////////////////////////////////////////////////////////// - - // Context interface - - - protected int createEmptyContext() { - return -1; - } - - - protected int getCurrentContext() { - return context; - } - - - /////////////////////////////////////////////////////////// - - // 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(int other) { - return other == -1 || other == context; - } - - - 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 (boundTextures == null) return false; - - if (target == TEXTURE_2D) { - return boundTextures[activeTexUnit][0] == id; - } else if (target == TEXTURE_RECTANGLE) { - return boundTextures[activeTexUnit][1] == id; - } else { - return false; - } - - } - - - protected void initTexture(int target, int format, int width, int height) { - initTexture(target, format, width, height, 0); - } - - - protected void initTexture(int target, int format, int width, int height, - int initColor) { - int[] glcolor = new int[16 * 16]; - Arrays.fill(glcolor, javaToNativeARGB(initColor)); - IntBuffer texels = PLWJGL.allocateDirectIntBuffer(16 * 16); - texels.put(glcolor); - texels.rewind(); - 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); - } - } - - - public void drawTexture(int target, int id, int width, int height, - int X0, int Y0, int X1, int Y1) { - drawTexture(target, id, width, height, X0, Y0, X1, Y1, X0, Y0, X1, Y1); - } - - - public void drawTexture(int target, int id, int width, int height, - int texX0, int texY0, int texX1, int texY1, - int scrX0, int scrY0, int scrX1, int scrY1) { - 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 != context) { - 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 != context) { - 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 boolean hasFBOs() { - int major = getGLVersion()[0]; - if (major < 2) { - String ext = getString(EXTENSIONS); - return ext.indexOf("_framebuffer_object") != -1; - } - return true; // Assuming FBOs are always available for OpenGL >= 2.0 - } - - - protected boolean hasShaders() { - // GLSL might still be available through extensions. For instance, - // GLContext.hasGLSL() gives false for older intel integrated chipsets on - // OSX, where OpenGL is 1.4 but shaders are available. - int major = getGLVersion()[0]; - if (major < 2) { - String ext = getString(EXTENSIONS); - return ext.indexOf("_fragment_shader") != -1 && - ext.indexOf("_vertex_shader") != -1 && - ext.indexOf("_shader_objects") != -1 && - ext.indexOf("_shading_language") != -1; - } - return true; // Assuming shaders are always available for OpenGL >= 2.0 - } - protected static ByteBuffer allocateDirectByteBuffer(int size) { - int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_BYTE; - return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()); + return BufferUtils.createByteBuffer(size); } - protected static ByteBuffer allocateByteBuffer(int size) { - if (USE_DIRECT_BUFFERS) { - return allocateDirectByteBuffer(size); - } else { - return ByteBuffer.allocate(size); - } + protected static ShortBuffer allocateDirectShortBuffer(int size) { + return BufferUtils.createShortBuffer(size); } - - protected static ByteBuffer allocateByteBuffer(byte[] arr) { - if (USE_DIRECT_BUFFERS) { - return PLWJGL.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 = PLWJGL.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 PLWJGL.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 = PLWJGL.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(); + return BufferUtils.createIntBuffer(size); } - - 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 PLWJGL.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 = PLWJGL.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(); + return BufferUtils.createFloatBuffer(size); } - - - 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 PLWJGL.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 = PLWJGL.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 + // LWJGL event handling protected class KeyPoller extends Thread { @@ -2526,14 +761,139 @@ public class PLWJGL extends PGL { return 0; } } - - - - - - + /////////////////////////////////////////////////////////// + + // Tessellator interface + + + protected Tessellator createTessellator(TessellatorCallback callback) { + return new Tessellator(callback); + } + + + protected class Tessellator implements PGL.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); + } + + + /////////////////////////////////////////////////////////// + + // Font outline + + + static { + SHAPE_TEXT_SUPPORTED = true; + SEG_MOVETO = PathIterator.SEG_MOVETO; + SEG_LINETO = PathIterator.SEG_LINETO; + SEG_QUADTO = PathIterator.SEG_QUADTO; + SEG_CUBICTO = PathIterator.SEG_CUBICTO; + SEG_CLOSE = PathIterator.SEG_CLOSE; + } + + + protected FontOutline createFontOutline(char ch, Object font) { + return new FontOutline(ch, font); + } + + + protected class FontOutline implements PGL.FontOutline { + PathIterator iter; + + public FontOutline(char ch, Object font) { + char textArray[] = new char[] { ch }; + Graphics2D graphics = (Graphics2D) pg.parent.getGraphics(); + FontRenderContext frc = graphics.getFontRenderContext(); + GlyphVector gv = ((Font)font).createGlyphVector(frc, textArray); + Shape shp = gv.getOutline(); + iter = shp.getPathIterator(null); + } + + public boolean isDone() { + return iter.isDone(); + } + + public int currentSegment(float coords[]) { + return iter.currentSegment(coords); + } + + public void next() { + iter.next(); + } + } + /////////////////////////////////////////////////////////// @@ -2902,7 +1262,7 @@ public class PLWJGL extends PGL { } public String errorString(int err) { - return glu.gluErrorString(err); + return GLU.gluErrorString(err); } //////////////////////////////////////////////////////////////////////////////