OdysseyDecomp/lib/al/Library/Play/Camera/CameraVerticalAbsorber.cpp

178 lines
6.9 KiB
C++

#include "Library/Play/Camera/CameraVerticalAbsorber.h"
#include <gfx/seadViewport.h>
#include "Library/Camera/CameraPoser.h"
#include "Library/Camera/CameraPoserFunction.h"
#include "Library/Camera/CameraStartInfo.h"
#include "Library/Math/MathUtil.h"
#include "Library/Nerve/NerveSetupUtil.h"
#include "Library/Nerve/NerveUtil.h"
#include "Library/Screen/ScreenFunction.h"
#include "Library/Yaml/ByamlUtil.h"
namespace {
using namespace al;
NERVE_IMPL(CameraVerticalAbsorber, FollowGround);
NERVE_IMPL(CameraVerticalAbsorber, FollowAbsolute);
NERVE_IMPL_(CameraVerticalAbsorber, FollowClimbPoleNoInterp, FollowClimbPole);
NERVE_IMPL_(CameraVerticalAbsorber, FollowSlow, Follow);
NERVE_IMPL(CameraVerticalAbsorber, Absorb);
NERVE_IMPL(CameraVerticalAbsorber, Follow);
NERVE_IMPL(CameraVerticalAbsorber, FollowClimbPole);
NERVES_MAKE_STRUCT(CameraVerticalAbsorber, FollowGround, FollowAbsolute, FollowClimbPoleNoInterp,
FollowSlow, Absorb, Follow, FollowClimbPole);
} // namespace
namespace al {
CameraVerticalAbsorber::CameraVerticalAbsorber(const CameraPoser* cameraParent,
bool isCameraPosAbsorb)
: NerveExecutor("カメラの縦パン"), mCameraPoser(cameraParent),
mIsNoCameraPosAbsorb(isCameraPosAbsorb) {
initNerve(&NrvCameraVerticalAbsorber.FollowGround);
}
void CameraVerticalAbsorber::load(const ByamlIter& iter) {
ByamlIter verticalAbsorbIter;
if (!iter.tryGetIterByKey(&verticalAbsorbIter, "VerticalAbsorb"))
return;
tryGetByamlF32(&mAbsorbScreenPosUp, verticalAbsorbIter, "AbsorbScreenPosUp");
tryGetByamlF32(&mAbsorbScreenPosDown, verticalAbsorbIter, "AbsorbScreenPosDown");
tryGetByamlF32(&mHighJumpJudgeSpeedV, verticalAbsorbIter, "HighJumpJudgeSpeedV");
ByamlIter advanceAbsorbUpIter;
if (verticalAbsorbIter.tryGetIterByKey(&advanceAbsorbUpIter, "AdvanceAbsorbUp")) {
mIsAdvanceAbsorbUp = true;
mAdvanceAbsorbScreenPosUp =
getByamlKeyFloat(advanceAbsorbUpIter, "AdvanceAbsorbScreenPosUp");
}
}
void CameraVerticalAbsorber::start(const sead::Vector3f& pos, const CameraStartInfo& info) {
alCameraPoserFunction::calcTargetFront(&mPrevTargetFront, mCameraPoser);
mAbsorbVec = {0.0f, 0.0f, 0.0f};
mPrevTargetTrans.set(pos);
if (!isValid() || alCameraPoserFunction::isPlayerTypeNotTouchGround(mCameraPoser))
return setNerve(this, &NrvCameraVerticalAbsorber.FollowAbsolute);
if (alCameraPoserFunction::isTargetClimbPole(mCameraPoser))
return setNerve(this, &NrvCameraVerticalAbsorber.FollowClimbPoleNoInterp);
if (alCameraPoserFunction::isTargetGrabCeil(mCameraPoser))
return setNerve(this, &NrvCameraVerticalAbsorber.FollowSlow);
if (!info._25 || alCameraPoserFunction::isTargetCollideGround(mCameraPoser))
return setNerve(this, &NrvCameraVerticalAbsorber.FollowGround);
mPrevTargetTrans.set(alCameraPoserFunction::getPreLookAtPos(mCameraPoser));
const CameraPoser* poser = mCameraPoser;
sead::Vector3f gravity = {0.0f, 0.0f, 0.0f};
alCameraPoserFunction::calcTargetGravity(&gravity, poser);
mAbsorbVec = pos - mPrevTargetTrans;
parallelizeVec(&mAbsorbVec, gravity, mAbsorbVec);
setNerve(this, &NrvCameraVerticalAbsorber.Absorb);
}
bool CameraVerticalAbsorber::isValid() const {
return !_1aa && !mIsInvalidated;
}
inline void updateAbsorbVec(sead::Vector3f* absorbVec, const CameraPoser* poser,
const sead::Vector3f& prevTrans) {
sead::Vector3f gravity = {0.0f, 0.0f, 0.0f};
alCameraPoserFunction::calcTargetGravity(&gravity, poser);
*absorbVec = poser->getTargetTrans() - prevTrans;
parallelizeVec(absorbVec, gravity, *absorbVec);
}
void CameraVerticalAbsorber::update() {
if (mIsStopUpdate)
return;
updateAbsorbVec(&mAbsorbVec, mCameraPoser, mPrevTargetTrans);
mLookAtCamera.setPos(mCameraPoser->getPosition());
mLookAtCamera.setAt(mCameraPoser->getTargetTrans());
mLookAtCamera.setUp(mCameraPoser->getCameraUp());
mLookAtCamera.normalizeUp();
makeLookAtCamera(&mLookAtCamera);
mLookAtCamera.updateViewMatrix();
mProjection.set(alCameraPoserFunction::getNear(mCameraPoser),
alCameraPoserFunction::getFar(mCameraPoser),
sead::Mathf::deg2rad(mCameraPoser->getFovyDegree()),
alCameraPoserFunction::getAspect(mCameraPoser));
alCameraPoserFunction::calcTargetFront(&mTargetFront, mCameraPoser);
if (!isNerve(this, &NrvCameraVerticalAbsorber.FollowGround) &&
alCameraPoserFunction::isTargetCollideGround(mCameraPoser))
setNerve(this, &NrvCameraVerticalAbsorber.FollowGround);
if (!isNerve(this, &NrvCameraVerticalAbsorber.FollowAbsolute) &&
alCameraPoserFunction::isPlayerTypeNotTouchGround(mCameraPoser))
setNerve(this, &NrvCameraVerticalAbsorber.FollowAbsolute);
updateNerve();
sead::Vector3f offset = {0.0f, 0.0f, 0.0f};
if (mIsKeepInFrame) {
sead::Vector3f offsetTrans = {0.0f, 0.0f, 0.0f};
alCameraPoserFunction::calcTargetTransWithOffset(&offsetTrans, mCameraPoser);
alCameraPoserFunction::calcOffsetCameraKeepInFrameV(
&offset, &mLookAtCamera, offsetTrans, mCameraPoser, mKeepInFrameOffsetUp,
alCameraPoserFunction::isPlayerTypeHighJump(mCameraPoser) ? 300.0f :
mKeepInFrameOffsetDown);
mAbsorbVec -= offset;
}
mPrevTargetTrans.set(mCameraPoser->getTargetTrans() - mAbsorbVec);
mPrevTargetFront.set(mTargetFront);
}
void CameraVerticalAbsorber::makeLookAtCamera(sead::LookAtCamera* lookAtCamera) const {
if (!isValid())
return;
lookAtCamera->setAt(lookAtCamera->getAt() - mAbsorbVec);
if (!mIsNoCameraPosAbsorb)
lookAtCamera->setPos(lookAtCamera->getPos() - mAbsorbVec);
}
void CameraVerticalAbsorber::liberateAbsorb() {
if (isNerve(this, &NrvCameraVerticalAbsorber.Absorb))
setNerve(this, &NrvCameraVerticalAbsorber.Follow);
}
bool CameraVerticalAbsorber::isAbsorbing() const {
return isValid() && isNerve(this, &NrvCameraVerticalAbsorber.Absorb);
}
void CameraVerticalAbsorber::invalidate() {
mIsInvalidated = true;
if (!isNerve(this, &NrvCameraVerticalAbsorber.FollowAbsolute))
setNerve(this, &NrvCameraVerticalAbsorber.FollowAbsolute);
}
void CameraVerticalAbsorber::tryResetAbsorbVecIfInCollision(const sead::Vector3f& pos) {
if (!alCameraPoserFunction::checkFirstCameraCollisionArrow(nullptr, nullptr, mCameraPoser,
pos + mAbsorbVec, -mAbsorbVec))
return;
mAbsorbVec = {0.0f, 0.0f, 0.0f};
if (alCameraPoserFunction::isTargetCollideGround(mCameraPoser))
setNerve(this, &NrvCameraVerticalAbsorber.FollowGround);
else
setNerve(this, &NrvCameraVerticalAbsorber.Follow);
}
void CameraVerticalAbsorber::exeFollowAbsolute() {
mAbsorbVec *= 0.8f;
}
} // namespace al