Jogamp
XHTML cleanup for jogl deployment doc.
[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
ccc30b05
SG
284 public void requestFocus() {
285 window.requestFocus();
286 }
287
a959c53b
KR
288 public void setSize(int width, int height) {
289 window.setSize(width, height);
290 }
291
292 public void setPosition(int x, int y) {
293 window.setPosition(x, y);
294 }
295
7bed517f 296 public Insets getInsets() {
297 return window.getInsets();
298 }
299
a959c53b
KR
300 public boolean setFullscreen(boolean fullscreen) {
301 return window.setFullscreen(fullscreen);
302 }
303
304 public boolean isVisible() {
305 return window.isVisible();
306 }
307
308 public int getX() {
309 return window.getX();
310 }
311
312 public int getY() {
313 return window.getY();
314 }
315
316 public int getWidth() {
317 return window.getWidth();
318 }
319
320 public int getHeight() {
321 return window.getHeight();
322 }
323
324 public boolean isFullscreen() {
325 return window.isFullscreen();
326 }
327
bf584fba
SG
328 public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
329 window.addSurfaceUpdatedListener(l);
330 }
331 public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
332 window.removeSurfaceUpdatedListener(l);
333 }
e8f4dc96
SG
334 public void removeAllSurfaceUpdatedListener() {
335 window.removeAllSurfaceUpdatedListener();
336 }
bf584fba
SG
337 public SurfaceUpdatedListener[] getSurfaceUpdatedListener() {
338 return window.getSurfaceUpdatedListener();
339 }
340 public void surfaceUpdated(Object updater, NativeWindow window0, long when) {
341 window.surfaceUpdated(updater, window, when);
342 }
343
ccc30b05
SG
344 public void sendEvent(NEWTEvent e) {
345 window.sendEvent(e);
346 }
347
a959c53b
KR
348 public void addMouseListener(MouseListener l) {
349 window.addMouseListener(l);
350 }
351
352 public void removeMouseListener(MouseListener l) {
353 window.removeMouseListener(l);
354 }
355
356 public MouseListener[] getMouseListeners() {
357 return window.getMouseListeners();
358 }
359
360 public void addKeyListener(KeyListener l) {
361 window.addKeyListener(l);
362 }
363
364 public void removeKeyListener(KeyListener l) {
365 window.removeKeyListener(l);
366 }
367
368 public KeyListener[] getKeyListeners() {
369 return window.getKeyListeners();
370 }
371
372 public void addWindowListener(WindowListener l) {
373 window.addWindowListener(l);
374 }
375
376 public void removeWindowListener(WindowListener l) {
377 window.removeWindowListener(l);
378 }
379
380 public WindowListener[] getWindowListeners() {
381 return window.getWindowListeners();
382 }
383
384 public String toString() {
1c1053c6 385 return "NEWT-GLWindow[ \n\tHelper: "+helper+", \n\tDrawable: "+drawable + /** ", \n\tWindow: "+window+", \n\tFactory: "+factory+ */ "]";
a959c53b
KR
386 }
387
388 //----------------------------------------------------------------------
389 // OpenGL-related methods and state
390 //
391
a959c53b
KR
392 private GLDrawableFactory factory;
393 private GLDrawable drawable;
394 private GLContext context;
395 private GLDrawableHelper helper = new GLDrawableHelper();
396 // To make reshape events be sent immediately before a display event
397 private boolean sendReshape=false;
398 private boolean sendDestroy=false;
399 private boolean perfLog = false;
400
401 public GLDrawableFactory getFactory() {
402 return factory;
403 }
404
405 public void setContext(GLContext newCtx) {
406 context = newCtx;
407 }
408
409 public GLContext getContext() {
410 return context;
411 }
412
413 public GL getGL() {
414 if (context == null) {
415 return null;
416 }
417 return context.getGL();
418 }
419
4e0a5af0 420 public GL setGL(GL gl) {
a959c53b
KR
421 if (context != null) {
422 context.setGL(gl);
4e0a5af0 423 return gl;
a959c53b 424 }
4e0a5af0 425 return null;
a959c53b
KR
426 }
427
428 public void addGLEventListener(GLEventListener listener) {
429 helper.addGLEventListener(listener);
430 }
431
432 public void removeGLEventListener(GLEventListener listener) {
433 helper.removeGLEventListener(listener);
434 }
435
436 public void display() {
cf4c4037
SG
437 display(false);
438 }
439
440 public void display(boolean forceReshape) {
2268a6ce 441 if(window!=null && drawable!=null && context != null) {
a92906bc 442 if(runPumpMessages) {
2268a6ce 443 window.getScreen().getDisplay().pumpMessages();
a92906bc 444 }
a959c53b 445 if(window.hasDeviceChanged() && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED) {
eab82899 446 dispose(true, true);
a959c53b
KR
447 }
448 if (sendDestroy) {
449 destroy();
450 sendDestroy=false;
451 } else {
cf4c4037
SG
452 if(forceReshape) {
453 sendReshape = true;
454 }
a959c53b
KR
455 helper.invokeGL(drawable, context, displayAction, initAction);
456 }
457 }
458 }
459
460 private void sendDisposeEvent() {
2268a6ce 461 if(drawable!=null && context != null) {
a959c53b
KR
462 helper.invokeGL(drawable, context, disposeAction, null);
463 }
464 }
465
a92906bc 466 /** This implementation uses a static value */
a959c53b 467 public void setAutoSwapBufferMode(boolean onOrOff) {
2268a6ce 468 helper.setAutoSwapBufferMode(onOrOff);
a959c53b
KR
469 }
470
a92906bc 471 /** This implementation uses a static value */
a959c53b 472 public boolean getAutoSwapBufferMode() {
2268a6ce 473 return helper.getAutoSwapBufferMode();
a959c53b
KR
474 }
475
476 public void swapBuffers() {
2268a6ce
SG
477 if(drawable!=null && context != null) {
478 if (context != GLContext.getCurrent()) {
a959c53b
KR
479 // Assume we should try to make the context current before swapping the buffers
480 helper.invokeGL(drawable, context, swapBuffersAction, initAction);
481 } else {
482 drawable.swapBuffers();
483 }
484 }
485 }
486
487 class InitAction implements Runnable {
488 public void run() {
489 helper.init(GLWindow.this);
490 startTime = System.currentTimeMillis();
491 curTime = startTime;
492 if(perfLog) {
493 lastCheck = startTime;
494 totalFrames = 0; lastFrames = 0;
495 }
496 }
497 }
498 private InitAction initAction = new InitAction();
499
500 class DisposeAction implements Runnable {
501 public void run() {
502 helper.dispose(GLWindow.this);
503 }
504 }
505 private DisposeAction disposeAction = new DisposeAction();
506
507 class DisplayAction implements Runnable {
508 public void run() {
509 if (sendReshape) {
510 int width = getWidth();
511 int height = getHeight();
512 getGL().glViewport(0, 0, width, height);
513 helper.reshape(GLWindow.this, 0, 0, width, height);
514 sendReshape = false;
515 }
516
517 helper.display(GLWindow.this);
518
519 curTime = System.currentTimeMillis();
520 totalFrames++;
521
522 if(perfLog) {
523 long dt0, dt1;
524 lastFrames++;
525 dt0 = curTime-lastCheck;
526 if ( dt0 > 5000 ) {
527 dt1 = curTime-startTime;
528 System.out.println(dt0/1000 +"s: "+ lastFrames + "f, " + (lastFrames*1000)/dt0 + " fps, "+dt0/lastFrames+" ms/f; "+
529 "total: "+ dt1/1000+"s, "+(totalFrames*1000)/dt1 + " fps, "+dt1/totalFrames+" ms/f");
530 lastCheck=curTime;
531 lastFrames=0;
532 }
533 }
534 }
535 }
a92906bc 536 private DisplayAction displayAction = new DisplayAction();
a959c53b
KR
537
538 public long getStartTime() { return startTime; }
539 public long getCurrentTime() { return curTime; }
540 public long getDuration() { return curTime-startTime; }
541 public int getTotalFrames() { return totalFrames; }
542
543 private long startTime = 0;
544 private long curTime = 0;
545 private long lastCheck = 0;
546 private int totalFrames = 0, lastFrames = 0;
a959c53b 547
a959c53b
KR
548 class SwapBuffersAction implements Runnable {
549 public void run() {
550 drawable.swapBuffers();
551 }
552 }
a959c53b
KR
553 private SwapBuffersAction swapBuffersAction = new SwapBuffersAction();
554
555 //----------------------------------------------------------------------
556 // GLDrawable methods
557 //
558
559 public NativeWindow getNativeWindow() {
560 return null!=drawable ? drawable.getNativeWindow() : null;
561 }
562
563 public synchronized int lockSurface() throws NativeWindowException {
564 if(null!=drawable) return drawable.getNativeWindow().lockSurface();
565 return NativeWindow.LOCK_SURFACE_NOT_READY;
566 }
567
568 public synchronized void unlockSurface() {
569 if(null!=drawable) drawable.getNativeWindow().unlockSurface();
570 else throw new NativeWindowException("NEWT-GLWindow not locked");
571 }
572
573 public synchronized boolean isSurfaceLocked() {
574 if(null!=drawable) return drawable.getNativeWindow().isSurfaceLocked();
575 return false;
576 }
577
578 public synchronized Exception getLockedStack() {
579 if(null!=drawable) return drawable.getNativeWindow().getLockedStack();
580 return null;
581 }
582
8883fa88 583 public boolean surfaceSwap() {
584 if(null!=drawable) return drawable.getNativeWindow().surfaceSwap();
585 return super.surfaceSwap();
586 }
587
a959c53b
KR
588 public long getWindowHandle() {
589 if(null!=drawable) return drawable.getNativeWindow().getWindowHandle();
590 return super.getWindowHandle();
591 }
592
593 public long getSurfaceHandle() {
594 if(null!=drawable) return drawable.getNativeWindow().getSurfaceHandle();
595 return super.getSurfaceHandle();
596 }
597
598 //----------------------------------------------------------------------
599 // GLDrawable methods that are not really needed
600 //
601
602 public GLContext createContext(GLContext shareWith) {
603 return drawable.createContext(shareWith);
604 }
605
606 public void setRealized(boolean realized) {
607 }
608
609 public GLCapabilities getChosenGLCapabilities() {
610 if (drawable == null) {
611 throw new GLException("No drawable yet");
612 }
613
614 return drawable.getChosenGLCapabilities();
615 }
616
617 public GLProfile getGLProfile() {
618 if (drawable == null) {
619 throw new GLException("No drawable yet");
620 }
621
622 return drawable.getGLProfile();
623 }
624
625 //----------------------------------------------------------------------
626 // Internals only below this point
627 //
628
629 private void shouldNotCallThis() {
630 throw new NativeWindowException("Should not call this");
631 }
632}
http://JogAmp.org git info: FAQ, tutorial and man pages.