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(); WaitVBL();
RefreshBackground(); RefreshBackground();
RefreshStatus(); RefreshStatus();
DrawView(); DrawView(65536);
videoNextPage(); videoNextPage();
} }
@ -1979,6 +1979,153 @@ void app_crashhandler(void)
void G_Polymer_UnInit(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) int app_main(int argc, char const* const* argv)
{ {
char tempbuf[256]; char tempbuf[256];
@ -2031,7 +2178,6 @@ int app_main(int argc, char const* const* argv)
//int edi = esi; //int edi = esi;
int doTitle = kFalse; // REVERT kTrue; int doTitle = kFalse; // REVERT kTrue;
int stopTitle = kFalse; int stopTitle = kFalse;
int tclocks, tclocks2;
levelnew = 1; levelnew = 1;
// REVERT - change back to kTrue // REVERT - change back to kTrue
@ -2358,6 +2504,8 @@ int app_main(int argc, char const* const* argv)
if (enginePostInit()) if (enginePostInit())
ShutDown(); ShutDown();
g_frameDelay = calcFrameDelay(r_maxfps + r_maxfpsoffset);
// loc_11745: // loc_11745:
FadeOut(0); FadeOut(0);
// InstallEngine(); // InstallEngine();
@ -2590,7 +2738,7 @@ LOOP3:
ResetMoveFifo(); ResetMoveFifo();
moveframes = 0; moveframes = 0;
bInMove = kFalse; bInMove = kFalse;
tclocks = (int)totalclock; tclocks = totalclock;
nPlayerDAng = 0; nPlayerDAng = 0;
lPlayerXVel = 0; lPlayerXVel = 0;
lPlayerYVel = 0; lPlayerYVel = 0;
@ -2604,7 +2752,7 @@ LOOP3:
mysetbrightness((uint8_t)nGamma); mysetbrightness((uint8_t)nGamma);
//int edi = totalclock; //int edi = totalclock;
tclocks2 = (int)totalclock; tclocks2 = totalclock;
CONTROL_BindsEnabled = 1; CONTROL_BindsEnabled = 1;
// Game Loop // Game Loop
while (1) while (1)
@ -2631,209 +2779,168 @@ LOOP3:
nCDTrackLength = -1; 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(); // TODO CONTROL_GetButtonInput();
CheckKeys(); CheckKeys();
UpdateSounds(); UpdateSounds();
bInMove = kTrue; if (bRecord || bPlayback)
moveframes = ((int)totalclock - tclocks2) / 4;
if (moveframes > 4)
moveframes = 4;
if (moveframes != 0)
tclocks2 = (int)totalclock;
if (bPlayback)
{ {
// YELLOW bInMove = kTrue;
if ((bInDemo && KB_KeyWaiting() || !ReadPlaybackInputs()) && KB_GetCh())
moveframes = ((int)totalclock - (int)tclocks2) / 4;
if (moveframes > 4)
moveframes = 4;
if (moveframes != 0)
tclocks2 = totalclock;
if (bPlayback)
{ {
KB_FlushKeyboardQueue(); // YELLOW
KB_ClearKeysDown(); if ((bInDemo && KB_KeyWaiting() || !ReadPlaybackInputs()) && KB_GetCh())
{
KB_FlushKeyboardQueue();
KB_ClearKeysDown();
bPlayback = kFalse; bPlayback = kFalse;
bInDemo = kFalse; bInDemo = kFalse;
if (vcrfp) { if (vcrfp) {
fclose(vcrfp); fclose(vcrfp);
}
CONTROL_BindsEnabled = 0;
goto MENU;
} }
CONTROL_BindsEnabled = 0;
goto MENU;
} }
} else if (bRecord || moveframes)
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)
{ {
UpdateInputs(); GetLocalInput();
moveframes = nNetMoveFrames;
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 else
{ {
// loc_11FBC: bInMove = kTrue;
while (bPause) if (!bPause && totalclock >= tclocks + 4)
{ {
ClearAllKeys(); GetLocalInput();
if (WaitAnyKey(-1) != sc_Pause)
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 (!bInDemo)
{ {
if (BUTTON(gamefunc_Escape)) if (BUTTON(gamefunc_Escape))
{ {
CONTROL_ClearButton(gamefunc_Escape); CONTROL_ClearButton(gamefunc_Escape);
MENU2: // MENU2:
CONTROL_BindsEnabled = 0; CONTROL_BindsEnabled = 0;
nMenu = menu_Menu(1); nMenu = menu_Menu(1);

View file

@ -188,6 +188,11 @@ extern int bVanilla;
extern int mouseaiming, aimmode, mouseflip; extern int mouseaiming, aimmode, mouseflip;
extern int runkey_mode, auto_run; 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 { enum {
kPalNormal = 0, kPalNormal = 0,

View file

@ -404,12 +404,12 @@ static int osdcmd_cvar_set_game(osdcmdptr_t parm)
{ {
ud.statusbarmode = (ud.screen_size < 8); ud.statusbarmode = (ud.screen_size < 8);
G_UpdateScreenArea(); G_UpdateScreenArea();
} }*/
else if (!Bstrcasecmp(parm->name, "r_maxfps") || !Bstrcasecmp(parm->name, "r_maxfpsoffset")) else if (!Bstrcasecmp(parm->name, "r_maxfps") || !Bstrcasecmp(parm->name, "r_maxfpsoffset"))
{ {
if (r_maxfps != 0) r_maxfps = clamp(r_maxfps, 30, 1000); if (r_maxfps != 0) r_maxfps = clamp(r_maxfps, 30, 1000);
g_frameDelay = calcFrameDelay(r_maxfps + r_maxfpsoffset); g_frameDelay = calcFrameDelay(r_maxfps + r_maxfpsoffset);
} }/*
else if (!Bstrcasecmp(parm->name, "r_ambientlight")) else if (!Bstrcasecmp(parm->name, "r_ambientlight"))
{ {
if (r_ambientlight == 0) 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_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_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_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_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 }, { "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; floorspr = -1;
} }
PlayerList[nPlayer].opos = sprite[nSprite].pos;
PlayerList[nPlayer].q16oangle = PlayerList[nPlayer].q16angle;
nPlayerFloorSprite[nPlayer] = floorspr; nPlayerFloorSprite[nPlayer] = floorspr;
sprite[nSprite].cstat = 0x101; sprite[nSprite].cstat = 0x101;
@ -775,7 +778,7 @@ void RestartPlayer(short nPlayer)
nYDamage[nPlayer] = 0; nYDamage[nPlayer] = 0;
nXDamage[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); nDestVertPan[nPlayer] = F16(92);
nBreathTimer[nPlayer] = 90; nBreathTimer[nPlayer] = 90;
@ -877,7 +880,7 @@ void StartDeathSeq(int nPlayer, int nVal)
StopFiringWeapon(nPlayer); StopFiringWeapon(nPlayer);
PlayerList[nPlayer].q16horiz = nVertPan[nPlayer] = F16(92); PlayerList[nPlayer].q16ohoriz = PlayerList[nPlayer].q16horiz = nVertPan[nPlayer] = F16(92);
eyelevel[nPlayer] = -14080; eyelevel[nPlayer] = -14080;
nPlayerInvisible[nPlayer] = 0; nPlayerInvisible[nPlayer] = 0;
dVertPan[nPlayer] = 15; dVertPan[nPlayer] = 15;
@ -1044,6 +1047,10 @@ void FuncPlayer(int pA, int nDamage, int nRun)
short nSprite2; short nSprite2;
PlayerList[nPlayer].opos = sprite[nPlayerSprite].pos;
PlayerList[nPlayer].q16oangle = PlayerList[nPlayer].q16angle;
PlayerList[nPlayer].q16ohoriz = PlayerList[nPlayer].q16horiz;
switch (nMessage) switch (nMessage)
{ {
case 0x90000: case 0x90000:

View file

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

View file

@ -59,6 +59,65 @@ short enemy;
short nEnemyPal = 0; 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() 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 playerX;
int playerY; int playerY;
@ -306,6 +375,7 @@ void DrawView()
zbob = Sin(2 * bobangle) >> 3; zbob = Sin(2 * bobangle) >> 3;
int nPlayerSprite = PlayerList[nLocalPlayer].nSprite; int nPlayerSprite = PlayerList[nLocalPlayer].nSprite;
int nPlayerOldCstat = sprite[nPlayerSprite].cstat;
if (nSnakeCam >= 0) if (nSnakeCam >= 0)
{ {
@ -334,11 +404,13 @@ void DrawView()
} }
else else
{ {
playerX = sprite[nPlayerSprite].x; playerX = interpolate16(PlayerList[nLocalPlayer].opos.x, sprite[nPlayerSprite].x, smoothRatio);
playerY = sprite[nPlayerSprite].y; playerY = interpolate16(PlayerList[nLocalPlayer].opos.y, sprite[nPlayerSprite].y, smoothRatio);
playerZ = sprite[nPlayerSprite].z + eyelevel[nLocalPlayer]; playerZ = interpolate16(PlayerList[nLocalPlayer].opos.z, sprite[nPlayerSprite].z, smoothRatio) + eyelevel[nLocalPlayer];
nSector = nPlayerViewSect[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; nCameraa = nAngle;
@ -356,7 +428,7 @@ void DrawView()
int floorZ = sector[sprite[nPlayerSprite].sectnum].floorz; int floorZ = sector[sprite[nPlayerSprite].sectnum].floorz;
// pan = nVertPan[nLocalPlayer]; // pan = nVertPan[nLocalPlayer];
pan = PlayerList[nLocalPlayer].q16horiz; pan = interpolate16(PlayerList[nLocalPlayer].q16ohoriz, PlayerList[nLocalPlayer].q16horiz, smoothRatio);
if (viewz > floorZ) if (viewz > floorZ)
viewz = floorZ; viewz = floorZ;
@ -523,6 +595,8 @@ void DrawView()
DrawStatus(); DrawStatus();
} }
sprite[nPlayerSprite].cstat = nPlayerOldCstat;
flash = 0; flash = 0;
} }

View file

@ -14,12 +14,18 @@ extern short bCamera;
void InitView(); void InitView();
void SetView1(); void SetView1();
void RefreshBackground(); void RefreshBackground();
void DrawView(); void DrawView(int smoothRatio);
void MySetView(int x1, int y1, int x2, int y2); void MySetView(int x1, int y1, int x2, int y2);
void ResetView(); void ResetView();
void NoClip(); void NoClip();
void Clip(); 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 fix16_t nDestVertPan[];
extern short dVertPan[]; extern short dVertPan[];
extern fix16_t nVertPan[]; extern fix16_t nVertPan[];