metaforce/Runtime/MP1/CSamusDoll.cpp

673 lines
27 KiB
C++
Raw Normal View History

2017-04-26 06:43:48 +00:00
#include "CSamusDoll.hpp"
2017-05-04 18:56:20 +00:00
#include "GameGlobalObjects.hpp"
#include "CSimplePool.hpp"
#include "CDependencyGroup.hpp"
#include "zeus/CEulerAngles.hpp"
#include "Collision/CollisionUtil.hpp"
2017-05-06 05:21:42 +00:00
#include "Graphics/CBooRenderer.hpp"
2017-09-12 05:51:17 +00:00
#include "World/CMorphBall.hpp"
2017-04-26 06:43:48 +00:00
2018-12-08 05:30:43 +00:00
namespace urde::MP1 {
2017-04-26 06:43:48 +00:00
2017-05-04 18:56:20 +00:00
const zeus::CVector3f CSamusDoll::skInitialOffset = {0.f, 0.f, 0.8f};
2018-12-08 05:30:43 +00:00
static const std::pair<const char*, u32> SpiderBallGlassModels[] = {
{"SamusSpiderBallGlassCMDL", 0}, {"SamusSpiderBallGlassCMDL", 0}, {"SamusSpiderBallGlassCMDL", 1},
{"SamusPhazonBallGlassCMDL", 0}, {"SamusSpiderBallGlassCMDL", 0}, {"SamusSpiderBallGlassCMDL", 0},
{"SamusSpiderBallGlassCMDL", 1}, {"SamusPhazonBallGlassCMDL", 0},
2017-05-04 18:56:20 +00:00
};
2018-12-08 05:30:43 +00:00
static const std::pair<const char*, u32> SpiderBallCharacters[] = {
{"SamusSpiderBallANCS", 0}, {"SamusSpiderBallANCS", 0}, {"SamusSpiderBallANCS", 1}, {"SamusPhazonBallANCS", 0},
{"SamusFusionBallANCS", 0}, {"SamusFusionBallANCS", 2}, {"SamusFusionBallANCS", 1}, {"SamusFusionBallANCS", 3},
2017-05-04 18:56:20 +00:00
};
2018-12-08 05:30:43 +00:00
static const std::pair<const char*, u32> BallCharacters[] = {
{"SamusBallANCS", 0}, {"SamusBallANCS", 0}, {"SamusBallANCS", 1}, {"SamusBallANCS", 0},
{"SamusFusionBallANCS", 0}, {"SamusFusionBallANCS", 2}, {"SamusFusionBallANCS", 1}, {"SamusFusionBallANCS", 3},
2017-05-04 18:56:20 +00:00
};
2018-12-08 05:30:43 +00:00
static const u32 SpiderBallGlowColorIdxs[] = {3, 3, 2, 4, 5, 7, 6, 8};
2017-05-04 18:56:20 +00:00
2018-12-08 05:30:43 +00:00
static const u32 BallGlowColorIdxs[] = {0, 0, 1, 0, 5, 7, 6, 8};
2017-05-04 18:56:20 +00:00
2018-12-08 05:30:43 +00:00
static const char* BeamModels[] = {"CMDL_InvPowerBeam", "CMDL_InvIceBeam", "CMDL_InvWaveBeam", "CMDL_InvPlasmaBeam",
"CMDL_InvPowerBeam"};
2017-05-04 18:56:20 +00:00
2018-12-08 05:30:43 +00:00
static const char* VisorModels[] = {"CMDL_InvVisor", "CMDL_InvGravityVisor", "CMDL_InvVisor",
"CMDL_InvPhazonVisor", "CMDL_InvFusionVisor", "CMDL_InvFusionVisor",
"CMDL_InvFusionVisor", "CMDL_InvFusionVisor"};
2017-05-04 18:56:20 +00:00
2018-12-08 05:30:43 +00:00
static const char* FinModels[] = {"CMDL_InvPowerFins", "CMDL_InvPowerFins", "CMDL_InvPowerFins",
"CMDL_InvPowerFins", "CMDL_InvPowerFins", "CMDL_InvVariaFins",
"CMDL_InvGravityFins", "CMDL_InvPhazonFins"};
2017-05-04 18:56:20 +00:00
2018-12-08 05:30:43 +00:00
static const u32 Character1Idxs[8] = {0, 6, 2, 10, 16, 24, 20, 28};
2017-05-04 18:56:20 +00:00
2018-12-08 05:30:43 +00:00
static const u32 CharacterBootsIdxs[8] = {1, 7, 3, 11, 17, 25, 21, 29};
2017-05-04 18:56:20 +00:00
2018-12-08 05:30:43 +00:00
static const u32 Character2and3Idxs[8][2] = {{14, 15}, {8, 9}, {4, 5}, {12, 13},
{18, 19}, {26, 27}, {22, 23}, {30, 31}};
2017-05-04 18:56:20 +00:00
2017-04-26 06:43:48 +00:00
CSamusDoll::CSamusDoll(const CDependencyGroup& suitDgrp, const CDependencyGroup& ballDgrp,
2018-12-08 05:30:43 +00:00
CPlayerState::EPlayerSuit suit, CPlayerState::EBeamId beam, bool hasSpiderBall,
bool hasGrappleBeam)
: x10_ballXf(zeus::CTransform::Translate(0.f, 0.f, 0.625f * g_tweakPlayer->GetPlayerBallHalfExtent()))
, x44_suit(suit)
, x48_beam(beam) {
x70_fixedRot.rotateZ(M_PIF);
x90_userInterpRot = xb0_userRot = x70_fixedRot;
x1d4_spiderBallGlass = g_SimplePool->GetObj(SpiderBallGlassModels[int(suit)].first);
x1e0_ballMatIdx = hasSpiderBall ? SpiderBallCharacters[int(suit)].second : BallCharacters[int(suit)].second;
x1e4_glassMatIdx = SpiderBallGlassModels[int(suit)].second;
x1e8_ballGlowColorIdx = hasSpiderBall ? SpiderBallGlowColorIdxs[int(suit)] : BallGlowColorIdxs[int(suit)];
x1ec_itemScreenSamus = g_SimplePool->GetObj("ANCS_ItemScreenSamus");
x1f4_invBeam = g_SimplePool->GetObj(BeamModels[int(beam)]);
x200_invVisor = g_SimplePool->GetObj(VisorModels[int(suit)]);
x20c_invGrappleBeam = g_SimplePool->GetObj("CMDL_InvGrappleBeam");
x218_invFins = g_SimplePool->GetObj(FinModels[int(suit)]);
x224_ballInnerGlow = g_SimplePool->GetObj("BallInnerGlow");
x22c_ballInnerGlowGen = std::make_unique<CElementGen>(x224_ballInnerGlow);
x230_ballTransitionFlash = g_SimplePool->GetObj("MorphBallTransitionFlash");
x23c_lights.push_back(CLight::BuildDirectional(zeus::skForward, zeus::skWhite));
x24c_actorLights = std::make_unique<CActorLights>(8, zeus::skZero3f, 4, 4, false, false, false, 0.1f);
2018-12-08 05:30:43 +00:00
x270_24_hasSpiderBall = hasSpiderBall;
x270_25_hasGrappleBeam = hasGrappleBeam;
x22c_ballInnerGlowGen->SetGlobalScale(zeus::CVector3f(0.625f));
x0_depToks.reserve(suitDgrp.GetObjectTagVector().size() + ballDgrp.GetObjectTagVector().size());
for (const SObjectTag& tag : suitDgrp.GetObjectTagVector()) {
x0_depToks.push_back(g_SimplePool->GetObj(tag));
x0_depToks.back().Lock();
}
for (const SObjectTag& tag : ballDgrp.GetObjectTagVector()) {
x0_depToks.push_back(g_SimplePool->GetObj(tag));
x0_depToks.back().Lock();
}
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
bool CSamusDoll::IsLoaded() const {
if (x270_31_loaded)
return true;
if (!x1ec_itemScreenSamus.IsLoaded())
return false;
if (!x1f4_invBeam.IsLoaded())
return false;
if (!x200_invVisor.IsLoaded())
return false;
if (!x20c_invGrappleBeam.IsLoaded())
return false;
if (!x1d4_spiderBallGlass.IsLoaded())
return false;
if (x218_invFins && !x218_invFins.IsLoaded())
return false;
return xc8_suitModel0.operator bool();
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
CModelData CSamusDoll::BuildSuitModelData1(CPlayerState::EPlayerSuit suit) {
CModelData ret(CAnimRes(g_ResFactory->GetResourceIdByName("ANCS_ItemScreenSamus")->id, Character1Idxs[int(suit)],
zeus::skOne3f, 2, true));
2018-12-08 05:30:43 +00:00
CAnimPlaybackParms parms(2, -1, 1.f, true);
ret.AnimationData()->SetAnimation(parms, false);
return ret;
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
CModelData CSamusDoll::BuildSuitModelDataBoots(CPlayerState::EPlayerSuit suit) {
CModelData ret(CAnimRes(g_ResFactory->GetResourceIdByName("ANCS_ItemScreenSamus")->id, CharacterBootsIdxs[int(suit)],
zeus::skOne3f, 2, true));
2018-12-08 05:30:43 +00:00
CAnimPlaybackParms parms(2, -1, 1.f, true);
ret.AnimationData()->SetAnimation(parms, false);
return ret;
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
bool CSamusDoll::CheckLoadComplete() {
if (IsLoaded())
2017-05-04 18:56:20 +00:00
return true;
2018-12-08 05:30:43 +00:00
for (const CToken& tok : x0_depToks)
if (!tok.IsLoaded())
return false;
xc8_suitModel0.emplace(BuildSuitModelData1(x44_suit));
for (int i = 0; i < 2; ++i) {
CAnimRes res(g_ResFactory->GetResourceIdByName("ANCS_ItemScreenSamus")->id, Character2and3Idxs[int(x44_suit)][i],
zeus::skOne3f, 2, true);
2018-12-08 05:30:43 +00:00
CModelData mData(res);
x118_suitModel1and2.push_back(mData.GetAnimationData()->GetModelData());
x118_suitModel1and2.back().Lock();
}
x134_suitModelBoots.emplace(BuildSuitModelDataBoots(x44_suit));
CAnimRes res(g_ResFactory
->GetResourceIdByName(x270_24_hasSpiderBall ? SpiderBallCharacters[int(x44_suit)].first
: BallCharacters[int(x44_suit)].first)
->id,
0, zeus::skOne3f, 0, true);
2018-12-08 05:30:43 +00:00
x184_ballModelData.emplace(res);
x1e0_ballMatIdx =
x270_24_hasSpiderBall ? SpiderBallCharacters[int(x44_suit)].second : BallCharacters[int(x44_suit)].second;
x270_31_loaded = true;
return true;
}
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
void CSamusDoll::Update(float dt, CRandom16& rand) {
if (x1f4_invBeam.IsLoaded())
x1f4_invBeam->Touch(0);
if (x200_invVisor.IsLoaded())
x200_invVisor->Touch(0);
if (x20c_invGrappleBeam.IsLoaded())
x20c_invGrappleBeam->Touch(0);
if (x1d4_spiderBallGlass.IsLoaded())
x1d4_spiderBallGlass->Touch(0);
if (x218_invFins.IsLoaded())
x218_invFins->Touch(0);
if (!CheckLoadComplete())
return;
x40_alphaIn = std::min(x40_alphaIn + 2.f * dt, 1.f);
if (x54_remTransitionTime > 0.f) {
float oldRemTransTime = x54_remTransitionTime;
x54_remTransitionTime = std::max(0.f, x54_remTransitionTime - dt);
if (!x4c_completedMorphball && x4d_selectedMorphball && oldRemTransTime >= x50_totalTransitionTime - 0.5f &&
x54_remTransitionTime < x50_totalTransitionTime - 0.5f) {
x238_ballTransitionFlashGen = std::make_unique<CElementGen>(x230_ballTransitionFlash);
x238_ballTransitionFlashGen->SetGlobalScale(zeus::CVector3f(0.625f));
2017-05-06 05:21:42 +00:00
}
2018-12-08 05:30:43 +00:00
if (x54_remTransitionTime == 0.f) {
x4c_completedMorphball = x4d_selectedMorphball;
if (!x4d_selectedMorphball) {
xc8_suitModel0->AnimationData()->SetAnimation(CAnimPlaybackParms(2, -1, 1.f, true), false);
x134_suitModelBoots->AnimationData()->SetAnimation(CAnimPlaybackParms(2, -1, 1.f, true), false);
}
2017-05-06 05:21:42 +00:00
}
2018-12-08 05:30:43 +00:00
}
if (x270_26_pulseSuit)
x58_suitPulseFactor = std::min(x58_suitPulseFactor + 2.f * dt, 1.f);
else
x58_suitPulseFactor = std::max(x58_suitPulseFactor - 2.f * dt, 0.f);
if (x270_27_pulseBeam)
x5c_beamPulseFactor = std::min(x5c_beamPulseFactor + 2.f * dt, 1.f);
else
x5c_beamPulseFactor = std::max(x5c_beamPulseFactor - 2.f * dt, 0.f);
if (x270_28_pulseGrapple)
x60_grapplePulseFactor = std::min(x60_grapplePulseFactor + 2.f * dt, 1.f);
else
x60_grapplePulseFactor = std::max(x60_grapplePulseFactor - 2.f * dt, 0.f);
if (x270_29_pulseBoots)
x64_bootsPulseFactor = std::min(x64_bootsPulseFactor + 2.f * dt, 1.f);
else
x64_bootsPulseFactor = std::max(x64_bootsPulseFactor - 2.f * dt, 0.f);
if (x270_30_pulseVisor)
x68_visorPulseFactor = std::min(x68_visorPulseFactor + 2.f * dt, 1.f);
else
x68_visorPulseFactor = std::max(x68_visorPulseFactor - 2.f * dt, 0.f);
if (x4c_completedMorphball)
x6c_ballPulseFactor = std::min(x6c_ballPulseFactor + 2.f * dt, 1.f);
else
x6c_ballPulseFactor = std::max(x6c_ballPulseFactor - 2.f * dt, 0.f);
if (x44_suit == CPlayerState::EPlayerSuit::Phazon) {
if (!x250_phazonIndirectTexture)
x250_phazonIndirectTexture = g_SimplePool->GetObj("PhazonIndirectTexture");
} else {
2017-05-06 05:21:42 +00:00
if (x250_phazonIndirectTexture)
2018-12-08 05:30:43 +00:00
x250_phazonIndirectTexture = TLockedToken<CTexture>();
}
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
if (x250_phazonIndirectTexture) {
x260_phazonOffsetAngle += 0.03f;
2018-12-17 03:52:51 +00:00
x260_phazonOffsetAngle.makeRel();
2018-12-08 05:30:43 +00:00
g_Renderer->AllocatePhazonSuitMaskTexture();
}
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
xc8_suitModel0->AdvanceAnimationIgnoreParticles(dt, rand, true);
x134_suitModelBoots->AdvanceAnimationIgnoreParticles(dt, rand, true);
x184_ballModelData->AdvanceAnimationIgnoreParticles(dt, rand, true);
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
SetupLights();
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
x22c_ballInnerGlowGen->SetGlobalTranslation(x10_ballXf.origin);
x22c_ballInnerGlowGen->Update(dt);
if (x238_ballTransitionFlashGen) {
if (x238_ballTransitionFlashGen->IsSystemDeletable())
x238_ballTransitionFlashGen.reset();
if (x238_ballTransitionFlashGen) {
x22c_ballInnerGlowGen->SetGlobalTranslation(x10_ballXf.origin);
x22c_ballInnerGlowGen->Update(dt);
2017-05-06 05:21:42 +00:00
}
2018-12-08 05:30:43 +00:00
}
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
if (xc4_viewInterp != 0.f && xc4_viewInterp != 1.f) {
if (xc4_viewInterp < 0.f)
xc4_viewInterp = std::min(xc4_viewInterp + 3.f * dt, 0.f);
else
xc4_viewInterp = std::min(xc4_viewInterp + 3.f * dt, 1.f);
2017-04-26 06:43:48 +00:00
2018-12-08 05:30:43 +00:00
float interp = std::fabs(xc4_viewInterp);
float oneMinusInterp = 1.f - interp;
xa4_offset = x84_interpStartOffset * interp + skInitialOffset * oneMinusInterp;
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
xb0_userRot = zeus::CQuaternion::slerpShort(x70_fixedRot, x90_userInterpRot, interp);
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
if (xc4_viewInterp <= 0.f) // Zoom out
xc0_userZoom = x80_fixedZoom * oneMinusInterp + xa0_userInterpZoom * interp;
else // Zoom in
xc0_userZoom = x80_fixedZoom * interp + xa0_userInterpZoom * oneMinusInterp;
}
2017-04-26 06:43:48 +00:00
}
2018-12-08 05:30:43 +00:00
void CSamusDoll::Draw(const CStateManager& mgr, float alpha) {
if (!IsLoaded())
return;
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
alpha *= x40_alphaIn;
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
float itemPulse = zeus::clamp(0.f, (std::sin(5.f * CGraphics::GetSecondsMod900()) + 1.f) * 0.5f, 1.f) *
(1.f - std::fabs(xc4_viewInterp));
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
g_Renderer->SetPerspective(55.f, g_Viewport.x8_width, g_Viewport.xc_height, 0.2f, 4096.f);
2017-05-04 18:56:20 +00:00
2018-12-08 05:30:43 +00:00
CGraphics::SetViewPointMatrix(zeus::CTransform(xb0_userRot, xa4_offset) *
zeus::CTransform::Translate(0.f, xc0_userZoom, 0.f));
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
zeus::CTransform gunXf = xc8_suitModel0->GetScaledLocatorTransform("GUN_LCTR");
zeus::CTransform visorXf = xc8_suitModel0->GetScaledLocatorTransform("VISOR_LCTR");
zeus::CTransform grappleXf = xc8_suitModel0->GetScaledLocatorTransform("GRAPPLE_LCTR");
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
if (!x4c_completedMorphball || !x4d_selectedMorphball) {
float suitPulse = itemPulse * x58_suitPulseFactor;
float bootsPulse = std::max(suitPulse, itemPulse * x64_bootsPulseFactor);
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
bool phazonSuit = x44_suit == CPlayerState::EPlayerSuit::Phazon;
// Enable dst alpha 1.0
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
for (int i = 0; i <= x118_suitModel1and2.size(); ++i) {
TCachedToken<CSkinnedModel> backupModelData = xc8_suitModel0->GetAnimationData()->GetModelData();
if (i < x118_suitModel1and2.size())
xc8_suitModel0->AnimationData()->SubstituteModelData(x118_suitModel1and2[i]);
xc8_suitModel0->InvSuitDraw(CModelData::EWhichModel::Normal, zeus::CTransform(), x24c_actorLights.get(),
2018-12-08 05:30:43 +00:00
zeus::CColor(1.f, alpha), zeus::CColor(1.f, alpha * suitPulse));
xc8_suitModel0->AnimationData()->SubstituteModelData(backupModelData);
}
2017-05-06 05:21:42 +00:00
x134_suitModelBoots->InvSuitDraw(CModelData::EWhichModel::Normal, zeus::CTransform(),
2018-12-08 05:30:43 +00:00
x24c_actorLights.get(), zeus::CColor(1.f, alpha),
zeus::CColor(1.f, alpha * bootsPulse));
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
{
CGraphics::SetModelMatrix(gunXf);
x1f4_invBeam->GetInstance().ActivateLights(x23c_lights);
CModelFlags flags = {};
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
flags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly;
flags.x4_color = zeus::skWhite;
2018-12-08 05:30:43 +00:00
x1f4_invBeam->Draw(flags);
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
flags.m_extendedShader = EExtendedShader::ForcedAlpha;
flags.x4_color = zeus::CColor(1.f, alpha);
x1f4_invBeam->Draw(flags);
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
flags.m_extendedShader = EExtendedShader::ForcedAdditive;
flags.x4_color = zeus::CColor(1.f, alpha * itemPulse * x5c_beamPulseFactor);
x1f4_invBeam->Draw(flags);
}
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
{
CGraphics::SetModelMatrix(visorXf);
float visorT = std::fmod(CGraphics::GetSecondsMod900(), 1.f) * (1.f - std::fabs(xc4_viewInterp));
float alphaBlend = (visorT < 0.25f) ? 1.f - 2.f * visorT : (visorT < 0.5f) ? 2.f * (visorT - 0.25f) + 0.5f : 1.f;
float addBlend = (visorT > 0.75f) ? 1.f - 4.f * (visorT - 0.75f) : (visorT > 0.5f) ? 4.f * (visorT - 0.5f) : 0.f;
x200_invVisor->GetInstance().ActivateLights(x23c_lights);
CModelFlags flags = {};
flags.m_extendedShader = EExtendedShader::Lighting;
flags.x4_color =
zeus::CColor::lerp(zeus::CColor(1.f, alpha), zeus::CColor(alphaBlend, alpha), x68_visorPulseFactor);
x200_invVisor->Draw(flags);
flags.m_extendedShader = EExtendedShader::ForcedAdditive;
flags.x4_color = zeus::CColor(1.f, alpha * addBlend * x68_visorPulseFactor);
x200_invVisor->Draw(flags);
}
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
if (x270_25_hasGrappleBeam) {
CGraphics::SetModelMatrix(grappleXf);
x20c_invGrappleBeam->GetInstance().ActivateLights(x23c_lights);
CModelFlags flags = {};
flags.m_extendedShader = EExtendedShader::ForcedAlpha;
flags.x4_color = zeus::CColor(1.f, alpha);
x20c_invGrappleBeam->Draw(flags);
flags.m_extendedShader = EExtendedShader::ForcedAdditive;
flags.x4_color = zeus::CColor(1.f, alpha * itemPulse * x60_grapplePulseFactor);
x20c_invGrappleBeam->Draw(flags);
} else if (x44_suit >= CPlayerState::EPlayerSuit::FusionPower) {
CGraphics::SetModelMatrix(grappleXf);
x218_invFins->GetInstance().ActivateLights(x23c_lights);
CModelFlags flags = {};
flags.m_extendedShader = EExtendedShader::ForcedAlpha;
flags.x4_color = zeus::CColor(1.f, alpha);
x218_invFins->Draw(flags);
flags.m_extendedShader = EExtendedShader::ForcedAdditive;
flags.x4_color = zeus::CColor(1.f, alpha * suitPulse);
x218_invFins->Draw(flags);
}
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
if (x54_remTransitionTime > 0.f) {
float ballT = 1.f - x54_remTransitionTime / x50_totalTransitionTime;
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
float ballAlpha = 0.f;
if (x4d_selectedMorphball)
ballAlpha = 1.f - std::min(x54_remTransitionTime / 0.25f, 1.f);
else if (x4c_completedMorphball)
ballAlpha = std::max(0.f, (x54_remTransitionTime - (x50_totalTransitionTime - 0.25f)) / 0.25f);
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
if (ballAlpha > 0.f) {
CModelFlags flags = {};
flags.x1_matSetIdx = x1e0_ballMatIdx;
flags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly;
flags.x4_color = zeus::skWhite;
2018-12-08 05:30:43 +00:00
x184_ballModelData->Render(mgr, x10_ballXf, x24c_actorLights.get(), flags);
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
flags.m_extendedShader = EExtendedShader::ForcedAlpha;
flags.x4_color = zeus::skWhite;
2018-12-08 05:30:43 +00:00
flags.x4_color.a() = alpha * ballAlpha;
x184_ballModelData->Render(mgr, x10_ballXf, x24c_actorLights.get(), flags);
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
flags.m_extendedShader = EExtendedShader::ForcedAdditive;
flags.x4_color = zeus::skWhite;
2018-12-08 05:30:43 +00:00
flags.x4_color.a() = x6c_ballPulseFactor * alpha * ballAlpha * itemPulse;
x184_ballModelData->Render(mgr, x10_ballXf, x24c_actorLights.get(), flags);
}
if (x4d_selectedMorphball && ballT > 0.5f) {
float ballEndT = (ballT - 0.5f) / 0.5f;
float oneMinusBallEndT = 1.f - ballEndT;
float spinScale = 0.75f * oneMinusBallEndT + 1.f;
float spinAlpha;
if (ballEndT < 0.1f)
spinAlpha = 0.f;
else if (ballEndT < 0.2f)
spinAlpha = (ballEndT - 0.1f) / 0.1f;
else if (ballEndT < 0.9f)
spinAlpha = 1.f;
else
spinAlpha = 1.f - (ballT - 0.9f) / 0.1f;
zeus::CRelAngle spinAngle = zeus::degToRad(360.f * oneMinusBallEndT);
spinAlpha *= 0.5f;
if (spinAlpha > 0.f) {
CModelFlags flags = {};
flags.m_extendedShader = EExtendedShader::ForcedAdditive;
flags.x1_matSetIdx = x1e0_ballMatIdx;
flags.x4_color = zeus::CColor(1.f, spinAlpha * alpha);
x184_ballModelData->Render(
mgr, x10_ballXf * zeus::CTransform::RotateZ(spinAngle) * zeus::CTransform::Scale(spinScale),
x24c_actorLights.get(), flags);
2017-05-06 05:21:42 +00:00
}
2018-12-08 05:30:43 +00:00
}
if (x270_24_hasSpiderBall) {
CGraphics::SetModelMatrix(x10_ballXf);
2017-05-06 05:21:42 +00:00
CModelFlags flags = {};
2018-12-08 05:30:43 +00:00
flags.x1_matSetIdx = x1e4_glassMatIdx;
x1d4_spiderBallGlass->GetInstance().ActivateLights(x23c_lights);
2017-05-06 05:21:42 +00:00
flags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly;
flags.x4_color = zeus::skWhite;
2018-12-08 05:30:43 +00:00
x1d4_spiderBallGlass->Draw(flags);
2017-05-06 05:21:42 +00:00
flags.m_extendedShader = EExtendedShader::ForcedAlpha;
flags.x4_color = zeus::skWhite;
2018-12-08 01:49:15 +00:00
flags.x4_color.a() = alpha;
2018-12-08 05:30:43 +00:00
x1d4_spiderBallGlass->Draw(flags);
2017-05-06 05:21:42 +00:00
flags.m_extendedShader = EExtendedShader::ForcedAdditive;
flags.x4_color = zeus::skWhite;
2018-12-08 01:49:15 +00:00
flags.x4_color.a() = x6c_ballPulseFactor * alpha * itemPulse;
2018-12-08 05:30:43 +00:00
x1d4_spiderBallGlass->Draw(flags);
}
}
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
if (phazonSuit && alpha > 0.1f) {
float radius = zeus::clamp(0.2f, (10.f - (xc0_userZoom >= 0.f ? xc0_userZoom : -xc0_userZoom)) / 20.f, 1.f);
float offset = std::sin(x260_phazonOffsetAngle);
zeus::CColor color = g_tweakGuiColors->GetPauseBlurFilterColor();
color.a() = alpha;
g_Renderer->DrawPhazonSuitIndirectEffect(zeus::CColor(0.1f, alpha), x250_phazonIndirectTexture, color, radius,
0.1f, offset, offset);
}
} else {
CModelFlags flags = {};
flags.x1_matSetIdx = x1e0_ballMatIdx;
flags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly;
flags.x4_color = zeus::skWhite;
2018-12-08 05:30:43 +00:00
x184_ballModelData->Render(mgr, x10_ballXf, x24c_actorLights.get(), flags);
flags.m_extendedShader = EExtendedShader::ForcedAlpha;
flags.x4_color = zeus::skWhite;
2018-12-08 05:30:43 +00:00
flags.x4_color.a() = alpha;
x184_ballModelData->Render(mgr, x10_ballXf, x24c_actorLights.get(), flags);
flags.m_extendedShader = EExtendedShader::ForcedAdditive;
flags.x4_color = zeus::skWhite;
2018-12-08 05:30:43 +00:00
flags.x4_color.a() = x6c_ballPulseFactor * alpha * itemPulse;
x184_ballModelData->Render(mgr, x10_ballXf, x24c_actorLights.get(), flags);
const u8* c = CMorphBall::BallGlowColors[x1e8_ballGlowColorIdx];
zeus::CColor color = {c[0] / 255.f, c[1] / 255.f, c[2] / 255.f, alpha};
x22c_ballInnerGlowGen->SetModulationColor(color);
if (alpha > 0.f) {
if (x22c_ballInnerGlowGen->GetNumActiveChildParticles() > 0) {
const u8* c = CMorphBall::BallTransFlashColors[x1e8_ballGlowColorIdx];
2017-05-06 05:21:42 +00:00
zeus::CColor color = {c[0] / 255.f, c[1] / 255.f, c[2] / 255.f, alpha};
2018-12-08 05:30:43 +00:00
x22c_ballInnerGlowGen->GetActiveChildParticle(0).SetModulationColor(color);
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
if (x22c_ballInnerGlowGen->GetNumActiveChildParticles() > 1) {
const u8* c = CMorphBall::BallAuxGlowColors[x1e8_ballGlowColorIdx];
zeus::CColor color = {c[0] / 255.f, c[1] / 255.f, c[2] / 255.f, alpha};
x22c_ballInnerGlowGen->GetActiveChildParticle(1).SetModulationColor(color);
2017-05-06 05:21:42 +00:00
}
2018-12-08 05:30:43 +00:00
}
x22c_ballInnerGlowGen->Render();
2017-05-06 05:21:42 +00:00
}
2018-12-08 05:30:43 +00:00
if (x270_24_hasSpiderBall) {
CGraphics::SetModelMatrix(x10_ballXf);
CModelFlags flags = {};
flags.x1_matSetIdx = x1e4_glassMatIdx;
x1d4_spiderBallGlass->GetInstance().ActivateLights(x23c_lights);
flags.m_extendedShader = EExtendedShader::SolidColorBackfaceCullLEqualAlphaOnly;
flags.x4_color = zeus::skWhite;
2018-12-08 05:30:43 +00:00
x1d4_spiderBallGlass->Draw(flags);
flags.m_extendedShader = EExtendedShader::ForcedAlpha;
flags.x4_color = zeus::skWhite;
2018-12-08 05:30:43 +00:00
flags.x4_color.a() = alpha;
x1d4_spiderBallGlass->Draw(flags);
flags.m_extendedShader = EExtendedShader::ForcedAdditive;
flags.x4_color = zeus::skWhite;
2018-12-08 05:30:43 +00:00
flags.x4_color.a() = x6c_ballPulseFactor * alpha * itemPulse;
x1d4_spiderBallGlass->Draw(flags);
2017-05-06 05:21:42 +00:00
}
2018-12-08 05:30:43 +00:00
}
if (x238_ballTransitionFlashGen) {
const u8* c = CMorphBall::BallTransFlashColors[x1e8_ballGlowColorIdx];
zeus::CColor color = {c[0] / 255.f, c[1] / 255.f, c[2] / 255.f, 1.f};
x238_ballTransitionFlashGen->SetModulationColor(color);
x238_ballTransitionFlashGen->Render();
}
2017-05-06 05:21:42 +00:00
2018-12-08 05:30:43 +00:00
CGraphics::DisableAllLights();
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
void CSamusDoll::Touch() {
if (!CheckLoadComplete())
return;
xc8_suitModel0->AnimationData()->PreRender();
x134_suitModelBoots->AnimationData()->PreRender();
x184_ballModelData->AnimationData()->PreRender();
xc8_suitModel0->Touch(CModelData::EWhichModel::Normal, 0);
x134_suitModelBoots->Touch(CModelData::EWhichModel::Normal, 0);
x184_ballModelData->Touch(CModelData::EWhichModel::Normal, 0);
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
void CSamusDoll::SetupLights() {
x23c_lights[0] = CLight::BuildDirectional(xb0_userRot.toTransform().basis[1], zeus::CColor(0.75f, 1.f));
x24c_actorLights->BuildFakeLightList(x23c_lights, zeus::skBlack);
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
void CSamusDoll::SetInMorphball(bool morphball) {
if (x54_remTransitionTime > 0.f)
return;
if (x4d_selectedMorphball == morphball)
return;
x4d_selectedMorphball = morphball;
SetTransitionAnimation();
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
void CSamusDoll::SetTransitionAnimation() {
if (!x4c_completedMorphball) {
/* Into morphball */
xc8_suitModel0->AnimationData()->SetAnimation(CAnimPlaybackParms{0, -1, 1.f, true}, false);
x134_suitModelBoots->AnimationData()->SetAnimation(CAnimPlaybackParms{0, -1, 1.f, true}, false);
x50_totalTransitionTime = x54_remTransitionTime = xc8_suitModel0->GetAnimationData()->GetAnimationDuration(0);
} else if (!x4d_selectedMorphball) {
/* Outta morphball */
xc8_suitModel0->AnimationData()->SetAnimation(CAnimPlaybackParms{1, -1, 1.f, true}, false);
x134_suitModelBoots->AnimationData()->SetAnimation(CAnimPlaybackParms{1, -1, 1.f, true}, false);
x50_totalTransitionTime = x54_remTransitionTime = xc8_suitModel0->GetAnimationData()->GetAnimationDuration(1);
}
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
void CSamusDoll::SetRotationSfxPlaying(bool playing) {
if (playing) {
if (x268_rotateSfx)
return;
x268_rotateSfx = CSfxManager::SfxStart(SFXui_map_rotate, 1.f, 0.f, false, 0x7f, true, kInvalidAreaId);
} else {
CSfxManager::SfxStop(x268_rotateSfx);
x268_rotateSfx.reset();
}
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
void CSamusDoll::SetOffsetSfxPlaying(bool playing) {
if (playing) {
if (x264_offsetSfx)
return;
x264_offsetSfx = CSfxManager::SfxStart(SFXui_map_pan, 1.f, 0.f, false, 0x7f, true, kInvalidAreaId);
} else {
CSfxManager::SfxStop(x264_offsetSfx);
x264_offsetSfx.reset();
}
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
void CSamusDoll::SetZoomSfxPlaying(bool playing) {
if (playing) {
if (x26c_zoomSfx)
return;
x26c_zoomSfx = CSfxManager::SfxStart(SFXui_map_zoom, 1.f, 0.f, false, 0x7f, true, kInvalidAreaId);
} else {
CSfxManager::SfxStop(x26c_zoomSfx);
x26c_zoomSfx.reset();
}
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
void CSamusDoll::SetRotation(float xDelta, float zDelta, float dt) {
if (xc4_viewInterp != 0.f && xc4_viewInterp != 1.f)
return;
SetRotationSfxPlaying(xDelta != 0.f || zDelta != 0.f);
zeus::CEulerAngles angles(xb0_userRot);
2017-05-04 18:56:20 +00:00
2018-12-08 05:30:43 +00:00
zeus::CRelAngle angX(angles.x());
2018-12-17 03:52:51 +00:00
angX.makeRel();
2018-12-08 05:30:43 +00:00
zeus::CRelAngle angZ(angles.z());
2018-12-17 03:52:51 +00:00
angZ.makeRel();
2017-05-04 18:56:20 +00:00
2018-12-08 05:30:43 +00:00
angX += xDelta;
2018-12-17 03:52:51 +00:00
angX.makeRel();
2018-12-08 05:30:43 +00:00
angZ += zDelta;
2018-12-17 03:52:51 +00:00
angZ.makeRel();
2017-05-04 18:56:20 +00:00
2018-12-08 05:30:43 +00:00
float angXCenter = angX;
if (angXCenter > M_PIF)
angXCenter -= 2.f * M_PIF;
angXCenter = zeus::clamp(-1.555f, angXCenter, 1.555f);
2017-05-04 18:56:20 +00:00
2018-12-08 05:30:43 +00:00
zeus::CQuaternion quat;
2018-12-17 03:52:51 +00:00
quat.rotateZ(angZ);
quat.rotateX(zeus::CRelAngle(angXCenter).asRel());
2018-12-08 05:30:43 +00:00
xb0_userRot = quat;
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
void CSamusDoll::SetOffset(const zeus::CVector3f& offset, float dt) {
if (xc4_viewInterp != 0.f && xc4_viewInterp != 1.f)
return;
zeus::CVector3f oldOffset = xa4_offset;
zeus::CMatrix3f rotMtx = xb0_userRot.toTransform().basis;
xa4_offset += rotMtx * zeus::CVector3f(offset.x(), 0.f, offset.z());
SetOffsetSfxPlaying((oldOffset - xa4_offset).magnitude() > dt);
float oldZoom = xc0_userZoom;
xc0_userZoom = zeus::clamp(-4.f, xc0_userZoom + offset.y(), -2.2f);
bool zoomSfx = std::fabs(xc0_userZoom - oldZoom) > dt;
float zoomDelta = offset.y() - (xc0_userZoom - oldZoom);
zeus::CVector3f newOffset = rotMtx[1] * zoomDelta + xa4_offset;
zeus::CVector3f delta = newOffset - xa4_offset;
oldOffset = xa4_offset;
if (!delta.isZero()) {
zeus::CSphere sphere(skInitialOffset, 1.f);
float T;
zeus::CVector3f point;
if (CollisionUtil::RaySphereIntersection(sphere, xa4_offset, delta.normalized(), 0.f, T, point)) {
if ((point - xa4_offset).magnitude() < std::fabs(zoomDelta))
xa4_offset = point;
else
xa4_offset = newOffset;
} else {
xa4_offset = newOffset;
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
}
if ((oldOffset - xa4_offset).magnitude() > dt)
zoomSfx = true;
SetZoomSfxPlaying(zoomSfx);
delta = xa4_offset - skInitialOffset;
if (delta.magnitude() > 1.f)
xa4_offset = delta.normalized() + skInitialOffset;
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
void CSamusDoll::BeginViewInterpolate(bool zoomIn) {
if (xc4_viewInterp == 0.f) {
CSfxManager::SfxStart(SFXui_samus_doll_enter, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
} else {
SetOffsetSfxPlaying(false);
SetZoomSfxPlaying(false);
SetRotationSfxPlaying(false);
CSfxManager::SfxStart(SFXui_samus_doll_exit, 1.f, 0.f, false, 0x7f, false, kInvalidAreaId);
}
xc4_viewInterp = zoomIn ? FLT_EPSILON : (-1.f + FLT_EPSILON);
x84_interpStartOffset = xa4_offset;
x90_userInterpRot = xb0_userRot;
xa0_userInterpZoom = xc0_userZoom;
x80_fixedZoom = zoomIn ? -2.2f : -3.6f;
2017-05-04 18:56:20 +00:00
}
2018-12-08 05:30:43 +00:00
} // namespace urde::MP1