lwjgl2-arm64/src/java/org/lwjgl/opengl/AWTGLCanvas.java
Elias Naur 3674d843c2 Added org.lwjgl.opengl.AWTInputAdapter which enabled use of Mouse and
Keyboard with AWTGLCanvases. Programs can now avoid implementing AWT input processing and access the mouse grabbing features from both Display and AWTGLCanvas. See org.lwjgl.test.opengl.awt.AWTInputAdapterTest for an example.

Note: This commit is the linux and generic AWT imlementation and can still
change a lot while implementing windows and mac os x.
2006-10-26 20:19:40 +00:00

376 lines
9.7 KiB
Java

/*
* Copyright (c) 2002-2004 LWJGL Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions 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 'LWJGL' nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.lwjgl.opengl;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import org.lwjgl.LWJGLException;
import org.lwjgl.LWJGLUtil;
import org.lwjgl.Sys;
/**
* <p>
* An AWT rendering context.
* <p>
* @version $Revision$
* @author $Author$
* $Id$
*/
public class AWTGLCanvas extends Canvas implements Drawable, ComponentListener, HierarchyListener {
private static final long serialVersionUID = 1L;
private final static AWTCanvasImplementation implementation;
private boolean update_context;
private Object SYNC_LOCK = new Object();
/** The requested pixel format */
private final PixelFormat pixel_format;
/** The drawable to share context with */
private final Drawable drawable;
/** Context handle */
private PeerInfo peer_info;
private Context context;
/**
* re-entry counter for support for re-entrant
* redrawing in paint(). It happens when using dialog boxes.
*/
private int reentry_count;
/** Tracks whether initGL() needs to be called */
private boolean first_run;
/** Track the input adapter, if any */
private volatile AWTCanvasInputImplementation awt_input;
static {
Sys.initialize();
String class_name;
switch (LWJGLUtil.getPlatform()) {
case LWJGLUtil.PLATFORM_LINUX:
class_name = "org.lwjgl.opengl.LinuxCanvasImplementation";
break;
case LWJGLUtil.PLATFORM_WINDOWS:
class_name = "org.lwjgl.opengl.WindowsCanvasImplementation";
break;
case LWJGLUtil.PLATFORM_MACOSX:
class_name = "org.lwjgl.opengl.MacOSXCanvasImplementation";
break;
default:
throw new IllegalStateException("Unsupported platform");
}
try {
Class impl_class = Class.forName(class_name);
implementation = (AWTCanvasImplementation)impl_class.newInstance();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InstantiationException e) {
throw new RuntimeException(e);
}
}
/**
* Used from AWTInputAdapter
*/
static AWTCanvasImplementation getImplementation() {
return implementation;
}
void setInput(AWTCanvasInputImplementation awt_input) {
this.awt_input = awt_input;
}
private void setUpdate() {
synchronized(SYNC_LOCK) {
update_context = true;
}
}
/**
* This method should only be called internally.
*/
public Context getContext() {
return context;
}
/**
* Constructor using the default PixelFormat.
*/
public AWTGLCanvas() throws LWJGLException {
this(new PixelFormat());
}
/**
* Create an AWTGLCanvas with the requested PixelFormat on the default GraphicsDevice.
*
* @param pixelFormat The desired pixel format. May not be null
* @param device the device to create the canvas on.
*/
public AWTGLCanvas(PixelFormat pixel_format) throws LWJGLException {
this(GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(), pixel_format);
}
/**
* Create an AWTGLCanvas with the requested PixelFormat on the default GraphicsDevice.
*
* @param pixelFormat The desired pixel format. May not be null
* @param device the device to create the canvas on.
*/
public AWTGLCanvas(GraphicsDevice device, PixelFormat pixel_format) throws LWJGLException {
this(device, pixel_format, null);
}
/**
* Create an AWTGLCanvas with the requested PixelFormat on the specified GraphicsDevice.
*
* @param device the device to create the canvas on.
* @param pixelFormat The desired pixel format. May not be null
* @param shared_drawable The Drawable to share context with
*/
public AWTGLCanvas(GraphicsDevice device, PixelFormat pixel_format, Drawable drawable) throws LWJGLException {
super(implementation.findConfiguration(device, pixel_format));
if (pixel_format == null)
throw new NullPointerException("Pixel format must be non-null");
addHierarchyListener(this);
addComponentListener(this);
this.drawable = drawable;
this.pixel_format = pixel_format;
}
/* (non-Javadoc)
* @see java.awt.Canvas#addNotify()
*/
public void addNotify() {
super.addNotify();
}
/* (non-Javadoc)
* @see java.awt.Component#removeNotify()
*/
public void removeNotify() {
destroyContext();
super.removeNotify();
}
/**
* Set swap interval.
*/
public void setSwapInterval(int swap_interval) {
synchronized(SYNC_LOCK) {
if (context == null)
throw new IllegalStateException("Canvas not yet displayable");
Context.setSwapInterval(swap_interval);
}
}
/**
* Enable vsync
*/
public void setVSyncEnabled(boolean enabled) {
setSwapInterval(enabled ? 1 : 0);
}
/**
* Swap the canvas' buffer
*/
public void swapBuffers() throws LWJGLException {
synchronized(SYNC_LOCK) {
if (context == null)
throw new IllegalStateException("Canvas not yet displayable");
Context.swapBuffers();
}
}
public void releaseContext() throws LWJGLException {
synchronized(SYNC_LOCK) {
if (context == null)
throw new IllegalStateException("Canvas not yet displayable");
if (context.isCurrent())
Context.releaseCurrentContext();
}
}
/**
* Make the canvas' context current. It is highly recommended that the context
* is only made current inside the AWT thread (for example in an overridden paintGL()).
*/
public void makeCurrent() throws LWJGLException {
synchronized(SYNC_LOCK) {
if (context == null)
throw new IllegalStateException("Canvas not yet displayable");
context.makeCurrent();
}
}
/**
* Destroy the OpenGL context. This happens when the component becomes undisplayable
*/
private void destroyContext() {
synchronized(SYNC_LOCK) {
try {
if (context != null) {
context.forceDestroy();
context = null;
reentry_count = 0;
peer_info.destroy();
peer_info = null;
}
} catch (LWJGLException e) {
throw new RuntimeException(e);
}
}
}
/**
* Override this to do initialising of the context.
* It will be called once from paint(), immediately after
* the context is created and made current.
*/
protected void initGL() {
}
/**
* Override this to do painting
*/
protected void paintGL() {
}
/**
* The default paint() operation makes the context current and calls paintGL() which should
* be overridden to do GL operations.
*/
public final void paint(Graphics g) {
try {
if (peer_info == null) {
this.peer_info = implementation.createPeerInfo(this, pixel_format);
}
peer_info.lockAndGetHandle();
try {
if (context == null) {
this.context = new Context(peer_info, drawable != null ? drawable.getContext() : null);
first_run = true;
}
if (reentry_count == 0)
context.makeCurrent();
reentry_count++;
try {
if (update_context) {
context.update();
update_context = false;
}
AWTCanvasInputImplementation current_input = awt_input;
if (current_input != null)
current_input.processInput(peer_info);
if (first_run) {
first_run = false;
initGL();
}
paintGL();
} finally {
reentry_count--;
if (reentry_count == 0)
Context.releaseCurrentContext();
}
} finally {
peer_info.unlock();
}
} catch (LWJGLException e) {
throw new RuntimeException(e);
}
}
/**
* override update to avoid clearing
*/
public void update(Graphics g) {
paint(g);
}
public void componentShown(ComponentEvent e) {
}
public void componentHidden(ComponentEvent e) {
}
public void componentResized(ComponentEvent e) {
setUpdate();
}
public void componentMoved(ComponentEvent e) {
setUpdate();
}
public void setLocation(int x, int y) {
super.setLocation(x, y);
setUpdate();
}
public void setLocation(Point p) {
super.setLocation(p);
setUpdate();
}
public void setSize(Dimension d) {
super.setSize(d);
setUpdate();
}
public void setSize(int width, int height) {
super.setSize(width, height);
setUpdate();
}
public void setBounds(int x, int y, int width, int height) {
super.setBounds(x, y, width, height);
setUpdate();
}
public void hierarchyChanged(HierarchyEvent e) {
setUpdate();
}
}