diff --git a/build.xml b/build.xml
index 7e36842a..9cf6d7df 100644
--- a/build.xml
+++ b/build.xml
@@ -568,6 +568,7 @@
+
diff --git a/src/java/org/lwjgl/opengl/AWTGLCanvas.java b/src/java/org/lwjgl/opengl/AWTGLCanvas.java
new file mode 100644
index 00000000..fddf0ab3
--- /dev/null
+++ b/src/java/org/lwjgl/opengl/AWTGLCanvas.java
@@ -0,0 +1,158 @@
+/*
+ * 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.Graphics;
+
+import org.lwjgl.LWJGLException;
+import org.lwjgl.Sys;
+
+/**
+ * $Id$
+ *
+ * An AWT rendering context.
+ *
+ * @version $Revision$
+ * @author $Author$
+ */
+public class AWTGLCanvas extends Canvas {
+
+ static {
+ System.loadLibrary("jawt");
+ Sys.initialize();
+ }
+
+ /** The requested pixel format */
+ private PixelFormat pixelFormat;
+
+ /** Context handle */
+ private long context;
+
+ /**
+ * Constructor using the default PixelFormat.
+ */
+ public AWTGLCanvas() {
+ this(new PixelFormat());
+ }
+
+ /**
+ * Create an AWTGLCanvas with the requested PixelFormat. Construction is always
+ * successful, however, when the time comes to actually realise the component on the
+ * screen
+ * @param pixelFormat The desired pixel format. May not be null
+ */
+ public AWTGLCanvas(PixelFormat pixelFormat) {
+ if (pixelFormat == null) {
+ throw new IllegalArgumentException("Pixel format may not be null");
+ }
+ this.pixelFormat = pixelFormat;
+ }
+
+ /* (non-Javadoc)
+ * @see java.awt.Canvas#addNotify()
+ */
+ public void addNotify() {
+ super.addNotify();
+ try {
+ createContext();
+ } catch (LWJGLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.awt.Component#removeNotify()
+ */
+ public void removeNotify() {
+ super.removeNotify();
+ try {
+ destroyContext();
+ } catch (LWJGLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Create the OpenGL context. This occurs when the component becomes displayable
+ * @throws LWJGLException
+ */
+ private synchronized void createContext() throws LWJGLException {
+ nCreateContext();
+ }
+ private native void nCreateContext() throws LWJGLException;
+
+ /**
+ * Destroy the OpenGL context. This occurs when the component is no longer displayable.
+ */
+ private synchronized void destroyContext() throws LWJGLException {
+ }
+ private native void nDestroyContext() throws LWJGLException;
+
+ /* (non-Javadoc)
+ * @see java.awt.Canvas#paint(java.awt.Graphics)
+ */
+ public synchronized final void paint(Graphics g) {
+ try {
+ nPaint();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ private native void nPaint() throws Exception;
+
+
+ /**
+ * Paint callback from native code
+ */
+ private final void cPaint() {
+ try {
+ GLContext.useContext(this);
+ } catch (LWJGLException e) {
+ throw new RuntimeException(e);
+ }
+ doPaint();
+ }
+
+ /**
+ * Do painting. Override this method to call GL commands.
+ */
+ protected void doPaint() {
+ }
+
+ /* (non-Javadoc)
+ * @see java.awt.Canvas#update(java.awt.Graphics)
+ */
+ public void update(Graphics g) {
+ paint(g);
+ }
+}
diff --git a/src/java/org/lwjgl/test/opengl/awt/AWTTest.java b/src/java/org/lwjgl/test/opengl/awt/AWTTest.java
new file mode 100644
index 00000000..8fcd39ad
--- /dev/null
+++ b/src/java/org/lwjgl/test/opengl/awt/AWTTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2004-2005 Covalent Software Ltd
+ * All rights reserved.
+ */
+package org.lwjgl.test.opengl.awt;
+
+import java.awt.Frame;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+
+import org.lwjgl.opengl.AWTGLCanvas;
+import org.lwjgl.opengl.GL11;
+import org.lwjgl.opengl.glu.GLU;
+
+/**
+ * $Id$
+ *
+ * Tests AWTGLCanvas functionality
+ *
+ * @version $Revision$
+ * @author $Author$
+ */
+public class AWTTest extends Frame {
+
+ /** AWT GL canvas */
+ private AWTGLCanvas canvas0, canvas1;
+
+ private float angle;
+
+ /**
+ * C'tor
+ */
+ public AWTTest() {
+ setTitle("LWJGL AWT Canvas Test");
+ setSize(640, 320);
+ setLayout(null);
+ add(canvas0 = new AWTGLCanvas() {
+ protected void doPaint() {
+ GL11.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+ GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
+ }
+ });
+ canvas0.setBounds(0, 0, 320, 320);
+ add(canvas1 = new AWTGLCanvas() {
+ protected void doPaint() {
+ GL11.glViewport(0, 0, getWidth(), getHeight());
+ GL11.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+ GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);
+ GL11.glMatrixMode(GL11.GL_PROJECTION);
+ GL11.glLoadIdentity();
+ GLU.gluOrtho2D(0.0f, (float) getWidth(), 0.0f, (float) getHeight());
+ GL11.glMatrixMode(GL11.GL_MODELVIEW);
+ GL11.glPushMatrix();
+ GL11.glTranslatef(getWidth() / 2.0f, getHeight() / 2.0f, 0.0f);
+ GL11.glRotatef(angle, 0f, 0f, 1.0f);
+ GL11.glRectf(-50.0f, -50.0f, 50.0f, 50.0f);
+ GL11.glPopMatrix();
+ }
+ });
+ canvas1.setBounds(320, 0, 320, 320);
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ dispose();
+ }
+ });
+ setResizable(true);
+
+ new Thread() {
+ {
+ setDaemon(true);
+ }
+ public void run() {
+ for (;;) {
+ angle += 1.0f;
+ canvas1.repaint();
+ try {
+ sleep(20);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+ }.start();
+ }
+
+ public static void main(String[] args) {
+ new AWTTest().setVisible(true);
+ }
+}
diff --git a/src/native/win32/org_lwjgl_opengl_AWTGLCanvas.c b/src/native/win32/org_lwjgl_opengl_AWTGLCanvas.c
new file mode 100644
index 00000000..975bc698
--- /dev/null
+++ b/src/native/win32/org_lwjgl_opengl_AWTGLCanvas.c
@@ -0,0 +1,326 @@
+/*
+ * 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.
+ */
+
+/**
+ * $Id$
+ *
+ * @author$
+ * @version$
+ */
+
+#include
+#include
+#include "../common/common_tools.h"
+#include "extgl_wgl.h"
+#include "org_lwjgl_opengl_AWTGLCanvas.h"
+
+extern bool createARBContextAndPixelFormat(JNIEnv *env, HDC hdc, jobject pixel_format, int *pixel_format_index_return, HGLRC *context_return);
+
+/*
+ * Grab the context from the incoming AWTGLCanvas and return it
+ */
+HGLRC getContext(JNIEnv * env, jobject awtglcanvas) {
+ jclass cls_AWTGLCanvas = (*env)->GetObjectClass(env, awtglcanvas);
+ jlong hglrc = (int)(*env)->GetLongField(env, awtglcanvas, (*env)->GetFieldID(env, cls_AWTGLCanvas, "context", "J"));
+ return (HGLRC) hglrc;
+}
+
+/*
+ * Grab the HWND from the incoming AWTGLCanvas's peer
+ */
+HWND getHWND(JNIEnv * env, jobject awtglcanvas) {
+ jclass cls_AWTGLCanvas = (*env)->GetObjectClass(env, awtglcanvas);
+ jobject componentPeer = (*env)->GetObjectField(env, awtglcanvas, (*env)->GetFieldID(env, cls_AWTGLCanvas, "peer", "Ljava/awt/peer/ComponentPeer;"));
+ jclass cls_CanvasPeer = (*env)->GetObjectClass(env, componentPeer);
+ jlong hwnd = (*env)->GetLongField(env, componentPeer, (*env)->GetFieldID(env, cls_CanvasPeer, "hwnd", "J"));
+ return (HWND) hwnd;
+}
+
+/*
+ * Stash the incoming context int the incoming AWTGLCanvas
+ */
+void setContext(JNIEnv * env, jobject awtglcanvas, HGLRC hglrc) {
+ jclass cls_AWTGLCanvas = (*env)->GetObjectClass(env, awtglcanvas);
+ (*env)->SetLongField(env, awtglcanvas, (*env)->GetFieldID(env, cls_AWTGLCanvas, "context", "J"), (jlong) hglrc);
+}
+
+/*
+ * Class: org_lwjgl_opengl_AWTGLCanvas
+ * Method: nCreateContext
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_lwjgl_opengl_AWTGLCanvas_nCreateContext
+ (JNIEnv * env, jobject awtglcanvas)
+{
+ HWND hwnd;
+ HDC hdc;
+ HGLRC hglrc;
+ BOOL result;
+ jclass cls_pixel_format;
+ int samples;
+ int pixel_format_index_arb;
+ int pixel_format_index;
+ HGLRC context_arb;
+ bool arb_success;
+ jclass cls_AWTGLCanvas;
+ jobject pixel_format;
+
+ hwnd = getHWND(env, awtglcanvas);
+ hdc = GetDC(hwnd);
+ cls_AWTGLCanvas = (*env)->GetObjectClass(env, awtglcanvas);
+ pixel_format = (*env)->GetObjectField(env, awtglcanvas, (*env)->GetFieldID(env, cls_AWTGLCanvas, "pixelFormat", "Lorg/lwjgl/opengl/PixelFormat;"));
+ pixel_format_index = findPixelFormat(env, hdc, pixel_format);
+
+ if (pixel_format_index == -1) {
+ throwException(env, "Could not find a suitable pixel format");
+ ReleaseDC(hwnd, hdc);
+ return;
+ }
+
+ if (!applyPixelFormat(hdc, pixel_format_index)) {
+ throwException(env, "Could not apply pixel format to component");
+ ReleaseDC(hwnd, hdc);
+ return;
+ }
+
+ hglrc = wglCreateContext(hdc);
+ if (hglrc == NULL) {
+ throwException(env, "Failed to create OpenGL rendering context");
+ ReleaseDC(hwnd, hdc);
+ return;
+ }
+ result = wglMakeCurrent(hdc, hglrc);
+ if (!result) {
+ throwException(env, "Could not bind context to component");
+ wglDeleteContext(hglrc);
+ ReleaseDC(hwnd, hdc);
+ return;
+ }
+ extgl_InitWGL(env);
+ cls_pixel_format = (*env)->GetObjectClass(env, pixel_format);
+ samples = (int)(*env)->GetIntField(env, pixel_format, (*env)->GetFieldID(env, cls_pixel_format, "samples", "I"));
+ if (samples > 0) {
+ // Create a new context using ARB pixel format instead
+ arb_success = createARBContextAndPixelFormat(env, hdc, pixel_format, &pixel_format_index_arb, &context_arb);
+ wglDeleteContext(hglrc);
+ if (!arb_success) {
+ throwException(env, "Samples > 0 but could not find a suitable ARB pixel format");
+ return;
+ }
+ hglrc = context_arb;
+ pixel_format_index = pixel_format_index_arb;
+ }
+
+ // 4. Stash the native handle back
+ setContext(env, awtglcanvas, hglrc);
+
+ // 5. Release the GLRC
+ wglMakeCurrent(hdc, NULL);
+
+ // 6. Release DC back to windoze
+ ReleaseDC(hwnd, hdc);
+
+}
+
+/*
+ * Class: org_lwjgl_opengl_AWTGLCanvas
+ * Method: nMakeCurrent
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_lwjgl_opengl_AWTGLCanvas_nMakeCurrent
+ (JNIEnv * env, jobject awtglcanvas)
+{
+ HGLRC hglrc = getContext(env, awtglcanvas);
+ HWND hwnd = getHWND(env, awtglcanvas);
+ HDC hdc = GetDC(hwnd);
+ BOOL result = wglMakeCurrent(hdc, hglrc);
+ ReleaseDC(hwnd, hdc);
+ if (result != TRUE) {
+ LPVOID lpMsgBuf;
+ if (!FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL ))
+ {
+ // Handle the error.
+ printf("Failed\n");
+ } else {
+ throwException(env, (LPCTSTR)lpMsgBuf);
+ // Free the buffer.
+ LocalFree( lpMsgBuf );
+ }
+ }
+}
+
+
+/*
+ * Class: org_lwjgl_opengl_AWTGLCanvas
+ * Method: nDestroyContext
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_lwjgl_opengl_AWTGLCanvas_nDestroyContext
+ (JNIEnv *env, jobject awtglcanvas)
+{
+ // 1. Get the context
+ HGLRC hglrc = getContext(env, awtglcanvas);
+ HWND hwnd = getHWND(env, awtglcanvas);
+ HDC hdc;
+
+ // Check to ensure it's the current context for this thread
+ // (it should be!)
+ if (hglrc = wglGetCurrentContext()) {
+
+ // obtain its associated device context
+ HDC hdc = wglGetCurrentDC() ;
+
+ // make the rendering context not current
+ wglMakeCurrent(NULL, NULL) ;
+
+ // release the device context
+ ReleaseDC (hwnd, hdc) ;
+
+ // delete the rendering context
+ wglDeleteContext(hglrc);
+
+ } else {
+ throwException(env, "Could not destroy context: not current");
+ }
+}
+/*
+ * Class: org_lwjgl_opengl_AWTGLCanvas
+ * Method: nSwapBuffers
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_lwjgl_opengl_AWTGLCanvas_nSwapBuffers
+ (JNIEnv *env, jobject awtglcanvas)
+{
+ HWND hwnd = getHWND(env, awtglcanvas);
+ HDC hdc = GetDC(hwnd);
+ SwapBuffers(hdc);
+ ReleaseDC(hwnd, hdc);
+}
+
+/*
+ * Class: org_lwjgl_opengl_AWTGLCanvas
+ * Method: nPaint
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_org_lwjgl_opengl_AWTGLCanvas_nPaint
+ (JNIEnv *env, jobject canvas)
+{
+ JAWT awt;
+ JAWT_DrawingSurface* ds;
+ JAWT_DrawingSurfaceInfo* dsi;
+ JAWT_Win32DrawingSurfaceInfo* dsi_win;
+ jboolean result;
+ jint lock;
+ HGLRC hglrc;
+ BOOL mcResult;
+ LPVOID lpMsgBuf;
+ jclass cls_AWTGLCanvas;
+ jmethodID mid_doPaint;
+
+ // Get the AWT
+ awt.version = JAWT_VERSION_1_4;
+ result = JAWT_GetAWT(env, &awt);
+ if (result == JNI_FALSE) {
+ throwGeneralException(env, "java/lang/RuntimeException", "Failed get AWT.");
+ return;
+ }
+
+ // Get the drawing surface
+ ds = awt.GetDrawingSurface(env, canvas);
+ if (ds == NULL) {
+ throwGeneralException(env, "java/lang/RuntimeException", "Failed get drawing surface.");
+ return;
+ }
+
+ // Lock the drawing surface
+ lock = ds->Lock(ds);
+ if ((lock & JAWT_LOCK_ERROR) != 0) {
+ throwGeneralException(env, "java/lang/RuntimeException", "Failed to lock drawing surface.");
+ return;
+ }
+
+ // Get the drawing surface info
+ dsi = ds->GetDrawingSurfaceInfo(ds);
+
+ // Get the platform-specific drawing info
+ dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
+
+ hglrc = getContext(env, canvas);
+ mcResult = wglMakeCurrent(dsi_win->hdc, hglrc);
+ if (mcResult != TRUE) {
+ if (!FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL ))
+ {
+ // Handle the error.
+ printf("Failed\n");
+ } else {
+ printfDebug("%s\n", lpMsgBuf);
+ throwGeneralException(env, "java/lang/RuntimeException", lpMsgBuf);
+ // Free the buffer.
+ LocalFree( lpMsgBuf );
+ // Don't return yet, let's free up stuff
+ }
+ } else {
+ // Callback paint
+ cls_AWTGLCanvas = (*env)->GetObjectClass(env, canvas);
+ mid_doPaint = (*env)->GetMethodID(env, cls_AWTGLCanvas, "cPaint", "()V");
+ (*env)->CallVoidMethod(env, canvas, mid_doPaint);
+ SwapBuffers(dsi_win->hdc);
+ }
+
+ // Free the drawing surface info
+ ds->FreeDrawingSurfaceInfo(dsi);
+
+ // Unlock the drawing surface
+ ds->Unlock(ds);
+
+ // Free the drawing surface
+ awt.FreeDrawingSurface(ds);
+}
+
diff --git a/src/native/win32/org_lwjgl_opengl_Display.c b/src/native/win32/org_lwjgl_opengl_Display.c
index 68cd3425..be16fb3d 100644
--- a/src/native/win32/org_lwjgl_opengl_Display.c
+++ b/src/native/win32/org_lwjgl_opengl_Display.c
@@ -705,7 +705,7 @@ JNIEXPORT jobject JNICALL Java_org_lwjgl_opengl_Win32Display_init(JNIEnv *env, j
return initDisplay(env);
}
-static bool createARBContextAndPixelFormat(JNIEnv *env, HDC hdc, jobject pixel_format, int *pixel_format_index_return, HGLRC *context_return) {
+bool createARBContextAndPixelFormat(JNIEnv *env, HDC hdc, jobject pixel_format, int *pixel_format_index_return, HGLRC *context_return) {
int pixel_format_index;
HWND arb_hwnd;
HDC arb_hdc;