Split cosmetics mod into submodule (#2378)

This commit is contained in:
jdflyer
2026-09-03 09:21:50 -06:00
committed by GitHub
parent 8551f5e0e4
commit 6a7acc8ddc
16 changed files with 5 additions and 2468 deletions
+3
View File
@@ -7,3 +7,6 @@
[submodule "mods/randomizer"]
path = mods/randomizer
url = https://github.com/TwilitRealm/dusklight-randomizer.git
[submodule "mods/cosmetics"]
path = mods/cosmetics
url = https://github.com/TwilitRealm/dusklight-cosmetics
+1 -1
View File
@@ -571,7 +571,7 @@ if (DUSK_ENABLE_CODE_MODS AND CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR
add_subdirectory(mods/shadow_mod)
add_subdirectory(mods/window_demo)
add_subdirectory(mods/flow_demo)
add_subdirectory(mods/basic_cosmetics_mod)
add_subdirectory(mods/cosmetics)
add_subdirectory(mods/randomizer)
endif ()
-35
View File
@@ -1,35 +0,0 @@
cmake_minimum_required(VERSION 3.25)
project(basic_cosmetics_mod CXX)
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
set(DUSK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../.." CACHE PATH "Path to dusk source root")
option(DUSK_MOD_USE_FULL_TREE "Use full build instead of the minimal mod SDK" OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
if (DUSK_MOD_USE_FULL_TREE)
add_subdirectory("${DUSK_DIR}" dusk EXCLUDE_FROM_ALL)
else ()
add_subdirectory("${DUSK_DIR}/sdk" dusk-sdk EXCLUDE_FROM_ALL)
endif ()
endif ()
include(FetchContent)
message(STATUS "basic_cosmetics_mod: Fetching xxhash")
FetchContent_Declare(
xxhash
GIT_REPOSITORY https://github.com/Cyan4973/xxHash.git
GIT_TAG v0.8.3
)
FetchContent_MakeAvailable(xxhash)
set(COSMETIC_SOURCES src/color_utils.cpp src/midna_hair_color.cpp src/texture_utils.cpp src/hooks.cpp)
add_mod(basic_cosmetics_mod
FEATURES game fmt
SOURCES src/mod.cpp ${COSMETIC_SOURCES}
MOD_JSON mod.json
RES_DIR res
BUNDLE
)
target_link_libraries(basic_cosmetics_mod PRIVATE xxHash::xxhash)
-7
View File
@@ -1,7 +0,0 @@
{
"id": "dev.twilitrealm.basic_cosmetics",
"name": "Basic Cosmetics",
"version": "1.0.0",
"author": "Twilit Realm",
"description": "Change Basic Cosmetic Colors"
}
@@ -1,88 +0,0 @@
#include "color_utils.hpp"
uint8_t desaturate_rgb_565(uint16_t rgb565Val) {
const uint32_t r = (rgb565Val & 0xf800) >> 11;
const uint32_t g = (rgb565Val & 0x7e0) >> 5;
const uint32_t b = rgb565Val & 0x1f;
// Here we are doing a quicker (0.22 * r + 0.72 * g + 0.06 * b) which
// uses multiplies and shifts rather than division.
const uint32_t combined = 30480413 * r + 49085341 * g + 8312839 * b;
uint8_t shifted = (combined >> 24) & 0xff;
// Check if should round up shifted value.
if (shifted < 0xff && combined & 0x00800000) {
shifted += 1;
}
return shifted;
}
uint16_t blend_overlay_rgb_565(uint8_t grayVal, GXColor color) {
uint32_t rTimes255, gTimes255, bTimes255;
if (grayVal <= 0x7f) {
const uint32_t grayTimesTwo = 2 * grayVal;
rTimes255 = grayTimesTwo * color.r;
gTimes255 = grayTimesTwo * color.g;
bTimes255 = grayTimesTwo * color.b;
} else {
const uint32_t multiplier = 2 * (255 - grayVal);
rTimes255 = 255 * 255 - multiplier * (255 - color.r);
gTimes255 = 255 * 255 - multiplier * (255 - color.g);
bTimes255 = 255 * 255 - multiplier * (255 - color.b);
}
// Divide each by 255
const uint32_t r = (rTimes255 + 1 + (rTimes255 >> 8)) >> 8;
const uint32_t g = (gTimes255 + 1 + (gTimes255 >> 8)) >> 8;
const uint32_t b = (bTimes255 + 1 + (bTimes255 >> 8)) >> 8;
return ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
}
// Helper function to perform overlay blending on a single 8-bit color channel
uint8_t blend_overlay_channel(uint8_t base, uint8_t blend) {
if (base < 128) {
return static_cast<uint8_t>((2 * base * blend) / 255);
}
return static_cast<uint8_t>(255 - (2 * (255 - base) * (255 - blend)) / 255);
}
bool is_valid_hex_color_str(std::string_view hexStr) {
return hexStr.find_first_not_of("0123456789ABCDEFabcdef") == std::string_view::npos &&
hexStr.length() == 6;
}
GXColor hex_color_str_to_gx_color(const std::string& hexColorStr) {
u8 r = std::stoi(hexColorStr.substr(0, 2), nullptr, 16);
u8 g = std::stoi(hexColorStr.substr(2, 2), nullptr, 16);
u8 b = std::stoi(hexColorStr.substr(4, 2), nullptr, 16);
return GXColor{r, g, b};
}
static f32 rainbowPhaseAngle = 0.f;
GXColor get_rainbow_rgb(f32 amplitude) {
f32 phase_rad = rainbowPhaseAngle * M_PI / 180.0f;
u8 r_val = (u8)(amplitude * (sinf(phase_rad) + 1.0f) + 0.5f);
u8 g_val = (u8)(amplitude * (sinf(phase_rad + 2.0f * M_PI / 3.0f) + 1.0f) + 0.5f);
u8 b_val = (u8)(amplitude * (sinf(phase_rad + 4.0f * M_PI / 3.0f) + 1.0f));
GXColor rgbColor;
rgbColor.r = r_val;
rgbColor.g = g_val;
rgbColor.b = b_val;
rgbColor.a = 0xff;
return rgbColor;
}
void update_rainbow_rgb(f32 increment) {
rainbowPhaseAngle += increment;
if (rainbowPhaseAngle >= 360.0f) {
rainbowPhaseAngle -= 360.0f;
}
}
@@ -1,30 +0,0 @@
#pragma once
/**
* File originally copied from console TPR with permission from isaac
* https://github.com/zsrtp/libtp_rel/blob/master/include/util/color_utils.h
*/
#include <gx.h>
#include <cstdint>
#include <string>
// Desaturates an RGB565 color to a u8 gray value (0xFF being white and 0x00
// being black).
uint8_t desaturate_rgb_565(uint16_t rgb565Val);
// Performs an "Overlay" blend of a u8 gray value and a pointer to a u8
// array of {r,g,b}. Returns the result as an RGB565.
uint16_t blend_overlay_rgb_565(uint8_t grayVal, GXColor color);
// Perform overlay blending on a single 8-bit color channel
uint8_t blend_overlay_channel(uint8_t base, uint8_t blend);
bool is_valid_hex_color_str(std::string_view hexStr);
GXColor hex_color_str_to_gx_color(const std::string& hexColorStr);
GXColor get_rainbow_rgb(f32 amplitude);
void update_rainbow_rgb(f32 increment);
File diff suppressed because it is too large Load Diff
-7
View File
@@ -1,7 +0,0 @@
#pragma once
#include "mods/service.hpp"
ModResult add_all_hooks();
ModResult remove_all_hooks();
@@ -1,115 +0,0 @@
#include "midna_hair_color.hpp"
#include "mod.hpp"
#include "mods/svc/log.hpp"
#include <array>
namespace {
constexpr std::array<std::array<GXColor, 9>, 10> kMidnaHairColors = {{
// Default
{{
/*l_lNormalKColor*/ /*l_normalKColor*/ /*l_normalColor*/
{0xFF, 0xDC, 0x00}, {0xB4, 0x87, 0x00}, {0x50, 0x00, 0x00},
/*l_bigKColor*/ /*l_lBigColor*/ /*l_bigColor*/
{0x1E, 0x00, 0x00}, {0xFF, 0x78, 0x00}, {0xFF, 0x64, 0x78},
/*l_lNormalKColor2*//*l_normalKColor2*/ /*l_lBigKColor2*/
{0x00, 0xC3, 0xEB}, {0x00, 0xC3, 0xC3}, {0xAA, 0xFF, 0xC3}
}},
// Pink
{{
{0xF5, 0xCF, 0xF3}, {0xAD, 0x7F, 0x7F}, {0x1B, 0x00, 0x20},
{0x3C, 0x02, 0x58}, {0xE3, 0x72, 0xF2}, {0xE3, 0x5F, 0xF8},
{0xDD, 0x00, 0xEB}, {0xDD, 0x00, 0xC3}, {0xF6, 0x4C, 0xFF}
}},
// Red
{{
{0xE4, 0x65, 0x41}, {0xA1, 0x3E, 0x22}, {0x21, 0x00, 0x00},
{0x4F, 0x02, 0x01}, {0xF0, 0x3A, 0x25}, {0xF0, 0x30, 0x8C},
{0xEB, 0x00, 0x00}, {0xEB, 0x00, 0x00}, {0xFF, 0x4F, 0x3A}
}},
// Yellow
{{
{0x91, 0x83, 0x0E}, {0x66, 0x50, 0x07}, {0x0E, 0x0B, 0x00},
{0x24, 0x25, 0x02}, {0xCB, 0xB7, 0x00}, {0xCB, 0x99, 0x78},
{0xEB, 0xDE, 0x00}, {0xEB, 0xDE, 0x00}, {0xFF, 0xF8, 0xBF}
}},
// Green
{{
{0x35, 0x79, 0x53}, {0x25, 0x4A, 0x2B}, {0x00, 0x0E, 0x05},
{0x0A, 0x29, 0x10}, {0x00, 0xB6, 0x6F}, {0x00, 0x98, 0xB3},
{0x1F, 0xEB, 0x00}, {0x1F, 0xEB, 0x00}, {0x9A, 0xFF, 0x81}
}},
// Blue
{{
{0x00, 0x72, 0xFF}, {0x00, 0x46, 0x85}, {0x00, 0x08, 0x28},
{0x16, 0x1B, 0x5D}, {0x00, 0x60, 0xFF}, {0x00, 0x50, 0xFF},
{0x00, 0x48, 0xEB}, {0x00, 0x48, 0xC3}, {0x3A, 0x66, 0xFF}
}},
// Purple
{{
{0x6F, 0x34, 0xFF}, {0x4E, 0x20, 0x85}, {0x0D, 0x00, 0x34},
{0x15, 0x08, 0x79}, {0x62, 0x00, 0xFF}, {0x62, 0x00, 0xFF},
{0x7B, 0x00, 0xEB}, {0x7B, 0x00, 0xC3}, {0x94, 0x3E, 0xFF}
}},
// Brown
{{
{0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x1A, 0x05, 0x00},
{0x3C, 0x19, 0x0E}, {0x3F, 0x1D, 0x0B}, {0x3F, 0x18, 0x7E},
{0x3F, 0x1D, 0x0B}, {0x3F, 0x1D, 0x09}, {0x59, 0x32, 0x1E}
}},
// White
{{
{0xF0, 0xF1, 0xF1}, {0xA9, 0x94, 0x7E}, {0x09, 0x0B, 0x0C},
{0x22, 0x24, 0x24}, {0xFF, 0xFF, 0xFF}, {0xFF, 0xD5, 0xFF},
{0xEA, 0xEA, 0xEA}, {0xEA, 0xEA, 0xC2}, {0xF3, 0xF3, 0xF3}
}},
// Black
{{
{0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x0B, 0x0B, 0x0B},
{0x23, 0x23, 0x23}, {0x00, 0x00, 0x00}, {0x00, 0x00, 0x78},
{0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}, {0x00, 0x00, 0x00}
}}
}};
size_t get_midna_hair_color_index(ConfigVarHandle handle) {
const auto optionIndex = get_int_option(handle, 0);
if (optionIndex < 0 || optionIndex >= static_cast<int64_t>(kMidnaHairColors.size())) {
return 0;
}
return static_cast<size_t>(optionIndex);
}
}
MidnaHairColors g_currentMidnaHairColors = {
.normalColor = {0x50, 0x00, 0x00, 0x00},
.normalKColor = {0xB4, 0x87, 0x00, 0x00},
.normalKColor2 = {0x00, 0xC3, 0xC3, 0x00},
.bigColor = {0xFF, 0x64, 0x78, 0x00},
.bigKColor = {0x1E, 0x00, 0x00, 0x00},
.lNormalKColor = {0xFF, 0xDC, 0x00, 0x00},
.lNormalKColor2 = {0x00, 0xC3, 0xEB, 0x00},
.lBigColor = {0xFF, 0x78, 0x00, 0x00},
.lBigKColor2 = {0xAA, 0xFF, 0xC3, 0x00},
};
void set_all_midna_hair_colors() {
auto& g_cvars = get_cvars();
auto hairBaseColor = get_midna_hair_color_index(g_cvars.midnaHairBaseColor);
auto hairTipsColor = get_midna_hair_color_index(g_cvars.midnaHairTipsColor);
// Colors we have to convert to GXColorS10
auto& normalColor = kMidnaHairColors.at(hairBaseColor)[2];
auto& bigColor = kMidnaHairColors.at(hairBaseColor)[5];
auto& lBigColor = kMidnaHairColors.at(hairBaseColor)[4];
g_currentMidnaHairColors.normalColor = GXColorS10{normalColor.r, normalColor.g, normalColor.b};
g_currentMidnaHairColors.normalKColor = kMidnaHairColors.at(hairBaseColor)[1];
g_currentMidnaHairColors.normalKColor2 = kMidnaHairColors.at(hairTipsColor)[7];
g_currentMidnaHairColors.bigColor = GXColorS10{bigColor.r, bigColor.g, bigColor.b};
g_currentMidnaHairColors.bigKColor = kMidnaHairColors.at(hairBaseColor)[3];
g_currentMidnaHairColors.lNormalKColor = kMidnaHairColors.at(hairBaseColor)[0];
g_currentMidnaHairColors.lNormalKColor2 = kMidnaHairColors.at(hairTipsColor)[6];
g_currentMidnaHairColors.lBigColor = GXColorS10{lBigColor.r, lBigColor.g, lBigColor.b};
g_currentMidnaHairColors.lBigKColor2 = kMidnaHairColors.at(hairTipsColor)[8];
}
@@ -1,19 +0,0 @@
#pragma once
#include <gx.h>
struct MidnaHairColors {
GXColorS10 normalColor;
GXColor normalKColor;
GXColor normalKColor2;
GXColorS10 bigColor;
GXColor bigKColor;
GXColor lNormalKColor;
GXColor lNormalKColor2;
GXColorS10 lBigColor;
GXColor lBigKColor2;
};
extern MidnaHairColors g_currentMidnaHairColors;
void set_all_midna_hair_colors();
File diff suppressed because it is too large Load Diff
-65
View File
@@ -1,65 +0,0 @@
#pragma once
#include "mods/svc/config.h"
#include "mods/svc/texture.h"
#include <gx.h>
#include <optional>
#include <string>
#include <vector>
struct cvars {
ConfigVarHandle herosTunicCapColor = 0;
ConfigVarHandle herosTunicTorsoColor = 0;
ConfigVarHandle herosTunicSkirtColor = 0;
ConfigVarHandle zoraArmorCapColor = 0;
ConfigVarHandle zoraArmorHelmetColor = 0;
ConfigVarHandle zoraArmorTorsoColor = 0;
ConfigVarHandle zoraArmorScalesColor = 0;
ConfigVarHandle zoraArmorFlippersColor = 0;
ConfigVarHandle lanternGlowColor = 0;
ConfigVarHandle woodenSwordColor = 0;
ConfigVarHandle ordonSwordBladeColor = 0;
ConfigVarHandle ordonSwordHandleColor = 0;
ConfigVarHandle msBladeColor = 0;
ConfigVarHandle msHandleColor = 0;
ConfigVarHandle lightSwordGlowColor = 0;
ConfigVarHandle boomerangColor = 0;
ConfigVarHandle ironBootsColor = 0;
ConfigVarHandle spinnerColor = 0;
ConfigVarHandle heartColor = 0;
ConfigVarHandle aButtonColor = 0;
ConfigVarHandle bButtonColor = 0;
ConfigVarHandle xButtonColor = 0;
ConfigVarHandle yButtonColor = 0;
ConfigVarHandle zButtonColor = 0;
ConfigVarHandle midnaHairBaseColor = 0;
ConfigVarHandle midnaHairTipsColor = 0;
ConfigVarHandle midnaChargeRingColor = 0;
ConfigVarHandle linkHairColor = 0;
ConfigVarHandle wolfLinkColor = 0;
ConfigVarHandle eponaColor = 0;
};
struct TextureReplacementData {
const char* arc{};
const char* modelFileName{};
const char* textureName{};
uint64_t textureHash{};
uint64_t tlutHash{};
TextureKey key = TEXTURE_KEY_INIT;
TextureData data = TEXTURE_DATA_INIT;
TextureReplacementHandle handle{};
std::vector<u8> baseTextureData{};
bool loadedTextureData = false;
std::optional<GXColor> curColor{};
};
cvars& get_cvars();
std::string get_str_option(ConfigVarHandle handle, const std::string& fallback);
int64_t get_int_option(ConfigVarHandle handle, int64_t fallback);
std::optional<GXColor> get_config_var_color(ConfigVarHandle handle, bool allowRainbow = false);
File diff suppressed because it is too large Load Diff
@@ -1,21 +0,0 @@
#pragma once
/**
* File originally copied from console TPR with permission from isaac
* https://github.com/zsrtp/libtp_rel/blob/master/include/util/texture_utils.h
*/
#include "mod.hpp"
#include <gx.h>
#include <list>
#include <unordered_map>
uint32_t get_image_data_size(
uint32_t format, uint32_t width, uint32_t height, uint32_t mipmapCount);
void recolor_texture(
TextureReplacementData& replacementData, GXColor color, std::vector<u8>& newTextureDataOut);
std::unordered_map<ConfigVarHandle, std::list<TextureReplacementData>>& get_texture_replacements();
+1
Submodule mods/cosmetics added at 93971c38aa