re3/src/render/WaterLevel.cpp
2020-07-22 15:19:22 +03:00

2967 lines
No EOL
92 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "common.h"
#include "main.h"
#include "FileMgr.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 "CdStream.h"
#include "Pad.h"
#include "RenderBuffer.h"
#include <rwcore.h>
#include <rpworld.h>
#include <rpmatfx.h>
#include "Occlusion.h"
#include "Replay.h"
#include "WaterLevel.h"
#include "SurfaceTable.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];
uint8 CWaterLevel::aWaterBlockList[WATER_BLOCK_SECTORS][WATER_BLOCK_SECTORS];
uint8 CWaterLevel::aWaterFineBlockList[WATER_FINEBLOCK_SECTORS][WATER_FINEBLOCK_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 = 0.5f;
#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
WaterLevelInitialise(Const char *pWaterDat)
{
CWaterLevel::ms_nNoOfWaterLevels = 0;
int32 hFile;
do
{
hFile = CFileMgr::OpenFile("DATA\\waterpro.dat", "rb");
}
while ( hFile < 0 );
if ( hFile > 0 )
{
if ( hFile >= 0 )
{
CFileMgr::Read(hFile, (char *)&CWaterLevel::ms_nNoOfWaterLevels, sizeof(CWaterLevel::ms_nNoOfWaterLevels));
CFileMgr::Read(hFile, (char *)CWaterLevel::ms_aWaterZs, sizeof(CWaterLevel::ms_aWaterZs));
CFileMgr::Read(hFile, (char *)CWaterLevel::ms_aWaterRects, sizeof(CWaterLevel::ms_aWaterRects));
CFileMgr::Read(hFile, (char *)CWaterLevel::aWaterBlockList, sizeof(CWaterLevel::aWaterBlockList));
CFileMgr::Read(hFile, (char *)CWaterLevel::aWaterFineBlockList, sizeof(CWaterLevel::aWaterFineBlockList));
}
CFileMgr::CloseFile(hFile);
}
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();
CWaterLevel::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(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
}
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
uint8 nBlock = aWaterFineBlockList[x][y];
if ( nBlock == 0x80 )
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
uint8 nBlock = aWaterFineBlockList[x][y];
if ( nBlock == 0x80 )
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;
//TODO:
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 & 0x80))
return true;
block = CWaterLevel::aWaterFineBlockList[x + 0][y + 1];
if (!(block & 0x80))
{
block = CWaterLevel::aWaterFineBlockList[x + 0][y + 2];
if (!(block & 0x80))
return true;
}
block = CWaterLevel::aWaterFineBlockList[x + 1][y + 0];
if (!(block & 0x80))
return true;
block = CWaterLevel::aWaterFineBlockList[x + 1][y + 1];
if (!(block & 0x80))
{
block = CWaterLevel::aWaterFineBlockList[x + 1][y + 2];
if (!(block & 0x80))
return true;
}
block = CWaterLevel::aWaterFineBlockList[x + 2][y + 0];
if (!(block & 0x80))
return true;
block = CWaterLevel::aWaterFineBlockList[x + 2][y + 1];
if (!(block & 0x80))
{
block = CWaterLevel::aWaterFineBlockList[x + 2][y + 2];
if (!(block & 0x80))
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] & 0x80)
|| !(aWaterBlockList[2*x+1][2*y+0] & 0x80)
|| !(aWaterBlockList[2*x+0][2*y+1] & 0x80)
|| !(aWaterBlockList[2*x+1][2*y+1] & 0x80) )
{
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] & 0x80) )
fZ = ms_aWaterZs[ aWaterBlockList[2*x+0][2*y+0] ];
if ( !(aWaterBlockList[2*x+1][2*y+0] & 0x80) )
fZ = ms_aWaterZs[ aWaterBlockList[2*x+1][2*y+0] ];
if ( !(aWaterBlockList[2*x+0][2*y+1] & 0x80) )
fZ = ms_aWaterZs[ aWaterBlockList[2*x+0][2*y+1] ];
if ( !(aWaterBlockList[2*x+1][2*y+1] & 0x80) )
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 - 400.0f;
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;
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] & 0x80)
|| !(aWaterBlockList[2*x+1][2*y+0] & 0x80)
|| !(aWaterBlockList[2*x+0][2*y+1] & 0x80)
|| !(aWaterBlockList[2*x+1][2*y+1] & 0x80) )
{
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] & 0x80) )
{
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] & 0x80) )
{
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] & 0x80) )
{
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] & 0x80) )
{
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] & 0x80) )
{
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 + 400.0f) + 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) - 400.0f;
float fSectorY = WATER_FROM_SMALL_SECTOR_Y(BlockY);
RenderWavyMask(fMaskX, fMaskY, fWaterZ,
fSectorX, fSectorY,
signX, signY, colorTrans);
}
}
}
DefinedState();
#endif
}
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] & 0x80) )
{
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()
{
CVector cur_pos = FindPlayerPed()->GetPosition();
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 )
{
//TODO(MIAMI)
// 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;
//TODO(MIAMI)
//CWaterCreatures::CreateOne(vecPos, 0xFFFFFFFF);
}
}
}
//TODO(MIAMI)
//CWaterCreatures::UpdateAll();
}
void
CWaterLevel::HandleBeachToysStuff(void)
{
CVector cur_pos = FindPlayerPed()->GetPosition();
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_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)
{
//TODO(MIAMI)
return nil;
}