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