#include "common.h" #include "main.h" #include "FileMgr.h" #include "FileLoader.h" #include "TxdStore.h" #include "Timer.h" #include "Weather.h" #include "Camera.h" #include "Vehicle.h" #include "PlayerPed.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 "ColStore.h" #include "CdStream.h" #include "Pad.h" #include "RenderBuffer.h" #include #include #include #include "Occlusion.h" #include "Replay.h" #include "WaterLevel.h" #include "SurfaceTable.h" #include "WaterCreatures.h" #define RwIm3DVertexSet_RGBA(vert, rgba) RwIm3DVertexSetRGBA(vert, rgba.red, rgba.green, rgba.blue, rgba.alpha) // (RwRGBAAssign(&(_dst)->color, &_src)) float TEXTURE_ADDU; float TEXTURE_ADDV; float _TEXTURE_MASK_ADDU; float _TEXTURE_MASK_ADDV; float _TEXTURE_WAKE_ADDU; float _TEXTURE_WAKE_ADDV; int32 CWaterLevel::ms_nNoOfWaterLevels; float CWaterLevel::ms_aWaterZs[48]; CRect CWaterLevel::ms_aWaterRects[48]; int8 CWaterLevel::aWaterBlockList[MAX_LARGE_SECTORS][MAX_LARGE_SECTORS]; int8 CWaterLevel::aWaterFineBlockList[MAX_SMALL_SECTORS][MAX_SMALL_SECTORS]; bool CWaterLevel::WavesCalculatedThisFrame; bool CWaterLevel::RequireWavySector; bool CWaterLevel::MaskCalculatedThisFrame; CVector CWaterLevel::PreCalculatedMaskPosn; bool CWaterLevel::m_bRenderSeaBed; int32 CWaterLevel::m_nRenderWaterLayers; RpAtomic *CWaterLevel::ms_pWavyAtomic; RpAtomic *CWaterLevel::ms_pMaskAtomic; //"Custom" Don't Render Water Toggle bool gbDontRenderWater; RwTexture *gpWaterTex; RwTexture *gpWaterEnvTex; RwTexture *gpWaterEnvBaseTex; RwTexture *gpWaterWakeTex; RwRaster *gpWaterRaster; RwRaster *gpWaterEnvRaster; RwRaster *gpWaterEnvBaseRaster; RwRaster *gpWaterWakeRaster; bool _bSeaLife; float _fWaterZOffset = WATER_Z_OFFSET; #ifdef PC_WATER float fEnvScale = 0.25f; #else float fEnvScale = 0.5f; #endif float fWave2InvLength = 0.03f; float fWave2NormScale = 0.5f; float fWave2Ampl = 0.1f; uint8 nWaterAlpha = 192; uint8 nWakeAlpha = 192; float fUnder1 = 4.0; float fUnder2 = 2.5; float fUnder3 = 1.5; int nMaskAlpha = 230; float fAdd1 = 180.0f; float fAdd2 = 80.0; float fRedMult = 0.6f; float fGreenMult = 1.0f; float fBlueMult = 1.4f; float fAlphaMult = 500.0f; float fAlphaBase = 30.0f; float fRandomMoveDiv = 8.0f; float fRandomDamp = 0.99f; float fNormMult = 2.0f; float fNormMultB = 1.0f; float fBumpScale = 1.5; float fBumpTexRepeat = 2.0; float fNormalDirectionScalar1 = 2.0f; float fNormalDirectionScalar2 = 1.0f; bool bTestDoNormals = true; float fSeaBedZ = 25.0f; float aAlphaFade[5] = { 0.4f, 1.0f, 0.2f, 1.0f, 0.4f}; //CWaterLevel::RenderWakeSegment float fFlatWaterBlendRange = 0.05f; float fStartBlendDistanceAdd = 64.0f; float fMinWaterAlphaMult = -30.0f; void CWaterLevel::Initialise(Const char *pWaterDat) { ms_nNoOfWaterLevels = 0; #ifdef MASTER int32 hFile = -1; do { hFile = CFileMgr::OpenFile("DATA\\waterpro.dat", "rb"); } while ( hFile < 0 ); #else int32 hFile = CFileMgr::OpenFile("DATA\\waterpro.dat", "rb"); #endif 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); } #ifndef MASTER else { printf("Init waterlevels\n"); // collision is streamed in VC CColStore::LoadAllCollision(); CFileMgr::SetDir(""); hFile = CFileMgr::OpenFile(pWaterDat, "r"); char *line; while ((line = CFileLoader::LoadLine(hFile))) { if (*line && *line != ';' && !strstr(line, "* ;end of file")) { 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 < MAX_SMALL_SECTORS; x++) { for (int32 y = 0; y < MAX_SMALL_SECTORS; y++) { aWaterFineBlockList[x][y] = NO_WATER; } } // rasterize water rects read from file for (int32 i = 0; i < ms_nNoOfWaterLevels; i++) { int32 l = WATER_HUGE_X(ms_aWaterRects[i].left + WATER_X_OFFSET); int32 r = WATER_HUGE_X(ms_aWaterRects[i].right + WATER_X_OFFSET) + 1.0f; int32 t = WATER_HUGE_Y(ms_aWaterRects[i].top); int32 b = WATER_HUGE_Y(ms_aWaterRects[i].bottom) + 1.0f; l = clamp(l, 0, MAX_SMALL_SECTORS - 1); r = clamp(r, 0, MAX_SMALL_SECTORS - 1); t = clamp(t, 0, MAX_SMALL_SECTORS - 1); b = clamp(b, 0, MAX_SMALL_SECTORS - 1); for (int32 x = l; x <= r; x++) { for (int32 y = t; y <= b; y++) { aWaterFineBlockList[x][y] = i; } } } // remove tiles that are obscured by land for (int32 x = 0; x < MAX_SMALL_SECTORS; x++) { float worldX = WATER_START_X + x * SMALL_SECTOR_SIZE - WATER_X_OFFSET; for (int32 y = 0; y < MAX_SMALL_SECTORS; y++) { if (CWaterLevel::aWaterFineBlockList[x][y] >= 0) { float worldY = WATER_START_Y + y * SMALL_SECTOR_SIZE; int32 i; for (i = 0; i <= 8; i++) { for (int32 j = 0; j <= 8; j++) { CVector worldPos = CVector(worldX + i * (SMALL_SECTOR_SIZE / 8), worldY + j * (SMALL_SECTOR_SIZE / 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) && (!WaterLevelAccordingToRectangles(worldPos.x, worldPos.y) || TestVisibilityForFineWaterBlocks(worldPos))) continue; // at least one point in the tile wasn't blocked, so don't remove water i = 1000; break; } } if (i < 1000) aWaterFineBlockList[x][y] = NO_WATER; } } } RemoveIsolatedWater(); // calculate coarse tiles from fine tiles for (int32 x = 0; x < MAX_LARGE_SECTORS; x++) { for (int32 y = 0; y < MAX_LARGE_SECTORS; 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); } // collision is streamed in VC CColStore::RemoveAllCollision(); } #endif CTxdStore::PushCurrentTxd(); int32 slot = CTxdStore::FindTxdSlot("particle"); CTxdStore::SetCurrentTxd(slot); if ( gpWaterTex == nil ) gpWaterTex = RwTextureRead("waterclear256", nil); gpWaterRaster = RwTextureGetRaster(gpWaterTex); if ( gpWaterEnvTex == nil ) gpWaterEnvTex = RwTextureRead("waterreflection2", nil); gpWaterEnvRaster = RwTextureGetRaster(gpWaterEnvTex); #ifdef PC_WATER if ( gpWaterEnvBaseTex == nil ) gpWaterEnvBaseTex = RwTextureRead("sandywater", nil); gpWaterEnvBaseRaster = RwTextureGetRaster(gpWaterEnvBaseTex); #endif if ( gpWaterWakeTex == nil ) gpWaterWakeTex = RwTextureRead("waterwake", nil); gpWaterWakeRaster = RwTextureGetRaster(gpWaterWakeTex); CTxdStore::PopCurrentTxd(); CreateWavyAtomic(); printf("Done Initing waterlevels\n"); } void CWaterLevel::Shutdown() { DestroyWavyAtomic(); #define _DELETE_TEXTURE(t) if ( t ) \ { \ RwTextureDestroy(t); \ t = nil; \ } _DELETE_TEXTURE(gpWaterTex); _DELETE_TEXTURE(gpWaterEnvTex); _DELETE_TEXTURE(gpWaterWakeTex); _DELETE_TEXTURE(gpWaterEnvBaseTex); #undef _DELETE_TEXTURE } void CWaterLevel::CreateWavyAtomic() { RpGeometry *wavyGeometry; RpGeometry *maskGeometry; RpMaterial *wavyMaterial; RpMaterial *maskMaterial; RpTriangle *wavytlist; RpTriangle *masktlist; RpMorphTarget *wavyMorphTarget; RpMorphTarget *maskMorphTarget; RwSphere boundingSphere; RwV3d *wavyVert; RwV3d *wavyNormal; RwV3d *maskVert; RwV3d *maskNormal; RwFrame *wavyFrame; RwFrame *maskFrame; { wavyGeometry = RpGeometryCreate(17*17, 512, rpGEOMETRYTRISTRIP |rpGEOMETRYTEXTURED |rpGEOMETRYPRELIT |rpGEOMETRYNORMALS |rpGEOMETRYMODULATEMATERIALCOLOR); #ifdef PC_WATER RpGeometryAddMorphTarget(wavyGeometry); #endif } { maskGeometry = RpGeometryCreate(33*33, 2048, rpGEOMETRYTRISTRIP |rpGEOMETRYTEXTURED |rpGEOMETRYPRELIT |rpGEOMETRYNORMALS |rpGEOMETRYMODULATEMATERIALCOLOR); #ifdef PC_WATER RpGeometryAddMorphTarget(maskGeometry); #endif } { wavyMaterial = RpMaterialCreate(); RpMaterialSetTexture(wavyMaterial, gpWaterTex); RwRGBA watercolor = { 255, 255, 255, 192 }; RpMaterialSetColor(wavyMaterial, &watercolor); } { maskMaterial = RpMaterialCreate(); #ifdef PC_WATER RpMaterialSetTexture(maskMaterial, gpWaterEnvBaseTex); #else RpMaterialSetTexture(maskMaterial, gpWaterTex); #endif RwRGBA watercolor = { 255, 255, 255, 192 }; RpMaterialSetColor(maskMaterial, &watercolor); } { wavytlist = RpGeometryGetTriangles(wavyGeometry); for ( int32 i = 0; i < 16; i++ ) { for ( int32 j = 0; j < 16; j++ ) { const RwUInt16 base = (RwUInt16)((16 + 1)*i+j); RpGeometryTriangleSetVertexIndices(wavyGeometry, wavytlist, (RwInt16)base, (RwInt16)(base+1), (RwInt16)(base+16+2)); RpGeometryTriangleSetVertexIndices(wavyGeometry, (wavytlist+1), (RwInt16)base, (RwInt16)(base+16+2), (RwInt16)(base+16+1)); RpGeometryTriangleSetMaterial(wavyGeometry, wavytlist, wavyMaterial); RpGeometryTriangleSetMaterial(wavyGeometry, (wavytlist+1), wavyMaterial); wavytlist+=2; } } } { masktlist = RpGeometryGetTriangles(maskGeometry); for ( int32 i = 0; i < 32; i++ ) { for ( int32 j = 0; j < 32; j++ ) { const RwUInt16 base = (RwUInt16)((32 + 1)*i+j); RpGeometryTriangleSetVertexIndices(maskGeometry, masktlist, (RwInt16)base, (RwInt16)(base+1), (RwInt16)(base+32+2)); RpGeometryTriangleSetVertexIndices(maskGeometry, (masktlist+1), (RwInt16)base, (RwInt16)(base+32+2), (RwInt16)(base+32+1)); RpGeometryTriangleSetMaterial(maskGeometry, masktlist, maskMaterial); RpGeometryTriangleSetMaterial(maskGeometry, (masktlist+1), maskMaterial); masktlist+=2; } } } { wavyMorphTarget = RpGeometryGetMorphTarget(wavyGeometry, 0); wavyVert = RpMorphTargetGetVertices(wavyMorphTarget); wavyNormal = RpMorphTargetGetVertexNormals(wavyMorphTarget); for ( int32 i = 0; i < 17; i++ ) { for ( int32 j = 0; j < 17; j++ ) { (*wavyVert).x = (float)i * 2.0f; (*wavyVert).y = (float)j * 2.0f; (*wavyVert).z = 0.0f; (*wavyNormal).x = 0.0f; (*wavyNormal).y = 0.0f; (*wavyNormal).z = 1.0f; wavyVert++; wavyNormal++; } } RpMorphTargetCalcBoundingSphere(wavyMorphTarget, &boundingSphere); RpMorphTargetSetBoundingSphere(wavyMorphTarget, &boundingSphere); RpGeometryUnlock(wavyGeometry); } { maskMorphTarget = RpGeometryGetMorphTarget(maskGeometry, 0); maskVert = RpMorphTargetGetVertices(maskMorphTarget); maskNormal = RpMorphTargetGetVertexNormals(maskMorphTarget); for ( int32 i = 0; i < 33; i++ ) { for ( int32 j = 0; j < 33; j++ ) { (*maskVert).x = (float)i * 2.0f; (*maskVert).y = (float)j * 2.0f; (*maskVert).z = 0.0f; (*maskNormal).x = 0.0f; (*maskNormal).y = 0.0f; (*maskNormal).z = 1.0f; maskVert++; maskNormal++; } } RpMorphTargetCalcBoundingSphere(maskMorphTarget, &boundingSphere); RpMorphTargetSetBoundingSphere(maskMorphTarget, &boundingSphere); RpGeometryUnlock(maskGeometry); } { wavyFrame = RwFrameCreate(); ms_pWavyAtomic = RpAtomicCreate(); RpAtomicSetGeometry(ms_pWavyAtomic, wavyGeometry, 0); RpAtomicSetFrame(ms_pWavyAtomic, wavyFrame); RpMaterialDestroy(wavyMaterial); RpGeometryDestroy(wavyGeometry); } { maskFrame = RwFrameCreate(); ms_pMaskAtomic = RpAtomicCreate(); RpAtomicSetGeometry(ms_pMaskAtomic, maskGeometry, 0); RpAtomicSetFrame(ms_pMaskAtomic, maskFrame); RpMaterialDestroy(maskMaterial); RpGeometryDestroy(maskGeometry); } static RwFrame *wakeEnvFrame; if ( wakeEnvFrame == nil ) { wakeEnvFrame = RwFrameCreate(); RwMatrixSetIdentity(RwFrameGetMatrix(wakeEnvFrame)); RwFrameUpdateObjects(wakeEnvFrame); } RpMatFXMaterialSetEffects(maskMaterial, rpMATFXEFFECTENVMAP); RpMatFXMaterialSetupEnvMap(maskMaterial, gpWaterEnvTex, wakeEnvFrame, TRUE, fEnvScale); RpMatFXAtomicEnableEffects(ms_pMaskAtomic); } void CWaterLevel::DestroyWavyAtomic() { #define _DELETE_ATOMIC(a) \ { \ RwFrame *frame; \ frame = RpAtomicGetFrame(a); \ RpAtomicDestroy(a); \ RwFrameDestroy(frame); \ } _DELETE_ATOMIC(ms_pWavyAtomic); _DELETE_ATOMIC(ms_pMaskAtomic); #undef _DELETE_ATOMIC } #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)[MAX_SMALL_SECTORS] = new bool[MAX_SMALL_SECTORS][MAX_SMALL_SECTORS]; for (int32 x = 0; x < MAX_SMALL_SECTORS; x++) { for (int32 y = 0; y < MAX_SMALL_SECTORS; y++) { isConnected[x][y] = false; } } isConnected[0][0] = true; bool keepGoing; do { keepGoing = false; for (int32 x = 0; x < MAX_SMALL_SECTORS; x++) { for (int32 y = 0; y < MAX_SMALL_SECTORS; y++) { if (aWaterFineBlockList[x][y] < 0 || isConnected[x][y]) continue; 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 < MAX_SMALL_SECTORS && isConnected[x + 1][y]) { isConnected[x][y] = true; keepGoing = true; } if (y + 1 < MAX_SMALL_SECTORS && isConnected[x][y + 1]) { isConnected[x][y] = true; keepGoing = true; } } } } while (keepGoing); int32 numRemoved = 0; for (int32 x = 0; x < MAX_SMALL_SECTORS; x++) { for (int32 y = 0; y < MAX_SMALL_SECTORS; y++) { if (aWaterFineBlockList[x][y] >= 0 && !isConnected[x][y] && ms_aWaterZs[aWaterFineBlockList[x][y]] == 6.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) { int32 x = WATER_TO_SMALL_SECTOR_X(fX + WATER_X_OFFSET); int32 y = WATER_TO_SMALL_SECTOR_Y(fY); #ifdef FIX_BUGS if ( x < 0 || x >= MAX_SMALL_SECTORS ) return false; if ( y < 0 || y >= MAX_SMALL_SECTORS ) return false; #endif int8 nBlock = aWaterFineBlockList[x][y]; if ( nBlock == NO_WATER ) return false; ASSERT( pfOutLevel != nil ); *pfOutLevel = ms_aWaterZs[nBlock]; float fAngle = (CTimer::GetTimeInMilliseconds() & 4095) * (TWOPI / 4096.0f); float fWave = Sin ( ( WATER_UNSIGN_Y(fY) - y*SMALL_SECTOR_SIZE + WATER_UNSIGN_X(fX + WATER_X_OFFSET) - x*SMALL_SECTOR_SIZE ) * (TWOPI / SMALL_SECTOR_SIZE ) + fAngle ); float fWindFactor = CWeather::WindClipped * 0.4f + 0.2f; *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_TO_SMALL_SECTOR_X(fX + WATER_X_OFFSET); int32 y = WATER_TO_SMALL_SECTOR_Y(fY); #ifdef FIX_BUGS if ( x < 0 || x >= MAX_SMALL_SECTORS ) return false; if ( y < 0 || y >= MAX_SMALL_SECTORS ) return false; #endif int8 nBlock = aWaterFineBlockList[x][y]; if ( nBlock == NO_WATER ) return false; ASSERT( pfOutLevel != nil ); *pfOutLevel = ms_aWaterZs[nBlock]; return true; } float CWaterLevel::GetWaterWavesOnly(short x, short y) { float fAngle = (CTimer::GetTimeInMilliseconds() & 4095) * (TWOPI / 4096.0f); float fWindFactor = CWeather::WindClipped * 0.7f + 0.3f; float fWave = Sin( float(float(4 * y + 4 * x) * (TWOPI / SMALL_SECTOR_SIZE )) + fAngle ); return fWave * fWindFactor; } CVector CWaterLevel::GetWaterNormal(float fX, float fY) { //TODO: BUG ? no x offset int32 x = WATER_TO_SMALL_SECTOR_X(fX); int32 y = WATER_TO_SMALL_SECTOR_Y(fY); float fAngle = (CTimer::GetTimeInMilliseconds() & 4095) * (TWOPI / 4096.0f); float fWindFactor = CWeather::WindClipped * 0.4f + 0.2f; float _fWave = (WATER_UNSIGN_Y(fY) - y*SMALL_SECTOR_SIZE + WATER_UNSIGN_X(fX) - x*SMALL_SECTOR_SIZE) * (TWOPI / SMALL_SECTOR_SIZE ) + fAngle; CVector vA(1.0f, 0.0f, fWindFactor * (TWOPI / SMALL_SECTOR_SIZE ) * Cos(_fWave)); CVector vB(0.0f, 1.0f, fWindFactor * (TWOPI / SMALL_SECTOR_SIZE ) * Cos(_fWave)); CVector norm = CrossProduct(vA, vB); norm.Normalise(); return norm; } inline float _GetWaterDrawDist() { if ( TheCamera.GetPosition().z < 15.0f ) return 1200.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 ( Abs(TheCamera.GetForward().x) > Abs(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; } } } inline bool _IsColideWithBlock(int32 x, int32 y, int32 &block) { block = CWaterLevel::aWaterFineBlockList[x + 0][y + 0]; if (block >= 0) return true; block = CWaterLevel::aWaterFineBlockList[x + 0][y + 1]; if (block >= 0) { block = CWaterLevel::aWaterFineBlockList[x + 0][y + 2]; if (block >= 0) return true; } block = CWaterLevel::aWaterFineBlockList[x + 1][y + 0]; if (block >= 0) return true; block = CWaterLevel::aWaterFineBlockList[x + 1][y + 1]; if (block >= 0) { block = CWaterLevel::aWaterFineBlockList[x + 1][y + 2]; if (block >= 0) return true; } block = CWaterLevel::aWaterFineBlockList[x + 2][y + 0]; if (block >= 0) return true; block = CWaterLevel::aWaterFineBlockList[x + 2][y + 1]; if (block >= 0) { block = CWaterLevel::aWaterFineBlockList[x + 2][y + 2]; if (block >= 0) return true; } return false; } inline float SectorRadius(float fSize) { return Sqrt(Pow(fSize, 2) + Pow(fSize, 2)); } void CWaterLevel::RenderWater() { //"Custom" Don't Render Water Toggle #ifndef MASTER if (gbDontRenderWater) return; #endif bool bUseCamEndX = false; bool bUseCamStartY = false; bool bUseCamStartX = false; bool bUseCamEndY = false; if ( !CGame::CanSeeWaterFromCurrArea() ) return; _GetCamBounds(&bUseCamStartY, &bUseCamEndY, &bUseCamStartX, &bUseCamEndX); float fHugeSectorMaxRenderDist = _GetWaterDrawDist(); float fHugeSectorMaxRenderDistSqr = SQR(fHugeSectorMaxRenderDist); float windAddUV = CWeather::WindClipped * 0.0005f + 0.0006f; float fAngle = (CTimer::GetTimeInMilliseconds() & 4095) * (TWOPI / 4096.0f); if ( !CTimer::GetIsPaused() ) { TEXTURE_ADDU += windAddUV; TEXTURE_ADDV += windAddUV; _TEXTURE_MASK_ADDU += Sin(fAngle) * 0.0005f + 1.1f * windAddUV; _TEXTURE_MASK_ADDV -= Cos(fAngle * 1.3f) * 0.0005f + 1.2f * windAddUV; _TEXTURE_WAKE_ADDU -= Sin(fAngle) * 0.0003f + windAddUV; _TEXTURE_WAKE_ADDV += Cos(fAngle * 0.7f) * 0.0003f + windAddUV; } if ( _TEXTURE_MASK_ADDU >= 1.0f ) _TEXTURE_MASK_ADDU = 0.0f; if ( _TEXTURE_MASK_ADDV >= 1.0f ) _TEXTURE_MASK_ADDV = 0.0f; if ( _TEXTURE_WAKE_ADDU >= 1.0f ) _TEXTURE_WAKE_ADDU = 0.0f; if ( _TEXTURE_WAKE_ADDV >= 1.0f ) _TEXTURE_WAKE_ADDV = 0.0f; if ( TEXTURE_ADDU >= 1.0f ) TEXTURE_ADDU = 0.0f; if ( TEXTURE_ADDV >= 1.0f ) TEXTURE_ADDV = 0.0f; #ifdef PC_WATER _fWaterZOffset = CWeather::WindClipped * 0.5f + 0.25f; #endif RwRGBA color = { 0, 0, 0, 255 }; color.red = CTimeCycle::GetWaterRed(); color.green = CTimeCycle::GetWaterGreen(); color.blue = CTimeCycle::GetWaterBlue(); #ifndef PC_WATER RwRGBA colorUnderwater = { 0, 0, 0, 255 }; colorUnderwater.red = (uint32)(0.8f * (float)colorUnderwater.red); colorUnderwater.green = (uint32)(0.8f * (float)colorUnderwater.green); colorUnderwater.blue = (uint32)(0.8f * (float)colorUnderwater.blue); #endif TempBufferVerticesStored = 0; TempBufferIndicesStored = 0; #ifndef PC_WATER WavesCalculatedThisFrame = false; #endif 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 + WATER_X_OFFSET); int32 nEndX = WATER_TO_HUGE_SECTOR_X(camPos.x + fHugeSectorMaxRenderDist + WATER_X_OFFSET) + 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 + WATER_X_OFFSET); if ( bUseCamEndX ) nEndX = WATER_TO_HUGE_SECTOR_X(camPos.x + WATER_X_OFFSET); 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] >= 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) - WATER_X_OFFSET; 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), &TheCamera.GetCameraMatrix()) ) { #ifndef PC_WATER WavesCalculatedThisFrame = true; #endif float fZ; 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] >= 0 ) fZ = ms_aWaterZs[ aWaterBlockList[2*x+1][2*y+0] ]; 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] >= 0 ) fZ = ms_aWaterZs[ aWaterBlockList[2*x+1][2*y+1] ]; if ( fHugeSectorDistToCamSqr >= SQR(500.0f) ) { RenderOneFlatHugeWaterPoly(fX, fY, fZ, color); } else { #ifndef PC_WATER if (m_bRenderSeaBed) RenderOneSlopedUnderWaterPoly(fX, fY, fZ, colorUnderwater); #endif // see RenderTransparentWater() ; } } } } } } /* ----------- ---------------------- ---------------------- | [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 */ 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 - WATER_X_OFFSET; float fY = WATER_SIGN_Y(float(y) * EXTRAHUGE_SECTOR_SIZE) - 1280.0f; if ( !bUseCamStartY ) { 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), &TheCamera.GetCameraMatrix()) ) { RenderOneFlatExtraHugeWaterPoly( vecExtraHugeSectorCentre.x - EXTRAHUGE_SECTOR_SIZE/2, vecExtraHugeSectorCentre.y - EXTRAHUGE_SECTOR_SIZE/2, 0.0f, color); } } } if ( !bUseCamEndY ) { 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), &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 - WATER_X_OFFSET; float fX2 = WATER_SIGN_X(float(x) * EXTRAHUGE_SECTOR_SIZE) - 1280.0f + WATER_X_OFFSET; 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), &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.x, 0.0f), SectorRadius(EXTRAHUGE_SECTOR_SIZE), &TheCamera.GetCameraMatrix()) ) { RenderOneFlatExtraHugeWaterPoly( vecExtraHugeSectorCentre.x - EXTRAHUGE_SECTOR_SIZE/2, vecExtraHugeSectorCentre.y - EXTRAHUGE_SECTOR_SIZE/2, 0.0f, color); } } } } } RenderAndEmptyRenderBuffer(); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); if ( WavesCalculatedThisFrame ) { RenderSeaBirds(); RenderShipsOnHorizon(); CParticle::HandleShipsAtHorizonStuff(); HandleBeachToysStuff(); } if ( _bSeaLife ) HandleSeaLifeForms(); DefinedState(); } void CWaterLevel::RenderTransparentWater(void) { bool bUseCamEndX = false; bool bUseCamStartY = false; bool bUseCamStartX = false; bool bUseCamEndY = false; _bSeaLife = false; if ( !CGame::CanSeeWaterFromCurrArea() ) return; PUSH_RENDERGROUP("CWaterLevel::RenderTransparentWater"); float fWaterDrawDist = _GetWavyDrawDist(); float fWaterDrawDistLarge = fWaterDrawDist + 90.0f; float fWavySectorMaxRenderDistSqr = SQR(fWaterDrawDist); _GetCamBounds(&bUseCamStartY, &bUseCamEndY, &bUseCamStartX, &bUseCamEndX); float fHugeSectorMaxRenderDist = _GetWaterDrawDist(); float fHugeSectorMaxRenderDistSqr = SQR(fHugeSectorMaxRenderDist); RenderBoatWakes(); RwRGBA color; color.red = CTimeCycle::GetWaterRed(); color.green = CTimeCycle::GetWaterGreen(); color.blue = CTimeCycle::GetWaterBlue(); color.alpha = 255; RwRGBA colorTrans; colorTrans.red = CTimeCycle::GetWaterRed(); colorTrans.green = CTimeCycle::GetWaterGreen(); colorTrans.blue = CTimeCycle::GetWaterBlue(); colorTrans.alpha = CTimeCycle::GetWaterAlpha(); TempBufferVerticesStored = 0; TempBufferIndicesStored = 0; #ifndef PC_WATER WavesCalculatedThisFrame = false; #endif RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)gpWaterRaster); #ifndef PC_WATER RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); #endif CVector2D camPos(TheCamera.GetPosition().x, TheCamera.GetPosition().y); int32 nStartX = WATER_TO_HUGE_SECTOR_X(camPos.x - fHugeSectorMaxRenderDist + WATER_X_OFFSET); int32 nEndX = WATER_TO_HUGE_SECTOR_X(camPos.x + fHugeSectorMaxRenderDist + WATER_X_OFFSET) + 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 + WATER_X_OFFSET); if ( bUseCamEndX ) nEndX = WATER_TO_HUGE_SECTOR_X(camPos.x + WATER_X_OFFSET); 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] >= 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) - WATER_X_OFFSET; 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), &TheCamera.GetCameraMatrix()) ) { if ( fHugeSectorDistToCamSqr >= SQR(500.0f) ) { // see RenderWater() ; } 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] >= 0 ) { float fLargeX = WATER_FROM_LARGE_SECTOR_X(x2) - WATER_X_OFFSET; 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), &TheCamera.GetCameraMatrix()) ) { // Render four small(32x32) sectors, or one large(64x64). // // [N] // --------- // |0x1|1x1| // [W] --------- [E] // |0x0|1x0| // --------- // [S] // float fLargeSectorDrawDistSqr = SQR((fWaterDrawDistLarge + 16.0f)); if ( fLargeSectorDistToCamSqr < fLargeSectorDrawDistSqr ) { _bSeaLife = true; float fZ; // WS if ( aWaterFineBlockList[2*x2+0][2*y2+0] >= 0 ) { 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, colorTrans); else RenderOneFlatSmallWaterPolyBlended(fSmallX, fSmallY, fZ, camPos.x, camPos.y, color, colorTrans, fWaterDrawDist); } // SE if ( aWaterFineBlockList[2*x2+1][2*y2+0] >= 0 ) { 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, colorTrans); else RenderOneFlatSmallWaterPolyBlended(fSmallX, fSmallY, fZ, camPos.x, camPos.y, color, colorTrans, fWaterDrawDist); } // WN if ( aWaterFineBlockList[2*x2+0][2*y2+1] >= 0 ) { 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, colorTrans); else RenderOneFlatSmallWaterPolyBlended(fSmallX, fSmallY, fZ, camPos.x, camPos.y, color, colorTrans, fWaterDrawDist); } //NE if ( aWaterFineBlockList[2*x2+1][2*y2+1] >= 0 ) { 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, colorTrans); else RenderOneFlatSmallWaterPolyBlended(fSmallX, fSmallY, fZ, camPos.x, camPos.y, color, colorTrans, fWaterDrawDist); } } else { float fZ; fZ = ms_aWaterZs[ aWaterBlockList[x2][y2] ]; RenderOneFlatLargeWaterPoly(fLargeX, fLargeY, fZ, color); } } } } } } } } } } } } RenderAndEmptyRenderBuffer(); #ifdef PC_WATER if ( MaskCalculatedThisFrame && (m_nRenderWaterLayers == 0 || m_nRenderWaterLayers == 2 || m_nRenderWaterLayers == 3) ) { RwV3d pos = { 0.0f, 0.0f, 0.0f }; pos.x = PreCalculatedMaskPosn.x; pos.y = PreCalculatedMaskPosn.y; pos.z = PreCalculatedMaskPosn.z; RpMatFXMaterialSetEnvMapFrame(RpGeometryGetMaterial(RpAtomicGetGeometry(ms_pMaskAtomic), 0), RwCameraGetFrame(RwCameraGetCurrentCamera())); RwFrameTranslate(RpAtomicGetFrame(ms_pMaskAtomic), &pos, rwCOMBINEREPLACE); RpAtomicRender(ms_pMaskAtomic); } #else if (!CCullZones::WaterFudge()) { int32 signX = 0; int32 signY = 0; float fCamX = camPos.x - SMALL_SECTOR_SIZE; float fCamY = camPos.y - SMALL_SECTOR_SIZE; if (TheCamera.GetForward().x > 0.3f) signX = 1; else if (TheCamera.GetForward().x < -0.3f) signX = -1; fCamX += 0.3f * (float)signX * float(SMALL_SECTOR_SIZE * 2.0f); // 19.2f if (TheCamera.GetForward().y > 0.3f) signY = 1; else if (TheCamera.GetForward().y < -0.3f) signY = -1; fCamY += 0.3f * (float)signY * float(SMALL_SECTOR_SIZE * 2.0f); // 19.2f int32 nBlock; int32 BlockX = WATER_TO_SMALL_SECTOR_X(fCamX + WATER_X_OFFSET) + 1; int32 BlockY = WATER_TO_SMALL_SECTOR_Y(fCamY) + 1; if (_IsColideWithBlock(BlockX, BlockY, nBlock)) { if (m_nRenderWaterLayers != 1 && m_nRenderWaterLayers != 6) { float fMaskX = Floor(fCamX / 2.0f) * 2.0f; float fMaskY = Floor(fCamY / 2.0f) * 2.0f; float fWaterZ = CWaterLevel::ms_aWaterZs[nBlock]; float fSectorX = WATER_FROM_SMALL_SECTOR_X(BlockX) - WATER_X_OFFSET; float fSectorY = WATER_FROM_SMALL_SECTOR_Y(BlockY); RenderWavyMask(fMaskX, fMaskY, fWaterZ, fSectorX, fSectorY, signX, signY, colorTrans); } } } DefinedState(); #endif POP_RENDERGROUP(); } 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 - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDV); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 0], color); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 1], fX, fY + SMALL_SECTOR_SIZE, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDV + 1.0f); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 1], color); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 2], fX + SMALL_SECTOR_SIZE, fY + SMALL_SECTOR_SIZE, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDU + 1.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDV + 1.0f); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 2], color); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 3], fX + SMALL_SECTOR_SIZE, fY, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDU + 1.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDV); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 3], color); 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 - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDV); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 0], color); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 1], fX, fY + LARGE_SECTOR_SIZE, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDV + 2.0f); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 1], color); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 2], fX + LARGE_SECTOR_SIZE, fY + LARGE_SECTOR_SIZE, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDU + 2.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDV + 2.0f); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 2], color); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 3], fX + LARGE_SECTOR_SIZE, fY, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDU + 2.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDV); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 3], color); 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; RwRGBA c; c.red = color.red; c.green = color.green; c.blue = color.blue; c.alpha = 255; RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 0], fX, fY, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDV); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 0], c); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 1], fX, fY + HUGE_SECTOR_SIZE, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDV + 4.0f); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 1], c); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 2], fX + HUGE_SECTOR_SIZE, fY + HUGE_SECTOR_SIZE, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDU + 4.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDV + 4.0f); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 2], c); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 3], fX + HUGE_SECTOR_SIZE, fY, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDU + 4.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDV); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 3], c); 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; RwRGBA c; c.red = color.red; c.green = color.green; c.blue = color.blue; c.alpha = 255; RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 0], fX, fY, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDV); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 0], c); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 1], fX, fY + EXTRAHUGE_SECTOR_SIZE, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDV + 8.0f); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 1], c); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 2], fX + EXTRAHUGE_SECTOR_SIZE, fY + EXTRAHUGE_SECTOR_SIZE, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDU + 8.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 2], TEXTURE_ADDV + 8.0f); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 2], c); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 3], fX + EXTRAHUGE_SECTOR_SIZE, fY, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDU + 8.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDV); RwIm3DVertexSet_RGBA(&TempBufferRenderVertices[vidx + 3], c); 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 bDontRender) { CVector vecSectorPos(fX + (SMALL_SECTOR_SIZE/2), fY + (SMALL_SECTOR_SIZE/2), fZ + 2.0f); if ( COcclusion::IsAABoxOccluded(vecSectorPos, SMALL_SECTOR_SIZE, SMALL_SECTOR_SIZE, 4.0f) ) return; #ifdef PC_WATER RequireWavySector = true; #else if (!WavesCalculatedThisFrame) { WavesCalculatedThisFrame = true; float fAngle = (CTimer::GetTimeInMilliseconds() & 4095) * (TWOPI / 4096.0f); RpGeometry *wavyGeometry = RpAtomicGetGeometry(ms_pWavyAtomic); RwTexCoords *wavyTexCoords = RpGeometryGetVertexTexCoords(wavyGeometry, rwTEXTURECOORDINATEINDEX0); RpMorphTarget *wavyMorph = RpGeometryGetMorphTarget(wavyGeometry, 0); RwRGBA *wavyPreLight = RpGeometryGetPreLightColors(wavyGeometry); RwV3d *wavyMorphVerts = RpMorphTargetGetVertices(wavyMorph); RwV3d *wavyMorphNormals = RpMorphTargetGetVertexNormals(wavyMorph); RpGeometryLock(wavyGeometry, rpGEOMETRYLOCKVERTICES | rpGEOMETRYLOCKNORMALS | rpGEOMETRYLOCKPRELIGHT | rpGEOMETRYLOCKTEXCOORDS); RwMatrix *camMat = RwFrameGetLTM(RwCameraGetFrame(RwCameraGetCurrentCamera())); //or curWorld float randomDampInv2 = (1.0f - fRandomDamp) * 2.0f; float move = 1.0f / 16.0f; float randomMove = 1.0f / (16.0f * fRandomMoveDiv); float vertMul = 0.5f; float wind = CWeather::WindClipped * 0.4f + 0.2f; float waveWind = CWeather::WindClipped * fWave2Ampl + 0.05f; float waveA = (TWOPI / 16.0f) * ((fNormalDirectionScalar1 * Abs(camMat->at.x + camMat->at.y) + fNormMult) * (CWeather::WindClipped * 0.4f + 0.2f)); float waveB = TWOPI / (16.0f * fWave2NormScale) * ((fNormalDirectionScalar2 * Abs(camMat->at.y - camMat->at.x) + fNormMultB) * (CWeather::WindClipped * 0.2f + 0.1f)); CVector vA(1.0f, 0.0f, 0.0f); CVector vB(0.0f, 1.0f, 0.0f); for ( int32 i = 0; i < 17; i++ ) { for ( int32 j = 0; j < 17; j++ ) { wavyTexCoords->u = float(i) * move + TEXTURE_ADDV; wavyTexCoords->v = float(j) * move + TEXTURE_ADDU; RwRGBAAssign(wavyPreLight, &color); if (i > 0 && i < 16 && j > 0 && j < 16) { wavyMorphVerts->x += CGeneral::GetRandomNumberInRange(-1.0f, 1.0f) * randomMove; wavyMorphVerts->x *= fRandomDamp; wavyMorphVerts->x += float(i) * randomDampInv2; wavyMorphVerts->y += CGeneral::GetRandomNumberInRange(-1.0f, 1.0f) * randomMove; wavyMorphVerts->y *= fRandomDamp; wavyMorphVerts->y += float(j) * randomDampInv2; } float morphVertXHalf = (i == 16) ? 0.0f : vertMul * wavyMorphVerts->x; float morphVertYHalf = (j == 16) ? 0.0f : vertMul * wavyMorphVerts->y; float waveMulA = (morphVertYHalf + morphVertXHalf) * (TWOPI / 16.0f) + fAngle; float waveMulB = (morphVertYHalf - morphVertXHalf) * (TWOPI / (16.0f * fWave2InvLength)) + fAngle; wavyMorphVerts->z = wind * Sin(waveMulA) + waveWind * Sin(waveMulB); vA.z = (waveA * Cos(waveMulA)) - (waveB * Cos(waveMulB)); vB.z = (waveA * Cos(waveMulA)) + (waveB * Cos(waveMulB)); CVector norm = CrossProduct(vA, vB); norm.Normalise(); wavyMorphNormals->x = norm.x; wavyMorphNormals->y = norm.y; wavyMorphNormals->z = norm.z; ++wavyPreLight; ++wavyTexCoords; ++wavyMorphVerts; ++wavyMorphNormals; } } RpGeometryUnlock(wavyGeometry); } float fCentreX = fX + (SMALL_SECTOR_SIZE / 2); float fCentreY = fY + (SMALL_SECTOR_SIZE / 2); #endif #ifdef PC_WATER if ( WavesCalculatedThisFrame ) #endif { if (bDontRender == false && m_nRenderWaterLayers != 2 && m_nRenderWaterLayers != 4 && m_nRenderWaterLayers != 6 ) { RwV3d pos = { 0.0f, 0.0f, 0.0f }; pos.x = fX; pos.y = fY; pos.z = fZ; RwFrameTranslate(RpAtomicGetFrame(ms_pWavyAtomic), &pos, rwCOMBINEREPLACE); RpAtomicRender(ms_pWavyAtomic); } } } int16 _RoundValue(int32 v) { int16 result = v; while ( result < 0 ) result += 16; while ( result > 16 ) result -= 16; return result; } void CWaterLevel::RenderWavyMask(float fX, float fY, float fZ, float fSectorX, float fSectorY, #ifdef PC_WATER float fCamPosX, float fCamPosY, float fCamDirX, float fCamDirY, RwRGBA const&color) #else int32 nCamDirX, int32 nCamDirY, RwRGBA const&color) #endif { #ifndef PC_WATER bool bRender = true; if (m_nRenderWaterLayers != 0 && m_nRenderWaterLayers != 2 && m_nRenderWaterLayers != 3) bRender = false; #endif CVector vecSectorPos(fX + (LARGE_SECTOR_SIZE/2), fY + (LARGE_SECTOR_SIZE/2), fZ + 2.0f); if ( COcclusion::IsAABoxOccluded(vecSectorPos, LARGE_SECTOR_SIZE, LARGE_SECTOR_SIZE, 4.0f) ) return; #ifndef PC_WATER float fUOffset = fX - (MAX_LARGE_SECTORS * (int32)Floor(fX / MAX_LARGE_SECTORS)); float fVOffset = fY - (MAX_LARGE_SECTORS * (int32)Floor(fY / MAX_LARGE_SECTORS)); int32 nSecsX = (int32)((fX - fSectorX) / 2.0f); int32 nSecsY = (int32)((fY - fSectorY) / 2.0f); #endif RpGeometry *wavyGeometry = RpAtomicGetGeometry(ms_pWavyAtomic); RpMorphTarget *wavyMorph = RpGeometryGetMorphTarget(wavyGeometry, 0); RwV3d *wavyMorphVerts = RpMorphTargetGetVertices(wavyMorph); RwV3d *wavyMorphNormals = RpMorphTargetGetVertexNormals(wavyMorph); RpGeometry *maskGeometry = RpAtomicGetGeometry(ms_pMaskAtomic); RwTexCoords *maskTexCoords = RpGeometryGetVertexTexCoords(maskGeometry, rwTEXTURECOORDINATEINDEX0); RwRGBA *maskPreLight = RpGeometryGetPreLightColors(maskGeometry); RpMorphTarget *maskMorph = RpGeometryGetMorphTarget(maskGeometry, 0); RwV3d *maskMorphVerts = RpMorphTargetGetVertices(maskMorph); RwV3d *maskMorphNormals = RpMorphTargetGetVertexNormals(maskMorph); RpGeometryLock(maskGeometry, rpGEOMETRYLOCKVERTICES|rpGEOMETRYLOCKNORMALS|rpGEOMETRYLOCKPRELIGHT|rpGEOMETRYLOCKTEXCOORDS); #ifndef PC_WATER RpMaterial *maskMat = RpGeometryGetMaterial(maskGeometry, 0); RpMatFXMaterialSetEnvMapFrame(maskMat, RwCameraGetFrame(RwCameraGetCurrentCamera())); RpMatFXMaterialSetEnvMapCoefficient(maskMat, fEnvScale); RpMatFXMaterialSetEnvMapFrameBufferAlpha(maskMat, TRUE); #endif #ifndef PC_WATER float fMinSparkZ = (CWeather::WindClipped * fWave2Ampl + 0.05f + CWeather::WindClipped * 0.4f + 0.2) * (1.0f - 0.04f * CWeather::SunGlare); int32 randval = CGeneral::GetRandomNumber(); float fUVStep = 0.125f; float f27 = 2.0f; float fMinU = (fUOffset / 16.0f) + _TEXTURE_MASK_ADDU; float fMinV = (fVOffset / 16.0f) + _TEXTURE_MASK_ADDV; float fAlphaMul = ((float)color.alpha * 0.4f) / 16.0f; float fXOffset = 16.0f; if (nCamDirX > 0) fXOffset = 6.4f; else if (nCamDirX < 0) fXOffset = 25.6f; float fYOffset = 16.0f; if (nCamDirY > 0) fYOffset = 6.4f; else if (nCamDirY < 0) fYOffset = 25.6f; int16 nX = _RoundValue(nSecsX - 1); int16 nY = _RoundValue(nSecsY - 1); #else float fMinSparkZ = (fWave2Ampl * CWeather::WindClipped + 0.05f + 0.4f * CWeather::WindClipped + 0.2) * (1.0f - 0.02f * CWeather::SunGlare); int32 randval = CGeneral::GetRandomNumber() & 255; int16 nX = _RoundValue((int32)((fX - fSectorX) * 0.5f) - 1); int16 nY = _RoundValue((int32)((fY - fSectorY) * 0.5f) - 1); #endif int16 idxX = nX; for ( int32 i = 0; i < 17; i++ ) { int16 idxY = nY; if ( ++idxX > 16 ) idxX -= 16; for ( int32 j = 0; j < 17; j++ ) { if ( ++idxY > 16 ) idxY -= 16; const int32 a = (0*16); const int32 b = (1*16); const int32 c = (33*16); const int32 d = (34*16); int32 base = (i*33+j); #ifndef PC_WATER maskTexCoords[base + a].u = fMinU + ((float)i * fUVStep); maskTexCoords[base + a].v = fMinV + ((float)j * fUVStep); maskTexCoords[base + b].u = maskTexCoords[base + a].u; maskTexCoords[base + b].v = maskTexCoords[base + a].v + (16.0f * fUVStep); maskTexCoords[base + c].u = maskTexCoords[base + a].u + (16.0f * fUVStep); maskTexCoords[base + c].v = maskTexCoords[base + a].v; maskTexCoords[base + d].u = maskTexCoords[base + a].u + (16.0f * fUVStep); maskTexCoords[base + d].v = maskTexCoords[base + a].v + (16.0f * fUVStep); #else maskTexCoords[base+a].v = float(j) / SMALL_SECTOR_SIZE + ((fCamPosY - fY) / 64); maskTexCoords[base+c].v = maskTexCoords[base+a].v; maskTexCoords[base+d].v = maskTexCoords[base+a].v + 0.5f; maskTexCoords[base+b].v = maskTexCoords[base+d].v; maskTexCoords[base+a].u = float(i) / SMALL_SECTOR_SIZE + ((fCamPosX - fX) / 64); maskTexCoords[base+b].u = maskTexCoords[base+a].u; maskTexCoords[base+d].u = maskTexCoords[base+a].u + 0.5f; maskTexCoords[base+c].u = maskTexCoords[base+d].u; #endif maskMorphVerts[base+a].x = (wavyMorphVerts[idxY + (17 * idxX)].x - (float)idxX * 2.0f) + (float(i) * 2.0f); maskMorphVerts[base+b].x = maskMorphVerts[base+a].x; maskMorphVerts[base+c].x = maskMorphVerts[base+a].x + SMALL_SECTOR_SIZE; maskMorphVerts[base+d].x = maskMorphVerts[base+c].x; maskMorphVerts[base+a].y = (wavyMorphVerts[idxY + (17 * idxX)].y - (float)idxY * 2.0f) + (float(j) * 2.0f); maskMorphVerts[base+c].y = maskMorphVerts[base+a].y; maskMorphVerts[base+b].y = maskMorphVerts[base+a].y + SMALL_SECTOR_SIZE; maskMorphVerts[base+d].y = maskMorphVerts[base+b].y; maskMorphVerts[base+a].z = wavyMorphVerts[idxY + (17 * idxX)].z; maskMorphVerts[base+d].z = maskMorphVerts[base+a].z; maskMorphVerts[base+c].z = maskMorphVerts[base+d].z; maskMorphVerts[base+b].z = maskMorphVerts[base+c].z; #ifndef PC_WATER if (maskMorphVerts[base].z >= fMinSparkZ) #else if ( maskMorphVerts[base].z > fMinSparkZ ) #endif { switch ( (i + j + randval) & 3 ) { case 0: { CVector vecPos ( fX + maskMorphVerts[base+a].x, fY + maskMorphVerts[base+a].y, fZ + maskMorphVerts[base+a].z + 0.12f ); vecPos -= 0.05f * TheCamera.GetForward(); CParticle::AddParticle(PARTICLE_WATER_SPARK, vecPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 15, CGeneral::GetRandomNumberInRange(-90, 90), 0, 0); } break; case 1: { CVector vecPos ( fX + maskMorphVerts[base+c].x, fY + maskMorphVerts[base+c].y, fZ + maskMorphVerts[base+c].z + 0.12f ); vecPos -= 0.05f * TheCamera.GetForward(); CParticle::AddParticle(PARTICLE_WATER_SPARK, vecPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 15, CGeneral::GetRandomNumberInRange(-90, 90), 0, 0); } break; case 2: { CVector vecPos ( fX + maskMorphVerts[base+b].x, fY + maskMorphVerts[base+b].y, fZ + maskMorphVerts[base+b].z + 0.12f ); vecPos -= 0.05f * TheCamera.GetForward(); CParticle::AddParticle(PARTICLE_WATER_SPARK, vecPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 15, CGeneral::GetRandomNumberInRange(-90, 90), 0, 0); } break; case 3: { CVector vecPos ( fX + maskMorphVerts[base+d].x, fY + maskMorphVerts[base+d].y, fZ + maskMorphVerts[base+d].z + 0.12f ); vecPos -= 0.05f * TheCamera.GetForward(); CParticle::AddParticle(PARTICLE_WATER_SPARK, vecPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 15, CGeneral::GetRandomNumberInRange(-90, 90), 0, 0); } break; } } maskMorphNormals[base+a].x = wavyMorphNormals[idxY + (17 * idxX)].x; maskMorphNormals[base+a].y = wavyMorphNormals[idxY + (17 * idxX)].y; maskMorphNormals[base+a].z = wavyMorphNormals[idxY + (17 * idxX)].z; maskMorphNormals[base+d].x = maskMorphNormals[base+a].x; maskMorphNormals[base+d].y = maskMorphNormals[base+a].y; maskMorphNormals[base+d].z = maskMorphNormals[base+a].z; maskMorphNormals[base+c].x = maskMorphNormals[base+d].x; maskMorphNormals[base+c].y = maskMorphNormals[base+d].y; maskMorphNormals[base+c].z = maskMorphNormals[base+d].z; maskMorphNormals[base+b].x = maskMorphNormals[base+c].x; maskMorphNormals[base+b].y = maskMorphNormals[base+c].y; maskMorphNormals[base+b].z = maskMorphNormals[base+c].z; maskPreLight[base+a].red = color.red; maskPreLight[base+a].green = color.green; maskPreLight[base+a].blue = color.blue; maskPreLight[base+a].alpha = color.alpha; maskPreLight[base+d].red = maskPreLight[base+a].red; maskPreLight[base+d].green = maskPreLight[base+a].green; maskPreLight[base+d].blue = maskPreLight[base+a].blue; maskPreLight[base+d].alpha = maskPreLight[base+a].alpha; maskPreLight[base+c].red = maskPreLight[base+d].red; maskPreLight[base+c].green = maskPreLight[base+d].green; maskPreLight[base+c].blue = maskPreLight[base+d].blue; maskPreLight[base+c].alpha = maskPreLight[base+d].alpha; maskPreLight[base+b].red = maskPreLight[base+c].red; maskPreLight[base+b].green = maskPreLight[base+c].green; maskPreLight[base+b].blue = maskPreLight[base+c].blue; maskPreLight[base+b].alpha = maskPreLight[base+c].alpha; #ifndef PC_WATER maskPreLight[base + a].alpha = Max(0, (int32)((float)color.alpha - (fAlphaMul * (Abs((float)i - fXOffset) + Abs((float)j - fYOffset))))); maskPreLight[base + b].alpha = Max(0, (int32)((float)color.alpha - (fAlphaMul * (Abs((float)i - fXOffset) + Abs(16.0f + (float)j - fYOffset))))); maskPreLight[base + c].alpha = Max(0, (int32)((float)color.alpha - (fAlphaMul * (Abs(16.0f + (float)i - fXOffset) + Abs((float)j - fYOffset))))); maskPreLight[base + d].alpha = Max(0, (int32)((float)color.alpha - (fAlphaMul * (Abs(16.0f + (float)i - fXOffset) + Abs(16.0f + (float)j - fYOffset))))); #endif } } RpGeometryUnlock(maskGeometry); #ifndef PC_WATER { RwV3d pos = { 0.0f, 0.0f, 0.0f }; pos.x = fX; pos.y = fY; pos.z = fZ + 0.05f; RwFrameTranslate(RpAtomicGetFrame(ms_pMaskAtomic), &pos, rwCOMBINEREPLACE); if (bRender) { #ifdef PS2 RpSkyTexCacheFlush(); #endif RpAtomicRender(ms_pMaskAtomic); } } #endif } #ifdef PC_WATER void CWaterLevel::PreCalcWaterGeometry(void) { if ( !RequireWavySector ) { WavesCalculatedThisFrame = false; MaskCalculatedThisFrame = false; return; } RequireWavySector = false; WavesCalculatedThisFrame = true; RwRGBA color; color.red = CTimeCycle::GetWaterRed(); color.green = CTimeCycle::GetWaterGreen(); color.blue = CTimeCycle::GetWaterBlue(); color.alpha = CTimeCycle::GetWaterAlpha(); PreCalcWavySector(color); if ( CCullZones::WaterFudge() ) { MaskCalculatedThisFrame = false; return; } CVector CamFwdDir = TheCamera.GetForward(); CamFwdDir.z = 0.0f; CamFwdDir.Normalise(); float fCamX = TheCamera.GetPosition().x - SMALL_SECTOR_SIZE; float fCamY = TheCamera.GetPosition().y - SMALL_SECTOR_SIZE; //1.4144272f; 1.4144f; float signX = CamFwdDir.x * 1.4144272f; float signY = CamFwdDir.y * 1.4144272f; signX = clamp(signX, -1.0f, 1.0f); fCamX += 0.4f * signX * float(SMALL_SECTOR_SIZE * 2.0f); signY = clamp(signY, -1.0f, 1.0f); fCamY += 0.4f * signY * float(SMALL_SECTOR_SIZE * 2.0f); int32 nBlock; int32 BlockX = WATER_TO_SMALL_SECTOR_X(fCamX + WATER_X_OFFSET) + 1; int32 BlockY = WATER_TO_SMALL_SECTOR_Y(fCamY ) + 1; ASSERT( BlockX >= 0 && BlockX < MAX_SMALL_SECTORS ); ASSERT( BlockY >= 0 && BlockY < MAX_SMALL_SECTORS ); if ( _IsColideWithBlock(BlockX, BlockY, nBlock) ) { float fMaskX = Floor(fCamX / 2.0f) * 2.0f; float fMaskY = Floor(fCamY / 2.0f) * 2.0f; float fSectorX = WATER_FROM_SMALL_SECTOR_X(BlockX) - WATER_X_OFFSET; float fSectorY = WATER_FROM_SMALL_SECTOR_Y(BlockY); if ( PreCalcWavyMask( fMaskX, fMaskY, ms_aWaterZs[nBlock], fSectorX, fSectorY, fCamX, fCamY, CamFwdDir.x, CamFwdDir.y, color ) ) { PreCalculatedMaskPosn.x = fMaskX; PreCalculatedMaskPosn.y = fMaskY; PreCalculatedMaskPosn.z = ms_aWaterZs[nBlock] + 0.05f; MaskCalculatedThisFrame = true; } else MaskCalculatedThisFrame = false; } else MaskCalculatedThisFrame = false; } bool CWaterLevel::PreCalcWavySector(RwRGBA const &color) { float fAngle = (CTimer::GetTimeInMilliseconds() & 4095) * (TWOPI / 4096.0f); RpGeometry *wavyGeometry = RpAtomicGetGeometry(ms_pWavyAtomic); RwTexCoords *wavyTexCoords = RpGeometryGetVertexTexCoords(wavyGeometry, rwTEXTURECOORDINATEINDEX0); RpMorphTarget *wavyMorph = RpGeometryGetMorphTarget(wavyGeometry, 0); RwRGBA *wavyPreLight = RpGeometryGetPreLightColors(wavyGeometry); RwV3d *wavyMorphVerts = RpMorphTargetGetVertices(wavyMorph); RwV3d *wavyMorphNormals = RpMorphTargetGetVertexNormals(wavyMorph); if ( !m_bRenderSeaBed ) RpGeometryLock(wavyGeometry, rpGEOMETRYLOCKVERTICES |rpGEOMETRYLOCKNORMALS |rpGEOMETRYLOCKPRELIGHT |rpGEOMETRYLOCKTEXCOORDS); CVector camPosUp = TheCamera.GetForward(); float randomDampInv2 = (1.0f - fRandomDamp) * 2.0f; float randomMove = 1.0f / (16.0f * fRandomMoveDiv); float wind = CWeather::WindClipped * 0.4f + 0.2f; float waveWind = CWeather::WindClipped * fWave2Ampl + 0.05f; float waveA = (TWOPI / 16.0f) * ((CWeather::WindClipped * 0.4f + 0.2f) * (fNormalDirectionScalar1 * Abs(camPosUp.x + camPosUp.y) + fNormMult)); float waveB = TWOPI / (16.0f * fWave2NormScale) * ((CWeather::WindClipped * 0.2f + 0.1f) * (fNormalDirectionScalar2 * Abs(camPosUp.y - camPosUp.x) + fNormMultB)); CVector vA(1.0f, 0.0f, 0.0f); CVector vB(0.0f, 1.0f, 0.0f); for ( int32 i = 0; i < 17; i++ ) { for ( int32 j = 0; j < 17; j++ ) { wavyTexCoords->u = (float(i) / 16.0f) + TEXTURE_ADDV; wavyTexCoords->v = (float(j) / 16.0f) + TEXTURE_ADDU; RwRGBAAssign(wavyPreLight, &color); if ( i > 0 && i < 16 && j > 0 && j < 16 ) { wavyMorphVerts->x += CGeneral::GetRandomNumberInRange(-1.0f, 1.0f) * randomMove; wavyMorphVerts->x *= fRandomDamp; wavyMorphVerts->x += float(i) * randomDampInv2; wavyMorphVerts->y += CGeneral::GetRandomNumberInRange(-1.0f, 1.0f) * randomMove; wavyMorphVerts->y *= fRandomDamp; wavyMorphVerts->y += float(j) * randomDampInv2; } float morphVertXHalf = ( i == 16 ) ? 0.0f : 0.5f * wavyMorphVerts->x; float morphVertYHalf = ( j == 16 ) ? 0.0f : 0.5f * wavyMorphVerts->y; float waveMulA = (morphVertYHalf + morphVertXHalf) * (TWOPI / 16.0f) + fAngle; float waveMulB = (morphVertYHalf - morphVertXHalf) * (TWOPI / (16.0f * fWave2InvLength)) + fAngle; wavyMorphVerts->z = wind * Sin(waveMulA) + waveWind * Sin(waveMulB); vA.z = (waveA * Cos(waveMulA)) - (waveB * Cos(waveMulB)); vB.z = (waveA * Cos(waveMulA)) + (waveB * Cos(waveMulB)); CVector norm = CrossProduct(vA, vB); norm.Normalise(); wavyMorphNormals->x = norm.x; wavyMorphNormals->y = norm.y; wavyMorphNormals->z = norm.z; ++wavyPreLight; ++wavyTexCoords; ++wavyMorphVerts; ++wavyMorphNormals; } } RpGeometryUnlock(wavyGeometry); return true; } bool CWaterLevel::PreCalcWavyMask(float fX, float fY, float fZ, float fSectorX, float fSectorY, float fCamPosX, float fCamPosY, float fCamDirX, float fCamDirY, RwRGBA const&color) { CVector vecSectorPos(fX + (MAX_LARGE_SECTORS/2), fY + (MAX_LARGE_SECTORS/2), fZ + 2.0f); if ( COcclusion::IsAABoxOccluded(vecSectorPos, MAX_LARGE_SECTORS, MAX_LARGE_SECTORS, 4.0f) ) return false; Floor(fX / MAX_LARGE_SECTORS); Floor(fY / MAX_LARGE_SECTORS); RpGeometry *wavyGeometry = RpAtomicGetGeometry(ms_pWavyAtomic); RpMorphTarget *wavyMorph = RpGeometryGetMorphTarget(wavyGeometry, 0); RwV3d *wavyMorphVerts = RpMorphTargetGetVertices(wavyMorph); RwV3d *wavyMorphNormals = RpMorphTargetGetVertexNormals(wavyMorph); RpGeometry *maskGeometry = RpAtomicGetGeometry(ms_pMaskAtomic); RwTexCoords *maskTexCoords = RpGeometryGetVertexTexCoords(maskGeometry, rwTEXTURECOORDINATEINDEX0); RwRGBA *maskPreLight = RpGeometryGetPreLightColors(maskGeometry); RpMorphTarget *maskMorph = RpGeometryGetMorphTarget(maskGeometry, 0); RwV3d *maskMorphVerts = RpMorphTargetGetVertices(maskMorph); RwV3d *maskMorphNormals = RpMorphTargetGetVertexNormals(maskMorph); if ( !m_bRenderSeaBed ) RpGeometryLock(maskGeometry, rpGEOMETRYLOCKVERTICES | rpGEOMETRYLOCKNORMALS | rpGEOMETRYLOCKPRELIGHT | rpGEOMETRYLOCKTEXCOORDS); float fMinSparkZ = (fWave2Ampl * CWeather::WindClipped + 0.05f + 0.4f * CWeather::WindClipped + 0.2) * (1.0f - 0.02f * CWeather::SunGlare); int32 randval = CGeneral::GetRandomNumber() & 255; int16 nX = _RoundValue((int32)((fX - fSectorX) * 0.5f) - 1); int16 nY = _RoundValue((int32)((fY - fSectorY) * 0.5f) - 1); int16 idxX = nX; for ( int32 i = 0; i < 17; i++ ) { int16 idxY = nY; if ( ++idxX > 16 ) idxX -= 16; for ( int32 j = 0; j < 17; j++ ) { if ( ++idxY > 16 ) idxY -= 16; const int32 a = (0*16); const int32 b = (1*16); const int32 c = (33*16); const int32 d = (34*16); int32 base = (i*33+j); maskTexCoords[base+a].v = float(j) / 32 + ((fCamPosY - fY) / 64); maskTexCoords[base+c].v = maskTexCoords[base+a].v; maskTexCoords[base+d].v = maskTexCoords[base+a].v + 0.5f; maskTexCoords[base+b].v = maskTexCoords[base+d].v; maskTexCoords[base+a].u = float(i) / 32 + ((fCamPosX - fX) / 64); maskTexCoords[base+b].u = maskTexCoords[base+a].u; maskTexCoords[base+d].u = maskTexCoords[base+a].u + 0.5f; maskTexCoords[base+c].u = maskTexCoords[base+d].u; maskMorphVerts[base+a].x = (wavyMorphVerts[idxY + (17 * idxX)].x - (float)idxX * 2.0f) + (float(i) * 2.0f); maskMorphVerts[base+b].x = maskMorphVerts[base+a].x; maskMorphVerts[base+c].x = maskMorphVerts[base+a].x + SMALL_SECTOR_SIZE; maskMorphVerts[base+d].x = maskMorphVerts[base+c].x; maskMorphVerts[base+a].y = (wavyMorphVerts[idxY + (17 * idxX)].y - (float)idxY * 2.0f) + (float(j) * 2.0f); maskMorphVerts[base+c].y = maskMorphVerts[base+a].y; maskMorphVerts[base+b].y = maskMorphVerts[base+a].y + SMALL_SECTOR_SIZE; maskMorphVerts[base+d].y = maskMorphVerts[base+b].y; maskMorphVerts[base+a].z = wavyMorphVerts[idxY + (17 * idxX)].z; maskMorphVerts[base+d].z = maskMorphVerts[base+a].z; maskMorphVerts[base+c].z = maskMorphVerts[base+d].z; maskMorphVerts[base+b].z = maskMorphVerts[base+c].z; if ( maskMorphVerts[base].z > fMinSparkZ ) { switch ( (i + j + randval) & 3 ) { case 0: { CVector vecPos ( fX + maskMorphVerts[base+a].x, fY + maskMorphVerts[base+a].y, fZ + maskMorphVerts[base+a].z + 0.12f ); vecPos -= 0.05f * TheCamera.GetForward(); CParticle::AddParticle(PARTICLE_WATER_SPARK, vecPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 15, CGeneral::GetRandomNumberInRange(-90, 90), 0, 0); } break; case 1: { CVector vecPos ( fX + maskMorphVerts[base+c].x, fY + maskMorphVerts[base+c].y, fZ + maskMorphVerts[base+c].z + 0.12f ); vecPos -= 0.05f * TheCamera.GetForward(); CParticle::AddParticle(PARTICLE_WATER_SPARK, vecPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 15, CGeneral::GetRandomNumberInRange(-90, 90), 0, 0); } break; case 2: { CVector vecPos ( fX + maskMorphVerts[base+b].x, fY + maskMorphVerts[base+b].y, fZ + maskMorphVerts[base+b].z + 0.12f ); vecPos -= 0.05f * TheCamera.GetForward(); CParticle::AddParticle(PARTICLE_WATER_SPARK, vecPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 15, CGeneral::GetRandomNumberInRange(-90, 90), 0, 0); } break; case 3: { CVector vecPos ( fX + maskMorphVerts[base+d].x, fY + maskMorphVerts[base+d].y, fZ + maskMorphVerts[base+d].z + 0.12f ); vecPos -= 0.05f * TheCamera.GetForward(); CParticle::AddParticle(PARTICLE_WATER_SPARK, vecPos, CVector(0.0f, 0.0f, 0.0f), nil, 0.0f, 15, CGeneral::GetRandomNumberInRange(-90, 90), 0, 0); } break; } } maskMorphNormals[base+a].x = wavyMorphNormals[idxY + (17 * idxX)].x; maskMorphNormals[base+a].y = wavyMorphNormals[idxY + (17 * idxX)].y; maskMorphNormals[base+a].z = wavyMorphNormals[idxY + (17 * idxX)].z; maskMorphNormals[base+d].x = maskMorphNormals[base+a].x; maskMorphNormals[base+d].y = maskMorphNormals[base+a].y; maskMorphNormals[base+d].z = maskMorphNormals[base+a].z; maskMorphNormals[base+c].x = maskMorphNormals[base+d].x; maskMorphNormals[base+c].y = maskMorphNormals[base+d].y; maskMorphNormals[base+c].z = maskMorphNormals[base+d].z; maskMorphNormals[base+b].x = maskMorphNormals[base+c].x; maskMorphNormals[base+b].y = maskMorphNormals[base+c].y; maskMorphNormals[base+b].z = maskMorphNormals[base+c].z; maskPreLight[base+a].red = color.red; maskPreLight[base+a].green = color.green; maskPreLight[base+a].blue = color.blue; maskPreLight[base+a].alpha = color.alpha; maskPreLight[base+d].red = maskPreLight[base+a].red; maskPreLight[base+d].green = maskPreLight[base+a].green; maskPreLight[base+d].blue = maskPreLight[base+a].blue; maskPreLight[base+d].alpha = maskPreLight[base+a].alpha; maskPreLight[base+c].red = maskPreLight[base+d].red; maskPreLight[base+c].green = maskPreLight[base+d].green; maskPreLight[base+c].blue = maskPreLight[base+d].blue; maskPreLight[base+c].alpha = maskPreLight[base+d].alpha; maskPreLight[base+b].red = maskPreLight[base+c].red; maskPreLight[base+b].green = maskPreLight[base+c].green; maskPreLight[base+b].blue = maskPreLight[base+c].blue; maskPreLight[base+b].alpha = maskPreLight[base+c].alpha; } } RpGeometryUnlock(maskGeometry); return true; } #endif void CWaterLevel::RenderBoatWakes(void) { RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)gpWaterWakeRaster); #ifndef PC_WATER RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE); RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); #endif #ifdef _XBOX // TODO save and restore rwRENDERSTATESRCBLEND rwRENDERSTATEDESTBLEND #endif CBoat::FillBoatList(); float fWakeZ = 5.97f; float fWakeLifeTimeMult = 0.01f / CBoat::WAKE_LIFETIME; for ( int32 idx = 0; idx < ARRAY_SIZE(CBoat::apFrameWakeGeneratingBoats); idx++ ) { CBoat *pBoat = CBoat::apFrameWakeGeneratingBoats[idx]; if ( pBoat == nil ) break; CVector2D vecDistA(pBoat->GetForward().x, pBoat->GetForward().y); float fSize = pBoat->GetColModel()->boundingBox.max.z * 0.65f; if ( pBoat->GetModelIndex() == MI_SKIMMER) fSize *= 0.4f; float fAplhaA = 255.0f; float fSizeA = fSize; float fAplhaB; float fSizeB; for ( int32 wake = 1; wake < pBoat->m_nNumWakePoints; wake++ ) { bool bRender = true; float fTimeleft = CBoat::WAKE_LIFETIME - pBoat->m_afWakePointLifeTime[wake]; float fWakeSizeB = ((float)wake * 0.19f) + fSize - fWakeLifeTimeMult * Max(fTimeleft, 0.0f); fSizeB = fWakeSizeB / CBoat::MIN_WAKE_INTERVAL; if ( fSizeB < 0.0f ) fSizeB = 1.0f; if ( wake == pBoat->m_nNumWakePoints - 1 ) { // set alpha to 0 if it's last point fAplhaB = 0.0f; } else { // clip (-100, 500), less lifetime - less val float val = 500.0f - (CBoat::WAKE_LIFETIME - pBoat->m_afWakePointLifeTime[wake]) * 600.0f / CBoat::WAKE_LIFETIME; fAplhaB = clamp(val, 0.0f, 255.0f); } CVector2D vecDistB = pBoat->m_avec2dWakePoints[wake - 1] - pBoat->m_avec2dWakePoints[wake]; float fScal = vecDistB.MagnitudeSqr(); // normalize if distance between points is greater than 3 if ( fScal > SQR(3.0f) ) { float fNorm = 1.0f / sqrt(fScal); vecDistB.x *= fNorm; vecDistB.y *= fNorm; // disable render if distance between points too big if ( sqrt(fScal) > 13.0f ) bRender = false; } CVector2D vecAA ( pBoat->m_avec2dWakePoints[wake - 1].x - (fSizeA * vecDistA.y), pBoat->m_avec2dWakePoints[wake - 1].y + (fSizeA * vecDistA.x) ); CVector2D vecAB ( pBoat->m_avec2dWakePoints[wake - 1].x + (fSizeA * vecDistA.y), pBoat->m_avec2dWakePoints[wake - 1].y - (fSizeA * vecDistA.x) ); CVector2D vecBA ( pBoat->m_avec2dWakePoints[wake].x + (fSizeB * vecDistB.y), pBoat->m_avec2dWakePoints[wake].y - (fSizeB * vecDistB.x) ); CVector2D vecBB ( pBoat->m_avec2dWakePoints[wake].x - (fSizeB * vecDistB.y), pBoat->m_avec2dWakePoints[wake].y + (fSizeB * vecDistB.x) ); if ( bRender ) RenderWakeSegment(vecAA, vecAB, vecBA, vecBB, fSizeA, fSizeB, fAplhaA, fAplhaB, fWakeZ); vecDistA = vecDistB; fSizeA = fSizeB; fAplhaB = fAplhaA; } } RenderAndEmptyRenderBuffer(); } inline float _GetWindedWave(float fX, float fY) { float fAngle = (CTimer::GetTimeInMilliseconds() & 4095) * (TWOPI / 4096.0f); float x = WATER_HUGE_X(fX + WATER_X_OFFSET); float y = WATER_HUGE_Y(fY); float fWindFactor (CWeather::WindClipped * 0.4f + 0.2f); float fWave = Sin(( (x - Floor(x)) + (y - Floor(y)) ) * TWOPI + fAngle); return fWindFactor * fWave; } void CWaterLevel::RenderWakeSegment(CVector2D &vecA, CVector2D &vecB, CVector2D &vecC, CVector2D &vecD, float &fSizeA, float &fSizeB, float &fAlphaA, float &fAlphaB, float &fWakeZ) { for ( int32 i = 0; i < 4; i++ ) { if ( TempBufferIndicesStored >= TEMPBUFFERINDEXSIZE-6 || TempBufferVerticesStored >= TEMPBUFFERVERTSIZE-4 ) RenderAndEmptyRenderBuffer(); float fCurStep = (float)i / 4; float fNxtStep = (float)(i + 1) / 4; float fLeftCurStep = 1.0f - fCurStep; float fLeftNxtStep = 1.0f - fNxtStep; uint8 AlphaA = (uint32)(fAlphaA * aAlphaFade[i] ); uint8 AlphaB = (uint32)(fAlphaA * aAlphaFade[i + 1]); uint8 AlphaC = (uint32)(fAlphaB * aAlphaFade[i + 1]); uint8 AlphaD = (uint32)(fAlphaB * aAlphaFade[i] ); CVector2D PosA = vecB*fCurStep + vecA*fLeftCurStep; CVector2D PosB = vecB*fNxtStep + vecA*fLeftNxtStep; CVector2D PosC = vecC*fNxtStep + vecD*fLeftNxtStep; CVector2D PosD = vecC*fCurStep + vecD*fLeftCurStep; float fUA = (PosA.x / 4) + _TEXTURE_WAKE_ADDU; float fVA = (PosA.y / 4) + _TEXTURE_WAKE_ADDV; float fUB = (PosB.x / 4) + _TEXTURE_WAKE_ADDU; float fVB = (PosB.y / 4) + _TEXTURE_WAKE_ADDV; float fUC = (PosC.x / 4) + _TEXTURE_WAKE_ADDU; float fVC = (PosC.y / 4) + _TEXTURE_WAKE_ADDV; float fUD = (PosD.x / 4) + _TEXTURE_WAKE_ADDU; float fVD = (PosD.y / 4) + _TEXTURE_WAKE_ADDV; #define MIN4(a, b, c, d) (Min((a), Min((b), Min((c), (d))))) float fMinU = Floor(MIN4(fUA, fUB, fUC, fUD)); float fMinV = Floor(MIN4(fVA, fVB, fVC, fVD)); #undef MIN4 float fZA = _GetWindedWave(PosA.x, PosA.y) + fWakeZ; float fZB = _GetWindedWave(PosB.x, PosB.y) + fWakeZ; float fZC = _GetWindedWave(PosC.x, PosC.y) + fWakeZ; float fZD = _GetWindedWave(PosD.x, PosD.y) + fWakeZ; int32 vidx = TempBufferVerticesStored; RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 0], PosA.x, PosA.y, fZA); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 0], fUA - fMinU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 0], fVA - fMinV); RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 0], 255, 255, 255, AlphaA); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 1], PosB.x, PosB.y, fZB); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 1], fUB - fMinU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 1], fVB - fMinV); RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 1], 255, 255, 255, AlphaB); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 2], PosC.x, PosC.y, fZC); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 2], fUC - fMinU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 2], fVC - fMinV); RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 2], 255, 255, 255, AlphaC); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 3], PosD.x, PosD.y, fZD); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 3], fUD - fMinU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 3], fVD - fMinV); RwIm3DVertexSetRGBA (&TempBufferRenderVertices[vidx + 3], 255, 255, 255, AlphaD); 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::RenderOneSlopedUnderWaterPoly(float fX, float fY, float fZ, RwRGBA const&color) { CVector2D camPos(TheCamera.GetPosition().x, TheCamera.GetPosition().y); float fDistA = (CVector2D(fX, fY) - camPos).Magnitude() + -140.0f; float fDistB = (CVector2D(fX, fY + HUGE_SECTOR_SIZE) - camPos).Magnitude() + -140.0f; float fDistC = (CVector2D(fX + HUGE_SECTOR_SIZE, fY + HUGE_SECTOR_SIZE) - camPos).Magnitude() + -140.0f; float fDistD = (CVector2D(fX + HUGE_SECTOR_SIZE, fY) - camPos).Magnitude() + -140.0f; #ifndef PC_WATER #define CALCSEABED(v, d) \ { \ if ( d < 0.0f ) \ v = 0.1f + fSeaBedZ; \ else if ( d > 240.0f ) \ v = 0.1f; \ else \ v = 0.1f + ((fSeaBedZ * (240.0f - d)) / 240.0f); \ } #else #define CALCSEABED(v, d) \ { \ v = 0.1f; \ if ( d < 0.0f ) \ v += fSeaBedZ; \ else if ( d <= 240.0f ) \ v += (fSeaBedZ / 240.0f) * (240.0f - d); \ } #endif float fSeaBedA, fSeaBedB, fSeaBedC, fSeaBedD; CALCSEABED(fSeaBedA, fDistA); CALCSEABED(fSeaBedB, fDistB); CALCSEABED(fSeaBedC, fDistC); CALCSEABED(fSeaBedD, fDistD); #undef CALCSEABED if ( TempBufferIndicesStored >= TEMPBUFFERINDEXSIZE-6 || TempBufferVerticesStored >= TEMPBUFFERVERTSIZE-4 ) RenderAndEmptyRenderBuffer(); int32 vidx = TempBufferVerticesStored; RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 0], fX, fY, fZ - _fWaterZOffset - fSeaBedA); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 0], 0.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 0], 0.0f); RwIm3DVertexSetRGBA(&TempBufferRenderVertices[vidx + 0], color.red, color.green, color.blue, 255); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 1], fX, fY + HUGE_SECTOR_SIZE, fZ - _fWaterZOffset - fSeaBedB); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 1], 0.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 1], 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 - _fWaterZOffset - fSeaBedC); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 2], 4.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 2], 4.0f); RwIm3DVertexSetRGBA(&TempBufferRenderVertices[vidx + 2], color.red, color.green, color.blue, 255); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 3], fX + HUGE_SECTOR_SIZE, fY, fZ - _fWaterZOffset - fSeaBedD); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 3], 4.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 3], 0.0f); 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::RenderOneFlatSmallWaterPolyBlended(float fX, float fY, float fZ, float fCamX, float fCamY, RwRGBA const &color, RwRGBA const &colorTrans, float fDrawDist) { if ( TempBufferIndicesStored >= TEMPBUFFERINDEXSIZE-6 || TempBufferVerticesStored >= TEMPBUFFERVERTSIZE-4 ) RenderAndEmptyRenderBuffer(); int32 vidx = TempBufferVerticesStored; float fBlendDrawDist = fDrawDist + fStartBlendDistanceAdd; float fDistStartX = SQR(fX - fCamX); float fDistStartY = SQR(fY - fCamY); float fDistEndX = SQR((fX + SMALL_SECTOR_SIZE) - fCamX); float fDistEndY = SQR((fY + SMALL_SECTOR_SIZE) - fCamY); float fAlphaBlendMulA = Min(fFlatWaterBlendRange * Max(sqrt(fDistStartX + fDistStartY) - fBlendDrawDist, fMinWaterAlphaMult), 1.0f); float fAlphaBlendMulB = Min(fFlatWaterBlendRange * Max(sqrt(fDistStartX + fDistEndY ) - fBlendDrawDist, fMinWaterAlphaMult), 1.0f); float fAlphaBlendMulC = Min(fFlatWaterBlendRange * Max(sqrt(fDistEndX + fDistEndY ) - fBlendDrawDist, fMinWaterAlphaMult), 1.0f); float fAlphaBlendMulD = Min(fFlatWaterBlendRange * Max(sqrt(fDistEndX + fDistStartY) - fBlendDrawDist, fMinWaterAlphaMult), 1.0f); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 0], fX, fY, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 0], TEXTURE_ADDV); RwIm3DVertexSetRGBA(&TempBufferRenderVertices[vidx + 0], color.red, color.green, color.blue, (colorTrans.alpha + (color.alpha - colorTrans.alpha) * (uint8)(int32)fAlphaBlendMulA)); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 1], fX, fY + SMALL_SECTOR_SIZE, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDU); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 1], TEXTURE_ADDV + 1.0f); RwIm3DVertexSetRGBA(&TempBufferRenderVertices[vidx + 1], color.red, color.green, color.blue, (colorTrans.alpha + (color.alpha - colorTrans.alpha) * (uint8)(int32)fAlphaBlendMulB)); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 2], fX + SMALL_SECTOR_SIZE, fY + SMALL_SECTOR_SIZE, fZ - _fWaterZOffset); 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, (colorTrans.alpha + (color.alpha - colorTrans.alpha) * (uint8)(int32)fAlphaBlendMulC)); RwIm3DVertexSetPos (&TempBufferRenderVertices[vidx + 3], fX + SMALL_SECTOR_SIZE, fY, fZ - _fWaterZOffset); RwIm3DVertexSetU (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDU + 1.0f); RwIm3DVertexSetV (&TempBufferRenderVertices[vidx + 3], TEXTURE_ADDV); RwIm3DVertexSetRGBA(&TempBufferRenderVertices[vidx + 3], color.red, color.green, color.blue, (colorTrans.alpha + (color.alpha - colorTrans.alpha) * (uint8)(int32)fAlphaBlendMulD)); 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; } float CWaterLevel::CalcDistanceToWater(float fX, float fY) { const float fSectorMaxRenderDist = 250.0f; int32 nStartX = WATER_TO_SMALL_SECTOR_X(fX - fSectorMaxRenderDist + WATER_X_OFFSET) - 1; int32 nEndX = WATER_TO_SMALL_SECTOR_X(fX + fSectorMaxRenderDist + WATER_X_OFFSET) + 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] >= 0 ) { float fSectorX = WATER_FROM_SMALL_SECTOR_X(x) - WATER_X_OFFSET; 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, nil, rwIM3D_VERTEXUV) ) { RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored); RwIm3DEnd(); } } TempBufferIndicesStored = 0; TempBufferVerticesStored = 0; } bool CWaterLevel::GetGroundLevel(CVector const &vecPosn, float *pfOutLevel, ColData *pData, float fDistance) { CColPoint point; CEntity *entity; if ( !CWorld::ProcessVerticalLine(vecPosn + CVector(0.0f, 0.0f, fDistance), -fDistance, point, entity, true, false, false, false, true, false, nil) ) return false; *pfOutLevel = point.point.z; if ( pData != nil ) { pData->SurfaceType = point.surfaceB; pData->PieceType = point.pieceB; } return true; } bool CWaterLevel::IsLocationOutOfWorldBounds_WS(CVector const &vecPosn, int nOffset) { int32 x = int32((vecPosn.x / 50.0f) + 48.0f); int32 y = int32((vecPosn.y / 50.0f) + 40.0f); return x < nOffset || x >= 80 - nOffset || y < nOffset || y >= 80 - nOffset; } bool CWaterLevel::GetGroundLevel_WS(CVector const &vecPosn, float *pfOutLevel, ColData *pData, float fDistance) { if ( IsLocationOutOfWorldBounds_WS(vecPosn, 0) ) return false; else return GetGroundLevel(vecPosn, pfOutLevel, pData, fDistance); } bool CWaterLevel::GetWaterDepth(CVector const &vecPosn, float *pfDepth, float *pfLevelNoWaves, float *pfGroundLevel) { float fLevelNoWaves; float fGroundLevel; if ( !GetWaterLevelNoWaves(vecPosn.x, vecPosn.y, vecPosn.z, &fLevelNoWaves) ) return false; if ( !GetGroundLevel(vecPosn, &fGroundLevel, nil, 30.0f) ) fGroundLevel = -100.0; if ( pfDepth != nil ) *pfDepth = fLevelNoWaves - fGroundLevel; if ( pfLevelNoWaves != nil ) *pfLevelNoWaves = fLevelNoWaves; if ( pfGroundLevel != nil ) *pfGroundLevel = fGroundLevel; return true; } void CWaterLevel::RenderSeaBirds() { CVector cur_pos = TheCamera.GetPosition(); if ( !CCullZones::CamNoRain() && !CCullZones::PlayerNoRain() && (CWeather::NewWeatherType == WEATHER_SUNNY || CWeather::NewWeatherType == WEATHER_EXTRA_SUNNY) && CClock::ms_nGameClockHours > 6 && CClock::ms_nGameClockHours < 20 ) { static CVector prev_pos(0.0f, 0.0f, 0.0f); static CVector prev_front(0.0f, 0.0f, 0.0f); static int32 timecounter; if ( Abs(prev_pos.x - cur_pos.x) + Abs(prev_pos.y - cur_pos.y) + Abs(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); uint16 nSinCosIdx = CGeneral::GetRandomNumber() % (CParticle::SIN_COS_TABLE_SIZE-1); float fCos = CParticle::Cos(nSinCosIdx); float fSin = CParticle::Sin(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, nil, 0.0f, 0, 0, 0, 0); } } } } void CWaterLevel::RenderShipsOnHorizon() { #ifdef FIX_BUGS CVector cur_pos = FindPlayerCoors(); #else CVector cur_pos = FindPlayerPed()->GetPosition(); #endif static CVector prev_pos(0.0f, 0.0f, 0.0f); static CVector prev_front(0.0f, 0.0f, 0.0f); static int32 timecounter; if ( Abs(prev_pos.x - cur_pos.x) + Abs(prev_pos.y - cur_pos.y) + Abs(prev_pos.z - cur_pos.z) > 1.5f ) { prev_pos = cur_pos; timecounter = CTimer::GetTimeInMilliseconds(); } else if ( (CTimer::GetTimeInMilliseconds() - timecounter) > 5000 ) { static int32 shipgenTime = 0; if ( (CTimer::GetTimeInMilliseconds() - shipgenTime) > 4000 ) { shipgenTime = CTimer::GetTimeInMilliseconds(); CVector vecPos = cur_pos; float fAngle = CGeneral::GetRandomNumberInRange(450.0f, 750.0f); uint16 nSinCosIdx = CGeneral::GetRandomNumber() % (CParticle::SIN_COS_TABLE_SIZE-1); float fCos = CParticle::Cos(nSinCosIdx); float fSin = CParticle::Sin(nSinCosIdx); vecPos.x += (fCos - fSin) * fAngle; vecPos.y += (fSin + fCos) * fAngle; float fLevelNoWaves; if ( GetWaterLevelNoWaves(vecPos.x, vecPos.y, vecPos.z, &fLevelNoWaves) ) { if ( IsLocationOutOfWorldBounds_WS(vecPos, 1) ) { vecPos.z = fLevelNoWaves + 9.5f; CVector vecDir ( CGeneral::GetRandomNumberInRange(-0.1f, 0.1f), 0.0f, 0.0f ); CParticle::AddParticle(PARTICLE_SHIP_SIDE, vecPos, vecDir, nil, 0.0f, 0, 0, CGeneral::GetRandomNumber() & 7, 0); } } } } } void CWaterLevel::HandleSeaLifeForms() { if ( CReplay::IsPlayingBack() ) return; CVector cur_pos = FindPlayerPed()->GetPosition(); static CVector prev_pos(0.0f, 0.0f, 0.0f); static int32 timecounter; if ( Abs(prev_pos.x - cur_pos.x) + Abs(prev_pos.y - cur_pos.y) + Abs(prev_pos.z - cur_pos.z) > 1.5f ) { prev_pos = cur_pos; timecounter = CTimer::GetTimeInMilliseconds(); } else if ( (CTimer::GetTimeInMilliseconds() - timecounter) > 5000 ) { if ( CWaterCreatures::IsSpaceForMoreWaterCreatures() ) { for ( int32 i = 0; i < 3; i++ ) { CVector vecPos = cur_pos; float fAngle = CGeneral::GetRandomNumberInRange(15.0f, 30.0f); uint16 nSinCosIdx = CGeneral::GetRandomNumber() % (CParticle::SIN_COS_TABLE_SIZE-1); float fCos = CParticle::Cos(nSinCosIdx); float fSin = CParticle::Sin(nSinCosIdx); vecPos.x += (fCos - fSin) * fAngle; vecPos.y += (fSin + fCos) * fAngle; CWaterCreatures::CreateOne(vecPos, -1); } } } CWaterCreatures::UpdateAll(); } void CWaterLevel::HandleBeachToysStuff(void) { #ifdef FIX_BUGS CVector cur_pos = FindPlayerCoors(); #else CVector cur_pos = FindPlayerPed()->GetPosition(); #endif static bool bBeachBallInit = true; static CVector FirstBeachBallPos = cur_pos; static bool bLoungeInit = true; static CVector FirstLoungePos = cur_pos; static CVector prev_pos(0.0f, 0.0f, 0.0f); static int32 timecounter; if ( Abs(prev_pos.x - cur_pos.x) + Abs(prev_pos.y - cur_pos.y) + Abs(prev_pos.z - cur_pos.z) > 1.5f ) { prev_pos = cur_pos; timecounter = CTimer::GetTimeInMilliseconds(); } else if ( (CTimer::GetTimeInMilliseconds() - timecounter) > 5000 ) { static int32 toygenTime = CTimer::GetTimeInMilliseconds(); if ( (CTimer::GetTimeInMilliseconds() - toygenTime) > 20000 ) { toygenTime = CTimer::GetTimeInMilliseconds(); if ( bBeachBallInit || (cur_pos - FirstBeachBallPos).MagnitudeSqr() > 6400.0f ) { for ( int32 i = 0; i < 3; i++ ) { CVector vecPos = cur_pos; float fAngle = CGeneral::GetRandomNumberInRange(20.0f, 35.0f); uint16 nSinCosIdx = CGeneral::GetRandomNumber() % (CParticle::SIN_COS_TABLE_SIZE-1); float fCos = CParticle::Cos(nSinCosIdx); float fSin = CParticle::Sin(nSinCosIdx); vecPos.x += (fCos - fSin) * fAngle; vecPos.y += (fSin + fCos) * fAngle; if ( TheCamera.IsSphereVisible(vecPos, 1.0f, &TheCamera.GetCameraMatrix()) ) { float fWaterLevel; if ( !GetWaterLevel(vecPos.x, vecPos.y, vecPos.z, &fWaterLevel, false) ) { float fGroundLevel; ColData coldata; if ( GetGroundLevel(vecPos, &fGroundLevel, &coldata, 30.0f) ) { if ( coldata.SurfaceType == SURFACE_SAND ) { CEntity *toy = CreateBeachToy(vecPos, BEACHTOY_BALL); if ( toy ) { FirstBeachBallPos = cur_pos; bBeachBallInit = false; i = 10; } } } } } } } if ( bLoungeInit || (cur_pos - FirstLoungePos).MagnitudeSqr() > 6400.0f ) { for ( int32 i = 0; i < 5; i++ ) { CVector vecPos = cur_pos; float fAngle = CGeneral::GetRandomNumberInRange(20.0f, 35.0f); uint16 nSinCosIdx = CGeneral::GetRandomNumber() % (CParticle::SIN_COS_TABLE_SIZE-1); float fCos = CParticle::Cos(nSinCosIdx); float fSin = CParticle::Sin(nSinCosIdx); vecPos.x += (fCos - fSin) * fAngle; vecPos.y += (fSin + fCos) * fAngle; if ( TheCamera.IsSphereVisible(vecPos, 2.0f, &TheCamera.GetCameraMatrix()) ) { float fWaterLevel; if ( !GetWaterLevel(vecPos.x, vecPos.y, vecPos.z, &fWaterLevel, false) ) { float fGroundLevel; ColData coldata; if ( GetGroundLevel(vecPos, &fGroundLevel, &coldata, 30.0f) ) { if ( coldata.SurfaceType == SURFACE_SAND ) { CEntity *toy = CreateBeachToy(vecPos, BEACHTOY_ANY_LOUNGE); if ( toy ) { toy->SetHeading(DEGTORAD(CGeneral::GetRandomNumberInRange(0.0f, 359.0f))); FirstLoungePos = cur_pos; bLoungeInit = false; } } } } } } } } } } CEntity * CWaterLevel::CreateBeachToy(CVector const &vec, eBeachToy beachtoy) { if (CObject::nNoTempObjects >= NUMTEMPOBJECTS) return nil; int finalToy = beachtoy; bool isStatic = false; int model = MI_BEACHBALL; switch (beachtoy) { case BEACHTOY_ANY_LOUNGE: switch ( CGeneral::GetRandomNumber() & 7 ) { case 1: case 7: finalToy = BEACHTOY_LOUNGE_WOOD_UP; break; case 3: case 5: finalToy = BEACHTOY_LOUNGE_TOWEL_UP; break; default: finalToy = BEACHTOY_LOUNGE_WOOD_ON; break; } break; case BEACHTOY_ANY_TOWEL: switch ( CGeneral::GetRandomNumber() & 7 ) { case 1: case 7: finalToy = BEACHTOY_TOWEL2; break; case 2: case 6: finalToy = BEACHTOY_TOWEL3; break; case 3: case 5: finalToy = BEACHTOY_TOWEL4; break; default: finalToy = BEACHTOY_TOWEL1; break; } if (CObject::nNoTempObjects >= 35) { return nil; } default: break; } switch (finalToy) { case BEACHTOY_BALL: isStatic = false; model = MI_BEACHBALL; break; case BEACHTOY_LOUNGE_WOOD_UP: isStatic = false; model = MI_LOUNGE_WOOD_UP; break; case BEACHTOY_LOUNGE_TOWEL_UP: isStatic = false; model = MI_LOUNGE_TOWEL_UP; break; case BEACHTOY_LOUNGE_WOOD_ON: isStatic = false; model = MI_LOUNGE_WOOD_DN; break; case BEACHTOY_LOTION: model = MI_LOTION; isStatic = true; break; case BEACHTOY_TOWEL1: model = MI_BEACHTOWEL01; isStatic = true; break; case BEACHTOY_TOWEL2: model = MI_BEACHTOWEL02; isStatic = true; break; case BEACHTOY_TOWEL3: model = MI_BEACHTOWEL03; isStatic = true; break; case BEACHTOY_TOWEL4: model = MI_BEACHTOWEL04; isStatic = true; break; default: break; } CObject *toy = new CObject(model, true); if (toy) { toy->SetPosition(vec); toy->GetMatrix().UpdateRW(); toy->m_vecMoveSpeed = CVector(0.f, 0.f, 0.f); toy->m_vecTurnSpeed = CVector(0.f, 0.f, 0.f); toy->ObjectCreatedBy = TEMP_OBJECT; toy->bIsStatic = isStatic; CObject::nNoTempObjects++; toy->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 43200000; CWorld::Add(toy); return toy; } else return nil; }