1#include "Library/Camera/CameraPoser.h"
2
3#include <gfx/seadCamera.h>
4
5#include "Library/Area/AreaObjDirector.h"
6#include "Library/Audio/System/AudioKeeper.h"
7#include "Library/Base/StringUtil.h"
8#include "Library/Camera/CameraArrowCollider.h"
9#include "Library/Camera/CameraOffsetCtrlPreset.h"
10#include "Library/Camera/CameraParamMoveLimit.h"
11#include "Library/Camera/CameraPoserFlag.h"
12#include "Library/Camera/CameraPoserFunction.h"
13#include "Library/Camera/CameraPoserSceneInfo.h"
14#include "Library/Camera/CameraStartInfo.h"
15#include "Library/Camera/CameraTargetAreaLimitter.h"
16#include "Library/Camera/CameraViewCtrlGyro.h"
17#include "Library/Camera/SnapShotCameraCtrl.h"
18#include "Library/Math/MathUtil.h"
19#include "Library/Nerve/NerveKeeper.h"
20#include "Library/Play/Camera/CameraVerticalAbsorber.h"
21#include "Library/Rail/RailKeeper.h"
22#include "Library/Yaml/ByamlIter.h"
23#include "Library/Yaml/ByamlUtil.h"
24#include "Project/Camera/CameraAngleCtrlInfo.h"
25#include "Project/Camera/CameraAngleSwingInfo.h"
26#include "Project/Camera/CameraObjectRequestInfo.h"
27
28namespace al {
29
30CameraPoser::CameraPoser(const char* name) : mPoserName(name) {
31 mPoserFlag = new CameraPoserFlag();
32 mActiveInterpoleParam = new CameraInterpoleParam();
33 mEndInterpoleParam = new CameraInterpoleStep();
34};
35
36bool CameraPoser::tryCalcOrthoProjectionInfo(OrthoProjectionInfo* projectionInfo) const {
37 OrthoProjectionParam* param = mOrthoProjectionParam;
38 if (param && param->isSetInfo && param->info.nearClipWidth > 0.1f &&
39 param->info.nearClipHeight > 0.1f) {
40 *projectionInfo = {.nearClipWidth: param->info.nearClipWidth, .nearClipHeight: param->info.nearClipHeight};
41 return true;
42 }
43 return false;
44}
45
46bool CameraPoser::isEnableRotateByPad() const {
47 if (mAngleCtrlInfo)
48 return !mAngleCtrlInfo->isFixByRangeHV();
49
50 if (mAngleSwingInfo)
51 return !mAngleSwingInfo->isInvalidSwing();
52
53 return false;
54}
55
56f32 CameraPoser::getFovyDegree() const {
57 if (alCameraPoserFunction::isSnapShotMode(this) && mSnapShotCtrl)
58 return mSnapShotCtrl->getFovyDegree();
59
60 return mFovyDegree;
61}
62
63f32 CameraPoser::getSceneFovyDegree() const {
64 return mSceneInfo->sceneFovyDegree;
65}
66
67AreaObjDirector* CameraPoser::getAreaObjDirector() const {
68 return mSceneInfo->areaObjDirector;
69}
70
71CollisionDirector* CameraPoser::getCollisionDirector() const {
72 return mSceneInfo->collisionDirector;
73}
74
75CameraInputHolder* CameraPoser::getInputHolder() const {
76 return mSceneInfo->inputHolder;
77}
78
79CameraTargetHolder* CameraPoser::getTargetHolder() const {
80 return mSceneInfo->targetHolder;
81}
82
83CameraFlagCtrl* CameraPoser::getFlagCtrl() const {
84 return mSceneInfo->flagCtrl;
85}
86
87RailRider* CameraPoser::getRailRider() const {
88 return mRailKeeper ? mRailKeeper->getRailRider() : nullptr;
89}
90
91bool CameraPoser::isInterpoleByCameraDistance() const {
92 return mActiveInterpoleParam->stepType == CameraInterpoleStepType::ByCameraDistance;
93}
94
95s32 CameraPoser::getInterpoleStep() const {
96 return mActiveInterpoleParam->stepNum < 0 ? 60 : mActiveInterpoleParam->stepNum;
97}
98
99void CameraPoser::setInterpoleStep(s32 step) {
100 mActiveInterpoleParam->set(type: CameraInterpoleStepType::ByStep, step, isInterpolate: true);
101}
102
103void CameraPoser::resetInterpoleStep() {
104 mActiveInterpoleParam->set(type: CameraInterpoleStepType::ByCameraDistance, step: -1, isInterpolate: false);
105}
106
107bool CameraPoser::isInterpoleEaseOut() const {
108 return mActiveInterpoleParam->isEaseOut;
109}
110
111void CameraPoser::setInterpoleEaseOut() {
112 mActiveInterpoleParam->isEaseOut = true;
113}
114
115bool CameraPoser::isEndInterpoleByStep() const {
116 return mEndInterpoleParam->stepType == CameraInterpoleStepType::ByStep;
117}
118
119s32 CameraPoser::getEndInterpoleStep() const {
120 return mEndInterpoleParam->stepNum;
121}
122
123void CameraPoser::initNerve(const Nerve* nerve, s32 maxStates) {
124 mNerveKeeper = new NerveKeeper(this, nerve, maxStates);
125}
126
127void CameraPoser::initArrowCollider(CameraArrowCollider* arrowCollider) {
128 mArrowCollider = arrowCollider;
129 mPoserFlag->isInvalidCollider = false;
130}
131
132void CameraPoser::initAudioKeeper(const char* name) {
133 mAudioKeeper =
134 alAudioKeeperFunction::createAudioKeeper(mSceneInfo->audioDirector, name, nullptr);
135}
136
137void CameraPoser::initRail(const PlacementInfo& info) {
138 mRailKeeper = new RailKeeper(info);
139}
140
141void CameraPoser::initLocalInterpole() {
142 mLocalInterpole = new LocalInterpole();
143}
144
145void CameraPoser::initLookAtInterpole(f32 v) {
146 mLookAtInterpole = new LookAtInterpole(v);
147}
148
149void CameraPoser::initOrthoProjectionParam() {
150 mOrthoProjectionParam = new OrthoProjectionParam();
151}
152
153void CameraPoser::tryInitAreaLimitter(const PlacementInfo& info) {
154 mTargetAreaLimitter = CameraTargetAreaLimitter::tryCreate(placementInfo: info);
155}
156
157inline void CameraPoser::CameraInterpoleParam::set(CameraInterpoleStepType type, s32 step,
158 bool is_interpolate_by_step) {
159 stepType = type;
160 stepNum = step;
161 isInterpolateByStep = is_interpolate_by_step;
162}
163
164inline void CameraPoser::CameraInterpoleParam::load(const ByamlIter& iter) {
165 tryGetByamlS32((s32*)&stepType, iter, "InterpoleStepType");
166
167 const char* curveType = nullptr;
168 if (tryGetByamlString(&curveType, iter, "InterpoleCurveType") != 0 && curveType &&
169 isEqualString(str1: curveType, str2: "EaseOut"))
170 isEaseOut = true;
171
172 isInterpolateByStep = tryGetByamlS32(&stepNum, iter, "InterpoleStep");
173 if (isInterpolateByStep)
174 stepType = CameraInterpoleStepType::ByStep;
175}
176
177inline void CameraPoser::CameraInterpoleStep::load(const ByamlIter& iter) {
178 ByamlIter newIter;
179 if (tryGetByamlIterByKey(&newIter, iter, "EndInterpoleParam")) {
180 if (isEqualString(str1: getByamlKeyString(newIter, "Type"), str2: "Step"))
181 stepType = CameraInterpoleStepType::ByStep;
182 if (stepType == CameraInterpoleStepType::ByStep)
183 stepNum = getByamlKeyInt(newIter, "Step");
184 }
185}
186
187inline void CameraPoser::OrthoProjectionParam::load(const ByamlIter& iter) {
188 bool isExist = tryGetByamlBool(&isSetInfo, iter, "IsSetOrthoProjectionInfo");
189
190 if (isExist && isSetInfo) {
191 tryGetByamlF32(&info.nearClipWidth, iter, "OrthoProjectionNearClipWidth");
192 tryGetByamlF32(&info.nearClipHeight, iter, "OrthoProjectionNearClipHeight");
193 }
194}
195
196void CameraPoser::load(const ByamlIter& iter) {
197 loadParam(iter);
198 tryGetByamlF32(&mFovyDegree, iter, "FovyDegree");
199
200 mPoserFlag->load(iter);
201 mActiveInterpoleParam->load(iter);
202 mEndInterpoleParam->load(iter);
203
204 if (mVerticalAbsorber)
205 mVerticalAbsorber->load(iter);
206
207 if (mAngleCtrlInfo)
208 mAngleCtrlInfo->load(iter);
209
210 if (mAngleSwingInfo)
211 mAngleSwingInfo->load(iter);
212
213 if (mOffsetCtrlPreset)
214 mOffsetCtrlPreset->load(iter);
215
216 if (mParamMoveLimit)
217 mParamMoveLimit->load(iter);
218
219 if (mSnapShotCtrl)
220 mSnapShotCtrl->load(iter);
221
222 if (mOrthoProjectionParam)
223 mOrthoProjectionParam->load(iter);
224}
225
226bool CameraPoser::isFirstCalc() const {
227 return mPoserFlag->isFirstCalc;
228}
229
230void CameraPoser::appear(const CameraStartInfo& info) {
231 mActiveState = ActiveState::Active;
232 if (mAngleCtrlInfo) {
233 sead::Vector3f vec = {0, 0, 0};
234 alCameraPoserFunction::calcPreCameraDir(&vec, this);
235 mAngleCtrlInfo->start(sead::Mathf::rad2deg(rad: asinf(vec.y)));
236 }
237
238 if (mAngleSwingInfo)
239 mAngleSwingInfo->setCurrentAngle({0, 0});
240
241 start(info);
242
243 if (mArrowCollider && !mPoserFlag->isInvalidCollider)
244 mArrowCollider->start();
245
246 if (mVerticalAbsorber && !mPoserFlag->isOffVerticalAbsorb)
247 mVerticalAbsorber->start(mTargetTrans, info);
248
249 if (mLookAtInterpole)
250 mLookAtInterpole->lookAtPos.set(mTargetTrans);
251}
252
253// TODO: CameraPoser::movement
254
255inline void CameraPoser::LocalInterpole::interpolate(sead::LookAtCamera* cam) {
256 if (step > -1) {
257 f32 rate = hermiteRate(t: normalize(x: step, min: 0, max: end), m0: 1.5f, m1: 0.0f);
258
259 sead::Vector3f camPosNext = sead::Vector3f(0, 0, 0);
260 sead::Vector3f lookAtPosNext = sead::Vector3f(0, 0, 0);
261 lerpVec(&camPosNext, prevCameraPos, cam->getPos(), rate);
262 lerpVec(&lookAtPosNext, prevLookAtPos, cam->getAt(), rate);
263
264 cam->setPos(camPosNext);
265 cam->setAt(lookAtPosNext);
266 }
267}
268
269void CameraPoser::makeLookAtCameraPrev(sead::LookAtCamera* cam) const {
270 cam->setPos(mPosition);
271 cam->setAt(mTargetTrans);
272 cam->setUp(mCameraUp);
273 cam->normalizeUp();
274
275 if (mVerticalAbsorber && !mPoserFlag->isOffVerticalAbsorb)
276 mVerticalAbsorber->makeLookAtCamera(cam);
277
278 if (mLocalInterpole)
279 mLocalInterpole->interpolate(cam);
280
281 if (mAngleSwingInfo)
282 mAngleSwingInfo->makeLookAtCamera(camera: cam);
283
284 if (mTargetAreaLimitter) {
285 sead::Vector3f camPosNext = cam->getAt();
286 if (mTargetAreaLimitter->applyAreaLimit(out: &camPosNext, vec: camPosNext)) {
287 sead::Vector3f camDiff = camPosNext - cam->getAt();
288 cam->setPos(camDiff + cam->getPos());
289 cam->setAt(camDiff + cam->getAt());
290 }
291 }
292}
293
294void CameraPoser::makeLookAtCameraPost(sead::LookAtCamera* cam) const {
295 if (alCameraPoserFunction::isSnapShotMode(this) && mSnapShotCtrl)
296 mSnapShotCtrl->makeLookAtCameraPost(cam);
297
298 if (mParamMoveLimit)
299 mParamMoveLimit->apply(camera: cam);
300}
301
302void CameraPoser::makeLookAtCameraLast(sead::LookAtCamera* cam) const {
303 if (alCameraPoserFunction::isSnapShotMode(this) && mSnapShotCtrl)
304 mSnapShotCtrl->makeLookAtCameraLast((cam));
305}
306
307void CameraPoser::makeLookAtCameraCollide(sead::LookAtCamera* cam) const {
308 if (!mPoserFlag->isInvalidCollider && mArrowCollider)
309 mArrowCollider->makeLookAtCamera(cam);
310}
311
312void CameraPoser::calcCameraPose(sead::LookAtCamera* cam) const {
313 makeLookAtCameraPrev(cam);
314 makeLookAtCamera(cam);
315 makeLookAtCameraPost(cam);
316 makeLookAtCameraCollide(cam);
317 makeLookAtCameraLast(cam);
318}
319
320bool CameraPoser::receiveRequestFromObjectCore(const CameraObjectRequestInfo& info) {
321 if (receiveRequestFromObject(info))
322 return true;
323
324 if (mVerticalAbsorber && info.isStopVerticalAbsorb) {
325 mVerticalAbsorber->liberateAbsorb();
326 return true;
327 }
328 if (mAngleCtrlInfo && mAngleCtrlInfo->receiveRequestFromObject(info))
329 return true;
330
331 return false;
332}
333
334void CameraPoser::startSnapShotModeCore() {
335 if (mSnapShotCtrl)
336 mSnapShotCtrl->start(mFovyDegree);
337
338 startSnapShotMode();
339}
340
341void CameraPoser::endSnapShotModeCore() {
342 endSnapShotMode();
343}
344} // namespace al
345