#include #include "CFluidPlane.hpp" #include "CSimplePool.hpp" #include "CRipple.hpp" #include "CScriptWater.hpp" #include "CStateManager.hpp" namespace urde { CFluidPlane::CFluidPlane(CAssetId texPattern1, CAssetId texPattern2, CAssetId texColor, float alpha, EFluidType fluidType, float rippleIntensity, const CFluidUVMotion& motion) : x4_texPattern1Id(texPattern1), x8_texPattern2Id(texPattern2), xc_texColorId(texColor), x40_alpha(alpha), x44_fluidType(fluidType), x48_rippleIntensity(rippleIntensity), x4c_uvMotion(motion) { if (g_ResFactory->GetResourceTypeById(texPattern1) == FOURCC('TXTR')) x10_texPattern1 = g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), texPattern1}); if (g_ResFactory->GetResourceTypeById(texPattern2) == FOURCC('TXTR')) x20_texPattern2 = g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), texPattern2}); if (g_ResFactory->GetResourceTypeById(texColor) == FOURCC('TXTR')) x30_texColor = g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), texColor}); } float CFluidPlane::ProjectRippleVelocity(float baseI, float velDot) const { float tmp = 0.5f * baseI * velDot * velDot; if (tmp != 0.f) tmp = std::sqrt(tmp); if (tmp >= 160.f) return 1.f; return tmp / 160.f; } float CFluidPlane::CalculateRippleIntensity(float baseI) const { float mul; switch (x44_fluidType) { case EFluidType::NormalWater: mul = g_tweakGame->GetRippleIntensityNormal(); break; case EFluidType::PoisonWater: mul = g_tweakGame->GetRippleIntensityPoison(); break; case EFluidType::Lava: mul = g_tweakGame->GetRippleIntensityLava(); break; case EFluidType::PhazonFluid: case EFluidType::Four: mul = 0.8f; break; case EFluidType::ThickLava: mul = 1.f; break; } return zeus::clamp(0.f, baseI * mul * (1.f - x48_rippleIntensity + 0.5f), 1.f); } void CFluidPlane::AddRipple(float mag, TUniqueId rippler, const zeus::CVector3f& center, CScriptWater& water, CStateManager& mgr) { if (!water.CanRippleAtPoint(center)) return; mag = CalculateRippleIntensity(mag); mgr.GetFluidPlaneManager()->RippleManager().AddRipple(CRipple(rippler, center, mag)); } void CFluidPlane::AddRipple(float intensity, TUniqueId rippler, const zeus::CVector3f& center, const zeus::CVector3f& velocity, const CScriptWater& water, CStateManager& mgr, const zeus::CVector3f& upVec) { if (!water.CanRippleAtPoint(center)) return; intensity = CalculateRippleIntensity(ProjectRippleVelocity(intensity, upVec.dot(velocity))); mgr.GetFluidPlaneManager()->RippleManager().AddRipple(CRipple(rippler, center, intensity)); } void CFluidPlane::AddRipple(const CRipple& ripple, const CScriptWater& water, CStateManager& mgr) { if (!water.CanRippleAtPoint(ripple.GetCenter())) return; mgr.GetFluidPlaneManager()->RippleManager().AddRipple(ripple); } void CFluidPlane::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) const { m_shader->bindRegular(); int yTile = (startYDiv + CFluidPlaneRender::numSubdivisionsInTile - 1) / CFluidPlaneRender::numSubdivisionsInTile; int endXTile = (info.x0_xSubdivs + CFluidPlaneRender::numSubdivisionsInTile - 4) / CFluidPlaneRender::numSubdivisionsInTile; int midDiv = CFluidPlaneRender::numSubdivisionsInTile / 2; float tileMid = info.x18_rippleResolution * midDiv; float yMin = curY; float yMid = curY + tileMid; float curX = info.x4_localMin.x; int gridCell = info.x28_tileX + info.x2a_gridDimX * (info.x2e_tileY + yTile - 1); int xTile = 1; int tileSpan; for (int i = 1 ; i < info.x0_xSubdivs - 2 ; i += CFluidPlaneRender::numSubdivisionsInTile * tileSpan, gridCell += tileSpan, xTile += tileSpan, curX += info.x14_tileSize * tileSpan) { tileSpan = 1; if (info.x30_gridFlags && !info.x30_gridFlags[gridCell]) continue; if ((flags[yTile][xTile] & 0x1f) == 0x1f) { for (; xTile+tileSpan<=endXTile ; ++tileSpan) { if ((flags[yTile][xTile+tileSpan] & 0x1f) != 0x1f) break; if (info.x30_gridFlags && !info.x30_gridFlags[gridCell+tileSpan]) break; } int stripDivCount = tileSpan * CFluidPlaneRender::numSubdivisionsInTile + 1; int remSubdivs = CFluidPlaneRender::numSubdivisionsInTile; std::function func; switch (info.x37_normalMode) { case CFluidPlaneRender::NormalMode::None: func = [&](float x, float y, const CFluidPlaneRender::SHFieldSample& samp) { vOut.emplace_back(zeus::CVector3f(x, y, samp.height)); }; break; case CFluidPlaneRender::NormalMode::NoNormals: func = [&](float x, float y, const CFluidPlaneRender::SHFieldSample& samp) { vOut.emplace_back(zeus::CVector3f(x, y, samp.height), samp.MakeColor(info)); }; break; case CFluidPlaneRender::NormalMode::Normals: func = [&](float x, float y, const CFluidPlaneRender::SHFieldSample& samp) { vOut.emplace_back(zeus::CVector3f(x, y, samp.height), samp.MakeNormal(), samp.MakeColor(info)); }; break; case CFluidPlaneRender::NormalMode::NBT: func = [&](float x, float y, const CFluidPlaneRender::SHFieldSample& samp) { vOut.emplace_back(zeus::CVector3f(x, y, samp.height), samp.MakeNormal(), samp.MakeBinormal(), samp.MakeTangent(), samp.MakeColor(info)); }; break; } float curTileY = yMin; int curYDiv = startYDiv; for (; remSubdivs>0 ; --remSubdivs, ++curYDiv, curTileY+=info.x18_rippleResolution) { size_t start = vOut.size(); float curTileX = curX; for (int v=0 ; v toStrip(vOut); std::function func; switch (info.x37_normalMode) { case CFluidPlaneRender::NormalMode::None: func = [&](float x, float y, const CFluidPlaneRender::SHFieldSample& samp) { toStrip.EmplaceVert(zeus::CVector3f(x, y, samp.height)); }; break; case CFluidPlaneRender::NormalMode::NoNormals: func = [&](float x, float y, const CFluidPlaneRender::SHFieldSample& samp) { toStrip.EmplaceVert(zeus::CVector3f(x, y, samp.height), samp.MakeColor(info)); }; break; case CFluidPlaneRender::NormalMode::Normals: func = [&](float x, float y, const CFluidPlaneRender::SHFieldSample& samp) { toStrip.EmplaceVert(zeus::CVector3f(x, y, samp.height), samp.MakeNormal(), samp.MakeColor(info)); }; break; case CFluidPlaneRender::NormalMode::NBT: func = [&](float x, float y, const CFluidPlaneRender::SHFieldSample& samp) { toStrip.EmplaceVert(zeus::CVector3f(x, y, samp.height), samp.MakeNormal(), samp.MakeBinormal(), samp.MakeTangent(), samp.MakeColor(info)); }; break; } func(tileMid + curX, yMid, heights[startYDiv+midDiv][i+midDiv]); int curXDiv = i; int curYDiv = startYDiv + CFluidPlaneRender::numSubdivisionsInTile; float curTileX = curX; float curTileY = yMin + info.x14_tileSize; for (int v=0 ; v<(r19 ? CFluidPlaneRender::numSubdivisionsInTile : 1) ; ++v) { const CFluidPlaneRender::SHFieldSample& samp = heights[curYDiv][curXDiv+v]; func(curTileX, curTileY, samp); curTileX += info.x18_rippleResolution; } curXDiv = i + CFluidPlaneRender::numSubdivisionsInTile; curYDiv = startYDiv + CFluidPlaneRender::numSubdivisionsInTile; curTileX = curX + info.x14_tileSize; curTileY = yMin + info.x14_tileSize; for (int v=0 ; v<(r18 ? CFluidPlaneRender::numSubdivisionsInTile : 1) ; ++v) { const CFluidPlaneRender::SHFieldSample& samp = heights[curYDiv-v][curXDiv]; func(curTileX, curTileY, samp); curTileY -= info.x18_rippleResolution; } curXDiv = i + CFluidPlaneRender::numSubdivisionsInTile; curYDiv = startYDiv; curTileX = curX + info.x14_tileSize; curTileY = yMin; for (int v=0 ; v<(r17 ? CFluidPlaneRender::numSubdivisionsInTile : 1) ; ++v) { const CFluidPlaneRender::SHFieldSample& samp = heights[curYDiv][curXDiv-v]; func(curTileX, curTileY, samp); curTileX -= info.x18_rippleResolution; } curXDiv = i; curYDiv = startYDiv; curTileX = curX; curTileY = yMin; if (r16) { for (int v=0 ; v& vOut, std::vector& pvOut) const { if (noRipples) { m_shader->bindRegular(); float xMin = info.x4_localMin.x; float yMin = info.x4_localMin.y; float xMax = info.x18_rippleResolution * (info.x0_xSubdivs - 2) + xMin; float yMax = info.x18_rippleResolution * (info.x1_ySubdivs - 2) + yMin; switch (info.x37_normalMode) { case CFluidPlaneRender::NormalMode::None: { size_t start = vOut.size(); vOut.emplace_back(zeus::CVector3f(xMin, yMin, 0.f)); vOut.emplace_back(zeus::CVector3f(xMin, yMax, 0.f)); vOut.emplace_back(zeus::CVector3f(xMax, yMin, 0.f)); vOut.emplace_back(zeus::CVector3f(xMax, yMax, 0.f)); CGraphics::DrawArray(start, 4); break; } case CFluidPlaneRender::NormalMode::NoNormals: { size_t start = vOut.size(); vOut.emplace_back(zeus::CVector3f(xMin, yMin, 0.f), zeus::CColor::skBlack); vOut.emplace_back(zeus::CVector3f(xMin, yMax, 0.f), zeus::CColor::skBlack); vOut.emplace_back(zeus::CVector3f(xMax, yMin, 0.f), zeus::CColor::skBlack); vOut.emplace_back(zeus::CVector3f(xMax, yMax, 0.f), zeus::CColor::skBlack); CGraphics::DrawArray(start, 4); break; } case CFluidPlaneRender::NormalMode::Normals: { int yTiles = (info.x1_ySubdivs - 3) / CFluidPlaneRender::numSubdivisionsInTile + 1; int xTiles = (info.x0_xSubdivs - 3) / CFluidPlaneRender::numSubdivisionsInTile + 1; int xTileStart = info.x28_tileX + info.x2e_tileY * info.x2a_gridDimX; yMax = yMin; for (int curYTile=yTiles ; curYTile>0 ; --curYTile, yMax += info.x14_tileSize, xTileStart += info.x2a_gridDimX) { xMax = xMin; int nextXTile; for (int curXTile=0 ; curXTile toStrip(vOut); toStrip.EmplaceVert(zeus::CVector3f(xMax + 0.5f * info.x14_tileSize, yMax + 0.5f * info.x14_tileSize, 0.f), zeus::CVector3f::skUp, zeus::CColor::skBlack); float tmp = xMax; for (int v=0 ; v<((curYTile == 1) ? CFluidPlaneRender::numSubdivisionsInTile : 1) ; ++v) { toStrip.EmplaceVert(zeus::CVector3f(tmp, yMax + info.x14_tileSize, 0.f), zeus::CVector3f::skUp, zeus::CColor::skBlack); tmp += info.x18_rippleResolution; } tmp = yMax + info.x14_tileSize; for (int v=0 ; v<((xTiles - 1 == curXTile) ? CFluidPlaneRender::numSubdivisionsInTile : 1) ; ++v) { toStrip.EmplaceVert(zeus::CVector3f(xMax + info.x14_tileSize, tmp, 0.f), zeus::CVector3f::skUp, zeus::CColor::skBlack); tmp -= info.x18_rippleResolution; } tmp = xMax + info.x14_tileSize; for (int v=0 ; v<((curYTile == yTiles) ? CFluidPlaneRender::numSubdivisionsInTile : 1) ; ++v) { toStrip.EmplaceVert(zeus::CVector3f(tmp, yMax, 0.f), zeus::CVector3f::skUp, zeus::CColor::skBlack); tmp -= info.x18_rippleResolution; } tmp = yMax; for (int v=0 ; v<((curXTile == 0) ? CFluidPlaneRender::numSubdivisionsInTile : 1) ; ++v) { toStrip.EmplaceVert(zeus::CVector3f(xMax, tmp, 0.f), zeus::CVector3f::skUp, zeus::CColor::skBlack); tmp += info.x18_rippleResolution; } toStrip.EmplaceVert(zeus::CVector3f(xMax, yMax + info.x14_tileSize, 0.f), zeus::CVector3f::skUp, zeus::CColor::skBlack); toStrip.Draw(); nextXTile = curXTile + 1; xMax += info.x14_tileSize; } else { nextXTile = curXTile + 1; while (nextXTile < xTiles - 1 && (!info.x30_gridFlags || info.x30_gridFlags[xTileStart+nextXTile])) ++nextXTile; size_t start = vOut.size(); for (int v = 0 ; v < nextXTile - curXTile + 1 ; ++v) { vOut.emplace_back(zeus::CVector3f(xMax, yMax, 0.f), zeus::CVector3f::skUp, zeus::CColor::skBlack); vOut.emplace_back(zeus::CVector3f(xMax, yMax + info.x14_tileSize, 0.f), zeus::CVector3f::skUp, zeus::CColor::skBlack); xMax += info.x14_tileSize; } CGraphics::DrawArray(start, vOut.size() - start); ++nextXTile; if (nextXTile == xTiles) { --nextXTile; xMax -= info.x14_tileSize; } } } else { nextXTile = curXTile + 1; xMax += info.x14_tileSize; while (nextXTile < xTiles && !info.x30_gridFlags[xTileStart+nextXTile]) { xMax += info.x14_tileSize; ++nextXTile; } } } } break; } case CFluidPlaneRender::NormalMode::NBT: { if (flagIs1 || !info.x30_gridFlags) { size_t start = vOut.size(); vOut.emplace_back(zeus::CVector3f(xMin, yMin, 0.f), zeus::CVector3f::skUp, zeus::CVector3f::skForward, zeus::CVector3f::skRight, zeus::CColor::skBlack); vOut.emplace_back(zeus::CVector3f(xMin, yMax, 0.f), zeus::CVector3f::skUp, zeus::CVector3f::skForward, zeus::CVector3f::skRight, zeus::CColor::skBlack); vOut.emplace_back(zeus::CVector3f(xMax, yMin, 0.f), zeus::CVector3f::skUp, zeus::CVector3f::skForward, zeus::CVector3f::skRight, zeus::CColor::skBlack); vOut.emplace_back(zeus::CVector3f(xMax, yMax, 0.f), zeus::CVector3f::skUp, zeus::CVector3f::skForward, zeus::CVector3f::skRight, zeus::CColor::skBlack); CGraphics::DrawArray(start, 4); } else { int xTiles = (info.x0_xSubdivs - 3) / CFluidPlaneRender::numSubdivisionsInTile + 1; int yTiles = (info.x1_ySubdivs - 3) / CFluidPlaneRender::numSubdivisionsInTile + 1; int xTileStart = info.x28_tileX + info.x2e_tileY * info.x2a_gridDimX; for (; yTiles>0 ; --yTiles, yMin += info.x14_tileSize, xTileStart += info.x2a_gridDimX) { xMax = xMin; int nextXTile; for (int curXTile=0 ; curXTile