From icculus at icculus.org Tue Jun 4 00:06:06 2013 From: icculus at icculus.org (Ryan C. Gordon) Date: Tue, 04 Jun 2013 00:06:06 -0400 Subject: [lugaru] [PATCH] SDL2 port... Message-ID: <51AD67AE.7060902@icculus.org> ...this patch is untested, but I'm throwing it out here in case anyone wants to clean it up and test it for the GPL code release. We just put a Linux version of Lugaru on Steam, based on the code right before the GPL release (to match the other platforms), but I wanted to convert it to SDL2, since it has better fullscreen support, etc. Attached are the changes for that, roughly mushed into the latest code from http://hg.icculus.org/icculus/lugaru/ ... I haven't tried to compile this at all. I've also attached a diff for limiting the framerate to approximately 60fps...the SDL2 patch attempts to set swap_tear vsync (sync to vblank, unless we've already missed it, in which case just swap buffers immediately), and failing that, sets regular vsync, and failing that, this patch tries to brute-force us into 60fps by spinning after swapping buffers. Lugaru fails in various ways if the framerate is too high, but 60 is totally fine and easy to achieve in this game on modern hardware. --ryan. -------------- next part -------------- diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -235,22 +235,21 @@ option (LUGARU_FORCE_INTERNAL_SDL "Force internal libSDL, even if there's a system version" False) if (NOT LUGARU_FORCE_INTERNAL_SDL) - find_package(SDL) + find_package(SDL2) else(NOT LUGARU_FORCE_INTERNAL_SDL) set(SDL_FOUND False) endif (NOT LUGARU_FORCE_INTERNAL_SDL) if (NOT SDL_FOUND) - message(STATUS "Using internal copy of SDL") - set(LUGARU_MISSING_DEPS "${LUGARU_MISSING_DEPS} SDL") - set(SDLDIR "${DEPDIR}/SDL12") + message(STATUS "Using internal copy of SDL2") + set(LUGARU_MISSING_DEPS "${LUGARU_MISSING_DEPS} SDL2") + set(SDLDIR "${DEPDIR}/SDL2") set(SDL_INCLUDE_DIR "${SDLDIR}/include") set(SDL_LIBRARY "") if (APPLE) set(LUGARU_HAS_INTERNAL_SDL True) set(SDL_LIBRARY - ${SDLDIR}/lib/macosx/libSDL-1.2.0.dylib - ${SDLDIR}/lib/macosx/libSDLmain-osx.a + ${SDLDIR}/lib/macosx/libSDL2-2.0.0.dylib ) endif (APPLE) @@ -258,21 +257,18 @@ set(LUGARU_HAS_INTERNAL_SDL True) if (MSVC80) set(SDL_LIBRARY - ${SDLDIR}/lib/win32/msvc2005/SDLmain.lib - ${SDLDIR}/lib/win32/msvc2005/SDL.lib + ${SDLDIR}/lib/win32/msvc2005/SDL2.lib ) endif (MSVC80) if (MSVC90) set(SDL_LIBRARY - ${SDLDIR}/lib/win32/msvc2008/SDLmain.lib - ${SDLDIR}/lib/win32/msvc2008/SDL.lib + ${SDLDIR}/lib/win32/msvc2008/SDL2.lib ) endif (MSVC90) if (MINGW) set(SDL_LIBRARY "mingw32" - ${SDLDIR}/lib/win32/mingw/libSDLmain.a - ${SDLDIR}/lib/win32/mingw/libSDL.dll.a + ${SDLDIR}/lib/win32/mingw/libSDL2.dll.a "-mwindows" ) endif (MINGW) @@ -519,15 +515,15 @@ if(WIN32) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/lugaru.exe DESTINATION ${CMAKE_INSTALL_PREFIX}) if(MSVC80) - install(FILES ${SDLDIR}/lib/win32/msvc2005/SDL.dll DESTINATION ${CMAKE_INSTALL_PREFIX}) + install(FILES ${SDLDIR}/lib/win32/msvc2005/SDL2.dll DESTINATION ${CMAKE_INSTALL_PREFIX}) install(FILES ${OPENALDIR}/lib/win32/msvc2005/OpenAL32.dll DESTINATION ${CMAKE_INSTALL_PREFIX}) endif(MSVC80) if(MSVC90) - install(FILES ${SDLDIR}/lib/win32/msvc2008/SDL.dll DESTINATION ${CMAKE_INSTALL_PREFIX}) + install(FILES ${SDLDIR}/lib/win32/msvc2008/SDL2.dll DESTINATION ${CMAKE_INSTALL_PREFIX}) install(FILES ${OPENALDIR}/lib/win32/msvc2008/OpenAL32.dll DESTINATION ${CMAKE_INSTALL_PREFIX}) endif(MSVC90) if(MINGW) - install(FILES ${SDLDIR}/lib/win32/mingw/SDL.dll DESTINATION ${CMAKE_INSTALL_PREFIX}) + install(FILES ${SDLDIR}/lib/win32/mingw/SDL2.dll DESTINATION ${CMAKE_INSTALL_PREFIX}) install(FILES ${OPENALDIR}/lib/win32/mingw/OpenAL32.dll DESTINATION ${CMAKE_INSTALL_PREFIX}) endif(MINGW) else(WIN32) @@ -538,7 +534,7 @@ endif(APPLE) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/lugaru DESTINATION ${CMAKE_INSTALL_PREFIX}) if(APPLE AND LUGARU_HAS_INTERNAL_SDL) - install(FILES ${SDLDIR}/lib/macosx/libSDL-1.2.0.dylib DESTINATION ${CMAKE_INSTALL_PREFIX}) + install(FILES ${SDLDIR}/lib/macosx/libSDL2-2.0.0.dylib DESTINATION ${CMAKE_INSTALL_PREFIX}) endif(APPLE AND LUGARU_HAS_INTERNAL_SDL) endif(WIN32) diff --git a/Source/Game.h b/Source/Game.h --- a/Source/Game.h +++ b/Source/Game.h @@ -305,7 +305,8 @@ static __forceinline void swap_gl_buffers(void) { - SDL_GL_SwapBuffers(); + extern SDL_Window *sdlwindow; + SDL_GL_SwapWindow(sdlwindow); } diff --git a/Source/Globals.cpp b/Source/Globals.cpp --- a/Source/Globals.cpp +++ b/Source/Globals.cpp @@ -78,7 +78,7 @@ Sprites sprites; float sps = 0; -SDL_Surface *sdlscreen; +SDL_Window *sdlwindow; int kTextureSize = 0; int detail = 0; diff --git a/Source/OpenGL_Windows.cpp b/Source/OpenGL_Windows.cpp --- a/Source/OpenGL_Windows.cpp +++ b/Source/OpenGL_Windows.cpp @@ -123,20 +123,13 @@ #include "win-res/resource.h" #endif +extern SDL_Window *sdlwindow; + using namespace std; SDL_Rect **resolutions = NULL; -static SDL_Rect rect_1024_768 = { 0, 0, 1024, 768 }; -static SDL_Rect rect_800_600 = { 0, 0, 800, 600 }; -static SDL_Rect rect_640_480 = { 0, 0, 640, 480 }; -static SDL_Rect *hardcoded_resolutions[] = { - &rect_1024_768, - &rect_800_600, - &rect_640_480, - NULL -}; @@ -225,7 +218,8 @@ pt->y = y; } #define GetCursorPos(x) sdlGetCursorPos(x) -#define SetCursorPos(x, y) SDL_WarpMouse(x, y) +#define SetCursorPos(x, y) SDL_WarpMouseInWindow(sdlwindow, x, y) + #define ScreenToClient(x, pt) #define ClientToScreen(x, pt) #ifdef MessageBox @@ -348,11 +342,11 @@ #define MAX_SDLKEYS SDLK_LAST -static unsigned short KeyTable[MAX_SDLKEYS]; +typedef std::map SdlKeyMap; +static SdlKeyMap KeyTable; static void initSDLKeyTable(void) { - memset(KeyTable, 0xFF, sizeof (KeyTable)); KeyTable[SDLK_BACKSPACE] = MAC_DELETE_KEY; KeyTable[SDLK_TAB] = MAC_TAB_KEY; KeyTable[SDLK_RETURN] = MAC_RETURN_KEY; @@ -404,16 +398,16 @@ KeyTable[SDLK_x] = MAC_X_KEY; KeyTable[SDLK_y] = MAC_Y_KEY; KeyTable[SDLK_z] = MAC_Z_KEY; - KeyTable[SDLK_KP0] = MAC_NUMPAD_0_KEY; - KeyTable[SDLK_KP1] = MAC_NUMPAD_1_KEY; - KeyTable[SDLK_KP2] = MAC_NUMPAD_2_KEY; - KeyTable[SDLK_KP3] = MAC_NUMPAD_3_KEY; - KeyTable[SDLK_KP4] = MAC_NUMPAD_4_KEY; - KeyTable[SDLK_KP5] = MAC_NUMPAD_5_KEY; - KeyTable[SDLK_KP6] = MAC_NUMPAD_6_KEY; - KeyTable[SDLK_KP7] = MAC_NUMPAD_7_KEY; - KeyTable[SDLK_KP8] = MAC_NUMPAD_8_KEY; - KeyTable[SDLK_KP9] = MAC_NUMPAD_9_KEY; + KeyTable[SDLK_KP_0] = MAC_NUMPAD_0_KEY; + KeyTable[SDLK_KP_1] = MAC_NUMPAD_1_KEY; + KeyTable[SDLK_KP_2] = MAC_NUMPAD_2_KEY; + KeyTable[SDLK_KP_3] = MAC_NUMPAD_3_KEY; + KeyTable[SDLK_KP_4] = MAC_NUMPAD_4_KEY; + KeyTable[SDLK_KP_5] = MAC_NUMPAD_5_KEY; + KeyTable[SDLK_KP_6] = MAC_NUMPAD_6_KEY; + KeyTable[SDLK_KP_7] = MAC_NUMPAD_7_KEY; + KeyTable[SDLK_KP_8] = MAC_NUMPAD_8_KEY; + KeyTable[SDLK_KP_9] = MAC_NUMPAD_9_KEY; KeyTable[SDLK_KP_MULTIPLY] = MAC_NUMPAD_ASTERISK_KEY; KeyTable[SDLK_KP_PLUS] = MAC_NUMPAD_PLUS_KEY; KeyTable[SDLK_KP_ENTER] = MAC_NUMPAD_ENTER_KEY; @@ -457,18 +451,26 @@ return -1; } -static void sdlEventProc(const SDL_Event &e, Game &game) +static SDL_bool sdlEventProc(const SDL_Event &e, Game &game) { int val; bool skipkey = false; - SDLMod mod; + SDL_Keycode sym; + Uint16 mod; switch(e.type) { + case SDL_QUIT: + return SDL_FALSE; + + case SDL_WINDOWEVENT: + if (e.window.event == SDL_WINDOWEVENT_CLOSE) + return SDL_FALSE; + case SDL_MOUSEMOTION: game.deltah += e.motion.xrel; game.deltav += e.motion.yrel; - return; + return SDL_TRUE; case SDL_MOUSEBUTTONDOWN: { @@ -480,7 +482,7 @@ buttons[val] = true; } } - return; + return SDL_TRUE; case SDL_MOUSEBUTTONUP: { @@ -492,61 +494,93 @@ buttons[val] = false; } } - return; + return SDL_TRUE; case SDL_KEYDOWN: - if (e.key.keysym.sym == SDLK_g) + sym = e.key.keysym.sym; + mod = e.key.keysym.mod; + + if (sym == SDLK_g) { - if (e.key.keysym.mod & KMOD_CTRL) + if (mod & KMOD_CTRL) { skipkey = true; - SDL_GrabMode mode = SDL_GRAB_ON; - if ((SDL_GetVideoSurface()->flags & SDL_FULLSCREEN) == 0) - { - mode = SDL_WM_GrabInput(SDL_GRAB_QUERY); - mode = (mode==SDL_GRAB_ON) ? SDL_GRAB_OFF:SDL_GRAB_ON; - } - SDL_WM_GrabInput(mode); + + SDL_bool mode = SDL_TRUE; + if ((SDL_GetWindowFlags(sdlwindow) & SDL_WINDOW_FULLSCREEN) == 0) + mode = SDL_GetWindowGrab(sdlwindow) ? SDL_FALSE : SDL_TRUE; + SDL_SetWindowGrab(sdlwindow, mode); + SDL_SetRelativeMouseMode(mode); } } - else if (e.key.keysym.sym == SDLK_RETURN) + #if PLATFORM_MACOSX + else if (sym == SDLK_q) { - if (e.key.keysym.mod & KMOD_ALT) + if (mod & KMOD_GUI) + return SDL_FALSE; // quit game + } + #endif + + else if (sym == SDLK_RETURN) + { + if (mod & KMOD_ALT) { skipkey = true; - SDL_WM_ToggleFullScreen(SDL_GetVideoSurface()); + + Uint32 flags = SDL_GetWindowFlags(sdlwindow); + if (flags & SDL_WINDOW_FULLSCREEN) + flags &= ~SDL_WINDOW_FULLSCREEN; + else + flags |= SDL_WINDOW_FULLSCREEN; + SDL_SetWindowFullscreen(sdlwindow, flags); } } - if ((!skipkey) && (e.key.keysym.sym < SDLK_LAST)) + if (!skipkey) { - if (KeyTable[e.key.keysym.sym] != 0xffff) - SetKey(KeyTable[e.key.keysym.sym]); + SdlKeyMap::const_iterator it = KeyTable.find(sym); + if (it != KeyTable.end()) + SetKey(it->second); } - mod = SDL_GetModState(); - if (mod & KMOD_CTRL) + if ((mod & KMOD_CTRL) || (sym == SDLK_LCTRL) || (sym == SDLK_RCTRL)) SetKey(MAC_CONTROL_KEY); - if (mod & KMOD_ALT) + else + ClearKey(MAC_CONTROL_KEY); + + if ((mod & KMOD_ALT) || (sym == SDLK_LALT) || (sym == SDLK_RALT)) SetKey(MAC_OPTION_KEY); - if (mod & KMOD_META) + else + ClearKey(MAC_OPTION_KEY); + + if ((mod & KMOD_GUI) || (sym == SDLK_LGUI) || (sym == SDLK_RGUI)) SetKey(MAC_COMMAND_KEY); - if (mod & KMOD_SHIFT) + else + ClearKey(MAC_COMMAND_KEY); + + if ((mod & KMOD_SHIFT) || (sym == SDLK_LSHIFT) || (sym == SDLK_RSHIFT)) SetKey(MAC_SHIFT_KEY); - if (mod & KMOD_CAPS) + else + ClearKey(MAC_SHIFT_KEY); + + if ((mod & KMOD_CAPS) || (sym == SDLK_CAPSLOCK)) SetKey(MAC_CAPS_LOCK_KEY); + else + ClearKey(MAC_CAPS_LOCK_KEY); - return; + return SDL_TRUE; case SDL_KEYUP: - if (e.key.keysym.sym < SDLK_LAST) + sym = e.key.keysym.sym; + mod = SDL_GetModState(); + { - if (KeyTable[e.key.keysym.sym] != 0xffff) - ClearKey(KeyTable[e.key.keysym.sym]); + SdlKeyMap::const_iterator it = KeyTable.find(sym); + if (it != KeyTable.end()) + ClearKey(it->second); } - mod = SDL_GetModState(); if ((mod & KMOD_CTRL) == 0) ClearKey(MAC_CONTROL_KEY); if ((mod & KMOD_ALT) == 0) @@ -557,8 +591,10 @@ ClearKey(MAC_SHIFT_KEY); if ((mod & KMOD_CAPS) == 0) ClearKey(MAC_CAPS_LOCK_KEY); - return; + return SDL_TRUE; } + + return SDL_TRUE; } @@ -862,31 +898,48 @@ SetupDSpFullScreen(); + const int displayIdx = 0; // !!! FIXME: other monitors? if (!SDL_WasInit(SDL_INIT_VIDEO)) { if (SDL_Init(SDL_INIT_VIDEO) == -1) { - fprintf(stderr, "SDL_Init() failed: %s\n", SDL_GetError()); + char buf[1024]; + snprintf(buf, sizeof (buf), "SDL_Init() failed: %s\n", SDL_GetError()); + fprintf(stderr, "%s\n", buf); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Lugaru init failed!", buf, NULL); return false; } if (SDL_GL_LoadLibrary(NULL) == -1) { - fprintf(stderr, "SDL_GL_LoadLibrary() failed: %s\n", SDL_GetError()); + char buf[1024]; + snprintf(buf, sizeof (buf), "SDL_GL_LoadLibrary() failed: %s\n", SDL_GetError()); + fprintf(stderr, "%s\n", buf); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Lugaru init failed!", buf, NULL); SDL_Quit(); return false; } - SDL_Rect **res = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_OPENGL); - if ( (res == NULL) || (res == ((SDL_Rect **)-1)) || (res[0] == NULL) || (res[0]->w < 640) || (res[0]->h < 480) ) - res = hardcoded_resolutions; + int count = 0; + const int nummodes = SDL_GetNumDisplayModes(displayIdx); + for (int i = 0; i < nummodes; i++) + { + SDL_DisplayMode mode; + if (SDL_GetDisplayMode(displayIdx, i, &mode) == -1) + continue; + if ((mode.w < 640) || (mode.h < 480)) + continue; // sane lower limit. + count++; + } - // reverse list (it was sorted biggest to smallest by SDL)... - int count; - for (count = 0; res[count]; count++) + if (count == 0) { - if ((res[count]->w < 640) || (res[count]->h < 480)) - break; // sane lower limit. + char buf[1024]; + snprintf(buf, sizeof (buf), "No suitable video resolutions found."); + fprintf(stderr, "%s\n", buf); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Lugaru init failed!", buf, NULL); + SDL_Quit(); + return false; } static SDL_Rect *resolutions_block = NULL; @@ -894,15 +947,25 @@ resolutions = (SDL_Rect**) realloc(resolutions, sizeof (SDL_Rect *) * (count + 1)); if ((resolutions_block == NULL) || (resolutions == NULL)) { + char buf[1024]; + snprintf(buf, sizeof (buf), "Out of memory!"); + fprintf(stderr, "%s\n", buf); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Lugaru init failed!", buf, NULL); SDL_Quit(); - fprintf(stderr, "Out of memory!\n"); return false; } resolutions[count--] = NULL; for (int i = 0; count >= 0; i++, count--) { - memcpy(&resolutions_block[count], res[i], sizeof (SDL_Rect)); + SDL_DisplayMode mode; + if (SDL_GetDisplayMode(displayIdx, i, &mode) == -1) + continue; + if ((mode.w < 640) || (mode.h < 480)) + continue; // sane lower limit. + resolutions_block[count].x = resolutions_block[count].y = 0; + resolutions_block[count].w = mode.w; + resolutions_block[count].h = mode.h; resolutions[count] = &resolutions_block[count]; } @@ -914,51 +977,85 @@ } } - Uint32 sdlflags = SDL_OPENGL; - if (!cmdline("windowed")) - sdlflags |= SDL_FULLSCREEN; - - SDL_WM_SetCaption("Lugaru", "Lugaru"); - - SDL_ShowCursor(0); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - if (SDL_SetVideoMode(kContextWidth, kContextHeight, 0, sdlflags) == NULL) + Uint32 sdlflags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN; + if (!cmdline("windowed")) + sdlflags |= SDL_WINDOW_FULLSCREEN; + if (!cmdline("nomousegrab")) + sdlflags |= SDL_WINDOW_INPUT_GRABBED; + + sdlwindow = SDL_CreateWindow("Lugaru", SDL_WINDOWPOS_CENTERED_DISPLAY(displayIdx), SDL_WINDOWPOS_CENTERED_DISPLAY(displayIdx), + kContextWidth, kContextHeight, sdlflags); + + if (!sdlwindow) { - fprintf(stderr, "SDL_SetVideoMode() failed: %s\n", SDL_GetError()); + fprintf(stderr, "SDL_CreateWindow() failed: %s\n", SDL_GetError()); fprintf(stderr, "forcing 640x480...\n"); kContextWidth = 640; kContextHeight = 480; - if (SDL_SetVideoMode(kContextWidth, kContextHeight, 0, sdlflags) == NULL) + sdlwindow = SDL_CreateWindow("Lugaru", SDL_WINDOWPOS_CENTERED_DISPLAY(displayIdx), SDL_WINDOWPOS_CENTERED_DISPLAY(displayIdx), + kContextWidth, kContextHeight, sdlflags); + if (!sdlwindow) { - fprintf(stderr, "SDL_SetVideoMode() failed: %s\n", SDL_GetError()); + fprintf(stderr, "SDL_CreateWindow() failed: %s\n", SDL_GetError()); fprintf(stderr, "forcing 640x480 windowed mode...\n"); - sdlflags &= ~SDL_FULLSCREEN; - if (SDL_SetVideoMode(kContextWidth, kContextHeight, 0, sdlflags) == NULL) + sdlflags &= ~SDL_WINDOW_FULLSCREEN; + sdlwindow = SDL_CreateWindow("Lugaru", SDL_WINDOWPOS_CENTERED_DISPLAY(displayIdx), SDL_WINDOWPOS_CENTERED_DISPLAY(displayIdx), + kContextWidth, kContextHeight, sdlflags); + + if (!sdlwindow) { - fprintf(stderr, "SDL_SetVideoMode() failed: %s\n", SDL_GetError()); + char buf[1024]; + snprintf(buf, sizeof (buf), "SDL_CreateWindow() failed: %s\n", SDL_GetError()); + fprintf(stderr, "%s\n", buf); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Lugaru init failed!", buf, NULL); + SDL_Quit(); return false; } } } - int dblbuf = 0; - if ((SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &dblbuf) == -1) || (!dblbuf)) + SDL_GLContext glctx = SDL_GL_CreateContext(sdlwindow); + if (!glctx) { - fprintf(stderr, "Failed to get double buffered GL context!\n"); + char buf[1024]; + snprintf(buf, sizeof (buf), "SDL_CreateContext() failed: %s\n", SDL_GetError()); + fprintf(stderr, "%s\n", buf); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Lugaru init failed!", buf, NULL); SDL_Quit(); return false; } + SDL_GL_MakeCurrent(sdlwindow, glctx); + if (!lookup_all_glsyms()) { + char buf[1024]; + snprintf(buf, sizeof (buf), "Missing required OpenGL functions."); + fprintf(stderr, "%s\n", buf); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Lugaru init failed!", buf, NULL); SDL_Quit(); return false; } - if (!cmdline("nomousegrab")) - SDL_WM_GrabInput(SDL_GRAB_ON); + int dblbuf = 0; + if ((SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &dblbuf) == -1) || (!dblbuf)) + { + char buf[1024]; + snprintf(buf, sizeof (buf), "Failed to get a double-buffered context."); + fprintf(stderr, "%s\n", buf); + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Lugaru init failed!", buf, NULL); + SDL_Quit(); + return false; + } + + if (SDL_GL_SetSwapInterval(-1) == -1) // try swap_tear first. + SDL_GL_SetSwapInterval(1); + + SDL_ShowCursor(0); + SDL_SetWindowGrab(sdlwindow, SDL_TRUE); + SDL_SetRelativeMouseMode(SDL_TRUE); glClear( GL_COLOR_BUFFER_BIT ); @@ -1368,12 +1465,11 @@ // message pump while( SDL_PollEvent( &e ) ) { - if( e.type == SDL_QUIT ) + if (!sdlEventProc(e, game)) { gDone=true; break; } - sdlEventProc(e, game); } -------------- next part -------------- diff --git a/Source/Game.h b/Source/Game.h --- a/Source/Game.h +++ b/Source/Game.h @@ -307,6 +307,13 @@ SDL_GL_SwapBuffers(); + // try to limit this to 60fps, even if vsync fails. + Uint32 now; + static Uint32 frameticks = 0; + const Uint32 endticks = (frameticks + 16); + while ((now = SDL_GetTicks()) < endticks) { /* spin. */ } + frameticks = now; + } #ifdef __GNUC__