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