mirror of
https://github.com/izzy2lost/Ghostship.git
synced 2026-06-19 01:17:03 -07:00
[WIP] Implemented frame interpolation
This commit is contained in:
@@ -500,6 +500,18 @@ extern void osCreateViManager(OSPri);
|
||||
extern uintptr_t osVirtualToPhysical(void *addr);
|
||||
extern void * osPhysicalToVirtual(u32);
|
||||
extern void osMapTLB(int32_t a, uint32_t b, void* c, uint32_t d, uint32_t e, uint32_t f);
|
||||
|
||||
// Interpolation
|
||||
|
||||
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);
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
@@ -109,6 +109,10 @@ struct AnimInfo {
|
||||
/*0x0A 0x42*/ u16 animTimer;
|
||||
/*0x0C 0x44*/ s32 animFrameAccelAssist;
|
||||
/*0x10 0x48*/ s32 animAccel;
|
||||
s16 prevAnimFrame;
|
||||
s16 prevAnimID;
|
||||
u32 prevAnimFrameTimestamp;
|
||||
struct Animation *prevAnimPtr;
|
||||
};
|
||||
|
||||
struct GraphNodeObject {
|
||||
@@ -118,11 +122,22 @@ struct GraphNodeObject {
|
||||
/*0x19*/ s8 activeAreaIndex;
|
||||
/*0x1A*/ Vec3s angle;
|
||||
/*0x20*/ Vec3f pos;
|
||||
Vec3s prevAngle;
|
||||
Vec3f prevPos;
|
||||
u32 prevTimestamp;
|
||||
Vec3f prevShadowPos;
|
||||
u32 prevShadowPosTimestamp;
|
||||
/*0x2C*/ Vec3f scale;
|
||||
Vec3f prevScale;
|
||||
u32 prevScaleTimestamp;
|
||||
/*0x38*/ struct AnimInfo animInfo;
|
||||
/*0x4C*/ struct SpawnInfo *unk4C;
|
||||
/*0x50*/ Mat4 *throwMatrix; // matrix ptr
|
||||
Mat4 prevThrowMatrix;
|
||||
u32 prevThrowMatrixTimestamp;
|
||||
Mat4 *throwMatrixInterpolated;
|
||||
/*0x54*/ Vec3f cameraToObject;
|
||||
u32 skipInterpolationTimestamp;
|
||||
};
|
||||
|
||||
struct ObjectNode {
|
||||
@@ -227,6 +242,10 @@ struct Surface {
|
||||
} normal;
|
||||
/*0x28*/ f32 originOffset;
|
||||
/*0x2C*/ struct Object *object;
|
||||
Vec3s prevVertex1;
|
||||
Vec3s prevVertex2;
|
||||
Vec3s prevVertex3;
|
||||
u32 modifiedTimestamp;
|
||||
};
|
||||
|
||||
struct MarioBodyState {
|
||||
|
||||
+15
-1
@@ -105,6 +105,8 @@ struct GraphNodePerspective {
|
||||
/*0x1C*/ f32 fov; // horizontal field of view in degrees
|
||||
/*0x20*/ s16 near; // near clipping plane
|
||||
/*0x22*/ s16 far; // far clipping plane
|
||||
f32 prevFov;
|
||||
f32 prevTimestamp;
|
||||
};
|
||||
|
||||
/** An entry in the master list. It is a linked list of display lists
|
||||
@@ -112,7 +114,9 @@ struct GraphNodePerspective {
|
||||
*/
|
||||
struct DisplayListNode {
|
||||
Mtx *transform;
|
||||
void *transformInterpolated;
|
||||
void *displayList;
|
||||
void *displayListInterpolated;
|
||||
struct DisplayListNode *next;
|
||||
};
|
||||
|
||||
@@ -174,7 +178,11 @@ struct GraphNodeCamera {
|
||||
} config;
|
||||
/*0x1C*/ Vec3f pos;
|
||||
/*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.
|
||||
/*0x3A*/ s16 rollScreen; // rolls screen while keeping the light direction consistent
|
||||
};
|
||||
@@ -212,7 +220,8 @@ struct GraphNodeRotation {
|
||||
/*0x00*/ struct GraphNode node;
|
||||
/*0x14*/ void *displayList;
|
||||
/*0x18*/ Vec3s rotation;
|
||||
u8 filler[2];
|
||||
Vec3s prevRotation;
|
||||
u32 prevTimestamp;
|
||||
};
|
||||
|
||||
/** GraphNode part that transforms itself and its children based on animation
|
||||
@@ -301,6 +310,9 @@ struct GraphNodeBackground {
|
||||
/*0x00*/ struct FnGraphNode fnNode;
|
||||
/*0x18*/ s32 unused;
|
||||
/*0x1C*/ s32 background; // background ID, or rgba5551 color if fnNode.func is null
|
||||
Vec3f prevCameraPos;
|
||||
Vec3f prevCameraFocus;
|
||||
u32 prevCameraTimestamp;
|
||||
};
|
||||
|
||||
/** Renders the object that Mario is holding.
|
||||
@@ -310,6 +322,8 @@ struct GraphNodeHeldObject {
|
||||
/*0x18*/ s32 playerIndex;
|
||||
/*0x1C*/ struct Object *objNode;
|
||||
/*0x20*/ Vec3s translation;
|
||||
Vec3f prevShadowPos;
|
||||
u32 prevShadowPosTimestamp;
|
||||
};
|
||||
|
||||
/** A node that allows an object to specify a different culling radius than the
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "game/object_list_processor.h"
|
||||
#include "surface_collision.h"
|
||||
#include "surface_load.h"
|
||||
#include "game/game_init.h"
|
||||
|
||||
/**************************************************
|
||||
* WALLS *
|
||||
@@ -395,26 +396,44 @@ f32 find_floor_height_and_data(f32 xPos, f32 yPos, f32 zPos, struct FloorGeometr
|
||||
return floorHeight;
|
||||
}
|
||||
|
||||
u8 gInterpolatingSurfaces;
|
||||
|
||||
/**
|
||||
* Iterate through the list of floors and find the first floor under a given point.
|
||||
*/
|
||||
static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32 x, s32 y, s32 z, f32 *pheight) {
|
||||
register struct Surface *surf;
|
||||
register s32 x1, z1, x2, z2, x3, z3;
|
||||
register f32 x1, z1, x2, z2, x3, z3;
|
||||
f32 nx, ny, nz;
|
||||
f32 oo;
|
||||
f32 height;
|
||||
struct Surface *floor = NULL;
|
||||
s32 interpolate;
|
||||
|
||||
// Iterate through the list of floors until there are no more floors.
|
||||
while (surfaceNode != NULL) {
|
||||
surf = surfaceNode->surface;
|
||||
surfaceNode = surfaceNode->next;
|
||||
interpolate = gInterpolatingSurfaces && surf->modifiedTimestamp == gGlobalTimer;
|
||||
|
||||
x1 = surf->vertex1[0];
|
||||
z1 = surf->vertex1[2];
|
||||
x2 = surf->vertex2[0];
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the point is within the triangle bounds.
|
||||
if ((z1 - z) * (x2 - x1) - (x1 - x) * (z2 - z1) < 0) {
|
||||
@@ -424,6 +443,10 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
|
||||
// To slightly save on computation time, set this later.
|
||||
x3 = surf->vertex3[0];
|
||||
z3 = surf->vertex3[2];
|
||||
if (interpolate) {
|
||||
x3 = (surf->prevVertex3[0] + x3) / 2;
|
||||
z3 = (surf->prevVertex3[2] + z3) / 2;
|
||||
}
|
||||
|
||||
if ((z2 - z) * (x3 - x2) - (x2 - x) * (z3 - z2) < 0) {
|
||||
continue;
|
||||
@@ -443,10 +466,30 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
|
||||
continue;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// If a wall, ignore it. Likely a remnant, should never occur.
|
||||
if (ny == 0.0f) {
|
||||
@@ -461,6 +504,15 @@ 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;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "game/mario.h"
|
||||
#include "game/object_list_processor.h"
|
||||
#include "surface_load.h"
|
||||
#include "game/game_init.h"
|
||||
|
||||
s32 unused8038BE90;
|
||||
|
||||
@@ -357,6 +358,11 @@ static struct Surface *read_surface_data(s16 *vertexData, s16 **vertexIndices) {
|
||||
|
||||
surface = alloc_surface();
|
||||
|
||||
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;
|
||||
surface->vertex2[0] = x2;
|
||||
surface->vertex3[0] = x3;
|
||||
|
||||
@@ -487,6 +487,10 @@ CameraTransition sModeTransitions[] = {
|
||||
extern u8 sDanceCutsceneIndexTable[][4];
|
||||
extern u8 sZoomOutAreaMasks[];
|
||||
|
||||
static void skip_camera_interpolation(void) {
|
||||
gLakituState.skipCameraInterpolationTimestamp = gGlobalTimer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a camera shake triggered by an interaction
|
||||
*/
|
||||
@@ -5504,6 +5508,7 @@ s32 set_camera_mode_fixed(struct Camera *c, s16 x, s16 y, s16 z) {
|
||||
c->mode = CAMERA_MODE_FIXED;
|
||||
vec3f_set(c->pos, sFixedModeBasePosition[0], sMarioCamState->pos[1],
|
||||
sFixedModeBasePosition[2]);
|
||||
skip_camera_interpolation();
|
||||
}
|
||||
return basePosSet;
|
||||
}
|
||||
@@ -5654,6 +5659,7 @@ BAD_RETURN(s32) cam_rr_enter_building_side(struct Camera *c) {
|
||||
if (c->mode != CAMERA_MODE_FIXED) {
|
||||
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
|
||||
c->mode = CAMERA_MODE_FIXED;
|
||||
skip_camera_interpolation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5849,6 +5855,7 @@ BAD_RETURN(s32) cam_castle_enter_lobby(struct Camera *c) {
|
||||
sStatusFlags &= ~CAM_FLAG_SMOOTH_MOVEMENT;
|
||||
set_fixed_cam_axis_sa_lobby(c->mode);
|
||||
c->mode = CAMERA_MODE_FIXED;
|
||||
skip_camera_interpolation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7212,6 +7219,7 @@ BAD_RETURN(s32) cutscene_unused_loop(UNUSED struct Camera *c) {
|
||||
BAD_RETURN(s32) cutscene_ending_mario_fall_start(struct Camera *c) {
|
||||
vec3f_set(c->focus, -26.f, 0.f, -137.f);
|
||||
vec3f_set(c->pos, 165.f, 4725.f, 324.f);
|
||||
skip_camera_interpolation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7244,6 +7252,7 @@ BAD_RETURN(s32) cutscene_ending_mario_fall(struct Camera *c) {
|
||||
BAD_RETURN(s32) cutscene_ending_mario_land_closeup(struct Camera *c) {
|
||||
vec3f_set(c->focus, 85.f, 826.f, 250.f);
|
||||
vec3f_set(c->pos, -51.f, 988.f, -202.f);
|
||||
skip_camera_interpolation();
|
||||
player2_rotate_cam(c, -0x2000, 0x2000, -0x2000, 0x2000);
|
||||
}
|
||||
|
||||
@@ -7253,6 +7262,7 @@ BAD_RETURN(s32) cutscene_ending_mario_land_closeup(struct Camera *c) {
|
||||
BAD_RETURN(s32) cutscene_ending_reset_spline(UNUSED struct Camera *c) {
|
||||
sCutsceneVars[9].point[0] = 0.f;
|
||||
cutscene_reset_spline();
|
||||
skip_camera_interpolation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7288,6 +7298,7 @@ BAD_RETURN(s32) cutscene_ending_peach_appear_closeup(struct Camera *c) {
|
||||
vec3f_set(c->pos, 179.f, 2463.f, -1216.f);
|
||||
c->pos[1] = gCutsceneFocus->oPosY + 35.f;
|
||||
vec3f_set(c->focus, gCutsceneFocus->oPosX, gCutsceneFocus->oPosY + 125.f, gCutsceneFocus->oPosZ);
|
||||
skip_camera_interpolation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7306,6 +7317,7 @@ BAD_RETURN(s32) cutscene_ending_peach_appears(struct Camera *c) {
|
||||
BAD_RETURN(s32) cutscene_ending_peach_descends_start(UNUSED struct Camera *c) {
|
||||
cutscene_reset_spline();
|
||||
sCutsceneVars[2].point[1] = 150.f;
|
||||
skip_camera_interpolation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7393,6 +7405,7 @@ BAD_RETURN(s32) cutscene_ending_dialog(struct Camera *c) {
|
||||
vec3f_set(c->focus, 11.f, 983.f, -1273.f);
|
||||
vec3f_set(c->pos, -473.f, 970.f, -1152.f);
|
||||
player2_rotate_cam(c, -0x800, 0x2000, -0x2000, 0x2000);
|
||||
skip_camera_interpolation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7402,6 +7415,7 @@ BAD_RETURN(s32) cutscene_ending_kiss_closeup(struct Camera *c) {
|
||||
set_fov_function(CAM_FOV_SET_29);
|
||||
vec3f_set(c->focus, 350.f, 1034.f, -1216.f);
|
||||
vec3f_set(c->pos, -149.f, 1021.f, -1216.f);
|
||||
skip_camera_interpolation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7437,6 +7451,7 @@ BAD_RETURN(s32) cutscene_ending_kiss(struct Camera *c) {
|
||||
BAD_RETURN(s32) cutscene_ending_look_at_sky(struct Camera *c) {
|
||||
move_point_along_spline(c->focus, sEndingLookAtSkyFocus, &sCutsceneSplineSegment, &sCutsceneSplineSegmentProgress);
|
||||
vec3f_set(c->pos, 699.f, 1680.f, -703.f);
|
||||
skip_camera_interpolation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -10257,6 +10272,7 @@ BAD_RETURN(s32) cutscene_door_start(struct Camera *c) {
|
||||
BAD_RETURN(s32) cutscene_door_fix_cam(struct Camera *c) {
|
||||
vec3f_copy(c->pos, sCutsceneVars[0].point);
|
||||
vec3f_copy(c->focus, sCutsceneVars[1].point);
|
||||
skip_camera_interpolation();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -10290,6 +10306,7 @@ BAD_RETURN(s32) cutscene_door_move_behind_mario(struct Camera *c) {
|
||||
}
|
||||
|
||||
offset_rotated(c->pos, sMarioCamState->pos, camOffset, sCutsceneVars[0].angle);
|
||||
skip_camera_interpolation();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -639,6 +639,8 @@ struct LakituState {
|
||||
/// Mario's action from the previous frame. Only used to determine if Mario just finished a dive.
|
||||
/*0xB8*/ u32 lastFrameAction;
|
||||
/*0xBC*/ s16 unused;
|
||||
|
||||
u32 skipCameraInterpolationTimestamp;
|
||||
};
|
||||
|
||||
// bss order hack to not affect BSS order. if possible, remove me, but it will be hard to match otherwise
|
||||
|
||||
@@ -35,6 +35,20 @@ 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];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the particle with the given index is
|
||||
* laterally within distance of point (x, z). Used to
|
||||
@@ -239,6 +253,7 @@ void envfx_update_whirlpool(void) {
|
||||
(gEnvFxBuffer + i)->yPos = (i + gEnvFxBuffer)->bubbleY;
|
||||
(gEnvFxBuffer + i)->unusedBubbleVar = 0;
|
||||
(gEnvFxBuffer + i)->isAlive = TRUE;
|
||||
(gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
|
||||
|
||||
envfx_rotate_around_whirlpool(&(gEnvFxBuffer + i)->xPos, &(gEnvFxBuffer + i)->yPos,
|
||||
&(gEnvFxBuffer + i)->zPos);
|
||||
@@ -297,6 +312,7 @@ void envfx_update_jetstream(void) {
|
||||
+ 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;
|
||||
} else {
|
||||
(gEnvFxBuffer + i)->angleAndDist[1] += 10;
|
||||
(gEnvFxBuffer + i)->xPos += sins((gEnvFxBuffer + i)->angleAndDist[0]) * 10.0f;
|
||||
@@ -471,6 +487,12 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro
|
||||
Vec3s vertex1;
|
||||
Vec3s vertex2;
|
||||
Vec3s vertex3;
|
||||
Vec3s interpolatedVertices[3];
|
||||
|
||||
static Vec3s prevVertex1;
|
||||
static Vec3s prevVertex2;
|
||||
static Vec3s prevVertex3;
|
||||
static u32 prevTimestamp;
|
||||
|
||||
Gfx *gfxStart = alloc_display_list(((sBubbleParticleMaxCount / 5) * 10 + sBubbleParticleMaxCount + 3)
|
||||
* sizeof(Gfx));
|
||||
@@ -484,18 +506,53 @@ Gfx *envfx_update_bubble_particles(s32 mode, UNUSED Vec3s marioPos, Vec3s camFro
|
||||
envfx_bubbles_update_switch(mode, camTo, vertex1, vertex2, vertex3);
|
||||
rotate_triangle_vertices(vertex1, vertex2, vertex3, pitch, yaw);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
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++);
|
||||
|
||||
+43
-17
@@ -55,6 +55,26 @@ 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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize snow particles by allocating a buffer for storing their state
|
||||
* and setting a start amount.
|
||||
@@ -220,6 +240,7 @@ void envfx_update_snow_normal(s32 snowCylinderX, s32 snowCylinderY, s32 snowCyli
|
||||
400.0f * random_float() - 200.0f + snowCylinderZ + (s16)(deltaZ * 2);
|
||||
(gEnvFxBuffer + i)->yPos = 200.0f * random_float() + snowCylinderY;
|
||||
(gEnvFxBuffer + i)->isAlive = TRUE;
|
||||
(gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
|
||||
} else {
|
||||
(gEnvFxBuffer + i)->xPos += random_float() * 2 - 1.0f + (s16)(deltaX / 1.2);
|
||||
(gEnvFxBuffer + i)->yPos -= 2 -(s16)(deltaY * 0.8);
|
||||
@@ -254,6 +275,7 @@ void envfx_update_snow_blizzard(s32 snowCylinderX, s32 snowCylinderY, s32 snowCy
|
||||
400.0f * random_float() - 200.0f + snowCylinderZ + (s16)(deltaZ * 2);
|
||||
(gEnvFxBuffer + i)->yPos = 400.0f * random_float() - 200.0f + snowCylinderY;
|
||||
(gEnvFxBuffer + i)->isAlive = TRUE;
|
||||
(gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
|
||||
} else {
|
||||
(gEnvFxBuffer + i)->xPos += random_float() * 2 - 1.0f + (s16)(deltaX / 1.2) + 20.0f;
|
||||
(gEnvFxBuffer + i)->yPos -= 5 -(s16)(deltaY * 0.8);
|
||||
@@ -297,6 +319,7 @@ void envfx_update_snow_water(s32 snowCylinderX, s32 snowCylinderY, s32 snowCylin
|
||||
(gEnvFxBuffer + i)->zPos = 400.0f * random_float() - 200.0f + snowCylinderZ;
|
||||
(gEnvFxBuffer + i)->yPos = 400.0f * random_float() - 200.0f + snowCylinderY;
|
||||
(gEnvFxBuffer + i)->isAlive = TRUE;
|
||||
(gEnvFxBuffer + i)->spawnTimestamp = gGlobalTimer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,29 +370,30 @@ void rotate_triangle_vertices(Vec3s vertex1, Vec3s vertex2, Vec3s vertex3, s16 p
|
||||
void append_snowflake_vertex_buffer(Gfx *gfx, s32 index, Vec3s vertex1, Vec3s vertex2, Vec3s vertex3) {
|
||||
s32 i = 0;
|
||||
Vtx *vertBuf = (Vtx *) alloc_display_list(15 * sizeof(Vtx));
|
||||
Vtx *vertBufInterpolated = (Vtx *) alloc_display_list(15 * sizeof(Vtx));
|
||||
Vtx *v;
|
||||
|
||||
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];
|
||||
|
||||
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 + 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];
|
||||
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];
|
||||
}
|
||||
|
||||
gSPVertex(gfx, VIRTUAL_TO_PHYSICAL(vertBuf), 15, 0);
|
||||
sPrevSnowVertices[index / 5].pos = gfx;
|
||||
gSPVertex(gfx, VIRTUAL_TO_PHYSICAL(vertBufInterpolated), 15, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -453,6 +477,8 @@ 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++);
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ struct EnvFxParticle {
|
||||
s32 angleAndDist[2]; // for whirpools, [0] = angle from center, [1] = distance from center
|
||||
s32 unusedBubbleVar; // set to zero for bubbles when respawning, never used elsewhere
|
||||
s32 bubbleY; // for Bubbles, yPos is always set to this
|
||||
u8 filler[24];
|
||||
u32 spawnTimestamp;
|
||||
};
|
||||
|
||||
extern s8 gEnvFxMode;
|
||||
|
||||
+24
-1
@@ -57,6 +57,20 @@ UNUSED static struct UnusedHUDStruct sUnusedHUDValues = { 0x00, 0x0A, 0x00 };
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a rgba16 16x16 glyph texture from a table list.
|
||||
*/
|
||||
@@ -107,12 +121,21 @@ void render_power_meter_health_segment(s16 numHealthWedges) {
|
||||
*/
|
||||
void render_dl_power_meter(s16 numHealthWedges) {
|
||||
Mtx *mtx = alloc_display_list(sizeof(Mtx));
|
||||
f32 interpolatedY;
|
||||
|
||||
if (mtx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx++),
|
||||
G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
|
||||
|
||||
@@ -116,6 +116,41 @@ u8 gMenuHoldKeyIndex = 0;
|
||||
u8 gMenuHoldKeyTimer = 0;
|
||||
s32 gDialogResponse = DIALOG_RESPONSE_NONE;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void create_dl_identity_matrix(void) {
|
||||
Mtx *matrix = (Mtx *) alloc_display_list(sizeof(Mtx));
|
||||
@@ -957,6 +992,14 @@ 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;
|
||||
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);
|
||||
// convert the speed into angle
|
||||
create_dl_rotation_matrix(MENU_MTX_NOPUSH, gDialogBoxOpenTimer * 4.0f, 0, 0, 1.0f);
|
||||
@@ -965,6 +1008,12 @@ void render_dialog_box_type(struct DialogEntry *dialog, s8 linesPerBox) {
|
||||
break;
|
||||
case DIALOG_TYPE_ZOOM: // Renders a dialog white box with zoom
|
||||
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),
|
||||
(40.0 / gDialogBoxScale) - 40, 0);
|
||||
create_dl_scale_matrix(MENU_MTX_NOPUSH, 1.0 / gDialogBoxScale, 1.0 / gDialogBoxScale, 1.0f);
|
||||
@@ -1236,6 +1285,8 @@ 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);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -34,12 +34,16 @@ Gfx *geo_envfx_main(s32 callContext, struct GraphNode *node, Mat4 mtxf) {
|
||||
vec3f_to_vec3s(marioPos, gPlayerCameraState->pos);
|
||||
particleList = envfx_update_particles(snowMode, marioPos, camTo, camFrom);
|
||||
if (particleList != NULL) {
|
||||
#if FALSE
|
||||
Mtx *mtx = alloc_display_list(sizeof(*mtx));
|
||||
|
||||
gfx = alloc_display_list(2 * sizeof(*gfx));
|
||||
mtxf_to_mtx(mtx, mtxf);
|
||||
gSPMatrix(&gfx[0], VIRTUAL_TO_PHYSICAL(mtx), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH);
|
||||
gSPBranchList(&gfx[1], VIRTUAL_TO_PHYSICAL(particleList));
|
||||
#else
|
||||
gfx = particleList;
|
||||
#endif
|
||||
execNode->fnNode.node.flags = (execNode->fnNode.node.flags & 0xFF) | 0x400;
|
||||
}
|
||||
SET_HIGH_U16_OF_32(*params, gAreaUpdateCounter);
|
||||
|
||||
@@ -1536,6 +1536,7 @@ void cur_obj_set_pos_to_home(void) {
|
||||
o->oPosX = o->oHomeX;
|
||||
o->oPosY = o->oHomeY;
|
||||
o->oPosZ = o->oHomeZ;
|
||||
o->header.gfx.skipInterpolationTimestamp = gGlobalTimer;
|
||||
}
|
||||
|
||||
void cur_obj_set_pos_to_home_and_stop(void) {
|
||||
|
||||
@@ -189,6 +189,32 @@ struct Painting **sPaintingGroups[] = {
|
||||
s16 gPaintingUpdateCounter = 1;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop paintings in paintingGroup from rippling if their id is different from *idptr.
|
||||
*/
|
||||
@@ -893,6 +919,23 @@ Gfx *render_painting(u8 *img, s16 tWidth, s16 tHeight, s16 *textureMap, s16 mapV
|
||||
gSP1Triangle(gfx++, group * 3, group * 3 + 1, group * 3 + 2, 0);
|
||||
}
|
||||
|
||||
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);
|
||||
return dlist;
|
||||
}
|
||||
@@ -957,6 +1000,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;
|
||||
|
||||
// Update the ripple, may automatically reset the painting's state.
|
||||
painting_update_ripple_state(painting);
|
||||
@@ -994,6 +1038,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;
|
||||
|
||||
// Update the ripple, may automatically reset the painting's state.
|
||||
painting_update_ripple_state(painting);
|
||||
|
||||
+418
-51
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,19 @@
|
||||
u8 sTransitionColorFadeCount[4] = { 0 };
|
||||
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) {
|
||||
s32 reset = FALSE;
|
||||
|
||||
@@ -85,6 +98,8 @@ s32 render_fade_transition_into_color(s8 fadeTimer, u8 transTime, struct WarpTra
|
||||
return dl_transition_color(fadeTimer, transTime, transData, alpha);
|
||||
}
|
||||
|
||||
#if FALSE
|
||||
|
||||
s16 calc_tex_transition_radius(s8 fadeTimer, s8 transTime, struct WarpTransitionData *transData) {
|
||||
f32 texRadius = transData->endTexRadius - transData->startTexRadius;
|
||||
f32 radiusTime = sTransitionColorFadeCount[fadeTimer] * texRadius / (f32)(transTime - 1);
|
||||
@@ -93,6 +108,19 @@ s16 calc_tex_transition_radius(s8 fadeTimer, s8 transTime, struct WarpTransition
|
||||
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) {
|
||||
f32 startX = transData->startTexX;
|
||||
f32 startY = transData->startTexY;
|
||||
@@ -166,6 +194,8 @@ void *sTextureTransitionID[] = {
|
||||
texture_transition_bowser_half,
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
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);
|
||||
@@ -206,6 +236,56 @@ s32 render_textured_transition(s8 fadeTimer, s8 transTime, struct WarpTransition
|
||||
return set_and_reset_transition_fade_timer(fadeTimer, transTime);
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
s32 render_screen_transition(s8 fadeTimer, s8 transType, u8 transTime, struct WarpTransitionData *transData) {
|
||||
switch (transType) {
|
||||
case WARP_TRANSITION_FADE_FROM_COLOR:
|
||||
|
||||
+21
-1
@@ -1,5 +1,6 @@
|
||||
#include <libultra/types.h>
|
||||
|
||||
#include "engine/math_util.h"
|
||||
#include "game/memory.h"
|
||||
#include "game/segment2.h"
|
||||
#include "game/segment7.h"
|
||||
@@ -36,6 +37,18 @@ static s32 sGameOverTableIndex;
|
||||
static s16 sIntroFrameCounter;
|
||||
static s32 sTmCopyrightAlpha;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Geo callback to render the "Super Mario 64" logo on the title screen
|
||||
*/
|
||||
@@ -49,6 +62,8 @@ Gfx *geo_intro_super_mario_64_logo(s32 state, struct GraphNode *node, UNUSED voi
|
||||
f32 scaleX;
|
||||
f32 scaleY;
|
||||
f32 scaleZ;
|
||||
Vec3f scale;
|
||||
Vec3f scaleInterpolated;
|
||||
|
||||
if (state != 1) {
|
||||
sIntroFrameCounter = 0;
|
||||
@@ -80,7 +95,12 @@ Gfx *geo_intro_super_mario_64_logo(s32 state, struct GraphNode *node, UNUSED voi
|
||||
scaleY = 0.0f;
|
||||
scaleZ = 0.0f;
|
||||
}
|
||||
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 = dlIter;
|
||||
|
||||
gSPMatrix(dlIter++, scaleMat, G_MTX_MODELVIEW | G_MTX_MUL | G_MTX_PUSH);
|
||||
gSPDisplayList(dlIter++, &intro_seg7_dl_0700B3A0); // draw model
|
||||
|
||||
+17
-1
@@ -45,7 +45,7 @@ GameEngine::GameEngine(){
|
||||
}
|
||||
}
|
||||
this->context = LUS::Context::CreateInstance("Ghostship", "sm64", "ghostship.cfg.json", OTRFiles, { 0xFF2B5A63 }, 3);
|
||||
this->context->GetWindow()->SetTargetFps(30);
|
||||
this->context->GetWindow()->SetTargetFps(60);
|
||||
this->context->GetWindow()->SetMaximumFrameLatency(1);
|
||||
this->context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::SAnim, "Animation", std::make_shared<CubeOS::AnimationFactory>());
|
||||
this->context->GetResourceManager()->GetResourceLoader()->RegisterResourceFactory(LUS::ResourceType::Bank, "Bank", std::make_shared<CubeOS::AudioBankFactory>());
|
||||
@@ -98,6 +98,18 @@ void GameEngine::ProcessFrame(void (*run_one_game_iter)()) const {
|
||||
this->context->GetWindow()->MainLoop(run_one_game_iter);
|
||||
}
|
||||
|
||||
uint32_t GameEngine::GetInterpolationFPS() {
|
||||
if (LUS::Context::GetInstance()->GetWindow()->GetWindowBackend() == LUS::WindowBackend::DX11) {
|
||||
return CVarGetInteger("gInterpolationFPS", 30);
|
||||
}
|
||||
|
||||
if (CVarGetInteger("gMatchRefreshRate", 0)) {
|
||||
return LUS::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate();
|
||||
}
|
||||
|
||||
return std::min<uint32_t>(LUS::Context::GetInstance()->GetWindow()->GetCurrentRefreshRate(), CVarGetInteger("gInterpolationFPS", 30));
|
||||
}
|
||||
|
||||
// Audio
|
||||
|
||||
void GameEngine::HandleAudioThread(){
|
||||
@@ -171,6 +183,10 @@ void GameEngine::LoadDictionary() {
|
||||
this->dictionary = static_cast<std::unordered_map<std::string, std::vector<uint8_t>> *>(ResourceGetDataByName("__OTR__texts/strings/global"));
|
||||
}
|
||||
|
||||
extern "C" uint32_t GameEngine_GetInterpolatedFPS() {
|
||||
return GameEngine::GetInterpolationFPS();
|
||||
}
|
||||
|
||||
extern "C" uint32_t GameEngine_GetSampleRate() {
|
||||
auto player = LUS::Context::GetInstance()->GetAudio()->GetAudioPlayer();
|
||||
if (player == nullptr) {
|
||||
|
||||
@@ -29,6 +29,7 @@ class GameEngine {
|
||||
void StartFrame() const;
|
||||
static void RunCommands(Gfx* Commands);
|
||||
void ProcessFrame(void (*run_one_game_iter)()) const;
|
||||
static uint32_t GetInterpolationFPS();
|
||||
static void HandleAudioThread();
|
||||
static void StartAudioFrame();
|
||||
static void EndAudioFrame();
|
||||
@@ -40,6 +41,7 @@ class GameEngine {
|
||||
};
|
||||
#else
|
||||
|
||||
uint32_t GameEngine_GetInterpolatedFPS();
|
||||
uint32_t GameEngine_GetSampleRate();
|
||||
uint32_t GameEngine_GetSamplesPerFrame();
|
||||
float GameEngine_GetAspectRatio();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user