From aed8218ef16679b36e5d869e79128315d9140794 Mon Sep 17 00:00:00 2001 From: Fire-Head Date: Thu, 11 Jul 2019 03:22:01 +0300 Subject: [PATCH] WaterLevel done --- src/core/common.h | 1 + src/render/Particle.h | 4 +- src/render/RenderBuffer.cpp | 10 +- src/render/RenderBuffer.h | 8 + src/render/WaterLevel.cpp | 1254 ++++++++++++++++++++++++++++++++++- src/render/WaterLevel.h | 92 ++- src/vehicles/Boat.cpp | 63 ++ src/vehicles/Boat.h | 44 +- 8 files changed, 1464 insertions(+), 12 deletions(-) diff --git a/src/core/common.h b/src/core/common.h index 79626acb..33ebcdbb 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -138,6 +138,7 @@ inline float sq(float x) { return x*x; } #define SQR(x) ((x) * (x)) #define PI M_PI +#define TWOPI PI*2 #define DEGTORAD(x) ((x) * PI / 180.0f) #define RADTODEG(x) ((x) * 180.0f / PI) diff --git a/src/render/Particle.h b/src/render/Particle.h index 25677569..eaacf2f5 100644 --- a/src/render/Particle.h +++ b/src/render/Particle.h @@ -6,13 +6,13 @@ class CEntity; class CParticle { +public: enum { RAND_TABLE_SIZE = 20, SIN_COS_TABLE_SIZE = 1024 }; - -public: + CVector m_vecPosition; CVector m_vecVelocity; CVector m_vecScreenPosition; diff --git a/src/render/RenderBuffer.cpp b/src/render/RenderBuffer.cpp index 9a1ed58d..1b91156e 100644 --- a/src/render/RenderBuffer.cpp +++ b/src/render/RenderBuffer.cpp @@ -5,7 +5,7 @@ int32 &TempBufferVerticesStored = *(int32*)0x8F5F78; int32 &TempBufferIndicesStored = *(int32*)0x8F1A4C; -RwIm3DVertex *TempVertexBuffer = (RwIm3DVertex*)0x862330; +RwIm3DVertex *TempBufferRenderVertices = (RwIm3DVertex*)0x862330; RwImVertexIndex *TempBufferRenderIndexList = (RwImVertexIndex*)0x846288; int RenderBuffer::VerticesToBeStored; @@ -21,12 +21,12 @@ RenderBuffer::ClearRenderBuffer(void) void RenderBuffer::StartStoring(int numIndices, int numVertices, RwImVertexIndex **indexStart, RwIm3DVertex **vertexStart) { - if(TempBufferIndicesStored + numIndices >= 1024) + if(TempBufferIndicesStored + numIndices >= TEMPBUFFERINDEXSIZE) RenderStuffInBuffer(); - if(TempBufferVerticesStored + numVertices >= 256) + if(TempBufferVerticesStored + numVertices >= TEMPBUFFERVERTSIZE) RenderStuffInBuffer(); *indexStart = &TempBufferRenderIndexList[TempBufferIndicesStored]; - *vertexStart = &TempVertexBuffer[TempBufferVerticesStored]; + *vertexStart = &TempBufferRenderVertices[TempBufferVerticesStored]; IndicesToBeStored = numIndices; VerticesToBeStored = numVertices; } @@ -44,7 +44,7 @@ RenderBuffer::StopStoring(void) void RenderBuffer::RenderStuffInBuffer(void) { - if(TempBufferVerticesStored && RwIm3DTransform(TempVertexBuffer, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){ + if(TempBufferVerticesStored && RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){ RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored); RwIm3DEnd(); } diff --git a/src/render/RenderBuffer.h b/src/render/RenderBuffer.h index 66baa2d0..28bfe157 100644 --- a/src/render/RenderBuffer.h +++ b/src/render/RenderBuffer.h @@ -8,3 +8,11 @@ public: static void StopStoring(void); static void RenderStuffInBuffer(void); }; + +#define TEMPBUFFERVERTSIZE 256 +#define TEMPBUFFERINDEXSIZE 1024 + +extern int32 &TempBufferVerticesStored; +extern int32 &TempBufferIndicesStored; +extern RwIm3DVertex *TempBufferRenderVertices; +extern RwImVertexIndex *TempBufferRenderIndexList; \ No newline at end of file diff --git a/src/render/WaterLevel.cpp b/src/render/WaterLevel.cpp index 866847b3..d5138b28 100644 --- a/src/render/WaterLevel.cpp +++ b/src/render/WaterLevel.cpp @@ -1,5 +1,1255 @@ #include "common.h" -#include "patcher.h" +#include "FileMgr.h" +#include "TxdStore.h" +#include "Timer.h" +#include "Weather.h" +#include "Camera.h" +#include "Vehicle.h" +#include "Boat.h" +#include "World.h" +#include "General.h" +#include "TimeCycle.h" +#include "ZoneCull.h" +#include "Clock.h" +#include "Particle.h" +#include "ParticleMgr.h" +#include "RwHelper.h" +#include "Streaming.h" +#include "CdStream.h" +#include "Pad.h" +#include "RenderBuffer.h" +#include #include "WaterLevel.h" +#include "patcher.h" -WRAPPER void CWaterLevel::RenderWater(void) { EAXJMP(0x5554E0); } +float TEXTURE_ADDU; +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]; +bool CWaterLevel::WavesCalculatedThisFrame; +RpAtomic *CWaterLevel::ms_pWavyAtomic; +RpGeometry *CWaterLevel::apGeomArray[8]; +int16 CWaterLevel::nGeomUsed; + +//RwTexture *gpWaterTex; +//RwRaster *gpWaterRaster; + +RwTexture *&gpWaterTex = *(RwTexture **)0x64D070; +RwRaster *&gpWaterRaster = *(RwRaster **)0x8F5FD4; + + +const float fAdd1 = 180.0f; +const float fAdd2 = 80.0f; +const float fRedMult = 0.6f; +const float fGreenMult = 1.0f; +const float fBlueMult = 1.4f; + + + +void +CWaterLevel::Initialise(char *pWaterDat) +{ + ms_nNoOfWaterLevels = 0; + + int32 hFile = -1; + + do + { + 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::CloseFile(hFile); + } + + CTxdStore::PushCurrentTxd(); + + int32 slot = CTxdStore::FindTxdSlot("particle"); + CTxdStore::SetCurrentTxd(slot); + + if ( gpWaterTex == NULL ) + gpWaterTex = RwTextureRead("water_old", NULL); + gpWaterRaster = RwTextureGetRaster(gpWaterTex); + + CTxdStore::PopCurrentTxd(); + + CreateWavyAtomic(); + FreeBoatWakeArray(); + + printf("Done Initing waterlevels\n"); +} + +void +CWaterLevel::Shutdown() +{ + FreeBoatWakeArray(); + DestroyWavyAtomic(); + + if ( gpWaterTex != NULL ) + { + RwTextureDestroy(gpWaterTex); + gpWaterTex = NULL; + } +} + +void +CWaterLevel::CreateWavyAtomic() +{ + RpGeometry *wavyGeometry; + RpMaterial *wavyMaterial; + RpTriangle *wavyTriangles; + RpMorphTarget *wavyMorphTarget; + RwSphere boundingSphere; + RwV3d *wavyVert; + + RwFrame *wavyFrame; + + { + wavyGeometry = RpGeometryCreate(9*9, 8*8*2, rpGEOMETRYTRISTRIP + |rpGEOMETRYTEXTURED + |rpGEOMETRYPRELIT + |rpGEOMETRYMODULATEMATERIALCOLOR); + + ASSERT(wavyGeometry != NULL); + + } + + { + wavyMaterial = RpMaterialCreate(); + + ASSERT(wavyMaterial != NULL); + ASSERT(gpWaterTex != NULL); + + RpMaterialSetTexture(wavyMaterial, gpWaterTex); + } + + { + wavyTriangles = RpGeometryGetTriangles(wavyGeometry); + + ASSERT(wavyTriangles != NULL); + /* + [B] [C] + *********** + * * * + * * * + * * * + * * * + *********** + [A] [D] + */ + + for ( int32 i = 0; i < 8; i++ ) + { + for ( int32 j = 0; j < 8; j++ ) + { + RpGeometryTriangleSetVertexIndices(wavyGeometry, + &wavyTriangles[2 * 8*i + 2*j + 0], /*A*/9*i+j+0, /*B*/9*i+j+1, /*C*/9*i+j+9+1); + + RpGeometryTriangleSetVertexIndices(wavyGeometry, + &wavyTriangles[2 * 8*i + 2*j + 1], /*A*/9*i+j+0, /*C*/9*i+j+9+1, /*D*/9*i+j+9 ); + + RpGeometryTriangleSetMaterial(wavyGeometry, &wavyTriangles[2 * 8*i + 2*j + 0], wavyMaterial); + RpGeometryTriangleSetMaterial(wavyGeometry, &wavyTriangles[2 * 8*i + 2*j + 1], wavyMaterial); + } + } + } + + + { + wavyMorphTarget = RpGeometryGetMorphTarget(wavyGeometry, 0); + wavyVert = RpMorphTargetGetVertices(wavyMorphTarget); + + ASSERT(wavyMorphTarget != NULL); + ASSERT(wavyVert != NULL); + + for ( int32 i = 0; i < 9; i++ ) + { + for ( int32 j = 0; j < 9; j++ ) + { + wavyVert[9*i+j].x = (float)i * 4.0f; + wavyVert[9*i+j].y = (float)j * 4.0f; + wavyVert[9*i+j].z = 0.0f; + } + } + + RpMorphTargetCalcBoundingSphere(wavyMorphTarget, &boundingSphere); + RpMorphTargetSetBoundingSphere(wavyMorphTarget, &boundingSphere); + RpGeometryUnlock(wavyGeometry); + } + + + { + wavyFrame = RwFrameCreate(); + ASSERT( wavyFrame != NULL ); + + ms_pWavyAtomic = RpAtomicCreate(); + ASSERT( ms_pWavyAtomic != NULL ); + + RpAtomicSetGeometry(ms_pWavyAtomic, wavyGeometry, 0); + RpAtomicSetFrame(ms_pWavyAtomic, wavyFrame); + RpMaterialDestroy(wavyMaterial); + RpGeometryDestroy(wavyGeometry); + } +} + +void +CWaterLevel::DestroyWavyAtomic() +{ + RwFrame *frame; + + frame = RpAtomicGetFrame(ms_pWavyAtomic); + + RpAtomicDestroy(ms_pWavyAtomic); + + RwFrameDestroy(frame); +} + +bool +CWaterLevel::GetWaterLevel(float fX, float fY, float fZ, float *pfOutLevel, bool bDontCheckZ) +{ + int32 x = WATER_HUGE_X(fX); + int32 y = WATER_HUGE_Y(fY); + + ASSERT( x >= 0 && x < HUGE_SECTOR_SIZE ); + ASSERT( y >= 0 && y < HUGE_SECTOR_SIZE ); + + uint8 nBlock = aWaterFineBlockList[x][y]; + + if ( nBlock == 128 ) + return false; + + ASSERT( pfOutLevel != NULL ); + *pfOutLevel = ms_aWaterZs[nBlock]; + + float fAngle = (CTimer::GetTimeInMilliseconds() & 4095) * (TWOPI / 4096.0f); + + float fWave = sin + ( + /*( WATER_UNSIGN_Y(fY) - float(y) * MAX_HUGE_SECTORS + WATER_UNSIGN_X(fX) - float(x) * MAX_HUGE_SECTORS )*/ // VC + (float)( ((int32)fX & (MAX_HUGE_SECTORS-1)) + ((int32)fY & (MAX_HUGE_SECTORS-1)) ) + * (TWOPI / MAX_HUGE_SECTORS ) + fAngle + ); + + float fWindFactor = CWeather::Wind * 0.7f + 0.3f; + + *pfOutLevel += fWave * fWindFactor; + + if ( bDontCheckZ == false && (*pfOutLevel - fZ) > 3.0f ) + { + *pfOutLevel = 0.0f; + return false; + } + + return true; +} + +bool +CWaterLevel::GetWaterLevelNoWaves(float fX, float fY, float fZ, float *pfOutLevel) +{ + int32 x = WATER_HUGE_X(fX); + int32 y = WATER_HUGE_Y(fY); + + ASSERT( x >= 0 && x < HUGE_SECTOR_SIZE ); + ASSERT( y >= 0 && y < HUGE_SECTOR_SIZE ); + + uint8 nBlock = aWaterFineBlockList[x][y]; + + if ( nBlock == 128 ) + return false; + + ASSERT( pfOutLevel != NULL ); + *pfOutLevel = ms_aWaterZs[nBlock]; + + return true; +} + +inline float +_GetWaterDrawDist() +{ + // if z less then 15.0f return 1200.0f + if ( TheCamera.GetPosition().z < 15.0f ) + return 1200.0f; + + // if z greater then 60.0f return 2000.0f; + if ( TheCamera.GetPosition().z > 60.0f ) + return 2000.0f; + + return (TheCamera.GetPosition().z + -15.0f) * 800.0f / 45.0f + 1200.0f; +} + +inline float +_GetWavyDrawDist() +{ + if ( FindPlayerVehicle() && FindPlayerVehicle()->IsBoat() ) + return 120.0f; + else + return 70.0f; +} + +inline void +_GetCamBounds(bool *bUseCamStartY, bool *bUseCamEndY, bool *bUseCamStartX, bool *bUseCamEndX) +{ + if ( TheCamera.GetForward().z > -0.8f ) + { + if ( fabsf(TheCamera.GetForward().x) > fabsf(TheCamera.GetForward().y) ) + { + if ( TheCamera.GetForward().x > 0.0f ) + *bUseCamStartX = true; + else + *bUseCamEndX = true; + } + else + { + if ( TheCamera.GetForward().y > 0.0f ) + *bUseCamStartY = true; + else + *bUseCamEndY = true; + } + } +} + +float +SectorRadius(float fSize) +{ + return sqrtf(powf(fSize, 2) + powf(fSize, 2)); +} + +void +CWaterLevel::RenderWater() +{ + bool bUseCamEndX = false; + bool bUseCamStartY = false; + + bool bUseCamStartX = false; + bool bUseCamEndY = false; + + float fWavySectorMaxRenderDist = _GetWavyDrawDist(); + float fWavySectorMaxRenderDistSqr = SQR(fWavySectorMaxRenderDist); + + _GetCamBounds(&bUseCamStartY, &bUseCamEndY, &bUseCamStartX, &bUseCamEndX); + + float fHugeSectorMaxRenderDist = _GetWaterDrawDist(); + float fHugeSectorMaxRenderDistSqr = SQR(fHugeSectorMaxRenderDist); + + float windAddUV = CWeather::Wind * 0.0015f + 0.0005f; + + + if ( !CTimer::GetIsPaused() ) + { + TEXTURE_ADDU += CGeneral::GetRandomNumberInRange(-0.0005f, 0.0005f) + windAddUV; + TEXTURE_ADDV += CGeneral::GetRandomNumberInRange(-0.0005f, 0.0005f) + windAddUV; + } + + if ( TEXTURE_ADDU >= 1.0f ) + TEXTURE_ADDU = 0.0f; + if ( TEXTURE_ADDV >= 1.0f ) + TEXTURE_ADDV = 0.0f; + + WavesCalculatedThisFrame = false; + + RwRGBA color = { 0, 0, 0, 255 }; + + color.red = uint32((CTimeCycle::GetDirectionalRed() * 0.5f + CTimeCycle::GetAmbientRed() ) * 255.0f); + color.green = uint32((CTimeCycle::GetDirectionalGreen() * 0.5f + CTimeCycle::GetAmbientGreen()) * 255.0f); + color.blue = uint32((CTimeCycle::GetDirectionalBlue() * 0.5f + CTimeCycle::GetAmbientBlue() ) * 255.0f); + + TempBufferVerticesStored = 0; + TempBufferIndicesStored = 0; + + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)gpWaterRaster); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDZERO); + + CVector2D camPos + ( + TheCamera.GetPosition().x, + TheCamera.GetPosition().y + ); + + int32 nStartX = WATER_TO_HUGE_SECTOR_X(camPos.x - fHugeSectorMaxRenderDist); + int32 nEndX = WATER_TO_HUGE_SECTOR_X(camPos.x + fHugeSectorMaxRenderDist) + 1; + int32 nStartY = WATER_TO_HUGE_SECTOR_Y(camPos.y - fHugeSectorMaxRenderDist); + int32 nEndY = WATER_TO_HUGE_SECTOR_Y(camPos.y + fHugeSectorMaxRenderDist) + 1; + + if ( bUseCamStartX ) + nStartX = WATER_TO_HUGE_SECTOR_X(camPos.x); + if ( bUseCamEndX ) + nEndX = WATER_TO_HUGE_SECTOR_X(camPos.x); + if ( bUseCamStartY ) + nStartY = WATER_TO_HUGE_SECTOR_Y(camPos.y); + if ( bUseCamEndY ) + nEndY = WATER_TO_HUGE_SECTOR_Y(camPos.y); + + nStartX = clamp(nStartX, 0, MAX_HUGE_SECTORS - 1); + nEndX = clamp(nEndX, 0, MAX_HUGE_SECTORS - 1); + nStartY = clamp(nStartY, 0, MAX_HUGE_SECTORS - 1); + nEndY = clamp(nEndY, 0, MAX_HUGE_SECTORS - 1); + + for ( int32 x = nStartX; x <= nEndX; x++ ) + { + 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) ) + { + float fX = WATER_FROM_HUGE_SECTOR_X(x); + float fY = WATER_FROM_HUGE_SECTOR_Y(y); + + CVector2D vecHugeSectorCentre + ( + fX + HUGE_SECTOR_SIZE/2, + fY + HUGE_SECTOR_SIZE/2 + ); + + float fHugeSectorDistToCamSqr = (camPos - vecHugeSectorCentre).MagnitudeSqr(); + + if ( fHugeSectorMaxRenderDistSqr > fHugeSectorDistToCamSqr ) + { + if ( TheCamera.IsSphereVisible(CVector(vecHugeSectorCentre.x, vecHugeSectorCentre.y, 0.0f), SectorRadius(HUGE_SECTOR_SIZE), + &CMatrix(TheCamera.GetCameraMatrix())) ) + { + if ( fHugeSectorDistToCamSqr >= SQR(500.0f) /*fHugeSectorNearDist*/ ) + { + float fZ; + + if ( !(aWaterBlockList[2*x+0][2*y+0] & 128) ) + fZ = ms_aWaterZs[ aWaterBlockList[2*x+0][2*y+0] ]; + + if ( !(aWaterBlockList[2*x+1][2*y+0] & 128) ) + fZ = ms_aWaterZs[ aWaterBlockList[2*x+1][2*y+0] ]; + + if ( !(aWaterBlockList[2*x+0][2*y+1] & 128) ) + fZ = ms_aWaterZs[ aWaterBlockList[2*x+0][2*y+1] ]; + + if ( !(aWaterBlockList[2*x+1][2*y+1] & 128) ) + fZ = ms_aWaterZs[ aWaterBlockList[2*x+1][2*y+1] ]; + + RenderOneFlatHugeWaterPoly(fX, fY, fZ, color); + } + else + { + for ( int32 x2 = 2*x; x2 <= 2*x+1; x2++ ) + { + for ( int32 y2 = 2*y; y2 <= 2*y+1; y2++ ) + { + if ( !(aWaterBlockList[x2][y2] & 128) ) + { + float fLargeX = WATER_FROM_LARGE_SECTOR_X(x2); + float fLargeY = WATER_FROM_LARGE_SECTOR_Y(y2); + + CVector2D vecLargeSectorCentre + ( + fLargeX + LARGE_SECTOR_SIZE/2, + fLargeY + LARGE_SECTOR_SIZE/2 + ); + + float fLargeSectorDistToCamSqr = (camPos - vecLargeSectorCentre).MagnitudeSqr(); + + if ( fLargeSectorDistToCamSqr < fHugeSectorMaxRenderDistSqr ) + { + if ( TheCamera.IsSphereVisible(CVector(vecLargeSectorCentre.x, vecLargeSectorCentre.y, 0.0f), SectorRadius(LARGE_SECTOR_SIZE), //90.879997f, + &CMatrix(TheCamera.GetCameraMatrix())) ) + { + // Render four small(32x32) sectors, or one large(64x64). + + // + // [N] + // --------- + // |0x1|1x1| + // [W] --------- [E] + // |0x0|1x0| + // --------- + // [S] + // + + if ( fLargeSectorDistToCamSqr < SQR(176.0f) ) + { + float fZ; + + // WS + if ( !(aWaterFineBlockList[2*x2+0][2*y2+0] & 128) ) + { + float fSmallX = fLargeX; + float fSmallY = fLargeY; + + CVector2D vecSmallSectorCentre + ( + fSmallX + SMALL_SECTOR_SIZE/2, + fSmallY + SMALL_SECTOR_SIZE/2 + ); + + float fSmallSectorDistToCamSqr = (camPos - vecSmallSectorCentre).MagnitudeSqr(); + fZ = ms_aWaterZs[ aWaterFineBlockList[2*x2+0][2*y2+0] ]; + + if ( fSmallSectorDistToCamSqr < fWavySectorMaxRenderDistSqr ) + RenderOneWavySector(fSmallX, fSmallY, fZ, color); + else + RenderOneFlatSmallWaterPoly(fSmallX, fSmallY, fZ, color); + } + + // SE + if ( !(aWaterFineBlockList[2*x2+1][2*y2+0] & 128) ) + { + float fSmallX = fLargeX + (LARGE_SECTOR_SIZE/2); + float fSmallY = fLargeY; + + CVector2D vecSmallSectorCentre + ( + fSmallX + SMALL_SECTOR_SIZE/2, + fSmallY + SMALL_SECTOR_SIZE/2 + ); + + float fSmallSectorDistToCamSqr = (camPos - vecSmallSectorCentre).MagnitudeSqr(); + fZ = ms_aWaterZs[ aWaterFineBlockList[2*x2+1][2*y2+0] ]; + + if ( fSmallSectorDistToCamSqr < fWavySectorMaxRenderDistSqr ) + RenderOneWavySector(fSmallX, fSmallY, fZ, color); + else + RenderOneFlatSmallWaterPoly(fSmallX, fSmallY, fZ, color); + } + + // WN + if ( !(aWaterFineBlockList[2*x2+0][2*y2+1] & 128) ) + { + float fSmallX = fLargeX; + float fSmallY = fLargeY + (LARGE_SECTOR_SIZE/2); + + CVector2D vecSmallSectorCentre + ( + fSmallX + SMALL_SECTOR_SIZE/2, + fSmallY + SMALL_SECTOR_SIZE/2 + ); + + float fSmallSectorDistToCamSqr = (camPos - vecSmallSectorCentre).MagnitudeSqr(); + fZ = ms_aWaterZs[ aWaterFineBlockList[2*x2+0][2*y2+1] ]; + + if ( fSmallSectorDistToCamSqr < fWavySectorMaxRenderDistSqr ) + RenderOneWavySector(fSmallX, fSmallY, fZ, color); + else + RenderOneFlatSmallWaterPoly(fSmallX, fSmallY, fZ, color); + } + + //NE + if ( !(aWaterFineBlockList[2*x2+1][2*y2+1] & 128) ) + { + float fSmallX = fLargeX + (LARGE_SECTOR_SIZE/2); + float fSmallY = fLargeY + (LARGE_SECTOR_SIZE/2); + + CVector2D vecSmallSectorCentre + ( + fSmallX + SMALL_SECTOR_SIZE/2, + fSmallY + SMALL_SECTOR_SIZE/2 + ); + + float fSmallSectorDistToCamSqr = (camPos - vecSmallSectorCentre).MagnitudeSqr(); + fZ = ms_aWaterZs[ aWaterFineBlockList[2*x2+1][2*y2+1] ]; + + if ( fSmallSectorDistToCamSqr < fWavySectorMaxRenderDistSqr ) + RenderOneWavySector(fSmallX, fSmallY, fZ, color); + else + RenderOneFlatSmallWaterPoly(fSmallX, fSmallY, fZ, color); + } + } + else + { + float fZ; + + fZ = ms_aWaterZs[ aWaterBlockList[x2][y2] ]; + + RenderOneFlatLargeWaterPoly(fLargeX, fLargeY, fZ, color); + } + } // if ( TheCamera.IsSphereVisible + } // if ( fLargeSectorDistToCamSqr < fHugeSectorMaxRenderDistSqr ) + } // if ( !(aWaterBlockList[x2][y2] & 128) ) + } // for ( int32 y2 = 2*y; y2 <= 2*y+1; y2++ ) + } // for ( int32 x2 = 2*x; x2 <= 2*x+1; x2++ ) + // + + } + } + } + } + } + } + + /* + ----------- ---------------------- ---------------------- + | [N] | | [ EndY ] | | [ top ] | + | | | | | | + |[W] [0] [E]| |[StartX] [] [ EndX ]| |[ left ] [] [ right]| + | | | | | | + | [S] | | [StartY] | | [bottom] | + ----------- ---------------------- ---------------------- + + + [S] [StartY] [bottom] + [N] [EndY] [top] + [W] [StartX] [left] + [E] [EndX] [right] + + [S] -> [N] && [W] -> [E] + bottom -> top && left -> right + */ + + if ( !bUseCamStartY ) + { + for ( int32 x = 0; x < 26; x++ ) + { + for ( int32 y = 0; y < 5; y++ ) + { + float fX = WATER_SIGN_X(float(x) * EXTRAHUGE_SECTOR_SIZE) - 1280.0f; + float fY = WATER_SIGN_Y(float(y) * EXTRAHUGE_SECTOR_SIZE) - 1280.0f; + + CVector2D vecExtraHugeSectorCentre + ( + fX + EXTRAHUGE_SECTOR_SIZE/2, + fY + EXTRAHUGE_SECTOR_SIZE/2 + ); + + float fCamDistToSector = (vecExtraHugeSectorCentre - camPos).Magnitude(); + + if ( fCamDistToSector < fHugeSectorMaxRenderDistSqr ) + { + if ( TheCamera.IsSphereVisible(CVector(vecExtraHugeSectorCentre.x, vecExtraHugeSectorCentre.y, 0.0f), SectorRadius(EXTRAHUGE_SECTOR_SIZE), + &CMatrix(TheCamera.GetCameraMatrix())) ) + { + RenderOneFlatExtraHugeWaterPoly( + vecExtraHugeSectorCentre.x - EXTRAHUGE_SECTOR_SIZE/2, + vecExtraHugeSectorCentre.y - EXTRAHUGE_SECTOR_SIZE/2, + 0.0f, + color); + } + } + } + } + } + + for ( int32 y = 5; y < 21; y++ ) + { + for ( int32 x = 0; x < 5; x++ ) + { + float fX = WATER_SIGN_X(float(x) * EXTRAHUGE_SECTOR_SIZE) - 1280.0f; + float fX2 = WATER_SIGN_X(float(x) * EXTRAHUGE_SECTOR_SIZE) - 1280.0f; + float fY = WATER_SIGN_Y(float(y) * EXTRAHUGE_SECTOR_SIZE) - 1280.0f; + + if ( !bUseCamStartX ) + { + CVector2D vecExtraHugeSectorCentre + ( + fX + EXTRAHUGE_SECTOR_SIZE/2, + fY + EXTRAHUGE_SECTOR_SIZE/2 + ); + + float fCamDistToSector = (vecExtraHugeSectorCentre - camPos).Magnitude(); + + if ( fCamDistToSector < fHugeSectorMaxRenderDistSqr ) + { + if ( TheCamera.IsSphereVisible(CVector(vecExtraHugeSectorCentre.x, vecExtraHugeSectorCentre.y, 0.0f), SectorRadius(EXTRAHUGE_SECTOR_SIZE), + &CMatrix(TheCamera.GetCameraMatrix())) ) + { + RenderOneFlatExtraHugeWaterPoly( + vecExtraHugeSectorCentre.x - EXTRAHUGE_SECTOR_SIZE/2, + vecExtraHugeSectorCentre.y - EXTRAHUGE_SECTOR_SIZE/2, + 0.0f, + color); + } + } + } + + if ( !bUseCamEndX ) + { + CVector2D vecExtraHugeSectorCentre + ( + -(fX2 + EXTRAHUGE_SECTOR_SIZE/2), + fY + EXTRAHUGE_SECTOR_SIZE/2 + ); + + float fCamDistToSector = (vecExtraHugeSectorCentre - camPos).Magnitude(); + + if ( fCamDistToSector < fHugeSectorMaxRenderDistSqr ) + { + if ( TheCamera.IsSphereVisible(CVector(vecExtraHugeSectorCentre.x, vecExtraHugeSectorCentre.y, 0.0f), SectorRadius(EXTRAHUGE_SECTOR_SIZE), + &CMatrix(TheCamera.GetCameraMatrix())) ) + { + RenderOneFlatExtraHugeWaterPoly( + vecExtraHugeSectorCentre.x - EXTRAHUGE_SECTOR_SIZE/2, + vecExtraHugeSectorCentre.y - EXTRAHUGE_SECTOR_SIZE/2, + 0.0f, + color); + } + } + } + } + } + + RenderAndEmptyRenderBuffer(); + + CVector cur_pos = TheCamera.GetPosition(); + + if ( !CCullZones::CamNoRain() + && !CCullZones::PlayerNoRain() + && CWeather::NewWeatherType == WEATHER_SUNNY + && CClock::GetHours() > 6 && CClock::GetHours() < 20 + && WavesCalculatedThisFrame) + { + static CVector prev_pos(0.0f, 0.0f, 0.0f); + static CVector prev_front(0.0f, 0.0f, 0.0f); + static int32 timecounter; + + if ( fabs(prev_pos.x - cur_pos.x) + fabs(prev_pos.y - cur_pos.y) + fabs(prev_pos.z - cur_pos.z) > 1.5f ) + { + prev_pos = cur_pos; + timecounter = CTimer::GetTimeInMilliseconds(); + } + else if ( CTimer::GetTimeInMilliseconds() - timecounter > 5000 ) + { + static int32 birdgenTime = 0; + + if ( CTimer::GetTimeInMilliseconds() - birdgenTime > 1000 ) + { + birdgenTime = CTimer::GetTimeInMilliseconds(); + + CVector vecPos = cur_pos; + + float fAngle = CGeneral::GetRandomNumberInRange(90.0f, 150.0f); + + int32 nSinCosIdx = CGeneral::GetRandomNumber() % CParticle::SIN_COS_TABLE_SIZE-1; + + float fCos = CParticle::m_CosTable[nSinCosIdx]; + float fSin = CParticle::m_SinTable[nSinCosIdx]; + + vecPos.x += (fCos - fSin) * fAngle; + vecPos.y += (fSin + fCos) * fAngle; + vecPos.z += CGeneral::GetRandomNumberInRange(10.0f, 30.0f); + + CVector vecDir(CGeneral::GetRandomNumberInRange(-1.0f, 1.0f), + CGeneral::GetRandomNumberInRange(-1.0f, 1.0f), + 0.0f); + + CParticle::AddParticle(PARTICLE_BIRD_FRONT, vecPos, vecDir); + } + } + } + + DefinedState(); +} + +void +CWaterLevel::RenderOneFlatSmallWaterPoly(float fX, float fY, float fZ, RwRGBA const &color) +{ + if ( TempBufferIndicesStored >= TEMPBUFFERINDEXSIZE-6 || TempBufferVerticesStored >= TEMPBUFFERVERTSIZE-4 ) + RenderAndEmptyRenderBuffer(); + + int32 vidx = TempBufferVerticesStored; + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 0], fX, fY, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDU); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDV); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 0], color.red, color.green, color.blue, color.alpha); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 1], fX, fY + SMALL_SECTOR_SIZE, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDU); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDV + 1.0f); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 1], color.red, color.green, color.blue, color.alpha); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 2], fX + SMALL_SECTOR_SIZE, fY + SMALL_SECTOR_SIZE, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDU + 1.0f); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDV + 1.0f); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 2], color.red, color.green, color.blue, color.alpha); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 3], fX + SMALL_SECTOR_SIZE, fY, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDU + 1.0f); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDV); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 3], color.red, color.green, color.blue, color.alpha); + + + int32 iidx = TempBufferIndicesStored; + + TempBufferRenderIndexList[iidx + 0] = TempBufferVerticesStored + 0; + TempBufferRenderIndexList[iidx + 1] = TempBufferVerticesStored + 2; + TempBufferRenderIndexList[iidx + 2] = TempBufferVerticesStored + 1; + TempBufferRenderIndexList[iidx + 3] = TempBufferVerticesStored + 0; + TempBufferRenderIndexList[iidx + 4] = TempBufferVerticesStored + 3; + TempBufferRenderIndexList[iidx + 5] = TempBufferVerticesStored + 2; + + TempBufferVerticesStored += 4; + TempBufferIndicesStored += 6; +} + +void +CWaterLevel::RenderOneFlatLargeWaterPoly(float fX, float fY, float fZ, RwRGBA const &color) +{ + if ( TempBufferIndicesStored >= TEMPBUFFERINDEXSIZE-6 || TempBufferVerticesStored >= TEMPBUFFERVERTSIZE-4 ) + RenderAndEmptyRenderBuffer(); + + int32 vidx = TempBufferVerticesStored; + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 0], fX, fY, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDU); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDV); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 0], color.red, color.green, color.blue, color.alpha); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 1], fX, fY + LARGE_SECTOR_SIZE, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDU); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDV + 2.0f); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 1], color.red, color.green, color.blue, color.alpha); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 2], fX + LARGE_SECTOR_SIZE, fY + LARGE_SECTOR_SIZE, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDU + 2.0f); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDV + 2.0f); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 2], color.red, color.green, color.blue, color.alpha); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 3], fX + LARGE_SECTOR_SIZE, fY, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDU + 2.0f); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDV); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 3], color.red, color.green, color.blue, color.alpha); + + + int32 iidx = TempBufferIndicesStored; + + TempBufferRenderIndexList[iidx + 0] = TempBufferVerticesStored + 0; + TempBufferRenderIndexList[iidx + 1] = TempBufferVerticesStored + 2; + TempBufferRenderIndexList[iidx + 2] = TempBufferVerticesStored + 1; + TempBufferRenderIndexList[iidx + 3] = TempBufferVerticesStored + 0; + TempBufferRenderIndexList[iidx + 4] = TempBufferVerticesStored + 3; + TempBufferRenderIndexList[iidx + 5] = TempBufferVerticesStored + 2; + + TempBufferVerticesStored += 4; + TempBufferIndicesStored += 6; +} + +void +CWaterLevel::RenderOneFlatHugeWaterPoly(float fX, float fY, float fZ, RwRGBA const &color) +{ + if ( TempBufferIndicesStored >= TEMPBUFFERINDEXSIZE-6 || TempBufferVerticesStored >= TEMPBUFFERVERTSIZE-4 ) + RenderAndEmptyRenderBuffer(); + + int32 vidx = TempBufferVerticesStored; + + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 0], fX, fY, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDU); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDV); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 0], color.red, color.green, color.blue, 255); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 1], fX, fY + HUGE_SECTOR_SIZE, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDU); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDV + 4.0f); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 1], color.red, color.green, color.blue, 255); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 2], fX + HUGE_SECTOR_SIZE, fY + HUGE_SECTOR_SIZE, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDU + 4.0f); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDV + 4.0f); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 2], color.red, color.green, color.blue, 255); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 3], fX + HUGE_SECTOR_SIZE, fY, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDU + 4.0f); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDV); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 3], color.red, color.green, color.blue, 255); + + + int32 iidx = TempBufferIndicesStored; + + TempBufferRenderIndexList[iidx + 0] = TempBufferVerticesStored + 0; + TempBufferRenderIndexList[iidx + 1] = TempBufferVerticesStored + 2; + TempBufferRenderIndexList[iidx + 2] = TempBufferVerticesStored + 1; + TempBufferRenderIndexList[iidx + 3] = TempBufferVerticesStored + 0; + TempBufferRenderIndexList[iidx + 4] = TempBufferVerticesStored + 3; + TempBufferRenderIndexList[iidx + 5] = TempBufferVerticesStored + 2; + + TempBufferVerticesStored += 4; + TempBufferIndicesStored += 6; +} + +void +CWaterLevel::RenderOneFlatExtraHugeWaterPoly(float fX, float fY, float fZ, RwRGBA const &color) +{ + if ( TempBufferIndicesStored >= TEMPBUFFERINDEXSIZE-6 || TempBufferVerticesStored >= TEMPBUFFERVERTSIZE-4 ) + RenderAndEmptyRenderBuffer(); + + int32 vidx = TempBufferVerticesStored; + + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 0], fX, fY, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDU); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDV); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 0], color.red, color.green, color.blue, 255); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 1], fX, fY + EXTRAHUGE_SECTOR_SIZE, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDU); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDV + 8.0f); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 1], color.red, color.green, color.blue, 255); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 2], fX + EXTRAHUGE_SECTOR_SIZE, fY + EXTRAHUGE_SECTOR_SIZE, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDU + 8.0f); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDV + 8.0f); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 2], color.red, color.green, color.blue, 255); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 3], fX + EXTRAHUGE_SECTOR_SIZE, fY, fZ - WATER_Z_OFFSET); + RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDU + 8.0f); + RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDV); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 3], color.red, color.green, color.blue, 255); + + + int32 iidx = TempBufferIndicesStored; + + TempBufferRenderIndexList[iidx + 0] = TempBufferVerticesStored + 0; + TempBufferRenderIndexList[iidx + 1] = TempBufferVerticesStored + 2; + TempBufferRenderIndexList[iidx + 2] = TempBufferVerticesStored + 1; + TempBufferRenderIndexList[iidx + 3] = TempBufferVerticesStored + 0; + TempBufferRenderIndexList[iidx + 4] = TempBufferVerticesStored + 3; + TempBufferRenderIndexList[iidx + 5] = TempBufferVerticesStored + 2; + + TempBufferVerticesStored += 4; + TempBufferIndicesStored += 6; +} + +void +CWaterLevel::RenderOneWavySector(float fX, float fY, float fZ, RwRGBA const &color, bool bUnk) +{ + float fAngle = (CTimer::GetTimeInMilliseconds() & 4095) * (TWOPI / 4096.0f); + + if ( !WavesCalculatedThisFrame ) + { + nGeomUsed = 0; + + WavesCalculatedThisFrame = true; + + CBoat::FillBoatList(); + + ASSERT( ms_pWavyAtomic != NULL ); + + RpGeometry *geometry = RpAtomicGetGeometry(ms_pWavyAtomic); + + ASSERT( geometry != NULL ); + + RwRGBA *wavyPreLights = RpGeometryGetPreLightColors(geometry); + RwTexCoords *wavyTexCoords = RpGeometryGetVertexTexCoords(geometry, rwTEXTURECOORDINATEINDEX0); + RwV3d *wavyVertices = RpMorphTargetGetVertices(RpGeometryGetMorphTarget(geometry, 0)); + + ASSERT( wavyPreLights != NULL ); + ASSERT( wavyTexCoords != NULL ); + ASSERT( wavyVertices != NULL ); + + RpGeometryLock(geometry, rpGEOMETRYLOCKVERTICES + | rpGEOMETRYLOCKPRELIGHT + | rpGEOMETRYLOCKTEXCOORDS); + + for ( int32 i = 0; i < 9; i++ ) + { + for ( int32 j = 0; j < 9; j++ ) + { + wavyTexCoords[9*i+j].u = float(i) / 8 + TEXTURE_ADDV; + wavyTexCoords[9*i+j].v = float(j) / 8 + TEXTURE_ADDU; + RwRGBAAssign(&wavyPreLights[9*i+j], &color); + + wavyVertices[9*i+j].z = ( CWeather::Wind * 0.7f + 0.3f ) + * ( sinf(float(i + j) * DEGTORAD(45.0f) + fAngle) ) + + ( CWeather::Wind * 0.2f * sinf(float(j - i) * PI + (2.0f * fAngle)) ); + } + } + + RpGeometryUnlock(geometry); + } + + static CBoat *apBoatList[4] = { NULL }; + + if ( apGeomArray[0] + && nGeomUsed < MAX_BOAT_WAKES + && CBoat::IsSectorAffectedByWake( + CVector2D(fX + (SMALL_SECTOR_SIZE / 2), fY + (SMALL_SECTOR_SIZE / 2)), + SMALL_SECTOR_SIZE / 2, + apBoatList) ) + { + float fWakeColor = fAdd1 - max(255.0f - float(color.blue + color.red + color.green) / 3, fAdd2); + + RpGeometry *wavyGeometry = RpAtomicGetGeometry(ms_pWavyAtomic); + RpGeometry *geom = apGeomArray[nGeomUsed++]; + + ASSERT( wavyGeometry != NULL ); + ASSERT( geom != NULL ); + + RpAtomic *atomic = RpAtomicCreate(); + ASSERT( atomic != NULL ); + + RpAtomicSetGeometry(atomic, geom, 0); + + RwFrame *frame = RwFrameCreate(); + ASSERT( frame != NULL ); + + RwMatrixCopy(RwFrameGetMatrix(frame), RwFrameGetMatrix(RpAtomicGetFrame(ms_pWavyAtomic))); + RpAtomicSetFrame(atomic, frame); + + RwTexCoords *geomTexCoords = RpGeometryGetVertexTexCoords(geom, rwTEXTURECOORDINATEINDEX0); + RwTexCoords *wavyTexCoord = RpGeometryGetVertexTexCoords(wavyGeometry, rwTEXTURECOORDINATEINDEX0); + RwRGBA *geomPreLights = RpGeometryGetPreLightColors(geom); + RwV3d *geomVertices = RpMorphTargetGetVertices(RpGeometryGetMorphTarget(geom, 0)); + RwV3d *wavyVertices = RpMorphTargetGetVertices(RpGeometryGetMorphTarget(wavyGeometry, 0)); + + ASSERT( geomTexCoords != NULL ); + ASSERT( wavyTexCoord != NULL ); + ASSERT( geomPreLights != NULL ); + ASSERT( geomVertices != NULL ); + ASSERT( wavyVertices != NULL ); + + RpGeometryLock(geom, rpGEOMETRYLOCKVERTICES | rpGEOMETRYLOCKPRELIGHT | rpGEOMETRYLOCKTEXCOORDS); + + for ( int32 i = 0; i < 9; i++ ) + { + for ( int32 j = 0; j < 9; j++ ) + { + geomTexCoords[9*i+j] = wavyTexCoord[9*i+j]; + + float fVertexX = (float)i * 4.0f + fX; + float fVertexY = (float)j * 4.0f + fY; + + float fDistMult = 0.0f; + + for ( int32 k = 0; k < 4; k++ ) + { + if ( apBoatList[k] != NULL ) + fDistMult += CBoat::IsVertexAffectedByWake(CVector(fVertexX, fVertexY, 0.0f), apBoatList[k]); + } + + if ( fDistMult > 0.0f ) + { + RwRGBA wakeColor; + + RwRGBAAssign(&wakeColor, &color); + + wakeColor.red = min(color.red + int32(fWakeColor * fRedMult * fDistMult), 255); + wakeColor.green = min(color.green + int32(fWakeColor * fGreenMult * fDistMult), 255); + wakeColor.blue = min(color.blue + int32(fWakeColor * fBlueMult * fDistMult), 255); + + RwRGBAAssign(&geomPreLights[9*i+j], &wakeColor); + + } + else + RwRGBAAssign(&geomPreLights[9*i+j], &color); + + + geomVertices[9*i+j].z = wavyVertices[9*i+j].z; + } + } + + RpGeometryUnlock(geom); + + + RwV3d pos = {0.0f, 0.0f, 0.0f}; + + pos.x = fX; + pos.z = fZ; + pos.y = fY; + + RwFrameTranslate(RpAtomicGetFrame(atomic), &pos, rwCOMBINEREPLACE); + + RpAtomicRender(atomic); + + RpAtomicDestroy(atomic); + RwFrameDestroy(frame); + } + else + { + RwV3d pos = { 0.0f, 0.0f, 0.0f }; + + pos.x = fX; + pos.y = fY; + pos.z = fZ; + + ASSERT( ms_pWavyAtomic != NULL ); + + RwFrameTranslate(RpAtomicGetFrame(ms_pWavyAtomic), &pos, rwCOMBINEREPLACE); + + RpAtomicRender(ms_pWavyAtomic); + } +} + +float +CWaterLevel::CalcDistanceToWater(float fX, float fY) +{ + const float fSectorMaxRenderDist = 75.0f; + + int32 nStartX = WATER_TO_SMALL_SECTOR_X(fX - fSectorMaxRenderDist) - 1; + int32 nEndX = WATER_TO_SMALL_SECTOR_X(fX + fSectorMaxRenderDist) + 1; + int32 nStartY = WATER_TO_SMALL_SECTOR_Y(fY - fSectorMaxRenderDist) - 1; + int32 nEndY = WATER_TO_SMALL_SECTOR_Y(fY + fSectorMaxRenderDist) + 1; + + nStartX = clamp(nStartX, 0, MAX_SMALL_SECTORS - 1); + nEndX = clamp(nEndX, 0, MAX_SMALL_SECTORS - 1); + nStartY = clamp(nStartY, 0, MAX_SMALL_SECTORS - 1); + nEndY = clamp(nEndY, 0, MAX_SMALL_SECTORS - 1); + + float fDistSqr = 1.0e10f; + + for ( int32 x = nStartX; x <= nEndX; x++ ) + { + for ( int32 y = nStartY; y <= nEndY; y++ ) + { + if ( !(aWaterFineBlockList[x][y] & 128) ) + { + float fSectorX = WATER_FROM_SMALL_SECTOR_X(x); + float fSectorY = WATER_FROM_SMALL_SECTOR_Y(y); + + CVector2D vecDist + ( + fSectorX + SMALL_SECTOR_SIZE - fX, + fSectorY + SMALL_SECTOR_SIZE - fY + ); + + fDistSqr = min(vecDist.MagnitudeSqr(), fDistSqr); + } + } + } + + return clamp(sqrt(fDistSqr) - 23.0f, 0.0f, fSectorMaxRenderDist); +} + +void +CWaterLevel::RenderAndEmptyRenderBuffer() +{ + if ( TempBufferVerticesStored ) + { + LittleTest(); + + if ( RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, NULL, rwIM3D_VERTEXUV) ) + { + RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored); + RwIm3DEnd(); + } + } + + TempBufferIndicesStored = 0; + TempBufferVerticesStored = 0; +} + +void +CWaterLevel::AllocateBoatWakeArray() +{ + CStreaming::MakeSpaceFor(14 * CDSTREAM_SECTOR_SIZE); + + ASSERT(ms_pWavyAtomic != NULL ); + + RpGeometry *wavyGeometry = RpAtomicGetGeometry(ms_pWavyAtomic); + RpMorphTarget *wavyMorphTarget = RpGeometryGetMorphTarget(wavyGeometry, 0); + RpMaterial *wavyMaterial = RpGeometryGetMaterial(wavyGeometry, 0); + + ASSERT(wavyGeometry != NULL ); + ASSERT(wavyMorphTarget != NULL ); + ASSERT(wavyMaterial != NULL ); + + for ( int32 geom = 0; geom < MAX_BOAT_WAKES; geom++ ) + { + if ( apGeomArray[geom] == NULL ) + { + apGeomArray[geom] = RpGeometryCreate(9*9, 8*8*2, rpGEOMETRYTRISTRIP + | rpGEOMETRYPRELIT + | rpGEOMETRYMODULATEMATERIALCOLOR + | rpGEOMETRYTEXTURED); + ASSERT(apGeomArray[geom] != NULL); + + RpTriangle *geomTriangles = RpGeometryGetTriangles(apGeomArray[geom]); + + ASSERT( geomTriangles != NULL ); + + for ( int32 i = 0; i < 8; i++ ) + { + for ( int32 j = 0; j < 8; j++ ) + { + + /* + [B] [C] + *********** + * * * + * * * + * * * + * * * + *********** + [A] [D] + */ + + + RpGeometryTriangleSetVertexIndices(apGeomArray[geom], + &geomTriangles[2 * 8*i + 2*j + 0], /*A*/i*9+j+0, /*B*/i*9+j+1, /*C*/i*9+j+9+1); + + RpGeometryTriangleSetVertexIndices(apGeomArray[geom], + &geomTriangles[2 * 8*i + 2*j + 1], /*A*/i*9+j+0, /*C*/i*9+j+9+1, /*D*/i*9+j+9 ); + + RpGeometryTriangleSetMaterial(apGeomArray[geom], &geomTriangles[2 * 8*i + 2*j + 0], wavyMaterial); + + RpGeometryTriangleSetMaterial(apGeomArray[geom], &geomTriangles[2 * 8*i + 2*j + 1], wavyMaterial); + } + } + + RpMorphTarget *geomMorphTarget = RpGeometryGetMorphTarget(apGeomArray[geom], 0); + RwV3d *geomVertices = RpMorphTargetGetVertices(geomMorphTarget); + + ASSERT( geomMorphTarget != NULL ); + ASSERT( geomVertices != NULL ); + + for ( int32 i = 0; i < 9; i++ ) + { + for ( int32 j = 0; j < 9; j++ ) + { + geomVertices[9*i+j].x = (float)i * 4.0f; + geomVertices[9*i+j].y = (float)j * 4.0f; + geomVertices[9*i+j].z = 0.0f; + } + } + + RpMorphTargetSetBoundingSphere(geomMorphTarget, RpMorphTargetGetBoundingSphere(wavyMorphTarget)); + RpGeometryUnlock(apGeomArray[geom]); + } + } +} + +void +CWaterLevel::FreeBoatWakeArray() +{ + for ( int32 i = 0; i < MAX_BOAT_WAKES; i++ ) + { + if ( apGeomArray[i] != NULL ) + { + RpGeometryDestroy(apGeomArray[i]); + apGeomArray[i] = NULL; + } + } + + nGeomUsed = 0; +} + +STARTPATCHES + InjectHook(0x554EA0, &CWaterLevel::Initialise, PATCH_JUMP); + InjectHook(0x554FE0, &CWaterLevel::Shutdown, PATCH_JUMP); + InjectHook(0x555010, &CWaterLevel::CreateWavyAtomic, PATCH_JUMP); + InjectHook(0x5552A0, &CWaterLevel::DestroyWavyAtomic, PATCH_JUMP); + InjectHook(0x5552C0, &CWaterLevel::GetWaterLevel, PATCH_JUMP); + InjectHook(0x555440, &CWaterLevel::GetWaterLevelNoWaves, PATCH_JUMP); + InjectHook(0x5554E0, &CWaterLevel::RenderWater, PATCH_JUMP); + InjectHook(0x556C30, &CWaterLevel::RenderOneFlatSmallWaterPoly, PATCH_JUMP); + InjectHook(0x556E80, &CWaterLevel::RenderOneFlatLargeWaterPoly, PATCH_JUMP); + InjectHook(0x5570D0, &CWaterLevel::RenderOneFlatHugeWaterPoly, PATCH_JUMP); + InjectHook(0x557320, &CWaterLevel::RenderOneFlatExtraHugeWaterPoly, PATCH_JUMP); + InjectHook(0x557570, &CWaterLevel::RenderOneWavySector, PATCH_JUMP); + InjectHook(0x557C30, &CWaterLevel::CalcDistanceToWater, PATCH_JUMP); + InjectHook(0x557EA0, &CWaterLevel::RenderAndEmptyRenderBuffer, PATCH_JUMP); + InjectHook(0x557F00, &CWaterLevel::AllocateBoatWakeArray, PATCH_JUMP); + InjectHook(0x5581C0, &CWaterLevel::FreeBoatWakeArray, PATCH_JUMP); +ENDPATCHES diff --git a/src/render/WaterLevel.h b/src/render/WaterLevel.h index 70a2ba97..ecd66c89 100644 --- a/src/render/WaterLevel.h +++ b/src/render/WaterLevel.h @@ -1,7 +1,97 @@ #pragma once + +#define WATER_BLOCK_SIZE LARGE_SECTOR_SIZE +#define WATER_FINEBLOCK_SIZE HUGE_SECTOR_SIZE +#define WATER_Z_OFFSET (1.5f) + +#define MAX_SMALL_SECTORS 128 +#define MAX_LARGE_SECTORS 64 +#define MAX_HUGE_SECTORS 32 +#define MAX_EXTRAHUGE_SECTORS 16 + +#define SMALL_SECTOR_SIZE 32 +#define LARGE_SECTOR_SIZE 64 +#define HUGE_SECTOR_SIZE 128 +#define EXTRAHUGE_SECTOR_SIZE 256 + +#define WATER_START_X -2048.0f +#define WATER_END_X 2048.0f + +#define WATER_START_Y -2048.0f +#define WATER_END_Y 2048.0f + +#define WATER_WIDTH ((WATER_END_X - WATER_START_X)) +#define WATER_HEIGHT ((WATER_END_Y - WATER_START_Y)) + + +#define WATER_UNSIGN_X(x) ( (x) + (WATER_WIDTH /2) ) +#define WATER_UNSIGN_Y(y) ( (y) + (WATER_HEIGHT/2) ) +#define WATER_SIGN_X(x) ( (x) - (WATER_WIDTH /2) ) +#define WATER_SIGN_Y(y) ( (y) - (WATER_HEIGHT/2) ) + +// 32 +#define WATER_SMALL_X(x) ( WATER_UNSIGN_X(x) / MAX_SMALL_SECTORS ) +#define WATER_SMALL_Y(y) ( WATER_UNSIGN_Y(y) / MAX_SMALL_SECTORS ) +#define WATER_FROM_SMALL_SECTOR_X(x) ( ((x) - (MAX_SMALL_SECTORS/2) ) * SMALL_SECTOR_SIZE ) +#define WATER_FROM_SMALL_SECTOR_Y(y) ( ((y) - (MAX_SMALL_SECTORS/2) ) * SMALL_SECTOR_SIZE ) +#define WATER_TO_SMALL_SECTOR_X(x) ( WATER_UNSIGN_X(x) / SMALL_SECTOR_SIZE ) +#define WATER_TO_SMALL_SECTOR_Y(y) ( WATER_UNSIGN_Y(y) / SMALL_SECTOR_SIZE ) + +// 64 +#define WATER_LARGE_X(x) ( WATER_UNSIGN_X(x) / MAX_LARGE_SECTORS ) +#define WATER_LARGE_Y(y) ( WATER_UNSIGN_Y(y) / MAX_LARGE_SECTORS ) +#define WATER_FROM_LARGE_SECTOR_X(x) ( ((x) - (MAX_LARGE_SECTORS/2) ) * LARGE_SECTOR_SIZE ) +#define WATER_FROM_LARGE_SECTOR_Y(y) ( ((y) - (MAX_LARGE_SECTORS/2) ) * LARGE_SECTOR_SIZE ) +#define WATER_TO_LARGE_SECTOR_X(x) ( WATER_UNSIGN_X(x) / LARGE_SECTOR_SIZE ) +#define WATER_TO_LARGE_SECTOR_Y(y) ( WATER_UNSIGN_Y(y) / LARGE_SECTOR_SIZE ) + +// 128 +#define WATER_HUGE_X(x) ( WATER_UNSIGN_X(x) / MAX_HUGE_SECTORS ) +#define WATER_HUGE_Y(y) ( WATER_UNSIGN_Y(y) / MAX_HUGE_SECTORS ) +#define WATER_FROM_HUGE_SECTOR_X(x) ( ((x) - (MAX_HUGE_SECTORS/2) ) * HUGE_SECTOR_SIZE ) +#define WATER_FROM_HUGE_SECTOR_Y(y) ( ((y) - (MAX_HUGE_SECTORS/2) ) * HUGE_SECTOR_SIZE ) +#define WATER_TO_HUGE_SECTOR_X(x) ( WATER_UNSIGN_X(x) / HUGE_SECTOR_SIZE ) +#define WATER_TO_HUGE_SECTOR_Y(y) ( WATER_UNSIGN_Y(y) / HUGE_SECTOR_SIZE ) + +// 256 +#define WATER_EXTRAHUGE_X(x) ( WATER_UNSIGN_X(x) / MAX_EXTRAHUGE_SECTORS ) +#define WATER_EXTRAHUGE_Y(y) ( WATER_UNSIGN_Y(y) / MAX_EXTRAHUGE_SECTORS ) +#define WATER_FROM_EXTRAHUGE_SECTOR_X(x) ( ((x) - (MAX_EXTRAHUGE_SECTORS/2)) * EXTRAHUGE_SECTOR_SIZE ) +#define WATER_FROM_EXTRAHUGE_SECTOR_Y(y) ( ((y) - (MAX_EXTRAHUGE_SECTORS/2)) * EXTRAHUGE_SECTOR_SIZE ) +#define WATER_TO_EXTRAHUGE_SECTOR_X(x) ( WATER_UNSIGN_X(x) / EXTRAHUGE_SECTOR_SIZE ) +#define WATER_TO_EXTRAHUGE_SECTOR_Y(y) ( WATER_UNSIGN_Y(y) / EXTRAHUGE_SECTOR_SIZE ) + + +#define MAX_BOAT_WAKES 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 bool WavesCalculatedThisFrame; + static RpAtomic *ms_pWavyAtomic; + static RpGeometry *apGeomArray[MAX_BOAT_WAKES]; + static int16 nGeomUsed; + public: - static void RenderWater(void); + static void Initialise(char *pWaterDat); + static void Shutdown(); + static void CreateWavyAtomic(); + static void DestroyWavyAtomic(); + static bool GetWaterLevel(float fX, float fY, float fZ, float *pfOutLevel, bool bDontCheckZ); + static bool GetWaterLevelNoWaves(float fX, float fY, float fZ, float *pfOutLevel); + static void RenderWater(); + static void RenderOneFlatSmallWaterPoly (float fX, float fY, float fZ, RwRGBA const &color); + static void RenderOneFlatLargeWaterPoly (float fX, float fY, float fZ, RwRGBA const &color); + static void RenderOneFlatHugeWaterPoly (float fX, float fY, float fZ, RwRGBA const &color); + static void RenderOneFlatExtraHugeWaterPoly(float fX, float fY, float fZ, RwRGBA const &color); + static void RenderOneWavySector (float fX, float fY, float fZ, RwRGBA const &color, bool bUnk = false); + static float CalcDistanceToWater(float fX, float fY); + static void RenderAndEmptyRenderBuffer(); + static void AllocateBoatWakeArray(); + static void FreeBoatWakeArray(); }; diff --git a/src/vehicles/Boat.cpp b/src/vehicles/Boat.cpp index 076a910e..9b462971 100644 --- a/src/vehicles/Boat.cpp +++ b/src/vehicles/Boat.cpp @@ -2,6 +2,17 @@ #include "patcher.h" #include "Boat.h" +float &fShapeLength = *(float*)0x600E78; +float &fShapeTime = *(float*)0x600E7C; +float &fRangeMult = *(float*)0x600E80; //0.6f; // 0.75f gta 3 +float &fTimeMult = *(float*)0xA0FCF4; + +float MAX_WAKE_LENGTH = 50.0f; +float MIN_WAKE_INTERVAL = 1.0f; +float WAKE_LIFETIME = 400.0f; + +CBoat * (&CBoat::apFrameWakeGeneratingBoats)[4] = *(CBoat * (*)[4])*(uintptr*)0x8620E0; + CBoat::CBoat(int mi, uint8 owner) { ctor(mi, owner); @@ -9,6 +20,58 @@ CBoat::CBoat(int mi, uint8 owner) WRAPPER CBoat* CBoat::ctor(int, uint8) { EAXJMP(0x53E3E0); } + +bool CBoat::IsSectorAffectedByWake(CVector2D sector, float fSize, CBoat **apBoats) +{ + uint8 numVerts = 0; + + if ( apFrameWakeGeneratingBoats[0] == NULL ) + return false; + + for ( int32 i = 0; i < 4; i++ ) + { + CBoat *pBoat = apFrameWakeGeneratingBoats[i]; + if ( !pBoat ) + break; + + for ( int j = 0; j < pBoat->m_nNumWakePoints; j++ ) + { + float fDist = (WAKE_LIFETIME - pBoat->m_afWakePointLifeTime[j]) * fShapeTime + float(j) * fShapeLength + fSize; + + if ( fabs(pBoat->m_avec2dWakePoints[j].x - sector.x) < fDist + && fabs(pBoat->m_avec2dWakePoints[i].y - sector.y) < fDist ) + { + apBoats[numVerts] = pBoat; + numVerts = 1; // += ? + break; + } + } + } + + return numVerts != 0; +} + +float CBoat::IsVertexAffectedByWake(CVector vecVertex, CBoat *pBoat) +{ + for ( int i = 0; i < pBoat->m_nNumWakePoints; i++ ) + { + float fMaxDist = (WAKE_LIFETIME - pBoat->m_afWakePointLifeTime[i]) * fShapeTime + float(i) * fShapeLength; + + float fX = pBoat->m_avec2dWakePoints[i].x - vecVertex.x; + float fY = pBoat->m_avec2dWakePoints[i].y - vecVertex.y; + + float fDist = fY * fY + fX * fX; + + if ( fDist < SQR(fMaxDist) ) + return 1.0f - min(fRangeMult * sqrt(fDist / SQR(fMaxDist)) + (WAKE_LIFETIME - pBoat->m_afWakePointLifeTime[i]) * fTimeMult, 1.0f); + } + + return 0.0f; +} + +WRAPPER void CBoat::FillBoatList(void) { EAXJMP(0x542250); } + + STARTPATCHES InjectHook(0x53E790, &CBoat::dtor, PATCH_JUMP); ENDPATCHES \ No newline at end of file diff --git a/src/vehicles/Boat.h b/src/vehicles/Boat.h index 6d6482a4..41fed2ff 100644 --- a/src/vehicles/Boat.h +++ b/src/vehicles/Boat.h @@ -6,12 +6,52 @@ class CBoat : public CVehicle { public: // 0x288 - uint8 stuff1[57]; + float field_288; + float field_28C; + float field_290; + float field_294; + float field_298; + float field_29C; + float field_2A0; + float field_2A4; + float m_fMovingHiRotation; + int32 _unk0; + RwFrame *m_aBoatNodes[4]; + uint8 m_nBoatFlags; bool m_bIsAnchored; - uint8 stuff[450]; + char _pad0[2]; + float field_2C4; + int32 _unk1; + float field_2CC; + CEntity *field_2D0; + bool _unk2; + char _pad1[3]; + float m_fAccelerate; + float m_fBrake; + float m_fSteeringLeftRight; + uint8 m_nPadID; + char _pad2[3]; + int32 _unk3; + float m_fTurnForceZ; + CVector m_vecMoveForce; + float field_2FC; + uint16 field_300; + uint16 m_nNumWakePoints; + CVector2D m_avec2dWakePoints[32]; + float m_afWakePointLifeTime[32]; CBoat(int, uint8); CBoat* ctor(int, uint8); void dtor() { this->CBoat::~CBoat(); }; + + static CBoat *(&apFrameWakeGeneratingBoats)[4]; + + static bool IsSectorAffectedByWake(CVector2D sector, float fSize, CBoat **apBoats); + static float IsVertexAffectedByWake(CVector vecVertex, CBoat *pBoat); + static void FillBoatList(void); }; static_assert(sizeof(CBoat) == 0x484, "CBoat: error"); + +extern float MAX_WAKE_LENGTH; +extern float MIN_WAKE_INTERVAL; +extern float WAKE_LIFETIME; \ No newline at end of file