2020-06-02 16:44:34 +00:00
# include <PR/ultratypes.h>
2019-08-25 04:46:40 +00:00
2020-06-02 16:44:34 +00:00
# include "area.h"
# include "engine/math_util.h"
# include "game_init.h"
2020-05-07 18:21:22 +00:00
# include "gfx_dimensions.h"
2019-08-25 04:46:40 +00:00
# include "main.h"
# include "memory.h"
2020-06-02 16:44:34 +00:00
# include "print.h"
2019-08-25 04:46:40 +00:00
# include "rendering_graph_node.h"
2020-06-02 16:44:34 +00:00
# include "shadow.h"
# include "sm64.h"
2021-09-05 21:17:20 +00:00
# include "game/level_update.h"
2022-04-20 05:36:47 +00:00
# include "pc/lua/smlua_hooks.h"
2022-04-27 03:00:18 +00:00
# include "pc/utils/misc.h"
2022-04-26 20:49:09 +00:00
# include "pc/debuglog.h"
2023-03-21 02:36:25 +00:00
# include "game/skybox.h"
2023-02-27 16:22:31 +00:00
# include "include/course_table.h"
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
/**
* This file contains the code that processes the scene graph for rendering .
* The scene graph is responsible for drawing everything except the HUD / text boxes .
* First the root of the scene graph is processed when geo_process_root
* is called from level_script . c . The rest of the tree is traversed recursively
* using the function geo_process_node_and_siblings , which switches over all
* geo node types and calls a specialized function accordingly .
* The types are defined in engine / graph_node . h
2019-08-25 04:46:40 +00:00
*
2019-09-01 19:50:50 +00:00
* The scene graph typically looks like :
* - Root ( viewport )
* - Master list
* - Ortho projection
* - Background ( skybox )
* - Master list
* - Perspective
* - Camera
* - < area - specific display lists >
* - Object parent
* - < group with 240 object nodes >
* - Master list
* - Script node ( Cannon overlay )
2019-08-25 04:46:40 +00:00
*
*/
2022-04-28 02:43:55 +00:00
2023-05-10 20:25:41 +00:00
# define MATRIX_STACK_SIZE 64
2023-05-13 01:53:25 +00:00
# define DISPLAY_LIST_HEAP_SIZE 32000
2019-08-25 04:46:40 +00:00
2022-05-28 02:56:38 +00:00
f32 gProjectionMaxNearValue = 5 ;
s16 gProjectionVanillaNearValue = 100 ;
s16 gProjectionVanillaFarValue = 1000 ;
2022-05-26 00:47:34 +00:00
2019-08-25 04:46:40 +00:00
s16 gMatStackIndex ;
2022-04-17 02:48:40 +00:00
Mat4 gMatStack [ MATRIX_STACK_SIZE ] = { } ;
2022-04-27 03:00:18 +00:00
Mat4 gMatStackPrev [ MATRIX_STACK_SIZE ] = { } ;
2022-04-17 02:48:40 +00:00
Mtx * gMatStackFixed [ MATRIX_STACK_SIZE ] = { 0 } ;
2022-04-27 03:00:18 +00:00
Mtx * gMatStackPrevFixed [ MATRIX_STACK_SIZE ] = { 0 } ;
2019-08-25 04:46:40 +00:00
2022-05-22 04:46:41 +00:00
u8 sUsingCamSpace = FALSE ;
Mtx sPrevCamTranf , sCurrCamTranf = {
. m = {
{ 1.0f , 0.0f , 0.0f , 0.0f } ,
{ 0.0f , 1.0f , 0.0f , 0.0f } ,
{ 0.0f , 0.0f , 1.0f , 0.0f } ,
{ 0.0f , 0.0f , 0.0f , 1.0f }
}
} ;
2019-09-01 19:50:50 +00:00
/**
* Animation nodes have state in global variables , so this struct captures
* the animation state so a ' context switch ' can be made when rendering the
* held object .
2019-08-25 04:46:40 +00:00
*/
struct GeoAnimState {
/*0x00*/ u8 type ;
/*0x01*/ u8 enabled ;
/*0x02*/ s16 frame ;
/*0x04*/ f32 translationMultiplier ;
/*0x08*/ u16 * attribute ;
/*0x0C*/ s16 * data ;
2020-07-29 01:28:12 +00:00
s16 prevFrame ;
2019-08-25 04:46:40 +00:00
} ;
// For some reason, this is a GeoAnimState struct, but the current state consists
// of separate global variables. It won't match EU otherwise.
struct GeoAnimState gGeoTempState ;
u8 gCurAnimType ;
u8 gCurAnimEnabled ;
s16 gCurrAnimFrame ;
2020-07-29 01:28:12 +00:00
s16 gPrevAnimFrame ;
2019-08-25 04:46:40 +00:00
f32 gCurAnimTranslationMultiplier ;
2022-04-17 02:48:40 +00:00
u16 * gCurrAnimAttribute = NULL ;
s16 * gCurAnimData = NULL ;
2019-08-25 04:46:40 +00:00
2023-05-13 01:53:25 +00:00
struct GrowingPool * gDisplayListHeap = NULL ;
2019-08-25 04:46:40 +00:00
struct RenderModeContainer {
u32 modes [ 8 ] ;
} ;
2019-11-03 19:36:27 +00:00
/* Rendermode settings for cycle 1 for all 8 layers. */
2019-08-25 04:46:40 +00:00
struct RenderModeContainer renderModeTable_1Cycle [ 2 ] = { { {
2019-11-03 19:36:27 +00:00
G_RM_OPA_SURF ,
G_RM_AA_OPA_SURF ,
G_RM_AA_OPA_SURF ,
G_RM_AA_OPA_SURF ,
G_RM_AA_TEX_EDGE ,
G_RM_AA_XLU_SURF ,
G_RM_AA_XLU_SURF ,
G_RM_AA_XLU_SURF ,
} } ,
{ {
/* z-buffered */
G_RM_ZB_OPA_SURF ,
G_RM_AA_ZB_OPA_SURF ,
G_RM_AA_ZB_OPA_DECAL ,
G_RM_AA_ZB_OPA_INTER ,
G_RM_AA_ZB_TEX_EDGE ,
G_RM_AA_ZB_XLU_SURF ,
G_RM_AA_ZB_XLU_DECAL ,
G_RM_AA_ZB_XLU_INTER ,
} } } ;
/* Rendermode settings for cycle 2 for all 8 layers. */
2019-08-25 04:46:40 +00:00
struct RenderModeContainer renderModeTable_2Cycle [ 2 ] = { { {
2019-11-03 19:36:27 +00:00
G_RM_OPA_SURF2 ,
G_RM_AA_OPA_SURF2 ,
G_RM_AA_OPA_SURF2 ,
G_RM_AA_OPA_SURF2 ,
G_RM_AA_TEX_EDGE2 ,
G_RM_AA_XLU_SURF2 ,
G_RM_AA_XLU_SURF2 ,
G_RM_AA_XLU_SURF2 ,
} } ,
{ {
/* z-buffered */
G_RM_ZB_OPA_SURF2 ,
G_RM_AA_ZB_OPA_SURF2 ,
G_RM_AA_ZB_OPA_DECAL2 ,
G_RM_AA_ZB_OPA_INTER2 ,
G_RM_AA_ZB_TEX_EDGE2 ,
G_RM_AA_ZB_XLU_SURF2 ,
G_RM_AA_ZB_XLU_DECAL2 ,
G_RM_AA_ZB_XLU_INTER2 ,
} } } ;
2019-08-25 04:46:40 +00:00
struct GraphNodeRoot * gCurGraphNodeRoot = NULL ;
struct GraphNodeMasterList * gCurGraphNodeMasterList = NULL ;
struct GraphNodePerspective * gCurGraphNodeCamFrustum = NULL ;
struct GraphNodeCamera * gCurGraphNodeCamera = NULL ;
struct GraphNodeObject * gCurGraphNodeObject = NULL ;
struct GraphNodeHeldObject * gCurGraphNodeHeldObject = NULL ;
u16 gAreaUpdateCounter = 0 ;
# ifdef F3DEX_GBI_2
LookAt lookAt ;
# endif
2022-04-27 03:00:18 +00:00
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 } ;
2020-07-29 01:28:12 +00:00
2023-04-21 04:56:37 +00:00
static struct GraphNodeBackground * sBackgroundNode = NULL ;
2022-04-28 01:41:05 +00:00
Gfx * gBackgroundSkyboxGfx = NULL ;
Vtx * gBackgroundSkyboxVerts [ 3 ] [ 3 ] = { 0 } ;
Mtx * gBackgroundSkyboxMtx = NULL ;
struct GraphNodeRoot * sBackgroundNodeRoot = NULL ;
2022-04-28 02:43:55 +00:00
# define MAX_SHADOW_NODES 128
struct ShadowInterp sShadowInterp [ MAX_SHADOW_NODES ] = { 0 } ;
struct ShadowInterp * gShadowInterpCurrent = NULL ;
static u8 sShadowInterpCount = 0 ;
2022-05-22 04:46:41 +00:00
static struct GraphNodeCamera * sCameraNode = NULL ;
2020-07-29 01:28:12 +00:00
struct {
Gfx * pos ;
2022-04-30 04:28:14 +00:00
Mtx * mtx ;
Mtx * mtxPrev ;
2020-07-29 01:28:12 +00:00
void * displayList ;
2022-04-27 03:00:18 +00:00
Mtx interp ;
2022-05-22 04:46:41 +00:00
u8 usingCamSpace ;
2020-07-29 01:28:12 +00:00
} gMtxTbl [ 6400 ] ;
2023-04-21 04:56:37 +00:00
s32 gMtxTblSize = 0 ;
2020-07-29 01:28:12 +00:00
2022-04-17 02:48:40 +00:00
struct Object * gCurGraphNodeProcessingObject = NULL ;
struct MarioState * gCurGraphNodeMarioState = NULL ;
2020-09-06 20:54:01 +00:00
2022-05-01 00:36:38 +00:00
f32 gOverrideFOV = 0 ;
f32 gOverrideNear = 0 ;
f32 gOverrideFar = 0 ;
2022-04-28 01:41:05 +00:00
void patch_mtx_before ( void ) {
gMtxTblSize = 0 ;
if ( sPerspectiveNode ! = NULL ) {
sPerspectiveNode - > prevFov = sPerspectiveNode - > fov ;
sPerspectiveNode = NULL ;
}
if ( sViewport ! = NULL ) {
sViewportPrev = * sViewport ;
sViewport = NULL ;
sViewportPos = NULL ;
sViewportClipPos = NULL ;
}
if ( sBackgroundNode ! = NULL ) {
vec3f_copy ( sBackgroundNode - > prevCameraPos , gLakituState . pos ) ;
vec3f_copy ( sBackgroundNode - > prevCameraFocus , gLakituState . focus ) ;
sBackgroundNode - > prevCameraTimestamp = gGlobalTimer ;
sBackgroundNode = NULL ;
gBackgroundSkyboxGfx = NULL ;
}
2022-04-28 02:43:55 +00:00
sShadowInterpCount = 0 ;
2022-04-28 01:41:05 +00:00
}
void patch_mtx_interpolated ( f32 delta ) {
2022-05-22 04:46:41 +00:00
Mtx camTranfInv , prevCamTranfInv ;
2022-04-27 03:00:18 +00:00
if ( sPerspectiveNode ! = NULL ) {
u16 perspNorm ;
f32 fovInterpolated = delta_interpolate_f32 ( sPerspectiveNode - > prevFov , sPerspectiveNode - > fov , delta ) ;
2022-05-28 02:56:38 +00:00
f32 near = MIN ( sPerspectiveNode - > near , gProjectionMaxNearValue ) ;
2022-05-26 00:47:34 +00:00
guPerspective ( sPerspectiveMtx , & perspNorm , not_zero ( fovInterpolated , gOverrideFOV ) , sPerspectiveAspect , not_zero ( near , gOverrideNear ) , not_zero ( sPerspectiveNode - > far , gOverrideFar ) , 1.0f ) ;
2022-04-27 03:00:18 +00:00
gSPMatrix ( sPerspectivePos , VIRTUAL_TO_PHYSICAL ( sPerspectiveNode ) , G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH ) ;
}
if ( sViewportClipPos ! = NULL ) {
2022-04-28 01:25:43 +00:00
delta_interpolate_vec3s ( sViewportInterp . vp . vtrans , sViewportPrev . vp . vtrans , sViewport - > vp . vtrans , delta ) ;
delta_interpolate_vec3s ( sViewportInterp . vp . vscale , sViewportPrev . vp . vscale , sViewport - > vp . vscale , delta ) ;
2022-04-27 03:00:18 +00:00
Gfx * saved = gDisplayListHead ;
gDisplayListHead = sViewportClipPos ;
make_viewport_clip_rect ( & sViewportInterp ) ;
gSPViewport ( gDisplayListHead , VIRTUAL_TO_PHYSICAL ( & sViewportInterp ) ) ;
gDisplayListHead = saved ;
2020-07-29 01:28:12 +00:00
}
2022-04-28 01:41:05 +00:00
if ( sBackgroundNode ! = NULL ) {
Vec3f posCopy ;
Vec3f focusCopy ;
struct GraphNodeRoot * rootCopy = gCurGraphNodeRoot ;
gCurGraphNodeRoot = sBackgroundNodeRoot ;
vec3f_copy ( posCopy , gLakituState . pos ) ;
vec3f_copy ( focusCopy , gLakituState . focus ) ;
2022-04-28 04:27:14 +00:00
if ( gGlobalTimer ! = gLakituState . skipCameraInterpolationTimestamp ) {
2022-04-28 01:41:05 +00:00
delta_interpolate_vec3f ( gLakituState . pos , sBackgroundNode - > prevCameraPos , posCopy , delta ) ;
delta_interpolate_vec3f ( gLakituState . focus , sBackgroundNode - > prevCameraFocus , focusCopy , delta ) ;
2022-04-28 04:27:14 +00:00
}
sBackgroundNode - > fnNode . func ( GEO_CONTEXT_RENDER , & sBackgroundNode - > fnNode . node , NULL ) ;
2022-04-28 01:41:05 +00:00
vec3f_copy ( gLakituState . pos , posCopy ) ;
vec3f_copy ( gLakituState . focus , focusCopy ) ;
gCurGraphNodeRoot = rootCopy ;
}
2022-04-28 02:43:55 +00:00
struct GraphNodeObject * savedObj = gCurGraphNodeObject ;
for ( s32 i = 0 ; i < sShadowInterpCount ; i + + ) {
struct ShadowInterp * interp = & sShadowInterp [ i ] ;
2022-06-05 06:36:41 +00:00
if ( ! interp - > gfx ) { continue ; }
2022-04-28 02:43:55 +00:00
gShadowInterpCurrent = interp ;
Vec3f posInterp ;
delta_interpolate_vec3f ( posInterp , interp - > shadowPosPrev , interp - > shadowPos , delta ) ;
gCurGraphNodeObject = interp - > obj ;
2022-05-01 00:25:47 +00:00
extern u8 gInterpolatingSurfaces ;
gInterpolatingSurfaces = true ;
2022-06-05 06:36:41 +00:00
gShadowInterpCurrent - > gfx = create_shadow_below_xyz ( posInterp [ 0 ] , posInterp [ 1 ] , posInterp [ 2 ] , interp - > shadowScale , interp - > node - > shadowSolidity , interp - > node - > shadowType ) ;
2022-05-01 00:25:47 +00:00
gInterpolatingSurfaces = false ;
2022-06-05 06:36:41 +00:00
gShadowInterpCurrent = NULL ;
2022-04-28 02:43:55 +00:00
}
gCurGraphNodeObject = savedObj ;
2022-05-22 04:46:41 +00:00
// calculate outside of for loop to reduce overhead
// technically this is improper use of mtxf functions, but coop doesn't target N64
2022-05-30 01:16:52 +00:00
bool translateCamSpace = ( gMtxTblSize > 0 ) & & sCameraNode & & ( sCameraNode - > matrixPtr ! = NULL ) & & ( sCameraNode - > matrixPtrPrev ! = NULL ) ;
2023-03-27 22:49:29 +00:00
if ( translateCamSpace ) {
2022-05-29 22:34:28 +00:00
mtxf_inverse ( camTranfInv . m , * sCameraNode - > matrixPtr ) ;
mtxf_inverse ( prevCamTranfInv . m , * sCameraNode - > matrixPtrPrev ) ;
}
2022-05-22 04:46:41 +00:00
2022-04-17 02:48:40 +00:00
for ( s32 i = 0 ; i < gMtxTblSize ; i + + ) {
2022-05-22 04:46:41 +00:00
Mtx bufMtx , bufMtxPrev ;
memcpy ( bufMtx . m , ( ( Mtx * ) gMtxTbl [ i ] . mtx ) - > m , sizeof ( f32 ) * 4 * 4 ) ;
memcpy ( bufMtxPrev . m , ( ( Mtx * ) gMtxTbl [ i ] . mtxPrev ) - > m , sizeof ( f32 ) * 4 * 4 ) ;
2020-07-29 01:28:12 +00:00
Gfx * pos = gMtxTbl [ i ] . pos ;
2022-05-22 04:46:41 +00:00
2022-05-29 22:34:28 +00:00
if ( gMtxTbl [ i ] . usingCamSpace & & translateCamSpace ) {
2022-05-22 04:46:41 +00:00
// transform out of camera space so the matrix can interp in world space
mtxf_mul ( bufMtx . m , bufMtx . m , camTranfInv . m ) ;
mtxf_mul ( bufMtxPrev . m , bufMtxPrev . m , prevCamTranfInv . m ) ;
}
delta_interpolate_mtx ( & gMtxTbl [ i ] . interp , & bufMtxPrev , & bufMtx , delta ) ;
if ( gMtxTbl [ i ] . usingCamSpace ) {
// transform back to camera space, respecting camera interpolation
Mtx camInterp ;
Vec3f posInterp , focusInterp ;
// use camera node's stored information to calculate interpolated camera transform
delta_interpolate_vec3f ( posInterp , sCameraNode - > prevPos , sCameraNode - > pos , delta ) ;
delta_interpolate_vec3f ( focusInterp , sCameraNode - > prevFocus , sCameraNode - > focus , delta ) ;
mtxf_lookat ( camInterp . m , posInterp , focusInterp , sCameraNode - > roll ) ;
mtxf_to_mtx ( & camInterp , camInterp . m ) ;
mtxf_mul ( gMtxTbl [ i ] . interp . m , gMtxTbl [ i ] . interp . m , camInterp . m ) ;
}
2022-04-27 03:00:18 +00:00
gSPMatrix ( pos + + , VIRTUAL_TO_PHYSICAL ( & gMtxTbl [ i ] . interp ) ,
2020-07-29 01:28:12 +00:00
G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH ) ;
}
2022-04-28 02:43:55 +00:00
2022-04-27 03:00:18 +00:00
}
2020-07-29 01:28:12 +00:00
2022-04-17 02:48:40 +00:00
/**
* Increments the matrix stack index and sets the matrixs at the new index .
*/
static u8 increment_mat_stack ( ) {
Mtx * mtx = alloc_display_list ( sizeof ( * mtx ) ) ;
2022-04-27 03:00:18 +00:00
Mtx * mtxPrev = alloc_display_list ( sizeof ( * mtxPrev ) ) ;
2023-05-10 20:25:41 +00:00
if ( mtx = = NULL | | mtxPrev = = NULL ) {
LOG_ERROR ( " Failed to allocate our matrices for the matrix stack. " ) ;
return FALSE ;
}
2022-04-28 02:43:55 +00:00
2022-04-17 02:48:40 +00:00
gMatStackIndex + + ;
2023-05-10 20:25:41 +00:00
if ( gMatStackIndex > = MATRIX_STACK_SIZE ) {
LOG_ERROR ( " Exceeded matrix stack size. " ) ;
gMatStackIndex = MATRIX_STACK_SIZE - 1 ;
return FALSE ;
}
2022-04-17 02:48:40 +00:00
mtxf_to_mtx ( mtx , gMatStack [ gMatStackIndex ] ) ;
2022-04-27 03:00:18 +00:00
mtxf_to_mtx ( mtxPrev , gMatStackPrev [ gMatStackIndex ] ) ;
2022-04-17 02:48:40 +00:00
gMatStackFixed [ gMatStackIndex ] = mtx ;
2022-04-27 03:00:18 +00:00
gMatStackPrevFixed [ gMatStackIndex ] = mtxPrev ;
2022-04-17 02:48:40 +00:00
return TRUE ;
}
2019-09-01 19:50:50 +00:00
/**
* Process a master list node .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_master_list_sub ( struct GraphNodeMasterList * node ) {
2022-04-17 02:48:40 +00:00
struct DisplayListNode * currList = NULL ;
2019-08-25 04:46:40 +00:00
s32 enableZBuffer = ( node - > node . flags & GRAPH_RENDER_Z_BUFFER ) ! = 0 ;
struct RenderModeContainer * modeList = & renderModeTable_1Cycle [ enableZBuffer ] ;
struct RenderModeContainer * mode2List = & renderModeTable_2Cycle [ enableZBuffer ] ;
2019-09-01 19:50:50 +00:00
// @bug This is where the LookAt values should be calculated but aren't.
// As a result, environment mapping is broken on Fast3DEX2 without the
// changes below.
2019-08-25 04:46:40 +00:00
# ifdef F3DEX_GBI_2
Mtx lMtx ;
guLookAtReflect ( & lMtx , & lookAt , 0 , 0 , 0 , /* eye */ 0 , 0 , 1 , /* at */ 1 , 0 , 0 /* up */ ) ;
# endif
2019-09-01 19:50:50 +00:00
2019-08-25 04:46:40 +00:00
if ( enableZBuffer ! = 0 ) {
gDPPipeSync ( gDisplayListHead + + ) ;
gSPSetGeometryMode ( gDisplayListHead + + , G_ZBUFFER ) ;
}
2022-04-17 02:48:40 +00:00
for ( s32 i = 0 ; i < GFX_NUM_MASTER_LISTS ; i + + ) {
2019-08-25 04:46:40 +00:00
if ( ( currList = node - > listHeads [ i ] ) ! = NULL ) {
gDPSetRenderMode ( gDisplayListHead + + , modeList - > modes [ i ] , mode2List - > modes [ i ] ) ;
while ( currList ! = NULL ) {
2022-05-22 04:47:53 +00:00
detect_and_skip_mtx_interpolation ( & currList - > transform , & currList - > transformPrev ) ;
2020-07-29 01:28:12 +00:00
if ( ( u32 ) gMtxTblSize < sizeof ( gMtxTbl ) / sizeof ( gMtxTbl [ 0 ] ) ) {
gMtxTbl [ gMtxTblSize ] . pos = gDisplayListHead ;
gMtxTbl [ gMtxTblSize ] . mtx = currList - > transform ;
2022-04-27 03:00:18 +00:00
gMtxTbl [ gMtxTblSize ] . mtxPrev = currList - > transformPrev ;
2022-04-30 04:28:14 +00:00
gMtxTbl [ gMtxTblSize ] . displayList = currList - > displayList ;
2022-05-22 04:46:41 +00:00
gMtxTbl [ gMtxTblSize + + ] . usingCamSpace = currList - > usingCamSpace ;
2020-07-29 01:28:12 +00:00
}
2022-04-27 03:00:18 +00:00
gSPMatrix ( gDisplayListHead + + , VIRTUAL_TO_PHYSICAL ( currList - > transformPrev ) ,
2020-04-03 18:57:26 +00:00
G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH ) ;
2022-04-28 04:27:14 +00:00
gSPDisplayList ( gDisplayListHead + + , currList - > displayList ) ;
2019-08-25 04:46:40 +00:00
currList = currList - > next ;
}
}
}
if ( enableZBuffer ! = 0 ) {
gDPPipeSync ( gDisplayListHead + + ) ;
gSPClearGeometryMode ( gDisplayListHead + + , G_ZBUFFER ) ;
}
}
2019-09-01 19:50:50 +00:00
/**
* Appends the display list to one of the master lists based on the layer
* parameter . Look at the RenderModeContainer struct to see the corresponding
* render modes of layers .
2019-08-25 04:46:40 +00:00
*/
2022-04-28 04:27:14 +00:00
static void geo_append_display_list ( void * displayList , s16 layer ) {
2019-08-25 04:46:40 +00:00
# ifdef F3DEX_GBI_2
gSPLookAt ( gDisplayListHead + + , & lookAt ) ;
# endif
if ( gCurGraphNodeMasterList ! = 0 ) {
2023-05-13 01:53:25 +00:00
struct DisplayListNode * listNode = growing_pool_alloc ( gDisplayListHeap , sizeof ( struct DisplayListNode ) ) ;
2019-08-25 04:46:40 +00:00
listNode - > transform = gMatStackFixed [ gMatStackIndex ] ;
2022-04-27 03:00:18 +00:00
listNode - > transformPrev = gMatStackPrevFixed [ gMatStackIndex ] ;
2019-08-25 04:46:40 +00:00
listNode - > displayList = displayList ;
listNode - > next = 0 ;
2022-05-22 04:46:41 +00:00
listNode - > usingCamSpace = sUsingCamSpace ;
2019-09-01 19:50:50 +00:00
if ( gCurGraphNodeMasterList - > listHeads [ layer ] = = 0 ) {
2019-08-25 04:46:40 +00:00
gCurGraphNodeMasterList - > listHeads [ layer ] = listNode ;
2019-09-01 19:50:50 +00:00
} else {
2019-08-25 04:46:40 +00:00
gCurGraphNodeMasterList - > listTails [ layer ] - > next = listNode ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
gCurGraphNodeMasterList - > listTails [ layer ] = listNode ;
}
}
2019-09-01 19:50:50 +00:00
/**
* Process the master list node .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_master_list ( struct GraphNodeMasterList * node ) {
if ( gCurGraphNodeMasterList = = NULL & & node - > node . children ! = NULL ) {
gCurGraphNodeMasterList = node ;
2022-04-17 02:48:40 +00:00
for ( s32 i = 0 ; i < GFX_NUM_MASTER_LISTS ; i + + ) {
2019-08-25 04:46:40 +00:00
node - > listHeads [ i ] = NULL ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
geo_process_master_list_sub ( node ) ;
gCurGraphNodeMasterList = NULL ;
}
}
2019-09-01 19:50:50 +00:00
/**
* Process an orthographic projection node .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_ortho_projection ( struct GraphNodeOrthoProjection * node ) {
if ( node - > node . children ! = NULL ) {
Mtx * mtx = alloc_display_list ( sizeof ( * mtx ) ) ;
2022-04-07 01:10:22 +00:00
if ( mtx = = NULL ) { return ; }
2022-05-17 08:22:45 +00:00
f32 left = ( ( gCurGraphNodeRoot - > x - gCurGraphNodeRoot - > width ) / 2.0f ) * node - > scale ;
f32 right = ( ( gCurGraphNodeRoot - > x + gCurGraphNodeRoot - > width ) / 2.0f ) * node - > scale ;
f32 top = ( ( gCurGraphNodeRoot - > y - gCurGraphNodeRoot - > height ) / 2.0f ) * node - > scale ;
f32 bottom = ( ( gCurGraphNodeRoot - > y + gCurGraphNodeRoot - > height ) / 2.0f ) * node - > scale ;
2019-08-25 04:46:40 +00:00
guOrtho ( mtx , left , right , bottom , top , - 2.0f , 2.0f , 1.0f ) ;
gSPPerspNormalize ( gDisplayListHead + + , 0xFFFF ) ;
2019-11-03 19:36:27 +00:00
gSPMatrix ( gDisplayListHead + + , VIRTUAL_TO_PHYSICAL ( mtx ) , G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH ) ;
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
}
}
2019-09-01 19:50:50 +00:00
/**
* Process a perspective projection node .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_perspective ( struct GraphNodePerspective * node ) {
2019-09-01 19:50:50 +00:00
if ( node - > fnNode . func ! = NULL ) {
2019-08-25 04:46:40 +00:00
node - > fnNode . func ( GEO_CONTEXT_RENDER , & node - > fnNode . node , gMatStack [ gMatStackIndex ] ) ;
2019-09-01 19:50:50 +00:00
}
2022-04-27 03:00:18 +00:00
if ( node - > fnNode . node . children = = NULL ) { return ; }
u16 perspNorm ;
Mtx * mtx = alloc_display_list ( sizeof ( * mtx ) ) ;
if ( mtx = = NULL ) { return ; }
2019-08-25 04:46:40 +00:00
2022-05-17 08:22:45 +00:00
f32 divisor = ( f32 ) gCurGraphNodeRoot - > height ;
if ( divisor = = 0 ) { divisor = 1 ; }
2019-08-25 04:46:40 +00:00
# ifdef VERSION_EU
2022-05-17 08:22:45 +00:00
f32 aspect = ( ( f32 ) gCurGraphNodeRoot - > width / divisor ) * 1.1f ;
2019-08-25 04:46:40 +00:00
# else
2022-05-17 08:22:45 +00:00
f32 aspect = ( f32 ) gCurGraphNodeRoot - > width / divisor ;
2019-08-25 04:46:40 +00:00
# endif
2022-05-28 02:56:38 +00:00
gProjectionVanillaNearValue = node - > near ;
gProjectionVanillaFarValue = node - > far ;
f32 near = MIN ( node - > near , gProjectionMaxNearValue ) ;
2022-05-26 00:47:34 +00:00
guPerspective ( mtx , & perspNorm , not_zero ( node - > prevFov , gOverrideFOV ) , aspect , not_zero ( near , gOverrideNear ) , not_zero ( node - > far , gOverrideFar ) , 1.0f ) ;
2020-07-29 01:28:12 +00:00
2022-04-27 03:00:18 +00:00
sPerspectiveNode = node ;
sPerspectiveMtx = mtx ;
sPerspectivePos = gDisplayListHead ;
sPerspectiveAspect = aspect ;
2020-07-29 01:28:12 +00:00
2022-04-27 03:00:18 +00:00
gSPPerspNormalize ( gDisplayListHead + + , perspNorm ) ;
gSPMatrix ( gDisplayListHead + + , VIRTUAL_TO_PHYSICAL ( mtx ) , G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH ) ;
2019-08-25 04:46:40 +00:00
2022-04-27 03:00:18 +00:00
gCurGraphNodeCamFrustum = node ;
geo_process_node_and_siblings ( node - > fnNode . node . children ) ;
gCurGraphNodeCamFrustum = NULL ;
2019-08-25 04:46:40 +00:00
}
2019-09-01 19:50:50 +00:00
/**
* Process a level of detail node . From the current transformation matrix ,
* the perpendicular distance to the camera is extracted and the children
* of this node are only processed if that distance is within the render
* range of this node .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_level_of_detail ( struct GraphNodeLevelOfDetail * node ) {
2020-07-04 20:18:17 +00:00
// We assume modern hardware is powerful enough to draw the most detailed variant
2020-07-05 11:42:26 +00:00
s16 distanceFromCam = 0 ;
2020-07-04 20:18:17 +00:00
2019-08-25 04:46:40 +00:00
if ( node - > minDistance < = distanceFromCam & & distanceFromCam < node - > maxDistance ) {
2019-09-01 19:50:50 +00:00
if ( node - > node . children ! = 0 ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
}
2019-09-01 19:50:50 +00:00
/**
* Process a switch case node . The node ' s selection function is called
* if it is 0 , and among the node ' s children , only the selected child is
* processed next .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_switch ( struct GraphNodeSwitchCase * node ) {
struct GraphNode * selectedChild = node - > fnNode . node . children ;
2019-09-01 19:50:50 +00:00
if ( node - > fnNode . func ! = NULL ) {
2019-08-25 04:46:40 +00:00
node - > fnNode . func ( GEO_CONTEXT_RENDER , & node - > fnNode . node , gMatStack [ gMatStackIndex ] ) ;
2019-09-01 19:50:50 +00:00
}
2022-04-17 02:48:40 +00:00
for ( s32 i = 0 ; selectedChild ! = NULL & & node - > selectedCase > i ; i + + ) {
2019-08-25 04:46:40 +00:00
selectedChild = selectedChild - > next ;
2019-09-01 19:50:50 +00:00
}
if ( selectedChild ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( selectedChild ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-09-01 19:50:50 +00:00
/**
* Process a camera node .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_camera ( struct GraphNodeCamera * node ) {
Mat4 cameraTransform ;
2022-04-28 02:43:55 +00:00
2022-04-27 03:00:18 +00:00
// Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB.
2023-05-10 20:25:41 +00:00
if ( ( gMatStackIndex + 1 ) > = MATRIX_STACK_SIZE ) { LOG_ERROR ( " Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i. " , MATRIX_STACK_SIZE - 1 , gMatStackIndex ) ; return ; }
2022-04-28 02:43:55 +00:00
2022-04-17 02:48:40 +00:00
Mtx * rollMtx = alloc_display_list ( sizeof ( * rollMtx ) ) ;
if ( rollMtx = = NULL ) { return ; }
2019-08-25 04:46:40 +00:00
2022-05-22 04:46:41 +00:00
vec3f_copy ( node - > prevPos , node - > pos ) ;
vec3f_copy ( node - > prevFocus , node - > focus ) ;
2019-09-01 19:50:50 +00:00
if ( node - > fnNode . func ! = NULL ) {
2019-08-25 04:46:40 +00:00
node - > fnNode . func ( GEO_CONTEXT_RENDER , & node - > fnNode . node , gMatStack [ gMatStackIndex ] ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
mtxf_rotate_xy ( rollMtx , node - > rollScreen ) ;
2019-11-03 19:36:27 +00:00
gSPMatrix ( gDisplayListHead + + , VIRTUAL_TO_PHYSICAL ( rollMtx ) , G_MTX_PROJECTION | G_MTX_MUL | G_MTX_NOPUSH ) ;
2019-08-25 04:46:40 +00:00
2020-01-03 15:38:57 +00:00
mtxf_lookat ( cameraTransform , node - > pos , node - > focus , node - > roll ) ;
2019-08-25 04:46:40 +00:00
mtxf_mul ( gMatStack [ gMatStackIndex + 1 ] , cameraTransform , gMatStack [ gMatStackIndex ] ) ;
2020-07-29 01:28:12 +00:00
if ( gGlobalTimer = = node - > prevTimestamp + 1 & & gGlobalTimer ! = gLakituState . skipCameraInterpolationTimestamp ) {
2022-04-27 05:42:57 +00:00
mtxf_lookat ( cameraTransform , node - > prevPos , node - > prevFocus , node - > roll ) ;
mtxf_mul ( gMatStackPrev [ gMatStackIndex + 1 ] , cameraTransform , gMatStackPrev [ gMatStackIndex ] ) ;
2020-07-29 01:28:12 +00:00
} else {
2022-04-27 05:42:57 +00:00
mtxf_lookat ( cameraTransform , node - > pos , node - > focus , node - > roll ) ;
mtxf_mul ( gMatStackPrev [ gMatStackIndex + 1 ] , cameraTransform , gMatStackPrev [ gMatStackIndex ] ) ;
2020-07-29 01:28:12 +00:00
}
node - > prevTimestamp = gGlobalTimer ;
2022-05-22 04:46:41 +00:00
sCameraNode = node ;
2020-07-29 01:28:12 +00:00
2022-04-17 02:48:40 +00:00
// Increment the matrix stack, If we fail to do so. Just return.
if ( ! increment_mat_stack ( ) ) { return ; }
2022-04-28 02:43:55 +00:00
2022-05-08 11:04:14 +00:00
// save the camera matrix
2023-04-27 19:28:39 +00:00
if ( gCamera ) {
mtxf_copy ( gCamera - > mtx , gMatStack [ gMatStackIndex ] ) ;
}
2022-05-08 11:04:14 +00:00
2019-08-25 04:46:40 +00:00
if ( node - > fnNode . node . children ! = 0 ) {
gCurGraphNodeCamera = node ;
2022-05-22 04:46:41 +00:00
sUsingCamSpace = TRUE ;
2020-07-04 15:18:55 +00:00
node - > matrixPtr = & gMatStack [ gMatStackIndex ] ;
2022-04-27 05:42:57 +00:00
node - > matrixPtrPrev = & gMatStackPrev [ gMatStackIndex ] ;
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > fnNode . node . children ) ;
gCurGraphNodeCamera = NULL ;
2022-05-22 04:46:41 +00:00
sUsingCamSpace = FALSE ;
2019-08-25 04:46:40 +00:00
}
gMatStackIndex - - ;
}
2019-09-01 19:50:50 +00:00
/**
* Process a translation / rotation node . A transformation matrix based
* on the node ' s translation and rotation is created and pushed on both
* the float and fixed point matrix stacks .
* For the rest it acts as a normal display list node .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_translation_rotation ( struct GraphNodeTranslationRotation * node ) {
Mat4 mtxf ;
Vec3f translation ;
2022-04-28 02:43:55 +00:00
2022-05-01 00:11:09 +00:00
// Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
2023-05-10 20:25:41 +00:00
if ( ( gMatStackIndex + 1 ) > = MATRIX_STACK_SIZE ) { LOG_ERROR ( " Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i. " , MATRIX_STACK_SIZE - 1 , gMatStackIndex ) ; return ; }
2019-08-25 04:46:40 +00:00
vec3s_to_vec3f ( translation , node - > translation ) ;
mtxf_rotate_zxy_and_translate ( mtxf , translation , node - > rotation ) ;
mtxf_mul ( gMatStack [ gMatStackIndex + 1 ] , mtxf , gMatStack [ gMatStackIndex ] ) ;
2022-04-27 03:00:18 +00:00
mtxf_mul ( gMatStackPrev [ gMatStackIndex + 1 ] , mtxf , gMatStackPrev [ gMatStackIndex ] ) ;
2022-04-28 02:43:55 +00:00
2022-04-17 02:48:40 +00:00
// Increment the matrix stack, If we fail to do so. Just return.
if ( ! increment_mat_stack ( ) ) { return ; }
2022-04-28 02:43:55 +00:00
2019-09-01 19:50:50 +00:00
if ( node - > displayList ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_append_display_list ( node - > displayList , node - > node . flags > > 8 ) ;
2019-09-01 19:50:50 +00:00
}
if ( node - > node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
gMatStackIndex - - ;
}
2019-09-01 19:50:50 +00:00
/**
* Process a translation node . A transformation matrix based on the node ' s
* translation is created and pushed on both the float and fixed point matrix stacks .
* For the rest it acts as a normal display list node .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_translation ( struct GraphNodeTranslation * node ) {
Mat4 mtxf ;
Vec3f translation ;
2022-04-28 02:43:55 +00:00
2022-05-01 00:11:09 +00:00
// Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
2023-05-10 20:25:41 +00:00
if ( ( gMatStackIndex + 1 ) > = MATRIX_STACK_SIZE ) { LOG_ERROR ( " Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i. " , MATRIX_STACK_SIZE - 1 , gMatStackIndex ) ; return ; }
2019-08-25 04:46:40 +00:00
vec3s_to_vec3f ( translation , node - > translation ) ;
mtxf_rotate_zxy_and_translate ( mtxf , translation , gVec3sZero ) ;
mtxf_mul ( gMatStack [ gMatStackIndex + 1 ] , mtxf , gMatStack [ gMatStackIndex ] ) ;
2022-04-27 03:00:18 +00:00
mtxf_mul ( gMatStackPrev [ gMatStackIndex + 1 ] , mtxf , gMatStackPrev [ gMatStackIndex ] ) ;
2022-04-28 02:43:55 +00:00
2022-04-17 02:48:40 +00:00
// Increment the matrix stack, If we fail to do so. Just return.
if ( ! increment_mat_stack ( ) ) { return ; }
2022-04-28 02:43:55 +00:00
2019-09-01 19:50:50 +00:00
if ( node - > displayList ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_append_display_list ( node - > displayList , node - > node . flags > > 8 ) ;
2019-09-01 19:50:50 +00:00
}
if ( node - > node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
gMatStackIndex - - ;
}
2019-09-01 19:50:50 +00:00
/**
* Process a rotation node . A transformation matrix based on the node ' s
* rotation is created and pushed on both the float and fixed point matrix stacks .
* For the rest it acts as a normal display list node .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_rotation ( struct GraphNodeRotation * node ) {
Mat4 mtxf ;
2022-04-28 02:43:55 +00:00
2022-05-01 00:11:09 +00:00
// Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
2023-05-10 20:25:41 +00:00
if ( ( gMatStackIndex + 1 ) > = MATRIX_STACK_SIZE ) { LOG_ERROR ( " Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i. " , MATRIX_STACK_SIZE - 1 , gMatStackIndex ) ; return ; }
2019-08-25 04:46:40 +00:00
mtxf_rotate_zxy_and_translate ( mtxf , gVec3fZero , node - > rotation ) ;
mtxf_mul ( gMatStack [ gMatStackIndex + 1 ] , mtxf , gMatStack [ gMatStackIndex ] ) ;
2022-04-27 05:42:57 +00:00
2020-07-29 01:28:12 +00:00
if ( gGlobalTimer = = node - > prevTimestamp + 1 ) {
2022-04-27 05:42:57 +00:00
mtxf_rotate_zxy_and_translate ( mtxf , gVec3fZero , node - > prevRotation ) ;
} else {
mtxf_rotate_zxy_and_translate ( mtxf , gVec3fZero , node - > rotation ) ;
2020-07-29 01:28:12 +00:00
}
2022-04-27 05:42:57 +00:00
mtxf_mul ( gMatStackPrev [ gMatStackIndex + 1 ] , mtxf , gMatStackPrev [ gMatStackIndex ] ) ;
2020-07-29 01:28:12 +00:00
vec3s_copy ( node - > prevRotation , node - > rotation ) ;
node - > prevTimestamp = gGlobalTimer ;
2022-04-28 02:43:55 +00:00
2022-04-17 02:48:40 +00:00
// Increment the matrix stack, If we fail to do so. Just return.
if ( ! increment_mat_stack ( ) ) { return ; }
2022-04-28 02:43:55 +00:00
2019-09-01 19:50:50 +00:00
if ( node - > displayList ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_append_display_list ( node - > displayList , node - > node . flags > > 8 ) ;
2019-09-01 19:50:50 +00:00
}
if ( node - > node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
gMatStackIndex - - ;
}
2019-09-01 19:50:50 +00:00
/**
* Process a scaling node . A transformation matrix based on the node ' s
* scale is created and pushed on both the float and fixed point matrix stacks .
* For the rest it acts as a normal display list node .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_scale ( struct GraphNodeScale * node ) {
Vec3f scaleVec ;
2022-04-27 05:42:57 +00:00
Vec3f prevScaleVec ;
2022-04-28 02:43:55 +00:00
2022-05-01 00:11:09 +00:00
// Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
2023-05-10 20:25:41 +00:00
if ( ( gMatStackIndex + 1 ) > = MATRIX_STACK_SIZE ) { LOG_ERROR ( " Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i. " , MATRIX_STACK_SIZE - 1 , gMatStackIndex ) ; return ; }
2019-08-25 04:46:40 +00:00
vec3f_set ( scaleVec , node - > scale , node - > scale , node - > scale ) ;
mtxf_scale_vec3f ( gMatStack [ gMatStackIndex + 1 ] , gMatStack [ gMatStackIndex ] , scaleVec ) ;
2022-04-27 05:42:57 +00:00
2022-05-01 00:11:09 +00:00
/* TODO: this fails because multiple player models reuse the same scalenode
2022-04-27 05:42:57 +00:00
vec3f_set ( prevScaleVec , node - > prevScale , node - > prevScale , node - > prevScale ) ;
mtxf_scale_vec3f ( gMatStackPrev [ gMatStackIndex + 1 ] , gMatStackPrev [ gMatStackIndex ] , prevScaleVec ) ;
2022-05-01 00:11:09 +00:00
node - > prevScale = node - > scale ; */
// just use the current scale for now
vec3f_set ( prevScaleVec , node - > scale , node - > scale , node - > scale ) ;
mtxf_scale_vec3f ( gMatStackPrev [ gMatStackIndex + 1 ] , gMatStackPrev [ gMatStackIndex ] , scaleVec ) ;
2022-04-17 02:48:40 +00:00
// Increment the matrix stack, If we fail to do so. Just return.
if ( ! increment_mat_stack ( ) ) { return ; }
2022-04-28 02:43:55 +00:00
2019-09-01 19:50:50 +00:00
if ( node - > displayList ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_append_display_list ( node - > displayList , node - > node . flags > > 8 ) ;
2019-09-01 19:50:50 +00:00
}
if ( node - > node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
gMatStackIndex - - ;
}
2019-09-01 19:50:50 +00:00
/**
* Process a billboard node . A transformation matrix is created that makes its
* children face the camera , and it is pushed on the floating point and fixed
* point matrix stacks .
* For the rest it acts as a normal display list node .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_billboard ( struct GraphNodeBillboard * node ) {
Vec3f translation ;
2022-04-28 02:43:55 +00:00
2022-05-01 00:11:09 +00:00
// Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
2023-05-10 20:25:41 +00:00
if ( ( gMatStackIndex + 1 ) > = MATRIX_STACK_SIZE ) { LOG_ERROR ( " Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i. " , MATRIX_STACK_SIZE - 1 , gMatStackIndex ) ; return ; }
2022-04-28 02:43:55 +00:00
2022-04-17 02:48:40 +00:00
s16 nextMatStackIndex = gMatStackIndex + 1 ;
2022-04-28 02:43:55 +00:00
2019-08-25 04:46:40 +00:00
vec3s_to_vec3f ( translation , node - > translation ) ;
2022-04-17 02:48:40 +00:00
mtxf_billboard ( gMatStack [ nextMatStackIndex ] , gMatStack [ gMatStackIndex ] , translation ,
2019-08-25 04:46:40 +00:00
gCurGraphNodeCamera - > roll ) ;
2022-04-27 03:00:18 +00:00
mtxf_billboard ( gMatStackPrev [ nextMatStackIndex ] , gMatStackPrev [ gMatStackIndex ] , translation ,
2020-07-29 01:28:12 +00:00
gCurGraphNodeCamera - > roll ) ;
2019-09-01 19:50:50 +00:00
if ( gCurGraphNodeHeldObject ! = NULL ) {
2022-04-17 02:48:40 +00:00
mtxf_scale_vec3f ( gMatStack [ nextMatStackIndex ] , gMatStack [ nextMatStackIndex ] ,
2019-11-03 19:36:27 +00:00
gCurGraphNodeHeldObject - > objNode - > header . gfx . scale ) ;
2022-04-27 03:00:18 +00:00
mtxf_scale_vec3f ( gMatStackPrev [ nextMatStackIndex ] , gMatStackPrev [ nextMatStackIndex ] ,
2020-07-29 01:28:12 +00:00
gCurGraphNodeHeldObject - > objNode - > header . gfx . scale ) ;
2019-09-01 19:50:50 +00:00
} else if ( gCurGraphNodeObject ! = NULL ) {
2022-04-17 02:48:40 +00:00
mtxf_scale_vec3f ( gMatStack [ nextMatStackIndex ] , gMatStack [ nextMatStackIndex ] ,
2019-08-25 04:46:40 +00:00
gCurGraphNodeObject - > scale ) ;
2022-04-27 03:00:18 +00:00
mtxf_scale_vec3f ( gMatStackPrev [ nextMatStackIndex ] , gMatStackPrev [ nextMatStackIndex ] ,
2020-07-29 01:28:12 +00:00
gCurGraphNodeObject - > scale ) ;
2022-04-26 20:49:09 +00:00
} else {
//LOG_ERROR("gCurGraphNodeObject and gCurGraphNodeHeldObject are both NULL!");
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2022-04-17 02:48:40 +00:00
// Increment the matrix stack, If we fail to do so. Just return.
if ( ! increment_mat_stack ( ) ) { return ; }
2022-04-28 02:43:55 +00:00
2019-09-01 19:50:50 +00:00
if ( node - > displayList ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_append_display_list ( node - > displayList , node - > node . flags > > 8 ) ;
2019-09-01 19:50:50 +00:00
}
if ( node - > node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
gMatStackIndex - - ;
}
2019-09-01 19:50:50 +00:00
/**
* Process a display list node . It draws a display list without first pushing
* a transformation on the stack , so all transformations are inherited from the
* parent node . It processes its children if it has them .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_display_list ( struct GraphNodeDisplayList * node ) {
2019-09-01 19:50:50 +00:00
if ( node - > displayList ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_append_display_list ( node - > displayList , node - > node . flags > > 8 ) ;
2019-09-01 19:50:50 +00:00
}
if ( node - > node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-09-01 19:50:50 +00:00
/**
* Process a generated list . Instead of storing a pointer to a display list ,
* the list is generated on the fly by a function .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_generated_list ( struct GraphNodeGenerated * node ) {
if ( node - > fnNode . func ! = NULL ) {
2019-11-03 19:36:27 +00:00
Gfx * list = node - > fnNode . func ( GEO_CONTEXT_RENDER , & node - > fnNode . node ,
2023-05-13 01:53:25 +00:00
( struct DynamicPool * ) gMatStack [ gMatStackIndex ] ) ;
2019-08-25 04:46:40 +00:00
2022-02-19 04:27:10 +00:00
if ( list ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_append_display_list ( ( void * ) VIRTUAL_TO_PHYSICAL ( list ) , node - > fnNode . node . flags > > 8 ) ;
}
}
2019-09-01 19:50:50 +00:00
if ( node - > fnNode . node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > fnNode . node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-09-01 19:50:50 +00:00
/**
* Process a background node . Tries to retrieve a background display list from
* the function of the node . If that function is null or returns null , a black
* rectangle is drawn instead .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_background ( struct GraphNodeBackground * node ) {
2019-11-03 19:36:27 +00:00
Gfx * list = NULL ;
2019-08-25 04:46:40 +00:00
2019-09-01 19:50:50 +00:00
if ( node - > fnNode . func ! = NULL ) {
2020-07-29 01:28:12 +00:00
Vec3f posCopy ;
Vec3f focusCopy ;
vec3f_copy ( posCopy , gLakituState . pos ) ;
vec3f_copy ( focusCopy , gLakituState . focus ) ;
2022-04-28 04:27:14 +00:00
if ( gGlobalTimer ! = gLakituState . skipCameraInterpolationTimestamp ) {
2022-04-27 05:42:57 +00:00
vec3f_copy ( gLakituState . pos , node - > prevCameraPos ) ;
vec3f_copy ( gLakituState . focus , node - > prevCameraFocus ) ;
2022-04-28 01:41:05 +00:00
sBackgroundNode = node ;
sBackgroundNodeRoot = gCurGraphNodeRoot ;
2022-04-28 04:27:14 +00:00
}
2022-04-28 01:41:05 +00:00
list = node - > fnNode . func ( GEO_CONTEXT_RENDER , & node - > fnNode . node , NULL ) ;
2020-07-29 01:28:12 +00:00
vec3f_copy ( gLakituState . pos , posCopy ) ;
vec3f_copy ( gLakituState . focus , focusCopy ) ;
2019-09-01 19:50:50 +00:00
}
2022-04-27 05:42:57 +00:00
2022-02-19 04:27:10 +00:00
if ( list ! = NULL ) {
2022-04-28 04:27:14 +00:00
geo_append_display_list ( ( void * ) VIRTUAL_TO_PHYSICAL ( list ) , node - > fnNode . node . flags > > 8 ) ;
2019-08-25 04:46:40 +00:00
} else if ( gCurGraphNodeMasterList ! = NULL ) {
2020-06-02 16:44:34 +00:00
# ifndef F3DEX_GBI_2E
Gfx * gfxStart = alloc_display_list ( sizeof ( Gfx ) * 7 ) ;
# else
2020-05-07 18:21:22 +00:00
Gfx * gfxStart = alloc_display_list ( sizeof ( Gfx ) * 8 ) ;
2020-06-02 16:44:34 +00:00
# endif
2019-08-25 04:46:40 +00:00
Gfx * gfx = gfxStart ;
2022-04-07 01:10:22 +00:00
if ( gfx = = NULL ) { return ; }
2019-08-25 04:46:40 +00:00
gDPPipeSync ( gfx + + ) ;
gDPSetCycleType ( gfx + + , G_CYC_FILL ) ;
gDPSetFillColor ( gfx + + , node - > background ) ;
2020-05-07 18:21:22 +00:00
gDPFillRectangle ( gfx + + , GFX_DIMENSIONS_RECT_FROM_LEFT_EDGE ( 0 ) , BORDER_HEIGHT ,
GFX_DIMENSIONS_RECT_FROM_RIGHT_EDGE ( 0 ) - 1 , SCREEN_HEIGHT - BORDER_HEIGHT - 1 ) ;
2019-08-25 04:46:40 +00:00
gDPPipeSync ( gfx + + ) ;
gDPSetCycleType ( gfx + + , G_CYC_1CYCLE ) ;
gSPEndDisplayList ( gfx + + ) ;
2023-03-21 02:36:25 +00:00
gReadOnlyBackground = - 1 ;
2019-08-25 04:46:40 +00:00
geo_append_display_list ( ( void * ) VIRTUAL_TO_PHYSICAL ( gfxStart ) , 0 ) ;
}
2019-09-01 19:50:50 +00:00
if ( node - > fnNode . node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > fnNode . node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2020-07-29 01:28:12 +00:00
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 ) ]
2019-08-25 04:46:40 +00:00
* gCurAnimTranslationMultiplier ;
2020-07-29 01:28:12 +00:00
translation [ 1 ] + = gCurAnimData [ retrieve_animation_index ( animFrame , animAttribute ) ]
2019-08-25 04:46:40 +00:00
* gCurAnimTranslationMultiplier ;
2020-07-29 01:28:12 +00:00
translation [ 2 ] + = gCurAnimData [ retrieve_animation_index ( animFrame , animAttribute ) ]
2019-08-25 04:46:40 +00:00
* gCurAnimTranslationMultiplier ;
2020-07-29 01:28:12 +00:00
* animType = ANIM_TYPE_ROTATION ;
2019-08-25 04:46:40 +00:00
} else {
2020-07-29 01:28:12 +00:00
if ( * animType = = ANIM_TYPE_LATERAL_TRANSLATION ) {
2019-08-25 04:46:40 +00:00
translation [ 0 ] + =
2020-07-29 01:28:12 +00:00
gCurAnimData [ retrieve_animation_index ( animFrame , animAttribute ) ]
2019-08-25 04:46:40 +00:00
* gCurAnimTranslationMultiplier ;
2020-07-29 01:28:12 +00:00
* animAttribute + = 2 ;
2019-08-25 04:46:40 +00:00
translation [ 2 ] + =
2020-07-29 01:28:12 +00:00
gCurAnimData [ retrieve_animation_index ( animFrame , animAttribute ) ]
2019-08-25 04:46:40 +00:00
* gCurAnimTranslationMultiplier ;
2020-07-29 01:28:12 +00:00
* animType = ANIM_TYPE_ROTATION ;
2019-08-25 04:46:40 +00:00
} else {
2020-07-29 01:28:12 +00:00
if ( * animType = = ANIM_TYPE_VERTICAL_TRANSLATION ) {
* animAttribute + = 2 ;
2019-08-25 04:46:40 +00:00
translation [ 1 ] + =
2020-07-29 01:28:12 +00:00
gCurAnimData [ retrieve_animation_index ( animFrame , animAttribute ) ]
2019-08-25 04:46:40 +00:00
* gCurAnimTranslationMultiplier ;
2020-07-29 01:28:12 +00:00
* animAttribute + = 2 ;
* animType = ANIM_TYPE_ROTATION ;
} else if ( * animType = = ANIM_TYPE_NO_TRANSLATION ) {
* animAttribute + = 6 ;
* animType = ANIM_TYPE_ROTATION ;
2019-08-25 04:46:40 +00:00
}
}
}
2020-07-29 01:28:12 +00:00
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 ) ] ;
2019-08-25 04:46:40 +00:00
}
2020-07-29 01:28:12 +00:00
}
/**
* 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 ;
2022-04-27 05:42:57 +00:00
Vec3s rotationPrev ;
Vec3f translationPrev ;
2022-04-28 02:43:55 +00:00
2022-05-01 00:11:09 +00:00
// Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
2023-05-10 20:25:41 +00:00
if ( ( gMatStackIndex + 1 ) > = MATRIX_STACK_SIZE ) { LOG_ERROR ( " Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i. " , MATRIX_STACK_SIZE - 1 , gMatStackIndex ) ; return ; }
2022-04-28 02:43:55 +00:00
2020-07-29 01:28:12 +00:00
u16 * animAttribute = gCurrAnimAttribute ;
u8 animType = gCurAnimType ;
vec3s_copy ( rotation , gVec3sZero ) ;
vec3f_set ( translation , node - > translation [ 0 ] , node - > translation [ 1 ] , node - > translation [ 2 ] ) ;
2022-04-27 05:42:57 +00:00
vec3s_copy ( rotationPrev , rotation ) ;
vec3f_copy ( translationPrev , translation ) ;
anim_process ( translationPrev , rotationPrev , & animType , gPrevAnimFrame , & animAttribute ) ;
2020-07-29 01:28:12 +00:00
anim_process ( translation , rotation , & gCurAnimType , gCurrAnimFrame , & gCurrAnimAttribute ) ;
2019-08-25 04:46:40 +00:00
mtxf_rotate_xyz_and_translate ( matrix , translation , rotation ) ;
mtxf_mul ( gMatStack [ gMatStackIndex + 1 ] , matrix , gMatStack [ gMatStackIndex ] ) ;
2022-04-27 05:42:57 +00:00
mtxf_rotate_xyz_and_translate ( matrix , translationPrev , rotationPrev ) ;
2022-04-27 03:00:18 +00:00
mtxf_mul ( gMatStackPrev [ gMatStackIndex + 1 ] , matrix , gMatStackPrev [ gMatStackIndex ] ) ;
2022-04-28 02:43:55 +00:00
2022-04-17 02:48:40 +00:00
// Increment the matrix stack, If we fail to do so. Just return.
if ( ! increment_mat_stack ( ) ) { return ; }
2021-09-05 21:17:20 +00:00
if ( gCurGraphNodeMarioState ! = NULL ) {
Vec3f translated = { 0 } ;
get_pos_from_transform_mtx ( translated , gMatStack [ gMatStackIndex ] , * gCurGraphNodeCamera - > matrixPtr ) ;
gCurGraphNodeMarioState - > minimumBoneY = fmin ( gCurGraphNodeMarioState - > minimumBoneY , translated [ 1 ] - gCurGraphNodeMarioState - > marioObj - > header . gfx . pos [ 1 ] ) ;
}
2019-09-01 19:50:50 +00:00
if ( node - > displayList ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_append_display_list ( node - > displayList , node - > node . flags > > 8 ) ;
2019-09-01 19:50:50 +00:00
}
if ( node - > node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
gMatStackIndex - - ;
}
2019-09-01 19:50:50 +00:00
/**
* Initialize the animation - related global variables for the currently drawn
* object ' s animation .
2019-08-25 04:46:40 +00:00
*/
2022-02-19 04:27:10 +00:00
void geo_set_animation_globals ( struct AnimInfo * node , s32 hasAnimation ) {
2019-08-25 04:46:40 +00:00
struct Animation * anim = node - > curAnim ;
2022-02-19 04:27:10 +00:00
if ( hasAnimation ) {
2019-08-25 04:46:40 +00:00
node - > animFrame = geo_update_animation_frame ( node , & node - > animFrameAccelAssist ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
node - > animTimer = gAreaUpdateCounter ;
2019-09-01 19:50:50 +00:00
if ( anim - > flags & ANIM_FLAG_HOR_TRANS ) {
2019-08-25 04:46:40 +00:00
gCurAnimType = ANIM_TYPE_VERTICAL_TRANSLATION ;
2019-09-01 19:50:50 +00:00
} else if ( anim - > flags & ANIM_FLAG_VERT_TRANS ) {
2019-08-25 04:46:40 +00:00
gCurAnimType = ANIM_TYPE_LATERAL_TRANSLATION ;
2019-09-01 19:50:50 +00:00
} else if ( anim - > flags & ANIM_FLAG_6 ) {
2019-08-25 04:46:40 +00:00
gCurAnimType = ANIM_TYPE_NO_TRANSLATION ;
2019-09-01 19:50:50 +00:00
} else {
2019-08-25 04:46:40 +00:00
gCurAnimType = ANIM_TYPE_TRANSLATION ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
gCurrAnimFrame = node - > animFrame ;
2020-07-29 01:28:12 +00:00
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 ;
2019-08-25 04:46:40 +00:00
gCurAnimEnabled = ( anim - > flags & ANIM_FLAG_5 ) = = 0 ;
2019-11-03 19:36:27 +00:00
gCurrAnimAttribute = segmented_to_virtual ( ( void * ) anim - > index ) ;
gCurAnimData = segmented_to_virtual ( ( void * ) anim - > values ) ;
2019-08-25 04:46:40 +00:00
2022-02-19 04:27:10 +00:00
if ( anim - > animYTransDivisor = = 0 ) {
2019-08-25 04:46:40 +00:00
gCurAnimTranslationMultiplier = 1.0f ;
2019-09-01 19:50:50 +00:00
} else {
2022-02-19 04:27:10 +00:00
gCurAnimTranslationMultiplier = ( f32 ) node - > animYTrans / ( f32 ) anim - > animYTransDivisor ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-09-01 19:50:50 +00:00
/**
* Process a shadow node . Renders a shadow under an object offset by the
* translation of the first animated component and rotated according to
* the floor below it .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_shadow ( struct GraphNodeShadow * node ) {
Mat4 mtxf ;
2022-04-27 05:42:57 +00:00
Vec3f shadowPosPrev ;
2019-08-25 04:46:40 +00:00
Vec3f animOffset ;
f32 shadowScale ;
2022-04-28 02:43:55 +00:00
2022-05-01 00:11:09 +00:00
// Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
2023-05-10 20:25:41 +00:00
if ( ( gMatStackIndex + 1 ) > = MATRIX_STACK_SIZE ) { LOG_ERROR ( " Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i. " , MATRIX_STACK_SIZE - 1 , gMatStackIndex ) ; return ; }
2019-08-25 04:46:40 +00:00
if ( gCurGraphNodeCamera ! = NULL & & gCurGraphNodeObject ! = NULL ) {
if ( gCurGraphNodeHeldObject ! = NULL ) {
2023-02-18 21:06:03 +00:00
get_pos_from_transform_mtx ( gCurGraphNodeObject - > shadowPos , gMatStack [ gMatStackIndex ] ,
2020-07-04 15:18:55 +00:00
* gCurGraphNodeCamera - > matrixPtr ) ;
2019-08-25 04:46:40 +00:00
shadowScale = node - > shadowScale ;
} else {
2023-02-18 21:06:03 +00:00
if ( ! gCurGraphNodeObject - > disableAutomaticShadowPos ) {
vec3f_copy ( gCurGraphNodeObject - > shadowPos , gCurGraphNodeObject - > pos ) ;
}
2019-08-25 04:46:40 +00:00
shadowScale = node - > shadowScale * gCurGraphNodeObject - > scale [ 0 ] ;
}
2022-04-17 02:48:40 +00:00
f32 objScale = 1.0f ;
2022-02-19 04:27:10 +00:00
if ( gCurAnimEnabled ) {
2019-08-25 04:46:40 +00:00
if ( gCurAnimType = = ANIM_TYPE_TRANSLATION
| | gCurAnimType = = ANIM_TYPE_LATERAL_TRANSLATION ) {
2022-04-17 02:48:40 +00:00
struct GraphNode * geo = node - > node . children ;
2019-09-01 19:50:50 +00:00
if ( geo ! = NULL & & geo - > type = = GRAPH_NODE_TYPE_SCALE ) {
2019-08-25 04:46:40 +00:00
objScale = ( ( struct GraphNodeScale * ) geo ) - > scale ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
animOffset [ 0 ] =
gCurAnimData [ retrieve_animation_index ( gCurrAnimFrame , & gCurrAnimAttribute ) ]
* gCurAnimTranslationMultiplier * objScale ;
animOffset [ 1 ] = 0.0f ;
gCurrAnimAttribute + = 2 ;
animOffset [ 2 ] =
gCurAnimData [ retrieve_animation_index ( gCurrAnimFrame , & gCurrAnimAttribute ) ]
* gCurAnimTranslationMultiplier * objScale ;
gCurrAnimAttribute - = 6 ;
// simple matrix rotation so the shadow offset rotates along with the object
2022-04-17 02:48:40 +00:00
f32 sinAng = sins ( gCurGraphNodeObject - > angle [ 1 ] ) ;
f32 cosAng = coss ( gCurGraphNodeObject - > angle [ 1 ] ) ;
2019-08-25 04:46:40 +00:00
2023-02-18 21:06:03 +00:00
gCurGraphNodeObject - > shadowPos [ 0 ] + = animOffset [ 0 ] * cosAng + animOffset [ 2 ] * sinAng ;
gCurGraphNodeObject - > shadowPos [ 2 ] + = - animOffset [ 0 ] * sinAng + animOffset [ 2 ] * cosAng ;
2019-08-25 04:46:40 +00:00
}
}
2020-07-29 01:28:12 +00:00
if ( gCurGraphNodeHeldObject ! = NULL ) {
2022-04-27 05:42:57 +00:00
2020-07-29 01:28:12 +00:00
if ( gGlobalTimer = = gCurGraphNodeHeldObject - > prevShadowPosTimestamp + 1 ) {
2022-04-27 05:42:57 +00:00
vec3f_copy ( shadowPosPrev , gCurGraphNodeHeldObject - > prevShadowPos ) ;
2020-07-29 01:28:12 +00:00
} else {
2023-02-18 21:06:03 +00:00
vec3f_copy ( shadowPosPrev , gCurGraphNodeObject - > shadowPos ) ;
2020-07-29 01:28:12 +00:00
}
2022-04-27 05:42:57 +00:00
2023-02-18 21:06:03 +00:00
vec3f_copy ( gCurGraphNodeHeldObject - > prevShadowPos , gCurGraphNodeObject - > shadowPos ) ;
2020-07-29 01:28:12 +00:00
gCurGraphNodeHeldObject - > prevShadowPosTimestamp = gGlobalTimer ;
} else {
if ( gGlobalTimer = = gCurGraphNodeObject - > prevShadowPosTimestamp + 1 & &
2020-09-27 05:00:34 +00:00
gGlobalTimer ! = gCurGraphNodeObject - > skipInterpolationTimestamp & &
gGlobalTimer ! = gLakituState . skipCameraInterpolationTimestamp ) {
2022-04-27 05:42:57 +00:00
vec3f_copy ( shadowPosPrev , gCurGraphNodeObject - > prevShadowPos ) ;
2020-07-29 01:28:12 +00:00
} else {
2023-02-18 21:06:03 +00:00
vec3f_copy ( shadowPosPrev , gCurGraphNodeObject - > shadowPos ) ;
2020-07-29 01:28:12 +00:00
}
2023-02-18 21:06:03 +00:00
vec3f_copy ( gCurGraphNodeObject - > prevShadowPos , gCurGraphNodeObject - > shadowPos ) ;
2020-07-29 01:28:12 +00:00
gCurGraphNodeObject - > prevShadowPosTimestamp = gGlobalTimer ;
}
2022-04-28 02:43:55 +00:00
if ( sShadowInterpCount < MAX_SHADOW_NODES ) {
struct ShadowInterp * interp = & sShadowInterp [ sShadowInterpCount + + ] ;
gShadowInterpCurrent = interp ;
interp - > gfx = NULL ;
interp - > node = node ;
interp - > shadowScale = shadowScale ;
interp - > obj = gCurGraphNodeObject ;
2023-02-18 21:06:03 +00:00
vec3f_copy ( interp - > shadowPos , gCurGraphNodeObject - > shadowPos ) ;
2022-04-28 02:43:55 +00:00
vec3f_copy ( interp - > shadowPosPrev , shadowPosPrev ) ;
} else {
gShadowInterpCurrent = NULL ;
}
2022-04-27 05:42:57 +00:00
Gfx * shadowListPrev = create_shadow_below_xyz ( shadowPosPrev [ 0 ] , shadowPosPrev [ 1 ] ,
shadowPosPrev [ 2 ] , shadowScale ,
node - > shadowSolidity , node - > shadowType ) ;
2022-04-28 02:43:55 +00:00
if ( gShadowInterpCurrent ! = NULL ) {
gShadowInterpCurrent - > gfx = shadowListPrev ;
}
2023-02-18 21:06:03 +00:00
if ( gCurGraphNodeObject - > shadowInvisible ) {
shadowListPrev = NULL ;
}
2022-04-28 02:43:55 +00:00
if ( shadowListPrev ! = NULL ) {
2023-02-18 21:06:03 +00:00
mtxf_translate ( mtxf , gCurGraphNodeObject - > shadowPos ) ;
2022-04-17 02:48:40 +00:00
mtxf_mul ( gMatStack [ gMatStackIndex + 1 ] , mtxf , * gCurGraphNodeCamera - > matrixPtr ) ;
2022-04-27 05:42:57 +00:00
mtxf_translate ( mtxf , shadowPosPrev ) ;
mtxf_mul ( gMatStackPrev [ gMatStackIndex + 1 ] , mtxf , * gCurGraphNodeCamera - > matrixPtrPrev ) ;
2022-04-28 02:43:55 +00:00
2022-04-17 02:48:40 +00:00
// Increment the matrix stack, If we fail to do so. Just return.
if ( ! increment_mat_stack ( ) ) { return ; }
2020-07-29 01:28:12 +00:00
2022-02-19 04:27:10 +00:00
if ( gShadowAboveWaterOrLava = = TRUE ) {
2022-04-28 04:27:14 +00:00
geo_append_display_list ( ( void * ) VIRTUAL_TO_PHYSICAL ( shadowListPrev ) , 4 ) ;
2022-02-19 04:27:10 +00:00
} else if ( gMarioOnIceOrCarpet = = TRUE ) {
2022-04-28 04:27:14 +00:00
geo_append_display_list ( ( void * ) VIRTUAL_TO_PHYSICAL ( shadowListPrev ) , 5 ) ;
2019-09-01 19:50:50 +00:00
} else {
2022-04-28 04:27:14 +00:00
geo_append_display_list ( ( void * ) VIRTUAL_TO_PHYSICAL ( shadowListPrev ) , 6 ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
gMatStackIndex - - ;
}
}
2019-09-01 19:50:50 +00:00
if ( node - > node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-09-01 19:50:50 +00:00
/**
* Check whether an object is in view to determine whether it should be drawn .
2020-06-02 16:44:34 +00:00
* This is known as frustum culling .
2019-09-01 19:50:50 +00:00
* It checks whether the object is far away , very close / behind the camera ,
* or horizontally out of view . It does not check whether it is vertically
* out of view . It assumes a sphere of 300 units around the object ' s position
* unless the object has a culling radius node that specifies otherwise .
2019-08-25 04:46:40 +00:00
*
2019-09-01 19:50:50 +00:00
* The matrix parameter should be the top of the matrix stack , which is the
* object ' s transformation matrix times the camera ' look - at ' matrix . The math
* is counter - intuitive , but it checks column 3 ( translation vector ) of this
* matrix to determine where the origin ( 0 , 0 , 0 ) in object space will be once
* transformed to camera space ( x + = right , y + = up , z = ' coming out the screen ' ) .
* In 3 D graphics , you typically model the world as being moved in front of a
* static camera instead of a moving camera through a static world , which in
* this case simplifies calculations . Note that the perspective matrix is not
* on the matrix stack , so there are still calculations with the fov to compute
2020-06-02 16:44:34 +00:00
* the slope of the lines of the frustum .
2019-08-25 04:46:40 +00:00
*
2019-09-01 19:50:50 +00:00
* z -
2019-08-25 04:46:40 +00:00
*
2019-09-01 19:50:50 +00:00
* \ | /
* \ | /
* \ | /
* \ | /
* \ | /
* \ | /
* C x +
2019-08-25 04:46:40 +00:00
*
2019-09-01 19:50:50 +00:00
* Since ( 0 , 0 , 0 ) is unaffected by rotation , columns 0 , 1 and 2 are ignored .
2019-08-25 04:46:40 +00:00
*/
2022-02-19 04:27:10 +00:00
static s32 obj_is_in_view ( struct GraphNodeObject * node , Mat4 matrix ) {
2019-09-01 19:50:50 +00:00
if ( node - > node . flags & GRAPH_RENDER_INVISIBLE ) {
2019-08-25 04:46:40 +00:00
return FALSE ;
2022-08-11 08:23:54 +00:00
} else if ( node - > skipInViewCheck ) {
return TRUE ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
// ! @bug The aspect ratio is not accounted for. When the fov value is 45,
// the horizontal effective fov is actually 60 degrees, so you can see objects
// visibly pop in or out at the edge of the screen.
2022-04-17 02:48:40 +00:00
//
// Half of the fov in in-game angle units instead of degrees.
s16 halfFov = ( gCurGraphNodeCamFrustum - > fov / 2.0f + 1.0f ) * 32768.0f / 180.0f + 0.5f ;
2019-08-25 04:46:40 +00:00
2022-05-17 08:22:45 +00:00
f32 divisor = coss ( halfFov ) ;
if ( divisor = = 0 ) { divisor = 1 ; }
f32 hScreenEdge = - matrix [ 3 ] [ 2 ] * sins ( halfFov ) / divisor ;
2019-08-25 04:46:40 +00:00
// -matrix[3][2] is the depth, which gets multiplied by tan(halfFov) to get
// the amount of units between the center of the screen and the horizontal edge
// given the distance from the object to the camera.
2020-06-02 16:44:34 +00:00
// This multiplication should really be performed on 4:3 as well,
// but the issue will be more apparent on widescreen.
2020-05-07 18:21:22 +00:00
hScreenEdge * = GFX_DIMENSIONS_ASPECT_RATIO ;
2022-04-28 02:43:55 +00:00
2022-04-17 02:48:40 +00:00
s16 cullingRadius = 300 ;
struct GraphNode * geo = node - > sharedChild ;
2019-09-01 19:50:50 +00:00
if ( geo ! = NULL & & geo - > type = = GRAPH_NODE_TYPE_CULLING_RADIUS ) {
2022-04-17 02:48:40 +00:00
cullingRadius = ( f32 ) ( ( struct GraphNodeCullingRadius * ) geo ) - > cullingRadius ; //! Why is there a f32 cast?
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
// Don't render if the object is close to or behind the camera
2019-09-01 19:50:50 +00:00
if ( matrix [ 3 ] [ 2 ] > - 100.0f + cullingRadius ) {
2019-08-25 04:46:40 +00:00
return FALSE ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
//! This makes the HOLP not update when the camera is far away, and it
// makes PU travel safe when the camera is locked on the main map.
// If Mario were rendered with a depth over 65536 it would cause overflow
// when converting the transformation matrix to a fixed point matrix.
2019-09-01 19:50:50 +00:00
if ( matrix [ 3 ] [ 2 ] < - 20000.0f - cullingRadius ) {
2019-08-25 04:46:40 +00:00
return FALSE ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
// Check whether the object is horizontally in view
2019-09-01 19:50:50 +00:00
if ( matrix [ 3 ] [ 0 ] > hScreenEdge + cullingRadius ) {
2019-08-25 04:46:40 +00:00
return FALSE ;
2019-09-01 19:50:50 +00:00
}
if ( matrix [ 3 ] [ 0 ] < - hScreenEdge - cullingRadius ) {
2019-08-25 04:46:40 +00:00
return FALSE ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
return TRUE ;
}
2019-09-01 19:50:50 +00:00
/**
* Process an object node .
2019-08-25 04:46:40 +00:00
*/
static void geo_process_object ( struct Object * node ) {
2020-10-10 04:36:15 +00:00
struct Object * lastProcessingObject = gCurGraphNodeProcessingObject ;
2021-09-05 21:17:20 +00:00
struct MarioState * lastMarioState = gCurGraphNodeMarioState ;
2020-09-06 20:54:01 +00:00
gCurGraphNodeProcessingObject = node ;
2019-08-25 04:46:40 +00:00
Mat4 mtxf ;
s32 hasAnimation = ( node - > header . gfx . node . flags & GRAPH_RENDER_HAS_ANIMATION ) ! = 0 ;
2022-04-27 05:42:57 +00:00
Vec3f scalePrev ;
2022-04-20 05:36:47 +00:00
2023-05-10 20:25:41 +00:00
// Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
if ( ( gMatStackIndex + 1 ) > = MATRIX_STACK_SIZE ) { LOG_ERROR ( " Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i. " , MATRIX_STACK_SIZE - 1 , gMatStackIndex ) ; return ; }
2022-04-20 05:36:47 +00:00
if ( node - > hookRender ) {
smlua_call_event_hooks_object_param ( HOOK_ON_OBJECT_RENDER , node ) ;
}
2021-09-05 21:17:20 +00:00
if ( node - > header . gfx . node . flags & GRAPH_RENDER_PLAYER ) {
gCurGraphNodeMarioState = NULL ;
2022-03-30 03:45:56 +00:00
for ( s32 i = 0 ; i < MAX_PLAYERS ; i + + ) {
2021-09-05 21:17:20 +00:00
if ( gMarioStates [ i ] . marioObj = = node ) {
gCurGraphNodeMarioState = & gMarioStates [ i ] ;
break ;
}
}
if ( gCurGraphNodeMarioState ! = NULL ) {
gCurGraphNodeMarioState - > minimumBoneY = 999 ;
}
}
2022-02-19 04:27:10 +00:00
if ( node - > header . gfx . areaIndex = = gCurGraphNodeRoot - > areaIndex ) {
2019-08-25 04:46:40 +00:00
if ( node - > header . gfx . throwMatrix ! = NULL ) {
2022-04-27 05:42:57 +00:00
2020-07-04 15:18:55 +00:00
mtxf_mul ( gMatStack [ gMatStackIndex + 1 ] , * node - > header . gfx . throwMatrix ,
2019-08-25 04:46:40 +00:00
gMatStack [ gMatStackIndex ] ) ;
2022-04-27 05:42:57 +00:00
2020-07-29 01:28:12 +00:00
if ( gGlobalTimer = = node - > header . gfx . prevThrowMatrixTimestamp + 1 & &
2020-09-27 05:00:34 +00:00
gGlobalTimer ! = node - > header . gfx . skipInterpolationTimestamp & &
gGlobalTimer ! = gLakituState . skipCameraInterpolationTimestamp ) {
2022-04-27 05:42:57 +00:00
mtxf_copy ( mtxf , node - > header . gfx . prevThrowMatrix ) ;
mtxf_mul ( gMatStackPrev [ gMatStackIndex + 1 ] , mtxf , gMatStackPrev [ gMatStackIndex ] ) ;
2020-07-29 01:28:12 +00:00
} else {
2022-04-27 03:00:18 +00:00
mtxf_mul ( gMatStackPrev [ gMatStackIndex + 1 ] , ( void * ) node - > header . gfx . throwMatrix ,
gMatStackPrev [ gMatStackIndex ] ) ;
2020-07-29 01:28:12 +00:00
}
2022-04-27 05:42:57 +00:00
2020-07-29 01:28:12 +00:00
mtxf_copy ( node - > header . gfx . prevThrowMatrix , * node - > header . gfx . throwMatrix ) ;
node - > header . gfx . prevThrowMatrixTimestamp = gGlobalTimer ;
2022-04-27 05:42:57 +00:00
2022-04-23 10:05:16 +00:00
} else if ( ( node - > header . gfx . node . flags & GRAPH_RENDER_CYLBOARD ) & & ! ( node - > header . gfx . sharedChild & & node - > header . gfx . sharedChild - > extraFlags & GRAPH_EXTRA_FORCE_3D ) ) {
2022-04-27 05:42:57 +00:00
Vec3f posPrev ;
2020-07-29 01:28:12 +00:00
if ( gGlobalTimer = = node - > header . gfx . prevTimestamp + 1 & &
2020-09-27 05:00:34 +00:00
gGlobalTimer ! = node - > header . gfx . skipInterpolationTimestamp & &
gGlobalTimer ! = gLakituState . skipCameraInterpolationTimestamp ) {
2022-04-27 05:42:57 +00:00
vec3f_copy ( posPrev , node - > header . gfx . prevPos ) ;
2020-07-29 01:28:12 +00:00
} else {
2022-04-27 05:42:57 +00:00
vec3f_copy ( posPrev , node - > header . gfx . pos ) ;
2020-07-29 01:28:12 +00:00
}
2022-04-27 05:42:57 +00:00
2020-07-29 01:28:12 +00:00
vec3f_copy ( node - > header . gfx . prevPos , node - > header . gfx . pos ) ;
node - > header . gfx . prevTimestamp = gGlobalTimer ;
2020-05-15 01:47:55 +00:00
mtxf_cylboard ( gMatStack [ gMatStackIndex + 1 ] , gMatStack [ gMatStackIndex ] ,
node - > header . gfx . pos , gCurGraphNodeCamera - > roll ) ;
2022-04-27 03:00:18 +00:00
mtxf_cylboard ( gMatStackPrev [ gMatStackIndex + 1 ] , gMatStackPrev [ gMatStackIndex ] ,
2022-04-27 05:42:57 +00:00
posPrev , gCurGraphNodeCamera - > roll ) ;
2022-04-23 10:05:16 +00:00
} else if ( ( node - > header . gfx . node . flags & GRAPH_RENDER_BILLBOARD ) & & ! ( node - > header . gfx . sharedChild & & node - > header . gfx . sharedChild - > extraFlags & GRAPH_EXTRA_FORCE_3D ) ) {
2022-04-27 05:42:57 +00:00
Vec3f posPrev ;
2020-07-29 01:28:12 +00:00
if ( gGlobalTimer = = node - > header . gfx . prevTimestamp + 1 & &
2020-09-27 05:00:34 +00:00
gGlobalTimer ! = node - > header . gfx . skipInterpolationTimestamp & &
gGlobalTimer ! = gLakituState . skipCameraInterpolationTimestamp ) {
2022-04-27 05:42:57 +00:00
vec3f_copy ( posPrev , node - > header . gfx . prevPos ) ;
2020-07-29 01:28:12 +00:00
} else {
2022-04-27 05:42:57 +00:00
vec3f_copy ( posPrev , node - > header . gfx . pos ) ;
2020-07-29 01:28:12 +00:00
}
2022-04-27 05:42:57 +00:00
2020-07-29 01:28:12 +00:00
vec3f_copy ( node - > header . gfx . prevPos , node - > header . gfx . pos ) ;
node - > header . gfx . prevTimestamp = gGlobalTimer ;
2019-08-25 04:46:40 +00:00
mtxf_billboard ( gMatStack [ gMatStackIndex + 1 ] , gMatStack [ gMatStackIndex ] ,
node - > header . gfx . pos , gCurGraphNodeCamera - > roll ) ;
2022-04-27 03:00:18 +00:00
mtxf_billboard ( gMatStackPrev [ gMatStackIndex + 1 ] , gMatStackPrev [ gMatStackIndex ] ,
2022-04-27 05:42:57 +00:00
posPrev , gCurGraphNodeCamera - > roll ) ;
2019-08-25 04:46:40 +00:00
} else {
2022-04-27 05:42:57 +00:00
Vec3f posPrev ;
Vec3s anglePrev ;
2020-07-29 01:28:12 +00:00
if ( gGlobalTimer = = node - > header . gfx . prevTimestamp + 1 & &
2020-09-27 05:00:34 +00:00
gGlobalTimer ! = node - > header . gfx . skipInterpolationTimestamp & &
gGlobalTimer ! = gLakituState . skipCameraInterpolationTimestamp ) {
2022-04-27 05:42:57 +00:00
vec3f_copy ( posPrev , node - > header . gfx . prevPos ) ;
vec3s_copy ( anglePrev , node - > header . gfx . prevAngle ) ;
2020-07-29 01:28:12 +00:00
} else {
2022-04-27 05:42:57 +00:00
vec3f_copy ( posPrev , node - > header . gfx . pos ) ;
vec3s_copy ( anglePrev , node - > header . gfx . angle ) ;
2020-07-29 01:28:12 +00:00
}
2022-04-27 05:42:57 +00:00
2020-07-29 01:28:12 +00:00
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 ;
2019-08-25 04:46:40 +00:00
mtxf_rotate_zxy_and_translate ( mtxf , node - > header . gfx . pos , node - > header . gfx . angle ) ;
mtxf_mul ( gMatStack [ gMatStackIndex + 1 ] , mtxf , gMatStack [ gMatStackIndex ] ) ;
2022-04-27 05:42:57 +00:00
mtxf_rotate_zxy_and_translate ( mtxf , posPrev , anglePrev ) ;
2022-04-27 03:00:18 +00:00
mtxf_mul ( gMatStackPrev [ gMatStackIndex + 1 ] , mtxf , gMatStackPrev [ gMatStackIndex ] ) ;
2020-07-29 01:28:12 +00:00
}
if ( gGlobalTimer = = node - > header . gfx . prevScaleTimestamp + 1 & &
2020-09-27 05:00:34 +00:00
gGlobalTimer ! = node - > header . gfx . skipInterpolationTimestamp & &
gGlobalTimer ! = gLakituState . skipCameraInterpolationTimestamp ) {
2022-04-27 05:42:57 +00:00
vec3f_copy ( scalePrev , node - > header . gfx . prevScale ) ;
2020-07-29 01:28:12 +00:00
} else {
2022-04-27 05:42:57 +00:00
vec3f_copy ( scalePrev , node - > header . gfx . scale ) ;
2019-08-25 04:46:40 +00:00
}
2022-04-27 05:42:57 +00:00
2020-07-29 01:28:12 +00:00
vec3f_copy ( node - > header . gfx . prevScale , node - > header . gfx . scale ) ;
node - > header . gfx . prevScaleTimestamp = gGlobalTimer ;
2019-08-25 04:46:40 +00:00
mtxf_scale_vec3f ( gMatStack [ gMatStackIndex + 1 ] , gMatStack [ gMatStackIndex + 1 ] ,
node - > header . gfx . scale ) ;
2022-04-27 03:00:18 +00:00
mtxf_scale_vec3f ( gMatStackPrev [ gMatStackIndex + 1 ] , gMatStackPrev [ gMatStackIndex + 1 ] ,
2022-04-27 05:42:57 +00:00
scalePrev ) ;
2020-07-04 15:18:55 +00:00
node - > header . gfx . throwMatrix = & gMatStack [ + + gMatStackIndex ] ;
2022-04-27 05:42:57 +00:00
node - > header . gfx . throwMatrixPrev = & gMatStackPrev [ gMatStackIndex ] ;
2019-08-25 04:46:40 +00:00
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 ] ;
// FIXME: correct types
2022-02-19 04:27:10 +00:00
if ( node - > header . gfx . animInfo . curAnim ! = NULL ) {
2022-03-10 02:01:03 +00:00
dynos_gfx_swap_animations ( node ) ;
2022-02-19 04:27:10 +00:00
geo_set_animation_globals ( & node - > header . gfx . animInfo , hasAnimation ) ;
2023-04-28 23:56:18 +00:00
smlua_call_event_hooks_object_param ( HOOK_ON_OBJECT_ANIM_UPDATE , node ) ;
2022-03-10 02:01:03 +00:00
dynos_gfx_swap_animations ( node ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
if ( obj_is_in_view ( & node - > header . gfx , gMatStack [ gMatStackIndex ] ) ) {
Mtx * mtx = alloc_display_list ( sizeof ( * mtx ) ) ;
2022-04-27 05:42:57 +00:00
Mtx * mtxPrev = alloc_display_list ( sizeof ( * mtxPrev ) ) ;
if ( mtx = = NULL | | mtxPrev = = NULL ) { return ; }
2019-08-25 04:46:40 +00:00
mtxf_to_mtx ( mtx , gMatStack [ gMatStackIndex ] ) ;
gMatStackFixed [ gMatStackIndex ] = mtx ;
2022-04-27 05:42:57 +00:00
mtxf_to_mtx ( mtxPrev , gMatStackPrev [ gMatStackIndex ] ) ;
gMatStackPrevFixed [ gMatStackIndex ] = mtxPrev ;
2019-08-25 04:46:40 +00:00
if ( node - > header . gfx . sharedChild ! = NULL ) {
gCurGraphNodeObject = ( struct GraphNodeObject * ) node ;
node - > header . gfx . sharedChild - > parent = & node - > header . gfx . node ;
geo_process_node_and_siblings ( node - > header . gfx . sharedChild ) ;
node - > header . gfx . sharedChild - > parent = NULL ;
gCurGraphNodeObject = NULL ;
}
2022-04-27 05:42:57 +00:00
2019-09-01 19:50:50 +00:00
if ( node - > header . gfx . node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > header . gfx . node . children ) ;
2019-09-01 19:50:50 +00:00
}
2022-04-27 05:42:57 +00:00
2020-07-29 01:28:12 +00:00
} else {
node - > header . gfx . prevThrowMatrixTimestamp = 0 ;
node - > header . gfx . prevTimestamp = 0 ;
node - > header . gfx . prevScaleTimestamp = 0 ;
2019-08-25 04:46:40 +00:00
}
gMatStackIndex - - ;
gCurAnimType = ANIM_TYPE_NONE ;
node - > header . gfx . throwMatrix = NULL ;
2022-04-27 05:42:57 +00:00
node - > header . gfx . throwMatrixPrev = NULL ;
2019-08-25 04:46:40 +00:00
}
2020-10-10 04:36:15 +00:00
gCurGraphNodeProcessingObject = lastProcessingObject ;
2021-09-05 21:17:20 +00:00
gCurGraphNodeMarioState = lastMarioState ;
2019-08-25 04:46:40 +00:00
}
2019-09-01 19:50:50 +00:00
/**
* Process an object parent node . Temporarily assigns itself as the parent of
* the subtree rooted at ' sharedChild ' and processes the subtree , after which the
* actual children are be processed . ( in practice they are null though )
2019-08-25 04:46:40 +00:00
*/
static void geo_process_object_parent ( struct GraphNodeObjectParent * node ) {
if ( node - > sharedChild ! = NULL ) {
node - > sharedChild - > parent = ( struct GraphNode * ) node ;
geo_process_node_and_siblings ( node - > sharedChild ) ;
node - > sharedChild - > parent = NULL ;
}
2019-09-01 19:50:50 +00:00
if ( node - > node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-09-01 19:50:50 +00:00
/**
* Process a held object node .
2019-08-25 04:46:40 +00:00
*/
void geo_process_held_object ( struct GraphNodeHeldObject * node ) {
Mat4 mat ;
Vec3f translation ;
2022-04-27 05:42:57 +00:00
Vec3f scalePrev ;
2022-04-28 02:43:55 +00:00
2022-05-01 00:11:09 +00:00
// Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
2023-05-10 20:25:41 +00:00
if ( ( gMatStackIndex + 1 ) > = MATRIX_STACK_SIZE ) { LOG_ERROR ( " Preventing attempt to exceed the maximum size %i for our matrix stack with size of %i. " , MATRIX_STACK_SIZE - 1 , gMatStackIndex ) ; return ; }
2019-08-25 04:46:40 +00:00
# ifdef F3DEX_GBI_2
gSPLookAt ( gDisplayListHead + + , & lookAt ) ;
# endif
2019-09-01 19:50:50 +00:00
if ( node - > fnNode . func ! = NULL ) {
2019-08-25 04:46:40 +00:00
node - > fnNode . func ( GEO_CONTEXT_RENDER , & node - > fnNode . node , gMatStack [ gMatStackIndex ] ) ;
2019-09-01 19:50:50 +00:00
}
2019-11-03 19:36:27 +00:00
if ( node - > objNode ! = NULL & & node - > objNode - > header . gfx . sharedChild ! = NULL ) {
s32 hasAnimation = ( node - > objNode - > header . gfx . node . flags & GRAPH_RENDER_HAS_ANIMATION ) ! = 0 ;
2019-08-25 04:46:40 +00:00
translation [ 0 ] = node - > translation [ 0 ] / 4.0f ;
translation [ 1 ] = node - > translation [ 1 ] / 4.0f ;
translation [ 2 ] = node - > translation [ 2 ] / 4.0f ;
2020-07-29 01:28:12 +00:00
if ( gGlobalTimer = = node - > objNode - > header . gfx . prevScaleTimestamp + 1 ) {
2022-04-27 05:42:57 +00:00
vec3f_copy ( scalePrev , node - > objNode - > header . gfx . prevScale ) ;
2020-07-29 01:28:12 +00:00
} else {
2022-04-27 05:42:57 +00:00
vec3f_copy ( scalePrev , node - > objNode - > header . gfx . scale ) ;
2020-07-29 01:28:12 +00:00
}
vec3f_copy ( node - > objNode - > header . gfx . prevScale , node - > objNode - > header . gfx . scale ) ;
node - > objNode - > header . gfx . prevScaleTimestamp = gGlobalTimer ;
2019-08-25 04:46:40 +00:00
mtxf_translate ( mat , translation ) ;
2020-07-04 15:18:55 +00:00
mtxf_copy ( gMatStack [ gMatStackIndex + 1 ] , * gCurGraphNodeObject - > throwMatrix ) ;
2019-08-25 04:46:40 +00:00
gMatStack [ gMatStackIndex + 1 ] [ 3 ] [ 0 ] = gMatStack [ gMatStackIndex ] [ 3 ] [ 0 ] ;
gMatStack [ gMatStackIndex + 1 ] [ 3 ] [ 1 ] = gMatStack [ gMatStackIndex ] [ 3 ] [ 1 ] ;
gMatStack [ gMatStackIndex + 1 ] [ 3 ] [ 2 ] = gMatStack [ gMatStackIndex ] [ 3 ] [ 2 ] ;
mtxf_mul ( gMatStack [ gMatStackIndex + 1 ] , mat , gMatStack [ gMatStackIndex + 1 ] ) ;
2022-04-17 02:48:40 +00:00
mtxf_scale_vec3f ( gMatStack [ gMatStackIndex + 1 ] , gMatStack [ gMatStackIndex + 1 ] , node - > objNode - > header . gfx . scale ) ;
2022-04-27 05:42:57 +00:00
mtxf_copy ( gMatStackPrev [ gMatStackIndex + 1 ] , ( void * ) gCurGraphNodeObject - > throwMatrixPrev ) ;
2022-04-27 03:00:18 +00:00
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 ] ,
2022-04-27 05:42:57 +00:00
scalePrev ) ;
2019-09-01 19:50:50 +00:00
if ( node - > fnNode . func ! = NULL ) {
2023-05-13 01:53:25 +00:00
node - > fnNode . func ( GEO_CONTEXT_HELD_OBJ , & node - > fnNode . node , ( struct DynamicPool * ) gMatStack [ gMatStackIndex + 1 ] ) ;
2019-09-01 19:50:50 +00:00
}
2022-04-28 02:43:55 +00:00
2022-04-17 02:48:40 +00:00
// Increment the matrix stack, If we fail to do so. Just return.
if ( ! increment_mat_stack ( ) ) { return ; }
2022-04-28 02:43:55 +00:00
2019-08-25 04:46:40 +00:00
gGeoTempState . type = gCurAnimType ;
gGeoTempState . enabled = gCurAnimEnabled ;
gGeoTempState . frame = gCurrAnimFrame ;
gGeoTempState . translationMultiplier = gCurAnimTranslationMultiplier ;
gGeoTempState . attribute = gCurrAnimAttribute ;
gGeoTempState . data = gCurAnimData ;
2020-07-29 01:28:12 +00:00
gGeoTempState . prevFrame = gPrevAnimFrame ;
2019-08-25 04:46:40 +00:00
gCurAnimType = 0 ;
gCurGraphNodeHeldObject = ( void * ) node ;
2022-02-19 04:27:10 +00:00
if ( node - > objNode - > header . gfx . animInfo . curAnim ! = NULL ) {
2022-03-10 02:01:03 +00:00
dynos_gfx_swap_animations ( node - > objNode ) ;
2022-02-19 04:27:10 +00:00
geo_set_animation_globals ( & node - > objNode - > header . gfx . animInfo , hasAnimation ) ;
2023-04-28 23:56:18 +00:00
smlua_call_event_hooks_object_param ( HOOK_ON_OBJECT_ANIM_UPDATE , node - > objNode ) ;
2022-03-10 02:01:03 +00:00
dynos_gfx_swap_animations ( node - > objNode ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
2019-11-03 19:36:27 +00:00
geo_process_node_and_siblings ( node - > objNode - > header . gfx . sharedChild ) ;
2019-08-25 04:46:40 +00:00
gCurGraphNodeHeldObject = NULL ;
gCurAnimType = gGeoTempState . type ;
gCurAnimEnabled = gGeoTempState . enabled ;
gCurrAnimFrame = gGeoTempState . frame ;
gCurAnimTranslationMultiplier = gGeoTempState . translationMultiplier ;
gCurrAnimAttribute = gGeoTempState . attribute ;
gCurAnimData = gGeoTempState . data ;
2020-07-29 01:28:12 +00:00
gPrevAnimFrame = gGeoTempState . prevFrame ;
2019-08-25 04:46:40 +00:00
gMatStackIndex - - ;
}
2019-09-01 19:50:50 +00:00
if ( node - > fnNode . node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > fnNode . node . children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-09-01 19:50:50 +00:00
/**
* Processes the children of the given GraphNode if it has any
2019-08-25 04:46:40 +00:00
*/
void geo_try_process_children ( struct GraphNode * node ) {
2019-09-01 19:50:50 +00:00
if ( node - > children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > children ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2019-09-01 19:50:50 +00:00
/**
* Process a generic geo node and its siblings .
* The first argument is the start node , and all its siblings will
* be iterated over .
2019-08-25 04:46:40 +00:00
*/
void geo_process_node_and_siblings ( struct GraphNode * firstNode ) {
s16 iterateChildren = TRUE ;
struct GraphNode * curGraphNode = firstNode ;
2022-02-26 10:14:30 +00:00
if ( curGraphNode = = NULL ) { return ; }
2023-05-10 20:25:41 +00:00
u32 depthSanity = 0 ;
2022-02-26 10:14:30 +00:00
2019-08-25 04:46:40 +00:00
struct GraphNode * parent = curGraphNode - > parent ;
// In the case of a switch node, exactly one of the children of the node is
// processed instead of all children like usual
2019-09-01 19:50:50 +00:00
if ( parent ! = NULL ) {
2019-08-25 04:46:40 +00:00
iterateChildren = ( parent - > type ! = GRAPH_NODE_TYPE_SWITCH_CASE ) ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
do {
2022-02-26 10:14:30 +00:00
if ( curGraphNode = = NULL ) {
break ;
}
2023-05-10 20:25:41 +00:00
// Sanity check our stack index, If we above or equal to our stack size. Return to prevent OOB\.
if ( ( gMatStackIndex + 1 ) > = MATRIX_STACK_SIZE ) { break ; }
// Break out of endless loops
if ( + + depthSanity > 5000 ) { break ; }
2019-08-25 04:46:40 +00:00
if ( curGraphNode - > flags & GRAPH_RENDER_ACTIVE ) {
if ( curGraphNode - > flags & GRAPH_RENDER_CHILDREN_FIRST ) {
geo_try_process_children ( curGraphNode ) ;
} else {
switch ( curGraphNode - > type ) {
case GRAPH_NODE_TYPE_ORTHO_PROJECTION :
geo_process_ortho_projection ( ( struct GraphNodeOrthoProjection * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_PERSPECTIVE :
geo_process_perspective ( ( struct GraphNodePerspective * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_MASTER_LIST :
geo_process_master_list ( ( struct GraphNodeMasterList * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_LEVEL_OF_DETAIL :
geo_process_level_of_detail ( ( struct GraphNodeLevelOfDetail * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_SWITCH_CASE :
geo_process_switch ( ( struct GraphNodeSwitchCase * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_CAMERA :
geo_process_camera ( ( struct GraphNodeCamera * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_TRANSLATION_ROTATION :
geo_process_translation_rotation (
( struct GraphNodeTranslationRotation * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_TRANSLATION :
geo_process_translation ( ( struct GraphNodeTranslation * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_ROTATION :
geo_process_rotation ( ( struct GraphNodeRotation * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_OBJECT :
geo_process_object ( ( struct Object * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_ANIMATED_PART :
geo_process_animated_part ( ( struct GraphNodeAnimatedPart * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_BILLBOARD :
geo_process_billboard ( ( struct GraphNodeBillboard * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_DISPLAY_LIST :
geo_process_display_list ( ( struct GraphNodeDisplayList * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_SCALE :
geo_process_scale ( ( struct GraphNodeScale * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_SHADOW :
geo_process_shadow ( ( struct GraphNodeShadow * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_OBJECT_PARENT :
geo_process_object_parent ( ( struct GraphNodeObjectParent * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_GENERATED_LIST :
geo_process_generated_list ( ( struct GraphNodeGenerated * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_BACKGROUND :
geo_process_background ( ( struct GraphNodeBackground * ) curGraphNode ) ;
break ;
case GRAPH_NODE_TYPE_HELD_OBJ :
geo_process_held_object ( ( struct GraphNodeHeldObject * ) curGraphNode ) ;
break ;
default :
geo_try_process_children ( ( struct GraphNode * ) curGraphNode ) ;
break ;
}
}
} else {
2023-04-14 05:38:32 +00:00
if ( curGraphNode & & curGraphNode - > type = = GRAPH_NODE_TYPE_OBJECT ) {
2019-08-25 04:46:40 +00:00
( ( struct GraphNodeObject * ) curGraphNode ) - > throwMatrix = NULL ;
2019-09-01 19:50:50 +00:00
}
2019-08-25 04:46:40 +00:00
}
2022-04-23 08:12:12 +00:00
} while ( iterateChildren & & curGraphNode & & ( curGraphNode = curGraphNode - > next ) ! = firstNode ) ;
2019-08-25 04:46:40 +00:00
}
2023-04-21 04:56:37 +00:00
static void geo_clear_interp_variables ( void ) {
sPerspectiveNode = NULL ;
sPerspectivePos = NULL ;
sPerspectiveMtx = NULL ;
sPerspectiveAspect = 0 ;
sViewport = NULL ;
sViewportPos = NULL ;
sViewportClipPos = NULL ;
sBackgroundNode = NULL ;
gBackgroundSkyboxGfx = NULL ;
memset ( gBackgroundSkyboxVerts , 0 , sizeof ( Vtx * ) * 3 * 3 ) ;
gBackgroundSkyboxMtx = NULL ;
sBackgroundNodeRoot = NULL ;
gShadowInterpCurrent = NULL ;
sShadowInterpCount = 0 ;
sCameraNode = NULL ;
gMtxTblSize = 0 ;
gCurGraphNodeProcessingObject = NULL ;
gCurGraphNodeMarioState = NULL ;
}
2019-09-01 19:50:50 +00:00
/**
* Process a root node . This is the entry point for processing the scene graph .
* The root node itself sets up the viewport , then all its children are processed
* to set up the projection and draw display lists .
2019-08-25 04:46:40 +00:00
*/
void geo_process_root ( struct GraphNodeRoot * node , Vp * b , Vp * c , s32 clearColor ) {
2023-04-21 04:56:37 +00:00
// clear interp stuff
geo_clear_interp_variables ( ) ;
2019-08-25 04:46:40 +00:00
if ( node - > node . flags & GRAPH_RENDER_ACTIVE ) {
2023-05-13 01:53:25 +00:00
gDisplayListHeap = growing_pool_init ( gDisplayListHeap , DISPLAY_LIST_HEAP_SIZE ) ;
2023-05-12 23:15:35 +00:00
2019-08-25 04:46:40 +00:00
Vp * viewport = alloc_display_list ( sizeof ( * viewport ) ) ;
2022-04-07 01:10:22 +00:00
if ( viewport = = NULL ) { return ; }
2019-08-25 04:46:40 +00:00
2022-04-17 02:48:40 +00:00
Mtx * initialMatrix = alloc_display_list ( sizeof ( * initialMatrix ) ) ;
2022-04-07 01:10:22 +00:00
if ( initialMatrix = = NULL ) { return ; }
2022-04-28 02:43:55 +00:00
2019-08-25 04:46:40 +00:00
gMatStackIndex = 0 ;
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 ) ;
2022-04-27 03:00:18 +00:00
2019-08-25 04:46:40 +00:00
if ( b ! = NULL ) {
clear_frame_buffer ( clearColor ) ;
2020-07-29 01:28:12 +00:00
2022-04-27 03:00:18 +00:00
sViewportClipPos = gDisplayListHead ;
make_viewport_clip_rect ( & sViewportPrev ) ;
2019-08-25 04:46:40 +00:00
* viewport = * b ;
2022-04-17 02:48:40 +00:00
} else if ( c ! = NULL ) {
2019-08-25 04:46:40 +00:00
clear_frame_buffer ( clearColor ) ;
make_viewport_clip_rect ( c ) ;
}
mtxf_identity ( gMatStack [ gMatStackIndex ] ) ;
mtxf_to_mtx ( initialMatrix , gMatStack [ gMatStackIndex ] ) ;
gMatStackFixed [ gMatStackIndex ] = initialMatrix ;
2020-07-29 01:28:12 +00:00
2022-04-27 03:00:18 +00:00
sViewport = viewport ;
sViewportPos = gDisplayListHead ;
// vvv 60 FPS PATCH vvv
mtxf_identity ( gMatStackPrev [ gMatStackIndex ] ) ;
gMatStackPrevFixed [ gMatStackIndex ] = initialMatrix ;
// ^^^ ^^^
2020-07-29 01:28:12 +00:00
2022-04-27 03:00:18 +00:00
gSPViewport ( gDisplayListHead + + , VIRTUAL_TO_PHYSICAL ( & sViewportPrev ) ) ;
2022-04-17 02:48:40 +00:00
gSPMatrix ( gDisplayListHead + + , VIRTUAL_TO_PHYSICAL ( gMatStackFixed [ gMatStackIndex ] ) , G_MTX_MODELVIEW | G_MTX_LOAD | G_MTX_NOPUSH ) ;
2022-04-28 02:43:55 +00:00
2019-08-25 04:46:40 +00:00
gCurGraphNodeRoot = node ;
2019-09-01 19:50:50 +00:00
if ( node - > node . children ! = NULL ) {
2019-08-25 04:46:40 +00:00
geo_process_node_and_siblings ( node - > node . children ) ;
2019-09-01 19:50:50 +00:00
}
2023-05-13 01:53:25 +00:00
2019-08-25 04:46:40 +00:00
gCurGraphNodeRoot = NULL ;
}
2022-04-17 02:48:40 +00:00
}