From 7407bebf6ea3e4d709f0144db2b375c8a501d18d Mon Sep 17 00:00:00 2001 From: Mr-Wiseguy Date: Wed, 9 Apr 2025 03:51:26 -0400 Subject: [PATCH] Add special config option id to control texture pack state for code mods --- include/zelda_render.h | 11 ++- lib/N64ModernRuntime | 2 +- src/main/main.cpp | 4 +- src/main/rt64_render_context.cpp | 114 ++++++++++++++++++++++++++----- src/ui/ui_mod_menu.cpp | 32 +++++++++ src/ui/ui_mod_menu.h | 2 + src/ui/ui_prompt.cpp | 18 +++++ 7 files changed, 162 insertions(+), 21 deletions(-) diff --git a/include/zelda_render.h b/include/zelda_render.h index 9fa0ce2..451c66b 100644 --- a/include/zelda_render.h +++ b/include/zelda_render.h @@ -14,6 +14,8 @@ namespace RT64 { namespace zelda64 { namespace renderer { + inline const std::string special_option_texture_pack_enabled = "_recomp_texture_pack_enabled"; + class RT64Context final : public ultramodern::renderer::RendererContext { public: ~RT64Context() override; @@ -33,6 +35,7 @@ namespace zelda64 { private: std::unique_ptr app; std::unordered_set enabled_texture_packs; + std::unordered_set secondary_disabled_texture_packs; void check_texture_pack_actions(); }; @@ -44,8 +47,14 @@ namespace zelda64 { bool RT64HighPrecisionFBEnabled(); void trigger_texture_pack_update(); - void enable_texture_pack(const recomp::mods::ModHandle& mod); + void enable_texture_pack(const recomp::mods::ModContext& context, const recomp::mods::ModHandle& mod); void disable_texture_pack(const recomp::mods::ModHandle& mod); + void secondary_enable_texture_pack(const std::string& mod_id); + void secondary_disable_texture_pack(const std::string& mod_id); + + // Texture pack enable option. Must be an enum with two options. + // The first option is treated as disabled and the second option is treated as enabled. + bool is_texture_pack_enable_config_option(const recomp::mods::ConfigOption& option, bool show_errors); } } diff --git a/lib/N64ModernRuntime b/lib/N64ModernRuntime index bb6b3b1..234ed4a 160000 --- a/lib/N64ModernRuntime +++ b/lib/N64ModernRuntime @@ -1 +1 @@ -Subproject commit bb6b3b1645a582b8d9305f221375da9d3563ee60 +Subproject commit 234ed4a95e6578c42434bc45d5232466a9b74de7 diff --git a/src/main/main.cpp b/src/main/main.cpp index a820c3f..ae6a590 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -544,8 +544,8 @@ void release_preload(PreloadContext& context) { #endif -void enable_texture_pack(recomp::mods::ModContext&, const recomp::mods::ModHandle& mod) { - zelda64::renderer::enable_texture_pack(mod); +void enable_texture_pack(recomp::mods::ModContext& context, const recomp::mods::ModHandle& mod) { + zelda64::renderer::enable_texture_pack(context, mod); } void disable_texture_pack(recomp::mods::ModContext&, const recomp::mods::ModHandle& mod) { diff --git a/src/main/rt64_render_context.cpp b/src/main/rt64_render_context.cpp index dd2f152..4994f34 100644 --- a/src/main/rt64_render_context.cpp +++ b/src/main/rt64_render_context.cpp @@ -30,10 +30,18 @@ struct TexturePackDisableAction { std::string mod_id; }; +struct TexturePackSecondaryEnableAction { + std::string mod_id; +}; + +struct TexturePackSecondaryDisableAction { + std::string mod_id; +}; + struct TexturePackUpdateAction { }; -using TexturePackAction = std::variant; +using TexturePackAction = std::variant; static moodycamel::ConcurrentQueue texture_pack_action_queue; @@ -403,6 +411,14 @@ void zelda64::renderer::RT64Context::check_texture_pack_actions() { enabled_texture_packs.insert(to_enable.mod_id); packs_changed = true; }, + [&](TexturePackSecondaryDisableAction &to_override_disable) { + secondary_disabled_texture_packs.insert(to_override_disable.mod_id); + packs_changed = true; + }, + [&](TexturePackSecondaryEnableAction &to_override_enable) { + secondary_disabled_texture_packs.erase(to_override_enable.mod_id); + packs_changed = true; + }, [&](TexturePackUpdateAction &) { packs_changed = true; } @@ -411,23 +427,29 @@ void zelda64::renderer::RT64Context::check_texture_pack_actions() { // If any packs were disabled, unload all packs and load all the active ones. if (packs_changed) { - if (!enabled_texture_packs.empty()) { - // Sort the enabled texture packs in reverse order so that earlier ones override later ones. - std::vector sorted_texture_packs{}; - sorted_texture_packs.assign(enabled_texture_packs.begin(), enabled_texture_packs.end()); - std::sort(sorted_texture_packs.begin(), sorted_texture_packs.end(), - [](const std::string& lhs, const std::string& rhs) { - return recomp::mods::get_mod_order_index(lhs) > recomp::mods::get_mod_order_index(rhs); - } - ); - - // Build the path list from the sorted mod list. - std::vector replacement_directories; - replacement_directories.reserve(enabled_texture_packs.size()); - for (const std::string &mod_id : sorted_texture_packs) { - replacement_directories.emplace_back(RT64::ReplacementDirectory(recomp::mods::get_mod_filename(mod_id))); + // Sort the enabled texture packs in reverse order so that earlier ones override later ones. + std::vector sorted_texture_packs{}; + sorted_texture_packs.reserve(enabled_texture_packs.size()); + for (const std::string& mod : enabled_texture_packs) { + if (!secondary_disabled_texture_packs.contains(mod)) { + sorted_texture_packs.emplace_back(mod); } + } + std::sort(sorted_texture_packs.begin(), sorted_texture_packs.end(), + [](const std::string& lhs, const std::string& rhs) { + return recomp::mods::get_mod_order_index(lhs) > recomp::mods::get_mod_order_index(rhs); + } + ); + + // Build the path list from the sorted mod list. + std::vector replacement_directories; + replacement_directories.reserve(enabled_texture_packs.size()); + for (const std::string &mod_id : sorted_texture_packs) { + replacement_directories.emplace_back(RT64::ReplacementDirectory(recomp::mods::get_mod_filename(mod_id))); + } + + if (!replacement_directories.empty()) { app->textureCache->loadReplacementDirectories(replacement_directories); } else { @@ -456,10 +478,68 @@ void zelda64::renderer::trigger_texture_pack_update() { texture_pack_action_queue.enqueue(TexturePackUpdateAction{}); } -void zelda64::renderer::enable_texture_pack(const recomp::mods::ModHandle& mod) { +void zelda64::renderer::enable_texture_pack(const recomp::mods::ModContext& context, const recomp::mods::ModHandle& mod) { texture_pack_action_queue.enqueue(TexturePackEnableAction{mod.manifest.mod_id}); + + // Check for the texture pack enabled config option. + const recomp::mods::ConfigSchema& config_schema = context.get_mod_config_schema(mod.manifest.mod_id); + auto find_it = config_schema.options_by_id.find(zelda64::renderer::special_option_texture_pack_enabled); + if (find_it != config_schema.options_by_id.end()) { + const recomp::mods::ConfigOption& config_option = config_schema.options[find_it->second]; + + if (is_texture_pack_enable_config_option(config_option, false)) { + recomp::mods::ConfigValueVariant value_variant = context.get_mod_config_value(mod.manifest.mod_id, config_option.id); + uint32_t value; + if (uint32_t* value_ptr = std::get_if(&value_variant)) { + value = *value_ptr; + } + else { + value = 0; + } + + if (value) { + zelda64::renderer::secondary_enable_texture_pack(mod.manifest.mod_id); + } + else { + zelda64::renderer::secondary_disable_texture_pack(mod.manifest.mod_id); + } + } + } } void zelda64::renderer::disable_texture_pack(const recomp::mods::ModHandle& mod) { texture_pack_action_queue.enqueue(TexturePackDisableAction{mod.manifest.mod_id}); } + +void zelda64::renderer::secondary_enable_texture_pack(const std::string& mod_id) { + texture_pack_action_queue.enqueue(TexturePackSecondaryEnableAction{mod_id}); +} + +void zelda64::renderer::secondary_disable_texture_pack(const std::string& mod_id) { + texture_pack_action_queue.enqueue(TexturePackSecondaryDisableAction{mod_id}); +} + + +// HD texture enable option. Must be an enum with two options. +// The first option is treated as disabled and the second option is treated as enabled. +bool zelda64::renderer::is_texture_pack_enable_config_option(const recomp::mods::ConfigOption& option, bool show_errors) { + if (option.id == zelda64::renderer::special_option_texture_pack_enabled) { + if (option.type != recomp::mods::ConfigOptionType::Enum) { + if (show_errors) { + recompui::message_box(("Mod has the special config option id for enabling an HD texture pack (\"" + zelda64::renderer::special_option_texture_pack_enabled + "\"), but the config option is not an enum.").c_str()); + } + return false; + } + + const recomp::mods::ConfigOptionEnum &option_enum = std::get(option.variant); + if (option_enum.options.size() != 2) { + if (show_errors) { + recompui::message_box(("Mod has the special config option id for enabling an HD texture pack (\"" + zelda64::renderer::special_option_texture_pack_enabled + "\"), but the config option doesn't have exactly 2 values.").c_str()); + } + return false; + } + + return true; + } + return false; +} diff --git a/src/ui/ui_mod_menu.cpp b/src/ui/ui_mod_menu.cpp index 5cc66ad..a1508c5 100644 --- a/src/ui/ui_mod_menu.cpp +++ b/src/ui/ui_mod_menu.cpp @@ -1,6 +1,7 @@ #include "ui_mod_menu.h" #include "recomp_ui.h" #include "zelda_support.h" +#include "zelda_render.h" #include "librecomp/mods.hpp" @@ -384,6 +385,22 @@ ContextId get_config_sub_menu_context_id() { return sub_menu_context; } +bool ModMenu::handle_special_config_options(const recomp::mods::ConfigOption& option, const recomp::mods::ConfigValueVariant& config_value) { + if (zelda64::renderer::is_texture_pack_enable_config_option(option, true)) { + const recomp::mods::ConfigOptionEnum &option_enum = std::get(option.variant); + + config_sub_menu->add_radio_option(option.id, option.name, option.description, std::get(config_value), option_enum.options, + [this](const std::string &id, uint32_t value) { + mod_enum_option_changed(id, value); + mod_hd_textures_enabled_changed(value); + }); + + return true; + } + + return false; +} + void ModMenu::mod_configure_requested() { if (active_mod_index >= 0) { // Record the context that was open when this function was called and close it. @@ -401,6 +418,10 @@ void ModMenu::mod_configure_requested() { continue; } + if (handle_special_config_options(option, config_value)) { + continue; + } + switch (option.type) { case recomp::mods::ConfigOptionType::Enum: { const recomp::mods::ConfigOptionEnum &option_enum = std::get(option.variant); @@ -455,6 +476,17 @@ void ModMenu::mod_number_option_changed(const std::string &id, double value) { } } +void ModMenu::mod_hd_textures_enabled_changed(uint32_t value) { + if (active_mod_index >= 0) { + if (value) { + zelda64::renderer::secondary_enable_texture_pack(mod_details[active_mod_index].mod_id); + } + else { + zelda64::renderer::secondary_disable_texture_pack(mod_details[active_mod_index].mod_id); + } + } +} + void ModMenu::create_mod_list() { ContextId context = get_current_context(); diff --git a/src/ui/ui_mod_menu.h b/src/ui/ui_mod_menu.h index 3f483db..086a320 100644 --- a/src/ui/ui_mod_menu.h +++ b/src/ui/ui_mod_menu.h @@ -74,9 +74,11 @@ private: void mod_selected(uint32_t mod_index); void mod_dragged(uint32_t mod_index, EventDrag drag); void mod_configure_requested(); + bool handle_special_config_options(const recomp::mods::ConfigOption& option, const recomp::mods::ConfigValueVariant& config_value); void mod_enum_option_changed(const std::string &id, uint32_t value); void mod_string_option_changed(const std::string &id, const std::string &value); void mod_number_option_changed(const std::string &id, double value); + void mod_hd_textures_enabled_changed(uint32_t value); void create_mod_list(); void process_event(const Event &e) override; diff --git a/src/ui/ui_prompt.cpp b/src/ui/ui_prompt.cpp index aea8bcf..5e6c179 100644 --- a/src/ui/ui_prompt.cpp +++ b/src/ui/ui_prompt.cpp @@ -234,6 +234,8 @@ void recompui::open_choice_prompt( std::function prev_cancel_action = std::move(prompt_state.cancel_action); + ContextId prev_context = try_close_current_context(); + prompt_state.ui_context.open(); prompt_state.prompt_header->set_text(header_text); @@ -252,6 +254,10 @@ void recompui::open_choice_prompt( prompt_state.ui_context.close(); + if (prev_context != ContextId::null()) { + prev_context.open(); + } + show_prompt(prev_cancel_action, focus_on_cancel); } @@ -267,6 +273,8 @@ void recompui::open_info_prompt( std::function prev_cancel_action = std::move(prompt_state.cancel_action); + ContextId prev_context = try_close_current_context(); + prompt_state.ui_context.open(); prompt_state.prompt_header->set_text(header_text); @@ -283,6 +291,10 @@ void recompui::open_info_prompt( prompt_state.ui_context.close(); + if (prev_context != ContextId::null()) { + prev_context.open(); + } + show_prompt(prev_cancel_action, true); } @@ -295,6 +307,8 @@ void recompui::open_notification( std::function prev_cancel_action = std::move(prompt_state.cancel_action); + ContextId prev_context = try_close_current_context(); + prompt_state.ui_context.open(); prompt_state.prompt_header->set_text(header_text); @@ -308,6 +322,10 @@ void recompui::open_notification( prompt_state.ui_context.close(); + if (prev_context != ContextId::null()) { + prev_context.open(); + } + show_prompt(prev_cancel_action, false); }