472 lines
11 KiB
C++
472 lines
11 KiB
C++
#ifndef _CREOCEAN_H_
|
|
#define _CREOCEAN_H_
|
|
|
|
#include "../nvTriStrip/nvTriStrip.h"
|
|
|
|
struct SREOceanStats
|
|
{
|
|
float m_StatsTimeFFTTable;
|
|
float m_StatsTimeFFT;
|
|
float m_StatsTimeUpdateVerts;
|
|
float m_StatsTimeTexUpdate;
|
|
float m_StatsTimeRendOcean;
|
|
int m_StatsAllocatedSectors;
|
|
int m_StatsNumRendOceanSectors;
|
|
};
|
|
|
|
#define OCEANPI 3.141592654f
|
|
#define OCEANGRID 64
|
|
#define LOG_OCEANGRID 6
|
|
|
|
#define NUM_LODS 5
|
|
#define LOD_MASK 7
|
|
#define LOD_LEFTSHIFT 3
|
|
#define LOD_RIGHTSHIFT 4
|
|
#define LOD_TOPSHIFT 5
|
|
#define LOD_BOTTOMSHIFT 6
|
|
|
|
#define OSF_VISIBLE 1
|
|
#define OSF_FIRSTTIME 2
|
|
#define OSF_NEEDHEIGHTS 4
|
|
#define OSF_LODUPDATED 8
|
|
#define OSF_BLEND 0x10
|
|
|
|
#define OVP_NOHEIGHT 0
|
|
#define OVP_NOHEIGHT_SPL 1
|
|
#define OVP_HEIGHT 2
|
|
#define OVP_HEIGHT_SPL 3
|
|
#define NUM_OVP 4
|
|
|
|
#define NUM_OCEANVBS 8
|
|
|
|
struct SOceanSector
|
|
{
|
|
float x, y;
|
|
int RenderState;
|
|
int nLod;
|
|
int m_Frame;
|
|
int m_Flags;
|
|
|
|
SOceanSector ()
|
|
{
|
|
m_Flags = OSF_FIRSTTIME;
|
|
m_Frame = -1;
|
|
}
|
|
};
|
|
|
|
struct SOceanIndicies
|
|
{
|
|
float m_fLastAccess;
|
|
int m_nInds;
|
|
ushort *m_pIndicies;
|
|
TArray<SPrimitiveGroup> m_Groups;
|
|
};
|
|
|
|
/**
|
|
* A random number class. It implements the <em>mersenne twister</em> algorithm to produce
|
|
* "high quality" pseudo random numbers.
|
|
*/
|
|
class CRERandom
|
|
{
|
|
public:
|
|
enum EMersenneTwisterInitialSeed
|
|
{
|
|
INITIAL_SEED = 4357U
|
|
};
|
|
|
|
public:
|
|
CRERandom( unsigned long ulSeed = INITIAL_SEED ) : m_ulIndex( 0 )
|
|
{
|
|
SetSeed( ulSeed );
|
|
}
|
|
|
|
~CRERandom() {};
|
|
|
|
void SetSeed( unsigned long ulSeed )
|
|
{
|
|
m_ulState[ 0 ] = ( ulSeed | 1 ) & 0xFFFFFFFFU;
|
|
for( m_ulIndex = 1; m_ulIndex < N; ++m_ulIndex )
|
|
{
|
|
m_ulState[ m_ulIndex ] = ( m_ulState[ m_ulIndex - 1 ] * GENERATOR ) & 0xFFFFFFFFU;
|
|
}
|
|
}
|
|
|
|
unsigned long GetInteger()
|
|
{
|
|
if( N == m_ulIndex )
|
|
{
|
|
Reload();
|
|
}
|
|
|
|
unsigned long ulY = m_ulState[ m_ulIndex++ ];
|
|
ulY ^= TemperingShiftU( ulY );
|
|
ulY ^= TemperingShiftS( ulY ) & TEMPERING_MASK_B;
|
|
ulY ^= TemperingShiftT( ulY ) & TEMPERING_MASK_C;
|
|
ulY ^= TemperingShiftL( ulY );
|
|
|
|
return( ulY );
|
|
}
|
|
|
|
double Get()
|
|
{
|
|
return( GetInteger() * (double) 2.3283064365386963e-10 ); // i.e. GetInteger() / 2^32
|
|
}
|
|
|
|
double GetInRange( double dLower = 0.0, double dUpper = 1.0 )
|
|
{
|
|
return( dLower + Get() * ( dUpper - dLower ) );
|
|
}
|
|
|
|
double GetGauss( double dMean = 0.0, double dStdDeviation = 1.0 )
|
|
{
|
|
double dX1;
|
|
double dX2;
|
|
double dW;
|
|
|
|
// perform box muller test
|
|
do
|
|
{
|
|
dX1 = 2.0 * Get() - 1.0;
|
|
dX2 = 2.0 * Get() - 1.0;
|
|
dW = dX1 * dX1 + dX2 * dX2;
|
|
} while( dW >= 1.0 );
|
|
|
|
dW = sqrt_tpl( -2.0f * log_tpl( dW ) / dW );
|
|
dX1 *= dW;
|
|
|
|
return( dMean + dX1 * dStdDeviation );
|
|
}
|
|
|
|
private:
|
|
enum EMersenneTwisterConstants
|
|
{
|
|
GENERATOR = 69069U,
|
|
|
|
N = 624U,
|
|
M = 397U,
|
|
|
|
MATRIX_A = 0x9908B0DFU,
|
|
UPPER_MASK = 0x80000000U,
|
|
LOWER_MASK = 0x7FFFFFFFU,
|
|
|
|
TEMPERING_MASK_B = 0x9D2C5680U,
|
|
TEMPERING_MASK_C = 0xEFC60000U
|
|
};
|
|
|
|
void Reload()
|
|
{
|
|
const unsigned long c_ulMag01[ 2 ] = { 0x0, MATRIX_A };
|
|
|
|
unsigned long ulY;
|
|
for( m_ulIndex = 0; m_ulIndex < N - M; ++m_ulIndex )
|
|
{
|
|
ulY = ( m_ulState[ m_ulIndex ] & UPPER_MASK ) |
|
|
( m_ulState[ m_ulIndex + 1 ] & LOWER_MASK );
|
|
|
|
m_ulState[ m_ulIndex ] = m_ulState[ m_ulIndex + M ] ^ ( ulY >> 1 ) ^ c_ulMag01[ ulY & 0x1 ];
|
|
}
|
|
|
|
for( ; m_ulIndex < N - 1; ++m_ulIndex)
|
|
{
|
|
ulY = ( m_ulState[ m_ulIndex ] & UPPER_MASK ) |
|
|
( m_ulState[ m_ulIndex + 1 ] & LOWER_MASK );
|
|
|
|
m_ulState[ m_ulIndex ] = m_ulState[ m_ulIndex + ( M - N ) ] ^ ( ulY >> 1 ) ^ c_ulMag01[ ulY & 0x1 ];
|
|
}
|
|
|
|
ulY = ( m_ulState[ N - 1 ] & UPPER_MASK ) | ( m_ulState[ 0 ] & LOWER_MASK );
|
|
m_ulState[ N - 1 ] = m_ulState[ M - 1 ] ^ ( ulY >> 1 ) ^ c_ulMag01[ ulY & 0x1 ];
|
|
|
|
m_ulIndex = 0;
|
|
}
|
|
|
|
unsigned long TemperingShiftU( unsigned long ulX )
|
|
{
|
|
return( ulX >> 11 );
|
|
}
|
|
|
|
unsigned long TemperingShiftS( unsigned long ulX )
|
|
{
|
|
return( ulX << 7 );
|
|
}
|
|
|
|
unsigned long TemperingShiftT( unsigned long ulX )
|
|
{
|
|
return( ulX << 15 );
|
|
}
|
|
|
|
unsigned long TemperingShiftL( unsigned long ulX )
|
|
{
|
|
return( ulX >> 18 );
|
|
}
|
|
|
|
private:
|
|
unsigned long m_ulIndex;
|
|
|
|
unsigned long m_ulState[ N ];
|
|
};
|
|
|
|
//=============================================================================
|
|
|
|
class CREOcean : public CRendElement
|
|
{
|
|
friend class CRender3D;
|
|
friend class CGLRenderer;
|
|
friend class CD3D9Renderer;
|
|
|
|
public:
|
|
|
|
static CREOcean *m_pStaticOcean;
|
|
CREOcean()
|
|
{
|
|
m_nFrameLoad = 0;
|
|
m_pBuffer = NULL;
|
|
mfSetType(eDATA_Ocean);
|
|
mfUpdateFlags(FCEF_TRANSFORM);
|
|
GenerateGeometry();
|
|
m_pStaticOcean = this;
|
|
}
|
|
|
|
virtual ~CREOcean();
|
|
|
|
public:
|
|
|
|
void GenerateGeometry();
|
|
void GenerateIndices(int nLodCode);
|
|
void DrawOceanSector(SOceanIndicies *oi);
|
|
void SmoothLods_r(SOceanSector *os, float fSize, int minLod);
|
|
void LinkVisSectors(float fSize);
|
|
float GetWaterZElevation(float fX, float fY);
|
|
|
|
void PostLoad( unsigned long ulSeed, float fWindDirection, float fWindSpeed, float fWaveHeight, float fDirectionalDependence, float fChoppyWavesFactor, float fSuppressSmallWavesFactor );
|
|
void Update( float fTime );
|
|
void UpdateTexture(void);
|
|
void PrepareHMap();
|
|
|
|
private:
|
|
int m_nFrameLoad;
|
|
float m_fGravity;
|
|
float m_fDepth;
|
|
|
|
TArray <unsigned short> m_pIndices[NUM_LODS];
|
|
|
|
private:
|
|
float *mfFillAdditionalBuffer(SOceanSector *os, int nSplashes, SSplash *pSplashes[], int& nCurSize, int nLod, float fSize);
|
|
|
|
void FFT(int iDir, float* real, float* imag);
|
|
void FFT2DReal(float cmpX[OCEANGRID][OCEANGRID]);
|
|
void FFT2D(int iDir, float cmpX[OCEANGRID][OCEANGRID], float cmpY[OCEANGRID][OCEANGRID] );
|
|
_inline float sqrf( float x )
|
|
{
|
|
return (x * x);
|
|
}
|
|
|
|
_inline float PhillipsSpectrum( float fKx, float fKy )
|
|
{
|
|
float fKLength = cry_sqrtf(sqrf(fKx) + sqrf(fKy));
|
|
|
|
if( fKLength < 1e-8f )
|
|
fKLength = 1e-8f;
|
|
|
|
float fScale = 1.0f / fKLength;
|
|
fKx *= fScale;
|
|
fKy *= fScale;
|
|
|
|
return (m_fWaveHeight * cry_expf(-1.0f / sqrf(fKLength * m_fLargestPossibleWave) - sqrf(fKLength * m_fSuppressSmallWaves)) * cry_powf(fKx*m_fWindX + fKy*m_fWindY, m_fDirectionalDependence) / cry_powf(fKLength, 4.0f));
|
|
}
|
|
|
|
_inline int GetHash(float x, float y)
|
|
{
|
|
return (int)(x*0.133f+y*0.356f) & 255;
|
|
}
|
|
|
|
_inline SOceanSector *GetSectorByPos(float x, float y, bool bCreate=true)
|
|
{
|
|
int i;
|
|
|
|
int hash = GetHash(x, y);
|
|
for (i=0; i<m_OceanSectorsHash[hash].Num(); i++)
|
|
{
|
|
SOceanSector *os = &m_OceanSectorsHash[hash][i];
|
|
if (os->x == x && os->y == y)
|
|
return os;
|
|
}
|
|
m_RS.m_StatsAllocatedSectors++;
|
|
SOceanSector os;
|
|
os.x = x;
|
|
os.y = y;
|
|
os.m_Flags |= OSF_FIRSTTIME;
|
|
os.nLod = NUM_LODS-1;
|
|
int n = m_OceanSectorsHash[hash].Num();
|
|
m_OceanSectorsHash[hash].AddElem(os);
|
|
return &m_OceanSectorsHash[hash][n];
|
|
}
|
|
int GetLOD(Vec3d camera, Vec3d pos);
|
|
|
|
private:
|
|
|
|
TArray<SOceanSector> m_OceanSectorsHash[256];
|
|
SOceanIndicies *m_OceanIndicies[1<<(LOD_BOTTOMSHIFT+1)];
|
|
TArray<SOceanSector *> m_VisOceanSectors;
|
|
float m_fSectorSize;
|
|
|
|
TArray<unsigned short> m_DWQIndices;
|
|
TArray<struct_VERTEX_FORMAT_P3F_COL4UB> m_DWQVertices;
|
|
|
|
float m_H0X[OCEANGRID+1][OCEANGRID+1];
|
|
float m_H0Y[OCEANGRID+1][OCEANGRID+1];
|
|
|
|
//static _declspec(align(16)) float m_HX[OCEANGRID][OCEANGRID];
|
|
//static _declspec(align(16)) float m_HY[OCEANGRID][OCEANGRID];
|
|
|
|
//static _declspec(align(16)) float m_NX[OCEANGRID][OCEANGRID];
|
|
//static _declspec(align(16)) float m_NY[OCEANGRID][OCEANGRID];
|
|
|
|
//static _declspec(align(16)) float m_DX[OCEANGRID][OCEANGRID];
|
|
//static _declspec(align(16)) float m_DY[OCEANGRID][OCEANGRID];
|
|
DEFINE_ALIGNED_DATA_STATIC( float, m_HX[OCEANGRID][OCEANGRID], 16 );
|
|
DEFINE_ALIGNED_DATA_STATIC( float, m_HY[OCEANGRID][OCEANGRID], 16 );
|
|
|
|
DEFINE_ALIGNED_DATA_STATIC( float, m_NX[OCEANGRID][OCEANGRID], 16 );
|
|
DEFINE_ALIGNED_DATA_STATIC( float, m_NY[OCEANGRID][OCEANGRID], 16 );
|
|
|
|
DEFINE_ALIGNED_DATA_STATIC( float, m_DX[OCEANGRID][OCEANGRID], 16 );
|
|
DEFINE_ALIGNED_DATA_STATIC( float, m_DY[OCEANGRID][OCEANGRID], 16 );
|
|
|
|
vec2_t m_Pos[OCEANGRID+1][OCEANGRID+1];
|
|
Vec3d m_Normals[OCEANGRID+1][OCEANGRID+1];
|
|
|
|
float m_aAngularFreq[OCEANGRID][OCEANGRID];
|
|
float m_aKScale[OCEANGRID][OCEANGRID];
|
|
|
|
float m_fWindX;
|
|
float m_fWindY;
|
|
float m_fWindSpeed;
|
|
float m_fSpeed;
|
|
float m_fLargestPossibleWave;
|
|
float m_fSuppressSmallWaves;
|
|
float m_fWaveHeight;
|
|
float m_fDirectionalDependence;
|
|
float m_fChoppyWaveFactor;
|
|
float m_fSuppressSmallWavesFactor;
|
|
|
|
CVertexBuffer *m_pBuffer;
|
|
|
|
Vec3d m_MinBound;
|
|
Vec3d m_MaxBound;
|
|
|
|
//===========================================================================
|
|
|
|
_inline float GetHMap(float x, float y)
|
|
{
|
|
float dDownLandZ;
|
|
|
|
if( x<-m_fExpandHM || y<-m_fExpandHM || x>=m_fTerrainSize+m_fExpandHM || y>=m_fTerrainSize+m_fExpandHM)
|
|
dDownLandZ = 0;
|
|
else
|
|
{
|
|
// convert into hmap space
|
|
x *= m_fInvHMUnitSize;
|
|
y *= m_fInvHMUnitSize;
|
|
|
|
x += m_fExpandHMap;
|
|
y += m_fExpandHMap;
|
|
|
|
long nX = QInt(x);
|
|
long nY = QInt(y);
|
|
long nX1 = (nX+1 >= m_nHMapSize) ? nX : nX+1;
|
|
long nY1 = (nY+1 >= m_nHMapSize) ? nY : nY+1;
|
|
|
|
float dx = x - nX;
|
|
float dy = y - nY;
|
|
|
|
float dDownLandZ0 = (1.0f-dx) * m_HMap[nX*m_nHMapSize+nY] + dx * m_HMap[nX1*m_nHMapSize+nY];
|
|
float dDownLandZ1 = (1.0f-dx) * m_HMap[nX*m_nHMapSize+nY1] + dx * m_HMap[nX1*m_nHMapSize+nY1];
|
|
dDownLandZ = (1-dy) * dDownLandZ0 + dy * dDownLandZ1;
|
|
}
|
|
return dDownLandZ;
|
|
}
|
|
|
|
public:
|
|
#if !defined(PS2) && !defined (GC)
|
|
CVProgram * m_VPs[NUM_OVP];
|
|
CVProgram * m_VPQ;
|
|
#endif
|
|
void *m_pVertsPool[NUM_OCEANVBS];
|
|
void *m_VertDecl;
|
|
void *m_VertDeclHeightSplash;
|
|
int m_nCurVB;
|
|
int m_nNumVertsInPool;
|
|
bool m_bLockedVB;
|
|
|
|
float *m_HMap;
|
|
int m_nHMUnitSize;
|
|
float m_fExpandHM;
|
|
float m_fExpandHMap;
|
|
int m_nHMapSize;
|
|
float m_fInvHMUnitSize;
|
|
float m_fTerrainSize;
|
|
|
|
void InitVB();
|
|
struct_VERTEX_FORMAT_TEX2F *GetVBPtr(int nVerts);
|
|
void UnlockVBPtr();
|
|
|
|
void mfDrawOceanSectors();
|
|
void mfDrawOceanScreenLod();
|
|
|
|
public:
|
|
virtual void mfPrepare();
|
|
virtual bool mfDraw(SShader *ef, SShaderPass *sfm);
|
|
virtual bool mfCompile(SShader *ef, char *scr);
|
|
virtual void *mfGetPointer(ESrcPointer ePT, int *Stride, int Type, ESrcPointer Dst, int Flags);
|
|
virtual bool mfPreDraw(SShaderPass *sl);
|
|
virtual void mfReset();
|
|
virtual int Size()
|
|
{
|
|
int i;
|
|
int nSize = sizeof(*this);
|
|
nSize += m_DWQVertices.GetMemoryUsage();
|
|
nSize += m_DWQIndices.GetMemoryUsage();
|
|
|
|
nSize += sizeof(m_Pos);
|
|
nSize += sizeof(m_Normals);
|
|
nSize += m_VisOceanSectors.GetMemoryUsage() + 12;
|
|
for (i=0; i<(1<<(LOD_BOTTOMSHIFT+1)); i++)
|
|
{
|
|
SOceanIndicies *oi = m_OceanIndicies[i];
|
|
if (!oi)
|
|
continue;
|
|
|
|
nSize += sizeof(SOceanIndicies);
|
|
nSize += oi->m_nInds * sizeof(short);
|
|
nSize += oi->m_Groups.GetMemoryUsage();
|
|
}
|
|
for (i=0; i<256; i++)
|
|
{
|
|
nSize += m_OceanSectorsHash[i].GetMemoryUsage()+12;
|
|
}
|
|
// CREOcean::m_HMap array
|
|
nSize += m_nHMapSize * m_nHMapSize * sizeof(float);
|
|
|
|
return nSize;
|
|
}
|
|
|
|
static SREOceanStats m_RS;
|
|
|
|
#ifdef DEBUGALLOC
|
|
#undef new
|
|
#endif
|
|
void* operator new( size_t Size )
|
|
{
|
|
void *ptr = malloc(Size);
|
|
memset(ptr, 0, Size);
|
|
return ptr;
|
|
}
|
|
#ifdef DEBUGALLOC
|
|
#define new DEBUG_CLIENTBLOCK
|
|
#endif
|
|
};
|
|
|
|
|
|
#endif // _CREOCEAN_H_
|