diff --git a/lib/libpm-jp.a b/lib/libpm-jp.a index 2a1b08a3..8175c9ca 100644 --- a/lib/libpm-jp.a +++ b/lib/libpm-jp.a @@ -39,6 +39,8 @@ pm_fioDeserializeState = 0x8002B450; pm_fioReadFlash = 0x8002B828; pm_fioWriteFlash = 0x8002B908; pm_setCurtainScaleGoal = 0x8002BE9C; +pm_update_cameras = 0x8002D090; +pm_update_camera_zone_interp = 0x80031124; pm_setCurtainDrawCallback = 0x8002BEC4; pm_setCurtainFadeGoal = 0x8002BED4; pm_setGameMode = 0x80033180; diff --git a/lib/libpm-us.a b/lib/libpm-us.a index ff42433d..2f608b78 100644 --- a/lib/libpm-us.a +++ b/lib/libpm-us.a @@ -41,6 +41,8 @@ pm_fioWriteFlash = 0x8002B948; pm_setCurtainScaleGoal = 0x8002BEDC; pm_setCurtainDrawCallback = 0x8002BF04; pm_setCurtainFadeGoal = 0x8002BF14; +pm_update_cameras = 0x8002D400; +pm_update_camera_zone_interp = 0x80031494; pm_setGameMode = 0x800334F0; pm_get_npc_safe = 0x8003AB48; pm_func_800554A4 = 0x800554A4; diff --git a/src/fp.c b/src/fp.c index 8a8157c2..577f6234 100644 --- a/src/fp.c +++ b/src/fp.c @@ -9,6 +9,7 @@ #include "sys/resource.h" #include "util/geometry.h" #include "util/watchlist.h" +#include #include #include #include @@ -378,21 +379,33 @@ void fpDrawLog(struct GfxFont *font, s32 cellWidth, s32 cellHeight, u8 menuAlpha void fpCamUpdate(void) { if (fp.freeCam) { if (!fp.camEnabledBefore) { - fp.camPos.x = pm_gCameras->lookAt_eye.x; - fp.camPos.y = pm_gCameras->lookAt_eye.y; - fp.camPos.z = pm_gCameras->lookAt_eye.z; + fp.cam.eye = pm_gCameras[pm_gCurrentCameraID].lookAt_eye; + fp.cam.pitch = pm_gCameras[pm_gCurrentCameraID].currentPitch; + fp.cam.yaw = pm_gCameras[pm_gCurrentCameraID].currentYaw; fp.camEnabledBefore = TRUE; } else { fpUpdateCam(); } - Vec3f *cameraAt = &pm_gCameras->lookAt_obj; - Vec3f *cameraEye = &pm_gCameras->lookAt_eye; - - *cameraEye = fp.camPos; + Vec3f *cameraAt = &pm_gCameras[pm_gCurrentCameraID].lookAt_obj; + Vec3f *cameraEye = &pm_gCameras[pm_gCurrentCameraID].lookAt_eye; + + *cameraEye = fp.cam.eye; + + if (fp.resetCam) { + pm_gCameras[pm_gCurrentCameraID].currentYaw = fp.cam.yaw; + fp.cam.pitch = (fp.cam.obj.y - cameraEye->y) * -1.0 / + sqrtf(SQ(fp.cam.obj.x - cameraEye->x) + SQ(fp.cam.obj.y - cameraEye->y) + + SQ(fp.cam.obj.z - cameraEye->z)); + fp.cam.yaw = (fp.cam.obj.x - cameraEye->x) * -1.0 / + sqrtf(SQ(fp.cam.obj.x - cameraEye->x) + SQ(fp.cam.obj.y - cameraEye->y) + + SQ(fp.cam.obj.z - cameraEye->z)); + fp.resetCam = FALSE; + } Vec3f vf; - vec3fPy(&vf, fp.camPitch, fp.camYaw); + vec3fPy(&vf, fp.cam.pitch, fp.cam.yaw); vec3fAdd(cameraAt, cameraEye, &vf); + pm_gCameras[pm_gCurrentCameraID].moveSpeed = 100; } } diff --git a/src/fp.h b/src/fp.h index 3e29df0c..a4f9a533 100644 --- a/src/fp.h +++ b/src/fp.h @@ -15,6 +15,13 @@ struct LogEntry { s32 age; }; +typedef struct { + Vec3f eye; + Vec3f obj; + f32 pitch; + f32 yaw; +} FpCam; + typedef struct { bool ready; struct Menu *mainMenu; @@ -49,12 +56,13 @@ typedef struct { enum CamBhv camBhv; s16 camDistMin; s16 camDistMax; - f32 camPitch; - f32 camYaw; - Vec3f camPos; + FpCam cam; + bool resetCam; pm_Controller inputMask; bool camEnabledBefore; pm_Camera savedCam; + s8 freeCamMoveSpeed; + s8 freeCamPanSpeed; } FpCtxt; extern FpCtxt fp; @@ -68,6 +76,8 @@ s32 fpImportFile(const char *path, void *data); void fpSetInputMask(u16 pad, u8 x, u8 y); void fpUpdateCam(void); void fpSaveSettingsProc(struct MenuItem *item, void *data); +void setFreeCamMoveSpeed(s8 s); +void setFreeCamPanSpeed(s8 s); struct Menu *createWarpsMenu(void); struct Menu *createCheatsMenu(void); diff --git a/src/fp/fp_camera.c b/src/fp/fp_camera.c index eb0b2d70..262a15a4 100644 --- a/src/fp/fp_camera.c +++ b/src/fp/fp_camera.c @@ -18,6 +18,7 @@ static s32 enableCamProc(struct MenuItem *item, enum MenuCallbackReason reason, } else if (reason == MENU_CALLBACK_SWITCH_OFF) { fp.freeCam = FALSE; pm_gCameras[pm_gCurrentCameraID].updateMode = 3; + pm_gCameras[pm_gCurrentCameraID].moveSpeed = 1; setCamInputMask(); } else if (reason == MENU_CALLBACK_THINK) { menuCheckboxSet(item, fp.freeCam); @@ -39,11 +40,16 @@ static s32 lockCamProc(struct MenuItem *item, enum MenuCallbackReason reason, vo } static void resetCamProc(struct MenuItem *item, void *data) { - fp.camYaw = 0.f; - fp.camPitch = 0.f; - fp.camPos.x = 0.f; - fp.camPos.y = 0.f; - fp.camPos.z = 0.f; + pm_Camera cam = pm_gCameras[pm_gCurrentCameraID]; + pm_gCameras[pm_gCurrentCameraID].targetPos = pm_gPlayerStatus.position; + pm_gCameras[pm_gCurrentCameraID].updateMode = 3; + pm_update_cameras(); + fp.cam.eye = pm_gCameras[pm_gCurrentCameraID].lookAt_eye; + fp.cam.obj = pm_gCameras[pm_gCurrentCameraID].lookAt_obj; + fp.cam.pitch = pm_gCameras[pm_gCurrentCameraID].currentPitch; + fp.cam.yaw = pm_gCameras[pm_gCurrentCameraID].currentYaw; + pm_gCameras[pm_gCurrentCameraID] = cam; + fp.resetCam = TRUE; } static s32 camBhvProc(struct MenuItem *item, enum MenuCallbackReason reason, void *data) { @@ -79,28 +85,58 @@ static s32 camDistMaxProc(struct MenuItem *item, enum MenuCallbackReason reason, return 0; } +static s32 camMoveSpeedProc(struct MenuItem *item, enum MenuCallbackReason reason, void *data) { + if (reason == MENU_CALLBACK_CHANGED) { + fp.freeCamMoveSpeed = menuIntinputGets(item); + setFreeCamMoveSpeed(fp.freeCamMoveSpeed); + } else if (reason == MENU_CALLBACK_THINK) { + if (menuIntinputGets(item) != fp.freeCamMoveSpeed) { + menuIntinputSet(item, fp.freeCamMoveSpeed); + } + } + return 0; +} + +static s32 camPanSpeedProc(struct MenuItem *item, enum MenuCallbackReason reason, void *data) { + if (reason == MENU_CALLBACK_CHANGED) { + fp.freeCamPanSpeed = menuIntinputGets(item); + setFreeCamPanSpeed(fp.freeCamPanSpeed); + } else if (reason == MENU_CALLBACK_THINK) { + if (menuIntinputGets(item) != fp.freeCamPanSpeed) { + menuIntinputSet(item, fp.freeCamPanSpeed); + } + } + return 0; +} + struct Menu *createCameraMenu(void) { static struct Menu menu; + int y = 0; + /* initialize menu */ menuInit(&menu, MENU_NOVALUE, MENU_NOVALUE, MENU_NOVALUE); - menu.selector = menuAddSubmenu(&menu, 0, 0, NULL, "return"); + menu.selector = menuAddSubmenu(&menu, 0, y++, NULL, "return"); - menuAddStatic(&menu, 0, 1, "enable", 0xC0C0C0); - menuAddCheckbox(&menu, 16, 1, enableCamProc, NULL); - menuAddStatic(&menu, 0, 2, "lock", 0xC0C0C0); - menuAddCheckbox(&menu, 16, 2, lockCamProc, NULL); - menuAddStatic(&menu, 0, 4, "behavior", 0xC0C0C0); - menuAddOption(&menu, 16, 4, + menuAddStatic(&menu, 0, y, "enable", 0xC0C0C0); + menuAddCheckbox(&menu, 16, y++, enableCamProc, NULL); + menuAddStatic(&menu, 0, y, "lock", 0xC0C0C0); + menuAddCheckbox(&menu, 16, y++, lockCamProc, NULL); + menuAddStatic(&menu, 0, ++y, "behavior", 0xC0C0C0); + menuAddOption(&menu, 16, y++, "manual\0" "birdseye follow\0" "radial follow\0", camBhvProc, NULL); - menuAddStatic(&menu, 0, 5, "distance min", 0xC0C0C0); - menuAddIntinput(&menu, 16, 5, -10, 5, camDistMinProc, NULL); - menuAddStatic(&menu, 0, 6, "distance max", 0xC0C0C0); - menuAddIntinput(&menu, 16, 6, -10, 5, camDistMaxProc, NULL); - menuAddButton(&menu, 16, 7, "reset", resetCamProc, NULL); + menuAddStatic(&menu, 0, y, "distance min", 0xC0C0C0); + menuAddIntinput(&menu, 16, y++, -10, 5, camDistMinProc, NULL); + menuAddStatic(&menu, 0, y, "distance max", 0xC0C0C0); + menuAddIntinput(&menu, 16, y++, -10, 5, camDistMaxProc, NULL); + menuAddStatic(&menu, 0, y, "move speed", 0xC0C0C0); + menuAddIntinput(&menu, 16, y++, -10, 2, camMoveSpeedProc, NULL); + menuAddStatic(&menu, 0, y, "pan speed", 0xC0C0C0); + menuAddIntinput(&menu, 16, y++, -10, 2, camPanSpeedProc, NULL); + menuAddButton(&menu, 16, y++, "reset", resetCamProc, NULL); return &menu; } diff --git a/src/macros.h b/src/macros.h index cac5d285..7a817ffb 100644 --- a/src/macros.h +++ b/src/macros.h @@ -14,4 +14,6 @@ #define ARRAY_LENGTH(arr) (s32)(sizeof(arr) / sizeof(arr[0])) +#define SQ(x) ((x) * (x)) + #endif // MACROS_H diff --git a/src/pm64.h b/src/pm64.h index e0608a09..5e2879ef 100644 --- a/src/pm64.h +++ b/src/pm64.h @@ -1250,6 +1250,8 @@ void pm_fioWriteFlash(s32 slot, void *buffer, u32 size); void pm_setCurtainScaleGoal(f32 goal); void pm_setCurtainDrawCallback(void *callback); void pm_setCurtainFadeGoal(f32 goal); +void pm_update_cameras(void); +void pm_update_camera_zone_interp(pm_Camera *camera); void pm_setGameMode(s32 mode); pm_Npc *pm_get_npc_safe(s32 npcID); s32 pm_func_800554A4(s32); diff --git a/src/util/camera.c b/src/util/camera.c index c959b925..f2e310a2 100644 --- a/src/util/camera.c +++ b/src/util/camera.c @@ -5,13 +5,25 @@ #include #include -static const f32 joyMspeed = 0.25f; -static const f32 joyRspeed = 0.0007f; -static const s32 joyMax = 60.f; -static const f32 pitchLim = M_PI / 2.f - joyRspeed; +static f32 joyMspeed = 0.25f; +static f32 joyRspeed = 0.0007f; +static const f32 joyMax = 60.f; +#define PITCH_LIM (M_PI / 2.f - joyRspeed) static const f32 folMspeed = 1.f / 3.f; static const f32 folRspeed = 1.f / 3.f; +void setFreeCamMoveSpeed(s8 s) { + if (s < 0) { + joyMspeed = (s + 14) / joyMax; + } else { + joyMspeed = (s + 1) * 15 / joyMax; + } +} + +void setFreeCamPanSpeed(s8 s) { + joyRspeed = 0.0007 + s * 0.00005; +} + s32 adjustJoystick(s32 v) { if (v < 0) { if (v > -8) { @@ -40,54 +52,54 @@ static void camManual(void) { Vec3f vf; Vec3f vr; Vec3f move; - vec3fPy(&vf, fp.camPitch, fp.camYaw); - vec3fPy(&vr, 0.f, fp.camYaw - M_PI / 2.f); + vec3fPy(&vf, fp.cam.pitch, fp.cam.yaw); + vec3fPy(&vr, 0.f, fp.cam.yaw - M_PI / 2.f); if (inputPad() & BUTTON_Z) { vec3fScale(&move, &vf, y * joyMspeed); - vec3fAdd(&fp.camPos, &fp.camPos, &move); + vec3fAdd(&fp.cam.eye, &fp.cam.eye, &move); vec3fScale(&move, &vr, x * joyMspeed); - vec3fAdd(&fp.camPos, &fp.camPos, &move); + vec3fAdd(&fp.cam.eye, &fp.cam.eye, &move); if (inputPad() & BUTTON_C_UP) { - fp.camPos.y += joyMax * joyMspeed; + fp.cam.eye.y += joyMax * joyMspeed; } if (inputPad() & BUTTON_C_DOWN) { - fp.camPos.y += -joyMax * joyMspeed; + fp.cam.eye.y += -joyMax * joyMspeed; } if (inputPad() & BUTTON_C_RIGHT) { - fp.camYaw -= joyMax * joyRspeed; + fp.cam.yaw -= joyMax * joyRspeed; } if (inputPad() & BUTTON_C_LEFT) { - fp.camYaw -= -joyMax * joyRspeed; + fp.cam.yaw -= -joyMax * joyRspeed; } } else { - fp.camPitch += y * joyRspeed; - fp.camYaw -= x * joyRspeed; + fp.cam.pitch += y * joyRspeed; + fp.cam.yaw -= x * joyRspeed; if (inputPad() & BUTTON_C_UP) { vec3fScale(&move, &vf, joyMax * joyMspeed); - vec3fAdd(&fp.camPos, &fp.camPos, &move); + vec3fAdd(&fp.cam.eye, &fp.cam.eye, &move); } if (inputPad() & BUTTON_C_DOWN) { vec3fScale(&move, &vf, -joyMax * joyMspeed); - vec3fAdd(&fp.camPos, &fp.camPos, &move); + vec3fAdd(&fp.cam.eye, &fp.cam.eye, &move); } if (inputPad() & BUTTON_C_RIGHT) { vec3fScale(&move, &vr, joyMax * joyMspeed); - vec3fAdd(&fp.camPos, &fp.camPos, &move); + vec3fAdd(&fp.cam.eye, &fp.cam.eye, &move); } if (inputPad() & BUTTON_C_LEFT) { vec3fScale(&move, &vr, -joyMax * joyMspeed); - vec3fAdd(&fp.camPos, &fp.camPos, &move); + vec3fAdd(&fp.cam.eye, &fp.cam.eye, &move); } } - if (fp.camPitch > pitchLim) { - fp.camPitch = pitchLim; - } else if (fp.camPitch < -pitchLim) { - fp.camPitch = -pitchLim; + if (fp.cam.pitch > PITCH_LIM) { + fp.cam.pitch = PITCH_LIM; + } else if (fp.cam.pitch < -PITCH_LIM) { + fp.cam.pitch = -PITCH_LIM; } } } @@ -99,36 +111,36 @@ static void camBirdseye(void) { vt.z = pm_gPlayerStatus.position.z; Vec3f vd; - vec3fSub(&vd, &vt, &fp.camPos); + vec3fSub(&vd, &vt, &fp.cam.eye); f32 pitch, yaw; vec3fPyangles(&vd, &pitch, &yaw); - f32 dPitch = angleDif(pitch, fp.camPitch); + f32 dPitch = angleDif(pitch, fp.cam.pitch); if (fabsf(dPitch) < .001f) { - fp.camPitch = pitch; + fp.cam.pitch = pitch; } else { - fp.camPitch += dPitch * folRspeed; + fp.cam.pitch += dPitch * folRspeed; } - f32 dYaw = angleDif(yaw, fp.camYaw); + f32 dYaw = angleDif(yaw, fp.cam.yaw); if (fabsf(dYaw) < .001f) { - fp.camYaw = yaw; + fp.cam.yaw = yaw; } else { - fp.camYaw += dYaw * folRspeed; + fp.cam.yaw += dYaw * folRspeed; } f32 dist = vec3fMag(&vd); if (dist < fp.camDistMin) { Vec3f move; - vec3fPy(&move, fp.camPitch, fp.camYaw); + vec3fPy(&move, fp.cam.pitch, fp.cam.yaw); vec3fScale(&move, &move, (dist - fp.camDistMin) * folMspeed); - vec3fAdd(&fp.camPos, &fp.camPos, &move); + vec3fAdd(&fp.cam.eye, &fp.cam.eye, &move); } else if (dist > fp.camDistMax) { Vec3f move; - vec3fPy(&move, fp.camPitch, fp.camYaw); + vec3fPy(&move, fp.cam.pitch, fp.cam.yaw); vec3fScale(&move, &move, (dist - fp.camDistMax) * folMspeed); - vec3fAdd(&fp.camPos, &fp.camPos, &move); + vec3fAdd(&fp.cam.eye, &fp.cam.eye, &move); } camManual(); @@ -136,7 +148,7 @@ static void camBirdseye(void) { static void camRadial(void) { Vec3f vf; - vec3fPy(&vf, fp.camPitch, fp.camYaw); + vec3fPy(&vf, fp.cam.pitch, fp.cam.yaw); Vec3f vt; vt.x = pm_gPlayerStatus.position.x; @@ -144,7 +156,7 @@ static void camRadial(void) { vt.z = pm_gPlayerStatus.position.z; Vec3f vd; - vec3fSub(&vd, &vt, &fp.camPos); + vec3fSub(&vd, &vt, &fp.cam.eye); f32 dist = vec3fDot(&vd, &vf); Vec3f vp; @@ -155,19 +167,19 @@ static void camRadial(void) { { Vec3f move; vec3fScale(&move, &vr, folMspeed); - vec3fAdd(&fp.camPos, &fp.camPos, &move); + vec3fAdd(&fp.cam.eye, &fp.cam.eye, &move); } if (dist < fp.camDistMin) { f32 norm = 1.f / dist; Vec3f move; vec3fScale(&move, &vp, (dist - fp.camDistMin) * folMspeed * norm); - vec3fAdd(&fp.camPos, &fp.camPos, &move); + vec3fAdd(&fp.cam.eye, &fp.cam.eye, &move); } else if (dist > fp.camDistMax) { f32 norm = 1.f / dist; Vec3f move; vec3fScale(&move, &vp, (dist - fp.camDistMax) * folMspeed * norm); - vec3fAdd(&fp.camPos, &fp.camPos, &move); + vec3fAdd(&fp.cam.eye, &fp.cam.eye, &move); } if (!fp.lockCam) { @@ -177,13 +189,13 @@ static void camRadial(void) { if (inputPad() & BUTTON_Z) { dist -= y * joyMspeed; if (inputPad() & BUTTON_C_UP) { - fp.camPitch += joyMax * joyRspeed; + fp.cam.pitch += joyMax * joyRspeed; } if (inputPad() & BUTTON_C_DOWN) { - fp.camPitch += -joyMax * joyRspeed; + fp.cam.pitch += -joyMax * joyRspeed; } } else { - fp.camPitch += y * joyRspeed; + fp.cam.pitch += y * joyRspeed; if (inputPad() & BUTTON_C_UP) { dist -= joyMax * joyMspeed; } @@ -191,27 +203,27 @@ static void camRadial(void) { dist -= -joyMax * joyMspeed; } } - fp.camYaw -= x * joyRspeed; + fp.cam.yaw -= x * joyRspeed; if (inputPad() & BUTTON_C_LEFT) { - fp.camYaw -= joyMax * joyRspeed; + fp.cam.yaw -= joyMax * joyRspeed; } if (inputPad() & BUTTON_C_RIGHT) { - fp.camYaw -= -joyMax * joyRspeed; + fp.cam.yaw -= -joyMax * joyRspeed; } - if (fp.camPitch > pitchLim) { - fp.camPitch = pitchLim; - } else if (fp.camPitch < -pitchLim) { - fp.camPitch = -pitchLim; + if (fp.cam.pitch > PITCH_LIM) { + fp.cam.pitch = PITCH_LIM; + } else if (fp.cam.pitch < -PITCH_LIM) { + fp.cam.pitch = -PITCH_LIM; } Vec3f vfoc; - vec3fAdd(&vfoc, &fp.camPos, &vp); + vec3fAdd(&vfoc, &fp.cam.eye, &vp); Vec3f move; - vec3fPy(&move, fp.camPitch, fp.camYaw); + vec3fPy(&move, fp.cam.pitch, fp.cam.yaw); vec3fScale(&move, &move, -dist); - vec3fAdd(&fp.camPos, &vfoc, &move); + vec3fAdd(&fp.cam.eye, &vfoc, &move); } }