diff --git a/configure.py b/configure.py index cb26dc9a..af39dd83 100755 --- a/configure.py +++ b/configure.py @@ -222,7 +222,7 @@ LIBS = [ ["MetroidPrime/Player/CFidget", True], "MetroidPrime/Enemies/CSpankWeed", "MetroidPrime/Enemies/CParasite", - "MetroidPrime/Player/CSamusFaceReflection", + ["MetroidPrime/Player/CSamusFaceReflection", False], ["MetroidPrime/ScriptObjects/CScriptPlayerHint", True], "MetroidPrime/Enemies/CRipper", "MetroidPrime/Cameras/CCameraShakeData", diff --git a/include/Kyoto/Graphics/CGraphics.hpp b/include/Kyoto/Graphics/CGraphics.hpp index 9dcd5297..e3f5b72f 100644 --- a/include/Kyoto/Graphics/CGraphics.hpp +++ b/include/Kyoto/Graphics/CGraphics.hpp @@ -149,6 +149,7 @@ public: static const CTransform4f& GetModelMatrix() { return mModelMatrix; } static void SetViewPointMatrix(const CTransform4f&); static void SetBrightness(float b) { mBrightness = b; } + static void SetOrtho(float left, float right, float top, float bottom, float znear, float zfar); static float GetSecondsMod900(); static void SetExternalTimeProvider(CTimeProvider* provider); diff --git a/include/Kyoto/Graphics/CModelFlags.hpp b/include/Kyoto/Graphics/CModelFlags.hpp index 37b80203..f2fa4bf7 100644 --- a/include/Kyoto/Graphics/CModelFlags.hpp +++ b/include/Kyoto/Graphics/CModelFlags.hpp @@ -102,8 +102,8 @@ public: static CModelFlags Normal() { return CModelFlags(kT_Opaque, 1.f); } static CModelFlags AlphaBlended(float alpha) { return CModelFlags(kT_Blend, alpha); } static CModelFlags AlphaBlended(const CColor& color) { return CModelFlags(kT_Blend, color); } - static CModelFlags Additive(float f); - static CModelFlags Additive(const CColor& color); + static CModelFlags Additive(float f) { return CModelFlags(CModelFlags::kT_Additive, f); } + static CModelFlags Additive(const CColor& color) { return CModelFlags(CModelFlags::kT_Additive, color); } static CModelFlags AdditiveRGB(const CColor& color); static CModelFlags ColorModulate(const CColor& color); diff --git a/include/Kyoto/Math/CMatrix3f.hpp b/include/Kyoto/Math/CMatrix3f.hpp index 8288fdb3..c65f6251 100644 --- a/include/Kyoto/Math/CMatrix3f.hpp +++ b/include/Kyoto/Math/CMatrix3f.hpp @@ -21,6 +21,8 @@ public: inline const CVector3f& GetRow(EDimY dim) const { return m1; } inline const CVector3f& GetRow(EDimZ dim) const { return m2; } + inline CVector3f GetColumn(EDimY dim) const { return CVector3f(m0.GetY(), m1.GetY(), m2.GetY()); } + private: // TODO maybe individual floats CVector3f m0; diff --git a/include/Kyoto/Math/CQuaternion.hpp b/include/Kyoto/Math/CQuaternion.hpp index 53c88c3d..5aa924b7 100644 --- a/include/Kyoto/Math/CQuaternion.hpp +++ b/include/Kyoto/Math/CQuaternion.hpp @@ -36,7 +36,7 @@ public: static CQuaternion LookAt(const CUnitVector3f&, const CUnitVector3f&, const CRelAngle&); // normalize_angle__Ff // IsValidQuaternion__11CQuaternionCFf - // SlerpLocal__11CQuaternionFRC11CQuaternionRC11CQuaternionf + static CQuaternion SlerpLocal(const CQuaternion& from, const CQuaternion& to, float t); // AngleFrom__11CQuaternionCFRC11CQuaternion // BuildEquivalent__11CQuaternionCFv // BuildNormalized__11CQuaternionCFv diff --git a/include/MetroidPrime/CActorLights.hpp b/include/MetroidPrime/CActorLights.hpp index 80b1689f..8b50c103 100644 --- a/include/MetroidPrime/CActorLights.hpp +++ b/include/MetroidPrime/CActorLights.hpp @@ -28,8 +28,10 @@ public: bool BuildAreaLightList(const CStateManager& mgr, const CGameArea& area, const CAABox& bounds); void BuildDynamicLightList(const CStateManager& mgr, const CAABox& bounds); void BuildFakeLightList(const rstl::vector&, const CColor&); + void BuildFaceLightList(const CStateManager& mgr, const CGameArea& area, const CAABox& aabb); void ActivateLights() const; + uint GetActiveLightCount() const; bool GetNeedsRelight() const { return x298_24_dirty == TRUE; } bool HasShadowLight() const { return x29c_shadowLightArrIdx != -1; } diff --git a/include/MetroidPrime/CAnimRes.hpp b/include/MetroidPrime/CAnimRes.hpp index 14b0c658..aa3bf661 100644 --- a/include/MetroidPrime/CAnimRes.hpp +++ b/include/MetroidPrime/CAnimRes.hpp @@ -28,7 +28,7 @@ public: , x18_defaultAnim(defaultAnim) {} // name? - static int kDefaultCharIdx; + static const int kDefaultCharIdx; }; CHECK_SIZEOF(CAnimRes, 0x1c) diff --git a/include/MetroidPrime/CModelData.hpp b/include/MetroidPrime/CModelData.hpp index 7c29781d..a650eb64 100644 --- a/include/MetroidPrime/CModelData.hpp +++ b/include/MetroidPrime/CModelData.hpp @@ -5,6 +5,7 @@ #include "MetroidPrime/TGameTypes.hpp" +#include "Kyoto/Animation/IAnimReader.hpp" #include "Kyoto/Graphics/CColor.hpp" #include "Kyoto/Math/CTransform4f.hpp" #include "Kyoto/Math/CVector3f.hpp" @@ -24,6 +25,7 @@ class CModel; class CModelFlags; class CStateManager; class CSkinnedModel; +class CRandom16; // TODO move #include "Kyoto/Math/CQuaternion.hpp" @@ -76,12 +78,12 @@ public: const CModelFlags& flags) const; void Render(const CStateManager&, const CTransform4f&, const CActorLights*, const CModelFlags&) const; - void Render(EWhichModel, const CTransform4f&, const CActorLights*, - const CModelFlags&) const; + void Render(EWhichModel, const CTransform4f&, const CActorLights*, const CModelFlags&) const; void FlatDraw(EWhichModel which, const CTransform4f& xf, bool unsortedOnly, const CModelFlags& flags) const; CSkinnedModel& PickAnimatedModel(EWhichModel which) const; void Touch(const CStateManager& mgr, int) const; + SAdvancementDeltas AdvanceAnimationIgnoreParticles(float dt, CRandom16& rand, bool advTree); const CAnimData* GetAnimationData() const { return xc_animData.get(); } CAnimData* AnimationData() { return xc_animData.get(); } diff --git a/include/MetroidPrime/Player/CSamusFaceReflection.hpp b/include/MetroidPrime/Player/CSamusFaceReflection.hpp new file mode 100644 index 00000000..17830235 --- /dev/null +++ b/include/MetroidPrime/Player/CSamusFaceReflection.hpp @@ -0,0 +1,33 @@ +#ifndef _CSAMUSFACEREFLECTION +#define _CSAMUSFACEREFLECTION + +#include "MetroidPrime/CModelData.hpp" + +#include "Kyoto/Math/CQuaternion.hpp" +#include "Kyoto/Math/CVector3f.hpp" + +#include "rstl/single_ptr.hpp" + +class CStateManager; +class CRandom16; +class CActorLights; + +class CSamusFaceReflection { + +public: + explicit CSamusFaceReflection(const CStateManager& stateMgr); + void PreDraw(const CStateManager& stateMgr); + void Draw(const CStateManager& stateMgr) const; + void Update(float dt, const CStateManager& stateMgr, CRandom16& rand); + +private: + CModelData x0_modelData; + rstl::single_ptr< CActorLights > x4c_lights; + CQuaternion x50_lookRot; + CVector3f x60_lookDir; + int x6c_; + bool x70_hidden; +}; + + +#endif // _CSAMUSFACEREFLECTION diff --git a/include/MetroidPrime/Tweaks/CTweakGui.hpp b/include/MetroidPrime/Tweaks/CTweakGui.hpp index bac5fa1b..06431fdf 100644 --- a/include/MetroidPrime/Tweaks/CTweakGui.hpp +++ b/include/MetroidPrime/Tweaks/CTweakGui.hpp @@ -142,6 +142,13 @@ public: const CColor& GetCreditsTextFontColor() const { return x300_; } const CColor& GetCreditsTextBorderColor() const { return x304_; } + + static float FaceReflectionDistanceDebugValueToActualValue(float v); + static float FaceReflectionHeightDebugValueToActualValue(float v); + static float FaceReflectionAspectDebugValueToActualValue(float v); + static float FaceReflectionOrthoWidthDebugValueToActualValue(float v); + static float FaceReflectionOrthoHeightDebugValueToActualValue(float v); + private: bool x4_; float x8_mapAlphaInterp; @@ -217,11 +224,11 @@ private: bool x130_noAbsoluteFreeLookSfxPitch; float x134_; float x138_; - uint x13c_faceReflectionOrthoWidth; - uint x140_faceReflectionOrthoHeight; - uint x144_faceReflectionDistance; - uint x148_faceReflectionHeight; - uint x14c_faceReflectionAspect; + float x13c_faceReflectionOrthoWidth; + float x140_faceReflectionOrthoHeight; + float x144_faceReflectionDistance; + float x148_faceReflectionHeight; + float x14c_faceReflectionAspect; rstl::string x150_; rstl::string x160_; rstl::string x170_; diff --git a/src/MetroidPrime/Player/CSamusFaceReflection.cpp b/src/MetroidPrime/Player/CSamusFaceReflection.cpp new file mode 100644 index 00000000..c23fd704 --- /dev/null +++ b/src/MetroidPrime/Player/CSamusFaceReflection.cpp @@ -0,0 +1,149 @@ +#include "MetroidPrime/Player/CSamusFaceReflection.hpp" + +#include "MetroidPrime/CActorLights.hpp" +#include "MetroidPrime/CAnimData.hpp" +#include "MetroidPrime/CAnimPlaybackParms.hpp" +#include "MetroidPrime/CAnimRes.hpp" +#include "MetroidPrime/CStateManager.hpp" +#include "MetroidPrime/CWorld.hpp" +#include "MetroidPrime/Cameras/CCameraManager.hpp" +#include "MetroidPrime/Cameras/CFirstPersonCamera.hpp" +#include "MetroidPrime/Player/CPlayer.hpp" +#include "MetroidPrime/TCastTo.hpp" +#include "MetroidPrime/Tweaks/CTweakGui.hpp" +#include "MetroidPrime/Tweaks/CTweakPlayer.hpp" + + +#include "Kyoto/CResFactory.hpp" +#include "Kyoto/Graphics/CGraphics.hpp" +#include "Kyoto/Graphics/CModelFlags.hpp" +#include "Kyoto/Math/CRelAngle.hpp" + + +static const CTransform4f PreXf = + CTransform4f::Scale(0.3f) * CTransform4f::Translate(CVector3f(0.f, 0.5f, 0.f)); + +CSamusFaceReflection::CSamusFaceReflection(const CStateManager& stateMgr) +: x0_modelData(CModelData(CAnimRes(gpResourceFactory->GetResourceIdByName("ACS_SamusFace")->id, + CAnimRes::kDefaultCharIdx, CVector3f(1.f, 1.f, 1.f), 0, true))) +, x4c_lights(new CActorLights(8, CVector3f::Zero(), 4, 4, 0.1f, false, false, false)) +, x50_lookRot(CQuaternion::NoRotation()) +, x60_lookDir(CVector3f::Forward()) +, x6c_(0) +, x70_hidden(true) { + + CAnimPlaybackParms parms(0, -1, 1.f, true); + x0_modelData.AnimationData()->SetAnimation(parms, false); +} + +void CSamusFaceReflection::Update(float dt, const CStateManager& mgr, CRandom16& rand) { + if (const CFirstPersonCamera* fpCam = + TCastToConstPtr< CFirstPersonCamera >(mgr.GetCameraManager()->GetCurrentCamera(mgr))) { + CVector3f camTrans = fpCam->GetTranslation(); + x0_modelData.AdvanceAnimationIgnoreParticles(dt, rand, true); + x4c_lights->SetFindShadowLight(false); + TAreaId areaId = mgr.GetPlayer()->GetCurrentAreaId(); + if (areaId == kInvalidAreaId) + return; + + CAABox aabb( + CVector3f(camTrans.GetX() - 0.125f, camTrans.GetY() - 0.125f, camTrans.GetZ() - 0.125f), + CVector3f(camTrans.GetX() + 0.125f, camTrans.GetY() + 0.125f, camTrans.GetZ() + 0.125f)); + + const CGameArea& area = mgr.GetWorld()->GetAreaAlways(areaId); + x4c_lights->BuildFaceLightList(mgr, area, aabb); + + CMatrix3f matrix = fpCam->GetTransform().BuildMatrix3f(); + CUnitVector3f lookDir(matrix.GetColumn(kDY)); + + CQuaternion xfLook1 = CQuaternion::LookAt(CUnitVector3f(lookDir), CUnitVector3f::Forward(), + CRelAngle::FromRadians(M_2PIF)); + CQuaternion xfLook2 = CQuaternion::LookAt( + CUnitVector3f::Forward(), xfLook1.Transform(x60_lookDir), CRelAngle::FromRadians(M_2PIF)); + xfLook2 = xfLook2 * xfLook2; + + CVector3f lookCenter = xfLook2.BuildTransform().GetColumn(kDY); + CVector3f lookRotCenter = x50_lookRot.BuildTransform().GetColumn(kDY); + float lookDot = CVector3f::Dot(lookCenter, lookRotCenter); + + float freeLookSpeed = dt * gpTweakPlayer->GetFreeLookSpeed() * 0.5f; + + if (fabsf(lookDot) >= 1.f) + lookDot = 1.f; + + float lookAng = acos(lookDot); + + float f = 0.0f; + if (lookAng > 0.0f) { + f = freeLookSpeed / lookAng; + } + x50_lookRot = + CQuaternion::SlerpLocal(x50_lookRot, xfLook2, CMath::Clamp(0.0f, dt * 18.0f * f, 1.0f)); + x60_lookDir = lookDir; + } +} + +void CSamusFaceReflection::PreDraw(const CStateManager& mgr) { + if ((x6c_ == 2 || (x4c_lights->GetActiveLightCount() < 1 && (x6c_ == 0 || x6c_ == 3))) || + !TCastToConstPtr< CFirstPersonCamera >(mgr.GetCameraManager()->GetCurrentCamera(mgr))) { + x70_hidden = true; + } else { + x70_hidden = false; + x0_modelData.AnimationData()->PreRender(); + } +} + +void CSamusFaceReflection::Draw(const CStateManager& mgr) const { + if (x70_hidden) + return; + + if (const CFirstPersonCamera* fpCam = + TCastToConstPtr< CFirstPersonCamera >(mgr.GetCameraManager()->GetCurrentCamera(mgr))) { + + CVector3f camTranslation = fpCam->GetTransform().GetTranslation(); + CVector3f camYcol = fpCam->GetTransform().GetColumn(kDY); + CVector3f camZcol = fpCam->GetTransform().GetColumn(kDZ); + + CQuaternion camRot(CQuaternion::FromMatrix(fpCam->GetTransform())); + + float dist = CTweakGui::FaceReflectionDistanceDebugValueToActualValue( + gpTweakGui->GetFaceReflectionDistance()); + float height = CTweakGui::FaceReflectionHeightDebugValueToActualValue( + gpTweakGui->GetFaceReflectionHeight()); + float aspect = CTweakGui::FaceReflectionAspectDebugValueToActualValue( + gpTweakGui->GetFaceReflectionAspect()); + float orthoWidth = CTweakGui::FaceReflectionOrthoWidthDebugValueToActualValue( + gpTweakGui->GetFaceReflectionOrthoWidth()); + float orthoHeight = CTweakGui::FaceReflectionOrthoHeightDebugValueToActualValue( + gpTweakGui->GetFaceReflectionOrthoHeight()); + + CVector3f camZHeight = height * camZcol; + CVector3f camYDist = dist * camYcol; + CVector3f vec1( + camTranslation.GetX() + camYDist.GetX() + camZHeight.GetX(), + camTranslation.GetY() + camYDist.GetY() + camZHeight.GetY(), + camTranslation.GetZ() + camYDist.GetZ() + camZHeight.GetZ()); + ; + CTransform4f modelXf = CTransform4f((camRot * x50_lookRot).BuildTransform(), vec1) * PreXf; + + CGraphics::SetViewPointMatrix(fpCam->GetTransform()); + CGraphics::SetOrtho(aspect * -orthoWidth, aspect * orthoWidth, orthoHeight, -orthoHeight, -10.f, + 10.f); + + CActorLights* lights = x6c_ == 1 ? nullptr : x4c_lights.get(); + if (x6c_ == 3) { + x0_modelData.Render(mgr, modelXf, lights, CModelFlags::Normal()); + } else { + CPlayerState::EPlayerVisor visor = mgr.GetPlayerState()->GetActiveVisor(mgr); + float transFactor; + if (visor == CPlayerState::kPV_Combat) + transFactor = mgr.GetPlayerState()->GetVisorTransitionFactor(); + else + transFactor = 0.f; + if (transFactor > 0.f) { + x0_modelData.Render(mgr, modelXf, nullptr, CModelFlags::Additive(CColor::Black()).DepthCompareUpdate(true, true)); + x0_modelData.Render(mgr, modelXf, lights, CModelFlags::Additive(transFactor).DepthCompareUpdate(true, false)); + } + } + } +}