mirror of
https://github.com/AxioDL/metaforce.git
synced 2025-05-14 10:31:22 +00:00
This member function alters instance state in a few implementations, so it shouldn't be made const. The state manager parameter also shouldn't be const. Retrieved data from the post constructed instance is further modified in some implementations. This removes the constness on this parameter in order to fix more const_cast usages in a follow-up change.
447 lines
18 KiB
C++
447 lines
18 KiB
C++
#include "Runtime/Weapon/CPlasmaProjectile.hpp"
|
|
|
|
#include "Runtime/CSimplePool.hpp"
|
|
#include "Runtime/CStateManager.hpp"
|
|
#include "Runtime/GameGlobalObjects.hpp"
|
|
#include "Runtime/Graphics/CBooRenderer.hpp"
|
|
#include "Runtime/World/CGameLight.hpp"
|
|
#include "Runtime/World/CHUDBillboardEffect.hpp"
|
|
#include "Runtime/World/CPlayer.hpp"
|
|
|
|
#include "TCastTo.hpp" // Generated file, do not modify include path
|
|
|
|
namespace urde {
|
|
|
|
CPlasmaProjectile::RenderObjects::RenderObjects(boo::IGraphicsDataFactory::Context& ctx,
|
|
boo::ObjToken<boo::ITexture> tex,
|
|
boo::ObjToken<boo::ITexture> glowTex)
|
|
: m_beamStrip1(ctx, 8, CColoredStripShader::Mode::Additive, {})
|
|
, m_beamStrip2(ctx, 10, CColoredStripShader::Mode::FullAdditive, tex)
|
|
, m_beamStrip3(ctx, 18, CColoredStripShader::Mode::FullAdditive, tex)
|
|
, m_beamStrip4(ctx, 14, CColoredStripShader::Mode::Additive, glowTex)
|
|
, m_beamStrip1Sub(ctx, 8, CColoredStripShader::Mode::Subtractive, {})
|
|
, m_beamStrip2Sub(ctx, 10, CColoredStripShader::Mode::Subtractive, tex)
|
|
, m_beamStrip3Sub(ctx, 18, CColoredStripShader::Mode::Subtractive, tex)
|
|
, m_beamStrip4Sub(ctx, 14, CColoredStripShader::Mode::Subtractive, glowTex)
|
|
, m_motionBlurStrip(ctx, 16, CColoredStripShader::Mode::Alpha, {}) {}
|
|
|
|
CPlasmaProjectile::CPlasmaProjectile(const TToken<CWeaponDescription>& wDesc, std::string_view name, EWeaponType wType,
|
|
const CBeamInfo& bInfo, const zeus::CTransform& xf, EMaterialTypes matType,
|
|
const CDamageInfo& dInfo, TUniqueId uid, TAreaId aid, TUniqueId owner,
|
|
const PlayerEffectResoures& res, bool growingBeam, EProjectileAttrib attribs)
|
|
: CBeamProjectile(wDesc, name, wType, xf, bInfo.GetLength(), bInfo.GetRadius(), bInfo.GetTravelSpeed(), matType,
|
|
dInfo, uid, aid, owner, attribs, growingBeam)
|
|
, x478_beamAttributes(bInfo.GetBeamAttributes())
|
|
, x47c_lifeTime(bInfo.GetLifeTime())
|
|
, x480_pulseSpeed(bInfo.GetPulseSpeed())
|
|
, x484_shutdownTime(bInfo.GetShutdownTime())
|
|
, x488_expansionSpeed(bInfo.GetExpansionSpeed())
|
|
, x48c_(bInfo.GetLength() / 32.f)
|
|
, x490_innerColor(bInfo.GetInnerColor())
|
|
, x494_outerColor(bInfo.GetOuterColor()) {
|
|
x4e8_texture = g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), bInfo.GetTextureId()});
|
|
x4f4_glowTexture = g_SimplePool->GetObj(SObjectTag{FOURCC('TXTR'), bInfo.GetGlowTextureId()});
|
|
x500_contactFxDesc = g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), bInfo.GetContactFxId()});
|
|
x50c_pulseFxDesc = g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), bInfo.GetPulseFxId()});
|
|
x518_contactGen = std::make_unique<CElementGen>(x500_contactFxDesc, CElementGen::EModelOrientationType::One);
|
|
x51c_pulseGen = std::make_unique<CElementGen>(x50c_pulseFxDesc, CElementGen::EModelOrientationType::Normal);
|
|
x524_freezeSteamTxtr = res[0];
|
|
x528_freezeIceTxtr = res[1];
|
|
if (res[2] != UINT64_MAX)
|
|
x52c_visorElectric = g_SimplePool->GetObj(SObjectTag{FOURCC('ELSC'), res[2]});
|
|
if (res[3] != UINT64_MAX)
|
|
x538_visorParticle = g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), res[3]});
|
|
x544_freezeSfx = CSfxManager::TranslateSFXID(res[4]);
|
|
x546_electricSfx = CSfxManager::TranslateSFXID(res[5]);
|
|
x548_25_enableEnergyPulse = true;
|
|
x548_28_drawOwnerFirst = growingBeam;
|
|
x518_contactGen->SetGlobalScale(zeus::CVector3f(bInfo.GetContactFxScale()));
|
|
x51c_pulseGen->SetGlobalScale(zeus::CVector3f(bInfo.GetPulseFxScale()));
|
|
x518_contactGen->SetParticleEmission(false);
|
|
x51c_pulseGen->SetParticleEmission(false);
|
|
|
|
CGraphics::CommitResources([this](boo::IGraphicsDataFactory::Context& ctx) {
|
|
m_renderObjs.emplace(ctx, x4e8_texture->GetBooTexture(), x4f4_glowTexture->GetBooTexture());
|
|
return true;
|
|
} BooTrace);
|
|
}
|
|
|
|
void CPlasmaProjectile::Accept(IVisitor& visitor) { visitor.Visit(this); }
|
|
|
|
void CPlasmaProjectile::SetLightsActive(bool active, CStateManager& mgr) {
|
|
for (TUniqueId lid : x468_lights) {
|
|
if (lid != kInvalidUniqueId) {
|
|
if (TCastToPtr<CGameLight> light = mgr.ObjectById(lid)) {
|
|
light->SetActive(active);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CPlasmaProjectile::CreatePlasmaLights(u32 sourceId, const CLight& l, CStateManager& mgr) {
|
|
DeletePlasmaLights(mgr);
|
|
x468_lights.reserve(3);
|
|
for (size_t i = 0; i < x468_lights.capacity(); ++i) {
|
|
const TUniqueId lid = mgr.AllocateUniqueId();
|
|
auto* light = new CGameLight(lid, GetAreaId(), GetActive(), "", GetTransform(), GetUniqueId(), l, sourceId, 0, 0.f);
|
|
mgr.AddObject(light);
|
|
x468_lights.push_back(lid);
|
|
}
|
|
}
|
|
|
|
void CPlasmaProjectile::DeletePlasmaLights(CStateManager& mgr) {
|
|
for (TUniqueId lid : x468_lights)
|
|
mgr.FreeScriptObject(lid);
|
|
x468_lights.clear();
|
|
}
|
|
|
|
void CPlasmaProjectile::UpdateLights(float expansion, float dt, CStateManager& mgr) {
|
|
if (x520_weaponGen) {
|
|
x520_weaponGen->Update(dt);
|
|
CLight l = x520_weaponGen->GetLight();
|
|
l.SetColor(zeus::CColor::lerp(zeus::skClear, l.GetColor(), expansion));
|
|
float halfLen = 0.5f * GetCurrentLength();
|
|
float y = 0.f;
|
|
for (TUniqueId lid : x468_lights) {
|
|
if (TCastToPtr<CGameLight> light = mgr.ObjectById(lid)) {
|
|
light->SetTransform({});
|
|
light->SetTranslation(GetBeamTransform() * zeus::CVector3f(0.f, y, 0.f));
|
|
light->SetLight(l);
|
|
}
|
|
y += halfLen;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CPlasmaProjectile::UpdateEnergyPulse(float dt) {
|
|
if (GetDamageType() != EDamageType::None && x548_25_enableEnergyPulse) {
|
|
x4d8_energyPulseTimer -= dt;
|
|
if (x4d8_energyPulseTimer <= 0.f) {
|
|
x4d8_energyPulseTimer = 2.f * dt;
|
|
x51c_pulseGen->SetParticleEmission(true);
|
|
float t = GetCurrentLength() / GetMaxLength();
|
|
for (float i = 0.f; i <= t; i += 0.1f) {
|
|
float y = i * GetMaxLength() + x4cc_energyPulseStartY;
|
|
if (y > GetCurrentLength())
|
|
continue;
|
|
x51c_pulseGen->SetTranslation({0.f, y, 0.f});
|
|
x51c_pulseGen->ForceParticleCreation(1);
|
|
}
|
|
x51c_pulseGen->SetGlobalOrientAndTrans(GetBeamTransform());
|
|
x51c_pulseGen->SetParticleEmission(false);
|
|
}
|
|
}
|
|
x51c_pulseGen->Update(dt);
|
|
}
|
|
|
|
void CPlasmaProjectile::RenderMotionBlur() const {
|
|
CGraphics::SetModelMatrix({});
|
|
zeus::CColor color1 = x494_outerColor;
|
|
zeus::CColor color2 = x494_outerColor;
|
|
color1.a() = 63.f / 255.f;
|
|
color2.a() = 0.f;
|
|
std::array<CColoredStripShader::Vert, 16> verts;
|
|
for (size_t i = 0; i < verts.size() / 2; ++i) {
|
|
auto& v1 = verts[i * 2];
|
|
auto& v2 = verts[i * 2 + 1];
|
|
v1.m_pos = GetBeamTransform().origin;
|
|
v1.m_color = zeus::CColor::lerp(color1, color2, float(i) / 8.f);
|
|
v2.m_pos = GetPointCache()[i];
|
|
v2.m_color = v1.m_color;
|
|
}
|
|
m_renderObjs->m_motionBlurStrip.draw(zeus::skWhite, verts.size(), verts.data());
|
|
}
|
|
|
|
void CPlasmaProjectile::RenderBeam(s32 subdivs, float width, const zeus::CColor& color, s32 flags,
|
|
CColoredStripShader& shader) const {
|
|
// Flags: 0x1: textured, 0x2: length controlled UVY 0x4: alpha controlled additive blend,
|
|
// 0x8: glow texture, 0x10: subtractive blend
|
|
if ((flags & 0x1) == 0 || (flags & 0x8) ? x4f4_glowTexture.IsLoaded() : x4e8_texture.IsLoaded()) {
|
|
float angIncrement = 2.f * M_PIF / float(subdivs);
|
|
float uvY1 = -(x4cc_energyPulseStartY / 16.f);
|
|
float uvY2 = (uvY1 + float((flags & 0x3) == 0x3) != 0.f) ? 2.f : 0.5f * GetCurrentLength();
|
|
std::array<CColoredStripShader::Vert, 18> verts;
|
|
s32 numNodes = subdivs + 1;
|
|
float angle = 0.f;
|
|
bool flip = false;
|
|
for (s32 i = 0; i < numNodes; ++i) {
|
|
CColoredStripShader::Vert& v0 = verts[i * 2];
|
|
CColoredStripShader::Vert& v1 = verts[i * 2 + 1];
|
|
float x = std::cos(angle);
|
|
float y = std::sin(angle);
|
|
float uvX;
|
|
if (flags & 0x8)
|
|
uvX = 0.5f * y;
|
|
else if (flip)
|
|
uvX = width;
|
|
else
|
|
uvX = 0.f;
|
|
flip ^= true;
|
|
v0.m_pos = zeus::CVector3f(width * x, 0.f, width * y);
|
|
v0.m_color = color;
|
|
v0.m_uv = zeus::CVector2f(uvX, uvY1);
|
|
v1.m_pos = zeus::CVector3f(width * x, GetCurrentLength(), width * y);
|
|
v1.m_color = color;
|
|
v1.m_uv = zeus::CVector2f(uvX, uvY2);
|
|
angle += angIncrement;
|
|
}
|
|
shader.draw(zeus::skWhite, numNodes * 2, verts.data());
|
|
}
|
|
}
|
|
|
|
void CPlasmaProjectile::ResetBeam(CStateManager& mgr, bool fullReset) {
|
|
if (fullReset) {
|
|
SetActive(false);
|
|
SetLightsActive(false, mgr);
|
|
x4bc_lifeTimer = 0.f;
|
|
x4c0_expansionT = 0.f;
|
|
x4c8_beamAngle = 0.f;
|
|
x4d0_shutdownTimer = 0.f;
|
|
x4d4_contactPulseTimer = 0.f;
|
|
x4d8_energyPulseTimer = 0.f;
|
|
x4dc_playerEffectPulseTimer = 0.f;
|
|
x4b4_expansionState = EExpansionState::Inactive;
|
|
x548_26_firing = false;
|
|
x518_contactGen->SetParticleEmission(false);
|
|
x51c_pulseGen->SetParticleEmission(false);
|
|
} else {
|
|
x548_26_firing = false;
|
|
x4b4_expansionState = EExpansionState::Release;
|
|
x518_contactGen->SetParticleEmission(false);
|
|
x51c_pulseGen->SetParticleEmission(false);
|
|
}
|
|
}
|
|
|
|
float CPlasmaProjectile::UpdateBeamState(float dt, CStateManager& mgr) {
|
|
switch (x4b4_expansionState) {
|
|
case EExpansionState::Attack:
|
|
if (x4c0_expansionT > 0.5f)
|
|
x4b4_expansionState = EExpansionState::Sustain;
|
|
else
|
|
x4c0_expansionT += dt * x488_expansionSpeed;
|
|
break;
|
|
case EExpansionState::Sustain:
|
|
if (x478_beamAttributes & 0x4) {
|
|
if (x4bc_lifeTimer > x47c_lifeTime)
|
|
x4b4_expansionState = EExpansionState::Release;
|
|
else
|
|
x4bc_lifeTimer += dt;
|
|
}
|
|
break;
|
|
case EExpansionState::Release:
|
|
x4c0_expansionT += dt * x488_expansionSpeed;
|
|
if (x4c0_expansionT > 1.f) {
|
|
x4c0_expansionT = 1.f;
|
|
x4b4_expansionState = EExpansionState::Done;
|
|
x548_25_enableEnergyPulse = false;
|
|
}
|
|
break;
|
|
case EExpansionState::Done:
|
|
x4d0_shutdownTimer += dt;
|
|
if (x4d0_shutdownTimer > x484_shutdownTime &&
|
|
(!x518_contactGen || x518_contactGen->GetParticleCountAll() == 0)) {
|
|
x4b4_expansionState = EExpansionState::Inactive;
|
|
ResetBeam(mgr, true);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return -4.f * x4c0_expansionT * (x4c0_expansionT - 1.f);
|
|
}
|
|
|
|
void CPlasmaProjectile::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) {
|
|
switch (msg) {
|
|
case EScriptObjectMessage::Registered: {
|
|
xe6_27_thermalVisorFlags = 2;
|
|
const SChildGeneratorDesc& apsm = x170_projectile.GetWeaponDescription()->x34_APSM;
|
|
if (apsm)
|
|
x520_weaponGen = std::make_unique<CElementGen>(apsm.m_token);
|
|
if (x520_weaponGen && x520_weaponGen->SystemHasLight())
|
|
CreatePlasmaLights(x170_projectile.GetWeaponDescription().GetObjectTag()->id.Value(),
|
|
x520_weaponGen->GetLight(), mgr);
|
|
else
|
|
x520_weaponGen.reset();
|
|
if (x548_28_drawOwnerFirst)
|
|
xc6_nextDrawNode = xec_ownerId;
|
|
mgr.AddWeaponId(xec_ownerId, xf0_weaponType);
|
|
break;
|
|
}
|
|
case EScriptObjectMessage::Deleted:
|
|
mgr.RemoveWeaponId(xec_ownerId, xf0_weaponType);
|
|
DeletePlasmaLights(mgr);
|
|
if (x548_29_activePlayerPhazon) {
|
|
mgr.GetPlayer().DecrementEnvironmentDamage();
|
|
x548_29_activePlayerPhazon = false;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
CGameProjectile::AcceptScriptMsg(msg, sender, mgr);
|
|
}
|
|
|
|
void CPlasmaProjectile::MakeBillboardEffect(const std::optional<TToken<CGenDescription>>& particle,
|
|
const std::optional<TToken<CElectricDescription>>& electric,
|
|
std::string_view name, CStateManager& mgr) {
|
|
auto* effect = new CHUDBillboardEffect(particle, electric, mgr.AllocateUniqueId(), true, name,
|
|
CHUDBillboardEffect::GetNearClipDistance(mgr),
|
|
CHUDBillboardEffect::GetScaleForPOV(mgr),
|
|
zeus::skWhite, zeus::skOne3f, zeus::skZero3f);
|
|
mgr.AddObject(effect);
|
|
}
|
|
|
|
void CPlasmaProjectile::UpdatePlayerEffects(float dt, CStateManager& mgr) {
|
|
x4dc_playerEffectPulseTimer -= dt;
|
|
if ((x4b4_expansionState == EExpansionState::Attack || x4b4_expansionState == EExpansionState::Sustain) &&
|
|
x4dc_playerEffectPulseTimer <= 0.f && GetDamageType() == EDamageType::Actor &&
|
|
GetCollisionActorId() == mgr.GetPlayer().GetUniqueId()) {
|
|
if ((x478_beamAttributes & 0x8) && !x548_29_activePlayerPhazon) {
|
|
x548_29_activePlayerPhazon = true;
|
|
x4e4_playerDamageTimer = 0.f;
|
|
mgr.GetPlayer().IncrementEnvironmentDamage();
|
|
}
|
|
switch (xf0_weaponType) {
|
|
case EWeaponType::Ice:
|
|
mgr.GetPlayer().Freeze(mgr, x524_freezeSteamTxtr, x544_freezeSfx, x528_freezeIceTxtr);
|
|
break;
|
|
case EWeaponType::Wave:
|
|
if (x52c_visorElectric) {
|
|
MakeBillboardEffect({}, {x52c_visorElectric}, "PlasmaElectricFx"sv, mgr);
|
|
CSfxManager::SfxStart(x546_electricSfx, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
|
|
mgr.GetPlayer().SetHudDisable(3.f, 0.5f, 2.5f);
|
|
mgr.GetPlayer().SetOrbitRequestForTarget(mgr.GetPlayer().GetOrbitTargetId(),
|
|
CPlayer::EPlayerOrbitRequest::ActivateOrbitSource, mgr);
|
|
mgr.GetPlayerState()->GetStaticInterference().AddSource(GetUniqueId(), 0.2f, 3.f);
|
|
}
|
|
break;
|
|
case EWeaponType::Plasma:
|
|
if (x538_visorParticle)
|
|
MakeBillboardEffect({x538_visorParticle}, {}, "PlasmaVisorFx"sv, mgr);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
x4dc_playerEffectPulseTimer = 0.75f;
|
|
}
|
|
if (x548_29_activePlayerPhazon) {
|
|
CDamageInfo scaledDamage(x498_phazonDamage, dt);
|
|
mgr.ApplyDamage(GetUniqueId(), mgr.GetPlayer().GetUniqueId(), xec_ownerId, scaledDamage, xf8_filter,
|
|
zeus::skZero3f);
|
|
x4e4_playerDamageTimer += dt;
|
|
if (x4e4_playerDamageTimer >= x4e0_playerDamageDuration) {
|
|
mgr.GetPlayer().DecrementEnvironmentDamage();
|
|
x4e4_playerDamageTimer = 0.f;
|
|
x548_29_activePlayerPhazon = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CPlasmaProjectile::UpdateFx(const zeus::CTransform& xf, float dt, CStateManager& mgr) {
|
|
if (!GetActive())
|
|
return;
|
|
|
|
x548_27_texturesLoaded = x4e8_texture.IsLoaded() && x4f4_glowTexture.IsLoaded();
|
|
CauseDamage(x4b4_expansionState == EExpansionState::Attack || x4b4_expansionState == EExpansionState::Sustain);
|
|
CBeamProjectile::UpdateFx(xf, dt, mgr);
|
|
UpdatePlayerEffects(dt, mgr);
|
|
if (x478_beamAttributes & 0x1) {
|
|
for (int i = 7; i > 0; --i)
|
|
PointCache()[i] = PointCache()[i - 1];
|
|
PointCache()[0] = GetCurrentPos();
|
|
}
|
|
if (x518_contactGen) {
|
|
x4d4_contactPulseTimer -= dt;
|
|
if ((GetDamageType() != EDamageType::None ? x548_25_enableEnergyPulse : false) && x4d4_contactPulseTimer <= 0.f) {
|
|
x518_contactGen->SetOrientation(zeus::lookAt(zeus::skZero3f, GetSurfaceNormal()));
|
|
x518_contactGen->SetTranslation(GetSurfaceNormal() * 0.001f + GetCurrentPos());
|
|
x518_contactGen->SetParticleEmission(true);
|
|
x4d4_contactPulseTimer = 1.f / 16.f;
|
|
} else {
|
|
x518_contactGen->SetParticleEmission(false);
|
|
}
|
|
x518_contactGen->Update(dt);
|
|
}
|
|
float modulation = UpdateBeamState(dt, mgr);
|
|
UpdateEnergyPulse(dt);
|
|
x4c8_beamAngle += 720.f * dt;
|
|
if (x4c8_beamAngle > 360.f)
|
|
x4c8_beamAngle = 0.f;
|
|
x4b8_beamWidth = modulation * GetMaxRadius();
|
|
x4c4_expansion = modulation;
|
|
x4cc_energyPulseStartY += dt * x480_pulseSpeed;
|
|
if (x4cc_energyPulseStartY > 5.f)
|
|
x4cc_energyPulseStartY = 0.f;
|
|
UpdateLights(modulation, dt, mgr);
|
|
}
|
|
|
|
void CPlasmaProjectile::Fire(const zeus::CTransform& xf, CStateManager& mgr, bool b) {
|
|
SetActive(true);
|
|
SetLightsActive(true, mgr);
|
|
x548_25_enableEnergyPulse = true;
|
|
x548_26_firing = true;
|
|
x548_24_ = b;
|
|
x4b4_expansionState = EExpansionState::Attack;
|
|
if (x478_beamAttributes & 0x1)
|
|
std::fill(PointCache().begin(), PointCache().end(), xf.origin);
|
|
}
|
|
|
|
void CPlasmaProjectile::Touch(CActor& other, CStateManager& mgr) {
|
|
// Empty
|
|
}
|
|
|
|
bool CPlasmaProjectile::CanRenderUnsorted(const CStateManager& mgr) const {
|
|
return false;
|
|
}
|
|
|
|
void CPlasmaProjectile::AddToRenderer(const zeus::CFrustum& frustum, CStateManager& mgr) {
|
|
if (GetActive()) {
|
|
g_Renderer->AddParticleGen(*x518_contactGen);
|
|
if (x478_beamAttributes & 0x2) {
|
|
g_Renderer->AddParticleGen(*x51c_pulseGen);
|
|
}
|
|
}
|
|
EnsureRendered(mgr, GetBeamTransform().origin, GetSortingBounds(mgr));
|
|
}
|
|
|
|
void CPlasmaProjectile::Render(const CStateManager& mgr) const {
|
|
if (!GetActive())
|
|
return;
|
|
SCOPED_GRAPHICS_DEBUG_GROUP("CPlasmaProjectile::Render", zeus::skOrange);
|
|
|
|
zeus::CTransform xf = GetBeamTransform();
|
|
|
|
// Subtractive blending for xray
|
|
s32 flags = mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::EPlayerVisor::XRay ? 0x10 : 0x0;
|
|
|
|
if ((x478_beamAttributes & 0x1) == 0)
|
|
xf.origin += mgr.GetCameraManager()->GetGlobalCameraTranslation(mgr);
|
|
|
|
// Z test, no write
|
|
|
|
if ((x478_beamAttributes & 0x1) && x548_25_enableEnergyPulse && x4b4_expansionState != EExpansionState::Attack)
|
|
RenderMotionBlur();
|
|
|
|
// Pass1: alpha-controlled additive
|
|
CGraphics::SetModelMatrix(xf);
|
|
RenderBeam(3, 0.25f * x4b8_beamWidth, zeus::CColor(1.f, 0.3f), flags | 0x4,
|
|
(flags & 0x10) ? m_renderObjs->m_beamStrip1Sub : m_renderObjs->m_beamStrip1);
|
|
|
|
// Pass2: textured
|
|
CGraphics::SetModelMatrix(xf * zeus::CTransform::RotateY(zeus::degToRad(x4c8_beamAngle)));
|
|
RenderBeam(4, 0.5f * x4b8_beamWidth, x490_innerColor, flags | 0x1,
|
|
(flags & 0x10) ? m_renderObjs->m_beamStrip2Sub : m_renderObjs->m_beamStrip2);
|
|
|
|
// Pass3: textured | length-controlled UVY
|
|
CGraphics::SetModelMatrix(xf * zeus::CTransform::RotateY(zeus::degToRad(-x4c8_beamAngle)));
|
|
RenderBeam(8, x4b8_beamWidth, x494_outerColor, flags | 0x3,
|
|
(flags & 0x10) ? m_renderObjs->m_beamStrip3Sub : m_renderObjs->m_beamStrip3);
|
|
|
|
// Pass4: textured | alpha-controlled additive | glow texture
|
|
CGraphics::SetModelMatrix(xf);
|
|
RenderBeam(6, 1.25f * x4b8_beamWidth, x494_outerColor, flags | 0xd,
|
|
(flags & 0x10) ? m_renderObjs->m_beamStrip4Sub : m_renderObjs->m_beamStrip4);
|
|
}
|
|
|
|
} // namespace urde
|