From e79cbd155c0ef1953a6995a7297aea1a80ad5bcf Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Fri, 16 Jan 2026 00:22:31 -0500 Subject: [PATCH 1/2] Add Lara collision debug visualization --- src/trx/config/map.def | 1 + src/trx/config/types.h | 1 + src/trx/game/console/cmd/debug.c | 1 + src/trx/game/lara/control.c | 18 ++++++++++++++++++ src/trx/game/lara/draw.c | 21 +++++++++++++++++++++ src/trx/game/lara/types.h | 2 ++ 6 files changed, 44 insertions(+) diff --git a/src/trx/config/map.def b/src/trx/config/map.def index a05bd62f67..93c33474f0 100644 --- a/src/trx/config/map.def +++ b/src/trx/config/map.def @@ -7,6 +7,7 @@ X_CFG_BOOL(audio.enable_underwater_anim_sfx, true) X_CFG_BOOL(audio.fix_chainblock_secret_sound, true) X_CFG_BOOL(audio.mute_out_of_focus, true) X_CFG_BOOL(debug.enable_debug_camera, false) +X_CFG_BOOL(debug.enable_debug_lara_collision, false) X_CFG_BOOL(debug.enable_debug_cuboids, false) X_CFG_BOOL(debug.enable_debug_portals, false) X_CFG_BOOL(debug.enable_debug_pos, false) diff --git a/src/trx/config/types.h b/src/trx/config/types.h index 35ac76f1d9..bc0382e75c 100644 --- a/src/trx/config/types.h +++ b/src/trx/config/types.h @@ -277,6 +277,7 @@ typedef struct { bool enable_debug_room_clip; bool enable_debug_spheres; bool enable_debug_cuboids; + bool enable_debug_lara_collision; bool enable_debug_pos; bool enable_debug_camera; bool enable_review_markers; diff --git a/src/trx/game/console/cmd/debug.c b/src/trx/game/console/cmd/debug.c index 6d43cca173..049157575e 100644 --- a/src/trx/game/console/cmd/debug.c +++ b/src/trx/game/console/cmd/debug.c @@ -17,6 +17,7 @@ static DEBUG_OPTION_ENTRY m_AllOptions[] = { { &g_Config.debug.enable_debug_triggers, nullptr }, { &g_Config.debug.enable_debug_spheres, nullptr }, { &g_Config.debug.enable_debug_cuboids, nullptr }, + { &g_Config.debug.enable_debug_lara_collision, nullptr }, { &g_Config.debug.enable_debug_pos, nullptr }, { &g_Config.debug.enable_debug_camera, nullptr }, { nullptr, nullptr } diff --git a/src/trx/game/lara/control.c b/src/trx/game/lara/control.c index 3d10eca53a..3c0ff738de 100644 --- a/src/trx/game/lara/control.c +++ b/src/trx/game/lara/control.c @@ -42,6 +42,14 @@ static int32_t m_OpenDoorsCheatCooldown = 0; extern bool Skidoo_Control(void); extern bool QuadBike_Control(void); +static void M_UpdateDebugCollision( + const COLL_INFO *const coll, const int32_t height) +{ + LARA_INFO *const lara_info = Lara_GetLaraInfo(); + lara_info->debug_collision_radius = coll->radius; + lara_info->debug_collision_height = height; +} + static SECTOR *M_GetCurrentSector(void) { const ITEM *const lara_item = Lara_GetItem(); @@ -476,22 +484,30 @@ static void M_HandleAboveWater(COLL_INFO *const coll) switch (vehicle->object_id) { case O_SKIDOO_FAST: if (Skidoo_Control()) { + M_UpdateDebugCollision(coll, 0); return; } break; case O_QUAD_BIKE: if (QuadBike_Control()) { + M_UpdateDebugCollision(coll, 0); return; } break; default: Gun_Control(); + M_UpdateDebugCollision(coll, 0); return; } } lara_info->is_crouched = false; Lara_State_Update(item, coll); + M_UpdateDebugCollision( + coll, + (lara_info->is_crouched || lara_info->keep_crouched) + ? LARA_HEIGHT_CROUCH + : LARA_HEIGHT); if (item->rot.z < -LARA_LEAN_UNDO) { item->rot.z += LARA_LEAN_UNDO; @@ -545,6 +561,7 @@ static void M_HandleUnderwater(COLL_INFO *const coll) Lara_Look_Update(); Lara_State_Update(item, coll); + M_UpdateDebugCollision(coll, LARA_HEIGHT_UW); if (item->rot.z > M_LEAN_UNDO_UW) { item->rot.z -= M_LEAN_UNDO_UW; @@ -633,6 +650,7 @@ static void M_HandleSurface(COLL_INFO *const coll) Lara_Look_Update(); Lara_State_Update(item, coll); + M_UpdateDebugCollision(coll, LARA_HEIGHT_UW); if (item->rot.z > M_LEAN_UNDO_SURF) { item->rot.z -= M_LEAN_UNDO_SURF; diff --git a/src/trx/game/lara/draw.c b/src/trx/game/lara/draw.c index 04cd6145b0..189b023336 100644 --- a/src/trx/game/lara/draw.c +++ b/src/trx/game/lara/draw.c @@ -14,6 +14,21 @@ static bool m_CacheMatrices = false; +static void M_DrawCollisionBounds(const LARA_INFO *const lara) +{ + if (lara->debug_collision_radius <= 0 || lara->debug_collision_height <= 0) { + return; + } + + const int16_t radius = (int16_t)lara->debug_collision_radius; + const int16_t height = (int16_t)lara->debug_collision_height; + const BOUNDS_16 bounds = { + .min = { .x = -radius, .y = -height, .z = -radius }, + .max = { .x = radius, .y = 0, .z = radius }, + }; + Output_DrawCuboid(&bounds); +} + static void M_CacheMatrix(const LARA_MESH mesh) { if (!m_CacheMatrices) { @@ -124,6 +139,9 @@ static bool M_Draw_I( if (g_Config.debug.enable_debug_cuboids) { Output_DrawCuboid(&frame1->bounds); } + if (is_lara && g_Config.debug.enable_debug_lara_collision) { + M_DrawCollisionBounds(lara); + } m_CacheMatrices = is_lara; if (m_CacheMatrices) { @@ -422,6 +440,9 @@ bool Lara_Draw(const ITEM *const item) if (g_Config.debug.enable_debug_cuboids) { Output_DrawCuboid(&frame->bounds); } + if (is_lara && g_Config.debug.enable_debug_lara_collision) { + M_DrawCollisionBounds(lara); + } m_CacheMatrices = is_lara; if (m_CacheMatrices) { diff --git a/src/trx/game/lara/types.h b/src/trx/game/lara/types.h index b5ca772765..08b980e529 100644 --- a/src/trx/game/lara/types.h +++ b/src/trx/game/lara/types.h @@ -111,6 +111,8 @@ typedef struct { MATRIX mesh_pos_matrices[LM_NUMBER_OF]; bool mesh_pos_matrices_valid; + int32_t debug_collision_radius; + int32_t debug_collision_height; // TR3: persistent gun smoke spawned from muzzle after firing. int32_t tr3_smoke_count_l; From 742734b997541f97a1c590f91475a55d5e5c2e59 Mon Sep 17 00:00:00 2001 From: walkawayy <81546780+walkawayy@users.noreply.github.com> Date: Sat, 17 Jan 2026 11:36:02 -0500 Subject: [PATCH 2/2] Clean up and fix debug collision --- src/trx/config/map.def | 2 +- src/trx/config/types.h | 2 +- src/trx/game/collision.c | 20 +++++++++++++------ src/trx/game/console/cmd/debug.c | 2 +- src/trx/game/lara/control.c | 18 ----------------- src/trx/game/lara/draw.c | 34 +++++++++++++++++--------------- src/trx/game/lara/types.h | 10 ++++++++-- src/trx/game/output/draw.c | 9 +++++++++ src/trx/game/output/draw.h | 1 + 9 files changed, 53 insertions(+), 45 deletions(-) diff --git a/src/trx/config/map.def b/src/trx/config/map.def index 93c33474f0..8bf68b96d7 100644 --- a/src/trx/config/map.def +++ b/src/trx/config/map.def @@ -7,7 +7,7 @@ X_CFG_BOOL(audio.enable_underwater_anim_sfx, true) X_CFG_BOOL(audio.fix_chainblock_secret_sound, true) X_CFG_BOOL(audio.mute_out_of_focus, true) X_CFG_BOOL(debug.enable_debug_camera, false) -X_CFG_BOOL(debug.enable_debug_lara_collision, false) +X_CFG_BOOL(debug.enable_debug_collision, false) X_CFG_BOOL(debug.enable_debug_cuboids, false) X_CFG_BOOL(debug.enable_debug_portals, false) X_CFG_BOOL(debug.enable_debug_pos, false) diff --git a/src/trx/config/types.h b/src/trx/config/types.h index bc0382e75c..7fb4e2f9c5 100644 --- a/src/trx/config/types.h +++ b/src/trx/config/types.h @@ -277,7 +277,7 @@ typedef struct { bool enable_debug_room_clip; bool enable_debug_spheres; bool enable_debug_cuboids; - bool enable_debug_lara_collision; + bool enable_debug_collision; bool enable_debug_pos; bool enable_debug_camera; bool enable_review_markers; diff --git a/src/trx/game/collision.c b/src/trx/game/collision.c index 94b3ab0c85..3cdeb3c4c4 100644 --- a/src/trx/game/collision.c +++ b/src/trx/game/collision.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -25,7 +26,7 @@ static bool M_IsOnWalkable( static void M_FillSide( const COLL_INFO *const coll, COLL_SIDE *const side, const int32_t x_pos, const int32_t z_pos, const int32_t y_pos, const int32_t obj_height, - int16_t *const room_num) + int16_t *const room_num, int32_t sphere_num) { const int32_t y = y_pos - obj_height; const int32_t y_top = y - M_HEADROOM; @@ -76,6 +77,13 @@ static void M_FillSide( side->floor = NO_HEIGHT; side->ceiling = NO_HEIGHT; } + + if (g_Config.debug.enable_debug_collision) { + LARA_INFO *const lara = Lara_GetLaraInfo(); + const XYZ_32 pos = { .x = x_pos, .y = y_pos, .z = z_pos }; + const DEBUG_COLLISION_SPHERE sphere = { .pos = pos, coll->radius }; + lara->debug_collision[sphere_num] = sphere; + } } int32_t Collide_GetSpheres( @@ -321,24 +329,24 @@ void Collide_GetCollisionInfo( M_FillSide( coll, &coll->side_front, x_pos + x_front, z_pos + z_front, y_pos, - obj_height, &room_num); + obj_height, &room_num, 0); int16_t room_num2; room_num2 = prev_room_num; M_FillSide( coll, &coll->side_left, x_pos + x_left, z_pos + z_left, y_pos, - obj_height, &room_num2); + obj_height, &room_num2, 1); room_num2 = prev_room_num; M_FillSide( coll, &coll->side_right, x_pos + x_right, z_pos + z_right, y_pos, - obj_height, &room_num2); + obj_height, &room_num2, 2); M_FillSide( coll, &coll->side_left2, x_pos + x_left, z_pos + z_left, y_pos, - obj_height, &room_num); + obj_height, &room_num, 3); M_FillSide( coll, &coll->side_right2, x_pos + x_right, z_pos + z_right, y_pos, - obj_height, &room_num); + obj_height, &room_num, 4); const int16_t static_room_num = g_TRVersion >= 3 ? prev_room_num : room_num; if (Collide_CollideStaticObjects( diff --git a/src/trx/game/console/cmd/debug.c b/src/trx/game/console/cmd/debug.c index 049157575e..0854202865 100644 --- a/src/trx/game/console/cmd/debug.c +++ b/src/trx/game/console/cmd/debug.c @@ -17,7 +17,7 @@ static DEBUG_OPTION_ENTRY m_AllOptions[] = { { &g_Config.debug.enable_debug_triggers, nullptr }, { &g_Config.debug.enable_debug_spheres, nullptr }, { &g_Config.debug.enable_debug_cuboids, nullptr }, - { &g_Config.debug.enable_debug_lara_collision, nullptr }, + { &g_Config.debug.enable_debug_collision, nullptr }, { &g_Config.debug.enable_debug_pos, nullptr }, { &g_Config.debug.enable_debug_camera, nullptr }, { nullptr, nullptr } diff --git a/src/trx/game/lara/control.c b/src/trx/game/lara/control.c index 3c0ff738de..3d10eca53a 100644 --- a/src/trx/game/lara/control.c +++ b/src/trx/game/lara/control.c @@ -42,14 +42,6 @@ static int32_t m_OpenDoorsCheatCooldown = 0; extern bool Skidoo_Control(void); extern bool QuadBike_Control(void); -static void M_UpdateDebugCollision( - const COLL_INFO *const coll, const int32_t height) -{ - LARA_INFO *const lara_info = Lara_GetLaraInfo(); - lara_info->debug_collision_radius = coll->radius; - lara_info->debug_collision_height = height; -} - static SECTOR *M_GetCurrentSector(void) { const ITEM *const lara_item = Lara_GetItem(); @@ -484,30 +476,22 @@ static void M_HandleAboveWater(COLL_INFO *const coll) switch (vehicle->object_id) { case O_SKIDOO_FAST: if (Skidoo_Control()) { - M_UpdateDebugCollision(coll, 0); return; } break; case O_QUAD_BIKE: if (QuadBike_Control()) { - M_UpdateDebugCollision(coll, 0); return; } break; default: Gun_Control(); - M_UpdateDebugCollision(coll, 0); return; } } lara_info->is_crouched = false; Lara_State_Update(item, coll); - M_UpdateDebugCollision( - coll, - (lara_info->is_crouched || lara_info->keep_crouched) - ? LARA_HEIGHT_CROUCH - : LARA_HEIGHT); if (item->rot.z < -LARA_LEAN_UNDO) { item->rot.z += LARA_LEAN_UNDO; @@ -561,7 +545,6 @@ static void M_HandleUnderwater(COLL_INFO *const coll) Lara_Look_Update(); Lara_State_Update(item, coll); - M_UpdateDebugCollision(coll, LARA_HEIGHT_UW); if (item->rot.z > M_LEAN_UNDO_UW) { item->rot.z -= M_LEAN_UNDO_UW; @@ -650,7 +633,6 @@ static void M_HandleSurface(COLL_INFO *const coll) Lara_Look_Update(); Lara_State_Update(item, coll); - M_UpdateDebugCollision(coll, LARA_HEIGHT_UW); if (item->rot.z > M_LEAN_UNDO_SURF) { item->rot.z -= M_LEAN_UNDO_SURF; diff --git a/src/trx/game/lara/draw.c b/src/trx/game/lara/draw.c index 189b023336..9519e5f9fa 100644 --- a/src/trx/game/lara/draw.c +++ b/src/trx/game/lara/draw.c @@ -14,19 +14,15 @@ static bool m_CacheMatrices = false; -static void M_DrawCollisionBounds(const LARA_INFO *const lara) +static void M_DrawCollisionBounds( + const LARA_INFO *const lara, int32_t sphere_num) { - if (lara->debug_collision_radius <= 0 || lara->debug_collision_height <= 0) { - return; - } - - const int16_t radius = (int16_t)lara->debug_collision_radius; - const int16_t height = (int16_t)lara->debug_collision_height; - const BOUNDS_16 bounds = { - .min = { .x = -radius, .y = -height, .z = -radius }, - .max = { .x = radius, .y = 0, .z = radius }, - }; - Output_DrawCuboid(&bounds); + Matrix_PushUnit(); + Matrix_TranslateAbs32(lara->debug_collision[sphere_num].pos); + Output_DrawSphereAbs32( + lara->debug_collision[sphere_num].pos, + lara->debug_collision[sphere_num].radius); + Matrix_Pop(); } static void M_CacheMatrix(const LARA_MESH mesh) @@ -139,8 +135,11 @@ static bool M_Draw_I( if (g_Config.debug.enable_debug_cuboids) { Output_DrawCuboid(&frame1->bounds); } - if (is_lara && g_Config.debug.enable_debug_lara_collision) { - M_DrawCollisionBounds(lara); + + if (g_Config.debug.enable_debug_collision) { + for (int i = 0; i < DEBUG_COLL_SPHERES_MAX; i++) { + M_DrawCollisionBounds(lara, i); + } } m_CacheMatrices = is_lara; @@ -440,8 +439,11 @@ bool Lara_Draw(const ITEM *const item) if (g_Config.debug.enable_debug_cuboids) { Output_DrawCuboid(&frame->bounds); } - if (is_lara && g_Config.debug.enable_debug_lara_collision) { - M_DrawCollisionBounds(lara); + + if (g_Config.debug.enable_debug_collision) { + for (int i = 0; i < 5; i++) { + M_DrawCollisionBounds(lara, i); + } } m_CacheMatrices = is_lara; diff --git a/src/trx/game/lara/types.h b/src/trx/game/lara/types.h index 08b980e529..d89d4c9fd8 100644 --- a/src/trx/game/lara/types.h +++ b/src/trx/game/lara/types.h @@ -9,6 +9,13 @@ #include #include +#define DEBUG_COLL_SPHERES_MAX 5 + +typedef struct { + XYZ_32 pos; // world space + int32_t radius; // world units +} DEBUG_COLLISION_SPHERE; + typedef struct { ANIM_FRAME *frame_base; int16_t frame_num; @@ -111,8 +118,7 @@ typedef struct { MATRIX mesh_pos_matrices[LM_NUMBER_OF]; bool mesh_pos_matrices_valid; - int32_t debug_collision_radius; - int32_t debug_collision_height; + DEBUG_COLLISION_SPHERE debug_collision[DEBUG_COLL_SPHERES_MAX]; // TR3: persistent gun smoke spawned from muzzle after firing. int32_t tr3_smoke_count_l; diff --git a/src/trx/game/output/draw.c b/src/trx/game/output/draw.c index df41522747..ec6880ca64 100644 --- a/src/trx/game/output/draw.c +++ b/src/trx/game/output/draw.c @@ -403,6 +403,15 @@ void Output_DrawSphere(const XYZ_16 center, const int32_t radius) Matrix_Pop(); } +void Output_DrawSphereAbs32(const XYZ_32 center, const int32_t radius) +{ + Matrix_PushUnit(); + Matrix_TranslateAbs32(center); + Matrix_Scale(radius << W2V_SHIFT); + OutputSource_Misc_StageSphere(); + Matrix_Pop(); +} + void Output_DrawCuboid(const BOUNDS_16 *const bounds) { const int32_t x0 = bounds->min.x; diff --git a/src/trx/game/output/draw.h b/src/trx/game/output/draw.h index a1c171e4ae..16332831c1 100644 --- a/src/trx/game/output/draw.h +++ b/src/trx/game/output/draw.h @@ -33,4 +33,5 @@ void Output_DrawScreenFrame( RGBA_8888 col_light, float thickness); void Output_DrawSphere(XYZ_16 center, int32_t radius); +void Output_DrawSphereAbs32(XYZ_32 center, int32_t radius); void Output_DrawCuboid(const BOUNDS_16 *bounds);