| |
| /* Copyright (c) Mark J. Kilgard, 1997. */ |
| |
| /* This program is freely distributable without licensing fees |
| and is provided without guarantee or warrantee expressed or |
| implied. This program is -not- in the public domain. */ |
| |
| #include <assert.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include "glutint.h" |
| |
| /* glxcaps matches the criteria macros listed in glutint.h, but |
| only list the first set (those that correspond to GLX visual |
| attributes). */ |
| static int glxcap[NUM_GLXCAPS] = |
| { |
| GLX_RGBA, |
| GLX_BUFFER_SIZE, |
| GLX_DOUBLEBUFFER, |
| GLX_STEREO, |
| GLX_AUX_BUFFERS, |
| GLX_RED_SIZE, |
| GLX_GREEN_SIZE, |
| GLX_BLUE_SIZE, |
| GLX_ALPHA_SIZE, |
| GLX_DEPTH_SIZE, |
| GLX_STENCIL_SIZE, |
| GLX_ACCUM_RED_SIZE, |
| GLX_ACCUM_GREEN_SIZE, |
| GLX_ACCUM_BLUE_SIZE, |
| GLX_ACCUM_ALPHA_SIZE, |
| GLX_LEVEL, |
| }; |
| |
| #ifdef TEST |
| |
| #if !defined(_WIN32) |
| char *__glutProgramName = "dstr"; |
| Display *__glutDisplay; |
| int __glutScreen; |
| XVisualInfo *(*__glutDetermineVisualFromString) (char *string, Bool * treatAsSingle, |
| Criterion * requiredCriteria, int nRequired, int requiredMask, void **fbc) = NULL; |
| char *__glutDisplayString = NULL; |
| #endif |
| static int verbose = 0; |
| |
| static char *compstr[] = |
| { |
| "none", "=", "!=", "<=", ">=", ">", "<", "~" |
| }; |
| static char *capstr[] = |
| { |
| "rgba", "bufsize", "double", "stereo", "auxbufs", "red", "green", "blue", "alpha", |
| "depth", "stencil", "acred", "acgreen", "acblue", "acalpha", "level", "xvisual", |
| "transparent", "samples", "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor", |
| "xtruecolor", "xdirectcolor", "slow", "conformant", "num" |
| }; |
| |
| static void |
| printCriteria(Criterion * criteria, int ncriteria) |
| { |
| int i; |
| printf("Criteria: %d\n", ncriteria); |
| for (i = 0; i < ncriteria; i++) { |
| printf(" %s %s %d\n", |
| capstr[criteria[i].capability], |
| compstr[criteria[i].comparison], |
| criteria[i].value); |
| } |
| } |
| |
| #endif /* TEST */ |
| |
| static int isMesaGLX = -1; |
| |
| static int |
| determineMesaGLX(void) |
| { |
| #ifdef GLX_VERSION_1_1 |
| const char *vendor, *version, *ch; |
| |
| vendor = glXGetClientString(__glutDisplay, GLX_VENDOR); |
| if (!strcmp(vendor, "Brian Paul")) { |
| version = glXGetClientString(__glutDisplay, GLX_VERSION); |
| for (ch = version; *ch != ' ' && *ch != '\0'; ch++); |
| for (; *ch == ' ' && *ch != '\0'; ch++); |
| |
| #define MESA_NAME "Mesa " /* Trailing space is intentional. */ |
| |
| if (!strncmp(MESA_NAME, ch, sizeof(MESA_NAME) - 1)) { |
| return 1; |
| } |
| } |
| #else |
| /* Recent versions for Mesa should support GLX 1.1 and |
| therefore glXGetClientString. If we get into this case, |
| we would be compiling against a true OpenGL not supporting |
| GLX 1.1, and the resulting compiled library won't work well |
| with Mesa then. */ |
| #endif |
| return 0; |
| } |
| |
| static XVisualInfo ** |
| getMesaVisualList(int *n) |
| { |
| XVisualInfo **vlist, *vinfo; |
| int attribs[23]; |
| int i, x, cnt; |
| |
| vlist = (XVisualInfo **) malloc((32 + 16) * sizeof(XVisualInfo *)); |
| if (!vlist) |
| __glutFatalError("out of memory."); |
| |
| cnt = 0; |
| for (i = 0; i < 32; i++) { |
| x = 0; |
| attribs[x] = GLX_RGBA; |
| x++; |
| attribs[x] = GLX_RED_SIZE; |
| x++; |
| attribs[x] = 1; |
| x++; |
| attribs[x] = GLX_GREEN_SIZE; |
| x++; |
| attribs[x] = 1; |
| x++; |
| attribs[x] = GLX_BLUE_SIZE; |
| x++; |
| attribs[x] = 1; |
| x++; |
| if (i & 1) { |
| attribs[x] = GLX_DEPTH_SIZE; |
| x++; |
| attribs[x] = 1; |
| x++; |
| } |
| if (i & 2) { |
| attribs[x] = GLX_STENCIL_SIZE; |
| x++; |
| attribs[x] = 1; |
| x++; |
| } |
| if (i & 4) { |
| attribs[x] = GLX_ACCUM_RED_SIZE; |
| x++; |
| attribs[x] = 1; |
| x++; |
| attribs[x] = GLX_ACCUM_GREEN_SIZE; |
| x++; |
| attribs[x] = 1; |
| x++; |
| attribs[x] = GLX_ACCUM_BLUE_SIZE; |
| x++; |
| attribs[x] = 1; |
| x++; |
| } |
| if (i & 8) { |
| attribs[x] = GLX_ALPHA_SIZE; |
| x++; |
| attribs[x] = 1; |
| x++; |
| if (i & 4) { |
| attribs[x] = GLX_ACCUM_ALPHA_SIZE; |
| x++; |
| attribs[x] = 1; |
| x++; |
| } |
| } |
| if (i & 16) { |
| attribs[x] = GLX_DOUBLEBUFFER; |
| x++; |
| } |
| attribs[x] = None; |
| x++; |
| assert(x <= sizeof(attribs) / sizeof(attribs[0])); |
| vinfo = glXChooseVisual(__glutDisplay, __glutScreen, attribs); |
| if (vinfo) { |
| vlist[cnt] = vinfo; |
| cnt++; |
| } |
| } |
| for (i = 0; i < 16; i++) { |
| x = 0; |
| if (i & 1) { |
| attribs[x] = GLX_DEPTH_SIZE; |
| x++; |
| attribs[x] = 1; |
| x++; |
| } |
| if (i & 2) { |
| attribs[x] = GLX_STENCIL_SIZE; |
| x++; |
| attribs[x] = 1; |
| x++; |
| } |
| if (i & 4) { |
| attribs[x] = GLX_DOUBLEBUFFER; |
| x++; |
| } |
| if (i & 8) { |
| attribs[x] = GLX_LEVEL; |
| x++; |
| attribs[x] = 1; |
| x++; |
| #if defined(GLX_TRANSPARENT_TYPE_EXT) && defined(GLX_TRANSPARENT_INDEX_EXT) |
| attribs[x] = GLX_TRANSPARENT_TYPE_EXT; |
| x++; |
| attribs[x] = GLX_TRANSPARENT_INDEX_EXT; |
| x++; |
| #endif |
| } |
| attribs[x] = None; |
| x++; |
| assert(x <= sizeof(attribs) / sizeof(attribs[0])); |
| vinfo = glXChooseVisual(__glutDisplay, __glutScreen, attribs); |
| if (vinfo) { |
| vlist[cnt] = vinfo; |
| cnt++; |
| } |
| } |
| |
| *n = cnt; |
| return vlist; |
| } |
| |
| static FrameBufferMode * |
| loadVisuals(int *nitems_return) |
| { |
| XVisualInfo *vinfo, **vlist, template; |
| FrameBufferMode *fbmodes, *mode; |
| int n, i, j, rc, glcapable; |
| #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) |
| int multisample; |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info) |
| int visual_info; |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating) |
| int visual_rating; |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig) |
| int fbconfig; |
| #endif |
| |
| isMesaGLX = determineMesaGLX(); |
| if (isMesaGLX) { |
| vlist = getMesaVisualList(&n); |
| } else { |
| #if !defined(_WIN32) |
| template.screen = __glutScreen; |
| vinfo = XGetVisualInfo(__glutDisplay, VisualScreenMask, &template, &n); |
| #else |
| vinfo = XGetVisualInfo(__glutDisplay, 0, &template, &n); |
| #endif |
| if (vinfo == NULL) { |
| *nitems_return = 0; |
| return NULL; |
| } |
| assert(n > 0); |
| |
| /* Make an array of XVisualInfo* pointers to help the Mesa |
| case because each glXChooseVisual call returns a |
| distinct XVisualInfo*, not a handy array like |
| XGetVisualInfo. (Mesa expects us to return the _exact_ |
| pointer returned by glXChooseVisual so we could not just |
| copy the returned structure.) */ |
| vlist = (XVisualInfo **) malloc(n * sizeof(XVisualInfo *)); |
| if (!vlist) |
| __glutFatalError("out of memory."); |
| for (i = 0; i < n; i++) { |
| vlist[i] = &vinfo[i]; |
| } |
| } |
| |
| #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) |
| multisample = __glutIsSupportedByGLX("GLX_SGIS_multisample"); |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info) |
| visual_info = __glutIsSupportedByGLX("GLX_EXT_visual_info"); |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating) |
| visual_rating = __glutIsSupportedByGLX("GLX_EXT_visual_rating"); |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig) |
| fbconfig = __glutIsSupportedByGLX("GLX_SGIX_fbconfig"); |
| #endif |
| |
| fbmodes = (FrameBufferMode *) malloc(n * sizeof(FrameBufferMode)); |
| if (fbmodes == NULL) { |
| *nitems_return = -1; |
| free(vlist); |
| return NULL; |
| } |
| for (i = 0; i < n; i++) { |
| mode = &fbmodes[i]; |
| mode->vi = vlist[i]; |
| #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig) |
| mode->fbc = NULL; |
| #endif |
| rc = glXGetConfig(__glutDisplay, vlist[i], GLX_USE_GL, &glcapable); |
| if (rc == 0 && glcapable) { |
| mode->valid = 1; /* Assume the best until proven |
| otherwise. */ |
| for (j = 0; j < NUM_GLXCAPS; j++) { |
| rc = glXGetConfig(__glutDisplay, vlist[i], glxcap[j], &mode->cap[j]); |
| if (rc != 0) { |
| mode->valid = 0; |
| } |
| } |
| #if defined(_WIN32) |
| mode->cap[XVISUAL] = ChoosePixelFormat(XHDC, vlist[i]); |
| #else |
| mode->cap[XVISUAL] = (int) vlist[i]->visualid; |
| #endif |
| mode->cap[XSTATICGRAY] = 0; |
| mode->cap[XGRAYSCALE] = 0; |
| mode->cap[XSTATICCOLOR] = 0; |
| mode->cap[XPSEUDOCOLOR] = 0; |
| mode->cap[XTRUECOLOR] = 0; |
| mode->cap[XDIRECTCOLOR] = 0; |
| #if !defined(_WIN32) |
| #if defined(__cplusplus) || defined(c_plusplus) |
| switch (vlist[i]->c_class) { |
| #else |
| switch (vlist[i]->class) { |
| #endif |
| case StaticGray: |
| mode->cap[XSTATICGRAY] = 1; |
| break; |
| case GrayScale: |
| mode->cap[XGRAYSCALE] = 1; |
| break; |
| case StaticColor: |
| mode->cap[XSTATICCOLOR] = 1; |
| break; |
| case PseudoColor: |
| mode->cap[XPSEUDOCOLOR] = 1; |
| break; |
| case TrueColor: |
| mode->cap[XTRUECOLOR] = 1; |
| break; |
| case DirectColor: |
| mode->cap[XDIRECTCOLOR] = 1; |
| break; |
| } |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating) |
| if (visual_rating) { |
| int rating; |
| |
| /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0 |
| 564 for Alpha did not properly define GLX_VISUAL_CAVEAT_EXT |
| in <GL/glx.h> despite claiming to support |
| GLX_EXT_visual_rating. */ |
| #ifndef GLX_VISUAL_CAVEAT_EXT |
| #define GLX_VISUAL_CAVEAT_EXT 0x20 |
| #endif |
| |
| rc = glXGetConfig(__glutDisplay, |
| vlist[i], GLX_VISUAL_CAVEAT_EXT, &rating); |
| if (rc != 0) { |
| mode->cap[SLOW] = 0; |
| mode->cap[CONFORMANT] = 1; |
| } else { |
| switch (rating) { |
| case GLX_SLOW_VISUAL_EXT: |
| mode->cap[SLOW] = 1; |
| mode->cap[CONFORMANT] = 1; |
| break; |
| |
| /* IRIX 5.3 for the R10K Indigo2 may have shipped without this |
| properly defined in /usr/include/GL/glxtokens.h */ |
| #ifndef GLX_NON_CONFORMANT_VISUAL_EXT |
| #define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D |
| #endif |
| |
| case GLX_NON_CONFORMANT_VISUAL_EXT: |
| mode->cap[SLOW] = 0; |
| mode->cap[CONFORMANT] = 0; |
| break; |
| case GLX_NONE_EXT: |
| default: /* XXX Hopefully this is a good default |
| assumption. */ |
| mode->cap[SLOW] = 0; |
| mode->cap[CONFORMANT] = 1; |
| break; |
| } |
| } |
| } else { |
| mode->cap[TRANSPARENT] = 0; |
| } |
| #else |
| mode->cap[SLOW] = 0; |
| mode->cap[CONFORMANT] = 1; |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info) |
| if (visual_info) { |
| int transparent; |
| |
| /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0 |
| 564 for Alpha did not properly define |
| GLX_TRANSPARENT_TYPE_EXT in <GL/glx.h> despite claiming to |
| support GLX_EXT_visual_info. */ |
| #ifndef GLX_TRANSPARENT_TYPE_EXT |
| #define GLX_TRANSPARENT_TYPE_EXT 0x23 |
| #endif |
| |
| rc = glXGetConfig(__glutDisplay, |
| vlist[i], GLX_TRANSPARENT_TYPE_EXT, &transparent); |
| if (rc != 0) { |
| mode->cap[TRANSPARENT] = 0; |
| } else { |
| mode->cap[TRANSPARENT] = (transparent != GLX_NONE_EXT); |
| } |
| } else { |
| mode->cap[TRANSPARENT] = 0; |
| } |
| #else |
| mode->cap[TRANSPARENT] = 0; |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) |
| if (multisample) { |
| rc = glXGetConfig(__glutDisplay, |
| vlist[i], GLX_SAMPLES_SGIS, &mode->cap[SAMPLES]); |
| if (rc != 0) { |
| mode->cap[SAMPLES] = 0; |
| } |
| } else { |
| mode->cap[SAMPLES] = 0; |
| } |
| #else |
| mode->cap[SAMPLES] = 0; |
| #endif |
| } else { |
| #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig) |
| if (fbconfig) { |
| GLXFBConfigSGIX fbc; |
| int fbconfigID, drawType, renderType; |
| |
| fbc = __glut_glXGetFBConfigFromVisualSGIX(__glutDisplay, vlist[i]); |
| if (fbc) { |
| rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, fbc, |
| GLX_FBCONFIG_ID_SGIX, &fbconfigID); |
| if ((rc == 0) && (fbconfigID != None)) { |
| rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, fbc, |
| GLX_DRAWABLE_TYPE_SGIX, &drawType); |
| if ((rc == 0) && (drawType & GLX_WINDOW_BIT_SGIX)) { |
| rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, fbc, |
| GLX_RENDER_TYPE_SGIX, &renderType); |
| if ((rc == 0) && (renderType & GLX_RGBA_BIT_SGIX)) { |
| mode->fbc = fbc; |
| mode->valid = 1; /* Assume the best until |
| proven otherwise. */ |
| |
| assert(glxcap[0] == GLX_RGBA); |
| mode->cap[0] = 1; |
| |
| /* Start with "j = 1" to skip the GLX_RGBA attribute. */ |
| for (j = 1; j < NUM_GLXCAPS; j++) { |
| rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, |
| fbc, glxcap[j], &mode->cap[j]); |
| if (rc != 0) { |
| mode->valid = 0; |
| } |
| } |
| |
| mode->cap[XVISUAL] = (int) vlist[i]->visualid; |
| mode->cap[XSTATICGRAY] = 0; |
| mode->cap[XGRAYSCALE] = 0; |
| mode->cap[XSTATICCOLOR] = 0; |
| mode->cap[XPSEUDOCOLOR] = 0; |
| mode->cap[XTRUECOLOR] = 0; |
| mode->cap[XDIRECTCOLOR] = 0; |
| #if defined(__cplusplus) || defined(c_plusplus) |
| switch (vlist[i]->c_class) { |
| #else |
| switch (vlist[i]->class) { |
| #endif |
| case StaticGray: |
| mode->cap[XSTATICGRAY] = 1; |
| break; |
| case GrayScale: |
| mode->cap[XGRAYSCALE] = 1; |
| break; |
| case StaticColor: |
| mode->cap[XSTATICCOLOR] = 1; |
| break; |
| case PseudoColor: |
| mode->cap[XPSEUDOCOLOR] = 1; |
| break; |
| case TrueColor: |
| mode->cap[XTRUECOLOR] = 1; |
| break; |
| case DirectColor: |
| mode->cap[XDIRECTCOLOR] = 1; |
| break; |
| } |
| #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating) |
| if (visual_rating) { |
| int rating; |
| |
| /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0 |
| 564 for Alpha did not properly define GLX_VISUAL_CAVEAT_EXT |
| in <GL/glx.h> despite claiming to support |
| GLX_EXT_visual_rating. */ |
| #ifndef GLX_VISUAL_CAVEAT_EXT |
| #define GLX_VISUAL_CAVEAT_EXT 0x20 |
| #endif |
| |
| rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, |
| fbc, GLX_VISUAL_CAVEAT_EXT, &rating); |
| if (rc != 0) { |
| mode->cap[SLOW] = 0; |
| mode->cap[CONFORMANT] = 1; |
| } else { |
| switch (rating) { |
| case GLX_SLOW_VISUAL_EXT: |
| mode->cap[SLOW] = 1; |
| mode->cap[CONFORMANT] = 1; |
| break; |
| |
| /* IRIX 5.3 for the R10K Indigo2 may have shipped without this |
| properly defined in /usr/include/GL/glxtokens.h */ |
| #ifndef GLX_NON_CONFORMANT_VISUAL_EXT |
| #define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D |
| #endif |
| |
| case GLX_NON_CONFORMANT_VISUAL_EXT: |
| mode->cap[SLOW] = 0; |
| mode->cap[CONFORMANT] = 0; |
| break; |
| case GLX_NONE_EXT: |
| default: /* XXX Hopefully this is a good |
| default assumption. */ |
| mode->cap[SLOW] = 0; |
| mode->cap[CONFORMANT] = 1; |
| break; |
| } |
| } |
| } else { |
| mode->cap[TRANSPARENT] = 0; |
| } |
| #else |
| mode->cap[SLOW] = 0; |
| mode->cap[CONFORMANT] = 1; |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info) |
| if (visual_info) { |
| int transparent; |
| |
| /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0 |
| 564 for Alpha did not properly define |
| GLX_TRANSPARENT_TYPE_EXT in <GL/glx.h> despite claiming to |
| support GLX_EXT_visual_info. */ |
| #ifndef GLX_TRANSPARENT_TYPE_EXT |
| #define GLX_TRANSPARENT_TYPE_EXT 0x23 |
| #endif |
| |
| rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, |
| fbc, GLX_TRANSPARENT_TYPE_EXT, &transparent); |
| if (rc != 0) { |
| mode->cap[TRANSPARENT] = 0; |
| } else { |
| mode->cap[TRANSPARENT] = (transparent != GLX_NONE_EXT); |
| } |
| } else { |
| mode->cap[TRANSPARENT] = 0; |
| } |
| #else |
| mode->cap[TRANSPARENT] = 0; |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) |
| if (multisample) { |
| rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, |
| fbc, GLX_SAMPLES_SGIS, &mode->cap[SAMPLES]); |
| if (rc != 0) { |
| mode->cap[SAMPLES] = 0; |
| } |
| } else { |
| mode->cap[SAMPLES] = 0; |
| } |
| #else |
| mode->cap[SAMPLES] = 0; |
| #endif |
| |
| } else { |
| /* Fbconfig is not RGBA; GLUT only uses RGBA |
| FBconfigs. */ |
| /* XXX Code could be exteneded to handle color |
| index FBconfigs, but seems a color index |
| window-renderable FBconfig would also be |
| advertised as an X visual. */ |
| mode->valid = 0; |
| } |
| } else { |
| /* Fbconfig does not support window rendering; |
| not a valid FBconfig for GLUT windows. */ |
| mode->valid = 0; |
| } |
| } else { |
| /* FBconfig ID is None (zero); not a valid |
| FBconfig. */ |
| mode->valid = 0; |
| } |
| } else { |
| /* FBconfig ID is None (zero); not a valid FBconfig. */ |
| mode->valid = 0; |
| } |
| } else { |
| /* No SGIX_fbconfig GLX sever implementation support. */ |
| mode->valid = 0; |
| } |
| #else |
| /* No SGIX_fbconfig GLX extension API support. */ |
| mode->valid = 0; |
| #endif |
| } |
| } |
| |
| free(vlist); |
| *nitems_return = n; |
| return fbmodes; |
| } |
| |
| static XVisualInfo * |
| findMatch(FrameBufferMode * fbmodes, int nfbmodes, |
| Criterion * criteria, int ncriteria, void **fbc) |
| { |
| FrameBufferMode *found; |
| int *bestScore, *thisScore; |
| int i, j, numok, result = 0, worse, better; |
| |
| found = NULL; |
| numok = 1; /* "num" capability is indexed from 1, |
| not 0. */ |
| |
| /* XXX alloca canidate. */ |
| bestScore = (int *) malloc(ncriteria * sizeof(int)); |
| if (!bestScore) |
| __glutFatalError("out of memory."); |
| for (j = 0; j < ncriteria; j++) { |
| /* Very negative number. */ |
| bestScore[j] = -32768; |
| } |
| |
| /* XXX alloca canidate. */ |
| thisScore = (int *) malloc(ncriteria * sizeof(int)); |
| if (!thisScore) |
| __glutFatalError("out of memory."); |
| |
| for (i = 0; i < nfbmodes; i++) { |
| if (fbmodes[i].valid) { |
| #ifdef TEST |
| #if !defined(_WIN32) |
| if (verbose) |
| printf("Visual 0x%x\n", fbmodes[i].vi->visualid); |
| #endif |
| #endif |
| |
| worse = 0; |
| better = 0; |
| |
| for (j = 0; j < ncriteria; j++) { |
| int cap, cvalue, fbvalue; |
| |
| cap = criteria[j].capability; |
| cvalue = criteria[j].value; |
| if (cap == NUM) { |
| fbvalue = numok; |
| } else { |
| fbvalue = fbmodes[i].cap[cap]; |
| } |
| #ifdef TEST |
| if (verbose) |
| printf(" %s %s %d to %d\n", |
| capstr[cap], compstr[criteria[j].comparison], cvalue, fbvalue); |
| #endif |
| switch (criteria[j].comparison) { |
| case EQ: |
| result = cvalue == fbvalue; |
| thisScore[j] = 1; |
| break; |
| case NEQ: |
| result = cvalue != fbvalue; |
| thisScore[j] = 1; |
| break; |
| case LT: |
| result = fbvalue < cvalue; |
| thisScore[j] = fbvalue - cvalue; |
| break; |
| case GT: |
| result = fbvalue > cvalue; |
| thisScore[j] = fbvalue - cvalue; |
| break; |
| case LTE: |
| result = fbvalue <= cvalue; |
| thisScore[j] = fbvalue - cvalue; |
| break; |
| case GTE: |
| result = (fbvalue >= cvalue); |
| thisScore[j] = fbvalue - cvalue; |
| break; |
| case MIN: |
| result = fbvalue >= cvalue; |
| thisScore[j] = cvalue - fbvalue; |
| break; |
| } |
| |
| #ifdef TEST |
| if (verbose) |
| printf(" result=%d score=%d bestScore=%d\n", result, thisScore[j], bestScore[j]); |
| #endif |
| |
| if (result) { |
| if (better || thisScore[j] > bestScore[j]) { |
| better = 1; |
| } else if (thisScore[j] == bestScore[j]) { |
| /* Keep looking. */ |
| } else { |
| goto nextFBM; |
| } |
| } else { |
| if (cap == NUM) { |
| worse = 1; |
| } else { |
| goto nextFBM; |
| } |
| } |
| |
| } |
| |
| if (better && !worse) { |
| found = &fbmodes[i]; |
| for (j = 0; j < ncriteria; j++) { |
| bestScore[j] = thisScore[j]; |
| } |
| } |
| numok++; |
| |
| nextFBM:; |
| |
| } |
| } |
| free(bestScore); |
| free(thisScore); |
| if (found) { |
| #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig) |
| *fbc = found->fbc; |
| #endif |
| return found->vi; |
| } else { |
| return NULL; |
| } |
| } |
| |
| static int |
| parseCriteria(char *word, Criterion * criterion, int *mask, |
| Bool * allowDoubleAsSingle) |
| { |
| char *cstr, *vstr, *response; |
| int comparator, value = 0; |
| int rgb, rgba, acc, acca, count, i; |
| |
| cstr = strpbrk(word, "=><!~"); |
| if (cstr) { |
| switch (cstr[0]) { |
| case '=': |
| comparator = EQ; |
| vstr = &cstr[1]; |
| break; |
| case '~': |
| comparator = MIN; |
| vstr = &cstr[1]; |
| break; |
| case '>': |
| if (cstr[1] == '=') { |
| comparator = GTE; |
| vstr = &cstr[2]; |
| } else { |
| comparator = GT; |
| vstr = &cstr[1]; |
| } |
| break; |
| case '<': |
| if (cstr[1] == '=') { |
| comparator = LTE; |
| vstr = &cstr[2]; |
| } else { |
| comparator = LT; |
| vstr = &cstr[1]; |
| } |
| break; |
| case '!': |
| if (cstr[1] == '=') { |
| comparator = NEQ; |
| vstr = &cstr[2]; |
| } else { |
| return -1; |
| } |
| break; |
| default: |
| return -1; |
| } |
| value = (int) strtol(vstr, &response, 0); |
| if (response == vstr) { |
| /* Not a valid number. */ |
| return -1; |
| } |
| *cstr = '\0'; |
| } else { |
| comparator = NONE; |
| } |
| switch (word[0]) { |
| case 'a': |
| if (!strcmp(word, "alpha")) { |
| criterion[0].capability = ALPHA_SIZE; |
| if (comparator == NONE) { |
| criterion[0].comparison = GTE; |
| criterion[0].value = 1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| *mask |= (1 << RGBA); |
| *mask |= (1 << ALPHA_SIZE); |
| *mask |= (1 << RGBA_MODE); |
| return 1; |
| } |
| acca = !strcmp(word, "acca"); |
| acc = !strcmp(word, "acc"); |
| if (acc || acca) { |
| criterion[0].capability = ACCUM_RED_SIZE; |
| criterion[1].capability = ACCUM_GREEN_SIZE; |
| criterion[2].capability = ACCUM_BLUE_SIZE; |
| criterion[3].capability = ACCUM_ALPHA_SIZE; |
| if (acca) { |
| count = 4; |
| } else { |
| count = 3; |
| criterion[3].comparison = MIN; |
| criterion[3].value = 0; |
| } |
| if (comparator == NONE) { |
| comparator = GTE; |
| value = 8; |
| } |
| for (i = 0; i < count; i++) { |
| criterion[i].comparison = comparator; |
| criterion[i].value = value; |
| } |
| *mask |= (1 << ACCUM_RED_SIZE); |
| return 4; |
| } |
| if (!strcmp(word, "auxbufs")) { |
| criterion[0].capability = AUX_BUFFERS; |
| if (comparator == NONE) { |
| criterion[0].comparison = MIN; |
| criterion[0].value = 1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| *mask |= (1 << AUX_BUFFERS); |
| return 1; |
| } |
| return -1; |
| case 'b': |
| if (!strcmp(word, "blue")) { |
| criterion[0].capability = BLUE_SIZE; |
| if (comparator == NONE) { |
| criterion[0].comparison = GTE; |
| criterion[0].value = 1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| *mask |= (1 << RGBA); |
| *mask |= (1 << RGBA_MODE); |
| return 1; |
| } |
| if (!strcmp(word, "buffer")) { |
| criterion[0].capability = BUFFER_SIZE; |
| if (comparator == NONE) { |
| criterion[0].comparison = GTE; |
| criterion[0].value = 1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| return 1; |
| } |
| return -1; |
| case 'c': |
| if (!strcmp(word, "conformant")) { |
| criterion[0].capability = CONFORMANT; |
| if (comparator == NONE) { |
| criterion[0].comparison = EQ; |
| criterion[0].value = 1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| *mask |= (1 << CONFORMANT); |
| return 1; |
| } |
| return -1; |
| case 'd': |
| if (!strcmp(word, "depth")) { |
| criterion[0].capability = DEPTH_SIZE; |
| if (comparator == NONE) { |
| criterion[0].comparison = GTE; |
| criterion[0].value = 12; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| *mask |= (1 << DEPTH_SIZE); |
| return 1; |
| } |
| if (!strcmp(word, "double")) { |
| criterion[0].capability = DOUBLEBUFFER; |
| if (comparator == NONE) { |
| criterion[0].comparison = EQ; |
| criterion[0].value = 1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| *mask |= (1 << DOUBLEBUFFER); |
| return 1; |
| } |
| return -1; |
| case 'g': |
| if (!strcmp(word, "green")) { |
| criterion[0].capability = GREEN_SIZE; |
| if (comparator == NONE) { |
| criterion[0].comparison = GTE; |
| criterion[0].value = 1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| *mask |= (1 << RGBA); |
| *mask |= (1 << RGBA_MODE); |
| return 1; |
| } |
| return -1; |
| case 'i': |
| if (!strcmp(word, "index")) { |
| criterion[0].capability = RGBA; |
| criterion[0].comparison = EQ; |
| criterion[0].value = 0; |
| *mask |= (1 << RGBA); |
| *mask |= (1 << CI_MODE); |
| criterion[1].capability = BUFFER_SIZE; |
| if (comparator == NONE) { |
| criterion[1].comparison = GTE; |
| criterion[1].value = 1; |
| } else { |
| criterion[1].comparison = comparator; |
| criterion[1].value = value; |
| } |
| return 2; |
| } |
| return -1; |
| case 'l': |
| if (!strcmp(word, "luminance")) { |
| criterion[0].capability = RGBA; |
| criterion[0].comparison = EQ; |
| criterion[0].value = 1; |
| |
| criterion[1].capability = RED_SIZE; |
| if (comparator == NONE) { |
| criterion[1].comparison = GTE; |
| criterion[1].value = 1; |
| } else { |
| criterion[1].comparison = comparator; |
| criterion[1].value = value; |
| } |
| |
| criterion[2].capability = GREEN_SIZE; |
| criterion[2].comparison = EQ; |
| criterion[2].value = 0; |
| |
| criterion[3].capability = BLUE_SIZE; |
| criterion[3].comparison = EQ; |
| criterion[3].value = 0; |
| |
| *mask |= (1 << RGBA); |
| *mask |= (1 << RGBA_MODE); |
| *mask |= (1 << LUMINANCE_MODE); |
| return 4; |
| } |
| return -1; |
| case 'n': |
| if (!strcmp(word, "num")) { |
| criterion[0].capability = NUM; |
| if (comparator == NONE) { |
| return -1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| return 1; |
| } |
| } |
| return -1; |
| case 'r': |
| if (!strcmp(word, "red")) { |
| criterion[0].capability = RED_SIZE; |
| if (comparator == NONE) { |
| criterion[0].comparison = GTE; |
| criterion[0].value = 1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| *mask |= (1 << RGBA); |
| *mask |= (1 << RGBA_MODE); |
| return 1; |
| } |
| rgba = !strcmp(word, "rgba"); |
| rgb = !strcmp(word, "rgb"); |
| if (rgb || rgba) { |
| criterion[0].capability = RGBA; |
| criterion[0].comparison = EQ; |
| criterion[0].value = 1; |
| |
| criterion[1].capability = RED_SIZE; |
| criterion[2].capability = GREEN_SIZE; |
| criterion[3].capability = BLUE_SIZE; |
| criterion[4].capability = ALPHA_SIZE; |
| if (rgba) { |
| count = 5; |
| } else { |
| count = 4; |
| criterion[4].comparison = MIN; |
| criterion[4].value = 0; |
| } |
| if (comparator == NONE) { |
| comparator = GTE; |
| value = 1; |
| } |
| for (i = 1; i < count; i++) { |
| criterion[i].comparison = comparator; |
| criterion[i].value = value; |
| } |
| *mask |= (1 << RGBA); |
| *mask |= (1 << RGBA_MODE); |
| return 5; |
| } |
| return -1; |
| case 's': |
| if (!strcmp(word, "stencil")) { |
| criterion[0].capability = STENCIL_SIZE; |
| if (comparator == NONE) { |
| criterion[0].comparison = MIN; |
| criterion[0].value = 1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| *mask |= (1 << STENCIL_SIZE); |
| return 1; |
| } |
| if (!strcmp(word, "single")) { |
| criterion[0].capability = DOUBLEBUFFER; |
| if (comparator == NONE) { |
| criterion[0].comparison = EQ; |
| criterion[0].value = 0; |
| *allowDoubleAsSingle = True; |
| *mask |= (1 << DOUBLEBUFFER); |
| return 1; |
| } else { |
| return -1; |
| } |
| } |
| if (!strcmp(word, "stereo")) { |
| criterion[0].capability = STEREO; |
| if (comparator == NONE) { |
| criterion[0].comparison = EQ; |
| criterion[0].value = 1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| *mask |= (1 << STEREO); |
| return 1; |
| } |
| if (!strcmp(word, "samples")) { |
| criterion[0].capability = SAMPLES; |
| if (comparator == NONE) { |
| criterion[0].comparison = LTE; |
| criterion[0].value = 4; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| *mask |= (1 << SAMPLES); |
| return 1; |
| } |
| if (!strcmp(word, "slow")) { |
| criterion[0].capability = SLOW; |
| if (comparator == NONE) { |
| /* Just "slow" means permit fast visuals, but accept |
| slow ones in preference. Presumably the slow ones |
| must be higher quality or something else desirable. */ |
| criterion[0].comparison = GTE; |
| criterion[0].value = 0; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| *mask |= (1 << SLOW); |
| return 1; |
| } |
| return -1; |
| #if defined(_WIN32) |
| case 'w': |
| if (!strcmp(word, "win32pfd")) { |
| criterion[0].capability = XVISUAL; |
| if (comparator == NONE) { |
| return -1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| return 1; |
| } |
| } |
| return -1; |
| #endif |
| #if !defined(_WIN32) |
| case 'x': |
| if (!strcmp(word, "xvisual")) { |
| if (comparator == NONE) { |
| return -1; |
| } else { |
| criterion[0].capability = XVISUAL; |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| /* Set everything in "mask" so that no default criteria |
| get used. Assume the program really wants the |
| xvisual specified. */ |
| *mask |= ~0; |
| return 1; |
| } |
| } |
| /* Be a little over-eager to fill in the comparison and |
| value so we won't have to replicate the code after each |
| string match. */ |
| if (comparator == NONE) { |
| criterion[0].comparison = EQ; |
| criterion[0].value = 1; |
| } else { |
| criterion[0].comparison = comparator; |
| criterion[0].value = value; |
| } |
| |
| if (!strcmp(word, "xstaticgray")) { |
| criterion[0].capability = XSTATICGRAY; |
| *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual |
| class selected. */ |
| return 1; |
| } |
| if (!strcmp(word, "xgrayscale")) { |
| criterion[0].capability = XGRAYSCALE; |
| *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual |
| class selected. */ |
| return 1; |
| } |
| if (!strcmp(word, "xstaticcolor")) { |
| criterion[0].capability = XSTATICCOLOR; |
| *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual |
| class selected. */ |
| return 1; |
| } |
| if (!strcmp(word, "xpseudocolor")) { |
| criterion[0].capability = XPSEUDOCOLOR; |
| *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual |
| class selected. */ |
| return 1; |
| } |
| if (!strcmp(word, "xtruecolor")) { |
| criterion[0].capability = XTRUECOLOR; |
| *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual |
| class selected. */ |
| return 1; |
| } |
| if (!strcmp(word, "xdirectcolor")) { |
| criterion[0].capability = XDIRECTCOLOR; |
| *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual |
| class selected. */ |
| return 1; |
| } |
| return -1; |
| #endif |
| default: |
| return -1; |
| } |
| } |
| |
| static Criterion * |
| parseModeString(char *mode, int *ncriteria, Bool * allowDoubleAsSingle, |
| Criterion * requiredCriteria, int nRequired, int requiredMask) |
| { |
| Criterion *criteria = NULL; |
| int n, mask, parsed, i; |
| char *copy, *word; |
| |
| *allowDoubleAsSingle = False; |
| copy = __glutStrdup(mode); |
| /* Attempt to estimate how many criteria entries should be |
| needed. */ |
| n = 0; |
| word = strtok(copy, " \t"); |
| while (word) { |
| n++; |
| word = strtok(NULL, " \t"); |
| } |
| /* Overestimate by 4 times ("rgba" might add four criteria |
| entries) plus add in possible defaults plus space for |
| required criteria. */ |
| criteria = (Criterion *) malloc((4 * n + 30 + nRequired) * sizeof(Criterion)); |
| if (!criteria) { |
| __glutFatalError("out of memory."); |
| } |
| |
| /* Re-copy the copy of the mode string. */ |
| strcpy(copy, mode); |
| |
| /* First add the required criteria (these match at the |
| highest priority). Typically these will be used to force a |
| specific level (layer), transparency, and/or visual type. */ |
| mask = requiredMask; |
| for (i = 0; i < nRequired; i++) { |
| criteria[i] = requiredCriteria[i]; |
| } |
| n = nRequired; |
| |
| word = strtok(copy, " \t"); |
| while (word) { |
| parsed = parseCriteria(word, &criteria[n], &mask, allowDoubleAsSingle); |
| if (parsed >= 0) { |
| n += parsed; |
| } else { |
| __glutWarning("Unrecognized display string word: %s (ignoring)\n", word); |
| } |
| word = strtok(NULL, " \t"); |
| } |
| |
| #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) |
| if (__glutIsSupportedByGLX("GLX_SGIS_multisample")) { |
| if (!(mask & (1 << SAMPLES))) { |
| criteria[n].capability = SAMPLES; |
| criteria[n].comparison = EQ; |
| criteria[n].value = 0; |
| n++; |
| } else { |
| /* Multisample visuals are marked nonconformant. If |
| multisampling was requeste and no conformant |
| preference was set, assume that we will settle for a |
| non-conformant visual to get multisampling. */ |
| if (!(mask & (1 << CONFORMANT))) { |
| criteria[n].capability = CONFORMANT; |
| criteria[n].comparison = MIN; |
| criteria[n].value = 0; |
| n++; |
| mask |= (1 << CONFORMANT); |
| } |
| } |
| } |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info) |
| if (__glutIsSupportedByGLX("GLX_EXT_visual_info")) { |
| if (!(mask & (1 << TRANSPARENT))) { |
| criteria[n].capability = TRANSPARENT; |
| criteria[n].comparison = EQ; |
| criteria[n].value = 0; |
| n++; |
| } |
| } |
| #endif |
| #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating) |
| if (__glutIsSupportedByGLX("GLX_EXT_visual_rating")) { |
| if (!(mask & (1 << SLOW))) { |
| criteria[n].capability = SLOW; |
| criteria[n].comparison = EQ; |
| criteria[n].value = 0; |
| n++; |
| } |
| if (!(mask & (1 << CONFORMANT))) { |
| criteria[n].capability = CONFORMANT; |
| criteria[n].comparison = EQ; |
| criteria[n].value = 1; |
| n++; |
| } |
| } |
| #endif |
| if (!(mask & (1 << ACCUM_RED_SIZE))) { |
| criteria[n].capability = ACCUM_RED_SIZE; |
| criteria[n].comparison = MIN; |
| criteria[n].value = 0; |
| criteria[n + 1].capability = ACCUM_GREEN_SIZE; |
| criteria[n + 1].comparison = MIN; |
| criteria[n + 1].value = 0; |
| criteria[n + 2].capability = ACCUM_BLUE_SIZE; |
| criteria[n + 2].comparison = MIN; |
| criteria[n + 2].value = 0; |
| criteria[n + 3].capability = ACCUM_ALPHA_SIZE; |
| criteria[n + 3].comparison = MIN; |
| criteria[n + 3].value = 0; |
| n += 4; |
| } |
| if (!(mask & (1 << AUX_BUFFERS))) { |
| criteria[n].capability = AUX_BUFFERS; |
| criteria[n].comparison = MIN; |
| criteria[n].value = 0; |
| n++; |
| } |
| if (!(mask & (1 << RGBA))) { |
| criteria[n].capability = RGBA; |
| criteria[n].comparison = EQ; |
| criteria[n].value = 1; |
| criteria[n + 1].capability = RED_SIZE; |
| criteria[n + 1].comparison = GTE; |
| criteria[n + 1].value = 1; |
| criteria[n + 2].capability = GREEN_SIZE; |
| criteria[n + 2].comparison = GTE; |
| criteria[n + 2].value = 1; |
| criteria[n + 3].capability = BLUE_SIZE; |
| criteria[n + 3].comparison = GTE; |
| criteria[n + 3].value = 1; |
| criteria[n + 4].capability = ALPHA_SIZE; |
| criteria[n + 4].comparison = MIN; |
| criteria[n + 4].value = 0; |
| n += 5; |
| mask |= (1 << RGBA_MODE); |
| } |
| #if !defined(_WIN32) |
| if (!(mask & (1 << XSTATICGRAY))) { |
| assert(isMesaGLX != -1); |
| if ((mask & (1 << RGBA_MODE)) && !isMesaGLX) { |
| /* Normally, request an RGBA mode visual be TrueColor, |
| except in the case of Mesa where we trust Mesa (and |
| other code in GLUT) to handle any type of RGBA visual |
| reasonably. */ |
| if (mask & (1 << LUMINANCE_MODE)) { |
| /* If RGBA luminance was requested, actually go for |
| a StaticGray visual. */ |
| criteria[n].capability = XSTATICGRAY; |
| } else { |
| criteria[n].capability = XTRUECOLOR; |
| } |
| criteria[n].value = 1; |
| criteria[n].comparison = EQ; |
| |
| n++; |
| } |
| if (mask & (1 << CI_MODE)) { |
| criteria[n].capability = XPSEUDOCOLOR; |
| criteria[n].value = 1; |
| criteria[n].comparison = EQ; |
| n++; |
| } |
| } |
| #endif |
| if (!(mask & (1 << STEREO))) { |
| criteria[n].capability = STEREO; |
| criteria[n].comparison = EQ; |
| criteria[n].value = 0; |
| n++; |
| } |
| if (!(mask & (1 << DOUBLEBUFFER))) { |
| criteria[n].capability = DOUBLEBUFFER; |
| criteria[n].comparison = EQ; |
| criteria[n].value = 0; |
| *allowDoubleAsSingle = True; |
| n++; |
| } |
| if (!(mask & (1 << DEPTH_SIZE))) { |
| criteria[n].capability = DEPTH_SIZE; |
| criteria[n].comparison = MIN; |
| criteria[n].value = 0; |
| n++; |
| } |
| if (!(mask & (1 << STENCIL_SIZE))) { |
| criteria[n].capability = STENCIL_SIZE; |
| criteria[n].comparison = MIN; |
| criteria[n].value = 0; |
| n++; |
| } |
| if (!(mask & (1 << LEVEL))) { |
| criteria[n].capability = LEVEL; |
| criteria[n].comparison = EQ; |
| criteria[n].value = 0; |
| n++; |
| } |
| if (n) { |
| /* Since over-estimated the size needed; squeeze it down to |
| reality. */ |
| criteria = (Criterion *) realloc(criteria, n * sizeof(Criterion)); |
| if (!criteria) { |
| /* Should never happen since should be shrinking down! */ |
| __glutFatalError("out of memory."); |
| } |
| } else { |
| /* For portability, avoid "realloc(ptr,0)" call. */ |
| free(criteria); |
| criteria = NULL; |
| } |
| |
| free(copy); |
| *ncriteria = n; |
| return criteria; |
| } |
| |
| static FrameBufferMode *fbmodes = NULL; |
| static int nfbmodes = 0; |
| |
| static XVisualInfo * |
| getVisualInfoFromString(char *string, Bool * treatAsSingle, |
| Criterion * requiredCriteria, int nRequired, int requiredMask, void **fbc) |
| { |
| Criterion *criteria; |
| XVisualInfo *visinfo; |
| Bool allowDoubleAsSingle; |
| int ncriteria, i; |
| |
| if (!fbmodes) { |
| fbmodes = loadVisuals(&nfbmodes); |
| } |
| criteria = parseModeString(string, &ncriteria, |
| &allowDoubleAsSingle, requiredCriteria, nRequired, requiredMask); |
| if (criteria == NULL) { |
| __glutWarning("failed to parse mode string"); |
| return NULL; |
| } |
| #ifdef TEST |
| printCriteria(criteria, ncriteria); |
| #endif |
| visinfo = findMatch(fbmodes, nfbmodes, criteria, ncriteria, fbc); |
| if (visinfo) { |
| *treatAsSingle = 0; |
| } else { |
| if (allowDoubleAsSingle) { |
| /* Rewrite criteria so that we now look for a double |
| buffered visual which will then get treated as a |
| single buffered visual. */ |
| for (i = 0; i < ncriteria; i++) { |
| if (criteria[i].capability == DOUBLEBUFFER |
| && criteria[i].comparison == EQ |
| && criteria[i].value == 0) { |
| criteria[i].value = 1; |
| } |
| } |
| visinfo = findMatch(fbmodes, nfbmodes, criteria, ncriteria, fbc); |
| if (visinfo) { |
| *treatAsSingle = 1; |
| } |
| } |
| } |
| free(criteria); |
| |
| if (visinfo) { |
| #if defined(_WIN32) |
| /* We could have a valid pixel format for drawing to a |
| bitmap. However, we don't want to draw into a bitmap, we |
| need one that can be used with a window, so make sure |
| that this is true. */ |
| if (!(visinfo->dwFlags & PFD_DRAW_TO_WINDOW)) |
| return NULL; |
| #endif |
| return visinfo; |
| } else { |
| return NULL; |
| } |
| } |
| |
| /* CENTRY */ |
| void GLUTAPIENTRY |
| glutInitDisplayString(const char *string) |
| { |
| #ifdef _WIN32 |
| XHDC = GetDC(GetDesktopWindow()); |
| #endif |
| |
| __glutDetermineVisualFromString = getVisualInfoFromString; |
| if (__glutDisplayString) { |
| free(__glutDisplayString); |
| } |
| if (string) { |
| __glutDisplayString = __glutStrdup(string); |
| if (!__glutDisplayString) |
| __glutFatalError("out of memory."); |
| } else { |
| __glutDisplayString = NULL; |
| } |
| } |
| /* ENDCENTRY */ |
| |
| #ifdef TEST |
| |
| Criterion requiredWindowCriteria[] = |
| { |
| {LEVEL, EQ, 0}, |
| {TRANSPARENT, EQ, 0} |
| }; |
| int numRequiredWindowCriteria = sizeof(requiredWindowCriteria) / sizeof(Criterion); |
| int requiredWindowCriteriaMask = (1 << LEVEL) | (1 << TRANSPARENT); |
| |
| Criterion requiredOverlayCriteria[] = |
| { |
| {LEVEL, EQ, 1}, |
| {TRANSPARENT, EQ, 1}, |
| {XPSEUDOCOLOR, EQ, 1}, |
| {RGBA, EQ, 0}, |
| {BUFFER_SIZE, GTE, 1} |
| }; |
| int numRequiredOverlayCriteria = sizeof(requiredOverlayCriteria) / sizeof(Criterion); |
| int requiredOverlayCriteriaMask = |
| (1 << LEVEL) | (1 << TRANSPARENT) | (1 << XSTATICGRAY) | (1 << RGBA) | (1 << CI_MODE); |
| |
| int |
| main(int argc, char **argv) |
| { |
| Display *dpy; |
| XVisualInfo *vinfo; |
| Bool treatAsSingle; |
| char *str, buffer[1024]; |
| int tty = isatty(fileno(stdin)); |
| int overlay = 0, showconfig = 0; |
| void *fbc; |
| |
| #if !defined(_WIN32) |
| dpy = XOpenDisplay(NULL); |
| if (dpy == NULL) { |
| printf("Could not connect to X server\n"); |
| exit(1); |
| } |
| __glutDisplay = dpy; |
| __glutScreen = DefaultScreen(__glutDisplay); |
| #endif |
| while (!feof(stdin)) { |
| if (tty) |
| printf("dstr> "); |
| str = fgets(buffer, 1023, stdin); |
| if (str) { |
| printf("\n"); |
| if (!strcmp("v", str)) { |
| verbose = 1 - verbose; |
| printf("verbose = %d\n\n", verbose); |
| } else if (!strcmp("s", str)) { |
| showconfig = 1 - showconfig; |
| printf("showconfig = %d\n\n", showconfig); |
| } else if (!strcmp("o", str)) { |
| overlay = 1 - overlay; |
| printf("overlay = %d\n\n", overlay); |
| } else { |
| if (overlay) { |
| vinfo = getVisualInfoFromString(str, &treatAsSingle, |
| requiredOverlayCriteria, numRequiredOverlayCriteria, requiredOverlayCriteriaMask, &fbc); |
| } else { |
| vinfo = getVisualInfoFromString(str, &treatAsSingle, |
| requiredWindowCriteria, numRequiredWindowCriteria, requiredWindowCriteriaMask, &fbc); |
| } |
| if (vinfo) { |
| printf("\n"); |
| if (!tty) |
| printf("Display string: %s", str); |
| #ifdef _WIN32 |
| printf("Visual = 0x%x\n", 0); |
| #else |
| printf("Visual = 0x%x%s\n", vinfo->visualid, fbc ? " (needs FBC)" : ""); |
| #endif |
| if (treatAsSingle) { |
| printf("Treat as SINGLE.\n"); |
| } |
| if (showconfig) { |
| int glxCapable, bufferSize, level, renderType, doubleBuffer, |
| stereo, auxBuffers, redSize, greenSize, blueSize, |
| alphaSize, depthSize, stencilSize, acRedSize, acGreenSize, |
| acBlueSize, acAlphaSize; |
| |
| glXGetConfig(dpy, vinfo, GLX_BUFFER_SIZE, &bufferSize); |
| glXGetConfig(dpy, vinfo, GLX_LEVEL, &level); |
| glXGetConfig(dpy, vinfo, GLX_RGBA, &renderType); |
| glXGetConfig(dpy, vinfo, GLX_DOUBLEBUFFER, &doubleBuffer); |
| glXGetConfig(dpy, vinfo, GLX_STEREO, &stereo); |
| glXGetConfig(dpy, vinfo, GLX_AUX_BUFFERS, &auxBuffers); |
| glXGetConfig(dpy, vinfo, GLX_RED_SIZE, &redSize); |
| glXGetConfig(dpy, vinfo, GLX_GREEN_SIZE, &greenSize); |
| glXGetConfig(dpy, vinfo, GLX_BLUE_SIZE, &blueSize); |
| glXGetConfig(dpy, vinfo, GLX_ALPHA_SIZE, &alphaSize); |
| glXGetConfig(dpy, vinfo, GLX_DEPTH_SIZE, &depthSize); |
| glXGetConfig(dpy, vinfo, GLX_STENCIL_SIZE, &stencilSize); |
| glXGetConfig(dpy, vinfo, GLX_ACCUM_RED_SIZE, &acRedSize); |
| glXGetConfig(dpy, vinfo, GLX_ACCUM_GREEN_SIZE, &acGreenSize); |
| glXGetConfig(dpy, vinfo, GLX_ACCUM_BLUE_SIZE, &acBlueSize); |
| glXGetConfig(dpy, vinfo, GLX_ACCUM_ALPHA_SIZE, &acAlphaSize); |
| printf("RGBA = (%d, %d, %d, %d)\n", redSize, greenSize, blueSize, alphaSize); |
| printf("acc = (%d, %d, %d, %d)\n", acRedSize, acGreenSize, acBlueSize, acAlphaSize); |
| printf("db = %d\n", doubleBuffer); |
| printf("str = %d\n", stereo); |
| printf("aux = %d\n", auxBuffers); |
| printf("lvl = %d\n", level); |
| printf("buf = %d\n", bufferSize); |
| printf("rgba = %d\n", renderType); |
| printf("z = %d\n", depthSize); |
| printf("s = %d\n", stencilSize); |
| } |
| } else { |
| printf("\n"); |
| printf("No match.\n"); |
| } |
| printf("\n"); |
| } |
| } |
| } |
| printf("\n"); |
| return 0; |
| } |
| #endif |