4 * Various freeglut initialization functions.
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
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:
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
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.
28 #define FREEGLUT_BUILDING_LIB
29 #include <GL/freeglut.h>
30 #include "fg_internal.h"
33 * TODO BEFORE THE STABLE RELEASE:
35 * fgDeinitialize() -- Win32's OK, X11 needs the OS-specific
36 * deinitialization done
37 * glutInitDisplayString() -- display mode string parsing
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?
44 /* -- GLOBAL VARIABLES ----------------------------------------------------- */
47 * A structure pointed by fgDisplay holds all information
48 * regarding the display, screen, root window etc.
50 SFG_Display fgDisplay;
53 * The settings for the current freeglut session
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 */
70 { NULL, NULL }, /* Timers */
71 { NULL, NULL }, /* FreeTimers */
72 NULL, /* IdleCallback */
73 NULL, /* IdleCallbackData */
75 NULL, /* MenuStateCallback */
76 NULL, /* MenuStatusCallback */
77 NULL, /* MenuStatusCallbackData */
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 */
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 */
100 NULL, /* ErrorFuncData */
101 NULL, /* WarningFunc */
102 NULL /* WarningFuncData */
106 /* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
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 );
113 void fghParseCommandLineArguments ( int* pargc, char** argv, char **pDisplayName, char **pGeometry )
116 int i, j, argc = *pargc;
119 /* check if GLUT_FPS env var is set */
120 const char *fps = getenv( "GLUT_FPS" );
125 sscanf( fps, "%d", &interval );
128 fgState.FPSInterval = 5000; /* 5000 millisecond default */
130 fgState.FPSInterval = interval;
134 *pDisplayName = getenv( "DISPLAY" );
136 for( i = 1; i < argc; i++ )
138 if( strcmp( argv[ i ], "-display" ) == 0 )
141 fgError( "-display parameter must be followed by display name" );
143 *pDisplayName = argv[ i ];
145 argv[ i - 1 ] = NULL;
149 else if( strcmp( argv[ i ], "-geometry" ) == 0 )
152 fgError( "-geometry parameter must be followed by window "
153 "geometry settings" );
155 *pGeometry = argv[ i ];
157 argv[ i - 1 ] = NULL;
161 else if( strcmp( argv[ i ], "-direct" ) == 0)
163 if( fgState.DirectContext == GLUT_FORCE_INDIRECT_CONTEXT )
164 fgError( "parameters ambiguity, -direct and -indirect "
165 "cannot be both specified" );
167 fgState.DirectContext = GLUT_FORCE_DIRECT_CONTEXT;
171 else if( strcmp( argv[ i ], "-indirect" ) == 0 )
173 if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )
174 fgError( "parameters ambiguity, -direct and -indirect "
175 "cannot be both specified" );
177 fgState.DirectContext = GLUT_FORCE_INDIRECT_CONTEXT;
181 else if( strcmp( argv[ i ], "-iconic" ) == 0 )
183 fgState.ForceIconic = GL_TRUE;
187 else if( strcmp( argv[ i ], "-gldebug" ) == 0 )
189 fgState.GLDebugSwitch = GL_TRUE;
193 else if( strcmp( argv[ i ], "-sync" ) == 0 )
195 fgState.XSyncSwitch = GL_TRUE;
201 /* Compact {argv}. */
202 for( i = j = 1; i < *pargc; i++, j++ )
204 /* Guaranteed to end because there are "*pargc" arguments left */
205 while ( argv[ j ] == NULL )
208 argv[ i ] = argv[ j ];
211 #endif /* _WIN32_WCE */
216 void fghCloseInputDevices ( void )
218 if ( fgState.JoysticksInitialised )
221 if ( fgState.InputDevsInitialised )
222 fgInputDeviceClose( );
227 * Perform the freeglut deinitialization...
229 void fgDeinitialize( void )
233 if( !fgState.Initialised )
238 /* If we're in game mode, we want to leave game mode */
239 if( fgStructure.GameModeWindow ) {
243 /* If there was a menu created, destroy the rendering context */
244 if( fgStructure.MenuContext )
246 fgPlatformDestroyContext (fgDisplay.pDisplay, fgStructure.MenuContext->MContext );
247 free( fgStructure.MenuContext );
248 fgStructure.MenuContext = NULL;
251 fgDestroyStructure( );
253 while( ( timer = fgState.Timers.First) )
255 fgListRemove( &fgState.Timers, &timer->Node );
259 while( ( timer = fgState.FreeTimers.First) )
261 fgListRemove( &fgState.FreeTimers, &timer->Node );
265 fgPlatformDeinitialiseInputDevices ();
267 fgState.MouseWheelTicks = 0;
269 fgState.MajorVersion = 1;
270 fgState.MinorVersion = 0;
271 fgState.ContextFlags = 0;
272 fgState.ContextProfile = 0;
274 fgState.Initialised = GL_FALSE;
276 fgState.Position.X = -1;
277 fgState.Position.Y = -1;
278 fgState.Position.Use = GL_FALSE;
280 fgState.Size.X = 300;
281 fgState.Size.Y = 300;
282 fgState.Size.Use = GL_TRUE;
284 fgState.DisplayMode = GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH;
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;
294 fgState.KeyRepeat = GLUT_KEY_REPEAT_ON;
295 fgState.Modifiers = INVALID_MODIFIERS;
297 fgState.GameModeSize.X = -1;
298 fgState.GameModeSize.Y = -1;
299 fgState.GameModeDepth = -1;
300 fgState.GameModeRefresh = -1;
302 fgListInit( &fgState.Timers );
303 fgListInit( &fgState.FreeTimers );
305 fgState.IdleCallback = ( FGCBIdleUC )NULL;
306 fgState.IdleCallbackData = NULL;
307 fgState.MenuStateCallback = ( FGCBMenuState )NULL;
308 fgState.MenuStatusCallback = ( FGCBMenuStatusUC )NULL;
309 fgState.MenuStatusCallbackData = NULL;
311 fgState.SwapCount = 0;
312 fgState.SwapTime = 0;
313 fgState.FPSInterval = 0;
315 if( fgState.ProgramName )
317 free( fgState.ProgramName );
318 fgState.ProgramName = NULL;
321 fgPlatformCloseDisplay ();
323 fgState.Initialised = GL_FALSE;
327 /* -- INTERFACE FUNCTIONS -------------------------------------------------- */
328 #if defined(NEED_XPARSEGEOMETRY_IMPL) || defined(TARGET_HOST_MS_WINDOWS)
329 # include "util/xparsegeometry_repl.h"
333 * Perform initialization. This usually happens on the program startup
334 * and restarting after glutMainLoop termination...
336 void FGAPIENTRY glutInit( int* pargc, char** argv )
338 char* displayName = NULL;
339 char* geometry = NULL;
340 if( fgState.Initialised )
341 fgError( "illegal glutInit() reinitialization attempt" );
343 if (pargc && *pargc && argv && *argv && **argv)
345 fgState.ProgramName = strdup (*argv);
347 if( !fgState.ProgramName )
348 fgError ("Could not allocate space for the program's name.");
351 fgCreateStructure( );
353 fghParseCommandLineArguments ( pargc, argv, &displayName, &geometry );
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):
360 fgPlatformInitialize( displayName );
363 * Geometry parsing deferred until here because we may need the screen
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;
377 if( (mask & (WidthValue|HeightValue)) == (WidthValue|HeightValue) )
378 fgState.Size.Use = GL_TRUE;
380 if( ( mask & XNegative ) && !fgState.AllowNegativeWindowPosition )
381 fgState.Position.X += fgDisplay.ScreenWidth - fgState.Size.X;
383 if( ( mask & YNegative ) && !fgState.AllowNegativeWindowPosition )
384 fgState.Position.Y += fgDisplay.ScreenHeight - fgState.Size.Y;
386 if( (mask & (XValue|YValue)) == (XValue|YValue) )
387 fgState.Position.Use = GL_TRUE;
392 * Undoes all the "glutInit" stuff
394 void FGAPIENTRY glutExit ( void )
400 * Sets the default initial window position for new windows
402 void FGAPIENTRY glutInitWindowPosition( int x, int y )
404 fgState.Position.X = x;
405 fgState.Position.Y = y;
407 if( ( ( x >= 0 ) && ( y >= 0 ) ) || fgState.AllowNegativeWindowPosition )
408 fgState.Position.Use = GL_TRUE;
410 fgState.Position.Use = GL_FALSE;
414 * Sets the default initial window size for new windows
416 void FGAPIENTRY glutInitWindowSize( int width, int height )
418 fgState.Size.X = width;
419 fgState.Size.Y = height;
421 if( ( width > 0 ) && ( height > 0 ) )
422 fgState.Size.Use = GL_TRUE;
424 fgState.Size.Use = GL_FALSE;
428 * Sets the default display mode for all new windows
430 void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode )
432 /* We will make use of this value when creating a new OpenGL context... */
433 fgState.DisplayMode = displayMode;
437 /* -- INIT DISPLAY STRING PARSING ------------------------------------------ */
439 static char* Tokens[] =
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"
449 #define NUM_TOKENS (sizeof(Tokens) / sizeof(*Tokens))
451 void FGAPIENTRY glutInitDisplayString( const char* displayMode )
453 int glut_state_flag = 0 ;
455 * Unpack a lot of options from a character string. The options are
456 * delimited by blanks or tabs.
459 size_t len = strlen ( displayMode );
460 char *buffer = (char *)malloc ( (len+1) * sizeof(char) );
461 memcpy ( buffer, displayMode, len );
464 token = strtok ( buffer, " \t" );
468 /* Process this token */
471 /* Temporary fix: Ignore any length specifications and at least
472 * process the basic token
473 * TODO: Fix this permanently
475 size_t cleanlength = strcspn ( token, "=<>~!" );
477 for ( i = 0; i < NUM_TOKENS; i++ )
479 if ( strncmp ( token, Tokens[i], cleanlength ) == 0 ) break ;
484 case 0 : /* "alpha": Alpha color buffer precision in bits */
485 glut_state_flag |= GLUT_ALPHA ; /* Somebody fix this for me! */
488 case 1 : /* "acca": Red, green, blue, and alpha accumulation buffer
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! */
497 case 3 : /* "blue": Blue color buffer precision in bits */
500 case 4 : /* "buffer": Number of bits in the color index color buffer
504 case 5 : /* "conformant": Boolean indicating if the frame buffer
505 configuration is conformant or not */
508 case 6 : /* "depth": Number of bits of precision in the depth buffer */
509 glut_state_flag |= GLUT_DEPTH ; /* Somebody fix this for me! */
512 case 7 : /* "double": Boolean indicating if the color buffer is
514 glut_state_flag |= GLUT_DOUBLE ;
517 case 8 : /* "green": Green color buffer precision in bits */
520 case 9 : /* "index": Boolean if the color model is color index or not
522 glut_state_flag |= GLUT_INDEX ;
525 case 10 : /* "num": A special capability name indicating where the
526 value represents the Nth frame buffer configuration
527 matching the description string */
530 case 11 : /* "red": Red color buffer precision in bits */
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! */
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! */
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
546 glut_state_flag |= GLUT_LUMINANCE ; /* Somebody fix this for me! */
549 case 15 : /* "stencil": Number of bits in the stencil buffer */
550 glut_state_flag |= GLUT_STENCIL; /* Somebody fix this for me! */
553 case 16 : /* "single": Boolean indicate the color buffer is single
555 glut_state_flag |= GLUT_SINGLE ;
558 case 17 : /* "stereo": Boolean indicating the color buffer supports
559 OpenGL-style stereo */
560 glut_state_flag |= GLUT_STEREO ;
563 case 18 : /* "samples": Indicates the number of multisamples to use
564 based on GLX's SGIS_multisample extension (for
566 glut_state_flag |= GLUT_MULTISAMPLE ; /*Somebody fix this for me!*/
569 case 19 : /* "slow": Boolean indicating if the frame buffer
570 configuration is slow or not */
573 case 20 : /* "win32pdf": (incorrect spelling but was there before */
574 case 21 : /* "win32pfd": matches the Win32 Pixel Format Descriptor by
576 #if TARGET_HOST_MS_WINDOWS
580 case 22 : /* "xvisual": matches the X visual ID by number */
581 #if TARGET_HOST_POSIX_X11
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
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
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
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
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
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
627 case 35 : /* "borderless": windows should not have borders */
628 glut_state_flag |= GLUT_BORDERLESS;
631 case 36 : /* "aux": some number of aux buffers */
632 glut_state_flag |= GLUT_AUX;
635 case 37 : /* Unrecognized */
636 fgWarning ( "WARNING - Display string token not recognized: %s",
641 token = strtok ( NULL, " \t" );
646 /* We will make use of this value when creating a new OpenGL context... */
647 fgState.DisplayMode = glut_state_flag;
650 /* -- SETTING OPENGL 3.0 CONTEXT CREATION PARAMETERS ---------------------- */
652 void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion )
654 /* We will make use of these value when creating a new OpenGL context... */
655 fgState.MajorVersion = majorVersion;
656 fgState.MinorVersion = minorVersion;
660 void FGAPIENTRY glutInitContextFlags( int flags )
662 /* We will make use of this value when creating a new OpenGL context... */
663 fgState.ContextFlags = flags;
666 void FGAPIENTRY glutInitContextProfile( int profile )
668 /* We will make use of this value when creating a new OpenGL context... */
669 fgState.ContextProfile = profile;
672 /* -------------- User Defined Error/Warning Handler Support -------------- */
675 * Sets the user error handler (note the use of va_list for the args to the fmt)
677 void FGAPIENTRY glutInitErrorFuncUcall( FGErrorUC callback, FGCBUserData userData )
679 /* This allows user programs to handle freeglut errors */
680 fgState.ErrorFunc = callback;
681 fgState.ErrorFuncData = userData;
684 static void fghInitErrorFuncCallback( const char *fmt, va_list ap, FGCBUserData userData )
686 FGError* callback = (FGError*)&userData;
687 (*callback)( fmt, ap );
690 void FGAPIENTRY glutInitErrorFunc( FGError callback )
694 FGError* reference = &callback;
695 glutInitErrorFuncUcall( fghInitErrorFuncCallback, *((FGCBUserData*)reference) );
699 glutInitErrorFuncUcall( NULL, NULL );
704 * Sets the user warning handler (note the use of va_list for the args to the fmt)
706 void FGAPIENTRY glutInitWarningFuncUcall( FGWarningUC callback, FGCBUserData userData )
708 /* This allows user programs to handle freeglut warnings */
709 fgState.WarningFunc = callback;
710 fgState.WarningFuncData = userData;
713 static void fghInitWarningFuncCallback( const char *fmt, va_list ap, FGCBUserData userData )
715 FGWarning* callback = (FGWarning*)&userData;
716 (*callback)( fmt, ap );
719 void FGAPIENTRY glutInitWarningFunc( FGWarning callback )
723 FGWarning* reference = &callback;
724 glutInitWarningFuncUcall( fghInitWarningFuncCallback, *((FGCBUserData*)reference) );
728 glutInitWarningFuncUcall( NULL, NULL );
732 /*** END OF FILE ***/