diff --git a/asm/Kyoto/Graphics/CLight.s b/asm/Kyoto/Graphics/CLight.s index c6e7e9ff..5441e35e 100644 --- a/asm/Kyoto/Graphics/CLight.s +++ b/asm/Kyoto/Graphics/CLight.s @@ -77,11 +77,11 @@ lbl_80306090: /* 803060C0 00303020 D0 01 00 0C */ stfs f0, 0xc(r1) /* 803060C4 00303024 48 00 E7 F5 */ bl Magnitude__9CVector3fCFv /* 803060C8 00303028 FC 40 08 18 */ frsp f2, f1 -/* 803060CC 0030302C C0 02 C7 78 */ lfs f0, lbl_805AE498@sda21(r2) +/* 803060CC 0030302C C0 02 C7 78 */ lfs f0, gkEpsilon32@sda21(r2) /* 803060D0 00303030 D0 21 00 08 */ stfs f1, 8(r1) /* 803060D4 00303034 FC 02 00 40 */ fcmpo cr0, f2, f0 /* 803060D8 00303038 40 80 00 0C */ bge lbl_803060E4 -/* 803060DC 0030303C 38 62 C7 78 */ addi r3, r2, lbl_805AE498@sda21 +/* 803060DC 0030303C 38 62 C7 78 */ addi r3, r2, gkEpsilon32@sda21 /* 803060E0 00303040 48 00 00 08 */ b lbl_803060E8 lbl_803060E4: /* 803060E4 00303044 38 61 00 08 */ addi r3, r1, 8 @@ -491,15 +491,15 @@ __sinit_CLight_cpp: .section .sdata2, "a" .balign 8 -.global lbl_805AE498 -lbl_805AE498: +.global gkEpsilon32 +gkEpsilon32: # ROM: 0x3FAD38 .float 1.1920929E-7 .global lbl_805AE49C lbl_805AE49C: # ROM: 0x3FAD3C - .4byte 0x3B808081 + .float 0.003921569 .global lbl_805AE4A0 lbl_805AE4A0: @@ -514,7 +514,7 @@ lbl_805AE4A4: .global lbl_805AE4A8 lbl_805AE4A8: # ROM: 0x3FAD48 - .4byte 0 + .float 0.0 .global lbl_805AE4AC lbl_805AE4AC: @@ -524,10 +524,9 @@ lbl_805AE4AC: .global lbl_805AE4B0 lbl_805AE4B0: # ROM: 0x3FAD50 - .4byte 0x7C1071DB + .float 3.0E36 .global lbl_805AE4B4 lbl_805AE4B4: # ROM: 0x3FAD54 - .4byte 0x43340000 - + .float 180.0 diff --git a/include/Kyoto/Graphics/CLight.hpp b/include/Kyoto/Graphics/CLight.hpp index 9f22f663..544f8f07 100644 --- a/include/Kyoto/Graphics/CLight.hpp +++ b/include/Kyoto/Graphics/CLight.hpp @@ -1,6 +1,82 @@ #ifndef __CLIGHT_HPP__ #define __CLIGHT_HPP__ -class CLight {}; +#include "Kyoto/Graphics/CColor.hpp" +#include "Kyoto/Math/CVector3f.hpp" + +enum ELightType { + kLT_Spot = 0, + kLT_Point = 1, + kLT_Directional = 2, + kLT_LocalAmbient = 3, + kLT_Custom = 4, +}; + +enum EFallofType { kFT_Constant, kFT_Linear, kFT_Quadratic }; + +class CLight { + static const CVector3f kDefaultPosition; + static const CVector3f kDefaultDirection; + + float CalculateLightRadius() const; +public: + CLight(ELightType type, const CVector3f& position, const CVector3f& direction, + const CColor& color, float cutoff); + CLight(const CVector3f& pos, const CVector3f& direction, const CColor& color, float distC, + float distL, float distQ, float angleC, float angleL, float angleQ); + + void SetPosition(const CVector3f& pos); + const CVector3f& GetPosition() const { return x0_pos; } + void SetDirection(const CVector3f& dir); + const CVector3f& GetDirection() const { return xc_dir; } + void SetColor(const CColor& col); + void SetAttenuation(float constant, float linear, float quadratic); + float GetSpotCutoff() const { return x20_spotCutoff; } + float GetAttenuationConstant() const { return x24_distC; } + float GetAttenuationLinear() const { return x28_distL; } + float GetAttenuationQuadratic() const { return x2c_distQ; } + + void SetAngleAttenuation(float constant, float linear, float quadratic); + float GetAngleAttenuationConstant() const { return x30_angleC; } + float GetAngleAttenuationLinear() const { return x34_angleL; } + float GetAngleAttenuationQuadratic() const { return x38_angleQ; } + + ELightType GetType() const { return x1c_type; } + u32 GetId() const { return x40_lightId; } + float GetIntensity() const; + float GetRadius() const; + const CColor& GetColor() const { return x18_color; } + + CVector3f GetNormalIndependentLightingAtPoint(const CVector3f& point) const; + + static CLight BuildDirectional(const CVector3f& dir, const CColor& color); + static CLight BuildSpot(const CVector3f& pos, const CVector3f& dir, const CColor& color, + float cutoff); + static CLight BuildPoint(const CVector3f& pos, const CColor& color); + static CLight BuildCustom(const CVector3f& pos, const CVector3f& dir, const CColor& color, + float distC, float distL, float distQ, float angleC, float angleL, + float angleQ); + static CLight BuildLocalAmbient(const CVector3f& pos, const CColor& color); + +private: + CVector3f x0_pos; + CVector3f xc_dir; + CColor x18_color; + ELightType x1c_type; + f32 x20_spotCutoff; + f32 x24_distC; + f32 x28_distL; + f32 x2c_distQ; + f32 x30_angleC; + f32 x34_angleL; + f32 x38_angleQ; + uint x3c_priority; + uint x40_lightId; + mutable f32 x44_cachedRadius; + mutable f32 x48_cachedIntensity; + mutable bool x4c_24_intensityDirty : 1; + mutable bool x4c_25_radiusDirty : 1; +}; +CHECK_SIZEOF(CLight, 0x50) #endif // __CLIGHT_HPP__ diff --git a/include/MetroidPrime/CActor.hpp b/include/MetroidPrime/CActor.hpp index 081aaeed..00454e72 100644 --- a/include/MetroidPrime/CActor.hpp +++ b/include/MetroidPrime/CActor.hpp @@ -265,10 +265,10 @@ public: void SetRotation(const CQuaternion& rot) { SetTransform(rot.BuildTransform4f(GetTranslation())); } - const CQuaternion& GetRotation() const { + CQuaternion GetRotation() const { return CQuaternion::FromMatrix(GetTransform()); } - const CVector3f& GetTranslation() const { return x34_transform.GetTranslation(); } + CVector3f GetTranslation() const { return x34_transform.GetTranslation(); } void SetTranslation(const CVector3f& vec); CTransform4f GetLocatorTransform(const rstl::string& segName) const; CTransform4f GetScaledLocatorTransform(const rstl::string& segName) const; diff --git a/include/MetroidPrime/CActorLights.hpp b/include/MetroidPrime/CActorLights.hpp index 515ae7e1..606bfed0 100644 --- a/include/MetroidPrime/CActorLights.hpp +++ b/include/MetroidPrime/CActorLights.hpp @@ -6,40 +6,11 @@ #include "MetroidPrime/TGameTypes.hpp" #include "Kyoto/Graphics/CColor.hpp" +#include "Kyoto/Graphics/CLight.hpp" #include "Kyoto/Math/CVector3f.hpp" #include "rstl/reserved_vector.hpp" -enum ELightType { - kLT_Spot = 0, - kLT_Point = 1, - kLT_Directional = 2, - kLT_LocalAmbient = 3, - kLT_Custom = 4, -}; - -class CLight { -private: - CVector3f x0_pos; - CVector3f xc_dir; - CColor x18_color; - ELightType x1c_type; - f32 x20_spotCutoff; - f32 x24_distC; - f32 x28_distL; - f32 x2c_distQ; - f32 x30_angleC; - f32 x34_angleL; - f32 x38_angleQ; - uint x3c_priority; - uint x40_lightId; - mutable f32 x44_cachedRadius; - mutable f32 x48_cachedIntensity; - mutable bool x4c_24_intensityDirty : 1; - mutable bool x4c_25_radiusDirty : 1; -}; -CHECK_SIZEOF(CLight, 0x50) - class CGameArea; class CStateManager; class CAABox; diff --git a/include/MetroidPrime/CPhysicsActor.hpp b/include/MetroidPrime/CPhysicsActor.hpp index 1d48981c..741ab684 100644 --- a/include/MetroidPrime/CPhysicsActor.hpp +++ b/include/MetroidPrime/CPhysicsActor.hpp @@ -101,11 +101,17 @@ public: const CVector3f& GetConstantForceWR() const { return xfc_constantForce; } void SetConstantForceWR(const CVector3f& force) { xfc_constantForce = force; } const CAxisAngle& GetAngularMomentumWR() const { return x108_angularMomentum; } + void SetAngularMomentumWR(const CAxisAngle& angularMomentum) { x108_angularMomentum = angularMomentum; } const CVector3f& GetMomentumWR() const { return x150_momentum; } + void SetMomentumWR(const CVector3f& momentum) { x150_momentum = momentum; } const CVector3f& GetForceWR() const { return x15c_force; } + void SetForceWR(const CVector3f& force) { x15c_force = force; } const CVector3f& GetImpulseWR() const { return x168_impulse; } + void SetImpulseWR(const CVector3f& impulse) { x168_impulse = impulse; } const CAxisAngle& GetTorqueWR() const { return x174_torque; } + void SetTorqueWR(const CAxisAngle& torque) { x174_torque = torque; } const CAxisAngle& GetAngularImpulseWR() const { return x180_angularImpulse; } + void SetAngularImpulseWR(const CAxisAngle& angularImpulse) { x180_angularImpulse = angularImpulse; } CPhysicsState GetPhysicsState() const; void SetPhysicsState(const CPhysicsState& state); @@ -121,6 +127,9 @@ public: void SetMovable(bool v) { xf8_24_movable = v; } void MoveToWR(const CVector3f&, float); + void MoveToInOneFrameWR(const CVector3f&, float); + CVector3f GetMoveToORImpulseWR(const CVector3f& impulse, float d) const; + CAxisAngle GetRotateToORAngularMomentumWR(const CQuaternion& q, float d) const; void RotateToWR(const CQuaternion&, float); void MoveToOR(const CVector3f&, float); diff --git a/src/Kyoto/Graphics/CLight.cpp b/src/Kyoto/Graphics/CLight.cpp new file mode 100644 index 00000000..274f117e --- /dev/null +++ b/src/Kyoto/Graphics/CLight.cpp @@ -0,0 +1,149 @@ +#include "Kyoto/Graphics/CLight.hpp" + +#include "Kyoto/Math/CMath.hpp" +#include "rstl/math.hpp" + +const CVector3f CLight::kDefaultPosition(0.f, 0.f, 0.f); +const CVector3f CLight::kDefaultDirection(0.f, -1.f, 0.f); + +static const float gkEpsilon32 = FLT_EPSILON; + +CLight::CLight(ELightType type, const CVector3f& position, const CVector3f& direction, + const CColor& color, float cutoff) +: x0_pos(position) +, xc_dir(direction) +, x18_color(color) +, x1c_type(type) +, x20_spotCutoff(cutoff) +, x24_distC(0.f) +, x28_distL(1.f) +, x2c_distQ(0.f) +, x30_angleC(0.f) +, x34_angleL(1.f) +, x38_angleQ(0.f) +, x3c_priority(0) +, x40_lightId(0) +, x44_cachedRadius(0.f) +, x48_cachedIntensity(0.f) +, x4c_24_intensityDirty(true) +, x4c_25_radiusDirty(true) {} + +CLight::CLight(const CVector3f& position, const CVector3f& direction, const CColor& color, + float distC, float distL, float distQ, float angleC, float angleL, float angleQ) +: x0_pos(position) +, xc_dir(direction) +, x18_color(color) +, x1c_type(kLT_Custom) +, x20_spotCutoff(0.f) +, x24_distC(distC) +, x28_distL(distL) +, x2c_distQ(distQ) +, x30_angleC(angleC) +, x34_angleL(angleL) +, x38_angleQ(angleQ) +, x3c_priority(0) +, x40_lightId(0) +, x44_cachedRadius(0.f) +, x48_cachedIntensity(0.f) +, x4c_24_intensityDirty(true) +, x4c_25_radiusDirty(true) {} + +CLight CLight::BuildLocalAmbient(const CVector3f& pos, const CColor& col) { + return CLight(kLT_LocalAmbient, pos, kDefaultDirection, col, 180.f); +} + +CLight CLight::BuildDirectional(const CVector3f& direction, const CColor& col) { + return CLight(kLT_Directional, kDefaultPosition, direction, col, 180.f); +} + +CLight CLight::BuildPoint(const CVector3f& pos, const CColor& color) { + return CLight(kLT_Point, pos, kDefaultDirection, color, 180.f); +} + +CLight CLight::BuildSpot(const CVector3f& pos, const CVector3f& dir, const CColor& color, + float cutoff) { + return CLight(kLT_Spot, pos, dir, color, cutoff); +} + +CLight CLight::BuildCustom(const CVector3f& pos, const CVector3f& dir, const CColor& color, + float distC, float distL, float distQ, float angleC, float angleL, + float angleQ) { + return CLight(pos, dir, color, distC, distL, distQ, angleC, angleL, angleQ); +} + +void CLight::SetAttenuation(float constant, float linear, float quadratic) { + x24_distC = constant; + x28_distL = linear; + x2c_distQ = quadratic; + x4c_25_radiusDirty = true; + x4c_24_intensityDirty = true; +} + +void CLight::SetAngleAttenuation(float constant, float linear, float quadratic) { + x30_angleC = constant; + x34_angleL = linear; + x38_angleQ = quadratic; + x4c_25_radiusDirty = true; + x4c_24_intensityDirty = true; +} + +void CLight::SetColor(const CColor& col) { + x18_color = col; + x4c_25_radiusDirty = true; + x4c_24_intensityDirty = true; +} + +void CLight::SetPosition(const CVector3f& position) { x0_pos = position; } + +void CLight::SetDirection(const CVector3f& direction) { xc_dir = direction; } + +float CLight::GetRadius() const { + if (x4c_25_radiusDirty) { + x44_cachedRadius = CalculateLightRadius(); + x4c_25_radiusDirty = false; + } + return x44_cachedRadius; +} + +float CLight::CalculateLightRadius() const { + if (x28_distL < gkEpsilon32 && x2c_distQ < gkEpsilon32) { + return FLT_MAX; + } + + float intensity = GetIntensity(); + float ret = 0.f; + if (x2c_distQ > gkEpsilon32) { + const float mulVal = rstl::min_val(0.05882353f, 0.2f); // Yes, retro really did do this + if (intensity > gkEpsilon32) { + ret = CMath::SqrtF(intensity / (mulVal * x2c_distQ)); + } + } else { + const float mulVal = rstl::min_val(0.05882353f, 0.2f); // See above comment + if (x28_distL > gkEpsilon32) { + ret = intensity / (mulVal * x28_distL); + } + } + + return ret; +} + +float CLight::GetIntensity() const { + if (x4c_24_intensityDirty) { + x4c_24_intensityDirty = false; + float coef = 1.f; + if (x1c_type == kLT_Custom) { + coef = x30_angleC; + } + x48_cachedIntensity = coef * rstl::max_val(x18_color.GetRed(), rstl::max_val(x18_color.GetGreen(), x18_color.GetBlue())); + } + return x48_cachedIntensity; +} + +CVector3f CLight::GetNormalIndependentLightingAtPoint(const CVector3f& point) const { + CVector3f floatCol(x18_color.GetRed(), x18_color.GetGreen(), x18_color.GetBlue()); + if (x1c_type == kLT_LocalAmbient) + return floatCol; + + float dist = rstl::max_val((x0_pos - point).Magnitude(), gkEpsilon32); + return floatCol * (1.f / (dist * (x2c_distQ * dist) + (x28_distL * dist + x24_distC))); +} diff --git a/src/MetroidPrime/CPhysicsActor.cpp b/src/MetroidPrime/CPhysicsActor.cpp index 1cd79c60..c9056004 100644 --- a/src/MetroidPrime/CPhysicsActor.cpp +++ b/src/MetroidPrime/CPhysicsActor.cpp @@ -91,15 +91,16 @@ CPhysicsState CPhysicsActor::GetPhysicsState() const { void CPhysicsActor::SetPhysicsState(const CPhysicsState& state) { SetTranslation(state.GetTranslation()); - const CQuaternion& quat = state.GetOrientationWR(); - SetTransform(quat.BuildTransform4f(GetTranslation())); - xfc_constantForce = state.GetConstantForceWR(); - x108_angularMomentum = state.GetAngularMomentumWR(); - x150_momentum = state.GetMomentumWR(); - x15c_force = state.GetForceWR(); - x168_impulse = state.GetImpulseWR(); - x174_torque = state.GetTorque(); - x180_angularImpulse = state.GetAngularImpulseWR(); + CQuaternion quat = state.GetOrientationWR(); + CVector3f translation = GetTranslation(); + SetTransform(quat.BuildTransform4f(translation)); + SetConstantForceWR(state.GetConstantForceWR()); + SetAngularMomentumWR(state.GetAngularMomentumWR()); + SetMomentumWR(state.GetMomentumWR()); + SetForceWR(state.GetForceWR()); + SetImpulseWR(state.GetImpulseWR()); + SetTorqueWR(state.GetTorque()); + SetAngularImpulseWR(state.GetAngularImpulseWR()); ComputeDerivedQuantities(); } @@ -190,3 +191,15 @@ void CPhysicsActor::MoveToWR(const CVector3f& trans, float d) { xfc_constantForce = (trans - GetTransform().GetTranslation()) * GetMass() * (1.f / d); ComputeDerivedQuantities(); } + +void CPhysicsActor::MoveToInOneFrameWR(const CVector3f& trans, float d) { + x18c_moveImpulse += (trans - GetTranslation()) * GetMass() * (1.f / d); +} + + +CVector3f CPhysicsActor::GetMoveToORImpulseWR(const CVector3f& trans, float d) const { + CVector3f impulse = x34_transform.Rotate(trans); + return (GetMass() * impulse) * (1.f / d); +} + +CAxisAngle CPhysicsActor::GetRotateToORAngularMomentumWR(const CQuaternion& q, float d) const {}