Fix for the font binary compatibility problem.
[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 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #define G_LOG_DOMAIN "freeglut-init"
33
34 #include "../include/GL/freeglut.h"
35 #include "freeglut_internal.h"
36
37 /*
38  * TODO BEFORE THE STABLE RELEASE:
39  *
40  *  fgDeinitialize()        -- Win32's OK, X11 needs the OS-specific deinitialization done
41  *  glutInitDisplayString() -- display mode string parsing
42  *
43  * Wouldn't it be cool to use gettext() for error messages? I just love bash saying 
44  * "nie znaleziono pliku" instead of "file not found" :) Is gettext easily portable?
45  */
46
47 /* -- GLOBAL VARIABLES ----------------------------------------------------- */
48
49 /*
50  * A structure pointed by g_pDisplay holds all information
51  * regarding the display, screen, root window etc.
52  */
53 SFG_Display fgDisplay;
54
55 /*
56  * The settings for the current freeglut session
57  */
58 SFG_State fgState = { { -1, -1, FALSE },  /* Position */
59                       { 300, 300, TRUE }, /* Size */
60                       GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH,  /* DisplayMode */
61                       FALSE, /* ForceDirectContext */
62                       TRUE,  /* TryDirectContext */
63                       FALSE, /* ForceIconic */
64                       FALSE, /* UseCurrentContext */
65                       FALSE, /* GLDebugSwitch */
66                       FALSE, /* XSyncSwitch */
67                       TRUE,  /* IgnoreKeyRepeat */
68                       0,     /* FPSInterval */
69                       0,     /* SwapCount */
70                       0,     /* SwapTime */
71 #ifdef TARGET_HOST_WIN32
72                       { 0, FALSE }, /* Time */
73 #else
74                       { { 0, 0 }, FALSE },
75 #endif
76                       { NULL, NULL }, /* Timers */
77                       NULL, /* IdleCallback */
78                       NULL, /* MenuStateCallback */
79                       NULL, /* MenuStatusCallback */
80                       { 640, 480, TRUE }, /* GameModeSize */
81                       16,  /* GameModeDepth */
82                       72,  /* GameModeRefresh */
83                       GLUT_ACTION_EXIT, /* ActionOnWindowClose */
84                       GLUT_EXEC_STATE_INIT /* ExecState */
85 } ;
86
87
88 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
89
90 /*
91  * A call to this function should initialize all the display stuff...
92  */
93 void fgInitialize( const char* displayName )
94 {
95 #if TARGET_HOST_UNIX_X11
96     /*
97      * Have the display created
98      */
99     fgDisplay.Display = XOpenDisplay( displayName );
100
101     if( fgDisplay.Display == NULL )
102     {
103         /*
104          * Failed to open a display. That's no good.
105          */
106         fgError( "failed to open display '%s'", XDisplayName( displayName ) );
107     }
108
109     /*
110      * Check for the OpenGL GLX extension availability:
111      */
112     if( !glXQueryExtension( fgDisplay.Display, NULL, NULL ) )
113     {
114         /*
115          * GLX extensions have not been found...
116          */
117         fgError( "OpenGL GLX extension not supported by display '%s'", XDisplayName( displayName ) );
118     }
119
120     /*
121      * Grab the default screen for the display we have just opened
122      */
123     fgDisplay.Screen = DefaultScreen( fgDisplay.Display );
124
125     /*
126      * The same applying to the root window
127      */
128     fgDisplay.RootWindow = RootWindow(
129         fgDisplay.Display,
130         fgDisplay.Screen
131     );
132
133     /*
134      * Grab the logical screen's geometry
135      */
136     fgDisplay.ScreenWidth  = DisplayWidth(
137         fgDisplay.Display,
138         fgDisplay.Screen
139     );
140
141     fgDisplay.ScreenHeight = DisplayHeight(
142         fgDisplay.Display,
143         fgDisplay.Screen
144     );
145
146     /*
147      * Grab the physical screen's geometry
148      */
149     fgDisplay.ScreenWidthMM = DisplayWidthMM(
150         fgDisplay.Display,
151         fgDisplay.Screen
152     );
153
154     fgDisplay.ScreenHeightMM = DisplayHeightMM(
155         fgDisplay.Display,
156         fgDisplay.Screen
157     );
158
159     /*
160      * The display's connection number
161      */
162     fgDisplay.Connection = ConnectionNumber( fgDisplay.Display );
163
164     /*
165      * Create the window deletion atom
166      */
167     fgDisplay.DeleteWindow = XInternAtom(
168         fgDisplay.Display,
169         "WM_DELETE_WINDOW",
170         FALSE
171     );
172
173 #elif TARGET_HOST_WIN32
174
175     WNDCLASS wc;
176     ATOM atom;
177
178     /*
179      * What we need to do is to initialize the fgDisplay global structure here...
180      */
181     fgDisplay.Instance = GetModuleHandle( NULL );
182
183     /*
184      * Check if the freeglut window class has been registered before...
185      */
186     atom = GetClassInfo( fgDisplay.Instance, "FREEGLUT", &wc );
187
188     /*
189      * ...nope, it has not, and we have to do it right now:
190      */
191     if( atom == 0 )
192     {
193         /*
194          * Make sure the unitialized fields are reset to zero
195          */
196         ZeroMemory( &wc, sizeof(WNDCLASS) );
197
198         /*
199          * Each of the windows should have its own device context...
200          */
201         wc.style          = CS_OWNDC;
202         wc.lpfnWndProc    = fgWindowProc;
203         wc.cbClsExtra     = 0;
204         wc.cbWndExtra     = 0;
205         wc.hInstance      = fgDisplay.Instance;
206         wc.hIcon          = LoadIcon( fgDisplay.Instance, "GLUT_ICON" );
207         if (!wc.hIcon)
208           wc.hIcon        = LoadIcon( NULL, IDI_WINLOGO );
209
210         wc.hCursor        = LoadCursor( NULL, IDC_ARROW );
211         wc.hbrBackground  = NULL;
212         wc.lpszMenuName   = NULL;
213         wc.lpszClassName  = "FREEGLUT";
214
215         /*
216          * Register the window class
217          */
218         atom = RegisterClass( &wc );
219         assert( atom != 0 );
220     }
221
222     /*
223      * The screen dimensions can be obtained via GetSystemMetrics() calls
224      */
225     fgDisplay.ScreenWidth  = GetSystemMetrics( SM_CXSCREEN );
226     fgDisplay.ScreenHeight = GetSystemMetrics( SM_CYSCREEN );
227
228     {
229         /*
230          * Checking the display's size in millimeters isn't too hard, too:
231          */
232         HWND desktop = GetDesktopWindow();
233         HDC  context = GetDC( desktop );
234
235         /*
236          * Grab the appropriate values now (HORZSIZE and VERTSIZE respectably):
237          */
238         fgDisplay.ScreenWidthMM  = GetDeviceCaps( context, HORZSIZE );
239         fgDisplay.ScreenHeightMM = GetDeviceCaps( context, VERTSIZE );
240
241         /*
242          * Whoops, forgot to release the device context :)
243          */
244         ReleaseDC( desktop, context );
245     }
246
247 #endif
248
249     /*
250      * Have the joystick device initialized now
251      */
252     fgJoystickInit( 0 );
253 }
254
255 /*
256  * Perform the freeglut deinitialization...
257  */
258 void fgDeinitialize( void )
259 {
260     SFG_Timer *timer;
261
262     /*
263      * Check if initialization has been performed before
264      */
265     if( !fgState.Time.Set )
266     {
267         fgWarning( "fgDeinitialize(): fgState.Timer is null => no valid initialization has been performed" );
268         return;
269     }
270
271     /*
272      * Perform the freeglut structure deinitialization
273      */
274     fgDestroyStructure();
275
276     /*
277      * Delete all the timers and their storage list
278      */
279     while ( (timer = fgState.Timers.First) != NULL )
280     {
281       fgListRemove ( &fgState.Timers, &timer->Node ) ;
282       free ( timer ) ;
283     }
284
285     /*
286      * Deinitialize the joystick device
287      */
288     fgJoystickClose();
289
290     /*
291      * Reset the state structure
292      */
293
294     fgState.Position.X = -1 ;
295     fgState.Position.Y = -1 ;
296     fgState.Position.Use = FALSE ;
297
298     fgState.Size.X = 300 ;
299     fgState.Size.Y = 300 ;
300     fgState.Size.Use = TRUE ;
301
302     /*
303      * The default display mode to be used
304      */
305     fgState.DisplayMode = GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH;
306
307     fgState.ForceDirectContext  = FALSE;
308     fgState.TryDirectContext    = TRUE;
309     fgState.ForceIconic         = FALSE;
310     fgState.UseCurrentContext   = FALSE;
311     fgState.GLDebugSwitch       = FALSE;
312     fgState.XSyncSwitch         = FALSE;
313     fgState.ActionOnWindowClose = GLUT_ACTION_EXIT ;
314     fgState.ExecState           = GLUT_EXEC_STATE_INIT ;
315
316     /*
317      * Assume we want to ignore the automatic key repeat
318      */
319     fgState.IgnoreKeyRepeat = TRUE;
320
321     /*
322      * Set the default game mode settings
323      */
324     fgState.GameModeSize.X  = 640;
325     fgState.GameModeSize.Y  = 480;
326     fgState.GameModeDepth   =  16;
327     fgState.GameModeRefresh =  72;
328
329     fgState.Time.Set = FALSE ;
330
331     fgState.Timers.First = fgState.Timers.Last = NULL ;
332     fgState.IdleCallback = NULL ;
333     fgState.MenuStateCallback = (FGCBmenuState)NULL ;
334     fgState.MenuStatusCallback = (FGCBmenuStatus)NULL ;
335
336     /*
337      * FPS display
338      */
339     fgState.SwapCount   = 0;
340     fgState.SwapTime    = 0;
341     fgState.FPSInterval = 0;
342
343
344 #if TARGET_HOST_UNIX_X11
345
346     /*
347      * Make sure all X-client data we have created will be destroyed on display closing
348      */
349     XSetCloseDownMode( fgDisplay.Display, DestroyAll );
350
351     /*
352      * Close the display connection, destroying all windows we have created so far
353      */
354     XCloseDisplay( fgDisplay.Display );
355
356 #endif
357 }
358
359
360 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
361
362 /*
363  * Perform initialization. This usually happens on the program startup
364  * and restarting after glutMainLoop termination...
365  */
366 void FGAPIENTRY glutInit( int* pargc, char** argv )
367 {
368     char* displayName = NULL;
369     int i, j, argc = *pargc;
370
371     /*
372      * Do not allow multiple initialization of the library
373      */
374     if( fgState.Time.Set )
375     {
376         /*
377          * We can't have multiple initialization performed
378          */
379         fgError( "illegal glutInit() reinitialization attemp" );
380     }
381
382     /*
383      * Have the internal freeglut structure initialized now
384      */
385     fgCreateStructure();
386
387     /*
388      * Remember the function's call time
389      */
390 #if TARGET_HOST_UNIX_X11
391     gettimeofday(&fgState.Time.Value, NULL);
392 #elif TARGET_HOST_WIN32
393     fgState.Time.Value = timeGetTime();
394 #endif
395     fgState.Time.Set = TRUE;
396
397     /* check if GLUT_FPS env var is set */
398     {
399       const char *fps = getenv ( "GLUT_FPS" );
400       if ( fps )
401       {
402         sscanf ( fps, "%d", &fgState.FPSInterval ) ;
403         if ( fgState.FPSInterval <= 0 )
404           fgState.FPSInterval = 5000 ;  /* 5000 milliseconds */
405       }
406     }
407
408     /*
409      * Grab the environment variable indicating the X display to use.
410      * This is harmless under Win32, so let's let it stay here...
411      */
412 #if TARGET_HOST_WIN32
413     if ( !getenv ( "DISPLAY" ) )
414       displayName = strdup ( "" ) ;
415     else
416 #endif
417     displayName = strdup( getenv( "DISPLAY" ) );
418
419     /*
420      * Have the program arguments parsed.
421      */
422     for( i=1; i<argc; i++ )
423     {
424         /*
425          * The X display name settings
426          */
427         if( strcmp( argv[ i ], "-display" ) == 0 )
428         {
429             /*
430              * Check for possible lack of the next argument
431              */
432             if( ++i >= argc )
433                 fgError( "-display parameter must be followed by display name" );
434
435             /*
436              * Release the previous display name (the one from app's environment)
437              */
438             free( displayName );
439
440             /*
441              * Make a working copy of the name for us to use
442              */
443             displayName = strdup( argv[ i ] );
444
445             /*
446              * Have both arguments removed
447              */
448             argv[ i - 1 ] = NULL;
449             argv[   i   ] = NULL;
450             (* pargc) -= 2;
451         }
452
453         /*
454          * The geometry settings
455          */
456         else if( strcmp( argv[ i ], "-geometry" ) == 0 )
457         {
458           int result, x, y;
459           unsigned int w, h;
460
461           /*
462            * Again, check if there is at least one more argument
463            */
464           if ( ++i >= argc )
465             fgError( "-geometry parameter must be followed by window geometry settings" );
466
467           /*
468            * Otherwise scan the geometry settings...
469            */
470           result = sscanf ( argv[i], "%dx%d+%d+%d", &x, &y, &w, &h );
471
472           /*
473            * Check what we have been supplied with...
474            */
475           if ( result > 3 )
476             fgState.Size.Y = h ;
477
478           if ( result > 2 )
479             fgState.Size.X = w ;
480
481           if( result > 1 )
482           {
483             if( y < 0 )
484               fgState.Position.Y = fgDisplay.ScreenHeight + y - fgState.Size.Y;
485             else
486               fgState.Position.Y = y;
487           }
488
489           if( result > 0 )
490           {
491             if( x < 0 )
492               fgState.Position.X = fgDisplay.ScreenWidth + x - fgState.Size.X;
493             else
494               fgState.Position.X = x;
495           }
496
497           /*
498            * Have both arguments removed
499            */
500           argv[ i - 1 ] = NULL;
501           argv[   i   ] = NULL;
502           (* pargc) -= 2;
503         }
504
505         /*
506          * The direct/indirect OpenGL contexts settings
507          */
508         else if( strcmp( argv[ i ], "-direct" ) == 0)
509         {
510             /*
511              * We try to force direct rendering...
512              */
513             if( fgState.TryDirectContext == FALSE )
514                 fgError( "parameters ambiguity, -direct and -indirect cannot be both specified" );
515
516             fgState.ForceDirectContext = TRUE;
517             argv[ i ] = NULL;
518             (* pargc)--;
519         }
520         else if( strcmp( argv[ i ], "-indirect" ) == 0 )
521         {
522             /*
523              * We try to force indirect rendering...
524              */
525             if( fgState.ForceDirectContext == TRUE )
526                 fgError( "parameters ambiguity, -direct and -indirect cannot be both specified" );
527
528             fgState.TryDirectContext = FALSE;
529             argv[ i ] = NULL;
530             (* pargc)--;
531         }
532
533         /*
534          * The '-iconic' parameter makes all new top-level
535          * windows created in iconified state...
536          */
537         else if( strcmp( argv[ i ], "-iconic" ) == 0 )
538         {
539             fgState.ForceIconic = TRUE;
540             argv[ i ] = NULL;
541             (* pargc)--;
542         }
543
544         /*
545          * The '-gldebug' option activates some OpenGL state debugging features
546          */
547         else if( strcmp( argv[ i ], "-gldebug" ) == 0 )
548         {
549             fgState.GLDebugSwitch = TRUE;
550             argv[ i ] = NULL;
551             (* pargc)--;
552         }
553
554         /*
555          * The '-sync' option activates X protocol synchronization (for debugging purposes)
556          */
557         else if( strcmp( argv[ i ], "-sync" ) == 0 )
558         {
559             fgState.XSyncSwitch = TRUE;
560             argv[ i ] = NULL;
561             (* pargc)--;
562         }
563     }
564
565     /*
566      * Have the arguments list compacted now
567      */
568     j = 2 ;
569     for( i = 1; i < *pargc; i++, j++ )
570     {
571       if( argv[ i ] == NULL )
572       {
573         while ( argv[j] == NULL ) j++ ;  /* Guaranteed to end because there are "*pargc" arguments left */
574         argv[i] = argv[j] ;
575       }
576     }
577
578     /*
579      * Have the display created now. As I am too lazy to implement
580      * the program arguments parsing, we will have the DISPLAY
581      * environment variable used for opening the X display:
582      */
583     fgInitialize( displayName );
584
585     /*
586      * Check for the minus one settings for both position and size...
587      */
588     if( fgState.Position.X < 0 || fgState.Position.Y < 0 )
589         fgState.Position.Use = FALSE;
590
591     if( fgState.Size.X < 0 || fgState.Size.Y < 0 )
592         fgState.Size.Use = FALSE;
593
594     /*
595      * Do not forget about releasing the display name string
596      */
597     free( displayName );
598 }
599
600 /*
601  * Sets the default initial window position for new windows
602  */
603 void FGAPIENTRY glutInitWindowPosition( int x, int y )
604 {
605     /*
606      * The settings can be disables when both coordinates are negative
607      */
608     if( (x >= 0) && (y >= 0) )
609     {
610         /*
611          * We want to specify the initial position of each of the windows
612          */
613         fgState.Position.X   =    x;
614         fgState.Position.Y   =    y;
615         fgState.Position.Use = TRUE;
616     }
617     else
618     {
619         /*
620          * The initial position of each of the windows is specified by the wm
621          */
622         fgState.Position.X   =    -1;
623         fgState.Position.Y   =    -1;
624         fgState.Position.Use = FALSE;
625     }
626 }
627
628 /*
629  * Sets the default initial window size for new windows
630  */
631 void FGAPIENTRY glutInitWindowSize( int width, int height )
632 {
633     /*
634      * The settings can be disables when both values are negative
635      */
636     if( (width > 0) && (height > 0) )
637     {
638         /*
639          * We want to specify the initial size of each of the windows
640          */
641         fgState.Size.X   =  width;
642         fgState.Size.Y   = height;
643         fgState.Size.Use =   TRUE;
644     }
645     else
646     {
647         /*
648          * The initial size of each of the windows is specified by the wm (officially this is an error condition)
649          */
650         fgState.Size.X   =    -1;
651         fgState.Size.Y   =    -1;
652         fgState.Size.Use = FALSE;
653     }
654 }
655
656 /*
657  * Sets the default display mode for all new windows
658  */
659 void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode )
660 {
661     /*
662      * We will make use of this value when creating a new OpenGL context...
663      */
664     fgState.DisplayMode = displayMode;
665 }
666
667
668 /* -- INIT DISPLAY STRING PARSING ------------------------------------------ */
669
670 #if 0 /* FIXME: CJP */
671 /*
672  * There is a discrete number of comparison operators we can encounter:
673  *
674  *     comparison ::= "=" | "!=" | "<" | ">" | "<=" | ">=" | "~"
675  */
676 #define  FG_NONE           0x0000
677 #define  FG_EQUAL          0x0001
678 #define  FG_NOT_EQUAL      0x0002
679 #define  FG_LESS           0x0003
680 #define  FG_MORE           0x0004
681 #define  FG_LESS_OR_EQUAL  0x0005
682 #define  FG_MORE_OR_EQUAL  0x0006
683 #define  FG_CLOSEST        0x0007
684
685 /*
686  * The caller can feed us with a number of capability tokens:
687  *
688  * capability ::= "alpha" | "acca" | "acc" | "blue" | "buffer" | "conformant" | "depth" | "double" |
689  *                "green" | "index" | "num" | "red" | "rgba" | "rgb" | "luminance" | "stencil" |
690  *                "single" | "stereo" | "samples" | "slow" | "win32pdf" | "xvisual" | "xstaticgray" |
691  *                "xgrayscale" | "xstaticcolor" | "xpseudocolor" | "xtruecolor" | "xdirectcolor"
692  */
693 static gchar* g_Tokens[] =
694 {
695     "none", "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double", "green",
696     "index", "num", "red", "rgba", "rgb", "luminance", "stencil", "single", "stereo", "samples",
697     "slow", "win32pdf", "xvisual", "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
698     "xtruecolor", "xdirectcolor", NULL
699 };
700
701 /*
702  * The structure to hold the parsed display string tokens
703  */
704 typedef struct tagSFG_Capability SFG_Capability;
705 struct tagSFG_Capability
706 {
707     gint capability;        /* the capability token enumerator */
708     gint comparison;        /* the comparison operator used    */
709     gint value;             /* the value we're comparing to    */
710 };
711
712 /*
713  * The scanner configuration for the init display string
714  */
715 static GScannerConfig fgInitDisplayStringScannerConfig =
716 {
717     ( " \t\r\n" )               /* cset_skip_characters     */,
718     (
719         G_CSET_a_2_z
720         "_"
721         G_CSET_A_2_Z
722     )                                   /* cset_identifier_first    */,
723     (
724         G_CSET_a_2_z
725         "_0123456789"
726         G_CSET_A_2_Z
727         G_CSET_LATINS
728         G_CSET_LATINC
729         "<>!=~"
730     )                                   /* cset_identifier_nth      */,
731     ( "#\n" )                       /* cpair_comment_single     */,
732     FALSE                                   /* case_sensitive           */,
733     TRUE                                    /* skip_comment_multi       */,
734     TRUE                                    /* skip_comment_single      */,
735     TRUE                                    /* scan_comment_multi       */,
736     TRUE                                    /* scan_identifier          */,
737     FALSE                                   /* scan_identifier_1char    */,
738     FALSE                                   /* scan_identifier_NULL     */,
739     TRUE                                    /* scan_symbols             */,
740     FALSE                                   /* scan_binary              */,
741     TRUE                                    /* scan_octal               */,
742     TRUE                                    /* scan_float               */,
743     TRUE                                    /* scan_hex                 */,
744     FALSE                                   /* scan_hex_dollar          */,
745     TRUE                                    /* scan_string_sq           */,
746     TRUE                                    /* scan_string_dq           */,
747     TRUE                                    /* numbers_2_int            */,
748     FALSE                                   /* int_2_float              */,
749     FALSE                                   /* identifier_2_string      */,
750     TRUE                                    /* char_2_token             */,
751     FALSE                                   /* symbol_2_token           */,
752     FALSE                                   /* scope_0_fallback         */,
753 };
754
755 /*
756  * Sets the default display mode for all new windows using a string
757  */
758 void FGAPIENTRY glutInitDisplayString( char* displayMode )
759 {
760     /*
761      * display_string ::= (switch)
762      * switch         ::= capability [comparison value]
763      * comparison     ::= "=" | "!=" | "<" | ">" | "<=" | ">=" | "~"
764      * capability     ::= "alpha" | "acca" | "acc" | "blue" | "buffer" | "conformant" |
765      *                    "depth" | "double" | "green" | "index" | "num" | "red" | "rgba" |
766      *                    "rgb" | "luminance" | "stencil" | "single" | "stereo" |
767      *                    "samples" | "slow" | "win32pdf" | "xvisual" | "xstaticgray" |
768      *                    "xgrayscale" | "xstaticcolor" | "xpseudocolor" |
769      *                    "xtruecolor" | "xdirectcolor"
770      * value          ::= 0..9 [value]
771      *
772      * The display string grammar. This should be EBNF, but I couldn't find the definitions so, to
773      * clarify: (expr) means 0 or more times the expression, [expr] means 0 or 1 times expr.
774      *
775      * Create a new GLib lexical analyzer to process the display mode string
776      */
777     GScanner* scanner = g_scanner_new( &fgInitDisplayStringScannerConfig );
778     GList* caps = NULL;
779     gint i;
780
781     /*
782      * Fail if the display mode string is empty or the scanner failed to initialize
783      */
784     freeglut_return_if_fail( (scanner != NULL) && (strlen( displayMode ) > 0) );
785
786     /*
787      * Set the scanner's input name (for debugging)
788      */
789     scanner->input_name = "glutInitDisplayString";
790
791     /*
792      * Start the lexical analysis of the extensions string
793      */
794     g_scanner_input_text( scanner, displayMode, strlen( displayMode ) );
795
796     /*
797      * While there are any more tokens to be checked...
798      */
799     while( !g_scanner_eof( scanner ) )
800     {
801         /*
802          * Actually we're expecting only string tokens
803          */
804         GTokenType tokenType = g_scanner_get_next_token( scanner );
805
806         /*
807          * We are looking for identifiers
808          */
809         if( tokenType == G_TOKEN_IDENTIFIER )
810         {
811             gchar* capability  = NULL;  /* the capability identifier string (always present) */
812             gint   capID       =    0;  /* the capability identifier value (from g_Tokens)   */
813             gint   comparison  =    0;  /* the comparison operator value, see definitions    */
814             gchar* valueString = NULL;  /* if the previous one is present, this is needed    */
815             gint   value       =    0;  /* the integer value converted using a strtol call   */
816             SFG_Capability* capStruct;  /* the capability description structure              */
817
818             /*
819              * OK. The general rule of thumb that we always should be getting a capability identifier
820              * string (see the grammar description). If it is followed by a comparison identifier, then
821              * there must follow an integer value we're comparing the capability to...
822              *
823              * Have the current token analyzed with that in mind...
824              */
825             for( i=0; i<(gint) strlen( scanner->value.v_identifier ); i++ )
826             {
827                 gchar c = scanner->value.v_identifier[ i ];
828
829                 if( (c == '=') || (c == '!') || (c == '<') || (c == '>') || (c == '~') )
830                     break;
831             }
832
833             /*
834              * Here we go with the length of the capability identifier string.
835              * In the worst of cases, it is as long as the token identifier.
836              */
837             capability = g_strndup( scanner->value.v_identifier, i );
838
839             /*
840              * OK. Is there a chance for comparison and value identifiers to follow?
841              * Note: checking against i+1 as this handles two cases: single character
842              * comparison operator and first of value's digits, which must always be
843              * there, or the two-character comparison operators.
844              */
845             if( (i + 1) < (gint) strlen( scanner->value.v_identifier ) )
846             {
847                 /*
848                  * Yeah, indeed, it is the i-th character to start the identifier, then.
849                  */
850                 gchar c1 = scanner->value.v_identifier[ i + 0 ];
851                 gchar c2 = scanner->value.v_identifier[ i + 1 ];
852
853                 if( (c1 == '=')                ) { i += 1; comparison = FG_EQUAL;         } else
854                 if( (c1 == '!') && (c2 == '=') ) { i += 2; comparison = FG_NOT_EQUAL;     } else
855                 if( (c1 == '<') && (c2 == '=') ) { i += 2; comparison = FG_LESS_OR_EQUAL; } else
856                 if( (c1 == '>') && (c2 == '=') ) { i += 2; comparison = FG_MORE_OR_EQUAL; } else
857                 if( (c1 == '<')                ) { i += 1; comparison = FG_LESS;          } else
858                 if( (c1 == '>')                ) { i += 1; comparison = FG_MORE;          } else
859                 if( (c1 == '~')                ) { i += 1; comparison = FG_CLOSEST;       } else
860                 g_warning( "invalid comparison operator in token `%s'", scanner->value.v_identifier );
861             }
862
863             /*
864              * Grab the value string that must follow the comparison operator...
865              */
866             if( comparison != FG_NONE && i < (gint) strlen( scanner->value.v_identifier ) )
867                 valueString = strdup( scanner->value.v_identifier + i );
868
869             /*
870              * If there was a value string, convert it to integer...
871              */
872             if( comparison != FG_NONE && strlen( valueString ) > 0 )
873                 value = strtol( valueString, NULL, 0 );
874
875             /*
876              * Now we need to match the capability string and its ID
877              */
878             for( i=0; g_Tokens[ i ]!=NULL; i++ )
879             {
880                 if( strcmp( capability, g_Tokens[ i ] ) == 0 )
881                 {
882                     /*
883                      * Looks like we've found the one we were looking for
884                      */
885                     capID = i;
886                     break;
887                 }
888             }
889
890             /*
891              * Create a new capability description structure
892              */
893             capStruct = g_new0( SFG_Capability, 1 );
894
895             /*
896              * Fill in the cap's values, as we have parsed it:
897              */
898             capStruct->capability =      capID;
899             capStruct->comparison = comparison;
900             capStruct->value      =      value;
901
902             /*
903              * Add the new capabaility to the caps list
904              */
905             caps = g_list_append( caps, capStruct );
906
907             /*
908              * Clean up the local mess and keep rolling on
909              */
910             g_free( valueString );
911             g_free( capability );
912         }
913     }
914
915     /*
916      * Now that we have converted the string into somewhat more machine-friendly
917      * form, proceed with matching the frame buffer configuration...
918      *
919      * The caps list could be passed to a function that would try finding the closest 
920      * matching pixel format, visual, frame buffer configuration or whatever. It would 
921      * be good to convert the glutInitDisplayMode() to use the same method.
922      */
923 #if 0
924     g_message( "found %i capability preferences", g_list_length( caps ) );
925
926     g_message( "token `%s': cap: %i, com: %i, val: %i",
927         scanner->value.v_identifier,
928         capStruct->capability,
929         capStruct->comparison,
930         capStruct->value
931     );
932 #endif
933
934     /*
935      * Free the capabilities we have parsed
936      */
937     for( i=0; i<(gint) g_list_length( caps ); i++ )
938         g_free( g_list_nth( caps, i )->data );
939
940     /*
941      * Destroy the capabilities list itself
942      */
943     g_list_free( caps );
944
945     /*
946      * Free the lexical scanner now...
947      */
948     g_scanner_destroy( scanner );
949 }
950 #endif
951
952 #define NUM_TOKENS             28
953 static char* Tokens[] =
954 {
955     "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double", "green",
956     "index", "num", "red", "rgba", "rgb", "luminance", "stencil", "single", "stereo", "samples",
957     "slow", "win32pdf", "xvisual", "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
958     "xtruecolor", "xdirectcolor"
959 };
960
961 static int TokenLengths[] =
962 {
963          5,      4,     3,      4,        6,           10,       5,        6,       5,
964          5,     3,     3,      4,     3,           9,         7,        6,        6,         7,
965         4,          8,         7,            11,           10,             12,             12,
966              10,             12
967 };
968
969 void FGAPIENTRY glutInitDisplayString( const char* displayMode )
970 {
971   int glut_state_flag = 0 ;
972   /*
973    * Unpack a lot of options from a character string.  The options are delimited by blanks or tabs.
974    */
975   char *token ;
976   int len = strlen ( displayMode ) ;
977   char *buffer = malloc ( (len+1) * sizeof(char) ) ;
978   memcpy ( buffer, displayMode, len ) ;
979   buffer[len] = '\0' ;
980
981   token = strtok ( buffer, " \t" ) ;
982   while ( token )
983   {
984     /*
985      * Process this token
986      */
987     int i ;
988     for ( i = 0; i < NUM_TOKENS; i++ )
989     {
990       if ( strncmp ( token, Tokens[i], TokenLengths[i] ) == 0 ) break ;
991     }
992
993     switch ( i )
994     {
995     case 0 :  /* "alpha":  Alpha color buffer precision in bits */
996       glut_state_flag |= GLUT_ALPHA ;  /* Somebody fix this for me! */
997       break ;
998
999     case 1 :  /* "acca":  Red, green, blue, and alpha accumulation buffer precision in bits */
1000       break ;
1001
1002     case 2 :  /* "acc":  Red, green, and blue accumulation buffer precision in bits with zero bits alpha */
1003       glut_state_flag |= GLUT_ACCUM ;  /* Somebody fix this for me! */
1004       break ;
1005
1006     case 3 :  /* "blue":  Blue color buffer precision in bits */
1007       break ;
1008
1009     case 4 :  /* "buffer":  Number of bits in the color index color buffer */
1010       break ;
1011
1012     case 5 :  /* "conformant":  Boolean indicating if the frame buffer configuration is conformant or not */
1013       break ;
1014
1015     case 6 :  /* "depth":  Number of bits of precsion in the depth buffer */
1016       glut_state_flag |= GLUT_DEPTH ;  /* Somebody fix this for me! */
1017       break ;
1018
1019     case 7 :  /* "double":  Boolean indicating if the color buffer is double buffered */
1020       glut_state_flag |= GLUT_DOUBLE ;
1021       break ;
1022
1023     case 8 :  /* "green":  Green color buffer precision in bits */
1024       break ;
1025
1026     case 9 :  /* "index":  Boolean if the color model is color index or not */
1027       glut_state_flag |= GLUT_INDEX ;
1028       break ;
1029
1030     case 10 :  /* "num":  A special capability  name indicating where the value represents the Nth frame buffer configuration matching the description string */
1031       break ;
1032
1033     case 11 :  /* "red":  Red color buffer precision in bits */
1034       break ;
1035
1036     case 12 :  /* "rgba":  Number of bits of red, green, blue, and alpha in the RGBA color buffer */
1037       glut_state_flag |= GLUT_RGBA ;  /* Somebody fix this for me! */
1038       break ;
1039
1040     case 13 :  /* "rgb":  Number of bits of red, green, and blue in the RGBA color buffer with zero bits alpha */
1041       glut_state_flag |= GLUT_RGB ;  /* Somebody fix this for me! */
1042       break ;
1043
1044     case 14 :  /* "luminance":  Number of bits of red in the RGBA and zero bits of green, blue (alpha not specified) of color buffer precision */
1045       glut_state_flag |= GLUT_LUMINANCE ;  /* Somebody fix this for me! */
1046       break ;
1047
1048     case 15 :  /* "stencil":  Number of bits in the stencil buffer */
1049       glut_state_flag |= GLUT_STENCIL ;  /* Somebody fix this for me! */
1050       break ;
1051
1052     case 16 :  /* "single":  Boolean indicate the color buffer is single buffered */
1053       glut_state_flag |= GLUT_SINGLE ;
1054       break ;
1055
1056     case 17 :  /* "stereo":  Boolean indicating the color buffer supports OpenGL-style stereo */
1057       glut_state_flag |= GLUT_STEREO ;
1058       break ;
1059
1060     case 18 :  /* "samples":  Indicates the number of multisamples to use based on GLX's SGIS_multisample extension (for antialiasing) */
1061       glut_state_flag |= GLUT_MULTISAMPLE ;  /* Somebody fix this for me! */
1062       break ;
1063
1064     case 19 :  /* "slow":  Boolean indicating if the frame buffer configuration is slow or not */
1065       break ;
1066
1067     case 20 :  /* "win32pdf":  matches the Win32 Pixel Format Descriptor by number */
1068 #ifdef TARGET_HOST_WIN32
1069 #endif
1070       break ;
1071
1072     case 21 :  /* "xvisual":  matches the X visual ID by number */
1073 #ifdef TARGET_HOST_UNIX_X11
1074 #endif
1075       break ;
1076
1077     case 22 :  /* "xstaticgray":  boolean indicating if the frame buffer configuration's X visual is of type StaticGray */
1078 #ifdef TARGET_HOST_UNIX_X11
1079 #endif
1080       break ;
1081
1082     case 23 :  /* "xgrayscale":  boolean indicating if the frame buffer configuration's X visual is of type GrayScale */
1083 #ifdef TARGET_HOST_UNIX_X11
1084 #endif
1085       break ;
1086
1087     case 24 :  /* "xstaticcolor":  boolean indicating if the frame buffer configuration's X visual is of type StaticColor */
1088 #ifdef TARGET_HOST_UNIX_X11
1089 #endif
1090       break ;
1091
1092     case 25 :  /* "xpseudocolor":  boolean indicating if the frame buffer configuration's X visual is of type PseudoColor */
1093 #ifdef TARGET_HOST_UNIX_X11
1094 #endif
1095       break ;
1096
1097     case 26 :  /* "xtruecolor":  boolean indicating if the frame buffer configuration's X visual is of type TrueColor */
1098 #ifdef TARGET_HOST_UNIX_X11
1099 #endif
1100       break ;
1101
1102     case 27 :  /* "xdirectcolor":  boolean indicating if the frame buffer configuration's X visual is of type DirectColor */
1103 #ifdef TARGET_HOST_UNIX_X11
1104 #endif
1105       break ;
1106
1107     case 28 :  /* Unrecognized */
1108       printf ( "WARNING - Display string token not recognized:  %s\n", token ) ;
1109       break ;
1110     }
1111
1112     token = strtok ( NULL, " \t" ) ;
1113   }
1114
1115   free ( buffer ) ;
1116
1117   /*
1118    * We will make use of this value when creating a new OpenGL context...
1119    */
1120   fgState.DisplayMode = glut_state_flag;
1121 }
1122
1123 /*** END OF FILE ***/