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