#pragma once #include #include #include #include #include "Runtime/CToken.hpp" #include "Runtime/RetroTypes.hpp" #include "Runtime/Graphics/CTexture.hpp" #include "Runtime/Graphics/Shaders/CFluidPlaneShader.hpp" #include "Runtime/World/CFluidUVMotion.hpp" #include #include #include #include namespace urde { class CFluidUVMotion; class CRipple; class CRippleManager; class CScriptWater; class CStateManager; class CFluidPlaneRender { public: enum class NormalMode { None, NoNormals, Normals, NBT }; static int numTilesInHField; static int numSubdivisionsInTile; static int numSubdivisionsInHField; struct SPatchInfo { u8 x0_xSubdivs, x1_ySubdivs; zeus::CVector2f x4_localMin, xc_globalMin; float x14_tileSize; float x18_rippleResolution; float x1c_tileHypRadius; float x20_ooTileSize; float x24_ooRippleResolution; u16 x28_tileX; u16 x2a_gridDimX; u16 x2c_gridDimY; u16 x2e_tileY; const bool* x30_gridFlags; u8 x34_redShift; u8 x35_greenShift; u8 x36_blueShift; NormalMode x37_normalMode; float x38_wavecapIntensityScale; public: SPatchInfo(const zeus::CVector3f& localMin, const zeus::CVector3f& localMax, const zeus::CVector3f& pos, float rippleResolution, float tileSize, float wavecapIntensityScale, int numSubdivisionsInHField, NormalMode normalMode, int redShift, int greenShift, int blueShift, u32 tileX, u32 gridDimX, u32 gridDimY, u32 tileY, const bool* gridFlags) { x0_xSubdivs = std::min(s16((localMax.x() - localMin.x()) / rippleResolution + 1.f - FLT_EPSILON) + 2, numSubdivisionsInHField + 2); x1_ySubdivs = std::min(s16((localMax.y() - localMin.y()) / rippleResolution + 1.f - FLT_EPSILON) + 2, numSubdivisionsInHField + 2); float tileHypRadius = tileSize * tileSize * 2 * 0.25f; x4_localMin = localMin.toVec2f(); xc_globalMin = x4_localMin + pos.toVec2f(); x14_tileSize = tileSize; x18_rippleResolution = rippleResolution; if (tileHypRadius != 0.f) tileHypRadius = std::sqrt(tileHypRadius); x1c_tileHypRadius = tileHypRadius; x20_ooTileSize = 1.f / x14_tileSize; x24_ooRippleResolution = 1.f / x18_rippleResolution; x28_tileX = u16(tileX); x2a_gridDimX = u16(gridDimX); x2c_gridDimY = u16(gridDimY); x2e_tileY = u16(tileY); x30_gridFlags = gridFlags; x34_redShift = u8(redShift); x35_greenShift = u8(greenShift); x36_blueShift = u8(blueShift); x37_normalMode = normalMode; x38_wavecapIntensityScale = wavecapIntensityScale; } }; struct SRippleInfo { const CRipple& x0_ripple; int x4_fromX = 0; int x8_toX = 0; int xc_fromY = 0; int x10_toY = 0; int x14_gfromX; int x18_gtoX; int x1c_gfromY; int x20_gtoY; public: SRippleInfo(const CRipple& ripple, int fromX, int toX, int fromY, int toY) : x0_ripple(ripple), x14_gfromX(fromX), x18_gtoX(toX), x1c_gfromY(fromY), x20_gtoY(toY) {} }; struct SHFieldSample { float height; s8 nx; s8 ny; s8 nz; u8 wavecapIntensity; zeus::CVector3f MakeNormal() const { return zeus::CVector3f{nx / 63.f, ny / 63.f, nz / 63.f}.normalized(); } zeus::CVector3f MakeBinormal() const { return zeus::CVector3f{nx / 63.f, nz / 63.f, -ny / 63.f}.normalized(); } zeus::CVector3f MakeTangent() const { return zeus::CVector3f{nz / 63.f, ny / 63.f, -nx / 63.f}.normalized(); } zeus::CColor MakeColor(const CFluidPlaneRender::SPatchInfo& info) const { return {(wavecapIntensity >> info.x34_redShift) / 255.f, (wavecapIntensity >> info.x35_greenShift) / 255.f, (wavecapIntensity >> info.x36_blueShift) / 255.f}; } }; }; class CFluidPlane { protected: CAssetId x4_texPattern1Id; CAssetId x8_texPattern2Id; CAssetId xc_texColorId; TLockedToken x10_texPattern1; TLockedToken x20_texPattern2; TLockedToken x30_texColor; float x40_alpha; EFluidType x44_fluidType; float x48_rippleIntensity; CFluidUVMotion x4c_uvMotion; std::vector m_verts; std::vector m_pVerts; std::optional m_shader; float ProjectRippleVelocity(float baseI, float velDot) const; float CalculateRippleIntensity(float baseI) const; virtual void RenderStripWithRipples(float curY, const CFluidPlaneRender::SHFieldSample (&heights)[46][46], const u8 (&flags)[9][9], int startYDiv, const CFluidPlaneRender::SPatchInfo& info, std::vector& vOut, std::vector& pvOut); void RenderPatch(const CFluidPlaneRender::SPatchInfo& info, const CFluidPlaneRender::SHFieldSample (&heights)[46][46], const u8 (&flags)[9][9], bool noRipples, bool flagIs1, std::vector& vOut, std::vector& pvOut); public: virtual ~CFluidPlane() = default; CFluidPlane(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, float alpha, EFluidType fluidType, float rippleIntensity, const CFluidUVMotion& motion); // Called by CPlayer, CMorphBall, CWeapon, CPuddleSpore, CMagdolite virtual void AddRipple(float mag, TUniqueId rippler, const zeus::CVector3f& center, CScriptWater& water, CStateManager& mgr); // Called by CAi virtual void AddRipple(float intensity, TUniqueId rippler, const zeus::CVector3f& center, const zeus::CVector3f& velocity, const CScriptWater& water, CStateManager& mgr, const zeus::CVector3f& upVec); virtual void AddRipple(const CRipple& ripple, const CScriptWater& water, CStateManager& mgr); virtual void Render(const CStateManager& mgr, float alpha, const zeus::CAABox& aabb, const zeus::CTransform& xf, const zeus::CTransform& areaXf, bool noNormals, const zeus::CFrustum& frustum, const std::optional& rippleManager, TUniqueId waterId, const bool* gridFlags, u32 gridDimX, u32 gridDimY, const zeus::CVector3f& areaCenter) {} float GetAlpha() const { return x40_alpha; } EFluidType GetFluidType() const { return x44_fluidType; } const CFluidUVMotion& GetUVMotion() const { return x4c_uvMotion; } const CTexture& GetColorTexture() const { return *x30_texColor; } bool HasColorTexture() const { return x30_texColor.HasReference(); } const CTexture& GetTexturePattern1() const { return *x10_texPattern1; } bool HasTexturePattern1() const { return x10_texPattern1.HasReference(); } const CTexture& GetTexturePattern2() const { return *x20_texPattern2; } bool HasTexturePattern2() const { return x20_texPattern2.HasReference(); } }; } // namespace urde