mirror of https://github.com/AxioDL/metaforce.git
443 lines
18 KiB
C++
443 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 metaforce {
|
|
|
|
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 PlayerEffectResources& 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())
|
|
, x548_28_drawOwnerFirst(growingBeam) {
|
|
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].IsValid()) {
|
|
x52c_visorElectric = g_SimplePool->GetObj(SObjectTag{FOURCC('ELSC'), res[2]});
|
|
}
|
|
if (res[3].IsValid()) {
|
|
x538_visorParticle = g_SimplePool->GetObj(SObjectTag{FOURCC('PART'), res[3]});
|
|
}
|
|
x544_freezeSfx = CSfxManager::TranslateSFXID(u16(res[4].Value()));
|
|
x546_electricSfx = CSfxManager::TranslateSFXID(u16(res[5].Value()));
|
|
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() {
|
|
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(CStateManager& mgr) {
|
|
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 metaforce
|