com.jogamp.newt.opengl.GLWindow Maven / Gradle / Ivy
Show all versions of jogl 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.nativewindow.util.Rectangle;
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 javax.media.opengl.GLRunnable;
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.Display.PointerIcon;
import com.jogamp.newt.event.GestureHandler;
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.NEWTEventListener;
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 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 NEWTEventListener},
* you can inject {@link GLRunnable} objects
* via {@link #invoke(boolean, 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(final Window window) {
super(null, null, false /* always handle device lifecycle ourselves */);
this.window = (WindowImpl) window;
this.window.setWindowDestroyNotifyAction( new Runnable() {
@Override
public void run() {
defaultWindowDestroyNotifyOp();
} } );
window.addWindowListener(new WindowAdapter() {
@Override
public void windowRepaint(final WindowUpdateEvent e) {
defaultWindowRepaintOp();
}
@Override
public void windowResized(final WindowEvent e) {
defaultWindowResizedOp(getSurfaceWidth(), getSurfaceHeight());
}
});
this.window.setLifecycleHook(new GLLifecycleHook());
}
@Override
public final Object getUpstreamWidget() {
return window;
}
@Override
public final RecursiveLock getUpstreamLock() {
return window.getLock();
}
/**
* 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(final 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(final Screen screen, final 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(final 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(final NativeWindow parentNativeWindow, final GLCapabilitiesImmutable caps) {
return new GLWindow(NewtFactory.createWindow(parentNativeWindow, caps));
}
//----------------------------------------------------------------------
// WindowClosingProtocol implementation
//
@Override
public WindowClosingMode getDefaultCloseOperation() {
return window.getDefaultCloseOperation();
}
@Override
public WindowClosingMode setDefaultCloseOperation(final WindowClosingMode op) {
return window.setDefaultCloseOperation(op);
}
//----------------------------------------------------------------------
// Window Access
//
@Override
public CapabilitiesChooser setCapabilitiesChooser(final 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(final 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(final boolean mouseVisible) {
window.setPointerVisible(mouseVisible);
}
@Override
public final PointerIcon getPointerIcon() {
return window.getPointerIcon();
}
@Override
public final void setPointerIcon(final PointerIcon pi) {
window.setPointerIcon(pi);
}
@Override
public final boolean isPointerConfined() {
return window.isPointerConfined();
}
@Override
public final void confinePointer(final boolean grab) {
window.confinePointer(grab);
}
@Override
public final void setUndecorated(final boolean value) {
window.setUndecorated(value);
}
@Override
public final void warpPointer(final int x, final int y) {
window.warpPointer(x, y);
}
@Override
public final boolean isUndecorated() {
return window.isUndecorated();
}
@Override
public final void setAlwaysOnTop(final boolean value) {
window.setAlwaysOnTop(value);
}
@Override
public final boolean isAlwaysOnTop() {
return window.isAlwaysOnTop();
}
@Override
public final void setFocusAction(final FocusRunnable focusAction) {
window.setFocusAction(focusAction);
}
@Override
public void setKeyboardFocusHandler(final KeyListener l) {
window.setKeyboardFocusHandler(l);
}
@Override
public final void requestFocus() {
window.requestFocus();
}
@Override
public final void requestFocus(final 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 Rectangle getBounds() {
return window.getBounds();
}
@Override
public final int getSurfaceWidth() {
return window.getSurfaceWidth();
}
@Override
public final int getSurfaceHeight() {
return window.getSurfaceHeight();
}
@Override
public final int[] convertToWindowUnits(final int[] pixelUnitsAndResult) {
return window.convertToWindowUnits(pixelUnitsAndResult);
}
@Override
public final int[] convertToPixelUnits(final int[] windowUnitsAndResult) {
return window.convertToPixelUnits(windowUnitsAndResult);
}
@Override
public final void setSurfaceScale(final int[] pixelScale) {
window.setSurfaceScale(pixelScale);
}
@Override
public final int[] getRequestedSurfaceScale(final int[] result) {
return window.getRequestedSurfaceScale(result);
}
@Override
public final int[] getCurrentSurfaceScale(final int[] result) {
return window.getCurrentSurfaceScale(result);
}
@Override
public final int[] getNativeSurfaceScale(final int[] result) {
return window.getNativeSurfaceScale(result);
}
@Override
public final float[] getPixelsPerMM(final float[] ppmmStore) {
return window.getPixelsPerMM(ppmmStore);
}
@Override
public final void setPosition(final int x, final int y) {
window.setPosition(x, y);
}
@Override
public void setTopLevelPosition(final int x, final int y) {
window.setTopLevelPosition(x, y);
}
@Override
public final boolean setFullscreen(final boolean fullscreen) {
return window.setFullscreen(fullscreen);
}
@Override
public boolean setFullscreen(final 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(final NativeWindow newParent, final int x, final int y, final int hints) {
return window.reparentWindow(newParent, x, y, hints);
}
@Override
public final boolean removeChild(final NativeWindow win) {
return window.removeChild(win);
}
@Override
public final boolean addChild(final NativeWindow win) {
return window.addChild(win);
}
//----------------------------------------------------------------------
// Window.LifecycleHook Implementation
//
@Override
public final void destroy() {
window.destroy();
}
@Override
public void setWindowDestroyNotifyAction(final Runnable r) {
window.setWindowDestroyNotifyAction(r);
}
@Override
public final void setVisible(final boolean visible) {
window.setVisible(visible);
}
@Override
public void setVisible(final boolean wait, final boolean visible) {
window.setVisible(wait, visible);
}
@Override
public final void setSize(final int width, final int height) {
window.setSize(width, height);
}
@Override
public final void setSurfaceSize(final int pixelWidth, final int pixelHeight) {
window.setSurfaceSize(pixelWidth, pixelHeight);
}
@Override
public void setTopLevelSize(final int width, final int height) {
window.setTopLevelSize(width, height);
}
@Override
public final boolean isNativeValid() {
return window.isNativeValid();
}
@Override
public Point getLocationOnScreen(final Point storage) {
return window.getLocationOnScreen(storage);
}
// Hide methods here ..
protected class GLLifecycleHook implements WindowImpl.LifecycleHook {
@Override
public void preserveGLStateAtDestroy(final boolean value) {
GLWindow.this.preserveGLStateAtDestroy(value);
}
@Override
public synchronized void destroyActionPreLock() {
// nop
}
@Override
public synchronized void destroyActionInLock() {
if(Window.DEBUG_IMPLEMENTATION) {
final 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(final boolean visible, final 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() {
@Override
public Object run() {
if( anim.isAnimating() && null != animThread ) {
try {
animThread.stop();
} catch(final Throwable t) {
if( DEBUG ) {
System.err.println("Caught "+t.getClass().getName()+": "+t.getMessage());
t.printStackTrace();
}
}
}
return null;
} } );
}
}
}
}
//----------------------------------------------------------------------
// OpenGL-related methods and state
//
@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 < getSurfaceWidth() && 0 < getSurfaceHeight() ) ) {
// 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(final NEWTEvent event) {
return window.consumeEvent(event);
}
//----------------------------------------------------------------------
// Window completion
//
@Override
public final void windowRepaint(final int x, final int y, final int width, final int height) {
window.windowRepaint(x, y, width, height);
}
@Override
public final void enqueueEvent(final boolean wait, final com.jogamp.newt.event.NEWTEvent event) {
window.enqueueEvent(wait, event);
}
@Override
public final void runOnEDTIfAvail(final boolean wait, final Runnable task) {
window.runOnEDTIfAvail(wait, task);
}
@Override
public void sendWindowEvent(final int eventType) {
window.sendWindowEvent(eventType);
}
@Override
public final WindowListener getWindowListener(final int index) {
return window.getWindowListener(index);
}
@Override
public final WindowListener[] getWindowListeners() {
return window.getWindowListeners();
}
@Override
public final void removeWindowListener(final WindowListener l) {
window.removeWindowListener(l);
}
@Override
public final void addWindowListener(final WindowListener l) {
window.addWindowListener(l);
}
@Override
public final void addWindowListener(final int index, final WindowListener l) throws IndexOutOfBoundsException {
window.addWindowListener(index, l);
}
@Override
public final void setKeyboardVisible(final boolean visible) {
window.setKeyboardVisible(visible);
}
@Override
public final boolean isKeyboardVisible() {
return window.isKeyboardVisible();
}
@Override
public final void addKeyListener(final KeyListener l) {
window.addKeyListener(l);
}
@Override
public final void addKeyListener(final int index, final KeyListener l) {
window.addKeyListener(index, l);
}
@Override
public final void removeKeyListener(final KeyListener l) {
window.removeKeyListener(l);
}
@Override
public final KeyListener getKeyListener(final int index) {
return window.getKeyListener(index);
}
@Override
public final KeyListener[] getKeyListeners() {
return window.getKeyListeners();
}
@Override
public final void addMouseListener(final MouseListener l) {
window.addMouseListener(l);
}
@Override
public final void addMouseListener(final int index, final MouseListener l) {
window.addMouseListener(index, l);
}
@Override
public final void removeMouseListener(final MouseListener l) {
window.removeMouseListener(l);
}
@Override
public final MouseListener getMouseListener(final int index) {
return window.getMouseListener(index);
}
@Override
public final MouseListener[] getMouseListeners() {
return window.getMouseListeners();
}
@Override
public void setDefaultGesturesEnabled(final boolean enable) {
window.setDefaultGesturesEnabled(enable);
}
@Override
public boolean areDefaultGesturesEnabled() {
return window.areDefaultGesturesEnabled();
}
@Override
public final void addGestureHandler(final GestureHandler gh) {
window.addGestureHandler(gh);
}
@Override
public final void addGestureHandler(final int index, final GestureHandler gh) {
window.addGestureHandler(index, gh);
}
@Override
public final void removeGestureHandler(final GestureHandler gh) {
window.removeGestureHandler(gh);
}
@Override
public final void addGestureListener(final GestureHandler.GestureListener gl) {
window.addGestureListener(-1, gl);
}
@Override
public final void addGestureListener(final int index, final GestureHandler.GestureListener gl) {
window.addGestureListener(index, gl);
}
@Override
public final void removeGestureListener(final GestureHandler.GestureListener gl) {
window.removeGestureListener(gl);
}
//----------------------------------------------------------------------
// 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 void removeSurfaceUpdatedListener(final SurfaceUpdatedListener l) {
window.removeSurfaceUpdatedListener(l);
}
@Override
public final void addSurfaceUpdatedListener(final SurfaceUpdatedListener l) {
window.addSurfaceUpdatedListener(l);
}
@Override
public final void addSurfaceUpdatedListener(final int index, final SurfaceUpdatedListener l) throws IndexOutOfBoundsException {
window.addSurfaceUpdatedListener(index, l);
}
@Override
public final void surfaceUpdated(final Object updater, final NativeSurface ns, final long when) {
window.surfaceUpdated(updater, ns, when);
}
@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();
}
/**
* A most simple JOGL AWT test entry
*/
public static void main(final 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