JOGL v2.6.0-rc-20250706
JOGL, High-Performance Graphics Binding for Java™ (public API).
GLDrawableUtil.java
Go to the documentation of this file.
1/**
2 * Copyright 2012 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28package com.jogamp.opengl.util;
29
30import com.jogamp.nativewindow.AbstractGraphicsDevice;
31import com.jogamp.nativewindow.NativeSurface;
32import com.jogamp.opengl.GLAnimatorControl;
33import com.jogamp.opengl.GLAutoDrawable;
34import com.jogamp.opengl.GLBase;
35import com.jogamp.opengl.GLCapabilitiesImmutable;
36import com.jogamp.opengl.GLContext;
37import com.jogamp.opengl.GLDrawable;
38import com.jogamp.opengl.GLEventListener;
39import com.jogamp.opengl.GLException;
40import com.jogamp.opengl.GLRunnable;
41import com.jogamp.opengl.Threading;
42
43import com.jogamp.common.util.locks.RecursiveLock;
44import com.jogamp.opengl.GLEventListenerState;
45
46import jogamp.opengl.Debug;
47
48/**
49 * Providing utility functions dealing w/ {@link GLDrawable}s, {@link GLAutoDrawable} and their {@link GLEventListener}.
50 */
51public class GLDrawableUtil {
52 protected static final boolean DEBUG = Debug.debug("GLDrawable");
53
54 public static final boolean isAnimatorStartedOnOtherThread(final GLAnimatorControl animatorCtrl) {
55 return ( null != animatorCtrl ) ? animatorCtrl.isStarted() && animatorCtrl.getThread() != Thread.currentThread() : false ;
56 }
57
58 public static final boolean isAnimatorStarted(final GLAnimatorControl animatorCtrl) {
59 return ( null != animatorCtrl ) ? animatorCtrl.isStarted() : false ;
60 }
61
62 public static final boolean isAnimatorAnimatingOnOtherThread(final GLAnimatorControl animatorCtrl) {
63 return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() && animatorCtrl.getThread() != Thread.currentThread() : false ;
64 }
65
66 public static final boolean isAnimatorAnimating(final GLAnimatorControl animatorCtrl) {
67 return ( null != animatorCtrl ) ? animatorCtrl.isAnimating() : false ;
68 }
69
70 /**
71 * {@link GLRunnable} to issue {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int)},
72 * returning <code>true</code> on {@link GLRunnable#run(GLAutoDrawable)}.
73 */
74 public static class ReshapeGLEventListener implements GLRunnable {
75 private final GLEventListener listener;
76 private final boolean displayAfterReshape;
77 /**
78 *
79 * @param listener
80 * @param displayAfterReshape <code>true</code> to issue {@link GLEventListener#display(GLAutoDrawable)}
81 * after {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int)},
82 * otherwise false.
83 */
84 public ReshapeGLEventListener(final GLEventListener listener, final boolean displayAfterReshape) {
85 this.listener = listener;
86 this.displayAfterReshape = displayAfterReshape;
87 }
88 @Override
89 public boolean run(final GLAutoDrawable drawable) {
90 listener.reshape(drawable, 0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight());
91 if( displayAfterReshape ) {
92 listener.display(drawable);
93 }
94 return true;
95 }
96 }
97
98 /**
99 * Moves the designated {@link GLEventListener} from {@link GLAutoDrawable} <code>src</code> to <code>dest</code>.
100 * If <code>preserveInitState</code> is <code>true</code>, it's initialized state is preserved
101 * and {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)} issued w/ the next {@link GLAutoDrawable#display()} call.
102 * <p>
103 * Note that it is only legal to pass <code>preserveInitState := true</code>,
104 * if the {@link GLContext} of both <code>src</code> and <code>dest</code> are shared, or has itself moved from <code>src</code> to <code>dest</code>.
105 * </p>
106 * <p>
107 * Also note that the caller is encouraged to pause an attached {@link GLAnimatorControl}.
108 * </p>
109 * @param src
110 * @param dest
111 * @param listener
112 * @param preserveInitState
113 */
114 public static final void moveGLEventListener(final GLAutoDrawable src, final GLAutoDrawable dest, final GLEventListener listener, final boolean preserveInitState) {
115 final boolean initialized = src.getGLEventListenerInitState(listener);
116 if( preserveInitState ) {
117 src.removeGLEventListener(listener);
118 dest.addGLEventListener(listener);
119 if( initialized ) {
120 dest.setGLEventListenerInitState(listener, true);
121 dest.invoke(false, new ReshapeGLEventListener(listener, true));
122 }
123 } else {
124 src.disposeGLEventListener(listener, true);
125 dest.addGLEventListener(listener);
126 }
127 }
128
129 /**
130 * Moves all {@link GLEventListener} from {@link GLAutoDrawable} <code>src</code> to <code>dest</code>.
131 * If <code>preserveInitState</code> is <code>true</code>, it's initialized state is preserved
132 * and {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)} issued w/ the next {@link GLAutoDrawable#display()} call.
133 * <p>
134 * Note that it is only legal to pass <code>preserveInitState := true</code>,
135 * if the {@link GLContext} of both <code>src</code> and <code>dest</code> are shared, or has itself moved from <code>src</code> to <code>dest</code>.
136 * </p>
137 * <p>
138 * Also note that the caller is encouraged to pause an attached {@link GLAnimatorControl}.
139 * </p>
140 * @param src
141 * @param dest
142 * @param listener
143 * @param preserveInitState
144 */
145 public static final void moveAllGLEventListener(final GLAutoDrawable src, final GLAutoDrawable dest, final boolean preserveInitState) {
146 for(int count = src.getGLEventListenerCount(); 0<count; count--) {
147 final GLEventListener listener = src.getGLEventListener(0);
148 moveGLEventListener(src, dest, listener, preserveInitState);
149 }
150 }
151
152 /**
153 * Return a heuristic value whether switching the {@link GLContext} is safe between {@link GLAutoDrawable}s,
154 * i.e. via {@link #swapGLContext(GLAutoDrawable, GLAutoDrawable)} or {@link #swapGLContextAndAllGLEventListener(GLAutoDrawable, GLAutoDrawable)}.
155 * <p>
156 * Method currently returns <code>false</code> if:
157 * <ul>
158 * <li>Switching between on- and offscreen and one of the following is <code>true</code>:
159 * <ul>
160 * <li>{@link GLCapabilitiesImmutable#getSampleBuffers() MSAA is <i>used</i>} [1] in <code>chosenCapsA</code> or <code>chosenCapsB</code></li>
161 * <li>{@link GLCapabilitiesImmutable#getStereo() Stereo is <i>used</i>} in <code>chosenCapsA</code> or <code>chosenCapsB</code></li>
162 * <li>{@link GLCapabilitiesImmutable#getAccumAlphaBits() Accumulator Buffer is <i>requested</i>} [2] in <code>requestedCaps</code></li>
163 * </ul></li>
164 * </ul>
165 * Otherwise method returns <code>true</code>
166 * </p>
167 * <pre>
168 * [1] See Bug 830: swapGLContextAndAllGLEventListener and onscreen MSAA w/ NV/GLX
169 * On NVidia GPUs w/ it's proprietary driver context swapping does not work if MSAA is involved
170 * and when swapping on- to offscreen.
171 * </pre>
172 * <pre>
173 * [2] On AMD GPUs w/ it's proprietary driver, requesting an accumulator buffer leads to receive an accumulator buffer configuration,
174 * for which context swapping does not work when swapping on- to offscreen and vice-versa, i.e. cannot make context current.
175 * With AMD and Mesa drivers we only receive an accumulator buffer if requested,
176 * where on NVidia drivers all configurations contain the accumulator buffer.
177 * On both drivers, NVidia and Mesa, context swapping with accumulator buffer works.
178 * </pre>
179 * @param requestedCaps requested {@link GLCapabilitiesImmutable} which are intended for usage by both {@link GLAutoDrawable}s A and B
180 * @param chosenCapsA chosen {@link GLCapabilitiesImmutable} of {@link GLAutoDrawable} A, which {@link GLContext} is intended to be swapped
181 * @param chosenCapsB chosen {@link GLCapabilitiesImmutable} of {@link GLAutoDrawable} B, which {@link GLContext} is intended to be swapped
182 * @see #swapGLContext(GLAutoDrawable, GLAutoDrawable)
183 * @see #swapGLContextAndAllGLEventListener(GLAutoDrawable, GLAutoDrawable)
184 */
185 public static boolean isSwapGLContextSafe(final GLCapabilitiesImmutable requestedCaps, final GLCapabilitiesImmutable chosenCapsA, final GLCapabilitiesImmutable chosenCapsB) {
186 final boolean usingAccumulatorBuffer = requestedCaps.getAccumAlphaBits() > 0 ||
187 requestedCaps.getAccumRedBits() > 0 ||
188 requestedCaps.getAccumGreenBits() > 0 ||
189 requestedCaps.getAccumBlueBits() > 0;
190 if( ( chosenCapsA.isOnscreen() && !chosenCapsB.isOnscreen() || !chosenCapsA.isOnscreen() && chosenCapsB.isOnscreen() ) && // switching between on- and offscreen
191 (
192 ( chosenCapsA.getSampleBuffers() || chosenCapsB.getSampleBuffers() ) || // MSAA involved
193 ( chosenCapsA.getStereo() || chosenCapsB.getStereo() ) || // Stereo involved
194 usingAccumulatorBuffer // Using accumulator buffer
195 )
196 )
197 {
198 return false;
199 } else {
200 return true;
201 }
202 }
203 /**
204 * Swaps the {@link GLContext} and all {@link GLEventListener} between {@link GLAutoDrawable} <code>a</code> and <code>b</code>,
205 * while preserving it's initialized state, resets the GL-Viewport and issuing {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)}.
206 * <p>
207 * The {@link GLAutoDrawable} to {@link GLAnimatorControl} association
208 * is also swapped.
209 * </p>
210 * <p>
211 * If an {@link GLAnimatorControl} is being attached to {@link GLAutoDrawable} <code>a</code> or <code>b</code>
212 * and the current thread is different than {@link GLAnimatorControl#getThread() the animator's thread}, it is paused during the operation.
213 * </p>
214 * <p>
215 * During operation, both {@link GLAutoDrawable auto-drawable's}
216 * {@link GLAutoDrawable#getUpstreamLock() upstream-locks} and {@link GLAutoDrawable#getNativeSurface() surfaces} are locked,
217 * hence atomicity of operation is guaranteed,
218 * see <a href="../../../../com/jogamp/opengl/GLAutoDrawable.html#locking">GLAutoDrawable Locking</a>.
219 * </p>
220 * <p>
221 * Because of above mentioned locking, if this method is not performed
222 * on {@link GLAutoDrawable#isThreadGLCapable() a OpenGL capable thread} of <i>both</i>
223 * {@link GLAutoDrawable}s, it must be invoked on such an OpenGL capable thread,
224 * e.g. via {@link Threading#invokeOnOpenGLThread(boolean, Runnable)}.
225 * </p>
226 * @throws GLException if the {@link AbstractGraphicsDevice} are incompatible w/ each other.
227 * @see #isSwapGLContextSafe(GLCapabilitiesImmutable, GLCapabilitiesImmutable, GLCapabilitiesImmutable)
228 */
229 public static final void swapGLContextAndAllGLEventListener(final GLAutoDrawable a, final GLAutoDrawable b) {
232 final Runnable gllsAUnlockOp = gllsA.getUnlockSurfaceOp();
233 final Runnable gllsBUnlockOp = gllsB.getUnlockSurfaceOp();
234 try {
235 gllsA.moveTo(b, gllsBUnlockOp);
236 gllsB.moveTo(a, gllsAUnlockOp);
237 } finally {
238 // guarantee unlock in case of an exception
239 gllsBUnlockOp.run();
240 gllsAUnlockOp.run();
241 }
242 }
243
244 /**
245 * Swaps the {@link GLContext} of given {@link GLAutoDrawable}
246 * and {@link GLAutoDrawable#disposeGLEventListener(GLEventListener, boolean) disposes}
247 * each {@link GLEventListener} w/o removing it.
248 * <p>
249 * The GL-Viewport is reset and {@link GLEventListener#reshape(GLAutoDrawable, int, int, int, int) reshape(..)} issued implicit.
250 * </p>
251 * <p>
252 * If an {@link GLAnimatorControl} is being attached to GLAutoDrawable src or dest and the current thread is different
253 * than {@link GLAnimatorControl#getThread() the animator's thread}, it is paused during the operation.
254 * </p>
255 * <p>
256 * During operation, both {@link GLAutoDrawable auto-drawable's}
257 * {@link GLAutoDrawable#getUpstreamLock() upstream-locks} and {@link GLAutoDrawable#getNativeSurface() surfaces} are locked,
258 * hence atomicity of operation is guaranteed,
259 * see <a href="../../../../com/jogamp/opengl/GLAutoDrawable.html#locking">GLAutoDrawable Locking</a>.
260 * </p>
261 * <p>
262 * Because of above mentioned locking, if this method is not performed
263 * on {@link GLAutoDrawable#isThreadGLCapable() a OpenGL capable thread} of <i>both</i>
264 * {@link GLAutoDrawable}s, it must be invoked on such an OpenGL capable thread,
265 * e.g. via {@link Threading#invokeOnOpenGLThread(boolean, Runnable)}.
266 * </p>
267 * @param a
268 * @param b
269 * @see #isSwapGLContextSafe(GLCapabilitiesImmutable, GLCapabilitiesImmutable, GLCapabilitiesImmutable)
270 */
271 public static final void swapGLContext(final GLAutoDrawable a, final GLAutoDrawable b) {
272 final GLAnimatorControl aAnim = a.getAnimator();
273 final GLAnimatorControl bAnim = b.getAnimator();
274 final boolean aIsPaused = isAnimatorAnimatingOnOtherThread(aAnim) && aAnim.pause();
275 final boolean bIsPaused = isAnimatorAnimatingOnOtherThread(bAnim) && bAnim.pause();
276
277 final RecursiveLock aUpstreamLock = a.getUpstreamLock();
278 final RecursiveLock bUpstreamLock = b.getUpstreamLock();
279 aUpstreamLock.lock();
280 bUpstreamLock.lock();
281 try {
282 final NativeSurface aSurface = a.getNativeSurface();
283 final boolean aSurfaceLocked = NativeSurface.LOCK_SURFACE_NOT_READY < aSurface.lockSurface();
284 if( a.isRealized() && !aSurfaceLocked ) {
285 throw new GLException("Could not lock realized a surface "+a);
286 }
287 final NativeSurface bSurface = b.getNativeSurface();
288 final boolean bSurfaceLocked = NativeSurface.LOCK_SURFACE_NOT_READY < bSurface.lockSurface();
289 if( b.isRealized() && !bSurfaceLocked ) {
290 throw new GLException("Could not lock realized b surface "+b);
291 }
292 try {
293 for(int i = a.getGLEventListenerCount() - 1; 0 <= i; i--) {
295 }
296 for(int i = b.getGLEventListenerCount() - 1; 0 <= i; i--) {
298 }
299 b.setContext( a.setContext( b.getContext(), false ), false );
300
301 } finally {
302 if( bSurfaceLocked ) {
303 bSurface.unlockSurface();
304 }
305 if( aSurfaceLocked ) {
306 aSurface.unlockSurface();
307 }
308 }
309 } finally {
310 bUpstreamLock.unlock();
311 aUpstreamLock.unlock();
312 }
313 a.invoke(true, setViewport);
314 b.invoke(true, setViewport);
315 if(aIsPaused) { aAnim.resume(); }
316 if(bIsPaused) { bAnim.resume(); }
317 }
318
319 private static final GLRunnable setViewport = new GLRunnable() {
320 @Override
321 public boolean run(final GLAutoDrawable drawable) {
322 drawable.getGL().glViewport(0, 0, drawable.getSurfaceWidth(), drawable.getSurfaceHeight());
323 return false; // issue re-display w/ new viewport!
324 }
325 };
326
327 /**
328 * Determines whether the chosen {@link GLCapabilitiesImmutable}
329 * requires a {@link GLDrawable#swapBuffers() swap-buffers}
330 * before reading pixels.
331 * <p>
332 * Usually one uses the {@link GLBase#getDefaultReadBuffer() default-read-buffer}
333 * in which case {@link GLDrawable#swapBuffers() swap-buffers} shall happen <b>after</b> calling reading pixels, the default.
334 * </p>
335 * <p>
336 * However, <i>multisampling</i> offscreen {@link com.jogamp.opengl.GLFBODrawable}s
337 * utilize {@link GLDrawable#swapBuffers() swap-buffers} to <i>downsample</i>
338 * the multisamples into the readable sampling sink.
339 * In this case, we require {@link GLDrawable#swapBuffers() swap-buffers} <b>before</b> reading pixels.
340 * </p>
341 * @return chosenCaps.isFBO() && chosenCaps.getSampleBuffers()
342 */
343 public static final boolean swapBuffersBeforeRead(final GLCapabilitiesImmutable chosenCaps) {
344 return chosenCaps.isFBO() && chosenCaps.getSampleBuffers();
345 }
346}
GLEventListenerState is holding GLAutoDrawable components crucial to relocating all its GLEventListen...
final void moveTo(final GLAutoDrawable dest)
Moves all GLEventListenerState components to the given GLAutoDrawable from this instance,...
static GLEventListenerState moveFrom(final GLAutoDrawable src)
Moves all GLEventListenerState components from the given GLAutoDrawable to a newly created instance.
Runnable getUnlockSurfaceOp()
Returns a Runnable unlocking an eventually locked NativeSurface, see moveFrom(GLAutoDrawable,...
A generic exception for OpenGL errors used throughout the binding as a substitute for RuntimeExceptio...
GLRunnable to issue GLEventListener#reshape(GLAutoDrawable, int, int, int, int), returning true on GL...
ReshapeGLEventListener(final GLEventListener listener, final boolean displayAfterReshape)
Providing utility functions dealing w/ GLDrawables, GLAutoDrawable and their GLEventListener.
static final void moveAllGLEventListener(final GLAutoDrawable src, final GLAutoDrawable dest, final boolean preserveInitState)
Moves all GLEventListener from GLAutoDrawable src to dest.
static final boolean isAnimatorAnimatingOnOtherThread(final GLAnimatorControl animatorCtrl)
static final boolean swapBuffersBeforeRead(final GLCapabilitiesImmutable chosenCaps)
Determines whether the chosen GLCapabilitiesImmutable requires a swap-buffers before reading pixels.
static final void swapGLContextAndAllGLEventListener(final GLAutoDrawable a, final GLAutoDrawable b)
Swaps the GLContext and all GLEventListener between GLAutoDrawable a and b, while preserving it's ini...
static final void swapGLContext(final GLAutoDrawable a, final GLAutoDrawable b)
Swaps the GLContext of given GLAutoDrawable and disposes each GLEventListener w/o removing it.
static final void moveGLEventListener(final GLAutoDrawable src, final GLAutoDrawable dest, final GLEventListener listener, final boolean preserveInitState)
Moves the designated GLEventListener from GLAutoDrawable src to dest.
static final boolean isAnimatorStarted(final GLAnimatorControl animatorCtrl)
static final boolean isAnimatorStartedOnOtherThread(final GLAnimatorControl animatorCtrl)
static final boolean isAnimatorAnimating(final GLAnimatorControl animatorCtrl)
static boolean isSwapGLContextSafe(final GLCapabilitiesImmutable requestedCaps, final GLCapabilitiesImmutable chosenCapsA, final GLCapabilitiesImmutable chosenCapsB)
Return a heuristic value whether switching the GLContext is safe between GLAutoDrawables,...
boolean isOnscreen()
Returns whether an on- or offscreen surface is requested, available or chosen.
Provides low-level information required for hardware-accelerated rendering using a surface in a platf...
int lockSurface()
Lock the surface of this native window.
void unlockSurface()
Unlock the surface of this native window.
An animator control interface, which implementation may drive a com.jogamp.opengl....
boolean resume()
Resumes animation if paused.
boolean isAnimating()
Indicates whether this animator is started and is not paused.
boolean pause()
Pauses this animator.
boolean isStarted()
Indicates whether this animator has been started.
A higher-level abstraction than GLDrawable which supplies an event based mechanism (GLEventListener) ...
GLEventListener getGLEventListener(int index)
Returns the GLEventListener at the given index of this drawable queue.
GLContext setContext(GLContext newCtx, boolean destroyPrevCtx)
Associate the new context, newtCtx, to this auto-drawable.
boolean invoke(boolean wait, GLRunnable glRunnable)
Enqueues a one-shot GLRunnable, which will be executed within the next display() call after all regis...
GLAnimatorControl getAnimator()
GLEventListener disposeGLEventListener(GLEventListener listener, boolean remove)
Disposes the given listener via dispose(..) if it has been initialized and added to this queue.
GL getGL()
Returns the GL pipeline object this GLAutoDrawable uses.
void setGLEventListenerInitState(GLEventListener listener, boolean initialized)
Sets the given listener's initialized state.
RecursiveLock getUpstreamLock()
Returns the recursive lock object of the upstream widget to synchronize multithreaded access on top o...
void addGLEventListener(GLEventListener listener)
Adds the given listener to the end of this drawable queue.
int getGLEventListenerCount()
Returns the number of GLEventListener of this drawable queue.
GLEventListener removeGLEventListener(GLEventListener listener)
Removes the given listener from this drawable queue.
GLContext getContext()
Returns the context associated with this drawable.
boolean getGLEventListenerInitState(GLEventListener listener)
Retrieves whether the given listener is initialized or not.
Specifies an immutable set of OpenGL capabilities.
boolean getSampleBuffers()
Returns whether sample buffers for full-scene antialiasing (FSAA) should be allocated for this drawab...
int getAccumGreenBits()
Returns the number of bits for the accumulation buffer's green component.
int getAccumRedBits()
Returns the number of bits for the accumulation buffer's red component.
int getAccumAlphaBits()
Returns the number of bits for the accumulation buffer's alpha component.
int getAccumBlueBits()
Returns the number of bits for the accumulation buffer's blue component.
boolean isFBO()
Returns whether FBO offscreen mode is requested, available or chosen.
boolean getStereo()
Returns whether stereo is requested, available or chosen.
int getSurfaceWidth()
Returns the width of this GLDrawable's surface client area in pixel units.
boolean isRealized()
Returns true if this drawable is realized, otherwise false.
NativeSurface getNativeSurface()
Returns the associated NativeSurface of this NativeSurfaceHolder.
int getSurfaceHeight()
Returns the height of this GLDrawable's surface client area in pixel units.
Declares events which client code can use to manage OpenGL rendering into a GLAutoDrawable.
void display(GLAutoDrawable drawable)
Called by the drawable to initiate OpenGL rendering by the client.
void reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
Called by the drawable during the first repaint after the component has been resized.
void glViewport(int x, int y, int width, int height)
Entry point to C language function: void {@native glViewport}(GLint x, GLint y, GLsizei width,...