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;