#include "global.h" #include "string.h" #include "z64olib.h" #pragma increment_block_number "n64-us:128" CutsceneCamera* sCurCsCamera; typedef s16 (*CsCamInterpolateCallback)(Vec3f*, f32*, s16*, CsCmdCamPoint*, CsCmdCamMisc*, CutsceneCameraInterp*); s16 CutsceneCamera_Interp_Off(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); s16 CutsceneCamera_Interp_None(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); s16 CutsceneCamera_Interp_MultiPointQuadratic(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); s16 CutsceneCamera_Interp_MultiPointCubic(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); s16 CutsceneCamera_Interp_Set(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); s16 CutsceneCamera_Interp_Linear(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); s16 CutsceneCamera_Interp_Scale(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); s16 CutsceneCamera_Interp_Geo(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); s16 CutsceneCamera_Interp_Unused(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState); f32 func_80163660(Actor* actor); s16 CutsceneCamera_Interp_Off(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { return 0; } /** * Initializes Cutscene Camera Info */ s32 CutsceneCamera_Init(Camera* camera, CutsceneCamera* csCamera) { csCamera->camera = camera; csCamera->nextSplineTimer = csCamera->updateSplineTimer = 0; csCamera->cmdIndex = 0; csCamera->splineIndex = -1; csCamera->splineNeedsInit = true; csCamera->state = CS_CAM_STATE_UPDATE_ALL; sCurCsCamera = csCamera; memset(&csCamera->eyeInterp, 0, sizeof(CutsceneCameraInterp)); memset(&csCamera->atInterp, 0, sizeof(CutsceneCameraInterp)); csCamera->eyeInterp.type = csCamera->atInterp.type = CS_CAM_INTERP_OFF; return 1; } CsCamInterpolateCallback CutsceneCamera_Interpolate(u8 interpType) { switch (interpType) { case CS_CAM_INTERP_OFF: default: return CutsceneCamera_Interp_Off; case CS_CAM_INTERP_NONE: return CutsceneCamera_Interp_None; case CS_CAM_INTERP_MP_QUAD: return CutsceneCamera_Interp_MultiPointQuadratic; case CS_CAM_INTERP_MP_CUBIC: return CutsceneCamera_Interp_MultiPointCubic; case CS_CAM_INTERP_SET: return CutsceneCamera_Interp_Set; case CS_CAM_INTERP_LINEAR: return CutsceneCamera_Interp_Linear; case CS_CAM_INTERP_SCALE: return CutsceneCamera_Interp_Scale; case CS_CAM_INTERP_GEO: return CutsceneCamera_Interp_Geo; } } u8 CutsceneCamera_ProcessSpline(CutsceneCamera* csCamera) { s32 sp5C; f32* camFov; s16* camRoll; CsCamInterpolateCallback interpHandler; Player* player; Actor* target; s16 numPoints; sp5C = true; if (csCamera->state == CS_CAM_STATE_DONE_SPLINE) { return false; } player = GET_PLAYER(csCamera->camera->play); target = csCamera->camera->target; if (csCamera->eyeCmd[csCamera->atInterp.curPoint].interpType < csCamera->atCmd[csCamera->eyeInterp.curPoint].interpType) { sp5C = false; } csCamera->eyeInterp.curPos = csCamera->camera->eye; csCamera->atInterp.curPos = csCamera->camera->at; if (sp5C) { camFov = NULL; } else { camFov = &csCamera->camera->fov; } if (sp5C) { camRoll = NULL; } else { camRoll = &csCamera->camera->roll; } interpHandler = CutsceneCamera_Interpolate(csCamera->atCmd[csCamera->eyeInterp.curPoint].interpType); switch (csCamera->atCmd[csCamera->eyeInterp.curPoint].relativeTo) { case CS_CAM_REL_2: OLib_Vec3fDiff(&player->actor.world, &csCamera->camera->at, &csCamera->camera->at, OLIB_DIFF); break; case CS_CAM_REL_3: OLib_Vec3fDiff(&player->actor.world, &csCamera->camera->at, &csCamera->camera->at, OLIB_DIFF_OFFSET); break; case CS_CAM_REL_1: OLib_Vec3fDiff(&player->actor.world, &csCamera->camera->at, &csCamera->camera->at, OLIB_DIFF_OFFSET); break; case CS_CAM_REL_4: OLib_Vec3fDiff(&target->world, &csCamera->camera->at, &csCamera->camera->at, OLIB_DIFF_OFFSET); break; case CS_CAM_REL_5: OLib_Vec3fDiff(&target->world, &csCamera->camera->at, &csCamera->camera->at, OLIB_DIFF); break; default: // CS_CAM_REL_0 break; } numPoints = interpHandler(&csCamera->camera->at, camFov, camRoll, &csCamera->atCmd[csCamera->eyeInterp.curPoint], &csCamera->miscCmd[csCamera->eyeInterp.curPoint], &csCamera->eyeInterp); switch (csCamera->atCmd[csCamera->eyeInterp.curPoint].relativeTo) { case CS_CAM_REL_2: OLib_Vec3fAdd(&player->actor.world, &csCamera->camera->at, &csCamera->camera->at, OLIB_ADD); break; case CS_CAM_REL_3: OLib_Vec3fAdd(&player->actor.world, &csCamera->camera->at, &csCamera->camera->at, OLIB_ADD_OFFSET); csCamera->camera->at.y += func_80163660(&player->actor); break; case CS_CAM_REL_1: OLib_Vec3fAdd(&player->actor.world, &csCamera->camera->at, &csCamera->camera->at, OLIB_ADD_OFFSET); break; case CS_CAM_REL_4: OLib_Vec3fAdd(&target->world, &csCamera->camera->at, &csCamera->camera->at, OLIB_ADD_OFFSET); break; case CS_CAM_REL_5: OLib_Vec3fAdd(&target->world, &csCamera->camera->at, &csCamera->camera->at, OLIB_ADD); break; default: // CS_CAM_REL_0 break; } csCamera->eyeInterp.curPoint += numPoints; if (sp5C) { camFov = &csCamera->camera->fov; } else { camFov = NULL; } if (sp5C) { camRoll = &csCamera->camera->roll; } else { camRoll = NULL; } interpHandler = CutsceneCamera_Interpolate(csCamera->eyeCmd[csCamera->atInterp.curPoint].interpType); switch (csCamera->eyeCmd[csCamera->atInterp.curPoint].relativeTo) { case CS_CAM_REL_2: OLib_Vec3fDiff(&player->actor.world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_DIFF); break; case CS_CAM_REL_3: OLib_Vec3fDiff(&player->actor.world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_DIFF_OFFSET); break; case CS_CAM_REL_1: OLib_Vec3fDiff(&player->actor.world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_DIFF_OFFSET); break; case CS_CAM_REL_4: OLib_Vec3fDiff(&target->world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_DIFF_OFFSET); break; case CS_CAM_REL_5: OLib_Vec3fDiff(&target->world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_DIFF); break; default: // CS_CAM_REL_0 break; } numPoints = interpHandler(&csCamera->camera->eye, camFov, camRoll, &csCamera->eyeCmd[csCamera->atInterp.curPoint], &csCamera->miscCmd[csCamera->atInterp.curPoint], &csCamera->atInterp); switch (csCamera->eyeCmd[csCamera->atInterp.curPoint].relativeTo) { case CS_CAM_REL_2: OLib_Vec3fAdd(&player->actor.world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_ADD); break; case CS_CAM_REL_3: OLib_Vec3fAdd(&player->actor.world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_ADD_OFFSET); csCamera->camera->eye.y += func_80163660(&player->actor); break; case CS_CAM_REL_1: OLib_Vec3fAdd(&player->actor.world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_ADD_OFFSET); break; case CS_CAM_REL_4: OLib_Vec3fAdd(&target->world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_ADD_OFFSET); break; case CS_CAM_REL_5: OLib_Vec3fAdd(&target->world, &csCamera->camera->eye, &csCamera->camera->eye, OLIB_ADD); break; default: // CS_CAM_REL_0 break; } csCamera->atInterp.curPoint += numPoints; if ((csCamera->eyeInterp.curPoint >= csCamera->eyeInterp.numEntries) || (csCamera->atInterp.curPoint >= csCamera->atInterp.numEntries)) { return false; } return true; } /** * Processes camera cutscene commands */ s32 CutsceneCamera_UpdateSplines(u8* script, CutsceneCamera* csCamera) { CsCmdCamSpline* spline; switch (csCamera->state) { case CS_CAM_STATE_DONE: return 0; case CS_CAM_STATE_PAUSE: return csCamera->nextSplineTimer; case CS_CAM_STATE_UPDATE_SPLINE: if (csCamera->updateSplineTimer <= csCamera->duration) { csCamera->updateSplineTimer++; if (csCamera->updateSplineTimer <= csCamera->duration) { // Process Spline if (!CutsceneCamera_ProcessSpline(csCamera)) { csCamera->state = CS_CAM_STATE_DONE_SPLINE; } } } break; case CS_CAM_STATE_DONE_SPLINE: break; default: // CS_CAM_STATE_UPDATE_ALL if (csCamera->splineNeedsInit == true) { // Spline Header spline = (CsCmdCamSpline*)&script[csCamera->cmdIndex]; csCamera->atInterp.numEntries = csCamera->eyeInterp.numEntries = spline->numEntries; csCamera->duration = spline->duration; csCamera->cmdIndex += sizeof(CsCmdCamSpline); // At Point csCamera->atCmd = (CsCmdCamPoint*)&script[csCamera->cmdIndex]; csCamera->cmdIndex += (s16)(csCamera->eyeInterp.numEntries * sizeof(CsCmdCamPoint)); // Eye Point csCamera->eyeCmd = (CsCmdCamPoint*)&script[csCamera->cmdIndex]; csCamera->cmdIndex += (s16)(csCamera->eyeInterp.numEntries * sizeof(CsCmdCamPoint)); // Misc csCamera->miscCmd = (CsCmdCamMisc*)&script[csCamera->cmdIndex]; csCamera->cmdIndex += (s16)(csCamera->eyeInterp.numEntries * sizeof(CsCmdCamMisc)); // Other Params csCamera->eyeInterp.curPoint = csCamera->atInterp.curPoint = 0; csCamera->splineNeedsInit = false; csCamera->splineIndex++; csCamera->state = CS_CAM_STATE_UPDATE_ALL; csCamera->nextSplineTimer = csCamera->updateSplineTimer = 0; csCamera->eyeInterp.type = csCamera->atInterp.type = CS_CAM_INTERP_OFF; } csCamera->nextSplineTimer++; if (csCamera->updateSplineTimer <= csCamera->duration) { csCamera->updateSplineTimer++; if (csCamera->updateSplineTimer <= csCamera->duration) { // Process SubCommands if (!CutsceneCamera_ProcessSpline(csCamera)) { csCamera->state = CS_CAM_STATE_DONE_SPLINE; } } } break; } if (csCamera->nextSplineTimer > csCamera->duration) { // Next Spline csCamera->splineNeedsInit = true; spline = (CsCmdCamSpline*)&script[csCamera->cmdIndex]; if (spline->numEntries == -1) { csCamera->state = CS_CAM_STATE_DONE; return 0; } } return csCamera->nextSplineTimer; } // Unused s16 func_80161BAC(void) { return (sCurCsCamera->state == CS_CAM_STATE_PAUSE) || (sCurCsCamera->state == CS_CAM_STATE_UPDATE_SPLINE); } void CutsceneCamera_SetState(s16 state) { if (sCurCsCamera->state == CS_CAM_STATE_UPDATE_ALL) { sCurCsCamera->state = state; } } void CutsceneCamera_Reset(void) { sCurCsCamera->state = CS_CAM_STATE_UPDATE_ALL; } // Linear interpolation from initial values to cmd values. Set weight to 100 to go all the way to the cmd value. s16 CutsceneCamera_Interp_Linear(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { f32 lerp; if (interpState->type != CS_CAM_INTERP_LINEAR) { // Initialize interpState->type = CS_CAM_INTERP_LINEAR; interpState->waypoint = 0; interpState->curFrame = 0; interpState->duration = 1; if (camPos != NULL) { interpState->initPos.x = camPos->x; interpState->initPos.y = camPos->y; interpState->initPos.z = camPos->z; } if (camFov != NULL) { interpState->initFov = *camFov; } if (camRoll != NULL) { interpState->initRoll = *camRoll; } } interpState->curFrame++; lerp = ((f32)interpState->curFrame / pointCmd->duration) * (pointCmd->weight / 100.0f); if (camPos != NULL) { VEC3F_LERPIMPDST(camPos, &interpState->initPos, &pointCmd->pos, lerp); } if (camFov != NULL) { *camFov = LERPIMP(interpState->initFov, miscCmd->fov, lerp); } if (camRoll != NULL) { s16 targetRoll; s16 rollDiffToTarget; targetRoll = CAM_DEG_TO_BINANG(miscCmd->roll); rollDiffToTarget = (s16)(targetRoll - TRUNCF_BINANG(interpState->initRoll)); *camRoll = TRUNCF_BINANG(interpState->initRoll) + TRUNCF_BINANG(rollDiffToTarget * lerp); } if (interpState->curFrame >= pointCmd->duration) { // Finished interpState->type = CS_CAM_INTERP_OFF; return 1; } return 0; } s16 CutsceneCamera_Interp_Scale(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { f32 lerp; f32 tmp1; f32 tmp2; if (interpState->type != CS_CAM_INTERP_SCALE) { // Initialize interpState->type = CS_CAM_INTERP_SCALE; interpState->waypoint = 0; interpState->curFrame = 0; interpState->duration = 1; if (camPos != NULL) { interpState->initPos.x = camPos->x; interpState->initPos.y = camPos->y; interpState->initPos.z = camPos->z; } if (camFov != NULL) { interpState->initFov = *camFov; } if (camRoll != NULL) { interpState->initRoll = *camRoll; } } tmp2 = (((pointCmd->weight + 100) * (pointCmd->duration / 2)) + (((pointCmd->weight + 100) / 2) * (pointCmd->duration & 1))); if (pointCmd->duration < 2) { lerp = 1.0f; } else { tmp1 = (f32)(pointCmd->weight - 100) / (pointCmd->duration - 1); lerp = ((interpState->curFrame * tmp1) + 100.0f) / tmp2; } interpState->curFrame++; if (camPos != NULL) { camPos->x += (pointCmd->pos.x - interpState->initPos.x) * lerp; camPos->y += (pointCmd->pos.y - interpState->initPos.y) * lerp; camPos->z += (pointCmd->pos.z - interpState->initPos.z) * lerp; } if (camFov != NULL) { *camFov += (miscCmd->fov - interpState->initFov) * lerp; } if (camRoll != NULL) { s16 targetRoll; s16 rollDiffToTarget; targetRoll = CAM_DEG_TO_BINANG(miscCmd->roll); rollDiffToTarget = (s16)(targetRoll - TRUNCF_BINANG(interpState->initRoll)); *camRoll += TRUNCF_BINANG(rollDiffToTarget * lerp); } if (interpState->curFrame >= pointCmd->duration) { // Finished interpState->type = CS_CAM_INTERP_OFF; return 1; } return 0; } s16 CutsceneCamera_Interp_Geo(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { VecGeo sp40; f32 lerp; f32 tmp1; f32 tmp2; if (interpState->type != CS_CAM_INTERP_GEO) { // Initialize interpState->type = CS_CAM_INTERP_GEO; interpState->waypoint = 0; interpState->curFrame = 0; interpState->duration = 1; if (camPos != NULL) { interpState->unk_20 = OLib_Vec3fDist(&interpState->curPos, camPos) * Math_FTanF(DEG_TO_RAD(*camFov)); } if (camFov != NULL) { interpState->initFov = *camFov; } if (camRoll != NULL) { interpState->initRoll = *camRoll; } } tmp2 = (((pointCmd->weight + 100) * (pointCmd->duration / 2)) + (((pointCmd->weight + 100) / 2) * (pointCmd->duration & 1))); if (pointCmd->duration < 2) { lerp = 1.0f; } else { tmp1 = (f32)(pointCmd->weight - 100) / (pointCmd->duration - 1); lerp = ((interpState->curFrame * tmp1) + 100.0f) / tmp2; } interpState->curFrame++; if (camPos != NULL) { sp40 = OLib_Vec3fDiffToVecGeo(&interpState->curPos, camPos); sp40.r = interpState->unk_20 / Math_FTanF(DEG_TO_RAD(*camFov)); *camPos = OLib_AddVecGeoToVec3f(&interpState->curPos, &sp40); } if (camFov != NULL) { *camFov += (miscCmd->fov - interpState->initFov) * lerp; } if (camRoll != NULL) { s16 targetRoll; s16 rollDiffToTarget; targetRoll = CAM_DEG_TO_BINANG(miscCmd->roll); rollDiffToTarget = (s16)(targetRoll - TRUNCF_BINANG(interpState->initRoll)); *camRoll += TRUNCF_BINANG(rollDiffToTarget * lerp); } if (interpState->curFrame >= pointCmd->duration) { // Finished interpState->type = CS_CAM_INTERP_OFF; return 1; } return 0; } // Updates the interpolation state but does not change the pos/fov/roll values s16 CutsceneCamera_Interp_None(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { if (interpState->type != CS_CAM_INTERP_NONE) { // Initialize interpState->type = CS_CAM_INTERP_NONE; interpState->waypoint = 0; interpState->curFrame = 0; interpState->duration = 1; } interpState->curFrame++; if (interpState->curFrame >= pointCmd->duration) { // Finishes interpState->type = CS_CAM_INTERP_OFF; return 1; } return 0; } // Immediately sets the values s16 CutsceneCamera_Interp_Set(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { s16 pad; if (interpState->type != CS_CAM_INTERP_SET) { // Initialize interpState->type = CS_CAM_INTERP_SET; interpState->waypoint = 0; interpState->curFrame = 0; interpState->duration = 1; if (camFov != NULL) { *camFov = miscCmd->fov; } if (camRoll != NULL) { *camRoll = CAM_DEG_TO_BINANG(miscCmd->roll); } } if (camPos != NULL) { camPos->x = pointCmd->pos.x; camPos->y = pointCmd->pos.y; camPos->z = pointCmd->pos.z; } interpState->curFrame++; if (interpState->curFrame >= pointCmd->duration) { // Finished interpState->type = CS_CAM_INTERP_OFF; return 1; } return 0; } void func_801624EC(f32 u, f32* coeff) { f32 u1 = 1.0f - u; coeff[0] = u1 * u1 * 0.5f; coeff[1] = u * u1 + 0.5f; coeff[2] = u * u * 0.5f; } s16 CutsceneCamera_Interp_MultiPointQuadratic(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { f32 new_var; f32 coeff[3]; s32 waypoints[3]; if (interpState->type != CS_CAM_INTERP_MP_QUAD) { // Initialize interpState->type = CS_CAM_INTERP_MP_QUAD; interpState->waypoint = 0; interpState->duration = pointCmd->duration; interpState->curFrame = 0; } new_var = (f32)interpState->curFrame / pointCmd[interpState->waypoint + 1].duration; if (interpState->waypoint < (interpState->duration - 1)) { waypoints[0] = interpState->waypoint; } else { waypoints[0] = interpState->duration - 1; } if ((interpState->waypoint + 1) < (interpState->duration - 1)) { waypoints[1] = interpState->waypoint + 1; } else { waypoints[1] = interpState->duration - 1; } if ((interpState->waypoint + 2) < (interpState->duration - 1)) { waypoints[2] = interpState->waypoint + 2; } else { waypoints[2] = interpState->duration - 1; } func_801624EC(new_var, coeff); if (camPos != NULL) { camPos->x = (coeff[0] * pointCmd[waypoints[0]].pos.x) + (coeff[1] * pointCmd[waypoints[1]].pos.x) + (coeff[2] * pointCmd[waypoints[2]].pos.x); camPos->y = (coeff[0] * pointCmd[waypoints[0]].pos.y) + (coeff[1] * pointCmd[waypoints[1]].pos.y) + (coeff[2] * pointCmd[waypoints[2]].pos.y); camPos->z = (coeff[0] * pointCmd[waypoints[0]].pos.z) + (coeff[1] * pointCmd[waypoints[1]].pos.z) + (coeff[2] * pointCmd[waypoints[2]].pos.z); } if (camFov != NULL) { *camFov = (coeff[0] * miscCmd[waypoints[0]].fov) + (coeff[1] * miscCmd[waypoints[1]].fov) + (coeff[2] * miscCmd[waypoints[2]].fov); } if (camRoll != NULL) { s16 targetRolls[3]; s32 sp28[2]; s32 rollDiffToTarget; targetRolls[0] = CAM_DEG_TO_BINANG(miscCmd[waypoints[0]].roll); targetRolls[1] = CAM_DEG_TO_BINANG(miscCmd[waypoints[1]].roll); targetRolls[2] = CAM_DEG_TO_BINANG(miscCmd[waypoints[2]].roll); sp28[0] = (s16)(targetRolls[1] - targetRolls[0]); sp28[1] = sp28[0] + (s16)(targetRolls[2] - targetRolls[1]); rollDiffToTarget = ((coeff[1] * sp28[0]) + (coeff[2] * sp28[1])); *camRoll = targetRolls[0] + rollDiffToTarget; } interpState->curFrame++; if (interpState->curFrame == pointCmd[interpState->waypoint + 1].duration) { interpState->waypoint++; interpState->curFrame = 0; if (interpState->waypoint >= (interpState->duration - 2)) { interpState->type = CS_CAM_INTERP_OFF; return interpState->duration; } } return 0; } /** * This code is very similar to the spline system in OoT's func_800BB0A0 * in that it is based on the Super Mario 64 cutscene camera movement */ void func_801629BC(f32 u, f32* coeff) { coeff[0] = (1.0f - u) * (1.0f - u) * (1.0f - u) * (1.0f / 6.0f); coeff[1] = ((u * u * u * 0.5f) - u * u) + (2.0f / 3.0f); coeff[2] = (u * u * u * -0.5f) + (u * u * 0.5f) + (u * 0.5f) + (1.0f / 6.0f); coeff[3] = u * u * u * (1.0f / 6.0f); } s16 CutsceneCamera_Interp_MultiPointCubic(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { f32 new_var; f32 coeff[4]; s32 waypoints[4]; if (interpState->type != CS_CAM_INTERP_MP_CUBIC) { // Initialize interpState->type = CS_CAM_INTERP_MP_CUBIC; interpState->waypoint = 0; interpState->duration = pointCmd->duration; interpState->curFrame = 0; } new_var = (f32)interpState->curFrame / pointCmd[interpState->waypoint + 1].duration; if (interpState->waypoint < (interpState->duration - 1)) { waypoints[0] = interpState->waypoint; } else { waypoints[0] = interpState->duration - 1; } if ((interpState->waypoint + 1) < (interpState->duration - 1)) { waypoints[1] = interpState->waypoint + 1; } else { waypoints[1] = interpState->duration - 1; } if ((interpState->waypoint + 2) < (interpState->duration - 1)) { waypoints[2] = interpState->waypoint + 2; } else { waypoints[2] = interpState->duration - 1; } if ((interpState->waypoint + 3) < (interpState->duration - 1)) { waypoints[3] = interpState->waypoint + 3; } else { waypoints[3] = interpState->duration - 1; } func_801629BC(new_var, coeff); if (camPos != NULL) { camPos->x = (coeff[0] * pointCmd[waypoints[0]].pos.x) + (coeff[1] * pointCmd[waypoints[1]].pos.x) + (coeff[2] * pointCmd[waypoints[2]].pos.x) + (coeff[3] * pointCmd[waypoints[3]].pos.x); camPos->y = (coeff[0] * pointCmd[waypoints[0]].pos.y) + (coeff[1] * pointCmd[waypoints[1]].pos.y) + (coeff[2] * pointCmd[waypoints[2]].pos.y) + (coeff[3] * pointCmd[waypoints[3]].pos.y); camPos->z = (coeff[0] * pointCmd[waypoints[0]].pos.z) + (coeff[1] * pointCmd[waypoints[1]].pos.z) + (coeff[2] * pointCmd[waypoints[2]].pos.z) + (coeff[3] * pointCmd[waypoints[3]].pos.z); } if (camFov != NULL) { *camFov = (coeff[0] * miscCmd[waypoints[0]].fov) + (coeff[1] * miscCmd[waypoints[1]].fov) + (coeff[2] * miscCmd[waypoints[2]].fov) + (coeff[3] * miscCmd[waypoints[3]].fov); } if (camRoll != NULL) { s16 targetRolls[4]; s32 sp2C[3]; s32 rollDiffToTarget; targetRolls[0] = CAM_DEG_TO_BINANG(miscCmd[waypoints[0]].roll); targetRolls[1] = CAM_DEG_TO_BINANG(miscCmd[waypoints[1]].roll); targetRolls[2] = CAM_DEG_TO_BINANG(miscCmd[waypoints[2]].roll); targetRolls[3] = CAM_DEG_TO_BINANG(miscCmd[waypoints[3]].roll); sp2C[0] = (s16)(targetRolls[1] - targetRolls[0]); sp2C[1] = sp2C[0] + (s16)(targetRolls[2] - targetRolls[1]); sp2C[2] = sp2C[1] + (s16)(targetRolls[3] - targetRolls[2]); rollDiffToTarget = ((coeff[1] * sp2C[0]) + (coeff[2] * sp2C[1]) + (coeff[3] * sp2C[2])); *camRoll = targetRolls[0] + rollDiffToTarget; } interpState->curFrame++; if (interpState->curFrame == pointCmd[interpState->waypoint + 1].duration) { interpState->curFrame = 0; interpState->waypoint++; if (interpState->waypoint >= (interpState->duration - 3)) { interpState->type = CS_CAM_INTERP_OFF; return interpState->duration; } } return 0; } f32 sCsCamKnots[38]; // Only used by unused CutsceneCamera_Interp_Unused void func_80162FF8(s16 arg0) { f32 val = 0.0f; s32 i; sCsCamKnots[0] = 0.0f; sCsCamKnots[1] = 0.0f; sCsCamKnots[2] = 0.0f; for (i = 3; i < arg0; i++) { if (i == 3) { val += 0.9f; } else if ((i == 4) || (i == (arg0 - 1))) { val += 0.6f; } else { val += 0.3f; } sCsCamKnots[i] = val; } val += 0.9f; sCsCamKnots[i++] = val; sCsCamKnots[i++] = val; sCsCamKnots[i++] = val; } #define FUNC_801631DC_ORDER 3 // Only used by unused CutsceneCamera_Interp_Unused void func_801631DC(f32 progress, s32 arg2, f32* coeff) { f32 coeffTemp[4][4]; s32 i; s32 j; s32 k; for (i = 0; i < FUNC_801631DC_ORDER + 1; i++) { for (j = 0; j < FUNC_801631DC_ORDER + 1; j++) { coeffTemp[i][j] = 0.0f; } } coeffTemp[0][FUNC_801631DC_ORDER - 1] = 1.0f; for (i = 1; i < FUNC_801631DC_ORDER; i++) { for (j = arg2 - i, k = (FUNC_801631DC_ORDER - 1) - i; j <= arg2; j++, k++) { if (sCsCamKnots[j + i] != sCsCamKnots[j]) { coeffTemp[i][k] = ((progress - sCsCamKnots[j]) / (sCsCamKnots[j + i] - sCsCamKnots[j])) * coeffTemp[i - 1][k]; } else { coeffTemp[i][k] = 0.0f; } if (sCsCamKnots[j + i + 1] != sCsCamKnots[j + 1]) { coeffTemp[i][k] += ((sCsCamKnots[j + i + 1] - progress) / (sCsCamKnots[j + i + 1] - sCsCamKnots[j + 1])) * coeffTemp[i - 1][k + 1]; } } } for (j = 0; j < FUNC_801631DC_ORDER; j++) { coeff[j] = coeffTemp[FUNC_801631DC_ORDER - 1][j]; } } s16 CutsceneCamera_Interp_Unused(Vec3f* camPos, f32* camFov, s16* camRoll, CsCmdCamPoint* pointCmd, CsCmdCamMisc* miscCmd, CutsceneCameraInterp* interpState) { s32 index; f32 coeff[3]; if (interpState->type != CS_CAM_INTERP_MP_CUBIC) { // Initialize interpState->type = CS_CAM_INTERP_MP_CUBIC; interpState->waypoint = 0; interpState->duration = pointCmd->duration; func_80162FF8(interpState->duration); interpState->curFrame = 0; } index = interpState->waypoint + 2; func_801631DC(F32_LERPIMP(sCsCamKnots[index], sCsCamKnots[index + 1], (f32)interpState->curFrame / miscCmd[interpState->waypoint].unused0), index, coeff); if (camPos != NULL) { camPos->x = (coeff[0] * pointCmd[interpState->waypoint].pos.x) + (coeff[1] * pointCmd[interpState->waypoint + 1].pos.x) + (coeff[2] * pointCmd[interpState->waypoint + 2].pos.x); camPos->y = (coeff[0] * pointCmd[interpState->waypoint].pos.y) + (coeff[1] * pointCmd[interpState->waypoint + 1].pos.y) + (coeff[2] * pointCmd[interpState->waypoint + 2].pos.y); camPos->z = (coeff[0] * pointCmd[interpState->waypoint].pos.z) + (coeff[1] * pointCmd[interpState->waypoint + 1].pos.z) + (coeff[2] * pointCmd[interpState->waypoint + 2].pos.z); } if (camFov != NULL) { *camFov = (coeff[0] * miscCmd[interpState->waypoint].fov) + (coeff[1] * miscCmd[interpState->waypoint + 1].fov) + (coeff[2] * miscCmd[interpState->waypoint + 2].fov); } if (camRoll != NULL) { *camRoll = CAM_DEG_TO_BINANG((coeff[0] * miscCmd[interpState->waypoint].roll) + (coeff[1] * miscCmd[interpState->waypoint + 1].roll) + (coeff[2] * miscCmd[interpState->waypoint + 2].roll)); } interpState->curFrame++; if (interpState->curFrame >= miscCmd[interpState->waypoint].unused0) { interpState->waypoint++; interpState->curFrame = 0; if (interpState->waypoint >= (interpState->duration - 2)) { interpState->type = CS_CAM_INTERP_OFF; return interpState->duration; } } return 0; } f32 func_80163660(Actor* actor) { if (actor->category != ACTORCAT_PLAYER) { return 38.0f - (actor->focus.pos.y - actor->world.pos.y); } switch (((Player*)actor)->transformation) { case PLAYER_FORM_DEKU: return -8.0f; case PLAYER_FORM_GORON: return 23.0f; case PLAYER_FORM_ZORA: return 27.0f; case PLAYER_FORM_FIERCE_DEITY: return 17.0f; default: return 0.0f; } }