com.jogamp.newt.opengl.GLWindow Maven / Gradle / Ivy
Show all versions of jogl-all Show documentation
/*
* Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright (c) 2010 JogAmp Community. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
* ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
* DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
*/
package com.jogamp.newt.opengl;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List;
import javax.media.nativewindow.AbstractGraphicsConfiguration;
import javax.media.nativewindow.CapabilitiesChooser;
import javax.media.nativewindow.CapabilitiesImmutable;
import javax.media.nativewindow.NativeSurface;
import javax.media.nativewindow.NativeWindow;
import javax.media.nativewindow.NativeWindowException;
import javax.media.nativewindow.SurfaceUpdatedListener;
import javax.media.nativewindow.util.InsetsImmutable;
import javax.media.nativewindow.util.Point;
import javax.media.opengl.FPSCounter;
import javax.media.opengl.GL;
import javax.media.opengl.GL3;
import javax.media.opengl.GL4ES3;
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLCapabilitiesImmutable;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawable;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLES2;
import javax.media.opengl.GLES3;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLException;
import javax.media.opengl.GLProfile;
import jogamp.newt.WindowImpl;
import jogamp.opengl.GLAutoDrawableBase;
import jogamp.opengl.GLContextImpl;
import jogamp.opengl.GLDrawableImpl;
import com.jogamp.common.GlueGenVersion;
import com.jogamp.common.util.VersionUtil;
import com.jogamp.common.util.locks.RecursiveLock;
import com.jogamp.newt.MonitorDevice;
import com.jogamp.newt.NewtFactory;
import com.jogamp.newt.Screen;
import com.jogamp.newt.Window;
import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.event.MouseListener;
import com.jogamp.newt.event.NEWTEvent;
import com.jogamp.newt.event.NEWTEventConsumer;
import com.jogamp.newt.event.WindowAdapter;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.event.WindowListener;
import com.jogamp.newt.event.WindowUpdateEvent;
import com.jogamp.opengl.JoglVersion;
import com.jogamp.opengl.GLStateKeeper;
/**
* An implementation of {@link GLAutoDrawable} and {@link Window} interface,
* using a delegated {@link Window} instance, which may be an aggregation (lifecycle: created and destroyed).
*
* This implementation supports {@link GLStateKeeper GL state preservation},
* hence {@link #isGLStatePreservationSupported()} returns true
.
*
*
* This implementation does not make the OpenGL context current
* before calling the various input EventListener callbacks, ie {@link com.jogamp.newt.event.MouseListener} etc.
* This design decision is made in favor of a more performant and simplified
* implementation. Also the event dispatcher shall be implemented OpenGL agnostic.
* To be able to use OpenGL commands from within such input {@link com.jogamp.newt.event.NEWTEventListener},
* you can inject {@link javax.media.opengl.GLRunnable} objects
* via {@link #invoke(boolean, javax.media.opengl.GLRunnable)} to the OpenGL command stream.
*
*/
public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Window, NEWTEventConsumer, FPSCounter {
private final WindowImpl window;
/**
* Constructor. Do not call this directly -- use {@link #create()} instead.
*/
protected GLWindow(Window window) {
super(null, null, false /* always handle device lifecycle ourselves */);
this.window = (WindowImpl) window;
this.window.setWindowDestroyNotifyAction( new Runnable() {
public void run() {
defaultWindowDestroyNotifyOp();
} } );
window.addWindowListener(new WindowAdapter() {
@Override
public void windowRepaint(WindowUpdateEvent e) {
defaultWindowRepaintOp();
}
@Override
public void windowResized(WindowEvent e) {
defaultWindowResizedOp(getWidth(), getHeight());
}
});
this.window.setLifecycleHook(new GLLifecycleHook());
}
@Override
public final Object getUpstreamWidget() {
return window;
}
/**
* Creates a new GLWindow attaching a new Window referencing a
* new default Screen and default Display with the given GLCapabilities.
*
* The lifecycle of this Window's Screen and Display is handled via {@link Screen#addReference()}
* and {@link Screen#removeReference()}.
*
* The default Display will be reused if already instantiated.
*/
public static GLWindow create(GLCapabilitiesImmutable caps) {
return new GLWindow(NewtFactory.createWindow(caps));
}
/**
* Creates a new GLWindow attaching a new Window referencing the given Screen
* with the given GLCapabilities.
*
* The lifecycle of this Window's Screen and Display is handled via {@link Screen#addReference()}
* and {@link Screen#removeReference()}.
*
*/
public static GLWindow create(Screen screen, GLCapabilitiesImmutable caps) {
return new GLWindow(NewtFactory.createWindow(screen, caps));
}
/**
* Creates a new GLWindow attaching the given window.
*
* The lifecycle of this Window's Screen and Display is handled via {@link Screen#addReference()}
* and {@link Screen#removeReference()}.
*
*/
public static GLWindow create(Window window) {
return new GLWindow(window);
}
/**
* Creates a new GLWindow attaching a new child Window
* of the given parentNativeWindow
with the given GLCapabilities.
*
* The Display/Screen will be compatible with the parentNativeWindow
,
* or even identical in case it's a Newt Window.
* An already instantiated compatible Display will be reused.
*
*
* The lifecycle of this Window's Screen and Display is handled via {@link Screen#addReference()}
* and {@link Screen#removeReference()}.
*
*/
public static GLWindow create(NativeWindow parentNativeWindow, GLCapabilitiesImmutable caps) {
return new GLWindow(NewtFactory.createWindow(parentNativeWindow, caps));
}
//----------------------------------------------------------------------
// WindowClosingProtocol implementation
//
@Override
public WindowClosingMode getDefaultCloseOperation() {
return window.getDefaultCloseOperation();
}
@Override
public WindowClosingMode setDefaultCloseOperation(WindowClosingMode op) {
return window.setDefaultCloseOperation(op);
}
//----------------------------------------------------------------------
// Window Access
//
@Override
public CapabilitiesChooser setCapabilitiesChooser(CapabilitiesChooser chooser) {
return window.setCapabilitiesChooser(chooser);
}
@Override
public final CapabilitiesImmutable getChosenCapabilities() {
final GLDrawable _drawable = drawable;
return null != _drawable ? _drawable.getChosenGLCapabilities() : window.getChosenCapabilities();
}
@Override
public final CapabilitiesImmutable getRequestedCapabilities() {
return window.getRequestedCapabilities();
}
@Override
public final Window getDelegatedWindow() {
return window.getDelegatedWindow();
}
@Override
public final NativeWindow getParent() {
return window.getParent();
}
@Override
public final Screen getScreen() {
return window.getScreen();
}
@Override
public final MonitorDevice getMainMonitor() {
return window.getMainMonitor();
}
@Override
public final void setTitle(String title) {
window.setTitle(title);
}
@Override
public final String getTitle() {
return window.getTitle();
}
@Override
public final boolean isPointerVisible() {
return window.isPointerVisible();
}
@Override
public final void setPointerVisible(boolean mouseVisible) {
window.setPointerVisible(mouseVisible);
}
@Override
public final boolean isPointerConfined() {
return window.isPointerConfined();
}
@Override
public final void confinePointer(boolean grab) {
window.confinePointer(grab);
}
@Override
public final void setUndecorated(boolean value) {
window.setUndecorated(value);
}
@Override
public final void warpPointer(int x, int y) {
window.warpPointer(x, y);
}
@Override
public final boolean isUndecorated() {
return window.isUndecorated();
}
@Override
public final void setAlwaysOnTop(boolean value) {
window.setAlwaysOnTop(value);
}
@Override
public final boolean isAlwaysOnTop() {
return window.isAlwaysOnTop();
}
@Override
public final void setFocusAction(FocusRunnable focusAction) {
window.setFocusAction(focusAction);
}
@Override
public void setKeyboardFocusHandler(KeyListener l) {
window.setKeyboardFocusHandler(l);
}
@Override
public final void requestFocus() {
window.requestFocus();
}
@Override
public final void requestFocus(boolean wait) {
window.requestFocus(wait);
}
@Override
public boolean hasFocus() {
return window.hasFocus();
}
@Override
public final InsetsImmutable getInsets() {
return window.getInsets();
}
@Override
public final int getX() {
return window.getX();
}
@Override
public final int getY() {
return window.getY();
}
@Override
public final int getWidth() {
return window.getWidth();
}
@Override
public final int getHeight() {
return window.getHeight();
}
@Override
public final void setPosition(int x, int y) {
window.setPosition(x, y);
}
@Override
public void setTopLevelPosition(int x, int y) {
window.setTopLevelPosition(x, y);
}
@Override
public final boolean setFullscreen(boolean fullscreen) {
return window.setFullscreen(fullscreen);
}
@Override
public boolean setFullscreen(List monitors) {
return window.setFullscreen(monitors);
}
@Override
public final boolean isFullscreen() {
return window.isFullscreen();
}
@Override
public final boolean isVisible() {
return window.isVisible();
}
@Override
public final String toString() {
return "NEWT-GLWindow[ \n\tHelper: " + helper + ", \n\tDrawable: " + drawable +
", \n\tContext: " + context + ", \n\tWindow: "+window+ /** ", \n\tFactory: "+factory+ */ "]";
}
@Override
public final ReparentOperation reparentWindow(NativeWindow newParent) {
return window.reparentWindow(newParent);
}
@Override
public final ReparentOperation reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) {
return window.reparentWindow(newParent, forceDestroyCreate);
}
@Override
public final boolean removeChild(NativeWindow win) {
return window.removeChild(win);
}
@Override
public final boolean addChild(NativeWindow win) {
return window.addChild(win);
}
//----------------------------------------------------------------------
// Window.LifecycleHook Implementation
//
@Override
public final void destroy() {
window.destroy();
}
@Override
public void setWindowDestroyNotifyAction(Runnable r) {
window.setWindowDestroyNotifyAction(r);
}
@Override
public final void setVisible(boolean visible) {
window.setVisible(visible);
}
@Override
public final void setSize(int width, int height) {
window.setSize(width, height);
}
@Override
public void setTopLevelSize(int width, int height) {
window.setTopLevelSize(width, height);
}
@Override
public final boolean isNativeValid() {
return window.isNativeValid();
}
@Override
public Point getLocationOnScreen(Point storage) {
return window.getLocationOnScreen(storage);
}
// Hide methods here ..
protected class GLLifecycleHook implements WindowImpl.LifecycleHook {
@Override
public void preserveGLStateAtDestroy(boolean value) {
GLWindow.this.preserveGLStateAtDestroy(value);
}
@Override
public synchronized void destroyActionPreLock() {
// nop
}
@Override
public synchronized void destroyActionInLock() {
if(Window.DEBUG_IMPLEMENTATION) {
String msg = "GLWindow.destroy() "+WindowImpl.getThreadName()+", start";
System.err.println(msg);
//Exception e1 = new Exception(msg);
//e1.printStackTrace();
}
destroyImplInLock();
if(Window.DEBUG_IMPLEMENTATION) {
System.err.println("GLWindow.destroy() "+WindowImpl.getThreadName()+", fin");
}
}
@Override
public synchronized void resetCounter() {
if(Window.DEBUG_IMPLEMENTATION) {
System.err.println("GLWindow.resetCounter() "+WindowImpl.getThreadName());
}
GLWindow.this.resetFPSCounter();
final GLAnimatorControl animator = GLWindow.this.getAnimator();
if( null != animator ) {
animator.resetFPSCounter();
}
}
@Override
public synchronized void setVisibleActionPost(boolean visible, boolean nativeWindowCreated) {
long t0;
if(Window.DEBUG_IMPLEMENTATION) {
t0 = System.nanoTime();
System.err.println("GLWindow.setVisibleActionPost("+visible+", "+nativeWindowCreated+") "+WindowImpl.getThreadName()+", start");
} else {
t0 = 0;
}
if (null == drawable && visible && 0 != window.getWindowHandle() && 0() {
public Object run() {
if( anim.isAnimating() && null != animThread ) {
try {
animThread.stop();
} catch(Throwable t) {
}
}
return null;
} } );
}
}
}
}
//----------------------------------------------------------------------
// OpenGL-related methods and state
//
private GLContext sharedContext = null;
@Override
protected final RecursiveLock getLock() {
return window.getLock();
}
/**
* Specifies an {@link javax.media.opengl.GLContext OpenGL context} to share with.
* At native creation, {@link #setVisible(boolean) setVisible(true)},
* a {@link javax.media.opengl.GLDrawable drawable} and {@link javax.media.opengl.GLContext context} is created besides the native Window itself,
* hence you shall set the shared context before.
*
* @param sharedContext The OpenGL context shared by this GLWindow's one
*/
public void setSharedContext(GLContext sharedContext) {
this.sharedContext = sharedContext;
}
@Override
public void display() {
if( !isNativeValid() || !isVisible() ) { return; }
if(sendDestroy || ( window.hasDeviceChanged() && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) ) {
sendDestroy=false;
destroy();
return;
}
final boolean done;
final RecursiveLock lock = window.getLock();
lock.lock(); // sync: context/drawable could have been recreated/destroyed while animating
try {
if( null != context ) {
// surface is locked/unlocked implicit by context's makeCurrent/release
helper.invokeGL(drawable, context, defaultDisplayAction, defaultInitAction);
done = true;
} else {
done = false;
}
} finally {
lock.unlock();
}
if( !done && ( 0 < getWidth() && 0 < getHeight() ) ) {
// retry drawable and context creation, will itself issue resize -> display
setVisible(true);
}
}
/**
* {@inheritDoc}
*
* GLWindow supports GL state preservation, hence returns true
.
*
*/
@Override
public final boolean isGLStatePreservationSupported() { return true; }
//----------------------------------------------------------------------
// GLDrawable methods
//
private GLDrawableFactory factory;
@Override
public final GLDrawableFactory getFactory() {
return factory;
}
@Override
public final void swapBuffers() throws GLException {
defaultSwapBuffers();
}
//----------------------------------------------------------------------
// NEWTEventConsumer
//
@Override
public boolean consumeEvent(NEWTEvent event) {
return window.consumeEvent(event);
}
//----------------------------------------------------------------------
// Window completion
//
@Override
public final void windowRepaint(int x, int y, int width, int height) {
window.windowRepaint(x, y, width, height);
}
@Override
public final void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) {
window.enqueueEvent(wait, event);
}
@Override
public final void runOnEDTIfAvail(boolean wait, final Runnable task) {
window.runOnEDTIfAvail(wait, task);
}
@Override
public final void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
window.removeSurfaceUpdatedListener(l);
}
@Override
public final void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
window.addSurfaceUpdatedListener(l);
}
@Override
public final void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
window.addSurfaceUpdatedListener(index, l);
}
@Override
public void sendWindowEvent(int eventType) {
window.sendWindowEvent(eventType);
}
@Override
public final WindowListener getWindowListener(int index) {
return window.getWindowListener(index);
}
@Override
public final WindowListener[] getWindowListeners() {
return window.getWindowListeners();
}
@Override
public final void removeWindowListener(WindowListener l) {
window.removeWindowListener(l);
}
@Override
public final void addWindowListener(WindowListener l) {
window.addWindowListener(l);
}
@Override
public final void addWindowListener(int index, WindowListener l) throws IndexOutOfBoundsException {
window.addWindowListener(index, l);
}
@Override
public final void setKeyboardVisible(boolean visible) {
window.setKeyboardVisible(visible);
}
@Override
public final boolean isKeyboardVisible() {
return window.isKeyboardVisible();
}
@Override
public final void addKeyListener(KeyListener l) {
window.addKeyListener(l);
}
@Override
public final void addKeyListener(int index, KeyListener l) {
window.addKeyListener(index, l);
}
@Override
public final void removeKeyListener(KeyListener l) {
window.removeKeyListener(l);
}
@Override
public final KeyListener getKeyListener(int index) {
return window.getKeyListener(index);
}
@Override
public final KeyListener[] getKeyListeners() {
return window.getKeyListeners();
}
@Override
public final void addMouseListener(MouseListener l) {
window.addMouseListener(l);
}
@Override
public final void addMouseListener(int index, MouseListener l) {
window.addMouseListener(index, l);
}
@Override
public final void removeMouseListener(MouseListener l) {
window.removeMouseListener(l);
}
@Override
public final MouseListener getMouseListener(int index) {
return window.getMouseListener(index);
}
@Override
public final MouseListener[] getMouseListeners() {
return window.getMouseListeners();
}
//----------------------------------------------------------------------
// NativeWindow completion
//
@Override
public final int lockSurface() throws NativeWindowException, RuntimeException {
return window.lockSurface();
}
@Override
public final void unlockSurface() {
window.unlockSurface();
}
@Override
public final boolean isSurfaceLockedByOtherThread() {
return window.isSurfaceLockedByOtherThread();
}
@Override
public final Thread getSurfaceLockOwner() {
return window.getSurfaceLockOwner();
}
@Override
public final boolean surfaceSwap() {
return window.surfaceSwap();
}
@Override
public final long getWindowHandle() {
return window.getWindowHandle();
}
@Override
public final long getSurfaceHandle() {
return window.getSurfaceHandle();
}
@Override
public final AbstractGraphicsConfiguration getGraphicsConfiguration() {
return window.getGraphicsConfiguration();
}
@Override
public final long getDisplayHandle() {
return window.getDisplayHandle();
}
@Override
public final int getScreenIndex() {
return window.getScreenIndex();
}
@Override
public final void surfaceUpdated(Object updater, NativeSurface ns, long when) {
window.surfaceUpdated(updater, ns, when);
}
/**
* A most simple JOGL AWT test entry
*/
public static void main(String args[]) {
final boolean forceES2;
final boolean forceES3;
final boolean forceGL3;
final boolean forceGL4ES3;
{
boolean _forceES2 = false;
boolean _forceES3 = false;
boolean _forceGL3 = false;
boolean _forceGL4ES3 = false;
if( null != args ) {
for(int i=0; i