Merge pull request #883 from withmorten/waterlevel

add dev build code for generating waterpro.dat
This commit is contained in:
aap 2020-12-15 11:43:29 +01:00 committed by GitHub
commit e594f1d81d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 343 additions and 41 deletions

View File

@ -1,6 +1,7 @@
#include "common.h"
#include "main.h"
#include "FileMgr.h"
#include "FileLoader.h"
#include "TxdStore.h"
#include "Timer.h"
#include "Weather.h"
@ -30,8 +31,8 @@ float TEXTURE_ADDV;
int32 CWaterLevel::ms_nNoOfWaterLevels;
float CWaterLevel::ms_aWaterZs[48];
CRect CWaterLevel::ms_aWaterRects[48];
uint8 CWaterLevel::aWaterBlockList[WATER_BLOCK_SIZE][WATER_BLOCK_SIZE];
uint8 CWaterLevel::aWaterFineBlockList[WATER_FINEBLOCK_SIZE][WATER_FINEBLOCK_SIZE];
int8 CWaterLevel::aWaterBlockList[WATER_BLOCK_SIZE][WATER_BLOCK_SIZE];
int8 CWaterLevel::aWaterFineBlockList[WATER_FINEBLOCK_SIZE][WATER_FINEBLOCK_SIZE];
bool CWaterLevel::WavesCalculatedThisFrame;
RpAtomic *CWaterLevel::ms_pWavyAtomic;
RpGeometry *CWaterLevel::apGeomArray[8];
@ -58,28 +59,158 @@ void
CWaterLevel::Initialise(Const char *pWaterDat)
{
ms_nNoOfWaterLevels = 0;
#ifdef MASTER
int32 hFile = -1;
do
while ((hFile = CFileMgr::OpenFile("DATA\\waterpro.dat", "rb")) < 0);
#else
int32 hFile = CFileMgr::OpenFile("DATA\\waterpro.dat", "rb");
#endif
if (hFile > 0)
{
hFile = CFileMgr::OpenFile("DATA\\waterpro.dat", "rb");
}
while ( hFile < 0 );
if ( hFile > 0 )
{
if ( hFile >= 0 )
{
CFileMgr::Read(hFile, (char *)&ms_nNoOfWaterLevels, sizeof(ms_nNoOfWaterLevels));
CFileMgr::Read(hFile, (char *)ms_aWaterZs, sizeof(ms_aWaterZs));
CFileMgr::Read(hFile, (char *)ms_aWaterRects, sizeof(ms_aWaterRects));
CFileMgr::Read(hFile, (char *)aWaterBlockList, sizeof(aWaterBlockList));
CFileMgr::Read(hFile, (char *)aWaterFineBlockList, sizeof(aWaterFineBlockList));
}
CFileMgr::Read(hFile, (char *)&ms_nNoOfWaterLevels, sizeof(ms_nNoOfWaterLevels));
CFileMgr::Read(hFile, (char *)ms_aWaterZs, sizeof(ms_aWaterZs));
CFileMgr::Read(hFile, (char *)ms_aWaterRects, sizeof(ms_aWaterRects));
CFileMgr::Read(hFile, (char *)aWaterBlockList, sizeof(aWaterBlockList));
CFileMgr::Read(hFile, (char *)aWaterFineBlockList, sizeof(aWaterFineBlockList));
CFileMgr::CloseFile(hFile);
}
#ifndef MASTER
else
{
printf("Init waterlevels\n");
CFileMgr::SetDir("");
hFile = CFileMgr::OpenFile(pWaterDat, "r");
char *line;
while ((line = CFileLoader::LoadLine(hFile)))
{
if (*line && *line != ';')
{
float z, l, b, r, t;
sscanf(line, "%f %f %f %f %f", &z, &l, &b, &r, &t);
AddWaterLevel(l, b, r, t, z);
}
}
CFileMgr::CloseFile(hFile);
for (int32 x = 0; x < WATER_FINEBLOCK_SIZE; x++)
{
for (int32 y = 0; y < WATER_FINEBLOCK_SIZE; y++)
{
aWaterFineBlockList[x][y] = NO_WATER;
}
}
for (int32 i = 0; i < ms_nNoOfWaterLevels; i++)
{
int32 l = WATER_HUGE_X(ms_aWaterRects[i].left);
int32 r = WATER_HUGE_X(ms_aWaterRects[i].right) + 1.0f;
int32 t = WATER_HUGE_Y(ms_aWaterRects[i].top);
int32 b = WATER_HUGE_Y(ms_aWaterRects[i].bottom) + 1.0f;
// originally this writes *god* knows where everywhere in game memory ...
// even in debug it manages to reach some textures so librw crashes with a ptr being 0x15151515 ....
#ifdef FIX_BUGS
l = clamp(l, 0, WATER_FINEBLOCK_SIZE - 1);
r = clamp(r, 0, WATER_FINEBLOCK_SIZE - 1);
t = clamp(t, 0, WATER_FINEBLOCK_SIZE - 1);
b = clamp(b, 0, WATER_FINEBLOCK_SIZE - 1);
#endif
for (int32 x = l; x <= r; x++)
{
for (int32 y = t; y <= b; y++)
{
aWaterFineBlockList[x][y] = i;
}
}
}
for (int32 x = 0; x < WATER_FINEBLOCK_SIZE; x++)
{
int32 worldX = WATER_START_X + x * SMALL_SECTOR_WIDTH;
for (int32 y = 0; y < WATER_FINEBLOCK_SIZE; y++)
{
if (aWaterBlockList[x][y] >= 0)
{
int32 worldY = WATER_START_Y + y * SMALL_SECTOR_WIDTH;
int32 i;
for (i = 0; i <= 8; i++)
{
for (int32 j = 0; j <= 8; j++)
{
CVector worldPos = CVector(worldX + i * (SMALL_SECTOR_WIDTH / 8), worldY + j * (SMALL_SECTOR_WIDTH / 8), ms_aWaterZs[aWaterFineBlockList[x][y]]);
if ((worldPos.x > WORLD_MIN_X && worldPos.x < WORLD_MAX_X) && (worldPos.y > WORLD_MIN_Y && worldPos.y < WORLD_MAX_Y))
{
if (WaterLevelAccordingToRectangles(worldPos.x, worldPos.y) && !TestVisibilityForFineWaterBlocks(worldPos))
{
i = 1000;
break;
}
}
}
if (i == 1000) break;
}
if (i < 1000) aWaterFineBlockList[x][y] = NO_WATER;
}
}
}
RemoveIsolatedWater();
for (int32 x = 0; x < WATER_BLOCK_SIZE; x++)
{
for (int32 y = 0; y < WATER_BLOCK_SIZE; y++)
{
if (aWaterFineBlockList[x * 2][y * 2] >= 0)
{
aWaterBlockList[x][y] = aWaterFineBlockList[x * 2][y * 2];
}
else if (aWaterFineBlockList[x * 2 + 1][y * 2] >= 0)
{
aWaterBlockList[x][y] = aWaterFineBlockList[x * 2 + 1][y * 2];
}
else if (aWaterFineBlockList[x * 2][y * 2 + 1] >= 0)
{
aWaterBlockList[x][y] = aWaterFineBlockList[x * 2][y * 2 + 1];
}
else if (aWaterFineBlockList[x * 2 + 1][y * 2 + 1] >= 0)
{
aWaterBlockList[x][y] = aWaterFineBlockList[x * 2 + 1][y * 2 + 1];
}
else
{
aWaterBlockList[x][y] = NO_WATER;
}
}
}
hFile = CFileMgr::OpenFileForWriting("data\\waterpro.dat");
if (hFile > 0)
{
CFileMgr::Write(hFile, (char *)&ms_nNoOfWaterLevels, sizeof(ms_nNoOfWaterLevels));
CFileMgr::Write(hFile, (char *)ms_aWaterZs, sizeof(ms_aWaterZs));
CFileMgr::Write(hFile, (char *)ms_aWaterRects, sizeof(ms_aWaterRects));
CFileMgr::Write(hFile, (char *)aWaterBlockList, sizeof(aWaterBlockList));
CFileMgr::Write(hFile, (char *)aWaterFineBlockList, sizeof(aWaterFineBlockList));
CFileMgr::CloseFile(hFile);
}
}
#endif
CTxdStore::PushCurrentTxd();
@ -222,6 +353,170 @@ CWaterLevel::DestroyWavyAtomic()
RwFrameDestroy(frame);
}
#ifndef MASTER
void
CWaterLevel::AddWaterLevel(float fXLeft, float fYBottom, float fXRight, float fYTop, float fLevel)
{
ms_aWaterRects[ms_nNoOfWaterLevels] = CRect(fXLeft, fYBottom, fXRight, fYTop);
ms_aWaterZs[ms_nNoOfWaterLevels] = fLevel;
ms_nNoOfWaterLevels++;
}
bool
CWaterLevel::WaterLevelAccordingToRectangles(float fX, float fY, float *pfOutLevel)
{
if (ms_nNoOfWaterLevels <= 0) return false;
for (int32 i = 0; i < ms_nNoOfWaterLevels; i++)
{
if (fX >= ms_aWaterRects[i].left && fX <= ms_aWaterRects[i].right
&& fY >= ms_aWaterRects[i].top && fY <= ms_aWaterRects[i].bottom)
{
if (pfOutLevel) *pfOutLevel = ms_aWaterZs[i];
return true;
}
}
return false;
}
bool
CWaterLevel::TestVisibilityForFineWaterBlocks(const CVector &worldPos)
{
static CVector2D tab[] =
{
{ 50.0f, 50.0f },
{ -50.0f, 50.0f },
{ -50.0f, -50.0f },
{ 50.0f, -50.0f },
{ 50.0f, 0.0f },
{ -50.0f, 0.0f },
{ 0.0f, -50.0f },
{ 0.0f, 50.0f },
};
CEntity *entity;
CColPoint col;
CVector lineStart, lineEnd;
lineStart = worldPos;
if (!CWorld::ProcessVerticalLine(lineStart, lineStart.z + 100.0f, col, entity, true, false, false, false, true, false, nil))
{
lineStart.x += 0.4f;
lineStart.y += 0.4f;
if (!CWorld::ProcessVerticalLine(lineStart, lineStart.z + 100.0f, col, entity, true, false, false, false, true, false, nil))
{
return false;
}
}
for (int32 i = 0; i < ARRAY_SIZE(tab); i++)
{
lineStart = worldPos;
lineEnd = worldPos;
lineEnd.x += tab[i].x;
lineEnd.y += tab[i].y;
lineEnd.z += 100.0f;
if ((lineEnd.x > WORLD_MIN_X && lineEnd.x < WORLD_MAX_X) && (lineEnd.y > WORLD_MIN_Y && lineEnd.y < WORLD_MAX_Y))
{
if (!CWorld::ProcessLineOfSight(lineStart, lineEnd, col, entity, true, false, false, false, true, false, nil))
{
lineStart.x += 0.4f;
lineStart.y += 0.4f;
lineEnd.x += 0.4f;
lineEnd.y += 0.4f;
if (!CWorld::ProcessLineOfSight(lineStart, lineEnd, col, entity, true, false, false, false, true, false, nil))
{
return false;
}
}
}
}
return true;
}
void
CWaterLevel::RemoveIsolatedWater()
{
bool (*isConnected)[WATER_FINEBLOCK_SIZE] = new bool[WATER_FINEBLOCK_SIZE][WATER_FINEBLOCK_SIZE];
for (int32 x = 0; x < WATER_FINEBLOCK_SIZE; x++)
{
for (int32 y = 0; y < WATER_FINEBLOCK_SIZE; y++)
{
isConnected[x][y] = false;
}
}
isConnected[0][0] = true;
bool keepGoing;
do
{
keepGoing = false;
for (int32 x = 0; x < WATER_FINEBLOCK_SIZE; x++)
{
for (int32 y = 0; y < WATER_FINEBLOCK_SIZE; y++)
{
if (aWaterBlockList[x][y] >= 0 && !isConnected[x][y])
{
if (x > 0 && isConnected[x - 1][y])
{
isConnected[x][y] = true;
keepGoing = true;
}
if (y > 0 && isConnected[x][y - 1])
{
isConnected[x][y] = true;
keepGoing = true;
}
if (x + 1 < WATER_FINEBLOCK_SIZE && isConnected[x + 1][y])
{
isConnected[x][y] = true;
keepGoing = true;
}
if (y + 1 < WATER_FINEBLOCK_SIZE && isConnected[x][y + 1])
{
isConnected[x][y] = true;
keepGoing = true;
}
}
}
}
}
while (keepGoing);
int32 numRemoved = 0;
for (int32 x = 0; x < WATER_FINEBLOCK_SIZE; x++)
{
for (int32 y = 0; y < WATER_FINEBLOCK_SIZE; y++)
{
if (aWaterBlockList[x][y] >= 0 && !isConnected[x][y] && ms_aWaterZs[aWaterFineBlockList[x][y]] != 0.0f)
{
numRemoved++;
aWaterFineBlockList[x][y] = NO_WATER;
}
}
}
printf("Removed %d isolated patches of water\n", numRemoved);
delete[] isConnected;
}
#endif
bool
CWaterLevel::GetWaterLevel(float fX, float fY, float fZ, float *pfOutLevel, bool bDontCheckZ)
{
@ -231,9 +526,9 @@ CWaterLevel::GetWaterLevel(float fX, float fY, float fZ, float *pfOutLevel, bool
ASSERT( x >= 0 && x < HUGE_SECTOR_SIZE );
ASSERT( y >= 0 && y < HUGE_SECTOR_SIZE );
uint8 nBlock = aWaterFineBlockList[x][y];
int8 nBlock = aWaterFineBlockList[x][y];
if ( nBlock == 128 )
if ( nBlock == NO_WATER )
return false;
ASSERT( pfOutLevel != NULL );
@ -270,9 +565,9 @@ CWaterLevel::GetWaterLevelNoWaves(float fX, float fY, float fZ, float *pfOutLeve
ASSERT( x >= 0 && x < HUGE_SECTOR_SIZE );
ASSERT( y >= 0 && y < HUGE_SECTOR_SIZE );
uint8 nBlock = aWaterFineBlockList[x][y];
int8 nBlock = aWaterFineBlockList[x][y];
if ( nBlock == 128 )
if ( nBlock == NO_WATER )
return false;
ASSERT( pfOutLevel != NULL );
@ -418,10 +713,10 @@ CWaterLevel::RenderWater()
{
for ( int32 y = nStartY; y <= nEndY; y++ )
{
if ( !(aWaterBlockList[2*x+0][2*y+0] & 128)
|| !(aWaterBlockList[2*x+1][2*y+0] & 128)
|| !(aWaterBlockList[2*x+0][2*y+1] & 128)
|| !(aWaterBlockList[2*x+1][2*y+1] & 128) )
if ( aWaterBlockList[2*x+0][2*y+0] >= 0
|| aWaterBlockList[2*x+1][2*y+0] >= 0
|| aWaterBlockList[2*x+0][2*y+1] >= 0
|| aWaterBlockList[2*x+1][2*y+1] >= 0 )
{
float fX = WATER_FROM_HUGE_SECTOR_X(x);
float fY = WATER_FROM_HUGE_SECTOR_Y(y);
@ -443,16 +738,16 @@ CWaterLevel::RenderWater()
{
float fZ;
if ( !(aWaterBlockList[2*x+0][2*y+0] & 128) )
if ( aWaterBlockList[2*x+0][2*y+0] >= 0 )
fZ = ms_aWaterZs[ aWaterBlockList[2*x+0][2*y+0] ];
if ( !(aWaterBlockList[2*x+1][2*y+0] & 128) )
if ( aWaterBlockList[2*x+1][2*y+0] >= 0 )
fZ = ms_aWaterZs[ aWaterBlockList[2*x+1][2*y+0] ];
if ( !(aWaterBlockList[2*x+0][2*y+1] & 128) )
if ( aWaterBlockList[2*x+0][2*y+1] >= 0 )
fZ = ms_aWaterZs[ aWaterBlockList[2*x+0][2*y+1] ];
if ( !(aWaterBlockList[2*x+1][2*y+1] & 128) )
if ( aWaterBlockList[2*x+1][2*y+1] >= 0 )
fZ = ms_aWaterZs[ aWaterBlockList[2*x+1][2*y+1] ];
RenderOneFlatHugeWaterPoly(fX, fY, fZ, color);
@ -463,7 +758,7 @@ CWaterLevel::RenderWater()
{
for ( int32 y2 = 2*y; y2 <= 2*y+1; y2++ )
{
if ( !(aWaterBlockList[x2][y2] & 128) )
if ( aWaterBlockList[x2][y2] >= 0 )
{
float fLargeX = WATER_FROM_LARGE_SECTOR_X(x2);
float fLargeY = WATER_FROM_LARGE_SECTOR_Y(y2);
@ -498,7 +793,7 @@ CWaterLevel::RenderWater()
float fZ;
// WS
if ( !(aWaterFineBlockList[2*x2+0][2*y2+0] & 128) )
if ( aWaterFineBlockList[2*x2+0][2*y2+0] >= 0 )
{
float fSmallX = fLargeX;
float fSmallY = fLargeY;
@ -519,7 +814,7 @@ CWaterLevel::RenderWater()
}
// SE
if ( !(aWaterFineBlockList[2*x2+1][2*y2+0] & 128) )
if ( aWaterFineBlockList[2*x2+1][2*y2+0] >= 0 )
{
float fSmallX = fLargeX + (LARGE_SECTOR_SIZE/2);
float fSmallY = fLargeY;
@ -540,7 +835,7 @@ CWaterLevel::RenderWater()
}
// WN
if ( !(aWaterFineBlockList[2*x2+0][2*y2+1] & 128) )
if ( aWaterFineBlockList[2*x2+0][2*y2+1] >= 0 )
{
float fSmallX = fLargeX;
float fSmallY = fLargeY + (LARGE_SECTOR_SIZE/2);
@ -561,7 +856,7 @@ CWaterLevel::RenderWater()
}
//NE
if ( !(aWaterFineBlockList[2*x2+1][2*y2+1] & 128) )
if ( aWaterFineBlockList[2*x2+1][2*y2+1] >= 0 )
{
float fSmallX = fLargeX + (LARGE_SECTOR_SIZE/2);
float fSmallY = fLargeY + (LARGE_SECTOR_SIZE/2);
@ -591,7 +886,7 @@ CWaterLevel::RenderWater()
}
} // if ( TheCamera.IsSphereVisible
} // if ( fLargeSectorDistToCamSqr < fHugeSectorMaxRenderDistSqr )
} // if ( !(aWaterBlockList[x2][y2] & 128) )
} // if ( aWaterBlockList[x2][y2] >= 0 )
} // for ( int32 y2 = 2*y; y2 <= 2*y+1; y2++ )
} // for ( int32 x2 = 2*x; x2 <= 2*x+1; x2++ )
//
@ -1116,7 +1411,7 @@ CWaterLevel::CalcDistanceToWater(float fX, float fY)
{
for ( int32 y = nStartY; y <= nEndY; y++ )
{
if ( !(aWaterFineBlockList[x][y] & 128) )
if ( aWaterFineBlockList[x][y] >= 0 )
{
float fSectorX = WATER_FROM_SMALL_SECTOR_X(x);
float fSectorY = WATER_FROM_SMALL_SECTOR_Y(y);

View File

@ -4,6 +4,8 @@
#define WATER_FINEBLOCK_SIZE HUGE_SECTOR_SIZE
#define WATER_Z_OFFSET (1.5f)
#define NO_WATER -128
#define MAX_SMALL_SECTORS 128
#define MAX_LARGE_SECTORS 64
#define MAX_HUGE_SECTORS 32
@ -23,6 +25,7 @@
#define WATER_WIDTH ((WATER_END_X - WATER_START_X))
#define WATER_HEIGHT ((WATER_END_Y - WATER_START_Y))
#define SMALL_SECTOR_WIDTH (WATER_WIDTH/MAX_SMALL_SECTORS)
#define WATER_UNSIGN_X(x) ( (x) + (WATER_WIDTH /2) )
#define WATER_UNSIGN_Y(y) ( (y) + (WATER_HEIGHT/2) )
@ -72,8 +75,8 @@ class CWaterLevel
static int32 ms_nNoOfWaterLevels;
static float ms_aWaterZs[48];
static CRect ms_aWaterRects[48];
static uint8 aWaterBlockList[WATER_BLOCK_SIZE][WATER_BLOCK_SIZE];
static uint8 aWaterFineBlockList[WATER_FINEBLOCK_SIZE][WATER_FINEBLOCK_SIZE];
static int8 aWaterBlockList[WATER_BLOCK_SIZE][WATER_BLOCK_SIZE];
static int8 aWaterFineBlockList[WATER_FINEBLOCK_SIZE][WATER_FINEBLOCK_SIZE];
static bool WavesCalculatedThisFrame;
static RpAtomic *ms_pWavyAtomic;
static RpGeometry *apGeomArray[MAX_BOAT_WAKES];
@ -84,6 +87,10 @@ public:
static void Shutdown();
static void CreateWavyAtomic();
static void DestroyWavyAtomic();
static void AddWaterLevel(float fXLeft, float fYBottom, float fXRight, float fYTop, float fLevel);
static bool WaterLevelAccordingToRectangles(float fX, float fY, float *pfOutLevel = nil);
static bool TestVisibilityForFineWaterBlocks(const CVector &worldPos);
static void RemoveIsolatedWater();
static bool GetWaterLevel(float fX, float fY, float fZ, float *pfOutLevel, bool bDontCheckZ);
static bool GetWaterLevel(CVector coors, float *pfOutLevel, bool bDontCheckZ) { return GetWaterLevel(coors.x, coors.y, coors.z, pfOutLevel, bDontCheckZ); }
static bool GetWaterLevelNoWaves(float fX, float fY, float fZ, float *pfOutLevel);