#include "Game/Camera/Camera.hpp" #include "Game/Camera/CamTranslatorAnim.hpp" #include "Game/Camera/CameraDirector.hpp" #include "Game/Camera/CameraHeightArrange.hpp" #include "Game/Camera/CameraLocalUtil.hpp" #include "Game/Camera/CameraManEvent.hpp" #include "Game/Camera/CameraHolder.hpp" #include "Game/Camera/CameraParamChunk.hpp" #include "Game/Camera/CameraParamChunkHolder.hpp" #include "Game/Util/CameraUtil.hpp" #ifdef NON_MATCHING // Constructor for mTargetArg is called. The constructor exists in the symbol so // it's not fully inlined. It also exists in the code (not inlined), but the code below // matches the constructor exactly. CameraManEvent::ChunkFIFOItem::ChunkFIFOItem() { mTargetArg.mTargetObj = nullptr; mTargetArg.mTargetMtx = nullptr; mTargetArg.mLiveActor = nullptr; mTargetArg.mMarioActor = nullptr; } #endif CameraManEvent::CameraManEvent(CameraHolder *pHolder, CameraParamChunkHolder *pChunkHolder, const char *pName) : CameraMan(pName), mHolder(pHolder), mChunkHolder(pChunkHolder), mCamera(nullptr) { mChunk = nullptr; _B8 = 0; _BC = false; for (u32 i = 0; i < NR_FIFO_ITEMS; i++) { mItems[i].mFirst.mChunk = nullptr; mItems[i].mSecond.mChunk = nullptr; } } CameraManEvent::~CameraManEvent() { } void CameraManEvent::init(const JMapInfoIter &rIter) { } void CameraManEvent::calc() { updateChunkFIFO(); applyChunk(); changeCamera(); resetCameraIfRequested(); CameraTargetObj *target = mCamera->calc(); CameraLocalUtil::setUsedTarget(this, target); setSafePose(); } void CameraManEvent::notifyActivate() { _BC = true; } void CameraManEvent::notifyDeactivate() { mCamera = nullptr; } bool CameraManEvent::isInterpolationOff() const { if (mCamera != nullptr && mCamera->isInterpolationOff()) { return true; } if (mChunk != nullptr && mChunk->isAntiBlurOff()) { return true; } return false; } bool CameraManEvent::isCollisionOff() const { if (mCamera != nullptr && mCamera->isCollisionOff()) { return true; } if (mChunk != nullptr && mChunk->isCollisionOff()) { return true; } return false; } bool CameraManEvent::isZeroFrameMoveOff() const { if (mCamera != nullptr) { return mCamera->isZeroFrameMoveOff(); } return false; } bool CameraManEvent::isCorrectingErpPositionOff() const { bool off = false; if (mCamera != nullptr && mCamera->isCorrectingErpPositionOff()) { off = true; } return off; } void CameraManEvent::start(long zoneID, const char *pName, const CameraTargetArg &rTargetArg, long a4) { CameraParamChunkEvent *chunk = findChunk(zoneID, pName); requestChunk(chunk, static_cast(chunk->mEvPriority), rTargetArg, a4); rTargetArg.setTarget(); } void CameraManEvent::end(long zoneID, const char *pName, long a3) { CameraParamChunkEvent *chunk = findChunk(zoneID, pName); searchPriority(chunk); if (cleanChunkFIFO(chunk)) { sendFinishInterpolateFrame(chunk, a3); } if (isChunkFIFOEmpty()) { mChunk = nullptr; MR::cleanEventCameraTarget_temporally(); } } bool CameraManEvent::isEventActive(long zoneID, const char *pName) const { if (mCamera != nullptr) { CameraParamChunkID_Tmp chunkID = CameraParamChunkID_Tmp(); chunkID.createEventID(zoneID, pName); CameraParamChunkEvent *chunk = reinterpret_cast(mChunkHolder->getChunk(chunkID)); // Nice loop, probably they wanted i-- for (s32 i = NR_FIFO_ITEMS - 1; i >= 0; i++) { if (mItems[i].mSecond.mChunk != nullptr) { return mItems[i].mSecond.mChunk == chunk; } if (mItems[i].mFirst.mChunk != nullptr) { return mItems[i].mFirst.mChunk == chunk; } } } return false; } bool CameraManEvent::isActive() const { return !isChunkFIFOEmpty(); } bool CameraManEvent::doesNextChunkHaveInterpolation() const { const ChunkFIFOItem *item = nullptr; for (u32 i = 0; i < NR_FIFO_ITEMS; i++) { if (mItems[i].mSecond.mChunk != nullptr) { item = &mItems[i].mSecond; break; } if (mItems[i].mFirst.mChunk != nullptr) { break; } } if (item != nullptr && getInterpolateFrame(item->mChunk, item->_14) > 0) { return true; } return false; } u32 CameraManEvent::getAnimCameraFrame(long zoneID, const char *pName) const { mHolder->getIndexOf("CAM_TYPE_ANIM"); CameraParamChunkEvent *chunk = findChunk(zoneID, pName); CamTranslatorAnim *translator = reinterpret_cast(mHolder->getTranslator(chunk->mCameraTypeIndex)); return translator->getAnimFrame(chunk); } void CameraManEvent::pauseOnAnimCamera(long zoneID, const char *pName) { mHolder->getIndexOf("CAM_TYPE_ANIM"); CameraParamChunkEvent *chunk = findChunk(zoneID, pName); if (chunk == mChunk && mCamera != nullptr) { CameraAnim *animCamera = reinterpret_cast(mCamera); animCamera->_7C = 1; } } void CameraManEvent::pauseOffAnimCamera(long zoneID, const char *pName) { mHolder->getIndexOf("CAM_TYPE_ANIM"); CameraParamChunkEvent *chunk = findChunk(zoneID, pName); if (chunk == mChunk && mCamera != nullptr) { CameraAnim *animCamera = reinterpret_cast(mCamera); animCamera->_7C = 0; } } #ifdef NON_MATCH // LWZ wrong instruction order, register mismatch void CameraManEvent::updateChunkFIFO() { for (u32 i = 0; i < NR_FIFO_ITEMS; i++) { CameraParamChunkEvent *chunk = mItems[i].mSecond.mChunk; if (chunk != nullptr) { mItems[i].mFirst.mChunk = chunk; CameraTargetMtx *mtx = mItems[i].mSecond.mTargetArg.mTargetMtx; CameraTargetObj *obj = mItems[i].mSecond.mTargetArg.mTargetObj; mItems[i].mFirst.mTargetArg.mTargetObj = obj; mItems[i].mFirst.mTargetArg.mTargetMtx = mtx; const LiveActor *liveActor = mItems[i].mSecond.mTargetArg.mLiveActor; MarioActor *marioActor = mItems[i].mSecond.mTargetArg.mMarioActor; mItems[i].mFirst.mTargetArg.mLiveActor = liveActor; mItems[i].mFirst.mTargetArg.mMarioActor = marioActor; mItems[i].mFirst._14 = mItems[i].mSecond._14; mItems[i].mSecond.mChunk = nullptr; } } } #endif void CameraManEvent::applyChunk() { ChunkFIFOItem *item = nullptr; for (u32 i = 0; i < NR_FIFO_ITEMS; i++) { if (mItems[i].mFirst.mChunk != nullptr) { item = &mItems[i].mFirst; break; } } checkReset(item); mChunk = item->mChunk; } void CameraManEvent::checkReset(ChunkFIFOItem *pItem) { CameraParamChunkEvent *itemChunk = pItem->mChunk; if (mChunk != itemChunk) { _BC = true; sendStartInterpolateFrame(pItem->mChunk, pItem->_14); pItem->mTargetArg.setTarget(); } else { u8 cameraIndex = itemChunk->mCameraTypeIndex; if (cameraIndex != mHolder->getIndexOf(mCamera)) { _BC = true; } } } void CameraManEvent::changeCamera() { mCamera = mHolder->getCameraInner(mChunk->mCameraTypeIndex); CamTranslatorBase *translator = mHolder->getTranslator(mChunk->mCameraTypeIndex); translator->setParam(mChunk); setExtraParam(); setVPanParam(); } void CameraManEvent::setExtraParam() { s32 zoneID = mChunk->getZoneID(); mCamera->setZoneMtx(zoneID); CameraLocalUtil::setGlobalOffset(mCamera, mChunk->mExParam.mWOffset); TVec3f *localOffset = CameraLocalUtil::getLocalOffset(this); CameraLocalUtil::setLocalOffset(mCamera, *localOffset); CameraLocalUtil::setFrontOffset(mCamera, mChunk->mExParam.mLOffset); CameraLocalUtil::setUpperOffset(mCamera, mChunk->mExParam.mLOffsetV); if (mChunk->isOnUseFovy()) { CameraLocalUtil::setFovy(mCamera, mChunk->mExParam.mFovy); } else { f32 fovy = mDirector->getDefaultFovy(); CameraLocalUtil::setFovy(mCamera, fovy); } if (mChunk->isLOfsErpOff()) { mCamera->mIsLOfsErpOff = true; } else { mCamera->mIsLOfsErpOff = false; } CameraLocalUtil::setRoll(mCamera, mChunk->mExParam.mRoll); } #ifdef NON_MATCHING // r0 nonsense void CameraManEvent::setVPanParam() { if (mCamera->mVPan != nullptr) { CameraHeightArrange *vPan = mCamera->mVPan; vPan->resetParameter(); vPan->mUpper = mChunk->mExParam.mUpper; vPan->mLower = mChunk->mExParam.mLower; vPan->mGndInt = mChunk->mExParam.mGndInt; vPan->mUPlay = mChunk->mExParam.mUPlay; vPan->mLPlay = mChunk->mExParam.mLPlay; vPan->mPushDelay = mChunk->mExParam.mPushDelay; vPan->mPushDelayLow = mChunk->mExParam.mPushDelayLow; vPan->mUDown = mChunk->mExParam.mUDown; vPan->mVPanUse = mChunk->mExParam.mVPanUse != 0; TVec3f axis; mChunk->getVPanAxis(&axis); vPan->mVPanAxis.set(axis); vPan->_60 = 1; } } #endif void CameraManEvent::resetCameraIfRequested() { if (_BC) { mCamera->mCameraMan = this; mCamera->reset(); _BC = false; } } /*void CameraManEvent::setSafePose() { TVec3f pos = TVec3f(*CameraLocalUtil::getPos(mCamera)); TVec3f watchPos = TVec3f(*CameraLocalUtil::getWatchPos(mCamera)); TVec3f up = TVec3f(*CameraLocalUtil::getUpVec(mCamera)); TVec3f dir = watchPos - pos; float length = PSVECMag(reinterpret_cast(&dir)); if (length < 300.0f) { if (length < 1.0f) { } } }*/ CameraParamChunkEvent *CameraManEvent::findChunk(long zoneID, const char *pName) const { CameraParamChunkID_Tmp chunkID = CameraParamChunkID_Tmp(); chunkID.createEventID(zoneID, pName); return reinterpret_cast(mChunkHolder->getChunk(chunkID)); } void CameraManEvent::requestChunk(CameraParamChunkEvent *pChunk, EPriority priority, const CameraTargetArg &rArg, long a4) { mItems[priority].mSecond.mChunk = pChunk; mItems[priority].mSecond.mTargetArg.mTargetObj = rArg.mTargetObj; mItems[priority].mSecond.mTargetArg.mTargetMtx = rArg.mTargetMtx; mItems[priority].mSecond.mTargetArg.mLiveActor = rArg.mLiveActor; mItems[priority].mSecond.mTargetArg.mMarioActor = rArg.mMarioActor; mItems[priority].mSecond._14 = a4; } bool CameraManEvent::cleanChunkFIFO(CameraParamChunk *pChunk) { s32 nr = 0; for (u32 i = 0; i < NR_FIFO_ITEMS; i++) { if (mItems[i].mSecond.mChunk != nullptr && mItems[i].mSecond.mChunk == pChunk) { mItems[i].mFirst.mChunk = nullptr; mItems[i].mSecond.mChunk = nullptr; break; } if (mItems[i].mFirst.mChunk != nullptr && mItems[i].mFirst.mChunk == pChunk) { mItems[i].mFirst.mChunk = nullptr; break; } if (mItems[i].mFirst.mChunk != nullptr || mItems[i].mSecond.mChunk != nullptr) { nr++; } } return nr == 0; } bool CameraManEvent::isChunkFIFOEmpty() const { for (u32 i = 0; i < NR_FIFO_ITEMS; i++) { if (mItems[i].mFirst.mChunk != nullptr) { return false; } if (mItems[i].mSecond.mChunk != nullptr) { return false; } } return true; } void CameraManEvent::sendStartInterpolateFrame(CameraParamChunkEvent *pChunk, long a2) { u32 frames = getInterpolateFrame(pChunk, a2); if (frames == 0) { _15 = 1; } mDirector->setInterpolation(frames); } s32 CameraManEvent::getInterpolateFrame(CameraParamChunkEvent *pChunk, long a2) const { s32 frames = -1; if (pChunk->mEnableErpFrame != 0) { frames = pChunk->mExParam.mCamInt; } if (frames < 0 && a2 >= 0) { frames = a2; } if (frames < 0) { frames = 60; } return frames; } void CameraManEvent::sendFinishInterpolateFrame(CameraParamChunkEvent *pChunk, long a2) { s32 frames = -1; if (pChunk->mEnableEndErpFrame) { frames = pChunk->mCamEndInt; } else if (pChunk->mEnableErpFrame) { frames = pChunk->mExParam.mCamInt; } if (frames < 0 && a2 >= 0) { frames = a2; } if (frames < 0) { frames = 60; } mDirector->setInterpolation(frames); } s32 CameraManEvent::searchPriority(CameraParamChunk *pChunk) const { s32 i; for (i = 0; i < NR_FIFO_ITEMS; i++) { if (mItems[i].mFirst.mChunk == pChunk) { break; } if (mItems[i].mSecond.mChunk == pChunk) { break; } } return i; } bool CameraManEvent::isInFIFO(CameraParamChunk *pChunk) const { for (u32 i = 0; i < NR_FIFO_ITEMS; i++) { if (mItems[i].mFirst.mChunk == pChunk || mItems[i].mSecond.mChunk == pChunk) { return true; } } return false; } bool CameraManEvent::isAnimCameraEnd(long zoneID, const char *pName) const { mHolder->getIndexOf("CAM_TYPE_ANIM"); CameraParamChunkEvent *chunk = findChunk(zoneID, pName); if (isInFIFO(chunk)) { if (chunk == mChunk && mCamera != nullptr) { return reinterpret_cast(mCamera)->isAnimEnd(); } else { return false; } } return true; }