mirror of
https://github.com/ZDoom/raze-gles.git
synced 2025-01-20 22:30:46 +00:00
966cf5e262
Taking a cue from GDX to properly synchronize it because PCExhumed's approach looked broken by design. It had no frame rate sync and solely depended on the low level audio stream for it.
523 lines
13 KiB
C++
523 lines
13 KiB
C++
//-------------------------------------------------------------------------
|
|
/*
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
Copyright (C) 2019 sirlemonhead, Nuke.YKT
|
|
This file is part of PCExhumed.
|
|
PCExhumed is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License version 2
|
|
as published by the Free Software Foundation.
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
See the GNU General Public License for more details.
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
//-------------------------------------------------------------------------
|
|
#include "ns.h"
|
|
#include "compat.h"
|
|
#include "engine.h"
|
|
#include "names.h"
|
|
#include "view.h"
|
|
#include "status.h"
|
|
#include "exhumed.h"
|
|
#include "player.h"
|
|
#include "aistuff.h"
|
|
#include "menu.h"
|
|
#include "sound.h"
|
|
#include "v_video.h"
|
|
#include "glbackend/glbackend.h"
|
|
#include <string.h>
|
|
|
|
BEGIN_PS_NS
|
|
|
|
short bSubTitles = true;
|
|
|
|
int zbob;
|
|
|
|
fix16_t nDestVertPan[kMaxPlayers] = { 0 };
|
|
short dVertPan[kMaxPlayers];
|
|
int nCamerax;
|
|
int nCameray;
|
|
int nCameraz;
|
|
|
|
|
|
short bTouchFloor;
|
|
|
|
short nQuake[kMaxPlayers] = { 0 };
|
|
|
|
short nChunkTotal = 0;
|
|
|
|
fix16_t nCameraa;
|
|
fix16_t nCamerapan;
|
|
short nViewTop;
|
|
short bCamera = false;
|
|
|
|
int viewz;
|
|
|
|
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()
|
|
{
|
|
polymostcenterhoriz = 92;
|
|
}
|
|
|
|
// NOTE - not to be confused with Ken's analyzesprites()
|
|
static void analyzesprites()
|
|
{
|
|
short nPlayerSprite = PlayerList[nLocalPlayer].nSprite;
|
|
|
|
int var_38 = 20;
|
|
int var_2C = 30000;
|
|
|
|
spritetype *pPlayerSprite = &sprite[nPlayerSprite];
|
|
|
|
besttarget = -1;
|
|
|
|
int x = pPlayerSprite->x;
|
|
int y = pPlayerSprite->y;
|
|
|
|
int z = pPlayerSprite->z - (GetSpriteHeight(nPlayerSprite) / 2);
|
|
|
|
short nSector = pPlayerSprite->sectnum;
|
|
|
|
int nAngle = (2048 - pPlayerSprite->ang) & kAngleMask;
|
|
|
|
int nTSprite;
|
|
tspritetype *pTSprite;
|
|
|
|
// int var_20 = var_24;
|
|
|
|
for (nTSprite = spritesortcnt-1, pTSprite = &tsprite[nTSprite]; nTSprite >= 0; nTSprite--, pTSprite--)
|
|
{
|
|
int nSprite = pTSprite->owner;
|
|
spritetype *pSprite = &sprite[nSprite];
|
|
|
|
if (pTSprite->sectnum >= 0)
|
|
{
|
|
sectortype *pSector = §or[pTSprite->sectnum];
|
|
int nSectShade = (pSector->ceilingstat & 1) ? pSector->ceilingshade : pSector->floorshade;
|
|
int nShade = pTSprite->shade + nSectShade + 6;
|
|
pTSprite->shade = clamp(nShade, -128, 127);
|
|
}
|
|
|
|
pTSprite->pal = RemapPLU(pTSprite->pal);
|
|
|
|
if (pSprite->statnum > 0)
|
|
{
|
|
runlist_SignalRun(pSprite->lotag - 1, nTSprite | 0x90000);
|
|
|
|
if ((pSprite->statnum < 150) && (pSprite->cstat & 0x101) && (nSprite != nPlayerSprite))
|
|
{
|
|
int xval = pSprite->x - x;
|
|
int yval = pSprite->y - y;
|
|
|
|
int vcos = Cos(nAngle);
|
|
int vsin = Sin(nAngle);
|
|
|
|
|
|
int edx = ((vcos * yval) + (xval * vsin)) >> 14;
|
|
|
|
|
|
int ebx = klabs(((vcos * xval) - (yval * vsin)) >> 14);
|
|
|
|
if (!ebx)
|
|
continue;
|
|
|
|
edx = (klabs(edx) * 32) / ebx;
|
|
if (ebx < 1000 && ebx < var_2C && edx < 10)
|
|
{
|
|
besttarget = nSprite;
|
|
var_38 = edx;
|
|
var_2C = ebx;
|
|
}
|
|
else if (ebx < 30000)
|
|
{
|
|
int t = var_38 - edx;
|
|
if (t > 3 || (ebx < var_2C && klabs(t) < 5))
|
|
{
|
|
var_38 = edx;
|
|
var_2C = ebx;
|
|
besttarget = nSprite;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (besttarget != -1)
|
|
{
|
|
spritetype *pTarget = &sprite[besttarget];
|
|
|
|
nCreepyTimer = kCreepyCount;
|
|
|
|
if (!cansee(x, y, z, nSector, pTarget->x, pTarget->y, pTarget->z - GetSpriteHeight(besttarget), pTarget->sectnum))
|
|
{
|
|
besttarget = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ResetView()
|
|
{
|
|
//videoSetGameMode(gSetup.fullscreen, gSetup.xdim, gSetup.ydim, gSetup.bpp, 0);
|
|
EraseScreen(overscanindex);
|
|
//videoUpdatePalette(0, 256);
|
|
#ifdef USE_OPENGL
|
|
videoTintBlood(0, 0, 0);
|
|
#endif
|
|
}
|
|
|
|
void SetView1()
|
|
{
|
|
}
|
|
|
|
|
|
static inline int interpolate16(int a, int b, int smooth)
|
|
{
|
|
return a + mulscale16(b - a, smooth);
|
|
}
|
|
|
|
void DrawView(int smoothRatio, bool sceneonly)
|
|
{
|
|
int playerX;
|
|
int playerY;
|
|
int playerZ;
|
|
short nSector;
|
|
fix16_t nAngle;
|
|
fix16_t pan;
|
|
|
|
zbob = Sin(2 * bobangle) >> 3;
|
|
|
|
int nPlayerSprite = PlayerList[nLocalPlayer].nSprite;
|
|
int nPlayerOldCstat = sprite[nPlayerSprite].cstat;
|
|
int nDoppleOldCstat = sprite[nDoppleSprite[nLocalPlayer]].cstat;
|
|
|
|
if (nSnakeCam >= 0 && !sceneonly)
|
|
{
|
|
int nSprite = SnakeList[nSnakeCam].nSprites[0];
|
|
|
|
playerX = sprite[nSprite].x;
|
|
playerY = sprite[nSprite].y;
|
|
playerZ = sprite[nSprite].z;
|
|
nSector = sprite[nSprite].sectnum;
|
|
nAngle = fix16_from_int(sprite[nSprite].ang);
|
|
|
|
SetGreenPal();
|
|
|
|
enemy = SnakeList[nSnakeCam].nEnemy;
|
|
|
|
if (enemy <= -1 || totalmoves & 1)
|
|
{
|
|
nEnemyPal = -1;
|
|
}
|
|
else
|
|
{
|
|
nEnemyPal = sprite[enemy].pal;
|
|
sprite[enemy].pal = 5;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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)
|
|
+ interpolate16(oeyelevel[nLocalPlayer], eyelevel[nLocalPlayer], smoothRatio);
|
|
nSector = nPlayerViewSect[nLocalPlayer];
|
|
nAngle = PlayerList[nLocalPlayer].q16angle;
|
|
|
|
if (!bCamera)
|
|
{
|
|
sprite[nPlayerSprite].cstat |= CSTAT_SPRITE_INVISIBLE;
|
|
sprite[nDoppleSprite[nLocalPlayer]].cstat |= CSTAT_SPRITE_INVISIBLE;
|
|
}
|
|
}
|
|
|
|
nCameraa = nAngle;
|
|
|
|
if (!bCamera || nFreeze || sceneonly)
|
|
{
|
|
if (nSnakeCam >= 0 && !sceneonly)
|
|
{
|
|
pan = F16(92);
|
|
viewz = playerZ;
|
|
}
|
|
else
|
|
{
|
|
viewz = playerZ + nQuake[nLocalPlayer];
|
|
int floorZ = sector[sprite[nPlayerSprite].sectnum].floorz;
|
|
|
|
pan = PlayerList[nLocalPlayer].q16horiz;
|
|
|
|
if (viewz > floorZ)
|
|
viewz = floorZ;
|
|
|
|
nCameraa += fix16_from_int((nQuake[nLocalPlayer] >> 7) % 31);
|
|
nCameraa &= 0x7FFFFFF;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
clipmove_old((int32_t*)&playerX, (int32_t*)&playerY, (int32_t*)&playerZ, &nSector,
|
|
-2000 * Sin(inita + 512),
|
|
-2000 * Sin(inita),
|
|
4, 0, 0, CLIPMASK1);
|
|
|
|
pan = F16(92);
|
|
viewz = playerZ;
|
|
}
|
|
|
|
nCamerax = playerX;
|
|
nCameray = playerY;
|
|
nCameraz = playerZ;
|
|
|
|
int Z = sector[nSector].ceilingz + 256;
|
|
if (Z <= viewz)
|
|
{
|
|
Z = sector[nSector].floorz - 256;
|
|
|
|
if (Z < viewz)
|
|
viewz = Z;
|
|
}
|
|
else {
|
|
viewz = Z;
|
|
}
|
|
|
|
nCamerapan = pan;
|
|
|
|
if (nFreeze == 2 || nFreeze == 1)
|
|
{
|
|
nSnakeCam = -1;
|
|
videoSetViewableArea(0, 0, xdim - 1, ydim - 1);
|
|
}
|
|
|
|
UpdateMap();
|
|
|
|
if (nFreeze != 3)
|
|
{
|
|
static uint8_t sectorFloorPal[MAXSECTORS];
|
|
static uint8_t sectorCeilingPal[MAXSECTORS];
|
|
static uint8_t wallPal[MAXWALLS];
|
|
int const viewingRange = viewingrange;
|
|
int const vr = Blrintf(65536.f * tanf(r_fov * (fPI / 360.f)));
|
|
|
|
if (r_usenewaspect)
|
|
{
|
|
newaspect_enable = 1;
|
|
videoSetCorrectedAspect();
|
|
renderSetAspect(mulscale16(vr, viewingrange), yxaspect);
|
|
}
|
|
else
|
|
renderSetAspect(vr, yxaspect);
|
|
|
|
if (HavePLURemap())
|
|
{
|
|
for (int i = 0; i < numsectors; i++)
|
|
{
|
|
sectorFloorPal[i] = sector[i].floorpal;
|
|
sectorCeilingPal[i] = sector[i].ceilingpal;
|
|
sector[i].floorpal = RemapPLU(sectorFloorPal[i]);
|
|
sector[i].ceilingpal = RemapPLU(sectorCeilingPal[i]);
|
|
}
|
|
for (int i = 0; i < numwalls; i++)
|
|
{
|
|
wallPal[i] = wall[i].pal;
|
|
wall[i].pal = RemapPLU(wallPal[i]);
|
|
}
|
|
}
|
|
|
|
renderDrawRoomsQ16(nCamerax, nCameray, viewz, nCameraa, nCamerapan, nSector);
|
|
analyzesprites();
|
|
renderDrawMasks();
|
|
|
|
if (HavePLURemap())
|
|
{
|
|
for (int i = 0; i < numsectors; i++)
|
|
{
|
|
sector[i].floorpal = sectorFloorPal[i];
|
|
sector[i].ceilingpal = sectorCeilingPal[i];
|
|
}
|
|
for (int i = 0; i < numwalls; i++)
|
|
{
|
|
wall[i].pal = wallPal[i];
|
|
}
|
|
}
|
|
|
|
if (r_usenewaspect)
|
|
{
|
|
newaspect_enable = 0;
|
|
renderSetAspect(viewingRange, divscale16(ydim * 8, xdim * 5));
|
|
}
|
|
|
|
if (nFreeze)
|
|
{
|
|
nSnakeCam = -1;
|
|
|
|
if (nFreeze == 2)
|
|
{
|
|
if (nHeadStage == 4)
|
|
{
|
|
nHeadStage = 5;
|
|
|
|
sprite[nPlayerSprite].cstat |= 0x8000;
|
|
|
|
int ang2 = fix16_to_int(nCameraa) - sprite[nPlayerSprite].ang;
|
|
if (ang2 < 0)
|
|
ang2 = -ang2;
|
|
|
|
if (ang2 > 10)
|
|
{
|
|
inita -= (ang2 >> 3);
|
|
return;
|
|
}
|
|
|
|
if (bSubTitles)
|
|
{
|
|
if (levelnum == 1)
|
|
ReadyCinemaText(1);
|
|
else
|
|
ReadyCinemaText(5);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((bSubTitles && !AdvanceCinemaText()) || inputState.CheckAllInput())
|
|
{
|
|
inputState.ClearAllInput();
|
|
levelnew = levelnum + 1;
|
|
|
|
if (CDplaying()) {
|
|
fadecdaudio();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (!sceneonly)
|
|
{
|
|
if (nSnakeCam < 0)
|
|
{
|
|
DrawWeapons(smoothRatio);
|
|
DrawMap();
|
|
}
|
|
else
|
|
{
|
|
RestoreGreenPal();
|
|
if (nEnemyPal > -1) {
|
|
sprite[enemy].pal = nEnemyPal;
|
|
}
|
|
|
|
DrawMap();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
twod->ClearScreen();
|
|
}
|
|
|
|
sprite[nPlayerSprite].cstat = nPlayerOldCstat;
|
|
sprite[nDoppleSprite[nLocalPlayer]].cstat = nDoppleOldCstat;
|
|
|
|
flash = 0;
|
|
}
|
|
|
|
bool GameInterface::GenerateSavePic()
|
|
{
|
|
DrawView(65536, true);
|
|
return true;
|
|
}
|
|
|
|
void NoClip()
|
|
{
|
|
}
|
|
|
|
void Clip()
|
|
{
|
|
}
|
|
|
|
|
|
static SavegameHelper sgh("view",
|
|
SV(nCamerax),
|
|
SV(nCameray),
|
|
SV(nCameraz),
|
|
SV(bTouchFloor),
|
|
SV(nChunkTotal),
|
|
SV(nCameraa),
|
|
SV(nCamerapan),
|
|
SV(bCamera),
|
|
SV(viewz),
|
|
SV(enemy),
|
|
SV(nEnemyPal),
|
|
SA(nDestVertPan),
|
|
SA(dVertPan),
|
|
SA(nQuake),
|
|
SV(g_interpolationCnt),
|
|
SA(oldipos),
|
|
SA(curipos),
|
|
SA(bakipos),
|
|
nullptr);
|
|
|
|
END_PS_NS
|