diff --git a/sysmodules/rosalina/include/menu.h b/sysmodules/rosalina/include/menu.h index 5d2807c..8e5f0ae 100644 --- a/sysmodules/rosalina/include/menu.h +++ b/sysmodules/rosalina/include/menu.h @@ -75,6 +75,7 @@ extern bool preTerminationRequested; extern Handle preTerminationEvent; u32 waitInputWithTimeout(s32 msec); +u32 waitInputWithTimeoutEx(u32 *outHeldKeys, s32 msec); u32 waitInput(void); u32 waitComboWithTimeout(s32 msec); diff --git a/sysmodules/rosalina/include/menus/screen_filters.h b/sysmodules/rosalina/include/menus/screen_filters.h index 3fdaee1..679af8f 100644 --- a/sysmodules/rosalina/include/menus/screen_filters.h +++ b/sysmodules/rosalina/include/menus/screen_filters.h @@ -49,3 +49,5 @@ void ScreenFiltersMenu_SetIncandescent(void); // 2700K void ScreenFiltersMenu_SetWarmIncandescent(void); // 2300K void ScreenFiltersMenu_SetCandle(void); // 1900K void ScreenFiltersMenu_SetEmber(void); // 1200K + +void ScreenFiltersMenu_AdvancedConfiguration(void); diff --git a/sysmodules/rosalina/include/utils.h b/sysmodules/rosalina/include/utils.h index 7f9a910..f531d90 100644 --- a/sysmodules/rosalina/include/utils.h +++ b/sysmodules/rosalina/include/utils.h @@ -41,6 +41,8 @@ #define REG32(addr) (*(vu32 *)(PA_PTR(addr))) +#define CLAMP(v, m, M) ((v) <= (m) ? (m) : (v) >= (M) ? (M) : (v)) + static inline u32 makeArmBranch(const void *src, const void *dst, bool link) // the macros for those are ugly and buggy { u32 instrBase = link ? 0xEB000000 : 0xEA000000; @@ -68,3 +70,4 @@ void formatMemoryPermission(char *outbuf, MemPerm perm); void formatUserMemoryState(char *outbuf, MemState state); u32 formatMemoryMapOfProcess(char *outbuf, u32 bufLen, Handle handle); int dateTimeToString(char *out, u64 msSince1900, bool filenameFormat); +int floatToString(char *out, float f, u32 precision, bool pad); diff --git a/sysmodules/rosalina/source/menu.c b/sysmodules/rosalina/source/menu.c index f5c1f61..68638d3 100644 --- a/sysmodules/rosalina/source/menu.c +++ b/sysmodules/rosalina/source/menu.c @@ -81,6 +81,33 @@ u32 waitInputWithTimeout(s32 msec) return keys; } +u32 waitInputWithTimeoutEx(u32 *outHeldKeys, s32 msec) +{ + s32 n = 0; + u32 keys; + + do + { + svcSleepThread(1 * 1000 * 1000LL); + Draw_Lock(); + if (!isHidInitialized || menuShouldExit) + { + keys = 0; + Draw_Unlock(); + break; + } + n++; + + hidScanInput(); + keys = convertHidKeys(hidKeysDown()) | (convertHidKeys(hidKeysDownRepeat()) & DIRECTIONAL_KEYS); + *outHeldKeys = convertHidKeys(hidKeysHeld()); + Draw_Unlock(); + } while (keys == 0 && !menuShouldExit && isHidInitialized && (msec < 0 || n < msec)); + + + return keys; +} + u32 waitInput(void) { return waitInputWithTimeout(-1); diff --git a/sysmodules/rosalina/source/menus/screen_filters.c b/sysmodules/rosalina/source/menus/screen_filters.c index 84c00ca..98a7d7e 100644 --- a/sysmodules/rosalina/source/menus/screen_filters.c +++ b/sysmodules/rosalina/source/menus/screen_filters.c @@ -59,7 +59,8 @@ static inline bool ScreenFiltersMenu_IsDefaultSettings(void) static inline u8 ScreenFiltersMenu_GetColorLevel(int inLevel, float wp, float a, float b, float g) { float level = inLevel / 255.0f; - level = powf(a * wp * level + b, g); + level = a * wp * level + b; + level = powf(CLAMP(level, 0.0f, 1.0f), g); s32 levelInt = (s32)(255.0f * level + 0.5f); // round to nearest integer return levelInt <= 0 ? 0 : levelInt >= 255 ? 255 : (u8)levelInt; // clamp } @@ -105,6 +106,7 @@ Menu screenFiltersMenu = { { "[2300K] Warm Incandescent", METHOD, .method = &ScreenFiltersMenu_SetWarmIncandescent }, { "[1900K] Candle", METHOD, .method = &ScreenFiltersMenu_SetCandle }, { "[1200K] Ember", METHOD, .method = &ScreenFiltersMenu_SetEmber }, + { "Advanced configuration", METHOD, .method = &ScreenFiltersMenu_AdvancedConfiguration }, {}, } }; @@ -137,3 +139,83 @@ DEF_CCT_SETTER(2700, Incandescent) DEF_CCT_SETTER(2300, WarmIncandescent) DEF_CCT_SETTER(1900, Candle) DEF_CCT_SETTER(1200, Ember) + +static void ScreenFiltersMenu_AdvancedConfigurationChangeValue(int pos, int mult) +{ + switch (pos) + { + case 0: + screenFiltersCurrentTemperature += 100 * mult; + break; + case 1: + screenFiltersCurrentGamma += 0.01f * mult; + break; + case 2: + screenFiltersCurrentContrast += 0.01f * mult; + break; + case 3: + screenFiltersCurrentBrightness += 0.01f * mult; + break; + } + + // Clamp + screenFiltersCurrentTemperature = CLAMP(screenFiltersCurrentTemperature, 1000, 25100); + screenFiltersCurrentGamma = CLAMP(screenFiltersCurrentGamma, 0.0f, 1411.0f); // ln(255) / ln(254/255): (254/255)^1411 <= 1/255 + screenFiltersCurrentContrast = CLAMP(screenFiltersCurrentContrast, 0.0f, 255.0f); + screenFiltersCurrentBrightness = CLAMP(screenFiltersCurrentBrightness, -1.0f, 1.0f); + + // Update the LUT + ScreenFiltersMenu_ApplyColorSettings(); +} + +void ScreenFiltersMenu_AdvancedConfiguration(void) +{ + u32 posY; + u32 input = 0; + u32 held = 0; + + char buf[64]; + int pos = 0; + int mult = 1; + + do + { + Draw_Lock(); + Draw_DrawString(10, 10, COLOR_TITLE, "Screen filters menu"); + + posY = 30; + posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Use left/right to increase/decrease the sel. value.\n"); + posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Hold R to change the value faster.\n") + SPACING_Y; + + Draw_DrawCharacter(10, posY, COLOR_TITLE, pos == 0 ? '>' : ' '); + posY = Draw_DrawFormattedString(30, posY, COLOR_WHITE, "Temperature: %12dK \n", screenFiltersCurrentTemperature); + + floatToString(buf, screenFiltersCurrentGamma, 2, true); + Draw_DrawCharacter(10, posY, COLOR_TITLE, pos == 1 ? '>' : ' '); + posY = Draw_DrawFormattedString(30, posY, COLOR_WHITE, "Gamma: %13s \n", buf); + + floatToString(buf, screenFiltersCurrentContrast, 2, true); + Draw_DrawCharacter(10, posY, COLOR_TITLE, pos == 2 ? '>' : ' '); + posY = Draw_DrawFormattedString(30, posY, COLOR_WHITE, "Contrast: %13s \n", buf); + + floatToString(buf, screenFiltersCurrentBrightness, 2, true); + Draw_DrawCharacter(10, posY, COLOR_TITLE, pos == 3 ? '>' : ' '); + posY = Draw_DrawFormattedString(30, posY, COLOR_WHITE, "Brightness: %13s \n", buf); + + input = waitInputWithTimeoutEx(&held, -1); + mult = (held & KEY_R) ? 10 : 1; + + if (input & KEY_LEFT) + ScreenFiltersMenu_AdvancedConfigurationChangeValue(pos, -mult); + if (input & KEY_RIGHT) + ScreenFiltersMenu_AdvancedConfigurationChangeValue(pos, mult); + if (input & KEY_UP) + pos = (4 + pos - 1) % 4; + if (input & KEY_DOWN) + pos = (pos + 1) % 4; + + Draw_FlushFramebuffer(); + Draw_Unlock(); + } + while(!(input & (KEY_A | KEY_B)) && !menuShouldExit); +} diff --git a/sysmodules/rosalina/source/utils.c b/sysmodules/rosalina/source/utils.c index 237989c..5cd5232 100644 --- a/sysmodules/rosalina/source/utils.c +++ b/sysmodules/rosalina/source/utils.c @@ -28,6 +28,8 @@ #include "csvc.h" #include #include +#include +#include <3ds.h> void formatMemoryPermission(char *outbuf, MemPerm perm) { @@ -161,3 +163,30 @@ int dateTimeToString(char *out, u64 msSince1900, bool filenameFormat) else return sprintf(out, "%04lu-%02lu-%02lu %02lu:%02lu:%02lu", year, month, days, hours, minutes, seconds); } + +int floatToString(char *out, float f, u32 precision, bool pad) +{ + // Floating point stuff is cringe + if (isnanf(f)) + return sprintf(out, "NaN"); + else if (isinff(f) && f >= -0.0f) + return sprintf(out, "inf"); + else if (isinff(f)) + return sprintf(out, "-inf"); + + static const u64 pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; + precision = precision >= 10 ? 10 : precision; + + u64 mult = pow10[precision]; + double f2 = fabs((double)f) * mult + 0.5; + const char *sign = f2 >= 0.0f ? "" : "-"; + u64 f3 = (u64)f2; + + u64 intPart = f3 / mult; + u64 fracPart = f3 % mult; + + if (pad) + return sprintf(out, "%s%llu.%0*llu", sign, intPart, (int)precision, fracPart); + else + return sprintf(out, "%s%llu.%llu", sign, intPart, fracPart); +}