diff --git a/configure.py b/configure.py index c5d3eb94..32b983d9 100755 --- a/configure.py +++ b/configure.py @@ -482,7 +482,7 @@ config.libs = [ Object(NonMatching, "MetroidPrime/CPhysicsActor.cpp"), Object(Matching, "MetroidPrime/CPhysicsState.cpp"), Object(NonMatching, "MetroidPrime/CRipple.cpp"), - Object(NonMatching, "MetroidPrime/CFluidUVMotion.cpp"), + Object(Matching, "MetroidPrime/CFluidUVMotion.cpp"), Object(NonMatching, "MetroidPrime/CRippleManager.cpp"), Object(NonMatching, "MetroidPrime/Player/CGrappleArm.cpp"), Object(NonMatching, "MetroidPrime/Enemies/CSpacePirate.cpp"), diff --git a/include/MetroidPrime/CFluidUVMotion.hpp b/include/MetroidPrime/CFluidUVMotion.hpp new file mode 100644 index 00000000..3e62cb42 --- /dev/null +++ b/include/MetroidPrime/CFluidUVMotion.hpp @@ -0,0 +1,63 @@ +#ifndef _CFLUIDUVMOTION +#define _CFLUIDUVMOTION + +#include + +class CFluidUVMotion { +public: + enum EFluidMotion { + kFM_Linear, + kFM_Circular, + kFM_Oscillate, + kFM_NumLayers, + }; + + struct SFluidLayerMotion { + EFluidMotion x0_motion; + float x4_ooTimeToWrap; + float x8_orientation; + float xc_magnitude; + float x10_uvMul; + float x14_uvScale; + + SFluidLayerMotion(EFluidMotion motion = kFM_Linear, float timeToWrap = 6.f, + float orientation = 0.f, float magnitude = 1.f, float uvMul = 5.f) + : x0_motion(motion) + , x4_ooTimeToWrap(1.f / timeToWrap) + , x8_orientation(orientation) + , xc_magnitude(magnitude) + , x10_uvMul(uvMul) + , x14_uvScale(1.f / uvMul) {} + SFluidLayerMotion(const SFluidLayerMotion& other) + : x0_motion(other.x0_motion) + , x4_ooTimeToWrap(other.x4_ooTimeToWrap) + , x8_orientation(other.x8_orientation) + , xc_magnitude(other.xc_magnitude) + , x10_uvMul(other.x10_uvMul) + , x14_uvScale(other.x14_uvScale) {} + }; + +private: + rstl::reserved_vector< SFluidLayerMotion, kFM_NumLayers > x0_fluidLayers; + float x4c_ooTimeToWrap; + float x50_orientation; + +public: + CFluidUVMotion(float timeToWrap, float orientation); + CFluidUVMotion(float timeToWrap, float orientation, const SFluidLayerMotion& colorLayer, + const SFluidLayerMotion& pattern1Layer, const SFluidLayerMotion& pattern2Layer); + CFluidUVMotion(const CFluidUVMotion&); + + void CalculateFluidTextureOffset(float t, float offsets[kFM_NumLayers][2]) const; + + float GetOOTimeToWrapTexPage() const { return x4c_ooTimeToWrap; } + float GetOrientation() const { return x50_orientation; } + const SFluidLayerMotion& GetFluidLayerMotion(EFluidMotion motion) const { + return x0_fluidLayers[motion]; + } + const rstl::reserved_vector< SFluidLayerMotion, kFM_NumLayers >& GetFluidLayers() const { + return x0_fluidLayers; + } +}; + +#endif // _CFLUIDUVMOTION diff --git a/src/MetroidPrime/CFluidUVMotion.cpp b/src/MetroidPrime/CFluidUVMotion.cpp new file mode 100644 index 00000000..731baeb7 --- /dev/null +++ b/src/MetroidPrime/CFluidUVMotion.cpp @@ -0,0 +1,61 @@ +#include + +#include + +CFluidUVMotion::CFluidUVMotion(float timeToWrap, float orientation) +: x0_fluidLayers(), x4c_ooTimeToWrap(1.f / timeToWrap), x50_orientation(orientation) { + x0_fluidLayers.resize(kFM_NumLayers, SFluidLayerMotion()); + x0_fluidLayers[0] = SFluidLayerMotion(CFluidUVMotion::kFM_Linear, 1000.f); + x0_fluidLayers[1] = SFluidLayerMotion(CFluidUVMotion::kFM_Linear, 3.f); + x0_fluidLayers[2] = SFluidLayerMotion(CFluidUVMotion::kFM_Linear, 5.f, CMath::Deg2Rad(45.f)); +} + +CFluidUVMotion::CFluidUVMotion(float timeToWrap, float orientation, + const SFluidLayerMotion& colorLayer, + const SFluidLayerMotion& pattern1Layer, + const SFluidLayerMotion& pattern2Layer) +: x0_fluidLayers(), x4c_ooTimeToWrap(1.f / timeToWrap), x50_orientation(orientation) { + x0_fluidLayers.resize(kFM_NumLayers, SFluidLayerMotion()); + x0_fluidLayers[0] = colorLayer; + x0_fluidLayers[1] = pattern1Layer; + x0_fluidLayers[2] = pattern2Layer; +} + +void CFluidUVMotion::CalculateFluidTextureOffset(float t, float offsets[kFM_NumLayers][2]) const { + float totalXOffset = t * GetOOTimeToWrapTexPage(); + float totalYOffset = CMath::FastCosR(GetOrientation()) * totalXOffset; + totalXOffset *= CMath::FastSinR(GetOrientation()); + + for (int i = 0; i < GetFluidLayers().size(); ++i) { + const SFluidLayerMotion& layer = GetFluidLayerMotion(EFluidMotion(i)); + + const float speedT = t * layer.x4_ooTimeToWrap; + const float cycleT = speedT - floorf(speedT); + float localY; + float localX; + switch (layer.x0_motion) { + case kFM_Linear: + localY = 0.f; + localX = speedT; + break; + case kFM_Circular: + localY = layer.xc_magnitude * CMath::FastSinR((M_PIF * 2) * cycleT); + localX = layer.xc_magnitude * CMath::FastCosR((M_PIF * 2) * cycleT); + break; + case kFM_Oscillate: + localY = 0.f; + localX = layer.xc_magnitude * CMath::FastCosR((M_PIF * 2) * cycleT); + break; + default: + localY = localX = 0.f; + break; + } + + const float x = totalXOffset + CMath::FastCosR(layer.x8_orientation) * localY + + CMath::FastSinR(layer.x8_orientation) * localX; + const float y = totalYOffset + CMath::FastCosR(layer.x8_orientation) * localX + + CMath::FastSinR(layer.x8_orientation) * localY; + offsets[i][0] = x - floorf(x); + offsets[i][1] = y - floorf(y); + } +} diff --git a/src/MetroidPrime/ScriptLoader.cpp b/src/MetroidPrime/ScriptLoader.cpp index d2e1ae43..13f6a949 100644 --- a/src/MetroidPrime/ScriptLoader.cpp +++ b/src/MetroidPrime/ScriptLoader.cpp @@ -4,6 +4,7 @@ #include "MetroidPrime/CAnimRes.hpp" #include "MetroidPrime/CAnimationParameters.hpp" #include "MetroidPrime/CDamageVulnerability.hpp" +#include "MetroidPrime/CFluidUVMotion.hpp" #include "MetroidPrime/CGrappleParameters.hpp" #include "MetroidPrime/CHealthInfo.hpp" #include "MetroidPrime/CModelData.hpp" @@ -272,8 +273,9 @@ CEntity* ScriptLoader::LoadDamageableTrigger(CStateManager& mgr, CInputStream& i CAssetId patternTex1 = in.Get< CAssetId >(); CAssetId patternTex2 = in.Get< CAssetId >(); CAssetId colorTex = in.Get< CAssetId >(); - CScriptDamageableTrigger::ECanOrbit canOrbit = - CScriptDamageableTrigger::ECanOrbit(in.Get< bool >()); + CScriptDamageableTrigger::ECanOrbit canOrbit = in.Get< bool >() + ? CScriptDamageableTrigger::kCO_Orbit + : CScriptDamageableTrigger::kCO_NoOrbit; bool active = in.Get< bool >(); CVisorParameters vParms = LoadVisorParameters(in); return rs_new CScriptDamageableTrigger(mgr.AllocateUniqueId(), name, info, position, volume, @@ -281,7 +283,32 @@ CEntity* ScriptLoader::LoadDamageableTrigger(CStateManager& mgr, CInputStream& i colorTex, canOrbit, active, vParms); } -// static CFluidUVMotion LoadFluidUVMotion(CInputStream&) {} +static CFluidUVMotion LoadFluidUVMotion(CInputStream& in) { + CFluidUVMotion::EFluidMotion motion = CFluidUVMotion::EFluidMotion(in.ReadLong()); + float a = in.ReadFloat(); + float b = (in.ReadFloat() * M_PIF) / 180.f - M_PIF; + float c = in.ReadFloat(); + float d = in.ReadFloat(); + CFluidUVMotion::SFluidLayerMotion pattern1Layer(motion, a, b, c, d); + + motion = CFluidUVMotion::EFluidMotion(in.ReadLong()); + a = in.ReadFloat(); + b = (in.ReadFloat() * M_PIF) / 180.f - M_PIF; + c = in.ReadFloat(); + d = in.ReadFloat(); + CFluidUVMotion::SFluidLayerMotion pattern2Layer(motion, a, b, c, d); + + motion = CFluidUVMotion::EFluidMotion(in.ReadLong()); + a = in.ReadFloat(); + b = in.ReadFloat(); + c = in.ReadFloat(); + d = in.ReadFloat(); + CFluidUVMotion::SFluidLayerMotion colorLayer(motion, a, (b * M_PIF) / 180.f - M_PIF, c, d); + + a = in.ReadFloat(); + b = in.ReadFloat(); + return CFluidUVMotion(a, (b * M_PIF) / 180.f - M_PIF, colorLayer, pattern1Layer, pattern2Layer); +} CEntity* ScriptLoader::LoadSpawnPoint(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info) {