mirror of https://github.com/AxioDL/metaforce.git
238 lines
6.9 KiB
C++
238 lines
6.9 KiB
C++
#include "CRainSplashGenerator.hpp"
|
|
#include "CStateManager.hpp"
|
|
#include "World/CWorld.hpp"
|
|
|
|
namespace urde
|
|
{
|
|
|
|
CRainSplashGenerator::CRainSplashGenerator(const zeus::CVector3f& scale, u32 maxSplashes,
|
|
u32 genRate, float minZ, float alpha)
|
|
: x14_scale(scale), x2c_minZ(minZ)
|
|
{
|
|
x30_alpha = std::min(1.f, alpha);
|
|
x44_genRate = std::min(maxSplashes, genRate);
|
|
x48_24 = false;
|
|
x48_25_raining = true;
|
|
x0_rainSplashes.reserve(maxSplashes);
|
|
CGraphics::CommitResources([&](boo::IGraphicsDataFactory::Context& ctx)
|
|
{
|
|
for (int i=0 ; i<maxSplashes ; ++i)
|
|
x0_rainSplashes.emplace_back(ctx);
|
|
return true;
|
|
} BooTrace);
|
|
}
|
|
|
|
void CRainSplashGenerator::SSplashLine::Draw(float alpha, float dt, const zeus::CVector3f& pos) const
|
|
{
|
|
if (x0_t > 0.f)
|
|
{
|
|
float delta = dt * xc_speed;
|
|
float vt = std::max(0.f, x0_t - delta * x15_length);
|
|
auto vertCount = u32((x0_t - vt) / delta + 1.f);
|
|
m_renderer.Reset();
|
|
for (u32 i=0 ; i<vertCount ; ++i)
|
|
{
|
|
float vertAlpha = vt * alpha;
|
|
zeus::CVector3f vec(vt * x4_xEnd, vt * x8_yEnd, -4.f * vt * (vt - 1.f) * x10_zParabolaHeight);
|
|
vec += pos;
|
|
vt += delta;
|
|
m_renderer.AddVertex(vec, zeus::CColor(1.f, vertAlpha), 1);
|
|
}
|
|
m_renderer.Render();
|
|
}
|
|
}
|
|
|
|
void CRainSplashGenerator::SRainSplash::Draw(float alpha, float dt, const zeus::CVector3f& pos) const
|
|
{
|
|
for (const SSplashLine& line : x0_lines)
|
|
line.Draw(alpha, dt, pos);
|
|
}
|
|
|
|
void CRainSplashGenerator::DoDraw(const zeus::CTransform& xf) const
|
|
{
|
|
CGraphics::SetModelMatrix(xf);
|
|
if (x40_queueSize > 0)
|
|
{
|
|
if (x38_queueTail <= x3c_queueHead)
|
|
{
|
|
for (int i=x3c_queueHead ; i<x0_rainSplashes.size() ; ++i)
|
|
{
|
|
const SRainSplash& splash = x0_rainSplashes[i];
|
|
splash.Draw(x30_alpha, x28_dt, splash.x64_pos);
|
|
}
|
|
for (int i=0 ; i<x38_queueTail ; ++i)
|
|
{
|
|
const SRainSplash& splash = x0_rainSplashes[i];
|
|
splash.Draw(x30_alpha, x28_dt, splash.x64_pos);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int i=x3c_queueHead ; i<x38_queueTail ; ++i)
|
|
{
|
|
const SRainSplash& splash = x0_rainSplashes[i];
|
|
splash.Draw(x30_alpha, x28_dt, splash.x64_pos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CRainSplashGenerator::Draw(const zeus::CTransform& xf) const
|
|
{
|
|
if (x48_25_raining)
|
|
DoDraw(xf);
|
|
}
|
|
|
|
CRainSplashGenerator::SSplashLine::SSplashLine(boo::IGraphicsDataFactory::Context& ctx)
|
|
: m_renderer(ctx, CLineRenderer::EPrimitiveMode::LineStrip, 3, nullptr, false)
|
|
{}
|
|
|
|
CRainSplashGenerator::SRainSplash::SRainSplash(boo::IGraphicsDataFactory::Context& ctx)
|
|
{
|
|
for (int i=0 ; i<4 ; ++i)
|
|
x0_lines.emplace_back(ctx);
|
|
}
|
|
|
|
void CRainSplashGenerator::SSplashLine::Update(float dt, CStateManager& mgr)
|
|
{
|
|
if (!x16_active)
|
|
return;
|
|
if (x0_t <= 0.8f)
|
|
{
|
|
x14_ = u8(5.f * (1.f - x0_t) + 3.f * x0_t);
|
|
x0_t += dt * xc_speed;
|
|
}
|
|
else if (x15_length != 0)
|
|
{
|
|
x15_length -= 1;
|
|
}
|
|
else
|
|
{
|
|
x16_active = false;
|
|
xc_speed = mgr.GetActiveRandom()->Range(0.015625f, 8.f);
|
|
x10_zParabolaHeight = mgr.GetActiveRandom()->Range(0.015625f, 0.03125f);
|
|
x4_xEnd = mgr.GetActiveRandom()->Range(-0.125f, 0.125f);
|
|
x8_yEnd = mgr.GetActiveRandom()->Range(-0.125f, 0.125f);
|
|
x15_length = u8(mgr.GetActiveRandom()->Range(1, 2));
|
|
}
|
|
}
|
|
|
|
void CRainSplashGenerator::SRainSplash::Update(float dt, CStateManager& mgr)
|
|
{
|
|
for (SSplashLine& point : x0_lines)
|
|
point.Update(dt, mgr);
|
|
}
|
|
|
|
bool CRainSplashGenerator::SRainSplash::IsActive() const
|
|
{
|
|
bool ret = false;
|
|
for (const SSplashLine& line : x0_lines)
|
|
ret |= line.x16_active;
|
|
return ret;
|
|
}
|
|
|
|
void CRainSplashGenerator::UpdateRainSplashRange(CStateManager& mgr, int start, int end, float dt)
|
|
{
|
|
for (int i=start ; i<end ; ++i)
|
|
{
|
|
SRainSplash& set = x0_rainSplashes[i];
|
|
set.Update(dt, mgr);
|
|
if (!set.IsActive())
|
|
{
|
|
x40_queueSize -= 1;
|
|
x3c_queueHead += 1;
|
|
if (x3c_queueHead >= x0_rainSplashes.size())
|
|
x3c_queueHead = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CRainSplashGenerator::UpdateRainSplashes(CStateManager& mgr, float magnitude, float dt)
|
|
{
|
|
x20_generateTimer += dt;
|
|
x24_generateInterval = 1.f / (70.f * magnitude);
|
|
if (x40_queueSize > 0)
|
|
{
|
|
if (x38_queueTail <= x3c_queueHead)
|
|
{
|
|
UpdateRainSplashRange(mgr, x3c_queueHead, int(x0_rainSplashes.size()), dt);
|
|
UpdateRainSplashRange(mgr, 0, x38_queueTail, dt);
|
|
}
|
|
else
|
|
{
|
|
UpdateRainSplashRange(mgr, x3c_queueHead, x38_queueTail, dt);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CRainSplashGenerator::Update(float dt, CStateManager& mgr)
|
|
{
|
|
EEnvFxType neededFx = mgr.GetWorld()->GetNeededEnvFx();
|
|
x28_dt = dt;
|
|
x48_25_raining = false;
|
|
if (neededFx != EEnvFxType::None && mgr.GetEnvFxManager()->IsSplashActive() &&
|
|
mgr.GetEnvFxManager()->GetRainMagnitude() != 0.f && neededFx == EEnvFxType::Rain)
|
|
{
|
|
UpdateRainSplashes(mgr, mgr.GetEnvFxManager()->GetRainMagnitude(), dt);
|
|
x48_25_raining = true;
|
|
}
|
|
}
|
|
|
|
u32 CRainSplashGenerator::GetNextBestPt(u32 pt, const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn,
|
|
CRandom16& rand, float minZ)
|
|
{
|
|
auto& refVert = vn[pt];
|
|
float maxDist = 0.f;
|
|
u32 nextPt = pt;
|
|
for (int i=0 ; i<3 ; ++i)
|
|
{
|
|
auto idx = u32(rand.Range(0, int(vn.size() - 1)));
|
|
auto& vert = vn[idx];
|
|
float distSq = (refVert.first - vert.first).magSquared();
|
|
if (distSq > maxDist &&
|
|
vert.second.dot(zeus::CVector3f::skUp) >= 0.f &&
|
|
(vert.first.z <= 0.f || vert.first.z > minZ))
|
|
{
|
|
nextPt = idx;
|
|
maxDist = distSq;
|
|
}
|
|
}
|
|
return nextPt;
|
|
}
|
|
|
|
void CRainSplashGenerator::SRainSplash::SetPoint(const zeus::CVector3f& pos)
|
|
{
|
|
for (SSplashLine& line : x0_lines)
|
|
line.SetActive();
|
|
x64_pos = pos;
|
|
}
|
|
|
|
void CRainSplashGenerator::AddPoint(const zeus::CVector3f& pos)
|
|
{
|
|
if (x38_queueTail >= x0_rainSplashes.size())
|
|
x38_queueTail = 0;
|
|
x0_rainSplashes[x38_queueTail].SetPoint(pos);
|
|
x40_queueSize += 1;
|
|
x38_queueTail += 1;
|
|
}
|
|
|
|
void CRainSplashGenerator::GeneratePoints(const std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vn)
|
|
{
|
|
if (!x48_25_raining)
|
|
return;
|
|
|
|
if (x20_generateTimer > x24_generateInterval)
|
|
{
|
|
for (int i=0 ; i<x44_genRate ; ++i)
|
|
{
|
|
if (x40_queueSize >= x0_rainSplashes.size())
|
|
break;
|
|
x34_curPoint = GetNextBestPt(x34_curPoint, vn, x10_random, x2c_minZ);
|
|
AddPoint(x14_scale * vn[x34_curPoint].first);
|
|
}
|
|
x20_generateTimer = 0.f;
|
|
}
|
|
}
|
|
|
|
}
|