#include "RenderPCH.h" #include "RendElement.h" #include "CREOcean.h" #include "../NvTriStrip/NVTriStrip.h" #include "I3dengine.h" SREOceanStats CREOcean::m_RS; CREOcean *CREOcean::m_pStaticOcean = NULL; DEFINE_ALIGNED_DATA( float, CREOcean::m_HX[OCEANGRID][OCEANGRID], 16 ); DEFINE_ALIGNED_DATA( float, CREOcean::m_HY[OCEANGRID][OCEANGRID], 16 ); DEFINE_ALIGNED_DATA( float, CREOcean::m_NX[OCEANGRID][OCEANGRID], 16 ); DEFINE_ALIGNED_DATA( float, CREOcean::m_NY[OCEANGRID][OCEANGRID], 16 ); DEFINE_ALIGNED_DATA( float, CREOcean::m_DX[OCEANGRID][OCEANGRID], 16 ); DEFINE_ALIGNED_DATA( float, CREOcean::m_DY[OCEANGRID][OCEANGRID], 16 ); CREOcean::~CREOcean() { m_pStaticOcean = NULL; if (m_pBuffer) { gRenDev->ReleaseBuffer(m_pBuffer); m_pBuffer = NULL; } SAFE_DELETE_ARRAY(m_HMap); for (int i=0; iGetI3DEngine(); float fSize = (float)CRenderer::CV_r_oceansectorsize; float fHeightScale = (float)CRenderer::CV_r_oceanheightscale; float fWaterLevel = eng->GetWaterLevel(); float fHScale = fabsf(gRenDev->m_RP.m_ViewOrg.z-fWaterLevel); float fMaxDist = eng->GetMaxViewDistance() / 1.0f; float fGrid = (float)OCEANGRID; float fZH = GetHMap(fX, fY); if (fZH >= fWaterLevel) return fWaterLevel; float fXPart = fX / fSize; float fYPart = fY / fSize; float fXLerp = (fXPart - (int)fXPart) * fGrid; float fYLerp = (fYPart - (int)fYPart) * fGrid; int nXMin = (int)fXLerp; int nXMax = nXMin+1; int nYMin = (int)fYLerp; int nYMax = nYMin+1; fXLerp = fXLerp - (int)fXLerp; fYLerp = fYLerp - (int)fYLerp; if (fHScale < 5.0f) fHScale = LERP(0.1f, 0.5f, fHScale/5.0f); else if (fHScale < 20) fHScale = LERP(0.5f, 1.0f, (fHScale-5.0f)/15.0f); else fHScale = 1.0f; float fZ00 = -m_HX[nYMin][nXMin] * fHScale; float fZ01 = -m_HX[nYMin][nXMax] * fHScale; float fZ10 = -m_HX[nYMax][nXMin] * fHScale; float fZ11 = -m_HX[nYMax][nXMax] * fHScale; float fZ0 = LERP(fZ00, fZ01, fXLerp); float fZ1 = LERP(fZ10, fZ11, fXLerp); float fZ = LERP(fZ0, fZ1, fYLerp); //fZ *= fHeightScale; float fHeightDelta = fWaterLevel - fZH; fHeightScale *= CLAMP(fHeightDelta * 0.066f, 0, 1); return fZ * fHeightScale + fWaterLevel; } void CREOcean::PrepareHMap() { int nDim=0; I3DEngine *eng = (I3DEngine *)iSystem->GetI3DEngine(); m_nHMUnitSize = eng->GetHeightMapUnitSize(); int nExp = 8; m_fExpandHMap = (float)nExp; m_fExpandHM = (float)m_nHMUnitSize * (float)nExp; m_fInvHMUnitSize = 1.0f / (float)m_nHMUnitSize; m_fTerrainSize = (float)eng->GetTerrainSize(); eng->MakeUnderWaterSmoothHMap(m_nHMUnitSize); ushort *shm = eng->GetUnderWaterSmoothHMap(nDim); if(!nDim) return; // terrain not present float fWaterLevel = eng->GetWaterLevel(); if (m_HMap) delete [] m_HMap; int nDimO = nDim+nExp*2; m_nHMapSize = nDimO; m_HMap = new float [nDimO*nDimO]; float f; for (int y=-nExp; y0 && x0 && y=nDim-1) nX = nDim-2; if (nY<=0) nY = 1; else if (nY>=nDim-1) nY = nDim-2; f = (float)shm[nY*nDim+nX] / 256.0f; if (nX != x) fLerpX = 1.0f - fabsf((float)(nX-x)) / (float)(nExp+1); if (nY != y) fLerpY = 1.0f - fabsf((float)(nY-y)) / (float)(nExp+1); float fX, fY; if (fLerpX >= 0) fX = LERP(fWaterLevel/2.0f, f, fLerpX); if (fLerpY >= 0) fY = LERP(fWaterLevel/2.0f, f, fLerpY); if (fLerpX >= 0 && fLerpY >= 0) m_HMap[(y+nExp)*nDimO+x+nExp] = (fX + fY) / 2.0f; else if (fLerpX >= 0) m_HMap[(y+nExp)*nDimO+x+nExp] = fX; else if (fLerpY >= 0) m_HMap[(y+nExp)*nDimO+x+nExp] = fY; else m_HMap[(y+nExp)*nDimO+x+nExp] = f; } } } } void CREOcean::mfPrepare() { CRenderer *rd = gRenDev; if (m_nFrameLoad != rd->m_nFrameLoad) { m_nFrameLoad = rd->m_nFrameLoad; PrepareHMap(); } rd->EF_CheckOverflow(0, 0, this); Update(rd->m_RP.m_RealTime * m_fSpeed); double time0 = 0; ticks(time0); I3DEngine *eng = (I3DEngine *)iSystem->GetI3DEngine(); float fWaterLevel = eng->GetWaterLevel(); float fHScale = fabsf(gRenDev->m_RP.m_ViewOrg.z-fWaterLevel); if (fHScale < 5.0f) fHScale = LERP(0.1f, 0.5f, fHScale/5.0f); else if (fHScale < 20) fHScale = LERP(0.5f, 1.0f, (fHScale-5.0f)/15.0f); else fHScale = 1.0f; m_MinBound.Set(9999.0f, 9999.0f, 9999.0f); m_MaxBound.Set(-9999.0f, -9999.0f, -9999.0f); if (!m_pBuffer) m_pBuffer = gRenDev->CreateBuffer((OCEANGRID+1)*(OCEANGRID+1), VERTEX_FORMAT_P3F_N, "Ocean", true); rd->UpdateBuffer(m_pBuffer, NULL, 0, 0, 0, 1); static const float fScale = 1.0f / (float)OCEANGRID; struct_VERTEX_FORMAT_P3F_N *pVertices = (struct_VERTEX_FORMAT_P3F_N *)m_pBuffer->m_VS[VSF_GENERAL].m_VData; for(int vy=0; vyxyz.x = m_Pos[vy][vx][0]; pVertices->xyz.y = m_Pos[vy][vx][1]; float fZ = -m_HX[y][x] * fHScale; pVertices->xyz.z = fZ; m_MinBound.x = min(m_Pos[vy][vx][0], m_MinBound.x); m_MinBound.y = min(m_Pos[vy][vx][1], m_MinBound.y); m_MinBound.z = min(fZ, m_MinBound.z); m_MaxBound.x = max(m_Pos[vy][vx][0], m_MaxBound.x); m_MaxBound.y = max(m_Pos[vy][vx][1], m_MaxBound.y); m_MaxBound.z = max(fZ, m_MaxBound.z); m_Normals[vy][vx] = Vec3d(m_NX[y][x], m_NY[y][x], 64.0f); pVertices->normal = m_Normals[vy][vx]; m_Normals[vy][vx].NormalizeFast(); pVertices++; } } unticks(time0); m_RS.m_StatsTimeUpdateVerts = (float)(time0*1000.0*g_SecondsPerCycle); UpdateTexture(); rd->m_RP.m_pRE = this; rd->m_RP.m_RendNumIndices = 0; rd->m_RP.m_RendNumVerts = (OCEANGRID+1)*(OCEANGRID+1); rd->m_RP.m_FirstVertex = 0; } int CREOcean::GetLOD(Vec3d camera, Vec3d pos) { float dist = (pos-camera).GetLength(); dist /= CRenderer::CV_r_oceanloddist; return (int)CLAMP(dist, 0.0f, (float)(NUM_LODS-1)); } void *CREOcean::mfGetPointer(ESrcPointer ePT, int *Stride, int Type, ESrcPointer Dst, int Flags) { switch(ePT) { case eSrcPointer_Vert: { struct_VERTEX_FORMAT_P3F_N *pVertices = (struct_VERTEX_FORMAT_P3F_N *)m_pBuffer->m_VS[VSF_GENERAL].m_VData; *Stride = sizeof(struct_VERTEX_FORMAT_P3F_N); return &pVertices->xyz.x; } case eSrcPointer_Normal: { struct_VERTEX_FORMAT_P3F_N *pVertices = (struct_VERTEX_FORMAT_P3F_N *)m_pBuffer->m_VS[VSF_GENERAL].m_VData; *Stride = sizeof(struct_VERTEX_FORMAT_P3F_N); return &pVertices->normal.x; } } return NULL; } void CREOcean::GenerateGeometry() { m_pBuffer = gRenDev->CreateBuffer((OCEANGRID+1)*(OCEANGRID+1), VERTEX_FORMAT_P3F_N, "Ocean", true); for (int lod=0; lodm_Frame != gRenDev->m_cEF.m_Frame) return; if (os->nLod > minLod+1) { os->nLod = minLod+1; SOceanSector *osLeft; SOceanSector *osRight; SOceanSector *osTop; SOceanSector *osBottom; // Left osLeft = GetSectorByPos(os->x-fSize, os->y, false); // Right osRight = GetSectorByPos(os->x+fSize, os->y, false); // Top osTop = GetSectorByPos(os->x, os->y-fSize, false); // Bottom osBottom = GetSectorByPos(os->x, os->y+fSize, false); if (osLeft) SmoothLods_r(osLeft, fSize, os->nLod); if (osRight) SmoothLods_r(osRight, fSize, os->nLod); if (osTop) SmoothLods_r(osTop, fSize, os->nLod); if (osBottom) SmoothLods_r(osBottom, fSize, os->nLod); } } void CREOcean::LinkVisSectors(float fSize) { for (int i=0; ix-fSize, os->y, false); // Right osRight = GetSectorByPos(os->x+fSize, os->y, false); // Top osTop = GetSectorByPos(os->x, os->y-fSize, false); // Bottom osBottom = GetSectorByPos(os->x, os->y+fSize, false); if (osLeft) SmoothLods_r(osLeft, fSize, os->nLod); if (osRight) SmoothLods_r(osRight, fSize, os->nLod); if (osTop) SmoothLods_r(osTop, fSize, os->nLod); if (osBottom) SmoothLods_r(osBottom, fSize, os->nLod); } } void CREOcean::PostLoad(unsigned long ulSeed, float fWindDirection, float fWindSpeed, float fWaveHeight, float fDirectionalDependence, float fChoppyWavesFactor, float fSuppressSmallWavesFactor) { m_fWindX = cry_cosf( fWindDirection ); m_fWindY = cry_sinf( fWindDirection ); m_fWindSpeed = fWindSpeed; m_fWaveHeight = fWaveHeight; m_fDirectionalDependence = fDirectionalDependence; m_fChoppyWaveFactor = fChoppyWavesFactor; m_fSuppressSmallWavesFactor = fSuppressSmallWavesFactor; m_fLargestPossibleWave = m_fWindSpeed * m_fWindSpeed / m_fGravity; m_fSuppressSmallWaves = m_fLargestPossibleWave * m_fSuppressSmallWavesFactor; // init H0 CRERandom kRnd( ulSeed ); float fOneBySqrtTwo = 1.0f / cry_sqrtf(2.0f); int i, j; for(j=-OCEANGRID/2; j<=OCEANGRID/2; j++) { int y = j + OCEANGRID/2; for(i=-OCEANGRID/2; i<=OCEANGRID/2; i++) { int x = i + OCEANGRID/2; float rndX = (float)kRnd.GetGauss(); float rndY = (float)kRnd.GetGauss(); rndX *= fOneBySqrtTwo * cry_sqrtf(PhillipsSpectrum(2.0f*PI*i, 2.0f*PI*j)); rndY *= fOneBySqrtTwo * cry_sqrtf(PhillipsSpectrum(2.0f*PI*i, 2.0f*PI*j)); m_H0X[y][x] = rndX; m_H0Y[y][x] = rndY; } } // precalc length of K for(j=-OCEANGRID/2; j> 1; j = 0; for( i = 0; i < nn - 1; ++i ) { if( i < j ) { treal = real[ i ]; timag = imag[ i ]; real[ i ] = real[ j ]; imag[ i ] = imag[ j ]; real[ j ] = treal; imag[ j ] = timag; } k = i2; while( k <= j ) { j -= k; k >>= 1; } j += k; } // Compute the FFT c1 = -1.0f; c2 = 0.0f; l2 = 1; for(l=0; lm_RP.m_tSinTable[val&0x3ff]; float fCos = gRenDev->m_RP.m_tSinTable[(val+512)&0x3ff]; int x1 = -i + OCEANGRID/2; int y1 = -j + OCEANGRID/2; float hx = (m_H0X[y][x] + m_H0X[y1][x1]) * fCos - (m_H0Y[y][x] + m_H0Y[y1][x1]) * fSin; float hy = (m_H0X[y][x] - m_H0X[y1][x1]) * fSin + (m_H0Y[y][x] - m_H0Y[y1][x1]) * fCos; int in = i & (OCEANGRID-1); // update height m_HX[jn][in] = hx; m_HY[jn][in] = hy; // update normal float fKx = fK * i; float fKy = fK * j; m_NX[jn][in] = (-hy * fKx - hx * fKy); m_NY[jn][in] = ( hx * fKx - hy * fKy); // update displacement vector for choppy waves fKx *= m_aKScale[y][x]; fKy *= m_aKScale[y][x]; m_DX[jn][in] = ( hy * fKx + hx * fKy); m_DY[jn][in] = (-hx * fKx + hy * fKy); } } unticks(time0); m_RS.m_StatsTimeFFTTable = (float)(time0*1000.0*g_SecondsPerCycle); ticks(time0); FFT2D(-1, m_HX, m_HY); FFT2D(-1, m_NX, m_NY); FFT2D(-1, m_DX, m_DY); unticks(time0); m_RS.m_StatsTimeFFT = (float)(time0*1000.0*g_SecondsPerCycle); } bool CREOcean::mfCompile(SShader *ef, char *scr) { char* name; long cmd; char *params; char *data; enum {eSeed = 1, eSpeed, eGravity, eDepth, eWindSpeed, eWindDirection, eWaveHeight, eDirectionalDependence, eChoppyWaveFactor, eSuppressSmallWavesFactor}; static tokenDesc commands[] = { {eSpeed, "Speed"}, {eGravity, "Gravity"}, {eDepth, "Depth"}, {eWindDirection, "WindDirection"}, {eWindSpeed, "WindSpeed"}, {eWaveHeight, "WaveHeight"}, {eDirectionalDependence, "DirectionalDependence"}, {eChoppyWaveFactor, "ChoppyWaveFactor"}, {eSuppressSmallWavesFactor, "SuppressSmallWavesFactor"}, {0, 0}, }; float fWindDirection = 90.0f; float fWindSpeed = m_fWindSpeed; float fWaveHeight = m_fWaveHeight; float fDirectionalDependence = m_fDirectionalDependence; float fChoppyWaveFactor = m_fChoppyWaveFactor; float fSuppressSmallWavesFactor = m_fSuppressSmallWavesFactor; m_fSpeed = 1.0f; m_fGravity = 9.81f; m_fDepth = 10; while ((cmd = shGetObject (&scr, commands, &name, ¶ms)) > 0) { data = NULL; if (name) data = name; else if (params) data = params; switch (cmd) { case eGravity: if (!data || !data[0]) { Warning( 0,0,"missing Gravity argument for Ocean Effect in Shader '%s'\n", ef->m_Name.c_str()); break; } m_fGravity = shGetFloat(data); break; case eDepth: if (!data || !data[0]) { Warning( 0,0,"missing Depth argument for Ocean Effect in Shader '%s'\n", ef->m_Name.c_str()); break; } m_fDepth = shGetFloat(data); break; case eSpeed: if (!data || !data[0]) { Warning( 0,0,"missing Speed argument for Ocean Effect in Shader '%s'\n", ef->m_Name.c_str()); break; } m_fSpeed = shGetFloat(data); break; case eWindDirection: if (!data || !data[0]) { Warning( 0,0,"missing WindDirection argument for Ocean Effect in Shader '%s'\n", ef->m_Name.c_str()); break; } fWindDirection = shGetFloat(data); break; case eWindSpeed: if (!data || !data[0]) { Warning( 0,0,"missing WindSpeed argument for Ocean Effect in Shader '%s'\n", ef->m_Name.c_str()); break; } fWindSpeed = shGetFloat(data); break; case eWaveHeight: if (!data || !data[0]) { Warning( 0,0,"missing WaveHeight argument for Ocean Effect in Shader '%s'\n", ef->m_Name.c_str()); break; } fWaveHeight = shGetFloat(data); break; case eDirectionalDependence: if (!data || !data[0]) { Warning( 0,0,"missing DirectionalDependence argument for Ocean Effect in Shader '%s'\n", ef->m_Name.c_str()); break; } fDirectionalDependence = shGetFloat(data); break; case eChoppyWaveFactor: if (!data || !data[0]) { Warning( 0,0,"missing ChoppyWaveFactor argument for Ocean Effect in Shader '%s'\n", ef->m_Name.c_str()); break; } fChoppyWaveFactor = shGetFloat(data); break; case eSuppressSmallWavesFactor: if (!data || !data[0]) { Warning( 0,0,"missing SuppressSmallWavesFactor argument for Ocean Effect in Shader '%s'\n", ef->m_Name.c_str()); break; } fSuppressSmallWavesFactor = shGetFloat(data); break; } } PostLoad(4357, fWindDirection, fWindSpeed, fWaveHeight, fDirectionalDependence, fChoppyWaveFactor, fSuppressSmallWavesFactor); m_CustomTexBind[0] = 0; #if !defined(PS2) && !defined (GC) && !defined (NULL_RENDERER) if (!m_VPs[OVP_NOHEIGHT]) { m_VPs[OVP_NOHEIGHT] = CVProgram::mfForName("CGVProgOcean_NoHeight"); m_VPs[OVP_NOHEIGHT_SPL] = CVProgram::mfForName("CGVProgOcean_NoHeight_Splash"); m_VPs[OVP_HEIGHT] = CVProgram::mfForName("CGVProgOcean"); m_VPs[OVP_HEIGHT_SPL] = CVProgram::mfForName("CGVProgOcean_Splash"); } if (!m_VPQ) m_VPQ = CVProgram::mfForName("CGVProgOcean_SL"); #endif return true; }