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