aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/com/jogamp/opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/com/jogamp/opengl')
-rw-r--r--src/jogl/classes/com/jogamp/opengl/DebugGL2.java21
-rw-r--r--src/jogl/classes/com/jogamp/opengl/DebugGL3.java21
-rw-r--r--src/jogl/classes/com/jogamp/opengl/DebugGL3bc.java21
-rw-r--r--src/jogl/classes/com/jogamp/opengl/DebugGL4.java21
-rw-r--r--src/jogl/classes/com/jogamp/opengl/DebugGLES2.java21
-rw-r--r--src/jogl/classes/com/jogamp/opengl/DefaultGLCapabilitiesChooser.java304
-rw-r--r--src/jogl/classes/com/jogamp/opengl/FPSCounter.java117
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java236
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLArrayData.java210
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLAutoDrawable.java636
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLBase.java646
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLBufferStorage.java160
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLCapabilities.java512
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLCapabilitiesChooser.java62
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLCapabilitiesImmutable.java178
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLContext.java2038
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLDebugListener.java44
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLDebugMessage.java253
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLDrawable.java251
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java798
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLEventListener.java102
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLException.java78
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLFBODrawable.java227
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLOffscreenAutoDrawable.java69
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLPipelineFactory.java207
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLProfile.java2322
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLRunnable.java58
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLRunnable2.java44
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLSharedContextSetter.java181
-rw-r--r--src/jogl/classes/com/jogamp/opengl/GLUniformData.java227
-rw-r--r--src/jogl/classes/com/jogamp/opengl/Threading.java226
-rw-r--r--src/jogl/classes/com/jogamp/opengl/TraceGL2.java23
-rw-r--r--src/jogl/classes/com/jogamp/opengl/TraceGL3.java23
-rw-r--r--src/jogl/classes/com/jogamp/opengl/TraceGL3bc.java23
-rw-r--r--src/jogl/classes/com/jogamp/opengl/TraceGL4.java23
-rw-r--r--src/jogl/classes/com/jogamp/opengl/TraceGLES2.java23
-rw-r--r--src/jogl/classes/com/jogamp/opengl/awt/AWTGLAutoDrawable.java51
-rw-r--r--src/jogl/classes/com/jogamp/opengl/awt/ComponentEvents.java75
-rw-r--r--src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java1643
-rw-r--r--src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java2689
-rw-r--r--src/jogl/classes/com/jogamp/opengl/fixedfunc/GLLightingFunc.java70
-rw-r--r--src/jogl/classes/com/jogamp/opengl/fixedfunc/GLMatrixFunc.java152
-rw-r--r--src/jogl/classes/com/jogamp/opengl/fixedfunc/GLPointerFunc.java61
-rw-r--r--src/jogl/classes/com/jogamp/opengl/fixedfunc/GLPointerFuncUtil.java68
-rw-r--r--src/jogl/classes/com/jogamp/opengl/glu/GLUnurbs.java8
-rw-r--r--src/jogl/classes/com/jogamp/opengl/glu/GLUquadric.java33
-rw-r--r--src/jogl/classes/com/jogamp/opengl/glu/GLUtessellator.java66
-rw-r--r--src/jogl/classes/com/jogamp/opengl/glu/GLUtessellatorCallback.java356
-rw-r--r--src/jogl/classes/com/jogamp/opengl/glu/GLUtessellatorCallbackAdapter.java96
49 files changed, 15774 insertions, 0 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/DebugGL2.java b/src/jogl/classes/com/jogamp/opengl/DebugGL2.java
new file mode 100644
index 000000000..dc0f0df50
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/DebugGL2.java
@@ -0,0 +1,21 @@
+package com.jogamp.opengl;
+
+/**
+ * <p>
+ * Composable pipeline which wraps an underlying {@link GL} implementation,
+ * providing error checking after each OpenGL method call. If an error occurs,
+ * causes a {@link GLException} to be thrown at exactly the point of failure.
+ * </p>
+ * <p>
+ * Sample code which installs this pipeline, manual:
+ * <pre>
+ * gl = drawable.setGL(new DebugGL(drawable.getGL()));
+ * </pre>
+ * For automatic instantiation see {@link GLPipelineFactory#create(String, Class, GL, Object[])}.
+ * </p>
+ */
+public class DebugGL2 extends DebugGL4bc {
+ public DebugGL2(final GL2 downstream) {
+ super((GL4bc)downstream);
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/DebugGL3.java b/src/jogl/classes/com/jogamp/opengl/DebugGL3.java
new file mode 100644
index 000000000..6b27d207b
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/DebugGL3.java
@@ -0,0 +1,21 @@
+package com.jogamp.opengl;
+
+/**
+ * <p>
+ * Composable pipeline which wraps an underlying {@link GL} implementation,
+ * providing error checking after each OpenGL method call. If an error occurs,
+ * causes a {@link GLException} to be thrown at exactly the point of failure.
+ * </p>
+ * <p>
+ * Sample code which installs this pipeline, manual:
+ * <pre>
+ * gl = drawable.setGL(new DebugGL(drawable.getGL()));
+ * </pre>
+ * For automatic instantiation see {@link GLPipelineFactory#create(String, Class, GL, Object[])}.
+ * </p>
+ */
+public class DebugGL3 extends DebugGL4bc {
+ public DebugGL3(final GL3 downstream) {
+ super((GL4bc)downstream);
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/DebugGL3bc.java b/src/jogl/classes/com/jogamp/opengl/DebugGL3bc.java
new file mode 100644
index 000000000..d92f6043f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/DebugGL3bc.java
@@ -0,0 +1,21 @@
+package com.jogamp.opengl;
+
+/**
+ * <p>
+ * Composable pipeline which wraps an underlying {@link GL} implementation,
+ * providing error checking after each OpenGL method call. If an error occurs,
+ * causes a {@link GLException} to be thrown at exactly the point of failure.
+ * </p>
+ * <p>
+ * Sample code which installs this pipeline, manual:
+ * <pre>
+ * gl = drawable.setGL(new DebugGL(drawable.getGL()));
+ * </pre>
+ * For automatic instantiation see {@link GLPipelineFactory#create(String, Class, GL, Object[])}.
+ * </p>
+ */
+public class DebugGL3bc extends DebugGL4bc {
+ public DebugGL3bc(final GL3bc downstream) {
+ super((GL4bc)downstream);
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/DebugGL4.java b/src/jogl/classes/com/jogamp/opengl/DebugGL4.java
new file mode 100644
index 000000000..76f5a4ac3
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/DebugGL4.java
@@ -0,0 +1,21 @@
+package com.jogamp.opengl;
+
+/**
+ * <p>
+ * Composable pipeline which wraps an underlying {@link GL} implementation,
+ * providing error checking after each OpenGL method call. If an error occurs,
+ * causes a {@link GLException} to be thrown at exactly the point of failure.
+ * </p>
+ * <p>
+ * Sample code which installs this pipeline, manual:
+ * <pre>
+ * gl = drawable.setGL(new DebugGL(drawable.getGL()));
+ * </pre>
+ * For automatic instantiation see {@link GLPipelineFactory#create(String, Class, GL, Object[])}.
+ * </p>
+ */
+public class DebugGL4 extends DebugGL4bc {
+ public DebugGL4(final GL4 downstream) {
+ super((GL4bc)downstream);
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/DebugGLES2.java b/src/jogl/classes/com/jogamp/opengl/DebugGLES2.java
new file mode 100644
index 000000000..e2b280515
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/DebugGLES2.java
@@ -0,0 +1,21 @@
+package com.jogamp.opengl;
+
+/**
+ * <p>
+ * Composable pipeline which wraps an underlying {@link GL} implementation,
+ * providing error checking after each OpenGL method call. If an error occurs,
+ * causes a {@link GLException} to be thrown at exactly the point of failure.
+ * </p>
+ * <p>
+ * Sample code which installs this pipeline, manual:
+ * <pre>
+ * gl = drawable.setGL(new DebugGL(drawable.getGL()));
+ * </pre>
+ * For automatic instantiation see {@link GLPipelineFactory#create(String, Class, GL, Object[])}.
+ * </p>
+ */
+public class DebugGLES2 extends DebugGLES3 {
+ public DebugGLES2(final GLES2 downstream) {
+ super((GLES3)downstream);
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/DefaultGLCapabilitiesChooser.java b/src/jogl/classes/com/jogamp/opengl/DefaultGLCapabilitiesChooser.java
new file mode 100644
index 000000000..88a88087f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/DefaultGLCapabilitiesChooser.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl;
+
+import com.jogamp.nativewindow.NativeWindowException;
+
+import java.util.List;
+
+import com.jogamp.nativewindow.CapabilitiesImmutable;
+
+import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.util.PropertyAccess;
+
+import jogamp.opengl.Debug;
+
+/** <P> The default implementation of the {@link
+ GLCapabilitiesChooser} interface, which provides consistent visual
+ selection behavior across platforms. The precise algorithm is
+ deliberately left loosely specified. Some properties are: </P>
+
+ <UL>
+
+ <LI> As long as there is at least one available non-null
+ GLCapabilities which matches the "stereo" option, will return a
+ valid index.
+
+ <LI> Attempts to match as closely as possible the given
+ GLCapabilities, but will select one with fewer capabilities (i.e.,
+ lower color depth) if necessary.
+
+ <LI> Prefers hardware-accelerated visuals to
+ non-hardware-accelerated.
+
+ <LI> If there is no exact match, prefers a more-capable visual to
+ a less-capable one.
+
+ <LI> If there is more than one exact match, chooses an arbitrary
+ one.
+
+ <LI> May select the opposite of a double- or single-buffered
+ visual (based on the user's request) in dire situations.
+
+ <LI> Color depth (including alpha) mismatches are weighted higher
+ than depth buffer mismatches, which are in turn weighted higher
+ than accumulation buffer (including alpha) and stencil buffer
+ depth mismatches.
+
+ <LI> If a valid windowSystemRecommendedChoice parameter is
+ supplied, chooses that instead of using the cross-platform code.
+
+ </UL>
+*/
+
+public class DefaultGLCapabilitiesChooser implements GLCapabilitiesChooser {
+ private static final boolean DEBUG;
+
+ static {
+ Debug.initSingleton();
+ DEBUG = PropertyAccess.isPropertyDefined("jogl.debug.CapabilitiesChooser", true);
+ }
+
+ private final static int NO_SCORE = -9999999;
+ private final static int DOUBLE_BUFFER_MISMATCH_PENALTY = 1000;
+ private final static int OPAQUE_MISMATCH_PENALTY = 750;
+ private final static int STENCIL_MISMATCH_PENALTY = 500;
+ private final static int MULTISAMPLE_MISMATCH_PENALTY = 500;
+ private final static int MULTISAMPLE_EXTENSION_MISMATCH_PENALTY = 250; // just a little drop, no scale
+ // Pseudo attempt to keep equal rank penalties scale-equivalent
+ // (e.g., stencil mismatch is 3 * accum because there are 3 accum
+ // components)
+ private final static int COLOR_MISMATCH_PENALTY_SCALE = 36;
+ private final static int DEPTH_MISMATCH_PENALTY_SCALE = 6;
+ private final static int ACCUM_MISMATCH_PENALTY_SCALE = 1;
+ private final static int STENCIL_MISMATCH_PENALTY_SCALE = 3;
+ private final static int MULTISAMPLE_MISMATCH_PENALTY_SCALE = 3;
+
+ @Override
+ public int chooseCapabilities(final CapabilitiesImmutable desired,
+ final List<? extends CapabilitiesImmutable> available,
+ final int windowSystemRecommendedChoice) {
+ if ( null == desired ) {
+ throw new NativeWindowException("Null desired capabilities");
+ }
+ if ( 0 == available.size() ) {
+ throw new NativeWindowException("Empty available capabilities");
+ }
+
+ final GLCapabilitiesImmutable gldes = (GLCapabilitiesImmutable) desired;
+ final int availnum = available.size();
+
+ if (DEBUG) {
+ ExceptionUtils.dumpStack(System.err);
+ System.err.println("Desired: " + gldes);
+ System.err.println("Available: " + availnum);
+ for (int i = 0; i < available.size(); i++) {
+ System.err.println(i + ": " + available.get(i));
+ }
+ System.err.println("Window system's recommended choice: " + windowSystemRecommendedChoice);
+ }
+
+ if (windowSystemRecommendedChoice >= 0 &&
+ windowSystemRecommendedChoice < availnum &&
+ null != available.get(windowSystemRecommendedChoice)) {
+ if (DEBUG) {
+ System.err.println("Choosing window system's recommended choice of " + windowSystemRecommendedChoice);
+ System.err.println(available.get(windowSystemRecommendedChoice));
+ }
+ return windowSystemRecommendedChoice;
+ }
+
+ // Create score array
+ final int[] scores = new int[availnum];
+
+ for (int i = 0; i < scores.length; i++) {
+ scores[i] = NO_SCORE;
+ }
+ final int gldes_samples = gldes.getNumSamples();
+
+ // Compute score for each
+ for (int i = 0; i < availnum; i++) {
+ final GLCapabilitiesImmutable cur = (GLCapabilitiesImmutable) available.get(i);
+ if (cur == null) {
+ continue;
+ }
+ if (gldes.isOnscreen() && !cur.isOnscreen()) {
+ continue; // requested onscreen, but n/a
+ }
+ if (!gldes.isOnscreen()) {
+ /** FBO is generic ..
+ if (gldes.isFBO() && !cur.isFBO()) {
+ continue; // requested FBO, but n/a
+ } */
+ if (gldes.isPBuffer() && !cur.isPBuffer()) {
+ continue; // requested pBuffer, but n/a
+ }
+ if (gldes.isBitmap() && !cur.isBitmap()) {
+ continue; // requested pBuffer, but n/a
+ }
+ }
+ if (gldes.getStereo() != cur.getStereo()) {
+ continue;
+ }
+ final int cur_samples = cur.getNumSamples() ;
+ int score = 0;
+
+ // Compute difference in color depth
+ // (Note that this decides the direction of all other penalties)
+ score += (COLOR_MISMATCH_PENALTY_SCALE *
+ ((cur.getRedBits() + cur.getGreenBits() + cur.getBlueBits() + cur.getAlphaBits()) -
+ (gldes.getRedBits() + gldes.getGreenBits() + gldes.getBlueBits() + gldes.getAlphaBits())));
+ // Compute difference in depth buffer depth
+ score += (DEPTH_MISMATCH_PENALTY_SCALE * sign(score) *
+ Math.abs(cur.getDepthBits() - gldes.getDepthBits()));
+ // Compute difference in accumulation buffer depth
+ score += (ACCUM_MISMATCH_PENALTY_SCALE * sign(score) *
+ Math.abs((cur.getAccumRedBits() + cur.getAccumGreenBits() + cur.getAccumBlueBits() + cur.getAccumAlphaBits()) -
+ (gldes.getAccumRedBits() + gldes.getAccumGreenBits() + gldes.getAccumBlueBits() + gldes.getAccumAlphaBits())));
+ // Compute difference in stencil bits
+ score += STENCIL_MISMATCH_PENALTY_SCALE * sign(score) * (cur.getStencilBits() - gldes.getStencilBits());
+ // Compute difference in multisampling bits
+ score += MULTISAMPLE_MISMATCH_PENALTY_SCALE * sign(score) * (cur_samples - gldes_samples);
+ // double buffer
+ if (cur.getDoubleBuffered() != gldes.getDoubleBuffered()) {
+ score += sign(score) * DOUBLE_BUFFER_MISMATCH_PENALTY;
+ }
+ // opaque
+ if (cur.isBackgroundOpaque() != gldes.isBackgroundOpaque()) {
+ score += sign(score) * OPAQUE_MISMATCH_PENALTY;
+ }
+ if ((gldes.getStencilBits() > 0) && (cur.getStencilBits() == 0)) {
+ score += sign(score) * STENCIL_MISMATCH_PENALTY;
+ }
+ if (gldes_samples > 0) {
+ if (cur_samples == 0) {
+ score += sign(score) * MULTISAMPLE_MISMATCH_PENALTY;
+ }
+ if (!gldes.getSampleExtension().equals(cur.getSampleExtension())) {
+ score += sign(score) * MULTISAMPLE_EXTENSION_MISMATCH_PENALTY;
+ }
+ }
+ scores[i] = score;
+ }
+ // Now prefer hardware-accelerated visuals by pushing scores of
+ // non-hardware-accelerated visuals out
+ boolean gotHW = false;
+ int maxAbsoluteHWScore = 0;
+ for (int i = 0; i < availnum; i++) {
+ final int score = scores[i];
+ if (score == NO_SCORE) {
+ continue;
+ }
+ final GLCapabilitiesImmutable cur = (GLCapabilitiesImmutable) available.get(i);
+ if (cur.getHardwareAccelerated()) {
+ final int absScore = Math.abs(score);
+ if (!gotHW ||
+ (absScore > maxAbsoluteHWScore)) {
+ gotHW = true;
+ maxAbsoluteHWScore = absScore;
+ }
+ }
+ }
+ if (gotHW) {
+ for (int i = 0; i < availnum; i++) {
+ int score = scores[i];
+ if (score == NO_SCORE) {
+ continue;
+ }
+ final GLCapabilitiesImmutable cur = (GLCapabilitiesImmutable) available.get(i);
+ if (!cur.getHardwareAccelerated()) {
+ if (score <= 0) {
+ score -= maxAbsoluteHWScore;
+ } else if (score > 0) {
+ score += maxAbsoluteHWScore;
+ }
+ scores[i] = score;
+ }
+ }
+ }
+
+ if (DEBUG) {
+ System.err.print("Scores: [");
+ for (int i = 0; i < availnum; i++) {
+ if (i > 0) {
+ System.err.print(",");
+ }
+ System.err.print(" " + i +": " + scores[i]);
+ }
+ System.err.println(" ]");
+ }
+
+ // Ready to select. Choose score closest to 0.
+ int scoreClosestToZero = NO_SCORE;
+ int chosenIndex = -1;
+ for (int i = 0; i < availnum; i++) {
+ final int score = scores[i];
+ if (score == NO_SCORE) {
+ continue;
+ }
+ // Don't substitute a positive score for a smaller negative score
+ if ((scoreClosestToZero == NO_SCORE) ||
+ (Math.abs(score) < Math.abs(scoreClosestToZero) &&
+ ((sign(scoreClosestToZero) < 0) || (sign(score) > 0)))) {
+ scoreClosestToZero = score;
+ chosenIndex = i;
+ }
+ }
+ if (chosenIndex < 0) {
+ throw new NativeWindowException("Unable to select one of the provided GLCapabilities");
+ }
+ if (DEBUG) {
+ System.err.println("Chosen index: " + chosenIndex);
+ System.err.println("Chosen capabilities:");
+ System.err.println(available.get(chosenIndex));
+ }
+
+ return chosenIndex;
+ }
+
+ private static int sign(final int score) {
+ if (score < 0) {
+ return -1;
+ }
+ return 1;
+ }
+
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/FPSCounter.java b/src/jogl/classes/com/jogamp/opengl/FPSCounter.java
new file mode 100644
index 000000000..a3b7ccb70
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/FPSCounter.java
@@ -0,0 +1,117 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl;
+
+import java.io.PrintStream;
+
+/**
+ * FPSCounter feature.<br>
+ * An implementation initially has the FPSCounter feature disabled.<br>
+ * Use {@link #setUpdateFPSFrames(int, PrintStream)} to enable and disable the FPSCounter feature.
+ */
+public interface FPSCounter {
+ public static final int DEFAULT_FRAMES_PER_INTERVAL = 5*60;
+
+ /**
+ * @param frames Update interval in frames.<br> At every rendered <i>frames</i> interval the currentTime and fps values are updated.
+ * If the <i>frames</i> interval is <= 0, no update will be issued, ie the FPSCounter feature is turned off. You may choose {@link #DEFAULT_FRAMES_PER_INTERVAL}.
+ * @param out optional print stream where the fps values gets printed if not null at every <i>frames</i> interval
+ */
+ void setUpdateFPSFrames(int frames, PrintStream out);
+
+ /**
+ * Reset all performance counter (startTime, currentTime, frame number)
+ */
+ void resetFPSCounter();
+
+ /**
+ * @return update interval in frames
+ *
+ * @see #setUpdateFPSFrames(int, PrintStream)
+ */
+ int getUpdateFPSFrames();
+
+ /**
+ * Returns the time of the first display call in milliseconds after enabling this feature via {@link #setUpdateFPSFrames(int, PrintStream)}.<br>
+ * This value is reset via {@link #resetFPSCounter()}.
+ *
+ * @see #setUpdateFPSFrames(int, PrintStream)
+ * @see #resetFPSCounter()
+ */
+ long getFPSStartTime();
+
+ /**
+ * Returns the time of the last update interval in milliseconds, if this feature is enabled via {@link #setUpdateFPSFrames(int, PrintStream)}.<br>
+ * This value is reset via {@link #resetFPSCounter()}.
+ *
+ * @see #setUpdateFPSFrames(int, PrintStream)
+ * @see #resetFPSCounter()
+ */
+ long getLastFPSUpdateTime();
+
+ /**
+ * @return Duration of the last update interval in milliseconds.
+ *
+ * @see #setUpdateFPSFrames(int, PrintStream)
+ * @see #resetFPSCounter()
+ */
+ long getLastFPSPeriod();
+
+ /**
+ * @return Last update interval's frames per seconds, {@link #getUpdateFPSFrames()} / {@link #getLastFPSPeriod()}
+ *
+ * @see #setUpdateFPSFrames(int, PrintStream)
+ * @see #resetFPSCounter()
+ */
+ float getLastFPS();
+
+ /**
+ * @return Number of frame rendered since {@link #getFPSStartTime()} up to {@link #getLastFPSUpdateTime()}
+ *
+ * @see #setUpdateFPSFrames(int, PrintStream)
+ * @see #resetFPSCounter()
+ */
+ int getTotalFPSFrames();
+
+ /**
+ * @return Total duration in milliseconds, {@link #getLastFPSUpdateTime()} - {@link #getFPSStartTime()}
+ *
+ * @see #setUpdateFPSFrames(int, PrintStream)
+ * @see #resetFPSCounter()
+ */
+ long getTotalFPSDuration();
+
+
+ /**
+ * @return Total frames per seconds, {@link #getTotalFPSFrames()} / {@link #getTotalFPSDuration()}
+ *
+ * @see #setUpdateFPSFrames(int, PrintStream)
+ * @see #resetFPSCounter()
+ */
+ float getTotalFPS();
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java b/src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java
new file mode 100644
index 000000000..549efd569
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLAnimatorControl.java
@@ -0,0 +1,236 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl;
+
+/**
+ * An animator control interface,
+ * which implementation may drive a {@link com.jogamp.opengl.GLAutoDrawable} animation.
+ */
+public interface GLAnimatorControl extends FPSCounter {
+ /**
+ * A {@link GLAnimatorControl#setUncaughtExceptionHandler(UncaughtExceptionHandler) registered}
+ * {@link UncaughtExceptionHandler} instance is invoked when an {@link GLAnimatorControl animator} abruptly {@link #stop() stops}
+ * due to an uncaught exception from one of its {@link GLAutoDrawable}s.
+ * @see #uncaughtException(GLAnimatorControl, GLAutoDrawable, Throwable)
+ * @see GLAnimatorControl#setUncaughtExceptionHandler(UncaughtExceptionHandler)
+ * @since 2.2
+ */
+ public static interface UncaughtExceptionHandler {
+ /**
+ * Method invoked when the given {@link GLAnimatorControl} is {@link GLAnimatorControl#stop() stopped} due to the
+ * given uncaught exception happened on the given {@link GLAutoDrawable}.
+ * <p>
+ * The animator thread can still be retrieved via {@link GLAnimatorControl#getThread()}.
+ * </p>
+ * <p>
+ * All {@link GLAnimatorControl} states already reflect its stopped state.
+ * </p>
+ * <p>
+ * After this handler method is called, the {@link GLAnimatorControl} is stopped.
+ * </p>
+ * <p>
+ * Any exception thrown by this method will be ignored.
+ * </p>
+ * @param animator the {@link GLAnimatorControl}
+ * @param drawable the causing {@link GLAutoDrawable}
+ * @param cause the uncaught exception
+ * @see GLAnimatorControl#setUncaughtExceptionHandler(UncaughtExceptionHandler)
+ * @since 2.2
+ */
+ void uncaughtException(final GLAnimatorControl animator, final GLAutoDrawable drawable, final Throwable cause);
+ }
+
+ /**
+ * Indicates whether this animator has been {@link #start() started}.
+ *
+ * @see #start()
+ * @see #stop()
+ * @see #isPaused()
+ * @see #pause()
+ * @see #resume()
+ */
+ boolean isStarted();
+
+ /**
+ * Indicates whether this animator {@link #isStarted() is started} and {@link #isPaused() is not paused}.
+ *
+ * @see #start()
+ * @see #stop()
+ * @see #pause()
+ * @see #resume()
+ */
+ boolean isAnimating();
+
+ /**
+ * Indicates whether this animator {@link #isStarted() is started}
+ * and either {@link #pause() manually paused} or paused
+ * automatically due to no {@link #add(GLAutoDrawable) added} {@link GLAutoDrawable}s.
+ *
+ * @see #start()
+ * @see #stop()
+ * @see #pause()
+ * @see #resume()
+ */
+ boolean isPaused();
+
+ /**
+ * @return The animation thread if running, otherwise null.
+ *
+ * @see #start()
+ * @see #stop()
+ */
+ Thread getThread();
+
+ /**
+ * Starts this animator, if not running.
+ * <p>
+ * In most situations this method blocks until
+ * completion, except when called from the animation thread itself
+ * or in some cases from an implementation-internal thread like the
+ * AWT event queue thread.
+ * </p>
+ * <p>
+ * Note that an animator w/o {@link #add(GLAutoDrawable) added drawables}
+ * will be paused automatically.
+ * </p>
+ * <p>
+ * If started, all counters (time, frames, ..) are reset to zero.
+ * </p>
+ *
+ * @return true is started due to this call,
+ * otherwise false, ie started already or unable to start.
+ *
+ * @see #stop()
+ * @see #isAnimating()
+ * @see #isPaused()
+ * @see #getThread()
+ */
+ boolean start();
+
+ /**
+ * Stops this animator.
+ * <p>
+ * In most situations this method blocks until
+ * completion, except when called from the animation thread itself
+ * or in some cases from an implementation-internal thread like the
+ * AWT event queue thread.
+ * </p>
+ *
+ * @return true is stopped due to this call,
+ * otherwise false, ie not started or unable to stop.
+ *
+ * @see #start()
+ * @see #isAnimating()
+ * @see #getThread()
+ */
+ boolean stop();
+
+ /**
+ * Pauses this animator.
+ * <p>
+ * In most situations this method blocks until
+ * completion, except when called from the animation thread itself
+ * or in some cases from an implementation-internal thread like the
+ * AWT event queue thread.
+ * </p>
+ *
+ * @return false if not started, already paused or failed to pause, otherwise true
+ *
+ * @see #resume()
+ * @see #isAnimating()
+ */
+ boolean pause();
+
+ /**
+ * Resumes animation if paused.
+ * <p>
+ * In most situations this method blocks until
+ * completion, except when called from the animation thread itself
+ * or in some cases from an implementation-internal thread like the
+ * AWT event queue thread.
+ * </p>
+ * <p>
+ * If resumed, all counters (time, frames, ..) are reset to zero.
+ * </p>
+ *
+ * @return false if not started, not paused or unable to resume, otherwise true
+ *
+ * @see #pause()
+ * @see #isAnimating()
+ */
+ boolean resume();
+
+ /**
+ * Adds a drawable to this animator's list of rendering drawables.
+ * <p>
+ * This allows the animator thread to become {@link #isAnimating() animating},
+ * in case the first drawable is added and the animator {@link #isStarted() is started}.
+ * </p>
+ *
+ * @param drawable the drawable to be added
+ * @throws IllegalArgumentException if drawable was already added to this animator
+ */
+ void add(GLAutoDrawable drawable);
+
+ /**
+ * Removes a drawable from the animator's list of rendering drawables.
+ * <p>
+ * This method should get called in case a drawable becomes invalid,
+ * and will not be recovered.
+ * </p>
+ * <p>
+ * This allows the animator thread to become {@link #isAnimating() not animating},
+ * in case the last drawable has been removed.
+ * </p>
+ *
+ * @param drawable the drawable to be removed
+ * @throws IllegalArgumentException if drawable was not added to this animator
+ */
+ void remove(GLAutoDrawable drawable);
+
+ /**
+ * Returns the {@link UncaughtExceptionHandler} invoked when this {@link GLAnimatorControl animator} abruptly {@link #stop() stops}
+ * due to an uncaught exception from one of its {@link GLAutoDrawable}s.
+ * <p>
+ * Default is <code>null</code>.
+ * </p>
+ * @since 2.2
+ */
+ UncaughtExceptionHandler getUncaughtExceptionHandler();
+
+ /**
+ * Set the handler invoked when this {@link GLAnimatorControl animator} abruptly {@link #stop() stops}
+ * due to an uncaught exception from one of its {@link GLAutoDrawable}s.
+ * @param handler the {@link UncaughtExceptionHandler} to use as this {@link GLAnimatorControl animator}'s uncaught exception
+ * handler. Pass <code>null</code> to unset the handler.
+ * @see UncaughtExceptionHandler#uncaughtException(GLAnimatorControl, GLAutoDrawable, Throwable)
+ * @since 2.2
+ */
+ void setUncaughtExceptionHandler(final UncaughtExceptionHandler handler);
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLArrayData.java b/src/jogl/classes/com/jogamp/opengl/GLArrayData.java
new file mode 100644
index 000000000..ea2dfb0f3
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLArrayData.java
@@ -0,0 +1,210 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl;
+
+import java.nio.Buffer;
+
+import com.jogamp.opengl.fixedfunc.GLPointerFunc;
+
+/**
+ *
+ * The total number of bytes hold by the referenced buffer is:
+ * getComponentSize()* getComponentNumber() * getElementNumber()
+ *
+ */
+public interface GLArrayData {
+ /**
+ * Implementation and type dependent object association.
+ * <p>
+ * One currently known use case is to associate a {@link com.jogamp.opengl.util.glsl.ShaderState ShaderState}
+ * to an GLSL aware vertex attribute object, allowing to use the ShaderState to handle it's
+ * data persistence, location and state change.<br/>
+ * This is implicitly done via {@link com.jogamp.opengl.util.glsl.ShaderState#ownAttribute(GLArrayData, boolean) shaderState.ownAttribute(GLArrayData, boolean)}.
+ * </p>
+ * @param obj implementation and type dependent association
+ * @param enable pass true to enable the association and false to disable it.
+ */
+ public void associate(Object obj, boolean enable);
+
+ /**
+ * Returns true if this data set is intended for a GLSL vertex shader attribute,
+ * otherwise false, ie intended for fixed function vertex pointer
+ */
+ public boolean isVertexAttribute();
+
+ /**
+ * The index of the predefined array index, see list below,
+ * or -1 in case of a shader attribute array.
+ *
+ * @see GLPointerFunc#GL_VERTEX_ARRAY
+ * @see GLPointerFunc#GL_NORMAL_ARRAY
+ * @see GLPointerFunc#GL_COLOR_ARRAY
+ * @see GLPointerFunc#GL_TEXTURE_COORD_ARRAY
+ */
+ public int getIndex();
+
+ /**
+ * The name of the reflecting shader array attribute.
+ */
+ public String getName();
+
+ /**
+ * Set a new name for this array.
+ * <p>
+ * This clears the location, i.e. sets it to -1.
+ * </p>
+ * @see #setLocation(int)
+ * @see #setLocation(GL2ES2, int)
+ */
+ public void setName(String newName);
+
+
+ /**
+ * Returns the shader attribute location for this name,
+ * -1 if not yet determined
+ */
+ public int getLocation();
+
+ /**
+ * Sets the given location of the shader attribute
+ *
+ * @return the given location
+ * @see com.jogamp.opengl.util.glsl.ShaderState#vertexAttribPointer(GL2ES2, GLArrayData)
+ */
+ public int setLocation(int v);
+
+ /**
+ * Retrieves the location of the shader attribute from the linked shader program.
+ * <p>
+ * No validation is performed within the implementation.
+ * </p>
+ * @param gl
+ * @param program
+ * @return &ge;0 denotes a valid attribute location as found and used in the given shader program.
+ * &lt;0 denotes an invalid location, i.e. not found or used in the given shader program.
+ */
+ public int setLocation(GL2ES2 gl, int program);
+
+ /**
+ * Binds the location of the shader attribute to the given location for the unlinked shader program.
+ * <p>
+ * No validation is performed within the implementation.
+ * </p>
+ * @param gl
+ * @param program
+ * @return the given location
+ */
+ public int setLocation(GL2ES2 gl, int program, int location);
+
+ /**
+ * Determines whether the data is server side (VBO) and enabled,
+ * or a client side array (false).
+ */
+ public boolean isVBO();
+
+ /**
+ * The VBO buffer offset or 0 if not a VBO
+ */
+ public long getVBOOffset();
+
+ /**
+ * The VBO name or 0 if not a VBO
+ */
+ public int getVBOName();
+
+ /**
+ * The VBO usage or 0 if not a VBO
+ * @return 0 if not a GPU buffer, otherwise {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW}
+ */
+ public int getVBOUsage();
+
+ /**
+ * The VBO target or 0 if not a VBO
+ * @return 0 if not a GPU buffer, otherwise {@link GL#GL_ARRAY_BUFFER} or {@link GL#GL_ELEMENT_ARRAY_BUFFER}
+ */
+ public int getVBOTarget();
+
+
+ /**
+ * The Buffer holding the data, may be null if a GPU buffer without client bound data
+ */
+ public Buffer getBuffer();
+
+ /**
+ * The number of components per element
+ */
+ public int getComponentCount();
+
+ /**
+ * The component's GL data type, ie. GL_FLOAT
+ */
+ public int getComponentType();
+
+ /**
+ * The component's size in bytes
+ */
+ public int getComponentSizeInBytes();
+
+ /**
+ * The current number of used elements.
+ * <p>
+ * On element consist out of {@link #getComponentCount()} components.
+ * </p>
+ * In case the buffer's position is 0 (sealed, flipped), it's based on it's limit instead of it's position.
+ */
+ public int getElementCount();
+
+ /**
+ * The currently used size in bytes.<br>
+ * In case the buffer's position is 0 (sealed, flipped), it's based on it's limit instead of it's position.
+ */
+ public int getSizeInBytes();
+
+ /**
+ * True, if GL shall normalize fixed point data while converting
+ * them into float.
+ * <p>
+ * Default behavior (of the fixed function pipeline) is <code>true</code>
+ * for fixed point data type and <code>false</code> for floating point data types.
+ * </p>
+ */
+ public boolean getNormalized();
+
+ /**
+ * @return the byte offset between consecutive components
+ */
+ public int getStride();
+
+ @Override
+ public String toString();
+
+ public void destroy(GL gl);
+
+}
+
diff --git a/src/jogl/classes/com/jogamp/opengl/GLAutoDrawable.java b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawable.java
new file mode 100644
index 000000000..385acf082
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLAutoDrawable.java
@@ -0,0 +1,636 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl;
+
+import java.util.List;
+
+import com.jogamp.nativewindow.NativeSurface;
+
+import com.jogamp.common.util.locks.RecursiveLock;
+
+import jogamp.opengl.Debug;
+
+/** A higher-level abstraction than {@link GLDrawable} which supplies
+ an event based mechanism ({@link GLEventListener}) for performing
+ OpenGL rendering. A GLAutoDrawable automatically creates a primary
+ rendering context which is associated with the GLAutoDrawable for
+ the lifetime of the object.
+ <p>
+ Since the {@link GLContext} {@link GLContext#makeCurrent makeCurrent}
+ implementation is synchronized, i.e. blocks if the context
+ is current on another thread, the internal
+ {@link GLContext} for the GLAutoDrawable can be used for the event
+ based rendering mechanism and by end users directly.
+ </p>
+ <h5><a name="initialization">GLAutoDrawable Initialization</a></h5>
+ <p>
+ The implementation shall initialize itself as soon as possible,
+ which is only possible <i>after</i> the attached {@link com.jogamp.nativewindow.NativeSurface NativeSurface} becomes visible and and is realized.<br>
+ The following initialization sequence should be implemented:
+ <ul>
+ <li> Create the {@link GLDrawable} with the requested {@link GLCapabilities}</li>
+ <li> Notify {@link GLDrawable} to validate the {@link GLCapabilities} by calling {@link GLDrawable#setRealized setRealized(true)}.</li>
+ <li> Create the new {@link GLContext}.</li>
+ <li> Initialize all OpenGL resources by calling {@link GLEventListener#init init(..)} for all
+ registered {@link GLEventListener}s. This can be done immediately, or with the followup {@link #display display(..)} call.</li>
+ <li> Send a reshape event by calling {@link GLEventListener#reshape reshape(..)} for all
+ registered {@link GLEventListener}s. This shall be done after the {@link GLEventListener#init init(..)} calls.</li>
+ </ul>
+ Note: The last to {@link GLEventListener} actions shall be also performed, when {@link #addGLEventListener(GLEventListener) adding}
+ a new one to an already initialized {@link GLAutoDrawable}.
+ </p>
+ <h5><a name="reconfiguration">GLAutoDrawable Reconfiguration</a></h5>
+ <p>
+ Another implementation detail is the {@link GLDrawable} reconfiguration. One use case is where a window is being
+ dragged to another screen with a different pixel configuration, ie {@link GLCapabilities}. The implementation
+ shall be able to detect such cases in conjunction with the associated {@link com.jogamp.nativewindow.NativeSurface NativeSurface}.<br/>
+ For example, AWT's {@link java.awt.Canvas} 's {@link java.awt.Canvas#getGraphicsConfiguration getGraphicsConfiguration()}
+ is capable to determine a display device change. This is demonstrated within {@link com.jogamp.opengl.awt.GLCanvas}'s
+ and NEWT's <code>AWTCanvas</code> {@link com.jogamp.opengl.awt.GLCanvas#getGraphicsConfiguration getGraphicsConfiguration()}
+ specialization. Another demonstration is NEWT's {@link com.jogamp.nativewindow.NativeWindow NativeWindow}
+ implementation on the Windows platform, which utilizes the native platform's <i>MonitorFromWindow(HWND)</i> function.<br/>
+ All OpenGL resources shall be regenerated, while the drawable's {@link GLCapabilities} has
+ to be chosen again. The following protocol shall be satisfied.
+ <ul>
+ <li> Controlled disposal:</li>
+ <ul>
+ <li> Dispose all OpenGL resources by calling {@link GLEventListener#dispose dispose(..)} for all
+ registered {@link GLEventListener}s.</li>
+ <li> Destroy the {@link GLContext}.</li>
+ <li> Notify {@link GLDrawable} of the invalid state by calling {@link GLDrawable#setRealized setRealized(false)}.</li>
+ </ul>
+ <li> Controlled regeneration:</li>
+ <ul>
+ <li> Create the new {@link GLDrawable} with the requested {@link GLCapabilities}
+ <li> Notify {@link GLDrawable} to revalidate the {@link GLCapabilities} by calling {@link GLDrawable#setRealized setRealized(true)}.</li>
+ <li> Create the new {@link GLContext}.</li>
+ <li> Initialize all OpenGL resources by calling {@link GLEventListener#init init(..)} for all
+ registered {@link GLEventListener}s. This can be done immediatly, or with the followup {@link #display display(..)} call.</li>
+ <li> Send a reshape event by calling {@link GLEventListener#reshape reshape(..)} for all
+ registered {@link GLEventListener}s. This shall be done after the {@link GLEventListener#init init(..)} calls.</li>
+ </ul>
+ </ul>
+ Note: Current graphics driver keep the surface configuration for a given window, even if the window is moved to
+ a monitor with a different pixel configuration, ie 32bpp to 16bpp. However, it is best to not assume such behavior
+ and make your application comply with the above protocol.
+ <p>
+ Avoiding breakage with older applications and because of the situation
+ mentioned above, the <code>boolean</code> system property <code>jogl.screenchange.action</code> will control the
+ screen change action as follows:<br/>
+ <PRE>
+ -Djogl.screenchange.action=false Disable the {@link GLDrawable} reconfiguration (the default)
+ -Djogl.screenchange.action=true Enable the {@link GLDrawable} reconfiguration
+ </PRE>
+ </p>
+ <h5><a name="locking">GLAutoDrawable Locking</a></h5>
+ GLAutoDrawable implementations perform locking in the following order:
+ <ol>
+ <li> {@link #getUpstreamLock()}.{@link RecursiveLock#lock() lock()}</li>
+ <li> {@link #getNativeSurface()}.{@link NativeSurface#lockSurface() lockSurface()} </li>
+ </ol>
+ and releases the locks accordingly:
+ <ol>
+ <li> {@link #getNativeSurface()}.{@link NativeSurface#unlockSurface() unlockSurface()} </li>
+ <li> {@link #getUpstreamLock()}.{@link RecursiveLock#unlock() unlock()}</li>
+ </ol>
+ Above <i>locking order</i> is mandatory to guarantee
+ atomicity of operation and to avoid race-conditions.
+ A custom implementation or user applications requiring exclusive access
+ shall follow the <i>locking order</i>.
+ See:
+ <ul>
+ <li>{@link #getUpstreamLock()}</li>
+ <li>{@link #invoke(boolean, GLRunnable)}</li>
+ <li>{@link #invoke(boolean, List)}</li>
+ </ul>
+ </p>
+ */
+public interface GLAutoDrawable extends GLDrawable {
+ /** Flag reflecting whether the {@link GLDrawable} reconfiguration will be issued in
+ * case a screen device change occurred, e.g. in a multihead environment,
+ * where you drag the window to another monitor. */
+ public static final boolean SCREEN_CHANGE_ACTION_ENABLED = Debug.getBooleanProperty("jogl.screenchange.action", true);
+
+ /**
+ * If the implementation uses delegation, return the delegated {@link GLDrawable} instance,
+ * otherwise return <code>this</code> instance.
+ */
+ public GLDrawable getDelegatedDrawable();
+
+ /**
+ * Returns the context associated with this drawable. The returned
+ * context will be synchronized.
+ * Don't rely on it's identity, the context may change.
+ */
+ public GLContext getContext();
+
+ /**
+ * Associate the new context, <code>newtCtx</code>, to this auto-drawable.
+ * <p>
+ * Remarks:
+ * <ul>
+ * <li>The currently associated context will be destroyed if <code>destroyPrevCtx</code> is <code>true</code>,
+ * otherwise it will be disassociated from this auto-drawable
+ * via {@link GLContext#setGLDrawable(GLDrawable, boolean) setGLDrawable(null, true);} including {@link GL#glFinish() glFinish()}.</li>
+ * <li>The new context will be associated with this auto-drawable
+ * via {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}.</li>
+ * <li>If the old context was current on this thread, it is being released after disassociating this auto-drawable.</li>
+ * <li>If the new context was current on this thread, it is being released before associating this auto-drawable
+ * and made current afterwards.</li>
+ * <li>Implementation may issue {@link #makeCurrent()} and {@link #release()} while drawable reassociation.</li>
+ * <li>The user shall take extra care of thread synchronization,
+ * i.e. lock the involved {@link GLAutoDrawable auto-drawable's}
+ * {@link GLAutoDrawable#getUpstreamLock() upstream-locks} and {@link GLAutoDrawable#getNativeSurface() surfaces}
+ * to avoid a race condition. See <a href="#locking">GLAutoDrawable Locking</a>.</li>
+ * </ul>
+ * </p>
+ *
+ * @param newCtx the new context, maybe <code>null</code> for dis-association.
+ * @param destroyPrevCtx if <code>true</code>, destroy the previous context if exists
+ * @return the previous GLContext, maybe <code>null</code>
+ *
+ * @see GLContext#setGLDrawable(GLDrawable, boolean)
+ * @see GLContext#setGLReadDrawable(GLDrawable)
+ * @see jogamp.opengl.GLDrawableHelper#switchContext(GLDrawable, GLContext, boolean, GLContext, int)
+ */
+ public GLContext setContext(GLContext newCtx, boolean destroyPrevCtx);
+
+ /**
+ * Adds the given {@link GLEventListener listener} to the end of this drawable queue.
+ * The {@link GLEventListener listeners} are notified of events in the order of the queue.
+ * <p>
+ * The newly added listener's {@link GLEventListener#init(GLAutoDrawable) init(..)}
+ * method will be called once before any other of it's callback methods.
+ * See {@link #getGLEventListenerInitState(GLEventListener)} for details.
+ * </p>
+ * @param listener The GLEventListener object to be inserted
+ */
+ public void addGLEventListener(GLEventListener listener);
+
+ /**
+ * Adds the given {@link GLEventListener listener} at the given index of this drawable queue.
+ * The {@link GLEventListener listeners} are notified of events in the order of the queue.
+ * <p>
+ * The newly added listener's {@link GLEventListener#init(GLAutoDrawable) init(..)}
+ * method will be called once before any other of it's callback methods.
+ * See {@link #getGLEventListenerInitState(GLEventListener)} for details.
+ * </p>
+ * @param index Position where the listener will be inserted.
+ * Should be within (0 <= index && index <= size()).
+ * An index value of -1 is interpreted as the end of the list, size().
+ * @param listener The GLEventListener object to be inserted
+ * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1
+ */
+ public void addGLEventListener(int index, GLEventListener listener) throws IndexOutOfBoundsException;
+
+ /**
+ * Returns the number of {@link GLEventListener} of this drawable queue.
+ * @return The number of GLEventListener objects of this drawable queue.
+ */
+ public int getGLEventListenerCount();
+
+ /**
+ * Returns true if all added {@link GLEventListener} are initialized, otherwise false.
+ * @since 2.2
+ */
+ boolean areAllGLEventListenerInitialized();
+
+ /**
+ * Returns the {@link GLEventListener} at the given index of this drawable queue.
+ * @param index Position of the listener to be returned.
+ * Should be within (0 <= index && index < size()).
+ * An index value of -1 is interpreted as last listener, size()-1.
+ * @return The GLEventListener object at the given index.
+ * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index < size()), or -1
+ */
+ public GLEventListener getGLEventListener(int index) throws IndexOutOfBoundsException;
+
+ /**
+ * Retrieves whether the given {@link GLEventListener listener} is initialized or not.
+ * <p>
+ * After {@link #addGLEventListener(GLEventListener) adding} a {@link GLEventListener} it is
+ * marked <i>uninitialized</i> and added to a list of to be initialized {@link GLEventListener}.
+ * If such <i>uninitialized</i> {@link GLEventListener}'s handler methods (reshape, display)
+ * are about to be invoked, it's {@link GLEventListener#init(GLAutoDrawable) init(..)} method is invoked first.
+ * Afterwards the {@link GLEventListener} is marked <i>initialized</i>
+ * and removed from the list of to be initialized {@link GLEventListener}.
+ * </p>
+ * <p>
+ * This methods returns the {@link GLEventListener} initialized state,
+ * i.e. returns <code>false</code> if it is included in the list of to be initialized {@link GLEventListener},
+ * otherwise <code>true</code>.
+ * </p>
+ * @param listener the GLEventListener object to query it's initialized state.
+ */
+ public boolean getGLEventListenerInitState(GLEventListener listener);
+
+ /**
+ * Sets the given {@link GLEventListener listener's} initialized state.
+ * <p>
+ * This methods allows manually setting the {@link GLEventListener} initialized state,
+ * i.e. adding it to, or removing it from the list of to be initialized {@link GLEventListener}.
+ * See {@link #getGLEventListenerInitState(GLEventListener)} for details.
+ * </p>
+ * <p>
+ * <b>Warning:</b> This method does not validate whether the given {@link GLEventListener listener's}
+ * is member of this drawable queue, i.e. {@link #addGLEventListener(GLEventListener) added}.
+ * </p>
+ * <p>
+ * This method is only exposed to allow users full control over the {@link GLEventListener}'s state
+ * and is usually not recommended to change.
+ * </p>
+ * <p>
+ * One use case is moving a {@link GLContext} and their initialized {@link GLEventListener}
+ * from one {@link GLAutoDrawable} to another,
+ * where a subsequent {@link GLEventListener#init(GLAutoDrawable) init(..)} call after adding it
+ * to the new owner is neither required nor desired.
+ * See {@link com.jogamp.opengl.util.GLDrawableUtil#swapGLContextAndAllGLEventListener(GLAutoDrawable, GLAutoDrawable) swapGLContextAndAllGLEventListener(..)}.
+ * </p>
+ * @param listener the GLEventListener object to perform a state change.
+ * @param initialized if <code>true</code>, mark the listener initialized, otherwise uninitialized.
+ */
+ public void setGLEventListenerInitState(GLEventListener listener, boolean initialized);
+
+ /**
+ * Disposes the given {@link GLEventListener listener} via {@link GLEventListener#dispose(GLAutoDrawable) dispose(..)}
+ * if it has been initialized and added to this queue.
+ * <p>
+ * If <code>remove</code> is <code>true</code>, the {@link GLEventListener} is removed from this drawable queue before disposal,
+ * otherwise marked uninitialized.
+ * </p>
+ * <p>
+ * If an {@link GLAnimatorControl} is being attached and the current thread is different
+ * than {@link GLAnimatorControl#getThread() the animator's thread}, it is paused during the operation.
+ * </p>
+ * <p>
+ * Note that this is an expensive operation, since {@link GLEventListener#dispose(GLAutoDrawable) dispose(..)}
+ * is decorated by {@link GLContext#makeCurrent()} and {@link GLContext#release()}.
+ * </p>
+ * <p>
+ * Use {@link #removeGLEventListener(GLEventListener) removeGLEventListener(listener)} instead
+ * if you just want to remove the {@link GLEventListener listener} and <i>don't care</i> about the disposal of the it's (OpenGL) resources.
+ * </p>
+ * <p>
+ * Also note that this is done from within a particular drawable's
+ * {@link GLEventListener} handler (reshape, display, etc.), that it is not
+ * guaranteed that all other listeners will be evaluated properly
+ * during this update cycle.
+ * </p>
+ * @param listener The GLEventListener object to be disposed and removed if <code>remove</code> is <code>true</code>
+ * @param remove pass <code>true</code> to have the <code>listener</code> removed from this drawable queue, otherwise pass <code>false</code>
+ * @return the disposed and/or removed GLEventListener, or null if no action was performed, i.e. listener was not added
+ */
+ public GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove);
+
+ /**
+ * Removes the given {@link GLEventListener listener} from this drawable queue.
+ * <p>
+ * This is an inexpensive operation, since the removed listener's
+ * {@link GLEventListener#dispose(GLAutoDrawable) dispose(..)} method will <i>not</i> be called.
+ * </p>
+ * <p>
+ * Use {@link #disposeGLEventListener(GLEventListener, boolean) disposeGLEventListener(listener, true)}
+ * instead to ensure disposal of the {@link GLEventListener listener}'s (OpenGL) resources.
+ * </p>
+ * <p>
+ * Note that if this is done from within a particular drawable's
+ * {@link GLEventListener} handler (reshape, display, etc.), that it is not
+ * guaranteed that all other listeners will be evaluated properly
+ * during this update cycle.
+ * </p>
+ * @param listener The GLEventListener object to be removed
+ * @return the removed GLEventListener, or null if listener was not added
+ */
+ public GLEventListener removeGLEventListener(GLEventListener listener);
+
+ /**
+ * Registers the usage of an animator, an {@link com.jogamp.opengl.GLAnimatorControl} implementation.
+ * The animator will be queried whether it's animating, ie periodically issuing {@link #display()} calls or not.
+ * <p>
+ * This method shall be called by an animator implementation only,<br>
+ * e.g. {@link com.jogamp.opengl.util.Animator#add(com.jogamp.opengl.GLAutoDrawable)}, passing it's control implementation,<br>
+ * and {@link com.jogamp.opengl.util.Animator#remove(com.jogamp.opengl.GLAutoDrawable)}, passing <code>null</code>.
+ * </p>
+ * <p>
+ * Impacts {@link #display()} and {@link #invoke(boolean, GLRunnable)} semantics.</p><br>
+ *
+ * @param animatorControl <code>null</code> reference indicates no animator is using
+ * this <code>GLAutoDrawable</code>,<br>
+ * a valid reference indicates an animator is using this <code>GLAutoDrawable</code>.
+ *
+ * @throws GLException if an animator is already registered.
+ * @see #display()
+ * @see #invoke(boolean, GLRunnable)
+ * @see com.jogamp.opengl.GLAnimatorControl
+ */
+ public abstract void setAnimator(GLAnimatorControl animatorControl) throws GLException;
+
+ /**
+ * @return the registered {@link com.jogamp.opengl.GLAnimatorControl} implementation, using this <code>GLAutoDrawable</code>.
+ *
+ * @see #setAnimator(com.jogamp.opengl.GLAnimatorControl)
+ * @see com.jogamp.opengl.GLAnimatorControl
+ */
+ public GLAnimatorControl getAnimator();
+
+ /**
+ * Dedicates this instance's {@link GLContext} to the given thread.<br/>
+ * The thread will exclusively claim the {@link GLContext} via {@link #display()} and not release it
+ * until {@link #destroy()} or <code>setExclusiveContextThread(null)</code> has been called.
+ * <p>
+ * Default non-exclusive behavior is <i>requested</i> via <code>setExclusiveContextThread(null)</code>,
+ * which will cause the next call of {@link #display()} on the exclusive thread to
+ * release the {@link GLContext}. Only after it's async release, {@link #getExclusiveContextThread()}
+ * will return <code>null</code>.
+ * </p>
+ * <p>
+ * To release a previous made exclusive thread, a user issues <code>setExclusiveContextThread(null)</code>
+ * and may poll {@link #getExclusiveContextThread()} until it returns <code>null</code>,
+ * <i>while</i> the exclusive thread is still running.
+ * </p>
+ * <p>
+ * Note: Setting a new exclusive thread without properly releasing a previous one
+ * will throw an GLException.
+ * </p>
+ * <p>
+ * Note: Utilizing this feature w/ AWT could lead to an AWT-EDT deadlock, depending on the AWT implementation.
+ * Hence it is advised not to use it with native AWT GLAutoDrawable like GLCanvas.
+ * </p>
+ * <p>
+ * One scenario could be to dedicate the context to the {@link GLAnimatorControl#getThread() animator thread}
+ * and spare redundant context switches, see {@link com.jogamp.opengl.util.AnimatorBase#setExclusiveContext(boolean)}.
+ * </p>
+ * @param t the exclusive thread to claim the context, or <code>null</code> for default operation.
+ * @return previous exclusive context thread
+ * @throws GLException If an exclusive thread is still active but a new one is attempted to be set
+ * @see com.jogamp.opengl.util.AnimatorBase#setExclusiveContext(boolean)
+ */
+ public Thread setExclusiveContextThread(Thread t) throws GLException;
+
+ /**
+ * @see #setExclusiveContextThread(Thread)
+ */
+ public Thread getExclusiveContextThread();
+
+ /**
+ * Enqueues a one-shot {@link GLRunnable},
+ * which will be executed within the next {@link #display()} call
+ * after all registered {@link GLEventListener}s
+ * {@link GLEventListener#display(GLAutoDrawable) display(GLAutoDrawable)}
+ * methods have been called.
+ * <p>
+ * If no {@link GLAnimatorControl} is animating (default),<br>
+ * or if the current thread is the animator thread,<br>
+ * a {@link #display()} call is issued after enqueue the <code>GLRunnable</code>,
+ * hence the {@link GLRunnable} will be executed right away.<br/>
+ * </p>
+ * <p>
+ * If an {@link GLAnimatorControl animator} is running,<br>
+ * no explicit {@link #display()} call is issued, allowing the {@link GLAnimatorControl animator} to perform at due time.<br>
+ * </p>
+ * <p>
+ * If <code>wait</code> is <code>true</code> the call blocks until the <code>glRunnable</code>
+ * has been executed by the {@link GLAnimatorControl animator}, otherwise the method returns immediately.
+ * </p>
+ * <p>
+ * If <code>wait</code> is <code>true</code> <b>and</b>
+ * {@link #isRealized()} returns <code>false</code> <i>or</i> {@link #getContext()} returns <code>null</code>,
+ * the call is ignored and returns <code>false</code>.<br>
+ * This helps avoiding deadlocking the caller.
+ * </p>
+ * <p>
+ * The internal queue of {@link GLRunnable}'s is being flushed with {@link #destroy()}
+ * where all blocked callers are being notified.
+ * </p>
+ * <p>
+ * To avoid a deadlock situation which causes an {@link IllegalStateException} one should
+ * avoid issuing {@link #invoke(boolean, GLRunnable) invoke} while this <a href="#locking">GLAutoDrawable is being locked</a>.<br>
+ * Detected deadlock situations throwing an {@link IllegalStateException} are:
+ * <ul>
+ * <li>{@link #getAnimator() Animator} is running on another thread and waiting and is locked on current thread, but is not {@link #isThreadGLCapable() GL-Thread}</li>
+ * <li>No {@link #getAnimator() Animator} is running on another thread and is locked on current thread, but is not {@link #isThreadGLCapable() GL-Thread}</li>
+ * </ul>
+ * </p>
+ *
+ * @param wait if <code>true</code> block until execution of <code>glRunnable</code> is finished, otherwise return immediately w/o waiting
+ * @param glRunnable the {@link GLRunnable} to execute within {@link #display()}
+ * @return <code>true</code> if the {@link GLRunnable} has been processed or queued, otherwise <code>false</code>.
+ * @throws IllegalStateException in case of a detected deadlock situation ahead, see above.
+ *
+ * @see #setAnimator(GLAnimatorControl)
+ * @see #display()
+ * @see GLRunnable
+ * @see #invoke(boolean, List)
+ * @see #flushGLRunnables()
+ */
+ public boolean invoke(boolean wait, GLRunnable glRunnable) throws IllegalStateException ;
+
+ /**
+ * Extends {@link #invoke(boolean, GLRunnable)} functionality
+ * allowing to inject a list of {@link GLRunnable}s.
+ * @param wait if <code>true</code> block until execution of the last <code>glRunnable</code> is finished, otherwise return immediately w/o waiting
+ * @param glRunnables the {@link GLRunnable}s to execute within {@link #display()}
+ * @return <code>true</code> if the {@link GLRunnable}s has been processed or queued, otherwise <code>false</code>.
+ * @throws IllegalStateException in case of a detected deadlock situation ahead, see {@link #invoke(boolean, GLRunnable)}.
+ * @see #invoke(boolean, GLRunnable)
+ * @see #flushGLRunnables()
+ */
+ public boolean invoke(boolean wait, List<GLRunnable> glRunnables) throws IllegalStateException;
+
+ /**
+ * Flushes all {@link #invoke(boolean, GLRunnable) enqueued} {@link GLRunnable} of this {@link GLAutoDrawable}
+ * including notifying waiting executor.
+ * <p>
+ * The executor which might have been blocked until notified
+ * will be unblocked and all tasks removed from the queue.
+ * </p>
+ * @see #invoke(boolean, GLRunnable)
+ * @since 2.2
+ */
+ public void flushGLRunnables();
+
+ /** Destroys all resources associated with this GLAutoDrawable,
+ inclusive the GLContext.
+ If a window is attached to it's implementation, it shall be closed.
+ Causes disposing of all OpenGL resources
+ by calling {@link GLEventListener#dispose dispose(..)} for all
+ registered {@link GLEventListener}s. Called automatically by the
+ window system toolkit upon receiving a destroy notification. This
+ routine may be called manually. */
+ public void destroy();
+
+ /**
+ * <p>
+ * Causes OpenGL rendering to be performed for this GLAutoDrawable
+ * in the following order:
+ * <ul>
+ * <li> Calling {@link GLEventListener#display display(..)} for all
+ * registered {@link GLEventListener}s. </li>
+ * <li> Executes all one-shot {@link com.jogamp.opengl.GLRunnable GLRunnable},
+ * enqueued via {@link #invoke(boolean, GLRunnable)}.</li>
+ * </ul></p>
+ * <p>
+ * May be called periodically by a running {@link com.jogamp.opengl.GLAnimatorControl} implementation,<br>
+ * which must register itself with {@link #setAnimator(com.jogamp.opengl.GLAnimatorControl)}.</p>
+ * <p>
+ * Called automatically by the window system toolkit upon receiving a repaint() request, <br>
+ * except an {@link com.jogamp.opengl.GLAnimatorControl} implementation {@link com.jogamp.opengl.GLAnimatorControl#isAnimating()}.</p>
+ * <p>
+ * This routine may also be called manually for better control over the
+ * rendering process. It is legal to call another GLAutoDrawable's
+ * display method from within the {@link GLEventListener#display
+ * display(..)} callback.</p>
+ * <p>
+ * In case of a new generated OpenGL context,
+ * the implementation shall call {@link GLEventListener#init init(..)} for all
+ * registered {@link GLEventListener}s <i>before</i> making the
+ * actual {@link GLEventListener#display display(..)} calls,
+ * in case this has not been done yet.</p>
+ *
+ * @see #setAnimator(com.jogamp.opengl.GLAnimatorControl)
+ */
+ public void display();
+
+ /** Enables or disables automatic buffer swapping for this drawable.
+ By default this property is set to true; when true, after all
+ GLEventListeners have been called for a display() event, the
+ front and back buffers are swapped, displaying the results of
+ the render. When disabled, the user is responsible for calling
+ {@link #swapBuffers(..)} manually. */
+ public void setAutoSwapBufferMode(boolean enable);
+
+ /** Indicates whether automatic buffer swapping is enabled for this
+ drawable. See {@link #setAutoSwapBufferMode}. */
+ public boolean getAutoSwapBufferMode();
+
+ /**
+ * @param flags Additional context creation flags.
+ *
+ * @see GLContext#setContextCreationFlags(int)
+ * @see GLContext#enableGLDebugMessage(boolean)
+ */
+ public void setContextCreationFlags(int flags);
+
+ /**
+ * @return Additional context creation flags
+ */
+ public int getContextCreationFlags();
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * This GLAutoDrawable implementation holds it's own GLContext reference,
+ * thus created a GLContext using this methods won't replace it implicitly.
+ * To replace or set this GLAutoDrawable's GLContext you need to call {@link #setContext(GLContext, boolean)}.
+ * </p>
+ * <p>
+ * The GLAutoDrawable implementation shall also set the
+ * context creation flags as customized w/ {@link #setContextCreationFlags(int)}.
+ * </p>
+ */
+ @Override
+ public GLContext createContext(GLContext shareWith);
+
+ /** Returns the {@link GL} pipeline object this GLAutoDrawable uses.
+ If this method is called outside of the {@link
+ GLEventListener}'s callback methods (init, display, etc.) it may
+ return null. Users should not rely on the identity of the
+ returned GL object; for example, users should not maintain a
+ hash table with the GL object as the key. Additionally, the GL
+ object should not be cached in client code, but should be
+ re-fetched from the GLAutoDrawable at the beginning of each call
+ to init, display, etc. */
+ public GL getGL();
+
+ /** Sets the {@link GL} pipeline object this GLAutoDrawable uses.
+ This should only be called from within the GLEventListener's
+ callback methods, and usually only from within the init()
+ method, in order to install a composable pipeline. See the JOGL
+ demos for examples.
+ @return the set GL pipeline or null if not successful */
+ public GL setGL(GL gl);
+
+ /**
+ * Method <i>may</i> return the upstream UI toolkit object
+ * holding this {@link GLAutoDrawable} instance, if exist.
+ * <p>
+ * Currently known Java UI toolkits and it's known return types are:
+ *
+ * <table border="1">
+ * <tr><td>Toolkit</td> <td>GLAutoDrawable Implementation</td> <td>~</td> <td>Return Type of getUpstreamWidget()</td</tr>
+ * <tr><td>NEWT</td> <td>{@link com.jogamp.newt.opengl.GLWindow}</td> <td>has a</td> <td>{@link com.jogamp.newt.Window}</td</tr>
+ * <tr><td>SWT</td> <td>{@link com.jogamp.opengl.swt.GLCanvas}</td> <td>is a</td> <td>{@link org.eclipse.swt.widgets.Canvas}</td</tr>
+ * <tr><td>AWT</td> <td>{@link com.jogamp.opengl.awt.GLCanvas}</td> <td>is a</td> <td>{@link java.awt.Canvas}</td</tr>
+ * <tr><td>AWT</td> <td>{@link com.jogamp.opengl.awt.GLJPanel}</td> <td>is a</td> <td>{@link javax.swing.JPanel}</td</tr>
+ * </table>
+ * However, the result may be other object types than the listed above
+ * due to new supported toolkits.
+ * </p>
+ * <p>
+ * This method may also return <code>null</code> if no UI toolkit is being used,
+ * as common for offscreen rendering.
+ * </p>
+ */
+ public Object getUpstreamWidget();
+
+ /**
+ * Returns the recursive lock object of the {@link #getUpstreamWidget() upstream widget}
+ * to synchronize multithreaded access on top of {@link NativeSurface#lockSurface()}.
+ * <p>
+ * See <a href="#locking">GLAutoDrawable Locking</a>.
+ * </p>
+ * @since 2.2
+ */
+ public RecursiveLock getUpstreamLock();
+
+ /**
+ * Indicates whether the current thread is capable of
+ * performing OpenGL-related work.
+ * <p>
+ * Implementation utilizes this knowledge to determine
+ * whether {@link #display()} performs the OpenGL commands on the current thread directly
+ * or spawns them on the dedicated OpenGL thread.
+ * </p>
+ * @since 2.2
+ */
+ public boolean isThreadGLCapable();
+
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLBase.java b/src/jogl/classes/com/jogamp/opengl/GLBase.java
new file mode 100644
index 000000000..19b7808fc
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLBase.java
@@ -0,0 +1,646 @@
+/**
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl;
+
+/**
+ * <P>The base interface from which all GL profiles derive, providing
+ * checked conversion down to concrete profiles, access to the
+ * OpenGL context associated with the GL and extension/function
+ * availability queries as described below.</P>
+ *
+ * <P> While the APIs for vendor extensions are unconditionally
+ * exposed, the underlying functions may not be present. The method
+ * {@link #isFunctionAvailable} should be used to query the
+ * availability of any non-core function before it is used for the
+ * first time; for example,
+ * <code>gl.isFunctionAvailable("glProgramStringARB")</code>. On
+ * certain platforms (Windows in particular), the most "core"
+ * functionality is only OpenGL 1.1, so in theory any routines first
+ * exposed in OpenGL 1.2, 1.3, and 1.4, 1.5, or 2.0 as well as vendor
+ * extensions should all be queried. Calling an unavailable function
+ * will cause a {@link GLException} to be raised. </P>
+ *
+ * {@link #isExtensionAvailable} may also be used to determine whether
+ * a specific extension is available before calling the routines or
+ * using the functionality it exposes: for example,
+ * <code>gl.isExtensionAvailable("GL_ARB_vertex_program");</code>.
+ * However, in this case it is up to the end user to know which
+ * routines or functionality are associated with which OpenGL
+ * extensions. It may also be used to test for the availability of a
+ * particular version of OpenGL: for example,
+ * <code>gl.isExtensionAvailable("GL_VERSION_1_5");</code>.
+ *
+ * <P> Exceptions to the window system extension naming rules:
+ *
+ * <UL>
+ *
+ * <LI> The memory allocators for the NVidia vertex_array_range (VAR)
+ * extension, in particular <code>wglAllocateMemoryNV</code> /
+ * <code>glXAllocateMemoryNV</code> and associated routines. {@link
+ * #glAllocateMemoryNV} has been provided for window system-independent
+ * access to VAR. {@link #isFunctionAvailable} will translate an argument
+ * of "glAllocateMemoryNV" or "glFreeMemoryNV" into the appropriate
+ * window system-specific name. </P>
+ *
+ * <LI> WGL_ARB_pbuffer, WGL_ARB_pixel_format, and other
+ * platform-specific pbuffer functionality; the availability of
+ * pbuffers can be queried on Windows, X11 and Mac OS X platforms by
+ * querying {@link #isExtensionAvailable} with an argument of
+ * "GL_ARB_pbuffer" or "GL_ARB_pixel_format".
+ *
+ * </UL> <P>
+ *
+ */
+public interface GLBase {
+
+ /**
+ * Indicates whether this GL object conforms to any of the OpenGL profiles.
+ */
+ public boolean isGL();
+
+ /**
+ * Indicates whether this GL object conforms to the OpenGL &ge; 4.0 compatibility profile.
+ * The GL4 compatibility profile includes the GL2, GL2ES1, GL2ES2, GL3, GL3bc and GL4 profile.
+ * @see GLContext#isGL4bc()
+ */
+ public boolean isGL4bc();
+
+ /**
+ * Indicates whether this GL object conforms to the OpenGL &ge; 4.0 core profile.
+ * The GL4 core profile includes the GL2ES2, and GL3 profile.
+ * @see GLContext#isGL4()
+ */
+ public boolean isGL4();
+
+ /**
+ * Indicates whether this GL object conforms to the OpenGL &ge; 3.1 compatibility profile.
+ * The GL3 compatibility profile includes the GL2, GL2ES1, GL2ES2 and GL3 profile.
+ * @see GLContext#isGL3bc()
+ */
+ public boolean isGL3bc();
+
+ /**
+ * Indicates whether this GL object conforms to the OpenGL &ge; 3.1 core profile.
+ * The GL3 core profile includes the GL2ES2 profile.
+ * @see GLContext#isGL3()
+ */
+ public boolean isGL3();
+
+ /**
+ * Indicates whether this GL object conforms to the OpenGL &le; 3.0 profile.
+ * The GL2 profile includes the GL2ES1 and GL2ES2 profile.
+ * @see GLContext#isGL2()
+ */
+ public boolean isGL2();
+
+ /**
+ * Indicates whether this GL object conforms to the OpenGL ES &ge; 1.0 profile.
+ * @see GLContext#isGLES1()
+ */
+ public boolean isGLES1();
+
+ /**
+ * Indicates whether this GL object conforms to the OpenGL ES &ge; 2.0 profile.
+ * <p>
+ * Remark: ES2 compatible desktop profiles are not included.
+ * To query whether core ES2 functionality is provided, use {@link #isGLES2Compatible()}.
+ * </p>
+ * @see #isGLES2Compatible()
+ * @see GLContext#isGLES2()
+ */
+ public boolean isGLES2();
+
+ /**
+ * Indicates whether this GL object conforms to the OpenGL ES &ge; 3.0 profile.
+ * <p>
+ * Remark: ES3 compatible desktop profiles are not included.
+ * To query whether core ES3 functionality is provided, use {@link #isGLES3Compatible()}.
+ * </p>
+ * @see #isGLES3Compatible()
+ * @see GLContext#isGLES3()
+ */
+ public boolean isGLES3();
+
+ /**
+ * Indicates whether this GL object conforms to one of the OpenGL ES profiles,
+ * see {@link #isGLES1()}, {@link #isGLES2()} and {@link #isGLES3()}.
+ * @see GLContext#isGLES()
+ */
+ public boolean isGLES();
+
+ /**
+ * Indicates whether this GL object conforms to a GL2ES1 compatible profile.
+ * @see GLContext#isGL2ES1()
+ */
+ public boolean isGL2ES1();
+
+ /**
+ * Indicates whether this GL object conforms to a GL2ES2 compatible profile.
+ * @see GLContext#isGL2ES2()
+ */
+ public boolean isGL2ES2();
+
+ /**
+ * Indicates whether this GL object conforms to a either a GL2GL3 or GL3ES3 compatible profile.
+ * @see GLContext#isGL2ES3()
+ */
+ public boolean isGL2ES3();
+
+ /**
+ * Indicates whether this GL object conforms to a GL3ES3 compatible profile.
+ * @see GLContext#isGL3ES3()
+ */
+ public boolean isGL3ES3();
+
+ /**
+ * Returns true if this GL object conforms to a GL4ES3 compatible profile, i.e. if {@link #isGLES3Compatible()} returns true.
+ * <p>Includes [ GL &ge; 4.3, GL &ge; 3.1 w/ GL_ARB_ES3_compatibility and GLES3 ]</p>
+ * @see GLContext#isGL4ES3()
+ */
+ public boolean isGL4ES3();
+
+ /**
+ * Indicates whether this GL object conforms to a GL2GL3 compatible profile.
+ * @see GLContext#isGL2GL3()
+ */
+ public boolean isGL2GL3();
+
+ /**
+ * Indicates whether this GL object uses a GL4 core profile. <p>Includes [ GL4 ].</p>
+ * @see GLContext#isGL4core()
+ */
+ public boolean isGL4core();
+
+ /**
+ * Indicates whether this GL object uses a GL3 core profile. <p>Includes [ GL4, GL3 ].</p>
+ * @see GLContext#isGL3core()
+ */
+ public boolean isGL3core();
+
+ /**
+ * Indicates whether this GL object uses a GL core profile. <p>Includes [ GL4, GL3, GLES3, GL2ES2 ].</p>
+ * @see GLContext#isGLcore()
+ */
+ public boolean isGLcore();
+
+ /**
+ * Indicates whether this GL object is compatible with the core OpenGL ES2 functionality.
+ * @return true if this context is an ES2 context or implements
+ * the extension <code>GL_ARB_ES2_compatibility</code>, otherwise false
+ * @see GLContext#isGLES2Compatible()
+ */
+ public boolean isGLES2Compatible();
+
+ /**
+ * Indicates whether this GL object is compatible with the core OpenGL ES3 functionality.
+ * <p>
+ * Return true if the underlying context is an ES3 context or implements
+ * the extension <code>GL_ARB_ES3_compatibility</code>, otherwise false.
+ * </p>
+ * <p>
+ * Includes [ GL &ge; 4.3, GL &ge; 3.1 w/ GL_ARB_ES3_compatibility and GLES3 ]
+ * </p>
+ * @see GLContext#isGLES3Compatible()
+ */
+ public boolean isGLES3Compatible();
+
+ /**
+ * Indicates whether this GL object supports GLSL.
+ * @see GLContext#hasGLSL()
+ */
+ public boolean hasGLSL();
+
+ /**
+ * Returns the downstream GL instance in case this is a wrapping pipeline, otherwise <code>null</code>.
+ * <p>
+ * See {@link #getRootGL()} for retrieving the implementing root instance.
+ * </p>
+ * @throws GLException if the downstream instance is not null and not a GL implementation
+ * @see #getRootGL()
+ */
+ public GL getDownstreamGL() throws GLException;
+
+ /**
+ * Returns the implementing root instance, considering a wrapped pipelined hierarchy, see {@link #getDownstreamGL()}.
+ * <p>
+ * If this instance is not a wrapping pipeline, i.e. has no downstream instance,
+ * this instance is returned.
+ * </p>
+ * @throws GLException if the root instance is not a GL implementation
+ */
+ public GL getRootGL() throws GLException;
+
+ /**
+ * Casts this object to the GL interface.
+ * @throws GLException if this object is not a GL implementation
+ */
+ public GL getGL() throws GLException;
+
+ /**
+ * Casts this object to the GL4bc interface.
+ * @throws GLException if this object is not a GL4bc implementation
+ */
+ public GL4bc getGL4bc() throws GLException;
+
+ /**
+ * Casts this object to the GL4 interface.
+ * @throws GLException if this object is not a GL4 implementation
+ */
+ public GL4 getGL4() throws GLException;
+
+ /**
+ * Casts this object to the GL3bc interface.
+ * @throws GLException if this object is not a GL3bc implementation
+ */
+ public GL3bc getGL3bc() throws GLException;
+
+ /**
+ * Casts this object to the GL3 interface.
+ * @throws GLException if this object is not a GL3 implementation
+ */
+ public GL3 getGL3() throws GLException;
+
+ /**
+ * Casts this object to the GL2 interface.
+ * @throws GLException if this object is not a GL2 implementation
+ */
+ public GL2 getGL2() throws GLException;
+
+ /**
+ * Casts this object to the GLES1 interface.
+ * @throws GLException if this object is not a GLES1 implementation
+ */
+ public GLES1 getGLES1() throws GLException;
+
+ /**
+ * Casts this object to the GLES2 interface.
+ * @throws GLException if this object is not a GLES2 implementation
+ */
+ public GLES2 getGLES2() throws GLException;
+
+ /**
+ * Casts this object to the GLES3 interface.
+ * @throws GLException if this object is not a GLES3 implementation
+ */
+ public GLES3 getGLES3() throws GLException;
+
+ /**
+ * Casts this object to the GL2ES1 interface.
+ * @throws GLException if this object is not a GL2ES1 implementation
+ */
+ public GL2ES1 getGL2ES1() throws GLException;
+
+ /**
+ * Casts this object to the GL2ES2 interface.
+ * @throws GLException if this object is not a GL2ES2 implementation
+ */
+ public GL2ES2 getGL2ES2() throws GLException;
+
+ /**
+ * Casts this object to the GL2ES3 interface.
+ * @throws GLException if this object is not a GL2ES3 implementation
+ */
+ public GL2ES3 getGL2ES3() throws GLException;
+
+ /**
+ * Casts this object to the GL3ES3 interface.
+ * @throws GLException if this object is not a GL3ES3 implementation
+ */
+ public GL3ES3 getGL3ES3() throws GLException;
+
+ /**
+ * Casts this object to the GL4ES3 interface.
+ * @throws GLException if this object is not a GL4ES3 implementation
+ */
+ public GL4ES3 getGL4ES3() throws GLException;
+
+ /**
+ * Casts this object to the GL2GL3 interface.
+ * @throws GLException if this object is not a GL2GL3 implementation
+ */
+ public GL2GL3 getGL2GL3() throws GLException;
+
+ /**
+ * Returns the GLProfile associated with this GL object.
+ */
+ public GLProfile getGLProfile();
+
+ /**
+ * Returns the GLContext associated which this GL object.
+ */
+ public GLContext getContext();
+
+ /**
+ * Returns true if the specified OpenGL core- or extension-function can be
+ * used successfully through this GL instance given the current host (OpenGL
+ * <i>client</i>) and display (OpenGL <i>server</i>) configuration.<P>
+ * By "successfully" we mean that the function is both <i>callable</i>
+ * on the machine running the program and <i>available</i> on the current
+ * display.<P>
+ *
+ * In order to call a function successfully, the function must be both
+ * <i>callable</i> on the machine running the program and <i>available</i> on
+ * the display device that is rendering the output (note: on non-networked,
+ * single-display machines these two conditions are identical; on networked and/or
+ * multi-display machines this becomes more complicated). These conditions are
+ * met if the function is either part of the core OpenGL version supported by
+ * both the host and display, or it is an OpenGL extension function that both
+ * the host and display support. <P>
+ *
+ * A GL function is <i>callable</i> if it is successfully linked at runtime,
+ * hence the GLContext must be made current at least once.
+ *
+ * @param glFunctionName the name of the OpenGL function (e.g., use
+ * "glBindRenderbufferEXT" or "glBindRenderbuffer" to check if {@link
+ * GL#glBindRenderbuffer(int,int)} is available).
+ */
+ public boolean isFunctionAvailable(String glFunctionName);
+
+ /**
+ * Returns true if the specified OpenGL extension can be
+ * used successfully through this GL instance given the current host (OpenGL
+ * <i>client</i>) and display (OpenGL <i>server</i>) configuration.<P>
+ *
+ * @param glExtensionName the name of the OpenGL extension (e.g.,
+ * "GL_ARB_vertex_program").
+ */
+ public boolean isExtensionAvailable(String glExtensionName);
+
+ /**
+ * Returns <code>true</code> if basic FBO support is available, otherwise <code>false</code>.
+ * <p>
+ * Basic FBO is supported if the context is either GL-ES >= 2.0, GL >= 3.0 [core, compat] or implements the extensions
+ * <code>GL_ARB_ES2_compatibility</code>, <code>GL_ARB_framebuffer_object</code>, <code>GL_EXT_framebuffer_object</code> or <code>GL_OES_framebuffer_object</code>.
+ * </p>
+ * <p>
+ * Basic FBO support may only include one color attachment and no multisampling,
+ * as well as limited internal formats for renderbuffer.
+ * </p>
+ * @see GLContext#hasBasicFBOSupport()
+ */
+ public boolean hasBasicFBOSupport();
+
+ /**
+ * Returns <code>true</code> if full FBO support is available, otherwise <code>false</code>.
+ * <p>
+ * Full FBO is supported if the context is either GL >= core 3.0 [ES, core, compat] or implements the extensions
+ * <code>ARB_framebuffer_object</code>, or all of
+ * <code>EXT_framebuffer_object</code>, <code>EXT_framebuffer_multisample</code>,
+ * <code>EXT_framebuffer_blit</code>, <code>GL_EXT_packed_depth_stencil</code>.
+ * </p>
+ * <p>
+ * Full FBO support includes multiple color attachments and multisampling.
+ * </p>
+ * @see GLContext#hasFullFBOSupport()
+ */
+ public boolean hasFullFBOSupport();
+
+ /**
+ * Returns the maximum number of FBO RENDERBUFFER samples
+ * if {@link #hasFullFBOSupport() full FBO is supported}, otherwise false.
+ * @see GLContext#getMaxRenderbufferSamples()
+ */
+ public int getMaxRenderbufferSamples();
+
+ /**
+ * Returns true if the GL context supports non power of two (NPOT) textures,
+ * otherwise false.
+ * <p>
+ * NPOT textures are supported in OpenGL >= 3, GLES2 or if the
+ * 'GL_ARB_texture_non_power_of_two' extension is available.
+ * </p>
+ */
+ public boolean isNPOTTextureAvailable();
+
+ public boolean isTextureFormatBGRA8888Available();
+
+ /** Provides a platform-independent way to specify the minimum swap
+ interval for buffer swaps. An argument of 0 disables
+ sync-to-vertical-refresh completely, while an argument of 1
+ causes the application to wait until the next vertical refresh
+ until swapping buffers. The default, which is platform-specific,
+ is usually either 0 or 1. This function is not guaranteed to
+ have an effect, and in particular only affects heavyweight
+ onscreen components.
+
+ @see #getSwapInterval
+ @throws GLException if this context is not the current
+ */
+ public void setSwapInterval(int interval);
+
+ /** Provides a platform-independent way to get the swap
+ interval set by {@link #setSwapInterval}. <br>
+
+ If the interval is not set by {@link #setSwapInterval} yet,
+ -1 is returned, indicating that the platforms default
+ is being used.
+
+ @see #setSwapInterval
+ */
+ public int getSwapInterval();
+
+ /**
+ * Returns an object through which platform-specific OpenGL extensions
+ * (EGL, GLX, WGL, etc.) may be accessed. The data type of the returned
+ * object and its associated capabilities are undefined. Most
+ * applications will never need to call this method. It is highly
+ * recommended that any applications which do call this method perform
+ * all accesses on the returned object reflectively to guard
+ * themselves against changes to the implementation.
+ */
+ public Object getPlatformGLExtensions();
+
+ /**
+ * Returns an object providing access to the specified OpenGL
+ * extension. This is intended to provide a mechanism for vendors who
+ * wish to provide access to new OpenGL extensions without changing
+ * the public API of the core package. For example, a user may request
+ * access to extension "GL_VENDOR_foo" and receive back an object
+ * which implements a vendor-specified interface which can call the
+ * OpenGL extension functions corresponding to that extension. It is
+ * up to the vendor to specify both the extension name and Java API
+ * for accessing it, including which class or interface contains the
+ * functions.
+ *
+ * <P>
+ *
+ * Note: it is the intent to add new extensions as quickly as possible
+ * to the core GL API. Therefore it is unlikely that most vendors will
+ * use this extension mechanism, but it is being provided for
+ * completeness.
+ */
+ public Object getExtension(String extensionName);
+
+ /** Aliased entrypoint of <code> void {@native glClearDepth}(GLclampd depth); </code> and <code> void {@native glClearDepthf}(GLclampf depth); </code>. */
+ public void glClearDepth( double depth );
+
+ /** Aliased entrypoint of <code> void {@native glDepthRange}(GLclampd depth); </code> and <code> void {@native glDepthRangef}(GLclampf depth); </code>. */
+ public void glDepthRange(double zNear, double zFar);
+
+ /**
+ * @param target a GL buffer (VBO) target as used in {@link GL#glBindBuffer(int, int)}, ie {@link GL#GL_ELEMENT_ARRAY_BUFFER}, {@link GL#GL_ARRAY_BUFFER}, ..
+ * @return the GL buffer name bound to a target via {@link GL#glBindBuffer(int, int)} or 0 if unbound.
+ * @see #getBufferStorage(int)
+ */
+ public int getBoundBuffer(int target);
+
+ /**
+ * @param bufferName a GL buffer name, generated with e.g. {@link GL#glGenBuffers(int, int[], int)} and used in {@link GL#glBindBuffer(int, int)}, {@link GL#glBufferData(int, long, java.nio.Buffer, int)} or {@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)}.
+ * @return the size of the given GL buffer storage, see {@link GLBufferStorage}
+ * @see #getBoundBuffer(int)
+ */
+ public GLBufferStorage getBufferStorage(int bufferName);
+
+ /**
+ * Returns the {@link GLBufferStorage} instance as mapped via OpenGL's native {@link GL#glMapBuffer(int, int) glMapBuffer(..)} implementation.
+ * <p>
+ * Throws a {@link GLException} if GL-function constraints are not met.
+ * </p>
+ * <p>
+ * {@link GL#glMapBuffer(int, int)} wrapper calls this method and returns {@link GLBufferStorage#getMappedBuffer()}.
+ * </p>
+ * <p>
+ * A zero {@link GLBufferStorage#getSize()} will avoid a native call and returns the unmapped {@link GLBufferStorage}.
+ * </p>
+ * <p>
+ * A null native mapping result indicating an error will
+ * not cause a GLException but returns the unmapped {@link GLBufferStorage}.
+ * This allows the user to handle this case.
+ * </p>
+ * @param target denotes the buffer via it's bound target
+ * @param access the mapping access mode
+ * @throws GLException if buffer is not bound to target
+ * @throws GLException if buffer is not tracked
+ * @throws GLException if buffer is already mapped
+ * @throws GLException if buffer has invalid store size, i.e. less-than zero
+ */
+ public GLBufferStorage mapBuffer(int target, int access) throws GLException;
+
+ /**
+ * Returns the {@link GLBufferStorage} instance as mapped via OpenGL's native {@link GL#glMapBufferRange(int, long, long, int) glMapBufferRange(..)} implementation.
+ * <p>
+ * Throws a {@link GLException} if GL-function constraints are not met.
+ * </p>
+ * <p>
+ * {@link GL#glMapBufferRange(int, long, long, int)} wrapper calls this method and returns {@link GLBufferStorage#getMappedBuffer()}.
+ * </p>
+ * <p>
+ * A zero {@link GLBufferStorage#getSize()} will avoid a native call and returns the unmapped {@link GLBufferStorage}.
+ * </p>
+ * <p>
+ * A null native mapping result indicating an error will
+ * not cause a GLException but returns the unmapped {@link GLBufferStorage}.
+ * This allows the user to handle this case.
+ * </p>
+ * @param target denotes the buffer via it's bound target
+ * @param offset offset of the mapped buffer's storage
+ * @param length length of the mapped buffer's storage
+ * @param access the mapping access mode
+ * @throws GLException if buffer is not bound to target
+ * @throws GLException if buffer is not tracked
+ * @throws GLException if buffer is already mapped
+ * @throws GLException if buffer has invalid store size, i.e. less-than zero
+ * @throws GLException if buffer mapping range does not fit, incl. offset
+ */
+ public GLBufferStorage mapBufferRange(final int target, final long offset, final long length, final int access) throws GLException;
+
+ /**
+ * @return true if a VBO is bound to {@link GL#GL_ARRAY_BUFFER} via {@link GL#glBindBuffer(int, int)}, otherwise false
+ */
+ public boolean isVBOArrayBound();
+
+ /**
+ * @return true if a VBO is bound to {@link GL#GL_ELEMENT_ARRAY_BUFFER} via {@link GL#glBindBuffer(int, int)}, otherwise false
+ */
+ public boolean isVBOElementArrayBound();
+
+ /**
+ * Return the framebuffer name bound to this context,
+ * see {@link GL#glBindFramebuffer(int, int)}.
+ * <p>
+ * Calls {@link GLContext#getBoundFramebuffer(int)}.
+ * </p>
+ */
+ public int getBoundFramebuffer(int target);
+
+ /**
+ * Return the default draw framebuffer name.
+ * <p>
+ * May differ from it's default <code>zero</code>
+ * in case an framebuffer object ({@link com.jogamp.opengl.FBObject}) based drawable
+ * is being used.
+ * </p>
+ * <p>
+ * Calls {@link GLContext#getDefaultDrawFramebuffer()}.
+ * </p>
+ */
+ public int getDefaultDrawFramebuffer();
+
+ /**
+ * Return the default read framebuffer name.
+ * <p>
+ * May differ from it's default <code>zero</code>
+ * in case an framebuffer object ({@link com.jogamp.opengl.FBObject}) based drawable
+ * is being used.
+ * </p>
+ * <p>
+ * Calls {@link GLContext#getDefaultReadFramebuffer()}.
+ * </p>
+ */
+ public int getDefaultReadFramebuffer();
+
+ /**
+ * Returns the default color buffer within the current bound
+ * {@link #getDefaultReadFramebuffer()}, i.e. GL_READ_FRAMEBUFFER,
+ * which will be used as the source for pixel reading commands,
+ * like {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer) glReadPixels} etc.
+ * <p>
+ * For offscreen framebuffer objects this is {@link GL#GL_COLOR_ATTACHMENT0},
+ * otherwise this is {@link GL#GL_FRONT} for single buffer configurations
+ * and {@link GL#GL_BACK} for double buffer configurations.
+ * </p>
+ * <p>
+ * Note-1: Neither ES1 nor ES2 supports selecting the read buffer via glReadBuffer
+ * and {@link GL#GL_BACK} is the default.
+ * </p>
+ * <p>
+ * Note-2: ES3 only supports {@link GL#GL_BACK}, {@link GL#GL_NONE} or {@link GL#GL_COLOR_ATTACHMENT0}+i
+ * </p>
+ * <p>
+ * Note-3: See {@link com.jogamp.opengl.util.GLDrawableUtil#swapBuffersBeforeRead(GLCapabilitiesImmutable) swapBuffersBeforeRead}
+ * for read-pixels and swap-buffers implications.
+ * </p>
+ * <p>
+ * Calls {@link GLContext#getDefaultReadBuffer()}.
+ * </p>
+ */
+ public int getDefaultReadBuffer();
+}
+
diff --git a/src/jogl/classes/com/jogamp/opengl/GLBufferStorage.java b/src/jogl/classes/com/jogamp/opengl/GLBufferStorage.java
new file mode 100644
index 000000000..5db97d42f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLBufferStorage.java
@@ -0,0 +1,160 @@
+/**
+ * Copyright 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl;
+
+import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+
+/**
+ * OpenGL buffer storage object reflecting it's
+ * <ul>
+ * <li>storage size</li>
+ * <li>storage memory if mapped</li>
+ * <li>mutable usage or immutable flags</li>
+ * </ul>
+ * <p>
+ * Buffer storage is created via:
+ * <ul>
+ * <li><code>glBufferStorage</code> - storage creation with target</li>
+ * <li>{@link GL#glBufferData(int, long, java.nio.Buffer, int)} - storage recreation with target</li>
+ * <li>{@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)} - storage recreation, direct</li>
+ * </ul>
+ * Note that storage <i>recreation</i> as mentioned above also invalidate a previous storage instance,
+ * i.e. disposed the buffer's current storage if exist and attaches a new storage instance.
+ * </p>
+ * <p>
+ * Buffer storage is disposed via:
+ * <ul>
+ * <li>{@link GL#glDeleteBuffers(int, IntBuffer)} - explicit, direct, via {@link #notifyBuffersDeleted(int, IntBuffer)} or {@link #notifyBuffersDeleted(int, int[], int)}</li>
+ * <li>{@link GL#glBufferData(int, long, java.nio.Buffer, int)} - storage recreation via target</li>
+ * <li>{@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)} - storage recreation, direct</li>
+ * </ul>
+ * </p>
+ * <p>
+ * GL buffer storage is mapped via
+ * <ul>
+ *
+ * <li>{@link GL#mapBuffer(int, int)}</li>
+ * <li>{@link GL#mapBufferRange(int, long, long, int)}</li>
+ * <li>{@link GL2#mapNamedBuffer(int, int)}</li>
+ * <li>{@link GL2#mapNamedBufferRange(int, long, long, int)}</li>
+ * </ul>
+ * </p>
+ * <p>
+ * GL buffer storage is unmapped via
+ * <ul>
+ * <li>{@link GL#glUnmapBuffer(int)} - explicit via target</li>
+ * <li>{@link GL2#glUnmapNamedBufferEXT(int)} - explicit direct</li>
+ * <li>{@link GL#glBufferData(int, long, java.nio.Buffer, int)} - storage recreation via target</li>
+ * <li>{@link GL2#glNamedBufferDataEXT(int, long, java.nio.Buffer, int)} - storage recreation, direct</li>
+ * <li>{@link GL#glDeleteBuffers(int, IntBuffer)} - buffer deletion</li>
+ * </ul>
+ * </p>
+ */
+public abstract class GLBufferStorage {
+ private final int name;
+ private /* final */ long size;
+ private /* final */ int mutableUsage;
+ private /* final */ int immutableFlags;
+ private ByteBuffer mappedBuffer;
+
+ protected GLBufferStorage(final int name, final long size, final int mutableUsage, final int immutableFlags) {
+ this.name = name;
+ this.size = size;
+ this.mutableUsage = mutableUsage;
+ this.immutableFlags = immutableFlags;
+ this.mappedBuffer = null;
+ }
+
+ protected void reset(final long size, final int mutableUsage, final int immutableFlags) {
+ this.size = size;
+ this.mutableUsage = mutableUsage;
+ this.immutableFlags = immutableFlags;
+ this.mappedBuffer = null;
+ }
+ protected void setMappedBuffer(final ByteBuffer buffer) {
+ this.mappedBuffer = buffer;
+ }
+
+ /** Return the buffer name */
+ public final int getName() { return name; }
+
+ /** Return the buffer's storage size. */
+ public final long getSize() { return size; }
+
+ /**
+ * Returns <code>true</code> if buffer's storage is mutable, i.e.
+ * created via {@link GL#glBufferData(int, long, java.nio.Buffer, int)}.
+ * <p>
+ * Returns <code>false</code> if buffer's storage is immutable, i.e.
+ * created via <code>glBufferStorage</code>. FIXME: Add GL 4.4 support!
+ * </p>
+ * @return
+ */
+ public final boolean isMutableStorage() { return 0 != mutableUsage; }
+
+ /**
+ * Returns the mutable storage usage or 0 if storage is not {@link #isMutableStorage() mutable}.
+ */
+ public final int getMutableUsage() { return mutableUsage; }
+
+ /**
+ * Returns the immutable storage flags, invalid if storage is {@link #isMutableStorage() mutable}.
+ */
+ public final int getImmutableFlags() { return immutableFlags; }
+
+ /**
+ * Returns the mapped ByteBuffer, or null if not mapped.
+ * Mapping may occur via:
+ * <ul>
+ * <li>{@link GL#glMapBuffer(int, int)}</li>
+ * <li>{@link GL#glMapBufferRange(int, long, long, int)}</li>
+ * <li>{@link GL2#glMapNamedBufferEXT(int, int)}</li>
+ * <li>{@link GL2#glMapNamedBufferRangeEXT(int, long, long, int)}
+ * </ul>
+ */
+ public final ByteBuffer getMappedBuffer() { return mappedBuffer; }
+
+ public final String toString() {
+ return toString(false);
+ }
+ public final String toString(final boolean skipMappedBuffer) {
+ final String s0;
+ if( isMutableStorage() ) {
+ s0 = String.format("%s[name %s, size %d, mutable usage 0x%X", msgClazzName, name, size, mutableUsage);
+ } else {
+ s0 = String.format("%s[name %s, size %d, immutable flags 0x%X", msgClazzName, name, size, immutableFlags);
+ }
+ if(skipMappedBuffer) {
+ return s0+"]";
+ } else {
+ return s0+", mapped "+mappedBuffer+"]";
+ }
+ }
+ private static final String msgClazzName = "GLBufferStorage";
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLCapabilities.java b/src/jogl/classes/com/jogamp/opengl/GLCapabilities.java
new file mode 100644
index 000000000..02aa47119
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLCapabilities.java
@@ -0,0 +1,512 @@
+/*
+ * Copyright (c) 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl;
+
+import com.jogamp.nativewindow.Capabilities;
+import com.jogamp.nativewindow.CapabilitiesImmutable;
+
+/** Specifies a set of OpenGL capabilities.<br>
+ At creation time of a {@link GLDrawable} using {@link GLDrawableFactory},
+ an instance of this class is passed,
+ describing the desired capabilities that a rendering context
+ must support, such as the OpenGL profile, color depth and whether stereo is enabled.<br>
+
+ The actual capabilites of created {@link GLDrawable}s are then reflected by their own
+ GLCapabilites instance, which can be queried with {@link GLDrawable#getChosenGLCapabilities()}.
+ <br>
+
+ It currently contains the minimal number of routines which allow
+ configuration on all supported window systems. */
+public class GLCapabilities extends Capabilities implements Cloneable, GLCapabilitiesImmutable {
+ private GLProfile glProfile = null;
+ private boolean isPBuffer = false;
+ private boolean isFBO = false;
+ private boolean doubleBuffered = true;
+ private boolean stereo = false;
+ private boolean hardwareAccelerated = true;
+ private int depthBits = 16;
+ private int stencilBits = 0;
+ private int accumRedBits = 0;
+ private int accumGreenBits = 0;
+ private int accumBlueBits = 0;
+ private int accumAlphaBits = 0;
+ // Shift bits from PIXELFORMATDESCRIPTOR not present because they
+ // are unlikely to be supported on Windows anyway
+
+ // Support for full-scene antialiasing (FSAA)
+ private String sampleExtension = DEFAULT_SAMPLE_EXTENSION;
+ private boolean sampleBuffers = false;
+ private int numSamples = 2;
+
+ /** Creates a GLCapabilities object. All attributes are in a default state.
+ * @param glp GLProfile, or null for the default GLProfile
+ * @throws GLException if no profile is given and no default profile is available for the default device.
+ */
+ public GLCapabilities(final GLProfile glp) throws GLException {
+ glProfile = (null!=glp)?glp:GLProfile.getDefault(GLProfile.getDefaultDevice());
+ }
+
+ @Override
+ public Object cloneMutable() {
+ return clone();
+ }
+
+ @Override
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (final RuntimeException e) {
+ throw new GLException(e);
+ }
+ }
+
+ /**
+ * Copies all {@link GLCapabilitiesImmutable} values
+ * from <code>source</code> into this instance.
+ * @return this instance
+ */
+ public GLCapabilities copyFrom(final GLCapabilitiesImmutable source) {
+ super.copyFrom(source);
+ glProfile = source.getGLProfile();
+ isPBuffer = source.isPBuffer();
+ isFBO = source.isFBO();
+ doubleBuffered = source.getDoubleBuffered();
+ stereo = source.getStereo();
+ hardwareAccelerated = source.getHardwareAccelerated();
+ depthBits = source.getDepthBits();
+ stencilBits = source.getStencilBits();
+ accumRedBits = source.getAccumRedBits();
+ accumGreenBits = source.getAccumGreenBits();
+ accumBlueBits = source.getAccumBlueBits();
+ accumAlphaBits = source.getAccumAlphaBits();
+ sampleBuffers = source.getSampleBuffers();
+ numSamples = source.getNumSamples();
+ sampleExtension = source.getSampleExtension();
+ return this;
+ }
+
+ @Override
+ public int hashCode() {
+ // 31 * x == (x << 5) - x
+ int hash = super.hashCode();
+ hash = ((hash << 5) - hash) + this.glProfile.hashCode() ;
+ hash = ((hash << 5) - hash) + ( this.hardwareAccelerated ? 1 : 0 );
+ hash = ((hash << 5) - hash) + ( this.stereo ? 1 : 0 );
+ hash = ((hash << 5) - hash) + ( this.isFBO ? 1 : 0 );
+ hash = ((hash << 5) - hash) + ( this.isPBuffer ? 1 : 0 );
+ hash = ((hash << 5) - hash) + ( this.sampleBuffers ? 1 : 0 );
+ hash = ((hash << 5) - hash) + this.getNumSamples();
+ hash = ((hash << 5) - hash) + this.sampleExtension.hashCode();
+ hash = ((hash << 5) - hash) + this.depthBits;
+ hash = ((hash << 5) - hash) + this.stencilBits;
+ hash = ((hash << 5) - hash) + this.accumRedBits;
+ hash = ((hash << 5) - hash) + this.accumGreenBits;
+ hash = ((hash << 5) - hash) + this.accumBlueBits;
+ hash = ((hash << 5) - hash) + this.accumAlphaBits;
+ return hash;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if(this == obj) { return true; }
+ if(!(obj instanceof GLCapabilitiesImmutable)) {
+ return false;
+ }
+ final GLCapabilitiesImmutable other = (GLCapabilitiesImmutable)obj;
+ boolean res = super.equals(obj) &&
+ other.getGLProfile()==glProfile &&
+ other.isPBuffer()==isPBuffer &&
+ other.isFBO()==isFBO &&
+ other.getDoubleBuffered() == doubleBuffered &&
+ other.getStereo()==stereo &&
+ other.getHardwareAccelerated()==hardwareAccelerated &&
+ other.getDepthBits()==depthBits &&
+ other.getStencilBits()==stencilBits &&
+ other.getAccumRedBits()==accumRedBits &&
+ other.getAccumGreenBits()==accumGreenBits &&
+ other.getAccumBlueBits()==accumBlueBits &&
+ other.getAccumAlphaBits()==accumAlphaBits &&
+ other.getSampleBuffers()==sampleBuffers;
+ if(res && sampleBuffers) {
+ res = other.getNumSamples()==getNumSamples() &&
+ other.getSampleExtension().equals(sampleExtension) ;
+ }
+ return res;
+ }
+
+ /** comparing hw/sw, stereo, multisample, stencil, RGBA and depth only */
+ @Override
+ public int compareTo(final CapabilitiesImmutable o) {
+ if ( ! ( o instanceof GLCapabilitiesImmutable ) ) {
+ final Class<?> c = (null != o) ? o.getClass() : null ;
+ throw new ClassCastException("Not a GLCapabilitiesImmutable object, but " + c);
+ }
+ final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) o;
+
+ if(hardwareAccelerated && !caps.getHardwareAccelerated()) {
+ return 1;
+ } else if(!hardwareAccelerated && caps.getHardwareAccelerated()) {
+ return -1;
+ }
+
+ if(stereo && !caps.getStereo()) {
+ return 1;
+ } else if(!stereo && caps.getStereo()) {
+ return -1;
+ }
+
+ if(doubleBuffered && !caps.getDoubleBuffered()) {
+ return 1;
+ } else if(!doubleBuffered && caps.getDoubleBuffered()) {
+ return -1;
+ }
+
+ final int ms = getNumSamples();
+ final int xms = caps.getNumSamples() ;
+
+ if(ms > xms) {
+ return 1;
+ } else if( ms < xms ) {
+ return -1;
+ }
+ // ignore the sample extension
+
+ if(stencilBits > caps.getStencilBits()) {
+ return 1;
+ } else if(stencilBits < caps.getStencilBits()) {
+ return -1;
+ }
+
+ final int sc = super.compareTo(caps); // RGBA
+ if(0 != sc) {
+ return sc;
+ }
+
+ if(depthBits > caps.getDepthBits()) {
+ return 1;
+ } else if(depthBits < caps.getDepthBits()) {
+ return -1;
+ }
+
+ return 0; // they are equal: hw/sw, stereo, multisample, stencil, RGBA and depth
+ }
+
+ @Override
+ public final GLProfile getGLProfile() {
+ return glProfile;
+ }
+
+ /** Sets the GL profile you desire */
+ public void setGLProfile(final GLProfile profile) {
+ glProfile=profile;
+ }
+
+ @Override
+ public final boolean isPBuffer() {
+ return isPBuffer;
+ }
+
+ /**
+ * Requesting offscreen pbuffer mode.
+ * <p>
+ * If enabled this method also invokes {@link #setOnscreen(boolean) setOnscreen(false)}.
+ * </p>
+ * <p>
+ * Defaults to false.
+ * </p>
+ * <p>
+ * Requesting offscreen pbuffer mode disables the offscreen auto selection.
+ * </p>
+ */
+ public void setPBuffer(final boolean enable) {
+ if(enable) {
+ setOnscreen(false);
+ }
+ isPBuffer = enable;
+ }
+
+ @Override
+ public final boolean isFBO() {
+ return isFBO;
+ }
+
+ /**
+ * Requesting offscreen FBO mode.
+ * <p>
+ * If enabled this method also invokes {@link #setOnscreen(boolean) setOnscreen(false)}.
+ * </p>
+ * <p>
+ * Defaults to false.
+ * </p>
+ * <p>
+ * Requesting offscreen FBO mode disables the offscreen auto selection.
+ * </p>
+ */
+ public void setFBO(final boolean enable) {
+ if(enable) {
+ setOnscreen(false);
+ }
+ isFBO = enable;
+ }
+
+ @Override
+ public final boolean getDoubleBuffered() {
+ return doubleBuffered;
+ }
+
+ /** Enables or disables double buffering. */
+ public void setDoubleBuffered(final boolean enable) {
+ doubleBuffered = enable;
+ }
+
+ @Override
+ public final boolean getStereo() {
+ return stereo;
+ }
+
+ /** Enables or disables stereo viewing. */
+ public void setStereo(final boolean enable) {
+ stereo = enable;
+ }
+
+ @Override
+ public final boolean getHardwareAccelerated() {
+ return hardwareAccelerated;
+ }
+
+ /** Enables or disables hardware acceleration. */
+ public void setHardwareAccelerated(final boolean enable) {
+ hardwareAccelerated = enable;
+ }
+
+ @Override
+ public final int getDepthBits() {
+ return depthBits;
+ }
+
+ /** Sets the number of bits requested for the depth buffer. */
+ public void setDepthBits(final int depthBits) {
+ this.depthBits = depthBits;
+ }
+
+ @Override
+ public final int getStencilBits() {
+ return stencilBits;
+ }
+
+ /** Sets the number of bits requested for the stencil buffer. */
+ public void setStencilBits(final int stencilBits) {
+ this.stencilBits = stencilBits;
+ }
+
+ @Override
+ public final int getAccumRedBits() {
+ return accumRedBits;
+ }
+
+ /** Sets the number of bits requested for the accumulation buffer's
+ red component. On some systems only the accumulation buffer
+ depth, which is the sum of the red, green, and blue bits, is
+ considered. */
+ public void setAccumRedBits(final int accumRedBits) {
+ this.accumRedBits = accumRedBits;
+ }
+
+ @Override
+ public final int getAccumGreenBits() {
+ return accumGreenBits;
+ }
+
+ /** Sets the number of bits requested for the accumulation buffer's
+ green component. On some systems only the accumulation buffer
+ depth, which is the sum of the red, green, and blue bits, is
+ considered. */
+ public void setAccumGreenBits(final int accumGreenBits) {
+ this.accumGreenBits = accumGreenBits;
+ }
+
+ @Override
+ public final int getAccumBlueBits() {
+ return accumBlueBits;
+ }
+
+ /** Sets the number of bits requested for the accumulation buffer's
+ blue component. On some systems only the accumulation buffer
+ depth, which is the sum of the red, green, and blue bits, is
+ considered. */
+ public void setAccumBlueBits(final int accumBlueBits) {
+ this.accumBlueBits = accumBlueBits;
+ }
+
+ @Override
+ public final int getAccumAlphaBits() {
+ return accumAlphaBits;
+ }
+
+ /** Sets number of bits requested for accumulation buffer's alpha
+ component. On some systems only the accumulation buffer depth,
+ which is the sum of the red, green, and blue bits, is
+ considered. */
+ public void setAccumAlphaBits(final int accumAlphaBits) {
+ this.accumAlphaBits = accumAlphaBits;
+ }
+
+ /**
+ * Sets the desired extension for full-scene antialiasing
+ * (FSAA), default is {@link #DEFAULT_SAMPLE_EXTENSION}.
+ */
+ public void setSampleExtension(final String se) {
+ sampleExtension = se;
+ }
+
+ @Override
+ public final String getSampleExtension() {
+ return sampleExtension;
+ }
+
+ /**
+ * Defaults to false.<br>
+ * Indicates whether sample buffers for full-scene antialiasing
+ * (FSAA) should be allocated for this drawable.<br>
+ * Mind that this requires the alpha component.<br>
+ * If enabled this method also invokes {@link #setAlphaBits(int) setAlphaBits(1)}
+ * if {@link #getAlphaBits()} == 0.<br>
+ */
+ public void setSampleBuffers(final boolean enable) {
+ sampleBuffers = enable;
+ if(sampleBuffers && getAlphaBits()==0) {
+ setAlphaBits(1);
+ }
+ }
+
+ @Override
+ public final boolean getSampleBuffers() {
+ return sampleBuffers;
+ }
+
+ /**
+ * If sample buffers are enabled, indicates the number of buffers
+ * to be allocated. Defaults to 2.
+ * @see #getNumSamples()
+ */
+ public void setNumSamples(final int numSamples) {
+ this.numSamples = numSamples;
+ }
+
+ @Override
+ public final int getNumSamples() {
+ return sampleBuffers ? numSamples : 0;
+ }
+
+ @Override
+ public StringBuilder toString(StringBuilder sink) {
+ if(null == sink) {
+ sink = new StringBuilder();
+ }
+
+ final int samples = sampleBuffers ? numSamples : 0 ;
+
+ super.toString(sink, false);
+
+ sink.append(", accum-rgba ").append(accumRedBits).append(ESEP).append(accumGreenBits).append(ESEP).append(accumBlueBits).append(ESEP).append(accumAlphaBits);
+ sink.append(", dp/st/ms ").append(depthBits).append(ESEP).append(stencilBits).append(ESEP).append(samples);
+ if(samples>0) {
+ sink.append(", sample-ext ").append(sampleExtension);
+ }
+ if(doubleBuffered) {
+ sink.append(", dbl");
+ } else {
+ sink.append(", one");
+ }
+ if(stereo) {
+ sink.append(", stereo");
+ } else {
+ sink.append(", mono ");
+ }
+ if(hardwareAccelerated) {
+ sink.append(", hw, ");
+ } else {
+ sink.append(", sw, ");
+ }
+ sink.append(glProfile);
+ if(isOnscreen()) {
+ sink.append(", on-scr[");
+ } else {
+ sink.append(", offscr[");
+ }
+ boolean ns=false;
+ if(isFBO()) {
+ sink.append("fbo");
+ ns = true;
+ }
+ if(isPBuffer()) {
+ if(ns) { sink.append(CSEP); }
+ sink.append("pbuffer");
+ ns = true;
+ }
+ if(isBitmap()) {
+ if(ns) { sink.append(CSEP); }
+ sink.append("bitmap");
+ ns = true;
+ }
+ if(!ns) { // !FBO !PBuffer !Bitmap
+ if(isOnscreen()) {
+ sink.append("."); // no additional off-screen modes besides on-screen
+ } else {
+ sink.append("auto-cfg"); // auto-config off-screen mode
+ }
+ }
+ sink.append("]");
+
+ return sink;
+ }
+
+ /** Returns a textual representation of this GLCapabilities
+ object. */
+ @Override
+ public String toString() {
+ final StringBuilder msg = new StringBuilder();
+ msg.append("GLCaps[");
+ toString(msg);
+ msg.append("]");
+ return msg.toString();
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLCapabilitiesChooser.java b/src/jogl/classes/com/jogamp/opengl/GLCapabilitiesChooser.java
new file mode 100644
index 000000000..9911d1314
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLCapabilitiesChooser.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl;
+
+import java.util.List;
+
+import com.jogamp.nativewindow.CapabilitiesImmutable;
+import com.jogamp.nativewindow.CapabilitiesChooser;
+
+import com.jogamp.opengl.GLCapabilitiesImmutable;
+
+/** Provides a mechanism by which applications can customize the
+ window type selection for a given {@link GLCapabilities}.
+ Developers can implement this interface and pass an instance into
+ the appropriate method of {@link GLDrawableFactory}; the chooser
+ will be called during the OpenGL context creation process. Note
+ that this is only a marker interface; its signature is the same as
+ {@link CapabilitiesChooser} and the {@link List} of
+ objects extending {@link CapabilitiesImmutable}
+ passed to {@link #chooseCapabilities chooseCapabilities}
+ is actually a {@link List} of type {@link GLCapabilitiesImmutable}. */
+
+public interface GLCapabilitiesChooser extends CapabilitiesChooser {
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLCapabilitiesImmutable.java b/src/jogl/classes/com/jogamp/opengl/GLCapabilitiesImmutable.java
new file mode 100644
index 000000000..25081a521
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLCapabilitiesImmutable.java
@@ -0,0 +1,178 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl;
+
+import com.jogamp.nativewindow.CapabilitiesImmutable;
+
+/**
+ * Specifies an immutable set of OpenGL capabilities.<br>
+ *
+ * @see com.jogamp.opengl.GLCapabilities
+ * @see com.jogamp.nativewindow.CapabilitiesImmutable
+ */
+public interface GLCapabilitiesImmutable extends CapabilitiesImmutable {
+ /**
+ * One of the platform's default sample extension
+ * <code>EGL.EGL_SAMPLES, GLX.GLX_SAMPLES, WGLExt.WGL_SAMPLES_ARB</code>
+ * if available, or any other <i>known</i> fallback one, ie <code>EGLExt.EGL_COVERAGE_SAMPLES_NV</code>
+ */
+ public static final String DEFAULT_SAMPLE_EXTENSION = "default" ;
+
+ /**
+ * Returns the GL profile you desire or used by the drawable.
+ */
+ GLProfile getGLProfile();
+
+ /**
+ * Returns the number of bits for the accumulation
+ * buffer's alpha component. On some systems only the accumulation
+ * buffer depth, which is the sum of the red, green, and blue bits,
+ * is considered.
+ */
+ int getAccumAlphaBits();
+
+ /**
+ * Returns the number of bits for the accumulation
+ * buffer's blue component. On some systems only the accumulation
+ * buffer depth, which is the sum of the red, green, and blue bits,
+ * is considered.
+ */
+ int getAccumBlueBits();
+
+ /**
+ * Returns the number of bits for the accumulation
+ * buffer's green component. On some systems only the accumulation
+ * buffer depth, which is the sum of the red, green, and blue bits,
+ * is considered.
+ */
+ int getAccumGreenBits();
+
+ /**
+ * Returns the number of bits for the accumulation
+ * buffer's red component. On some systems only the accumulation
+ * buffer depth, which is the sum of the red, green, and blue bits,
+ * is considered.
+ */
+ int getAccumRedBits();
+
+ /**
+ * Returns the number of depth buffer bits.
+ */
+ int getDepthBits();
+
+ /**
+ * Returns whether double-buffering is requested, available or chosen.
+ * <p>
+ * Default is true.
+ * </p>
+ */
+ boolean getDoubleBuffered();
+
+ /**
+ * Returns whether hardware acceleration is requested, available or chosen.
+ * <p>
+ * Default is true.
+ * </p>
+ */
+ boolean getHardwareAccelerated();
+
+ /**
+ * Returns the extension for full-scene antialiasing
+ * (FSAA).
+ * <p>
+ * Default is {@link #DEFAULT_SAMPLE_EXTENSION}.
+ * </p>
+ */
+ String getSampleExtension();
+
+ /**
+ * Returns whether sample buffers for full-scene antialiasing
+ * (FSAA) should be allocated for this drawable.
+ * <p>
+ * Default is false.
+ * </p>
+ */
+ boolean getSampleBuffers();
+
+ /**
+ * Returns the number of sample buffers to be allocated if sample
+ * buffers are enabled, otherwise returns 0.
+ * <p>
+ * Default is 0 due to disable sample buffers per default.
+ * </p>
+ */
+ int getNumSamples();
+
+ /**
+ * Returns the number of stencil buffer bits.
+ * <p>
+ * Default is 0.
+ * </p>
+ */
+ int getStencilBits();
+
+ /**
+ * Returns whether stereo is requested, available or chosen.
+ * <p>
+ * Default is false.
+ * </p>
+ */
+ boolean getStereo();
+
+ /**
+ * Returns whether pbuffer offscreen mode is requested, available or chosen.
+ * <p>
+ * Default is false.
+ * </p>
+ * <p>
+ * For chosen capabilities, only the selected offscreen surface is set to <code>true</code>.
+ * </p>
+ */
+ boolean isPBuffer();
+
+ /**
+ * Returns whether FBO offscreen mode is requested, available or chosen.
+ * <p>
+ * Default is false.
+ * </p>
+ * <p>
+ * For chosen capabilities, only the selected offscreen surface is set to <code>true</code>.
+ * </p>
+ */
+ boolean isFBO();
+
+ @Override
+ boolean equals(Object obj);
+
+ @Override
+ int hashCode();
+
+ @Override
+ String toString();
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLContext.java b/src/jogl/classes/com/jogamp/opengl/GLContext.java
new file mode 100644
index 000000000..6366c4e37
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLContext.java
@@ -0,0 +1,2038 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl;
+
+import java.nio.IntBuffer;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import com.jogamp.nativewindow.AbstractGraphicsDevice;
+import com.jogamp.nativewindow.NativeSurface;
+
+import jogamp.opengl.Debug;
+import jogamp.opengl.GLContextImpl;
+import jogamp.opengl.GLContextShareSet;
+
+import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.VersionNumber;
+import com.jogamp.common.util.VersionNumberString;
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
+import com.jogamp.opengl.GLExtensions;
+import com.jogamp.opengl.GLRendererQuirks;
+
+/** Abstraction for an OpenGL rendering context. In order to perform
+ OpenGL rendering, a context must be "made current" on the current
+ thread. OpenGL rendering semantics specify that only one context
+ may be current on the current thread at any given time, and also
+ that a given context may be current on only one thread at any
+ given time. Because components can be added to and removed from
+ the component hierarchy at any time, it is possible that the
+ underlying OpenGL context may need to be destroyed and recreated
+ multiple times over the lifetime of a given component. This
+ process is handled by the implementation, and the GLContext
+ abstraction provides a stable object which clients can use to
+ refer to a given context. */
+public abstract class GLContext {
+
+ public static final boolean DEBUG = Debug.debug("GLContext");
+ public static final boolean TRACE_SWITCH = Debug.isPropertyDefined("jogl.debug.GLContext.TraceSwitch", true);
+ public static final boolean DEBUG_TRACE_SWITCH = DEBUG || TRACE_SWITCH;
+
+ /**
+ * If <code>true</code> (default), bootstrapping the available GL profiles
+ * will use the highest compatible GL context for each profile,
+ * hence skipping querying lower profiles if a compatible higher one is found:
+ * <ul>
+ * <li>4.2-core -> 4.2-core, 3.3-core</li>
+ * <li>4.2-comp -> 4.2-comp, 3.3-comp, 2</li>
+ * </ul>
+ * Otherwise the dedicated GL context would be queried and used:
+ * <ul>
+ * <li>4.2-core -> 4.2-core</li>
+ * <li>3.3-core -> 3.3-core</li>
+ * <li>4.2-comp -> 4.2-comp</li>
+ * <li>3.3-comp -> 3.3-comp</li>
+ * <li>3.0-comp -> 2</li>
+ * </ul>
+ * Using aliasing speeds up initialization about:
+ * <ul>
+ * <li>Linux x86_64 - Nvidia: 28%, 700ms down to 500ms</li>
+ * <li>Linux x86_64 - AMD : 40%, 1500ms down to 900ms</li>
+ * <p>
+ * Can be turned off with property <code>jogl.debug.GLContext.NoProfileAliasing</code>.
+ * </p>
+ */
+ public static final boolean PROFILE_ALIASING = !Debug.isPropertyDefined("jogl.debug.GLContext.NoProfileAliasing", true);
+
+ protected static final boolean FORCE_NO_FBO_SUPPORT = Debug.isPropertyDefined("jogl.fbo.force.none", true);
+ protected static final boolean FORCE_MIN_FBO_SUPPORT = Debug.isPropertyDefined("jogl.fbo.force.min", true);
+ protected static final boolean FORCE_NO_COLOR_RENDERBUFFER = Debug.isPropertyDefined("jogl.fbo.force.nocolorrenderbuffer", true);
+
+ /** Reflects property jogl.debug.DebugGL. If true, the debug pipeline is enabled at context creation. */
+ public static final boolean DEBUG_GL = Debug.isPropertyDefined("jogl.debug.DebugGL", true);
+ /** Reflects property jogl.debug.TraceGL. If true, the trace pipeline is enabled at context creation. */
+ public static final boolean TRACE_GL = Debug.isPropertyDefined("jogl.debug.TraceGL", true);
+
+ /** Indicates that the context was not made current during the last call to {@link #makeCurrent makeCurrent}, value {@value}. */
+ public static final int CONTEXT_NOT_CURRENT = 0;
+ /** Indicates that the context was made current during the last call to {@link #makeCurrent makeCurrent}, value {@value}. */
+ public static final int CONTEXT_CURRENT = 1;
+ /** Indicates that a newly-created context was made current during the last call to {@link #makeCurrent makeCurrent}, value {@value}. */
+ public static final int CONTEXT_CURRENT_NEW = 2;
+
+ /** Version 1.00, i.e. GLSL 1.00 for ES 2.0. */
+ public static final VersionNumber Version1_0 = new VersionNumber(1, 0, 0);
+ /** Version 1.10, i.e. GLSL 1.10 for GL 2.0. */
+ public static final VersionNumber Version1_10 = new VersionNumber(1, 10, 0);
+ /** Version 1.20, i.e. GLSL 1.20 for GL 2.1. */
+ public static final VersionNumber Version1_20 = new VersionNumber(1, 20, 0);
+ /** Version 1.30, i.e. GLSL 1.30 for GL 3.0. */
+ public static final VersionNumber Version1_30 = new VersionNumber(1, 30, 0);
+ /** Version 1.40, i.e. GLSL 1.40 for GL 3.1. */
+ public static final VersionNumber Version1_40 = new VersionNumber(1, 40, 0);
+ /** Version 1.50, i.e. GLSL 1.50 for GL 3.2. */
+ public static final VersionNumber Version1_50 = new VersionNumber(1, 50, 0);
+
+ /** Version 1.1, i.e. GL 1.1 */
+ public static final VersionNumber Version1_1 = new VersionNumber(1, 1, 0);
+
+ /** Version 1.2, i.e. GL 1.2 */
+ public static final VersionNumber Version1_2 = new VersionNumber(1, 2, 0);
+
+ /** Version 1.4, i.e. GL 1.4 */
+ public static final VersionNumber Version1_4 = new VersionNumber(1, 4, 0);
+
+ /** Version 1.5, i.e. GL 1.5 */
+ public static final VersionNumber Version1_5 = new VersionNumber(1, 5, 0);
+
+ /** Version 3.0. As an OpenGL version, it qualifies for desktop {@link #isGL2()} only, or ES 3.0. Or GLSL 3.00 for ES 3.0. */
+ public static final VersionNumber Version3_0 = new VersionNumber(3, 0, 0);
+
+ /** Version 3.1. As an OpenGL version, it qualifies for {@link #isGL3core()}, {@link #isGL3bc()} and {@link #isGL3()} */
+ public static final VersionNumber Version3_1 = new VersionNumber(3, 1, 0);
+
+ /** Version 3.2. As an OpenGL version, it qualifies for geometry shader */
+ public static final VersionNumber Version3_2 = new VersionNumber(3, 2, 0);
+
+ /** Version 4.3. As an OpenGL version, it qualifies for <code>GL_ARB_ES3_compatibility</code> */
+ public static final VersionNumber Version4_3 = new VersionNumber(4, 3, 0);
+
+ protected static final VersionNumber Version8_0 = new VersionNumber(8, 0, 0);
+
+ private static final String S_EMPTY = "";
+
+ //
+ // Cached keys, bits [0..15]
+ //
+
+ /** Context option bits, full bit mask covering 16 bits [0..15], i.e. <code>0x0000FFFF</code>, {@value}. */
+ protected static final int CTX_IMPL_FULL_MASK = 0x0000FFFF;
+
+ /** Context option bits, cached bit mask covering 10 bits [0..9], i.e. <code>0x000003FF</code>, {@value}. Leaving 6 bits for non cached options, i.e. 10:6. */
+ protected static final int CTX_IMPL_CACHE_MASK = 0x000003FF;
+
+ /** <code>ARB_create_context</code> related: created via ARB_create_context. Cache key value. See {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */
+ protected static final int CTX_IS_ARB_CREATED = 1 << 0;
+ /** <code>ARB_create_context</code> related: desktop compatibility profile. Cache key value. See {@link #isGLCompatibilityProfile()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */
+ protected static final int CTX_PROFILE_COMPAT = 1 << 1;
+ /** <code>ARB_create_context</code> related: desktop core profile. Cache key value. See {@link #isGLCoreProfile()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */
+ protected static final int CTX_PROFILE_CORE = 1 << 2;
+ /** <code>ARB_create_context</code> related: ES profile. Cache key value. See {@link #isGLES()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */
+ protected static final int CTX_PROFILE_ES = 1 << 3;
+ /** <code>ARB_create_context</code> related: flag forward compatible. Cache key value. See {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */
+ protected static final int CTX_OPTION_FORWARD = 1 << 4;
+ /** <code>ARB_create_context</code> related: flag debug. Cache key value. See {@link #setContextCreationFlags(int)}, {@link GLAutoDrawable#setContextCreationFlags(int)}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */
+ public static final int CTX_OPTION_DEBUG = 1 << 5;
+ /** Context uses software rasterizer, otherwise hardware rasterizer. Cache key value. See {@link #isHardwareRasterizer()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */
+ protected static final int CTX_IMPL_ACCEL_SOFT = 1 << 6;
+
+ //
+ // Non cached keys, 6 bits [10..15]
+ //
+
+ /** <code>GL_ARB_ES2_compatibility</code> implementation related: Context is compatible w/ ES2. Not a cache key. See {@link #isGLES2Compatible()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */
+ protected static final int CTX_IMPL_ES2_COMPAT = 1 << 10;
+
+ /** <code>GL_ARB_ES3_compatibility</code> implementation related: Context is compatible w/ ES3. Not a cache key. See {@link #isGLES3Compatible()}, {@link #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)}. */
+ protected static final int CTX_IMPL_ES3_COMPAT = 1 << 11;
+
+ /**
+ * Context supports basic FBO, details see {@link #hasBasicFBOSupport()}.
+ * Not a cache key.
+ * @see #hasBasicFBOSupport()
+ * @see #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)
+ */
+ protected static final int CTX_IMPL_FBO = 1 << 12;
+
+ /**
+ * Context supports <code>OES_single_precision</code>, fp32, fixed function point (FFP) compatibility entry points,
+ * see {@link #hasFP32CompatAPI()}.
+ * Not a cache key.
+ * @see #hasFP32CompatAPI()
+ * @see #getAvailableContextProperties(AbstractGraphicsDevice, GLProfile)
+ */
+ protected static final int CTX_IMPL_FP32_COMPAT_API = 1 << 13;
+
+ private static final ThreadLocal<GLContext> currentContext = new ThreadLocal<GLContext>();
+
+ private final HashMap<String, Object> attachedObjects = new HashMap<String, Object>();
+
+ // RecursiveLock maintains a queue of waiting Threads, ensuring the longest waiting thread will be notified at unlock.
+ protected final RecursiveLock lock = LockFactory.createRecursiveLock(); // FIXME: Move to GLContextImpl when incr. minor version (incompatible change)
+
+ /** The underlying native OpenGL context */
+ protected volatile long contextHandle; // volatile: avoid locking for read-only access
+
+ protected GLContext() {
+ resetStates(true);
+ }
+
+ protected VersionNumber ctxVersion;
+ protected int ctxOptions;
+ protected String ctxVersionString;
+ protected VersionNumberString ctxVendorVersion;
+ protected VersionNumber ctxGLSLVersion;
+ private int currentSwapInterval;
+ protected GLRendererQuirks glRendererQuirks;
+
+ /** Did the drawable association changed ? see {@link GLRendererQuirks#NoSetSwapIntervalPostRetarget} */
+ protected boolean drawableRetargeted;
+
+ /**
+ * @param isInit true if called for class initialization, otherwise false (re-init or destruction).
+ */
+ protected void resetStates(final boolean isInit) {
+ if (DEBUG) {
+ System.err.println(getThreadName() + ": GLContext.resetStates(isInit "+isInit+")");
+ // Thread.dumpStack();
+ }
+ ctxVersion = VersionNumberString.zeroVersion;
+ ctxVendorVersion = VersionNumberString.zeroVersion;
+ ctxOptions=0;
+ ctxVersionString=null;
+ ctxGLSLVersion = VersionNumber.zeroVersion;
+ attachedObjects.clear();
+ contextHandle=0;
+ currentSwapInterval = -1;
+ glRendererQuirks = null;
+ drawableRetargeted = false;
+ }
+
+ /** Returns true if this GLContext is shared, otherwise false. */
+ public final boolean isShared() {
+ return GLContextShareSet.isShared(this);
+ }
+
+ /**
+ * Returns the shared master GLContext of this GLContext if shared, otherwise return <code>null</code>.
+ * <p>
+ * Returns this GLContext, if it is a shared master.
+ * </p>
+ * @since 2.2.1
+ */
+ public final GLContext getSharedMaster() {
+ return GLContextShareSet.getSharedMaster(this);
+ }
+
+ /** Returns a new list of created GLContext shared with this GLContext. */
+ public final List<GLContext> getCreatedShares() {
+ return GLContextShareSet.getCreatedShares(this);
+ }
+
+ /** Returns a new list of destroyed GLContext shared with this GLContext. */
+ public final List<GLContext> getDestroyedShares() {
+ return GLContextShareSet.getDestroyedShares(this);
+ }
+
+ /**
+ * Returns the instance of {@link GLRendererQuirks}, allowing one to determine workarounds.
+ * @return instance of {@link GLRendererQuirks} if context was made current once, otherwise <code>null</code>.
+ */
+ public final GLRendererQuirks getRendererQuirks() { return glRendererQuirks; }
+
+ /**
+ * Returns true if the <code>quirk</code> exist in {@link #getRendererQuirks()}, otherwise false.
+ * <p>
+ * Convenience method for:
+ * <pre>
+ * final GLRendererQuirks glrq = ctx.getRendererQuirks();
+ * boolean hasQuirk = null != glrq ? glrq.exist(quirk) : false ;
+ * </pre>
+ * </p>
+ * @param quirk the quirk to be tested, e.g. {@link GLRendererQuirks#NoDoubleBufferedPBuffer}.
+ * @throws IllegalArgumentException if the quirk is out of range
+ */
+ public final boolean hasRendererQuirk(final int quirk) throws IllegalArgumentException {
+ return null != glRendererQuirks ? glRendererQuirks.exist(quirk) : false ;
+ }
+
+ /**
+ * Sets the read/write drawable for framebuffer operations, i.e. reassociation of the context's drawable.
+ * <p>
+ * If the arguments reflect the current state of this context
+ * this method is a no-operation and returns the old and current {@link GLDrawable}.
+ * </p>
+ * <p>
+ * Remarks:
+ * <ul>
+ * <li>{@link GL#glFinish() glFinish()} is issued if context {@link #isCreated()} and a {@link #getGLDrawable() previous drawable} was bound before disassociation.</li>
+ * <li>If the context was current on this thread, it is being released before drawable reassociation
+ * and made current afterwards.</li>
+ * <li>Implementation may issue {@link #makeCurrent()} and {@link #release()} while drawable reassociation.</li>
+ * <li>The user shall take extra care of thread synchronization,
+ * i.e. lock the involved {@link GLDrawable#getNativeSurface() drawable's} {@link NativeSurface}s
+ * to avoid a race condition. In case {@link GLAutoDrawable auto-drawable's} are used,
+ * their {@link GLAutoDrawable#getUpstreamLock() upstream-lock} must be locked beforehand
+ * see <a href="GLAutoDrawable.html#locking">GLAutoDrawable Locking</a>.</li>
+ * </ul>
+ * </p>
+ * @param readWrite The read/write drawable for framebuffer operations, maybe <code>null</code> to remove association.
+ * @param setWriteOnly Only change the write-drawable, if <code>setWriteOnly</code> is <code>true</code> and
+ * if the {@link #getGLReadDrawable() read-drawable} differs
+ * from the {@link #getGLDrawable() write-drawable}.
+ * Otherwise set both drawables, read and write.
+ * @return The previous read/write drawable if operation succeeds
+ *
+ * @throws GLException in case <code>null</code> is being passed,
+ * this context is made current on another thread
+ * or operation fails.
+ *
+ * @see #isGLReadDrawableAvailable()
+ * @see #setGLReadDrawable(GLDrawable)
+ * @see #getGLReadDrawable()
+ * @see #setGLDrawable(GLDrawable, boolean)
+ * @see #getGLDrawable()
+ */
+ public abstract GLDrawable setGLDrawable(GLDrawable readWrite, boolean setWriteOnly);
+
+ /**
+ * Returns the write-drawable this context uses for framebuffer operations.
+ * <p>
+ * If the read-drawable has not been changed manually via {@link #setGLReadDrawable(GLDrawable)},
+ * it equals to the write-drawable (default).
+ * </p>
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
+ * @see #setGLDrawable(GLDrawable, boolean)
+ * @see #setGLReadDrawable(GLDrawable)
+ */
+ public abstract GLDrawable getGLDrawable();
+
+ /**
+ * Query whether using a distinguished read-drawable is supported.
+ * @return true if using a read-drawable is supported with your driver/OS, otherwise false.
+ */
+ public abstract boolean isGLReadDrawableAvailable();
+
+ /**
+ * Set the read-Drawable for read framebuffer operations.<br>
+ * The caller should query if this feature is supported via {@link #isGLReadDrawableAvailable()}.
+ * <p>
+ * If the context was current on this thread, it is being released before switching the drawable
+ * and made current afterwards. However the user shall take extra care that not other thread
+ * attempts to make this context current. Otherwise a race condition may happen.
+ * </p>
+ *
+ * @param read the read-drawable for read framebuffer operations.
+ * If null is passed, the default write drawable will be set.
+ * @return the previous read-drawable
+ *
+ * @throws GLException in case a read drawable is not supported or
+ * this context is made current on another thread.
+ *
+ * @see #isGLReadDrawableAvailable()
+ * @see #getGLReadDrawable()
+ */
+ public abstract GLDrawable setGLReadDrawable(GLDrawable read);
+
+ /**
+ * Returns the read-Drawable this context uses for read framebuffer operations.
+ * <p>
+ * If the read-drawable has not been changed manually via {@link #setGLReadDrawable(GLDrawable)},
+ * it equals to the write-drawable (default).
+ * </p>
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
+ * @see #isGLReadDrawableAvailable()
+ * @see #setGLReadDrawable(GLDrawable)
+ * @see #getGLReadDrawable()
+ */
+ public abstract GLDrawable getGLReadDrawable();
+
+ /**
+ * Makes this GLContext current on the calling thread.
+ * <p>
+ * Recursive call to {@link #makeCurrent()} and hence {@link #release()} are supported.
+ * </p>
+ * <p>
+ * There are two return values that indicate success and one that
+ * indicates failure.
+ * </p>
+ * <p>
+ * A return value of {@link #CONTEXT_CURRENT_NEW}
+ * indicates that that context has been made current for the 1st time,
+ * or that the state of the underlying context or drawable has
+ * changed since the last time this context was current.
+ * In this case, the application may wish to initialize the render state.
+ * </p>
+ * <p>
+ * A return value of {@link #CONTEXT_CURRENT} indicates that the context has
+ * been made current, with its previous state restored.
+ * </p>
+ * <p>
+ * If the context could not be made current (for example, because
+ * the underlying drawable has not ben realized on the display) ,
+ * a value of {@link #CONTEXT_NOT_CURRENT} is returned.
+ * </p>
+ * <p>
+ * This method is blocking, i.e. waits until another thread has
+ * released the context.
+ * </p>
+ * <p>
+ * The drawable's surface is being locked at entry
+ * and unlocked at {@link #release()}
+ * </p>
+ *
+ * @return <ul>
+ * <li>{@link #CONTEXT_CURRENT_NEW} if the context was successfully made current the 1st time,</li>
+ * <li>{@link #CONTEXT_CURRENT} if the context was successfully made current,</li>
+ * <li>{@link #CONTEXT_NOT_CURRENT} if the context could not be made current.</li>
+ * </ul>
+ *
+ * @throws GLException if the context could not be created
+ * or made current due to non-recoverable, system-specific errors.
+ */
+ public abstract int makeCurrent() throws GLException;
+
+ /**
+ * Releases control of this GLContext from the current thread.
+ * <p>
+ * Recursive call to {@link #release()} and hence {@link #makeCurrent()} are supported.
+ * </p>
+ * <p>
+ * The drawable's surface is being unlocked at exit,
+ * assumed to be locked by {@link #makeCurrent()}.
+ * </p>
+ *
+ * @throws GLException if the context had not previously been made
+ * current on the current thread
+ */
+ public abstract void release() throws GLException;
+
+ /**
+ * Copies selected groups of OpenGL state variables from the
+ * supplied source context into this one. The <code>mask</code>
+ * parameter indicates which groups of state variables are to be
+ * copied. <code>mask</code> contains the bitwise OR of the same
+ * symbolic names that are passed to the GL command {@link
+ * GL2#glPushAttrib glPushAttrib}. The single symbolic constant
+ * {@link GL2#GL_ALL_ATTRIB_BITS GL_ALL_ATTRIB_BITS} can be used to
+ * copy the maximum possible portion of rendering state. <P>
+ *
+ * Not all values for GL state can be copied. For example, pixel
+ * pack and unpack state, render mode state, and select and feedback
+ * state are not copied. The state that can be copied is exactly the
+ * state that is manipulated by the GL command {@link
+ * GL2#glPushAttrib glPushAttrib}. <P>
+ *
+ * On most platforms, this context may not be current to any thread,
+ * including the calling thread, when this method is called. Some
+ * platforms have additional requirements such as whether this
+ * context or the source context must occasionally be made current
+ * in order for the results of the copy to be seen; these
+ * requirements are beyond the scope of this specification.
+ *
+ * @param source the source OpenGL context from which to copy state
+ * @param mask a mask of symbolic names indicating which groups of state to copy
+
+ * @throws GLException if an OpenGL-related error occurred
+ */
+ public abstract void copy(GLContext source, int mask) throws GLException;
+
+ /**
+ * Returns the GL object bound to this thread current context.
+ * If no context is current, throw an GLException
+ *
+ * @return the current context's GL object on this thread
+ * @throws GLException if no context is current
+ */
+ public static GL getCurrentGL() throws GLException {
+ final GLContext glc = getCurrent();
+ if(null==glc) {
+ throw new GLException(getThreadName()+": No OpenGL context current on this thread");
+ }
+ return glc.getGL();
+ }
+
+ /**
+ * Returns this thread current context.
+ * If no context is current, returns null.
+ *
+ * @return the context current on this thread, or null if no context
+ * is current.
+ */
+ public static GLContext getCurrent() {
+ return currentContext.get();
+ }
+
+ /**
+ * @return true if this GLContext is current on this thread
+ */
+ public final boolean isCurrent() {
+ return getCurrent() == this ;
+ }
+
+ /**
+ * @throws GLException if this GLContext is not current on this thread
+ */
+ public final void validateCurrent() throws GLException {
+ if(getCurrent() != this) {
+ throw new GLException(getThreadName()+": This context is not current. Current context: "+getCurrent()+", this context "+this);
+ }
+ }
+
+ /** Returns a String representation of the {@link #makeCurrent()} result. */
+ public static final String makeCurrentResultToString(final int res) {
+ switch(res) {
+ case CONTEXT_NOT_CURRENT: return "CONTEXT_NOT_CURRENT";
+ case CONTEXT_CURRENT: return "CONTEXT_CURRENT";
+ case CONTEXT_CURRENT_NEW: return "CONTEXT_CURRENT_NEW";
+ default: return "INVALID_VALUE";
+ }
+ }
+
+ /**
+ * Sets the thread-local variable returned by {@link #getCurrent}
+ * and has no other side-effects. For use by third parties adding
+ * new GLContext implementations; not for use by end users.
+ */
+ protected static void setCurrent(final GLContext cur) {
+ if( TRACE_SWITCH ) {
+ if(null == cur) {
+ System.err.println(getThreadName()+": GLContext.ContextSwitch: - setCurrent() - NULL");
+ } else {
+ System.err.println(getThreadName()+": GLContext.ContextSwitch: - setCurrent() - obj " + toHexString(cur.hashCode()) + ", ctx " + toHexString(cur.getHandle()));
+ }
+ }
+ currentContext.set(cur);
+ }
+
+ /**
+ * Destroys this OpenGL context and frees its associated
+ * resources.
+ * <p>
+ * The context may be current w/o recursion when calling <code>destroy()</code>,
+ * in which case this method destroys the context and releases the lock.
+ * </p>
+ */
+ public abstract void destroy();
+
+ /**
+ * Returns the implementing root GL instance of this GLContext's GL object,
+ * considering a wrapped pipelined hierarchy, see {@link GLBase#getDownstreamGL()}.
+ * @throws GLException if the root instance is not a GL implementation
+ * @see GLBase#getRootGL()
+ * @see GLBase#getDownstreamGL()
+ * @see #getGL()
+ * @see #setGL(GL)
+ */
+ public abstract GL getRootGL();
+
+ /**
+ * Returns the GL pipeline object for this GLContext.
+ *
+ * @return the aggregated GL instance, or null if this context was not yet made current.
+ */
+ public abstract GL getGL();
+
+ /**
+ * Sets the GL pipeline object for this GLContext.
+ *
+ * @return the set GL pipeline or null if not successful
+ */
+ public abstract GL setGL(GL gl);
+
+ /**
+ * Returns the underlying native OpenGL context handle
+ */
+ public final long getHandle() { return contextHandle; }
+
+ /**
+ * Indicates whether the underlying native OpenGL context has been created.
+ */
+ public final boolean isCreated() {
+ return 0 != contextHandle;
+ }
+
+ /**
+ * Returns the attached user object for the given name to this GLContext.
+ */
+ public final Object getAttachedObject(final String name) {
+ return attachedObjects.get(name);
+ }
+
+ /**
+ * Sets the attached user object for the given name to this GLContext.
+ * Returns the previously set object or null.
+ */
+ public final Object attachObject(final String name, final Object obj) {
+ return attachedObjects.put(name, obj);
+ }
+
+ public final Object detachObject(final String name) {
+ return attachedObjects.remove(name);
+ }
+
+ /**
+ * Classname, GL, GLDrawable
+ */
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getSimpleName());
+ sb.append(" [");
+ this.append(sb);
+ sb.append("] ");
+ return sb.toString();
+ }
+
+ public final StringBuilder append(final StringBuilder sb) {
+ sb.append("Version ").append(getGLVersion()).append(" [GL ").append(getGLVersionNumber()).append(", vendor ").append(getGLVendorVersionNumber());
+ sb.append("], options 0x");
+ sb.append(Integer.toHexString(ctxOptions));
+ sb.append(", this ");
+ sb.append(toHexString(hashCode()));
+ sb.append(", handle ");
+ sb.append(toHexString(contextHandle));
+ sb.append(", isShared "+isShared()+", ");
+ sb.append(getGL());
+ sb.append(",\n\t quirks: ");
+ if(null != glRendererQuirks) {
+ glRendererQuirks.toString(sb);
+ } else {
+ sb.append("n/a");
+ }
+ if(getGLDrawable()!=getGLReadDrawable()) {
+ sb.append(",\n\tRead Drawable : ");
+ sb.append(getGLReadDrawable());
+ sb.append(",\n\tWrite Drawable: ");
+ sb.append(getGLDrawable());
+ } else {
+ sb.append(",\n\tDrawable: ");
+ sb.append(getGLDrawable());
+ }
+ return sb;
+ }
+
+ /**
+ * Returns true if the specified OpenGL core- or extension-function can be
+ * successfully called using this GL context given the current host (OpenGL
+ * <i>client</i>) and display (OpenGL <i>server</i>) configuration.
+ *
+ * See {@link GL#isFunctionAvailable(String)} for more details.
+ *
+ * @param glFunctionName the name of the OpenGL function (e.g., use
+ * "glPolygonOffsetEXT" or "glPolygonOffset" to check if the {@link
+ * com.jogamp.opengl.GL#glPolygonOffset(float,float)} is available).
+ */
+ public abstract boolean isFunctionAvailable(String glFunctionName);
+
+ /**
+ * Returns true if the specified OpenGL extension can be
+ * successfully called using this GL context given the current host (OpenGL
+ * <i>client</i>) and display (OpenGL <i>server</i>) configuration.
+ *
+ * See {@link GL#isExtensionAvailable(String)} for more details.
+ *
+ * @param glExtensionName the name of the OpenGL extension (e.g.,
+ * "GL_VERTEX_PROGRAM_ARB").
+ */
+ public abstract boolean isExtensionAvailable(String glExtensionName);
+
+ /** Returns the number of platform extensions */
+ public abstract int getPlatformExtensionCount();
+
+ /** Returns a non-null (but possibly empty) string containing the
+ space-separated list of available platform-dependent (e.g., WGL,
+ GLX) extensions. Can only be called while this context is
+ current. */
+ public abstract String getPlatformExtensionsString();
+
+ /** Returns the number of OpenGL extensions */
+ public abstract int getGLExtensionCount();
+
+ /** Returns a non-null (but possibly empty) string containing the
+ space-separated list of available extensions.
+ Can only be called while this context is current.
+ This is equivalent to
+ {@link com.jogamp.opengl.GL#glGetString(int) glGetString}({@link com.jogamp.opengl.GL#GL_EXTENSIONS GL_EXTENSIONS})
+ */
+ public abstract String getGLExtensionsString();
+
+ /**
+ * @return Additional context creation flags, supported: {@link GLContext#CTX_OPTION_DEBUG}.
+ */
+ public abstract int getContextCreationFlags();
+
+ /**
+ * @param flags Additional context creation flags, supported: {@link GLContext#CTX_OPTION_DEBUG}.
+ * Unsupported flags are masked out.
+ * Only affects this context state if not created yet via {@link #makeCurrent()}.
+ * @see #enableGLDebugMessage(boolean)
+ * @see GLAutoDrawable#setContextCreationFlags(int)
+ */
+ public abstract void setContextCreationFlags(int flags);
+
+ /**
+ * Returns a valid OpenGL version string, ie<br>
+ * <pre>
+ * major.minor ([option]?[options,]*) - gl-version
+ * </pre><br>
+ *
+ * <ul>
+ * <li> options
+ * <ul>
+ * <li> <code>ES profile</code> ES profile</li>
+ * <li> <code>Compatibility profile</code> Compatibility profile including fixed function pipeline and deprecated functionality</li>
+ * <li> <code>Core profile</code> Core profile</li>
+ * <li> <code>forward</code> Forward profile excluding deprecated functionality</li>
+ * <li> <code>arb</code> refers to an ARB_create_context created context</li>
+ * <li> <code>debug</code> refers to a debug context</li>
+ * <li> <code>ES2 compatible</code> refers to an ES2 compatible implementation</li>
+ * <li> <code>software</code> refers to a software implementation of the rasterizer</li>
+ * <li> <code>hardware</code> refers to a hardware implementation of the rasterizer</li>
+ * </ul></li>
+ * <li> <i>gl-version</i> the GL_VERSION string</li>
+ * </ul>
+ *
+ * e.g.:
+ * <table border="0">
+ * <tr> <td></td> <td></td> </tr>
+ * <tr>
+ * <td>row 2, cell 1</td>
+ * <td>row 2, cell 2</td>
+ * </tr>
+ * </table>
+ *
+ * <table border="0">
+ * <tr><td></td> <td>ES2</td> <td><code>2.0 (ES profile, ES2 compatible, hardware) - 2.0 ES Profile</code></td></tr>
+ * <tr><td>ATI</td><td>GL2</td> <td><code>3.0 (Compatibility profile, arb, hardware) - 3.2.9704 Compatibility Profile Context</code></td></tr>
+ * <tr><td>ATI</td><td>GL3</td> <td><code>3.3 (Core profile, any, new, hardware) - 1.4 (3.2.9704 Compatibility Profile Context)</code></td></tr>
+ * <tr><td>ATI</td><td>GL3bc</td><td><code>3.3 (Compatibility profile, arb, hardware) - 1.4 (3.2.9704 Compatibility Profile Context)</code></td></tr>
+ * <tr><td>NV</td><td>GL2</td> <td><code>3.0 (Compatibility profile, arb, hardware) - 3.0.0 NVIDIA 195.36.07.03</code></td></tr>
+ * <tr><td>NV</td><td>GL3</td> <td><code>3.3 (Core profile, arb, hardware) - 3.3.0 NVIDIA 195.36.07.03</code></td></tr>
+ * <tr><td>NV</td><td>GL3bc</td> <td><code>3.3 (Compatibility profile, arb, hardware) - 3.3.0 NVIDIA 195.36.07.03</code></td></tr>
+ * <tr><td>NV</td><td>GL2</td> <td><code>3.0 (Compatibility profile, arb, ES2 compatible, hardware) - 3.0.0 NVIDIA 290.10</code></td></tr>
+ * </table>
+ */
+ public final String getGLVersion() {
+ return ctxVersionString;
+ }
+
+ /**
+ * Returns this context OpenGL version.
+ * @see #getGLSLVersionNumber()
+ **/
+ public final VersionNumber getGLVersionNumber() { return ctxVersion; }
+ /**
+ * Returns the vendor's version, i.e. version number at the end of <code>GL_VERSION</code> not being the GL version.
+ * <p>
+ * In case no such version exists within <code>GL_VERSION</code>,
+ * the {@link VersionNumberString#zeroVersion zero version} instance is returned.
+ * </p>
+ * <p>
+ * The vendor's version is usually the vendor's OpenGL driver version.
+ * </p>
+ */
+ public final VersionNumberString getGLVendorVersionNumber() { return ctxVendorVersion; }
+ public final boolean isGLCompatibilityProfile() { return ( 0 != ( CTX_PROFILE_COMPAT & ctxOptions ) ); }
+ public final boolean isGLCoreProfile() { return ( 0 != ( CTX_PROFILE_CORE & ctxOptions ) ); }
+ public final boolean isGLESProfile() { return ( 0 != ( CTX_PROFILE_ES & ctxOptions ) ); }
+ public final boolean isGLForwardCompatible() { return ( 0 != ( CTX_OPTION_FORWARD & ctxOptions ) ); }
+ public final boolean isGLDebugEnabled() { return ( 0 != ( CTX_OPTION_DEBUG & ctxOptions ) ); }
+ public final boolean isCreatedWithARBMethod() { return ( 0 != ( CTX_IS_ARB_CREATED & ctxOptions ) ); }
+
+ /**
+ * Returns the matching GLSL version number, queried by this context GL
+ * via {@link GL2ES2#GL_SHADING_LANGUAGE_VERSION} if &ge; ES2.0 or GL2.0,
+ * otherwise a static match is being utilized.
+ * <p>
+ * The context must have been current once,
+ * otherwise the {@link VersionNumberString#zeroVersion zero version} instance is returned.
+ * </p>
+ * <p>
+ * Examples w/ <code>major.minor</code>:
+ * <pre>
+ * 1.00 (ES 2.0), 3.00 (ES 3.0)
+ * 1.10 (GL 2.0), 1.20 (GL 2.1), 1.50 (GL 3.2),
+ * 3.30 (GL 3.3), 4.00 (GL 4.0), 4.10 (GL 4.1), 4.20 (GL 4.2)
+ * </pre >
+ * </p>
+ * <p>
+ * <i>Matching</i> could also refer to the maximum GLSL version usable by this context
+ * since <i>normal</i> GL implementations are capable of using a lower GLSL version as well.
+ * The latter is not true on OSX w/ a GL3 context.
+ * </p>
+ *
+ * @return GLSL version number if context has been made current at least once,
+ * otherwise the {@link VersionNumberString#zeroVersion zero version} instance is returned.
+ *
+ * @see #getGLVersionNumber()
+ */
+ public final VersionNumber getGLSLVersionNumber() {
+ return ctxGLSLVersion;
+ }
+
+ /**
+ * Returns the GLSL version string as to be used in a shader program, including a terminating newline '\n',
+ * i.e. for desktop
+ * <pre>
+ * #version 110
+ * ..
+ * #version 150 core
+ * #version 330 compatibility
+ * ...
+ * </pre>
+ * And for ES:
+ * <pre>
+ * #version 100
+ * #version 300 es
+ * ..
+ * </pre>
+ * <p>
+ * If context has not been made current yet, a string of zero length is returned.
+ * </p>
+ * @see #getGLSLVersionNumber()
+ */
+ public final String getGLSLVersionString() {
+ if( ctxGLSLVersion.isZero() ) {
+ return S_EMPTY;
+ }
+ final int minor = ctxGLSLVersion.getMinor();
+ final String profileOpt;
+ if( isGLES() ) {
+ profileOpt = ctxGLSLVersion.compareTo(Version3_0) >= 0 ? " es" : S_EMPTY;
+ } else if( isGLCoreProfile() ) {
+ profileOpt = ctxGLSLVersion.compareTo(Version1_50) >= 0 ? " core" : S_EMPTY;
+ } else if( isGLCompatibilityProfile() ) {
+ profileOpt = ctxGLSLVersion.compareTo(Version1_50) >= 0 ? " compatibility" : S_EMPTY;
+ } else {
+ throw new InternalError("Neither ES, Core nor Compat: "+this); // see validateProfileBits(..)
+ }
+ return "#version " + ctxGLSLVersion.getMajor() + ( minor < 10 ? "0"+minor : minor ) + profileOpt + "\n" ;
+ }
+
+ protected static final VersionNumber getStaticGLSLVersionNumber(final int glMajorVersion, final int glMinorVersion, final int ctxOptions) {
+ if( 0 != ( CTX_PROFILE_ES & ctxOptions ) ) {
+ if( 3 == glMajorVersion ) {
+ return Version3_0; // ES 3.0 -> GLSL 3.00
+ } else if( 2 == glMajorVersion ) {
+ return Version1_0; // ES 2.0 -> GLSL 1.00
+ }
+ } else if( 1 == glMajorVersion ) {
+ return Version1_10; // GL 1.x -> GLSL 1.10
+ } else if( 2 == glMajorVersion ) {
+ switch ( glMinorVersion ) {
+ case 0: return Version1_10; // GL 2.0 -> GLSL 1.10
+ default: return Version1_20; // GL 2.1 -> GLSL 1.20
+ }
+ } else if( 3 == glMajorVersion && 2 >= glMinorVersion ) {
+ switch ( glMinorVersion ) {
+ case 0: return Version1_30; // GL 3.0 -> GLSL 1.30
+ case 1: return Version1_40; // GL 3.1 -> GLSL 1.40
+ default: return Version1_50; // GL 3.2 -> GLSL 1.50
+ }
+ }
+ // The new default: GL >= 3.3, ES >= 3.0
+ return new VersionNumber(glMajorVersion, glMinorVersion * 10, 0); // GL M.N -> GLSL M.N
+ }
+
+ /**
+ * @return true if this context is an ES2 context or implements
+ * the extension <code>GL_ARB_ES3_compatibility</code> or <code>GL_ARB_ES2_compatibility</code>, otherwise false
+ */
+ public final boolean isGLES2Compatible() {
+ return 0 != ( ctxOptions & ( CTX_IMPL_ES3_COMPAT | CTX_IMPL_ES2_COMPAT ) ) ;
+ }
+
+ /**
+ * Return true if this context is an ES3 context or implements
+ * the extension <code>GL_ARB_ES3_compatibility</code>, otherwise false.
+ * <p>
+ * Includes [ GL &ge; 4.3, GL &ge; 3.1 w/ GL_ARB_ES3_compatibility and GLES3 ]
+ * </p>
+ */
+ public final boolean isGLES3Compatible() {
+ return 0 != ( ctxOptions & CTX_IMPL_ES3_COMPAT ) ;
+ }
+
+ /**
+ * @return true if impl. is a hardware rasterizer, otherwise false.
+ * @see #isHardwareRasterizer(AbstractGraphicsDevice, GLProfile)
+ * @see GLProfile#isHardwareRasterizer()
+ */
+ public final boolean isHardwareRasterizer() {
+ return 0 == ( ctxOptions & CTX_IMPL_ACCEL_SOFT ) ;
+ }
+
+ /**
+ * @return true if context supports GLSL, i.e. is either {@link #isGLES3()}, {@link #isGLES2()}, {@link #isGL3()} or {@link #isGL2()} <i>and</i> major-version > 1.
+ * @see GLProfile#hasGLSL()
+ */
+ public final boolean hasGLSL() {
+ return isGLES3() ||
+ isGLES2() ||
+ isGL3() ||
+ isGL2() && ctxVersion.getMajor()>1 ;
+ }
+
+ /**
+ * Returns <code>true</code> if basic FBO support is available, otherwise <code>false</code>.
+ * <p>
+ * Basic FBO is supported if the context is either GL-ES >= 2.0, GL >= 3.0 [core, compat] or implements the extensions
+ * <code>GL_ARB_ES2_compatibility</code>, <code>GL_ARB_framebuffer_object</code>, <code>GL_EXT_framebuffer_object</code> or <code>GL_OES_framebuffer_object</code>.
+ * </p>
+ * <p>
+ * Basic FBO support may only include one color attachment and no multisampling,
+ * as well as limited internal formats for renderbuffer.
+ * </p>
+ * @see #CTX_IMPL_FBO
+ */
+ public final boolean hasBasicFBOSupport() {
+ return 0 != ( ctxOptions & CTX_IMPL_FBO ) ;
+ }
+
+ /**
+ * Returns <code>true</code> if full FBO support is available, otherwise <code>false</code>.
+ * <p>
+ * Full FBO is supported if the context is either GL >= 3.0 [ES, core, compat] or implements the extensions
+ * <code>ARB_framebuffer_object</code>, or all of
+ * <code>EXT_framebuffer_object</code>, <code>EXT_framebuffer_multisample</code>,
+ * <code>EXT_framebuffer_blit</code>, <code>GL_EXT_packed_depth_stencil</code>.
+ * </p>
+ * <p>
+ * Full FBO support includes multiple color attachments and multisampling.
+ * </p>
+ */
+ public final boolean hasFullFBOSupport() {
+ return hasBasicFBOSupport() && !hasRendererQuirk(GLRendererQuirks.NoFullFBOSupport) &&
+ ( isGL3ES3() || // GL >= 3.0 [ES, core, compat]
+ isExtensionAvailable(GLExtensions.ARB_framebuffer_object) || // ARB_framebuffer_object
+ ( isExtensionAvailable(GLExtensions.EXT_framebuffer_object) && // All EXT_framebuffer_object*
+ isExtensionAvailable(GLExtensions.EXT_framebuffer_multisample) &&
+ isExtensionAvailable(GLExtensions.EXT_framebuffer_blit) &&
+ isExtensionAvailable(GLExtensions.EXT_packed_depth_stencil)
+ )
+ ) ;
+ }
+
+ /**
+ * Returns <code>true</code> if <code>OES_single_precision</code>, fp32, fixed function point (FFP) compatibility entry points available,
+ * otherwise <code>false</code>.
+ * @see #CTX_IMPL_FP32_COMPAT_API
+ */
+ public final boolean hasFP32CompatAPI() {
+ return 0 != ( ctxOptions & CTX_IMPL_FP32_COMPAT_API ) ;
+ }
+
+ /**
+ * Returns the maximum number of FBO RENDERBUFFER samples
+ * if {@link #hasFullFBOSupport() full FBO is supported}, otherwise false.
+ */
+ public final int getMaxRenderbufferSamples() {
+ if( hasFullFBOSupport() ) {
+ final GL gl = getGL();
+ final int[] val = new int[] { 0 } ;
+ try {
+ gl.glGetIntegerv(GL2ES3.GL_MAX_SAMPLES, val, 0);
+ final int glerr = gl.glGetError();
+ if(GL.GL_NO_ERROR == glerr) {
+ return val[0];
+ } else if(DEBUG) {
+ System.err.println("GLContext.getMaxRenderbufferSamples: GL_MAX_SAMPLES query GL Error 0x"+Integer.toHexString(glerr));
+ }
+ } catch (final GLException gle) { gle.printStackTrace(); }
+ }
+ return 0;
+ }
+
+ /** Note: The GL impl. may return a const value, ie {@link GLES2#isNPOTTextureAvailable()} always returns <code>true</code>. */
+ public boolean isNPOTTextureAvailable() {
+ return isGL3() || isGLES2Compatible() || isExtensionAvailable(GLExtensions.ARB_texture_non_power_of_two);
+ }
+
+ public boolean isTextureFormatBGRA8888Available() {
+ return isGL2GL3() ||
+ isExtensionAvailable(GLExtensions.EXT_texture_format_BGRA8888) ||
+ isExtensionAvailable(GLExtensions.IMG_texture_format_BGRA8888) ;
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GL4bc. <p>Includes [ GL4bc ].</p>
+ * @see GLProfile#isGL4bc()
+ */
+ public final boolean isGL4bc() {
+ return 0 != (ctxOptions & CTX_PROFILE_COMPAT) &&
+ ctxVersion.getMajor() >= 4;
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GL4. <p>Includes [ GL4bc, GL4 ].</p>
+ * @see GLProfile#isGL4()
+ */
+ public final boolean isGL4() {
+ return 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)) &&
+ ctxVersion.getMajor() >= 4;
+ }
+
+ /**
+ * Indicates whether this GLContext uses a GL4 core profile. <p>Includes [ GL4 ].</p>
+ */
+ public final boolean isGL4core() {
+ return 0 != ( ctxOptions & CTX_PROFILE_CORE ) &&
+ ctxVersion.getMajor() >= 4;
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GL3bc. <p>Includes [ GL4bc, GL3bc ].</p>
+ * @see GLProfile#isGL3bc()
+ */
+ public final boolean isGL3bc() {
+ return 0 != (ctxOptions & CTX_PROFILE_COMPAT) &&
+ ctxVersion.compareTo(Version3_1) >= 0 ;
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GL3. <p>Includes [ GL4bc, GL4, GL3bc, GL3 ].</p>
+ * @see GLProfile#isGL3()
+ */
+ public final boolean isGL3() {
+ return 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)) &&
+ ctxVersion.compareTo(Version3_1) >= 0 ;
+ }
+
+ /**
+ * Indicates whether this GLContext uses a GL3 core profile. <p>Includes [ GL4, GL3 ].</p>
+ */
+ public final boolean isGL3core() {
+ return 0 != ( ctxOptions & CTX_PROFILE_CORE ) &&
+ ctxVersion.compareTo(Version3_1) >= 0;
+ }
+
+ /**
+ * Indicates whether this GLContext uses a GL core profile. <p>Includes [ GL4, GL3, GLES3, GLES2 ].</p>
+ */
+ public final boolean isGLcore() {
+ return ( 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() >= 2 ) ||
+ ( 0 != ( ctxOptions & CTX_PROFILE_CORE ) &&
+ ctxVersion.compareTo(Version3_1) >= 0
+ ) ;
+ }
+
+ /**
+ * Indicates whether this GLContext allows CPU data sourcing (indices, vertices ..) as opposed to using a GPU buffer source (VBO),
+ * e.g. {@link GL2#glDrawElements(int, int, int, java.nio.Buffer)}.
+ * <p>Includes [GL2ES1, GLES2] == [ GL4bc, GL3bc, GL2, GLES1, GL2ES1, GLES2 ].</p>
+ * <p>See Bug 852 - https://jogamp.org/bugzilla/show_bug.cgi?id=852 </p>
+ */
+ public final boolean isCPUDataSourcingAvail() {
+ return isGL2ES1() || isGLES2();
+ }
+
+ /**
+ * Indicates whether this GLContext's native profile does not implement a <i>default vertex array object</i> (VAO),
+ * starting w/ OpenGL 3.1 core.
+ * <p>Includes [ GL4, GL3 ].</p>
+ * <pre>
+ Due to GL 3.1 core spec: E.1. DEPRECATED AND REMOVED FEATURES (p 296),
+ GL 3.2 core spec: E.2. DEPRECATED AND REMOVED FEATURES (p 331)
+ there is no more default VAO buffer 0 bound, hence generating and binding one
+ to avoid INVALID_OPERATION at VertexAttribPointer.
+ More clear is GL 4.3 core spec: 10.4 (p 307).
+ * </pre>
+ * <pre>
+ ES 3.x is <i>not</i> included here.
+ Due to it's ES 2.0 backward compatibility it still supports the following features:
+ <i>client side vertex arrays</i>
+ <i>default vertex array object</i>
+
+ Binding a custom VAO with ES 3.0 would cause <i>client side vertex arrays</i> via {@link GL2ES1#glVertexPointer(int, int, int, java.nio.Buffer) glVertexPointer}
+ to produce <code>GL_INVALID_OPERATION</code>.
+
+ However, they are marked <i>deprecated</i>:
+ GL ES 3.0 spec F.1. Legacy Features (p 322).
+ GL ES 3.1 spec F.1. Legacy Features (p 454).
+ * </pre>
+ * <p>
+ * If no default VAO is implemented in the native OpenGL profile,
+ * an own default VAO is being used, see {@link #getDefaultVAO()}.
+ * </p>
+ * @see #getDefaultVAO()
+ */
+ public final boolean hasNoDefaultVAO() {
+ return // ES 3.x not included, see above. ( 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() >= 3 ) ||
+ ( 0 != ( ctxOptions & CTX_IS_ARB_CREATED ) &&
+ 0 != ( ctxOptions & CTX_PROFILE_CORE ) &&
+ ctxVersion.compareTo(Version3_1) >= 0
+ ) ;
+ }
+
+ /**
+ * If this GLContext does not implement a default VAO, see {@link #hasNoDefaultVAO()},
+ * an <i>own default VAO</i> will be created and bound at context creation.
+ * <p>
+ * If this GLContext does implement a default VAO, i.e. {@link #hasNoDefaultVAO()}
+ * returns <code>false</code>, this method returns <code>0</code>.
+ * </p>
+ * <p>
+ * Otherwise this method returns the VAO object name
+ * representing this GLContext's <i>own default VAO</i>.
+ * </p>
+ * @see #hasNoDefaultVAO()
+ */
+ public abstract int getDefaultVAO();
+
+ /**
+ * Indicates whether this GLContext is capable of GL2. <p>Includes [ GL4bc, GL3bc, GL2 ].</p>
+ * @see GLProfile#isGL2()
+ */
+ public final boolean isGL2() {
+ return 0 != ( ctxOptions & CTX_PROFILE_COMPAT ) && ctxVersion.getMajor()>=1 ;
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GL2GL3. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GL2, GL2GL3 ].</p>
+ * @see GLProfile#isGL2GL3()
+ */
+ public final boolean isGL2GL3() {
+ return isGL2() || isGL3();
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GLES1. <p>Includes [ GLES1 ].</p>
+ * @see GLProfile#isGLES1()
+ */
+ public final boolean isGLES1() {
+ return 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() == 1 ;
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GLES2. <p>Includes [ GLES2, GLES3 ].</p>
+ * @see GLProfile#isGLES2()
+ */
+ public final boolean isGLES2() {
+ if( 0 != ( ctxOptions & CTX_PROFILE_ES ) ) {
+ final int major = ctxVersion.getMajor();
+ return 2 == major || 3 == major;
+ }
+ return false;
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GLES3. <p>Includes [ GLES3 ].</p>
+ * @see GLProfile#isGLES3()
+ */
+ public final boolean isGLES3() {
+ return 0 != ( ctxOptions & CTX_PROFILE_ES ) && ctxVersion.getMajor() == 3 ;
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GLES. <p>Includes [ GLES3, GLES1, GLES2 ].</p>
+ * @see GLProfile#isGLES()
+ */
+ public final boolean isGLES() {
+ return 0 != ( CTX_PROFILE_ES & ctxOptions ) ;
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GL2ES1. <p>Includes [ GL4bc, GL3bc, GL2, GLES1, GL2ES1 ].</p>
+ * @see GLProfile#isGL2ES1()
+ */
+ public final boolean isGL2ES1() {
+ return isGLES1() || isGL2();
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GL2ES2. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GLES3, GL2, GL2GL3, GL2ES2, GLES2 ].</p>
+ * @see GLProfile#isGL2ES2()
+ */
+ public final boolean isGL2ES2() {
+ return isGLES2() || isGL2GL3();
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GL2ES3. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GLES3, GL3ES3, GL2, GL2GL3 ].</p>
+ * @see GLProfile#isGL2ES3()
+ * @see #isGL3ES3()
+ * @see #isGL2GL3()
+ */
+ public final boolean isGL2ES3() {
+ return isGL3ES3() || isGL2GL3();
+ }
+
+ /**
+ * Indicates whether this GLContext is capable of GL3ES3. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GLES3 ].</p>
+ * @see GLProfile#isGL3ES3()
+ */
+ public final boolean isGL3ES3() {
+ return isGL4ES3() || isGL3();
+ }
+
+ /**
+ * Returns true if this profile is capable of GL4ES3, i.e. if {@link #isGLES3Compatible()} returns true.
+ * <p>Includes [ GL &ge; 4.3, GL &ge; 3.1 w/ GL_ARB_ES3_compatibility and GLES3 ]</p>
+ * @see GLProfile#isGL4ES3()
+ */
+ public final boolean isGL4ES3() {
+ return isGLES3Compatible() ;
+ }
+
+ /**
+ * Set the swap interval of the current context and attached drawable.
+ * @param interval Should be &ge; 0. 0 disables the vertical synchronization,
+ * where &ge; 1 is the number of vertical refreshes before a swap buffer occurs.
+ * A value &lt; 0 is ignored.
+ * @return true if the operation was successful, otherwise false
+ *
+ * @throws GLException if the context is not current.
+ */
+ public final boolean setSwapInterval(final int interval) throws GLException {
+ validateCurrent();
+ if(0<=interval) {
+ if( !drawableRetargeted || !hasRendererQuirk(GLRendererQuirks.NoSetSwapIntervalPostRetarget) ) {
+ if( setSwapIntervalImpl(interval) ) {
+ currentSwapInterval = interval;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ protected boolean setSwapIntervalImpl(final int interval) {
+ return false;
+ }
+ /** Return the current swap interval.
+ * <p>
+ * If the context has not been made current at all,
+ * the default value <code>-1</code> is returned.
+ * </p>
+ * <p>
+ * For a valid context the default value is <code>1</code>
+ * in case of an EGL based profile (ES1 or ES2) and <code>-1</code>
+ * (undefined) for desktop.
+ * </p>
+ */
+ public final int getSwapInterval() {
+ return currentSwapInterval;
+ }
+ protected final void setDefaultSwapInterval() {
+ if(this.isGLES()) {
+ currentSwapInterval = 1;
+ } else {
+ currentSwapInterval = -1;
+ }
+ }
+
+ public final boolean queryMaxSwapGroups(final int[] maxGroups, final int maxGroups_offset,
+ final int[] maxBarriers, final int maxBarriers_offset) {
+ validateCurrent();
+ return queryMaxSwapGroupsImpl(maxGroups, maxGroups_offset, maxBarriers, maxBarriers_offset);
+ }
+ protected boolean queryMaxSwapGroupsImpl(final int[] maxGroups, final int maxGroups_offset,
+ final int[] maxBarriers, final int maxBarriers_offset) { return false; }
+ public final boolean joinSwapGroup(final int group) {
+ validateCurrent();
+ return joinSwapGroupImpl(group);
+ }
+ protected boolean joinSwapGroupImpl(final int group) { /** nop per default .. **/ return false; }
+ protected int currentSwapGroup = -1; // default: not set yet ..
+ public int getSwapGroup() {
+ return currentSwapGroup;
+ }
+ public final boolean bindSwapBarrier(final int group, final int barrier) {
+ validateCurrent();
+ return bindSwapBarrierImpl(group, barrier);
+ }
+ protected boolean bindSwapBarrierImpl(final int group, final int barrier) { /** nop per default .. **/ return false; }
+
+ /**
+ * Return the framebuffer name bound to this context,
+ * see {@link GL#glBindFramebuffer(int, int)}.
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
+ */
+ public abstract int getBoundFramebuffer(int target);
+
+ /**
+ * Return the default draw framebuffer name.
+ * <p>
+ * May differ from it's default <code>zero</code>
+ * in case an framebuffer object ({@link com.jogamp.opengl.FBObject}) based drawable
+ * is being used.
+ * </p>
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
+ */
+ public abstract int getDefaultDrawFramebuffer();
+
+ /**
+ * Return the default read framebuffer name.
+ * <p>
+ * May differ from it's default <code>zero</code>
+ * in case an framebuffer object ({@link com.jogamp.opengl.FBObject}) based drawable
+ * is being used.
+ * </p>
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
+ */
+ public abstract int getDefaultReadFramebuffer();
+
+ /**
+ * Returns the default color buffer within the current bound
+ * {@link #getDefaultReadFramebuffer()}, i.e. GL_READ_FRAMEBUFFER​,
+ * which will be used as the source for pixel reading commands,
+ * like {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer) glReadPixels} etc.
+ * <p>
+ * For offscreen framebuffer objects this is {@link GL#GL_COLOR_ATTACHMENT0},
+ * otherwise this is {@link GL#GL_FRONT} for single buffer configurations
+ * and {@link GL#GL_BACK} for double buffer configurations.
+ * </p>
+ * <p>
+ * Note-1: Neither ES1 nor ES2 supports selecting the read buffer via glReadBuffer
+ * and {@link GL#GL_BACK} is the default.
+ * </p>
+ * <p>
+ * Note-2: ES3 only supports {@link GL#GL_BACK}, {@link GL#GL_NONE} or {@link GL#GL_COLOR_ATTACHMENT0}+i
+ * </p>
+ * <p>
+ * Note-3: See {@link com.jogamp.opengl.util.GLDrawableUtil#swapBuffersBeforeRead(GLCapabilitiesImmutable) swapBuffersBeforeRead}
+ * for read-pixels and swap-buffers implications.
+ * </p>
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
+ */
+ public abstract int getDefaultReadBuffer();
+
+ /**
+ * Get the default pixel data type, as required by e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer)}.
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
+ */
+ public abstract int getDefaultPixelDataType();
+
+ /**
+ * Get the default pixel data format, as required by e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer)}.
+ * <p>
+ * Method is only thread-safe while context is {@link #makeCurrent() made current}.
+ * </p>
+ */
+ public abstract int getDefaultPixelDataFormat();
+
+ /**
+ * @return The extension implementing the GLDebugOutput feature,
+ * either {@link GLExtensions#ARB_debug_output} or {@link GLExtensions#AMD_debug_output}.
+ * If unavailable or called before initialized via {@link #makeCurrent()}, <i>null</i> is returned.
+ */
+ public abstract String getGLDebugMessageExtension();
+
+ /**
+ * @return the current synchronous debug behavior, set via {@link #setGLDebugSynchronous(boolean)}.
+ */
+ public abstract boolean isGLDebugSynchronous();
+
+ /**
+ * Enables or disables the synchronous debug behavior via
+ * {@link GL2GL3#GL_DEBUG_OUTPUT_SYNCHRONOUS glEnable/glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS)},
+ * if extension is {@link GLExtensions#ARB_debug_output}.
+ * There is no equivalent for {@link GLExtensions#AMD_debug_output}.
+ * <p> The default is <code>true</code>, ie {@link GL2GL3#GL_DEBUG_OUTPUT_SYNCHRONOUS}.</p>
+ * @link {@link #isGLDebugSynchronous()}
+ */
+ public abstract void setGLDebugSynchronous(boolean synchronous);
+
+ /**
+ * @return true if the GLDebugOutput feature is enabled or not.
+ */
+ public abstract boolean isGLDebugMessageEnabled();
+
+ /**
+ * Enables or disables the GLDebugOutput feature of extension {@link GLExtensions#ARB_debug_output}
+ * or {@link GLExtensions#AMD_debug_output}, if available.
+ *
+ * <p>To enable the GLDebugOutput feature {@link #enableGLDebugMessage(boolean) enableGLDebugMessage(true)}
+ * or {@link #setContextCreationFlags(int) setContextCreationFlags}({@link GLContext#CTX_OPTION_DEBUG})
+ * shall be called <b>before</b> context creation via {@link #makeCurrent()}!</p>
+ *
+ * <p>In case {@link GLAutoDrawable} are being used,
+ * {@link GLAutoDrawable#setContextCreationFlags(int) glAutoDrawable.setContextCreationFlags}({@link GLContext#CTX_OPTION_DEBUG})
+ * shall be issued before context creation via {@link #makeCurrent()}!</p>
+ *
+ * <p>After context creation, the GLDebugOutput feature may be enabled or disabled at any time using this method.</p>
+ *
+ * @param enable If true enables, otherwise disables the GLDebugOutput feature.
+ *
+ * @throws GLException if this context is not current or GLDebugOutput registration failed (enable)
+ *
+ * @see #setContextCreationFlags(int)
+ * @see #addGLDebugListener(GLDebugListener)
+ * @see GLAutoDrawable#setContextCreationFlags(int)
+ */
+ public abstract void enableGLDebugMessage(boolean enable) throws GLException;
+
+ /**
+ * Add {@link GLDebugListener}.<br>
+ *
+ * @param listener {@link GLDebugListener} handling {@link GLDebugMessage}s
+ * @see #enableGLDebugMessage(boolean)
+ * @see #removeGLDebugListener(GLDebugListener)
+ */
+ public abstract void addGLDebugListener(GLDebugListener listener);
+
+ /**
+ * Remove {@link GLDebugListener}.<br>
+ *
+ * @param listener {@link GLDebugListener} handling {@link GLDebugMessage}s
+ * @see #enableGLDebugMessage(boolean)
+ * @see #addGLDebugListener(GLDebugListener)
+ */
+ public abstract void removeGLDebugListener(GLDebugListener listener);
+
+ /**
+ * Generic entry for {@link GL2GL3#glDebugMessageControl(int, int, int, int, IntBuffer, boolean)}
+ * and {@link GL2GL3#glDebugMessageEnableAMD(int, int, int, IntBuffer, boolean)} of the GLDebugOutput feature.
+ * @see #enableGLDebugMessage(boolean)
+ */
+ public abstract void glDebugMessageControl(int source, int type, int severity, int count, IntBuffer ids, boolean enabled);
+
+ /**
+ * Generic entry for {@link GL2GL3#glDebugMessageControl(int, int, int, int, int[], int, boolean)}
+ * and {@link GL2GL3#glDebugMessageEnableAMD(int, int, int, int[], int, boolean)} of the GLDebugOutput feature.
+ * @see #enableGLDebugMessage(boolean)
+ */
+ public abstract void glDebugMessageControl(int source, int type, int severity, int count, int[] ids, int ids_offset, boolean enabled);
+
+ /**
+ * Generic entry for {@link GL2GL3#glDebugMessageInsert(int, int, int, int, int, String)}
+ * and {@link GL2GL3#glDebugMessageInsertAMD(int, int, int, int, String)} of the GLDebugOutput feature.
+ * @see #enableGLDebugMessage(boolean)
+ */
+ public abstract void glDebugMessageInsert(int source, int type, int id, int severity, String buf);
+
+ public static final int GL_VERSIONS[][] = {
+ /* 0.*/ { -1 },
+ /* 1.*/ { 0, 1, 2, 3, 4, 5 },
+ /* 2.*/ { 0, 1 },
+ /* 3.*/ { 0, 1, 2, 3 },
+ /* 4.*/ { 0, 1, 2, 3, 4, 5 } };
+
+ public static final int ES_VERSIONS[][] = {
+ /* 0.*/ { -1 },
+ /* 1.*/ { 0, 1 },
+ /* 2.*/ { 0 },
+ /* 3.*/ { 0, 1 } };
+
+ public static final int getMaxMajor(final int ctxProfile) {
+ return ( 0 != ( CTX_PROFILE_ES & ctxProfile ) ) ? ES_VERSIONS.length-1 : GL_VERSIONS.length-1;
+ }
+
+ public static final int getMaxMinor(final int ctxProfile, final int major) {
+ if( 1>major ) {
+ return -1;
+ }
+ if( ( 0 != ( CTX_PROFILE_ES & ctxProfile ) ) ) {
+ if( major>=ES_VERSIONS.length ) return -1;
+ return ES_VERSIONS[major].length-1;
+ } else {
+ if( major>=GL_VERSIONS.length ) return -1;
+ return GL_VERSIONS[major].length-1;
+ }
+ }
+
+ /**
+ * Returns true, if the major.minor is not inferior to the lowest
+ * valid version and does not exceed the highest known major number by more than one.
+ * <p>
+ * The minor version number is ignored by the upper limit validation
+ * and the major version number may exceed by one.
+ * </p>
+ * <p>
+ * The upper limit check is relaxed since we don't want to cut-off
+ * unforseen new GL version since the release of JOGL.
+ * </p>
+ * <p>
+ * Hence it is important to iterate through GL version from the upper limit
+ * and {@link #decrementGLVersion(int, int[], int[])} until invalid.
+ * </p>
+ */
+ public static final boolean isValidGLVersion(final int ctxProfile, final int major, final int minor) {
+ if( 1>major || 0>minor ) {
+ return false;
+ }
+ if( 0 != ( CTX_PROFILE_ES & ctxProfile ) ) {
+ if( major >= ES_VERSIONS.length + 1 ) return false;
+ } else {
+ if( major>=GL_VERSIONS.length + 1 ) return false;
+ }
+ return true;
+ }
+
+ /**
+ * Clip the given GL version to the maximum known valid version if exceeding.
+ * @return true if clipped, i.e. given value exceeds maximum, otherwise false.
+ */
+ public static final boolean clipGLVersion(final int ctxProfile, final int major[], final int minor[]) {
+ final int m = major[0];
+ final int n = minor[0];
+
+ if( 0 != ( CTX_PROFILE_ES & ctxProfile ) ) {
+ if( m >= ES_VERSIONS.length ) {
+ major[0] = ES_VERSIONS.length - 1;
+ minor[0] = ES_VERSIONS[major[0]].length - 1;
+ return true;
+ }
+ if( n >= ES_VERSIONS[m].length ) {
+ minor[0] = ES_VERSIONS[m].length - 1;
+ return true;
+ }
+ } else if( m >= GL_VERSIONS.length ) { // !isES
+ major[0] = GL_VERSIONS.length - 1;
+ minor[0] = GL_VERSIONS[major[0]].length - 1;
+ return true;
+ } else if( n >= GL_VERSIONS[m].length ) { // !isES
+ minor[0] = GL_VERSIONS[m].length - 1;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Decrement the given GL version by one
+ * and return true if still valid, otherwise false.
+ * <p>
+ * If the given version exceeds the maximum known valid version,
+ * it is {@link #clipGLVersion(int, int[], int[]) clipped} and
+ * true is returned.
+ * </p>
+ *
+ * @param ctxProfile
+ * @param major
+ * @param minor
+ * @return
+ */
+ public static final boolean decrementGLVersion(final int ctxProfile, final int major[], final int minor[]) {
+ if( !clipGLVersion(ctxProfile, major, minor) ) {
+ int m = major[0];
+ int n = minor[0] - 1;
+ if(n < 0) {
+ if( 0 != ( CTX_PROFILE_ES & ctxProfile ) ) {
+ if( m >= 3 ) {
+ m -= 1;
+ } else {
+ m = 0; // major decr [1,2] -> 0
+ }
+ n = ES_VERSIONS[m].length-1;
+ } else {
+ m -= 1;
+ n = GL_VERSIONS[m].length-1;
+ }
+ }
+ if( !isValidGLVersion(ctxProfile, m, n) ) {
+ return false;
+ }
+ major[0]=m;
+ minor[0]=n;
+ }
+ return true;
+ }
+
+ protected static int composeBits(final int a8, final int b8, final int c16) {
+ return ( ( a8 & 0x000000FF ) << 24 ) |
+ ( ( b8 & 0x000000FF ) << 16 ) |
+ ( ( c16 & 0x0000FFFF ) ) ;
+ }
+
+ private static void validateProfileBits(final int bits, final String argName) {
+ int num = 0;
+ if( 0 != ( CTX_PROFILE_COMPAT & bits ) ) { num++; }
+ if( 0 != ( CTX_PROFILE_CORE & bits ) ) { num++; }
+ if( 0 != ( CTX_PROFILE_ES & bits ) ) { num++; }
+ if(1!=num) {
+ throw new GLException("Internal Error: "+argName+": 1 != num-profiles: "+num);
+ }
+ }
+
+ //
+ // version mapping
+ //
+
+ /**
+ * @see #getDeviceVersionAvailableKey(com.jogamp.nativewindow.AbstractGraphicsDevice, int, int)
+ */
+ protected static final IdentityHashMap<String, Integer> deviceVersionAvailable = new IdentityHashMap<String, Integer>();
+
+ /**
+ * @see #getUniqueDeviceString(com.jogamp.nativewindow.AbstractGraphicsDevice)
+ */
+ private static final IdentityHashMap<String, String> deviceVersionsAvailableSet = new IdentityHashMap<String, String>();
+
+ /** clears the device/context mappings as well as the GL/GLX proc address tables. */
+ protected static void shutdown() {
+ deviceVersionAvailable.clear();
+ deviceVersionsAvailableSet.clear();
+ GLContextImpl.shutdownImpl(); // well ..
+ }
+
+ protected static boolean getAvailableGLVersionsSet(final AbstractGraphicsDevice device) {
+ synchronized ( deviceVersionsAvailableSet ) {
+ return deviceVersionsAvailableSet.containsKey(device.getUniqueID());
+ }
+ }
+
+ protected static void setAvailableGLVersionsSet(final AbstractGraphicsDevice device, final boolean set) {
+ synchronized ( deviceVersionsAvailableSet ) {
+ final String devKey = device.getUniqueID();
+ if( set ) {
+ deviceVersionsAvailableSet.put(devKey, devKey);
+ } else {
+ deviceVersionsAvailableSet.remove(devKey);
+ }
+ if (DEBUG) {
+ System.err.println(getThreadName() + ": createContextARB: SET mappedVersionsAvailableSet "+devKey);
+ System.err.println(GLContext.dumpAvailableGLVersions(null).toString());
+ }
+ }
+ }
+
+ /**
+ * Returns a unique String object using {@link String#intern()} for the given arguments,
+ * which object reference itself can be used as a key.
+ */
+ protected static String getDeviceVersionAvailableKey(final AbstractGraphicsDevice device, final int major, final int profile) {
+ final String r = device.getUniqueID() + "-" + toHexString(composeBits(major, profile, 0));
+ return r.intern();
+ }
+
+ /**
+ * Called by {@link jogamp.opengl.GLContextImpl#createContextARBMapVersionsAvailable(int,int)} not intended to be used by
+ * implementations. However, if {@link jogamp.opengl.GLContextImpl#createContextARB(long, boolean)} is not being used within
+ * {@link com.jogamp.opengl.GLDrawableFactory#getOrCreateSharedContext(com.jogamp.nativewindow.AbstractGraphicsDevice)},
+ * GLProfile has to map the available versions.
+ *
+ * @param reqMajor Key Value either 1, 2, 3 or 4
+ * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES}
+ * @return the old mapped value
+ *
+ * @see #createContextARBMapVersionsAvailable
+ */
+ protected static Integer mapAvailableGLVersion(final AbstractGraphicsDevice device,
+ final int reqMajor, final int profile, final int resMajor, final int resMinor, int resCtp)
+ {
+ validateProfileBits(profile, "profile");
+ validateProfileBits(resCtp, "resCtp");
+
+ if(FORCE_NO_FBO_SUPPORT) {
+ resCtp &= ~CTX_IMPL_FBO ;
+ }
+ if(DEBUG) {
+ System.err.println("GLContext.mapAvailableGLVersion: "+device+": "+getGLVersion(reqMajor, 0, profile, null)+" -> "+getGLVersion(resMajor, resMinor, resCtp, null));
+ // Thread.dumpStack();
+ }
+ final String objectKey = getDeviceVersionAvailableKey(device, reqMajor, profile);
+ final Integer val = Integer.valueOf(composeBits(resMajor, resMinor, resCtp));
+ synchronized(deviceVersionAvailable) {
+ return deviceVersionAvailable.put( objectKey, val );
+ }
+ }
+
+ protected static StringBuilder dumpAvailableGLVersions(StringBuilder sb) {
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
+ synchronized(deviceVersionAvailable) {
+ final Set<String> keys = deviceVersionAvailable.keySet();
+ boolean needsSeparator = false;
+ for(final Iterator<String> i = keys.iterator(); i.hasNext(); ) {
+ if(needsSeparator) {
+ sb.append(Platform.getNewline());
+ }
+ final String key = i.next();
+ sb.append(key).append(": ");
+ final Integer valI = deviceVersionAvailable.get(key);
+ if(null != valI) {
+ final int bits32 = valI.intValue();
+ final int major = ( bits32 & 0xFF000000 ) >>> 24 ;
+ final int minor = ( bits32 & 0x00FF0000 ) >>> 16 ;
+ final int ctp = ( bits32 & 0x0000FFFF ) ;
+ sb.append(GLContext.getGLVersion(major, minor, ctp, null));
+ } else {
+ sb.append("n/a");
+ }
+ needsSeparator = true;
+ }
+ }
+ return sb;
+ }
+
+ /**
+ * @param device the device to request whether the profile is available for
+ * @param reqMajor Key Value either 1, 2, 3 or 4
+ * @param reqProfile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES}
+ * @return the available GL version as encoded with {@link #composeBits(int, int, int), otherwise <code>null</code>
+ */
+ protected static Integer getAvailableGLVersion(final AbstractGraphicsDevice device, final int reqMajor, final int reqProfile) {
+ final String objectKey = getDeviceVersionAvailableKey(device, reqMajor, reqProfile);
+ Integer val;
+ synchronized(deviceVersionAvailable) {
+ val = deviceVersionAvailable.get( objectKey );
+ }
+ return val;
+ }
+
+ /**
+ * @param reqMajor Key Value either 1, 2, 3 or 4
+ * @param reqProfile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES}
+ * @param major if not null, returns the used major version
+ * @param minor if not null, returns the used minor version
+ * @param ctp if not null, returns the used context profile
+ */
+ protected static boolean getAvailableGLVersion(final AbstractGraphicsDevice device, final int reqMajor, final int reqProfile,
+ final int[] major, final int minor[], final int ctp[]) {
+
+ final Integer valI = getAvailableGLVersion(device, reqMajor, reqProfile);
+ if(null==valI) {
+ return false;
+ }
+
+ final int bits32 = valI.intValue();
+
+ if(null!=major) {
+ major[0] = ( bits32 & 0xFF000000 ) >>> 24 ;
+ }
+ if(null!=minor) {
+ minor[0] = ( bits32 & 0x00FF0000 ) >>> 16 ;
+ }
+ if(null!=ctp) {
+ ctp[0] = ( bits32 & 0x0000FFFF ) ;
+ }
+ return true;
+ }
+
+ /**
+ * returns the highest GLProfile string regarding the implementation version and context profile bits.
+ * @throws GLException if version and context profile bits could not be mapped to a GLProfile
+ */
+ protected static String getGLProfile(final int major, final int minor, final int ctp)
+ throws GLException {
+ if(0 != ( CTX_PROFILE_COMPAT & ctp )) {
+ if(major >= 4) { return GLProfile.GL4bc; }
+ else if(major == 3 && minor >= 1) { return GLProfile.GL3bc; }
+ else { return GLProfile.GL2; }
+ } else if(0 != ( CTX_PROFILE_CORE & ctp )) {
+ if(major >= 4) { return GLProfile.GL4; }
+ else if(major == 3 && minor >= 1) { return GLProfile.GL3; }
+ } else if(0 != ( CTX_PROFILE_ES & ctp )) {
+ if(major == 3) { return GLProfile.GLES3; }
+ else if(major == 2) { return GLProfile.GLES2; }
+ else if(major == 1) { return GLProfile.GLES1; }
+ }
+ throw new GLException("Unhandled OpenGL version/profile: "+GLContext.getGLVersion(major, minor, ctp, null));
+ }
+
+ /**
+ * Returns the GLProfile's major version number at reqMajorCTP[0] and it's context property (CTP) at reqMajorCTP[1] for availability mapping request.
+ */
+ protected static final void getRequestMajorAndCompat(final GLProfile glp, final int[/*2*/] reqMajorCTP) {
+ final GLProfile glpImpl = glp.getImpl();
+ if( glpImpl.isGL4() ) {
+ reqMajorCTP[0]=4;
+ } else if ( glpImpl.isGL3() || glpImpl.isGLES3() ) {
+ reqMajorCTP[0]=3;
+ } else if (glpImpl.isGLES1()) {
+ reqMajorCTP[0]=1;
+ } else /* if (glpImpl.isGL2() || glpImpl.isGLES2()) */ {
+ reqMajorCTP[0]=2;
+ }
+ if( glpImpl.isGLES() ) {
+ reqMajorCTP[1]=CTX_PROFILE_ES;
+ } else if( glpImpl.isGL2() ) { // incl GL3bc and GL4bc
+ reqMajorCTP[1]=CTX_PROFILE_COMPAT;
+ } else {
+ reqMajorCTP[1]=CTX_PROFILE_CORE;
+ }
+ }
+
+ /**
+ * @param device the device the context profile is being requested for
+ * @param GLProfile the GLProfile the context profile is being requested for
+ * @return the GLProfile's context property (CTP) if available, otherwise <code>0</code>
+ */
+ protected static final int getAvailableContextProperties(final AbstractGraphicsDevice device, final GLProfile glp) {
+ final int[] reqMajorCTP = new int[] { 0, 0 };
+ getRequestMajorAndCompat(glp, reqMajorCTP);
+
+ final int _major[] = { 0 };
+ final int _minor[] = { 0 };
+ final int _ctp[] = { 0 };
+ if( GLContext.getAvailableGLVersion(device, reqMajorCTP[0], reqMajorCTP[1], _major, _minor, _ctp)) {
+ return _ctp[0];
+ }
+ return 0; // n/a
+ }
+
+ /**
+ * @param device the device the profile is being requested
+ * @param major Key Value either 1, 2, 3 or 4
+ * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES}
+ * @return the highest GLProfile for the device regarding availability, version and profile bits.
+ */
+ protected static GLProfile getAvailableGLProfile(final AbstractGraphicsDevice device, final int reqMajor, final int reqProfile)
+ throws GLException {
+ final String glpName = getAvailableGLProfileName(device, reqMajor, reqProfile);
+ return null != glpName ? GLProfile.get(device, glpName) : null;
+ }
+
+ /**
+ * @param device the device the profile is being requested
+ * @param major Key Value either 1, 2, 3 or 4
+ * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES}
+ * @return the highest GLProfile name for the device regarding availability, version and profile bits.
+ */
+ /* package */ static String getAvailableGLProfileName(final AbstractGraphicsDevice device, final int reqMajor, final int reqProfile)
+ throws GLException {
+ final int major[] = { 0 };
+ final int minor[] = { 0 };
+ final int ctp[] = { 0 };
+ if(GLContext.getAvailableGLVersion(device, reqMajor, reqProfile, major, minor, ctp)) {
+ return GLContext.getGLProfile(major[0], minor[0], ctp[0]);
+ }
+ return null;
+ }
+
+ /**
+ * @param device the device the profile is being requested
+ * @param major Key Value either 1, 2, 3 or 4
+ * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES}
+ */
+ protected static String getAvailableGLVersionAsString(final AbstractGraphicsDevice device, final int major, final int profile) {
+ final int _major[] = { 0 };
+ final int _minor[] = { 0 };
+ final int _ctp[] = { 0 };
+ if(getAvailableGLVersion(device, major, profile, _major, _minor, _ctp)) {
+ return getGLVersion(_major[0], _minor[0], _ctp[0], null);
+ }
+ return null;
+ }
+
+ /**
+ * Returns true if it is possible to create an <i>framebuffer object</i> (FBO).
+ * <p>
+ * FBO feature is implemented in OpenGL, hence it is {@link GLProfile} dependent.
+ * </p>
+ * <p>
+ * FBO support is queried as described in {@link #hasBasicFBOSupport()}.
+ * </p>
+ *
+ * @param device the device to request whether FBO is available for
+ * @param glp {@link GLProfile} to check for FBO capabilities
+ * @see GLContext#hasBasicFBOSupport()
+ */
+ public static final boolean isFBOAvailable(final AbstractGraphicsDevice device, final GLProfile glp) {
+ return 0 != ( CTX_IMPL_FBO & getAvailableContextProperties(device, glp) );
+ }
+
+ /**
+ * @return <code>1</code> if using a hardware rasterizer, <code>0</code> if using a software rasterizer and <code>-1</code> if not determined yet.
+ * @see GLContext#isHardwareRasterizer()
+ * @see GLProfile#isHardwareRasterizer()
+ */
+ public static final int isHardwareRasterizer(final AbstractGraphicsDevice device, final GLProfile glp) {
+ final int r;
+ final int ctp = getAvailableContextProperties(device, glp);
+ if(0 == ctp) {
+ r = -1;
+ } else if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctp ) ) {
+ r = 1;
+ } else {
+ r = 0;
+ }
+ return r;
+ }
+
+ /**
+ * @param device the device to request whether the profile is available for
+ * @param reqMajor Key Value either 1, 2, 3 or 4
+ * @param reqProfile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES}
+ * @param isHardware return value of one boolean, whether the profile is a hardware rasterizer or not
+ * @return true if the requested GL version is available regardless of a software or hardware rasterizer, otherwise false.
+ */
+ protected static boolean isGLVersionAvailable(final AbstractGraphicsDevice device, final int reqMajor, final int reqProfile, final boolean isHardware[]) {
+ final Integer valI = getAvailableGLVersion(device, reqMajor, reqProfile);
+ if(null==valI) {
+ return false;
+ }
+ isHardware[0] = 0 == ( valI.intValue() & GLContext.CTX_IMPL_ACCEL_SOFT ) ;
+ return true;
+ }
+
+ public static boolean isGLES1Available(final AbstractGraphicsDevice device, final boolean isHardware[]) {
+ return isGLVersionAvailable(device, 1, GLContext.CTX_PROFILE_ES, isHardware);
+ }
+
+ public static boolean isGLES2Available(final AbstractGraphicsDevice device, final boolean isHardware[]) {
+ return isGLVersionAvailable(device, 2, GLContext.CTX_PROFILE_ES, isHardware);
+ }
+
+ public static boolean isGLES3Available(final AbstractGraphicsDevice device, final boolean isHardware[]) {
+ return isGLVersionAvailable(device, 3, GLContext.CTX_PROFILE_ES, isHardware);
+ }
+
+ /**
+ * Returns true if a ES3 compatible profile is available,
+ * i.e. either a &ge; 4.3 context or a &ge; 3.1 context supporting <code>GL_ARB_ES3_compatibility</code>,
+ * otherwise false.
+ * <p>
+ * Includes [ GL &ge; 4.3, GL &ge; 3.1 w/ GL_ARB_ES3_compatibility and GLES3 ]
+ * </p>
+ */
+ public static final boolean isGLES3CompatibleAvailable(final AbstractGraphicsDevice device) {
+ final int major[] = { 0 };
+ final int minor[] = { 0 };
+ final int ctp[] = { 0 };
+ boolean ok;
+
+ ok = GLContext.getAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_ES, major, minor, ctp);
+ if( !ok ) {
+ ok = GLContext.getAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_CORE, major, minor, ctp);
+ }
+ if( !ok ) {
+ GLContext.getAvailableGLVersion(device, 3, GLContext.CTX_PROFILE_COMPAT, major, minor, ctp);
+ }
+ return 0 != ( ctp[0] & CTX_IMPL_ES3_COMPAT );
+ }
+
+ public static boolean isGL4bcAvailable(final AbstractGraphicsDevice device, final boolean isHardware[]) {
+ return isGLVersionAvailable(device, 4, CTX_PROFILE_COMPAT, isHardware);
+ }
+
+ public static boolean isGL4Available(final AbstractGraphicsDevice device, final boolean isHardware[]) {
+ return isGLVersionAvailable(device, 4, CTX_PROFILE_CORE, isHardware);
+ }
+
+ public static boolean isGL3bcAvailable(final AbstractGraphicsDevice device, final boolean isHardware[]) {
+ return isGLVersionAvailable(device, 3, CTX_PROFILE_COMPAT, isHardware);
+ }
+
+ public static boolean isGL3Available(final AbstractGraphicsDevice device, final boolean isHardware[]) {
+ return isGLVersionAvailable(device, 3, CTX_PROFILE_CORE, isHardware);
+ }
+
+ public static boolean isGL2Available(final AbstractGraphicsDevice device, final boolean isHardware[]) {
+ return isGLVersionAvailable(device, 2, CTX_PROFILE_COMPAT, isHardware);
+ }
+
+ protected static String getGLVersion(final int major, final int minor, final int ctp, final String gl_version) {
+ boolean needColon = false;
+ final StringBuilder sb = new StringBuilder();
+ sb.append(major);
+ sb.append(".");
+ sb.append(minor);
+ sb.append(" (");
+ needColon = appendString(sb, "ES profile", needColon, 0 != ( CTX_PROFILE_ES & ctp ));
+ needColon = appendString(sb, "Compat profile", needColon, 0 != ( CTX_PROFILE_COMPAT & ctp ));
+ needColon = appendString(sb, "Core profile", needColon, 0 != ( CTX_PROFILE_CORE & ctp ));
+ needColon = appendString(sb, "forward", needColon, 0 != ( CTX_OPTION_FORWARD & ctp ));
+ needColon = appendString(sb, "arb", needColon, 0 != ( CTX_IS_ARB_CREATED & ctp ));
+ needColon = appendString(sb, "debug", needColon, 0 != ( CTX_OPTION_DEBUG & ctp ));
+ needColon = appendString(sb, "ES2 compat", needColon, 0 != ( CTX_IMPL_ES2_COMPAT & ctp ));
+ needColon = appendString(sb, "ES3 compat", needColon, 0 != ( CTX_IMPL_ES3_COMPAT & ctp ));
+ needColon = appendString(sb, "FBO", needColon, 0 != ( CTX_IMPL_FBO & ctp ));
+ needColon = appendString(sb, "FP32 compat", needColon, 0 != ( CTX_IMPL_FP32_COMPAT_API & ctp ));
+ if( 0 != ( CTX_IMPL_ACCEL_SOFT & ctp ) ) {
+ needColon = appendString(sb, "software", needColon, true);
+ } else {
+ needColon = appendString(sb, "hardware", needColon, true);
+ }
+ sb.append(")");
+ if(null!=gl_version) {
+ sb.append(" - ");
+ sb.append(gl_version);
+ }
+ return sb.toString();
+ }
+
+ //
+ // internal string utils
+ //
+
+ protected static String toHexString(final int hex) {
+ return "0x" + Integer.toHexString(hex);
+ }
+
+ protected static String toHexString(final long hex) {
+ return "0x" + Long.toHexString(hex);
+ }
+
+ private static boolean appendString(final StringBuilder sb, final String string, boolean needColon, final boolean condition) {
+ if(condition) {
+ if(needColon) {
+ sb.append(", ");
+ }
+ sb.append(string);
+ needColon=true;
+ }
+ return needColon;
+ }
+
+ protected static String getThreadName() { return Thread.currentThread().getName(); }
+
+}
+
diff --git a/src/jogl/classes/com/jogamp/opengl/GLDebugListener.java b/src/jogl/classes/com/jogamp/opengl/GLDebugListener.java
new file mode 100644
index 000000000..30e1a49c2
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLDebugListener.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl;
+
+/**
+ * Listener for {@link GLDebugMessage}s.
+ *
+ * <p>One can enable GLDebugOutput via {@link GLContext#enableGLDebugMessage(boolean)}
+ * and add listeners via {@link GLContext#addGLDebugListener(GLDebugListener)}.
+ */
+public interface GLDebugListener {
+ /**
+ * Handle {@link GLDebugMessage} message sent from native GL implementation.
+ *
+ * <p>Since this method is invoked directly by the GL implementation, it shall
+ * return as fast as possible.</p>
+ */
+ void messageSent(GLDebugMessage event);
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLDebugMessage.java b/src/jogl/classes/com/jogamp/opengl/GLDebugMessage.java
new file mode 100644
index 000000000..a8868026b
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLDebugMessage.java
@@ -0,0 +1,253 @@
+/**
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl;
+
+import com.jogamp.common.os.Platform;
+
+/**
+ * OpenGL debug message generated by the driver
+ * and delivered via {@link GLDebugListener}.
+ */
+public class GLDebugMessage {
+ final GLContext source;
+ final long when;
+ final int dbgSource;
+ final int dbgType;
+ final int dbgId;
+ final int dbgSeverity;
+ final String dbgMsg;
+
+ /**
+ * @param source The source of the event
+ * @param when The time of the event
+ * @param dbgSource The ARB source
+ * @param dbgType The ARB type
+ * @param dbgId The ARB id
+ * @param dbgSeverity The ARB severity level
+ * @param dbgMsg The debug message
+ */
+ public GLDebugMessage(final GLContext source, final long when, final int dbgSource, final int dbgType, final int dbgId, final int dbgSeverity, final String dbgMsg) {
+ this.source = source;
+ this.when = when;
+ this.dbgSource = dbgSource;
+ this.dbgType = dbgType;
+ this.dbgId = dbgId;
+ this.dbgSeverity = dbgSeverity;
+ this.dbgMsg = dbgMsg;
+ }
+
+ /**
+ *
+ * @param source
+ * @param when
+ * @param dbgId
+ * @param amdDbgCategory
+ * @param dbgSeverity AMD severity level equals ARB severity level (value and semantic)
+ * @param dbgMsg
+ * @return
+ */
+ public static GLDebugMessage translateAMDEvent(final GLContext source, final long when, final int dbgId, final int amdDbgCategory, final int dbgSeverity, final String dbgMsg) {
+ int dbgSource, dbgType;
+
+ // AMD category == ARB source/type
+ switch(amdDbgCategory) {
+ case GL2GL3.GL_DEBUG_CATEGORY_API_ERROR_AMD:
+ dbgSource = GL2ES2.GL_DEBUG_SOURCE_API;
+ dbgType = GL2ES2.GL_DEBUG_TYPE_ERROR;
+ break;
+
+ //
+ // def source / other type
+ //
+
+ case GL2GL3.GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD:
+ dbgSource = GL2ES2.GL_DEBUG_SOURCE_WINDOW_SYSTEM;
+ dbgType = GL2ES2.GL_DEBUG_TYPE_OTHER;
+ break;
+
+ case GL2GL3.GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD:
+ dbgSource = GL2ES2.GL_DEBUG_SOURCE_SHADER_COMPILER;
+ dbgType = GL2ES2.GL_DEBUG_TYPE_OTHER;
+ break;
+
+ case GL2GL3.GL_DEBUG_CATEGORY_APPLICATION_AMD:
+ dbgSource = GL2ES2.GL_DEBUG_SOURCE_APPLICATION;
+ dbgType = GL2ES2.GL_DEBUG_TYPE_OTHER;
+ break;
+
+
+ //
+ // other source / def type
+ //
+
+ case GL2GL3.GL_DEBUG_CATEGORY_DEPRECATION_AMD:
+ dbgSource = GL2ES2.GL_DEBUG_SOURCE_OTHER;
+ dbgType = GL2ES2.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR;
+ break;
+
+ case GL2GL3.GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD:
+ dbgSource = GL2ES2.GL_DEBUG_SOURCE_OTHER;
+ dbgType = GL2ES2.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR;
+ break;
+
+ case GL2GL3.GL_DEBUG_CATEGORY_PERFORMANCE_AMD:
+ dbgSource = GL2ES2.GL_DEBUG_SOURCE_OTHER;
+ dbgType = GL2ES2.GL_DEBUG_TYPE_PERFORMANCE;
+ break;
+
+ case GL2GL3.GL_DEBUG_CATEGORY_OTHER_AMD:
+ default:
+ dbgSource = GL2ES2.GL_DEBUG_SOURCE_OTHER;
+ dbgType = GL2ES2.GL_DEBUG_TYPE_OTHER;
+ }
+
+ return new GLDebugMessage(source, when, dbgSource, dbgType, dbgId, dbgSeverity, dbgMsg);
+ }
+
+ public static int translateARB2AMDCategory(final int dbgSource, final int dbgType) {
+ switch (dbgSource) {
+ case GL2ES2.GL_DEBUG_SOURCE_WINDOW_SYSTEM:
+ return GL2GL3.GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD;
+
+ case GL2ES2.GL_DEBUG_SOURCE_SHADER_COMPILER:
+ return GL2GL3.GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD;
+
+ case GL2ES2.GL_DEBUG_SOURCE_APPLICATION:
+ return GL2GL3.GL_DEBUG_CATEGORY_APPLICATION_AMD;
+ }
+
+ switch(dbgType) {
+ case GL2ES2.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
+ return GL2GL3.GL_DEBUG_CATEGORY_DEPRECATION_AMD;
+
+ case GL2ES2.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
+ return GL2GL3.GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD;
+
+ case GL2ES2.GL_DEBUG_TYPE_PERFORMANCE:
+ return GL2GL3.GL_DEBUG_CATEGORY_PERFORMANCE_AMD;
+ }
+
+ return GL2GL3.GL_DEBUG_CATEGORY_OTHER_AMD;
+ }
+
+ public GLContext getSource() {
+ return source;
+ }
+
+ public long getWhen() {
+ return when;
+ }
+
+ public int getDbgSource() {
+ return dbgSource;
+ }
+
+ public int getDbgType() {
+ return dbgType;
+ }
+
+ public int getDbgId() {
+ return dbgId;
+ }
+
+ public int getDbgSeverity() {
+ return dbgSeverity;
+ }
+
+ public String getDbgMsg() {
+ return dbgMsg;
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ final String crtab = Platform.getNewline()+"\t";
+ if(null==sb) {
+ sb = new StringBuilder();
+ }
+ sb.append("GLDebugEvent[ id ");
+ toHexString(sb, dbgId)
+ .append(crtab).append("type ").append(getDbgTypeString(dbgType))
+ .append(crtab).append("severity ").append(getDbgSeverityString(dbgSeverity))
+ .append(crtab).append("source ").append(getDbgSourceString(dbgSource))
+ .append(crtab).append("msg ").append(dbgMsg)
+ .append(crtab).append("when ").append(when);
+ if(null != source) {
+ sb.append(crtab).append("source ").append(source.getGLVersion()).append(" - hash 0x").append(Integer.toHexString(source.hashCode()));
+ }
+ sb.append("]");
+ return sb;
+ }
+
+ @Override
+ public String toString() {
+ return toString(null).toString();
+ }
+
+ public static String getDbgSourceString(final int dbgSource) {
+ switch(dbgSource) {
+ case GL2ES2.GL_DEBUG_SOURCE_API: return "GL API";
+ case GL2ES2.GL_DEBUG_SOURCE_SHADER_COMPILER: return "GLSL or extension compiler";
+ case GL2ES2.GL_DEBUG_SOURCE_WINDOW_SYSTEM: return "Native Windowing binding";
+ case GL2ES2.GL_DEBUG_SOURCE_THIRD_PARTY: return "Third party";
+ case GL2ES2.GL_DEBUG_SOURCE_APPLICATION: return "Application";
+ case GL2ES2.GL_DEBUG_SOURCE_OTHER: return "generic";
+ default: return "Unknown (" + toHexString(dbgSource) + ")";
+ }
+ }
+
+ public static String getDbgTypeString(final int dbgType) {
+ switch(dbgType) {
+ case GL2ES2.GL_DEBUG_TYPE_ERROR: return "Error";
+ case GL2ES2.GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: return "Warning: marked for deprecation";
+ case GL2ES2.GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: return "Warning: undefined behavior";
+ case GL2ES2.GL_DEBUG_TYPE_PERFORMANCE: return "Warning: implementation dependent performance";
+ case GL2ES2.GL_DEBUG_TYPE_PORTABILITY: return "Warning: vendor-specific extension use";
+ case GL2ES2.GL_DEBUG_TYPE_OTHER: return "Warning: generic";
+ default: return "Unknown (" + toHexString(dbgType) + ")";
+ }
+ }
+
+ public static String getDbgSeverityString(final int dbgSeverity) {
+ switch(dbgSeverity) {
+ case GL2ES2.GL_DEBUG_SEVERITY_HIGH: return "High: dangerous undefined behavior";
+ case GL2ES2.GL_DEBUG_SEVERITY_MEDIUM: return "Medium: Severe performance/deprecation/other warnings";
+ case GL2ES2.GL_DEBUG_SEVERITY_LOW: return "Low: Performance warnings (redundancy/undefined)";
+ default: return "Unknown (" + toHexString(dbgSeverity) + ")";
+ }
+ }
+
+ public static StringBuilder toHexString(StringBuilder sb, final int i) {
+ if(null==sb) {
+ sb = new StringBuilder();
+ }
+ return sb.append("0x").append(Integer.toHexString(i));
+ }
+ public static String toHexString(final int i) {
+ return "0x"+Integer.toHexString(i);
+ }
+
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLDrawable.java b/src/jogl/classes/com/jogamp/opengl/GLDrawable.java
new file mode 100644
index 000000000..c801ba463
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLDrawable.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl;
+
+import com.jogamp.nativewindow.AbstractGraphicsConfiguration;
+import com.jogamp.nativewindow.NativeSurface;
+import com.jogamp.nativewindow.NativeSurfaceHolder;
+
+
+/** An abstraction for an OpenGL rendering target. A GLDrawable's
+ primary functionality is to create OpenGL contexts which can be
+ used to perform rendering. A GLDrawable does not automatically
+ create an OpenGL context, but all implementations of {@link
+ GLAutoDrawable} do so upon creation. */
+
+public interface GLDrawable extends NativeSurfaceHolder {
+ /**
+ * Creates a new context for drawing to this drawable that will
+ * optionally share buffer objects, textures and other server-side OpenGL
+ * objects with the specified GLContext.
+ * <p>
+ * The GLContext <code>share</code> need not be associated with this
+ * GLDrawable and may be null if sharing of display lists and other
+ * objects is not desired. See the note in the overview
+ * documentation
+ * <a href="../../../overview-summary.html#SHARING">context sharing</a>
+ * as well as {@link GLSharedContextSetter}.
+ * </p>
+ */
+ public GLContext createContext(GLContext shareWith);
+
+ /**
+ * Indicates to GLDrawable implementations whether the
+ * underlying {@link NativeSurface surface} has been created and can be drawn into.
+ * <p>
+ * If realized, the {@link #getHandle() drawable handle} may become
+ * valid while it's {@link NativeSurface surface} is being {@link NativeSurface#lockSurface() locked}.
+ * </p>
+ * <p>
+ * End users do not need to call this method; it is not necessary to
+ * call <code>setRealized</code> on a {@link GLAutoDrawable}
+ * as these perform the appropriate calls on their underlying GLDrawables internally.
+ * </p>
+ * <p>
+ * Developers implementing new OpenGL components for various window
+ * toolkits need to call this method against GLDrawables obtained
+ * from the GLDrawableFactory via the
+ * {@link GLDrawableFactory#createGLDrawable(NativeSurface)} method.
+ * It must typically be
+ * called with an argument of <code>true</code> when the component
+ * associated with the GLDrawable is realized and with an argument
+ * of <code>false</code> just before the component is unrealized.
+ * For the AWT, this means calling <code>setRealized(true)</code> in
+ * the <code>addNotify</code> method and with an argument of
+ * <code>false</code> in the <code>removeNotify</code> method.
+ * </p>
+ * <p>
+ * <code>GLDrawable</code> implementations should handle multiple
+ * cycles of <code>setRealized(true)</code> /
+ * <code>setRealized(false)</code> calls. Most, if not all, Java
+ * window toolkits have a persistent object associated with a given
+ * component, regardless of whether that component is currently
+ * realized. The <CODE>GLDrawable</CODE> object associated with a
+ * particular component is intended to be similarly persistent. A
+ * <CODE>GLDrawable</CODE> is intended to be created for a given
+ * component when it is constructed and live as long as that
+ * component. <code>setRealized</code> allows the
+ * <code>GLDrawable</code> to re-initialize and destroy any
+ * associated resources as the component becomes realized and
+ * unrealized, respectively.
+ * </p>
+ * <p>
+ * With an argument of <code>true</code>,
+ * the minimum implementation shall call
+ * {@link NativeSurface#lockSurface() NativeSurface's lockSurface()} and if successful:
+ * <ul>
+ * <li> Update the {@link GLCapabilities}, which are associated with
+ * the attached {@link NativeSurface}'s {@link AbstractGraphicsConfiguration}.</li>
+ * <li> Release the lock with {@link NativeSurface#unlockSurface() NativeSurface's unlockSurface()}.</li>
+ * </ul><br>
+ * This is important since {@link NativeSurface#lockSurface() NativeSurface's lockSurface()}
+ * ensures resolving the window/surface handles, and the drawable's {@link GLCapabilities}
+ * might have changed.
+ * </p>
+ * <p>
+ * Calling this method has no other effects. For example, if
+ * <code>removeNotify</code> is called on a Canvas implementation
+ * for which a GLDrawable has been created, it is also necessary to
+ * destroy all OpenGL contexts associated with that GLDrawable. This
+ * is not done automatically by the implementation.
+ * </p>
+ * @see #isRealized()
+ * @see #getHandle()
+ * @see NativeSurface#lockSurface()
+ */
+ public void setRealized(boolean realized);
+
+ /**
+ * Returns <code>true</code> if this drawable is realized, otherwise <code>true</code>.
+ * <p>
+ * A drawable can be realized and unrealized via {@link #setRealized(boolean)}.
+ * </p>
+ * @see #setRealized(boolean)
+ */
+ public boolean isRealized();
+
+ /**
+ * Returns the width of this {@link GLDrawable}'s {@link #getNativeSurface() surface} client area in pixel units.
+ * @see NativeSurface#getSurfaceWidth()
+ */
+ public int getSurfaceWidth();
+
+ /**
+ * Returns the height of this {@link GLDrawable}'s {@link #getNativeSurface() surface} client area in pixel units.
+ * @see NativeSurface#getSurfaceHeight()
+ */
+ public int getSurfaceHeight();
+
+ /**
+ * Returns <code>true</code> if the drawable is rendered in
+ * OpenGL's coordinate system, <i>origin at bottom left</i>.
+ * Otherwise returns <code>false</code>, i.e. <i>origin at top left</i>.
+ * <p>
+ * Default impl. is <code>true</code>, i.e. OpenGL coordinate system.
+ * </p>
+ * <p>
+ * Currently only MS-Windows bitmap offscreen drawable uses a non OpenGL orientation and hence returns <code>false</code>.<br/>
+ * This removes the need of a vertical flip when used in AWT or Windows applications.
+ * </p>
+ */
+ public boolean isGLOriented();
+
+ /** Swaps the front and back buffers of this drawable. For {@link
+ GLAutoDrawable} implementations, when automatic buffer swapping
+ is enabled (as is the default), this method is called
+ automatically and should not be called by the end user. */
+ public void swapBuffers() throws GLException;
+
+ /** Fetches the {@link GLCapabilitiesImmutable} corresponding to the chosen
+ OpenGL capabilities (pixel format / visual / GLProfile) for this drawable.
+ <p>
+ This query only returns the chosen capabilities if {@link #isRealized()}.
+ </p>
+ <p>
+ On some platforms, the pixel format is not directly associated
+ with the drawable; a best attempt is made to return a reasonable
+ value in this case.
+ </p>
+ <p>
+ This object shall be directly associated to the attached {@link NativeSurface}'s
+ {@link AbstractGraphicsConfiguration}, and if changes are necessary,
+ they should reflect those as well.
+ </p>
+ @return The immutable queried instance.
+ @see #getRequestedGLCapabilities()
+ */
+ public GLCapabilitiesImmutable getChosenGLCapabilities();
+
+ /** Fetches the {@link GLCapabilitiesImmutable} corresponding to the user requested
+ OpenGL capabilities (pixel format / visual / GLProfile) for this drawable.
+ <p>
+ If {@link #isRealized() realized}, {@link #getChosenGLCapabilities() the chosen capabilities}
+ reflect the actual selected OpenGL capabilities.
+ </p>
+ @return The immutable queried instance.
+ @see #getChosenGLCapabilities()
+ @since 2.2
+ */
+ public GLCapabilitiesImmutable getRequestedGLCapabilities();
+
+ /** Fetches the {@link GLProfile} for this drawable.
+ Returns the GLProfile object, no copy.
+ */
+ public GLProfile getGLProfile();
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Returns the underlying {@link NativeSurface} which {@link NativeSurface#getSurfaceHandle() native handle}
+ * represents this OpenGL drawable's native resource.
+ * </p>
+ *
+ * @see #getHandle()
+ */
+ @Override
+ public NativeSurface getNativeSurface();
+
+ /**
+ * Returns the GL drawable handle,
+ * guaranteed to be valid after {@link #setRealized(boolean) realization}
+ * <i>and</i> while it's {@link NativeSurface surface} is being {@link NativeSurface#lockSurface() locked}.
+ * <p>
+ * It is usually identical to the underlying windowing toolkit {@link NativeSurface surface}'s
+ * {@link com.jogamp.nativewindow.NativeSurface#getSurfaceHandle() handle}
+ * or an intermediate layer to suite GL, e.g. an EGL surface.
+ * </p>
+ * <p>
+ * On EGL it is represented by the EGLSurface.<br>
+ * On X11/GLX it is represented by either the Window XID, GLXPixmap, or GLXPbuffer.<br>
+ * On Windows it is represented by the HDC, which may change with each {@link NativeSurface#lockSurface()}.<br>
+ * </p>
+ * @see #setRealized(boolean)
+ * @see NativeSurface#lockSurface()
+ * @see NativeSurface#unlockSurface()
+ */
+ public long getHandle();
+
+ /** Return the {@link GLDrawableFactory} being used to create this instance. */
+ public GLDrawableFactory getFactory();
+
+ @Override
+ public String toString();
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java b/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java
new file mode 100644
index 000000000..07c3e77e0
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLDrawableFactory.java
@@ -0,0 +1,798 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.jogamp.common.util.PropertyAccess;
+import com.jogamp.common.util.ReflectionUtil;
+import com.jogamp.opengl.GLAutoDrawableDelegate;
+import com.jogamp.opengl.GLRendererQuirks;
+
+import com.jogamp.nativewindow.AbstractGraphicsDevice;
+import com.jogamp.nativewindow.AbstractGraphicsScreen;
+import com.jogamp.nativewindow.AbstractGraphicsConfiguration;
+import com.jogamp.nativewindow.CapabilitiesImmutable;
+import com.jogamp.nativewindow.NativeSurface;
+import com.jogamp.nativewindow.NativeWindowFactory;
+import com.jogamp.nativewindow.ProxySurface;
+import com.jogamp.nativewindow.UpstreamSurfaceHook;
+
+import jogamp.opengl.Debug;
+
+/** <p> Provides a virtual machine- and operating system-independent
+ mechanism for creating {@link GLDrawable}s.
+ </p>
+ <p> The {@link com.jogamp.opengl.GLCapabilities} objects passed
+ in to the various factory methods are used as a hint for the
+ properties of the returned drawable. The default capabilities
+ selection algorithm (equivalent to passing in a null {@link
+ GLCapabilitiesChooser}) is described in {@link
+ DefaultGLCapabilitiesChooser}. Sophisticated applications needing
+ to change the selection algorithm may pass in their own {@link
+ GLCapabilitiesChooser} which can select from the available pixel
+ formats. The GLCapabilitiesChooser mechanism may not be supported
+ by all implementations or on all platforms, in which case any
+ passed GLCapabilitiesChooser will be ignored.
+ </p>
+
+ <p> Because of the multithreaded nature of the Java platform's
+ Abstract Window Toolkit, it is typically not possible to immediately
+ reject a given {@link GLCapabilities} as being unsupportable by
+ either returning <code>null</code> from the creation routines or
+ raising a {@link GLException}. The semantics of the rejection
+ process are (unfortunately) left unspecified for now. The current
+ implementation will cause a {@link GLException} to be raised
+ during the first repaint of the {@link com.jogamp.opengl.awt.GLCanvas} or {@link
+ com.jogamp.opengl.awt.GLJPanel} if the capabilities can not be met.<br>
+ {@link GLOffscreenAutoDrawable} are created lazily,
+ see {@link #createOffscreenAutoDrawable(AbstractGraphicsDevice, GLCapabilitiesImmutable, GLCapabilitiesChooser, int, int) createOffscreenAutoDrawable(..)}.
+ </p>
+
+ <p> The concrete GLDrawableFactory subclass instantiated by {@link
+ #getFactory getFactory} can be changed by setting the system
+ property <code>opengl.factory.class.name</code> to the
+ fully-qualified name of the desired class.
+ </p>
+*/
+public abstract class GLDrawableFactory {
+
+ protected static final boolean DEBUG = Debug.debug("GLDrawable");
+
+ private static volatile boolean isInit = false;
+ private static GLDrawableFactory eglFactory;
+ private static GLDrawableFactory nativeOSFactory;
+
+ private static ArrayList<GLDrawableFactory> glDrawableFactories = new ArrayList<GLDrawableFactory>();
+
+ /**
+ * Instantiate singleton factories if available, EGLES1, EGLES2 and the OS native ones.
+ */
+ public static final void initSingleton() {
+ if (!isInit) { // volatile: ok
+ synchronized (GLDrawableFactory.class) {
+ if (!isInit) {
+ isInit=true;
+ initSingletonImpl();
+ }
+ }
+ }
+ }
+ private static final void initSingletonImpl() {
+ NativeWindowFactory.initSingleton();
+ NativeWindowFactory.addCustomShutdownHook(false /* head */, new Runnable() {
+ @Override
+ public void run() {
+ shutdown0();
+ }
+ });
+
+ final String nwt = NativeWindowFactory.getNativeWindowType(true);
+ GLDrawableFactory tmp = null;
+ String factoryClassName = PropertyAccess.getProperty("jogl.gldrawablefactory.class.name", true);
+ final ClassLoader cl = GLDrawableFactory.class.getClassLoader();
+ if (null == factoryClassName) {
+ if ( nwt == NativeWindowFactory.TYPE_X11 ) {
+ factoryClassName = "jogamp.opengl.x11.glx.X11GLXDrawableFactory";
+ } else if ( nwt == NativeWindowFactory.TYPE_WINDOWS ) {
+ factoryClassName = "jogamp.opengl.windows.wgl.WindowsWGLDrawableFactory";
+ } else if ( nwt == NativeWindowFactory.TYPE_MACOSX ) {
+ factoryClassName = "jogamp.opengl.macosx.cgl.MacOSXCGLDrawableFactory";
+ } else {
+ // may use egl*Factory ..
+ if (DEBUG || GLProfile.DEBUG) {
+ System.err.println("GLDrawableFactory.static - No native Windowing Factory for: "+nwt+"; May use EGLDrawableFactory, if available." );
+ }
+ }
+ }
+ if (null != factoryClassName && !GLProfile.disableOpenGLDesktop) {
+ if (DEBUG || GLProfile.DEBUG) {
+ System.err.println("GLDrawableFactory.static - Native OS Factory for: "+nwt+": "+factoryClassName);
+ }
+ try {
+ tmp = (GLDrawableFactory) ReflectionUtil.createInstance(factoryClassName, cl);
+ } catch (final Exception jre) {
+ if (DEBUG || GLProfile.DEBUG) {
+ System.err.println("Info: GLDrawableFactory.static - Native Platform: "+nwt+" - not available: "+factoryClassName);
+ jre.printStackTrace();
+ }
+ }
+ }
+ if(null != tmp && tmp.isComplete()) {
+ nativeOSFactory = tmp;
+ }
+ tmp = null;
+
+ if(!GLProfile.disableOpenGLES) {
+ try {
+ tmp = (GLDrawableFactory) ReflectionUtil.createInstance("jogamp.opengl.egl.EGLDrawableFactory", cl);
+ } catch (final Exception jre) {
+ if (DEBUG || GLProfile.DEBUG) {
+ System.err.println("Info: GLDrawableFactory.static - EGLDrawableFactory - not available");
+ jre.printStackTrace();
+ }
+ }
+ if(null != tmp && tmp.isComplete()) {
+ eglFactory = tmp;
+ }
+ } else if( DEBUG || GLProfile.DEBUG ) {
+ System.err.println("Info: GLDrawableFactory.static - EGLDrawableFactory - disabled!");
+ }
+ }
+
+ protected static void shutdown() {
+ if (isInit) { // volatile: ok
+ synchronized (GLDrawableFactory.class) {
+ if (isInit) {
+ isInit=false;
+ shutdown0();
+ }
+ }
+ }
+ }
+
+ private static void shutdown0() {
+ // Following code will _always_ remain in shutdown hook
+ // due to special semantics of native utils, i.e. X11Utils.
+ // The latter requires shutdown at JVM-Shutdown only.
+ synchronized(glDrawableFactories) {
+ final int gldfCount = glDrawableFactories.size();
+ if( DEBUG ) {
+ System.err.println("GLDrawableFactory.shutdownAll "+gldfCount+" instances, on thread "+getThreadName());
+ }
+ for(int i=0; i<gldfCount; i++) {
+ final GLDrawableFactory gldf = glDrawableFactories.get(i);
+ if( DEBUG ) {
+ System.err.println("GLDrawableFactory.shutdownAll["+(i+1)+"/"+gldfCount+"]: "+gldf.getClass().getName());
+ }
+ try {
+ gldf.resetAllDisplayGammaNoSync();
+ gldf.shutdownImpl();
+ } catch (final Throwable t) {
+ System.err.println("GLDrawableFactory.shutdownImpl: Caught "+t.getClass().getName()+" during factory shutdown #"+(i+1)+"/"+gldfCount+" "+gldf.getClass().getName());
+ if( DEBUG ) {
+ t.printStackTrace();
+ }
+ }
+ }
+ glDrawableFactories.clear();
+
+ // both were members of glDrawableFactories and are shutdown already
+ nativeOSFactory = null;
+ eglFactory = null;
+ }
+ GLContext.shutdown();
+ if( DEBUG ) {
+ System.err.println("GLDrawableFactory.shutdownAll.X on thread "+getThreadName());
+ }
+ }
+
+ protected GLDrawableFactory() {
+ synchronized(glDrawableFactories) {
+ glDrawableFactories.add(this);
+ }
+ }
+
+ protected static String getThreadName() { return Thread.currentThread().getName(); }
+
+ /** Returns true if this factory is complete, i.e. ready to be used. Otherwise return false. */
+ protected abstract boolean isComplete();
+
+ protected void enterThreadCriticalZone() {};
+ protected void leaveThreadCriticalZone() {};
+
+ protected abstract void shutdownImpl();
+
+ /**
+ * Sets the gamma, brightness, and contrast of the display associated with the given <code>surface</code>.
+ * <p>
+ * This functionality is not available on all platforms and
+ * graphics hardware. Returns true if the settings were successfully
+ * changed, false if not. This method may return false for some
+ * values of the incoming arguments even on hardware which does
+ * support the underlying functionality. </p>
+ * <p>
+ * If this method returns true, the display settings will
+ * automatically be reset to their original values upon JVM exit
+ * (assuming the JVM does not crash); if the user wishes to change
+ * the display settings back to normal ahead of time,
+ * use {@link #resetDisplayGamma(NativeSurface)} or {@link #resetAllDisplayGamma()}.
+ * </p>
+ * <p>
+ * It is recommended to call {@link #resetDisplayGamma(NativeSurface)} or {@link #resetAllDisplayGamma()}
+ * before calling e.g. <code>System.exit()</code> from the application rather than
+ * rely on the shutdown hook functionality due to inevitable race
+ * conditions and unspecified behavior during JVM teardown.
+ * </p>
+ * <p>
+ * This method may be called multiple times during the application's
+ * execution, but calling {@link #resetDisplayGamma(NativeSurface)}
+ * will only reset the settings to the values
+ * before the first call to this method. </p>
+ *
+ * @param surface denominates the display device
+ * @param gamma The gamma value, typically > 1.0 (default values vary, but typically roughly 1.0)
+ * @param brightness The brightness value between -1.0 and 1.0, inclusive (default values vary, but typically 0)
+ * @param contrast The contrast, greater than 0.0 (default values vary, but typically 1)
+ *
+ * @return true if gamma settings were successfully changed, false if not
+ * @throws IllegalArgumentException if any of the parameters were out-of-bounds
+ * @see #resetDisplayGamma(NativeSurface)
+ * @see #resetAllDisplayGamma()
+ */
+ public abstract boolean setDisplayGamma(final NativeSurface surface, final float gamma, final float brightness, final float contrast) throws IllegalArgumentException;
+
+ /**
+ * Resets the gamma, brightness and contrast values of the display associated with the given <code>surface</code>
+ * to its original values before {@link #setDisplayGamma(NativeSurface, float, float, float) setDisplayGamma}
+ * was called the first time.
+ * <p>
+ * While it is not explicitly required that this method be called before
+ * exiting manually, calling it is recommended because of the inevitable
+ * unspecified behavior during JVM teardown.
+ * </p>
+ */
+ public abstract void resetDisplayGamma(final NativeSurface surface);
+
+ /**
+ * Resets the gamma, brightness and contrast values of all modified
+ * displays to their original values before {@link #setDisplayGamma(NativeSurface, float, float, float) setDisplayGamma}
+ * was called the first time.
+ * <p>
+ * While it is not explicitly required that this method be called before
+ * exiting manually, calling it is recommended because of the inevitable
+ * unspecified behavior during JVM teardown.
+ * </p>
+ */
+ public abstract void resetAllDisplayGamma();
+
+ protected abstract void resetAllDisplayGammaNoSync();
+
+ /**
+ * Retrieve the default <code>device</code> {@link AbstractGraphicsDevice#getConnection() connection},
+ * {@link AbstractGraphicsDevice#getUnitID() unit ID} and {@link AbstractGraphicsDevice#getUniqueID() unique ID name}. for this factory<br>
+ * The implementation must return a non <code>null</code> default device, which must not be opened, ie. it's native handle is <code>null</code>.
+ * <p>
+ * This method shall return the default device if available
+ * even if the GLDrawableFactory is not functional and hence not compatible.
+ * The latter situation may happen because no native OpenGL implementation is available for the specific implementation.
+ * </p>
+ * @return the default shared device for this factory, eg. :0.0 on X11 desktop.
+ * @see #getIsDeviceCompatible(AbstractGraphicsDevice)
+ */
+ public abstract AbstractGraphicsDevice getDefaultDevice();
+
+ /**
+ * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device.
+ * @return true if the device is compatible with this factory, ie. if it can be used for GLDrawable creation. Otherwise false.
+ * This implies validation whether the implementation is functional.
+ *
+ * @see #getDefaultDevice()
+ */
+ public abstract boolean getIsDeviceCompatible(AbstractGraphicsDevice device);
+
+ protected final AbstractGraphicsDevice validateDevice(AbstractGraphicsDevice device) {
+ if(null==device) {
+ device = getDefaultDevice();
+ if(null==device) {
+ throw new InternalError("no default device available");
+ }
+ if (GLProfile.DEBUG) {
+ System.err.println("Info: "+getClass().getSimpleName()+".validateDevice: using default device : "+device);
+ }
+ }
+
+ // Always validate the device,
+ // since even the default device may not be used by this factory.
+ if( !getIsDeviceCompatible(device) ) {
+ if (GLProfile.DEBUG) {
+ System.err.println("Info: "+getClass().getSimpleName()+".validateDevice: device not compatible : "+device);
+ }
+ return null;
+ }
+ return device;
+ }
+
+ /**
+ * Validate and start the shared resource runner thread if necessary and
+ * if the implementation uses it.
+ *
+ * @return the shared resource runner thread, if implementation uses it.
+ */
+ protected abstract Thread getSharedResourceThread();
+
+ /**
+ * Create the shared resource used internally as a reference for capabilities etc.
+ * <p>
+ * Returns true if a shared resource could be created
+ * for the <code>device</code> {@link AbstractGraphicsDevice#getConnection()}.<br>
+ * This does not imply a shared resource is mapped (ie. made persistent), but is available in general<br>.
+ * </p>
+ *
+ * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device.
+ * @return true if a shared resource could been created, otherwise false.
+ */
+ protected final boolean createSharedResource(final AbstractGraphicsDevice device) {
+ return createSharedResourceImpl(device);
+ }
+ protected abstract boolean createSharedResourceImpl(AbstractGraphicsDevice device);
+
+ /**
+ * Returns true if the <code>quirk</code> exist in the shared resource's context {@link GLRendererQuirks}.
+ * <p>
+ * Convenience method for:
+ * <pre>
+ final GLRendererQuirks glrq = factory.getRendererQuirks(device);
+ return null != glrq ? glrq.exist(quirk) : false;
+ * </pre>
+ * </p>
+ *
+ * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device.
+ * @param glp {@link GLProfile} to identify the device's {@link GLRendererQuirks}, maybe {@code null}
+ * @param quirk the quirk to be tested, e.g. {@link GLRendererQuirks#NoDoubleBufferedPBuffer}.
+ * @throws IllegalArgumentException if the quirk is out of range
+ * @see #getRendererQuirks(AbstractGraphicsDevice, GLProfile)
+ * @see GLRendererQuirks
+ */
+ public final boolean hasRendererQuirk(final AbstractGraphicsDevice device, final GLProfile glp, final int quirk) {
+ final GLRendererQuirks glrq = getRendererQuirks(device, glp);
+ return null != glrq ? glrq.exist(quirk) : false;
+ }
+
+ /**
+ * Returns the shared resource's context {@link GLRendererQuirks}.
+ * <p>
+ * Implementation calls {@link GLContext#getRendererQuirks()} on the shared resource context.
+ * </p>
+ * <p>
+ * In case no shared device exist yet or the implementation doesn't support tracking quirks,
+ * the result is always <code>null</code>.
+ * </p>
+ * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device.
+ * @param glp {@link GLProfile} to identify the device's {@link GLRendererQuirks}, maybe {@code null}
+ * @see GLContext#getRendererQuirks()
+ * @see GLRendererQuirks
+ */
+ public abstract GLRendererQuirks getRendererQuirks(AbstractGraphicsDevice device, final GLProfile glp);
+
+ /**
+ * Returns the sole GLDrawableFactory instance for the desktop (X11, WGL, ..) if exist or null
+ */
+ public static GLDrawableFactory getDesktopFactory() {
+ GLProfile.initSingleton();
+ return nativeOSFactory;
+ }
+
+ /**
+ * Returns the sole GLDrawableFactory instance for EGL if exist or null
+ */
+ public static GLDrawableFactory getEGLFactory() {
+ GLProfile.initSingleton();
+ return eglFactory;
+ }
+
+ /**
+ * Returns the sole GLDrawableFactory instance.
+ *
+ * @param glProfile GLProfile to determine the factory type, ie EGLDrawableFactory,
+ * or one of the native GLDrawableFactory's, ie X11/GLX, Windows/WGL or MacOSX/CGL.
+ */
+ public static GLDrawableFactory getFactory(final GLProfile glProfile) throws GLException {
+ return getFactoryImpl(glProfile.getImplName());
+ }
+
+ protected static GLDrawableFactory getFactoryImpl(final String glProfileImplName) throws GLException {
+ if ( GLProfile.usesNativeGLES(glProfileImplName) ) {
+ if(null!=eglFactory) {
+ return eglFactory;
+ }
+ } else if(null!=nativeOSFactory) {
+ return nativeOSFactory;
+ }
+ throw new GLException("No GLDrawableFactory available for profile: "+glProfileImplName);
+ }
+
+ protected static GLDrawableFactory getFactoryImpl(final AbstractGraphicsDevice device) throws GLException {
+ if(null != nativeOSFactory && nativeOSFactory.getIsDeviceCompatible(device)) {
+ return nativeOSFactory;
+ }
+ if(null != eglFactory && eglFactory.getIsDeviceCompatible(device)) {
+ return eglFactory;
+ }
+ throw new GLException("No native platform GLDrawableFactory, nor EGLDrawableFactory available: "+device);
+ }
+
+ /**
+ * Returns an array of available GLCapabilities for the device.<br>
+ * The list is sorted by the native ID, ascending.<br>
+ * The chosen GLProfile statement in the result may not refer to the maximum available profile
+ * due to implementation constraints, ie using the shared resource.
+ *
+ * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device.
+ * @return A list of {@link com.jogamp.opengl.GLCapabilitiesImmutable}'s, maybe empty if none is available.
+ */
+ public final List<GLCapabilitiesImmutable> getAvailableCapabilities(AbstractGraphicsDevice device) {
+ device = validateDevice(device);
+ if(null!=device) {
+ return getAvailableCapabilitiesImpl(device);
+ }
+ return null;
+ }
+ protected abstract List<GLCapabilitiesImmutable> getAvailableCapabilitiesImpl(AbstractGraphicsDevice device);
+
+ //----------------------------------------------------------------------
+ // Methods to create high-level objects
+
+ /**
+ * Returns an {@link GLDrawable#isRealized() unrealized} GLDrawable according to it's chosen {@link GLCapabilitiesImmutable},<br>
+ * which determines pixel format, on- and offscreen incl. PBuffer type.
+ * <p>
+ * The chosen {@link GLCapabilitiesImmutable} are referenced within the target
+ * {@link NativeSurface}'s {@link AbstractGraphicsConfiguration}.<p>
+ * </p>
+ * <p>
+ * An onscreen GLDrawable is created if {@link CapabilitiesImmutable#isOnscreen() caps.isOnscreen()} is true.
+ * </p>
+ * <p>
+ * A FBO drawable is created if both {@link GLCapabilitiesImmutable#isFBO() caps.isFBO()}
+ * and {@link GLContext#isFBOAvailable(AbstractGraphicsDevice, GLProfile) canCreateFBO(device, caps.getGLProfile())} is true.
+ * </p>
+ * <p>
+ * A Pbuffer drawable is created if both {@link GLCapabilitiesImmutable#isPBuffer() caps.isPBuffer()}
+ * and {@link #canCreateGLPbuffer(AbstractGraphicsDevice, GLProfile) canCreateGLPbuffer(device)} is true.
+ * </p>
+ * <p>
+ * If not onscreen and neither FBO nor Pbuffer is available,
+ * a simple pixmap/bitmap drawable/surface is created, which is unlikely to be hardware accelerated.
+ * </p>
+ *
+ * @throws IllegalArgumentException if the passed target is null
+ * @throws GLException if any window system-specific errors caused
+ * the creation of the GLDrawable to fail.
+ *
+ * @see #canCreateGLPbuffer(AbstractGraphicsDevice, GLProfile)
+ * @see GLContext#isFBOAvailable(AbstractGraphicsDevice, GLProfile)
+ * @see com.jogamp.opengl.GLCapabilities#isOnscreen()
+ * @see com.jogamp.opengl.GLCapabilities#isFBO()
+ * @see com.jogamp.opengl.GLCapabilities#isPBuffer()
+ * @see GraphicsConfigurationFactory#chooseGraphicsConfiguration(CapabilitiesImmutable, CapabilitiesImmutable, CapabilitiesChooser, AbstractGraphicsScreen, int)
+ */
+ public abstract GLDrawable createGLDrawable(NativeSurface target)
+ throws IllegalArgumentException, GLException;
+
+ /**
+ * Creates a {@link GLDrawable#isRealized() realized} {@link GLOffscreenAutoDrawable}
+ * incl it's offscreen {@link NativeSurface} with the given capabilites and dimensions.
+ * <p>
+ * The {@link GLOffscreenAutoDrawable}'s {@link GLDrawable} is {@link GLDrawable#isRealized() realized}
+ * <i>without</i> an assigned {@link GLContext}, hence not initialized completely.<br>
+ *
+ * The {@link GLContext} can be assigned later manually via {@link GLAutoDrawable#setContext(GLContext, boolean) setContext(ctx)}
+ * <i>or</i> it will be created <i>lazily</i> at the 1st {@link GLAutoDrawable#display() display()} method call.<br>
+ *
+ * <i>Lazy</i> {@link GLContext} creation will take a shared {@link GLContext} into account
+ * which has been set {@link GLOffscreenAutoDrawable#setSharedContext(GLContext) directly}
+ * or {@link GLOffscreenAutoDrawable#setSharedAutoDrawable(GLAutoDrawable) via another GLAutoDrawable}.
+ * </p>
+ * <p>
+ * In case the passed {@link GLCapabilitiesImmutable} contains default values, i.e.
+ * {@link GLCapabilitiesImmutable#isOnscreen() caps.isOnscreen()} <code> == true</code>,
+ * it is auto-configured. Auto configuration will set {@link GLCapabilitiesImmutable caps} to offscreen
+ * and FBO <i>or</i> Pbuffer, whichever is available in that order.
+ * </p>
+ * <p>
+ * A FBO based auto drawable, {@link GLOffscreenAutoDrawable.FBO}, is created if both {@link GLCapabilitiesImmutable#isFBO() caps.isFBO()}
+ * and {@link GLContext#isFBOAvailable(AbstractGraphicsDevice, GLProfile) canCreateFBO(device, caps.getGLProfile())} is true.
+ * </p>
+ * <p>
+ * A Pbuffer based auto drawable is created if both {@link GLCapabilitiesImmutable#isPBuffer() caps.isPBuffer()}
+ * and {@link #canCreateGLPbuffer(AbstractGraphicsDevice, GLProfile) canCreateGLPbuffer(device)} is true.
+ * </p>
+ * <p>
+ * If neither FBO nor Pbuffer is available,
+ * a simple pixmap/bitmap auto drawable is created, which is unlikely to be hardware accelerated.
+ * </p>
+ * <p>
+ * The resulting {@link GLOffscreenAutoDrawable} has it's own independent device instance using <code>device</code> details.
+ * </p>
+ *
+ * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> for the platform's default device.
+ * @param caps the requested GLCapabilties
+ * @param chooser the custom chooser, may be null for default
+ * @param width the requested offscreen width
+ * @param height the requested offscreen height
+ * @return the created and realized offscreen {@link GLOffscreenAutoDrawable} instance
+ *
+ * @throws GLException if any window system-specific errors caused
+ * the creation of the Offscreen to fail.
+ *
+ * @see #createOffscreenDrawable(AbstractGraphicsDevice, GLCapabilitiesImmutable, GLCapabilitiesChooser, int, int)
+ */
+ public abstract GLOffscreenAutoDrawable createOffscreenAutoDrawable(AbstractGraphicsDevice device,
+ GLCapabilitiesImmutable caps,
+ GLCapabilitiesChooser chooser,
+ int width, int height) throws GLException;
+
+ /**
+ * Creates a {@link GLDrawable#isRealized() realized} <i>dummy</i> {@link GLAutoDrawable}
+ * incl it's <i>dummy, invisible</i> {@link NativeSurface}
+ * as created with {@link #createDummyDrawable(AbstractGraphicsDevice, boolean, GLCapabilitiesImmutable, GLCapabilitiesChooser)}.
+ * <p>
+ * The <i>dummy</i> {@link GLAutoDrawable}'s {@link GLDrawable} is {@link GLDrawable#isRealized() realized}
+ * <i>without</i> an assigned {@link GLContext}, hence not initialized completely.<br>
+ * The {@link GLContext} can be assigned later manually via {@link GLAutoDrawable#setContext(GLContext, boolean) setContext(ctx)}
+ * <i>or</i> it will be created <i>lazily</i> at the 1st {@link GLAutoDrawable#display() display()} method call.<br>
+ * <i>Lazy</i> {@link GLContext} creation will take a shared {@link GLContext} into account
+ * which has been set {@link GLOffscreenAutoDrawable#setSharedContext(GLContext) directly}
+ * or {@link GLOffscreenAutoDrawable#setSharedAutoDrawable(GLAutoDrawable) via another GLAutoDrawable}.
+ * </p>
+ *
+ * @param deviceReq which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> for the platform's default device.
+ * @param createNewDevice if <code>true</code> a new independent device instance is created from the <code>deviceReq</code>, otherwise <code>deviceReq</code> is used as-is and must be valid!
+ * @param capsRequested the desired {@link GLCapabilitiesImmutable}, incl. it's {@link GLProfile}.
+ * For shared context, same {@link GLCapabilitiesImmutable#getVisualID(com.jogamp.nativewindow.VisualIDHolder.VIDType)}
+ * across shared drawables will yield best compatibility.
+ * @param chooser the custom chooser, may be null for default
+ * @return the created and realized <i>dummy</i> {@link GLAutoDrawable} instance
+ *
+ * @see #createDummyDrawable(AbstractGraphicsDevice, boolean, GLCapabilitiesImmutable, GLCapabilitiesChooser)
+ */
+ public abstract GLAutoDrawable createDummyAutoDrawable(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser);
+
+ /**
+ * Creates an {@link GLDrawable#isRealized() unrealized} offscreen {@link GLDrawable}
+ * incl it's offscreen {@link NativeSurface} with the given capabilites and dimensions.
+ * <p>
+ * In case the passed {@link GLCapabilitiesImmutable} contains default values, i.e.
+ * {@link GLCapabilitiesImmutable#isOnscreen() caps.isOnscreen()} <code> == true</code>,
+ * it is auto-configured. The latter will set offscreen and also FBO <i>or</i> Pbuffer, whichever is available in that order.
+ * </p>
+ * <p>
+ * A resizeable FBO drawable, {@link GLFBODrawable.Resizeable}, is created if both {@link GLCapabilitiesImmutable#isFBO() caps.isFBO()}
+ * and {@link GLContext#isFBOAvailable(AbstractGraphicsDevice, GLProfile) canCreateFBO(device, caps.getGLProfile())} is true.
+ * </p>
+ * <p>
+ * A Pbuffer drawable is created if both {@link GLCapabilitiesImmutable#isPBuffer() caps.isPBuffer()}
+ * and {@link #canCreateGLPbuffer(AbstractGraphicsDevice, GLProfile) canCreateGLPbuffer(device)} is true.
+ * </p>
+ * <p>
+ * If neither FBO nor Pbuffer is available,
+ * a simple pixmap/bitmap drawable is created, which is unlikely to be hardware accelerated.
+ * </p>
+ * <p>
+ * The resulting {@link GLDrawable} has it's own independent device instance using <code>device</code> details.
+ * </p>
+ *
+ * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> for the platform's default device.
+ * @param caps the requested GLCapabilties
+ * @param chooser the custom chooser, may be null for default
+ * @param width the requested offscreen width
+ * @param height the requested offscreen height
+ *
+ * @return the created unrealized offscreen {@link GLDrawable}
+ *
+ * @throws GLException if any window system-specific errors caused
+ * the creation of the Offscreen to fail.
+ *
+ * @see #createOffscreenAutoDrawable(AbstractGraphicsDevice, GLCapabilitiesImmutable, GLCapabilitiesChooser, int, int, GLContext)
+ */
+ public abstract GLDrawable createOffscreenDrawable(AbstractGraphicsDevice device,
+ GLCapabilitiesImmutable caps,
+ GLCapabilitiesChooser chooser,
+ int width, int height) throws GLException;
+
+ /**
+ * Creates an {@link GLDrawable#isRealized() unrealized} dummy {@link GLDrawable}.
+ * A dummy drawable is not visible on screen and will not be used to render directly to, it maybe on- or offscreen.
+ * <p>
+ * It is used to allow the creation of a {@link GLContext} to query information.
+ * It also allows creation of framebuffer objects which are used for rendering or creating a shared GLContext w/o actually rendering to this dummy drawable's framebuffer.
+ * </p>
+ * @param deviceReq which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared device to be used, may be <code>null</code> for the platform's default device.
+ * @param createNewDevice if <code>true</code> a new independent device instance is created from the <code>deviceReq</code>, otherwise <code>deviceReq</code> is used as-is and must be valid!
+ * @param capsRequested the desired {@link GLCapabilitiesImmutable}, incl. it's {@link GLProfile}.
+ * For shared context, same {@link GLCapabilitiesImmutable#getVisualID(com.jogamp.nativewindow.VisualIDHolder.VIDType) visual ID}
+ * or {@link GLCapabilitiesImmutable caps}
+ * across shared drawables will yield best compatibility.
+ * @param chooser the custom chooser, may be null for default
+ * @return the created unrealized dummy {@link GLDrawable}
+ */
+ public abstract GLDrawable createDummyDrawable(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser);
+
+ /**
+ * Creates a proxy {@link NativeSurface} w/ defined surface handle,
+ * i.e. a {@link jogamp.nativewindow.WrappedSurface} or {@link jogamp.nativewindow.windows.GDISurface} instance.
+ * <p>
+ * It's {@link AbstractGraphicsConfiguration} is properly set according to the given
+ * <code>windowHandle</code>'s native visualID if set or the given {@link GLCapabilitiesImmutable}.
+ * </p>
+ * <p>
+ * Lifecycle (creation and destruction) of the given surface handle shall be handled by the caller
+ * via {@link ProxySurface#createNotify()} and {@link ProxySurface#destroyNotify()}.
+ * </p>
+ * <p>
+ * Such surface can be used to instantiate a GLDrawable. With the help of {@link GLAutoDrawableDelegate}
+ * you will be able to implement a new native windowing system binding almost on-the-fly,
+ * see {@link com.jogamp.opengl.swt.GLCanvas}.
+ * </p>
+ * <p>
+ * The resulting {@link GLOffscreenAutoDrawable} has it's own independent device instance using <code>device</code> details
+ * which may be blocking depending on platform and windowing-toolkit requirements.
+ * </p>
+ *
+ * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device.
+ * Caller has to ensure it is compatible w/ the given <code>windowHandle</code>
+ * @param screenIdx matching screen index of given <code>windowHandle</code>
+ * @param windowHandle the native window handle
+ * @param caps the requested GLCapabilties
+ * @param chooser the custom chooser, may be null for default
+ * @param upstream optional {@link UpstreamSurfaceHook} allowing control of the {@link ProxySurface}'s lifecycle and data it presents.
+ * @return the created {@link ProxySurface} instance w/ defined surface handle.
+ */
+ public abstract ProxySurface createProxySurface(AbstractGraphicsDevice device,
+ int screenIdx,
+ long windowHandle,
+ GLCapabilitiesImmutable caps, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream);
+
+ /**
+ * Returns true if it is possible to create an <i>framebuffer object</i> (FBO).
+ * <p>
+ * FBO feature is implemented in OpenGL, hence it is {@link GLProfile} dependent.
+ * </p>
+ * <p>
+ * FBO support is queried as described in {@link GLContext#hasBasicFBOSupport()}.
+ * </p>
+ *
+ * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device.
+ * @param glp {@link GLProfile} to check for FBO capabilities
+ * @see GLContext#hasBasicFBOSupport()
+ */
+ public abstract boolean canCreateFBO(AbstractGraphicsDevice device, GLProfile glp);
+
+ /**
+ * Returns true if it is possible to create an <i>pbuffer surface</i>.
+ * <p>
+ * Some older graphics cards do not have this capability,
+ * as well as some new GL implementation, i.e. OpenGL 3 core on OSX.
+ * </p>
+ *
+ * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device.
+ * @param glp {@link GLProfile} to check for FBO capabilities
+ */
+ public abstract boolean canCreateGLPbuffer(AbstractGraphicsDevice device, GLProfile glp);
+
+ //----------------------------------------------------------------------
+ // Methods for interacting with third-party OpenGL libraries
+
+ /**
+ * <P> Creates a GLContext object representing an existing OpenGL
+ * context in an external (third-party) OpenGL-based library. This
+ * GLContext object may be used to draw into this preexisting
+ * context using its {@link GL} and {@link
+ * com.jogamp.opengl.glu.GLU} objects. New contexts created through
+ * {@link GLDrawable}s may share textures and display lists with
+ * this external context. </P>
+ *
+ * <P> The underlying OpenGL context must be current on the current
+ * thread at the time this method is called. The user is responsible
+ * for the maintenance of the underlying OpenGL context; calls to
+ * <code>makeCurrent</code> and <code>release</code> on the returned
+ * GLContext object have no effect. If the underlying OpenGL context
+ * is destroyed, the <code>destroy</code> method should be called on
+ * the <code>GLContext</code>. A new <code>GLContext</code> object
+ * should be created for each newly-created underlying OpenGL
+ * context.
+ *
+ * @throws GLException if any window system-specific errors caused
+ * the creation of the external GLContext to fail.
+ */
+ public abstract GLContext createExternalGLContext()
+ throws GLException;
+
+ /**
+ * Returns true if it is possible to create an external GLDrawable
+ * object via {@link #createExternalGLDrawable}.
+ *
+ * @param device which {@link AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device.
+ */
+ public abstract boolean canCreateExternalGLDrawable(AbstractGraphicsDevice device);
+
+ /**
+ * <P> Creates a {@link GLDrawable} object representing an existing
+ * OpenGL drawable in an external (third-party) OpenGL-based
+ * library. This GLDrawable object may be used to create new,
+ * fully-functional {@link GLContext}s on the OpenGL drawable. This
+ * is useful when interoperating with a third-party OpenGL-based
+ * library and it is essential to not perturb the state of the
+ * library's existing context, even to the point of not sharing
+ * textures or display lists with that context. </P>
+ *
+ * <P> An underlying OpenGL context must be current on the desired
+ * drawable and the current thread at the time this method is
+ * called. The user is responsible for the maintenance of the
+ * underlying drawable. If one or more contexts are created on the
+ * drawable using {@link GLDrawable#createContext}, and the drawable
+ * is deleted by the third-party library, the user is responsible
+ * for calling {@link GLContext#destroy} on these contexts. </P>
+ *
+ * <P> Calls to <code>setSize</code>, <code>getWidth</code> and
+ * <code>getHeight</code> are illegal on the returned GLDrawable. If
+ * these operations are required by the user, they must be performed
+ * by the third-party library. </P>
+ *
+ * <P> It is legal to create both an external GLContext and
+ * GLDrawable representing the same third-party OpenGL entities.
+ * This can be used, for example, to query current state information
+ * using the external GLContext and then create and set up new
+ * GLContexts using the external GLDrawable. </P>
+ *
+ * <P> This functionality may not be available on all platforms and
+ * {@link #canCreateExternalGLDrawable} should be called first to
+ * see if it is present. For example, on X11 platforms, this API
+ * requires the presence of GLX 1.3 or later.
+ *
+ * @throws GLException if any window system-specific errors caused
+ * the creation of the external GLDrawable to fail.
+ */
+ public abstract GLDrawable createExternalGLDrawable()
+ throws GLException;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLEventListener.java b/src/jogl/classes/com/jogamp/opengl/GLEventListener.java
new file mode 100644
index 000000000..8c5dfd3b3
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLEventListener.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl;
+
+import java.util.EventListener;
+
+/** Declares events which client code can use to manage OpenGL
+ rendering into a {@link GLAutoDrawable}. At the time any of these
+ methods is called, the drawable has made its associated OpenGL
+ context current, so it is valid to make OpenGL calls. */
+
+public interface GLEventListener extends EventListener {
+ /** Called by the drawable immediately after the OpenGL context is
+ initialized. Can be used to perform one-time OpenGL
+ initialization per GLContext, such as setup of lights and display lists.<p>
+
+ Note that this method may be called more than once if the underlying
+ OpenGL context for the GLAutoDrawable is destroyed and
+ recreated, for example if a GLCanvas is removed from the widget
+ hierarchy and later added again.
+ */
+ public void init(GLAutoDrawable drawable);
+
+ /** Notifies the listener to perform the release of all OpenGL
+ resources per GLContext, such as memory buffers and GLSL programs.<P>
+
+ Called by the drawable before the OpenGL context is
+ destroyed by an external event, like a reconfiguration of the
+ {@link GLAutoDrawable} closing an attached window,
+ but also manually by calling {@link GLAutoDrawable#destroy destroy}.<P>
+
+ Note that this event does not imply the end of life of the application.
+ It could be produced with a followup call to {@link #init(GLAutoDrawable)}
+ in case the GLContext has been recreated,
+ e.g. due to a pixel configuration change in a multihead environment.
+ */
+ public void dispose(GLAutoDrawable drawable);
+
+ /** Called by the drawable to initiate OpenGL rendering by the
+ client. After all GLEventListeners have been notified of a
+ display event, the drawable will swap its buffers if {@link
+ GLAutoDrawable#setAutoSwapBufferMode setAutoSwapBufferMode} is
+ enabled. */
+ public void display(GLAutoDrawable drawable);
+
+ /**
+ * Called by the drawable during the first repaint after the
+ * component has been resized.
+ * <p>
+ * The client can update it's viewport associated data
+ * and view volume of the window appropriately.
+ * </p>
+ * <p>
+ * For efficiency the GL viewport has already been updated
+ * via <code>glViewport(x, y, width, height)</code> when this method is called.
+ * </p>
+ *
+ * @param drawable the triggering {@link GLAutoDrawable}
+ * @param x viewport x-coord in pixel units
+ * @param y viewport y-coord in pixel units
+ * @param width viewport width in pixel units
+ * @param height viewport height in pixel units
+ */
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height);
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLException.java b/src/jogl/classes/com/jogamp/opengl/GLException.java
new file mode 100644
index 000000000..843934ab2
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLException.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2014 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl;
+
+/** A generic exception for OpenGL errors used throughout the binding
+ as a substitute for {@link RuntimeException}. */
+@SuppressWarnings("serial")
+public class GLException extends RuntimeException {
+ /** Constructs a GLException object. */
+ public GLException() {
+ super();
+ }
+
+ /** Constructs a GLException object with the specified detail
+ message. */
+ public GLException(final String message) {
+ super(message);
+ }
+
+ /** Constructs a GLException object with the specified detail
+ message and root cause. */
+ public GLException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+
+ /** Constructs a GLException object with the specified root
+ cause. */
+ public GLException(final Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * Constructs a GLException object with the specified root
+ * cause with a decorating message including the current thread name.
+ * @since 2.2
+ */
+ public static GLException newGLException(final Throwable t) {
+ return new GLException("Caught "+t.getClass().getSimpleName()+": "+t.getMessage()+" on thread "+Thread.currentThread().getName(), t);
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLFBODrawable.java b/src/jogl/classes/com/jogamp/opengl/GLFBODrawable.java
new file mode 100644
index 000000000..69358743e
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLFBODrawable.java
@@ -0,0 +1,227 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl;
+
+import com.jogamp.nativewindow.NativeWindowException;
+
+import com.jogamp.opengl.FBObject;
+import com.jogamp.opengl.FBObject.Colorbuffer;
+import com.jogamp.opengl.FBObject.ColorAttachment;
+import com.jogamp.opengl.FBObject.TextureAttachment;
+import com.jogamp.opengl.GLRendererQuirks;
+
+/**
+ * Platform-independent {@link GLDrawable} specialization,
+ * exposing {@link FBObject} functionality.
+ *
+ * <p>
+ * A {@link GLFBODrawable} is uninitialized until a {@link GLContext} is bound
+ * and made current the first time, hence only then it's capabilities <i>fully</i> reflect expectations,
+ * i.e. color, depth, stencil and MSAA bits will be <i>valid</i> only after the first {@link GLContext#makeCurrent() makeCurrent()} call.
+ * On-/offscreen bits are <i>valid</i> after {@link #setRealized(boolean) setRealized(true)}.
+ * </p>
+ *
+ * <p>
+ * MSAA is used if {@link GLCapabilitiesImmutable#getNumSamples() requested}.
+ * </p>
+ * <p>
+ * Double buffering is used if {@link GLCapabilitiesImmutable#getDoubleBuffered() requested}.
+ * </p>
+ * <p>
+ * In MSAA mode, it always uses the implicit 2nd {@link FBObject framebuffer} {@link FBObject#getSamplingSinkFBO() sink}.
+ * Hence double buffering is always the case w/ MSAA.
+ * </p>
+ * <p>
+ * In non MSAA a second explicit {@link FBObject framebuffer} is being used.
+ * This method allows compliance w/ the spec, i.e. read and draw framebuffer selection
+ * and double buffer usage for e.g. {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer) glReadPixels(..)}.
+ * This method also allows usage of both textures seperately.
+ * </p>
+ * <p>
+ * It would be possible to implement double buffering simply using
+ * {@link Colorbuffer}s with one {@link FBObject framebuffer}.
+ * This would require mode selection and hence complicate the API. Besides, it would
+ * not support differentiation of read and write framebuffer and hence not be spec compliant.
+ * </p>
+ * <p>
+ * Actual swapping of the {@link Colorbuffer}s and/or {@link FBObject framebuffer}
+ * is performed either in the {@link jogamp.opengl.GLContextImpl#contextMadeCurrent(boolean) context current hook}
+ * or when {@link jogamp.opengl.GLDrawableImpl#swapBuffersImpl(boolean) swapping buffers}, whatever comes first.
+ * </p>
+ */
+public interface GLFBODrawable extends GLDrawable {
+ // public enum DoubleBufferMode { NONE, TEXTURE, FBO }; // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+
+ /** FBO Mode Bit: Use a {@link TextureAttachment} for the {@link #getColorbuffer(int) render colorbuffer}, see {@link #setFBOMode(int)}. */
+ public static final int FBOMODE_USE_TEXTURE = 1 << 0;
+
+ /**
+ * @return <code>true</code> if initialized, i.e. a {@link GLContext} is bound and made current once, otherwise <code>false</code>.
+ */
+ public boolean isInitialized();
+
+ /**
+ * Set the FBO mode bits used for FBO creation.
+ * <p>
+ * Default value is: {@link #FBOMODE_USE_TEXTURE}.
+ * </p>
+ * <p>
+ * If {@link GLRendererQuirks#BuggyColorRenderbuffer} is set,
+ * {@link #FBOMODE_USE_TEXTURE} is always added at initialization.
+ * </p>
+ *
+ * @param modeBits custom FBO mode bits like {@link #FBOMODE_USE_TEXTURE}.
+ * @throws IllegalStateException if already initialized, see {@link #isInitialized()}.
+ */
+ void setFBOMode(final int modeBits) throws IllegalStateException;
+
+ /**
+ * @return the used FBO mode bits, mutable via {@link #setFBOMode(int)}
+ */
+ int getFBOMode();
+
+ /**
+ * Notify this instance about upstream size change
+ * to reconfigure the {@link FBObject}.
+ * @param gl GL context object bound to this drawable, will be made current during operation.
+ * A prev. current context will be make current after operation.
+ * @throws GLException if resize operation failed
+ */
+ void resetSize(final GL gl) throws GLException;
+
+ /**
+ * @return the used texture unit
+ */
+ int getTextureUnit();
+
+ /**
+ *
+ * @param unit the texture unit to be used
+ */
+ void setTextureUnit(final int unit);
+
+ /**
+ * Set the number of sample buffers if using MSAA
+ *
+ * @param gl GL context object bound to this drawable, will be made current during operation.
+ * A prev. current context will be make current after operation.
+ * @param newSamples new sample size
+ * @throws GLException if resetting the FBO failed
+ */
+ void setNumSamples(final GL gl, final int newSamples) throws GLException;
+
+ /**
+ * @return the number of sample buffers if using MSAA, otherwise 0
+ */
+ int getNumSamples();
+
+ /**
+ * Sets the number of buffers (FBO) being used if using {@link GLCapabilities#getDoubleBuffered() double buffering}.
+ * <p>
+ * If {@link GLCapabilities#getDoubleBuffered() double buffering} is not chosen, this is a NOP.
+ * </p>
+ * <p>
+ * Must be called before {@link #isInitialized() initialization}, otherwise an exception is thrown.
+ * </p>
+ * @return the new number of buffers (FBO) used, maybe different than the requested <code>bufferCount</code> (see above)
+ * @throws IllegalStateException if already initialized, see {@link #isInitialized()}.
+ */
+ int setNumBuffers(final int bufferCount) throws IllegalStateException, GLException;
+
+ /**
+ * @return the number of buffers (FBO) being used. 1 if not using {@link GLCapabilities#getDoubleBuffered() double buffering},
+ * otherwise &ge; 2, depending on {@link #setNumBuffers(int)}.
+ */
+ int getNumBuffers();
+
+ /**
+ * @return the used {@link DoubleBufferMode}
+ */
+ // DoubleBufferMode getDoubleBufferMode(); // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+
+ /**
+ * Sets the {@link DoubleBufferMode}. Must be called before {@link #isInitialized() initialization},
+ * otherwise an exception is thrown.
+ * <p>
+ * This call has no effect is MSAA is selected, since MSAA always forces the mode to {@link DoubleBufferMode#FBO FBO}.
+ * Also setting the mode to {@link DoubleBufferMode#NONE NONE} where double buffering is {@link GLCapabilitiesImmutable#getDoubleBuffered() requested}
+ * or setting a double buffering mode w/o {@link GLCapabilitiesImmutable#getDoubleBuffered() request} will be ignored.
+ * </p>
+ * <p>
+ * Since {@link DoubleBufferMode#TEXTURE TEXTURE} mode is currently not implemented, this method has no effect.
+ * </p>
+ * @throws GLException if already initialized, see {@link #isInitialized()}.
+ */
+ // void setDoubleBufferMode(DoubleBufferMode mode) throws GLException; // TODO: Add or remove TEXTURE (only) DoubleBufferMode support
+
+ /**
+ * If MSAA is being used and {@link GL#GL_FRONT} is requested,
+ * the internal {@link FBObject} {@link FBObject#getSamplingSinkFBO() sample sink} is being returned.
+ *
+ * @param bufferName {@link GL#GL_FRONT} and {@link GL#GL_BACK} are valid buffer names
+ * @return the named {@link FBObject}
+ * @throws IllegalArgumentException if an illegal buffer name is being used
+ */
+ FBObject getFBObject(final int bufferName) throws IllegalArgumentException;
+
+ /**
+ * Returns the named {@link Colorbuffer} instance.
+ * <p>
+ * If MSAA is being used, only the {@link GL#GL_FRONT} buffer is accessible
+ * and an exception is being thrown if {@link GL#GL_BACK} is being requested.
+ * </p>
+ * <p>
+ * Depending on the {@link #setFBOMode(int) fbo mode} the resulting {@link Colorbuffer}
+ * is either a {@link TextureAttachment} if {@link #FBOMODE_USE_TEXTURE} is set,
+ * otherwise a {@link ColorAttachment}.
+ * See {@link Colorbuffer#isTextureAttachment()}.
+ * </p>
+ * @param bufferName {@link GL#GL_FRONT} and {@link GL#GL_BACK} are valid buffer names
+ * @return the named {@link Colorbuffer}
+ * @throws IllegalArgumentException if using MSAA and {@link GL#GL_BACK} is requested or an illegal buffer name is being used
+ */
+ Colorbuffer getColorbuffer(final int bufferName) throws IllegalArgumentException;
+
+ /** Resizeable {@link GLFBODrawable} specialization */
+ public interface Resizeable extends GLFBODrawable {
+ /**
+ * Resize this {@link GLFBODrawable}'s surface.
+ * <p>
+ * This drawable is being locked during operation.
+ * </p>
+ * @param context the {@link GLContext} bound to this drawable, will be made current during operation
+ * A prev. current context will be make current after operation.
+ * @param newWidth new width in pixel units
+ * @param newHeight new width in pixel units
+ * @throws NativeWindowException in case the surface could no be locked
+ * @throws GLException in case an error during the resize operation occurred
+ */
+ void setSurfaceSize(GLContext context, int newWidth, int newHeight) throws NativeWindowException, GLException;
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLOffscreenAutoDrawable.java b/src/jogl/classes/com/jogamp/opengl/GLOffscreenAutoDrawable.java
new file mode 100644
index 000000000..a2d0f5fdb
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLOffscreenAutoDrawable.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl;
+
+import com.jogamp.nativewindow.NativeWindowException;
+
+import com.jogamp.opengl.FBObject;
+
+/**
+ * Platform-independent {@link GLAutoDrawable} specialization,
+ * exposing offscreen functionality.
+ * <p>
+ * This class distinguishes itself from {@link GLAutoDrawable}
+ * with it's {@link #setSurfaceSize(int, int)} functionality.
+ * </p>
+ * <p>
+ * <a name="contextSharing"><h5>OpenGL Context Sharing</h5></a>
+ * To share a {@link GLContext} see the following note in the documentation overview:
+ * <a href="../../../overview-summary.html#SHARING">context sharing</a>
+ * as well as {@link GLSharedContextSetter}.
+ * </p>
+ */
+public interface GLOffscreenAutoDrawable extends GLAutoDrawable, GLSharedContextSetter {
+
+ /**
+ * Resize this {@link GLAutoDrawable}'s surface
+ * @param newWidth new width in pixel units
+ * @param newHeight new height in pixel units
+ * @throws NativeWindowException in case the surface could no be locked
+ * @throws GLException in case of an error during the resize operation
+ */
+ void setSurfaceSize(int newWidth, int newHeight) throws NativeWindowException, GLException;
+
+ /**
+ * Set the upstream UI toolkit object.
+ * @see #getUpstreamWidget()
+ */
+ void setUpstreamWidget(Object newUpstreamWidget);
+
+ /** {@link FBObject} based {@link GLOffscreenAutoDrawable} specialization */
+ public interface FBO extends GLOffscreenAutoDrawable, GLFBODrawable {
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLPipelineFactory.java b/src/jogl/classes/com/jogamp/opengl/GLPipelineFactory.java
new file mode 100644
index 000000000..8d8b0428b
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLPipelineFactory.java
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ */
+
+package com.jogamp.opengl;
+
+import java.lang.reflect.*;
+import java.util.StringTokenizer;
+
+import com.jogamp.common.util.ReflectionUtil;
+
+import jogamp.opengl.*;
+
+/**
+ * Factory for pipelining GL instances
+ */
+public class GLPipelineFactory {
+ public static final boolean DEBUG = Debug.debug("GLPipelineFactory");
+
+ /**
+ * Creates a pipelined GL instance using the given downstream <code>downstream</code>
+ * and optional arguments <code>additionalArgs</code> for the constructor.
+ *
+ * <p>
+ * Sample code which installs a Debug and Trace pipeline
+ * automatic w/ user defined interface, here: GL2ES2:
+ * <pre>
+ * gl = drawable.setGL( GLPipelineFactory.create("com.jogamp.opengl.Debug", GL2ES2.class, gl, null) );
+ * gl = drawable.setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", GL2ES2.class, gl, new Object[] { System.err } ) );
+ * </pre>
+ * or automatic w/ automatic defined class:
+ * <pre>
+ * gl = drawable.setGL( GLPipelineFactory.create("com.jogamp.opengl.Debug", null, gl, null) );
+ * gl = drawable.setGL( GLPipelineFactory.create("com.jogamp.opengl.Trace", null, gl, new Object[] { System.err } ) );
+ * </pre>
+ * </p>
+ *
+ * <p>
+ * The upstream GL instance is determined as follows:
+ * <ul>
+ * <li> Use <code>pipelineClazzBaseName</code> as the class name's full basename, incl. package name</li>
+ * <li> For the <code>downstream</code> class and it's superclasses, do:</li>
+ * <ul>
+ * <li> For all <code>downstream</code> class and superclass interfaces, do:</li>
+ * <ul>
+ * <li> If <code>reqInterface</code> is not null and the interface is unequal, continue loop.</li>
+ * <li> If <code>downstream</code> is not instance of interface, continue loop.</li>
+ * <li> If upstream class is available use it, end loop.</li>
+ * </ul>
+ * </ul>
+ * </ul>
+ * </p>
+ *
+ * @param pipelineClazzBaseName the basename of the pipline class name
+ * @param reqInterface optional requested interface to be used, may be null, in which case the first matching one is used
+ * @param downstream is always the 1st argument for the upstream constructor
+ * @param additionalArgs additional arguments for the upstream constructor
+ */
+ public static final GL create(final String pipelineClazzBaseName, final Class<?> reqInterface, final GL downstream, final Object[] additionalArgs) {
+ Class<?> downstreamClazz = downstream.getClass();
+ Class<?> upstreamClazz = null;
+ Class<?> interfaceClazz = null;
+
+ if(DEBUG) {
+ System.out.println("GLPipelineFactory: Start "+downstreamClazz.getName()+", req. Interface: "+reqInterface+" -> "+pipelineClazzBaseName);
+ }
+
+ // For all classes: child -> parent
+ do {
+ // For all interfaces: right -> left == child -> parent
+ // It is important that this matches with the gluegen cfg file's 'Implements' clause !
+ final Class<?>[] clazzes = downstreamClazz.getInterfaces();
+ for(int i=clazzes.length-1; null==upstreamClazz && i>=0; i--) {
+ if(DEBUG) {
+ System.out.println("GLPipelineFactory: Try "+downstreamClazz.getName()+" Interface["+i+"]: "+clazzes[i].getName());
+ }
+ if( reqInterface != null && !reqInterface.getName().equals(clazzes[i].getName()) ) {
+ if(DEBUG) {
+ System.out.println("GLPipelineFactory: requested Interface "+reqInterface+" is _not_ "+ clazzes[i].getName());
+ }
+ continue; // not the requested one ..
+ }
+ if( ! clazzes[i].isInstance(downstream) ) {
+ if(DEBUG) {
+ System.out.println("GLPipelineFactory: "+downstream.getClass().getName() + " is _not_ instance of "+ clazzes[i].getName());
+ }
+ continue; // not a compatible one
+ } else {
+ if(DEBUG) {
+ System.out.println("GLPipelineFactory: "+downstream.getClass().getName() + " _is_ instance of "+ clazzes[i].getName());
+ }
+ }
+ upstreamClazz = getUpstreamClazz(clazzes[i], pipelineClazzBaseName);
+ if( null != upstreamClazz ) {
+ interfaceClazz = clazzes[i];
+ }
+ }
+
+ if(null==upstreamClazz) {
+ downstreamClazz = downstreamClazz.getSuperclass();
+ }
+ } while (null!=downstreamClazz && null==upstreamClazz);
+
+
+ if(null==upstreamClazz) {
+ throw new GLException("No pipeline ("+pipelineClazzBaseName+"*) available for :"+downstream.getClass().getName());
+ }
+
+ if(DEBUG) {
+ System.out.println("GLPipelineFactory: Got : "+ upstreamClazz.getName()+", base interface: "+interfaceClazz.getName());
+ }
+
+ final Class<?>[] cstrArgTypes = new Class<?>[ 1 + ( ( null==additionalArgs ) ? 0 : additionalArgs.length ) ] ;
+ {
+ int i = 0;
+ cstrArgTypes[i++] = interfaceClazz;
+ for(int j=0; null!=additionalArgs && j<additionalArgs.length; j++) {
+ cstrArgTypes[i++] = additionalArgs[j].getClass();
+ }
+ }
+ // throws exception if cstr not found!
+ final Constructor<?> cstr = ReflectionUtil.getConstructor(upstreamClazz, cstrArgTypes);
+ Object instance = null;
+ try {
+ final Object[] cstrArgs = new Object[ 1 + ( ( null==additionalArgs ) ? 0 : additionalArgs.length ) ] ;
+ {
+ int i = 0;
+ cstrArgs[i++] = downstream;
+ for(int j=0; null!=additionalArgs && j<additionalArgs.length; j++) {
+ cstrArgs[i++] = additionalArgs[j];
+ }
+ }
+ instance = cstr.newInstance( cstrArgs ) ;
+ } catch (final Throwable t) { t.printStackTrace(); }
+ if(null==instance) {
+ throw new GLException("Error: Couldn't create instance of pipeline: "+upstreamClazz.getName()+
+ " ( "+getArgsClassNameList(downstreamClazz, additionalArgs) +" )");
+ }
+ if( ! (instance instanceof GL) ) {
+ throw new GLException("Error: "+upstreamClazz.getName()+" not an instance of GL");
+ }
+ return (GL) instance;
+ }
+
+ private static final String getArgsClassNameList(final Class<?> arg0, final Object[] args) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append(arg0.getName());
+ if(args!=null) {
+ for(int j=0; j<args.length; j++) {
+ sb.append(", ");
+ sb.append(args[j].getClass().getName());
+ }
+ }
+ return sb.toString();
+ }
+
+ private static final Class<?> getUpstreamClazz(final Class<?> downstreamClazz, final String pipelineClazzBaseName) {
+ final String downstreamClazzName = downstreamClazz.getName();
+
+ final StringTokenizer st = new StringTokenizer(downstreamClazzName, ".");
+ String downstreamClazzBaseName = downstreamClazzName;
+ while(st.hasMoreTokens()) {
+ downstreamClazzBaseName = st.nextToken();
+ }
+ final String upstreamClazzName = pipelineClazzBaseName+downstreamClazzBaseName;
+
+ Class<?> upstreamClazz = null;
+ try {
+ upstreamClazz = Class.forName(upstreamClazzName, true, GLPipelineFactory.class.getClassLoader());
+ } catch (final Throwable e) { e.printStackTrace(); }
+
+ return upstreamClazz;
+ }
+}
+
diff --git a/src/jogl/classes/com/jogamp/opengl/GLProfile.java b/src/jogl/classes/com/jogamp/opengl/GLProfile.java
new file mode 100644
index 000000000..a36a21ad5
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLProfile.java
@@ -0,0 +1,2322 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ */
+
+package com.jogamp.opengl;
+
+import jogamp.opengl.Debug;
+import jogamp.opengl.GLDrawableFactoryImpl;
+import jogamp.opengl.DesktopGLDynamicLookupHelper;
+
+import com.jogamp.common.ExceptionUtils;
+import com.jogamp.common.GlueGenVersion;
+import com.jogamp.common.jvm.JNILibLoaderBase;
+import com.jogamp.common.os.Platform;
+import com.jogamp.common.util.PropertyAccess;
+import com.jogamp.common.util.ReflectionUtil;
+import com.jogamp.common.util.VersionUtil;
+import com.jogamp.common.util.cache.TempJarCache;
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveThreadGroupLock;
+import com.jogamp.gluegen.runtime.FunctionAddressResolver;
+import com.jogamp.nativewindow.NativeWindowVersion;
+import com.jogamp.opengl.GLRendererQuirks;
+import com.jogamp.opengl.JoglVersion;
+
+import com.jogamp.nativewindow.AbstractGraphicsDevice;
+import com.jogamp.nativewindow.NativeWindowFactory;
+import com.jogamp.opengl.fixedfunc.GLPointerFunc;
+
+import java.lang.reflect.Constructor;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Specifies the the OpenGL profile.
+ *
+ * This class static singleton initialization queries the availability of all OpenGL Profiles
+ * and instantiates singleton GLProfile objects for each available profile.
+ *
+ * The platform default profile may be used, using {@link GLProfile#GetProfileDefault()},
+ * or more specialized versions using the other static GetProfile methods.
+ */
+public class GLProfile {
+
+ public static final boolean DEBUG;
+
+ /**
+ * In case no native OpenGL core profiles are required
+ * and if one platform may have a buggy implementation,
+ * setting the property <code>jogl.disable.openglcore</code> disables querying possible existing native OpenGL core profiles.
+ * <p>
+ * This exclusion is disabled for {@link Platform.OSType#MACOS}.
+ * </p>
+ */
+ public static final boolean disableOpenGLCore;
+
+ /**
+ * In case the implementation of the <i>ARB_create_context</i>
+ * context creation extension is buggy on one platform,
+ * setting the property <code>jogl.disable.openglarbcontext</code> disables utilizing it.
+ * <p>
+ * This exclusion also disables {@link #disableOpenGLES OpenGL ES}.
+ * </p>
+ * <p>
+ * This exclusion is disabled for {@link Platform.OSType#MACOS}.
+ * </p>
+ */
+ public static final boolean disableOpenGLARBContext;
+
+ /**
+ * In case no OpenGL ES profiles are required
+ * and if one platform may have a buggy implementation,
+ * setting the property <code>jogl.disable.opengles</code> disables querying possible existing OpenGL ES profiles.
+ */
+ public static final boolean disableOpenGLES;
+
+ /**
+ * In case no OpenGL desktop profiles are required
+ * and if one platform may have a buggy implementation,
+ * setting the property <code>jogl.disable.opengldesktop</code> disables querying possible existing OpenGL desktop profiles.
+ */
+ public static final boolean disableOpenGLDesktop;
+
+ /**
+ * Disable surfaceless OpenGL context capability and its probing
+ * by setting the property <code>jogl.disable.surfacelesscontext</code>.
+ * <p>
+ * By default surfaceless OpenGL context capability is probed,
+ * i.e. whether an OpenGL context can be made current without a default framebuffer.
+ * </p>
+ * <p>
+ * If probing fails or if this property is set, the {@link GLRendererQuirks quirk} {@link GLRendererQuirks#NoSurfacelessCtx}
+ * is being set.
+ * </p>
+ */
+ public static final boolean disableSurfacelessContext;
+
+ /**
+ * We have to disable support for ANGLE, the D3D ES2 emulation on Windows provided w/ Firefox and Chrome.
+ * When run in the mentioned browsers, the eglInitialize(..) implementation crashes.
+ * <p>
+ * This can be overridden by explicitly enabling ANGLE on Windows by setting the property
+ * <code>jogl.enable.ANGLE</code>.
+ * </p>
+ */
+ public static final boolean enableANGLE;
+
+ static {
+ // Also initializes TempJarCache if shall be used.
+ Platform.initSingleton();
+ final boolean isOSX = Platform.OSType.MACOS == Platform.getOSType();
+
+ DEBUG = Debug.debug("GLProfile");
+ disableOpenGLCore = PropertyAccess.isPropertyDefined("jogl.disable.openglcore", true) && !isOSX;
+ disableOpenGLARBContext = PropertyAccess.isPropertyDefined("jogl.disable.openglarbcontext", true) && !isOSX;
+ disableOpenGLES = disableOpenGLARBContext || PropertyAccess.isPropertyDefined("jogl.disable.opengles", true);
+ disableOpenGLDesktop = PropertyAccess.isPropertyDefined("jogl.disable.opengldesktop", true);
+ disableSurfacelessContext = PropertyAccess.isPropertyDefined("jogl.disable.surfacelesscontext", true);
+ enableANGLE = PropertyAccess.isPropertyDefined("jogl.enable.ANGLE", true);
+ }
+
+ /**
+ * @return <code>true</code> if JOGL has been initialized, i.e. manually via {@link #initSingleton()} or implicit,
+ * otherwise returns <code>false</code>.
+ *
+ * @since 2.2.1
+ */
+ public static boolean isInitialized() {
+ initLock.lock();
+ try {
+ return initialized;
+ } finally {
+ initLock.unlock();
+ }
+ }
+
+ /**
+ * Static initialization of JOGL.
+ *
+ * <p>
+ * This method shall not need to be called for other reasons than having a defined initialization sequence.
+ * </p>
+ *
+ * <P>
+ * In case this method is not invoked, GLProfile is initialized implicit by
+ * the first call to {@link #getDefault()}, {@link #get(java.lang.String)}.
+ * <P>
+ *
+ * <p>
+ * To initialize JOGL at startup ASAP, this method may be invoked in the <i>main class</i>'s
+ * static initializer block, in the <i>static main() method</i> or in the <i>Applet init() method</i>.
+ * </p>
+ *
+ * <p>
+ * Since JOGL's initialization is complex and involves multi threading, it is <b>not</b> recommended
+ * to be have it invoked on the AWT EDT thread. In case all JOGL usage is performed
+ * on the AWT EDT, invoke this method outside the AWT EDT - see above.
+ * </p>
+ *
+ */
+ public static void initSingleton() {
+ final boolean justInitialized;
+ initLock.lock();
+ try {
+ if(!initialized) {
+ initialized = true;
+ justInitialized = true;
+ if(DEBUG) {
+ System.err.println("GLProfile.initSingleton() - thread "+Thread.currentThread().getName());
+ ExceptionUtils.dumpStack(System.err);
+ }
+
+ if(ReflectionUtil.DEBUG_STATS_FORNAME) {
+ ReflectionUtil.resetForNameCount();
+ }
+
+ // run the whole static initialization privileged to speed up,
+ // since this skips checking further access
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
+ public Object run() {
+ Platform.initSingleton();
+
+ if(TempJarCache.isInitialized()) {
+ final ClassLoader cl = GLProfile.class.getClassLoader();
+ final String newtDebugClassName = "jogamp.newt.Debug";
+ final Class<?>[] classesFromJavaJars = new Class<?>[] { jogamp.nativewindow.Debug.class, jogamp.opengl.Debug.class, null };
+ if( ReflectionUtil.isClassAvailable(newtDebugClassName, cl) ) {
+ classesFromJavaJars[2] = ReflectionUtil.getClass(newtDebugClassName, false, cl);
+ }
+ JNILibLoaderBase.addNativeJarLibsJoglCfg(classesFromJavaJars);
+ }
+ initProfilesForDefaultDevices();
+ return null;
+ }
+ });
+ if( ReflectionUtil.DEBUG_STATS_FORNAME ) {
+ if( justInitialized ) {
+ System.err.println(ReflectionUtil.getForNameStats(null).toString());
+ }
+ }
+ } else {
+ justInitialized = false;
+ }
+ } finally {
+ initLock.unlock();
+ }
+ if(DEBUG) {
+ if( justInitialized && ( hasGL234Impl || hasGLES1Impl || hasGLES3Impl ) ) {
+ System.err.println(JoglVersion.getDefaultOpenGLInfo(defaultDevice, null, true));
+ }
+ }
+ }
+
+ /**
+ * Trigger eager initialization of GLProfiles for the given device,
+ * in case it isn't done yet.
+ *
+ * @throws GLException if no profile for the given device is available.
+ */
+ public static void initProfiles(final AbstractGraphicsDevice device) throws GLException {
+ getProfileMap(device, true);
+ }
+
+ /**
+ * Manual shutdown method, may be called after your last JOGL use
+ * within the running JVM.<br>
+ * It releases all temporary created resources, ie issues {@link com.jogamp.opengl.GLDrawableFactory#shutdown()}.<br>
+ * The shutdown implementation is called via the JVM shutdown hook, if not manually invoked.<br>
+ * <p>
+ * This method shall not need to be called for other reasons than issuing a proper shutdown of resources at a defined time.
+ * </p>
+ */
+ public static void shutdown() {
+ initLock.lock();
+ try {
+ if(initialized) {
+ initialized = false;
+ if(DEBUG) {
+ System.err.println("GLProfile.shutdown() - thread "+Thread.currentThread().getName());
+ ExceptionUtils.dumpStack(System.err);
+ }
+ GLDrawableFactory.shutdown();
+ }
+ } finally {
+ initLock.unlock();
+ }
+ }
+
+ //
+ // Query platform available OpenGL implementation
+ //
+
+ /**
+ * Returns the availability of a profile on a device.
+ *
+ * @param device a valid AbstractGraphicsDevice, or <code>null</null> for the default device.
+ * @param profile a valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..),
+ * or <code>[ null, GL ]</code> for the default profile.
+ * @return true if the profile is available for the device, otherwise false.
+ */
+ public static boolean isAvailable(final AbstractGraphicsDevice device, final String profile) {
+ initSingleton();
+ return isAvailableImpl(getProfileMap(device, false), profile);
+ }
+ private static boolean isAvailableImpl(final HashMap<String /*GLProfile_name*/, GLProfile> map, final String profile) {
+ return null != map && null != map.get(profile);
+ }
+
+ /**
+ * Returns the availability of a profile on the default device.
+ *
+ * @param profile a valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..),
+ * or <code>[ null, GL ]</code> for the default profile.
+ * @return true if the profile is available for the default device, otherwise false.
+ */
+ public static boolean isAvailable(final String profile) {
+ return isAvailable(null, profile);
+ }
+
+ /**
+ * Returns the availability of any profile on the default device.
+ *
+ * @return true if any profile is available for the default device, otherwise false.
+ */
+ public static boolean isAnyAvailable() {
+ return isAvailable(null, null);
+ }
+
+ public static String glAvailabilityToString(final AbstractGraphicsDevice device) {
+ return glAvailabilityToString(device, null).toString();
+ }
+
+ public static StringBuilder glAvailabilityToString(final AbstractGraphicsDevice device, final StringBuilder sb) {
+ return glAvailabilityToString(device, sb, null, 0);
+ }
+ private static StringBuilder doIndent(final StringBuilder sb, final String indent, int indentCount) {
+ while(indentCount>0) {
+ sb.append(indent);
+ indentCount--;
+ }
+ return sb;
+ }
+ public static StringBuilder glAvailabilityToString(AbstractGraphicsDevice device, StringBuilder sb, final String indent, int indentCount) {
+ boolean avail;
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
+ final boolean useIndent = null != indent;
+
+ initSingleton();
+
+ int allCount = 0;
+ int nativeCount = 0;
+
+ if(null==device) {
+ device = defaultDevice;
+ }
+ final HashMap<String /*GLProfile_name*/, GLProfile> map = getProfileMap(device, false);
+
+ if(useIndent) {
+ doIndent(sb, indent, indentCount).append("Natives");
+ indentCount++;
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append(GL4bc+" ").append(indent);
+ } else {
+ sb.append("Natives["+GL4bc+" ");
+ }
+ avail=isAvailableImpl(map, GL4bc);
+ sb.append(avail);
+ if(avail) {
+ nativeCount++;
+ glAvailabilityToString(device, sb.append(" "), 4, GLContext.CTX_PROFILE_COMPAT);
+ }
+ allCount++;
+
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append(GL4+" ").append(indent);
+ } else {
+ sb.append(", "+GL4+" ");
+ }
+ avail=isAvailableImpl(map, GL4);
+ sb.append(avail);
+ if(avail) {
+ nativeCount++;
+ glAvailabilityToString(device, sb.append(" "), 4, GLContext.CTX_PROFILE_CORE);
+ }
+ allCount++;
+
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append(GLES3+" ").append(indent);
+ } else {
+ sb.append(", "+GLES3+" ");
+ }
+ avail=isAvailableImpl(map, GLES3);
+ sb.append(avail);
+ if(avail) {
+ nativeCount++;
+ glAvailabilityToString(device, sb.append(" "), 3, GLContext.CTX_PROFILE_ES);
+ }
+ allCount++;
+
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append(GL3bc+" ").append(indent);
+ } else {
+ sb.append(", "+GL3bc+" ");
+ }
+ avail=isAvailableImpl(map, GL3bc);
+ sb.append(avail);
+ if(avail) {
+ nativeCount++;
+ glAvailabilityToString(device, sb.append(" "), 3, GLContext.CTX_PROFILE_COMPAT);
+ }
+ allCount++;
+
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append(GL3+" ").append(indent);
+ } else {
+ sb.append(", "+GL3+" ");
+ }
+ avail=isAvailableImpl(map, GL3);
+ sb.append(avail);
+ if(avail) {
+ nativeCount++;
+ glAvailabilityToString(device, sb.append(" "), 3, GLContext.CTX_PROFILE_CORE);
+ }
+ allCount++;
+
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append(GL2+" ").append(indent);
+ } else {
+ sb.append(", "+GL2+" ");
+ }
+ avail=isAvailableImpl(map, GL2);
+ sb.append(avail);
+ if(avail) {
+ nativeCount++;
+ glAvailabilityToString(device, sb.append(" "), 2, GLContext.CTX_PROFILE_COMPAT);
+ }
+ allCount++;
+
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append(GLES2+" ").append(indent);
+ } else {
+ sb.append(", "+GLES2+" ");
+ }
+ avail=isAvailableImpl(map, GLES2);
+ sb.append(avail);
+ if(avail) {
+ nativeCount++;
+ glAvailabilityToString(device, sb.append(" "), 2, GLContext.CTX_PROFILE_ES);
+ }
+ allCount++;
+
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append(GLES1+" ").append(indent);
+ } else {
+ sb.append(", "+GLES1+" ");
+ }
+ avail=isAvailableImpl(map, GLES1);
+ sb.append(avail);
+ if(avail) {
+ nativeCount++;
+ glAvailabilityToString(device, sb.append(" "), 1, GLContext.CTX_PROFILE_ES);
+ }
+ allCount++;
+
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("Count\t"+nativeCount+" / "+allCount);
+ indentCount--;
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("Common");
+ indentCount++;
+ } else {
+ sb.append(", count "+nativeCount+" / "+allCount+"], Common[");
+ }
+
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append(GL4ES3+" ").append(indent);
+ } else {
+ sb.append(", "+GL4ES3+" ");
+ }
+ sb.append(isAvailableImpl(map, GL4ES3));
+ allCount++;
+
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append(GL2GL3+" ").append(indent);
+ } else {
+ sb.append(", "+GL2GL3+" ");
+ }
+ sb.append(isAvailableImpl(map, GL2GL3));
+ allCount++;
+
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append(GL2ES2+" ").append(indent);
+ } else {
+ sb.append(", "+GL2ES2+" ");
+ }
+ sb.append(isAvailableImpl(map, GL2ES2));
+ allCount++;
+
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append(GL2ES1+" ").append(indent);
+ } else {
+ sb.append(", "+GL2ES1+" ");
+ }
+ sb.append(isAvailableImpl(map, GL2ES1));
+ allCount++;
+
+ if(useIndent) {
+ indentCount--;
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("Mappings");
+ indentCount++;
+ } else {
+ sb.append("], Mappings[");
+ }
+
+ int profileCount = 0;
+
+ if(null != map) {
+ for (final Map.Entry<String,GLProfile> entry : map.entrySet()) {
+ if( GL_DEFAULT != entry.getKey() ) {
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount);
+ }
+ sb.append(entry.getKey()+(useIndent?" \t":" ")+entry.getValue());
+ if(!useIndent) {
+ sb.append(", ");
+ }
+ profileCount++;
+ }
+ }
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("default ");
+ } else {
+ sb.append(", default ");
+ }
+ try {
+ sb.append(getDefault(device));
+ } catch (final GLException gle) {
+ sb.append("n/a");
+ }
+ }
+ if(useIndent) {
+ doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("Count\t"+profileCount+" / "+allCount);
+ sb.append(Platform.getNewline());
+ } else {
+ sb.append(", count "+profileCount+" / "+allCount+"]");
+ }
+
+ return sb;
+ }
+
+ /** Uses the default device */
+ public static String glAvailabilityToString() {
+ return glAvailabilityToString(null);
+ }
+
+ //
+ // Public (user-visible) profiles
+ //
+
+ /** The desktop OpenGL compatibility profile 4.x, with x >= 0, ie GL2 plus GL4.<br>
+ <code>bc</code> stands for backward compatibility. */
+ public static final String GL4bc = "GL4bc"; // Implicitly intern(), see Bug 1059
+
+ /** The desktop OpenGL core profile 4.x, with x >= 0 */
+ public static final String GL4 = "GL4"; // Implicitly intern(), see Bug 1059
+
+ /** The desktop OpenGL compatibility profile 3.x, with x >= 1, ie GL2 plus GL3.<br>
+ <code>bc</code> stands for backward compatibility. */
+ public static final String GL3bc = "GL3bc"; // Implicitly intern(), see Bug 1059
+
+ /** The desktop OpenGL core profile 3.x, with x >= 1 */
+ public static final String GL3 = "GL3"; // Implicitly intern(), see Bug 1059
+
+ /** The desktop OpenGL profile 1.x up to 3.0 */
+ public static final String GL2 = "GL2"; // Implicitly intern(), see Bug 1059
+
+ /** The embedded OpenGL profile ES 1.x, with x >= 0 */
+ public static final String GLES1 = "GLES1"; // Implicitly intern(), see Bug 1059
+
+ /** The embedded OpenGL profile ES 2.x, with x >= 0 */
+ public static final String GLES2 = "GLES2"; // Implicitly intern(), see Bug 1059
+
+ /** The embedded OpenGL profile ES 3.x, with x >= 0 */
+ public static final String GLES3 = "GLES3"; // Implicitly intern(), see Bug 1059
+
+ /** The intersection of the desktop GL2 and embedded ES1 profile */
+ public static final String GL2ES1 = "GL2ES1"; // Implicitly intern(), see Bug 1059
+
+ /** The intersection of the desktop GL3, GL2 and embedded ES2 profile */
+ public static final String GL2ES2 = "GL2ES2"; // Implicitly intern(), see Bug 1059
+
+ /** The intersection of the desktop GL3 and GL2 profile */
+ public static final String GL2GL3 = "GL2GL3"; // Implicitly intern(), see Bug 1059
+
+ /** The intersection of the desktop GL4 and ES3 profile, available only if either ES3 or GL4 w/ <code>GL_ARB_ES3_compatibility</code> is available. */
+ public static final String GL4ES3 = "GL4ES3"; // Implicitly intern(), see Bug 1059
+
+ /** The default profile, used for the device default profile map */
+ private static final String GL_DEFAULT = "GL_DEFAULT"; // Implicitly intern(), see Bug 1059
+ /** The default profile, used for the device default profile map */
+ private static final String GL_GL = "GL"; // Implicitly intern(), see Bug 1059
+
+ /**
+ * All GL Profiles in the order of default detection.
+ * Desktop compatibility profiles (the one with fixed function pipeline) comes first
+ * from highest to lowest version.
+ * <p> This includes the generic subset profiles GL2GL3, GL2ES2 and GL2ES1.</p>
+ *
+ * <ul>
+ * <li> GL4bc </li>
+ * <li> GL3bc </li>
+ * <li> GL2 </li>
+ * <li> GL4 </li>
+ * <li> GL3 </li>
+ * <li> GLES3 </li>
+ * <li> GL4ES3 </li>
+ * <li> GL2GL3 </li>
+ * <li> GLES2 </li>
+ * <li> GL2ES2 </li>
+ * <li> GLES1 </li>
+ * <li> GL2ES1 </li>
+ * </ul>
+ *
+ */
+ public static final String[] GL_PROFILE_LIST_ALL = new String[] { GL4bc, GL3bc, GL2, GL4, GL3, GLES3, GL4ES3, GL2GL3, GLES2, GL2ES2, GLES1, GL2ES1 };
+
+ /**
+ * Order of maximum profiles.
+ *
+ * <ul>
+ * <li> GL4bc </li>
+ * <li> GL4 </li>
+ * <li> GL3bc </li>
+ * <li> GL3 </li>
+ * <li> GLES3 </li>
+ * <li> GL2 </li>
+ * <li> GLES2 </li>
+ * <li> GLES1 </li>
+ * </ul>
+ *
+ */
+ public static final String[] GL_PROFILE_LIST_MAX = new String[] { GL4bc, GL4, GL3bc, GL3, GLES3, GL2, GLES2, GLES1 };
+
+ /**
+ * Order of minimum profiles.
+ *
+ * <ul>
+ * <li> GLES1 </li>
+ * <li> GLES2 </li>
+ * <li> GL2 </li>
+ * <li> GLES3 </li>
+ * <li> GL3 </li>
+ * <li> GL3bc </li>
+ * <li> GL4 </li>
+ * <li> GL4bc </li>
+ * </ul>
+ *
+ */
+ public static final String[] GL_PROFILE_LIST_MIN = new String[] { GLES1, GLES2, GL2, GLES3, GL3, GL3bc, GL4, GL4bc };
+
+ /**
+ * Order of minimum original desktop profiles.
+ *
+ * <ul>
+ * <li> GL2 </li>
+ * <li> GL3bc </li>
+ * <li> GL4bc </li>
+ * <li> GL3 </li>
+ * <li> GL4 </li>
+ * </ul>
+ *
+ */
+ public static final String[] GL_PROFILE_LIST_MIN_DESKTOP = new String[] { GL2, GL3bc, GL4bc, GL3, GL4 };
+
+ /**
+ * Order of maximum fixed function profiles
+ *
+ * <ul>
+ * <li> GL4bc </li>
+ * <li> GL3bc </li>
+ * <li> GL2 </li>
+ * <li> GLES1 </li>
+ * </ul>
+ *
+ */
+ public static final String[] GL_PROFILE_LIST_MAX_FIXEDFUNC = new String[] { GL4bc, GL3bc, GL2, GLES1 };
+
+ /**
+ * Order of maximum programmable shader profiles
+ *
+ * <ul>
+ * <li> GL4bc </li>
+ * <li> GL4 </li>
+ * <li> GL3bc </li>
+ * <li> GL3 </li>
+ * <li> GLES3 </li>
+ * <li> GL2 </li>
+ * <li> GLES2 </li>
+ * </ul>
+ *
+ */
+ public static final String[] GL_PROFILE_LIST_MAX_PROGSHADER = new String[] { GL4bc, GL4, GL3bc, GL3, GLES3, GL2, GLES2 };
+
+ /**
+ * Order of maximum programmable shader <i>core only</i> profiles
+ *
+ * <ul>
+ * <li> GL4 </li>
+ * <li> GL3 </li>
+ * <li> GLES3 </li>
+ * <li> GLES2 </li>
+ * </ul>
+ *
+ */
+ public static final String[] GL_PROFILE_LIST_MAX_PROGSHADER_CORE = new String[] { GL4, GL3, GLES3, GLES2 };
+
+ /** Returns a default GLProfile object, reflecting the best for the running platform.
+ * It selects the first of the set {@link GLProfile#GL_PROFILE_LIST_ALL}
+ * and favors hardware acceleration.
+ * @throws GLException if no profile is available for the device.
+ * @see #GL_PROFILE_LIST_ALL
+ */
+ public static GLProfile getDefault(final AbstractGraphicsDevice device) {
+ final GLProfile glp = get(device, GL_DEFAULT);
+ return glp;
+ }
+
+ /** Returns a default GLProfile object, reflecting the best for the running platform.
+ * It selects the first of the set {@link GLProfile#GL_PROFILE_LIST_ALL}
+ * and favors hardware acceleration.
+ * <p>Uses the default device.</p>
+ * @throws GLException if no profile is available for the default device.
+ */
+ public static GLProfile getDefault() {
+ return getDefault(defaultDevice);
+ }
+
+ /**
+ * Returns the highest profile.
+ * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX}
+ *
+ * @throws GLException if no profile is available for the device.
+ * @see #GL_PROFILE_LIST_MAX
+ */
+ public static GLProfile getMaximum(final AbstractGraphicsDevice device, final boolean favorHardwareRasterizer)
+ throws GLException
+ {
+ return get(device, GL_PROFILE_LIST_MAX, favorHardwareRasterizer);
+ }
+
+ /** Uses the default device
+ * @throws GLException if no profile is available for the default device.
+ * @see #GL_PROFILE_LIST_MAX
+ */
+ public static GLProfile getMaximum(final boolean favorHardwareRasterizer)
+ throws GLException
+ {
+ return get(GL_PROFILE_LIST_MAX, favorHardwareRasterizer);
+ }
+
+ /**
+ * Returns the lowest profile.
+ * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MIN}
+ *
+ * @throws GLException if no desktop profile is available for the device.
+ * @see #GL_PROFILE_LIST_MIN
+ */
+ public static GLProfile getMinimum(final AbstractGraphicsDevice device, final boolean favorHardwareRasterizer)
+ throws GLException
+ {
+ return get(device, GL_PROFILE_LIST_MIN, favorHardwareRasterizer);
+ }
+
+ /** Uses the default device
+ * @throws GLException if no desktop profile is available for the default device.
+ * @see #GL_PROFILE_LIST_MIN
+ */
+ public static GLProfile getMinimum(final boolean favorHardwareRasterizer)
+ throws GLException
+ {
+ return get(GL_PROFILE_LIST_MIN, favorHardwareRasterizer);
+ }
+
+
+ /**
+ * Returns the highest profile, implementing the fixed function pipeline.
+ * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX_FIXEDFUNC}
+ *
+ * @throws GLException if no fixed function profile is available for the device.
+ * @see #GL_PROFILE_LIST_MAX_FIXEDFUNC
+ */
+ public static GLProfile getMaxFixedFunc(final AbstractGraphicsDevice device, final boolean favorHardwareRasterizer)
+ throws GLException
+ {
+ return get(device, GL_PROFILE_LIST_MAX_FIXEDFUNC, favorHardwareRasterizer);
+ }
+
+ /** Uses the default device
+ * @throws GLException if no fixed function profile is available for the default device.
+ * @see #GL_PROFILE_LIST_MAX_FIXEDFUNC
+ */
+ public static GLProfile getMaxFixedFunc(final boolean favorHardwareRasterizer)
+ throws GLException
+ {
+ return get(GL_PROFILE_LIST_MAX_FIXEDFUNC, favorHardwareRasterizer);
+ }
+
+ /**
+ * Returns the highest profile, implementing the programmable shader pipeline.
+ * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX_PROGSHADER}
+ *
+ * @throws GLException if no programmable profile is available for the device.
+ * @see #GL_PROFILE_LIST_MAX_PROGSHADER
+ */
+ public static GLProfile getMaxProgrammable(final AbstractGraphicsDevice device, final boolean favorHardwareRasterizer)
+ throws GLException
+ {
+ return get(device, GL_PROFILE_LIST_MAX_PROGSHADER, favorHardwareRasterizer);
+ }
+
+ /** Uses the default device
+ * @throws GLException if no programmable profile is available for the default device.
+ * @see #GL_PROFILE_LIST_MAX_PROGSHADER
+ */
+ public static GLProfile getMaxProgrammable(final boolean favorHardwareRasterizer)
+ throws GLException
+ {
+ return get(GL_PROFILE_LIST_MAX_PROGSHADER, favorHardwareRasterizer);
+ }
+
+ /**
+ * Returns the highest profile, implementing the programmable shader <i>core</i> pipeline <i>only</i>.
+ * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX_PROGSHADER_CORE}
+ *
+ * @throws GLException if no programmable core profile is available for the device.
+ * @see #GL_PROFILE_LIST_MAX_PROGSHADER_CORE
+ */
+ public static GLProfile getMaxProgrammableCore(final AbstractGraphicsDevice device, final boolean favorHardwareRasterizer)
+ throws GLException
+ {
+ return get(device, GL_PROFILE_LIST_MAX_PROGSHADER_CORE, favorHardwareRasterizer);
+ }
+
+ /** Uses the default device
+ * @throws GLException if no programmable core profile is available for the default device.
+ * @see #GL_PROFILE_LIST_MAX_PROGSHADER_CORE
+ */
+ public static GLProfile getMaxProgrammableCore(final boolean favorHardwareRasterizer)
+ throws GLException
+ {
+ return get(GL_PROFILE_LIST_MAX_PROGSHADER_CORE, favorHardwareRasterizer);
+ }
+
+ /**
+ * Returns the GL2ES1 profile implementation, hence compatible w/ GL2ES1.<br/>
+ * It returns:
+ * <pre>
+ * GLProfile.get(device, GLProfile.GL2ES1).getImpl());
+ * </pre>
+ * <p>Selection favors hardware rasterizer.</p>
+ *
+ * @throws GLException if no GL2ES1 compatible profile is available for the default device.
+ * @see #isGL2ES1()
+ * @see #get(AbstractGraphicsDevice, String)
+ * @see #getImpl()
+ */
+ public static GLProfile getGL2ES1(final AbstractGraphicsDevice device)
+ throws GLException
+ {
+ return get(device, GL2ES1).getImpl();
+ }
+
+ /**
+ * Calls {@link #getGL2ES1(AbstractGraphicsDevice)} using the default device.
+ * <p>Selection favors hardware rasterizer.</p>
+ * @see #getGL2ES1(AbstractGraphicsDevice)
+ */
+ public static GLProfile getGL2ES1()
+ throws GLException
+ {
+ return get(defaultDevice, GL2ES1).getImpl();
+ }
+
+ /**
+ * Returns the GL2ES2 profile implementation, hence compatible w/ GL2ES2.<br/>
+ * It returns:
+ * <pre>
+ * GLProfile.get(device, GLProfile.GL2ES2).getImpl());
+ * </pre>
+ * <p>Selection favors hardware rasterizer.</p>
+ *
+ * @throws GLException if no GL2ES2 compatible profile is available for the default device.
+ * @see #isGL2ES2()
+ * @see #get(AbstractGraphicsDevice, String)
+ * @see #getImpl()
+ */
+ public static GLProfile getGL2ES2(final AbstractGraphicsDevice device)
+ throws GLException
+ {
+ return get(device, GL2ES2).getImpl();
+ }
+
+ /**
+ * Calls {@link #getGL2ES2(AbstractGraphicsDevice)} using the default device.
+ * <p>Selection favors hardware rasterizer.</p>
+ * @see #getGL2ES2(AbstractGraphicsDevice)
+ */
+ public static GLProfile getGL2ES2()
+ throws GLException
+ {
+ return get(defaultDevice, GL2ES2).getImpl();
+ }
+
+ /**
+ * Returns the GL4ES3 profile implementation, hence compatible w/ GL4ES3.<br/>
+ * It returns:
+ * <pre>
+ * GLProfile.get(device, GLProfile.GL4ES3).getImpl());
+ * </pre>
+ * <p>Selection favors hardware rasterizer.</p>
+ *
+ * @throws GLException if no GL4ES3 compatible profile is available for the default device.
+ * @see #isGL4ES3()
+ * @see #get(AbstractGraphicsDevice, String)
+ * @see #getImpl()
+ */
+ public static GLProfile getGL4ES3(final AbstractGraphicsDevice device)
+ throws GLException
+ {
+ return get(device, GL4ES3).getImpl();
+ }
+
+ /**
+ * Calls {@link #getGL4ES3(AbstractGraphicsDevice)} using the default device.
+ * <p>Selection favors hardware rasterizer.</p>
+ * @see #getGL4ES3(AbstractGraphicsDevice)
+ */
+ public static GLProfile getGL4ES3()
+ throws GLException
+ {
+ return get(defaultDevice, GL4ES3).getImpl();
+ }
+
+ /**
+ * Returns the GL2GL3 profile implementation, hence compatible w/ GL2GL3.<br/>
+ * It returns:
+ * <pre>
+ * GLProfile.get(device, GLProfile.GL2GL3).getImpl());
+ * </pre>
+ * <p>Selection favors hardware rasterizer.</p>
+ *
+ * @throws GLException if no GL2GL3 compatible profile is available for the default device.
+ * @see #isGL2GL3()
+ * @see #get(AbstractGraphicsDevice, String)
+ * @see #getImpl()
+ */
+ public static GLProfile getGL2GL3(final AbstractGraphicsDevice device)
+ throws GLException
+ {
+ return get(device, GL2GL3).getImpl();
+ }
+
+ /**
+ * Calls {@link #getGL2GL3(AbstractGraphicsDevice)} using the default device.
+ * <p>Selection favors hardware rasterizer.</p>
+ * @see #getGL2GL3(AbstractGraphicsDevice)
+ */
+ public static GLProfile getGL2GL3()
+ throws GLException
+ {
+ return get(defaultDevice, GL2GL3).getImpl();
+ }
+
+ /** Returns a GLProfile object.
+ * verifies the given profile and chooses an appropriate implementation.
+ * A generic value of <code>null</code> or <code>GL</code> will result in
+ * the default profile.
+ *
+ * @param device a valid AbstractGraphicsDevice, or <code>null</null> for the default device.
+ * @param profile a valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..),
+ * or <code>[ null, GL ]</code> for the default profile.
+ * @throws GLException if the requested profile is not available for the device.
+ */
+ public static GLProfile get(final AbstractGraphicsDevice device, String profile)
+ throws GLException
+ {
+ if(null==profile || profile == GL_GL) {
+ profile = GL_DEFAULT;
+ }
+ final HashMap<String /*GLProfile_name*/, GLProfile> glpMap = getProfileMap(device, true);
+ final GLProfile glp = glpMap.get(profile);
+ if(null == glp) {
+ throw new GLException("Profile "+profile+" is not available on "+device+", but: "+glpMap.values());
+ }
+ return glp;
+ }
+
+ /** Uses the default device
+ * @param profile a valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..),
+ * or <code>[ null, GL ]</code> for the default profile.
+ * @throws GLException if the requested profile is not available for the default device.
+ */
+ public static GLProfile get(final String profile)
+ throws GLException
+ {
+ return get(defaultDevice, profile);
+ }
+
+ /**
+ * Returns the first profile from the given list,
+ * where an implementation is available.
+ *
+ * @param device a valid AbstractGraphicsDevice, or <code>null</null> for the default device.
+ * @param profiles array of valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..)
+ * @param favorHardwareRasterizer set to true, if hardware rasterizer shall be favored, otherwise false.
+ * @throws GLException if the non of the requested profiles is available for the device.
+ */
+ public static GLProfile get(final AbstractGraphicsDevice device, final String[] profiles, final boolean favorHardwareRasterizer)
+ throws GLException
+ {
+ GLProfile glProfileAny = null;
+
+ final HashMap<String /*GLProfile_name*/, GLProfile> map = getProfileMap(device, true);
+ for(int i=0; i<profiles.length; i++) {
+ final GLProfile glProfile = map.get(profiles[i]);
+ if(null!=glProfile) {
+ if(!favorHardwareRasterizer) {
+ return glProfile;
+ }
+ if(glProfile.isHardwareRasterizer()) {
+ return glProfile;
+ }
+ if(null==glProfileAny) {
+ glProfileAny = glProfile;
+ }
+ }
+ }
+ if(null!=glProfileAny) {
+ return glProfileAny;
+ }
+ throw new GLException("Profiles "+array2String(profiles)+" not available on device "+device);
+ }
+
+ /** Uses the default device
+ * @param profiles array of valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..)
+ * @param favorHardwareRasterizer set to true, if hardware rasterizer shall be favored, otherwise false.
+ * @throws GLException if the non of the requested profiles is available for the default device.
+ */
+ public static GLProfile get(final String[] profiles, final boolean favorHardwareRasterizer)
+ throws GLException
+ {
+ return get(defaultDevice, profiles, favorHardwareRasterizer);
+ }
+
+ /** Indicates whether the native OpenGL ES1 profile is in use.
+ * This requires an EGL interface.
+ */
+ public static boolean usesNativeGLES1(final String profileImpl) {
+ return GLES1 == profileImpl;
+ }
+
+ /** Indicates whether the native OpenGL ES3 or ES2 profile is in use.
+ * This requires an EGL, ES3 or ES2 compatible interface.
+ */
+ public static boolean usesNativeGLES2(final String profileImpl) {
+ return GLES3 == profileImpl || GLES2 == profileImpl;
+ }
+
+ /** Indicates whether the native OpenGL ES2 profile is in use.
+ * This requires an EGL, ES3 compatible interface.
+ */
+ public static boolean usesNativeGLES3(final String profileImpl) {
+ return GLES3 == profileImpl;
+ }
+
+ /** Indicates whether either of the native OpenGL ES profiles are in use. */
+ public static boolean usesNativeGLES(final String profileImpl) {
+ return usesNativeGLES2(profileImpl) || usesNativeGLES1(profileImpl);
+ }
+
+ /** @return {@link com.jogamp.nativewindow.NativeWindowFactory#isAWTAvailable()} and
+ JOGL's AWT part */
+ public static boolean isAWTAvailable() { return isAWTAvailable; }
+
+ public static String getGLTypeName(final int type) {
+ switch (type) {
+ case GL.GL_UNSIGNED_BYTE:
+ return "GL_UNSIGNED_BYTE";
+ case GL.GL_BYTE:
+ return "GL_BYTE";
+ case GL.GL_UNSIGNED_SHORT:
+ return "GL_UNSIGNED_SHORT";
+ case GL.GL_SHORT:
+ return "GL_SHORT";
+ case GL.GL_FLOAT:
+ return "GL_FLOAT";
+ case GL.GL_FIXED:
+ return "GL_FIXED";
+ case com.jogamp.opengl.GL2ES2.GL_INT:
+ return "GL_INT";
+ case GL.GL_UNSIGNED_INT:
+ return "GL_UNSIGNED_INT";
+ case com.jogamp.opengl.GL2GL3.GL_DOUBLE:
+ return "GL_DOUBLE";
+ case com.jogamp.opengl.GL2.GL_2_BYTES:
+ return "GL_2_BYTES";
+ case com.jogamp.opengl.GL2.GL_3_BYTES:
+ return "GL_3_BYTES";
+ case com.jogamp.opengl.GL2.GL_4_BYTES:
+ return "GL_4_BYTES";
+ }
+ return null;
+ }
+
+ public static String getGLArrayName(final int array) {
+ switch(array) {
+ case GLPointerFunc.GL_VERTEX_ARRAY:
+ return "GL_VERTEX_ARRAY";
+ case GLPointerFunc.GL_NORMAL_ARRAY:
+ return "GL_NORMAL_ARRAY";
+ case GLPointerFunc.GL_COLOR_ARRAY:
+ return "GL_COLOR_ARRAY";
+ case GLPointerFunc.GL_TEXTURE_COORD_ARRAY:
+ return "GL_TEXTURE_COORD_ARRAY";
+ }
+ return null;
+ }
+
+ public final String getGLImplBaseClassName() {
+ return getGLImplBaseClassName(getImplName());
+ }
+ private static final String getGLImplBaseClassName(final String profileImpl) {
+ if( GLES2 == profileImpl || GLES3 == profileImpl ) {
+ return "jogamp.opengl.es3.GLES3";
+ } else if( GLES1 == profileImpl ) {
+ return "jogamp.opengl.es1.GLES1";
+ } else if ( GL4bc == profileImpl ||
+ GL4 == profileImpl ||
+ GL3bc == profileImpl ||
+ GL3 == profileImpl ||
+ GL2 == profileImpl ) {
+ return "jogamp.opengl.gl4.GL4bc";
+ } else {
+ throw new GLException("unsupported profile \"" + profileImpl + "\"");
+ }
+ }
+
+ public final Constructor<?> getGLCtor(final boolean glObject) {
+ return getGLCtor(getImplName(), glObject);
+ }
+ private static final Constructor<?> getGLCtor(final String profileImpl, final boolean glObject) {
+ if( GLES2 == profileImpl || GLES3 == profileImpl ) {
+ return glObject ? ctorGLES3Impl : ctorGLES3ProcAddr;
+ } else if( GLES1 == profileImpl ) {
+ return glObject ? ctorGLES1Impl : ctorGLES1ProcAddr;
+ } else if ( GL4bc == profileImpl ||
+ GL4 == profileImpl ||
+ GL3bc == profileImpl ||
+ GL3 == profileImpl ||
+ GL2 == profileImpl ) {
+ return glObject ? ctorGL234Impl : ctorGL234ProcAddr;
+ } else {
+ throw new GLException("unsupported profile \"" + profileImpl + "\"");
+ }
+ }
+
+ /**
+ * @param o GLProfile object to compare with
+ * @return true if given Object is a GLProfile and
+ * if both, profile and profileImpl is equal with this.
+ */
+ @Override
+ public final boolean equals(final Object o) {
+ if(this==o) { return true; }
+ if(o instanceof GLProfile) {
+ final GLProfile glp = (GLProfile)o;
+ return getName() == glp.getName() && getImplName() == glp.getImplName() ; // uses .intern()!
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 5;
+ hash = 97 * hash + getImplName().hashCode();
+ hash = 97 * hash + getName().hashCode();
+ return hash;
+ }
+
+ /**
+ * @param glp GLProfile to compare with
+ * @throws GLException if given GLProfile and this aren't equal
+ */
+ public final void verifyEquality(final GLProfile glp) throws GLException {
+ if(!this.equals(glp)) {
+ throw new GLException("GLProfiles are not equal: "+this+" != "+glp);
+ }
+ }
+
+ /** return this profiles name */
+ public final String getName() {
+ return profile;
+ }
+
+ /** return this profiles implementation, eg. GL2ES2 -> GL2, or GL3 -> GL3 */
+ public final GLProfile getImpl() {
+ return null != profileImpl ? profileImpl : this;
+ }
+
+ /** return true if impl. is a hardware rasterizer, otherwise false. */
+ public final boolean isHardwareRasterizer() {
+ return isHardwareRasterizer;
+ }
+
+ /**
+ * return this profiles implementation name, eg. GL2ES2 -> GL2, or GL3 -> GL3
+ */
+ public final String getImplName() {
+ return null != profileImpl ? profileImpl.getName() : getName();
+ }
+
+ /** Indicates whether this profile is capable of GL4bc. <p>Includes [ GL4bc ].</p> */
+ public final boolean isGL4bc() {
+ return GL4bc == profile;
+ }
+
+ /** Indicates whether this profile is capable of GL4. <p>Includes [ GL4bc, GL4 ].</p> */
+ public final boolean isGL4() {
+ return isGL4bc() || GL4 == profile;
+ }
+
+ /** Indicates whether this profile is capable of GL3bc. <p>Includes [ GL4bc, GL3bc ].</p> */
+ public final boolean isGL3bc() {
+ return isGL4bc() || GL3bc == profile;
+ }
+
+ /** Indicates whether this profile is capable of GL3. <p>Includes [ GL4bc, GL4, GL3bc, GL3 ].</p> */
+ public final boolean isGL3() {
+ return isGL4() || isGL3bc() || GL3 == profile;
+ }
+
+ /** Indicates whether this profile is capable of GL2 . <p>Includes [ GL4bc, GL3bc, GL2 ].</p> */
+ public final boolean isGL2() {
+ return isGL3bc() || GL2 == profile;
+ }
+
+ /** Indicates whether this profile is capable of GLES1. <p>Includes [ GLES1 ].</p> */
+ public final boolean isGLES1() {
+ return GLES1 == profile;
+ }
+
+ /** Indicates whether this profile is capable of GLES2. <p>Includes [ GLES2, GLES3 ].</p> */
+ public final boolean isGLES2() {
+ return isGLES3() || GLES2 == profile;
+ }
+
+ /** Indicates whether this profile is capable of GLES3. <p>Includes [ GLES3 ].</p> */
+ public final boolean isGLES3() {
+ return GLES3 == profile;
+ }
+
+ /** Indicates whether this profile is capable of GLES. <p>Includes [ GLES1, GLES2, GLES3 ].</p> */
+ public final boolean isGLES() {
+ return GLES3 == profile || GLES2 == profile || GLES1 == profile;
+ }
+
+ /** Indicates whether this profile is capable of GL2ES1. <p>Includes [ GL4bc, GL3bc, GL2, GLES1, GL2ES1 ].</p> */
+ public final boolean isGL2ES1() {
+ return GL2ES1 == profile || isGLES1() || isGL2();
+ }
+
+ /** Indicates whether this profile is capable of GL2GL3. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GL2, GL2GL3 ].</p> */
+ public final boolean isGL2GL3() {
+ return GL2GL3 == profile || isGL3() || isGL2();
+ }
+
+ /** Indicates whether this profile is capable of GL2ES2. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GLES3, GL2, GL2GL3, GL2ES2, GLES2 ].</p> */
+ public final boolean isGL2ES2() {
+ return GL2ES2 == profile || isGLES2() || isGL2GL3();
+ }
+
+ /**
+ * Indicates whether this profile is capable of GL2ES3. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GLES3, GL3ES3, GL2, GL2GL3 ].</p>
+ * @see #isGL3ES3()
+ * @see #isGL2GL3()
+ */
+ public final boolean isGL2ES3() {
+ return isGL3ES3() || isGL2GL3();
+ }
+
+ /** Indicates whether this profile is capable of GL3ES3. <p>Includes [ GL4bc, GL4, GL3bc, GL3, GLES3 ].</p> */
+ public final boolean isGL3ES3() {
+ return isGL4ES3() || isGL3();
+ }
+
+ /** Indicates whether this profile is capable of GL4ES3. <p>Includes [ GL4bc, GL4, GLES3 ].</p> */
+ public final boolean isGL4ES3() {
+ return GL4ES3 == profile || isGLES3() || isGL4();
+ }
+
+ /** Indicates whether this profile supports GLSL, i.e. {@link #isGL2ES2()}. */
+ public final boolean hasGLSL() {
+ return isGL2ES2() ;
+ }
+
+ /** Indicates whether this profile uses the native OpenGL ES1 implementations. */
+ public final boolean usesNativeGLES1() {
+ return GLES1 == getImplName();
+ }
+
+ /** Indicates whether this profile uses the native OpenGL ES2 implementations. */
+ public final boolean usesNativeGLES2() {
+ return GLES2 == getImplName();
+ }
+
+ /** Indicates whether this profile uses the native OpenGL ES3 implementations. */
+ public final boolean usesNativeGLES3() {
+ return GLES3 == getImplName();
+ }
+
+ /** Indicates whether this profile uses either of the native OpenGL ES implementations. */
+ public final boolean usesNativeGLES() {
+ return usesNativeGLES3() || usesNativeGLES2() || usesNativeGLES1();
+ }
+
+ /**
+ * General validation if type is a valid GL data type
+ * for the current profile
+ */
+ public boolean isValidDataType(final int type, final boolean throwException) {
+ switch(type) {
+ case GL.GL_UNSIGNED_BYTE:
+ case GL.GL_BYTE:
+ case GL.GL_UNSIGNED_SHORT:
+ case GL.GL_SHORT:
+ case GL.GL_FLOAT:
+ case GL.GL_FIXED:
+ return true;
+ case com.jogamp.opengl.GL2ES2.GL_INT:
+ case GL.GL_UNSIGNED_INT:
+ if( isGL2ES2() ) {
+ return true;
+ }
+ case com.jogamp.opengl.GL2GL3.GL_DOUBLE:
+ if( isGL3() ) {
+ return true;
+ }
+ case com.jogamp.opengl.GL2.GL_2_BYTES:
+ case com.jogamp.opengl.GL2.GL_3_BYTES:
+ case com.jogamp.opengl.GL2.GL_4_BYTES:
+ if( isGL2() ) {
+ return true;
+ }
+ }
+ if(throwException) {
+ throw new GLException("Illegal data type on profile "+this+": "+type);
+ }
+ return false;
+ }
+
+ public boolean isValidArrayDataType(final int index, final int comps, final int type,
+ final boolean isVertexAttribPointer, final boolean throwException) {
+ final String arrayName = getGLArrayName(index);
+ if( isGLES1() ) {
+ if(isVertexAttribPointer) {
+ if(throwException) {
+ throw new GLException("Illegal array type for "+arrayName+" on profile GLES1: VertexAttribPointer");
+ }
+ return false;
+ }
+ switch(index) {
+ case GLPointerFunc.GL_VERTEX_ARRAY:
+ case GLPointerFunc.GL_TEXTURE_COORD_ARRAY:
+ switch(type) {
+ case GL.GL_BYTE:
+ case GL.GL_SHORT:
+ case GL.GL_FIXED:
+ case GL.GL_FLOAT:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal data type for "+arrayName+" on profile GLES1: "+type);
+ }
+ return false;
+ }
+ switch(comps) {
+ case 0:
+ case 2:
+ case 3:
+ case 4:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal component number for "+arrayName+" on profile GLES1: "+comps);
+ }
+ return false;
+ }
+ break;
+ case GLPointerFunc.GL_NORMAL_ARRAY:
+ switch(type) {
+ case GL.GL_BYTE:
+ case GL.GL_SHORT:
+ case GL.GL_FIXED:
+ case GL.GL_FLOAT:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal data type for "+arrayName+" on profile GLES1: "+type);
+ }
+ return false;
+ }
+ switch(comps) {
+ case 0:
+ case 3:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal component number for "+arrayName+" on profile GLES1: "+comps);
+ }
+ return false;
+ }
+ break;
+ case GLPointerFunc.GL_COLOR_ARRAY:
+ switch(type) {
+ case GL.GL_UNSIGNED_BYTE:
+ case GL.GL_FIXED:
+ case GL.GL_FLOAT:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal data type for "+arrayName+" on profile GLES1: "+type);
+ }
+ return false;
+ }
+ switch(comps) {
+ case 0:
+ case 4:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal component number for "+arrayName+" on profile GLES1: "+comps);
+ }
+ return false;
+ }
+ break;
+ }
+ } else if( isGLES2() ) {
+ // simply ignore !isVertexAttribPointer case, since it is simulated anyway ..
+ switch(type) {
+ case GL.GL_UNSIGNED_BYTE:
+ case GL.GL_BYTE:
+ case GL.GL_UNSIGNED_SHORT:
+ case GL.GL_SHORT:
+ case GL.GL_FLOAT:
+ case GL.GL_FIXED:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal data type for "+arrayName+" on profile GLES2: "+type);
+ }
+ return false;
+ }
+ /** unable to validate .. could be any valid type/component combination
+ switch(comps) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal component number for "+arrayName+" on profile GLES2: "+comps);
+ }
+ return false;
+ } */
+ } else if( isGL2ES2() ) {
+ if(isVertexAttribPointer) {
+ switch(type) {
+ case GL.GL_UNSIGNED_BYTE:
+ case GL.GL_BYTE:
+ case GL.GL_UNSIGNED_SHORT:
+ case GL.GL_SHORT:
+ case GL.GL_FLOAT:
+ case com.jogamp.opengl.GL2ES2.GL_INT:
+ case GL.GL_UNSIGNED_INT:
+ case com.jogamp.opengl.GL2GL3.GL_DOUBLE:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
+ }
+ return false;
+ }
+ switch(comps) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal component number for "+arrayName+" on profile GL2: "+comps);
+ }
+ return false;
+ }
+ } else {
+ switch(index) {
+ case GLPointerFunc.GL_VERTEX_ARRAY:
+ switch(type) {
+ case GL.GL_SHORT:
+ case GL.GL_FLOAT:
+ case com.jogamp.opengl.GL2ES2.GL_INT:
+ case com.jogamp.opengl.GL2GL3.GL_DOUBLE:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
+ }
+ return false;
+ }
+ switch(comps) {
+ case 0:
+ case 2:
+ case 3:
+ case 4:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal component number for "+arrayName+" on profile GL2: "+comps);
+ }
+ return false;
+ }
+ break;
+ case GLPointerFunc.GL_NORMAL_ARRAY:
+ switch(type) {
+ case GL.GL_BYTE:
+ case GL.GL_SHORT:
+ case GL.GL_FLOAT:
+ case com.jogamp.opengl.GL2ES2.GL_INT:
+ case com.jogamp.opengl.GL2GL3.GL_DOUBLE:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
+ }
+ return false;
+ }
+ switch(comps) {
+ case 0:
+ case 3:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal component number for "+arrayName+" on profile GLES1: "+comps);
+ }
+ return false;
+ }
+ break;
+ case GLPointerFunc.GL_COLOR_ARRAY:
+ switch(type) {
+ case GL.GL_UNSIGNED_BYTE:
+ case GL.GL_BYTE:
+ case GL.GL_UNSIGNED_SHORT:
+ case GL.GL_SHORT:
+ case GL.GL_FLOAT:
+ case com.jogamp.opengl.GL2ES2.GL_INT:
+ case GL.GL_UNSIGNED_INT:
+ case com.jogamp.opengl.GL2GL3.GL_DOUBLE:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
+ }
+ return false;
+ }
+ switch(comps) {
+ case 0:
+ case 3:
+ case 4:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal component number for "+arrayName+" on profile GL2: "+comps);
+ }
+ return false;
+ }
+ break;
+ case GLPointerFunc.GL_TEXTURE_COORD_ARRAY:
+ switch(type) {
+ case GL.GL_SHORT:
+ case GL.GL_FLOAT:
+ case com.jogamp.opengl.GL2ES2.GL_INT:
+ case com.jogamp.opengl.GL2GL3.GL_DOUBLE:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
+ }
+ return false;
+ }
+ switch(comps) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ break;
+ default:
+ if(throwException) {
+ throw new GLException("Illegal component number for "+arrayName+" on profile GL2: "+comps);
+ }
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "GLProfile[" + getName() + "/" + getImplName() + "."+(this.isHardwareRasterizer?"hw":"sw")+(isCustom?".custom":"")+"]";
+ }
+
+ private static /*final*/ boolean isAWTAvailable;
+
+ private static /*final*/ boolean hasDesktopGLFactory;
+ private static /*final*/ boolean hasGL234Impl;
+ private static /*final*/ boolean hasEGLFactory;
+ private static /*final*/ boolean hasGLES3Impl;
+ private static /*final*/ boolean hasGLES1Impl;
+ private static /*final*/ Constructor<?> ctorGL234Impl;
+ private static /*final*/ Constructor<?> ctorGLES3Impl;
+ private static /*final*/ Constructor<?> ctorGLES1Impl;
+ private static /*final*/ Constructor<?> ctorGL234ProcAddr;
+ private static /*final*/ Constructor<?> ctorGLES3ProcAddr;
+ private static /*final*/ Constructor<?> ctorGLES1ProcAddr;
+
+ private static /*final*/ GLDrawableFactoryImpl eglFactory = null;
+ private static /*final*/ GLDrawableFactoryImpl desktopFactory = null;
+ private static /*final*/ AbstractGraphicsDevice defaultDevice = null;
+
+ private static boolean initialized = false;
+ private static final RecursiveThreadGroupLock initLock = LockFactory.createRecursiveThreadGroupLock();
+
+ private static final Class<?>[] ctorGLArgs = new Class<?>[] { GLProfile.class, jogamp.opengl.GLContextImpl.class };
+ private static final Class<?>[] ctorProcArgs = new Class<?>[] { FunctionAddressResolver.class };
+ private static final String GL4bcImplClassName = "jogamp.opengl.gl4.GL4bcImpl";
+ private static final String GL4bcProcClassName = "jogamp.opengl.gl4.GL4bcProcAddressTable";
+ private static final String GLES1ImplClassName = "jogamp.opengl.es1.GLES1Impl";
+ private static final String GLES1ProcClassName = "jogamp.opengl.es1.GLES1ProcAddressTable";
+ private static final String GLES3ImplClassName = "jogamp.opengl.es3.GLES3Impl";
+ private static final String GLES3ProcClassName = "jogamp.opengl.es3.GLES3ProcAddressTable";
+
+ private static final Constructor<?> getCtor(final String clazzName, final boolean glObject, final ClassLoader cl) {
+ try {
+ return ReflectionUtil.getConstructor(clazzName, glObject ? ctorGLArgs : ctorProcArgs, false, cl);
+ } catch (final Throwable t) {
+ if( DEBUG ) {
+ System.err.println("Caught: "+t.getMessage());
+ t.printStackTrace();
+ }
+ return null;
+ }
+ }
+
+ private static final void initGLCtorImpl() {
+ final ClassLoader classloader = GLProfile.class.getClassLoader();
+
+ // depends on hasDesktopGLFactory
+ {
+ final Constructor<?> ctorGL = getCtor(GL4bcImplClassName, true, classloader);
+ final Constructor<?> ctorProc = null != ctorGL ? getCtor(GL4bcProcClassName, false, classloader) : null;
+ if( null != ctorProc ) {
+ hasGL234Impl = true;
+ ctorGL234Impl = ctorGL;
+ ctorGL234ProcAddr = ctorProc;
+ } else {
+ hasGL234Impl = false;
+ ctorGL234Impl = null;
+ ctorGL234ProcAddr = null;
+ }
+ }
+
+ // depends on hasEGLFactory
+ {
+ final Constructor<?> ctorGL = getCtor(GLES1ImplClassName, true, classloader);
+ final Constructor<?> ctorProc = null != ctorGL ? getCtor(GLES1ProcClassName, false, classloader) : null;
+ if( null != ctorProc ) {
+ hasGLES1Impl = true;
+ ctorGLES1Impl = ctorGL;
+ ctorGLES1ProcAddr = ctorProc;
+ } else {
+ hasGLES1Impl = false;
+ ctorGLES1Impl = null;
+ ctorGLES1ProcAddr = null;
+ }
+ }
+ {
+ final Constructor<?> ctorGL = getCtor(GLES3ImplClassName, true, classloader);
+ final Constructor<?> ctorProc = null != ctorGL ? getCtor(GLES3ProcClassName, false, classloader) : null;
+ if( null != ctorProc ) {
+ hasGLES3Impl = true;
+ ctorGLES3Impl = ctorGL;
+ ctorGLES3ProcAddr = ctorProc;
+ } else {
+ hasGLES3Impl = false;
+ ctorGLES3Impl = null;
+ ctorGLES3ProcAddr = null;
+ }
+ }
+ }
+
+ /**
+ * Tries the profiles implementation and native libraries.
+ */
+ private static void initProfilesForDefaultDevices() {
+ NativeWindowFactory.initSingleton();
+ if(DEBUG) {
+ System.err.println("GLProfile.init - thread: " + Thread.currentThread().getName());
+ System.err.println(VersionUtil.getPlatformInfo());
+ System.err.println(GlueGenVersion.getInstance());
+ System.err.println(NativeWindowVersion.getInstance());
+ System.err.println(JoglVersion.getInstance());
+ }
+
+ final ClassLoader classloader = GLProfile.class.getClassLoader();
+
+ isAWTAvailable = NativeWindowFactory.isAWTAvailable() &&
+ ReflectionUtil.isClassAvailable("com.jogamp.opengl.awt.GLCanvas", classloader) ; // JOGL
+
+ initGLCtorImpl();
+
+ //
+ // Iteration of desktop GL availability detection
+ // utilizing the detected GL version in the shared context.
+ //
+ // - Instantiate GLDrawableFactory incl its shared dummy drawable/context,
+ // which will register at GLContext ..
+ //
+ GLDrawableFactory.initSingleton();
+
+ Throwable t=null;
+ // if successfull it has a shared dummy drawable and context created
+ try {
+ desktopFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GL2);
+ if(null != desktopFactory) {
+ final DesktopGLDynamicLookupHelper glLookupHelper = (DesktopGLDynamicLookupHelper) desktopFactory.getGLDynamicLookupHelper(GL2);
+ if(null!=glLookupHelper) {
+ hasDesktopGLFactory = glLookupHelper.isLibComplete() && hasGL234Impl;
+ }
+ }
+ } catch (final LinkageError le) {
+ t=le;
+ } catch (final RuntimeException re) {
+ t=re;
+ } catch (final Throwable tt) {
+ t=tt;
+ }
+ if(DEBUG) {
+ if(null!=t) {
+ t.printStackTrace();
+ }
+ }
+
+ final AbstractGraphicsDevice defaultDesktopDevice;
+ if(null == desktopFactory) {
+ hasDesktopGLFactory = false;
+ hasGL234Impl = false;
+ defaultDesktopDevice = null;
+ if(DEBUG) {
+ System.err.println("Info: GLProfile.init - Desktop GLDrawable factory not available");
+ }
+ } else {
+ defaultDesktopDevice = desktopFactory.getDefaultDevice();
+ }
+
+ if ( ReflectionUtil.isClassAvailable("jogamp.opengl.egl.EGLDrawableFactory", classloader) ) {
+ t=null;
+ try {
+ eglFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GLES2);
+ if(null != eglFactory) {
+ hasEGLFactory = true;
+ // update hasGLES1Impl, hasGLES3Impl based on EGL
+ hasGLES3Impl = null!=eglFactory.getGLDynamicLookupHelper(GLES2) && hasGLES3Impl;
+ hasGLES1Impl = null!=eglFactory.getGLDynamicLookupHelper(GLES1) && hasGLES1Impl;
+ }
+ } catch (final LinkageError le) {
+ t=le;
+ } catch (final SecurityException se) {
+ t=se;
+ } catch (final NullPointerException npe) {
+ t=npe;
+ } catch (final RuntimeException re) {
+ t=re;
+ }
+ if(DEBUG) {
+ if(null!=t) {
+ t.printStackTrace();
+ }
+ }
+ }
+
+ final AbstractGraphicsDevice defaultEGLDevice;
+ if(null == eglFactory) {
+ hasGLES3Impl = false;
+ hasGLES1Impl = false;
+ defaultEGLDevice = null;
+ if(DEBUG) {
+ System.err.println("Info: GLProfile.init - EGL GLDrawable factory not available");
+ }
+ } else {
+ defaultEGLDevice = eglFactory.getDefaultDevice();
+ }
+
+ if( null != defaultDesktopDevice ) {
+ defaultDevice = defaultDesktopDevice;
+ if(DEBUG) {
+ System.err.println("Info: GLProfile.init - Default device is desktop derived: "+defaultDevice);
+ }
+ } else if ( null != defaultEGLDevice ) {
+ defaultDevice = defaultEGLDevice;
+ if(DEBUG) {
+ System.err.println("Info: GLProfile.init - Default device is EGL derived: "+defaultDevice);
+ }
+ } else {
+ if(DEBUG) {
+ System.err.println("Info: GLProfile.init - Default device not available");
+ }
+ defaultDevice = null;
+ }
+
+ // we require to initialize the EGL device 1st, if available
+ final boolean addedEGLProfile = null != defaultEGLDevice ? initProfilesForDevice(defaultEGLDevice) : false;
+ final boolean addedDesktopProfile = null != defaultDesktopDevice ? initProfilesForDevice(defaultDesktopDevice) : false;
+ final boolean addedAnyProfile = addedEGLProfile || addedDesktopProfile ;
+
+ if(DEBUG) {
+ System.err.println("GLProfile.init addedAnyProfile "+addedAnyProfile+" (desktop: "+addedDesktopProfile+", egl "+addedEGLProfile+")");
+ System.err.println("GLProfile.init isAWTAvailable "+isAWTAvailable);
+ System.err.println("GLProfile.init hasDesktopGLFactory "+hasDesktopGLFactory);
+ System.err.println("GLProfile.init hasGL234Impl "+hasGL234Impl);
+ System.err.println("GLProfile.init hasEGLFactory "+hasEGLFactory);
+ System.err.println("GLProfile.init hasGLES1Impl "+hasGLES1Impl);
+ System.err.println("GLProfile.init hasGLES3Impl "+hasGLES3Impl);
+ System.err.println("GLProfile.init defaultDevice "+defaultDevice);
+ System.err.println("GLProfile.init defaultDevice Desktop "+defaultDesktopDevice);
+ System.err.println("GLProfile.init defaultDevice EGL "+defaultEGLDevice);
+ System.err.println("GLProfile.init profile order "+array2String(GL_PROFILE_LIST_ALL));
+ }
+ }
+
+ /**
+ * @param device the device for which profiles shall be initialized
+ * @return true if any profile for the device exists, otherwise false
+ */
+ private static boolean initProfilesForDevice(final AbstractGraphicsDevice device) {
+ if(null == device) {
+ return false;
+ }
+ initLock.lock();
+ try {
+ final GLDrawableFactory factory = GLDrawableFactory.getFactoryImpl(device);
+ factory.enterThreadCriticalZone();
+ try {
+ return initProfilesForDeviceCritical(device);
+ } finally {
+ factory.leaveThreadCriticalZone();
+ }
+ } finally {
+ initLock.unlock();
+ }
+ }
+ private static boolean initProfilesForDeviceCritical(final AbstractGraphicsDevice device) {
+ final boolean isSet = GLContext.getAvailableGLVersionsSet(device);
+
+ if(DEBUG) {
+ System.err.println("Info: GLProfile.initProfilesForDevice: "+device+" ("+device.getClass().getName()+"), isSet "+isSet+", hasDesktopGLFactory "+hasDesktopGLFactory+", hasEGLFactory "+hasEGLFactory);
+ }
+ if(isSet) {
+ // Avoid recursion and check whether impl. is sane!
+ final String deviceKey = device.getUniqueID();
+ final HashMap<String /*GLProfile_name*/, GLProfile> map = deviceConn2ProfileMap.get(deviceKey);
+ if( null == map ) {
+ throw new InternalError("GLContext Avail. GLVersion is set - but no profile map for device: "+device);
+ }
+ return null != map.get(GL_DEFAULT);
+ }
+
+ boolean addedDesktopProfile = false;
+ boolean addedEGLProfile = false;
+
+ final boolean deviceIsDesktopCompatible = hasDesktopGLFactory && desktopFactory.getIsDeviceCompatible(device);
+
+ if( deviceIsDesktopCompatible ) {
+ // 1st pretend we have all Desktop and EGL profiles ..
+ computeProfileMap(device, true /* desktopCtxUndef*/, true /* esCtxUndef */);
+
+ // Triggers eager initialization of share context in GLDrawableFactory for the device,
+ // hence querying all available GLProfiles
+ final Thread sharedResourceThread = desktopFactory.getSharedResourceThread();
+ if(null != sharedResourceThread) {
+ initLock.addOwner(sharedResourceThread);
+ }
+ final boolean desktopSharedCtxAvail = desktopFactory.createSharedResource(device);
+ if(null != sharedResourceThread) {
+ initLock.removeOwner(sharedResourceThread);
+ }
+ if (DEBUG) {
+ System.err.println("GLProfile.initProfilesForDevice: "+device+": desktop Shared Ctx "+desktopSharedCtxAvail);
+ }
+ if(!desktopSharedCtxAvail) {
+ hasDesktopGLFactory = false;
+ } else if( !GLContext.getAvailableGLVersionsSet(device) ) {
+ throw new InternalError("Available GLVersions not set");
+ }
+ addedDesktopProfile = computeProfileMap(device, false /* desktopCtxUndef*/, false /* esCtxUndef */);
+ }
+
+ final boolean deviceIsEGLCompatible = hasEGLFactory && eglFactory.getIsDeviceCompatible(device);
+
+ // also test GLES1, GLES2 and GLES3 on desktop, since we have implementations / emulations available.
+ if( deviceIsEGLCompatible && ( hasGLES3Impl || hasGLES1Impl ) ) {
+ // 1st pretend we have all EGL profiles ..
+ computeProfileMap(device, true /* desktopCtxUndef*/, true /* esCtxUndef */);
+
+ // Triggers eager initialization of share context in GLDrawableFactory for the device,
+ // hence querying all available GLProfiles
+ final Thread sharedResourceThread = eglFactory.getSharedResourceThread();
+ if(null != sharedResourceThread) {
+ initLock.addOwner(sharedResourceThread);
+ }
+ final boolean eglSharedCtxAvail = eglFactory.createSharedResource(device);
+ if(null != sharedResourceThread) {
+ initLock.removeOwner(sharedResourceThread);
+ }
+ if(!eglSharedCtxAvail) {
+ // Remark: On Windows there is a libEGL.dll delivered w/ Chrome 15.0.874.121m and Firefox 8.0.1
+ // but it seems even EGL.eglInitialize(eglDisplay, null, null)
+ // fails in some scenarios (eg VirtualBox 4.1.6) w/ EGL error 0x3001 (EGL_NOT_INITIALIZED).
+ hasEGLFactory = false;
+ hasGLES3Impl = false;
+ hasGLES1Impl = false;
+ }
+ if (DEBUG) {
+ System.err.println("GLProfile.initProfilesForDevice: "+device+": egl Shared Ctx "+eglSharedCtxAvail);
+ }
+ addedEGLProfile = computeProfileMap(device, false /* desktopCtxUndef*/, false /* esCtxUndef */);
+ }
+
+ if( !addedDesktopProfile && !addedEGLProfile ) {
+ setProfileMap(device, new HashMap<String /*GLProfile_name*/, GLProfile>()); // empty
+ if(DEBUG) {
+ System.err.println("GLProfile: device could not be initialized: "+device);
+ System.err.println("GLProfile: compatible w/ desktop: "+deviceIsDesktopCompatible+
+ ", egl "+deviceIsEGLCompatible);
+ System.err.println("GLProfile: desktoplFactory "+desktopFactory);
+ System.err.println("GLProfile: eglFactory "+eglFactory);
+ System.err.println("GLProfile: hasGLES1Impl "+hasGLES1Impl);
+ System.err.println("GLProfile: hasGLES3Impl "+hasGLES3Impl);
+ }
+ }
+
+ GLContext.setAvailableGLVersionsSet(device, true);
+
+ if (DEBUG) {
+ System.err.println("GLProfile.initProfilesForDevice: "+device.getConnection()+": added profile(s): desktop "+addedDesktopProfile+", egl "+addedEGLProfile);
+ System.err.println("GLProfile.initProfilesForDevice: "+device.getConnection()+": "+glAvailabilityToString(device));
+ if(addedDesktopProfile) {
+ dumpGLInfo(desktopFactory, device);
+ final List<GLCapabilitiesImmutable> availCaps = desktopFactory.getAvailableCapabilities(device);
+ for(int i=0; i<availCaps.size(); i++) {
+ System.err.println(availCaps.get(i));
+ }
+ } else if(addedEGLProfile) {
+ dumpGLInfo(eglFactory, device);
+ final List<GLCapabilitiesImmutable> availCaps = eglFactory.getAvailableCapabilities(device);
+ for(int i=0; i<availCaps.size(); i++) {
+ System.err.println(availCaps.get(i));
+ }
+ }
+ }
+
+ return addedDesktopProfile || addedEGLProfile;
+ }
+
+ private static void dumpGLInfo(final GLDrawableFactoryImpl factory, final AbstractGraphicsDevice device) {
+ final GLContext ctx = factory.getOrCreateSharedContext(device);
+ if(null != ctx) {
+ System.err.println("GLProfile.dumpGLInfo: "+ctx);
+ ctx.makeCurrent();
+ try {
+ System.err.println(JoglVersion.getGLInfo(ctx.getGL(), null));
+ } finally {
+ ctx.release();
+ }
+ } else {
+ System.err.println("GLProfile.dumpGLInfo: shared context n/a");
+ }
+ }
+
+ public static AbstractGraphicsDevice getDefaultDevice() {
+ initSingleton();
+ return defaultDevice;
+ }
+
+ private static String array2String(final String[] list) {
+ final StringBuilder msg = new StringBuilder();
+ msg.append("[");
+ for (int i = 0; i < list.length; i++) {
+ if (i > 0)
+ msg.append(", ");
+ msg.append(list[i]);
+ }
+ msg.append("]");
+ return msg.toString();
+ }
+
+ private static void glAvailabilityToString(final AbstractGraphicsDevice device, final StringBuilder sb, final int major, final int profile) {
+ final String str = GLContext.getAvailableGLVersionAsString(device, major, profile);
+ if(null==str) {
+ throw new GLException("Internal Error");
+ }
+ sb.append("[");
+ sb.append(str);
+ sb.append("]");
+ }
+
+ private static boolean computeProfileMap(final AbstractGraphicsDevice device, final boolean desktopCtxUndef, final boolean esCtxUndef) {
+ if (DEBUG) {
+ System.err.println("GLProfile.init map "+device.getConnection()+", desktopCtxUndef "+desktopCtxUndef+", esCtxUndef "+esCtxUndef);
+ }
+ final boolean isHardwareRasterizer[] = new boolean[1];
+ GLProfile defaultGLProfileAny = null;
+ GLProfile defaultGLProfileHW = null;
+ final HashMap<String, GLProfile> _mappedProfiles = new HashMap<String, GLProfile>(GL_PROFILE_LIST_ALL.length + 1 /* default */);
+ for(int i=0; i<GL_PROFILE_LIST_ALL.length; i++) {
+ final String profile = GL_PROFILE_LIST_ALL[i];
+ final String profileImpl = computeProfileImpl(device, profile, desktopCtxUndef, esCtxUndef, isHardwareRasterizer);
+ if( null != profileImpl ) {
+ final GLProfile glProfile;
+ if( profile.equals( profileImpl ) ) {
+ glProfile = new GLProfile(profile, null, isHardwareRasterizer[0], false /* custom */);
+ } else {
+ final GLProfile _mglp = _mappedProfiles.get( profileImpl );
+ if( null == _mglp ) {
+ throw new InternalError("XXX0 profile["+i+"]: "+profile+" -> profileImpl "+profileImpl+" !!! not mapped ");
+ }
+ glProfile = new GLProfile(profile, _mglp, isHardwareRasterizer[0], false /* custom */);
+ }
+ _mappedProfiles.put(profile, glProfile);
+ if (DEBUG) {
+ System.err.println("GLProfile.init map "+glProfile+" on device "+device.getConnection());
+ }
+ if( null == defaultGLProfileHW && isHardwareRasterizer[0] ) {
+ defaultGLProfileHW=glProfile;
+ if (DEBUG) {
+ System.err.println("GLProfile.init map defaultHW "+glProfile+" on device "+device.getConnection());
+ }
+ } else if( null == defaultGLProfileAny ) {
+ defaultGLProfileAny=glProfile;
+ if (DEBUG) {
+ System.err.println("GLProfile.init map defaultAny "+glProfile+" on device "+device.getConnection());
+ }
+ }
+ } else {
+ if (DEBUG) {
+ System.err.println("GLProfile.init map *** no mapping for "+profile+" on device "+device.getConnection());
+ }
+ }
+ }
+ if( null != defaultGLProfileHW ) {
+ _mappedProfiles.put(GL_DEFAULT, defaultGLProfileHW);
+ } else if( null != defaultGLProfileAny ) {
+ _mappedProfiles.put(GL_DEFAULT, defaultGLProfileAny);
+ }
+ setProfileMap(device, _mappedProfiles);
+ return _mappedProfiles.size() > 0;
+ }
+
+ /**
+ * Returns the profile implementation
+ */
+ private static String computeProfileImpl(final AbstractGraphicsDevice device, final String profile, final boolean desktopCtxUndef, final boolean esCtxUndef, final boolean isHardwareRasterizer[]) {
+ final boolean hardwareRasterizer[] = new boolean[1];
+ if ( GL2ES1 == profile ) {
+ final boolean gles1Available;
+ final boolean gles1HWAvailable;
+ if( hasGLES1Impl ) {
+ gles1Available = esCtxUndef || GLContext.isGLES1Available(device, hardwareRasterizer);
+ gles1HWAvailable = gles1Available && hardwareRasterizer[0] ;
+ } else {
+ gles1Available = false;
+ gles1HWAvailable = false;
+ }
+ if(hasGL234Impl) {
+ final boolean gl3bcAvailable = GLContext.isGL3bcAvailable(device, hardwareRasterizer);
+ final boolean gl3bcHWAvailable = gl3bcAvailable && hardwareRasterizer[0] ;
+ final boolean gl2Available = GLContext.isGL2Available(device, hardwareRasterizer);
+ final boolean gl2HWAvailable = gl2Available && hardwareRasterizer[0] ;
+ final boolean glAnyHWAvailable = gl3bcHWAvailable || gl2HWAvailable ||
+ gles1HWAvailable ;
+
+ if( GLContext.isGL4bcAvailable(device, isHardwareRasterizer) &&
+ ( isHardwareRasterizer[0] || !glAnyHWAvailable ) ) {
+ return GL4bc;
+ }
+ if( gl3bcAvailable && ( gl3bcHWAvailable || !glAnyHWAvailable ) ) {
+ isHardwareRasterizer[0] = gl3bcHWAvailable;
+ return GL3bc;
+ }
+ if( ( desktopCtxUndef || gl2Available ) && ( gl2HWAvailable || !glAnyHWAvailable ) ) {
+ isHardwareRasterizer[0] = gl2HWAvailable;
+ return GL2;
+ }
+ }
+ if( gles1Available ) {
+ isHardwareRasterizer[0] = gles1HWAvailable;
+ return GLES1;
+ }
+ } else if ( GL2ES2 == profile ) {
+ final boolean gles2Available, gles3Available;
+ final boolean gles2HWAvailable, gles3HWAvailable;
+ if( hasGLES3Impl ) {
+ gles2Available = esCtxUndef || GLContext.isGLES2Available(device, hardwareRasterizer);
+ gles2HWAvailable = gles2Available && hardwareRasterizer[0] ;
+ gles3Available = esCtxUndef || GLContext.isGLES3Available(device, hardwareRasterizer);
+ gles3HWAvailable = gles3Available && hardwareRasterizer[0] ;
+ } else {
+ gles2Available = false;
+ gles2HWAvailable = false;
+ gles3Available = false;
+ gles3HWAvailable = false;
+ }
+ if( hasGL234Impl ) {
+ final boolean gl4bcAvailable = GLContext.isGL4bcAvailable(device, hardwareRasterizer);
+ final boolean gl4bcHWAvailable = gl4bcAvailable && hardwareRasterizer[0] ;
+ final boolean gl3Available = GLContext.isGL3Available(device, hardwareRasterizer);
+ final boolean gl3HWAvailable = gl3Available && hardwareRasterizer[0] ;
+ final boolean gl3bcAvailable = GLContext.isGL3bcAvailable(device, hardwareRasterizer);
+ final boolean gl3bcHWAvailable = gl3bcAvailable && hardwareRasterizer[0] ;
+ final boolean gl2Available = GLContext.isGL2Available(device, hardwareRasterizer);
+ final boolean gl2HWAvailable = gl2Available && hardwareRasterizer[0] ;
+ final boolean glAnyHWAvailable = gl4bcHWAvailable || gl3HWAvailable || gl3bcHWAvailable || gl2HWAvailable ||
+ gles3HWAvailable || gles2HWAvailable ;
+
+ if( GLContext.isGL4Available(device, isHardwareRasterizer) &&
+ ( isHardwareRasterizer[0] || !glAnyHWAvailable ) ) {
+ return GL4;
+ }
+ if( gl4bcAvailable && ( gl4bcHWAvailable || !glAnyHWAvailable ) ) {
+ isHardwareRasterizer[0] = gl4bcHWAvailable;
+ return GL4bc;
+ }
+ if( gl3Available && ( gl3HWAvailable || !glAnyHWAvailable ) ) {
+ isHardwareRasterizer[0] = gl3HWAvailable;
+ return GL3;
+ }
+ if( gl3bcAvailable && ( gl3bcHWAvailable || !glAnyHWAvailable ) ) {
+ isHardwareRasterizer[0] = gl3bcHWAvailable;
+ return GL3bc;
+ }
+ if( ( desktopCtxUndef || gl2Available ) && ( gl2HWAvailable || !glAnyHWAvailable ) ) {
+ isHardwareRasterizer[0] = gl2HWAvailable;
+ return GL2;
+ }
+ }
+ if( gles3Available && ( gles3HWAvailable || !gles2HWAvailable ) ) {
+ isHardwareRasterizer[0] = gles3HWAvailable;
+ return GLES3;
+ }
+ if( gles2Available ) {
+ isHardwareRasterizer[0] = gles2HWAvailable;
+ return GLES2;
+ }
+ } else if (GL4ES3 == profile) {
+ final boolean gles3CompatAvail = GLContext.isGLES3CompatibleAvailable(device);
+ if( desktopCtxUndef || esCtxUndef || gles3CompatAvail ) {
+ final boolean es3HardwareRasterizer[] = new boolean[1];
+ final boolean gles3Available = hasGLES3Impl && ( esCtxUndef || GLContext.isGLES3Available(device, es3HardwareRasterizer) );
+ final boolean gles3HWAvailable = gles3Available && es3HardwareRasterizer[0] ;
+ if( hasGL234Impl ) {
+ final boolean gl4bcAvailable = GLContext.isGL4bcAvailable(device, hardwareRasterizer);
+ final boolean gl4bcHWAvailable = gl4bcAvailable && hardwareRasterizer[0] ;
+ final boolean glAnyHWAvailable = gl4bcHWAvailable ||
+ gles3HWAvailable;
+
+ if( GLContext.isGL4Available(device, isHardwareRasterizer) &&
+ ( isHardwareRasterizer[0] || !glAnyHWAvailable ) ) {
+ return GL4;
+ }
+ if( ( desktopCtxUndef || gl4bcAvailable ) && ( gl4bcHWAvailable || !glAnyHWAvailable ) ) {
+ isHardwareRasterizer[0] = gl4bcHWAvailable;
+ return GL4bc;
+ }
+ }
+ if(gles3Available) {
+ isHardwareRasterizer[0] = es3HardwareRasterizer[0];
+ return GLES3;
+ }
+ }
+ } else if(GL2GL3 == profile) {
+ if(hasGL234Impl) {
+ final boolean gl4Available = GLContext.isGL4Available(device, hardwareRasterizer);
+ final boolean gl4HWAvailable = gl4Available && hardwareRasterizer[0] ;
+ final boolean gl3Available = GLContext.isGL3Available(device, hardwareRasterizer);
+ final boolean gl3HWAvailable = gl3Available && hardwareRasterizer[0] ;
+ final boolean gl3bcAvailable = GLContext.isGL3bcAvailable(device, hardwareRasterizer);
+ final boolean gl3bcHWAvailable = gl3bcAvailable && hardwareRasterizer[0] ;
+ final boolean gl2Available = GLContext.isGL2Available(device, hardwareRasterizer);
+ final boolean gl2HWAvailable = gl2Available && hardwareRasterizer[0] ;
+ final boolean glAnyHWAvailable = gl4HWAvailable || gl3HWAvailable || gl3bcHWAvailable || gl2HWAvailable;
+
+ if( GLContext.isGL4bcAvailable(device, isHardwareRasterizer) &&
+ ( isHardwareRasterizer[0] || !glAnyHWAvailable ) ) {
+ return GL4bc;
+ }
+ if( gl4Available && ( gl4HWAvailable || !glAnyHWAvailable ) ) {
+ isHardwareRasterizer[0] = gl4HWAvailable;
+ return GL4;
+ }
+ if( gl3bcAvailable && ( gl3bcHWAvailable || !glAnyHWAvailable ) ) {
+ isHardwareRasterizer[0] = gl3bcHWAvailable;
+ return GL3bc;
+ }
+ if( gl3Available && ( gl3HWAvailable || !glAnyHWAvailable ) ) {
+ isHardwareRasterizer[0] = gl3HWAvailable;
+ return GL3;
+ }
+ if( desktopCtxUndef || gl2Available ) {
+ isHardwareRasterizer[0] = gl2HWAvailable;
+ return GL2;
+ }
+ }
+ } else if(GL4bc == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4bcAvailable(device, isHardwareRasterizer))) {
+ return desktopCtxUndef ? GL4bc : GLContext.getAvailableGLProfileName(device, 4, GLContext.CTX_PROFILE_COMPAT);
+ } else if(GL4 == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4Available(device, isHardwareRasterizer))) {
+ return desktopCtxUndef ? GL4 : GLContext.getAvailableGLProfileName(device, 4, GLContext.CTX_PROFILE_CORE);
+ } else if(GL3bc == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3bcAvailable(device, isHardwareRasterizer))) {
+ return desktopCtxUndef ? GL3bc : GLContext.getAvailableGLProfileName(device, 3, GLContext.CTX_PROFILE_COMPAT);
+ } else if(GL3 == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3Available(device, isHardwareRasterizer))) {
+ return desktopCtxUndef ? GL3 : GLContext.getAvailableGLProfileName(device, 3, GLContext.CTX_PROFILE_CORE);
+ } else if(GL2 == profile && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer))) {
+ return desktopCtxUndef ? GL2 : GLContext.getAvailableGLProfileName(device, 2, GLContext.CTX_PROFILE_COMPAT);
+ } else if(GLES3 == profile && hasGLES3Impl && ( esCtxUndef || GLContext.isGLES3Available(device, isHardwareRasterizer))) {
+ return esCtxUndef ? GLES3 : GLContext.getAvailableGLProfileName(device, 3, GLContext.CTX_PROFILE_ES);
+ } else if(GLES2 == profile && hasGLES3Impl && ( esCtxUndef || GLContext.isGLES2Available(device, isHardwareRasterizer))) {
+ return esCtxUndef ? GLES2 : GLContext.getAvailableGLProfileName(device, 2, GLContext.CTX_PROFILE_ES);
+ } else if(GLES1 == profile && hasGLES1Impl && ( esCtxUndef || GLContext.isGLES1Available(device, isHardwareRasterizer))) {
+ return esCtxUndef ? GLES1 : GLContext.getAvailableGLProfileName(device, 1, GLContext.CTX_PROFILE_ES);
+ }
+ return null;
+ }
+
+ private static /*final*/ HashMap<String /*device_connection*/, HashMap<String /*GLProfile_name*/, GLProfile>> deviceConn2ProfileMap =
+ new HashMap<String /*device_connection*/, HashMap<String /*GLProfile_name*/, GLProfile>>();
+
+ /**
+ * This implementation support lazy initialization, while avoiding recursion/deadlocks.<br>
+ * If no mapping 'device -> GLProfiles-Map' exists yet, it triggers<br>
+ * - create empty mapping device -> GLProfiles-Map <br>
+ * - initialization<br<
+ *
+ * @param device the key 'device -> GLProfiles-Map'
+ * @param throwExceptionOnZeroProfile true if <code>GLException</code> shall be thrown in case of no mapped profile, otherwise false.
+ * @return the GLProfile HashMap if exists, otherwise null
+ * @throws GLException if no profile for the given device is available.
+ */
+ private static HashMap<String /*GLProfile_name*/, GLProfile> getProfileMap(AbstractGraphicsDevice device, final boolean throwExceptionOnZeroProfile)
+ throws GLException
+ {
+ initSingleton();
+
+ if(null==defaultDevice) { // avoid NPE and notify of incomplete initialization
+ throw new GLException("No default device available");
+ }
+
+ if(null==device) {
+ device = defaultDevice;
+ }
+
+ final String deviceKey = device.getUniqueID();
+ HashMap<String /*GLProfile_name*/, GLProfile> map = deviceConn2ProfileMap.get(deviceKey);
+ if( null != map ) {
+ return map;
+ }
+ if( !initProfilesForDevice(device) ) {
+ if( throwExceptionOnZeroProfile ) {
+ throw new GLException("No Profile available for "+device);
+ } else {
+ return null;
+ }
+ }
+ map = deviceConn2ProfileMap.get(deviceKey);
+ if( null == map && throwExceptionOnZeroProfile ) {
+ throw new InternalError("initProfilesForDevice(..) didn't setProfileMap(..) for "+device);
+ }
+ return map;
+ }
+
+ private static void setProfileMap(final AbstractGraphicsDevice device, final HashMap<String /*GLProfile_name*/, GLProfile> mappedProfiles) {
+ synchronized ( deviceConn2ProfileMap ) {
+ deviceConn2ProfileMap.put(device.getUniqueID(), mappedProfiles);
+ }
+ }
+
+ private GLProfile(final String profile, final GLProfile profileImpl, final boolean isHardwareRasterizer, final boolean isCustom) {
+ this.profile = profile;
+ this.profileImpl = profileImpl;
+ this.isHardwareRasterizer = isHardwareRasterizer;
+ this.isCustom = isCustom;
+ }
+
+ public static GLProfile createCustomGLProfile(final String profile, final GLProfile profileImpl) {
+ return new GLProfile(profile, profileImpl, profileImpl.isHardwareRasterizer, true);
+ }
+
+ private final GLProfile profileImpl;
+ private final String profile;
+ private final boolean isHardwareRasterizer;
+ private final boolean isCustom;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLRunnable.java b/src/jogl/classes/com/jogamp/opengl/GLRunnable.java
new file mode 100644
index 000000000..97a72d6cd
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLRunnable.java
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl;
+
+/**
+ * <p>
+ * Declares a one-shot OpenGL command usable for injection
+ * via {@link GLAutoDrawable#invoke(boolean, com.jogamp.opengl.GLRunnable)}.<br>
+ * {@link GLAutoDrawable} executes the GLRunnables within it's {@link GLAutoDrawable#display() display()}
+ * method after all registered {@link GLEventListener}s
+ * {@link GLEventListener#display(GLAutoDrawable) display(GLAutoDrawable)}
+ * methods has been called.
+ * </p>
+ * <p>
+ * The OpenGL context is current while executing the GLRunnable.
+ * </p>
+ * <p>
+ * This might be useful to inject OpenGL commands from an I/O event listener.
+ * </p>
+ */
+public interface GLRunnable {
+ /**
+ * @param drawable the associated drawable and current context for this call
+ * @return true if the GL [back] framebuffer remains intact by this runnable, otherwise false.
+ * If returning false {@link GLAutoDrawable} will call
+ * {@link GLEventListener#display(GLAutoDrawable) display(GLAutoDrawable)}
+ * of all registered {@link GLEventListener}s once more.
+ * @see GLRunnable
+ */
+ boolean run(GLAutoDrawable drawable);
+}
+
diff --git a/src/jogl/classes/com/jogamp/opengl/GLRunnable2.java b/src/jogl/classes/com/jogamp/opengl/GLRunnable2.java
new file mode 100644
index 000000000..4b0c63da0
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLRunnable2.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl;
+
+/**
+ * <p>
+ * Declares a one-shot OpenGL command.
+ * </p>
+ */
+public interface GLRunnable2<T,U> {
+ /**
+ * @param gl a current GL object
+ * @param args custom arguments
+ * @return the desired object
+ */
+ T run(GL gl, U args);
+}
+
diff --git a/src/jogl/classes/com/jogamp/opengl/GLSharedContextSetter.java b/src/jogl/classes/com/jogamp/opengl/GLSharedContextSetter.java
new file mode 100644
index 000000000..852ebcaa7
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLSharedContextSetter.java
@@ -0,0 +1,181 @@
+/**
+ * Copyright 2013 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl;
+
+import com.jogamp.opengl.GLRendererQuirks;
+
+/**
+ * Adds capabilities to set a shared {@link GLContext} directly or via an {@link GLAutoDrawable}.
+ * <p>
+ * Sharing of server-side OpenGL objects such as buffer objects, e.g. VBOs,
+ * and textures among OpenGL contexts is supported with this interface.
+ * </p>
+ * <p>
+ * A <i>master</i> {@link GLContext} is the {@link GLContext} which is created first.
+ * Subsequent shared {@link GLContext} w/ the <i>master</i> are referred as <i>slave</i> {@link GLContext}.
+ * </p>
+ * <p>
+ * Implementations of this interface control the <i>slave's</i> {@link GLContext} and {@link GLAutoDrawable} realization,
+ * i.e. the <i>slave</i> {@link GLAutoDrawable} will not be realized before their associated <i>master</i>.
+ * </p>
+ * <p>
+ * Using the nearest or same {@link GLCapabilitiesImmutable#getVisualID(com.jogamp.nativewindow.VisualIDHolder.VIDType) visual ID}
+ * or {@link GLCapabilitiesImmutable caps} across the shared {@link GLDrawable}s will yield best compatibility.
+ * </p>
+ * <h5><a name="lifecycle">Lifecycle Considerations</a></h5>
+ * <p>
+ * After shared objects are created on the <i>master</i>, the OpenGL pipeline
+ * might need to be synchronized w/ the <i>slaves</i>, e.g. via {@link GL#glFinish()}.
+ * At least this has been experienced w/ OSX 10.9.
+ * </p>
+ * <p>
+ * In general, destroying a <i>master</i> {@link GLContext} before their shared <i>slaves</i>
+ * shall be permissible, i.e. the OpenGL driver needs to handle pending destruction of shared resources.
+ * This is confirmed to work properly on most platform/driver combinations,
+ * see unit test <code>com.jogamp.opengl.test.junit.jogl.acore.TestSharedContextVBOES2NEWT3</code> and similar.
+ * </p>
+ * <p>
+ * However, to avoid scenarios with buggy drivers, users <i>may not</i> destroy the
+ * <i>master</i> {@link GLContext} before its shared <i>slave</i> {@link GLContext} instances
+ * <i>as long as they are using them</i>.<br>
+ * Otherwise the OpenGL driver may crash w/ SIGSEGV, due to using already destroyed shared resources,
+ * if not handling the pending destruction of the latter!<br>
+ * Either proper lifecycle synchronization is implemented, e.g. by notifying the <i>slaves</i> about the loss of the shared resources,
+ * <i>or</i> the <i>slaves</i> validate whether the resources are still valid.
+ * </p>
+ * <p>
+ * To simplify above lifecycle issues, one may use a {@link GLDrawableFactory#createDummyDrawable(com.jogamp.nativewindow.AbstractGraphicsDevice, boolean, GLCapabilitiesImmutable, GLCapabilitiesChooser) dummy}
+ * {@link GLDrawable} and it's {@link GLContext} as the <i>master</i> of all shared <i>slave</i> {@link GLContext}.
+ * Since this <i>dummy instance</i> does not depend on any native windowing system, it can be controlled easily w/o being <i>in sight</i>.<br>
+ * Below code creates a {@link GLAutoDrawable} based on a <i>dummy GLDrawable</i>:
+ * <pre>
+ // GLProfile and GLCapabilities should be equal across all shared GL drawable/context.
+ final GLCapabilitiesImmutable caps = ... ;
+ final GLProfile glp = caps.getGLProfile();
+ ..
+ final boolean createNewDevice = true; // use 'own' display device!
+ final GLAutoDrawable sharedDrawable = GLDrawableFactory.getFactory(glp).createDummyAutoDrawable(null, createNewDevice, caps, null);
+ sharedDrawable.display(); // triggers GLContext object creation and native realization.
+ ...
+ // Later a shared 'slave' can be created e.g.:
+ GLWindow glad = GLWindow.create(caps); // or any other GLAutoDrawable supporting GLSharedContextSetter
+ glad.setSharedAutoDrawable(sharedDrawable);
+ glad.addGLEventListener(..);
+ glad.setVisible(true); // GLWindow creation ..
+ * </pre>
+ * </p>
+ * <h5><a name="synchronization">GL Object Synchronization</a></h5>
+ * <p>
+ * Usually synchronization of shared GL objects should not be required, if the shared GL objects
+ * are created and immutable before concurrent usage.
+ * </p>
+ * <p>
+ * However, using drivers exposing {@link GLRendererQuirks#NeedSharedObjectSync} always
+ * require the user to synchronize access of shared GL objects.
+ * </p>
+ * <p>
+ * Synchronization can be avoided if accessing the shared GL objects
+ * exclusively via a queue or {@link com.jogamp.common.util.Ringbuffer Ringbuffer}, see GLMediaPlayerImpl as an example.
+ * </p>
+ * </p>
+ * <h5><a name="driverissues">Known Driver Issues</a></h5>
+ * <h7><a name="intelmesa">Intel's Mesa >= 9.1.2 Backend for [Sandybridge/Ivybridge] on GNU/Linux</a></h7>
+ * <p>
+ * <pre>
+ * Error: 'intel_do_flush_locked: No such file or directory'
+ * JogAmp: https://jogamp.org/bugzilla/show_bug.cgi?id=873
+ * freedesktop.org: https://bugs.freedesktop.org/show_bug.cgi?id=41736#c8
+ * </pre>
+ * Shared context seems not to be supported w/ lock-free bound X11 display connections
+ * per OpenGL drawable/context. The error message above is thrown in this case.
+ * Hence the driver bug renders shared context use w/ JOGL impossible.
+ * </p>
+ * <h7><a name="hisilicon">Hisilicon's Immersion.16 on Android</a></h7>
+ * <p>
+ * We failed to create a shared ES2 context on another thread.
+ * </p>
+ */
+public interface GLSharedContextSetter extends GLAutoDrawable {
+ /**
+ * Specifies an {@link GLContext OpenGL context}, which shall be shared by this {@link GLAutoDrawable}'s {@link GLContext}.
+ * <p>
+ * Since the {@link GLDrawable drawable} and {@link GLContext context} is created
+ * at {@link GLAutoDrawable#initialization GLAutoDrawable initialization}
+ * this method shall be called beforehand to have any effect.
+ * </p>
+ * <p>
+ * A set <i>sharedContext</i> will block context creation, i.e. {@link GLAutoDrawable#initialization GLAutoDrawable initialization},
+ * as long it is not {@link GLContext#isCreated() created natively}.
+ * </p>
+ * <p>
+ * The <i>preferred method</i> of assigning a <i>shared context</i> is
+ * to {@link #setSharedAutoDrawable(GLAutoDrawable) set the shared GLAutoDrawable},
+ * since this method also takes the {@link GLEventListener}
+ * {@link GLAutoDrawable#areAllGLEventListenerInitialized() initialization into account}.
+ * </p>
+ * <p>
+ * See <a href="#lifecycle">Lifecycle Considerations</a>.
+ * </p>
+ *
+ * @param sharedContext The OpenGL context to be shared by this {@link GLAutoDrawable}'s {@link GLContext}.
+ * @throws IllegalStateException if a {@link #setSharedContext(GLContext) shared GLContext}
+ * or {@link #setSharedAutoDrawable(GLAutoDrawable) shared GLAutoDrawable} is already set,
+ * the given sharedContext is null or equal to this {@link GLAutoDrawable}'s context.
+ * @see #setSharedAutoDrawable(GLAutoDrawable)
+ */
+ void setSharedContext(GLContext sharedContext) throws IllegalStateException;
+
+ /**
+ * Specifies an {@link GLAutoDrawable}, which {@link GLContext OpenGL context} shall be shared by this {@link GLAutoDrawable}'s {@link GLContext}.
+ * <p>
+ * Since the {@link GLDrawable drawable} and {@link GLContext context} is created
+ * at {@link GLAutoDrawable#initialization GLAutoDrawable initialization}
+ * this method shall be called beforehand to have any effect.
+ * </p>
+ * <p>
+ * A set <i>sharedAutoDrawable</i> will block context creation, i.e. <a href="GLAutoDrawable.html#initialization">initialization</a>
+ * as long it's
+ * <ul>
+ * <li>{@link GLContext} is <code>null</code>, or</li>
+ * <li>{@link GLContext} has not been {@link GLContext#isCreated() created natively}, or</li>
+ * <li>{@link GLEventListener} are <i>not</i> {@link GLAutoDrawable#areAllGLEventListenerInitialized() completely initialized}</li>
+ * </ul>
+ * </p>
+ * <p>
+ * See <a href="#lifecycle">Lifecycle Considerations</a>.
+ * </p>
+ *
+ * @param sharedContext The GLAutoDrawable, which OpenGL context shall be shared by this {@link GLAutoDrawable}'s {@link GLContext}.
+ * @throws IllegalStateException if a {@link #setSharedContext(GLContext) shared GLContext}
+ * or {@link #setSharedAutoDrawable(GLAutoDrawable) shared GLAutoDrawable} is already set,
+ * the given sharedAutoDrawable is null or equal to this GLAutoDrawable.
+ * @see #setSharedContext(GLContext)
+ */
+ void setSharedAutoDrawable(GLAutoDrawable sharedAutoDrawable) throws IllegalStateException;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/GLUniformData.java b/src/jogl/classes/com/jogamp/opengl/GLUniformData.java
new file mode 100644
index 000000000..44f7f29c7
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/GLUniformData.java
@@ -0,0 +1,227 @@
+
+package com.jogamp.opengl;
+
+import java.nio.*;
+
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.opengl.math.FloatUtil;
+
+public class GLUniformData {
+
+ /**
+ * int atom
+ *
+ * Number of objects is 1
+ *
+ */
+ public GLUniformData(final String name, final int val) {
+ initScalar(name, 1, Integer.valueOf(val));
+ }
+
+ /**
+ * float atom
+ *
+ * Number of objects is 1
+ *
+ */
+ public GLUniformData(final String name, final float val) {
+ initScalar(name, 1, Float.valueOf(val));
+ }
+
+ /**
+ * Multiple IntBuffer Vector
+ *
+ * Number of objects is calculated by data.limit()/components
+ *
+ * @param components number of elements of one object, ie 4 for GL_FLOAT_VEC4,
+ */
+ public GLUniformData(final String name, final int components, final IntBuffer data) {
+ initBuffer(name, components, data);
+ }
+
+ /**
+ * Multiple FloatBuffer Vector
+ *
+ * Number of objects is calculated by data.limit()/components
+ *
+ * @param components number of elements of one object, ie 4 for GL_FLOAT_VEC4,
+ */
+ public GLUniformData(final String name, final int components, final FloatBuffer data) {
+ initBuffer(name, components, data);
+ }
+
+ private GLUniformData(final int components, final String name) {
+ initBuffer(name, components, null);
+ }
+
+ public static GLUniformData creatEmptyVector(final String name, final int components) {
+ return new GLUniformData(components, name);
+ }
+
+ public static GLUniformData creatEmptyMatrix(final String name, final int rows, final int columns) {
+ return new GLUniformData(name, rows, columns, null);
+ }
+
+ /**
+ * Multiple FloatBuffer Matrix
+ *
+ * Number of objects is calculated by data.limit()/(rows*columns)
+ *
+ * @param rows the matrix rows
+ * @param column the matrix column
+ */
+ public GLUniformData(final String name, final int rows, final int columns, final FloatBuffer data) {
+ initBuffer(name, rows, columns, data);
+ }
+
+ public GLUniformData setData(final int data) { initScalar(Integer.valueOf(data)); return this; }
+ public GLUniformData setData(final float data) { initScalar(Float.valueOf(data)); return this; }
+ public GLUniformData setData(final IntBuffer data) { initBuffer(data); return this; }
+ public GLUniformData setData(final FloatBuffer data) { initBuffer(data); return this; }
+
+ public int intValue() { return ((Integer)data).intValue(); };
+ public float floatValue() { return ((Float)data).floatValue(); };
+ public IntBuffer intBufferValue() { return (IntBuffer)data; };
+ public FloatBuffer floatBufferValue() { return (FloatBuffer)data; };
+
+ public StringBuilder toString(StringBuilder sb) {
+ if(null == sb) {
+ sb = new StringBuilder();
+ }
+ sb.append("GLUniformData[name ").append(name).
+ append(", location ").append(location).
+ append(", size ").append(rows).append("x").append(columns).
+ append(", count ").append(count).
+ append(", data ");
+ if(isMatrix() && data instanceof FloatBuffer) {
+ sb.append("\n");
+ final FloatBuffer fb = (FloatBuffer)getBuffer();
+ for(int i=0; i<count; i++) {
+ FloatUtil.matrixToString(sb, i+": ", "%10.5f", fb, i*rows*columns, rows, columns, false);
+ sb.append(",\n");
+ }
+ } else if(isBuffer()) {
+ Buffers.toString(sb, null, getBuffer());
+ } else {
+ sb.append(data);
+ }
+ sb.append("]");
+ return sb;
+ }
+
+ @Override
+ public String toString() {
+ return toString(null).toString();
+ }
+
+ private void initBuffer(final String name, final int rows, final int columns, final Buffer buffer) {
+ if( 2>rows || rows>4 || 2>columns || columns>4 ) {
+ throw new GLException("rowsXcolumns must be within [2..4]X[2..4], is: "+rows+"X"+columns);
+ }
+ this.name=name;
+ this.rows=rows;
+ this.columns=columns;
+ this.isMatrix=true;
+ this.location=-1;
+ initBuffer(buffer);
+ }
+ private void initScalar(final String name, final int components, final Object data) {
+ if( 1>components || components>4 ) {
+ throw new GLException("components must be within [1..4], is: "+components);
+ }
+ this.name=name;
+ this.columns=components;
+ this.rows=1;
+ this.isMatrix=false;
+ this.location=-1;
+ initScalar(data);
+ }
+ private void initBuffer(final String name, final int components, final Buffer buffer) {
+ if( 1>components || components>4 ) {
+ throw new GLException("components must be within [1..4], is: "+components);
+ }
+ this.name=name;
+ this.columns=components;
+ this.rows=1;
+ this.isMatrix=false;
+ this.location=-1;
+ initBuffer(buffer);
+ }
+
+ private void initScalar(final Object data) {
+ if(data instanceof Buffer) {
+ initBuffer((Buffer)data);
+ } else if( null != data ) {
+ if(isMatrix) {
+ throw new GLException("Atom type not allowed for matrix : "+this);
+ }
+ this.count=1;
+ this.data=data;
+ } else {
+ this.count=0;
+ this.data=data;
+ }
+ }
+
+ private void initBuffer(final Buffer buffer) {
+ if( null != buffer ) {
+ final int sz = rows*columns;
+ if(buffer.remaining()<sz || 0!=buffer.remaining()%sz) {
+ throw new GLException("remaining data buffer size invalid: buffer: "+buffer.toString()+"\n\t"+this);
+ }
+ this.count=buffer.remaining()/sz;
+ this.data=buffer;
+ } else {
+ this.count=0;
+ this.data=null;
+ }
+ }
+
+ public String getName() { return name; }
+
+ public int getLocation() { return location; }
+
+ /**
+ * Sets the given location of the shader uniform.
+ * @return the given location
+ */
+ public int setLocation(final int location) { this.location=location; return location; }
+
+ /**
+ * Retrieves the location of the shader uniform from the linked shader program.
+ * <p>
+ * No validation is performed within the implementation.
+ * </p>
+ * @param gl
+ * @param program
+ * @return &ge;0 denotes a valid uniform location as found and used in the given shader program.
+ * &lt;0 denotes an invalid location, i.e. not found or used in the given shader program.
+ */
+ public int setLocation(final GL2ES2 gl, final int program) {
+ location = gl.glGetUniformLocation(program, name);
+ return location;
+ }
+
+ public Object getObject() {
+ return data;
+ }
+ public Buffer getBuffer() {
+ return (data instanceof Buffer)?(Buffer)data:null;
+ }
+ public boolean isBuffer() {
+ return (data instanceof Buffer);
+ }
+ public boolean isMatrix() { return isMatrix; }
+
+ public int count() { return count; }
+ public int components() { return rows*columns; }
+ public int rows() { return rows; }
+ public int columns() { return columns; }
+
+ private String name;
+ private int location;
+ private int rows, columns;
+ private int count;
+ private Object data;
+ private boolean isMatrix;
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/Threading.java b/src/jogl/classes/com/jogamp/opengl/Threading.java
new file mode 100644
index 000000000..852c8081f
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/Threading.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2012 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl;
+
+import jogamp.opengl.ThreadingImpl;
+
+/** This API provides access to the threading model for the implementation of
+ the classes in this package.
+
+ <P>
+
+ OpenGL is specified as a thread-safe API, but in practice there
+ are multithreading-related issues on most, if not all, of the
+ platforms which support it. For example, some OpenGL
+ implementations do not behave well when one context is made
+ current first on one thread, released, and then made current on a
+ second thread, although this is legal according to the OpenGL
+ specification. On other platforms there are other problems.
+
+ <P>
+
+ Due to these limitations, and due to the inherent multithreading
+ in the Java platform (in particular, in the Abstract Window
+ Toolkit), it is often necessary to limit the multithreading
+ occurring in the typical application using the OpenGL API.
+
+ <P>
+
+ In the current reference implementation, for instance, multithreading
+ has been limited by
+ forcing all OpenGL-related work for GLAutoDrawables on to a single
+ thread. In other words, if an application uses only the
+ GLAutoDrawable and GLEventListener callback mechanism, it is
+ guaranteed to have the most correct single-threaded behavior on
+ all platforms.
+
+ <P>
+
+ Applications using the GLContext makeCurrent/release API directly
+ will inherently break this single-threaded model, as these methods
+ require that the OpenGL context be made current on the current
+ thread immediately. For applications wishing to integrate better
+ with an implementation that uses the single-threaded model, this
+ class provides public access to the mechanism used by the implementation.
+
+ <P>
+
+ Users can execute Runnables on the
+ internal thread used for performing OpenGL work, and query whether
+ the current thread is already this thread. Using these mechanisms
+ the user can move work from the current thread on to the internal
+ OpenGL thread if desired.
+
+ <P>
+
+ This class also provides mechanisms for querying whether this
+ internal serialization of OpenGL work is in effect, and a
+ programmatic way of disabling it. In the current reference
+ implementation it is enabled by default, although it could be
+ disabled in the future if OpenGL drivers become more robust on
+ all platforms.
+
+ <P>
+
+ In addition to specifying programmatically whether the single
+ thread for OpenGL work is enabled, users may switch it on and off
+ using the system property <code>jogl.1thread</code>. Valid values
+ for this system property are:
+
+ <PRE>
+ -Djogl.1thread=false Disable single-threading of OpenGL work, hence use multithreading.
+ -Djogl.1thread=true Enable single-threading of OpenGL work (default -- on a newly-created worker thread)
+ -Djogl.1thread=auto Select default single-threading behavior (currently on)
+ -Djogl.1thread=awt Enable single-threading of OpenGL work on AWT event dispatch thread (current default on all
+ platforms, and also the default behavior older releases)
+ -Djogl.1thread=worker Enable single-threading of OpenGL work on newly-created worker thread (not suitable for Mac
+ OS X or X11 platforms, and risky on Windows in applet environments)
+ </PRE>
+*/
+
+public class Threading {
+ public static enum Mode {
+ /**
+ * Full multithreaded OpenGL,
+ * i.e. any {@link Threading#invoke(boolean, Runnable, Object) invoke}
+ * {@link Threading#invokeOnOpenGLThread(boolean, Runnable) commands}
+ * will be issued on the current thread immediately.
+ */
+ MT(0),
+
+ /** Single-Threaded OpenGL on AWT EDT */
+ ST_AWT(1),
+
+ /** Single-Threaded OpenGL on dedicated worker thread. */
+ ST_WORKER(2);
+
+ public final int id;
+
+ Mode(final int id){
+ this.id = id;
+ }
+ }
+
+ /** No reason to ever instantiate this class */
+ private Threading() {}
+
+ /** Returns the threading mode */
+ public static Mode getMode() {
+ return ThreadingImpl.getMode();
+ }
+
+ /** If an implementation of the com.jogamp.opengl APIs offers a
+ multithreading option but the default behavior is single-threading,
+ this API provides a mechanism for end users to disable single-threading
+ in this implementation. Users are strongly discouraged from
+ calling this method unless they are aware of all of the
+ consequences and are prepared to enforce some amount of
+ threading restrictions in their applications. Disabling
+ single-threading, for example, may have unintended consequences
+ on GLAutoDrawable implementations such as GLCanvas and GLJPanel.
+ Currently there is no supported way to re-enable it
+ once disabled, partly to discourage careless use of this
+ method. This method should be called as early as possible in an
+ application. */
+ public static final void disableSingleThreading() {
+ ThreadingImpl.disableSingleThreading();
+ }
+
+ /** Indicates whether OpenGL work is being automatically forced to a
+ single thread in this implementation. */
+ public static final boolean isSingleThreaded() {
+ return ThreadingImpl.isSingleThreaded();
+ }
+
+ /** Indicates whether the current thread is the designated toolkit thread,
+ if such semantics exists. */
+ public static final boolean isToolkitThread() throws GLException {
+ return ThreadingImpl.isToolkitThread();
+ }
+
+ /**
+ * Indicates whether the current thread is capable of
+ * performing OpenGL-related work.
+ * <p>
+ * Method always returns <code>true</code>
+ * if {@link #getMode()} == {@link Mode#MT} or {@link #isSingleThreaded()} == <code>false</code>.
+ * </p>
+ */
+ public static final boolean isOpenGLThread() throws GLException {
+ return ThreadingImpl.isOpenGLThread();
+ }
+
+ /** Executes the passed Runnable on the single thread used for all
+ OpenGL work in this com.jogamp.opengl API implementation. It is
+ not specified exactly which thread is used for this
+ purpose. This method should only be called if the single-thread
+ model is in use and if the current thread is not the OpenGL
+ thread (i.e., if <code>isOpenGLThread()</code> returns
+ false). It is up to the end user to check to see whether the
+ current thread is the OpenGL thread and either execute the
+ Runnable directly or perform the work inside it.
+ **/
+ public static final void invokeOnOpenGLThread(final boolean wait, final Runnable r) throws GLException {
+ ThreadingImpl.invokeOnOpenGLThread(wait, r);
+ }
+
+ /**
+ * If not {@link #isOpenGLThread()}
+ * <b>and</b> the <code>lock</code> is not being hold by this thread,
+ * invoke Runnable <code>r</code> on the OpenGL thread via {@link #invokeOnOpenGLThread(boolean, Runnable)}.
+ * <p>
+ * Otherwise invoke Runnable <code>r</code> on the current thread.
+ * </p>
+ *
+ * @param wait set to true for waiting until Runnable <code>r</code> is finished, otherwise false.
+ * @param r the Runnable to be executed
+ * @param lock optional lock object to be tested
+ * @throws GLException
+ */
+ public static final void invoke(final boolean wait, final Runnable r, final Object lock) throws GLException {
+ if ( !isOpenGLThread() &&
+ ( null == lock || !Thread.holdsLock(lock) ) ) {
+ invokeOnOpenGLThread(wait, r);
+ } else {
+ r.run();
+ }
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/TraceGL2.java b/src/jogl/classes/com/jogamp/opengl/TraceGL2.java
new file mode 100644
index 000000000..1609398e7
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/TraceGL2.java
@@ -0,0 +1,23 @@
+package com.jogamp.opengl;
+
+import java.io.PrintStream;
+
+/**
+ * <p>
+ * Composable pipeline which wraps an underlying {@link GL} implementation,
+ * providing tracing information to a user-specified {@link java.io.PrintStream}
+ * before and after each OpenGL method call.
+ * </p>
+ * <p>
+ * Sample code which installs this pipeline, manual:
+ * <pre>
+ * gl = drawable.setGL(new TraceGL(drawable.getGL(), System.err));
+ * </pre>
+ * For automatic instantiation see {@link GLPipelineFactory#create(String, Class, GL, Object[])}.
+ * </p>
+ */
+public class TraceGL2 extends TraceGL4bc {
+ public TraceGL2(final GL2 downstream, final PrintStream stream) {
+ super((GL4bc)downstream, stream);
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/TraceGL3.java b/src/jogl/classes/com/jogamp/opengl/TraceGL3.java
new file mode 100644
index 000000000..fd95d6392
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/TraceGL3.java
@@ -0,0 +1,23 @@
+package com.jogamp.opengl;
+
+import java.io.PrintStream;
+
+/**
+ * <p>
+ * Composable pipeline which wraps an underlying {@link GL} implementation,
+ * providing tracing information to a user-specified {@link java.io.PrintStream}
+ * before and after each OpenGL method call.
+ * </p>
+ * <p>
+ * Sample code which installs this pipeline, manual:
+ * <pre>
+ * gl = drawable.setGL(new TraceGL(drawable.getGL(), System.err));
+ * </pre>
+ * For automatic instantiation see {@link GLPipelineFactory#create(String, Class, GL, Object[])}.
+ * </p>
+ */
+public class TraceGL3 extends TraceGL4bc {
+ public TraceGL3(final GL3 downstream, final PrintStream stream) {
+ super((GL4bc)downstream, stream);
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/TraceGL3bc.java b/src/jogl/classes/com/jogamp/opengl/TraceGL3bc.java
new file mode 100644
index 000000000..7daa9e392
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/TraceGL3bc.java
@@ -0,0 +1,23 @@
+package com.jogamp.opengl;
+
+import java.io.PrintStream;
+
+/**
+ * <p>
+ * Composable pipeline which wraps an underlying {@link GL} implementation,
+ * providing tracing information to a user-specified {@link java.io.PrintStream}
+ * before and after each OpenGL method call.
+ * </p>
+ * <p>
+ * Sample code which installs this pipeline, manual:
+ * <pre>
+ * gl = drawable.setGL(new TraceGL(drawable.getGL(), System.err));
+ * </pre>
+ * For automatic instantiation see {@link GLPipelineFactory#create(String, Class, GL, Object[])}.
+ * </p>
+ */
+public class TraceGL3bc extends TraceGL4bc {
+ public TraceGL3bc(final GL3bc downstream, final PrintStream stream) {
+ super((GL4bc)downstream, stream);
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/TraceGL4.java b/src/jogl/classes/com/jogamp/opengl/TraceGL4.java
new file mode 100644
index 000000000..b0c817105
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/TraceGL4.java
@@ -0,0 +1,23 @@
+package com.jogamp.opengl;
+
+import java.io.PrintStream;
+
+/**
+ * <p>
+ * Composable pipeline which wraps an underlying {@link GL} implementation,
+ * providing tracing information to a user-specified {@link java.io.PrintStream}
+ * before and after each OpenGL method call.
+ * </p>
+ * <p>
+ * Sample code which installs this pipeline, manual:
+ * <pre>
+ * gl = drawable.setGL(new TraceGL(drawable.getGL(), System.err));
+ * </pre>
+ * For automatic instantiation see {@link GLPipelineFactory#create(String, Class, GL, Object[])}.
+ * </p>
+ */
+public class TraceGL4 extends TraceGL4bc {
+ public TraceGL4(final GL4 downstream, final PrintStream stream) {
+ super((GL4bc)downstream, stream);
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/TraceGLES2.java b/src/jogl/classes/com/jogamp/opengl/TraceGLES2.java
new file mode 100644
index 000000000..7c7956b68
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/TraceGLES2.java
@@ -0,0 +1,23 @@
+package com.jogamp.opengl;
+
+import java.io.PrintStream;
+
+/**
+ * <p>
+ * Composable pipeline which wraps an underlying {@link GL} implementation,
+ * providing tracing information to a user-specified {@link java.io.PrintStream}
+ * before and after each OpenGL method call.
+ * </p>
+ * <p>
+ * Sample code which installs this pipeline, manual:
+ * <pre>
+ * gl = drawable.setGL(new TraceGL(drawable.getGL(), System.err));
+ * </pre>
+ * For automatic instantiation see {@link GLPipelineFactory#create(String, Class, GL, Object[])}.
+ * </p>
+ */
+public class TraceGLES2 extends TraceGLES3 {
+ public TraceGLES2(final GLES2 downstream, final PrintStream stream) {
+ super((GLES3)downstream, stream);
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/awt/AWTGLAutoDrawable.java b/src/jogl/classes/com/jogamp/opengl/awt/AWTGLAutoDrawable.java
new file mode 100644
index 000000000..6e273e4e6
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/awt/AWTGLAutoDrawable.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl.awt;
+
+import com.jogamp.opengl.GLAutoDrawable;
+
+public interface AWTGLAutoDrawable extends GLAutoDrawable, ComponentEvents {
+ /** Requests a new width and height for this AWTGLAutoDrawable. */
+ public void setSize(int width, int height);
+
+ /** Schedules a repaint of the component at some point in the
+ future. */
+ public void repaint();
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/awt/ComponentEvents.java b/src/jogl/classes/com/jogamp/opengl/awt/ComponentEvents.java
new file mode 100644
index 000000000..996776c9b
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/awt/ComponentEvents.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl.awt;
+
+import com.jogamp.opengl.*;
+import java.awt.event.*;
+import java.beans.PropertyChangeListener;
+
+/** Factors out the listener manipulation for the events supported by
+ all of the {@link GLDrawable} implementations. Provided to reduce
+ clutter in the documentation for GLDrawable. */
+
+public interface ComponentEvents {
+ public void addComponentListener(ComponentListener l);
+ public void removeComponentListener(ComponentListener l);
+ public void addFocusListener(FocusListener l);
+ public void removeFocusListener(FocusListener l);
+ public void addHierarchyBoundsListener(HierarchyBoundsListener l);
+ public void removeHierarchyBoundsListener(HierarchyBoundsListener l);
+ public void addHierarchyListener(HierarchyListener l);
+ public void removeHierarchyListener(HierarchyListener l);
+ public void addInputMethodListener(InputMethodListener l);
+ public void removeInputMethodListener(InputMethodListener l);
+ public void addKeyListener(KeyListener l);
+ public void removeKeyListener(KeyListener l);
+ public void addMouseListener(MouseListener l);
+ public void removeMouseListener(MouseListener l);
+ public void addMouseMotionListener(MouseMotionListener l);
+ public void removeMouseMotionListener(MouseMotionListener l);
+ public void addMouseWheelListener(MouseWheelListener l);
+ public void removeMouseWheelListener(MouseWheelListener l);
+ public void addPropertyChangeListener(PropertyChangeListener listener);
+ public void removePropertyChangeListener(PropertyChangeListener listener);
+ public void addPropertyChangeListener(String propertyName,
+ PropertyChangeListener listener);
+ public void removePropertyChangeListener(String propertyName,
+ PropertyChangeListener listener);
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java b/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java
new file mode 100644
index 000000000..11d217535
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/awt/GLCanvas.java
@@ -0,0 +1,1643 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl.awt;
+
+import java.beans.Beans;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.awt.Canvas;
+import java.awt.Color;
+import java.awt.FontMetrics;
+import java.awt.Frame;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsDevice;
+import java.awt.event.HierarchyEvent;
+import java.awt.event.HierarchyListener;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Rectangle2D;
+import java.awt.EventQueue;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.jogamp.nativewindow.AbstractGraphicsConfiguration;
+import com.jogamp.nativewindow.OffscreenLayerOption;
+import com.jogamp.nativewindow.ScalableSurface;
+import com.jogamp.nativewindow.VisualIDHolder;
+import com.jogamp.nativewindow.WindowClosingProtocol;
+import com.jogamp.nativewindow.AbstractGraphicsDevice;
+import com.jogamp.nativewindow.AbstractGraphicsScreen;
+import com.jogamp.nativewindow.GraphicsConfigurationFactory;
+import com.jogamp.nativewindow.NativeSurface;
+import com.jogamp.nativewindow.NativeWindowFactory;
+import com.jogamp.opengl.GL;
+import com.jogamp.opengl.GLAnimatorControl;
+import com.jogamp.opengl.GLAutoDrawable;
+import com.jogamp.opengl.GLCapabilities;
+import com.jogamp.opengl.GLCapabilitiesChooser;
+import com.jogamp.opengl.GLCapabilitiesImmutable;
+import com.jogamp.opengl.GLContext;
+import com.jogamp.opengl.GLDrawable;
+import com.jogamp.opengl.GLDrawableFactory;
+import com.jogamp.opengl.GLEventListener;
+import com.jogamp.opengl.GLException;
+import com.jogamp.opengl.GLOffscreenAutoDrawable;
+import com.jogamp.opengl.GLProfile;
+import com.jogamp.opengl.GLRunnable;
+import com.jogamp.opengl.GLSharedContextSetter;
+import com.jogamp.opengl.Threading;
+
+import com.jogamp.common.GlueGenVersion;
+import com.jogamp.common.util.VersionUtil;
+import com.jogamp.common.util.awt.AWTEDTExecutor;
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
+import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration;
+import com.jogamp.nativewindow.awt.AWTGraphicsDevice;
+import com.jogamp.nativewindow.awt.AWTGraphicsScreen;
+import com.jogamp.nativewindow.awt.AWTPrintLifecycle;
+import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol;
+import com.jogamp.nativewindow.awt.JAWTWindow;
+import com.jogamp.opengl.JoglVersion;
+import com.jogamp.opengl.util.GLDrawableUtil;
+import com.jogamp.opengl.util.TileRenderer;
+
+import jogamp.nativewindow.SurfaceScaleUtils;
+import jogamp.opengl.Debug;
+import jogamp.opengl.GLContextImpl;
+import jogamp.opengl.GLDrawableHelper;
+import jogamp.opengl.GLDrawableImpl;
+import jogamp.opengl.awt.AWTTilePainter;
+
+// FIXME: Subclasses need to call resetGLFunctionAvailability() on their
+// context whenever the displayChanged() function is called on our
+// GLEventListeners
+
+/** A heavyweight AWT component which provides OpenGL rendering
+ support. This is the primary implementation of an AWT {@link GLDrawable};
+ {@link GLJPanel} is provided for compatibility with Swing user
+ interfaces when adding a heavyweight doesn't work either because
+ of Z-ordering or LayoutManager problems.
+ *
+ * <h5><a name="offscreenlayer">Offscreen Layer Remarks</a></h5>
+ *
+ * {@link OffscreenLayerOption#setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)}
+ * maybe called to use an offscreen drawable (FBO or PBuffer) allowing
+ * the underlying JAWT mechanism to composite the image, if supported.
+ * <p>
+ * {@link OffscreenLayerOption#setShallUseOffscreenLayer(boolean) setShallUseOffscreenLayer(true)}
+ * is being called if {@link GLCapabilitiesImmutable#isOnscreen()} is <code>false</code>.
+ * </p>
+ *
+ * <h5><a name="java2dgl">Java2D OpenGL Remarks</a></h5>
+ *
+ * To avoid any conflicts with a potential Java2D OpenGL context,<br>
+ * you shall consider setting the following JVM properties:<br>
+ * <ul>
+ * <li><pre>sun.java2d.opengl=false</pre></li>
+ * <li><pre>sun.java2d.noddraw=true</pre></li>
+ * </ul>
+ * This is especially true in case you want to utilize a GLProfile other than
+ * {@link GLProfile#GL2}, eg. using {@link GLProfile#getMaxFixedFunc()}.<br>
+ * On the other hand, if you like to experiment with GLJPanel's utilization
+ * of Java2D's OpenGL pipeline, you have to set them to
+ * <ul>
+ * <li><pre>sun.java2d.opengl=true</pre></li>
+ * <li><pre>sun.java2d.noddraw=true</pre></li>
+ * </ul>
+ *
+ * <h5><a name="backgrounderase">Disable Background Erase</a></h5>
+ *
+ * GLCanvas tries to disable background erase for the AWT Canvas
+ * before native peer creation (X11) and after it (Windows), <br>
+ * utilizing the optional {@link java.awt.Toolkit} method <code>disableBeackgroundErase(java.awt.Canvas)</code>.<br>
+ * However if this does not give you the desired results, you may want to disable AWT background erase in general:
+ * <ul>
+ * <li><pre>sun.awt.noerasebackground=true</pre></li>
+ * </ul>
+ *
+ * <p>
+ * <a name="contextSharing"><h5>OpenGL Context Sharing</h5></a>
+ * To share a {@link GLContext} see the following note in the documentation overview:
+ * <a href="../../../../overview-summary.html#SHARING">context sharing</a>
+ * as well as {@link GLSharedContextSetter}.
+ * </p>
+ */
+
+@SuppressWarnings("serial")
+public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosingProtocol, OffscreenLayerOption,
+ AWTPrintLifecycle, GLSharedContextSetter, ScalableSurface {
+
+ private static final boolean DEBUG = Debug.debug("GLCanvas");
+
+ private final RecursiveLock lock = LockFactory.createRecursiveLock();
+ private final GLDrawableHelper helper = new GLDrawableHelper();
+ private AWTGraphicsConfiguration awtConfig;
+ private volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access
+ private volatile JAWTWindow jawtWindow; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle
+ private volatile GLContextImpl context; // volatile: avoid locking for read-only access
+ private volatile boolean sendReshape = false; // volatile: maybe written by EDT w/o locking
+ private final float[] minPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+ private final float[] maxPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+ private final float[] hasPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+ final float[] reqPixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
+
+ // copy of the cstr args, mainly for recreation
+ private final GLCapabilitiesImmutable capsReqUser;
+ private final GLCapabilitiesChooser chooser;
+ private int additionalCtxCreationFlags = 0;
+ private final GraphicsDevice device;
+ private boolean shallUseOffscreenLayer = false;
+
+ private volatile boolean isShowing;
+ private final HierarchyListener hierarchyListener = new HierarchyListener() {
+ @Override
+ public void hierarchyChanged(final HierarchyEvent e) {
+ isShowing = GLCanvas.this.isShowing();
+ }
+ };
+
+ private final AWTWindowClosingProtocol awtWindowClosingProtocol =
+ new AWTWindowClosingProtocol(this, new Runnable() {
+ @Override
+ public void run() {
+ GLCanvas.this.destroyImpl( true );
+ }
+ }, null);
+
+ /** Creates a new GLCanvas component with a default set of OpenGL
+ capabilities, using the default OpenGL capabilities selection
+ mechanism, on the default screen device.
+ <p>
+ See details about <a href="#contextSharing">OpenGL context sharing</a>.
+ </p>
+ * @throws GLException if no default profile is available for the default desktop device.
+ */
+ public GLCanvas() throws GLException {
+ this(null);
+ }
+
+ /** Creates a new GLCanvas component with the requested set of
+ OpenGL capabilities, using the default OpenGL capabilities
+ selection mechanism, on the default screen device.
+ <p>
+ See details about <a href="#contextSharing">OpenGL context sharing</a>.
+ </p>
+ * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device.
+ * @see GLCanvas#GLCanvas(com.jogamp.opengl.GLCapabilitiesImmutable, com.jogamp.opengl.GLCapabilitiesChooser, com.jogamp.opengl.GLContext, java.awt.GraphicsDevice)
+ */
+ public GLCanvas(final GLCapabilitiesImmutable capsReqUser) throws GLException {
+ this(capsReqUser, null, null);
+ }
+
+ /** Creates a new GLCanvas component. The passed GLCapabilities
+ specifies the OpenGL capabilities for the component; if null, a
+ default set of capabilities is used. The GLCapabilitiesChooser
+ specifies the algorithm for selecting one of the available
+ GLCapabilities for the component; a DefaultGLCapabilitesChooser
+ is used if null is passed for this argument.
+ The passed GraphicsDevice indicates the screen on
+ which to create the GLCanvas; the GLDrawableFactory uses the
+ default screen device of the local GraphicsEnvironment if null
+ is passed for this argument.
+ <p>
+ See details about <a href="#contextSharing">OpenGL context sharing</a>.
+ </p>
+ * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device.
+ */
+ public GLCanvas(final GLCapabilitiesImmutable capsReqUser,
+ final GLCapabilitiesChooser chooser,
+ final GraphicsDevice device)
+ throws GLException
+ {
+ /*
+ * Determination of the native window is made in 'super.addNotify()',
+ * which creates the native peer using AWT's GraphicsConfiguration.
+ * GraphicsConfiguration is returned by this class overwritten
+ * 'getGraphicsConfiguration()', which returns our OpenGL compatible
+ * 'chosen' GraphicsConfiguration.
+ */
+ super();
+
+ if(null==capsReqUser) {
+ this.capsReqUser = new GLCapabilities(GLProfile.getDefault(GLProfile.getDefaultDevice()));
+ } else {
+ // don't allow the user to change data
+ this.capsReqUser = (GLCapabilitiesImmutable) capsReqUser.cloneMutable();
+ }
+ if( !this.capsReqUser.isOnscreen() ) {
+ setShallUseOffscreenLayer(true); // trigger offscreen layer - if supported
+ }
+
+ if(null==device) {
+ final GraphicsConfiguration gc = super.getGraphicsConfiguration();
+ if(null!=gc) {
+ this.device = gc.getDevice();
+ } else {
+ this.device = null;
+ }
+ } else {
+ this.device = device;
+ }
+
+ // instantiation will be issued in addNotify()
+ this.chooser = chooser;
+
+ this.addHierarchyListener(hierarchyListener);
+ this.isShowing = isShowing();
+ }
+
+ @Override
+ public final void setSharedContext(final GLContext sharedContext) throws IllegalStateException {
+ helper.setSharedContext(this.context, sharedContext);
+ }
+
+ @Override
+ public final void setSharedAutoDrawable(final GLAutoDrawable sharedAutoDrawable) throws IllegalStateException {
+ helper.setSharedAutoDrawable(this, sharedAutoDrawable);
+ }
+
+ @Override
+ public final Object getUpstreamWidget() {
+ return this;
+ }
+
+ @Override
+ public final RecursiveLock getUpstreamLock() { return lock; }
+
+ @Override
+ public final boolean isThreadGLCapable() { return Threading.isOpenGLThread(); }
+
+ @Override
+ public void setShallUseOffscreenLayer(final boolean v) {
+ shallUseOffscreenLayer = v;
+ }
+
+ @Override
+ public final boolean getShallUseOffscreenLayer() {
+ return shallUseOffscreenLayer;
+ }
+
+ @Override
+ public final boolean isOffscreenLayerSurfaceEnabled() {
+ final JAWTWindow _jawtWindow = jawtWindow;
+ if(null != _jawtWindow) {
+ return _jawtWindow.isOffscreenLayerSurfaceEnabled();
+ }
+ return false;
+ }
+
+
+ /**
+ * Overridden to choose a GraphicsConfiguration on a parent container's
+ * GraphicsDevice because both devices
+ */
+ @Override
+ public GraphicsConfiguration getGraphicsConfiguration() {
+ /*
+ * Workaround for problems with Xinerama and java.awt.Component.checkGD
+ * when adding to a container on a different graphics device than the
+ * one that this Canvas is associated with.
+ *
+ * GC will be null unless:
+ * - A native peer has assigned it. This means we have a native
+ * peer, and are already comitted to a graphics configuration.
+ * - This canvas has been added to a component hierarchy and has
+ * an ancestor with a non-null GC, but the native peer has not
+ * yet been created. This means we can still choose the GC on
+ * all platforms since the peer hasn't been created.
+ */
+ final GraphicsConfiguration gc = super.getGraphicsConfiguration();
+
+ if( Beans.isDesignTime() ) {
+ return gc;
+ }
+
+ /*
+ * chosen is only non-null on platforms where the GLDrawableFactory
+ * returns a non-null GraphicsConfiguration (in the GLCanvas
+ * constructor).
+ *
+ * if gc is from this Canvas' native peer then it should equal chosen,
+ * otherwise it is from an ancestor component that this Canvas is being
+ * added to, and we go into this block.
+ */
+ GraphicsConfiguration chosen = null != awtConfig ? awtConfig.getAWTGraphicsConfiguration() : null;
+
+ if (gc != null && chosen != null && !chosen.equals(gc)) {
+ /*
+ * Check for compatibility with gc. If they differ by only the
+ * device then return a new GCconfig with the super-class' GDevice
+ * (and presumably the same visual ID in Xinerama).
+ *
+ */
+ if (!chosen.getDevice().getIDstring().equals(gc.getDevice().getIDstring())) {
+ /*
+ * Here we select a GraphicsConfiguration on the alternate
+ * device that is presumably identical to the chosen
+ * configuration, but on the other device.
+ *
+ * Should really check to ensure that we select a configuration
+ * with the same X visual ID for Xinerama screens, otherwise the
+ * GLDrawable may have the wrong visual ID (I don't think this
+ * ever gets updated). May need to add a method to
+ * X11GLDrawableFactory to do this in a platform specific
+ * manner.
+ *
+ * However, on platforms where we can actually get into this
+ * block, both devices should have the same visual list, and the
+ * same configuration should be selected here.
+ */
+ final AWTGraphicsConfiguration config = chooseGraphicsConfiguration( (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities(),
+ (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities(),
+ chooser, gc.getDevice());
+ final GraphicsConfiguration compatible = config.getAWTGraphicsConfiguration();
+ final boolean equalCaps = config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities());
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info:");
+ System.err.println("Created Config (n): HAVE GC "+chosen);
+ System.err.println("Created Config (n): THIS GC "+gc);
+ System.err.println("Created Config (n): Choosen GC "+compatible);
+ System.err.println("Created Config (n): HAVE CF "+awtConfig);
+ System.err.println("Created Config (n): Choosen CF "+config);
+ System.err.println("Created Config (n): EQUALS CAPS "+equalCaps);
+ // Thread.dumpStack();
+ }
+
+ if (compatible != null) {
+ /*
+ * Save the new GC for equals test above, and to return to
+ * any outside callers of this method.
+ */
+ chosen = compatible;
+
+ if( !equalCaps && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) {
+ // complete destruction!
+ destroyImpl( true );
+ // recreation!
+ awtConfig = config;
+ createJAWTDrawableAndContext();
+ validateGLDrawable();
+ } else {
+ awtConfig = config;
+ }
+ }
+ }
+
+ /*
+ * If a compatible GC was not found in the block above, this will
+ * return the GC that was selected in the constructor (and might
+ * cause an exception in Component.checkGD when adding to a
+ * container, but in this case that would be the desired behavior).
+ *
+ */
+ return chosen;
+ } else if (gc == null) {
+ /*
+ * The GC is null, which means we have no native peer, and are not
+ * part of a (realized) component hierarchy. So we return the
+ * desired visual that was selected in the constructor (possibly
+ * null).
+ */
+ return chosen;
+ }
+
+ /*
+ * Otherwise we have not explicitly selected a GC in the constructor, so
+ * just return what Canvas would have.
+ */
+ return gc;
+ }
+
+ @Override
+ public GLContext createContext(final GLContext shareWith) {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if(drawable != null) {
+ final GLContext _ctx = drawable.createContext(shareWith);
+ _ctx.setContextCreationFlags(additionalCtxCreationFlags);
+ return _ctx;
+ }
+ return null;
+ } finally {
+ _lock.unlock();
+ }
+ }
+
+ private final void setRealizedImpl(final boolean realized) {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final GLDrawable _drawable = drawable;
+ if( null == _drawable || realized == _drawable.isRealized() ||
+ realized && ( 0 >= _drawable.getSurfaceWidth() || 0 >= _drawable.getSurfaceHeight() ) ) {
+ return;
+ }
+ _drawable.setRealized(realized);
+ if( realized && _drawable.isRealized() ) {
+ sendReshape=true; // ensure a reshape is being send ..
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+ private final Runnable realizeOnEDTAction = new Runnable() {
+ @Override
+ public void run() { setRealizedImpl(true); }
+ };
+ private final Runnable unrealizeOnEDTAction = new Runnable() {
+ @Override
+ public void run() { setRealizedImpl(false); }
+ };
+
+ @Override
+ public final void setRealized(final boolean realized) {
+ // Make sure drawable realization happens on AWT-EDT and only there. Consider the AWTTree lock!
+ AWTEDTExecutor.singleton.invoke(getTreeLock(), false /* allowOnNonEDT */, true /* wait */, realized ? realizeOnEDTAction : unrealizeOnEDTAction);
+ }
+
+ @Override
+ public boolean isRealized() {
+ final GLDrawable _drawable = drawable;
+ return ( null != _drawable ) ? _drawable.isRealized() : false;
+ }
+
+ @Override
+ public WindowClosingMode getDefaultCloseOperation() {
+ return awtWindowClosingProtocol.getDefaultCloseOperation();
+ }
+
+ @Override
+ public WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) {
+ return awtWindowClosingProtocol.setDefaultCloseOperation(op);
+ }
+
+ @Override
+ public void display() {
+ if( !validateGLDrawable() ) {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: GLCanvas display - skipped GL render, drawable not valid yet");
+ }
+ return; // not yet available ..
+ }
+ if( isShowing && !printActive ) {
+ Threading.invoke(true, displayOnEDTAction, getTreeLock());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>
+ * This impl. only destroys all GL related resources.
+ * </p>
+ * <p>
+ * This impl. does not remove the GLCanvas from it's parent AWT container
+ * so this class's {@link #removeNotify()} AWT override won't get called.
+ * To do so, remove this component from it's parent AWT container.
+ * </p>
+ */
+ @Override
+ public void destroy() {
+ destroyImpl( false );
+ }
+
+ protected void destroyImpl(final boolean destroyJAWTWindowAndAWTDevice) {
+ Threading.invoke(true, destroyOnEDTAction, getTreeLock());
+ if( destroyJAWTWindowAndAWTDevice ) {
+ AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, disposeJAWTWindowAndAWTDeviceOnEDT);
+ }
+ }
+
+ /** Overridden to cause OpenGL rendering to be performed during
+ repaint cycles. Subclasses which override this method must call
+ super.paint() in their paint() method in order to function
+ properly.
+ */
+ @Override
+ public void paint(final Graphics g) {
+ if( Beans.isDesignTime() ) {
+ // Make GLCanvas behave better in NetBeans GUI builder
+ g.setColor(Color.BLACK);
+ g.fillRect(0, 0, getWidth(), getHeight());
+ final FontMetrics fm = g.getFontMetrics();
+ String name = getName();
+ if (name == null) {
+ name = getClass().getName();
+ final int idx = name.lastIndexOf('.');
+ if (idx >= 0) {
+ name = name.substring(idx + 1);
+ }
+ }
+ final Rectangle2D bounds = fm.getStringBounds(name, g);
+ g.setColor(Color.WHITE);
+ g.drawString(name,
+ (int) ((getWidth() - bounds.getWidth()) / 2),
+ (int) ((getHeight() + bounds.getHeight()) / 2));
+ } else if( !this.helper.isAnimatorAnimatingOnOtherThread() ) {
+ display();
+ }
+ }
+
+ /** Overridden to track when this component is added to a container.
+ Subclasses which override this method must call
+ super.addNotify() in their addNotify() method in order to
+ function properly. <P>
+
+ <B>Overrides:</B>
+ <DL><DD><CODE>addNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
+ @SuppressWarnings("deprecation")
+ @Override
+ public void addNotify() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final boolean isBeansDesignTime = Beans.isDesignTime();
+
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: addNotify - start, bounds: "+this.getBounds()+", isBeansDesignTime "+isBeansDesignTime);
+ // Thread.dumpStack();
+ }
+
+ if( isBeansDesignTime ) {
+ super.addNotify();
+ } else {
+ /**
+ * 'super.addNotify()' determines the GraphicsConfiguration,
+ * while calling this class's overriden 'getGraphicsConfiguration()' method
+ * after which it creates the native peer.
+ * Hence we have to set the 'awtConfig' before since it's GraphicsConfiguration
+ * is being used in getGraphicsConfiguration().
+ * This code order also allows recreation, ie re-adding the GLCanvas.
+ */
+ awtConfig = chooseGraphicsConfiguration(capsReqUser, capsReqUser, chooser, device);
+ if(null==awtConfig) {
+ throw new GLException("Error: NULL AWTGraphicsConfiguration");
+ }
+
+ // before native peer is valid: X11
+ disableBackgroundErase();
+
+ // issues getGraphicsConfiguration() and creates the native peer
+ super.addNotify();
+
+ // after native peer is valid: Windows
+ disableBackgroundErase();
+
+ createJAWTDrawableAndContext();
+
+ // init drawable by paint/display makes the init sequence more equal
+ // for all launch flavors (applet/javaws/..)
+ // validateGLDrawable();
+ }
+ awtWindowClosingProtocol.addClosingListener();
+
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: addNotify - end: peer: "+getPeer());
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+
+ @Override
+ public final boolean setSurfaceScale(final float[] pixelScale) {
+ System.arraycopy(pixelScale, 0, reqPixelScale, 0, 2);
+ if( isRealized() && isShowing ) {
+ Threading.invoke(true, setSurfaceScaleOnEDTAction, getTreeLock());
+ return true;
+ } else {
+ return false;
+ }
+ }
+ private final Runnable setSurfaceScaleOnEDTAction = new Runnable() {
+ @Override
+ public void run() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( null != drawable && drawable.isRealized() ) {
+ if( setSurfaceScaleImpl(jawtWindow) ) {
+ reshapeImpl(getWidth(), getHeight());
+ if( !helper.isAnimatorAnimatingOnOtherThread() ) {
+ helper.invokeGL(drawable, context, displayAction, initAction); // display
+ }
+ }
+ }
+ } finally {
+ _lock.unlock();
+ }
+ } };
+ private final boolean setSurfaceScaleImpl(final ScalableSurface ns) {
+ if( ns.setSurfaceScale(reqPixelScale) ) {
+ ns.getCurrentSurfaceScale(hasPixelScale);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private final boolean updatePixelScale() {
+ if( jawtWindow.hasPixelScaleChanged() ) {
+ jawtWindow.getMaximumSurfaceScale(maxPixelScale);
+ jawtWindow.getMinimumSurfaceScale(minPixelScale);
+ return setSurfaceScaleImpl(jawtWindow);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public final float[] getRequestedSurfaceScale(final float[] result) {
+ System.arraycopy(reqPixelScale, 0, result, 0, 2);
+ return result;
+ }
+
+ @Override
+ public final float[] getCurrentSurfaceScale(final float[] result) {
+ System.arraycopy(hasPixelScale, 0, result, 0, 2);
+ return result;
+ }
+
+ @Override
+ public float[] getMinimumSurfaceScale(final float[] result) {
+ System.arraycopy(minPixelScale, 0, result, 0, 2);
+ return result;
+ }
+
+ @Override
+ public float[] getMaximumSurfaceScale(final float[] result) {
+ System.arraycopy(maxPixelScale, 0, result, 0, 2);
+ return result;
+ }
+
+ private void createJAWTDrawableAndContext() {
+ if ( !Beans.isDesignTime() ) {
+ jawtWindow = (JAWTWindow) NativeWindowFactory.getNativeWindow(this, awtConfig);
+ jawtWindow.setShallUseOffscreenLayer(shallUseOffscreenLayer);
+ jawtWindow.lockSurface();
+ try {
+ jawtWindow.setSurfaceScale(reqPixelScale);
+ drawable = (GLDrawableImpl) GLDrawableFactory.getFactory(capsReqUser.getGLProfile()).createGLDrawable(jawtWindow);
+ createContextImpl(drawable);
+ jawtWindow.getCurrentSurfaceScale(hasPixelScale);
+ jawtWindow.getMinimumSurfaceScale(minPixelScale);
+ jawtWindow.getMaximumSurfaceScale(maxPixelScale);
+ } finally {
+ jawtWindow.unlockSurface();
+ }
+ }
+ }
+ private boolean createContextImpl(final GLDrawable drawable) {
+ final GLContext[] shareWith = { null };
+ if( !helper.isSharedGLContextPending(shareWith) ) {
+ context = (GLContextImpl) drawable.createContext(shareWith[0]);
+ context.setContextCreationFlags(additionalCtxCreationFlags);
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Context created: has shared "+(null != shareWith[0]));
+ }
+ return true;
+ } else {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Context !created: pending share");
+ }
+ return false;
+ }
+ }
+
+ private boolean validateGLDrawable() {
+ if( Beans.isDesignTime() || !isDisplayable() ) {
+ return false; // early out!
+ }
+ final GLDrawable _drawable = drawable;
+ if ( null != _drawable ) {
+ boolean res = _drawable.isRealized();
+ if( !res ) {
+ // re-try drawable creation
+ if( 0 >= _drawable.getSurfaceWidth() || 0 >= _drawable.getSurfaceHeight() ) {
+ return false; // early out!
+ }
+ setRealized(true);
+ res = _drawable.isRealized();
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Realized Drawable: isRealized "+res+", "+_drawable.toString());
+ // Thread.dumpStack();
+ }
+ }
+ if( res && null == context ) {
+ // re-try context creation
+ res = createContextImpl(_drawable); // pending creation.
+ }
+ return res;
+ }
+ return false;
+ }
+
+ /** <p>Overridden to track when this component is removed from a
+ container. Subclasses which override this method must call
+ super.removeNotify() in their removeNotify() method in order to
+ function properly. </p>
+ <p>User shall not call this method outside of EDT, read the AWT/Swing specs
+ about this.</p>
+ <B>Overrides:</B>
+ <DL><DD><CODE>removeNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
+ @SuppressWarnings("deprecation")
+ @Override
+ public void removeNotify() {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: removeNotify - start");
+ // Thread.dumpStack();
+ }
+
+ awtWindowClosingProtocol.removeClosingListener();
+
+ if( Beans.isDesignTime() ) {
+ super.removeNotify();
+ } else {
+ try {
+ destroyImpl( true );
+ } finally {
+ super.removeNotify();
+ }
+ }
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: removeNotify - end, peer: "+getPeer());
+ }
+ }
+
+ /** Overridden to cause {@link GLDrawableHelper#reshape} to be
+ called on all registered {@link GLEventListener}s. Subclasses
+ which override this method must call super.reshape() in
+ their reshape() method in order to function properly. <P>
+
+ <B>Overrides:</B>
+ <DL><DD><CODE>reshape</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
+ @SuppressWarnings("deprecation")
+ @Override
+ public void reshape(final int x, final int y, final int width, final int height) {
+ synchronized (getTreeLock()) { // super.reshape(..) claims tree lock, so we do extend it's lock over reshape
+ super.reshape(x, y, width, height);
+ reshapeImpl(width, height);
+ }
+ }
+ private void reshapeImpl(final int width, final int height) {
+ final int scaledWidth = SurfaceScaleUtils.scale(width, hasPixelScale[0]);
+ final int scaledHeight = SurfaceScaleUtils.scale(height, hasPixelScale[1]);
+
+ if(DEBUG) {
+ final NativeSurface ns = getNativeSurface();
+ final long nsH = null != ns ? ns.getSurfaceHandle() : 0;
+ System.err.println(getThreadName()+": GLCanvas.reshape.0 "+this.getName()+" resize"+(printActive?"WithinPrint":"")+
+ " [ this "+getWidth()+"x"+getHeight()+", pixelScale "+getPixelScaleStr()+
+ "] -> "+(printActive?"[skipped] ":"") + width+"x"+height+" * "+getPixelScaleStr()+" -> "+scaledWidth+"x"+scaledHeight+
+ " - surfaceHandle 0x"+Long.toHexString(nsH));
+ // Thread.dumpStack();
+ }
+ if( validateGLDrawable() && !printActive ) {
+ final GLDrawableImpl _drawable = drawable;
+ if( ! _drawable.getChosenGLCapabilities().isOnscreen() ) {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final GLDrawableImpl _drawableNew = GLDrawableHelper.resizeOffscreenDrawable(_drawable, context, scaledWidth, scaledHeight);
+ if(_drawable != _drawableNew) {
+ // write back
+ drawable = _drawableNew;
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+ sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock
+ }
+ }
+
+ /**
+ * Overridden from Canvas to prevent the AWT's clearing of the
+ * canvas from interfering with the OpenGL rendering.
+ */
+ @Override
+ public void update(final Graphics g) {
+ paint(g);
+ }
+
+ private volatile boolean printActive = false;
+ private GLAnimatorControl printAnimator = null;
+ private GLAutoDrawable printGLAD = null;
+ private AWTTilePainter printAWTTiles = null;
+
+ @Override
+ public void setupPrint(final double scaleMatX, final double scaleMatY, final int numSamples, final int tileWidth, final int tileHeight) {
+ printActive = true;
+ final int componentCount = isOpaque() ? 3 : 4;
+ final TileRenderer printRenderer = new TileRenderer();
+ printAWTTiles = new AWTTilePainter(printRenderer, componentCount, scaleMatX, scaleMatY, numSamples, tileWidth, tileHeight, DEBUG);
+ AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, setupPrintOnEDT);
+ }
+ private final Runnable setupPrintOnEDT = new Runnable() {
+ @Override
+ public void run() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( !validateGLDrawable() ) {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, drawable not valid yet");
+ }
+ printActive = false;
+ return; // not yet available ..
+ }
+ if( !isVisible() ) {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: GLCanvas setupPrint - skipped GL render, canvas not visible");
+ }
+ printActive = false;
+ return; // not yet available ..
+ }
+ sendReshape = false; // clear reshape flag
+ printAnimator = helper.getAnimator();
+ if( null != printAnimator ) {
+ printAnimator.remove(GLCanvas.this);
+ }
+ printGLAD = GLCanvas.this; // _not_ default, shall be replaced by offscreen GLAD
+ final GLCapabilitiesImmutable gladCaps = getChosenGLCapabilities();
+ final int printNumSamples = printAWTTiles.getNumSamples(gladCaps);
+ GLDrawable printDrawable = printGLAD.getDelegatedDrawable();
+ final boolean reqNewGLADSamples = printNumSamples != gladCaps.getNumSamples();
+ final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() ||
+ printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight();
+ final boolean reqNewGLADOnscrn = gladCaps.isOnscreen();
+
+ final GLCapabilities newGLADCaps = (GLCapabilities)gladCaps.cloneMutable();
+ newGLADCaps.setDoubleBuffered(false);
+ newGLADCaps.setOnscreen(false);
+ if( printNumSamples != newGLADCaps.getNumSamples() ) {
+ newGLADCaps.setSampleBuffers(0 < printNumSamples);
+ newGLADCaps.setNumSamples(printNumSamples);
+ }
+ final boolean reqNewGLADSafe = GLDrawableUtil.isSwapGLContextSafe(getRequestedGLCapabilities(), gladCaps, newGLADCaps);
+
+ final boolean reqNewGLAD = ( reqNewGLADOnscrn || reqNewGLADSamples || reqNewGLADSize ) && reqNewGLADSafe;
+
+ if( DEBUG ) {
+ System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ onscreen "+reqNewGLADOnscrn+", samples "+reqNewGLADSamples+", size "+reqNewGLADSize+", safe "+reqNewGLADSafe+"], "+
+ ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+
+ ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+
+ ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+
+ ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator);
+ }
+ if( reqNewGLAD ) {
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(newGLADCaps.getGLProfile());
+ GLOffscreenAutoDrawable offGLAD = null;
+ try {
+ offGLAD = factory.createOffscreenAutoDrawable(null, newGLADCaps, null,
+ printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE,
+ printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE);
+ } catch (final GLException gle) {
+ if( DEBUG ) {
+ System.err.println("Caught: "+gle.getMessage());
+ gle.printStackTrace();
+ }
+ }
+ if( null != offGLAD ) {
+ printGLAD = offGLAD;
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(GLCanvas.this, printGLAD);
+ printDrawable = printGLAD.getDelegatedDrawable();
+ }
+ }
+ printAWTTiles.setGLOrientation(printGLAD.isGLOriented(), printGLAD.isGLOriented());
+ printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0);
+ printAWTTiles.renderer.attachAutoDrawable(printGLAD);
+ if( DEBUG ) {
+ System.err.println("AWT print.setup "+printAWTTiles);
+ System.err.println("AWT print.setup AA "+printNumSamples+", "+newGLADCaps);
+ System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD);
+ System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable);
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+ };
+
+ @Override
+ public void releasePrint() {
+ if( !printActive || null == printGLAD ) {
+ throw new IllegalStateException("setupPrint() not called");
+ }
+ sendReshape = false; // clear reshape flag
+ AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, releasePrintOnEDT);
+ }
+ private final Runnable releasePrintOnEDT = new Runnable() {
+ @Override
+ public void run() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( DEBUG ) {
+ System.err.println("AWT print.release "+printAWTTiles);
+ }
+ printAWTTiles.dispose();
+ printAWTTiles= null;
+ if( printGLAD != GLCanvas.this ) {
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLCanvas.this);
+ printGLAD.destroy();
+ }
+ printGLAD = null;
+ if( null != printAnimator ) {
+ printAnimator.add(GLCanvas.this);
+ printAnimator = null;
+ }
+ sendReshape = true; // trigger reshape, i.e. gl-viewport and -listener - this component might got resized!
+ printActive = false;
+ display();
+ } finally {
+ _lock.unlock();
+ }
+ }
+ };
+
+ @Override
+ public void print(final Graphics graphics) {
+ if( !printActive || null == printGLAD ) {
+ throw new IllegalStateException("setupPrint() not called");
+ }
+ if(DEBUG && !EventQueue.isDispatchThread()) {
+ System.err.println(getThreadName()+": Warning: GLCanvas print - not called from AWT-EDT");
+ // we cannot dispatch print on AWT-EDT due to printing internal locking ..
+ }
+ sendReshape = false; // clear reshape flag
+
+ final Graphics2D g2d = (Graphics2D)graphics;
+ try {
+ printAWTTiles.setupGraphics2DAndClipBounds(g2d, getWidth(), getHeight());
+ final TileRenderer tileRenderer = printAWTTiles.renderer;
+ if( DEBUG ) {
+ System.err.println("AWT print.0: "+tileRenderer);
+ }
+ if( !tileRenderer.eot() ) {
+ try {
+ do {
+ if( printGLAD != GLCanvas.this ) {
+ tileRenderer.display();
+ } else {
+ Threading.invoke(true, displayOnEDTAction, getTreeLock());
+ }
+ } while ( !tileRenderer.eot() );
+ if( DEBUG ) {
+ System.err.println("AWT print.1: "+printAWTTiles);
+ }
+ } finally {
+ tileRenderer.reset();
+ printAWTTiles.resetGraphics2D();
+ }
+ }
+ } catch (final NoninvertibleTransformException nte) {
+ System.err.println("Caught: Inversion failed of: "+g2d.getTransform());
+ nte.printStackTrace();
+ }
+ if( DEBUG ) {
+ System.err.println("AWT print.X: "+printAWTTiles);
+ }
+ }
+
+ @Override
+ public void addGLEventListener(final GLEventListener listener) {
+ helper.addGLEventListener(listener);
+ }
+
+ @Override
+ public void addGLEventListener(final int index, final GLEventListener listener) throws IndexOutOfBoundsException {
+ helper.addGLEventListener(index, listener);
+ }
+
+ @Override
+ public int getGLEventListenerCount() {
+ return helper.getGLEventListenerCount();
+ }
+
+ @Override
+ public GLEventListener getGLEventListener(final int index) throws IndexOutOfBoundsException {
+ return helper.getGLEventListener(index);
+ }
+
+ @Override
+ public boolean areAllGLEventListenerInitialized() {
+ return helper.areAllGLEventListenerInitialized();
+ }
+
+ @Override
+ public boolean getGLEventListenerInitState(final GLEventListener listener) {
+ return helper.getGLEventListenerInitState(listener);
+ }
+
+ @Override
+ public void setGLEventListenerInitState(final GLEventListener listener, final boolean initialized) {
+ helper.setGLEventListenerInitState(listener, initialized);
+ }
+
+ @Override
+ public GLEventListener disposeGLEventListener(final GLEventListener listener, final boolean remove) {
+ final DisposeGLEventListenerAction r = new DisposeGLEventListenerAction(listener, remove);
+ Threading.invoke(true, r, getTreeLock());
+ return r.listener;
+ }
+
+ @Override
+ public GLEventListener removeGLEventListener(final GLEventListener listener) {
+ return helper.removeGLEventListener(listener);
+ }
+
+ @Override
+ public void setAnimator(final GLAnimatorControl animatorControl) {
+ helper.setAnimator(animatorControl);
+ }
+
+ @Override
+ public GLAnimatorControl getAnimator() {
+ return helper.getAnimator();
+ }
+
+ @Override
+ public final Thread setExclusiveContextThread(final Thread t) throws GLException {
+ return helper.setExclusiveContextThread(t, context);
+ }
+
+ @Override
+ public final Thread getExclusiveContextThread() {
+ return helper.getExclusiveContextThread();
+ }
+
+ @Override
+ public boolean invoke(final boolean wait, final GLRunnable glRunnable) throws IllegalStateException {
+ return helper.invoke(this, wait, glRunnable);
+ }
+
+ @Override
+ public boolean invoke(final boolean wait, final List<GLRunnable> glRunnables) throws IllegalStateException {
+ return helper.invoke(this, wait, glRunnables);
+ }
+
+ @Override
+ public void flushGLRunnables() {
+ helper.flushGLRunnables();
+ }
+
+ @Override
+ public GLContext setContext(final GLContext newCtx, final boolean destroyPrevCtx) {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final GLContext oldCtx = context;
+ GLDrawableHelper.switchContext(drawable, oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags);
+ context=(GLContextImpl)newCtx;
+ return oldCtx;
+ } finally {
+ _lock.unlock();
+ }
+ }
+
+ @Override
+ public final GLDrawable getDelegatedDrawable() {
+ return drawable;
+ }
+
+ @Override
+ public GLContext getContext() {
+ return context;
+ }
+
+ @Override
+ public GL getGL() {
+ if( Beans.isDesignTime() ) {
+ return null;
+ }
+ final GLContext _context = context;
+ return (_context == null) ? null : _context.getGL();
+ }
+
+ @Override
+ public GL setGL(final GL gl) {
+ final GLContext _context = context;
+ if (_context != null) {
+ _context.setGL(gl);
+ return gl;
+ }
+ return null;
+ }
+
+
+ @Override
+ public void setAutoSwapBufferMode(final boolean onOrOff) {
+ helper.setAutoSwapBufferMode(onOrOff);
+ }
+
+ @Override
+ public boolean getAutoSwapBufferMode() {
+ return helper.getAutoSwapBufferMode();
+ }
+
+ @Override
+ public void swapBuffers() {
+ Threading.invoke(true, swapBuffersOnEDTAction, getTreeLock());
+ }
+
+ @Override
+ public void setContextCreationFlags(final int flags) {
+ additionalCtxCreationFlags = flags;
+ final GLContext _context = context;
+ if(null != _context) {
+ _context.setContextCreationFlags(additionalCtxCreationFlags);
+ }
+ }
+
+ @Override
+ public int getContextCreationFlags() {
+ return additionalCtxCreationFlags;
+ }
+
+ @Override
+ public GLProfile getGLProfile() {
+ return capsReqUser.getGLProfile();
+ }
+
+ @Override
+ public GLCapabilitiesImmutable getChosenGLCapabilities() {
+ if( Beans.isDesignTime() ) {
+ return capsReqUser;
+ } else if( null == awtConfig ) {
+ throw new GLException("No AWTGraphicsConfiguration: "+this);
+ }
+ return (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities();
+ }
+
+ @Override
+ public GLCapabilitiesImmutable getRequestedGLCapabilities() {
+ if( null == awtConfig ) {
+ return capsReqUser;
+ }
+ return (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities();
+ }
+
+ @Override
+ public int getSurfaceWidth() {
+ return SurfaceScaleUtils.scale(getWidth(), hasPixelScale[0]);
+ }
+
+ @Override
+ public int getSurfaceHeight() {
+ return SurfaceScaleUtils.scale(getHeight(), hasPixelScale[1]);
+ }
+
+ @Override
+ public boolean isGLOriented() {
+ final GLDrawable _drawable = drawable;
+ return null != _drawable ? _drawable.isGLOriented() : true;
+ }
+
+ @Override
+ public NativeSurface getNativeSurface() {
+ final GLDrawable _drawable = drawable;
+ return (null != _drawable) ? _drawable.getNativeSurface() : null;
+ }
+
+ @Override
+ public long getHandle() {
+ final GLDrawable _drawable = drawable;
+ return (null != _drawable) ? _drawable.getHandle() : 0;
+ }
+
+ @Override
+ public GLDrawableFactory getFactory() {
+ final GLDrawable _drawable = drawable;
+ return (null != _drawable) ? _drawable.getFactory() : null;
+ }
+
+ @Override
+ public String toString() {
+ final GLDrawable _drawable = drawable;
+ final int dw = (null!=_drawable) ? _drawable.getSurfaceWidth() : -1;
+ final int dh = (null!=_drawable) ? _drawable.getSurfaceHeight() : -1;
+
+ return "AWT-GLCanvas[Realized "+isRealized()+
+ ",\n\t"+((null!=_drawable)?_drawable.getClass().getName():"null-drawable")+
+ ",\n\tFactory "+getFactory()+
+ ",\n\thandle 0x"+Long.toHexString(getHandle())+
+ ",\n\tDrawable size "+dw+"x"+dh+" surface["+getSurfaceWidth()+"x"+getSurfaceHeight()+"]"+
+ ",\n\tAWT[pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+
+ ",\n\tvisible "+isVisible()+", displayable "+isDisplayable()+", showing "+isShowing+
+ ",\n\t"+awtConfig+"]]";
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private final String getPixelScaleStr() { return "["+hasPixelScale[0]+", "+hasPixelScale[1]+"]"; }
+
+ private final Runnable destroyOnEDTAction = new Runnable() {
+ @Override
+ public void run() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final GLAnimatorControl animator = getAnimator();
+
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: destroyOnEDTAction() - START, hasContext " +
+ (null!=context) + ", hasDrawable " + (null!=drawable)+", "+animator);
+ // Thread.dumpStack();
+ }
+
+ final boolean animatorPaused;
+ if(null!=animator) {
+ // can't remove us from animator for recreational addNotify()
+ animatorPaused = animator.pause();
+ } else {
+ animatorPaused = false;
+ }
+
+ GLException exceptionOnDisposeGL = null;
+
+ // OLS will be detached by disposeGL's context destruction below
+ if( null != context ) {
+ if( context.isCreated() ) {
+ try {
+ helper.disposeGL(GLCanvas.this, context, true);
+ if(DEBUG) {
+ System.err.println(getThreadName()+": destroyOnEDTAction() - post ctx: "+context);
+ }
+ } catch (final GLException gle) {
+ exceptionOnDisposeGL = gle;
+ }
+ }
+ context = null;
+ }
+
+ Throwable exceptionOnUnrealize = null;
+ if( null != drawable ) {
+ try {
+ drawable.setRealized(false);
+ if(DEBUG) {
+ System.err.println(getThreadName()+": destroyOnEDTAction() - post drawable: "+drawable);
+ }
+ } catch( final Throwable re ) {
+ exceptionOnUnrealize = re;
+ }
+ drawable = null;
+ }
+
+ if(animatorPaused) {
+ animator.resume();
+ }
+
+ // throw exception in order of occurrence ..
+ if( null != exceptionOnDisposeGL ) {
+ throw exceptionOnDisposeGL;
+ }
+ if( null != exceptionOnUnrealize ) {
+ throw GLException.newGLException(exceptionOnUnrealize);
+ }
+
+ if(DEBUG) {
+ System.err.println(getThreadName()+": dispose() - END, animator "+animator);
+ }
+
+ } finally {
+ _lock.unlock();
+ }
+ }
+ };
+
+ /**
+ * Disposes the JAWTWindow and AbstractGraphicsDevice within EDT,
+ * since resources created (X11: Display), must be destroyed in the same thread, where they have been created.
+ * <p>
+ * The drawable and context handle are null'ed as well, assuming {@link #destroy()} has been called already.
+ * </p>
+ *
+ * @see #chooseGraphicsConfiguration(com.jogamp.opengl.GLCapabilitiesImmutable, com.jogamp.opengl.GLCapabilitiesImmutable, com.jogamp.opengl.GLCapabilitiesChooser, java.awt.GraphicsDevice)
+ */
+ private final Runnable disposeJAWTWindowAndAWTDeviceOnEDT = new Runnable() {
+ @Override
+ public void run() {
+ context=null;
+ drawable=null;
+
+ if( null != jawtWindow ) {
+ jawtWindow.destroy();
+ if(DEBUG) {
+ System.err.println(getThreadName()+": GLCanvas.disposeJAWTWindowAndAWTDeviceOnEDT(): post JAWTWindow: "+jawtWindow);
+ }
+ jawtWindow=null;
+ }
+ hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+ hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+ minPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+ minPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+ maxPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+ maxPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+
+ if(null != awtConfig) {
+ final AbstractGraphicsConfiguration aconfig = awtConfig.getNativeGraphicsConfiguration();
+ final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice();
+ final String adeviceMsg;
+ if(DEBUG) {
+ adeviceMsg = adevice.toString();
+ } else {
+ adeviceMsg = null;
+ }
+ final boolean closed = adevice.close();
+ if(DEBUG) {
+ System.err.println(getThreadName()+": GLCanvas.disposeJAWTWindowAndAWTDeviceOnEDT(): post GraphicsDevice: "+adeviceMsg+", result: "+closed);
+ }
+ }
+ awtConfig=null;
+ }
+ };
+
+ private final Runnable initAction = new Runnable() {
+ @Override
+ public void run() {
+ helper.init(GLCanvas.this, !sendReshape);
+ }
+ };
+
+ private final Runnable displayAction = new Runnable() {
+ @Override
+ public void run() {
+ if (sendReshape) {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Reshape: "+getSurfaceWidth()+"x"+getSurfaceHeight());
+ }
+ // Note: we ignore the given x and y within the parent component
+ // since we are drawing directly into this heavyweight component.
+ helper.reshape(GLCanvas.this, 0, 0, getSurfaceWidth(), getSurfaceHeight());
+ sendReshape = false;
+ }
+
+ helper.display(GLCanvas.this);
+ }
+ };
+
+ private final Runnable displayOnEDTAction = new Runnable() {
+ @Override
+ public void run() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( null != drawable && drawable.isRealized() ) {
+ if( GLCanvas.this.updatePixelScale() ) {
+ GLCanvas.this.reshapeImpl(getWidth(), getHeight());
+ }
+ helper.invokeGL(drawable, context, displayAction, initAction);
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+ };
+
+ private final Runnable swapBuffersOnEDTAction = new Runnable() {
+ @Override
+ public void run() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( null != drawable && drawable.isRealized() ) {
+ drawable.swapBuffers();
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+ };
+
+ private class DisposeGLEventListenerAction implements Runnable {
+ GLEventListener listener;
+ private final boolean remove;
+ private DisposeGLEventListenerAction(final GLEventListener listener, final boolean remove) {
+ this.listener = listener;
+ this.remove = remove;
+ }
+
+ @Override
+ public void run() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ listener = helper.disposeGLEventListener(GLCanvas.this, drawable, context, listener, remove);
+ } finally {
+ _lock.unlock();
+ }
+ }
+ };
+
+ // Disables the AWT's erasing of this Canvas's background on Windows
+ // in Java SE 6. This internal API is not available in previous
+ // releases, but the system property
+ // -Dsun.awt.noerasebackground=true can be specified to get similar
+ // results globally in previous releases.
+ private static boolean disableBackgroundEraseInitialized;
+ private static Method disableBackgroundEraseMethod;
+ private void disableBackgroundErase() {
+ if (!disableBackgroundEraseInitialized) {
+ try {
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
+ public Object run() {
+ try {
+ Class<?> clazz = getToolkit().getClass();
+ while (clazz != null && disableBackgroundEraseMethod == null) {
+ try {
+ disableBackgroundEraseMethod =
+ clazz.getDeclaredMethod("disableBackgroundErase",
+ new Class[] { Canvas.class });
+ disableBackgroundEraseMethod.setAccessible(true);
+ } catch (final Exception e) {
+ clazz = clazz.getSuperclass();
+ }
+ }
+ } catch (final Exception e) {
+ }
+ return null;
+ }
+ });
+ } catch (final Exception e) {
+ }
+ disableBackgroundEraseInitialized = true;
+ if(DEBUG) {
+ System.err.println(getThreadName()+": GLCanvas: TK disableBackgroundErase method found: "+
+ (null!=disableBackgroundEraseMethod));
+ }
+ }
+ if (disableBackgroundEraseMethod != null) {
+ Throwable t=null;
+ try {
+ disableBackgroundEraseMethod.invoke(getToolkit(), new Object[] { this });
+ } catch (final Exception e) {
+ t = e;
+ }
+ if(DEBUG) {
+ System.err.println(getThreadName()+": GLCanvas: TK disableBackgroundErase error: "+t);
+ }
+ }
+ }
+
+ /**
+ * Issues the GraphicsConfigurationFactory's choosing facility within EDT,
+ * since resources created (X11: Display), must be destroyed in the same thread, where they have been created.
+ *
+ * @param capsChosen
+ * @param capsRequested
+ * @param chooser
+ * @param device
+ * @return the chosen AWTGraphicsConfiguration
+ *
+ * @see #disposeJAWTWindowAndAWTDeviceOnEDT
+ */
+ private AWTGraphicsConfiguration chooseGraphicsConfiguration(final GLCapabilitiesImmutable capsChosen,
+ final GLCapabilitiesImmutable capsRequested,
+ final GLCapabilitiesChooser chooser,
+ final GraphicsDevice device) {
+ // Make GLCanvas behave better in NetBeans GUI builder
+ if( Beans.isDesignTime() ) {
+ return null;
+ }
+
+ final AbstractGraphicsScreen aScreen = null != device ?
+ AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT):
+ AWTGraphicsScreen.createDefault();
+ AWTGraphicsConfiguration config = null;
+
+ if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) {
+ config = (AWTGraphicsConfiguration)
+ GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, GLCapabilitiesImmutable.class).chooseGraphicsConfiguration(capsChosen,
+ capsRequested,
+ chooser, aScreen, VisualIDHolder.VID_UNDEFINED);
+ } else {
+ try {
+ final ArrayList<AWTGraphicsConfiguration> bucket = new ArrayList<AWTGraphicsConfiguration>(1);
+ EventQueue.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ final AWTGraphicsConfiguration c = (AWTGraphicsConfiguration)
+ GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class, GLCapabilitiesImmutable.class).chooseGraphicsConfiguration(capsChosen,
+ capsRequested,
+ chooser, aScreen, VisualIDHolder.VID_UNDEFINED);
+ bucket.add(c);
+ }
+ });
+ config = ( bucket.size() > 0 ) ? bucket.get(0) : null ;
+ } catch (final InvocationTargetException e) {
+ throw new GLException(e.getTargetException());
+ } catch (final InterruptedException e) {
+ throw new GLException(e);
+ }
+ }
+
+ if ( null == config ) {
+ throw new GLException("Error: Couldn't fetch AWTGraphicsConfiguration");
+ }
+
+ return config;
+ }
+
+ protected static String getThreadName() { return Thread.currentThread().getName(); }
+
+ /**
+ * A most simple JOGL AWT test entry
+ */
+ public static void main(final String args[]) {
+ System.err.println(VersionUtil.getPlatformInfo());
+ System.err.println(GlueGenVersion.getInstance());
+ // System.err.println(NativeWindowVersion.getInstance());
+ System.err.println(JoglVersion.getInstance());
+
+ System.err.println(JoglVersion.getDefaultOpenGLInfo(null, null, true).toString());
+
+ final GLCapabilitiesImmutable caps = new GLCapabilities( GLProfile.getDefault(GLProfile.getDefaultDevice()) );
+ final Frame frame = new Frame("JOGL AWT Test");
+
+ final GLCanvas glCanvas = new GLCanvas(caps);
+ frame.add(glCanvas);
+ frame.setSize(128, 128);
+
+ glCanvas.addGLEventListener(new GLEventListener() {
+ @Override
+ public void init(final GLAutoDrawable drawable) {
+ final GL gl = drawable.getGL();
+ System.err.println(JoglVersion.getGLInfo(gl, null));
+ }
+ @Override
+ public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) { }
+ @Override
+ public void display(final GLAutoDrawable drawable) { }
+ @Override
+ public void dispose(final GLAutoDrawable drawable) { }
+ });
+
+ try {
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ frame.setVisible(true);
+ }});
+ } catch (final Throwable t) {
+ t.printStackTrace();
+ }
+ glCanvas.display();
+ try {
+ javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ frame.dispose();
+ }});
+ } catch (final Throwable t) {
+ t.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java b/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java
new file mode 100644
index 000000000..91b2f5e0c
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/awt/GLJPanel.java
@@ -0,0 +1,2689 @@
+/*
+ * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright (c) 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of Sun Microsystems, Inc. or the names of
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
+ * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
+ * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
+ * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
+ * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
+ * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ *
+ * Sun gratefully acknowledges that this software was originally authored
+ * and developed by Kenneth Bradley Russell and Christopher John Kline.
+ */
+
+package com.jogamp.opengl.awt;
+
+import java.awt.Color;
+import java.awt.EventQueue;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.GraphicsEnvironment;
+import java.awt.Rectangle;
+import java.awt.event.HierarchyEvent;
+import java.awt.event.HierarchyListener;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.beans.Beans;
+import java.nio.IntBuffer;
+import java.util.List;
+
+import com.jogamp.nativewindow.AbstractGraphicsDevice;
+import com.jogamp.nativewindow.NativeSurface;
+import com.jogamp.nativewindow.ScalableSurface;
+import com.jogamp.nativewindow.SurfaceUpdatedListener;
+import com.jogamp.nativewindow.WindowClosingProtocol;
+import com.jogamp.nativewindow.util.PixelFormat;
+import com.jogamp.opengl.GL;
+import com.jogamp.opengl.GL2;
+import com.jogamp.opengl.GL2ES3;
+import com.jogamp.opengl.GL2GL3;
+import com.jogamp.opengl.GLAnimatorControl;
+import com.jogamp.opengl.GLAutoDrawable;
+import com.jogamp.opengl.GLCapabilities;
+import com.jogamp.opengl.GLCapabilitiesChooser;
+import com.jogamp.opengl.GLCapabilitiesImmutable;
+import com.jogamp.opengl.GLContext;
+import com.jogamp.opengl.GLDrawable;
+import com.jogamp.opengl.GLDrawableFactory;
+import com.jogamp.opengl.GLEventListener;
+import com.jogamp.opengl.GLException;
+import com.jogamp.opengl.GLFBODrawable;
+import com.jogamp.opengl.GLOffscreenAutoDrawable;
+import com.jogamp.opengl.GLProfile;
+import com.jogamp.opengl.GLRunnable;
+import com.jogamp.opengl.GLSharedContextSetter;
+import com.jogamp.opengl.Threading;
+import javax.swing.JPanel;
+
+import jogamp.nativewindow.SurfaceScaleUtils;
+import jogamp.nativewindow.WrappedSurface;
+import jogamp.nativewindow.jawt.JAWTUtil;
+import jogamp.opengl.Debug;
+import jogamp.opengl.GLContextImpl;
+import jogamp.opengl.GLDrawableFactoryImpl;
+import jogamp.opengl.GLDrawableHelper;
+import jogamp.opengl.GLDrawableImpl;
+import jogamp.opengl.awt.AWTTilePainter;
+import jogamp.opengl.awt.Java2D;
+import jogamp.opengl.util.glsl.GLSLTextureRaster;
+
+import com.jogamp.common.util.PropertyAccess;
+import com.jogamp.common.util.awt.AWTEDTExecutor;
+import com.jogamp.common.util.locks.LockFactory;
+import com.jogamp.common.util.locks.RecursiveLock;
+import com.jogamp.nativewindow.awt.AWTPrintLifecycle;
+import com.jogamp.nativewindow.awt.AWTWindowClosingProtocol;
+import com.jogamp.opengl.FBObject;
+import com.jogamp.opengl.GLRendererQuirks;
+import com.jogamp.opengl.util.GLPixelBuffer.GLPixelAttributes;
+import com.jogamp.opengl.util.GLPixelBuffer.SingletonGLPixelBufferProvider;
+import com.jogamp.opengl.util.GLDrawableUtil;
+import com.jogamp.opengl.util.GLPixelStorageModes;
+import com.jogamp.opengl.util.TileRenderer;
+import com.jogamp.opengl.util.awt.AWTGLPixelBuffer;
+import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.AWTGLPixelBufferProvider;
+import com.jogamp.opengl.util.awt.AWTGLPixelBuffer.SingleAWTGLPixelBufferProvider;
+import com.jogamp.opengl.util.texture.TextureState;
+
+/** A lightweight Swing component which provides OpenGL rendering
+ support. Provided for compatibility with Swing user interfaces
+ when adding a heavyweight doesn't work either because of
+ Z-ordering or LayoutManager problems.
+ <p>
+ The GLJPanel can be made transparent by creating it with a
+ GLCapabilities object with alpha bits specified and calling {@link
+ #setOpaque}(false). Pixels with resulting OpenGL alpha values less
+ than 1.0 will be overlaid on any underlying Swing rendering.
+ </p>
+ <p>
+ This component attempts to use hardware-accelerated rendering via FBO or pbuffers and
+ falls back on to software rendering if none of the former are available
+ using {@link GLDrawableFactory#createOffscreenDrawable(AbstractGraphicsDevice, GLCapabilitiesImmutable, GLCapabilitiesChooser, int, int) GLDrawableFactory.createOffscreenDrawable(..)}.<br/>
+ </p>
+ <p>
+ <a name="verticalFlip">A vertical-flip is required</a>, if the drawable {@link #isGLOriented()} and {@link #setSkipGLOrientationVerticalFlip(boolean) vertical flip is not skipped}.<br>
+ In this case this component performs the required vertical flip to bring the content from OpenGL's orientation into AWT's orientation.<br>
+ In case <a href="#fboGLSLVerticalFlip">GLSL based vertical-flip</a> is not available,
+ the CPU intensive {@link System#arraycopy(Object, int, Object, int, int) System.arraycopy(..)} is used line by line.
+ See details about <a href="#fboGLSLVerticalFlip">FBO and GLSL vertical flipping</a>.
+ </p>
+ <p>
+ For performance reasons, as well as for <a href="#bug842">GL state sideeffects</a>,
+ <b>{@link #setSkipGLOrientationVerticalFlip(boolean) skipping vertical flip} is highly recommended</b>!
+ </p>
+ <p>
+ The OpenGL path is concluded by copying the rendered pixels an {@link BufferedImage} via {@link GL#glReadPixels(int, int, int, int, int, int, java.nio.Buffer) glReadPixels(..)}
+ for later Java2D composition.
+ </p>
+ <p>
+ Finally the Java2D compositioning takes place via via {@link Graphics#drawImage(java.awt.Image, int, int, int, int, java.awt.image.ImageObserver) Graphics.drawImage(...)}
+ on the prepared {@link BufferedImage} as described above.
+ </p>
+ <P>
+ * Please read <a href="GLCanvas.html#java2dgl">Java2D OpenGL Remarks</a>.
+ * </P>
+ *
+ <a name="fboGLSLVerticalFlip"><h5>FBO / GLSL Vertical Flip</h5></a>
+ If <a href="#verticalFlip">vertical flip is required</a>,
+ FBO is used, GLSL is available and {@link #setSkipGLOrientationVerticalFlip(boolean) vertical flip is not skipped}, a fragment shader is utilized
+ to flip the FBO texture vertically. This hardware-accelerated step can be disabled via system property <code>jogl.gljpanel.noglsl</code>.
+ <p>
+ The FBO / GLSL code path uses one texture-unit and binds the FBO texture to it's active texture-target,
+ see {@link #setTextureUnit(int)} and {@link #getTextureUnit()}.
+ </p>
+ <p>
+ The active and dedicated texture-unit's {@link GL#GL_TEXTURE_2D} state is preserved via {@link TextureState}.
+ See also {@link Texture#textureCallOrder Order of Texture Commands}.
+ </p>
+ <p>
+ The current gl-viewport is preserved.
+ </p>
+ <p>
+ <a name="bug842"><i>Warning (Bug 842)</i></a>: Certain GL states other than viewport and texture (see above)
+ influencing rendering, will also influence the GLSL vertical flip, e.g. {@link GL#glFrontFace(int) glFrontFace}({@link GL#GL_CCW}).
+ It is recommended to reset those states to default when leaving the {@link GLEventListener#display(GLAutoDrawable)} method!
+ We may change this behavior in the future, i.e. preserve all influencing states.
+ </p>
+ <p>
+ <a name="contextSharing"><h5>OpenGL Context Sharing</h5></a>
+ To share a {@link GLContext} see the following note in the documentation overview:
+ <a href="../../../../overview-summary.html#SHARING">context sharing</a>
+ as well as {@link GLSharedContextSetter}.
+ </p>
+*/
+
+@SuppressWarnings("serial")
+public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosingProtocol, AWTPrintLifecycle, GLSharedContextSetter, ScalableSurface {
+ private static final boolean DEBUG;
+ private static final boolean DEBUG_FRAMES;
+ private static final boolean DEBUG_VIEWPORT;
+ private static final boolean USE_GLSL_TEXTURE_RASTERIZER;
+ private static final boolean SKIP_VERTICAL_FLIP_DEFAULT;
+
+ /** Indicates whether the Java 2D OpenGL pipeline is requested by user. */
+ private static final boolean java2dOGLEnabledByProp;
+
+ /** Indicates whether the Java 2D OpenGL pipeline is enabled, resource-compatible and requested by user. */
+ private static final boolean useJava2DGLPipeline;
+
+ /** Indicates whether the Java 2D OpenGL pipeline's usage is error free. */
+ private static boolean java2DGLPipelineOK;
+
+ static {
+ Debug.initSingleton();
+ DEBUG = Debug.debug("GLJPanel");
+ DEBUG_FRAMES = PropertyAccess.isPropertyDefined("jogl.debug.GLJPanel.Frames", true);
+ DEBUG_VIEWPORT = PropertyAccess.isPropertyDefined("jogl.debug.GLJPanel.Viewport", true);
+ USE_GLSL_TEXTURE_RASTERIZER = !PropertyAccess.isPropertyDefined("jogl.gljpanel.noglsl", true);
+ SKIP_VERTICAL_FLIP_DEFAULT = PropertyAccess.isPropertyDefined("jogl.gljpanel.noverticalflip", true);
+ boolean enabled = PropertyAccess.getBooleanProperty("sun.java2d.opengl", false);
+ java2dOGLEnabledByProp = enabled && !PropertyAccess.isPropertyDefined("jogl.gljpanel.noogl", true);
+
+ enabled = false;
+ if( java2dOGLEnabledByProp ) {
+ // Force eager initialization of part of the Java2D class since
+ // otherwise it's likely it will try to be initialized while on
+ // the Queue Flusher Thread, which is not allowed
+ if (Java2D.isOGLPipelineResourceCompatible() && Java2D.isFBOEnabled()) {
+ if( null != Java2D.getShareContext(GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()) ) {
+ enabled = true;
+ }
+ }
+ }
+ useJava2DGLPipeline = enabled;
+ java2DGLPipelineOK = enabled;
+ if( DEBUG ) {
+ System.err.println("GLJPanel: DEBUG_VIEWPORT "+DEBUG_VIEWPORT);
+ System.err.println("GLJPanel: USE_GLSL_TEXTURE_RASTERIZER "+USE_GLSL_TEXTURE_RASTERIZER);
+ System.err.println("GLJPanel: SKIP_VERTICAL_FLIP_DEFAULT "+SKIP_VERTICAL_FLIP_DEFAULT);
+ System.err.println("GLJPanel: java2dOGLEnabledByProp "+java2dOGLEnabledByProp);
+ System.err.println("GLJPanel: useJava2DGLPipeline "+useJava2DGLPipeline);
+ System.err.println("GLJPanel: java2DGLPipelineOK "+java2DGLPipelineOK);
+ }
+ }
+
+ private static SingleAWTGLPixelBufferProvider singleAWTGLPixelBufferProvider = null;
+ private static synchronized SingleAWTGLPixelBufferProvider getSingleAWTGLPixelBufferProvider() {
+ if( null == singleAWTGLPixelBufferProvider ) {
+ singleAWTGLPixelBufferProvider = new SingleAWTGLPixelBufferProvider( true /* allowRowStride */ );
+ }
+ return singleAWTGLPixelBufferProvider;
+ }
+
+ private final RecursiveLock lock = LockFactory.createRecursiveLock();
+
+ private final GLDrawableHelper helper;
+ private boolean autoSwapBufferMode;
+
+ private volatile boolean isInitialized;
+
+ //
+ // Data used for either pbuffers or pixmap-based offscreen surfaces
+ //
+ private AWTGLPixelBufferProvider customPixelBufferProvider = null;
+ /** Requested single buffered offscreen caps */
+ private volatile GLCapabilitiesImmutable reqOffscreenCaps;
+ private volatile GLDrawableFactoryImpl factory;
+ private final GLCapabilitiesChooser chooser;
+ private int additionalCtxCreationFlags = 0;
+
+ // Lazy reshape notification: reshapeWidth -> panelWidth -> backend.width
+ private boolean handleReshape = false;
+ private boolean sendReshape = true;
+
+ private final float[] minPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+ private final float[] maxPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+ private final float[] hasPixelScale = new float[] { ScalableSurface.IDENTITY_PIXELSCALE, ScalableSurface.IDENTITY_PIXELSCALE };
+ private final float[] reqPixelScale = new float[] { ScalableSurface.AUTOMAX_PIXELSCALE, ScalableSurface.AUTOMAX_PIXELSCALE };
+
+ /** For handling reshape events lazily: reshapeWidth -> panelWidth -> backend.width in pixel units (scaled) */
+ private int reshapeWidth;
+ /** For handling reshape events lazily: reshapeHeight -> panelHeight -> backend.height in pixel units (scaled) */
+ private int reshapeHeight;
+
+ /** Scaled pixel width of the actual GLJPanel: reshapeWidth -> panelWidth -> backend.width */
+ private int panelWidth = 0;
+ /** Scaled pixel height of the actual GLJPanel: reshapeHeight -> panelHeight -> backend.height */
+ private int panelHeight = 0;
+
+ // These are always set to (0, 0) except when the Java2D / OpenGL
+ // pipeline is active
+ private int viewportX;
+ private int viewportY;
+
+ private int requestedTextureUnit = 0; // default
+
+ // The backend in use
+ private volatile Backend backend;
+
+ private boolean skipGLOrientationVerticalFlip = SKIP_VERTICAL_FLIP_DEFAULT;
+
+ // Used by all backends either directly or indirectly to hook up callbacks
+ private final Updater updater = new Updater();
+
+ private boolean oglPipelineUsable() {
+ return null == customPixelBufferProvider && useJava2DGLPipeline && java2DGLPipelineOK;
+ }
+
+ private volatile boolean isShowing;
+ private final HierarchyListener hierarchyListener = new HierarchyListener() {
+ @Override
+ public void hierarchyChanged(final HierarchyEvent e) {
+ isShowing = GLJPanel.this.isShowing();
+ }
+ };
+
+ private final AWTWindowClosingProtocol awtWindowClosingProtocol =
+ new AWTWindowClosingProtocol(this, new Runnable() {
+ @Override
+ public void run() {
+ GLJPanel.this.destroy();
+ }
+ }, null);
+
+ /** Creates a new GLJPanel component with a default set of OpenGL
+ capabilities and using the default OpenGL capabilities selection
+ mechanism.
+ <p>
+ See details about <a href="#contextSharing">OpenGL context sharing</a>.
+ </p>
+ * @throws GLException if no default profile is available for the default desktop device.
+ */
+ public GLJPanel() throws GLException {
+ this(null);
+ }
+
+ /** Creates a new GLJPanel component with the requested set of
+ OpenGL capabilities, using the default OpenGL capabilities
+ selection mechanism.
+ <p>
+ See details about <a href="#contextSharing">OpenGL context sharing</a>.
+ </p>
+ * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device.
+ */
+ public GLJPanel(final GLCapabilitiesImmutable userCapsRequest) throws GLException {
+ this(userCapsRequest, null);
+ }
+
+ /** Creates a new GLJPanel component. The passed GLCapabilities
+ specifies the OpenGL capabilities for the component; if null, a
+ default set of capabilities is used. The GLCapabilitiesChooser
+ specifies the algorithm for selecting one of the available
+ GLCapabilities for the component; a DefaultGLCapabilitesChooser
+ is used if null is passed for this argument.
+ <p>
+ See details about <a href="#contextSharing">OpenGL context sharing</a>.
+ </p>
+ * @throws GLException if no GLCapabilities are given and no default profile is available for the default desktop device.
+ */
+ public GLJPanel(final GLCapabilitiesImmutable userCapsRequest, final GLCapabilitiesChooser chooser)
+ throws GLException
+ {
+ super();
+
+ // Works around problems on many vendors' cards; we don't need a
+ // back buffer for the offscreen surface anyway
+ {
+ GLCapabilities caps;
+ if (userCapsRequest != null) {
+ caps = (GLCapabilities) userCapsRequest.cloneMutable();
+ } else {
+ caps = new GLCapabilities(GLProfile.getDefault(GLProfile.getDefaultDevice()));
+ }
+ caps.setDoubleBuffered(false);
+ reqOffscreenCaps = caps;
+ }
+ this.factory = GLDrawableFactoryImpl.getFactoryImpl( reqOffscreenCaps.getGLProfile() ); // pre-fetch, reqOffscreenCaps may changed
+ this.chooser = chooser;
+
+ helper = new GLDrawableHelper();
+ autoSwapBufferMode = helper.getAutoSwapBufferMode();
+
+ this.setFocusable(true); // allow keyboard input!
+ this.addHierarchyListener(hierarchyListener);
+ this.isShowing = isShowing();
+ }
+
+ /**
+ * Attempts to initialize the backend, if not initialized yet.
+ * <p>
+ * If backend is already initialized method returns <code>true</code>.
+ * </p>
+ * <p>
+ * If <code>offthread</code> is <code>true</code>, initialization will kicked off
+ * on a <i>short lived</i> arbitrary thread and method returns immediately.<br/>
+ * If platform supports such <i>arbitrary thread</i> initialization method returns
+ * <code>true</code>, otherwise <code>false</code>.
+ * </p>
+ * <p>
+ * If <code>offthread</code> is <code>false</code>, initialization be performed
+ * on the current thread and method returns after initialization.<br/>
+ * Method returns <code>true</code> if initialization was successful, otherwise <code>false</code>.
+ * <p>
+ * @param offthread
+ */
+ public final boolean initializeBackend(final boolean offthread) {
+ if( offthread ) {
+ new Thread(getThreadName()+"-GLJPanel_Init") {
+ public void run() {
+ if( !isInitialized ) {
+ initializeBackendImpl();
+ }
+ } }.start();
+ return true;
+ } else {
+ if( !isInitialized ) {
+ return initializeBackendImpl();
+ } else {
+ return true;
+ }
+ }
+ }
+
+ @Override
+ public final void setSharedContext(final GLContext sharedContext) throws IllegalStateException {
+ helper.setSharedContext(this.getContext(), sharedContext);
+ }
+
+ @Override
+ public final void setSharedAutoDrawable(final GLAutoDrawable sharedAutoDrawable) throws IllegalStateException {
+ helper.setSharedAutoDrawable(this, sharedAutoDrawable);
+ }
+
+ public AWTGLPixelBufferProvider getCustomPixelBufferProvider() { return customPixelBufferProvider; }
+
+ /**
+ * @param custom custom {@link AWTGLPixelBufferProvider}
+ * @throws IllegalArgumentException if <code>custom</code> is <code>null</code>
+ * @throws IllegalStateException if backend is already realized, i.e. this instanced already painted once.
+ */
+ public void setPixelBufferProvider(final AWTGLPixelBufferProvider custom) throws IllegalArgumentException, IllegalStateException {
+ if( null == custom ) {
+ throw new IllegalArgumentException("Null PixelBufferProvider");
+ }
+ if( null != backend ) {
+ throw new IllegalStateException("Backend already realized.");
+ }
+ customPixelBufferProvider = custom;
+ }
+
+ @Override
+ public final Object getUpstreamWidget() {
+ return this;
+ }
+
+ @Override
+ public final RecursiveLock getUpstreamLock() { return lock; }
+
+ @Override
+ public final boolean isThreadGLCapable() { return EventQueue.isDispatchThread(); }
+
+ @Override
+ public void display() {
+ if( isShowing || ( printActive && isVisible() ) ) {
+ if (EventQueue.isDispatchThread()) {
+ // Want display() to be synchronous, so call paintImmediately()
+ paintImmediatelyAction.run();
+ } else {
+ // Multithreaded redrawing of Swing components is not allowed,
+ // so do everything on the event dispatch thread
+ try {
+ EventQueue.invokeAndWait(paintImmediatelyAction);
+ } catch (final Exception e) {
+ throw new GLException(e);
+ }
+ }
+ }
+ }
+
+ protected void dispose(final Runnable post) {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.dispose() - start");
+ // Thread.dumpStack();
+ }
+
+ if (backend != null && backend.getContext() != null) {
+ final boolean animatorPaused;
+ final GLAnimatorControl animator = getAnimator();
+ if(null!=animator) {
+ animatorPaused = animator.pause();
+ } else {
+ animatorPaused = false;
+ }
+
+ if(backend.getContext().isCreated()) {
+ Threading.invoke(true, disposeAction, getTreeLock());
+ }
+ if(null != backend) {
+ // not yet destroyed due to backend.isUsingOwnThreadManagment() == true
+ backend.destroy();
+ isInitialized = false;
+ }
+ if( null != post ) {
+ post.run();
+ }
+
+ if( animatorPaused ) {
+ animator.resume();
+ }
+ }
+
+ if(DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.dispose() - stop");
+ }
+ }
+
+ /**
+ * Just an alias for removeNotify
+ */
+ @Override
+ public void destroy() {
+ removeNotify();
+ }
+
+ /** Overridden to cause OpenGL rendering to be performed during
+ repaint cycles. Subclasses which override this method must call
+ super.paintComponent() in their paintComponent() method in order
+ to function properly. <P>
+
+ <DL><DD><CODE>paintComponent</CODE> in class <CODE>javax.swing.JComponent</CODE></DD></DL> */
+ @Override
+ protected void paintComponent(final Graphics g) {
+ if (Beans.isDesignTime()) {
+ // Make GLJPanel behave better in NetBeans GUI builder
+ g.setColor(Color.BLACK);
+ g.fillRect(0, 0, getWidth(), getHeight());
+ final FontMetrics fm = g.getFontMetrics();
+ String name = getName();
+ if (name == null) {
+ name = getClass().getName();
+ final int idx = name.lastIndexOf('.');
+ if (idx >= 0) {
+ name = name.substring(idx + 1);
+ }
+ }
+ final Rectangle2D bounds = fm.getStringBounds(name, g);
+ g.setColor(Color.WHITE);
+ g.drawString(name,
+ (int) ((getWidth() - bounds.getWidth()) / 2),
+ (int) ((getHeight() + bounds.getHeight()) / 2));
+ return;
+ }
+
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( !isInitialized ) {
+ initializeBackendImpl();
+ }
+
+ if (!isInitialized || printActive) {
+ return;
+ }
+
+ // NOTE: must do this when the context is not current as it may
+ // involve destroying the pbuffer (current context) and
+ // re-creating it -- tricky to do properly while the context is
+ // current
+ if( !printActive ) {
+ updatePixelScale(backend);
+ if ( handleReshape ) {
+ handleReshape = false;
+ sendReshape = handleReshape();
+ }
+
+ if( isShowing ) {
+ updater.setGraphics(g);
+ backend.doPaintComponent(g);
+ }
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+
+ private final void updateWrappedSurfaceScale(final GLDrawable d) {
+ final NativeSurface s = d.getNativeSurface();
+ if( s instanceof WrappedSurface ) {
+ ((WrappedSurface)s).setSurfaceScale(hasPixelScale);
+ }
+ }
+
+ @Override
+ public final boolean setSurfaceScale(final float[] pixelScale) { // HiDPI support
+ System.arraycopy(pixelScale, 0, reqPixelScale, 0, 2);
+ final Backend b = backend;
+ if ( isInitialized && null != b && isShowing ) {
+ if( isShowing || ( printActive && isVisible() ) ) {
+ if (EventQueue.isDispatchThread()) {
+ setSurfaceScaleAction.run();
+ } else {
+ try {
+ EventQueue.invokeAndWait(setSurfaceScaleAction);
+ } catch (final Exception e) {
+ throw new GLException(e);
+ }
+ }
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+ private final Runnable setSurfaceScaleAction = new Runnable() {
+ @Override
+ public void run() {
+ final Backend b = backend;
+ if( null != b && setSurfaceScaleImpl(b) ) {
+ if( !helper.isAnimatorAnimatingOnOtherThread() ) {
+ paintImmediatelyAction.run(); // display
+ }
+ }
+ }
+ };
+
+ private final boolean setSurfaceScaleImpl(final Backend b) {
+ if( SurfaceScaleUtils.setNewPixelScale(hasPixelScale, hasPixelScale, reqPixelScale, minPixelScale, maxPixelScale, DEBUG ? getClass().getSimpleName() : null) ) {
+ reshapeImpl(getWidth(), getHeight());
+ updateWrappedSurfaceScale(b.getDrawable());
+ return true;
+ }
+ return false;
+ }
+
+ private final boolean updatePixelScale(final Backend b) {
+ if( JAWTUtil.getPixelScale(getGraphicsConfiguration(), minPixelScale, maxPixelScale) ) {
+ return setSurfaceScaleImpl(b);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public final float[] getRequestedSurfaceScale(final float[] result) {
+ System.arraycopy(reqPixelScale, 0, result, 0, 2);
+ return result;
+ }
+
+ @Override
+ public final float[] getCurrentSurfaceScale(final float[] result) {
+ System.arraycopy(hasPixelScale, 0, result, 0, 2);
+ return result;
+ }
+
+ @Override
+ public float[] getMinimumSurfaceScale(final float[] result) {
+ System.arraycopy(minPixelScale, 0, result, 0, 2);
+ return result;
+ }
+
+ @Override
+ public float[] getMaximumSurfaceScale(final float[] result) {
+ System.arraycopy(maxPixelScale, 0, result, 0, 2);
+ return result;
+ }
+
+ /** Overridden to track when this component is added to a container.
+ Subclasses which override this method must call
+ super.addNotify() in their addNotify() method in order to
+ function properly. <P>
+
+ <DL><DD><CODE>addNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
+ @Override
+ public void addNotify() {
+ super.addNotify();
+ awtWindowClosingProtocol.addClosingListener();
+
+ // HiDPI support
+ JAWTUtil.getPixelScale(getGraphicsConfiguration(), minPixelScale, maxPixelScale);
+ SurfaceScaleUtils.setNewPixelScale(hasPixelScale, hasPixelScale, reqPixelScale, minPixelScale, maxPixelScale, DEBUG ? getClass().getSimpleName() : null);
+
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.addNotify()");
+ }
+ }
+
+ /** Overridden to track when this component is removed from a
+ container. Subclasses which override this method must call
+ super.removeNotify() in their removeNotify() method in order to
+ function properly. <P>
+
+ <DL><DD><CODE>removeNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */
+ @Override
+ public void removeNotify() {
+ awtWindowClosingProtocol.removeClosingListener();
+
+ dispose(null);
+ hasPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+ hasPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+ minPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+ minPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+ maxPixelScale[0] = ScalableSurface.IDENTITY_PIXELSCALE;
+ maxPixelScale[1] = ScalableSurface.IDENTITY_PIXELSCALE;
+
+ super.removeNotify();
+ }
+
+ /** Overridden to cause {@link GLDrawableHelper#reshape} to be
+ called on all registered {@link GLEventListener}s. Subclasses
+ which override this method must call super.reshape() in
+ their reshape() method in order to function properly. <P>
+ *
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("deprecation")
+ @Override
+ public void reshape(final int x, final int y, final int width, final int height) {
+ super.reshape(x, y, width, height);
+ reshapeImpl(width, height);
+ }
+
+ private void reshapeImpl(final int width, final int height) {
+ final int scaledWidth = SurfaceScaleUtils.scale(width, hasPixelScale[0]);
+ final int scaledHeight = SurfaceScaleUtils.scale(height, hasPixelScale[1]);
+ if( !printActive && ( handleReshape || scaledWidth != panelWidth || scaledHeight != panelHeight ) ) {
+ reshapeWidth = scaledWidth;
+ reshapeHeight = scaledHeight;
+ handleReshape = true;
+ }
+ if( DEBUG ) {
+ System.err.println(getThreadName()+": GLJPanel.reshape.0 "+this.getName()+" resize ["+(printActive?"printing":"paint")+
+ "] [ this "+getWidth()+"x"+getHeight()+", pixelScale "+getPixelScaleStr()+
+ ", panel "+panelWidth+"x"+panelHeight +
+ "] -> "+(handleReshape?"":"[skipped] ") + width+"x"+height+" * "+getPixelScaleStr()+
+ " -> "+scaledWidth+"x"+scaledHeight+", reshapeSize "+reshapeWidth+"x"+reshapeHeight);
+ }
+ }
+
+ private volatile boolean printActive = false;
+ private GLAnimatorControl printAnimator = null;
+ private GLAutoDrawable printGLAD = null;
+ private AWTTilePainter printAWTTiles = null;
+
+ @Override
+ public void setupPrint(final double scaleMatX, final double scaleMatY, final int numSamples, final int tileWidth, final int tileHeight) {
+ printActive = true;
+ if( DEBUG ) {
+ System.err.printf(getThreadName()+": GLJPanel.setupPrint: scale %f / %f, samples %d, tileSz %d x %d%n", scaleMatX, scaleMatY, numSamples, tileWidth, tileHeight);
+ }
+ final int componentCount = isOpaque() ? 3 : 4;
+ final TileRenderer printRenderer = new TileRenderer();
+ printAWTTiles = new AWTTilePainter(printRenderer, componentCount, scaleMatX, scaleMatY, numSamples, tileWidth, tileHeight, DEBUG);
+ AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, setupPrintOnEDT);
+ }
+ private final Runnable setupPrintOnEDT = new Runnable() {
+ @Override
+ public void run() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( !isInitialized ) {
+ initializeBackendImpl();
+ }
+ if (!isInitialized) {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, drawable not valid yet");
+ }
+ printActive = false;
+ return; // not yet available ..
+ }
+ if( !isVisible() ) {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": Info: GLJPanel setupPrint - skipped GL render, panel not visible");
+ }
+ printActive = false;
+ return; // not yet available ..
+ }
+ sendReshape = false; // clear reshape flag
+ handleReshape = false; // ditto
+ printAnimator = helper.getAnimator();
+ if( null != printAnimator ) {
+ printAnimator.remove(GLJPanel.this);
+ }
+
+ printGLAD = GLJPanel.this; // default: re-use
+ final GLCapabilitiesImmutable gladCaps = getChosenGLCapabilities();
+ final int printNumSamples = printAWTTiles.getNumSamples(gladCaps);
+ GLDrawable printDrawable = printGLAD.getDelegatedDrawable();
+ final boolean reqNewGLADSamples = printNumSamples != gladCaps.getNumSamples();
+ final boolean reqNewGLADSize = printAWTTiles.customTileWidth != -1 && printAWTTiles.customTileWidth != printDrawable.getSurfaceWidth() ||
+ printAWTTiles.customTileHeight != -1 && printAWTTiles.customTileHeight != printDrawable.getSurfaceHeight();
+
+ final GLCapabilities newGLADCaps = (GLCapabilities)gladCaps.cloneMutable();
+ newGLADCaps.setDoubleBuffered(false);
+ newGLADCaps.setOnscreen(false);
+ if( printNumSamples != newGLADCaps.getNumSamples() ) {
+ newGLADCaps.setSampleBuffers(0 < printNumSamples);
+ newGLADCaps.setNumSamples(printNumSamples);
+ }
+ final boolean reqNewGLADSafe = GLDrawableUtil.isSwapGLContextSafe(getRequestedGLCapabilities(), gladCaps, newGLADCaps);
+
+ final boolean reqNewGLAD = ( reqNewGLADSamples || reqNewGLADSize ) && reqNewGLADSafe;
+
+ if( DEBUG ) {
+ System.err.println("AWT print.setup: reqNewGLAD "+reqNewGLAD+"[ samples "+reqNewGLADSamples+", size "+reqNewGLADSize+", safe "+reqNewGLADSafe+"], "+
+ ", drawableSize "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+
+ ", customTileSize "+printAWTTiles.customTileWidth+"x"+printAWTTiles.customTileHeight+
+ ", scaleMat "+printAWTTiles.scaleMatX+" x "+printAWTTiles.scaleMatY+
+ ", numSamples "+printAWTTiles.customNumSamples+" -> "+printNumSamples+", printAnimator "+printAnimator);
+ }
+ if( reqNewGLAD ) {
+ final GLDrawableFactory factory = GLDrawableFactory.getFactory(newGLADCaps.getGLProfile());
+ GLOffscreenAutoDrawable offGLAD = null;
+ try {
+ offGLAD = factory.createOffscreenAutoDrawable(null, newGLADCaps, null,
+ printAWTTiles.customTileWidth != -1 ? printAWTTiles.customTileWidth : DEFAULT_PRINT_TILE_SIZE,
+ printAWTTiles.customTileHeight != -1 ? printAWTTiles.customTileHeight : DEFAULT_PRINT_TILE_SIZE);
+ } catch (final GLException gle) {
+ if( DEBUG ) {
+ System.err.println("Caught: "+gle.getMessage());
+ gle.printStackTrace();
+ }
+ }
+ if( null != offGLAD ) {
+ printGLAD = offGLAD;
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(GLJPanel.this, printGLAD);
+ printDrawable = printGLAD.getDelegatedDrawable();
+ }
+ }
+ printAWTTiles.setGLOrientation( !GLJPanel.this.skipGLOrientationVerticalFlip && printGLAD.isGLOriented(), printGLAD.isGLOriented() );
+ printAWTTiles.renderer.setTileSize(printDrawable.getSurfaceWidth(), printDrawable.getSurfaceHeight(), 0);
+ printAWTTiles.renderer.attachAutoDrawable(printGLAD);
+ if( DEBUG ) {
+ System.err.println("AWT print.setup "+printAWTTiles);
+ System.err.println("AWT print.setup AA "+printNumSamples+", "+newGLADCaps);
+ System.err.println("AWT print.setup printGLAD: "+printGLAD.getSurfaceWidth()+"x"+printGLAD.getSurfaceHeight()+", "+printGLAD);
+ System.err.println("AWT print.setup printDraw: "+printDrawable.getSurfaceWidth()+"x"+printDrawable.getSurfaceHeight()+", "+printDrawable);
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+ };
+
+ @Override
+ public void releasePrint() {
+ if( !printActive ) {
+ throw new IllegalStateException("setupPrint() not called");
+ }
+ sendReshape = false; // clear reshape flag
+ handleReshape = false; // ditto
+ AWTEDTExecutor.singleton.invoke(getTreeLock(), true /* allowOnNonEDT */, true /* wait */, releasePrintOnEDT);
+ }
+
+ private final Runnable releasePrintOnEDT = new Runnable() {
+ @Override
+ public void run() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if( DEBUG ) {
+ System.err.println(getThreadName()+": GLJPanel.releasePrintOnEDT.0 "+printAWTTiles);
+ }
+ printAWTTiles.dispose();
+ printAWTTiles= null;
+ if( printGLAD != GLJPanel.this ) {
+ GLDrawableUtil.swapGLContextAndAllGLEventListener(printGLAD, GLJPanel.this);
+ printGLAD.destroy();
+ }
+ printGLAD = null;
+ if( null != printAnimator ) {
+ printAnimator.add(GLJPanel.this);
+ printAnimator = null;
+ }
+
+ // trigger reshape, i.e. gl-viewport and -listener - this component might got resized!
+ final int awtWidth = GLJPanel.this.getWidth();
+ final int awtHeight= GLJPanel.this.getHeight();
+ final int scaledAWTWidth = SurfaceScaleUtils.scale(awtWidth, hasPixelScale[0]);
+ final int scaledAWTHeight= SurfaceScaleUtils.scale(awtHeight, hasPixelScale[1]);
+ final GLDrawable drawable = GLJPanel.this.getDelegatedDrawable();
+ if( scaledAWTWidth != panelWidth || scaledAWTHeight != panelHeight ||
+ drawable.getSurfaceWidth() != panelWidth || drawable.getSurfaceHeight() != panelHeight ) {
+ // -> !( awtSize == panelSize == drawableSize )
+ if ( DEBUG ) {
+ System.err.println(getThreadName()+": GLJPanel.releasePrintOnEDT.0: resize [printing] panel " +panelWidth+"x"+panelHeight + " @ scale "+getPixelScaleStr()+
+ ", draw "+drawable.getSurfaceWidth()+"x"+drawable.getSurfaceHeight()+
+ " -> " + awtWidth+"x"+awtHeight+" * "+getPixelScaleStr()+" -> "+scaledAWTWidth+"x"+scaledAWTHeight);
+ }
+ reshapeWidth = scaledAWTWidth;
+ reshapeHeight = scaledAWTHeight;
+ sendReshape = handleReshape(); // reshapeSize -> panelSize, backend reshape w/ GL reshape
+ } else {
+ sendReshape = true; // only GL reshape
+ }
+ printActive = false;
+ display();
+ } finally {
+ _lock.unlock();
+ }
+ }
+ };
+
+ @Override
+ public void print(final Graphics graphics) {
+ if( !printActive ) {
+ throw new IllegalStateException("setupPrint() not called");
+ }
+ if(DEBUG && !EventQueue.isDispatchThread()) {
+ System.err.println(getThreadName()+": Warning: GLCanvas print - not called from AWT-EDT");
+ // we cannot dispatch print on AWT-EDT due to printing internal locking ..
+ }
+ sendReshape = false; // clear reshape flag
+ handleReshape = false; // ditto
+
+ final Graphics2D g2d = (Graphics2D)graphics;
+ try {
+ printAWTTiles.setupGraphics2DAndClipBounds(g2d, getWidth(), getHeight());
+ final TileRenderer tileRenderer = printAWTTiles.renderer;
+ if( DEBUG ) {
+ System.err.println("AWT print.0: "+tileRenderer);
+ }
+ if( !tileRenderer.eot() ) {
+ try {
+ do {
+ if( printGLAD != GLJPanel.this ) {
+ tileRenderer.display();
+ } else {
+ backend.doPlainPaint();
+ }
+ } while ( !tileRenderer.eot() );
+ if( DEBUG ) {
+ System.err.println("AWT print.1: "+printAWTTiles);
+ }
+ } finally {
+ tileRenderer.reset();
+ printAWTTiles.resetGraphics2D();
+ }
+ }
+ } catch (final NoninvertibleTransformException nte) {
+ System.err.println("Caught: Inversion failed of: "+g2d.getTransform());
+ nte.printStackTrace();
+ }
+ if( DEBUG ) {
+ System.err.println("AWT print.X: "+printAWTTiles);
+ }
+ }
+ @Override
+ protected void printComponent(final Graphics g) {
+ if( DEBUG ) {
+ System.err.println("AWT printComponent.X: "+printAWTTiles);
+ }
+ print(g);
+ }
+
+ @Override
+ public void setOpaque(final boolean opaque) {
+ if (backend != null) {
+ backend.setOpaque(opaque);
+ }
+ super.setOpaque(opaque);
+ }
+
+ @Override
+ public void addGLEventListener(final GLEventListener listener) {
+ helper.addGLEventListener(listener);
+ }
+
+ @Override
+ public void addGLEventListener(final int index, final GLEventListener listener) {
+ helper.addGLEventListener(index, listener);
+ }
+
+ @Override
+ public int getGLEventListenerCount() {
+ return helper.getGLEventListenerCount();
+ }
+
+ @Override
+ public GLEventListener getGLEventListener(final int index) throws IndexOutOfBoundsException {
+ return helper.getGLEventListener(index);
+ }
+
+ @Override
+ public boolean areAllGLEventListenerInitialized() {
+ return helper.areAllGLEventListenerInitialized();
+ }
+
+ @Override
+ public boolean getGLEventListenerInitState(final GLEventListener listener) {
+ return helper.getGLEventListenerInitState(listener);
+ }
+
+ @Override
+ public void setGLEventListenerInitState(final GLEventListener listener, final boolean initialized) {
+ helper.setGLEventListenerInitState(listener, initialized);
+ }
+
+ @Override
+ public GLEventListener disposeGLEventListener(final GLEventListener listener, final boolean remove) {
+ final DisposeGLEventListenerAction r = new DisposeGLEventListenerAction(listener, remove);
+ if (EventQueue.isDispatchThread()) {
+ r.run();
+ } else {
+ // Multithreaded redrawing of Swing components is not allowed,
+ // so do everything on the event dispatch thread
+ try {
+ EventQueue.invokeAndWait(r);
+ } catch (final Exception e) {
+ throw new GLException(e);
+ }
+ }
+ return r.listener;
+ }
+
+ @Override
+ public GLEventListener removeGLEventListener(final GLEventListener listener) {
+ return helper.removeGLEventListener(listener);
+ }
+
+ @Override
+ public void setAnimator(final GLAnimatorControl animatorControl) {
+ helper.setAnimator(animatorControl);
+ }
+
+ @Override
+ public GLAnimatorControl getAnimator() {
+ return helper.getAnimator();
+ }
+
+ @Override
+ public final Thread setExclusiveContextThread(final Thread t) throws GLException {
+ return helper.setExclusiveContextThread(t, getContext());
+ }
+
+ @Override
+ public final Thread getExclusiveContextThread() {
+ return helper.getExclusiveContextThread();
+ }
+
+ @Override
+ public boolean invoke(final boolean wait, final GLRunnable glRunnable) throws IllegalStateException {
+ return helper.invoke(this, wait, glRunnable);
+ }
+
+ @Override
+ public boolean invoke(final boolean wait, final List<GLRunnable> glRunnables) throws IllegalStateException {
+ return helper.invoke(this, wait, glRunnables);
+ }
+
+ @Override
+ public void flushGLRunnables() {
+ helper.flushGLRunnables();
+ }
+
+ @Override
+ public GLContext createContext(final GLContext shareWith) {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final Backend b = backend;
+ if ( null == b ) {
+ return null;
+ }
+ return b.createContext(shareWith);
+ } finally {
+ _lock.unlock();
+ }
+ }
+
+ @Override
+ public void setRealized(final boolean realized) {
+ }
+
+ @Override
+ public boolean isRealized() {
+ return isInitialized;
+ }
+
+ @Override
+ public GLContext setContext(final GLContext newCtx, final boolean destroyPrevCtx) {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ final Backend b = backend;
+ if ( null == b ) {
+ return null;
+ }
+ final GLContext oldCtx = b.getContext();
+ GLDrawableHelper.switchContext(b.getDrawable(), oldCtx, destroyPrevCtx, newCtx, additionalCtxCreationFlags);
+ b.setContext(newCtx);
+ return oldCtx;
+ } finally {
+ _lock.unlock();
+ }
+ }
+
+
+ @Override
+ public final GLDrawable getDelegatedDrawable() {
+ final Backend b = backend;
+ if ( null == b ) {
+ return null;
+ }
+ return b.getDrawable();
+ }
+
+ @Override
+ public GLContext getContext() {
+ final Backend b = backend;
+ if ( null == b ) {
+ return null;
+ }
+ return b.getContext();
+ }
+
+ @Override
+ public GL getGL() {
+ if (Beans.isDesignTime()) {
+ return null;
+ }
+ final GLContext context = getContext();
+ return (context == null) ? null : context.getGL();
+ }
+
+ @Override
+ public GL setGL(final GL gl) {
+ final GLContext context = getContext();
+ if (context != null) {
+ context.setGL(gl);
+ return gl;
+ }
+ return null;
+ }
+
+ @Override
+ public void setAutoSwapBufferMode(final boolean enable) {
+ this.autoSwapBufferMode = enable;
+ boolean backendHandlesSwapBuffer = false;
+ if( isInitialized ) {
+ final Backend b = backend;
+ if ( null != b ) {
+ backendHandlesSwapBuffer= b.handlesSwapBuffer();
+ }
+ }
+ if( !backendHandlesSwapBuffer ) {
+ helper.setAutoSwapBufferMode(enable);
+ }
+ }
+
+ @Override
+ public boolean getAutoSwapBufferMode() {
+ return autoSwapBufferMode;
+ }
+
+ @Override
+ public void swapBuffers() {
+ if( isInitialized ) {
+ final Backend b = backend;
+ if ( null != b ) {
+ b.swapBuffers();
+ }
+ }
+ }
+
+ @Override
+ public void setContextCreationFlags(final int flags) {
+ additionalCtxCreationFlags = flags;
+ }
+
+ @Override
+ public int getContextCreationFlags() {
+ return additionalCtxCreationFlags;
+ }
+
+ /** For a translucent GLJPanel (one for which {@link #setOpaque
+ setOpaque}(false) has been called), indicates whether the
+ application should preserve the OpenGL color buffer
+ (GL_COLOR_BUFFER_BIT) for correct rendering of the GLJPanel and
+ underlying widgets which may show through portions of the
+ GLJPanel with alpha values less than 1. Most Swing
+ implementations currently expect the GLJPanel to be completely
+ cleared (e.g., by <code>glClear(GL_COLOR_BUFFER_BIT |
+ GL_DEPTH_BUFFER_BIT)</code>), but for certain optimized Swing
+ implementations which use OpenGL internally, it may be possible
+ to perform OpenGL rendering using the GLJPanel into the same
+ OpenGL drawable as the Swing implementation uses. */
+ public boolean shouldPreserveColorBufferIfTranslucent() {
+ return oglPipelineUsable();
+ }
+
+ @Override
+ public int getSurfaceWidth() {
+ return panelWidth; // scaled surface width in pixel units, current as-from reshape
+ }
+
+ @Override
+ public int getSurfaceHeight() {
+ return panelHeight; // scaled surface height in pixel units, current as-from reshape
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p>
+ * Method returns a valid value only <i>after</i>
+ * the backend has been initialized, either {@link #initializeBackend(boolean) eagerly}
+ * or manually via the first display call.<br/>
+ * Method always returns a valid value when called from within a {@link GLEventListener}.
+ * </p>
+ */
+ @Override
+ public boolean isGLOriented() {
+ final Backend b = backend;
+ if ( null == b ) {
+ return true;
+ }
+ return b.getDrawable().isGLOriented();
+ }
+
+ /**
+ * Skip {@link #isGLOriented()} based vertical flip,
+ * which usually is required by the offscreen backend,
+ * see details about <a href="#verticalFlip">vertical flip</a>
+ * and <a href="#fboGLSLVerticalFlip">FBO / GLSL vertical flip</a>.
+ * <p>
+ * If set to <code>true</code>, user needs to flip the OpenGL rendered scene
+ * <i>if {@link #isGLOriented()} == true</i>, e.g. via the projection matrix.<br/>
+ * See constraints of {@link #isGLOriented()}.
+ * </p>
+ */
+ public final void setSkipGLOrientationVerticalFlip(final boolean v) {
+ skipGLOrientationVerticalFlip = v;
+ }
+ /** See {@link #setSkipGLOrientationVerticalFlip(boolean)}. */
+ public final boolean getSkipGLOrientationVerticalFlip() {
+ return skipGLOrientationVerticalFlip;
+ }
+
+ @Override
+ public GLCapabilitiesImmutable getChosenGLCapabilities() {
+ final Backend b = backend;
+ if ( null == b ) {
+ return null;
+ }
+ return b.getChosenGLCapabilities();
+ }
+
+ @Override
+ public final GLCapabilitiesImmutable getRequestedGLCapabilities() {
+ return reqOffscreenCaps;
+ }
+
+ /**
+ * Set a new requested {@link GLCapabilitiesImmutable} for this GLJPanel
+ * allowing reconfiguration.
+ * <p>
+ * Method shall be invoked from the {@link #isThreadGLCapable() AWT-EDT thread}.
+ * In case it is not invoked on the AWT-EDT thread, an attempt is made to do so.
+ * </p>
+ * <p>
+ * Method will dispose a previous {@link #isRealized() realized} GLContext and offscreen backend!
+ * </p>
+ * @param caps new capabilities.
+ */
+ public final void setRequestedGLCapabilities(final GLCapabilitiesImmutable caps) {
+ if( null == caps ) {
+ throw new IllegalArgumentException("null caps");
+ }
+ Threading.invoke(true,
+ new Runnable() {
+ @Override
+ public void run() {
+ dispose( new Runnable() {
+ @Override
+ public void run() {
+ // switch to new caps and re-init backend
+ // after actual dispose, but before resume animator
+ reqOffscreenCaps = caps;
+ initializeBackendImpl();
+ } } );
+ }
+ }, getTreeLock());
+ }
+
+ @Override
+ public final GLProfile getGLProfile() {
+ return reqOffscreenCaps.getGLProfile();
+ }
+
+ @Override
+ public NativeSurface getNativeSurface() {
+ final Backend b = backend;
+ if ( null == b ) {
+ return null;
+ }
+ return b.getDrawable().getNativeSurface();
+ }
+
+ @Override
+ public long getHandle() {
+ final Backend b = backend;
+ if ( null == b ) {
+ return 0;
+ }
+ return b.getDrawable().getNativeSurface().getSurfaceHandle();
+ }
+
+ @Override
+ public final GLDrawableFactory getFactory() {
+ return factory;
+ }
+
+ /**
+ * Returns the used texture unit, i.e. a value of [0..n], or -1 if non used.
+ * <p>
+ * If implementation uses a texture-unit, it will be known only after the first initialization, i.e. display call.
+ * </p>
+ * <p>
+ * See <a href="#fboGLSLVerticalFlip">FBO / GLSL Vertical Flip</a>.
+ * </p>
+ */
+ public final int getTextureUnit() {
+ final Backend b = backend;
+ if ( null == b ) {
+ return -1;
+ }
+ return b.getTextureUnit();
+ }
+
+ /**
+ * Allows user to request a texture unit to be used,
+ * must be called before the first initialization, i.e. {@link #display()} call.
+ * <p>
+ * Defaults to <code>0</code>.
+ * </p>
+ * <p>
+ * See <a href="#fboGLSLVerticalFlip">FBO / GLSL Vertical Flip</a>.
+ * </p>
+ *
+ * @param v requested texture unit
+ * @see #getTextureUnit()
+ */
+ public final void setTextureUnit(final int v) {
+ requestedTextureUnit = v;
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private final Object initSync = new Object();
+ private boolean initializeBackendImpl() {
+ synchronized(initSync) {
+ if( !isInitialized ) {
+ if( handleReshape ) {
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.createAndInitializeBackend.1: ["+(printActive?"printing":"paint")+"] "+
+ panelWidth+"x"+panelHeight+" @ scale "+getPixelScaleStr() + " -> " +
+ reshapeWidth+"x"+reshapeHeight+" @ scale "+getPixelScaleStr());
+ }
+ panelWidth = reshapeWidth;
+ panelHeight = reshapeHeight;
+ handleReshape = false;
+ } else {
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.createAndInitializeBackend.0: ["+(printActive?"printing":"paint")+"] "+
+ panelWidth+"x"+panelHeight+" @ scale "+getPixelScaleStr());
+ }
+ }
+
+ if ( 0 >= panelWidth || 0 >= panelHeight ) {
+ return false;
+ }
+
+ if ( null == backend ) {
+ if ( oglPipelineUsable() ) {
+ backend = new J2DOGLBackend();
+ } else {
+ backend = new OffscreenBackend(customPixelBufferProvider);
+ }
+ isInitialized = false;
+ }
+
+ if (!isInitialized) {
+ this.factory = GLDrawableFactoryImpl.getFactoryImpl( reqOffscreenCaps.getGLProfile() ); // reqOffscreenCaps may have changed
+ backend.initialize();
+ }
+ return isInitialized;
+ } else {
+ return true;
+ }
+ }
+ }
+
+ private final String getPixelScaleStr() { return "["+hasPixelScale[0]+", "+hasPixelScale[1]+"]"; }
+
+ @Override
+ public WindowClosingMode getDefaultCloseOperation() {
+ return awtWindowClosingProtocol.getDefaultCloseOperation();
+ }
+
+ @Override
+ public WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) {
+ return awtWindowClosingProtocol.setDefaultCloseOperation(op);
+ }
+
+ private boolean handleReshape() {
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.handleReshape: "+
+ panelWidth+"x"+panelHeight+" @ scale "+getPixelScaleStr() + " -> " +
+ reshapeWidth+"x"+reshapeHeight+" @ scale "+getPixelScaleStr());
+ }
+ panelWidth = reshapeWidth;
+ panelHeight = reshapeHeight;
+
+ return backend.handleReshape();
+ }
+
+ // This is used as the GLEventListener for the pbuffer-based backend
+ // as well as the callback mechanism for the other backends
+ class Updater implements GLEventListener {
+ private Graphics g;
+
+ public void setGraphics(final Graphics g) {
+ this.g = g;
+ }
+
+ @Override
+ public void init(final GLAutoDrawable drawable) {
+ if (!backend.preGL(g)) {
+ return;
+ }
+ helper.init(GLJPanel.this, !sendReshape);
+ backend.postGL(g, false);
+ }
+
+ @Override
+ public void dispose(final GLAutoDrawable drawable) {
+ helper.disposeAllGLEventListener(GLJPanel.this, false);
+ }
+
+ @Override
+ public void display(final GLAutoDrawable drawable) {
+ if (!backend.preGL(g)) {
+ return;
+ }
+ if (sendReshape) {
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.display: reshape(" + viewportX + "," + viewportY + " " + panelWidth + "x" + panelHeight + " @ scale "+getPixelScaleStr()+")");
+ }
+ helper.reshape(GLJPanel.this, viewportX, viewportY, panelWidth, panelHeight);
+ sendReshape = false;
+ }
+
+ helper.display(GLJPanel.this);
+ backend.postGL(g, true);
+ }
+
+ public void plainPaint(final GLAutoDrawable drawable) {
+ helper.display(GLJPanel.this);
+ }
+
+ @Override
+ public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, final int height) {
+ // This is handled above and dispatched directly to the appropriate context
+ }
+ }
+
+ @Override
+ public String toString() {
+ final GLDrawable d = ( null != backend ) ? backend.getDrawable() : null;
+ return "AWT-GLJPanel[ drawableType "+ ( ( null != d ) ? d.getClass().getName() : "null" ) +
+ ", chosenCaps " + getChosenGLCapabilities() +
+ "]";
+ }
+
+ private final Runnable disposeAction = new Runnable() {
+ @Override
+ public void run() {
+ final RecursiveLock _lock = lock;
+ _lock.lock();
+ try {
+ if ( null != backend ) {
+ final GLContext _context = backend.getContext();
+ final boolean backendDestroy = !backend.isUsingOwnLifecycle();
+
+ GLException exceptionOnDisposeGL = null;
+ if( null != _context && _context.isCreated() ) {
+ try {
+ helper.disposeGL(GLJPanel.this, _context, !backendDestroy);
+ } catch (final GLException gle) {
+ exceptionOnDisposeGL = gle;
+ }
+ }
+ Throwable exceptionBackendDestroy = null;
+ if ( backendDestroy ) {
+ try {
+ backend.destroy();
+ } catch( final Throwable re ) {
+ exceptionBackendDestroy = re;
+ }
+ backend = null;
+ isInitialized = false;
+ }
+
+ // throw exception in order of occurrence ..
+ if( null != exceptionOnDisposeGL ) {
+ throw exceptionOnDisposeGL;
+ }
+ if( null != exceptionBackendDestroy ) {
+ throw GLException.newGLException(exceptionBackendDestroy);
+ }
+ }
+ } finally {
+ _lock.unlock();
+ }
+ }
+ };
+
+ private final Runnable updaterInitAction = new Runnable() {
+ @Override
+ public void run() {
+ updater.init(GLJPanel.this);
+ }
+ };
+
+ private final Runnable updaterDisplayAction = new Runnable() {
+ @Override
+ public void run() {
+ updater.display(GLJPanel.this);
+ }
+ };
+
+ private final Runnable updaterPlainDisplayAction = new Runnable() {
+ @Override
+ public void run() {
+ updater.plainPaint(GLJPanel.this);
+ }
+ };
+
+ private final Runnable paintImmediatelyAction = new Runnable() {
+ @Override
+ public void run() {
+ paintImmediately(0, 0, getWidth(), getHeight());
+ }
+ };
+
+ private class DisposeGLEventListenerAction implements Runnable {
+ GLEventListener listener;
+ private final boolean remove;
+ private DisposeGLEventListenerAction(final GLEventListener listener, final boolean remove) {
+ this.listener = listener;
+ this.remove = remove;
+ }
+
+ @Override
+ public void run() {
+ final Backend b = backend;
+ if ( null != b ) {
+ listener = helper.disposeGLEventListener(GLJPanel.this, b.getDrawable(), b.getContext(), listener, remove);
+ }
+ }
+ };
+
+ private int getGLInteger(final GL gl, final int which) {
+ final int[] tmp = new int[1];
+ gl.glGetIntegerv(which, tmp, 0);
+ return tmp[0];
+ }
+
+ protected static String getThreadName() { return Thread.currentThread().getName(); }
+
+ //----------------------------------------------------------------------
+ // Implementations of the various backends
+ //
+
+ /**
+ * Abstraction of the different rendering backends: i.e., pure
+ * software / pixmap rendering, pbuffer-based acceleration, Java 2D
+ * JOGL bridge
+ */
+ static interface Backend {
+ /** Create, Destroy, .. */
+ public boolean isUsingOwnLifecycle();
+
+ /** Called each time the backend needs to initialize itself */
+ public void initialize();
+
+ /** Called when the backend should clean up its resources */
+ public void destroy();
+
+ /** Called when the opacity of the GLJPanel is changed */
+ public void setOpaque(boolean opaque);
+
+ /**
+ * Called to manually create an additional OpenGL context against
+ * this GLJPanel
+ */
+ public GLContext createContext(GLContext shareWith);
+
+ /** Called to set the current backend's GLContext */
+ public void setContext(GLContext ctx);
+
+ /** Called to get the current backend's GLContext */
+ public GLContext getContext();
+
+ /** Called to get the current backend's GLDrawable */
+ public GLDrawable getDrawable();
+
+ /** Returns the used texture unit, i.e. a value of [0..n], or -1 if non used. */
+ public int getTextureUnit();
+
+ /** Called to fetch the "real" GLCapabilities for the backend */
+ public GLCapabilitiesImmutable getChosenGLCapabilities();
+
+ /** Called to fetch the "real" GLProfile for the backend */
+ public GLProfile getGLProfile();
+
+ /**
+ * Called to handle a reshape event. When this is called, the
+ * OpenGL context associated with the backend is not current, to
+ * make it easier to destroy and re-create pbuffers if necessary.
+ */
+ public boolean handleReshape();
+
+ /**
+ * Called before the OpenGL work is done in init() and display().
+ * If false is returned, this render is aborted.
+ */
+ public boolean preGL(Graphics g);
+
+ /**
+ * Return true if backend handles 'swap buffer' itself
+ * and hence the helper's setAutoSwapBuffer(enable) shall not be called.
+ * In this case {@link GLJPanel#autoSwapBufferMode} is being used
+ * in the backend to determine whether to swap buffers or not.
+ */
+ public boolean handlesSwapBuffer();
+
+ /**
+ * Shall invoke underlying drawable's swapBuffer.
+ */
+ public void swapBuffers();
+
+ /**
+ * Called after the OpenGL work is done in init() and display().
+ * The isDisplay argument indicates whether this was called on
+ * behalf of a call to display() rather than init().
+ */
+ public void postGL(Graphics g, boolean isDisplay);
+
+ /** Called from within paintComponent() to initiate the render */
+ public void doPaintComponent(Graphics g);
+
+ /** Called from print .. no backend update desired onscreen */
+ public void doPlainPaint();
+ }
+
+ // Base class used by both the software (pixmap) and pbuffer
+ // backends, both of which rely on reading back the OpenGL frame
+ // buffer and drawing it with a BufferedImage
+ class OffscreenBackend implements Backend {
+ private final AWTGLPixelBufferProvider pixelBufferProvider;
+ private final boolean useSingletonBuffer;
+ private AWTGLPixelBuffer pixelBuffer;
+ private BufferedImage alignedImage;
+
+ // One of these is used to store the read back pixels before storing
+ // in the BufferedImage
+ protected IntBuffer readBackIntsForCPUVFlip;
+
+ // Implementation using software rendering
+ private volatile GLDrawable offscreenDrawable; // volatile: avoid locking for read-only access
+ private boolean offscreenIsFBO;
+ private FBObject fboFlipped;
+ private GLSLTextureRaster glslTextureRaster;
+
+ private volatile GLContextImpl offscreenContext; // volatile: avoid locking for read-only access
+ private boolean flipVertical;
+ private int frameCount = 0;
+
+ // For saving/restoring of OpenGL state during ReadPixels
+ private final GLPixelStorageModes psm = new GLPixelStorageModes();
+
+ OffscreenBackend(final AWTGLPixelBufferProvider custom) {
+ if(null == custom) {
+ pixelBufferProvider = getSingleAWTGLPixelBufferProvider();
+ } else {
+ pixelBufferProvider = custom;
+ }
+ if( pixelBufferProvider instanceof SingletonGLPixelBufferProvider ) {
+ useSingletonBuffer = true;
+ } else {
+ useSingletonBuffer = false;
+ }
+ }
+
+ @Override
+ public final boolean isUsingOwnLifecycle() { return false; }
+
+ @Override
+ public final void initialize() {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": OffscreenBackend: initialize() - frameCount "+frameCount);
+ }
+ GLException glException = null;
+ try {
+ final GLContext[] shareWith = { null };
+ if( helper.isSharedGLContextPending(shareWith) ) {
+ return; // pending ..
+ }
+ offscreenDrawable = factory.createOffscreenDrawable(
+ null /* default platform device */,
+ reqOffscreenCaps,
+ chooser,
+ panelWidth, panelHeight);
+ updateWrappedSurfaceScale(offscreenDrawable);
+ offscreenDrawable.setRealized(true);
+ if( DEBUG_FRAMES ) {
+ offscreenDrawable.getNativeSurface().addSurfaceUpdatedListener(new SurfaceUpdatedListener() {
+ @Override
+ public final void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) {
+ System.err.println(getThreadName()+": OffscreenBackend.swapBuffers - frameCount "+frameCount);
+ } } );
+ }
+
+ //
+ // Pre context configuration
+ //
+ flipVertical = !GLJPanel.this.skipGLOrientationVerticalFlip && offscreenDrawable.isGLOriented();
+ offscreenIsFBO = offscreenDrawable.getRequestedGLCapabilities().isFBO();
+ final boolean useGLSLFlip_pre = flipVertical && offscreenIsFBO && reqOffscreenCaps.getGLProfile().isGL2ES2() && USE_GLSL_TEXTURE_RASTERIZER;
+ if( offscreenIsFBO && !useGLSLFlip_pre ) {
+ // Texture attachment only required for GLSL vertical flip, hence simply use a color-renderbuffer attachment.
+ ((GLFBODrawable)offscreenDrawable).setFBOMode(0);
+ }
+
+ offscreenContext = (GLContextImpl) offscreenDrawable.createContext(shareWith[0]);
+ offscreenContext.setContextCreationFlags(additionalCtxCreationFlags);
+ if( GLContext.CONTEXT_NOT_CURRENT < offscreenContext.makeCurrent() ) {
+ isInitialized = true;
+ helper.setAutoSwapBufferMode(false); // we handle swap-buffers, see handlesSwapBuffer()
+
+ final GL gl = offscreenContext.getGL();
+ // Remedy for Bug 1020, i.e. OSX/Nvidia's FBO needs to be cleared before blitting,
+ // otherwise first MSAA frame lacks antialiasing.
+ // Clearing of FBO is performed within GLFBODrawableImpl.initialize(..):
+ // gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ final GLCapabilitiesImmutable chosenCaps = offscreenDrawable.getChosenGLCapabilities();
+ final boolean glslCompliant = !offscreenContext.hasRendererQuirk(GLRendererQuirks.GLSLNonCompliant);
+ final boolean useGLSLFlip = useGLSLFlip_pre && gl.isGL2ES2() && glslCompliant;
+ if( DEBUG ) {
+ System.err.println(getThreadName()+": OffscreenBackend.initialize: useGLSLFlip "+useGLSLFlip+
+ " [flip "+flipVertical+", isFBO "+offscreenIsFBO+", isGL2ES2 "+gl.isGL2ES2()+
+ ", noglsl "+!USE_GLSL_TEXTURE_RASTERIZER+", glslNonCompliant "+!glslCompliant+
+ ", isGL2ES2 " + gl.isGL2ES2()+"\n "+offscreenDrawable+"]");
+ }
+ if( useGLSLFlip ) {
+ final GLFBODrawable fboDrawable = (GLFBODrawable) offscreenDrawable;
+ fboDrawable.setTextureUnit( GLJPanel.this.requestedTextureUnit );
+ try {
+ fboFlipped = new FBObject();
+ fboFlipped.init(gl, panelWidth, panelHeight, 0);
+ fboFlipped.attachColorbuffer(gl, 0, chosenCaps.getAlphaBits()>0);
+ // fboFlipped.attachRenderbuffer(gl, Attachment.Type.DEPTH, 24);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT); // Bug 1020 (see above), cannot do in FBObject due to unknown 'first bind' state.
+ glslTextureRaster = new GLSLTextureRaster(fboDrawable.getTextureUnit(), true);
+ glslTextureRaster.init(gl.getGL2ES2());
+ glslTextureRaster.reshape(gl.getGL2ES2(), 0, 0, panelWidth, panelHeight);
+ } catch (final Exception ex) {
+ ex.printStackTrace();
+ if(null != glslTextureRaster) {
+ glslTextureRaster.dispose(gl.getGL2ES2());
+ glslTextureRaster = null;
+ }
+ if(null != fboFlipped) {
+ fboFlipped.destroy(gl);
+ fboFlipped = null;
+ }
+ }
+ } else {
+ fboFlipped = null;
+ glslTextureRaster = null;
+ }
+ offscreenContext.release();
+ } else {
+ isInitialized = false;
+ }
+ } catch( final GLException gle ) {
+ glException = gle;
+ } finally {
+ if( !isInitialized ) {
+ if(null != offscreenContext) {
+ offscreenContext.destroy();
+ offscreenContext = null;
+ }
+ if(null != offscreenDrawable) {
+ offscreenDrawable.setRealized(false);
+ offscreenDrawable = null;
+ }
+ }
+ if( null != glException ) {
+ throw new GLException("Caught GLException: "+glException.getMessage(), glException);
+ }
+ }
+ }
+
+ @Override
+ public final void destroy() {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": OffscreenBackend: destroy() - offscreenContext: "+(null!=offscreenContext)+" - offscreenDrawable: "+(null!=offscreenDrawable)+" - frameCount "+frameCount);
+ }
+ if ( null != offscreenContext && offscreenContext.isCreated() ) {
+ if( GLContext.CONTEXT_NOT_CURRENT < offscreenContext.makeCurrent() ) {
+ try {
+ final GL gl = offscreenContext.getGL();
+ if(null != glslTextureRaster) {
+ glslTextureRaster.dispose(gl.getGL2ES2());
+ }
+ if(null != fboFlipped) {
+ fboFlipped.destroy(gl);
+ }
+ } finally {
+ offscreenContext.destroy();
+ }
+ }
+ }
+ offscreenContext = null;
+ glslTextureRaster = null;
+ fboFlipped = null;
+ offscreenContext = null;
+
+ if (offscreenDrawable != null) {
+ final AbstractGraphicsDevice adevice = offscreenDrawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice();
+ offscreenDrawable.setRealized(false);
+ offscreenDrawable = null;
+ if(null != adevice) {
+ adevice.close();
+ }
+ }
+ offscreenIsFBO = false;
+
+ if( null != readBackIntsForCPUVFlip ) {
+ readBackIntsForCPUVFlip.clear();
+ readBackIntsForCPUVFlip = null;
+ }
+ if( null != pixelBuffer ) {
+ if( !useSingletonBuffer ) {
+ pixelBuffer.dispose();
+ }
+ pixelBuffer = null;
+ }
+ alignedImage = null;
+ }
+
+ @Override
+ public final void setOpaque(final boolean opaque) {
+ if ( opaque != isOpaque() && !useSingletonBuffer ) {
+ pixelBuffer.dispose();
+ pixelBuffer = null;
+ alignedImage = null;
+ }
+ }
+
+ @Override
+ public final boolean preGL(final Graphics g) {
+ // Empty in this implementation
+ return true;
+ }
+
+ @Override
+ public final boolean handlesSwapBuffer() {
+ return true;
+ }
+
+ @Override
+ public final void swapBuffers() {
+ final GLDrawable d = offscreenDrawable;
+ if( null != d ) {
+ d.swapBuffers();
+ }
+ }
+
+ @Override
+ public final void postGL(final Graphics g, final boolean isDisplay) {
+ if (isDisplay) {
+ if( DEBUG_FRAMES ) {
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: - frameCount "+frameCount);
+ }
+
+ final GL gl = offscreenContext.getGL();
+
+ //
+ // Save TextureState ASAP, i.e. the user values for the used FBO texture-unit
+ // and the current active texture-unit (if not same)
+ //
+ final TextureState usrTexState, fboTexState;
+ final int fboTexUnit;
+
+ if( offscreenIsFBO ) {
+ fboTexUnit = GL.GL_TEXTURE0 + ((GLFBODrawable)offscreenDrawable).getTextureUnit();
+ usrTexState = new TextureState(gl, GL.GL_TEXTURE_2D);
+ if( fboTexUnit != usrTexState.getUnit() ) {
+ // glActiveTexture(..) + glBindTexture(..) are implicit performed in GLFBODrawableImpl's
+ // swapBuffers/contextMadeCurent -> swapFBOImpl.
+ // We need to cache the texture unit's bound texture-id before it's overwritten.
+ gl.glActiveTexture(fboTexUnit);
+ fboTexState = new TextureState(gl, fboTexUnit, GL.GL_TEXTURE_2D);
+ } else {
+ fboTexState = usrTexState;
+ }
+ } else {
+ fboTexUnit = 0;
+ usrTexState = null;
+ fboTexState = null;
+ }
+
+
+ if( autoSwapBufferMode ) {
+ // Since we only use a single-buffer non-MSAA or double-buffered MSAA offscreenDrawable,
+ // we can always swap!
+ offscreenDrawable.swapBuffers();
+ }
+
+ final int componentCount;
+ final int alignment;
+ if( isOpaque() ) {
+ // w/o alpha
+ componentCount = 3;
+ alignment = 1;
+ } else {
+ // with alpha
+ componentCount = 4;
+ alignment = 4;
+ }
+
+ final PixelFormat awtPixelFormat = pixelBufferProvider.getAWTPixelFormat(gl.getGLProfile(), componentCount);
+ final GLPixelAttributes pixelAttribs = pixelBufferProvider.getAttributes(gl, componentCount, true);
+
+ if( useSingletonBuffer ) { // attempt to fetch the latest AWTGLPixelBuffer
+ pixelBuffer = (AWTGLPixelBuffer) ((SingletonGLPixelBufferProvider)pixelBufferProvider).getSingleBuffer(awtPixelFormat.comp, pixelAttribs, true);
+ }
+ if( null != pixelBuffer && pixelBuffer.requiresNewBuffer(gl, panelWidth, panelHeight, 0) ) {
+ pixelBuffer.dispose();
+ pixelBuffer = null;
+ alignedImage = null;
+ }
+ final boolean DEBUG_INIT;
+ if ( null == pixelBuffer ) {
+ if (0 >= panelWidth || 0 >= panelHeight ) {
+ return;
+ }
+ pixelBuffer = pixelBufferProvider.allocate(gl, awtPixelFormat.comp, pixelAttribs, true, panelWidth, panelHeight, 1, 0);
+ if(DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" pixelBufferProvider isSingletonBufferProvider "+useSingletonBuffer+", 0x"+Integer.toHexString(pixelBufferProvider.hashCode())+", "+pixelBufferProvider.getClass().getSimpleName());
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" pixelBuffer 0x"+Integer.toHexString(pixelBuffer.hashCode())+", "+pixelBuffer+", alignment "+alignment);
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" flippedVertical "+flipVertical+", glslTextureRaster "+(null!=glslTextureRaster)+", isGL2ES3 "+gl.isGL2ES3());
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" panelSize "+panelWidth+"x"+panelHeight+" @ scale "+getPixelScaleStr());
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" pixelAttribs "+pixelAttribs);
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" awtPixelFormat "+awtPixelFormat);
+ DEBUG_INIT = true;
+ } else {
+ DEBUG_INIT = false;
+ }
+ } else {
+ DEBUG_INIT = false;
+ }
+ if( offscreenDrawable.getSurfaceWidth() != panelWidth || offscreenDrawable.getSurfaceHeight() != panelHeight ) {
+ throw new InternalError("OffscreenDrawable panelSize mismatch (reshape missed): panelSize "+panelWidth+"x"+panelHeight+" != drawable "+offscreenDrawable.getSurfaceWidth()+"x"+offscreenDrawable.getSurfaceHeight()+", on thread "+getThreadName());
+ }
+ if( null == alignedImage ||
+ panelWidth != alignedImage.getWidth() || panelHeight != alignedImage.getHeight() ||
+ !pixelBuffer.isDataBufferSource(alignedImage) ) {
+ alignedImage = pixelBuffer.getAlignedImage(panelWidth, panelHeight);
+ if(DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0: "+GLJPanel.this.getName()+" new alignedImage "+alignedImage.getWidth()+"x"+alignedImage.getHeight()+" @ scale "+getPixelScaleStr()+", "+alignedImage+", pixelBuffer "+pixelBuffer.width+"x"+pixelBuffer.height+", "+pixelBuffer);
+ }
+ }
+ final IntBuffer readBackInts;
+
+ if( !flipVertical || null != glslTextureRaster ) {
+ readBackInts = (IntBuffer) pixelBuffer.buffer;
+ } else {
+ if( null == readBackIntsForCPUVFlip || pixelBuffer.width * pixelBuffer.height > readBackIntsForCPUVFlip.remaining() ) {
+ readBackIntsForCPUVFlip = IntBuffer.allocate(pixelBuffer.width * pixelBuffer.height);
+ }
+ readBackInts = readBackIntsForCPUVFlip;
+ }
+
+ // Must now copy pixels from offscreen context into surface
+ if( DEBUG_FRAMES ) {
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.readPixels: - frameCount "+frameCount);
+ }
+
+ // Save PACK modes, reset them to defaults and set alignment
+ psm.setPackAlignment(gl, alignment);
+ if( gl.isGL2ES3() ) {
+ final GL2ES3 gl2es3 = gl.getGL2ES3();
+ psm.setPackRowLength(gl2es3, panelWidth);
+ gl2es3.glReadBuffer(gl2es3.getDefaultReadBuffer());
+ if( DEBUG_INIT ) {
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: fboDrawable "+offscreenDrawable);
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: isGL2ES3, readBuffer 0x"+Integer.toHexString(gl2es3.getDefaultReadBuffer()));
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: def-readBuffer 0x"+Integer.toHexString(gl2es3.getDefaultReadBuffer()));
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: def-readFBO 0x"+Integer.toHexString(gl2es3.getDefaultReadFramebuffer()));
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.0: bound-readFBO 0x"+Integer.toHexString(gl2es3.getBoundFramebuffer(GL2ES3.GL_READ_FRAMEBUFFER)));
+ }
+ }
+
+ if(null != glslTextureRaster) { // implies flippedVertical
+ final boolean viewportChange;
+ final int[] usrViewport = new int[] { 0, 0, 0, 0 };
+ gl.glGetIntegerv(GL.GL_VIEWPORT, usrViewport, 0);
+ viewportChange = 0 != usrViewport[0] || 0 != usrViewport[1] ||
+ panelWidth != usrViewport[2] || panelHeight != usrViewport[3];
+ if( DEBUG_VIEWPORT ) {
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL: "+GLJPanel.this.getName()+" Viewport: change "+viewportChange+
+ ", "+usrViewport[0]+"/"+usrViewport[1]+" "+usrViewport[2]+"x"+usrViewport[3]+
+ " -> 0/0 "+panelWidth+"x"+panelHeight);
+ }
+ if( viewportChange ) {
+ gl.glViewport(0, 0, panelWidth, panelHeight);
+ }
+
+ // perform vert-flipping via OpenGL/FBO
+ final GLFBODrawable fboDrawable = (GLFBODrawable)offscreenDrawable;
+ final FBObject.TextureAttachment fboTex = fboDrawable.getColorbuffer(GL.GL_FRONT).getTextureAttachment();
+
+ fboFlipped.bind(gl);
+
+ // gl.glActiveTexture(GL.GL_TEXTURE0 + fboDrawable.getTextureUnit()); // implicit by GLFBODrawableImpl: swapBuffers/contextMadeCurent -> swapFBOImpl
+ gl.glBindTexture(GL.GL_TEXTURE_2D, fboTex.getName());
+ // gl.glClear(GL.GL_DEPTH_BUFFER_BIT); // fboFlipped runs w/o DEPTH!
+
+ glslTextureRaster.display(gl.getGL2ES2());
+ if( DEBUG_INIT ) {
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: fboDrawable "+fboDrawable);
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: read from fbo-rb "+fboFlipped.getReadFramebuffer()+", fbo "+fboFlipped);
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: isGL2ES3, readBuffer 0x"+Integer.toHexString(gl.getDefaultReadBuffer()));
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: def-readBuffer 0x"+Integer.toHexString(gl.getDefaultReadBuffer()));
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: def-readFBO 0x"+Integer.toHexString(gl.getDefaultReadFramebuffer()));
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: bound-readFBO 0x"+Integer.toHexString(gl.getBoundFramebuffer(GL2ES3.GL_READ_FRAMEBUFFER)));
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.1: "+GLJPanel.this.getName()+" pixelAttribs "+pixelAttribs);
+ }
+ gl.glReadPixels(0, 0, panelWidth, panelHeight, pixelAttribs.format, pixelAttribs.type, readBackInts);
+
+ fboFlipped.unbind(gl);
+ if( DEBUG_INIT ) {
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: fboDrawable "+fboDrawable);
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: read from fbo-rb "+fboFlipped.getReadFramebuffer()+", fbo "+fboFlipped);
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: isGL2ES3, readBuffer 0x"+Integer.toHexString(gl.getDefaultReadBuffer()));
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: def-readBuffer 0x"+Integer.toHexString(gl.getDefaultReadBuffer()));
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: def-readFBO 0x"+Integer.toHexString(gl.getDefaultReadFramebuffer()));
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.postGL.0.2: bound-readFBO 0x"+Integer.toHexString(gl.getBoundFramebuffer(GL2ES3.GL_READ_FRAMEBUFFER)));
+ }
+ if( viewportChange ) {
+ gl.glViewport(usrViewport[0], usrViewport[1], usrViewport[2], usrViewport[3]);
+ }
+ } else {
+ gl.glReadPixels(0, 0, panelWidth, panelHeight, pixelAttribs.format, pixelAttribs.type, readBackInts);
+
+ if ( flipVertical ) {
+ // Copy temporary data into raster of BufferedImage for faster
+ // blitting Note that we could avoid this copy in the cases
+ // where !offscreenDrawable.isGLOriented(),
+ // but that's the software rendering path which is very slow anyway.
+ final BufferedImage image = alignedImage;
+ final int[] src = readBackInts.array();
+ final int[] dest = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
+ final int incr = panelWidth;
+ int srcPos = 0;
+ int destPos = (panelHeight - 1) * panelWidth;
+ for (; destPos >= 0; srcPos += incr, destPos -= incr) {
+ System.arraycopy(src, srcPos, dest, destPos, incr);
+ }
+ }
+ }
+ if( 0 != fboTexUnit ) { // implies offscreenIsFBO
+ fboTexState.restore(gl);
+ if( fboTexUnit != usrTexState.getUnit() ) {
+ usrTexState.restore(gl);
+ }
+ }
+
+ // Restore saved modes.
+ psm.restore(gl);
+
+ // Note: image will be drawn back in paintComponent() for
+ // correctness on all platforms
+ }
+ }
+
+ @Override
+ public final int getTextureUnit() {
+ if(null != glslTextureRaster && null != offscreenDrawable) { // implies flippedVertical
+ return ((GLFBODrawable)offscreenDrawable).getTextureUnit();
+ }
+ return -1;
+ }
+
+ @Override
+ public final void doPaintComponent(final Graphics g) {
+ helper.invokeGL(offscreenDrawable, offscreenContext, updaterDisplayAction, updaterInitAction);
+
+ if ( null != alignedImage ) {
+ if( DEBUG_FRAMES ) {
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.doPaintComponent.drawImage: - frameCount "+frameCount);
+ }
+ // Draw resulting image in one shot
+ g.drawImage(alignedImage, 0, 0,
+ SurfaceScaleUtils.scaleInv(alignedImage.getWidth(), hasPixelScale[0]),
+ SurfaceScaleUtils.scaleInv(alignedImage.getHeight(), hasPixelScale[1]), null); // Null ImageObserver since image data is ready.
+ }
+ frameCount++;
+ }
+
+ @Override
+ public final void doPlainPaint() {
+ helper.invokeGL(offscreenDrawable, offscreenContext, updaterPlainDisplayAction, updaterInitAction);
+ }
+
+ @Override
+ public final boolean handleReshape() {
+ GLDrawableImpl _drawable = (GLDrawableImpl)offscreenDrawable;
+ {
+ final GLDrawableImpl _drawableNew = GLDrawableHelper.resizeOffscreenDrawable(_drawable, offscreenContext, panelWidth, panelHeight);
+ if(_drawable != _drawableNew) {
+ // write back
+ _drawable = _drawableNew;
+ offscreenDrawable = _drawableNew;
+ updateWrappedSurfaceScale(offscreenDrawable);
+ }
+ }
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.OffscreenBackend.handleReshape: " +panelWidth+"x"+panelHeight + " @ scale "+getPixelScaleStr() + " -> " + _drawable.getSurfaceWidth()+"x"+_drawable.getSurfaceHeight());
+ }
+ panelWidth = _drawable.getSurfaceWidth();
+ panelHeight = _drawable.getSurfaceHeight();
+
+ if( null != glslTextureRaster ) {
+ if( GLContext.CONTEXT_NOT_CURRENT < offscreenContext.makeCurrent() ) {
+ try {
+ final GL gl = offscreenContext.getGL();
+ fboFlipped.reset(gl, panelWidth, panelHeight, 0);
+ glslTextureRaster.reshape(gl.getGL2ES2(), 0, 0, panelWidth, panelHeight);
+ } finally {
+ offscreenContext.release();
+ }
+ }
+ }
+ return _drawable.isRealized();
+ }
+
+ @Override
+ public final GLContext createContext(final GLContext shareWith) {
+ return (null != offscreenDrawable) ? offscreenDrawable.createContext(shareWith) : null;
+ }
+
+ @Override
+ public final void setContext(final GLContext ctx) {
+ offscreenContext=(GLContextImpl)ctx;
+ }
+
+ @Override
+ public final GLContext getContext() {
+ return offscreenContext;
+ }
+
+ @Override
+ public final GLDrawable getDrawable() {
+ return offscreenDrawable;
+ }
+
+ @Override
+ public final GLCapabilitiesImmutable getChosenGLCapabilities() {
+ if (offscreenDrawable == null) {
+ return null;
+ }
+ return offscreenDrawable.getChosenGLCapabilities();
+ }
+
+ @Override
+ public final GLProfile getGLProfile() {
+ if (offscreenDrawable == null) {
+ return null;
+ }
+ return offscreenDrawable.getGLProfile();
+ }
+ }
+
+ class J2DOGLBackend implements Backend {
+ // Opaque Object identifier representing the Java2D surface we are
+ // drawing to; used to determine when to destroy and recreate JOGL
+ // context
+ private Object j2dSurface;
+ // Graphics object being used during Java2D update action
+ // (absolutely essential to cache this)
+ // No-op context representing the Java2D OpenGL context
+ private GLContext j2dContext;
+ // Context associated with no-op drawable representing the JOGL
+ // OpenGL context
+ private GLDrawable joglDrawable;
+ // The real OpenGL context JOGL uses to render
+ private GLContext joglContext;
+ // State captured from Java2D OpenGL context necessary in order to
+ // properly render into Java2D back buffer
+ private final int[] drawBuffer = new int[1];
+ private final int[] readBuffer = new int[1];
+ // This is required when the FBO option of the Java2D / OpenGL
+ // pipeline is active
+ private final int[] frameBuffer = new int[1];
+ // Current (as of this writing) NVidia drivers have a couple of bugs
+ // relating to the sharing of framebuffer and renderbuffer objects
+ // between contexts. It appears we have to (a) reattach the color
+ // attachment and (b) actually create new depth buffer storage and
+ // attach it in order for the FBO to behave properly in our context.
+ private boolean checkedForFBObjectWorkarounds;
+ private boolean fbObjectWorkarounds;
+ private int[] frameBufferDepthBuffer;
+ private int[] frameBufferTexture;
+ private boolean createNewDepthBuffer;
+ // Current (as of this writing) ATI drivers have problems when the
+ // same FBO is bound in two different contexts. Here we check for
+ // this case and explicitly release the FBO from Java2D's context
+ // before switching to ours. Java2D will re-bind the FBO when it
+ // makes its context current the next time. Interestingly, if we run
+ // this code path on NVidia hardware, it breaks the rendering
+ // results -- no output is generated. This doesn't appear to be an
+ // interaction with the abovementioned NVidia-specific workarounds,
+ // as even if we disable that code the FBO is still reported as
+ // incomplete in our context.
+ private boolean checkedGLVendor;
+ private boolean vendorIsATI;
+
+ // Holding on to this GraphicsConfiguration is a workaround for a
+ // problem in the Java 2D / JOGL bridge when FBOs are enabled; see
+ // comment related to Issue 274 below
+ private GraphicsConfiguration workaroundConfig;
+
+ @Override
+ public final boolean isUsingOwnLifecycle() { return true; }
+
+ @Override
+ public final void initialize() {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": J2DOGL: initialize()");
+ }
+ // No-op in this implementation; everything is done lazily
+ isInitialized = true;
+ }
+
+ @Override
+ public final void destroy() {
+ Java2D.invokeWithOGLContextCurrent(null, new Runnable() {
+ @Override
+ public void run() {
+ if(DEBUG) {
+ System.err.println(getThreadName()+": J2DOGL: destroy() - joglContext: "+(null!=joglContext)+" - joglDrawable: "+(null!=joglDrawable));
+ }
+ if (joglContext != null) {
+ joglContext.destroy();
+ joglContext = null;
+ }
+ joglDrawable = null;
+ if (j2dContext != null) {
+ j2dContext.destroy();
+ j2dContext = null;
+ }
+ }
+ });
+ }
+
+ @Override
+ public final void setOpaque(final boolean opaque) {
+ // Empty in this implementation
+ }
+
+ @Override
+ public final GLContext createContext(final GLContext shareWith) {
+ if(null != shareWith) {
+ throw new GLException("J2DOGLBackend cannot create context w/ additional shared context, since it already needs to share the context w/ J2D.");
+ }
+ return (null != joglDrawable && null != j2dContext) ? joglDrawable.createContext(j2dContext) : null;
+ }
+
+ @Override
+ public final void setContext(final GLContext ctx) {
+ joglContext=ctx;
+ }
+
+ @Override
+ public final GLContext getContext() {
+ return joglContext;
+ }
+
+ @Override
+ public final GLDrawable getDrawable() {
+ return joglDrawable;
+ }
+
+ @Override
+ public final int getTextureUnit() { return -1; }
+
+ @Override
+ public final GLCapabilitiesImmutable getChosenGLCapabilities() {
+ // FIXME: should do better than this; is it possible to query J2D Caps ?
+ return new GLCapabilities(null);
+ }
+
+ @Override
+ public final GLProfile getGLProfile() {
+ // FIXME: should do better than this; is it possible to query J2D's Profile ?
+ return GLProfile.getDefault(GLProfile.getDefaultDevice());
+ }
+
+ @Override
+ public final boolean handleReshape() {
+ // Empty in this implementation
+ return true;
+ }
+
+ @Override
+ public final boolean preGL(final Graphics g) {
+ final GL2 gl = joglContext.getGL().getGL2();
+ // Set up needed state in JOGL context from Java2D context
+ gl.glEnable(GL.GL_SCISSOR_TEST);
+ final Rectangle r = Java2D.getOGLScissorBox(g);
+
+ if (r == null) {
+ if (DEBUG) {
+ System.err.println(getThreadName()+": Java2D.getOGLScissorBox() returned null");
+ }
+ return false;
+ }
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel: gl.glScissor(" + r.x + ", " + r.y + ", " + r.width + ", " + r.height + ")");
+ }
+
+ gl.glScissor(r.x, r.y, r.width, r.height);
+ final Rectangle oglViewport = Java2D.getOGLViewport(g, panelWidth, panelHeight);
+ // If the viewport X or Y changes, in addition to the panel's
+ // width or height, we need to send a reshape operation to the
+ // client
+ if ((viewportX != oglViewport.x) ||
+ (viewportY != oglViewport.y)) {
+ sendReshape = true;
+ if (DEBUG) {
+ System.err.println(getThreadName()+": Sending reshape because viewport changed");
+ System.err.println(" viewportX (" + viewportX + ") ?= oglViewport.x (" + oglViewport.x + ")");
+ System.err.println(" viewportY (" + viewportY + ") ?= oglViewport.y (" + oglViewport.y + ")");
+ }
+ }
+ viewportX = oglViewport.x;
+ viewportY = oglViewport.y;
+
+ // If the FBO option is active, bind to the FBO from the Java2D
+ // context.
+ // Note that all of the plumbing in the context sharing stuff will
+ // allow us to bind to this object since it's in our namespace.
+ if (Java2D.isFBOEnabled() &&
+ Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT) {
+
+ // The texture target for Java2D's OpenGL pipeline when using FBOs
+ // -- either GL_TEXTURE_2D or GL_TEXTURE_RECTANGLE_ARB
+ final int fboTextureTarget = Java2D.getOGLTextureType(g);
+
+ if (!checkedForFBObjectWorkarounds) {
+ checkedForFBObjectWorkarounds = true;
+ gl.glBindTexture(fboTextureTarget, 0);
+ gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, frameBuffer[0]);
+ final int status = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER);
+ if (status != GL.GL_FRAMEBUFFER_COMPLETE) {
+ // Need to do workarounds
+ fbObjectWorkarounds = true;
+ createNewDepthBuffer = true;
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel: ERR GL_FRAMEBUFFER_BINDING: Discovered Invalid J2D FBO("+frameBuffer[0]+"): "+FBObject.getStatusString(status) +
+ ", frame_buffer_object workarounds to be necessary");
+ }
+ } else {
+ // Don't need the frameBufferTexture temporary any more
+ frameBufferTexture = null;
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel: OK GL_FRAMEBUFFER_BINDING: "+frameBuffer[0]);
+ }
+ }
+ }
+
+ if (fbObjectWorkarounds && createNewDepthBuffer) {
+ if (frameBufferDepthBuffer == null)
+ frameBufferDepthBuffer = new int[1];
+
+ // Create our own depth renderbuffer and associated storage
+ // If we have an old one, delete it
+ if (frameBufferDepthBuffer[0] != 0) {
+ gl.glDeleteRenderbuffers(1, frameBufferDepthBuffer, 0);
+ frameBufferDepthBuffer[0] = 0;
+ }
+
+ gl.glBindTexture(fboTextureTarget, frameBufferTexture[0]);
+ final int[] width = new int[1];
+ final int[] height = new int[1];
+ gl.glGetTexLevelParameteriv(fboTextureTarget, 0, GL2GL3.GL_TEXTURE_WIDTH, width, 0);
+ gl.glGetTexLevelParameteriv(fboTextureTarget, 0, GL2GL3.GL_TEXTURE_HEIGHT, height, 0);
+
+ gl.glGenRenderbuffers(1, frameBufferDepthBuffer, 0);
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel: Generated frameBufferDepthBuffer " + frameBufferDepthBuffer[0] +
+ " with width " + width[0] + ", height " + height[0]);
+ }
+
+ gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, frameBufferDepthBuffer[0]);
+ // FIXME: may need a loop here like in Java2D
+ gl.glRenderbufferStorage(GL.GL_RENDERBUFFER, GL.GL_DEPTH_COMPONENT24, width[0], height[0]);
+
+ gl.glBindRenderbuffer(GL.GL_RENDERBUFFER, 0);
+ createNewDepthBuffer = false;
+ }
+
+ gl.glBindTexture(fboTextureTarget, 0);
+ gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, frameBuffer[0]);
+
+ if (fbObjectWorkarounds) {
+ // Hook up the color and depth buffer attachment points for this framebuffer
+ gl.glFramebufferTexture2D(GL.GL_FRAMEBUFFER,
+ GL.GL_COLOR_ATTACHMENT0,
+ fboTextureTarget,
+ frameBufferTexture[0],
+ 0);
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel: frameBufferDepthBuffer: " + frameBufferDepthBuffer[0]);
+ }
+ gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER,
+ GL.GL_DEPTH_ATTACHMENT,
+ GL.GL_RENDERBUFFER,
+ frameBufferDepthBuffer[0]);
+ }
+
+ if (DEBUG) {
+ final int status = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER);
+ if (status != GL.GL_FRAMEBUFFER_COMPLETE) {
+ throw new GLException("Error: framebuffer was incomplete: status = 0x" +
+ Integer.toHexString(status));
+ }
+ }
+ } else {
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel: Setting up drawBuffer " + drawBuffer[0] +
+ " and readBuffer " + readBuffer[0]);
+ }
+
+ gl.glDrawBuffer(drawBuffer[0]);
+ gl.glReadBuffer(readBuffer[0]);
+ }
+
+ return true;
+ }
+
+ @Override
+ public final boolean handlesSwapBuffer() {
+ return false;
+ }
+
+ @Override
+ public final void swapBuffers() {
+ final GLDrawable d = joglDrawable;
+ if( null != d ) {
+ d.swapBuffers();
+ }
+ }
+
+ @Override
+ public final void postGL(final Graphics g, final boolean isDisplay) {
+ // Cause OpenGL pipeline to flush its results because
+ // otherwise it's possible we will buffer up multiple frames'
+ // rendering results, resulting in apparent mouse lag
+ final GL gl = joglContext.getGL();
+ gl.glFinish();
+
+ if (Java2D.isFBOEnabled() &&
+ Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT) {
+ // Unbind the framebuffer from our context to work around
+ // apparent driver bugs or at least unspecified behavior causing
+ // OpenGL to run out of memory with certain cards and drivers
+ gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0);
+ }
+ }
+
+ @Override
+ public final void doPaintComponent(final Graphics g) {
+ // This is a workaround for an issue in the Java 2D / JOGL
+ // bridge (reported by an end user as JOGL Issue 274) where Java
+ // 2D can occasionally leave its internal OpenGL context current
+ // to the on-screen window rather than its internal "scratch"
+ // pbuffer surface to which the FBO is attached. JOGL expects to
+ // find a stable OpenGL drawable (on Windows, an HDC) upon which
+ // it can create another OpenGL context. It turns out that, on
+ // Windows, when Java 2D makes its internal OpenGL context
+ // current against the window in order to put pixels on the
+ // screen, it gets the device context for the window, makes its
+ // context current, and releases the device context. This means
+ // that when JOGL's Runnable gets to run below, the HDC is
+ // already invalid. The workaround for this is to force Java 2D
+ // to make its context current to the scratch surface, which we
+ // can do by executing an empty Runnable with the "shared"
+ // context current. This will be fixed in a Java SE 6 update
+ // release, hopefully 6u2.
+ if (Java2D.isFBOEnabled()) {
+ if (workaroundConfig == null) {
+ workaroundConfig = GraphicsEnvironment.
+ getLocalGraphicsEnvironment().
+ getDefaultScreenDevice().
+ getDefaultConfiguration();
+ }
+ Java2D.invokeWithOGLSharedContextCurrent(workaroundConfig, new Runnable() { @Override
+ public void run() {}});
+ }
+
+ Java2D.invokeWithOGLContextCurrent(g, new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.invokeWithOGLContextCurrent");
+ }
+
+ // Create no-op context representing Java2D context
+ if (j2dContext == null) {
+ j2dContext = factory.createExternalGLContext();
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel.Created External Context: "+j2dContext);
+ }
+ if (DEBUG) {
+// j2dContext.setGL(new DebugGL2(j2dContext.getGL().getGL2()));
+ }
+
+ // Check to see whether we can support the requested
+ // capabilities or need to fall back to a pbuffer
+ // FIXME: add more checks?
+
+ j2dContext.makeCurrent();
+ final GL gl = j2dContext.getGL();
+ if ((getGLInteger(gl, GL.GL_RED_BITS) < reqOffscreenCaps.getRedBits()) ||
+ (getGLInteger(gl, GL.GL_GREEN_BITS) < reqOffscreenCaps.getGreenBits()) ||
+ (getGLInteger(gl, GL.GL_BLUE_BITS) < reqOffscreenCaps.getBlueBits()) ||
+ // (getGLInteger(gl, GL.GL_ALPHA_BITS) < offscreenCaps.getAlphaBits()) ||
+ (getGLInteger(gl, GL2.GL_ACCUM_RED_BITS) < reqOffscreenCaps.getAccumRedBits()) ||
+ (getGLInteger(gl, GL2.GL_ACCUM_GREEN_BITS) < reqOffscreenCaps.getAccumGreenBits()) ||
+ (getGLInteger(gl, GL2.GL_ACCUM_BLUE_BITS) < reqOffscreenCaps.getAccumBlueBits()) ||
+ (getGLInteger(gl, GL2.GL_ACCUM_ALPHA_BITS) < reqOffscreenCaps.getAccumAlphaBits()) ||
+ // (getGLInteger(gl, GL2.GL_DEPTH_BITS) < offscreenCaps.getDepthBits()) ||
+ (getGLInteger(gl, GL.GL_STENCIL_BITS) < reqOffscreenCaps.getStencilBits())) {
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel: Falling back to pbuffer-based support because Java2D context insufficient");
+ System.err.println(" Available Required");
+ System.err.println("GL_RED_BITS " + getGLInteger(gl, GL.GL_RED_BITS) + " " + reqOffscreenCaps.getRedBits());
+ System.err.println("GL_GREEN_BITS " + getGLInteger(gl, GL.GL_GREEN_BITS) + " " + reqOffscreenCaps.getGreenBits());
+ System.err.println("GL_BLUE_BITS " + getGLInteger(gl, GL.GL_BLUE_BITS) + " " + reqOffscreenCaps.getBlueBits());
+ System.err.println("GL_ALPHA_BITS " + getGLInteger(gl, GL.GL_ALPHA_BITS) + " " + reqOffscreenCaps.getAlphaBits());
+ System.err.println("GL_ACCUM_RED_BITS " + getGLInteger(gl, GL2.GL_ACCUM_RED_BITS) + " " + reqOffscreenCaps.getAccumRedBits());
+ System.err.println("GL_ACCUM_GREEN_BITS " + getGLInteger(gl, GL2.GL_ACCUM_GREEN_BITS) + " " + reqOffscreenCaps.getAccumGreenBits());
+ System.err.println("GL_ACCUM_BLUE_BITS " + getGLInteger(gl, GL2.GL_ACCUM_BLUE_BITS) + " " + reqOffscreenCaps.getAccumBlueBits());
+ System.err.println("GL_ACCUM_ALPHA_BITS " + getGLInteger(gl, GL2.GL_ACCUM_ALPHA_BITS) + " " + reqOffscreenCaps.getAccumAlphaBits());
+ System.err.println("GL_DEPTH_BITS " + getGLInteger(gl, GL.GL_DEPTH_BITS) + " " + reqOffscreenCaps.getDepthBits());
+ System.err.println("GL_STENCIL_BITS " + getGLInteger(gl, GL.GL_STENCIL_BITS) + " " + reqOffscreenCaps.getStencilBits());
+ }
+ isInitialized = false;
+ backend = null;
+ java2DGLPipelineOK = false;
+ handleReshape = true;
+ j2dContext.destroy();
+ j2dContext = null;
+ return;
+ }
+ } else {
+ j2dContext.makeCurrent();
+ }
+ try {
+ captureJ2DState(j2dContext.getGL(), g);
+ final Object curSurface = Java2D.getOGLSurfaceIdentifier(g);
+ if (curSurface != null) {
+ if (j2dSurface != curSurface) {
+ if (joglContext != null) {
+ joglContext.destroy();
+ joglContext = null;
+ joglDrawable = null;
+ sendReshape = true;
+ if (DEBUG) {
+ System.err.println(getThreadName()+": Sending reshape because surface changed");
+ System.err.println("New surface = " + curSurface);
+ }
+ }
+ j2dSurface = curSurface;
+ if (DEBUG) {
+ System.err.print(getThreadName()+": Surface type: ");
+ final int surfaceType = Java2D.getOGLSurfaceType(g);
+ if (surfaceType == Java2D.UNDEFINED) {
+ System.err.println("UNDEFINED");
+ } else if (surfaceType == Java2D.WINDOW) {
+ System.err.println("WINDOW");
+ } else if (surfaceType == Java2D.PBUFFER) {
+ System.err.println("PBUFFER");
+ } else if (surfaceType == Java2D.TEXTURE) {
+ System.err.println("TEXTURE");
+ } else if (surfaceType == Java2D.FLIP_BACKBUFFER) {
+ System.err.println("FLIP_BACKBUFFER");
+ } else if (surfaceType == Java2D.FBOBJECT) {
+ System.err.println("FBOBJECT");
+ } else {
+ System.err.println("(Unknown surface type " + surfaceType + ")");
+ }
+ }
+ }
+ if (joglContext == null) {
+ final AbstractGraphicsDevice device = j2dContext.getGLDrawable().getNativeSurface().getGraphicsConfiguration().getScreen().getDevice();
+ if (factory.canCreateExternalGLDrawable(device)) {
+ joglDrawable = factory.createExternalGLDrawable();
+ joglContext = joglDrawable.createContext(j2dContext);
+ if (DEBUG) {
+ System.err.println("-- Created External Drawable: "+joglDrawable);
+ System.err.println("-- Created Context: "+joglContext);
+ }
+ }
+ if (Java2D.isFBOEnabled() &&
+ Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT &&
+ fbObjectWorkarounds) {
+ createNewDepthBuffer = true;
+ }
+ }
+ helper.invokeGL(joglDrawable, joglContext, updaterDisplayAction, updaterInitAction);
+ }
+ } finally {
+ j2dContext.release();
+ }
+ }
+ });
+ }
+
+ @Override
+ public final void doPlainPaint() {
+ helper.invokeGL(joglDrawable, joglContext, updaterPlainDisplayAction, updaterInitAction);
+ }
+
+ private final void captureJ2DState(final GL gl, final Graphics g) {
+ gl.glGetIntegerv(GL2GL3.GL_DRAW_BUFFER, drawBuffer, 0);
+ gl.glGetIntegerv(GL2ES3.GL_READ_BUFFER, readBuffer, 0);
+ if (Java2D.isFBOEnabled() &&
+ Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT) {
+ gl.glGetIntegerv(GL.GL_FRAMEBUFFER_BINDING, frameBuffer, 0);
+ if(!gl.glIsFramebuffer(frameBuffer[0])) {
+ checkedForFBObjectWorkarounds=true;
+ fbObjectWorkarounds = true;
+ createNewDepthBuffer = true;
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel: Fetched ERR GL_FRAMEBUFFER_BINDING: "+frameBuffer[0]+" - NOT A FBO"+
+ ", frame_buffer_object workarounds to be necessary");
+ }
+ } else if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel: Fetched OK GL_FRAMEBUFFER_BINDING: "+frameBuffer[0]);
+ }
+
+ if(fbObjectWorkarounds || !checkedForFBObjectWorkarounds) {
+ // See above for description of what we are doing here
+ if (frameBufferTexture == null)
+ frameBufferTexture = new int[1];
+
+ // Query the framebuffer for its color buffer so we can hook
+ // it back up in our context (should not be necessary)
+ gl.glGetFramebufferAttachmentParameteriv(GL.GL_FRAMEBUFFER,
+ GL.GL_COLOR_ATTACHMENT0,
+ GL.GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ frameBufferTexture, 0);
+ if (DEBUG) {
+ System.err.println(getThreadName()+": GLJPanel: FBO COLOR_ATTACHMENT0: " + frameBufferTexture[0]);
+ }
+ }
+
+ if (!checkedGLVendor) {
+ checkedGLVendor = true;
+ final String vendor = gl.glGetString(GL.GL_VENDOR);
+
+ if ((vendor != null) &&
+ vendor.startsWith("ATI")) {
+ vendorIsATI = true;
+ }
+ }
+
+ if (vendorIsATI) {
+ // Unbind the FBO from Java2D's context as it appears that
+ // driver bugs on ATI's side are causing problems if the FBO is
+ // simultaneously bound to more than one context. Java2D will
+ // re-bind the FBO during the next validation of its context.
+ // Note: this breaks rendering at least on NVidia hardware
+ gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, 0);
+ }
+ }
+ }
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/fixedfunc/GLLightingFunc.java b/src/jogl/classes/com/jogamp/opengl/fixedfunc/GLLightingFunc.java
new file mode 100644
index 000000000..cf7b9da46
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/fixedfunc/GLLightingFunc.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.fixedfunc;
+
+public interface GLLightingFunc {
+ public static final int GL_LIGHT0 = 0x4000;
+ public static final int GL_LIGHT1 = 0x4001;
+ public static final int GL_LIGHT2 = 0x4002;
+ public static final int GL_LIGHT3 = 0x4003;
+ public static final int GL_LIGHT4 = 0x4004;
+ public static final int GL_LIGHT5 = 0x4005;
+ public static final int GL_LIGHT6 = 0x4006;
+ public static final int GL_LIGHT7 = 0x4007;
+ public static final int GL_LIGHTING = 0xB50;
+ public static final int GL_AMBIENT = 0x1200;
+ public static final int GL_DIFFUSE = 0x1201;
+ public static final int GL_SPECULAR = 0x1202;
+ public static final int GL_POSITION = 0x1203;
+ public static final int GL_SPOT_DIRECTION = 0x1204;
+ public static final int GL_SPOT_EXPONENT = 0x1205;
+ public static final int GL_SPOT_CUTOFF = 0x1206;
+ public static final int GL_CONSTANT_ATTENUATION = 0x1207;
+ public static final int GL_LINEAR_ATTENUATION = 0x1208;
+ public static final int GL_QUADRATIC_ATTENUATION = 0x1209;
+ public static final int GL_EMISSION = 0x1600;
+ public static final int GL_SHININESS = 0x1601;
+ public static final int GL_AMBIENT_AND_DIFFUSE = 0x1602;
+ public static final int GL_COLOR_MATERIAL = 0xB57;
+ public static final int GL_NORMALIZE = 0xBA1;
+
+ public static final int GL_FLAT = 0x1D00;
+ public static final int GL_SMOOTH = 0x1D01;
+
+ public void glLightfv(int light, int pname, java.nio.FloatBuffer params);
+ public void glLightfv(int light, int pname, float[] params, int params_offset);
+ public void glMaterialf(int face, int pname, float param);
+ public void glMaterialfv(int face, int pname, java.nio.FloatBuffer params);
+ public void glMaterialfv(int face, int pname, float[] params, int params_offset);
+ public void glColor4f(float red, float green, float blue, float alpha);
+ public void glShadeModel(int mode);
+
+}
+
diff --git a/src/jogl/classes/com/jogamp/opengl/fixedfunc/GLMatrixFunc.java b/src/jogl/classes/com/jogamp/opengl/fixedfunc/GLMatrixFunc.java
new file mode 100644
index 000000000..90f13faf1
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/fixedfunc/GLMatrixFunc.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.fixedfunc;
+
+import java.nio.*;
+
+import com.jogamp.opengl.GL;
+
+/**
+ * Subset of OpenGL fixed function pipeline's matrix operations.
+ */
+public interface GLMatrixFunc {
+
+ public static final int GL_MATRIX_MODE = 0x0BA0;
+ /** Matrix mode modelview */
+ public static final int GL_MODELVIEW = 0x1700;
+ /** Matrix mode projection */
+ public static final int GL_PROJECTION = 0x1701;
+ // public static final int GL_TEXTURE = 0x1702; // Use GL.GL_TEXTURE due to ambiguous GL usage
+ /** Matrix access name for modelview */
+ public static final int GL_MODELVIEW_MATRIX = 0x0BA6;
+ /** Matrix access name for projection */
+ public static final int GL_PROJECTION_MATRIX = 0x0BA7;
+ /** Matrix access name for texture */
+ public static final int GL_TEXTURE_MATRIX = 0x0BA8;
+
+ /**
+ * Copy the named matrix into the given storage.
+ * @param pname {@link #GL_MODELVIEW_MATRIX}, {@link #GL_PROJECTION_MATRIX} or {@link #GL_TEXTURE_MATRIX}
+ * @param params the FloatBuffer's position remains unchanged,
+ * which is the same behavior than the native JOGL GL impl
+ */
+ public void glGetFloatv(int pname, java.nio.FloatBuffer params);
+
+ /**
+ * Copy the named matrix to the given storage at offset.
+ * @param pname {@link #GL_MODELVIEW_MATRIX}, {@link #GL_PROJECTION_MATRIX} or {@link #GL_TEXTURE_MATRIX}
+ * @param params storage
+ * @param params_offset storage offset
+ */
+ public void glGetFloatv(int pname, float[] params, int params_offset);
+
+ /**
+ * glGetIntegerv
+ * @param pname {@link #GL_MATRIX_MODE} to receive the current matrix mode
+ * @param params the FloatBuffer's position remains unchanged
+ * which is the same behavior than the native JOGL GL impl
+ */
+ public void glGetIntegerv(int pname, IntBuffer params);
+ public void glGetIntegerv(int pname, int[] params, int params_offset);
+
+ /**
+ * Sets the current matrix mode.
+ * @param mode {@link #GL_MODELVIEW}, {@link #GL_PROJECTION} or {@link GL#GL_TEXTURE GL_TEXTURE}.
+ */
+ public void glMatrixMode(int mode) ;
+
+ /**
+ * Push the current matrix to it's stack, while preserving it's values.
+ * <p>
+ * There exist one stack per matrix mode, i.e. {@link #GL_MODELVIEW}, {@link #GL_PROJECTION} and {@link GL#GL_TEXTURE GL_TEXTURE}.
+ * </p>
+ */
+ public void glPushMatrix();
+
+ /**
+ * Pop the current matrix from it's stack.
+ * @see #glPushMatrix()
+ */
+ public void glPopMatrix();
+
+ /**
+ * Load the current matrix with the identity matrix
+ */
+ public void glLoadIdentity() ;
+
+ /**
+ * Load the current matrix w/ the provided one.
+ * @param params the FloatBuffer's position remains unchanged,
+ * which is the same behavior than the native JOGL GL impl
+ */
+ public void glLoadMatrixf(java.nio.FloatBuffer m) ;
+ /**
+ * Load the current matrix w/ the provided one.
+ */
+ public void glLoadMatrixf(float[] m, int m_offset);
+
+ /**
+ * Multiply the current matrix: [c] = [c] x [m]
+ * @param m the FloatBuffer's position remains unchanged,
+ * which is the same behavior than the native JOGL GL impl
+ */
+ public void glMultMatrixf(java.nio.FloatBuffer m) ;
+ /**
+ * Multiply the current matrix: [c] = [c] x [m]
+ */
+ public void glMultMatrixf(float[] m, int m_offset);
+
+ /**
+ * Translate the current matrix.
+ */
+ public void glTranslatef(float x, float y, float z) ;
+
+ /**
+ * Rotate the current matrix.
+ */
+ public void glRotatef(float angle, float x, float y, float z);
+
+ /**
+ * Scale the current matrix.
+ */
+ public void glScalef(float x, float y, float z) ;
+
+ /**
+ * {@link #glMultMatrixf(FloatBuffer) Multiply} the current matrix with the orthogonal matrix.
+ */
+ public void glOrthof(float left, float right, float bottom, float top, float zNear, float zFar) ;
+
+ /**
+ * {@link #glMultMatrixf(FloatBuffer) Multiply} the current matrix with the frustum matrix.
+ */
+ public void glFrustumf(float left, float right, float bottom, float top, float zNear, float zFar);
+
+}
+
diff --git a/src/jogl/classes/com/jogamp/opengl/fixedfunc/GLPointerFunc.java b/src/jogl/classes/com/jogamp/opengl/fixedfunc/GLPointerFunc.java
new file mode 100644
index 000000000..852d4ebba
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/fixedfunc/GLPointerFunc.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2010 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.fixedfunc;
+
+import com.jogamp.opengl.*;
+
+public interface GLPointerFunc {
+ public static final int GL_VERTEX_ARRAY = 0x8074;
+ public static final int GL_NORMAL_ARRAY = 0x8075;
+ public static final int GL_COLOR_ARRAY = 0x8076;
+ public static final int GL_TEXTURE_COORD_ARRAY = 0x8078;
+
+ public void glEnableClientState(int arrayName);
+ public void glDisableClientState(int arrayName);
+
+ public void glVertexPointer(GLArrayData array);
+ public void glVertexPointer(int size, int type, int stride, java.nio.Buffer pointer);
+ public void glVertexPointer(int size, int type, int stride, long pointer_buffer_offset);
+
+ public void glColorPointer(GLArrayData array);
+ public void glColorPointer(int size, int type, int stride, java.nio.Buffer pointer);
+ public void glColorPointer(int size, int type, int stride, long pointer_buffer_offset);
+ public void glColor4f(float red, float green, float blue, float alpha);
+
+ public void glNormalPointer(GLArrayData array);
+ public void glNormalPointer(int type, int stride, java.nio.Buffer pointer);
+ public void glNormalPointer(int type, int stride, long pointer_buffer_offset);
+
+ public void glTexCoordPointer(GLArrayData array);
+ public void glTexCoordPointer(int size, int type, int stride, java.nio.Buffer pointer);
+ public void glTexCoordPointer(int size, int type, int stride, long pointer_buffer_offset);
+
+}
+
diff --git a/src/jogl/classes/com/jogamp/opengl/fixedfunc/GLPointerFuncUtil.java b/src/jogl/classes/com/jogamp/opengl/fixedfunc/GLPointerFuncUtil.java
new file mode 100644
index 000000000..cb1ff3827
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/fixedfunc/GLPointerFuncUtil.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package com.jogamp.opengl.fixedfunc;
+
+public class GLPointerFuncUtil {
+ public static final String mgl_Vertex = "mgl_Vertex";
+ public static final String mgl_Normal = "mgl_Normal";
+ public static final String mgl_Color = "mgl_Color";
+ public static final String mgl_MultiTexCoord = "mgl_MultiTexCoord" ;
+ public static final String mgl_InterleaveArray = "mgl_InterleaveArray" ; // magic name for interleaved arrays w/ sub-arrays
+
+ /**
+ * @param glArrayIndex the fixed function array index
+ * @return default fixed function array name
+ */
+ public static String getPredefinedArrayIndexName(final int glArrayIndex) {
+ return getPredefinedArrayIndexName(glArrayIndex, -1);
+ }
+
+ /**
+ * @param glArrayIndex the fixed function array index
+ * @param multiTexCoordIndex index for multiTexCoordIndex
+ * @return default fixed function array name
+ */
+ public static String getPredefinedArrayIndexName(final int glArrayIndex, final int multiTexCoordIndex) {
+ switch(glArrayIndex) {
+ case GLPointerFunc.GL_VERTEX_ARRAY:
+ return mgl_Vertex;
+ case GLPointerFunc.GL_NORMAL_ARRAY:
+ return mgl_Normal;
+ case GLPointerFunc.GL_COLOR_ARRAY:
+ return mgl_Color;
+ case GLPointerFunc.GL_TEXTURE_COORD_ARRAY:
+ if(0<=multiTexCoordIndex) {
+ return mgl_MultiTexCoord+multiTexCoordIndex;
+ } else {
+ return mgl_MultiTexCoord+multiTexCoordIndex;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/glu/GLUnurbs.java b/src/jogl/classes/com/jogamp/opengl/glu/GLUnurbs.java
new file mode 100644
index 000000000..0dbd54674
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/glu/GLUnurbs.java
@@ -0,0 +1,8 @@
+package com.jogamp.opengl.glu;
+
+/**
+ * Wrapper for a GLU NURBS object.
+ */
+
+public interface GLUnurbs {
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/glu/GLUquadric.java b/src/jogl/classes/com/jogamp/opengl/glu/GLUquadric.java
new file mode 100644
index 000000000..45b2d054d
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/glu/GLUquadric.java
@@ -0,0 +1,33 @@
+package com.jogamp.opengl.glu;
+
+import com.jogamp.opengl.GL;
+import com.jogamp.opengl.util.ImmModeSink;
+
+/**
+ * Wrapper for a GLU quadric object.
+ */
+
+public interface GLUquadric {
+ // enable/disables the Immediate Mode Sink module.
+ // This defaults to false for GLUgl2,
+ // and is always true for GLUes1.
+ public void enableImmModeSink(boolean val);
+
+ public boolean isImmModeSinkEnabled();
+
+ // set Immediate Mode usage.
+ // This defaults to false at GLU creation time.
+ // If enabled rendering will happen immediately,
+ // otherwise rendering will be hold in the ImmModeSink
+ // object, to be rendered deferred.
+ public void setImmMode(boolean val);
+
+ public boolean getImmMode();
+
+ // creates a new ImmModeSink (VBO Buffers) and
+ // returns the old vbo buffer with it's rendering result
+ public ImmModeSink replaceImmModeSink();
+
+ // gl may be null, then the GL client states are not disabled
+ public void resetImmModeSink(GL gl);
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/glu/GLUtessellator.java b/src/jogl/classes/com/jogamp/opengl/glu/GLUtessellator.java
new file mode 100644
index 000000000..ce9fda8e7
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/glu/GLUtessellator.java
@@ -0,0 +1,66 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 2.0 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.glu;
+
+/**
+ * The <b>GLUtessellator</b> object is used to hold the data, such as the
+ * vertices, edges and callback objects, to describe and tessellate complex
+ * polygons. A <b>GLUtessellator</b> object is used with the
+ * {@link GLU GLU} tessellator methods and
+ * {@link GLUtessellatorCallback GLU callbacks}.
+ *
+ * @author Eric Veach, July 1994
+ * @author Java Port: Pepijn Van Eechhoudt, July 2003
+ * @author Java Port: Nathan Parker Burg, August 2003
+ */
+public interface GLUtessellator {}
diff --git a/src/jogl/classes/com/jogamp/opengl/glu/GLUtessellatorCallback.java b/src/jogl/classes/com/jogamp/opengl/glu/GLUtessellatorCallback.java
new file mode 100644
index 000000000..c616bca38
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/glu/GLUtessellatorCallback.java
@@ -0,0 +1,356 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 2.0 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.glu;
+
+/**
+ * <b>GLUtessellatorCallback</b> interface provides methods that the user will
+ * override to define the callbacks for a tessellation object.
+ *
+ * @author Eric Veach, July 1994
+ * @author Java Port: Pepijn Van Eeckhoudt, July 2003
+ * @author Java Port: Nathan Parker Burg, August 2003
+ */
+public interface GLUtessellatorCallback {
+ /**
+ * The <b>begin</b> callback method is invoked like
+ * {@link com.jogamp.opengl.GL#glBegin glBegin} to indicate the start of a
+ * (triangle) primitive. The method takes a single argument of type int. If
+ * the <b>GLU_TESS_BOUNDARY_ONLY</b> property is set to <b>GL_FALSE</b>, then
+ * the argument is set to either <b>GL_TRIANGLE_FAN</b>,
+ * <b>GL_TRIANGLE_STRIP</b>, or <b>GL_TRIANGLES</b>. If the
+ * <b>GLU_TESS_BOUNDARY_ONLY</b> property is set to <b>GL_TRUE</b>, then the
+ * argument will be set to <b>GL_LINE_LOOP</b>.
+ *
+ * @param type
+ * Specifics the type of begin/end pair being defined. The following
+ * values are valid: <b>GL_TRIANGLE_FAN</b>, <b>GL_TRIANGLE_STRIP</b>,
+ * <b>GL_TRIANGLES</b> or <b>GL_LINE_LOOP</b>.
+ *
+ * @see GLU#gluTessCallback gluTessCallback
+ * @see #end end
+ * @see #begin begin
+ */
+ public void begin(int type);
+
+ /**
+ * The same as the {@link #begin begin} callback method except that
+ * it takes an additional reference argument. This reference is
+ * identical to the opaque reference provided when {@link
+ * GLU#gluTessBeginPolygon gluTessBeginPolygon} was called.
+ *
+ * @param type
+ * Specifics the type of begin/end pair being defined. The following
+ * values are valid: <b>GL_TRIANGLE_FAN</b>, <b>GL_TRIANGLE_STRIP</b>,
+ * <b>GL_TRIANGLES</b> or <b>GL_LINE_LOOP</b>.
+ * @param polygonData
+ * Specifics a reference to user-defined data.
+ *
+ * @see GLU#gluTessCallback gluTessCallback
+ * @see #endData endData
+ * @see #begin begin
+ */
+ public void beginData(int type, Object polygonData);
+
+
+ /**
+ * The <b>edgeFlag</b> callback method is similar to
+ * {@link com.jogamp.opengl.GL#glEdgeFlag glEdgeFlag}. The method takes
+ * a single boolean boundaryEdge that indicates which edges lie on the
+ * polygon boundary. If the boundaryEdge is <b>GL_TRUE</b>, then each vertex
+ * that follows begins an edge that lies on the polygon boundary, that is,
+ * an edge that separates an interior region from an exterior one. If the
+ * boundaryEdge is <b>GL_FALSE</b>, then each vertex that follows begins an
+ * edge that lies in the polygon interior. The edge flag callback (if
+ * defined) is invoked before the first vertex callback.<P>
+ *
+ * Since triangle fans and triangle strips do not support edge flags, the
+ * begin callback is not called with <b>GL_TRIANGLE_FAN</b> or
+ * <b>GL_TRIANGLE_STRIP</b> if a non-null edge flag callback is provided.
+ * (If the callback is initialized to null, there is no impact on
+ * performance). Instead, the fans and strips are converted to independent
+ * triangles.
+ *
+ * @param boundaryEdge
+ * Specifics which edges lie on the polygon boundary.
+ *
+ * @see GLU#gluTessCallback gluTessCallback
+ * @see #edgeFlagData edgeFlagData
+ */
+ public void edgeFlag(boolean boundaryEdge);
+
+
+ /**
+ * The same as the {@link #edgeFlag edgeFlage} callback method
+ * except that it takes an additional reference argument. This
+ * reference is identical to the opaque reference provided when
+ * {@link GLU#gluTessBeginPolygon gluTessBeginPolygon} was called.
+ *
+ * @param boundaryEdge
+ * Specifics which edges lie on the polygon boundary.
+ * @param polygonData
+ * Specifics a reference to user-defined data.
+ *
+ * @see GLU#gluTessCallback gluTessCallback
+ * @see #edgeFlag edgeFlag
+ */
+ public void edgeFlagData(boolean boundaryEdge, Object polygonData);
+
+
+ /**
+ * The <b>vertex</b> callback method is invoked between the {@link
+ * #begin begin} and {@link #end end} callback methods. It is
+ * similar to {@link com.jogamp.opengl.GL#glVertex3f glVertex3f},
+ * and it defines the vertices of the triangles created by the
+ * tessellation process. The method takes a reference as its only
+ * argument. This reference is identical to the opaque reference
+ * provided by the user when the vertex was described (see {@link
+ * GLU#gluTessVertex gluTessVertex}).
+ *
+ * @param vertexData
+ * Specifics a reference to the vertices of the triangles created
+ * by the tessellation process.
+ *
+ * @see GLU#gluTessCallback gluTessCallback
+ * @see #vertexData vertexData
+ */
+ public void vertex(Object vertexData);
+
+
+ /**
+ * The same as the {@link #vertex vertex} callback method except
+ * that it takes an additional reference argument. This reference is
+ * identical to the opaque reference provided when {@link
+ * GLU#gluTessBeginPolygon gluTessBeginPolygon} was called.
+ *
+ * @param vertexData
+ * Specifics a reference to the vertices of the triangles created
+ * by the tessellation process.
+ * @param polygonData
+ * Specifics a reference to user-defined data.
+ *
+ * @see GLU#gluTessCallback gluTessCallback
+ * @see #vertex vertex
+ */
+ public void vertexData(Object vertexData, Object polygonData);
+
+
+ /**
+ * The end callback serves the same purpose as
+ * {@link com.jogamp.opengl.GL#glEnd glEnd}. It indicates the end of a
+ * primitive and it takes no arguments.
+ *
+ * @see GLU#gluTessCallback gluTessCallback
+ * @see #begin begin
+ * @see #endData endData
+ */
+ public void end();
+
+
+ /**
+ * The same as the {@link #end end} callback method except that it
+ * takes an additional reference argument. This reference is
+ * identical to the opaque reference provided when {@link
+ * GLU#gluTessBeginPolygon gluTessBeginPolygon} was called.
+ *
+ * @param polygonData
+ * Specifics a reference to user-defined data.
+ *
+ * @see GLU#gluTessCallback gluTessCallback
+ * @see #beginData beginData
+ * @see #end end
+ */
+ public void endData(Object polygonData);
+
+
+ /**
+ * The <b>combine</b> callback method is called to create a new vertex when
+ * the tessellation detects an intersection, or wishes to merge features. The
+ * method takes four arguments: an array of three elements each of type
+ * double, an array of four references, an array of four elements each of
+ * type float, and a reference to a reference.<P>
+ *
+ * The vertex is defined as a linear combination of up to four existing
+ * vertices, stored in <i>data</i>. The coefficients of the linear combination
+ * are given by <i>weight</i>; these weights always add up to 1. All vertex
+ * pointers are valid even when some of the weights are 0. <i>coords</i> gives
+ * the location of the new vertex.<P>
+ *
+ * The user must allocate another vertex, interpolate parameters using
+ * <i>data</i> and <i>weight</i>, and return the new vertex pointer in
+ * <i>outData</i>. This handle is supplied during rendering callbacks. The
+ * user is responsible for freeing the memory some time after
+ * {@link GLU#gluTessEndPolygon gluTessEndPolygon} is
+ * called.<P>
+ *
+ * For example, if the polygon lies in an arbitrary plane in 3-space, and a
+ * color is associated with each vertex, the <b>GLU_TESS_COMBINE</b>
+ * callback might look like this:
+ * </UL>
+ * <PRE>
+ * void myCombine(double[] coords, Object[] data,
+ * float[] weight, Object[] outData)
+ * {
+ * MyVertex newVertex = new MyVertex();
+ *
+ * newVertex.x = coords[0];
+ * newVertex.y = coords[1];
+ * newVertex.z = coords[2];
+ * newVertex.r = weight[0]*data[0].r +
+ * weight[1]*data[1].r +
+ * weight[2]*data[2].r +
+ * weight[3]*data[3].r;
+ * newVertex.g = weight[0]*data[0].g +
+ * weight[1]*data[1].g +
+ * weight[2]*data[2].g +
+ * weight[3]*data[3].g;
+ * newVertex.b = weight[0]*data[0].b +
+ * weight[1]*data[1].b +
+ * weight[2]*data[2].b +
+ * weight[3]*data[3].b;
+ * newVertex.a = weight[0]*data[0].a +
+ * weight[1]*data[1].a +
+ * weight[2]*data[2].a +
+ * weight[3]*data[3].a;
+ * outData = newVertex;
+ * }</PRE>
+ *
+ * @param coords
+ * Specifics the location of the new vertex.
+ * @param data
+ * Specifics the vertices used to create the new vertex.
+ * @param weight
+ * Specifics the weights used to create the new vertex.
+ * @param outData
+ * Reference user the put the coodinates of the new vertex.
+ *
+ * @see GLU#gluTessCallback gluTessCallback
+ * @see #combineData combineData
+ */
+ public void combine(double[] coords, Object[] data,
+ float[] weight, Object[] outData);
+
+
+ /**
+ * The same as the {@link #combine combine} callback method except
+ * that it takes an additional reference argument. This reference is
+ * identical to the opaque reference provided when {@link
+ * GLU#gluTessBeginPolygon gluTessBeginPolygon} was called.
+ *
+ * @param coords
+ * Specifics the location of the new vertex.
+ * @param data
+ * Specifics the vertices used to create the new vertex.
+ * @param weight
+ * Specifics the weights used to create the new vertex.
+ * @param outData
+ * Reference user the put the coodinates of the new vertex.
+ * @param polygonData
+ * Specifics a reference to user-defined data.
+ *
+ * @see GLU#gluTessCallback gluTessCallback
+ * @see #combine combine
+ */
+ public void combineData(double[] coords, Object[] data,
+ float[] weight, Object[] outData,
+ Object polygonData);
+
+
+ /**
+ * The <b>error</b> callback method is called when an error is encountered.
+ * The one argument is of type int; it indicates the specific error that
+ * occurred and will be set to one of <b>GLU_TESS_MISSING_BEGIN_POLYGON</b>,
+ * <b>GLU_TESS_MISSING_END_POLYGON</b>, <b>GLU_TESS_MISSING_BEGIN_CONTOUR</b>,
+ * <b>GLU_TESS_MISSING_END_CONTOUR</b>, <b>GLU_TESS_COORD_TOO_LARGE</b>,
+ * <b>GLU_TESS_NEED_COMBINE_CALLBACK</b> or <b>GLU_OUT_OF_MEMORY</b>.
+ * Character strings describing these errors can be retrieved with the
+ * {@link GLU#gluErrorString gluErrorString} call.<P>
+ *
+ * The GLU library will recover from the first four errors by inserting the
+ * missing call(s). <b>GLU_TESS_COORD_TOO_LARGE</b> indicates that some
+ * vertex coordinate exceeded the predefined constant
+ * <b>GLU_TESS_MAX_COORD</b> in absolute value, and that the value has been
+ * clamped. (Coordinate values must be small enough so that two can be
+ * multiplied together without overflow.)
+ * <b>GLU_TESS_NEED_COMBINE_CALLBACK</b> indicates that the tessellation
+ * detected an intersection between two edges in the input data, and the
+ * <b>GLU_TESS_COMBINE</b> or <b>GLU_TESS_COMBINE_DATA</b> callback was not
+ * provided. No output is generated. <b>GLU_OUT_OF_MEMORY</b> indicates that
+ * there is not enough memory so no output is generated.
+ *
+ * @param errnum
+ * Specifics the error number code.
+ *
+ * @see GLU#gluTessCallback gluTessCallback
+ * @see #errorData errorData
+ */
+ public void error(int errnum);
+
+
+ /**
+ * The same as the {@link #error error} callback method except that
+ * it takes an additional reference argument. This reference is
+ * identical to the opaque reference provided when {@link
+ * GLU#gluTessBeginPolygon gluTessBeginPolygon} was called.
+ *
+ * @param errnum
+ * Specifics the error number code.
+ * @param polygonData
+ * Specifics a reference to user-defined data.
+ *
+ * @see GLU#gluTessCallback gluTessCallback
+ * @see #error error
+ */
+ public void errorData(int errnum, Object polygonData);
+
+ //void mesh(jogamp.opengl.tessellator.GLUmesh mesh);
+}
diff --git a/src/jogl/classes/com/jogamp/opengl/glu/GLUtessellatorCallbackAdapter.java b/src/jogl/classes/com/jogamp/opengl/glu/GLUtessellatorCallbackAdapter.java
new file mode 100644
index 000000000..b9503f12e
--- /dev/null
+++ b/src/jogl/classes/com/jogamp/opengl/glu/GLUtessellatorCallbackAdapter.java
@@ -0,0 +1,96 @@
+/*
+* Portions Copyright (C) 2003-2006 Sun Microsystems, Inc.
+* All rights reserved.
+*/
+
+/*
+** License Applicability. Except to the extent portions of this file are
+** made subject to an alternative license as permitted in the SGI Free
+** Software License B, Version 2.0 (the "License"), the contents of this
+** file are subject only to the provisions of the License. You may not use
+** this file except in compliance with the License. You may obtain a copy
+** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
+** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
+**
+** http://oss.sgi.com/projects/FreeB
+**
+** Note that, as provided in the License, the Software is distributed on an
+** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
+** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
+** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
+** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
+**
+** NOTE: The Original Code (as defined below) has been licensed to Sun
+** Microsystems, Inc. ("Sun") under the SGI Free Software License B
+** (Version 1.1), shown above ("SGI License"). Pursuant to Section
+** 3.2(3) of the SGI License, Sun is distributing the Covered Code to
+** you under an alternative license ("Alternative License"). This
+** Alternative License includes all of the provisions of the SGI License
+** except that Section 2.2 and 11 are omitted. Any differences between
+** the Alternative License and the SGI License are offered solely by Sun
+** and not by SGI.
+**
+** Original Code. The Original Code is: OpenGL Sample Implementation,
+** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
+** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
+** Copyright in any portions created by third parties is as indicated
+** elsewhere herein. All Rights Reserved.
+**
+** Additional Notice Provisions: The application programming interfaces
+** established by SGI in conjunction with the Original Code are The
+** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
+** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
+** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
+** Window System(R) (Version 1.3), released October 19, 1998. This software
+** was created using the OpenGL(R) version 1.2.1 Sample Implementation
+** published by SGI, but has not been independently verified as being
+** compliant with the OpenGL(R) version 1.2.1 Specification.
+**
+** Author: Eric Veach, July 1994
+** Java Port: Pepijn Van Eeckhoudt, July 2003
+** Java Port: Nathan Parker Burg, August 2003
+*/
+package com.jogamp.opengl.glu;
+
+/**
+ * The <b>GLUtessellatorCallbackAdapter</b> provides a default implementation of
+ * {@link GLUtessellatorCallback GLUtessellatorCallback}
+ * with empty callback methods. This class can be extended to provide user
+ * defined callback methods.
+ *
+ * @author Eric Veach, July 1994
+ * @author Java Port: Pepijn Van Eechhoudt, July 2003
+ * @author Java Port: Nathan Parker Burg, August 2003
+ */
+
+public class GLUtessellatorCallbackAdapter implements GLUtessellatorCallback {
+ @Override
+ public void begin(final int type) {}
+ @Override
+ public void edgeFlag(final boolean boundaryEdge) {}
+ @Override
+ public void vertex(final Object vertexData) {}
+ @Override
+ public void end() {}
+// public void mesh(jogamp.opengl.tessellator.GLUmesh mesh) {}
+ @Override
+ public void error(final int errnum) {}
+ @Override
+ public void combine(final double[] coords, final Object[] data,
+ final float[] weight, final Object[] outData) {}
+ @Override
+ public void beginData(final int type, final Object polygonData) {}
+ @Override
+ public void edgeFlagData(final boolean boundaryEdge,
+ final Object polygonData) {}
+ @Override
+ public void vertexData(final Object vertexData, final Object polygonData) {}
+ @Override
+ public void endData(final Object polygonData) {}
+ @Override
+ public void errorData(final int errnum, final Object polygonData) {}
+ @Override
+ public void combineData(final double[] coords, final Object[] data,
+ final float[] weight, final Object[] outData,
+ final Object polygonData) {}
+}