Jogamp
Fix comments
[jogl.git] / src / newt / classes / com / jogamp / newt / opengl / GLWindow.java
CommitLineData
a959c53b
KR
1/*
2 * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * - Redistribution of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistribution in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * Neither the name of Sun Microsystems, Inc. or the names of
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * This software is provided "AS IS," without a warranty of any kind. ALL
20 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
23 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
24 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
25 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
26 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
27 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
28 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
29 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
30 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31 *
32 */
33
2d57c252 34package com.jogamp.newt.opengl;
a959c53b 35
2d57c252 36import com.jogamp.newt.*;
1ad8c39d 37import com.jogamp.newt.event.*;
a959c53b
KR
38import javax.media.nativewindow.*;
39import javax.media.opengl.*;
f3bc93b0 40import com.jogamp.opengl.impl.GLDrawableHelper;
a92906bc 41import java.util.*;
a959c53b
KR
42
43/**
44 * An implementation of {@link Window} which is customized for OpenGL
2268a6ce
SG
45 * use, and which implements the {@link javax.media.opengl.GLAutoDrawable} interface.
46 * <P>
47 * This implementation does not make the OpenGL context current<br>
48 * before calling the various input EventListener callbacks (MouseListener, KeyListener,
49 * etc.).<br>
50 * This design decision is made to favor a more performant and simplified
51 * implementation, as well as the event dispatcher shall be allowed
52 * not having a notion about OpenGL.
53 * <p>
a959c53b
KR
54 */
55public class GLWindow extends Window implements GLAutoDrawable {
a92906bc
SG
56 private static List/*GLWindow*/ glwindows = new ArrayList();
57
eab82899 58 private boolean ownerOfWinScrDpy;
a959c53b 59 private Window window;
2268a6ce 60 private boolean runPumpMessages;
a959c53b 61
476d1d75
MB
62 /**
63 * Constructor. Do not call this directly -- use {@link #create()} instead.
64 */
eab82899
SG
65 protected GLWindow(Window window, boolean ownerOfWinScrDpy) {
66 this.ownerOfWinScrDpy = ownerOfWinScrDpy;
a959c53b
KR
67 this.window = window;
68 this.window.setAutoDrawableClient(true);
1c1053c6 69 this.runPumpMessages = ( null == getScreen().getDisplay().getEDTUtil() ) ;
1ad8c39d 70 window.addWindowListener(new WindowAdapter() {
a959c53b
KR
71 public void windowResized(WindowEvent e) {
72 sendReshape = true;
73 }
74
a959c53b
KR
75 public void windowDestroyNotify(WindowEvent e) {
76 sendDestroy = true;
77 }
78 });
a92906bc
SG
79
80 List newglw = (List) ((ArrayList) glwindows).clone();
81 newglw.add(this);
82 glwindows=newglw;
a959c53b
KR
83 }
84
85 /** Creates a new GLWindow on the local display, screen 0, with a
86 dummy visual ID, and with the default GLCapabilities. */
87 public static GLWindow create() {
88 return create(null, null, false);
89 }
90
91 public static GLWindow create(boolean undecorated) {
92 return create(null, null, undecorated);
93 }
94
95 /** Creates a new GLWindow referring to the given window. */
96 public static GLWindow create(Window window) {
97 return create(window, null, false);
98 }
99 public static GLWindow create(GLCapabilities caps) {
100 return create(null, caps, false);
101 }
102
103 /** Creates a new GLWindow on the local display, screen 0, with a
104 dummy visual ID, and with the given GLCapabilities. */
105 public static GLWindow create(GLCapabilities caps, boolean undecorated) {
106 return create(null, caps, undecorated);
107 }
108
3cc7335e
SG
109 /** Either or: window (prio), or caps and undecorated (2nd choice) */
110 private static GLWindow create(Window window,
111 GLCapabilities caps,
112 boolean undecorated) {
a92906bc 113 Display display;
eab82899 114 boolean ownerOfWinScrDpy=false;
a959c53b 115 if (window == null) {
3cc7335e
SG
116 if (caps == null) {
117 caps = new GLCapabilities(null); // default ..
118 }
eab82899 119 ownerOfWinScrDpy = true;
a92906bc 120 display = NewtFactory.createDisplay(null); // local display
a959c53b
KR
121 Screen screen = NewtFactory.createScreen(display, 0); // screen 0
122 window = NewtFactory.createWindow(screen, caps, undecorated);
123 }
124
eab82899 125 return new GLWindow(window, ownerOfWinScrDpy);
a959c53b
KR
126 }
127
a92906bc
SG
128 /**
129 * EXPERIMENTAL<br>
130 * Enable or disables running the {@link Display#pumpMessages} in the {@link #display()} call.<br>
131 * The default behavior is to run {@link Display#pumpMessages}.<P>
132 *
133 * The idea was that in a single threaded environment with one {@link Display} and many {@link Window}'s,
134 * a performance benefit was expected while disabling the implicit {@link Display#pumpMessages} and
135 * do it once via {@link GLWindow#runCurrentThreadPumpMessage()} <br>
136 * This could not have been verified. No measurable difference could have been recognized.<P>
137 *
138 * Best performance has been achieved with one GLWindow per thread.<br>
139 *
2268a6ce 140 * Enabling local pump messages while using the EDT,
2d57c252 141 * {@link com.jogamp.newt.NewtFactory#setUseEDT(boolean)},
2268a6ce
SG
142 * will result in an exception.
143 *
a92906bc
SG
144 * @deprecated EXPERIMENTAL, semantic is about to be removed after further verification.
145 */
146 public void setRunPumpMessages(boolean onoff) {
1c1053c6 147 if( onoff && null!=getScreen().getDisplay().getEDTUtil() ) {
2268a6ce
SG
148 throw new GLException("GLWindow.setRunPumpMessages(true) - Can't do with EDT on");
149 }
a92906bc
SG
150 runPumpMessages = onoff;
151 }
152
3cc7335e 153 protected void createNative(long parentWindowHandle, Capabilities caps) {
a959c53b
KR
154 shouldNotCallThis();
155 }
156
157 protected void closeNative() {
158 shouldNotCallThis();
159 }
160
eab82899 161 protected void dispose(boolean regenerate, boolean sendEvent) {
a959c53b 162 if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
eab82899 163 Exception e1 = new Exception("GLWindow.dispose("+regenerate+") "+Thread.currentThread()+", 1");
a959c53b
KR
164 e1.printStackTrace();
165 }
166
eab82899
SG
167 if(sendEvent) {
168 sendDisposeEvent();
169 }
a959c53b
KR
170
171 if (context != null) {
172 context.destroy();
173 }
174 if (drawable != null) {
175 drawable.setRealized(false);
176 }
177
a959c53b
KR
178 if(regenerate) {
179 if(null==window) {
180 throw new GLException("GLWindow.dispose(true): null window");
181 }
182
183 // recreate GLDrawable, to reflect the new graphics configurations
184 NativeWindow nw;
185 if (window.getWrappedWindow() != null) {
186 nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration());
187 } else {
188 nw = window;
189 }
190 drawable = factory.createGLDrawable(nw);
191 drawable.setRealized(true);
a959c53b
KR
192 context = drawable.createContext(null);
193 sendReshape = true; // ensure a reshape event is send ..
194 }
195
196 if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
2268a6ce 197 System.out.println("GLWindow.dispose("+regenerate+") "+Thread.currentThread()+", fin: "+this);
a959c53b
KR
198 }
199 }
200
201 public synchronized void destroy() {
eab82899 202 destroy(true);
2268a6ce
SG
203 }
204
eab82899
SG
205 /** @param sendDisposeEvent should be false in a [time,reliable] critical shutdown */
206 public synchronized void destroy(boolean sendDisposeEvent) {
a959c53b 207 if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
2268a6ce 208 Exception e1 = new Exception("GLWindow.destroy "+Thread.currentThread()+", 1: "+this);
a959c53b
KR
209 e1.printStackTrace();
210 }
211
a92906bc
SG
212 List newglw = (List) ((ArrayList) glwindows).clone();
213 newglw.remove(this);
214 glwindows=newglw;
215
eab82899 216 dispose(false, sendDisposeEvent);
a959c53b 217
a959c53b 218 if(null!=window) {
eab82899
SG
219 if(ownerOfWinScrDpy) {
220 window.destroy(true);
a959c53b 221 }
a959c53b
KR
222 }
223
224 drawable = null;
225 context = null;
eab82899 226 window = null;
a959c53b 227
eab82899
SG
228 if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
229 System.out.println("GLWindow.destroy "+Thread.currentThread()+", fin: "+this);
a959c53b 230 }
a959c53b
KR
231 }
232
233 public boolean getPerfLogEnabled() { return perfLog; }
234
235 public void enablePerfLog(boolean v) {
236 perfLog = v;
237 }
238
a959c53b 239 public void setVisible(boolean visible) {
2268a6ce
SG
240 if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
241 System.out.println(Thread.currentThread()+" GLWindow.setVisible("+visible+") START ; isVisible "+this.visible+" ; has context "+(null!=context));
242 }
243 this.visible=visible;
a959c53b
KR
244 window.setVisible(visible);
245 if (visible && context == null) {
246 NativeWindow nw;
247 if (window.getWrappedWindow() != null) {
248 nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration());
249 } else {
250 nw = window;
251 }
252 GLCapabilities glCaps = (GLCapabilities) nw.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities();
253 factory = GLDrawableFactory.getFactory(glCaps.getGLProfile());
254 drawable = factory.createGLDrawable(nw);
255 drawable.setRealized(true);
a959c53b
KR
256 context = drawable.createContext(null);
257 sendReshape = true; // ensure a reshape event is send ..
258 }
2268a6ce
SG
259 if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
260 System.out.println(Thread.currentThread()+" GLWindow.setVisible("+visible+") END ; has context "+(null!=context));
261 }
a959c53b
KR
262 }
263
264 public Screen getScreen() {
265 return window.getScreen();
266 }
267
268 public void setTitle(String title) {
269 window.setTitle(title);
270 }
271
272 public String getTitle() {
273 return window.getTitle();
274 }
275
276 public void setUndecorated(boolean value) {
277 window.setUndecorated(value);
278 }
279
280 public boolean isUndecorated() {
281 return window.isUndecorated();
282 }
283
284 public void setSize(int width, int height) {
285 window.setSize(width, height);
286 }
287
288 public void setPosition(int x, int y) {
289 window.setPosition(x, y);
290 }
291
7bed517f 292 public Insets getInsets() {
293 return window.getInsets();
294 }
295
a959c53b
KR
296 public boolean setFullscreen(boolean fullscreen) {
297 return window.setFullscreen(fullscreen);
298 }
299
300 public boolean isVisible() {
301 return window.isVisible();
302 }
303
304 public int getX() {
305 return window.getX();
306 }
307
308 public int getY() {
309 return window.getY();
310 }
311
312 public int getWidth() {
313 return window.getWidth();
314 }
315
316 public int getHeight() {
317 return window.getHeight();
318 }
319
320 public boolean isFullscreen() {
321 return window.isFullscreen();
322 }
323
bf584fba
SG
324 public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
325 window.addSurfaceUpdatedListener(l);
326 }
327 public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
328 window.removeSurfaceUpdatedListener(l);
329 }
e8f4dc96
SG
330 public void removeAllSurfaceUpdatedListener() {
331 window.removeAllSurfaceUpdatedListener();
332 }
bf584fba
SG
333 public SurfaceUpdatedListener[] getSurfaceUpdatedListener() {
334 return window.getSurfaceUpdatedListener();
335 }
336 public void surfaceUpdated(Object updater, NativeWindow window0, long when) {
337 window.surfaceUpdated(updater, window, when);
338 }
339
a959c53b
KR
340 public void addMouseListener(MouseListener l) {
341 window.addMouseListener(l);
342 }
343
344 public void removeMouseListener(MouseListener l) {
345 window.removeMouseListener(l);
346 }
347
348 public MouseListener[] getMouseListeners() {
349 return window.getMouseListeners();
350 }
351
352 public void addKeyListener(KeyListener l) {
353 window.addKeyListener(l);
354 }
355
356 public void removeKeyListener(KeyListener l) {
357 window.removeKeyListener(l);
358 }
359
360 public KeyListener[] getKeyListeners() {
361 return window.getKeyListeners();
362 }
363
364 public void addWindowListener(WindowListener l) {
365 window.addWindowListener(l);
366 }
367
368 public void removeWindowListener(WindowListener l) {
369 window.removeWindowListener(l);
370 }
371
372 public WindowListener[] getWindowListeners() {
373 return window.getWindowListeners();
374 }
375
376 public String toString() {
1c1053c6 377 return "NEWT-GLWindow[ \n\tHelper: "+helper+", \n\tDrawable: "+drawable + /** ", \n\tWindow: "+window+", \n\tFactory: "+factory+ */ "]";
a959c53b
KR
378 }
379
380 //----------------------------------------------------------------------
381 // OpenGL-related methods and state
382 //
383
a959c53b
KR
384 private GLDrawableFactory factory;
385 private GLDrawable drawable;
386 private GLContext context;
387 private GLDrawableHelper helper = new GLDrawableHelper();
388 // To make reshape events be sent immediately before a display event
389 private boolean sendReshape=false;
390 private boolean sendDestroy=false;
391 private boolean perfLog = false;
392
393 public GLDrawableFactory getFactory() {
394 return factory;
395 }
396
397 public void setContext(GLContext newCtx) {
398 context = newCtx;
399 }
400
401 public GLContext getContext() {
402 return context;
403 }
404
405 public GL getGL() {
406 if (context == null) {
407 return null;
408 }
409 return context.getGL();
410 }
411
4e0a5af0 412 public GL setGL(GL gl) {
a959c53b
KR
413 if (context != null) {
414 context.setGL(gl);
4e0a5af0 415 return gl;
a959c53b 416 }
4e0a5af0 417 return null;
a959c53b
KR
418 }
419
420 public void addGLEventListener(GLEventListener listener) {
421 helper.addGLEventListener(listener);
422 }
423
424 public void removeGLEventListener(GLEventListener listener) {
425 helper.removeGLEventListener(listener);
426 }
427
428 public void display() {
cf4c4037
SG
429 display(false);
430 }
431
432 public void display(boolean forceReshape) {
2268a6ce 433 if(window!=null && drawable!=null && context != null) {
a92906bc 434 if(runPumpMessages) {
2268a6ce 435 window.getScreen().getDisplay().pumpMessages();
a92906bc 436 }
a959c53b 437 if(window.hasDeviceChanged() && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED) {
eab82899 438 dispose(true, true);
a959c53b
KR
439 }
440 if (sendDestroy) {
441 destroy();
442 sendDestroy=false;
443 } else {
cf4c4037
SG
444 if(forceReshape) {
445 sendReshape = true;
446 }
a959c53b
KR
447 helper.invokeGL(drawable, context, displayAction, initAction);
448 }
449 }
450 }
451
452 private void sendDisposeEvent() {
2268a6ce 453 if(drawable!=null && context != null) {
a959c53b
KR
454 helper.invokeGL(drawable, context, disposeAction, null);
455 }
456 }
457
a92906bc 458 /** This implementation uses a static value */
a959c53b 459 public void setAutoSwapBufferMode(boolean onOrOff) {
2268a6ce 460 helper.setAutoSwapBufferMode(onOrOff);
a959c53b
KR
461 }
462
a92906bc 463 /** This implementation uses a static value */
a959c53b 464 public boolean getAutoSwapBufferMode() {
2268a6ce 465 return helper.getAutoSwapBufferMode();
a959c53b
KR
466 }
467
468 public void swapBuffers() {
2268a6ce
SG
469 if(drawable!=null && context != null) {
470 if (context != GLContext.getCurrent()) {
a959c53b
KR
471 // Assume we should try to make the context current before swapping the buffers
472 helper.invokeGL(drawable, context, swapBuffersAction, initAction);
473 } else {
474 drawable.swapBuffers();
475 }
476 }
477 }
478
479 class InitAction implements Runnable {
480 public void run() {
481 helper.init(GLWindow.this);
482 startTime = System.currentTimeMillis();
483 curTime = startTime;
484 if(perfLog) {
485 lastCheck = startTime;
486 totalFrames = 0; lastFrames = 0;
487 }
488 }
489 }
490 private InitAction initAction = new InitAction();
491
492 class DisposeAction implements Runnable {
493 public void run() {
494 helper.dispose(GLWindow.this);
495 }
496 }
497 private DisposeAction disposeAction = new DisposeAction();
498
499 class DisplayAction implements Runnable {
500 public void run() {
501 if (sendReshape) {
502 int width = getWidth();
503 int height = getHeight();
504 getGL().glViewport(0, 0, width, height);
505 helper.reshape(GLWindow.this, 0, 0, width, height);
506 sendReshape = false;
507 }
508
509 helper.display(GLWindow.this);
510
511 curTime = System.currentTimeMillis();
512 totalFrames++;
513
514 if(perfLog) {
515 long dt0, dt1;
516 lastFrames++;
517 dt0 = curTime-lastCheck;
518 if ( dt0 > 5000 ) {
519 dt1 = curTime-startTime;
520 System.out.println(dt0/1000 +"s: "+ lastFrames + "f, " + (lastFrames*1000)/dt0 + " fps, "+dt0/lastFrames+" ms/f; "+
521 "total: "+ dt1/1000+"s, "+(totalFrames*1000)/dt1 + " fps, "+dt1/totalFrames+" ms/f");
522 lastCheck=curTime;
523 lastFrames=0;
524 }
525 }
526 }
527 }
a92906bc 528 private DisplayAction displayAction = new DisplayAction();
a959c53b
KR
529
530 public long getStartTime() { return startTime; }
531 public long getCurrentTime() { return curTime; }
532 public long getDuration() { return curTime-startTime; }
533 public int getTotalFrames() { return totalFrames; }
534
535 private long startTime = 0;
536 private long curTime = 0;
537 private long lastCheck = 0;
538 private int totalFrames = 0, lastFrames = 0;
a959c53b 539
a959c53b
KR
540 class SwapBuffersAction implements Runnable {
541 public void run() {
542 drawable.swapBuffers();
543 }
544 }
a959c53b
KR
545 private SwapBuffersAction swapBuffersAction = new SwapBuffersAction();
546
547 //----------------------------------------------------------------------
548 // GLDrawable methods
549 //
550
551 public NativeWindow getNativeWindow() {
552 return null!=drawable ? drawable.getNativeWindow() : null;
553 }
554
555 public synchronized int lockSurface() throws NativeWindowException {
556 if(null!=drawable) return drawable.getNativeWindow().lockSurface();
557 return NativeWindow.LOCK_SURFACE_NOT_READY;
558 }
559
560 public synchronized void unlockSurface() {
561 if(null!=drawable) drawable.getNativeWindow().unlockSurface();
562 else throw new NativeWindowException("NEWT-GLWindow not locked");
563 }
564
565 public synchronized boolean isSurfaceLocked() {
566 if(null!=drawable) return drawable.getNativeWindow().isSurfaceLocked();
567 return false;
568 }
569
570 public synchronized Exception getLockedStack() {
571 if(null!=drawable) return drawable.getNativeWindow().getLockedStack();
572 return null;
573 }
574
8883fa88 575 public boolean surfaceSwap() {
576 if(null!=drawable) return drawable.getNativeWindow().surfaceSwap();
577 return super.surfaceSwap();
578 }
579
a959c53b
KR
580 public long getWindowHandle() {
581 if(null!=drawable) return drawable.getNativeWindow().getWindowHandle();
582 return super.getWindowHandle();
583 }
584
585 public long getSurfaceHandle() {
586 if(null!=drawable) return drawable.getNativeWindow().getSurfaceHandle();
587 return super.getSurfaceHandle();
588 }
589
590 //----------------------------------------------------------------------
591 // GLDrawable methods that are not really needed
592 //
593
594 public GLContext createContext(GLContext shareWith) {
595 return drawable.createContext(shareWith);
596 }
597
598 public void setRealized(boolean realized) {
599 }
600
601 public GLCapabilities getChosenGLCapabilities() {
602 if (drawable == null) {
603 throw new GLException("No drawable yet");
604 }
605
606 return drawable.getChosenGLCapabilities();
607 }
608
609 public GLProfile getGLProfile() {
610 if (drawable == null) {
611 throw new GLException("No drawable yet");
612 }
613
614 return drawable.getGLProfile();
615 }
616
617 //----------------------------------------------------------------------
618 // Internals only below this point
619 //
620
621 private void shouldNotCallThis() {
622 throw new NativeWindowException("Should not call this");
623 }
624}
http://JogAmp.org git info: FAQ, tutorial and man pages.