diff --git a/src/Sourcefile b/src/Sourcefile index fa82f86da..de90bb609 100644 --- a/src/Sourcefile +++ b/src/Sourcefile @@ -18,6 +18,7 @@ am_map.c command.c console.c hu_stuff.c +i_time.c y_inter.c st_stuff.c m_aatree.c diff --git a/src/android/i_system.c b/src/android/i_system.c index 7256bac34..e6e840ac0 100644 --- a/src/android/i_system.c +++ b/src/android/i_system.c @@ -82,18 +82,6 @@ INT64 current_time_in_ps() { return (t.tv_sec * (INT64)1000000) + t.tv_usec; } -tic_t I_GetTime(void) -{ - INT64 since_start = current_time_in_ps() - start_time; - return (since_start*TICRATE)/1000000; -} - -fixed_t I_GetTimeFrac(void) -{ - //stub - return 0; -} - void I_Sleep(void){} void I_GetEvent(void){} diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 74f3dd959..ac0ccc054 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -15,6 +15,7 @@ #include //for unlink #endif +#include "i_time.h" #include "i_net.h" #include "i_system.h" #include "i_video.h" diff --git a/src/d_main.c b/src/d_main.c index ec5b354cd..b2f10988a 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -40,6 +40,7 @@ #include "hu_stuff.h" #include "i_sound.h" #include "i_system.h" +#include "i_time.h" #include "i_threads.h" #include "i_video.h" #include "m_argv.h" @@ -695,10 +696,9 @@ tic_t rendergametic; void D_SRB2Loop(void) { - tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS; + tic_t realtics = 0, rendertimeout = INFTICS; static lumpnum_t gstartuplumpnum; - boolean ticked = false; boolean interp = false; boolean doDisplay = false; boolean screenUpdate = false; @@ -715,7 +715,7 @@ void D_SRB2Loop(void) I_DoStartupMouse(); #endif - oldentertics = I_GetTime(); + I_UpdateTime(cv_timescale.value); // end of loading screen: CONS_Printf() will no more call FinishUpdate() con_refresh = false; @@ -757,17 +757,18 @@ void D_SRB2Loop(void) { frameEnd = I_GetFrameTime(); + I_UpdateTime(cv_timescale.value); + + // Can't guarantee that I_UpdateTime won't be called inside TryRunTics + // so capture the realtics for later use + realtics = g_time.realtics; + if (lastwipetic) { - oldentertics = lastwipetic; + // oldentertics = lastwipetic; lastwipetic = 0; } - // get real tics - entertic = I_GetTime(); - realtics = entertic - oldentertics; - oldentertics = entertic; - if (demoplayback && gamestate == GS_LEVEL) { // Nicer place to put this. @@ -782,7 +783,6 @@ void D_SRB2Loop(void) interp = R_UsingFrameInterpolation() && !dedicated; doDisplay = screenUpdate = false; - ticked = false; #ifdef HW3SOUND HW3S_BeginFrameUpdate(); @@ -798,16 +798,16 @@ void D_SRB2Loop(void) realtics = 1; // process tics (but maybe not if realtic == 0) - ticked = TryRunTics(realtics); + TryRunTics(realtics); if (lastdraw || singletics || gametic > rendergametic) { rendergametic = gametic; - rendertimeout = entertic+TICRATE/17; + rendertimeout = g_time.time + TICRATE/17; doDisplay = true; } - else if (rendertimeout < entertic) // in case the server hang or netsplit + else if (rendertimeout < g_time.time) // in case the server hang or netsplit { // Lagless camera! Yay! if (gamestate == GS_LEVEL && netgame) @@ -836,41 +836,21 @@ void D_SRB2Loop(void) if (interp) { - static float tictime = 0.0f; - static float prevtime = 0.0f; - float entertime = I_GetTimeFrac(); - - fixed_t entertimefrac = FRACUNIT; - - if (ticked) - { - tictime = entertime; - } - // I looked at the possibility of putting in a float drawer for // perfstats and it's very complicated, so we'll just do this instead... - ps_interp_frac.value.p = (precise_t)((entertime - tictime) * 1000.0f); - ps_interp_lag.value.p = (precise_t)((entertime - prevtime) * 1000.0f); + ps_interp_frac.value.p = (precise_t)((FIXED_TO_FLOAT(g_time.timefrac)) * 1000.0f); + ps_interp_lag.value.p = (precise_t)((FIXED_TO_FLOAT(g_time.deltaseconds)) * 1000.0f); + + renderdeltatics = g_time.deltatics; if (!(paused || P_AutoPause())) { - if (entertime - prevtime >= 1.0f) - { - // Lagged for more frames than a gametic... - // No need for interpolation. - entertimefrac = FRACUNIT; - } - else - { - entertimefrac = min(FRACUNIT, FLOAT_TO_FIXED(entertime - tictime)); - } - - // renderdeltatics is a bit awkard to evaluate, since the system time interface is whole tic-based - renderdeltatics = FloatToFixed(entertime - prevtime); - rendertimefrac = entertimefrac; + rendertimefrac = g_time.timefrac; + } + else + { + rendertimefrac = FRACUNIT; } - - prevtime = entertime; } else { @@ -1398,8 +1378,8 @@ void D_SRB2Main(void) //---------------------------------------------------- READY TIME // we need to check for dedicated before initialization of some subsystems - CONS_Printf("I_StartupTimer()...\n"); - I_StartupTimer(); + CONS_Printf("I_InitializeTime()...\n"); + I_InitializeTime(); // Make backups of some SOCcable tables. P_BackupTables(); diff --git a/src/d_net.c b/src/d_net.c index 5e5c10889..c2a86481f 100644 --- a/src/d_net.c +++ b/src/d_net.c @@ -18,6 +18,7 @@ #include "doomdef.h" #include "g_game.h" +#include "i_time.h" #include "i_net.h" #include "i_system.h" #include "m_argv.h" diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9b14e0913..024f4fede 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -16,6 +16,7 @@ #include "console.h" #include "command.h" +#include "i_time.h" #include "i_system.h" #include "g_game.h" #include "hu_stuff.h" diff --git a/src/d_netfil.c b/src/d_netfil.c index 37fb7265f..edbef30bb 100644 --- a/src/d_netfil.c +++ b/src/d_netfil.c @@ -35,6 +35,7 @@ #include "doomstat.h" #include "d_main.h" #include "g_game.h" +#include "i_time.h" #include "i_net.h" #include "i_system.h" #include "m_argv.h" diff --git a/src/dummy/i_system.c b/src/dummy/i_system.c index f3d0bc5e8..d11e8e576 100644 --- a/src/dummy/i_system.c +++ b/src/dummy/i_system.c @@ -11,16 +11,6 @@ UINT32 I_GetFreeMem(UINT32 *total) return 0; } -tic_t I_GetTime(void) -{ - return 0; -} - -fixed_t I_GetTimeFrac(void) -{ - return 0; -} - void I_Sleep(void){} void I_GetEvent(void){} diff --git a/src/f_finale.c b/src/f_finale.c index 4ddcaff5f..a26600101 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -20,6 +20,7 @@ #include "hu_stuff.h" #include "r_local.h" #include "s_sound.h" +#include "i_time.h" #include "i_video.h" #include "v_video.h" #include "w_wad.h" diff --git a/src/f_wipe.c b/src/f_wipe.c index 43b7180b7..612d2ab83 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -24,6 +24,7 @@ #include "w_wad.h" #include "z_zone.h" +#include "i_time.h" #include "i_system.h" #include "i_threads.h" #include "m_menu.h" diff --git a/src/g_demo.c b/src/g_demo.c index 7a7236945..9a0d5a293 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -17,6 +17,7 @@ #include "d_player.h" #include "d_clisrv.h" #include "p_setup.h" +#include "i_time.h" #include "i_system.h" #include "m_random.h" #include "p_local.h" diff --git a/src/g_game.c b/src/g_game.c index 8eb731b1f..dfc5fadd5 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -19,6 +19,7 @@ #include "f_finale.h" #include "p_setup.h" #include "p_saveg.h" +#include "i_time.h" #include "i_system.h" #include "am_map.h" #include "m_random.h" diff --git a/src/i_system.h b/src/i_system.h index f607ec79c..bf4627d54 100644 --- a/src/i_system.h +++ b/src/i_system.h @@ -42,14 +42,6 @@ extern UINT8 keyboard_started; */ UINT32 I_GetFreeMem(UINT32 *total); -/** \brief Called by D_SRB2Loop, returns current time in game tics. -*/ -tic_t I_GetTime(void); - -/** \brief Get the current time in game tics, including fractions. -*/ -float I_GetTimeFrac(void); - /** \brief Returns precise time value for performance measurement. */ precise_t I_GetPreciseTime(void); @@ -58,6 +50,10 @@ precise_t I_GetPreciseTime(void); */ int I_PreciseToMicros(precise_t d); +/** \brief Calculates the elapsed microseconds between two precise_t. + */ +double I_PreciseElapsedSeconds(precise_t before, precise_t after); + /** \brief Get the current time in rendering tics, including fractions. */ double I_GetFrameTime(void); diff --git a/src/i_time.c b/src/i_time.c new file mode 100644 index 000000000..93f9b3410 --- /dev/null +++ b/src/i_time.c @@ -0,0 +1,86 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file i_time.c +/// \brief Timing for the system layer. + +#include "i_time.h" + +#include "command.h" +#include "doomtype.h" +#include "m_fixed.h" +#include "i_system.h" + +timestate_t g_time; + +static CV_PossibleValue_t timescale_cons_t[] = {{FRACUNIT/20, "MIN"}, {20*FRACUNIT, "MAX"}, {0, NULL}}; +consvar_t cv_timescale = CVAR_INIT ("timescale", "1.0", CV_NETVAR|CV_CHEAT|CV_FLOAT, timescale_cons_t, NULL); + +static precise_t enterprecise, oldenterprecise; +static fixed_t entertic, oldentertics; +static double tictimer; + +tic_t I_GetTime(void) +{ + return g_time.time; +} + +void I_InitializeTime(void) +{ + g_time.time = 0; + g_time.timefrac = 0; + g_time.realtics = 0; + g_time.deltaseconds = 0; + g_time.ticrate = FLOAT_TO_FIXED(TICRATE); + + enterprecise = 0; + oldenterprecise = 0; + tictimer = 0.0; + + CV_RegisterVar(&cv_timescale); + + // I_StartupTimer is preserved for potential subsystems that need to setup + // timing information for I_GetPreciseTime and sleeping + I_StartupTimer(); +} + +void I_UpdateTime(fixed_t timescale) +{ + double ticratescaled; + double elapsedseconds; + tic_t realtics; + + // get real tics + ticratescaled = (double)TICRATE * FIXED_TO_FLOAT(timescale); + + enterprecise = I_GetPreciseTime(); + elapsedseconds = I_PreciseElapsedSeconds(oldenterprecise, enterprecise); + tictimer += elapsedseconds; + while (tictimer > 1.0/ticratescaled) + { + entertic += 1; + tictimer -= 1.0/ticratescaled; + } + realtics = entertic - oldentertics; + oldentertics = entertic; + oldenterprecise = enterprecise; + + // Update global time state + g_time.time += realtics; + { + double fractional, integral; + fractional = modf(tictimer * ticratescaled, &integral); + g_time.timefrac = FLOAT_TO_FIXED(fractional); + } + g_time.realtics = realtics; + g_time.deltatics = FLOAT_TO_FIXED(elapsedseconds * ticratescaled); + g_time.deltaseconds = FLOAT_TO_FIXED(elapsedseconds); + g_time.ticrate = FLOAT_TO_FIXED(ticratescaled); +} diff --git a/src/i_time.h b/src/i_time.h new file mode 100644 index 000000000..077174756 --- /dev/null +++ b/src/i_time.h @@ -0,0 +1,51 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2022 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file i_time.h +/// \brief Timing for the system layer. + +#ifndef __I_TIME_H__ +#define __I_TIME_H__ + +#include "command.h" +#include "doomtype.h" +#include "m_fixed.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct timestate_s { + tic_t time; + fixed_t timefrac; + fixed_t realtics; + fixed_t deltatics; + fixed_t deltaseconds; + fixed_t ticrate; +} timestate_t; + +extern timestate_t g_time; +extern consvar_t cv_timescale; + +/** \brief Called by D_SRB2Loop, returns current time in game tics. +*/ +tic_t I_GetTime(void); + +/** \brief Initializes timing system. +*/ +void I_InitializeTime(void); + +void I_UpdateTime(fixed_t timescale); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __I_TIME_H__ diff --git a/src/m_menu.c b/src/m_menu.c index d32782ed1..0c0f90386 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -32,6 +32,7 @@ // Data. #include "sounds.h" #include "s_sound.h" +#include "i_time.h" #include "i_system.h" #include "i_threads.h" diff --git a/src/m_misc.c b/src/m_misc.c index d7d6d6bbb..a400865f3 100644 --- a/src/m_misc.c +++ b/src/m_misc.c @@ -36,6 +36,7 @@ #include "v_video.h" #include "z_zone.h" #include "g_input.h" +#include "i_time.h" #include "i_video.h" #include "d_main.h" #include "m_argv.h" diff --git a/src/p_setup.c b/src/p_setup.c index 0e7432bbf..20c6952d9 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -21,6 +21,7 @@ #include "p_spec.h" #include "p_saveg.h" +#include "i_time.h" #include "i_sound.h" // for I_PlayCD().. #include "i_video.h" // for I_FinishUpdate().. #include "r_sky.h" diff --git a/src/screen.c b/src/screen.c index 6ad36273b..62b1fe05c 100644 --- a/src/screen.c +++ b/src/screen.c @@ -15,6 +15,7 @@ #include "screen.h" #include "console.h" #include "am_map.h" +#include "i_time.h" #include "i_system.h" #include "i_video.h" #include "r_local.h" diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index afd13910c..de7369236 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -170,6 +170,7 @@ static char returnWadPath[256]; #include "../doomdef.h" #include "../m_misc.h" +#include "../i_time.h" #include "../i_video.h" #include "../i_sound.h" #include "../i_system.h" @@ -2143,44 +2144,6 @@ ticcmd_t *I_BaseTiccmd2(void) static Uint64 timer_frequency; -static double tic_frequency; -static Uint64 tic_epoch; -static double elapsed_tics; - -static void UpdateTicFreq(void) -{ - tic_frequency = (timer_frequency / (double)NEWTICRATE) / FixedToFloat(cv_timescale.value); -} - -static CV_PossibleValue_t timescale_cons_t[] = {{FRACUNIT/20, "MIN"}, {20*FRACUNIT, "MAX"}, {0, NULL}}; -consvar_t cv_timescale = CVAR_INIT ("timescale", "1.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_CALL, timescale_cons_t, UpdateTicFreq); - -static void UpdateElapsedTics(void) -{ - const Uint64 now = SDL_GetPerformanceCounter(); - - elapsed_tics += (now - tic_epoch) / tic_frequency; - tic_epoch = now; // moving epoch -} - -tic_t I_GetTime(void) -{ - float f = 0.0f; - - UpdateElapsedTics(); - - // This needs kept in a separate variable before converting - // to tic_t, due to stupid -Wbad-function-cast error. - f = floor(elapsed_tics); - return (tic_t)f; -} - -float I_GetTimeFrac(void) -{ - UpdateElapsedTics(); - return elapsed_tics; -} - // // I_GetPreciseTime // returns time in precise_t @@ -2201,6 +2164,11 @@ int I_PreciseToMicros(precise_t d) return (int)(UINT64)(d / (timer_frequency / 1000000.0)); } +double I_PreciseElapsedSeconds(precise_t before, precise_t after) +{ + return (after - before) / (double)timer_frequency; +} + // // I_GetFrameTime // returns time in 1/fpscap second tics @@ -2259,15 +2227,9 @@ double I_GetFrameTime(void) // void I_StartupTimer(void) { - CV_RegisterVar(&cv_timescale); - timer_frequency = SDL_GetPerformanceFrequency(); - tic_epoch = SDL_GetPerformanceCounter(); - tic_frequency = timer_frequency / (double)NEWTICRATE; - elapsed_tics = 0.0; - - I_InitFrameTime(tic_epoch, R_GetFramerateCap()); + I_InitFrameTime(0, R_GetFramerateCap()); elapsed_frames = 0.0; } @@ -2279,6 +2241,10 @@ void I_Sleep(void) { if (cv_sleep.value > 0) SDL_Delay(cv_sleep.value); + + // I_Sleep is still called in a number of places + // we need to update the internal time state to make this work + I_UpdateTime(cv_timescale.value); } // diff --git a/src/w_wad.c b/src/w_wad.c index 0a8f630a8..b24614647 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -59,6 +59,7 @@ #include "r_textures.h" #include "r_patch.h" #include "r_picformats.h" +#include "i_time.h" #include "i_system.h" #include "i_video.h" // rendermode #include "md5.h" diff --git a/src/win32/win_sys.c b/src/win32/win_sys.c index 393b913da..7e6f82a29 100644 --- a/src/win32/win_sys.c +++ b/src/win32/win_sys.c @@ -35,6 +35,7 @@ #include #include "../m_misc.h" +#include "../i_time.h" #include "../i_video.h" #include "../i_sound.h" #include "../i_system.h" @@ -262,15 +263,12 @@ tic_t I_GetTime(void) return newtics; } -fixed_t I_GetTimeFrac(void) -{ - return 0; -} - void I_Sleep(void) { if (cv_sleep.value != -1) Sleep(cv_sleep.value); + + I_UpdateTime(cv_timescale.value); } // should move to i_video