diff options
Diffstat (limited to 'src/jogl/classes/javax/media')
31 files changed, 9443 insertions, 0 deletions
diff --git a/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java b/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java new file mode 100644 index 000000000..9352ad4f3 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/DefaultGLCapabilitiesChooser.java @@ -0,0 +1,257 @@ +/* + * 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 javax.media.opengl; + +import javax.media.nativewindow.NativeWindowException; +import jogamp.opengl.Debug; +import java.util.List; +import javax.media.nativewindow.CapabilitiesImmutable; + +/** <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 = Debug.debug("CapabilitiesChooser"); + + public int chooseCapabilities(final CapabilitiesImmutable desired, + final List /*<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) { + 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 + int[] scores = new int[availnum]; + int NO_SCORE = -9999999; + int DOUBLE_BUFFER_MISMATCH_PENALTY = 1000; + int STENCIL_MISMATCH_PENALTY = 500; + // Pseudo attempt to keep equal rank penalties scale-equivalent + // (e.g., stencil mismatch is 3 * accum because there are 3 accum + // components) + int COLOR_MISMATCH_PENALTY_SCALE = 36; + int DEPTH_MISMATCH_PENALTY_SCALE = 6; + int ACCUM_MISMATCH_PENALTY_SCALE = 1; + int STENCIL_MISMATCH_PENALTY_SCALE = 3; + for (int i = 0; i < scores.length; i++) { + scores[i] = NO_SCORE; + } + // Compute score for each + for (int i = 0; i < availnum; i++) { + GLCapabilitiesImmutable cur = (GLCapabilitiesImmutable) available.get(i); + if (cur == null) { + continue; + } + if (gldes.isOnscreen() != cur.isOnscreen()) { + continue; + } + if (!gldes.isOnscreen() && gldes.isPBuffer() && !cur.isPBuffer()) { + continue; // only skip if requested Offscreen && PBuffer, but no PBuffer available + } + if (gldes.getStereo() != cur.getStereo()) { + continue; + } + 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()); + if (cur.getDoubleBuffered() != gldes.getDoubleBuffered()) { + score += sign(score) * DOUBLE_BUFFER_MISMATCH_PENALTY; + } + if ((gldes.getStencilBits() > 0) && (cur.getStencilBits() == 0)) { + score += sign(score) * STENCIL_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++) { + int score = scores[i]; + if (score == NO_SCORE) { + continue; + } + GLCapabilitiesImmutable cur = (GLCapabilitiesImmutable) available.get(i); + if (cur.getHardwareAccelerated()) { + 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; + } + 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(" " + 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++) { + 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(int score) { + if (score < 0) { + return -1; + } + return 1; + } + +} diff --git a/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java new file mode 100644 index 000000000..2c8c7cca3 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLAnimatorControl.java @@ -0,0 +1,194 @@ +/** + * 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 javax.media.opengl; + +/** + * An animator control interface, + * which implementation may drive a {@link javax.media.opengl.GLAutoDrawable} animation. + */ +public interface GLAnimatorControl { + + /** + * @return Time of the first display call in milliseconds. + * This value is reset if started or resumed. + * + * @see #start() + * @see #resume() + */ + long getStartTime(); + + /** + * @return Time of the last display call in milliseconds. + * This value is reset if started or resumed. + * + * @see #start() + * @see #resume() + */ + long getCurrentTime(); + + /** + * @return Duration <code>getCurrentTime() - getStartTime()</code>. + * + * @see #getStartTime() + * @see #getCurrentTime() + */ + long getDuration(); + + + /** + * @return Number of frame cycles displayed + * since the first display call, ie <code>getStartTime()</code>. + * This value is reset if started or resumed. + * + * @see #start() + * @see #resume() + */ + int getTotalFrames(); + + /** Reset all performance counter (startTime, currentTime, frame number) */ + public void resetCounter(); + + /** + * Indicates whether this animator is running, ie. has been started and not stopped. + * + * @see #start() + * @see #stop() + * @see #pause() + * @see #resume() + */ + boolean isStarted(); + + /** + * Indicates whether this animator is running and animating,<br> + * the latter is true if it has {@link GLAutoDrawable}s to render and is not paused. + * + * @see #start() + * @see #stop() + * @see #pause() + * @see #resume() + */ + boolean isAnimating(); + + /** + * Indicates whether this animator is running and paused. + * + * @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> + * If started, all counters (time, frames, ..) are reset to zero. + * + * @return true is started due to this call, + * otherwise false, ie started already or unable to start. + * + * @see #stop() + * @see #isAnimating() + * @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. + * + * @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. + * + * @return false if if not started or already paused, 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> + * If resumed, all counters (time, frames, ..) are reset to zero. + * + * @return false if if not started or not paused, otherwise true + * + * @see #pause() + * @see #isAnimating() + */ + boolean resume(); + + /** + * Removes a drawable from the animator's list of rendering drawables.<br> + * This method should get called in case a drawable becomes invalid, + * and will not be recovered.<br> + * This allows the animator thread to become idle in case the last drawable + * has reached it's end of life.<br> + * + * @param drawable the to be removed drawable + */ + void remove(GLAutoDrawable drawable); +} diff --git a/src/jogl/classes/javax/media/opengl/GLArrayData.java b/src/jogl/classes/javax/media/opengl/GLArrayData.java new file mode 100644 index 000000000..6c8122f27 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLArrayData.java @@ -0,0 +1,141 @@ +/** + * 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 javax.media.opengl; + +import java.nio.*; + +/** + * + * The total number of bytes hold by the referenced buffer is: + * getComponentSize()* getComponentNumber() * getElementNumber() + * + */ +public interface GLArrayData { + + /** + * 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 javax.media.opengl.GL2#GL_VERTEX_ARRAY + * @see javax.media.opengl.GL2#GL_NORMAL_ARRAY + * @see javax.media.opengl.GL2#GL_COLOR_ARRAY + * @see javax.media.opengl.GL2#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. + */ + public void setName(String newName); + + + /** + * Returns the shader attribute location for this name, + * -1 if not yet determined + */ + public int getLocation(); + + /** + * Sets the determined location of the shader attribute + * This is usually done within ShaderState. + * + * @see com.jogamp.opengl.util.glsl.ShaderState#glVertexAttribPointer(GL2ES2, GLArrayData) + */ + public void setLocation(int v); + + /** + * Determines wheather the data is server side (VBO), + * or a client side array (false). + */ + public boolean isVBO(); + + /** + * The offset, if it's an VBO, otherwise -1 + */ + public long getOffset(); + + /** + * The VBO name, if it's an VBO, otherwise -1 + */ + public int getVBOName(); + + /** + * The Buffer holding the data, may be null in case of VBO + */ + public Buffer getBuffer(); + + /** + * The number of components per element + */ + public int getComponentNumber(); + + /** + * The component's GL data type, ie. GL_FLOAT + */ + public int getComponentType(); + + /** + * The components size in bytes + */ + public int getComponentSize(); + + /** + * Return the number of elements. + */ + public int getElementNumber(); + + /** + * True, if GL shall normalize fixed point data while converting + * them into float + */ + public boolean getNormalized(); + + /** + * The distance to the next payload, + * allowing interleaved arrays. + */ + public int getStride(); + + public String toString(); + + public void destroy(GL gl); + +} + diff --git a/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java new file mode 100644 index 000000000..cf24d1028 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLAutoDrawable.java @@ -0,0 +1,277 @@ +/* + * 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 javax.media.opengl; + +import jogamp.opengl.Debug; +import java.security.*; + +/** 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. This context has the {@link + GLContext#setSynchronized synchronized} property enabled so that + calls to {@link GLContext#makeCurrent makeCurrent} will block if + the context is current on another thread. This allows the internal + GLContext for the GLAutoDrawable to be used both by the event + based rendering mechanism as well by end users directly.<P> + + The implementation shall initialize itself as soon as possible, + ie if the attached {@link javax.media.nativewindow.NativeSurface NativeSurface} becomes visible/realized. + The following protocol shall be satisfied: + <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 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><P> + + Another implementation detail is the drawable 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 javax.media.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 javax.media.opengl.awt.GLCanvas}'s + and NEWT's <code>AWTCanvas</code> {@link javax.media.opengl.awt.GLCanvas#getGraphicsConfiguration getGraphicsConfiguration()} + specialization. Another demonstration is NEWT's {@link javax.media.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 choosen 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> + + However, to not introduce to much 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 drawable reconfiguration (the default) + -Djogl.screenchange.action=true Enable the drawable reconfiguration + </PRE> + */ +public interface GLAutoDrawable extends GLDrawable { + /** Flag reflecting wheather the drawable reconfiguration will be issued in + * case a screen device change occured, 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, AccessController.getContext()); + + /** + * 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 a new context to this drawable. + */ + public void setContext(GLContext context); + + /** Adds a {@link GLEventListener} to the end of this drawable queue. + The listeners are notified of events in the order of the queue. */ + public void addGLEventListener(GLEventListener listener); + + /** + * Adds a {@link GLEventListener} at the given index of this drawable queue. + * The listeners are notified of events in the order of the queue. + * @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; + + /** Removes a {@link GLEventListener} from this drawable. 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. */ + public void removeGLEventListener(GLEventListener listener); + + /** + * <p> + * Registers the usage of an animator, an {@link javax.media.opengl.GLAnimatorControl} implementation. + * The animator will be queried whether it's animating, ie periodically issuing {@link #display()} calls or not.</p><br> + * <p> + * This method shall be called by an animator implementation only,<br> + * e.g. {@link com.jogamp.opengl.util.Animator#add(javax.media.opengl.GLAutoDrawable)}, passing it's control implementation,<br> + * and {@link com.jogamp.opengl.util.Animator#remove(javax.media.opengl.GLAutoDrawable)}, passing <code>null</code>.</p><br> + * <p> + * Impacts {@link #display()} and {@link #invoke(boolean, GLRunnable)} semantics.</p><br> + * + * @param animator <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 javax.media.opengl.GLAnimatorControl + */ + public abstract void setAnimator(GLAnimatorControl animatorControl) throws GLException; + + /** + * @return the registered {@link javax.media.opengl.GLAnimatorControl} implementation, using this <code>GLAutoDrawable</code>. + * + * @see #setAnimator(javax.media.opengl.GLAnimatorControl) + * @see javax.media.opengl.GLAnimatorControl + */ + public GLAnimatorControl getAnimator(); + + /** + * <p> + * Enqueues a one-shot {@link javax.media.opengl.GLRunnable}, + * which will be executed with the next {@link #display()} call.</p> + * <p> + * If a {@link javax.media.opengl.GLAnimatorControl} is registered, or if it's not animating, the default situation,<br> + * or if the current thread is the animator thread,<br> + * a {@link #display()} call has to be issued after enqueue the <code>GLRunnable</code>.<br> + * No extra synchronization must be performed in case <code>wait</code> is true, since it is executed in the current thread.</p> + * <p> + * If {@link javax.media.opengl.GLAnimatorControl} is registered and is animating,<br> + * no call of {@link #display()} must be issued, since the animator thread will performs it.<br> + * If <code>wait</code> is true, the implementation must wait until the <code>GLRunnable</code> is executed.<br> + * </p><br> + * + * @see #setAnimator(javax.media.opengl.GLAnimatorControl) + * @see #display() + * @see javax.media.opengl.GLRunnable + */ + public void invoke(boolean wait, GLRunnable glRunnable); + + /** 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 javax.media.opengl.GLRunnable}, + * enqueued via {@link #invoke(boolean, GLRunnable)}.</li> + * </ul></p> + * <p> + * May be called periodically by a running {@link javax.media.opengl.GLAnimatorControl} implementation,<br> + * which must register itself with {@link #setAnimator(javax.media.opengl.GLAnimatorControl)}.</p> + * <p> + * Called automatically by the window system toolkit upon receiving a repaint() request, <br> + * except an {@link javax.media.opengl.GLAnimatorControl} implementation {@link javax.media.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(javax.media.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 onOrOff); + + /** Indicates whether automatic buffer swapping is enabled for this + drawable. See {@link #setAutoSwapBufferMode}. */ + public boolean getAutoSwapBufferMode(); + + /** 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); + +} diff --git a/src/jogl/classes/javax/media/opengl/GLBase.java b/src/jogl/classes/javax/media/opengl/GLBase.java new file mode 100644 index 000000000..90b320ed3 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLBase.java @@ -0,0 +1,347 @@ +/** + * 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 javax.media.opengl; + +import java.nio.*; + +/** + * <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 common GL profiles. + * @return whether this GL object conforms to any of the common GL profiles + */ + public boolean isGL(); + + /** + * Indicates whether this GL object conforms to the GL4 compatibility profile. + * The GL4 compatibility profile merges the GL2 profile and GL4 core profile. + * @return whether this GL object conforms to the GL4 compatibility profile + */ + public boolean isGL4bc(); + + /** + * Indicates whether this GL object conforms to the GL4 core profile. + * The GL4 core profile reflects OpenGL versions greater or equal 3.1 + * @return whether this GL object conforms to the GL4 core profile + */ + public boolean isGL4(); + + /** + * Indicates whether this GL object conforms to the GL3 compatibility profile. + * The GL3 compatibility profile merges the GL2 profile and GL3 core profile. + * @return whether this GL object conforms to the GL3 compatibility profile + */ + public boolean isGL3bc(); + + /** + * Indicates whether this GL object conforms to the GL3 core profile. + * The GL3 core profile reflects OpenGL versions greater or equal 3.1 + * @return whether this GL object conforms to the GL3 core profile + */ + public boolean isGL3(); + + /** + * Indicates whether this GL object conforms to the GL2 profile. + * The GL2 profile reflects OpenGL versions greater or equal 1.5 + * @return whether this GL object conforms to the GL2 profile + */ + public boolean isGL2(); + + /** + * Indicates whether this GL object conforms to the GLES1 profile. + * @return whether this GL object conforms to the GLES1 profile + */ + public boolean isGLES1(); + + /** + * Indicates whether this GL object conforms to the GLES2 profile. + * @return whether this GL object conforms to the GLES2 profile + */ + public boolean isGLES2(); + + /** + * Indicates whether this GL object conforms to one of the OpenGL ES compatible profiles. + * @return whether this GL object conforms to one of the OpenGL ES profiles + */ + public boolean isGLES(); + + /** + * Indicates whether this GL object conforms to the GL2ES1 compatible profile. + * @return whether this GL object conforms to the GL2ES1 profile + */ + public boolean isGL2ES1(); + + /** + * Indicates whether this GL object conforms to the GL2ES2 compatible profile. + * @return whether this GL object conforms to the GL2ES2 profile + */ + public boolean isGL2ES2(); + + /** + * Indicates whether this GL object conforms to the GL2GL3 compatible profile. + * @return whether this GL object conforms to the GL2GL3 profile + */ + public boolean isGL2GL3(); + + /** Indicates whether this GL object supports GLSL. */ + public boolean hasGLSL(); + + /** + * Casts this object to the GL interface. + * @return this object cast to the GL interface + * @throws GLException if this GLObject is not a GL implementation + */ + public GL getGL() throws GLException; + + /** + * Casts this object to the GL4bc interface. + * @return this object cast to the GL4bc interface + * @throws GLException if this GLObject is not a GL4bc implementation + */ + public GL4bc getGL4bc() throws GLException; + + /** + * Casts this object to the GL4 interface. + * @return this object cast to the GL4 interface + * @throws GLException if this GLObject is not a GL4 implementation + */ + public GL4 getGL4() throws GLException; + + /** + * Casts this object to the GL3bc interface. + * @return this object cast to the GL3bc interface + * @throws GLException if this GLObject is not a GL3bc implementation + */ + public GL3bc getGL3bc() throws GLException; + + /** + * Casts this object to the GL3 interface. + * @return this object cast to the GL3 interface + * @throws GLException if this GLObject is not a GL3 implementation + */ + public GL3 getGL3() throws GLException; + + /** + * Casts this object to the GL2 interface. + * @return this object cast to the GL2 interface + * @throws GLException if this GLObject is not a GL2 implementation + */ + public GL2 getGL2() throws GLException; + + /** + * Casts this object to the GLES1 interface. + * @return this object cast to the GLES1 interface + * @throws GLException if this GLObject is not a GLES1 implementation + */ + public GLES1 getGLES1() throws GLException; + + /** + * Casts this object to the GLES2 interface. + * @return this object cast to the GLES2 interface + * @throws GLException if this GLObject is not a GLES2 implementation + */ + public GLES2 getGLES2() throws GLException; + + /** + * Casts this object to the GL2ES1 interface. + * @return this object cast to the GL2ES1 interface + * @throws GLException if this GLObject is not a GL2ES1 implementation + */ + public GL2ES1 getGL2ES1() throws GLException; + + /** + * Casts this object to the GL2ES2 interface. + * @return this object cast to the GL2ES2 interface + * @throws GLException if this GLObject is not a GL2ES2 implementation + */ + public GL2ES2 getGL2ES2() throws GLException; + + /** + * Casts this object to the GL2GL3 interface. + * @return this object cast to the GL2GL3 interface + * @throws GLException if this GLObject is not a GL2GL3 implementation + */ + public GL2GL3 getGL2GL3() throws GLException; + + /** + * Returns the GLProfile with which this GL object is associated. + * @return the GLProfile with which this GL object is associated + */ + public GLProfile getGLProfile(); + + /** + * Returns the GLContext with which this GL object is associated. + * @return the GLContext with which this GL object is associated + */ + 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); + + /** 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); +} + diff --git a/src/jogl/classes/javax/media/opengl/GLCapabilities.java b/src/jogl/classes/javax/media/opengl/GLCapabilities.java new file mode 100644 index 000000000..1ae9e40aa --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLCapabilities.java @@ -0,0 +1,462 @@ +/* + * 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 javax.media.opengl; + +import javax.media.nativewindow.Capabilities; + +/** 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#getGLCapabilities()}.<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 pbuffer = 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 boolean sampleBuffers = false; + private int numSamples = 2; + + // Bits for pbuffer creation + private boolean pbufferFloatingPointBuffers; + private boolean pbufferRenderToTexture; + private boolean pbufferRenderToTextureRectangle; + + /** Creates a GLCapabilities object. All attributes are in a default state. + * @param glp GLProfile, or null for the default GLProfile + */ + public GLCapabilities(GLProfile glp) { + glProfile = (null!=glp)?glp:GLProfile.getDefault(GLProfile.getDefaultDevice()); + } + + public Object cloneMutable() { + return clone(); + } + + public Object clone() { + try { + return super.clone(); + } catch (RuntimeException e) { + throw new GLException(e); + } + } + + public int hashCode() { + // 31 * x == (x << 5) - x + int hash = 31 + this.glProfile.hashCode() ; + hash = ((hash << 5) - hash) + ( this.pbuffer ? 1 : 0 ); + hash = ((hash << 5) - hash) + ( this.stereo ? 1 : 0 ); + hash = ((hash << 5) - hash) + ( this.hardwareAccelerated ? 1 : 0 ); + 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; + hash = ((hash << 5) - hash) + ( this.sampleBuffers ? 1 : 0 ); + hash = ((hash << 5) - hash) + this.numSamples; + hash = ((hash << 5) - hash) + ( this.pbufferFloatingPointBuffers ? 1 : 0 ); + hash = ((hash << 5) - hash) + ( this.pbufferRenderToTexture ? 1 : 0 ); + hash = ((hash << 5) - hash) + ( this.pbufferRenderToTextureRectangle ? 1 : 0 ); + return hash; + } + + public boolean equals(Object obj) { + if(this == obj) { return true; } + if(!(obj instanceof GLCapabilitiesImmutable)) { + return false; + } + GLCapabilitiesImmutable other = (GLCapabilitiesImmutable)obj; + boolean res = super.equals(obj) && + other.getGLProfile()==glProfile && + other.isPBuffer()==pbuffer && + 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 && + other.getPbufferFloatingPointBuffers()==pbufferFloatingPointBuffers && + other.getPbufferRenderToTexture()==pbufferRenderToTexture && + other.getPbufferRenderToTextureRectangle()==pbufferRenderToTextureRectangle; + if(sampleBuffers) { + res = res && other.getNumSamples()==numSamples; + } + return res; + } + + /** comparing hw/sw, stereo, multisample, stencil, RGBA and depth only */ + public int compareTo(Object o) { + if ( ! ( o instanceof GLCapabilities ) ) { + Class c = (null != o) ? o.getClass() : null ; + throw new ClassCastException("Not a GLCapabilities object: " + c); + } + + final GLCapabilities caps = (GLCapabilities) o; + + if(hardwareAccelerated && !caps.hardwareAccelerated) { + return 1; + } else if(!hardwareAccelerated && caps.hardwareAccelerated) { + return -1; + } + + if(stereo && !caps.stereo) { + return 1; + } else if(!stereo && caps.stereo) { + return -1; + } + + final int ms = sampleBuffers ? numSamples : 0; + final int xms = caps.sampleBuffers ? caps.numSamples : 0; + + if(ms > xms) { + return 1; + } else if( ms < xms ) { + return -1; + } + + if(stencilBits > caps.stencilBits) { + return 1; + } else if(stencilBits < caps.stencilBits) { + return -1; + } + + final int sc = super.compareTo(caps); // RGBA + if(0 != sc) { + return sc; + } + + if(depthBits > caps.depthBits) { + return 1; + } else if(depthBits < caps.depthBits) { + return -1; + } + + return 0; // they are equal: hw/sw, stereo, multisample, stencil, RGBA and depth + } + + /** Returns the GL profile you desire or used by the drawable. */ + public GLProfile getGLProfile() { + return glProfile; + } + + /** Sets the GL profile you desire */ + public void setGLProfile(GLProfile profile) { + glProfile=profile; + } + + /** Indicates whether pbuffer is used/requested. */ + public boolean isPBuffer() { + return pbuffer; + } + + /** + * Enables or disables pbuffer usage.<br> + * If enabled, onscreen := false. + * Defaults to false. + */ + public void setPBuffer(boolean onOrOff) { + if(onOrOff) { + setOnscreen(false); + } + pbuffer = onOrOff; + } + + /** + * Sets whether the drawable surface supports onscreen.<br> + * If enabled, pbuffer := false.<br> + * Defaults to true. + */ + public void setOnscreen(boolean onscreen) { + if(onscreen) { + setPBuffer(false); + } + super.setOnscreen(onscreen); + } + + /** Indicates whether double-buffering is enabled. */ + public boolean getDoubleBuffered() { + return doubleBuffered; + } + + /** Enables or disables double buffering. */ + public void setDoubleBuffered(boolean onOrOff) { + doubleBuffered = onOrOff; + } + + /** Indicates whether stereo is enabled. */ + public boolean getStereo() { + return stereo; + } + + /** Enables or disables stereo viewing. */ + public void setStereo(boolean onOrOff) { + stereo = onOrOff; + } + + /** Indicates whether hardware acceleration is enabled. */ + public boolean getHardwareAccelerated() { + return hardwareAccelerated; + } + + /** Enables or disables hardware acceleration. */ + public void setHardwareAccelerated(boolean onOrOff) { + hardwareAccelerated = onOrOff; + } + + /** Returns the number of bits requested for the depth buffer. */ + public int getDepthBits() { + return depthBits; + } + + /** Sets the number of bits requested for the depth buffer. */ + public void setDepthBits(int depthBits) { + this.depthBits = depthBits; + } + + /** Returns the number of bits requested for the stencil buffer. */ + public int getStencilBits() { + return stencilBits; + } + + /** Sets the number of bits requested for the stencil buffer. */ + public void setStencilBits(int stencilBits) { + this.stencilBits = stencilBits; + } + + /** Returns 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 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(int accumRedBits) { + this.accumRedBits = accumRedBits; + } + + /** Returns 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 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(int accumGreenBits) { + this.accumGreenBits = accumGreenBits; + } + + /** Returns 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 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(int accumBlueBits) { + this.accumBlueBits = accumBlueBits; + } + + /** Returns the number of bits requested 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. */ + public 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(int accumAlphaBits) { + this.accumAlphaBits = accumAlphaBits; + } + + /** Indicates whether sample buffers for full-scene antialiasing + (FSAA) should be allocated for this drawable. Defaults to + false. */ + public void setSampleBuffers(boolean onOrOff) { + sampleBuffers = onOrOff; + } + + /** Returns whether sample buffers for full-scene antialiasing + (FSAA) should be allocated for this drawable. Defaults to + false. */ + public boolean getSampleBuffers() { + return sampleBuffers; + } + + /** If sample buffers are enabled, indicates the number of buffers + to be allocated. Defaults to 2. */ + public void setNumSamples(int numSamples) { + this.numSamples = numSamples; + } + + /** Returns the number of sample buffers to be allocated if sample + buffers are enabled. Defaults to 2. */ + public int getNumSamples() { + return numSamples; + } + + /** For pbuffers only, indicates whether floating-point buffers + should be used if available. Defaults to false. */ + public void setPbufferFloatingPointBuffers(boolean onOrOff) { + pbufferFloatingPointBuffers = onOrOff; + } + + /** For pbuffers only, returns whether floating-point buffers should + be used if available. Defaults to false. */ + public boolean getPbufferFloatingPointBuffers() { + return pbufferFloatingPointBuffers; + } + + /** For pbuffers only, indicates whether the render-to-texture + extension should be used if available. Defaults to false. */ + public void setPbufferRenderToTexture(boolean onOrOff) { + pbufferRenderToTexture = onOrOff; + } + + /** For pbuffers only, returns whether the render-to-texture + extension should be used if available. Defaults to false. */ + public boolean getPbufferRenderToTexture() { + return pbufferRenderToTexture; + } + + /** For pbuffers only, indicates whether the + render-to-texture-rectangle extension should be used if + available. Defaults to false. */ + public void setPbufferRenderToTextureRectangle(boolean onOrOff) { + pbufferRenderToTextureRectangle = onOrOff; + } + + /** For pbuffers only, returns whether the render-to-texture + extension should be used. Defaults to false. */ + public boolean getPbufferRenderToTextureRectangle() { + return pbufferRenderToTextureRectangle; + } + + public StringBuffer toString(StringBuffer sink) { + if(null == sink) { + sink = new StringBuffer(); + } + + int samples = sampleBuffers ? numSamples : 0 ; + + super.toString(sink); + + sink.append(", accum-rgba ").append(accumRedBits).append("/").append(accumGreenBits).append("/").append(accumBlueBits).append("/").append(accumAlphaBits); + sink.append(", dp/st/ms: ").append(depthBits).append("/").append(stencilBits).append("/").append(samples); + 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()) { + if(pbuffer) { + sink.append(", pbuffer [r2t ").append(pbufferRenderToTexture?1:0) + .append(", r2tr ").append(pbufferRenderToTextureRectangle?1:0) + .append(", float ").append(pbufferFloatingPointBuffers?1:0) + .append("]"); + } else { + sink.append(", pixmap"); + } + } + + return sink; + } + + /** Returns a textual representation of this GLCapabilities + object. */ + public String toString() { + StringBuffer msg = new StringBuffer(); + msg.append("GLCaps["); + toString(msg); + msg.append("]"); + return msg.toString(); + } +} diff --git a/src/jogl/classes/javax/media/opengl/GLCapabilitiesChooser.java b/src/jogl/classes/javax/media/opengl/GLCapabilitiesChooser.java new file mode 100644 index 000000000..73a77de27 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLCapabilitiesChooser.java @@ -0,0 +1,56 @@ +/* + * 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 javax.media.opengl; + +import javax.media.nativewindow.CapabilitiesChooser; + +/** 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}, but the array of {@link Capabilities} + objects passed to {@link #chooseCapabilities chooseCapabilities} + will actually be an array of {@link GLCapabilities}. */ + +public interface GLCapabilitiesChooser extends CapabilitiesChooser { +} diff --git a/src/jogl/classes/javax/media/opengl/GLCapabilitiesImmutable.java b/src/jogl/classes/javax/media/opengl/GLCapabilitiesImmutable.java new file mode 100644 index 000000000..a89aec080 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLCapabilitiesImmutable.java @@ -0,0 +1,150 @@ +/** + * 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 javax.media.opengl; + +import com.jogamp.common.type.WriteCloneable; +import javax.media.nativewindow.CapabilitiesImmutable; + +/** + * Specifies an immutable set of OpenGL capabilities.<br> + * + * @see javax.media.opengl.GLCapabilities + * @see javax.media.nativewindow.CapabilitiesImmutable + */ +public interface GLCapabilitiesImmutable extends WriteCloneable, CapabilitiesImmutable { + + /** + * Returns the number of bits requested 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 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. + */ + int getAccumBlueBits(); + + /** + * Returns 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. + */ + int getAccumGreenBits(); + + /** + * Returns 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. + */ + int getAccumRedBits(); + + /** + * Returns the number of bits requested for the depth buffer. + */ + int getDepthBits(); + + /** + * Indicates whether double-buffering is enabled. + */ + boolean getDoubleBuffered(); + + /** + * Returns the GL profile you desire or used by the drawable. + */ + GLProfile getGLProfile(); + + /** + * Indicates whether hardware acceleration is enabled. + */ + boolean getHardwareAccelerated(); + + /** + * Returns the number of sample buffers to be allocated if sample + * buffers are enabled. Defaults to 2. + */ + int getNumSamples(); + + /** + * For pbuffers only, returns whether floating-point buffers should + * be used if available. Defaults to false. + */ + boolean getPbufferFloatingPointBuffers(); + + /** + * For pbuffers only, returns whether the render-to-texture + * extension should be used if available. Defaults to false. + */ + boolean getPbufferRenderToTexture(); + + /** + * For pbuffers only, returns whether the render-to-texture + * extension should be used. Defaults to false. + */ + boolean getPbufferRenderToTextureRectangle(); + + /** + * Returns whether sample buffers for full-scene antialiasing + * (FSAA) should be allocated for this drawable. Defaults to + * false. + */ + boolean getSampleBuffers(); + + /** + * Returns the number of bits requested for the stencil buffer. + */ + int getStencilBits(); + + /** + * Indicates whether stereo is enabled. + */ + boolean getStereo(); + + /** + * Indicates whether pbuffer is used/requested. + */ + boolean isPBuffer(); + + Object cloneMutable(); + + @Override + boolean equals(Object obj); + + @Override + int hashCode(); + + @Override + String toString(); +} diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java new file mode 100644 index 000000000..b859dee00 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -0,0 +1,780 @@ +/* + * 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 javax.media.opengl; + +import java.util.HashMap; +import java.util.HashSet; +import javax.media.nativewindow.AbstractGraphicsDevice; +import jogamp.opengl.Debug; + +/** 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 { + protected static final boolean DEBUG0 = Debug.debug("GLContext"); + + /** Indicates that the context was not made current during the last call to {@link #makeCurrent makeCurrent}. */ + public static final int CONTEXT_NOT_CURRENT = 0; + /** Indicates that the context was made current during the last call to {@link #makeCurrent makeCurrent}. */ + public static final int CONTEXT_CURRENT = 1; + /** Indicates that a newly-created context was made current during the last call to {@link #makeCurrent makeCurrent}. */ + public static final int CONTEXT_CURRENT_NEW = 2; + + /** <code>ARB_create_context</code> related: created via ARB_create_context */ + protected static final int CTX_IS_ARB_CREATED = 1 << 0; + /** <code>ARB_create_context</code> related: compatibility profile */ + protected static final int CTX_PROFILE_COMPAT = 1 << 1; + /** <code>ARB_create_context</code> related: core profile */ + protected static final int CTX_PROFILE_CORE = 1 << 2; + /** <code>ARB_create_context</code> related: ES profile */ + protected static final int CTX_PROFILE_ES = 1 << 3; + /** <code>ARB_create_context</code> related: flag forward compatible */ + protected static final int CTX_OPTION_FORWARD = 1 << 4; + /** <code>ARB_create_context</code> related: not flag forward compatible */ + protected static final int CTX_OPTION_ANY = 1 << 5; + /** <code>ARB_create_context</code> related: flag debug */ + protected static final int CTX_OPTION_DEBUG = 1 << 6; + + /** GLContext {@link com.jogamp.gluegen.runtime.ProcAddressTable} caching related: GL software implementation */ + protected static final int CTX_IMPL_ACCEL_SOFT = 1 << 0; + /** GLContext {@link com.jogamp.gluegen.runtime.ProcAddressTable} caching related: GL hardware implementation */ + protected static final int CTX_IMPL_ACCEL_HARD = 1 << 1; + + private static ThreadLocal currentContext = new ThreadLocal(); + + private HashMap/*<int, Object>*/ attachedObjects = new HashMap(); + + /** The underlying native OpenGL context */ + protected long contextHandle; + + protected GLContext() { + resetStates(); + } + + protected int ctxMajorVersion; + protected int ctxMinorVersion; + protected int ctxOptions; + protected String ctxVersionString; + + protected void resetStates() { + ctxMajorVersion=-1; + ctxMinorVersion=-1; + ctxOptions=0; + ctxVersionString=null; + if(null!=attachedObjects) { + attachedObjects.clear(); + } + contextHandle=0; + } + + /** + * Returns the GLDrawable to which this context may be used to + * draw. + */ + public abstract GLDrawable getGLDrawable(); + + /** + * Return availability of GL read drawable. + * @return true if a GL read drawable is supported with your driver, otherwise false. + */ + public abstract boolean isGLReadDrawableAvailable(); + + /** + * Set the read GLDrawable for read framebuffer operations.<br> + * The caller should query if this feature is supported via {@link #isGLReadDrawableAvailable()}. + * + * @param read the read GLDrawable for read framebuffer operations. + * If null is passed, the default write drawable will be set. + * + * @throws GLException in case a read drawable is not supported + * and the given drawable is not null and not equal to the internal write drawable. + * + * @see #isGLReadDrawableAvailable() + * @see #getGLReadDrawable() + */ + public abstract void setGLReadDrawable(GLDrawable read); + + /** + * Returns the read GLDrawable this context uses for read framebuffer operations. + * @see #isGLReadDrawableAvailable() + * @see #setGLReadDrawable(javax.media.opengl.GLDrawable) + */ + public abstract GLDrawable getGLReadDrawable(); + + /** + * Makes this GLContext current on the calling thread. + * + * There are two return values that indicate success and one that + * indicates failure. A return value of CONTEXT_CURRENT_NEW + * indicates that that context has been made current, and that + * this is the first time this context has been made current, or + * that the state of the underlying context or drawable may have + * changed since the last time this context was made current. In + * this case, the application may wish to initialize the state. A + * return value of CONTEXT_CURRENT indicates that the context has + * been made currrent, with its previous state restored. + * + * If the context could not be made current (for example, because + * the underlying drawable has not ben realized on the display) , + * a value of CONTEXT_NOT_CURRENT is returned. + * + * If the context is in use by another thread at the time of the + * call, then if isSynchronized() is true the call will + * block. If isSynchronized() is false, an exception will be + * thrown and the context will remain current on the other thread. + * + * @return CONTEXT_CURRENT if the context was successfully made current + * @return CONTEXT_CURRENT_NEW if the context was successfully made + * current, but need to be initialized. + * + * @return CONTEXT_NOT_CURRENT if the context could not be made current. + * + * @throws GLException if synchronization is disabled and the + * context is current on another thread, or because the context + * could not be created or made current due to non-recoverable, + * window system-specific errors. + */ + public abstract int makeCurrent() throws GLException; + + /** + * Releases control of this GLContext from the current thread. + * + * @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 + * GL#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 { + GLContext glc = getCurrent(); + if(null==glc) { + throw new GLException("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 (GLContext) currentContext.get(); + } + + /** + * @return true if this GLContext is current on this thread + */ + public final boolean isCurrent() { + return getCurrent() == this ; + } + + /** + * 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(GLContext cur) { + currentContext.set(cur); + } + + /** + * Destroys this OpenGL context and frees its associated + * resources. The context should have been released before this + * method is called. + */ + public abstract void destroy(); + + /** + * Returns true if 'makeCurrent' will exhibit synchronized behavior. + */ + public abstract boolean isSynchronized(); + + /** + * Determines whether 'makeCurrent' will exhibit synchronized behavior. + */ + public abstract void setSynchronized(boolean isSynchronized); + + /** + * 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 native GL context handle + */ + public final long getHandle() { return contextHandle; } + + /** + * Indicates whether the underlying 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(int name) { + return attachedObjects.get(new Integer(name)); + } + + /** + * Returns the attached user object for the given name to this GLContext. + */ + public final Object getAttachedObject(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 putAttachedObject(int name, Object obj) { + return attachedObjects.put(new Integer(name), obj); + } + + /** + * Sets the attached user object for the given name to this GLContext. + * Returns the previously set object or null. + */ + public final Object putAttachedObject(String name, Object obj) { + return attachedObjects.put(name, obj); + } + + /** + * Classname, GL, GLDrawable + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append(getClass().getName()); + sb.append(" ["); + this.append(sb); + sb.append("] "); + return sb.toString(); + } + + public final StringBuffer append(StringBuffer sb) { + sb.append("OpenGL "); + sb.append(getGLVersionMajor()); + sb.append("."); + sb.append(getGLVersionMinor()); + sb.append(", options 0x"); + sb.append(Integer.toHexString(ctxOptions)); + sb.append(", "); + sb.append(getGLVersion()); + sb.append(", handle "); + sb.append(toHexString(contextHandle)); + sb.append(", "); + sb.append(getGL()); + 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 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 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 javax.media.opengl.GL#glGetString(int) glGetString}({@link javax.media.opengl.GL#GL_EXTENSIONS GL_EXTENSIONS}) + */ + public abstract String getGLExtensionsString(); + + public final int getGLVersionMajor() { return ctxMajorVersion; } + public final int getGLVersionMinor() { return ctxMinorVersion; } + public final boolean isGLCompatibilityProfile() { return ( 0 != ( CTX_PROFILE_COMPAT & ctxOptions ) ); } + public final boolean isGLCoreProfile() { return ( 0 != ( CTX_PROFILE_CORE & ctxOptions ) ); } + public final boolean isGLEmbeddedProfile() { return ( 0 != ( CTX_PROFILE_ES & ctxOptions ) ); } + public final boolean isGLForwardCompatible() { return ( 0 != ( CTX_OPTION_FORWARD & ctxOptions ) ); } + public final boolean isCreatedWithARBMethod() { return ( 0 != ( CTX_IS_ARB_CREATED & ctxOptions ) ); } + + /** + * Returns a valid OpenGL version string, ie<br> + * <pre> + * major.minor ([option]?[options,]*) - gl-version + * </pre><br> + * + * <ul> + * <li> options + * <ul> + * <li> <code>old</code> refers to the non ARB_create_context created context</li> + * <li> <code>new</code> refers to the ARB_create_context created context</li> + * <li> <code>compatible profile</code></li> + * <li> <code>core profile</code></li> + * <li> <code>forward compatible</code></li> + * <li> <code>any</code> refers to the non forward compatible context</li> + * <li> <code>ES</code> refers to the GLES context variant</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, any, new) - 2.0 ES Profile</code></td></tr> + * <tr><td>ATI</td><td>GL2</td> <td><code>3.0 (compatibility profile, any, new) - 3.2.9704 Compatibility Profile Context</code></td></tr> + * <tr><td>ATI</td><td>GL3</td> <td><code>3.3 (core profile, any, new) - 1.4 (3.2.9704 Compatibility Profile Context)</code></td></tr> + * <tr><td>ATI</td><td>GL3bc</td><td><code>3.3 (compatibility profile, any, new) - 1.4 (3.2.9704 Compatibility Profile Context)</code></td></tr> + * <tr><td>NV</td><td>GL2</td> <td><code>3.0 (compatibility profile, any, new) - 3.0.0 NVIDIA 195.36.07.03</code></td></tr> + * <tr><td>NV</td><td>GL3</td> <td><code>3.3 (core profile, any, new) - 3.3.0 NVIDIA 195.36.07.03</code></td></tr> + * <tr><td>NV</td><td>GL3bc</td> <td><code>3.3 (compatibility profile, any, new) - 3.3.0 NVIDIA 195.36.07.03</code></td></tr> + * </table> + */ + public final String getGLVersion() { + return ctxVersionString; + } + + public final boolean isGL4bc() { + return ctxMajorVersion>=4 && 0 != (ctxOptions & CTX_IS_ARB_CREATED) + && 0 != (ctxOptions & CTX_PROFILE_COMPAT); + } + + public final boolean isGL4() { + return ctxMajorVersion>=4 && 0 != (ctxOptions & CTX_IS_ARB_CREATED) + && 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)); + } + + public final boolean isGL3bc() { + return ( ctxMajorVersion>3 || ctxMajorVersion==3 && ctxMinorVersion>=1 ) + && 0 != (ctxOptions & CTX_IS_ARB_CREATED) + && 0 != (ctxOptions & CTX_PROFILE_COMPAT); + } + + public final boolean isGL3() { + return ( ctxMajorVersion>3 || ctxMajorVersion==3 && ctxMinorVersion>=1 ) + && 0 != (ctxOptions & CTX_IS_ARB_CREATED) + && 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)); + } + + public final boolean isGL2() { + return ctxMajorVersion>=1 && 0!=(ctxOptions & CTX_PROFILE_COMPAT); + } + + public final boolean isGL2GL3() { + return isGL2() || isGL3(); + } + + public final boolean isGLES1() { + return ctxMajorVersion==1 && 0!=(ctxOptions & CTX_PROFILE_ES); + } + + public final boolean isGLES2() { + return ctxMajorVersion==2 && 0!=(ctxOptions & CTX_PROFILE_ES); + } + + public final boolean isGLES() { + return isGLEmbeddedProfile(); + } + + public final boolean isGL2ES1() { + return isGL2() || isGLES1() ; + } + + public final boolean isGL2ES2() { + return isGL2GL3() || isGLES2() ; + } + + public final boolean hasGLSL() { + return isGL2ES2() ; + } + + 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 } }; + + public static final int getMaxMajor() { + return GL_VERSIONS.length-1; + } + + public static final int getMaxMinor(int major) { + if(1>major || major>=GL_VERSIONS.length) return -1; + return GL_VERSIONS[major].length-1; + } + + public static final boolean isValidGLVersion(int major, int minor) { + if(1>major || major>=GL_VERSIONS.length) return false; + if(0>minor || minor>=GL_VERSIONS[major].length) return false; + return true; + } + + public static final boolean decrementGLVersion(int major[], int minor[]) { + if(null==major || major.length<1 ||null==minor || minor.length<1) { + throw new GLException("invalid array arguments"); + } + int m = major[0]; + int n = minor[0]; + if(!isValidGLVersion(m, n)) return false; + + // decrement .. + n -= 1; + if(n < 0) { + m -= 1; + n = GL_VERSIONS[m].length-1; + } + if(!isValidGLVersion(m, n)) return false; + major[0]=m; + minor[0]=n; + + return true; + } + + protected static int compose8bit(int one, int two, int three, int four) { + return ( ( one & 0x000000FF ) << 24 ) | + ( ( two & 0x000000FF ) << 16 ) | + ( ( three & 0x000000FF ) << 8 ) | + ( ( four & 0x000000FF ) ) ; + } + + protected static int getComposed8bit(int bits32, int which ) { + switch (which) { + case 1: return ( bits32 & 0xFF000000 ) >> 24 ; + case 2: return ( bits32 & 0x00FF0000 ) >> 16 ; + case 3: return ( bits32 & 0x0000FF00 ) >> 8 ; + case 4: return ( bits32 & 0xFF0000FF ) ; + } + throw new GLException("argument which out of range: "+which); + } + + protected static String composed8BitToString(int bits32, boolean hex1, boolean hex2, boolean hex3, boolean hex4) { + int a = getComposed8bit(bits32, 1); + int b = getComposed8bit(bits32, 2); + int c = getComposed8bit(bits32, 3); + int d = getComposed8bit(bits32, 4); + return "["+toString(a, hex1)+", "+toString(b, hex2)+", "+toString(c, hex3)+", "+toString(d, hex4)+"]"; + } + + private static void validateProfileBits(int bits, 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(javax.media.nativewindow.AbstractGraphicsDevice, int, int) + */ + protected static /*final*/ HashMap/*<DeviceVersionAvailableKey, Integer>*/ deviceVersionAvailable = new HashMap(); + + /** + * @see #getUniqueDeviceString(javax.media.nativewindow.AbstractGraphicsDevice) + */ + private static /*final*/ HashSet/*<UniqueDeviceString>*/ deviceVersionsAvailableSet = new HashSet(); + + protected static String getDeviceVersionAvailableKey(AbstractGraphicsDevice device, int major, int profile) { + return device.getUniqueID() + "-" + toHexString(compose8bit(major, profile, 0, 0)); + } + + protected static boolean getAvailableGLVersionsSet(AbstractGraphicsDevice device) { + synchronized ( deviceVersionsAvailableSet ) { + return deviceVersionsAvailableSet.contains(device.getUniqueID()); + } + } + + protected static void setAvailableGLVersionsSet(AbstractGraphicsDevice device) { + synchronized ( deviceVersionsAvailableSet ) { + String devKey = device.getUniqueID(); + if ( deviceVersionsAvailableSet.contains(devKey) ) { + throw new InternalError("Already set: "+devKey); + } + deviceVersionsAvailableSet.add(devKey); + if (DEBUG0) { + String msg = getThreadName() + ": !!! createContextARB: SET mappedVersionsAvailableSet "+devKey; + // Throwable t = new Throwable(msg); + // t.printStackTrace(); + System.err.println(msg); + } + } + } + + /** + * Called by {@link jogamp.opengl.GLContextImpl#createContextARBMapVersionsAvailable} not intended to be used by + * implementations. However, if {@link #createContextARB} is not being used within + * {@link javax.media.opengl.GLDrawableFactory#getOrCreateSharedContext(javax.media.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(AbstractGraphicsDevice device, + int reqMajor, int profile, int resMajor, int resMinor, int resCtp) + { + validateProfileBits(profile, "profile"); + validateProfileBits(resCtp, "resCtp"); + + String key = getDeviceVersionAvailableKey(device, reqMajor, profile); + Integer val = new Integer(compose8bit(resMajor, resMinor, resCtp, 0)); + synchronized(deviceVersionAvailable) { + val = (Integer) deviceVersionAvailable.put( key, val ); + } + return val; + } + + protected static Integer getAvailableGLVersion(AbstractGraphicsDevice device, int reqMajor, int profile) { + String key = getDeviceVersionAvailableKey(device, reqMajor, profile); + Integer val; + synchronized(deviceVersionAvailable) { + val = (Integer) deviceVersionAvailable.get( key ); + } + 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(AbstractGraphicsDevice device, + int reqMajor, int reqProfile, int[] major, int minor[], int ctp[]) { + + Integer valI = getAvailableGLVersion(device, reqMajor, reqProfile); + if(null==valI) { + return false; + } + + int val = valI.intValue(); + + if(null!=major) { + major[0] = getComposed8bit(val, 1); + } + if(null!=minor) { + minor[0] = getComposed8bit(val, 2); + } + if(null!=ctp) { + ctp[0] = getComposed8bit(val, 3); + } + return true; + } + + /** + * @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} + */ + public static boolean isGLVersionAvailable(AbstractGraphicsDevice device, int major, int profile) { + return null != getAvailableGLVersion(device, major, profile); + } + + public static boolean isGLES1Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 1, GLContext.CTX_PROFILE_ES); + } + + public static boolean isGLES2Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 2, GLContext.CTX_PROFILE_ES); + } + + public static boolean isGL4bcAvailable(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 4, CTX_PROFILE_COMPAT); + } + + public static boolean isGL4Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 4, CTX_PROFILE_CORE); + } + + public static boolean isGL3bcAvailable(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 3, CTX_PROFILE_COMPAT); + } + + public static boolean isGL3Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 3, CTX_PROFILE_CORE); + } + + public static boolean isGL2Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 2, CTX_PROFILE_COMPAT); + } + + /** + * @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} + */ + public static String getAvailableGLVersionAsString(AbstractGraphicsDevice device, int major, int profile) { + int _major[] = { 0 }; + int _minor[] = { 0 }; + int _ctp[] = { 0 }; + if(getAvailableGLVersion(device, major, profile, _major, _minor, _ctp)) { + return getGLVersion(_major[0], _minor[0], _ctp[0], null); + } + return null; + } + + public static String getGLVersion(int major, int minor, int ctp, String gl_version) { + boolean needColon = false; + StringBuffer sb = new StringBuffer(); + sb.append(major); + sb.append("."); + sb.append(minor); + sb.append(" ("); + needColon = appendString(sb, "ES", needColon, 0 != ( CTX_PROFILE_ES & ctp )); + needColon = appendString(sb, "compatibility profile", needColon, 0 != ( CTX_PROFILE_COMPAT & ctp )); + needColon = appendString(sb, "core profile", needColon, 0 != ( CTX_PROFILE_CORE & ctp )); + needColon = appendString(sb, "forward compatible", needColon, 0 != ( CTX_OPTION_FORWARD & ctp )); + needColon = appendString(sb, "any", needColon, 0 != ( CTX_OPTION_ANY & ctp )); + needColon = appendString(sb, "new", needColon, 0 != ( CTX_IS_ARB_CREATED & ctp )); + needColon = appendString(sb, "old", needColon, 0 == ( CTX_IS_ARB_CREATED & ctp )); + sb.append(")"); + if(null!=gl_version) { + sb.append(" - "); + sb.append(gl_version); + } + return sb.toString(); + } + + protected static String toString(int val, boolean hex) { + if(hex) { + return "0x" + Integer.toHexString(val); + } + return String.valueOf(val); + } + + protected static String toHexString(int hex) { + return "0x" + Integer.toHexString(hex); + } + + protected static String toHexString(long hex) { + return "0x" + Long.toHexString(hex); + } + + private static boolean appendString(StringBuffer sb, String string, boolean needColon, 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/javax/media/opengl/GLDrawable.java b/src/jogl/classes/javax/media/opengl/GLDrawable.java new file mode 100644 index 000000000..f4cd77059 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLDrawable.java @@ -0,0 +1,175 @@ +/* + * 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 javax.media.opengl; + +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.NativeSurface; + + +/** 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 { + /** + * Creates a new context for drawing to this drawable that will + * optionally share display lists 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 on + * <a href="../../../overview-summary.html#SHARING">context sharing</a>. + */ + public GLContext createContext(GLContext shareWith); + + /** + * Indicates to on-screen GLDrawable implementations whether the + * underlying window has been created and can be drawn into. End + * users do not need to call this method; it is not necessary to + * call <code>setRealized</code> on a GLCanvas, a GLJPanel, or a + * GLPbuffer, as these perform the appropriate calls on their + * underlying GLDrawables internally. + * + * <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#getGLDrawable + * GLDrawableFactory.getGLDrawable()} 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> + * + * <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> + * + * With an argument of <code>true</code>, + * the minimum implementation shall call + * {@link NativeSurface#lockSurface() NativeSurface's lockSurface()} and if successfull: + * <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> + * + * 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. + */ + public void setRealized(boolean realized); + + /** @return true if this drawable is realized, otherwise false */ + public boolean isRealized(); + + /** Returns the current width of this GLDrawable. */ + public int getWidth(); + + /** Returns the current height of this GLDrawable. */ + public int getHeight(); + + /** 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.<br> + 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. <br> + 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. + @return A copy of the queried object. + */ + public GLCapabilitiesImmutable getChosenGLCapabilities(); + + /** Fetches the {@link GLProfile} for this drawable. + Returns the GLProfile object, no copy. + */ + public GLProfile getGLProfile(); + + public NativeSurface getNativeSurface(); + + /** + * This is the GL/Windowing drawable handle.<br> + * It is usually the {@link javax.media.nativewindow.NativeSurface#getSurfaceHandle()}, + * ie the native surface handle of the underlying windowing toolkit.<br> + * However, on X11/GLX this reflects a GLXDrawable, which represents a GLXWindow, GLXPixmap, or GLXPbuffer.<br> + * On EGL, this represents the EGLSurface.<br> + */ + public long getHandle(); + + public GLDrawableFactory getFactory(); + + public String toString(); +} diff --git a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java new file mode 100644 index 000000000..73b2b3823 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java @@ -0,0 +1,554 @@ +/* + * 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 javax.media.opengl; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.List; + +import com.jogamp.common.JogampRuntimeException; +import jogamp.common.Debug; +import com.jogamp.common.util.ReflectionUtil; + +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.ProxySurface; + +/** <P> Provides a virtual machine- and operating system-independent + mechanism for creating {@link GLDrawable}s. </P> + + <P> The {@link javax.media.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 javax.media.opengl.awt.GLCanvas} or {@link + javax.media.opengl.awt.GLJPanel} if the capabilities can not be met.<br> + {@link javax.media.opengl.GLPbuffer} are always + created immediately and their creation will fail with a + {@link javax.media.opengl.GLException} if errors occur. </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 { + + private static final GLDrawableFactory eglFactory; + private static final GLDrawableFactory nativeOSFactory; + private static final String nativeOSType; + static final String macosxFactoryClassNameCGL = "jogamp.opengl.macosx.cgl.MacOSXCGLDrawableFactory"; + static final String macosxFactoryClassNameAWTCGL = "jogamp.opengl.macosx.cgl.awt.MacOSXAWTCGLDrawableFactory"; + + protected static ArrayList/*<GLDrawableFactoryImpl>*/ glDrawableFactories = new ArrayList(); + + // Shutdown hook mechanism for the factory + private static boolean factoryShutdownHookRegistered = false; + private static Thread factoryShutdownHook = null; + + /** + * Instantiate singleton factories if available, EGLES1, EGLES2 and the OS native ones. + */ + static { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + registerFactoryShutdownHook(); + return null; + } + }); + + nativeOSType = NativeWindowFactory.getNativeWindowType(true); + + GLDrawableFactory tmp = null; + String factoryClassName = Debug.getProperty("jogl.gldrawablefactory.class.name", true, AccessController.getContext()); + ClassLoader cl = GLDrawableFactory.class.getClassLoader(); + if (null == factoryClassName) { + if ( nativeOSType.equals(NativeWindowFactory.TYPE_X11) ) { + factoryClassName = "jogamp.opengl.x11.glx.X11GLXDrawableFactory"; + } else if ( nativeOSType.equals(NativeWindowFactory.TYPE_WINDOWS) ) { + factoryClassName = "jogamp.opengl.windows.wgl.WindowsWGLDrawableFactory"; + } else if ( nativeOSType.equals(NativeWindowFactory.TYPE_MACOSX) ) { + if(ReflectionUtil.isClassAvailable(macosxFactoryClassNameAWTCGL, cl)) { + factoryClassName = macosxFactoryClassNameAWTCGL; + } else { + factoryClassName = macosxFactoryClassNameCGL; + } + } else { + // may use egl*Factory .. + if (GLProfile.DEBUG) { + System.err.println("GLDrawableFactory.static - No native OS Factory for: "+nativeOSType+"; May use EGLDrawableFactory, if available." ); + } + } + } + if (null != factoryClassName) { + if (GLProfile.DEBUG) { + System.err.println("GLDrawableFactory.static - Native OS Factory for: "+nativeOSType+": "+factoryClassName); + } + try { + tmp = (GLDrawableFactory) ReflectionUtil.createInstance(factoryClassName, cl); + } catch (JogampRuntimeException jre) { + if (GLProfile.DEBUG) { + System.err.println("Info: GLDrawableFactory.static - Native Platform: "+nativeOSType+" - not available: "+factoryClassName); + jre.printStackTrace(); + } + } + } + nativeOSFactory = tmp; + + tmp = null; + try { + tmp = (GLDrawableFactory) ReflectionUtil.createInstance("jogamp.opengl.egl.EGLDrawableFactory", cl); + } catch (JogampRuntimeException jre) { + if (GLProfile.DEBUG) { + System.err.println("Info: GLDrawableFactory.static - EGLDrawableFactory - not available"); + jre.printStackTrace(); + } + } + eglFactory = tmp; + } + + private static synchronized void registerFactoryShutdownHook() { + if (factoryShutdownHookRegistered) { + return; + } + factoryShutdownHook = new Thread(new Runnable() { + public void run() { + GLDrawableFactory.shutdownImpl(); + } + }); + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + Runtime.getRuntime().addShutdownHook(factoryShutdownHook); + return null; + } + }); + factoryShutdownHookRegistered = true; + } + + private static synchronized void unregisterFactoryShutdownHook() { + if (!factoryShutdownHookRegistered) { + return; + } + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + Runtime.getRuntime().removeShutdownHook(factoryShutdownHook); + return null; + } + }); + factoryShutdownHookRegistered = false; + } + + private static void shutdownImpl() { + synchronized(glDrawableFactories) { + for(int i=0; i<glDrawableFactories.size(); i++) { + GLDrawableFactory factory = (GLDrawableFactory) glDrawableFactories.get(i); + factory.shutdownInstance(); + } + glDrawableFactories.clear(); + } + } + + protected static void shutdown() { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + unregisterFactoryShutdownHook(); + return null; + } + }); + shutdownImpl(); + } + + private AbstractGraphicsDevice defaultSharedDevice = null; + + protected GLDrawableFactory() { + synchronized(glDrawableFactories) { + glDrawableFactories.add(this); + } + } + + protected void enterThreadCriticalZone() {}; + protected void leaveThreadCriticalZone() {}; + + protected abstract void shutdownInstance(); + + /** + * 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>. + * @return the default shared device for this factory, eg. :0.0 on X11 desktop. + */ + public abstract AbstractGraphicsDevice getDefaultDevice(); + + /** + * @param device which {@link javax.media.nativewindow.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 creation. Otherwise false. + */ + 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"); + } + if (GLProfile.DEBUG) { + System.err.println("Info: GLDrawableFactory.validateDevice: using default device : "+device); + } + } else if( !getIsDeviceCompatible(device) ) { + if (GLProfile.DEBUG) { + System.err.println("Info: GLDrawableFactory.validateDevice: device not compatible : "+device); + } + return null; + } + return device; + } + + /** + * Returns true if a shared context is already mapped to the <code>device</code> {@link AbstractGraphicsDevice#getConnection()}, + * or if a new shared context could be created and mapped. Otherwise return false.<br> + * Creation of the shared context is tried only once. + * + * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + */ + public final boolean getIsSharedContextAvailable(AbstractGraphicsDevice device) { + return null != getOrCreateSharedContext(device); + } + + /** + * Returns the shared context mapped to the <code>device</code> {@link AbstractGraphicsDevice#getConnection()}, + * either a preexisting or newly created, or <code>null</code> if creation failed or not supported.<br> + * Creation of the shared context is tried only once. + * + * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + */ + public final GLContext getOrCreateSharedContext(AbstractGraphicsDevice device) { + device = validateDevice(device); + if(null!=device) { + return getOrCreateSharedContextImpl(device); + } + return null; + } + protected abstract GLContext getOrCreateSharedContextImpl(AbstractGraphicsDevice device); + + /** + * Returns the sole GLDrawableFactory instance for the desktop (X11, WGL, ..) if exist or null + */ + public static GLDrawableFactory getDesktopFactory() { + return nativeOSFactory; + } + + /** + * Returns the sole GLDrawableFactory instance for EGL if exist or null + */ + public static GLDrawableFactory getEGLFactory() { + 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(GLProfile glProfile) throws GLException { + return getFactoryImpl(glProfile.getImplName()); + } + + protected static GLDrawableFactory getFactoryImpl(String glProfileImplName) throws GLException { + if ( GLProfile.usesNativeGLES(glProfileImplName) ) { + if(null==eglFactory) throw new GLException("EGLDrawableFactory unavailable: "+glProfileImplName); + return eglFactory; + } + if(null!=nativeOSFactory) { + return nativeOSFactory; + } + if(null!=eglFactory) { + return eglFactory; + } + throw new GLException("No native platform GLDrawableFactory, nor EGLDrawableFactory available: "+glProfileImplName); + } + + protected static GLDrawableFactory getFactoryImpl(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 javax.media.nativewindow.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 javax.media.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 a GLDrawable according to it's chosen Capabilities,<br> + * which determines pixel format, on- and offscreen incl. PBuffer type. + * <p> + * The native platform's chosen Capabilties are referenced within the target + * NativeSurface's AbstractGraphicsConfiguration.<p> + * + * In case target's {@link javax.media.nativewindow.Capabilities#isOnscreen()} is true,<br> + * an onscreen GLDrawable will be realized. + * <p> + * In case target's {@link javax.media.nativewindow.Capabilities#isOnscreen()} is false,<br> + * either a Pbuffer drawable is created if target's {@link javax.media.opengl.GLCapabilities#isPBuffer()} is true,<br> + * or a simple pixmap/bitmap drawable is created. The latter is unlikely to be hardware accelerated.<br> + * <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 javax.media.nativewindow.GraphicsConfigurationFactory#chooseGraphicsConfiguration(Capabilities, CapabilitiesChooser, AbstractGraphicsScreen) + */ + public abstract GLDrawable createGLDrawable(NativeSurface target) + throws IllegalArgumentException, GLException; + + /** + * Creates a Offscreen GLDrawable incl it's offscreen {@link javax.media.nativewindow.NativeSurface} with the given capabilites and dimensions. + * <p> + * A Pbuffer drawable/surface is created if both {@link javax.media.opengl.GLCapabilities#isPBuffer() caps.isPBuffer()} + * and {@link #canCreateGLPbuffer(javax.media.nativewindow.AbstractGraphicsDevice) canCreateGLPbuffer(device)} is true.<br> + * Otherwise a simple pixmap/bitmap drawable/surface is created, which is unlikely to be hardware accelerated.<br> + * </p> + * + * @param device which {@link javax.media.nativewindow.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 offscreen GLDrawable + * + * @throws GLException if any window system-specific errors caused + * the creation of the Offscreen to fail. + */ + public abstract GLDrawable createOffscreenDrawable(AbstractGraphicsDevice device, + GLCapabilitiesImmutable capabilities, + GLCapabilitiesChooser chooser, + int width, int height) + throws GLException; + + /** + * Creates an offscreen NativeSurface.<br> + * A Pbuffer surface is created if both {@link javax.media.opengl.GLCapabilities#isPBuffer() caps.isPBuffer()} + * and {@link #canCreateGLPbuffer(javax.media.nativewindow.AbstractGraphicsDevice) canCreateGLPbuffer(device)} is true.<br> + * Otherwise a simple pixmap/bitmap surface is created. The latter is unlikely to be hardware accelerated.<br> + * + * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, 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 offscreen native surface + * + * @throws GLException if any window system-specific errors caused + * the creation of the GLDrawable to fail. + */ + public abstract NativeSurface createOffscreenSurface(AbstractGraphicsDevice device, + GLCapabilitiesImmutable caps, + GLCapabilitiesChooser chooser, + int width, int height); + + /** + * Highly experimental API entry, allowing developer of new windowing system bindings + * to leverage the native window handle to produce a NativeSurface implementation (ProxySurface), having the required GLCapabilities.<br> + * Such surface can be used to instantiate a GLDrawable and hence test your new binding w/o the + * costs of providing a full set of abstraction like the AWT GLCanvas or even the native NEWT bindings. + * + * @param device the platform's target device, shall not be <code>null</code> + * @param windowHandle the native window handle + * @param caps the requested GLCapabilties + * @param chooser the custom chooser, may be null for default + * @return The proxy surface wrapping the windowHandle on the device + */ + public abstract ProxySurface createProxySurface(AbstractGraphicsDevice device, + long windowHandle, + GLCapabilitiesImmutable caps, + GLCapabilitiesChooser chooser); + + /** + * Returns true if it is possible to create a GLPbuffer. Some older + * graphics cards do not have this capability. + * + * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + */ + public abstract boolean canCreateGLPbuffer(AbstractGraphicsDevice device); + + /** + * Creates a GLPbuffer with the given capabilites and dimensions. <P> + * + * See the note in the overview documentation on + * <a href="../../../overview-summary.html#SHARING">context sharing</a>. + * + * @param device which {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection() connection} denotes the shared the target device, may be <code>null</code> for the platform's default device. + * @param capabilities the requested capabilities + * @param chooser the custom chooser, may be null for default + * @param initialWidth initial width of pbuffer + * @param initialHeight initial height of pbuffer + * @param shareWith a shared GLContext this GLPbuffer shall use + * + * @return the new {@link GLPbuffer} specific {@link GLAutoDrawable} + * + * @throws GLException if any window system-specific errors caused + * the creation of the GLPbuffer to fail. + */ + public abstract GLPbuffer createGLPbuffer(AbstractGraphicsDevice device, + GLCapabilitiesImmutable capabilities, + GLCapabilitiesChooser chooser, + int initialWidth, + int initialHeight, + GLContext shareWith) + throws GLException; + + //---------------------------------------------------------------------- + // 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 + * javax.media.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 javax.media.nativewindow.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/javax/media/opengl/GLEventListener.java b/src/jogl/classes/javax/media/opengl/GLEventListener.java new file mode 100644 index 000000000..15fae4a39 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLEventListener.java @@ -0,0 +1,92 @@ +/* + * 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 javax.media.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. The client can update the viewport + and view volume of the window appropriately, for example by a + call to {@link javax.media.opengl.GL#glViewport}; note that for + convenience the component has already called <code>glViewport(x, + y, width, height)</code> when this method is called, so the + client may not have to do anything in this method. + */ + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height); +} diff --git a/src/jogl/classes/javax/media/opengl/GLException.java b/src/jogl/classes/javax/media/opengl/GLException.java new file mode 100644 index 000000000..644042e15 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLException.java @@ -0,0 +1,68 @@ +/* + * 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 javax.media.opengl; + +/** A generic exception for OpenGL errors used throughout the binding + as a substitute for {@link RuntimeException}. */ + +public class GLException extends RuntimeException { + /** Constructs a GLException object. */ + public GLException() { + super(); + } + + /** Constructs a GLException object with the specified detail + message. */ + public GLException(String message) { + super(message); + } + + /** Constructs a GLException object with the specified detail + message and root cause. */ + public GLException(String message, Throwable cause) { + super(message, cause); + } + + /** Constructs a GLException object with the specified root + cause. */ + public GLException(Throwable cause) { + super(cause); + } +} diff --git a/src/jogl/classes/javax/media/opengl/GLPbuffer.java b/src/jogl/classes/javax/media/opengl/GLPbuffer.java new file mode 100644 index 000000000..0250365b0 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLPbuffer.java @@ -0,0 +1,91 @@ +/* + * 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 javax.media.opengl; + +/** Provides offscreen rendering support via pbuffers. The principal + addition of this interface is a {@link #destroy} method to + deallocate the pbuffer and its associated resources. It also + contains experimental methods for accessing the pbuffer's contents + as a texture map and enabling rendering to floating-point frame + buffers. These methods are not guaranteed to be supported on all + platforms and may be deprecated in a future release. */ + +public interface GLPbuffer extends GLAutoDrawable { + /** Indicates the GL_APPLE_float_pixels extension is being used for this pbuffer. */ + public static final int APPLE_FLOAT = 1; + + /** Indicates the GL_ATI_texture_float extension is being used for this pbuffer. */ + public static final int ATI_FLOAT = 2; + + /** Indicates the GL_NV_float_buffer extension is being used for this pbuffer. */ + public static final int NV_FLOAT = 3; + + /** Binds this pbuffer to its internal texture target. Only valid to + call if offscreen render-to-texture has been specified in the + NWCapabilities for this GLPbuffer. If the + render-to-texture-rectangle capability has also been specified, + this will use e.g. wglBindTexImageARB as its implementation and + cause the texture to be bound to e.g. the + GL_TEXTURE_RECTANGLE_NV state; otherwise, during the display() + phase the pixels will have been copied into an internal texture + target and this will cause that to be bound to the GL_TEXTURE_2D + state. */ + public void bindTexture(); + + /** Unbinds the pbuffer from its internal texture target. */ + public void releaseTexture(); + + /** Destroys the native resources associated with this pbuffer. It + is not valid to call display() or any other routines on this + pbuffer after it has been destroyed. Before destroying the + pbuffer, the application must destroy any additional OpenGL + contexts which have been created for the pbuffer via {@link + #createContext}. */ + public void destroy(); + + /** Indicates which vendor's extension is being used to support + floating point channels in this pbuffer if that capability was + requested in the NWCapabilities during pbuffer creation. Returns + one of NV_FLOAT, ATI_FLOAT or APPLE_FLOAT, or throws GLException + if floating-point channels were not requested for this pbuffer. + This function may only be called once the init method for this + pbuffer's GLEventListener has been called. */ + public int getFloatingPointMode(); +} diff --git a/src/jogl/classes/javax/media/opengl/GLPipelineFactory.java b/src/jogl/classes/javax/media/opengl/GLPipelineFactory.java new file mode 100644 index 000000000..926651c1d --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLPipelineFactory.java @@ -0,0 +1,194 @@ +/* + * 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 javax.media.opengl; + +import java.lang.reflect.*; +import java.util.StringTokenizer; + +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.<br> + * + * 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><br> + * + * @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(String pipelineClazzBaseName, Class reqInterface, GL downstream, 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 ! + 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()); + } + + 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(); + } + } + Constructor cstr = null; + try { + cstr = upstreamClazz.getDeclaredConstructor( cstrArgTypes ); + } catch(NoSuchMethodException nsme) { + throw new GLException("Couldn't find pipeline constructor: " + upstreamClazz.getName() + + " ( "+getArgsClassNameList(downstreamClazz, additionalArgs) +" )"); + } + Object instance = null; + try { + 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 (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(Class arg0, Object[] args) { + StringBuffer sb = new StringBuffer(); + 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(Class downstreamClazz, String pipelineClazzBaseName) { + String downstreamClazzName = downstreamClazz.getName(); + + StringTokenizer st = new StringTokenizer(downstreamClazzName, "."); + String downstreamClazzBaseName = downstreamClazzName; + while(st.hasMoreTokens()) { + downstreamClazzBaseName = st.nextToken(); + } + String upstreamClazzName = pipelineClazzBaseName+downstreamClazzBaseName; + + Class upstreamClazz = null; + try { + upstreamClazz = Class.forName(upstreamClazzName, true, GLPipelineFactory.class.getClassLoader()); + } catch (Throwable e) { e.printStackTrace(); } + + return upstreamClazz; + } +} + diff --git a/src/jogl/classes/javax/media/opengl/GLProfile.java b/src/jogl/classes/javax/media/opengl/GLProfile.java new file mode 100644 index 000000000..17313f770 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLProfile.java @@ -0,0 +1,1609 @@ +/* + * 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 javax.media.opengl; + +import jogamp.opengl.Debug; +import jogamp.opengl.GLDrawableFactoryImpl; +import jogamp.opengl.GLDynamicLookupHelper; +import jogamp.opengl.DesktopGLDynamicLookupHelper; + +import com.jogamp.common.GlueGenVersion; +import com.jogamp.common.jvm.JVMUtil; +import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.common.util.VersionUtil; +import com.jogamp.nativewindow.NativeWindowVersion; +import com.jogamp.opengl.JoglVersion; + +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.opengl.fixedfunc.GLPointerFunc; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + +/** + * 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 = Debug.debug("GLProfile"); + + /** + * Static one time initialization of JOGL. + * <p> + * The parameter <code>firstUIActionOnProcess</code> has an impact on concurrent locking,<br> + * see {@link javax.media.nativewindow.NativeWindowFactory#initSingleton(boolean) NativeWindowFactory.initSingleton(firstUIActionOnProcess)}. + * </p> + * <p> + * Applications shall call this methods <b>ASAP</b>, before any other UI invocation.<br> + * You may issue the call in your <code>main class</code> static block, which is the earliest point in your application/applet lifecycle, + * or within the <code>main function</code>.<br> + * In case applications are able to initialize JOGL before any other UI action,<br> + * they shall invoke this method with <code>firstUIActionOnProcess=true</code> and benefit from fast native multithreading support on all platforms if possible.</P> + * <P> + * RCP Application (Applet's, Webstart, Netbeans, ..) using JOGL may not be able to initialize JOGL + * before the first UI action.<br> + * In such case you shall invoke this method with <code>firstUIActionOnProcess=false</code>.<br> + * On some platforms, notably X11 with AWT usage, JOGL will utilize special locking mechanisms which may slow down your + * application.</P> + * <P> + * Remark: NEWT is currently not affected by this behavior, ie always uses native multithreading.</P> + * <P> + * However, in case this method is not invoked, hence GLProfile is not initialized explicitly by the user,<br> + * the first call to {@link #getDefault()}, {@link #get(java.lang.String)}, etc, will initialize with <code>firstUIActionOnProcess=false</code>,<br> + * hence without the possibility to enable native multithreading.<br> + * This is not the recommended way, since it may has a performance impact, but it allows you to run code without explicit initialization.</P> + * <P> + * In case no explicit initialization was invoked and the implicit initialization didn't happen,<br> + * you may encounter the following exception: + * <pre> + * javax.media.opengl.GLException: No default profile available + * </pre></P> + * + * @param firstUIActionOnProcess Should be <code>true</code> if called before the first UI action of the running program, + * otherwise <code>false</code>. + */ + public static synchronized void initSingleton(final boolean firstUIActionOnProcess) { + if(!initialized) { + initialized = true; + // run the whole static initialization privileged to speed up, + // since this skips checking further access + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + initProfilesForDefaultDevices(firstUIActionOnProcess); + return null; + } + }); + } + } + + /** + * Trigger eager initialization of GLProfiles for the given device, + * in case it isn't done yet. + */ + public static void initProfiles(AbstractGraphicsDevice device) { + getProfileMap(device); + } + + /** + * 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 javax.media.opengl.GLDrawableFactory#shutdown()}.<br> + * The shutdown implementation is called via the JVM shutdown hook, if not manually invoked here.<br> + * Invoke <code>shutdown()</code> manually is recommended, due to the unreliable JVM state within the shutdown hook.<br> + */ + public static synchronized void shutdown() { + if(initialized) { + initialized = false; + GLDrawableFactory.shutdown(); + } + } + + // + // Query platform available OpenGL implementation + // + + public static boolean isGL4bcAvailable(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL4bc); + } + + public static boolean isGL4Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL4); + } + + public static boolean isGL3bcAvailable(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL3bc); + } + + public static boolean isGL3Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL3); + } + + public static boolean isGL2Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL2); + } + + public static boolean isGLES2Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GLES2); + } + + public static boolean isGLES1Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GLES1); + } + + public static boolean isGL2ES1Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL2ES1); + } + + public static boolean isGL2ES2Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL2ES2); + } + + /** Uses the default device */ + public static boolean isGL4bcAvailable() { + return isGL4bcAvailable(null); + } + + /** Uses the default device */ + public static boolean isGL4Available() { + return isGL4Available(null); + } + + /** Uses the default device */ + public static boolean isGL3bcAvailable() { + return isGL3bcAvailable(null); + } + + /** Uses the default device */ + public static boolean isGL3Available() { + return isGL3Available(null); + } + + /** Uses the default device */ + public static boolean isGL2Available() { + return isGL2Available(null); + } + + /** Uses the default device */ + public static boolean isGLES2Available() { + return isGLES2Available(null); + } + + /** Uses the default device */ + public static boolean isGLES1Available() { + return isGLES1Available(null); + } + + /** Uses the default device */ + public static boolean isGL2ES1Available() { + return isGL2ES1Available(null); + } + + /** Uses the default device */ + public static boolean isGL2ES2Available() { + return isGL2ES2Available(null); + } + + public static String glAvailabilityToString(AbstractGraphicsDevice device) { + boolean avail; + StringBuffer sb = new StringBuffer(); + + validateInitialization(); + + if(null==device) { + device = defaultDevice; + } + + sb.append("GLAvailability[Native[GL4bc "); + avail=isGL4bcAvailable(device); + sb.append(avail); + if(avail) { + glAvailabilityToString(device, sb, 4, GLContext.CTX_PROFILE_COMPAT); + } + + sb.append(", GL4 "); + avail=isGL4Available(device); + sb.append(avail); + if(avail) { + glAvailabilityToString(device, sb, 4, GLContext.CTX_PROFILE_CORE); + } + + sb.append(", GL3bc "); + avail=isGL3bcAvailable(device); + sb.append(avail); + if(avail) { + glAvailabilityToString(device, sb, 3, GLContext.CTX_PROFILE_COMPAT); + } + + sb.append(", GL3 "); + avail=isGL3Available(device); + sb.append(avail); + if(avail) { + glAvailabilityToString(device, sb, 3, GLContext.CTX_PROFILE_CORE); + } + + sb.append(", GL2 "); + avail=isGL2Available(device); + sb.append(avail); + if(avail) { + glAvailabilityToString(device, sb, 2, GLContext.CTX_PROFILE_COMPAT); + } + + sb.append(", GL2ES1 "); + sb.append(isGL2ES1Available(device)); + + sb.append(", GLES1 "); + avail=isGLES1Available(device); + sb.append(avail); + if(avail) { + glAvailabilityToString(device, sb, 1, GLContext.CTX_PROFILE_ES); + } + + sb.append(", GL2ES2 "); + sb.append(isGL2ES2Available(device)); + + sb.append(", GLES2 "); + avail=isGLES2Available(device); + sb.append(avail); + if(avail) { + glAvailabilityToString(device, sb, 2, GLContext.CTX_PROFILE_ES); + } + + sb.append("], Profiles["); + for(Iterator i=getProfileMap(device).values().iterator(); i.hasNext(); ) { + sb.append(((GLProfile)i.next()).toString()); + sb.append(", "); + } + sb.append(", default "); + sb.append(getDefault(device)); + sb.append("]]"); + + return sb.toString(); + } + + /** 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"; + + /** The desktop OpenGL core profile 4.x, with x >= 0 */ + public static final String GL4 = "GL4"; + + /** 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"; + + /** The desktop OpenGL core profile 3.x, with x >= 1 */ + public static final String GL3 = "GL3"; + + /** The desktop OpenGL profile 1.x up to 3.0 */ + public static final String GL2 = "GL2"; + + /** The embedded OpenGL profile ES 1.x, with x >= 0 */ + public static final String GLES1 = "GLES1"; + + /** The embedded OpenGL profile ES 2.x, with x >= 0 */ + public static final String GLES2 = "GLES2"; + + /** The intersection of the desktop GL2 and embedded ES1 profile */ + public static final String GL2ES1 = "GL2ES1"; + + /** The intersection of the desktop GL3, GL2 and embedded ES2 profile */ + public static final String GL2ES2 = "GL2ES2"; + + /** The intersection of the desktop GL3 and GL2 profile */ + public static final String GL2GL3 = "GL2GL3"; + + /** The default profile, used for the device default profile map */ + private static final String GL_DEFAULT = "GL_DEFAULT"; + + /** + * 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. + * + * <ul> + * <li> GL4bc + * <li> GL3bc + * <li> GL2 + * <li> GL2GL3 + * <li> GL4 + * <li> GL3 + * <li> GL2ES2 + * <li> GLES2 + * <li> GL2ES1 + * <li> GLES1 + * </ul> + * + */ + public static final String[] GL_PROFILE_LIST_ALL = new String[] { GL4bc, GL3bc, GL2, GL2GL3, GL4, GL3, GL2ES2, GLES2, GL2ES1, GLES1 }; + + /** + * Order of maximum profiles. + * + * <ul> + * <li> GL4bc + * <li> GL4 + * <li> GL3bc + * <li> GL3 + * <li> GL2 + * <li> GL2GL3 + * <li> GL2ES2 + * <li> GLES2 + * <li> GL2ES1 + * <li> GLES1 + * </ul> + * + */ + public static final String[] GL_PROFILE_LIST_MAX = new String[] { GL4bc, GL4, GL3bc, GL3, GL2, GL2GL3, GL2ES2, GLES2, GL2ES1, GLES1 }; + + /** + * Order of minimum original desktop profiles. + * + * <ul> + * <li> GL2 + * <li> GL3bc + * <li> GL4bc + * <li> GL3 + * <li> GL4 + * </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> GL3bc + * <li> GL2 + * <li> GL2ES1 + * <li> GLES1 + * </ul> + * + */ + public static final String[] GL_PROFILE_LIST_MAX_FIXEDFUNC = new String[] { GL4bc, GL3bc, GL2, GL2ES1, GLES1 }; + + /** + * Order of maximum programmable shader profiles + * + * <ul> + * <li> GL4 + * <li> GL4bc + * <li> GL3 + * <li> GL3bc + * <li> GL2 + * <li> GL2ES2 + * <li> GLES2 + * </ul> + * + */ + public static final String[] GL_PROFILE_LIST_MAX_PROGSHADER = new String[] { GL4bc, GL4, GL3bc, GL3, GL2, GL2ES2, GLES2 }; + + /** + * All GL2ES2 Profiles in the order of default detection. + * + * <ul> + * <li> GL2ES2 + * <li> GL2 + * <li> GL3 + * <li> GL4 + * <li> GLES2 + * </ul> + * + */ + public static final String[] GL_PROFILE_LIST_GL2ES2 = new String[] { GL2ES2, GL4, GL3, GL2, GLES2 }; + + /** + * All GL2ES1 Profiles in the order of default detection. + * + * <ul> + * <li> GL2ES1 + * <li> GL2 + * <li> GL3bc + * <li> GL4bc + * <li> GLES1 + * </ul> + * + */ + public static final String[] GL_PROFILE_LIST_GL2ES1 = new String[] { GL2ES1, GL4bc, GL3bc, GL2, GLES1 }; + + /** + * All GLES Profiles in the order of default detection. + * + * <ul> + * <li> GLES2 + * <li> GLES1 + * </ul> + * + */ + public static final String[] GL_PROFILE_LIST_GLES = new String[] { GLES2, GLES1 }; + + /** 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} + * @see #GL_PROFILE_LIST_ALL + */ + public static GLProfile getDefault(AbstractGraphicsDevice device) { + GLProfile glp = get(device, GL_DEFAULT); + return glp; + } + + /** Uses 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 implementation for the given profile is found. + * @see #GL_PROFILE_LIST_MAX + */ + public static GLProfile getMaximum(AbstractGraphicsDevice device) + throws GLException + { + return get(device, GL_PROFILE_LIST_MAX); + } + + /** Uses the default device */ + public static GLProfile getMaximum() + throws GLException + { + return get(GL_PROFILE_LIST_MAX); + } + + /** + * Returns the lowest desktop profile. + * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MIN_DESKTOP} + * + * @throws GLException if no implementation for the given profile is found. + * @see #GL_PROFILE_LIST_MIN_DESKTOP + */ + public static GLProfile getMinDesktop(AbstractGraphicsDevice device) + throws GLException + { + return get(device, GL_PROFILE_LIST_MIN_DESKTOP); + } + + /** Uses the default device */ + public static GLProfile getMinDesktop() + throws GLException + { + return get(GL_PROFILE_LIST_MIN_DESKTOP); + } + + + /** + * 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 implementation for the given profile is found. + * @see #GL_PROFILE_LIST_MAX_FIXEDFUNC + */ + public static GLProfile getMaxFixedFunc(AbstractGraphicsDevice device) + throws GLException + { + return get(device, GL_PROFILE_LIST_MAX_FIXEDFUNC); + } + + /** Uses the default device */ + public static GLProfile getMaxFixedFunc() + throws GLException + { + return get(GL_PROFILE_LIST_MAX_FIXEDFUNC); + } + + /** + * 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 implementation for the given profile is found. + * @see #GL_PROFILE_LIST_MAX_PROGSHADER + */ + public static GLProfile getMaxProgrammable(AbstractGraphicsDevice device) + throws GLException + { + return get(device, GL_PROFILE_LIST_MAX_PROGSHADER); + } + + /** Uses the default device */ + public static GLProfile getMaxProgrammable() + throws GLException + { + return get(GL_PROFILE_LIST_MAX_PROGSHADER); + } + + /** + * Returns a profile, implementing the interface GL2ES1. + * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_GL2ES1} + * + * @throws GLException if no implementation for the given profile is found. + * @see #GL_PROFILE_LIST_GL2ES1 + */ + public static GLProfile getGL2ES1(AbstractGraphicsDevice device) + throws GLException + { + return get(device, GL_PROFILE_LIST_GL2ES1); + } + + /** Uses the default device */ + public static GLProfile getGL2ES1() + throws GLException + { + return get(GL_PROFILE_LIST_GL2ES1); + } + + /** + * Returns a profile, implementing the interface GL2ES2. + * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_GL2ES2} + * + * @throws GLException if no implementation for the given profile is found. + * @see #GL_PROFILE_LIST_GL2ES2 + */ + public static GLProfile getGL2ES2(AbstractGraphicsDevice device) + throws GLException + { + return get(device, GL_PROFILE_LIST_GL2ES2); + } + + /** Uses the default device */ + public static GLProfile getGL2ES2() + throws GLException + { + return get(GL_PROFILE_LIST_GL2ES2); + } + + /** 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. + * + * @throws GLException if no implementation for the given profile is found. + */ + public static GLProfile get(AbstractGraphicsDevice device, String profile) + throws GLException + { + if(null==profile || profile.equals("GL")) { + profile = GL_DEFAULT; + } + return (GLProfile) getProfileMap(device).get(profile); + } + + /** Uses the default device */ + public static GLProfile get(String profile) + throws GLException + { + return get(defaultDevice, profile); + } + + /** + * Returns the first profile from the given list, + * where an implementation is available. + * + * @throws GLException if no implementation for the given profile is found. + */ + public static GLProfile get(AbstractGraphicsDevice device, String[] profiles) + throws GLException + { + HashMap map = getProfileMap(device); + for(int i=0; i<profiles.length; i++) { + String profile = profiles[i]; + GLProfile glProfile = (GLProfile) map.get(profile); + if(null!=glProfile) { + return glProfile; + } + } + throw new GLException("Profiles "+array2String(profiles)+" not available on device "+device); + } + + /** Uses the default device */ + public static GLProfile get(String[] profiles) + throws GLException + { + return get(defaultDevice, profiles); + } + + /** Indicates whether the native OpenGL ES1 profile is in use. + * This requires an EGL interface. + */ + public static boolean usesNativeGLES1(String profileImpl) { + return GLES1.equals(profileImpl); + } + + /** Indicates whether the native OpenGL ES2 profile is in use. + * This requires an EGL or ES2 compatible interface. + */ + public static boolean usesNativeGLES2(String profileImpl) { + return GLES2.equals(profileImpl); + } + + /** Indicates whether either of the native OpenGL ES profiles are in use. */ + public static boolean usesNativeGLES(String profileImpl) { + return usesNativeGLES2(profileImpl) || usesNativeGLES1(profileImpl); + } + + /** @return {@link javax.media.nativewindow.NativeWindowFactory#isAWTAvailable()} and + JOGL's AWT part */ + public static boolean isAWTAvailable() { return isAWTAvailable; } + + public static String getGLTypeName(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 javax.media.opengl.GL2ES2.GL_INT: + return "GL_INT"; + case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT: + return "GL_UNSIGNED_INT"; + case javax.media.opengl.GL2.GL_DOUBLE: + return "GL_DOUBLE"; + case javax.media.opengl.GL2.GL_2_BYTES: + return "GL_2_BYTES"; + case javax.media.opengl.GL2.GL_3_BYTES: + return "GL_3_BYTES"; + case javax.media.opengl.GL2.GL_4_BYTES: + return "GL_4_BYTES"; + } + return null; + } + + public static String getGLArrayName(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(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. + */ + public final boolean equals(Object o) { + if(this==o) { return true; } + if(o instanceof GLProfile) { + GLProfile glp = (GLProfile)o; + return profile.equals(glp.getName()) && profileImpl.equals(glp.getImplName()) ; + } + return false; + } + + public int hashCode() { + int hash = 5; + hash = 97 * hash + (this.profileImpl != null ? this.profileImpl.hashCode() : 0); + hash = 97 * hash + (this.profile != null ? this.profile.hashCode() : 0); + return hash; + } + + /** + * @param glp GLProfile to compare with + * @throws GLException if given GLProfile and this aren't equal + */ + public final void verifyEquality(GLProfile glp) throws GLException { + if(!this.equals(glp)) { + throw new GLException("GLProfiles are not equal: "+this+" != "+glp); + } + } + + public final String getName() { + return profile; + } + + public final String getImplName() { + return profileImpl; + } + + /** Indicates whether this profile is capable of GL4bc. */ + public final boolean isGL4bc() { + return GL4bc.equals(profile); + } + + /** Indicates whether this profile is capable of GL4. */ + public final boolean isGL4() { + return isGL4bc() || GL4.equals(profile); + } + + /** Indicates whether this profile is capable of GL3bc. */ + public final boolean isGL3bc() { + return isGL4bc() || GL3bc.equals(profile); + } + + /** Indicates whether this profile is capable of GL3. */ + public final boolean isGL3() { + return isGL4() || isGL3bc() || GL3.equals(profile); + } + + /** Indicates whether this context is a GL2 context */ + public final boolean isGL2() { + return isGL3bc() || GL2.equals(profile); + } + + /** Indicates whether this profile is capable of GLES1. */ + public final boolean isGLES1() { + return GLES1.equals(profile); + } + + /** Indicates whether this profile is capable of GLES2. */ + public final boolean isGLES2() { + return GLES2.equals(profile); + } + + /** Indicates whether this profile is capable of GL2ES1. */ + public final boolean isGL2ES1() { + return GL2ES1.equals(profile) || isGL2() || isGLES1() ; + } + + /** Indicates whether this profile is capable os GL2ES2. */ + public final boolean isGL2ES2() { + return GL2ES2.equals(profile) || isGL2() || isGL3() || isGLES2() ; + } + + /** Indicates whether this profile is capable os GL2GL3. */ + public final boolean isGL2GL3() { + return GL2GL3.equals(profile) || isGL2() || isGL3() ; + } + + /** Indicates whether this profile supports GLSL. */ + public final boolean hasGLSL() { + return isGL2ES2() ; + } + + /** Indicates whether this profile uses the native OpenGL ES1 implementations. */ + public final boolean usesNativeGLES1() { + return GLES1.equals(profileImpl); + } + + /** Indicates whether this profile uses the native OpenGL ES2 implementations. */ + public final boolean usesNativeGLES2() { + return GLES2.equals(profileImpl); + } + + /** Indicates whether this profile uses either of the native OpenGL ES implementations. */ + public final boolean usesNativeGLES() { + return usesNativeGLES2() || usesNativeGLES1(); + } + + /** + * General validation if type is a valid GL data type + * for the current profile + */ + public boolean isValidDataType(int type, 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 javax.media.opengl.GL2ES2.GL_INT: + case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT: + if( isGL2ES2() ) { + return true; + } + case javax.media.opengl.GL2.GL_DOUBLE: + if( isGL3() ) { + return true; + } + case javax.media.opengl.GL2.GL_2_BYTES: + case javax.media.opengl.GL2.GL_3_BYTES: + case javax.media.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(int index, int comps, int type, + boolean isVertexAttribPointer, boolean throwException) { + 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; + } + 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 GLES1: "+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 javax.media.opengl.GL2ES2.GL_INT: + case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT: + case javax.media.opengl.GL2.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 javax.media.opengl.GL2ES2.GL_INT: + case javax.media.opengl.GL2.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 javax.media.opengl.GL2ES2.GL_INT: + case javax.media.opengl.GL2.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 javax.media.opengl.GL2ES2.GL_INT: + case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT: + case javax.media.opengl.GL2.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 javax.media.opengl.GL2ES2.GL_INT: + case javax.media.opengl.GL2.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; + } + + public String toString() { + return "GLProfile[" + profile + "/" + profileImpl + "]"; + } + + static { + JVMUtil.initSingleton(); + } + + private static /*final*/ boolean isAWTAvailable; + + private static /*final*/ boolean hasDesktopGL; + private static /*final*/ boolean hasGL234Impl; + private static /*final*/ boolean hasGLES2Impl; + private static /*final*/ boolean hasGLES1Impl; + + private static /*final*/ GLDrawableFactoryImpl eglFactory; + private static /*final*/ GLDrawableFactoryImpl desktopFactory; + private static /*final*/ AbstractGraphicsDevice defaultDevice; + private static /*final*/ AbstractGraphicsDevice defaultDesktopDevice; + private static /*final*/ AbstractGraphicsDevice defaultEGLDevice; + + static boolean initialized = false; + + /** + * Tries the profiles implementation and native libraries. + * Throws an GLException if no profile could be found at all. + */ + private static void initProfilesForDefaultDevices(boolean firstUIActionOnProcess) { + NativeWindowFactory.initSingleton(firstUIActionOnProcess); + + if(DEBUG) { + System.err.println("GLProfile.init firstUIActionOnProcess: "+ firstUIActionOnProcess + + ", thread: " + Thread.currentThread().getName()); + System.err.println(VersionUtil.getPlatformInfo()); + System.err.println(GlueGenVersion.getInstance()); + System.err.println(NativeWindowVersion.getInstance()); + System.err.println(JoglVersion.getInstance()); + } + + ClassLoader classloader = GLProfile.class.getClassLoader(); + + isAWTAvailable = NativeWindowFactory.isAWTAvailable() && + ReflectionUtil.isClassAvailable("javax.media.opengl.awt.GLCanvas", classloader) ; // JOGL + + hasGL234Impl = ReflectionUtil.isClassAvailable("jogamp.opengl.gl4.GL4bcImpl", classloader); + + // + // 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 .. + // + Throwable t=null; + // if successfull it has a shared dummy drawable and context created + try { + desktopFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GL2); + if(null != desktopFactory) { + DesktopGLDynamicLookupHelper glLookupHelper = (DesktopGLDynamicLookupHelper) desktopFactory.getGLDynamicLookupHelper(0); + if(null!=glLookupHelper) { + hasDesktopGL = glLookupHelper.hasGLBinding(); + } + } + } catch (LinkageError le) { + t=le; + } catch (RuntimeException re) { + t=re; + } catch (Throwable tt) { + t=tt; + } + if(DEBUG) { + if(null!=t) { + t.printStackTrace(); + } + if(null == desktopFactory) { + System.err.println("Info: GLProfile.init - Desktop GLDrawable factory not available"); + } + } + + if(null == desktopFactory) { + hasDesktopGL = false; + hasGL234Impl = false; + } else { + defaultDesktopDevice = desktopFactory.getDefaultDevice(); + defaultDevice = defaultDesktopDevice; + } + + if ( ReflectionUtil.isClassAvailable("jogamp.opengl.egl.EGLDrawableFactory", classloader) ) { + t=null; + try { + eglFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GLES2); + if(null != eglFactory) { + GLDynamicLookupHelper eglLookupHelper = eglFactory.getGLDynamicLookupHelper(2); + if(null!=eglLookupHelper) { + hasGLES2Impl = eglLookupHelper.isLibComplete(); + } + eglLookupHelper = eglFactory.getGLDynamicLookupHelper(1); + if(null!=eglLookupHelper) { + hasGLES1Impl = eglLookupHelper.isLibComplete(); + } + } + } catch (LinkageError le) { + t=le; + } catch (SecurityException se) { + t=se; + } catch (NullPointerException npe) { + t=npe; + } catch (RuntimeException re) { + t=re; + } + if(DEBUG) { + if(null!=t) { + t.printStackTrace(); + } + if(null == eglFactory) { + System.err.println("Info: GLProfile.init - EGL GLDrawable factory not available"); + } + } + } + + if(null == eglFactory) { + hasGLES2Impl = false; + hasGLES1Impl = false; + } else { + defaultEGLDevice = eglFactory.getDefaultDevice(); + if (null==defaultDevice) { + defaultDevice = defaultEGLDevice; + } + } + + boolean addedAnyProfile = initProfilesForDevice(defaultDesktopDevice) || + initProfilesForDevice(defaultEGLDevice); + + if(DEBUG) { + System.err.println("GLProfile.init isAWTAvailable "+isAWTAvailable); + System.err.println("GLProfile.init has desktopFactory "+(null!=desktopFactory)); + System.err.println("GLProfile.init hasDesktopGL "+hasDesktopGL); + System.err.println("GLProfile.init hasGL234Impl "+hasGL234Impl); + System.err.println("GLProfile.init has eglFactory "+(null!=eglFactory)); + System.err.println("GLProfile.init hasGLES1Impl "+hasGLES1Impl); + System.err.println("GLProfile.init hasGLES2Impl "+hasGLES2Impl); + System.err.println("GLProfile.init defaultDesktopDevice "+defaultDesktopDevice); + System.err.println("GLProfile.init defaultEGLDevice "+defaultEGLDevice); + System.err.println("GLProfile.init defaultDevice "+defaultDevice); + } + + if(!addedAnyProfile) { + throw new GLException("No profile available: "+array2String(GL_PROFILE_LIST_ALL)+", "+ glAvailabilityToString()); + } + } + + /** + * @param device the device for which profiles shall be initialized + * @return true if any profile for the device exists, otherwise false + */ + private static synchronized boolean initProfilesForDevice(AbstractGraphicsDevice device) { + if(null == device) { + return false; + } + GLDrawableFactory factory = GLDrawableFactory.getFactoryImpl(device); + factory.enterThreadCriticalZone(); + try { + return initProfilesForDeviceImpl(device); + } finally { + factory.leaveThreadCriticalZone(); + } + } + private static synchronized boolean initProfilesForDeviceImpl(AbstractGraphicsDevice device) { + boolean isSet = GLContext.getAvailableGLVersionsSet(device); + + if(DEBUG) { + String msg = "Info: GLProfile.initProfilesForDevice: "+device+", isSet "+isSet; + Throwable t = new Throwable(msg); + t.printStackTrace(); + // System.err.println(msg); + } + if(isSet) { + return null != GLProfile.getDefault(device); + } + + boolean addedDesktopProfile = false; + boolean addedEGLProfile = false; + + if( hasDesktopGL && desktopFactory.getIsDeviceCompatible(device)) { + // 1st pretend we have all Desktop and EGL profiles .. + computeProfileMap(device, true /* desktopCtxUndef*/, true /* eglCtxUndef */); + + // Triggers eager initialization of share context in GLDrawableFactory for the device, + // hence querying all available GLProfiles + boolean desktopSharedCtxAvail = desktopFactory.getIsSharedContextAvailable(device); + if (DEBUG) { + System.err.println("GLProfile.initProfilesForDevice: "+device+": desktop Shared Ctx "+desktopSharedCtxAvail); + } + if( null == GLContext.getAvailableGLVersion(device, 2, GLContext.CTX_PROFILE_COMPAT) ) { + // nobody yet set the available desktop versions, see {@link GLContextImpl#makeCurrent}, + // so we have to add the usual suspect + GLContext.mapAvailableGLVersion(device, + 2, GLContext.CTX_PROFILE_COMPAT, + 1, 5, GLContext.CTX_PROFILE_COMPAT|GLContext.CTX_OPTION_ANY); + } + addedDesktopProfile = computeProfileMap(device, false /* desktopCtxUndef*/, false /* eglCtxUndef */); + } else if( null!=eglFactory && ( hasGLES2Impl || hasGLES1Impl ) && eglFactory.getIsDeviceCompatible(device)) { + // 1st pretend we have all EGL profiles .. + computeProfileMap(device, false /* desktopCtxUndef*/, true /* eglCtxUndef */); + + // Triggers eager initialization of share context in GLDrawableFactory for the device, + // hence querying all available GLProfiles + boolean eglSharedCtxAvail = eglFactory.getIsSharedContextAvailable(device); + if (DEBUG) { + System.err.println("GLProfile.initProfilesForDevice: "+device+": egl Shared Ctx "+eglSharedCtxAvail); + } + if(hasGLES2Impl && null == GLContext.getAvailableGLVersion(device, 2, GLContext.CTX_PROFILE_ES) ) { + // nobody yet set the available desktop versions, see {@link GLContextImpl#makeCurrent}, + // so we have to add the usual suspect + GLContext.mapAvailableGLVersion(device, + 2, GLContext.CTX_PROFILE_ES, + 2, 0, GLContext.CTX_PROFILE_ES|GLContext.CTX_OPTION_ANY); + } + if(hasGLES1Impl && null == GLContext.getAvailableGLVersion(device, 1, GLContext.CTX_PROFILE_ES)) { + // nobody yet set the available desktop versions, see {@link GLContextImpl#makeCurrent}, + // so we have to add the usual suspect + GLContext.mapAvailableGLVersion(device, + 1, GLContext.CTX_PROFILE_ES, + 1, 0, GLContext.CTX_PROFILE_ES|GLContext.CTX_OPTION_ANY); + } + addedEGLProfile = computeProfileMap(device, false /* desktopCtxUndef*/, false /* eglCtxUndef */); + } else { + setProfileMap(device, new HashMap()); // empty + if(DEBUG) { + System.err.println("GLProfile: EGLFactory - Device is not available: "+device); + } + } + + if(!GLContext.getAvailableGLVersionsSet(device)) { + GLContext.setAvailableGLVersionsSet(device); + } + + 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); + 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); + 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(GLDrawableFactoryImpl factory, AbstractGraphicsDevice device) { + 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() { + validateInitialization(); + return defaultDevice; + } + + public static AbstractGraphicsDevice getDefaultDesktopDevice() { + validateInitialization(); + return defaultDesktopDevice; + } + + public static AbstractGraphicsDevice getDefaultEGLDevice() { + validateInitialization(); + return defaultEGLDevice; + } + + private static void validateInitialization() { + if(!initialized) { + synchronized(GLProfile.class) { + if(!initialized) { + initSingleton(false); + } + } + } + } + + private static String array2String(String[] list) { + StringBuffer msg = new StringBuffer(); + 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(AbstractGraphicsDevice device, StringBuffer sb, int major, int profile) { + 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(AbstractGraphicsDevice device, boolean desktopCtxUndef, boolean eglCtxUndef) { + if (DEBUG) { + System.err.println("GLProfile.init map "+device.getConnection()+", desktopCtxUndef "+desktopCtxUndef+", eglCtxUndef "+eglCtxUndef); + } + GLProfile defaultGLProfile = null; + HashMap/*<String, GLProfile>*/ _mappedProfiles = new HashMap(GL_PROFILE_LIST_ALL.length + 1 /* default */); + for(int i=0; i<GL_PROFILE_LIST_ALL.length; i++) { + String profile = GL_PROFILE_LIST_ALL[i]; + String profileImpl = computeProfileImpl(device, profile, desktopCtxUndef, eglCtxUndef); + if(null!=profileImpl) { + GLProfile glProfile = new GLProfile(profile, profileImpl); + _mappedProfiles.put(profile, glProfile); + if (DEBUG) { + System.err.println("GLProfile.init map "+glProfile+" on devide "+device.getConnection()); + } + if(null==defaultGLProfile) { + defaultGLProfile=glProfile; + if (DEBUG) { + System.err.println("GLProfile.init map default "+glProfile+" on device "+device.getConnection()); + } + } + } else { + if (DEBUG) { + System.err.println("GLProfile.init map *** no mapping for "+profile+" on device "+device.getConnection()); + } + } + } + if(null!=defaultGLProfile) { + _mappedProfiles.put(GL_DEFAULT, defaultGLProfile); + } + setProfileMap(device, _mappedProfiles); + return _mappedProfiles.size() > 0; + } + + /** + * Returns the profile implementation + */ + private static String computeProfileImpl(AbstractGraphicsDevice device, String profile, boolean desktopCtxUndef, boolean eglCtxUndef) { + if (GL2ES1.equals(profile)) { + if(hasGL234Impl) { + if(desktopCtxUndef || GLContext.isGL2Available(device)) { + return GL2; + } else if(GLContext.isGL3bcAvailable(device)) { + return GL3bc; + } else if(GLContext.isGL4bcAvailable(device)) { + return GL4bc; + } + } + if(hasGLES1Impl && ( eglCtxUndef || GLContext.isGLES1Available(device))) { + return GLES1; + } + } else if (GL2ES2.equals(profile)) { + if(hasGL234Impl) { + if(desktopCtxUndef || GLContext.isGL2Available(device)) { + return GL2; + } else if(GLContext.isGL3Available(device)) { + return GL3; + } else if(GLContext.isGL4Available(device)) { + return GL4; + } + } + if(hasGLES2Impl && ( eglCtxUndef || GLContext.isGLES2Available(device))) { + return GLES2; + } + } else if(GL2GL3.equals(profile)) { + if(hasGL234Impl) { + if(desktopCtxUndef || GLContext.isGL2Available(device)) { + return GL2; + } else if(GLContext.isGL3bcAvailable(device)) { + return GL3bc; + } else if(GLContext.isGL4bcAvailable(device)) { + return GL4bc; + } else if(GLContext.isGL3Available(device)) { + return GL3; + } else if(GLContext.isGL4Available(device)) { + return GL4; + } + } + } else if(GL4bc.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4bcAvailable(device))) { + return GL4bc; + } else if(GL4.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4Available(device))) { + return GL4; + } else if(GL3bc.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3bcAvailable(device))) { + return GL3bc; + } else if(GL3.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3Available(device))) { + return GL3; + } else if(GL2.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL2Available(device))) { + return GL2; + } else if(GLES2.equals(profile) && hasGLES2Impl && ( eglCtxUndef || GLContext.isGLES2Available(device))) { + return GLES2; + } else if(GLES1.equals(profile) && hasGLES1Impl && ( eglCtxUndef || GLContext.isGLES1Available(device))) { + return GLES1; + } + return null; + } + + private static String getGLImplBaseClassName(String profileImpl) { + if ( GL4bc.equals(profileImpl) || + GL4.equals(profileImpl) || + GL3bc.equals(profileImpl) || + GL3.equals(profileImpl) || + GL2.equals(profileImpl) ) { + return "jogamp.opengl.gl4.GL4bc"; + } else if(GLES1.equals(profileImpl) || GL2ES1.equals(profileImpl)) { + return "jogamp.opengl.es1.GLES1"; + } else if(GLES2.equals(profileImpl) || GL2ES2.equals(profileImpl)) { + return "jogamp.opengl.es2.GLES2"; + } else { + throw new GLException("unsupported profile \"" + profileImpl + "\""); + } + } + + private static /*final*/ HashMap/*<device_connection, HashMap<GL-String, GLProfile>*/ deviceConn2ProfileMap = new HashMap(); + + /** + * 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' + * @return the GLProfile HashMap + */ + private static HashMap getProfileMap(AbstractGraphicsDevice device) { + validateInitialization(); + if(null==device) { + device = defaultDevice; + } + String deviceKey = device.getUniqueID(); + HashMap map = (HashMap) deviceConn2ProfileMap.get(deviceKey); + if(null==map) { + initProfilesForDevice(device); + if( null == deviceConn2ProfileMap.get(deviceKey) ) { + throw new InternalError("initProfilesForDevice(..) didn't issue setProfileMap(..) on "+device); + } + } + return map; + } + + private static void setProfileMap(AbstractGraphicsDevice device, HashMap/*<GL-String, GLProfile>*/mappedProfiles) { + validateInitialization(); + synchronized ( deviceConn2ProfileMap ) { + deviceConn2ProfileMap.put(device.getUniqueID(), mappedProfiles); + } + } + + private GLProfile(String profile, String profileImpl) { + this.profile = profile; + this.profileImpl = profileImpl; + } + + private String profileImpl = null; + private String profile = null; +} diff --git a/src/jogl/classes/javax/media/opengl/GLRunnable.java b/src/jogl/classes/javax/media/opengl/GLRunnable.java new file mode 100644 index 000000000..de0f5df48 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLRunnable.java @@ -0,0 +1,47 @@ +/** + * 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 javax.media.opengl; + +/** + * <p> + * Declares one-shot OpenGL commands usable for injection into a {@link GLAutoDrawable},<br> + * via {@link GLAutoDrawable#invoke(boolean, javax.media.opengl.GLRunnable)}.<br> + * {@link GLAutoDrawable} executes these commands within it's {@link GLAutoDrawable#display()} + * method while the OpenGL context is current.<br> + * <p> + * This might be useful to inject OpenGL commands from an I/O event listener. + */ +public interface GLRunnable { + /** + * Called by the drawable to initiate one-shot OpenGL commands by the + * client, like {@link GLEventListener#display(GLAutoDrawable)}. + */ + void run(GLAutoDrawable drawable); +} + diff --git a/src/jogl/classes/javax/media/opengl/GLUniformData.java b/src/jogl/classes/javax/media/opengl/GLUniformData.java new file mode 100644 index 000000000..9b0d5f151 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/GLUniformData.java @@ -0,0 +1,154 @@ + +package javax.media.opengl; + +import java.nio.*; + +public class GLUniformData { + + /** + * int atom + * + * Number of objects is 1 + * + */ + public GLUniformData(String name, int val) { + init(name, 1, new Integer(val)); + } + + /** + * float atom + * + * Number of objects is 1 + * + */ + public GLUniformData(String name, float val) { + init(name, 1, new Float(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(String name, int components, IntBuffer data) { + init(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(String name, int components, FloatBuffer data) { + init(name, components, data); + } + + /** + * 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(String name, int rows, int columns, FloatBuffer data) { + init(name, rows, columns, data); + } + + public void setData(int data) { init(new Integer(data)); } + public void setData(float data) { init(new Float(data)); } + public void setData(IntBuffer data) { init(data); } + public void setData(FloatBuffer data) { init(data); } + + 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 String toString() { + return "GLUniformData[name "+name+ + ", location "+location+ + ", size "+rows+"*"+columns+ + ", count "+count+ + ", matrix "+isMatrix+ + ", data "+data+ + "]"; + } + + private void init(String name, int rows, int columns, Object data) { + 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; + init(data); + } + + private void init(String name, int components, 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; + init(data); + } + + private void init(Object data) { + if(data instanceof Buffer) { + int sz = rows*columns; + Buffer buffer = (Buffer)data; + if(buffer.limit()<sz || 0!=buffer.limit()%sz) { + throw new GLException("data buffer size invalid: new buffer limit: "+buffer.limit()+"\n\t"+this); + } + this.count=buffer.limit()/(rows*columns); + } else { + if(isMatrix) { + throw new GLException("Atom type not allowed for matrix : "+this); + } + this.count=1; + } + this.data=data; + } + + public String getName() { return name; } + + public int getLocation() { return location; } + + /** + * Sets the determined location of the shader uniform. + */ + public void setLocation(int location) { this.location=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/javax/media/opengl/Threading.java b/src/jogl/classes/javax/media/opengl/Threading.java new file mode 100644 index 000000000..d0f3ebb93 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/Threading.java @@ -0,0 +1,166 @@ +/* + * 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 javax.media.opengl; + +import jogamp.opengl.*; + +/** 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>opengl.1thread</code>. Valid values + for this system property are: + + <PRE> + -Dopengl.1thread=false Disable single-threading of OpenGL work + -Dopengl.1thread=true Enable single-threading of OpenGL work (default -- on a newly-created worker thread) + -Dopengl.1thread=auto Select default single-threading behavior (currently on) + -Dopengl.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) + -Dopengl.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 { + + /** No reason to ever instantiate this class */ + private Threading() {} + + /** If an implementation of the javax.media.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, GLJPanel and + GLPbuffer. 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 void disableSingleThreading() { + ThreadingImpl.disableSingleThreading(); + } + + /** Indicates whether OpenGL work is being automatically forced to a + single thread in this implementation. */ + public static boolean isSingleThreaded() { + return ThreadingImpl.isSingleThreaded(); + } + + /** Indicates whether the current thread is the single thread on + which this implementation of the javax.media.opengl APIs + performs all of its OpenGL-related work. This method should only + be called if the single-thread model is in effect. */ + public static boolean isOpenGLThread() throws GLException { + return ThreadingImpl.isOpenGLThread(); + } + + /** Executes the passed Runnable on the single thread used for all + OpenGL work in this javax.media.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 void invokeOnOpenGLThread(Runnable r) throws GLException { + ThreadingImpl.invokeOnOpenGLThread(r); + } +} diff --git a/src/jogl/classes/javax/media/opengl/awt/AWTGLAutoDrawable.java b/src/jogl/classes/javax/media/opengl/awt/AWTGLAutoDrawable.java new file mode 100644 index 000000000..d1e725b00 --- /dev/null +++ b/src/jogl/classes/javax/media/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 javax.media.opengl.awt; + +import javax.media.opengl.*; + +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/javax/media/opengl/awt/ComponentEvents.java b/src/jogl/classes/javax/media/opengl/awt/ComponentEvents.java new file mode 100644 index 000000000..0c4f63c2d --- /dev/null +++ b/src/jogl/classes/javax/media/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 javax.media.opengl.awt; + +import javax.media.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/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java new file mode 100644 index 000000000..4076dac54 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -0,0 +1,1074 @@ +/* + * 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 javax.media.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.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.geom.Rectangle2D; + +import java.awt.EventQueue; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.List; + +import javax.media.nativewindow.WindowClosingProtocol; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.awt.AWTGraphicsConfiguration; +import javax.media.nativewindow.awt.AWTGraphicsDevice; +import javax.media.nativewindow.awt.AWTGraphicsScreen; +import javax.media.nativewindow.awt.AWTWindowClosingProtocol; + +import javax.media.opengl.GL; +import javax.media.opengl.GLAnimatorControl; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLCapabilitiesChooser; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; +import javax.media.opengl.GLRunnable; +import javax.media.opengl.Threading; + +import com.jogamp.nativewindow.NativeWindowVersion; +import com.jogamp.common.GlueGenVersion; +import com.jogamp.common.util.VersionUtil; +import com.jogamp.opengl.JoglVersion; + +import com.jogamp.common.util.locks.RecursiveLock; +import jogamp.opengl.Debug; +import jogamp.opengl.GLContextImpl; +import jogamp.opengl.GLDrawableHelper; +import jogamp.opengl.ThreadingImpl; + +// 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="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> + */ + +public class GLCanvas extends Canvas implements AWTGLAutoDrawable, WindowClosingProtocol { + + private static final boolean DEBUG; + + static { + DEBUG = Debug.debug("GLCanvas"); + } + + private GLDrawableHelper drawableHelper = new GLDrawableHelper(); + private AWTGraphicsConfiguration awtConfig; + private GLDrawable drawable; + private GLContextImpl context; + private boolean sendReshape = false; + + // copy of the cstr args, mainly for recreation + private GLCapabilitiesImmutable capsReqUser; + private GLCapabilitiesChooser chooser; + private GLContext shareWith; + private GraphicsDevice device; + + private AWTWindowClosingProtocol awtWindowClosingProtocol = + new AWTWindowClosingProtocol(this, new Runnable() { + public void run() { + GLCanvas.this.destroy(); + } + }); + + /** Creates a new GLCanvas component with a default set of OpenGL + capabilities, using the default OpenGL capabilities selection + mechanism, on the default screen device. */ + public GLCanvas() { + 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. + * @see GLCanvas#GLCanvas(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, javax.media.opengl.GLContext, java.awt.GraphicsDevice) + */ + public GLCanvas(GLCapabilitiesImmutable capsReqUser) { + this(capsReqUser, null, null, 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. + * This constructor variant also supports using a shared GLContext. + * + * @see GLCanvas#GLCanvas(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, javax.media.opengl.GLContext, java.awt.GraphicsDevice) + */ + public GLCanvas(GLCapabilitiesImmutable capsReqUser, GLContext shareWith) { + this(capsReqUser, null, shareWith, 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 + GLContext specifies an OpenGL context with which to share + textures, display lists and other OpenGL state, and may be null + if sharing is not desired. See the note in the overview + documentation on <a + href="../../../overview-summary.html#SHARING">context + sharing</a>. 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. */ + public GLCanvas(GLCapabilitiesImmutable capsReqUser, + GLCapabilitiesChooser chooser, + GLContext shareWith, + GraphicsDevice device) { + /* + * 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) { + capsReqUser = new GLCapabilities(GLProfile.getDefault(GLProfile.getDefaultDesktopDevice())); + } else { + // don't allow the user to change data + capsReqUser = (GLCapabilitiesImmutable) capsReqUser.cloneMutable(); + } + + if(null==device) { + GraphicsConfiguration gc = super.getGraphicsConfiguration(); + if(null!=gc) { + device = gc.getDevice(); + } + } + + // instantiation will be issued in addNotify() + this.capsReqUser = capsReqUser; + this.chooser = chooser; + this.shareWith = shareWith; + this.device = device; + } + + /** + * 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(); + /* + * 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 = awtConfig.getGraphicsConfiguration(); + + 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. + */ + AWTGraphicsConfiguration config = chooseGraphicsConfiguration( (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities(), + (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities(), + chooser, gc.getDevice()); + final GraphicsConfiguration compatible = (null!=config)?config.getGraphicsConfiguration():null; + boolean equalCaps = config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities()); + if(DEBUG) { + Exception e = new Exception("Info: Call Stack: "+Thread.currentThread().getName()); + e.printStackTrace(); + 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); + } + + if (compatible != null) { + /* + * Save the new GC for equals test above, and to return to + * any outside callers of this method. + */ + chosen = compatible; + + awtConfig = config; + + if( !equalCaps && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) { + dispose(true); + } + } + } + + /* + * 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; + } + + public GLContext createContext(GLContext shareWith) { + drawableSync.lock(); + try { + return (null != drawable) ? drawable.createContext(shareWith) : null; + } finally { + drawableSync.unlock(); + } + } + + public void setRealized(boolean realized) { + } + + public boolean isRealized() { + drawableSync.lock(); + try { + return ( null != drawable ) ? drawable.isRealized() : false; + } finally { + drawableSync.unlock(); + } + } + + public int getDefaultCloseOperation() { + return awtWindowClosingProtocol.getDefaultCloseOperation(); + } + + public int setDefaultCloseOperation(int op) { + return awtWindowClosingProtocol.setDefaultCloseOperation(op); + } + + public void display() { + if( !validateGLDrawable() ) { + if(DEBUG) { + System.err.println("Info: GLCanvas display - skipped GL render, drawable not valid yet"); + } + return; // not yet available .. + } + maybeDoSingleThreadedWorkaround(displayOnEventDispatchThreadAction, + displayAction); + + awtWindowClosingProtocol.addClosingListenerOneShot(); + } + + private void dispose(boolean regenerate) { + drawableSync.lock(); + try { + if(DEBUG) { + Exception ex1 = new Exception("Info: dispose("+regenerate+") - start, hasContext " + + (null!=context) + ", hasDrawable " + (null!=drawable)); + ex1.printStackTrace(); + } + + if(null!=context) { + boolean animatorPaused = false; + GLAnimatorControl animator = getAnimator(); + if(null!=animator) { + // can't remove us from animator for recreational addNotify() + animatorPaused = animator.pause(); + } + + disposeRegenerate=regenerate; + + if (Threading.isSingleThreaded() && + !Threading.isOpenGLThread()) { + // Workaround for termination issues with applets -- + // sun.applet.AppletPanel should probably be performing the + // remove() call on the EDT rather than on its own thread + // Hint: User should run remove from EDT. + if (ThreadingImpl.isAWTMode() && + Thread.holdsLock(getTreeLock())) { + // The user really should not be invoking remove() from this + // thread -- but since he/she is, we can not go over to the + // EDT at this point. Try to destroy the context from here. + if(context.isCreated()) { + drawableHelper.invokeGL(drawable, context, disposeAction, null); + } + } else if(context.isCreated()) { + Threading.invokeOnOpenGLThread(disposeOnEventDispatchThreadAction); + } + } else if(context.isCreated()) { + drawableHelper.invokeGL(drawable, context, disposeAction, null); + } + + if(animatorPaused) { + animator.resume(); + } + } + if(!regenerate) { + disposeAbstractGraphicsDevice(); + } + + if(DEBUG) { + System.err.println("dispose("+regenerate+") - stop"); + } + } finally { + drawableSync.unlock(); + } + } + + /** + * Just an alias for removeNotify + */ + public void destroy() { + removeNotify(); + } + + /** 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. <P> + + <B>Overrides:</B> + <DL><DD><CODE>paint</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ + @Override + public void paint(Graphics g) { + if (Beans.isDesignTime()) { + // Make GLCanvas behave better in NetBeans GUI builder + g.setColor(Color.BLACK); + g.fillRect(0, 0, getWidth(), getHeight()); + FontMetrics fm = g.getFontMetrics(); + String name = getName(); + if (name == null) { + name = getClass().getName(); + int idx = name.lastIndexOf('.'); + if (idx >= 0) { + name = name.substring(idx + 1); + } + } + Rectangle2D bounds = fm.getStringBounds(name, g); + g.setColor(Color.WHITE); + g.drawString(name, + (int) ((getWidth() - bounds.getWidth()) / 2), + (int) ((getHeight() + bounds.getHeight()) / 2)); + return; + } + if( ! this.drawableHelper.isExternalAnimatorAnimating() ) { + display(); + } + } + + RecursiveLock drawableSync = new RecursiveLock(); + + /** 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> */ + @Override + public void addNotify() { + if(DEBUG) { + Exception ex1 = new Exception(Thread.currentThread().getName()+" - Info: addNotify - start, bounds: "+this.getBounds()); + ex1.printStackTrace(); + } + + drawableSync.lock(); + try { + /** + * '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"); + } + + if (!Beans.isDesignTime()) { + // no lock required, since this resource ain't available yet + drawable = GLDrawableFactory.getFactory(capsReqUser.getGLProfile()) + .createGLDrawable(NativeWindowFactory.getNativeWindow(this, awtConfig)); + context = (GLContextImpl) drawable.createContext(shareWith); + context.setSynchronized(true); + } + + // before native peer is valid: X11 + disableBackgroundErase(); + + // issues getGraphicsConfiguration() and creates the native peer + super.addNotify(); + + // after native peer is valid: Windows + disableBackgroundErase(); + + // init drawable by paint/display makes the init sequence more equal + // for all launch flavors (applet/javaws/..) + // validateGLDrawable(); + + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - Info: addNotify - end: peer: "+getPeer()); + } + } finally { + drawableSync.unlock(); + } + } + + private boolean validateGLDrawable() { + boolean realized = false; + if (!Beans.isDesignTime()) { + drawableSync.lock(); + try { + if ( null != drawable ) { + realized = drawable.isRealized(); + if ( !realized && 0 < drawable.getWidth() * drawable.getHeight() ) { + drawable.setRealized(true); + realized = true; + sendReshape=true; // ensure a reshape is being send .. + if(DEBUG) { + String msg = Thread.currentThread().getName()+" - Realized Drawable: "+drawable.toString(); + // System.err.println(msg); + Throwable t = new Throwable(msg); + t.printStackTrace(); + } + } + } + } finally { + drawableSync.unlock(); + } + } + return realized; + } + + /** <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> */ + @Override + public void removeNotify() { + if(DEBUG) { + Exception ex1 = new Exception(Thread.currentThread().getName()+" - Info: removeNotify - start"); + ex1.printStackTrace(); + } + + awtWindowClosingProtocol.removeClosingListener(); + + if (Beans.isDesignTime()) { + super.removeNotify(); + } else { + drawableSync.lock(); + try { + dispose(false); + } finally { + context=null; + drawable=null; + awtConfig=null; + super.removeNotify(); + drawableSync.unlock(); + } + } + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - 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> */ + @Override + public void reshape(int x, int y, int width, int height) { + super.reshape(x, y, width, height); + sendReshape = true; + } + + /** <B>Overrides:</B> + <DL><DD><CODE>update</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ + /** + * Overridden from Canvas to prevent the AWT's clearing of the + * canvas from interfering with the OpenGL rendering. + */ + @Override + public void update(Graphics g) { + paint(g); + } + + public void addGLEventListener(GLEventListener listener) { + drawableHelper.addGLEventListener(listener); + } + + public void addGLEventListener(int index, GLEventListener listener) { + drawableHelper.addGLEventListener(index, listener); + } + + public void removeGLEventListener(GLEventListener listener) { + drawableHelper.removeGLEventListener(listener); + } + + public void setAnimator(GLAnimatorControl animatorControl) { + drawableHelper.setAnimator(animatorControl); + } + + public GLAnimatorControl getAnimator() { + return drawableHelper.getAnimator(); + } + + public void invoke(boolean wait, GLRunnable glRunnable) { + drawableHelper.invoke(this, wait, glRunnable); + } + + public void setContext(GLContext ctx) { + context=(GLContextImpl)ctx; + } + + public GLContext getContext() { + return context; + } + + public GL getGL() { + if (Beans.isDesignTime()) { + return null; + } + GLContext ctx = getContext(); + return (ctx == null) ? null : ctx.getGL(); + } + + public GL setGL(GL gl) { + GLContext ctx = getContext(); + if (ctx != null) { + ctx.setGL(gl); + return gl; + } + return null; + } + + + public void setAutoSwapBufferMode(boolean onOrOff) { + drawableHelper.setAutoSwapBufferMode(onOrOff); + } + + public boolean getAutoSwapBufferMode() { + return drawableHelper.getAutoSwapBufferMode(); + } + + public void swapBuffers() { + maybeDoSingleThreadedWorkaround(swapBuffersOnEventDispatchThreadAction, swapBuffersAction); + } + + public GLProfile getGLProfile() { + return capsReqUser.getGLProfile(); + } + + public GLCapabilitiesImmutable getChosenGLCapabilities() { + if (awtConfig == null) { + throw new GLException("No AWTGraphicsConfiguration: "+this); + } + + return (GLCapabilitiesImmutable)awtConfig.getChosenCapabilities(); + } + + public GLCapabilitiesImmutable getRequestedGLCapabilities() { + if (awtConfig == null) { + return capsReqUser; + } + + return (GLCapabilitiesImmutable)awtConfig.getRequestedCapabilities(); + } + + public NativeSurface getNativeSurface() { + drawableSync.lock(); + try { + return (null != drawable) ? drawable.getNativeSurface() : null; + } finally { + drawableSync.unlock(); + } + } + + public long getHandle() { + drawableSync.lock(); + try { + return (null != drawable) ? drawable.getHandle() : 0; + } finally { + drawableSync.unlock(); + } + } + + public GLDrawableFactory getFactory() { + drawableSync.lock(); + try { + return (null != drawable) ? drawable.getFactory() : null; + } finally { + drawableSync.unlock(); + } + } + + @Override + public String toString() { + final int dw = (null!=drawable) ? drawable.getWidth() : -1; + final int dh = (null!=drawable) ? drawable.getHeight() : -1; + + return "AWT-GLCanvas[Realized "+isRealized()+ + ",\n\t"+((null!=drawable)?drawable.getClass().getName():"null-drawable")+ + ",\n\tRealized "+isRealized()+ + ",\n\tFactory "+getFactory()+ + ",\n\thandle 0x"+Long.toHexString(getHandle())+ + ",\n\tDrawable size "+dw+"x"+dh+ + ",\n\tAWT pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ + ",\n\tvisible "+isVisible()+ + ",\n\t"+awtConfig+"]"; + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private void maybeDoSingleThreadedWorkaround(Runnable eventDispatchThreadAction, + Runnable invokeGLAction) { + if (Threading.isSingleThreaded() && + !Threading.isOpenGLThread()) { + Threading.invokeOnOpenGLThread(eventDispatchThreadAction); + } else { + drawableHelper.invokeGL(drawable, context, invokeGLAction, initAction); + } + } + + class DisposeAction implements Runnable { + public void run() { + drawableHelper.dispose(GLCanvas.this); + + if(null!=context) { + context.makeCurrent(); // implicit wait for lock .. + context.destroy(); + context=null; + } + + if(null!=drawable) { + drawable.setRealized(false); + drawable=null; + } + + if(disposeRegenerate) { + // recreate GLDrawable to reflect it's new graphics configuration + drawable = GLDrawableFactory.getFactory(capsReqUser.getGLProfile()) + .createGLDrawable(NativeWindowFactory.getNativeWindow(GLCanvas.this, awtConfig)); + if(DEBUG) { + System.err.println("GLCanvas.dispose(true): new drawable: "+drawable); + } + drawable.setRealized(true); + context = (GLContextImpl) drawable.createContext(shareWith); + context.setSynchronized(true); + sendReshape=true; // ensure a reshape is being send .. + } + } + } + private boolean disposeRegenerate; + private DisposeAction disposeAction = new DisposeAction(); + + private DisposeOnEventDispatchThreadAction disposeOnEventDispatchThreadAction = + new DisposeOnEventDispatchThreadAction(); + + class DisposeOnEventDispatchThreadAction implements Runnable { + public void run() { + drawableHelper.invokeGL(drawable, context, disposeAction, null); + } + } + + class DisposeAbstractGraphicsDeviceAction implements Runnable { + public void run() { + AbstractGraphicsConfiguration aconfig = (null!=awtConfig) ? awtConfig.getNativeGraphicsConfiguration() : null; + AbstractGraphicsScreen ascreen = (null!=aconfig) ? aconfig.getScreen() : null; + AbstractGraphicsDevice adevice = (null!=ascreen) ? ascreen.getDevice() : null; + if(null!=adevice) { + String adeviceMsg=null; + if(DEBUG) { + adeviceMsg = adevice.toString(); + } + boolean closed = adevice.close(); + if(DEBUG) { + System.err.println(Thread.currentThread().getName() + " - GLCanvas.dispose(false): closed GraphicsDevice: "+adeviceMsg+", result: "+closed); + } + } + awtConfig=null; + } + } + private DisposeAbstractGraphicsDeviceAction disposeAbstractGraphicsDeviceAction = new DisposeAbstractGraphicsDeviceAction(); + + /** + * Disposes the AbstractGraphicsDevice within EDT, + * since resources created (X11: Display), must be destroyed in the same thread, where they have been created. + * + * @see #chooseGraphicsConfiguration(javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesImmutable, javax.media.opengl.GLCapabilitiesChooser, java.awt.GraphicsDevice) + */ + void disposeAbstractGraphicsDevice() { + if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) { + disposeAbstractGraphicsDeviceAction.run(); + } else { + try { + EventQueue.invokeAndWait(disposeAbstractGraphicsDeviceAction); + } catch (InvocationTargetException e) { + throw new GLException(e.getTargetException()); + } catch (InterruptedException e) { + throw new GLException(e); + } + } + } + + class InitAction implements Runnable { + public void run() { + drawableHelper.init(GLCanvas.this); + } + } + private InitAction initAction = new InitAction(); + + class DisplayAction implements Runnable { + public void run() { + if (sendReshape) { + if(DEBUG) { + System.err.println(Thread.currentThread().getName()+" - reshape: "+getWidth()+"x"+getHeight()); + } + // Note: we ignore the given x and y within the parent component + // since we are drawing directly into this heavyweight component. + drawableHelper.reshape(GLCanvas.this, 0, 0, getWidth(), getHeight()); + sendReshape = false; + } + + drawableHelper.display(GLCanvas.this); + } + } + private DisplayAction displayAction = new DisplayAction(); + + class SwapBuffersAction implements Runnable { + public void run() { + drawable.swapBuffers(); + } + } + private SwapBuffersAction swapBuffersAction = new SwapBuffersAction(); + + // Workaround for ATI driver bugs related to multithreading issues + // like simultaneous rendering via Animators to canvases that are + // being resized on the AWT event dispatch thread + class DisplayOnEventDispatchThreadAction implements Runnable { + public void run() { + drawableHelper.invokeGL(drawable, context, displayAction, initAction); + } + } + private DisplayOnEventDispatchThreadAction displayOnEventDispatchThreadAction = + new DisplayOnEventDispatchThreadAction(); + class SwapBuffersOnEventDispatchThreadAction implements Runnable { + public void run() { + drawableHelper.invokeGL(drawable, context, swapBuffersAction, initAction); + } + } + private SwapBuffersOnEventDispatchThreadAction swapBuffersOnEventDispatchThreadAction = + new SwapBuffersOnEventDispatchThreadAction(); + + // 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() { + 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 (Exception e) { + clazz = clazz.getSuperclass(); + } + } + } catch (Exception e) { + } + return null; + } + }); + } catch (Exception e) { + } + disableBackgroundEraseInitialized = true; + if(DEBUG) { + System.err.println("GLCanvas: TK disableBackgroundErase method found: "+ + (null!=disableBackgroundEraseMethod)); + } + } + if (disableBackgroundEraseMethod != null) { + Throwable t=null; + try { + disableBackgroundEraseMethod.invoke(getToolkit(), new Object[] { this }); + } catch (Exception e) { + t = e; + } + if(DEBUG) { + System.err.println("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 #disposeAbstractGraphicsDevice() + */ + 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 = AWTGraphicsScreen.createScreenDevice(device, AbstractGraphicsDevice.DEFAULT_UNIT); + AWTGraphicsConfiguration config = null; + + if( EventQueue.isDispatchThread() || Thread.holdsLock(getTreeLock()) ) { + config = (AWTGraphicsConfiguration) + GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capsChosen, + capsRequested, + chooser, aScreen); + } else { + try { + final ArrayList bucket = new ArrayList(1); + EventQueue.invokeAndWait(new Runnable() { + public void run() { + AWTGraphicsConfiguration c = (AWTGraphicsConfiguration) + GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capsChosen, + capsRequested, + chooser, aScreen); + bucket.add(c); + } + }); + config = ( bucket.size() > 0 ) ? (AWTGraphicsConfiguration)bucket.get(0) : null ; + } catch (InvocationTargetException e) { + throw new GLException(e.getTargetException()); + } catch (InterruptedException e) { + throw new GLException(e); + } + } + + if (config == null) { + throw new GLException("Error: Couldn't fetch AWTGraphicsConfiguration"); + } + + return config; + } + + /** + * A most simple JOGL AWT test entry + */ + public static void main(String args[]) { + System.err.println(VersionUtil.getPlatformInfo()); + System.err.println(GlueGenVersion.getInstance()); + System.err.println(NativeWindowVersion.getInstance()); + System.err.println(JoglVersion.getInstance()); + + GLDrawableFactory factory = GLDrawableFactory.getDesktopFactory(); + List/*<GLCapabilitiesImmutable>*/ availCaps = factory.getAvailableCapabilities(null); + for(int i=0; i<availCaps.size(); i++) { + System.err.println(availCaps.get(i)); + } + + GLCapabilitiesImmutable caps = new GLCapabilities( GLProfile.getDefault(GLProfile.getDefaultDesktopDevice()) ); + Frame frame = new Frame("JOGL AWT Test"); + + GLCanvas glCanvas = new GLCanvas(caps); + frame.add(glCanvas); + frame.setSize(128, 128); + + glCanvas.addGLEventListener(new GLEventListener() { + public void init(GLAutoDrawable drawable) { + GL gl = drawable.getGL(); + System.err.println(JoglVersion.getGLInfo(gl, null)); + } + + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + } + + public void display(GLAutoDrawable drawable) { + } + + public void dispose(GLAutoDrawable drawable) { + } + }); + + final Frame _frame = frame; + final GLCanvas _glCanvas = glCanvas; + + try { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + _frame.setVisible(true); + }}); + } catch (Throwable t) { + t.printStackTrace(); + } + glCanvas.display(); + try { + javax.swing.SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + _frame.setVisible(false); + _frame.remove(_glCanvas); + _frame.dispose(); + }}); + } catch (Throwable t) { + t.printStackTrace(); + } + } + +} diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java new file mode 100644 index 000000000..d58ad0304 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -0,0 +1,1721 @@ +/* + * 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 javax.media.opengl.awt; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.beans.Beans; +import java.security.AccessControlContext; +import java.security.AccessController; + +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import javax.swing.JPanel; + +import javax.media.nativewindow.WindowClosingProtocol; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.awt.AWTWindowClosingProtocol; + +import javax.media.opengl.DefaultGLCapabilitiesChooser; +import javax.media.opengl.GL; +import javax.media.opengl.GL2; +import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLAnimatorControl; +import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLCapabilitiesChooser; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLDrawableFactory; +import javax.media.opengl.GLEventListener; +import javax.media.opengl.GLException; +import javax.media.opengl.GLPbuffer; +import javax.media.opengl.GLProfile; +import javax.media.opengl.GLRunnable; +import javax.media.opengl.Threading; +import com.jogamp.opengl.util.FBObject; +import jogamp.opengl.Debug; +import jogamp.opengl.GLContextImpl; +import jogamp.opengl.GLDrawableFactoryImpl; +import jogamp.opengl.GLDrawableHelper; +import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.ThreadingImpl; +import jogamp.opengl.awt.Java2D; +import jogamp.opengl.awt.Java2DGLContext; + +// FIXME: Subclasses need to call resetGLFunctionAvailability() on their +// context whenever the displayChanged() function is called on their +// GLEventListeners + +/** 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> + Notes specific to the Reference Implementation: This component + attempts to use hardware-accelerated rendering via pbuffers and + falls back on to software rendering if problems occur. + Note that because this component attempts to use pbuffers for + rendering, and because pbuffers can not be resized, somewhat + surprising behavior may occur during resize operations; the {@link + GLEventListener#init} method may be called multiple times as the + pbuffer is resized to be able to cover the size of the GLJPanel. + This behavior is correct, as the textures and display lists for + the GLJPanel will have been lost during the resize operation. The + application should attempt to make its GLEventListener.init() + methods as side-effect-free as possible. </P> + <P> + * Please read <A HREF="GLCanvas.html#java2dgl">Java2D OpenGL Remarks</A>. + * </P> +*/ + +public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosingProtocol { + private static final boolean DEBUG = Debug.debug("GLJPanel"); + private static final boolean VERBOSE = Debug.verbose(); + + private GLDrawableHelper drawableHelper = new GLDrawableHelper(); + private volatile boolean isInitialized; + + // Data used for either pbuffers or pixmap-based offscreen surfaces + private GLCapabilitiesImmutable offscreenCaps; + private GLProfile glProfile; + private GLDrawableFactoryImpl factory; + private GLCapabilitiesChooser chooser; + private GLContext shareWith; + // Width of the actual GLJPanel + private int panelWidth = 0; + private int panelHeight = 0; + // Lazy reshape notification + private boolean handleReshape = false; + private boolean sendReshape = true; + + // The backend in use + private Backend backend; + + // Used by all backends either directly or indirectly to hook up callbacks + private Updater updater = new Updater(); + + private static final AccessControlContext localACC = AccessController.getContext(); + + // Turns off the pbuffer-based backend (used by default, unless the + // Java 2D / OpenGL pipeline is in use) + private static boolean hardwareAccelerationDisabled = + Debug.isPropertyDefined("jogl.gljpanel.nohw", true, localACC); + + // Turns off the fallback to software-based rendering from + // pbuffer-based rendering + private static boolean softwareRenderingDisabled = + Debug.isPropertyDefined("jogl.gljpanel.nosw", true, localACC); + + // Indicates whether the Java 2D OpenGL pipeline is enabled + private boolean oglPipelineEnabled = + Java2D.isOGLPipelineActive() && + !Debug.isPropertyDefined("jogl.gljpanel.noogl", true, localACC); + + // For handling reshape events lazily + // private int reshapeX; + // private int reshapeY; + private int reshapeWidth; + private int reshapeHeight; + + // These are always set to (0, 0) except when the Java2D / OpenGL + // pipeline is active + private int viewportX; + private int viewportY; + + private AWTWindowClosingProtocol awtWindowClosingProtocol = + new AWTWindowClosingProtocol(this, new Runnable() { + public void run() { + GLJPanel.this.destroy(); + } + }); + + static { + // 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.isOGLPipelineActive() && Java2D.isFBOEnabled()) { + Java2D.getShareContext(GraphicsEnvironment. + getLocalGraphicsEnvironment(). + getDefaultScreenDevice()); + } + } + + /** Creates a new GLJPanel component with a default set of OpenGL + capabilities and using the default OpenGL capabilities selection + mechanism. */ + public GLJPanel() { + this(null); + } + + /** Creates a new GLJPanel component with the requested set of + OpenGL capabilities, using the default OpenGL capabilities + selection mechanism. */ + public GLJPanel(GLCapabilitiesImmutable userCapsRequest) { + this(userCapsRequest, null, 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. The passed + GLContext specifies an OpenGL context with which to share + textures, display lists and other OpenGL state, and may be null + if sharing is not desired. See the note in the overview documentation on + <a href="../../../overview-summary.html#SHARING">context sharing</a>. + <P> + Note: Sharing cannot be enabled using J2D OpenGL FBO sharing, + since J2D GL Context must be shared and we can only share one context. + */ + public GLJPanel(GLCapabilitiesImmutable userCapsRequest, GLCapabilitiesChooser chooser, GLContext shareWith) { + 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(null); + } + caps.setDoubleBuffered(false); + offscreenCaps = caps; + } + this.glProfile = offscreenCaps.getGLProfile(); + this.factory = GLDrawableFactoryImpl.getFactoryImpl(glProfile); + this.chooser = ((chooser != null) ? chooser : new DefaultGLCapabilitiesChooser()); + this.shareWith = shareWith; + } + + public void display() { + if (EventQueue.isDispatchThread()) { + // Want display() to be synchronous, so call paintImmediately() + paintImmediately(0, 0, getWidth(), getHeight()); + } else { + // Multithreaded redrawing of Swing components is not allowed, + // so do everything on the event dispatch thread + try { + EventQueue.invokeAndWait(paintImmediatelyAction); + } catch (Exception e) { + throw new GLException(e); + } + } + } + + protected void dispose(boolean regenerate) { + if(DEBUG) { + Exception ex1 = new Exception("Info: dispose("+regenerate+") - start"); + ex1.printStackTrace(); + } + + if (backend != null) { + boolean animatorPaused = false; + GLAnimatorControl animator = getAnimator(); + if(null!=animator) { + if(regenerate) { + animatorPaused = animator.pause(); + } else { + animator.remove(this); + } + } + + disposeRegenerate=regenerate; + disposeContext=backend.getContext(); + disposeDrawable=backend.getDrawable(); + + if (Threading.isSingleThreaded() && + !Threading.isOpenGLThread()) { + // Workaround for termination issues with applets -- + // sun.applet.AppletPanel should probably be performing the + // remove() call on the EDT rather than on its own thread + if (ThreadingImpl.isAWTMode() && + Thread.holdsLock(getTreeLock())) { + // The user really should not be invoking remove() from this + // thread -- but since he/she is, we can not go over to the + // EDT at this point. Try to destroy the context from here. + if(disposeContext.isCreated()) { + drawableHelper.invokeGL(disposeDrawable, disposeContext, disposeAction, null); + } + } else if(disposeContext.isCreated()) { + Threading.invokeOnOpenGLThread(disposeOnEventDispatchThreadAction); + } + } else if(disposeContext.isCreated()) { + drawableHelper.invokeGL(disposeDrawable, disposeContext, disposeAction, null); + } + + if(!regenerate) { + AbstractGraphicsDevice adevice = disposeDrawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getScreen().getDevice(); + String adeviceMsg=null; + if(DEBUG) { + adeviceMsg = adevice.toString(); + } + // boolean closed = adevice.close(); + boolean closed = false; + if (DEBUG) { + System.err.println("GLJPanel.dispose(false): closed GraphicsDevice: " + adeviceMsg + ", result: " + closed); + } + } + + backend.setContext(disposeContext); + if(null==disposeContext) { + isInitialized = false; + } + + if(animatorPaused) { + animator.resume(); + } + } + + if(DEBUG) { + System.err.println("dispose("+regenerate+") - stop"); + } + } + + /** + * Just an alias for removeNotify + */ + 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> + + <B>Overrides:</B> + <DL><DD><CODE>paintComponent</CODE> in class <CODE>javax.swing.JComponent</CODE></DD></DL> */ + 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()); + FontMetrics fm = g.getFontMetrics(); + String name = getName(); + if (name == null) { + name = getClass().getName(); + int idx = name.lastIndexOf('.'); + if (idx >= 0) { + name = name.substring(idx + 1); + } + } + Rectangle2D bounds = fm.getStringBounds(name, g); + g.setColor(Color.WHITE); + g.drawString(name, + (int) ((getWidth() - bounds.getWidth()) / 2), + (int) ((getHeight() + bounds.getHeight()) / 2)); + return; + } + + if (backend == null || !isInitialized) { + createAndInitializeBackend(); + } + + if (!isInitialized) { + 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 (handleReshape) { + handleReshape(); + } + + updater.setGraphics(g); + backend.doPaintComponent(g); + } + + /** 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> */ + public void addNotify() { + super.addNotify(); + if (DEBUG) { + System.err.println("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> + + <B>Overrides:</B> + <DL><DD><CODE>removeNotify</CODE> in class <CODE>java.awt.Component</CODE></DD></DL> */ + public void removeNotify() { + if(DEBUG) { + Exception ex1 = new Exception("Info: removeNotify - start"); + ex1.printStackTrace(); + } + + awtWindowClosingProtocol.removeClosingListener(); + + dispose(false); + if (backend != null) { + backend.destroy(); + backend = null; + } + isInitialized = false; + super.removeNotify(); + if(DEBUG) { + System.err.println("Info: removeNotify - end"); + } + } + + /** 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> */ + public void reshape(int x, int y, int width, int height) { + super.reshape(x, y, width, height); + + // reshapeX = x; + // reshapeY = y; + reshapeWidth = width; + reshapeHeight = height; + handleReshape = true; + } + + public void setOpaque(boolean opaque) { + if (backend != null) { + backend.setOpaque(opaque); + } + super.setOpaque(opaque); + } + + public void addGLEventListener(GLEventListener listener) { + drawableHelper.addGLEventListener(listener); + } + + public void addGLEventListener(int index, GLEventListener listener) { + drawableHelper.addGLEventListener(index, listener); + } + + public void removeGLEventListener(GLEventListener listener) { + drawableHelper.removeGLEventListener(listener); + } + + public void setAnimator(GLAnimatorControl animatorControl) { + drawableHelper.setAnimator(animatorControl); + } + + public GLAnimatorControl getAnimator() { + return drawableHelper.getAnimator(); + } + + public void invoke(boolean wait, GLRunnable glRunnable) { + drawableHelper.invoke(this, wait, glRunnable); + } + + public GLContext createContext(GLContext shareWith) { + return backend.createContext(shareWith); + } + + public void setRealized(boolean realized) { + } + + public boolean isRealized() { + return isInitialized; + } + + public void setContext(GLContext ctx) { + if (backend == null) { + return; + } + backend.setContext(ctx); + } + + public GLContext getContext() { + if (backend == null) { + return null; + } + return backend.getContext(); + } + + public GL getGL() { + if (Beans.isDesignTime()) { + return null; + } + GLContext context = getContext(); + return (context == null) ? null : context.getGL(); + } + + public GL setGL(GL gl) { + GLContext context = getContext(); + if (context != null) { + context.setGL(gl); + return gl; + } + return null; + } + + public void setAutoSwapBufferMode(boolean onOrOff) { + // In the current implementation this is a no-op. Both the pbuffer + // and pixmap based rendering paths use a single-buffered surface + // so swapping the buffers doesn't do anything. We also don't + // currently have the provision to skip copying the data to the + // Swing portion of the GLJPanel in any of the rendering paths. + } + + public boolean getAutoSwapBufferMode() { + // In the current implementation this is a no-op. Both the pbuffer + // and pixmap based rendering paths use a single-buffered surface + // so swapping the buffers doesn't do anything. We also don't + // currently have the provision to skip copying the data to the + // Swing portion of the GLJPanel in any of the rendering paths. + return true; + } + + public void swapBuffers() { + // In the current implementation this is a no-op. Both the pbuffer + // and pixmap based rendering paths use a single-buffered surface + // so swapping the buffers doesn't do anything. We also don't + // currently have the provision to skip copying the data to the + // Swing portion of the GLJPanel in any of the rendering paths. + } + + /** 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 oglPipelineEnabled; + } + + public GLCapabilitiesImmutable getChosenGLCapabilities() { + return backend.getChosenGLCapabilities(); + } + + public final GLProfile getGLProfile() { + return glProfile; + } + + public NativeSurface getNativeSurface() { + throw new GLException("FIXME"); + } + + public long getHandle() { + throw new GLException("FIXME"); + } + + public final GLDrawableFactory getFactory() { + return factory; + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private void createAndInitializeBackend() { + if (panelWidth == 0 || + panelHeight == 0) { + // See whether we have a non-zero size yet and can go ahead with + // initialization + if (reshapeWidth == 0 || + reshapeHeight == 0) { + return; + } + + // Pull down reshapeWidth and reshapeHeight into panelWidth and + // panelHeight eagerly in order to complete initialization, and + // force a reshape later + panelWidth = reshapeWidth; + panelHeight = reshapeHeight; + } + + do { + if (backend == null) { + if (oglPipelineEnabled) { + backend = new J2DOGLBackend(); + } else { + if (!hardwareAccelerationDisabled && + factory.canCreateGLPbuffer(null)) { + backend = new PbufferBackend(); + } else { + if (softwareRenderingDisabled) { + throw new GLException("Fallback to software rendering disabled by user"); + } + backend = new SoftwareBackend(); + } + } + } + + if (!isInitialized) { + backend.initialize(); + } + // The backend might set itself to null, indicating it punted to + // a different implementation -- try again + } while (backend == null); + + awtWindowClosingProtocol.addClosingListenerOneShot(); + } + + public int getDefaultCloseOperation() { + return awtWindowClosingProtocol.getDefaultCloseOperation(); + } + + public int setDefaultCloseOperation(int op) { + return awtWindowClosingProtocol.setDefaultCloseOperation(op); + } + + private void handleReshape() { + panelWidth = reshapeWidth; + panelHeight = reshapeHeight; + + if (DEBUG) { + System.err.println("GLJPanel.handleReshape: (w,h) = (" + + panelWidth + "," + panelHeight + ")"); + } + + sendReshape = true; + backend.handleReshape(); + handleReshape = false; + } + + // 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(Graphics g) { + this.g = g; + } + + public void init(GLAutoDrawable drawable) { + if (!backend.preGL(g)) { + return; + } + drawableHelper.init(GLJPanel.this); + backend.postGL(g, false); + } + + public void dispose(GLAutoDrawable drawable) { + drawableHelper.dispose(GLJPanel.this); + } + + public void display(GLAutoDrawable drawable) { + if (!backend.preGL(g)) { + return; + } + if (sendReshape) { + if (DEBUG||VERBOSE) { + System.err.println("display: reshape(" + viewportX + "," + viewportY + " " + panelWidth + "x" + panelHeight + ")"); + } + drawableHelper.reshape(GLJPanel.this, viewportX, viewportY, panelWidth, panelHeight); + sendReshape = false; + } + + drawableHelper.display(GLJPanel.this); + backend.postGL(g, true); + } + + public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { + // This is handled above and dispatched directly to the appropriate context + } + + public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) { + } + } + + public String toString() { + return "AWT-GLJPanel[ "+((null!=backend)?backend.getDrawable().getClass().getName():"null-drawable")+"]"; + } + + private boolean disposeRegenerate; + private GLContext disposeContext; + private GLDrawable disposeDrawable; + private DisposeAction disposeAction = new DisposeAction(); + + class DisposeAction implements Runnable { + public void run() { + updater.dispose(GLJPanel.this); + + if (null != disposeContext) { + disposeContext.destroy(); + disposeContext = null; + } + if (null != disposeDrawable) { + disposeDrawable.setRealized(false); + } + if (null != disposeDrawable) { + if (disposeRegenerate) { + disposeDrawable.setRealized(true); + disposeContext = (GLContextImpl) disposeDrawable.createContext(shareWith); + disposeContext.setSynchronized(true); + } + } + } + } + + private DisposeOnEventDispatchThreadAction disposeOnEventDispatchThreadAction = + new DisposeOnEventDispatchThreadAction(); + + class DisposeOnEventDispatchThreadAction implements Runnable { + public void run() { + drawableHelper.invokeGL(disposeDrawable, disposeContext, disposeAction, null); + } + } + + + class InitAction implements Runnable { + public void run() { + updater.init(GLJPanel.this); + } + } + private InitAction initAction = new InitAction(); + + class DisplayAction implements Runnable { + public void run() { + updater.display(GLJPanel.this); + } + } + private DisplayAction displayAction = new DisplayAction(); + + class PaintImmediatelyAction implements Runnable { + public void run() { + paintImmediately(0, 0, getWidth(), getHeight()); + } + } + private PaintImmediatelyAction paintImmediatelyAction = new PaintImmediatelyAction(); + + private int getNextPowerOf2(int number) { + // Workaround for problems where 0 width or height are transiently + // seen during layout + if (number == 0) { + return 2; + } + + if (((number-1) & number) == 0) { + //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0 + return number; + } + int power = 0; + while (number > 0) { + number = number>>1; + power++; + } + return (1<<power); + } + + private int getGLInteger(GL gl, int which) { + int[] tmp = new int[1]; + gl.glGetIntegerv(which, tmp, 0); + return tmp[0]; + } + + //---------------------------------------------------------------------- + // 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 { + // 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(); + + // 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 void 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); + + // 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); + } + + // 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 + abstract class AbstractReadbackBackend implements Backend { + // This image is exactly the correct size to render into the panel + protected BufferedImage offscreenImage; + // One of these is used to store the read back pixels before storing + // in the BufferedImage + protected ByteBuffer readBackBytes; + protected IntBuffer readBackInts; + protected int readBackWidthInPixels; + protected int readBackHeightInPixels; + + private int awtFormat; + private int glFormat; + private int glType; + + // For saving/restoring of OpenGL state during ReadPixels + private int[] swapbytes = new int[1]; + private int[] rowlength = new int[1]; + private int[] skiprows = new int[1]; + private int[] skippixels = new int[1]; + private int[] alignment = new int[1]; + + public void setOpaque(boolean opaque) { + if (opaque != isOpaque()) { + if (offscreenImage != null) { + offscreenImage.flush(); + offscreenImage = null; + } + } + } + + public boolean preGL(Graphics g) { + // Empty in this implementation + return true; + } + + public void postGL(Graphics g, boolean isDisplay) { + if (isDisplay) { + // Must now copy pixels from offscreen context into surface + if (offscreenImage == null) { + if (panelWidth > 0 && panelHeight > 0) { + // It looks like NVidia's drivers (at least the ones on my + // notebook) are buggy and don't allow a sub-rectangle to be + // read from a pbuffer...this doesn't really matter because + // it's the Graphics.drawImage() calls that are the + // bottleneck + + int awtFormat = 0; + + // Should be more flexible in these BufferedImage formats; + // perhaps see what the preferred image types are on the + // given platform + if (isOpaque()) { + awtFormat = BufferedImage.TYPE_INT_RGB; + } else { + awtFormat = BufferedImage.TYPE_INT_ARGB; + } + + offscreenImage = new BufferedImage(panelWidth, + panelHeight, + awtFormat); + switch (awtFormat) { + case BufferedImage.TYPE_3BYTE_BGR: + glFormat = GL2.GL_BGR; + glType = GL2.GL_UNSIGNED_BYTE; + readBackBytes = ByteBuffer.allocate(readBackWidthInPixels * readBackHeightInPixels * 3); + break; + + case BufferedImage.TYPE_INT_RGB: + case BufferedImage.TYPE_INT_ARGB: + glFormat = GL2.GL_BGRA; + glType = getGLPixelType(); + readBackInts = IntBuffer.allocate(readBackWidthInPixels * readBackHeightInPixels); + break; + + default: + // FIXME: Support more off-screen image types (current + // offscreen context implementations don't use others, and + // some of the OpenGL formats aren't supported in the 1.1 + // headers, which we're currently using) + throw new GLException("Unsupported offscreen image type " + awtFormat); + } + } + } + + if (offscreenImage != null) { + GL2 gl = getGL().getGL2(); + // Save current modes + gl.glGetIntegerv(GL2.GL_PACK_SWAP_BYTES, swapbytes, 0); + gl.glGetIntegerv(GL2.GL_PACK_ROW_LENGTH, rowlength, 0); + gl.glGetIntegerv(GL2.GL_PACK_SKIP_ROWS, skiprows, 0); + gl.glGetIntegerv(GL2.GL_PACK_SKIP_PIXELS, skippixels, 0); + gl.glGetIntegerv(GL2.GL_PACK_ALIGNMENT, alignment, 0); + + gl.glPixelStorei(GL2.GL_PACK_SWAP_BYTES, GL.GL_FALSE); + gl.glPixelStorei(GL2.GL_PACK_ROW_LENGTH, readBackWidthInPixels); + gl.glPixelStorei(GL2.GL_PACK_SKIP_ROWS, 0); + gl.glPixelStorei(GL2.GL_PACK_SKIP_PIXELS, 0); + gl.glPixelStorei(GL2.GL_PACK_ALIGNMENT, 1); + + // Actually read the pixels. + gl.glReadBuffer(GL2.GL_FRONT); + if (readBackBytes != null) { + gl.glReadPixels(0, 0, readBackWidthInPixels, readBackHeightInPixels, glFormat, glType, readBackBytes); + } else if (readBackInts != null) { + gl.glReadPixels(0, 0, readBackWidthInPixels, readBackHeightInPixels, glFormat, glType, readBackInts); + } + + // Restore saved modes. + gl.glPixelStorei(GL2.GL_PACK_SWAP_BYTES, swapbytes[0]); + gl.glPixelStorei(GL2.GL_PACK_ROW_LENGTH, rowlength[0]); + gl.glPixelStorei(GL2.GL_PACK_SKIP_ROWS, skiprows[0]); + gl.glPixelStorei(GL2.GL_PACK_SKIP_PIXELS, skippixels[0]); + gl.glPixelStorei(GL2.GL_PACK_ALIGNMENT, alignment[0]); + + if (readBackBytes != null || readBackInts != null) { + // Copy temporary data into raster of BufferedImage for faster + // blitting Note that we could avoid this copy in the cases + // where !offscreenContext.offscreenImageNeedsVerticalFlip(), + // but that's the software rendering path which is very slow + // anyway + Object src = null; + Object dest = null; + int srcIncr = 0; + int destIncr = 0; + + if (readBackBytes != null) { + src = readBackBytes.array(); + dest = ((DataBufferByte) offscreenImage.getRaster().getDataBuffer()).getData(); + srcIncr = readBackWidthInPixels * 3; + destIncr = offscreenImage.getWidth() * 3; + } else { + src = readBackInts.array(); + dest = ((DataBufferInt) offscreenImage.getRaster().getDataBuffer()).getData(); + srcIncr = readBackWidthInPixels; + destIncr = offscreenImage.getWidth(); + } + + if (flipVertically()) { + int srcPos = 0; + int destPos = (offscreenImage.getHeight() - 1) * destIncr; + for (; destPos >= 0; srcPos += srcIncr, destPos -= destIncr) { + System.arraycopy(src, srcPos, dest, destPos, destIncr); + } + } else { + int srcPos = 0; + int destEnd = destIncr * offscreenImage.getHeight(); + for (int destPos = 0; destPos < destEnd; srcPos += srcIncr, destPos += destIncr) { + System.arraycopy(src, srcPos, dest, destPos, destIncr); + } + } + + // Note: image will be drawn back in paintComponent() for + // correctness on all platforms + } + } + } + } + + public void doPaintComponent(Graphics g) { + doPaintComponentImpl(); + if (offscreenImage != null) { + // Draw resulting image in one shot + g.drawImage(offscreenImage, 0, 0, + offscreenImage.getWidth(), + offscreenImage.getHeight(), + GLJPanel.this); + } + } + + protected abstract void doPaintComponentImpl(); + protected abstract int getGLPixelType(); + protected abstract boolean flipVertically(); + } + + class SoftwareBackend extends AbstractReadbackBackend { + // Implementation using software rendering + private GLDrawableImpl offscreenDrawable; + private GLContextImpl offscreenContext; + + public void initialize() { + // Fall-through path: create an offscreen context instead + offscreenDrawable = (GLDrawableImpl) factory.createOffscreenDrawable( + null /* default platform device */, + offscreenCaps, + chooser, + Math.max(1, panelWidth), + Math.max(1, panelHeight)); + offscreenContext = (GLContextImpl) offscreenDrawable.createContext(shareWith); + offscreenContext.setSynchronized(true); + isInitialized = true; + } + + public void destroy() { + if (offscreenContext != null) { + offscreenContext.destroy(); + offscreenContext = null; + } + if (offscreenDrawable != null) { + offscreenDrawable.destroy(); + offscreenDrawable = null; + } + } + + public GLContext createContext(GLContext shareWith) { + return offscreenDrawable.createContext(shareWith); + } + + public void setContext(GLContext ctx) { + offscreenContext=(GLContextImpl)ctx; + } + + public GLContext getContext() { + return offscreenContext; + } + + public GLDrawable getDrawable() { + return offscreenDrawable; + } + + public GLCapabilitiesImmutable getChosenGLCapabilities() { + if (offscreenDrawable == null) { + return null; + } + return offscreenDrawable.getChosenGLCapabilities(); + } + + public GLProfile getGLProfile() { + if (offscreenDrawable == null) { + return null; + } + return offscreenDrawable.getGLProfile(); + } + + public void handleReshape() { + destroy(); + initialize(); + readBackWidthInPixels = Math.max(1, panelWidth); + readBackHeightInPixels = Math.max(1, panelHeight); + + if (offscreenImage != null) { + offscreenImage.flush(); + offscreenImage = null; + } + } + + protected void doPaintComponentImpl() { + drawableHelper.invokeGL(offscreenDrawable, offscreenContext, displayAction, initAction); + } + + protected int getGLPixelType() { + return offscreenContext.getOffscreenContextPixelDataType(); + } + + protected boolean flipVertically() { + return offscreenContext.offscreenImageNeedsVerticalFlip(); + } + } + + class PbufferBackend extends AbstractReadbackBackend { + private GLPbuffer pbuffer; + private int pbufferWidth = 256; + private int pbufferHeight = 256; + + public void initialize() { + if (pbuffer != null) { + throw new InternalError("Creating pbuffer twice without destroying it (memory leak / correctness bug)"); + } + try { + pbuffer = factory.createGLPbuffer(null /* default platform device */, + offscreenCaps, + null, + pbufferWidth, + pbufferHeight, + shareWith); + pbuffer.addGLEventListener(updater); + isInitialized = true; + } catch (GLException e) { + if (DEBUG) { + e.printStackTrace(); + System.err.println("Info: GLJPanel: Falling back on software rendering because of problems creating pbuffer"); + } + hardwareAccelerationDisabled = true; + backend = null; + isInitialized = false; + createAndInitializeBackend(); + } + } + + public void destroy() { + if (pbuffer != null) { + pbuffer.destroy(); + pbuffer = null; + } + } + + public GLContext createContext(GLContext shareWith) { + return pbuffer.createContext(shareWith); + } + + public void setContext(GLContext ctx) { + if (pbuffer == null && Beans.isDesignTime()) { + return; + } + pbuffer.setContext(ctx); + } + + public GLContext getContext() { + // Workaround for crashes in NetBeans GUI builder + if (pbuffer == null && Beans.isDesignTime()) { + return null; + } + return pbuffer.getContext(); + } + + public GLDrawable getDrawable() { + return pbuffer; + } + + public GLCapabilitiesImmutable getChosenGLCapabilities() { + if (pbuffer == null) { + return null; + } + return pbuffer.getChosenGLCapabilities(); + } + + public GLProfile getGLProfile() { + if (pbuffer == null) { + return null; + } + return pbuffer.getGLProfile(); + } + + public void handleReshape() { + // Use factor larger than 2 during shrinks for some hysteresis + float shrinkFactor = 2.5f; + if ((panelWidth > pbufferWidth) || (panelHeight > pbufferHeight) || + (panelWidth < (pbufferWidth / shrinkFactor)) || (panelHeight < (pbufferHeight / shrinkFactor))) { + if (DEBUG) { + System.err.println("Resizing pbuffer from (" + pbufferWidth + ", " + pbufferHeight + ") " + + " to fit (" + panelWidth + ", " + panelHeight + ")"); + } + // Must destroy and recreate pbuffer to fit + if (pbuffer != null) { + // Watch for errors during pbuffer destruction (due to + // buggy / bad OpenGL drivers, in particular SiS) and fall + // back to software rendering + try { + pbuffer.destroy(); + } catch (GLException e) { + hardwareAccelerationDisabled = true; + backend = null; + isInitialized = false; + // Just disabled hardware acceleration during this resize operation; do a fixup + readBackWidthInPixels = Math.max(1, panelWidth); + readBackHeightInPixels = Math.max(1, panelHeight); + if (DEBUG) { + System.err.println("Warning: falling back to software rendering due to bugs in OpenGL drivers"); + e.printStackTrace(); + } + createAndInitializeBackend(); + return; + } + } + pbuffer = null; + isInitialized = false; + pbufferWidth = getNextPowerOf2(panelWidth); + pbufferHeight = getNextPowerOf2(panelHeight); + if (DEBUG && !hardwareAccelerationDisabled) { + System.err.println("New pbuffer size is (" + pbufferWidth + ", " + pbufferHeight + ")"); + } + initialize(); + } + + // It looks like NVidia's drivers (at least the ones on my + // notebook) are buggy and don't allow a rectangle of less than + // the pbuffer's width to be read...this doesn't really matter + // because it's the Graphics.drawImage() calls that are the + // bottleneck. Should probably make the size of the offscreen + // image be the exact size of the pbuffer to save some work on + // resize operations... + readBackWidthInPixels = pbufferWidth; + readBackHeightInPixels = panelHeight; + + if (offscreenImage != null) { + offscreenImage.flush(); + offscreenImage = null; + } + } + + protected void doPaintComponentImpl() { + pbuffer.display(); + } + + protected int getGLPixelType() { + // This seems to be a good choice on all platforms + return GL2.GL_UNSIGNED_INT_8_8_8_8_REV; + } + + protected boolean flipVertically() { + return true; + } + } + + 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) + private Graphics cached2DGraphics; + // 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 int[] drawBuffer = new int[1]; + private int[] readBuffer = new int[1]; + // This is required when the FBO option of the Java2D / OpenGL + // pipeline is active + private 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; + + public void initialize() { + // No-op in this implementation; everything is done lazily + isInitialized = true; + } + + public void destroy() { + Java2D.invokeWithOGLContextCurrent(null, new Runnable() { + public void run() { + if (joglContext != null) { + joglContext.destroy(); + joglContext = null; + } + joglDrawable = null; + if (j2dContext != null) { + j2dContext.destroy(); + j2dContext = null; + } + } + }); + } + + public void setOpaque(boolean opaque) { + // Empty in this implementation + } + + public GLContext createContext(GLContext shareWith) { + // FIXME: should implement this, but it was not properly + // implemented before the refactoring anyway + throw new GLException("Not yet implemented"); + } + + public void setContext(GLContext ctx) { + joglContext=ctx; + } + + public GLContext getContext() { + return joglContext; + } + + public GLDrawable getDrawable() { + return joglDrawable; + } + + public GLCapabilitiesImmutable getChosenGLCapabilities() { + // FIXME: should do better than this; is it possible to using only platform-independent code? + return new GLCapabilities(null); + } + + public GLProfile getGLProfile() { + // FIXME: should do better than this; is it possible to using only platform-independent code? + return GLProfile.getDefault(GLProfile.getDefaultDesktopDevice()); + } + + public void handleReshape() { + // Empty in this implementation + } + + public boolean preGL(Graphics g) { + GL2 gl = joglContext.getGL().getGL2(); + // Set up needed state in JOGL context from Java2D context + gl.glEnable(GL2.GL_SCISSOR_TEST); + Rectangle r = Java2D.getOGLScissorBox(g); + + if (r == null) { + if (DEBUG && VERBOSE) { + System.err.println("Java2D.getOGLScissorBox() returned null"); + } + return false; + } + if (DEBUG && VERBOSE) { + System.err.println("GLJPanel: gl.glScissor(" + r.x + ", " + r.y + ", " + r.width + ", " + r.height + ")"); + } + + gl.glScissor(r.x, r.y, r.width, r.height); + 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("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 + int fboTextureTarget = Java2D.getOGLTextureType(g); + + if (!checkedForFBObjectWorkarounds) { + checkedForFBObjectWorkarounds = true; + gl.glBindTexture(fboTextureTarget, 0); + gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, frameBuffer[0]); + int status = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER); + if (status != GL.GL_FRAMEBUFFER_COMPLETE) { + // Need to do workarounds + fbObjectWorkarounds = true; + createNewDepthBuffer = true; + if (DEBUG || VERBOSE) { + System.err.println("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 || VERBOSE) { + System.err.println("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]); + int[] width = new int[1]; + int[] height = new int[1]; + gl.glGetTexLevelParameteriv(fboTextureTarget, 0, GL2.GL_TEXTURE_WIDTH, width, 0); + gl.glGetTexLevelParameteriv(fboTextureTarget, 0, GL2.GL_TEXTURE_HEIGHT, height, 0); + + gl.glGenRenderbuffers(1, frameBufferDepthBuffer, 0); + if (DEBUG) { + System.err.println("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, GL2GL3.GL_DEPTH_COMPONENT24, width[0], height[0]); + + gl.glBindRenderbuffer(GL2.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 && VERBOSE) { + System.err.println("GLJPanel: frameBufferDepthBuffer: " + frameBufferDepthBuffer[0]); + } + gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, + GL.GL_DEPTH_ATTACHMENT, + GL.GL_RENDERBUFFER, + frameBufferDepthBuffer[0]); + } + + if (DEBUG) { + 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 && VERBOSE) { + System.err.println("GLJPanel: Setting up drawBuffer " + drawBuffer[0] + + " and readBuffer " + readBuffer[0]); + } + + gl.glDrawBuffer(drawBuffer[0]); + gl.glReadBuffer(readBuffer[0]); + } + + return true; + } + + public void postGL(Graphics g, 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 + GL gl = 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); + } + } + + public 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() { public void run() {}}); + } + + Java2D.invokeWithOGLContextCurrent(g, new Runnable() { + public void run() { + if (DEBUG && VERBOSE) { + System.err.println("-- In invokeWithOGLContextCurrent"); + } + + // Create no-op context representing Java2D context + if (j2dContext == null) { + j2dContext = factory.createExternalGLContext(); + if (DEBUG||VERBOSE) { + System.err.println("-- 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(); + GL gl = j2dContext.getGL(); + if ((getGLInteger(gl, GL.GL_RED_BITS) < offscreenCaps.getRedBits()) || + (getGLInteger(gl, GL.GL_GREEN_BITS) < offscreenCaps.getGreenBits()) || + (getGLInteger(gl, GL.GL_BLUE_BITS) < offscreenCaps.getBlueBits()) || + // (getGLInteger(gl, GL.GL_ALPHA_BITS) < offscreenCaps.getAlphaBits()) || + (getGLInteger(gl, GL2.GL_ACCUM_RED_BITS) < offscreenCaps.getAccumRedBits()) || + (getGLInteger(gl, GL2.GL_ACCUM_GREEN_BITS) < offscreenCaps.getAccumGreenBits()) || + (getGLInteger(gl, GL2.GL_ACCUM_BLUE_BITS) < offscreenCaps.getAccumBlueBits()) || + (getGLInteger(gl, GL2.GL_ACCUM_ALPHA_BITS) < offscreenCaps.getAccumAlphaBits()) || + // (getGLInteger(gl, GL2.GL_DEPTH_BITS) < offscreenCaps.getDepthBits()) || + (getGLInteger(gl, GL.GL_STENCIL_BITS) < offscreenCaps.getStencilBits())) { + if (DEBUG) { + System.err.println("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) + " " + offscreenCaps.getRedBits()); + System.err.println("GL_GREEN_BITS " + getGLInteger(gl, GL.GL_GREEN_BITS) + " " + offscreenCaps.getGreenBits()); + System.err.println("GL_BLUE_BITS " + getGLInteger(gl, GL.GL_BLUE_BITS) + " " + offscreenCaps.getBlueBits()); + System.err.println("GL_ALPHA_BITS " + getGLInteger(gl, GL.GL_ALPHA_BITS) + " " + offscreenCaps.getAlphaBits()); + System.err.println("GL_ACCUM_RED_BITS " + getGLInteger(gl, GL2.GL_ACCUM_RED_BITS) + " " + offscreenCaps.getAccumRedBits()); + System.err.println("GL_ACCUM_GREEN_BITS " + getGLInteger(gl, GL2.GL_ACCUM_GREEN_BITS) + " " + offscreenCaps.getAccumGreenBits()); + System.err.println("GL_ACCUM_BLUE_BITS " + getGLInteger(gl, GL2.GL_ACCUM_BLUE_BITS) + " " + offscreenCaps.getAccumBlueBits()); + System.err.println("GL_ACCUM_ALPHA_BITS " + getGLInteger(gl, GL2.GL_ACCUM_ALPHA_BITS) + " " + offscreenCaps.getAccumAlphaBits()); + System.err.println("GL_DEPTH_BITS " + getGLInteger(gl, GL.GL_DEPTH_BITS) + " " + offscreenCaps.getDepthBits()); + System.err.println("GL_STENCIL_BITS " + getGLInteger(gl, GL.GL_STENCIL_BITS) + " " + offscreenCaps.getStencilBits()); + } + isInitialized = false; + backend = null; + oglPipelineEnabled = false; + handleReshape = true; + j2dContext.release(); + j2dContext.destroy(); + j2dContext = null; + return; + } + j2dContext.release(); + } + + j2dContext.makeCurrent(); + try { + captureJ2DState(j2dContext.getGL(), g); + Object curSurface = Java2D.getOGLSurfaceIdentifier(g); + if (curSurface != null) { + if (j2dSurface != curSurface) { + if (joglContext != null) { + joglContext.destroy(); + joglContext = null; + joglDrawable = null; + sendReshape = true; + if (DEBUG||VERBOSE) { + System.err.println("Sending reshape because surface changed"); + System.err.println("New surface = " + curSurface); + } + } + j2dSurface = curSurface; + if (DEBUG || VERBOSE) { + System.err.print("-- Surface type: "); + 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) { + AbstractGraphicsDevice device = j2dContext.getGLDrawable().getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getScreen().getDevice(); + if (factory.canCreateExternalGLDrawable(device)) { + joglDrawable = factory.createExternalGLDrawable(); + // FIXME: Need to share with j2d context, due to FBO resource .. + // - ORIG: joglContext = joglDrawable.createContext(shareWith); + joglContext = joglDrawable.createContext(j2dContext); + if (DEBUG||VERBOSE) { + System.err.println("-- Created External Drawable: "+joglDrawable); + System.err.println("-- Created Context: "+joglContext); + } + } else if (factory.canCreateContextOnJava2DSurface(device)) { + // Mac OS X code path + // FIXME: Need to share with j2d context, due to FBO resource .. + // - ORIG: joglContext = factory.createContextOnJava2DSurface(g, shareWith); + joglContext = factory.createContextOnJava2DSurface(g, j2dContext); + if (DEBUG||VERBOSE) { + System.err.println("-- Created Context: "+joglContext); + } + } + /*if (DEBUG) { + joglContext.setGL(new DebugGL2(joglContext.getGL().getGL2())); + }*/ + + if (Java2D.isFBOEnabled() && + Java2D.getOGLSurfaceType(g) == Java2D.FBOBJECT && + fbObjectWorkarounds) { + createNewDepthBuffer = true; + } + } + if (joglContext instanceof Java2DGLContext) { + // Mac OS X code path + ((Java2DGLContext) joglContext).setGraphics(g); + } + + drawableHelper.invokeGL(joglDrawable, joglContext, displayAction, initAction); + } + } finally { + j2dContext.release(); + } + } + }); + } + + private void captureJ2DState(GL gl, Graphics g) { + gl.glGetIntegerv(GL2.GL_DRAW_BUFFER, drawBuffer, 0); + gl.glGetIntegerv(GL2.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 || VERBOSE) { + System.err.println("GLJPanel: Fetched ERR GL_FRAMEBUFFER_BINDING: "+frameBuffer[0]+" - NOT A FBO"+ + ", frame_buffer_object workarounds to be necessary"); + } + } else if (DEBUG) { + System.err.println("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 && VERBOSE) { + System.err.println("GLJPanel: FBO COLOR_ATTACHMENT0: " + frameBufferTexture[0]); + } + } + + if (!checkedGLVendor) { + checkedGLVendor = true; + 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/javax/media/opengl/fixedfunc/GLLightingFunc.java b/src/jogl/classes/javax/media/opengl/fixedfunc/GLLightingFunc.java new file mode 100644 index 000000000..5563ea9c8 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/fixedfunc/GLLightingFunc.java @@ -0,0 +1,49 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + */ + +package javax.media.opengl.fixedfunc; + +import java.nio.*; + +import javax.media.opengl.*; + +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/javax/media/opengl/fixedfunc/GLMatrixFunc.java b/src/jogl/classes/javax/media/opengl/fixedfunc/GLMatrixFunc.java new file mode 100644 index 000000000..b899f3c0a --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/fixedfunc/GLMatrixFunc.java @@ -0,0 +1,74 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + */ + +package javax.media.opengl.fixedfunc; + +import java.nio.*; + +public interface GLMatrixFunc { + + public static final int GL_MATRIX_MODE = 0x0BA0; + public static final int GL_MODELVIEW = 0x1700; + public static final int GL_PROJECTION = 0x1701; + // public static final int GL_TEXTURE = 0x1702; // Use GL.GL_TEXTURE due to ambiguous GL usage + public static final int GL_MODELVIEW_MATRIX = 0x0BA6; + public static final int GL_PROJECTION_MATRIX = 0x0BA7; + public static final int GL_TEXTURE_MATRIX = 0x0BA8; + + /** + * glGetFloatv + * @param pname GL_MODELVIEW_MATRIX, GL_PROJECTION_MATRIX or 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); + public void glGetFloatv(int pname, float[] params, int params_offset); + /** + * glGetIntegerv + * @param pname GL_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 + * @param pname GL_MODELVIEW, GL_PROJECTION or GL.GL_TEXTURE + */ + public void glMatrixMode(int mode) ; + + public void glPushMatrix(); + public void glPopMatrix(); + + public void glLoadIdentity() ; + + /** + * glLoadMatrixf + * @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) ; + public void glLoadMatrixf(float[] m, int m_offset); + + /** + * glMultMatrixf + * @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) ; + public void glMultMatrixf(float[] m, int m_offset); + + public void glTranslatef(float x, float y, float z) ; + + public void glRotatef(float angle, float x, float y, float z); + + public void glScalef(float x, float y, float z) ; + + public void glOrthof(float left, float right, float bottom, float top, float zNear, float zFar) ; + + public void glFrustumf(float left, float right, float bottom, float top, float zNear, float zFar); + +} + diff --git a/src/jogl/classes/javax/media/opengl/fixedfunc/GLPointerFunc.java b/src/jogl/classes/javax/media/opengl/fixedfunc/GLPointerFunc.java new file mode 100644 index 000000000..ed7bef5d4 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/fixedfunc/GLPointerFunc.java @@ -0,0 +1,38 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + */ + +package javax.media.opengl.fixedfunc; + +import java.nio.*; + +import javax.media.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/javax/media/opengl/glu/GLUnurbs.java b/src/jogl/classes/javax/media/opengl/glu/GLUnurbs.java new file mode 100644 index 000000000..2641115d0 --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/glu/GLUnurbs.java @@ -0,0 +1,8 @@ +package javax.media.opengl.glu; + +/** + * Wrapper for a GLU NURBS object. + */ + +public interface GLUnurbs { +} diff --git a/src/jogl/classes/javax/media/opengl/glu/GLUquadric.java b/src/jogl/classes/javax/media/opengl/glu/GLUquadric.java new file mode 100644 index 000000000..49451a34b --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/glu/GLUquadric.java @@ -0,0 +1,33 @@ +package javax.media.opengl.glu; + +import javax.media.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/javax/media/opengl/glu/GLUtessellator.java b/src/jogl/classes/javax/media/opengl/glu/GLUtessellator.java new file mode 100644 index 000000000..f98bbe158 --- /dev/null +++ b/src/jogl/classes/javax/media/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 javax.media.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/javax/media/opengl/glu/GLUtessellatorCallback.java b/src/jogl/classes/javax/media/opengl/glu/GLUtessellatorCallback.java new file mode 100644 index 000000000..0f05619a4 --- /dev/null +++ b/src/jogl/classes/javax/media/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 javax.media.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 javax.media.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 javax.media.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 javax.media.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 javax.media.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/javax/media/opengl/glu/GLUtessellatorCallbackAdapter.java b/src/jogl/classes/javax/media/opengl/glu/GLUtessellatorCallbackAdapter.java new file mode 100644 index 000000000..bd12dfb9d --- /dev/null +++ b/src/jogl/classes/javax/media/opengl/glu/GLUtessellatorCallbackAdapter.java @@ -0,0 +1,84 @@ +/* +* 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 javax.media.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 { + public void begin(int type) {} + public void edgeFlag(boolean boundaryEdge) {} + public void vertex(Object vertexData) {} + public void end() {} +// public void mesh(jogamp.opengl.tessellator.GLUmesh mesh) {} + public void error(int errnum) {} + public void combine(double[] coords, Object[] data, + float[] weight, Object[] outData) {} + public void beginData(int type, Object polygonData) {} + public void edgeFlagData(boolean boundaryEdge, + Object polygonData) {} + public void vertexData(Object vertexData, Object polygonData) {} + public void endData(Object polygonData) {} + public void errorData(int errnum, Object polygonData) {} + public void combineData(double[] coords, Object[] data, + float[] weight, Object[] outData, + Object polygonData) {} +} |