1 /*
2  * fg_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 #define FREEGLUT_BUILDING_LIB
29 #include <GL/freeglut.h>
30 #include "fg_internal.h"
31 
32 /*
33  * TODO BEFORE THE STABLE RELEASE:
34  *
35  *  fgDeinitialize()        -- Win32's OK, X11 needs the OS-specific
36  *                             deinitialization done
37  *  glutInitDisplayString() -- display mode string parsing
38  *
39  * Wouldn't it be cool to use gettext() for error messages? I just love
40  * bash saying  "nie znaleziono pliku" instead of "file not found" :)
41  * Is gettext easily portable?
42  */
43 
44 /* -- GLOBAL VARIABLES ----------------------------------------------------- */
45 
46 /*
47  * A structure pointed by fgDisplay holds all information
48  * regarding the display, screen, root window etc.
49  */
50 SFG_Display fgDisplay;
51 
52 /*
53  * The settings for the current freeglut session
54  */
55 SFG_State fgState = { { -1, -1, GL_FALSE },  /* Position */
56                       { 300, 300, GL_TRUE }, /* Size */
57                       GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH,  /* DisplayMode */
58                       GL_FALSE,              /* Initialised */
59                       GLUT_TRY_DIRECT_CONTEXT,  /* DirectContext */
60                       GL_FALSE,              /* ForceIconic */
61                       GL_FALSE,              /* UseCurrentContext */
62                       GL_FALSE,              /* GLDebugSwitch */
63                       GL_FALSE,              /* XSyncSwitch */
64                       GLUT_KEY_REPEAT_ON,    /* KeyRepeat */
65                       INVALID_MODIFIERS,     /* Modifiers */
66                       0,                     /* FPSInterval */
67                       0,                     /* SwapCount */
68                       0,                     /* SwapTime */
69                       0,                     /* Time */
70                       { NULL, NULL },         /* Timers */
71                       { NULL, NULL },         /* FreeTimers */
72                       NULL,                   /* IdleCallback */
73                       NULL,                   /* IdleCallbackData */
74                       0,                      /* ActiveMenus */
75                       NULL,                   /* MenuStateCallback */
76                       NULL,                   /* MenuStatusCallback */
77                       NULL,                   /* MenuStatusCallbackData */
78                       FREEGLUT_MENU_FONT,
79                       { -1, -1, GL_TRUE },    /* GameModeSize */
80                       -1,                     /* GameModeDepth */
81                       -1,                     /* GameModeRefresh */
82                       GLUT_ACTION_EXIT,       /* ActionOnWindowClose */
83                       GLUT_EXEC_STATE_INIT,   /* ExecState */
84                       NULL,                   /* ProgramName */
85                       GL_FALSE,               /* JoysticksInitialised */
86                       0,                      /* NumActiveJoysticks */
87                       GL_FALSE,               /* InputDevsInitialised */
88                       0,                      /* MouseWheelTicks */
89                       1,                      /* AuxiliaryBufferNumber */
90                       4,                      /* SampleNumber */
91                       GL_FALSE,               /* SkipStaleMotion */
92                       GL_FALSE,               /* StrokeFontDrawJoinDots */
93                       GL_FALSE,               /* AllowNegativeWindowPosition */
94                       1,                      /* OpenGL context MajorVersion */
95                       0,                      /* OpenGL context MinorVersion */
96                       0,                      /* OpenGL ContextFlags */
97                       0,                      /* OpenGL ContextProfile */
98                       0,                      /* HasOpenGL20 */
99                       NULL,                   /* ErrorFunc */
100                       NULL,                   /* ErrorFuncData */
101                       NULL,                   /* WarningFunc */
102                       NULL                    /* WarningFuncData */
103 };
104 
105 
106 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
107 
108 extern void fgPlatformInitialize( const char* displayName );
109 extern void fgPlatformDeinitialiseInputDevices ( void );
110 extern void fgPlatformCloseDisplay ( void );
111 extern void fgPlatformDestroyContext ( SFG_PlatformDisplay pDisplay, SFG_WindowContextType MContext );
112 
fghParseCommandLineArguments(int * pargc,char ** argv,char ** pDisplayName,char ** pGeometry)113 void fghParseCommandLineArguments ( int* pargc, char** argv, char **pDisplayName, char **pGeometry )
114 {
115 #ifndef _WIN32_WCE
116     int i, j, argc = *pargc;
117 
118     {
119         /* check if GLUT_FPS env var is set */
120         const char *fps = getenv( "GLUT_FPS" );
121 
122         if( fps )
123         {
124             int interval;
125             sscanf( fps, "%d", &interval );
126 
127             if( interval <= 0 )
128                 fgState.FPSInterval = 5000;  /* 5000 millisecond default */
129             else
130                 fgState.FPSInterval = interval;
131         }
132     }
133 
134     *pDisplayName = getenv( "DISPLAY" );
135 
136     for( i = 1; i < argc; i++ )
137     {
138         if( strcmp( argv[ i ], "-display" ) == 0 )
139         {
140             if( ++i >= argc )
141                 fgError( "-display parameter must be followed by display name" );
142 
143             *pDisplayName = argv[ i ];
144 
145             argv[ i - 1 ] = NULL;
146             argv[ i     ] = NULL;
147             ( *pargc ) -= 2;
148         }
149         else if( strcmp( argv[ i ], "-geometry" ) == 0 )
150         {
151             if( ++i >= argc )
152                 fgError( "-geometry parameter must be followed by window "
153                          "geometry settings" );
154 
155             *pGeometry = argv[ i ];
156 
157             argv[ i - 1 ] = NULL;
158             argv[ i     ] = NULL;
159             ( *pargc ) -= 2;
160         }
161         else if( strcmp( argv[ i ], "-direct" ) == 0)
162         {
163             if( fgState.DirectContext == GLUT_FORCE_INDIRECT_CONTEXT )
164                 fgError( "parameters ambiguity, -direct and -indirect "
165                     "cannot be both specified" );
166 
167             fgState.DirectContext = GLUT_FORCE_DIRECT_CONTEXT;
168             argv[ i ] = NULL;
169             ( *pargc )--;
170         }
171         else if( strcmp( argv[ i ], "-indirect" ) == 0 )
172         {
173             if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )
174                 fgError( "parameters ambiguity, -direct and -indirect "
175                     "cannot be both specified" );
176 
177             fgState.DirectContext = GLUT_FORCE_INDIRECT_CONTEXT;
178             argv[ i ] = NULL;
179             (*pargc)--;
180         }
181         else if( strcmp( argv[ i ], "-iconic" ) == 0 )
182         {
183             fgState.ForceIconic = GL_TRUE;
184             argv[ i ] = NULL;
185             ( *pargc )--;
186         }
187         else if( strcmp( argv[ i ], "-gldebug" ) == 0 )
188         {
189             fgState.GLDebugSwitch = GL_TRUE;
190             argv[ i ] = NULL;
191             ( *pargc )--;
192         }
193         else if( strcmp( argv[ i ], "-sync" ) == 0 )
194         {
195             fgState.XSyncSwitch = GL_TRUE;
196             argv[ i ] = NULL;
197             ( *pargc )--;
198         }
199     }
200 
201     /* Compact {argv}. */
202     for( i = j = 1; i < *pargc; i++, j++ )
203     {
204         /* Guaranteed to end because there are "*pargc" arguments left */
205         while ( argv[ j ] == NULL )
206             j++;
207         if ( i != j )
208             argv[ i ] = argv[ j ];
209     }
210 
211 #endif /* _WIN32_WCE */
212 
213 }
214 
215 
fghCloseInputDevices(void)216 void fghCloseInputDevices ( void )
217 {
218     if ( fgState.JoysticksInitialised )
219         fgJoystickClose( );
220 
221     if ( fgState.InputDevsInitialised )
222         fgInputDeviceClose( );
223 }
224 
225 
226 /*
227  * Perform the freeglut deinitialization...
228  */
fgDeinitialize(void)229 void fgDeinitialize( void )
230 {
231     SFG_Timer *timer;
232 
233     if( !fgState.Initialised )
234     {
235         return;
236     }
237 
238     /* If we're in game mode, we want to leave game mode */
239     if( fgStructure.GameModeWindow ) {
240         glutLeaveGameMode();
241     }
242 
243     /* If there was a menu created, destroy the rendering context */
244     if( fgStructure.MenuContext )
245     {
246         fgPlatformDestroyContext (fgDisplay.pDisplay, fgStructure.MenuContext->MContext );
247         free( fgStructure.MenuContext );
248         fgStructure.MenuContext = NULL;
249     }
250 
251     fgDestroyStructure( );
252 
253     while( ( timer = fgState.Timers.First) )
254     {
255         fgListRemove( &fgState.Timers, &timer->Node );
256         free( timer );
257     }
258 
259     while( ( timer = fgState.FreeTimers.First) )
260     {
261         fgListRemove( &fgState.FreeTimers, &timer->Node );
262         free( timer );
263     }
264 
265     fgPlatformDeinitialiseInputDevices ();
266 
267     fgState.MouseWheelTicks = 0;
268 
269     fgState.MajorVersion = 1;
270     fgState.MinorVersion = 0;
271     fgState.ContextFlags = 0;
272     fgState.ContextProfile = 0;
273 
274     fgState.Initialised = GL_FALSE;
275 
276     fgState.Position.X = -1;
277     fgState.Position.Y = -1;
278     fgState.Position.Use = GL_FALSE;
279 
280     fgState.Size.X = 300;
281     fgState.Size.Y = 300;
282     fgState.Size.Use = GL_TRUE;
283 
284     fgState.DisplayMode = GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH;
285 
286     fgState.DirectContext  = GLUT_TRY_DIRECT_CONTEXT;
287     fgState.ForceIconic         = GL_FALSE;
288     fgState.UseCurrentContext   = GL_FALSE;
289     fgState.GLDebugSwitch       = GL_FALSE;
290     fgState.XSyncSwitch         = GL_FALSE;
291     fgState.ActionOnWindowClose = GLUT_ACTION_EXIT;
292     fgState.ExecState           = GLUT_EXEC_STATE_INIT;
293 
294     fgState.KeyRepeat       = GLUT_KEY_REPEAT_ON;
295     fgState.Modifiers       = INVALID_MODIFIERS;
296 
297     fgState.GameModeSize.X  = -1;
298     fgState.GameModeSize.Y  = -1;
299     fgState.GameModeDepth   = -1;
300     fgState.GameModeRefresh = -1;
301 
302     fgListInit( &fgState.Timers );
303     fgListInit( &fgState.FreeTimers );
304 
305     fgState.IdleCallback           = ( FGCBIdleUC )NULL;
306     fgState.IdleCallbackData       = NULL;
307     fgState.MenuStateCallback      = ( FGCBMenuState )NULL;
308     fgState.MenuStatusCallback     = ( FGCBMenuStatusUC )NULL;
309     fgState.MenuStatusCallbackData = NULL;
310 
311     fgState.SwapCount   = 0;
312     fgState.SwapTime    = 0;
313     fgState.FPSInterval = 0;
314 
315     if( fgState.ProgramName )
316     {
317         free( fgState.ProgramName );
318         fgState.ProgramName = NULL;
319     }
320 
321     fgPlatformCloseDisplay ();
322 
323     fgState.Initialised = GL_FALSE;
324 }
325 
326 
327 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
328 #if defined(NEED_XPARSEGEOMETRY_IMPL) || defined(TARGET_HOST_MS_WINDOWS)
329 #   include "util/xparsegeometry_repl.h"
330 #endif
331 
332 /*
333  * Perform initialization. This usually happens on the program startup
334  * and restarting after glutMainLoop termination...
335  */
glutInit(int * pargc,char ** argv)336 void FGAPIENTRY glutInit( int* pargc, char** argv )
337 {
338     char* displayName = NULL;
339     char* geometry = NULL;
340     if( fgState.Initialised )
341         fgError( "illegal glutInit() reinitialization attempt" );
342 
343     if (pargc && *pargc && argv && *argv && **argv)
344     {
345         fgState.ProgramName = strdup (*argv);
346 
347         if( !fgState.ProgramName )
348             fgError ("Could not allocate space for the program's name.");
349     }
350 
351     fgCreateStructure( );
352 
353     fghParseCommandLineArguments ( pargc, argv, &displayName, &geometry );
354 
355     /*
356      * Have the display created now. If there wasn't a "-display"
357      * in the program arguments, we will use the DISPLAY environment
358      * variable for opening the X display (see code above):
359      */
360     fgPlatformInitialize( displayName );
361 
362     /*
363      * Geometry parsing deferred until here because we may need the screen
364      * size.
365      */
366 
367     if ( geometry )
368     {
369         unsigned int parsedWidth, parsedHeight;
370         int mask = XParseGeometry( geometry,
371                                    &fgState.Position.X, &fgState.Position.Y,
372                                    &parsedWidth, &parsedHeight );
373         /* TODO: Check for overflow? */
374         fgState.Size.X = parsedWidth;
375         fgState.Size.Y = parsedHeight;
376 
377         if( (mask & (WidthValue|HeightValue)) == (WidthValue|HeightValue) )
378             fgState.Size.Use = GL_TRUE;
379 
380         if( ( mask & XNegative ) && !fgState.AllowNegativeWindowPosition )
381             fgState.Position.X += fgDisplay.ScreenWidth - fgState.Size.X;
382 
383         if( ( mask & YNegative ) && !fgState.AllowNegativeWindowPosition )
384             fgState.Position.Y += fgDisplay.ScreenHeight - fgState.Size.Y;
385 
386         if( (mask & (XValue|YValue)) == (XValue|YValue) )
387             fgState.Position.Use = GL_TRUE;
388     }
389 }
390 
391 /*
392  * Undoes all the "glutInit" stuff
393  */
glutExit(void)394 void FGAPIENTRY glutExit ( void )
395 {
396   fgDeinitialize ();
397 }
398 
399 /*
400  * Sets the default initial window position for new windows
401  */
glutInitWindowPosition(int x,int y)402 void FGAPIENTRY glutInitWindowPosition( int x, int y )
403 {
404     fgState.Position.X = x;
405     fgState.Position.Y = y;
406 
407     if( ( ( x >= 0 ) && ( y >= 0 ) ) || fgState.AllowNegativeWindowPosition )
408         fgState.Position.Use = GL_TRUE;
409     else
410         fgState.Position.Use = GL_FALSE;
411 }
412 
413 /*
414  * Sets the default initial window size for new windows
415  */
glutInitWindowSize(int width,int height)416 void FGAPIENTRY glutInitWindowSize( int width, int height )
417 {
418     fgState.Size.X = width;
419     fgState.Size.Y = height;
420 
421     if( ( width > 0 ) && ( height > 0 ) )
422         fgState.Size.Use = GL_TRUE;
423     else
424         fgState.Size.Use = GL_FALSE;
425 }
426 
427 /*
428  * Sets the default display mode for all new windows
429  */
glutInitDisplayMode(unsigned int displayMode)430 void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode )
431 {
432     /* We will make use of this value when creating a new OpenGL context... */
433     fgState.DisplayMode = displayMode;
434 }
435 
436 
437 /* -- INIT DISPLAY STRING PARSING ------------------------------------------ */
438 
439 static char* Tokens[] =
440 {
441     "alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double",
442     "green", "index", "num", "red", "rgba", "rgb", "luminance", "stencil",
443     "single", "stereo", "samples", "slow", "win32pdf", "win32pfd", "xvisual",
444     "xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
445     "xtruecolor", "xdirectcolor",
446     "xstaticgrey", "xgreyscale", "xstaticcolour", "xpseudocolour",
447     "xtruecolour", "xdirectcolour", "borderless", "aux"
448 };
449 #define NUM_TOKENS             (sizeof(Tokens) / sizeof(*Tokens))
450 
glutInitDisplayString(const char * displayMode)451 void FGAPIENTRY glutInitDisplayString( const char* displayMode )
452 {
453     int glut_state_flag = 0 ;
454     /*
455      * Unpack a lot of options from a character string.  The options are
456      * delimited by blanks or tabs.
457      */
458     char *token ;
459     size_t len = strlen ( displayMode );
460     char *buffer = (char *)malloc ( (len+1) * sizeof(char) );
461     memcpy ( buffer, displayMode, len );
462     buffer[len] = '\0';
463 
464     token = strtok ( buffer, " \t" );
465 
466     while ( token )
467     {
468         /* Process this token */
469         int i ;
470 
471         /* Temporary fix:  Ignore any length specifications and at least
472          * process the basic token
473          * TODO:  Fix this permanently
474          */
475         size_t cleanlength = strcspn ( token, "=<>~!" );
476 
477         for ( i = 0; i < NUM_TOKENS; i++ )
478         {
479             if ( strncmp ( token, Tokens[i], cleanlength ) == 0 ) break ;
480         }
481 
482         switch ( i )
483         {
484         case 0 :  /* "alpha":  Alpha color buffer precision in bits */
485             glut_state_flag |= GLUT_ALPHA ;  /* Somebody fix this for me! */
486             break ;
487 
488         case 1 :  /* "acca":  Red, green, blue, and alpha accumulation buffer
489                      precision in bits */
490             break ;
491 
492         case 2 :  /* "acc":  Red, green, and blue accumulation buffer precision
493                      in bits with zero bits alpha */
494             glut_state_flag |= GLUT_ACCUM ;  /* Somebody fix this for me! */
495             break ;
496 
497         case 3 :  /* "blue":  Blue color buffer precision in bits */
498             break ;
499 
500         case 4 :  /* "buffer":  Number of bits in the color index color buffer
501                    */
502             break ;
503 
504         case 5 :  /* "conformant":  Boolean indicating if the frame buffer
505                      configuration is conformant or not */
506             break ;
507 
508         case 6 : /* "depth":  Number of bits of precision in the depth buffer */
509             glut_state_flag |= GLUT_DEPTH ;  /* Somebody fix this for me! */
510             break ;
511 
512         case 7 :  /* "double":  Boolean indicating if the color buffer is
513                      double buffered */
514             glut_state_flag |= GLUT_DOUBLE ;
515             break ;
516 
517         case 8 :  /* "green":  Green color buffer precision in bits */
518             break ;
519 
520         case 9 :  /* "index":  Boolean if the color model is color index or not
521                    */
522             glut_state_flag |= GLUT_INDEX ;
523             break ;
524 
525         case 10 :  /* "num":  A special capability  name indicating where the
526                       value represents the Nth frame buffer configuration
527                       matching the description string */
528             break ;
529 
530         case 11 :  /* "red":  Red color buffer precision in bits */
531             break ;
532 
533         case 12 :  /* "rgba":  Number of bits of red, green, blue, and alpha in
534                       the RGBA color buffer */
535             glut_state_flag |= GLUT_RGBA ;  /* Somebody fix this for me! */
536             break ;
537 
538         case 13 :  /* "rgb":  Number of bits of red, green, and blue in the
539                       RGBA color buffer with zero bits alpha */
540             glut_state_flag |= GLUT_RGB ;  /* Somebody fix this for me! */
541             break ;
542 
543         case 14 :  /* "luminance":  Number of bits of red in the RGBA and zero
544                       bits of green, blue (alpha not specified) of color buffer
545                       precision */
546             glut_state_flag |= GLUT_LUMINANCE ; /* Somebody fix this for me! */
547             break ;
548 
549         case 15 :  /* "stencil":  Number of bits in the stencil buffer */
550             glut_state_flag |= GLUT_STENCIL;  /* Somebody fix this for me! */
551             break ;
552 
553         case 16 :  /* "single":  Boolean indicate the color buffer is single
554                       buffered */
555             glut_state_flag |= GLUT_SINGLE ;
556             break ;
557 
558         case 17 :  /* "stereo":  Boolean indicating the color buffer supports
559                       OpenGL-style stereo */
560             glut_state_flag |= GLUT_STEREO ;
561             break ;
562 
563         case 18 :  /* "samples":  Indicates the number of multisamples to use
564                       based on GLX's SGIS_multisample extension (for
565                       antialiasing) */
566             glut_state_flag |= GLUT_MULTISAMPLE ; /*Somebody fix this for me!*/
567             break ;
568 
569         case 19 :  /* "slow":  Boolean indicating if the frame buffer
570                       configuration is slow or not */
571             break ;
572 
573         case 20 :  /* "win32pdf": (incorrect spelling but was there before */
574         case 21 :  /* "win32pfd":  matches the Win32 Pixel Format Descriptor by
575                       number */
576 #if TARGET_HOST_MS_WINDOWS
577 #endif
578             break ;
579 
580         case 22 :  /* "xvisual":  matches the X visual ID by number */
581 #if TARGET_HOST_POSIX_X11
582 #endif
583             break ;
584 
585         case 23 :  /* "xstaticgray": */
586         case 29 :  /* "xstaticgrey":  boolean indicating if the frame buffer
587                       configuration's X visual is of type StaticGray */
588 #if TARGET_HOST_POSIX_X11
589 #endif
590             break ;
591 
592         case 24 :  /* "xgrayscale": */
593         case 30 :  /* "xgreyscale":  boolean indicating if the frame buffer
594                       configuration's X visual is of type GrayScale */
595 #if TARGET_HOST_POSIX_X11
596 #endif
597             break ;
598 
599         case 25 :  /* "xstaticcolor": */
600         case 31 :  /* "xstaticcolour":  boolean indicating if the frame buffer
601                       configuration's X visual is of type StaticColor */
602 #if TARGET_HOST_POSIX_X11
603 #endif
604             break ;
605 
606         case 26 :  /* "xpseudocolor": */
607         case 32 :  /* "xpseudocolour":  boolean indicating if the frame buffer
608                       configuration's X visual is of type PseudoColor */
609 #if TARGET_HOST_POSIX_X11
610 #endif
611             break ;
612 
613         case 27 :  /* "xtruecolor": */
614         case 33 :  /* "xtruecolour":  boolean indicating if the frame buffer
615                       configuration's X visual is of type TrueColor */
616 #if TARGET_HOST_POSIX_X11
617 #endif
618             break ;
619 
620         case 28 :  /* "xdirectcolor": */
621         case 34 :  /* "xdirectcolour":  boolean indicating if the frame buffer
622                       configuration's X visual is of type DirectColor */
623 #if TARGET_HOST_POSIX_X11
624 #endif
625             break ;
626 
627         case 35 :  /* "borderless":  windows should not have borders */
628             glut_state_flag |= GLUT_BORDERLESS;
629             break ;
630 
631         case 36 :  /* "aux":  some number of aux buffers */
632             glut_state_flag |= GLUT_AUX;
633             break ;
634 
635         case 37 :  /* Unrecognized */
636             fgWarning ( "WARNING - Display string token not recognized:  %s",
637                         token );
638             break ;
639         }
640 
641         token = strtok ( NULL, " \t" );
642     }
643 
644     free ( buffer );
645 
646     /* We will make use of this value when creating a new OpenGL context... */
647     fgState.DisplayMode = glut_state_flag;
648 }
649 
650 /* -- SETTING OPENGL 3.0 CONTEXT CREATION PARAMETERS ---------------------- */
651 
glutInitContextVersion(int majorVersion,int minorVersion)652 void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion )
653 {
654     /* We will make use of these value when creating a new OpenGL context... */
655     fgState.MajorVersion = majorVersion;
656     fgState.MinorVersion = minorVersion;
657 }
658 
659 
glutInitContextFlags(int flags)660 void FGAPIENTRY glutInitContextFlags( int flags )
661 {
662     /* We will make use of this value when creating a new OpenGL context... */
663     fgState.ContextFlags = flags;
664 }
665 
glutInitContextProfile(int profile)666 void FGAPIENTRY glutInitContextProfile( int profile )
667 {
668     /* We will make use of this value when creating a new OpenGL context... */
669     fgState.ContextProfile = profile;
670 }
671 
672 /* -------------- User Defined Error/Warning Handler Support -------------- */
673 
674 /*
675  * Sets the user error handler (note the use of va_list for the args to the fmt)
676  */
glutInitErrorFuncUcall(FGErrorUC callback,FGCBUserData userData)677 void FGAPIENTRY glutInitErrorFuncUcall( FGErrorUC callback, FGCBUserData userData )
678 {
679     /* This allows user programs to handle freeglut errors */
680     fgState.ErrorFunc = callback;
681     fgState.ErrorFuncData = userData;
682 }
683 
fghInitErrorFuncCallback(const char * fmt,va_list ap,FGCBUserData userData)684 static void fghInitErrorFuncCallback( const char *fmt, va_list ap, FGCBUserData userData )
685 {
686     FGError* callback = (FGError*)&userData;
687     (*callback)( fmt, ap );
688 }
689 
glutInitErrorFunc(FGError callback)690 void FGAPIENTRY glutInitErrorFunc( FGError callback )
691 {
692     if (callback)
693     {
694         FGError* reference = &callback;
695         glutInitErrorFuncUcall( fghInitErrorFuncCallback, *((FGCBUserData*)reference) );
696     }
697     else
698     {
699         glutInitErrorFuncUcall( NULL, NULL );
700     }
701 }
702 
703 /*
704  * Sets the user warning handler (note the use of va_list for the args to the fmt)
705  */
glutInitWarningFuncUcall(FGWarningUC callback,FGCBUserData userData)706 void FGAPIENTRY glutInitWarningFuncUcall( FGWarningUC callback, FGCBUserData userData )
707 {
708     /* This allows user programs to handle freeglut warnings */
709     fgState.WarningFunc = callback;
710     fgState.WarningFuncData = userData;
711 }
712 
fghInitWarningFuncCallback(const char * fmt,va_list ap,FGCBUserData userData)713 static void fghInitWarningFuncCallback( const char *fmt, va_list ap, FGCBUserData userData )
714 {
715     FGWarning* callback = (FGWarning*)&userData;
716     (*callback)( fmt, ap );
717 }
718 
glutInitWarningFunc(FGWarning callback)719 void FGAPIENTRY glutInitWarningFunc( FGWarning callback )
720 {
721     if (callback)
722     {
723         FGWarning* reference = &callback;
724         glutInitWarningFuncUcall( fghInitWarningFuncCallback, *((FGCBUserData*)reference) );
725     }
726     else
727     {
728         glutInitWarningFuncUcall( NULL, NULL );
729     }
730 }
731 
732 /*** END OF FILE ***/
733