Start adding view interpolation using code from duke3d

This commit is contained in:
nukeykt 2019-11-04 02:20:05 +09:00 committed by Christoph Oelckers
parent 6378082339
commit 4e21cf5cbf
7 changed files with 397 additions and 197 deletions

View file

@ -1817,7 +1817,7 @@ void FinishLevel()
WaitVBL();
RefreshBackground();
RefreshStatus();
DrawView();
DrawView(65536);
videoNextPage();
}
@ -1979,6 +1979,153 @@ void app_crashhandler(void)
void G_Polymer_UnInit(void) { }
static inline int32_t calc_smoothratio(ClockTicks totalclk, ClockTicks ototalclk)
{
// if (!((ud.show_help == 0 && (!g_netServer && ud.multimode < 2) && ((g_player[myconnectindex].ps->gm & MODE_MENU) == 0)) ||
// (g_netServer || ud.multimode > 1) ||
// ud.recstat == 2) ||
// ud.pause_on)
// {
// return 65536;
// }
if (bRecord || bPlayback)
return 65536;
int32_t rfreq = (refreshfreq != -1 ? refreshfreq : 60);
uint64_t elapsedFrames = tabledivide64(((uint64_t) (totalclk - ototalclk).toScale16()) * rfreq, 65536*120);
#if 0
//POGO: additional debug info for testing purposes
OSD_Printf("Elapsed frames: %" PRIu64 ", smoothratio: %" PRIu64 "\n", elapsedFrames, tabledivide64(65536*elapsedFrames*30, rfreq));
#endif
return clamp(tabledivide64(65536*elapsedFrames*30, rfreq), 0, 65536);
}
ClockTicks tclocks, tclocks2;
static void GameDisplay(void)
{
// End Section B
SetView1();
if (levelnum == kMap20)
{
LockEnergyTiles();
DoEnergyTile();
DrawClock();
}
auto smoothRatio = calc_smoothratio(totalclock, tclocks);
DrawView(smoothRatio);
UpdateMap();
if (bMapMode)
{
#if 0
if (bHiRes && nViewBottom > nMaskY)
{
videoSetViewableArea(nViewLeft, nViewTop, nViewRight, nMaskY);
DrawMap();
videoSetViewableArea(nViewLeft, nViewTop, nViewRight, nViewBottom);
}
else
{
DrawMap();
}
#else
// TODO: Map should not be drawn on top of status bar. Redraw status bar?
DrawMap();
#endif
}
videoNextPage();
}
static void GameMove(void)
{
FixPalette();
if (levelnum == kMap20)
{
if (lCountDown <= 0)
{
for (int i = 0; i < nTotalPlayers; i++) {
nPlayerLives[i] = 0;
}
DoFailedFinalScene();
levelnew = 100;
return;
}
// Pink section
lCountDown--;
DrawClock();
if (nRedTicks)
{
nRedTicks--;
if (nRedTicks <= 0) {
DoRedAlert(0);
}
nAlarmTicks--;
nButtonColor--;
if (nAlarmTicks <= 0) {
DoRedAlert(1);
}
}
}
// YELLOW SECTION
MoveThings();
if (totalvel[nLocalPlayer] == 0)
{
bobangle = 0;
}
else
{
bobangle += 56;
bobangle &= kAngleMask;
}
// loc_120E9:
totalmoves++;
moveframes--;
}
int32_t r_maxfps = 60;
int32_t r_maxfpsoffset = 0;
double g_frameDelay = 0.0;
int G_FPSLimit(void)
{
if (!r_maxfps)
return 1;
static double nextPageDelay;
static uint64_t lastFrameTicks;
uint64_t const frameTicks = timerGetTicksU64();
uint64_t const elapsedTime = frameTicks - lastFrameTicks;
double const dElapsedTime = elapsedTime;
if (dElapsedTime >= floor(nextPageDelay))
{
if (dElapsedTime <= nextPageDelay+g_frameDelay)
nextPageDelay += g_frameDelay-dElapsedTime;
lastFrameTicks = frameTicks;
return 1;
}
return 0;
}
int app_main(int argc, char const* const* argv)
{
char tempbuf[256];
@ -2031,7 +2178,6 @@ int app_main(int argc, char const* const* argv)
//int edi = esi;
int doTitle = kFalse; // REVERT kTrue;
int stopTitle = kFalse;
int tclocks, tclocks2;
levelnew = 1;
// REVERT - change back to kTrue
@ -2358,6 +2504,8 @@ int app_main(int argc, char const* const* argv)
if (enginePostInit())
ShutDown();
g_frameDelay = calcFrameDelay(r_maxfps + r_maxfpsoffset);
// loc_11745:
FadeOut(0);
// InstallEngine();
@ -2590,7 +2738,7 @@ LOOP3:
ResetMoveFifo();
moveframes = 0;
bInMove = kFalse;
tclocks = (int)totalclock;
tclocks = totalclock;
nPlayerDAng = 0;
lPlayerXVel = 0;
lPlayerYVel = 0;
@ -2604,7 +2752,7 @@ LOOP3:
mysetbrightness((uint8_t)nGamma);
//int edi = totalclock;
tclocks2 = (int)totalclock;
tclocks2 = totalclock;
CONTROL_BindsEnabled = 1;
// Game Loop
while (1)
@ -2631,209 +2779,168 @@ LOOP3:
nCDTrackLength = -1;
}
}
// End Section B
SetView1();
if (levelnum == kMap20)
{
LockEnergyTiles();
DoEnergyTile();
DrawClock();
}
DrawView();
UpdateMap();
if (bMapMode)
{
#if 0
if (bHiRes && nViewBottom > nMaskY)
{
videoSetViewableArea(nViewLeft, nViewTop, nViewRight, nMaskY);
DrawMap();
videoSetViewableArea(nViewLeft, nViewTop, nViewRight, nViewBottom);
}
else
{
DrawMap();
}
#else
// TODO: Map should not be drawn on top of status bar. Redraw status bar?
DrawMap();
#endif
}
videoNextPage();
// TODO CONTROL_GetButtonInput();
CheckKeys();
UpdateSounds();
bInMove = kTrue;
moveframes = ((int)totalclock - tclocks2) / 4;
if (moveframes > 4)
moveframes = 4;
if (moveframes != 0)
tclocks2 = (int)totalclock;
if (bPlayback)
if (bRecord || bPlayback)
{
// YELLOW
if ((bInDemo && KB_KeyWaiting() || !ReadPlaybackInputs()) && KB_GetCh())
bInMove = kTrue;
moveframes = ((int)totalclock - (int)tclocks2) / 4;
if (moveframes > 4)
moveframes = 4;
if (moveframes != 0)
tclocks2 = totalclock;
if (bPlayback)
{
KB_FlushKeyboardQueue();
KB_ClearKeysDown();
// YELLOW
if ((bInDemo && KB_KeyWaiting() || !ReadPlaybackInputs()) && KB_GetCh())
{
KB_FlushKeyboardQueue();
KB_ClearKeysDown();
bPlayback = kFalse;
bInDemo = kFalse;
bPlayback = kFalse;
bInDemo = kFalse;
if (vcrfp) {
fclose(vcrfp);
if (vcrfp) {
fclose(vcrfp);
}
CONTROL_BindsEnabled = 0;
goto MENU;
}
CONTROL_BindsEnabled = 0;
goto MENU;
}
}
else if (bRecord || moveframes)
{
GetLocalInput();
sPlayerInput[nLocalPlayer].xVel = lPlayerXVel;
sPlayerInput[nLocalPlayer].yVel = lPlayerYVel;
sPlayerInput[nLocalPlayer].buttons = lLocalButtons | lLocalCodes;
sPlayerInput[nLocalPlayer].nAngle = nPlayerDAng;
sPlayerInput[nLocalPlayer].nTarget = besttarget;
Ra[nLocalPlayer].nTarget = besttarget;
lLocalCodes = 0;
nPlayerDAng = 0;
sPlayerInput[nLocalPlayer].horizon = nVertPan[nLocalPlayer];
}
// loc_11F72:
if (bRecord && !bInDemo) {
WritePlaybackInputs();
}
if (nNetPlayerCount)
{
if (moveframes)
else if (bRecord || moveframes)
{
UpdateInputs();
moveframes = nNetMoveFrames;
GetLocalInput();
sPlayerInput[nLocalPlayer].xVel = lPlayerXVel;
sPlayerInput[nLocalPlayer].yVel = lPlayerYVel;
sPlayerInput[nLocalPlayer].buttons = lLocalButtons | lLocalCodes;
sPlayerInput[nLocalPlayer].nAngle = nPlayerDAng;
sPlayerInput[nLocalPlayer].nTarget = besttarget;
Ra[nLocalPlayer].nTarget = besttarget;
lLocalCodes = 0;
nPlayerDAng = 0;
sPlayerInput[nLocalPlayer].horizon = nVertPan[nLocalPlayer];
}
// loc_11F72:
if (bRecord && !bInDemo) {
WritePlaybackInputs();
}
if (nNetPlayerCount)
{
if (moveframes)
{
UpdateInputs();
moveframes = nNetMoveFrames;
}
}
else
{
// loc_11FBC:
while (bPause)
{
ClearAllKeys();
if (WaitAnyKey(-1) != sc_Pause)
{
bPause = kFalse;
}
}
}
// loc_11FEE:
tclocks += moveframes * 4;
while (moveframes && levelnew < 0)
{
GameMove();
// if (nNetTime > 0)
// {
// nNetTime--;
//
// if (!nNetTime) {
// nFreeze = 3;
// }
// }
// else if (nNetTime == 0)
// {
// if (BUTTON(gamefunc_Open))
// {
// CONTROL_ClearButton(gamefunc_Open);
// goto MENU2;
// }
// }
}
bInMove = kFalse;
// END YELLOW SECTION
// loc_12149:
if (bInDemo)
{
while (tclocks > totalclock) { HandleAsync(); }
tclocks = totalclock;
}
if (G_FPSLimit())
{
GameDisplay();
}
}
else
{
// loc_11FBC:
while (bPause)
bInMove = kTrue;
if (!bPause && totalclock >= tclocks + 4)
{
ClearAllKeys();
if (WaitAnyKey(-1) != sc_Pause)
GetLocalInput();
sPlayerInput[nLocalPlayer].xVel = lPlayerXVel;
sPlayerInput[nLocalPlayer].yVel = lPlayerYVel;
sPlayerInput[nLocalPlayer].buttons = lLocalButtons | lLocalCodes;
sPlayerInput[nLocalPlayer].nAngle = nPlayerDAng;
sPlayerInput[nLocalPlayer].nTarget = besttarget;
Ra[nLocalPlayer].nTarget = besttarget;
lLocalCodes = 0;
nPlayerDAng = 0;
sPlayerInput[nLocalPlayer].horizon = nVertPan[nLocalPlayer];
do
{
bPause = kFalse;
}
timerUpdate();
tclocks += 4;
GameMove();
timerUpdate();
} while (levelnew < 0 && totalclock >= tclocks + 4);
}
bInMove = kFalse;
faketimerhandler();
if (G_FPSLimit())
{
GameDisplay();
}
}
// loc_11FEE:
tclocks += moveframes * 4;
while (moveframes&& levelnew < 0)
{
FixPalette();
if (levelnum == kMap20)
{
if (lCountDown <= 0)
{
for (int i = 0; i < nTotalPlayers; i++) {
nPlayerLives[i] = 0;
}
DoFailedFinalScene();
levelnew = 100;
break;
}
// Pink section
lCountDown--;
DrawClock();
if (nRedTicks)
{
nRedTicks--;
if (nRedTicks <= 0) {
DoRedAlert(0);
}
nAlarmTicks--;
nButtonColor--;
if (nAlarmTicks <= 0) {
DoRedAlert(1);
}
}
}
// YELLOW SECTION
MoveThings();
if (totalvel[nLocalPlayer] == 0)
{
bobangle = 0;
}
else
{
bobangle += 56;
bobangle &= kAngleMask;
}
// loc_120E9:
totalmoves++;
moveframes--;
if (nNetTime > 0)
{
nNetTime--;
if (!nNetTime) {
nFreeze = 3;
}
}
else if (nNetTime == 0)
{
if (BUTTON(gamefunc_Open))
{
CONTROL_ClearButton(gamefunc_Open);
goto MENU2;
}
}
}
// END YELLOW SECTION
// loc_12149:
if (bInDemo)
{
while (tclocks > (int)totalclock) { HandleAsync(); }
tclocks = (int)totalclock;
}
bInMove = kFalse;
if (!bInDemo)
{
if (BUTTON(gamefunc_Escape))
{
CONTROL_ClearButton(gamefunc_Escape);
MENU2:
// MENU2:
CONTROL_BindsEnabled = 0;
nMenu = menu_Menu(1);

View file

@ -188,6 +188,11 @@ extern int bVanilla;
extern int mouseaiming, aimmode, mouseflip;
extern int runkey_mode, auto_run;
extern int32_t r_maxfps;
extern int32_t r_maxfpsoffset;
extern double g_frameDelay;
static inline double calcFrameDelay(int const maxFPS) { return maxFPS > 0 ? (timerGetFreqU64()/(double)maxFPS) : 0.0; }
enum {
kPalNormal = 0,

View file

@ -404,12 +404,12 @@ static int osdcmd_cvar_set_game(osdcmdptr_t parm)
{
ud.statusbarmode = (ud.screen_size < 8);
G_UpdateScreenArea();
}
}*/
else if (!Bstrcasecmp(parm->name, "r_maxfps") || !Bstrcasecmp(parm->name, "r_maxfpsoffset"))
{
if (r_maxfps != 0) r_maxfps = clamp(r_maxfps, 30, 1000);
g_frameDelay = calcFrameDelay(r_maxfps + r_maxfpsoffset);
}
}/*
else if (!Bstrcasecmp(parm->name, "r_ambientlight"))
{
if (r_ambientlight == 0)
@ -624,8 +624,8 @@ int32_t registerosdcommands(void)
{ "r_precache", "enable/disable the pre-level caching routine", (void *)&useprecache, CVAR_BOOL, 0, 1 },
// { "r_ambientlight", "sets the global map light level",(void *)&r_ambientlight, CVAR_FLOAT|CVAR_FUNCPTR, 0, 10 },
//{ "r_maxfps", "limit the frame rate",(void *)&r_maxfps, CVAR_INT|CVAR_FUNCPTR, 0, 1000 },
//{ "r_maxfpsoffset", "menu-controlled offset for r_maxfps",(void *)&r_maxfpsoffset, CVAR_INT|CVAR_FUNCPTR, -10, 10 },
{ "r_maxfps", "limit the frame rate",(void *)&r_maxfps, CVAR_INT|CVAR_FUNCPTR, 0, 1000 },
{ "r_maxfpsoffset", "menu-controlled offset for r_maxfps",(void *)&r_maxfpsoffset, CVAR_INT|CVAR_FUNCPTR, -10, 10 },
{ "sensitivity","changes the mouse sensitivity", (void *)&CONTROL_MouseSensitivity, CVAR_FLOAT|CVAR_FUNCPTR, 0, 25 },

View file

@ -677,6 +677,9 @@ void RestartPlayer(short nPlayer)
floorspr = -1;
}
PlayerList[nPlayer].opos = sprite[nSprite].pos;
PlayerList[nPlayer].q16oangle = PlayerList[nPlayer].q16angle;
nPlayerFloorSprite[nPlayer] = floorspr;
sprite[nSprite].cstat = 0x101;
@ -775,7 +778,7 @@ void RestartPlayer(short nPlayer)
nYDamage[nPlayer] = 0;
nXDamage[nPlayer] = 0;
PlayerList[nPlayer].q16horiz = nVertPan[nPlayer] = F16(92);
PlayerList[nPlayer].q16ohoriz = PlayerList[nPlayer].q16horiz = nVertPan[nPlayer] = F16(92);
nDestVertPan[nPlayer] = F16(92);
nBreathTimer[nPlayer] = 90;
@ -877,7 +880,7 @@ void StartDeathSeq(int nPlayer, int nVal)
StopFiringWeapon(nPlayer);
PlayerList[nPlayer].q16horiz = nVertPan[nPlayer] = F16(92);
PlayerList[nPlayer].q16ohoriz = PlayerList[nPlayer].q16horiz = nVertPan[nPlayer] = F16(92);
eyelevel[nPlayer] = -14080;
nPlayerInvisible[nPlayer] = 0;
dVertPan[nPlayer] = 15;
@ -1044,6 +1047,10 @@ void FuncPlayer(int pA, int nDamage, int nRun)
short nSprite2;
PlayerList[nPlayer].opos = sprite[nPlayerSprite].pos;
PlayerList[nPlayer].q16oangle = PlayerList[nPlayer].q16angle;
PlayerList[nPlayer].q16ohoriz = PlayerList[nPlayer].q16horiz;
switch (nMessage)
{
case 0x90000:

View file

@ -53,8 +53,9 @@ struct Player
short field_3C;
short nRun;
fix16_t q16angle;
fix16_t q16horiz;
fix16_t q16angle, q16oangle;
fix16_t q16horiz, q16ohoriz;
vec3_t opos;
};
extern short PlayerCount;

View file

@ -59,6 +59,65 @@ short enemy;
short nEnemyPal = 0;
#define MAXINTERPOLATIONS MAXSPRITES
int32_t g_interpolationCnt;
int32_t oldipos[MAXINTERPOLATIONS];
int32_t* curipos[MAXINTERPOLATIONS];
int32_t bakipos[MAXINTERPOLATIONS];
int viewSetInterpolation(int32_t *const posptr)
{
if (g_interpolationCnt >= MAXINTERPOLATIONS)
return 1;
for (bssize_t i = 0; i < g_interpolationCnt; ++i)
if (curipos[i] == posptr)
return 0;
curipos[g_interpolationCnt] = posptr;
oldipos[g_interpolationCnt] = *posptr;
g_interpolationCnt++;
return 0;
}
void viewStopInterpolation(const int32_t * const posptr)
{
for (bssize_t i = 0; i < g_interpolationCnt; ++i)
if (curipos[i] == posptr)
{
g_interpolationCnt--;
oldipos[i] = oldipos[g_interpolationCnt];
bakipos[i] = bakipos[g_interpolationCnt];
curipos[i] = curipos[g_interpolationCnt];
}
}
void viewDoInterpolations(int smoothRatio)
{
int32_t ndelta = 0;
for (bssize_t i = 0, j = 0; i < g_interpolationCnt; ++i)
{
int32_t const odelta = ndelta;
bakipos[i] = *curipos[i];
ndelta = (*curipos[i]) - oldipos[i];
if (odelta != ndelta)
j = mulscale16(ndelta, smoothRatio);
*curipos[i] = oldipos[i] + j;
}
}
void viewUpdateInterpolations(void) //Stick at beginning of G_DoMoveThings
{
for (bssize_t i=g_interpolationCnt-1; i>=0; i--) oldipos[i] = *curipos[i];
}
void viewRestoreInterpolations(void) //Stick at end of drawscreen
{
int32_t i=g_interpolationCnt-1;
for (; i>=0; i--) *curipos[i] = bakipos[i];
}
void InitView()
{
@ -271,7 +330,17 @@ void TestLava()
{
}
void DrawView()
static inline int interpolate16(int a, int b, int smooth)
{
return a + mulscale16(b - a, smooth);
}
static inline fix16_t q16angle_interpolate16(fix16_t a, fix16_t b, int smooth)
{
return a + mulscale16(((b+F16(1024)-a)&0x7FFFFFF)-F16(1024), smooth);
}
void DrawView(int smoothRatio)
{
int playerX;
int playerY;
@ -306,6 +375,7 @@ void DrawView()
zbob = Sin(2 * bobangle) >> 3;
int nPlayerSprite = PlayerList[nLocalPlayer].nSprite;
int nPlayerOldCstat = sprite[nPlayerSprite].cstat;
if (nSnakeCam >= 0)
{
@ -334,11 +404,13 @@ void DrawView()
}
else
{
playerX = sprite[nPlayerSprite].x;
playerY = sprite[nPlayerSprite].y;
playerZ = sprite[nPlayerSprite].z + eyelevel[nLocalPlayer];
playerX = interpolate16(PlayerList[nLocalPlayer].opos.x, sprite[nPlayerSprite].x, smoothRatio);
playerY = interpolate16(PlayerList[nLocalPlayer].opos.y, sprite[nPlayerSprite].y, smoothRatio);
playerZ = interpolate16(PlayerList[nLocalPlayer].opos.z, sprite[nPlayerSprite].z, smoothRatio) + eyelevel[nLocalPlayer];
nSector = nPlayerViewSect[nLocalPlayer];
nAngle = PlayerList[nLocalPlayer].q16angle;
nAngle = q16angle_interpolate16(PlayerList[nLocalPlayer].q16oangle, PlayerList[nLocalPlayer].q16angle, smoothRatio);
sprite[nPlayerSprite].cstat |= CSTAT_SPRITE_INVISIBLE;
}
nCameraa = nAngle;
@ -356,7 +428,7 @@ void DrawView()
int floorZ = sector[sprite[nPlayerSprite].sectnum].floorz;
// pan = nVertPan[nLocalPlayer];
pan = PlayerList[nLocalPlayer].q16horiz;
pan = interpolate16(PlayerList[nLocalPlayer].q16ohoriz, PlayerList[nLocalPlayer].q16horiz, smoothRatio);
if (viewz > floorZ)
viewz = floorZ;
@ -523,6 +595,8 @@ void DrawView()
DrawStatus();
}
sprite[nPlayerSprite].cstat = nPlayerOldCstat;
flash = 0;
}

View file

@ -14,12 +14,18 @@ extern short bCamera;
void InitView();
void SetView1();
void RefreshBackground();
void DrawView();
void DrawView(int smoothRatio);
void MySetView(int x1, int y1, int x2, int y2);
void ResetView();
void NoClip();
void Clip();
int viewSetInterpolation(int32_t *const posptr);
void viewStopInterpolation(const int32_t * const posptr);
void viewDoInterpolations(int smoothRatio);
void viewUpdateInterpolations(void);
void viewRestoreInterpolations(void);
extern fix16_t nDestVertPan[];
extern short dVertPan[];
extern fix16_t nVertPan[];