From 19877f6fa2333f255ab922692f77e279ab64789e Mon Sep 17 00:00:00 2001 From: Henrique Gemignani Passos Lima Date: Thu, 17 Nov 2022 06:56:21 +0200 Subject: [PATCH] Add CSimpleShadow --- asm/MetroidPrime/CSimpleShadow.s | 4 +- asm/MetroidPrime/Enemies/CAi.s | 2 +- asm/MetroidPrime/Enemies/CFlaahgra.s | 2 +- configure.py | 2 +- include/Collision/CMaterialFilter.hpp | 2 + include/Collision/CRayCastResult.hpp | 1 + include/Kyoto/Graphics/CGraphics.hpp | 1 + include/Kyoto/Graphics/CTevCombiners.hpp | 2 - include/MetroidPrime/CGameCollision.hpp | 5 + include/MetroidPrime/CSimpleShadow.hpp | 29 ++++- include/MetroidPrime/CStateManager.hpp | 3 + src/MetroidPrime/CSimpleShadow.cpp | 125 +++++++++++++++++++++ src/MetroidPrime/Cameras/CCameraFilter.cpp | 2 +- 13 files changed, 167 insertions(+), 13 deletions(-) create mode 100644 src/MetroidPrime/CSimpleShadow.cpp diff --git a/asm/MetroidPrime/CSimpleShadow.s b/asm/MetroidPrime/CSimpleShadow.s index 5a879ed5..c7ee553e 100644 --- a/asm/MetroidPrime/CSimpleShadow.s +++ b/asm/MetroidPrime/CSimpleShadow.s @@ -191,8 +191,8 @@ GetBounds__13CSimpleShadowCFv: /* 80105CE8 00102C48 38 21 00 30 */ addi r1, r1, 0x30 /* 80105CEC 00102C4C 4E 80 00 20 */ blr -.global sub_80105cf0 -sub_80105cf0: +.global SetAlwaysCalculateRadius__13CSimpleShadowFb +SetAlwaysCalculateRadius__13CSimpleShadowFb: /* 80105CF0 00102C50 88 03 00 48 */ lbz r0, 0x48(r3) /* 80105CF4 00102C54 50 80 36 72 */ rlwimi r0, r4, 6, 0x19, 0x19 /* 80105CF8 00102C58 98 03 00 48 */ stb r0, 0x48(r3) diff --git a/asm/MetroidPrime/Enemies/CAi.s b/asm/MetroidPrime/Enemies/CAi.s index 8a04ee4d..baf7432b 100644 --- a/asm/MetroidPrime/Enemies/CAi.s +++ b/asm/MetroidPrime/Enemies/CAi.s @@ -2251,7 +2251,7 @@ lbl_800A2DE4: /* 800A30C0 000A0020 4B FA FC AD */ bl CreateShadow__6CActorFb /* 800A30C4 000A0024 80 7F 00 94 */ lwz r3, 0x94(r31) /* 800A30C8 000A0028 38 80 00 00 */ li r4, 0 -/* 800A30CC 000A002C 48 06 2C 25 */ bl sub_80105cf0 +/* 800A30CC 000A002C 48 06 2C 25 */ bl SetAlwaysCalculateRadius__13CSimpleShadowFb lbl_800A30D0: /* 800A30D0 000A0030 80 9F 00 90 */ lwz r4, 0x90(r31) /* 800A30D4 000A0034 28 04 00 00 */ cmplwi r4, 0 diff --git a/asm/MetroidPrime/Enemies/CFlaahgra.s b/asm/MetroidPrime/Enemies/CFlaahgra.s index 017e06ba..4975339f 100644 --- a/asm/MetroidPrime/Enemies/CFlaahgra.s +++ b/asm/MetroidPrime/Enemies/CFlaahgra.s @@ -625,7 +625,7 @@ sub_801ad790: /* 801AD7E0 001AA740 4B EA 55 8D */ bl CreateShadow__6CActorFb /* 801AD7E4 001AA744 80 7F 00 94 */ lwz r3, 0x94(r31) /* 801AD7E8 001AA748 38 80 00 00 */ li r4, 0 -/* 801AD7EC 001AA74C 4B F5 85 05 */ bl sub_80105cf0 +/* 801AD7EC 001AA74C 4B F5 85 05 */ bl SetAlwaysCalculateRadius__13CSimpleShadowFb /* 801AD7F0 001AA750 7F E3 FB 78 */ mr r3, r31 /* 801AD7F4 001AA754 38 80 00 02 */ li r4, 2 /* 801AD7F8 001AA758 4B EC F9 19 */ bl BuildBodyController__10CPatternedF9EBodyType diff --git a/configure.py b/configure.py index bced93b1..343cdf7b 100755 --- a/configure.py +++ b/configure.py @@ -156,7 +156,7 @@ LIBS = [ ["MetroidPrime/CDamageVulnerability", False], "MetroidPrime/CActorLights", ["MetroidPrime/Enemies/CPatternedInfo", True], - "MetroidPrime/CSimpleShadow", + ["MetroidPrime/CSimpleShadow", False], ["MetroidPrime/CActorParameters", False], "MetroidPrime/CInGameGuiManager", "MetroidPrime/Enemies/CWarWasp", diff --git a/include/Collision/CMaterialFilter.hpp b/include/Collision/CMaterialFilter.hpp index f3f337dc..f819c301 100644 --- a/include/Collision/CMaterialFilter.hpp +++ b/include/Collision/CMaterialFilter.hpp @@ -31,6 +31,8 @@ public: return CMaterialFilter(include, exclude, kFT_IncludeExclude); } + static const CMaterialFilter& GetPassEverything() { return skPassEverything; } + bool Passes(const CMaterialList& other) const; private: diff --git a/include/Collision/CRayCastResult.hpp b/include/Collision/CRayCastResult.hpp index 2a8045ad..87657ff6 100644 --- a/include/Collision/CRayCastResult.hpp +++ b/include/Collision/CRayCastResult.hpp @@ -20,6 +20,7 @@ public: // TODO: figure out what's going on here bool IsInvalid() const { return x20_valid == kI_Invalid; } // GetPlane__14CRayCastResultCFv + const CPlane& GetPlane() const { return x10_plane; } const CVector3f& GetPoint() const { return x4_point; } // GetMaterial__14CRayCastResultCFv // Transform__14CRayCastResultFRC12CTransform4f diff --git a/include/Kyoto/Graphics/CGraphics.hpp b/include/Kyoto/Graphics/CGraphics.hpp index 52d653b7..8f3f567f 100644 --- a/include/Kyoto/Graphics/CGraphics.hpp +++ b/include/Kyoto/Graphics/CGraphics.hpp @@ -135,6 +135,7 @@ public: static void EndScene(); static void SetTevOp(ERglTevStage stage, const CTevCombiners::CTevPass& pass); static void StreamBegin(ERglPrimitive primitive); + static void StreamColor(uint color); static void StreamColor(const CColor& color); static void StreamTexcoord(float u, float v); static void StreamVertex(float, float, float); diff --git a/include/Kyoto/Graphics/CTevCombiners.hpp b/include/Kyoto/Graphics/CTevCombiners.hpp index d0145013..34eaec9b 100644 --- a/include/Kyoto/Graphics/CTevCombiners.hpp +++ b/include/Kyoto/Graphics/CTevCombiners.hpp @@ -96,7 +96,5 @@ public: }; extern CTevCombiners::CTevPass CTevPass_805a5ebc; -// TODO move to CGraphics -extern CTevCombiners::CTevPass* PTR_skPassThru_805a8828; #endif // _CTEVCOMBINERS diff --git a/include/MetroidPrime/CGameCollision.hpp b/include/MetroidPrime/CGameCollision.hpp index 4fe66529..1e017aa7 100644 --- a/include/MetroidPrime/CGameCollision.hpp +++ b/include/MetroidPrime/CGameCollision.hpp @@ -3,6 +3,8 @@ #include "types.h" +#include "MetroidPrime/CStateManager.hpp" + class CAreaCollisionCache; class CCollisionInfo; class CCollisionPrimitive; @@ -30,6 +32,9 @@ public: TUniqueId&, CCollisionInfo&, double&); static CRayCastResult RayStaticIntersection(const CStateManager&, const CVector3f&, const CVector3f&, float, const CMaterialFilter&); + static CRayCastResult RayDynamicIntersection(const CStateManager& mgr, TUniqueId& idOut, const CVector3f& pos, + const CVector3f& dir, float mag, const CMaterialFilter& filter, + const TEntityList& nearList); static void Move(CStateManager& mgr, CPhysicsActor& actor, float dt, const TEntityList*); }; diff --git a/include/MetroidPrime/CSimpleShadow.hpp b/include/MetroidPrime/CSimpleShadow.hpp index ed417ec2..febcbf1d 100644 --- a/include/MetroidPrime/CSimpleShadow.hpp +++ b/include/MetroidPrime/CSimpleShadow.hpp @@ -3,20 +3,39 @@ #include "types.h" +#include "Kyoto/Math/CTransform4f.hpp" +#include "Kyoto/TToken.hpp" + class CAABox; class CStateManager; -class CTransform4f; +class CTexture; class CSimpleShadow { public: - CAABox GetBounds() const; - const CTransform4f& GetTransform() const; - CAABox GetMaxShadowBox(const CAABox& bounds) const; + CSimpleShadow(float scale, float userAlpha, float maxObjHeight, float displacement); + void Calculate(const CAABox& bounds, const CTransform4f& xf, const CStateManager& mgr); + void Render(const CTexture* tex) const; + const CTransform4f& GetTransform() const; + void SetUserAlpha(float); + float GetMaxObjectHeight() const; + + void SetAlwaysCalculateRadius(bool); + CAABox GetBounds() const; + CAABox GetMaxShadowBox(const CAABox& bounds) const; bool Valid() const; private: - // TODO + CTransform4f x0_xf; + float x30_scale; + float x34_radius; + float x38_userAlpha; + float x3c_heightAlpha; + float x40_maxObjHeight; + float x44_displacement; + bool x48_24_collision : 1; + bool x48_25_alwaysCalculateRadius : 1; + bool x48_26_radiusCalculated : 1; }; #endif // _CSIMPLESHADOW diff --git a/include/MetroidPrime/CStateManager.hpp b/include/MetroidPrime/CStateManager.hpp index 752b4be6..83871d25 100644 --- a/include/MetroidPrime/CStateManager.hpp +++ b/include/MetroidPrime/CStateManager.hpp @@ -139,6 +139,9 @@ public: const CActor*) const; bool RayCollideWorld(const CVector3f& start, const CVector3f& end, const TEntityList& nearList, const CMaterialFilter& filter, const CActor* damagee) const; + + CRayCastResult RayStaticIntersection(const CVector3f& pos, const CVector3f& dir, float length, + const CMaterialFilter& filter) const; CRayCastResult RayWorldIntersection(TUniqueId& idOut, const CVector3f& pos, const CVector3f& dir, float length, const CMaterialFilter& filter, const TEntityList& list) const; diff --git a/src/MetroidPrime/CSimpleShadow.cpp b/src/MetroidPrime/CSimpleShadow.cpp new file mode 100644 index 00000000..f2b7d189 --- /dev/null +++ b/src/MetroidPrime/CSimpleShadow.cpp @@ -0,0 +1,125 @@ +#include "MetroidPrime/CSimpleShadow.hpp" + +#include "MetroidPrime/CGameCollision.hpp" +#include "MetroidPrime/CStateManager.hpp" + +#include "Collision/CMaterialFilter.hpp" +#include "Collision/CRayCastResult.hpp" + +#include "MetaRender/CCubeRenderer.hpp" +#include "Kyoto/Graphics/CColor.hpp" +#include "Kyoto/Graphics/CGraphics.hpp" +#include "Kyoto/Graphics/CTexture.hpp" +#include "Kyoto/Math/CAABox.hpp" + +CSimpleShadow::CSimpleShadow(float scale, float userAlpha, float maxObjHeight, float displacement) +: x0_xf(CTransform4f::Identity()) +, x30_scale(scale) +, x34_radius(1.f) +, x38_userAlpha(userAlpha) +, x3c_heightAlpha(1.f) +, x40_maxObjHeight(maxObjHeight) +, x44_displacement(displacement) +, x48_24_collision(false) +, x48_25_alwaysCalculateRadius(true) +, x48_26_radiusCalculated(false) {} + +void CSimpleShadow::Calculate(const CAABox& aabb, const CTransform4f& xf, + const CStateManager& mgr) { + x48_24_collision = false; + float halfHeight = (aabb.GetMaxPoint().GetZ() - aabb.GetMinPoint().GetZ()) * 0.5f; + float xExtent = aabb.GetMaxPoint().GetX() - aabb.GetMinPoint().GetX(); + float yExtent = aabb.GetMaxPoint().GetY() - aabb.GetMinPoint().GetY(); + + CVector3f pos = xf.GetTranslation() + CVector3f(0.f, 0.f, halfHeight); + CVector3f dir(0.0f, 0.0f, -1.0f); + CRayCastResult res = + mgr.RayStaticIntersection(pos, dir, x40_maxObjHeight, + CMaterialFilter::MakeExclude(CMaterialList(kMT_SeeThrough))); + float height = x40_maxObjHeight; + if (res.IsValid()) { + x48_24_collision = true; + height = res.GetTime(); + } + CVector3f resPoint = res.GetPoint(); + CUnitVector3f resPlaneNormal = res.GetPlane().GetNormal(); + + if (height > 0.1f + halfHeight) { + TEntityList nearList; + mgr.BuildNearList(nearList, pos, dir, x40_maxObjHeight, CMaterialFilter::MakeInclude(CMaterialList(kMT_Floor)), nullptr); + + TUniqueId cid = kInvalidUniqueId; + CRayCastResult resD = + CGameCollision::RayDynamicIntersection(mgr, cid, pos, dir, x40_maxObjHeight, + CMaterialFilter::GetPassEverything(), nearList); + if (resD.IsValid() && resD.GetTime() < height) { + resPoint = resD.GetPoint(); + resPlaneNormal = resD.GetPlane().GetNormal(); + x48_24_collision = true; + height = resD.GetTime(); + } + } + + if (x48_24_collision) { + x3c_heightAlpha = 1.f - height / x40_maxObjHeight; + CVector3f normalVector = resPlaneNormal; + x0_xf = CTransform4f::LookAt(normalVector, CVector3f::Zero()); + x0_xf.SetTranslation(resPoint + x44_displacement * normalVector); + if (x48_25_alwaysCalculateRadius || !x48_26_radiusCalculated) { + x34_radius = sqrtf(xExtent * xExtent + yExtent * yExtent) * 0.5f; + x48_26_radiusCalculated = true; + } + } +} + +void CSimpleShadow::Render(const CTexture* tex) const { + if (!x48_24_collision) + return; + + CGraphics::DisableAllLights(); + gpRender->SetModelMatrix(x0_xf); + tex->Load(GX_TEXMAP0, CTexture::kCM_Repeat); + CGraphics::SetTevOp(kTS_Stage0, CGraphics::kEnvModulate); + CGraphics::SetTevOp(kTS_Stage1, CGraphics::kEnvPassthru); + CGraphics::SetAlphaCompare(kAF_Always, 0, kAO_And, kAF_Always, 0); + CGraphics::SetDepthWriteMode(true, kE_LEqual, false); + CGraphics::SetBlendMode(kBM_Blend, kBF_SrcAlpha, kBF_InvSrcAlpha, kLO_Clear); + float radius = x34_radius * x30_scale; + CGraphics::StreamBegin(kP_Quads); + CGraphics::StreamColor(CCast::ToUint8((x3c_heightAlpha * x38_userAlpha) * 255.f) - 0x100); + CGraphics::StreamTexcoord(0.f, 0.f); + CGraphics::StreamVertex(CVector3f(-radius, 0.f, -radius)); + CGraphics::StreamTexcoord(0.f, 1.f); + CGraphics::StreamVertex(CVector3f(radius, 0.f, -radius)); + CGraphics::StreamTexcoord(1.f, 1.f); + CGraphics::StreamVertex(CVector3f(radius, 0.f, radius)); + CGraphics::StreamTexcoord(1.f, 0.f); + CGraphics::StreamVertex(CVector3f(-radius, 0.f, radius)); + CGraphics::StreamEnd(); +} + +const CTransform4f& CSimpleShadow::GetTransform() const { return x0_xf; } + +void CSimpleShadow::SetUserAlpha(float alpha) { x38_userAlpha = alpha; } + +float CSimpleShadow::GetMaxObjectHeight() const { return x40_maxObjHeight; } + +void CSimpleShadow::SetAlwaysCalculateRadius(bool b) { x48_25_alwaysCalculateRadius = b; } + +CAABox CSimpleShadow::GetBounds() const { + const CVector3f& translation = x0_xf.GetTranslation(); + float extent = x34_radius * x30_scale; + return CAABox(translation - CVector3f(extent, extent, extent), + translation + CVector3f(extent, extent, extent)); +} + +CAABox CSimpleShadow::GetMaxShadowBox(const CAABox& aabb) const { + float extent = x34_radius * x30_scale; + CVector3f center = aabb.GetCenterPoint(); + CAABox expandedAABB = aabb; + expandedAABB.AccumulateBounds(center + CVector3f(extent, extent, -GetMaxObjectHeight())); + expandedAABB.AccumulateBounds(center + CVector3f(-extent, -extent, -GetMaxObjectHeight())); + return expandedAABB; +} + +bool CSimpleShadow::Valid() const { return x48_24_collision; } diff --git a/src/MetroidPrime/Cameras/CCameraFilter.cpp b/src/MetroidPrime/Cameras/CCameraFilter.cpp index a8f1917d..1d71983f 100644 --- a/src/MetroidPrime/Cameras/CCameraFilter.cpp +++ b/src/MetroidPrime/Cameras/CCameraFilter.cpp @@ -191,7 +191,7 @@ void CCameraFilterPass::DrawWideScreen(const CColor& color, const CTexture* tex, tex->Load(GX_TEXMAP0, CTexture::kCM_Repeat); } CGraphics::SetTevOp(kTS_Stage0, CTevPass_805a5ebc); - CGraphics::SetTevOp(kTS_Stage1, *PTR_skPassThru_805a8828); + CGraphics::SetTevOp(kTS_Stage1, CGraphics::kEnvPassthru); { CGraphics::StreamBegin(kP_TriangleStrip);