From d725125f9b12a48a5086944103ca3632daf85de5 Mon Sep 17 00:00:00 2001 From: lilacLunatic <8488221+lilacLunatic@users.noreply.github.com> Date: Tue, 17 Dec 2024 07:35:54 -0300 Subject: [PATCH] [Holiday] Custom rainbows (#4698) * [Holiday] Custom rainbows * Update soh/soh/Enhancements/Holiday/LL.h Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com> --------- Co-authored-by: briaguya <70942617+briaguya-ai@users.noreply.github.com> --- soh/soh/Enhancements/Holiday/LL.cpp | 129 ++++++++++++++++++ soh/soh/Enhancements/Holiday/LL.h | 86 ++++++++++++ .../cosmetics/CosmeticsEditor.cpp | 42 +++++- 3 files changed, 254 insertions(+), 3 deletions(-) create mode 100644 soh/soh/Enhancements/Holiday/LL.cpp create mode 100644 soh/soh/Enhancements/Holiday/LL.h diff --git a/soh/soh/Enhancements/Holiday/LL.cpp b/soh/soh/Enhancements/Holiday/LL.cpp new file mode 100644 index 00000000000..344d8043eca --- /dev/null +++ b/soh/soh/Enhancements/Holiday/LL.cpp @@ -0,0 +1,129 @@ +#include "Holiday.hpp" +#include "LL.h" + +extern "C" { +#include "macros.h" +#include "functions.h" +#include "variables.h" +extern PlayState* gPlayState; + +// TODO: Include anything you need here from C land +} + +// TODO: Change this to YourName +#define AUTHOR "LL" +#define CVAR(v) "gHoliday." AUTHOR "." v + +static ImVec4 customColorZero = RAINBOW_PRESETS[0][0]; +static ImVec4 customColorOne = RAINBOW_PRESETS[0][1]; +static ImVec4 customColorMinusZero = RAINBOW_PRESETS[0][2]; +static ImVec4 customColorMinusOne = RAINBOW_PRESETS[0][3]; + +ImVec4 Color_LUSToImGui(Color_RGBA8 color) { + ImVec4 result; + + result.x = color.r / 255.0f; + result.y = color.g / 255.0f; + result.z = color.b / 255.0f; + result.w = color.a / 255.0f; + + return result; +} + +Color_RGBA8 Color_ImGuiToLUS(ImVec4 color) { + Color_RGBA8 result; + + result.r = static_cast(color.x * 255); + result.g = static_cast(color.y * 255); + result.b = static_cast(color.z * 255); + result.a = static_cast(color.w * 255); + + return result; +} + +static void OnConfigurationChanged() { + Color_RGBA8 c1 = CVarGetColor(CVAR("lCustomRainbow1"), Color_ImGuiToLUS(RAINBOW_PRESETS[0][0])); + Color_RGBA8 c2 = CVarGetColor(CVAR("lCustomRainbow2"), Color_ImGuiToLUS(RAINBOW_PRESETS[0][1])); + Color_RGBA8 c3 = CVarGetColor(CVAR("lCustomRainbow3"), Color_ImGuiToLUS(RAINBOW_PRESETS[0][2])); + Color_RGBA8 c4 = CVarGetColor(CVAR("lCustomRainbow4"), Color_ImGuiToLUS(RAINBOW_PRESETS[0][3])); + + customColorZero = Color_LUSToImGui((Color_RGBA8)c1); + customColorOne = Color_LUSToImGui((Color_RGBA8)c2); + customColorMinusZero = Color_LUSToImGui((Color_RGBA8)c3); + customColorMinusOne = Color_LUSToImGui((Color_RGBA8)c4); + + // TODO: Register any hooks or things that need to run on startup and when the main CVar is toggled + // Note: Hooks should be registered/unregistered depending on the CVar state (Use COND_HOOK or COND_ID_HOOK) + + // COND_HOOK(OnSceneSpawnActors, CVarGetInteger(CVAR("Enabled"), 0), []() { + // // Spawn your own actors? + // }); + + // COND_ID_HOOK(OnActorInit, ACTOR_OBJ_TSUBO, CVarGetInteger(CVAR("DoSomethingWithPots"), 0), [](void* actorRef) { + // // Do something with pots? + // }); +} + +static void DrawMenu() { + ImGui::SeparatorText(AUTHOR); + if (ImGui::BeginMenu("Customize Rainbows")) { + UIWidgets::EnhancementCheckbox("Enable", CVAR("lEnableCustomRainbows")); + if (CVarGetInteger(CVAR("lEnableCustomRainbows"), 0)) { + ImGui::ColorEdit3("Color 1", (float*)&customColorZero, ImGuiColorEditFlags_NoInputs); + ImGui::ColorEdit3("Color 2", (float*)&customColorOne, ImGuiColorEditFlags_NoInputs); + ImGui::ColorEdit3("Color 3", (float*)&customColorMinusZero, ImGuiColorEditFlags_NoInputs); + ImGui::ColorEdit3("Color 4", (float*)&customColorMinusOne, ImGuiColorEditFlags_NoInputs); + + UIWidgets::PaddedText("Presets", true, false); + size_t rainbowPresetIdx = 0; + if (UIWidgets::EnhancementCombobox(CVAR("lCustomRainbowPreset"), RAINBOW_PRESET_NAMES, 0) && + (rainbowPresetIdx = CVarGetInteger(CVAR("lCustomRainbowPreset"), 0)) <= RAINBOW_PRESET_LEN) { //paranoia + customColorZero = RAINBOW_PRESETS[rainbowPresetIdx][0]; + customColorOne = RAINBOW_PRESETS[rainbowPresetIdx][1]; + customColorMinusZero = RAINBOW_PRESETS[rainbowPresetIdx][2]; + customColorMinusOne = RAINBOW_PRESETS[rainbowPresetIdx][3]; + } + + Color_RGBA8 color1, color2, color3, color4; + color1.r = static_cast(customColorZero.x * 255.0f); + color1.g = static_cast(customColorZero.y * 255.0f); + color1.b = static_cast(customColorZero.z * 255.0f); + + color2.r = static_cast(customColorOne.x * 255.0f); + color2.g = static_cast(customColorOne.y * 255.0f); + color2.b = static_cast(customColorOne.z * 255.0f); + + color3.r = static_cast(customColorMinusZero.x * 255.0f); + color3.g = static_cast(customColorMinusZero.y * 255.0f); + color3.b = static_cast(customColorMinusZero.z * 255.0f); + + color4.r = static_cast(customColorMinusOne.x * 255.0f); + color4.g = static_cast(customColorMinusOne.y * 255.0f); + color4.b = static_cast(customColorMinusOne.z * 255.0f); + + CVarSetColor(CVAR("lCustomRainbow1"), color1); + CVarSetColor(CVAR("lCustomRainbow2"), color2); + CVarSetColor(CVAR("lCustomRainbow3"), color3); + CVarSetColor(CVAR("lCustomRainbow4"), color4); + + OnConfigurationChanged(); + } + + ImGui::EndMenu(); + + } + //if (UIWidgets::EnhancementCheckbox("DoSomethingWithPots", CVAR("DoSomethingWithPots"))) { + // OnConfigurationChanged(); + //} +} + +static void RegisterMod() { + // #region Leave this alone unless you know what you are doing + OnConfigurationChanged(); + // #endregion + + // TODO: Anything you want to run once on startup +} + +// TODO: Uncomment this line to enable the mod +static Holiday holiday(DrawMenu, RegisterMod); diff --git a/soh/soh/Enhancements/Holiday/LL.h b/soh/soh/Enhancements/Holiday/LL.h new file mode 100644 index 00000000000..ba936b6c307 --- /dev/null +++ b/soh/soh/Enhancements/Holiday/LL.h @@ -0,0 +1,86 @@ +#ifndef LL_H +#define LL_H + +#include "soh/Enhancements/cosmetics/CosmeticsEditor.h" +#include "soh/Enhancements/game-interactor/GameInteractor.h" + +const size_t RAINBOW_PRESET_LEN = 9; + +static const char* RAINBOW_PRESET_NAMES[RAINBOW_PRESET_LEN] = { + "Christmas", + "Transgender", + "Nonbinary", + "Bisexual", + "Lesbian", + "Gay (MLM)", + "Asexual", + "Brazil", + "Italy" +}; + +static const ImVec4 RAINBOW_PRESETS[RAINBOW_PRESET_LEN][4] = { + { //christmas + {0.0/255.0, 140.0/255.0, 69.0/255.0, 0}, + {205.0/255.0, 33.0/255.0, 42.0/255.0, 0}, + {0.0/255.0, 140.0/255.0, 69.0/255.0, 0}, + {205.0/255.0, 33.0/255.0, 42.0/255.0, 0} + }, + { //trans + {255.0/255.0, 255.0/255.0, 255.0/255.0, 0}, + {255.0/255.0, 159.0/255.0, 186.0/255.0, 0}, + {255.0/255.0, 255.0/255.0, 255.0/255.0, 0}, + {71.0/255.0, 186.0/255.0, 230.0/255.0, 0} + }, + + { //enby + {252.0/255.0, 244.0/255.0, 52.0/255.0, 0}, + {255.0/255.0, 255.0/255.0, 255.0/255.0, 0}, + {156.0/255.0, 89.0/255.0, 209.0/255.0, 0}, + {0.0/255.0, 0.0/255.0, 0.0/255.0, 0} + }, + + { //bi + {155.0/255.0, 79.0/255.0, 150.0/255.0, 0}, + {0.0/255.0, 56.0/255.0, 168.0/255.0, 0}, + {155.0/255.0, 79.0/255.0, 150.0/255.0, 0}, + {214.0/255.0, 2.0/255.0, 112.0/255.0, 0} + }, + + { //lesbian + {255.0/255.0, 255.0/255.0, 255.0/255.0, 0}, + {213.0/255.0, 45.0/255.0, 0.0/255.0, 0}, + {255.0/255.0, 255.0/255.0, 255.0/255.0, 0}, + {163.0/255.0, 2.0/255.0, 98.0/255.0, 0} + }, + + { //gay + {7.0/255.0, 141.0/255.0, 112.0/255.0, 0}, + {255.0/255.0, 255.0/255.0, 255.0/255.0, 0}, + {123.0/255.0, 173.0/255.0, 226.0/255.0, 0}, + {61.0/255.0, 26.0/255.0, 120.0/255.0, 0} + }, + + { //ace + {0.0/255.0, 0.0/255.0, 0.0/255.0, 0}, + {163.0/255.0, 163.0/255.0, 163.0/255.0, 0}, + {255.0/255.0, 255.0/255.0, 255.0/255.0, 0}, + {128.0/255.0, 0.0/255.0, 128.0/255.0, 0} + }, + + { //br + {0.0/255.0, 151.0/255.0, 57.0/255.0, 0}, + {254.0/255.0, 221.0/255.0, 0.0/255.0, 0}, + {255.0/255.0, 255.0/255.0, 255.0/255.0, 0}, + {1.0/255.0, 33.0/255.0, 105.0/255.0, 0} + }, + + { //it + {255.0/255.0, 255.0/255.0, 255.0/255.0, 0}, + {0.0/255.0, 140.0/255.0, 69.0/255.0, 0}, + {255.0/255.0, 255.0/255.0, 255.0/255.0, 0}, + {205.0/255.0, 33.0/255.0, 42.0/255.0, 0} + } + +}; + +#endif diff --git a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp index ee6b08fd46a..426101fdd61 100644 --- a/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp +++ b/soh/soh/Enhancements/cosmetics/CosmeticsEditor.cpp @@ -493,6 +493,8 @@ void ResetPositionAll() { int hue = 0; +#define CVAR_LL(v) "gHoliday." "LL" "." v + // Runs every frame to update rainbow hue, a potential future optimization is to only run this a once or twice a second and increase the speed of the rainbow hue rotation. void CosmeticsUpdateTick() { int index = 0; @@ -501,10 +503,44 @@ void CosmeticsUpdateTick() { if (cosmeticOption.supportsRainbow && CVarGetInteger(cosmeticOption.rainbowCvar, 0)) { double frequency = 2 * M_PI / (360 * rainbowSpeed); Color_RGBA8 newColor; - newColor.r = static_cast(sin(frequency * (hue + index) + 0) * 127) + 128; - newColor.g = static_cast(sin(frequency * (hue + index) + (2 * M_PI / 3)) * 127) + 128; - newColor.b = static_cast(sin(frequency * (hue + index) + (4 * M_PI / 3)) * 127) + 128; + newColor.a = 255; + + if (!CVarGetInteger(CVAR_LL("lEnableCustomRainbows"), 0)) { + newColor.r = static_cast(sin(frequency * (hue + index) + 0) * 127) + 128; + newColor.g = static_cast(sin(frequency * (hue + index) + (2 * M_PI / 3)) * 127) + 128; + newColor.b = static_cast(sin(frequency * (hue + index) + (4 * M_PI / 3)) * 127) + 128; + } + else { + Color_RGBA8 customColorZero = CVarGetColor(CVAR_LL("lCustomRainbow1"), {}); + Color_RGBA8 customColorOne = CVarGetColor(CVAR_LL("lCustomRainbow2"), {}); + Color_RGBA8 customColorMinusZero = CVarGetColor(CVAR_LL("lCustomRainbow3"), {}); + Color_RGBA8 customColorMinusOne = CVarGetColor(CVAR_LL("lCustomRainbow4"), {}); + float sinangle = sin(frequency * (hue + index)); + bool quadrant1 = hue <= (360 * rainbowSpeed) / 4; + bool quadrant2 = hue >= (360 * rainbowSpeed) / 4 && hue <= (360 * rainbowSpeed) / 2; + bool quadrant3 = hue >= (360 * rainbowSpeed) / 2 && hue <= (360 * rainbowSpeed) * 3 / 4; + bool quadrant4 = hue >= (360 * rainbowSpeed) * 3 / 4; + + if (quadrant1) { //zero to one + newColor.r = sinangle * (customColorOne.r - customColorZero.r) + customColorZero.r; + newColor.g = sinangle * (customColorOne.g - customColorZero.g) + customColorZero.g; + newColor.b = sinangle * (customColorOne.b - customColorZero.b) + customColorZero.b; + } else if (quadrant2) { //one to zero + newColor.r = sinangle * (customColorOne.r - customColorMinusZero.r) + customColorMinusZero.r; + newColor.g = sinangle * (customColorOne.g - customColorMinusZero.g) + customColorMinusZero.g; + newColor.b = sinangle * (customColorOne.b - customColorMinusZero.b) + customColorMinusZero.b; + } else if (quadrant3) { //zero to minus one + newColor.r = -sinangle * (customColorMinusOne.r - customColorMinusZero.r) + customColorMinusZero.r; + newColor.g = -sinangle * (customColorMinusOne.g - customColorMinusZero.g) + customColorMinusZero.g; + newColor.b = -sinangle * (customColorMinusOne.b - customColorMinusZero.b) + customColorMinusZero.b; + } else if (quadrant4) { //minus one to zero + newColor.r = -sinangle * (customColorMinusOne.r - customColorZero.r) + customColorZero.r; + newColor.g = -sinangle * (customColorMinusOne.g - customColorZero.g) + customColorZero.g; + newColor.b = -sinangle * (customColorMinusOne.b - customColorZero.b) + customColorZero.b; + } + } + // For alpha supported options, retain the last set alpha instead of overwriting if (cosmeticOption.supportsAlpha) { newColor.a = static_cast(cosmeticOption.currentColor.w * 255.0f);