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