rosalina: add color gamma control, and more

This commits adds an "Advanced configuration" option to screen filters,
where CCT, color gamma, contrast and "brightness" can be fine-tuned,
instead of just using a preset.

Persistence in config.ini TBD in a later commit.
This commit is contained in:
TuxSH 2023-01-20 02:10:14 +00:00
parent 6592b516a4
commit 7397c85434
6 changed files with 145 additions and 1 deletions

View File

@ -75,6 +75,7 @@ extern bool preTerminationRequested;
extern Handle preTerminationEvent; extern Handle preTerminationEvent;
u32 waitInputWithTimeout(s32 msec); u32 waitInputWithTimeout(s32 msec);
u32 waitInputWithTimeoutEx(u32 *outHeldKeys, s32 msec);
u32 waitInput(void); u32 waitInput(void);
u32 waitComboWithTimeout(s32 msec); u32 waitComboWithTimeout(s32 msec);

View File

@ -49,3 +49,5 @@ void ScreenFiltersMenu_SetIncandescent(void); // 2700K
void ScreenFiltersMenu_SetWarmIncandescent(void); // 2300K void ScreenFiltersMenu_SetWarmIncandescent(void); // 2300K
void ScreenFiltersMenu_SetCandle(void); // 1900K void ScreenFiltersMenu_SetCandle(void); // 1900K
void ScreenFiltersMenu_SetEmber(void); // 1200K void ScreenFiltersMenu_SetEmber(void); // 1200K
void ScreenFiltersMenu_AdvancedConfiguration(void);

View File

@ -41,6 +41,8 @@
#define REG32(addr) (*(vu32 *)(PA_PTR(addr))) #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 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; u32 instrBase = link ? 0xEB000000 : 0xEA000000;
@ -68,3 +70,4 @@ void formatMemoryPermission(char *outbuf, MemPerm perm);
void formatUserMemoryState(char *outbuf, MemState state); void formatUserMemoryState(char *outbuf, MemState state);
u32 formatMemoryMapOfProcess(char *outbuf, u32 bufLen, Handle handle); u32 formatMemoryMapOfProcess(char *outbuf, u32 bufLen, Handle handle);
int dateTimeToString(char *out, u64 msSince1900, bool filenameFormat); int dateTimeToString(char *out, u64 msSince1900, bool filenameFormat);
int floatToString(char *out, float f, u32 precision, bool pad);

View File

@ -81,6 +81,33 @@ u32 waitInputWithTimeout(s32 msec)
return keys; 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) u32 waitInput(void)
{ {
return waitInputWithTimeout(-1); return waitInputWithTimeout(-1);

View File

@ -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) static inline u8 ScreenFiltersMenu_GetColorLevel(int inLevel, float wp, float a, float b, float g)
{ {
float level = inLevel / 255.0f; 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 s32 levelInt = (s32)(255.0f * level + 0.5f); // round to nearest integer
return levelInt <= 0 ? 0 : levelInt >= 255 ? 255 : (u8)levelInt; // clamp return levelInt <= 0 ? 0 : levelInt >= 255 ? 255 : (u8)levelInt; // clamp
} }
@ -105,6 +106,7 @@ Menu screenFiltersMenu = {
{ "[2300K] Warm Incandescent", METHOD, .method = &ScreenFiltersMenu_SetWarmIncandescent }, { "[2300K] Warm Incandescent", METHOD, .method = &ScreenFiltersMenu_SetWarmIncandescent },
{ "[1900K] Candle", METHOD, .method = &ScreenFiltersMenu_SetCandle }, { "[1900K] Candle", METHOD, .method = &ScreenFiltersMenu_SetCandle },
{ "[1200K] Ember", METHOD, .method = &ScreenFiltersMenu_SetEmber }, { "[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(2300, WarmIncandescent)
DEF_CCT_SETTER(1900, Candle) DEF_CCT_SETTER(1900, Candle)
DEF_CCT_SETTER(1200, Ember) 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);
}

View File

@ -28,6 +28,8 @@
#include "csvc.h" #include "csvc.h"
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <math.h>
#include <3ds.h>
void formatMemoryPermission(char *outbuf, MemPerm perm) void formatMemoryPermission(char *outbuf, MemPerm perm)
{ {
@ -161,3 +163,30 @@ int dateTimeToString(char *out, u64 msSince1900, bool filenameFormat)
else else
return sprintf(out, "%04lu-%02lu-%02lu %02lu:%02lu:%02lu", year, month, days, hours, minutes, seconds); 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);
}