mirror of
https://github.com/zeldaret/ss
synced 2026-05-27 16:13:08 -04:00
592 lines
16 KiB
C++
592 lines
16 KiB
C++
#include "d/d_camera.h"
|
|
|
|
#include "c/c_math.h"
|
|
#include "common.h"
|
|
#include "d/a/d_a_player.h"
|
|
#include "d/col/bg/d_bg_s_gnd_chk.h"
|
|
#include "d/col/bg/d_bg_s_lin_chk.h"
|
|
#include "d/col/bg/d_bg_s_roof_chk.h"
|
|
#include "d/d_gfx.h"
|
|
#include "d/d_pad.h"
|
|
#include "d/d_sc_game.h"
|
|
#include "d/d_stage_mgr.h"
|
|
#include "d/snd/d_snd_3d_manager.h"
|
|
#include "egg/gfx/eggFrustum.h"
|
|
#include "egg/math/eggMatrix.h"
|
|
#include "f/f_base.h"
|
|
#include "f/f_profile.h"
|
|
#include "m/m_angle.h"
|
|
#include "m/m_mtx.h"
|
|
#include "m/m_vec.h"
|
|
#include "nw4r/g3d/g3d_camera.h"
|
|
#include "toBeSorted/d_camera_base.h"
|
|
#include "toBeSorted/d_camera_math.h"
|
|
#include "toBeSorted/event_manager.h"
|
|
|
|
class dCamera_HIO_c {
|
|
public:
|
|
dCamera_HIO_c();
|
|
virtual ~dCamera_HIO_c();
|
|
|
|
/* 0x04 */ f32 field_0x04;
|
|
/* 0x08 */ f32 field_0x08;
|
|
/* 0x0C */ f32 field_0x0C;
|
|
/* 0x10 */ s16 field_0x10;
|
|
/* 0x12 */ s16 field_0x12;
|
|
/* 0x14 */ f32 field_0x14;
|
|
/* 0x18 */ u16 field_0x18;
|
|
/* 0x1C */ f32 field_0x1C;
|
|
/* 0x20 */ f32 field_0x20;
|
|
/* 0x24 */ s16 field_0x24;
|
|
/* 0x28 */ f32 field_0x28;
|
|
/* 0x2C */ f32 field_0x2C;
|
|
/* 0x30 */ s16 field_0x30;
|
|
};
|
|
|
|
dCamera_HIO_c::~dCamera_HIO_c() {}
|
|
dCamera_HIO_c::dCamera_HIO_c() {
|
|
field_0x04 = 1.0f;
|
|
field_0x08 = 240000.0f;
|
|
field_0x14 = 0.1f;
|
|
field_0x18 = 0x1555;
|
|
field_0x1C = 30.0f;
|
|
field_0x20 = 30.0f;
|
|
field_0x24 = 8;
|
|
field_0x28 = 0.7f;
|
|
field_0x2C = 0.2f;
|
|
field_0x30 = 0;
|
|
field_0x0C = 1.0f;
|
|
field_0x10 = 1;
|
|
field_0x12 = 1;
|
|
}
|
|
|
|
static dCamera_HIO_c sHio;
|
|
|
|
SPECIAL_BASE_PROFILE(CAMERA, dCamera_c, fProfile::CAMERA, 0xA, 0x30);
|
|
|
|
void debugWarn2(const char *fmt, ...);
|
|
void debugPrintf7(const char *fmt, ...);
|
|
|
|
dCamera_c::dCamera_c()
|
|
: mMyCameraIndex(0),
|
|
mpScreen(dStageMgr_c::GetInstance()->getScreen(0)),
|
|
mYAngle(0),
|
|
mXZAngle(0),
|
|
field_0x1F8(0),
|
|
field_0x1FC(0),
|
|
mFlags(0) {
|
|
mScreenShaker.init(this);
|
|
field_0xDC0.setCamera(this);
|
|
field_0x08C = mVec3_c(0.0f, 1.0f, 0.0f);
|
|
|
|
mActiveCameraIdx = 0;
|
|
for (int i = 0; i < CAM_MAX; i++) {
|
|
mpCameras[i] = nullptr;
|
|
}
|
|
}
|
|
|
|
int dCamera_c::create() {
|
|
mFlags = 0;
|
|
mMyCameraIndex = getFromParams(0, 0xF);
|
|
dScGame_c::setCamera(mMyCameraIndex, nullptr);
|
|
mpCameras[CAM_GAME_0] = &mGameCam1;
|
|
mpCameras[CAM_GAME_1] = &mGameCam2;
|
|
mpCameras[CAM_EVENT] = &mEventCam;
|
|
mpCameras[CAM_MAP] = &mMapCam;
|
|
|
|
for (int i = 0; i < CAM_MAX; i++) {
|
|
if (mpCameras[i] == nullptr) {
|
|
continue;
|
|
}
|
|
if (!mpCameras[i]->doCreate(i)) {
|
|
return NOT_READY;
|
|
}
|
|
}
|
|
|
|
debugWarn2("u can NOT use debug camera!!"); // aww
|
|
mActiveCameraIdx = 0;
|
|
|
|
mpCameras[0]->activate();
|
|
|
|
mLetterboxAmount = getEventLetterboxAmount();
|
|
field_0x290 = 1.0f;
|
|
onFlag(CAM_FLAGS_IN_EVENT);
|
|
|
|
// TODO maybe struct + inline
|
|
mGlobalAlpha = 1.0f;
|
|
field_0x298 = field_0x299 = 0;
|
|
|
|
field_0x29C = 1.0f;
|
|
field_0x2A0 = field_0x2A1 = 0;
|
|
|
|
mView1 = mpCameras[mActiveCameraIdx]->getView();
|
|
|
|
field_0xDCC = false;
|
|
mYAngle = 0;
|
|
mXZAngle = 0;
|
|
|
|
dScGame_c::setCamera(mMyCameraIndex, this);
|
|
updateView();
|
|
apply();
|
|
|
|
const STIF *stif = dStageMgr_c::GetInstance()->getStif();
|
|
if (stif != nullptr) {
|
|
sHio.field_0x04 = stif->field_0x00;
|
|
sHio.field_0x08 = stif->field_0x04;
|
|
}
|
|
|
|
field_0x1FC = 0;
|
|
if ((dScGame_c::isCurrentStage("F000") && 26 <= dScGame_c::currentSpawnInfo.layer &&
|
|
dScGame_c::currentSpawnInfo.layer <= 28) ||
|
|
dScGame_c::isInCredits() || dScGame_c::isSeekerStoneStageAndLayer()) {
|
|
onFlag(CAM_FLAGS_NO_LETTERBOX_IN_EVENT);
|
|
dScGame_c::GetInstance()->setTargetingScreenLetterboxAmount(0.0f);
|
|
}
|
|
|
|
debugPrintf7("create ok!!");
|
|
|
|
return SUCCEEDED;
|
|
}
|
|
|
|
// Maybe inlines that couldn't be inlined due to variadics...
|
|
void debugWarn2(const char *fmt, ...) {
|
|
// no-op
|
|
}
|
|
|
|
void debugPrintf7(const char *fmt, ...) {
|
|
// no-op
|
|
}
|
|
|
|
int dCamera_c::doDelete() {
|
|
debugPrintf7("delete!!");
|
|
for (int i = 0; i < CAM_MAX; i++) {
|
|
// No null check needed :)
|
|
mpCameras[i]->doRemove();
|
|
}
|
|
dScGame_c::setCamera(mMyCameraIndex, nullptr);
|
|
return SUCCEEDED;
|
|
}
|
|
|
|
void dCamera_c::setWorldOffset(f32 x, f32 z) {
|
|
mView.mPosition.x += x;
|
|
mView.mPosition.z += z;
|
|
mView.mTarget.x += x;
|
|
mView.mTarget.z += z;
|
|
// TODO maybe inline
|
|
getGameCam1()->setView(mView);
|
|
getGameCam1()->onFlag(0x1);
|
|
getGameCam1()->onFlag(0x4000);
|
|
updateView();
|
|
apply();
|
|
}
|
|
|
|
int dCamera_c::execute() {
|
|
dAcPy_c *link = dAcPy_c::GetLinkM();
|
|
|
|
checkCameraChange();
|
|
|
|
for (int i = 0; i < CAM_MAX; i++) {
|
|
if (mpCameras[i] != nullptr) {
|
|
mpCameras[i]->doExecute();
|
|
}
|
|
}
|
|
|
|
if (mActiveCameraIdx == CAM_EVENT) {
|
|
// hmmmm
|
|
static_cast<dCameraGame_c *>(mpCameras[0])->clearCamIds();
|
|
}
|
|
|
|
updateView();
|
|
apply();
|
|
field_0xDC0.fn_8019E940();
|
|
|
|
field_0xDCC = false;
|
|
if (mActiveCameraIdx == CAM_EVENT) {
|
|
onFlag(CAM_FLAGS_IN_EVENT);
|
|
}
|
|
|
|
if (checkFlag(CAM_FLAGS_0x100 | CAM_FLAGS_IN_EVENT)) {
|
|
field_0x290 += (1.0f / sHio.field_0x24);
|
|
if (field_0x290 > 1.0f) {
|
|
field_0x290 = 1.0f;
|
|
}
|
|
} else {
|
|
field_0x290 = field_0x290 - (1.0f / sHio.field_0x24);
|
|
if (field_0x290 < 0.0f) {
|
|
field_0x290 = 0.0f;
|
|
}
|
|
}
|
|
|
|
f32 scale = checkFlag(CAM_FLAGS_IN_EVENT) != 0 ? getEventLetterboxAmount() : sHio.field_0x20;
|
|
f32 target = camEaseInOut(field_0x290, 1.0f);
|
|
mLetterboxAmount += (target * scale - mLetterboxAmount) * 0.5f;
|
|
|
|
if (mActiveCameraIdx == CAM_EVENT && checkFlag(CAM_FLAGS_NO_LETTERBOX_IN_EVENT) != 0) {
|
|
mLetterboxAmount = 0.0f;
|
|
}
|
|
|
|
dScGame_c::GetInstance()->setTargetingScreenLetterboxAmount(mLetterboxAmount);
|
|
offFlag(CAM_FLAGS_0x100 | CAM_FLAGS_IN_EVENT);
|
|
|
|
if (!link->checkActionFlagsCont(0x400000)) {
|
|
field_0x299 = 0;
|
|
}
|
|
|
|
f32 alphaTarget;
|
|
f32 alphaUpdateSpeed = sHio.field_0x2C;
|
|
if (EventManager::isInEvent()) {
|
|
alphaUpdateSpeed = 1.0f;
|
|
if (field_0x2A1 != 0) {
|
|
alphaTarget = field_0x2A0 ? sHio.field_0x28 : 0.0f;
|
|
} else {
|
|
alphaTarget = 1.0f;
|
|
}
|
|
} else {
|
|
if (field_0x299 != 0) {
|
|
alphaTarget = field_0x298 ? sHio.field_0x28 : 0.0f;
|
|
} else {
|
|
alphaTarget = 1.0f;
|
|
}
|
|
}
|
|
|
|
mGlobalAlpha += alphaUpdateSpeed * (alphaTarget - mGlobalAlpha);
|
|
dStageMgr_c::GetInstance()->setGlobalAlpha((u8)(mGlobalAlpha * 255.1f) & 0xFF);
|
|
|
|
return SUCCEEDED;
|
|
}
|
|
|
|
void dCamera_c::checkCameraChange() {
|
|
offFlag(CAM_FLAGS_0x10);
|
|
if (checkFlag(CAM_FLAGS_0x4)) {
|
|
getGameCam1()->onFlag(0x400);
|
|
offFlag(CAM_FLAGS_0x4);
|
|
}
|
|
|
|
if (checkFlag(CAM_FLAGS_MAP) && mActiveCameraIdx == CAM_MAP && !mMapCam.isActiveOrAnimating()) {
|
|
offFlag(CAM_FLAGS_MAP);
|
|
onFlag(CAM_FLAGS_0x4);
|
|
getGameCam1()->onFlag(0x10000);
|
|
debugPrintf7("off map");
|
|
}
|
|
|
|
if (EventManager::isInEvent()) {
|
|
onFlag(CAM_FLAGS_EVENT);
|
|
offFlag(CAM_FLAGS_MAP);
|
|
} else {
|
|
offFlag(CAM_FLAGS_EVENT);
|
|
}
|
|
|
|
if (checkFlag(CAM_FLAGS_EVENT)) {
|
|
if (mActiveCameraIdx != CAM_EVENT) {
|
|
setActiveCamera(CAM_EVENT);
|
|
}
|
|
} else if (checkFlag(CAM_FLAGS_MAP)) {
|
|
if (mActiveCameraIdx != CAM_MAP) {
|
|
setActiveCamera(CAM_MAP);
|
|
}
|
|
} else {
|
|
if (mActiveCameraIdx != CAM_GAME_0) {
|
|
setActiveCamera(CAM_GAME_0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void dCamera_c::updateView() {
|
|
if (field_0xDCC) {
|
|
mView = mView1;
|
|
field_0xDCC = 0;
|
|
} else {
|
|
mView = mpCameras[mActiveCameraIdx]->getView();
|
|
}
|
|
|
|
mVec3_c dir = mView.mTarget - mView.mPosition;
|
|
mYAngle = cM::atan2s(dir.y, dir.absXZ());
|
|
mXZAngle = cM::atan2s(dir.x, dir.z);
|
|
}
|
|
|
|
int dCamera_c::draw() {
|
|
if (mpCameras[mActiveCameraIdx] != nullptr) {
|
|
mpCameras[mActiveCameraIdx]->doDraw();
|
|
}
|
|
return SUCCEEDED;
|
|
}
|
|
|
|
bool dCamera_c::isUnderwater() const {
|
|
return checkFlag(CAM_FLAGS_UNDERWATER);
|
|
}
|
|
|
|
void dCamera_c::apply() {
|
|
updateUnderwaterDepth(mView.mPosition);
|
|
if (isUnderwater_()) {
|
|
onFlag(CAM_FLAGS_UNDERWATER);
|
|
} else {
|
|
offFlag(CAM_FLAGS_UNDERWATER);
|
|
}
|
|
|
|
if (mScreenShaker.execute()) {
|
|
mView.mPosition += mScreenShaker.getShakeOffset();
|
|
mView.mTarget += mScreenShaker.getShakeOffset();
|
|
}
|
|
|
|
mLookAtCamera.mPos = mView.mPosition;
|
|
mLookAtCamera.mAt = mView.mTarget;
|
|
if (mLookAtCamera.mAt.x == mLookAtCamera.mPos.x && mLookAtCamera.mAt.z == mLookAtCamera.mPos.z) {
|
|
mLookAtCamera.mPos.z += 1.0f;
|
|
}
|
|
mLookAtCamera.mUp = mVec3_c::Ey;
|
|
mLookAtCamera.doUpdateMatrix();
|
|
mMtx.copyFrom(mLookAtCamera.getViewMatrix());
|
|
// TODO: Maybe mutating mtx wasn't intended here but it's probably unproblematic
|
|
mMtx.inverse();
|
|
mMtxInv = mMtx;
|
|
mMtxInv.m[0][3] = 0.0f;
|
|
mMtxInv.m[1][3] = 0.0f;
|
|
mMtxInv.m[2][3] = 0.0f;
|
|
|
|
dSnd3DManager_c::GetInstance()->updateFromCamera(mLookAtCamera);
|
|
applyTilt();
|
|
setFrustum(mView.mFov, sHio.field_0x04, sHio.field_0x08);
|
|
nw4r::g3d::Camera cam = dStageMgr_c::GetInstance()->getCamera(mMyCameraIndex);
|
|
mpScreen->CopyToG3D(cam);
|
|
mLookAtCamera.setG3DCamera(cam);
|
|
}
|
|
|
|
s32 dCamera_c::setActiveCamera(s32 newCamIdx) {
|
|
if (mpCameras[newCamIdx] == nullptr) {
|
|
return mActiveCameraIdx;
|
|
} else if (mActiveCameraIdx == newCamIdx) {
|
|
return newCamIdx;
|
|
} else {
|
|
for (int i = 0; i < CAM_MAX; i++) {
|
|
mpCameras[i]->deactivate();
|
|
}
|
|
mpCameras[newCamIdx]->activate();
|
|
debugPrintf7("unit %d -> %d", mActiveCameraIdx, newCamIdx);
|
|
mActiveCameraIdx = newCamIdx;
|
|
return newCamIdx;
|
|
}
|
|
}
|
|
|
|
f32 dCamera_c::getEventLetterboxAmount() {
|
|
return sHio.field_0x1C;
|
|
}
|
|
|
|
void dCamera_c::setFrustum(f32 fov, f32 near, f32 far) {
|
|
if (dGfx_c::isTvMode4To3()) {
|
|
mpScreen->Reset(
|
|
0.0f, dGfx_c::getEFBHeightDifferenceF(), dGfx_c::getCurrentScreenWidthF(), dGfx_c::getHeightScaledF(),
|
|
mpScreen->GetCanvasMode()
|
|
);
|
|
} else {
|
|
mpScreen->Reset(
|
|
0.0f, 0.0f, dGfx_c::getCurrentScreenWidthF(), dGfx_c::getCurrentScreenHeightF(), mpScreen->GetCanvasMode()
|
|
);
|
|
if (dGfx_c::isTvMode4To3()) {
|
|
// Unreachable...
|
|
fov *= sHio.field_0x0C;
|
|
}
|
|
}
|
|
|
|
mpScreen->SetProjectionType(EGG::Frustum::PROJ_PERSP);
|
|
mpScreen->SetNearZ(near);
|
|
mpScreen->SetFarZ(far);
|
|
mpScreen->SetFovy(fov);
|
|
|
|
// Possible fakematch: Either the internals of EGG::Matrix34f allow
|
|
// copying the data via compiler-generated struct copies (lwz/stw),
|
|
// or this is really what they did. NSMBW symbols confirm that this function
|
|
// takes mMtx_c while it's clear that EGG cameras return EGG matrices.
|
|
mMtx_c mtx = *(mMtx_c *)&mLookAtCamera.getViewMatrix();
|
|
mFrustum.set(fov, mpScreen->GetAspect(), near, far, mtx);
|
|
}
|
|
|
|
mAng dCamera_c::getYAngle() const {
|
|
return mYAngle;
|
|
}
|
|
|
|
mAng dCamera_c::getYRot() const {
|
|
return field_0xDC0.fn_8019E930();
|
|
}
|
|
|
|
mAng dCamera_c::getXZAngle() const {
|
|
return mXZAngle;
|
|
}
|
|
|
|
bool dCamera_c::fn_8019E3C0() const {
|
|
if (mActiveCameraIdx == CAM_GAME_0) {
|
|
return mGameCam1.getField_0x078() == true;
|
|
} else if (mActiveCameraIdx == CAM_GAME_1) {
|
|
return mGameCam2.getField_0x078() == true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void dCamera_c::enterMap() {
|
|
if (!checkFlag(CAM_FLAGS_MAP)) {
|
|
onFlag(CAM_FLAGS_MAP);
|
|
}
|
|
}
|
|
|
|
void dCamera_c::leaveMap() {
|
|
if (checkFlag(CAM_FLAGS_MAP)) {
|
|
mMapCam.startOut();
|
|
}
|
|
}
|
|
|
|
void dCamera_c::applyTilt() {
|
|
EGG::Matrix34f &mtx = mLookAtCamera.getViewMatrix();
|
|
mMtx_c rotMtx;
|
|
rotMtx.ZrotS(mAng::fromDeg(-mView.mTilt));
|
|
MTXConcat(rotMtx, mtx.m, mtx.m);
|
|
}
|
|
|
|
bool dCamera_c::fn_8019E4D0() const {
|
|
dAcPy_c *link = dAcPy_c::GetLinkM();
|
|
return !EventManager::isInEvent() && !(link != nullptr && link->checkActionFlagsCont(0x5d7));
|
|
}
|
|
|
|
void dCamera_c::updateUnderwaterDepth(const mVec3_c &pos) {
|
|
mVec3_c chkPos = pos;
|
|
dBgS_RoofChk roofChk;
|
|
roofChk.SetPos(&chkPos);
|
|
roofChk.SetUnderwaterRoof();
|
|
roofChk.SetField_0x7C(1);
|
|
|
|
f32 f = dBgS::GetInstance()->RoofChk(&roofChk);
|
|
if (f != 1e9f) {
|
|
chkPos.y = f;
|
|
} else {
|
|
chkPos.y += 10000.0f;
|
|
}
|
|
|
|
dBgS_ObjGndChk_Wtr wtrChk;
|
|
wtrChk.SetPos(chkPos);
|
|
f32 waterHeight = dBgS::GetInstance()->GroundCross(&wtrChk);
|
|
if (waterHeight != 1e9f) {
|
|
mIsUnderwater = waterHeight > pos.y;
|
|
mWaterHeight = waterHeight;
|
|
} else {
|
|
mIsUnderwater = false;
|
|
mWaterHeight = -1e9f;
|
|
}
|
|
|
|
if (mIsUnderwater) {
|
|
mUnderwaterDepth = waterHeight - pos.y;
|
|
} else {
|
|
mUnderwaterDepth = 0.0f;
|
|
}
|
|
}
|
|
|
|
bool dCamera_c::isUnderwater_() const {
|
|
return mIsUnderwater;
|
|
}
|
|
|
|
f32 dCamera_c::getUnderwaterDepth() const {
|
|
return mUnderwaterDepth;
|
|
}
|
|
|
|
bool dCamera_c::screen_shaker::execute() {
|
|
mShakeOffset = mVec3_c::Zero;
|
|
bool ret = false;
|
|
if (mScreenShakeIntensity > 0.001f) {
|
|
static s32 upOrDown = 0;
|
|
upOrDown = upOrDown ^ 1;
|
|
|
|
f32 f;
|
|
if (upOrDown) {
|
|
f = 400.0f;
|
|
} else {
|
|
f = -400.0f;
|
|
}
|
|
|
|
mVec3_c shakeOffset(cM::rndFX(100.0f), cM::rndF(f), 0.0f);
|
|
shakeOffset.normalize();
|
|
// Note: the difference in coordinates here is due to the camera view using a different
|
|
// coordinate convention than game code.
|
|
shakeOffset.rotX(mpCamera->getYAngle());
|
|
shakeOffset.rotY(mpCamera->getXZAngle());
|
|
|
|
mVec3_c chckVector = shakeOffset * (mScreenShakeIntensity + 5.0f);
|
|
shakeOffset *= mScreenShakeIntensity;
|
|
mVec3_c pos = mpCamera->getPosition();
|
|
mVec3_c dest = pos + chckVector;
|
|
|
|
dBgS_CamLinChk chk;
|
|
chk.Set(&pos, &dest, nullptr);
|
|
|
|
if (!dBgS::GetInstance()->LineCross(&chk)) {
|
|
mShakeOffset = shakeOffset;
|
|
ret = true;
|
|
}
|
|
}
|
|
mScreenShakeIntensity = 0.0f;
|
|
return ret;
|
|
}
|
|
|
|
mVec3_c dCamera_c::screen_shaker::getShakeOffset() const {
|
|
return mShakeOffset;
|
|
}
|
|
|
|
void dCamera_c::substruct_1::setCamera(dCamera_c *cam) {
|
|
mpCamera = cam;
|
|
}
|
|
|
|
void dCamera_c::substruct_1::fn_8019E890() {
|
|
fn_8019E8D0(mpCamera->getXZAngle());
|
|
}
|
|
|
|
void dCamera_c::substruct_1::fn_8019E8D0(const mAng &ang) {
|
|
if (!mActive) {
|
|
mActive = true;
|
|
field_0x04 = ang;
|
|
mFSStickAngle = dPad::getFSStickAngle();
|
|
}
|
|
}
|
|
|
|
mAng dCamera_c::substruct_1::fn_8019E930() const {
|
|
return field_0x04;
|
|
}
|
|
|
|
void dCamera_c::substruct_1::fn_8019E940() {
|
|
if (mActive) {
|
|
mAng angle = mFSStickAngle - dPad::getFSStickAngle();
|
|
f32 distance = dPad::getFSStickDistance();
|
|
if (distance < sHio.field_0x14 || mAng::abs(angle) > sHio.field_0x18) {
|
|
mActive = false;
|
|
}
|
|
}
|
|
|
|
if (!mActive) {
|
|
field_0x04 = mpCamera->getXZAngle();
|
|
mFSStickAngle = dPad::getFSStickAngle();
|
|
}
|
|
}
|
|
|
|
bool dCamera_c::setEventCamView(const mVec3_c &target, const mVec3_c &pos, f32 fov, f32 tilt) {
|
|
CamView view(pos, target, fov, tilt);
|
|
getEventCam()->setView(view);
|
|
return true;
|
|
}
|
|
|
|
bool dCamera_c::fn_8019EA70(bool b) {
|
|
CamView view = getEventCam()->getView();
|
|
mVec3_c dest;
|
|
|
|
dest = camGetPointOnLine(view.mTarget, view.mPosition, dAcPy_c::GetLinkM()->mPositionCopy3);
|
|
view.mTarget = dest;
|
|
// TODO maybe inline
|
|
getGameCam1()->setView(view);
|
|
getGameCam1()->onFlag(0x1);
|
|
if (b) {
|
|
getGameCam1()->onFlag(0x4000);
|
|
} else {
|
|
getGameCam1()->offFlag(0x200);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
f32 dCamera_c::fn_8019EB90() {
|
|
return getGameCam1()->getField_0x0AC();
|
|
}
|