From 305518ce3c5b1824a6a1f5ef55da234675596d63 Mon Sep 17 00:00:00 2001 From: Fazana <52551480+FazanaJ@users.noreply.github.com> Date: Sat, 24 Jul 2021 16:14:03 +0100 Subject: [PATCH 1/7] Puppy Camera 2 Now supported with the HackerSM64 repo --- Makefile | 1 + include/text_strings.h.in | 65 ++ src/game/camera.c | 43 +- src/game/game_init.c | 4 +- src/game/hud.c | 4 +- src/game/ingame_menu.c | 13 +- src/game/mario_misc.c | 17 +- src/game/puppycam2.c | 1595 +++++++++++++++++++++++++++++++++++++ src/game/puppycam2.h | 171 ++++ src/game/save_file.c | 30 + src/game/save_file.h | 9 +- 11 files changed, 1944 insertions(+), 8 deletions(-) create mode 100644 src/game/puppycam2.c create mode 100644 src/game/puppycam2.h diff --git a/Makefile b/Makefile index ef303a7b..c0041f67 100644 --- a/Makefile +++ b/Makefile @@ -566,6 +566,7 @@ $(BUILD_DIR)/include/text_strings.h: $(BUILD_DIR)/include/text_menu_strings.h $(BUILD_DIR)/src/menu/file_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/src/menu/star_select.o: $(BUILD_DIR)/include/text_strings.h $(BUILD_DIR)/src/game/ingame_menu.o: $(BUILD_DIR)/include/text_strings.h +$(BUILD_DIR)/src/game/puppycam2.o: $(BUILD_DIR)/include/text_strings.h #==============================================================================# diff --git a/include/text_strings.h.in b/include/text_strings.h.in index d2660588..26b2c0a7 100644 --- a/include/text_strings.h.in +++ b/include/text_strings.h.in @@ -3,6 +3,71 @@ #include "text_menu_strings.h" +#define NC_CAMX_EN _("Camera X Sensitivity") +#define NC_CAMY_EN _("Camera Y Sensitivity") +#define NC_INVERTX_EN _("Invert X Axis") +#define NC_INVERTX_FR _("Invertir Axe X") +#define NC_INVERTX_DE _("Invert X Axis") +#define NC_INVERTY_EN _("Invert Y Axis") +#define NC_CAMC_EN _("Camera Centre Speed") +#define NC_ANALOGUE_EN _("Analogue Camera") +#define NC_SCHEME_EN _("Control Scheme") +#define OPTION_ENABLED_EN _("Enabled") +#define OPTION_DISABLED_EN _("Disabled") +#define OPTION_SCHEME1_EN _("Double Tap") +#define OPTION_SCHEME2_EN _("Single Press") +#define OPTION_SCHEME3_EN _("Classic") +#define NC_HIGHLIGHT_L _(">") +#define NC_HIGHLIGHT_R _("<") +#define NC_BUTTON_EN _("[R]: Options") +#define NC_BUTTON2_EN _("[R]: Return") +#define NC_OPTION_EN _("PUPPYCAM OPTIONS") + + +#if defined(VERSION_EU) +#define NC_CAMX_FR _("Sensibilite sur l'axe X") +#define NC_CAMX_DE _("Camera X Sensitivity") + +#define NC_CAMY_FR _("Sensibilite sur l'axe Y") +#define NC_CAMY_DE _("Camera Y Sensitivity") + +#define NC_INVERTY_FR _("Invertir Axe Y") +#define NC_INVERTY_DE _("Invert Y Axis") + +#define NC_CAMC_FR _("Vitesse de Centrage") +#define NC_CAMC_DE _("Camera Centre Speed") + +#define NC_ANALOGUE_FR _("Camera Analogue") +#define NC_ANALOGUE_DE _("Analogue Camera") + +#define NC_SCHEME_FR _("Control Scheme") +#define NC_SCHEME_DE _("Control Scheme") + +#define OPTION_ENABLED_FR _("Active") +#define OPTION_ENABLED_DE _("Enabled") + +#define OPTION_DISABLED_FR _("Desactive") +#define OPTION_DISABLED_DE _("Disabled") + +#define OPTION_SCHEME1_FR _("Double Tap") +#define OPTION_SCHEME1_DE _("Double Tap") + +#define OPTION_SCHEME2_FR _("Single Press") +#define OPTION_SCHEME2_DE _("Single Press") + +#define OPTION_SCHEME3_FR _("Classic") +#define OPTION_SCHEME3_DE _("Classic") + +#define NC_BUTTON_FR _("[R]: Options") +#define NC_BUTTON_DE _("[R]: Options") + +#define NC_BUTTON2_FR _("[R]: Retournez") +#define NC_BUTTON2_DE _("[R]: Return") + +#define NC_OPTION_FR _("OPTIONS PUPPYCAM") +#define NC_OPTION_DE _("PUPPYCAM OPTIONS") +#endif + /** * Global Symbols */ diff --git a/src/game/camera.c b/src/game/camera.c index dfcf16ae..0435d3be 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -1202,7 +1202,7 @@ void mode_8_directions_camera(struct Camera *c) { } else if (gPlayer1Controller->buttonPressed & D_JPAD) { s8DirModeYawOffset = s8DirModeYawOffset&0xE000; - } + } #endif lakitu_zoom(400.f, 0x900); @@ -3038,7 +3038,7 @@ void update_camera(struct Camera *c) { gCamera = c; update_camera_hud_status(c); - if (c->cutscene == 0) { + if (c->cutscene == 0 && !gPuppyCam.enabled && !(gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON)) { // Only process R_TRIG if 'fixed' is not selected in the menu if (cam_select_alt_mode(0) == CAM_SELECTION_MARIO) { if (gPlayer1Controller->buttonPressed & R_TRIG) { @@ -3060,6 +3060,7 @@ void update_camera(struct Camera *c) { sStatusFlags |= CAM_FLAG_FRAME_AFTER_CAM_INIT; } + if (!gPuppyCam.enabled || c->cutscene != 0 || gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON) { // Store previous geometry information sMarioGeometry.prevFloorHeight = sMarioGeometry.currFloorHeight; sMarioGeometry.prevCeilHeight = sMarioGeometry.currCeilHeight; @@ -3182,10 +3183,12 @@ void update_camera(struct Camera *c) { } } } + } // Start any Mario-related cutscenes start_cutscene(c, get_cutscene_from_mario_status(c)); stub_camera_2(c); gCheckingSurfaceCollisionsForCamera = FALSE; + if (!gPuppyCam.enabled || c->cutscene != 0 || gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON) { if (gCurrLevelNum != LEVEL_CASTLE) { // If fixed camera is selected as the alternate mode, then fix the camera as long as the right // trigger is held @@ -3223,7 +3226,42 @@ void update_camera(struct Camera *c) { } update_lakitu(c); + } + //Just a cute little bit that syncs puppycamera up to vanilla when playing a vanilla cutscene :3 + if (c->cutscene != 0) + { + gPuppyCam.yawTarget = gCamera->yaw; + gPuppyCam.yaw = gCamera->yaw; + if (gMarioState->action == ACT_ENTERING_STAR_DOOR) + { //god this is stupid and the fact I have to continue doing this is testament to the idiocy of the star door cutscene >:( + gPuppyCam.yawTarget = gMarioState->faceAngle[1]+0x8000; + gPuppyCam.yaw = gMarioState->faceAngle[1]+0x8000; + } + } + if (c->cutscene == 0 && gPuppyCam.enabled && !(gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON)) + { + // Clear the recent cutscene after 8 frames + if (gRecentCutscene != 0 && sFramesSinceCutsceneEnded < 8) { + sFramesSinceCutsceneEnded++; + if (sFramesSinceCutsceneEnded >= 8) { + gRecentCutscene = 0; + sFramesSinceCutsceneEnded = 0; + } + } + puppycam_loop(); + // Apply camera shakes + shake_camera_pitch(gLakituState.pos, gLakituState.focus); + shake_camera_yaw(gLakituState.pos, gLakituState.focus); + shake_camera_roll(&gLakituState.roll); + shake_camera_handheld(gLakituState.pos, gLakituState.focus); + + if (sMarioCamState->action == ACT_DIVE && gLakituState.lastFrameAction != ACT_DIVE) { + set_camera_shake_from_hit(SHAKE_HIT_FROM_BELOW); + } + gLakituState.roll += sHandheldShakeRoll; + gLakituState.roll += gLakituState.keyDanceRoll; + } gLakituState.lastFrameAction = sMarioCamState->action; } @@ -3460,6 +3498,7 @@ void init_camera(struct Camera *c) { gLakituState.nextYaw = gLakituState.yaw; c->yaw = gLakituState.yaw; c->nextYaw = gLakituState.yaw; + puppycam_init(); } /** diff --git a/src/game/game_init.c b/src/game/game_init.c index 6cfa8f55..30295677 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -30,6 +30,7 @@ #include "sram.h" #endif #include +#include "puppycam2.h" // First 3 controller slots struct Controller gControllers[3]; @@ -288,7 +289,7 @@ void create_gfx_task_structure(void) { gGfxSPTask->task.t.ucode_data = gspF3DEX_fifoDataStart; #elif SUPER3D_GBI gGfxSPTask->task.t.ucode = gspSuper3D_fifoTextStart; - gGfxSPTask->task.t.ucode_data = gspSuper3D_fifoDataStart; + gGfxSPTask->task.t.ucode_data = gspSuper3D_fifoDataStart; #else gGfxSPTask->task.t.ucode = gspFast3D_fifoTextStart; gGfxSPTask->task.t.ucode_data = gspFast3D_fifoDataStart; @@ -707,6 +708,7 @@ void thread5_game_loop(UNUSED void *arg) { createHvqmThread(); #endif save_file_load_all(); + puppycam_boot(); set_vblank_handler(2, &gGameVblankHandler, &gGameVblankQueue, (OSMesg) 1); diff --git a/src/game/hud.c b/src/game/hud.c index 42fd1554..ee927a00 100644 --- a/src/game/hud.c +++ b/src/game/hud.c @@ -14,6 +14,7 @@ #include "save_file.h" #include "print.h" #include "engine/surface_load.h" +#include "puppycam2.h" /* @file hud.c * This file implements HUD rendering and power meter animations. @@ -506,7 +507,8 @@ void render_hud(void) { if (hudDisplayFlags & HUD_DISPLAY_FLAG_CAMERA_AND_POWER) { render_hud_power_meter(); - render_hud_camera_status(); + if (!gPuppyCam.enabled) + render_hud_camera_status(); } if (hudDisplayFlags & HUD_DISPLAY_FLAG_TIMER) { diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index 9cd458a8..4ac9f8ee 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -23,6 +23,7 @@ #include "text_strings.h" #include "types.h" #include "config.h" +#include "puppycam2.h" u16 gDialogColorFadeTimer; s8 gLastDialogLineNum; @@ -1414,7 +1415,7 @@ void render_widescreen_setting(void) { gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); if (!gWidescreen) { print_generic_string(10, 20, textCurrRatio43); - print_generic_string(10, 7, textPressL); + print_generic_string(10, 7, textPressL); } else { print_generic_string(10, 20, textCurrRatio169); @@ -1713,6 +1714,9 @@ s16 render_pause_courses_and_castle(void) { s16 index; + puppycam_check_pause_buttons(); + if (!gPCOptionOpen) + { switch (gDialogBoxState) { case DIALOG_STATE_OPENING: gDialogLineNum = MENU_OPT_DEFAULT; @@ -1787,7 +1791,14 @@ s16 render_pause_courses_and_castle(void) { if (gDialogTextAlpha < 250) { gDialogTextAlpha += 25; } + } + else + { + shade_screen(); + puppycam_display_options(); + } + puppycam_render_option_text(); return MENU_OPT_NONE; } diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index f4a3d99c..68af9f7a 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -24,6 +24,7 @@ #include "save_file.h" #include "skybox.h" #include "sound_init.h" +#include "puppycam2.h" #include "config.h" @@ -127,7 +128,7 @@ static void toad_message_opaque(void) { } static void toad_message_talking(void) { - if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_DOWN, + if (cur_obj_update_dialog_with_cutscene(MARIO_DIALOG_LOOK_DOWN, DIALOG_FLAG_TURN_TO_MARIO, CUTSCENE_DIALOG, gCurrentObject->oToadMessageDialogId)) { gCurrentObject->oToadMessageRecentlyTalked = TRUE; gCurrentObject->oToadMessageState = TOAD_MESSAGE_FADING; @@ -314,7 +315,14 @@ static Gfx *make_gfx_mario_alpha(struct GraphNodeGenerated *node, s16 alpha) { node->fnNode.node.flags = (node->fnNode.node.flags & 0xFF) | (LAYER_TRANSPARENT << 8); gfxHead = alloc_display_list(3 * sizeof(*gfxHead)); gfx = gfxHead; - gDPSetAlphaCompare(gfx++, G_AC_DITHER); + if (gMarioState->flags & MARIO_VANISH_CAP) + { + gDPSetAlphaCompare(gfx++, G_AC_DITHER); + } + else + { + gDPSetAlphaCompare(gfx++, G_AC_NONE); + } } gDPSetEnvColor(gfx++, 255, 255, 255, alpha); gSPEndDisplayList(gfx); @@ -334,6 +342,11 @@ Gfx *geo_mirror_mario_set_alpha(s32 callContext, struct GraphNode *node, UNUSED if (callContext == GEO_CONTEXT_RENDER) { alpha = (bodyState->modelState & 0x100) ? (bodyState->modelState & 0xFF) : 255; + if (alpha > gPuppyCam.opacity) + { + alpha = gPuppyCam.opacity; + bodyState->modelState |= MODEL_STATE_NOISE_ALPHA; + } gfx = make_gfx_mario_alpha(asGenerated, alpha); } return gfx; diff --git a/src/game/puppycam2.c b/src/game/puppycam2.c new file mode 100644 index 00000000..daa4f9ca --- /dev/null +++ b/src/game/puppycam2.c @@ -0,0 +1,1595 @@ +///Puppycam 2.1 by Fazana + +#include +#include +#include "sm64.h" +#include "types.h" +#include "level_update.h" +#include "puppycam2.h" +#include "audio/external.h" +#include "audio/data.h" +#include "game_init.h" +#include "engine/math_util.h" +#include "print.h" +#include "engine/surface_collision.h" +#include "engine/surface_load.h" +#include "include/text_strings.h" +#include "segment2.h" +#include "ingame_menu.h" +#include "memory.h" +#include "object_list_processor.h" +#include "object_helpers.h" +#include "behavior_data.h" +#include "save_file.h" +#include "mario.h" + +#define OFFSET 30.0f +#define STEPS 1 +#define DECELERATION 0.66f +#define DEADZONE 20 +#define SCRIPT_MEMORY_POOL 0x1000 + +struct gPuppyStruct gPuppyCam; +struct sPuppyVolume *sPuppyVolumeStack[MAX_PUPPYCAM_VOLUMES]; +s16 sFloorHeight = 0; +u8 gPCOptionOpen = 0; +s8 gPCOptionSelected = 0; +s32 gPCOptionTimer = 0; +u8 gPCOptionIndex = 0; +u8 gPCOptionScroll = 0; +u16 gPuppyVolumeCount = 0; +struct MemoryPool *gPuppyMemoryPool; +s32 gPuppyError = 0; + +#if defined(VERSION_EU) +static u8 gPCOptionStringsFR[][64] = {{NC_ANALOGUE_FR}, {NC_CAMX_FR}, {NC_CAMY_FR}, {NC_INVERTX_FR}, {NC_INVERTY_FR}, {NC_CAMC_FR}, {NC_SCHEME_FR},}; +static u8 gPCOptionStringsDE[][64] = {{NC_ANALOGUE_DE}, {NC_CAMX_DE}, {NC_CAMY_DE}, {NC_INVERTX_DE}, {NC_INVERTY_DE}, {NC_CAMC_DE}, {NC_SCHEME_DE},}; +static u8 gPCFlagStringsFR[][64] = {{OPTION_DISABLED_FR}, {OPTION_ENABLED_FR}, {OPTION_SCHEME1_FR}, {OPTION_SCHEME2_FR}, {OPTION_SCHEME3_FR}}; +static u8 gPCFlagStringsDE[][64] = {{OPTION_DISABLED_DE}, {OPTION_ENABLED_DE}, {OPTION_SCHEME1_DE}, {OPTION_SCHEME2_DE}, {OPTION_SCHEME3_DE}}; +static u8 gPCToggleStringsFR[][64] = {{NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}}; +static u8 gPCToggleStringsDE[][64] = {{NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}}; +//static u8 gPCToggleStringsFR[][64] = {{NC_BUTTON_FR}, {NC_BUTTON2_FR}, {NC_OPTION_FR}, {NC_HIGHLIGHT_L_FR}, {NC_HIGHLIGHT_R_FR}}; +//static u8 gPCToggleStringsDE[][64] = {{NC_BUTTON_DE}, {NC_BUTTON2_DE}, {NC_OPTION_DE}, {NC_HIGHLIGHT_L_DE}, {NC_HIGHLIGHT_R_DE}}; +#endif +static u8 gPCOptionStringsEN[][64] = {{NC_ANALOGUE_EN}, {NC_CAMX_EN}, {NC_CAMY_EN}, {NC_INVERTX_EN}, {NC_INVERTY_EN}, {NC_CAMC_EN}, {NC_SCHEME_EN},}; +static u8 gPCFlagStringsEN[][64] = {{OPTION_DISABLED_EN}, {OPTION_ENABLED_EN}, {OPTION_SCHEME1_EN}, {OPTION_SCHEME2_EN}, {OPTION_SCHEME3_EN}}; +static u8 gPCToggleStringsEN[][64] = {{NC_BUTTON_EN}, {NC_BUTTON2_EN}, {NC_OPTION_EN}, {NC_HIGHLIGHT_L}, {NC_HIGHLIGHT_R}}; + + +#define OPT 32 //Just a temp thing + +static u8 (*gPCOptionStringsPtr)[OPT][64] = &gPCOptionStringsEN; +static u8 (*gPCFlagStringsPtr)[OPT][64] = &gPCFlagStringsEN; +static u8 (*gPCToggleStringsPtr)[OPT][64] = &gPCToggleStringsEN; + + +static const struct gPCOptionStruct +{ + u8 gPCOptionName; //This is the position in the newcam_options text array. It doesn't have to directly correlate with its position in the struct + s16 *gPCOptionVar; //This is the value that the option is going to directly affect. + u8 gPCOptionStart; //This is where the text array will start. Set it to 255 to have it be ignored. + s32 gPCOptionMin; //The minimum value of the option. + s32 gPCOptionMax; //The maximum value of the option. +}; + +static const struct gPCOptionStruct gPCOptions[]= +{ //If the min and max are 0 and 1, then the value text is used, otherwise it's ignored. + {/*Option Name*/ 0, /*Option Variable*/ &gPuppyCam.options.analogue, /*Option Value Text Start*/ 0, /*Option Minimum*/ FALSE, /*Option Maximum*/ TRUE}, + {/*Option Name*/ 6, /*Option Variable*/ &gPuppyCam.options.inputType, /*Option Value Text Start*/ 2, /*Option Minimum*/ 0, /*Option Maximum*/ 2}, + {/*Option Name*/ 1, /*Option Variable*/ &gPuppyCam.options.sensitivityX, /*Option Value Text Start*/ 255, /*Option Minimum*/ 10, /*Option Maximum*/ 500}, + {/*Option Name*/ 2, /*Option Variable*/ &gPuppyCam.options.sensitivityY, /*Option Value Text Start*/ 255, /*Option Minimum*/ 10, /*Option Maximum*/ 500}, + {/*Option Name*/ 3, /*Option Variable*/ &gPuppyCam.options.invertX, /*Option Value Text Start*/ 0, /*Option Minimum*/ FALSE, /*Option Maximum*/ TRUE}, + {/*Option Name*/ 4, /*Option Variable*/ &gPuppyCam.options.invertY, /*Option Value Text Start*/ 0, /*Option Minimum*/ FALSE, /*Option Maximum*/ TRUE}, + {/*Option Name*/ 5, /*Option Variable*/ &gPuppyCam.options.turnAggression, /*Option Value Text Start*/ 255, /*Option Minimum*/ 0, /*Option Maximum*/ 100}, +}; + +u8 gPCOptionCap = sizeof(gPCOptions) / sizeof(struct gPCOptionStruct); //How many options there are in newcam_uptions. + +//Some macros for the sake of basic human sanity. +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) +#define ABS(x) ((x) > 0.f ? (x) : -(x)) + +s16 LENSIN(s16 length, s16 direction) +{ + return (length * sins(direction)); +} +s16 LENCOS(s16 length, s16 direction) +{ + return (length * coss(direction)); +} + +static void puppycam_analogue_stick(void) +{ + #ifdef TARGET_N64 + if (!gPuppyCam.options.analogue) + return; + + //I make the X axis negative, so that the movement reflects the Cbuttons. + gPuppyCam.stick2[0] = -gPlayer2Controller->rawStickX; + gPuppyCam.stick2[1] = gPlayer2Controller->rawStickY; + + if (ABS(gPuppyCam.stick2[0]) < DEADZONE) + { + gPuppyCam.stick2[0] = 0; + gPuppyCam.stickN[0] = 0; + } + if (ABS(gPuppyCam.stick2[1]) < DEADZONE) + { + gPuppyCam.stick2[1] = 0; + gPuppyCam.stickN[1] = 0; + } + #endif +} + +void puppycam_default_config(void) +{ + gPuppyCam.options.invertX = 1; + gPuppyCam.options.invertY = 1; + gPuppyCam.options.sensitivityX = 100; + gPuppyCam.options.sensitivityY = 100; + gPuppyCam.options.turnAggression = 50; + gPuppyCam.options.analogue = 0; + gPuppyCam.options.inputType = 1; +} + +//Initial setup. Ran at the beginning of the game and never again. +void puppycam_boot(void) +{ + gPuppyCam.zoomPoints[0] = 600; + gPuppyCam.zoomPoints[1] = 1000; + gPuppyCam.zoomPoints[2] = 1500; + gPuppyCam.povHeight = 125; + gPuppyCam.stick2[0] = 0; + gPuppyCam.stick2[1] = 0; + gPuppyCam.stickN[0] = 0; + gPuppyCam.stickN[1] = 0; + gPuppyMemoryPool = mem_pool_init(MAX_PUPPYCAM_VOLUMES * sizeof(struct sPuppyVolume), MEMORY_POOL_LEFT); + gPuppyVolumeCount = 0; + gPuppyCam.enabled = 1; + + puppycam_get_save(); +} + +//Called when an instant warp is done. +void puppycam_warp(f32 displacementX, f32 displacementY, f32 displacementZ) +{ + gPuppyCam.pos[0] += displacementX; + gPuppyCam.pos[1] += displacementY; + gPuppyCam.pos[2] += displacementZ; + gPuppyCam.targetFloorHeight += displacementY; + gPuppyCam.lastTargetFloorHeight += displacementY; + gPuppyCam.floorY[0] += displacementY; + gPuppyCam.floorY[1] += displacementY; +} + +#if defined(VERSION_EU) +static void newcam_set_language(void) +{ + switch (eu_get_language()) + { + case 0: + gPCOptionStringsPtr = &gPCOptionStringsEN; + gPCFlagStringsPtr = &gPCFlagStringsEN; + gPCToggleStringsPtr = &gPCToggleStringsEN; + break; + case 1: + gPCOptionStringsPtr = &gPCOptionStringsFR; + gPCFlagStringsPtr = &gPCFlagStringsFR; + gPCToggleStringsPtr = &gPCToggleStringsFR; + break; + case 2: + gPCOptionStringsPtr = &gPCOptionStringsDE; + gPCFlagStringsPtr = &gPCFlagStringsDE; + gPCToggleStringsPtr = &gPCToggleStringsDE; + break; + } +} +#endif + +///CUTSCENE + +void puppycam_activate_cutscene(s32 *scene, s32 lockinput) +{ + gPuppyCam.cutscene = 1; + gPuppyCam.sceneTimer = 0; + gPuppyCam.sceneFunc = scene; + gPuppyCam.sceneInput = lockinput; +} + +static void newcam_process_cutscene(void) +{ + if (gPuppyCam.cutscene) + { + if ((gPuppyCam.sceneFunc)() == 1) + { + gPuppyCam.cutscene = 0; + gPuppyCam.sceneInput = 0; + gPuppyCam.flags = gPuppyCam.intendedFlags; + } + gPuppyCam.sceneTimer++; + } +} + +///MENU + +#define BLANK 0, 0, 0, ENVIRONMENT, 0, 0, 0, ENVIRONMENT + +static void puppycam_display_box(s16 x1, s16 y1, s16 x2, s16 y2, u8 r, u8 g, u8 b, u8 a) +{ + gDPSetCombineMode(gDisplayListHead++, BLANK, BLANK); + gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); + if (a !=255) + { + gDPSetRenderMode(gDisplayListHead++, G_RM_XLU_SURF, G_RM_XLU_SURF2); + } + else + { + gDPSetRenderMode(gDisplayListHead++, G_RM_OPA_SURF, G_RM_OPA_SURF); + } + gDPSetEnvColor(gDisplayListHead++, r, g, b, a); + gDPFillRectangle(gDisplayListHead++, x1, y1, x2, y2); + gDPPipeSync(gDisplayListHead++); + gDPSetEnvColor(gDisplayListHead++,255,255,255,255); + gDPSetCycleType(gDisplayListHead++, G_CYC_1CYCLE); + gSPDisplayList(gDisplayListHead++,dl_hud_img_end); +} + +//I actually took the time to redo this, properly. Lmao. Please don't bully me over this anymore :( +void puppycam_change_setting(s8 toggle) +{ + if (gPlayer1Controller->buttonDown & A_BUTTON) + toggle*= 5; + if (gPlayer1Controller->buttonDown & B_BUTTON) + toggle*= 10; + + if (gPCOptions[gPCOptionSelected].gPCOptionMin == FALSE && gPCOptions[gPCOptionSelected].gPCOptionMax == TRUE) + { + *gPCOptions[gPCOptionSelected].gPCOptionVar ^= 1; + } + else + *gPCOptions[gPCOptionSelected].gPCOptionVar += toggle; + //Forgive me father, for I have sinned. I guess if you wanted a selling point for a 21:9 monitor though, "I can view this line in puppycam's code without scrolling!" can be added to it. + *gPCOptions[gPCOptionSelected].gPCOptionVar = CLAMP(*gPCOptions[gPCOptionSelected].gPCOptionVar, gPCOptions[gPCOptionSelected].gPCOptionMin, gPCOptions[gPCOptionSelected].gPCOptionMax); +} + +void puppycam_print_text(s16 x, s16 y, u8 str[], u8 col) +{ + u8 textX; + textX = get_str_x_pos_from_center(x,str,10.0f); + gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 255); + print_generic_string(textX+1,y-1,str); + if (col != 0) + { + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); + } + else + { + gDPSetEnvColor(gDisplayListHead++, 255, 32, 32, 255); + } + print_generic_string(textX,y,str); +} + +//Options menu +void puppycam_display_options() +{ + u8 i = 0; + u8 newstring[32]; + s16 scroll; + s16 scrollpos; + s16 var = gPCOptions; + s16 vr; + u16 maxvar; + u16 minvar; + f32 newcam_sinpos; + + puppycam_display_box(47,83,281,84,0x0,0x0,0x0, 0xFF); + puppycam_display_box(47,218,281,219,0x0,0x0,0x0, 0xFF); + puppycam_display_box(47,83,48,219,0x0,0x0,0x0, 0xFF); + puppycam_display_box(280,83,281,219,0x0,0x0,0x0, 0xFF); + puppycam_display_box(271,83,272,219,0x0,0x0,0x0, 0xFF); + + puppycam_display_box(48,84,272,218,0x0,0x0,0x0, 0x50); + gSPDisplayList(gDisplayListHead++, dl_rgba16_text_begin); + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); + print_hud_lut_string(HUD_LUT_GLOBAL, 64, 40, (*gPCToggleStringsPtr)[2]); + gSPDisplayList(gDisplayListHead++, dl_rgba16_text_end); + + if (gPCOptionCap>4) + { + puppycam_display_box(272,84,280,218,0x80,0x80,0x80, 0xFF); + scrollpos = (62)*((f32)gPCOptionScroll/(gPCOptionCap-4)); + puppycam_display_box(272,84+scrollpos,280,156+scrollpos,0xFF,0xFF,0xFF, 0xFF); + } + + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); + gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 80, SCREEN_WIDTH, SCREEN_HEIGHT); + for (i = 0; i < gPCOptionCap; i++) + { + scroll = 140-(32*i)+(gPCOptionScroll*32); + if (scroll <= 140 && scroll > 32) + { + puppycam_print_text(160,scroll,(*gPCOptionStringsPtr)[gPCOptions[i].gPCOptionName],gPCOptionSelected-i); + if (gPCOptions[i].gPCOptionStart != 255) + { + var = *gPCOptions[i].gPCOptionVar+gPCOptions[i].gPCOptionStart; + if (var < sizeof(gPCFlagStringsEN)) //Failsafe for if it somehow indexes an out of bounds array. + puppycam_print_text(160,scroll-12,(*gPCFlagStringsPtr)[var],gPCOptionSelected-i); + } + else + { + int_to_str(*gPCOptions[i].gPCOptionVar,newstring); + puppycam_print_text(160,scroll-12,newstring,gPCOptionSelected-i); + puppycam_display_box(96,111+(32*i)-(gPCOptionScroll*32),224,117+(32*i)-(gPCOptionScroll*32),0x80,0x80,0x80, 0xFF); + maxvar = gPCOptions[i].gPCOptionMax - gPCOptions[i].gPCOptionMin; + minvar = *gPCOptions[i].gPCOptionVar - gPCOptions[i].gPCOptionMin; + puppycam_display_box(96,111+(32*i)-(gPCOptionScroll*32),96+(((f32)minvar/maxvar)*128),117+(32*i)-(gPCOptionScroll*32),0xFF,0xFF,0xFF, 0xFF); + puppycam_display_box(94+(((f32)minvar/maxvar)*128),109+(32*i)-(gPCOptionScroll*32),98+(((f32)minvar/maxvar)*128),119+(32*i)-(gPCOptionScroll*32),0xFF,0x0,0x0, 0xFF); + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); + } + } + } + newcam_sinpos = sins(gGlobalTimer*5000)*4; + gDPSetScissor(gDisplayListHead++, G_SC_NON_INTERLACE, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 255); + print_generic_string(80-newcam_sinpos, 132-(32*(gPCOptionSelected-gPCOptionScroll)), (*gPCToggleStringsPtr)[3]); + print_generic_string(232+newcam_sinpos, 132-(32*(gPCOptionSelected-gPCOptionScroll)), (*gPCToggleStringsPtr)[4]); + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); +} + +//This has been separated for interesting reasons. Don't question it. +void puppycam_render_option_text(void) +{ + gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); + puppycam_print_text(278,212,(*gPCToggleStringsPtr)[gPCOptionOpen],1); + gSPDisplayList(gDisplayListHead++, dl_ia_text_end); +} + +extern struct SaveBuffer gSaveBuffer; + +void puppycam_check_pause_buttons() +{ + if (gPlayer1Controller->buttonPressed & R_TRIG) + { + play_sound(SOUND_MENU_CHANGE_SELECT, gGlobalSoundSource); + if (gPCOptionOpen == 0) + { + gPCOptionOpen = 1; + #if defined(VERSION_EU) + newcam_set_language(); + #endif + } + + else + { + gPCOptionOpen = 0; + puppycam_set_save(); + } + } + + if (gPCOptionOpen) + { + if (ABS(gPlayer1Controller->rawStickY) > 60 || gPlayer1Controller->buttonDown & U_JPAD || gPlayer1Controller->buttonDown & D_JPAD) + { + gPCOptionTimer -= 1; + if (gPCOptionTimer <= 0) + { + switch (gPCOptionIndex) + { + case 0: gPCOptionIndex++; gPCOptionTimer += 10; break; + default: gPCOptionTimer += 5; break; + } + play_sound(SOUND_MENU_CHANGE_SELECT, gGlobalSoundSource); + if (gPlayer1Controller->rawStickY >= 60 || gPlayer1Controller->buttonDown & U_JPAD) + { + gPCOptionSelected--; + if (gPCOptionSelected < 0) + gPCOptionSelected = gPCOptionCap-1; + } + else + if (gPlayer1Controller->rawStickY <= -60 || gPlayer1Controller->buttonDown & D_JPAD) + { + gPCOptionSelected++; + if (gPCOptionSelected >= gPCOptionCap) + gPCOptionSelected = 0; + } + } + } + else + if (ABS(gPlayer1Controller->rawStickX) > 60 || gPlayer1Controller->buttonDown & L_JPAD || gPlayer1Controller->buttonDown & R_JPAD) + { + gPCOptionTimer -= 1; + if (gPCOptionTimer <= 0) + { + switch (gPCOptionIndex) + { + case 0: gPCOptionIndex++; gPCOptionTimer += 10; break; + default: gPCOptionTimer += 5; break; + } + play_sound(SOUND_MENU_CHANGE_SELECT, gGlobalSoundSource); + if (gPlayer1Controller->rawStickX >= 60 || gPlayer1Controller->buttonDown & R_JPAD) + puppycam_change_setting(1); + else + if (gPlayer1Controller->rawStickX <= -60 || gPlayer1Controller->buttonDown & L_JPAD) + puppycam_change_setting(-1); + } + } + else + { + gPCOptionTimer = 0; + gPCOptionIndex = 0; + } + + while (gPCOptionScroll - gPCOptionSelected < -3 && gPCOptionSelected > gPCOptionScroll) + gPCOptionScroll +=1; + while (gPCOptionScroll + gPCOptionSelected > 0 && gPCOptionSelected < gPCOptionScroll) + gPCOptionScroll -=1; + } +} + +///CORE + +//Just a function that sets a bunch of camera values to 0. It's a function because it's got shared functionality. +void puppycam_reset_values(void) +{ + gPuppyCam.posHeight[0] = 0; + gPuppyCam.posHeight[1] = 0; + gPuppyCam.swimPitch = 0; + gPuppyCam.edgePitch = 0; + gPuppyCam.moveZoom = 0; + gPuppyCam.floorY[0] = 0; + gPuppyCam.floorY[1] = 0; +} + +//Set up values. Runs on level load. +void puppycam_init(void) +{ + if (gMarioState->marioObj) + gPuppyCam.targetObj = gMarioState->marioObj; + gPuppyCam.targetObj2 = NULL; + + gPuppyCam.intendedFlags = PUPPYCAM_BEHAVIOUR_DEFAULT; + + if (gCurrLevelNum == 27 || (gCurrLevelNum == 36 && gCurrAreaIndex == 2) || (gCurrLevelNum == 5 && gCurrAreaIndex == 2)) + gPuppyCam.intendedFlags |= PUPPYCAM_BEHAVIOUR_SLIDE_CORRECTION; + gPuppyCam.flags = gPuppyCam.intendedFlags; + gPuppyCam.zoom = gPuppyCam.zoomPoints[1]; + gPuppyCam.zoomSet = 1; + gPuppyCam.zoomTarget = gPuppyCam.zoom; + gPuppyCam.yaw = gMarioState->faceAngle[1]+0x8000; + gPuppyCam.yawTarget = gPuppyCam.yaw; + gPuppyCam.pitch = 0x3800; + gPuppyCam.pitchTarget = gPuppyCam.pitch; + gPuppyCam.yawAcceleration = 0; + gPuppyCam.pitchAcceleration = 0; + gPuppyCam.shakeFrames = 0; + gPuppyCam.shake[0] = 0; + gPuppyCam.shake[1] = 0; + gPuppyCam.shake[2] = 0; + gPuppyCam.pos[0] = 0; + gPuppyCam.pos[1] = 0; + gPuppyCam.pos[2] = 0; + gPuppyCam.focus[0] = 0; + gPuppyCam.focus[1] = 0; + gPuppyCam.focus[2] = 0; + gPuppyCam.pan[0] = 0; + gPuppyCam.pan[1] = 0; //gMarioState->pos[1]; + gPuppyCam.pan[2] = 0; + gPuppyCam.targetFloorHeight = gPuppyCam.pan[1]; + gPuppyCam.lastTargetFloorHeight = gMarioState->pos[1]; + gPuppyCam.opacity = 255; + gPuppyCam.framesSinceC[0] = 10; //This just exists to stop input type B being stupid. + gPuppyCam.framesSinceC[1] = 10; //This just exists to stop input type B being stupid. + gPuppyCam.mode3Flags = PUPPYCAM_MODE3_ZOOMED_MED; + puppycam_reset_values(); +} + +void puppycam_input_pitch(void) +{ + f32 ivY = ((gPuppyCam.options.invertY*2)-1)*(gPuppyCam.options.sensitivityY/100.f); + + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_PITCH_ROTATION) + { + //Handles vertical inputs. + if (gPlayer1Controller->buttonDown & U_CBUTTONS || gPuppyCam.stick2[1] != 0) + gPuppyCam.pitchAcceleration -= 50*(gPuppyCam.options.sensitivityY/100.f); + else + if (gPlayer1Controller->buttonDown & D_CBUTTONS || gPuppyCam.stick2[1] != 0) + gPuppyCam.pitchAcceleration += 50*(gPuppyCam.options.sensitivityY/100.f); + else + gPuppyCam.pitchAcceleration = approach_f32_asymptotic(gPuppyCam.pitchAcceleration, 0, DECELERATION); + + gPuppyCam.pitchAcceleration = CLAMP(gPuppyCam.pitchAcceleration, -100, 100); + + //When Mario's moving, his pitch is clamped pretty aggressively, so this exists so you can shift your view up and down momentarily at an actually usable range, rather than the otherwise baby range. + if (gMarioState->action & ACT_FLAG_MOVING && (gPuppyCam.pitch >= 0x3800 || gPuppyCam.pitch <= 0x2000)) + gPuppyCam.moveFlagAdd = 8; + } +} + +void puppycam_input_zoom(void) +{ + //Handles R button zooming. + if (gPlayer1Controller->buttonPressed & R_TRIG && gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_ZOOM_CHANGE) + { + gPuppyCam.zoomSet++; + + if (gPuppyCam.zoomSet >= 3) + gPuppyCam.zoomSet = 0; + + gPuppyCam.zoomTarget = gPuppyCam.zoomPoints[gPuppyCam.zoomSet]; + play_sound(SOUND_MENU_CLICK_CHANGE_VIEW,gGlobalSoundSource); + } +} + +void puppycam_input_centre(void) +{ + s32 inputDefault = L_TRIG; + if (gPuppyCam.options.inputType == 3) + inputDefault = R_TRIG; + //Handles L button centering. + if (gPlayer1Controller->buttonPressed & inputDefault && gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_YAW_ROTATION && + !(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_8DIR) && !(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_4DIR) && !(gPlayer1Controller->buttonDown & U_JPAD)) + { + gPuppyCam.yawTarget = gMarioState->faceAngle[1]+0x8000; + play_sound(SOUND_MENU_CLICK_CHANGE_VIEW,gGlobalSoundSource); + } +} + +//The default control scheme. Hold the button down to turn the camera, and double tap to turn quickly. +static void puppycam_input_hold_preset1(f32 ivX) +{ + if (!gPuppyCam.options.analogue && gPlayer1Controller->buttonPressed & L_CBUTTONS && gPuppyCam.framesSinceC[0] <= 5) + { + gPuppyCam.yawTarget -= 0x4000*ivX; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); + } + else + if (!gPuppyCam.options.analogue && gPlayer1Controller->buttonPressed & R_CBUTTONS && gPuppyCam.framesSinceC[1] <= 5) + { + gPuppyCam.yawTarget += 0x4000*ivX; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); + } + + if ((gPlayer1Controller->buttonDown & L_CBUTTONS && !gPuppyCam.options.analogue) || gPuppyCam.stick2[0] != 0) + { + gPuppyCam.yawAcceleration -= 50*(gPuppyCam.options.sensitivityX/100.f); + gPuppyCam.framesSinceC[0] = 0; + } + else + if ((gPlayer1Controller->buttonDown & R_CBUTTONS && !gPuppyCam.options.analogue) || gPuppyCam.stick2[0] != 0) + { + gPuppyCam.yawAcceleration += 50*(gPuppyCam.options.sensitivityX/100.f); + gPuppyCam.framesSinceC[1] = 0; + } + else + gPuppyCam.yawAcceleration = approach_f32_asymptotic(gPuppyCam.yawAcceleration, 0, DECELERATION); +} + +//An alternative control scheme, hold the button down to turn the camera, or press it once to turn it quickly. +static void puppycam_input_hold_preset2(f32 ivX) +{ + //These set the initial button press. + if (gPlayer1Controller->buttonPressed & L_CBUTTONS) + { + gPuppyCam.framesSinceC[0] = 0; + } + + if (gPlayer1Controller->buttonPressed & R_CBUTTONS) + { + gPuppyCam.framesSinceC[1] = 0; + } + + //These handle when you release the button + if ((!(gPlayer1Controller->buttonDown & L_CBUTTONS)) && gPuppyCam.framesSinceC[0] <= 5) + { + gPuppyCam.yawTarget -= 0x3000*ivX; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); + gPuppyCam.framesSinceC[0] = 6; + } + + if ((!(gPlayer1Controller->buttonDown & R_CBUTTONS)) && gPuppyCam.framesSinceC[1] <= 5) + { + gPuppyCam.yawTarget += 0x3000*ivX; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); + gPuppyCam.framesSinceC[1] = 6; + } + + //Handles continuous movement as normal, as long as the button's held. + if (gPlayer1Controller->buttonDown & L_CBUTTONS) + { + gPuppyCam.yawAcceleration -= 10*(gPuppyCam.options.sensitivityX/100.f); + } + else + if (gPlayer1Controller->buttonDown & R_CBUTTONS) + { + gPuppyCam.yawAcceleration += 10*(gPuppyCam.options.sensitivityX/100.f); + } + else + gPuppyCam.yawAcceleration = approach_f32_asymptotic(gPuppyCam.yawAcceleration, 0, DECELERATION); +} + +//Another alternative control scheme. This one aims to mimic the parallel camera scheme down to the last bit from the original game. +static void puppycam_input_hold_preset3(f32 ivX) +{ + f32 stickMag[2] = {gPlayer1Controller->rawStickX*0.65f, gPlayer1Controller->rawStickY*0.2f}; + //Just in case it happens to be nonzero. + gPuppyCam.yawAcceleration = 0; + + //In theory this shouldn't be necessary, but it's nice to cover all bases. + if (!(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_YAW_ROTATION)) + return; + + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_IN) + { + gPuppyCam.flags &= ~PUPPYCAM_BEHAVIOUR_COLLISION; + f32 ivY = ((gPuppyCam.options.invertY*2)-1)*(gPuppyCam.options.sensitivityY/100.f); + + //Handles continuous movement as normal, as long as the button's held. + if (ABS(gPlayer1Controller->rawStickX) > DEADZONE) + { + gPuppyCam.yawAcceleration -= (gPuppyCam.options.sensitivityX/100.f)*stickMag[0]; + } + else + gPuppyCam.yawAcceleration = approach_f32_asymptotic(gPuppyCam.yawAcceleration, 0, DECELERATION); + + if (ABS(gPlayer1Controller->rawStickY) > DEADZONE) + { + gPuppyCam.pitchAcceleration -= (gPuppyCam.options.sensitivityY/100.f)*stickMag[1]; + } + else + gPuppyCam.pitchAcceleration = approach_f32_asymptotic(gPuppyCam.pitchAcceleration, 0, DECELERATION); + } + else + { + if (gPlayer1Controller->buttonPressed & L_TRIG) + { + if (gPuppyCam.yawTarget % 0x2000) + gPuppyCam.yawTarget += 0x2000 - gPuppyCam.yawTarget % 0x2000; + } + + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_MED) + gPuppyCam.pitchTarget = approach_s32(gPuppyCam.pitchTarget, 0x3800, 0x200, 0x200); + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_OUT) + gPuppyCam.pitchTarget = approach_s32(gPuppyCam.pitchTarget, 0x3000, 0x200, 0x200); + + if (gPlayer1Controller->buttonPressed & L_CBUTTONS) + { + gPuppyCam.yawTarget -= 0x2000; + play_sound(SOUND_MENU_CAMERA_TURN,gGlobalSoundSource); + } + if (gPlayer1Controller->buttonPressed & R_CBUTTONS) + { + gPuppyCam.yawTarget += 0x2000; + play_sound(SOUND_MENU_CAMERA_TURN,gGlobalSoundSource); + } + } + + //Handles zooming in. Works just like vanilla. + if (gPlayer1Controller->buttonPressed & U_CBUTTONS) + { + if ((gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_MED) && !(gMarioState->action & ACT_FLAG_AIR) && !(gMarioState->action & ACT_FLAG_SWIMMING)) + { + gPuppyCam.mode3Flags |= PUPPYCAM_MODE3_ZOOMED_IN; + gPuppyCam.mode3Flags &= ~PUPPYCAM_MODE3_ZOOMED_MED; + gPuppyCam.zoomTarget = 200; + gPuppyCam.mode3Flags |= PUPPYCAM_MODE3_ENTER_FIRST_PERSON; + + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); + } + else + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_OUT) + { + gPuppyCam.mode3Flags |= PUPPYCAM_MODE3_ZOOMED_MED; + gPuppyCam.mode3Flags &= ~PUPPYCAM_MODE3_ZOOMED_OUT; + gPuppyCam.zoomTarget = gPuppyCam.zoomPoints[1]; + + play_sound(SOUND_MENU_CAMERA_ZOOM_IN, gGlobalSoundSource); + } + } + else //Otherwise handle zooming out. + if (gPlayer1Controller->buttonPressed & D_CBUTTONS) + { + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_MED) + { + gPuppyCam.mode3Flags |= PUPPYCAM_MODE3_ZOOMED_OUT; + gPuppyCam.mode3Flags &= ~PUPPYCAM_MODE3_ZOOMED_MED; + gPuppyCam.zoomTarget = gPuppyCam.zoomPoints[2]; + + play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); + } + } + if (gPlayer1Controller->buttonPressed & D_CBUTTONS || gPlayer1Controller->buttonPressed & B_BUTTON || gPlayer1Controller->buttonPressed & A_BUTTON) + { + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ZOOMED_IN) + { + gPuppyCam.mode3Flags |= PUPPYCAM_MODE3_ZOOMED_MED; + gPuppyCam.mode3Flags &= ~PUPPYCAM_MODE3_ZOOMED_IN; + gPuppyCam.zoomTarget = gPuppyCam.zoomPoints[1]; + gPuppyCam.mode3Flags &= ~PUPPYCAM_MODE3_ENTER_FIRST_PERSON; + + play_sound(SOUND_MENU_CAMERA_ZOOM_OUT, gGlobalSoundSource); + } + } +} + +//Handles C Button inputs for modes that have held inputs, rather than presses. +static void puppycam_input_hold(void) +{ + f32 ivX = ((gPuppyCam.options.invertX*2)-1)*(gPuppyCam.options.sensitivityX/100.f); + f32 ivY = ((gPuppyCam.options.invertY*2)-1)*(gPuppyCam.options.sensitivityY/100.f); + s8 stickMag[2] = {100, 100}; + + //Analogue Camera stuff. If it fails to find an input, then it just sets stickmag to 100, which after calculations means the value goes unchanged. + if (gPuppyCam.options.analogue && gPuppyCam.options.inputType != 2) + { + stickMag[0] = gPuppyCam.stick2[0]*1.25f; + stickMag[1] = gPuppyCam.stick2[1]*1.25f; + } + + //In theory this shouldn't be necessary, but it's nice to cover all bases. + if (!(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_YAW_ROTATION)) + return; + + if (!gPuppyCam.options.analogue) + { + switch (gPuppyCam.options.inputType) + { + default: puppycam_input_hold_preset1(ivX); puppycam_input_pitch(); puppycam_input_zoom(); puppycam_input_centre(); break; + case 1: puppycam_input_hold_preset2(ivX); puppycam_input_pitch(); puppycam_input_zoom(); puppycam_input_centre(); break; + case 2: puppycam_input_hold_preset3(ivX); puppycam_input_centre(); break; + } + } + else + { + puppycam_input_hold_preset1(ivX); + } + + gPuppyCam.framesSinceC[0]++; + gPuppyCam.framesSinceC[1]++; + + gPuppyCam.yawAcceleration = CLAMP(gPuppyCam.yawAcceleration, -100, 100); + + gPuppyCam.yawTarget += (12*gPuppyCam.yawAcceleration*ivX)*(stickMag[0]*0.01f); + gPuppyCam.pitchTarget += ((4+gPuppyCam.moveFlagAdd)*gPuppyCam.pitchAcceleration*ivY)*(stickMag[1]*0.01f); +} + +//Handles C Button inputs for modes that have pressed inputs, rather than held. +static void puppycam_input_press(void) +{ + f32 ivX = ((gPuppyCam.options.invertX*2)-1)*(gPuppyCam.options.sensitivityX/100.f); + f32 ivY = ((gPuppyCam.options.invertY*2)-1)*(gPuppyCam.options.sensitivityY/100.f); + s8 stickMag = 0; + + //Analogue Camera stuff. If it fails to find an input, then it just sets stickmag to 100, which after calculations means the value goes unchanged. + if (gPuppyCam.options.analogue) + stickMag = gPuppyCam.stick2[0]*1.25f; + else + stickMag = 100; + + //Just in case it happens to be nonzero. + gPuppyCam.yawAcceleration = 0; + + //In theory this shouldn't be necessary, but it's nice to cover all bases. + if (!(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_YAW_ROTATION)) + return; + + if ((gPlayer1Controller->buttonPressed & L_CBUTTONS && !gPuppyCam.options.analogue) || (gPuppyCam.stickN[0] == 0 && gPuppyCam.stick2[0] < -DEADZONE)) + { + gPuppyCam.stickN[0] = 1; + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_8DIR) + gPuppyCam.yawTarget -= 0x2000*ivX; + else + gPuppyCam.yawTarget -= 0x4000*ivX; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN,gGlobalSoundSource); + } + + if ((gPlayer1Controller->buttonPressed & R_CBUTTONS && !gPuppyCam.options.analogue) || (gPuppyCam.stickN[0] == 0 && gPuppyCam.stick2[0] > DEADZONE)) + { + gPuppyCam.stickN[0] = 1; + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_8DIR) + gPuppyCam.yawTarget += 0x2000*ivX; + else + gPuppyCam.yawTarget += 0x4000*ivX; + play_sound(SOUND_MENU_CAMERA_ZOOM_IN,gGlobalSoundSource); + } + puppycam_input_pitch(); + gPuppyCam.pitchTarget += ((4+gPuppyCam.moveFlagAdd)*gPuppyCam.pitchAcceleration*ivY)*(stickMag*0.01f); +} + +static void puppycam_view_panning(void) +{ + f32 panFloor, panMulti; + s32 expectedPanX, expectedPanZ; + s32 height = gPuppyCam.targetObj->oPosY; + s32 panEx = (gPuppyCam.zoomTarget >= 1000) * 250; //Removes the basic panning when idling if the zoom level is at the closest. + f32 slideSpeed = 1; + + panMulti = CLAMP(gPuppyCam.zoom/(f32)gPuppyCam.zoomPoints[2], 0.f, 1.f); + + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_PANSHIFT && gMarioState->action != ACT_HOLDING_BOWSER && gMarioState->action != ACT_SLEEPING && gMarioState->action != ACT_START_SLEEPING) + { + if (gMarioState->action & ACT_FLAG_BUTT_OR_STOMACH_SLIDE) + slideSpeed = 10; + + expectedPanX = LENSIN(panEx+(200*(gMarioState->forwardVel/32.f)), gMarioState->faceAngle[1])*panMulti; + expectedPanZ = LENCOS(panEx+(200*(gMarioState->forwardVel/32.f)), gMarioState->faceAngle[1])*panMulti; + + gPuppyCam.pan[0] = approach_f32_asymptotic(gPuppyCam.pan[0], expectedPanX, 0.02f*slideSpeed); + gPuppyCam.pan[2] = approach_f32_asymptotic(gPuppyCam.pan[2], expectedPanZ, 0.02f*slideSpeed); + if (gMarioState->vel[1] == 0.0f) + { + panFloor = CLAMP(find_floor_height((s16)(gPuppyCam.targetObj->oPosX+expectedPanX),(s16)(gPuppyCam.targetObj->oPosY + 200), + (s16)(gPuppyCam.targetObj->oPosZ+expectedPanZ)),gPuppyCam.targetObj->oPosY-50,gPuppyCam.targetObj->oPosY+50); + //If the floor is lower than 50 units below Mario, then ignore the Y value and tilt the camera instead. + if (panFloor <= gPuppyCam.targetObj->oPosY-50) + { + panFloor = gPuppyCam.targetObj->oPosY; + gPuppyCam.edgePitch = approach_s32(gPuppyCam.edgePitch, -0x500, 0x80, 0x80); + } + else + { + gPuppyCam.edgePitch = approach_s32(gPuppyCam.edgePitch, 0, 0x80, 0x80); + } + + gPuppyCam.pan[1] = approach_f32_asymptotic(gPuppyCam.pan[1], panFloor-height, 0.25f); + } + else + gPuppyCam.pan[1] = approach_f32_asymptotic(gPuppyCam.pan[1], 0, 0.5f); + } + else + { + gPuppyCam.pan[0] = 0; + gPuppyCam.pan[1] = 0; + gPuppyCam.pan[2] = 0; + } +} + +//Sets the +static void puppycam_view_height_offset(void) +{ + s16 floorTemp; + s16 tempDist = sqrtf((gPuppyCam.pos[0] - gPuppyCam.focus[0]) * (gPuppyCam.pos[0] - gPuppyCam.focus[0]) + (gPuppyCam.pos[1] - gPuppyCam.focus[1]) * + (gPuppyCam.pos[1] - gPuppyCam.focus[1]) + (gPuppyCam.pos[2] - gPuppyCam.focus[2]) * (gPuppyCam.pos[2] - gPuppyCam.focus[2])); + + floorTemp = find_floor_height(gPuppyCam.targetObj->oPosX, gPuppyCam.targetObj->oPosY+50, gPuppyCam.targetObj->oPosZ); + if (floorTemp > gPuppyCam.targetObj->oPosY - 50 && !(gMarioState->action & ACT_FLAG_SWIMMING_OR_FLYING)) + { + gPuppyCam.posHeight[0] = approach_f32_asymptotic(gPuppyCam.posHeight[0],floorTemp-gPuppyCam.targetFloorHeight,0.05f); + //if (gPuppyCam.posHeight[0]-gPuppyCam.shake[1] - gPuppyCam.floorY[1] < floorTemp) + // gPuppyCam.posHeight[0] = floorTemp-gPuppyCam.shake[1]+gPuppyCam.povHeight - gPuppyCam.floorY[1]; + } + else + { + gPuppyCam.posHeight[0] = approach_f32_asymptotic(gPuppyCam.posHeight[0],0,0.1f); + } + + + floorTemp = find_floor_height(gPuppyCam.targetObj->oPosX + LENSIN(tempDist,gPuppyCam.yaw), gPuppyCam.targetObj->oPosY+50, gPuppyCam.targetObj->oPosZ + LENCOS(tempDist,gPuppyCam.yaw)); + if (floorTemp > gPuppyCam.targetObj->oPosY - 50 && !(gMarioState->action & ACT_FLAG_SWIMMING_OR_FLYING) && gPuppyCam.collisionDistance != gPuppyCam.zoomTarget) + { + gPuppyCam.posHeight[1] = approach_f32_asymptotic(gPuppyCam.posHeight[1],floorTemp-gPuppyCam.targetFloorHeight,0.05f); + //if (gPuppyCam.posHeight[1]-gPuppyCam.shake[1] - gPuppyCam.floorY[0] < floorTemp) + // gPuppyCam.posHeight[1] = floorTemp-gPuppyCam.shake[1]+gPuppyCam.povHeight - gPuppyCam.floorY[0]; + } + else + { + gPuppyCam.posHeight[1] = approach_f32_asymptotic(gPuppyCam.posHeight[1],0,0.1f); + } +} + +/// Multiply vector 'dest' by a +void *vec3f_mul(Vec3f dest, f32 a) +{ + dest[0] *= a; + dest[1] *= a; + dest[2] *= a; + return dest; //! warning: function returns address of local variable +} + +/// Get length of vector 'a' +f32 vec3f_length(Vec3f a) +{ + return sqrtf(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]); +} + +/// Get dot product of vectors 'a' and 'b' +f32 vec3f_dot(Vec3f a, Vec3f b) +{ + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; +} + +/// Make 'dest' the difference of vectors a and b. +void *vec3f_dif(Vec3f dest, Vec3f a, Vec3f b) { + dest[0] = a[0] - b[0]; + dest[1] = a[1] - b[1]; + dest[2] = a[2] - b[2]; + return dest; //! warning: function returns address of local variable +} + +//Raycasting +s32 ray_surface_intersect(Vec3f orig, Vec3f dir, f32 dir_length, struct Surface *surface, Vec3f hit_pos, f32 *length) +{ + Vec3f v0, v1, v2, e1, e2, h, s, q; + f32 a, f, u, v; + Vec3f add_dir; + Vec3f norm; + + //Ignore certain surface types. + if (surface->type == SURFACE_INTANGIBLE || surface->flags & SURFACE_FLAG_NO_CAM_COLLISION) + return FALSE; + + // Get surface normal and some other stuff + norm[0] = 0; + norm[1] = surface->normal.y; + norm[2] = 0; + vec3f_mul(norm,OFFSET); + + vec3s_to_vec3f(v0, surface->vertex1); + vec3s_to_vec3f(v1, surface->vertex2); + vec3s_to_vec3f(v2, surface->vertex3); + + vec3f_add(v0, norm); + vec3f_add(v1, norm); + vec3f_add(v2, norm); + + vec3f_dif(e1, v1, v0); + vec3f_dif(e2, v2, v0); + + vec3f_cross(h, dir, e2); + + // Check if we're perpendicular from the surface + a = vec3f_dot(e1, h); + if (a > -0.00001f && a < 0.00001f) + return FALSE; + + // Check if we're making contact with the surface + f = 1.0f / a; + + vec3f_dif(s, orig, v0); + u = f * vec3f_dot(s, h); + if (u < 0.0f || u > 1.0f) + return FALSE; + + vec3f_cross(q, s, e1); + v = f * vec3f_dot(dir, q); + if (v < 0.0f || u + v > 1.0f) + return FALSE; + + // Get the length between our origin and the surface contact point + *length = f * vec3f_dot(e2, q); + if (*length <= 0.00001 || *length > dir_length) + return FALSE; + + // Successful contact + vec3f_copy(add_dir, dir); + vec3f_mul(add_dir, *length); + vec3f_sum(hit_pos, orig, add_dir); + return TRUE; +} + +void find_surface_on_ray_list(struct SurfaceNode *list, Vec3f orig, Vec3f dir, f32 dir_length, struct Surface **hit_surface, Vec3f hit_pos, f32 *max_length) +{ + s32 hit; + f32 length; + Vec3f chk_hit_pos; + f32 top, bottom; + + // Get upper and lower bounds of ray + if (dir[1] >= 0.0f) + { + top = orig[1] + dir[1] * dir_length; + bottom = orig[1]; + } + else + { + top = orig[1]; + bottom = orig[1] + dir[1] * dir_length; + } + + // Iterate through every surface of the list + for (; list != NULL; list = list->next) + { + // Reject surface if out of vertical bounds + if (list->surface->lowerY > top || list->surface->upperY < bottom) + continue; + + // Check intersection between the ray and this surface + if ((hit = ray_surface_intersect(orig, dir, dir_length, list->surface, chk_hit_pos, &length)) != 0) + { + if (length <= *max_length) + { + *hit_surface = list->surface; + vec3f_copy(hit_pos, chk_hit_pos); + *max_length = length; + } + } + } +} + + +void find_surface_on_ray_cell(s16 cellX, s16 cellZ, Vec3f orig, Vec3f normalized_dir, f32 dir_length, struct Surface **hit_surface, Vec3f hit_pos, f32 *max_length) +{ + // Skip if OOB + if (cellX >= 0 && cellX <= (NUM_CELLS - 1) && cellZ >= 0 && cellZ <= (NUM_CELLS - 1)) + { + // Iterate through each surface in this partition + if (normalized_dir[1] > -0.99999f) + { + find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_CEILS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + } + if (normalized_dir[1] < 0.99999f) + { + find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_FLOORS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + } + find_surface_on_ray_list(gStaticSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + find_surface_on_ray_list(gDynamicSurfacePartition[cellZ][cellX][SPATIAL_PARTITION_WALLS].next, orig, normalized_dir, dir_length, hit_surface, hit_pos, max_length); + } +} + +void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos) +{ + f32 max_length; + s16 cellZ, cellX, cellPrevX, cellPrevZ; + f32 fCellZ, fCellX; + f32 dir_length; + Vec3f normalized_dir; + f32 step, dx, dz; + u32 i; + + // Set that no surface has been hit + *hit_surface = NULL; + vec3f_sum(hit_pos, orig, dir); + + // Get normalized direction + dir_length = vec3f_length(dir); + max_length = dir_length; + vec3f_copy(normalized_dir, dir); + vec3f_normalize(normalized_dir); + + // Get our cell coordinate + fCellX = (orig[0] + LEVEL_BOUNDARY_MAX) / CELL_SIZE; + fCellZ = (orig[2] + LEVEL_BOUNDARY_MAX) / CELL_SIZE; + cellX = (s16)fCellX; + cellZ = (s16)fCellZ; + + // Don't do DDA if straight down + if (normalized_dir[1] >= 0.99999f || normalized_dir[1] <= -0.99999f) + { + find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length); + return; + } + + // Get cells we cross using DDA + if (ABS(dir[0]) >= ABS(dir[2])) + step = STEPS*ABS(dir[0]) / CELL_SIZE; + else + step = STEPS*ABS(dir[2]) / CELL_SIZE; + + dx = dir[0] / step / CELL_SIZE; + dz = dir[2] / step / CELL_SIZE; + + for (i = 0; i < step && *hit_surface == NULL; i++) + { + find_surface_on_ray_cell(cellX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length); + + // Move cell coordinate + fCellX += dx; + fCellZ += dz; + cellPrevX = cellX; + cellPrevZ = cellZ; + cellX = (s16)fCellX; + cellZ = (s16)fCellZ; + + if ((cellPrevX != cellX) && (cellPrevZ != cellZ)) + { + find_surface_on_ray_cell(cellX, cellPrevZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length); + find_surface_on_ray_cell(cellPrevX, cellZ, orig, normalized_dir, dir_length, hit_surface, hit_pos, &max_length); + } + } +} + +const struct sPuppyAngles puppyAnglesNull = +{ + {PUPPY_NULL, PUPPY_NULL, PUPPY_NULL}, + {PUPPY_NULL, PUPPY_NULL, PUPPY_NULL}, + {PUPPY_NULL}, + {PUPPY_NULL}, + {PUPPY_NULL}, +}; + +//Checks the bounding box of a puppycam volume. If it's inside, then set the pointer to the current index. +static s32 puppycam_check_volume_bounds(struct sPuppyVolume *volume, s32 index) +{ + s32 rel[3]; + s32 pos[2]; + f32 distCheck; + + if (sPuppyVolumeStack[index]->room != gMarioCurrentRoom && sPuppyVolumeStack[index]->room != -1) + return FALSE; + + if (sPuppyVolumeStack[index]->shape == PUPPYVOLUME_SHAPE_BOX) + { + //Fetch the relative position. to the triggeree. + rel[0] = sPuppyVolumeStack[index]->pos[0] - gPuppyCam.targetObj->oPosX; + rel[1] = sPuppyVolumeStack[index]->pos[1] - gPuppyCam.targetObj->oPosY; + rel[2] = sPuppyVolumeStack[index]->pos[2] - gPuppyCam.targetObj->oPosZ; + //Use the dark, forbidden arts of trig to rotate the volume. + pos[0] = rel[2] * sins(sPuppyVolumeStack[index]->rot) + rel[0] * coss(sPuppyVolumeStack[index]->rot); + pos[1] = rel[2] * coss(sPuppyVolumeStack[index]->rot) - rel[0] * sins(sPuppyVolumeStack[index]->rot); + + //Now compare values. + if (-sPuppyVolumeStack[index]->radius[0] < pos[0] && pos[0] < sPuppyVolumeStack[index]->radius[0] && + -sPuppyVolumeStack[index]->radius[1] < rel[1] && rel[1] < sPuppyVolumeStack[index]->radius[1] && + -sPuppyVolumeStack[index]->radius[2] < pos[1] && pos[1] < sPuppyVolumeStack[index]->radius[2]) + { + *volume = *sPuppyVolumeStack[index]; + return TRUE; + } + } + else + if (sPuppyVolumeStack[index]->shape == PUPPYVOLUME_SHAPE_CYLINDER) + { + s16 dir; + f32 dist; + rel[0] = sPuppyVolumeStack[index]->pos[0] - gPuppyCam.targetObj->oPosX; + rel[1] = sPuppyVolumeStack[index]->pos[1] - gPuppyCam.targetObj->oPosY; + rel[2] = sPuppyVolumeStack[index]->pos[2] - gPuppyCam.targetObj->oPosZ; + dist = sqrtf((rel[0] * rel[0]) + (rel[2] * rel[2])); + + distCheck = (dist < sPuppyVolumeStack[index]->radius[0]); + + if (-sPuppyVolumeStack[index]->radius[1] < rel[1] && rel[1] < sPuppyVolumeStack[index]->radius[1] && distCheck) + { + *volume = *sPuppyVolumeStack[index]; + return TRUE; + } + + } + + return FALSE; +} + +void puppycam_projection_behaviours(void) +{ + f32 turnRate = 1; + + //This will only be executed if Mario's the target. If it's not, it'll reset the + if (gPuppyCam.targetObj = gMarioState->marioObj) + { + if (gPuppyCam.options.turnAggression > 0 && gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_TURN_HELPER && !(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_8DIR) && + gMarioState->vel[1] == 0.0f && !(gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_4DIR) && gPuppyCam.options.inputType != 2) + {//Holy hell this is getting spicy. + //With turn aggression enabled, or if Mario's sliding, adjust the camera view behind mario. + if (gPuppyCam.options.turnAggression > 0 || gMarioState->action & ACT_FLAG_BUTT_OR_STOMACH_SLIDE) + { + if (gMarioState->action & ACT_FLAG_BUTT_OR_STOMACH_SLIDE) + turnRate = 4; //If he's sliding, do it 4x as fast. + //The deal here, is if Mario's moving, or he's sliding and the camera's within 90 degrees behind him, it'll auto focus behind him, with an intensity based on the camera's centre speed. + //It also scales with forward velocity, so it's a gradual effect as he speeds up. + if ((ABS(gPlayer1Controller->rawStickX) > 20 && !(gMarioState->action & ACT_FLAG_BUTT_OR_STOMACH_SLIDE)) || + (gMarioState->action & ACT_FLAG_BUTT_OR_STOMACH_SLIDE && + (s16)ABS(((gPuppyCam.yaw + 0x8000) % 0xFFFF - 0x8000) - ((gMarioState->faceAngle[1]) % 0xFFFF - 0x8000)) < 0x3000 )) + gPuppyCam.yawTarget = gMarioState->faceAngle[1]+0x8000 - approach_s32((s16)(gMarioState->faceAngle[1]+0x8000 - gPuppyCam.yawTarget), 0, + ((gPuppyCam.options.turnAggression*10)*ABS(gMarioState->forwardVel/32) * ABS(gPlayer1Controller->rawStickX/80.0f)*turnRate), + ((gPuppyCam.options.turnAggression*10)*ABS(gMarioState->forwardVel/32) * ABS(gPlayer1Controller->rawStickX/80.0f)*turnRate)); + } + } + else + { //If none of the above is true, it'll attempt to do this instead. + //If the camera's in these modes, snap the yaw to prevent desync. + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_8DIR) + { + if (gPuppyCam.yawTarget % 0x2000) + gPuppyCam.yawTarget += 0x2000 - gPuppyCam.yawTarget % 0x2000; + } + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_4DIR) + { + if (gPuppyCam.yawTarget % 0x4000) + gPuppyCam.yawTarget += 0x4000 - gPuppyCam.yawTarget % 0x4000; + } + } + + //This is the base floor height when stood on the ground. It's used to set a baseline for where the camera sits while Mario remains a height from this point, so it keeps a consistent motion. + gPuppyCam.targetFloorHeight = CLAMP(find_floor_height(gPuppyCam.targetObj->oPosX, gPuppyCam.targetObj->oPosY, gPuppyCam.targetObj->oPosZ), gPuppyCam.targetObj->oPosY-350, gPuppyCam.targetObj->oPosY+300); + + if (gMarioState->vel[1] <= 0.0f) + gPuppyCam.lastTargetFloorHeight = CLAMP(approach_f32_asymptotic(gPuppyCam.lastTargetFloorHeight,gPuppyCam.targetFloorHeight, 0.1f), gPuppyCam.targetObj->oPosY-350, gPuppyCam.targetObj->oPosY+300); + + if (gMarioState->action == ACT_SLEEPING || gMarioState->action == ACT_START_SLEEPING) + gPuppyCam.zoom = approach_f32_asymptotic(gPuppyCam.zoom,gPuppyCam.zoomPoints[0],0.01f); + else + if (gMarioState->action & ACT_FLAG_SWIMMING && gMarioState->waterLevel-100 - gMarioState->pos[1] > 5) + { + //When moving underwater, the camera will zoom in on Mayro. + gPuppyCam.zoom = approach_f32_asymptotic(gPuppyCam.zoom, MAX(gPuppyCam.zoomTarget/1.5f, gPuppyCam.zoomPoints[0]), 0.2f); + } + else + gPuppyCam.zoom = approach_f32_asymptotic(gPuppyCam.zoom,gPuppyCam.zoomTarget,0.2f); + + //Attempts at automatic adjustment that only apply when moving or jumping. + if (gMarioState->action & ACT_FLAG_MOVING || gMarioState->action & ACT_FLAG_AIR || (gMarioState->action & ACT_FLAG_SWIMMING && !gMarioState->waterLevel-100 - gMarioState->pos[1] > 5 && gMarioState->forwardVel != 0.0f)) + { + //Clamp the height when moving. You can still look up and down to a reasonable degree but it readjusts itself the second you let go. + if (gPuppyCam.pitchTarget > 0x3800) + gPuppyCam.pitchTarget = approach_f32_asymptotic(gPuppyCam.pitchTarget, 0x3800, 0.2f); + + if (gPuppyCam.pitchTarget < 0x2000) + gPuppyCam.pitchTarget = approach_f32_asymptotic(gPuppyCam.pitchTarget, 0x2000, 0.2f); + + /*//Will tilt the camera just a wip thing though, doesn't work too well but will hopefully replace view_height_offset eventually. + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_HEIGHT_HELPER && gMarioState->floor && gMarioState->action & ACT_FLAG_MOVING) + gPuppyCam.terrainPitch = approach_f32_asymptotic(gPuppyCam.terrainPitch, find_floor_slope(gMarioState, 0), (gMarioState->intendedMag/32)*0.2); + else + gPuppyCam.terrainPitch = approach_f32_asymptotic(gPuppyCam.terrainPitch, 0, 0.2);*/ + } + + //Applies a light outward zoom to the camera when moving. Sets it back to 0 when not moving. + if (gMarioState->forwardVel > 0) + { + gPuppyCam.moveZoom = approach_f32(gPuppyCam.moveZoom, 100.0f*(gMarioState->forwardVel/32.0f), gMarioState->forwardVel/10, gMarioState->forwardVel/10); + } + else + { + gPuppyCam.moveZoom = approach_f32(gPuppyCam.moveZoom, 0, 5, 5); + } + + //Zooms the camera in further when underwater. + if (gPuppyCam.pitch > 0x38C0 && ABS(gPuppyCam.swimPitch) < 100) + { + gPuppyCam.zoom = approach_f32_asymptotic((f32)gPuppyCam.zoom, 250.0f, CLAMP((f32)((gPuppyCam.pitch-0x38C0)/3072.0f), 0.0f, 1.0f)); + } + + if (!(gMarioState->action & ACT_FLAG_SWIMMING)) + { + gPuppyCam.floorY[0] = CLAMP(gPuppyCam.targetObj->oPosY - gPuppyCam.lastTargetFloorHeight, 0, 300); + gPuppyCam.floorY[1] = CLAMP(gPuppyCam.targetObj->oPosY - gPuppyCam.lastTargetFloorHeight, 0, 350); + gPuppyCam.swimPitch = approach_f32_asymptotic(gPuppyCam.swimPitch,0,0.2f); + } + else + { + gPuppyCam.floorY[0] = 0; + gPuppyCam.floorY[1] = 0; + gPuppyCam.targetFloorHeight = gPuppyCam.targetObj->oPosY; + gPuppyCam.lastTargetFloorHeight = gPuppyCam.targetObj->oPosY; + gPuppyCam.yawTarget = gMarioState->faceAngle[1]+0x8000 - approach_s32((s16)(gMarioState->faceAngle[1]+0x8000 - gPuppyCam.yawTarget), 0, + 1000*(gMarioState->forwardVel/32), 1000*(gMarioState->forwardVel/32)); + if (gMarioState->waterLevel-100 - gMarioState->pos[1] > 5 && gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_PITCH_ROTATION) + gPuppyCam.swimPitch = approach_f32_asymptotic(gPuppyCam.swimPitch,gMarioState->faceAngle[0]/10,0.05f); + else + gPuppyCam.swimPitch = approach_f32_asymptotic(gPuppyCam.swimPitch,0,0.2f); + } + + //This sets the view offset from Mario. It accentuates a bit further when moving. + puppycam_view_panning(); + + //This sets a pseudo tilt offset based on the floor heights in front and behind mario. + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_HEIGHT_HELPER) + { + puppycam_view_height_offset(); + } + else + { + gPuppyCam.posHeight[0] = 0; + gPuppyCam.posHeight[1] = 0; + } + } + else + { + puppycam_reset_values(); + } +} + +void puppycam_shake(s16 x, s16 y, s16 z) +{ + +} + +///This is the highest level of the basic steps that go into the code. Anything above is called from these following functions. + +//The centrepiece behind the input side of PuppyCam. The C buttons branch off. +static void puppycam_input_core(void) +{ + s32 stickMag = 0; + + puppycam_analogue_stick(); + gPuppyCam.moveFlagAdd = 0; + + if (gPuppyCam.options.analogue) + stickMag = gPuppyCam.stick2[1]*1.25f; + else + stickMag = 100; + + //Decide which input for left and right C buttons to use based on behaviour type. + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_NORMAL) + puppycam_input_hold(); + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_8DIR || gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_INPUT_4DIR) + puppycam_input_press(); +} + +//Calculates the base position the camera should be, before any modification. +static void puppycam_projection(void) +{ + Vec3s targetPos, targetPos2, targetPos3; + s16 pitchTotal; + s32 panD = (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_PANSHIFT)/8192; + + //Extra behaviours that get tacked onto the projection. Will be completely ignored if there is no target object. + puppycam_projection_behaviours(); + //These are what the base rotations aspire to be. + gPuppyCam.pitch = CLAMP(gPuppyCam.pitch,0x1000,0x7000); + gPuppyCam.pitchTarget = CLAMP(gPuppyCam.pitchTarget,0x1000,0x7000); + //These are the base rotations going to be used. + gPuppyCam.yaw = gPuppyCam.yawTarget - approach_f32_asymptotic((s16)(gPuppyCam.yawTarget - gPuppyCam.yaw), 0, 0.3335f); + gPuppyCam.pitch = gPuppyCam.pitchTarget - approach_f32_asymptotic((s16)(gPuppyCam.pitchTarget - gPuppyCam.pitch), 0, 0.3335f); + //This adds the pitch effect when underwater, which is capped so it doesn't get out of control. If you're not swimming, swimpitch is 0, so it's normal. + pitchTotal = CLAMP(gPuppyCam.pitch+(gPuppyCam.swimPitch*10)+gPuppyCam.edgePitch, 800, 0x7800); + + if (gPuppyCam.targetObj) + { + vec3s_set(targetPos, gPuppyCam.targetObj->oPosX, gPuppyCam.targetObj->oPosY, gPuppyCam.targetObj->oPosZ); + vec3s_copy(targetPos3, targetPos); + if (gPuppyCam.targetObj2) + { + vec3s_set(targetPos2, gPuppyCam.targetObj2->oPosX, gPuppyCam.targetObj2->oPosY, gPuppyCam.targetObj2->oPosZ); + targetPos3[0] = (s16)approach_f32_asymptotic(targetPos[0], targetPos2[0], 0.5f); + targetPos3[1] = (s16)approach_f32_asymptotic(targetPos[1], targetPos2[1], 0.5f); + targetPos3[2] = (s16)approach_f32_asymptotic(targetPos[2], targetPos2[2], 0.5f); + gPuppyCam.targetDist[0] = approach_f32_asymptotic(gPuppyCam.targetDist[0],(ABS(LENCOS(sqrtf(((targetPos[0]-targetPos2[0])*(targetPos[0]-targetPos2[0]))+((targetPos[2]-targetPos2[2])*(targetPos[2]-targetPos2[2]))), + (s16)ABS(((gPuppyCam.yaw + 0x8000) % 0xFFFF - 0x8000) - (atan2s(targetPos[2]-targetPos2[2], targetPos[0]-targetPos2[0])) % 0xFFFF - 0x8000)+0x4000))), 0.2f); + } + else + { + gPuppyCam.targetDist[0] = approach_f32_asymptotic(gPuppyCam.targetDist[0], 0, 0.2f); + } + + gPuppyCam.targetDist[1] = gPuppyCam.targetDist[0] + gPuppyCam.zoom+gPuppyCam.moveZoom; + + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_X_MOVEMENT) + gPuppyCam.focus[0] = targetPos3[0] + gPuppyCam.shake[0] + (gPuppyCam.pan[0]*gPuppyCam.targetDist[1]/gPuppyCam.zoomPoints[2])*panD; + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_Y_MOVEMENT) + gPuppyCam.focus[1] = targetPos3[1] + gPuppyCam.shake[1] + (gPuppyCam.pan[1]*gPuppyCam.targetDist[1]/gPuppyCam.zoomPoints[2]) + gPuppyCam.povHeight - gPuppyCam.floorY[0] + gPuppyCam.posHeight[0] + (gPuppyCam.swimPitch/10); + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_Z_MOVEMENT) + gPuppyCam.focus[2] = targetPos3[2] + gPuppyCam.shake[2] + (gPuppyCam.pan[2]*gPuppyCam.targetDist[1]/gPuppyCam.zoomPoints[2])*panD; + + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_X_MOVEMENT) + gPuppyCam.pos[0] = gPuppyCam.targetObj->oPosX + LENSIN(LENSIN(gPuppyCam.targetDist[1],pitchTotal),gPuppyCam.yaw) + gPuppyCam.shake[0]; + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_Y_MOVEMENT) + gPuppyCam.pos[1] = gPuppyCam.targetObj->oPosY + gPuppyCam.povHeight + LENCOS(gPuppyCam.targetDist[1],pitchTotal) + gPuppyCam.shake[1] - gPuppyCam.floorY[1] + gPuppyCam.posHeight[1]; + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_Z_MOVEMENT) + gPuppyCam.pos[2] = gPuppyCam.targetObj->oPosZ + LENCOS(LENSIN(gPuppyCam.targetDist[1],pitchTotal),gPuppyCam.yaw) + gPuppyCam.shake[2]; + } + +} + +//Calls any scripts to affect the camera, if applicable. +static void puppycam_script(void) +{ + u16 i = 0; + struct sPuppyVolume volume; + void (*func)(); + + if (gPuppyVolumeCount == 0 || !gPuppyCam.targetObj) + return; + + for (i = 0; i < gPuppyVolumeCount; i++) + { + if (puppycam_check_volume_bounds(&volume, i)) + { + //First applies pos and focus, for the most basic of volumes. + if (volume.angles != NULL) + { + if (volume.angles->pos[0] != PUPPY_NULL) + gPuppyCam.pos[0] = volume.angles->pos[0]; + if (volume.angles->pos[1] != PUPPY_NULL) + gPuppyCam.pos[1] = volume.angles->pos[1]; + if (volume.angles->pos[2] != PUPPY_NULL) + gPuppyCam.pos[2] = volume.angles->pos[2]; + + if (volume.angles->focus[0] != PUPPY_NULL) + gPuppyCam.focus[0] = volume.angles->focus[0]; + if (volume.angles->focus[1] != PUPPY_NULL) + gPuppyCam.focus[1] = volume.angles->focus[1]; + if (volume.angles->focus[2] != PUPPY_NULL) + gPuppyCam.focus[2] = volume.angles->focus[2]; + + if (volume.angles->yaw != PUPPY_NULL) + { + gPuppyCam.yawTarget = volume.angles->yaw; + gPuppyCam.yaw = volume.angles->yaw; + + gPuppyCam.flags &= ~PUPPYCAM_BEHAVIOUR_YAW_ROTATION; + } + + if (volume.angles->pitch != PUPPY_NULL) + { + gPuppyCam.pitchTarget = volume.angles->pitch; + gPuppyCam.pitch = volume.angles->pitch; + + gPuppyCam.flags &= ~PUPPYCAM_BEHAVIOUR_PITCH_ROTATION; + } + + if (volume.angles->zoom != PUPPY_NULL) + { + gPuppyCam.zoomTarget = volume.angles->zoom; + gPuppyCam.zoom = gPuppyCam.zoomTarget; + + gPuppyCam.flags &= ~PUPPYCAM_BEHAVIOUR_ZOOM_CHANGE; + } + } + + //Adds and removes behaviour flags, as set. + if (volume.flagsRemove) + gPuppyCam.flags &= ~volume.flagsRemove; + if (volume.flagsAdd) + gPuppyCam.flags |= volume.flagsAdd; + if (volume.flagPersistance == PUPPYCAM_BEHAVIOUR_PERMANENT) + { + //Adds and removes behaviour flags, as set. + if (volume.flagsRemove) + gPuppyCam.intendedFlags &= ~volume.flagsRemove; + if (volume.flagsAdd) + gPuppyCam.intendedFlags |= volume.flagsAdd; + } + + //Last and probably least, check if there's a function attached, and call it, if so. + if (volume.func) + { + func = volume.func; + (func)(); + } + } + } +} + +//Handles collision detection using ray casting. +static void puppycam_collision(void) +{ + struct Surface *surf[2]; + Vec3f camdir[2]; + Vec3f hitpos[2]; + Vec3f target[2]; + s16 pitchTotal = CLAMP(gPuppyCam.pitch+(gPuppyCam.swimPitch*10), 800, 0x7800); + s32 dist[2]; + + if (gPuppyCam.targetObj == NULL) + return; + + //The ray, starting from the top + target[0][0] = gPuppyCam.targetObj->oPosX; + target[0][1] = gPuppyCam.targetObj->oPosY + (gPuppyCam.povHeight) - CLAMP(gPuppyCam.targetObj->oPosY - gPuppyCam.targetFloorHeight, 0, 300); + target[0][2] = gPuppyCam.targetObj->oPosZ; + //The ray, starting from the bottom + target[1][0] = gPuppyCam.targetObj->oPosX; + target[1][1] = gPuppyCam.targetObj->oPosY + (gPuppyCam.povHeight *0.4f); + target[1][2] = gPuppyCam.targetObj->oPosZ; + + camdir[0][0] = LENSIN(LENSIN(gPuppyCam.zoomTarget,pitchTotal),gPuppyCam.yaw) + gPuppyCam.shake[0]; + camdir[0][1] = LENCOS(gPuppyCam.zoomTarget,pitchTotal) + gPuppyCam.shake[1];// + gPuppyCam.posHeight[1]; + camdir[0][2] = LENCOS(LENSIN(gPuppyCam.zoomTarget,pitchTotal),gPuppyCam.yaw) + gPuppyCam.shake[2]; + + camdir[1][0] = camdir[0][0]; + camdir[1][1] = camdir[0][1]; + camdir[1][2] = camdir[0][2]; + + find_surface_on_ray(target[0], camdir[0], &surf[0], hitpos[0]); + find_surface_on_ray(target[1], camdir[1], &surf[1], hitpos[1]); + resolve_and_return_wall_collisions(hitpos[0], 0.0f, 50.0f); + resolve_and_return_wall_collisions(hitpos[1], 0.0f, 50.0f); + dist[0] = ((target[0][0] - hitpos[0][0]) * (target[0][0] - hitpos[0][0]) + (target[0][1] - hitpos[0][1]) * (target[0][1] - hitpos[0][1]) + (target[0][2] - hitpos[0][2]) * (target[0][2] - hitpos[0][2])); + dist[1] = ((target[1][0] - hitpos[1][0]) * (target[1][0] - hitpos[1][0]) + (target[1][1] - hitpos[1][1]) * (target[1][1] - hitpos[1][1]) + (target[1][2] - hitpos[1][2]) * (target[1][2] - hitpos[1][2])); + + + gPuppyCam.collisionDistance = gPuppyCam.zoomTarget; + + if (surf[0] && surf[1]) + { + gPuppyCam.collisionDistance = sqrtf(MAX(dist[0], dist[1])); + if (gPuppyCam.zoom > gPuppyCam.collisionDistance) + { + gPuppyCam.zoom = MIN(gPuppyCam.collisionDistance, gPuppyCam.zoomTarget); + if (gPuppyCam.zoom - gPuppyCam.zoomTarget < 5) + { + if (dist[0] >= dist[1]) + { + gPuppyCam.pos[0] = hitpos[0][0]; + gPuppyCam.pos[1] = hitpos[0][1]; + gPuppyCam.pos[2] = hitpos[0][2]; + } + else + { + gPuppyCam.pos[0] = hitpos[1][0]; + gPuppyCam.pos[1] = hitpos[1][1] + (gPuppyCam.povHeight*0.6f); + gPuppyCam.pos[2] = hitpos[1][2]; + } + } + } + } + + #define START_DIST 500 + #define END_DIST 250 + gPuppyCam.opacity = CLAMP((f32)(((gPuppyCam.zoom-END_DIST)/255.0f)*(START_DIST-END_DIST)), 0, 255); +} + +extern Vec3f sOldPosition; +extern Vec3f sOldFocus; +extern struct PlayerGeometry sMarioGeometry; + +//Applies the PuppyCam values to the actual game's camera, giving the final product. +static void puppycam_apply(void) +{ + vec3f_set(gLakituState.pos, (f32)gPuppyCam.pos[0], (f32)gPuppyCam.pos[1], (f32)gPuppyCam.pos[2]); + vec3f_set(gLakituState.goalPos, (f32)gPuppyCam.pos[0], (f32)gPuppyCam.pos[1], (f32)gPuppyCam.pos[2]); + vec3f_set(gLakituState.curPos, (f32)gPuppyCam.pos[0], (f32)gPuppyCam.pos[1], (f32)gPuppyCam.pos[2]); + vec3f_set(gCamera->pos, (f32)gPuppyCam.pos[0], (f32)gPuppyCam.pos[1], (f32)gPuppyCam.pos[2]); + vec3f_set(sOldPosition, (f32)gPuppyCam.pos[0], (f32)gPuppyCam.pos[1], (f32)gPuppyCam.pos[2]); + + vec3f_set(gLakituState.focus, (f32)gPuppyCam.focus[0], (f32)gPuppyCam.focus[1], (f32)gPuppyCam.focus[2]); + vec3f_set(gLakituState.goalFocus, (f32)gPuppyCam.focus[0], (f32)gPuppyCam.focus[1], (f32)gPuppyCam.focus[2]); + vec3f_set(gLakituState.curFocus, (f32)gPuppyCam.focus[0], (f32)gPuppyCam.focus[1], (f32)gPuppyCam.focus[2]); + vec3f_set(gCamera->focus, (f32)gPuppyCam.focus[0], (f32)gPuppyCam.focus[1], (f32)gPuppyCam.focus[2]); + vec3f_set(sOldFocus, (f32)gPuppyCam.focus[0], (f32)gPuppyCam.focus[1], (f32)gPuppyCam.focus[2]); + + gCamera->yaw = gPuppyCam.yaw; + gCamera->nextYaw = gPuppyCam.yaw; + + gLakituState.yaw = gPuppyCam.yaw; + gLakituState.nextYaw = gPuppyCam.yaw; + gLakituState.oldYaw = gPuppyCam.yaw; + + gLakituState.mode = gCamera->mode; + gLakituState.defMode = gCamera->defMode; + gLakituState.roll = approach_s32(gLakituState.roll, 0, 0x80, 0x80); + + //Commented out simply because vanilla SM64 has this always set sometimes, and relies on certain camera modes to apply secondary foci. + //Uncomment to have fun with certain angles. + /*if (gSecondCameraFocus != NULL) + { + gPuppyCam.targetObj2 = gSecondCameraFocus; + } + else + { + gPuppyCam.targetObj2 = NULL; + }*/ + + if (gMarioState->floor != NULL) + { + sMarioGeometry.currFloor = gMarioState->floor; + sMarioGeometry.currFloorHeight = gMarioState->floorHeight; + sMarioGeometry.currFloorType = gMarioState->floor->type; + } + + if (gMarioState->ceil != NULL) + { + sMarioGeometry.currCeil = gMarioState->ceil; + sMarioGeometry.currCeilHeight = gMarioState->ceilHeight; + sMarioGeometry.currCeilType = gMarioState->ceil->type; + } +} + +//The basic loop sequence, which is called outside. +void puppycam_loop(void) +{ + if (!gPuppyCam.cutscene && sDelayedWarpOp == 0) + { + //Sets this before going through any possible modifications. + gPuppyCam.flags = gPuppyCam.intendedFlags; + puppycam_input_core(); + puppycam_projection(); + puppycam_script(); + if (gPuppyCam.flags & PUPPYCAM_BEHAVIOUR_COLLISION) + puppycam_collision(); + else + gPuppyCam.opacity = 255; + } + else + if (gPuppyCam.cutscene) + { + gPuppyCam.opacity = 255; + newcam_process_cutscene(); + } + + puppycam_apply(); +} + diff --git a/src/game/puppycam2.h b/src/game/puppycam2.h new file mode 100644 index 00000000..0663b691 --- /dev/null +++ b/src/game/puppycam2.h @@ -0,0 +1,171 @@ +#ifndef PUPPYCAM2_H +#define PUPPYCAM2_H + +#define PUPPYCAM_FLAGS_CUTSCENE 0x0001 +#define PUPPYCAM_FLAGS_SMOOTH 0x0002 + +#define PUPPY_ERROR_POOL_FULL 0x1 + +#define PUPPY_NULL 15151 +#define MAX_PUPPYCAM_VOLUMES 128 + +#define PUPPYCAM_BEHAVIOUR_TEMPORARY 0x0 +#define PUPPYCAM_BEHAVIOUR_PERMANENT 0x1 + +#define PUPPYVOLUME_SHAPE_BOX 0x0 +#define PUPPYVOLUME_SHAPE_CYLINDER 0x1 + +#define PUPPYCAM_MODE3_ZOOMED_IN 0x1 +#define PUPPYCAM_MODE3_ZOOMED_MED 0x2 +#define PUPPYCAM_MODE3_ZOOMED_OUT 0x4 +#define PUPPYCAM_MODE3_ENTER_FIRST_PERSON 0x8 + +#include "include/command_macros_base.h" + +#define PUPPYVOLUME(x, y, z, length, height, width, yaw, functionptr, anglesptr, addflags, removeflags, flagpersistance, room, shape) \ + CMD_BBH(0x3D, 0x24, x), \ + CMD_HHHHHH(y, z, length, height, width, yaw), \ + CMD_PTR(functionptr), \ + CMD_PTR(anglesptr), \ + CMD_W(addflags), \ + CMD_W(removeflags), \ + CMD_BBH(flagpersistance, shape, room) + +struct gPuppyOptions +{ + s16 analogue; + s16 sensitivityX; + s16 sensitivityY; + s16 invertX; + s16 invertY; + s16 turnAggression; + s16 inputType; +}; + +struct gPuppyStruct +{ + s16 yaw; //Horizontal Direction the game reads as the active value. + s16 yawTarget; //Horizontal Direction that yaw tries to be. + f32 yawAcceleration; //Horizontal Direction that sets yawTarget. + s16 pitch; //Vertical Direction the game reads as the active value. + s16 pitchTarget; //Vertical Direction that pitch tries to be. + f32 pitchAcceleration; //Vertical Direction that sets pitchTarget. + s16 posHeight[2]; //The first index is the ground offset of pos[1], the second index is the ground offset of focus[1]. + s16 zoom; //How far the camera is currently zoomed out + u8 zoomSet; //The current setting of which zoompoint to set the target to. + s16 zoomTarget; //The value that zoom tries to be. + s16 zoomPoints[3]; //An array containing distances. + s16 targetFloorHeight; //Mario's current floor height + s16 lastTargetFloorHeight; //Mirror's mario's floor height when his velocity is not above 0. + Vec3s pos; //Where the camera is + Vec3s focus; //Where the camera's looking + Vec3s pan; //An offset of the camera's focus + s32 intendedFlags; //The flagset the camera tries to be when it's not held hostage. + s32 flags; //Behaviour flags that affect different properties of the camera's behaviour + Vec3s shake; //How much the camera's shaking + u8 shakeFrames; //How long the camera's shaking for + f32 shakeForce; //How violently the camera's shaking + s32 framesSinceC[2]; //Counts the number of frames since the last C left or right press, to track double presses. + s16 collisionDistance; //Tries to be zoom, but will be overwritten by collision detection + struct Object *targetObj; //The object that the focus will base its positioning off. Usually Mario. + struct Object *targetObj2; //This is the second focus point that the camera will focus on. It'll focus between them. + s16 povHeight; //An offset of the focus object's Y value. + s16 floorY[2]; //Floor offsets, to allow a grace period before following Mario into the air. + u8 opacity; //A value set by collision distance, to fade Mario out if you're too close. + s8 stick2[2];//The value that's set and read for analogue stick. + u8 stickN[2]; //This is set when the stick is neutral. It's to prevent rapidfire input. + u8 enabled; //A boolean that decides whether to use vanilla camera or puppy camera. Of course, anybody with this enabled is obligated to a death sentence :) + s16 swimPitch; //Pitch adjustment that's applied when swimming. All pitch adjustment is clamped. + s16 edgePitch; //Pitch adjustment that's applied when stood near an edge. All pitch adjustment is clamped. + s16 moveZoom; //A small zoom value that's added on top of the regular zoom when moving. It's pretty subtle, but gives the feeling of a bit of speed. + u8 mode3Flags; //A flagset for classic mode. + u8 moveFlagAdd; //A bit that multiplies movement rate of axes when moving, to centre them faster. + s16 targetDist[2]; + + u8 cutscene; //A boolean that decides whether a cutscene is active + s32 (*sceneFunc)(); + u8 sceneInput; //A boolean that decides whether the controller updates during the scene. + s32 sceneTimer; //The cutscene timer that goes up during a cutscene. + Vec3s scenePos; //Where the camera is during a cutscene + Vec3s sceneFocus; //Where the camera looks during a cutscene + + struct gPuppyOptions options; + +}; + +//A second container for bounds that have 2 pairs of coordinates. Optional. +struct sPuppyAngles +{ + Vec3s pos; + Vec3s focus; + s16 yaw; + s16 pitch; + s16 zoom; +}; + +//A bounding volume for activating puppycamera scripts and angles. +struct sPuppyVolume +{ + Vec3s pos; //The set position of the volume + Vec3s radius; //Where it extends. + s16 rot; //The rotational angle of the volume. + s32 *func; //a pointer to a function. Optional. + struct sPuppyAngles *angles; //A pointer to a gPuppyAngles struct. Optional + s32 flagsAdd; //Adds behaviour flags. + s32 flagsRemove; //Removes behaviour flags. + u8 flagPersistance; //Decides if adding or removing the flags is temporary or permanent. + u8 shape; + s16 room; +}; + +enum gPuppyCamBeh +{ + PUPPYCAM_BEHAVIOUR_X_MOVEMENT = 0x0001, + PUPPYCAM_BEHAVIOUR_Y_MOVEMENT = 0x0002, + PUPPYCAM_BEHAVIOUR_Z_MOVEMENT = 0x0004, + + PUPPYCAM_BEHAVIOUR_YAW_ROTATION = 0x0008, + PUPPYCAM_BEHAVIOUR_PITCH_ROTATION = 0x0010, + PUPPYCAM_BEHAVIOUR_ZOOM_CHANGE = 0x0020, + + PUPPYCAM_BEHAVIOUR_INPUT_NORMAL = 0x0040, + PUPPYCAM_BEHAVIOUR_INPUT_8DIR = 0x0080, + PUPPYCAM_BEHAVIOUR_INPUT_4DIR = 0x0100, + PUPPYCAM_BEHAVIOUR_INPUT_2D = 0x0200, + + PUPPYCAM_BEHAVIOUR_SLIDE_CORRECTION = 0x0400, + PUPPYCAM_BEHAVIOUR_TURN_HELPER = 0x0800, + PUPPYCAM_BEHAVIOUR_HEIGHT_HELPER = 0x1000, + PUPPYCAM_BEHAVIOUR_PANSHIFT = 0x2000, + + PUPPYCAM_BEHAVIOUR_COLLISION = 0x4000, + + + PUPPYCAM_BEHAVIOUR_DEFAULT = PUPPYCAM_BEHAVIOUR_X_MOVEMENT | PUPPYCAM_BEHAVIOUR_Y_MOVEMENT | PUPPYCAM_BEHAVIOUR_Z_MOVEMENT | + PUPPYCAM_BEHAVIOUR_YAW_ROTATION | PUPPYCAM_BEHAVIOUR_PITCH_ROTATION | PUPPYCAM_BEHAVIOUR_ZOOM_CHANGE | + PUPPYCAM_BEHAVIOUR_HEIGHT_HELPER | PUPPYCAM_BEHAVIOUR_TURN_HELPER | PUPPYCAM_BEHAVIOUR_INPUT_NORMAL | PUPPYCAM_BEHAVIOUR_PANSHIFT | PUPPYCAM_BEHAVIOUR_COLLISION +}; + +extern u8 gPCOptionOpen; +extern s32 gPuppyError; +extern struct gPuppyStruct gPuppyCam; +extern struct sPuppyVolume *sPuppyVolumeStack[MAX_PUPPYCAM_VOLUMES]; +extern u16 gPuppyVolumeCount; +extern struct MemoryPool *gPuppyMemoryPool; +extern void puppycam_boot(void); +extern void puppycam_init(void); +extern void puppycam_loop(void); +extern void puppycam_shake(s16 x, s16 y, s16 z); +extern void find_surface_on_ray(Vec3f orig, Vec3f dir, struct Surface **hit_surface, Vec3f hit_pos); +extern f32 approach_f32_asymptotic(f32 current, f32 target, f32 multiplier); +extern void puppycam_default_config(void); +extern s16 LENCOS(s16 length, s16 direction); +extern s16 LENSIN(s16 length, s16 direction); +extern void puppycam_display_options(void); +extern void puppycam_set_save(void); +extern void puppycam_check_pause_buttons(void); +extern void puppycam_activate_cutscene(s32 *scene, s32 lockinput); +extern void puppycam_render_option_text(); +void puppycam_warp(f32 displacementX, f32 displacementY, f32 displacementZ); + +#endif // PUPPYCAM2_H diff --git a/src/game/save_file.c b/src/game/save_file.c index b27d869b..cf801dcb 100644 --- a/src/game/save_file.c +++ b/src/game/save_file.c @@ -15,6 +15,7 @@ #ifdef SRAM #include "sram.h" #endif +#include "puppycam2.h" #define ALIGN4(val) (((val) + 0x3) & ~0x3) @@ -390,6 +391,35 @@ void save_file_load_all(void) { } } +void puppycam_check_save(void) +{ + if (gSaveBuffer.menuData[0].firstBoot != 4 || gSaveBuffer.menuData[0].saveOptions.sensitivityX < 5 || gSaveBuffer.menuData[0].saveOptions.sensitivityY < 5) + { + wipe_main_menu_data(); + gSaveBuffer.menuData[0].firstBoot = 4; + puppycam_default_config(); + } +} + +void puppycam_get_save(void) +{ + gPuppyCam.options = gSaveBuffer.menuData[0].saveOptions; + + gSaveBuffer.menuData[0].firstBoot = gSaveBuffer.menuData[0].firstBoot; + + puppycam_check_save(); +} + +void puppycam_set_save(void) +{ + gSaveBuffer.menuData[0].saveOptions = gPuppyCam.options; + + gSaveBuffer.menuData[0].firstBoot = 4; + + gMainMenuDataModified = TRUE; + save_main_menu_data(); +} + /** * Reload the current save file from its backup copy, which is effectively a * a cached copy of what has been written to EEPROM. diff --git a/src/game/save_file.h b/src/game/save_file.h index 3ac0c4d9..d255f2d1 100644 --- a/src/game/save_file.h +++ b/src/game/save_file.h @@ -5,6 +5,7 @@ #include "types.h" #include "area.h" +#include "puppycam2.h" #include "course_table.h" @@ -69,10 +70,12 @@ struct MainMenuSaveData #else #define SUBTRAHEND 6 #endif + u8 firstBoot; // Pad to match the EEPROM size of 0x200 (10 bytes on JP/US, 8 bytes on EU) //u8 filler[EEPROM_SIZE / 2 - SUBTRAHEND - NUM_SAVE_FILES * (4 + sizeof(struct SaveFile))]; + struct gPuppyOptions saveOptions; struct SaveBlockSignature signature; }; @@ -81,9 +84,13 @@ struct SaveBuffer // Each of the four save files has two copies. If one is bad, the other is used as a backup. struct SaveFile files[NUM_SAVE_FILES][2]; // The main menu data has two copies. If one is bad, the other is used as a backup. - struct MainMenuSaveData menuData[2]; + struct MainMenuSaveData menuData[1]; }; +extern void puppycam_set_save(void); +extern void puppycam_get_save(void); +extern void puppycam_check_save(void); + STATIC_ASSERT(sizeof(struct SaveBuffer) <= EEPROM_SIZE, "ERROR: Save struct too big for specified save type"); extern u8 gLastCompletedCourseNum; From 8be1e09124c0ee19d95aab6b664993f0d05de9f5 Mon Sep 17 00:00:00 2001 From: Fazana <52551480+FazanaJ@users.noreply.github.com> Date: Wed, 4 Aug 2021 15:20:35 +0100 Subject: [PATCH 2/7] Classic mode bugfix oopsiedaisy --- src/game/mario.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/game/mario.c b/src/game/mario.c index b381afa8..15d6c78e 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -1400,6 +1400,12 @@ void update_mario_inputs(struct MarioState *m) { m->collidedObjInteractTypes = m->marioObj->collidedObjInteractTypes; m->flags &= 0xFFFFFF; + if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ENTER_FIRST_PERSON) + { + m->input = INPUT_FIRST_PERSON; + return; + } + update_mario_button_inputs(m); update_mario_joystick_inputs(m); update_mario_geometry_inputs(m); @@ -1417,7 +1423,7 @@ void update_mario_inputs(struct MarioState *m) { if (!(m->input & (INPUT_NONZERO_ANALOG | INPUT_A_PRESSED))) { m->input |= INPUT_UNKNOWN_5; } - + // These 3 flags are defined by Bowser stomping attacks if (m->marioObj->oInteractStatus & (INT_STATUS_MARIO_STUNNED | INT_STATUS_MARIO_KNOCKBACK_DMG | INT_STATUS_MARIO_SHOCKWAVE)) { From 111d2609fcded3bd0332f31281388616b9322913 Mon Sep 17 00:00:00 2001 From: Fazana <52551480+FazanaJ@users.noreply.github.com> Date: Tue, 10 Aug 2021 21:53:43 +0100 Subject: [PATCH 3/7] Widescreen option change, puppyvolumes --- include/text_strings.h.in | 4 ++++ src/engine/level_script.c | 36 ++++++++++++++++++++++++++++++++++++ src/game/camera.h | 1 + src/game/game_init.c | 2 +- src/game/game_init.h | 2 +- src/game/ingame_menu.c | 6 ++++-- src/game/puppycam2.c | 11 ++++------- src/game/puppycam2.h | 4 ++++ 8 files changed, 55 insertions(+), 11 deletions(-) diff --git a/include/text_strings.h.in b/include/text_strings.h.in index 0be03f04..8c264389 100644 --- a/include/text_strings.h.in +++ b/include/text_strings.h.in @@ -17,6 +17,7 @@ #define OPTION_SCHEME1_EN _("Double Tap") #define OPTION_SCHEME2_EN _("Single Press") #define OPTION_SCHEME3_EN _("Classic") +#define NC_WIDE_EN _("Widescreen") #define NC_HIGHLIGHT_L _(">") #define NC_HIGHLIGHT_R _("<") #define NC_BUTTON_EN _("[R]: Options") @@ -43,6 +44,9 @@ #define NC_SCHEME_FR _("Control Scheme") #define NC_SCHEME_DE _("Control Scheme") +#define NC_WIDE_FR _("Widescreen") +#define NC_WIDE_DE _("Widescreen") + #define OPTION_ENABLED_FR _("Active") #define OPTION_ENABLED_DE _("Enabled") diff --git a/src/engine/level_script.c b/src/engine/level_script.c index cfda0e59..ae9bd5cb 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -24,6 +24,7 @@ #include "math_util.h" #include "surface_collision.h" #include "surface_load.h" +#include "game/puppycam2.h" #include "config.h" @@ -757,6 +758,40 @@ static void level_cmd_get_or_set_var(void) { sCurrentCmd = CMD_NEXT; } +static void level_cmd_puppyvolume(void) +{ + if ((sPuppyVolumeStack[gPuppyVolumeCount] = mem_pool_alloc(gPuppyMemoryPool,sizeof(struct sPuppyVolume))) == NULL) + { + sCurrentCmd = CMD_NEXT; + gPuppyError |= PUPPY_ERROR_POOL_FULL; + return; + } + + sPuppyVolumeStack[gPuppyVolumeCount]->pos[0] = CMD_GET(s16, 2); + sPuppyVolumeStack[gPuppyVolumeCount]->pos[1] = CMD_GET(s16, 4); + sPuppyVolumeStack[gPuppyVolumeCount]->pos[2] = CMD_GET(s16, 6); + + sPuppyVolumeStack[gPuppyVolumeCount]->radius[0] = CMD_GET(s16, 8); + sPuppyVolumeStack[gPuppyVolumeCount]->radius[1] = CMD_GET(s16, 10); + sPuppyVolumeStack[gPuppyVolumeCount]->radius[2] = CMD_GET(s16, 12); + + sPuppyVolumeStack[gPuppyVolumeCount]->rot = CMD_GET(s16, 14); + + sPuppyVolumeStack[gPuppyVolumeCount]->func = CMD_GET(void *, 16); + sPuppyVolumeStack[gPuppyVolumeCount]->angles = segmented_to_virtual(CMD_GET(void *, 20)); + + sPuppyVolumeStack[gPuppyVolumeCount]->flagsAdd = CMD_GET(s32, 24); + sPuppyVolumeStack[gPuppyVolumeCount]->flagsRemove = CMD_GET(s32, 28); + + sPuppyVolumeStack[gPuppyVolumeCount]->flagPersistance = CMD_GET(u8, 32); + + sPuppyVolumeStack[gPuppyVolumeCount]->shape = CMD_GET(u8, 33); + sPuppyVolumeStack[gPuppyVolumeCount]->room = CMD_GET(s16, 34); + + gPuppyVolumeCount++; + sCurrentCmd = CMD_NEXT; +} + static void (*LevelScriptJumpTable[])(void) = { /*00*/ level_cmd_load_and_execute, /*01*/ level_cmd_exit_and_execute, @@ -819,6 +854,7 @@ static void (*LevelScriptJumpTable[])(void) = { /*3A*/ level_cmd_3A, /*3B*/ level_cmd_create_whirlpool, /*3C*/ level_cmd_get_or_set_var, + /*3E*/ level_cmd_puppyvolume, }; struct LevelCommand *level_script_execute(struct LevelCommand *cmd) { diff --git a/src/game/camera.h b/src/game/camera.h index f56ed027..fad76a35 100644 --- a/src/game/camera.h +++ b/src/game/camera.h @@ -7,6 +7,7 @@ #include "area.h" #include "engine/geo_layout.h" #include "engine/graph_node.h" +#include "puppycam2.h" #include "level_table.h" diff --git a/src/game/game_init.c b/src/game/game_init.c index b82d89d9..cfc5de72 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -81,7 +81,7 @@ UNUSED static s32 sUnusedGameInitValue = 0; // General timer that runs as the game starts u32 gGlobalTimer = 0; #ifdef WIDE -u8 gWidescreen; +s16 gWidescreen; #endif // Framebuffer rendering values (max 3) diff --git a/src/game/game_init.h b/src/game/game_init.h index f3f650c3..481c81b0 100644 --- a/src/game/game_init.h +++ b/src/game/game_init.h @@ -43,7 +43,7 @@ extern struct GfxPool *gGfxPool; extern u8 gControllerBits; extern u8 gIsConsole; #ifdef WIDE -extern u8 gWidescreen; +extern s16 gWidescreen; #endif extern u8 gBorderHeight; #ifdef CUSTOM_DEBUG diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index 2b8b24fe..ac93f3dd 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -1493,6 +1493,8 @@ void render_pause_red_coins(void) { print_animated_red_coin(GFX_DIMENSIONS_FROM_RIGHT_EDGE(30) - x * 20, 16); } } +///By default, not needed as puppycamera has an option, but should you wish to revert that, you are legally allowed. +/* #ifdef WIDE void render_widescreen_setting(void) { gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); @@ -1512,7 +1514,7 @@ void render_widescreen_setting(void) { save_file_set_widescreen_mode(gWidescreen); } } -#endif +#endif*/ #define CRS_NUM_X1 100 #define TXT_STAR_X 98 @@ -1869,7 +1871,7 @@ s16 render_pause_courses_and_castle(void) { break; } #ifdef WIDE - render_widescreen_setting(); + //render_widescreen_setting(); #endif if (gDialogTextAlpha < 250) { gDialogTextAlpha += 25; diff --git a/src/game/puppycam2.c b/src/game/puppycam2.c index daa4f9ca..1963f215 100644 --- a/src/game/puppycam2.c +++ b/src/game/puppycam2.c @@ -42,8 +42,8 @@ struct MemoryPool *gPuppyMemoryPool; s32 gPuppyError = 0; #if defined(VERSION_EU) -static u8 gPCOptionStringsFR[][64] = {{NC_ANALOGUE_FR}, {NC_CAMX_FR}, {NC_CAMY_FR}, {NC_INVERTX_FR}, {NC_INVERTY_FR}, {NC_CAMC_FR}, {NC_SCHEME_FR},}; -static u8 gPCOptionStringsDE[][64] = {{NC_ANALOGUE_DE}, {NC_CAMX_DE}, {NC_CAMY_DE}, {NC_INVERTX_DE}, {NC_INVERTY_DE}, {NC_CAMC_DE}, {NC_SCHEME_DE},}; +static u8 gPCOptionStringsFR[][64] = {{NC_ANALOGUE_FR}, {NC_CAMX_FR}, {NC_CAMY_FR}, {NC_INVERTX_FR}, {NC_INVERTY_FR}, {NC_CAMC_FR}, {NC_SCHEME_FR}, {NC_WIDE_FR},}; +static u8 gPCOptionStringsDE[][64] = {{NC_ANALOGUE_DE}, {NC_CAMX_DE}, {NC_CAMY_DE}, {NC_INVERTX_DE}, {NC_INVERTY_DE}, {NC_CAMC_DE}, {NC_SCHEME_DE}, {NC_WIDE_DE},}; static u8 gPCFlagStringsFR[][64] = {{OPTION_DISABLED_FR}, {OPTION_ENABLED_FR}, {OPTION_SCHEME1_FR}, {OPTION_SCHEME2_FR}, {OPTION_SCHEME3_FR}}; static u8 gPCFlagStringsDE[][64] = {{OPTION_DISABLED_DE}, {OPTION_ENABLED_DE}, {OPTION_SCHEME1_DE}, {OPTION_SCHEME2_DE}, {OPTION_SCHEME3_DE}}; static u8 gPCToggleStringsFR[][64] = {{NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}}; @@ -51,7 +51,7 @@ static u8 gPCToggleStringsDE[][64] = {{NC_ANALOGUE_EN}, {NC_ANALOGUE_EN}, {NC_AN //static u8 gPCToggleStringsFR[][64] = {{NC_BUTTON_FR}, {NC_BUTTON2_FR}, {NC_OPTION_FR}, {NC_HIGHLIGHT_L_FR}, {NC_HIGHLIGHT_R_FR}}; //static u8 gPCToggleStringsDE[][64] = {{NC_BUTTON_DE}, {NC_BUTTON2_DE}, {NC_OPTION_DE}, {NC_HIGHLIGHT_L_DE}, {NC_HIGHLIGHT_R_DE}}; #endif -static u8 gPCOptionStringsEN[][64] = {{NC_ANALOGUE_EN}, {NC_CAMX_EN}, {NC_CAMY_EN}, {NC_INVERTX_EN}, {NC_INVERTY_EN}, {NC_CAMC_EN}, {NC_SCHEME_EN},}; +static u8 gPCOptionStringsEN[][64] = {{NC_ANALOGUE_EN}, {NC_CAMX_EN}, {NC_CAMY_EN}, {NC_INVERTX_EN}, {NC_INVERTY_EN}, {NC_CAMC_EN}, {NC_SCHEME_EN}, {NC_WIDE_EN},}; static u8 gPCFlagStringsEN[][64] = {{OPTION_DISABLED_EN}, {OPTION_ENABLED_EN}, {OPTION_SCHEME1_EN}, {OPTION_SCHEME2_EN}, {OPTION_SCHEME3_EN}}; static u8 gPCToggleStringsEN[][64] = {{NC_BUTTON_EN}, {NC_BUTTON2_EN}, {NC_OPTION_EN}, {NC_HIGHLIGHT_L}, {NC_HIGHLIGHT_R}}; @@ -74,6 +74,7 @@ static const struct gPCOptionStruct static const struct gPCOptionStruct gPCOptions[]= { //If the min and max are 0 and 1, then the value text is used, otherwise it's ignored. + {/*Option Name*/ 7, /*Option Variable*/ &gWidescreen, /*Option Value Text Start*/ 0, /*Option Minimum*/ FALSE, /*Option Maximum*/ TRUE}, {/*Option Name*/ 0, /*Option Variable*/ &gPuppyCam.options.analogue, /*Option Value Text Start*/ 0, /*Option Minimum*/ FALSE, /*Option Maximum*/ TRUE}, {/*Option Name*/ 6, /*Option Variable*/ &gPuppyCam.options.inputType, /*Option Value Text Start*/ 2, /*Option Minimum*/ 0, /*Option Maximum*/ 2}, {/*Option Name*/ 1, /*Option Variable*/ &gPuppyCam.options.sensitivityX, /*Option Value Text Start*/ 255, /*Option Minimum*/ 10, /*Option Maximum*/ 500}, @@ -85,10 +86,6 @@ static const struct gPCOptionStruct gPCOptions[]= u8 gPCOptionCap = sizeof(gPCOptions) / sizeof(struct gPCOptionStruct); //How many options there are in newcam_uptions. -//Some macros for the sake of basic human sanity. -#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) -#define ABS(x) ((x) > 0.f ? (x) : -(x)) - s16 LENSIN(s16 length, s16 direction) { return (length * sins(direction)); diff --git a/src/game/puppycam2.h b/src/game/puppycam2.h index 0663b691..da825d5e 100644 --- a/src/game/puppycam2.h +++ b/src/game/puppycam2.h @@ -31,6 +31,10 @@ CMD_W(removeflags), \ CMD_BBH(flagpersistance, shape, room) +//Some macros for the sake of basic human sanity. +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) +#define ABS(x) ((x) > 0.f ? (x) : -(x)) + struct gPuppyOptions { s16 analogue; From 5dc75cf792b1809b82d73237540ca0c7920b2ae6 Mon Sep 17 00:00:00 2001 From: Fazana <52551480+FazanaJ@users.noreply.github.com> Date: Sun, 15 Aug 2021 15:15:16 +0100 Subject: [PATCH 4/7] Ifdefs and config --- include/config.h | 2 ++ include/text_strings.h.in | 2 ++ src/engine/level_script.c | 4 ++++ src/game/camera.c | 25 ++++++++++++++++++++++--- src/game/game_init.c | 2 ++ src/game/hud.c | 2 ++ src/game/ingame_menu.c | 15 +++++++++------ src/game/mario.c | 2 ++ src/game/mario_misc.c | 2 ++ src/game/puppycam2.c | 3 +++ src/game/puppycam2.h | 4 ++++ src/game/save_file.c | 2 ++ src/game/save_file.h | 4 ++++ 13 files changed, 60 insertions(+), 9 deletions(-) diff --git a/include/config.h b/include/config.h index f38082b4..ca21728b 100644 --- a/include/config.h +++ b/include/config.h @@ -98,6 +98,8 @@ #define PARALLEL_LAKITU_CAM // Allows Mario to ledgegrab sloped floors #define NO_FALSE_LEDGEGRABS +//Enables Puppy Camera 2, a rewritten camera that can be freely configured and modified. +//#define PUPPYCAM // HACKER QOL diff --git a/include/text_strings.h.in b/include/text_strings.h.in index 8c264389..30d01fa6 100644 --- a/include/text_strings.h.in +++ b/include/text_strings.h.in @@ -3,6 +3,7 @@ #include "text_menu_strings.h" +#ifdef PUPPYCAM #define NC_CAMX_EN _("Camera X Sensitivity") #define NC_CAMY_EN _("Camera Y Sensitivity") #define NC_INVERTX_EN _("Invert X Axis") @@ -71,6 +72,7 @@ #define NC_OPTION_FR _("OPTIONS PUPPYCAM") #define NC_OPTION_DE _("PUPPYCAM OPTIONS") #endif +#endif /** * Global Symbols diff --git a/src/engine/level_script.c b/src/engine/level_script.c index ae9bd5cb..06ab70d1 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -758,6 +758,7 @@ static void level_cmd_get_or_set_var(void) { sCurrentCmd = CMD_NEXT; } +#ifdef PUPPYCAM static void level_cmd_puppyvolume(void) { if ((sPuppyVolumeStack[gPuppyVolumeCount] = mem_pool_alloc(gPuppyMemoryPool,sizeof(struct sPuppyVolume))) == NULL) @@ -791,6 +792,7 @@ static void level_cmd_puppyvolume(void) gPuppyVolumeCount++; sCurrentCmd = CMD_NEXT; } +#endif static void (*LevelScriptJumpTable[])(void) = { /*00*/ level_cmd_load_and_execute, @@ -854,7 +856,9 @@ static void (*LevelScriptJumpTable[])(void) = { /*3A*/ level_cmd_3A, /*3B*/ level_cmd_create_whirlpool, /*3C*/ level_cmd_get_or_set_var, + #ifdef PUPPYCAM /*3E*/ level_cmd_puppyvolume, + #endif }; struct LevelCommand *level_script_execute(struct LevelCommand *cmd) { diff --git a/src/game/camera.c b/src/game/camera.c index 0435d3be..919bff93 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -3038,7 +3038,11 @@ void update_camera(struct Camera *c) { gCamera = c; update_camera_hud_status(c); - if (c->cutscene == 0 && !gPuppyCam.enabled && !(gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON)) { + if (c->cutscene == 0 && + #ifdef PUPPYCAM + !gPuppyCam.enabled && + #endif + !(gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON)) { // Only process R_TRIG if 'fixed' is not selected in the menu if (cam_select_alt_mode(0) == CAM_SELECTION_MARIO) { if (gPlayer1Controller->buttonPressed & R_TRIG) { @@ -3060,7 +3064,9 @@ void update_camera(struct Camera *c) { sStatusFlags |= CAM_FLAG_FRAME_AFTER_CAM_INIT; } + #ifdef PUPPYCAM if (!gPuppyCam.enabled || c->cutscene != 0 || gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON) { + #endif // Store previous geometry information sMarioGeometry.prevFloorHeight = sMarioGeometry.currFloorHeight; sMarioGeometry.prevCeilHeight = sMarioGeometry.currCeilHeight; @@ -3183,12 +3189,16 @@ void update_camera(struct Camera *c) { } } } + #ifdef PUPPYCAM } + #endif // Start any Mario-related cutscenes start_cutscene(c, get_cutscene_from_mario_status(c)); stub_camera_2(c); gCheckingSurfaceCollisionsForCamera = FALSE; + #ifdef PUPPYCAM if (!gPuppyCam.enabled || c->cutscene != 0 || gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON) { + #endif if (gCurrLevelNum != LEVEL_CASTLE) { // If fixed camera is selected as the alternate mode, then fix the camera as long as the right // trigger is held @@ -3226,6 +3236,7 @@ void update_camera(struct Camera *c) { } update_lakitu(c); + #ifdef PUPPYCAM } //Just a cute little bit that syncs puppycamera up to vanilla when playing a vanilla cutscene :3 if (c->cutscene != 0) @@ -3238,8 +3249,12 @@ void update_camera(struct Camera *c) { gPuppyCam.yaw = gMarioState->faceAngle[1]+0x8000; } } - - if (c->cutscene == 0 && gPuppyCam.enabled && !(gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON)) + #endif + if (c->cutscene == 0 && + #ifdef PUPPYCAM + gPuppyCam.enabled && + #endif + !(gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON)) { // Clear the recent cutscene after 8 frames if (gRecentCutscene != 0 && sFramesSinceCutsceneEnded < 8) { @@ -3249,7 +3264,9 @@ void update_camera(struct Camera *c) { sFramesSinceCutsceneEnded = 0; } } + #ifdef PUPPYCAM puppycam_loop(); + #endif // Apply camera shakes shake_camera_pitch(gLakituState.pos, gLakituState.focus); shake_camera_yaw(gLakituState.pos, gLakituState.focus); @@ -3498,7 +3515,9 @@ void init_camera(struct Camera *c) { gLakituState.nextYaw = gLakituState.yaw; c->yaw = gLakituState.yaw; c->nextYaw = gLakituState.yaw; + #ifdef PUPPYCAM puppycam_init(); + #endif } /** diff --git a/src/game/game_init.c b/src/game/game_init.c index d15b405e..317e33bf 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -728,7 +728,9 @@ void thread5_game_loop(UNUSED void *arg) { createHvqmThread(); #endif save_file_load_all(); + #ifdef PUPPYCAM puppycam_boot(); + #endif set_vblank_handler(2, &gGameVblankHandler, &gGameVblankQueue, (OSMesg) 1); diff --git a/src/game/hud.c b/src/game/hud.c index 7d73ce81..5106d7dd 100644 --- a/src/game/hud.c +++ b/src/game/hud.c @@ -526,7 +526,9 @@ void render_hud(void) { if (hudDisplayFlags & HUD_DISPLAY_FLAG_CAMERA_AND_POWER) { render_hud_power_meter(); + #ifdef PUPPYCAM if (!gPuppyCam.enabled) + #endif render_hud_camera_status(); } diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index ac93f3dd..c5736037 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -1494,8 +1494,8 @@ void render_pause_red_coins(void) { } } ///By default, not needed as puppycamera has an option, but should you wish to revert that, you are legally allowed. -/* -#ifdef WIDE + +#if defined(WIDE) && !defined(PUPPYCAM) void render_widescreen_setting(void) { gSPDisplayList(gDisplayListHead++, dl_ia_text_begin); gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, gDialogTextAlpha); @@ -1514,7 +1514,7 @@ void render_widescreen_setting(void) { save_file_set_widescreen_mode(gWidescreen); } } -#endif*/ +#endif #define CRS_NUM_X1 100 #define TXT_STAR_X 98 @@ -1802,10 +1802,11 @@ s8 gHudFlash = 0; s16 render_pause_courses_and_castle(void) { s16 index; - + #ifdef PUPPYCAM puppycam_check_pause_buttons(); if (!gPCOptionOpen) { + #endif switch (gDialogBoxState) { case DIALOG_STATE_OPENING: gDialogLineNum = MENU_OPT_DEFAULT; @@ -1870,12 +1871,13 @@ s16 render_pause_courses_and_castle(void) { } break; } - #ifdef WIDE - //render_widescreen_setting(); + #if defined(WIDE) && !defined(PUPPYCAM) + render_widescreen_setting(); #endif if (gDialogTextAlpha < 250) { gDialogTextAlpha += 25; } + #ifdef PUPPYCAM } else { @@ -1884,6 +1886,7 @@ s16 render_pause_courses_and_castle(void) { } puppycam_render_option_text(); + #endif return MENU_OPT_NONE; } diff --git a/src/game/mario.c b/src/game/mario.c index 1ea37156..31e97bce 100644 --- a/src/game/mario.c +++ b/src/game/mario.c @@ -1417,11 +1417,13 @@ void update_mario_inputs(struct MarioState *m) { m->collidedObjInteractTypes = m->marioObj->collidedObjInteractTypes; m->flags &= 0xFFFFFF; + #ifdef PUPPYCAM if (gPuppyCam.mode3Flags & PUPPYCAM_MODE3_ENTER_FIRST_PERSON) { m->input = INPUT_FIRST_PERSON; return; } + #endif update_mario_button_inputs(m); update_mario_joystick_inputs(m); diff --git a/src/game/mario_misc.c b/src/game/mario_misc.c index 68af9f7a..6eab1b69 100644 --- a/src/game/mario_misc.c +++ b/src/game/mario_misc.c @@ -342,11 +342,13 @@ Gfx *geo_mirror_mario_set_alpha(s32 callContext, struct GraphNode *node, UNUSED if (callContext == GEO_CONTEXT_RENDER) { alpha = (bodyState->modelState & 0x100) ? (bodyState->modelState & 0xFF) : 255; + #ifdef PUPPYCAM if (alpha > gPuppyCam.opacity) { alpha = gPuppyCam.opacity; bodyState->modelState |= MODEL_STATE_NOISE_ALPHA; } + #endif gfx = make_gfx_mario_alpha(asGenerated, alpha); } return gfx; diff --git a/src/game/puppycam2.c b/src/game/puppycam2.c index 1963f215..d69c5bb5 100644 --- a/src/game/puppycam2.c +++ b/src/game/puppycam2.c @@ -23,6 +23,8 @@ #include "save_file.h" #include "mario.h" +#ifdef PUPPYCAM + #define OFFSET 30.0f #define STEPS 1 #define DECELERATION 0.66f @@ -1590,3 +1592,4 @@ void puppycam_loop(void) puppycam_apply(); } +#endif diff --git a/src/game/puppycam2.h b/src/game/puppycam2.h index da825d5e..69819243 100644 --- a/src/game/puppycam2.h +++ b/src/game/puppycam2.h @@ -1,6 +1,8 @@ #ifndef PUPPYCAM2_H #define PUPPYCAM2_H +#ifdef PUPPYCAM + #define PUPPYCAM_FLAGS_CUTSCENE 0x0001 #define PUPPYCAM_FLAGS_SMOOTH 0x0002 @@ -172,4 +174,6 @@ extern void puppycam_activate_cutscene(s32 *scene, s32 lockinput); extern void puppycam_render_option_text(); void puppycam_warp(f32 displacementX, f32 displacementY, f32 displacementZ); +#endif + #endif // PUPPYCAM2_H diff --git a/src/game/save_file.c b/src/game/save_file.c index cf801dcb..1dd1606a 100644 --- a/src/game/save_file.c +++ b/src/game/save_file.c @@ -391,6 +391,7 @@ void save_file_load_all(void) { } } +#ifdef PUPPYCAM void puppycam_check_save(void) { if (gSaveBuffer.menuData[0].firstBoot != 4 || gSaveBuffer.menuData[0].saveOptions.sensitivityX < 5 || gSaveBuffer.menuData[0].saveOptions.sensitivityY < 5) @@ -419,6 +420,7 @@ void puppycam_set_save(void) gMainMenuDataModified = TRUE; save_main_menu_data(); } +#endif /** * Reload the current save file from its backup copy, which is effectively a diff --git a/src/game/save_file.h b/src/game/save_file.h index d255f2d1..64cf0c63 100644 --- a/src/game/save_file.h +++ b/src/game/save_file.h @@ -75,7 +75,9 @@ struct MainMenuSaveData // Pad to match the EEPROM size of 0x200 (10 bytes on JP/US, 8 bytes on EU) //u8 filler[EEPROM_SIZE / 2 - SUBTRAHEND - NUM_SAVE_FILES * (4 + sizeof(struct SaveFile))]; + #ifdef PUPPYCAM struct gPuppyOptions saveOptions; + #endif struct SaveBlockSignature signature; }; @@ -87,9 +89,11 @@ struct SaveBuffer struct MainMenuSaveData menuData[1]; }; +#ifdef PUPPYCAM extern void puppycam_set_save(void); extern void puppycam_get_save(void); extern void puppycam_check_save(void); +#endif STATIC_ASSERT(sizeof(struct SaveBuffer) <= EEPROM_SIZE, "ERROR: Save struct too big for specified save type"); From 984dcb3d6e7ef15fd16aba6aa0b8586f80f96a85 Mon Sep 17 00:00:00 2001 From: Fazana <52551480+FazanaJ@users.noreply.github.com> Date: Sun, 15 Aug 2021 15:18:28 +0100 Subject: [PATCH 5/7] oops typo heehee --- src/game/camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/camera.c b/src/game/camera.c index 919bff93..69ec60b8 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -3266,7 +3266,6 @@ void update_camera(struct Camera *c) { } #ifdef PUPPYCAM puppycam_loop(); - #endif // Apply camera shakes shake_camera_pitch(gLakituState.pos, gLakituState.focus); shake_camera_yaw(gLakituState.pos, gLakituState.focus); @@ -3278,6 +3277,7 @@ void update_camera(struct Camera *c) { } gLakituState.roll += sHandheldShakeRoll; gLakituState.roll += gLakituState.keyDanceRoll; + #endif } gLakituState.lastFrameAction = sMarioCamState->action; } From 78ebe1c6174ce1889e3b0c06b7f9d3c79b15aa26 Mon Sep 17 00:00:00 2001 From: Fazana <52551480+FazanaJ@users.noreply.github.com> Date: Sun, 15 Aug 2021 15:20:30 +0100 Subject: [PATCH 6/7] dude I'm actually ook ook :monkey: --- src/game/camera.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/game/camera.c b/src/game/camera.c index 69ec60b8..25b27983 100644 --- a/src/game/camera.c +++ b/src/game/camera.c @@ -3249,12 +3249,7 @@ void update_camera(struct Camera *c) { gPuppyCam.yaw = gMarioState->faceAngle[1]+0x8000; } } - #endif - if (c->cutscene == 0 && - #ifdef PUPPYCAM - gPuppyCam.enabled && - #endif - !(gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON)) + if (c->cutscene == 0 && gPuppyCam.enabled && !(gCurrentArea->camera->mode == CAMERA_MODE_INSIDE_CANNON)) { // Clear the recent cutscene after 8 frames if (gRecentCutscene != 0 && sFramesSinceCutsceneEnded < 8) { @@ -3264,7 +3259,6 @@ void update_camera(struct Camera *c) { sFramesSinceCutsceneEnded = 0; } } - #ifdef PUPPYCAM puppycam_loop(); // Apply camera shakes shake_camera_pitch(gLakituState.pos, gLakituState.focus); @@ -3277,8 +3271,8 @@ void update_camera(struct Camera *c) { } gLakituState.roll += sHandheldShakeRoll; gLakituState.roll += gLakituState.keyDanceRoll; - #endif } + #endif gLakituState.lastFrameAction = sMarioCamState->action; } From 20ffa3de16cc333dc3eee4a55013a0332fad6eca Mon Sep 17 00:00:00 2001 From: Fazana <52551480+FazanaJ@users.noreply.github.com> Date: Sun, 15 Aug 2021 17:26:38 +0100 Subject: [PATCH 7/7] Antialiasing Changes --- include/n64/PR/gbi.h | 152 +++++++++++++++++--------------- src/game/rendering_graph_node.c | 49 +--------- 2 files changed, 81 insertions(+), 120 deletions(-) diff --git a/include/n64/PR/gbi.h b/include/n64/PR/gbi.h index 702a9933..16968a8e 100644 --- a/include/n64/PR/gbi.h +++ b/include/n64/PR/gbi.h @@ -76,13 +76,13 @@ * * IMPLEMENTATION NOTE: * There is another group of RDP commands that includes the triangle commands - * generated by the RSP code. These are the raw commands the rasterizer - * hardware chews on, with slope info, etc. They will follow the RDP + * generated by the RSP code. These are the raw commands the rasterizer + * hardware chews on, with slope info, etc. They will follow the RDP * ordering... * * IMPLEMENTATION NOTE: - * The RDP hardware has some of these bit patterns wired up. If the hardware - * changes, we must adjust this table, likewise we can't change/add things + * The RDP hardware has some of these bit patterns wired up. If the hardware + * changes, we must adjust this table, likewise we can't change/add things * once the hardware is frozen. (actually, the RDP hardware only looks at * the lower 6 bits of the command byte) * @@ -206,7 +206,7 @@ #define G_TEXRECT 0xe4 /* -28 */ -/* +/* * The following commands are the "generated" RDP commands; the user * never sees them, the RSP microcode generates them. * @@ -326,7 +326,7 @@ * * DO NOT USE THE LOW 8 BITS OF GEOMETRYMODE: * The weird bit-ordering is for the micro-code: the lower byte - * can be OR'd in with G_TRI_SHADE (11001100) to construct + * can be OR'd in with G_TRI_SHADE (11001100) to construct * the triangle command directly. Don't break it... * * DO NOT USE THE HIGH 8 BITS OF GEOMETRYMODE: @@ -340,7 +340,7 @@ * appropriately and use primcolor to see anything. * * G_SHADING_SMOOTH enabled means use all 3 colors of the triangle. - * If it is not set, then do 'flat shading', where only one vertex color + * If it is not set, then do 'flat shading', where only one vertex color * is used (and all 3 vertices are set to that same color by the ucode) * See the man page for gSP1Triangle(). * @@ -718,154 +718,162 @@ #define G_BL_1 2 #define G_BL_0 3 +#ifdef DISABLE_AA +#define AA_DEF +#define RD_DEF +#else +#define AA_DEF AA_EN | +#define RD_DEF IM_RD | +#endif + #define GBL_c1(m1a, m1b, m2a, m2b) \ (m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18 #define GBL_c2(m1a, m1b, m2a, m2b) \ (m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16 #define RM_AA_ZB_OPA_SURF(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | RD_DEF CVG_DST_CLAMP | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_RA_ZB_OPA_SURF(clk) \ - AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | CVG_DST_CLAMP | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_ZB_XLU_SURF(clk) \ - AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ + AA_DEF Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ FORCE_BL | ZMODE_XLU | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_OPA_DECAL(clk) \ - AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | ALPHA_CVG_SEL | \ + AA_DEF Z_CMP | RD_DEF CVG_DST_WRAP | ALPHA_CVG_SEL | \ ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_RA_ZB_OPA_DECAL(clk) \ - AA_EN | Z_CMP | CVG_DST_WRAP | ALPHA_CVG_SEL | \ + AA_DEF Z_CMP | CVG_DST_WRAP | ALPHA_CVG_SEL | \ ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_ZB_XLU_DECAL(clk) \ - AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ + AA_DEF Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ FORCE_BL | ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_OPA_INTER(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | RD_DEF CVG_DST_CLAMP | \ ALPHA_CVG_SEL | ZMODE_INTER | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_RA_ZB_OPA_INTER(clk) \ - AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | CVG_DST_CLAMP | \ ALPHA_CVG_SEL | ZMODE_INTER | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_ZB_XLU_INTER(clk) \ - AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ + AA_DEF Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ FORCE_BL | ZMODE_INTER | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_XLU_LINE(clk) \ - AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \ + AA_DEF Z_CMP | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \ ALPHA_CVG_SEL | FORCE_BL | ZMODE_XLU | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_DEC_LINE(clk) \ - AA_EN | Z_CMP | IM_RD | CVG_DST_SAVE | CVG_X_ALPHA | \ + AA_DEF Z_CMP | IM_RD | CVG_DST_SAVE | CVG_X_ALPHA | \ ALPHA_CVG_SEL | FORCE_BL | ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_TEX_EDGE(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_EN | Z_CMP | Z_UPD | RD_DEF CVG_DST_CLAMP | \ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_ZB_TEX_INTER(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | RD_DEF CVG_DST_CLAMP | \ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_INTER | TEX_EDGE | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_ZB_SUB_SURF(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \ + AA_DEF Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_ZB_PCL_SURF(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ ZMODE_OPA | G_AC_DITHER | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_OPA_TERR(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | RD_DEF CVG_DST_CLAMP | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_TEX_TERR(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ + AA_DEF Z_CMP | Z_UPD | RD_DEF CVG_DST_CLAMP | \ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_ZB_SUB_TERR(clk) \ - AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \ + AA_DEF Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_OPA_SURF(clk) \ - AA_EN | IM_RD | CVG_DST_CLAMP | \ + AA_DEF RD_DEF CVG_DST_CLAMP | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_RA_OPA_SURF(clk) \ - AA_EN | CVG_DST_CLAMP | \ + AA_DEF CVG_DST_CLAMP | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_XLU_SURF(clk) \ - AA_EN | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | \ + AA_DEF IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | \ ZMODE_OPA | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_XLU_LINE(clk) \ - AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \ + AA_DEF IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \ ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_DEC_LINE(clk) \ - AA_EN | IM_RD | CVG_DST_FULL | CVG_X_ALPHA | \ + AA_DEF IM_RD | CVG_DST_FULL | CVG_X_ALPHA | \ ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_TEX_EDGE(clk) \ - AA_EN | IM_RD | CVG_DST_CLAMP | \ + AA_EN | RD_DEF CVG_DST_CLAMP | \ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_SUB_SURF(clk) \ - AA_EN | IM_RD | CVG_DST_FULL | \ + AA_DEF IM_RD | CVG_DST_FULL | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) #define RM_AA_PCL_SURF(clk) \ - AA_EN | IM_RD | CVG_DST_CLAMP | \ + AA_DEF IM_RD | CVG_DST_CLAMP | \ ZMODE_OPA | G_AC_DITHER | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_OPA_TERR(clk) \ - AA_EN | IM_RD | CVG_DST_CLAMP | \ + AA_DEF RD_DEF CVG_DST_CLAMP | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_TEX_TERR(clk) \ - AA_EN | IM_RD | CVG_DST_CLAMP | \ + AA_DEF RD_DEF CVG_DST_CLAMP | \ CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) #define RM_AA_SUB_TERR(clk) \ - AA_EN | IM_RD | CVG_DST_FULL | \ + AA_DEF IM_RD | CVG_DST_FULL | \ ZMODE_OPA | ALPHA_CVG_SEL | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) @@ -874,27 +882,27 @@ Z_CMP | Z_UPD | CVG_DST_FULL | ALPHA_CVG_SEL | \ ZMODE_OPA | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - + #define RM_ZB_XLU_SURF(clk) \ Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_XLU | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - + #define RM_ZB_OPA_DECAL(clk) \ Z_CMP | CVG_DST_FULL | ALPHA_CVG_SEL | ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - + #define RM_ZB_XLU_DECAL(clk) \ Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - + #define RM_ZB_CLD_SURF(clk) \ Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_XLU | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - + #define RM_ZB_OVL_SURF(clk) \ Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_DEC | \ GBL_c##clk(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - + #define RM_ZB_PCL_SURF(clk) \ Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | \ G_AC_DITHER | \ @@ -1151,7 +1159,7 @@ * element, we can't depend on the C compiler to align things * properly. * - * 64-bit structure alignment is enforced by wrapping structures with + * 64-bit structure alignment is enforced by wrapping structures with * unions that contain a dummy "long long int". Why this works is * explained in the ANSI C Spec, or on page 186 of the second edition * of K&R, "The C Programming Language". @@ -1223,14 +1231,14 @@ typedef struct { /* 20 bytes for above */ /* padding to bring structure size to 64 bit allignment */ - char dummy[4]; + char dummy[4]; } uSprite_t; -typedef union { +typedef union { uSprite_t s; - /* Need to make sure this is 64 bit aligned */ + /* Need to make sure this is 64 bit aligned */ long long int force_structure_allignment[3]; } uSprite; @@ -1315,7 +1323,7 @@ typedef union { */ #ifdef F3DEX_GBI_2 /* 0,4 are reserved by G_MTX */ -# define G_MV_MMTX 2 +# define G_MV_MMTX 2 # define G_MV_PMTX 6 # define G_MV_VIEWPORT 8 # define G_MV_LIGHT 10 @@ -1373,7 +1381,7 @@ typedef union { /* * These are offsets from the address in the dmem table - */ + */ #define G_MWO_NUMLIGHT 0x00 #define G_MWO_CLIP_RNX 0x04 #define G_MWO_CLIP_RNY 0x0c @@ -1455,7 +1463,7 @@ typedef union { * * Note: only directional (infinite) lights are currently supported. * - * Note: the weird order is for the DMEM alignment benefit of + * Note: the weird order is for the DMEM alignment benefit of * the microcode. * */ @@ -1775,7 +1783,7 @@ typedef struct { /* * Textured rectangles are 128 bits not 64 bits - */ + */ typedef struct { unsigned long w0; unsigned long w1; @@ -1933,7 +1941,7 @@ typedef union { gsDma1p(G_VTX, v, sizeof(Vtx)*(n), ((n)-1)<<4|(v0)) #endif - + #ifdef F3DEX_GBI_2 # define gSPViewport(pkt, v) \ gDma2p((pkt), G_MOVEMEM, (v), sizeof(Vp), G_MV_VIEWPORT, 0) @@ -2192,7 +2200,7 @@ typedef union { /*** *** 1 Triangle - ***/ + ***/ #define gSP1Triangle(pkt, v0, v1, v2, flag) \ { \ Gfx *_g = (Gfx *)(pkt); \ @@ -2368,7 +2376,7 @@ typedef union { * Insert values into Matrix * * where = element of matrix (byte offset) - * num = new element (32 bit value replacing 2 int or 2 frac matrix + * num = new element (32 bit value replacing 2 int or 2 frac matrix * componants */ #ifdef F3DEX_GBI_2 @@ -2396,7 +2404,7 @@ typedef union { #define gsSPForceMatrix(mptr) \ gsDma2p(G_MOVEMEM,(mptr),sizeof(Mtx),G_MV_MATRIX,0), \ gsMoveWd(G_MW_FORCEMTX,0,0x00010000) - + #else /* F3DEX_GBI_2 */ #define gSPForceMatrix(pkt, mptr) \ { \ @@ -2444,7 +2452,7 @@ typedef union { /* * gSPBranchLessZ Branch DL if (vtx.z) less than or equal (zval). * - * dl = DL branch to + * dl = DL branch to * vtx = Vertex * zval = Screen depth * near = Near plane @@ -2491,7 +2499,7 @@ typedef union { /* * gSPBranchLessZraw Branch DL if (vtx.z) less than or equal (raw zval). * - * dl = DL branch to + * dl = DL branch to * vtx = Vertex * zval = Raw value of screen depth */ @@ -2592,7 +2600,7 @@ typedef union { #define NUMLIGHTS_7 7 /* * n should be one of: NUMLIGHTS_0, NUMLIGHTS_1, ..., NUMLIGHTS_7 - * NOTE: in addition to the number of directional lights specified, + * NOTE: in addition to the number of directional lights specified, * there is always 1 ambient light */ #define gSPNumLights(pkt, n) \ @@ -2604,7 +2612,7 @@ typedef union { #define LIGHT_2 2 #define LIGHT_3 3 #define LIGHT_4 4 -#define LIGHT_5 5 +#define LIGHT_5 5 #define LIGHT_6 6 #define LIGHT_7 7 #define LIGHT_8 8 @@ -2829,7 +2837,7 @@ typedef union { * min, max: range 0 to 1000: 0=nearplane, 1000=farplane * min is where fog begins (usually less than max and often 0) * max is where fog is thickest (usually 1000) - * + * */ #define gSPFogFactor(pkt, fm, fo) \ gMoveWd(pkt, G_MW_FOG, G_MWO_FOG, \ @@ -2869,7 +2877,7 @@ typedef union { _SHIFTL((level),11,3) | _SHIFTL((tile),8,3) | _SHIFTL((on),1,7)),\ (_SHIFTL((s),16,16) | _SHIFTL((t),0,16)) \ }} -/* +/* * Different version of SPTexture macro, has an additional parameter * which is currently reserved in the microcode. */ @@ -2908,7 +2916,7 @@ typedef union { _SHIFTL((level),11,3)|_SHIFTL((tile),8,3)|_SHIFTL((on),0,8)), \ (_SHIFTL((s),16,16)|_SHIFTL((t),0,16)) \ }} -/* +/* * Different version of SPTexture macro, has an additional parameter * which is currently reserved in the microcode. */ @@ -3135,7 +3143,7 @@ typedef union { gsSPSetOtherMode(G_SETOTHERMODE_H, G_MDSFT_ALPHADITHER, 2, mode) #endif -/* 'blendmask' is not supported anymore. +/* 'blendmask' is not supported anymore. * The bits are reserved for future use. * Fri May 26 13:45:55 PDT 1995 */ @@ -3341,7 +3349,7 @@ typedef union { * * This command makes all othermode parameters set. * Do not use this command in the same DL with another g*SPSetOtherMode DLs. - * + * * [Usage] * gDPSetOtherMode(pkt, modeA, modeB) * @@ -3594,9 +3602,9 @@ typedef union { ((height)-1) << G_TEXTURE_IMAGE_FRAC) \ } -/* +/* * Allow tmem address and render tile to be specified. - * The S at the end means odd lines are already word Swapped + * The S at the end means odd lines are already word Swapped */ #define gDPLoadMultiBlockS(pkt, timg, tmem, rtile, fmt, siz, width, \ height, pal, cms, cmt, masks, maskt, shifts, shiftt) \ @@ -3812,13 +3820,13 @@ typedef union { ((width)-1) << G_TEXTURE_IMAGE_FRAC, \ ((height)-1) << G_TEXTURE_IMAGE_FRAC) -/* +/* * Allows tmem and render tile to be specified. Useful when loading * several tiles at a time. * * Here is the static form of the pre-swapped texture block loading * See gDPLoadTextureBlockS() for reference. Basically, just don't - * calculate DxT, use 0 + * calculate DxT, use 0 */ #define gsDPLoadMultiBlockS(timg, tmem, rtile, fmt, siz, width, height, \ @@ -3902,7 +3910,7 @@ typedef union { } /* - * 4-bit load block. Allows tmem and render tile to be specified. Useful when + * 4-bit load block. Allows tmem and render tile to be specified. Useful when * loading multiple tiles. The S means odd lines are already word swapped. */ #define gDPLoadMultiBlock_4bS(pkt, timg, tmem, rtile, fmt, width, height,\ @@ -4337,7 +4345,7 @@ typedef union { G_IM_FMT_RGBA, G_IM_SIZ_16b, 4*16, 1, \ pal, 0, 0, 0, 0, 0, 0) -#endif /* _HW_VERSION_1 */ +#endif /* _HW_VERSION_1 */ /* * Load a 256-entry palette (for 8-bit CI textures) @@ -4379,7 +4387,7 @@ typedef union { gsDPLoadSync(), \ gsDPLoadTLUTCmd(G_TX_LOADTILE, 255), \ gsDPPipeSync() - + #else /* **** WORKAROUND hardware 1 load_tlut bug ****** */ #define gsDPLoadTLUT_pal256(dram) \ @@ -4434,7 +4442,7 @@ typedef union { G_IM_FMT_RGBA, G_IM_SIZ_16b, 4, count, \ 0, 0, 0, 0, 0, 0, 0) -#endif /* _HW_VERSION_1 */ +#endif /* _HW_VERSION_1 */ #define gDPSetScissor(pkt, mode, ulx, uly, lrx, lry) \ { \ @@ -4611,7 +4619,7 @@ typedef union { }} /* Notice that textured rectangles are 128-bit commands, therefore - * gsDPTextureRectangle() should not be used in display lists + * gsDPTextureRectangle() should not be used in display lists * under normal circumstances (use gsSPTextureRectangle()). * That is also why there is no gDPTextureRectangle() macros. */ diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 65627bab..3c31b145 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -78,52 +78,6 @@ struct RenderModeContainer { }; /* Rendermode settings for cycle 1 for all 8 layers. */ -#ifdef DISABLE_AA -struct RenderModeContainer renderModeTable_1Cycle[2] = { { { - G_RM_OPA_SURF, - G_RM_AA_OPA_SURF, - G_RM_AA_OPA_SURF, - G_RM_AA_OPA_SURF, - G_RM_AA_TEX_EDGE, - G_RM_AA_XLU_SURF, - G_RM_AA_XLU_SURF, - G_RM_AA_XLU_SURF, - } }, - { { - /* z-buffered */ - G_RM_ZB_OPA_SURF, - G_RM_ZB_OPA_SURF, - G_RM_ZB_OPA_DECAL, - G_RM_AA_ZB_OPA_INTER, - G_RM_AA_ZB_TEX_EDGE, - G_RM_ZB_XLU_SURF, - G_RM_ZB_XLU_DECAL, - G_RM_AA_ZB_XLU_INTER, - } } }; - -/* Rendermode settings for cycle 2 for all 8 layers. */ -struct RenderModeContainer renderModeTable_2Cycle[2] = { { { - G_RM_OPA_SURF2, - G_RM_AA_OPA_SURF2, - G_RM_AA_OPA_SURF2, - G_RM_AA_OPA_SURF2, - G_RM_AA_TEX_EDGE2, - G_RM_AA_XLU_SURF2, - G_RM_AA_XLU_SURF2, - G_RM_AA_XLU_SURF2, - } }, - { { - /* z-buffered */ - G_RM_ZB_OPA_SURF2, - G_RM_ZB_OPA_SURF2, - G_RM_ZB_OPA_DECAL2, - G_RM_AA_ZB_OPA_INTER2, - G_RM_AA_ZB_TEX_EDGE2, - G_RM_ZB_XLU_SURF2, - G_RM_ZB_XLU_DECAL2, - G_RM_AA_ZB_XLU_INTER2, - } } }; -#else struct RenderModeContainer renderModeTable_1Cycle[2] = { { { G_RM_OPA_SURF, G_RM_AA_OPA_SURF, @@ -168,7 +122,6 @@ struct RenderModeContainer renderModeTable_2Cycle[2] = { { { G_RM_AA_ZB_XLU_DECAL2, G_RM_AA_ZB_XLU_INTER2, } } }; -#endif struct GraphNodeRoot *gCurGraphNodeRoot = NULL; struct GraphNodeMasterList *gCurGraphNodeMasterList = NULL; @@ -333,7 +286,7 @@ static void geo_process_level_of_detail(struct GraphNodeLevelOfDetail *node) { #else distanceFromCam = -gMatStack[gMatStackIndex][3][2]; #endif - + if ((f32)node->minDistance <= distanceFromCam && distanceFromCam < (f32)node->maxDistance) { if (node->node.children != 0) { geo_process_node_and_siblings(node->node.children);