raze/source/games/blood/src/sectorfx.cpp
2021-05-12 21:49:06 +02:00

432 lines
13 KiB
C++

//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood 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" // Must come before everything else!
#include "compat.h"
#include "build.h"
#include "blood.h"
#include "interpolate.h"
BEGIN_BLD_NS
char flicker1[] = {
0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0,
1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1,
0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1,
0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1
};
char flicker2[] = {
1, 2, 4, 2, 3, 4, 3, 2, 0, 0, 1, 2, 4, 3, 2, 0,
2, 1, 0, 1, 0, 2, 3, 4, 3, 2, 1, 1, 2, 0, 0, 1,
1, 2, 3, 4, 4, 3, 2, 1, 2, 3, 4, 4, 2, 1, 0, 1,
0, 0, 0, 0, 1, 2, 3, 4, 3, 2, 1, 2, 3, 4, 3, 2
};
char flicker3[] = {
4, 4, 4, 4, 3, 4, 4, 4, 4, 4, 4, 2, 4, 3, 4, 4,
4, 4, 2, 1, 3, 3, 3, 4, 3, 4, 4, 4, 4, 4, 2, 4,
4, 4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 1, 0, 1,
0, 1, 0, 1, 0, 2, 3, 4, 4, 4, 4, 4, 4, 4, 3, 4
};
char flicker4[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 0, 3, 0, 1, 0, 1, 0, 4, 4, 4, 4, 4, 2, 0,
0, 0, 0, 4, 4, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 4, 3, 2,
0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0 ,0 ,0 ,0, 0, 0 ,0, 0
};
char strobe[] = {
64, 64, 64, 48, 36, 27, 20, 15, 11, 9, 6, 5, 4, 3, 2, 2,
1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int GetWaveValue(int a, int b, int c)
{
b &= 2047;
switch (a)
{
case 0:
return c;
case 1:
return (b>>10)*c;
case 2:
return (abs(128-(b>>3))*c)>>7;
case 3:
return ((b>>3)*c)>>8;
case 4:
return ((255-(b>>3))*c)>>8;
case 5:
return (c+MulScale(c,Sin(b), 30))>>1;
case 6:
return flicker1[b>>5]*c;
case 7:
return (flicker2[b>>5]*c)>>2;
case 8:
return (flicker3[b>>5]*c)>>2;
case 9:
return (flicker4[b>>4]*c)>>2;
case 10:
return (strobe[b>>5]*c)>>6;
case 11:
if (b*4 > 2048)
return 0;
return (c-MulScale(c, Cos(b*4), 30))>>1;
}
return 0;
}
int shadeCount = 0;
short shadeList[kMaxXSectors];
int panCount = 0;
short panList[kMaxXSectors];
void DoSectorLighting(void)
{
for (int i = 0; i < shadeCount; i++)
{
int nXSector = shadeList[i];
XSECTOR *pXSector = &xsector[nXSector];
int nSector = pXSector->reference;
assert(sector[nSector].extra == nXSector);
if (pXSector->shade)
{
int v4 = pXSector->shade;
if (pXSector->shadeFloor)
{
sector[nSector].floorshade -= v4;
if (pXSector->color)
{
int nTemp = pXSector->floorpal;
pXSector->floorpal = sector[nSector].floorpal;
sector[nSector].floorpal = nTemp;
}
}
if (pXSector->shadeCeiling)
{
sector[nSector].ceilingshade -= v4;
if (pXSector->color)
{
int nTemp = pXSector->ceilpal;
pXSector->ceilpal = sector[nSector].ceilingpal;
sector[nSector].ceilingpal = nTemp;
}
}
if (pXSector->shadeWalls)
{
int nStartWall = sector[nSector].wallptr;
int nEndWall = nStartWall + sector[nSector].wallnum;
for (int j = nStartWall; j < nEndWall; j++)
{
wall[j].shade -= v4;
if (pXSector->color)
{
wall[j].pal = sector[nSector].floorpal;
}
}
}
pXSector->shade = 0;
}
if (pXSector->shadeAlways || pXSector->busy)
{
int t1 = pXSector->wave;
int t2 = pXSector->amplitude;
if (!pXSector->shadeAlways && pXSector->busy)
{
t2 = MulScale(t2, pXSector->busy, 16);
}
int v4 = GetWaveValue(t1, pXSector->phase*8+pXSector->freq*PlayClock, t2);
if (pXSector->shadeFloor)
{
sector[nSector].floorshade = ClipRange(sector[nSector].floorshade+v4, -128, 127);
if (pXSector->color && v4 != 0)
{
int nTemp = pXSector->floorpal;
pXSector->floorpal = sector[nSector].floorpal;
sector[nSector].floorpal = nTemp;
}
}
if (pXSector->shadeCeiling)
{
sector[nSector].ceilingshade = ClipRange(sector[nSector].ceilingshade+v4, -128, 127);
if (pXSector->color && v4 != 0)
{
int nTemp = pXSector->ceilpal;
pXSector->ceilpal = sector[nSector].ceilingpal;
sector[nSector].ceilingpal = nTemp;
}
}
if (pXSector->shadeWalls)
{
int nStartWall = sector[nSector].wallptr;
int nEndWall = nStartWall + sector[nSector].wallnum;
for (int j = nStartWall; j < nEndWall; j++)
{
wall[j].shade = ClipRange(wall[j].shade+v4, -128, 127);
if (pXSector->color && v4 != 0)
{
wall[j].pal = sector[nSector].floorpal;
}
}
}
pXSector->shade = v4;
}
}
}
void UndoSectorLighting(void)
{
for (int i = 0; i < numsectors; i++)
{
int nXSprite = sector[i].extra;
if (nXSprite > 0)
{
XSECTOR *pXSector = &xsector[i];
if (pXSector->shade)
{
int v4 = pXSector->shade;
if (pXSector->shadeFloor)
{
sector[i].floorshade -= v4;
if (pXSector->color)
{
int nTemp = pXSector->floorpal;
pXSector->floorpal = sector[i].floorpal;
sector[i].floorpal = nTemp;
}
}
if (pXSector->shadeCeiling)
{
sector[i].ceilingshade -= v4;
if (pXSector->color)
{
int nTemp = pXSector->ceilpal;
pXSector->ceilpal = sector[i].ceilingpal;
sector[i].ceilingpal = nTemp;
}
}
if (pXSector->shadeWalls)
{
int nStartWall = sector[i].wallptr;
int nEndWall = nStartWall + sector[i].wallnum;
for (int j = nStartWall; j < nEndWall; j++)
{
wall[j].shade -= v4;
if (pXSector->color)
{
wall[j].pal = sector[i].floorpal;
}
}
}
pXSector->shade = 0;
}
}
}
}
short wallPanList[kMaxXWalls];
int wallPanCount;
void DoSectorPanning(void)
{
for (int i = 0; i < panCount; i++)
{
int nXSector = panList[i];
XSECTOR *pXSector = &xsector[nXSector];
int nSector = pXSector->reference;
assert(nSector >= 0 && nSector < kMaxSectors);
sectortype *pSector = &sector[nSector];
assert(pSector->extra == nXSector);
if (pXSector->panAlways || pXSector->busy)
{
int angle = pXSector->panAngle+1024;
int speed = pXSector->panVel<<10;
if (!pXSector->panAlways && (pXSector->busy&0xffff))
speed = MulScale(speed, pXSector->busy, 16);
if (pXSector->panFloor) // Floor
{
int nTile = pSector->floorpicnum;
if (pSector->floorstat & 64)
angle -= 512;
int xBits = tileWidth(nTile) >> int((pSector->floorstat & 8) != 0);
int px = MulScale(speed << 2, Cos(angle), 30) / xBits;
int yBits = tileHeight(nTile) >> int((pSector->floorstat & 8) != 0);
int py = MulScale(speed << 2, Sin(angle), 30) / yBits;
pSector->addfloorxpan(px * (1.f / 256));
pSector->addfloorypan(-py * (1.f / 256));
}
if (pXSector->panCeiling) // Ceiling
{
int nTile = pSector->ceilingpicnum;
if (pSector->ceilingstat & 64)
angle -= 512;
int xBits = tileWidth(nTile) >> int((pSector->ceilingstat & 8) != 0);
int px = MulScale(speed << 2, Cos(angle), 30) / xBits;
int yBits = tileHeight(nTile) >> int((pSector->ceilingstat & 8) != 0);
int py = MulScale(speed << 2, Sin(angle), 30) / yBits;
pSector->addceilingxpan(px * (1.f / 256));
pSector->addceilingypan(-py * (1.f / 256));
}
}
}
for (int i = 0; i < wallPanCount; i++)
{
int nXWall = wallPanList[i];
XWALL *pXWall = &xwall[nXWall];
int nWall = pXWall->reference;
assert(wall[nWall].extra == nXWall);
if (pXWall->panAlways || pXWall->busy)
{
int psx = pXWall->panXVel<<10;
int psy = pXWall->panYVel<<10;
if (!pXWall->panAlways && (pXWall->busy & 0xffff))
{
psx = MulScale(psx, pXWall->busy, 16);
psy = MulScale(psy, pXWall->busy, 16);
}
int nTile = wall[nWall].picnum;
int px = (psx << 2) / tileWidth(nTile);
int py = (psy << 2) / tileHeight(nTile);
wall[nWall].addxpan(px * (1.f / 256));
wall[nWall].addypan(py * (1.f / 256));
}
}
}
void InitSectorFX(void)
{
shadeCount = 0;
panCount = 0;
wallPanCount = 0;
for (int i = 0; i < numsectors; i++)
{
int nXSector = sector[i].extra;
if (nXSector > 0)
{
XSECTOR *pXSector = &xsector[nXSector];
if (pXSector->amplitude)
shadeList[shadeCount++] = nXSector;
if (pXSector->panVel)
{
panList[panCount++] = nXSector;
if (pXSector->panCeiling)
{
StartInterpolation(i, Interp_Sect_CeilingPanX);
StartInterpolation(i, Interp_Sect_CeilingPanY);
}
if (pXSector->panFloor)
{
StartInterpolation(i, Interp_Sect_FloorPanX);
StartInterpolation(i, Interp_Sect_FloorPanY);
}
}
}
}
for (int i = 0; i < numwalls; i++)
{
int nXWall = wall[i].extra;
if (nXWall > 0)
{
XWALL *pXWall = &xwall[nXWall];
if (pXWall->panXVel || pXWall->panYVel)
{
wallPanList[wallPanCount++] = nXWall;
if (pXWall->panXVel) StartInterpolation(i, Interp_Wall_PanX);
if (pXWall->panXVel) StartInterpolation(i, Interp_Wall_PanY);
}
}
}
}
class CSectorListMgr
{
public:
CSectorListMgr();
int CreateList(short);
void AddSector(int, short);
int GetSectorCount(int);
short *GetSectorList(int);
private:
int nLists;
int nListSize[32];
int nListStart[32];
short nSectors[kMaxSectors];
};
CSectorListMgr::CSectorListMgr()
{
nLists = 0;
}
int CSectorListMgr::CreateList(short nSector)
{
int nStart = 0;
if (nLists)
nStart = nListStart[nLists-1]+nListStart[nLists-1];
int nList = nLists;
nListStart[nList] = nStart;
nListSize[nList] = 1;
nLists++;
short *pList = GetSectorList(nList);
pList[0] = nSector;
return nList;
}
void CSectorListMgr::AddSector(int nList, short nSector)
{
for (int i = nLists; i > nList; i--)
{
short *pList = GetSectorList(i);
int nCount = GetSectorCount(i);
memmove(pList+1,pList,nCount*sizeof(short));
nListStart[i]++;
}
short *pList = GetSectorList(nList);
int nCount = GetSectorCount(nList);
pList[nCount] = nSector;
nListSize[nList]++;
}
int CSectorListMgr::GetSectorCount(int nList)
{
return nListSize[nList];
}
short * CSectorListMgr::GetSectorList(int nList)
{
return nSectors+nListStart[nList];
}
END_BLD_NS