在 Java AWT Canvas 中嵌入 OpenGL






4.50/5 (4投票s)
2000年10月26日

147241

592
本文展示了如何使用 JDK1.3 的 JAWT 接口在 Java AWT 画布中使用 OpenGL 调用。

引言
本文提供了一个将 OpenGL 代码添加到 Java 应用程序的框架。示例项目展示了如何在 AWT 画布小部件内运行 OpenGL 动画。这得益于最新 JDK1.3 中的基于 JNI 的 JAWT 接口。
为了实现这一点,需要解决两个主要问题。
问题 #1 通过使用 JDK 1.3 中提供的已记录的 API 解决。以下网址解释了 JAWT 接口及其使用方法:
http://java.sun.com/j2se/1.3/docs/guide/awt/AWT_Native_Interface.html
以下是项目中的一段摘录,展示了实现方式:
// Helper class for accessing JAWT Information.
class JAWT_Info 
{
private:
    JAWT awt;
    JAWT_DrawingSurface* ds;
    JAWT_DrawingSurfaceInfo* dsi;
    JAWT_Win32DrawingSurfaceInfo* dsi_win;
public:
    JAWT_Info(JNIEnv *env, jobject panel)
    {
        jboolean result;
        jint lock;
        // Get the AWT
        awt.version = JAWT_VERSION_1_3;
        result = JAWT_GetAWT(env, &awt);
        assert(result != JNI_FALSE);
        // Get the drawing surface
        ds = awt.GetDrawingSurface(env, panel);
        if(ds == NULL)
            return;
        // Lock the drawing surface
        lock = ds->Lock(ds);
        assert((lock & JAWT_LOCK_ERROR) == 0);
        // Get the drawing surface info
        dsi = ds->GetDrawingSurfaceInfo(ds);
        // Get the platform-specific drawing info
        dsi_win = (JAWT_Win32DrawingSurfaceInfo*)dsi->platformInfo;
    }
    HWND getHWND()
    {
        if(dsi_win == NULL)
            return NULL;
        return dsi_win->hwnd;
    }
    HDC getHDC()
    {
        if(dsi_win == NULL)
            return NULL;
        return dsi_win->hdc;
    }
    virtual ~JAWT_Info()
    {
        if(ds != NULL)
        {
            // Free the drawing surface info
            ds->FreeDrawingSurfaceInfo(dsi);
            // Unlock the drawing surface
            ds->Unlock(ds);
            // Free the drawing surface
            awt.FreeDrawingSurface(ds);
        }
    }
};
问题 #2 在获得 HWND 后就变得很简单了。以下是项目中的一段摘录,展示了如何初始化 OpenGL:
// Static variables for the OpenGL calls.
static HGLRC    hRC = NULL;
static HDC      hDC = NULL;
/*
 * Class:     MyWindow
 * Method:    initializeOpenGL
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_MyWindow_initializeOpenGL
  (JNIEnv *env, jobject panel)
{
    // get the window handle
    JAWT_Info info(env, panel);
    HWND hWnd = (HWND)info.getHWND();
    if(hWnd == NULL)
        return;
    PIXELFORMATDESCRIPTOR pfd;
    int iFormat;
    // get the device context (DC)
    HWND hwnd = info.getHWND();
    hDC = ::GetDC(hwnd);
    // set the pixel format for the DC
    ::ZeroMemory( &pfd, sizeof( pfd ) );
    pfd.nSize = sizeof( pfd );
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | 
    PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 24;
    pfd.cDepthBits = 16;
    pfd.iLayerType = PFD_MAIN_PLANE;
    iFormat = ::ChoosePixelFormat( hDC, &pfd );
    ::SetPixelFormat( hDC, iFormat, &pfd );
    // create and enable the render context (RC)
    hRC = ::wglCreateContext( hDC );
    ::wglMakeCurrent( hDC, hRC );
}
以下是项目中的一段摘录,展示了如何使用 OpenGL 进行绘制:
/*
 * Class:     MyWindow
 * Method:    paint
 * Signature: (Ljava/awt/Graphics;)V
 */
JNIEXPORT void JNICALL Java_MyWindow_paintOpenGL
  (JNIEnv *env, jobject panel)
{
    static float theta = 0.0f;
    // get the window handle
    JAWT_Info info(env, panel);
    HWND hWnd = (HWND)info.getHWND();
    if(hWnd == NULL)
        return;
    // OpenGL animation code goes here
    ::glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
    ::glClear( GL_COLOR_BUFFER_BIT );
    ::glPushMatrix();
    ::glRotatef( theta, 0.0f, 0.0f, 1.0f );
    ::glBegin( GL_TRIANGLES );
    ::glColor3f( 1.0f, 0.0f, 0.0f ); glVertex2f( 0.0f, 1.0f );
    ::glColor3f( 0.0f, 1.0f, 0.0f ); glVertex2f( 0.87f, -0.5f );
    ::glColor3f( 0.0f, 0.0f, 1.0f ); glVertex2f( -0.87f, -0.5f );
    ::glEnd();
    ::glPopMatrix();
    ::SwapBuffers( hDC );
    theta += 1.0f;
}
完成之后,这是清理代码:
/*
 * Class:     MyWindow
 * Method:    cleanupOpenGL
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_MyWindow_cleanupOpenGL
(JNIEnv *env, jobject panel)
{
    // get the window handle
    JAWT_Info info(env, panel);
    HWND hWnd = (HWND)info.getHWND();
    if(hWnd == NULL)
        return;
    ::wglMakeCurrent( NULL, NULL );
    ::wglDeleteContext( hRC );
    ::ReleaseDC( hWnd, hDC );
}
上述 zip 文件包含本文的所有源代码,以及用于构建和运行代码的批处理文件。
- jGuru.com 上的 JNI 常见问题解答
 http://www.jguru.com/faq/JNI
- Java 技巧 86:在 JDK 1.3 中支持本机渲染
 http://www.javaworld.com/javaworld/javatips/jw-javatip86.html
- Sun 对 AWT 本机接口的介绍
 hhttp://java.sun.com/j2se/1.3/docs/guide/awt/AWT_Native_Interface.html
- Sun 关于 Java 2 SDK 版本 1.3 中 AWT 增强功能的介绍
 http://java.sun.com/products/jdk/1.3/docs/guide/awt/enhancements.html
- Sun 关于 JAWT 接口改进的本机绘图,Kestrel 之后(需要免费注册)
 http://developer.java.sun.com/developer/bugParade/bugs/4281429.html
- “使用 Java 本机接口 (JNI) 增强您的 Java 应用程序”,Tal Lyron(JavaWorld,1999 年 10 月)
 http://www.javaworld.com/javaworld/jw-10-1999/jw-10-jni.html
- “Java 技巧 23:编写本机方法”,John D. Mitchell (JavaWorld):
 http://www.javaworld.com/javaworld/javatips/jw-javatip23.html
