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