diff --git a/inc/dd.h b/inc/dd.h index 01abeac..fb2ef4e 100644 --- a/inc/dd.h +++ b/inc/dd.h @@ -54,7 +54,8 @@ typedef struct cnc_ddraw struct { int maxfps; - BOOL forcefps; + int minfps; + DWORD minfps_tick_len; int width; int height; int bpp; diff --git a/src/config.c b/src/config.c index 443ff76..c296467 100644 --- a/src/config.c +++ b/src/config.c @@ -63,9 +63,17 @@ void cfg_load() #endif g_ddraw->render.maxfps = cfg_get_int("maxfps", 60); + g_ddraw->render.minfps = cfg_get_int("minfps", 0); - if (g_ddraw->render.maxfps) - g_ddraw->render.forcefps = cfg_get_bool("forcefps", FALSE); + if (g_ddraw->render.minfps > 1000) + { + g_ddraw->render.minfps = 1000; + } + + if (g_ddraw->render.minfps > 0) + { + g_ddraw->render.minfps_tick_len = 1000.0f / g_ddraw->render.minfps; + } if (g_ddraw->accurate_timers || g_ddraw->vsync) g_ddraw->fps_limiter.htimer = CreateWaitableTimer(NULL, TRUE, NULL); @@ -295,12 +303,13 @@ static void cfg_create_ini() "handlemouse=true\n" "\n" "; Windows API Hooking, Possible values: 0 = disabled, 1 = IAT Hooking, 2 = Microsoft Detours, 3 = IAT+Detours Hooking (All Modules), 4 = IAT Hooking (All Modules)\n" - "; Note: Can be used to fix issues related to new features added by cnc-ddraw such as windowed mode or stretching\n" + "; Note: Change this value if windowed mode or upscaling isn't working properly\n" + "; Note: 'hook=2' will usually work for problematic games, but 'hook=2' must be combined with renderer=gdi\n" "hook=4\n" "\n" - "; Force consistent FPS (Requires 'maxfps=' to be set to a value other than 0)\n" - "; Note: Fixes flickering cursor issues in C&C games (Might be useful for some screen recorders too)\n" - "forcefps=false\n" + "; Force minimum FPS, possible values: 0 = disabled, -1 = use 'maxfps=' value, 1-1000 = custom FPS\n" + "; Note: Set this to a low value such as 5 or 10 if some parts of the game are not being displayed (e.g. menus or loading screens)\n" + "minfps=0\n" "\n" "; Disable fullscreen-exclusive mode for the OpenGL renderer\n" "; Note: Can be used in case some GUI elements like buttons/textboxes/videos/etc.. are invisible\n" @@ -339,18 +348,18 @@ static void cfg_create_ini() "[C&C95]\n" "maxgameticks=120\n" "maxfps=60\n" - "forcefps=true\n" + "minfps=-1\n" "\n" "; Command & Conquer: Red Alert\n" "[ra95]\n" "maxgameticks=120\n" "maxfps=60\n" - "forcefps=true\n" + "minfps=-1\n" "\n" "; Command & Conquer: Red Alert\n" "[ra95p]\n" "maxfps=60\n" - "forcefps=true\n" + "minfps=-1\n" "\n" "; Age of Empires\n" "[empires]\n" @@ -413,71 +422,70 @@ static void cfg_create_ini() "noactivateapp=true\n" "handlemouse=false\n" "maxfps=60\n" - "forcefps=true\n" + "minfps=-1\n" "\n" "; Command & Conquer: Tiberian Sun Demo\n" "[SUN]\n" "noactivateapp=true\n" "handlemouse=false\n" "maxfps=60\n" - "forcefps=true\n" + "minfps=-1\n" "\n" "; Command & Conquer: Tiberian Sun - CnCNet\n" "[ts-spawn]\n" "noactivateapp=true\n" "handlemouse=false\n" "maxfps=60\n" - "forcefps=true\n" + "minfps=-1\n" "\n" "; Command & Conquer: Red Alert 2 - XWIS\n" "[ra2]\n" "noactivateapp=true\n" "handlemouse=false\n" "maxfps=60\n" - "forcefps=true\n" + "minfps=-1\n" "\n" "; Command & Conquer: Red Alert 2 - XWIS\n" "[Red Alert 2]\n" "noactivateapp=true\n" "handlemouse=false\n" "maxfps=60\n" - "forcefps=true\n" + "minfps=-1\n" "\n" "; Command & Conquer: Red Alert 2: Yuri's Revenge\n" "[gamemd]\n" "noactivateapp=true\n" "handlemouse=false\n" "maxfps=60\n" - "forcefps=true\n" + "minfps=-1\n" "\n" "; Command & Conquer: Red Alert 2: Yuri's Revenge - ?ModExe?\n" "[ra2md]\n" "noactivateapp=true\n" "handlemouse=false\n" "maxfps=60\n" - "forcefps=true\n" + "minfps=-1\n" "\n" "; Command & Conquer: Red Alert 2: Yuri's Revenge - CnCNet\n" "[gamemd-spawn]\n" "noactivateapp=true\n" "handlemouse=false\n" "maxfps=60\n" - "forcefps=true\n" + "minfps=-1\n" "\n" "; Command & Conquer: Red Alert 2: Yuri's Revenge - XWIS\n" "[Yuri's Revenge]\n" "noactivateapp=true\n" "handlemouse=false\n" "maxfps=60\n" - "forcefps=true\n" + "minfps=-1\n" "\n" "; Twisted Metal\n" "[TWISTED]\n" "renderer=opengl\n" "nonexclusive=true\n" "maxgameticks=25\n" - "maxfps=25\n" - "forcefps=true\n" + "minfps=5\n" "\n" "; Twisted Metal 2\n" "[Tm2]\n" diff --git a/src/render_d3d9.c b/src/render_d3d9.c index 9bfe54e..9ffaaa0 100644 --- a/src/render_d3d9.c +++ b/src/render_d3d9.c @@ -319,8 +319,10 @@ DWORD WINAPI d3d9_render_main(void) DWORD tick_end = 0; BOOL needs_update = FALSE; + DWORD timeout = g_ddraw->render.minfps > 0 ? g_ddraw->render.minfps_tick_len : 200; + while (g_ddraw->render.run && - (g_ddraw->render.forcefps || WaitForSingleObject(g_ddraw->render.sem, 200) != WAIT_FAILED)) + (g_ddraw->render.minfps < 0 || WaitForSingleObject(g_ddraw->render.sem, timeout) != WAIT_FAILED)) { #if _DEBUG dbg_draw_frame_info_start(); diff --git a/src/render_gdi.c b/src/render_gdi.c index e1c96b7..7ed0ba6 100644 --- a/src/render_gdi.c +++ b/src/render_gdi.c @@ -49,8 +49,10 @@ DWORD WINAPI gdi_render_main(void) g_ddraw->fps_limiter.tick_length = len + (g_ddraw->accurate_timers ? 0.5f : 0.0f); } + DWORD timeout = g_ddraw->render.minfps > 0 ? g_ddraw->render.minfps_tick_len : INFINITE; + while (g_ddraw->render.run && - (g_ddraw->render.forcefps || WaitForSingleObject(g_ddraw->render.sem, INFINITE) != WAIT_FAILED)) + (g_ddraw->render.minfps < 0 || WaitForSingleObject(g_ddraw->render.sem, timeout) != WAIT_FAILED)) { #if _DEBUG dbg_draw_frame_info_start(); diff --git a/src/render_ogl.c b/src/render_ogl.c index 188d0f4..1da92ce 100644 --- a/src/render_ogl.c +++ b/src/render_ogl.c @@ -547,8 +547,10 @@ static void ogl_render() glEnable(GL_TEXTURE_2D); } + DWORD timeout = g_ddraw->render.minfps > 0 ? g_ddraw->render.minfps_tick_len : INFINITE; + while (g_ogl.use_opengl && g_ddraw->render.run && - (g_ddraw->render.forcefps || WaitForSingleObject(g_ddraw->render.sem, INFINITE) != WAIT_FAILED)) + (g_ddraw->render.minfps < 0 || WaitForSingleObject(g_ddraw->render.sem, timeout) != WAIT_FAILED)) { #if _DEBUG dbg_draw_frame_info_start();