From ee35d251f30ed07dc21ade0d1b6f11f6661fb57a Mon Sep 17 00:00:00 2001 From: rPhase Date: Tue, 30 Jun 2026 18:08:51 -0700 Subject: [PATCH 1/2] get_mario_anim_part_mtx --- autogen/lua_definitions/functions.lua | 9 +++++++++ autogen/lua_definitions/structs.lua | 1 + docs/lua/functions-7.md | 25 +++++++++++++++++++++++++ docs/lua/functions.md | 1 + docs/lua/structs.md | 1 + include/types.h | 1 + src/game/rendering_graph_node.c | 6 ++++-- src/pc/lua/smlua_cobject_autogen.c | 3 ++- src/pc/lua/smlua_functions_autogen.c | 26 ++++++++++++++++++++++++++ src/pc/lua/utils/smlua_misc_utils.c | 7 +++++++ src/pc/lua/utils/smlua_misc_utils.h | 4 ++++ 11 files changed, 81 insertions(+), 3 deletions(-) diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 49bc9496e..21a0e2888 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -12151,6 +12151,15 @@ function get_mario_anim_part_rot(m, animPart, rot) -- ... end +--- @param m MarioState +--- @param animPart integer +--- @param mtx Mat4 +--- @return boolean +--- Retrieves the animated part matrix associated to `animPart` from the MarioState `m` and stores it into `mtx`. Returns `true` on success or `false` on failure +function get_mario_anim_part_mtx(m, animPart, mtx) + -- ... +end + --- @return integer --- Gets the current save file number (1-indexed) function get_current_save_file_num() diff --git a/autogen/lua_definitions/structs.lua b/autogen/lua_definitions/structs.lua index 9468093ef..9489cfe05 100644 --- a/autogen/lua_definitions/structs.lua +++ b/autogen/lua_definitions/structs.lua @@ -1075,6 +1075,7 @@ --- @field public heldObjLastPosition Vec3f --- @field public animPartsPos Vec3f[] --- @field public animPartsRot Vec3s[] +--- @field public animPartsMtx Mat4[] --- @field public currAnimPart integer --- @field public updateTorsoTime integer --- @field public updateHeadPosTime integer diff --git a/docs/lua/functions-7.md b/docs/lua/functions-7.md index c786d0fed..3ea0d0673 100644 --- a/docs/lua/functions-7.md +++ b/docs/lua/functions-7.md @@ -3116,6 +3116,31 @@ Retrieves the animated part rotation associated to `animPart` from the MarioStat
+## [get_mario_anim_part_mtx](#get_mario_anim_part_mtx) + +### Description +Retrieves the animated part matrix associated to `animPart` from the MarioState `m` and stores it into `mtx`. Returns `true` on success or `false` on failure + +### Lua Example +`local booleanValue = get_mario_anim_part_mtx(m, animPart, mtx)` + +### Parameters +| Field | Type | +| ----- | ---- | +| m | [MarioState](structs.md#MarioState) | +| animPart | `integer` | +| mtx | [Mat4](structs.md#Mat4) | + +### Returns +- `boolean` + +### C Prototype +`bool get_mario_anim_part_mtx(struct MarioState *m, u32 animPart, VEC_OUT Mat4 mtx);` + +[:arrow_up_small:](#) + +
+ ## [get_current_save_file_num](#get_current_save_file_num) ### Description diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 78a6c299c..0c8e1ceb9 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -2071,6 +2071,7 @@ - [get_hand_foot_pos_z](functions-7.md#get_hand_foot_pos_z) - [get_mario_anim_part_pos](functions-7.md#get_mario_anim_part_pos) - [get_mario_anim_part_rot](functions-7.md#get_mario_anim_part_rot) + - [get_mario_anim_part_mtx](functions-7.md#get_mario_anim_part_mtx) - [get_current_save_file_num](functions-7.md#get_current_save_file_num) - [save_file_get_using_backup_slot](functions-7.md#save_file_get_using_backup_slot) - [save_file_set_using_backup_slot](functions-7.md#save_file_set_using_backup_slot) diff --git a/docs/lua/structs.md b/docs/lua/structs.md index e4318c5da..44d960bd1 100644 --- a/docs/lua/structs.md +++ b/docs/lua/structs.md @@ -1585,6 +1585,7 @@ | heldObjLastPosition | [Vec3f](structs.md#Vec3f) | read-only | | animPartsPos | `Array` <`Vec3f`> | read-only | | animPartsRot | `Array` <`Vec3s`> | read-only | +| animPartsMtx | `Array` <`Mat4`> | read-only | | currAnimPart | `integer` | read-only | | updateTorsoTime | `integer` | read-only | | updateHeadPosTime | `integer` | read-only | diff --git a/include/types.h b/include/types.h index 0feab5d95..976adbbe5 100644 --- a/include/types.h +++ b/include/types.h @@ -419,6 +419,7 @@ struct MarioBodyState Vec3f animPartsPos[MARIO_ANIM_PART_MAX]; Vec3s animPartsRot[MARIO_ANIM_PART_MAX]; + Mat4 animPartsMtx[MARIO_ANIM_PART_MAX]; u32 currAnimPart; u32 updateTorsoTime; diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 82d0da8f7..50d0b87fc 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -1203,7 +1203,7 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) { // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } - // Mario anim part pos and rot + // Mario anim part pos, rot, and matrix if (gCurMarioBodyState && !gCurGraphNodeHeldObject && gCurMarioBodyState->currAnimPart > MARIO_ANIM_PART_NONE && gCurMarioBodyState->currAnimPart < MARIO_ANIM_PART_MAX) { get_pos_from_transform_mtx( gCurMarioBodyState->animPartsPos[gCurMarioBodyState->currAnimPart], @@ -1213,6 +1213,7 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) { Vec3s rot = { rotation[2], rotation[0], rotation[1] }; vec3s_copy(gCurMarioBodyState->animPartsRot[gCurMarioBodyState->currAnimPart], rot); + mtxf_copy(gCurMarioBodyState->animPartsMtx[gCurMarioBodyState->currAnimPart], gMatStack[gMatStackIndex]); } if (gCurGraphNodeMarioState != NULL) { @@ -1861,7 +1862,7 @@ static void geo_process_bone(struct GraphNodeBone *node) { // Increment the matrix stack, If we fail to do so. Just return. if (!increment_mat_stack()) { return; } - // Mario anim part pos and rot + // Mario anim part pos, rot, and matrix if (gCurMarioBodyState && !gCurGraphNodeHeldObject && gCurMarioBodyState->currAnimPart > MARIO_ANIM_PART_NONE && gCurMarioBodyState->currAnimPart < MARIO_ANIM_PART_MAX) { get_pos_from_transform_mtx( gCurMarioBodyState->animPartsPos[gCurMarioBodyState->currAnimPart], @@ -1871,6 +1872,7 @@ static void geo_process_bone(struct GraphNodeBone *node) { Vec3s rot = { rotation[2], rotation[0], rotation[1] }; vec3s_copy(gCurMarioBodyState->animPartsRot[gCurMarioBodyState->currAnimPart], rot); + mtxf_copy(gCurMarioBodyState->animPartsMtx[gCurMarioBodyState->currAnimPart], gMatStack[gMatStackIndex]); } if (gCurGraphNodeMarioState != NULL) { diff --git a/src/pc/lua/smlua_cobject_autogen.c b/src/pc/lua/smlua_cobject_autogen.c index 389dc9729..c6dd0af77 100644 --- a/src/pc/lua/smlua_cobject_autogen.c +++ b/src/pc/lua/smlua_cobject_autogen.c @@ -1351,10 +1351,11 @@ static struct LuaObjectField sMarioAnimationFields[LUA_MARIO_ANIMATION_FIELD_COU { "targetAnim", LVT_COBJECT_P, offsetof(struct MarioAnimation, targetAnim), false, LOT_ANIMATION }, }; -#define LUA_MARIO_BODY_STATE_FIELD_COUNT 29 +#define LUA_MARIO_BODY_STATE_FIELD_COUNT 30 static struct LuaObjectField sMarioBodyStateFields[LUA_MARIO_BODY_STATE_FIELD_COUNT] = { { "action", LVT_U32, offsetof(struct MarioBodyState, action), false, LOT_NONE }, { "allowPartRotation", LVT_U8, offsetof(struct MarioBodyState, allowPartRotation), false, LOT_NONE }, + { "animPartsMtx", LVT_COBJECT, offsetof(struct MarioBodyState, animPartsMtx), true, LOT_MAT4, MARIO_ANIM_PART_MAX, sizeof(Mat4) }, { "animPartsPos", LVT_COBJECT, offsetof(struct MarioBodyState, animPartsPos), true, LOT_VEC3F, MARIO_ANIM_PART_MAX, sizeof(Vec3f) }, { "animPartsRot", LVT_COBJECT, offsetof(struct MarioBodyState, animPartsRot), true, LOT_VEC3S, MARIO_ANIM_PART_MAX, sizeof(Vec3s) }, { "capState", LVT_S8, offsetof(struct MarioBodyState, capState), false, LOT_NONE }, diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 1d2750281..91917e2f7 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -34250,6 +34250,31 @@ int smlua_func_get_mario_anim_part_rot(lua_State* L) { return 1; } +int smlua_func_get_mario_anim_part_mtx(lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 3) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "get_mario_anim_part_mtx", 3, top); + return 0; + } + + struct MarioState* m = (struct MarioState*)smlua_to_cobject(L, 1, LOT_MARIOSTATE); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "get_mario_anim_part_mtx"); return 0; } + u32 animPart = smlua_to_integer(L, 2); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "get_mario_anim_part_mtx"); return 0; } + + Mat4 mtx; + smlua_get_mat4(mtx, 3); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "get_mario_anim_part_mtx"); return 0; } + + lua_pushboolean(L, get_mario_anim_part_mtx(m, animPart, mtx)); + + smlua_push_mat4(mtx, 3); + + return 1; +} + int smlua_func_get_current_save_file_num(lua_State* L) { if (L == NULL) { return 0; } @@ -39164,6 +39189,7 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "get_hand_foot_pos_z", smlua_func_get_hand_foot_pos_z); smlua_bind_function(L, "get_mario_anim_part_pos", smlua_func_get_mario_anim_part_pos); smlua_bind_function(L, "get_mario_anim_part_rot", smlua_func_get_mario_anim_part_rot); + smlua_bind_function(L, "get_mario_anim_part_mtx", smlua_func_get_mario_anim_part_mtx); smlua_bind_function(L, "get_current_save_file_num", smlua_func_get_current_save_file_num); smlua_bind_function(L, "save_file_get_using_backup_slot", smlua_func_save_file_get_using_backup_slot); smlua_bind_function(L, "save_file_set_using_backup_slot", smlua_func_save_file_set_using_backup_slot); diff --git a/src/pc/lua/utils/smlua_misc_utils.c b/src/pc/lua/utils/smlua_misc_utils.c index eb4a98956..bbf9c8dfd 100644 --- a/src/pc/lua/utils/smlua_misc_utils.c +++ b/src/pc/lua/utils/smlua_misc_utils.c @@ -393,6 +393,13 @@ bool get_mario_anim_part_rot(struct MarioState *m, u32 animPart, VEC_OUT Vec3s r return true; } +bool get_mario_anim_part_mtx(struct MarioState *m, u32 animPart, VEC_OUT Mat4 mtx) { + if (!m) { return false; } + if (animPart >= MARIO_ANIM_PART_MAX) { return false; } + mtxf_copy(mtx, m->marioBodyState->animPartsMtx[animPart]); + return true; +} + /// s16 get_current_save_file_num(void) { diff --git a/src/pc/lua/utils/smlua_misc_utils.h b/src/pc/lua/utils/smlua_misc_utils.h index 7078396eb..c5d31a83a 100644 --- a/src/pc/lua/utils/smlua_misc_utils.h +++ b/src/pc/lua/utils/smlua_misc_utils.h @@ -178,6 +178,10 @@ bool get_mario_anim_part_pos(struct MarioState *m, u32 animPart, VEC_OUT Vec3f p Retrieves the animated part rotation associated to `animPart` from the MarioState `m` and stores it into `rot`. Returns `true` on success or `false` on failure |descriptionEnd| */ bool get_mario_anim_part_rot(struct MarioState *m, u32 animPart, VEC_OUT Vec3s rot); +/* |description| +Retrieves the animated part matrix associated to `animPart` from the MarioState `m` and stores it into `mtx`. Returns `true` on success or `false` on failure +|descriptionEnd| */ +bool get_mario_anim_part_mtx(struct MarioState *m, u32 animPart, VEC_OUT Mat4 mtx); /* |description|Gets the current save file number (1-indexed)|descriptionEnd| */ s16 get_current_save_file_num(void); From a3b0041b5ae1e629109b7df48e3d649345ccc855 Mon Sep 17 00:00:00 2001 From: rPhase Date: Sat, 4 Jul 2026 15:43:13 -0700 Subject: [PATCH 2/2] Remove camera transforms from animPartsMtx Added a helper function to remove camera transforms from model-view matrix to get a world-space matrix. Store world-space mario part matrices instead of model-view in `animPartsMtx`. This is for consistency with `animPartsPos` coordinate space. --- autogen/lua_definitions/functions.lua | 8 +++++++ docs/lua/functions-4.md | 25 ++++++++++++++++++++++ docs/lua/functions.md | 1 + src/engine/math_util.c | 13 ++++++++++++ src/engine/math_util.h | 4 ++++ src/game/rendering_graph_node.c | 14 +++++++++++-- src/pc/lua/smlua_functions_autogen.c | 30 +++++++++++++++++++++++++++ 7 files changed, 93 insertions(+), 2 deletions(-) diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 21a0e2888..9123e4015 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -7082,6 +7082,14 @@ function get_pos_from_transform_mtx(dest, objMtx, camMtx) -- ... end +--- @param dest Mat4 +--- @param objMtx Mat4 +--- @param camMtx Mat4 +--- Strip the camera-view matrix `camMtx` off of a model-view matrix `objMtx` and store the resulting matrix in `dest`. This can be used to get the object's transforms in world space. +function get_world_mtx_from_transform(dest, objMtx, camMtx) + -- ... +end + --- @param value number --- @param replacement number --- @return number diff --git a/docs/lua/functions-4.md b/docs/lua/functions-4.md index 114faf99d..11bef099b 100644 --- a/docs/lua/functions-4.md +++ b/docs/lua/functions-4.md @@ -5634,6 +5634,31 @@ Extracts the position (translation component) from the transformation matrix `ob
+## [get_world_mtx_from_transform](#get_world_mtx_from_transform) + +### Description +Strip the camera-view matrix `camMtx` off of a model-view matrix `objMtx` and store the resulting matrix in `dest`. This can be used to get the object's transforms in world space. + +### Lua Example +`get_world_mtx_from_transform(dest, objMtx, camMtx)` + +### Parameters +| Field | Type | +| ----- | ---- | +| dest | [Mat4](structs.md#Mat4) | +| objMtx | [Mat4](structs.md#Mat4) | +| camMtx | [Mat4](structs.md#Mat4) | + +### Returns +- None + +### C Prototype +`void get_world_mtx_from_transform(VEC_OUT Mat4 dest, Mat4 objMtx, Mat4 camMtx);` + +[:arrow_up_small:](#) + +
+ --- # functions from math_util.inl diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 0c8e1ceb9..35ac3c04e 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -1261,6 +1261,7 @@ - [mtxf_inverse](functions-4.md#mtxf_inverse) - [mtxf_inverse_non_affine](functions-4.md#mtxf_inverse_non_affine) - [get_pos_from_transform_mtx](functions-4.md#get_pos_from_transform_mtx) + - [get_world_mtx_from_transform](functions-4.md#get_world_mtx_from_transform)
diff --git a/src/engine/math_util.c b/src/engine/math_util.c index 04c4ad3d6..a04382331 100644 --- a/src/engine/math_util.c +++ b/src/engine/math_util.c @@ -883,3 +883,16 @@ OPTIMIZE_O3 Vec3fp get_pos_from_transform_mtx(VEC_OUT Vec3f dest, Mat4 objMtx, M return dest; } +/** + * Extract world-space transformations given an object's model-view matrix and a + * camera matrix. A model-view matrix generated during rendering is a combination + * of world-space and camera transforms to position and orient objects in a scene + * relative to the camera view. By multiplying this matrix with the inverse of the + * camera matrix, the camera transforms can be removed to get the position and + * orientation of an object relative to world-space. + */ +OPTIMIZE_O3 void get_world_mtx_from_transform(VEC_OUT Mat4 dest, Mat4 objMtx, Mat4 camMtx) { + Mat4 invCamMtx; + mtxf_inverse(invCamMtx, camMtx); + mtxf_mul(dest, objMtx, invCamMtx); +} \ No newline at end of file diff --git a/src/engine/math_util.h b/src/engine/math_util.h index 888a64adf..31adca783 100644 --- a/src/engine/math_util.h +++ b/src/engine/math_util.h @@ -291,5 +291,9 @@ Extracts the position (translation component) from the transformation matrix `ob |descriptionEnd| */ OPTIMIZE_O3 Vec3fp get_pos_from_transform_mtx(VEC_OUT Vec3f dest, Mat4 objMtx, Mat4 camMtx); +/* |description| +Strip the camera-view matrix `camMtx` off of a model-view matrix `objMtx` and store the resulting matrix in `dest`. This can be used to get the object's transforms in world space. +|descriptionEnd| */ +OPTIMIZE_O3 void get_world_mtx_from_transform(VEC_OUT Mat4 dest, Mat4 objMtx, Mat4 camMtx); #endif // MATH_UTIL_H diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 50d0b87fc..8f4394657 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -1213,7 +1213,12 @@ static void geo_process_animated_part(struct GraphNodeAnimatedPart *node) { Vec3s rot = { rotation[2], rotation[0], rotation[1] }; vec3s_copy(gCurMarioBodyState->animPartsRot[gCurMarioBodyState->currAnimPart], rot); - mtxf_copy(gCurMarioBodyState->animPartsMtx[gCurMarioBodyState->currAnimPart], gMatStack[gMatStackIndex]); + + get_world_mtx_from_transform( + gCurMarioBodyState->animPartsMtx[gCurMarioBodyState->currAnimPart], + gMatStack[gMatStackIndex], + *gCurGraphNodeCamera->matrixPtr + ); } if (gCurGraphNodeMarioState != NULL) { @@ -1872,7 +1877,12 @@ static void geo_process_bone(struct GraphNodeBone *node) { Vec3s rot = { rotation[2], rotation[0], rotation[1] }; vec3s_copy(gCurMarioBodyState->animPartsRot[gCurMarioBodyState->currAnimPart], rot); - mtxf_copy(gCurMarioBodyState->animPartsMtx[gCurMarioBodyState->currAnimPart], gMatStack[gMatStackIndex]); + + get_world_mtx_from_transform( + gCurMarioBodyState->animPartsMtx[gCurMarioBodyState->currAnimPart], + gMatStack[gMatStackIndex], + *gCurGraphNodeCamera->matrixPtr + ); } if (gCurGraphNodeMarioState != NULL) { diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 91917e2f7..b60c934aa 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -20321,6 +20321,35 @@ int smlua_func_get_pos_from_transform_mtx(lua_State* L) { return 1; } +int smlua_func_get_world_mtx_from_transform(lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 3) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "get_world_mtx_from_transform", 3, top); + return 0; + } + + + Mat4 dest; + smlua_get_mat4(dest, 1); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "get_world_mtx_from_transform"); return 0; } + + Mat4 objMtx; + smlua_get_mat4(objMtx, 2); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 2, "get_world_mtx_from_transform"); return 0; } + + Mat4 camMtx; + smlua_get_mat4(camMtx, 3); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 3, "get_world_mtx_from_transform"); return 0; } + + get_world_mtx_from_transform(dest, objMtx, camMtx); + + smlua_push_mat4(dest, 1); + + return 1; +} + /////////////////// // math_util.inl // /////////////////// @@ -38418,6 +38447,7 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "mtxf_inverse", smlua_func_mtxf_inverse); smlua_bind_function(L, "mtxf_inverse_non_affine", smlua_func_mtxf_inverse_non_affine); smlua_bind_function(L, "get_pos_from_transform_mtx", smlua_func_get_pos_from_transform_mtx); + smlua_bind_function(L, "get_world_mtx_from_transform", smlua_func_get_world_mtx_from_transform); // math_util.inl smlua_bind_function(L, "replace_value_if_not_zero", smlua_func_replace_value_if_not_zero);