Commit | Line | Data |
---|---|---|
a959c53b KR |
1 | /* |
2 | * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. | |
0feca163 | 3 | * Copyright (c) 2010 JogAmp Community. All rights reserved. |
a959c53b KR |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without | |
6 | * modification, are permitted provided that the following conditions are | |
7 | * met: | |
8 | * | |
9 | * - Redistribution of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * | |
12 | * - Redistribution in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * | |
16 | * Neither the name of Sun Microsystems, Inc. or the names of | |
17 | * contributors may be used to endorse or promote products derived from | |
18 | * this software without specific prior written permission. | |
19 | * | |
20 | * This software is provided "AS IS," without a warranty of any kind. ALL | |
21 | * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, | |
22 | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A | |
23 | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN | |
24 | * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR | |
25 | * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |
26 | * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR | |
27 | * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR | |
28 | * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE | |
29 | * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, | |
30 | * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF | |
31 | * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
32 | * | |
33 | */ | |
34 | ||
2d57c252 | 35 | package com.jogamp.newt.opengl; |
a959c53b | 36 | |
dac35658 | 37 | import com.jogamp.common.GlueGenVersion; |
8c9f3bb3 | 38 | import com.jogamp.common.util.VersionUtil; |
dac35658 | 39 | import com.jogamp.nativewindow.NativeWindowVersion; |
2d57c252 | 40 | import com.jogamp.newt.*; |
1ad8c39d | 41 | import com.jogamp.newt.event.*; |
0feca163 | 42 | import com.jogamp.newt.impl.WindowImpl; |
a959c53b | 43 | import javax.media.nativewindow.*; |
018c7e86 | 44 | import javax.media.nativewindow.util.Point; |
a959c53b | 45 | import javax.media.opengl.*; |
f3bc93b0 | 46 | import com.jogamp.opengl.impl.GLDrawableHelper; |
dac35658 | 47 | import com.jogamp.opengl.JoglVersion; |
018c7e86 | 48 | import javax.media.nativewindow.util.Insets; |
a959c53b KR |
49 | |
50 | /** | |
0feca163 SG |
51 | * An implementation of {@link javax.media.opengl.GLAutoDrawable} interface, |
52 | * using an aggregation of a {@link com.jogamp.newt.Window} implementation. | |
2268a6ce SG |
53 | * <P> |
54 | * This implementation does not make the OpenGL context current<br> | |
0feca163 SG |
55 | * before calling the various input EventListener callbacks, ie {@link com.jogamp.newt.event.MouseListener} etc.<br> |
56 | * This design decision is made in favor of a more performant and simplified | |
57 | * implementation. Also the event dispatcher shall be implemented OpenGL agnostic.<br> | |
58 | * To be able to use OpenGL commands from within such input {@link com.jogamp.newt.event.NEWTEventListener},<br> | |
59 | * you can inject {@link javax.media.opengl.GLRunnable} objects | |
60 | * via {@link #invoke(boolean, javax.media.opengl.GLRunnable)} to the OpenGL command stream.<br> | |
2268a6ce | 61 | * <p> |
a959c53b | 62 | */ |
1b7b5d34 | 63 | public class GLWindow implements GLAutoDrawable, Window, NEWTEventConsumer { |
0feca163 | 64 | private WindowImpl window; |
a959c53b | 65 | |
476d1d75 MB |
66 | /** |
67 | * Constructor. Do not call this directly -- use {@link #create()} instead. | |
68 | */ | |
811bd23e | 69 | protected GLWindow(Window window) { |
018c7e86 | 70 | resetCounter(); |
0feca163 SG |
71 | this.window = (WindowImpl) window; |
72 | ((WindowImpl)this.window).setHandleDestroyNotify(false); | |
1ad8c39d | 73 | window.addWindowListener(new WindowAdapter() { |
969e4276 | 74 | public void windowRepaint(WindowUpdateEvent e) { |
0feca163 | 75 | if( !GLWindow.this.window.isSurfaceLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) { |
969e4276 SG |
76 | display(); |
77 | } | |
78 | } | |
79 | ||
a959c53b KR |
80 | public void windowResized(WindowEvent e) { |
81 | sendReshape = true; | |
0feca163 | 82 | if( !GLWindow.this.window.isSurfaceLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) { |
969e4276 SG |
83 | display(); |
84 | } | |
a959c53b KR |
85 | } |
86 | ||
a959c53b | 87 | public void windowDestroyNotify(WindowEvent e) { |
5ece52d5 | 88 | // Is an animator thread perform rendering? |
2aa29677 | 89 | if (GLWindow.this.helper.isExternalAnimatorRunning()) { |
6f73de7c SG |
90 | // Pause animations before initiating safe destroy. |
91 | GLAnimatorControl ctrl = GLWindow.this.helper.getAnimator(); | |
4c3e9e25 | 92 | boolean isPaused = ctrl.pause(); |
969e4276 | 93 | destroy(); |
4c3e9e25 SG |
94 | if(isPaused) { |
95 | ctrl.resume(); | |
96 | } | |
6f73de7c SG |
97 | } else if (GLWindow.this.window.isSurfaceLockedByOtherThread()) { |
98 | // Surface is locked by another thread | |
5ece52d5 SV |
99 | // Flag that destroy should be performed on the next |
100 | // attempt to display. | |
63be4a40 | 101 | sendDestroy = true; |
6f73de7c | 102 | } else { |
5ece52d5 | 103 | // Without an external thread animating or locking the |
6f73de7c | 104 | // surface, we are safe. |
5ece52d5 SV |
105 | destroy (); |
106 | } | |
a959c53b KR |
107 | } |
108 | }); | |
0feca163 | 109 | this.window.setLifecycleHook(new GLLifecycleHook()); |
a959c53b KR |
110 | } |
111 | ||
0feca163 SG |
112 | /** |
113 | * Creates a new GLWindow attaching a new Window referencing a new Screen | |
114 | * with the given GLCapabilities. | |
115 | * <P> | |
116 | * The resulting GLWindow owns the Window, Screen and Device, ie it will be destructed. | |
117 | */ | |
29e3b223 | 118 | public static GLWindow create(GLCapabilitiesImmutable caps) { |
0feca163 | 119 | return new GLWindow(NewtFactory.createWindow(caps)); |
a959c53b KR |
120 | } |
121 | ||
0feca163 SG |
122 | /** |
123 | * Creates a new GLWindow attaching a new Window referencing the given Screen | |
124 | * with the given GLCapabilities. | |
125 | * <P> | |
126 | * The resulting GLWindow owns the Window, ie it will be destructed. | |
127 | */ | |
29e3b223 | 128 | public static GLWindow create(Screen screen, GLCapabilitiesImmutable caps) { |
0feca163 | 129 | return new GLWindow(NewtFactory.createWindow(screen, caps)); |
a959c53b KR |
130 | } |
131 | ||
0feca163 SG |
132 | /** |
133 | * Creates a new GLWindow attaching the given window. | |
134 | * <P> | |
135 | * The resulting GLWindow does not own the given Window, ie it will not be destructed. | |
136 | */ | |
137 | public static GLWindow create(Window window) { | |
811bd23e | 138 | return new GLWindow(window); |
a959c53b | 139 | } |
6e599a26 | 140 | |
0feca163 SG |
141 | /** |
142 | * Creates a new GLWindow attaching a new child Window | |
143 | * of the given <code>parentNativeWindow</code> with the given GLCapabilities. | |
144 | * <P> | |
145 | * The Display/Screen will be compatible with the <code>parentNativeWindow</code>, | |
146 | * or even identical in case it's a Newt Window. | |
147 | * <P> | |
148 | * The resulting GLWindow owns the Window, ie it will be destructed. | |
149 | */ | |
29e3b223 | 150 | public static GLWindow create(NativeWindow parentNativeWindow, GLCapabilitiesImmutable caps) { |
0feca163 | 151 | return new GLWindow(NewtFactory.createWindow(parentNativeWindow, caps)); |
a959c53b | 152 | } |
a959c53b | 153 | |
0feca163 SG |
154 | //---------------------------------------------------------------------- |
155 | // Window Access | |
156 | // | |
a959c53b | 157 | |
7c159772 SG |
158 | public CapabilitiesChooser setCapabilitiesChooser(CapabilitiesChooser chooser) { |
159 | return window.setCapabilitiesChooser(chooser); | |
160 | } | |
161 | ||
e4913066 | 162 | public final CapabilitiesImmutable getChosenCapabilities() { |
0feca163 SG |
163 | if (drawable == null) { |
164 | return window.getChosenCapabilities(); | |
811bd23e | 165 | } |
811bd23e | 166 | |
0feca163 | 167 | return drawable.getChosenGLCapabilities(); |
a959c53b KR |
168 | } |
169 | ||
e4913066 | 170 | public final CapabilitiesImmutable getRequestedCapabilities() { |
0feca163 | 171 | return window.getRequestedCapabilities(); |
811bd23e SG |
172 | } |
173 | ||
0feca163 SG |
174 | public final Window getWindow() { |
175 | return window; | |
811bd23e SG |
176 | } |
177 | ||
018c7e86 SG |
178 | public final NativeWindow getParent() { |
179 | return window.getParent(); | |
811bd23e SG |
180 | } |
181 | ||
0feca163 | 182 | public final Screen getScreen() { |
a959c53b KR |
183 | return window.getScreen(); |
184 | } | |
185 | ||
0feca163 | 186 | public final void setTitle(String title) { |
a959c53b KR |
187 | window.setTitle(title); |
188 | } | |
189 | ||
0feca163 | 190 | public final String getTitle() { |
a959c53b KR |
191 | return window.getTitle(); |
192 | } | |
193 | ||
0feca163 | 194 | public final void setUndecorated(boolean value) { |
a959c53b KR |
195 | window.setUndecorated(value); |
196 | } | |
197 | ||
0feca163 | 198 | public final boolean isUndecorated() { |
a959c53b KR |
199 | return window.isUndecorated(); |
200 | } | |
201 | ||
0feca163 | 202 | public final void setFocusAction(FocusRunnable focusAction) { |
a4b16ad5 SG |
203 | window.setFocusAction(focusAction); |
204 | } | |
0feca163 SG |
205 | |
206 | public final void requestFocus() { | |
207 | window.requestFocus(); | |
811bd23e SG |
208 | } |
209 | ||
609e3083 SG |
210 | public boolean hasFocus() { |
211 | return window.hasFocus(); | |
212 | } | |
213 | ||
0feca163 SG |
214 | public final Insets getInsets() { |
215 | return window.getInsets(); | |
811bd23e | 216 | } |
a959c53b | 217 | |
0feca163 | 218 | public final void setPosition(int x, int y) { |
a959c53b KR |
219 | window.setPosition(x, y); |
220 | } | |
7bed517f | 221 | |
0feca163 | 222 | public final boolean setFullscreen(boolean fullscreen) { |
a959c53b KR |
223 | return window.setFullscreen(fullscreen); |
224 | } | |
0feca163 SG |
225 | |
226 | public final boolean isFullscreen() { | |
227 | return window.isFullscreen(); | |
811bd23e | 228 | } |
a959c53b | 229 | |
0feca163 | 230 | public final boolean isVisible() { |
a959c53b KR |
231 | return window.isVisible(); |
232 | } | |
233 | ||
0feca163 SG |
234 | public final String toString() { |
235 | return "NEWT-GLWindow[ \n\tHelper: " + helper + ", \n\tDrawable: " + drawable + | |
236 | ", \n\tContext: " + context + /** ", \n\tWindow: "+window+", \n\tFactory: "+factory+ */ "]"; | |
a959c53b KR |
237 | } |
238 | ||
0feca163 SG |
239 | public final int reparentWindow(NativeWindow newParent) { |
240 | return window.reparentWindow(newParent); | |
a959c53b KR |
241 | } |
242 | ||
0feca163 SG |
243 | public final int reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) { |
244 | return window.reparentWindow(newParent, forceDestroyCreate); | |
a959c53b KR |
245 | } |
246 | ||
0feca163 SG |
247 | public final void removeChild(NativeWindow win) { |
248 | window.removeChild(win); | |
a959c53b KR |
249 | } |
250 | ||
0feca163 SG |
251 | public final void addChild(NativeWindow win) { |
252 | window.addChild(win); | |
a959c53b | 253 | } |
2aa29677 | 254 | |
0feca163 SG |
255 | //---------------------------------------------------------------------- |
256 | // Window.LifecycleHook Implementation | |
257 | // | |
969e4276 | 258 | |
db4d7d19 SG |
259 | public final void destroy() { |
260 | window.destroy(); | |
bf584fba SG |
261 | } |
262 | ||
0feca163 SG |
263 | public final void setVisible(boolean visible) { |
264 | window.setVisible(visible); | |
a959c53b KR |
265 | } |
266 | ||
0feca163 SG |
267 | public final void setSize(int width, int height) { |
268 | window.setSize(width, height); | |
a959c53b KR |
269 | } |
270 | ||
0feca163 SG |
271 | public final boolean isValid() { |
272 | return window.isValid(); | |
969e4276 | 273 | } |
a959c53b | 274 | |
0feca163 SG |
275 | public final boolean isNativeValid() { |
276 | return window.isNativeValid(); | |
a959c53b KR |
277 | } |
278 | ||
018c7e86 SG |
279 | public Point getLocationOnScreen(Point storage) { |
280 | return window.getLocationOnScreen(storage); | |
281 | } | |
282 | ||
0feca163 SG |
283 | // Hide methods here .. |
284 | protected class GLLifecycleHook implements WindowImpl.LifecycleHook { | |
285 | ||
286 | class DisposeAction implements Runnable { | |
287 | public void run() { | |
288 | // Lock: Covered by DestroyAction .. | |
289 | helper.dispose(GLWindow.this); | |
290 | } | |
291 | } | |
292 | DisposeAction disposeAction = new DisposeAction(); | |
293 | ||
db4d7d19 SG |
294 | public synchronized void destroyActionPreLock() { |
295 | // nop | |
e6225fce SG |
296 | } |
297 | ||
db4d7d19 | 298 | public synchronized void destroyActionInLock() { |
0feca163 | 299 | if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { |
db4d7d19 | 300 | String msg = new String("GLWindow.destroy() "+Thread.currentThread()+", start"); |
0feca163 SG |
301 | System.err.println(msg); |
302 | //Exception e1 = new Exception(msg); | |
303 | //e1.printStackTrace(); | |
304 | } | |
305 | ||
306 | if( window.isNativeValid() && null != drawable && drawable.isRealized() ) { | |
307 | if( null != context && context.isCreated() ) { | |
308 | // Catch dispose GLExceptions by GLEventListener, just 'print' them | |
309 | // so we can continue with the destruction. | |
310 | try { | |
311 | helper.invokeGL(drawable, context, disposeAction, null); | |
312 | } catch (GLException gle) { | |
313 | gle.printStackTrace(); | |
314 | } | |
315 | context.destroy(); | |
316 | } | |
317 | drawable.setRealized(false); | |
318 | } | |
319 | context = null; | |
320 | drawable = null; | |
321 | ||
db4d7d19 SG |
322 | if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { |
323 | System.err.println("GLWindow.destroy() "+Thread.currentThread()+", fin"); | |
0feca163 | 324 | } |
db4d7d19 | 325 | } |
0feca163 | 326 | |
db4d7d19 | 327 | public synchronized void invalidate(boolean unrecoverable) { |
0feca163 | 328 | if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { |
db4d7d19 SG |
329 | String msg = new String("GLWindow.invalidate("+unrecoverable+") "+Thread.currentThread()+", start"); |
330 | System.err.println(msg); | |
331 | //Exception e1 = new Exception(msg); | |
332 | //e1.printStackTrace(); | |
333 | } | |
334 | if(unrecoverable) { | |
335 | GLAnimatorControl ctrl = GLWindow.this.getAnimator(); | |
2aa29677 SG |
336 | if ( null!=ctrl ) { |
337 | ctrl.remove(GLWindow.this); | |
db4d7d19 SG |
338 | } |
339 | helper=null; | |
0feca163 SG |
340 | } |
341 | } | |
342 | ||
2c1a870f | 343 | public synchronized void resetCounter() { |
0feca163 | 344 | if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { |
2c1a870f SG |
345 | System.err.println("GLWindow.resetCounter() "+Thread.currentThread()); |
346 | } | |
347 | GLWindow.this.resetCounter(); | |
348 | } | |
349 | ||
350 | public synchronized void setVisibleActionPost(boolean visible, boolean nativeWindowCreated) { | |
351 | if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { | |
352 | String msg = new String("GLWindow.setVisibleActionPost("+visible+", "+nativeWindowCreated+") "+Thread.currentThread()+", start"); | |
0feca163 SG |
353 | System.err.println(msg); |
354 | // Exception e1 = new Exception(msg); | |
355 | // e1.printStackTrace(); | |
356 | } | |
357 | ||
358 | /* if (nativeWindowCreated && null != context) { | |
359 | throw new GLException("InternalError: Native Windows has been just created, but context wasn't destroyed (is not null)"); | |
360 | } */ | |
361 | if (null == context && visible && 0 != window.getWindowHandle() && 0<getWidth()*getHeight()) { | |
362 | NativeWindow nw; | |
363 | if (window.getWrappedWindow() != null) { | |
364 | nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration()); | |
365 | } else { | |
366 | nw = window; | |
367 | } | |
29e3b223 | 368 | GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) nw.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); |
0feca163 SG |
369 | if(null==factory) { |
370 | factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); | |
371 | } | |
372 | if(null==drawable) { | |
373 | drawable = factory.createGLDrawable(nw); | |
374 | } | |
375 | drawable.setRealized(true); | |
fd0d3f15 | 376 | context = drawable.createContext(sharedContext); |
0feca163 SG |
377 | } |
378 | if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { | |
2c1a870f | 379 | String msg = new String("GLWindow.setVisibleActionPost("+visible+", "+nativeWindowCreated+") "+Thread.currentThread()+", fin"); |
0feca163 SG |
380 | System.err.println(msg); |
381 | //Exception e1 = new Exception(msg); | |
382 | //e1.printStackTrace(); | |
383 | } | |
384 | } | |
2aa29677 SG |
385 | |
386 | public synchronized boolean pauseRenderingAction() { | |
387 | boolean animatorPaused = false; | |
0feca163 | 388 | GLAnimatorControl ctrl = GLWindow.this.getAnimator(); |
4c3e9e25 SG |
389 | if ( null!=ctrl ) { |
390 | animatorPaused = ctrl.pause(); | |
0feca163 | 391 | } |
2aa29677 | 392 | return animatorPaused; |
0feca163 SG |
393 | } |
394 | ||
a0e9d6c8 | 395 | public synchronized void resumeRenderingAction() { |
0feca163 | 396 | GLAnimatorControl ctrl = GLWindow.this.getAnimator(); |
2aa29677 | 397 | if ( null!=ctrl && ctrl.isPaused() ) { |
0feca163 SG |
398 | ctrl.resume(); |
399 | } | |
400 | } | |
401 | } | |
a0e9d6c8 | 402 | |
a959c53b KR |
403 | //---------------------------------------------------------------------- |
404 | // OpenGL-related methods and state | |
405 | // | |
406 | ||
fd0d3f15 | 407 | private GLContext sharedContext = null; |
a959c53b KR |
408 | private GLDrawableFactory factory; |
409 | private GLDrawable drawable; | |
410 | private GLContext context; | |
411 | private GLDrawableHelper helper = new GLDrawableHelper(); | |
412 | // To make reshape events be sent immediately before a display event | |
413 | private boolean sendReshape=false; | |
414 | private boolean sendDestroy=false; | |
415 | private boolean perfLog = false; | |
0feca163 SG |
416 | private long startTime, curTime, lastCheck; |
417 | private int totalFrames, lastFrames; | |
418 | ||
a959c53b KR |
419 | public GLDrawableFactory getFactory() { |
420 | return factory; | |
421 | } | |
422 | ||
fd0d3f15 SG |
423 | /** |
424 | * Specifies an {@link javax.media.opengl.GLContext OpenGL context} to share with.<br> | |
425 | * At native creation, {@link #setVisible(boolean) setVisible(true)}, | |
426 | * a {@link javax.media.opengl.GLDrawable drawable} and {@link javax.media.opengl.GLContext context} is created besides the native Window itself,<br> | |
427 | * hence you shall set the shared context before. | |
428 | * | |
429 | * @param sharedContext The OpenGL context shared by this GLWindow's one | |
430 | */ | |
431 | public void setSharedContext(GLContext sharedContext) { | |
432 | this.sharedContext = sharedContext; | |
433 | } | |
434 | ||
a959c53b KR |
435 | public void setContext(GLContext newCtx) { |
436 | context = newCtx; | |
437 | } | |
438 | ||
439 | public GLContext getContext() { | |
440 | return context; | |
441 | } | |
442 | ||
443 | public GL getGL() { | |
444 | if (context == null) { | |
445 | return null; | |
446 | } | |
447 | return context.getGL(); | |
448 | } | |
449 | ||
4e0a5af0 | 450 | public GL setGL(GL gl) { |
a959c53b KR |
451 | if (context != null) { |
452 | context.setGL(gl); | |
4e0a5af0 | 453 | return gl; |
a959c53b | 454 | } |
4e0a5af0 | 455 | return null; |
a959c53b KR |
456 | } |
457 | ||
458 | public void addGLEventListener(GLEventListener listener) { | |
77413854 SG |
459 | if(null!=helper) { |
460 | helper.addGLEventListener(listener); | |
461 | } | |
a959c53b KR |
462 | } |
463 | ||
302f183c | 464 | public void addGLEventListener(int index, GLEventListener listener) { |
77413854 SG |
465 | if(null!=helper) { |
466 | helper.addGLEventListener(index, listener); | |
467 | } | |
302f183c SG |
468 | } |
469 | ||
a959c53b | 470 | public void removeGLEventListener(GLEventListener listener) { |
77413854 SG |
471 | if(null!=helper) { |
472 | helper.removeGLEventListener(listener); | |
473 | } | |
a959c53b KR |
474 | } |
475 | ||
0feca163 | 476 | public void setAnimator(GLAnimatorControl animatorControl) { |
77413854 SG |
477 | if(null!=helper) { |
478 | helper.setAnimator(animatorControl); | |
479 | } | |
969e4276 SG |
480 | } |
481 | ||
0feca163 | 482 | public GLAnimatorControl getAnimator() { |
77413854 SG |
483 | if(null!=helper) { |
484 | return helper.getAnimator(); | |
485 | } | |
486 | return null; | |
969e4276 SG |
487 | } |
488 | ||
0feca163 SG |
489 | public boolean getPerfLogEnabled() { return perfLog; } |
490 | ||
491 | public void enablePerfLog(boolean v) { | |
492 | perfLog = v; | |
493 | } | |
494 | ||
0d24458c | 495 | public void invoke(boolean wait, GLRunnable glRunnable) { |
77413854 SG |
496 | if(null!=helper) { |
497 | helper.invoke(this, wait, glRunnable); | |
498 | } | |
0d24458c SG |
499 | } |
500 | ||
a959c53b | 501 | public void display() { |
cf4c4037 SG |
502 | display(false); |
503 | } | |
504 | ||
505 | public void display(boolean forceReshape) { | |
6e599a26 SG |
506 | if( null == window ) { return; } |
507 | ||
969e4276 | 508 | if(sendDestroy || ( null!=window && window.hasDeviceChanged() && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) ) { |
63be4a40 SG |
509 | sendDestroy=false; |
510 | destroy(); | |
511 | return; | |
512 | } | |
969e4276 | 513 | |
5e1a67c9 | 514 | if( null == context && isVisible() && 0<getWidth()*getHeight() ) { |
6e599a26 SG |
515 | // retry native window and drawable/context creation |
516 | setVisible(true); | |
517 | } | |
518 | ||
2aa29677 SG |
519 | if(forceReshape) { |
520 | sendReshape = true; | |
521 | } | |
522 | ||
523 | if( isVisible() && null != context ) { | |
c8a9c59e | 524 | if( NativeSurface.LOCK_SURFACE_NOT_READY < lockSurface() ) { |
1d265b51 | 525 | try { |
c8a9c59e SG |
526 | helper.invokeGL(drawable, context, displayAction, initAction); |
527 | } finally { | |
528 | unlockSurface(); | |
529 | } | |
a959c53b KR |
530 | } |
531 | } | |
532 | } | |
533 | ||
a92906bc | 534 | /** This implementation uses a static value */ |
a959c53b | 535 | public void setAutoSwapBufferMode(boolean onOrOff) { |
77413854 SG |
536 | if(null!=helper) { |
537 | helper.setAutoSwapBufferMode(onOrOff); | |
538 | } | |
a959c53b KR |
539 | } |
540 | ||
a92906bc | 541 | /** This implementation uses a static value */ |
a959c53b | 542 | public boolean getAutoSwapBufferMode() { |
77413854 SG |
543 | if(null!=helper) { |
544 | return helper.getAutoSwapBufferMode(); | |
545 | } | |
546 | return false; | |
a959c53b KR |
547 | } |
548 | ||
549 | public void swapBuffers() { | |
2268a6ce | 550 | if(drawable!=null && context != null) { |
1d333a77 | 551 | // Lock: Locked Surface/Window by MakeCurrent/Release |
2268a6ce | 552 | if (context != GLContext.getCurrent()) { |
a959c53b KR |
553 | // Assume we should try to make the context current before swapping the buffers |
554 | helper.invokeGL(drawable, context, swapBuffersAction, initAction); | |
555 | } else { | |
556 | drawable.swapBuffers(); | |
557 | } | |
558 | } | |
559 | } | |
560 | ||
561 | class InitAction implements Runnable { | |
562 | public void run() { | |
1d333a77 | 563 | // Lock: Locked Surface/Window by MakeCurrent/Release |
a959c53b | 564 | helper.init(GLWindow.this); |
018c7e86 | 565 | resetCounter(); |
a959c53b KR |
566 | } |
567 | } | |
568 | private InitAction initAction = new InitAction(); | |
569 | ||
a959c53b KR |
570 | class DisplayAction implements Runnable { |
571 | public void run() { | |
1d333a77 | 572 | // Lock: Locked Surface/Window by display _and_ MakeCurrent/Release |
a959c53b | 573 | if (sendReshape) { |
969e4276 | 574 | helper.reshape(GLWindow.this, 0, 0, getWidth(), getHeight()); |
a959c53b KR |
575 | sendReshape = false; |
576 | } | |
577 | ||
578 | helper.display(GLWindow.this); | |
579 | ||
580 | curTime = System.currentTimeMillis(); | |
581 | totalFrames++; | |
582 | ||
583 | if(perfLog) { | |
584 | long dt0, dt1; | |
585 | lastFrames++; | |
586 | dt0 = curTime-lastCheck; | |
587 | if ( dt0 > 5000 ) { | |
588 | dt1 = curTime-startTime; | |
0feca163 | 589 | System.err.println(dt0/1000 +"s: "+ lastFrames + "f, " + (lastFrames*1000)/dt0 + " fps, "+dt0/lastFrames+" ms/f; "+ |
a959c53b KR |
590 | "total: "+ dt1/1000+"s, "+(totalFrames*1000)/dt1 + " fps, "+dt1/totalFrames+" ms/f"); |
591 | lastCheck=curTime; | |
592 | lastFrames=0; | |
593 | } | |
594 | } | |
595 | } | |
596 | } | |
a92906bc | 597 | private DisplayAction displayAction = new DisplayAction(); |
a959c53b | 598 | |
0feca163 SG |
599 | /** |
600 | * @return Time of the first display call in milliseconds. | |
601 | * This value is reset if becoming visible again or reparenting. | |
0feca163 SG |
602 | */ |
603 | public final long getStartTime() { | |
018c7e86 | 604 | return startTime; |
0feca163 | 605 | } |
a959c53b | 606 | |
0feca163 SG |
607 | /** |
608 | * @return Time of the last display call in milliseconds. | |
609 | * This value is reset if becoming visible again or reparenting. | |
0feca163 SG |
610 | */ |
611 | public final long getCurrentTime() { | |
018c7e86 | 612 | return curTime; |
0feca163 SG |
613 | } |
614 | ||
615 | /** | |
616 | * @return Duration <code>getCurrentTime() - getStartTime()</code>. | |
617 | * | |
618 | * @see #getStartTime() | |
619 | * @see #getCurrentTime() | |
620 | */ | |
621 | public final long getDuration() { | |
622 | return getCurrentTime()-getStartTime(); | |
623 | } | |
624 | ||
625 | /** | |
626 | * @return Number of frames displayed since the first display call, ie <code>getStartTime()</code>. | |
627 | * This value is reset if becoming visible again or reparenting. | |
0feca163 | 628 | */ |
018c7e86 SG |
629 | public final int getTotalFrames() { |
630 | return totalFrames; | |
631 | } | |
632 | ||
633 | /** Reset all counter (startTime, currentTime, frame number) */ | |
634 | public synchronized void resetCounter() { | |
635 | startTime = System.currentTimeMillis(); // overwrite startTime to real init one | |
636 | curTime = startTime; | |
637 | lastCheck = startTime; | |
638 | totalFrames = 0; lastFrames = 0; | |
0feca163 | 639 | } |
a959c53b | 640 | |
a959c53b KR |
641 | class SwapBuffersAction implements Runnable { |
642 | public void run() { | |
643 | drawable.swapBuffers(); | |
644 | } | |
645 | } | |
a959c53b KR |
646 | private SwapBuffersAction swapBuffersAction = new SwapBuffersAction(); |
647 | ||
648 | //---------------------------------------------------------------------- | |
0feca163 | 649 | // GLDrawable methods |
a959c53b KR |
650 | // |
651 | ||
018c7e86 SG |
652 | public final NativeSurface getNativeSurface() { |
653 | return null!=drawable ? drawable.getNativeSurface() : null; | |
a959c53b KR |
654 | } |
655 | ||
0feca163 SG |
656 | public final long getHandle() { |
657 | return null!=drawable ? drawable.getHandle() : 0; | |
8883fa88 | 658 | } |
659 | ||
0feca163 SG |
660 | public final int getX() { |
661 | return window.getX(); | |
6e599a26 SG |
662 | } |
663 | ||
0feca163 SG |
664 | public final int getY() { |
665 | return window.getY(); | |
6e599a26 SG |
666 | } |
667 | ||
0feca163 SG |
668 | public final int getWidth() { |
669 | return window.getWidth(); | |
a959c53b KR |
670 | } |
671 | ||
0feca163 SG |
672 | public final int getHeight() { |
673 | return window.getHeight(); | |
1d333a77 SG |
674 | } |
675 | ||
a959c53b KR |
676 | //---------------------------------------------------------------------- |
677 | // GLDrawable methods that are not really needed | |
678 | // | |
679 | ||
0feca163 | 680 | public final GLContext createContext(GLContext shareWith) { |
a959c53b KR |
681 | return drawable.createContext(shareWith); |
682 | } | |
683 | ||
0feca163 | 684 | public final void setRealized(boolean realized) { |
a959c53b KR |
685 | } |
686 | ||
0feca163 | 687 | public final boolean isRealized() { |
811bd23e SG |
688 | return ( null != drawable ) ? drawable.isRealized() : false; |
689 | } | |
690 | ||
29e3b223 | 691 | public final GLCapabilitiesImmutable getChosenGLCapabilities() { |
a959c53b KR |
692 | if (drawable == null) { |
693 | throw new GLException("No drawable yet"); | |
694 | } | |
695 | ||
696 | return drawable.getChosenGLCapabilities(); | |
697 | } | |
698 | ||
0feca163 | 699 | public final GLProfile getGLProfile() { |
a959c53b KR |
700 | if (drawable == null) { |
701 | throw new GLException("No drawable yet"); | |
702 | } | |
703 | ||
704 | return drawable.getGLProfile(); | |
705 | } | |
0feca163 SG |
706 | |
707 | //---------------------------------------------------------------------- | |
1b7b5d34 SG |
708 | // NEWTEventConsumer |
709 | // | |
710 | public boolean consumeEvent(NEWTEvent event) { | |
711 | return window.consumeEvent(event); | |
712 | } | |
713 | ||
714 | //---------------------------------------------------------------------- | |
0feca163 SG |
715 | // Window completion |
716 | // | |
717 | public final void windowRepaint(int x, int y, int width, int height) { | |
718 | window.windowRepaint(x, y, width, height); | |
719 | } | |
720 | ||
721 | public final void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) { | |
722 | window.enqueueEvent(wait, event); | |
723 | } | |
724 | ||
725 | public final void runOnEDTIfAvail(boolean wait, final Runnable task) { | |
726 | window.runOnEDTIfAvail(wait, task); | |
727 | } | |
728 | ||
729 | public final SurfaceUpdatedListener getSurfaceUpdatedListener(int index) { | |
730 | return window.getSurfaceUpdatedListener(index); | |
731 | } | |
732 | ||
733 | public final SurfaceUpdatedListener[] getSurfaceUpdatedListeners() { | |
734 | return window.getSurfaceUpdatedListeners(); | |
735 | } | |
736 | ||
737 | public final void removeAllSurfaceUpdatedListener() { | |
738 | window.removeAllSurfaceUpdatedListener(); | |
739 | } | |
740 | ||
741 | public final void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { | |
742 | window.removeSurfaceUpdatedListener(l); | |
743 | } | |
744 | ||
745 | public final void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { | |
746 | window.addSurfaceUpdatedListener(l); | |
747 | } | |
748 | ||
749 | public final void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { | |
750 | window.addSurfaceUpdatedListener(index, l); | |
751 | } | |
752 | ||
753 | public void sendWindowEvent(int eventType) { | |
754 | window.sendWindowEvent(eventType); | |
755 | } | |
756 | ||
757 | public final WindowListener getWindowListener(int index) { | |
758 | return window.getWindowListener(index); | |
759 | } | |
760 | ||
761 | public final WindowListener[] getWindowListeners() { | |
762 | return window.getWindowListeners(); | |
763 | } | |
764 | ||
765 | public final void removeWindowListener(WindowListener l) { | |
766 | window.removeWindowListener(l); | |
767 | } | |
768 | ||
769 | public final void addWindowListener(WindowListener l) { | |
770 | window.addWindowListener(l); | |
771 | } | |
772 | ||
773 | public final void addWindowListener(int index, WindowListener l) throws IndexOutOfBoundsException { | |
774 | window.addWindowListener(index, l); | |
775 | } | |
776 | ||
777 | public final void addKeyListener(KeyListener l) { | |
778 | window.addKeyListener(l); | |
779 | } | |
780 | ||
781 | public final void addKeyListener(int index, KeyListener l) { | |
782 | window.addKeyListener(index, l); | |
783 | } | |
784 | ||
785 | public final void removeKeyListener(KeyListener l) { | |
786 | window.removeKeyListener(l); | |
787 | } | |
788 | ||
789 | public final KeyListener getKeyListener(int index) { | |
790 | return window.getKeyListener(index); | |
791 | } | |
792 | ||
793 | public final KeyListener[] getKeyListeners() { | |
794 | return window.getKeyListeners(); | |
795 | } | |
796 | ||
797 | public final void addMouseListener(MouseListener l) { | |
798 | window.addMouseListener(l); | |
799 | } | |
800 | ||
801 | public final void addMouseListener(int index, MouseListener l) { | |
802 | window.addMouseListener(index, l); | |
803 | } | |
804 | ||
805 | public final void removeMouseListener(MouseListener l) { | |
806 | window.removeMouseListener(l); | |
807 | } | |
808 | ||
809 | public final MouseListener getMouseListener(int index) { | |
810 | return window.getMouseListener(index); | |
811 | } | |
812 | ||
813 | public final MouseListener[] getMouseListeners() { | |
814 | return window.getMouseListeners(); | |
815 | } | |
816 | ||
817 | //---------------------------------------------------------------------- | |
818 | // NativeWindow completion | |
819 | // | |
820 | ||
821 | public final int lockSurface() { | |
822 | return window.lockSurface(); | |
823 | } | |
824 | ||
825 | public final void unlockSurface() throws NativeWindowException { | |
826 | window.unlockSurface(); | |
827 | } | |
828 | ||
829 | public final boolean isSurfaceLockedByOtherThread() { | |
830 | return window.isSurfaceLockedByOtherThread(); | |
831 | } | |
832 | ||
833 | public final boolean isSurfaceLocked() { | |
834 | return window.isSurfaceLocked(); | |
835 | } | |
836 | ||
837 | public final Thread getSurfaceLockOwner() { | |
838 | return window.getSurfaceLockOwner(); | |
839 | ||
840 | } | |
841 | ||
0feca163 SG |
842 | public final boolean surfaceSwap() { |
843 | return window.surfaceSwap(); | |
844 | } | |
845 | ||
846 | public final void invalidate() { | |
847 | window.invalidate(); | |
848 | } | |
849 | ||
850 | public final long getWindowHandle() { | |
851 | return window.getWindowHandle(); | |
852 | ||
853 | } | |
854 | ||
855 | public final long getSurfaceHandle() { | |
856 | return window.getSurfaceHandle(); | |
857 | ||
858 | } | |
859 | ||
860 | public final AbstractGraphicsConfiguration getGraphicsConfiguration() { | |
861 | return window.getGraphicsConfiguration(); | |
862 | } | |
863 | ||
864 | public final long getDisplayHandle() { | |
865 | return window.getDisplayHandle(); | |
866 | } | |
867 | ||
868 | public final int getScreenIndex() { | |
869 | return window.getScreenIndex(); | |
870 | } | |
871 | ||
018c7e86 SG |
872 | public final void surfaceUpdated(Object updater, NativeSurface ns, long when) { |
873 | window.surfaceUpdated(updater, ns, when); | |
0feca163 | 874 | } |
597d10f5 SG |
875 | |
876 | /** | |
877 | * A most simple JOGL AWT test entry | |
878 | */ | |
879 | public static void main(String args[]) { | |
8c9f3bb3 | 880 | System.err.println(VersionUtil.getPlatformInfo()); |
6ea02e25 SG |
881 | System.err.println(GlueGenVersion.getInstance()); |
882 | System.err.println(NativeWindowVersion.getInstance()); | |
2aa90676 | 883 | System.err.println(JoglVersion.getInstance()); |
6ea02e25 | 884 | System.err.println(NewtVersion.getInstance()); |
29e3b223 | 885 | GLCapabilitiesImmutable caps = new GLCapabilities( GLProfile.getDefault() ); |
597d10f5 SG |
886 | |
887 | GLWindow glWindow = GLWindow.create(caps); | |
888 | glWindow.setSize(128, 128); | |
889 | ||
890 | glWindow.addGLEventListener(new GLEventListener() { | |
891 | public void init(GLAutoDrawable drawable) { | |
892 | GL gl = drawable.getGL(); | |
2aa90676 | 893 | System.err.println(JoglVersion.getInstance().getGLInfo(gl, null)); |
597d10f5 SG |
894 | } |
895 | ||
896 | public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { | |
897 | } | |
898 | ||
899 | public void display(GLAutoDrawable drawable) { | |
900 | } | |
901 | ||
902 | public void dispose(GLAutoDrawable drawable) { | |
903 | } | |
904 | }); | |
905 | ||
906 | glWindow.setVisible(true); | |
db4d7d19 | 907 | glWindow.invalidate(); |
597d10f5 SG |
908 | } |
909 | ||
a959c53b | 910 | } |
http://JogAmp.org | git info: FAQ, tutorial and man pages. |