diff --git a/src/engine/extended_bounds.h b/src/engine/extended_bounds.h index 3acb24c7..591a183e 100644 --- a/src/engine/extended_bounds.h +++ b/src/engine/extended_bounds.h @@ -21,10 +21,10 @@ level boundaries are 4 times as big (-32768 to 32767) Collision calculations remain as fast as vanilla, at the cost of using far more RAM (16 times vanilla). 64x64 collision cells. - - If you see "SURFACE POOL FULL" or "SURFACE NODE POOL FULL" in game, you should increase - SURFACE_POOL_SIZE or SURFACE_NODE_POOL_SIZE, respectively, or reduce the amount of + + If you see "SURFACE POOL FULL" or "SURFACE NODE POOL FULL" in game, you should increase + SURFACE_POOL_SIZE or SURFACE_NODE_POOL_SIZE, respectively, or reduce the amount of collision surfaces in your level. */ @@ -55,22 +55,18 @@ #undef LEVEL_BOUNDARY_MAX // Undefine the old value to avoid compiler warnings #define LEVEL_BOUNDARY_MAX 0x2000L #define CELL_SIZE 0x400 - #define WORLD_SCALE 1.f #elif EXTENDED_BOUNDS_MODE == 1 #undef LEVEL_BOUNDARY_MAX #define LEVEL_BOUNDARY_MAX 0x4000L #define CELL_SIZE 0x400 - #define WORLD_SCALE 2.f #elif EXTENDED_BOUNDS_MODE == 2 #undef LEVEL_BOUNDARY_MAX #define LEVEL_BOUNDARY_MAX 0x2000L #define CELL_SIZE 0x200 - #define WORLD_SCALE 1.f #elif EXTENDED_BOUNDS_MODE == 3 #undef LEVEL_BOUNDARY_MAX #define LEVEL_BOUNDARY_MAX 0x8000L #define CELL_SIZE 0x400 - #define WORLD_SCALE 4.f #endif STATIC_ASSERT(LEVEL_BOUNDARY_MAX != 0, "You must set a valid extended bounds mode!"); diff --git a/src/engine/math_util.c b/src/engine/math_util.c index 76084582..25db470f 100644 --- a/src/engine/math_util.c +++ b/src/engine/math_util.c @@ -8,6 +8,7 @@ #include "trig_tables.inc.c" #include "surface_load.h" #include "game/puppyprint.h" +#include "game/rendering_graph_node.h" #include "config.h" @@ -583,7 +584,7 @@ void mtxf_to_mtx(Mtx *dest, Mat4 src) { for( i = 0; i < 4; i++ ) { for( j = 0; j < 3; j++ ) { - temp[i][j] = src[i][j] / WORLD_SCALE; + temp[i][j] = src[i][j] / gWorldScale; } temp[i][3] = src[i][3]; } diff --git a/src/game/puppycam2.c b/src/game/puppycam2.c index a774c239..2fb9fb9b 100644 --- a/src/game/puppycam2.c +++ b/src/game/puppycam2.c @@ -1,4 +1,4 @@ -///Puppycam 2.1 by Fazana +///Puppycam 2.2 by Fazana #include #include @@ -198,7 +198,82 @@ void puppycam_activate_cutscene(s32 *scene, s32 lockinput) gPuppyCam.sceneInput = lockinput; } -static void newcam_process_cutscene(void) +//If you've read camera.c this will look familiar. +//It takes the next 4 spline points and extrapolates a curvature based positioning of the camera vector that's passed through. +//It's a standard B spline +static void puppycam_evaluate_spline(f32 progress, Vec3s cameraPos, Vec3f spline1, Vec3f spline2, Vec3f spline3, Vec3f spline4) +{ + f32 tempP[4]; + + if (progress > 1.0f) { + progress = 1.0f; + } + + tempP[0] = (1.0f - progress) * (1.0f - progress) * (1.0f - progress) / 6.0f; + tempP[1] = progress * progress * progress / 2.0f - progress * progress + 0.6666667f; + tempP[2] = -progress * progress * progress / 2.0f + progress * progress / 2.0f + progress / 2.0f + 0.16666667f; + tempP[3] = progress * progress * progress / 6.0f; + + cameraPos[0] = tempP[0] * spline1[0] + tempP[1] * spline2[0] + tempP[2] * spline3[0] + tempP[3] * spline4[0]; + cameraPos[1] = tempP[0] * spline1[1] + tempP[1] * spline2[1] + tempP[2] * spline3[1] + tempP[3] * spline4[1]; + cameraPos[2] = tempP[0] * spline1[2] + tempP[1] * spline2[2] + tempP[2] * spline3[2] + tempP[3] * spline4[2]; +} + +s32 puppycam_move_spline(struct sPuppySpline splinePos[], struct sPuppySpline splineFocus[], s32 mode, s32 index) +{ + Vec3f tempPoints[4]; + f32 tempProgress[2] = {0.0f, 0.0f}; + f32 progChange = 0.0f; + s32 i; + Vec3f prevPos; + + if (gPuppyCam.splineIndex == 65000) + gPuppyCam.splineIndex = index; + + if (splinePos[gPuppyCam.splineIndex].index == -1 || splinePos[gPuppyCam.splineIndex + 1].index == -1 || splinePos[gPuppyCam.splineIndex + 2].index == -1) + return 1; + if (mode == PUPPYSPLINE_FOLLOW) + if (splineFocus[gPuppyCam.splineIndex].index == -1 || splineFocus[gPuppyCam.splineIndex + 1].index == -1 || splineFocus[gPuppyCam.splineIndex + 2].index == -1) + return 1; + + vec3f_set(prevPos, gPuppyCam.pos[0], gPuppyCam.pos[1], gPuppyCam.pos[2]); + + for (i = 0; i < 4; i++) + vec3f_set(tempPoints[i], splinePos[gPuppyCam.splineIndex + i].pos[0], splinePos[gPuppyCam.splineIndex + i].pos[1], splinePos[gPuppyCam.splineIndex + i].pos[2]); + puppycam_evaluate_spline(gPuppyCam.splineProgress, gPuppyCam.pos, tempPoints[0], tempPoints[1], tempPoints[2], tempPoints[3]); + if (mode == PUPPYSPLINE_FOLLOW) + { + for (i = 0; i < 4; i++) + vec3f_set(tempPoints[i], splineFocus[gPuppyCam.splineIndex + i].pos[0], splineFocus[gPuppyCam.splineIndex + i].pos[1], splineFocus[gPuppyCam.splineIndex + i].pos[2]); + puppycam_evaluate_spline(gPuppyCam.splineProgress, gPuppyCam.focus, tempPoints[0], tempPoints[1], tempPoints[2], tempPoints[3]); + } + + if (splinePos[gPuppyCam.splineIndex+1].speed != 0) { + tempProgress[0] = 1.0f / splinePos[gPuppyCam.splineIndex+1].speed; + } + if (splinePos[gPuppyCam.splineIndex+2].speed != 0) { + tempProgress[1] = 1.0f / splinePos[gPuppyCam.splineIndex+2].speed; + } + progChange = (tempProgress[1] - tempProgress[0]) * gPuppyCam.splineProgress + tempProgress[0]; + + gPuppyCam.splineProgress += progChange; + + if (gPuppyCam.splineProgress >= 1.0f) + { + gPuppyCam.splineIndex++; + if (splinePos[gPuppyCam.splineIndex+3].index == -1) + { + gPuppyCam.splineIndex = 0; + gPuppyCam.splineProgress = 0; + return 1; + } + gPuppyCam.splineProgress -=1; + } + + return 0; +} + +static void puppycam_process_cutscene(void) { if (gPuppyCam.cutscene) { @@ -446,6 +521,8 @@ void puppycam_reset_values(void) gPuppyCam.floorY[0] = 0; gPuppyCam.floorY[1] = 0; gPuppyCam.terrainPitch = 0; + gPuppyCam.splineIndex = 0; + gPuppyCam.splineProgress = 0; } //Set up values. Runs on level load. @@ -615,7 +692,7 @@ static void puppycam_input_hold_preset2(f32 ivX) } //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) +static void puppycam_input_hold_preset3(void) { f32 stickMag[2] = {gPlayer1Controller->rawStickX*0.65f, gPlayer1Controller->rawStickY*0.2f}; //Just in case it happens to be nonzero. @@ -741,7 +818,7 @@ static void puppycam_input_hold(void) { 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; + case 2: puppycam_input_hold_preset3(); puppycam_input_centre(); break; } } else @@ -972,6 +1049,35 @@ static s32 puppycam_check_volume_bounds(struct sPuppyVolume *volume, s32 index) return FALSE; } +//Handles wall adjustment when wall kicking. +void puppycam_wall_angle(void) +{ + struct Surface *wall; + struct WallCollisionData cData; + s16 wallYaw; + + if (!(gMarioState->action & ACT_WALL_KICK_AIR) || ((gMarioState->action & ACT_FLAG_AIR) && ABS(gMarioState->forwardVel) < 16.0f) || !(gMarioState->action & ACT_FLAG_AIR)) + return; + + cData.x = gPuppyCam.targetObj->oPosX; + cData.y = gPuppyCam.targetObj->oPosY; + cData.z = gPuppyCam.targetObj->oPosZ; + cData.radius = 150.0f; + cData.offsetY = 0; + + if (find_wall_collisions(&cData)) + wall = cData.walls[cData.numWalls - 1]; + else + return; + wallYaw = atan2s(wall->normal.z, wall->normal.x) + 0x4000; + + wallYaw -= gPuppyCam.yawTarget; + if (wallYaw % 0x4000) + wallYaw += 0x4000 - wallYaw % 0x4000; + + gPuppyCam.yawTarget = approach_s32(gPuppyCam.yawTarget, wallYaw, 0x200, 0x200); +} + void puppycam_projection_behaviours(void) { f32 turnRate = 1; @@ -1081,6 +1187,9 @@ void puppycam_projection_behaviours(void) //This sets a pseudo tilt offset based on the floor heights in front and behind mario. puppycam_terrain_angle(); + + //This will shift the intended yaw when wall kicking, to align with the wall being kicked. + puppycam_wall_angle(); } else { @@ -1386,7 +1495,7 @@ void puppycam_loop(void) if (gPuppyCam.cutscene) { gPuppyCam.opacity = 255; - newcam_process_cutscene(); + puppycam_process_cutscene(); } puppycam_apply(); diff --git a/src/game/puppycam2.h b/src/game/puppycam2.h index 7f8b0e9b..e094671c 100644 --- a/src/game/puppycam2.h +++ b/src/game/puppycam2.h @@ -25,6 +25,9 @@ #define PUPPYCAM_MODE3_ZOOMED_OUT 0x4 #define PUPPYCAM_MODE3_ENTER_FIRST_PERSON 0x8 +#define PUPPYSPLINE_NONE 1 //Will not write to focus at all. +#define PUPPYSPLINE_FOLLOW 2 //Focus will follow a separate spline, but will mirror the speed and progress of the pos. + #include "include/command_macros_base.h" #define PUPPYVOLUME(x, y, z, length, height, width, yaw, functionptr, anglesptr, addflags, removeflags, flagpersistance, room, shape) \ @@ -94,6 +97,8 @@ struct gPuppyStruct 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 + u16 splineIndex; //Determines which point of the spline it's at. + f32 splineProgress; //Determines how far along the index the spline is. struct gPuppyOptions options; @@ -109,6 +114,14 @@ struct sPuppyAngles s16 zoom; }; +//Structurally, it's exactly the same as CutsceneSplinePoint +struct sPuppySpline +{ + s8 index; //The index of the spline. Ends with -1 + u8 speed; //The amount of frames it takes to get through this index. + Vec3s pos; //The vector pos of the spline index itself. +}; + //A bounding volume for activating puppycamera scripts and angles. struct sPuppyVolume { @@ -172,7 +185,8 @@ 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); +extern void puppycam_warp(f32 displacementX, f32 displacementY, f32 displacementZ); +extern s32 puppycam_move_spline(struct sPuppySpline splinePos[], struct sPuppySpline splineFocus[], s32 mode, s32 index); #endif diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 5a50acf2..c1c7bfa0 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -46,6 +46,7 @@ s16 gMatStackIndex; Mat4 gMatStack[32]; Mtx *gMatStackFixed[32]; f32 aspect; +f32 gWorldScale = 1.0f; /** * Animation nodes have state in global variables, so this struct captures @@ -259,7 +260,12 @@ static void geo_process_perspective(struct GraphNodePerspective *node) { aspect = 1.33333f; #endif - guPerspective(mtx, &perspNorm, node->fov, aspect, node->near / WORLD_SCALE, node->far / WORLD_SCALE, 1.0f); + if (gCamera) + gWorldScale = MAX(((gCamera->pos[0] * gCamera->pos[0]) + (gCamera->pos[1] * gCamera->pos[1]) + (gCamera->pos[2] * gCamera->pos[2]))/67108864, 1.0f); + else + gWorldScale = 1.0f; + + guPerspective(mtx, &perspNorm, node->fov, aspect, node->near / gWorldScale, node->far / gWorldScale, 1.0f); gSPPerspNormalize(gDisplayListHead++, perspNorm); gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); diff --git a/src/game/rendering_graph_node.h b/src/game/rendering_graph_node.h index 097c7876..8c37e512 100644 --- a/src/game/rendering_graph_node.h +++ b/src/game/rendering_graph_node.h @@ -12,6 +12,7 @@ extern struct GraphNodeCamera *gCurGraphNodeCamera; extern struct GraphNodeObject *gCurGraphNodeObject; extern struct GraphNodeHeldObject *gCurGraphNodeHeldObject; extern u16 gAreaUpdateCounter; +extern f32 gWorldScale; // after processing an object, the type is reset to this #define ANIM_TYPE_NONE 0