#include "Runtime/World/CFluidPlane.hpp" #include "Runtime/CSimplePool.hpp" #include "Runtime/CStateManager.hpp" #include "Runtime/GameGlobalObjects.hpp" #include "Runtime/World/CRipple.hpp" #include "Runtime/World/CScriptWater.hpp" namespace metaforce { 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 = 0.0f; 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 Heights& heights, const Flags& flags, int startYDiv, // const CFluidPlaneRender::SPatchInfo& info, // std::vector& vOut, // std::vector& pvOut) { // 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 < stripDivCount; ++v) { // func(curTileX, curTileY, heights[curYDiv][i + v]); // func(curTileX, curTileY + info.x18_rippleResolution, heights[curYDiv + 1][i + v]); // curTileX += info.x18_rippleResolution; // } // // CGraphics::DrawArray(start, vOut.size() - start); // } // } else { // bool r19 = (flags[yTile + 1][xTile] & 0x2) != 0; // North // bool r16 = (flags[yTile][xTile - 1] & 0x8) != 0; // West // bool r18 = (flags[yTile][xTile + 1] & 0x4) != 0; // East // bool r17 = (flags[yTile - 1][xTile] & 0x1) != 0; // South // // int r6 = (r19 ? CFluidPlaneRender::numSubdivisionsInTile : 1) + 2; // r6 += r18 ? CFluidPlaneRender::numSubdivisionsInTile : 1; // r6 += r17 ? CFluidPlaneRender::numSubdivisionsInTile : 1; // r6 += r16 ? CFluidPlaneRender::numSubdivisionsInTile : 1; // // if (r6 == 6 && (info.x37_normalMode == CFluidPlaneRender::NormalMode::Normals || // info.x37_normalMode == CFluidPlaneRender::NormalMode::NBT)) { // for (; xTile + tileSpan <= endXTile; ++tileSpan) { // if ((flags[yTile][xTile + tileSpan] & 0x1f) == 0x1f) // break; // if (info.x30_gridFlags && !info.x30_gridFlags[gridCell + tileSpan]) // break; // if ((flags[yTile + 1][xTile + tileSpan] & 0x2) != 0x0) // break; // if ((flags[yTile][xTile + tileSpan + 1] & 0x4) != 0x0) // break; // if ((flags[yTile - 1][xTile + tileSpan] & 0x1) != 0x0) // break; // } // // int stripDivCount = tileSpan + 1; // size_t start = vOut.size(); // switch (info.x37_normalMode) { // case CFluidPlaneRender::NormalMode::Normals: { // int curYDiv0 = startYDiv; // int curYDiv1 = startYDiv + CFluidPlaneRender::numSubdivisionsInTile; // float curTileX = curX; // for (int v = 0; v < stripDivCount; ++v) { // int curXDiv = v * CFluidPlaneRender::numSubdivisionsInTile + i; // const CFluidPlaneRender::SHFieldSample& samp0 = heights[curYDiv0][curXDiv]; // const CFluidPlaneRender::SHFieldSample& samp1 = heights[curYDiv1][curXDiv]; // vOut.emplace_back(zeus::CVector3f(curTileX, yMin, samp0.height), samp0.MakeNormal(), samp0.MakeColor(info)); // vOut.emplace_back(zeus::CVector3f(curTileX, yMin + info.x14_tileSize, samp1.height), samp1.MakeNormal(), // samp1.MakeColor(info)); // curTileX += info.x14_tileSize; // } // break; // } // case CFluidPlaneRender::NormalMode::NBT: { // int curYDiv0 = startYDiv; // int curYDiv1 = startYDiv + CFluidPlaneRender::numSubdivisionsInTile; // float curTileX = curX; // for (int v = 0; v < stripDivCount; ++v) { // int curXDiv = v * CFluidPlaneRender::numSubdivisionsInTile + i; // const CFluidPlaneRender::SHFieldSample& samp0 = heights[curYDiv0][curXDiv]; // const CFluidPlaneRender::SHFieldSample& samp1 = heights[curYDiv1][curXDiv]; // vOut.emplace_back(zeus::CVector3f(curTileX, yMin, samp0.height), samp0.MakeNormal(), samp0.MakeBinormal(), // samp0.MakeTangent(), samp0.MakeColor(info)); // vOut.emplace_back(zeus::CVector3f(curTileX, yMin + info.x14_tileSize, samp1.height), samp1.MakeNormal(), // samp1.MakeBinormal(), samp1.MakeTangent(), samp1.MakeColor(info)); // curTileX += info.x14_tileSize; // } // break; // } // default: // break; // } // // CGraphics::DrawArray(start, vOut.size() - start); // } else { // TriFanToStrip 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 < CFluidPlaneRender::numSubdivisionsInTile + 1; ++v) { // const CFluidPlaneRender::SHFieldSample& samp = heights[curYDiv + v][curXDiv]; // func(curTileX, curTileY, samp); // curTileY += info.x18_rippleResolution; // } // } else { // { // const CFluidPlaneRender::SHFieldSample& samp = heights[curYDiv][curXDiv]; // func(curTileX, curTileY, samp); // } // curTileY += info.x14_tileSize; // { // const CFluidPlaneRender::SHFieldSample& samp = // heights[curYDiv + CFluidPlaneRender::numSubdivisionsInTile][curXDiv]; // func(curTileX, curTileY, samp); // } // } // // // toStrip.Draw(); // } // } // } // } // // void CFluidPlane::RenderPatch(const CFluidPlaneRender::SPatchInfo& info, const Heights& heights, const Flags& flags, // bool noRipples, bool flagIs1, std::vector& vOut, // std::vector& pvOut) { // OPTICK_EVENT(); // 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::skBlack); // vOut.emplace_back(zeus::CVector3f(xMin, yMax, 0.f), zeus::skBlack); // vOut.emplace_back(zeus::CVector3f(xMax, yMin, 0.f), zeus::skBlack); // vOut.emplace_back(zeus::CVector3f(xMax, yMax, 0.f), zeus::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 < xTiles; curXTile = nextXTile) { // if (!info.x30_gridFlags || info.x30_gridFlags[xTileStart + curXTile]) { // if (curYTile == yTiles || curYTile == 1 || curXTile == 0 || xTiles - 1 == curXTile) { // TriFanToStrip toStrip(vOut); // // toStrip.EmplaceVert( // zeus::CVector3f(xMax + 0.5f * info.x14_tileSize, yMax + 0.5f * info.x14_tileSize, 0.f), zeus::skUp, // zeus::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::skUp, zeus::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::skUp, zeus::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::skUp, zeus::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::skUp, zeus::skBlack); // tmp += info.x18_rippleResolution; // } // // toStrip.EmplaceVert(zeus::CVector3f(xMax, yMax + info.x14_tileSize, 0.f), zeus::skUp, zeus::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::skUp, zeus::skBlack); // vOut.emplace_back(zeus::CVector3f(xMax, yMax + info.x14_tileSize, 0.f), zeus::skUp, zeus::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::skUp, zeus::skForward, zeus::skRight, zeus::skBlack); // vOut.emplace_back(zeus::CVector3f(xMin, yMax, 0.f), zeus::skUp, zeus::skForward, zeus::skRight, zeus::skBlack); // vOut.emplace_back(zeus::CVector3f(xMax, yMin, 0.f), zeus::skUp, zeus::skForward, zeus::skRight, zeus::skBlack); // vOut.emplace_back(zeus::CVector3f(xMax, yMax, 0.f), zeus::skUp, zeus::skForward, zeus::skRight, zeus::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 < xTiles; curXTile = nextXTile) { // if (info.x30_gridFlags[xTileStart + curXTile]) { // nextXTile = curXTile + 1; // int tile = xTileStart + nextXTile; // while (nextXTile < xTiles && info.x30_gridFlags[tile]) { // ++nextXTile; // ++tile; // } // // size_t start = vOut.size(); // for (int v = 0; v < nextXTile - curXTile + 1; ++v) { // vOut.emplace_back(zeus::CVector3f(xMax, yMin, 0.f), zeus::skUp, zeus::skForward, zeus::skRight, // zeus::skBlack); // vOut.emplace_back(zeus::CVector3f(xMax, yMin + info.x14_tileSize, 0.f), zeus::skUp, zeus::skForward, // zeus::skRight, zeus::skBlack); // xMax += info.x14_tileSize; // } // // CGraphics::DrawArray(start, vOut.size() - start); // } else { // nextXTile = curXTile + 1; // xMax += info.x14_tileSize; // int tile = xTileStart + nextXTile; // while (nextXTile < xTiles && !info.x30_gridFlags[tile]) { // xMax += info.x14_tileSize; // ++nextXTile; // ++tile; // } // } // } // } // } // break; // } // } // } else { // float curY = info.x4_localMin.y(); // for (int startYDiv = 1; startYDiv < info.x1_ySubdivs - 2; // startYDiv += CFluidPlaneRender::numSubdivisionsInTile, curY += info.x14_tileSize) // RenderStripWithRipples(curY, heights, flags, startYDiv, info, vOut, pvOut); // } // } } // namespace metaforce