diff --git a/asm/MetroidPrime/CFlameWarp.s b/asm/MetroidPrime/CFlameWarp.s index 84764116..89dab537 100644 --- a/asm/MetroidPrime/CFlameWarp.s +++ b/asm/MetroidPrime/CFlameWarp.s @@ -3,8 +3,8 @@ .section .data .balign 8 -.global lbl_803E51C8 -lbl_803E51C8: +.global __vt__10CFlameWarp +__vt__10CFlameWarp: # ROM: 0x3E21C8 .4byte 0 .4byte 0 @@ -42,8 +42,8 @@ IsActivated__10CFlameWarpFv: /* 801B4F6C 001B1ECC 54 03 CF FE */ rlwinm r3, r0, 0x19, 0x1f, 0x1f /* 801B4F70 001B1ED0 4E 80 00 20 */ blr -.global sub_801b4f74 -sub_801b4f74: +.global ResetPosition__10CFlameWarpFRC9CVector3f +ResetPosition__10CFlameWarpFRC9CVector3f: /* 801B4F74 001B1ED4 38 A3 00 08 */ addi r5, r3, 8 /* 801B4F78 001B1ED8 7C A6 2B 78 */ mr r6, r5 /* 801B4F7C 001B1EDC 48 00 00 20 */ b lbl_801B4F9C @@ -105,7 +105,7 @@ lbl_801B503C: /* 801B5044 001B1FA4 90 01 00 8C */ stw r0, 0x8c(r1) /* 801B5048 001B1FA8 90 01 00 90 */ stw r0, 0x90(r1) /* 801B504C 001B1FAC 90 01 00 94 */ stw r0, 0x94(r1) -/* 801B5050 001B1FB0 48 00 09 7D */ bl sub_801b59cc +/* 801B5050 001B1FB0 48 00 09 7D */ bl "reserve__Q24rstl54vector,Q24rstl17rmemory_allocator>Fi" /* 801B5054 001B1FB4 C0 22 A9 4C */ lfs f1, lbl_805AC66C@sda21(r2) /* 801B5058 001B1FB8 3B 60 00 00 */ li r27, 0 /* 801B505C 001B1FBC C0 02 A9 50 */ lfs f0, lbl_805AC670@sda21(r2) @@ -174,7 +174,7 @@ lbl_801B5128: /* 801B5148 001B20A8 41 82 00 08 */ beq lbl_801B5150 /* 801B514C 001B20AC 54 A4 08 3C */ slwi r4, r5, 1 lbl_801B5150: -/* 801B5150 001B20B0 48 00 08 7D */ bl sub_801b59cc +/* 801B5150 001B20B0 48 00 08 7D */ bl "reserve__Q24rstl54vector,Q24rstl17rmemory_allocator>Fi" lbl_801B5154: /* 801B5154 001B20B4 80 01 00 8C */ lwz r0, 0x8c(r1) /* 801B5158 001B20B8 80 61 00 94 */ lwz r3, 0x94(r1) @@ -383,7 +383,7 @@ lbl_801B5454: /* 801B5478 001B23D8 90 01 00 18 */ stw r0, 0x18(r1) /* 801B547C 001B23DC 90 01 00 1C */ stw r0, 0x1c(r1) /* 801B5480 001B23E0 90 A1 00 24 */ stw r5, 0x24(r1) -/* 801B5484 001B23E4 48 00 03 C1 */ bl sub_801b5844 +/* 801B5484 001B23E4 48 00 03 C1 */ bl "sort,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>,8Comparer>__4rstlFQ24rstl128pointer_iterator,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl128pointer_iterator,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>8Comparer" /* 801B5488 001B23E8 3C 60 38 E4 */ lis r3, 0x38E38E39@ha /* 801B548C 001B23EC 3B 7E 00 08 */ addi r27, r30, 8 /* 801B5490 001B23F0 38 03 8E 39 */ addi r0, r3, 0x38E38E39@l @@ -523,9 +523,9 @@ __dt__10CFlameWarpFv: /* 801B567C 001B25DC 93 C1 00 08 */ stw r30, 8(r1) /* 801B5680 001B25E0 7C 7E 1B 79 */ or. r30, r3, r3 /* 801B5684 001B25E4 41 82 00 88 */ beq lbl_801B570C -/* 801B5688 001B25E8 3C 60 80 3E */ lis r3, lbl_803E51C8@ha +/* 801B5688 001B25E8 3C 60 80 3E */ lis r3, __vt__10CFlameWarp@ha /* 801B568C 001B25EC 34 1E 00 04 */ addic. r0, r30, 4 -/* 801B5690 001B25F0 38 03 51 C8 */ addi r0, r3, lbl_803E51C8@l +/* 801B5690 001B25F0 38 03 51 C8 */ addi r0, r3, __vt__10CFlameWarp@l /* 801B5694 001B25F4 90 1E 00 00 */ stw r0, 0(r30) /* 801B5698 001B25F8 41 82 00 58 */ beq lbl_801B56F0 /* 801B569C 001B25FC 80 BE 00 04 */ lwz r5, 4(r30) @@ -575,9 +575,9 @@ __ct__10CFlameWarpFfRC9CVector3fb: /* 801B5728 001B2688 3C C0 80 3F */ lis r6, __vt__5CWarp@ha /* 801B572C 001B268C 39 03 00 08 */ addi r8, r3, 8 /* 801B5730 001B2690 38 06 E2 F8 */ addi r0, r6, __vt__5CWarp@l -/* 801B5734 001B2694 3C C0 80 3E */ lis r6, lbl_803E51C8@ha +/* 801B5734 001B2694 3C C0 80 3E */ lis r6, __vt__10CFlameWarp@ha /* 801B5738 001B2698 90 03 00 00 */ stw r0, 0(r3) -/* 801B573C 001B269C 38 E6 51 C8 */ addi r7, r6, lbl_803E51C8@l +/* 801B573C 001B269C 38 E6 51 C8 */ addi r7, r6, __vt__10CFlameWarp@l /* 801B5740 001B26A0 38 00 00 03 */ li r0, 3 /* 801B5744 001B26A4 90 E3 00 00 */ stw r7, 0(r3) /* 801B5748 001B26A8 38 C0 00 09 */ li r6, 9 @@ -648,8 +648,8 @@ lbl_801B57B8: /* 801B583C 001B279C 98 03 00 A0 */ stb r0, 0xa0(r3) /* 801B5840 001B27A0 4E 80 00 20 */ blr -.global sub_801b5844 -sub_801b5844: +.global "sort,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>,8Comparer>__4rstlFQ24rstl128pointer_iterator,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl128pointer_iterator,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>8Comparer" +"sort,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>,8Comparer>__4rstlFQ24rstl128pointer_iterator,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl128pointer_iterator,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>8Comparer": /* 801B5844 001B27A4 94 21 FF C0 */ stwu r1, -0x40(r1) /* 801B5848 001B27A8 7C 08 02 A6 */ mflr r0 /* 801B584C 001B27AC 90 01 00 44 */ stw r0, 0x44(r1) @@ -739,14 +739,14 @@ lbl_801B5978: /* 801B5984 001B28E4 38 81 00 10 */ addi r4, r1, 0x10 /* 801B5988 001B28E8 90 A1 00 10 */ stw r5, 0x10(r1) /* 801B598C 001B28EC 90 01 00 14 */ stw r0, 0x14(r1) -/* 801B5990 001B28F0 4B FF FE B5 */ bl sub_801b5844 +/* 801B5990 001B28F0 4B FF FE B5 */ bl "sort,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>,8Comparer>__4rstlFQ24rstl128pointer_iterator,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl128pointer_iterator,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>8Comparer" /* 801B5994 001B28F4 80 BF 00 00 */ lwz r5, 0(r31) /* 801B5998 001B28F8 38 61 00 0C */ addi r3, r1, 0xc /* 801B599C 001B28FC 80 01 00 28 */ lwz r0, 0x28(r1) /* 801B59A0 001B2900 38 81 00 08 */ addi r4, r1, 8 /* 801B59A4 001B2904 90 A1 00 08 */ stw r5, 8(r1) /* 801B59A8 001B2908 90 01 00 0C */ stw r0, 0xc(r1) -/* 801B59AC 001B290C 4B FF FE 99 */ bl sub_801b5844 +/* 801B59AC 001B290C 4B FF FE 99 */ bl "sort,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>,8Comparer>__4rstlFQ24rstl128pointer_iterator,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>Q24rstl128pointer_iterator,Q24rstl54vector,Q24rstl17rmemory_allocator>,Q24rstl17rmemory_allocator>8Comparer" lbl_801B59B0: /* 801B59B0 001B2910 80 01 00 44 */ lwz r0, 0x44(r1) /* 801B59B4 001B2914 83 E1 00 3C */ lwz r31, 0x3c(r1) @@ -756,8 +756,8 @@ lbl_801B59B0: /* 801B59C4 001B2924 38 21 00 40 */ addi r1, r1, 0x40 /* 801B59C8 001B2928 4E 80 00 20 */ blr -.global sub_801b59cc -sub_801b59cc: +.global "reserve__Q24rstl54vector,Q24rstl17rmemory_allocator>Fi" +"reserve__Q24rstl54vector,Q24rstl17rmemory_allocator>Fi": /* 801B59CC 001B292C 94 21 FF D0 */ stwu r1, -0x30(r1) /* 801B59D0 001B2930 7C 08 02 A6 */ mflr r0 /* 801B59D4 001B2934 90 01 00 34 */ stw r0, 0x34(r1) diff --git a/asm/MetroidPrime/Weapons/CFlameThrower.s b/asm/MetroidPrime/Weapons/CFlameThrower.s index 01bde36c..a67714b9 100644 --- a/asm/MetroidPrime/Weapons/CFlameThrower.s +++ b/asm/MetroidPrime/Weapons/CFlameThrower.s @@ -997,7 +997,7 @@ Reset__13CFlameThrowerFR13CStateManagerb: /* 80198290 001951F0 D0 01 00 08 */ stfs f0, 8(r1) /* 80198294 001951F4 D0 21 00 0C */ stfs f1, 0xc(r1) /* 80198298 001951F8 D0 41 00 10 */ stfs f2, 0x10(r1) -/* 8019829C 001951FC 48 01 CC D9 */ bl sub_801b4f74 +/* 8019829C 001951FC 48 01 CC D9 */ bl ResetPosition__10CFlameWarpFRC9CVector3f /* 801982A0 00195200 48 00 00 34 */ b lbl_801982D4 lbl_801982A4: /* 801982A4 00195204 80 7E 03 48 */ lwz r3, 0x348(r30) diff --git a/configure.py b/configure.py index 7e119af5..a916ce94 100755 --- a/configure.py +++ b/configure.py @@ -264,7 +264,7 @@ LIBS = [ ["MetroidPrime/Enemies/CBurstFire", True], "MetroidPrime/Enemies/CFlaahgra", "MetroidPrime/Player/CPlayerEnergyDrain", - "MetroidPrime/CFlameWarp", + ["MetroidPrime/CFlameWarp", False], "MetroidPrime/Weapons/CIceImpact", ["MetroidPrime/GameObjectLists", True], "MetroidPrime/Weapons/CAuxWeapon", diff --git a/include/Kyoto/Math/CPlane.hpp b/include/Kyoto/Math/CPlane.hpp index 0c3f189b..0252b9c3 100644 --- a/include/Kyoto/Math/CPlane.hpp +++ b/include/Kyoto/Math/CPlane.hpp @@ -22,6 +22,8 @@ public: // IsFacing__6CPlaneCFRC9CVector3f float ClipLineSegment(const CVector3f& start, const CVector3f& end) const; + float PointToPlaneDist(const CVector3f& pos) const { return CVector3f::Dot(GetNormal(), pos) - xc_constant; } + private: CUnitVector3f x0_normal; float xc_constant; diff --git a/include/Kyoto/Particles/CWarp.hpp b/include/Kyoto/Particles/CWarp.hpp index 8ae383d6..f6600661 100644 --- a/include/Kyoto/Particles/CWarp.hpp +++ b/include/Kyoto/Particles/CWarp.hpp @@ -1,18 +1,24 @@ #ifndef _CWARP #define _CWARP +#include "Kyoto/SObjectTag.hpp" + #include "rstl/vector.hpp" class CParticle; +class CColor; +class CVector3f; class CWarp { public: virtual ~CWarp(); virtual bool UpdateWarp() = 0; - virtual void ModifyParticles(const rstl::vector< CParticle >& particles) = 0; + virtual void ModifyParticles(int particleCount, int stripe, int*, CVector3f* particlePos, + CVector3f* particlePrevPos, CVector3f* particleVelocity, + CColor* color, float* lineLengthOrSize, float* lineWidthOrRota) = 0; virtual void Activate(bool) = 0; virtual bool IsActivated() = 0; - virtual int Get4CharID() = 0; + virtual FourCC Get4CharID() = 0; }; #endif // _CWARP diff --git a/include/MetroidPrime/CFlameWarp.hpp b/include/MetroidPrime/CFlameWarp.hpp new file mode 100644 index 00000000..f97f2636 --- /dev/null +++ b/include/MetroidPrime/CFlameWarp.hpp @@ -0,0 +1,54 @@ +#ifndef _CFLAMEWARP +#define _CFLAMEWARP + +#include "Kyoto/Particles/CWarp.hpp" + +#include "Kyoto/Math/CAABox.hpp" +#include "Kyoto/Math/CVector3f.hpp" + +#include "rstl/reserved_vector.hpp" + +class CStateManager; +class CColor; + +class CFlameWarp : public CWarp { +public: + CFlameWarp(float maxInfluenceDist, const CVector3f& warpPoint, bool collisionWarp); + ~CFlameWarp() override; + + const rstl::reserved_vector< CVector3f, 9 >& GetCollisionPoints() const { + return x4_collisionPoints; + } + float GetMinSize() const { return x90_minSize; } + float GetMaxSize() const { return x94_maxSize; } + void SetWarpPoint(const CVector3f& p) { x74_warpPoint = p; } + void SetFloatingPoint(const CVector3f& p) { x80_floatingPoint = p; } + const CVector3f& GetFloatingPoint() const { return x80_floatingPoint; } + void SetMaxDistSq(float d) { x8c_maxDistSq = d; } + void SetStateManager(CStateManager& mgr) { x9c_stateMgr = &mgr; } + bool UpdateWarp() override; + void ModifyParticles(int particleCount, int stripe, int*, CVector3f* particlePos, + CVector3f* particlePrevPos, CVector3f* particleVelocity, + CColor* color, float* lineLengthOrSize, float* lineWidthOrRota) override; + void Activate(bool val) override { xa0_24_activated = val; } + bool IsActivated() override; + bool IsProcessed() const { return xa0_26_processed; } + FourCC Get4CharID() override; + void ResetPosition(const CVector3f& pos); + CAABox CalculateBounds() const; + +private: + rstl::reserved_vector< CVector3f, 9 > x4_collisionPoints; + CVector3f x74_warpPoint; + CVector3f x80_floatingPoint; + float x8c_maxDistSq; + float x90_minSize; + float x94_maxSize; + float x98_maxInfluenceDistSq; + CStateManager* x9c_stateMgr; + bool xa0_24_activated : 1; + bool xa0_25_collisionWarp : 1; + bool xa0_26_processed : 1; +}; + +#endif // _CFLAMEWARP diff --git a/src/MetroidPrime/CFlameWarp.cpp b/src/MetroidPrime/CFlameWarp.cpp new file mode 100644 index 00000000..4be99434 --- /dev/null +++ b/src/MetroidPrime/CFlameWarp.cpp @@ -0,0 +1,146 @@ +#include "MetroidPrime/CFlameWarp.hpp" + +#include "MetroidPrime/CStateManager.hpp" + +#include "Collision/CMaterialFilter.hpp" +#include "Collision/CRayCastResult.hpp" +#include "Kyoto/Graphics/CColor.hpp" + +#include "rstl/algorithm.hpp" +#include "rstl/pair.hpp" +#include "rstl/vector.hpp" + + +CFlameWarp::CFlameWarp(float maxInfluenceDist, const CVector3f& warpPoint, bool collisionWarp) +: x4_collisionPoints(warpPoint) +, x74_warpPoint(warpPoint) +, x80_floatingPoint(warpPoint) + +, x8c_maxDistSq(0.f) +, x90_minSize(FLT_MAX) +, x94_maxSize(FLT_MIN) +, x98_maxInfluenceDistSq(maxInfluenceDist * maxInfluenceDist) +, x9c_stateMgr(nullptr) +, xa0_24_activated(false) +, xa0_25_collisionWarp(collisionWarp) +, xa0_26_processed(false) {} + +CFlameWarp::~CFlameWarp() {} + +bool CFlameWarp::UpdateWarp() { return xa0_24_activated; } + +class Comparer { +public: + bool operator()(const rstl::pair< float, uchar >& left, + const rstl::pair< float, uchar >& right) const { + return left.first < right.first; + } +}; + +void CFlameWarp::ModifyParticles(int particleCount, int stripe, int*, CVector3f* particlePos, + CVector3f* particlePrevPos, CVector3f* particleVelocity, + CColor* color, float* lineLengthOrSize, float* lineWidthOrRota) { + + if (x9c_stateMgr == nullptr || particleCount < 9) { + return; + } + + rstl::vector< rstl::pair< float, uchar > > vec; + vec.reserve(particleCount); + + x90_minSize = FLT_MAX; + x94_maxSize = FLT_MIN; + float maxTransp = 0.f; + + int idx = 0; + for (int i = 0; i < particleCount; ++i) { + CVector3f& partPos = particlePos[idx]; + const float transp = 1.f - color[idx].GetAlpha(); + + if (transp > maxTransp) { + const float distSq = (partPos - x74_warpPoint).MagSquared(); + if (distSq > x8c_maxDistSq && distSq < x98_maxInfluenceDistSq) { + x8c_maxDistSq = distSq; + maxTransp = transp; + x80_floatingPoint = partPos; + } + } + + if (lineLengthOrSize[idx] < x90_minSize) { + x90_minSize = lineLengthOrSize[idx]; + } + if (lineLengthOrSize[idx] > x94_maxSize) { + x94_maxSize = lineLengthOrSize[idx]; + } + + vec.push_back(rstl::pair< float, uchar >(0.f, i)); + if (xa0_25_collisionWarp) { + CVector3f& prevPos = particlePrevPos[idx]; + CVector3f& partVel = particleVelocity[idx]; + const CVector3f delta = partPos - prevPos; + + if (delta.MagSquared() >= 0.0011920929f) { + const CVector3f deltaNorm = delta.AsNormalized(); + const CVector3f behindPos = prevPos - deltaNorm * 5.f; + const CVector3f fullDelta = partPos - behindPos; + float fullDeltaMag = fullDelta.Magnitude(); + + const CRayCastResult result = x9c_stateMgr->RayStaticIntersection( + behindPos, deltaNorm, fullDeltaMag, + CMaterialFilter::MakeIncludeExclude(CMaterialList(kMT_Solid), + CMaterialList(kMT_ProjectilePassthrough))); + + if (result.IsValid()) { + const float dist = result.GetPlane().PointToPlaneDist(partPos); + if (dist <= 0.f) { + partPos -= dist * result.GetPlane().GetNormal(); + if (CVector3f::Dot(result.GetPlane().GetNormal(), partVel) < 0.f) { + const CVector3f prevStepPos = partPos - partVel; + partPos += (-result.GetPlane().PointToPlaneDist(prevStepPos) / + CVector3f::Dot(partVel, result.GetPlane().GetNormal()) - + 1.f) * + partVel; + partVel -= partVel * 0.001f; + } + } + } + } + } + + idx += stripe; + } + + rstl::sort(vec.begin(), vec.end(), Comparer()); + + + int vecIdx = 0; + const int pitch = particleCount / 9; + + for (int i = 0; i < x4_collisionPoints.capacity(); ++i) { + CVector3f& partPos = particlePos[int(vec[vecIdx].second) * stripe]; + x4_collisionPoints[i] = partPos; + if (i > 0) { + const CVector3f delta = x4_collisionPoints[i] - x4_collisionPoints[i - 1]; + if (delta.Magnitude() < 0.0011920929f) { + x4_collisionPoints[i] += delta.AsNormalized() * 0.0011920929f; + } + } + vecIdx += pitch * 8; + } + + x4_collisionPoints[0] = x74_warpPoint; + x80_floatingPoint = x4_collisionPoints[8]; + xa0_26_processed = true; +} + +void CFlameWarp::ResetPosition(const CVector3f& pos) { + rstl::reserved_vector< CVector3f, 9 >::iterator it; + for (it = x4_collisionPoints.begin(); it != x4_collisionPoints.end(); ++it) { + *it = pos; + } + xa0_26_processed = false; +} + +bool CFlameWarp::IsActivated() { return xa0_24_activated; } + +FourCC CFlameWarp::Get4CharID() { return 'FWRP'; }