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`.
This commit is contained in:
Isaac0-dev 2026-05-16 11:13:02 +10:00 committed by GitHub
parent 91208e4e06
commit 967d120505
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 121 additions and 17 deletions

View file

@ -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()

View file

@ -139,6 +139,27 @@ Sets the current object's position to random floats between 0.0 and 1.0
<br />
## [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:](#)
<br />
## [draw_distance_scalar](#draw_distance_scalar)
### Description

View file

@ -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)
<br />

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -167,6 +167,7 @@ D1P5X = "1.5x"
D3X = "3x"
D10X = "10x"
D100X = "100x"
INFINITE = "無限"
DRAW_DISTANCE = "描画距離"
DYNOS_PACKS = "DynOSパック"
ANTIALIASING = "アンチエイリアス"

View file

@ -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"

View file

@ -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"

View file

@ -166,6 +166,7 @@ D1P5X = "1.5x"
D3X = "3x"
D10X = "10x"
D100X = "100x"
INFINITE = "Бесконечный"
DRAW_DISTANCE = "Дальность прорисовки"
DYNOS_PACKS = "Пакеты DynOS"
ANTIALIASING = "Анизотропная фильтрация"

View file

@ -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"

View file

@ -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; }

View file

@ -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);

View file

@ -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;

View file

@ -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();

View file

@ -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;
}

View file

@ -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

View file

@ -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;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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