glsl: Fix scoping bug in if statements.
[mesa.git] / src / glut / glx / glut_dstr.c
1
2 /* Copyright (c) Mark J. Kilgard, 1997. */
3
4 /* This program is freely distributable without licensing fees
5 and is provided without guarantee or warrantee expressed or
6 implied. This program is -not- in the public domain. */
7
8 #include <assert.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include "glutint.h"
13
14 /* glxcaps matches the criteria macros listed in glutint.h, but
15 only list the first set (those that correspond to GLX visual
16 attributes). */
17 static int glxcap[NUM_GLXCAPS] =
18 {
19 GLX_RGBA,
20 GLX_BUFFER_SIZE,
21 GLX_DOUBLEBUFFER,
22 GLX_STEREO,
23 GLX_AUX_BUFFERS,
24 GLX_RED_SIZE,
25 GLX_GREEN_SIZE,
26 GLX_BLUE_SIZE,
27 GLX_ALPHA_SIZE,
28 GLX_DEPTH_SIZE,
29 GLX_STENCIL_SIZE,
30 GLX_ACCUM_RED_SIZE,
31 GLX_ACCUM_GREEN_SIZE,
32 GLX_ACCUM_BLUE_SIZE,
33 GLX_ACCUM_ALPHA_SIZE,
34 GLX_LEVEL,
35 };
36
37 #ifdef TEST
38
39 #if !defined(_WIN32)
40 char *__glutProgramName = "dstr";
41 Display *__glutDisplay;
42 int __glutScreen;
43 XVisualInfo *(*__glutDetermineVisualFromString) (char *string, Bool * treatAsSingle,
44 Criterion * requiredCriteria, int nRequired, int requiredMask, void **fbc) = NULL;
45 char *__glutDisplayString = NULL;
46 #endif
47 static int verbose = 0;
48
49 static char *compstr[] =
50 {
51 "none", "=", "!=", "<=", ">=", ">", "<", "~"
52 };
53 static char *capstr[] =
54 {
55 "rgba", "bufsize", "double", "stereo", "auxbufs", "red", "green", "blue", "alpha",
56 "depth", "stencil", "acred", "acgreen", "acblue", "acalpha", "level", "xvisual",
57 "transparent", "samples", "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
58 "xtruecolor", "xdirectcolor", "slow", "conformant", "num"
59 };
60
61 static void
62 printCriteria(Criterion * criteria, int ncriteria)
63 {
64 int i;
65 printf("Criteria: %d\n", ncriteria);
66 for (i = 0; i < ncriteria; i++) {
67 printf(" %s %s %d\n",
68 capstr[criteria[i].capability],
69 compstr[criteria[i].comparison],
70 criteria[i].value);
71 }
72 }
73
74 #endif /* TEST */
75
76 static int isMesaGLX = -1;
77
78 static int
79 determineMesaGLX(void)
80 {
81 #ifdef GLX_VERSION_1_1
82 const char *vendor, *version, *ch;
83
84 vendor = glXGetClientString(__glutDisplay, GLX_VENDOR);
85 if (!strcmp(vendor, "Brian Paul")) {
86 version = glXGetClientString(__glutDisplay, GLX_VERSION);
87 for (ch = version; *ch != ' ' && *ch != '\0'; ch++);
88 for (; *ch == ' ' && *ch != '\0'; ch++);
89
90 #define MESA_NAME "Mesa " /* Trailing space is intentional. */
91
92 if (!strncmp(MESA_NAME, ch, sizeof(MESA_NAME) - 1)) {
93 return 1;
94 }
95 }
96 #else
97 /* Recent versions for Mesa should support GLX 1.1 and
98 therefore glXGetClientString. If we get into this case,
99 we would be compiling against a true OpenGL not supporting
100 GLX 1.1, and the resulting compiled library won't work well
101 with Mesa then. */
102 #endif
103 return 0;
104 }
105
106 static XVisualInfo **
107 getMesaVisualList(int *n)
108 {
109 XVisualInfo **vlist, *vinfo;
110 int attribs[23];
111 int i, x, cnt;
112
113 vlist = (XVisualInfo **) malloc((32 + 16) * sizeof(XVisualInfo *));
114 if (!vlist)
115 __glutFatalError("out of memory.");
116
117 cnt = 0;
118 for (i = 0; i < 32; i++) {
119 x = 0;
120 attribs[x] = GLX_RGBA;
121 x++;
122 attribs[x] = GLX_RED_SIZE;
123 x++;
124 attribs[x] = 1;
125 x++;
126 attribs[x] = GLX_GREEN_SIZE;
127 x++;
128 attribs[x] = 1;
129 x++;
130 attribs[x] = GLX_BLUE_SIZE;
131 x++;
132 attribs[x] = 1;
133 x++;
134 if (i & 1) {
135 attribs[x] = GLX_DEPTH_SIZE;
136 x++;
137 attribs[x] = 1;
138 x++;
139 }
140 if (i & 2) {
141 attribs[x] = GLX_STENCIL_SIZE;
142 x++;
143 attribs[x] = 1;
144 x++;
145 }
146 if (i & 4) {
147 attribs[x] = GLX_ACCUM_RED_SIZE;
148 x++;
149 attribs[x] = 1;
150 x++;
151 attribs[x] = GLX_ACCUM_GREEN_SIZE;
152 x++;
153 attribs[x] = 1;
154 x++;
155 attribs[x] = GLX_ACCUM_BLUE_SIZE;
156 x++;
157 attribs[x] = 1;
158 x++;
159 }
160 if (i & 8) {
161 attribs[x] = GLX_ALPHA_SIZE;
162 x++;
163 attribs[x] = 1;
164 x++;
165 if (i & 4) {
166 attribs[x] = GLX_ACCUM_ALPHA_SIZE;
167 x++;
168 attribs[x] = 1;
169 x++;
170 }
171 }
172 if (i & 16) {
173 attribs[x] = GLX_DOUBLEBUFFER;
174 x++;
175 }
176 attribs[x] = None;
177 x++;
178 assert(x <= sizeof(attribs) / sizeof(attribs[0]));
179 vinfo = glXChooseVisual(__glutDisplay, __glutScreen, attribs);
180 if (vinfo) {
181 vlist[cnt] = vinfo;
182 cnt++;
183 }
184 }
185 for (i = 0; i < 16; i++) {
186 x = 0;
187 if (i & 1) {
188 attribs[x] = GLX_DEPTH_SIZE;
189 x++;
190 attribs[x] = 1;
191 x++;
192 }
193 if (i & 2) {
194 attribs[x] = GLX_STENCIL_SIZE;
195 x++;
196 attribs[x] = 1;
197 x++;
198 }
199 if (i & 4) {
200 attribs[x] = GLX_DOUBLEBUFFER;
201 x++;
202 }
203 if (i & 8) {
204 attribs[x] = GLX_LEVEL;
205 x++;
206 attribs[x] = 1;
207 x++;
208 #if defined(GLX_TRANSPARENT_TYPE_EXT) && defined(GLX_TRANSPARENT_INDEX_EXT)
209 attribs[x] = GLX_TRANSPARENT_TYPE_EXT;
210 x++;
211 attribs[x] = GLX_TRANSPARENT_INDEX_EXT;
212 x++;
213 #endif
214 }
215 attribs[x] = None;
216 x++;
217 assert(x <= sizeof(attribs) / sizeof(attribs[0]));
218 vinfo = glXChooseVisual(__glutDisplay, __glutScreen, attribs);
219 if (vinfo) {
220 vlist[cnt] = vinfo;
221 cnt++;
222 }
223 }
224
225 *n = cnt;
226 return vlist;
227 }
228
229 static FrameBufferMode *
230 loadVisuals(int *nitems_return)
231 {
232 XVisualInfo *vinfo, **vlist, template;
233 FrameBufferMode *fbmodes, *mode;
234 int n, i, j, rc, glcapable;
235 #if defined(GLX_VERSION_1_1) && (defined(GLX_SGIS_multisample) || defined(GLX_ARB_multisample))
236 int multisample;
237 #endif
238 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
239 int visual_info;
240 #endif
241 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
242 int visual_rating;
243 #endif
244 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
245 int fbconfig;
246 #endif
247
248 isMesaGLX = determineMesaGLX();
249 if (isMesaGLX) {
250 vlist = getMesaVisualList(&n);
251 } else {
252 #if !defined(_WIN32)
253 template.screen = __glutScreen;
254 vinfo = XGetVisualInfo(__glutDisplay, VisualScreenMask, &template, &n);
255 #else
256 vinfo = XGetVisualInfo(__glutDisplay, 0, &template, &n);
257 #endif
258 if (vinfo == NULL) {
259 *nitems_return = 0;
260 return NULL;
261 }
262 assert(n > 0);
263
264 /* Make an array of XVisualInfo* pointers to help the Mesa
265 case because each glXChooseVisual call returns a
266 distinct XVisualInfo*, not a handy array like
267 XGetVisualInfo. (Mesa expects us to return the _exact_
268 pointer returned by glXChooseVisual so we could not just
269 copy the returned structure.) */
270 vlist = (XVisualInfo **) malloc(n * sizeof(XVisualInfo *));
271 if (!vlist)
272 __glutFatalError("out of memory.");
273 for (i = 0; i < n; i++) {
274 vlist[i] = &vinfo[i];
275 }
276 }
277
278 #if defined(GLX_VERSION_1_1) && (defined(GLX_SGIS_multisample) || defined(GLX_ARB_multisample))
279 multisample = __glutIsSupportedByGLX("GLX_SGIS_multisample") ||
280 __glutIsSupportedByGLX("GLX_ARB_multisample");
281 #endif
282 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
283 visual_info = __glutIsSupportedByGLX("GLX_EXT_visual_info");
284 #endif
285 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
286 visual_rating = __glutIsSupportedByGLX("GLX_EXT_visual_rating");
287 #endif
288 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
289 fbconfig = __glutIsSupportedByGLX("GLX_SGIX_fbconfig");
290 #endif
291
292 fbmodes = (FrameBufferMode *) malloc(n * sizeof(FrameBufferMode));
293 if (fbmodes == NULL) {
294 *nitems_return = -1;
295 free(vlist);
296 return NULL;
297 }
298 for (i = 0; i < n; i++) {
299 mode = &fbmodes[i];
300 mode->vi = vlist[i];
301 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
302 mode->fbc = NULL;
303 #endif
304 rc = glXGetConfig(__glutDisplay, vlist[i], GLX_USE_GL, &glcapable);
305 if (rc == 0 && glcapable) {
306 mode->valid = 1; /* Assume the best until proven
307 otherwise. */
308 for (j = 0; j < NUM_GLXCAPS; j++) {
309 rc = glXGetConfig(__glutDisplay, vlist[i], glxcap[j], &mode->cap[j]);
310 if (rc != 0) {
311 mode->valid = 0;
312 }
313 }
314 #if defined(_WIN32)
315 mode->cap[XVISUAL] = ChoosePixelFormat(XHDC, vlist[i]);
316 #else
317 mode->cap[XVISUAL] = (int) vlist[i]->visualid;
318 #endif
319 mode->cap[XSTATICGRAY] = 0;
320 mode->cap[XGRAYSCALE] = 0;
321 mode->cap[XSTATICCOLOR] = 0;
322 mode->cap[XPSEUDOCOLOR] = 0;
323 mode->cap[XTRUECOLOR] = 0;
324 mode->cap[XDIRECTCOLOR] = 0;
325 #if !defined(_WIN32)
326 #if defined(__cplusplus) || defined(c_plusplus)
327 switch (vlist[i]->c_class) {
328 #else
329 switch (vlist[i]->class) {
330 #endif
331 case StaticGray:
332 mode->cap[XSTATICGRAY] = 1;
333 break;
334 case GrayScale:
335 mode->cap[XGRAYSCALE] = 1;
336 break;
337 case StaticColor:
338 mode->cap[XSTATICCOLOR] = 1;
339 break;
340 case PseudoColor:
341 mode->cap[XPSEUDOCOLOR] = 1;
342 break;
343 case TrueColor:
344 mode->cap[XTRUECOLOR] = 1;
345 break;
346 case DirectColor:
347 mode->cap[XDIRECTCOLOR] = 1;
348 break;
349 }
350 #endif
351 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
352 if (visual_rating) {
353 int rating;
354
355 /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0
356 564 for Alpha did not properly define GLX_VISUAL_CAVEAT_EXT
357 in <GL/glx.h> despite claiming to support
358 GLX_EXT_visual_rating. */
359 #ifndef GLX_VISUAL_CAVEAT_EXT
360 #define GLX_VISUAL_CAVEAT_EXT 0x20
361 #endif
362
363 rc = glXGetConfig(__glutDisplay,
364 vlist[i], GLX_VISUAL_CAVEAT_EXT, &rating);
365 if (rc != 0) {
366 mode->cap[SLOW] = 0;
367 mode->cap[CONFORMANT] = 1;
368 } else {
369 switch (rating) {
370 case GLX_SLOW_VISUAL_EXT:
371 mode->cap[SLOW] = 1;
372 mode->cap[CONFORMANT] = 1;
373 break;
374
375 /* IRIX 5.3 for the R10K Indigo2 may have shipped without this
376 properly defined in /usr/include/GL/glxtokens.h */
377 #ifndef GLX_NON_CONFORMANT_VISUAL_EXT
378 #define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D
379 #endif
380
381 case GLX_NON_CONFORMANT_VISUAL_EXT:
382 mode->cap[SLOW] = 0;
383 mode->cap[CONFORMANT] = 0;
384 break;
385 case GLX_NONE_EXT:
386 default: /* XXX Hopefully this is a good default
387 assumption. */
388 mode->cap[SLOW] = 0;
389 mode->cap[CONFORMANT] = 1;
390 break;
391 }
392 }
393 } else {
394 mode->cap[TRANSPARENT] = 0;
395 }
396 #else
397 mode->cap[SLOW] = 0;
398 mode->cap[CONFORMANT] = 1;
399 #endif
400 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
401 if (visual_info) {
402 int transparent;
403
404 /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0
405 564 for Alpha did not properly define
406 GLX_TRANSPARENT_TYPE_EXT in <GL/glx.h> despite claiming to
407 support GLX_EXT_visual_info. */
408 #ifndef GLX_TRANSPARENT_TYPE_EXT
409 #define GLX_TRANSPARENT_TYPE_EXT 0x23
410 #endif
411
412 rc = glXGetConfig(__glutDisplay,
413 vlist[i], GLX_TRANSPARENT_TYPE_EXT, &transparent);
414 if (rc != 0) {
415 mode->cap[TRANSPARENT] = 0;
416 } else {
417 mode->cap[TRANSPARENT] = (transparent != GLX_NONE_EXT);
418 }
419 } else {
420 mode->cap[TRANSPARENT] = 0;
421 }
422 #else
423 mode->cap[TRANSPARENT] = 0;
424 #endif
425 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
426 if (multisample) {
427 rc = glXGetConfig(__glutDisplay,
428 vlist[i], GLX_SAMPLES_SGIS, &mode->cap[SAMPLES]);
429 if (rc != 0) {
430 mode->cap[SAMPLES] = 0;
431 }
432 } else {
433 mode->cap[SAMPLES] = 0;
434 }
435 #else
436 mode->cap[SAMPLES] = 0;
437 #endif
438 } else {
439 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
440 if (fbconfig) {
441 GLXFBConfigSGIX fbc;
442 int fbconfigID, drawType, renderType;
443
444 fbc = __glut_glXGetFBConfigFromVisualSGIX(__glutDisplay, vlist[i]);
445 if (fbc) {
446 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, fbc,
447 GLX_FBCONFIG_ID_SGIX, &fbconfigID);
448 if ((rc == 0) && (fbconfigID != None)) {
449 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, fbc,
450 GLX_DRAWABLE_TYPE_SGIX, &drawType);
451 if ((rc == 0) && (drawType & GLX_WINDOW_BIT_SGIX)) {
452 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay, fbc,
453 GLX_RENDER_TYPE_SGIX, &renderType);
454 if ((rc == 0) && (renderType & GLX_RGBA_BIT_SGIX)) {
455 mode->fbc = fbc;
456 mode->valid = 1; /* Assume the best until
457 proven otherwise. */
458
459 assert(glxcap[0] == GLX_RGBA);
460 mode->cap[0] = 1;
461
462 /* Start with "j = 1" to skip the GLX_RGBA attribute. */
463 for (j = 1; j < NUM_GLXCAPS; j++) {
464 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay,
465 fbc, glxcap[j], &mode->cap[j]);
466 if (rc != 0) {
467 mode->valid = 0;
468 }
469 }
470
471 mode->cap[XVISUAL] = (int) vlist[i]->visualid;
472 mode->cap[XSTATICGRAY] = 0;
473 mode->cap[XGRAYSCALE] = 0;
474 mode->cap[XSTATICCOLOR] = 0;
475 mode->cap[XPSEUDOCOLOR] = 0;
476 mode->cap[XTRUECOLOR] = 0;
477 mode->cap[XDIRECTCOLOR] = 0;
478 #if defined(__cplusplus) || defined(c_plusplus)
479 switch (vlist[i]->c_class) {
480 #else
481 switch (vlist[i]->class) {
482 #endif
483 case StaticGray:
484 mode->cap[XSTATICGRAY] = 1;
485 break;
486 case GrayScale:
487 mode->cap[XGRAYSCALE] = 1;
488 break;
489 case StaticColor:
490 mode->cap[XSTATICCOLOR] = 1;
491 break;
492 case PseudoColor:
493 mode->cap[XPSEUDOCOLOR] = 1;
494 break;
495 case TrueColor:
496 mode->cap[XTRUECOLOR] = 1;
497 break;
498 case DirectColor:
499 mode->cap[XDIRECTCOLOR] = 1;
500 break;
501 }
502 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
503 if (visual_rating) {
504 int rating;
505
506 /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0
507 564 for Alpha did not properly define GLX_VISUAL_CAVEAT_EXT
508 in <GL/glx.h> despite claiming to support
509 GLX_EXT_visual_rating. */
510 #ifndef GLX_VISUAL_CAVEAT_EXT
511 #define GLX_VISUAL_CAVEAT_EXT 0x20
512 #endif
513
514 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay,
515 fbc, GLX_VISUAL_CAVEAT_EXT, &rating);
516 if (rc != 0) {
517 mode->cap[SLOW] = 0;
518 mode->cap[CONFORMANT] = 1;
519 } else {
520 switch (rating) {
521 case GLX_SLOW_VISUAL_EXT:
522 mode->cap[SLOW] = 1;
523 mode->cap[CONFORMANT] = 1;
524 break;
525
526 /* IRIX 5.3 for the R10K Indigo2 may have shipped without this
527 properly defined in /usr/include/GL/glxtokens.h */
528 #ifndef GLX_NON_CONFORMANT_VISUAL_EXT
529 #define GLX_NON_CONFORMANT_VISUAL_EXT 0x800D
530 #endif
531
532 case GLX_NON_CONFORMANT_VISUAL_EXT:
533 mode->cap[SLOW] = 0;
534 mode->cap[CONFORMANT] = 0;
535 break;
536 case GLX_NONE_EXT:
537 default: /* XXX Hopefully this is a good
538 default assumption. */
539 mode->cap[SLOW] = 0;
540 mode->cap[CONFORMANT] = 1;
541 break;
542 }
543 }
544 } else {
545 mode->cap[TRANSPARENT] = 0;
546 }
547 #else
548 mode->cap[SLOW] = 0;
549 mode->cap[CONFORMANT] = 1;
550 #endif
551 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
552 if (visual_info) {
553 int transparent;
554
555 /* babcock@cs.montana.edu reported that DEC UNIX (OSF1) V4.0
556 564 for Alpha did not properly define
557 GLX_TRANSPARENT_TYPE_EXT in <GL/glx.h> despite claiming to
558 support GLX_EXT_visual_info. */
559 #ifndef GLX_TRANSPARENT_TYPE_EXT
560 #define GLX_TRANSPARENT_TYPE_EXT 0x23
561 #endif
562
563 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay,
564 fbc, GLX_TRANSPARENT_TYPE_EXT, &transparent);
565 if (rc != 0) {
566 mode->cap[TRANSPARENT] = 0;
567 } else {
568 mode->cap[TRANSPARENT] = (transparent != GLX_NONE_EXT);
569 }
570 } else {
571 mode->cap[TRANSPARENT] = 0;
572 }
573 #else
574 mode->cap[TRANSPARENT] = 0;
575 #endif
576 #if defined(GLX_VERSION_1_1) && (defined(GLX_SGIS_multisample) || defined(GLX_ARB_multisample))
577 if (multisample) {
578 rc = __glut_glXGetFBConfigAttribSGIX(__glutDisplay,
579 fbc, GLX_SAMPLES_SGIS, &mode->cap[SAMPLES]);
580 if (rc != 0) {
581 mode->cap[SAMPLES] = 0;
582 }
583 } else {
584 mode->cap[SAMPLES] = 0;
585 }
586 #else
587 mode->cap[SAMPLES] = 0;
588 #endif
589
590 } else {
591 /* Fbconfig is not RGBA; GLUT only uses RGBA
592 FBconfigs. */
593 /* XXX Code could be exteneded to handle color
594 index FBconfigs, but seems a color index
595 window-renderable FBconfig would also be
596 advertised as an X visual. */
597 mode->valid = 0;
598 }
599 } else {
600 /* Fbconfig does not support window rendering;
601 not a valid FBconfig for GLUT windows. */
602 mode->valid = 0;
603 }
604 } else {
605 /* FBconfig ID is None (zero); not a valid
606 FBconfig. */
607 mode->valid = 0;
608 }
609 } else {
610 /* FBconfig ID is None (zero); not a valid FBconfig. */
611 mode->valid = 0;
612 }
613 } else {
614 /* No SGIX_fbconfig GLX sever implementation support. */
615 mode->valid = 0;
616 }
617 #else
618 /* No SGIX_fbconfig GLX extension API support. */
619 mode->valid = 0;
620 #endif
621 }
622 }
623
624 free(vlist);
625 *nitems_return = n;
626 return fbmodes;
627 }
628
629 static XVisualInfo *
630 findMatch(FrameBufferMode * fbmodes, int nfbmodes,
631 Criterion * criteria, int ncriteria, void **fbc)
632 {
633 FrameBufferMode *found;
634 int *bestScore, *thisScore;
635 int i, j, numok, result = 0, worse, better;
636
637 found = NULL;
638 numok = 1; /* "num" capability is indexed from 1,
639 not 0. */
640
641 /* XXX alloca canidate. */
642 bestScore = (int *) malloc(ncriteria * sizeof(int));
643 if (!bestScore)
644 __glutFatalError("out of memory.");
645 for (j = 0; j < ncriteria; j++) {
646 /* Very negative number. */
647 bestScore[j] = -32768;
648 }
649
650 /* XXX alloca canidate. */
651 thisScore = (int *) malloc(ncriteria * sizeof(int));
652 if (!thisScore)
653 __glutFatalError("out of memory.");
654
655 for (i = 0; i < nfbmodes; i++) {
656 if (fbmodes[i].valid) {
657 #ifdef TEST
658 #if !defined(_WIN32)
659 if (verbose)
660 printf("Visual 0x%x\n", fbmodes[i].vi->visualid);
661 #endif
662 #endif
663
664 worse = 0;
665 better = 0;
666
667 for (j = 0; j < ncriteria; j++) {
668 int cap, cvalue, fbvalue;
669
670 cap = criteria[j].capability;
671 cvalue = criteria[j].value;
672 if (cap == NUM) {
673 fbvalue = numok;
674 } else {
675 fbvalue = fbmodes[i].cap[cap];
676 }
677 #ifdef TEST
678 if (verbose)
679 printf(" %s %s %d to %d\n",
680 capstr[cap], compstr[criteria[j].comparison], cvalue, fbvalue);
681 #endif
682 switch (criteria[j].comparison) {
683 case EQ:
684 result = cvalue == fbvalue;
685 thisScore[j] = 1;
686 break;
687 case NEQ:
688 result = cvalue != fbvalue;
689 thisScore[j] = 1;
690 break;
691 case LT:
692 result = fbvalue < cvalue;
693 thisScore[j] = fbvalue - cvalue;
694 break;
695 case GT:
696 result = fbvalue > cvalue;
697 thisScore[j] = fbvalue - cvalue;
698 break;
699 case LTE:
700 result = fbvalue <= cvalue;
701 thisScore[j] = fbvalue - cvalue;
702 break;
703 case GTE:
704 result = (fbvalue >= cvalue);
705 thisScore[j] = fbvalue - cvalue;
706 break;
707 case MIN:
708 result = fbvalue >= cvalue;
709 thisScore[j] = cvalue - fbvalue;
710 break;
711 }
712
713 #ifdef TEST
714 if (verbose)
715 printf(" result=%d score=%d bestScore=%d\n", result, thisScore[j], bestScore[j]);
716 #endif
717
718 if (result) {
719 if (better || thisScore[j] > bestScore[j]) {
720 better = 1;
721 } else if (thisScore[j] == bestScore[j]) {
722 /* Keep looking. */
723 } else {
724 goto nextFBM;
725 }
726 } else {
727 if (cap == NUM) {
728 worse = 1;
729 } else {
730 goto nextFBM;
731 }
732 }
733
734 }
735
736 if (better && !worse) {
737 found = &fbmodes[i];
738 for (j = 0; j < ncriteria; j++) {
739 bestScore[j] = thisScore[j];
740 }
741 }
742 numok++;
743
744 nextFBM:;
745
746 }
747 }
748 free(bestScore);
749 free(thisScore);
750 if (found) {
751 #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
752 *fbc = found->fbc;
753 #endif
754 return found->vi;
755 } else {
756 return NULL;
757 }
758 }
759
760 static int
761 parseCriteria(char *word, Criterion * criterion, int *mask,
762 Bool * allowDoubleAsSingle)
763 {
764 char *cstr, *vstr, *response;
765 int comparator, value = 0;
766 int rgb, rgba, acc, acca, count, i;
767
768 cstr = strpbrk(word, "=><!~");
769 if (cstr) {
770 switch (cstr[0]) {
771 case '=':
772 comparator = EQ;
773 vstr = &cstr[1];
774 break;
775 case '~':
776 comparator = MIN;
777 vstr = &cstr[1];
778 break;
779 case '>':
780 if (cstr[1] == '=') {
781 comparator = GTE;
782 vstr = &cstr[2];
783 } else {
784 comparator = GT;
785 vstr = &cstr[1];
786 }
787 break;
788 case '<':
789 if (cstr[1] == '=') {
790 comparator = LTE;
791 vstr = &cstr[2];
792 } else {
793 comparator = LT;
794 vstr = &cstr[1];
795 }
796 break;
797 case '!':
798 if (cstr[1] == '=') {
799 comparator = NEQ;
800 vstr = &cstr[2];
801 } else {
802 return -1;
803 }
804 break;
805 default:
806 return -1;
807 }
808 value = (int) strtol(vstr, &response, 0);
809 if (response == vstr) {
810 /* Not a valid number. */
811 return -1;
812 }
813 *cstr = '\0';
814 } else {
815 comparator = NONE;
816 }
817 switch (word[0]) {
818 case 'a':
819 if (!strcmp(word, "alpha")) {
820 criterion[0].capability = ALPHA_SIZE;
821 if (comparator == NONE) {
822 criterion[0].comparison = GTE;
823 criterion[0].value = 1;
824 } else {
825 criterion[0].comparison = comparator;
826 criterion[0].value = value;
827 }
828 *mask |= (1 << RGBA);
829 *mask |= (1 << ALPHA_SIZE);
830 *mask |= (1 << RGBA_MODE);
831 return 1;
832 }
833 acca = !strcmp(word, "acca");
834 acc = !strcmp(word, "acc");
835 if (acc || acca) {
836 criterion[0].capability = ACCUM_RED_SIZE;
837 criterion[1].capability = ACCUM_GREEN_SIZE;
838 criterion[2].capability = ACCUM_BLUE_SIZE;
839 criterion[3].capability = ACCUM_ALPHA_SIZE;
840 if (acca) {
841 count = 4;
842 } else {
843 count = 3;
844 criterion[3].comparison = MIN;
845 criterion[3].value = 0;
846 }
847 if (comparator == NONE) {
848 comparator = GTE;
849 value = 8;
850 }
851 for (i = 0; i < count; i++) {
852 criterion[i].comparison = comparator;
853 criterion[i].value = value;
854 }
855 *mask |= (1 << ACCUM_RED_SIZE);
856 return 4;
857 }
858 if (!strcmp(word, "auxbufs")) {
859 criterion[0].capability = AUX_BUFFERS;
860 if (comparator == NONE) {
861 criterion[0].comparison = MIN;
862 criterion[0].value = 1;
863 } else {
864 criterion[0].comparison = comparator;
865 criterion[0].value = value;
866 }
867 *mask |= (1 << AUX_BUFFERS);
868 return 1;
869 }
870 return -1;
871 case 'b':
872 if (!strcmp(word, "blue")) {
873 criterion[0].capability = BLUE_SIZE;
874 if (comparator == NONE) {
875 criterion[0].comparison = GTE;
876 criterion[0].value = 1;
877 } else {
878 criterion[0].comparison = comparator;
879 criterion[0].value = value;
880 }
881 *mask |= (1 << RGBA);
882 *mask |= (1 << RGBA_MODE);
883 return 1;
884 }
885 if (!strcmp(word, "buffer")) {
886 criterion[0].capability = BUFFER_SIZE;
887 if (comparator == NONE) {
888 criterion[0].comparison = GTE;
889 criterion[0].value = 1;
890 } else {
891 criterion[0].comparison = comparator;
892 criterion[0].value = value;
893 }
894 return 1;
895 }
896 return -1;
897 case 'c':
898 if (!strcmp(word, "conformant")) {
899 criterion[0].capability = CONFORMANT;
900 if (comparator == NONE) {
901 criterion[0].comparison = EQ;
902 criterion[0].value = 1;
903 } else {
904 criterion[0].comparison = comparator;
905 criterion[0].value = value;
906 }
907 *mask |= (1 << CONFORMANT);
908 return 1;
909 }
910 return -1;
911 case 'd':
912 if (!strcmp(word, "depth")) {
913 criterion[0].capability = DEPTH_SIZE;
914 if (comparator == NONE) {
915 criterion[0].comparison = GTE;
916 criterion[0].value = 12;
917 } else {
918 criterion[0].comparison = comparator;
919 criterion[0].value = value;
920 }
921 *mask |= (1 << DEPTH_SIZE);
922 return 1;
923 }
924 if (!strcmp(word, "double")) {
925 criterion[0].capability = DOUBLEBUFFER;
926 if (comparator == NONE) {
927 criterion[0].comparison = EQ;
928 criterion[0].value = 1;
929 } else {
930 criterion[0].comparison = comparator;
931 criterion[0].value = value;
932 }
933 *mask |= (1 << DOUBLEBUFFER);
934 return 1;
935 }
936 return -1;
937 case 'g':
938 if (!strcmp(word, "green")) {
939 criterion[0].capability = GREEN_SIZE;
940 if (comparator == NONE) {
941 criterion[0].comparison = GTE;
942 criterion[0].value = 1;
943 } else {
944 criterion[0].comparison = comparator;
945 criterion[0].value = value;
946 }
947 *mask |= (1 << RGBA);
948 *mask |= (1 << RGBA_MODE);
949 return 1;
950 }
951 return -1;
952 case 'i':
953 if (!strcmp(word, "index")) {
954 criterion[0].capability = RGBA;
955 criterion[0].comparison = EQ;
956 criterion[0].value = 0;
957 *mask |= (1 << RGBA);
958 *mask |= (1 << CI_MODE);
959 criterion[1].capability = BUFFER_SIZE;
960 if (comparator == NONE) {
961 criterion[1].comparison = GTE;
962 criterion[1].value = 1;
963 } else {
964 criterion[1].comparison = comparator;
965 criterion[1].value = value;
966 }
967 return 2;
968 }
969 return -1;
970 case 'l':
971 if (!strcmp(word, "luminance")) {
972 criterion[0].capability = RGBA;
973 criterion[0].comparison = EQ;
974 criterion[0].value = 1;
975
976 criterion[1].capability = RED_SIZE;
977 if (comparator == NONE) {
978 criterion[1].comparison = GTE;
979 criterion[1].value = 1;
980 } else {
981 criterion[1].comparison = comparator;
982 criterion[1].value = value;
983 }
984
985 criterion[2].capability = GREEN_SIZE;
986 criterion[2].comparison = EQ;
987 criterion[2].value = 0;
988
989 criterion[3].capability = BLUE_SIZE;
990 criterion[3].comparison = EQ;
991 criterion[3].value = 0;
992
993 *mask |= (1 << RGBA);
994 *mask |= (1 << RGBA_MODE);
995 *mask |= (1 << LUMINANCE_MODE);
996 return 4;
997 }
998 return -1;
999 case 'n':
1000 if (!strcmp(word, "num")) {
1001 criterion[0].capability = NUM;
1002 if (comparator == NONE) {
1003 return -1;
1004 } else {
1005 criterion[0].comparison = comparator;
1006 criterion[0].value = value;
1007 return 1;
1008 }
1009 }
1010 return -1;
1011 case 'r':
1012 if (!strcmp(word, "red")) {
1013 criterion[0].capability = RED_SIZE;
1014 if (comparator == NONE) {
1015 criterion[0].comparison = GTE;
1016 criterion[0].value = 1;
1017 } else {
1018 criterion[0].comparison = comparator;
1019 criterion[0].value = value;
1020 }
1021 *mask |= (1 << RGBA);
1022 *mask |= (1 << RGBA_MODE);
1023 return 1;
1024 }
1025 rgba = !strcmp(word, "rgba");
1026 rgb = !strcmp(word, "rgb");
1027 if (rgb || rgba) {
1028 criterion[0].capability = RGBA;
1029 criterion[0].comparison = EQ;
1030 criterion[0].value = 1;
1031
1032 criterion[1].capability = RED_SIZE;
1033 criterion[2].capability = GREEN_SIZE;
1034 criterion[3].capability = BLUE_SIZE;
1035 criterion[4].capability = ALPHA_SIZE;
1036 if (rgba) {
1037 count = 5;
1038 } else {
1039 count = 4;
1040 criterion[4].comparison = MIN;
1041 criterion[4].value = 0;
1042 }
1043 if (comparator == NONE) {
1044 comparator = GTE;
1045 value = 1;
1046 }
1047 for (i = 1; i < count; i++) {
1048 criterion[i].comparison = comparator;
1049 criterion[i].value = value;
1050 }
1051 *mask |= (1 << RGBA);
1052 *mask |= (1 << RGBA_MODE);
1053 return 5;
1054 }
1055 return -1;
1056 case 's':
1057 if (!strcmp(word, "stencil")) {
1058 criterion[0].capability = STENCIL_SIZE;
1059 if (comparator == NONE) {
1060 criterion[0].comparison = MIN;
1061 criterion[0].value = 1;
1062 } else {
1063 criterion[0].comparison = comparator;
1064 criterion[0].value = value;
1065 }
1066 *mask |= (1 << STENCIL_SIZE);
1067 return 1;
1068 }
1069 if (!strcmp(word, "single")) {
1070 criterion[0].capability = DOUBLEBUFFER;
1071 if (comparator == NONE) {
1072 criterion[0].comparison = EQ;
1073 criterion[0].value = 0;
1074 *allowDoubleAsSingle = True;
1075 *mask |= (1 << DOUBLEBUFFER);
1076 return 1;
1077 } else {
1078 return -1;
1079 }
1080 }
1081 if (!strcmp(word, "stereo")) {
1082 criterion[0].capability = STEREO;
1083 if (comparator == NONE) {
1084 criterion[0].comparison = EQ;
1085 criterion[0].value = 1;
1086 } else {
1087 criterion[0].comparison = comparator;
1088 criterion[0].value = value;
1089 }
1090 *mask |= (1 << STEREO);
1091 return 1;
1092 }
1093 if (!strcmp(word, "samples")) {
1094 criterion[0].capability = SAMPLES;
1095 if (comparator == NONE) {
1096 criterion[0].comparison = LTE;
1097 criterion[0].value = 4;
1098 } else {
1099 criterion[0].comparison = comparator;
1100 criterion[0].value = value;
1101 }
1102 *mask |= (1 << SAMPLES);
1103 return 1;
1104 }
1105 if (!strcmp(word, "slow")) {
1106 criterion[0].capability = SLOW;
1107 if (comparator == NONE) {
1108 /* Just "slow" means permit fast visuals, but accept
1109 slow ones in preference. Presumably the slow ones
1110 must be higher quality or something else desirable. */
1111 criterion[0].comparison = GTE;
1112 criterion[0].value = 0;
1113 } else {
1114 criterion[0].comparison = comparator;
1115 criterion[0].value = value;
1116 }
1117 *mask |= (1 << SLOW);
1118 return 1;
1119 }
1120 return -1;
1121 #if defined(_WIN32)
1122 case 'w':
1123 if (!strcmp(word, "win32pfd")) {
1124 criterion[0].capability = XVISUAL;
1125 if (comparator == NONE) {
1126 return -1;
1127 } else {
1128 criterion[0].comparison = comparator;
1129 criterion[0].value = value;
1130 return 1;
1131 }
1132 }
1133 return -1;
1134 #endif
1135 #if !defined(_WIN32)
1136 case 'x':
1137 if (!strcmp(word, "xvisual")) {
1138 if (comparator == NONE) {
1139 return -1;
1140 } else {
1141 criterion[0].capability = XVISUAL;
1142 criterion[0].comparison = comparator;
1143 criterion[0].value = value;
1144 /* Set everything in "mask" so that no default criteria
1145 get used. Assume the program really wants the
1146 xvisual specified. */
1147 *mask |= ~0;
1148 return 1;
1149 }
1150 }
1151 /* Be a little over-eager to fill in the comparison and
1152 value so we won't have to replicate the code after each
1153 string match. */
1154 if (comparator == NONE) {
1155 criterion[0].comparison = EQ;
1156 criterion[0].value = 1;
1157 } else {
1158 criterion[0].comparison = comparator;
1159 criterion[0].value = value;
1160 }
1161
1162 if (!strcmp(word, "xstaticgray")) {
1163 criterion[0].capability = XSTATICGRAY;
1164 *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual
1165 class selected. */
1166 return 1;
1167 }
1168 if (!strcmp(word, "xgrayscale")) {
1169 criterion[0].capability = XGRAYSCALE;
1170 *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual
1171 class selected. */
1172 return 1;
1173 }
1174 if (!strcmp(word, "xstaticcolor")) {
1175 criterion[0].capability = XSTATICCOLOR;
1176 *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual
1177 class selected. */
1178 return 1;
1179 }
1180 if (!strcmp(word, "xpseudocolor")) {
1181 criterion[0].capability = XPSEUDOCOLOR;
1182 *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual
1183 class selected. */
1184 return 1;
1185 }
1186 if (!strcmp(word, "xtruecolor")) {
1187 criterion[0].capability = XTRUECOLOR;
1188 *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual
1189 class selected. */
1190 return 1;
1191 }
1192 if (!strcmp(word, "xdirectcolor")) {
1193 criterion[0].capability = XDIRECTCOLOR;
1194 *mask |= (1 << XSTATICGRAY); /* Indicates _any_ visual
1195 class selected. */
1196 return 1;
1197 }
1198 return -1;
1199 #endif
1200 default:
1201 return -1;
1202 }
1203 }
1204
1205 static Criterion *
1206 parseModeString(char *mode, int *ncriteria, Bool * allowDoubleAsSingle,
1207 Criterion * requiredCriteria, int nRequired, int requiredMask)
1208 {
1209 Criterion *criteria = NULL;
1210 int n, mask, parsed, i;
1211 char *copy, *word;
1212
1213 *allowDoubleAsSingle = False;
1214 copy = __glutStrdup(mode);
1215 /* Attempt to estimate how many criteria entries should be
1216 needed. */
1217 n = 0;
1218 word = strtok(copy, " \t");
1219 while (word) {
1220 n++;
1221 word = strtok(NULL, " \t");
1222 }
1223 /* Overestimate by 4 times ("rgba" might add four criteria
1224 entries) plus add in possible defaults plus space for
1225 required criteria. */
1226 criteria = (Criterion *) malloc((4 * n + 30 + nRequired) * sizeof(Criterion));
1227 if (!criteria) {
1228 __glutFatalError("out of memory.");
1229 }
1230
1231 /* Re-copy the copy of the mode string. */
1232 strcpy(copy, mode);
1233
1234 /* First add the required criteria (these match at the
1235 highest priority). Typically these will be used to force a
1236 specific level (layer), transparency, and/or visual type. */
1237 mask = requiredMask;
1238 for (i = 0; i < nRequired; i++) {
1239 criteria[i] = requiredCriteria[i];
1240 }
1241 n = nRequired;
1242
1243 word = strtok(copy, " \t");
1244 while (word) {
1245 parsed = parseCriteria(word, &criteria[n], &mask, allowDoubleAsSingle);
1246 if (parsed >= 0) {
1247 n += parsed;
1248 } else {
1249 __glutWarning("Unrecognized display string word: %s (ignoring)\n", word);
1250 }
1251 word = strtok(NULL, " \t");
1252 }
1253
1254 #if defined(GLX_VERSION_1_1) && (defined(GLX_SGIS_multisample) || defined(GLX_ARB_multisample))
1255 if (__glutIsSupportedByGLX("GLX_SGIS_multisample") ||
1256 __glutIsSupportedByGLX("GLX_ARB_multisample")) {
1257 if (!(mask & (1 << SAMPLES))) {
1258 criteria[n].capability = SAMPLES;
1259 criteria[n].comparison = EQ;
1260 criteria[n].value = 0;
1261 n++;
1262 } else {
1263 /* Multisample visuals are marked nonconformant. If
1264 multisampling was requeste and no conformant
1265 preference was set, assume that we will settle for a
1266 non-conformant visual to get multisampling. */
1267 if (!(mask & (1 << CONFORMANT))) {
1268 criteria[n].capability = CONFORMANT;
1269 criteria[n].comparison = MIN;
1270 criteria[n].value = 0;
1271 n++;
1272 mask |= (1 << CONFORMANT);
1273 }
1274 }
1275 }
1276 #endif
1277 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_info)
1278 if (__glutIsSupportedByGLX("GLX_EXT_visual_info")) {
1279 if (!(mask & (1 << TRANSPARENT))) {
1280 criteria[n].capability = TRANSPARENT;
1281 criteria[n].comparison = EQ;
1282 criteria[n].value = 0;
1283 n++;
1284 }
1285 }
1286 #endif
1287 #if defined(GLX_VERSION_1_1) && defined(GLX_EXT_visual_rating)
1288 if (__glutIsSupportedByGLX("GLX_EXT_visual_rating")) {
1289 if (!(mask & (1 << SLOW))) {
1290 criteria[n].capability = SLOW;
1291 criteria[n].comparison = EQ;
1292 criteria[n].value = 0;
1293 n++;
1294 }
1295 if (!(mask & (1 << CONFORMANT))) {
1296 criteria[n].capability = CONFORMANT;
1297 criteria[n].comparison = EQ;
1298 criteria[n].value = 1;
1299 n++;
1300 }
1301 }
1302 #endif
1303 if (!(mask & (1 << ACCUM_RED_SIZE))) {
1304 criteria[n].capability = ACCUM_RED_SIZE;
1305 criteria[n].comparison = MIN;
1306 criteria[n].value = 0;
1307 criteria[n + 1].capability = ACCUM_GREEN_SIZE;
1308 criteria[n + 1].comparison = MIN;
1309 criteria[n + 1].value = 0;
1310 criteria[n + 2].capability = ACCUM_BLUE_SIZE;
1311 criteria[n + 2].comparison = MIN;
1312 criteria[n + 2].value = 0;
1313 criteria[n + 3].capability = ACCUM_ALPHA_SIZE;
1314 criteria[n + 3].comparison = MIN;
1315 criteria[n + 3].value = 0;
1316 n += 4;
1317 }
1318 if (!(mask & (1 << AUX_BUFFERS))) {
1319 criteria[n].capability = AUX_BUFFERS;
1320 criteria[n].comparison = MIN;
1321 criteria[n].value = 0;
1322 n++;
1323 }
1324 if (!(mask & (1 << RGBA))) {
1325 criteria[n].capability = RGBA;
1326 criteria[n].comparison = EQ;
1327 criteria[n].value = 1;
1328 criteria[n + 1].capability = RED_SIZE;
1329 criteria[n + 1].comparison = GTE;
1330 criteria[n + 1].value = 1;
1331 criteria[n + 2].capability = GREEN_SIZE;
1332 criteria[n + 2].comparison = GTE;
1333 criteria[n + 2].value = 1;
1334 criteria[n + 3].capability = BLUE_SIZE;
1335 criteria[n + 3].comparison = GTE;
1336 criteria[n + 3].value = 1;
1337 criteria[n + 4].capability = ALPHA_SIZE;
1338 criteria[n + 4].comparison = MIN;
1339 criteria[n + 4].value = 0;
1340 n += 5;
1341 mask |= (1 << RGBA_MODE);
1342 }
1343 #if !defined(_WIN32)
1344 if (!(mask & (1 << XSTATICGRAY))) {
1345 assert(isMesaGLX != -1);
1346 if ((mask & (1 << RGBA_MODE)) && !isMesaGLX) {
1347 /* Normally, request an RGBA mode visual be TrueColor,
1348 except in the case of Mesa where we trust Mesa (and
1349 other code in GLUT) to handle any type of RGBA visual
1350 reasonably. */
1351 if (mask & (1 << LUMINANCE_MODE)) {
1352 /* If RGBA luminance was requested, actually go for
1353 a StaticGray visual. */
1354 criteria[n].capability = XSTATICGRAY;
1355 } else {
1356 criteria[n].capability = XTRUECOLOR;
1357 }
1358 criteria[n].value = 1;
1359 criteria[n].comparison = EQ;
1360
1361 n++;
1362 }
1363 if (mask & (1 << CI_MODE)) {
1364 criteria[n].capability = XPSEUDOCOLOR;
1365 criteria[n].value = 1;
1366 criteria[n].comparison = EQ;
1367 n++;
1368 }
1369 }
1370 #endif
1371 if (!(mask & (1 << STEREO))) {
1372 criteria[n].capability = STEREO;
1373 criteria[n].comparison = EQ;
1374 criteria[n].value = 0;
1375 n++;
1376 }
1377 if (!(mask & (1 << DOUBLEBUFFER))) {
1378 criteria[n].capability = DOUBLEBUFFER;
1379 criteria[n].comparison = EQ;
1380 criteria[n].value = 0;
1381 *allowDoubleAsSingle = True;
1382 n++;
1383 }
1384 if (!(mask & (1 << DEPTH_SIZE))) {
1385 criteria[n].capability = DEPTH_SIZE;
1386 criteria[n].comparison = MIN;
1387 criteria[n].value = 0;
1388 n++;
1389 }
1390 if (!(mask & (1 << STENCIL_SIZE))) {
1391 criteria[n].capability = STENCIL_SIZE;
1392 criteria[n].comparison = MIN;
1393 criteria[n].value = 0;
1394 n++;
1395 }
1396 if (!(mask & (1 << LEVEL))) {
1397 criteria[n].capability = LEVEL;
1398 criteria[n].comparison = EQ;
1399 criteria[n].value = 0;
1400 n++;
1401 }
1402 if (n) {
1403 /* Since over-estimated the size needed; squeeze it down to
1404 reality. */
1405 criteria = (Criterion *) realloc(criteria, n * sizeof(Criterion));
1406 if (!criteria) {
1407 /* Should never happen since should be shrinking down! */
1408 __glutFatalError("out of memory.");
1409 }
1410 } else {
1411 /* For portability, avoid "realloc(ptr,0)" call. */
1412 free(criteria);
1413 criteria = NULL;
1414 }
1415
1416 free(copy);
1417 *ncriteria = n;
1418 return criteria;
1419 }
1420
1421 static FrameBufferMode *fbmodes = NULL;
1422 static int nfbmodes = 0;
1423
1424 static XVisualInfo *
1425 getVisualInfoFromString(char *string, Bool * treatAsSingle,
1426 Criterion * requiredCriteria, int nRequired, int requiredMask, void **fbc)
1427 {
1428 Criterion *criteria;
1429 XVisualInfo *visinfo;
1430 Bool allowDoubleAsSingle;
1431 int ncriteria, i;
1432
1433 if (!fbmodes) {
1434 fbmodes = loadVisuals(&nfbmodes);
1435 }
1436 criteria = parseModeString(string, &ncriteria,
1437 &allowDoubleAsSingle, requiredCriteria, nRequired, requiredMask);
1438 if (criteria == NULL) {
1439 __glutWarning("failed to parse mode string");
1440 return NULL;
1441 }
1442 #ifdef TEST
1443 printCriteria(criteria, ncriteria);
1444 #endif
1445 visinfo = findMatch(fbmodes, nfbmodes, criteria, ncriteria, fbc);
1446 if (visinfo) {
1447 *treatAsSingle = 0;
1448 } else {
1449 if (allowDoubleAsSingle) {
1450 /* Rewrite criteria so that we now look for a double
1451 buffered visual which will then get treated as a
1452 single buffered visual. */
1453 for (i = 0; i < ncriteria; i++) {
1454 if (criteria[i].capability == DOUBLEBUFFER
1455 && criteria[i].comparison == EQ
1456 && criteria[i].value == 0) {
1457 criteria[i].value = 1;
1458 }
1459 }
1460 visinfo = findMatch(fbmodes, nfbmodes, criteria, ncriteria, fbc);
1461 if (visinfo) {
1462 *treatAsSingle = 1;
1463 }
1464 }
1465 }
1466 free(criteria);
1467
1468 if (visinfo) {
1469 #if defined(_WIN32)
1470 /* We could have a valid pixel format for drawing to a
1471 bitmap. However, we don't want to draw into a bitmap, we
1472 need one that can be used with a window, so make sure
1473 that this is true. */
1474 if (!(visinfo->dwFlags & PFD_DRAW_TO_WINDOW))
1475 return NULL;
1476 #endif
1477 return visinfo;
1478 } else {
1479 return NULL;
1480 }
1481 }
1482
1483 /* CENTRY */
1484 void GLUTAPIENTRY
1485 glutInitDisplayString(const char *string)
1486 {
1487 #ifdef _WIN32
1488 XHDC = GetDC(GetDesktopWindow());
1489 #endif
1490
1491 __glutDetermineVisualFromString = getVisualInfoFromString;
1492 if (__glutDisplayString) {
1493 free(__glutDisplayString);
1494 }
1495 if (string) {
1496 __glutDisplayString = __glutStrdup(string);
1497 if (!__glutDisplayString)
1498 __glutFatalError("out of memory.");
1499 } else {
1500 __glutDisplayString = NULL;
1501 }
1502 }
1503 /* ENDCENTRY */
1504
1505 #ifdef TEST
1506
1507 Criterion requiredWindowCriteria[] =
1508 {
1509 {LEVEL, EQ, 0},
1510 {TRANSPARENT, EQ, 0}
1511 };
1512 int numRequiredWindowCriteria = sizeof(requiredWindowCriteria) / sizeof(Criterion);
1513 int requiredWindowCriteriaMask = (1 << LEVEL) | (1 << TRANSPARENT);
1514
1515 Criterion requiredOverlayCriteria[] =
1516 {
1517 {LEVEL, EQ, 1},
1518 {TRANSPARENT, EQ, 1},
1519 {XPSEUDOCOLOR, EQ, 1},
1520 {RGBA, EQ, 0},
1521 {BUFFER_SIZE, GTE, 1}
1522 };
1523 int numRequiredOverlayCriteria = sizeof(requiredOverlayCriteria) / sizeof(Criterion);
1524 int requiredOverlayCriteriaMask =
1525 (1 << LEVEL) | (1 << TRANSPARENT) | (1 << XSTATICGRAY) | (1 << RGBA) | (1 << CI_MODE);
1526
1527 int
1528 main(int argc, char **argv)
1529 {
1530 Display *dpy;
1531 XVisualInfo *vinfo;
1532 Bool treatAsSingle;
1533 char *str, buffer[1024];
1534 int tty = isatty(fileno(stdin));
1535 int overlay = 0, showconfig = 0;
1536 void *fbc;
1537
1538 #if !defined(_WIN32)
1539 dpy = XOpenDisplay(NULL);
1540 if (dpy == NULL) {
1541 printf("Could not connect to X server\n");
1542 exit(1);
1543 }
1544 __glutDisplay = dpy;
1545 __glutScreen = DefaultScreen(__glutDisplay);
1546 #endif
1547 while (!feof(stdin)) {
1548 if (tty)
1549 printf("dstr> ");
1550 str = fgets(buffer, 1023, stdin);
1551 if (str) {
1552 printf("\n");
1553 if (!strcmp("v", str)) {
1554 verbose = 1 - verbose;
1555 printf("verbose = %d\n\n", verbose);
1556 } else if (!strcmp("s", str)) {
1557 showconfig = 1 - showconfig;
1558 printf("showconfig = %d\n\n", showconfig);
1559 } else if (!strcmp("o", str)) {
1560 overlay = 1 - overlay;
1561 printf("overlay = %d\n\n", overlay);
1562 } else {
1563 if (overlay) {
1564 vinfo = getVisualInfoFromString(str, &treatAsSingle,
1565 requiredOverlayCriteria, numRequiredOverlayCriteria, requiredOverlayCriteriaMask, &fbc);
1566 } else {
1567 vinfo = getVisualInfoFromString(str, &treatAsSingle,
1568 requiredWindowCriteria, numRequiredWindowCriteria, requiredWindowCriteriaMask, &fbc);
1569 }
1570 if (vinfo) {
1571 printf("\n");
1572 if (!tty)
1573 printf("Display string: %s", str);
1574 #ifdef _WIN32
1575 printf("Visual = 0x%x\n", 0);
1576 #else
1577 printf("Visual = 0x%x%s\n", vinfo->visualid, fbc ? " (needs FBC)" : "");
1578 #endif
1579 if (treatAsSingle) {
1580 printf("Treat as SINGLE.\n");
1581 }
1582 if (showconfig) {
1583 int glxCapable, bufferSize, level, renderType, doubleBuffer,
1584 stereo, auxBuffers, redSize, greenSize, blueSize,
1585 alphaSize, depthSize, stencilSize, acRedSize, acGreenSize,
1586 acBlueSize, acAlphaSize;
1587
1588 glXGetConfig(dpy, vinfo, GLX_BUFFER_SIZE, &bufferSize);
1589 glXGetConfig(dpy, vinfo, GLX_LEVEL, &level);
1590 glXGetConfig(dpy, vinfo, GLX_RGBA, &renderType);
1591 glXGetConfig(dpy, vinfo, GLX_DOUBLEBUFFER, &doubleBuffer);
1592 glXGetConfig(dpy, vinfo, GLX_STEREO, &stereo);
1593 glXGetConfig(dpy, vinfo, GLX_AUX_BUFFERS, &auxBuffers);
1594 glXGetConfig(dpy, vinfo, GLX_RED_SIZE, &redSize);
1595 glXGetConfig(dpy, vinfo, GLX_GREEN_SIZE, &greenSize);
1596 glXGetConfig(dpy, vinfo, GLX_BLUE_SIZE, &blueSize);
1597 glXGetConfig(dpy, vinfo, GLX_ALPHA_SIZE, &alphaSize);
1598 glXGetConfig(dpy, vinfo, GLX_DEPTH_SIZE, &depthSize);
1599 glXGetConfig(dpy, vinfo, GLX_STENCIL_SIZE, &stencilSize);
1600 glXGetConfig(dpy, vinfo, GLX_ACCUM_RED_SIZE, &acRedSize);
1601 glXGetConfig(dpy, vinfo, GLX_ACCUM_GREEN_SIZE, &acGreenSize);
1602 glXGetConfig(dpy, vinfo, GLX_ACCUM_BLUE_SIZE, &acBlueSize);
1603 glXGetConfig(dpy, vinfo, GLX_ACCUM_ALPHA_SIZE, &acAlphaSize);
1604 printf("RGBA = (%d, %d, %d, %d)\n", redSize, greenSize, blueSize, alphaSize);
1605 printf("acc = (%d, %d, %d, %d)\n", acRedSize, acGreenSize, acBlueSize, acAlphaSize);
1606 printf("db = %d\n", doubleBuffer);
1607 printf("str = %d\n", stereo);
1608 printf("aux = %d\n", auxBuffers);
1609 printf("lvl = %d\n", level);
1610 printf("buf = %d\n", bufferSize);
1611 printf("rgba = %d\n", renderType);
1612 printf("z = %d\n", depthSize);
1613 printf("s = %d\n", stencilSize);
1614 }
1615 } else {
1616 printf("\n");
1617 printf("No match.\n");
1618 }
1619 printf("\n");
1620 }
1621 }
1622 }
1623 printf("\n");
1624 return 0;
1625 }
1626 #endif