diff --git a/gl-natives/pom.xml b/gl-natives/pom.xml index 3f92aff..2b36aff 100644 --- a/gl-natives/pom.xml +++ b/gl-natives/pom.xml @@ -12,4 +12,31 @@ nar OpenRS2 GL Natives + + + + + com.github.maven-nar + nar-maven-plugin + + + + + shared + GL + + + shared + GLX + + + shared + jawt + + + + + + + diff --git a/gl-natives/src/main/c/jaggl.c b/gl-natives/src/main/c/jaggl.c new file mode 100644 index 0000000..910e241 --- /dev/null +++ b/gl-natives/src/main/c/jaggl.c @@ -0,0 +1,258 @@ +#include "jaggl_context.h" +#include "jaggl_opengl.h" + +#include +#include +#include +#include +#include + +#define JAGGL_LOCK(env) \ + JAWT awt = { .version = JAWT_VERSION_1_4 }; \ + bool awt_valid = JAWT_GetAWT(env, &awt); \ + if (awt_valid) { \ + awt.Lock(env); \ + } + +#define JAGGL_UNLOCK(env) \ + if (awt_valid) { \ + awt.Unlock(env); \ + } + +static Display *jaggl_display; +static XVisualInfo *jaggl_visual_info; +static VisualID jaggl_visual_id; +static GLXContext jaggl_context; +static GLXDrawable jaggl_drawable; +static int jaggl_alpha_bits; +static bool jaggl_double_buffered; + +static PFNGLXSWAPINTERVALSGIPROC jaggl_glXSwapIntervalSGI; + +static void jaggl_init_proc_table(void) { + jaggl_glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC) glXGetProcAddressARB((const GLubyte *) "glXSwapIntervalSGI"); +} + +JNIEXPORT jboolean JNICALL Java_jaggl_context_createContext(JNIEnv *env, jclass cls) { + JAGGL_LOCK(env); + + GLXContext current = glXGetCurrentContext(); + if (current) { + glXMakeCurrent(jaggl_display, None, NULL); + } + + if (jaggl_context) { + glXDestroyContext(jaggl_display, jaggl_context); + jaggl_context = NULL; + } + + jaggl_context = glXCreateContext(jaggl_display, jaggl_visual_info, NULL, True); + + JAGGL_UNLOCK(env); + return jaggl_context != NULL; +} + +JNIEXPORT jboolean JNICALL Java_jaggl_context_releaseContext(JNIEnv *env, jclass cls) { + JAGGL_LOCK(env); + + jboolean result = JNI_TRUE; + + GLXContext current = glXGetCurrentContext(); + if (current) { + result = (jboolean) glXMakeCurrent(jaggl_display, None, NULL); + } + + JAGGL_UNLOCK(env); + return result; +} + +JNIEXPORT jboolean JNICALL Java_jaggl_context_destroy(JNIEnv *env, jclass cls) { + JAGGL_LOCK(env); + + GLXContext current = glXGetCurrentContext(); + if (current) { + glXMakeCurrent(jaggl_display, None, NULL); + } + + if (jaggl_context) { + glXDestroyContext(jaggl_display, jaggl_context); + jaggl_context = NULL; + } + + if (jaggl_visual_info) { + XFree(jaggl_visual_info); + jaggl_visual_info = NULL; + } + + jaggl_display = None; + + JAGGL_UNLOCK(env); + return JNI_TRUE; +} + +JNIEXPORT jboolean JNICALL Java_jaggl_context_swapBuffers(JNIEnv *env, jclass cls) { + JAGGL_LOCK(env); + + if (jaggl_double_buffered) { + glXSwapBuffers(jaggl_display, jaggl_drawable); + } else { + glFlush(); + } + + JAGGL_UNLOCK(env); + return JNI_TRUE; +} + +JNIEXPORT jint JNICALL Java_jaggl_context_getLastError(JNIEnv *env, jclass cls) { + return 0; +} + +JNIEXPORT void JNICALL Java_jaggl_context_setSwapInterval(JNIEnv *env, jclass cls, jint interval) { + JAGGL_LOCK(env); + + if (jaggl_glXSwapIntervalSGI) { + jaggl_glXSwapIntervalSGI(interval); + } + + JAGGL_UNLOCK(env); +} + +JNIEXPORT jstring JNICALL Java_jaggl_context_getExtensionsString(JNIEnv *env, jclass cls) { + JAGGL_LOCK(env); + + const char *extensions_str = glXQueryExtensionsString(jaggl_display, jaggl_visual_info->screen); + jstring extensions = (*env)->NewStringUTF(env, extensions_str); + + JAGGL_UNLOCK(env); + return extensions; +} + +JNIEXPORT jint JNICALL Java_jaggl_context_getAlphaBits(JNIEnv *env, jclass cls) { + return jaggl_alpha_bits; +} + +JNIEXPORT jboolean JNICALL Java_jaggl_context_choosePixelFormat1(JNIEnv *env, jclass cls, jobject component, jint num_samples, jint alpha_bits) { + JAGGL_LOCK(env); + + jboolean result = JNI_FALSE; + + if (!awt_valid) { + goto awt_unlock; + } + + JAWT_DrawingSurface *ds = awt.GetDrawingSurface(env, component); + if (!ds) { + goto awt_unlock; + } + + jint lock_result = ds->Lock(ds); + if ((lock_result & JAWT_LOCK_ERROR) != 0) { + goto ds_free; + } + + JAWT_DrawingSurfaceInfo *dsi = ds->GetDrawingSurfaceInfo(ds); + if (!dsi) { + goto ds_unlock; + } + + JAWT_X11DrawingSurfaceInfo *platformInfo = (JAWT_X11DrawingSurfaceInfo *) dsi->platformInfo; + if (!platformInfo) { + goto dsi_free; + } + + jaggl_display = platformInfo->display; + jaggl_drawable = platformInfo->drawable; + jaggl_visual_id = platformInfo->visualID; + + if (!glXQueryExtension(jaggl_display, NULL, NULL)) { + goto dsi_free; + } + + XWindowAttributes window_attribs; + if (XGetWindowAttributes(jaggl_display, jaggl_drawable, &window_attribs)) { + XVisualInfo visual_info_template = { .visualid = window_attribs.visual->visualid }; + int matches; + jaggl_visual_info = XGetVisualInfo(jaggl_display, VisualIDMask, &visual_info_template, &matches); + if (jaggl_visual_info) { + int value; + glXGetConfig(jaggl_display, jaggl_visual_info, GLX_DOUBLEBUFFER, &value); + jaggl_double_buffered = value; + + glXGetConfig(jaggl_display, jaggl_visual_info, GLX_ALPHA_SIZE, &value); + jaggl_alpha_bits = value; + + result = JNI_TRUE; + goto dsi_free; + } + } + + for (int i = 0; i < 2; i++) { + bool double_buffered = i == 0; + int attribs[] = { + GLX_RGBA, + GLX_RED_SIZE, + 8, + GLX_GREEN_SIZE, + 8, + GLX_BLUE_SIZE, + 8, + GLX_ALPHA_SIZE, + alpha_bits, + GLX_DEPTH_SIZE, + 24, + GLX_SAMPLE_BUFFERS, + num_samples ? True : False, + GLX_SAMPLES, + num_samples, + double_buffered ? GLX_DOUBLEBUFFER : None, + None + }; + jaggl_visual_info = glXChooseVisual(jaggl_display, DefaultScreen(jaggl_display), attribs); + if (jaggl_visual_info) { + jaggl_double_buffered = double_buffered; + jaggl_alpha_bits = alpha_bits; + + result = JNI_TRUE; + goto dsi_free; + } + } + +dsi_free: + ds->FreeDrawingSurfaceInfo(dsi); +ds_unlock: + ds->Unlock(ds); +ds_free: + awt.FreeDrawingSurface(ds); +awt_unlock: + JAGGL_UNLOCK(env); + return result; +} + +JNIEXPORT jboolean JNICALL Java_jaggl_context_makeCurrent1(JNIEnv *env, jclass cls) { + JAGGL_LOCK(env); + + jboolean result = JNI_FALSE; + + if (!jaggl_context) { + goto done; + } + + GLXContext current = glXGetCurrentContext(); + if (jaggl_context == current) { + result = JNI_TRUE; + goto done; + } + + glXMakeCurrent(jaggl_display, None, NULL); + + if (!glXMakeCurrent(jaggl_display, jaggl_drawable, jaggl_context)) { + goto done; + } + + jaggl_init_proc_table(); + result = JNI_TRUE; + +done: + JAGGL_UNLOCK(env); + return result; +}