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 */
50SFG_Display fgDisplay;
51
52/*
53 * The settings for the current freeglut session
54 */
55SFG_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
103extern void fgPlatformInitialize( const char* displayName );
104extern void fgPlatformDeinitialiseInputDevices ( void );
105extern void fgPlatformCloseDisplay ( void );
106extern void fgPlatformDestroyContext ( SFG_PlatformDisplay pDisplay, SFG_WindowContextType MContext );
107
108void 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
211void 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 */
224void 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 */
329void 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 */
387void FGAPIENTRY glutExit ( void )
388{
389 fgDeinitialize ();
390}
391
392/*
393 * Sets the default initial window position for new windows
394 */
395void 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 */
409void 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 */
423void 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
432static 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
444void 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
645void 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
653void 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
659void 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 */
670void 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 */
679void 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