From 967d12050562a54911afbb31fae51ff32387fed2 Mon Sep 17 00:00:00 2001 From: Isaac0-dev <62234577+Isaac0-dev@users.noreply.github.com> Date: Sat, 16 May 2026 11:13:02 +1000 Subject: [PATCH] much further draw distance option (#1240) The existing draw distance options don't actually increase the draw distance. It only impacts whether or not distant objects are rendered. This PR: - Adds another option to the draw distance setting in the display menu, called "Infinite". It is not truly infinite, but it is significantly larger than what current options allow. Due to it not being truly infinite, we could use the name "Max" instead to be more accurate. - Exposes a new function to the Lua API `draw_distance_scalar_is_infinite` which returns whether or not the infinite setting is enabled. - `draw_distance_scalar_is_infinite` is now used in several places in this repo to bypass distance checks for objects if infinite mode is enabled. - Fixes a bug where you couldn't bypass the distance check in `obj_is_in_view`, meaning you could never disable all object distance culling. - The infinite setting now forces the far plane to be at least a minimum of `1,000,000`. --- autogen/lua_definitions/functions.lua | 6 ++++++ docs/lua/functions-3.md | 21 +++++++++++++++++++++ docs/lua/functions.md | 1 + lang/Czech.ini | 1 + lang/Dutch.ini | 1 + lang/English.ini | 1 + lang/French.ini | 1 + lang/German.ini | 1 + lang/Italian.ini | 1 + lang/Japanese.ini | 1 + lang/Polish.ini | 1 + lang/Portuguese.ini | 1 + lang/Russian.ini | 1 + lang/Spanish.ini | 1 + src/engine/behavior_script.c | 11 ++++++++++- src/engine/behavior_script.h | 2 ++ src/engine/surface_load.c | 4 +++- src/game/behaviors/king_bobomb.inc.c | 6 +++++- src/game/behaviors/piranha_plant.inc.c | 14 +++++++++----- src/game/behaviors/whirlpool.inc.c | 10 +++++++--- src/game/obj_behaviors.c | 4 ++++ src/game/object_helpers.c | 4 +++- src/game/rendering_graph_node.c | 14 ++++++++++++-- src/pc/configfile.c | 2 +- src/pc/djui/djui_panel_display.c | 12 ++++++++++-- src/pc/lua/smlua_functions_autogen.c | 16 ++++++++++++++++ 26 files changed, 121 insertions(+), 17 deletions(-) diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index 925623f9f..e8258f161 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -2997,6 +2997,12 @@ function position_based_random_float_position() -- ... end +--- @return boolean +--- Checks if the draw distance scalar is infinite +function draw_distance_scalar_is_infinite() + -- ... +end + --- @return number --- Gets the draw distance scalar function draw_distance_scalar() diff --git a/docs/lua/functions-3.md b/docs/lua/functions-3.md index 2aab0ab14..ec32aed47 100644 --- a/docs/lua/functions-3.md +++ b/docs/lua/functions-3.md @@ -139,6 +139,27 @@ Sets the current object's position to random floats between 0.0 and 1.0
+## [draw_distance_scalar_is_infinite](#draw_distance_scalar_is_infinite) + +### Description +Checks if the draw distance scalar is infinite + +### Lua Example +`local booleanValue = draw_distance_scalar_is_infinite()` + +### Parameters +- None + +### Returns +- `boolean` + +### C Prototype +`bool draw_distance_scalar_is_infinite(void);` + +[:arrow_up_small:](#) + +
+ ## [draw_distance_scalar](#draw_distance_scalar) ### Description diff --git a/docs/lua/functions.md b/docs/lua/functions.md index bb2cd05d3..24dc305d0 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -623,6 +623,7 @@ - [obj_update_gfx_pos_and_angle](functions-3.md#obj_update_gfx_pos_and_angle) - [position_based_random_u16](functions-3.md#position_based_random_u16) - [position_based_random_float_position](functions-3.md#position_based_random_float_position) + - [draw_distance_scalar_is_infinite](functions-3.md#draw_distance_scalar_is_infinite) - [draw_distance_scalar](functions-3.md#draw_distance_scalar)
diff --git a/lang/Czech.ini b/lang/Czech.ini index e025a5e4e..21934b00a 100644 --- a/lang/Czech.ini +++ b/lang/Czech.ini @@ -167,6 +167,7 @@ D1P5X = "1.5x" D3X = "3x" D10X = "10x" D100X = "100x" +INFINITE = "Nekonečno" DRAW_DISTANCE = "Vzdálenost vykreslování" DYNOS_PACKS = "DynOS packy" ANTIALIASING = "Anti-aliasing" diff --git a/lang/Dutch.ini b/lang/Dutch.ini index dc22bb586..3e4cbe5eb 100644 --- a/lang/Dutch.ini +++ b/lang/Dutch.ini @@ -167,6 +167,7 @@ D1P5X = "1.5x" D3X = "3x" D10X = "10x" D100X = "100x" +INFINITE = "Oneindig" DRAW_DISTANCE = "Teken afstand" DYNOS_PACKS = "DynOS Packs" ANTIALIASING = "Anti-aliasing" diff --git a/lang/English.ini b/lang/English.ini index 3a0061d4d..0e51e68d9 100644 --- a/lang/English.ini +++ b/lang/English.ini @@ -167,6 +167,7 @@ D1P5X = "1.5x" D3X = "3x" D10X = "10x" D100X = "100x" +INFINITE = "Infinite" DRAW_DISTANCE = "Draw Distance" DYNOS_PACKS = "DynOS Packs" ANTIALIASING = "Anti-aliasing" diff --git a/lang/French.ini b/lang/French.ini index 863306e82..2f8cf7143 100644 --- a/lang/French.ini +++ b/lang/French.ini @@ -167,6 +167,7 @@ D1P5X = "x1.5" D3X = "x3" D10X = "x10" D100X = "x100" +INFINITE = "Infini" DRAW_DISTANCE = "Distance d'affichage" DYNOS_PACKS = "Packs DynOS" ANTIALIASING = "Anti-aliasing" diff --git a/lang/German.ini b/lang/German.ini index 90127de7b..9a2c3da44 100644 --- a/lang/German.ini +++ b/lang/German.ini @@ -167,6 +167,7 @@ D1P5X = "1.5x" D3X = "3x" D10X = "10x" D100X = "100x" +INFINITE = "Unendlich" DRAW_DISTANCE = "Sichtweite" DYNOS_PACKS = "DynOS-Pakete" ANTIALIASING = "Kantenglättung" diff --git a/lang/Italian.ini b/lang/Italian.ini index 3f75a5686..ee36b2939 100644 --- a/lang/Italian.ini +++ b/lang/Italian.ini @@ -165,6 +165,7 @@ D1P5X = "1.5x" D3X = "3x" D10X = "10x" D100X = "100x" +INFINITE = "Infinito" DRAW_DISTANCE = "Distanza di Simulazione" DYNOS_PACKS = "Pacchetti DynOS" ANTIALIASING = "Anti-aliasing" diff --git a/lang/Japanese.ini b/lang/Japanese.ini index 06a9e2800..e9d1e125b 100644 --- a/lang/Japanese.ini +++ b/lang/Japanese.ini @@ -167,6 +167,7 @@ D1P5X = "1.5x" D3X = "3x" D10X = "10x" D100X = "100x" +INFINITE = "無限" DRAW_DISTANCE = "描画距離" DYNOS_PACKS = "DynOSパック" ANTIALIASING = "アンチエイリアス" diff --git a/lang/Polish.ini b/lang/Polish.ini index 0989080ad..571b35444 100644 --- a/lang/Polish.ini +++ b/lang/Polish.ini @@ -167,6 +167,7 @@ D1P5X = "1,5x" D3X = "3x" D10X = "10x" D100X = "100x" +INFINITE = "Nieskończony" DRAW_DISTANCE = "Odległość Renderowania" DYNOS_PACKS = "Paczki DynOS" ANTIALIASING = "Anti-aliasing" diff --git a/lang/Portuguese.ini b/lang/Portuguese.ini index 750f6cb5c..275ff2b02 100644 --- a/lang/Portuguese.ini +++ b/lang/Portuguese.ini @@ -167,6 +167,7 @@ D1P5X = "1.5x" D3X = "3x" D10X = "10x" D100X = "100x" +INFINITE = "Infinito" DRAW_DISTANCE = "Distância de renderização" DYNOS_PACKS = "Pacotes DynOS" ANTIALIASING = "Antisserrilhamento" diff --git a/lang/Russian.ini b/lang/Russian.ini index f04fdbd49..569f7ee33 100644 --- a/lang/Russian.ini +++ b/lang/Russian.ini @@ -166,6 +166,7 @@ D1P5X = "1.5x" D3X = "3x" D10X = "10x" D100X = "100x" +INFINITE = "Бесконечный" DRAW_DISTANCE = "Дальность прорисовки" DYNOS_PACKS = "Пакеты DynOS" ANTIALIASING = "Анизотропная фильтрация" diff --git a/lang/Spanish.ini b/lang/Spanish.ini index b0129ad60..f525ea49b 100644 --- a/lang/Spanish.ini +++ b/lang/Spanish.ini @@ -167,6 +167,7 @@ D1P5X = "1.5x" D3X = "3x" D10X = "10x" D100X = "100x" +INFINITE = "Infinito" DRAW_DISTANCE = "Distancia de dibujado" DYNOS_PACKS = "Packs DynOS" ANTIALIASING = "Anti-aliasing" diff --git a/src/engine/behavior_script.c b/src/engine/behavior_script.c index 054e773f4..316b5b82d 100644 --- a/src/engine/behavior_script.c +++ b/src/engine/behavior_script.c @@ -1438,7 +1438,9 @@ cur_obj_update_begin:; } else if ((objFlags & OBJ_FLAG_COMPUTE_DIST_TO_MARIO) && gCurrentObject->collisionData == NULL) { if (!(objFlags & OBJ_FLAG_ACTIVE_FROM_AFAR)) { // If the object has a render distance, check if it should be shown. - if (distanceFromMario > gCurrentObject->oDrawingDistance * draw_distance_scalar()) { + if (!draw_distance_scalar_is_infinite() && + distanceFromMario > gCurrentObject->oDrawingDistance * draw_distance_scalar() + ) { // Out of render distance, hide the object. gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE; @@ -1486,6 +1488,13 @@ f32 position_based_random_float_position(void) { return rnd / (double)0x10000; } +bool draw_distance_scalar_is_infinite(void) { + if (!gBehaviorValues.InfiniteRenderDistance) { + return false; + } + return configDrawDistance == 6; // Expecting this to be "Infinite" +} + f32 draw_distance_scalar(void) { if (!gBehaviorValues.InfiniteRenderDistance) { return 1.0f; } diff --git a/src/engine/behavior_script.h b/src/engine/behavior_script.h index c3af4e0ed..43b0769d2 100644 --- a/src/engine/behavior_script.h +++ b/src/engine/behavior_script.h @@ -37,6 +37,8 @@ void obj_update_gfx_pos_and_angle(struct Object *obj); u16 position_based_random_u16(void); /* |description|Sets the current object's position to random floats between 0.0 and 1.0|descriptionEnd| */ f32 position_based_random_float_position(void); +/* |description|Checks if the draw distance scalar is infinite|descriptionEnd| */ +bool draw_distance_scalar_is_infinite(void); /* |description|Gets the draw distance scalar|descriptionEnd| */ f32 draw_distance_scalar(void); diff --git a/src/engine/surface_load.c b/src/engine/surface_load.c index c611750b0..5fbda2faf 100644 --- a/src/engine/surface_load.c +++ b/src/engine/surface_load.c @@ -1045,7 +1045,9 @@ static void load_object_collision_model_internal(bool isSOC) { if (!isSOC) { f32 marioDist = dist_between_objects(gCurrentObject, gMarioStates[0].marioObj); - if (marioDist < gCurrentObject->oDrawingDistance * draw_distance_scalar()) { + if (draw_distance_scalar_is_infinite() || + marioDist < gCurrentObject->oDrawingDistance * draw_distance_scalar() + ) { gCurrentObject->header.gfx.node.flags |= GRAPH_RENDER_ACTIVE; } else { gCurrentObject->header.gfx.node.flags &= ~GRAPH_RENDER_ACTIVE; diff --git a/src/game/behaviors/king_bobomb.inc.c b/src/game/behaviors/king_bobomb.inc.c index 80945aca1..0ff0d7b56 100644 --- a/src/game/behaviors/king_bobomb.inc.c +++ b/src/game/behaviors/king_bobomb.inc.c @@ -230,7 +230,7 @@ void king_bobomb_act_7(void) { void king_bobomb_act_8(void) { if (!(o->header.gfx.node.flags & GRAPH_RENDER_INVISIBLE)) { struct Object *star = NULL; - + create_sound_spawner(SOUND_OBJ_KING_WHOMP_DEATH); cur_obj_hide(); cur_obj_become_intangible(); @@ -367,6 +367,10 @@ void king_bobomb_move(void) { cur_obj_move_using_fvel_and_gravity(); CUR_OBJ_CALL_ACTION_FUNCTION(sKingBobombActions); exec_anim_sound_state(sKingBobombSoundStates, sizeof(sKingBobombSoundStates) / sizeof(struct SoundState)); + if (draw_distance_scalar_is_infinite()) { + cur_obj_enable_rendering(); + return; + } s32 distanceToPlayer = dist_between_objects(o, gMarioStates[0].marioObj); if (distanceToPlayer < 5000.0f * draw_distance_scalar()) cur_obj_enable_rendering(); diff --git a/src/game/behaviors/piranha_plant.inc.c b/src/game/behaviors/piranha_plant.inc.c index 628bfcb01..f986c4eb4 100644 --- a/src/game/behaviors/piranha_plant.inc.c +++ b/src/game/behaviors/piranha_plant.inc.c @@ -375,12 +375,16 @@ void bhv_piranha_plant_loop(void) { CUR_OBJ_CALL_ACTION_FUNCTION(TablePiranhaPlantActions); // In WF, hide all Piranha Plants once high enough up. if (gCurrLevelNum == LEVEL_WF) { - struct Object* player = gMarioStates[0].marioObj; - f32 scalar = max(draw_distance_scalar(), 1.0f); - if (player->oPosY > 3400.0f * scalar) - cur_obj_hide(); - else + if (draw_distance_scalar_is_infinite()) { cur_obj_unhide(); + } else { + struct Object* player = gMarioStates[0].marioObj; + f32 scalar = max(draw_distance_scalar(), 1.0f); + if (player->oPosY > 3400.0f * scalar) + cur_obj_hide(); + else + cur_obj_unhide(); + } } o->oInteractStatus = 0; } diff --git a/src/game/behaviors/whirlpool.inc.c b/src/game/behaviors/whirlpool.inc.c index a5646f0c1..7034e4f0f 100644 --- a/src/game/behaviors/whirlpool.inc.c +++ b/src/game/behaviors/whirlpool.inc.c @@ -44,11 +44,15 @@ void bhv_whirlpool_loop(void) { o->oWhirlpoolTimeout = 30; } - f32 marioDist = dist_between_objects(o, gMarioStates[0].marioObj); - if (marioDist < 5000.0f * draw_distance_scalar()) { + if (draw_distance_scalar_is_infinite()) { o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; } else { - o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; + f32 marioDist = dist_between_objects(o, gMarioStates[0].marioObj); + if (marioDist < 5000.0f * draw_distance_scalar()) { + o->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; + } else { + o->header.gfx.node.flags |= GRAPH_RENDER_INVISIBLE; + } } // not sure if actually an array diff --git a/src/game/obj_behaviors.c b/src/game/obj_behaviors.c index fc38d0a15..26b04be76 100644 --- a/src/game/obj_behaviors.c +++ b/src/game/obj_behaviors.c @@ -701,6 +701,10 @@ s8 is_point_close_to_object(struct Object *obj, f32 x, f32 y, f32 z, s32 dist) { /* |description|Sets an object as visible if within a certain distance of Mario's graphical position|descriptionEnd| */ void set_object_visibility(struct Object *obj, s32 dist) { if (!obj) { return; } + if (draw_distance_scalar_is_infinite()) { + obj->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; + return; + } s32 distanceToPlayer = dist_between_objects(obj, gMarioStates[0].marioObj); if (distanceToPlayer < dist * draw_distance_scalar()) { obj->header.gfx.node.flags &= ~GRAPH_RENDER_INVISIBLE; diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index 3d600d10d..8705b804a 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -3010,7 +3010,9 @@ void cur_obj_if_hit_wall_bounce_away(void) { s32 cur_obj_hide_if_mario_far_away_y(f32 distY) { if (!o) { return 0; } if (!gMarioStates[0].marioObj) { return FALSE; } - if (absf(o->oPosY - gMarioStates[0].marioObj->oPosY) < distY * draw_distance_scalar()) { + if (draw_distance_scalar_is_infinite() || + absf(o->oPosY - gMarioStates[0].marioObj->oPosY) < distY * draw_distance_scalar() + ) { cur_obj_unhide(); return FALSE; } diff --git a/src/game/rendering_graph_node.c b/src/game/rendering_graph_node.c index 07089fea5..82d0da8f7 100644 --- a/src/game/rendering_graph_node.c +++ b/src/game/rendering_graph_node.c @@ -50,6 +50,8 @@ #define DISPLAY_LIST_HEAP_SIZE 32000 +#define MAX_FAR_PLANE_DIST 1000000.f + f32 gProjectionMaxNearValue = 5; s16 gProjectionVanillaNearValue = 100; s16 gProjectionVanillaFarValue = 1000; @@ -310,6 +312,10 @@ void patch_mtx_interpolated(f32 delta) { f32 fovInterpolated = delta_interpolate_f32(sPerspectiveNode->prevFov, sPerspectiveNode->fov, delta); f32 near = get_first_person_enabled() ? 1.f : replace_value_if_not_zero(MIN(sPerspectiveNode->near, gProjectionMaxNearValue), gOverrideNear); f32 far = replace_value_if_not_zero(sPerspectiveNode->far, gOverrideFar); + + // "infinite" draw distance + if (gOverrideFar == 0 && configDrawDistance == 6) { far = max(far, MAX_FAR_PLANE_DIST); } + guPerspective(sPerspectiveMtx, &perspNorm, fovInterpolated, sPerspectiveAspect, near, far, 1.0f); gSPMatrix(sPerspectivePos, VIRTUAL_TO_PHYSICAL(sPerspectiveNode), G_MTX_PROJECTION | G_MTX_LOAD | G_MTX_NOPUSH); } @@ -650,6 +656,10 @@ static void geo_process_perspective(struct GraphNodePerspective *node) { gProjectionVanillaFarValue = node->far; f32 near = get_first_person_enabled() ? 1.f : replace_value_if_not_zero(MIN(node->near, gProjectionMaxNearValue), gOverrideNear); f32 far = replace_value_if_not_zero(node->far, gOverrideFar); + + // "infinite" draw distance + if (gOverrideFar == 0 && configDrawDistance == 6) { far = max(far, MAX_FAR_PLANE_DIST); } + guPerspective(mtx, &perspNorm, node->prevFov, aspect, near, far, 1.0f); sPerspectiveNode = node; @@ -1139,7 +1149,7 @@ static void anim_process(Vec3f translation, Vec3s rotation, Vec3f scale, u8 *ani scale[2] *= ((f32) scaleZ) / 256.0f; } } - + if (gCurAnim->flags & ANIM_FLAG_BONE_TRANS) { *animType = ANIM_TYPE_TRANSLATION; } @@ -1459,7 +1469,7 @@ static s32 obj_is_in_view(struct GraphNodeObject *node, Mat4 matrix) { // 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. - if (matrix[3][2] < -20000.0f - cullingRadius) { + if (configDrawDistance != 6 && matrix[3][2] < -20000.0f - cullingRadius) { return FALSE; } diff --git a/src/pc/configfile.c b/src/pc/configfile.c index 8873966f7..7f210a52c 100644 --- a/src/pc/configfile.c +++ b/src/pc/configfile.c @@ -89,7 +89,7 @@ bool configShowPing = false; enum RefreshRateMode configFramerateMode = RRM_AUTO; unsigned int configFrameLimit = 60; unsigned int configInterpolationMode = 1; -unsigned int configDrawDistance = 4; +unsigned int configDrawDistance = 6; // sound settings unsigned int configMasterVolume = 80; // 0 - MAX_VOLUME unsigned int configMusicVolume = MAX_VOLUME; diff --git a/src/pc/djui/djui_panel_display.c b/src/pc/djui/djui_panel_display.c index fccf76752..d12e0f3ba 100644 --- a/src/pc/djui/djui_panel_display.c +++ b/src/pc/djui/djui_panel_display.c @@ -129,8 +129,16 @@ void djui_panel_display_create(struct DjuiBase* caller) { djui_selectionbox_create(body, DLANG(DISPLAY, ANTIALIASING), msaaChoices, choiceCount, &sMsaaSelection, djui_panel_display_msaa_change); } - char* drawDistanceChoices[6] = { DLANG(DISPLAY, D0P5X), DLANG(DISPLAY, D1X), DLANG(DISPLAY, D1P5X), DLANG(DISPLAY, D3X), DLANG(DISPLAY, D10X), DLANG(DISPLAY, D100X) }; - djui_selectionbox_create(body, DLANG(DISPLAY, DRAW_DISTANCE), drawDistanceChoices, 6, &configDrawDistance, NULL); + char* drawDistanceChoices[] = { + DLANG(DISPLAY, D0P5X), + DLANG(DISPLAY, D1X), + DLANG(DISPLAY, D1P5X), + DLANG(DISPLAY, D3X), + DLANG(DISPLAY, D10X), + DLANG(DISPLAY, D100X), + DLANG(DISPLAY, INFINITE), + }; + djui_selectionbox_create(body, DLANG(DISPLAY, DRAW_DISTANCE), drawDistanceChoices, ARRAY_COUNT(drawDistanceChoices), &configDrawDistance, NULL); djui_button_create(body, DLANG(MENU, BACK), DJUI_BUTTON_STYLE_BACK, djui_panel_menu_back); diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 86c6d90df..b0c76d8e3 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -9889,6 +9889,21 @@ int smlua_func_position_based_random_float_position(UNUSED lua_State* L) { return 1; } +int smlua_func_draw_distance_scalar_is_infinite(UNUSED lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 0) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "draw_distance_scalar_is_infinite", 0, top); + return 0; + } + + + lua_pushboolean(L, draw_distance_scalar_is_infinite()); + + return 1; +} + int smlua_func_draw_distance_scalar(UNUSED lua_State* L) { if (L == NULL) { return 0; } @@ -37695,6 +37710,7 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "obj_update_gfx_pos_and_angle", smlua_func_obj_update_gfx_pos_and_angle); smlua_bind_function(L, "position_based_random_u16", smlua_func_position_based_random_u16); smlua_bind_function(L, "position_based_random_float_position", smlua_func_position_based_random_float_position); + smlua_bind_function(L, "draw_distance_scalar_is_infinite", smlua_func_draw_distance_scalar_is_infinite); smlua_bind_function(L, "draw_distance_scalar", smlua_func_draw_distance_scalar); // behavior_table.h