diff --git a/src/d_main.cpp b/src/d_main.cpp index 828f2023b..67f6f2e81 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -132,6 +132,8 @@ boolean devparm = false; // started game with -devparm boolean singletics = false; // timedemo boolean lastdraw = false; +static INT32 lastwipetic = 0; + INT32 postimgparam[MAXSPLITSCREENPLAYERS]; // These variables are in effect @@ -734,6 +736,178 @@ static bool D_Display(void) return ranwipe; } +static void D_WipeTick(boolean menu) +{ + I_OsPolling(); + D_ProcessEvents(); + + // Update the network so we don't cause timeouts + NetKeepAlive(); + + HU_Ticker(); + if (menu) + { +#ifdef HAVE_THREADS + I_lock_mutex(&m_menu_mutex); +#endif + M_Ticker(); +#ifdef HAVE_THREADS + I_unlock_mutex(m_menu_mutex); +#endif + } + CON_Ticker(); +} + +static void D_WipeDraw(boolean menu) +{ + if (rendermode == render_none) + return; + + I_UpdateNoBlit(); + + HU_Erase(); + HU_Drawer(); + if (menu) + { +#ifdef HAVE_THREADS + I_lock_mutex(&m_menu_mutex); +#endif + M_Drawer(); +#ifdef HAVE_THREADS + I_unlock_mutex(m_menu_mutex); +#endif + } + CON_Drawer(); + + I_FinishUpdate(); // page flip or blit buffer +} + +static double D_EndFrame(precise_t enterprecise, int *frameskip) +{ + // Fully completed frame made. + precise_t finishprecise = I_GetPreciseTime(); + + // Use the time before sleep for frameskip calculations: + // post-sleep time is literally being intentionally wasted + double deltasecs = (double)((INT64)(finishprecise - enterprecise)) / I_GetPrecisePrecision(); + double deltatics = deltasecs * NEWTICRATE; + + // If time spent this game loop exceeds a single tic, + // it's probably because of rendering. + // + // Skip rendering the next frame, up to a limit of 3 + // frames before a frame is rendered no matter what. + if (frameskip) + { + if (*frameskip < 3 && deltatics > 1.0) + *frameskip += 1; + else + *frameskip = 0; + } + + if (!singletics) + { + precise_t elapsed = finishprecise - enterprecise; + + // capbudget is the minimum precise_t duration of a single loop iteration + precise_t capbudget = round((1.0 / R_GetFramerateCap()) * I_GetPrecisePrecision()); + + // in the case of "match refresh rate" + vsync, don't sleep at all + const boolean vsync_with_match_refresh = cv_vidwait.value && cv_fpscap.value == 0; + + if (elapsed > 0 && capbudget > elapsed && !vsync_with_match_refresh) + { + I_SleepDuration(capbudget - (finishprecise - enterprecise)); + } + } + + // Capture the time once more to get the real delta time. + finishprecise = I_GetPreciseTime(); + deltasecs = (double)((INT64)(finishprecise - enterprecise)) / I_GetPrecisePrecision(); + return deltasecs * NEWTICRATE; +} + +static INT32 endtimes[] = { + [WIPELOOP_RUNWIPE] = UINT8_MAX, + [WIPELOOP_TITLECARD] = PRELEVELTIME*NEWTICRATERATIO, + [WIPELOOP_ENCORE] = 3*TICRATE/2, + [WIPELOOP_TITLEBLACK] = NEWTICRATE, // Shortened the quit time, used to be 2 seconds +}; + +// one single function for all the extra main loops in this god-forsaken codebase +// should make it easier to fold these back into D_SRB2Loop at some point... +void D_WipeLoop(wipelooptype_t type, UINT8 wipetype, boolean drawMenu) +{ + tic_t nowtime, endtime; + UINT8 wipeframe = 0; + fademask_t *fmask; + double delta = 0.0; + + nowtime = lastwipetic = I_GetTime(); + endtime = nowtime + endtimes[type]; + + if (gamestate != GS_TITLESCREEN && gamestate != GS_TIMEATTACK) + drawMenu = true; + + // lastwipetic should either be 0 or the tic we last wiped + // on for fade-to-black + while (nowtime < endtime) + { + precise_t enterprecise = I_GetPreciseTime(); + I_UpdateTime(cv_timescale.value); + + nowtime = I_GetTime(); + + // wait loop + if (nowtime - lastwipetic) + { + renderisnewtic = true; + wipeframe++; + D_WipeTick(drawMenu); + if (type == WIPELOOP_TITLECARD) + ST_runTitleCard(); + } + else + renderisnewtic = false; + + // draw loop + rendertimefrac = g_time.timefrac; + renderdeltatics = FLOAT_TO_FIXED(delta); + +#ifndef NOWIPE + if (type == WIPELOOP_RUNWIPE) + { + // get fademask first so we can tell if it exists or not + fmask = F_GetFadeMask(wipetype, wipeframe); + if (!fmask) + break; + +#ifdef HWRENDER + if (rendermode == render_opengl) + HWR_DoWipe(wipetype, wipeframe); // send in the wipe type and wipeframe because we need to cache the graphic + else +#endif + if (rendermode != render_none) //this allows F_RunWipe to be called in dedicated servers + F_DoWipe(fmask); + } +#endif + + if (type == WIPELOOP_TITLECARD) + ST_preLevelTitleCardDrawer(); + + D_WipeDraw(drawMenu); + + // Only take screenshots after drawing. + if (moviemode) + M_SaveFrame(); + if (takescreenshot) + M_DoScreenShot(); + + delta = D_EndFrame(enterprecise, NULL); + lastwipetic = nowtime; + } +} + // ========================================================================= // D_SRB2Loop // ========================================================================= @@ -744,7 +918,6 @@ void D_SRB2Loop(void) { tic_t entertic = 0, oldentertics = 0, realtics = 0, rendertimeout = INFTICS; double deltatics = 0.0; - double deltasecs = 0.0; boolean interp = false; boolean doDisplay = false; @@ -797,20 +970,11 @@ void D_SRB2Loop(void) for (;;) { - // capbudget is the minimum precise_t duration of a single loop iteration - precise_t capbudget; precise_t enterprecise = I_GetPreciseTime(); - precise_t finishprecise = enterprecise; g_dc = {}; Z_Frame_Reset(); - { - // Casting the return value of a function is bad practice (apparently) - double budget = round((1.0 / R_GetFramerateCap()) * I_GetPrecisePrecision()); - capbudget = (precise_t) budget; - } - bool ranwipe = false; I_UpdateTime(cv_timescale.value); @@ -965,47 +1129,11 @@ void D_SRB2Loop(void) } #endif - // Fully completed frame made. - finishprecise = I_GetPreciseTime(); - - // Use the time before sleep for frameskip calculations: - // post-sleep time is literally being intentionally wasted - deltasecs = (double)((INT64)(finishprecise - enterprecise)) / I_GetPrecisePrecision(); - deltatics = deltasecs * NEWTICRATE; - - // If time spent this game loop exceeds a single tic, - // it's probably because of rendering. - // - // Skip rendering the next frame, up to a limit of 3 - // frames before a frame is rendered no matter what. - // // Wipes run an inner loop and artificially increase // the measured time. - if (!ranwipe && frameskip < 3 && deltatics > 1.0) - { - frameskip++; - } - else - { + if (ranwipe) frameskip = 0; - } - - if (!singletics) - { - INT64 elapsed = (INT64)(finishprecise - enterprecise); - - // in the case of "match refresh rate" + vsync, don't sleep at all - const boolean vsync_with_match_refresh = cv_vidwait.value && cv_fpscap.value == 0; - - if (elapsed > 0 && (INT64)capbudget > elapsed && !vsync_with_match_refresh) - { - I_SleepDuration(capbudget - (finishprecise - enterprecise)); - } - } - // Capture the time once more to get the real delta time. - finishprecise = I_GetPreciseTime(); - deltasecs = (double)((INT64)(finishprecise - enterprecise)) / I_GetPrecisePrecision(); - deltatics = deltasecs * NEWTICRATE; + deltatics = D_EndFrame(enterprecise, !ranwipe ? &frameskip : NULL); } } diff --git a/src/d_main.h b/src/d_main.h index 5210c76be..a9749408a 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -61,6 +61,16 @@ extern char srb2path[256]; //Alam: SRB2's Home // the infinite loop of D_SRB2Loop() called from win_main for windows version void D_SRB2Loop(void) FUNCNORETURN; +typedef enum +{ + WIPELOOP_RUNWIPE, + WIPELOOP_TITLECARD, + WIPELOOP_ENCORE, + WIPELOOP_TITLEBLACK, +} wipelooptype_t; + +void D_WipeLoop(wipelooptype_t type, UINT8 wipetype, boolean drawMenu); + // // D_SRB2Main() // Not a globally visible function, just included for source reference, diff --git a/src/f_finale.c b/src/f_finale.c index e8de3b581..0c648bc36 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -431,34 +431,7 @@ void F_IntroTicker(void) } // Stay on black for a bit. =) - { - tic_t nowtime, quittime, lasttime; - nowtime = lasttime = I_GetTime(); - quittime = nowtime + NEWTICRATE; // Shortened the quit time, used to be 2 seconds - while (quittime > nowtime) - { - while (!((nowtime = I_GetTime()) - lasttime)) - { - I_Sleep(cv_sleep.value); - I_UpdateTime(cv_timescale.value); - } - lasttime = nowtime; - - I_OsPolling(); - I_UpdateNoBlit(); -#ifdef HAVE_THREADS - I_lock_mutex(&m_menu_mutex); -#endif - M_Drawer(); // menu is drawn even on top of wipes -#ifdef HAVE_THREADS - I_unlock_mutex(m_menu_mutex); -#endif - I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001 - - if (moviemode) // make sure we save frames for the white hold too - M_SaveFrame(); - } - } + D_WipeLoop(WIPELOOP_TITLEBLACK, 0, false); D_StartTitle(); return; diff --git a/src/f_finale.h b/src/f_finale.h index 4c8da0b23..516a0caf3 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -145,12 +145,12 @@ void F_MenuPresTicker(boolean run); extern boolean WipeInAction; extern boolean WipeStageTitle; -extern INT32 lastwipetic; - // Don't know where else to place this constant // But this file seems appropriate #define PRELEVELTIME TICRATE // frames in tics +fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum); +void F_DoWipe(fademask_t *fademask); void F_WipeStartScreen(void); void F_WipeEndScreen(void); void F_RunWipe(UINT8 wipetype, boolean drawMenu); diff --git a/src/f_wipe.c b/src/f_wipe.c index 0497ae497..f52ca8d55 100644 --- a/src/f_wipe.c +++ b/src/f_wipe.c @@ -43,12 +43,12 @@ #define NOWIPE // do not enable wipe image post processing for ARM, SH and MIPS CPUs #endif -typedef struct fademask_s { +struct fademask_t { UINT8* mask; UINT16 width, height; size_t size; fixed_t xscale, yscale; -} fademask_t; +}; UINT8 wipedefs[NUMWIPEDEFS] = { 99, // wipe_credits_intermediate (0) @@ -85,7 +85,6 @@ UINT8 wipedefs[NUMWIPEDEFS] = { boolean WipeInAction = false; boolean WipeStageTitle = false; -INT32 lastwipetic = 0; #ifndef NOWIPE @@ -101,7 +100,7 @@ static fixed_t paldiv; * \param lump Lump name to get data from * \return fademask_t for lump */ -static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) { +fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) { static char lumpname[9] = "FADEmmss"; static fademask_t fm = {NULL,0,0,0,0,0}; lumpnum_t lumpnum; @@ -186,7 +185,7 @@ static fademask_t *F_GetFadeMask(UINT8 masknum, UINT8 scrnnum) { * * \param fademask pixels to change */ -static void F_DoWipe(fademask_t *fademask) +void F_DoWipe(fademask_t *fademask) { // Software mask wipe -- optimized; though it might not look like it! // Okay, to save you wondering *how* this is more optimized than the simpler @@ -360,62 +359,14 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu) (void)wipetype; (void)drawMenu; #else - tic_t nowtime; - UINT8 wipeframe = 0; - fademask_t *fmask; - paldiv = FixedDiv(257<