rosalina: refactor screen filter code

https://i.kym-cdn.com/photos/images/original/001/264/842/220.png
This commit is contained in:
TuxSH 2023-01-17 23:48:07 +00:00
parent 571592ca7c
commit 6592b516a4
6 changed files with 52 additions and 257 deletions

View File

@ -46,7 +46,7 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH) ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),-wrap,exit,--section-start,.text=0x14000000 LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),-wrap,exit,--section-start,.text=0x14000000
LIBS := -lctru LIBS := -lctru -lm
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing # list of directories containing libraries, this must be the top level containing

View File

@ -31,6 +31,9 @@
extern Menu screenFiltersMenu; extern Menu screenFiltersMenu;
extern int screenFiltersCurrentTemperature; extern int screenFiltersCurrentTemperature;
extern float screenFiltersCurrentGamma;
extern float screenFiltersCurrentContrast;
extern float screenFiltersCurrentBrightness;
void ScreenFiltersMenu_SetCct(int cct); void ScreenFiltersMenu_SetCct(int cct);
void ScreenFiltersMenu_RestoreCct(void); void ScreenFiltersMenu_RestoreCct(void);

View File

@ -22,11 +22,8 @@
#include <stdint.h> #include <stdint.h>
#include "redshift.h" //#include "redshift.h"
void colorramp_fill(uint16_t *gamma_r, uint16_t *gamma_g, uint16_t *gamma_b, void colorramp_get_white_point(float *out_white_point, int temperature); // not in original code
int size, const color_setting_t *setting);
void colorramp_fill_float(float *gamma_r, float *gamma_g, float *gamma_b,
int size, const color_setting_t *setting);
#endif /* ! REDSHIFT_COLORRAMP_H */ #endif /* ! REDSHIFT_COLORRAMP_H */

View File

@ -1,153 +0,0 @@
/* redshift.h -- Main program header
This file is part of Redshift.
Redshift is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Redshift is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Redshift. If not, see <http://www.gnu.org/licenses/>.
Copyright (c) 2013-2017 Jon Lund Steffensen <jonlst@gmail.com>
*/
#ifndef REDSHIFT_REDSHIFT_H
#define REDSHIFT_REDSHIFT_H
#include <stdio.h>
#include <stdlib.h>
/* The color temperature when no adjustment is applied. */
#define NEUTRAL_TEMP 6500
/* Location */
typedef struct {
float lat;
float lon;
} location_t;
/* Periods of day. */
typedef enum {
PERIOD_NONE = 0,
PERIOD_DAYTIME,
PERIOD_NIGHT,
PERIOD_TRANSITION
} period_t;
/* Color setting */
typedef struct {
int temperature;
float gamma[3];
float brightness;
} color_setting_t;
/* Program modes. */
typedef enum {
PROGRAM_MODE_CONTINUAL,
PROGRAM_MODE_ONE_SHOT,
PROGRAM_MODE_PRINT,
PROGRAM_MODE_RESET,
PROGRAM_MODE_MANUAL
} program_mode_t;
/* Time range.
Fields are offsets from midnight in seconds. */
typedef struct {
int start;
int end;
} time_range_t;
/* Transition scheme.
The solar elevations at which the transition begins/ends,
and the association color settings. */
typedef struct {
double high;
double low;
int use_time; /* When enabled, ignore elevation and use time ranges. */
time_range_t dawn;
time_range_t dusk;
color_setting_t day;
color_setting_t night;
} transition_scheme_t;
/* Gamma adjustment method */
typedef struct gamma_state gamma_state_t;
typedef int gamma_method_init_func(gamma_state_t **state);
typedef int gamma_method_start_func(gamma_state_t *state);
typedef void gamma_method_free_func(gamma_state_t *state);
typedef void gamma_method_print_help_func(FILE *f);
typedef int gamma_method_set_option_func(gamma_state_t *state, const char *key,
const char *value);
typedef void gamma_method_restore_func(gamma_state_t *state);
typedef int gamma_method_set_temperature_func(
gamma_state_t *state, const color_setting_t *setting, int preserve);
typedef struct {
char *name;
/* If true, this method will be tried if none is explicitly chosen. */
int autostart;
/* Initialize state. Options can be set between init and start. */
gamma_method_init_func *init;
/* Allocate storage and make connections that depend on options. */
gamma_method_start_func *start;
/* Free all allocated storage and close connections. */
gamma_method_free_func *free;
/* Print help on options for this adjustment method. */
gamma_method_print_help_func *print_help;
/* Set an option key, value-pair */
gamma_method_set_option_func *set_option;
/* Restore the adjustment to the state before start was called. */
gamma_method_restore_func *restore;
/* Set a specific color temperature. */
gamma_method_set_temperature_func *set_temperature;
} gamma_method_t;
/* Location provider */
typedef struct location_state location_state_t;
typedef int location_provider_init_func(location_state_t **state);
typedef int location_provider_start_func(location_state_t *state);
typedef void location_provider_free_func(location_state_t *state);
typedef void location_provider_print_help_func(FILE *f);
typedef int location_provider_set_option_func(
location_state_t *state, const char *key, const char *value);
typedef int location_provider_get_fd_func(location_state_t *state);
typedef int location_provider_handle_func(
location_state_t *state, location_t *location, int *available);
typedef struct {
char *name;
/* Initialize state. Options can be set between init and start. */
location_provider_init_func *init;
/* Allocate storage and make connections that depend on options. */
location_provider_start_func *start;
/* Free all allocated storage and close connections. */
location_provider_free_func *free;
/* Print help on options for this location provider. */
location_provider_print_help_func *print_help;
/* Set an option key, value-pair. */
location_provider_set_option_func *set_option;
/* Listen and handle location updates. */
location_provider_get_fd_func *get_fd;
location_provider_handle_func *handle;
} location_provider_t;
#endif /* ! REDSHIFT_REDSHIFT_H */

View File

@ -25,11 +25,11 @@
*/ */
#include <3ds.h> #include <3ds.h>
#include <math.h>
#include "memory.h" #include "memory.h"
#include "menu.h" #include "menu.h"
#include "menus/screen_filters.h" #include "menus/screen_filters.h"
#include "draw.h" #include "draw.h"
#include "redshift/redshift.h"
#include "redshift/colorramp.h" #include "redshift/colorramp.h"
typedef union { typedef union {
@ -42,67 +42,54 @@ typedef union {
u32 raw; u32 raw;
} Pixel; } Pixel;
static u16 g_c[0x600];
static Pixel g_px[0x400];
int screenFiltersCurrentTemperature = 6500; int screenFiltersCurrentTemperature = 6500;
float screenFiltersCurrentGamma = 1.0f;
float screenFiltersCurrentContrast = 1.0f;
float screenFiltersCurrentBrightness = 0.0f;
static void ScreenFiltersMenu_WriteLut(const Pixel* lut) static inline bool ScreenFiltersMenu_IsDefaultSettings(void)
{
bool ret = screenFiltersCurrentTemperature == 6500;
ret = ret && screenFiltersCurrentGamma == 1.0f;
ret = ret && screenFiltersCurrentContrast == 1.0f;
ret = ret && screenFiltersCurrentBrightness == 0.0f;
return ret;
}
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);
s32 levelInt = (s32)(255.0f * level + 0.5f); // round to nearest integer
return levelInt <= 0 ? 0 : levelInt >= 255 ? 255 : (u8)levelInt; // clamp
}
static void ScreenFiltersMenu_ApplyColorSettings(void)
{ {
GPU_FB_TOP_COL_LUT_INDEX = 0; GPU_FB_TOP_COL_LUT_INDEX = 0;
GPU_FB_BOTTOM_COL_LUT_INDEX = 0; GPU_FB_BOTTOM_COL_LUT_INDEX = 0;
float wp[3];
colorramp_get_white_point(wp, screenFiltersCurrentTemperature);
float a = screenFiltersCurrentContrast;
float g = screenFiltersCurrentGamma;
float b = screenFiltersCurrentBrightness;
for (int i = 0; i <= 255; i++) { for (int i = 0; i <= 255; i++) {
GPU_FB_TOP_COL_LUT_ELEM = lut->raw; Pixel px;
GPU_FB_BOTTOM_COL_LUT_ELEM = lut->raw; px.r = ScreenFiltersMenu_GetColorLevel(i, wp[0], a, b, g);
lut++; px.g = ScreenFiltersMenu_GetColorLevel(i, wp[1], a, b, g);
px.b = ScreenFiltersMenu_GetColorLevel(i, wp[2], a, b, g);
px.z = 0;
GPU_FB_TOP_COL_LUT_ELEM = px.raw;
GPU_FB_BOTTOM_COL_LUT_ELEM = px.raw;
} }
} }
static void ScreenFiltersMenu_ApplyColorSettings(color_setting_t* cs)
{
u8 i = 0;
memset(g_c, 0, sizeof(g_c));
memset(g_px, 0, sizeof(g_px));
do {
g_px[i].r = i;
g_px[i].g = i;
g_px[i].b = i;
g_px[i].z = 0;
} while(++i);
do {
*(g_c + i + 0x000) = g_px[i].r | (g_px[i].r << 8);
*(g_c + i + 0x100) = g_px[i].g | (g_px[i].g << 8);
*(g_c + i + 0x200) = g_px[i].b | (g_px[i].b << 8);
} while(++i);
colorramp_fill(g_c + 0x000, g_c + 0x100, g_c + 0x200, 0x100, cs);
do {
g_px[i].r = *(g_c + i + 0x000) >> 8;
g_px[i].g = *(g_c + i + 0x100) >> 8;
g_px[i].b = *(g_c + i + 0x200) >> 8;
} while(++i);
ScreenFiltersMenu_WriteLut(g_px);
}
void ScreenFiltersMenu_SetCct(int cct) void ScreenFiltersMenu_SetCct(int cct)
{ {
color_setting_t cs;
memset(&cs, 0, sizeof(cs));
cs.temperature = cct;
/*cs.gamma[0] = 1.0F;
cs.gamma[1] = 1.0F;
cs.gamma[2] = 1.0F;
cs.brightness = 1.0F;*/
ScreenFiltersMenu_ApplyColorSettings(&cs);
screenFiltersCurrentTemperature = cct; screenFiltersCurrentTemperature = cct;
ScreenFiltersMenu_ApplyColorSettings();
} }
Menu screenFiltersMenu = { Menu screenFiltersMenu = {
@ -131,15 +118,12 @@ void ScreenFiltersMenu_Set##name(void)\
void ScreenFiltersMenu_RestoreCct(void) void ScreenFiltersMenu_RestoreCct(void)
{ {
// Not initialized/default: return // Not initialized/default: return
if (screenFiltersCurrentTemperature == 6500) if (ScreenFiltersMenu_IsDefaultSettings())
return; return;
// Wait for GSP to restore the CCT table // Wait for GSP to restore the CCT table
while (GPU_FB_TOP_COL_LUT_ELEM != g_px[0].raw) svcSleepThread(20 * 1000 * 1000LL);
svcSleepThread(10 * 1000 * 1000LL); ScreenFiltersMenu_ApplyColorSettings();
svcSleepThread(10 * 1000 * 1000LL);
ScreenFiltersMenu_WriteLut(g_px);
} }
DEF_CCT_SETTER(6500, Default) DEF_CCT_SETTER(6500, Default)

View File

@ -21,7 +21,7 @@
#include <stdint.h> #include <stdint.h>
//#include <math.h> //#include <math.h>
#include "redshift/redshift.h" //#include "redshift/redshift.h"
/* Whitepoint values for temperatures at 100K intervals. /* Whitepoint values for temperatures at 100K intervals.
These will be interpolated for the actual temperature. These will be interpolated for the actual temperature.
@ -281,49 +281,13 @@ interpolate_color(float a, const float *c1, const float *c2, float *c)
c[2] = (1.0-a)*c1[2] + a*c2[2]; c[2] = (1.0-a)*c1[2] + a*c2[2];
} }
/* Helper macro used in the fill functions */
#define F(Y, C) ((Y) * white_point[C])
/*#define F(Y, C) pow((Y) * setting->brightness * \ // Not in original code
white_point[C], 1.0/setting->gamma[C])*/ void colorramp_get_white_point(float *out_white_point, int temperature)
void
colorramp_fill(uint16_t *gamma_r, uint16_t *gamma_g, uint16_t *gamma_b,
int size, const color_setting_t *setting)
{ {
/* Approximate white point */ /* Approximate white point */
float white_point[3]; float alpha = (temperature % 100) / 100.0;
float alpha = (setting->temperature % 100) / 100.0; int temp_index = ((temperature - 1000) / 100)*3;
int temp_index = ((setting->temperature - 1000) / 100)*3;
interpolate_color(alpha, &blackbody_color[temp_index], interpolate_color(alpha, &blackbody_color[temp_index],
&blackbody_color[temp_index+3], white_point); &blackbody_color[temp_index+3], out_white_point);
for (int i = 0; i < size; i++) {
gamma_r[i] = F((double)gamma_r[i]/(UINT16_MAX+1), 0) *
(UINT16_MAX+1);
gamma_g[i] = F((double)gamma_g[i]/(UINT16_MAX+1), 1) *
(UINT16_MAX+1);
gamma_b[i] = F((double)gamma_b[i]/(UINT16_MAX+1), 2) *
(UINT16_MAX+1);
} }
}
void
colorramp_fill_float(float *gamma_r, float *gamma_g, float *gamma_b,
int size, const color_setting_t *setting)
{
/* Approximate white point */
float white_point[3];
float alpha = (setting->temperature % 100) / 100.0;
int temp_index = ((setting->temperature - 1000) / 100)*3;
interpolate_color(alpha, &blackbody_color[temp_index],
&blackbody_color[temp_index+3], white_point);
for (int i = 0; i < size; i++) {
gamma_r[i] = F((double)gamma_r[i], 0);
gamma_g[i] = F((double)gamma_g[i], 1);
gamma_b[i] = F((double)gamma_b[i], 2);
}
}
#undef F