diff options
author | Chien Yang <[email protected]> | 2004-10-01 01:04:36 +0000 |
---|---|---|
committer | Chien Yang <[email protected]> | 2004-10-01 01:04:36 +0000 |
commit | eced19d79a943c18f54dc7cbe693243e5953e792 (patch) | |
tree | 0d98627cc82661e26d4b94a1fce24c46f27261b9 /src/native/ogl | |
parent | 7a5f73109c44b123dd6e785163f2a2aa2d53730a (diff) |
With this fix Java 3D will require GLX 1.3 or higher to
compile or run.
1) Fixed issue 20 - Off-screen rendering doesn't work on Linux.
2) Cleanup native chooseOglVisual code.
git-svn-id: https://svn.java.net/svn/j3d-core~svn/trunk@50 ba19aa83-45c5-6ac9-afd3-db810772062c
Diffstat (limited to 'src/native/ogl')
-rw-r--r-- | src/native/ogl/Canvas3D.c | 487 | ||||
-rw-r--r-- | src/native/ogl/NativeConfigTemplate3D.c | 482 | ||||
-rw-r--r-- | src/native/ogl/NativeScreenInfo.c | 69 |
3 files changed, 552 insertions, 486 deletions
diff --git a/src/native/ogl/Canvas3D.c b/src/native/ogl/Canvas3D.c index 146d531..ab8f1db 100644 --- a/src/native/ogl/Canvas3D.c +++ b/src/native/ogl/Canvas3D.c @@ -423,7 +423,7 @@ BOOL getPropertiesFromCurrentContext( jlong hdc, int pixelFormat, long display, - jlong vinfo) + int stencilSize) { JNIEnv table = *env; @@ -434,7 +434,7 @@ BOOL getPropertiesFromCurrentContext( char *tmpExtensionStr; int versionNumbers[2]; char *cgHwStr = 0; - int stencilSize; + #ifdef WIN32 PFNWGLGETPIXELFORMATATTRIBIVEXTPROC wglGetPixelFormatAttribivEXT = NULL; @@ -942,10 +942,8 @@ BOOL getPropertiesFromCurrentContext( ctxInfo->global_alpha_sun = JNI_FALSE; } } - - glXGetConfig((Display *) display, (XVisualInfo *) vinfo, GLX_STENCIL_SIZE, &stencilSize); -#endif +#endif /* Solaris or Linux */ if (stencilSize > 1) { ctxInfo->extMask |= javax_media_j3d_Canvas3D_STENCIL_BUFFER; @@ -1081,33 +1079,46 @@ LONG WINAPI WndProc( HWND hWnd, UINT msg, #endif /*end of WIN32 */ - - JNIEXPORT -jlong JNICALL Java_javax_media_j3d_Canvas3D_createContext( +jlong JNICALL Java_javax_media_j3d_Canvas3D_createNewContext( JNIEnv *env, jobject obj, jlong display, jint window, jint vid, - jlong visInfo, + jlong fbConfigListPtr, jlong sharedCtxInfo, jboolean isSharedCtx, jboolean offScreen) { jlong gctx; jlong sharedCtx; - + int stencilSize=0; + static GLboolean first_time = GL_TRUE; static GLboolean force_normalize = GL_FALSE; GraphicsContextPropertiesInfo *ctxInfo = NULL; GraphicsContextPropertiesInfo *sharedCtxStructure; int PixelFormatID=0; - + #if defined(SOLARIS) || defined(__linux__) + + /* Fix for issue 20 */ + GLXContext ctx; jlong hdc; + + GLXFBConfig *fbConfigList = NULL; + + fbConfigList = (GLXFBConfig *)fbConfigListPtr; + + /* + fprintf(stderr, "Canvas3D_createNewContext: \n"); + fprintf(stderr, "fbConfigListPtr 0x%x\n", (int) fbConfigListPtr); + fprintf(stderr, "fbConfigList 0x%x, fbConfigList[0] 0x%x\n", + (int) fbConfigList, (int) fbConfigList[0]); + */ if(sharedCtxInfo == 0) sharedCtx = 0; @@ -1117,37 +1128,47 @@ jlong JNICALL Java_javax_media_j3d_Canvas3D_createContext( } if (display == 0) { - fprintf(stderr, "Canvas3D_createContext: display is null\n"); + fprintf(stderr, "Canvas3D_createNewContext: display is null\n"); ctx = NULL; } - else if (visInfo == 0) { + else if((fbConfigList == NULL) || (fbConfigList[0] == NULL)) { /* - * visInfo must be a valid pointer to an XVisualInfo struct returned - * by glXChooseVisual() for a physical screen. The visual id in vid + * fbConfig must be a valid pointer to an GLXFBConfig struct returned + * by glXChooseFBConfig() for a physical screen. The visual id in vid * is not sufficient for handling OpenGL with Xinerama mode disabled: * it doesn't distinguish between the physical screens making up the * virtual screen when the X server is running in Xinerama mode. */ - fprintf(stderr, "Canvas3D_createContext: visual is null\n"); + fprintf(stderr, "Canvas3D_createNewContext: FBConfig is null\n"); ctx = NULL; } else { - ctx = glXCreateContext((Display *)display, (XVisualInfo *)visInfo, - (GLXContext)sharedCtx, True); + ctx = glXCreateNewContext((Display *)display, fbConfigList[0], + GLX_RGBA_TYPE, (GLXContext)sharedCtx, True); } - if (ctx == NULL) { - fprintf(stderr, "Canvas3D_createContext: couldn't create context\n"); + fprintf(stderr, "Canvas3D_createNewContext: couldn't create context\n"); return 0; } - if (!glXMakeCurrent((Display *)display, (GLXDrawable)window, - (GLXContext)ctx)) { - fprintf( stderr, "Canvas3D_createContext: couldn't make current\n"); + /* There is a known interportability issue between Solaris and Linux(Nvidia) + on the new glxMakeContextCurrent() call. Bug Id 5109045. + if (!glXMakeContextCurrent((Display *)display, (GLXDrawable)window, + (GLXDrawable)window,(GLXContext)ctx)) { + */ + + if (!glXMakeCurrent((Display *)display, (GLXDrawable)window,(GLXContext)ctx)) { + + fprintf( stderr, "Canvas3D_createNewContext: couldn't make current\n"); return 0; } + + glXGetFBConfigAttrib((Display *) display, fbConfigList[0], + GLX_STENCIL_SIZE, &stencilSize); + + gctx = (jlong)ctx; #endif /* SOLARIS */ @@ -1219,7 +1240,6 @@ jlong JNICALL Java_javax_media_j3d_Canvas3D_createContext( PixelFormatID = vid; } - SetPixelFormat(hdc, PixelFormatID, &pfd); hrc = wglCreateContext( hdc ); @@ -1257,9 +1277,10 @@ jlong JNICALL Java_javax_media_j3d_Canvas3D_createContext( /* initialize the structure */ initializeCtxInfo(env, ctxInfo); - ctxInfo->context = gctx; - - if (!getPropertiesFromCurrentContext(env, obj, ctxInfo, (jlong) hdc, PixelFormatID, display, (jlong) visInfo)) { + ctxInfo->context = gctx; + + if (!getPropertiesFromCurrentContext(env, obj, ctxInfo, (jlong) hdc, PixelFormatID, + display, stencilSize)) { return 0; } @@ -2546,57 +2567,6 @@ int getTextureColorTableSize( return size; } -/* we want to use this if available: */ -#define GLX_SGIX_pbuffer 1 - -#ifndef GLX_VERSION_1_3 -#ifdef GLX_SGIX_pbuffer -#ifdef __linux__ -typedef XID GLXPbuffer; -typedef struct __GLXFBConfigRec *GLXFBConfig; -typedef struct __GLXFBConfigRec *GLXFBConfigSGIX; -extern GLXFBConfig * glXChooseFBConfig (Display *dpy, int screen, const int *attrib_list, int *nelements); -extern GLXPbuffer glXCreatePbuffer (Display *dpy, GLXFBConfig config, const int *attrib_list); -extern void glXDestroyPbuffer (Display *dpy, GLXPbuffer pbuf); -extern GLXFBConfigSGIX *glXChooseFBConfigSGIX(Display *dpy, int screen, const int *attribList, int *nitems); -extern GLXPbuffer glXCreateGLXPbufferSGIX(Display *dpy, GLXFBConfig config, unsigned int width, unsigned int height, const int *attribList); -extern void glXDestroyGLXPbufferSGIX(Display *dpy, GLXPbuffer pbuf); -#define GLX_DRAWABLE_TYPE 0x8010 -#define GLX_PBUFFER_BIT 0x00000004 -#define GLX_RENDER_TYPE 0x8011 -#define GLX_RGBA_BIT 0x00000001 -#define GLX_MAX_PBUFFER_WIDTH 0x8016 -#define GLX_MAX_PBUFFER_HEIGHT 0x8017 -#define GLX_PRESERVED_CONTENTS 0x801B -#define GLX_PBUFFER_HEIGHT 0x8040 /* New for GLX 1.3 */ -#define GLX_PBUFFER_WIDTH 0x8041 /* New for GLX 1.3 */ -#define GLX_LARGEST_PBUFFER 0x801C -#define GLX_LARGEST_PBUFFER_SGIX GLX_LARGEST_PBUFFER -#else - -#define GLX_DRAWABLE_TYPE GLX_DRAWABLE_TYPE_SGIX -#define GLX_PBUFFER_BIT GLX_PBUFFER_BIT_SGIX -#define GLX_RENDER_TYPE GLX_RENDER_TYPE_SGIX -#define GLX_RGBA_BIT GLX_RGBA_BIT_SGIX -#endif -#endif /* GLX_SGIX_pbuffer */ -#else -#ifdef __linux__ -typedef struct __GLXFBConfigRec *GLXFBConfigSGIX; -#endif /* __linux__ */ -#endif /* GLX_VERSION_1_3 */ - -#if defined(SOLARIS) || defined(__linux__) -#pragma weak glXChooseFBConfig -#pragma weak glXCreatePbuffer -#pragma weak glXDestroyPbuffer -#pragma weak glXChooseFBConfigSGIX -#pragma weak glXCreateGLXPbufferSGIX -#pragma weak glXDestroyGLXPbufferSGIX -#endif /* SOLARIS */ - - - /* For dvr support */ JNIEXPORT void JNICALL Java_javax_media_j3d_Canvas3D_videoResize( @@ -2650,146 +2620,121 @@ jint JNICALL Java_javax_media_j3d_Canvas3D_createOffScreenBuffer( jobject obj, jlong ctxInfo, jlong display, - jint vid, + jint window, + jlong fbConfigListPtr, jint width, jint height) { #if defined(SOLARIS) || defined(__linux__) - XVisualInfo *vinfo, template; - int nitems, depth, redSize; - Display *dpy; - static GLboolean pbufferSupported = GL_FALSE; - static GLboolean pbufferExtSupported = GL_FALSE; - int major, minor; - const char *extStr; - int status; - dpy = (Display *)display; + /* Fix for issue 20 */ + + const char *extStr; + int attrCount, configAttr[10]; + GLXPbuffer pbuff = None; + GLXFBConfig *fbConfigList = (GLXFBConfig *)fbConfigListPtr; + int val; + + /* + glXGetFBConfigAttrib((Display *) display, fbConfigList[0], + GLX_FBCONFIG_ID, &val); + fprintf(stderr, "GLX_FBCONFIG_ID returns %d\n", val); + + fprintf(stderr, "display 0x%x, fbConfigList[0] 0x%x, width %d, height %d\n", + (int) display, (int) fbConfigList[0], width, height); + + */ - if (dpy == NULL) - dpy = XOpenDisplay(NULL); + + /* Query DRAWABLE_TYPE. Will use Pbuffer if fbConfig support it, + else will try for Pixmap. If neither one exists, flag error message + and return None */ + + glXGetFBConfigAttrib((Display *) display, fbConfigList[0], + GLX_DRAWABLE_TYPE, &val); + /* fprintf(stderr, "GLX_DRAWABLE_TYPE returns %d\n", val); */ + + if ((val & GLX_PBUFFER_BIT) != 0) { - template.visualid = vid; - vinfo = XGetVisualInfo(dpy, VisualIDMask, &template, &nitems); - if (nitems != 1) { - fprintf(stderr, "Warning Canvas3D_createContext got unexpected number of matching visuals %d\n", nitems); - } - glXGetConfig (dpy, vinfo, GLX_BUFFER_SIZE, &depth); - glXGetConfig (dpy, vinfo, GLX_RED_SIZE, &redSize); + /* fprintf(stderr, "Using pbuffer %d\n", val); */ + + /* Initialize the attribute list to be used for choosing FBConfig */ + + attrCount = 0; + configAttr[attrCount++] = GLX_PBUFFER_WIDTH; + configAttr[attrCount++] = width; + configAttr[attrCount++] = GLX_PBUFFER_HEIGHT; + configAttr[attrCount++] = height; + configAttr[attrCount++] = GLX_PRESERVED_CONTENTS; + configAttr[attrCount++] = GL_TRUE; + configAttr[attrCount++] = None; + - if (status = glXQueryVersion(dpy, &major, &minor)) { + pbuff = glXCreatePbuffer((Display *) display, fbConfigList[0], configAttr); + + if (pbuff == None) { + fprintf(stderr, "Java 3D ERROR : glXCreateGLXPbuffer() returns None\n"); + } -#if 0 - /* don't use the 1.3 pbuffer interface for now. */ - if ((major > 1) || (major == 1 && minor >= 3)) - pbufferSupported = GL_TRUE; - else -#endif - { - extStr = glXQueryExtensionsString(dpy, DefaultScreen(dpy)); - if ((extStr != NULL) && (strstr(extStr, "GLX_SGIX_pbuffer"))) { - pbufferExtSupported = GL_TRUE; - } - } + return pbuff; } + else if((val & GLX_PIXMAP_BIT) != 0) { + Pixmap pixmap; + GLXPixmap glxpixmap = None; + XVisualInfo *vinfo; + Window root; + Window glWin; + XSetWindowAttributes win_attrs; + Colormap cmap; + unsigned long win_mask; + + /* fprintf(stderr, "Using pixmap %d\n", val); */ + vinfo = glXGetVisualFromFBConfig((Display*)display, fbConfigList[0]); + if (vinfo == NULL) { + fprintf(stderr, "Java 3D ERROR : glXGetVisualFromFBConfig failed\n"); + } + else { + /* fprintf(stderr, "found a %d-bit visual (visual ID = 0x%x)\n", + vinfo->depth, vinfo->visualid); */ + + /* fall back to pixmap */ + root = RootWindow((Display *)display, vinfo->screen); + + /* Create a colormap */ + cmap = XCreateColormap((Display *)display, root, vinfo->visual, AllocNone); + + /* Create a window */ + win_attrs.colormap = cmap; + win_attrs.border_pixel = 0; + win_mask = CWColormap | CWBorderPixel; + glWin = XCreateWindow((Display *)display, root, 0, 0, 1, 1, 0, + vinfo->depth, InputOutput, vinfo->visual, + win_mask, &win_attrs); + + /* fprintf(stderr, "glWin %d\n",(int) glWin); */ + + pixmap = XCreatePixmap((Display*)display, (GLXDrawable)glWin, + width, height, vinfo->depth); + + /* fprintf(stderr, "XCreatePixmap returns %d\n", (int) pixmap); */ + + glxpixmap = glXCreatePixmap((Display*)display, fbConfigList[0], pixmap, NULL); + if (glxpixmap == None) { + fprintf(stderr, "Java 3D ERROR : glXCreateGLXPixmap() returns None\n"); + } + } -#if defined(GLX_VERSION_1_3) || defined(GLX_SGIX_pbuffer) - if (pbufferExtSupported || pbufferSupported) { - - - int attrCount, configAttr[10], numConfig, val; - GLXPbuffer pbuff; - - /* Initialize the attribute list to be used for choosing FBConfig */ - attrCount = 0; - configAttr[attrCount++] = GLX_DRAWABLE_TYPE; - configAttr[attrCount++] = GLX_PBUFFER_BIT; - configAttr[attrCount++] = GLX_RENDER_TYPE; - configAttr[attrCount++] = GLX_RGBA_BIT; - configAttr[attrCount++] = GLX_RED_SIZE; - configAttr[attrCount++] = redSize; - configAttr[attrCount++] = None; -/* - configAttr[attrCount++] = GLX_DEPTH_SIZE; - configAttr[attrCount++] = depth; -*/ - - -#ifdef GLX_VERSION_1_3 - if (pbufferSupported) { - GLXFBConfig *fbconfiglst; - - fbconfiglst = glXChooseFBConfig(dpy, DefaultScreen(dpy), - configAttr, &numConfig); - - if (numConfig < 1) { - fprintf(stderr, "# of configs returned is %d\n", numConfig); - return None; - } - - attrCount = 0; - configAttr[attrCount++] = GLX_PBUFFER_WIDTH; - configAttr[attrCount++] = width; - configAttr[attrCount++] = GLX_PBUFFER_HEIGHT; - configAttr[attrCount++] = height; - configAttr[attrCount++] = GLX_PRESERVED_CONTENTS; - configAttr[attrCount++] = GL_TRUE; - configAttr[attrCount++] = None; - - - pbuff = glXCreatePbuffer(dpy, fbconfiglst[0], configAttr); - } -#endif /* GLX_VERSION_1_3 */ - -#ifdef GLX_SGIX_pbuffer - if (pbufferExtSupported && !pbufferSupported) { - GLXFBConfigSGIX *fbconfiglst; - - - /* Determine what config to use according to config_attr */ - fbconfiglst = glXChooseFBConfigSGIX(dpy, DefaultScreen(dpy), - configAttr, &numConfig); - - if (numConfig < 1) { - fprintf(stderr, "# of configs returned is %d\n", numConfig); - return None; - } - - attrCount = 0; - configAttr[attrCount++] = GLX_PRESERVED_CONTENTS; - configAttr[attrCount++] = GL_TRUE; - configAttr[attrCount++] = None; - pbuff = glXCreateGLXPbufferSGIX(dpy, fbconfiglst[0], width, height, - configAttr ); - } -#endif /* GLX_SGIX_pbuffer */ - if (pbuff == None) { - fprintf(stderr, "glXCreateGLXPbuffer() returns None\n"); - } - - return pbuff; - - } else -#endif /* GLX_VERSION_1_3 || GLX_SGIX_pbuffer */ - - { - Pixmap pixmap; - GLXPixmap glxpixmap; - - /* fall back to pixmap */ - pixmap = XCreatePixmap(dpy, DefaultRootWindow(dpy), width, height, - vinfo->depth); - - glxpixmap = glXCreateGLXPixmap(dpy, vinfo, pixmap); - if (glxpixmap == None) { - fprintf(stderr, "glXCreateGLXPixmap() returns None\n"); - } - - return glxpixmap; + /* fprintf(stderr, "glxpixmap %d\n",(int) glxpixmap); */ + return glxpixmap; + } + else { + fprintf(stderr, "Java 3D ERROR : FBConfig doesn't support pbuffer or pixmap returns None\n"); + return None; } + #endif /* SOLARIS */ #ifdef WIN32 @@ -2857,45 +2802,25 @@ void JNICALL Java_javax_media_j3d_Canvas3D_destroyOffScreenBuffer( jobject obj, jlong ctxInfo, jlong display, + jlong fbConfigListPtr, jint window) { #if defined(SOLARIS) || defined(__linux__) - Display *dpy = (Display*)display; - - GLboolean pbufferSupported = GL_FALSE; - GLboolean pbufferExtSupported = GL_TRUE; - int major, minor; - char *extStr; - - if (glXQueryVersion(dpy, &major, &minor)) { - -#if 0 - /* don't use the 1.3 pbuffer interface for now. */ - if ((major > 1) || (major == 1 && minor >= 3)) - pbufferSupported = GL_TRUE; - else -#endif - { - extStr = (char *)glXQueryExtensionsString(dpy, - DefaultScreen(dpy)); - if ((extStr != NULL) && (strstr(extStr, "GLX_SGIX_pbuffer"))) { - pbufferExtSupported = GL_TRUE; - } - } - } - -#if defined(GLX_VERSION_1_3) || defined(GLX_SGIX_pbuffer) - - if (pbufferSupported) { - glXDestroyPbuffer(dpy, (GLXPbuffer)window); - } else if (pbufferExtSupported) { - glXDestroyGLXPbufferSGIX(dpy, (GLXPbuffer)window); - } else -#endif - - { - glXDestroyGLXPixmap(dpy, (GLXPixmap)window); - } + /* Fix for Issue 20 */ + GLXFBConfig *fbConfigList = (GLXFBConfig *)fbConfigListPtr; + int val; + + glXGetFBConfigAttrib((Display *) display, (GLXFBConfig) fbConfigList[0], + GLX_DRAWABLE_TYPE, &val); + /* fprintf(stderr, "GLX_DRAWABLE_TYPE returns %d\n", val); */ + + if((val & GLX_PBUFFER_BIT) != 0) { + glXDestroyPbuffer((Display *) display, (GLXPbuffer)window); + } + else if((val & GLX_PIXMAP_BIT) != 0) { + glXDestroyPixmap((Display *) display, (GLXPixmap)window); + } + #endif /* SOLARIS */ #ifdef WIN32 @@ -3159,17 +3084,22 @@ void JNICALL Java_javax_media_j3d_Canvas3D_createQueryContext( jlong display, jint window, jint vid, + jlong fbConfigListPtr, jboolean offScreen, jint width, jint height) { JNIEnv table = *env; jlong gctx; + int stencilSize=0; long newWin; int PixelFormatID=0; GraphicsContextPropertiesInfo* ctxInfo = (GraphicsContextPropertiesInfo *)malloc(sizeof(GraphicsContextPropertiesInfo)); #if defined(SOLARIS) || defined(__linux__) + + /* Fix for issue 20 */ + XVisualInfo *vinfo, template; int nitems; GLXContext ctx; @@ -3180,46 +3110,71 @@ void JNICALL Java_javax_media_j3d_Canvas3D_createQueryContext( Colormap cmap; unsigned long win_mask; jlong hdc; + + GLXFBConfig *fbConfigList = NULL; - template.visualid = vid; - vinfo = XGetVisualInfo((Display *)display, VisualIDMask, &template, &nitems); - if (nitems != 1) { - fprintf(stderr, "Warning Canvas3D_createQueryContext got unexpected number of matching visuals %d\n", nitems); - } + fbConfigList = (GLXFBConfig *)fbConfigListPtr; - ctx = glXCreateContext((Display *)display, vinfo, NULL, True); + /* + fprintf(stderr, "Canvas3D_createQueryContext:\n"); + fprintf(stderr, "fbConfigListPtr 0x%x\n", (int) fbConfigListPtr); + fprintf(stderr, "fbConfigList 0x%x, fbConfigList[0] 0x%x\n", + (int) fbConfigList, (int) fbConfigList[0]); + */ + + ctx = glXCreateNewContext((Display *)display, fbConfigList[0], + GLX_RGBA_TYPE, NULL, True); + if (ctx == NULL) { - fprintf(stderr, "Error Canvas3D_createQueryContext: couldn't create context.\n"); + fprintf(stderr, "Java 3D ERROR : Canvas3D_createQueryContext: couldn't create context.\n"); } /* create window if window == 0 and offscreen == true */ if(window == 0 && !offScreen) { - - root = RootWindow((Display *)display, vinfo->screen); - - /* Create a colormap */ - cmap = XCreateColormap((Display *)display, root, vinfo->visual, AllocNone); - /* Create a window */ - win_attrs.colormap = cmap; - win_attrs.border_pixel = 0; - win_attrs.event_mask = KeyPressMask | ExposureMask | StructureNotifyMask; - win_mask = CWColormap | CWBorderPixel | CWEventMask; - glWin = XCreateWindow((Display *)display, root, 0, 0, width, height, 0, vinfo->depth, - InputOutput, vinfo->visual, win_mask, &win_attrs); - newWin = (unsigned long)glWin; + vinfo = glXGetVisualFromFBConfig((Display*)display, fbConfigList[0]); + if (vinfo == NULL) { + fprintf(stderr, "Java 3D ERROR : glXGetVisualFromFBConfig failed\n"); + } + else { + /* fprintf(stderr, "found a %d-bit visual (visual ID = 0x%x)\n", + vinfo->depth, vinfo->visualid); + */ + root = RootWindow((Display *)display, vinfo->screen); + + /* Create a colormap */ + cmap = XCreateColormap((Display *)display, root, vinfo->visual, AllocNone); + + /* Create a window */ + win_attrs.colormap = cmap; + win_attrs.border_pixel = 0; + win_attrs.event_mask = KeyPressMask | ExposureMask | StructureNotifyMask; + win_mask = CWColormap | CWBorderPixel | CWEventMask; + glWin = XCreateWindow((Display *)display, root, 0, 0, width, height, 0, + vinfo->depth, InputOutput, vinfo->visual, + win_mask, &win_attrs); + newWin = (unsigned long)glWin; + } } else if(window == 0 && offScreen){ - newWin = Java_javax_media_j3d_Canvas3D_createOffScreenBuffer( env, obj, 0, display, vid, width, height); + newWin = Java_javax_media_j3d_Canvas3D_createOffScreenBuffer( env, obj, 0, + display, window, + fbConfigListPtr, + width, height); } else if(window != 0) { newWin = window; } - + result = glXMakeCurrent((Display *)display, (GLXDrawable)newWin, (GLXContext)ctx); if (result == GL_FALSE) - fprintf(stderr, "glXMakeCurrent fails\n"); + fprintf(stderr, "Java 3D ERROR : glXMakeCurrent fails\n"); + + glXGetFBConfigAttrib((Display *) display, fbConfigList[0], + GLX_STENCIL_SIZE, &stencilSize); + + gctx = (jlong)ctx; #endif @@ -3264,7 +3219,8 @@ void JNICALL Java_javax_media_j3d_Canvas3D_createQueryContext( hdc = GetDC(hWnd); } else if(window == 0 && offScreen){ - hdc = (HDC)Java_javax_media_j3d_Canvas3D_createOffScreenBuffer( env, obj, 0, display, vid, width, height); + hdc = (HDC)Java_javax_media_j3d_Canvas3D_createOffScreenBuffer( env, obj, 0, display, + window, vid, width, height); pfd.dwFlags = PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL | PFD_SUPPORT_GDI; vid = -1; @@ -3329,7 +3285,8 @@ void JNICALL Java_javax_media_j3d_Canvas3D_createQueryContext( ctxInfo->context = gctx; /* get current context properties */ - if (getPropertiesFromCurrentContext(env, obj, ctxInfo, (jlong) hdc, PixelFormatID, display, (jlong) vinfo)) { + if (getPropertiesFromCurrentContext(env, obj, ctxInfo, (jlong) hdc, PixelFormatID, display, + stencilSize)) { /* put the properties to the Java side */ setupCanvasProperties(env, obj, ctxInfo); } @@ -3353,7 +3310,7 @@ void JNICALL Java_javax_media_j3d_Canvas3D_createQueryContext( #endif /* WIN32 */ } else if(window == 0 && offScreen) { - Java_javax_media_j3d_Canvas3D_destroyOffScreenBuffer(env, obj, gctx, display, newWin); + Java_javax_media_j3d_Canvas3D_destroyOffScreenBuffer(env, obj, gctx, display, fbConfigListPtr, newWin); Java_javax_media_j3d_Canvas3D_destroyContext(env, obj, display, newWin, (jlong)ctxInfo); } else if(window != 0){ diff --git a/src/native/ogl/NativeConfigTemplate3D.c b/src/native/ogl/NativeConfigTemplate3D.c index ae2340f..4dbbfaa 100644 --- a/src/native/ogl/NativeConfigTemplate3D.c +++ b/src/native/ogl/NativeConfigTemplate3D.c @@ -37,151 +37,210 @@ extern int isExtensionSupported(const char *allExtensions, const char *extension #if defined(SOLARIS) || defined(__linux__) -XVisualInfo *findVisualInfoSwitchDoubleBufferAndStereo(jlong display, - jint screen, - int* glxAttrs, - int sVal, int sIndex, - int dbVal, int dbIndex ) { - int stereoLoop; - int doubleBufferLoop; - XVisualInfo *vis_info = NULL; - - int i, j; - /* - * set all "enums" to user's preferred state - */ - if (dbVal == REQUIRED || dbVal == PREFERRED) - glxAttrs[dbIndex] = GLX_DOUBLEBUFFER; - else - glxAttrs[dbIndex] = GLX_USE_GL; +/* Fix for issue 20 */ +#define MAX_GLX_ATTRS_LENGTH 25 - if (sVal == REQUIRED || sVal == PREFERRED) - glxAttrs[sIndex] = GLX_STEREO; - else - glxAttrs[sIndex] = GLX_USE_GL; - - vis_info = glXChooseVisual((Display*)display, screen, glxAttrs); - if (vis_info == NULL) { - /* - * coudn't match visual with default values - try - * enabling UNNECESSARY attributes. - */ - if(sVal == UNNECESSARY) - stereoLoop = 1; - else - stereoLoop = 0; - - if(dbVal == UNNECESSARY) - doubleBufferLoop = 1; - else - doubleBufferLoop = 0; +GLXFBConfig *find_S_FBConfigs(jlong display, + jint screen, + int* glxAttrs, + int sVal, int sIndex) { + + GLXFBConfig *fbConfigList = NULL; + int numFBConfigs, index; + + J3D_ASSERT((sIndex+3) < MAX_GLX_ATTRS_LENGTH); + + if (sVal == REQUIRED || sVal== PREFERRED) { + + index = sIndex; + glxAttrs[index++] = GLX_STEREO; + glxAttrs[index++] = True; + glxAttrs[index] = None; - i = 0; - while(i <= stereoLoop && vis_info == NULL ) { - if (sVal == UNNECESSARY) - glxAttrs[sIndex] = i? GLX_STEREO : GLX_USE_GL; - j = 0; - while(j <= doubleBufferLoop && vis_info == NULL) { - if(dbVal == UNNECESSARY) { - glxAttrs[dbIndex] = j? GLX_USE_GL: GLX_DOUBLEBUFFER; - } - vis_info = glXChooseVisual((Display*)display, screen, glxAttrs); - j++; - } /* end of doubleBufferLoop */ - i++; - } /* end of stereoLoop */ + fbConfigList = glXChooseFBConfig((Display*)display, screen, + glxAttrs, &numFBConfigs); + + if(fbConfigList != NULL) { + return fbConfigList; + } } + + if (sVal == UNNECESSARY || sVal== PREFERRED) { + /* This is a workaround to BugId : 5106472 in Solaris OGL. + We can't set glxAttrs with GLX_STEREO follow by a boolean */ - if (vis_info == NULL) { - /* - * still coudn't match visual with default values - try - * disabling PREFERRED attributes. - */ - /* restore default values */ - if (sVal == REQUIRED || sVal == PREFERRED) - glxAttrs[sIndex] = GLX_STEREO; - else - glxAttrs[sIndex] = GLX_USE_GL; - - if (dbVal == REQUIRED || dbVal == PREFERRED) - glxAttrs[dbIndex] = GLX_DOUBLEBUFFER; - else - glxAttrs[dbIndex] = GLX_USE_GL; - - if(sVal == PREFERRED) - stereoLoop = 1; - else - stereoLoop = 0; + index = sIndex; + glxAttrs[index] = None; - if(dbVal == PREFERRED) - doubleBufferLoop = 1; - else - doubleBufferLoop = 0; + /* For debug only + { + int i=0; + fprintf(stderr, "find_S_FBConfigs sVal = %d\n", sVal); + + while(glxAttrs[i] != None) { + fprintf(stderr, "glxAttrs[%d] = %x", i, glxAttrs[i]); + i++; + fprintf(stderr, " glxAttrs[%d] = %x\n", i, glxAttrs[i]); + i++; + } + } + */ + fbConfigList = glXChooseFBConfig((Display*)display, screen, + glxAttrs, &numFBConfigs); - i = 0; - while(i <= stereoLoop && vis_info == NULL ) { - if (sVal == PREFERRED) - glxAttrs[sIndex] = i? GLX_USE_GL : GLX_STEREO ; - j = 0; - while(j <= doubleBufferLoop && vis_info == NULL) { - if(dbVal == PREFERRED) { - glxAttrs[dbIndex] = j? GLX_DOUBLEBUFFER : GLX_USE_GL; - } - vis_info = glXChooseVisual((Display*)display, screen, glxAttrs); - j++; - } /* end of doubleBufferLoop */ - i++; - } /* end of stereoLoop */ + if(fbConfigList != NULL) { + return fbConfigList; + } } - if (vis_info == NULL) { + if (sVal == UNNECESSARY) { + index = sIndex; + glxAttrs[index++] = GLX_STEREO; + glxAttrs[index++] = True; + glxAttrs[index] = None; + + fbConfigList = glXChooseFBConfig((Display*)display, screen, + glxAttrs, &numFBConfigs); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + + return NULL; +} + +GLXFBConfig *find_AA_S_FBConfigs(jlong display, + jint screen, + int* glxAttrs, + int sVal, + int antialiasVal, int antialiasIndex) { + + const char *glxExtensions = NULL; + GLXFBConfig *fbConfigList = NULL; + int index = antialiasIndex; + + + J3D_ASSERT((antialiasIndex+7) < MAX_GLX_ATTRS_LENGTH); + + if(antialiasVal == REQUIRED || antialiasVal== PREFERRED) { + glxExtensions = (const char *) glXGetClientString((Display*)display, GLX_EXTENSIONS); + + if(isExtensionSupported(glxExtensions, "GLX_ARB_multisample")){ + + index = antialiasIndex; + glxAttrs[index++] = GLX_SAMPLE_BUFFERS_ARB; + glxAttrs[index++] = 1; + glxAttrs[index++] = GLX_SAMPLES_ARB; + glxAttrs[index++] = 1; + glxAttrs[index] = None; - /* - * STILL coudn't match visual with default values - try - * disabling PREFERRED attributes and enabling UNNECESSARY. - */ + fbConfigList = find_S_FBConfigs(display, screen, + glxAttrs, sVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + } + + if ( antialiasVal == REQUIRED ) { + index = antialiasIndex; + glxAttrs[index++] = GLX_ACCUM_RED_SIZE; + glxAttrs[index++] = 8; + glxAttrs[index++] = GLX_ACCUM_GREEN_SIZE; + glxAttrs[index++] = 8; + glxAttrs[index++] = GLX_ACCUM_BLUE_SIZE; + glxAttrs[index++] = 8; + glxAttrs[index] = None; - /* restore default values */ - if (sVal == REQUIRED || sVal == PREFERRED) - glxAttrs[sIndex] = GLX_STEREO; - else - glxAttrs[sIndex] = GLX_USE_GL; - - if (dbVal == REQUIRED || dbVal == PREFERRED) - glxAttrs[dbIndex] = GLX_DOUBLEBUFFER; - else - glxAttrs[dbIndex] = GLX_USE_GL; - - if(sVal != REQUIRED) - stereoLoop = 1; - else - stereoLoop = 0; + fbConfigList = find_S_FBConfigs(display, screen, + glxAttrs, sVal, index); - if(dbVal != REQUIRED) - doubleBufferLoop = 1; - else - doubleBufferLoop = 0; - - i = 0; - while(i <= stereoLoop && vis_info == NULL ) { - if (sVal == PREFERRED || sVal == UNNECESSARY) - glxAttrs[sIndex] = i? GLX_USE_GL : GLX_STEREO ; - j = 0; - while(j <= doubleBufferLoop && vis_info == NULL) { - if(dbVal == PREFERRED || dbVal == UNNECESSARY) { - glxAttrs[dbIndex] = j? GLX_DOUBLEBUFFER : GLX_USE_GL; - } - vis_info = glXChooseVisual((Display*)display, screen, glxAttrs); - j++; - } /* end of doubleBufferLoop */ - i++; - } /* end of stereoLoop */ + if(fbConfigList != NULL) { + return fbConfigList; + } + } + + glxAttrs[antialiasIndex] = None; + + if (antialiasVal == UNNECESSARY || antialiasVal == PREFERRED) { + fbConfigList = find_S_FBConfigs(display, screen, + glxAttrs, sVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + /* We will stop trying even if no fbConfigList is found and + antialiasVal = UNNECESSARY */ + + return NULL; + +} + +GLXFBConfig *find_DB_AA_S_FBConfigs(jlong display, + jint screen, + int* glxAttrs, + int sVal, int dbVal, + int antialiasVal, int dbIndex) { + + GLXFBConfig *fbConfigList = NULL; + int index = dbIndex; + + J3D_ASSERT((dbIndex+3) < MAX_GLX_ATTRS_LENGTH); + + if (dbVal == REQUIRED || dbVal== PREFERRED) { + + index = dbIndex; + glxAttrs[index++] = GLX_DOUBLEBUFFER; + glxAttrs[index++] = True; + glxAttrs[index] = None; + + fbConfigList = find_AA_S_FBConfigs(display, screen, + glxAttrs, sVal, + antialiasVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + + if (dbVal == UNNECESSARY || dbVal== PREFERRED) { + index = dbIndex; + glxAttrs[index++] = GLX_DOUBLEBUFFER; + glxAttrs[index++] = False; + glxAttrs[index] = None; + + fbConfigList = find_AA_S_FBConfigs(display, screen, + glxAttrs, sVal, + antialiasVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } + } + + if (dbVal == UNNECESSARY) { + index = dbIndex; + glxAttrs[index++] = GLX_DOUBLEBUFFER; + glxAttrs[index++] = True; + glxAttrs[index] = None; + + fbConfigList = find_AA_S_FBConfigs(display, screen, + glxAttrs, sVal, + antialiasVal, index); + + if(fbConfigList != NULL) { + return fbConfigList; + } } - return vis_info; + + return NULL; } /* - * Uses the past in array to choose the best OpenGL visual. + * Uses the passed in array to choose the best OpenGL visual. * When the "best" visual cannot be used, the "enums" (three * state attributes) are looped through setting/resetting in all * combinations in hopes of finding an valid visual. @@ -193,34 +252,47 @@ jint JNICALL Java_javax_media_j3d_NativeConfigTemplate3D_chooseOglVisual( jlong display, jint screen, jintArray attrList, - jlongArray vInfArray) + jlongArray fbConfigArray) { - VisualID vis_id = 0; jint *mx_ptr; - int glxAttrs[256]; /* value, attr pair plus a None */ + int glxAttrs[MAX_GLX_ATTRS_LENGTH]; /* value, attr pair plus a None */ int index; - XVisualInfo *vis_info = NULL; + GLXFBConfig *fbConfigList = NULL; /* use to cycle through when attr is not REQUIRED */ int sVal; - int sIndex; + int dbVal; + int antialiasVal; - int dbVal; - int dbIndex; + int drawableIndex; - int antialiasVal; - int antialiasIndex; + jlong *fbConfigListPtr = NULL; + int status, major, minor; - const char *glxExtensions = NULL; - jlong *visInfo = (*env)->GetLongArrayElements(env, vInfArray, NULL); + Display *dpy = (Display *) display; + fbConfigListPtr = (*env)->GetLongArrayElements(env, fbConfigArray, NULL); mx_ptr = (jint *)(*env)->GetPrimitiveArrayCritical(env, attrList, NULL); /* * convert Java 3D values to GLX */ index = 0; - glxAttrs[index++] = GLX_RGBA; /* only interested in RGB visuals */ + + /* Specify pbuffer as default */ + /* Fix for Issue 20 */ + glxAttrs[index++] = GLX_DRAWABLE_TYPE; + drawableIndex = index; + glxAttrs[index++] = (GLX_PBUFFER_BIT | GLX_WINDOW_BIT); + + /* only interested in RGBA type */ + glxAttrs[index++] = GLX_RENDER_TYPE; + glxAttrs[index++] = GLX_RGBA_BIT; + + /* only interested in FBConfig with associated X Visual type */ + glxAttrs[index++] = GLX_X_RENDERABLE; + glxAttrs[index++] = True; + glxAttrs[index++] = GLX_RED_SIZE; glxAttrs[index++] = mx_ptr[RED_SIZE]; glxAttrs[index++] = GLX_GREEN_SIZE; @@ -229,107 +301,81 @@ jint JNICALL Java_javax_media_j3d_NativeConfigTemplate3D_chooseOglVisual( glxAttrs[index++] = mx_ptr[BLUE_SIZE]; glxAttrs[index++] = GLX_DEPTH_SIZE; glxAttrs[index++] = mx_ptr[DEPTH_SIZE]; - + glxAttrs[index] = None; - dbIndex = index++; dbVal = mx_ptr[DOUBLEBUFFER]; - - sIndex = index++; sVal = mx_ptr[STEREO]; - - antialiasIndex = index++; antialiasVal = mx_ptr[ANTIALIASING]; - /* glxAttrs[index] = None; */ (*env)->ReleasePrimitiveArrayCritical(env, attrList, mx_ptr, 0); + fbConfigList = find_DB_AA_S_FBConfigs(display, screen, glxAttrs, sVal, + dbVal, antialiasVal, index); - if(antialiasVal == REQUIRED || antialiasVal== PREFERRED) { - /* try GLX_ARB_multisample */ - glxExtensions = (const char *)glXGetClientString((Display*)display, GLX_EXTENSIONS); - + if(fbConfigList == NULL) { // Try with Pixmap, if Pbuffer fail. */ + + glxAttrs[drawableIndex] = (GLX_PIXMAP_BIT | GLX_WINDOW_BIT); + + fbConfigList = find_DB_AA_S_FBConfigs(display, screen, glxAttrs, sVal, + dbVal, antialiasVal, index); - if(isExtensionSupported(glxExtensions, "GLX_ARB_multisample")){ - /* path 1: */ - /* Query the visual with mulitsamples */ - - index = antialiasIndex; - glxAttrs[index++] = GLX_SAMPLE_BUFFERS_ARB; - glxAttrs[index++] = 1; - glxAttrs[index++] = GLX_SAMPLES_ARB; - glxAttrs[index++] = 1; - glxAttrs[index++] = None; - vis_info = findVisualInfoSwitchDoubleBufferAndStereo(display, screen, glxAttrs, sVal, sIndex, - dbVal, dbIndex); - - if(vis_info != NULL) { - vis_id = XVisualIDFromVisual(vis_info->visual); - visInfo[0] = (jlong)vis_info; - (*env)->ReleaseLongArrayElements(env, vInfArray, visInfo, 0); - return vis_id; - } - } } - - /* normal path */ - if ( antialiasVal == REQUIRED || antialiasVal == PREFERRED) { - /* step 1 : enable antialiasing */ - index = antialiasIndex; - glxAttrs[index++] = GLX_ACCUM_RED_SIZE; - glxAttrs[index++] = 8; - glxAttrs[index++] = GLX_ACCUM_GREEN_SIZE; - glxAttrs[index++] = 8; - glxAttrs[index++] = GLX_ACCUM_BLUE_SIZE; - glxAttrs[index++] = 8; - glxAttrs[index++] = None; - vis_info = findVisualInfoSwitchDoubleBufferAndStereo(display, screen, glxAttrs, sVal, sIndex, - dbVal, dbIndex); + + if(fbConfigList == NULL) { // Try with Window only, if Pixmap fail. + glxAttrs[drawableIndex] = GLX_WINDOW_BIT; + + fbConfigList = find_DB_AA_S_FBConfigs(display, screen, glxAttrs, sVal, + dbVal, antialiasVal, index); - if( vis_info == NULL) { - /* try disable antialiasing if it is PREFERRED */ - if(antialiasVal == PREFERRED) { - glxAttrs[antialiasIndex] = None; - vis_info = findVisualInfoSwitchDoubleBufferAndStereo(display, screen, glxAttrs, sVal, sIndex, - dbVal, dbIndex); - } - } - - visInfo[0] = (jlong)vis_info; - (*env)->ReleaseLongArrayElements(env, vInfArray, visInfo, 0); - - if( vis_info != NULL) { - vis_id = XVisualIDFromVisual(vis_info->visual); - return vis_id; - } else { - return 0; - } } + fbConfigListPtr[0] = (jlong)fbConfigList; + (*env)->ReleaseLongArrayElements(env, fbConfigArray, fbConfigListPtr, 0); + + /* For debug only. + if(fbConfigList != NULL) { + int val; + + glXGetFBConfigAttrib(dpy, fbConfigList[0], + GLX_FBCONFIG_ID, &val); + + fprintf(stderr, "display 0x%x, fbConfigList 0x%x, fbConfig 0x%x, fbConfigId %d\n", + (int) display, (int) fbConfigList, (int) fbConfigList[0], val); + + } + else { + fprintf(stderr, "display 0x%x, fbConfigList 0x%x\n", + (int) display, (int) fbConfigList); + } + */ - glxAttrs[antialiasIndex] = None; - vis_info = findVisualInfoSwitchDoubleBufferAndStereo(display, screen, glxAttrs, sVal, sIndex, - dbVal, dbIndex); - - visInfo[0] = (jlong)vis_info; - (*env)->ReleaseLongArrayElements(env, vInfArray, visInfo, 0); + if(fbConfigList != NULL) { + int vis_id; + + if(glXGetFBConfigAttrib(dpy, fbConfigList[0], GLX_VISUAL_ID, &vis_id) != Success) { + fprintf(stderr, "Java 3D ERROR: unable to get VisualID\n"); + return 0; + } - if( vis_info != NULL) { - vis_id = XVisualIDFromVisual(vis_info->visual); - return vis_id; + /* fprintf(stderr, "********* VisualID = %d\n", vis_id ); */ + + return (jint) vis_id; + } else { return 0; } -} +} JNIEXPORT -void JNICALL Java_javax_media_j3d_NativeConfigTemplate3D_freeVisual( +void JNICALL Java_javax_media_j3d_NativeConfigTemplate3D_freeFBConfig( JNIEnv *env, jclass class, /* this is a static native method */ - jlong visInfo) + jlong fbConfigListPtr) { - XFree((XVisualInfo *)visInfo); + GLXFBConfig *fbConfigList = (GLXFBConfig *) fbConfigListPtr; + XFree(fbConfigList); } diff --git a/src/native/ogl/NativeScreenInfo.c b/src/native/ogl/NativeScreenInfo.c index c92900c..23ad8b8 100644 --- a/src/native/ogl/NativeScreenInfo.c +++ b/src/native/ogl/NativeScreenInfo.c @@ -32,6 +32,10 @@ #endif #if defined(SOLARIS) || defined(__linux__) + +#pragma weak glXChooseFBConfig + + /* * Class: javax_media_j3d_NativeScreenInfo * Method: openDisplay @@ -40,14 +44,13 @@ JNIEXPORT jlong JNICALL Java_javax_media_j3d_NativeScreenInfo_openDisplay( JNIEnv *env, - jobject obj) + jclass cls) { Display* dpy; dpy = XOpenDisplay(NULL); return (jlong)dpy; } - /* * Class: javax_media_j3d_NativeScreenInfo * Method: getDefaultScreen @@ -56,10 +59,70 @@ Java_javax_media_j3d_NativeScreenInfo_openDisplay( JNIEXPORT jint JNICALL Java_javax_media_j3d_NativeScreenInfo_getDefaultScreen( JNIEnv *env, - jobject obj, + jclass cls, jlong display) { Display* dpy = (Display*)display; return (jint)DefaultScreen(dpy); } + +/* + * Class: javax_media_j3d_NativeScreenInfo + * Method: queryGLX13 + * Signature: (J)Z + */ +JNIEXPORT jboolean JNICALL +Java_javax_media_j3d_NativeScreenInfo_queryGLX13( + JNIEnv *env, + jclass cls, + jlong display) +{ + /* Fix for Issue 20 */ + void (*tmpfp)(); + int major, minor; + int errorBase, eventBase; + Display* dpy = (Display*)display; + // It should be cleaner to return both the major and minor to the caller. + + if (!glXQueryExtension(dpy, &errorBase, &eventBase)) { + fprintf(stderr, "Java 3D ERROR : GLX extension is not supported\n"); + fprintf(stderr, " GLX version 1.3 or higher is required\n"); + return JNI_FALSE; + } + +#if 0 /* Temporary disable this code segment because the ATI driver incorrectly + return 1.2 */ + + /* Check for glX 1.3 and higher */ + if (glXQueryVersion(dpy, &major, &minor)) { + /* fprintf(stderr, "Checking glX version : %d.%d\n",major, minor); */ + if (!(major == 1 && minor >= 3)) { + fprintf(stderr, "Java 3D ERROR : GLX version = %d.%d\n", major, minor); + fprintf(stderr, " GLX version 1.3 or higher is required\n"); + return JNI_FALSE; + } + } + else { + fprintf(stderr, "Java 3D ERROR : Unable to query GLX version\n"); + fprintf(stderr, " GLX version 1.3 or higher is required\n"); + return JNI_FALSE; + } + +#elseif + + tmpfp = (void (*)())glXChooseFBConfig; + + if (tmpfp == NULL) { + glXQueryVersion(dpy, &major, &minor); + fprintf(stderr, "Java 3D ERROR : glXChooseFBConfig not found\n"); + fprintf(stderr, " GLX version = %d.%d\n", major, minor); + fprintf(stderr, " GLX version 1.3 or higher is required\n"); + return JNI_FALSE; + } + +#endif + + return JNI_TRUE; +} + #endif |