Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart.git into new-menus

# Conflicts:
#	src/Sourcefile
#	src/f_finale.c
#	src/m_menu.c
#	src/y_inter.c
This commit is contained in:
toaster 2022-05-22 17:22:49 +01:00
commit 54b9f3b7cc
65 changed files with 2598 additions and 720 deletions

View file

@ -45,6 +45,9 @@ endif
ifdef GCC45
#WFLAGS+=-Wc++-compat
WFLAGS+=-std=gnu99
endif
ifdef GCC47
WFLAGS+=-std=gnu11
endif
WFLAGS+=-Wcast-qual
ifndef NOCASTALIGNWARN

View file

@ -20,6 +20,7 @@ command.c
console.c
font.c
hu_stuff.c
i_time.c
y_inter.c
st_stuff.c
m_aatree.c
@ -96,6 +97,7 @@ lua_taglib.c
lua_polyobjlib.c
lua_blockmaplib.c
lua_hudlib.c
lua_hudlib_drawlist.c
k_kart.c
k_respawn.c
k_collide.c

View file

@ -82,20 +82,18 @@ INT64 current_time_in_ps() {
return (t.tv_sec * (INT64)1000000) + t.tv_usec;
}
tic_t I_GetTime(void)
void I_Sleep(UINT32 ms){}
precise_t I_GetPreciseTime(void)
{
INT64 since_start = current_time_in_ps() - start_time;
return (since_start*TICRATE)/1000000;
return 0;
}
fixed_t I_GetTimeFrac(void)
UINT64 I_GetPrecisePrecision(void)
{
//stub
return 0;
return 1000000;
}
void I_Sleep(void){}
void I_GetEvent(void){}
void I_OsPolling(void){}

View file

@ -2013,9 +2013,10 @@ void CV_AddValue(consvar_t *var, INT32 increment)
{
increment = 0;
currentindice = max;
break; // The value we definitely want, stop here.
}
else if (var->PossibleValue[max].value == var->value)
currentindice = max;
currentindice = max; // The value we maybe want.
}
if (increment)

View file

@ -15,6 +15,7 @@
#include <unistd.h> //for unlink
#endif
#include "i_time.h"
#include "i_net.h"
#include "i_system.h"
#include "i_video.h"
@ -1949,7 +1950,10 @@ static boolean CL_ServerConnectionTicker(const char *tmpsave, tic_t *oldtic, tic
#endif
}
else
I_Sleep();
{
I_Sleep(cv_sleep.value);
I_UpdateTime(cv_timescale.value);
}
return true;
}

View file

@ -520,12 +520,12 @@ extern UINT8 hu_redownloadinggamestate;
extern UINT8 adminpassmd5[16];
extern boolean adminpasswordset;
extern boolean hu_stopped;
//
// SRB2Kart
//
extern boolean hu_stopped;
typedef struct rewind_s {
UINT8 savebuffer[(768*1024)];
tic_t leveltime;

View file

@ -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"
@ -467,6 +468,8 @@ static void D_Display(void)
{
if (!automapactive && !dedicated && cv_renderview.value)
{
R_ApplyLevelInterpolators(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT);
viewwindowy = 0;
viewwindowx = 0;
@ -542,6 +545,7 @@ static void D_Display(void)
}
ps_rendercalltime = I_GetPreciseTime() - ps_rendercalltime;
R_RestoreLevelInterpolators();
}
if (lastdraw)
@ -690,29 +694,6 @@ static void D_Display(void)
}
}
static boolean D_CheckFrameCap(void)
{
static boolean init = false;
static precise_t startCap = 0;
precise_t endCap = 0;
endCap = I_GetPreciseTime();
if (init == false)
{
startCap = endCap;
init = true;
}
else if (I_CheckFrameCap(startCap, endCap))
{
// Framerate should be capped.
return true;
}
startCap = endCap;
return false;
}
// =========================================================================
// D_SRB2Loop
// =========================================================================
@ -721,9 +702,11 @@ tic_t rendergametic;
void D_SRB2Loop(void)
{
tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS;
boolean ticked;
boolean interp;
tic_t entertic = 0, oldentertics = 0, realtics = 0, rendertimeout = INFTICS;
double deltatics = 0.0;
double deltasecs = 0.0;
boolean interp = false;
boolean doDisplay = false;
if (dedicated)
@ -736,6 +719,7 @@ void D_SRB2Loop(void)
I_DoStartupMouse();
#endif
I_UpdateTime(cv_timescale.value);
oldentertics = I_GetTime();
// end of loading screen: CONS_Printf() will no more call FinishUpdate()
@ -777,6 +761,19 @@ 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;
{
// Casting the return value of a function is bad practice (apparently)
double budget = round((1.0 / R_GetFramerateCap()) * I_GetPrecisePrecision());
capbudget = (precise_t) budget;
}
I_UpdateTime(cv_timescale.value);
if (lastwipetic)
{
oldentertics = lastwipetic;
@ -802,16 +799,8 @@ void D_SRB2Loop(void)
debugload--;
#endif
interp = R_UsingFrameInterpolation();
interp = R_UsingFrameInterpolation() && !dedicated;
doDisplay = false;
ticked = false;
if (!realtics && !singletics && !interp)
{
// Non-interp sleep
I_Sleep();
continue;
}
#ifdef HW3SOUND
HW3S_BeginFrameUpdate();
@ -825,76 +814,51 @@ 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 = entertic + TICRATE/17;
doDisplay = true;
}
else if (rendertimeout < entertic) // in case the server hang or netsplit
{
// Lagless camera! Yay!
if (gamestate == GS_LEVEL && netgame)
{
// Evaluate the chase cam once for every local realtic
// This might actually be better suited inside G_Ticker or TryRunTics
for (tic_t chasecamtics = 0; chasecamtics < realtics; chasecamtics++)
{
P_RunChaseCameras();
}
R_UpdateViewInterpolation();
}
doDisplay = true;
}
renderisnewtic = true;
}
else
{
renderisnewtic = false;
}
if (interp)
{
static float tictime = 0.0f;
static float prevtime = 0.0f;
float entertime = I_GetTimeFrac();
renderdeltatics = FLOAT_TO_FIXED(deltatics);
fixed_t entertimefrac = FRACUNIT;
if (ticked)
if (!(paused || P_AutoPause()) && !hu_stopped)
{
tictime = entertime;
rendertimefrac = g_time.timefrac;
}
// Handle interp sleep / framerate cap here.
// TryRunTics needs ran if possible to prevent lagged map changes,
// (and if that runs, the code above needs to also run)
// so this is done here after TryRunTics.
if (D_CheckFrameCap())
else
{
continue;
rendertimefrac = FRACUNIT;
}
if (!(paused || P_AutoPause()))
{
#if 0
CONS_Printf("prevtime = %f\n", prevtime);
CONS_Printf("entertime = %f\n", entertime);
CONS_Printf("tictime = %f\n", tictime);
CONS_Printf("entertime - prevtime = %f\n", entertime - prevtime);
CONS_Printf("entertime - tictime = %f\n", entertime - tictime);
CONS_Printf("========\n");
#endif
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 = realtics * FRACUNIT;
if (entertimefrac > rendertimefrac)
renderdeltatics += entertimefrac - rendertimefrac;
else
renderdeltatics -= rendertimefrac - entertimefrac;
rendertimefrac = entertimefrac;
}
prevtime = entertime;
}
else
{
@ -907,9 +871,10 @@ void D_SRB2Loop(void)
D_Display();
}
// Only take screenshots after drawing.
if (moviemode)
M_SaveFrame();
if (takescreenshot) // Only take screenshots after drawing.
if (takescreenshot)
M_DoScreenShot();
// consoleplayer -> displayplayers (hear sounds from viewpoint)
@ -929,10 +894,20 @@ void D_SRB2Loop(void)
}
#endif
// Moved to here from I_FinishUpdate.
// It doesn't track fades properly anymore by being here (might be easy fix),
// but it's a little more accurate for actual game logic when its here.
SCR_CalculateFPS();
// Fully completed frame made.
finishprecise = I_GetPreciseTime();
if (!singletics)
{
INT64 elapsed = (INT64)(finishprecise - enterprecise);
if (elapsed > 0 && (INT64)capbudget > elapsed)
{
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;
}
}
@ -1406,8 +1381,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();
CON_SetLoadingProgress(LOADED_ISTARTUPTIMER);
// Make backups of some SOCcable tables.

View file

@ -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"
@ -618,7 +619,10 @@ void Net_WaitAllAckReceived(UINT32 timeout)
while (timeout > I_GetTime() && !Net_AllAcksReceived())
{
while (tictac == I_GetTime())
I_Sleep();
{
I_Sleep(cv_sleep.value);
I_UpdateTime(cv_timescale.value);
}
tictac = I_GetTime();
HGetPacket();
Net_AckTicker();

View file

@ -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"

View file

@ -43,6 +43,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"

View file

@ -343,6 +343,7 @@ typedef struct player_s
// fun thing for player sprite
angle_t drawangle;
angle_t old_drawangle; // interp
angle_t old_drawangle2;
// Bit flags.
// See pflags_t, above.

View file

@ -402,9 +402,7 @@ unset_bit_array (bitarray_t * const array, const int value)
array[value >> 3] &= ~(1<<(value & 7));
}
#ifdef HAVE_SDL
typedef UINT64 precise_t;
#endif
#define intsign(n) \
((n) < 0 ? -1 : (n) > 0 ? 1 : 0)

View file

@ -11,18 +11,16 @@ UINT32 I_GetFreeMem(UINT32 *total)
return 0;
}
tic_t I_GetTime(void)
{
void I_Sleep(UINT32 ms){}
precise_t I_GetPreciseTime(void) {
return 0;
}
fixed_t I_GetTimeFrac(void)
{
return 0;
UINT64 I_GetPrecisePrecision(void) {
return 1000000;
}
void I_Sleep(void){}
void I_GetEvent(void){}
void I_OsPolling(void){}

View file

@ -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"
@ -164,6 +165,8 @@ static tic_t cutscene_lasttextwrite = 0;
// STJR Intro
char stjrintro[9] = "STJRI000";
static huddrawlist_h luahuddrawlist_title;
//
// This alters the text string cutscene_disptext.
// Use the typical string drawing functions to display it.
@ -367,9 +370,6 @@ static void F_IntroDrawScene(void)
W_UnlockCachedPatch(background);
if (animtimer)
animtimer--;
V_DrawString(cx, cy, 0, cutscene_disptext);
}
@ -398,7 +398,10 @@ void F_IntroDrawer(void)
while (quittime > nowtime)
{
while (!((nowtime = I_GetTime()) - lasttime))
I_Sleep();
{
I_Sleep(cv_sleep.value);
I_UpdateTime(cv_timescale.value);
}
lasttime = nowtime;
I_OsPolling();
@ -468,6 +471,9 @@ void F_IntroTicker(void)
// check for skipping
if (keypressed)
keypressed = false;
if (animtimer > 0)
animtimer--;
}
//
@ -1705,6 +1711,9 @@ static void F_InitMenuPresValues(void)
curtty = tty;
curttloop = ttloop;
curtttics = tttics;
LUA_HUD_DestroyDrawList(luahuddrawlist_title);
luahuddrawlist_title = LUA_HUD_CreateDrawList();
}
//
@ -1720,7 +1729,7 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname)
INT32 pw, ph; // scaled by dupz
patch_t *pat;
INT32 i, j;
INT32 xscrolltimer, yscrolltimer;
fixed_t fracmenuanimtimer, xscrolltimer, yscrolltimer;
if (rendermode == render_none)
return;
@ -1748,12 +1757,13 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname)
tilex = max(FixedCeil(FixedDiv(vid.width, pw)) >> FRACBITS, 1)+2; // one tile on both sides of center
tiley = max(FixedCeil(FixedDiv(vid.height, ph)) >> FRACBITS, 1)+2;
xscrolltimer = ((menuanimtimer*scrollxspeed)/16 + patwidth*xneg) % (patwidth);
yscrolltimer = ((menuanimtimer*scrollyspeed)/16 + patheight*yneg) % (patheight);
fracmenuanimtimer = (menuanimtimer * FRACUNIT) - (FRACUNIT - rendertimefrac);
xscrolltimer = ((fracmenuanimtimer*scrollxspeed)/16 + patwidth*xneg*FRACUNIT) % (patwidth * FRACUNIT);
yscrolltimer = ((fracmenuanimtimer*scrollyspeed)/16 + patheight*yneg*FRACUNIT) % (patheight * FRACUNIT);
// coordinate offsets
xscrolled = xscrolltimer * dupz;
yscrolled = yscrolltimer * dupz;
xscrolled = FixedInt(xscrolltimer * dupz);
yscrolled = FixedInt(yscrolltimer * dupz);
for (x = (xispos) ? -pw*(tilex-1)+pw : 0, i = 0;
i < tilex;
@ -2059,7 +2069,21 @@ void F_TitleScreenDrawer(void)
}
luahook:
LUAh_TitleHUD();
// The title drawer is sometimes called without first being started
// In order to avoid use-before-initialization crashes, let's check and
// create the drawlist if it doesn't exist.
if (!LUA_HUD_IsDrawListValid(luahuddrawlist_title))
{
LUA_HUD_DestroyDrawList(luahuddrawlist_title);
luahuddrawlist_title = LUA_HUD_CreateDrawList();
}
if (renderisnewtic)
{
LUA_HUD_ClearDrawList(luahuddrawlist_title);
LUAh_TitleHUD(luahuddrawlist_title);
}
LUA_HUD_DrawList(luahuddrawlist_title);
}
// (no longer) De-Demo'd Title Screen
@ -2308,6 +2332,7 @@ static INT32 textxpos, textypos;
static boolean dofadenow = false, cutsceneover = false;
static boolean runningprecutscene = false, precutresetplayer = false;
static void F_AdvanceToNextScene(void)
{
// Don't increment until after endcutscene check
@ -2317,6 +2342,7 @@ static void F_AdvanceToNextScene(void)
F_EndCutScene();
return;
}
++scenenum;
timetonext = 0;
@ -2332,7 +2358,6 @@ static void F_AdvanceToNextScene(void)
cutscenes[cutnum]->scene[scenenum].musswitchposition, 0, 0);
// Fade to the next
dofadenow = true;
F_NewCutscene(cutscenes[cutnum]->scene[scenenum].text);
picnum = 0;
@ -2465,8 +2490,6 @@ void F_CutsceneTicker(void)
finalecount++;
cutscene_boostspeed = 0;
dofadenow = false;
for (i = 0; i < MAXPLAYERS; i++)
{
if (netgame && i != serverplayer && !IsPlayerAdmin(i))

View file

@ -23,6 +23,7 @@
#include "w_wad.h"
#include "z_zone.h"
#include "i_time.h"
#include "i_system.h"
#include "i_threads.h"
#include "console.h"
@ -479,7 +480,10 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu, const char *colormap, boolean r
// wait loop
while (!((nowtime = I_GetTime()) - lastwipetic))
I_Sleep();
{
I_Sleep(cv_sleep.value);
I_UpdateTime(cv_timescale.value);
}
lastwipetic = nowtime;
#ifdef HWRENDER

View file

@ -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"

View file

@ -21,6 +21,7 @@
#include "filesrch.h" // for refreshdirmenu
#include "p_setup.h"
#include "p_saveg.h"
#include "i_time.h"
#include "i_system.h"
#include "am_map.h"
#include "m_random.h"
@ -1303,7 +1304,10 @@ void G_PreLevelTitleCard(void)
M_DoScreenShot();
while (!((nowtime = I_GetTime()) - lasttime))
I_Sleep();
{
I_Sleep(cv_sleep.value);
I_UpdateTime(cv_timescale.value);
}
lasttime = nowtime;
}
#endif
@ -1890,7 +1894,6 @@ void G_Ticker(boolean run)
F_TextPromptTicker();
AM_Ticker();
HU_Ticker();
R_UpdateViewInterpolation();
break;
@ -1948,10 +1951,7 @@ void G_Ticker(boolean run)
case GS_TITLESCREEN:
if (titlemapinaction)
{
P_Ticker(run);
R_UpdateViewInterpolation();
}
F_TitleScreenTicker(run);
break;

View file

@ -51,7 +51,7 @@ EXPORT void HWRAPI(ClearMipMapCache) (void);
EXPORT void HWRAPI(SetSpecialState) (hwdspecialstate_t IdState, INT32 Value);
//Hurdler: added for new development
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface);
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface);
EXPORT void HWRAPI(CreateModelVBOs) (model_t *model);
EXPORT void HWRAPI(SetTransform) (FTransform *stransform);
EXPORT INT32 HWRAPI(GetTextureUsed) (void);

View file

@ -24,6 +24,7 @@
#include "../v_video.h"
#include "../p_local.h"
#include "../p_setup.h"
#include "../r_fps.h"
#include "../r_local.h"
#include "../r_patch.h"
#include "../r_picformats.h"
@ -3051,6 +3052,7 @@ static void HWR_Subsector(size_t num)
INT32 light = 0;
extracolormap_t *floorcolormap;
extracolormap_t *ceilingcolormap;
ffloor_t *rover;
#ifdef PARANOIA //no risk while developing, enough debugging nights!
if (num >= addsubsector)
@ -3108,7 +3110,22 @@ static void HWR_Subsector(size_t num)
if (gl_frontsector->ffloors)
{
if (gl_frontsector->moved)
boolean anyMoved = gl_frontsector->moved;
if (anyMoved == false)
{
for (rover = gl_frontsector->ffloors; rover; rover = rover->next)
{
sector_t *controlSec = &sectors[rover->secnum];
if (controlSec->moved == true)
{
anyMoved = true;
break;
}
}
}
if (anyMoved == true)
{
gl_frontsector->numlights = sub->sector->numlights = 0;
R_Prep3DFloors(gl_frontsector);
@ -3189,7 +3206,6 @@ static void HWR_Subsector(size_t num)
if (gl_frontsector->ffloors)
{
/// \todo fix light, xoffs, yoffs, extracolormap ?
ffloor_t * rover;
for (rover = gl_frontsector->ffloors;
rover; rover = rover->next)
{
@ -3703,9 +3719,17 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
fixed_t slopez;
pslope_t *groundslope;
fixed_t interpx = R_InterpolateFixed(thing->old_x, thing->x);
fixed_t interpy = R_InterpolateFixed(thing->old_y, thing->y);
fixed_t interpz = R_InterpolateFixed(thing->old_z, thing->z);
// uncapped/interpolation
interpmobjstate_t interp = {0};
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(thing, rendertimefrac, &interp);
}
else
{
R_InterpolateMobjState(thing, FRACUNIT, &interp);
}
// hitlag vibrating (todo: interp somehow?)
if (thing->hitlag > 0 && (thing->eflags & MFE_DAMAGEHITLAG))
@ -3717,17 +3741,17 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
mul = -mul;
}
interpx += FixedMul(thing->momx, mul);
interpy += FixedMul(thing->momy, mul);
interpz += FixedMul(thing->momz, mul);
interp.x += FixedMul(thing->momx, mul);
interp.y += FixedMul(thing->momy, mul);
interp.z += FixedMul(thing->momz, mul);
}
// sprite offset
interpx += thing->sprxoff;
interpy += thing->spryoff;
interpz += thing->sprzoff;
interp.x += thing->sprxoff;
interp.y += thing->spryoff;
interp.z += thing->sprzoff;
groundz = R_GetShadowZ(thing, &groundslope, interpx, interpy, interpz);
groundz = R_GetShadowZ(thing, &groundslope);
gpatch = (patch_t *)W_CachePatchName("DSHADOW", PU_SPRITE);
if (!(gpatch && ((GLPatch_t *)gpatch->hardware)->mipmap->format)) return;
@ -3738,8 +3762,8 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
ph = (float)gpatch->height;
fscale = FIXED_TO_FLOAT(scalemul);
fx = FIXED_TO_FLOAT(interpx);
fy = FIXED_TO_FLOAT(interpy);
fx = FIXED_TO_FLOAT(interp.x);
fy = FIXED_TO_FLOAT(interp.y);
if (fscale > 0.0)
{
@ -5146,33 +5170,22 @@ static void HWR_ProjectSprite(mobj_t *thing)
#endif
// uncapped/interpolation
fixed_t interpx;
fixed_t interpy;
fixed_t interpz;
angle_t interpangle;
interpmobjstate_t interp = {0};
if (!thing)
return;
if (thing->spritexscale < 1 || thing->spriteyscale < 1)
return;
dispoffset = thing->info->dispoffset;
interpx = R_InterpolateFixed(thing->old_x, thing->x);
interpy = R_InterpolateFixed(thing->old_y, thing->y);
interpz = R_InterpolateFixed(thing->old_z, thing->z);
interpangle = ANGLE_MAX;
if (thing->player)
if (R_UsingFrameInterpolation() && !paused)
{
interpangle = R_InterpolateAngle(thing->player->old_drawangle, thing->player->drawangle);
R_InterpolateMobjState(thing, rendertimefrac, &interp);
}
else
{
interpangle = R_InterpolateAngle(thing->old_angle, thing->angle);
R_InterpolateMobjState(thing, FRACUNIT, &interp);
}
dispoffset = thing->info->dispoffset;
// hitlag vibrating (todo: interp somehow?)
if (thing->hitlag > 0 && (thing->eflags & MFE_DAMAGEHITLAG))
{
@ -5183,23 +5196,26 @@ static void HWR_ProjectSprite(mobj_t *thing)
mul = -mul;
}
interpx += FixedMul(thing->momx, mul);
interpy += FixedMul(thing->momy, mul);
interpz += FixedMul(thing->momz, mul);
interp.x += FixedMul(thing->momx, mul);
interp.y += FixedMul(thing->momy, mul);
interp.z += FixedMul(thing->momz, mul);
}
// sprite offset
interpx += thing->sprxoff;
interpy += thing->spryoff;
interpz += thing->sprzoff;
interp.x += thing->sprxoff;
interp.y += thing->spryoff;
interp.z += thing->sprzoff;
this_scale = FIXED_TO_FLOAT(thing->scale);
spritexscale = FIXED_TO_FLOAT(thing->spritexscale);
spriteyscale = FIXED_TO_FLOAT(thing->spriteyscale);
if (interp.spritexscale < 1 || interp.spriteyscale < 1)
return;
this_scale = FIXED_TO_FLOAT(interp.scale);
spritexscale = FIXED_TO_FLOAT(interp.spritexscale);
spriteyscale = FIXED_TO_FLOAT(interp.spriteyscale);
// transform the origin point
tr_x = FIXED_TO_FLOAT(interpx) - gl_viewx;
tr_y = FIXED_TO_FLOAT(interpy) - gl_viewy;
tr_x = FIXED_TO_FLOAT(interp.x) - gl_viewx;
tr_y = FIXED_TO_FLOAT(interp.y) - gl_viewy;
// rotation around vertical axis
tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin);
@ -5222,8 +5238,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
}
// The above can stay as it works for cutting sprites that are too close
tr_x = FIXED_TO_FLOAT(interpx);
tr_y = FIXED_TO_FLOAT(interpy);
tr_x = FIXED_TO_FLOAT(interp.x);
tr_y = FIXED_TO_FLOAT(interp.y);
// decide which patch to use for sprite relative to player
#ifdef RANGECHECK
@ -5271,7 +5287,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
I_Error("sprframes NULL for sprite %d\n", thing->sprite);
#endif
ang = R_PointToAngle (interpx, interpy) - interpangle;
ang = R_PointToAngle (interp.x, interp.y) - interp.angle;
if (mirrored)
ang = InvAngle(ang);
@ -5342,8 +5358,8 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (thing->renderflags & RF_ABSOLUTEOFFSETS)
{
spr_offset = thing->spritexoffset;
spr_topoffset = thing->spriteyoffset;
spr_offset = interp.spritexoffset;
spr_topoffset = interp.spriteyoffset;
}
else
{
@ -5352,14 +5368,14 @@ static void HWR_ProjectSprite(mobj_t *thing)
if ((thing->renderflags & RF_FLIPOFFSETS) && flip)
flipoffset = -1;
spr_offset += thing->spritexoffset * flipoffset;
spr_topoffset += thing->spriteyoffset * flipoffset;
spr_offset += interp.spritexoffset * flipoffset;
spr_topoffset += interp.spriteyoffset * flipoffset;
}
if (papersprite)
{
rightsin = FIXED_TO_FLOAT(FINESINE((interpangle)>>ANGLETOFINESHIFT));
rightcos = FIXED_TO_FLOAT(FINECOSINE((interpangle)>>ANGLETOFINESHIFT));
rightsin = FIXED_TO_FLOAT(FINESINE(interp.angle >> ANGLETOFINESHIFT));
rightcos = FIXED_TO_FLOAT(FINECOSINE(interp.angle >> ANGLETOFINESHIFT));
}
else
{
@ -5372,14 +5388,24 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (thing->renderflags & RF_SHADOWEFFECTS)
{
mobj_t *caster = thing->target;
interpmobjstate_t casterinterp = {0};
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(caster, rendertimefrac, &casterinterp);
}
else
{
R_InterpolateMobjState(caster, FRACUNIT, &casterinterp);
}
if (caster && !P_MobjWasRemoved(caster))
{
fixed_t groundz = R_GetShadowZ(thing, NULL, interpx, interpy, interpz);
fixed_t floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + caster->z - groundz);
fixed_t groundz = R_GetShadowZ(thing, NULL);
fixed_t floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + casterinterp.z - groundz);
shadowheight = FIXED_TO_FLOAT(floordiff);
shadowscale = FIXED_TO_FLOAT(FixedMul(FRACUNIT - floordiff/640, caster->scale));
shadowscale = FIXED_TO_FLOAT(FixedMul(FRACUNIT - floordiff/640, casterinterp.scale));
if (splat)
spritexscale *= shadowscale;
@ -5420,12 +5446,12 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (vflip)
{
gz = FIXED_TO_FLOAT(interpz + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale);
gz = FIXED_TO_FLOAT(interp.z + thing->height) - (FIXED_TO_FLOAT(spr_topoffset) * this_yscale);
gzt = gz + (FIXED_TO_FLOAT(spr_height) * this_yscale);
}
else
{
gzt = FIXED_TO_FLOAT(interpz) + (FIXED_TO_FLOAT(spr_topoffset) * this_yscale);
gzt = FIXED_TO_FLOAT(interp.z) + (FIXED_TO_FLOAT(spr_topoffset) * this_yscale);
gz = gzt - (FIXED_TO_FLOAT(spr_height) * this_yscale);
}
@ -5444,24 +5470,35 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (heightsec != -1 && phs != -1) // only clip things which are in special sectors
{
if (gl_viewz < FIXED_TO_FLOAT(sectors[phs].floorheight) ?
FIXED_TO_FLOAT(interpz) >= FIXED_TO_FLOAT(sectors[heightsec].floorheight) :
FIXED_TO_FLOAT(interp.z) >= FIXED_TO_FLOAT(sectors[heightsec].floorheight) :
gzt < FIXED_TO_FLOAT(sectors[heightsec].floorheight))
return;
if (gl_viewz > FIXED_TO_FLOAT(sectors[phs].ceilingheight) ?
gzt < FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) && gl_viewz >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) :
FIXED_TO_FLOAT(interpz) >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight))
FIXED_TO_FLOAT(interp.z) >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight))
return;
}
if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer)
{
interpmobjstate_t tracer_interp = {0};
if (! R_ThingVisible(thing->tracer))
return;
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(thing->tracer, rendertimefrac, &tracer_interp);
}
else
{
R_InterpolateMobjState(thing->tracer, FRACUNIT, &tracer_interp);
}
// calculate tz for tracer, same way it is calculated for this sprite
// transform the origin point
tr_x = FIXED_TO_FLOAT(thing->tracer->x) - gl_viewx;
tr_y = FIXED_TO_FLOAT(thing->tracer->y) - gl_viewy;
tr_x = FIXED_TO_FLOAT(tracer_interp.x) - gl_viewx;
tr_y = FIXED_TO_FLOAT(tracer_interp.y) - gl_viewy;
// rotation around vertical axis
tracertz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin);
@ -5588,21 +5625,25 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
unsigned rot = 0;
UINT8 flip;
// uncapped/interpolation
fixed_t interpx;
fixed_t interpy;
fixed_t interpz;
if (!thing)
return;
interpx = R_InterpolateFixed(thing->old_x, thing->x);
interpy = R_InterpolateFixed(thing->old_y, thing->y);
interpz = R_InterpolateFixed(thing->old_z, thing->z);
// uncapped/interpolation
interpmobjstate_t interp = {0};
// do interpolation
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolatePrecipMobjState(thing, rendertimefrac, &interp);
}
else
{
R_InterpolatePrecipMobjState(thing, FRACUNIT, &interp);
}
// transform the origin point
tr_x = FIXED_TO_FLOAT(interpx) - gl_viewx;
tr_y = FIXED_TO_FLOAT(interpy) - gl_viewy;
tr_x = FIXED_TO_FLOAT(interp.x) - gl_viewx;
tr_y = FIXED_TO_FLOAT(interp.y) - gl_viewy;
// rotation around vertical axis
tz = (tr_x * gl_viewcos) + (tr_y * gl_viewsin);
@ -5611,8 +5652,8 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
if (tz < ZCLIP_PLANE)
return;
tr_x = FIXED_TO_FLOAT(interpx);
tr_y = FIXED_TO_FLOAT(interpy);
tr_x = FIXED_TO_FLOAT(interp.x);
tr_y = FIXED_TO_FLOAT(interp.y);
// decide which patch to use for sprite relative to player
if ((unsigned)thing->sprite >= numsprites)
@ -5679,7 +5720,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
#endif
// set top/bottom coords
vis->gzt = FIXED_TO_FLOAT(interpz + spritecachedinfo[lumpoff].topoffset);
vis->gzt = FIXED_TO_FLOAT(interp.z + spritecachedinfo[lumpoff].topoffset);
vis->gz = vis->gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height);
vis->precip = true;

View file

@ -30,6 +30,7 @@
#include "hw_md2.h"
#include "../d_main.h"
#include "../r_bsp.h"
#include "../r_fps.h"
#include "../r_main.h"
#include "../m_misc.h"
#include "../w_wad.h"
@ -1360,8 +1361,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
{
patch_t *gpatch, *blendgpatch;
GLPatch_t *hwrPatch = NULL, *hwrBlendPatch = NULL;
INT32 durs = spr->mobj->state->tics;
INT32 tics = spr->mobj->tics;
float durs = (float)spr->mobj->state->tics;
float tics = (float)spr->mobj->tics;
const boolean papersprite = (R_ThingIsPaperSprite(spr->mobj) && !R_ThingIsFloorSprite(spr->mobj));
const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(spr->mobj));
const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj));
@ -1369,6 +1370,16 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
spriteframe_t *sprframe;
INT32 mod;
float finalscale;
interpmobjstate_t interp;
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(spr->mobj, rendertimefrac, &interp);
}
else
{
R_InterpolateMobjState(spr->mobj, FRACUNIT, &interp);
}
fixed_t interpx = R_InterpolateFixed(spr->mobj->old_x, spr->mobj->x);
fixed_t interpy = R_InterpolateFixed(spr->mobj->old_y, spr->mobj->y);
@ -1543,8 +1554,8 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
if (spr->mobj->frame & FF_ANIMATE)
{
// set duration and tics to be the correct values for FF_ANIMATE states
durs = spr->mobj->state->var2;
tics = spr->mobj->anim_duration;
durs = (float)spr->mobj->state->var2;
tics = (float)spr->mobj->anim_duration;
}
frame = (spr->mobj->frame & FF_FRAMEMASK);
@ -1568,6 +1579,9 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
}
#ifdef USE_MODEL_NEXTFRAME
// Interpolate the model interpolation. (lol)
tics -= FixedToFloat(rendertimefrac);
#define INTERPOLERATION_LIMIT TICRATE/4
if (
#ifdef BAD_MODEL_OPTIONS
@ -1620,13 +1634,13 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
#endif
//Hurdler: it seems there is still a small problem with mobj angle
p.x = FIXED_TO_FLOAT(interpx);
p.y = FIXED_TO_FLOAT(interpy) + md2->offset;
p.x = FIXED_TO_FLOAT(interp.x);
p.y = FIXED_TO_FLOAT(interp.y) + md2->offset;
if (flip)
p.z = FIXED_TO_FLOAT(spr->mobj->z + spr->mobj->height);
p.z = FIXED_TO_FLOAT(interp.z + spr->mobj->height);
else
p.z = FIXED_TO_FLOAT(interpz);
p.z = FIXED_TO_FLOAT(interp.z);
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
sprdef = &((skin_t *)spr->mobj->skin)->sprites[spr->mobj->sprite2];
@ -1637,22 +1651,13 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
if (sprframe->rotate || papersprite)
{
fixed_t anglef = INT32_MAX;
if (spr->mobj->player)
{
anglef = AngleFixed(R_InterpolateAngle(spr->mobj->player->old_drawangle, spr->mobj->player->drawangle));
}
else
{
anglef = AngleFixed(R_InterpolateAngle(spr->mobj->old_angle, spr->mobj->angle));
}
fixed_t anglef = AngleFixed(interp.angle);
p.angley = FIXED_TO_FLOAT(anglef);
}
else
{
const fixed_t anglef = AngleFixed((R_PointToAngle(interpx, interpy))-ANGLE_180);
const fixed_t anglef = AngleFixed((R_PointToAngle(interp.x, interp.y))-ANGLE_180);
p.angley = FIXED_TO_FLOAT(anglef);
}

View file

@ -2702,7 +2702,7 @@ EXPORT void HWRAPI(CreateModelVBOs) (model_t *model)
#define BUFFER_OFFSET(i) ((void*)(i))
static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
{
static GLRGBAFloat poly = {0,0,0,0};
static GLRGBAFloat tint = {0,0,0,0};
@ -2732,11 +2732,11 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
scaley = vscale;
scalez = hscale;
if (duration != 0 && duration != -1 && tics != -1) // don't interpolate if instantaneous or infinite in length
if (duration > 0.0 && tics >= 0.0) // don't interpolate if instantaneous or infinite in length
{
UINT32 newtime = (duration - tics); // + 1;
float newtime = (duration - tics); // + 1;
pol = (newtime)/(float)duration;
pol = newtime / duration;
if (pol > 1.0f)
pol = 1.0f;
@ -2988,7 +2988,7 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
// -----------------+
// HWRAPI DrawModel : Draw a model
// -----------------+
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, INT32 duration, INT32 tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float hscale, float vscale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
{
DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, hscale, vscale, flipped, hflipped, Surface);
}

View file

@ -49,6 +49,7 @@
#endif
#include "lua_hud.h"
#include "lua_hudlib_drawlist.h"
#include "lua_hook.h"
// SRB2Kart
@ -155,6 +156,8 @@ static INT32 cechoflags = 0;
static tic_t resynch_ticker = 0;
static huddrawlist_h luahuddrawlist_scores;
//======================================================================
// HEADS UP INIT
//======================================================================
@ -303,6 +306,8 @@ void HU_Init(void)
}
HU_LoadGraphics();
luahuddrawlist_scores = LUA_HUD_CreateDrawList();
}
patch_t *HU_UpdateOrBlankPatch(patch_t **user, boolean required, const char *format, ...)
@ -401,12 +406,12 @@ static INT16 addy = 0; // use this to make the messages scroll smoothly when one
static void HU_removeChatText_Mini(void)
{
// MPC: Don't create new arrays, just iterate through an existing one
// MPC: Don't create new arrays, just iterate through an existing one
size_t i;
for(i=0;i<chat_nummsg_min-1;i++) {
strcpy(chat_mini[i], chat_mini[i+1]);
chat_timers[i] = chat_timers[i+1];
}
for(i=0;i<chat_nummsg_min-1;i++) {
strcpy(chat_mini[i], chat_mini[i+1]);
chat_timers[i] = chat_timers[i+1];
}
chat_nummsg_min--; // lost 1 msg.
// use addy and make shit slide smoothly af.
@ -419,10 +424,10 @@ static void HU_removeChatText_Log(void)
{
// MPC: Don't create new arrays, just iterate through an existing one
size_t i;
for(i=0;i<chat_nummsg_log-1;i++) {
strcpy(chat_log[i], chat_log[i+1]);
}
chat_nummsg_log--; // lost 1 msg.
for(i=0;i<chat_nummsg_log-1;i++) {
strcpy(chat_log[i], chat_log[i+1]);
}
chat_nummsg_log--; // lost 1 msg.
}
#endif
@ -1005,12 +1010,8 @@ void HU_Ticker(void)
if (chat_scrolltime > 0)
chat_scrolltime--;
}
else
{
chat_scrolltime = 0;
}
if (netgame) // would handle that in hu_drawminichat, but it's actually kinda awkward when you're typing a lot of messages. (only handle that in netgames duh)
if (netgame)
{
size_t i = 0;
@ -2126,6 +2127,8 @@ void HU_Drawer(void)
else
{
typelines = 1;
chat_scrolltime = 0;
if (!OLDCHAT && cv_consolechat.value < 2 && netgame) // Don't display minimized chat if you set the mode to Window (Hidden)
HU_drawMiniChat(); // draw messages in a cool fashion.
}
@ -2148,7 +2151,12 @@ void HU_Drawer(void)
{
if (LUA_HudEnabled(hud_rankings))
HU_DrawRankings();
LUAh_ScoresHUD();
if (renderisnewtic)
{
LUA_HUD_ClearDrawList(luahuddrawlist_scores);
LUAh_ScoresHUD(luahuddrawlist_scores);
}
LUA_HUD_DrawList(luahuddrawlist_scores);
}
if (demo.playback)

View file

@ -42,27 +42,32 @@ extern UINT8 keyboard_started;
*/
UINT32 I_GetFreeMem(UINT32 *total);
/** \brief Called by D_SRB2Loop, returns current time in tics.
*/
tic_t I_GetTime(void);
/** \brief Get the current time in tics including fractions.
*/
float I_GetTimeFrac(void);
/** \brief Returns precise time value for performance measurement.
/** \brief Returns precise time value for performance measurement. The precise
time should be a monotonically increasing counter, and will wrap.
precise_t is internally represented as an unsigned integer and
integer arithmetic may be used directly between values of precise_t.
*/
precise_t I_GetPreciseTime(void);
/** \brief Converts a precise_t to microseconds and casts it to a 32 bit integer.
/** \brief Get the precision of precise_t in units per second. Invocations of
this function for the program's duration MUST return the same value.
*/
int I_PreciseToMicros(precise_t d);
UINT64 I_GetPrecisePrecision(void);
/** \brief The I_Sleep function
/** \brief Get the current time in rendering tics, including fractions.
*/
double I_GetFrameTime(void);
/** \brief Sleeps for the given duration in milliseconds. Depending on the
operating system's scheduler, the calling thread may give up its
time slice for a longer duration. The implementation should give a
best effort to sleep for the given duration, without spin-locking.
Calling code should check the current precise time after sleeping
and not assume the thread has slept for the expected duration.
\return void
*/
void I_Sleep(void);
void I_Sleep(UINT32 ms);
boolean I_CheckFrameCap(precise_t start, precise_t end);

123
src/i_time.c Normal file
View file

@ -0,0 +1,123 @@
// 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 <math.h>
#include "command.h"
#include "doomtype.h"
#include "d_netcmd.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;
// A little more than the minimum sleep duration on Windows.
// May be incorrect for other platforms, but we don't currently have a way to
// query the scheduler granularity. SDL will do what's needed to make this as
// low as possible though.
#define MIN_SLEEP_DURATION_MS 2.1
tic_t I_GetTime(void)
{
return g_time.time;
}
void I_InitializeTime(void)
{
g_time.time = 0;
g_time.timefrac = 0;
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 = (double)(enterprecise - oldenterprecise) / I_GetPrecisePrecision();
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);
}
}
void I_SleepDuration(precise_t duration)
{
UINT64 precision = I_GetPrecisePrecision();
INT32 sleepvalue = cv_sleep.value;
UINT64 delaygranularity;
precise_t cur;
precise_t dest;
{
double gran = round(((double)(precision / 1000) * sleepvalue * MIN_SLEEP_DURATION_MS));
delaygranularity = (UINT64)gran;
}
cur = I_GetPreciseTime();
dest = cur + duration;
// the reason this is not dest > cur is because the precise counter may wrap
// two's complement arithmetic is our friend here, though!
// e.g. cur 0xFFFFFFFFFFFFFFFE = -2, dest 0x0000000000000001 = 1
// 0x0000000000000001 - 0xFFFFFFFFFFFFFFFE = 3
while ((INT64)(dest - cur) > 0)
{
// If our cv_sleep value exceeds the remaining sleep duration, use the
// hard sleep function.
if (sleepvalue > 0 && (dest - cur) > delaygranularity)
{
I_Sleep(sleepvalue);
}
// Otherwise, this is a spinloop.
cur = I_GetPreciseTime();
}
}

54
src/i_time.h Normal file
View file

@ -0,0 +1,54 @@
// 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;
} 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);
/** \brief Block for at minimum the duration specified. This function makes a
best effort not to oversleep, and will spinloop if sleeping would
take too long. However, callers should still check the current time
after this returns.
*/
void I_SleepDuration(precise_t duration);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __I_TIME_H__

View file

@ -45,6 +45,7 @@
#include "byteptr.h"
#include "st_stuff.h"
#include "i_sound.h"
#include "i_time.h"
#include "k_kart.h" // SRB2kart
#include "d_player.h" // KITEM_ constants
#include "doomstat.h" // MAXSPLITSCREENPLAYERS
@ -2114,7 +2115,8 @@ void M_QuitResponse(INT32 ch)
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
V_DrawSmallScaledPatch(0, 0, 0, W_CachePatchName("GAMEQUIT", PU_CACHE)); // Demo 3 Quit Screen Tails 06-16-2001
I_FinishUpdate(); // Update the screen with the image Tails 06-19-2001
I_Sleep();
I_Sleep(cv_sleep.value);
I_UpdateTime(cv_timescale.value);
}
}
I_Quit();

View file

@ -35,7 +35,7 @@
#include "k_menu.h" // Player Setup menu color stuff
#include "m_misc.h" // M_MapNumber
#include "p_spec.h" // P_StartQuake
#include "i_system.h" // I_GetPreciseTime, I_PreciseToMicros
#include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision
#include "lua_script.h"
#include "lua_libs.h"
@ -1454,7 +1454,7 @@ static int lib_pTeleportMove(lua_State *L)
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
LUA_Deprecated(L, "P_TeleportMove", "P_SetOrigin\" or \"P_MoveOrigin");
lua_pushboolean(L, P_SetOrigin(thing, x, y, z));
lua_pushboolean(L, P_MoveOrigin(thing, x, y, z));
LUA_PushUserdata(L, tmthing, META_MOBJ);
P_SetTarget(&tmthing, ptmthing);
return 2;
@ -1494,42 +1494,6 @@ static int lib_pMoveOrigin(lua_State *L)
return 2;
}
static int lib_pInitAngle(lua_State *L)
{
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
angle_t newValue = luaL_checkangle(L, 2);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
P_InitAngle(thing, newValue);
return 0;
}
static int lib_pInitPitch(lua_State *L)
{
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
angle_t newValue = luaL_checkangle(L, 2);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
P_InitPitch(thing, newValue);
return 0;
}
static int lib_pInitRoll(lua_State *L)
{
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
angle_t newValue = luaL_checkangle(L, 2);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
P_InitRoll(thing, newValue);
return 0;
}
static int lib_pSlideMove(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@ -3835,7 +3799,7 @@ static int lib_kDeclareWeakspot(lua_State *L)
static int lib_getTimeMicros(lua_State *L)
{
lua_pushinteger(L, I_PreciseToMicros(I_GetPreciseTime()));
lua_pushinteger(L, I_GetPreciseTime() / (I_GetPrecisePrecision() / 1000000));
return 1;
}
@ -3947,9 +3911,6 @@ static luaL_Reg lib[] = {
{"P_TeleportMove",lib_pTeleportMove},
{"P_SetOrigin",lib_pSetOrigin},
{"P_MoveOrigin",lib_pMoveOrigin},
{"P_InitAngle",lib_pInitAngle},
{"P_InitPitch",lib_pInitPitch},
{"P_InitRoll",lib_pInitRoll},
{"P_SlideMove",lib_pSlideMove},
{"P_BounceMove",lib_pBounceMove},
{"P_CheckSight", lib_pCheckSight},

View file

@ -12,6 +12,7 @@
#include "r_defs.h"
#include "d_player.h"
#include "lua_hudlib_drawlist.h"
enum hook {
hook_NetVars=0,

View file

@ -10,6 +10,11 @@
/// \file lua_hud.h
/// \brief HUD enable/disable flags for Lua scripting
#ifndef __LUA_HUD_H__
#define __LUA_HUD_H__
#include "lua_hudlib_drawlist.h"
enum hud {
hud_stagetitle = 0,
hud_textspectator,
@ -42,8 +47,10 @@ extern boolean hud_running;
boolean LUA_HudEnabled(enum hud option);
void LUAh_GameHUD(player_t *stplyr);
void LUAh_ScoresHUD(void);
void LUAh_TitleHUD(void);
void LUAh_TitleCardHUD(player_t *stplayr);
void LUAh_IntermissionHUD(void);
void LUAh_GameHUD(player_t *stplyr, huddrawlist_h list);
void LUAh_ScoresHUD(huddrawlist_h list);
void LUAh_TitleHUD(huddrawlist_h list);
void LUAh_TitleCardHUD(player_t *stplayr, huddrawlist_h list);
void LUAh_IntermissionHUD(huddrawlist_h list);
#endif // __LUA_HUD_H__

View file

@ -493,7 +493,8 @@ static int libd_draw(lua_State *L)
{
INT32 x, y, flags;
patch_t *patch;
const UINT8 *colormap = NULL;
UINT8 *colormap = NULL;
huddrawlist_h list;
HUDONLY
x = luaL_checkinteger(L, 1);
@ -507,7 +508,14 @@ static int libd_draw(lua_State *L)
flags &= ~V_PARAMMASK; // Don't let crashes happen.
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, flags, patch, colormap);
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddDraw(list, x, y, patch, flags, colormap);
else
V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, flags, patch, colormap);
return 0;
}
@ -516,7 +524,8 @@ static int libd_drawScaled(lua_State *L)
fixed_t x, y, scale;
INT32 flags;
patch_t *patch;
const UINT8 *colormap = NULL;
UINT8 *colormap = NULL;
huddrawlist_h list;
HUDONLY
x = luaL_checkinteger(L, 1);
@ -533,7 +542,14 @@ static int libd_drawScaled(lua_State *L)
flags &= ~V_PARAMMASK; // Don't let crashes happen.
V_DrawFixedPatch(x, y, scale, flags, patch, colormap);
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddDrawScaled(list, x, y, scale, patch, flags, colormap);
else
V_DrawFixedPatch(x, y, scale, flags, patch, colormap);
return 0;
}
@ -542,7 +558,8 @@ static int libd_drawStretched(lua_State *L)
fixed_t x, y, hscale, vscale;
INT32 flags;
patch_t *patch;
const UINT8 *colormap = NULL;
UINT8 *colormap = NULL;
huddrawlist_h list;
HUDONLY
x = luaL_checkinteger(L, 1);
@ -560,7 +577,14 @@ static int libd_drawStretched(lua_State *L)
flags &= ~V_PARAMMASK; // Don't let crashes happen.
V_DrawStretchyFixedPatch(x, y, hscale, vscale, flags, patch, colormap);
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddDrawStretched(list, x, y, hscale, vscale, patch, flags, colormap);
else
V_DrawStretchyFixedPatch(x, y, hscale, vscale, flags, patch, colormap);
return 0;
}
@ -569,8 +593,9 @@ static int libd_drawOnMinimap(lua_State *L)
{
fixed_t x, y, scale; // coordinates of the object
patch_t *patch; // patch we want to draw
const UINT8 *colormap = NULL; // do we want to colormap this patch?
UINT8 *colormap = NULL; // do we want to colormap this patch?
boolean centered; // the patch is centered and doesn't need readjusting on x/y coordinates.
huddrawlist_h list;
// variables used to replicate k_kart's mmap drawer:
INT32 lumpnum;
@ -733,13 +758,22 @@ static int libd_drawOnMinimap(lua_State *L)
amypos = amnumypos + ((my + AutomapPic->height/2)<<FRACBITS) - patchh;
// and NOW we can FINALLY DRAW OUR GOD DAMN PATCH :V
V_DrawFixedPatch(amxpos, amypos, scale, splitflags, patch, colormap);
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddDrawScaled(list, amxpos, amypos, scale, patch, splitflags, colormap);
else
V_DrawFixedPatch(amxpos, amypos, scale, splitflags, patch, colormap);
return 0;
}
static int libd_drawNum(lua_State *L)
{
INT32 x, y, flags, num;
huddrawlist_h list;
HUDONLY
x = luaL_checkinteger(L, 1);
y = luaL_checkinteger(L, 2);
@ -747,13 +781,22 @@ static int libd_drawNum(lua_State *L)
flags = luaL_optinteger(L, 4, 0);
flags &= ~V_PARAMMASK; // Don't let crashes happen.
V_DrawTallNum(x, y, flags, num);
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddDrawNum(list, x, y, num, flags);
else
V_DrawTallNum(x, y, flags, num);
return 0;
}
static int libd_drawPaddedNum(lua_State *L)
{
INT32 x, y, flags, num, digits;
huddrawlist_h list;
HUDONLY
x = luaL_checkinteger(L, 1);
y = luaL_checkinteger(L, 2);
@ -762,14 +805,22 @@ static int libd_drawPaddedNum(lua_State *L)
flags = luaL_optinteger(L, 5, 0);
flags &= ~V_PARAMMASK; // Don't let crashes happen.
V_DrawPaddedTallNum(x, y, flags, num, digits);
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddDrawPaddedNum(list, x, y, num, digits, flags);
else
V_DrawPaddedTallNum(x, y, flags, num, digits);
return 0;
}
static int libd_drawPingNum(lua_State *L)
{
INT32 x, y, flags, num;
const UINT8 *colormap = NULL;
UINT8 *colormap = NULL;
huddrawlist_h list;
HUDONLY
x = luaL_checkinteger(L, 1);
y = luaL_checkinteger(L, 2);
@ -779,12 +830,20 @@ static int libd_drawPingNum(lua_State *L)
if (!lua_isnoneornil(L, 5))
colormap = *((UINT8 **)luaL_checkudata(L, 5, META_COLORMAP));
V_DrawPingNum(x, y, flags, num, colormap);
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddDrawPingNum(list, x, y, flags, num, colormap);
else
V_DrawPingNum(x, y, flags, num, colormap);
return 0;
}
static int libd_drawFill(lua_State *L)
{
huddrawlist_h list;
INT32 x = luaL_optinteger(L, 1, 0);
INT32 y = luaL_optinteger(L, 2, 0);
INT32 w = luaL_optinteger(L, 3, BASEVIDWIDTH);
@ -792,7 +851,15 @@ static int libd_drawFill(lua_State *L)
INT32 c = luaL_optinteger(L, 5, 31);
HUDONLY
V_DrawFill(x, y, w, h, c);
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddDrawFill(list, x, y, w, h, c);
else
V_DrawFill(x, y, w, h, c);
return 0;
}
@ -801,6 +868,7 @@ static int libd_fadeScreen(lua_State *L)
UINT16 color = luaL_checkinteger(L, 1);
UINT8 strength = luaL_checkinteger(L, 2);
const UINT8 maxstrength = ((color & 0xFF00) ? 32 : 10);
huddrawlist_h list;
HUDONLY
@ -810,18 +878,29 @@ static int libd_fadeScreen(lua_State *L)
if (strength > maxstrength)
return luaL_error(L, "%s fade strength %d out of range (0 - %d)", ((color & 0xFF00) ? "COLORMAP" : "TRANSMAP"), strength, maxstrength);
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
if (strength == maxstrength) // Allow as a shortcut for drawfill...
{
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, ((color & 0xFF00) ? 31 : color));
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddDrawFill(list, 0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, ((color & 0xFF00) ? 31 : color));
else
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, ((color & 0xFF00) ? 31 : color));
return 0;
}
V_DrawFadeScreen(color, strength);
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddFadeScreen(list, color, strength);
else
V_DrawFadeScreen(color, strength);
return 0;
}
static int libd_drawString(lua_State *L)
{
huddrawlist_h list;
fixed_t x = luaL_checkinteger(L, 1);
fixed_t y = luaL_checkinteger(L, 2);
const char *str = luaL_checkstring(L, 3);
@ -831,6 +910,15 @@ static int libd_drawString(lua_State *L)
flags &= ~V_PARAMMASK; // Don't let crashes happen.
HUDONLY
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
// okay, sorry, this is kind of ugly
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddDrawString(list, x, y, str, flags, align);
else
switch(align)
{
// hu_font
@ -877,11 +965,19 @@ static int libd_drawTitleCardString(lua_State *L)
boolean rightalign = lua_optboolean(L, 5);
INT32 timer = luaL_optinteger(L, 6, 0);
INT32 threshold = luaL_optinteger(L, 7, 0);
huddrawlist_h list;
flags &= ~V_PARAMMASK; // Don't let crashes happen.
HUDONLY
V_DrawTitleCardString(x, y, str, flags, rightalign, timer, threshold);
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddDrawTitleCardString(list, x, y, flags, str, rightalign, timer, threshold);
else
V_DrawTitleCardString(x, y, str, flags, rightalign, timer, threshold);
return 0;
}
@ -891,11 +987,19 @@ static int libd_drawKartString(lua_State *L)
fixed_t y = luaL_checkinteger(L, 2);
const char *str = luaL_checkstring(L, 3);
INT32 flags = luaL_optinteger(L, 4, V_ALLOWLOWERCASE);
huddrawlist_h list;
flags &= ~V_PARAMMASK; // Don't let crashes happen.
HUDONLY
V_DrawKartString(x, y, flags, str);
lua_getfield(L, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
list = (huddrawlist_h) lua_touserdata(L, -1);
lua_pop(L, 1);
if (LUA_HUD_IsDrawListValid(list))
LUA_HUD_AddDrawKartString(list, x, y, str, flags);
else
V_DrawKartString(x, y, flags, str);
return 0;
}
@ -1093,6 +1197,14 @@ static int libd_getusertransflag(lua_State *L)
return 1;
}
// Return the time elapsed for the previous frame, in tics.
static int libd_getDeltaTime(lua_State *L)
{
HUDONLY
lua_pushfixed(L, renderdeltatics);
return 1;
}
static luaL_Reg lib_draw[] = {
// cache
{"patchExists", libd_patchExists},
@ -1132,6 +1244,7 @@ static luaL_Reg lib_draw[] = {
{"localTransFlag", libd_getlocaltransflag},
{"drawOnMinimap", libd_drawOnMinimap},
{"userTransFlag", libd_getusertransflag},
{"getDeltaTime", libd_getDeltaTime},
{NULL, NULL}
};
@ -1258,11 +1371,14 @@ boolean LUA_HudEnabled(enum hud option)
}
// Hook for HUD rendering
void LUAh_GameHUD(player_t *stplayr)
void LUAh_GameHUD(player_t *stplayr, huddrawlist_h list)
{
if (!gL || !(hudAvailable & (1<<hudhook_game)))
return;
lua_pushlightuserdata(gL, list);
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
hud_running = true;
lua_settop(gL, 0);
@ -1310,11 +1426,14 @@ void LUAh_GameHUD(player_t *stplayr)
hud_running = false;
}
void LUAh_ScoresHUD(void)
void LUAh_ScoresHUD(huddrawlist_h list)
{
if (!gL || !(hudAvailable & (1<<hudhook_scores)))
return;
lua_pushlightuserdata(gL, list);
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
hud_running = true;
lua_settop(gL, 0);
@ -1337,11 +1456,14 @@ void LUAh_ScoresHUD(void)
hud_running = false;
}
void LUAh_TitleHUD(void)
void LUAh_TitleHUD(huddrawlist_h list)
{
if (!gL || !(hudAvailable & (1<<hudhook_title)))
return;
lua_pushlightuserdata(gL, list);
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
hud_running = true;
lua_settop(gL, 0);
@ -1364,11 +1486,14 @@ void LUAh_TitleHUD(void)
hud_running = false;
}
void LUAh_TitleCardHUD(player_t *stplayr)
void LUAh_TitleCardHUD(player_t *stplayr, huddrawlist_h list)
{
if (!gL || !(hudAvailable & (1<<hudhook_titlecard)))
return;
lua_pushlightuserdata(gL, list);
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
hud_running = true;
lua_settop(gL, 0);
@ -1400,11 +1525,14 @@ void LUAh_TitleCardHUD(player_t *stplayr)
hud_running = false;
}
void LUAh_IntermissionHUD(void)
void LUAh_IntermissionHUD(huddrawlist_h list)
{
if (!gL || !(hudAvailable & (1<<hudhook_intermission)))
return;
lua_pushlightuserdata(gL, list);
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
hud_running = true;
lua_settop(gL, 0);

470
src/lua_hudlib_drawlist.c Normal file
View file

@ -0,0 +1,470 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2014-2016 by John "JTE" Muniz.
// Copyright (C) 2014-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 lua_hudlib_drawlist.c
/// \brief a data structure for managing cached drawlists for the Lua hud lib
#include "lua_hudlib_drawlist.h"
#include <string.h>
#include "v_video.h"
#include "z_zone.h"
enum drawitem_e {
DI_Draw = 0,
DI_DrawScaled,
DI_DrawStretched,
DI_DrawNum,
DI_DrawPaddedNum,
DI_DrawPingNum,
DI_DrawFill,
DI_DrawString,
DI_FadeScreen,
DI_DrawTitleCardString,
DI_DrawKartString,
DI_MAX,
};
// A single draw item with all possible arguments needed for a draw call.
typedef struct drawitem_s {
enum drawitem_e type;
fixed_t x;
fixed_t y;
fixed_t w;
fixed_t h;
INT32 c;
fixed_t scale;
fixed_t hscale;
fixed_t vscale;
patch_t *patch;
INT32 flags;
UINT16 basecolor;
UINT16 outlinecolor;
UINT8 *colormap;
UINT8 *basecolormap;
UINT8 *outlinecolormap;
fixed_t sx;
fixed_t sy;
INT32 num;
INT32 digits;
const char *str;
UINT16 color;
UINT8 strength;
INT32 align;
INT32 timer;
INT32 threshold;
boolean bossmode;
} drawitem_t;
// The internal structure of a drawlist.
struct huddrawlist_s {
drawitem_t *items;
size_t items_capacity;
size_t items_len;
char *strbuf;
size_t strbuf_capacity;
size_t strbuf_len;
};
// alignment types for v.drawString
enum align {
align_left = 0,
align_center,
align_right,
align_small,
align_smallcenter,
align_smallright,
align_thin,
align_thincenter,
align_thinright
};
huddrawlist_h LUA_HUD_CreateDrawList(void)
{
huddrawlist_h drawlist;
drawlist = (huddrawlist_h) Z_CallocAlign(sizeof(struct huddrawlist_s), PU_STATIC, NULL, 64);
drawlist->items = NULL;
drawlist->items_capacity = 0;
drawlist->items_len = 0;
drawlist->strbuf = NULL;
drawlist->strbuf_capacity = 0;
drawlist->strbuf_len = 0;
return drawlist;
}
void LUA_HUD_ClearDrawList(huddrawlist_h list)
{
// rather than deallocate, we'll just save the existing allocation and empty
// it out for reuse
// this memset probably isn't necessary
if (list->items)
{
memset(list->items, 0, sizeof(drawitem_t) * list->items_capacity);
}
list->items_len = 0;
if (list->strbuf)
{
list->strbuf[0] = 0;
}
list->strbuf_len = 0;
}
void LUA_HUD_DestroyDrawList(huddrawlist_h list)
{
if (list == NULL) return;
if (list->items)
{
Z_Free(list->items);
}
Z_Free(list);
}
boolean LUA_HUD_IsDrawListValid(huddrawlist_h list)
{
if (!list) return false;
// that's all we can really do to check the validity of the handle right now
return true;
}
static size_t AllocateDrawItem(huddrawlist_h list)
{
if (!list) I_Error("can't allocate draw item: invalid list");
if (list->items_capacity <= list->items_len + 1)
{
if (list->items_capacity == 0) list->items_capacity = 128;
else list->items_capacity *= 2;
list->items = (drawitem_t *) Z_ReallocAlign(list->items, sizeof(struct drawitem_s) * list->items_capacity, PU_STATIC, NULL, 64);
}
return list->items_len++;
}
// copy string to list's internal string buffer
// lua can deallocate the string before we get to use it, so it's important to
// keep our own copy
static const char *CopyString(huddrawlist_h list, const char* str)
{
size_t lenstr;
if (!list) I_Error("can't allocate string; invalid list");
lenstr = strlen(str);
if (list->strbuf_capacity <= list->strbuf_len + lenstr + 1)
{
if (list->strbuf_capacity == 0) list->strbuf_capacity = 256;
else list->strbuf_capacity *= 2;
list->strbuf = (char*) Z_ReallocAlign(list->strbuf, sizeof(char) * list->strbuf_capacity, PU_STATIC, NULL, 8);
}
const char *result = (const char *) &list->strbuf[list->strbuf_len];
strncpy(&list->strbuf[list->strbuf_len], str, lenstr + 1);
list->strbuf_len += lenstr + 1;
return result;
}
void LUA_HUD_AddDraw(
huddrawlist_h list,
INT32 x,
INT32 y,
patch_t *patch,
INT32 flags,
UINT8 *colormap
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_Draw;
item->x = x;
item->y = y;
item->patch = patch;
item->flags = flags;
item->colormap = colormap;
}
void LUA_HUD_AddDrawScaled(
huddrawlist_h list,
fixed_t x,
fixed_t y,
fixed_t scale,
patch_t *patch,
INT32 flags,
UINT8 *colormap
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawScaled;
item->x = x;
item->y = y;
item->scale = scale;
item->patch = patch;
item->flags = flags;
item->colormap = colormap;
}
void LUA_HUD_AddDrawStretched(
huddrawlist_h list,
fixed_t x,
fixed_t y,
fixed_t hscale,
fixed_t vscale,
patch_t *patch,
INT32 flags,
UINT8 *colormap
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawStretched;
item->x = x;
item->y = y;
item->hscale = hscale;
item->vscale = vscale;
item->patch = patch;
item->flags = flags;
item->colormap = colormap;
}
void LUA_HUD_AddDrawNum(
huddrawlist_h list,
INT32 x,
INT32 y,
INT32 num,
INT32 flags
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawNum;
item->x = x;
item->y = y;
item->num = num;
item->flags = flags;
}
void LUA_HUD_AddDrawPaddedNum(
huddrawlist_h list,
INT32 x,
INT32 y,
INT32 num,
INT32 digits,
INT32 flags
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawPaddedNum;
item->x = x;
item->y = y;
item->num = num;
item->digits = digits;
item->flags = flags;
}
void LUA_HUD_AddDrawPingNum(
huddrawlist_h list,
INT32 x,
INT32 y,
INT32 flags,
INT32 num,
UINT8 *colormap
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawPingNum;
item->x = x;
item->y = y;
item->flags = flags;
item->num = num;
item->colormap = colormap;
}
void LUA_HUD_AddDrawFill(
huddrawlist_h list,
INT32 x,
INT32 y,
INT32 w,
INT32 h,
INT32 c
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawFill;
item->x = x;
item->y = y;
item->w = w;
item->h = h;
item->c = c;
}
void LUA_HUD_AddDrawString(
huddrawlist_h list,
fixed_t x,
fixed_t y,
const char *str,
INT32 flags,
INT32 align
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawString;
item->x = x;
item->y = y;
item->str = CopyString(list, str);
item->flags = flags;
item->align = align;
}
void LUA_HUD_AddFadeScreen(
huddrawlist_h list,
UINT16 color,
UINT8 strength
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_FadeScreen;
item->color = color;
item->strength = strength;
}
void LUA_HUD_AddDrawTitleCardString(
huddrawlist_h list,
INT32 x,
INT32 y,
INT32 flags,
const char *str,
boolean bossmode,
INT32 timer,
INT32 threshold
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawTitleCardString;
item->x = x;
item->y = y;
item->flags = flags;
item->str = CopyString(list, str);
item->bossmode = bossmode;
item->timer = timer;
item->threshold = threshold;
}
void LUA_HUD_AddDrawKartString(
huddrawlist_h list,
fixed_t x,
fixed_t y,
const char *str,
INT32 flags
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawKartString;
item->x = x;
item->y = y;
item->flags = flags;
item->str = CopyString(list, str);
}
void LUA_HUD_DrawList(huddrawlist_h list)
{
size_t i;
if (!list) I_Error("HUD drawlist invalid");
if (list->items_len <= 0) return;
if (!list->items) I_Error("HUD drawlist->items invalid");
for (i = 0; i < list->items_len; i++)
{
drawitem_t *item = &list->items[i];
switch (item->type)
{
case DI_Draw:
V_DrawFixedPatch(item->x<<FRACBITS, item->y<<FRACBITS, FRACUNIT, item->flags, item->patch, item->colormap);
break;
case DI_DrawScaled:
V_DrawFixedPatch(item->x, item->y, item->scale, item->flags, item->patch, item->colormap);
break;
case DI_DrawStretched:
V_DrawStretchyFixedPatch(item->x, item->y, item->hscale, item->vscale, item->flags, item->patch, item->colormap);
break;
case DI_DrawNum:
V_DrawTallNum(item->x, item->y, item->flags, item->num);
break;
case DI_DrawPaddedNum:
V_DrawPaddedTallNum(item->x, item->y, item->flags, item->num, item->digits);
break;
case DI_DrawPingNum:
V_DrawPingNum(item->x, item->y, item->flags, item->num, item->colormap);
break;
case DI_DrawFill:
V_DrawFill(item->x, item->y, item->w, item->h, item->c);
break;
case DI_DrawString:
switch(item->align)
{
// hu_font
case align_left:
V_DrawString(item->x, item->y, item->flags, item->str);
break;
case align_center:
V_DrawCenteredString(item->x, item->y, item->flags, item->str);
break;
case align_right:
V_DrawRightAlignedString(item->x, item->y, item->flags, item->str);
break;
// hu_font, 0.5x scale
case align_small:
V_DrawSmallString(item->x, item->y, item->flags, item->str);
break;
case align_smallcenter:
V_DrawCenteredSmallString(item->x, item->y, item->flags, item->str);
break;
case align_smallright:
V_DrawRightAlignedSmallString(item->x, item->y, item->flags, item->str);
break;
// tny_font
case align_thin:
V_DrawThinString(item->x, item->y, item->flags, item->str);
break;
case align_thincenter:
V_DrawCenteredThinString(item->x, item->y, item->flags, item->str);
break;
case align_thinright:
V_DrawRightAlignedThinString(item->x, item->y, item->flags, item->str);
break;
}
break;
case DI_FadeScreen:
V_DrawFadeScreen(item->color, item->strength);
break;
case DI_DrawTitleCardString:
V_DrawTitleCardString(item->x, item->y, item->str, item->flags, item->bossmode, item->timer, item->threshold);
break;
case DI_DrawKartString:
V_DrawKartString(item->x, item->y, item->flags, item->str);
break;
default:
I_Error("can't draw draw list item: invalid draw list item type");
continue;
}
}
}

133
src/lua_hudlib_drawlist.h Normal file
View file

@ -0,0 +1,133 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2022-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 lua_hudlib_drawlist.h
/// \brief a data structure for managing cached drawlists for the Lua hud lib
// The idea behinds this module is to cache drawcall information into an ordered
// list to repeat the same draw operations in later frames. It's used to ensure
// that the HUD hooks from Lua are called at precisely 35hz to avoid problems
// with variable framerates in existing Lua addons.
#ifndef __LUA_HUDLIB_DRAWLIST__
#define __LUA_HUDLIB_DRAWLIST__
#include "doomtype.h"
#include "r_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct huddrawlist_s *huddrawlist_h;
// Create a new drawlist. Returns a handle to it.
huddrawlist_h LUA_HUD_CreateDrawList(void);
// Clears the draw list.
void LUA_HUD_ClearDrawList(huddrawlist_h list);
// Destroys the drawlist, invalidating the given handle
void LUA_HUD_DestroyDrawList(huddrawlist_h list);
boolean LUA_HUD_IsDrawListValid(huddrawlist_h list);
void LUA_HUD_AddDraw(
huddrawlist_h list,
INT32 x,
INT32 y,
patch_t *patch,
INT32 flags,
UINT8 *colormap
);
void LUA_HUD_AddDrawScaled(
huddrawlist_h list,
fixed_t x,
fixed_t y,
fixed_t scale,
patch_t *patch,
INT32 flags,
UINT8 *colormap
);
void LUA_HUD_AddDrawStretched(
huddrawlist_h list,
fixed_t x,
fixed_t y,
fixed_t hscale,
fixed_t vscale,
patch_t *patch,
INT32 flags,
UINT8 *colormap
);
void LUA_HUD_AddDrawNum(
huddrawlist_h list,
INT32 x,
INT32 y,
INT32 num,
INT32 flags
);
void LUA_HUD_AddDrawPaddedNum(
huddrawlist_h list,
INT32 x,
INT32 y,
INT32 num,
INT32 digits,
INT32 flags
);
void LUA_HUD_AddDrawPingNum(
huddrawlist_h list,
INT32 x,
INT32 y,
INT32 flags,
INT32 num,
UINT8 *colormap
);
void LUA_HUD_AddDrawFill(
huddrawlist_h list,
INT32 x,
INT32 y,
INT32 w,
INT32 h,
INT32 c
);
void LUA_HUD_AddDrawString(
huddrawlist_h list,
fixed_t x,
fixed_t y,
const char *str,
INT32 flags,
INT32 align
);
void LUA_HUD_AddFadeScreen(
huddrawlist_h list,
UINT16 color,
UINT8 strength
);
void LUA_HUD_AddDrawTitleCardString(
huddrawlist_h list,
INT32 x,
INT32 y,
INT32 flags,
const char *str,
boolean bossmode,
INT32 timer,
INT32 threshold
);
void LUA_HUD_AddDrawKartString(
huddrawlist_h list,
fixed_t x,
fixed_t y,
const char *str,
INT32 flags
);
// Draws the given draw list
void LUA_HUD_DrawList(huddrawlist_h list);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __LUA_HUDLIB_DRAWLIST__

View file

@ -778,6 +778,7 @@ static int mobj_set(lua_State *L)
scale = FRACUNIT/100;
mo->destscale = scale;
P_SetScale(mo, scale);
mo->old_scale = scale;
break;
}
case mobj_destscale:

View file

@ -608,7 +608,7 @@ static void GIF_framewrite(void)
{
// golden's attempt at creating a "dynamic delay"
UINT16 mingifdelay = 10; // minimum gif delay in milliseconds (keep at 10 because gifs can't get more precise).
gif_delayus += I_PreciseToMicros(I_GetPreciseTime() - gif_prevframetime); // increase delay by how much time was spent between last measurement
gif_delayus += (I_GetPreciseTime() - gif_prevframetime) / (I_GetPrecisePrecision() / 1000000); // increase delay by how much time was spent between last measurement
if (gif_delayus/1000 >= mingifdelay) // delay is big enough to be able to effect gif frame delay?
{
@ -621,7 +621,7 @@ static void GIF_framewrite(void)
{
float delayf = ceil(100.0f/NEWTICRATE);
delay = (UINT16)I_PreciseToMicros((I_GetPreciseTime() - gif_prevframetime))/10/1000;
delay = (UINT16)((I_GetPreciseTime() - gif_prevframetime)) / (I_GetPrecisePrecision() / 1000000) /10/1000;
if (delay < (UINT16)(delayf))
delay = (UINT16)(delayf);

View file

@ -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"

View file

@ -15,6 +15,7 @@
#include "d_netcmd.h"
#include "r_main.h"
#include "i_system.h"
#include "i_time.h"
#include "z_zone.h"
#include "p_local.h"
@ -117,7 +118,7 @@ static void M_DrawPerfString(perfstatcol_t *col, int type)
for (row = col->rows; row->lores_label; ++row)
{
if (type == PERF_TIME)
value = I_PreciseToMicros(*(precise_t *)row->value);
value = (*(precise_t *)row->value) / (I_GetPrecisePrecision() / 1000000);
else
value = *(int *)row->value;
@ -567,7 +568,7 @@ void M_DrawPerfStats(void)
len = (int)strlen(str);
if (len > 20)
str += len - 20;
snprintf(s, sizeof s - 1, "%20s: %d", str, I_PreciseToMicros(thinkframe_hooks[i].time_taken));
snprintf(s, sizeof s - 1, "%20s: %ld", str, (long)((thinkframe_hooks[i].time_taken) / (I_GetPrecisePrecision() / 1000000)));
V_DrawSmallString(x, y, V_MONOSPACE | V_ALLOWLOWERCASE | text_color, s);
y += 4; // repeated code!
if (y > 192)

View file

@ -13,6 +13,7 @@
#include "doomdef.h"
#include "p_local.h"
#include "r_fps.h"
#include "r_main.h"
#include "s_sound.h"
#include "z_zone.h"
@ -602,6 +603,9 @@ INT32 EV_DoCeiling(line_t *line, ceiling_e type)
ceiling->tag = tag;
ceiling->type = type;
firstone = 0;
// interpolation
R_CreateInterpolator_SectorPlane(&ceiling->thinker, sec, true);
}
return rtn;
}
@ -679,6 +683,10 @@ INT32 EV_DoCrush(line_t *line, ceiling_e type)
ceiling->tag = tag;
ceiling->type = type;
// interpolation
R_CreateInterpolator_SectorPlane(&ceiling->thinker, sec, false);
R_CreateInterpolator_SectorPlane(&ceiling->thinker, sec, true);
}
return rtn;
}

View file

@ -16,6 +16,7 @@
#include "m_random.h"
#include "p_local.h"
#include "p_slopes.h"
#include "r_fps.h"
#include "r_state.h"
#include "s_sound.h"
#include "z_zone.h"
@ -573,6 +574,8 @@ void T_ContinuousFalling(continuousfall_t *faller)
{
faller->sector->ceilingheight = faller->ceilingstartheight;
faller->sector->floorheight = faller->floorstartheight;
R_ClearLevelInterpolatorState(&faller->thinker);
}
P_CheckSector(faller->sector, false); // you might think this is irrelevant. you would be wrong
@ -1948,6 +1951,9 @@ void EV_DoFloor(line_t *line, floor_e floortype)
}
firstone = 0;
// interpolation
R_CreateInterpolator_SectorPlane(&dofloor->thinker, sec, false);
}
}
@ -2078,6 +2084,10 @@ void EV_DoElevator(line_t *line, elevator_e elevtype, boolean customspeed)
default:
break;
}
// interpolation
R_CreateInterpolator_SectorPlane(&elevator->thinker, sec, false);
R_CreateInterpolator_SectorPlane(&elevator->thinker, sec, true);
}
}
@ -2232,6 +2242,10 @@ void EV_BounceSector(sector_t *sec, fixed_t momz, line_t *sourceline)
bouncer->speed = momz/2;
bouncer->distance = FRACUNIT;
bouncer->low = true;
// interpolation
R_CreateInterpolator_SectorPlane(&bouncer->thinker, sec, false);
R_CreateInterpolator_SectorPlane(&bouncer->thinker, sec, true);
}
// For T_ContinuousFalling special
@ -2257,6 +2271,10 @@ void EV_DoContinuousFall(sector_t *sec, sector_t *backsector, fixed_t spd, boole
faller->destheight = backwards ? backsector->ceilingheight : backsector->floorheight;
faller->direction = backwards ? 1 : -1;
// interpolation
R_CreateInterpolator_SectorPlane(&faller->thinker, sec, false);
R_CreateInterpolator_SectorPlane(&faller->thinker, sec, true);
}
// Some other 3dfloor special things Tails 03-11-2002 (Search p_mobj.c for description)
@ -2309,6 +2327,10 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating,
crumble->sector->crumblestate = CRUMBLE_ACTIVATED;
// interpolation
R_CreateInterpolator_SectorPlane(&crumble->thinker, sec, false);
R_CreateInterpolator_SectorPlane(&crumble->thinker, sec, true);
TAG_ITER_SECTORS(tag, i)
{
foundsec = &sectors[i];
@ -2360,6 +2382,10 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher)
block->ceilingstartheight = block->sector->ceilingheight;
block->tag = (INT16)Tag_FGet(&sector->tags);
// interpolation
R_CreateInterpolator_SectorPlane(&block->thinker, roversec, false);
R_CreateInterpolator_SectorPlane(&block->thinker, roversec, true);
if (itsamonitor)
{
oldx = thing->x;
@ -2368,9 +2394,9 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher)
}
P_UnsetThingPosition(thing);
thing->x = sector->soundorg.x;
thing->y = sector->soundorg.y;
thing->z = topheight;
thing->x = thing->old_x = sector->soundorg.x;
thing->y = thing->old_y = sector->soundorg.y;
thing->z = thing->old_z = topheight;
thing->momz = FixedMul(6*FRACUNIT, thing->scale);
P_SetThingPosition(thing);
if (thing->flags & MF_SHOOTABLE)
@ -2391,9 +2417,9 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher)
if (itsamonitor && thing)
{
P_UnsetThingPosition(thing);
thing->x = oldx;
thing->y = oldy;
thing->z = oldz;
thing->x = thing->old_x = oldx;
thing->y = thing->old_y = oldy;
thing->z = thing->old_z = oldz;
thing->momx = 1;
thing->momy = 1;
P_SetThingPosition(thing);

View file

@ -19,6 +19,7 @@
#include "m_random.h"
#include "p_local.h"
#include "p_setup.h" // NiGHTS stuff
#include "r_fps.h"
#include "r_state.h"
#include "r_main.h"
#include "r_sky.h"
@ -181,6 +182,7 @@ void P_InitRoll(mobj_t *thing, angle_t newValue)
thing->roll = thing->old_roll = newValue;
}
// =========================================================================
// MOVEMENT ITERATOR FUNCTIONS
// =========================================================================
@ -654,9 +656,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; // underneath
if (tmthing->eflags & MFE_VERTICALFLIP)
thing->z = tmthing->z - thing->height - FixedMul(FRACUNIT, tmthing->scale);
P_SetOrigin(thing, thing->x, thing->y, tmthing->z - thing->height - FixedMul(FRACUNIT, tmthing->scale));
else
thing->z = tmthing->z + tmthing->height + FixedMul(FRACUNIT, tmthing->scale);
P_SetOrigin(thing, thing->x, thing->y, tmthing->z + tmthing->height + FixedMul(FRACUNIT, tmthing->scale));
if (thing->flags & MF_SHOOTABLE)
P_DamageMobj(thing, tmthing, tmthing, 1, 0);
return true;

View file

@ -18,6 +18,7 @@
#include "hu_stuff.h"
#include "p_local.h"
#include "p_setup.h"
#include "r_fps.h"
#include "r_main.h"
#include "r_skins.h"
#include "r_sky.h"
@ -3807,13 +3808,7 @@ void P_NullPrecipThinker(precipmobj_t *mobj)
void P_PrecipThinker(precipmobj_t *mobj)
{
// reset old state (for interpolation)
mobj->old_x = mobj->x;
mobj->old_y = mobj->y;
mobj->old_z = mobj->z;
mobj->old_angle = mobj->angle;
mobj->old_pitch = mobj->pitch;
mobj->old_roll = mobj->roll;
R_ResetPrecipitationMobjInterpolationState(mobj);
P_CycleStateAnimation((mobj_t *)mobj);
@ -3861,12 +3856,14 @@ void P_PrecipThinker(precipmobj_t *mobj)
if ((mobj->info->deathstate == S_NULL) || (mobj->precipflags & PCF_PIT)) // no splashes on sky or bottomless pits
{
mobj->z = mobj->ceilingz;
R_ResetPrecipitationMobjInterpolationState(mobj);
}
else
{
P_SetPrecipMobjState(mobj, mobj->info->deathstate);
mobj->z = mobj->floorz;
mobj->precipflags |= PCF_SPLASH;
R_ResetPrecipitationMobjInterpolationState(mobj);
}
}
}
@ -5420,6 +5417,9 @@ static void P_MobjSceneryThink(mobj_t *mobj)
mobj->z = mobj->target->z + mobj->target->height + FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale);
else
mobj->z = mobj->target->z - FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->target->scale) - mobj->height;
mobj->old_z = mobj->z;
break;
case MT_LOCKONINF:
if (!(mobj->flags2 & MF2_STRONGBOX))
@ -5431,6 +5431,9 @@ static void P_MobjSceneryThink(mobj_t *mobj)
mobj->z = mobj->threshold + FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->scale);
else
mobj->z = mobj->threshold - FixedMul((16 + abs((signed)(leveltime % TICRATE) - TICRATE/2))*FRACUNIT, mobj->scale);
mobj->old_z = mobj->z;
break;
case MT_FLAMEJET:
P_FlameJetSceneryThink(mobj);
@ -10256,13 +10259,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
}
}
// OK so we kind of need NOTHINK objects to still think
// because otherwise they can never update their
// interpolation values. They might need some other kind
// of system, so consider this temporary...
#if 0
if (!(mobj->flags & MF_NOTHINK))
#endif
P_AddThinker(THINK_MOBJ, &mobj->thinker);
if (mobj->skin) // correct inadequecies above.
@ -10298,13 +10295,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
if (CheckForReverseGravity && !(mobj->flags & MF_NOBLOCKMAP))
P_CheckGravity(mobj, false);
// set initial old positions (for interpolation)
mobj->old_x = mobj->x;
mobj->old_y = mobj->y;
mobj->old_z = mobj->z;
mobj->old_angle = mobj->angle;
mobj->old_pitch = mobj->pitch;
mobj->old_roll = mobj->roll;
R_AddMobjInterpolator(mobj);
return mobj;
}
@ -10357,13 +10348,7 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
|| mobj->subsector->sector->floorpic == skyflatnum)
mobj->precipflags |= PCF_PIT;
// set initial old positions (for interpolation)
mobj->old_x = mobj->x;
mobj->old_y = mobj->y;
mobj->old_z = mobj->z;
mobj->old_angle = mobj->angle;
mobj->old_pitch = mobj->pitch;
mobj->old_roll = mobj->roll;
R_ResetPrecipitationMobjInterpolationState(mobj);
return mobj;
}
@ -10495,6 +10480,8 @@ void P_RemoveMobj(mobj_t *mobj)
memset((UINT8 *)mobj + sizeof(thinker_t), 0xff, sizeof(mobj_t) - sizeof(thinker_t));
#endif
R_RemoveMobjInterpolator(mobj);
// free block
if (!mobj->thinker.next)
{ // Uh-oh, the mobj doesn't think, P_RemoveThinker would never go through!
@ -13455,18 +13442,43 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo
newmobj->eflags |= MFE_VERTICALFLIP;
newmobj->flags2 |= MF2_OBJECTFLIP;
newmobj->z = mobj->z + mobj->height - zofs - newmobj->height;
newmobj->old_z = mobj->old_z + mobj->height - zofs - newmobj->height;
newmobj->old_z2 = mobj->old_z2 + mobj->height - zofs - newmobj->height;
}
else
{
newmobj->old_z = mobj->old_z + zofs;
newmobj->old_z2 = mobj->old_z2 + zofs;
}
// EXPERIMENT: Let all objects set their interp values relative to their owner's old values.
// This will hopefully create a lot less mobj-specific spawn cases,
// but if there's any weird scenarios feel free to remove again.
newmobj->destscale = mobj->destscale;
P_SetScale(newmobj, mobj->scale);
newmobj->old_x2 = mobj->old_x2 + xofs;
newmobj->old_y2 = mobj->old_y2 + yofs;
newmobj->old_x = mobj->old_x + xofs;
newmobj->old_y = mobj->old_y + yofs;
newmobj->old_z = mobj->old_z + zofs;
/*
newmobj->angle = mobj->angle;
newmobj->old_angle = mobj->old_angle;
*/
// This angle hack is needed for Lua scripts that set the angle after
// spawning, to avoid erroneous interpolation.
if (mobj->player)
{
newmobj->old_angle2 = mobj->player->old_drawangle2;
newmobj->old_angle = mobj->player->old_drawangle;
}
else
{
newmobj->old_angle2 = mobj->old_angle2;
newmobj->old_angle = mobj->old_angle;
}
newmobj->old_scale2 = mobj->old_scale2;
newmobj->old_scale = mobj->old_scale;
newmobj->old_spritexscale = mobj->old_spritexscale;
newmobj->old_spriteyscale = mobj->old_spriteyscale;
newmobj->old_spritexoffset = mobj->old_spritexoffset;
newmobj->old_spriteyoffset = mobj->old_spriteyoffset;
return newmobj;
}

View file

@ -282,6 +282,7 @@ typedef struct mobj_s
// Info for drawing: position.
fixed_t x, y, z;
fixed_t old_x, old_y, old_z; // position interpolation
fixed_t old_x2, old_y2, old_z2;
// More list: links in sector (if needed)
struct mobj_s *snext;
@ -290,6 +291,7 @@ typedef struct mobj_s
// More drawing info: to determine current sprite.
angle_t angle, pitch, roll; // orientation
angle_t old_angle, old_pitch, old_roll; // orientation interpolation
angle_t old_angle2, old_pitch2, old_roll2;
angle_t rollangle;
spritenum_t sprite; // used to find patch_t and flip value
UINT32 frame; // frame number, plus bits see p_pspr.h
@ -299,6 +301,8 @@ typedef struct mobj_s
UINT32 renderflags; // render flags
fixed_t spritexscale, spriteyscale;
fixed_t spritexoffset, spriteyoffset;
fixed_t old_spritexscale, old_spriteyscale;
fixed_t old_spritexoffset, old_spriteyoffset;
struct pslope_s *floorspriteslope; // The slope that the floorsprite is rotated by
struct msecnode_s *touching_sectorlist; // a linked list of sectors where this object appears
@ -377,6 +381,8 @@ typedef struct mobj_s
UINT32 mobjnum; // A unique number for this mobj. Used for restoring pointers on save games.
fixed_t scale;
fixed_t old_scale; // interpolation
fixed_t old_scale2;
fixed_t destscale;
fixed_t scalespeed;
@ -391,6 +397,7 @@ typedef struct mobj_s
struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?)
boolean resetinterp; // if true, some fields should not be interpolated (see R_InterpolateMobjState implementation)
boolean colorized; // Whether the mobj uses the rainbow colormap
boolean mirrored; // The object's rotations will be mirrored left to right, e.g., see frame AL from the right and AR from the left
@ -423,6 +430,7 @@ typedef struct precipmobj_s
// Info for drawing: position.
fixed_t x, y, z;
fixed_t old_x, old_y, old_z; // position interpolation
fixed_t old_x2, old_y2, old_z2;
// More list: links in sector (if needed)
struct precipmobj_s *snext;
@ -431,6 +439,7 @@ typedef struct precipmobj_s
// More drawing info: to determine current sprite.
angle_t angle, pitch, roll; // orientation
angle_t old_angle, old_pitch, old_roll; // orientation interpolation
angle_t old_angle2, old_pitch2, old_roll2;
angle_t rollangle;
spritenum_t sprite; // used to find patch_t and flip value
UINT32 frame; // frame number, plus bits see p_pspr.h
@ -440,6 +449,8 @@ typedef struct precipmobj_s
UINT32 renderflags; // render flags
fixed_t spritexscale, spriteyscale;
fixed_t spritexoffset, spriteyoffset;
fixed_t old_spritexscale, old_spriteyscale;
fixed_t old_spritexoffset, old_spriteyoffset;
struct pslope_s *floorspriteslope; // The slope that the floorsprite is rotated by
struct mprecipsecnode_s *touching_sectorlist; // a linked list of sectors where this object appears

View file

@ -24,6 +24,7 @@
#include "p_tick.h"
#include "p_local.h"
#include "p_polyobj.h"
#include "r_fps.h"
#include "r_main.h"
#include "r_state.h"
#include "r_defs.h"
@ -2051,6 +2052,9 @@ boolean EV_DoPolyObjRotate(polyrotdata_t *prdata)
oldpo = po;
// interpolation
R_CreateInterpolator_Polyobj(&th->thinker, po);
th->turnobjs = prdata->turnobjs;
// apply action to mirroring polyobjects as well
@ -2112,6 +2116,9 @@ boolean EV_DoPolyObjMove(polymovedata_t *pmdata)
oldpo = po;
// interpolation
R_CreateInterpolator_Polyobj(&th->thinker, po);
// apply action to mirroring polyobjects as well
start = 0;
while ((po = Polyobj_GetChild(oldpo, &start)))
@ -2127,8 +2134,10 @@ boolean EV_DoPolyObjMove(polymovedata_t *pmdata)
boolean EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
{
polyobj_t *po;
polyobj_t *oldpo;
polywaypoint_t *th;
mobj_t *first = NULL;
INT32 start;
if (!(po = Polyobj_GetForNum(pwdata->polyObjNum)))
{
@ -2179,6 +2188,26 @@ boolean EV_DoPolyObjWaypoint(polywaypointdata_t *pwdata)
th->continuous = false;
}
// interpolation
R_CreateInterpolator_Polyobj(&th->thinker, po);
// T_PolyObjWaypoint is the only polyobject movement
// that can adjust z, so we add these ones too.
R_CreateInterpolator_SectorPlane(&th->thinker, po->lines[0]->backsector, false);
R_CreateInterpolator_SectorPlane(&th->thinker, po->lines[0]->backsector, true);
// Most other polyobject functions handle children by recursively
// giving each child another thinker. T_PolyObjWaypoint handles
// it manually though, which means we need to manually give them
// interpolation here instead.
start = 0;
oldpo = po;
while ((po = Polyobj_GetChild(oldpo, &start)))
{
R_CreateInterpolator_Polyobj(&th->thinker, po);
R_CreateInterpolator_SectorPlane(&th->thinker, po->lines[0]->backsector, false);
R_CreateInterpolator_SectorPlane(&th->thinker, po->lines[0]->backsector, true);
}
th->pointnum = first->health;
return true;
@ -2227,6 +2256,9 @@ static void Polyobj_doSlideDoor(polyobj_t *po, polydoordata_t *doordata)
oldpo = po;
// interpolation
R_CreateInterpolator_Polyobj(&th->thinker, po);
// start action on mirroring polyobjects as well
start = 0;
while ((po = Polyobj_GetChild(oldpo, &start)))
@ -2267,6 +2299,9 @@ static void Polyobj_doSwingDoor(polyobj_t *po, polydoordata_t *doordata)
oldpo = po;
// interpolation
R_CreateInterpolator_Polyobj(&th->thinker, po);
// start action on mirroring polyobjects as well
start = 0;
while ((po = Polyobj_GetChild(oldpo, &start)))
@ -2338,6 +2373,9 @@ boolean EV_DoPolyObjDisplace(polydisplacedata_t *prdata)
oldpo = po;
// interpolation
R_CreateInterpolator_Polyobj(&th->thinker, po);
// apply action to mirroring polyobjects as well
start = 0;
while ((po = Polyobj_GetChild(oldpo, &start)))
@ -2384,6 +2422,9 @@ boolean EV_DoPolyObjRotDisplace(polyrotdisplacedata_t *prdata)
oldpo = po;
// interpolation
R_CreateInterpolator_Polyobj(&th->thinker, po);
// apply action to mirroring polyobjects as well
start = 0;
while ((po = Polyobj_GetChild(oldpo, &start)))
@ -2488,6 +2529,9 @@ boolean EV_DoPolyObjFlag(polyflagdata_t *pfdata)
oldpo = po;
// interpolation
R_CreateInterpolator_Polyobj(&th->thinker, po);
// apply action to mirroring polyobjects as well
start = 0;
while ((po = Polyobj_GetChild(oldpo, &start)))

View file

@ -22,6 +22,7 @@
#include "p_setup.h"
#include "p_saveg.h"
#include "r_data.h"
#include "r_fps.h"
#include "r_textures.h"
#include "r_things.h"
#include "r_skins.h"
@ -3170,6 +3171,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
mobj->info = (mobjinfo_t *)next; // temporarily, set when leave this function
R_AddMobjInterpolator(mobj);
return &mobj->thinker;
}

View file

@ -21,6 +21,7 @@
#include "p_spec.h"
#include "p_saveg.h"
#include "i_time.h"
#include "i_video.h" // for I_FinishUpdate()..
#include "r_sky.h"
#include "i_system.h"
@ -32,6 +33,7 @@
#include "r_picformats.h"
#include "r_sky.h"
#include "r_draw.h"
#include "r_fps.h" // R_ResetViewInterpolation in level load
#include "s_sound.h"
#include "st_stuff.h"
@ -4160,7 +4162,10 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
while (nowtime < endtime) \
{ \
while (!((nowtime = I_GetTime()) - lastwipetic)) \
I_Sleep(); \
{ \
I_Sleep(cv_sleep.value); \
I_UpdateTime(cv_timescale.value); \
} \
lastwipetic = nowtime; \
if (moviemode) \
M_SaveFrame(); \
@ -4288,7 +4293,10 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
Patch_FreeTag(PU_PATCH_ROTATED);
Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1);
R_InitializeLevelInterpolators();
P_InitThinkers();
R_InitMobjInterpolators();
P_InitCachedActions();
if (!fromnetsave && savedata.lives > 0)

View file

@ -22,6 +22,7 @@
#include "r_main.h"
#include "p_maputl.h"
#include "w_wad.h"
#include "r_fps.h"
#include "k_kart.h" // K_PlayerEBrake
pslope_t *slopelist = NULL;
@ -241,6 +242,9 @@ static inline void P_AddDynSlopeThinker (pslope_t* slope, dynplanetype_t type, l
th->type = type;
P_AddThinker(THINK_DYNSLOPE, &th->thinker);
// interpolation
R_CreateInterpolator_DynSlope(&th->thinker, slope);
}

View file

@ -20,6 +20,7 @@
#include "p_local.h"
#include "p_setup.h" // levelflats for flat animation
#include "r_data.h"
#include "r_fps.h"
#include "r_textures.h"
#include "m_random.h"
#include "p_mobj.h"
@ -5528,6 +5529,10 @@ static void P_AddFloatThinker(sector_t *sec, UINT16 tag, line_t *sourceline)
floater->sector = sec;
floater->tag = (INT16)tag;
floater->sourceline = sourceline;
// interpolation
R_CreateInterpolator_SectorPlane(&floater->thinker, sec, false);
R_CreateInterpolator_SectorPlane(&floater->thinker, sec, true);
}
/**
@ -5557,6 +5562,9 @@ static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control,
displace->speed = speed;
displace->type = type;
displace->reverse = reverse;
// interpolation
R_CreateInterpolator_SectorPlane(&displace->thinker, &sectors[affectee], false);
}
/** Adds a Mario block thinker, which changes the block's texture between blank
@ -5616,6 +5624,10 @@ static void P_AddRaiseThinker(sector_t *sec, INT16 tag, fixed_t speed, fixed_t c
raise->flags |= RF_REVERSE;
if (spindash)
raise->flags |= RF_SPINDASH;
// interpolation
R_CreateInterpolator_SectorPlane(&raise->thinker, sec, false);
R_CreateInterpolator_SectorPlane(&raise->thinker, sec, true);
}
static void P_AddAirbob(sector_t *sec, INT16 tag, fixed_t dist, boolean raise, boolean spindash, boolean dynamic)
@ -5641,6 +5653,10 @@ static void P_AddAirbob(sector_t *sec, INT16 tag, fixed_t dist, boolean raise, b
airbob->flags |= RF_SPINDASH;
if (dynamic)
airbob->flags |= RF_DYNAMIC;
// interpolation
R_CreateInterpolator_SectorPlane(&airbob->thinker, sec, false);
R_CreateInterpolator_SectorPlane(&airbob->thinker, sec, true);
}
/** Adds a thwomp thinker.
@ -5681,6 +5697,10 @@ static inline void P_AddThwompThinker(sector_t *sec, line_t *sourceline, fixed_t
sec->ceilingdata = thwomp;
// Start with 'resting' texture
sides[sourceline->sidenum[0]].midtexture = sides[sourceline->sidenum[0]].bottomtexture;
// interpolation
R_CreateInterpolator_SectorPlane(&thwomp->thinker, sec, false);
R_CreateInterpolator_SectorPlane(&thwomp->thinker, sec, true);
}
/** Adds a thinker which checks if any MF_ENEMY objects with health are in the defined area.
@ -7301,6 +7321,22 @@ static void Add_Scroller(INT32 type, fixed_t dx, fixed_t dy, INT32 control, INT3
s->last_height = sectors[control].floorheight + sectors[control].ceilingheight;
s->affectee = affectee;
P_AddThinker(THINK_MAIN, &s->thinker);
// interpolation
switch (type)
{
case sc_side:
R_CreateInterpolator_SideScroll(&s->thinker, &sides[affectee]);
break;
case sc_floor:
R_CreateInterpolator_SectorScroll(&s->thinker, &sectors[affectee], false);
break;
case sc_ceiling:
R_CreateInterpolator_SectorScroll(&s->thinker, &sectors[affectee], true);
break;
default:
break;
}
}
/** Initializes the scrollers.

View file

@ -171,7 +171,5 @@ boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle
P_FlashPal(thing->player, PAL_MIXUP, 10);
}
P_InitAngle(thing, angle);
return true;
}

View file

@ -261,6 +261,7 @@ void P_RemoveThinkerDelayed(thinker_t *thinker)
* thinker->prev->next = thinker->next */
(next->prev = currentthinker = thinker->prev)->next = next;
R_DestroyLevelInterpolators(thinker);
Z_Free(thinker);
}
@ -492,6 +493,19 @@ static inline void P_DoTeamStuff(void)
}
}
void P_RunChaseCameras(void)
{
UINT8 i;
for (i = 0; i <= r_splitscreen; i++)
{
if (camera[i].chase)
{
P_MoveChaseCamera(&players[displayplayers[i]], &camera[i], false);
}
}
}
//
// P_Ticker
//
@ -511,8 +525,10 @@ void P_Ticker(boolean run)
if (OP_FreezeObjectplace())
{
P_MapStart();
R_UpdateMobjInterpolators();
OP_ObjectplaceMovement(&players[0]);
P_MoveChaseCamera(&players[0], &camera[0], false);
R_UpdateViewInterpolation();
P_MapEnd();
S_SetStackAdjustmentStart();
return;
@ -545,6 +561,8 @@ void P_Ticker(boolean run)
if (run)
{
R_UpdateMobjInterpolators();
if (demo.recording)
{
G_WriteDemoExtraData();
@ -730,11 +748,14 @@ void P_Ticker(boolean run)
K_UpdateDirector();
// Always move the camera.
for (i = 0; i <= r_splitscreen; i++)
P_RunChaseCameras();
LUAh_PostThinkFrame();
if (run)
{
if (camera[i].chase)
P_MoveChaseCamera(&players[displayplayers[i]], &camera[i], false);
LUAh_PostThinkFrame();
R_UpdateLevelInterpolators();
R_UpdateViewInterpolation();
}
P_MapEnd();
@ -770,6 +791,8 @@ void P_PreTicker(INT32 frames)
{
P_MapStart();
R_UpdateMobjInterpolators();
// First loop: Ensure all players' distance to the finish line are all accurate
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
@ -814,6 +837,10 @@ void P_PreTicker(INT32 frames)
LUAh_PostThinkFrame();
R_UpdateLevelInterpolators();
R_UpdateViewInterpolation();
R_ResetViewInterpolation(0);
P_MapEnd();
hook_defrosting--;

View file

@ -24,6 +24,7 @@ extern tic_t leveltime;
void Command_Numthinkers_f(void);
void Command_CountMobjs_f(void);
void P_RunChaseCameras(void);
void P_Ticker(boolean run);
void P_PreTicker(INT32 frames);
void P_DoTeamscrambling(void);

View file

@ -20,6 +20,7 @@
#include "d_net.h"
#include "g_game.h"
#include "p_local.h"
#include "r_fps.h"
#include "r_main.h"
#include "s_sound.h"
#include "r_skins.h"
@ -1204,12 +1205,12 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
}
// Copy interpolation data :)
ghost->old_x = mobj->old_x;
ghost->old_y = mobj->old_y;
ghost->old_z = mobj->old_z;
ghost->old_angle = (mobj->player ? mobj->player->old_drawangle : mobj->old_angle);
ghost->old_pitch = mobj->old_pitch;
ghost->old_roll = mobj->old_roll;
ghost->old_x = mobj->old_x2;
ghost->old_y = mobj->old_y2;
ghost->old_z = mobj->old_z2;
ghost->old_angle = (mobj->player ? mobj->player->old_drawangle2 : mobj->old_angle2);
ghost->old_pitch = mobj->old_pitch2;
ghost->old_roll = mobj->old_roll2;
return ghost;
}

View file

@ -904,6 +904,7 @@ static void R_Subsector(size_t num)
extracolormap_t *floorcolormap;
extracolormap_t *ceilingcolormap;
fixed_t floorcenterz, ceilingcenterz;
ffloor_t *rover;
#ifdef RANGECHECK
if (num >= numsubsectors)
@ -930,7 +931,23 @@ static void R_Subsector(size_t num)
// Check and prep all 3D floors. Set the sector floor/ceiling light levels and colormaps.
if (frontsector->ffloors)
{
if (frontsector->moved)
boolean anyMoved = frontsector->moved;
if (anyMoved == false)
{
for (rover = frontsector->ffloors; rover; rover = rover->next)
{
sector_t *controlSec = &sectors[rover->secnum];
if (controlSec->moved == true)
{
anyMoved = true;
break;
}
}
}
if (anyMoved == true)
{
frontsector->numlights = sub->sector->numlights = 0;
R_Prep3DFloors(frontsector);
@ -983,7 +1000,6 @@ static void R_Subsector(size_t num)
ffloor[numffloors].polyobj = NULL;
if (frontsector->ffloors)
{
ffloor_t *rover;
fixed_t heightcheck, planecenterz;
for (rover = frontsector->ffloors; rover && numffloors < MAXFFLOORS; rover = rover->next)

View file

@ -20,42 +20,45 @@
#include "r_plane.h"
#include "p_spec.h"
#include "r_state.h"
#include "z_zone.h"
#include "console.h" // con_startup_loadprogress
#ifdef HWRENDER
#include "hardware/hw_main.h" // for cv_glshearing
#endif
static CV_PossibleValue_t fpscap_cons_t[] = {
{-1, "Match refresh rate"},
{0, "Unlimited"},
#ifdef DEVELOP
// Lower values are actually pretty useful for debugging interp problems!
{1, "One Singular Frame"},
{10, "10"},
{20, "20"},
{25, "25"},
{30, "30"},
{1, "MIN"},
#else
{TICRATE, "MIN"},
#endif
{35, "35"},
{50, "50"},
{60, "60"},
{70, "70"},
{75, "75"},
{90, "90"},
{100, "100"},
{120, "120"},
{144, "144"},
{200, "200"},
{240, "240"},
{300, "MAX"},
{-1, "Unlimited"},
{0, "Match refresh rate"},
{0, NULL}
};
consvar_t cv_fpscap = CVAR_INIT ("fpscap", "Match refresh rate", CV_SAVE, fpscap_cons_t, NULL);
UINT32 R_GetFramerateCap(void)
{
if (rendermode == render_none)
{
// If we're not rendering (dedicated server),
// we shouldn't be using any interpolation.
return TICRATE;
}
if (cv_fpscap.value == 0)
{
// 0: Match refresh rate
return I_GetRefreshRate();
}
if (cv_fpscap.value < 0)
{
return I_GetRefreshRate();
// -1: Unlimited
return 0;
}
return cv_fpscap.value;
@ -63,7 +66,7 @@ UINT32 R_GetFramerateCap(void)
boolean R_UsingFrameInterpolation(void)
{
return (R_GetFramerateCap() != TICRATE); // maybe use ">" instead?
return (R_GetFramerateCap() != TICRATE || cv_timescale.value < FRACUNIT);
}
static viewvars_t pview_old[MAXSPLITSCREENPLAYERS];
@ -72,18 +75,41 @@ static viewvars_t skyview_old[MAXSPLITSCREENPLAYERS];
static viewvars_t skyview_new[MAXSPLITSCREENPLAYERS];
static viewvars_t *oldview = &pview_old[0];
static int oldview_invalid[MAXSPLITSCREENPLAYERS] = {0, 0, 0, 0};
viewvars_t *newview = &pview_new[0];
enum viewcontext_e viewcontext = VIEWCONTEXT_PLAYER1;
static levelinterpolator_t **levelinterpolators;
static size_t levelinterpolators_len;
static size_t levelinterpolators_size;
static fixed_t R_LerpFixed(fixed_t from, fixed_t to, fixed_t frac)
{
return FixedMul(frac, to - from);
return from + FixedMul(frac, to - from);
}
static angle_t R_LerpAngle(angle_t from, angle_t to, fixed_t frac)
{
return FixedMul(frac, to - from);
return from + FixedMul(frac, to - from);
}
static vector2_t *R_LerpVector2(const vector2_t *from, const vector2_t *to, fixed_t frac, vector2_t *out)
{
FV2_SubEx(to, from, out);
FV2_MulEx(out, frac, out);
FV2_AddEx(from, out, out);
return out;
}
static vector3_t *R_LerpVector3(const vector3_t *from, const vector3_t *to, fixed_t frac, vector3_t *out)
{
FV3_SubEx(to, from, out);
FV3_MulEx(out, frac, out);
FV3_AddEx(from, out, out);
return out;
}
// recalc necessary stuff for mouseaiming
@ -124,25 +150,49 @@ static void R_SetupFreelook(player_t *player, boolean skybox)
void R_InterpolateViewRollAngle(fixed_t frac)
{
viewroll = oldview->roll + R_LerpAngle(oldview->roll, newview->roll, frac);
viewroll = R_LerpAngle(oldview->roll, newview->roll, frac);
}
void R_InterpolateView(fixed_t frac)
{
if (frac < 0)
viewvars_t* prevview = oldview;
UINT8 i;
if (FIXED_TO_FLOAT(frac) < 0)
frac = 0;
#if 0
if (frac > FRACUNIT)
frac = FRACUNIT;
#endif
viewx = oldview->x + R_LerpFixed(oldview->x, newview->x, frac);
viewy = oldview->y + R_LerpFixed(oldview->y, newview->y, frac);
viewz = oldview->z + R_LerpFixed(oldview->z, newview->z, frac);
if (viewcontext == VIEWCONTEXT_SKY1 || viewcontext == VIEWCONTEXT_PLAYER1)
{
i = 0;
}
else if (viewcontext == VIEWCONTEXT_SKY2 || viewcontext == VIEWCONTEXT_PLAYER2)
{
i = 1;
}
else if (viewcontext == VIEWCONTEXT_SKY3 || viewcontext == VIEWCONTEXT_PLAYER3)
{
i = 2;
}
else
{
i = 3;
}
viewangle = oldview->angle + R_LerpAngle(oldview->angle, newview->angle, frac);
aimingangle = oldview->aim + R_LerpAngle(oldview->aim, newview->aim, frac);
R_InterpolateViewRollAngle(frac);
if (oldview_invalid[i] != 0)
{
// interpolate from newview to newview
prevview = newview;
}
viewx = R_LerpFixed(prevview->x, newview->x, frac);
viewy = R_LerpFixed(prevview->y, newview->y, frac);
viewz = R_LerpFixed(prevview->z, newview->z, frac);
viewangle = R_LerpAngle(prevview->angle, newview->angle, frac);
aimingangle = R_LerpAngle(prevview->aim, newview->aim, frac);
viewroll = R_LerpAngle(prevview->roll, newview->roll, frac);
viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
@ -161,6 +211,23 @@ void R_UpdateViewInterpolation(void)
{
pview_old[i] = pview_new[i];
skyview_old[i] = skyview_new[i];
if (oldview_invalid[i] > 0) oldview_invalid[i]--;
}
}
void R_ResetViewInterpolation(UINT8 p)
{
if (p == 0)
{
UINT8 i;
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
oldview_invalid[i]++;
}
}
else
{
oldview_invalid[p - 1]++;
}
}
@ -203,7 +270,7 @@ fixed_t R_InterpolateFixed(fixed_t from, fixed_t to)
return to;
}
return (from + R_LerpFixed(from, to, rendertimefrac));
return (R_LerpFixed(from, to, rendertimefrac));
}
angle_t R_InterpolateAngle(angle_t from, angle_t to)
@ -213,5 +280,537 @@ angle_t R_InterpolateAngle(angle_t from, angle_t to)
return to;
}
return (from + R_LerpAngle(from, to, rendertimefrac));
return (R_LerpAngle(from, to, rendertimefrac));
}
void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out)
{
if (frac == FRACUNIT)
{
out->x = mobj->x;
out->y = mobj->y;
out->z = mobj->z;
out->scale = mobj->scale;
out->subsector = mobj->subsector;
out->angle = mobj->player ? mobj->player->drawangle : mobj->angle;
out->spritexscale = mobj->spritexscale;
out->spriteyscale = mobj->spriteyscale;
out->spritexoffset = mobj->spritexoffset;
out->spriteyoffset = mobj->spriteyoffset;
return;
}
out->x = R_LerpFixed(mobj->old_x, mobj->x, frac);
out->y = R_LerpFixed(mobj->old_y, mobj->y, frac);
out->z = R_LerpFixed(mobj->old_z, mobj->z, frac);
out->scale = mobj->resetinterp ? mobj->scale : R_LerpFixed(mobj->old_scale, mobj->scale, frac);
out->spritexscale = mobj->resetinterp ? mobj->spritexscale : R_LerpFixed(mobj->old_spritexscale, mobj->spritexscale, frac);
out->spriteyscale = mobj->resetinterp ? mobj->spriteyscale : R_LerpFixed(mobj->old_spriteyscale, mobj->spriteyscale, frac);
// Sprite offsets are not interpolated until we have a way to interpolate them explicitly in Lua.
// It seems existing mods visually break more often than not if it is interpolated.
out->spritexoffset = mobj->spritexoffset;
out->spriteyoffset = mobj->spriteyoffset;
out->subsector = R_PointInSubsector(out->x, out->y);
if (mobj->player)
{
out->angle = mobj->resetinterp ? mobj->player->drawangle : R_LerpAngle(mobj->player->old_drawangle, mobj->player->drawangle, frac);
}
else
{
out->angle = mobj->resetinterp ? mobj->angle : R_LerpAngle(mobj->old_angle, mobj->angle, frac);
}
}
void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out)
{
if (frac == FRACUNIT)
{
out->x = mobj->x;
out->y = mobj->y;
out->z = mobj->z;
out->scale = FRACUNIT;
out->subsector = mobj->subsector;
out->angle = mobj->angle;
out->spritexscale = mobj->spritexscale;
out->spriteyscale = mobj->spriteyscale;
out->spritexoffset = mobj->spritexoffset;
out->spriteyoffset = mobj->spriteyoffset;
return;
}
out->x = R_LerpFixed(mobj->old_x, mobj->x, frac);
out->y = R_LerpFixed(mobj->old_y, mobj->y, frac);
out->z = R_LerpFixed(mobj->old_z, mobj->z, frac);
out->scale = FRACUNIT;
out->spritexscale = R_LerpFixed(mobj->old_spritexscale, mobj->spritexscale, frac);
out->spriteyscale = R_LerpFixed(mobj->old_spriteyscale, mobj->spriteyscale, frac);
out->spritexoffset = R_LerpFixed(mobj->old_spritexoffset, mobj->spritexoffset, frac);
out->spriteyoffset = R_LerpFixed(mobj->old_spriteyoffset, mobj->spriteyoffset, frac);
out->subsector = R_PointInSubsector(out->x, out->y);
out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac);
}
static void AddInterpolator(levelinterpolator_t* interpolator)
{
if (levelinterpolators_len >= levelinterpolators_size)
{
if (levelinterpolators_size == 0)
{
levelinterpolators_size = 128;
}
else
{
levelinterpolators_size *= 2;
}
levelinterpolators = Z_ReallocAlign(
(void*) levelinterpolators,
sizeof(levelinterpolator_t*) * levelinterpolators_size,
PU_LEVEL,
NULL,
sizeof(levelinterpolator_t*) * 8
);
}
levelinterpolators[levelinterpolators_len] = interpolator;
levelinterpolators_len += 1;
}
static levelinterpolator_t *CreateInterpolator(levelinterpolator_type_e type, thinker_t *thinker)
{
levelinterpolator_t *ret = (levelinterpolator_t*) Z_CallocAlign(
sizeof(levelinterpolator_t),
PU_LEVEL,
NULL,
sizeof(levelinterpolator_t) * 8
);
ret->type = type;
ret->thinker = thinker;
AddInterpolator(ret);
return ret;
}
void R_CreateInterpolator_SectorPlane(thinker_t *thinker, sector_t *sector, boolean ceiling)
{
levelinterpolator_t *interp = CreateInterpolator(LVLINTERP_SectorPlane, thinker);
interp->sectorplane.sector = sector;
interp->sectorplane.ceiling = ceiling;
if (ceiling)
{
interp->sectorplane.oldheight = interp->sectorplane.bakheight = sector->ceilingheight;
}
else
{
interp->sectorplane.oldheight = interp->sectorplane.bakheight = sector->floorheight;
}
}
void R_CreateInterpolator_SectorScroll(thinker_t *thinker, sector_t *sector, boolean ceiling)
{
levelinterpolator_t *interp = CreateInterpolator(LVLINTERP_SectorScroll, thinker);
interp->sectorscroll.sector = sector;
interp->sectorscroll.ceiling = ceiling;
if (ceiling)
{
interp->sectorscroll.oldxoffs = interp->sectorscroll.bakxoffs = sector->ceiling_xoffs;
interp->sectorscroll.oldyoffs = interp->sectorscroll.bakyoffs = sector->ceiling_yoffs;
}
else
{
interp->sectorscroll.oldxoffs = interp->sectorscroll.bakxoffs = sector->floor_xoffs;
interp->sectorscroll.oldyoffs = interp->sectorscroll.bakyoffs = sector->floor_yoffs;
}
}
void R_CreateInterpolator_SideScroll(thinker_t *thinker, side_t *side)
{
levelinterpolator_t *interp = CreateInterpolator(LVLINTERP_SideScroll, thinker);
interp->sidescroll.side = side;
interp->sidescroll.oldtextureoffset = interp->sidescroll.baktextureoffset = side->textureoffset;
interp->sidescroll.oldrowoffset = interp->sidescroll.bakrowoffset = side->rowoffset;
}
void R_CreateInterpolator_Polyobj(thinker_t *thinker, polyobj_t *polyobj)
{
levelinterpolator_t *interp = CreateInterpolator(LVLINTERP_Polyobj, thinker);
interp->polyobj.polyobj = polyobj;
interp->polyobj.vertices_size = polyobj->numVertices;
interp->polyobj.oldvertices = Z_CallocAlign(sizeof(fixed_t) * 2 * polyobj->numVertices, PU_LEVEL, NULL, 32);
interp->polyobj.bakvertices = Z_CallocAlign(sizeof(fixed_t) * 2 * polyobj->numVertices, PU_LEVEL, NULL, 32);
for (size_t i = 0; i < polyobj->numVertices; i++)
{
interp->polyobj.oldvertices[i * 2 ] = interp->polyobj.bakvertices[i * 2 ] = polyobj->vertices[i]->x;
interp->polyobj.oldvertices[i * 2 + 1] = interp->polyobj.bakvertices[i * 2 + 1] = polyobj->vertices[i]->y;
}
interp->polyobj.oldcx = interp->polyobj.bakcx = polyobj->centerPt.x;
interp->polyobj.oldcy = interp->polyobj.bakcy = polyobj->centerPt.y;
}
void R_CreateInterpolator_DynSlope(thinker_t *thinker, pslope_t *slope)
{
levelinterpolator_t *interp = CreateInterpolator(LVLINTERP_DynSlope, thinker);
interp->dynslope.slope = slope;
FV3_Copy(&interp->dynslope.oldo, &slope->o);
FV3_Copy(&interp->dynslope.bako, &slope->o);
FV2_Copy(&interp->dynslope.oldd, &slope->d);
FV2_Copy(&interp->dynslope.bakd, &slope->d);
interp->dynslope.oldzdelta = interp->dynslope.bakzdelta = slope->zdelta;
}
void R_InitializeLevelInterpolators(void)
{
levelinterpolators_len = 0;
levelinterpolators_size = 0;
levelinterpolators = NULL;
}
static void UpdateLevelInterpolatorState(levelinterpolator_t *interp)
{
size_t i;
switch (interp->type)
{
case LVLINTERP_SectorPlane:
interp->sectorplane.oldheight = interp->sectorplane.bakheight;
interp->sectorplane.bakheight = interp->sectorplane.ceiling ? interp->sectorplane.sector->ceilingheight : interp->sectorplane.sector->floorheight;
break;
case LVLINTERP_SectorScroll:
interp->sectorscroll.oldxoffs = interp->sectorscroll.bakxoffs;
interp->sectorscroll.bakxoffs = interp->sectorscroll.ceiling ? interp->sectorscroll.sector->ceiling_xoffs : interp->sectorscroll.sector->floor_xoffs;
interp->sectorscroll.oldyoffs = interp->sectorscroll.bakyoffs;
interp->sectorscroll.bakyoffs = interp->sectorscroll.ceiling ? interp->sectorscroll.sector->ceiling_yoffs : interp->sectorscroll.sector->floor_yoffs;
break;
case LVLINTERP_SideScroll:
interp->sidescroll.oldtextureoffset = interp->sidescroll.baktextureoffset;
interp->sidescroll.baktextureoffset = interp->sidescroll.side->textureoffset;
interp->sidescroll.oldrowoffset = interp->sidescroll.bakrowoffset;
interp->sidescroll.bakrowoffset = interp->sidescroll.side->rowoffset;
break;
case LVLINTERP_Polyobj:
for (i = 0; i < interp->polyobj.vertices_size; i++)
{
interp->polyobj.oldvertices[i * 2 ] = interp->polyobj.bakvertices[i * 2 ];
interp->polyobj.oldvertices[i * 2 + 1] = interp->polyobj.bakvertices[i * 2 + 1];
interp->polyobj.bakvertices[i * 2 ] = interp->polyobj.polyobj->vertices[i]->x;
interp->polyobj.bakvertices[i * 2 + 1] = interp->polyobj.polyobj->vertices[i]->y;
}
interp->polyobj.oldcx = interp->polyobj.bakcx;
interp->polyobj.oldcy = interp->polyobj.bakcy;
interp->polyobj.bakcx = interp->polyobj.polyobj->centerPt.x;
interp->polyobj.bakcy = interp->polyobj.polyobj->centerPt.y;
break;
case LVLINTERP_DynSlope:
FV3_Copy(&interp->dynslope.oldo, &interp->dynslope.bako);
FV2_Copy(&interp->dynslope.oldd, &interp->dynslope.bakd);
interp->dynslope.oldzdelta = interp->dynslope.bakzdelta;
FV3_Copy(&interp->dynslope.bako, &interp->dynslope.slope->o);
FV2_Copy(&interp->dynslope.bakd, &interp->dynslope.slope->d);
interp->dynslope.bakzdelta = interp->dynslope.slope->zdelta;
break;
}
}
void R_UpdateLevelInterpolators(void)
{
size_t i;
for (i = 0; i < levelinterpolators_len; i++)
{
levelinterpolator_t *interp = levelinterpolators[i];
UpdateLevelInterpolatorState(interp);
}
}
void R_ClearLevelInterpolatorState(thinker_t *thinker)
{
size_t i;
for (i = 0; i < levelinterpolators_len; i++)
{
levelinterpolator_t *interp = levelinterpolators[i];
if (interp->thinker == thinker)
{
// Do it twice to make the old state match the new
UpdateLevelInterpolatorState(interp);
UpdateLevelInterpolatorState(interp);
}
}
}
void R_ApplyLevelInterpolators(fixed_t frac)
{
size_t i, ii;
for (i = 0; i < levelinterpolators_len; i++)
{
levelinterpolator_t *interp = levelinterpolators[i];
switch (interp->type)
{
case LVLINTERP_SectorPlane:
if (interp->sectorplane.ceiling)
{
interp->sectorplane.sector->ceilingheight = R_LerpFixed(interp->sectorplane.oldheight, interp->sectorplane.bakheight, frac);
}
else
{
interp->sectorplane.sector->floorheight = R_LerpFixed(interp->sectorplane.oldheight, interp->sectorplane.bakheight, frac);
}
interp->sectorplane.sector->moved = true;
break;
case LVLINTERP_SectorScroll:
if (interp->sectorscroll.ceiling)
{
interp->sectorscroll.sector->ceiling_xoffs = R_LerpFixed(interp->sectorscroll.oldxoffs, interp->sectorscroll.bakxoffs, frac);
interp->sectorscroll.sector->ceiling_yoffs = R_LerpFixed(interp->sectorscroll.oldyoffs, interp->sectorscroll.bakyoffs, frac);
}
else
{
interp->sectorscroll.sector->floor_xoffs = R_LerpFixed(interp->sectorscroll.oldxoffs, interp->sectorscroll.bakxoffs, frac);
interp->sectorscroll.sector->floor_yoffs = R_LerpFixed(interp->sectorscroll.oldyoffs, interp->sectorscroll.bakyoffs, frac);
}
break;
case LVLINTERP_SideScroll:
interp->sidescroll.side->textureoffset = R_LerpFixed(interp->sidescroll.oldtextureoffset, interp->sidescroll.baktextureoffset, frac);
interp->sidescroll.side->rowoffset = R_LerpFixed(interp->sidescroll.oldrowoffset, interp->sidescroll.bakrowoffset, frac);
break;
case LVLINTERP_Polyobj:
for (ii = 0; ii < interp->polyobj.vertices_size; ii++)
{
interp->polyobj.polyobj->vertices[ii]->x = R_LerpFixed(interp->polyobj.oldvertices[ii * 2 ], interp->polyobj.bakvertices[ii * 2 ], frac);
interp->polyobj.polyobj->vertices[ii]->y = R_LerpFixed(interp->polyobj.oldvertices[ii * 2 + 1], interp->polyobj.bakvertices[ii * 2 + 1], frac);
}
interp->polyobj.polyobj->centerPt.x = R_LerpFixed(interp->polyobj.oldcx, interp->polyobj.bakcx, frac);
interp->polyobj.polyobj->centerPt.y = R_LerpFixed(interp->polyobj.oldcy, interp->polyobj.bakcy, frac);
break;
case LVLINTERP_DynSlope:
R_LerpVector3(&interp->dynslope.oldo, &interp->dynslope.bako, frac, &interp->dynslope.slope->o);
R_LerpVector2(&interp->dynslope.oldd, &interp->dynslope.bakd, frac, &interp->dynslope.slope->d);
interp->dynslope.slope->zdelta = R_LerpFixed(interp->dynslope.oldzdelta, interp->dynslope.bakzdelta, frac);
break;
}
}
}
void R_RestoreLevelInterpolators(void)
{
size_t i, ii;
for (i = 0; i < levelinterpolators_len; i++)
{
levelinterpolator_t *interp = levelinterpolators[i];
switch (interp->type)
{
case LVLINTERP_SectorPlane:
if (interp->sectorplane.ceiling)
{
interp->sectorplane.sector->ceilingheight = interp->sectorplane.bakheight;
}
else
{
interp->sectorplane.sector->floorheight = interp->sectorplane.bakheight;
}
interp->sectorplane.sector->moved = true;
break;
case LVLINTERP_SectorScroll:
if (interp->sectorscroll.ceiling)
{
interp->sectorscroll.sector->ceiling_xoffs = interp->sectorscroll.bakxoffs;
interp->sectorscroll.sector->ceiling_yoffs = interp->sectorscroll.bakyoffs;
}
else
{
interp->sectorscroll.sector->floor_xoffs = interp->sectorscroll.bakxoffs;
interp->sectorscroll.sector->floor_yoffs = interp->sectorscroll.bakyoffs;
}
break;
case LVLINTERP_SideScroll:
interp->sidescroll.side->textureoffset = interp->sidescroll.baktextureoffset;
interp->sidescroll.side->rowoffset = interp->sidescroll.bakrowoffset;
break;
case LVLINTERP_Polyobj:
for (ii = 0; ii < interp->polyobj.vertices_size; ii++)
{
interp->polyobj.polyobj->vertices[ii]->x = interp->polyobj.bakvertices[ii * 2 ];
interp->polyobj.polyobj->vertices[ii]->y = interp->polyobj.bakvertices[ii * 2 + 1];
}
interp->polyobj.polyobj->centerPt.x = interp->polyobj.bakcx;
interp->polyobj.polyobj->centerPt.y = interp->polyobj.bakcy;
break;
case LVLINTERP_DynSlope:
FV3_Copy(&interp->dynslope.slope->o, &interp->dynslope.bako);
FV2_Copy(&interp->dynslope.slope->d, &interp->dynslope.bakd);
interp->dynslope.slope->zdelta = interp->dynslope.bakzdelta;
break;
}
}
}
void R_DestroyLevelInterpolators(thinker_t *thinker)
{
size_t i;
for (i = 0; i < levelinterpolators_len; i++)
{
levelinterpolator_t *interp = levelinterpolators[i];
if (interp->thinker == thinker)
{
// Swap the tail of the level interpolators to this spot
levelinterpolators[i] = levelinterpolators[levelinterpolators_len - 1];
levelinterpolators_len -= 1;
Z_Free(interp);
i -= 1;
}
}
}
static mobj_t **interpolated_mobjs = NULL;
static size_t interpolated_mobjs_len = 0;
static size_t interpolated_mobjs_capacity = 0;
// NOTE: This will NOT check that the mobj has already been added, for perf
// reasons.
void R_AddMobjInterpolator(mobj_t *mobj)
{
if (interpolated_mobjs_len >= interpolated_mobjs_capacity)
{
if (interpolated_mobjs_capacity == 0)
{
interpolated_mobjs_capacity = 256;
}
else
{
interpolated_mobjs_capacity *= 2;
}
interpolated_mobjs = Z_ReallocAlign(
interpolated_mobjs,
sizeof(mobj_t *) * interpolated_mobjs_capacity,
PU_LEVEL,
NULL,
64
);
}
interpolated_mobjs[interpolated_mobjs_len] = mobj;
interpolated_mobjs_len += 1;
R_ResetMobjInterpolationState(mobj);
mobj->resetinterp = true;
}
void R_RemoveMobjInterpolator(mobj_t *mobj)
{
size_t i;
if (interpolated_mobjs_len == 0) return;
for (i = 0; i < interpolated_mobjs_len - 1; i++)
{
if (interpolated_mobjs[i] == mobj)
{
interpolated_mobjs[i] = interpolated_mobjs[
interpolated_mobjs_len - 1
];
interpolated_mobjs_len -= 1;
return;
}
}
}
void R_InitMobjInterpolators(void)
{
// apparently it's not acceptable to free something already unallocated
// Z_Free(interpolated_mobjs);
interpolated_mobjs = NULL;
interpolated_mobjs_len = 0;
interpolated_mobjs_capacity = 0;
}
void R_UpdateMobjInterpolators(void)
{
size_t i;
for (i = 0; i < interpolated_mobjs_len; i++)
{
mobj_t *mobj = interpolated_mobjs[i];
if (!P_MobjWasRemoved(mobj))
R_ResetMobjInterpolationState(mobj);
}
}
//
// P_ResetMobjInterpolationState
//
// Reset the rendering interpolation state of the mobj.
//
void R_ResetMobjInterpolationState(mobj_t *mobj)
{
mobj->old_x2 = mobj->old_x;
mobj->old_y2 = mobj->old_y;
mobj->old_z2 = mobj->old_z;
mobj->old_angle2 = mobj->old_angle;
mobj->old_pitch2 = mobj->old_pitch;
mobj->old_roll2 = mobj->old_roll;
mobj->old_scale2 = mobj->old_scale;
mobj->old_x = mobj->x;
mobj->old_y = mobj->y;
mobj->old_z = mobj->z;
mobj->old_angle = mobj->angle;
mobj->old_pitch = mobj->pitch;
mobj->old_roll = mobj->roll;
mobj->old_scale = mobj->scale;
mobj->old_spritexscale = mobj->spritexscale;
mobj->old_spriteyscale = mobj->spriteyscale;
mobj->old_spritexoffset = mobj->spritexoffset;
mobj->old_spriteyoffset = mobj->spriteyoffset;
if (mobj->player)
{
mobj->player->old_drawangle2 = mobj->player->old_drawangle;
mobj->player->old_drawangle = mobj->player->drawangle;
}
mobj->resetinterp = false;
}
//
// P_ResetPrecipitationMobjInterpolationState
//
// Reset the rendering interpolation state of the precipmobj.
//
void R_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj)
{
mobj->old_x2 = mobj->old_x;
mobj->old_y2 = mobj->old_y;
mobj->old_z2 = mobj->old_z;
mobj->old_angle2 = mobj->old_angle;
mobj->old_pitch2 = mobj->old_pitch;
mobj->old_roll2 = mobj->old_roll;
mobj->old_x = mobj->x;
mobj->old_y = mobj->y;
mobj->old_z = mobj->z;
mobj->old_angle = mobj->angle;
mobj->old_spritexscale = mobj->spritexscale;
mobj->old_spriteyscale = mobj->spriteyscale;
mobj->old_spritexoffset = mobj->spritexoffset;
mobj->old_spriteyoffset = mobj->spriteyoffset;
}

View file

@ -54,16 +54,112 @@ typedef struct {
extern viewvars_t *newview;
typedef struct {
fixed_t x;
fixed_t y;
fixed_t z;
subsector_t *subsector;
angle_t angle;
fixed_t scale;
fixed_t spritexscale;
fixed_t spriteyscale;
fixed_t spritexoffset;
fixed_t spriteyoffset;
} interpmobjstate_t;
// Level interpolators
// The union tag for levelinterpolator_t
typedef enum {
LVLINTERP_SectorPlane,
LVLINTERP_SectorScroll,
LVLINTERP_SideScroll,
LVLINTERP_Polyobj,
LVLINTERP_DynSlope,
} levelinterpolator_type_e;
// Tagged union of a level interpolator
typedef struct levelinterpolator_s {
levelinterpolator_type_e type;
thinker_t *thinker;
union {
struct {
sector_t *sector;
fixed_t oldheight;
fixed_t bakheight;
boolean ceiling;
} sectorplane;
struct {
sector_t *sector;
fixed_t oldxoffs, oldyoffs, bakxoffs, bakyoffs;
boolean ceiling;
} sectorscroll;
struct {
side_t *side;
fixed_t oldtextureoffset, oldrowoffset, baktextureoffset, bakrowoffset;
} sidescroll;
struct {
polyobj_t *polyobj;
fixed_t *oldvertices;
fixed_t *bakvertices;
size_t vertices_size;
fixed_t oldcx, oldcy, bakcx, bakcy;
} polyobj;
struct {
pslope_t *slope;
vector3_t oldo, bako;
vector2_t oldd, bakd;
fixed_t oldzdelta, bakzdelta;
} dynslope;
};
} levelinterpolator_t;
// Interpolates the current view variables (r_state.h) against the selected view context in R_SetViewContext
void R_InterpolateView(fixed_t frac);
// Special function just for software
void R_InterpolateViewRollAngle(fixed_t frac);
// Buffer the current new views into the old views. Call once after each real tic.
void R_UpdateViewInterpolation(void);
// Reset the view states (e.g. after level load) so R_InterpolateView doesn't interpolate invalid data
void R_ResetViewInterpolation(UINT8 p);
// Set the current view context (the viewvars pointed to by newview)
void R_SetViewContext(enum viewcontext_e _viewcontext);
fixed_t R_InterpolateFixed(fixed_t from, fixed_t to);
angle_t R_InterpolateAngle(angle_t from, angle_t to);
// Evaluate the interpolated mobj state for the given mobj
void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out);
// Evaluate the interpolated mobj state for the given precipmobj
void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjstate_t *out);
void R_CreateInterpolator_SectorPlane(thinker_t *thinker, sector_t *sector, boolean ceiling);
void R_CreateInterpolator_SectorScroll(thinker_t *thinker, sector_t *sector, boolean ceiling);
void R_CreateInterpolator_SideScroll(thinker_t *thinker, side_t *side);
void R_CreateInterpolator_Polyobj(thinker_t *thinker, polyobj_t *polyobj);
void R_CreateInterpolator_DynSlope(thinker_t *thinker, pslope_t *slope);
// Initialize level interpolators after a level change
void R_InitializeLevelInterpolators(void);
// Update level interpolators, storing the previous and current states.
void R_UpdateLevelInterpolators(void);
// Clear states for all level interpolators for the thinker
void R_ClearLevelInterpolatorState(thinker_t *thinker);
// Apply level interpolators to the actual game state
void R_ApplyLevelInterpolators(fixed_t frac);
// Restore level interpolators to the real game state
void R_RestoreLevelInterpolators(void);
// Destroy interpolators associated with a thinker
void R_DestroyLevelInterpolators(thinker_t *thinker);
// Initialize internal mobj interpolator list (e.g. during level loading)
void R_InitMobjInterpolators(void);
// Add interpolation state for the given mobj
void R_AddMobjInterpolator(mobj_t *mobj);
// Remove the interpolation state for the given mobj
void R_RemoveMobjInterpolator(mobj_t *mobj);
void R_UpdateMobjInterpolators(void);
void R_ResetMobjInterpolationState(mobj_t *mobj);
void R_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj);
#endif

View file

@ -82,6 +82,7 @@ int r_splitscreen;
fixed_t rendertimefrac;
fixed_t renderdeltatics;
boolean renderisnewtic;
//
// precalculated math tables

View file

@ -37,6 +37,8 @@ extern size_t validcount, linecount, loopcount, framecount;
extern fixed_t rendertimefrac;
// Evaluated delta tics for this frame (how many tics since the last frame)
extern fixed_t renderdeltatics;
// The current render is a new logical tic
extern boolean renderisnewtic;
//
// Lighting LUT.

View file

@ -23,6 +23,7 @@
#include "info.h" // spr2names
#include "i_video.h" // rendermode
#include "i_system.h"
#include "r_fps.h"
#include "r_things.h"
#include "r_patch.h"
#include "r_patchrotation.h"
@ -1178,19 +1179,34 @@ static void R_SplitSprite(vissprite_t *sprite)
// shadowslope is filled with the floor's slope, if provided
//
fixed_t R_GetShadowZ(
mobj_t *thing, pslope_t **shadowslope,
fixed_t interpx, fixed_t interpy, fixed_t interpz)
mobj_t *thing, pslope_t **shadowslope)
{
fixed_t halfHeight = interpz + (thing->height >> 1);
fixed_t halfHeight;
boolean isflipped = thing->eflags & MFE_VERTICALFLIP;
fixed_t floorz = P_GetFloorZ(thing, thing->subsector->sector, interpx, interpy, NULL);
fixed_t ceilingz = P_GetCeilingZ(thing, thing->subsector->sector, interpx, interpy, NULL);
fixed_t floorz;
fixed_t ceilingz;
fixed_t z, groundz = isflipped ? INT32_MAX : INT32_MIN;
pslope_t *slope, *groundslope = NULL;
msecnode_t *node;
sector_t *sector;
ffloor_t *rover;
// for frame interpolation
interpmobjstate_t interp = {0};
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(thing, rendertimefrac, &interp);
}
else
{
R_InterpolateMobjState(thing, FRACUNIT, &interp);
}
halfHeight = interp.z + (thing->height >> 1);
floorz = P_GetFloorZ(thing, interp.subsector->sector, interp.x, interp.y, NULL);
ceilingz = P_GetCeilingZ(thing, interp.subsector->sector, interp.x, interp.y, NULL);
#define CHECKZ (isflipped ? z > halfHeight && z < groundz : z < halfHeight && z > groundz)
for (node = thing->touching_sectorlist; node; node = node->m_sectorlist_next)
@ -1202,7 +1218,7 @@ fixed_t R_GetShadowZ(
if (sector->heightsec != -1)
z = isflipped ? sectors[sector->heightsec].ceilingheight : sectors[sector->heightsec].floorheight;
else
z = isflipped ? P_GetSectorCeilingZAt(sector, interpx, interpy) : P_GetSectorFloorZAt(sector, interpx, interpy);
z = isflipped ? P_GetSectorCeilingZAt(sector, interp.x, interp.y) : P_GetSectorFloorZAt(sector, interp.x, interp.y);
if CHECKZ
{
@ -1216,8 +1232,7 @@ fixed_t R_GetShadowZ(
if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES) || (rover->alpha < 90 && !(rover->flags & FF_SWIMMABLE)))
continue;
z = isflipped ? P_GetFFloorBottomZAt(rover, interpx, interpy) : P_GetFFloorTopZAt(rover, interpx, interpy);
z = isflipped ? P_GetFFloorBottomZAt(rover, interp.x, interp.y) : P_GetFFloorTopZAt(rover, interp.x, interp.y);
if CHECKZ
{
groundz = z;
@ -1233,65 +1248,6 @@ fixed_t R_GetShadowZ(
groundslope = NULL;
}
#if 0 // Unfortunately, this drops CEZ2 down to sub-17 FPS on my i7.
// NOTE: this section was not updated to reflect reverse gravity support
// Check polyobjects and see if groundz needs to be altered, for rings only because they don't update floorz
if (thing->type == MT_RING)
{
INT32 xl, xh, yl, yh, bx, by;
xl = (unsigned)(interpx - thing->radius - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(interpx + thing->radius - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(interpy - thing->radius - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(interpy + thing->radius - bmaporgy)>>MAPBLOCKSHIFT;
BMBOUNDFIX(xl, xh, yl, yh);
validcount++;
for (by = yl; by <= yh; by++)
for (bx = xl; bx <= xh; bx++)
{
INT32 offset;
polymaplink_t *plink; // haleyjd 02/22/06
if (bx < 0 || by < 0 || bx >= bmapwidth || by >= bmapheight)
continue;
offset = by*bmapwidth + bx;
// haleyjd 02/22/06: consider polyobject lines
plink = polyblocklinks[offset];
while (plink)
{
polyobj_t *po = plink->po;
if (po->validcount != validcount) // if polyobj hasn't been checked
{
po->validcount = validcount;
if (!P_MobjInsidePolyobj(po, thing) || !(po->flags & POF_RENDERPLANES))
{
plink = (polymaplink_t *)(plink->link.next);
continue;
}
// We're inside it! Yess...
z = po->lines[0]->backsector->ceilingheight;
if (z < halfHeight && z > groundz)
{
groundz = z;
groundslope = NULL;
}
}
plink = (polymaplink_t *)(plink->link.next);
}
}
}
#endif
if (shadowslope != NULL)
*shadowslope = groundslope;
@ -1303,12 +1259,26 @@ fixed_t R_GetShadowZ(
static void R_SkewShadowSprite(
mobj_t *thing, pslope_t *groundslope,
fixed_t groundz, INT32 spriteheight, fixed_t scalemul,
fixed_t *shadowyscale, fixed_t *shadowskew,
fixed_t interpx, fixed_t interpy)
fixed_t *shadowyscale, fixed_t *shadowskew)
{
// haha let's try some dumb stuff
fixed_t xslope, zslope;
angle_t sloperelang = (R_PointToAngle(interpx, interpy) - groundslope->xydirection) >> ANGLETOFINESHIFT;
angle_t sloperelang;
// for frame interpolation
interpmobjstate_t interp = {0};
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(thing, rendertimefrac, &interp);
}
else
{
R_InterpolateMobjState(thing, FRACUNIT, &interp);
}
sloperelang = (R_PointToAngle(interp.x, interp.y) - groundslope->xydirection) >> ANGLETOFINESHIFT;
xslope = FixedMul(FINESINE(sloperelang), groundslope->zdelta);
zslope = FixedMul(FINECOSINE(sloperelang), groundslope->zdelta);
@ -1326,8 +1296,7 @@ static void R_SkewShadowSprite(
static void R_ProjectDropShadow(
mobj_t *thing, vissprite_t *vis,
fixed_t scale, fixed_t tx, fixed_t tz,
fixed_t interpx, fixed_t interpy, fixed_t interpz)
fixed_t scale, fixed_t tx, fixed_t tz)
{
vissprite_t *shadow;
patch_t *patch;
@ -1335,11 +1304,21 @@ static void R_ProjectDropShadow(
INT32 light = 0;
fixed_t groundz;
pslope_t *groundslope;
interpmobjstate_t interp = {0};
groundz = R_GetShadowZ(thing, &groundslope, interpx, interpy, interpz);
groundz = R_GetShadowZ(thing, &groundslope);
if (abs(groundz-viewz)/tz > 4) return; // Prevent stretchy shadows and possible crashes
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(thing, rendertimefrac, &interp);
}
else
{
R_InterpolateMobjState(thing, FRACUNIT, &interp);
}
patch = W_CachePatchName("DSHADOW", PU_SPRITE);
xscale = FixedDiv(projection[viewssnum], tz);
yscale = FixedDiv(projectiony[viewssnum], tz);
@ -1355,8 +1334,7 @@ static void R_ProjectDropShadow(
thing,
groundslope, groundz,
patch->height, FRACUNIT,
&shadowyscale, &shadowskew,
interpx, interpy);
&shadowyscale, &shadowskew);
}
tx -= patch->width * shadowxscale/2;
@ -1376,11 +1354,11 @@ static void R_ProjectDropShadow(
shadow->mobjflags = 0;
shadow->sortscale = vis->sortscale;
shadow->dispoffset = vis->dispoffset - 5;
shadow->gx = interpx;
shadow->gy = interpy;
shadow->gx = interp.x;
shadow->gy = interp.y;
shadow->gzt = groundz + patch->height * shadowyscale / 2;
shadow->gz = shadow->gzt - patch->height * shadowyscale;
shadow->texturemid = FixedMul(thing->scale, FixedDiv(shadow->gzt - viewz, shadowyscale));
shadow->texturemid = FixedMul(interp.scale, FixedDiv(shadow->gzt - viewz, shadowyscale));
if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
shadow->texturemid = FixedMul(shadow->texturemid, ((skin_t *)thing->skin)->highresscale);
shadow->scalestep = 0;
@ -1393,7 +1371,7 @@ static void R_ProjectDropShadow(
shadow->xscale = FixedMul(xscale, shadowxscale); //SoM: 4/17/2000
shadow->scale = FixedMul(yscale, shadowyscale);
shadow->thingscale = thing->scale;
shadow->thingscale = interp.scale;
shadow->sector = vis->sector;
shadow->szt = (INT16)((centeryfrac - FixedMul(shadow->gzt - viewz, yscale))>>FRACBITS);
shadow->sz = (INT16)((centeryfrac - FixedMul(shadow->gz - viewz, yscale))>>FRACBITS);
@ -1421,7 +1399,7 @@ static void R_ProjectDropShadow(
// R_GetPlaneLight won't work on sloped lights!
for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) {
fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y);
fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], interp.x, interp.y);
if (h <= shadow->gzt) {
light = lightnum - 1;
break;
@ -1501,7 +1479,7 @@ static void R_ProjectSprite(mobj_t *thing)
fixed_t gz = 0, gzt = 0;
INT32 heightsec, phs;
INT32 light = 0;
fixed_t this_scale = thing->scale;
fixed_t this_scale;
fixed_t spritexscale, spriteyscale;
// rotsprite
@ -1515,20 +1493,20 @@ static void R_ProjectSprite(mobj_t *thing)
#endif
// uncapped/interpolation
fixed_t interpx = R_InterpolateFixed(thing->old_x, thing->x);
fixed_t interpy = R_InterpolateFixed(thing->old_y, thing->y);
fixed_t interpz = R_InterpolateFixed(thing->old_z, thing->z);
angle_t interpangle = ANGLE_MAX;
interpmobjstate_t interp = {0};
if (thing->player)
// do interpolation
if (R_UsingFrameInterpolation() && !paused)
{
interpangle = R_InterpolateAngle(thing->player->old_drawangle, thing->player->drawangle);
R_InterpolateMobjState(oldthing, rendertimefrac, &interp);
}
else
{
interpangle = R_InterpolateAngle(thing->old_angle, thing->angle);
R_InterpolateMobjState(oldthing, FRACUNIT, &interp);
}
this_scale = interp.scale;
// hitlag vibrating (todo: interp somehow?)
if (thing->hitlag > 0 && (thing->eflags & MFE_DAMAGEHITLAG))
{
@ -1539,19 +1517,19 @@ static void R_ProjectSprite(mobj_t *thing)
mul = -mul;
}
interpx += FixedMul(thing->momx, mul);
interpy += FixedMul(thing->momy, mul);
interpz += FixedMul(thing->momz, mul);
interp.x += FixedMul(thing->momx, mul);
interp.y += FixedMul(thing->momy, mul);
interp.z += FixedMul(thing->momz, mul);
}
// sprite offset
interpx += thing->sprxoff;
interpy += thing->spryoff;
interpz += thing->sprzoff;
interp.x += thing->sprxoff;
interp.y += thing->spryoff;
interp.z += thing->sprzoff;
// transform the origin point
tr_x = interpx - viewx;
tr_y = interpy - viewy;
tr_x = interp.x - viewx;
tr_y = interp.y - viewy;
basetz = tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance
@ -1628,7 +1606,7 @@ static void R_ProjectSprite(mobj_t *thing)
if (sprframe->rotate != SRF_SINGLE || papersprite)
{
ang = R_PointToAngle (interpx, interpy) - interpangle;
ang = R_PointToAngle (interp.x, interp.y) - interp.angle;
if (mirrored)
ang = InvAngle(ang);
}
@ -1643,7 +1621,7 @@ static void R_ProjectSprite(mobj_t *thing)
else
{
// choose a different rotation based on player view
//ang = R_PointToAngle (interpx, interpy) - interpangle;
//ang = R_PointToAngle (interp.x, interp.y) - interpangle;
if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right
rot = 6; // F7 slot
@ -1706,15 +1684,15 @@ static void R_ProjectSprite(mobj_t *thing)
flip = !flip != !hflip;
// calculate edges of the shape
spritexscale = thing->spritexscale;
spriteyscale = thing->spriteyscale;
spritexscale = interp.spritexscale;
spriteyscale = interp.spriteyscale;
if (spritexscale < 1 || spriteyscale < 1)
return;
if (thing->renderflags & RF_ABSOLUTEOFFSETS)
{
spr_offset = thing->spritexoffset;
spr_topoffset = thing->spriteyoffset;
spr_offset = interp.spritexoffset;
spr_topoffset = interp.spriteyoffset;
}
else
{
@ -1723,8 +1701,8 @@ static void R_ProjectSprite(mobj_t *thing)
if ((thing->renderflags & RF_FLIPOFFSETS) && flip)
flipoffset = -1;
spr_offset += thing->spritexoffset * flipoffset;
spr_topoffset += thing->spriteyoffset * flipoffset;
spr_offset += interp.spritexoffset * flipoffset;
spr_topoffset += interp.spriteyoffset * flipoffset;
}
if (flip)
@ -1746,8 +1724,8 @@ static void R_ProjectSprite(mobj_t *thing)
offset2 *= -1;
}
cosmul = FINECOSINE(thing->angle>>ANGLETOFINESHIFT);
sinmul = FINESINE(thing->angle>>ANGLETOFINESHIFT);
cosmul = FINECOSINE(interp.angle >> ANGLETOFINESHIFT);
sinmul = FINESINE(interp.angle >> ANGLETOFINESHIFT);
tr_x += FixedMul(offset, cosmul);
tr_y += FixedMul(offset, sinmul);
@ -1763,7 +1741,7 @@ static void R_ProjectSprite(mobj_t *thing)
paperoffset = -paperoffset;
paperdistance = -paperdistance;
}
centerangle = viewangle - thing->angle;
centerangle = viewangle - interp.angle;
tr_x += FixedMul(offset2, cosmul);
tr_y += FixedMul(offset2, sinmul);
@ -1855,13 +1833,19 @@ static void R_ProjectSprite(mobj_t *thing)
if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY)
{
interpmobjstate_t tracer_interp = {0};
fixed_t linkscale;
thing = thing->tracer;
interpx = R_InterpolateFixed(thing->old_x, thing->x);
interpy = R_InterpolateFixed(thing->old_y, thing->y);
interpz = R_InterpolateFixed(thing->old_z, thing->z);
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(thing, rendertimefrac, &tracer_interp);
}
else
{
R_InterpolateMobjState(thing, FRACUNIT, &tracer_interp);
}
// hitlag vibrating (todo: interp somehow?)
if (thing->hitlag > 0 && (thing->eflags & MFE_DAMAGEHITLAG))
@ -1873,21 +1857,21 @@ static void R_ProjectSprite(mobj_t *thing)
mul = -mul;
}
interpx += FixedMul(thing->momx, mul);
interpy += FixedMul(thing->momy, mul);
interpz += FixedMul(thing->momz, mul);
tracer_interp.x += FixedMul(thing->momx, mul);
tracer_interp.y += FixedMul(thing->momy, mul);
tracer_interp.z += FixedMul(thing->momz, mul);
}
// sprite offset
interpx += thing->sprxoff;
interpy += thing->spryoff;
interpz += thing->sprzoff;
tracer_interp.x += thing->sprxoff;
tracer_interp.y += thing->spryoff;
tracer_interp.z += thing->sprzoff;
if (! R_ThingVisible(thing))
return;
tr_x = (interpx + sort_x) - viewx;
tr_y = (interpy + sort_y) - viewy;
tr_x = (tracer_interp.x + sort_x) - viewx;
tr_y = (tracer_interp.y + sort_y) - viewy;
tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin);
linkscale = FixedDiv(projectiony[viewssnum], tz);
@ -1902,8 +1886,8 @@ static void R_ProjectSprite(mobj_t *thing)
}
else if (splat)
{
tr_x = (interpx + sort_x) - viewx;
tr_y = (interpy + sort_y) - viewy;
tr_x = (interp.x + sort_x) - viewx;
tr_y = (interp.y + sort_y) - viewy;
sort_z = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin);
sortscale = FixedDiv(projectiony[viewssnum], sort_z);
}
@ -1911,8 +1895,8 @@ static void R_ProjectSprite(mobj_t *thing)
// Calculate the splat's sortscale
if (splat)
{
tr_x = (thing->x - sort_x) - viewx;
tr_y = (thing->y - sort_y) - viewy;
tr_x = (interp.x - sort_x) - viewx;
tr_y = (interp.y - sort_y) - viewy;
sort_z = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin);
sortsplat = FixedDiv(projectiony[viewssnum], sort_z);
}
@ -1923,7 +1907,7 @@ static void R_ProjectSprite(mobj_t *thing)
if (x2 < portalclipstart || x1 >= portalclipend)
return;
if (P_PointOnLineSide(interpx, interpy, portalclipline) != 0)
if (P_PointOnLineSide(interp.x, interp.y, portalclipline) != 0)
return;
}
@ -1951,7 +1935,7 @@ static void R_ProjectSprite(mobj_t *thing)
if (shadowdraw || shadoweffects)
{
fixed_t groundz = R_GetShadowZ(thing, NULL, interpx, interpy, interpz);
fixed_t groundz = R_GetShadowZ(thing, NULL);
boolean isflipped = (thing->eflags & MFE_VERTICALFLIP);
if (shadoweffects)
@ -1975,9 +1959,9 @@ static void R_ProjectSprite(mobj_t *thing)
if (shadowskew)
{
R_SkewShadowSprite(thing, thing->standingslope, groundz, patch->height, shadowscale, &spriteyscale, &sheartan, interpx, interpy);
R_SkewShadowSprite(thing, thing->standingslope, groundz, patch->height, shadowscale, &spriteyscale, &sheartan);
gzt = (isflipped ? (thing->z + thing->height) : thing->z) + patch->height * spriteyscale / 2;
gzt = (isflipped ? (interp.z + thing->height) : interp.z) + patch->height * spriteyscale / 2;
gz = gzt - patch->height * spriteyscale;
cut |= SC_SHEAR;
@ -1992,12 +1976,12 @@ static void R_ProjectSprite(mobj_t *thing)
// When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned.
// sprite height - sprite topoffset is the proper inverse of the vertical offset, of course.
// remember gz and gzt should be seperated by sprite height, not thing height - thing height can be shorter than the sprite itself sometimes!
gz = interpz + oldthing->height - FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale));
gz = interp.z + oldthing->height - FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale));
gzt = gz + FixedMul(spr_height, FixedMul(spriteyscale, this_scale));
}
else
{
gzt = interpz + FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale));
gzt = interp.z + FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale));
gz = gzt - FixedMul(spr_height, FixedMul(spriteyscale, this_scale));
}
}
@ -2016,7 +2000,7 @@ static void R_ProjectSprite(mobj_t *thing)
// R_GetPlaneLight won't work on sloped lights!
for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) {
fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], interpx, interpy);
fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], interp.x, interp.y);
if (h <= top) {
light = lightnum - 1;
break;
@ -2042,12 +2026,12 @@ static void R_ProjectSprite(mobj_t *thing)
if (heightsec != -1 && phs != -1) // only clip things which are in special sectors
{
if (viewz < sectors[phs].floorheight ?
interpz >= sectors[heightsec].floorheight :
interp.z >= sectors[heightsec].floorheight :
gzt < sectors[heightsec].floorheight)
return;
if (viewz > sectors[phs].ceilingheight ?
gzt < sectors[heightsec].ceilingheight && viewz >= sectors[heightsec].ceilingheight :
interpz >= sectors[heightsec].ceilingheight)
interp.z >= sectors[heightsec].ceilingheight)
return;
}
@ -2060,12 +2044,12 @@ static void R_ProjectSprite(mobj_t *thing)
vis->sortscale = sortscale;
vis->sortsplat = sortsplat;
vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15
vis->gx = interpx;
vis->gy = interpy;
vis->gx = interp.x;
vis->gy = interp.y;
vis->gz = gz;
vis->gzt = gzt;
vis->thingheight = thing->height;
vis->pz = interpz;
vis->pz = interp.z;
vis->pzt = vis->pz + vis->thingheight;
vis->texturemid = FixedDiv(gzt - viewz, spriteyscale);
vis->scalestep = scalestep;
@ -2096,7 +2080,7 @@ static void R_ProjectSprite(mobj_t *thing)
vis->xscale = FixedMul(spritexscale, xscale); //SoM: 4/17/2000
vis->scale = FixedMul(spriteyscale, yscale); //<<detailshift;
vis->thingscale = oldthing->scale;
vis->thingscale = interp.scale;
vis->spritexscale = spritexscale;
vis->spriteyscale = spriteyscale;
@ -2178,8 +2162,7 @@ static void R_ProjectSprite(mobj_t *thing)
if (oldthing->shadowscale && cv_shadow.value)
{
R_ProjectDropShadow(oldthing, vis, oldthing->shadowscale, basetx, basetz,
interpx, interpy, interpz);
R_ProjectDropShadow(oldthing, vis, oldthing->shadowscale, basetx, basetz);
}
// Debug
@ -2206,13 +2189,21 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
fixed_t gz, gzt;
// uncapped/interpolation
fixed_t interpx = R_InterpolateFixed(thing->old_x, thing->x);
fixed_t interpy = R_InterpolateFixed(thing->old_y, thing->y);
fixed_t interpz = R_InterpolateFixed(thing->old_z, thing->z);
interpmobjstate_t interp = {0};
// do interpolation
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolatePrecipMobjState(thing, rendertimefrac, &interp);
}
else
{
R_InterpolatePrecipMobjState(thing, FRACUNIT, &interp);
}
// transform the origin point
tr_x = interpx - viewx;
tr_y = interpy - viewy;
tr_x = interp.x - viewx;
tr_y = interp.y - viewy;
tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance
@ -2276,12 +2267,12 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
if (x2 < portalclipstart || x1 >= portalclipend)
return;
if (P_PointOnLineSide(interpx, interpy, portalclipline) != 0)
if (P_PointOnLineSide(interp.x, interp.y, portalclipline) != 0)
return;
}
//SoM: 3/17/2000: Disregard sprites that are out of view..
gzt = interpz + spritecachedinfo[lump].topoffset;
gzt = interp.z + spritecachedinfo[lump].topoffset;
gz = gzt - spritecachedinfo[lump].height;
if (thing->subsector->sector->cullheight)
@ -2294,12 +2285,12 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
vis = R_NewVisSprite();
vis->scale = vis->sortscale = yscale; //<<detailshift;
vis->dispoffset = 0; // Monster Iestyn: 23/11/15
vis->gx = interpx;
vis->gy = interpy;
vis->gx = interp.x;
vis->gy = interp.y;
vis->gz = gz;
vis->gzt = gzt;
vis->thingheight = 4*FRACUNIT;
vis->pz = interpz;
vis->pz = interp.z;
vis->pzt = vis->pz + vis->thingheight;
vis->texturemid = vis->gzt - viewz;
vis->scalestep = 0;

View file

@ -59,7 +59,7 @@ void R_DrawFlippedMaskedColumn(column_t *column, column_t *brightmap);
extern INT16 negonearray[MAXVIDWIDTH];
extern INT16 screenheightarray[MAXVIDWIDTH];
fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope, fixed_t interpx, fixed_t interpy, fixed_t interpz);
fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope);
//SoM: 6/5/2000: Light sprites correctly!
void R_AddSprites(sector_t *sec, INT32 lightlevel);

View file

@ -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"
@ -518,55 +519,69 @@ boolean SCR_IsAspectCorrect(INT32 width, INT32 height)
double averageFPS = 0.0f;
#define FPS_SAMPLE_RATE (50000) // How often to update FPS samples, in microseconds
#define NUM_FPS_SAMPLES 16 // Number of samples to store
#define USE_FPS_SAMPLES
#ifdef USE_FPS_SAMPLES
#define FPS_SAMPLE_RATE (0.05) // How often to update FPS samples, in seconds
#define NUM_FPS_SAMPLES (16) // Number of samples to store
static double fps_samples[NUM_FPS_SAMPLES];
static double updateElapsed = 0.0;
#endif
static boolean fps_init = false;
static precise_t fps_enter = 0;
void SCR_CalculateFPS(void)
{
static boolean init = false;
precise_t fps_finish = 0;
static precise_t startTime = 0;
precise_t endTime = 0;
double frameElapsed = 0.0;
static precise_t updateTime = 0;
int updateElapsed = 0;
int i;
endTime = I_GetPreciseTime();
if (init == false)
if (fps_init == false)
{
startTime = updateTime = endTime;
init = true;
return;
fps_enter = I_GetPreciseTime();
fps_init = true;
}
updateElapsed = I_PreciseToMicros(endTime - updateTime);
fps_finish = I_GetPreciseTime();
frameElapsed = (double)((INT64)(fps_finish - fps_enter)) / I_GetPrecisePrecision();
fps_enter = fps_finish;
#ifdef USE_FPS_SAMPLES
updateElapsed += frameElapsed;
if (updateElapsed >= FPS_SAMPLE_RATE)
{
static int sampleIndex = 0;
int frameElapsed = I_PreciseToMicros(endTime - startTime);
int i;
fps_samples[sampleIndex] = frameElapsed / 1000.0f;
fps_samples[sampleIndex] = frameElapsed;
sampleIndex++;
if (sampleIndex >= NUM_FPS_SAMPLES)
sampleIndex = 0;
averageFPS = 0.0f;
averageFPS = 0.0;
for (i = 0; i < NUM_FPS_SAMPLES; i++)
{
averageFPS += fps_samples[i];
}
averageFPS = 1000.0f / (averageFPS / NUM_FPS_SAMPLES);
updateTime = endTime;
if (averageFPS > 0.0)
{
averageFPS = 1.0 / (averageFPS / NUM_FPS_SAMPLES);
}
}
startTime = endTime;
while (updateElapsed >= FPS_SAMPLE_RATE)
{
updateElapsed -= FPS_SAMPLE_RATE;
}
#else
// Direct, unsampled counter.
averageFPS = 1.0 / frameElapsed;
#endif
}
void SCR_DisplayTicRate(void)
@ -575,14 +590,14 @@ void SCR_DisplayTicRate(void)
UINT32 cap = R_GetFramerateCap();
UINT32 benchmark = (cap == 0) ? I_GetRefreshRate() : cap;
INT32 x = 318;
double fps = ceil(averageFPS);
double fps = round(averageFPS);
// draw "FPS"
V_DrawFixedPatch(306<<FRACBITS, 183<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, framecounter, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE));
V_DrawFixedPatch(306<<FRACBITS, 183<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT, framecounter, R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_YELLOW, GTC_CACHE));
if (fps > (benchmark - 5))
if (fps > (benchmark * 0.9))
ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MINT, GTC_CACHE);
else if (fps < 20)
else if (fps < (benchmark * 0.5))
ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE);
if (cap != 0)
@ -597,15 +612,15 @@ void SCR_DisplayTicRate(void)
}
// draw total frame:
V_DrawPingNum(x, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, cap, ticcntcolor);
V_DrawPingNum(x, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT, cap, ticcntcolor);
x -= digits * 4;
// draw "/"
V_DrawFixedPatch(x<<FRACBITS, 190<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, frameslash, ticcntcolor);
V_DrawFixedPatch(x<<FRACBITS, 190<<FRACBITS, FRACUNIT, V_SNAPTOBOTTOM|V_SNAPTORIGHT, frameslash, ticcntcolor);
}
// draw our actual framerate
V_DrawPingNum(x, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS, fps, ticcntcolor);
V_DrawPingNum(x, 190, V_SNAPTOBOTTOM|V_SNAPTORIGHT, fps, ticcntcolor);
}
// SCR_DisplayLocalPing

View file

@ -206,6 +206,7 @@ extern consvar_t cv_vhseffect, cv_shittyscreen;
// wait for page flipping to end or not
extern consvar_t cv_vidwait;
extern consvar_t cv_timescale;
// Initialize the screen
void SCR_Startup(void);

View file

@ -165,6 +165,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"
@ -1551,115 +1552,78 @@ ticcmd_t *I_BaseTiccmd4(void)
static Uint64 timer_frequency;
static double tic_frequency;
static Uint64 tic_epoch;
static double elapsed_tics;
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)
{
double f = 0.0;
UpdateElapsedTics();
f = floor(elapsed_tics);
return (tic_t)f;
}
float I_GetTimeFrac(void)
{
UpdateElapsedTics();
return elapsed_tics;
}
precise_t I_GetPreciseTime(void)
{
return SDL_GetPerformanceCounter();
}
int I_PreciseToMicros(precise_t d)
UINT64 I_GetPrecisePrecision(void)
{
// d is going to be converted into a double. So remove the highest bits
// to avoid loss of precision in the lower bits, for the (probably rare) case
// that the higher bits are actually used.
d &= ((precise_t)1 << 53) - 1; // The mantissa of a double can handle 53 bits at most.
// The resulting double from the calculation is converted first to UINT64 to avoid overflow,
// which is undefined behaviour when converting floating point values to integers.
return (int)(UINT64)(d / (timer_frequency / 1000000.0));
return SDL_GetPerformanceFrequency();
}
static UINT32 frame_rate;
static double frame_frequency;
static UINT64 frame_epoch;
static double elapsed_frames;
static void I_InitFrameTime(const UINT64 now, const UINT32 cap)
{
frame_rate = cap;
frame_epoch = now;
//elapsed_frames = 0.0;
if (frame_rate == 0)
{
// Shouldn't be used, but just in case...?
frame_frequency = 1.0;
return;
}
frame_frequency = timer_frequency / (double)frame_rate;
}
double I_GetFrameTime(void)
{
const UINT64 now = SDL_GetPerformanceCounter();
const UINT32 cap = R_GetFramerateCap();
if (cap != frame_rate)
{
// Maybe do this in a OnChange function for cv_fpscap?
I_InitFrameTime(now, cap);
}
if (frame_rate == 0)
{
// Always advance a frame.
elapsed_frames += 1.0;
}
else
{
elapsed_frames += (now - frame_epoch) / frame_frequency;
}
frame_epoch = now; // moving epoch
return elapsed_frames;
}
//
//I_StartupTimer
// I_StartupTimer
//
void I_StartupTimer(void)
{
timer_frequency = SDL_GetPerformanceFrequency();
tic_epoch = SDL_GetPerformanceCounter();
tic_frequency = timer_frequency / (double)NEWTICRATE;
elapsed_tics = 0.0;
I_InitFrameTime(0, R_GetFramerateCap());
elapsed_frames = 0.0;
}
void I_Sleep(void)
void I_Sleep(UINT32 ms)
{
if (cv_sleep.value > 0)
SDL_Delay(cv_sleep.value);
}
boolean I_CheckFrameCap(precise_t start, precise_t end)
{
UINT32 capFrames = R_GetFramerateCap();
int capMicros = 0;
int elapsed;
if (capFrames == 0)
{
// We don't want to cap.
return false;
}
elapsed = I_PreciseToMicros(end - start);
capMicros = 1000000 / capFrames;
if (elapsed < capMicros)
{
// Wait to draw the next frame.
UINT32 wait = ((capMicros - elapsed) / 1000);
if (cv_sleep.value > 1)
{
// 1 is the default, and in non-interpolated mode is just the bare minimum wait.
// Since we're already adding some wait with an FPS cap, only apply when it's above 1.
wait += cv_sleep.value - 1;
}
// If the wait's greater than our granularity value,
// we'll just burn the couple extra cycles in the main loop
// in order to get to the next frame.
// This makes us get to the exact FPS cap more often.
// Higher values have more wasted CPU cycles, but the in-game frame performance is better.
// 10ms is the average clock tick of most OS scheduling.
// 15ms is a little more than that, for leniency on slow machines. (This helps mine reach a stable 60, at least!)
// (https://www.libsdl.org/release/SDL-1.2.15/docs/html/sdldelay.html)
#define DELAY_GRANULARITY 15
if (wait >= DELAY_GRANULARITY)
{
SDL_Delay(wait);
}
#undef DELAY_GRANULARITY
return true;
}
// Waited enough to draw again.
return false;
SDL_Delay(ms);
}
#ifdef NEWSIGNALHANDLER

View file

@ -1232,7 +1232,7 @@ void I_FinishUpdate(void)
if (rendermode == render_none)
return; //Alam: No software or OpenGl surface
//SCR_CalculateFPS(); // Moved to main loop
SCR_CalculateFPS();
if (I_SkipFrame())
return;
@ -1649,6 +1649,27 @@ boolean VID_CheckRenderer(void)
return rendererchanged;
}
static UINT32 refresh_rate;
static UINT32 VID_GetRefreshRate(void)
{
int index = SDL_GetWindowDisplayIndex(window);
SDL_DisplayMode m;
if (SDL_WasInit(SDL_INIT_VIDEO) == 0)
{
// Video not init yet.
return 0;
}
if (SDL_GetCurrentDisplayMode(index, &m) != 0)
{
// Error has occurred.
return 0;
}
return m.refresh_rate;
}
INT32 VID_SetMode(INT32 modeNum)
{
SDLdoUngrabMouse();
@ -1668,6 +1689,8 @@ INT32 VID_SetMode(INT32 modeNum)
src_rect.w = vid.width;
src_rect.h = vid.height;
refresh_rate = VID_GetRefreshRate();
//Impl_SetWindowName("Dr. Robotnik's Ring Racers "VERSIONSTRING);
VID_CheckRenderer();
return SDL_TRUE;
@ -2013,20 +2036,10 @@ void I_ShutdownGraphics(void)
UINT32 I_GetRefreshRate(void)
{
int index = SDL_GetWindowDisplayIndex(window);
SDL_DisplayMode m;
if (SDL_WasInit(SDL_INIT_VIDEO) == 0)
{
// Video not init yet.
return 0;
}
if (SDL_GetDesktopDisplayMode(index, &m) != 0)
{
// Error has occurred.
return 0;
}
return m.refresh_rate;
// Moved to VID_GetRefreshRate.
// Precalculating it like that won't work as
// well for windowed mode since you can drag
// the window around, but very slow PCs might have
// trouble querying mode over and over again.
return refresh_rate;
}

View file

@ -44,6 +44,7 @@
#include "hardware/hw_main.h"
#endif
#include "lua_hudlib_drawlist.h"
#include "lua_hud.h"
// SRB2Kart
@ -51,6 +52,8 @@
#include "v_video.h"
#include "r_skins.h" // NUMFACES
#include "r_fps.h"
UINT16 objectsdrawn = 0;
//
@ -72,6 +75,9 @@ static patch_t *hud_tv2;
static patch_t *envelope;
#endif
static huddrawlist_h luahuddrawlist_game;
static huddrawlist_h luahuddrawlist_titlecard;
//
// STATUS BAR CODE
//
@ -242,6 +248,9 @@ void ST_Init(void)
return;
ST_LoadGraphics();
luahuddrawlist_game = LUA_HUD_CreateDrawList();
luahuddrawlist_titlecard = LUA_HUD_CreateDrawList();
}
// change the status bar too, when pressing F12 while viewing a demo.
@ -949,8 +958,12 @@ void ST_drawTitleCard(void)
lt_lasttic = lt_ticker;
luahook:
LUAh_TitleCardHUD(stplyr);
if (renderisnewtic)
{
LUA_HUD_ClearDrawList(luahuddrawlist_titlecard);
LUAh_TitleCardHUD(stplyr, luahuddrawlist_titlecard);
}
LUA_HUD_DrawList(luahuddrawlist_titlecard);
}
// Clear defined coordinates, we don't need them anymore
@ -1019,7 +1032,14 @@ static void ST_overlayDrawer(void)
}
if (!(netgame || multiplayer) || !hu_showscores)
LUAh_GameHUD(stplyr);
{
if (renderisnewtic)
{
LUA_HUD_ClearDrawList(luahuddrawlist_game);
LUAh_GameHUD(stplyr, luahuddrawlist_game);
}
LUA_HUD_DrawList(luahuddrawlist_game);
}
if (!hu_showscores && netgame && !mapreset)
{

View file

@ -60,6 +60,7 @@
#include "r_textures.h"
#include "r_patch.h"
#include "r_picformats.h"
#include "i_time.h"
#include "i_system.h"
#include "md5.h"
#include "lua_script.h"

View file

@ -35,6 +35,7 @@
#include <mmsystem.h>
#include "../m_misc.h"
#include "../i_time.h"
#include "../i_video.h"
#include "../i_sound.h"
#include "../i_system.h"
@ -262,15 +263,25 @@ tic_t I_GetTime(void)
return newtics;
}
fixed_t I_GetTimeFrac(void)
precise_t I_GetPreciseTime(void)
{
return 0;
LARGE_INTEGER time;
BOOL res = QueryPerformanceCounter(&time);
if (!res) I_Error("QueryPerformanceCounter error"); // if this happens, you've gone back to the 90s
return (precise_t) time.QuadPart;
}
void I_Sleep(void)
UINT64 I_GetPrecisePrecision(void)
{
if (cv_sleep.value > 0)
Sleep(cv_sleep.value);
LARGE_INTEGER time;
BOOL res = QueryPerformanceFrequency(&time);
if (!res) I_Error("QueryPerformanceFrequency error"); // if this happens, you've gone back to the 90s
return (precise_t) time.QuadPart;
}
void I_Sleep(UINT32 ms)
{
Sleep(ms);
}
// should move to i_video

View file

@ -38,6 +38,7 @@
#include "lua_hook.h" // IntermissionThinker hook
#include "lua_hud.h"
#include "lua_hudlib_drawlist.h"
#include "m_random.h" // M_RandomKey
#include "g_input.h" // G_PlayerInputDown
@ -98,6 +99,8 @@ static INT32 sorttic = -1;
intertype_t intertype = int_none;
intertype_t intermissiontypes[NUMGAMETYPES];
static huddrawlist_h luahuddrawlist_intermission;
static void Y_FollowIntermission(void);
static void Y_UnloadData(void);
@ -345,7 +348,13 @@ void Y_IntermissionDrawer(void)
M_DrawMenuBackground();
}
LUAh_IntermissionHUD();
if (renderisnewtic)
{
LUA_HUD_ClearDrawList(luahuddrawlist_intermission);
LUAh_IntermissionHUD(luahuddrawlist_intermission);
}
LUA_HUD_DrawList(luahuddrawlist_intermission);
if (!LUA_HudEnabled(hud_intermissiontally))
goto skiptallydrawer;
@ -1013,6 +1022,9 @@ void Y_StartIntermission(void)
break;
}
LUA_HUD_DestroyDrawList(luahuddrawlist_intermission);
luahuddrawlist_intermission = LUA_HUD_CreateDrawList();
if (powertype != PWRLV_DISABLED)
{
K_UpdatePowerLevels();