1 /********************************************************************************
2 *                                                                               *
3 *                            V i s u a l   C l a s s                            *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1999,2021 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify          *
9 * it under the terms of the GNU Lesser General Public License as published by   *
10 * the Free Software Foundation; either version 3 of the License, or             *
11 * (at your option) any later version.                                           *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
16 * GNU Lesser General Public License for more details.                           *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public License      *
19 * along with this program.  If not, see <http://www.gnu.org/licenses/>          *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "FXArray.h"
26 #include "FXHash.h"
27 #include "FXMutex.h"
28 #include "FXElement.h"
29 #include "FXStream.h"
30 #include "FXString.h"
31 #include "FXSize.h"
32 #include "FXPoint.h"
33 #include "FXRectangle.h"
34 #include "FXException.h"
35 #include "FXStringDictionary.h"
36 #include "FXSettings.h"
37 #include "FXRegistry.h"
38 #include "FXAccelTable.h"
39 #include "FXFont.h"
40 #include "FXEvent.h"
41 #include "FXWindow.h"
42 #include "FXApp.h"
43 #include "FXGLVisual.h"
44 
45 
46 /*
47   Notes:
48 
49   - FXGLVisual builds a visual/pixelformat suitable for GL drawing.
50 
51   - Selection of visual/pixelformat is based on a best match to a
52     given set of hints, according to some heuristics:
53 
54     1) Prefer color depth close to asked ones; really like to
55        get a bit MORE color, rather than LESS, however.
56 
57     2) If we wanted Z-buffer, it is STRONGLY preferred; If there's
58        a choice, we prefer more color depth over more Z-depth; if
59        we already have more colors than requested, we prefer to meet
60        requested Z depth.
61 
62     3) If we wanted double buffer, we strongly prefer it over color and
63        Z depth, but HAVING a Z-buffer is still more important.
64 
65     4) If we wanted alpha buffer, it is preferred, but Z-buffering
66        and double buffering are considered more important.
67        If there's a choice, we prefer to receive a few MORE bits of
68        alpha buffer than we asked for, rather than LESS.
69 
70     5) If we wanted stereo, we prefer it, but almost everything except
71        the color-, alpha-, and Z-depths are more important.
72 
73   - Some further tuning may be desired, but I think this should satisfy
74     most cases....
75 
76   - Note that as long as OpenGL is in any way supported, you should ALWAYS
77     be able to get at least some visual/pixelformat you can draw on.
78 
79   - As far as hardware acceleration goes, H/W acceleration should be
80     enabled, possibly at the expense of color-, alpha-, and Z-depth;
81     but NEVER at the expense of presence or absence of a requested feature.
82     We only drop FEATURES which are requested if there is neither hardware
83     nor software support.
84 
85     For example, we may trade in some Z-depth, but not the entire Z-buffer,
86     to get a hardware accelerated visual/pixelformat.
87 */
88 
89 
90 using namespace FX;
91 
92 /*******************************************************************************/
93 
94 namespace FX {
95 
96 // Object implementation
97 FXIMPLEMENT(FXGLVisual,FXVisual,NULL,0)
98 
99 
100 // Deserialization
FXGLVisual()101 FXGLVisual::FXGLVisual(){
102   redSize=0;
103   greenSize=0;
104   blueSize=0;
105   alphaSize=0;
106   depthSize=0;
107   stencilSize=0;
108   multiSamples=0;
109   accumRedSize=0;
110   accumGreenSize=0;
111   accumBlueSize=0;
112   accumAlphaSize=0;
113   actualRedSize=0;
114   actualGreenSize=0;
115   actualBlueSize=0;
116   actualAlphaSize=0;
117   actualDepthSize=0;
118   actualStencilSize=0;
119   actualMultiSamples=0;
120   actualAccumRedSize=0;
121   actualAccumGreenSize=0;
122   actualAccumBlueSize=0;
123   actualAccumAlphaSize=0;
124   doubleBuffer=false;
125   stereoBuffer=false;
126   accelerated=false;
127   copying=false;
128   }
129 
130 
131 // Construct
FXGLVisual(FXApp * a,FXuint flgs)132 FXGLVisual::FXGLVisual(FXApp* a,FXuint flgs):FXVisual(a,flgs,0){
133   FXTRACE((100,"FXGLVisual::FXGLVisual %p\n",this));
134   redSize=8;
135   greenSize=8;
136   blueSize=8;
137   alphaSize=0;
138   depthSize=24;
139   stencilSize=0;
140   multiSamples=0;
141   accumRedSize=0;
142   accumGreenSize=0;
143   accumBlueSize=0;
144   accumAlphaSize=0;
145   actualRedSize=0;
146   actualGreenSize=0;
147   actualBlueSize=0;
148   actualAlphaSize=0;
149   actualDepthSize=0;
150   actualStencilSize=0;
151   actualMultiSamples=0;
152   actualAccumRedSize=0;
153   actualAccumGreenSize=0;
154   actualAccumBlueSize=0;
155   actualAccumAlphaSize=0;
156   doubleBuffer=false;
157   stereoBuffer=false;
158   accelerated=false;
159   copying=false;
160   }
161 
162 
163 // Test if OpenGL is possible
hasOpenGL(FXApp * application)164 FXbool FXGLVisual::hasOpenGL(FXApp* application){
165   if(application->isInitialized()){
166 #ifdef HAVE_GL_H
167 #ifdef WIN32            // WIN32
168     return true;
169 #else                   // UNIX
170     return glXQueryExtension((Display*)application->getDisplay(),NULL,NULL);
171 #endif
172 #endif
173     }
174   return false;
175   }
176 
177 
178 /*******************************************************************************/
179 
180 // Describes particular FB configuration
181 struct FXGLVisual::FXGLSpecs {
182   int redsize;
183   int greensize;
184   int bluesize;
185   int alphasize;
186   int depthsize;
187   int stencilsize;
188   int accumredsize;
189   int accumgreensize;
190   int accumbluesize;
191   int accumalphasize;
192   int doublebuffer;
193   int stereobuffer;
194   int multisamples;
195   int composition;
196   int image;
197   int accel;
198   int copy;
199   };
200 
201 
202 // Match actual GL depth to desired one
matchSpecs(const FXGLSpecs & s)203 FXint FXGLVisual::matchSpecs(const FXGLSpecs& s){
204   FXint match,dred,dgreen,dblue,dalpha,ddepth,dstencil,dsamples,daccred,daccgreen,daccblue,daccalpha;
205 
206   // We prefer to get a few MORE bits in RGBA than we asked for
207   dred   = s.redsize-redSize;     if(dred<0)   dred   *= -100;
208   dgreen = s.greensize-greenSize; if(dgreen<0) dgreen *= -100;
209   dblue  = s.bluesize-blueSize;   if(dblue<0)  dblue  *= -100;
210   dalpha = s.alphasize-alphaSize; if(dalpha<0) dalpha *= -100;
211 
212   // Prefer better Z than asked, but colors more important
213   ddepth = s.depthsize-depthSize; if(ddepth<0) ddepth *= -10;
214 
215   // We care about colors and Z depth more than stencil depth
216   dstencil = s.stencilsize-stencilSize; if(dstencil<0) dstencil *= -1;
217 
218   // Accumulation buffers
219   daccred=s.accumredsize-accumRedSize;       if(daccred<0)   daccred   *= -1;
220   daccgreen=s.accumgreensize-accumGreenSize; if(daccgreen<0) daccgreen *= -1;
221   daccblue=s.accumbluesize-accumBlueSize;    if(daccblue<0)  daccblue  *= -1;
222   daccalpha=s.accumalphasize-accumAlphaSize; if(daccalpha<0) daccalpha *= -1;
223 
224   // Want the best colors, of course
225   match=dred+dgreen+dblue+dalpha;
226 
227   // Accumulation buffers
228   match+=daccred+daccgreen+daccblue+daccalpha;
229 
230   // Hardware accelerated is normally a plus
231   if(!s.accel && !(flags&VISUAL_NO_ACCEL)){
232     match+=10000;
233     }
234 
235   // Extra penalty for no alpha if we asked for alpha, but no
236   // penalty at all if there is alpha and we didn't ask for it.
237   if(alphaSize>0){
238     if(s.alphasize<1) match+=100000;
239     }
240 
241   // Wanted Z-buffer
242   if(depthSize>0){
243     if(s.depthsize<1) match+=10000000;
244     else match+=ddepth;
245     }
246   else{
247     if(s.depthsize>0) match+=10000000;
248     }
249 
250   // Stencil buffers desired
251   if(stencilSize>0){
252     if(s.stencilsize<1) match+=10000;
253     else match+=dstencil;
254     }
255   else{
256     if(s.stencilsize>0) match+=1;
257     }
258 
259   // Multisamples
260   if(multiSamples>0){
261     dsamples=s.multisamples-multiSamples;
262     if(dsamples<0) dsamples*=-10;
263     match+=dsamples;
264     }
265   else{
266     if(s.multisamples>0) match+=100;
267     }
268 
269   // Double buffering also quite strongly preferred
270   if(flags&VISUAL_DOUBLE_BUFFER){
271     if(!s.doublebuffer) match+=1000000;
272     }
273   else{
274     if(s.doublebuffer) match+=1000000;
275     }
276 
277   // Stereo not so important
278   if(flags&VISUAL_STEREO){
279     if(!s.stereobuffer) match+=10000;
280     }
281   else{
282     if(s.stereobuffer) match+=10000;
283     }
284 
285   // Swap copies also important
286   if(flags&VISUAL_SWAP_COPY){
287     if(!s.copy) match+=10000000;
288     }
289 
290   // Composition support would be nice to have
291   if(!s.composition) match+=100;
292 
293   // Off-screen drawing would be nice
294   if(!s.image) match+=1;
295 
296   return match;
297   }
298 
299 
300 #if defined(WIN32) ///////////////// WIN32 //////////////////////////////////////
301 
302 #ifndef PFD_SUPPORT_COMPOSITION
303 #define PFD_SUPPORT_COMPOSITION         0x00008000
304 #endif
305 
306 #ifdef HAVE_GL_H
307 
308 // Palette struct
309 struct LOGPALETTE256 {
310   WORD         palVersion;
311   WORD         palNumEntries;
312   PALETTEENTRY palPalEntry[257];
313   };
314 
315 
316 // System colors to match against
317 static FXuchar defSysClr[20][3] = {
318     {  0,  0,  0},
319     {128,  0,  0},
320     {  0,128,  0},
321     {128,128,  0},
322     {  0,  0,128},
323     {128,  0,128},
324     {  0,128,128},
325     {192,192,192},
326 
327     {192,220,192},
328     {166,202,240},
329     {255,251,240},
330     {160,160,164},
331 
332     {128,128,128},
333     {255,  0,  0},
334     {  0,255,  0},
335     {255,255,  0},
336     {  0,  0,255},
337     {255,  0,255},
338     {  0,255,255},
339     {255,255,255}
340     };
341 
342 static int defaultOverride[13] = {
343   0, 3, 24, 27, 64, 67, 88, 173, 181, 236, 247, 164, 91
344   };
345 
346 
347 // Make palette
makeOpenGLPalette(PIXELFORMATDESCRIPTOR * info)348 static HPALETTE makeOpenGLPalette(PIXELFORMATDESCRIPTOR* info){
349   LOGPALETTE256 palette;
350   int num,i,j,rr,gg,bb;
351   int rmax,gmax,bmax;
352   HPALETTE hPalette;
353 
354   // Size of palette array
355   num=1<<((PIXELFORMATDESCRIPTOR*)info)->cColorBits;
356 
357   FXASSERT(num<=256);
358 
359   // Maximum values each color
360   rmax=(1 << info->cRedBits)-1;
361   gmax=(1 << info->cGreenBits)-1;
362   bmax=(1 << info->cBlueBits)-1;
363 
364   // Build palette
365   for(rr=0; rr<=rmax; rr++){
366     for(gg=0; gg<=gmax; gg++){
367       for(bb=0; bb<=bmax; bb++){
368         i = (rr << info->cRedShift) | (gg << info->cGreenShift) | (bb << info->cBlueShift);
369         palette.palPalEntry[i].peRed = (255*rr)/rmax;
370         palette.palPalEntry[i].peGreen = (255*gg)/gmax;
371         palette.palPalEntry[i].peBlue = (255*bb)/bmax;
372         palette.palPalEntry[i].peFlags = PC_NOCOLLAPSE;
373         }
374       }
375     }
376 
377   // For 8-bit palette
378   if((info->cColorBits==8) && (info->cRedBits==3) && (info->cRedShift==0) && (info->cGreenBits==3) && (info->cGreenShift==3) && (info->cBlueBits==2) && (info->cBlueShift==6)){
379     for(j=1; j<=12; j++){
380       palette.palPalEntry[defaultOverride[j]].peRed=defSysClr[j][0];
381       palette.palPalEntry[defaultOverride[j]].peGreen=defSysClr[j][1];
382       palette.palPalEntry[defaultOverride[j]].peBlue=defSysClr[j][1];
383       palette.palPalEntry[defaultOverride[j]].peFlags=0;
384       }
385     }
386 
387   // Fill in the rest
388   palette.palVersion=0x300;
389   palette.palNumEntries=num;
390 
391   // Make palette
392   hPalette=CreatePalette((const LOGPALETTE*)&palette);
393 
394   return hPalette;
395   }
396 
397 #endif
398 
399 
400 // Initialize
create()401 void FXGLVisual::create(){
402   if(!xid){
403     if(getApp()->isInitialized()){
404       FXTRACE((100,"%s::create %p\n",getClassName(),this));
405 #ifdef HAVE_GL_H
406       PIXELFORMATDESCRIPTOR pfd;
407       int bestmatch=1000000000;
408       int best=-1;
409       int match;
410       int npf;
411       HDC hdc;
412 
413       // Get some window handle
414       hdc=GetDC(GetDesktopWindow());
415 
416       // Get number of supported pixel formats
417       pfd.nSize=sizeof(PIXELFORMATDESCRIPTOR);
418       pfd.nVersion=1;
419 
420       // Get number of supported pixel formats
421       if(0<(npf=DescribePixelFormat(hdc,1,sizeof(PIXELFORMATDESCRIPTOR),&pfd))){
422 
423         FXTRACE((140,"Found %d OpenGL configs\n",npf));
424 
425         // Try to find the best
426         for(int v=1; v<=npf; v++){
427           FXGLSpecs specs;
428 
429           // Get info about this visual
430           DescribePixelFormat(hdc,v,sizeof(PIXELFORMATDESCRIPTOR),&pfd);
431 
432           // Make sure this visual is valid
433 //          if(ChoosePixelFormat(hdc,&pfd)!=v) continue;
434 
435           // Get supported render type; we don't want index mode
436           if(pfd.iPixelType==PFD_TYPE_COLORINDEX) continue;
437 
438           // OpenGL support is required
439           if(!(pfd.dwFlags&PFD_SUPPORT_OPENGL)) continue;
440 
441           // Draw to window is required
442           if(!(pfd.dwFlags&PFD_DRAW_TO_WINDOW)) continue;
443 
444           // Get planes
445           specs.redsize=pfd.cRedBits;
446           specs.greensize=pfd.cGreenBits;
447           specs.bluesize=pfd.cBlueBits;
448           specs.alphasize=pfd.cAlphaBits;
449           specs.depthsize=pfd.cDepthBits;
450           specs.stencilsize=pfd.cStencilBits;
451           specs.accumredsize=pfd.cAccumRedBits;
452           specs.accumgreensize=pfd.cAccumGreenBits;
453           specs.accumbluesize=pfd.cAccumBlueBits;
454           specs.accumalphasize=pfd.cAccumAlphaBits;
455 
456           // Double buffer capable
457           specs.doublebuffer=(pfd.dwFlags&PFD_DOUBLEBUFFER)!=0;
458 
459           // Stereo capable
460           specs.stereobuffer=(pfd.dwFlags&PFD_STEREO)!=0;
461 
462           // Multisample
463           specs.multisamples=0;
464 
465           // Windows Vista and Windows 7 composition support
466           specs.composition=(pfd.dwFlags&PFD_SUPPORT_COMPOSITION)!=0;
467 
468           // Bitmap drawing would be nice
469           specs.image=(pfd.dwFlags&PFD_DRAW_TO_BITMAP)!=0;
470 
471           // Hardware accelerated format
472           specs.accel=(pfd.dwFlags&PFD_GENERIC_FORMAT)==0;
473 
474           // Swap buffers by copying
475           specs.copy=(pfd.dwFlags&PFD_SWAP_COPY)!=0;
476 
477           // Match specs
478           match=matchSpecs(specs);
479 
480           // Trace
481           FXTRACE((150,"Config: #%d: match=%d\n",v,match));
482           FXTRACE((150,"  drawables  = %s%s\n",(pfd.dwFlags&PFD_DRAW_TO_WINDOW)?"PFD_DRAW_TO_WINDOW ":"",(pfd.dwFlags&PFD_DRAW_TO_BITMAP)?"PFD_DRAW_TO_BITMAP ":""));
483           FXTRACE((150,"  render     = %s\n",(pfd.iPixelType==PFD_TYPE_COLORINDEX)?"PFD_TYPE_COLORINDEX":(pfd.iPixelType==PFD_TYPE_RGBA)?"PFD_TYPE_RGBA":""));
484           FXTRACE((150,"  red size   = %d\n",specs.redsize));
485           FXTRACE((150,"  green size = %d\n",specs.greensize));
486           FXTRACE((150,"  blue size  = %d\n",specs.bluesize));
487           FXTRACE((150,"  alpha size = %d\n",specs.alphasize));
488           FXTRACE((150,"  depth size = %d\n",specs.depthsize));
489           FXTRACE((150,"  stencil    = %d\n",specs.stencilsize));
490           FXTRACE((150,"  acc red    = %d\n",specs.accumredsize));
491           FXTRACE((150,"  acc green  = %d\n",specs.accumgreensize));
492           FXTRACE((150,"  acc blue   = %d\n",specs.accumbluesize));
493           FXTRACE((150,"  acc alpha  = %d\n",specs.accumalphasize));
494           FXTRACE((150,"  double buf = %d\n",specs.doublebuffer));
495           FXTRACE((150,"  stereo buf = %d\n",specs.stereobuffer));
496           FXTRACE((150,"  samples    = %d\n",specs.multisamples));
497           FXTRACE((150,"  accel      = %d\n",specs.accel));
498 
499           // May the best visual win
500           if(match<=bestmatch){
501             actualRedSize=specs.redsize;
502             actualGreenSize=specs.greensize;
503             actualBlueSize=specs.bluesize;
504             actualAlphaSize=specs.alphasize;
505             actualDepthSize=specs.depthsize;
506             actualStencilSize=specs.stencilsize;
507             actualMultiSamples=specs.multisamples;
508             actualAccumRedSize=specs.accumredsize;
509             actualAccumGreenSize=specs.accumgreensize;
510             actualAccumBlueSize=specs.accumbluesize;
511             actualAccumAlphaSize=specs.accumalphasize;
512             doubleBuffer=specs.doublebuffer;
513             stereoBuffer=specs.stereobuffer;
514             accelerated=specs.accel;
515             copying=specs.copy;
516             bestmatch=match;
517             best=v;
518             }
519           }
520         }
521 
522       // Hopefully, we got one
523       if(0<=best){
524         FXTRACE((140,"Best Config: #%d: match=%d\n",best,bestmatch));
525 
526         // Fill in visual data
527         depth=actualRedSize+actualGreenSize+actualBlueSize;
528         numred=(1<<actualRedSize);
529         numgreen=(1<<actualGreenSize);
530         numblue=(1<<actualBlueSize);
531         numcolors=numred*numgreen*numblue;
532 
533         // Make a palette for it if needed
534         if(pfd.dwFlags&PFD_NEED_PALETTE){
535           colormap=makeOpenGLPalette(&pfd);
536           freemap=true;
537           }
538 
539         // Remember best config
540         xid=(void*)(FXival)best;
541         }
542 
543       // Done with that window
544       ::ReleaseDC(GetDesktopWindow(),hdc);
545 
546       // Make non-current
547       wglMakeCurrent(NULL,NULL);
548 #endif
549       }
550 
551     // Test if successful
552     if(!xid){
553       throw FXWindowException("unable to create GL context.");
554       }
555     }
556   }
557 
558 
559 #else //////////////////////////////// X11 OLD //////////////////////////////////
560 
561 
562 #ifndef GLX_ARB_multisample
563 #define GLX_SAMPLE_BUFFERS_ARB             100000
564 #define GLX_SAMPLES_ARB                    100001
565 #endif
566 #ifndef GLX_EXT_visual_rating
567 #define GLX_VISUAL_CAVEAT_EXT              0x20
568 #define GLX_SLOW_VISUAL_EXT                0x8001
569 #define GLX_NON_CONFORMANT_VISUAL_EXT      0x800D
570 #endif
571 
572 
573 // Initialize
create()574 void FXGLVisual::create(){
575   if(!xid){
576     if(getApp()->isInitialized()){
577       FXTRACE((100,"%s::create %p\n",getClassName(),this));
578 #ifdef HAVE_GL_H
579       int majoropcode,errorbase,eventbase;
580 
581       // Assume the default
582       visual=DefaultVisual((Display*)getApp()->getDisplay(),DefaultScreen((Display*)getApp()->getDisplay()));
583       depth=DefaultDepth((Display*)getApp()->getDisplay(),DefaultScreen((Display*)getApp()->getDisplay()));
584 
585       // OpenGL is available if we're talking to an OpenGL-capable X-Server
586       if(XQueryExtension((Display*)getApp()->getDisplay(),"GLX",&majoropcode,&errorbase,&eventbase)){
587         if(glXQueryExtension((Display*)getApp()->getDisplay(),&errorbase,&eventbase)){
588           int major,minor;
589 
590           // Try get OpenGL version info
591           if(glXQueryVersion((Display*)getApp()->getDisplay(),&major,&minor)){
592             XVisualInfo vitemplate,*vi; int nvi;
593 
594             // Report version found
595             FXTRACE((100,"Found GLX version: %d.%d (Major: %d, Error: %d, Event: %d)\n",major,minor,majoropcode,errorbase,eventbase));
596 
597             // Scan for all visuals of given screen
598             vitemplate.screen=DefaultScreen((Display*)getApp()->getDisplay());
599             vi=XGetVisualInfo((Display*)getApp()->getDisplay(),VisualScreenMask,&vitemplate,&nvi);
600             if(vi){
601               int defvisualid=XVisualIDFromVisual(DefaultVisual((Display*)getApp()->getDisplay(),DefaultScreen((Display*)getApp()->getDisplay())));
602               int samplebuffers=0;
603               int bestmatch=1000000000;
604               int best=-1;
605               int value;
606               int match;
607 
608               FXTRACE((150,"Found %d configs\n",nvi));
609               FXTRACE((150,"Default visualid=0x%02x\n",defvisualid));
610 
611               // Find the best one
612               for(int v=0; v<nvi; v++){
613                 FXGLSpecs specs;
614 
615                 // GL support is requested
616                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_USE_GL,&value)!=Success || (value==0)) continue;
617 
618                 // Get supported drawable targets
619                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_RGBA,&value)!=Success || (value==0)) continue;
620 
621                 // Get overlay level
622                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_LEVEL,&value)!=Success || (value!=0)) continue;
623 
624                 // Get plane depths
625                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_RED_SIZE,&specs.redsize)!=Success) continue;
626                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_GREEN_SIZE,&specs.greensize)!=Success) continue;
627                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_BLUE_SIZE,&specs.bluesize)!=Success) continue;
628                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_ALPHA_SIZE,&specs.alphasize)!=Success) continue;
629                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_DEPTH_SIZE,&specs.depthsize)!=Success) continue;
630                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_STENCIL_SIZE,&specs.stencilsize)!=Success) continue;
631                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_ACCUM_RED_SIZE,&specs.accumredsize)!=Success) continue;
632                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_ACCUM_GREEN_SIZE,&specs.accumgreensize)!=Success) continue;
633                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_ACCUM_BLUE_SIZE,&specs.accumbluesize)!=Success) continue;
634                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_ACCUM_ALPHA_SIZE,&specs.accumalphasize)!=Success) continue;
635 
636                 // Get stereo and double buffer support
637                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_DOUBLEBUFFER,&specs.doublebuffer)!=Success) continue;
638                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_STEREO,&specs.stereobuffer)!=Success) continue;
639 
640                 // Get multisample support (if we don't succeed, set it to zero)
641                 specs.multisamples=0;
642                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_SAMPLE_BUFFERS_ARB,&samplebuffers)==Success && samplebuffers){
643                   if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_SAMPLES_ARB,&specs.multisamples)!=Success) continue;
644                   }
645 
646                 // Check if accelerated or not (assume yes)
647                 if(glXGetConfig((Display*)getApp()->getDisplay(),&vi[v],GLX_VISUAL_CAVEAT_EXT,&specs.accel)==Success){
648                   specs.accel=(specs.accel!=GLX_SLOW_VISUAL_EXT);        // Penalize if any caveats present
649                   }
650                 else{
651                   specs.accel=1;
652                   }
653 
654                 // Composition and swap copy
655                 specs.composition=false;
656                 specs.image=false;
657                 specs.copy=false;
658 
659                 // Match specs
660                 match=matchSpecs(specs);
661 
662                 // Trace
663                 FXTRACE((150,"Config: #%d: match=%d\n",v,match));
664                 FXTRACE((150,"  visualid   = 0x%02lx\n",vi[v].visualid));
665                 FXTRACE((150,"  red size   = %d\n",specs.redsize));
666                 FXTRACE((150,"  green size = %d\n",specs.greensize));
667                 FXTRACE((150,"  blue size  = %d\n",specs.bluesize));
668                 FXTRACE((150,"  alpha size = %d\n",specs.alphasize));
669                 FXTRACE((150,"  depth size = %d\n",specs.depthsize));
670                 FXTRACE((150,"  stencil    = %d\n",specs.stencilsize));
671                 FXTRACE((150,"  acc red    = %d\n",specs.accumredsize));
672                 FXTRACE((150,"  acc green  = %d\n",specs.accumgreensize));
673                 FXTRACE((150,"  acc blue   = %d\n",specs.accumbluesize));
674                 FXTRACE((150,"  acc alpha  = %d\n",specs.accumalphasize));
675                 FXTRACE((150,"  double buf = %d\n",specs.doublebuffer));
676                 FXTRACE((150,"  stereo buf = %d\n",specs.stereobuffer));
677                 FXTRACE((150,"  samples    = %d\n",specs.multisamples));
678                 FXTRACE((150,"  accel      = %d\n",specs.accel));
679 
680                 // May the best config win
681                 if(match<=bestmatch){
682 
683                   // All other things being equal, we prefer default visual!
684                   if((match<bestmatch) || (vi[v].visualid==defvisualid)){
685                     actualRedSize=specs.redsize;
686                     actualGreenSize=specs.greensize;
687                     actualBlueSize=specs.bluesize;
688                     actualAlphaSize=specs.alphasize;
689                     actualDepthSize=specs.depthsize;
690                     actualStencilSize=specs.stencilsize;
691                     actualMultiSamples=specs.multisamples;
692                     actualAccumRedSize=specs.accumredsize;
693                     actualAccumGreenSize=specs.accumgreensize;
694                     actualAccumBlueSize=specs.accumbluesize;
695                     actualAccumAlphaSize=specs.accumalphasize;
696                     doubleBuffer=specs.doublebuffer;
697                     stereoBuffer=specs.stereobuffer;
698                     accelerated=specs.accel;
699                     copying=specs.copy;
700                     bestmatch=match;
701                     best=v;
702                     }
703                   }
704                 }
705 
706               // We should have one now
707               if(0<=best){
708                 FXTRACE((140,"Best Config: #%d: match=%d\n",best,bestmatch));
709 
710                 // Remember visual, depth, visualid
711                 visual=vi[best].visual;
712                 depth=vi[best].depth;
713 
714                 // Initialize colormap
715                 setupcolormap();
716 
717                 // Make GC's for this visual
718                 scrollgc=setupgc(true);
719                 gc=setupgc(false);
720 
721                 // Remember best config
722                 xid=((Visual*)visual)->visualid;
723                 }
724 
725               // Free visual info
726               XFree((char*)vi);
727               }
728             }
729           }
730         }
731 #endif
732       }
733 
734     // Test if successful
735     if(!xid){
736       throw FXWindowException("no matching GL configuration.");
737       }
738     }
739   }
740 
741 
742 #endif //////////////////////////////////////////////////////////////////////////
743 
744 
745 // Detach visual
detach()746 void FXGLVisual::detach(){
747 #ifdef HAVE_GL_H
748   if(xid){
749     FXTRACE((100,"%s::detach %p\n",getClassName(),this));
750     colormap=0;
751     freemap=false;
752     xid=0;
753     }
754 #endif
755   }
756 
757 
758 // Destroy visual
destroy()759 void FXGLVisual::destroy(){
760 #ifdef HAVE_GL_H
761   if(xid){
762     if(getApp()->isInitialized()){
763       FXTRACE((100,"%s::destroy %p\n",getClassName(),this));
764 #ifdef WIN32
765       if(colormap){ DeleteObject(colormap); }
766 #else
767       if(freemap){ XFreeColormap((Display*)getApp()->getDisplay(),colormap); }
768       if(scrollgc){ XFreeGC((Display*)getApp()->getDisplay(),(GC)scrollgc); }
769       if(gc){ XFreeGC((Display*)getApp()->getDisplay(),(GC)gc); }
770 #endif
771       }
772 #ifndef WIN32
773     scrollgc=0;
774     gc=0;
775 #endif
776     colormap=0;
777     freemap=false;
778     xid=0;
779     }
780 #endif
781   }
782 
783 
784 // Save to stream
save(FXStream & store) const785 void FXGLVisual::save(FXStream& store) const {
786   FXVisual::save(store);
787   store << redSize;
788   store << greenSize;
789   store << blueSize;
790   store << alphaSize;
791   store << depthSize;
792   store << stencilSize;
793   store << multiSamples;
794   store << accumRedSize;
795   store << accumGreenSize;
796   store << accumBlueSize;
797   store << accumAlphaSize;
798   }
799 
800 
801 // Load from stream
load(FXStream & store)802 void FXGLVisual::load(FXStream& store){
803   FXVisual::load(store);
804   store >> redSize;
805   store >> greenSize;
806   store >> blueSize;
807   store >> alphaSize;
808   store >> depthSize;
809   store >> stencilSize;
810   store >> multiSamples;
811   store >> accumRedSize;
812   store >> accumGreenSize;
813   store >> accumBlueSize;
814   store >> accumAlphaSize;
815   }
816 
817 
818 // Destroy
~FXGLVisual()819 FXGLVisual::~FXGLVisual(){
820   FXTRACE((100,"FXGLVisual::~FXGLVisual %p\n",this));
821   destroy();
822   }
823 
824 
825 }
826