0
0
Fork 0
mirror of https://git.do.srb2.org/STJr/SRB2.git synced 2025-03-23 11:21:01 +00:00

Merge branch 'uncappedrevengeance' into next

Uncapped

See merge request 

# Conflicts:
#	src/dummy/i_system.c
#	src/win32/win_sys.c
This commit is contained in:
Eidolon 2022-11-08 21:13:50 -06:00
commit 12c2ddb115
68 changed files with 3760 additions and 798 deletions

View file

@ -156,7 +156,7 @@ ifdef DEBUGMODE
ifdef GCC48
opts+=-Og
else
opts+=O0
opts+=-O0
endif
endif

View file

@ -18,6 +18,7 @@ am_map.c
command.c
console.c
hu_stuff.c
i_time.c
y_inter.c
st_stuff.c
m_aatree.c
@ -55,6 +56,7 @@ tables.c
r_bsp.c
r_data.c
r_draw.c
r_fps.c
r_main.c
r_plane.c
r_segs.c
@ -95,4 +97,5 @@ lua_taglib.c
lua_polyobjlib.c
lua_blockmaplib.c
lua_hudlib.c
lua_hudlib_drawlist.c
lua_inputlib.c

View file

@ -82,13 +82,17 @@ 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;
}
void I_Sleep(void){}
UINT64 I_GetPrecisePrecision(void)
{
return 1000000;
}
void I_GetEvent(void){}

View file

@ -579,7 +579,7 @@ void B_RespawnBot(INT32 playernum)
player->powers[pw_nocontrol] = sonic->player->powers[pw_nocontrol];
player->pflags |= PF_AUTOBRAKE|(sonic->player->pflags & PF_DIRECTIONCHAR);
P_TeleportMove(tails, x, y, z);
P_SetOrigin(tails, x, y, z);
if (player->charability == CA_FLY)
{
P_SetPlayerMobjState(tails, S_PLAY_FLY);

View file

@ -2076,9 +2076,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"
@ -113,6 +114,9 @@ static INT16 consistancy[BACKUPTICS];
static UINT8 player_joining = false;
UINT8 hu_redownloadinggamestate = 0;
// true when a player is connecting or disconnecting so that the gameplay has stopped in its tracks
boolean hu_stopped = false;
UINT8 adminpassmd5[16];
boolean adminpasswordset = false;
@ -2441,7 +2445,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;
}
@ -5206,8 +5213,10 @@ static void SV_Maketic(void)
maketic++;
}
void TryRunTics(tic_t realtics)
boolean TryRunTics(tic_t realtics)
{
boolean ticking;
// the machine has lagged but it is not so bad
if (realtics > TICRATE/7) // FIXME: consistency failure!!
{
@ -5231,7 +5240,7 @@ void TryRunTics(tic_t realtics)
if (demoplayback)
{
neededtic = gametic + (realtics * cv_playbackspeed.value);
neededtic = gametic + realtics;
// start a game after a demo
maketic += realtics;
firstticstosend = maketic;
@ -5251,10 +5260,22 @@ void TryRunTics(tic_t realtics)
}
#endif
if (player_joining)
return;
ticking = neededtic > gametic;
if (neededtic > gametic)
if (ticking)
{
if (realtics)
hu_stopped = false;
}
if (player_joining)
{
if (realtics)
hu_stopped = true;
return false;
}
if (ticking)
{
if (advancedemo)
{
@ -5290,6 +5311,13 @@ void TryRunTics(tic_t realtics)
break;
}
}
else
{
if (realtics)
hu_stopped = true;
}
return ticking;
}
/*

View file

@ -430,7 +430,7 @@ boolean Playing(void);
void D_QuitNetGame(void);
//? How many ticks to run?
void TryRunTics(tic_t realtic);
boolean TryRunTics(tic_t realtic);
// extra data for lmps
// these functions scare me. they contain magic.
@ -458,4 +458,7 @@ extern UINT8 hu_redownloadinggamestate;
extern UINT8 adminpassmd5[16];
extern boolean adminpasswordset;
extern boolean hu_stopped;
#endif

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"
@ -64,6 +65,7 @@
#include "deh_tables.h" // Dehacked list test
#include "m_cond.h" // condition initialization
#include "fastcmp.h"
#include "r_fps.h" // Frame interpolation/uncapped
#include "keys.h"
#include "filesrch.h" // refreshdirmenu
#include "g_input.h" // tutorial mode control scheming
@ -476,6 +478,7 @@ static void D_Display(void)
if (!automapactive && !dedicated && cv_renderview.value)
{
R_ApplyLevelInterpolators(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT);
PS_START_TIMING(ps_rendercalltime);
if (players[displayplayer].mo || players[displayplayer].playerstate == PST_DEAD)
{
@ -524,6 +527,7 @@ static void D_Display(void)
V_DoPostProcessor(1, postimgtype2, postimgparam2);
}
PS_STOP_TIMING(ps_rendercalltime);
R_RestoreLevelInterpolators();
}
if (lastdraw)
@ -692,9 +696,14 @@ tic_t rendergametic;
void D_SRB2Loop(void)
{
tic_t oldentertics = 0, entertic = 0, realtics = 0, rendertimeout = INFTICS;
tic_t entertic = 0, oldentertics = 0, realtics = 0, rendertimeout = INFTICS;
double deltatics = 0.0;
double deltasecs = 0.0;
static lumpnum_t gstartuplumpnum;
boolean interp = false;
boolean doDisplay = false;
if (dedicated)
server = true;
@ -705,6 +714,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()
@ -745,6 +755,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;
@ -756,7 +779,11 @@ void D_SRB2Loop(void)
realtics = entertic - oldentertics;
oldentertics = entertic;
refreshdirmenu = 0; // not sure where to put this, here as good as any?
if (demoplayback && gamestate == GS_LEVEL)
{
// Nicer place to put this.
realtics = realtics * cv_playbackspeed.value;
}
#ifdef DEBUGFILE
if (!realtics)
@ -764,64 +791,119 @@ void D_SRB2Loop(void)
debugload--;
#endif
if (!realtics && !singletics)
{
I_Sleep();
continue;
}
interp = R_UsingFrameInterpolation() && !dedicated;
doDisplay = false;
#ifdef HW3SOUND
HW3S_BeginFrameUpdate();
#endif
// don't skip more than 10 frames at a time
// (fadein / fadeout cause massive frame skip!)
if (realtics > 8)
realtics = 1;
refreshdirmenu = 0; // not sure where to put this, here as good as any?
// process tics (but maybe not if realtic == 0)
TryRunTics(realtics);
if (lastdraw || singletics || gametic > rendergametic)
if (realtics > 0 || singletics)
{
rendergametic = gametic;
rendertimeout = entertic+TICRATE/17;
// don't skip more than 10 frames at a time
// (fadein / fadeout cause massive frame skip!)
if (realtics > 8)
realtics = 1;
// Update display, next frame, with current state.
D_Display();
// process tics (but maybe not if realtic == 0)
TryRunTics(realtics);
if (moviemode)
M_SaveFrame();
if (takescreenshot) // Only take screenshots after drawing.
M_DoScreenShot();
}
else if (rendertimeout < entertic) // in case the server hang or netsplit
{
// Lagless camera! Yay!
if (gamestate == GS_LEVEL && netgame)
if (lastdraw || singletics || gametic > rendergametic)
{
if (splitscreen && camera2.chase)
P_MoveChaseCamera(&players[secondarydisplayplayer], &camera2, false);
if (camera.chase)
P_MoveChaseCamera(&players[displayplayer], &camera, false);
}
D_Display();
rendergametic = gametic;
rendertimeout = entertic + TICRATE/17;
if (moviemode)
M_SaveFrame();
if (takescreenshot) // Only take screenshots after drawing.
M_DoScreenShot();
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++)
{
if (splitscreen && camera2.chase)
P_MoveChaseCamera(&players[secondarydisplayplayer], &camera2, false);
if (camera.chase)
P_MoveChaseCamera(&players[displayplayer], &camera, false);
}
R_UpdateViewInterpolation();
}
doDisplay = true;
}
renderisnewtic = true;
}
else
{
renderisnewtic = false;
}
// consoleplayer -> displayplayer (hear sounds from viewpoint)
if (interp)
{
// I looked at the possibility of putting in a float drawer for
// perfstats and it's very complicated, so we'll just do this instead...
ps_interp_frac.value.p = (precise_t)((FIXED_TO_FLOAT(g_time.timefrac)) * 1000.0f);
ps_interp_lag.value.p = (precise_t)((deltasecs) * 1000.0f);
renderdeltatics = FLOAT_TO_FIXED(deltatics);
if (!(paused || P_AutoPause()) && deltatics < 1.0 && !hu_stopped)
{
rendertimefrac = g_time.timefrac;
}
else
{
rendertimefrac = FRACUNIT;
}
}
else
{
renderdeltatics = realtics * FRACUNIT;
rendertimefrac = FRACUNIT;
}
if (interp || doDisplay)
{
D_Display();
}
// Only take screenshots after drawing.
if (moviemode)
M_SaveFrame();
if (takescreenshot)
M_DoScreenShot();
// consoleplayer -> displayplayers (hear sounds from viewpoint)
S_UpdateSounds(); // move positional sounds
S_UpdateClosedCaptions();
if (realtics > 0 || singletics)
S_UpdateClosedCaptions();
#ifdef HW3SOUND
HW3S_EndFrameUpdate();
#endif
LUA_Step();
// 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;
}
}
@ -1307,8 +1389,8 @@ void D_SRB2Main(void)
//---------------------------------------------------- READY TIME
// we need to check for dedicated before initialization of some subsystems
CONS_Printf("I_StartupTimer()...\n");
I_StartupTimer();
CONS_Printf("I_InitializeTime()...\n");
I_InitializeTime();
// Make backups of some SOCcable tables.
P_BackupTables();
@ -1583,6 +1665,8 @@ void D_SRB2Main(void)
// as having been modified for the first game.
M_PushSpecialParameters(); // push all "+" parameter at the command buffer
COM_BufExecute(); // ensure the command buffer gets executed before the map starts (+skin)
if (M_CheckParm("-gametype") && M_IsNextParm())
{
// from Command_Map_f

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"
@ -614,7 +615,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"
@ -191,7 +192,7 @@ static CV_PossibleValue_t joyport_cons_t[] = {{1, "/dev/js0"}, {2, "/dev/js1"},
static CV_PossibleValue_t teamscramble_cons_t[] = {{0, "Off"}, {1, "Random"}, {2, "Points"}, {0, NULL}};
static CV_PossibleValue_t startingliveslimit_cons_t[] = {{1, "MIN"}, {99, "MAX"}, {0, NULL}};
static CV_PossibleValue_t sleeping_cons_t[] = {{-1, "MIN"}, {1000/TICRATE, "MAX"}, {0, NULL}};
static CV_PossibleValue_t sleeping_cons_t[] = {{0, "MIN"}, {1000/TICRATE, "MAX"}, {0, NULL}};
static CV_PossibleValue_t competitionboxes_cons_t[] = {{0, "Normal"}, {1, "Mystery"}, //{2, "Teleport"},
{3, "None"}, {0, NULL}};

View file

@ -35,6 +35,7 @@
#include "doomstat.h"
#include "d_main.h"
#include "g_game.h"
#include "i_time.h"
#include "i_net.h"
#include "i_system.h"
#include "m_argv.h"

View file

@ -383,6 +383,8 @@ typedef struct player_s
// fun thing for player sprite
angle_t drawangle;
angle_t old_drawangle;
angle_t old_drawangle2;
// player's ring count
INT16 rings;

View file

@ -14,24 +14,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;
}
precise_t I_GetPreciseTime(void)
{
return 0;
UINT64 I_GetPrecisePrecision(void) {
return 1000000;
}
int I_PreciseToMicros(precise_t d)
{
(void)d;
return 0;
}
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"
@ -62,8 +63,6 @@ static tic_t stoptimer;
static boolean keypressed = false;
// (no longer) De-Demo'd Title Screen
static tic_t xscrolltimer;
static tic_t yscrolltimer;
static INT32 menuanimtimer; // Title screen: background animation timing
mobj_t *titlemapcameraref = NULL;
@ -229,6 +228,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.
@ -517,9 +518,9 @@ void F_StartIntro(void)
}
//
// F_IntroDrawScene
// F_IntroDrawer
//
static void F_IntroDrawScene(void)
void F_IntroDrawer(void)
{
boolean highres = true;
INT32 cx = 8, cy = 128;
@ -625,24 +626,22 @@ static void F_IntroDrawScene(void)
if (intro_curtime > 1 && intro_curtime < (INT32)introscenetime[intro_scenenum])
{
V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
if (intro_curtime < TICRATE-5) // Make the text shine!
{
sprintf(stjrintro, "STJRI%03u", intro_curtime-1);
}
else if (intro_curtime >= TICRATE-6 && intro_curtime < 2*TICRATE-20) // Pause on black screen for just a second
{
return;
}
else if (intro_curtime == 2*TICRATE-19)
{
// Fade in the text
// The text fade out is automatically handled when switching to a new intro scene
strncpy(stjrintro, "STJRI029", 9);
S_ChangeMusicInternal("_stjr", false);
background = W_CachePatchName(stjrintro, PU_PATCH_LOWPRIORITY);
wipestyleflags = WSF_FADEIN;
F_WipeStartScreen();
F_TryColormapFade(31);
V_DrawSmallScaledPatch(bgxoffs, 84, 0, background);
F_WipeEndScreen();
F_RunWipe(0,true);
}
if (!WipeInAction) // Draw the patch if not in a wipe
@ -841,17 +840,27 @@ static void F_IntroDrawScene(void)
V_DrawRightAlignedString(BASEVIDWIDTH-4, BASEVIDHEIGHT-12, V_ALLOWLOWERCASE|(trans<<V_ALPHASHIFT), "\x86""Press ""\x82""ENTER""\x86"" to skip...");
}
if (animtimer)
animtimer--;
V_DrawString(cx, cy, V_ALLOWLOWERCASE, cutscene_disptext);
}
//
// F_IntroDrawer
// F_IntroTicker
//
void F_IntroDrawer(void)
void F_IntroTicker(void)
{
// advance animation
finalecount++;
timetonext--;
F_WriteText();
// check for skipping
if (keypressed)
keypressed = false;
wipestyleflags = WSF_CROSSFADE;
if (timetonext <= 0)
{
if (intro_scenenum == 0)
@ -861,6 +870,9 @@ void F_IntroDrawer(void)
wipestyleflags = WSF_FADEOUT;
F_WipeStartScreen();
F_TryColormapFade(31);
F_IntroDrawer();
F_WipeEndScreen();
F_RunWipe(99,true);
}
@ -874,6 +886,9 @@ void F_IntroDrawer(void)
wipestyleflags = (WSF_FADEOUT|WSF_TOWHITE);
F_WipeStartScreen();
F_TryColormapFade(0);
F_IntroDrawer();
F_WipeEndScreen();
F_RunWipe(99,true);
}
@ -885,6 +900,9 @@ void F_IntroDrawer(void)
wipestyleflags = WSF_FADEOUT;
F_WipeStartScreen();
F_TryColormapFade(31);
F_IntroDrawer();
F_WipeEndScreen();
F_RunWipe(99,true);
}
@ -897,7 +915,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();
@ -920,12 +941,12 @@ void F_IntroDrawer(void)
wipegamestate = GS_INTRO;
return;
}
F_NewCutscene(introtext[++intro_scenenum]);
timetonext = introscenetime[intro_scenenum];
F_WipeStartScreen();
wipegamestate = -1;
wipestyleflags = WSF_CROSSFADE;
animtimer = stoptimer = 0;
}
@ -933,78 +954,36 @@ void F_IntroDrawer(void)
if (rendermode != render_none)
{
if (intro_scenenum == 5 && intro_curtime == 5*TICRATE)
if (intro_scenenum == 0 && intro_curtime == 2*TICRATE-19)
{
patch_t *radar = W_CachePatchName("RADAR", PU_PATCH_LOWPRIORITY);
S_ChangeMusicInternal("_stjr", false);
wipestyleflags = WSF_FADEIN;
F_WipeStartScreen();
F_WipeColorFill(31);
V_DrawSmallScaledPatch(0, 0, 0, radar);
W_UnlockCachedPatch(radar);
V_DrawString(8, 128, V_ALLOWLOWERCASE, cutscene_disptext);
F_TryColormapFade(31);
F_IntroDrawer();
F_WipeEndScreen();
F_RunWipe(99,true);
}
else if (intro_scenenum == 7 && intro_curtime == 6*TICRATE) // Force a wipe here
else if ((intro_scenenum == 5 && intro_curtime == 5*TICRATE)
|| (intro_scenenum == 7 && intro_curtime == 6*TICRATE)
//|| (intro_scenenum == 11 && intro_curtime == 7*TICRATE)
|| (intro_scenenum == 15 && intro_curtime == 7*TICRATE))
{
patch_t *grass = W_CachePatchName("SGRASS2", PU_PATCH_LOWPRIORITY);
F_WipeStartScreen();
F_WipeColorFill(31);
V_DrawSmallScaledPatch(0, 0, 0, grass);
W_UnlockCachedPatch(grass);
V_DrawString(8, 128, V_ALLOWLOWERCASE, cutscene_disptext);
F_WipeEndScreen();
F_RunWipe(99,true);
}
/*else if (intro_scenenum == 11 && intro_curtime == 7*TICRATE)
{
patch_t *confront = W_CachePatchName("CONFRONT", PU_PATCH_LOWPRIORITY);
F_WipeStartScreen();
F_WipeColorFill(31);
V_DrawSmallScaledPatch(0, 0, 0, confront);
W_UnlockCachedPatch(confront);
V_DrawString(8, 128, V_ALLOWLOWERCASE, cutscene_disptext);
F_WipeEndScreen();
F_RunWipe(99,true);
}*/
if (intro_scenenum == 15 && intro_curtime == 7*TICRATE)
{
patch_t *sdo = W_CachePatchName("SONICDO2", PU_PATCH_LOWPRIORITY);
F_WipeStartScreen();
F_WipeColorFill(31);
V_DrawSmallScaledPatch(0, 0, 0, sdo);
W_UnlockCachedPatch(sdo);
V_DrawString(224, 8, V_ALLOWLOWERCASE, cutscene_disptext);
F_IntroDrawer();
F_WipeEndScreen();
F_RunWipe(99,true);
}
}
F_IntroDrawScene();
}
//
// F_IntroTicker
//
void F_IntroTicker(void)
{
// advance animation
finalecount++;
timetonext--;
F_WriteText();
// check for skipping
if (keypressed)
keypressed = false;
if (animtimer)
animtimer--;
}
//
@ -2304,6 +2283,9 @@ void F_InitMenuPresValues(void)
M_SetMenuCurBackground((gamestate == GS_TIMEATTACK) ? "RECATTBG" : "TITLESKY");
M_SetMenuCurFadeValue(16);
M_SetMenuCurTitlePics();
LUA_HUD_DestroyDrawList(luahuddrawlist_title);
luahuddrawlist_title = LUA_HUD_CreateDrawList();
}
//
@ -2319,6 +2301,7 @@ void F_SkyScroll(INT32 scrollxspeed, INT32 scrollyspeed, const char *patchname)
INT32 pw, ph; // scaled by dupz
patch_t *pat;
INT32 i, j;
fixed_t fracmenuanimtimer, xscrolltimer, yscrolltimer;
if (rendermode == render_none)
return;
@ -2345,12 +2328,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;
@ -3421,7 +3405,21 @@ void F_TitleScreenDrawer(void)
}
luahook:
LUA_HUDHOOK(title);
// 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);
LUA_HUDHOOK(title, luahuddrawlist_title);
}
LUA_HUD_DrawList(luahuddrawlist_title);
}
// separate animation timer for backgrounds, since we also count
@ -3858,11 +3856,27 @@ boolean F_ContinueResponder(event_t *event)
static INT32 scenenum, cutnum;
static INT32 picxpos, picypos, picnum, pictime, picmode, numpics, pictoloop;
static INT32 textxpos, textypos;
static boolean dofadenow = false, cutsceneover = false;
static boolean cutsceneover = false;
static boolean runningprecutscene = false, precutresetplayer = false;
static void F_AdvanceToNextScene(void)
{
if (rendermode != render_none)
{
F_WipeStartScreen();
// Fade to any palette color you want.
if (cutscenes[cutnum]->scene[scenenum].fadecolor)
{
V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,cutscenes[cutnum]->scene[scenenum].fadecolor);
F_WipeEndScreen();
F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeinid, true);
F_WipeStartScreen();
}
}
// Don't increment until after endcutscene check
// (possible overflow / bad patch names from the one tic drawn before the fade)
if (scenenum+1 >= cutscenes[cutnum]->numscenes)
@ -3870,6 +3884,7 @@ static void F_AdvanceToNextScene(void)
F_EndCutScene();
return;
}
++scenenum;
timetonext = 0;
@ -3885,7 +3900,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;
@ -3895,6 +3909,14 @@ static void F_AdvanceToNextScene(void)
textypos = cutscenes[cutnum]->scene[scenenum].textypos;
animtimer = pictime = cutscenes[cutnum]->scene[scenenum].picduration[picnum];
if (rendermode != render_none)
{
F_CutsceneDrawer();
F_WipeEndScreen();
F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true);
}
}
// See also G_AfterIntermission, the only other place which handles intra-map/ending transitions
@ -3969,21 +3991,6 @@ void F_StartCustomCutscene(INT32 cutscenenum, boolean precutscene, boolean reset
//
void F_CutsceneDrawer(void)
{
if (dofadenow && rendermode != render_none)
{
F_WipeStartScreen();
// Fade to any palette color you want.
if (cutscenes[cutnum]->scene[scenenum].fadecolor)
{
V_DrawFill(0,0,BASEVIDWIDTH,BASEVIDHEIGHT,cutscenes[cutnum]->scene[scenenum].fadecolor);
F_WipeEndScreen();
F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeinid, true);
F_WipeStartScreen();
}
}
V_DrawFill(0,0, BASEVIDWIDTH, BASEVIDHEIGHT, 31);
if (cutscenes[cutnum]->scene[scenenum].picname[picnum][0] != '\0')
@ -3996,12 +4003,6 @@ void F_CutsceneDrawer(void)
W_CachePatchName(cutscenes[cutnum]->scene[scenenum].picname[picnum], PU_PATCH_LOWPRIORITY));
}
if (dofadenow && rendermode != render_none)
{
F_WipeEndScreen();
F_RunWipe(cutscenes[cutnum]->scene[scenenum].fadeoutid, true);
}
V_DrawString(textxpos, textypos, V_ALLOWLOWERCASE, cutscene_disptext);
}
@ -4018,8 +4019,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

@ -24,6 +24,7 @@
#include "w_wad.h"
#include "z_zone.h"
#include "i_time.h"
#include "i_system.h"
#include "i_threads.h"
#include "m_menu.h"
@ -555,7 +556,10 @@ void F_RunWipe(UINT8 wipetype, boolean drawMenu)
// wait loop
while (!((nowtime = I_GetTime()) - lastwipetic))
I_Sleep();
{
I_Sleep(cv_sleep.value);
I_UpdateTime(cv_timescale.value);
}
lastwipetic = nowtime;
// Wipe styles

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"
@ -1008,7 +1009,7 @@ void G_ReadMetalTic(mobj_t *metal)
oldmetal.x = READFIXED(metal_p);
oldmetal.y = READFIXED(metal_p);
oldmetal.z = READFIXED(metal_p);
P_TeleportMove(metal, oldmetal.x, oldmetal.y, oldmetal.z);
P_MoveOrigin(metal, oldmetal.x, oldmetal.y, oldmetal.z);
oldmetal.x = metal->x;
oldmetal.y = metal->y;
oldmetal.z = metal->z;

View file

@ -19,6 +19,7 @@
#include "f_finale.h"
#include "p_setup.h"
#include "p_saveg.h"
#include "i_time.h"
#include "i_system.h"
#include "am_map.h"
#include "m_random.h"
@ -46,6 +47,7 @@
#include "b_bot.h"
#include "m_cond.h" // condition sets
#include "lua_script.h"
#include "r_fps.h" // frame interpolation/uncapped
#include "lua_hud.h"
@ -1903,7 +1905,10 @@ void G_PreLevelTitleCard(void)
{
// draw loop
while (!((nowtime = I_GetTime()) - lasttime))
I_Sleep();
{
I_Sleep(cv_sleep.value);
I_UpdateTime(cv_timescale.value);
}
lasttime = nowtime;
ST_runTitleCard();
@ -2362,6 +2367,7 @@ void G_Ticker(boolean run)
F_TextPromptTicker();
AM_Ticker();
HU_Ticker();
break;
case GS_INTERMISSION:
@ -2414,7 +2420,9 @@ void G_Ticker(boolean run)
break;
case GS_TITLESCREEN:
if (titlemapinaction) P_Ticker(run); // then intentionally fall through
if (titlemapinaction)
P_Ticker(run);
// then intentionally fall through
/* FALLTHRU */
case GS_WAITINGPLAYERS:
F_MenuPresTicker(run);
@ -2801,6 +2809,13 @@ void G_MovePlayerToSpawnOrStarpost(INT32 playernum)
P_MovePlayerToStarpost(playernum);
else
P_MovePlayerToSpawn(playernum, G_FindMapStart(playernum));
R_ResetMobjInterpolationState(players[playernum].mo);
if (playernum == consoleplayer)
P_ResetCamera(&players[playernum], &camera);
else if (playernum == secondarydisplayplayer)
P_ResetCamera(&players[playernum], &camera2);
}
mapthing_t *G_FindCTFStart(INT32 playernum)

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 scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface);
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface);
EXPORT void HWRAPI(CreateModelVBOs) (model_t *model);
EXPORT void HWRAPI(SetTransform) (FTransform *ptransform);
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"
@ -38,6 +39,7 @@
#include "../m_cheat.h"
#include "../f_finale.h"
#include "../r_things.h" // R_GetShadowZ
#include "../d_main.h"
#include "../p_slopes.h"
#include "hw_md2.h"
@ -2968,6 +2970,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)
@ -3025,7 +3028,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);
@ -3104,7 +3122,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)
{
@ -3616,6 +3633,18 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
fixed_t slopez;
pslope_t *groundslope;
// uncapped/interpolation
interpmobjstate_t interp = {0};
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(thing, rendertimefrac, &interp);
}
else
{
R_InterpolateMobjState(thing, FRACUNIT, &interp);
}
groundz = R_GetShadowZ(thing, &groundslope);
heightsec = thing->subsector->sector->heightsec;
@ -3636,7 +3665,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
return;
}
floordiff = abs((flip < 0 ? thing->height : 0) + thing->z - groundz);
floordiff = abs((flip < 0 ? thing->height : 0) + interp.z - groundz);
alpha = floordiff / (4*FRACUNIT) + 75;
if (alpha >= 255) return;
@ -3650,8 +3679,8 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale)
scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height);
fscale = FIXED_TO_FLOAT(scalemul);
fx = FIXED_TO_FLOAT(thing->x);
fy = FIXED_TO_FLOAT(thing->y);
fx = FIXED_TO_FLOAT(interp.x);
fy = FIXED_TO_FLOAT(interp.y);
// 3--2
// | /|
@ -3729,12 +3758,44 @@ static void HWR_RotateSpritePolyToAim(gl_vissprite_t *spr, FOutVector *wallVerts
&& spr && spr->mobj && !R_ThingIsPaperSprite(spr->mobj)
&& wallVerts)
{
float basey = FIXED_TO_FLOAT(spr->mobj->z);
float lowy = wallVerts[0].y;
if (!precip && P_MobjFlip(spr->mobj) == -1) // precip doesn't have eflags so they can't flip
// uncapped/interpolation
interpmobjstate_t interp = {0};
float basey, lowy;
// do interpolation
if (R_UsingFrameInterpolation() && !paused)
{
basey = FIXED_TO_FLOAT(spr->mobj->z + spr->mobj->height);
if (precip)
{
R_InterpolatePrecipMobjState((precipmobj_t *)spr->mobj, rendertimefrac, &interp);
}
else
{
R_InterpolateMobjState(spr->mobj, rendertimefrac, &interp);
}
}
else
{
if (precip)
{
R_InterpolatePrecipMobjState((precipmobj_t *)spr->mobj, FRACUNIT, &interp);
}
else
{
R_InterpolateMobjState(spr->mobj, FRACUNIT, &interp);
}
}
if (P_MobjFlip(spr->mobj) == -1)
{
basey = FIXED_TO_FLOAT(interp.z + spr->mobj->height);
}
else
{
basey = FIXED_TO_FLOAT(interp.z);
}
lowy = wallVerts[0].y;
// Rotate sprites to fully billboard with the camera
// X, Y, AND Z need to be manipulated for the polys to rotate around the
// origin, because of how the origin setting works I believe that should
@ -5013,7 +5074,6 @@ static void HWR_ProjectSprite(mobj_t *thing)
INT32 heightsec, phs;
const boolean splat = R_ThingIsFloorSprite(thing);
const boolean papersprite = (R_ThingIsPaperSprite(thing) && !splat);
angle_t mobjangle = (thing->player ? thing->player->drawangle : thing->angle);
float z1, z2;
fixed_t spr_width, spr_height;
@ -5023,10 +5083,10 @@ static void HWR_ProjectSprite(mobj_t *thing)
INT32 rollangle = 0;
#endif
if (!thing)
return;
// uncapped/interpolation
interpmobjstate_t interp = {0};
if (thing->spritexscale < 1 || thing->spriteyscale < 1)
if (!thing)
return;
INT32 blendmode;
@ -5044,13 +5104,26 @@ static void HWR_ProjectSprite(mobj_t *thing)
dispoffset = thing->info->dispoffset;
this_scale = FIXED_TO_FLOAT(thing->scale);
spritexscale = FIXED_TO_FLOAT(thing->spritexscale);
spriteyscale = FIXED_TO_FLOAT(thing->spriteyscale);
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(thing, rendertimefrac, &interp);
}
else
{
R_InterpolateMobjState(thing, FRACUNIT, &interp);
}
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(thing->x) - gl_viewx;
tr_y = FIXED_TO_FLOAT(thing->y) - 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);
@ -5073,8 +5146,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(thing->x);
tr_y = FIXED_TO_FLOAT(thing->y);
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
@ -5122,7 +5195,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
I_Error("sprframes NULL for sprite %d\n", thing->sprite);
#endif
ang = R_PointToAngle (thing->x, thing->y) - mobjangle;
ang = R_PointToAngle (interp.x, interp.y) - interp.angle;
if (mirrored)
ang = InvAngle(ang);
@ -5190,8 +5263,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
{
@ -5200,14 +5273,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((mobjangle)>>ANGLETOFINESHIFT));
rightcos = FIXED_TO_FLOAT(FINECOSINE((mobjangle)>>ANGLETOFINESHIFT));
rightsin = FIXED_TO_FLOAT(FINESINE(interp.angle >> ANGLETOFINESHIFT));
rightcos = FIXED_TO_FLOAT(FINECOSINE(interp.angle >> ANGLETOFINESHIFT));
}
else
{
@ -5220,14 +5293,24 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (thing->renderflags & RF_SHADOWEFFECTS)
{
mobj_t *caster = thing->target;
interpmobjstate_t casterinterp = {};
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);
fixed_t floordiff = abs(((thing->eflags & MFE_VERTICALFLIP) ? caster->height : 0) + caster->z - groundz);
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;
@ -5268,12 +5351,12 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (vflip)
{
gz = FIXED_TO_FLOAT(thing->z + 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(thing->z) + (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);
}
@ -5292,7 +5375,7 @@ static void HWR_ProjectSprite(mobj_t *thing)
if (heightsec != -1 && phs != -1) // only clip things which are in special sectors
{
float top = gzt;
float bottom = FIXED_TO_FLOAT(thing->z);
float bottom = FIXED_TO_FLOAT(interp.z);
if (R_ThingIsFloorSprite(thing))
top = bottom;
@ -5309,13 +5392,24 @@ static void HWR_ProjectSprite(mobj_t *thing)
if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer)
{
interpmobjstate_t tracer_interp = {};
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);
@ -5438,6 +5532,9 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
unsigned rot = 0;
UINT8 flip;
if (!thing)
return;
// Visibility check by the blend mode.
if (thing->frame & FF_TRANSMASK)
{
@ -5445,9 +5542,22 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
return;
}
// 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(thing->x) - gl_viewx;
tr_y = FIXED_TO_FLOAT(thing->y) - 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);
@ -5456,8 +5566,8 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
if (tz < ZCLIP_PLANE)
return;
tr_x = FIXED_TO_FLOAT(thing->x);
tr_y = FIXED_TO_FLOAT(thing->y);
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)
@ -5520,7 +5630,7 @@ static void HWR_ProjectPrecipitationSprite(precipmobj_t *thing)
vis->colormap = NULL;
// set top/bottom coords
vis->gzt = FIXED_TO_FLOAT(thing->z + 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;
@ -6656,6 +6766,7 @@ void HWR_DoPostProcessor(player_t *player)
// 10 by 10 grid. 2 coordinates (xy)
float v[SCREENVERTS][SCREENVERTS][2];
static double disStart = 0;
UINT8 x, y;
INT32 WAVELENGTH;
INT32 AMPLITUDE;
@ -6664,15 +6775,15 @@ void HWR_DoPostProcessor(player_t *player)
// Modifies the wave.
if (*type == postimg_water)
{
WAVELENGTH = 20; // Lower is longer
AMPLITUDE = 20; // Lower is bigger
FREQUENCY = 16; // Lower is faster
WAVELENGTH = 5;
AMPLITUDE = 20;
FREQUENCY = 8;
}
else
{
WAVELENGTH = 10; // Lower is longer
AMPLITUDE = 30; // Lower is bigger
FREQUENCY = 4; // Lower is faster
WAVELENGTH = 10;
AMPLITUDE = 60;
FREQUENCY = 4;
}
for (x = 0; x < SCREENVERTS; x++)
@ -6686,7 +6797,7 @@ void HWR_DoPostProcessor(player_t *player)
}
HWD.pfnPostImgRedraw(v);
if (!(paused || P_AutoPause()))
disStart += 1;
disStart += FIXED_TO_FLOAT(renderdeltatics);
// Capture the screen again for screen waving on the intermission
if(gamestate != GS_INTERMISSION)

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"
@ -1338,8 +1339,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));
@ -1349,6 +1350,16 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
angle_t ang;
INT32 mod;
float finalscale;
interpmobjstate_t interp;
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(spr->mobj, rendertimefrac, &interp);
}
else
{
R_InterpolateMobjState(spr->mobj, FRACUNIT, &interp);
}
// Apparently people don't like jump frames like that, so back it goes
//if (tics > durs)
@ -1498,8 +1509,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);
@ -1523,7 +1534,11 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
}
#ifdef USE_MODEL_NEXTFRAME
#define INTERPOLERATION_LIMIT TICRATE/4
// Interpolate the model interpolation. (lol)
tics -= FixedToFloat(rendertimefrac);
#define INTERPOLERATION_LIMIT (TICRATE * 0.25f)
if (cv_glmodelinterpolation.value && tics <= durs && tics <= INTERPOLERATION_LIMIT)
{
if (durs > INTERPOLERATION_LIMIT)
@ -1572,13 +1587,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(spr->mobj->x);
p.y = FIXED_TO_FLOAT(spr->mobj->y)+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(spr->mobj->z);
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];
@ -1589,16 +1604,13 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
if (sprframe->rotate || papersprite)
{
fixed_t anglef = AngleFixed(spr->mobj->angle);
if (spr->mobj->player)
anglef = AngleFixed(spr->mobj->player->drawangle);
fixed_t anglef = AngleFixed(interp.angle);
p.angley = FIXED_TO_FLOAT(anglef);
}
else
{
const fixed_t anglef = AngleFixed((R_PointToAngle(spr->mobj->x, spr->mobj->y))-ANGLE_180);
const fixed_t anglef = AngleFixed((R_PointToAngle(interp.x, interp.y))-ANGLE_180);
p.angley = FIXED_TO_FLOAT(anglef);
}
@ -1620,7 +1632,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
p.rotaxis = (UINT8)(sprinfo->pivot[(spr->mobj->frame & FF_FRAMEMASK)].rotaxis);
// for NiGHTS specifically but should work everywhere else
ang = R_PointToAngle (spr->mobj->x, spr->mobj->y) - (spr->mobj->player ? spr->mobj->player->drawangle : spr->mobj->angle);
ang = R_PointToAngle (interp.x, interp.y) - interp.angle;
if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right
p.rollflip = 1;
else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left

View file

@ -2672,7 +2672,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 scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
static void DrawModelEx(model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
{
static GLRGBAFloat poly = {0,0,0,0};
static GLRGBAFloat tint = {0,0,0,0};
@ -2701,11 +2701,11 @@ static void DrawModelEx(model_t *model, INT32 frameIndex, INT32 duration, INT32
scaley = scale;
scalez = scale;
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;
@ -2977,7 +2977,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 scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
EXPORT void HWRAPI(DrawModel) (model_t *model, INT32 frameIndex, float duration, float tics, INT32 nextFrameIndex, FTransform *pos, float scale, UINT8 flipped, UINT8 hflipped, FSurfaceInfo *Surface)
{
DrawModelEx(model, frameIndex, duration, tics, nextFrameIndex, pos, scale, flipped, hflipped, Surface);
}

View file

@ -48,6 +48,7 @@
#endif
#include "lua_hud.h"
#include "lua_hudlib_drawlist.h"
#include "lua_hook.h"
// coords are scaled
@ -166,10 +167,14 @@ static tic_t cechotimer = 0;
static tic_t cechoduration = 5*TICRATE;
static INT32 cechoflags = 0;
static huddrawlist_h luahuddrawlist_scores;
//======================================================================
// HEADS UP INIT
//======================================================================
static tic_t resynch_ticker = 0;
#ifndef NONET
// just after
static void Command_Say_f(void);
@ -332,6 +337,8 @@ void HU_Init(void)
// set shift translation table
shiftxform = english_shiftxform;
luahuddrawlist_scores = LUA_HUD_CreateDrawList();
}
static inline void HU_Stop(void)
@ -382,12 +389,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.
@ -400,10 +407,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
@ -874,6 +881,39 @@ void HU_Ticker(void)
hu_showscores = !chat_on;
else
hu_showscores = false;
if (chat_on)
{
// count down the scroll timer.
if (chat_scrolltime > 0)
chat_scrolltime--;
}
if (netgame)
{
size_t i = 0;
// handle spam while we're at it:
for(; (i<MAXPLAYERS); i++)
{
if (stop_spamming[i] > 0)
stop_spamming[i]--;
}
// handle chat timers
for (i=0; (i<chat_nummsg_min); i++)
{
if (chat_timers[i] > 0)
chat_timers[i]--;
else
HU_removeChatText_Mini();
}
}
if (cechotimer > 0) --cechotimer;
if (hu_redownloadinggamestate)
resynch_ticker++;
}
#ifndef NONET
@ -1102,7 +1142,7 @@ boolean HU_Responder(event_t *ev)
if (chatlen+pastelen > HU_MAXMSGLEN)
return true; // we can't paste this!!
memmove(&w_chat[c_input + pastelen], &w_chat[c_input], pastelen);
memmove(&w_chat[c_input + pastelen], &w_chat[c_input], (chatlen - c_input) + 1); // +1 for '\0'
memcpy(&w_chat[c_input], paste, pastelen); // copy all of that.
c_input += pastelen;
return true;
@ -1854,8 +1894,6 @@ static void HU_DrawCEcho(void)
echoptr = line;
echoptr++;
}
--cechotimer;
}
static void HU_drawGametype(void)
@ -1917,9 +1955,6 @@ void HU_Drawer(void)
// draw chat string plus cursor
if (chat_on)
{
// count down the scroll timer.
if (chat_scrolltime > 0)
chat_scrolltime--;
if (!OLDCHAT)
HU_DrawChat();
else
@ -1929,30 +1964,10 @@ void HU_Drawer(void)
{
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.
}
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)
{
size_t i = 0;
// handle spam while we're at it:
for(; (i<MAXPLAYERS); i++)
{
if (stop_spamming[i] > 0)
stop_spamming[i]--;
}
// handle chat timers
for (i=0; (i<chat_nummsg_min); i++)
{
if (chat_timers[i] > 0)
chat_timers[i]--;
else
HU_removeChatText_Mini();
}
}
#endif
if (cechotimer)
@ -1979,7 +1994,13 @@ void HU_Drawer(void)
}
else
HU_DrawCoopOverlay();
LUA_HUDHOOK(scores);
if (renderisnewtic)
{
LUA_HUD_ClearDrawList(luahuddrawlist_scores);
LUA_HUDHOOK(scores, luahuddrawlist_scores);
}
LUA_HUD_DrawList(luahuddrawlist_scores);
}
if (gamestate != GS_LEVEL)
@ -1992,12 +2013,9 @@ void HU_Drawer(void)
// draw desynch text
if (hu_redownloadinggamestate)
{
static UINT32 resynch_ticker = 0;
char resynch_text[14];
UINT32 i;
// Animate the dots
resynch_ticker++;
strcpy(resynch_text, "Resynching");
for (i = 0; i < (resynch_ticker / 16) % 4; i++)
strcat(resynch_text, ".");

View file

@ -42,23 +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 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);
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);
/** \brief Get events

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

@ -151,4 +151,6 @@ void I_BeginRead(void);
*/
void I_EndRead(void);
UINT32 I_GetRefreshRate(void);
#endif

View file

@ -770,9 +770,9 @@ state_t states[NUMSTATES] =
// 1-Up box sprites (uses player sprite)
{SPR_PLAY, SPR2_LIFE, 2, {NULL}, 0, 18, S_PLAY_BOX2}, // S_PLAY_BOX1
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_PLAY_BOX1}, // S_PLAY_BOX2
{SPR_NULL, 0, 1, {NULL}, 0, 18, S_PLAY_BOX1}, // S_PLAY_BOX2
{SPR_PLAY, SPR2_LIFE, 4, {NULL}, 0, 4, S_PLAY_ICON2}, // S_PLAY_ICON1
{SPR_NULL, 0, 12, {NULL}, 0, 0, S_PLAY_ICON3}, // S_PLAY_ICON2
{SPR_NULL, 0, 12, {NULL}, 0, 4, S_PLAY_ICON3}, // S_PLAY_ICON2
{SPR_PLAY, SPR2_LIFE, 20, {NULL}, 0, 4, S_NULL}, // S_PLAY_ICON3
// Level end sign (uses player sprite)

View file

@ -31,7 +31,7 @@
#include "m_misc.h" // M_MapNumber
#include "b_bot.h" // B_UpdateBotleader
#include "d_clisrv.h" // CL_RemovePlayer
#include "i_system.h" // I_GetPreciseTime, I_PreciseToMicros
#include "i_system.h" // I_GetPreciseTime, I_GetPrecisePrecision
#include "lua_script.h"
#include "lua_libs.h"
@ -1783,7 +1783,42 @@ static int lib_pTeleportMove(lua_State *L)
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_TeleportMove(thing, x, y, z));
LUA_Deprecated(L, "P_TeleportMove", "P_SetOrigin\" or \"P_MoveOrigin");
lua_pushboolean(L, P_MoveOrigin(thing, x, y, z));
LUA_PushUserdata(L, tmthing, META_MOBJ);
P_SetTarget(&tmthing, ptmthing);
return 2;
}
static int lib_pSetOrigin(lua_State *L)
{
mobj_t *ptmthing = tmthing;
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
fixed_t z = luaL_checkfixed(L, 4);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_SetOrigin(thing, x, y, z));
LUA_PushUserdata(L, tmthing, META_MOBJ);
P_SetTarget(&tmthing, ptmthing);
return 2;
}
static int lib_pMoveOrigin(lua_State *L)
{
mobj_t *ptmthing = tmthing;
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
fixed_t x = luaL_checkfixed(L, 2);
fixed_t y = luaL_checkfixed(L, 3);
fixed_t z = luaL_checkfixed(L, 4);
NOHUD
INLEVEL
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_MoveOrigin(thing, x, y, z));
LUA_PushUserdata(L, tmthing, META_MOBJ);
P_SetTarget(&tmthing, ptmthing);
return 2;
@ -3909,7 +3944,7 @@ static int lib_gTicsToMilliseconds(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;
}
@ -4048,6 +4083,8 @@ static luaL_Reg lib[] = {
{"P_TryMove",lib_pTryMove},
{"P_Move",lib_pMove},
{"P_TeleportMove",lib_pTeleportMove},
{"P_SetOrigin",lib_pSetOrigin},
{"P_MoveOrigin",lib_pMoveOrigin},
{"P_SlideMove",lib_pSlideMove},
{"P_BounceMove",lib_pBounceMove},
{"P_CheckSight", lib_pCheckSight},

View file

@ -14,6 +14,7 @@
#include "d_player.h"
#include "s_sound.h"
#include "d_event.h"
#include "lua_hudlib_drawlist.h"
/*
Do you know what an 'X Macro' is? Such a macro is called over each element of
@ -110,12 +111,12 @@ ENUM (STRING_HOOK);
/* dead simple, LUA_HOOK(GameQuit) */
#define LUA_HOOK(type) LUA_HookVoid(HOOK(type))
#define LUA_HUDHOOK(type) LUA_HookHUD(HUD_HOOK(type))
#define LUA_HUDHOOK(type,drawlist) LUA_HookHUD(HUD_HOOK(type),(drawlist))
extern boolean hook_cmd_running;
void LUA_HookVoid(int hook);
void LUA_HookHUD(int hook);
void LUA_HookHUD(int hook, huddrawlist_h drawlist);
int LUA_HookMobj(mobj_t *, int hook);
int LUA_Hook2Mobj(mobj_t *, mobj_t *, int hook);

View file

@ -641,7 +641,7 @@ int LUA_HookKey(event_t *event, int hook_type)
return hook.status;
}
void LUA_HookHUD(int hook_type)
void LUA_HookHUD(int hook_type, huddrawlist_h list)
{
const hook_t * map = &hudHookIds[hook_type];
Hook_State hook;
@ -650,12 +650,15 @@ void LUA_HookHUD(int hook_type)
start_hook_stack();
begin_hook_values(&hook);
LUA_SetHudHook(hook_type);
LUA_SetHudHook(hook_type, list);
hud_running = true; // local hook
init_hook_call(&hook, 0, res_none);
call_mapped(&hook, map);
hud_running = false;
lua_pushnil(gL);
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
}
}

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,
@ -47,4 +52,6 @@ extern boolean hud_running;
boolean LUA_HudEnabled(enum hud option);
void LUA_SetHudHook(int hook);
void LUA_SetHudHook(int hook, huddrawlist_h list);
#endif // __LUA_HUD_H__

View file

@ -645,7 +645,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);
@ -659,7 +660,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;
}
@ -668,7 +676,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);
@ -685,7 +694,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;
}
@ -694,7 +710,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);
@ -712,7 +729,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;
}
@ -721,7 +745,8 @@ static int libd_drawCropped(lua_State *L)
fixed_t x, y, hscale, vscale, sx, sy, w, h;
INT32 flags;
patch_t *patch;
const UINT8 *colormap = NULL;
UINT8 *colormap = NULL;
huddrawlist_h list;
HUDONLY
x = luaL_checkinteger(L, 1);
@ -751,13 +776,22 @@ static int libd_drawCropped(lua_State *L)
flags &= ~V_PARAMMASK; // Don't let crashes happen.
V_DrawCroppedPatch(x, y, hscale, vscale, flags, patch, colormap, sx, sy, w, h);
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_AddDrawCropped(list, x, y, hscale, vscale, patch, flags, colormap, sx, sy, w, h);
else
V_DrawCroppedPatch(x, y, hscale, vscale, flags, patch, colormap, sx, sy, w, h);
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);
@ -765,13 +799,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);
@ -780,12 +823,20 @@ 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_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);
@ -793,12 +844,21 @@ 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;
}
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);
@ -808,6 +868,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
@ -899,6 +968,7 @@ static int libd_drawNameTag(lua_State *L)
UINT16 outlinecolor;
UINT8 *basecolormap = NULL;
UINT8 *outlinecolormap = NULL;
huddrawlist_h list;
HUDONLY
@ -914,7 +984,15 @@ static int libd_drawNameTag(lua_State *L)
outlinecolormap = R_GetTranslationColormap(TC_DEFAULT, outlinecolor, GTC_CACHE);
flags &= ~V_PARAMMASK; // Don't let crashes happen.
V_DrawNameTag(x, y, flags, FRACUNIT, basecolormap, outlinecolormap, 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_AddDrawNameTag(list, x, y, str, flags, basecolor, outlinecolor, basecolormap, outlinecolormap);
else
V_DrawNameTag(x, y, flags, FRACUNIT, basecolormap, outlinecolormap, str);
return 0;
}
@ -929,6 +1007,7 @@ static int libd_drawScaledNameTag(lua_State *L)
UINT16 outlinecolor;
UINT8 *basecolormap = NULL;
UINT8 *outlinecolormap = NULL;
huddrawlist_h list;
HUDONLY
@ -947,7 +1026,15 @@ static int libd_drawScaledNameTag(lua_State *L)
outlinecolormap = R_GetTranslationColormap(TC_DEFAULT, outlinecolor, GTC_CACHE);
flags &= ~V_PARAMMASK; // Don't let crashes happen.
V_DrawNameTag(FixedInt(x), FixedInt(y), flags, scale, basecolormap, outlinecolormap, 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_AddDrawScaledNameTag(list, x, y, str, flags, scale, basecolor, outlinecolor, basecolormap, outlinecolormap);
else
V_DrawNameTag(FixedInt(x), FixedInt(y), flags, scale, basecolormap, outlinecolormap, str);
return 0;
}
@ -957,6 +1044,7 @@ static int libd_drawLevelTitle(lua_State *L)
INT32 y;
const char *str;
INT32 flags;
huddrawlist_h list;
HUDONLY
@ -967,7 +1055,14 @@ static int libd_drawLevelTitle(lua_State *L)
flags &= ~V_PARAMMASK; // Don't let crashes happen.
V_DrawLevelTitle(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_AddDrawLevelTitle(list, x, y, str, flags);
else
V_DrawLevelTitle(x, y, flags, str);
return 0;
}
@ -1060,6 +1155,7 @@ static int libd_getStringColormap(lua_State *L)
static int libd_fadeScreen(lua_State *L)
{
huddrawlist_h list;
UINT16 color = luaL_checkinteger(L, 1);
UINT8 strength = luaL_checkinteger(L, 2);
const UINT8 maxstrength = ((color & 0xFF00) ? 32 : 10);
@ -1072,13 +1168,24 @@ 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;
}
@ -1356,10 +1463,13 @@ boolean LUA_HudEnabled(enum hud option)
return false;
}
void LUA_SetHudHook(int hook)
void LUA_SetHudHook(int hook, huddrawlist_h list)
{
lua_getref(gL, lib_draw_ref);
lua_pushlightuserdata(gL, list);
lua_setfield(gL, LUA_REGISTRYINDEX, "HUD_DRAW_LIST");
switch (hook)
{
case HUD_HOOK(game): {

572
src/lua_hudlib_drawlist.c Normal file
View file

@ -0,0 +1,572 @@
// 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_DrawCropped,
DI_DrawNum,
DI_DrawPaddedNum,
DI_DrawFill,
DI_DrawString,
DI_DrawNameTag,
DI_DrawScaledNameTag,
DI_DrawLevelTitle,
DI_FadeScreen,
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;
} 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_fixed,
align_fixedcenter,
align_fixedright,
align_small,
align_smallfixed,
align_smallfixedcenter,
align_smallfixedright,
align_smallcenter,
align_smallright,
align_smallthin,
align_smallthincenter,
align_smallthinright,
align_smallthinfixed,
align_smallthinfixedcenter,
align_smallthinfixedright,
align_thin,
align_thinfixed,
align_thinfixedcenter,
align_thinfixedright,
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_AddDrawCropped(
huddrawlist_h list,
fixed_t x,
fixed_t y,
fixed_t hscale,
fixed_t vscale,
patch_t *patch,
INT32 flags,
UINT8 *colormap,
fixed_t sx,
fixed_t sy,
fixed_t w,
fixed_t h
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawCropped;
item->x = x;
item->y = y;
item->hscale = hscale;
item->vscale = vscale;
item->patch = patch;
item->flags = flags;
item->colormap = colormap;
item->sx = sx;
item->sy = sy;
item->w = w;
item->h = h;
}
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_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_AddDrawNameTag(
huddrawlist_h list,
INT32 x,
INT32 y,
const char *str,
INT32 flags,
UINT16 basecolor,
UINT16 outlinecolor,
UINT8 *basecolormap,
UINT8 *outlinecolormap
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawNameTag;
item->x = x;
item->y = y;
item->str = CopyString(list, str);
item->flags = flags;
item->basecolor = basecolor;
item->outlinecolor = outlinecolor;
item->basecolormap = basecolormap;
item->outlinecolormap = outlinecolormap;
}
void LUA_HUD_AddDrawScaledNameTag(
huddrawlist_h list,
fixed_t x,
fixed_t y,
const char *str,
INT32 flags,
fixed_t scale,
UINT16 basecolor,
UINT16 outlinecolor,
UINT8 *basecolormap,
UINT8 *outlinecolormap
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawScaledNameTag;
item->x = x;
item->y = y;
item->str = CopyString(list, str);
item->flags = flags;
item->scale = scale;
item->basecolor = basecolor;
item->outlinecolor = outlinecolor;
item->basecolormap = basecolormap;
item->outlinecolormap = outlinecolormap;
}
void LUA_HUD_AddDrawLevelTitle(
huddrawlist_h list,
INT32 x,
INT32 y,
const char *str,
INT32 flags
)
{
size_t i = AllocateDrawItem(list);
drawitem_t *item = &list->items[i];
item->type = DI_DrawLevelTitle;
item->x = x;
item->y = y;
item->str = CopyString(list, str);
item->flags = flags;
}
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_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_DrawCropped:
V_DrawCroppedPatch(item->x, item->y, item->hscale, item->vscale, item->flags, item->patch, item->colormap, item->sx, item->sy, item->w, item->h);
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_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;
case align_fixed:
V_DrawStringAtFixed(item->x, item->y, item->flags, item->str);
break;
case align_fixedcenter:
V_DrawCenteredStringAtFixed(item->x, item->y, item->flags, item->str);
break;
case align_fixedright:
V_DrawRightAlignedStringAtFixed(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_smallfixed:
V_DrawSmallStringAtFixed(item->x, item->y, item->flags, item->str);
break;
case align_smallfixedcenter:
V_DrawCenteredSmallStringAtFixed(item->x, item->y, item->flags, item->str);
break;
case align_smallfixedright:
V_DrawRightAlignedSmallStringAtFixed(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;
case align_smallthin:
V_DrawSmallThinString(item->x, item->y, item->flags, item->str);
break;
case align_smallthincenter:
V_DrawCenteredSmallThinString(item->x, item->y, item->flags, item->str);
break;
case align_smallthinright:
V_DrawRightAlignedSmallThinString(item->x, item->y, item->flags, item->str);
break;
case align_smallthinfixed:
V_DrawSmallThinStringAtFixed(item->x, item->y, item->flags, item->str);
break;
case align_smallthinfixedcenter:
V_DrawCenteredSmallThinStringAtFixed(item->x, item->y, item->flags, item->str);
break;
case align_smallthinfixedright:
V_DrawRightAlignedSmallThinStringAtFixed(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;
case align_thinfixed:
V_DrawThinStringAtFixed(item->x, item->y, item->flags, item->str);
break;
case align_thinfixedcenter:
V_DrawCenteredThinStringAtFixed(item->x, item->y, item->flags, item->str);
break;
case align_thinfixedright:
V_DrawRightAlignedThinStringAtFixed(item->x, item->y, item->flags, item->str);
break;
}
break;
case DI_DrawNameTag:
V_DrawNameTag(item->x, item->y, item->flags, FRACUNIT, item->basecolormap, item->outlinecolormap, item->str);
break;
case DI_DrawScaledNameTag:
V_DrawNameTag(FixedInt(item->x), FixedInt(item->y), item->flags, item->scale, item->basecolormap, item->outlinecolormap, item->str);
break;
case DI_DrawLevelTitle:
V_DrawLevelTitle(item->x, item->y, item->flags, item->str);
break;
case DI_FadeScreen:
V_DrawFadeScreen(item->color, item->strength);
break;
default:
I_Error("can't draw draw list item: invalid draw list item type");
continue;
}
}
}

152
src/lua_hudlib_drawlist.h Normal file
View file

@ -0,0 +1,152 @@
// 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_AddDrawCropped(
huddrawlist_h list,
fixed_t x,
fixed_t y,
fixed_t hscale,
fixed_t vscale,
patch_t *patch,
INT32 flags,
UINT8 *colormap,
fixed_t sx,
fixed_t sy,
fixed_t w,
fixed_t h
);
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_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_AddDrawNameTag(
huddrawlist_h list,
INT32 x,
INT32 y,
const char *str,
INT32 flags,
UINT16 basecolor,
UINT16 outlinecolor,
UINT8 *basecolormap,
UINT8 *outlinecolormap
);
void LUA_HUD_AddDrawScaledNameTag(
huddrawlist_h list,
fixed_t x,
fixed_t y,
const char *str,
INT32 flags,
fixed_t scale,
UINT16 basecolor,
UINT16 outlinecolor,
UINT8 *basecolormap,
UINT8 *outlinecolormap
);
void LUA_HUD_AddDrawLevelTitle(
huddrawlist_h list,
INT32 x,
INT32 y,
const char *str,
INT32 flags
);
void LUA_HUD_AddFadeScreen(
huddrawlist_h list,
UINT16 color,
UINT8 strength
);
// Draws the given draw list
void LUA_HUD_DrawList(huddrawlist_h list);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __LUA_HUDLIB_DRAWLIST__

View file

@ -458,7 +458,7 @@ static int mobj_get(lua_State *L)
}
#define NOSET luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " should not be set directly.", mobj_opt[field])
#define NOSETPOS luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " should not be set directly. Use " LUA_QL("P_Move") ", " LUA_QL("P_TryMove") ", or " LUA_QL("P_TeleportMove") " instead.", mobj_opt[field])
#define NOSETPOS luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " should not be set directly. Use " LUA_QL("P_Move") ", " LUA_QL("P_TryMove") ", or " LUA_QL("P_SetOrigin") ", or " LUA_QL("P_MoveOrigin") " instead.", mobj_opt[field])
static int mobj_set(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@ -767,6 +767,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

@ -475,7 +475,7 @@ void Command_RTeleport_f(void)
CONS_Printf(M_GetText("Teleporting by %d, %d, %d...\n"), intx, inty, FixedInt((intz-p->mo->z)));
P_MapStart();
if (!P_TeleportMove(p->mo, p->mo->x+intx*FRACUNIT, p->mo->y+inty*FRACUNIT, intz))
if (!P_SetOrigin(p->mo, p->mo->x+intx*FRACUNIT, p->mo->y+inty*FRACUNIT, intz))
CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n"));
else
S_StartSound(p->mo, sfx_mixup);
@ -696,7 +696,7 @@ void Command_Teleport_f(void)
}
P_MapStart();
if (!P_TeleportMove(p->mo, intx, inty, intz))
if (!P_SetOrigin(p->mo, intx, inty, intz))
CONS_Alert(CONS_WARNING, M_GetText("Unable to teleport to that spot!\n"));
else
S_StartSound(p->mo, sfx_mixup);
@ -1315,13 +1315,13 @@ void OP_ObjectplaceMovement(player_t *player)
if (cmd->forwardmove != 0)
{
P_Thrust(player->mo, player->mo->angle, (cmd->forwardmove*player->mo->scale/MAXPLMOVE)*cv_speed.value);
P_TeleportMove(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z);
P_MoveOrigin(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z);
player->mo->momx = player->mo->momy = 0;
}
if (cmd->sidemove != 0)
{
P_Thrust(player->mo, player->mo->angle-ANGLE_90, (cmd->sidemove*player->mo->scale/MAXPLMOVE)*cv_speed.value);
P_TeleportMove(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z);
P_MoveOrigin(player->mo, player->mo->x+player->mo->momx, player->mo->y+player->mo->momy, player->mo->z);
player->mo->momx = player->mo->momy = 0;
}

View file

@ -22,6 +22,7 @@
#include "d_main.h"
#include "d_netcmd.h"
#include "console.h"
#include "r_fps.h"
#include "r_local.h"
#include "hu_stuff.h"
#include "g_game.h"
@ -31,6 +32,7 @@
// Data.
#include "sounds.h"
#include "s_sound.h"
#include "i_time.h"
#include "i_system.h"
#include "i_threads.h"
@ -171,10 +173,10 @@ static INT32 vidm_nummodes;
static INT32 vidm_column_size;
// new menus
static tic_t recatkdrawtimer = 0;
static tic_t ntsatkdrawtimer = 0;
static fixed_t recatkdrawtimer = 0;
static fixed_t ntsatkdrawtimer = 0;
static tic_t charseltimer = 0;
static fixed_t charseltimer = 0;
static fixed_t char_scroll = 0;
#define charscrollamt 128*FRACUNIT
@ -207,17 +209,17 @@ menu_t SPauseDef;
static levelselect_t levelselect = {0, NULL};
static UINT8 levelselectselect[3];
static patch_t *levselp[2][3];
static INT32 lsoffs[2];
static fixed_t lsoffs[2];
#define lsrow levelselectselect[0]
#define lscol levelselectselect[1]
#define lshli levelselectselect[2]
#define lshseperation 101
#define lsbasevseperation (62*vid.height)/(BASEVIDHEIGHT*vid.dupy) //62
#define lsbasevseperation ((62*vid.height)/(BASEVIDHEIGHT*vid.dupy)) //62
#define lsheadingheight 16
#define getheadingoffset(row) (levelselect.rows[row].header[0] ? lsheadingheight : 0)
#define lsvseperation(row) lsbasevseperation + getheadingoffset(row)
#define lsvseperation(row) (lsbasevseperation + getheadingoffset(row))
#define lswide(row) levelselect.rows[row].mapavailable[3]
#define lsbasex 19
@ -1386,6 +1388,7 @@ static menuitem_t OP_VideoOptionsMenu[] =
#ifdef HWRENDER
{IT_HEADER, NULL, "Renderer", NULL, 208},
{IT_CALL | IT_STRING, NULL, "OpenGL Options...", M_OpenGLOptionsMenu, 214},
{IT_STRING | IT_CVAR, NULL, "FPS Cap", &cv_fpscap, 219},
#endif
};
@ -5496,7 +5499,7 @@ static void M_HandleLevelPlatter(INT32 choice)
{
if (!lsoffs[0]) // prevent sound spam
{
lsoffs[0] = -8;
lsoffs[0] = -8 * FRACUNIT;
S_StartSound(NULL,sfx_s3kb7);
}
return;
@ -5505,7 +5508,7 @@ static void M_HandleLevelPlatter(INT32 choice)
}
lsrow++;
lsoffs[0] = lsvseperation(lsrow);
lsoffs[0] = lsvseperation(lsrow) * FRACUNIT;
if (levelselect.rows[lsrow].header[0])
lshli = lsrow;
@ -5524,7 +5527,7 @@ static void M_HandleLevelPlatter(INT32 choice)
{
if (!lsoffs[0]) // prevent sound spam
{
lsoffs[0] = 8;
lsoffs[0] = 8 * FRACUNIT;
S_StartSound(NULL,sfx_s3kb7);
}
return;
@ -5533,7 +5536,7 @@ static void M_HandleLevelPlatter(INT32 choice)
}
lsrow--;
lsoffs[0] = -lsvseperation(iter);
lsoffs[0] = -lsvseperation(iter) * FRACUNIT;
if (levelselect.rows[lsrow].header[0])
lshli = lsrow;
@ -5574,7 +5577,7 @@ static void M_HandleLevelPlatter(INT32 choice)
}
else if (!lsoffs[0]) // prevent sound spam
{
lsoffs[0] = -8;
lsoffs[0] = -8 * FRACUNIT;
S_StartSound(NULL,sfx_s3kb2);
}
break;
@ -5600,14 +5603,14 @@ static void M_HandleLevelPlatter(INT32 choice)
{
lscol++;
lsoffs[1] = (lswide(lsrow) ? 8 : -lshseperation);
lsoffs[1] = (lswide(lsrow) ? 8 : -lshseperation) * FRACUNIT;
S_StartSound(NULL,sfx_s3kb7);
ifselectvalnextmap(lscol) else ifselectvalnextmap(0)
}
else if (!lsoffs[1]) // prevent sound spam
{
lsoffs[1] = 8;
lsoffs[1] = 8 * FRACUNIT;
S_StartSound(NULL,sfx_s3kb7);
}
break;
@ -5632,14 +5635,14 @@ static void M_HandleLevelPlatter(INT32 choice)
{
lscol--;
lsoffs[1] = (lswide(lsrow) ? -8 : lshseperation);
lsoffs[1] = (lswide(lsrow) ? -8 : lshseperation) * FRACUNIT;
S_StartSound(NULL,sfx_s3kb7);
ifselectvalnextmap(lscol) else ifselectvalnextmap(0)
}
else if (!lsoffs[1]) // prevent sound spam
{
lsoffs[1] = -8;
lsoffs[1] = -8 * FRACUNIT;
S_StartSound(NULL,sfx_s3kb7);
}
break;
@ -5802,7 +5805,7 @@ static void M_DrawRecordAttackForeground(void)
for (i = -12; i < (BASEVIDHEIGHT/height) + 12; i++)
{
INT32 y = ((i*height) - (height - ((recatkdrawtimer*2)%height)));
INT32 y = ((i*height) - (height - ((FixedInt(recatkdrawtimer*2))%height)));
// don't draw above the screen
{
INT32 sy = FixedMul(y, dupz<<FRACBITS) >> FRACBITS;
@ -5819,17 +5822,18 @@ static void M_DrawRecordAttackForeground(void)
}
// draw clock
fa = (FixedAngle(((recatkdrawtimer * 4) % 360)<<FRACBITS)>>ANGLETOFINESHIFT) & FINEMASK;
fa = (FixedAngle(((FixedInt(recatkdrawtimer * 4)) % 360)<<FRACBITS)>>ANGLETOFINESHIFT) & FINEMASK;
V_DrawSciencePatch(160<<FRACBITS, (80<<FRACBITS) + (4*FINESINE(fa)), 0, clock, FRACUNIT);
// Increment timer.
recatkdrawtimer++;
recatkdrawtimer += renderdeltatics;
if (recatkdrawtimer < 0) recatkdrawtimer = 0;
}
// NiGHTS Attack background.
static void M_DrawNightsAttackMountains(void)
{
static INT32 bgscrollx;
static fixed_t bgscrollx;
INT32 dupz = (vid.dupx < vid.dupy ? vid.dupx : vid.dupy);
patch_t *background = W_CachePatchName(curbgname, PU_PATCH);
INT16 w = background->width;
@ -5845,7 +5849,7 @@ static void M_DrawNightsAttackMountains(void)
if (x < BASEVIDWIDTH)
V_DrawScaledPatch(x, y, V_SNAPTOLEFT, background);
bgscrollx += (FRACUNIT/2);
bgscrollx += FixedMul(FRACUNIT/2, renderdeltatics);
if (bgscrollx > w<<FRACBITS)
bgscrollx &= 0xFFFF;
}
@ -5876,7 +5880,7 @@ static void M_DrawNightsAttackBackground(void)
M_DrawNightsAttackMountains();
// back top foreground patch
x = 0-(ntsatkdrawtimer%backtopwidth);
x = 0-(FixedInt(ntsatkdrawtimer)%backtopwidth);
V_DrawScaledPatch(x, y, V_SNAPTOTOP|V_SNAPTOLEFT, backtopfg);
for (i = 0; i < 3; i++)
{
@ -5887,7 +5891,7 @@ static void M_DrawNightsAttackBackground(void)
}
// front top foreground patch
x = 0-((ntsatkdrawtimer*2)%fronttopwidth);
x = 0-(FixedInt(ntsatkdrawtimer*2)%fronttopwidth);
V_DrawScaledPatch(x, y, V_SNAPTOTOP|V_SNAPTOLEFT, fronttopfg);
for (i = 0; i < 3; i++)
{
@ -5898,7 +5902,7 @@ static void M_DrawNightsAttackBackground(void)
}
// back bottom foreground patch
x = 0-(ntsatkdrawtimer%backbottomwidth);
x = 0-(FixedInt(ntsatkdrawtimer)%backbottomwidth);
y = BASEVIDHEIGHT - backbottomheight;
V_DrawScaledPatch(x, y, V_SNAPTOBOTTOM|V_SNAPTOLEFT, backbottomfg);
for (i = 0; i < 3; i++)
@ -5910,7 +5914,7 @@ static void M_DrawNightsAttackBackground(void)
}
// front bottom foreground patch
x = 0-((ntsatkdrawtimer*2)%frontbottomwidth);
x = 0-(FixedInt(ntsatkdrawtimer*2)%frontbottomwidth);
y = BASEVIDHEIGHT - frontbottomheight;
V_DrawScaledPatch(x, y, V_SNAPTOBOTTOM|V_SNAPTOLEFT, frontbottomfg);
for (i = 0; i < 3; i++)
@ -5922,7 +5926,8 @@ static void M_DrawNightsAttackBackground(void)
}
// Increment timer.
ntsatkdrawtimer++;
ntsatkdrawtimer += renderdeltatics;
if (ntsatkdrawtimer < 0) ntsatkdrawtimer = 0;
}
// NiGHTS Attack floating Super Sonic.
@ -5930,15 +5935,15 @@ static patch_t *ntssupersonic[2];
static void M_DrawNightsAttackSuperSonic(void)
{
const UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_YELLOW, GTC_CACHE);
INT32 timer = (ntsatkdrawtimer/4) % 2;
angle_t fa = (FixedAngle(((ntsatkdrawtimer * 4) % 360)<<FRACBITS)>>ANGLETOFINESHIFT) & FINEMASK;
INT32 timer = FixedInt(ntsatkdrawtimer/4) % 2;
angle_t fa = (FixedAngle((FixedInt(ntsatkdrawtimer * 4) % 360)<<FRACBITS)>>ANGLETOFINESHIFT) & FINEMASK;
V_DrawFixedPatch(235<<FRACBITS, (120<<FRACBITS) - (8*FINESINE(fa)), FRACUNIT, 0, ntssupersonic[timer], colormap);
}
static void M_DrawLevelPlatterMenu(void)
{
UINT8 iter = lsrow, sizeselect = (lswide(lsrow) ? 1 : 0);
INT32 y = lsbasey + lsoffs[0] - getheadingoffset(lsrow);
INT32 y = lsbasey + FixedInt(lsoffs[0]) - getheadingoffset(lsrow);
const INT32 cursorx = (sizeselect ? 0 : (lscol*lshseperation));
if (currentMenu->prevMenu == &SP_TimeAttackDef)
@ -6006,7 +6011,7 @@ static void M_DrawLevelPlatterMenu(void)
// draw cursor box
if (levellistmode != LLM_CREATESERVER || lsrow)
V_DrawSmallScaledPatch(lsbasex + cursorx + lsoffs[1], lsbasey+lsoffs[0], 0, (levselp[sizeselect][((skullAnimCounter/4) ? 1 : 0)]));
V_DrawSmallScaledPatch(lsbasex + cursorx + FixedInt(lsoffs[1]), lsbasey+FixedInt(lsoffs[0]), 0, (levselp[sizeselect][((skullAnimCounter/4) ? 1 : 0)]));
#if 0
if (levelselect.rows[lsrow].maplist[lscol] > 0)
@ -6014,13 +6019,26 @@ static void M_DrawLevelPlatterMenu(void)
#endif
// handle movement of cursor box
if (lsoffs[0] > 1 || lsoffs[0] < -1)
lsoffs[0] = 2*lsoffs[0]/3;
fixed_t cursormovefrac = FixedDiv(2, 3);
if (lsoffs[0] > FRACUNIT || lsoffs[0] < -FRACUNIT)
{
fixed_t offs = lsoffs[0];
fixed_t newoffs = FixedMul(offs, cursormovefrac);
fixed_t deltaoffs = newoffs - offs;
newoffs = offs + FixedMul(deltaoffs, renderdeltatics);
lsoffs[0] = newoffs;
}
else
lsoffs[0] = 0;
if (lsoffs[1] > 1 || lsoffs[1] < -1)
lsoffs[1] = 2*lsoffs[1]/3;
if (lsoffs[1] > FRACUNIT || lsoffs[1] < -FRACUNIT)
{
fixed_t offs = lsoffs[1];
fixed_t newoffs = FixedMul(offs, cursormovefrac);
fixed_t deltaoffs = newoffs - offs;
newoffs = offs + FixedMul(deltaoffs, renderdeltatics);
lsoffs[1] = newoffs;
}
else
lsoffs[1] = 0;
@ -7647,7 +7665,7 @@ static void M_HandleEmblemHints(INT32 choice)
static musicdef_t *curplaying = NULL;
static INT32 st_sel = 0, st_cc = 0;
static tic_t st_time = 0;
static fixed_t st_time = 0;
static patch_t* st_radio[9];
static patch_t* st_launchpad[4];
@ -7711,16 +7729,17 @@ static void M_DrawSoundTest(void)
{
if (cv_soundtest.value)
{
frame[1] = (2-st_time);
frame[1] = (2 - (st_time >> FRACBITS));
frame[2] = ((cv_soundtest.value - 1) % 9);
frame[3] += (((cv_soundtest.value - 1) / 9) % (FIRSTSUPERCOLOR - frame[3]));
if (st_time < 2)
st_time++;
if (st_time < (2 << FRACBITS))
st_time += renderdeltatics;
}
}
else
{
if (curplaying->stoppingtics && st_time >= curplaying->stoppingtics)
fixed_t stoppingtics = (fixed_t)(curplaying->stoppingtics) << FRACBITS;
if (stoppingtics && st_time >= stoppingtics)
{
curplaying = NULL;
st_time = 0;
@ -7731,11 +7750,11 @@ static void M_DrawSoundTest(void)
angle_t ang;
//bpm = FixedDiv((60*TICRATE)<<FRACBITS, bpm); -- bake this in on load
work = st_time<<FRACBITS;
work = st_time;
work %= bpm;
if (st_time >= (FRACUNIT>>1)) // prevent overflow jump - takes about 15 minutes of loop on the same song to reach
st_time = (work>>FRACBITS);
if (st_time >= (FRACUNIT << (FRACBITS - 2))) // prevent overflow jump - takes about 15 minutes of loop on the same song to reach
st_time = work;
work = FixedDiv(work*180, bpm);
frame[0] = 8-(work/(20<<FRACBITS));
@ -7746,7 +7765,7 @@ static void M_DrawSoundTest(void)
hscale -= bounce/16;
vscale += bounce/16;
st_time++;
st_time += renderdeltatics;
}
}
}
@ -7786,7 +7805,7 @@ static void M_DrawSoundTest(void)
V_DrawFill(y, 20, vid.width/vid.dupx, 24, 159);
{
static fixed_t st_scroll = -1;
static fixed_t st_scroll = -FRACUNIT;
const char* titl;
x = 16;
V_DrawString(x, 10, 0, "NOW PLAYING:");
@ -7802,10 +7821,12 @@ static void M_DrawSoundTest(void)
i = V_LevelNameWidth(titl);
if (++st_scroll >= i)
st_scroll %= i;
st_scroll += renderdeltatics;
x -= st_scroll;
while (st_scroll >= (i << FRACBITS))
st_scroll -= i << FRACBITS;
x -= st_scroll >> FRACBITS;
while (x < BASEVIDWIDTH-y)
x += i;
@ -8329,8 +8350,8 @@ static void M_StartTutorial(INT32 choice)
// ==============
static INT32 saveSlotSelected = 1;
static INT32 loadgamescroll = 0;
static UINT8 loadgameoffset = 0;
static fixed_t loadgamescroll = 0;
static fixed_t loadgameoffset = 0;
static void M_CacheLoadGameData(void)
{
@ -8355,14 +8376,14 @@ static void M_DrawLoadGameData(void)
{
prev_i = i;
savetodraw = (saveSlotSelected + i + numsaves)%numsaves;
x = (BASEVIDWIDTH/2 - 42 + loadgamescroll) + (i*hsep);
x = (BASEVIDWIDTH/2 - 42 + FixedInt(loadgamescroll)) + (i*hsep);
y = 33 + 9;
{
INT32 diff = x - (BASEVIDWIDTH/2 - 42);
if (diff < 0)
diff = -diff;
diff = (42 - diff)/3 - loadgameoffset;
diff = (42 - diff)/3 - FixedInt(loadgameoffset);
if (diff < 0)
diff = 0;
y -= diff;
@ -8647,14 +8668,23 @@ skiplife:
static void M_DrawLoad(void)
{
M_DrawMenuTitle();
fixed_t scrollfrac = FixedDiv(2, 3);
if (loadgamescroll > 1 || loadgamescroll < -1)
loadgamescroll = 2*loadgamescroll/3;
if (loadgamescroll > FRACUNIT || loadgamescroll < -FRACUNIT)
{
fixed_t newscroll = FixedMul(loadgamescroll, scrollfrac);
fixed_t deltascroll = FixedMul(newscroll - loadgamescroll, renderdeltatics);
loadgamescroll += deltascroll;
}
else
loadgamescroll = 0;
if (loadgameoffset > 1)
loadgameoffset = 2*loadgameoffset/3;
if (loadgameoffset > FRACUNIT)
{
fixed_t newoffs = FixedMul(loadgameoffset, scrollfrac);
fixed_t deltaoffs = FixedMul(newoffs - loadgameoffset, renderdeltatics);
loadgameoffset += deltaoffs;
}
else
loadgameoffset = 0;
@ -8863,7 +8893,7 @@ static void M_ReadSaveStrings(void)
UINT8 lastseen = 0;
loadgamescroll = 0;
loadgameoffset = 14;
loadgameoffset = 14 * FRACUNIT;
for (i = 1; (i < MAXSAVEGAMES); i++) // slot 0 is no save
{
@ -8954,7 +8984,7 @@ static void M_HandleLoadSave(INT32 choice)
++saveSlotSelected;
if (saveSlotSelected >= numsaves)
saveSlotSelected -= numsaves;
loadgamescroll = 90;
loadgamescroll = 90 * FRACUNIT;
break;
case KEY_LEFTARROW:
@ -8962,7 +8992,7 @@ static void M_HandleLoadSave(INT32 choice)
--saveSlotSelected;
if (saveSlotSelected < 0)
saveSlotSelected += numsaves;
loadgamescroll = -90;
loadgamescroll = -90 * FRACUNIT;
break;
case KEY_ENTER:
@ -8987,7 +9017,7 @@ static void M_HandleLoadSave(INT32 choice)
else if (!loadgameoffset)
{
S_StartSound(NULL, sfx_lose);
loadgameoffset = 14;
loadgameoffset = 14 * FRACUNIT;
}
break;
@ -9013,7 +9043,7 @@ static void M_HandleLoadSave(INT32 choice)
}
else
S_StartSound(NULL, sfx_lose);
loadgameoffset = 14;
loadgameoffset = 14 * FRACUNIT;
}
break;
}
@ -9073,13 +9103,13 @@ static void M_LoadGame(INT32 choice)
//
void M_ForceSaveSlotSelected(INT32 sslot)
{
loadgameoffset = 14;
loadgameoffset = 14 * FRACUNIT;
// Already there? Whatever, then!
if (sslot == saveSlotSelected)
return;
loadgamescroll = 90;
loadgamescroll = 90 * FRACUNIT;
if (saveSlotSelected <= numsaves/2)
loadgamescroll = -loadgamescroll;
@ -9323,8 +9353,8 @@ static void M_DrawSetupChoosePlayerMenu(void)
INT32 x, y;
INT32 w = (vid.width/vid.dupx);
if (abs(char_scroll) > FRACUNIT)
char_scroll -= (char_scroll>>2);
if (abs(char_scroll) > FRACUNIT/4)
char_scroll -= FixedMul((char_scroll>>2), renderdeltatics);
else // close enough.
char_scroll = 0; // just be exact now.
@ -9352,7 +9382,7 @@ static void M_DrawSetupChoosePlayerMenu(void)
// Don't render the title map
hidetitlemap = true;
charseltimer++;
charseltimer += renderdeltatics;
// Background and borders
V_DrawFill(0, 0, bgwidth, vid.height, V_SNAPTOTOP|colormap[101]);
@ -9364,7 +9394,7 @@ static void M_DrawSetupChoosePlayerMenu(void)
V_DrawFill(0, 0, bw, vid.height, V_NOSCALESTART|col);
}
y = (charseltimer%32);
y = (charseltimer / FRACUNIT) % 32;
V_DrawMappedPatch(0, y-bgheight, V_SNAPTOTOP, charbg, colormap);
V_DrawMappedPatch(0, y, V_SNAPTOTOP, charbg, colormap);
V_DrawMappedPatch(0, y+bgheight, V_SNAPTOTOP, charbg, colormap);
@ -10631,7 +10661,7 @@ static void M_Marathon(INT32 choice)
titlemapinaction = TITLEMAP_OFF; // Nope don't give us HOMs please
M_SetupNextMenu(&SP_MarathonDef);
itemOn = marathonstart; // "Start" is selected.
recatkdrawtimer = 50-8;
recatkdrawtimer = (50-8) * FRACUNIT;
char_scroll = 0;
}
@ -10712,13 +10742,16 @@ void M_DrawMarathon(void)
x = (((BASEVIDWIDTH-82)/2)+11)<<FRACBITS;
y = (((BASEVIDHEIGHT-82)/2)+12-10)<<FRACBITS;
cnt = (36*(recatkdrawtimer<<FRACBITS))/TICRATE;
cnt = (36 * recatkdrawtimer) / TICRATE;
fa = (FixedAngle(cnt)>>ANGLETOFINESHIFT) & FINEMASK;
y -= (10*FINECOSINE(fa));
recatkdrawtimer++;
if (renderisnewtic)
{
recatkdrawtimer += FRACUNIT;
}
soffset = cnt = (recatkdrawtimer%50);
soffset = cnt = ((recatkdrawtimer >> FRACBITS) % 50);
if (!useBlackRock)
{
if (cnt > 8)
@ -10757,7 +10790,7 @@ void M_DrawMarathon(void)
}
w = char_scroll + (((8-cnt)*(8-cnt))<<(FRACBITS-5));
if (soffset == 50-1)
if (soffset == 50-1 && renderisnewtic)
w += FRACUNIT/2;
{
@ -10812,11 +10845,11 @@ void M_DrawMarathon(void)
if (!soffset)
{
char_scroll += (360<<FRACBITS)/42; // like a clock, ticking at 42bpm!
char_scroll += (360 * renderdeltatics)/42; // like a clock, ticking at 42bpm!
if (char_scroll >= 360<<FRACBITS)
char_scroll -= 360<<FRACBITS;
if (recatkdrawtimer > (10*TICRATE))
recatkdrawtimer -= (10*TICRATE);
if (recatkdrawtimer > ((10 << FRACBITS) * TICRATE))
recatkdrawtimer -= ((10 << FRACBITS) * TICRATE);
}
M_DrawMenuTitle();
@ -11028,7 +11061,7 @@ static INT32 menuRoomIndex = 0;
static void M_DrawRoomMenu(void)
{
static int frame = -12;
static fixed_t frame = -(12 << FRACBITS);
int dot_frame;
char text[4];
@ -11039,7 +11072,7 @@ static void M_DrawRoomMenu(void)
if (m_waiting_mode)
{
dot_frame = frame / 4;
dot_frame = (int)(frame >> FRACBITS) / 4;
dots = dot_frame + 3;
strcpy(text, " ");
@ -11052,8 +11085,9 @@ static void M_DrawRoomMenu(void)
strncpy(&text[dot_frame], "...", min(dots, 3 - dot_frame));
}
if (++frame == 12)
frame = -12;
frame += renderdeltatics;
while (frame >= (12 << FRACBITS))
frame -= 12 << FRACBITS;
currentMenu->menuitems[0].text = text;
}
@ -11819,7 +11853,7 @@ static void M_HandleConnectIP(INT32 choice)
// ========================
// Tails 03-02-2002
static UINT8 multi_tics;
static fixed_t multi_tics;
static UINT8 multi_frame;
static UINT8 multi_spr2;
@ -11887,10 +11921,11 @@ static void M_DrawSetupMultiPlayerMenu(void)
y += 11;
// anim the player in the box
if (--multi_tics <= 0)
multi_tics -= renderdeltatics;
while (multi_tics <= 0)
{
multi_frame++;
multi_tics = 4;
multi_tics += 4*FRACUNIT;
}
#define charw 74
@ -12161,7 +12196,7 @@ static void M_SetupMultiPlayer(INT32 choice)
(void)choice;
multi_frame = 0;
multi_tics = 4;
multi_tics = 4*FRACUNIT;
strcpy(setupm_name, cv_playername.string);
// set for player 1
@ -12205,7 +12240,7 @@ static void M_SetupMultiPlayer2(INT32 choice)
(void)choice;
multi_frame = 0;
multi_tics = 4;
multi_tics = 4*FRACUNIT;
strcpy (setupm_name, cv_playername2.string);
// set for splitscreen secondary player
@ -13536,7 +13571,8 @@ void M_QuitResponse(INT32 ch)
{
V_DrawScaledPatch(0, 0, 0, W_CachePatchName("GAMEQUIT", PU_PATCH)); // 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

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

@ -17,6 +17,7 @@
#include "i_system.h"
#include "z_zone.h"
#include "p_local.h"
#include "r_fps.h"
#ifdef HWRENDER
#include "hardware/hw_main.h"
@ -122,6 +123,12 @@ perfstatrow_t commoncounter_rows[] = {
{0}
};
perfstatrow_t interpolation_rows[] = {
{"intpfrc", "Interp frac: ", &ps_interp_frac, PS_TIME},
{"intplag", "Interp lag: ", &ps_interp_lag, PS_TIME},
{0}
};
#ifdef HWRENDER
perfstatrow_t batchcount_rows[] = {
{"polygon", "Polygons: ", &ps_hw_numpolys, 0},
@ -261,7 +268,7 @@ static INT32 PS_GetMetricAverage(ps_metric_t *metric, boolean time_metric)
for (i = 0; i < cv_ps_samplesize.value; i++)
{
if (time_metric)
sum += I_PreciseToMicros(*((precise_t*)history_read_pos));
sum += (*((precise_t*)history_read_pos)) / (I_GetPrecisePrecision() / 1000000);
else
sum += *((INT32*)history_read_pos);
history_read_pos += value_size;
@ -281,7 +288,7 @@ static INT32 PS_GetMetricMinOrMax(ps_metric_t *metric, boolean time_metric, bool
{
INT32 value;
if (time_metric)
value = I_PreciseToMicros(*((precise_t*)history_read_pos));
value = (*((precise_t*)history_read_pos)) / (I_GetPrecisePrecision() / 1000000);
else
value = *((INT32*)history_read_pos);
@ -309,7 +316,7 @@ static INT32 PS_GetMetricSD(ps_metric_t *metric, boolean time_metric)
{
INT64 value;
if (time_metric)
value = I_PreciseToMicros(*((precise_t*)history_read_pos));
value = (*((precise_t*)history_read_pos)) / (I_GetPrecisePrecision() / 1000000);
else
value = *((INT32*)history_read_pos);
@ -339,7 +346,7 @@ static INT32 PS_GetMetricScreenValue(ps_metric_t *metric, boolean time_metric)
else
{
if (time_metric)
return I_PreciseToMicros(metric->value.p);
return (metric->value.p) / (I_GetPrecisePrecision() / 1000000);
else
return metric->value.i;
}
@ -473,6 +480,9 @@ static void PS_UpdateFrameStats(void)
if (PS_IsLevelActive())
PS_UpdateRowHistories(commoncounter_rows, true);
if (R_UsingFrameInterpolation())
PS_UpdateRowHistories(interpolation_rows, true);
#ifdef HWRENDER
if (rendermode == render_opengl && cv_glbatching.value)
{
@ -634,7 +644,7 @@ static void PS_DrawRenderStats(void)
{
const boolean hires = PS_HighResolution();
const int half_row = hires ? 5 : 4;
int x, y;
int x, y, cy = 10;
PS_DrawDescriptorHeader();
@ -645,7 +655,7 @@ static void PS_DrawRenderStats(void)
if (PS_IsLevelActive())
{
x = hires ? 115 : 90;
PS_DrawPerfRows(x, 10, V_BLUEMAP, commoncounter_rows);
cy = PS_DrawPerfRows(x, 10, V_BLUEMAP, commoncounter_rows) + half_row;
#ifdef HWRENDER
if (rendermode == render_opengl && cv_glbatching.value)
@ -659,6 +669,12 @@ static void PS_DrawRenderStats(void)
}
#endif
}
if (R_UsingFrameInterpolation())
{
x = hires ? 115 : 90;
PS_DrawPerfRows(x, cy, V_ROSYMAP, interpolation_rows);
}
}
static void PS_DrawGameLogicStats(void)

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"
@ -334,6 +335,9 @@ INT32 EV_DoCeiling(mtag_t tag, line_t *line, ceiling_e type)
ceiling->type = type;
firstone = 0;
// interpolation
R_CreateInterpolator_SectorPlane(&ceiling->thinker, sec, true);
}
return rtn;
}
@ -398,6 +402,10 @@ INT32 EV_DoCrush(mtag_t tag, line_t *line, ceiling_e type)
}
ceiling->type = type;
// interpolation
R_CreateInterpolator_SectorPlane(&ceiling->thinker, sec, false);
R_CreateInterpolator_SectorPlane(&ceiling->thinker, sec, true);
}
return rtn;
}

View file

@ -1333,7 +1333,7 @@ void A_FaceStabHurl(mobj_t *actor)
hwork->destscale = FixedSqrt(step*basesize);
P_SetScale(hwork, hwork->destscale);
hwork->fuse = 2;
P_TeleportMove(hwork, actor->x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<<FRACBITS)));
P_MoveOrigin(hwork, actor->x + xo*(15-step), actor->y + yo*(15-step), actor->z + (actor->height - hwork->height)/2 + (P_MobjFlip(actor)*(8<<FRACBITS)));
step -= NUMGRADS;
}
@ -2095,7 +2095,7 @@ void A_CrushclawAim(mobj_t *actor)
#undef anglimit
#undef angfactor
P_TeleportMove(actor,
P_MoveOrigin(actor,
crab->x + P_ReturnThrustX(actor, actor->angle, locvar1*crab->scale),
crab->y + P_ReturnThrustY(actor, actor->angle, locvar1*crab->scale),
crab->z + locvar2*crab->scale);
@ -2233,7 +2233,7 @@ void A_CrushclawLaunch(mobj_t *actor)
fixed_t idx = dx, idy = dy, idz = dz;
while (chain)
{
P_TeleportMove(chain, actor->target->x + idx, actor->target->y + idy, actor->target->z + idz);
P_MoveOrigin(chain, actor->target->x + idx, actor->target->y + idy, actor->target->z + idz);
chain->movefactor = chain->z;
idx += dx;
idy += dy;
@ -11181,7 +11181,7 @@ void A_VileAttack(mobj_t *actor)
// move the fire between the vile and the player
//fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
//fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
P_TeleportMove(fire,
P_MoveOrigin(fire,
actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
fire->z);
@ -11226,7 +11226,7 @@ void A_VileAttack(mobj_t *actor)
// move the fire between the vile and the player
//fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
//fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
P_TeleportMove(fire,
P_MoveOrigin(fire,
actor->target->x - P_ReturnThrustX(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
actor->target->y - P_ReturnThrustY(fire, actor->angle, FixedMul(24*FRACUNIT, fire->scale)),
fire->z);
@ -11893,12 +11893,12 @@ void A_FlickyCenter(mobj_t *actor)
if (actor->target && P_AproxDistance(actor->target->x - originx, actor->target->y - originy) < actor->extravalue1)
{
actor->extravalue2 = 1;
P_TeleportMove(actor, actor->target->x, actor->target->y, actor->target->z);
P_SetOrigin(actor, actor->target->x, actor->target->y, actor->target->z);
}
else if(actor->extravalue2)
{
actor->extravalue2 = 0;
P_TeleportMove(actor, originx, originy, originz);
P_SetOrigin(actor, originx, originy, originz);
}
}
}
@ -12431,7 +12431,7 @@ void A_LightBeamReset(mobj_t *actor)
actor->momy = (P_SignedRandom()*FINECOSINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/128;
actor->momz = (P_SignedRandom()*FRACUNIT)/128;
P_TeleportMove(actor,
P_SetOrigin(actor,
actor->spawnpoint->x*FRACUNIT - (P_SignedRandom()*FINESINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/2,
actor->spawnpoint->y*FRACUNIT + (P_SignedRandom()*FINECOSINE(((actor->spawnpoint->angle*ANG1)>>ANGLETOFINESHIFT) & FINEMASK))/2,
actor->spawnpoint->z*FRACUNIT + (P_SignedRandom()*FRACUNIT)/2);
@ -12988,7 +12988,7 @@ void A_DoNPCSkid(mobj_t *actor)
actor->momy = (2*actor->momy)/3;
}
P_TeleportMove(actor, x, y, z);
P_MoveOrigin(actor, x, y, z);
// Spawn a particle every 3 tics.
if (!(leveltime % 3))
@ -13329,7 +13329,7 @@ void A_Boss5MakeJunk(mobj_t *actor)
if (locvar1 > 0)
P_SetMobjState(broked, locvar1);
if (!P_MobjWasRemoved(broked))
P_TeleportMove(broked, broked->x + broked->momx, broked->y + broked->momy, broked->z);
P_MoveOrigin(broked, broked->x + broked->momx, broked->y + broked->momy, broked->z);
ang += ANGLE_45;
}
@ -13538,7 +13538,7 @@ void A_DustDevilThink(mobj_t *actor)
//Chained thinker for the spiralling dust column.
while (layer && !P_MobjWasRemoved(layer)) {
angle_t fa = layer->angle >> ANGLETOFINESHIFT;
P_TeleportMove(layer, layer->x + 5 * FixedMul(scale, FINECOSINE(fa)), layer->y + 5 * FixedMul(scale, FINESINE(fa)), layer->z);
P_MoveOrigin(layer, layer->x + 5 * FixedMul(scale, FINECOSINE(fa)), layer->y + 5 * FixedMul(scale, FINESINE(fa)), layer->z);
layer->scale = scale;
layer->angle += ANG10 / 2;
layer->momx = actor->momx;
@ -14547,7 +14547,7 @@ void A_DragonWing(mobj_t *actor)
actor->angle = target->angle + actor->movedir;
x = target->x + P_ReturnThrustX(actor, actor->angle, -target->radius);
y = target->y + P_ReturnThrustY(actor, actor->angle, -target->radius);
P_TeleportMove(actor, x, y, target->z);
P_MoveOrigin(actor, x, y, target->z);
}
// Function: A_DragonSegment
@ -14588,7 +14588,7 @@ void A_DragonSegment(mobj_t *actor)
zdist = P_ReturnThrustY(target, zangle, radius);
actor->angle = hangle;
P_TeleportMove(actor, target->x + xdist, target->y + ydist, target->z + zdist);
P_MoveOrigin(actor, target->x + xdist, target->y + ydist, target->z + zdist);
}
// Function: A_ChangeHeight

View file

@ -17,6 +17,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"
@ -523,6 +524,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
@ -1709,6 +1712,9 @@ void EV_DoFloor(mtag_t tag, line_t *line, floor_e floortype)
}
firstone = 0;
// interpolation
R_CreateInterpolator_SectorPlane(&dofloor->thinker, sec, false);
}
}
@ -1805,6 +1811,10 @@ void EV_DoElevator(mtag_t tag, line_t *line, elevator_e elevtype)
}
elevator->ceilingdestheight = elevator->floordestheight + sec->ceilingheight - sec->floorheight;
// interpolation
R_CreateInterpolator_SectorPlane(&elevator->thinker, sec, false);
R_CreateInterpolator_SectorPlane(&elevator->thinker, sec, true);
}
}
@ -1953,6 +1963,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
@ -1978,6 +1992,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)
@ -2030,6 +2048,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];
@ -2081,6 +2103,10 @@ void EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher)
block->ceilingstartheight = block->sector->ceilingheight;
block->tag = (INT16)rover->master->args[0];
// interpolation
R_CreateInterpolator_SectorPlane(&block->thinker, roversec, false);
R_CreateInterpolator_SectorPlane(&block->thinker, roversec, true);
if (itsamonitor)
{
oldx = thing->x;
@ -2089,9 +2115,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)
@ -2112,9 +2138,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

@ -91,6 +91,7 @@ typedef struct camera_s
// Camera demobjerization
// Info for drawing: position.
fixed_t x, y, z;
boolean reset;
//More drawing info: to determine current sprite.
angle_t angle; // orientation
@ -413,7 +414,8 @@ boolean P_CheckCameraPosition(fixed_t x, fixed_t y, camera_t *thiscam);
boolean P_CheckMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff);
boolean P_TryMove(mobj_t *thing, fixed_t x, fixed_t y, boolean allowdropoff);
boolean P_Move(mobj_t *actor, fixed_t speed);
boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z);
boolean P_SetOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z);
boolean P_MoveOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z);
void P_SlideMove(mobj_t *mo);
void P_BounceMove(mobj_t *mo);
boolean P_CheckSight(mobj_t *t1, mobj_t *t2);

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"
@ -74,7 +75,7 @@ camera_t *mapcampointer;
//
// P_TeleportMove
//
boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z)
static boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z)
{
// the move is ok,
// so link the thing into its new position
@ -106,6 +107,30 @@ boolean P_TeleportMove(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z)
return true;
}
// P_SetOrigin - P_TeleportMove which RESETS interpolation values.
//
boolean P_SetOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z)
{
boolean result = P_TeleportMove(thing, x, y, z);
if (result == true)
{
thing->old_x = thing->x;
thing->old_y = thing->y;
thing->old_z = thing->z;
}
return result;
}
//
// P_MoveOrigin - P_TeleportMove which KEEPS interpolation values.
//
boolean P_MoveOrigin(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z)
{
return P_TeleportMove(thing, x, y, z);
}
// =========================================================================
// MOVEMENT ITERATOR FUNCTIONS
// =========================================================================
@ -1153,9 +1178,9 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true; // underneath
if (tmthing->eflags & MFE_VERTICALFLIP)
P_TeleportMove(thing, thing->x, thing->y, tmthing->z - thing->height - FixedMul(FRACUNIT, tmthing->scale));
P_SetOrigin(thing, thing->x, thing->y, tmthing->z - thing->height - FixedMul(FRACUNIT, tmthing->scale));
else
P_TeleportMove(thing, thing->x, thing->y, 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, DMG_SPIKE);
return true;
@ -1915,7 +1940,7 @@ static boolean PIT_CheckLine(line_t *ld)
cosradius = FixedMul(dist, FINECOSINE(langle>>ANGLETOFINESHIFT));
sinradius = FixedMul(dist, FINESINE(langle>>ANGLETOFINESHIFT));
tmthing->flags |= MF_NOCLIP;
P_TeleportMove(tmthing, result.x + cosradius - tmthing->momx, result.y + sinradius - tmthing->momy, tmthing->z);
P_MoveOrigin(tmthing, result.x + cosradius - tmthing->momx, result.y + sinradius - tmthing->momy, tmthing->z);
tmthing->flags &= ~MF_NOCLIP;
}
#endif

View file

@ -19,6 +19,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"
@ -4023,15 +4024,22 @@ void P_NullPrecipThinker(precipmobj_t *mobj)
void P_SnowThinker(precipmobj_t *mobj)
{
R_ResetPrecipitationMobjInterpolationState(mobj);
P_CycleStateAnimation((mobj_t *)mobj);
// adjust height
if ((mobj->z += mobj->momz) <= mobj->floorz)
{
mobj->z = mobj->ceilingz;
R_ResetPrecipitationMobjInterpolationState(mobj);
}
}
void P_RainThinker(precipmobj_t *mobj)
{
R_ResetPrecipitationMobjInterpolationState(mobj);
P_CycleStateAnimation((mobj_t *)mobj);
if (mobj->state != &states[S_RAIN1])
@ -4051,6 +4059,7 @@ void P_RainThinker(precipmobj_t *mobj)
return;
mobj->z = mobj->ceilingz;
R_ResetPrecipitationMobjInterpolationState(mobj);
P_SetPrecipMobjState(mobj, S_RAIN1);
return;
@ -4657,7 +4666,7 @@ static void P_Boss4MoveSpikeballs(mobj_t *mobj, angle_t angle, fixed_t fz)
while ((base = base->tracer))
{
for (seg = base, dist = 172*FRACUNIT, s = 9; seg; seg = seg->hnext, dist += 124*FRACUNIT, --s)
P_TeleportMove(seg, mobj->x + P_ReturnThrustX(mobj, angle, dist), mobj->y + P_ReturnThrustY(mobj, angle, dist), bz + FixedMul(fz, FixedDiv(s<<FRACBITS, 9<<FRACBITS)));
P_MoveOrigin(seg, mobj->x + P_ReturnThrustX(mobj, angle, dist), mobj->y + P_ReturnThrustY(mobj, angle, dist), bz + FixedMul(fz, FixedDiv(s<<FRACBITS, 9<<FRACBITS)));
angle += ANGLE_MAX/3;
}
}
@ -5578,7 +5587,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
mobj->hprev->destscale = FRACUNIT + (2*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2);
P_SetScale(mobj->hprev, mobj->hprev->destscale);
P_TeleportMove(mobj->hprev, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->hprev->height/2);
P_MoveOrigin(mobj->hprev, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->hprev->height/2);
mobj->hprev->momx = mobj->momx;
mobj->hprev->momy = mobj->momy;
mobj->hprev->momz = mobj->momz;
@ -6433,7 +6442,7 @@ void P_Attract(mobj_t *source, mobj_t *dest, boolean nightsgrab) // Home in on y
if (dist < source->movefactor)
{
source->momx = source->momy = source->momz = 0;
P_TeleportMove(source, tx, ty, tz);
P_MoveOrigin(source, tx, ty, tz);
}
else
{
@ -7042,7 +7051,7 @@ static void P_UpdateMinecartSegments(mobj_t *mobj)
dx = seg->extravalue1;
dy = seg->extravalue2;
sang = seg->cusval;
P_TeleportMove(seg, x + s*dx + c*dy, y - c*dx + s*dy, z);
P_MoveOrigin(seg, x + s*dx + c*dy, y - c*dx + s*dy, z);
seg->angle = ang + FixedAngle(FRACUNIT*sang);
seg->flags2 = (seg->flags2 & ~MF2_DONTDRAW) | (mobj->flags2 & MF2_DONTDRAW);
seg = seg->tracer;
@ -7809,6 +7818,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))
@ -7820,6 +7832,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_DROWNNUMBERS:
if (!P_DrownNumbersSceneryThink(mobj))
@ -8658,7 +8673,7 @@ static boolean P_EggRobo1Think(mobj_t *mobj)
< mobj->scale)
S_StartSound(mobj, mobj->info->seesound);
P_TeleportMove(mobj,
P_MoveOrigin(mobj,
(15*(mobj->x >> 4)) + (basex >> 4) + P_ReturnThrustX(mobj, mobj->angle, SPECTATORRADIUS >> 4),
(15*(mobj->y >> 4)) + (basey >> 4) + P_ReturnThrustY(mobj, mobj->angle, SPECTATORRADIUS >> 4),
mobj->z);
@ -8684,9 +8699,9 @@ static boolean P_EggRobo1Think(mobj_t *mobj)
if (!didmove)
{
if (P_AproxDistance(mobj->x - basex, mobj->y - basey) < mobj->scale)
P_TeleportMove(mobj, basex, basey, mobj->z);
P_MoveOrigin(mobj, basex, basey, mobj->z);
else
P_TeleportMove(mobj,
P_MoveOrigin(mobj,
(15*(mobj->x >> 4)) + (basex >> 4),
(15*(mobj->y >> 4)) + (basey >> 4),
mobj->z);
@ -8808,11 +8823,11 @@ static void P_NiGHTSDroneThink(mobj_t *mobj)
sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale);
}
P_TeleportMove(goalpost, mobj->x, mobj->y, mobj->z + goaloffset);
P_TeleportMove(sparkle, mobj->x, mobj->y, mobj->z + sparkleoffset);
P_MoveOrigin(goalpost, mobj->x, mobj->y, mobj->z + goaloffset);
P_MoveOrigin(sparkle, mobj->x, mobj->y, mobj->z + sparkleoffset);
if (goalpost->movefactor != mobj->z || goalpost->friction != mobj->height)
{
P_TeleportMove(droneman, mobj->x, mobj->y, mobj->z + dronemanoffset);
P_MoveOrigin(droneman, mobj->x, mobj->y, mobj->z + dronemanoffset);
goalpost->movefactor = mobj->z;
goalpost->friction = mobj->height;
}
@ -8822,12 +8837,12 @@ static void P_NiGHTSDroneThink(mobj_t *mobj)
{
if (goalpost->x != mobj->x || goalpost->y != mobj->y)
{
P_TeleportMove(goalpost, mobj->x, mobj->y, goalpost->z);
P_TeleportMove(sparkle, mobj->x, mobj->y, sparkle->z);
P_MoveOrigin(goalpost, mobj->x, mobj->y, goalpost->z);
P_MoveOrigin(sparkle, mobj->x, mobj->y, sparkle->z);
}
if (droneman->x != mobj->x || droneman->y != mobj->y)
P_TeleportMove(droneman, mobj->x, mobj->y,
P_MoveOrigin(droneman, mobj->x, mobj->y,
droneman->z >= mobj->floorz && droneman->z <= mobj->ceilingz ? droneman->z : mobj->z);
}
@ -9026,7 +9041,7 @@ static void P_SaloonDoorThink(mobj_t *mobj)
fma = (mobj->angle >> ANGLETOFINESHIFT) & FINEMASK;
c = 48*FINECOSINE(fma);
s = 48*FINESINE(fma);
P_TeleportMove(mobj, x + c0 + c, y + s0 + s, z);
P_MoveOrigin(mobj, x + c0 + c, y + s0 + s, z);
}
static void P_PyreFlyThink(mobj_t *mobj)
@ -9581,7 +9596,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
P_RemoveMobj(mobj);
return false;
}
P_TeleportMove(mobj, mobj->target->x, mobj->target->y, mobj->target->z - mobj->height);
P_MoveOrigin(mobj, mobj->target->x, mobj->target->y, mobj->target->z - mobj->height);
break;
case MT_HAMMER:
if (mobj->z <= mobj->floorz)
@ -10993,6 +11008,8 @@ 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);
R_AddMobjInterpolator(mobj);
return mobj;
}
@ -11040,6 +11057,8 @@ static precipmobj_t *P_SpawnPrecipMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype
|| mobj->subsector->sector->floorpic == skyflatnum)
mobj->precipflags |= PCF_PIT;
R_ResetPrecipitationMobjInterpolationState(mobj);
return mobj;
}
@ -11159,6 +11178,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!
@ -12562,7 +12583,7 @@ static boolean P_SetupNiGHTSDrone(mapthing_t *mthing, mobj_t *mobj)
dronemangoaldiff = max(mobjinfo[MT_NIGHTSDRONE_MAN].height - mobjinfo[MT_NIGHTSDRONE_GOAL].height, 0);
if (flip && mobj->height != oldheight)
P_TeleportMove(mobj, mobj->x, mobj->y, mobj->z - (mobj->height - oldheight));
P_MoveOrigin(mobj, mobj->x, mobj->y, mobj->z - (mobj->height - oldheight));
if (!flip)
{
@ -12631,9 +12652,9 @@ static boolean P_SetupNiGHTSDrone(mapthing_t *mthing, mobj_t *mobj)
// correct Z position
if (flip)
{
P_TeleportMove(goalpost, goalpost->x, goalpost->y, mobj->z + goaloffset);
P_TeleportMove(sparkle, sparkle->x, sparkle->y, mobj->z + sparkleoffset);
P_TeleportMove(droneman, droneman->x, droneman->y, mobj->z + dronemanoffset);
P_MoveOrigin(goalpost, goalpost->x, goalpost->y, mobj->z + goaloffset);
P_MoveOrigin(sparkle, sparkle->x, sparkle->y, mobj->z + sparkleoffset);
P_MoveOrigin(droneman, droneman->x, droneman->y, mobj->z + dronemanoffset);
}
// Remember position preference for later
@ -14086,9 +14107,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 - elementheight;
newmobj->old_z = mobj->old_z + mobj->height - zofs - elementheight;
newmobj->old_z2 = mobj->old_z2 + mobj->height - zofs - elementheight;
}
else
{
newmobj->old_z = mobj->old_z + zofs;
newmobj->old_z2 = mobj->old_z2 + zofs;
}
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;
// 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

@ -281,6 +281,8 @@ 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;
@ -288,6 +290,8 @@ 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
@ -298,6 +302,8 @@ typedef struct mobj_s
INT32 blendmode; // blend mode
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
@ -373,6 +379,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;
@ -387,6 +395,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
fixed_t shadowscale; // If this object casts a shadow, and the size relative to radius
@ -408,6 +417,8 @@ 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;
@ -415,6 +426,8 @@ 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
@ -425,6 +438,8 @@ typedef struct precipmobj_s
INT32 blendmode; // blend mode
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"
@ -2049,6 +2050,9 @@ boolean EV_DoPolyObjRotate(polyrotdata_t *prdata)
oldpo = po;
// interpolation
R_CreateInterpolator_Polyobj(&th->thinker, po);
th->turnobjs = 0;
if (!(prdata->flags & TMPR_DONTROTATEOTHERS))
th->turnobjs |= PTF_OTHERS;
@ -2114,6 +2118,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)))
@ -2129,8 +2136,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)))
{
@ -2181,6 +2190,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;
@ -2229,6 +2258,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)))
@ -2269,6 +2301,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)))
@ -2340,6 +2375,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)))
@ -2386,6 +2424,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)))
@ -2490,6 +2531,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"
@ -3060,6 +3061,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_sound.h" // for I_PlayCD()..
#include "i_video.h" // for I_FinishUpdate()..
#include "r_sky.h"
@ -33,6 +34,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"
@ -7313,7 +7315,10 @@ static void P_RunSpecialStageWipe(void)
{
// wait loop
while (!((nowtime = I_GetTime()) - lastwipetic))
I_Sleep();
{
I_Sleep(cv_sleep.value);
I_UpdateTime(cv_timescale.value);
}
lastwipetic = nowtime;
if (moviemode) // make sure we save frames for the white hold too
M_SaveFrame();
@ -7615,7 +7620,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"
pslope_t *slopelist = NULL;
UINT16 slopecount = 0;
@ -189,6 +190,9 @@ static inline void P_AddDynLineSlopeThinker (pslope_t* slope, dynplanetype_t typ
th->sourceline = sourceline;
th->extent = extent;
P_AddThinker(THINK_DYNSLOPE, &th->thinker);
// interpolation
R_CreateInterpolator_DynSlope(&th->thinker, slope);
}
static inline void P_AddDynVertexSlopeThinker (pslope_t* slope, const INT16 tags[3], const vector3_t vx[3])

View file

@ -21,6 +21,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"
@ -2480,7 +2481,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
if (mo->player)
{
if (bot) // This might put poor Tails in a wall if he's too far behind! D: But okay, whatever! >:3
P_TeleportMove(bot, bot->x + x, bot->y + y, bot->z + z);
P_SetOrigin(bot, bot->x + x, bot->y + y, bot->z + z);
if (splitscreen && mo->player == &players[secondarydisplayplayer] && camera2.chase)
{
camera2.x += x;
@ -2726,7 +2727,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
// Reset bot too.
if (bot) {
if (line->args[0])
P_TeleportMove(bot, mo->x, mo->y, mo->z);
P_SetOrigin(bot, mo->x, mo->y, mo->z);
bot->momx = bot->momy = bot->momz = 1;
bot->pmomz = 0;
bot->player->rmomx = bot->player->rmomy = 1;
@ -2767,7 +2768,7 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
// (Teleport them to you so they don't break it.)
if (bot && (bot->flags2 & MF2_TWOD) != (mo->flags2 & MF2_TWOD)) {
bot->flags2 = (bot->flags2 & ~MF2_TWOD) | (mo->flags2 & MF2_TWOD);
P_TeleportMove(bot, mo->x, mo->y, mo->z);
P_SetOrigin(bot, mo->x, mo->y, mo->z);
}
}
break;
@ -5703,6 +5704,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);
}
/**
@ -5732,6 +5737,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
@ -5791,6 +5799,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)
@ -5816,6 +5828,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.
@ -5856,6 +5872,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.
@ -7524,6 +7544,22 @@ static void Add_Scroller(INT32 type, fixed_t dx, fixed_t dy, INT32 control, INT3
}
}
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;
}
}
static void P_SpawnPlaneScroller(line_t *l, fixed_t dx, fixed_t dy, INT32 control, INT32 affectee, INT32 accel, INT32 exclusive)

View file

@ -122,7 +122,7 @@ void P_MixUp(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle,
*/
boolean P_Teleport(mobj_t *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, boolean flash, boolean dontstopmove)
{
if (!P_TeleportMove(thing, x, y, z))
if (!P_SetOrigin(thing, x, y, z))
return false;
if (!dontstopmove)

View file

@ -23,6 +23,9 @@
#include "lua_hook.h"
#include "m_perfstats.h"
#include "i_system.h" // I_GetPreciseTime
#include "r_main.h"
#include "r_fps.h"
#include "i_video.h" // rendermode
// Object place
#include "m_cheat.h"
@ -254,6 +257,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);
}
@ -616,8 +620,10 @@ void P_Ticker(boolean run)
if (OP_FreezeObjectplace())
{
P_MapStart();
R_UpdateMobjInterpolators();
OP_ObjectplaceMovement(&players[0]);
P_MoveChaseCamera(&players[0], &camera, false);
R_UpdateViewInterpolation();
P_MapEnd();
S_SetStackAdjustmentStart();
return;
@ -640,6 +646,8 @@ void P_Ticker(boolean run)
if (run)
{
R_UpdateMobjInterpolators();
if (demorecording)
G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0);
if (demoplayback)
@ -763,6 +771,42 @@ void P_Ticker(boolean run)
LUA_HOOK(PostThinkFrame);
}
if (run)
{
R_UpdateLevelInterpolators();
R_UpdateViewInterpolation();
// Hack: ensure newview is assigned every tic.
// Ensures view interpolation is T-1 to T in poor network conditions
// We need a better way to assign view state decoupled from game logic
if (rendermode != render_none)
{
player_t *player1 = &players[displayplayer];
if (player1->mo && skyboxmo[0] && cv_skybox.value)
{
R_SkyboxFrame(player1);
}
if (player1->mo)
{
R_SetupFrame(player1);
}
if (splitscreen)
{
player_t *player2 = &players[secondarydisplayplayer];
if (player2->mo && skyboxmo[0] && cv_skybox.value)
{
R_SkyboxFrame(player2);
}
if (player2->mo)
{
R_SetupFrame(player2);
}
}
}
}
P_MapEnd();
// Z_CheckMemCleanup();
@ -783,6 +827,8 @@ void P_PreTicker(INT32 frames)
{
P_MapStart();
R_UpdateMobjInterpolators();
LUA_HOOK(PreThinkFrame);
for (i = 0; i < MAXPLAYERS; i++)
@ -821,6 +867,10 @@ void P_PreTicker(INT32 frames)
LUA_HOOK(PostThinkFrame);
R_UpdateLevelInterpolators();
R_UpdateViewInterpolation();
R_ResetViewInterpolation(0);
P_MapEnd();
}

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"
@ -1996,6 +1997,14 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
ghost2->flags2 |= (mobj->player->followmobj->flags2 & MF2_LINKDRAW);
}
// Copy interpolation data :)
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;
}
@ -6931,7 +6940,7 @@ static void P_MoveNiGHTSToDrone(player_t *player)
}
player->mo->momx = player->mo->momy = player->mo->momz = 0;
P_TeleportMove(player->mo, player->drone->x, player->drone->y, player->drone->z + zofs);
P_MoveOrigin(player->mo, player->drone->x, player->drone->y, player->drone->z + zofs);
P_SetTarget(&player->drone, NULL);
}
@ -9647,6 +9656,7 @@ void P_ResetCamera(player_t *player, camera_t *thiscam)
thiscam->x = x;
thiscam->y = y;
thiscam->z = z;
thiscam->reset = true;
if ((thiscam == &camera && G_ControlStyle(1) == CS_SIMPLE)
|| (thiscam == &camera2 && G_ControlStyle(2) == CS_SIMPLE))
@ -10997,7 +11007,7 @@ static void P_MinecartThink(player_t *player)
}
// Move player to minecart.
P_TeleportMove(player->mo, minecart->x - minecart->momx, minecart->y - minecart->momy, minecart->z + max(minecart->momz, 0) + 8*FRACUNIT);
P_MoveOrigin(player->mo, minecart->x - minecart->momx, minecart->y - minecart->momy, minecart->z + max(minecart->momz, 0) + 8*FRACUNIT);
if (player->powers[pw_carry] != CR_MINECART)
return;
player->mo->momx = player->mo->momy = player->mo->momz = 0;
@ -11236,6 +11246,7 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume)
tic_t dashmode = min(player->dashmode, DASHMODE_MAX);
boolean underwater = mo->eflags & MFE_UNDERWATER;
statenum_t stat = fume->state-states;
boolean resetinterp = false;
if (panim != PA_WALK && panim != PA_RUN && panim != PA_DASH) // turn invisible when not in a coherent movement state
{
@ -11287,6 +11298,7 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume)
{
P_SetMobjState(fume, (stat = fume->info->seestate));
P_SetScale(fume, mo->scale);
resetinterp = true;
}
if (dashmode > DASHMODE_THRESHOLD && stat != fume->info->seestate) // If in dashmode, grow really big and flash
@ -11330,6 +11342,7 @@ static void P_DoMetalJetFume(player_t *player, mobj_t *fume)
fume->y = mo->y + P_ReturnThrustY(fume, angle, dist);
fume->z = mo->z + heightoffset - (fume->height >> 1);
P_SetThingPosition(fume);
if (resetinterp) R_ResetMobjInterpolationState(fume);
// If dashmode is high enough, spawn a trail
if (player->normalspeed >= skins[player->skin].normalspeed*2)
@ -11732,7 +11745,7 @@ void P_PlayerThink(player_t *player)
// P_TouchSpecialThing case MT_NIGHTSBUMPER, that position is fudged in the time
// between that routine in the previous tic
// and reaching here in the current tic
P_TeleportMove(player->mo, player->mo->hnext->x, player->mo->hnext->y
P_MoveOrigin(player->mo, player->mo->hnext->x, player->mo->hnext->y
, player->mo->hnext->z + FixedMul(player->mo->hnext->height/4, player->mo->hnext->scale));
P_SetTarget(&player->mo->hnext, NULL);
}
@ -12556,7 +12569,7 @@ void P_PlayerAfterThink(player_t *player)
player->mo->momx = (chain->x - player->mo->x)*2;
player->mo->momy = (chain->y - player->mo->y)*2;
player->mo->momz = (chain->z - (player->mo->height-chain->height/2) - player->mo->z)*2;
P_TeleportMove(player->mo, chain->x, chain->y, chain->z - (player->mo->height-chain->height/2));
P_MoveOrigin(player->mo, chain->x, chain->y, chain->z - (player->mo->height-chain->height/2));
if (!player->powers[pw_flashing]) // handle getting hurt
{
player->pflags |= PF_JUMPED;
@ -12650,7 +12663,7 @@ void P_PlayerAfterThink(player_t *player)
mo->tics = walktics;
}
P_TeleportMove(player->mo, rock->x, rock->y, rock->z + ((mo->eflags & MFE_VERTICALFLIP) ? -mo->height : rock->height));
P_MoveOrigin(player->mo, rock->x, rock->y, rock->z + ((mo->eflags & MFE_VERTICALFLIP) ? -mo->height : rock->height));
break;
}
case CR_PTERABYTE: // being carried by a Pterabyte

View file

@ -840,6 +840,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)
@ -866,7 +867,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);
@ -914,7 +931,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)

817
src/r_fps.c Normal file
View file

@ -0,0 +1,817 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2000 by Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko (prboom)
// Copyright (C) 1999-2019 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 r_fps.h
/// \brief Uncapped framerate stuff.
#include "r_fps.h"
#include "r_main.h"
#include "g_game.h"
#include "i_video.h"
#include "r_plane.h"
#include "p_spec.h"
#include "r_state.h"
#include "z_zone.h"
#include "console.h" // con_startup_loadprogress
#include "m_perfstats.h" // ps_metric_t
#ifdef HWRENDER
#include "hardware/hw_main.h" // for cv_glshearing
#endif
static CV_PossibleValue_t fpscap_cons_t[] = {
#ifdef DEVELOP
// Lower values are actually pretty useful for debugging interp problems!
{1, "MIN"},
#else
{TICRATE, "MIN"},
#endif
{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);
ps_metric_t ps_interp_frac = {0};
ps_metric_t ps_interp_lag = {0};
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)
{
// -1: Unlimited
return 0;
}
return cv_fpscap.value;
}
boolean R_UsingFrameInterpolation(void)
{
return (R_GetFramerateCap() != TICRATE || cv_timescale.value < FRACUNIT);
}
static viewvars_t p1view_old;
static viewvars_t p1view_new;
static viewvars_t p2view_old;
static viewvars_t p2view_new;
static viewvars_t sky1view_old;
static viewvars_t sky1view_new;
static viewvars_t sky2view_old;
static viewvars_t sky2view_new;
static viewvars_t *oldview = &p1view_old;
static int oldview_invalid[MAXSPLITSCREENPLAYERS] = {0, 0};
viewvars_t *newview = &p1view_new;
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 from + FixedMul(frac, to - from);
}
static angle_t R_LerpAngle(angle_t from, angle_t to, fixed_t frac)
{
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
// slopes are already calculated for the full possible view (which is 4*viewheight).
// 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out)
static void R_SetupFreelook(player_t *player, boolean skybox)
{
#ifndef HWRENDER
(void)player;
(void)skybox;
#endif
// clip it in the case we are looking a hardware 90 degrees full aiming
// (lmps, network and use F12...)
if (rendermode == render_soft
#ifdef HWRENDER
|| (rendermode == render_opengl
&& (cv_glshearing.value == 1
|| (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox))))
#endif
)
{
G_SoftwareClipAimingPitch((INT32 *)&aimingangle);
}
centeryfrac = (viewheight/2)<<FRACBITS;
if (rendermode == render_soft)
centeryfrac += FixedMul(AIMINGTODY(aimingangle), FixedDiv(viewwidth<<FRACBITS, BASEVIDWIDTH<<FRACBITS));
centery = FixedInt(FixedRound(centeryfrac));
if (rendermode == render_soft)
yslope = &yslopetab[viewheight*8 - centery];
}
#undef AIMINGTODY
void R_InterpolateView(fixed_t frac)
{
viewvars_t* prevview = oldview;
boolean skybox = 0;
UINT8 i;
if (FIXED_TO_FLOAT(frac) < 0)
frac = 0;
if (frac > FRACUNIT)
frac = FRACUNIT;
if (viewcontext == VIEWCONTEXT_SKY1 || viewcontext == VIEWCONTEXT_PLAYER1)
{
i = 0;
}
else
{
i = 1;
}
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);
viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
// this is gonna create some interesting visual errors for long distance teleports...
// might want to recalculate the view sector every frame instead...
viewplayer = newview->player;
viewsector = R_PointInSubsector(viewx, viewy)->sector;
// well, this ain't pretty
if (newview == &sky1view_new || newview == &sky2view_new)
{
skybox = 1;
}
R_SetupFreelook(newview->player, skybox);
}
void R_UpdateViewInterpolation(void)
{
p1view_old = p1view_new;
p2view_old = p2view_new;
sky1view_old = sky1view_new;
sky2view_old = sky2view_new;
if (oldview_invalid[0] > 0) oldview_invalid[0]--;
if (oldview_invalid[1] > 0) oldview_invalid[1]--;
}
void R_ResetViewInterpolation(UINT8 p)
{
if (p == 0)
{
UINT8 i;
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{
oldview_invalid[i]++;
}
}
else
{
oldview_invalid[p - 1]++;
}
}
void R_SetViewContext(enum viewcontext_e _viewcontext)
{
I_Assert(_viewcontext == VIEWCONTEXT_PLAYER1
|| _viewcontext == VIEWCONTEXT_PLAYER2
|| _viewcontext == VIEWCONTEXT_SKY1
|| _viewcontext == VIEWCONTEXT_SKY2);
viewcontext = _viewcontext;
switch (viewcontext)
{
case VIEWCONTEXT_PLAYER1:
oldview = &p1view_old;
newview = &p1view_new;
break;
case VIEWCONTEXT_PLAYER2:
oldview = &p2view_old;
newview = &p2view_new;
break;
case VIEWCONTEXT_SKY1:
oldview = &sky1view_old;
newview = &sky1view_new;
break;
case VIEWCONTEXT_SKY2:
oldview = &sky2view_old;
newview = &sky2view_new;
break;
default:
I_Error("viewcontext value is invalid: we should never get here without an assert!!");
break;
}
}
fixed_t R_InterpolateFixed(fixed_t from, fixed_t to)
{
if (!R_UsingFrameInterpolation())
{
return to;
}
return (R_LerpFixed(from, to, rendertimefrac));
}
angle_t R_InterpolateAngle(angle_t from, angle_t to)
{
if (!R_UsingFrameInterpolation())
{
return to;
}
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;
}

162
src/r_fps.h Normal file
View file

@ -0,0 +1,162 @@
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2000 by Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze, Andrey Budko (prboom)
// Copyright (C) 1999-2019 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 r_fps.h
/// \brief Uncapped framerate stuff.
#ifndef __R_FPS_H__
#define __R_FPS_H__
#include "m_fixed.h"
#include "p_local.h"
#include "r_state.h"
#include "m_perfstats.h" // ps_metric_t
extern consvar_t cv_fpscap;
extern ps_metric_t ps_interp_frac;
extern ps_metric_t ps_interp_lag;
UINT32 R_GetFramerateCap(void);
boolean R_UsingFrameInterpolation(void);
enum viewcontext_e
{
VIEWCONTEXT_PLAYER1 = 0,
VIEWCONTEXT_PLAYER2,
VIEWCONTEXT_SKY1,
VIEWCONTEXT_SKY2
};
typedef struct {
fixed_t x;
fixed_t y;
fixed_t z;
boolean sky;
sector_t *sector;
player_t *player;
angle_t angle;
angle_t aim;
fixed_t cos;
fixed_t sin;
mobj_t *mobj;
} viewvars_t;
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);
// 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

@ -35,6 +35,7 @@
#include "r_portal.h"
#include "r_main.h"
#include "i_system.h" // I_GetPreciseTime
#include "r_fps.h" // Frame interpolation/uncapped
#ifdef HWRENDER
#include "hardware/hw_main.h"
@ -75,6 +76,10 @@ sector_t *viewsector;
player_t *viewplayer;
mobj_t *r_viewmobj;
fixed_t rendertimefrac;
fixed_t renderdeltatics;
boolean renderisnewtic;
//
// precalculated math tables
//
@ -1084,41 +1089,6 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y)
//
// R_SetupFrame
//
// recalc necessary stuff for mouseaiming
// slopes are already calculated for the full possible view (which is 4*viewheight).
// 18/08/18: (No it's actually 16*viewheight, thanks Jimita for finding this out)
static void R_SetupFreelook(player_t *player, boolean skybox)
{
#ifndef HWRENDER
(void)player;
(void)skybox;
#endif
// clip it in the case we are looking a hardware 90 degrees full aiming
// (lmps, network and use F12...)
if (rendermode == render_soft
#ifdef HWRENDER
|| (rendermode == render_opengl
&& (cv_glshearing.value == 1
|| (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox))))
#endif
)
{
G_SoftwareClipAimingPitch((INT32 *)&aimingangle);
}
centeryfrac = (viewheight/2)<<FRACBITS;
if (rendermode == render_soft)
centeryfrac += FixedMul(AIMINGTODY(aimingangle), FixedDiv(viewwidth<<FRACBITS, BASEVIDWIDTH<<FRACBITS));
centery = FixedInt(FixedRound(centeryfrac));
if (rendermode == render_soft)
yslope = &yslopetab[viewheight*8 - centery];
}
void R_SetupFrame(player_t *player)
{
camera_t *thiscam;
@ -1129,11 +1099,13 @@ void R_SetupFrame(player_t *player)
{
thiscam = &camera2;
chasecam = (cv_chasecam2.value != 0);
R_SetViewContext(VIEWCONTEXT_PLAYER2);
}
else
{
thiscam = &camera;
chasecam = (cv_chasecam.value != 0);
R_SetViewContext(VIEWCONTEXT_PLAYER1);
}
if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || tutorialmode)
@ -1149,81 +1121,83 @@ void R_SetupFrame(player_t *player)
else if (!chasecam)
thiscam->chase = false;
newview->sky = false;
if (player->awayviewtics)
{
// cut-away view stuff
r_viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN
I_Assert(r_viewmobj != NULL);
viewz = r_viewmobj->z + 20*FRACUNIT;
aimingangle = player->awayviewaiming;
viewangle = r_viewmobj->angle;
newview->z = r_viewmobj->z + 20*FRACUNIT;
newview->aim = player->awayviewaiming;
newview->angle = r_viewmobj->angle;
}
else if (!player->spectator && chasecam)
// use outside cam view
{
r_viewmobj = NULL;
viewz = thiscam->z + (thiscam->height>>1);
aimingangle = thiscam->aiming;
viewangle = thiscam->angle;
newview->z = thiscam->z + (thiscam->height>>1);
newview->aim = thiscam->aiming;
newview->angle = thiscam->angle;
}
else
// use the player's eyes view
{
viewz = player->viewz;
newview->z = player->viewz;
r_viewmobj = player->mo;
I_Assert(r_viewmobj != NULL);
aimingangle = player->aiming;
viewangle = r_viewmobj->angle;
newview->aim = player->aiming;
newview->angle = r_viewmobj->angle;
if (!demoplayback && player->playerstate != PST_DEAD)
{
if (player == &players[consoleplayer])
{
viewangle = localangle; // WARNING: camera uses this
aimingangle = localaiming;
newview->angle = localangle; // WARNING: camera uses this
newview->aim = localaiming;
}
else if (player == &players[secondarydisplayplayer])
{
viewangle = localangle2;
aimingangle = localaiming2;
newview->angle = localangle2;
newview->aim = localaiming2;
}
}
}
viewz += quake.z;
newview->z += quake.z;
viewplayer = player;
newview->player = player;
if (chasecam && !player->awayviewtics && !player->spectator)
{
viewx = thiscam->x;
viewy = thiscam->y;
viewx += quake.x;
viewy += quake.y;
newview->x = thiscam->x;
newview->y = thiscam->y;
newview->x += quake.x;
newview->y += quake.y;
if (thiscam->subsector)
viewsector = thiscam->subsector->sector;
newview->sector = thiscam->subsector->sector;
else
viewsector = R_PointInSubsector(viewx, viewy)->sector;
newview->sector = R_PointInSubsector(newview->x, newview->y)->sector;
}
else
{
viewx = r_viewmobj->x;
viewy = r_viewmobj->y;
viewx += quake.x;
viewy += quake.y;
newview->x = r_viewmobj->x;
newview->y = r_viewmobj->y;
newview->x += quake.x;
newview->y += quake.y;
if (r_viewmobj->subsector)
viewsector = r_viewmobj->subsector->sector;
newview->sector = r_viewmobj->subsector->sector;
else
viewsector = R_PointInSubsector(viewx, viewy)->sector;
newview->sector = R_PointInSubsector(newview->x, newview->y)->sector;
}
viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
// newview->sin = FINESINE(viewangle>>ANGLETOFINESHIFT);
// newview->cos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
R_SetupFreelook(player, false);
R_InterpolateView(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT);
}
void R_SkyboxFrame(player_t *player)
@ -1232,11 +1206,18 @@ void R_SkyboxFrame(player_t *player)
if (splitscreen && player == &players[secondarydisplayplayer]
&& player != &players[consoleplayer])
{
thiscam = &camera2;
R_SetViewContext(VIEWCONTEXT_SKY2);
}
else
{
thiscam = &camera;
R_SetViewContext(VIEWCONTEXT_SKY1);
}
// cut-away view stuff
newview->sky = true;
r_viewmobj = skyboxmo[0];
#ifdef PARANOIA
if (!r_viewmobj)
@ -1247,39 +1228,39 @@ void R_SkyboxFrame(player_t *player)
#endif
if (player->awayviewtics)
{
aimingangle = player->awayviewaiming;
viewangle = player->awayviewmobj->angle;
newview->aim = player->awayviewaiming;
newview->angle = player->awayviewmobj->angle;
}
else if (thiscam->chase)
{
aimingangle = thiscam->aiming;
viewangle = thiscam->angle;
newview->aim = thiscam->aiming;
newview->angle = thiscam->angle;
}
else
{
aimingangle = player->aiming;
viewangle = player->mo->angle;
newview->aim = player->aiming;
newview->angle = player->mo->angle;
if (!demoplayback && player->playerstate != PST_DEAD)
{
if (player == &players[consoleplayer])
{
viewangle = localangle; // WARNING: camera uses this
aimingangle = localaiming;
newview->angle = localangle; // WARNING: camera uses this
newview->aim = localaiming;
}
else if (player == &players[secondarydisplayplayer])
{
viewangle = localangle2;
aimingangle = localaiming2;
newview->angle = localangle2;
newview->aim = localaiming2;
}
}
}
viewangle += r_viewmobj->angle;
newview->angle += r_viewmobj->angle;
viewplayer = player;
newview->player = player;
viewx = r_viewmobj->x;
viewy = r_viewmobj->y;
viewz = r_viewmobj->z; // 26/04/17: use actual Z position instead of spawnpoint angle!
newview->x = r_viewmobj->x;
newview->y = r_viewmobj->y;
newview->z = r_viewmobj->z; // 26/04/17: use actual Z position instead of spawnpoint angle!
if (mapheaderinfo[gamemap-1])
{
@ -1321,56 +1302,75 @@ void R_SkyboxFrame(player_t *player)
if (r_viewmobj->angle == 0)
{
viewx += x;
viewy += y;
newview->x += x;
newview->y += y;
}
else if (r_viewmobj->angle == ANGLE_90)
{
viewx -= y;
viewy += x;
newview->x -= y;
newview->y += x;
}
else if (r_viewmobj->angle == ANGLE_180)
{
viewx -= x;
viewy -= y;
newview->x -= x;
newview->y -= y;
}
else if (r_viewmobj->angle == ANGLE_270)
{
viewx += y;
viewy -= x;
newview->x += y;
newview->y -= x;
}
else
{
angle_t ang = r_viewmobj->angle>>ANGLETOFINESHIFT;
viewx += FixedMul(x,FINECOSINE(ang)) - FixedMul(y, FINESINE(ang));
viewy += FixedMul(x, FINESINE(ang)) + FixedMul(y,FINECOSINE(ang));
newview->x += FixedMul(x,FINECOSINE(ang)) - FixedMul(y, FINESINE(ang));
newview->y += FixedMul(x, FINESINE(ang)) + FixedMul(y,FINECOSINE(ang));
}
}
if (mh->skybox_scalez > 0)
viewz += campos.z / mh->skybox_scalez;
newview->z += campos.z / mh->skybox_scalez;
else if (mh->skybox_scalez < 0)
viewz += campos.z * -mh->skybox_scalez;
newview->z += campos.z * -mh->skybox_scalez;
}
if (r_viewmobj->subsector)
viewsector = r_viewmobj->subsector->sector;
newview->sector = r_viewmobj->subsector->sector;
else
viewsector = R_PointInSubsector(viewx, viewy)->sector;
newview->sector = R_PointInSubsector(newview->x, newview->y)->sector;
viewsin = FINESINE(viewangle>>ANGLETOFINESHIFT);
viewcos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
// newview->sin = FINESINE(viewangle>>ANGLETOFINESHIFT);
// newview->cos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
R_SetupFreelook(player, true);
R_InterpolateView(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT);
}
boolean R_ViewpointHasChasecam(player_t *player)
{
camera_t *thiscam;
boolean chasecam = false;
if (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer])
{
thiscam = &camera2;
chasecam = (cv_chasecam2.value != 0);
R_SetViewContext(VIEWCONTEXT_PLAYER2);
if (thiscam->reset)
{
R_ResetViewInterpolation(2);
thiscam->reset = false;
}
}
else
{
thiscam = &camera;
chasecam = (cv_chasecam.value != 0);
R_SetViewContext(VIEWCONTEXT_PLAYER1);
if (thiscam->reset)
{
R_ResetViewInterpolation(1);
thiscam->reset = false;
}
}
if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || tutorialmode)
chasecam = true; // force chasecam on
@ -1642,4 +1642,7 @@ void R_RegisterEngineStuff(void)
CV_RegisterVar(&cv_maxportals);
CV_RegisterVar(&cv_movebob);
// Frame interpolation/uncapped
CV_RegisterVar(&cv_fpscap);
}

View file

@ -35,6 +35,13 @@ extern fixed_t fovtan;
extern size_t validcount, linecount, loopcount, framecount;
// The fraction of a tic being drawn (for interpolation between two tics)
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.
// Used for z-depth cuing per column/row,

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"
@ -1134,13 +1135,33 @@ static void R_SplitSprite(vissprite_t *sprite)
//
fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope)
{
fixed_t halfHeight;
boolean isflipped = thing->eflags & MFE_VERTICALFLIP;
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;
#define CHECKZ (isflipped ? z > thing->z+thing->height/2 && z < groundz : z < thing->z+thing->height/2 && z > groundz)
// 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)
{
@ -1151,7 +1172,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope)
if (sector->heightsec != -1)
z = isflipped ? sectors[sector->heightsec].ceilingheight : sectors[sector->heightsec].floorheight;
else
z = isflipped ? P_GetSectorCeilingZAt(sector, thing->x, thing->y) : P_GetSectorFloorZAt(sector, thing->x, thing->y);
z = isflipped ? P_GetSectorCeilingZAt(sector, interp.x, interp.y) : P_GetSectorFloorZAt(sector, interp.x, interp.y);
if CHECKZ
{
@ -1165,7 +1186,7 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope)
if (!(rover->fofflags & FOF_EXISTS) || !(rover->fofflags & FOF_RENDERPLANES) || (rover->alpha < 90 && !(rover->fofflags & FOF_SWIMMABLE)))
continue;
z = isflipped ? P_GetFFloorBottomZAt(rover, thing->x, thing->y) : P_GetFFloorTopZAt(rover, thing->x, thing->y);
z = isflipped ? P_GetFFloorBottomZAt(rover, interp.x, interp.y) : P_GetFFloorTopZAt(rover, interp.x, interp.y);
if CHECKZ
{
groundz = z;
@ -1174,72 +1195,39 @@ fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope)
}
}
if (isflipped ? (thing->ceilingz < groundz - (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2)))
: (thing->floorz > groundz + (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2))))
// Check polyobjects and see if groundz needs to be altered
{
groundz = isflipped ? thing->ceilingz : thing->floorz;
// This isn't very precise, but the precise method was far too slow.
// (Polies are just naturally pretty flickery anyway :P)
polyobj_t *po = interp.subsector->polyList;
while (po)
{
if (!(po->flags & POF_RENDERPLANES) || !P_MobjInsidePolyobj(po, thing))
{
po = (polyobj_t *)(po->link.next);
continue;
}
// We're inside it! Yess...
z = isflipped ? po->lines[0]->backsector->floorheight : po->lines[0]->backsector->ceilingheight;
if CHECKZ
{
groundz = z;
groundslope = NULL;
}
po = (polyobj_t *)(po->link.next);
}
}
if (isflipped ? (ceilingz < groundz - (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2)))
: (floorz > groundz + (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2))))
{
groundz = isflipped ? ceilingz : floorz;
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)(thing->x - thing->radius - bmaporgx)>>MAPBLOCKSHIFT;
xh = (unsigned)(thing->x + thing->radius - bmaporgx)>>MAPBLOCKSHIFT;
yl = (unsigned)(thing->y - thing->radius - bmaporgy)>>MAPBLOCKSHIFT;
yh = (unsigned)(thing->y + 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 < thing->z+thing->height/2 && z > groundz)
{
groundz = z;
groundslope = NULL;
}
}
plink = (polymaplink_t *)(plink->link.next);
}
}
}
#endif
if (shadowslope != NULL)
*shadowslope = groundslope;
@ -1252,9 +1240,24 @@ static void R_SkewShadowSprite(
fixed_t groundz, INT32 spriteheight, fixed_t scalemul,
fixed_t *shadowyscale, fixed_t *shadowskew)
{
// haha let's try some dumb stuff
fixed_t xslope, zslope;
angle_t sloperelang = (R_PointToAngle(thing->x, thing->y) - 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);
@ -1282,11 +1285,21 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
fixed_t groundz;
pslope_t *groundslope;
boolean isflipped = thing->eflags & MFE_VERTICALFLIP;
interpmobjstate_t interp = {0};
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);
}
heightsec = thing->subsector->sector->heightsec;
if (viewplayer->mo && viewplayer->mo->subsector)
phs = viewplayer->mo->subsector->sector->heightsec;
@ -1305,7 +1318,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
return;
}
floordiff = abs((isflipped ? thing->height : 0) + thing->z - groundz);
floordiff = abs((isflipped ? thing->height : 0) + interp.z - groundz);
trans = floordiff / (100*FRACUNIT) + 3;
if (trans >= 9) return;
@ -1345,11 +1358,11 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
shadow->mobjflags = 0;
shadow->sortscale = vis->sortscale;
shadow->dispoffset = vis->dispoffset - 5;
shadow->gx = thing->x;
shadow->gy = thing->y;
shadow->gx = interp.x;
shadow->gy = interp.y;
shadow->gzt = (isflipped ? shadow->pzt : shadow->pz) + 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;
@ -1363,7 +1376,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
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);
@ -1391,7 +1404,7 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale,
// 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;
@ -1469,7 +1482,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
@ -1481,9 +1494,24 @@ static void R_ProjectSprite(mobj_t *thing)
INT32 rollangle = 0;
#endif
// uncapped/interpolation
interpmobjstate_t interp = {0};
// do interpolation
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(oldthing, rendertimefrac, &interp);
}
else
{
R_InterpolateMobjState(oldthing, FRACUNIT, &interp);
}
this_scale = interp.scale;
// transform the origin point
tr_x = thing->x - viewx;
tr_y = thing->y - viewy;
tr_x = interp.x - viewx;
tr_y = interp.y - viewy;
basetz = tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance
@ -1560,7 +1588,7 @@ static void R_ProjectSprite(mobj_t *thing)
if (sprframe->rotate != SRF_SINGLE || papersprite)
{
ang = R_PointToAngle (thing->x, thing->y) - (thing->player ? thing->player->drawangle : thing->angle);
ang = R_PointToAngle (interp.x, interp.y) - interp.angle;
if (mirrored)
ang = InvAngle(ang);
}
@ -1575,7 +1603,7 @@ static void R_ProjectSprite(mobj_t *thing)
else
{
// choose a different rotation based on player view
//ang = R_PointToAngle (thing->x, thing->y) - thing->angle;
//ang = R_PointToAngle (interp.x, interp.y) - interpangle;
if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right
rot = 6; // F7 slot
@ -1644,15 +1672,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
{
@ -1661,8 +1689,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)
@ -1684,8 +1712,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);
@ -1701,7 +1729,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);
@ -1789,6 +1817,7 @@ 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;
@ -1796,8 +1825,17 @@ static void R_ProjectSprite(mobj_t *thing)
if (! R_ThingVisible(thing))
return;
tr_x = (thing->x + sort_x) - viewx;
tr_y = (thing->y + sort_y) - viewy;
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(thing, rendertimefrac, &tracer_interp);
}
else
{
R_InterpolateMobjState(thing, FRACUNIT, &tracer_interp);
}
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, tz);
@ -1812,8 +1850,8 @@ static void R_ProjectSprite(mobj_t *thing)
}
else 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);
sortscale = FixedDiv(projectiony, sort_z);
}
@ -1821,8 +1859,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, sort_z);
}
@ -1833,7 +1871,7 @@ static void R_ProjectSprite(mobj_t *thing)
if (x2 < portalclipstart || x1 >= portalclipend)
return;
if (P_PointOnLineSide(thing->x, thing->y, portalclipline) != 0)
if (P_PointOnLineSide(interp.x, interp.y, portalclipline) != 0)
return;
}
@ -1868,6 +1906,16 @@ static void R_ProjectSprite(mobj_t *thing)
if (shadoweffects)
{
mobj_t *caster = thing->target;
interpmobjstate_t casterinterp = {};
if (R_UsingFrameInterpolation() && !paused)
{
R_InterpolateMobjState(caster, rendertimefrac, &casterinterp);
}
else
{
R_InterpolateMobjState(caster, FRACUNIT, &casterinterp);
}
if (caster && !P_MobjWasRemoved(caster))
{
@ -1876,9 +1924,9 @@ static void R_ProjectSprite(mobj_t *thing)
if (abs(groundz-viewz)/tz > 4)
return; // Prevent stretchy shadows and possible crashes
floordiff = abs((isflipped ? caster->height : 0) + caster->z - groundz);
floordiff = abs((isflipped ? caster->height : 0) + casterinterp.z - groundz);
trans += ((floordiff / (100*FRACUNIT)) + 3);
shadowscale = FixedMul(FRACUNIT - floordiff/640, caster->scale);
shadowscale = FixedMul(FRACUNIT - floordiff/640, casterinterp.scale);
}
else
trans += 3;
@ -1907,7 +1955,7 @@ static void R_ProjectSprite(mobj_t *thing)
{
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;
@ -1922,12 +1970,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 = oldthing->z + 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 = oldthing->z + 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));
}
}
@ -1946,7 +1994,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], thing->x, thing->y);
fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], interp.x, interp.y);
if (h <= top) {
light = lightnum - 1;
break;
@ -1972,7 +2020,7 @@ static void R_ProjectSprite(mobj_t *thing)
if (heightsec != -1 && phs != -1) // only clip things which are in special sectors
{
fixed_t top = gzt;
fixed_t bottom = thing->z;
fixed_t bottom = interp.z;
if (splat)
top = bottom;
@ -1996,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 = thing->x;
vis->gy = thing->y;
vis->gx = interp.x;
vis->gy = interp.y;
vis->gz = gz;
vis->gzt = gzt;
vis->thingheight = thing->height;
vis->pz = thing->z;
vis->pz = interp.z;
vis->pzt = vis->pz + vis->thingheight;
vis->texturemid = FixedDiv(gzt - viewz, spriteyscale);
vis->scalestep = scalestep;
@ -2036,7 +2084,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;
@ -2144,9 +2192,22 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
//SoM: 3/17/2000
fixed_t gz, gzt;
// 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 = thing->x - viewx;
tr_y = thing->y - viewy;
tr_x = interp.x - viewx;
tr_y = interp.y - viewy;
tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance
@ -2210,13 +2271,13 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
if (x2 < portalclipstart || x1 >= portalclipend)
return;
if (P_PointOnLineSide(thing->x, thing->y, portalclipline) != 0)
if (P_PointOnLineSide(interp.x, interp.y, portalclipline) != 0)
return;
}
//SoM: 3/17/2000: Disregard sprites that are out of view..
gzt = thing->z + spritecachedinfo[lump].topoffset;
gzt = interp.z + spritecachedinfo[lump].topoffset;
gz = gzt - spritecachedinfo[lump].height;
if (thing->subsector->sector->cullheight)
@ -2229,12 +2290,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 = thing->x;
vis->gy = thing->y;
vis->gx = interp.x;
vis->gy = interp.y;
vis->gz = gz;
vis->gzt = gzt;
vis->thingheight = 4*FRACUNIT;
vis->pz = thing->z;
vis->pz = interp.z;
vis->pzt = vis->pz + vis->thingheight;
vis->texturemid = vis->gzt - viewz;
vis->scalestep = 0;

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"
@ -33,12 +34,15 @@
#include "s_sound.h" // ditto
#include "g_game.h" // ditto
#include "p_local.h" // P_AutoPause()
#ifdef HWRENDER
#include "hardware/hw_main.h"
#include "hardware/hw_light.h"
#include "hardware/hw_model.h"
#endif
// SRB2Kart
#include "r_fps.h" // R_GetFramerateCap
#if defined (USEASM) && !defined (NORUSEASM)//&& (!defined (_MSC_VER) || (_MSC_VER <= 1200))
#define RUSEASM //MSC.NET can't patch itself
@ -67,6 +71,7 @@ static CV_PossibleValue_t scr_depth_cons_t[] = {{8, "8 bits"}, {16, "16 bits"},
consvar_t cv_scr_width = CVAR_INIT ("scr_width", "1280", CV_SAVE, CV_Unsigned, NULL);
consvar_t cv_scr_height = CVAR_INIT ("scr_height", "800", CV_SAVE, CV_Unsigned, NULL);
consvar_t cv_scr_depth = CVAR_INIT ("scr_depth", "16 bits", CV_SAVE, scr_depth_cons_t, NULL);
consvar_t cv_renderview = CVAR_INIT ("renderview", "On", 0, CV_OnOff, NULL);
CV_PossibleValue_t cv_renderer_t[] = {
@ -447,46 +452,117 @@ boolean SCR_IsAspectCorrect(INT32 width, INT32 height)
);
}
// XMOD FPS display
// moved out of os-specific code for consistency
static boolean fpsgraph[TICRATE];
static tic_t lasttic;
double averageFPS = 0.0f;
#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)
{
precise_t fps_finish = 0;
double frameElapsed = 0.0;
if (fps_init == false)
{
fps_enter = I_GetPreciseTime();
fps_init = true;
}
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 i;
fps_samples[sampleIndex] = frameElapsed;
sampleIndex++;
if (sampleIndex >= NUM_FPS_SAMPLES)
sampleIndex = 0;
averageFPS = 0.0;
for (i = 0; i < NUM_FPS_SAMPLES; i++)
{
averageFPS += fps_samples[i];
}
if (averageFPS > 0.0)
{
averageFPS = 1.0 / (averageFPS / NUM_FPS_SAMPLES);
}
}
while (updateElapsed >= FPS_SAMPLE_RATE)
{
updateElapsed -= FPS_SAMPLE_RATE;
}
#else
// Direct, unsampled counter.
averageFPS = 1.0 / frameElapsed;
#endif
}
void SCR_DisplayTicRate(void)
{
tic_t i;
tic_t ontic = I_GetTime();
tic_t totaltics = 0;
INT32 ticcntcolor = 0;
const INT32 h = vid.height-(8*vid.dupy);
UINT32 cap = R_GetFramerateCap();
double fps = round(averageFPS);
if (gamestate == GS_NULL)
return;
for (i = lasttic + 1; i < TICRATE+lasttic && i < ontic; ++i)
fpsgraph[i % TICRATE] = false;
fpsgraph[ontic % TICRATE] = true;
for (i = 0;i < TICRATE;++i)
if (fpsgraph[i])
++totaltics;
if (totaltics <= TICRATE/2) ticcntcolor = V_REDMAP;
else if (totaltics == TICRATE) ticcntcolor = V_GREENMAP;
if (cv_ticrate.value == 2) // compact counter
V_DrawString(vid.width-(16*vid.dupx), h,
ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%02d", totaltics));
else if (cv_ticrate.value == 1) // full counter
if (cap > 0)
{
V_DrawString(vid.width-(72*vid.dupx), h,
V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:");
V_DrawString(vid.width-(40*vid.dupx), h,
ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%02d/%02u", totaltics, TICRATE));
if (fps <= cap / 2.0) ticcntcolor = V_REDMAP;
else if (fps <= cap * 0.90) ticcntcolor = V_YELLOWMAP;
else ticcntcolor = V_GREENMAP;
}
else
{
ticcntcolor = V_GREENMAP;
}
lasttic = ontic;
if (cv_ticrate.value == 2) // compact counter
{
V_DrawRightAlignedString(vid.width, h,
ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, va("%04.2f", averageFPS)); // use averageFPS directly
}
else if (cv_ticrate.value == 1) // full counter
{
const char *drawnstr;
INT32 width;
// The highest assignable cap is < 1000, so 3 characters is fine.
if (cap > 0)
drawnstr = va("%3.0f/%3u", fps, cap);
else
drawnstr = va("%4.2f", averageFPS);
width = V_StringWidth(drawnstr, V_NOSCALESTART);
V_DrawString(vid.width - ((7 * 8 * vid.dupx) + V_StringWidth("FPS: ", V_NOSCALESTART)), h,
V_YELLOWMAP|V_NOSCALESTART|V_USERHUDTRANS, "FPS:");
V_DrawString(vid.width - width, h,
ticcntcolor|V_NOSCALESTART|V_USERHUDTRANS, drawnstr);
}
}
void SCR_DisplayLocalPing(void)

View file

@ -182,6 +182,8 @@ extern viddef_t vid;
extern INT32 setmodeneeded; // mode number to set if needed, or 0
extern UINT8 setrenderneeded;
extern double averageFPS;
void SCR_ChangeRenderer(void);
extern CV_PossibleValue_t cv_renderer_t[];
@ -192,6 +194,7 @@ extern UINT8 *scr_borderpatch; // patch used to fill the view borders
extern consvar_t cv_scr_width, cv_scr_height, cv_scr_depth, cv_renderview, cv_renderer, cv_fullscreen;
// 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);
@ -211,6 +214,8 @@ void SCR_CheckDefaultMode(void);
// Set the mode number which is saved in the config
void SCR_SetDefaultMode(void);
void SCR_CalculateFPS(void);
FUNCMATH boolean SCR_IsAspectCorrect(INT32 width, INT32 height);
// move out to main code for consistency

View file

@ -181,6 +181,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"
@ -196,7 +197,8 @@ static char returnWadPath[256];
#include "../m_argv.h"
#include "../m_menu.h"
#include "../r_main.h" // Frame interpolation/uncapped
#include "../r_fps.h"
#ifdef MAC_ALERT
#include "macosx/mac_alert.h"
@ -2153,52 +2155,78 @@ ticcmd_t *I_BaseTiccmd2(void)
static Uint64 timer_frequency;
static double tic_frequency;
static Uint64 tic_epoch;
tic_t I_GetTime(void)
{
static double elapsed;
const Uint64 now = SDL_GetPerformanceCounter();
elapsed += (now - tic_epoch) / tic_frequency;
tic_epoch = now; // moving epoch
return (tic_t)elapsed;
}
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;
I_InitFrameTime(0, R_GetFramerateCap());
elapsed_frames = 0.0;
}
void I_Sleep(void)
void I_Sleep(UINT32 ms)
{
if (cv_sleep.value != -1)
SDL_Delay(cv_sleep.value);
SDL_Delay(ms);
}
#ifdef NEWSIGNALHANDLER

View file

@ -1178,12 +1178,15 @@ void I_UpdateNoBlit(void)
// from PrBoom's src/SDL/i_video.c
static inline boolean I_SkipFrame(void)
{
#if 0
#if 1
// While I fixed the FPS counter bugging out with this,
// I actually really like being able to pause and
// use perfstats to measure rendering performance
// without game logic changes.
return false;
#else
static boolean skip = false;
if (rendermode != render_soft)
return false;
skip = !skip;
switch (gamestate)
@ -1199,17 +1202,20 @@ static inline boolean I_SkipFrame(void)
return false;
}
#endif
return false;
}
//
// I_FinishUpdate
//
static SDL_Rect src_rect = { 0, 0, 0, 0 };
void I_FinishUpdate(void)
{
if (rendermode == render_none)
return; //Alam: No software or OpenGl surface
SCR_CalculateFPS();
if (I_SkipFrame())
return;
@ -1228,27 +1234,22 @@ void I_FinishUpdate(void)
if (rendermode == render_soft && screens[0])
{
SDL_Rect rect;
rect.x = 0;
rect.y = 0;
rect.w = vid.width;
rect.h = vid.height;
if (!bufSurface) //Double-Check
{
Impl_VideoSetupSDLBuffer();
}
if (bufSurface)
{
SDL_BlitSurface(bufSurface, NULL, vidSurface, &rect);
SDL_BlitSurface(bufSurface, &src_rect, vidSurface, &src_rect);
// Fury -- there's no way around UpdateTexture, the GL backend uses it anyway
SDL_LockSurface(vidSurface);
SDL_UpdateTexture(texture, &rect, vidSurface->pixels, vidSurface->pitch);
SDL_UpdateTexture(texture, &src_rect, vidSurface->pixels, vidSurface->pitch);
SDL_UnlockSurface(vidSurface);
}
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, texture, NULL, NULL);
SDL_RenderCopy(renderer, texture, &src_rect, NULL);
SDL_RenderPresent(renderer);
}
#ifdef HWRENDER
@ -1257,6 +1258,7 @@ void I_FinishUpdate(void)
OglSdlFinishUpdate(cv_vidwait.value);
}
#endif
exposevideo = SDL_FALSE;
}
@ -1473,8 +1475,15 @@ static SDL_bool Impl_CreateContext(void)
int flags = 0; // Use this to set SDL_RENDERER_* flags now
if (usesdl2soft)
flags |= SDL_RENDERER_SOFTWARE;
#if 0
// This shit is BROKEN.
// - The version of SDL we're using cannot toggle VSync at runtime. We'll need a new SDL version implemented to have this work properly.
// - cv_vidwait is initialized before config is loaded, so it's forced to default value at runtime, and forced off when switching. The config loading code would need restructured.
// - With both this & frame interpolation on, I_FinishUpdate takes x10 longer. At this point, it is simpler to use a standard FPS cap.
// So you can probably guess why I'm kinda over this, I'm just disabling it.
else if (cv_vidwait.value)
flags |= SDL_RENDERER_PRESENTVSYNC;
#endif
if (!renderer)
renderer = SDL_CreateRenderer(window, -1, flags);
@ -1593,6 +1602,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();
@ -1610,6 +1640,11 @@ INT32 VID_SetMode(INT32 modeNum)
vid.modenum = modeNum;
//Impl_SetWindowName("SRB2 "VERSIONSTRING);
src_rect.w = vid.width;
src_rect.h = vid.height;
refresh_rate = VID_GetRefreshRate();
VID_CheckRenderer();
return SDL_TRUE;
}
@ -1961,3 +1996,13 @@ void I_GetCursorPosition(INT32 *x, INT32 *y)
{
SDL_GetMouseState(x, y);
}
UINT32 I_GetRefreshRate(void)
{
// 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

@ -43,8 +43,11 @@
#endif
#include "lua_hud.h"
#include "lua_hudlib_drawlist.h"
#include "lua_hook.h"
#include "r_fps.h"
UINT16 objectsdrawn = 0;
//
@ -161,6 +164,9 @@ hudinfo_t hudinfo[NUMHUDITEMS] =
{ 288, 176, V_SNAPTORIGHT|V_SNAPTOBOTTOM}, // HUD_POWERUPS
};
static huddrawlist_h luahuddrawlist_game;
static huddrawlist_h luahuddrawlist_titlecard;
//
// STATUS BAR CODE
//
@ -420,6 +426,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.
@ -1402,7 +1411,12 @@ void ST_drawTitleCard(void)
lt_lasttic = lt_ticker;
luahook:
LUA_HUDHOOK(titlecard);
if (renderisnewtic)
{
LUA_HUD_ClearDrawList(luahuddrawlist_titlecard);
LUA_HUDHOOK(titlecard, luahuddrawlist_titlecard);
}
LUA_HUD_DrawList(luahuddrawlist_titlecard);
}
//
@ -2526,7 +2540,7 @@ static void ST_doHuntIconsAndSound(void)
interval = newinterval;
}
if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0)
if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0 && renderisnewtic)
S_StartSound(NULL, sfx_emfind);
}
@ -2588,7 +2602,7 @@ static void ST_doItemFinderIconsAndSound(void)
}
if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0)
if (!(P_AutoPause() || paused) && interval > 0 && leveltime && leveltime % interval == 0 && renderisnewtic)
S_StartSound(NULL, sfx_emfind);
}
@ -2742,7 +2756,12 @@ static void ST_overlayDrawer(void)
ST_drawPowerupHUD(); // same as it ever was...
if (!(netgame || multiplayer) || !hu_showscores)
LUA_HUDHOOK(game);
{
if (renderisnewtic)
{
LUA_HUDHOOK(game, luahuddrawlist_game);
}
}
// draw level title Tails
if (stagetitle && (!WipeInAction) && (!WipeStageTitle))
@ -2820,6 +2839,10 @@ void ST_Drawer(void)
if (st_overlay)
{
if (renderisnewtic)
{
LUA_HUD_ClearDrawList(luahuddrawlist_game);
}
// No deadview!
stplyr = &players[displayplayer];
ST_overlayDrawer();
@ -2829,5 +2852,7 @@ void ST_Drawer(void)
stplyr = &players[secondarydisplayplayer];
ST_overlayDrawer();
}
LUA_HUD_DrawList(luahuddrawlist_game);
}
}

View file

@ -59,6 +59,7 @@
#include "r_textures.h"
#include "r_patch.h"
#include "r_picformats.h"
#include "i_time.h"
#include "i_system.h"
#include "i_video.h" // rendermode
#include "md5.h"

View file

@ -38,6 +38,7 @@
#include "lua_hook.h" // IntermissionThinker hook
#include "lua_hud.h"
#include "lua_hudlib_drawlist.h"
#ifdef HWRENDER
#include "hardware/hw_main.h"
@ -83,6 +84,10 @@ typedef union
INT32 passedx3;
INT32 passedx4;
INT32 emeraldbounces;
INT32 emeraldmomy;
INT32 emeraldy;
y_bonus_t bonuses[2];
patch_t *bonuspatches[2];
@ -161,6 +166,8 @@ static INT32 endtic = -1;
intertype_t intertype = int_none;
intertype_t intermissiontypes[NUMGAMETYPES];
static huddrawlist_h luahuddrawlist_intermission;
static void Y_RescaleScreenBuffer(void);
static void Y_AwardCoopBonuses(void);
static void Y_AwardSpecialStageBonus(void);
@ -429,7 +436,13 @@ void Y_IntermissionDrawer(void)
else if (bgtile)
V_DrawPatchFill(bgtile);
LUA_HUDHOOK(intermission);
if (renderisnewtic)
{
LUA_HUD_ClearDrawList(luahuddrawlist_intermission);
LUA_HUDHOOK(intermission, luahuddrawlist_intermission);
}
LUA_HUD_DrawList(luahuddrawlist_intermission);
if (!LUA_HudEnabled(hud_intermissiontally))
goto skiptallydrawer;
@ -646,7 +659,6 @@ void Y_IntermissionDrawer(void)
}
// draw the emeralds
//if (intertic & 1)
if (LUA_HudEnabled(hud_intermissionemeralds))
{
boolean drawthistic = !(ALL7EMERALDS(emeralds) && (intertic & 1));
@ -663,10 +675,6 @@ void Y_IntermissionDrawer(void)
}
else if (em < 7)
{
static UINT8 emeraldbounces = 0;
static INT32 emeraldmomy = 20;
static INT32 emeraldy = -40;
if (drawthistic)
for (i = 0; i < 7; ++i)
{
@ -677,45 +685,15 @@ void Y_IntermissionDrawer(void)
emeraldx = 152 + (em-3)*28;
if (intertic <= 1)
if (intertic > 1)
{
emeraldbounces = 0;
emeraldmomy = 20;
emeraldy = -40;
}
else
{
if (!stagefailed)
if (stagefailed && data.spec.emeraldy < (vid.height/vid.dupy)+16)
{
if (emeraldbounces < 3)
{
emeraldy += (++emeraldmomy);
if (emeraldy > 74)
{
S_StartSound(NULL, sfx_tink); // tink
emeraldbounces++;
emeraldmomy = -(emeraldmomy/2);
emeraldy = 74;
}
}
}
else
{
if (emeraldy < (vid.height/vid.dupy)+16)
{
emeraldy += (++emeraldmomy);
emeraldx += intertic - 6;
}
if (emeraldbounces < 1 && emeraldy > 74)
{
S_StartSound(NULL, sfx_shldls); // nope
emeraldbounces++;
emeraldmomy = -(emeraldmomy/2);
emeraldy = 74;
}
emeraldx += intertic - 6;
}
if (drawthistic)
V_DrawScaledPatch(emeraldx, emeraldy, 0, emeraldpics[0][em]);
V_DrawScaledPatch(emeraldx, data.spec.emeraldy, 0, emeraldpics[0][em]);
}
}
}
@ -1153,6 +1131,45 @@ void Y_Ticker(void)
S_ChangeMusicInternal("_clear", false); // don't loop it
tallydonetic = -1;
}
// emerald bounce
if (intertic <= 1)
{
data.spec.emeraldbounces = 0;
data.spec.emeraldmomy = 20;
data.spec.emeraldy = -40;
}
else
{
if (!stagefailed)
{
if (data.spec.emeraldbounces < 3)
{
data.spec.emeraldy += (++data.spec.emeraldmomy);
if (data.spec.emeraldy > 74)
{
S_StartSound(NULL, sfx_tink); // tink
data.spec.emeraldbounces++;
data.spec.emeraldmomy = -(data.spec.emeraldmomy/2);
data.spec.emeraldy = 74;
}
}
}
else
{
if (data.spec.emeraldy < (vid.height/vid.dupy)+16)
{
data.spec.emeraldy += (++data.spec.emeraldmomy);
}
if (data.spec.emeraldbounces < 1 && data.spec.emeraldy > 74)
{
S_StartSound(NULL, sfx_shldls); // nope
data.spec.emeraldbounces++;
data.spec.emeraldmomy = -(data.spec.emeraldmomy/2);
data.spec.emeraldy = 74;
}
}
}
if (intertic < 2*TICRATE) // TWO second pause before tally begins, thank you mazmazz
return;
@ -1583,6 +1600,9 @@ void Y_StartIntermission(void)
default:
break;
}
LUA_HUD_DestroyDrawList(luahuddrawlist_intermission);
luahuddrawlist_intermission = LUA_HUD_CreateDrawList();
}
//