Fixed bug #252: menu windows are drawn with immediate mode and the fixed
[freeglut] / src / x11 / fg_window_x11_glx.c
1 /*
2  * fg_window_x11_glx.c
3  *
4  * Window management methods for X11 with GLX
5  *
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7  * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8  * Copied for Platform code by Evan Felix <karcaw at gmail.com>
9  * Creation date: Thur Feb 2 2012
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  */
28
29 #define FREEGLUT_BUILDING_LIB
30 #include <GL/freeglut.h>
31 #include "fg_internal.h"
32
33 /* pushing attribute/value pairs into an array */
34 #define ATTRIB(a) attributes[where++]=(a)
35 #define ATTRIB_VAL(a,v) {ATTRIB(a); ATTRIB(v);}
36
37 /*
38  * Chooses a visual basing on the current display mode settings
39  */
40
41 int fghChooseConfig(GLXFBConfig* fbconfig)
42 {
43   GLboolean wantIndexedMode = GL_FALSE;
44   int attributes[ 100 ];
45   int where = 0, numAuxBuffers;
46
47   /* First we have to process the display mode settings... */
48   if( fgState.DisplayMode & GLUT_INDEX ) {
49     ATTRIB_VAL( GLX_BUFFER_SIZE, 8 );
50     /*  Buffer size is selected later.  */
51
52     ATTRIB_VAL( GLX_RENDER_TYPE, GLX_COLOR_INDEX_BIT );
53     wantIndexedMode = GL_TRUE;
54   } else {
55     ATTRIB_VAL( GLX_RED_SIZE,   1 );
56     ATTRIB_VAL( GLX_GREEN_SIZE, 1 );
57     ATTRIB_VAL( GLX_BLUE_SIZE,  1 );
58     if( fgState.DisplayMode & GLUT_ALPHA ) {
59       ATTRIB_VAL( GLX_ALPHA_SIZE, 1 );
60     }
61   }
62
63   if( fgState.DisplayMode & GLUT_DOUBLE ) {
64     ATTRIB_VAL( GLX_DOUBLEBUFFER, True );
65   }
66
67   if( fgState.DisplayMode & GLUT_STEREO ) {
68     ATTRIB_VAL( GLX_STEREO, True );
69   }
70
71   if( fgState.DisplayMode & GLUT_DEPTH ) {
72     ATTRIB_VAL( GLX_DEPTH_SIZE, 1 );
73   }
74
75   if( fgState.DisplayMode & GLUT_STENCIL ) {
76     ATTRIB_VAL( GLX_STENCIL_SIZE, 1 );
77   }
78
79   if( fgState.DisplayMode & GLUT_ACCUM ) {
80     ATTRIB_VAL( GLX_ACCUM_RED_SIZE, 1 );
81     ATTRIB_VAL( GLX_ACCUM_GREEN_SIZE, 1 );
82     ATTRIB_VAL( GLX_ACCUM_BLUE_SIZE, 1 );
83     if( fgState.DisplayMode & GLUT_ALPHA ) {
84       ATTRIB_VAL( GLX_ACCUM_ALPHA_SIZE, 1 );
85     }
86   }
87
88   numAuxBuffers = fghNumberOfAuxBuffersRequested();
89   if ( numAuxBuffers > 0 ) {
90     ATTRIB_VAL( GLX_AUX_BUFFERS, numAuxBuffers );
91   }
92
93   if( fgState.DisplayMode & GLUT_SRGB ) {
94     ATTRIB_VAL( GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, True );
95   }
96
97   if (fgState.DisplayMode & GLUT_MULTISAMPLE) {
98     ATTRIB_VAL(GLX_SAMPLE_BUFFERS, 1);
99     ATTRIB_VAL(GLX_SAMPLES, fgState.SampleNumber);
100   }
101
102   /* Push a terminator at the end of the list */
103   ATTRIB( None );
104
105     {
106         GLXFBConfig * fbconfigArray;  /*  Array of FBConfigs  */
107         int fbconfigArraySize;        /*  Number of FBConfigs in the array  */
108
109
110         /*  Get all FBConfigs that match "attributes".  */
111         fbconfigArray = glXChooseFBConfig( fgDisplay.pDisplay.Display,
112                                            fgDisplay.pDisplay.Screen,
113                                            attributes,
114                                            &fbconfigArraySize );
115
116         if (fbconfigArray != NULL)
117         {
118             int result __fg_unused;  /* Returned by glXGetFBConfigAttrib, not checked. */
119
120
121             if( wantIndexedMode )
122             {
123                 /*
124                  * In index mode, we want the largest buffer size, i.e. visual
125                  * depth.  Here, FBConfigs are sorted by increasing buffer size
126                  * first, so FBConfigs with the largest size come last.
127                  */
128
129                 int bufferSizeMin, bufferSizeMax;
130
131                 /*  Get bufferSizeMin.  */
132                 result =
133                   glXGetFBConfigAttrib( fgDisplay.pDisplay.Display,
134                                         fbconfigArray[0],
135                                         GLX_BUFFER_SIZE,
136                                         &bufferSizeMin );
137                 /*  Get bufferSizeMax.  */
138                 result =
139                   glXGetFBConfigAttrib( fgDisplay.pDisplay.Display,
140                                         fbconfigArray[fbconfigArraySize - 1],
141                                         GLX_BUFFER_SIZE,
142                                         &bufferSizeMax );
143
144                 if (bufferSizeMax > bufferSizeMin)
145                 {
146                     /* 
147                      * Free and reallocate fbconfigArray, keeping only FBConfigs
148                      * with the largest buffer size.
149                      */
150                     XFree(fbconfigArray);
151
152                     /*  Add buffer size token at the end of the list.  */
153                     where--;
154                     ATTRIB_VAL( GLX_BUFFER_SIZE, bufferSizeMax );
155                     ATTRIB( None );
156
157                     fbconfigArray = glXChooseFBConfig( fgDisplay.pDisplay.Display,
158                                                        fgDisplay.pDisplay.Screen,
159                                                        attributes,
160                                                        &fbconfigArraySize );
161                 }
162             }
163
164             *fbconfig = fbconfigArray[0];
165         }
166         else
167         {
168            *fbconfig = NULL;
169            return 0;
170         }
171         XFree(fbconfigArray);
172
173         return 1;
174     }
175 }
176
177 static void fghFillContextAttributes( int *attributes ) {
178   int where = 0, contextFlags, contextProfile;
179
180   ATTRIB_VAL( GLX_CONTEXT_MAJOR_VERSION_ARB, fgState.MajorVersion );
181   ATTRIB_VAL( GLX_CONTEXT_MINOR_VERSION_ARB, fgState.MinorVersion );
182
183   contextFlags =
184     fghMapBit( fgState.ContextFlags, GLUT_DEBUG, GLX_CONTEXT_DEBUG_BIT_ARB ) |
185     fghMapBit( fgState.ContextFlags, GLUT_FORWARD_COMPATIBLE, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB );
186   if ( contextFlags != 0 ) {
187     ATTRIB_VAL( GLX_CONTEXT_FLAGS_ARB, contextFlags );
188   }
189
190   contextProfile =
191     fghMapBit( fgState.ContextProfile, GLUT_CORE_PROFILE, GLX_CONTEXT_CORE_PROFILE_BIT_ARB ) |
192     fghMapBit( fgState.ContextProfile, GLUT_COMPATIBILITY_PROFILE, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB );
193   if ( contextProfile != 0 ) {
194     ATTRIB_VAL( GLX_CONTEXT_PROFILE_MASK_ARB, contextProfile );
195   }
196
197   ATTRIB( 0 );
198 }
199
200 typedef GLXContext (*CreateContextAttribsProc)(Display *dpy, GLXFBConfig config,
201                                                GLXContext share_list, Bool direct,
202                                                const int *attrib_list);
203
204 GLXContext fghCreateNewContext( SFG_Window* window )
205 {
206   /* for color model calculation */
207   int menu = ( window->IsMenu && !fgStructure.MenuContext );
208   int index_mode = ( fgState.DisplayMode & GLUT_INDEX );
209
210   /* "classic" context creation */
211   Display *dpy = fgDisplay.pDisplay.Display;
212   GLXFBConfig config = window->Window.pContext.FBConfig;
213   int render_type = ( !menu && index_mode ) ? GLX_COLOR_INDEX_TYPE : GLX_RGBA_TYPE;
214   GLXContext share_list = NULL;
215   Bool direct = ( fgState.DirectContext != GLUT_FORCE_INDIRECT_CONTEXT );
216   GLXContext context;
217
218   /* new context creation */
219   int attributes[9];
220   CreateContextAttribsProc createContextAttribs = (CreateContextAttribsProc) fgPlatformGetProcAddress( "glXCreateContextAttribsARB" );
221  
222   /* glXCreateContextAttribsARB not found, yet the user has requested the new context creation */
223   if ( !createContextAttribs && !fghIsLegacyContextRequested(window) ) {
224     fgWarning( "OpenGL >2.1 context requested but glXCreateContextAttribsARB is not available! Falling back to legacy context creation" );
225         fgState.MajorVersion = 2;
226         fgState.MinorVersion = 1;
227   }
228
229   /* If nothing fancy has been required, simply use the old context creation GLX API entry */
230   if ( fghIsLegacyContextRequested(window) || !createContextAttribs )
231   {
232     context = glXCreateNewContext( dpy, config, render_type, share_list, direct );
233     if ( context == NULL ) {
234       fghContextCreationError();
235     }
236     return context;
237   }
238
239   /* color index mode is not available anymore with OpenGL 3.0 */
240   if ( render_type == GLX_COLOR_INDEX_TYPE ) {
241     fgWarning( "color index mode is deprecated, using RGBA mode" );
242   }
243
244   fghFillContextAttributes( attributes );
245
246   context = createContextAttribs( dpy, config, share_list, direct, attributes );
247   if ( context == NULL ) {
248     fghContextCreationError();
249   }
250   return context;
251 }
252
253 void fgPlatformSetWindow ( SFG_Window *window )
254 {
255     if ( window )
256     {
257         glXMakeContextCurrent(
258             fgDisplay.pDisplay.Display,
259             window->Window.Handle,
260             window->Window.Handle,
261             window->Window.Context
262         );
263     }
264 }