mirror of https://github.com/sm64pc/sm64pc.git
1513 lines
70 KiB
Diff
1513 lines
70 KiB
Diff
diff --git a/include/types.h b/include/types.h
|
|
index b3dc27e2..c46bdf01 100644
|
|
--- a/include/types.h
|
|
+++ b/include/types.h
|
|
@@ -120,2 +120,6 @@ struct GraphNodeObject_sub
|
|
/*0x10 0x48*/ s32 animAccel;
|
|
+ s16 prevAnimFrame;
|
|
+ s16 prevAnimID;
|
|
+ u32 prevAnimFrameTimestamp;
|
|
+ struct Animation *prevAnimPtr;
|
|
};
|
|
@@ -130,3 +134,10 @@ struct GraphNodeObject
|
|
/*0x20*/ Vec3f pos;
|
|
+ Vec3s prevAngle;
|
|
+ Vec3f prevPos;
|
|
+ u32 prevTimestamp;
|
|
+ Vec3f prevShadowPos;
|
|
+ u32 prevShadowPosTimestamp;
|
|
/*0x2C*/ Vec3f scale;
|
|
+ Vec3f prevScale;
|
|
+ u32 prevScaleTimestamp;
|
|
/*0x38*/ struct GraphNodeObject_sub unk38;
|
|
@@ -134,3 +145,7 @@ struct GraphNodeObject
|
|
/*0x50*/ Mat4 *throwMatrix; // matrix ptr
|
|
+ Mat4 prevThrowMatrix;
|
|
+ u32 prevThrowMatrixTimestamp;
|
|
+ Mat4 *throwMatrixInterpolated;
|
|
/*0x54*/ Vec3f cameraToObject;
|
|
+ u32 skipInterpolationTimestamp;
|
|
};
|
|
@@ -245,2 +260,6 @@ struct Surface
|
|
/*0x2C*/ struct Object *object;
|
|
+ Vec3s prevVertex1;
|
|
+ Vec3s prevVertex2;
|
|
+ Vec3s prevVertex3;
|
|
+ u32 modifiedTimestamp;
|
|
};
|
|
diff --git a/src/engine/graph_node.h b/src/engine/graph_node.h
|
|
index 802d97a8..1b0d6772 100644
|
|
--- a/src/engine/graph_node.h
|
|
+++ b/src/engine/graph_node.h
|
|
@@ -112,2 +112,4 @@ struct GraphNodePerspective
|
|
/*0x22*/ s16 far; // far clipping plane
|
|
+ f32 prevFov;
|
|
+ f32 prevTimestamp;
|
|
};
|
|
@@ -120,3 +122,5 @@ struct DisplayListNode
|
|
Mtx *transform;
|
|
+ void *transformInterpolated;
|
|
void *displayList;
|
|
+ void *displayListInterpolated;
|
|
struct DisplayListNode *next;
|
|
@@ -187,3 +191,7 @@ struct GraphNodeCamera
|
|
/*0x28*/ Vec3f focus;
|
|
+ Vec3f prevPos;
|
|
+ Vec3f prevFocus;
|
|
+ u32 prevTimestamp;
|
|
/*0x34*/ Mat4 *matrixPtr; // pointer to look-at matrix of this camera as a Mat4
|
|
+ Mat4 *matrixPtrInterpolated;
|
|
/*0x38*/ s16 roll; // roll in look at matrix. Doesn't account for light direction unlike rollScreen.
|
|
@@ -228,3 +236,4 @@ struct GraphNodeRotation
|
|
/*0x18*/ Vec3s rotation;
|
|
- u8 pad1E[2];
|
|
+ Vec3s prevRotation;
|
|
+ u32 prevTimestamp;
|
|
};
|
|
@@ -325,2 +334,5 @@ struct GraphNodeBackground
|
|
/*0x1C*/ s32 background; // background ID, or rgba5551 color if fnNode.func is null
|
|
+ Vec3f prevCameraPos;
|
|
+ Vec3f prevCameraFocus;
|
|
+ u32 prevCameraTimestamp;
|
|
};
|
|
@@ -335,2 +347,4 @@ struct GraphNodeHeldObject
|
|
/*0x20*/ Vec3s translation;
|
|
+ Vec3f prevShadowPos;
|
|
+ u32 prevShadowPosTimestamp;
|
|
};
|
|
diff --git a/src/engine/surface_collision.c b/src/engine/surface_collision.c
|
|
index 5b6775fe..2c11e254 100644
|
|
--- a/src/engine/surface_collision.c
|
|
+++ b/src/engine/surface_collision.c
|
|
@@ -10,2 +10,3 @@
|
|
#include "math_util.h"
|
|
+#include "game/game_init.h"
|
|
|
|
@@ -396,2 +397,4 @@ f32 find_floor_height_and_data(f32 xPos, f32 yPos, f32 zPos, struct FloorGeometr
|
|
|
|
+u8 gInterpolatingSurfaces;
|
|
+
|
|
/**
|
|
@@ -401,3 +404,3 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
|
|
register struct Surface *surf;
|
|
- register s32 x1, z1, x2, z2, x3, z3;
|
|
+ register f32 x1, z1, x2, z2, x3, z3;
|
|
f32 nx, ny, nz;
|
|
@@ -406,2 +409,3 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
|
|
struct Surface *floor = NULL;
|
|
+ s32 interpolate;
|
|
|
|
@@ -411,2 +415,3 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
|
|
surfaceNode = surfaceNode->next;
|
|
+ interpolate = gInterpolatingSurfaces && surf->modifiedTimestamp == gGlobalTimer;
|
|
|
|
@@ -416,2 +421,16 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
|
|
z2 = surf->vertex2[2];
|
|
+ if (interpolate) {
|
|
+ f32 diff = (surf->prevVertex1[0] - x1) * (surf->prevVertex1[0] - x1);
|
|
+ diff += (surf->prevVertex1[1] - surf->vertex1[1]) * (surf->prevVertex1[1] - surf->vertex1[1]);
|
|
+ diff += (surf->prevVertex1[2] - z1) * (surf->prevVertex1[2] - z1);
|
|
+ //printf("%f\n", sqrtf(diff));
|
|
+ if (diff > 10000) {
|
|
+ interpolate = FALSE;
|
|
+ } else {
|
|
+ x1 = (surf->prevVertex1[0] + x1) / 2;
|
|
+ z1 = (surf->prevVertex1[2] + z1) / 2;
|
|
+ x2 = (surf->prevVertex2[0] + x2) / 2;
|
|
+ z2 = (surf->prevVertex2[2] + z2) / 2;
|
|
+ }
|
|
+ }
|
|
|
|
@@ -425,2 +444,6 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
|
|
z3 = surf->vertex3[2];
|
|
+ if (interpolate) {
|
|
+ x3 = (surf->prevVertex3[0] + x3) / 2;
|
|
+ z3 = (surf->prevVertex3[2] + z3) / 2;
|
|
+ }
|
|
|
|
@@ -444,6 +467,26 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
|
|
|
|
- nx = surf->normal.x;
|
|
- ny = surf->normal.y;
|
|
- nz = surf->normal.z;
|
|
- oo = surf->originOffset;
|
|
+ if (interpolate) {
|
|
+ f32 y1, y2, y3;
|
|
+ f32 mag;
|
|
+ y1 = (surf->prevVertex1[1] + surf->vertex1[1]) / 2;
|
|
+ y2 = (surf->prevVertex2[1] + surf->vertex2[1]) / 2;
|
|
+ y3 = (surf->prevVertex3[1] + surf->vertex3[1]) / 2;
|
|
+ nx = (y2 - y1) * (z3 - z2) - (z2 - z1) * (y3 - y2);
|
|
+ ny = (z2 - z1) * (x3 - x2) - (x2 - x1) * (z3 - z2);
|
|
+ nz = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2);
|
|
+ mag = sqrtf(nx * nx + ny * ny + nz * nz);
|
|
+ if (mag < 0.0001) {
|
|
+ continue;
|
|
+ }
|
|
+ mag = (f32)(1.0 / mag);
|
|
+ nx *= mag;
|
|
+ ny *= mag;
|
|
+ nz *= mag;
|
|
+ oo = -(nx * x1 + ny * y1 + nz * z1);
|
|
+ } else {
|
|
+ nx = surf->normal.x;
|
|
+ ny = surf->normal.y;
|
|
+ nz = surf->normal.z;
|
|
+ oo = surf->originOffset;
|
|
+ }
|
|
|
|
@@ -462,2 +505,11 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
|
|
*pheight = height;
|
|
+ if (interpolate) {
|
|
+ static struct Surface s;
|
|
+ s.type = surf->type;
|
|
+ s.normal.x = nx;
|
|
+ s.normal.y = ny;
|
|
+ s.normal.z = nz;
|
|
+ s.originOffset = oo;
|
|
+ return &s;
|
|
+ }
|
|
floor = surf;
|
|
diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c
|
|
index ac2ee50c..323b7d05 100644
|
|
--- a/src/engine/surface_load.c
|
|
+++ b/src/engine/surface_load.c
|
|
@@ -16,2 +16,3 @@
|
|
#include "surface_load.h"
|
|
+#include "game/game_init.h"
|
|
|
|
@@ -361,2 +362,7 @@ static struct Surface *read_surface_data(s16 *vertexData, s16 **vertexIndices) {
|
|
|
|
+ vec3s_copy(surface->prevVertex1, surface->vertex1);
|
|
+ vec3s_copy(surface->prevVertex2, surface->vertex2);
|
|
+ vec3s_copy(surface->prevVertex3, surface->vertex3);
|
|
+ surface->modifiedTimestamp = gGlobalTimer;
|
|
+
|
|
surface->vertex1[0] = x1;
|
|
diff --git a/src/game/camera.c b/src/game/camera.c
|
|
index bde06626..aa65c00b 100644
|
|
--- a/src/game/camera.c
|
|
+++ b/src/game/camera.c
|
|
@@ -486,2 +486,6 @@ extern u8 sZoomOutAreaMasks[];
|
|
|
|
+static void skip_camera_interpolation(void) {
|
|
+ gLakituState.skipCameraInterpolationTimestamp = gGlobalTimer;
|
|
+}
|
|
+
|
|
/**
|
|
@@ -5554,2 +5558,3 @@ s32 set_camera_mode_fixed(struct Camera *c, s16 x, s16 y, s16 z) {
|
|
sFixedModeBasePosition[2]);
|
|
+ skip_camera_interpolation();
|
|
}
|
|
@@ -5716,2 +5721,3 @@ BAD_RETURN(s32) cam_rr_enter_building_side(struct Camera *c) {
|
|
c->mode = CAMERA_MODE_FIXED;
|
|
+ skip_camera_interpolation();
|
|
}
|
|
@@ -5911,2 +5917,3 @@ BAD_RETURN(s32) cam_castle_enter_lobby(struct Camera *c) {
|
|
c->mode = CAMERA_MODE_FIXED;
|
|
+ skip_camera_interpolation();
|
|
}
|
|
@@ -7281,2 +7288,3 @@ BAD_RETURN(s32) cutscene_ending_mario_fall_start(struct Camera *c) {
|
|
vec3f_set(c->pos, 165.f, 4725.f, 324.f);
|
|
+ skip_camera_interpolation();
|
|
}
|
|
@@ -7313,2 +7321,3 @@ BAD_RETURN(s32) cutscene_ending_mario_land_closeup(struct Camera *c) {
|
|
vec3f_set(c->pos, -51.f, 988.f, -202.f);
|
|
+ skip_camera_interpolation();
|
|
player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000);
|
|
@@ -7322,2 +7331,3 @@ BAD_RETURN(s32) cutscene_ending_reset_spline(UNUSED struct Camera *c) {
|
|
cutscene_reset_spline();
|
|
+ skip_camera_interpolation();
|
|
}
|
|
@@ -7357,2 +7367,3 @@ BAD_RETURN(s32) cutscene_ending_peach_appear_closeup(struct Camera *c) {
|
|
vec3f_set(c->focus, gCutsceneFocus->oPosX, gCutsceneFocus->oPosY + 125.f, gCutsceneFocus->oPosZ);
|
|
+ skip_camera_interpolation();
|
|
}
|
|
@@ -7375,2 +7386,3 @@ BAD_RETURN(s32) cutscene_ending_peach_descends_start(UNUSED struct Camera *c) {
|
|
sCutsceneVars[2].point[1] = 150.f;
|
|
+ skip_camera_interpolation();
|
|
}
|
|
@@ -7461,2 +7473,3 @@ BAD_RETURN(s32) cutscene_ending_dialog(struct Camera *c) {
|
|
vec3f_set(c->pos, -473.f, 970.f, -1152.f);
|
|
+ skip_camera_interpolation();
|
|
player2_rotate_cam(c, -0x800, 0x2000, -0x2000, 0x2000);
|
|
@@ -7471,2 +7484,3 @@ BAD_RETURN(s32) cutscene_ending_kiss_closeup(struct Camera *c) {
|
|
vec3f_set(c->pos, -149.f, 1021.f, -1216.f);
|
|
+ skip_camera_interpolation();
|
|
}
|
|
@@ -10375,2 +10389,3 @@ BAD_RETURN(s32) cutscene_door_move_behind_mario(struct Camera *c) {
|
|
offset_rotated(c->pos, sMarioCamState->pos, camOffset, sCutsceneVars[0].angle);
|
|
+ skip_camera_interpolation();
|
|
}
|
|
diff --git a/src/game/camera.h b/src/game/camera.h
|
|
index 173ab8a7..b1abdc4f 100644
|
|
--- a/src/game/camera.h
|
|
+++ b/src/game/camera.h
|
|
@@ -659,2 +659,4 @@ struct LakituState
|
|
/*0xBC*/ s16 unused;
|
|
+
|
|
+ u32 skipCameraInterpolationTimestamp;
|
|
};
|
|
diff --git a/src/game/envfx_bubbles.c b/src/game/envfx_bubbles.c
|
|
index 16a92720..ee1b029d 100644
|
|
--- a/src/game/envfx_bubbles.c
|
|
+++ b/src/game/envfx_bubbles.c
|
|
@@ -37,2 +37,16 @@ Vtx_t gBubbleTempVtx[3] = {
|
|
|
|
+static Gfx sGfxSaved[60 / 5];
|
|
+static Gfx *sBubbleInterpolatedDisplayListPos[60 / 5];
|
|
+static Vec3s sPrevBubblePositions[60];
|
|
+
|
|
+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;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
@@ -243,2 +257,3 @@ void envfx_update_whirlpool(void) {
|
|
(gEnvFxBuffer + i)->isAlive = 1;
|
|
+ (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
|
|
|
|
@@ -301,2 +316,3 @@ void envfx_update_jetstream(void) {
|
|
gEnvFxBubbleConfig[ENVFX_STATE_SRC_Y] + (random_float() * 400.0f - 200.0f);
|
|
+ (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
|
|
} else {
|
|
@@ -508,2 +524,8 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro
|
|
Vec3s vertex3;
|
|
+ Vec3s interpolatedVertices[3];
|
|
+
|
|
+ static Vec3s prevVertex1;
|
|
+ static Vec3s prevVertex2;
|
|
+ static Vec3s prevVertex3;
|
|
+ static u32 prevTimestamp;
|
|
|
|
@@ -523,2 +545,12 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro
|
|
|
|
+ if (gGlobalTimer == prevTimestamp + 1) {
|
|
+ interpolate_vectors_s16(interpolatedVertices[0], prevVertex1, vertex1);
|
|
+ interpolate_vectors_s16(interpolatedVertices[1], prevVertex2, vertex2);
|
|
+ interpolate_vectors_s16(interpolatedVertices[2], prevVertex3, vertex3);
|
|
+ }
|
|
+ vec3s_copy(prevVertex1, vertex1);
|
|
+ vec3s_copy(prevVertex2, vertex2);
|
|
+ vec3s_copy(prevVertex3, vertex3);
|
|
+ prevTimestamp = gGlobalTimer;
|
|
+
|
|
gSPDisplayList(sGfxCursor++, &tiny_bubble_dl_0B006D38);
|
|
@@ -526,5 +558,24 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro
|
|
for (i = 0; i < sBubbleParticleMaxCount; i += 5) {
|
|
+ Vtx *interpolatedVertBuf = alloc_display_list(15 * sizeof(Vtx));
|
|
+ s32 j, k;
|
|
gDPPipeSync(sGfxCursor++);
|
|
envfx_set_bubble_texture(mode, i);
|
|
- append_bubble_vertex_buffer(sGfxCursor++, i, vertex1, vertex2, vertex3, (Vtx *) gBubbleTempVtx);
|
|
+ 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);
|
|
gSP1Triangle(sGfxCursor++, 0, 1, 2, 0);
|
|
@@ -535,2 +586,7 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro
|
|
}
|
|
+ for (i = 0; i < sBubbleParticleMaxCount; i++) {
|
|
+ sPrevBubblePositions[i][0] = gEnvFxBuffer[i].xPos;
|
|
+ sPrevBubblePositions[i][1] = gEnvFxBuffer[i].yPos;
|
|
+ sPrevBubblePositions[i][2] = gEnvFxBuffer[i].zPos;
|
|
+ }
|
|
|
|
diff --git a/src/game/envfx_snow.c b/src/game/envfx_snow.c
|
|
index c3c14a5c..d2212ef6 100644
|
|
--- a/src/game/envfx_snow.c
|
|
+++ b/src/game/envfx_snow.c
|
|
@@ -56,2 +56,22 @@ extern void *tiny_bubble_dl_0B006CD8;
|
|
|
|
+static struct {
|
|
+ Gfx *pos;
|
|
+ Vtx vertices[15];
|
|
+} sPrevSnowVertices[140 / 5];
|
|
+static s16 sPrevSnowParticleCount;
|
|
+static u32 sPrevSnowTimestamp;
|
|
+
|
|
+void patch_interpolated_snow_particles(void) {
|
|
+ int i;
|
|
+
|
|
+ if (gGlobalTimer != sPrevSnowTimestamp + 1) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < sPrevSnowParticleCount; i += 5) {
|
|
+ gSPVertex(sPrevSnowVertices[i / 5].pos,
|
|
+ VIRTUAL_TO_PHYSICAL(sPrevSnowVertices[i / 5].vertices), 15, 0);
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
@@ -219,2 +239,3 @@ void envfx_update_snow_normal(s32 snowCylinderX, s32 snowCylinderY, s32 snowCyli
|
|
(gEnvFxBuffer + i)->isAlive = 1;
|
|
+ (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
|
|
} else {
|
|
@@ -253,2 +274,3 @@ void envfx_update_snow_blizzard(s32 snowCylinderX, s32 snowCylinderY, s32 snowCy
|
|
(gEnvFxBuffer + i)->isAlive = 1;
|
|
+ (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
|
|
} else {
|
|
@@ -296,2 +318,3 @@ void envfx_update_snow_water(s32 snowCylinderX, s32 snowCylinderY, s32 snowCylin
|
|
(gEnvFxBuffer + i)->isAlive = 1;
|
|
+ (gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
|
|
}
|
|
@@ -348,2 +371,4 @@ void append_snowflake_vertex_buffer(Gfx *gfx, s32 index, Vec3s vertex1, Vec3s ve
|
|
Vtx *vertBuf = (Vtx *) alloc_display_list(15 * sizeof(Vtx));
|
|
+ Vtx *vertBufInterpolated = (Vtx *) alloc_display_list(15 * sizeof(Vtx));
|
|
+ Vtx *v;
|
|
#ifdef VERSION_EU
|
|
@@ -397,3 +422,19 @@ void append_snowflake_vertex_buffer(Gfx *gfx, s32 index, Vec3s vertex1, Vec3s ve
|
|
|
|
- gSPVertex(gfx, VIRTUAL_TO_PHYSICAL(vertBuf), 15, 0);
|
|
+ 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);
|
|
}
|
|
@@ -481,2 +522,4 @@ Gfx *envfx_update_snow(s32 snowMode, Vec3s marioPos, Vec3s camFrom, Vec3s camTo)
|
|
}
|
|
+ sPrevSnowParticleCount = gSnowParticleCount;
|
|
+ sPrevSnowTimestamp = gGlobalTimer;
|
|
|
|
diff --git a/src/game/envfx_snow.h b/src/game/envfx_snow.h
|
|
index 7a83b536..f4acc2de 100644
|
|
--- a/src/game/envfx_snow.h
|
|
+++ b/src/game/envfx_snow.h
|
|
@@ -27,3 +27,4 @@ struct EnvFxParticle {
|
|
s32 bubbleY; // for Bubbles, yPos is always set to this
|
|
- s8 filler20[56 - 0x20];
|
|
+ //s8 filler20[56 - 0x20];
|
|
+ u32 spawnTimestamp;
|
|
};
|
|
diff --git a/src/game/hud.c b/src/game/hud.c
|
|
index 1540b675..0de6e0bb 100644
|
|
--- a/src/game/hud.c
|
|
+++ b/src/game/hud.c
|
|
@@ -61,2 +61,16 @@ static struct CameraHUD sCameraHUD = { CAM_STATUS_NONE };
|
|
|
|
+static u32 sPowerMeterLastRenderTimestamp;
|
|
+static s16 sPowerMeterLastY;
|
|
+static Gfx *sPowerMeterDisplayListPos;
|
|
+
|
|
+void patch_interpolated_hud(void) {
|
|
+ if (sPowerMeterDisplayListPos != NULL) {
|
|
+ Mtx *mtx = alloc_display_list(sizeof(Mtx));
|
|
+ guTranslate(mtx, (f32) sPowerMeterHUD.x, (f32) sPowerMeterHUD.y, 0);
|
|
+ gSPMatrix(sPowerMeterDisplayListPos, VIRTUAL_TO_PHYSICAL(mtx),
|
|
+ G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
|
|
+ sPowerMeterDisplayListPos = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
@@ -113,2 +127,3 @@ void render_dl_power_meter(s16 numHealthWedges) {
|
|
Mtx *mtx;
|
|
+ f32 interpolatedY;
|
|
|
|
@@ -120,3 +135,11 @@ void render_dl_power_meter(s16 numHealthWedges) {
|
|
|
|
- guTranslate(mtx, (f32) sPowerMeterHUD.x, (f32) sPowerMeterHUD.y, 0);
|
|
+ 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;
|
|
+ sPowerMeterDisplayListPos = gDisplayListHead;
|
|
|
|
diff --git a/src/game/ingame_menu.c b/src/game/ingame_menu.c
|
|
index 3f02281a..d7d0aced 100644
|
|
--- a/src/game/ingame_menu.c
|
|
+++ b/src/game/ingame_menu.c
|
|
@@ -118,2 +118,43 @@ u8 gMenuHoldKeyTimer = 0;
|
|
s32 gDialogResponse = 0;
|
|
+static Gfx *sInterpolatedDialogOffsetPos;
|
|
+static f32 sInterpolatedDialogOffset;
|
|
+static Gfx *sInterpolatedDialogRotationPos;
|
|
+static f32 sInterpolatedDialogScale;
|
|
+static f32 sInterpolatedDialogRotation;
|
|
+static Gfx *sInterpolatedDialogZoomPos;
|
|
+
|
|
+void patch_interpolated_dialog(void) {
|
|
+ Mtx *matrix;
|
|
+
|
|
+ if (sInterpolatedDialogOffsetPos != NULL) {
|
|
+ matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
|
|
+ guTranslate(matrix, 0, sInterpolatedDialogOffset, 0);
|
|
+ gSPMatrix(sInterpolatedDialogOffsetPos, VIRTUAL_TO_PHYSICAL(matrix),
|
|
+ G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_NOPUSH);
|
|
+ sInterpolatedDialogOffsetPos = NULL;
|
|
+ }
|
|
+ if (sInterpolatedDialogRotationPos != NULL) {
|
|
+ matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
|
|
+ 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);
|
|
+ matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
|
|
+ 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;
|
|
+ }
|
|
+ if (sInterpolatedDialogZoomPos != NULL) {
|
|
+ matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
|
|
+ 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);
|
|
+ matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
|
|
+ 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;
|
|
+ }
|
|
+}
|
|
|
|
@@ -940,2 +981,10 @@ void render_dialog_box_type(struct DialogEntry *dialog, s8 linesPerBox) {
|
|
if (gDialogBoxState == DIALOG_STATE_OPENING || gDialogBoxState == DIALOG_STATE_CLOSING) {
|
|
+ sInterpolatedDialogRotationPos = gDisplayListHead;
|
|
+ if (gDialogBoxState == DIALOG_STATE_OPENING) {
|
|
+ sInterpolatedDialogScale = gDialogBoxScale - 2 / 2;
|
|
+ sInterpolatedDialogRotation = gDialogBoxOpenTimer - 7.5f / 2;
|
|
+ } else {
|
|
+ sInterpolatedDialogScale = gDialogBoxScale + 2 / 2;
|
|
+ sInterpolatedDialogRotation = gDialogBoxOpenTimer + 7.5f / 2;
|
|
+ }
|
|
create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / gDialogBoxScale, 1.0 / gDialogBoxScale, 1.0f);
|
|
@@ -948,2 +997,8 @@ void render_dialog_box_type(struct DialogEntry *dialog, s8 linesPerBox) {
|
|
if (gDialogBoxState == DIALOG_STATE_OPENING || gDialogBoxState == DIALOG_STATE_CLOSING) {
|
|
+ sInterpolatedDialogZoomPos = gDisplayListHead;
|
|
+ if (gDialogBoxState == DIALOG_STATE_OPENING) {
|
|
+ sInterpolatedDialogScale = gDialogBoxScale - 2 / 2;
|
|
+ } else {
|
|
+ sInterpolatedDialogScale = gDialogBoxScale + 2 / 2;
|
|
+ }
|
|
create_dl_translation_matrix(MENU_MTX_NOPUSH, 65.0 - (65.0 / gDialogBoxScale),
|
|
@@ -1230,2 +1285,4 @@ void handle_dialog_text_and_pages(s8 colorMode, struct DialogEntry *dialog, s8 l
|
|
#else
|
|
+ sInterpolatedDialogOffset = gDialogScrollOffsetY + dialog->linesPerBox;
|
|
+ sInterpolatedDialogOffsetPos = gDisplayListHead;
|
|
create_dl_translation_matrix(MENU_MTX_NOPUSH, 0, (f32) gDialogScrollOffsetY, 0);
|
|
diff --git a/src/game/level_geo.c b/src/game/level_geo.c
|
|
index 4c98e705..abc51213 100644
|
|
--- a/src/game/level_geo.c
|
|
+++ b/src/game/level_geo.c
|
|
@@ -36,2 +36,3 @@ Gfx *geo_envfx_main(s32 callContext, struct GraphNode *node, Mat4 mtxf) {
|
|
if (particleList != NULL) {
|
|
+#if 0
|
|
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
|
@@ -42,2 +43,5 @@ Gfx *geo_envfx_main(s32 callContext, struct GraphNode *node, Mat4 mtxf) {
|
|
gSPBranchList(&gfx[1], VIRTUAL_TO_PHYSICAL(particleList));
|
|
+#else
|
|
+ gfx = particleList;
|
|
+#endif
|
|
execNode->fnNode.node.flags = (execNode->fnNode.node.flags & 0xFF) | 0x400;
|
|
diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c
|
|
index 22b45b32..109d7f74 100644
|
|
--- a/src/game/object_helpers.c
|
|
+++ b/src/game/object_helpers.c
|
|
@@ -1556,2 +1556,3 @@ void cur_obj_set_pos_to_home(void) {
|
|
o->oPosZ = o->oHomeZ;
|
|
+ o->header.gfx.skipInterpolationTimestamp = gGlobalTimer;
|
|
}
|
|
diff --git a/src/game/paintings.c b/src/game/paintings.c
|
|
index 6cae19c0..a304d4ae 100644
|
|
--- a/src/game/paintings.c
|
|
+++ b/src/game/paintings.c
|
|
@@ -191,2 +191,28 @@ s16 gLastPaintingUpdateCounter = 0;
|
|
|
|
+static Vtx sLastVertices[2 * 264 * 3];
|
|
+static u32 sLastVerticesTimestamp;
|
|
+static Vtx *sVerticesPtr[2];
|
|
+static s32 sVerticesCount;
|
|
+
|
|
+void patch_interpolated_paintings(void) {
|
|
+ if (sVerticesPtr[0] != NULL) {
|
|
+ s32 i;
|
|
+ if (sVerticesPtr[1] != NULL) {
|
|
+ for (i = 0; i < sVerticesCount / 2; i++) {
|
|
+ sVerticesPtr[0][i] = sLastVertices[i];
|
|
+ }
|
|
+ for (; i < sVerticesCount; i++) {
|
|
+ sVerticesPtr[1][i - sVerticesCount / 2] = sLastVertices[i];
|
|
+ }
|
|
+ } else {
|
|
+ for (i = 0; i < sVerticesCount; i++) {
|
|
+ sVerticesPtr[0][i] = sLastVertices[i];
|
|
+ }
|
|
+ }
|
|
+ sVerticesPtr[0] = NULL;
|
|
+ sVerticesPtr[1] = NULL;
|
|
+ sVerticesCount = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
@@ -892,2 +918,19 @@ Gfx *render_painting(u8 *img, s16 tWidth, s16 tHeight, s16 *textureMap, s16 mapV
|
|
|
|
+ if (sVerticesCount >= numVtx * 2) {
|
|
+ sVerticesCount = 0;
|
|
+ }
|
|
+ for (map = 0; map < numVtx; map++) {
|
|
+ Vtx v = verts[map];
|
|
+ if (gGlobalTimer == sLastVerticesTimestamp + 1) {
|
|
+ s32 i;
|
|
+ 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;
|
|
+ }
|
|
+ }
|
|
+ sLastVertices[sVerticesCount + map] = v;
|
|
+ }
|
|
+ sVerticesPtr[sVerticesCount / numVtx] = verts;
|
|
+ sVerticesCount += numVtx;
|
|
+
|
|
gSPEndDisplayList(gfx);
|
|
@@ -956,2 +999,3 @@ Gfx *painting_ripple_image(struct Painting *painting) {
|
|
}
|
|
+ sLastVerticesTimestamp = gGlobalTimer;
|
|
|
|
@@ -993,2 +1037,3 @@ Gfx *painting_ripple_env_mapped(struct Painting *painting) {
|
|
gSPDisplayList(gfx++, render_painting(tArray[0], tWidth, tHeight, textureMap, meshVerts, meshTris, painting->alpha));
|
|
+ sLastVerticesTimestamp = gGlobalTimer;
|
|
|
|
diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c
|
|
index d5bf5778..71656b49 100644
|
|
--- a/src/game/rendering_graph_node.c
|
|
+++ b/src/game/rendering_graph_node.c
|
|
@@ -41,2 +41,4 @@ Mat4 gMatStack[32];
|
|
Mtx *gMatStackFixed[32];
|
|
+Mat4 gMatStackInterpolated[32];
|
|
+Mtx *gMatStackInterpolatedFixed[32];
|
|
|
|
@@ -54,2 +56,3 @@ struct GeoAnimState {
|
|
/*0x0C*/ s16 *data;
|
|
+ s16 prevFrame;
|
|
};
|
|
@@ -63,2 +66,3 @@ u8 gCurAnimEnabled;
|
|
s16 gCurrAnimFrame;
|
|
+s16 gPrevAnimFrame;
|
|
f32 gCurAnimTranslationMultiplier;
|
|
@@ -131,2 +135,42 @@ LookAt lookAt;
|
|
|
|
+static Gfx *sPerspectivePos;
|
|
+static Mtx *sPerspectiveMtx;
|
|
+
|
|
+struct {
|
|
+ Gfx *pos;
|
|
+ void *mtx;
|
|
+ void *displayList;
|
|
+} gMtxTbl[6400];
|
|
+s32 gMtxTblSize;
|
|
+
|
|
+static Gfx *sViewportPos;
|
|
+static Vp sPrevViewport;
|
|
+
|
|
+void mtx_patch_interpolated(void) {
|
|
+ s32 i;
|
|
+
|
|
+ if (sPerspectivePos != NULL) {
|
|
+ gSPMatrix(sPerspectivePos, VIRTUAL_TO_PHYSICAL(sPerspectiveMtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < gMtxTblSize; i++) {
|
|
+ Gfx *pos = gMtxTbl[i].pos;
|
|
+ gSPMatrix(pos++, VIRTUAL_TO_PHYSICAL(gMtxTbl[i].mtx),
|
|
+ G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
|
|
+ gSPDisplayList(pos++, gMtxTbl[i].displayList);
|
|
+ }
|
|
+
|
|
+ if (sViewportPos != NULL) {
|
|
+ Gfx *saved = gDisplayListHead;
|
|
+ gDisplayListHead = sViewportPos;
|
|
+ make_viewport_clip_rect(&sPrevViewport);
|
|
+ gSPViewport(gDisplayListHead, VIRTUAL_TO_PHYSICAL(&sPrevViewport));
|
|
+ gDisplayListHead = saved;
|
|
+ }
|
|
+
|
|
+ gMtxTblSize = 0;
|
|
+ sPerspectivePos = NULL;
|
|
+ sViewportPos = NULL;
|
|
+}
|
|
+
|
|
/**
|
|
@@ -158,5 +202,10 @@ static void geo_process_master_list_sub(struct GraphNodeMasterList *node) {
|
|
while (currList != NULL) {
|
|
- gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transform),
|
|
+ if ((u32) gMtxTblSize < sizeof(gMtxTbl) / sizeof(gMtxTbl[0])) {
|
|
+ gMtxTbl[gMtxTblSize].pos = gDisplayListHead;
|
|
+ gMtxTbl[gMtxTblSize].mtx = currList->transform;
|
|
+ gMtxTbl[gMtxTblSize++].displayList = currList->displayList;
|
|
+ }
|
|
+ gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transformInterpolated),
|
|
G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
|
|
- gSPDisplayList(gDisplayListHead++, currList->displayList);
|
|
+ gSPDisplayList(gDisplayListHead++, currList->displayListInterpolated);
|
|
currList = currList->next;
|
|
@@ -176,3 +225,3 @@ static void geo_process_master_list_sub(struct GraphNodeMasterList *node) {
|
|
*/
|
|
-static void geo_append_display_list(void *displayList, s16 layer) {
|
|
+static void geo_append_display_list2(void *displayList, void *displayListInterpolated, s16 layer) {
|
|
|
|
@@ -186,3 +235,5 @@ static void geo_append_display_list(void *displayList, s16 layer) {
|
|
listNode->transform = gMatStackFixed[gMatStackIndex];
|
|
+ listNode->transformInterpolated = gMatStackInterpolatedFixed[gMatStackIndex];
|
|
listNode->displayList = displayList;
|
|
+ listNode->displayListInterpolated = displayListInterpolated;
|
|
listNode->next = 0;
|
|
@@ -197,2 +248,6 @@ static void geo_append_display_list(void *displayList, s16 layer) {
|
|
|
|
+static void geo_append_display_list(void *displayList, s16 layer) {
|
|
+ geo_append_display_list2(displayList, displayList, layer);
|
|
+}
|
|
+
|
|
/**
|
|
@@ -243,3 +298,5 @@ static void geo_process_perspective(struct GraphNodePerspective *node) {
|
|
u16 perspNorm;
|
|
+ Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
|
|
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
|
+ f32 fovInterpolated;
|
|
|
|
@@ -252,5 +309,19 @@ static void geo_process_perspective(struct GraphNodePerspective *node) {
|
|
guPerspective(mtx, &perspNorm, node->fov, aspect, node->near, node->far, 1.0f);
|
|
- gSPPerspNormalize(gDisplayListHead++, perspNorm);
|
|
|
|
- gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
|
|
+ if (gGlobalTimer == node->prevTimestamp + 1 && gGlobalTimer != gLakituState.skipCameraInterpolationTimestamp) {
|
|
+
|
|
+ fovInterpolated = (node->prevFov + node->fov) / 2.0f;
|
|
+ guPerspective(mtxInterpolated, &perspNorm, fovInterpolated, aspect, node->near, node->far, 1.0f);
|
|
+ gSPPerspNormalize(gDisplayListHead++, perspNorm);
|
|
+
|
|
+ sPerspectivePos = gDisplayListHead;
|
|
+ sPerspectiveMtx = mtx;
|
|
+ gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtxInterpolated),
|
|
+ G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
|
|
+ } else {
|
|
+ gSPPerspNormalize(gDisplayListHead++, perspNorm);
|
|
+ gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH);
|
|
+ }
|
|
+ node->prevFov = node->fov;
|
|
+ node->prevTimestamp = gGlobalTimer;
|
|
|
|
@@ -299,2 +370,35 @@ static void geo_process_switch(struct GraphNodeSwitchCase *node) {
|
|
|
|
+void interpolate_vectors(Vec3f res, Vec3f a, Vec3f b) {
|
|
+ res[0] = (a[0] + b[0]) / 2.0f;
|
|
+ res[1] = (a[1] + b[1]) / 2.0f;
|
|
+ res[2] = (a[2] + b[2]) / 2.0f;
|
|
+}
|
|
+
|
|
+void interpolate_vectors_s16(Vec3s res, Vec3s a, Vec3s b) {
|
|
+ res[0] = (a[0] + b[0]) / 2;
|
|
+ res[1] = (a[1] + b[1]) / 2;
|
|
+ res[2] = (a[2] + b[2]) / 2;
|
|
+}
|
|
+
|
|
+static s16 interpolate_angle(s16 a, s16 b) {
|
|
+ s32 absDiff = b - a;
|
|
+ if (absDiff < 0) {
|
|
+ absDiff = -absDiff;
|
|
+ }
|
|
+ if (absDiff >= 0x4000 && absDiff <= 0xC000) {
|
|
+ return b;
|
|
+ }
|
|
+ if (absDiff <= 0x8000) {
|
|
+ return (a + b) / 2;
|
|
+ } else {
|
|
+ return (a + b) / 2 + 0x8000;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void interpolate_angles(Vec3s res, Vec3s a, Vec3s b) {
|
|
+ res[0] = interpolate_angle(a[0], b[0]);
|
|
+ res[1] = interpolate_angle(a[1], b[1]);
|
|
+ res[2] = interpolate_angle(a[2], b[2]);
|
|
+}
|
|
+
|
|
/**
|
|
@@ -306,2 +410,5 @@ static void geo_process_camera(struct GraphNodeCamera *node) {
|
|
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
|
+ Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
|
|
+ Vec3f posInterpolated;
|
|
+ Vec3f focusInterpolated;
|
|
|
|
@@ -316,2 +423,27 @@ static void geo_process_camera(struct GraphNodeCamera *node) {
|
|
mtxf_mul(gMatStack[gMatStackIndex + 1], cameraTransform, gMatStack[gMatStackIndex]);
|
|
+
|
|
+ if (gGlobalTimer == node->prevTimestamp + 1 && gGlobalTimer != gLakituState.skipCameraInterpolationTimestamp) {
|
|
+ interpolate_vectors(posInterpolated, node->prevPos, node->pos);
|
|
+ interpolate_vectors(focusInterpolated, node->prevFocus, node->focus);
|
|
+ float magnitude = 0;
|
|
+ for (int i = 0; i < 3; i++) {
|
|
+ float diff = node->pos[i] - node->prevPos[i];
|
|
+ magnitude += diff * diff;
|
|
+ }
|
|
+ if (magnitude > 500000) {
|
|
+ // Observed ~479000 in BBH when toggling R camera
|
|
+ // Can get over 3 million in VCUTM though...
|
|
+ vec3f_copy(posInterpolated, node->pos);
|
|
+ vec3f_copy(focusInterpolated, node->focus);
|
|
+ }
|
|
+ } else {
|
|
+ vec3f_copy(posInterpolated, node->pos);
|
|
+ vec3f_copy(focusInterpolated, node->focus);
|
|
+ }
|
|
+ vec3f_copy(node->prevPos, node->pos);
|
|
+ vec3f_copy(node->prevFocus, node->focus);
|
|
+ node->prevTimestamp = gGlobalTimer;
|
|
+ mtxf_lookat(cameraTransform, posInterpolated, focusInterpolated, node->roll);
|
|
+ mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], cameraTransform, gMatStackInterpolated[gMatStackIndex]);
|
|
+
|
|
gMatStackIndex++;
|
|
@@ -319,2 +451,4 @@ static void geo_process_camera(struct GraphNodeCamera *node) {
|
|
gMatStackFixed[gMatStackIndex] = mtx;
|
|
+ mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
|
|
+ gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
|
|
if (node->fnNode.node.children != 0) {
|
|
@@ -322,2 +456,3 @@ static void geo_process_camera(struct GraphNodeCamera *node) {
|
|
node->matrixPtr = &gMatStack[gMatStackIndex];
|
|
+ node->matrixPtrInterpolated = &gMatStackInterpolated[gMatStackIndex];
|
|
geo_process_node_and_siblings(node->fnNode.node.children);
|
|
@@ -338,2 +473,3 @@ static void geo_process_translation_rotation(struct GraphNodeTranslationRotation
|
|
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
|
+ Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
|
|
|
|
@@ -342,2 +478,3 @@ static void geo_process_translation_rotation(struct GraphNodeTranslationRotation
|
|
mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
|
|
+ mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]);
|
|
gMatStackIndex++;
|
|
@@ -345,2 +482,4 @@ static void geo_process_translation_rotation(struct GraphNodeTranslationRotation
|
|
gMatStackFixed[gMatStackIndex] = mtx;
|
|
+ mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
|
|
+ gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
|
|
if (node->displayList != NULL) {
|
|
@@ -363,2 +502,3 @@ static void geo_process_translation(struct GraphNodeTranslation *node) {
|
|
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
|
+ Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
|
|
|
|
@@ -367,2 +507,3 @@ static void geo_process_translation(struct GraphNodeTranslation *node) {
|
|
mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
|
|
+ mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]);
|
|
gMatStackIndex++;
|
|
@@ -370,2 +511,4 @@ static void geo_process_translation(struct GraphNodeTranslation *node) {
|
|
gMatStackFixed[gMatStackIndex] = mtx;
|
|
+ mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
|
|
+ gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
|
|
if (node->displayList != NULL) {
|
|
@@ -387,2 +530,4 @@ static void geo_process_rotation(struct GraphNodeRotation *node) {
|
|
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
|
+ Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
|
|
+ Vec3s rotationInterpolated;
|
|
|
|
@@ -390,2 +535,9 @@ static void geo_process_rotation(struct GraphNodeRotation *node) {
|
|
mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
|
|
+ if (gGlobalTimer == node->prevTimestamp + 1) {
|
|
+ interpolate_angles(rotationInterpolated, node->prevRotation, node->rotation);
|
|
+ mtxf_rotate_zxy_and_translate(mtxf, gVec3fZero, rotationInterpolated);
|
|
+ }
|
|
+ vec3s_copy(node->prevRotation, node->rotation);
|
|
+ node->prevTimestamp = gGlobalTimer;
|
|
+ mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]);
|
|
gMatStackIndex++;
|
|
@@ -393,2 +545,4 @@ static void geo_process_rotation(struct GraphNodeRotation *node) {
|
|
gMatStackFixed[gMatStackIndex] = mtx;
|
|
+ mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
|
|
+ gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
|
|
if (node->displayList != NULL) {
|
|
@@ -411,2 +565,3 @@ static void geo_process_scale(struct GraphNodeScale *node) {
|
|
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
|
+ Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
|
|
|
|
@@ -414,2 +569,3 @@ static void geo_process_scale(struct GraphNodeScale *node) {
|
|
mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], scaleVec);
|
|
+ mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex], scaleVec);
|
|
gMatStackIndex++;
|
|
@@ -417,2 +573,4 @@ static void geo_process_scale(struct GraphNodeScale *node) {
|
|
gMatStackFixed[gMatStackIndex] = mtx;
|
|
+ mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
|
|
+ gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
|
|
if (node->displayList != NULL) {
|
|
@@ -435,2 +593,3 @@ static void geo_process_billboard(struct GraphNodeBillboard *node) {
|
|
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
|
+ Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
|
|
|
|
@@ -440,2 +599,4 @@ static void geo_process_billboard(struct GraphNodeBillboard *node) {
|
|
gCurGraphNodeCamera->roll);
|
|
+ mtxf_billboard(gMatStackInterpolated[gMatStackIndex], gMatStackInterpolated[gMatStackIndex - 1], translation,
|
|
+ gCurGraphNodeCamera->roll);
|
|
if (gCurGraphNodeHeldObject != NULL) {
|
|
@@ -443,2 +604,4 @@ static void geo_process_billboard(struct GraphNodeBillboard *node) {
|
|
gCurGraphNodeHeldObject->objNode->header.gfx.scale);
|
|
+ mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex], gMatStackInterpolated[gMatStackIndex],
|
|
+ gCurGraphNodeHeldObject->objNode->header.gfx.scale);
|
|
} else if (gCurGraphNodeObject != NULL) {
|
|
@@ -446,2 +609,4 @@ static void geo_process_billboard(struct GraphNodeBillboard *node) {
|
|
gCurGraphNodeObject->scale);
|
|
+ mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex], gMatStackInterpolated[gMatStackIndex],
|
|
+ gCurGraphNodeObject->scale);
|
|
}
|
|
@@ -450,2 +615,4 @@ static void geo_process_billboard(struct GraphNodeBillboard *node) {
|
|
gMatStackFixed[gMatStackIndex] = mtx;
|
|
+ mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
|
|
+ gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
|
|
if (node->displayList != NULL) {
|
|
@@ -498,9 +665,35 @@ static void geo_process_background(struct GraphNodeBackground *node) {
|
|
Gfx *list = NULL;
|
|
+ Gfx *listInterpolated = NULL;
|
|
|
|
if (node->fnNode.func != NULL) {
|
|
+ Vec3f posCopy;
|
|
+ Vec3f focusCopy;
|
|
+ Vec3f posInterpolated;
|
|
+ Vec3f focusInterpolated;
|
|
+
|
|
+ if (gGlobalTimer == node->prevCameraTimestamp + 1 &&
|
|
+ gGlobalTimer != gLakituState.skipCameraInterpolationTimestamp) {
|
|
+ interpolate_vectors(posInterpolated, node->prevCameraPos, gLakituState.pos);
|
|
+ interpolate_vectors(focusInterpolated, node->prevCameraFocus, gLakituState.focus);
|
|
+ } else {
|
|
+ vec3f_copy(posInterpolated, gLakituState.pos);
|
|
+ vec3f_copy(focusInterpolated, gLakituState.focus);
|
|
+ }
|
|
+ vec3f_copy(node->prevCameraPos, gLakituState.pos);
|
|
+ vec3f_copy(node->prevCameraFocus, gLakituState.focus);
|
|
+ node->prevCameraTimestamp = gGlobalTimer;
|
|
+
|
|
list = node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node,
|
|
(struct AllocOnlyPool *) gMatStack[gMatStackIndex]);
|
|
+ vec3f_copy(posCopy, gLakituState.pos);
|
|
+ vec3f_copy(focusCopy, gLakituState.focus);
|
|
+ vec3f_copy(gLakituState.pos, posInterpolated);
|
|
+ vec3f_copy(gLakituState.focus, focusInterpolated);
|
|
+ listInterpolated = node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, NULL);
|
|
+ vec3f_copy(gLakituState.pos, posCopy);
|
|
+ vec3f_copy(gLakituState.focus, focusCopy);
|
|
}
|
|
if (list != 0) {
|
|
- geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(list), node->fnNode.node.flags >> 8);
|
|
+ geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(list),
|
|
+ (void *) VIRTUAL_TO_PHYSICAL(listInterpolated), node->fnNode.node.flags >> 8);
|
|
} else if (gCurGraphNodeMasterList != NULL) {
|
|
@@ -529,43 +722,32 @@ static void geo_process_background(struct GraphNodeBackground *node) {
|
|
|
|
-/**
|
|
- * Render an animated part. The current animation state is not part of the node
|
|
- * but set in global variables. If an animated part is skipped, everything afterwards desyncs.
|
|
- */
|
|
-static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) {
|
|
- Mat4 matrix;
|
|
- Vec3s rotation;
|
|
- Vec3f translation;
|
|
- Mtx *matrixPtr = alloc_display_list(sizeof(*matrixPtr));
|
|
-
|
|
- vec3s_copy(rotation, gVec3sZero);
|
|
- vec3f_set(translation, node->translation[0], node->translation[1], node->translation[2]);
|
|
- if (gCurAnimType == ANIM_TYPE_TRANSLATION) {
|
|
- translation[0] += gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]
|
|
+static void anim_process(Vec3f translation, Vec3s rotation, u8 *animType, s16 animFrame, u16 **animAttribute) {
|
|
+ if (*animType == ANIM_TYPE_TRANSLATION) {
|
|
+ translation[0] += gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]
|
|
* gCurAnimTranslationMultiplier;
|
|
- translation[1] += gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]
|
|
+ translation[1] += gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]
|
|
* gCurAnimTranslationMultiplier;
|
|
- translation[2] += gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]
|
|
+ translation[2] += gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]
|
|
* gCurAnimTranslationMultiplier;
|
|
- gCurAnimType = ANIM_TYPE_ROTATION;
|
|
+ *animType = ANIM_TYPE_ROTATION;
|
|
} else {
|
|
- if (gCurAnimType == ANIM_TYPE_LATERAL_TRANSLATION) {
|
|
+ if (*animType == ANIM_TYPE_LATERAL_TRANSLATION) {
|
|
translation[0] +=
|
|
- gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]
|
|
+ gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]
|
|
* gCurAnimTranslationMultiplier;
|
|
- gCurrAnimAttribute += 2;
|
|
+ *animAttribute += 2;
|
|
translation[2] +=
|
|
- gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]
|
|
+ gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]
|
|
* gCurAnimTranslationMultiplier;
|
|
- gCurAnimType = ANIM_TYPE_ROTATION;
|
|
+ *animType = ANIM_TYPE_ROTATION;
|
|
} else {
|
|
- if (gCurAnimType == ANIM_TYPE_VERTICAL_TRANSLATION) {
|
|
- gCurrAnimAttribute += 2;
|
|
+ if (*animType == ANIM_TYPE_VERTICAL_TRANSLATION) {
|
|
+ *animAttribute += 2;
|
|
translation[1] +=
|
|
- gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)]
|
|
+ gCurAnimData[retrieve_animation_index(animFrame, animAttribute)]
|
|
* gCurAnimTranslationMultiplier;
|
|
- gCurrAnimAttribute += 2;
|
|
- gCurAnimType = ANIM_TYPE_ROTATION;
|
|
- } else if (gCurAnimType == ANIM_TYPE_NO_TRANSLATION) {
|
|
- gCurrAnimAttribute += 6;
|
|
- gCurAnimType = ANIM_TYPE_ROTATION;
|
|
+ *animAttribute += 2;
|
|
+ *animType = ANIM_TYPE_ROTATION;
|
|
+ } else if (*animType == ANIM_TYPE_NO_TRANSLATION) {
|
|
+ *animAttribute += 6;
|
|
+ *animType = ANIM_TYPE_ROTATION;
|
|
}
|
|
@@ -574,9 +756,38 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) {
|
|
|
|
- if (gCurAnimType == ANIM_TYPE_ROTATION) {
|
|
- rotation[0] = gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)];
|
|
- rotation[1] = gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)];
|
|
- rotation[2] = gCurAnimData[retrieve_animation_index(gCurrAnimFrame, &gCurrAnimAttribute)];
|
|
+ if (*animType == ANIM_TYPE_ROTATION) {
|
|
+ rotation[0] = gCurAnimData[retrieve_animation_index(animFrame, animAttribute)];
|
|
+ rotation[1] = gCurAnimData[retrieve_animation_index(animFrame, animAttribute)];
|
|
+ rotation[2] = gCurAnimData[retrieve_animation_index(animFrame, animAttribute)];
|
|
}
|
|
+}
|
|
+
|
|
+/**
|
|
+ * Render an animated part. The current animation state is not part of the node
|
|
+ * but set in global variables. If an animated part is skipped, everything afterwards desyncs.
|
|
+ */
|
|
+static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) {
|
|
+ Mat4 matrix;
|
|
+ Vec3s rotation;
|
|
+ Vec3f translation;
|
|
+ Vec3s rotationInterpolated;
|
|
+ Vec3f translationInterpolated;
|
|
+ Mtx *matrixPtr = alloc_display_list(sizeof(*matrixPtr));
|
|
+ Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
|
|
+ u16 *animAttribute = gCurrAnimAttribute;
|
|
+ u8 animType = gCurAnimType;
|
|
+
|
|
+ vec3s_copy(rotation, gVec3sZero);
|
|
+ vec3f_set(translation, node->translation[0], node->translation[1], node->translation[2]);
|
|
+ vec3s_copy(rotationInterpolated, rotation);
|
|
+ vec3f_copy(translationInterpolated, translation);
|
|
+
|
|
+ anim_process(translationInterpolated, rotationInterpolated, &animType, gPrevAnimFrame, &animAttribute);
|
|
+ anim_process(translation, rotation, &gCurAnimType, gCurrAnimFrame, &gCurrAnimAttribute);
|
|
+ interpolate_vectors(translationInterpolated, translationInterpolated, translation);
|
|
+ interpolate_angles(rotationInterpolated, rotationInterpolated, rotation);
|
|
+
|
|
mtxf_rotate_xyz_and_translate(matrix, translation, rotation);
|
|
mtxf_mul(gMatStack[gMatStackIndex + 1], matrix, gMatStack[gMatStackIndex]);
|
|
+ mtxf_rotate_xyz_and_translate(matrix, translationInterpolated, rotationInterpolated);
|
|
+ mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], matrix, gMatStackInterpolated[gMatStackIndex]);
|
|
gMatStackIndex++;
|
|
@@ -584,2 +795,4 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) {
|
|
gMatStackFixed[gMatStackIndex] = matrixPtr;
|
|
+ mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
|
|
+ gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
|
|
if (node->displayList != NULL) {
|
|
@@ -615,2 +828,13 @@ void geo_set_animation_globals(struct GraphNodeObject_sub *node, s32 hasAnimatio
|
|
gCurrAnimFrame = node->animFrame;
|
|
+ if (node->prevAnimPtr == anim && node->prevAnimID == node->animID &&
|
|
+ gGlobalTimer == node->prevAnimFrameTimestamp + 1) {
|
|
+ gPrevAnimFrame = node->prevAnimFrame;
|
|
+ } else {
|
|
+ gPrevAnimFrame = node->animFrame;
|
|
+ }
|
|
+ node->prevAnimPtr = anim;
|
|
+ node->prevAnimID = node->animID;
|
|
+ node->prevAnimFrame = node->animFrame;
|
|
+ node->prevAnimFrameTimestamp = gGlobalTimer;
|
|
+
|
|
gCurAnimEnabled = (anim->flags & ANIM_FLAG_5) == 0;
|
|
@@ -633,4 +857,6 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
|
|
Gfx *shadowList;
|
|
+ Gfx *shadowListInterpolated;
|
|
Mat4 mtxf;
|
|
Vec3f shadowPos;
|
|
+ Vec3f shadowPosInterpolated;
|
|
Vec3f animOffset;
|
|
@@ -642,2 +868,3 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
|
|
Mtx *mtx;
|
|
+ Mtx *mtxInterpolated;
|
|
|
|
@@ -680,7 +907,34 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
|
|
|
|
+ if (gCurGraphNodeHeldObject != NULL) {
|
|
+ if (gGlobalTimer == gCurGraphNodeHeldObject->prevShadowPosTimestamp + 1) {
|
|
+ interpolate_vectors(shadowPosInterpolated, gCurGraphNodeHeldObject->prevShadowPos, shadowPos);
|
|
+ } else {
|
|
+ vec3f_copy(shadowPosInterpolated, shadowPos);
|
|
+ }
|
|
+ vec3f_copy(gCurGraphNodeHeldObject->prevShadowPos, shadowPos);
|
|
+ gCurGraphNodeHeldObject->prevShadowPosTimestamp = gGlobalTimer;
|
|
+ } else {
|
|
+ if (gGlobalTimer == gCurGraphNodeObject->prevShadowPosTimestamp + 1 &&
|
|
+ gGlobalTimer != gCurGraphNodeObject->skipInterpolationTimestamp) {
|
|
+ interpolate_vectors(shadowPosInterpolated, gCurGraphNodeObject->prevShadowPos, shadowPos);
|
|
+ } else {
|
|
+ vec3f_copy(shadowPosInterpolated, shadowPos);
|
|
+ }
|
|
+ vec3f_copy(gCurGraphNodeObject->prevShadowPos, shadowPos);
|
|
+ gCurGraphNodeObject->prevShadowPosTimestamp = gGlobalTimer;
|
|
+ }
|
|
+
|
|
+ extern u8 gInterpolatingSurfaces;
|
|
+ gInterpolatingSurfaces = TRUE;
|
|
+ shadowListInterpolated = create_shadow_below_xyz(shadowPosInterpolated[0], shadowPosInterpolated[1],
|
|
+ shadowPosInterpolated[2], shadowScale,
|
|
+ node->shadowSolidity, node->shadowType);
|
|
+ gInterpolatingSurfaces = FALSE;
|
|
shadowList = create_shadow_below_xyz(shadowPos[0], shadowPos[1], shadowPos[2], shadowScale,
|
|
node->shadowSolidity, node->shadowType);
|
|
- if (shadowList != NULL) {
|
|
+ if (shadowListInterpolated != NULL && shadowList != NULL) {
|
|
mtx = alloc_display_list(sizeof(*mtx));
|
|
+ mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
|
|
gMatStackIndex++;
|
|
+
|
|
mtxf_translate(mtxf, shadowPos);
|
|
@@ -689,8 +943,17 @@ static void geo_process_shadow(struct GraphNodeShadow *node) {
|
|
gMatStackFixed[gMatStackIndex] = mtx;
|
|
+
|
|
+ mtxf_translate(mtxf, shadowPosInterpolated);
|
|
+ mtxf_mul(gMatStackInterpolated[gMatStackIndex], mtxf, *gCurGraphNodeCamera->matrixPtrInterpolated);
|
|
+ mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
|
|
+ gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
|
|
+
|
|
if (gShadowAboveWaterOrLava == 1) {
|
|
- geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 4);
|
|
+ geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowList),
|
|
+ (void *) VIRTUAL_TO_PHYSICAL(shadowListInterpolated), 4);
|
|
} else if (gMarioOnIceOrCarpet == 1) {
|
|
- geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 5);
|
|
+ geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowList),
|
|
+ (void *) VIRTUAL_TO_PHYSICAL(shadowListInterpolated), 5);
|
|
} else {
|
|
- geo_append_display_list((void *) VIRTUAL_TO_PHYSICAL(shadowList), 6);
|
|
+ geo_append_display_list2((void *) VIRTUAL_TO_PHYSICAL(shadowList),
|
|
+ (void *) VIRTUAL_TO_PHYSICAL(shadowListInterpolated), 6);
|
|
}
|
|
@@ -791,2 +1054,11 @@ static int obj_is_in_view(struct GraphNodeObject *node, Mat4 matrix) {
|
|
|
|
+static void interpolate_matrix(Mat4 result, Mat4 a, Mat4 b) {
|
|
+ s32 i, j;
|
|
+ for (i = 0; i < 4; i++) {
|
|
+ for (j = 0; j < 4; j++) {
|
|
+ result[i][j] = (a[i][j] + b[i][j]) / 2.0f;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
/**
|
|
@@ -797,2 +1069,3 @@ static void geo_process_object(struct Object *node) {
|
|
s32 hasAnimation = (node->header.gfx.node.flags & GRAPH_RENDER_HAS_ANIMATION) != 0;
|
|
+ Vec3f scaleInterpolated;
|
|
|
|
@@ -802,12 +1075,69 @@ static void geo_process_object(struct Object *node) {
|
|
gMatStack[gMatStackIndex]);
|
|
+ if (gGlobalTimer == node->header.gfx.prevThrowMatrixTimestamp + 1 &&
|
|
+ gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) {
|
|
+ interpolate_matrix(mtxf, *node->header.gfx.throwMatrix, node->header.gfx.prevThrowMatrix);
|
|
+ mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf,
|
|
+ gMatStackInterpolated[gMatStackIndex]);
|
|
+ } else {
|
|
+ mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], (void *) node->header.gfx.throwMatrix,
|
|
+ gMatStackInterpolated[gMatStackIndex]);
|
|
+ }
|
|
+ mtxf_copy(node->header.gfx.prevThrowMatrix, *node->header.gfx.throwMatrix);
|
|
+ node->header.gfx.prevThrowMatrixTimestamp = gGlobalTimer;
|
|
} else if (node->header.gfx.node.flags & GRAPH_RENDER_CYLBOARD) {
|
|
+ Vec3f posInterpolated;
|
|
+ if (gGlobalTimer == node->header.gfx.prevTimestamp + 1 &&
|
|
+ gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) {
|
|
+ interpolate_vectors(posInterpolated, node->header.gfx.prevPos, node->header.gfx.pos);
|
|
+ } else {
|
|
+ vec3f_copy(posInterpolated, node->header.gfx.pos);
|
|
+ }
|
|
+ vec3f_copy(node->header.gfx.prevPos, node->header.gfx.pos);
|
|
+ node->header.gfx.prevTimestamp = gGlobalTimer;
|
|
mtxf_cylboard(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex],
|
|
node->header.gfx.pos, gCurGraphNodeCamera->roll);
|
|
+ mtxf_cylboard(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex],
|
|
+ posInterpolated, gCurGraphNodeCamera->roll);
|
|
} else if (node->header.gfx.node.flags & GRAPH_RENDER_BILLBOARD) {
|
|
+ Vec3f posInterpolated;
|
|
+ if (gGlobalTimer == node->header.gfx.prevTimestamp + 1 &&
|
|
+ gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) {
|
|
+ interpolate_vectors(posInterpolated, node->header.gfx.prevPos, node->header.gfx.pos);
|
|
+ } else {
|
|
+ vec3f_copy(posInterpolated, node->header.gfx.pos);
|
|
+ }
|
|
+ vec3f_copy(node->header.gfx.prevPos, node->header.gfx.pos);
|
|
+ node->header.gfx.prevTimestamp = gGlobalTimer;
|
|
mtxf_billboard(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex],
|
|
node->header.gfx.pos, gCurGraphNodeCamera->roll);
|
|
+ mtxf_billboard(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex],
|
|
+ posInterpolated, gCurGraphNodeCamera->roll);
|
|
} else {
|
|
+ Vec3f posInterpolated;
|
|
+ Vec3s angleInterpolated;
|
|
+ if (gGlobalTimer == node->header.gfx.prevTimestamp + 1 &&
|
|
+ gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) {
|
|
+ interpolate_vectors(posInterpolated, node->header.gfx.prevPos, node->header.gfx.pos);
|
|
+ interpolate_angles(angleInterpolated, node->header.gfx.prevAngle, node->header.gfx.angle);
|
|
+ } else {
|
|
+ vec3f_copy(posInterpolated, node->header.gfx.pos);
|
|
+ vec3s_copy(angleInterpolated, node->header.gfx.angle);
|
|
+ }
|
|
+ vec3f_copy(node->header.gfx.prevPos, node->header.gfx.pos);
|
|
+ vec3s_copy(node->header.gfx.prevAngle, node->header.gfx.angle);
|
|
+ node->header.gfx.prevTimestamp = gGlobalTimer;
|
|
mtxf_rotate_zxy_and_translate(mtxf, node->header.gfx.pos, node->header.gfx.angle);
|
|
mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]);
|
|
+ mtxf_rotate_zxy_and_translate(mtxf, posInterpolated, angleInterpolated);
|
|
+ mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]);
|
|
+ }
|
|
+
|
|
+ if (gGlobalTimer == node->header.gfx.prevScaleTimestamp + 1 &&
|
|
+ gGlobalTimer != node->header.gfx.skipInterpolationTimestamp) {
|
|
+ interpolate_vectors(scaleInterpolated, node->header.gfx.prevScale, node->header.gfx.scale);
|
|
+ } else {
|
|
+ vec3f_copy(scaleInterpolated, node->header.gfx.scale);
|
|
}
|
|
+ vec3f_copy(node->header.gfx.prevScale, node->header.gfx.scale);
|
|
+ node->header.gfx.prevScaleTimestamp = gGlobalTimer;
|
|
|
|
@@ -815,3 +1145,6 @@ static void geo_process_object(struct Object *node) {
|
|
node->header.gfx.scale);
|
|
+ mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex + 1],
|
|
+ scaleInterpolated);
|
|
node->header.gfx.throwMatrix = &gMatStack[++gMatStackIndex];
|
|
+ node->header.gfx.throwMatrixInterpolated = &gMatStackInterpolated[gMatStackIndex];
|
|
node->header.gfx.cameraToObject[0] = gMatStack[gMatStackIndex][3][0];
|
|
@@ -826,2 +1159,3 @@ static void geo_process_object(struct Object *node) {
|
|
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
|
+ Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
|
|
|
|
@@ -829,2 +1163,4 @@ static void geo_process_object(struct Object *node) {
|
|
gMatStackFixed[gMatStackIndex] = mtx;
|
|
+ mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
|
|
+ gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
|
|
if (node->header.gfx.sharedChild != NULL) {
|
|
@@ -839,2 +1175,6 @@ static void geo_process_object(struct Object *node) {
|
|
}
|
|
+ } else {
|
|
+ node->header.gfx.prevThrowMatrixTimestamp = 0;
|
|
+ node->header.gfx.prevTimestamp = 0;
|
|
+ node->header.gfx.prevScaleTimestamp = 0;
|
|
}
|
|
@@ -844,2 +1184,3 @@ static void geo_process_object(struct Object *node) {
|
|
node->header.gfx.throwMatrix = NULL;
|
|
+ node->header.gfx.throwMatrixInterpolated = NULL;
|
|
}
|
|
@@ -870,2 +1211,4 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
|
|
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
|
+ Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated));
|
|
+ Vec3f scaleInterpolated;
|
|
|
|
@@ -885,2 +1228,10 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
|
|
|
|
+ if (gGlobalTimer == node->objNode->header.gfx.prevScaleTimestamp + 1) {
|
|
+ interpolate_vectors(scaleInterpolated, node->objNode->header.gfx.prevScale, node->objNode->header.gfx.scale);
|
|
+ } else {
|
|
+ vec3f_copy(scaleInterpolated, node->objNode->header.gfx.scale);
|
|
+ }
|
|
+ vec3f_copy(node->objNode->header.gfx.prevScale, node->objNode->header.gfx.scale);
|
|
+ node->objNode->header.gfx.prevScaleTimestamp = gGlobalTimer;
|
|
+
|
|
mtxf_translate(mat, translation);
|
|
@@ -893,2 +1244,9 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
|
|
node->objNode->header.gfx.scale);
|
|
+ mtxf_copy(gMatStackInterpolated[gMatStackIndex + 1], (void *) gCurGraphNodeObject->throwMatrixInterpolated);
|
|
+ gMatStackInterpolated[gMatStackIndex + 1][3][0] = gMatStackInterpolated[gMatStackIndex][3][0];
|
|
+ gMatStackInterpolated[gMatStackIndex + 1][3][1] = gMatStackInterpolated[gMatStackIndex][3][1];
|
|
+ gMatStackInterpolated[gMatStackIndex + 1][3][2] = gMatStackInterpolated[gMatStackIndex][3][2];
|
|
+ mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mat, gMatStackInterpolated[gMatStackIndex + 1]);
|
|
+ mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex + 1],
|
|
+ scaleInterpolated);
|
|
if (node->fnNode.func != NULL) {
|
|
@@ -900,2 +1258,4 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
|
|
gMatStackFixed[gMatStackIndex] = mtx;
|
|
+ mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]);
|
|
+ gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated;
|
|
gGeoTempState.type = gCurAnimType;
|
|
@@ -906,2 +1266,3 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
|
|
gGeoTempState.data = gCurAnimData;
|
|
+ gGeoTempState.prevFrame = gPrevAnimFrame;
|
|
gCurAnimType = 0;
|
|
@@ -920,2 +1281,3 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) {
|
|
gCurAnimData = gGeoTempState.data;
|
|
+ gPrevAnimFrame = gGeoTempState.prevFrame;
|
|
gMatStackIndex--;
|
|
@@ -1041,2 +1403,3 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor)
|
|
Vp *viewport = alloc_display_list(sizeof(*viewport));
|
|
+ Vp *viewportInterpolated = viewport;
|
|
|
|
@@ -1051,3 +1414,8 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor)
|
|
clear_frame_buffer(clearColor);
|
|
- make_viewport_clip_rect(b);
|
|
+ viewportInterpolated = alloc_display_list(sizeof(*viewportInterpolated));
|
|
+ interpolate_vectors_s16(viewportInterpolated->vp.vtrans, sPrevViewport.vp.vtrans, b->vp.vtrans);
|
|
+ interpolate_vectors_s16(viewportInterpolated->vp.vscale, sPrevViewport.vp.vscale, b->vp.vscale);
|
|
+
|
|
+ sViewportPos = gDisplayListHead;
|
|
+ make_viewport_clip_rect(viewportInterpolated);
|
|
*viewport = *b;
|
|
@@ -1059,2 +1427,3 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor)
|
|
}
|
|
+ sPrevViewport = *viewport;
|
|
|
|
@@ -1063,3 +1432,7 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor)
|
|
gMatStackFixed[gMatStackIndex] = initialMatrix;
|
|
- gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(viewport));
|
|
+
|
|
+ mtxf_identity(gMatStackInterpolated[gMatStackIndex]);
|
|
+ gMatStackInterpolatedFixed[gMatStackIndex] = initialMatrix;
|
|
+
|
|
+ gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(viewportInterpolated));
|
|
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(gMatStackFixed[gMatStackIndex]),
|
|
diff --git a/src/game/screen_transition.c b/src/game/screen_transition.c
|
|
index b49ddaf5..d6656af2 100644
|
|
--- a/src/game/screen_transition.c
|
|
+++ b/src/game/screen_transition.c
|
|
@@ -18,2 +18,15 @@ u16 sTransitionTextureFadeCount[2] = { 0 };
|
|
|
|
+static Gfx *sScreenTransitionVerticesPos[2];
|
|
+static Vtx *sScreenTransitionVertices;
|
|
+
|
|
+void patch_screen_transition_interpolated(void) {
|
|
+ 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;
|
|
+ }
|
|
+}
|
|
+
|
|
s32 set_and_reset_transition_fade_timer(s8 fadeTimer, u8 transTime) {
|
|
@@ -87,2 +100,4 @@ s32 render_fade_transition_into_color(s8 fadeTimer, u8 transTime, struct WarpTra
|
|
|
|
+#if 0
|
|
+
|
|
s16 calc_tex_transition_radius(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData) {
|
|
@@ -92,5 +107,18 @@ s16 calc_tex_transition_radius(s8 fadeTimer, s8 transTime, struct WarpTransition
|
|
|
|
- return (s16)(result + 0.5);;
|
|
+ return (s16)(result + 0.5);
|
|
}
|
|
|
|
+#else
|
|
+
|
|
+s16 calc_tex_transition_radius(s8 fadeTimer, f32 interpolationFraction, s8 transTime, struct WarpTransitionData *transData) {
|
|
+ f32 texRadius = transData->endTexRadius - transData->startTexRadius;
|
|
+ f32 radiusTime = (sTransitionColorFadeCount[fadeTimer] == 0 ? 0 :
|
|
+ sTransitionColorFadeCount[fadeTimer] - 1 + interpolationFraction) * texRadius / (f32)(transTime - 1);
|
|
+ f32 result = transData->startTexRadius + radiusTime;
|
|
+
|
|
+ return (s16)(result + 0.5);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
f32 calc_tex_transition_time(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData) {
|
|
@@ -168,2 +196,4 @@ void *sTextureTransitionID[] = {
|
|
|
|
+#if 0
|
|
+
|
|
s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData, s8 texID, s8 transTexType) {
|
|
@@ -208,2 +238,52 @@ s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransition
|
|
|
|
+#else
|
|
+
|
|
+s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData, s8 texID, s8 transTexType) {
|
|
+ f32 texTransTime = calc_tex_transition_time(fadeTimer, transTime, transData);
|
|
+ u16 texTransPos = convert_tex_transition_angle_to_pos(transData);
|
|
+ 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);
|
|
+ Vtx *verts = alloc_display_list(8 * sizeof(*verts));
|
|
+ Vtx *vertsInterpolated = alloc_display_list(8 * sizeof(*vertsInterpolated));
|
|
+
|
|
+ if (verts != NULL && vertsInterpolated != NULL) {
|
|
+ load_tex_transition_vertex(verts, fadeTimer, transData, centerTransX, centerTransY, texTransRadius, transTexType);
|
|
+ load_tex_transition_vertex(vertsInterpolated, fadeTimer, transData, centerTransX, centerTransY, texTransRadiusInterpolated, transTexType);
|
|
+ sScreenTransitionVertices = verts;
|
|
+ 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);
|
|
+ gSPDisplayList(gDisplayListHead++, dl_transition_draw_filled_region);
|
|
+ gDPPipeSync(gDisplayListHead++);
|
|
+ gDPSetCombineMode(gDisplayListHead++, G_CC_MODULATEIDECALA, G_CC_MODULATEIDECALA);
|
|
+ gDPSetRenderMode(gDisplayListHead++, G_RM_AA_XLU_SURF, G_RM_AA_XLU_SURF2);
|
|
+ gDPSetTextureFilter(gDisplayListHead++, G_TF_BILERP);
|
|
+ switch (transTexType) {
|
|
+ case TRANS_TYPE_MIRROR:
|
|
+ gDPLoadTextureBlock(gDisplayListHead++, sTextureTransitionID[texID], G_IM_FMT_IA, G_IM_SIZ_8b, 32, 64, 0,
|
|
+ G_TX_WRAP | G_TX_MIRROR, G_TX_WRAP | G_TX_MIRROR, 5, 6, G_TX_NOLOD, G_TX_NOLOD);
|
|
+ break;
|
|
+ case TRANS_TYPE_CLAMP:
|
|
+ gDPLoadTextureBlock(gDisplayListHead++, sTextureTransitionID[texID], G_IM_FMT_IA, G_IM_SIZ_8b, 64, 64, 0,
|
|
+ G_TX_CLAMP, G_TX_CLAMP, 6, 6, G_TX_NOLOD, G_TX_NOLOD);
|
|
+ break;
|
|
+ }
|
|
+ gSPTexture(gDisplayListHead++, 0xFFFF, 0xFFFF, 0, G_TX_RENDERTILE, G_ON);
|
|
+ sScreenTransitionVerticesPos[1] = gDisplayListHead;
|
|
+ gSPVertex(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(vertsInterpolated), 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);
|
|
+ sTransitionTextureFadeCount[fadeTimer] += transData->texTimer;
|
|
+ } else {
|
|
+ }
|
|
+ return set_and_reset_transition_fade_timer(fadeTimer, transTime);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
int render_screen_transition(s8 fadeTimer, s8 transType, u8 transTime, struct WarpTransitionData *transData) {
|
|
diff --git a/src/game/skybox.c b/src/game/skybox.c
|
|
index 258ef0a3..bf92d0d5 100644
|
|
--- a/src/game/skybox.c
|
|
+++ b/src/game/skybox.c
|
|
@@ -253,3 +253,3 @@ void *create_skybox_ortho_matrix(s8 player) {
|
|
Gfx *init_skybox_display_list(s8 player, s8 background, s8 colorIndex) {
|
|
- s32 dlCommandCount = 7 + (3 * 3) * 7; // 5 for the start and end, plus 9 skybox tiles
|
|
+ s32 dlCommandCount = 124; // 5 for the start and end, plus 9 skybox tiles
|
|
void *skybox = alloc_display_list(dlCommandCount * sizeof(Gfx));
|
|
diff --git a/src/menu/intro_geo.c b/src/menu/intro_geo.c
|
|
index 1d3be071..01c5ad61 100644
|
|
--- a/src/menu/intro_geo.c
|
|
+++ b/src/menu/intro_geo.c
|
|
@@ -2,2 +2,3 @@
|
|
|
|
+#include "engine/math_util.h"
|
|
#include "game/memory.h"
|
|
@@ -72,2 +73,14 @@ s8 gameOverBackgroundFlipOrder[] = { 0x00, 0x01, 0x02, 0x03, 0x07, 0x0B,
|
|
|
|
+static Gfx *sIntroScalePos;
|
|
+static Vec3f sIntroScale;
|
|
+
|
|
+void patch_title_screen_scales(void) {
|
|
+ if (sIntroScalePos != NULL) {
|
|
+ Mtx *scaleMat = alloc_display_list(sizeof(*scaleMat));
|
|
+ guScale(scaleMat, sIntroScale[0], sIntroScale[1], sIntroScale[2]);
|
|
+ gSPMatrix(sIntroScalePos, scaleMat, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
|
|
+ sIntroScalePos = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
|
|
@@ -82,2 +95,4 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
|
|
f32 scaleZ; // sp2c
|
|
+ Vec3f scale;
|
|
+ Vec3f scaleInterpolated;
|
|
graphNode = sp54;
|
|
@@ -113,2 +128,7 @@ Gfx *geo_title_screen(s32 sp50, struct GraphNode *sp54, UNUSED void *context) {
|
|
guScale(scaleMat, scaleX, scaleY, scaleZ);
|
|
+ vec3f_set(scale, scaleX, scaleY, scaleZ);
|
|
+ interpolate_vectors(scaleInterpolated, sIntroScale, scale);
|
|
+ vec3f_set(sIntroScale, scaleX, scaleY, scaleZ);
|
|
+ guScale(scaleMat, scaleInterpolated[0], scaleInterpolated[1], scaleInterpolated[2]);
|
|
+ sIntroScalePos = displayListIter;
|
|
gSPMatrix(displayListIter++, scaleMat, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
|
|
diff --git a/src/pc/gfx/gfx_dxgi.cpp b/src/pc/gfx/gfx_dxgi.cpp
|
|
index 04674952..fa4eb33c 100644
|
|
--- a/src/pc/gfx/gfx_dxgi.cpp
|
|
+++ b/src/pc/gfx/gfx_dxgi.cpp
|
|
@@ -38,6 +38,6 @@
|
|
#define FRAME_INTERVAL_US_NUMERATOR 40000
|
|
-#define FRAME_INTERVAL_US_DENOMINATOR 1
|
|
+#define FRAME_INTERVAL_US_DENOMINATOR 2
|
|
#else
|
|
#define FRAME_INTERVAL_US_NUMERATOR 100000
|
|
-#define FRAME_INTERVAL_US_DENOMINATOR 3
|
|
+#define FRAME_INTERVAL_US_DENOMINATOR 6
|
|
#endif
|
|
diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c
|
|
index 4d907893..0b21e230 100644
|
|
--- a/src/pc/gfx/gfx_sdl2.c
|
|
+++ b/src/pc/gfx/gfx_sdl2.c
|
|
@@ -55,3 +55,3 @@ static bool use_timer = true;
|
|
// time between consequtive game frames
|
|
-static const int frame_time = 1000 / FRAMERATE;
|
|
+static const int frame_time = 1000 / (2 * FRAMERATE);
|
|
|
|
@@ -144,3 +144,7 @@ static inline void gfx_sdl_set_vsync(const bool enabled) {
|
|
SDL_GL_SetSwapInterval(1);
|
|
- const int vblanks = test_vsync();
|
|
+ int vblanks = test_vsync();
|
|
+ if (vblanks & 1)
|
|
+ vblanks = 0; // not divisible by 60, fuck that
|
|
+ else
|
|
+ vblanks /= 2;
|
|
if (vblanks) {
|
|
diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c
|
|
index 3a725c03..7bff83d5 100644
|
|
--- a/src/pc/pc_main.c
|
|
+++ b/src/pc/pc_main.c
|
|
@@ -87,2 +87,21 @@ void send_display_list(struct SPTask *spTask) {
|
|
|
|
+static inline void patch_interpolations(void) {
|
|
+ extern void mtx_patch_interpolated(void);
|
|
+ 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);
|
|
+ mtx_patch_interpolated();
|
|
+ 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();
|
|
+}
|
|
+
|
|
void produce_one_frame(void) {
|
|
@@ -114,2 +133,7 @@ void produce_one_frame(void) {
|
|
gfx_end_frame();
|
|
+
|
|
+ gfx_start_frame();
|
|
+ patch_interpolations();
|
|
+ send_display_list(gGfxSPTask);
|
|
+ gfx_end_frame();
|
|
}
|