diff --git a/CMakeLists.txt b/CMakeLists.txt index 02b765622..2d200a2d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,11 +5,11 @@ set(CMAKE_CXX_STANDARD 20 CACHE STRING "The C++ standard to use") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version") -project(Ship VERSION 8.0.5 LANGUAGES C CXX) +project(Ship VERSION 8.0.6 LANGUAGES C CXX) include(CMake/soh-cvars.cmake) include(CMake/lus-cvars.cmake) -set(PROJECT_BUILD_NAME "MacReady Foxtrot" CACHE STRING "") -set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "") +set(PROJECT_BUILD_NAME "MacReady Golf" CACHE STRING "" FORCE) +set(PROJECT_TEAM "github.com/harbourmasters" CACHE STRING "" FORCE) set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT soh) add_compile_options($<$:/MP>) diff --git a/soh/assets/custom/scenes/nonmq/syotes_scene/syotes_room_0 b/soh/assets/custom/scenes/shared/syotes_scene/syotes_room_0 similarity index 100% rename from soh/assets/custom/scenes/nonmq/syotes_scene/syotes_room_0 rename to soh/assets/custom/scenes/shared/syotes_scene/syotes_room_0 diff --git a/soh/include/functions.h b/soh/include/functions.h index fc7fc15b7..77d578997 100644 --- a/soh/include/functions.h +++ b/soh/include/functions.h @@ -1257,6 +1257,8 @@ void SkelAnime_DrawFlexLod(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListIndex); void SkelAnime_DrawSkeletonOpa(PlayState* play, SkelAnime* skelAnime, OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, void* arg); +Gfx* SkelAnime_DrawSkeleton2(PlayState* play, SkelAnime* skelAnime, OverrideLimbDrawOpa overrideLimbDraw, + PostLimbDrawOpa postLimbDraw, void* arg, Gfx* gfx); void SkelAnime_DrawOpa(PlayState* play, void** skeleton, Vec3s* jointTable, OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, void* arg); void SkelAnime_DrawFlexOpa(PlayState* play, void** skeleton, Vec3s* jointTable, s32 dListCount, @@ -2462,6 +2464,8 @@ void Message_DrawText(PlayState* play, Gfx** gfxP); void Interface_CreateQuadVertexGroup(Vtx* vtxList, s32 xStart, s32 yStart, s32 width, s32 height, u8 flippedH); void Interface_RandoRestoreSwordless(void); +s32 Ship_CalcShouldDrawAndUpdate(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projectedW, bool* shouldDraw, + bool* shouldUpdate); //Pause Warp void PauseWarp_HandleSelection(); diff --git a/soh/include/z64.h b/soh/include/z64.h index 7a4cb193d..97f68341d 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -1484,6 +1484,8 @@ typedef struct PlayState { /* 0x1242B */ u8 unk_1242B; /* 0x1242C */ SceneTableEntry* loadedScene; /* 0x12430 */ char unk_12430[0xE8]; + // SOH [Custom Models] MTX tracker for flex based skeletons + Mtx** flexLimbOverrideMTX; } PlayState; // size = 0x12518 typedef struct { diff --git a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp index 216e0e12f..daf088942 100644 --- a/soh/soh/Enhancements/debugger/debugSaveEditor.cpp +++ b/soh/soh/Enhancements/debugger/debugSaveEditor.cpp @@ -782,7 +782,7 @@ void DrawFlagTableArray16(const FlagTable& flagTable, uint16_t row, uint16_t& fl ImGui::PopStyleColor(); if (ImGui::IsItemHovered() && hasDescription) { ImGui::BeginTooltip(); - ImGui::Text("%s", UIWidgets::WrappedText(flagTable.flagDescriptions.at(row * 16 + flagIndex), 60)); + ImGui::Text("%s", UIWidgets::WrappedText(flagTable.flagDescriptions.at(row * 16 + flagIndex), 60).c_str()); ImGui::EndTooltip(); } ImGui::PopID(); diff --git a/soh/soh/Enhancements/presets.h b/soh/soh/Enhancements/presets.h index 54c729371..450eca919 100644 --- a/soh/soh/Enhancements/presets.h +++ b/soh/soh/Enhancements/presets.h @@ -226,6 +226,8 @@ const std::vector enhancementsCvars = { CVAR_ENHANCEMENT("DisableLOD"), CVAR_ENHANCEMENT("DisableDrawDistance"), CVAR_ENHANCEMENT("DisableKokiriDrawDistance"), + CVAR_ENHANCEMENT("WidescreenActorCulling"), + CVAR_ENHANCEMENT("ExtendedCullingExcludeGlitchActors"), CVAR_LOW_RES_MODE, CVAR_ENHANCEMENT("DrawLineupTick"), CVAR_ENHANCEMENT("QuickBongoKill"), diff --git a/soh/soh/Enhancements/savestates.cpp b/soh/soh/Enhancements/savestates.cpp index 4d051911e..4797c27a3 100644 --- a/soh/soh/Enhancements/savestates.cpp +++ b/soh/soh/Enhancements/savestates.cpp @@ -5,7 +5,6 @@ #include // std::sprintf #include -#include #include #include @@ -25,19 +24,6 @@ extern "C" PlayState* gPlayState; -template <> struct fmt::formatter { - constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } - - template - auto format(const RequestType& type, FormatContext& ctx) { - switch (type) { - case RequestType::SAVE: return fmt::format_to(ctx.out(), "Save"); - case RequestType::LOAD: return fmt::format_to(ctx.out(), "Load"); - default: return fmt::format_to(ctx.out(), "Unknown"); - } - } -}; - // FROM z_lights.c // I didn't feel like moving it into a header file. #define LIGHTS_BUFFER_SIZE 32 @@ -862,11 +848,11 @@ void SaveStateMgr::ProcessSaveStateRequests(void) { this->states[request.slot]->Load(); Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()->TextDrawNotification(1.0f, true, "loaded state %u", request.slot); } else { - SPDLOG_ERROR("Invalid SaveState slot: {}", request.type); + SPDLOG_ERROR("Invalid SaveState slot: {}", request.slot); } break; [[unlikely]] default: - SPDLOG_ERROR("Invalid SaveState request type: {}", request.type); + SPDLOG_ERROR("Invalid SaveState request type: Unknown ({})", static_cast(request.type)); break; } this->requests.pop(); @@ -889,12 +875,12 @@ SaveStateReturn SaveStateMgr::AddRequest(const SaveStateRequest request) { requests.push(request); return SaveStateReturn::SUCCESS; } else { - SPDLOG_ERROR("Invalid SaveState slot: {}", request.type); + SPDLOG_ERROR("Invalid SaveState slot: {}", request.slot); Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGameOverlay()->TextDrawNotification(1.0f, true, "state slot %u empty", request.slot); return SaveStateReturn::FAIL_INVALID_SLOT; } [[unlikely]] default: - SPDLOG_ERROR("Invalid SaveState request type: {}", request.type); + SPDLOG_ERROR("Invalid SaveState request type: Unknown ({})", static_cast(request.type)); return SaveStateReturn::FAIL_BAD_REQUEST; } } diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 2d7e1fcd5..456e07eaa 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -1832,6 +1832,7 @@ extern "C" char* ResourceMgr_LoadArrayByName(const char* path) return (char*)res->Scalars.data(); } +// Return of LoadArrayByNameAsVec3s must be freed by the caller extern "C" char* ResourceMgr_LoadArrayByNameAsVec3s(const char* path) { auto res = std::static_pointer_cast(GetResourceByNameHandlingMQ(path)); diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index 00f7994f5..7286fe0b9 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -51,6 +51,12 @@ std::string GetWindowButtonText(const char* text, bool menuOpen) { return buttonText; } +static std::unordered_map windowBackendNames = { + { Ship::WindowBackend::FAST3D_DXGI_DX11, "DirectX" }, + { Ship::WindowBackend::FAST3D_SDL_OPENGL, "OpenGL" }, + { Ship::WindowBackend::FAST3D_SDL_METAL, "Metal" }, +}; + static const char* imguiScaleOptions[4] = { "Small", "Normal", "Large", "X-Large" }; static const char* filters[3] = { @@ -103,6 +109,24 @@ extern "C" SaveContext gSaveContext; namespace SohGui { +std::unordered_map availableWindowBackendsMap; +Ship::WindowBackend configWindowBackend; + +void UpdateWindowBackendObjects() { + Ship::WindowBackend runningWindowBackend = Ship::Context::GetInstance()->GetWindow()->GetWindowBackend(); + int32_t configWindowBackendId = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1); + if (Ship::Context::GetInstance()->GetWindow()->IsAvailableWindowBackend(configWindowBackendId)) { + configWindowBackend = static_cast(configWindowBackendId); + } else { + configWindowBackend = runningWindowBackend; + } + + auto availableWindowBackends = Ship::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends(); + for (auto& backend : *availableWindowBackends) { + availableWindowBackendsMap[backend] = windowBackendNames[backend]; + } +} + void DrawMenuBarIcon() { static bool gameIconLoaded = false; if (!gameIconLoaded) { @@ -441,39 +465,24 @@ void DrawSettingsMenu() { UIWidgets::Tooltip("Changes the scaling of the ImGui menu elements."); UIWidgets::PaddedSeparator(true, true, 3.0f, 3.0f); - - static std::unordered_map windowBackendNames = { - { Ship::WindowBackend::FAST3D_DXGI_DX11, "DirectX" }, - { Ship::WindowBackend::FAST3D_SDL_OPENGL, "OpenGL"}, - { Ship::WindowBackend::FAST3D_SDL_METAL, "Metal" } - }; ImGui::Text("Renderer API (Needs reload)"); - Ship::WindowBackend runningWindowBackend = Ship::Context::GetInstance()->GetWindow()->GetWindowBackend(); - Ship::WindowBackend configWindowBackend; - int configWindowBackendId = Ship::Context::GetInstance()->GetConfig()->GetInt("Window.Backend.Id", -1); - if (Ship::Context::GetInstance()->GetWindow()->IsAvailableWindowBackend(configWindowBackendId)) { - configWindowBackend = static_cast(configWindowBackendId); - } else { - configWindowBackend = runningWindowBackend; - } - if (Ship::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1) { + if (availableWindowBackendsMap.size() <= 1) { UIWidgets::DisableComponent(ImGui::GetStyle().Alpha * 0.5f); } - if (ImGui::BeginCombo("##RApi", windowBackendNames[configWindowBackend])) { - for (size_t i = 0; i < Ship::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size(); i++) { - auto backend = Ship::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->data()[i]; - if (ImGui::Selectable(windowBackendNames[backend], backend == configWindowBackend)) { - Ship::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id", static_cast(backend)); - Ship::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name", - windowBackendNames[backend]); + if (ImGui::BeginCombo("##RApi", availableWindowBackendsMap[configWindowBackend])) { + for (auto backend : availableWindowBackendsMap) { + if (ImGui::Selectable(backend.second, backend.first == configWindowBackend)) { + Ship::Context::GetInstance()->GetConfig()->SetInt("Window.Backend.Id", static_cast(backend.first)); + Ship::Context::GetInstance()->GetConfig()->SetString("Window.Backend.Name", backend.second); Ship::Context::GetInstance()->GetConfig()->Save(); + UpdateWindowBackendObjects(); } } ImGui::EndCombo(); } - if (Ship::Context::GetInstance()->GetWindow()->GetAvailableWindowBackends()->size() <= 1) { + if (availableWindowBackendsMap.size() <= 1) { UIWidgets::ReEnableComponent(""); } @@ -1147,26 +1156,42 @@ void DrawEnhancementsMenu() { UIWidgets::Spacer(0); UIWidgets::PaddedEnhancementCheckbox("Disable LOD", CVAR_ENHANCEMENT("DisableLOD"), true, false); - UIWidgets::Tooltip("Turns off the Level of Detail setting, making models use their higher-poly variants at any distance"); - if (UIWidgets::PaddedEnhancementCheckbox("Disable Draw Distance", CVAR_ENHANCEMENT("DisableDrawDistance"), true, false)) { - if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 0) == 0) { + UIWidgets::Tooltip( + "Turns off the Level of Detail setting, making models use their higher-poly variants at any distance"); + if (UIWidgets::EnhancementSliderInt("Increase Actor Draw Distance: %dx", "##IncreaseActorDrawDistance", + CVAR_ENHANCEMENT("DisableDrawDistance"), 1, 5, "", 1, true, false)) { + if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) <= 1) { CVarSetInteger(CVAR_ENHANCEMENT("DisableKokiriDrawDistance"), 0); } } - UIWidgets::Tooltip("Turns off the objects draw distance, making objects being visible from a longer range"); - if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 0) == 1) { - UIWidgets::PaddedEnhancementCheckbox("Kokiri Draw Distance", CVAR_ENHANCEMENT("DisableKokiriDrawDistance"), true, false); - UIWidgets::Tooltip("The Kokiri are mystical beings that fade into view when approached\nEnabling this will remove their draw distance"); + UIWidgets::Tooltip("Increases the range in which actors/objects are drawn"); + if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) > 1) { + UIWidgets::PaddedEnhancementCheckbox("Kokiri Draw Distance", + CVAR_ENHANCEMENT("DisableKokiriDrawDistance"), true, false); + UIWidgets::Tooltip("The Kokiri are mystical beings that fade into view when approached\nEnabling this " + "will remove their draw distance"); } - if (UIWidgets::PaddedEnhancementCheckbox("Show Age-Dependent Equipment", CVAR_ENHANCEMENT("EquimentAlwaysVisible"), true, - false)) { - UpdatePatchHand(); - } - UIWidgets::Tooltip("Makes all equipment visible, regardless of Age."); - if (CVarGetInteger(CVAR_ENHANCEMENT("EquimentAlwaysVisible"), 0) == 1) { - UIWidgets::PaddedEnhancementCheckbox("Scale Adult Equipment as Child", CVAR_ENHANCEMENT("ScaleAdultEquimentAsChild"), true, false); - UIWidgets::Tooltip("Scales all of the Adult Equipment, as well and moving some a bit, to fit on Child Link Better. May not work properly with some mods."); - } + UIWidgets::PaddedEnhancementCheckbox("Widescreen Actor Culling", CVAR_ENHANCEMENT("WidescreenActorCulling"), + true, false); + UIWidgets::Tooltip("Adjusts the horizontal culling plane to account for widescreen resolutions"); + UIWidgets::PaddedEnhancementCheckbox( + "Cull Glitch Useful Actors", CVAR_ENHANCEMENT("ExtendedCullingExcludeGlitchActors"), true, false, + !CVarGetInteger(CVAR_ENHANCEMENT("WidescreenActorCulling"), 0) && + CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) <= 1, + "Requires Actor Draw Distance to be increased or Widescreen Actor Culling enabled"); + UIWidgets::Tooltip( + "Exclude actors that are useful for glitches from the extended culling ranges.\n" + "Some actors may still draw in the extended ranges, but will not \"update\" so that certain " + "glitches that leverage the original culling requirements will still work.\n" + "\n" + "The following actors are excluded:\n" + "- White clothed Gerudos\n" + "- King Zora\n" + "- Gossip Stones\n" + "- Boulders\n" + "- Blue Warps\n" + "- Darunia\n" + "- Gold Skulltulas"); UIWidgets::PaddedEnhancementCheckbox("N64 Mode", CVAR_LOW_RES_MODE, true, false); UIWidgets::Tooltip("Sets aspect ratio to 4:3 and lowers resolution to 240p, the N64's native resolution"); UIWidgets::PaddedEnhancementCheckbox("Glitch line-up tick", CVAR_ENHANCEMENT("DrawLineupTick"), true, false); @@ -2004,6 +2029,10 @@ void DrawRandomizerMenu() { } } +void SohMenuBar::InitElement() { + UpdateWindowBackendObjects(); +} + void SohMenuBar::DrawElement() { if (ImGui::BeginMenuBar()) { DrawMenuBarIcon(); diff --git a/soh/soh/SohMenuBar.h b/soh/soh/SohMenuBar.h index 99fb8a0ae..b90960e2c 100644 --- a/soh/soh/SohMenuBar.h +++ b/soh/soh/SohMenuBar.h @@ -10,7 +10,7 @@ class SohMenuBar : public Ship::GuiMenuBar { using Ship::GuiMenuBar::GuiMenuBar; protected: void DrawElement() override; - void InitElement() override {}; + void InitElement() override; void UpdateElement() override {}; }; } // namespace SohGui \ No newline at end of file diff --git a/soh/soh/UIWidgets.cpp b/soh/soh/UIWidgets.cpp index d1bf0967a..c08a37a6a 100644 --- a/soh/soh/UIWidgets.cpp +++ b/soh/soh/UIWidgets.cpp @@ -24,7 +24,7 @@ namespace UIWidgets { // Automatically adds newlines to break up text longer than a specified number of characters // Manually included newlines will still be respected and reset the line length // If line is midword when it hits the limit, text should break at the last encountered space - char* WrappedText(const char* text, unsigned int charactersPerLine) { + std::string WrappedText(const char* text, unsigned int charactersPerLine) { std::string newText(text); const size_t tipLength = newText.length(); int lastSpace = -1; @@ -46,17 +46,17 @@ namespace UIWidgets { currentLineLength++; } - return strdup(newText.c_str()); + return newText; } - char* WrappedText(const std::string& text, unsigned int charactersPerLine) { + std::string WrappedText(const std::string& text, unsigned int charactersPerLine) { return WrappedText(text.c_str(), charactersPerLine); } void SetLastItemHoverText(const std::string& text) { if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); - ImGui::Text("%s", WrappedText(text, 60)); + ImGui::Text("%s", WrappedText(text, 60).c_str()); ImGui::EndTooltip(); } } @@ -64,7 +64,7 @@ namespace UIWidgets { void SetLastItemHoverText(const char* text) { if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); - ImGui::Text("%s", WrappedText(text, 60)); + ImGui::Text("%s", WrappedText(text, 60).c_str()); ImGui::EndTooltip(); } } @@ -75,7 +75,7 @@ namespace UIWidgets { ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); - ImGui::Text("%s", WrappedText(text, 60)); + ImGui::Text("%s", WrappedText(text, 60).c_str()); ImGui::EndTooltip(); } } @@ -85,7 +85,7 @@ namespace UIWidgets { ImGui::TextColored(ImVec4(0.7f, 0.7f, 0.7f, 1.0f), "?"); if (ImGui::IsItemHovered()) { ImGui::BeginTooltip(); - ImGui::Text("%s", WrappedText(text, 60)); + ImGui::Text("%s", WrappedText(text, 60).c_str()); ImGui::EndTooltip(); } } @@ -95,7 +95,7 @@ namespace UIWidgets { void Tooltip(const char* text) { if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("%s", WrappedText(text)); + ImGui::SetTooltip("%s", WrappedText(text).c_str()); } } diff --git a/soh/soh/UIWidgets.hpp b/soh/soh/UIWidgets.hpp index 70580340c..b4f113708 100644 --- a/soh/soh/UIWidgets.hpp +++ b/soh/soh/UIWidgets.hpp @@ -54,8 +54,8 @@ namespace UIWidgets { constexpr float sliderButtonWidth = 30.0f; #endif - char* WrappedText(const char* text, unsigned int charactersPerLine = 60); - char* WrappedText(const std::string& text, unsigned int charactersPerLine); + std::string WrappedText(const char* text, unsigned int charactersPerLine = 60); + std::string WrappedText(const std::string& text, unsigned int charactersPerLine); void SetLastItemHoverText(const std::string& text); void SetLastItemHoverText(const char* text); diff --git a/soh/soh/mixer.c b/soh/soh/mixer.c index 2e80ffb16..ba6a01bc1 100644 --- a/soh/soh/mixer.c +++ b/soh/soh/mixer.c @@ -99,8 +99,14 @@ void aClearBufferImpl(uint16_t addr, int nbytes) { memset(BUF_U8(addr), 0, nbytes); } -void aLoadBufferImpl(const void *source_addr, uint16_t dest_addr, uint16_t nbytes) { +void aLoadBufferImpl(const void* source_addr, uint16_t dest_addr, uint16_t nbytes) { +#if __SANITIZE_ADDRESS__ + for (size_t i = 0; i < ROUND_DOWN_16(nbytes); i++) { + BUF_U8(dest_addr)[i] = ((const unsigned char*)source_addr)[i]; + } +#else memcpy(BUF_U8(dest_addr), source_addr, ROUND_DOWN_16(nbytes)); +#endif } void aSaveBufferImpl(uint16_t source_addr, int16_t *dest_addr, uint16_t nbytes) { diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 9eac79559..289982318 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -1228,14 +1228,6 @@ void Actor_Init(Actor* actor, PlayState* play) { actor->uncullZoneForward = 1000.0f; actor->uncullZoneScale = 350.0f; actor->uncullZoneDownward = 700.0f; - if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 0) != 0 && actor->id != ACTOR_EN_TORCH2 && actor->id != ACTOR_EN_BLKOBJ // Extra check for Dark Link and his room - && actor->id != ACTOR_EN_HORSE // Check for Epona, else if we call her she will spawn at the other side of the map + we can hear her during the title screen sequence - && actor->id != ACTOR_EN_HORSE_GANON && actor->id != ACTOR_EN_HORSE_ZELDA // check for Zelda's and Ganondorf's horses that will always be scene during cinematic whith camera paning - && (play->sceneNum != SCENE_DODONGOS_CAVERN && actor->id != ACTOR_EN_ZF)) { // Check for DC and Lizalfos for the case where the miniboss music would still play under certains conditions and changing room - actor->uncullZoneForward = 32767.0f; - actor->uncullZoneScale = 32767.0f; - actor->uncullZoneDownward = 32767.0f; - } CollisionCheck_InitInfo(&actor->colChkInfo); actor->floorBgId = BGCHECK_SCENE; ActorShape_Init(&actor->shape, 0.0f, NULL, 0.0f); @@ -2898,34 +2890,93 @@ s32 func_800314B0(PlayState* play, Actor* actor) { s32 func_800314D4(PlayState* play, Actor* actor, Vec3f* arg2, f32 arg3) { f32 var; - if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 0) != 0 && actor->id != ACTOR_EN_TORCH2 && actor->id != ACTOR_EN_BLKOBJ // Extra check for Dark Link and his room - && actor->id != ACTOR_EN_HORSE // Check for Epona, else if we call her she will spawn at the other side of the map + we can hear her during the title screen sequence - && actor->id != ACTOR_EN_HORSE_GANON && actor->id != ACTOR_EN_HORSE_ZELDA // check for Zelda's and Ganondorf's horses that will always be scene during cinematic whith camera paning - && (play->sceneNum != SCENE_DODONGOS_CAVERN && actor->id != ACTOR_EN_ZF)) { // Check for DC and Lizalfos for the case where the miniboss music would still play under certains conditions and changing room - return true; - } - if ((arg2->z > -actor->uncullZoneScale) && (arg2->z < (actor->uncullZoneForward + actor->uncullZoneScale))) { var = (arg3 < 1.0f) ? 1.0f : 1.0f / arg3; - // #region SoH [Widescreen support] - // Doors will cull quite noticeably on wider screens. For these actors the zone is increased - f32 limit = 1.0f; - if (((actor->id == ACTOR_EN_DOOR) || (actor->id == ACTOR_DOOR_SHUTTER)) && CVarGetInteger(CVAR_GENERAL("IncreaseDoorUncullZones"), 1)) { - limit = 2.0f; - } - - if ((((fabsf(arg2->x) - actor->uncullZoneScale) * var) < limit) && - (((arg2->y + actor->uncullZoneDownward) * var) > -limit) && - (((arg2->y - actor->uncullZoneScale) * var) < limit)) { + if ((((fabsf(arg2->x) - actor->uncullZoneScale) * var) < 1.0f) && + (((arg2->y + actor->uncullZoneDownward) * var) > -1.0f) && + (((arg2->y - actor->uncullZoneScale) * var) < 1.0f)) { return true; } - // #endregion } return false; } +// #region SOH [Enhancements] Allows us to increase the draw and update distance independently, +// mostly a modified version of the function above and additional tweaks for some specfic actors +s32 Ship_CalcShouldDrawAndUpdate(PlayState* play, Actor* actor, Vec3f* projectedPos, f32 projectedW, bool* shouldDraw, + bool* shouldUpdate) { + f32 clampedProjectedW; + + // Check if the actor passes its original/vanilla culling requirements + if (func_800314D4(play, actor, projectedPos, projectedW)) { + *shouldUpdate = true; + *shouldDraw = true; + return true; + } + + // Skip cutscne actors that depend on culling to hide from camera pans + if (actor->id == ACTOR_EN_VIEWER) { + return false; + } + + s32 multiplier = CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1); + multiplier = MAX(multiplier, 1); + + // Some actors have a really short forward value, so we need to add to it before the multiplier to increase the + // final strength of the forward culling + f32 adder = (actor->uncullZoneForward < 500) ? 1000.0f : 0.0f; + + if ((projectedPos->z > -actor->uncullZoneScale) && + (projectedPos->z < (((actor->uncullZoneForward + adder) * multiplier) + actor->uncullZoneScale))) { + clampedProjectedW = (projectedW < 1.0f) ? 1.0f : 1.0f / projectedW; + + f32 ratioAdjusted = 1.0f; + + if (CVarGetInteger(CVAR_ENHANCEMENT("WidescreenActorCulling"), 0)) { + f32 originalAspectRatio = 4.0f / 3.0f; + f32 currentAspectRatio = OTRGetAspectRatio(); + ratioAdjusted = MAX(currentAspectRatio / originalAspectRatio, 1.0f); + } + + if ((((fabsf(projectedPos->x) - actor->uncullZoneScale) * (clampedProjectedW / ratioAdjusted)) < 1.0f) && + (((projectedPos->y + actor->uncullZoneDownward) * clampedProjectedW) > -1.0f) && + (((projectedPos->y - actor->uncullZoneScale) * clampedProjectedW) < 1.0f)) { + + if (CVarGetInteger(CVAR_ENHANCEMENT("ExtendedCullingExcludeGlitchActors"), 0)) { + // These actors are safe to draw without impacting glitches + if ((actor->id == ACTOR_OBJ_BOMBIWA || actor->id == ACTOR_OBJ_HAMISHI || + actor->id == ACTOR_EN_ISHI) || // Boulders (hookshot through collision) + actor->id == ACTOR_EN_GS || // Gossip stones (text delay) + actor->id == ACTOR_EN_GE1 || // White gerudos (gate clip/archery room transition) + actor->id == ACTOR_EN_KZ || // King Zora (unfreeze glitch) + actor->id == ACTOR_EN_DU || // Darunia (Fire temple BK skip) + actor->id == ACTOR_DOOR_WARP1 // Blue warps (wrong warps) + ) { + *shouldDraw = true; + return true; + } + + // Skip these actors entirely as their draw funcs impacts glitches + if ((actor->id == ACTOR_EN_SW && + (((actor->params & 0xE000) >> 0xD) == 1 || + ((actor->params & 0xE000) >> 0xD) == 2)) // Gold Skulltulas (hitbox at 0,0) + ) { + return false; + } + } + + *shouldDraw = true; + *shouldUpdate = true; + return true; + } + } + + return false; +} +// #endregion + void func_800315AC(PlayState* play, ActorContext* actorCtx) { s32 invisibleActorCounter; Actor* invisibleActors[INVISIBLE_ACTOR_MAX]; @@ -2961,18 +3012,35 @@ void func_800315AC(PlayState* play, ActorContext* actorCtx) { } } + // #region SOH [Enhancement] Extended culling updates + bool shipShouldDraw = false; + bool shipShouldUpdate = false; if ((HREG(64) != 1) || ((HREG(65) != -1) && (HREG(65) != HREG(66))) || (HREG(70) == 0)) { - if (func_800314B0(play, actor)) { - actor->flags |= ACTOR_FLAG_ACTIVE; + if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) > 1 || + CVarGetInteger(CVAR_ENHANCEMENT("WidescreenActorCulling"), 0)) { + Ship_CalcShouldDrawAndUpdate(play, actor, &actor->projectedPos, actor->projectedW, &shipShouldDraw, + &shipShouldUpdate); + + if (shipShouldUpdate) { + actor->flags |= ACTOR_FLAG_ACTIVE; + } else { + actor->flags &= ~ACTOR_FLAG_ACTIVE; + } } else { - actor->flags &= ~ACTOR_FLAG_ACTIVE; + if (func_800314B0(play, actor)) { + actor->flags |= ACTOR_FLAG_ACTIVE; + } else { + actor->flags &= ~ACTOR_FLAG_ACTIVE; + } } } actor->isDrawn = false; if ((HREG(64) != 1) || ((HREG(65) != -1) && (HREG(65) != HREG(66))) || (HREG(71) == 0)) { - if ((actor->init == NULL) && (actor->draw != NULL) && (actor->flags & (ACTOR_FLAG_DRAW_WHILE_CULLED | ACTOR_FLAG_ACTIVE))) { + if ((actor->init == NULL) && (actor->draw != NULL) && + ((actor->flags & (ACTOR_FLAG_DRAW_WHILE_CULLED | ACTOR_FLAG_ACTIVE)) || shipShouldDraw)) { + // #endregion if ((actor->flags & ACTOR_FLAG_LENS) && ((play->roomCtx.curRoom.lensMode == LENS_MODE_HIDE_ACTORS) || play->actorCtx.lensActive || (actor->room != play->roomCtx.curRoom.num))) { diff --git a/soh/src/code/z_fcurve_data_skelanime.c b/soh/src/code/z_fcurve_data_skelanime.c index 91b6dc90c..c75450be2 100644 --- a/soh/src/code/z_fcurve_data_skelanime.c +++ b/soh/src/code/z_fcurve_data_skelanime.c @@ -131,10 +131,6 @@ void SkelCurve_DrawLimb(PlayState* play, s32 limbIndex, SkelAnimeCurve* skelCurv Matrix_TranslateRotateZYX(&pos, &rot); Matrix_Scale(scale.x, scale.y, scale.z, MTXMODE_APPLY); - if (CVarGetInteger(CVAR_ENHANCEMENT("DisableLOD"), 0)) { - lod = 0; - } - if (lod == 0) { s32 pad1; diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index c6b1415f6..0495df1dd 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -1116,7 +1116,7 @@ void Message_DrawText(PlayState* play, Gfx** gfxP) { } } if (msgCtx->textDelayTimer == 0) { - msgCtx->textDrawPos = i + CVarGetInteger(CVAR_ENHANCEMENT("TextSpeed"), 2); + msgCtx->textDrawPos = i + CVarGetInteger(CVAR_ENHANCEMENT("TextSpeed"), 1); msgCtx->textDelayTimer = msgCtx->textDelay; } else { msgCtx->textDelayTimer--; diff --git a/soh/src/code/z_player_lib.c b/soh/src/code/z_player_lib.c index 4b790122f..b5128740c 100644 --- a/soh/src/code/z_player_lib.c +++ b/soh/src/code/z_player_lib.c @@ -2415,10 +2415,12 @@ void Player_DrawPause(PlayState* play, u8* segment, SkelAnime* skelAnime, Vec3f* } srcTable = ResourceMgr_LoadArrayByNameAsVec3s(srcTable); + Vec3s* ogSrcTable = srcTable; destTable = skelAnime->jointTable; for (i = 0; i < skelAnime->limbCount; i++) { *destTable++ = *srcTable++; } + free(ogSrcTable); } Player_DrawPauseImpl(play, segment + 0x3800, segment + 0x8800, skelAnime, pos, rot, scale, sword, tunic, shield, diff --git a/soh/src/code/z_skelanime.c b/soh/src/code/z_skelanime.c index 3df8a26a5..0bcf39236 100644 --- a/soh/src/code/z_skelanime.c +++ b/soh/src/code/z_skelanime.c @@ -148,6 +148,8 @@ void SkelAnime_DrawFlexLimbLod(PlayState* play, s32 limbIndex, void** skeleton, newDList = limbDList = limb->dLists[lod]; + play->flexLimbOverrideMTX = mtx; + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(play, limbIndex, &newDList, &pos, &rot, arg)) { Matrix_TranslateRotateZYX(&pos, &rot); if (newDList != NULL) { @@ -220,6 +222,8 @@ void SkelAnime_DrawFlexLod(PlayState* play, void** skeleton, Vec3s* jointTable, newDList = limbDList = rootLimb->dLists[lod]; + play->flexLimbOverrideMTX = &mtx; + if ((overrideLimbDraw == 0) || !overrideLimbDraw(play, 1, &newDList, &pos, &rot, arg)) { Matrix_TranslateRotateZYX(&pos, &rot); if (newDList != NULL) { @@ -306,6 +310,20 @@ void SkelAnime_DrawSkeletonOpa(PlayState* play, SkelAnime* skelAnime, OverrideLi } } +Gfx* SkelAnime_DrawSkeleton2(PlayState* play, SkelAnime* skelAnime, OverrideLimbDrawOpa overrideLimbDraw, + PostLimbDrawOpa postLimbDraw, void* arg, Gfx* gfx) +{ + if (skelAnime->skeletonHeader->skeletonType == SKELANIME_TYPE_NORMAL) { + return SkelAnime_Draw(play, skelAnime->skeleton, skelAnime->jointTable, overrideLimbDraw, postLimbDraw, arg, gfx); + } else if (skelAnime->skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) { + FlexSkeletonHeader* flexHeader = (FlexSkeletonHeader*)skelAnime->skeletonHeader; + return SkelAnime_DrawFlex(play, skelAnime->skeleton, skelAnime->jointTable, flexHeader->dListCount, + overrideLimbDraw, postLimbDraw, arg, gfx); + } + + return gfx; +} + /** * Draw all limbs of type `StandardLimb` in a given skeleton to the polyOpa buffer */ @@ -383,6 +401,8 @@ void SkelAnime_DrawFlexLimbOpa(PlayState* play, s32 limbIndex, void** skeleton, newDList = limbDList = limb->dList; + play->flexLimbOverrideMTX = limbMatricies; + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(play, limbIndex, &newDList, &pos, &rot, arg)) { Matrix_TranslateRotateZYX(&pos, &rot); if (newDList != NULL) { diff --git a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c index 30455e8e5..8427a9694 100644 --- a/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c +++ b/soh/src/overlays/actors/ovl_Boss_Dodongo/z_boss_dodongo.c @@ -1288,6 +1288,10 @@ block_1: if (*dList != NULL) { OPEN_DISPS(play->state.gfxCtx); + if (this->skelAnime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) { + MATRIX_TOMTX(*play->flexLimbOverrideMTX); + } + mtxScaleZ = 1.0f; mtxScaleY = 1.0f; @@ -1308,11 +1312,20 @@ block_1: Matrix_RotateX(-(this->unk_25C[limbIndex] * 0.115f), MTXMODE_APPLY); } - gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), - G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + if (this->skelAnime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) { + gSPMatrix(POLY_OPA_DISP++, *play->flexLimbOverrideMTX, G_MTX_LOAD); + } else { + gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + } + gSPDisplayList(POLY_OPA_DISP++, *dList); Matrix_Pop(); + if (this->skelAnime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) { + (*play->flexLimbOverrideMTX)++; + } + CLOSE_DISPS(play->state.gfxCtx); } { s32 pad; } // Required to match diff --git a/soh/src/overlays/actors/ovl_Boss_Goma/z_boss_goma.c b/soh/src/overlays/actors/ovl_Boss_Goma/z_boss_goma.c index 049cb3da5..4d6165994 100644 --- a/soh/src/overlays/actors/ovl_Boss_Goma/z_boss_goma.c +++ b/soh/src/overlays/actors/ovl_Boss_Goma/z_boss_goma.c @@ -2015,12 +2015,26 @@ s32 BossGoma_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f Matrix_TranslateRotateZYX(pos, rot); if (*dList != NULL) { + if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) { + MATRIX_TOMTX(*play->flexLimbOverrideMTX); + } + Matrix_Push(); Matrix_Scale(this->eyeIrisScaleX, this->eyeIrisScaleY, 1.0f, MTXMODE_APPLY); - gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), - G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) { + gSPMatrix(POLY_OPA_DISP++, *play->flexLimbOverrideMTX, G_MTX_LOAD); + } else { + gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + } + gSPDisplayList(POLY_OPA_DISP++, *dList); Matrix_Pop(); + + if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) { + (*play->flexLimbOverrideMTX)++; + } } doNotDrawLimb = true; @@ -2034,14 +2048,28 @@ s32 BossGoma_OverrideLimbDraw(PlayState* play, s32 limbIndex, Gfx** dList, Vec3f Matrix_TranslateRotateZYX(pos, rot); if (*dList != NULL) { + if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) { + MATRIX_TOMTX(*play->flexLimbOverrideMTX); + } + Matrix_Push(); Matrix_Scale(this->tailLimbsScale[limbIndex - BOSSGOMA_LIMB_TAIL4], this->tailLimbsScale[limbIndex - BOSSGOMA_LIMB_TAIL4], this->tailLimbsScale[limbIndex - BOSSGOMA_LIMB_TAIL4], MTXMODE_APPLY); - gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), - G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) { + gSPMatrix(POLY_OPA_DISP++, *play->flexLimbOverrideMTX, G_MTX_LOAD); + } else { + gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + } + gSPDisplayList(POLY_OPA_DISP++, *dList); Matrix_Pop(); + + if (this->skelanime.skeletonHeader->skeletonType == SKELANIME_TYPE_FLEX) { + (*play->flexLimbOverrideMTX)++; + } } doNotDrawLimb = true; diff --git a/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c b/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c index 5ea64e232..19c60cf55 100644 --- a/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c +++ b/soh/src/overlays/actors/ovl_Door_Warp1/z_door_warp1.c @@ -1055,7 +1055,7 @@ void DoorWarp1_DrawBlueCrystal(DoorWarp1* this, PlayState* play) { gDPSetPrimColor(POLY_XLU_DISP++, 0xFF, 0xFF, 200, 255, 255, (u8)this->crystalAlpha); gDPSetEnvColor(POLY_XLU_DISP++, 0, 100, 255, (u8)this->crystalAlpha); - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, NULL, NULL, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, NULL, NULL, &this->actor, POLY_XLU_DISP); CLOSE_DISPS(play->state.gfxCtx); @@ -1079,7 +1079,7 @@ void DoorWarp1_DrawPurpleCrystal(DoorWarp1* this, PlayState* play) { gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (u8)this->crystalAlpha); gDPSetEnvColor(POLY_XLU_DISP++, 150, 0, 100, (u8)this->crystalAlpha); - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, NULL, NULL, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, NULL, NULL, &this->actor, POLY_XLU_DISP); CLOSE_DISPS(play->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_En_Bili/z_en_bili.c b/soh/src/overlays/actors/ovl_En_Bili/z_en_bili.c index 74f89cbe3..a50dabe01 100644 --- a/soh/src/overlays/actors/ovl_En_Bili/z_en_bili.c +++ b/soh/src/overlays/actors/ovl_En_Bili/z_en_bili.c @@ -768,7 +768,7 @@ void EnBili_Draw(Actor* thisx, PlayState* play) { gSPSegment(POLY_XLU_DISP++, 0x09, D_809C1700); } - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnBili_OverrideLimbDraw, NULL, this, POLY_XLU_DISP); CLOSE_DISPS(play->state.gfxCtx); } diff --git a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c index ee052bc58..30398a208 100644 --- a/soh/src/overlays/actors/ovl_En_Box/z_en_box.c +++ b/soh/src/overlays/actors/ovl_En_Box/z_en_box.c @@ -955,7 +955,7 @@ void EnBox_Draw(Actor* thisx, PlayState* play) { gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); gSPSegment(POLY_OPA_DISP++, 0x08, EnBox_EmptyDList(play->state.gfxCtx)); Gfx_SetupDL_25Opa(play->state.gfxCtx); - POLY_OPA_DISP = SkelAnime_Draw(play, this->skelanime.skeleton, this->skelanime.jointTable, NULL, + POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelanime, NULL, EnBox_PostLimbDraw, this, POLY_OPA_DISP); } else if (this->alpha != 0) { gDPPipeSync(POLY_XLU_DISP++); @@ -966,7 +966,7 @@ void EnBox_Draw(Actor* thisx, PlayState* play) { } else { gSPSegment(POLY_XLU_DISP++, 0x08, func_809CA4A0(play->state.gfxCtx)); } - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelanime.skeleton, this->skelanime.jointTable, NULL, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelanime, NULL, EnBox_PostLimbDraw, this, POLY_XLU_DISP); } diff --git a/soh/src/overlays/actors/ovl_En_Bw/z_en_bw.c b/soh/src/overlays/actors/ovl_En_Bw/z_en_bw.c index 2a6fdb4fd..501c7ec9e 100644 --- a/soh/src/overlays/actors/ovl_En_Bw/z_en_bw.c +++ b/soh/src/overlays/actors/ovl_En_Bw/z_en_bw.c @@ -856,7 +856,7 @@ void EnBw_Draw(Actor* thisx, PlayState* play2) { Gfx_SetupDL_25Opa(play->state.gfxCtx); gDPSetEnvColor(POLY_OPA_DISP++, this->color1.r, this->color1.g, this->color1.b, this->color1.a); gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]); - POLY_OPA_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnBw_OverrideLimbDraw, NULL, this, POLY_OPA_DISP); } else { Gfx_SetupDL_25Xlu(play->state.gfxCtx); @@ -864,7 +864,7 @@ void EnBw_Draw(Actor* thisx, PlayState* play2) { gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, 0, 0, 0, this->color1.a); gDPSetEnvColor(POLY_XLU_DISP++, this->color1.r, this->color1.g, this->color1.b, this->color1.a); gSPSegment(POLY_XLU_DISP++, 0x08, &D_80116280[0]); - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnBw_OverrideLimbDraw, NULL, this, POLY_XLU_DISP); } diff --git a/soh/src/overlays/actors/ovl_En_Eiyer/z_en_eiyer.c b/soh/src/overlays/actors/ovl_En_Eiyer/z_en_eiyer.c index 049570716..7340d9cf5 100644 --- a/soh/src/overlays/actors/ovl_En_Eiyer/z_en_eiyer.c +++ b/soh/src/overlays/actors/ovl_En_Eiyer/z_en_eiyer.c @@ -708,14 +708,14 @@ void EnEiyer_Draw(Actor* thisx, PlayState* play) { gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]); gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 255); - POLY_OPA_DISP = SkelAnime_Draw(play, this->skelanime.skeleton, this->skelanime.jointTable, + POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelanime, EnEiyer_OverrideLimbDraw, NULL, this, POLY_OPA_DISP); } else { Gfx_SetupDL_25Xlu(play->state.gfxCtx); gSPSegment(POLY_XLU_DISP++, 0x08, D_80116280); gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->actor.shape.shadowAlpha); - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelanime.skeleton, this->skelanime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelanime, EnEiyer_OverrideLimbDraw, NULL, this, POLY_XLU_DISP); } CLOSE_DISPS(play->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_En_Elf/z_en_elf.c b/soh/src/overlays/actors/ovl_En_Elf/z_en_elf.c index 3c3e7c462..3d0566a7f 100644 --- a/soh/src/overlays/actors/ovl_En_Elf/z_en_elf.c +++ b/soh/src/overlays/actors/ovl_En_Elf/z_en_elf.c @@ -1540,7 +1540,7 @@ void EnElf_Draw(Actor* thisx, PlayState* play) { gSPEndDisplayList(dListHead++); gDPSetEnvColor(POLY_XLU_DISP++, (u8)this->outerColor.r, (u8)this->outerColor.g, (u8)this->outerColor.b, (u8)(envAlpha * alphaScale)); - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnElf_OverrideLimbDraw, NULL, this, POLY_XLU_DISP); CLOSE_DISPS(play->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_En_Firefly/z_en_firefly.c b/soh/src/overlays/actors/ovl_En_Firefly/z_en_firefly.c index 6c8afb6d7..7797cba9c 100644 --- a/soh/src/overlays/actors/ovl_En_Firefly/z_en_firefly.c +++ b/soh/src/overlays/actors/ovl_En_Firefly/z_en_firefly.c @@ -839,8 +839,9 @@ void EnFirefly_Draw(Actor* thisx, PlayState* play) { gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255); } - POLY_OPA_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, - EnFirefly_OverrideLimbDraw, EnFirefly_PostLimbDraw, &this->actor, POLY_OPA_DISP); + POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnFirefly_OverrideLimbDraw, EnFirefly_PostLimbDraw, + &this->actor, POLY_OPA_DISP); + CLOSE_DISPS(play->state.gfxCtx); } @@ -856,7 +857,7 @@ void EnFirefly_DrawInvisible(Actor* thisx, PlayState* play) { gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, 255); } - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnFirefly_OverrideLimbDraw, EnFirefly_PostLimbDraw, this, POLY_XLU_DISP); CLOSE_DISPS(play->state.gfxCtx); } diff --git a/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.c b/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.c index de7bddf82..0c30fcf17 100644 --- a/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.c +++ b/soh/src/overlays/actors/ovl_En_Partner/z_en_partner.c @@ -880,7 +880,7 @@ void EnPartner_Draw(Actor* thisx, PlayState* play) { gSPEndDisplayList(dListHead++); gDPSetEnvColor(POLY_XLU_DISP++, (u8)this->outerColor.r, (u8)this->outerColor.g, (u8)this->outerColor.b, (u8)(envAlpha * alphaScale)); - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnPartner_OverrideLimbDraw, NULL, this, POLY_XLU_DISP); CLOSE_DISPS(play->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_En_Po_Desert/z_en_po_desert.c b/soh/src/overlays/actors/ovl_En_Po_Desert/z_en_po_desert.c index 55155226b..2c00b284b 100644 --- a/soh/src/overlays/actors/ovl_En_Po_Desert/z_en_po_desert.c +++ b/soh/src/overlays/actors/ovl_En_Po_Desert/z_en_po_desert.c @@ -267,7 +267,7 @@ void EnPoDesert_Draw(Actor* thisx, PlayState* play) { } else { gSPSegment(POLY_XLU_DISP++, 0x0C, D_80116280 + 2); } - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnPoDesert_OverrideLimbDraw, EnPoDesert_PostLimbDraw, &this->actor, POLY_XLU_DISP); CLOSE_DISPS(play->state.gfxCtx); } diff --git a/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c b/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c index 3f109863c..d391840ba 100644 --- a/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c +++ b/soh/src/overlays/actors/ovl_En_Po_Field/z_en_po_field.c @@ -944,15 +944,14 @@ void EnPoField_Draw(Actor* thisx, PlayState* play) { this->lightColor.a)); gSPSegment(POLY_OPA_DISP++, 0x0C, D_80116280 + 2); POLY_OPA_DISP = - SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnPoField_OverrideLimbDraw2, EnPoField_PostLimDraw2, &this->actor, POLY_OPA_DISP); } else { gSPSegment(POLY_XLU_DISP++, 0x08, Gfx_EnvColor(play->state.gfxCtx, this->lightColor.r, this->lightColor.g, this->lightColor.b, this->lightColor.a)); gSPSegment(POLY_XLU_DISP++, 0x0C, D_80116280); - POLY_XLU_DISP = - SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnPoField_OverrideLimbDraw2, EnPoField_PostLimDraw2, &this->actor, POLY_XLU_DISP); } gDPPipeSync(POLY_OPA_DISP++); diff --git a/soh/src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.c b/soh/src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.c index ea324c5a5..8bd5c2112 100644 --- a/soh/src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.c +++ b/soh/src/overlays/actors/ovl_En_Po_Sisters/z_en_po_sisters.c @@ -1373,14 +1373,12 @@ void EnPoSisters_Draw(Actor* thisx, PlayState* play) { if (this->unk_22E.a == 255 || this->unk_22E.a == 0) { gDPSetEnvColor(POLY_OPA_DISP++, this->unk_22E.r, this->unk_22E.g, this->unk_22E.b, this->unk_22E.a); gSPSegment(POLY_OPA_DISP++, 0x09, D_80116280 + 2); - POLY_OPA_DISP = - SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, - EnPoSisters_OverrideLimbDraw, EnPoSisters_PostLimbDraw, &this->actor, POLY_OPA_DISP); + POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnPoSisters_OverrideLimbDraw, + EnPoSisters_PostLimbDraw, &this->actor, POLY_OPA_DISP); } else { gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->unk_22E.a); gSPSegment(POLY_XLU_DISP++, 0x09, D_80116280); - POLY_XLU_DISP = - SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnPoSisters_OverrideLimbDraw, EnPoSisters_PostLimbDraw, &this->actor, POLY_XLU_DISP); } if (!(this->unk_199 & 0x80)) { diff --git a/soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c b/soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c index 809150fe6..2c7e90416 100644 --- a/soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c +++ b/soh/src/overlays/actors/ovl_En_Poh/z_en_poh.c @@ -1085,12 +1085,12 @@ void EnPoh_DrawRegular(Actor* thisx, PlayState* play) { if (this->lightColor.a == 255 || this->lightColor.a == 0) { gDPSetEnvColor(POLY_OPA_DISP++, this->lightColor.r, this->lightColor.g, this->lightColor.b, this->lightColor.a); gSPSegment(POLY_OPA_DISP++, 0x08, D_80116280 + 2); - POLY_OPA_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnPoh_OverrideLimbDraw, EnPoh_PostLimbDraw, &this->actor, POLY_OPA_DISP); } else { gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->lightColor.a); gSPSegment(POLY_XLU_DISP++, 0x08, D_80116280); - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnPoh_OverrideLimbDraw, EnPoh_PostLimbDraw, &this->actor, POLY_XLU_DISP); } gDPPipeSync(POLY_OPA_DISP++); diff --git a/soh/src/overlays/actors/ovl_En_Vali/z_en_vali.c b/soh/src/overlays/actors/ovl_En_Vali/z_en_vali.c index 9b6154a8b..11772cd90 100644 --- a/soh/src/overlays/actors/ovl_En_Vali/z_en_vali.c +++ b/soh/src/overlays/actors/ovl_En_Vali/z_en_vali.c @@ -814,7 +814,7 @@ void EnVali_Draw(Actor* thisx, PlayState* play) { EnVali_DrawBody(this, play); - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnVali_OverrideLimbDraw, EnVali_PostLimbDraw, this, POLY_XLU_DISP); CLOSE_DISPS(play->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_En_Weiyer/z_en_weiyer.c b/soh/src/overlays/actors/ovl_En_Weiyer/z_en_weiyer.c index 4a267b001..e3f19a3ed 100644 --- a/soh/src/overlays/actors/ovl_En_Weiyer/z_en_weiyer.c +++ b/soh/src/overlays/actors/ovl_En_Weiyer/z_en_weiyer.c @@ -640,13 +640,13 @@ void EnWeiyer_Draw(Actor* thisx, PlayState* play) { Gfx_SetupDL_25Opa(play->state.gfxCtx); gSPSegment(POLY_OPA_DISP++, 0x08, &D_80116280[2]); gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 255); - POLY_OPA_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, - EnWeiyer_OverrideLimbDraw, NULL, &this->actor, POLY_OPA_DISP); + POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnWeiyer_OverrideLimbDraw, NULL, &this->actor, + POLY_OPA_DISP); } else { Gfx_SetupDL_25Xlu(play->state.gfxCtx); gSPSegment(POLY_XLU_DISP++, 0x08, &D_80116280[0]); gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, this->actor.shape.shadowAlpha); - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnWeiyer_OverrideLimbDraw, NULL, &this->actor, POLY_XLU_DISP); } diff --git a/soh/src/overlays/actors/ovl_En_Wood02/z_en_wood02.c b/soh/src/overlays/actors/ovl_En_Wood02/z_en_wood02.c index 2b0d6c126..eb6a77e24 100644 --- a/soh/src/overlays/actors/ovl_En_Wood02/z_en_wood02.c +++ b/soh/src/overlays/actors/ovl_En_Wood02/z_en_wood02.c @@ -101,13 +101,19 @@ static f32 sSpawnSin; s32 EnWood02_SpawnZoneCheck(EnWood02* this, PlayState* play, Vec3f* pos) { f32 phi_f12; - if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 0) != 0) { - return true; - } - SkinMatrix_Vec3fMtxFMultXYZW(&play->viewProjectionMtxF, pos, &this->actor.projectedPos, &this->actor.projectedW); + // #region SOH [Enhancement] Use the extended culling calculation + if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) > 1 || + CVarGetInteger(CVAR_ENHANCEMENT("WidescreenActorCulling"), 0)) { + bool shipShouldDraw = false; + bool shipShouldUpdate = false; + return Ship_CalcShouldDrawAndUpdate(play, &this->actor, &this->actor.projectedPos, this->actor.projectedW, + &shipShouldDraw, &shipShouldUpdate); + } + // #endregion + phi_f12 = ((this->actor.projectedW == 0.0f) ? 1000.0f : fabsf(1.0f / this->actor.projectedW)); if ((-this->actor.uncullZoneScale < this->actor.projectedPos.z) && diff --git a/soh/src/overlays/actors/ovl_En_Zf/z_en_zf.c b/soh/src/overlays/actors/ovl_En_Zf/z_en_zf.c index 98180605e..03fb95bd3 100644 --- a/soh/src/overlays/actors/ovl_En_Zf/z_en_zf.c +++ b/soh/src/overlays/actors/ovl_En_Zf/z_en_zf.c @@ -2252,7 +2252,7 @@ void EnZf_Draw(Actor* thisx, PlayState* play) { gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, this->alpha); gSPSegment(POLY_OPA_DISP++, 0x09, &D_80116280[2]); - POLY_OPA_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_OPA_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnZf_OverrideLimbDraw, EnZf_PostLimbDraw, this, POLY_OPA_DISP); if (this->iceTimer != 0) { @@ -2271,7 +2271,7 @@ void EnZf_Draw(Actor* thisx, PlayState* play) { gDPPipeSync(POLY_XLU_DISP++); gDPSetEnvColor(POLY_XLU_DISP++, 0, 0, 0, this->alpha); gSPSegment(POLY_XLU_DISP++, 0x09, &D_80116280[0]); - POLY_XLU_DISP = SkelAnime_Draw(play, this->skelAnime.skeleton, this->skelAnime.jointTable, + POLY_XLU_DISP = SkelAnime_DrawSkeleton2(play, &this->skelAnime, EnZf_OverrideLimbDraw, EnZf_PostLimbDraw, this, POLY_XLU_DISP); } CLOSE_DISPS(play->state.gfxCtx); diff --git a/soh/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.c b/soh/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.c index a59dc5ab6..b1bafa9c7 100644 --- a/soh/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.c +++ b/soh/src/overlays/actors/ovl_Obj_Mure/z_obj_mure.c @@ -275,7 +275,12 @@ void ObjMure_InitialAction(ObjMure* this, PlayState* play) { } void ObjMure_CulledState(ObjMure* this, PlayState* play) { - if (fabsf(this->actor.projectedPos.z) < sZClip[this->type] || CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 0) != 0) { + // #region SOH [Enhancements] Extended draw distance + s32 distanceMultiplier = CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1); + distanceMultiplier = MAX(distanceMultiplier, 1); + + if (fabsf(this->actor.projectedPos.z) < sZClip[this->type] * distanceMultiplier) { + // #endregion this->actionFunc = ObjMure_ActiveState; this->actor.flags |= ACTOR_FLAG_UPDATE_WHILE_CULLED; ObjMure_SpawnActors(this, play); @@ -398,8 +403,13 @@ static ObjMureActionFunc sTypeGroupBehaviorFunc[] = { void ObjMure_ActiveState(ObjMure* this, PlayState* play) { ObjMure_CheckChildren(this, play); - if (sZClip[this->type] + 40.0f <= fabsf(this->actor.projectedPos.z) && - CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1) != 0) { + + // #region SOH [Enhancements] Extended draw distance + s32 distanceMultiplier = CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1); + distanceMultiplier = MAX(distanceMultiplier, 1); + + if ((sZClip[this->type] + 40.0f) * distanceMultiplier <= fabsf(this->actor.projectedPos.z)) { + // #endregion this->actionFunc = ObjMure_CulledState; this->actor.flags &= ~ACTOR_FLAG_UPDATE_WHILE_CULLED; ObjMure_KillActors(this, play); diff --git a/soh/src/overlays/actors/ovl_Obj_Mure2/z_obj_mure2.c b/soh/src/overlays/actors/ovl_Obj_Mure2/z_obj_mure2.c index 0aad27c04..5b1eecbd4 100644 --- a/soh/src/overlays/actors/ovl_Obj_Mure2/z_obj_mure2.c +++ b/soh/src/overlays/actors/ovl_Obj_Mure2/z_obj_mure2.c @@ -190,8 +190,7 @@ void func_80B9A658(ObjMure2* this) { void func_80B9A668(ObjMure2* this, PlayState* play) { if (Math3D_Dist1DSq(this->actor.projectedPos.x, this->actor.projectedPos.z) < - (sDistSquared1[this->actor.params & 3] * this->unk_184) || - CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 0) != 0) { + (sDistSquared1[this->actor.params & 3] * this->unk_184)) { this->actor.flags |= ACTOR_FLAG_UPDATE_WHILE_CULLED; ObjMure2_SpawnActors(this, play); func_80B9A6E8(this); @@ -205,12 +204,8 @@ void func_80B9A6E8(ObjMure2* this) { void func_80B9A6F8(ObjMure2* this, PlayState* play) { func_80B9A534(this); - if (CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 0) != 0) { - return; - } - if ((sDistSquared2[this->actor.params & 3] * this->unk_184) <= - Math3D_Dist1DSq(this->actor.projectedPos.x, this->actor.projectedPos.z)) { + Math3D_Dist1DSq(this->actor.projectedPos.x, this->actor.projectedPos.z)) { this->actor.flags &= ~ACTOR_FLAG_UPDATE_WHILE_CULLED; ObjMure2_CleanupAndDie(this, play); func_80B9A658(this); @@ -225,5 +220,20 @@ void ObjMure2_Update(Actor* thisx, PlayState* play) { } else { this->unk_184 = 4.0f; } + + // SOH [Enhancements] Extended draw distance + s32 distanceMultiplier = CVarGetInteger(CVAR_ENHANCEMENT("DisableDrawDistance"), 1); + if (CVarGetInteger(CVAR_ENHANCEMENT("WidescreenActorCulling"), 0) || distanceMultiplier > 1) { + f32 originalAspectRatio = 4.0f / 3.0f; + f32 currentAspectRatio = OTRGetAspectRatio(); + // Adjust ratio difference based on field of view testing + f32 ratioAdjusted = 1.0f + (MAX(currentAspectRatio / originalAspectRatio, 1.0f) / 1.5f); + // Distance multiplier is squared due to the checks above for squared distances + distanceMultiplier = SQ(MAX(distanceMultiplier, 1)); + + // Prefer the largest of the three values + this->unk_184 = MAX(MAX((f32)distanceMultiplier, ratioAdjusted), this->unk_184); + } + this->actionFunc(this, play); } diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 3e1452648..1ef4fa593 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -11892,10 +11892,6 @@ void Player_Draw(Actor* thisx, PlayState* play2) { lod = 1; } - if (CVarGetInteger(CVAR_ENHANCEMENT("DisableLOD"), 0)) { - lod = 0; - } - func_80093C80(play); Gfx_SetupDL_25Xlu(play->state.gfxCtx);