From 02ab54b3ada42d493efdab73d2dad83753b03035 Mon Sep 17 00:00:00 2001 From: MysterD Date: Wed, 27 Apr 2022 18:25:43 -0700 Subject: [PATCH] WIP: uncapped framerate 3 --- src/game/envfx_bubbles.c | 180 +++++++++--------- src/game/envfx_snow.c | 140 ++++++++------ src/game/envfx_snow.h | 1 + src/game/hud.c | 31 +-- src/game/ingame_menu.c | 102 ++++++---- src/game/paintings.c | 89 +++++++-- src/game/rendering_graph_node.c | 4 +- src/game/screen_transition.c | 42 ++-- src/menu/intro_geo.c | 24 ++- src/pc/controller/controller_keyboard_debug.c | 6 +- src/pc/pc_main.c | 44 +++-- src/pc/utils/misc.c | 28 ++- src/pc/utils/misc.h | 6 +- 13 files changed, 437 insertions(+), 260 deletions(-) diff --git a/src/game/envfx_bubbles.c b/src/game/envfx_bubbles.c index ac34ddb4..e2245b45 100644 --- a/src/game/envfx_bubbles.c +++ b/src/game/envfx_bubbles.c @@ -11,6 +11,7 @@ #include "audio/external.h" #include "textures.h" #include "game/rendering_graph_node.h" +#include "pc/utils/misc.h" /** * This file implements environment effects that are not snow: @@ -36,17 +37,26 @@ Vtx_t gBubbleTempVtx[3] = { { { 0, 0, 0 }, 0, { -498, 964 }, { 0xFF, 0xFF, 0xFF, 0xFF } }, }; -static Gfx sGfxSaved[60 / 5]; -static Gfx *sBubbleInterpolatedDisplayListPos[60 / 5]; -static Vec3s sPrevBubblePositions[60]; +Gfx *envfx_update_bubble_particles_internal(s32 mode, UNUSED Vec3s marioPos, Vec3s camFrom, Vec3s camTo, u8 interpolated); -void patch_interpolated_bubble_particles(void) { - s32 i; - for (i = 0; i < 60 / 5; i++) { - if (sBubbleInterpolatedDisplayListPos[i] != NULL) { - *sBubbleInterpolatedDisplayListPos[i] = sGfxSaved[i]; - sBubbleInterpolatedDisplayListPos[i] = NULL; +static s32 sBubbleGfxMode; +static Gfx* sBubbleGfxPos; +static Vtx* sBubbleInternalGfxPos[65 / 5]; +static Vec3s sBubbleGfxCamFrom; +static Vec3s sBubbleGfxCamTo; + +void patch_bubble_particles_before(void) { + if (sBubbleGfxPos) { + for (s32 i = 0; i < sBubbleParticleMaxCount; i++) { + vec3s_set((gEnvFxBuffer + i)->prevPos, (gEnvFxBuffer + i)->xPos, (gEnvFxBuffer + i)->yPos, (gEnvFxBuffer + i)->zPos); } + sBubbleGfxPos = NULL; + } +} + +void patch_bubble_particles_interpolated(UNUSED f32 delta) { + if (sBubbleGfxPos) { + envfx_update_bubble_particles_internal(sBubbleGfxMode, NULL, sBubbleGfxCamFrom, sBubbleGfxCamTo, true); } } @@ -103,6 +113,7 @@ void envfx_update_flower(Vec3s centerPos) { (gEnvFxBuffer + i)->zPos, &floorGeo); (gEnvFxBuffer + i)->isAlive = 1; (gEnvFxBuffer + i)->animFrame = random_float() * 5.0f; + vec3s_set((gEnvFxBuffer + i)->prevPos, (gEnvFxBuffer + i)->xPos, (gEnvFxBuffer + i)->yPos, (gEnvFxBuffer + i)->zPos); } else if ((timer & 0x03) == 0) { (gEnvFxBuffer + i)->animFrame += 1; if ((gEnvFxBuffer + i)->animFrame > 5) { @@ -147,8 +158,7 @@ void envfx_set_lava_bubble_position(s32 index, Vec3s centerPos) { (gEnvFxBuffer + index)->zPos = -16000 - (gEnvFxBuffer + index)->zPos; } - floorY = - find_floor((gEnvFxBuffer + index)->xPos, centerY + 500, (gEnvFxBuffer + index)->zPos, &surface); + floorY = find_floor((gEnvFxBuffer + index)->xPos, centerY + 500, (gEnvFxBuffer + index)->zPos, &surface); if (surface == NULL) { (gEnvFxBuffer + index)->yPos = FLOOR_LOWER_LIMIT_MISC; return; @@ -178,6 +188,7 @@ void envfx_update_lava(Vec3s centerPos) { for (i = 0; i < sBubbleParticleMaxCount; i++) { if ((gEnvFxBuffer + i)->isAlive == 0) { envfx_set_lava_bubble_position(i, centerPos); + vec3s_set((gEnvFxBuffer + i)->prevPos, (gEnvFxBuffer + i)->xPos, (gEnvFxBuffer + i)->yPos, (gEnvFxBuffer + i)->zPos); (gEnvFxBuffer + i)->isAlive = 1; } else if ((timer & 0x01) == 0) { (gEnvFxBuffer + i)->animFrame += 1; @@ -257,10 +268,13 @@ void envfx_update_whirlpool(void) { (gEnvFxBuffer + i)->unusedBubbleVar = 0; (gEnvFxBuffer + i)->isAlive = 1; (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer; + vec3s_set((gEnvFxBuffer + i)->prevPos, (gEnvFxBuffer + i)->xPos, (gEnvFxBuffer + i)->yPos, (gEnvFxBuffer + i)->zPos); envfx_rotate_around_whirlpool(&(gEnvFxBuffer + i)->xPos, &(gEnvFxBuffer + i)->yPos, &(gEnvFxBuffer + i)->zPos); - } else { + } + + if ((gEnvFxBuffer + i)->isAlive != 0) { (gEnvFxBuffer + i)->angleAndDist[1] -= 40; (gEnvFxBuffer + i)->angleAndDist[0] += (s16)(3000 - (gEnvFxBuffer + i)->angleAndDist[1] * 2) + 0x400; @@ -307,15 +321,11 @@ void envfx_update_jetstream(void) { if ((gEnvFxBuffer + i)->isAlive == 0) { (gEnvFxBuffer + i)->angleAndDist[1] = random_float() * 300.0f; (gEnvFxBuffer + i)->angleAndDist[0] = random_u16(); - (gEnvFxBuffer + i)->xPos = - gEnvFxBubbleConfig[ENVFX_STATE_SRC_X] - + sins((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1]; - (gEnvFxBuffer + i)->zPos = - gEnvFxBubbleConfig[ENVFX_STATE_SRC_Z] - + coss((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1]; - (gEnvFxBuffer + i)->yPos = - gEnvFxBubbleConfig[ENVFX_STATE_SRC_Y] + (random_float() * 400.0f - 200.0f); + (gEnvFxBuffer + i)->xPos = gEnvFxBubbleConfig[ENVFX_STATE_SRC_X] + sins((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1]; + (gEnvFxBuffer + i)->zPos = gEnvFxBubbleConfig[ENVFX_STATE_SRC_Z] + coss((gEnvFxBuffer + i)->angleAndDist[0]) * (gEnvFxBuffer + i)->angleAndDist[1]; + (gEnvFxBuffer + i)->yPos = gEnvFxBubbleConfig[ENVFX_STATE_SRC_Y] + (random_float() * 400.0f - 200.0f); (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer; + vec3s_set((gEnvFxBuffer + i)->prevPos, (gEnvFxBuffer + i)->xPos, (gEnvFxBuffer + i)->yPos, (gEnvFxBuffer + i)->zPos); } else { (gEnvFxBuffer + i)->angleAndDist[1] += 10; (gEnvFxBuffer + i)->xPos += sins((gEnvFxBuffer + i)->angleAndDist[0]) * 10.0f; @@ -381,31 +391,31 @@ s32 envfx_init_bubble(s32 mode) { * Also sets the given vertices to the correct shape for each mode, * though they are not being rotated yet. */ -void envfx_bubbles_update_switch(s32 mode, Vec3s camTo, Vec3s vertex1, Vec3s vertex2, Vec3s vertex3) { +void envfx_bubbles_update_switch(s32 mode, Vec3s camTo, Vec3s vertex1, Vec3s vertex2, Vec3s vertex3, u8 interpolated) { switch (mode) { case ENVFX_FLOWERS: - envfx_update_flower(camTo); + if (!interpolated) { envfx_update_flower(camTo); } vertex1[0] = 50; vertex1[1] = 0; vertex1[2] = 0; vertex2[0] = 0; vertex2[1] = 75; vertex2[2] = 0; vertex3[0] = -50; vertex3[1] = 0; vertex3[2] = 0; break; case ENVFX_LAVA_BUBBLES: - envfx_update_lava(camTo); + if (!interpolated) { envfx_update_lava(camTo); } vertex1[0] = 100; vertex1[1] = 0; vertex1[2] = 0; vertex2[0] = 0; vertex2[1] = 150; vertex2[2] = 0; vertex3[0] = -100; vertex3[1] = 0; vertex3[2] = 0; break; case ENVFX_WHIRLPOOL_BUBBLES: - envfx_update_whirlpool(); + if (!interpolated) { envfx_update_whirlpool(); } vertex1[0] = 40; vertex1[1] = 0; vertex1[2] = 0; vertex2[0] = 0; vertex2[1] = 60; vertex2[2] = 0; vertex3[0] = -40; vertex3[1] = 0; vertex3[2] = 0; break; case ENVFX_JETSTREAM_BUBBLES: - envfx_update_jetstream(); + if (!interpolated) { envfx_update_jetstream(); } vertex1[0] = 40; vertex1[1] = 0; vertex1[2] = 0; vertex2[0] = 0; vertex2[1] = 60; vertex2[2] = 0; vertex3[0] = -40; vertex3[1] = 0; vertex3[2] = 0; @@ -419,9 +429,15 @@ void envfx_bubbles_update_switch(s32 mode, Vec3s camTo, Vec3s vertex1, Vec3s ver * that will be translated to bubble positions to draw the bubble image */ void append_bubble_vertex_buffer(Gfx *gfx, s32 index, Vec3s vertex1, Vec3s vertex2, Vec3s vertex3, - Vtx *template) { + Vtx *template, u8 interpolated) { s32 i = 0; - Vtx *vertBuf = alloc_display_list(15 * sizeof(Vtx)); + Vtx *vertBuf; + if (interpolated) { + vertBuf = sBubbleInternalGfxPos[index/5]; + } else { + vertBuf = alloc_display_list(15 * sizeof(Vtx)); + sBubbleInternalGfxPos[index/5] = vertBuf; + } if (vertBuf == NULL) { return; @@ -429,19 +445,37 @@ void append_bubble_vertex_buffer(Gfx *gfx, s32 index, Vec3s vertex1, Vec3s verte for (i = 0; i < 15; i += 3) { vertBuf[i] = template[0]; - (vertBuf + i)->v.ob[0] = (gEnvFxBuffer + (index + i / 3))->xPos + vertex1[0]; - (vertBuf + i)->v.ob[1] = (gEnvFxBuffer + (index + i / 3))->yPos + vertex1[1]; - (vertBuf + i)->v.ob[2] = (gEnvFxBuffer + (index + i / 3))->zPos + vertex1[2]; + s32 xPos; + s32 yPos; + s32 zPos; + + s32 particleIndex = (index + i / 3); + struct EnvFxParticle* particle = (gEnvFxBuffer + particleIndex); + + if (interpolated) { + extern f32 gRenderingDelta; + xPos = delta_interpolate_s32(particle->prevPos[0], particle->xPos, gRenderingDelta); + yPos = delta_interpolate_s32(particle->prevPos[1], particle->yPos, gRenderingDelta); + zPos = delta_interpolate_s32(particle->prevPos[2], particle->zPos, gRenderingDelta); + } else { + xPos = particle->prevPos[0]; + yPos = particle->prevPos[1]; + zPos = particle->prevPos[2]; + } + + (vertBuf + i)->v.ob[0] = xPos + vertex1[0]; + (vertBuf + i)->v.ob[1] = yPos + vertex1[1]; + (vertBuf + i)->v.ob[2] = zPos + vertex1[2]; vertBuf[i + 1] = template[1]; - (vertBuf + i + 1)->v.ob[0] = (gEnvFxBuffer + (index + i / 3))->xPos + vertex2[0]; - (vertBuf + i + 1)->v.ob[1] = (gEnvFxBuffer + (index + i / 3))->yPos + vertex2[1]; - (vertBuf + i + 1)->v.ob[2] = (gEnvFxBuffer + (index + i / 3))->zPos + vertex2[2]; + (vertBuf + i + 1)->v.ob[0] = xPos + vertex2[0]; + (vertBuf + i + 1)->v.ob[1] = yPos + vertex2[1]; + (vertBuf + i + 1)->v.ob[2] = zPos + vertex2[2]; vertBuf[i + 2] = template[2]; - (vertBuf + i + 2)->v.ob[0] = (gEnvFxBuffer + (index + i / 3))->xPos + vertex3[0]; - (vertBuf + i + 2)->v.ob[1] = (gEnvFxBuffer + (index + i / 3))->yPos + vertex3[1]; - (vertBuf + i + 2)->v.ob[2] = (gEnvFxBuffer + (index + i / 3))->zPos + vertex3[2]; + (vertBuf + i + 2)->v.ob[0] = xPos + vertex3[0]; + (vertBuf + i + 2)->v.ob[1] = yPos + vertex3[1]; + (vertBuf + i + 2)->v.ob[2] = zPos + vertex3[2]; } gSPVertex(gfx, VIRTUAL_TO_PHYSICAL(vertBuf), 15, 0); @@ -478,28 +512,25 @@ void envfx_set_bubble_texture(s32 mode, s16 index) { gSPDisplayList(sGfxCursor++, &tiny_bubble_dl_0B006D68); } -/** - * Updates the bubble particle positions, then generates and returns a display - * list drawing them. - */ -Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFrom, Vec3s camTo) { +Gfx *envfx_update_bubble_particles_internal(s32 mode, UNUSED Vec3s marioPos, Vec3s camFrom, Vec3s camTo, u8 interpolated) { s32 i; s16 radius, pitch, yaw; Vec3s vertex1 = { 0 }; Vec3s vertex2 = { 0 }; Vec3s vertex3 = { 0 }; - Vec3s interpolatedVertices[3] = { 0 }; - - static Vec3s prevVertex1; - static Vec3s prevVertex2; - static Vec3s prevVertex3; - static u32 prevTimestamp; Gfx *gfxStart; + if (interpolated) { + gfxStart = sBubbleGfxPos; + } else { + gfxStart = alloc_display_list(((sBubbleParticleMaxCount / 5) * 10 + sBubbleParticleMaxCount + 3) * sizeof(Gfx)); + sBubbleGfxPos = gfxStart; + sBubbleGfxMode = mode; + vec3s_copy(sBubbleGfxCamFrom, camFrom); + vec3s_copy(sBubbleGfxCamTo, camTo); + } - gfxStart = alloc_display_list(((sBubbleParticleMaxCount / 5) * 10 + sBubbleParticleMaxCount + 3) - * sizeof(Gfx)); if (gfxStart == NULL) { return NULL; } @@ -507,60 +538,21 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro sGfxCursor = gfxStart; orbit_from_positions(camTo, camFrom, &radius, &pitch, &yaw); - envfx_bubbles_update_switch(mode, camTo, vertex1, vertex2, vertex3); + envfx_bubbles_update_switch(mode, camTo, vertex1, vertex2, vertex3, interpolated); rotate_triangle_vertices(vertex1, vertex2, vertex3, pitch, yaw); - if (gGlobalTimer == prevTimestamp + 1) { - // TODO: fixme - //interpolate_vectors_s16(interpolatedVertices[0], prevVertex1, vertex1); - vec3s_copy(interpolatedVertices[0], vertex1); - //interpolate_vectors_s16(interpolatedVertices[1], prevVertex2, vertex2); - vec3s_copy(interpolatedVertices[1], vertex2); - //interpolate_vectors_s16(interpolatedVertices[2], prevVertex3, vertex3); - vec3s_copy(interpolatedVertices[2], vertex3); - } - vec3s_copy(prevVertex1, vertex1); - vec3s_copy(prevVertex2, vertex2); - vec3s_copy(prevVertex3, vertex3); - prevTimestamp = gGlobalTimer; - gSPDisplayList(sGfxCursor++, &tiny_bubble_dl_0B006D38); for (i = 0; i < sBubbleParticleMaxCount; i += 5) { - Vtx *interpolatedVertBuf = alloc_display_list(15 * sizeof(Vtx)); - if (interpolatedVertBuf == NULL) { continue; } - s32 j, k; gDPPipeSync(sGfxCursor++); envfx_set_bubble_texture(mode, i); - sBubbleInterpolatedDisplayListPos[i / 5] = sGfxCursor; - for (j = 0; j < 5; j++) { - for (k = 0; k < 3; k++) { - Vtx *v = &interpolatedVertBuf[j * 3 + k]; - v->v = gBubbleTempVtx[k]; - if (gGlobalTimer != gEnvFxBuffer[i + j].spawnTimestamp && mode != ENVFX_LAVA_BUBBLES) { - v->v.ob[0] = (sPrevBubblePositions[i + j][0] + gEnvFxBuffer[i + j].xPos) / 2.0f + interpolatedVertices[k][0]; - v->v.ob[1] = (sPrevBubblePositions[i + j][1] + gEnvFxBuffer[i + j].yPos) / 2.0f + interpolatedVertices[k][1]; - v->v.ob[2] = (sPrevBubblePositions[i + j][2] + gEnvFxBuffer[i + j].zPos) / 2.0f + interpolatedVertices[k][2]; - } else { - v->v.ob[0] = gEnvFxBuffer[i + j].xPos + interpolatedVertices[k][0]; - v->v.ob[1] = gEnvFxBuffer[i + j].yPos + interpolatedVertices[k][1]; - v->v.ob[2] = gEnvFxBuffer[i + j].zPos + interpolatedVertices[k][2]; - } - } - } - gSPVertex(sGfxCursor++, VIRTUAL_TO_PHYSICAL(interpolatedVertBuf), 15, 0); - append_bubble_vertex_buffer(&sGfxSaved[i / 5], i, vertex1, vertex2, vertex3, (Vtx *) gBubbleTempVtx); + append_bubble_vertex_buffer(sGfxCursor++, i, vertex1, vertex2, vertex3, (Vtx *) gBubbleTempVtx, interpolated); gSP1Triangle(sGfxCursor++, 0, 1, 2, 0); gSP1Triangle(sGfxCursor++, 3, 4, 5, 0); gSP1Triangle(sGfxCursor++, 6, 7, 8, 0); gSP1Triangle(sGfxCursor++, 9, 10, 11, 0); gSP1Triangle(sGfxCursor++, 12, 13, 14, 0); } - for (i = 0; i < sBubbleParticleMaxCount; i++) { - sPrevBubblePositions[i][0] = gEnvFxBuffer[i].xPos; - sPrevBubblePositions[i][1] = gEnvFxBuffer[i].yPos; - sPrevBubblePositions[i][2] = gEnvFxBuffer[i].zPos; - } gSPDisplayList(sGfxCursor++, &tiny_bubble_dl_0B006AB0); gSPEndDisplayList(sGfxCursor++); @@ -568,6 +560,14 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro return gfxStart; } +/** + * Updates the bubble particle positions, then generates and returns a display + * list drawing them. + */ +Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFrom, Vec3s camTo) { + return envfx_update_bubble_particles_internal(mode,marioPos, camFrom, camTo, false); +} + /** * Set the maximum particle count from the gEnvFxBubbleConfig variable, * which is set by the whirlpool or jet stream behavior. diff --git a/src/game/envfx_snow.c b/src/game/envfx_snow.c index d36c5178..23cba4d2 100644 --- a/src/game/envfx_snow.c +++ b/src/game/envfx_snow.c @@ -11,6 +11,7 @@ #include "engine/behavior_script.h" #include "audio/external.h" #include "obj_behaviors.h" +#include "pc/utils/misc.h" /** * This file contains the function that handles 'environment effects', @@ -54,23 +55,27 @@ extern void *tiny_bubble_dl_0B006AB0; extern void *tiny_bubble_dl_0B006A50; extern void *tiny_bubble_dl_0B006CD8; -static struct { - Gfx *pos; - Vtx vertices[15]; -} sPrevSnowVertices[140 / 5]; -static s16 sPrevSnowParticleCount; -static u32 sPrevSnowTimestamp; +Gfx *envfx_update_snow_internal(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo, u8 interpolated); -void patch_interpolated_snow_particles(void) { - int i; +static s32 sSnowGfxMode; +static Gfx* sSnowGfxPos; +static Vtx* sSnowInternalGfxPos[140 / 5]; +static Vec3s sSnowGfxCamFrom; +static Vec3s sSnowGfxCamTo; +static Vec3s sSnowGfxMarioPos; - if (gGlobalTimer != sPrevSnowTimestamp + 1) { - return; +void patch_snow_particles_before(void) { + if (sSnowGfxPos) { + for (s32 i = 0; i < gSnowParticleCount; i++) { + vec3s_set((gEnvFxBuffer + i)->prevPos, (gEnvFxBuffer + i)->xPos, (gEnvFxBuffer + i)->yPos, (gEnvFxBuffer + i)->zPos); + } + sSnowGfxPos = NULL; } +} - for (i = 0; i < sPrevSnowParticleCount; i += 5) { - gSPVertex(sPrevSnowVertices[i / 5].pos, - VIRTUAL_TO_PHYSICAL(sPrevSnowVertices[i / 5].vertices), 15, 0); +void patch_snow_particles_interpolated(UNUSED f32 delta) { + if (sSnowGfxPos) { + envfx_update_snow_internal(sSnowGfxMode, sSnowGfxMarioPos, sSnowGfxCamFrom, sSnowGfxCamTo, true); } } @@ -238,6 +243,7 @@ void envfx_update_snow_normal(s32 snowCylinderX, s32 snowCylinderY, s32 snowCyli (gEnvFxBuffer + i)->yPos = 200.0f * random_float() + snowCylinderY; (gEnvFxBuffer + i)->isAlive = 1; (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer; + vec3s_set((gEnvFxBuffer + i)->prevPos, (gEnvFxBuffer + i)->xPos, (gEnvFxBuffer + i)->yPos, (gEnvFxBuffer + i)->zPos); } else { (gEnvFxBuffer + i)->xPos += random_float() * 2 - 1.0f + (s16)(deltaX / 1.2); (gEnvFxBuffer + i)->yPos -= 2 -(s16)(deltaY * 0.8); @@ -273,6 +279,7 @@ void envfx_update_snow_blizzard(s32 snowCylinderX, s32 snowCylinderY, s32 snowCy (gEnvFxBuffer + i)->yPos = 400.0f * random_float() - 200.0f + snowCylinderY; (gEnvFxBuffer + i)->isAlive = 1; (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer; + vec3s_set((gEnvFxBuffer + i)->prevPos, (gEnvFxBuffer + i)->xPos, (gEnvFxBuffer + i)->yPos, (gEnvFxBuffer + i)->zPos); } else { (gEnvFxBuffer + i)->xPos += random_float() * 2 - 1.0f + (s16)(deltaX / 1.2) + 20.0f; (gEnvFxBuffer + i)->yPos -= 5 -(s16)(deltaY * 0.8); @@ -317,6 +324,7 @@ void envfx_update_snow_water(s32 snowCylinderX, s32 snowCylinderY, s32 snowCylin (gEnvFxBuffer + i)->yPos = 400.0f * random_float() - 200.0f + snowCylinderY; (gEnvFxBuffer + i)->isAlive = 1; (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer; + vec3s_set((gEnvFxBuffer + i)->prevPos, (gEnvFxBuffer + i)->xPos, (gEnvFxBuffer + i)->yPos, (gEnvFxBuffer + i)->zPos); } } } @@ -364,57 +372,61 @@ void rotate_triangle_vertices(Vec3s vertex1, Vec3s vertex2, Vec3s vertex3, s16 p * around (0,0,0) that will be translated to snowflake positions to draw the * snowflake image. */ -void append_snowflake_vertex_buffer(Gfx *gfx, s32 index, Vec3s vertex1, Vec3s vertex2, Vec3s vertex3) { +void append_snowflake_vertex_buffer(Gfx *gfx, s32 index, Vec3s vertex1, Vec3s vertex2, Vec3s vertex3, u8 interpolated) { s32 i = 0; - Vtx *vertBuf = (Vtx *) alloc_display_list(15 * sizeof(Vtx)); - Vtx *vertBufInterpolated = (Vtx *) alloc_display_list(15 * sizeof(Vtx)); - Vtx *v; + Vtx *vertBuf; - if (vertBuf == NULL || vertBufInterpolated == NULL) { + if (interpolated) { + vertBuf = sSnowInternalGfxPos[index/5]; + } else { + vertBuf = (Vtx *) alloc_display_list(15 * sizeof(Vtx)); + sSnowInternalGfxPos[index/5] = vertBuf; + } + + if (vertBuf == NULL) { return; } for (i = 0; i < 15; i += 3) { vertBuf[i] = gSnowTempVtx[0]; - (vertBuf + i)->v.ob[0] = (gEnvFxBuffer + (index + i / 3))->xPos + vertex1[0]; - (vertBuf + i)->v.ob[1] = (gEnvFxBuffer + (index + i / 3))->yPos + vertex1[1]; - (vertBuf + i)->v.ob[2] = (gEnvFxBuffer + (index + i / 3))->zPos + vertex1[2]; + + s32 xPos; + s32 yPos; + s32 zPos; + s32 particleIndex = (index + i / 3); + struct EnvFxParticle* particle = (gEnvFxBuffer + particleIndex); + + if (interpolated) { + extern f32 gRenderingDelta; + xPos = delta_interpolate_s32(particle->prevPos[0], particle->xPos, gRenderingDelta); + yPos = delta_interpolate_s32(particle->prevPos[1], particle->yPos, gRenderingDelta); + zPos = delta_interpolate_s32(particle->prevPos[2], particle->zPos, gRenderingDelta); + } else { + xPos = particle->prevPos[0]; + yPos = particle->prevPos[1]; + zPos = particle->prevPos[2]; + } + + (vertBuf + i)->v.ob[0] = xPos + vertex1[0]; + (vertBuf + i)->v.ob[1] = yPos + vertex1[1]; + (vertBuf + i)->v.ob[2] = zPos + vertex1[2]; vertBuf[i + 1] = gSnowTempVtx[1]; - (vertBuf + i + 1)->v.ob[0] = (gEnvFxBuffer + (index + i / 3))->xPos + vertex2[0]; - (vertBuf + i + 1)->v.ob[1] = (gEnvFxBuffer + (index + i / 3))->yPos + vertex2[1]; - (vertBuf + i + 1)->v.ob[2] = (gEnvFxBuffer + (index + i / 3))->zPos + vertex2[2]; + (vertBuf + i + 1)->v.ob[0] = xPos + vertex2[0]; + (vertBuf + i + 1)->v.ob[1] = yPos + vertex2[1]; + (vertBuf + i + 1)->v.ob[2] = zPos + vertex2[2]; vertBuf[i + 2] = gSnowTempVtx[2]; - (vertBuf + i + 2)->v.ob[0] = (gEnvFxBuffer + (index + i / 3))->xPos + vertex3[0]; - (vertBuf + i + 2)->v.ob[1] = (gEnvFxBuffer + (index + i / 3))->yPos + vertex3[1]; - (vertBuf + i + 2)->v.ob[2] = (gEnvFxBuffer + (index + i / 3))->zPos + vertex3[2]; + (vertBuf + i + 2)->v.ob[0] = xPos + vertex3[0]; + (vertBuf + i + 2)->v.ob[1] = yPos + vertex3[1]; + (vertBuf + i + 2)->v.ob[2] = zPos + vertex3[2]; } - for (i = 0; i < 15; i++) { - v = &sPrevSnowVertices[index / 5].vertices[i]; - vertBufInterpolated[i] = gSnowTempVtx[i % 3]; - if (index < sPrevSnowParticleCount && gGlobalTimer == sPrevSnowTimestamp + 1 && - gGlobalTimer != gEnvFxBuffer[index + i / 3].spawnTimestamp) { - vertBufInterpolated[i].v.ob[0] = (v->v.ob[0] + vertBuf[i].v.ob[0]) / 2; - vertBufInterpolated[i].v.ob[1] = (v->v.ob[1] + vertBuf[i].v.ob[1]) / 2; - vertBufInterpolated[i].v.ob[2] = (v->v.ob[2] + vertBuf[i].v.ob[2]) / 2; - } else { - vertBufInterpolated[i].v.ob[0] = vertBuf[i].v.ob[0]; - vertBufInterpolated[i].v.ob[1] = vertBuf[i].v.ob[1]; - vertBufInterpolated[i].v.ob[2] = vertBuf[i].v.ob[2]; - } - *v = vertBuf[i]; - } - sPrevSnowVertices[index / 5].pos = gfx; - gSPVertex(gfx, VIRTUAL_TO_PHYSICAL(vertBufInterpolated), 15, 0); + gSPVertex(gfx, VIRTUAL_TO_PHYSICAL(vertBuf), 15, 0); } -/** - * Updates positions of snow particles and returns a pointer to a display list - * drawing all snowflakes. - */ -Gfx *envfx_update_snow(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo) { + +Gfx *envfx_update_snow_internal(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo, u8 interpolated) { s32 i; s16 radius, pitch, yaw; Vec3s snowCylinderPos; @@ -426,7 +438,17 @@ Gfx *envfx_update_snow(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo) vertex2 = gSnowFlakeVertex2; vertex3 = gSnowFlakeVertex3; - gfxStart = (Gfx *) alloc_display_list((gSnowParticleCount * 6 + 3) * sizeof(Gfx)); + if (interpolated) { + gfxStart = sSnowGfxPos; + } else { + gfxStart = (Gfx *) alloc_display_list((gSnowParticleCount * 6 + 3) * sizeof(Gfx)); + sSnowGfxPos = gfxStart; + sSnowGfxMode = snowMode; + vec3s_copy(sSnowGfxMarioPos, marioPos); + vec3s_copy(sSnowGfxCamFrom, camFrom); + vec3s_copy(sSnowGfxCamTo, camTo); + } + gfx = gfxStart; if (gfxStart == NULL) { @@ -449,7 +471,7 @@ Gfx *envfx_update_snow(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo) } pos_from_orbit(camTo, snowCylinderPos, radius, pitch, yaw); - envfx_update_snow_normal(snowCylinderPos[0], snowCylinderPos[1], snowCylinderPos[2]); + if (!interpolated) { envfx_update_snow_normal(snowCylinderPos[0], snowCylinderPos[1], snowCylinderPos[2]); } break; case ENVFX_SNOW_WATER: @@ -460,7 +482,7 @@ Gfx *envfx_update_snow(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo) } pos_from_orbit(camTo, snowCylinderPos, radius, pitch, yaw); - envfx_update_snow_water(snowCylinderPos[0], snowCylinderPos[1], snowCylinderPos[2]); + if (!interpolated) { envfx_update_snow_water(snowCylinderPos[0], snowCylinderPos[1], snowCylinderPos[2]); } break; case ENVFX_SNOW_BLIZZARD: if (radius > 250) { @@ -470,7 +492,7 @@ Gfx *envfx_update_snow(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo) } pos_from_orbit(camTo, snowCylinderPos, radius, pitch, yaw); - envfx_update_snow_blizzard(snowCylinderPos[0], snowCylinderPos[1], snowCylinderPos[2]); + if (!interpolated) { envfx_update_snow_blizzard(snowCylinderPos[0], snowCylinderPos[1], snowCylinderPos[2]); } break; } @@ -483,7 +505,7 @@ Gfx *envfx_update_snow(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo) } for (i = 0; i < gSnowParticleCount; i += 5) { - append_snowflake_vertex_buffer(gfx++, i, (s16 *) &vertex1, (s16 *) &vertex2, (s16 *) &vertex3); + append_snowflake_vertex_buffer(gfx++, i, (s16 *) &vertex1, (s16 *) &vertex2, (s16 *) &vertex3, interpolated); gSP1Triangle(gfx++, 0, 1, 2, 0); gSP1Triangle(gfx++, 3, 4, 5, 0); @@ -491,14 +513,20 @@ Gfx *envfx_update_snow(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo) gSP1Triangle(gfx++, 9, 10, 11, 0); gSP1Triangle(gfx++, 12, 13, 14, 0); } - sPrevSnowParticleCount = gSnowParticleCount; - sPrevSnowTimestamp = gGlobalTimer; gSPDisplayList(gfx++, &tiny_bubble_dl_0B006AB0) gSPEndDisplayList(gfx++); return gfxStart; } +/** + * Updates positions of snow particles and returns a pointer to a display list + * drawing all snowflakes. + */ +Gfx *envfx_update_snow(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo) { + return envfx_update_snow_internal(snowMode, marioPos, camFrom, camTo, false); +} + /** * Updates the environment effects (snow, flowers, bubbles) * and returns a display list drawing them. diff --git a/src/game/envfx_snow.h b/src/game/envfx_snow.h index f4acc2de..b0842192 100644 --- a/src/game/envfx_snow.h +++ b/src/game/envfx_snow.h @@ -27,6 +27,7 @@ struct EnvFxParticle { s32 bubbleY; // for Bubbles, yPos is always set to this //s8 filler20[56 - 0x20]; u32 spawnTimestamp; + Vec3s prevPos; }; extern s8 gEnvFxMode; diff --git a/src/game/hud.c b/src/game/hud.c index 1f4263e8..8f921967 100644 --- a/src/game/hud.c +++ b/src/game/hud.c @@ -17,6 +17,7 @@ #include "print.h" #include "pc/configfile.h" #include "pc/network/network.h" +#include "pc/utils/misc.h" extern bool gDjuiInMainMenu; u8 gOverrideHideHud; @@ -64,18 +65,26 @@ static struct UnusedHUDStruct sUnusedHUDValues = { 0x00, 0x0A, 0x00 }; static struct CameraHUD sCameraHUD = { CAM_STATUS_NONE }; -static u32 sPowerMeterLastRenderTimestamp; -static s16 sPowerMeterLastY; +static u32 sPowerMeterPrevTimestamp; +static f32 sPowerMeterPrevY; static Gfx *sPowerMeterDisplayListPos; -void patch_interpolated_hud(void) { +void patch_hud_before(void) { + if (sPowerMeterDisplayListPos != NULL) { + sPowerMeterPrevY = sPowerMeterHUD.y; + sPowerMeterPrevTimestamp = gGlobalTimer; + sPowerMeterDisplayListPos = NULL; + } +} + +void patch_hud_interpolated(f32 delta) { if (sPowerMeterDisplayListPos != NULL) { Mtx *mtx = alloc_display_list(sizeof(Mtx)); if (mtx == NULL) { return; } - guTranslate(mtx, (f32) sPowerMeterHUD.x, (f32) sPowerMeterHUD.y, 0); + f32 interpY = delta_interpolate_f32(sPowerMeterPrevY, (f32)sPowerMeterHUD.y, delta); + guTranslate(mtx, (f32) sPowerMeterHUD.x, interpY, 0); gSPMatrix(sPowerMeterDisplayListPos, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH); - sPowerMeterDisplayListPos = NULL; } } @@ -131,7 +140,6 @@ void render_power_meter_health_segment(s16 numHealthWedges) { */ void render_dl_power_meter(s16 numHealthWedges) { Mtx *mtx; - f32 interpolatedY; mtx = alloc_display_list(sizeof(Mtx)); @@ -139,14 +147,7 @@ void render_dl_power_meter(s16 numHealthWedges) { return; } - if (gGlobalTimer == sPowerMeterLastRenderTimestamp + 1) { - interpolatedY = (sPowerMeterLastY + sPowerMeterHUD.y) / 2.0f; - } else { - interpolatedY = sPowerMeterHUD.y; - } - guTranslate(mtx, (f32) sPowerMeterHUD.x, interpolatedY, 0); - sPowerMeterLastY = sPowerMeterHUD.y; - sPowerMeterLastRenderTimestamp = gGlobalTimer; + guTranslate(mtx, (f32) sPowerMeterHUD.x, sPowerMeterPrevY, 0); sPowerMeterDisplayListPos = gDisplayListHead; gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx++), @@ -202,6 +203,7 @@ static void animate_power_meter_deemphasizing(void) { if (sPowerMeterHUD.y >= 201) { sPowerMeterHUD.y = 200; + sPowerMeterPrevY = 200; sPowerMeterHUD.animation = POWER_METER_VISIBLE; } } @@ -226,6 +228,7 @@ void handle_power_meter_actions(s16 numHealthWedges) { if (numHealthWedges < 8 && sPowerMeterStoredHealth == 8 && sPowerMeterHUD.animation == POWER_METER_HIDDEN) { sPowerMeterHUD.animation = POWER_METER_EMPHASIZED; sPowerMeterHUD.y = 166; + sPowerMeterPrevY = 166; } // Show power meter if health is full, has 8 diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c index c48e0200..4b8ed7a9 100644 --- a/src/game/ingame_menu.c +++ b/src/game/ingame_menu.c @@ -27,6 +27,7 @@ #include "pc/cheats.h" #include "pc/network/network.h" #include "pc/djui/djui.h" +#include "pc/utils/misc.h" #ifdef BETTERCAMERA #include "bettercamera.h" #endif @@ -130,44 +131,63 @@ s32 gDialogResponse = 0; static struct CachedChar { u8 used; u8 data[CHCACHE_BUFLEN]; } charCache[256]; #endif // VERSION -static Gfx *sInterpolatedDialogOffsetPos; -static f32 sInterpolatedDialogOffset; -static Gfx *sInterpolatedDialogRotationPos; -static f32 sInterpolatedDialogScale; -static f32 sInterpolatedDialogRotation; -static Gfx *sInterpolatedDialogZoomPos; +static Gfx *sDialogOffsetPos; +static Gfx *sDialogRotationPos; +static Gfx *sDialogZoomPos; -void patch_interpolated_dialog(void) { +static f32 sDialogOffset; +static f32 sDialogOffsetPrev; +static f32 sDialogScale; +static f32 sDialogScalePrev; +static f32 sDialogRotation; +static f32 sDialogRotationPrev; + +void patch_dialog_before(void) { + sDialogOffsetPos = NULL; + sDialogRotationPos = NULL; + sDialogZoomPos = NULL; +} + +void patch_dialog_interpolated(f32 delta) { Mtx *matrix; - if (sInterpolatedDialogOffsetPos != NULL) { + if (sDialogOffsetPos != NULL) { matrix = (Mtx *) alloc_display_list(sizeof(Mtx)); if (matrix == NULL) { return; } - guTranslate(matrix, 0, sInterpolatedDialogOffset, 0); - gSPMatrix(sInterpolatedDialogOffsetPos, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); - sInterpolatedDialogOffsetPos = NULL; + f32 interpOffset = delta_interpolate_f32(sDialogOffsetPrev, sDialogOffset, delta); + guTranslate(matrix, 0, interpOffset, 0); + gSPMatrix(sDialogOffsetPos, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); } - if (sInterpolatedDialogRotationPos != NULL) { + + if (sDialogRotationPos != NULL) { matrix = (Mtx *) alloc_display_list(sizeof(Mtx)); if (matrix == NULL) { return; } - guScale(matrix, 1.0 / sInterpolatedDialogScale, 1.0 / sInterpolatedDialogScale, 1.0f); - gSPMatrix(sInterpolatedDialogRotationPos++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); + + f32 interpScale = delta_interpolate_f32(sDialogScalePrev, sDialogScale, delta); + guScale(matrix, 1.0 / interpScale, 1.0 / interpScale, 1.0f); + gSPMatrix(sDialogRotationPos, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); + matrix = (Mtx *) alloc_display_list(sizeof(Mtx)); if (matrix == NULL) { return; } - guRotate(matrix, sInterpolatedDialogRotation * 4.0f, 0, 0, 1.0f); - gSPMatrix(sInterpolatedDialogRotationPos, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); - sInterpolatedDialogRotationPos = NULL; + + f32 interpRotation = delta_interpolate_f32(sDialogRotationPrev, sDialogRotation, delta); + guRotate(matrix, interpRotation * 4.0f, 0, 0, 1.0f); + gSPMatrix((sDialogRotationPos + 1), VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); } - if (sInterpolatedDialogZoomPos != NULL) { + + if (sDialogZoomPos != NULL) { matrix = (Mtx *) alloc_display_list(sizeof(Mtx)); if (matrix == NULL) { return; } - guTranslate(matrix, 65.0 - (65.0 / sInterpolatedDialogScale), (40.0 / sInterpolatedDialogScale) - 40, 0); - gSPMatrix(sInterpolatedDialogZoomPos++, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); + + f32 interpScale = delta_interpolate_f32(sDialogScalePrev, sDialogScale, delta); + guTranslate(matrix, 65.0 - (65.0 / interpScale), (40.0 / interpScale) - 40, 0); + gSPMatrix(sDialogZoomPos, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); + matrix = (Mtx *) alloc_display_list(sizeof(Mtx)); if (matrix == NULL) { return; } - guScale(matrix, 1.0 / sInterpolatedDialogScale, 1.0 / sInterpolatedDialogScale, 1.0f); - gSPMatrix(sInterpolatedDialogZoomPos, VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); - sInterpolatedDialogZoomPos = NULL; + + guScale(matrix, 1.0 / interpScale, 1.0 / interpScale, 1.0f); + gSPMatrix((sDialogZoomPos + 1), VIRTUAL_TO_PHYSICAL(matrix), G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH); } } @@ -1121,31 +1141,34 @@ void render_dialog_box_type(struct DialogEntry *dialog, s8 linesPerBox) { switch (gDialogBoxType) { case DIALOG_TYPE_ROTATE: // Renders a dialog black box with zoom and rotation if (gDialogBoxState == DIALOG_STATE_OPENING || gDialogBoxState == DIALOG_STATE_CLOSING) { - sInterpolatedDialogRotationPos = gDisplayListHead; + sDialogRotationPos = gDisplayListHead; if (gDialogBoxState == DIALOG_STATE_OPENING) { - sInterpolatedDialogScale = gDialogBoxScale - 2 / 2; - sInterpolatedDialogRotation = gDialogBoxOpenTimer - 7.5f / 2; + sDialogScale = gDialogBoxScale - 1.5f; + sDialogRotation = gDialogBoxOpenTimer - 7.5f; } else { - sInterpolatedDialogScale = gDialogBoxScale + 2 / 2; - sInterpolatedDialogRotation = gDialogBoxOpenTimer + 7.5f / 2; + sDialogScale = gDialogBoxScale + 2.0f; + sDialogRotation = gDialogBoxOpenTimer + 10.0f; } - create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / gDialogBoxScale, 1.0 / gDialogBoxScale, 1.0f); + sDialogScalePrev = gDialogBoxScale; + sDialogRotationPrev = gDialogBoxOpenTimer; + create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / sDialogScalePrev, 1.0 / sDialogScalePrev, 1.0f); // convert the speed into angle - create_dl_rotation_matrix(MENU_MTX_NOPUSH, gDialogBoxOpenTimer * 4.0f, 0, 0, 1.0f); + create_dl_rotation_matrix(MENU_MTX_NOPUSH, sDialogRotationPrev * 4.0f, 0, 0, 1.0f); } gDPSetEnvColor(gDisplayListHead++, 0, 0, 0, 150); break; case DIALOG_TYPE_ZOOM: // Renders a dialog white box with zoom if (gDialogBoxState == DIALOG_STATE_OPENING || gDialogBoxState == DIALOG_STATE_CLOSING) { - sInterpolatedDialogZoomPos = gDisplayListHead; + sDialogZoomPos = gDisplayListHead; if (gDialogBoxState == DIALOG_STATE_OPENING) { - sInterpolatedDialogScale = gDialogBoxScale - 2 / 2; + sDialogScale = gDialogBoxScale - 2; } else { - sInterpolatedDialogScale = gDialogBoxScale + 2 / 2; + sDialogScale = gDialogBoxScale + 2; } - create_dl_translation_matrix(MENU_MTX_NOPUSH, 65.0 - (65.0 / gDialogBoxScale), - (40.0 / gDialogBoxScale) - 40, 0); - create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / gDialogBoxScale, 1.0 / gDialogBoxScale, 1.0f); + sDialogScalePrev = gDialogBoxScale; + create_dl_translation_matrix(MENU_MTX_NOPUSH, 65.0 - (65.0 / sDialogScalePrev), + (40.0 / sDialogScalePrev) - 40, 0); + create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / sDialogScalePrev, 1.0 / sDialogScalePrev, 1.0f); } gDPSetEnvColor(gDisplayListHead++, 255, 255, 255, 150); break; @@ -1425,9 +1448,10 @@ void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 l #ifdef VERSION_EU gDialogY -= gDialogScrollOffsetY; #else - sInterpolatedDialogOffset = gDialogScrollOffsetY + dialog->linesPerBox; - sInterpolatedDialogOffsetPos = gDisplayListHead; - create_dl_translation_matrix(MENU_MTX_NOPUSH, 0, (f32) gDialogScrollOffsetY, 0); + sDialogOffset = gDialogScrollOffsetY + dialog->linesPerBox * 2; + sDialogOffsetPrev = gDialogScrollOffsetY; + sDialogOffsetPos = gDisplayListHead; + create_dl_translation_matrix(MENU_MTX_NOPUSH, 0, (f32) sDialogOffsetPrev, 0); #endif } diff --git a/src/game/paintings.c b/src/game/paintings.c index 464e16b1..fda2cd07 100644 --- a/src/game/paintings.c +++ b/src/game/paintings.c @@ -16,6 +16,7 @@ #include "paintings.h" #include "save_file.h" #include "segment2.h" +#include "pc/utils/misc.h" /** * @file paintings.c @@ -189,29 +190,74 @@ struct Painting **sPaintingGroups[] = { s16 gPaintingUpdateCounter = 1; s16 gLastPaintingUpdateCounter = 0; -static Vtx sLastVertices[2 * 264 * 3]; -static u32 sLastVerticesTimestamp; + +typedef struct { + float ob[3]; /* x, y, z */ + signed char n[3]; /* normal */ +} Vtx_Interp; + +static Vtx_Interp sVertexBuffers[2][2 * 264 * 3]; +static u8 sVerticesCurIndex = 0; +static u8 sVertexSwaps = 0; +static Vtx_Interp* sVerticesCur = sVertexBuffers[0]; +static Vtx_Interp* sVerticesPrev = NULL; +static u32 sVerticesPrevTimestamp; static Vtx *sVerticesPtr[2]; static s32 sVerticesCount; -void patch_interpolated_paintings(void) { - if (sVerticesPtr[0] != NULL) { +void patch_paintings_before(void) { + + if (gGlobalTimer == sVerticesPrevTimestamp + 1) { + sVerticesCurIndex = !sVerticesCurIndex; + sVerticesCur = sVertexBuffers[sVerticesCurIndex]; + sVerticesPrev = sVertexBuffers[!sVerticesCurIndex]; + sVertexSwaps++; + } else { + sVerticesPrev = NULL; + sVertexSwaps = 0; + } + + sVerticesPtr[0] = NULL; + sVerticesPtr[1] = NULL; + sVerticesCount = 0; +} + +void patch_paintings_interpolated(f32 delta) { + if (sVerticesPtr[0] != NULL && sVerticesPrev != NULL && sVertexSwaps > 2) { s32 i; if (sVerticesPtr[1] != NULL) { for (i = 0; i < sVerticesCount / 2; i++) { - sVerticesPtr[0][i] = sLastVertices[i]; + Vec3f obInterp; + delta_interpolate_vec3f(obInterp, sVerticesPrev[i].ob, sVerticesCur[i].ob, delta); + s8 nInterp[3]; + delta_interpolate_normal(nInterp, sVerticesPrev[i].n, sVerticesCur[i].n, delta); + for (u8 j = 0; j < 3; j++) { + sVerticesPtr[0][i].n.ob[j] = obInterp[j]; + sVerticesPtr[0][i].n.n[j] = nInterp[j]; + } } for (; i < sVerticesCount; i++) { - sVerticesPtr[1][i - sVerticesCount / 2] = sLastVertices[i]; + Vec3f obInterp; + delta_interpolate_vec3f(obInterp, sVerticesPrev[i].ob, sVerticesCur[i].ob, delta); + s8 nInterp[3]; + delta_interpolate_normal(nInterp, sVerticesPrev[i].n, sVerticesCur[i].n, delta); + for (u8 j = 0; j < 3; j++) { + sVerticesPtr[1][i - sVerticesCount / 2].n.ob[j] = obInterp[j]; + sVerticesPtr[1][i - sVerticesCount / 2].n.n[j] = nInterp[j]; + } } } else { for (i = 0; i < sVerticesCount; i++) { - sVerticesPtr[0][i] = sLastVertices[i]; + Vec3f obInterp; + delta_interpolate_vec3f(obInterp, sVerticesPrev[i].ob, sVerticesCur[i].ob, delta); + s8 nInterp[3]; + delta_interpolate_normal(nInterp, sVerticesPrev[i].n, sVerticesCur[i].n, delta); + for (u8 j = 0; j < 3; j++) { + sVerticesPtr[0][i].n.ob[j] = obInterp[j]; + sVerticesPtr[0][i].n.n[j] = nInterp[j]; + } } } - sVerticesPtr[0] = NULL; - sVerticesPtr[1] = NULL; - sVerticesCount = 0; } } @@ -932,16 +978,25 @@ Gfx *render_painting(u8 *img, s16 tWidth, s16 tHeight, s16 *textureMap, s16 mapV sVerticesCount = 0; } for (map = 0; map < numVtx; map++) { - Vtx v = verts[map]; - if (gGlobalTimer == sLastVerticesTimestamp + 1) { + Vtx* v = &verts[map]; + if (gGlobalTimer == sVerticesPrevTimestamp + 1) { s32 i; + Vtx_Interp* vCur = &sVerticesCur[sVerticesCount + map]; + Vtx_Interp* vPrev = (sVerticesPrev && sVertexSwaps > 2) ? &sVerticesPrev[sVerticesCount + map] : NULL; for (i = 0; i < 3; i++) { - verts[map].n.ob[i] = (v.n.ob[i] + sLastVertices[sVerticesCount + map].n.ob[i]) / 2; - verts[map].n.n[i] = (v.n.n[i] + sLastVertices[sVerticesCount + map].n.n[i]) / 2; + // save current + vCur->ob[i] = v->n.ob[i]; + vCur->n[i] = v->n.n[i]; + + // override verts with prev + if (vPrev) { + v->n.ob[i] = vPrev->ob[i]; + v->n.n[i] = vPrev->n[i]; + } } } - sLastVertices[sVerticesCount + map] = v; } + sVerticesPtr[sVerticesCount / numVtx] = verts; sVerticesCount += numVtx; @@ -1010,7 +1065,7 @@ Gfx *painting_ripple_image(struct Painting *painting) { meshTris = textureMap[meshVerts * 3 + 1]; gSPDisplayList(gfx++, render_painting(textures[i], tWidth, tHeight, textureMap, meshVerts, meshTris, painting->alpha)); } - sLastVerticesTimestamp = gGlobalTimer; + sVerticesPrevTimestamp = gGlobalTimer; // Update the ripple, may automatically reset the painting's state. painting_update_ripple_state(painting); @@ -1048,7 +1103,7 @@ Gfx *painting_ripple_env_mapped(struct Painting *painting) { meshVerts = textureMap[0]; meshTris = textureMap[meshVerts * 3 + 1]; gSPDisplayList(gfx++, render_painting(tArray[0], tWidth, tHeight, textureMap, meshVerts, meshTris, painting->alpha)); - sLastVerticesTimestamp = gGlobalTimer; + sVerticesPrevTimestamp = gGlobalTimer; // Update the ripple, may automatically reset the painting's state. painting_update_ripple_state(painting); diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 62b8ea0a..d7438c5a 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -170,8 +170,8 @@ void mtx_patch_interpolated(f32 delta) { } if (sViewportClipPos != NULL) { - delta_interpolate_vectors_s16(sViewportInterp.vp.vtrans, sViewportPrev.vp.vtrans, sViewport->vp.vtrans, delta); - delta_interpolate_vectors_s16(sViewportInterp.vp.vscale, sViewportPrev.vp.vscale, sViewport->vp.vscale, delta); + delta_interpolate_vec3s(sViewportInterp.vp.vtrans, sViewportPrev.vp.vtrans, sViewport->vp.vtrans, delta); + delta_interpolate_vec3s(sViewportInterp.vp.vscale, sViewportPrev.vp.vscale, sViewport->vp.vscale, delta); Gfx *saved = gDisplayListHead; diff --git a/src/game/screen_transition.c b/src/game/screen_transition.c index bc1fc6de..84bd3c4d 100644 --- a/src/game/screen_transition.c +++ b/src/game/screen_transition.c @@ -12,25 +12,42 @@ #include "screen_transition.h" #include "segment2.h" #include "sm64.h" +#include "pc/utils/misc.h" u8 sTransitionColorFadeCount[4] = { 0 }; u16 sTransitionTextureFadeCount[2] = { 0 }; static Gfx *sScreenTransitionVerticesPos[2]; static Vtx *sScreenTransitionVertices; +static Vtx *sScreenTransitionVerticesPrev; +static Vtx sScreenTransitionInterp[8] = { 0 }; void reset_screen_transition_timers(void) { for (s32 i = 0; i < 4; i++) { sTransitionColorFadeCount[i] = 0; } for (s32 i = 0; i < 2; i++) { sTransitionTextureFadeCount[i] = 0; } } -void patch_screen_transition_interpolated(void) { + +extern void patch_screen_transition_before(void) { + sScreenTransitionVerticesPos[0] = NULL; + sScreenTransitionVerticesPos[1] = NULL; + sScreenTransitionVertices = NULL; + sScreenTransitionVerticesPrev = NULL; +} + +void patch_screen_transition_interpolated(f32 delta) { if (sScreenTransitionVerticesPos[0] != NULL) { - gSPVertex(sScreenTransitionVerticesPos[0], VIRTUAL_TO_PHYSICAL(sScreenTransitionVertices), 8, 0); - gSPVertex(sScreenTransitionVerticesPos[1], VIRTUAL_TO_PHYSICAL(sScreenTransitionVertices), 4, 0); - sScreenTransitionVerticesPos[0] = NULL; - sScreenTransitionVerticesPos[1] = NULL; - sScreenTransitionVertices = NULL; + for (s32 i = 0; i < 8; i++) { + sScreenTransitionInterp[i] = sScreenTransitionVerticesPrev[i]; + delta_interpolate_vec3f(sScreenTransitionInterp[i].n.ob, + sScreenTransitionVerticesPrev[i].n.ob, + sScreenTransitionVertices[i].n.ob, delta); + delta_interpolate_rgba(sScreenTransitionInterp[i].v.cn, + sScreenTransitionVerticesPrev[i].v.cn, + sScreenTransitionVertices[i].v.cn, delta); + } + gSPVertex(sScreenTransitionVerticesPos[0], VIRTUAL_TO_PHYSICAL(sScreenTransitionInterp), 8, 0); + gSPVertex(sScreenTransitionVerticesPos[1], VIRTUAL_TO_PHYSICAL(sScreenTransitionInterp), 4, 0); } } @@ -249,19 +266,20 @@ s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransition s16 centerTransX = center_tex_transition_x(transData, texTransTime, texTransPos); s16 centerTransY = center_tex_transition_y(transData, texTransTime, texTransPos); s16 texTransRadius = calc_tex_transition_radius(fadeTimer, 1.0f, transTime, transData); - s16 texTransRadiusInterpolated = calc_tex_transition_radius(fadeTimer, 0.5f, transTime, transData); + s16 texTransRadiusPrev = calc_tex_transition_radius(fadeTimer, 0.0f, transTime, transData); Vtx *verts = alloc_display_list(8 * sizeof(*verts)); - Vtx *vertsInterpolated = alloc_display_list(8 * sizeof(*vertsInterpolated)); + Vtx *vertsPrev = alloc_display_list(8 * sizeof(*vertsPrev)); - if (verts != NULL && vertsInterpolated != NULL) { + if (verts != NULL && vertsPrev != NULL) { load_tex_transition_vertex(verts, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, transTexType); - load_tex_transition_vertex(vertsInterpolated, fadeTimer, transData, centerTransX, centerTransY, texTransRadiusInterpolated, transTexType); + load_tex_transition_vertex(vertsPrev, fadeTimer, transData, centerTransX, centerTransY, texTransRadiusPrev, transTexType); sScreenTransitionVertices = verts; + sScreenTransitionVerticesPrev = vertsPrev; gSPDisplayList(gDisplayListHead++, dl_proj_mtx_fullscreen) gDPSetCombineMode(gDisplayListHead++, G_CC_SHADE, G_CC_SHADE); gDPSetRenderMode(gDisplayListHead++, G_RM_AA_OPA_SURF, G_RM_AA_OPA_SURF2); sScreenTransitionVerticesPos[0] = gDisplayListHead; - gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(vertsInterpolated), 8, 0); + gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(vertsPrev), 8, 0); gSPDisplayList(gDisplayListHead++, dl_transition_draw_filled_region); gDPPipeSync(gDisplayListHead++); gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEIDECALA, G_CC_MODULATEIDECALA); @@ -279,7 +297,7 @@ s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransition } gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON); sScreenTransitionVerticesPos[1] = gDisplayListHead; - gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(vertsInterpolated), 4, 0); + gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(vertsPrev), 4, 0); gSPDisplayList(gDisplayListHead++, dl_draw_quad_verts_0123); gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_OFF); gSPDisplayList(gDisplayListHead++, dl_screen_transition_end); diff --git a/src/menu/intro_geo.c b/src/menu/intro_geo.c index 32368bd7..9f08b288 100644 --- a/src/menu/intro_geo.c +++ b/src/menu/intro_geo.c @@ -15,6 +15,7 @@ #include "gfx_dimensions.h" #include "game/rendering_graph_node.h" +#include "pc/utils/misc.h" // frame counts for the zoom in, hold, and zoom out of title model #define INTRO_STEPS_ZOOM_IN 20 @@ -60,14 +61,20 @@ s8 gameOverBackgroundFlipOrder[] = { 0x00, 0x01, 0x02, 0x03, 0x07, 0x0B, static Gfx *sIntroScalePos; static Vec3f sIntroScale; +static Vec3f sIntroScalePrev; -void patch_title_screen_scales(void) { +void patch_title_screen_before(void) { + sIntroScalePos = NULL; +} + +void patch_title_screen_interpolated(f32 delta) { if (sIntroScalePos != NULL) { Mtx *scaleMat = alloc_display_list(sizeof(*scaleMat)); if (scaleMat == NULL) { return; } - guScale(scaleMat, sIntroScale[0], sIntroScale[1], sIntroScale[2]); + Vec3f scaleInterp; + delta_interpolate_vec3f(scaleInterp, sIntroScalePrev, sIntroScale, delta); + guScale(scaleMat, scaleInterp[0], scaleInterp[1], scaleInterp[2]); gSPMatrix(sIntroScalePos, scaleMat, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH); - sIntroScalePos = NULL; } } @@ -82,7 +89,6 @@ Gfx *geo_title_screen(s32 state, struct GraphNode *sp54, UNUSED void *context) { f32 scaleY; // sp30 f32 scaleZ; // sp2c Vec3f scale; - Vec3f scaleInterpolated; graphNode = sp54; dl = NULL; dlIter = NULL; @@ -119,14 +125,12 @@ Gfx *geo_title_screen(s32 state, struct GraphNode *sp54, UNUSED void *context) { scaleY = 0.0f; scaleZ = 0.0f; } + + vec3f_copy(sIntroScalePrev, sIntroScale); vec3f_set(scale, scaleX, scaleY, scaleZ); - - // TODO: fixme - //interpolate_vectors(scaleInterpolated, sIntroScale, scale); - vec3f_copy(scaleInterpolated, scale); - vec3f_set(sIntroScale, scaleX, scaleY, scaleZ); - guScale(scaleMat, scaleInterpolated[0], scaleInterpolated[1], scaleInterpolated[2]); + + guScale(scaleMat, sIntroScalePrev[0], sIntroScalePrev[1], sIntroScalePrev[2]); sIntroScalePos = dlIter; gSPMatrix(dlIter++, scaleMat, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH); gSPDisplayList(dlIter++, &intro_seg7_dl_0700B3A0); // draw model diff --git a/src/pc/controller/controller_keyboard_debug.c b/src/pc/controller/controller_keyboard_debug.c index e3e5d64c..645fbc44 100644 --- a/src/pc/controller/controller_keyboard_debug.c +++ b/src/pc/controller/controller_keyboard_debug.c @@ -39,10 +39,10 @@ extern bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct); static void debug_warp_level1() { // warp to credits - set_mario_action(&gMarioStates[0], ACT_JUMBO_STAR_CUTSCENE, 0); - return; + //set_mario_action(&gMarioStates[0], ACT_JUMBO_STAR_CUTSCENE, 0); + //return; - dynos_warp_to_level(LEVEL_BOB, 1, 1); + dynos_warp_to_level(LEVEL_CCM, 1, 1); } static void debug_warp_level2() { diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index af1322ed..94e95d7c 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -100,28 +100,42 @@ void send_display_list(struct SPTask *spTask) { static void patch_interpolations_before(void) { extern void mtx_patch_before(void); + extern void patch_screen_transition_before(void); + extern void patch_title_screen_before(void); + extern void patch_dialog_before(void); + extern void patch_hud_before(void); + extern void patch_paintings_before(void); + extern void patch_bubble_particles_before(void); + extern void patch_snow_particles_before(void); mtx_patch_before(); + patch_screen_transition_before(); + patch_title_screen_before(); + patch_dialog_before(); + patch_hud_before(); + patch_paintings_before(); + patch_bubble_particles_before(); + patch_snow_particles_before(); } static inline void patch_interpolations(f32 delta) { extern void mtx_patch_interpolated(f32 delta); - extern void patch_screen_transition_interpolated(void); - extern void patch_title_screen_scales(void); - extern void patch_interpolated_dialog(void); - extern void patch_interpolated_hud(void); - extern void patch_interpolated_paintings(void); - extern void patch_interpolated_bubble_particles(void); - extern void patch_interpolated_snow_particles(void); + extern void patch_screen_transition_interpolated(f32 delta); + extern void patch_title_screen_interpolated(f32 delta); + extern void patch_dialog_interpolated(f32 delta); + extern void patch_hud_interpolated(f32 delta); + extern void patch_paintings_interpolated(f32 delta); + extern void patch_bubble_particles_interpolated(f32 delta); + extern void patch_snow_particles_interpolated(f32 delta); extern void djui_render_patch(void); mtx_patch_interpolated(delta); - /*patch_screen_transition_interpolated(); - patch_title_screen_scales(); - patch_interpolated_dialog(); - patch_interpolated_hud(); - patch_interpolated_paintings(); - patch_interpolated_bubble_particles(); - patch_interpolated_snow_particles(); - djui_render_patch();*/ + patch_screen_transition_interpolated(delta); + patch_title_screen_interpolated(delta); + patch_dialog_interpolated(delta); + patch_hud_interpolated(delta); + patch_paintings_interpolated(delta); + patch_bubble_particles_interpolated(delta); + patch_snow_particles_interpolated(delta); + /*djui_render_patch();*/ } void produce_uncapped_frames(void) { diff --git a/src/pc/utils/misc.c b/src/pc/utils/misc.c index edadf720..578799ca 100644 --- a/src/pc/utils/misc.c +++ b/src/pc/utils/misc.c @@ -120,7 +120,25 @@ f32 delta_interpolate_f32(f32 start, f32 end, f32 delta) { return start * (1.0f - delta) + end * delta; } -void delta_interpolate_vectors_s16(Vec3s res, Vec3s a, Vec3s b, f32 delta) { +s32 delta_interpolate_s32(s32 a, s32 b, f32 delta) { + return a * (1.0f - delta) + b * delta; +} + +void delta_interpolate_vec3f(Vec3f res, Vec3f a, Vec3f b, f32 delta) { + f32 antiDelta = 1.0f - delta; + res[0] = ((a[0] * antiDelta) + (b[0] * delta)); + res[1] = ((a[1] * antiDelta) + (b[1] * delta)); + res[2] = ((a[2] * antiDelta) + (b[2] * delta)); +} + +void delta_interpolate_vec3s(Vec3s res, Vec3s a, Vec3s b, f32 delta) { + f32 antiDelta = 1.0f - delta; + res[0] = ((a[0] * antiDelta) + (b[0] * delta)); + res[1] = ((a[1] * antiDelta) + (b[1] * delta)); + res[2] = ((a[2] * antiDelta) + (b[2] * delta)); +} + +void delta_interpolate_normal(s8* res, s8* a, s8* b, f32 delta) { f32 antiDelta = 1.0f - delta; res[0] = ((a[0] * antiDelta) + (b[0] * delta)); res[1] = ((a[1] * antiDelta) + (b[1] * delta)); @@ -136,6 +154,14 @@ void delta_interpolate_mtx(Mtx* out, Mtx* a, Mtx* b, f32 delta) { } } +void delta_interpolate_rgba(u8* res, u8* a, u8* b, f32 delta) { + f32 antiDelta = 1.0f - delta; + res[0] = ((a[0] * antiDelta) + (b[0] * delta)); + res[1] = ((a[1] * antiDelta) + (b[1] * delta)); + res[2] = ((a[2] * antiDelta) + (b[2] * delta)); + res[3] = ((a[3] * antiDelta) + (b[3] * delta)); +} + /* void interpolate_vectors(Vec3f res, Vec3f a, Vec3f b) { diff --git a/src/pc/utils/misc.h b/src/pc/utils/misc.h index 1f454d88..da1b1fc2 100644 --- a/src/pc/utils/misc.h +++ b/src/pc/utils/misc.h @@ -15,7 +15,11 @@ u32 clock_elapsed_ticks(void); void file_get_line(char* buffer, size_t maxLength, FILE* fp); f32 delta_interpolate_f32(f32 start, f32 end, f32 delta); -void delta_interpolate_vectors_s16(Vec3s res, Vec3s a, Vec3s b, f32 delta); +s32 delta_interpolate_s32(s32 a, s32 b, f32 delta); +void delta_interpolate_vec3f(Vec3f res, Vec3f a, Vec3f b, f32 delta); +void delta_interpolate_vec3s(Vec3s res, Vec3s a, Vec3s b, f32 delta); +void delta_interpolate_normal(s8* res, s8* a, s8* b, f32 delta); void delta_interpolate_mtx(Mtx* out, Mtx* a, Mtx* b, f32 delta); +void delta_interpolate_rgba(u8* res, u8* a, u8* b, f32 delta); #endif \ No newline at end of file