diff --git a/Runtime/Graphics/CSimpleShadow.cpp b/Runtime/Graphics/CSimpleShadow.cpp index c515c8e14..cc3ae221d 100644 --- a/Runtime/Graphics/CSimpleShadow.cpp +++ b/Runtime/Graphics/CSimpleShadow.cpp @@ -42,8 +42,7 @@ void CSimpleShadow::Render(TLockedToken& tex) { ERglLogicOp::Clear); CGraphics::StreamBegin(GX::QUADS); float radius = x34_radius * x30_scale; - float t = x3c_heightAlpha * x38_userAlpha; - CGraphics::StreamColor(zeus::CColor{t, t} /* TODO double check */); + CGraphics::StreamColor(zeus::CColor{1.f, x3c_heightAlpha * x38_userAlpha}); CGraphics::StreamTexcoord(0.f, 0.f); CGraphics::StreamVertex(-radius, 0.f, -radius); CGraphics::StreamTexcoord(0.f, 1.f); diff --git a/Runtime/MP1/World/CDrone.cpp b/Runtime/MP1/World/CDrone.cpp index c6a396e1c..e2732532d 100644 --- a/Runtime/MP1/World/CDrone.cpp +++ b/Runtime/MP1/World/CDrone.cpp @@ -934,8 +934,8 @@ void CDrone::SetVisorFlareEnabled(CStateManager& mgr, bool activate) { x57a_visorFlareId = mgr.AllocateUniqueId(); flare = new CScriptVisorFlare(x57a_visorFlareId, "DroneVisorFlare"sv, CEntityInfo{GetAreaIdAlways(), CEntity::NullConnectionList}, activate, - GetLctrTransform("Beacon_LCTR"sv).origin, CVisorFlare::EBlendMode::Zero, true, 0.1f, - 1.f, 2.f, 0, 0, x57c_flares); + GetLctrTransform("Beacon_LCTR"sv).origin, CVisorFlare::EBlendMode::Additive, true, + 0.1f, 1.f, 2.f, 0, 0, x57c_flares); mgr.AddObject(flare); } mgr.SendScriptMsg(flare, GetUniqueId(), activate ? EScriptObjectMessage::Activate : EScriptObjectMessage::Deactivate); diff --git a/Runtime/World/CScriptVisorFlare.cpp b/Runtime/World/CScriptVisorFlare.cpp index 076c13c19..68432b194 100644 --- a/Runtime/World/CScriptVisorFlare.cpp +++ b/Runtime/World/CScriptVisorFlare.cpp @@ -14,7 +14,8 @@ CScriptVisorFlare::CScriptVisorFlare(TUniqueId uid, std::string_view name, const float f2, float f3, u32 w1, u32 w2, std::vector flares) : CActor(uid, active, name, info, zeus::CTransform::Translate(pos), CModelData::CModelDataNull(), CMaterialList(EMaterialTypes::NoStepLogic), CActorParameters::None(), kInvalidUniqueId) -, xe8_flare(blendMode, b1, f1, f2, f3, w1, w2, std::move(flares)) { +, xe8_flare(blendMode, b1, f1, f2, f3, w1, w2, std::move(flares)) +, x11c_notInRenderLast(true) { xe6_27_thermalVisorFlags = 2; } diff --git a/Runtime/World/CVisorFlare.cpp b/Runtime/World/CVisorFlare.cpp index d06ce9210..2d340f67a 100644 --- a/Runtime/World/CVisorFlare.cpp +++ b/Runtime/World/CVisorFlare.cpp @@ -6,6 +6,8 @@ #include "Runtime/GameGlobalObjects.hpp" #include "Runtime/CStateManager.hpp" #include "Runtime/CSimplePool.hpp" +#include "Runtime/Graphics/CCubeRenderer.hpp" +#include "Runtime/Graphics/CGX.hpp" namespace metaforce { @@ -31,7 +33,7 @@ CVisorFlare::CVisorFlare(EBlendMode blendMode, bool b1, float f1, float f2, floa : x0_blendMode(blendMode) , x4_flareDefs(std::move(flares)) , x14_b1(b1) -, x18_f1(std::max(f1, FLT_EPSILON)) +, x18_f1(std::max(f1, 1.0E-4f)) , x1c_f2(f2) , x20_f3(f3) , x2c_w1(w1) @@ -45,56 +47,182 @@ void CVisorFlare::Update(float dt, const zeus::CVector3f& pos, const CActor* act zeus::CVector3f camPos = mgr.GetCameraManager()->GetCurrentCamera(mgr)->GetTranslation(); zeus::CVector3f camDiff = pos - camPos; - const float mag = (camDiff.magnitude()); + const float mag = camDiff.magnitude(); + camDiff = camDiff * (1.f / mag); EntityList nearVec; - mgr.BuildNearList(nearVec, camPos, camDiff * (1.f / mag), mag, + mgr.BuildNearList(nearVec, camPos, camDiff, mag, CMaterialFilter::MakeInclude({EMaterialTypes::Occluder}), act); TUniqueId id; CRayCastResult result = mgr.RayWorldIntersection( id, camPos, camDiff, mag, CMaterialFilter::MakeIncludeExclude({EMaterialTypes::Solid}, {EMaterialTypes::SeeThrough}), nearVec); - if (result.IsValid()) { - x28_ -= mag; + if (result.IsInvalid()) { + x28_ -= dt; } else { - x28_ += mag; + x28_ += dt; } x28_ = zeus::clamp(0.f, x28_, x18_f1); x24_ = 1.f - (x28_ / x18_f1); - const CGameCamera* curCam = mgr.GetCameraManager()->GetCurrentCamera(mgr); - x24_ *= std::max( - 0.f, 1.f - (4.f * x1c_f2 * (1.f - (pos - curCam->GetTranslation()).dot(curCam->GetTransform().basis[1])))); + const auto* curCam = mgr.GetCameraManager()->GetCurrentCamera(mgr); + const auto dir = (pos - curCam->GetTranslation()).normalized(); + float dot = dir.dot(curCam->GetTransform().frontVector()); + x24_ *= std::max(0.f, 1.f - (x1c_f2 * 4.f * (1.f - dot))); if (x2c_w1 == 2) { mgr.SetThermalColdScale2(mgr.GetThermalColdScale2() + x24_); } - - //#ifndef NDEBUG - // printf("%08X %f %f\n", act->GetEditorId().id, x24_, x28_); - //#endif } } void CVisorFlare::Render(const zeus::CVector3f& pos, const CStateManager& mgr) const { - if (zeus::close_enough(x28_, x18_f1) && - mgr.GetPlayer().GetMorphballTransitionState() == CPlayer::EPlayerMorphBallState::Unmorphed) { - int iVar; - const auto visor = mgr.GetPlayerState()->GetActiveVisor(mgr); - if (visor == CPlayerState::EPlayerVisor::Thermal) { - iVar = x2c_w1; - } else if (visor == CPlayerState::EPlayerVisor::XRay) { - return; - } else { - iVar = x30_w2; + if (zeus::close_enough(x28_, x18_f1, 1.0E-5f) || + mgr.GetPlayer().GetMorphballTransitionState() != CPlayer::EPlayerMorphBallState::Unmorphed) { + return; + } + SCOPED_GRAPHICS_DEBUG_GROUP("CVisorFlare::Render", zeus::skGrey); + + u32 type; + const auto visor = mgr.GetPlayerState()->GetActiveVisor(mgr); + if (visor == CPlayerState::EPlayerVisor::Thermal) { + type = x2c_w1; + } else if (visor == CPlayerState::EPlayerVisor::XRay) { + return; + } else { + type = x30_w2; + } + if (type != 0) { + return; + } + + CGraphics::DisableAllLights(); + g_Renderer->SetDepthReadWrite(false, false); + const CGameCamera* cam = mgr.GetCameraManager()->GetCurrentCamera(mgr); + zeus::CVector3f camPos = cam->GetTranslation(); + zeus::CVector3f camFront = cam->GetTransform().frontVector(); + const auto invPos = CGraphics::g_ViewMatrix.inverse() * pos; + const auto invPos2 = CGraphics::g_ViewMatrix * zeus::CVector3f{-invPos.x(), invPos.y(), -invPos.z()}; + if (!zeus::close_enough(x24_, 0.f, 1.0E-5f)) { + float acos = 0.f; + if (!zeus::close_enough(x20_f3, 0.f, 1.0E-5f)) { + zeus::CVector3f camDist{pos.x() - camPos.x(), pos.y() - camPos.y(), 0.f}; + camDist.normalize(); + zeus::CVector3f camDir{camFront.x(), camFront.y(), 0.f}; + camDir.normalize(); + acos = std::acos(camDist.dot(camDir)); + if (camDist.x() * camDir.y() - camDir.x() * camDist.y() < 0.f) { + acos = -acos; + } + acos = x20_f3 * acos; } - if (iVar != 0) - return; - CGraphics::DisableAllLights(); - // g_Renderer->SetDepthReadWrite(false, false); - // const CGameCamera* cam = mgr.GetCameraManager()->GetCurrentCamera(mgr); - // zeus::CVector3f camPos = cam->GetTranslation(); + SetupRenderState(mgr); + for (const auto& item : x4_flareDefs) { + const auto origin = pos * (1.f - item.GetPosition()) + invPos2 * item.GetPosition(); + g_Renderer->SetModelMatrix(zeus::lookAt(origin, camPos)); + float scale = 0.5f * x24_ * item.GetScale(); + if (x14_b1) { + auto dist = origin - camPos; + if (dist.canBeNormalized()) { + scale *= dist.magnitude(); + } + } + if (item.GetTexture()) { + item.GetTexture()->Load(GX::TEXMAP0, EClampMode::Repeat); + float f1; + if (zeus::close_enough(acos, 0.f)) { + f1 = 0.f; + } else { + f1 = scale * std::sin(acos); + scale *= std::cos(acos); + } + if (mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot) { + DrawDirect(item.GetColor(), f1, scale); + } else { + DrawStreamed(item.GetColor(), f1, scale); + } + } + } + ResetTevSwapMode(mgr); } } +void CVisorFlare::SetupRenderState(const CStateManager& mgr) const { + if (mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot) { + CGX::SetBlendMode(GX::BM_BLEND, GX::BL_ONE, GX::BL_ONE, GX::LO_CLEAR); + CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0); + CGX::SetTevOrder(GX::TEVSTAGE0, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL); + CGX::SetAlphaCompare(GX::ALWAYS, 0, GX::AOP_OR, GX::ALWAYS, 0); + GXSetTevSwapMode(GX::TEVSTAGE0, GX::TEV_SWAP0, GX::TEV_SWAP1); + CGX::SetTevKColorSel(GX::TEVSTAGE0, GX::TEV_KCSEL_K0_A); + CGX::SetTevKAlphaSel(GX::TEVSTAGE0, GX::TEV_KASEL_K0_A); + CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_TEXC, GX::CC_KONST, GX::CC_ZERO); + CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_TEXA, GX::CA_KONST, GX::CA_ZERO); + CGX::SetNumTexGens(1); + CGX::SetNumChans(0); + CGX::SetTexCoordGen(GX::TEXCOORD0, GX::TG_MTX2x4, GX::TG_TEX0, GX::IDENTITY, false, GX::PTIDENTITY); + if (x0_blendMode == EBlendMode::Blend) { + CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE1); + CGX::SetTevOrder(GX::TEVSTAGE1, GX::TEXCOORD0, GX::TEXMAP0, GX::COLOR_NULL); + CGX::SetTevColorIn(GX::TEVSTAGE1, GX::CC_ZERO, GX::CC_TEXA, GX::CC_CPREV, GX::CC_ZERO); + CGX::SetTevAlphaIn(GX::TEVSTAGE1, GX::CA_ZERO, GX::CA_TEXA, GX::CA_APREV, GX::CA_ZERO); + CGX::SetNumTevStages(2); + } else if (x0_blendMode == EBlendMode::Additive) { + CGX::SetNumTevStages(1); + } + constexpr std::array vtxDescList{ + GX::VtxDescList{GX::VA_POS, GX::DIRECT}, + GX::VtxDescList{GX::VA_TEX0, GX::DIRECT}, + GX::VtxDescList{}, + }; + CGX::SetVtxDescv(vtxDescList.data()); + } else { + if (x0_blendMode == EBlendMode::Blend) { + g_Renderer->SetBlendMode_AlphaBlended(); + } else if (x0_blendMode == EBlendMode::Additive) { + g_Renderer->SetBlendMode_AdditiveAlpha(); + } + CGraphics::SetTevOp(ERglTevStage::Stage0, CTevCombiners::sTevPass805a5ebc); + CGraphics::SetTevOp(ERglTevStage::Stage1, CTevCombiners::skPassThru); + } +} + +void CVisorFlare::ResetTevSwapMode(const CStateManager& mgr) const { + if (mgr.GetThermalDrawFlag() == EThermalDrawFlag::Hot) { + GXSetTevSwapMode(GX::TEVSTAGE0, GX::TEV_SWAP0, GX::TEV_SWAP0); + } +} + +void CVisorFlare::DrawDirect(const zeus::CColor& color, float f1, float f2) const { + zeus::CColor kcolor = color; + kcolor.a() *= x24_; + CGX::SetTevKColor(GX::KCOLOR0, kcolor); + CGX::Begin(GX::TRIANGLESTRIP, GX::VTXFMT0, 4); + GXPosition3f32(f1 - f2, 0.f, f2 + f1); + GXTexCoord2f32(0.f, 1.f); + GXPosition3f32(f2 + f1, 0.f, f2 - f1); + GXTexCoord2f32(1.f, 1.f); + GXPosition3f32(-(f2 - f1), 0.f, -(f2 - f1)); + GXTexCoord2f32(0.f, 0.f); + GXPosition3f32(-f1 + f2, 0.f, -f2 - f1); + GXTexCoord2f32(1.f, 0.f); + CGX::End(); +} + +void CVisorFlare::DrawStreamed(const zeus::CColor& color, float f1, float f2) const { + CGraphics::StreamBegin(GX::TRIANGLESTRIP); + zeus::CColor kcolor = color; + kcolor.a() *= x24_; + CGraphics::StreamColor(kcolor); + CGraphics::StreamTexcoord(0.f, 1.f); + CGraphics::StreamVertex(f1 - f2, 0.f, f2 + f1); + CGraphics::StreamTexcoord(1.f, 1.f); + CGraphics::StreamVertex(f1 + f2, 0.f, f2 - f1); + CGraphics::StreamTexcoord(0.f, 0.f); + CGraphics::StreamVertex(-(f1 + f2), 0.f, -(f2 - f1)); + CGraphics::StreamTexcoord(1.f, 0.f); + CGraphics::StreamVertex(-f1 + f2, 0.f, -f2 - f1); + CGraphics::StreamEnd(); +} + } // namespace metaforce diff --git a/Runtime/World/CVisorFlare.hpp b/Runtime/World/CVisorFlare.hpp index db0370629..06d8d09d0 100644 --- a/Runtime/World/CVisorFlare.hpp +++ b/Runtime/World/CVisorFlare.hpp @@ -16,26 +16,27 @@ class CTexture; class CVisorFlare { public: enum class EBlendMode { - Zero = 0, + Additive = 0, + Blend = 1, }; class CFlareDef { - TToken x0_tex; - float x8_f1; - float xc_f2; + mutable TToken x0_tex; + float x8_pos; + float xc_scale; zeus::CColor x10_color; public: CFlareDef() = default; CFlareDef(const CFlareDef&) = default; - CFlareDef(const TToken& tex, float f1, float f2, const zeus::CColor& color) - : x0_tex(tex), x8_f1(f1), xc_f2(f2), x10_color(color) { + CFlareDef(const TToken& tex, float pos, float scale, const zeus::CColor& color) + : x0_tex(tex), x8_pos(pos), xc_scale(scale), x10_color(color) { x0_tex.Lock(); } - TToken GetTexture() const { return x0_tex; } + TToken& GetTexture() const { return x0_tex; } zeus::CColor GetColor() const { return x10_color; } - float GetScale() const; - float GetPosition() const; + float GetPosition() const { return x8_pos; } + float GetScale() const { return xc_scale; } }; private: @@ -50,6 +51,11 @@ private: u32 x2c_w1; u32 x30_w2; + void SetupRenderState(const CStateManager& mgr) const; + void ResetTevSwapMode(const CStateManager& mgr) const; + void DrawDirect(const zeus::CColor& color, float f1, float f2) const; + void DrawStreamed(const zeus::CColor& color, float f1, float f2) const; + public: CVisorFlare(EBlendMode blendMode, bool, float, float, float, u32, u32, std::vector flares); void Update(float dt, const zeus::CVector3f& pos, const CActor* act, CStateManager& mgr);