void fgPlatformInitialize( const char* displayName ) { fgDisplay.pDisplay.display = wl_display_connect( NULL ); if( fgDisplay.pDisplay.display == NULL ) fgError( "failed to connect to a Wayland compositor" ); fgDisplay.pDisplay.registry = wl_display_get_registry( fgDisplay.pDisplay.display ); wl_registry_add_listener( fgDisplay.pDisplay.registry, &fghRegistryListener, &fgDisplay.pDisplay ); wl_display_roundtrip( fgDisplay.pDisplay.display ); if( fgDisplay.pDisplay.compositor == NULL || fgDisplay.pDisplay.shell == NULL || fgDisplay.pDisplay.seat == NULL || fgDisplay.pDisplay.shm == NULL ) fgError( "failed to discover all needed compositor interfaces" ); fghInitialiseCursorTheme(); fghPlatformInitializeEGL(); /* Get start time */ fgState.Time = fgSystemTime(); fgState.Initialised = GL_TRUE; atexit(fgDeinitialize); /* InputDevice uses GlutTimerFunc(), so fgState.Initialised must be TRUE */ fgPlatformInitialiseInputDevices(); }
/* * 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; 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( ); fghParseCommandLineArguments ( pargc, argv, &displayName, &geometry ); /* * 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): */ fgPlatformInitialize( displayName ); /* * Geometry parsing deferred 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; } }
/* * Changes the specified menu item in the current menu into a sub-menu trigger. */ void FGAPIENTRY glutChangeToSubMenu( int item, const char* label, int subMenuID ) { SFG_Menu* subMenu; SFG_MenuEntry* menuEntry; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutChangeToSubMenu" ); freeglut_return_if_fail( fgStructure.CurrentMenu ); if (fgGetActiveMenu()) fgError("Menu manipulation not allowed while menus in use."); /* Get handle to sub menu */ subMenu = fgMenuByID( subMenuID ); menuEntry = NULL; freeglut_return_if_fail( subMenu ); /* Get n-th menu entry in the current menu, starting from one: */ menuEntry = fghFindMenuEntry( fgStructure.CurrentMenu, item ); freeglut_return_if_fail( menuEntry ); /* We want it to become a sub menu entry, so: */ if( menuEntry->Text ) free( menuEntry->Text ); menuEntry->Text = strdup( label ); menuEntry->SubMenu = subMenu; menuEntry->ID = -1; fghCalculateMenuBoxSize( ); }
/** * Initialize an EGL context for the current display. */ EGLContext fghCreateNewContextEGL( SFG_Window* window ) { EGLContext context; EGLDisplay eglDisplay = fgDisplay.pDisplay.egl.Display; EGLConfig eglConfig = window->Window.pContext.egl.Config; /* Ensure OpenGLES 2.0 context */ static const EGLint ctx_attribs[] = { #ifdef GL_ES_VERSION_2_0 EGL_CONTEXT_CLIENT_VERSION, 2, #elif GL_VERSION_ES_CM_1_0 || GL_VERSION_ES_CL_1_0 || GL_VERSION_ES_CM_1_1 || GL_VERSION_ES_CL_1_1 EGL_CONTEXT_CLIENT_VERSION, 1, #endif EGL_NONE }; context = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, ctx_attribs); if (context == EGL_NO_CONTEXT) { fgWarning("Cannot initialize EGL context, err=%x\n", eglGetError()); fghContextCreationError(); } EGLint ver = -1; eglQueryContext(fgDisplay.pDisplay.egl.Display, context, EGL_CONTEXT_CLIENT_VERSION, &ver); #ifdef GL_ES_VERSION_2_0 if (ver != 2) #else if (ver != 1) #endif fgError("Wrong GLES major version: %d\n", ver); return context; }
/* * A call to this function should initialize all the display stuff... */ void fgPlatformInitialize( const char* displayName ) { fprintf(stderr, "fgPlatformInitialize\n"); fgState.Initialised = GL_TRUE; /* CreateDisplay */ /* Using EGL_DEFAULT_DISPLAY, or a specific native display */ EGLNativeDisplayType nativeDisplay = EGL_DEFAULT_DISPLAY; fgDisplay.pDisplay.eglDisplay = eglGetDisplay(nativeDisplay); FREEGLUT_INTERNAL_ERROR_EXIT(fgDisplay.pDisplay.eglDisplay != EGL_NO_DISPLAY, "No display available", "fgPlatformInitialize"); if (!eglInitialize(fgDisplay.pDisplay.eglDisplay, NULL, NULL)) fgError("eglInitialize: error %x\n", eglGetError()); /* CreateContext */ fghCreateContext(); // fgDisplay.ScreenWidth = ...; // fgDisplay.ScreenHeight = ...; // fgDisplay.ScreenWidthMM = ...; // fgDisplay.ScreenHeightMM = ...; }
/* * Sets the Timer callback for the current window */ void FGAPIENTRY glutTimerFunc( unsigned int timeOut, void (* callback)( int ), int timerID ) { SFG_Timer *timer, *node; glutes_assert_ready; if( (timer = fgState.FreeTimers.Last) ) { fgListRemove( &fgState.FreeTimers, &timer->Node ); } else { if( ! (timer = malloc(sizeof(SFG_Timer))) ) fgError( "Fatal error: " "Memory allocation failure in glutTimerFunc()\n" ); } timer->Callback = callback; timer->ID = timerID; timer->TriggerTime = fgElapsedTime() + timeOut; for( node = fgState.Timers.First; node; node = node->Node.Next ) { if( node->TriggerTime > timer->TriggerTime ) break; } fgListInsert( &fgState.Timers, &node->Node, &timer->Node ); }
/** * Initialize an EGL context for the current display. */ EGLContext fghCreateNewContextEGL( SFG_Window* window ) { EGLContext context; EGLint ver = -1; EGLDisplay eglDisplay = fgDisplay.pDisplay.egl.Display; EGLConfig eglConfig = window->Window.pContext.egl.Config; /* On GLES, user specifies the target version with glutInitContextVersion */ EGLint attributes[32]; int where = 0; ATTRIB_VAL(EGL_CONTEXT_CLIENT_VERSION, fgState.MajorVersion); ATTRIB(EGL_NONE); context = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, attributes); if (context == EGL_NO_CONTEXT) { fgWarning("Cannot initialize EGL context, err=%x\n", eglGetError()); fghContextCreationError(); } eglQueryContext(fgDisplay.pDisplay.egl.Display, context, EGL_CONTEXT_CLIENT_VERSION, &ver); if (ver != fgState.MajorVersion) fgError("Wrong GLES major version: %d\n", ver); return context; }
/* Creates a timer and sets its callback */ void FGAPIENTRY glutTimerFunc( unsigned int timeOut, FGCBTimer callback, int timerID ) { SFG_Timer *timer, *node; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutTimerFunc" ); if( (timer = fgState.FreeTimers.Last) ) { fgListRemove( &fgState.FreeTimers, &timer->Node ); } else { if( ! (timer = malloc(sizeof(SFG_Timer))) ) fgError( "Fatal error: " "Memory allocation failure in glutTimerFunc()" ); } timer->Callback = callback; timer->ID = timerID; timer->TriggerTime = fgElapsedTime() + timeOut; /* Insert such that timers are sorted by end-time */ for( node = fgState.Timers.First; node; node = node->Node.Next ) { if( node->TriggerTime > timer->TriggerTime ) break; } fgListInsert( &fgState.Timers, &node->Node, &timer->Node ); }
void __glInit() { EGLint majorVersion; EGLint minorVersion; // EGLConfig cfg; /* EGL Setup */ #ifdef _WIN32_WCE HDC hdc = GetDC(NULL); ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, NULL, sizeof(RawFrameBufferInfo), (char *) &fgDisplay.FrameBufferInfo); ReleaseDC(NULL, hdc); #endif if(fgDisplay.eglDisplay) return; #if TARGET_HOST_UNIX_X11 fgDisplay.eglDisplay = eglGetDisplay((NativeDisplayType)fgDisplay.Display); #else fgDisplay.eglDisplay = eglGetDisplay((NativeDisplayType)EGL_DEFAULT_DISPLAY); #endif if(!eglInitialize(fgDisplay.eglDisplay, &majorVersion, &minorVersion)) fgError("Unable to initialize OpenGL|ES!"); }
int FGAPIENTRY glutCreateMenu(FGCBMenu selectFunc) { SFG_WinMenu *menu; int menuid; if (fgMappedMenu) menuModificationError(); menuid = getUnusedMenuSlot(); menu = (SFG_WinMenu *) malloc(sizeof(SFG_WinMenu)); if (!menu) fgError("out of memory."); menu->ID = menuid; menu->Num = 0; menu->SubMenus = 0; menu->Select = selectFunc; menu->List = NULL; menu->Cascade = NULL; menu->Highlighted = NULL; menu->Anchor = NULL; menu->Handle = CreatePopupMenu(); menuList[menuid] = menu; fgSetMenu(menu); return menuid + 1; }
void FGAPIENTRY glutChangeToSubMenu(int num, const char *label, int menu) { SFG_WinMenu *popupmenu; SFG_WinMenuItem *item; int i; #ifdef UNICODE WCHAR *wlabel; #endif if (fgMappedMenu) menuModificationError(); i = fgCurrentMenu->Num; item = fgCurrentMenu->List; while (item) { if (i == num) { if (!item->IsTrigger) { /* If changing a menu entry to as submenu trigger, we need to account for submenus. */ item->Menu->SubMenus++; } free(item->Label); item->Label = _strdup(label); if (!item->Label) fgError("out of memory"); item->IsTrigger = TRUE; item->Len = (int) strlen(label); item->Value = menu - 1; item->Unique = UniqueMenuHandler++; popupmenu = fgGetMenuByNum(menu); if (popupmenu) item->Handle = popupmenu->Handle; #ifdef UNICODE wlabel = (WCHAR*)malloc((item->Len + 1) * sizeof(WCHAR)); mbstowcs(wlabel, label, item->Len + 1); #endif RemoveMenu(fgCurrentMenu->Handle, (UINT) i - 1, MF_BYPOSITION); InsertMenu(fgCurrentMenu->Handle, (UINT) i - 1, MF_BYPOSITION | MFT_STRING | MF_POPUP, (UINT)item->Handle, #ifdef UNICODE wlabel #else label #endif ); #ifdef UNICODE free(wlabel); #endif return; } i--; item = item->Next; } fgWarning("Current menu has no %d item.", num); }
void fgPlatformSetWindow ( SFG_Window *window ) { if (eglMakeCurrent(fgDisplay.pDisplay.egl.Display, window->Window.pContext.egl.Surface, window->Window.pContext.egl.Surface, window->Window.Context) == EGL_FALSE) fgError("eglMakeCurrent: err=%x\n", eglGetError()); }
/* * Creates a new menu object, adding it to the freeglut structure */ int FGAPIENTRY glutCreateMenu( void(* callback)( int ) ) { /* The menu object creation code resides in freeglut_structure.c */ FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutCreateMenu" ); if (fgGetActiveMenu()) fgError("Menu manipulation not allowed while menus in use."); return fgCreateMenu( callback )->ID; }
/* * Sets the Display callback for the current window */ void FGAPIENTRY glutDisplayFunc( void (* callback)( void ) ) { if( !callback ) fgError( "Fatal error in program. NULL display callback not " "permitted in GLUT 3.0+ or FreeGLUT|ES 1.0+\n" ); SET_CALLBACK( Display ); fgStructure.Window->State.Redisplay = GL_TRUE; }
/* * Sets the Display callback for the current window */ void FGAPIENTRY glutDisplayFunc( FGCBDisplay callback ) { FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDisplayFunc" ); if( !callback ) fgError( "Fatal error in program. NULL display callback not " "permitted in GLUT 3.0+ or freeglut 2.0.1+" ); SET_CALLBACK( Display ); }
void fgPlatformGlutSwapBuffers( SFG_PlatformDisplay *pDisplayPtr, SFG_Window* CurrentWindow ) { if (!eglSwapBuffers(pDisplayPtr->egl.Display, CurrentWindow->Window.pContext.egl.Surface)) { int err = eglGetError(); if (err != EGL_BAD_CURRENT_SURFACE) // on certain hardware, this is occasionally returned without it being a real error fgError("eglSwapBuffers: error %x\n", err); } }
static void fghSetCursor ( SFG_Window *window, int cursorID ) { Cursor cursor; /* * XXX FULL_CROSSHAIR demotes to plain CROSSHAIR. Old GLUT allows * for this, but if there is a system that easily supports a full- * window (or full-screen) crosshair, we might consider it. */ int cursorIDToUse = ( cursorID == GLUT_CURSOR_FULL_CROSSHAIR ) ? GLUT_CURSOR_CROSSHAIR : cursorID; if( ( cursorIDToUse >= 0 ) && ( cursorIDToUse < sizeof( cursorCache ) / sizeof( cursorCache[0] ) ) ) { cursorCacheEntry *entry = &cursorCache[ cursorIDToUse ]; if( entry->cachedCursor == None ) { entry->cachedCursor = XCreateFontCursor( fgDisplay.Display, entry->cursorShape ); } cursor = entry->cachedCursor; } else { switch( cursorIDToUse ) { case GLUT_CURSOR_NONE: cursor = getEmptyCursor( ); break; case GLUT_CURSOR_INHERIT: cursor = None; break; default: fgError( "Unknown cursor type: %d", cursorIDToUse ); return; } } if ( cursorIDToUse == GLUT_CURSOR_INHERIT ) { XUndefineCursor( fgDisplay.Display, window->Window.Handle ); } else if ( cursor != None ) { XDefineCursor( fgDisplay.Display, window->Window.Handle, cursor ); } else if ( cursorIDToUse != GLUT_CURSOR_NONE ) { fgError( "Failed to create cursor" ); } }
/* * Matches a font ID with a SFG_StrokeFont structure pointer. * This was changed to match the GLUT header style. */ static SFG_StrokeFont* fghStrokeByID( void* font ) { if( font == GLUT_STROKE_ROMAN ) return &fgStrokeRoman; if( font == GLUT_STROKE_MONO_ROMAN ) return &fgStrokeMonoRoman; fgError( "stroke font 0x%08x not found", font ); return 0; /*** NOT REACHED ***/ }
/* * Marks the current window to have the redisplay performed when possible... */ void FGAPIENTRY glutPostRedisplay( void ) { FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutPostRedisplay" ); if ( ! fgStructure.CurrentWindow ) { fgError ( " ERROR: Function <%s> called" " with no current window defined.", "glutPostRedisplay" ) ; } fgStructure.CurrentWindow->State.Redisplay = GL_TRUE; }
void fgJoystickClose( void ) { if( !fgJoystick ) fgError( "illegal attempt to deinitialize joystick device" ); #ifndef WIN32 if( ! fgJoystick->error ) close( fgJoystick->fd ); #endif free( fgJoystick ); fgJoystick = NULL; /* show joystick has been deinitialized */ }
/* * Destroys a menu object, removing all references to it */ void FGAPIENTRY glutDestroyMenu( int menuID ) { SFG_Menu* menu; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDestroyMenu" ); menu = fgMenuByID( menuID ); freeglut_return_if_fail( menu ); if (fgState.ActiveMenus) fgError("Menu manipulation not allowed while menus in use."); /* The menu object destruction code resides in freeglut_structure.c */ fgDestroyMenu( menu ); }
/* * Detaches a menu from the current window */ void FGAPIENTRY glutDetachMenu( int button ) { FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutDetachMenu" ); freeglut_return_if_fail( fgStructure.CurrentWindow ); freeglut_return_if_fail( fgStructure.CurrentMenu ); if (fgGetActiveMenu()) fgError("Menu manipulation not allowed while menus in use."); freeglut_return_if_fail( button >= 0 ); freeglut_return_if_fail( button < FREEGLUT_MAX_MENUS ); fgStructure.CurrentWindow->Menu[ button ] = NULL; }
void FGAPIENTRY glutAddMenuEntry(const char *label, int value) { SFG_WinMenuItem *entry; if (fgMappedMenu) menuModificationError(); entry = (SFG_WinMenuItem *) malloc(sizeof(SFG_WinMenuItem)); if (!entry) fgError("out of memory."); entry->Menu = fgCurrentMenu; setMenuItem(entry, label, value, FALSE); fgCurrentMenu->Num++; entry->Next = fgCurrentMenu->List; fgCurrentMenu->List = entry; }
/* * Really opens a window when handle is available */ void fghPlatformOpenWindowEGL( SFG_Window* window ) { EGLDisplay display = fgDisplay.pDisplay.egl.Display; EGLConfig config = window->Window.pContext.egl.Config; EGLSurface surface = eglCreateWindowSurface(display, config, window->Window.Handle, NULL); if (surface == EGL_NO_SURFACE) fgError("Cannot create EGL window surface, err=%x\n", eglGetError()); window->Window.pContext.egl.Surface = surface; fgPlatformSetWindow(window); /* EGLint w, h; */ /* eglQuerySurface(display, surface, EGL_WIDTH, &w); */ /* eglQuerySurface(display, surface, EGL_HEIGHT, &h); */ }
/* * Adds a menu entry to the bottom of the current menu */ void FGAPIENTRY glutAddMenuEntry( const char* label, int value ) { SFG_MenuEntry* menuEntry; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutAddMenuEntry" ); menuEntry = (SFG_MenuEntry *)calloc( sizeof(SFG_MenuEntry), 1 ); freeglut_return_if_fail( fgStructure.CurrentMenu ); if (fgGetActiveMenu()) fgError("Menu manipulation not allowed while menus in use."); menuEntry->Text = strdup( label ); menuEntry->ID = value; /* Have the new menu entry attached to the current menu */ fgListAppend( &fgStructure.CurrentMenu->Entries, &menuEntry->Node ); fghCalculateMenuBoxSize( ); }
static void setMenuItem(SFG_WinMenuItem * item, const char *label, int value, int IsTrigger) { SFG_WinMenu *menu; #ifdef UNICODE WCHAR *wlabel; #endif menu = item->Menu; item->Label = _strdup(label); if (!item->Label) fgError("out of memory."); item->IsTrigger = IsTrigger; item->Len = (int) strlen(label); item->Value = value; item->Unique = UniqueMenuHandler++; #ifdef UNICODE wlabel = (WCHAR*)malloc((item->Len + 1) * sizeof(WCHAR)); mbstowcs(wlabel, label, item->Len + 1); #endif if (IsTrigger) AppendMenu(menu->Handle, MF_POPUP, (UINT)item->Handle, #ifdef UNICODE wlabel #else label #endif ); else AppendMenu(menu->Handle, MF_STRING, item->Unique, #ifdef UNICODE wlabel #else label #endif ); #ifdef UNICODE free(wlabel); #endif }
static void fghCircleTable(double **sint,double **cost,const int n) { int i; /* Table size, the sign of n flips the circle direction */ const int size = abs(n); /* Determine the angle between samples */ const double angle = 2*M_PI/(double)( ( n == 0 ) ? 1 : n ); /* Allocate memory for n samples, plus duplicate of first entry at the end */ *sint = (double *) calloc(sizeof(double), size+1); *cost = (double *) calloc(sizeof(double), size+1); /* Bail out if memory allocation fails, fgError never returns */ if (!(*sint) || !(*cost)) { free(*sint); free(*cost); fgError("Failed to allocate memory in fghCircleTable"); } /* Compute cos and sin around the circle */ (*sint)[0] = 0.0; (*cost)[0] = 1.0; for (i=1; i<size; i++) { (*sint)[i] = sin(angle*i); (*cost)[i] = cos(angle*i); } /* Last sample is duplicate of the first */ (*sint)[size] = (*sint)[0]; (*cost)[size] = (*cost)[0]; }
/* * Set global auto-repeat of keystrokes * * RepeatMode should be either: * GLUT_KEY_REPEAT_OFF * GLUT_KEY_REPEAT_ON * GLUT_KEY_REPEAT_DEFAULT */ void FGAPIENTRY glutSetKeyRepeat( int repeatMode ) { FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetKeyRepeat" ); switch( repeatMode ) { case GLUT_KEY_REPEAT_OFF: case GLUT_KEY_REPEAT_ON: fgState.KeyRepeat = repeatMode; break; case GLUT_KEY_REPEAT_DEFAULT: fgState.KeyRepeat = GLUT_KEY_REPEAT_ON; break; default: fgError ("Invalid glutSetKeyRepeat mode: %d", repeatMode); break; } }
/* * Matches a font ID with a SFG_Font structure pointer. * This was changed to match the GLUT header style. */ static SFG_Font* fghFontByID( void* font ) { if( font == GLUT_BITMAP_8_BY_13 ) return &fgFontFixed8x13; if( font == GLUT_BITMAP_9_BY_15 ) return &fgFontFixed9x15; if( font == GLUT_BITMAP_HELVETICA_10 ) return &fgFontHelvetica10; if( font == GLUT_BITMAP_HELVETICA_12 ) return &fgFontHelvetica12; if( font == GLUT_BITMAP_HELVETICA_18 ) return &fgFontHelvetica18; if( font == GLUT_BITMAP_TIMES_ROMAN_10 ) return &fgFontTimesRoman10; if( font == GLUT_BITMAP_TIMES_ROMAN_24 ) return &fgFontTimesRoman24; fgError( "font 0x%08x not found", font ); return 0; /*** NOT REACHED ***/ }
/* * Changes the current menu's font */ void FGAPIENTRY glutSetMenuFont( int menuID, void* fontID ) { SFG_Font* font; SFG_Menu* menu; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSetMenuFont" ); menu = fgMenuByID( menuID ); freeglut_return_if_fail( menu ); if (fgState.ActiveMenus) fgError("Menu manipulation not allowed while menus in use."); font = fghFontByID( fontID ); if (!font) { fgWarning("glutChangeMenuFont: bitmap font 0x%08x not found. Make sure you're not passing a stroke font. Ignoring...\n",fontID); return; } fgStructure.CurrentMenu->Font = fontID; fghCalculateMenuBoxSize( ); }