diff --git a/src/engine/graph_node.h b/src/engine/graph_node.h index 0f9e2914..a44689a7 100644 --- a/src/engine/graph_node.h +++ b/src/engine/graph_node.h @@ -124,9 +124,9 @@ struct GraphNodePerspective struct DisplayListNode { Mtx *transform; - void *transformInterpolated; + void *transformPrev; void *displayList; - void *displayListInterpolated; + void *displayListPrev; struct DisplayListNode *next; }; diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 5e87327d..405e260c 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -12,6 +12,7 @@ #include "sm64.h" #include "game/level_update.h" #include "pc/lua/smlua_hooks.h" +#include "pc/utils/misc.h" /** * This file contains the code that processes the scene graph for rendering. @@ -42,9 +43,9 @@ s16 gMatStackIndex; Mat4 gMatStack[MATRIX_STACK_SIZE] = {}; -Mat4 gMatStackInterpolated[MATRIX_STACK_SIZE] = {}; +Mat4 gMatStackPrev[MATRIX_STACK_SIZE] = {}; Mtx *gMatStackFixed[MATRIX_STACK_SIZE] = { 0 }; -Mtx *gMatStackInterpolatedFixed[MATRIX_STACK_SIZE] = { 0 }; +Mtx *gMatStackPrevFixed[MATRIX_STACK_SIZE] = { 0 }; /** * Animation nodes have state in global variables, so this struct captures @@ -137,45 +138,73 @@ u16 gAreaUpdateCounter = 0; LookAt lookAt; #endif -static Gfx *sPerspectivePos = NULL; -static Mtx *sPerspectiveMtx = NULL; +static struct GraphNodePerspective *sPerspectiveNode = NULL; +static Gfx* sPerspectivePos = NULL; +static Mtx* sPerspectiveMtx = NULL; +static f32 sPerspectiveAspect = 0; + +static Vp* sViewport = NULL; +static Gfx* sViewportPos = NULL; +static Gfx* sViewportClipPos = NULL; +static Vp sViewportPrev = { 0 }; +static Vp sViewportInterp = { 0 }; struct { Gfx *pos; void *mtx; void *displayList; + void *mtxPrev; + Mtx interp; } gMtxTbl[6400]; s32 gMtxTblSize; -static Gfx *sViewportPos = NULL; -static Vp sPrevViewport; - struct Object* gCurGraphNodeProcessingObject = NULL; struct MarioState* gCurGraphNodeMarioState = NULL; -void mtx_patch_interpolated(void) { - if (sPerspectivePos != NULL) { - gSPMatrix(sPerspectivePos, VIRTUAL_TO_PHYSICAL(sPerspectiveMtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); +void mtx_patch_interpolated(f32 delta) { + if (sPerspectiveNode != NULL) { + u16 perspNorm; + f32 fovInterpolated = delta_interpolate_f32(sPerspectiveNode->prevFov, sPerspectiveNode->fov, delta); + guPerspective(sPerspectiveMtx, &perspNorm, fovInterpolated, sPerspectiveAspect, sPerspectiveNode->near, sPerspectiveNode->far, 1.0f); + gSPMatrix(sPerspectivePos, VIRTUAL_TO_PHYSICAL(sPerspectiveNode), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); + } + + if (sViewportClipPos != NULL) { + delta_interpolate_vectors_s16(sViewportInterp.vp.vtrans, sViewportPrev.vp.vtrans, sViewport->vp.vtrans, delta); + delta_interpolate_vectors_s16(sViewportInterp.vp.vscale, sViewportPrev.vp.vscale, sViewport->vp.vscale, delta); + + Gfx *saved = gDisplayListHead; + + gDisplayListHead = sViewportClipPos; + make_viewport_clip_rect(&sViewportInterp); + gSPViewport(gDisplayListHead, VIRTUAL_TO_PHYSICAL(&sViewportInterp)); + + gDisplayListHead = saved; } for (s32 i = 0; i < gMtxTblSize; i++) { Gfx *pos = gMtxTbl[i].pos; - gSPMatrix(pos++, VIRTUAL_TO_PHYSICAL(gMtxTbl[i].mtx), + delta_interpolate_mtx(&gMtxTbl[i].interp, (Mtx*) gMtxTbl[i].mtxPrev, (Mtx*) gMtxTbl[i].mtx, delta); + gSPMatrix(pos++, VIRTUAL_TO_PHYSICAL(&gMtxTbl[i].interp), 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; +void mtx_patch_before(void) { + gMtxTblSize = 0; + + if (sPerspectiveNode != NULL) { + sPerspectiveNode->prevFov = sPerspectiveNode->fov; + sPerspectiveNode = NULL; } - gMtxTblSize = 0; - sPerspectivePos = NULL; - sViewportPos = NULL; + if (sViewport != NULL) { + sViewportPrev = *sViewport; + sViewport = NULL; + sViewportPos = NULL; + sViewportClipPos = NULL; + } } /** @@ -183,14 +212,14 @@ void mtx_patch_interpolated(void) { */ static u8 increment_mat_stack() { Mtx *mtx = alloc_display_list(sizeof(*mtx)); - Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); - if (mtx == NULL || mtxInterpolated == NULL) { return FALSE; } + Mtx *mtxPrev = alloc_display_list(sizeof(*mtxPrev)); + if (mtx == NULL || mtxPrev == NULL) { return FALSE; } gMatStackIndex++; mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); - mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]); + mtxf_to_mtx(mtxPrev, gMatStackPrev[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; - gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated; + gMatStackPrevFixed[gMatStackIndex] = mtxPrev; return TRUE; } @@ -223,11 +252,12 @@ static void geo_process_master_list_sub(struct GraphNodeMasterList *node) { if ((u32) gMtxTblSize < sizeof(gMtxTbl) / sizeof(gMtxTbl[0])) { gMtxTbl[gMtxTblSize].pos = gDisplayListHead; gMtxTbl[gMtxTblSize].mtx = currList->transform; + gMtxTbl[gMtxTblSize].mtxPrev = currList->transformPrev; gMtxTbl[gMtxTblSize++].displayList = currList->displayList; } - gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transformInterpolated), + gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(currList->transformPrev), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); - gSPDisplayList(gDisplayListHead++, currList->displayListInterpolated); + gSPDisplayList(gDisplayListHead++, currList->displayListPrev); currList = currList->next; } } @@ -243,7 +273,7 @@ static void geo_process_master_list_sub(struct GraphNodeMasterList *node) { * parameter. Look at the RenderModeContainer struct to see the corresponding * render modes of layers. */ -static void geo_append_display_list2(void *displayList, void *displayListInterpolated, s16 layer) { +static void geo_append_display_list2(void *displayList, void *displayListPrev, s16 layer) { #ifdef F3DEX_GBI_2 gSPLookAt(gDisplayListHead++, &lookAt); @@ -253,9 +283,9 @@ static void geo_append_display_list2(void *displayList, void *displayListInterpo alloc_only_pool_alloc(gDisplayListHeap, sizeof(struct DisplayListNode)); listNode->transform = gMatStackFixed[gMatStackIndex]; - listNode->transformInterpolated = gMatStackInterpolatedFixed[gMatStackIndex]; + listNode->transformPrev = gMatStackPrevFixed[gMatStackIndex]; listNode->displayList = displayList; - listNode->displayListInterpolated = displayListInterpolated; + listNode->displayListPrev = displayListPrev; listNode->next = 0; if (gCurGraphNodeMasterList->listHeads[layer] == 0) { gCurGraphNodeMasterList->listHeads[layer] = listNode; @@ -312,42 +342,31 @@ static void geo_process_perspective(struct GraphNodePerspective *node) { if (node->fnNode.func != NULL) { node->fnNode.func(GEO_CONTEXT_RENDER, &node->fnNode.node, gMatStack[gMatStackIndex]); } - if (node->fnNode.node.children != NULL) { - u16 perspNorm; - Mtx *mtxInterpolated = alloc_display_list(sizeof(*mtxInterpolated)); - Mtx *mtx = alloc_display_list(sizeof(*mtx)); - if (mtx == NULL || mtxInterpolated == NULL) { return; } - f32 fovInterpolated; + if (node->fnNode.node.children == NULL) { return; } + + u16 perspNorm; + Mtx *mtx = alloc_display_list(sizeof(*mtx)); + if (mtx == NULL) { return; } #ifdef VERSION_EU - f32 aspect = ((f32) gCurGraphNodeRoot->width / (f32) gCurGraphNodeRoot->height) * 1.1f; + f32 aspect = ((f32) gCurGraphNodeRoot->width / (f32) gCurGraphNodeRoot->height) * 1.1f; #else - f32 aspect = (f32) gCurGraphNodeRoot->width / (f32) gCurGraphNodeRoot->height; + f32 aspect = (f32) gCurGraphNodeRoot->width / (f32) gCurGraphNodeRoot->height; #endif - guPerspective(mtx, &perspNorm, node->fov, aspect, node->near, node->far, 1.0f); + guPerspective(mtx, &perspNorm, node->prevFov, aspect, node->near, node->far, 1.0f); - if (gGlobalTimer == node->prevTimestamp + 1 && gGlobalTimer != gLakituState.skipCameraInterpolationTimestamp) { + sPerspectiveNode = node; + sPerspectiveMtx = mtx; + sPerspectivePos = gDisplayListHead; + sPerspectiveAspect = aspect; - fovInterpolated = (node->prevFov + node->fov) / 2.0f; - guPerspective(mtxInterpolated, &perspNorm, fovInterpolated, aspect, node->near, node->far, 1.0f); - gSPPerspNormalize(gDisplayListHead++, perspNorm); + gSPPerspNormalize(gDisplayListHead++, perspNorm); + gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(mtx), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); - 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; - - gCurGraphNodeCamFrustum = node; - geo_process_node_and_siblings(node->fnNode.node.children); - gCurGraphNodeCamFrustum = NULL; - } + gCurGraphNodeCamFrustum = node; + geo_process_node_and_siblings(node->fnNode.node.children); + gCurGraphNodeCamFrustum = NULL; } /** @@ -427,7 +446,7 @@ static void geo_process_camera(struct GraphNodeCamera *node) { Vec3f posInterpolated; Vec3f focusInterpolated; - // Sanity check our stack index, If we above or equal to our stack size. Return top prevent OOB. + // Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB. if (gMatStackIndex >= MATRIX_STACK_SIZE) { return; } Mtx *rollMtx = alloc_display_list(sizeof(*rollMtx)); @@ -465,7 +484,7 @@ static void geo_process_camera(struct GraphNodeCamera *node) { vec3f_copy(node->prevFocus, node->focus); node->prevTimestamp = gGlobalTimer; mtxf_lookat(cameraTransform, posInterpolated, focusInterpolated, node->roll); - mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], cameraTransform, gMatStackInterpolated[gMatStackIndex]); + mtxf_mul(gMatStackPrev[gMatStackIndex + 1], cameraTransform, gMatStackPrev[gMatStackIndex]); // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } @@ -473,7 +492,7 @@ static void geo_process_camera(struct GraphNodeCamera *node) { if (node->fnNode.node.children != 0) { gCurGraphNodeCamera = node; node->matrixPtr = &gMatStack[gMatStackIndex]; - node->matrixPtrInterpolated = &gMatStackInterpolated[gMatStackIndex]; + node->matrixPtrInterpolated = &gMatStackPrev[gMatStackIndex]; geo_process_node_and_siblings(node->fnNode.node.children); gCurGraphNodeCamera = NULL; } @@ -496,7 +515,7 @@ static void geo_process_translation_rotation(struct GraphNodeTranslationRotation vec3s_to_vec3f(translation, node->translation); mtxf_rotate_zxy_and_translate(mtxf, translation, node->rotation); mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); - mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]); + mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]); // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } @@ -525,7 +544,7 @@ static void geo_process_translation(struct GraphNodeTranslation *node) { vec3s_to_vec3f(translation, node->translation); mtxf_rotate_zxy_and_translate(mtxf, translation, gVec3sZero); mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, gMatStack[gMatStackIndex]); - mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]); + mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]); // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } @@ -559,7 +578,7 @@ static void geo_process_rotation(struct GraphNodeRotation *node) { } vec3s_copy(node->prevRotation, node->rotation); node->prevTimestamp = gGlobalTimer; - mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, gMatStackInterpolated[gMatStackIndex]); + mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]); // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } @@ -586,7 +605,7 @@ static void geo_process_scale(struct GraphNodeScale *node) { vec3f_set(scaleVec, node->scale, node->scale, node->scale); mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex], scaleVec); - mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex], scaleVec); + mtxf_scale_vec3f(gMatStackPrev[gMatStackIndex + 1], gMatStackPrev[gMatStackIndex], scaleVec); // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } @@ -617,17 +636,17 @@ static void geo_process_billboard(struct GraphNodeBillboard *node) { vec3s_to_vec3f(translation, node->translation); mtxf_billboard(gMatStack[nextMatStackIndex], gMatStack[gMatStackIndex], translation, gCurGraphNodeCamera->roll); - mtxf_billboard(gMatStackInterpolated[nextMatStackIndex], gMatStackInterpolated[gMatStackIndex], translation, + mtxf_billboard(gMatStackPrev[nextMatStackIndex], gMatStackPrev[gMatStackIndex], translation, gCurGraphNodeCamera->roll); if (gCurGraphNodeHeldObject != NULL) { mtxf_scale_vec3f(gMatStack[nextMatStackIndex], gMatStack[nextMatStackIndex], gCurGraphNodeHeldObject->objNode->header.gfx.scale); - mtxf_scale_vec3f(gMatStackInterpolated[nextMatStackIndex], gMatStackInterpolated[nextMatStackIndex], + mtxf_scale_vec3f(gMatStackPrev[nextMatStackIndex], gMatStackPrev[nextMatStackIndex], gCurGraphNodeHeldObject->objNode->header.gfx.scale); } else if (gCurGraphNodeObject != NULL) { mtxf_scale_vec3f(gMatStack[nextMatStackIndex], gMatStack[nextMatStackIndex], gCurGraphNodeObject->scale); - mtxf_scale_vec3f(gMatStackInterpolated[nextMatStackIndex], gMatStackInterpolated[nextMatStackIndex], + mtxf_scale_vec3f(gMatStackPrev[nextMatStackIndex], gMatStackPrev[nextMatStackIndex], gCurGraphNodeObject->scale); } @@ -810,7 +829,7 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) { 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]); + mtxf_mul(gMatStackPrev[gMatStackIndex + 1], matrix, gMatStackPrev[gMatStackIndex]); // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } @@ -957,7 +976,7 @@ static void geo_process_shadow(struct GraphNodeShadow *node) { mtxf_translate(mtxf, shadowPos); mtxf_mul(gMatStack[gMatStackIndex + 1], mtxf, *gCurGraphNodeCamera->matrixPtr); mtxf_translate(mtxf, shadowPosInterpolated); - mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, *gCurGraphNodeCamera->matrixPtrInterpolated); + mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, *gCurGraphNodeCamera->matrixPtrInterpolated); // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } @@ -1105,11 +1124,11 @@ static void geo_process_object(struct Object *node) { gGlobalTimer != node->header.gfx.skipInterpolationTimestamp && gGlobalTimer != gLakituState.skipCameraInterpolationTimestamp) { interpolate_matrix(mtxf, *node->header.gfx.throwMatrix, node->header.gfx.prevThrowMatrix); - mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], mtxf, - gMatStackInterpolated[gMatStackIndex]); + mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, + gMatStackPrev[gMatStackIndex]); } else { - mtxf_mul(gMatStackInterpolated[gMatStackIndex + 1], (void *) node->header.gfx.throwMatrix, - gMatStackInterpolated[gMatStackIndex]); + mtxf_mul(gMatStackPrev[gMatStackIndex + 1], (void *) node->header.gfx.throwMatrix, + gMatStackPrev[gMatStackIndex]); } mtxf_copy(node->header.gfx.prevThrowMatrix, *node->header.gfx.throwMatrix); node->header.gfx.prevThrowMatrixTimestamp = gGlobalTimer; @@ -1126,7 +1145,7 @@ static void geo_process_object(struct Object *node) { 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], + mtxf_cylboard(gMatStackPrev[gMatStackIndex + 1], gMatStackPrev[gMatStackIndex], posInterpolated, gCurGraphNodeCamera->roll); } else if ((node->header.gfx.node.flags & GRAPH_RENDER_BILLBOARD) && !(node->header.gfx.sharedChild && node->header.gfx.sharedChild->extraFlags & GRAPH_EXTRA_FORCE_3D)) { Vec3f posInterpolated; @@ -1141,7 +1160,7 @@ static void geo_process_object(struct Object *node) { 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], + mtxf_billboard(gMatStackPrev[gMatStackIndex + 1], gMatStackPrev[gMatStackIndex], posInterpolated, gCurGraphNodeCamera->roll); } else { Vec3f posInterpolated; @@ -1161,7 +1180,7 @@ static void geo_process_object(struct Object *node) { 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]); + mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mtxf, gMatStackPrev[gMatStackIndex]); } if (gGlobalTimer == node->header.gfx.prevScaleTimestamp + 1 && @@ -1176,10 +1195,10 @@ static void geo_process_object(struct Object *node) { mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex + 1], node->header.gfx.scale); - mtxf_scale_vec3f(gMatStackInterpolated[gMatStackIndex + 1], gMatStackInterpolated[gMatStackIndex + 1], + mtxf_scale_vec3f(gMatStackPrev[gMatStackIndex + 1], gMatStackPrev[gMatStackIndex + 1], scaleInterpolated); node->header.gfx.throwMatrix = &gMatStack[++gMatStackIndex]; - node->header.gfx.throwMatrixInterpolated = &gMatStackInterpolated[gMatStackIndex]; + node->header.gfx.throwMatrixInterpolated = &gMatStackPrev[gMatStackIndex]; node->header.gfx.cameraToObject[0] = gMatStack[gMatStackIndex][3][0]; node->header.gfx.cameraToObject[1] = gMatStack[gMatStackIndex][3][1]; node->header.gfx.cameraToObject[2] = gMatStack[gMatStackIndex][3][2]; @@ -1197,8 +1216,8 @@ static void geo_process_object(struct Object *node) { mtxf_to_mtx(mtx, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = mtx; - mtxf_to_mtx(mtxInterpolated, gMatStackInterpolated[gMatStackIndex]); - gMatStackInterpolatedFixed[gMatStackIndex] = mtxInterpolated; + mtxf_to_mtx(mtxInterpolated, gMatStackPrev[gMatStackIndex]); + gMatStackPrevFixed[gMatStackIndex] = mtxInterpolated; if (node->header.gfx.sharedChild != NULL) { gCurGraphNodeObject = (struct GraphNodeObject *) node; node->header.gfx.sharedChild->parent = &node->header.gfx.node; @@ -1280,12 +1299,12 @@ void geo_process_held_object(struct GraphNodeHeldObject *node) { gMatStack[gMatStackIndex + 1][3][2] = gMatStack[gMatStackIndex][3][2]; mtxf_mul(gMatStack[gMatStackIndex + 1], mat, gMatStack[gMatStackIndex + 1]); mtxf_scale_vec3f(gMatStack[gMatStackIndex + 1], gMatStack[gMatStackIndex + 1], 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], + mtxf_copy(gMatStackPrev[gMatStackIndex + 1], (void *) gCurGraphNodeObject->throwMatrixInterpolated); + gMatStackPrev[gMatStackIndex + 1][3][0] = gMatStackPrev[gMatStackIndex][3][0]; + gMatStackPrev[gMatStackIndex + 1][3][1] = gMatStackPrev[gMatStackIndex][3][1]; + gMatStackPrev[gMatStackIndex + 1][3][2] = gMatStackPrev[gMatStackIndex][3][2]; + mtxf_mul(gMatStackPrev[gMatStackIndex + 1], mat, gMatStackPrev[gMatStackIndex + 1]); + mtxf_scale_vec3f(gMatStackPrev[gMatStackIndex + 1], gMatStackPrev[gMatStackIndex + 1], scaleInterpolated); if (node->fnNode.func != NULL) { node->fnNode.func(GEO_CONTEXT_HELD_OBJ, &node->fnNode.node, (struct AllocOnlyPool *) gMatStack[gMatStackIndex + 1]); @@ -1442,7 +1461,6 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor) if (node->node.flags & GRAPH_RENDER_ACTIVE) { Vp *viewport = alloc_display_list(sizeof(*viewport)); if (viewport == NULL) { return; } - Vp *viewportInterpolated = viewport; gDisplayListHeap = alloc_only_pool_init(main_pool_available() - sizeof(struct AllocOnlyPool), MEMORY_POOL_LEFT); @@ -1453,32 +1471,32 @@ void geo_process_root(struct GraphNodeRoot *node, Vp *b, Vp *c, s32 clearColor) gCurAnimType = 0; vec3s_set(viewport->vp.vtrans, node->x * 4, node->y * 4, 511); vec3s_set(viewport->vp.vscale, node->width * 4, node->height * 4, 511); - + if (b != NULL) { clear_frame_buffer(clearColor); - viewportInterpolated = alloc_display_list(sizeof(*viewportInterpolated)); - if (viewportInterpolated == NULL) { return; } - 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); + sViewportClipPos = gDisplayListHead; + make_viewport_clip_rect(&sViewportPrev); + *viewport = *b; } else if (c != NULL) { clear_frame_buffer(clearColor); make_viewport_clip_rect(c); } - - sPrevViewport = *viewport; mtxf_identity(gMatStack[gMatStackIndex]); mtxf_to_mtx(initialMatrix, gMatStack[gMatStackIndex]); gMatStackFixed[gMatStackIndex] = initialMatrix; - mtxf_identity(gMatStackInterpolated[gMatStackIndex]); - gMatStackInterpolatedFixed[gMatStackIndex] = initialMatrix; + sViewport = viewport; + sViewportPos = gDisplayListHead; - gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(viewportInterpolated)); + // vvv 60 FPS PATCH vvv + mtxf_identity(gMatStackPrev[gMatStackIndex]); + gMatStackPrevFixed[gMatStackIndex] = initialMatrix; + // ^^^ ^^^ + + gSPViewport(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(&sViewportPrev)); gSPMatrix(gDisplayListHead++, VIRTUAL_TO_PHYSICAL(gMatStackFixed[gMatStackIndex]), G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH); gCurGraphNodeRoot = node; diff --git a/src/pc/controller/controller_keyboard_debug.c b/src/pc/controller/controller_keyboard_debug.c index 10093b50..e3e5d64c 100644 --- a/src/pc/controller/controller_keyboard_debug.c +++ b/src/pc/controller/controller_keyboard_debug.c @@ -39,18 +39,24 @@ extern bool dynos_warp_to_level(s32 aLevel, s32 aArea, s32 aAct); static void debug_warp_level1() { // warp to credits - //set_mario_action(&gMarioStates[0], ACT_JUMBO_STAR_CUTSCENE, 0); - //return; + set_mario_action(&gMarioStates[0], ACT_JUMBO_STAR_CUTSCENE, 0); + return; dynos_warp_to_level(LEVEL_BOB, 1, 1); } static void debug_warp_level2() { - dynos_warp_to_level(gCurrLevelNum, gCurrAreaIndex^3, 1); + extern f32 gGameSpeed; + gGameSpeed = MAX(gGameSpeed - 0.1f, 0.1f); + printf("GAME SPEED: %f\n", gGameSpeed); + //dynos_warp_to_level(gCurrLevelNum, gCurrAreaIndex^3, 1); } static void debug_warp_level3() { - dynos_warp_to_level(LEVEL_CASTLE_GROUNDS, 1, 1); + extern f32 gGameSpeed; + gGameSpeed = MIN(gGameSpeed + 0.1f, 10.0f); + printf("GAME SPEED: %f\n", gGameSpeed); + //dynos_warp_to_level(LEVEL_CASTLE_GROUNDS, 1, 1); } static void debug_grand_star(void) { diff --git a/src/pc/gfx/gfx_sdl2.c b/src/pc/gfx/gfx_sdl2.c index 110925fc..fc0c60c9 100644 --- a/src/pc/gfx/gfx_sdl2.c +++ b/src/pc/gfx/gfx_sdl2.c @@ -247,6 +247,7 @@ static void gfx_sdl_set_keyboard_callbacks(kb_callback_t on_key_down, kb_callbac } static bool gfx_sdl_start_frame(void) { + return true; f64 curTime = clock_elapsed_f64(); f64 frameTime = config60Fps ? (sFrameTime / 2.0) : sFrameTime; if (curTime > sFrameTargetTime) { @@ -260,6 +261,7 @@ static bool gfx_sdl_start_frame(void) { } static inline void sync_framerate_with_timer(void) { + return; f64 curTime = clock_elapsed_f64(); if (curTime < sFrameTargetTime) { u32 delayMs = (sFrameTargetTime - curTime) * 1000.0; diff --git a/src/pc/pc_main.c b/src/pc/pc_main.c index 939ef018..f937ac0a 100644 --- a/src/pc/pc_main.c +++ b/src/pc/pc_main.c @@ -48,6 +48,7 @@ #include "pc/network/version.h" #include "pc/network/network_player.h" #include "pc/djui/djui.h" +#include "pc/utils/misc.h" #include "pc/mods/mods.h" @@ -63,6 +64,8 @@ s8 gShowDebugText; s32 gRumblePakPfs; u32 gNumVblanks = 0; +f32 gGameSpeed = 1.0f; // DO NOT COMMIT + static struct AudioAPI *audio_api; struct GfxWindowManagerAPI *wm_api; static struct GfxRenderingAPI *rendering_api; @@ -94,8 +97,13 @@ void send_display_list(struct SPTask *spTask) { #define SAMPLES_LOW 528 #endif -static inline void patch_interpolations(void) { - extern void mtx_patch_interpolated(void); +static void patch_interpolations_before(void) { + extern void mtx_patch_before(void); + mtx_patch_before(); +} + +static inline void patch_interpolations(f32 delta) { + extern void mtx_patch_interpolated(f32 delta); extern void patch_screen_transition_interpolated(void); extern void patch_title_screen_scales(void); extern void patch_interpolated_dialog(void); @@ -104,19 +112,44 @@ static inline void patch_interpolations(void) { extern void patch_interpolated_bubble_particles(void); extern void patch_interpolated_snow_particles(void); extern void djui_render_patch(void); - mtx_patch_interpolated(); - patch_screen_transition_interpolated(); + mtx_patch_interpolated(delta); + /*patch_screen_transition_interpolated(); patch_title_screen_scales(); patch_interpolated_dialog(); patch_interpolated_hud(); patch_interpolated_paintings(); patch_interpolated_bubble_particles(); patch_interpolated_snow_particles(); - djui_render_patch(); + djui_render_patch();*/ +} + +void produce_uncapped_frames(void) { + #define FRAMERATE 30 + static const f64 sFrameTime = (1.0 / ((double)FRAMERATE)); + static f64 sFrameTargetTime = 0; + + f64 startTime = clock_elapsed_f64(); + f64 curTime = startTime; + u64 frames = 0; + while ((curTime = clock_elapsed_f64()) < sFrameTargetTime) { + gfx_start_frame(); + f32 delta = (curTime - startTime) / (sFrameTargetTime - startTime); + patch_interpolations(delta); + send_display_list(gGfxSPTask); + gfx_end_frame(); + frames++; + } + + printf(">> frames %llu | %f\n", frames, gGameSpeed); + fflush(stdout); + + sFrameTargetTime += sFrameTime * gGameSpeed; } void produce_one_frame(void) { network_update(); + + patch_interpolations_before(); gfx_start_frame(); const f32 master_mod = (f32)configMasterVolume / 127.0f; @@ -145,11 +178,9 @@ void produce_one_frame(void) { gfx_end_frame(); + // uncapped if (config60Fps) { - gfx_start_frame(); - patch_interpolations(); - send_display_list(gGfxSPTask); - gfx_end_frame(); + produce_uncapped_frames(); } } diff --git a/src/pc/utils/misc.c b/src/pc/utils/misc.c index dfd67180..e0357e89 100644 --- a/src/pc/utils/misc.c +++ b/src/pc/utils/misc.c @@ -113,3 +113,25 @@ next_get: *buffer = '\0'; } + +///////////////// + +f32 delta_interpolate_f32(f32 start, f32 end, f32 delta) { + return start * (1.0f - delta) + end * delta; +} + +void delta_interpolate_vectors_s16(Vec3s res, Vec3s a, Vec3s b, f32 delta) { + f32 antiDelta = 1.0f - delta; + res[0] = ((a[0] * antiDelta) + (b[0] * delta)); + res[1] = ((a[1] * antiDelta) + (b[1] * delta)); + res[2] = ((a[2] * antiDelta) + (b[2] * delta)); +} + +void delta_interpolate_mtx(Mtx* out, Mtx* a, Mtx* b, f32 delta) { + f32 antiDelta = 1.0f - delta; + for (s32 i = 0; i < 4; i++) { + for (s32 j = 0; j < 4; j++) { + out->m[i][j] = (a->m[i][j] * antiDelta) + (b->m[i][j] * delta); + } + } +} \ No newline at end of file diff --git a/src/pc/utils/misc.h b/src/pc/utils/misc.h index 52677fea..1f454d88 100644 --- a/src/pc/utils/misc.h +++ b/src/pc/utils/misc.h @@ -2,12 +2,20 @@ #define UTILS_MISC_H #include +#include "types.h" +#include "PR/gbi.h" float smoothstep(float edge0, float edge1, float x); void update_all_mario_stars(void); + f32 clock_elapsed(void); f64 clock_elapsed_f64(void); u32 clock_elapsed_ticks(void); + void file_get_line(char* buffer, size_t maxLength, FILE* fp); +f32 delta_interpolate_f32(f32 start, f32 end, f32 delta); +void delta_interpolate_vectors_s16(Vec3s res, Vec3s a, Vec3s b, f32 delta); +void delta_interpolate_mtx(Mtx* out, Mtx* a, Mtx* b, f32 delta); + #endif \ No newline at end of file