1#include "Library/Play/Camera/CameraVerticalAbsorber.h"
2
3#include "Library/Camera/CameraPoser.h"
4#include "Library/Camera/CameraStartInfo.h"
5#include "Library/Math/MathUtil.h"
6#include "Library/Nerve/NerveSetupUtil.h"
7#include "Library/Nerve/NerveUtil.h"
8#include "Library/Yaml/ByamlUtil.h"
9
10namespace {
11using namespace al;
12NERVE_IMPL(CameraVerticalAbsorber, FollowGround);
13NERVE_IMPL(CameraVerticalAbsorber, FollowAbsolute);
14NERVE_IMPL_(CameraVerticalAbsorber, FollowClimbPoleNoInterp, Follow);
15NERVE_IMPL_(CameraVerticalAbsorber, FollowSlow, Absorb);
16NERVE_IMPL(CameraVerticalAbsorber, Absorb);
17NERVE_IMPL(CameraVerticalAbsorber, Follow);
18NERVE_IMPL(CameraVerticalAbsorber, FollowClimbPole);
19
20NERVES_MAKE_STRUCT(CameraVerticalAbsorber, FollowGround, FollowAbsolute, FollowClimbPoleNoInterp,
21 FollowSlow, Absorb, Follow, FollowClimbPole);
22} // namespace
23
24namespace al {
25
26void CameraVerticalAbsorber::exeFollowAbsolute() {
27 mTargetInterp *= 0.8f;
28}
29
30void CameraVerticalAbsorber::invalidate() {
31 mIsInvalidated = true;
32 if (!isNerve(user: this, nerve: &NrvCameraVerticalAbsorber.FollowAbsolute))
33 setNerve(user: this, nerve: &NrvCameraVerticalAbsorber.FollowAbsolute);
34}
35
36// NON_MATCHING
37void CameraVerticalAbsorber::start(const sead::Vector3f& pos, const CameraStartInfo& info) {
38 alCameraPoserFunction::calcTargetFront(&mPrevTargetFront, mCameraPoser);
39
40 mTargetInterp.x = 0.0f;
41 mTargetInterp.y = 0.0f;
42 mTargetInterp.z = 0.0f;
43
44 mPrevTargetTrans = pos;
45
46 if (unk_unusedBool || mIsInvalidated ||
47 alCameraPoserFunction::isPlayerTypeNotTouchGround(mCameraPoser))
48 return setNerve(user: this, nerve: &NrvCameraVerticalAbsorber.FollowAbsolute);
49 if (alCameraPoserFunction::isTargetClimbPole(mCameraPoser))
50 return setNerve(user: this, nerve: &NrvCameraVerticalAbsorber.FollowClimbPoleNoInterp);
51 if (alCameraPoserFunction::isTargetGrabCeil(mCameraPoser))
52 return setNerve(user: this, nerve: &NrvCameraVerticalAbsorber.FollowSlow);
53 if (!info.isGrounded || alCameraPoserFunction::isTargetCollideGround(mCameraPoser))
54 return setNerve(user: this, nerve: &NrvCameraVerticalAbsorber.FollowGround);
55
56 mPrevTargetTrans = alCameraPoserFunction::getPreLookAtPos(mCameraPoser);
57
58 sead::Vector3f target;
59
60 alCameraPoserFunction::calcTargetGravity(&target, mCameraPoser);
61 mTargetInterp = pos - mPrevTargetTrans;
62 parallelizeVec(&mTargetInterp, target, mTargetInterp);
63 setNerve(user: this, nerve: &NrvCameraVerticalAbsorber.Absorb);
64}
65
66void CameraVerticalAbsorber::load(const ByamlIter& data) {
67 ByamlIter it;
68 if (!data.tryGetIterByKey(iter: &it, key: "VerticalAbsorb"))
69 return;
70
71 tryGetByamlF32(&mAbsorbScreenPosUp, it, "AbsorbScreenPosUp");
72 tryGetByamlF32(&mAbsorbScreenPosDown, it, "AbsorbScreenPosDown");
73 tryGetByamlF32(&mHighJumpJudgeSpeedV, it, "HighJumpJudgeSpeedV");
74 ByamlIter it2;
75
76 if (!it.tryGetIterByKey(iter: &it2, key: "AdvanceAbsorbUp"))
77 return;
78 mIsAdvanceAbsorbUp = true;
79 mAdvanceAbsorbScreenPosUp = getByamlKeyFloat(it2, "AdvanceAbsorbScreenPosUp");
80}
81
82// NON_MATCHING
83void CameraVerticalAbsorber::update() {
84 if (mIsStopUpdate)
85 return;
86 sead::Vector3f gravity{};
87 alCameraPoserFunction::calcTargetGravity(&gravity, mCameraPoser);
88 mTargetInterp = mCameraPoser->getPosition() - mPrevTargetTrans;
89 parallelizeVec(&mTargetInterp, gravity, mTargetInterp);
90 mLookAtCamera.getPos() = mCameraPoser->getPosition();
91 mLookAtCamera.getAt() = mCameraPoser->getTargetTrans();
92 mLookAtCamera.getUp() = mCameraPoser->getCameraUp();
93 if (mLookAtCamera.getUp().length() > 0.0f)
94 mLookAtCamera.getUp().normalize();
95 if (!unk_unusedBool && !mIsInvalidated) {
96 mLookAtCamera.getAt() -= mTargetInterp;
97 if (!mIsNoCameraPosAbsorb)
98 mLookAtCamera.getPos() -= mTargetInterp;
99 }
100 mLookAtCamera.doUpdateMatrix(dst: &mLookAtCamera.getMatrix());
101 mProjection.set(near: alCameraPoserFunction::getNear(mCameraPoser),
102 far: alCameraPoserFunction::getFar(mCameraPoser),
103 fovy_rad: sead::Mathf::deg2rad(deg: mCameraPoser->getFovyDegree()),
104 aspect: alCameraPoserFunction::getAspect(mCameraPoser));
105 alCameraPoserFunction::calcTargetFront(&mTargetFront, mCameraPoser);
106 if (!isNerve(user: this, nerve: &NrvCameraVerticalAbsorber.FollowGround) &&
107 alCameraPoserFunction::isTargetCollideGround(mCameraPoser))
108 setNerve(user: this, nerve: &NrvCameraVerticalAbsorber.FollowGround);
109 if (!isNerve(user: this, nerve: &NrvCameraVerticalAbsorber.FollowAbsolute) &&
110 alCameraPoserFunction::isPlayerTypeNotTouchGround(mCameraPoser))
111 setNerve(user: this, nerve: &NrvCameraVerticalAbsorber.FollowAbsolute);
112 updateNerve();
113 sead::Vector3f prevTargetTrans = sead::Vector3f::zero;
114 if (!mIsKeepInFrame) {
115 prevTargetTrans = mTargetInterp;
116 } else {
117 sead::Vector3f offsetTrans = sead::Vector3f::zero;
118 alCameraPoserFunction::calcTargetTransWithOffset(&offsetTrans, mCameraPoser);
119 alCameraPoserFunction::calcOffsetCameraKeepInFrameV(
120 &gravity, &mLookAtCamera, offsetTrans, mCameraPoser, mKeepInFrameOffsetUp,
121 alCameraPoserFunction::isPlayerTypeHighJump(mCameraPoser) ? 300.0f :
122 mKeepInFrameOffsetDown);
123 prevTargetTrans = mTargetInterp - gravity;
124 }
125 mPrevTargetTrans = mCameraPoser->getTargetTrans() - prevTargetTrans;
126 mPrevTargetFront = mTargetFront;
127}
128
129} // namespace al
130