Fixing a preprocessor typo
[freeglut] / src / Common / freeglut_init.c
1 /*\r
2  * freeglut_init.c\r
3  *\r
4  * Various freeglut initialization functions.\r
5  *\r
6  * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.\r
7  * Written by Pawel W. Olszta, <olszta@sourceforge.net>\r
8  * Creation date: Thu Dec 2 1999\r
9  *\r
10  * Permission is hereby granted, free of charge, to any person obtaining a\r
11  * copy of this software and associated documentation files (the "Software"),\r
12  * to deal in the Software without restriction, including without limitation\r
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,\r
14  * and/or sell copies of the Software, and to permit persons to whom the\r
15  * Software is furnished to do so, subject to the following conditions:\r
16  *\r
17  * The above copyright notice and this permission notice shall be included\r
18  * in all copies or substantial portions of the Software.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS\r
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL\r
23  * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
24  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
26  */\r
27 \r
28 #define FREEGLUT_BUILDING_LIB\r
29 #include <GL/freeglut.h>\r
30 #include "freeglut_internal.h"\r
31 \r
32 #if TARGET_HOST_POSIX_X11\r
33 #include <limits.h>  /* LONG_MAX */\r
34 #endif\r
35 \r
36 /*\r
37  * TODO BEFORE THE STABLE RELEASE:\r
38  *\r
39  *  fgDeinitialize()        -- Win32's OK, X11 needs the OS-specific\r
40  *                             deinitialization done\r
41  *  glutInitDisplayString() -- display mode string parsing\r
42  *\r
43  * Wouldn't it be cool to use gettext() for error messages? I just love\r
44  * bash saying  "nie znaleziono pliku" instead of "file not found" :)\r
45  * Is gettext easily portable?\r
46  */\r
47 \r
48 /* -- GLOBAL VARIABLES ----------------------------------------------------- */\r
49 \r
50 /*\r
51  * A structure pointed by g_pDisplay holds all information\r
52  * regarding the display, screen, root window etc.\r
53  */\r
54 SFG_Display fgDisplay;\r
55 \r
56 /*\r
57  * The settings for the current freeglut session\r
58  */\r
59 SFG_State fgState = { { -1, -1, GL_FALSE },  /* Position */\r
60                       { 300, 300, GL_TRUE }, /* Size */\r
61                       GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH,  /* DisplayMode */\r
62                       GL_FALSE,              /* Initialised */\r
63                       GLUT_TRY_DIRECT_CONTEXT,  /* DirectContext */\r
64                       GL_FALSE,              /* ForceIconic */\r
65                       GL_FALSE,              /* UseCurrentContext */\r
66                       GL_FALSE,              /* GLDebugSwitch */\r
67                       GL_FALSE,              /* XSyncSwitch */\r
68                       GLUT_KEY_REPEAT_ON,    /* KeyRepeat */\r
69                       INVALID_MODIFIERS,     /* Modifiers */\r
70                       0,                     /* FPSInterval */\r
71                       0,                     /* SwapCount */\r
72                       0,                     /* SwapTime */\r
73                       0,                     /* Time */\r
74                       { NULL, NULL },         /* Timers */\r
75                       { NULL, NULL },         /* FreeTimers */\r
76                       NULL,                   /* IdleCallback */\r
77                       0,                      /* ActiveMenus */\r
78                       NULL,                   /* MenuStateCallback */\r
79                       NULL,                   /* MenuStatusCallback */\r
80                       { 640, 480, GL_TRUE },  /* GameModeSize */\r
81                       16,                     /* GameModeDepth */\r
82                       72,                     /* GameModeRefresh */\r
83                       GLUT_ACTION_EXIT,       /* ActionOnWindowClose */\r
84                       GLUT_EXEC_STATE_INIT,   /* ExecState */\r
85                       NULL,                   /* ProgramName */\r
86                       GL_FALSE,               /* JoysticksInitialised */\r
87                       0,                      /* NumActiveJoysticks */\r
88                       GL_FALSE,               /* InputDevsInitialised */\r
89                       0,                      /* MouseWheelTicks */\r
90                       1,                      /* AuxiliaryBufferNumber */\r
91                       4,                      /* SampleNumber */\r
92                       1,                      /* MajorVersion */\r
93                       0,                      /* MinorVersion */\r
94                       0,                      /* ContextFlags */\r
95                       0,                      /* ContextProfile */\r
96                       NULL,                   /* ErrorFunc */\r
97                       NULL                    /* WarningFunc */\r
98 };\r
99 \r
100 \r
101 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */\r
102 \r
103 extern void fgPlatformInitialize( const char* displayName );\r
104 extern void fgPlatformDeinitialiseInputDevices ( void );\r
105 extern void fgPlatformCloseDisplay ( void );\r
106 \r
107 #if TARGET_HOST_POSIX_X11\r
108 \r
109 /* Return the atom associated with "name". */\r
110 static Atom fghGetAtom(const char * name)\r
111 {\r
112   return XInternAtom(fgDisplay.Display, name, False);\r
113 }\r
114 \r
115 /*\r
116  * Check if "property" is set on "window".  The property's values are returned\r
117  * through "data".  If the property is set and is of type "type", return the\r
118  * number of elements in "data".  Return zero otherwise.  In both cases, use\r
119  * "Xfree()" to free "data".\r
120  */\r
121 static int fghGetWindowProperty(Window window,\r
122                                 Atom property,\r
123                                 Atom type,\r
124                                 unsigned char ** data)\r
125 {\r
126   /*\r
127    * Caller always has to use "Xfree()" to free "data", since\r
128    * "XGetWindowProperty() always allocates one extra byte in prop_return\r
129    * [i.e. "data"] (even if the property is zero length) [..]".\r
130    */\r
131 \r
132   int status;  /*  Returned by "XGetWindowProperty". */\r
133 \r
134   Atom          type_returned;\r
135   int           temp_format;             /*  Not used. */\r
136   unsigned long number_of_elements;\r
137   unsigned long temp_bytes_after;        /*  Not used. */\r
138 \r
139 \r
140   status = XGetWindowProperty(fgDisplay.Display,\r
141                               window,\r
142                               property,\r
143                               0,\r
144                               LONG_MAX,\r
145                               False,\r
146                               type,\r
147                               &type_returned,\r
148                               &temp_format,\r
149                               &number_of_elements,\r
150                               &temp_bytes_after,\r
151                               data);\r
152 \r
153   FREEGLUT_INTERNAL_ERROR_EXIT(status == Success,\r
154                                "XGetWindowProperty failled",\r
155                                "fghGetWindowProperty");\r
156 \r
157   if (type_returned != type)\r
158     {\r
159       number_of_elements = 0;\r
160     }\r
161 \r
162   return number_of_elements;\r
163 }\r
164 \r
165 /*  Check if the window manager is NET WM compliant. */\r
166 static int fghNetWMSupported(void)\r
167 {\r
168   Atom wm_check;\r
169   Window ** window_ptr_1;\r
170 \r
171   int number_of_windows;\r
172   int net_wm_supported;\r
173 \r
174 \r
175   net_wm_supported = 0;\r
176 \r
177   wm_check = fghGetAtom("_NET_SUPPORTING_WM_CHECK");\r
178   window_ptr_1 = malloc(sizeof(Window *));\r
179 \r
180   /*\r
181    * Check that the window manager has set this property on the root window.\r
182    * The property must be the ID of a child window.\r
183    */\r
184   number_of_windows = fghGetWindowProperty(fgDisplay.RootWindow,\r
185                                            wm_check,\r
186                                            XA_WINDOW,\r
187                                            (unsigned char **) window_ptr_1);\r
188   if (number_of_windows == 1)\r
189     {\r
190       Window ** window_ptr_2;\r
191 \r
192       window_ptr_2 = malloc(sizeof(Window *));\r
193 \r
194       /* Check that the window has the same property set to the same value. */\r
195       number_of_windows = fghGetWindowProperty(**window_ptr_1,\r
196                                                wm_check,\r
197                                                XA_WINDOW,\r
198                                                (unsigned char **) window_ptr_2);\r
199       if ((number_of_windows == 1) && (**window_ptr_1 == **window_ptr_2))\r
200       {\r
201         /* NET WM compliant */\r
202         net_wm_supported = 1;\r
203       }\r
204 \r
205       XFree(*window_ptr_2);\r
206       free(window_ptr_2);\r
207     }\r
208 \r
209         XFree(*window_ptr_1);\r
210         free(window_ptr_1);\r
211 \r
212         return net_wm_supported;\r
213 }\r
214 \r
215 /*  Check if "hint" is present in "property" for "window". */\r
216 int fgHintPresent(Window window, Atom property, Atom hint)\r
217 {\r
218   Atom *atoms;\r
219   int number_of_atoms;\r
220   int supported;\r
221   int i;\r
222 \r
223   supported = 0;\r
224 \r
225   number_of_atoms = fghGetWindowProperty(window,\r
226                                          property,\r
227                                          XA_ATOM,\r
228                                          (unsigned char **) &atoms);\r
229   for (i = 0; i < number_of_atoms; i++)\r
230   {\r
231       if (atoms[i] == hint)\r
232       {\r
233           supported = 1;\r
234           break;\r
235       }\r
236   }\r
237 \r
238   XFree(atoms);\r
239   return supported;\r
240 }\r
241 \r
242 #endif /*  TARGET_HOST_POSIX_X11  */\r
243 \r
244 \r
245 #if TARGET_HOST_POSIX_X11\r
246 /*\r
247  * A call to this function should initialize all the display stuff...\r
248  */\r
249 static void fgPlatformInitialize( const char* displayName )\r
250 {\r
251     fgDisplay.Display = XOpenDisplay( displayName );\r
252 \r
253     if( fgDisplay.Display == NULL )\r
254         fgError( "failed to open display '%s'", XDisplayName( displayName ) );\r
255 \r
256     if( !glXQueryExtension( fgDisplay.Display, NULL, NULL ) )\r
257         fgError( "OpenGL GLX extension not supported by display '%s'",\r
258             XDisplayName( displayName ) );\r
259 \r
260     fgDisplay.Screen = DefaultScreen( fgDisplay.Display );\r
261     fgDisplay.RootWindow = RootWindow(\r
262         fgDisplay.Display,\r
263         fgDisplay.Screen\r
264     );\r
265 \r
266     fgDisplay.ScreenWidth  = DisplayWidth(\r
267         fgDisplay.Display,\r
268         fgDisplay.Screen\r
269     );\r
270     fgDisplay.ScreenHeight = DisplayHeight(\r
271         fgDisplay.Display,\r
272         fgDisplay.Screen\r
273     );\r
274 \r
275     fgDisplay.ScreenWidthMM = DisplayWidthMM(\r
276         fgDisplay.Display,\r
277         fgDisplay.Screen\r
278     );\r
279     fgDisplay.ScreenHeightMM = DisplayHeightMM(\r
280         fgDisplay.Display,\r
281         fgDisplay.Screen\r
282     );\r
283 \r
284     fgDisplay.Connection = ConnectionNumber( fgDisplay.Display );\r
285 \r
286     /* Create the window deletion atom */\r
287     fgDisplay.DeleteWindow = fghGetAtom("WM_DELETE_WINDOW");\r
288 \r
289     /* Create the state and full screen atoms */\r
290     fgDisplay.State           = None;\r
291     fgDisplay.StateFullScreen = None;\r
292 \r
293     if (fghNetWMSupported())\r
294     {\r
295       const Atom supported = fghGetAtom("_NET_SUPPORTED");\r
296       const Atom state     = fghGetAtom("_NET_WM_STATE");\r
297       \r
298       /* Check if the state hint is supported. */\r
299       if (fgHintPresent(fgDisplay.RootWindow, supported, state))\r
300       {\r
301         const Atom full_screen = fghGetAtom("_NET_WM_STATE_FULLSCREEN");\r
302         \r
303         fgDisplay.State = state;\r
304         \r
305         /* Check if the window manager supports full screen. */\r
306         /**  Check "_NET_WM_ALLOWED_ACTIONS" on our window instead? **/\r
307         if (fgHintPresent(fgDisplay.RootWindow, supported, full_screen))\r
308         {\r
309           fgDisplay.StateFullScreen = full_screen;\r
310         }\r
311       }\r
312     }\r
313 \r
314 \r
315     fgState.Initialised = GL_TRUE;\r
316 \r
317     atexit(fgDeinitialize);\r
318 \r
319     /* InputDevice uses GlutTimerFunc(), so fgState.Initialised must be TRUE */\r
320     fgInitialiseInputDevices();\r
321 }\r
322 \r
323 #endif\r
324 \r
325 \r
326 void fghParseCommandLineArguments ( int* pargc, char** argv, char **pDisplayName, char **pGeometry )\r
327 {\r
328 #ifndef _WIN32_WCE\r
329     int i, j, argc = *pargc;\r
330 \r
331     {\r
332             /* check if GLUT_FPS env var is set */\r
333         const char *fps = getenv( "GLUT_FPS" );\r
334 \r
335         if( fps )\r
336         {\r
337             int interval;\r
338             sscanf( fps, "%d", &interval );\r
339 \r
340             if( interval <= 0 )\r
341                 fgState.FPSInterval = 5000;  /* 5000 millisecond default */\r
342             else\r
343                 fgState.FPSInterval = interval;\r
344         }\r
345     }\r
346 \r
347     *pDisplayName = getenv( "DISPLAY" );\r
348 \r
349     for( i = 1; i < argc; i++ )\r
350     {\r
351         if( strcmp( argv[ i ], "-display" ) == 0 )\r
352         {\r
353             if( ++i >= argc )\r
354                 fgError( "-display parameter must be followed by display name" );\r
355 \r
356             *pDisplayName = argv[ i ];\r
357 \r
358             argv[ i - 1 ] = NULL;\r
359             argv[ i     ] = NULL;\r
360             ( *pargc ) -= 2;\r
361         }\r
362         else if( strcmp( argv[ i ], "-geometry" ) == 0 )\r
363         {\r
364             if( ++i >= argc )\r
365                 fgError( "-geometry parameter must be followed by window "\r
366                          "geometry settings" );\r
367 \r
368             *pGeometry = argv[ i ];\r
369 \r
370             argv[ i - 1 ] = NULL;\r
371             argv[ i     ] = NULL;\r
372             ( *pargc ) -= 2;\r
373         }\r
374         else if( strcmp( argv[ i ], "-direct" ) == 0)\r
375         {\r
376             if( fgState.DirectContext == GLUT_FORCE_INDIRECT_CONTEXT )\r
377                 fgError( "parameters ambiguity, -direct and -indirect "\r
378                     "cannot be both specified" );\r
379 \r
380             fgState.DirectContext = GLUT_FORCE_DIRECT_CONTEXT;\r
381             argv[ i ] = NULL;\r
382             ( *pargc )--;\r
383         }\r
384         else if( strcmp( argv[ i ], "-indirect" ) == 0 )\r
385         {\r
386             if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )\r
387                 fgError( "parameters ambiguity, -direct and -indirect "\r
388                     "cannot be both specified" );\r
389 \r
390             fgState.DirectContext = GLUT_FORCE_INDIRECT_CONTEXT;\r
391             argv[ i ] = NULL;\r
392             (*pargc)--;\r
393         }\r
394         else if( strcmp( argv[ i ], "-iconic" ) == 0 )\r
395         {\r
396             fgState.ForceIconic = GL_TRUE;\r
397             argv[ i ] = NULL;\r
398             ( *pargc )--;\r
399         }\r
400         else if( strcmp( argv[ i ], "-gldebug" ) == 0 )\r
401         {\r
402             fgState.GLDebugSwitch = GL_TRUE;\r
403             argv[ i ] = NULL;\r
404             ( *pargc )--;\r
405         }\r
406         else if( strcmp( argv[ i ], "-sync" ) == 0 )\r
407         {\r
408             fgState.XSyncSwitch = GL_TRUE;\r
409             argv[ i ] = NULL;\r
410             ( *pargc )--;\r
411         }\r
412     }\r
413 \r
414     /* Compact {argv}. */\r
415     for( i = j = 1; i < *pargc; i++, j++ )\r
416     {\r
417         /* Guaranteed to end because there are "*pargc" arguments left */\r
418         while ( argv[ j ] == NULL )\r
419             j++;\r
420         if ( i != j )\r
421             argv[ i ] = argv[ j ];\r
422     }\r
423 \r
424 #endif /* _WIN32_WCE */\r
425 \r
426 }\r
427 \r
428 \r
429 void fghCloseInputDevices ( void )\r
430 {\r
431     if ( fgState.JoysticksInitialised )\r
432         fgJoystickClose( );\r
433 \r
434     if ( fgState.InputDevsInitialised )\r
435         fgInputDeviceClose( );\r
436 }\r
437 \r
438 \r
439 #if TARGET_HOST_POSIX_X11\r
440 static void fgPlatformDeinitialiseInputDevices ( void )\r
441 {\r
442         fghCloseInputDevices ();\r
443 \r
444     fgState.JoysticksInitialised = GL_FALSE;\r
445     fgState.InputDevsInitialised = GL_FALSE;\r
446 }\r
447 \r
448 \r
449 static void fgPlatformCloseDisplay ( void )\r
450 {\r
451     /*\r
452      * Make sure all X-client data we have created will be destroyed on\r
453      * display closing\r
454      */\r
455     XSetCloseDownMode( fgDisplay.Display, DestroyAll );\r
456 \r
457     /*\r
458      * Close the display connection, destroying all windows we have\r
459      * created so far\r
460      */\r
461     XCloseDisplay( fgDisplay.Display );\r
462 }\r
463 \r
464 #endif\r
465 \r
466 \r
467 /*\r
468  * Perform the freeglut deinitialization...\r
469  */\r
470 void fgDeinitialize( void )\r
471 {\r
472     SFG_Timer *timer;\r
473 \r
474     if( !fgState.Initialised )\r
475     {\r
476         return;\r
477     }\r
478 \r
479         /* If we're in game mode, we want to leave game mode */\r
480     if( fgStructure.GameModeWindow ) {\r
481         glutLeaveGameMode();\r
482     }\r
483 \r
484     /* If there was a menu created, destroy the rendering context */\r
485     if( fgStructure.MenuContext )\r
486     {\r
487 #if TARGET_HOST_POSIX_X11\r
488         /* Note that the MVisualInfo is not owned by the MenuContext! */\r
489         glXDestroyContext( fgDisplay.Display, fgStructure.MenuContext->MContext );\r
490 #endif\r
491         free( fgStructure.MenuContext );\r
492         fgStructure.MenuContext = NULL;\r
493     }\r
494 \r
495     fgDestroyStructure( );\r
496 \r
497     while( ( timer = fgState.Timers.First) )\r
498     {\r
499         fgListRemove( &fgState.Timers, &timer->Node );\r
500         free( timer );\r
501     }\r
502 \r
503     while( ( timer = fgState.FreeTimers.First) )\r
504     {\r
505         fgListRemove( &fgState.FreeTimers, &timer->Node );\r
506         free( timer );\r
507     }\r
508 \r
509         fgPlatformDeinitialiseInputDevices ();\r
510 \r
511         fgState.MouseWheelTicks = 0;\r
512 \r
513     fgState.MajorVersion = 1;\r
514     fgState.MinorVersion = 0;\r
515     fgState.ContextFlags = 0;\r
516     fgState.ContextProfile = 0;\r
517 \r
518     fgState.Initialised = GL_FALSE;\r
519 \r
520     fgState.Position.X = -1;\r
521     fgState.Position.Y = -1;\r
522     fgState.Position.Use = GL_FALSE;\r
523 \r
524     fgState.Size.X = 300;\r
525     fgState.Size.Y = 300;\r
526     fgState.Size.Use = GL_TRUE;\r
527 \r
528     fgState.DisplayMode = GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH;\r
529 \r
530     fgState.DirectContext  = GLUT_TRY_DIRECT_CONTEXT;\r
531     fgState.ForceIconic         = GL_FALSE;\r
532     fgState.UseCurrentContext   = GL_FALSE;\r
533     fgState.GLDebugSwitch       = GL_FALSE;\r
534     fgState.XSyncSwitch         = GL_FALSE;\r
535     fgState.ActionOnWindowClose = GLUT_ACTION_EXIT;\r
536     fgState.ExecState           = GLUT_EXEC_STATE_INIT;\r
537 \r
538     fgState.KeyRepeat       = GLUT_KEY_REPEAT_ON;\r
539     fgState.Modifiers       = INVALID_MODIFIERS;\r
540 \r
541     fgState.GameModeSize.X  = 640;\r
542     fgState.GameModeSize.Y  = 480;\r
543     fgState.GameModeDepth   =  16;\r
544     fgState.GameModeRefresh =  72;\r
545 \r
546     fgListInit( &fgState.Timers );\r
547     fgListInit( &fgState.FreeTimers );\r
548 \r
549     fgState.IdleCallback = NULL;\r
550     fgState.MenuStateCallback = ( FGCBMenuState )NULL;\r
551     fgState.MenuStatusCallback = ( FGCBMenuStatus )NULL;\r
552 \r
553     fgState.SwapCount   = 0;\r
554     fgState.SwapTime    = 0;\r
555     fgState.FPSInterval = 0;\r
556 \r
557     if( fgState.ProgramName )\r
558     {\r
559         free( fgState.ProgramName );\r
560         fgState.ProgramName = NULL;\r
561     }\r
562 \r
563         fgPlatformCloseDisplay ();\r
564 \r
565     fgState.Initialised = GL_FALSE;\r
566 }\r
567 \r
568 \r
569 #if TARGET_HOST_MS_WINDOWS\r
570 #define NoValue         0x0000\r
571 #define XValue          0x0001\r
572 #define YValue          0x0002\r
573 #define WidthValue      0x0004\r
574 #define HeightValue     0x0008\r
575 #define AllValues       0x000F\r
576 #define XNegative       0x0010\r
577 #define YNegative       0x0020\r
578 \r
579 extern int XParseGeometry (\r
580     const char *string,\r
581     int *x,\r
582     int *y,\r
583     unsigned int *width,    /* RETURN */\r
584     unsigned int *height);    /* RETURN */\r
585 #endif\r
586 \r
587 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */\r
588 \r
589 /*\r
590  * Perform initialization. This usually happens on the program startup\r
591  * and restarting after glutMainLoop termination...\r
592  */\r
593 void FGAPIENTRY glutInit( int* pargc, char** argv )\r
594 {\r
595     char* displayName = NULL;\r
596     char* geometry = NULL;\r
597     if( fgState.Initialised )\r
598         fgError( "illegal glutInit() reinitialization attempt" );\r
599 \r
600     if (pargc && *pargc && argv && *argv && **argv)\r
601     {\r
602         fgState.ProgramName = strdup (*argv);\r
603 \r
604         if( !fgState.ProgramName )\r
605             fgError ("Could not allocate space for the program's name.");\r
606     }\r
607 \r
608     fgCreateStructure( );\r
609 \r
610     /* Get start time */\r
611     fgState.Time = fgSystemTime();\r
612 \r
613         fghParseCommandLineArguments ( pargc, argv, &displayName, &geometry );\r
614 \r
615     /*\r
616      * Have the display created now. If there wasn't a "-display"\r
617      * in the program arguments, we will use the DISPLAY environment\r
618      * variable for opening the X display (see code above):\r
619      */\r
620     fgPlatformInitialize( displayName );\r
621 \r
622     /*\r
623      * Geometry parsing deffered until here because we may need the screen\r
624      * size.\r
625      */\r
626 \r
627     if (geometry )\r
628     {\r
629         unsigned int parsedWidth, parsedHeight;\r
630         int mask = XParseGeometry( geometry,\r
631                                    &fgState.Position.X, &fgState.Position.Y,\r
632                                    &parsedWidth, &parsedHeight );\r
633         /* TODO: Check for overflow? */\r
634         fgState.Size.X = parsedWidth;\r
635         fgState.Size.Y = parsedHeight;\r
636 \r
637         if( (mask & (WidthValue|HeightValue)) == (WidthValue|HeightValue) )\r
638             fgState.Size.Use = GL_TRUE;\r
639 \r
640         if( mask & XNegative )\r
641             fgState.Position.X += fgDisplay.ScreenWidth - fgState.Size.X;\r
642 \r
643         if( mask & YNegative )\r
644             fgState.Position.Y += fgDisplay.ScreenHeight - fgState.Size.Y;\r
645 \r
646         if( (mask & (XValue|YValue)) == (XValue|YValue) )\r
647             fgState.Position.Use = GL_TRUE;\r
648     }\r
649 }\r
650 \r
651 #if TARGET_HOST_MS_WINDOWS\r
652 void (__cdecl *__glutExitFunc)( int return_value ) = NULL;\r
653 \r
654 void FGAPIENTRY __glutInitWithExit( int *pargc, char **argv, void (__cdecl *exit_function)(int) )\r
655 {\r
656   __glutExitFunc = exit_function;\r
657   glutInit(pargc, argv);\r
658 }\r
659 #endif\r
660 \r
661 /*\r
662  * Undoes all the "glutInit" stuff\r
663  */\r
664 void FGAPIENTRY glutExit ( void )\r
665 {\r
666   fgDeinitialize ();\r
667 }\r
668 \r
669 /*\r
670  * Sets the default initial window position for new windows\r
671  */\r
672 void FGAPIENTRY glutInitWindowPosition( int x, int y )\r
673 {\r
674     fgState.Position.X = x;\r
675     fgState.Position.Y = y;\r
676 \r
677     if( ( x >= 0 ) && ( y >= 0 ) )\r
678         fgState.Position.Use = GL_TRUE;\r
679     else\r
680         fgState.Position.Use = GL_FALSE;\r
681 }\r
682 \r
683 /*\r
684  * Sets the default initial window size for new windows\r
685  */\r
686 void FGAPIENTRY glutInitWindowSize( int width, int height )\r
687 {\r
688     fgState.Size.X = width;\r
689     fgState.Size.Y = height;\r
690 \r
691     if( ( width > 0 ) && ( height > 0 ) )\r
692         fgState.Size.Use = GL_TRUE;\r
693     else\r
694         fgState.Size.Use = GL_FALSE;\r
695 }\r
696 \r
697 /*\r
698  * Sets the default display mode for all new windows\r
699  */\r
700 void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode )\r
701 {\r
702     /* We will make use of this value when creating a new OpenGL context... */\r
703     fgState.DisplayMode = displayMode;\r
704 }\r
705 \r
706 \r
707 /* -- INIT DISPLAY STRING PARSING ------------------------------------------ */\r
708 \r
709 static char* Tokens[] =\r
710 {\r
711     "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double",\r
712     "green", "index", "num", "red", "rgba", "rgb", "luminance", "stencil",\r
713     "single", "stereo", "samples", "slow", "win32pdf", "win32pfd", "xvisual",\r
714     "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",\r
715     "xtruecolor", "xdirectcolor",\r
716     "xstaticgrey", "xgreyscale", "xstaticcolour", "xpseudocolour",\r
717     "xtruecolour", "xdirectcolour", "borderless", "aux"\r
718 };\r
719 #define NUM_TOKENS             (sizeof(Tokens) / sizeof(*Tokens))\r
720 \r
721 void FGAPIENTRY glutInitDisplayString( const char* displayMode )\r
722 {\r
723     int glut_state_flag = 0 ;\r
724     /*\r
725      * Unpack a lot of options from a character string.  The options are\r
726      * delimited by blanks or tabs.\r
727      */\r
728     char *token ;\r
729     size_t len = strlen ( displayMode );\r
730     char *buffer = (char *)malloc ( (len+1) * sizeof(char) );\r
731     memcpy ( buffer, displayMode, len );\r
732     buffer[len] = '\0';\r
733 \r
734     token = strtok ( buffer, " \t" );\r
735 \r
736     while ( token )\r
737     {\r
738         /* Process this token */\r
739         int i ;\r
740 \r
741         /* Temporary fix:  Ignore any length specifications and at least\r
742          * process the basic token\r
743          * TODO:  Fix this permanently\r
744          */\r
745         size_t cleanlength = strcspn ( token, "=<>~!" );\r
746 \r
747         for ( i = 0; i < NUM_TOKENS; i++ )\r
748         {\r
749             if ( strncmp ( token, Tokens[i], cleanlength ) == 0 ) break ;\r
750         }\r
751 \r
752         switch ( i )\r
753         {\r
754         case 0 :  /* "alpha":  Alpha color buffer precision in bits */\r
755             glut_state_flag |= GLUT_ALPHA ;  /* Somebody fix this for me! */\r
756             break ;\r
757 \r
758         case 1 :  /* "acca":  Red, green, blue, and alpha accumulation buffer\r
759                      precision in bits */\r
760             break ;\r
761 \r
762         case 2 :  /* "acc":  Red, green, and blue accumulation buffer precision\r
763                      in bits with zero bits alpha */\r
764             glut_state_flag |= GLUT_ACCUM ;  /* Somebody fix this for me! */\r
765             break ;\r
766 \r
767         case 3 :  /* "blue":  Blue color buffer precision in bits */\r
768             break ;\r
769 \r
770         case 4 :  /* "buffer":  Number of bits in the color index color buffer\r
771                    */\r
772             break ;\r
773 \r
774         case 5 :  /* "conformant":  Boolean indicating if the frame buffer\r
775                      configuration is conformant or not */\r
776             break ;\r
777 \r
778         case 6 : /* "depth":  Number of bits of precsion in the depth buffer */\r
779             glut_state_flag |= GLUT_DEPTH ;  /* Somebody fix this for me! */\r
780             break ;\r
781 \r
782         case 7 :  /* "double":  Boolean indicating if the color buffer is\r
783                      double buffered */\r
784             glut_state_flag |= GLUT_DOUBLE ;\r
785             break ;\r
786 \r
787         case 8 :  /* "green":  Green color buffer precision in bits */\r
788             break ;\r
789 \r
790         case 9 :  /* "index":  Boolean if the color model is color index or not\r
791                    */\r
792             glut_state_flag |= GLUT_INDEX ;\r
793             break ;\r
794 \r
795         case 10 :  /* "num":  A special capability  name indicating where the\r
796                       value represents the Nth frame buffer configuration\r
797                       matching the description string */\r
798             break ;\r
799 \r
800         case 11 :  /* "red":  Red color buffer precision in bits */\r
801             break ;\r
802 \r
803         case 12 :  /* "rgba":  Number of bits of red, green, blue, and alpha in\r
804                       the RGBA color buffer */\r
805             glut_state_flag |= GLUT_RGBA ;  /* Somebody fix this for me! */\r
806             break ;\r
807 \r
808         case 13 :  /* "rgb":  Number of bits of red, green, and blue in the\r
809                       RGBA color buffer with zero bits alpha */\r
810             glut_state_flag |= GLUT_RGB ;  /* Somebody fix this for me! */\r
811             break ;\r
812 \r
813         case 14 :  /* "luminance":  Number of bits of red in the RGBA and zero\r
814                       bits of green, blue (alpha not specified) of color buffer\r
815                       precision */\r
816             glut_state_flag |= GLUT_LUMINANCE ; /* Somebody fix this for me! */\r
817             break ;\r
818 \r
819         case 15 :  /* "stencil":  Number of bits in the stencil buffer */\r
820             glut_state_flag |= GLUT_STENCIL;  /* Somebody fix this for me! */\r
821             break ;\r
822 \r
823         case 16 :  /* "single":  Boolean indicate the color buffer is single\r
824                       buffered */\r
825             glut_state_flag |= GLUT_SINGLE ;\r
826             break ;\r
827 \r
828         case 17 :  /* "stereo":  Boolean indicating the color buffer supports\r
829                       OpenGL-style stereo */\r
830             glut_state_flag |= GLUT_STEREO ;\r
831             break ;\r
832 \r
833         case 18 :  /* "samples":  Indicates the number of multisamples to use\r
834                       based on GLX's SGIS_multisample extension (for\r
835                       antialiasing) */\r
836             glut_state_flag |= GLUT_MULTISAMPLE ; /*Somebody fix this for me!*/\r
837             break ;\r
838 \r
839         case 19 :  /* "slow":  Boolean indicating if the frame buffer\r
840                       configuration is slow or not */\r
841             break ;\r
842 \r
843         case 20 :  /* "win32pdf": (incorrect spelling but was there before */\r
844         case 21 :  /* "win32pfd":  matches the Win32 Pixel Format Descriptor by\r
845                       number */\r
846 #if TARGET_HOST_MS_WINDOWS\r
847 #endif\r
848             break ;\r
849 \r
850         case 22 :  /* "xvisual":  matches the X visual ID by number */\r
851 #if TARGET_HOST_POSIX_X11\r
852 #endif\r
853             break ;\r
854 \r
855         case 23 :  /* "xstaticgray": */\r
856         case 29 :  /* "xstaticgrey":  boolean indicating if the frame buffer\r
857                       configuration's X visual is of type StaticGray */\r
858 #if TARGET_HOST_POSIX_X11\r
859 #endif\r
860             break ;\r
861 \r
862         case 24 :  /* "xgrayscale": */\r
863         case 30 :  /* "xgreyscale":  boolean indicating if the frame buffer\r
864                       configuration's X visual is of type GrayScale */\r
865 #if TARGET_HOST_POSIX_X11\r
866 #endif\r
867             break ;\r
868 \r
869         case 25 :  /* "xstaticcolor": */\r
870         case 31 :  /* "xstaticcolour":  boolean indicating if the frame buffer\r
871                       configuration's X visual is of type StaticColor */\r
872 #if TARGET_HOST_POSIX_X11\r
873 #endif\r
874             break ;\r
875 \r
876         case 26 :  /* "xpseudocolor": */\r
877         case 32 :  /* "xpseudocolour":  boolean indicating if the frame buffer\r
878                       configuration's X visual is of type PseudoColor */\r
879 #if TARGET_HOST_POSIX_X11\r
880 #endif\r
881             break ;\r
882 \r
883         case 27 :  /* "xtruecolor": */\r
884         case 33 :  /* "xtruecolour":  boolean indicating if the frame buffer\r
885                       configuration's X visual is of type TrueColor */\r
886 #if TARGET_HOST_POSIX_X11\r
887 #endif\r
888             break ;\r
889 \r
890         case 28 :  /* "xdirectcolor": */\r
891         case 34 :  /* "xdirectcolour":  boolean indicating if the frame buffer\r
892                       configuration's X visual is of type DirectColor */\r
893 #if TARGET_HOST_POSIX_X11\r
894 #endif\r
895             break ;\r
896 \r
897         case 35 :  /* "borderless":  windows should not have borders */\r
898 #if TARGET_HOST_POSIX_X11\r
899 #endif\r
900             break ;\r
901 \r
902         case 36 :  /* "aux":  some number of aux buffers */\r
903             glut_state_flag |= GLUT_AUX;\r
904             break ;\r
905 \r
906         case 37 :  /* Unrecognized */\r
907             fgWarning ( "WARNING - Display string token not recognized:  %s",\r
908                         token );\r
909             break ;\r
910         }\r
911 \r
912         token = strtok ( NULL, " \t" );\r
913     }\r
914 \r
915     free ( buffer );\r
916 \r
917     /* We will make use of this value when creating a new OpenGL context... */\r
918     fgState.DisplayMode = glut_state_flag;\r
919 }\r
920 \r
921 /* -- SETTING OPENGL 3.0 CONTEXT CREATION PARAMETERS ---------------------- */\r
922 \r
923 void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion )\r
924 {\r
925     /* We will make use of these valuse when creating a new OpenGL context... */\r
926     fgState.MajorVersion = majorVersion;\r
927     fgState.MinorVersion = minorVersion;\r
928 }\r
929 \r
930 \r
931 void FGAPIENTRY glutInitContextFlags( int flags )\r
932 {\r
933     /* We will make use of this value when creating a new OpenGL context... */\r
934     fgState.ContextFlags = flags;\r
935 }\r
936 \r
937 void FGAPIENTRY glutInitContextProfile( int profile )\r
938 {\r
939     /* We will make use of this value when creating a new OpenGL context... */\r
940     fgState.ContextProfile = profile;\r
941 }\r
942 \r
943 /* -------------- User Defined Error/Warning Handler Support -------------- */\r
944 \r
945 /*\r
946  * Sets the user error handler (note the use of va_list for the args to the fmt)\r
947  */\r
948 void FGAPIENTRY glutInitErrorFunc( void (* vfgError) ( const char *fmt, va_list ap ) )\r
949 {\r
950     /* This allows user programs to handle freeglut errors */\r
951     fgState.ErrorFunc = vfgError;\r
952 }\r
953 \r
954 /*\r
955  * Sets the user warning handler (note the use of va_list for the args to the fmt)\r
956  */\r
957 void FGAPIENTRY glutInitWarningFunc( void (* vfgWarning) ( const char *fmt, va_list ap ) )\r
958 {\r
959     /* This allows user programs to handle freeglut warnings */\r
960     fgState.WarningFunc = vfgWarning;\r
961 }\r
962 \r
963 /*** END OF FILE ***/\r