prime/src/MetroidPrime/CExplosion.cpp

157 lines
5.6 KiB
C++

#include "MetroidPrime/CExplosion.hpp"
#include "MetroidPrime/CGameLight.hpp"
#include "MetroidPrime/CStateManager.hpp"
#include "MetroidPrime/Player/CPlayerState.hpp"
#include "Kyoto/Graphics/CCubeModel.hpp"
#include "Kyoto/Graphics/CGraphics.hpp"
#include "Kyoto/Math/CFrustumPlanes.hpp"
#include "Kyoto/Particles/CElementGen.hpp"
#include "Kyoto/Particles/CGenDescription.hpp"
#include "Kyoto/Particles/CParticleElectric.hpp"
#include "MetaRender/CCubeRenderer.hpp"
CExplosion::CExplosion(const TLockedToken< CGenDescription >& particle, TUniqueId uid, bool active,
const CEntityInfo& info, const rstl::string& name, const CTransform4f& xf,
uint flags, const CVector3f& scale, const CColor& color)
: CEffect(uid, info, active, name, xf)
, xe8_particleGen(rs_new CElementGen(TToken< CGenDescription >(particle), CElementGen::kMOT_Normal,
flags & 0x2 ? CElementGen::kOSF_Two : CElementGen::kOSF_One))
, xec_explosionLight(kInvalidUniqueId)
, xf0_sourceId(CToken(particle).GetTag().GetId())
, xf4_24_renderThermalHot(flags & 0x4)
, xf4_25_hasRenderBounds(true)
, xf4_26_renderXray(flags & 0x8)
, xf8_time(0.0f) {
SetThermalFlags(flags & 0x1 ? kTF_Cold : kTF_Hot);
xe8_particleGen->SetGlobalTranslation(xf.GetTranslation());
xe8_particleGen->SetOrientation(xf.GetRotation());
xe8_particleGen->SetGlobalScale(scale);
xe8_particleGen->SetModulationColor(color);
}
CExplosion::CExplosion(const TLockedToken< CElectricDescription >& electric, TUniqueId uid,
bool active, const CEntityInfo& info, const rstl::string& name,
const CTransform4f& xf, uint flags, const CVector3f& scale,
const CColor& color)
: CEffect(uid, info, active, name, xf)
, xe8_particleGen(rs_new CParticleElectric(electric))
, xec_explosionLight(kInvalidUniqueId)
, xf0_sourceId(CToken(electric).GetTag().GetId())
, xf4_24_renderThermalHot(flags & 0x4)
, xf4_25_hasRenderBounds(true)
, xf4_26_renderXray(flags & 0x8)
#if NONMATCHING
, xf8_time(0.0f)
#endif
{
SetThermalFlags(flags & 0x1 ? kTF_Cold : kTF_Hot);
xe8_particleGen->SetGlobalTranslation(xf.GetTranslation());
xe8_particleGen->SetOrientation(xf.GetRotation());
xe8_particleGen->SetGlobalScale(scale);
xe8_particleGen->SetModulationColor(color);
}
CExplosion::~CExplosion() {}
void CExplosion::AddToRenderer(const CFrustumPlanes& frustum, const CStateManager& mgr) const {
if (GetPreRenderClipped()) {
return;
}
if ((xf4_24_renderThermalHot && mgr.GetThermalDrawFlag() == kTD_Hot) ||
(xf4_26_renderXray && mgr.GetPlayerState()->GetActiveVisor(mgr) == CPlayerState::kPV_XRay)) {
EnsureRendered(mgr);
} else {
gpRender->AddParticleGen(*xe8_particleGen);
}
}
void CExplosion::PreRender(CStateManager& mgr, const CFrustumPlanes& frustum) {
CActor::PreRender(mgr, frustum);
SetPreRenderClipped(!xf4_25_hasRenderBounds || !frustum.BoxInFrustumPlanes(GetRenderBoundsCached()));
}
void CExplosion::Think(float dt, CStateManager& mgr) {
if (GetTransformDirtySpare()) {
xe8_particleGen->SetGlobalTranslation(GetTranslation());
xe8_particleGen->SetOrientation(GetTransform().GetRotation());
SetTransformDirtySpare(false);
}
xe8_particleGen->Update(dt);
if (xec_explosionLight != kInvalidUniqueId) {
CGameLight* light = TCastToPtr< CGameLight >(mgr.ObjectById(xec_explosionLight));
if (light && GetActive())
light->SetLight(xe8_particleGen->GetLight());
}
xf8_time += dt;
if (xf8_time > 15.f) {
mgr.DeleteObjectRequest(GetUniqueId());
} else if (xe8_particleGen->IsSystemDeletable()) {
mgr.DeleteObjectRequest(GetUniqueId());
}
}
void CExplosion::Accept(IVisitor& visitor) { visitor.Visit(*this); }
void CExplosion::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId sender, CStateManager& mgr) {
switch (msg) {
case kSM_Registered:
if (xe8_particleGen->SystemHasLight()) {
xec_explosionLight = mgr.AllocateUniqueId();
uint sourceId = xf0_sourceId;
mgr.AddObject(rs_new CGameLight(xec_explosionLight, GetCurrentAreaId(), GetActive(),
rstl::string_l("ExplodePLight_") + GetDebugName(),
GetTransform(), GetUniqueId(), xe8_particleGen->GetLight(),
sourceId, 1, 0.f));
}
break;
case kSM_Deleted:
if (xec_explosionLight != kInvalidUniqueId) {
mgr.DeleteObjectRequest(xec_explosionLight);
xec_explosionLight = kInvalidUniqueId;
}
break;
default:
break;
}
CActor::AcceptScriptMsg(msg, sender, mgr);
if (xec_explosionLight != kInvalidUniqueId)
mgr.SendScriptMsgAlways(xec_explosionLight, sender, msg);
}
void CExplosion::CalculateRenderBounds() {
rstl::optional_object< CAABox > bounds = xe8_particleGen->GetBounds();
if (bounds) {
SetRenderBounds(*bounds);
xf4_25_hasRenderBounds = true;
} else {
xf4_25_hasRenderBounds = false;
CVector3f pos = GetTransform().GetTranslation();
SetRenderBounds(CAABox(pos, pos));
}
}
void CExplosion::Render(const CStateManager& mgr) const {
if (mgr.GetThermalDrawFlag() == kTD_Hot && xf4_24_renderThermalHot) {
CElementGen::SetSubtractBlend(true);
CCubeModel::SetRenderModelBlack(true);
xe8_particleGen->Render();
CCubeModel::SetRenderModelBlack(false);
CElementGen::SetSubtractBlend(false);
return;
}
CElementGen::SetSubtractBlend(!xf4_24_renderThermalHot);
CGraphics::SetFog(kRFM_PerspLin, 0.f, 75.f, CColor::Black());
xe8_particleGen->Render();
mgr.SetupFogForArea(GetCurrentAreaId());
CElementGen::SetSubtractBlend(false);
}