Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split camera.c #827

Open
wants to merge 32 commits into
base: develop/3.0.0
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8287ecc
start splitting
Aug 9, 2024
f763de1
more cutscenes; consolidations and renamings; todo file added
Aug 26, 2024
1c0195e
consolidate door cutscenes to one file
Aug 26, 2024
499aef1
figure out syntax for local spline points
Aug 26, 2024
95c67ec
consolidate level painting exit cutscene files
Aug 26, 2024
50ccefa
remove empty level exit files
Aug 26, 2024
c697896
delete the other empty files
Aug 26, 2024
465035a
split basically all cutscenes
Aug 26, 2024
688080d
create src/camera since the file count has gotten to that point
Aug 26, 2024
2bee79f
remove empty level specific files; add camera_math
Aug 26, 2024
19ff8a2
add camera modes folder too
Aug 26, 2024
5eb8513
split modes; checkpoint to make this compile
Aug 26, 2024
9b873fa
top level files compiling
Aug 27, 2024
b415624
game builds
Aug 27, 2024
bf7bf26
move some funcs to camera_cutscene
Aug 27, 2024
dfb200b
moving stuff around again
Aug 27, 2024
aeb2102
more cutscene helpers
Aug 27, 2024
0eb84d7
defer camera mode consolidation; add todos
Aug 28, 2024
2fcc455
i suspect camera_cutscene will be 1000 lines at the end of this
Aug 28, 2024
1d37dfc
mario_actions_cutscene is now involved
Aug 28, 2024
fc0ab52
migrate object cutscene code
Aug 28, 2024
e8bedd9
2500 lines; checkpoint to fix vanilla defines
Aug 28, 2024
048a5b3
that was less painful than i thought
Aug 29, 2024
f3c6814
poll results from #sm64-pr-discussion: it's now cutscene_helpers
Aug 29, 2024
136205c
and finish building
Aug 29, 2024
68ad3b5
update camera readme
Aug 29, 2024
130f261
camera_geo.h
Aug 29, 2024
c0a9b5e
rename update_camera_yaw
Aug 29, 2024
b59fc03
move more to cutscene and modes
Aug 29, 2024
da9a913
header cleanup
Aug 29, 2024
1e1dcd3
group shake funcs in camera.h
Aug 29, 2024
80573e7
remove temp cutscene tool
Aug 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -382,7 +382,8 @@ ACTOR_DIR := actors
LEVEL_DIRS := $(patsubst levels/%,%,$(dir $(wildcard levels/*/header.h)))

# Directories containing source files
SRC_DIRS += src src/boot src/game src/engine src/audio src/menu src/buffers actors levels bin data assets asm lib sound
CAMERA_DIRS += src/camera src/camera/level_specific src/camera/cutscenes src/camera/modes
SRC_DIRS += src src/boot src/game $(CAMERA_DIRS) src/engine src/audio src/menu src/buffers actors levels bin data assets asm lib sound
LIBZ_SRC_DIRS := src/libz
GODDARD_SRC_DIRS := src/goddard src/goddard/dynlists
BIN_DIRS := bin bin/$(VERSION)
5 changes: 5 additions & 0 deletions sm64.ld
Original file line number Diff line number Diff line change
@@ -248,18 +248,22 @@ SECTIONS
BUILD_DIR/src/engine/surface_collision.o(.text*);
BUILD_DIR/src/engine/surface_load.o(.text*);
BUILD_DIR/src/engine/graph_node.o(.text*);
BUILD_DIR/src/camera*.o(.text*);
BUILD_DIR/src/engine*.o(.text*);
_engineSegmentTextEnd = .;
/* data */
BUILD_DIR/src/game*.o(.data*);
BUILD_DIR/src/camera*.o(.*data*);
BUILD_DIR/src/engine*.o(.data*);
BUILD_DIR/src/usb*.o(.data*);
/* sdata */
BUILD_DIR/src/game*.o(.sdata*);
BUILD_DIR/src/camera*.o(.sdata*);
BUILD_DIR/src/engine*.o(.sdata*);
BUILD_DIR/src/usb*.o(.data*);
/* rodata */
BUILD_DIR/src/game*.o(.rodata*);
BUILD_DIR/src/camera*.o(.rodata*);
BUILD_DIR/src/engine*.o(.rodata*);
BUILD_DIR/src/usb*.o(.rodata*);
. = ALIGN(0x10);
@@ -268,6 +272,7 @@ SECTIONS
BEGIN_NOLOAD(engine)
{
BUILD_DIR/src/game*.o(.*bss*);
BUILD_DIR/src/camera*.o(.*bss*);
BUILD_DIR/src/engine*.o(.bss*);
. = ALIGN(0x40);
}
19 changes: 19 additions & 0 deletions src/camera/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Camera

The camera system in SM64 is notoriously complex, with the original file exceeding 11000 lines of code. HackerSM64 separates the camera code into more relevant and granular files. An index of changes is provided below.

```
src/game
└── camera.c: the default camera modes, as well as CameraTrigger and sZoomOutAreaMasks definitions (as not to interfere with Fast64)
src/camera
├── cutscenes
│ └── {cutscene}.c: the code for a cutscene (or group of scenes), and its cutscene struct definition
├── level_specific
│ └── {level}.c: camera trigger code for a vanilla level, if applicable
├── modes
│ └── {mode}.c: code for a specific camera mode
├── cutscene_helpers.c: cutscene and spline procesing, as well as shared cutscene functions
├── camera_geo.c: code for generating the Camera GraphNode
├── camera_math.c: math routines
└── camera_modes.c: shared functions used by camera modes
```
248 changes: 248 additions & 0 deletions src/camera/camera_geo.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
#include <ultra64.h>

#include "camera/camera_math.h"
#include "engine/math_util.h"
#include "game/camera.h"
#include "game/level_update.h"
#include "game/rendering_graph_node.h"

/**
* Add a cyclic offset to the camera's field of view based on a cosine wave
*/
static void shake_camera_fov(struct GraphNodePerspective *perspective) {
if (sFOVState.shakeAmplitude != 0.f) {
sFOVState.fovOffset = coss(sFOVState.shakePhase) * sFOVState.shakeAmplitude / 0x100;
sFOVState.shakePhase += sFOVState.shakeSpeed;
camera_approach_f32_symmetric_bool(&sFOVState.shakeAmplitude, 0.f, sFOVState.decay);
perspective->fov += sFOVState.fovOffset;
} else {
sFOVState.shakePhase = 0;
}
}

static void set_fov_30(UNUSED struct MarioState *m) {
sFOVState.fov = 30.f;
}

static void approach_fov_20(UNUSED struct MarioState *m) {
camera_approach_f32_symmetric_bool(&sFOVState.fov, 20.f, 0.3f);
}

static void set_fov_45(UNUSED struct MarioState *m) {
sFOVState.fov = 45.f;
}

static void set_fov_29(UNUSED struct MarioState *m) {
sFOVState.fov = 29.f;
}

static void zoom_fov_30(UNUSED struct MarioState *m) {
// Pretty sure approach_f32_asymptotic_bool would do a much nicer job here, but you do you,
// Nintendo.
camera_approach_f32_symmetric_bool(&sFOVState.fov, 30.f, (30.f - sFOVState.fov) / 60.f);
}

/**
* This is the default fov function. It makes fov approach 45 degrees, and it handles zooming in when
* Mario falls a sleep.
*/
static void fov_default(struct MarioState *m) {
sStatusFlags &= ~CAM_FLAG_SLEEPING;

if ((m->action == ACT_SLEEPING) || (m->action == ACT_START_SLEEPING)) {
camera_approach_f32_symmetric_bool(&sFOVState.fov, 30.f, (30.f - sFOVState.fov) / 30.f);
sStatusFlags |= CAM_FLAG_SLEEPING;
} else {
camera_approach_f32_symmetric_bool(&sFOVState.fov, 45.f, (45.f - sFOVState.fov) / 30.f);
sFOVState.unusedIsSleeping = 0;
}
if (m->area->camera->cutscene == CUTSCENE_0F_UNUSED) {
sFOVState.fov = 45.f;
}
}

static void approach_fov_30(UNUSED struct MarioState *m) {
camera_approach_f32_symmetric_bool(&sFOVState.fov, 30.f, 1.f);
}

static void approach_fov_60(UNUSED struct MarioState *m) {
camera_approach_f32_symmetric_bool(&sFOVState.fov, 60.f, 1.f);
}

static void approach_fov_45(struct MarioState *m) {
f32 targetFoV = sFOVState.fov;

if (m->area->camera->mode == CAMERA_MODE_FIXED && m->area->camera->cutscene == 0) {
targetFoV = 45.f;
} else {
targetFoV = 45.f;
}

sFOVState.fov = approach_f32(sFOVState.fov, targetFoV, 2.f, 2.f);
}

static void approach_fov_80(UNUSED struct MarioState *m) {
camera_approach_f32_symmetric_bool(&sFOVState.fov, 80.f, 3.5f);
}

/**
* Sets the fov in BBH.
* If there's a cutscene, sets fov to 45. Otherwise sets fov to 60.
*/
static void set_fov_bbh(struct MarioState *m) {
f32 targetFoV = sFOVState.fov;

if (m->area->camera->mode == CAMERA_MODE_FIXED && m->area->camera->cutscene == 0) {
targetFoV = 60.f;
} else {
targetFoV = 45.f;
}

sFOVState.fov = approach_f32(sFOVState.fov, targetFoV, 2.f, 2.f);
}

/**
* Sets the field of view for the GraphNodeCamera
*/
Gfx *geo_camera_fov(s32 callContext, struct GraphNode *g, UNUSED void *context) {
struct GraphNodePerspective *perspective = (struct GraphNodePerspective *) g;
struct MarioState *marioState = &gMarioStates[0];
u8 fovFunc = sFOVState.fovFunc;

if (callContext == GEO_CONTEXT_RENDER) {
switch (fovFunc) {
case CAM_FOV_SET_45:
set_fov_45(marioState);
break;
case CAM_FOV_SET_29:
set_fov_29(marioState);
break;
case CAM_FOV_ZOOM_30:
zoom_fov_30(marioState);
break;
case CAM_FOV_DEFAULT:
fov_default(marioState);
break;
case CAM_FOV_BBH:
set_fov_bbh(marioState);
break;
case CAM_FOV_APP_45:
approach_fov_45(marioState);
break;
case CAM_FOV_SET_30:
set_fov_30(marioState);
break;
case CAM_FOV_APP_20:
approach_fov_20(marioState);
break;
case CAM_FOV_APP_80:
approach_fov_80(marioState);
break;
case CAM_FOV_APP_30:
approach_fov_30(marioState);
break;
case CAM_FOV_APP_60:
approach_fov_60(marioState);
break;
default:
set_fov_45(marioState);
break;
}
}

perspective->fov = sFOVState.fov;
shake_camera_fov(perspective);
return NULL;
}

/**
* Allocate the GraphNodeCamera's config.camera, and copy `c`'s focus to the Camera's area center point.
*/
static void create_camera(struct GraphNodeCamera *gc, struct AllocOnlyPool *pool) {
#ifdef FORCED_CAMERA_MODE
gc->config.mode = FORCED_CAMERA_MODE;
#endif
s16 mode = gc->config.mode;
struct Camera *c = alloc_only_pool_alloc(pool, sizeof(struct Camera));

gc->config.camera = c;
c->mode = mode;
c->defMode = mode;
c->cutscene = CUTSCENE_NONE;
c->doorStatus = DOOR_DEFAULT;
c->areaCenX = gc->focus[0];
c->areaCenY = gc->focus[1];
c->areaCenZ = gc->focus[2];
c->yaw = 0;
vec3f_copy(c->pos, gc->pos);
vec3f_copy(c->focus, gc->focus);
}

/**
* Zooms out the camera if paused and the level is 'outside', as determined by sZoomOutAreaMasks.
*
* Because gCurrLevelArea is assigned gCurrLevelNum * 16 + gCurrentArea->index,
* dividing by 32 maps 2 levels to one index.
*
* areaBit definition:
* (gCurrLevelArea & 0x10) / 4):
* This adds 4 to the shift if the level is an odd multiple of 16
*
* ((gCurrLevelArea & 0xF) - 1) & 3):
* This isolates the lower 16 'area' bits, subtracts 1 because areas are 1-indexed, and effectively
* modulo-4's the result, because each 8-bit mask only has 4 area bits for each level
*/
static void zoom_out_if_paused_and_outside(struct GraphNodeCamera *camera) {
s16 yaw;
s32 areaMaskIndex = gCurrLevelArea / 32;
s32 areaBit = 1 << (((gCurrLevelArea & 0x10) / 4) + (((gCurrLevelArea & 0xF) - 1) & 3));

if (areaMaskIndex >= LEVEL_MAX / 2) {
areaMaskIndex = 0;
areaBit = 0;
}
if (gCameraMovementFlags & CAM_MOVE_PAUSE_SCREEN) {
if (sFramesPaused >= 2) {
if (sZoomOutAreaMasks[areaMaskIndex] & areaBit) {

camera->focus[0] = gCamera->areaCenX;
camera->focus[1] = (sMarioCamState->pos[1] + gCamera->areaCenY) / 2;
camera->focus[2] = gCamera->areaCenZ;
vec3f_get_yaw(camera->focus, sMarioCamState->pos, &yaw);
vec3f_set_dist_and_angle(sMarioCamState->pos, camera->pos, 6000.f, 0x1000, yaw);
#ifdef ENABLE_VANILLA_LEVEL_SPECIFIC_CHECKS
if (gCurrLevelNum != LEVEL_THI) {
find_in_bounds_yaw_wdw_bob_thi(camera->pos, camera->focus, 0);
}
#endif
}
} else {
sFramesPaused++;
}
} else {
sFramesPaused = 0;
}
}

/**
* Copy Lakitu's pos and foc into `gc`
*/
static void update_graph_node_camera(struct GraphNodeCamera *gc) {
gc->rollScreen = gLakituState.roll;
vec3f_copy(gc->pos, gLakituState.pos);
vec3f_copy(gc->focus, gLakituState.focus);
zoom_out_if_paused_and_outside(gc);
}

Gfx *geo_camera_main(s32 callContext, struct GraphNode *g, void *context) {
struct GraphNodeCamera *gc = (struct GraphNodeCamera *) g;
switch (callContext) {
case GEO_CONTEXT_CREATE:
create_camera(gc, context);
break;
case GEO_CONTEXT_RENDER:
update_graph_node_camera(gc);
break;
}
return NULL;
}
8 changes: 8 additions & 0 deletions src/camera/camera_geo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

#include "types.h"
#include "game/camera.h"

Gfx *geo_camera_fov(s32 callContext, struct GraphNode *g, UNUSED void *context);
Gfx *geo_camera_main(s32 callContext, struct GraphNode *g, void *context);

Loading