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