mirror of
https://github.com/QB64Official/qb64.git
synced 2024-09-04 11:10:15 +00:00
1183 lines
36 KiB
C
1183 lines
36 KiB
C
#ifndef FREEGLUT_STATIC
|
|
#define FREEGLUT_STATIC
|
|
#endif
|
|
/*
|
|
* freeglut_init.c
|
|
*
|
|
* Various freeglut initialization functions.
|
|
*
|
|
* Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
|
|
* Written by Pawel W. Olszta, <olszta@sourceforge.net>
|
|
* Creation date: Thu Dec 2 1999
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#define FREEGLUT_BUILDING_LIB
|
|
#include "freeglut.h"
|
|
#include "freeglut_internal.h"
|
|
|
|
#if TARGET_HOST_POSIX_X11
|
|
#include <limits.h> /* LONG_MAX */
|
|
#endif
|
|
|
|
/*
|
|
* TODO BEFORE THE STABLE RELEASE:
|
|
*
|
|
* fgDeinitialize() -- Win32's OK, X11 needs the OS-specific
|
|
* deinitialization done
|
|
* glutInitDisplayString() -- display mode string parsing
|
|
*
|
|
* Wouldn't it be cool to use gettext() for error messages? I just love
|
|
* bash saying "nie znaleziono pliku" instead of "file not found" :)
|
|
* Is gettext easily portable?
|
|
*/
|
|
|
|
/* -- GLOBAL VARIABLES ----------------------------------------------------- */
|
|
|
|
/*
|
|
* A structure pointed by g_pDisplay holds all information
|
|
* regarding the display, screen, root window etc.
|
|
*/
|
|
SFG_Display fgDisplay;
|
|
|
|
/*
|
|
* The settings for the current freeglut session
|
|
*/
|
|
SFG_State fgState = { { -1, -1, GL_FALSE }, /* Position */
|
|
{ 300, 300, GL_TRUE }, /* Size */
|
|
GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH, /* DisplayMode */
|
|
GL_FALSE, /* Initialised */
|
|
GLUT_TRY_DIRECT_CONTEXT, /* DirectContext */
|
|
GL_FALSE, /* ForceIconic */
|
|
GL_FALSE, /* UseCurrentContext */
|
|
GL_FALSE, /* GLDebugSwitch */
|
|
GL_FALSE, /* XSyncSwitch */
|
|
GLUT_KEY_REPEAT_ON, /* KeyRepeat */
|
|
INVALID_MODIFIERS, /* Modifiers */
|
|
0, /* FPSInterval */
|
|
0, /* SwapCount */
|
|
0, /* SwapTime */
|
|
0, /* Time */
|
|
{ NULL, NULL }, /* Timers */
|
|
{ NULL, NULL }, /* FreeTimers */
|
|
NULL, /* IdleCallback */
|
|
0, /* ActiveMenus */
|
|
NULL, /* MenuStateCallback */
|
|
NULL, /* MenuStatusCallback */
|
|
{ 640, 480, GL_TRUE }, /* GameModeSize */
|
|
16, /* GameModeDepth */
|
|
72, /* GameModeRefresh */
|
|
GLUT_ACTION_EXIT, /* ActionOnWindowClose */
|
|
GLUT_EXEC_STATE_INIT, /* ExecState */
|
|
NULL, /* ProgramName */
|
|
GL_FALSE, /* JoysticksInitialised */
|
|
0, /* NumActiveJoysticks */
|
|
GL_FALSE, /* InputDevsInitialised */
|
|
0, /* MouseWheelTicks */
|
|
1, /* AuxiliaryBufferNumber */
|
|
4, /* SampleNumber */
|
|
1, /* MajorVersion */
|
|
0, /* MinorVersion */
|
|
0, /* ContextFlags */
|
|
0, /* ContextProfile */
|
|
NULL, /* ErrorFunc */
|
|
NULL /* WarningFunc */
|
|
};
|
|
|
|
|
|
/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */
|
|
|
|
#if TARGET_HOST_POSIX_X11
|
|
|
|
/* Return the atom associated with "name". */
|
|
static Atom fghGetAtom(const char * name)
|
|
{
|
|
return XInternAtom(fgDisplay.Display, name, False);
|
|
}
|
|
|
|
/*
|
|
* Check if "property" is set on "window". The property's values are returned
|
|
* through "data". If the property is set and is of type "type", return the
|
|
* number of elements in "data". Return zero otherwise. In both cases, use
|
|
* "Xfree()" to free "data".
|
|
*/
|
|
static int fghGetWindowProperty(Window window,
|
|
Atom property,
|
|
Atom type,
|
|
unsigned char ** data)
|
|
{
|
|
/*
|
|
* Caller always has to use "Xfree()" to free "data", since
|
|
* "XGetWindowProperty() always allocates one extra byte in prop_return
|
|
* [i.e. "data"] (even if the property is zero length) [..]".
|
|
*/
|
|
|
|
int status; /* Returned by "XGetWindowProperty". */
|
|
|
|
Atom type_returned;
|
|
int temp_format; /* Not used. */
|
|
unsigned long number_of_elements;
|
|
unsigned long temp_bytes_after; /* Not used. */
|
|
|
|
|
|
status = XGetWindowProperty(fgDisplay.Display,
|
|
window,
|
|
property,
|
|
0,
|
|
LONG_MAX,
|
|
False,
|
|
type,
|
|
&type_returned,
|
|
&temp_format,
|
|
&number_of_elements,
|
|
&temp_bytes_after,
|
|
data);
|
|
|
|
FREEGLUT_INTERNAL_ERROR_EXIT(status == Success,
|
|
"XGetWindowProperty failled",
|
|
"fghGetWindowProperty");
|
|
|
|
if (type_returned != type)
|
|
{
|
|
number_of_elements = 0;
|
|
}
|
|
|
|
return number_of_elements;
|
|
}
|
|
|
|
/* Check if the window manager is NET WM compliant. */
|
|
static int fghNetWMSupported(void)
|
|
{
|
|
Atom wm_check;
|
|
Window ** window_ptr_1;
|
|
|
|
int number_of_windows;
|
|
int net_wm_supported;
|
|
|
|
|
|
net_wm_supported = 0;
|
|
|
|
wm_check = fghGetAtom("_NET_SUPPORTING_WM_CHECK");
|
|
window_ptr_1 = malloc(sizeof(Window *));
|
|
|
|
/*
|
|
* Check that the window manager has set this property on the root window.
|
|
* The property must be the ID of a child window.
|
|
*/
|
|
number_of_windows = fghGetWindowProperty(fgDisplay.RootWindow,
|
|
wm_check,
|
|
XA_WINDOW,
|
|
(unsigned char **) window_ptr_1);
|
|
if (number_of_windows == 1)
|
|
{
|
|
Window ** window_ptr_2;
|
|
|
|
window_ptr_2 = malloc(sizeof(Window *));
|
|
|
|
/* Check that the window has the same property set to the same value. */
|
|
number_of_windows = fghGetWindowProperty(**window_ptr_1,
|
|
wm_check,
|
|
XA_WINDOW,
|
|
(unsigned char **) window_ptr_2);
|
|
if ((number_of_windows == 1) && (**window_ptr_1 == **window_ptr_2))
|
|
{
|
|
/* NET WM compliant */
|
|
net_wm_supported = 1;
|
|
}
|
|
|
|
XFree(*window_ptr_2);
|
|
free(window_ptr_2);
|
|
}
|
|
|
|
XFree(*window_ptr_1);
|
|
free(window_ptr_1);
|
|
|
|
return net_wm_supported;
|
|
}
|
|
|
|
/* Check if "hint" is present in "property" for "window". */
|
|
int fgHintPresent(Window window, Atom property, Atom hint)
|
|
{
|
|
Atom *atoms;
|
|
int number_of_atoms;
|
|
int supported;
|
|
int i;
|
|
|
|
supported = 0;
|
|
|
|
number_of_atoms = fghGetWindowProperty(window,
|
|
property,
|
|
XA_ATOM,
|
|
(unsigned char **) &atoms);
|
|
for (i = 0; i < number_of_atoms; i++)
|
|
{
|
|
if (atoms[i] == hint)
|
|
{
|
|
supported = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
XFree(atoms);
|
|
return supported;
|
|
}
|
|
|
|
#endif /* TARGET_HOST_POSIX_X11 */
|
|
|
|
|
|
/*
|
|
* A call to this function should initialize all the display stuff...
|
|
*/
|
|
static void fghInitialize( const char* displayName )
|
|
{
|
|
#if TARGET_HOST_POSIX_X11
|
|
fgDisplay.Display = XOpenDisplay( displayName );
|
|
|
|
if( fgDisplay.Display == NULL )
|
|
fgError( "failed to open display '%s'", XDisplayName( displayName ) );
|
|
|
|
if( !glXQueryExtension( fgDisplay.Display, NULL, NULL ) )
|
|
fgError( "OpenGL GLX extension not supported by display '%s'",
|
|
XDisplayName( displayName ) );
|
|
|
|
fgDisplay.Screen = DefaultScreen( fgDisplay.Display );
|
|
fgDisplay.RootWindow = RootWindow(
|
|
fgDisplay.Display,
|
|
fgDisplay.Screen
|
|
);
|
|
|
|
fgDisplay.ScreenWidth = DisplayWidth(
|
|
fgDisplay.Display,
|
|
fgDisplay.Screen
|
|
);
|
|
fgDisplay.ScreenHeight = DisplayHeight(
|
|
fgDisplay.Display,
|
|
fgDisplay.Screen
|
|
);
|
|
|
|
fgDisplay.ScreenWidthMM = DisplayWidthMM(
|
|
fgDisplay.Display,
|
|
fgDisplay.Screen
|
|
);
|
|
fgDisplay.ScreenHeightMM = DisplayHeightMM(
|
|
fgDisplay.Display,
|
|
fgDisplay.Screen
|
|
);
|
|
|
|
fgDisplay.Connection = ConnectionNumber( fgDisplay.Display );
|
|
|
|
/* Create the window deletion atom */
|
|
fgDisplay.DeleteWindow = fghGetAtom("WM_DELETE_WINDOW");
|
|
|
|
/* Create the state and full screen atoms */
|
|
fgDisplay.State = None;
|
|
fgDisplay.StateFullScreen = None;
|
|
|
|
if (fghNetWMSupported())
|
|
{
|
|
const Atom supported = fghGetAtom("_NET_SUPPORTED");
|
|
const Atom state = fghGetAtom("_NET_WM_STATE");
|
|
|
|
/* Check if the state hint is supported. */
|
|
if (fgHintPresent(fgDisplay.RootWindow, supported, state))
|
|
{
|
|
const Atom full_screen = fghGetAtom("_NET_WM_STATE_FULLSCREEN");
|
|
|
|
fgDisplay.State = state;
|
|
|
|
/* Check if the window manager supports full screen. */
|
|
/** Check "_NET_WM_ALLOWED_ACTIONS" on our window instead? **/
|
|
if (fgHintPresent(fgDisplay.RootWindow, supported, full_screen))
|
|
{
|
|
fgDisplay.StateFullScreen = full_screen;
|
|
}
|
|
}
|
|
}
|
|
|
|
#elif TARGET_HOST_MS_WINDOWS
|
|
|
|
WNDCLASS wc;
|
|
ATOM atom;
|
|
|
|
/* What we need to do is to initialize the fgDisplay global structure here. */
|
|
fgDisplay.Instance = GetModuleHandle( NULL );
|
|
fgDisplay.DisplayName= displayName ? strdup(displayName) : 0 ;
|
|
atom = GetClassInfo( fgDisplay.Instance, _T("FREEGLUT"), &wc );
|
|
|
|
if( atom == 0 )
|
|
{
|
|
ZeroMemory( &wc, sizeof(WNDCLASS) );
|
|
|
|
/*
|
|
* Each of the windows should have its own device context, and we
|
|
* want redraw events during Vertical and Horizontal Resizes by
|
|
* the user.
|
|
*
|
|
* XXX Old code had "| CS_DBCLCKS" commented out. Plans for the
|
|
* XXX future? Dead-end idea?
|
|
*/
|
|
wc.lpfnWndProc = fgWindowProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = fgDisplay.Instance;
|
|
wc.hIcon = LoadIcon( fgDisplay.Instance, _T("GLUT_ICON") );
|
|
|
|
#if defined(_WIN32_WCE)
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
#else
|
|
wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
|
|
if (!wc.hIcon)
|
|
wc.hIcon = LoadIcon( NULL, IDI_WINLOGO );
|
|
#endif
|
|
|
|
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
|
|
wc.hbrBackground = NULL;
|
|
wc.lpszMenuName = NULL;
|
|
wc.lpszClassName = _T("FREEGLUT");
|
|
|
|
/* Register the window class */
|
|
atom = RegisterClass( &wc );
|
|
FREEGLUT_INTERNAL_ERROR_EXIT ( atom, "Window Class Not Registered", "fghInitialize" );
|
|
}
|
|
|
|
/* The screen dimensions can be obtained via GetSystemMetrics() calls */
|
|
fgDisplay.ScreenWidth = GetSystemMetrics( SM_CXSCREEN );
|
|
fgDisplay.ScreenHeight = GetSystemMetrics( SM_CYSCREEN );
|
|
|
|
{
|
|
HWND desktop = GetDesktopWindow( );
|
|
HDC context = GetDC( desktop );
|
|
|
|
fgDisplay.ScreenWidthMM = GetDeviceCaps( context, HORZSIZE );
|
|
fgDisplay.ScreenHeightMM = GetDeviceCaps( context, VERTSIZE );
|
|
|
|
ReleaseDC( desktop, context );
|
|
}
|
|
/* If we have a DisplayName try to use it for metrics */
|
|
if( fgDisplay.DisplayName )
|
|
{
|
|
HDC context = CreateDC(fgDisplay.DisplayName,0,0,0);
|
|
if( context )
|
|
{
|
|
fgDisplay.ScreenWidth = GetDeviceCaps( context, HORZRES );
|
|
fgDisplay.ScreenHeight = GetDeviceCaps( context, VERTRES );
|
|
fgDisplay.ScreenWidthMM = GetDeviceCaps( context, HORZSIZE );
|
|
fgDisplay.ScreenHeightMM = GetDeviceCaps( context, VERTSIZE );
|
|
DeleteDC(context);
|
|
}
|
|
else
|
|
fgWarning("fghInitialize: "
|
|
"CreateDC failed, Screen size info may be incorrect\n"
|
|
"This is quite likely caused by a bad '-display' parameter");
|
|
|
|
}
|
|
/* Set the timer granularity to 1 ms */
|
|
timeBeginPeriod ( 1 );
|
|
|
|
#endif
|
|
|
|
fgState.Initialised = GL_TRUE;
|
|
|
|
/* Avoid registering atexit callback on Win32 as it results in an access
|
|
* violation due to calling into a module which has been unloaded. */
|
|
#if ( TARGET_HOST_MS_WINDOWS == 0 )
|
|
atexit(fgDeinitialize);
|
|
#endif
|
|
|
|
/* InputDevice uses GlutTimerFunc(), so fgState.Initialised must be TRUE */
|
|
fgInitialiseInputDevices();
|
|
}
|
|
|
|
/*
|
|
* Perform the freeglut deinitialization...
|
|
*/
|
|
void fgDeinitialize( void )
|
|
{
|
|
SFG_Timer *timer;
|
|
|
|
if( !fgState.Initialised )
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* If we're in game mode, we want to leave game mode */
|
|
if( fgStructure.GameModeWindow ) {
|
|
glutLeaveGameMode();
|
|
}
|
|
|
|
/* If there was a menu created, destroy the rendering context */
|
|
if( fgStructure.MenuContext )
|
|
{
|
|
#if TARGET_HOST_POSIX_X11
|
|
/* Note that the MVisualInfo is not owned by the MenuContext! */
|
|
glXDestroyContext( fgDisplay.Display, fgStructure.MenuContext->MContext );
|
|
#endif
|
|
free( fgStructure.MenuContext );
|
|
fgStructure.MenuContext = NULL;
|
|
}
|
|
|
|
fgDestroyStructure( );
|
|
|
|
while( ( timer = fgState.Timers.First) )
|
|
{
|
|
fgListRemove( &fgState.Timers, &timer->Node );
|
|
free( timer );
|
|
}
|
|
|
|
while( ( timer = fgState.FreeTimers.First) )
|
|
{
|
|
fgListRemove( &fgState.FreeTimers, &timer->Node );
|
|
free( timer );
|
|
}
|
|
|
|
#if !defined(_WIN32_WCE)
|
|
if ( fgState.JoysticksInitialised )
|
|
fgJoystickClose( );
|
|
|
|
if ( fgState.InputDevsInitialised )
|
|
fgInputDeviceClose( );
|
|
#endif /* !defined(_WIN32_WCE) */
|
|
fgState.JoysticksInitialised = GL_FALSE;
|
|
fgState.InputDevsInitialised = GL_FALSE;
|
|
|
|
fgState.MouseWheelTicks = 0;
|
|
|
|
fgState.MajorVersion = 1;
|
|
fgState.MinorVersion = 0;
|
|
fgState.ContextFlags = 0;
|
|
fgState.ContextProfile = 0;
|
|
|
|
fgState.Initialised = GL_FALSE;
|
|
|
|
fgState.Position.X = -1;
|
|
fgState.Position.Y = -1;
|
|
fgState.Position.Use = GL_FALSE;
|
|
|
|
fgState.Size.X = 300;
|
|
fgState.Size.Y = 300;
|
|
fgState.Size.Use = GL_TRUE;
|
|
|
|
fgState.DisplayMode = GLUT_RGBA | GLUT_SINGLE | GLUT_DEPTH;
|
|
|
|
fgState.DirectContext = GLUT_TRY_DIRECT_CONTEXT;
|
|
fgState.ForceIconic = GL_FALSE;
|
|
fgState.UseCurrentContext = GL_FALSE;
|
|
fgState.GLDebugSwitch = GL_FALSE;
|
|
fgState.XSyncSwitch = GL_FALSE;
|
|
fgState.ActionOnWindowClose = GLUT_ACTION_EXIT;
|
|
fgState.ExecState = GLUT_EXEC_STATE_INIT;
|
|
|
|
fgState.KeyRepeat = GLUT_KEY_REPEAT_ON;
|
|
fgState.Modifiers = INVALID_MODIFIERS;
|
|
|
|
fgState.GameModeSize.X = 640;
|
|
fgState.GameModeSize.Y = 480;
|
|
fgState.GameModeDepth = 16;
|
|
fgState.GameModeRefresh = 72;
|
|
|
|
fgListInit( &fgState.Timers );
|
|
fgListInit( &fgState.FreeTimers );
|
|
|
|
fgState.IdleCallback = NULL;
|
|
fgState.MenuStateCallback = ( FGCBMenuState )NULL;
|
|
fgState.MenuStatusCallback = ( FGCBMenuStatus )NULL;
|
|
|
|
fgState.SwapCount = 0;
|
|
fgState.SwapTime = 0;
|
|
fgState.FPSInterval = 0;
|
|
|
|
if( fgState.ProgramName )
|
|
{
|
|
free( fgState.ProgramName );
|
|
fgState.ProgramName = NULL;
|
|
}
|
|
|
|
#if TARGET_HOST_POSIX_X11
|
|
|
|
/*
|
|
* Make sure all X-client data we have created will be destroyed on
|
|
* display closing
|
|
*/
|
|
XSetCloseDownMode( fgDisplay.Display, DestroyAll );
|
|
|
|
/*
|
|
* Close the display connection, destroying all windows we have
|
|
* created so far
|
|
*/
|
|
XCloseDisplay( fgDisplay.Display );
|
|
|
|
#elif TARGET_HOST_MS_WINDOWS
|
|
if( fgDisplay.DisplayName )
|
|
{
|
|
free( fgDisplay.DisplayName );
|
|
fgDisplay.DisplayName = NULL;
|
|
}
|
|
|
|
/* Reset the timer granularity */
|
|
timeEndPeriod ( 1 );
|
|
|
|
#endif
|
|
|
|
fgState.Initialised = GL_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Everything inside the following #ifndef is copied from the X sources.
|
|
*/
|
|
|
|
#if TARGET_HOST_MS_WINDOWS
|
|
|
|
/*
|
|
|
|
Copyright 1985, 1986, 1987,1998 The Open Group
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
the above copyright notice appear in all copies and that both that
|
|
copyright notice and this permission notice appear in supporting
|
|
documentation.
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall
|
|
not be used in advertising or otherwise to promote the sale, use or
|
|
other dealings in this Software without prior written authorization
|
|
from The Open Group.
|
|
|
|
*/
|
|
|
|
#define NoValue 0x0000
|
|
#define XValue 0x0001
|
|
#define YValue 0x0002
|
|
#define WidthValue 0x0004
|
|
#define HeightValue 0x0008
|
|
#define AllValues 0x000F
|
|
#define XNegative 0x0010
|
|
#define YNegative 0x0020
|
|
|
|
/*
|
|
* XParseGeometry parses strings of the form
|
|
* "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
|
|
* width, height, xoffset, and yoffset are unsigned integers.
|
|
* Example: "=80x24+300-49"
|
|
* The equal sign is optional.
|
|
* It returns a bitmask that indicates which of the four values
|
|
* were actually found in the string. For each value found,
|
|
* the corresponding argument is updated; for each value
|
|
* not found, the corresponding argument is left unchanged.
|
|
*/
|
|
|
|
static int
|
|
ReadInteger(char *string, char **NextString)
|
|
{
|
|
register int Result = 0;
|
|
int Sign = 1;
|
|
|
|
if (*string == '+')
|
|
string++;
|
|
else if (*string == '-')
|
|
{
|
|
string++;
|
|
Sign = -1;
|
|
}
|
|
for (; (*string >= '0') && (*string <= '9'); string++)
|
|
{
|
|
Result = (Result * 10) + (*string - '0');
|
|
}
|
|
*NextString = string;
|
|
if (Sign >= 0)
|
|
return Result;
|
|
else
|
|
return -Result;
|
|
}
|
|
|
|
static int XParseGeometry (
|
|
const char *string,
|
|
int *x,
|
|
int *y,
|
|
unsigned int *width, /* RETURN */
|
|
unsigned int *height) /* RETURN */
|
|
{
|
|
int mask = NoValue;
|
|
register char *strind;
|
|
unsigned int tempWidth = 0, tempHeight = 0;
|
|
int tempX = 0, tempY = 0;
|
|
char *nextCharacter;
|
|
|
|
if ( (string == NULL) || (*string == '\0'))
|
|
return mask;
|
|
if (*string == '=')
|
|
string++; /* ignore possible '=' at beg of geometry spec */
|
|
|
|
strind = (char *)string;
|
|
if (*strind != '+' && *strind != '-' && *strind != 'x') {
|
|
tempWidth = ReadInteger(strind, &nextCharacter);
|
|
if (strind == nextCharacter)
|
|
return 0;
|
|
strind = nextCharacter;
|
|
mask |= WidthValue;
|
|
}
|
|
|
|
if (*strind == 'x' || *strind == 'X') {
|
|
strind++;
|
|
tempHeight = ReadInteger(strind, &nextCharacter);
|
|
if (strind == nextCharacter)
|
|
return 0;
|
|
strind = nextCharacter;
|
|
mask |= HeightValue;
|
|
}
|
|
|
|
if ((*strind == '+') || (*strind == '-')) {
|
|
if (*strind == '-') {
|
|
strind++;
|
|
tempX = -ReadInteger(strind, &nextCharacter);
|
|
if (strind == nextCharacter)
|
|
return 0;
|
|
strind = nextCharacter;
|
|
mask |= XNegative;
|
|
}
|
|
else
|
|
{
|
|
strind++;
|
|
tempX = ReadInteger(strind, &nextCharacter);
|
|
if (strind == nextCharacter)
|
|
return 0;
|
|
strind = nextCharacter;
|
|
}
|
|
mask |= XValue;
|
|
if ((*strind == '+') || (*strind == '-')) {
|
|
if (*strind == '-') {
|
|
strind++;
|
|
tempY = -ReadInteger(strind, &nextCharacter);
|
|
if (strind == nextCharacter)
|
|
return 0;
|
|
strind = nextCharacter;
|
|
mask |= YNegative;
|
|
}
|
|
else
|
|
{
|
|
strind++;
|
|
tempY = ReadInteger(strind, &nextCharacter);
|
|
if (strind == nextCharacter)
|
|
return 0;
|
|
strind = nextCharacter;
|
|
}
|
|
mask |= YValue;
|
|
}
|
|
}
|
|
|
|
/* If strind isn't at the end of the string the it's an invalid
|
|
geometry specification. */
|
|
|
|
if (*strind != '\0') return 0;
|
|
|
|
if (mask & XValue)
|
|
*x = tempX;
|
|
if (mask & YValue)
|
|
*y = tempY;
|
|
if (mask & WidthValue)
|
|
*width = tempWidth;
|
|
if (mask & HeightValue)
|
|
*height = tempHeight;
|
|
return mask;
|
|
}
|
|
#endif
|
|
|
|
/* -- INTERFACE FUNCTIONS -------------------------------------------------- */
|
|
|
|
/*
|
|
* Perform initialization. This usually happens on the program startup
|
|
* and restarting after glutMainLoop termination...
|
|
*/
|
|
void FGAPIENTRY glutInit( int* pargc, char** argv )
|
|
{
|
|
char* displayName = NULL;
|
|
char* geometry = NULL;
|
|
int i, j, argc = *pargc;
|
|
|
|
if( fgState.Initialised )
|
|
fgError( "illegal glutInit() reinitialization attempt" );
|
|
|
|
if (pargc && *pargc && argv && *argv && **argv)
|
|
{
|
|
fgState.ProgramName = strdup (*argv);
|
|
|
|
if( !fgState.ProgramName )
|
|
fgError ("Could not allocate space for the program's name.");
|
|
}
|
|
|
|
fgCreateStructure( );
|
|
|
|
/* Get start time */
|
|
fgState.Time = fgSystemTime();
|
|
|
|
/* check if GLUT_FPS env var is set */
|
|
#ifndef _WIN32_WCE
|
|
{
|
|
const char *fps = getenv( "GLUT_FPS" );
|
|
|
|
if( fps )
|
|
{
|
|
int interval;
|
|
sscanf( fps, "%d", &interval );
|
|
|
|
if( interval <= 0 )
|
|
fgState.FPSInterval = 5000; /* 5000 millisecond default */
|
|
else
|
|
fgState.FPSInterval = interval;
|
|
}
|
|
}
|
|
|
|
displayName = getenv( "DISPLAY" );
|
|
|
|
for( i = 1; i < argc; i++ )
|
|
{
|
|
if( strcmp( argv[ i ], "-display" ) == 0 )
|
|
{
|
|
if( ++i >= argc )
|
|
fgError( "-display parameter must be followed by display name" );
|
|
|
|
displayName = argv[ i ];
|
|
|
|
argv[ i - 1 ] = NULL;
|
|
argv[ i ] = NULL;
|
|
( *pargc ) -= 2;
|
|
}
|
|
else if( strcmp( argv[ i ], "-geometry" ) == 0 )
|
|
{
|
|
if( ++i >= argc )
|
|
fgError( "-geometry parameter must be followed by window "
|
|
"geometry settings" );
|
|
|
|
geometry = argv[ i ];
|
|
|
|
argv[ i - 1 ] = NULL;
|
|
argv[ i ] = NULL;
|
|
( *pargc ) -= 2;
|
|
}
|
|
else if( strcmp( argv[ i ], "-direct" ) == 0)
|
|
{
|
|
if( fgState.DirectContext == GLUT_FORCE_INDIRECT_CONTEXT )
|
|
fgError( "parameters ambiguity, -direct and -indirect "
|
|
"cannot be both specified" );
|
|
|
|
fgState.DirectContext = GLUT_FORCE_DIRECT_CONTEXT;
|
|
argv[ i ] = NULL;
|
|
( *pargc )--;
|
|
}
|
|
else if( strcmp( argv[ i ], "-indirect" ) == 0 )
|
|
{
|
|
if( fgState.DirectContext == GLUT_FORCE_DIRECT_CONTEXT )
|
|
fgError( "parameters ambiguity, -direct and -indirect "
|
|
"cannot be both specified" );
|
|
|
|
fgState.DirectContext = GLUT_FORCE_INDIRECT_CONTEXT;
|
|
argv[ i ] = NULL;
|
|
(*pargc)--;
|
|
}
|
|
else if( strcmp( argv[ i ], "-iconic" ) == 0 )
|
|
{
|
|
fgState.ForceIconic = GL_TRUE;
|
|
argv[ i ] = NULL;
|
|
( *pargc )--;
|
|
}
|
|
else if( strcmp( argv[ i ], "-gldebug" ) == 0 )
|
|
{
|
|
fgState.GLDebugSwitch = GL_TRUE;
|
|
argv[ i ] = NULL;
|
|
( *pargc )--;
|
|
}
|
|
else if( strcmp( argv[ i ], "-sync" ) == 0 )
|
|
{
|
|
fgState.XSyncSwitch = GL_TRUE;
|
|
argv[ i ] = NULL;
|
|
( *pargc )--;
|
|
}
|
|
}
|
|
|
|
/* Compact {argv}. */
|
|
for( i = j = 1; i < *pargc; i++, j++ )
|
|
{
|
|
/* Guaranteed to end because there are "*pargc" arguments left */
|
|
while ( argv[ j ] == NULL )
|
|
j++;
|
|
if ( i != j )
|
|
argv[ i ] = argv[ j ];
|
|
}
|
|
|
|
#endif /* _WIN32_WCE */
|
|
|
|
/*
|
|
* Have the display created now. If there wasn't a "-display"
|
|
* in the program arguments, we will use the DISPLAY environment
|
|
* variable for opening the X display (see code above):
|
|
*/
|
|
fghInitialize( displayName );
|
|
|
|
/*
|
|
* Geometry parsing deffered until here because we may need the screen
|
|
* size.
|
|
*/
|
|
|
|
if (geometry )
|
|
{
|
|
unsigned int parsedWidth, parsedHeight;
|
|
int mask = XParseGeometry( geometry,
|
|
&fgState.Position.X, &fgState.Position.Y,
|
|
&parsedWidth, &parsedHeight );
|
|
/* TODO: Check for overflow? */
|
|
fgState.Size.X = parsedWidth;
|
|
fgState.Size.Y = parsedHeight;
|
|
|
|
if( (mask & (WidthValue|HeightValue)) == (WidthValue|HeightValue) )
|
|
fgState.Size.Use = GL_TRUE;
|
|
|
|
if( mask & XNegative )
|
|
fgState.Position.X += fgDisplay.ScreenWidth - fgState.Size.X;
|
|
|
|
if( mask & YNegative )
|
|
fgState.Position.Y += fgDisplay.ScreenHeight - fgState.Size.Y;
|
|
|
|
if( (mask & (XValue|YValue)) == (XValue|YValue) )
|
|
fgState.Position.Use = GL_TRUE;
|
|
}
|
|
}
|
|
|
|
#if TARGET_HOST_MS_WINDOWS
|
|
void (__cdecl *__glutExitFunc)( int return_value ) = NULL;
|
|
|
|
void FGAPIENTRY __glutInitWithExit( int *pargc, char **argv, void (__cdecl *exit_function)(int) )
|
|
{
|
|
__glutExitFunc = exit_function;
|
|
glutInit(pargc, argv);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Undoes all the "glutInit" stuff
|
|
*/
|
|
void FGAPIENTRY glutExit ( void )
|
|
{
|
|
fgDeinitialize ();
|
|
}
|
|
|
|
/*
|
|
* Sets the default initial window position for new windows
|
|
*/
|
|
void FGAPIENTRY glutInitWindowPosition( int x, int y )
|
|
{
|
|
fgState.Position.X = x;
|
|
fgState.Position.Y = y;
|
|
|
|
if( ( x >= 0 ) && ( y >= 0 ) )
|
|
fgState.Position.Use = GL_TRUE;
|
|
else
|
|
fgState.Position.Use = GL_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Sets the default initial window size for new windows
|
|
*/
|
|
void FGAPIENTRY glutInitWindowSize( int width, int height )
|
|
{
|
|
fgState.Size.X = width;
|
|
fgState.Size.Y = height;
|
|
|
|
if( ( width > 0 ) && ( height > 0 ) )
|
|
fgState.Size.Use = GL_TRUE;
|
|
else
|
|
fgState.Size.Use = GL_FALSE;
|
|
}
|
|
|
|
/*
|
|
* Sets the default display mode for all new windows
|
|
*/
|
|
void FGAPIENTRY glutInitDisplayMode( unsigned int displayMode )
|
|
{
|
|
/* We will make use of this value when creating a new OpenGL context... */
|
|
fgState.DisplayMode = displayMode;
|
|
}
|
|
|
|
|
|
/* -- INIT DISPLAY STRING PARSING ------------------------------------------ */
|
|
|
|
static char* Tokens[] =
|
|
{
|
|
"alpha", "acca", "acc", "blue", "buffer", "conformant", "depth", "double",
|
|
"green", "index", "num", "red", "rgba", "rgb", "luminance", "stencil",
|
|
"single", "stereo", "samples", "slow", "win32pdf", "win32pfd", "xvisual",
|
|
"xstaticgray", "xgrayscale", "xstaticcolor", "xpseudocolor",
|
|
"xtruecolor", "xdirectcolor",
|
|
"xstaticgrey", "xgreyscale", "xstaticcolour", "xpseudocolour",
|
|
"xtruecolour", "xdirectcolour", "borderless", "aux"
|
|
};
|
|
#define NUM_TOKENS (sizeof(Tokens) / sizeof(*Tokens))
|
|
|
|
void FGAPIENTRY glutInitDisplayString( const char* displayMode )
|
|
{
|
|
int glut_state_flag = 0 ;
|
|
/*
|
|
* Unpack a lot of options from a character string. The options are
|
|
* delimited by blanks or tabs.
|
|
*/
|
|
char *token ;
|
|
size_t len = strlen ( displayMode );
|
|
char *buffer = (char *)malloc ( (len+1) * sizeof(char) );
|
|
memcpy ( buffer, displayMode, len );
|
|
buffer[len] = '\0';
|
|
|
|
token = strtok ( buffer, " \t" );
|
|
|
|
while ( token )
|
|
{
|
|
/* Process this token */
|
|
int i ;
|
|
|
|
/* Temporary fix: Ignore any length specifications and at least
|
|
* process the basic token
|
|
* TODO: Fix this permanently
|
|
*/
|
|
size_t cleanlength = strcspn ( token, "=<>~!" );
|
|
|
|
for ( i = 0; i < NUM_TOKENS; i++ )
|
|
{
|
|
if ( strncmp ( token, Tokens[i], cleanlength ) == 0 ) break ;
|
|
}
|
|
|
|
switch ( i )
|
|
{
|
|
case 0 : /* "alpha": Alpha color buffer precision in bits */
|
|
glut_state_flag |= GLUT_ALPHA ; /* Somebody fix this for me! */
|
|
break ;
|
|
|
|
case 1 : /* "acca": Red, green, blue, and alpha accumulation buffer
|
|
precision in bits */
|
|
break ;
|
|
|
|
case 2 : /* "acc": Red, green, and blue accumulation buffer precision
|
|
in bits with zero bits alpha */
|
|
glut_state_flag |= GLUT_ACCUM ; /* Somebody fix this for me! */
|
|
break ;
|
|
|
|
case 3 : /* "blue": Blue color buffer precision in bits */
|
|
break ;
|
|
|
|
case 4 : /* "buffer": Number of bits in the color index color buffer
|
|
*/
|
|
break ;
|
|
|
|
case 5 : /* "conformant": Boolean indicating if the frame buffer
|
|
configuration is conformant or not */
|
|
break ;
|
|
|
|
case 6 : /* "depth": Number of bits of precsion in the depth buffer */
|
|
glut_state_flag |= GLUT_DEPTH ; /* Somebody fix this for me! */
|
|
break ;
|
|
|
|
case 7 : /* "double": Boolean indicating if the color buffer is
|
|
double buffered */
|
|
glut_state_flag |= GLUT_DOUBLE ;
|
|
break ;
|
|
|
|
case 8 : /* "green": Green color buffer precision in bits */
|
|
break ;
|
|
|
|
case 9 : /* "index": Boolean if the color model is color index or not
|
|
*/
|
|
glut_state_flag |= GLUT_INDEX ;
|
|
break ;
|
|
|
|
case 10 : /* "num": A special capability name indicating where the
|
|
value represents the Nth frame buffer configuration
|
|
matching the description string */
|
|
break ;
|
|
|
|
case 11 : /* "red": Red color buffer precision in bits */
|
|
break ;
|
|
|
|
case 12 : /* "rgba": Number of bits of red, green, blue, and alpha in
|
|
the RGBA color buffer */
|
|
glut_state_flag |= GLUT_RGBA ; /* Somebody fix this for me! */
|
|
break ;
|
|
|
|
case 13 : /* "rgb": Number of bits of red, green, and blue in the
|
|
RGBA color buffer with zero bits alpha */
|
|
glut_state_flag |= GLUT_RGB ; /* Somebody fix this for me! */
|
|
break ;
|
|
|
|
case 14 : /* "luminance": Number of bits of red in the RGBA and zero
|
|
bits of green, blue (alpha not specified) of color buffer
|
|
precision */
|
|
glut_state_flag |= GLUT_LUMINANCE ; /* Somebody fix this for me! */
|
|
break ;
|
|
|
|
case 15 : /* "stencil": Number of bits in the stencil buffer */
|
|
glut_state_flag |= GLUT_STENCIL; /* Somebody fix this for me! */
|
|
break ;
|
|
|
|
case 16 : /* "single": Boolean indicate the color buffer is single
|
|
buffered */
|
|
glut_state_flag |= GLUT_SINGLE ;
|
|
break ;
|
|
|
|
case 17 : /* "stereo": Boolean indicating the color buffer supports
|
|
OpenGL-style stereo */
|
|
glut_state_flag |= GLUT_STEREO ;
|
|
break ;
|
|
|
|
case 18 : /* "samples": Indicates the number of multisamples to use
|
|
based on GLX's SGIS_multisample extension (for
|
|
antialiasing) */
|
|
glut_state_flag |= GLUT_MULTISAMPLE ; /*Somebody fix this for me!*/
|
|
break ;
|
|
|
|
case 19 : /* "slow": Boolean indicating if the frame buffer
|
|
configuration is slow or not */
|
|
break ;
|
|
|
|
case 20 : /* "win32pdf": (incorrect spelling but was there before */
|
|
case 21 : /* "win32pfd": matches the Win32 Pixel Format Descriptor by
|
|
number */
|
|
#if TARGET_HOST_MS_WINDOWS
|
|
#endif
|
|
break ;
|
|
|
|
case 22 : /* "xvisual": matches the X visual ID by number */
|
|
#if TARGET_HOST_POSIX_X11
|
|
#endif
|
|
break ;
|
|
|
|
case 23 : /* "xstaticgray": */
|
|
case 29 : /* "xstaticgrey": boolean indicating if the frame buffer
|
|
configuration's X visual is of type StaticGray */
|
|
#if TARGET_HOST_POSIX_X11
|
|
#endif
|
|
break ;
|
|
|
|
case 24 : /* "xgrayscale": */
|
|
case 30 : /* "xgreyscale": boolean indicating if the frame buffer
|
|
configuration's X visual is of type GrayScale */
|
|
#if TARGET_HOST_POSIX_X11
|
|
#endif
|
|
break ;
|
|
|
|
case 25 : /* "xstaticcolor": */
|
|
case 31 : /* "xstaticcolour": boolean indicating if the frame buffer
|
|
configuration's X visual is of type StaticColor */
|
|
#if TARGET_HOST_POSIX_X11
|
|
#endif
|
|
break ;
|
|
|
|
case 26 : /* "xpseudocolor": */
|
|
case 32 : /* "xpseudocolour": boolean indicating if the frame buffer
|
|
configuration's X visual is of type PseudoColor */
|
|
#if TARGET_HOST_POSIX_X11
|
|
#endif
|
|
break ;
|
|
|
|
case 27 : /* "xtruecolor": */
|
|
case 33 : /* "xtruecolour": boolean indicating if the frame buffer
|
|
configuration's X visual is of type TrueColor */
|
|
#if TARGET_HOST_POSIX_X11
|
|
#endif
|
|
break ;
|
|
|
|
case 28 : /* "xdirectcolor": */
|
|
case 34 : /* "xdirectcolour": boolean indicating if the frame buffer
|
|
configuration's X visual is of type DirectColor */
|
|
#if TARGET_HOST_POSIX_X11
|
|
#endif
|
|
break ;
|
|
|
|
case 35 : /* "borderless": windows should not have borders */
|
|
#if TARGET_HOST_POSIX_X11
|
|
#endif
|
|
break ;
|
|
|
|
case 36 : /* "aux": some number of aux buffers */
|
|
glut_state_flag |= GLUT_AUX;
|
|
break ;
|
|
|
|
case 37 : /* Unrecognized */
|
|
fgWarning ( "WARNING - Display string token not recognized: %s",
|
|
token );
|
|
break ;
|
|
}
|
|
|
|
token = strtok ( NULL, " \t" );
|
|
}
|
|
|
|
free ( buffer );
|
|
|
|
/* We will make use of this value when creating a new OpenGL context... */
|
|
fgState.DisplayMode = glut_state_flag;
|
|
}
|
|
|
|
/* -- SETTING OPENGL 3.0 CONTEXT CREATION PARAMETERS ---------------------- */
|
|
|
|
void FGAPIENTRY glutInitContextVersion( int majorVersion, int minorVersion )
|
|
{
|
|
/* We will make use of these valuse when creating a new OpenGL context... */
|
|
fgState.MajorVersion = majorVersion;
|
|
fgState.MinorVersion = minorVersion;
|
|
}
|
|
|
|
|
|
void FGAPIENTRY glutInitContextFlags( int flags )
|
|
{
|
|
/* We will make use of this value when creating a new OpenGL context... */
|
|
fgState.ContextFlags = flags;
|
|
}
|
|
|
|
void FGAPIENTRY glutInitContextProfile( int profile )
|
|
{
|
|
/* We will make use of this value when creating a new OpenGL context... */
|
|
fgState.ContextProfile = profile;
|
|
}
|
|
|
|
/* -------------- User Defined Error/Warning Handler Support -------------- */
|
|
|
|
/*
|
|
* Sets the user error handler (note the use of va_list for the args to the fmt)
|
|
*/
|
|
void FGAPIENTRY glutInitErrorFunc( void (* vfgError) ( const char *fmt, va_list ap ) )
|
|
{
|
|
/* This allows user programs to handle freeglut errors */
|
|
fgState.ErrorFunc = vfgError;
|
|
}
|
|
|
|
/*
|
|
* Sets the user warning handler (note the use of va_list for the args to the fmt)
|
|
*/
|
|
void FGAPIENTRY glutInitWarningFunc( void (* vfgWarning) ( const char *fmt, va_list ap ) )
|
|
{
|
|
/* This allows user programs to handle freeglut warnings */
|
|
fgState.WarningFunc = vfgWarning;
|
|
}
|
|
|
|
/*** END OF FILE ***/
|