diff --git a/arm9/data/config_template.ini b/arm9/data/config_template.ini index c1bd041f..69b6c8f8 100644 Binary files a/arm9/data/config_template.ini and b/arm9/data/config_template.ini differ diff --git a/arm9/source/config.c b/arm9/source/config.c index 18c0353f..ab91dbf6 100644 --- a/arm9/source/config.c +++ b/arm9/source/config.c @@ -501,6 +501,11 @@ static int configIniHandler(void* user, const char* section, const char* name, c CHECK_PARSE_OPTION(parseBoolOption(&opt, value)); cfg->topScreenFilter.invert = opt; return 1; + } else if (strcmp(name, "screen_filters_top_color_curve_adj") == 0) { + s64 opt; + CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, 0, 2)); + cfg->topScreenFilter.colorCurveCorrection = (u8)opt; + return 1; } else if (strcmp(name, "screen_filters_bot_cct") == 0) { s64 opt; CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, 1000, 25100)); @@ -526,6 +531,11 @@ static int configIniHandler(void* user, const char* section, const char* name, c CHECK_PARSE_OPTION(parseBoolOption(&opt, value)); cfg->bottomScreenFilter.invert = opt; return 1; + } else if (strcmp(name, "screen_filters_bot_color_curve_adj") == 0) { + s64 opt; + CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, 0, 2)); + cfg->bottomScreenFilter.colorCurveCorrection = (u8)opt; + return 1; } else { CHECK_PARSE_OPTION(-1); } @@ -666,6 +676,7 @@ static size_t saveLumaIniConfigToStr(char *out) (int)cfg->ntpTzOffetMinutes, (int)cfg->topScreenFilter.cct, (int)cfg->bottomScreenFilter.cct, + (int)cfg->topScreenFilter.colorCurveCorrection, (int)cfg->bottomScreenFilter.colorCurveCorrection, topScreenFilterGammaStr, bottomScreenFilterGammaStr, topScreenFilterContrastStr, bottomScreenFilterContrastStr, topScreenFilterBrightnessStr, bottomScreenFilterBrightnessStr, diff --git a/arm9/source/config.h b/arm9/source/config.h index acbd20f1..fdc25e1d 100644 --- a/arm9/source/config.h +++ b/arm9/source/config.h @@ -36,7 +36,7 @@ #define CONFIG_FILE "config.ini" #define CONFIG_VERSIONMAJOR 3 -#define CONFIG_VERSIONMINOR 12 +#define CONFIG_VERSIONMINOR 13 #define BOOTCFG_NAND BOOTCONFIG(0, 1) #define BOOTCFG_EMUINDEX BOOTCONFIG(1, 3) diff --git a/arm9/source/types.h b/arm9/source/types.h index cdbc7f17..357c5d76 100644 --- a/arm9/source/types.h +++ b/arm9/source/types.h @@ -64,6 +64,7 @@ typedef volatile s64 vs64; typedef struct ScreenFiltersCfgData { u16 cct; bool invert; + u8 colorCurveCorrection; s64 gammaEnc; s64 contrastEnc; s64 brightnessEnc; diff --git a/k11_extension/include/globals.h b/k11_extension/include/globals.h index bbba81d8..0e0d4ab4 100644 --- a/k11_extension/include/globals.h +++ b/k11_extension/include/globals.h @@ -131,6 +131,7 @@ extern void* (*kAlloc)(FcramDescriptor *fcramDesc, u32 nbPages, u32 alignment, u typedef struct ScreenFiltersCfgData { u16 cct; bool invert; + u8 colorCurveCorrection; s64 gammaEnc; s64 contrastEnc; s64 brightnessEnc; diff --git a/k11_extension/source/svc/GetSystemInfo.c b/k11_extension/source/svc/GetSystemInfo.c index 127f7b7e..8d7a6117 100644 --- a/k11_extension/source/svc/GetSystemInfo.c +++ b/k11_extension/source/svc/GetSystemInfo.c @@ -43,7 +43,7 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param) s32 toCopy = (s32)sizeof(cfwInfo.launchedPath) - offset; if (toCopy > 8) toCopy = 8; memcpy(out, (u8*)cfwInfo.launchedPath + offset, (toCopy > 0) ? toCopy : 0); - } + } else switch(param) { // Please do not use these, except 0, 1, and 0x200 @@ -120,6 +120,12 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param) case 0x10C: *out = (s64)cfwInfo.bottomScreenFilter.invert; break; + case 0x10D: + *out = (s64)cfwInfo.topScreenFilter.colorCurveCorrection; + break; + case 0x10E: + *out = (s64)cfwInfo.bottomScreenFilter.colorCurveCorrection; + break; case 0x180: *out = cfwInfo.pluginLoaderFlags; break; diff --git a/sysmodules/rosalina/data/config_template.ini b/sysmodules/rosalina/data/config_template.ini index c1bd041f..69b6c8f8 100644 Binary files a/sysmodules/rosalina/data/config_template.ini and b/sysmodules/rosalina/data/config_template.ini differ diff --git a/sysmodules/rosalina/include/menu.h b/sysmodules/rosalina/include/menu.h index 4656b8b1..89b79474 100644 --- a/sysmodules/rosalina/include/menu.h +++ b/sysmodules/rosalina/include/menu.h @@ -62,7 +62,7 @@ typedef struct MenuItem { typedef struct Menu { const char *title; - MenuItem items[16]; + MenuItem items[24]; } Menu; extern u32 menuCombo; diff --git a/sysmodules/rosalina/include/menus/screen_filters.h b/sysmodules/rosalina/include/menus/screen_filters.h index 91a98801..f3cf6bff 100644 --- a/sysmodules/rosalina/include/menus/screen_filters.h +++ b/sysmodules/rosalina/include/menus/screen_filters.h @@ -33,6 +33,7 @@ extern Menu screenFiltersMenu; typedef struct ScreenFilter { u16 cct; bool invert; + u8 colorCurveCorrection; float gamma; float contrast; float brightness; @@ -56,4 +57,7 @@ void ScreenFiltersMenu_SetWarmIncandescent(void); // 2300K void ScreenFiltersMenu_SetCandle(void); // 1900K void ScreenFiltersMenu_SetEmber(void); // 1200K +void ScreenFiltersMenu_SetSrgbColorCurves(void); +void ScreenFiltersMenu_RestoreColorCurves(void); + void ScreenFiltersMenu_AdvancedConfiguration(void); diff --git a/sysmodules/rosalina/include/menus/screen_filters_srgb_tables.h b/sysmodules/rosalina/include/menus/screen_filters_srgb_tables.h new file mode 100644 index 00000000..062eb2f7 --- /dev/null +++ b/sysmodules/rosalina/include/menus/screen_filters_srgb_tables.h @@ -0,0 +1,1046 @@ +// SPDX-License-Identifier: MIT +// (c) 2024 LumaTeam + +#pragma once +#include <3ds/types.h> + +static const u8 ctrToSrgbTableTop[256][3] = { + { 0x00, 0x00, 0x00, }, + { 0x01, 0x01, 0x01, }, // i = 0x01 + { 0x02, 0x01, 0x02, }, // i = 0x02 + { 0x03, 0x02, 0x03, }, // i = 0x03 + { 0x04, 0x03, 0x04, }, // i = 0x04 + { 0x05, 0x04, 0x05, }, // i = 0x05 + { 0x06, 0x04, 0x06, }, // i = 0x06 + { 0x07, 0x05, 0x06, }, // i = 0x07 + { 0x08, 0x06, 0x07, }, // i = 0x08 + { 0x08, 0x06, 0x08, }, // i = 0x09 + { 0x09, 0x07, 0x09, }, // i = 0x0A + { 0x0A, 0x08, 0x0A, }, // i = 0x0B + { 0x0B, 0x09, 0x0B, }, // i = 0x0C + { 0x0C, 0x09, 0x0B, }, // i = 0x0D + { 0x0D, 0x0A, 0x0C, }, // i = 0x0E + { 0x0E, 0x0B, 0x0D, }, // i = 0x0F + { 0x0F, 0x0B, 0x0E, }, // i = 0x10 + { 0x10, 0x0C, 0x0F, }, // i = 0x11 + { 0x10, 0x0D, 0x0F, }, // i = 0x12 + { 0x11, 0x0E, 0x10, }, // i = 0x13 + { 0x12, 0x0E, 0x11, }, // i = 0x14 + { 0x13, 0x0F, 0x12, }, // i = 0x15 + { 0x14, 0x10, 0x12, }, // i = 0x16 + { 0x15, 0x11, 0x13, }, // i = 0x17 + { 0x16, 0x11, 0x14, }, // i = 0x18 + { 0x16, 0x12, 0x15, }, // i = 0x19 + { 0x17, 0x13, 0x15, }, // i = 0x1A + { 0x18, 0x14, 0x16, }, // i = 0x1B + { 0x19, 0x14, 0x17, }, // i = 0x1C + { 0x1A, 0x15, 0x18, }, // i = 0x1D + { 0x1B, 0x16, 0x18, }, // i = 0x1E + { 0x1C, 0x17, 0x19, }, // i = 0x1F + { 0x1C, 0x17, 0x1A, }, // i = 0x20 + { 0x1D, 0x18, 0x1B, }, // i = 0x21 + { 0x1E, 0x19, 0x1B, }, // i = 0x22 + { 0x1F, 0x1A, 0x1C, }, // i = 0x23 + { 0x20, 0x1B, 0x1D, }, // i = 0x24 + { 0x21, 0x1B, 0x1E, }, // i = 0x25 + { 0x22, 0x1C, 0x1E, }, // i = 0x26 + { 0x23, 0x1D, 0x1F, }, // i = 0x27 + { 0x23, 0x1E, 0x20, }, // i = 0x28 + { 0x24, 0x1F, 0x21, }, // i = 0x29 + { 0x25, 0x1F, 0x21, }, // i = 0x2A + { 0x26, 0x20, 0x22, }, // i = 0x2B + { 0x27, 0x21, 0x23, }, // i = 0x2C + { 0x28, 0x22, 0x24, }, // i = 0x2D + { 0x29, 0x23, 0x24, }, // i = 0x2E + { 0x2A, 0x24, 0x25, }, // i = 0x2F + { 0x2B, 0x24, 0x26, }, // i = 0x30 + { 0x2C, 0x25, 0x27, }, // i = 0x31 + { 0x2D, 0x26, 0x28, }, // i = 0x32 + { 0x2E, 0x27, 0x28, }, // i = 0x33 + { 0x2E, 0x28, 0x29, }, // i = 0x34 + { 0x2F, 0x29, 0x2A, }, // i = 0x35 + { 0x30, 0x2A, 0x2B, }, // i = 0x36 + { 0x31, 0x2B, 0x2B, }, // i = 0x37 + { 0x32, 0x2B, 0x2C, }, // i = 0x38 + { 0x33, 0x2C, 0x2D, }, // i = 0x39 + { 0x34, 0x2D, 0x2E, }, // i = 0x3A + { 0x35, 0x2E, 0x2F, }, // i = 0x3B + { 0x36, 0x2F, 0x30, }, // i = 0x3C + { 0x37, 0x30, 0x30, }, // i = 0x3D + { 0x38, 0x31, 0x31, }, // i = 0x3E + { 0x39, 0x32, 0x32, }, // i = 0x3F + { 0x3A, 0x33, 0x33, }, // i = 0x40 + { 0x3B, 0x34, 0x34, }, // i = 0x41 + { 0x3C, 0x35, 0x34, }, // i = 0x42 + { 0x3D, 0x35, 0x35, }, // i = 0x43 + { 0x3E, 0x36, 0x36, }, // i = 0x44 + { 0x3F, 0x37, 0x37, }, // i = 0x45 + { 0x40, 0x38, 0x38, }, // i = 0x46 + { 0x41, 0x39, 0x39, }, // i = 0x47 + { 0x42, 0x3A, 0x3A, }, // i = 0x48 + { 0x43, 0x3B, 0x3A, }, // i = 0x49 + { 0x44, 0x3C, 0x3B, }, // i = 0x4A + { 0x45, 0x3D, 0x3C, }, // i = 0x4B + { 0x46, 0x3E, 0x3D, }, // i = 0x4C + { 0x47, 0x3F, 0x3E, }, // i = 0x4D + { 0x48, 0x40, 0x3F, }, // i = 0x4E + { 0x49, 0x41, 0x40, }, // i = 0x4F + { 0x4A, 0x42, 0x41, }, // i = 0x50 + { 0x4B, 0x43, 0x41, }, // i = 0x51 + { 0x4C, 0x44, 0x42, }, // i = 0x52 + { 0x4D, 0x45, 0x43, }, // i = 0x53 + { 0x4E, 0x46, 0x44, }, // i = 0x54 + { 0x4F, 0x47, 0x45, }, // i = 0x55 + { 0x50, 0x48, 0x46, }, // i = 0x56 + { 0x51, 0x49, 0x47, }, // i = 0x57 + { 0x52, 0x4A, 0x48, }, // i = 0x58 + { 0x53, 0x4B, 0x49, }, // i = 0x59 + { 0x54, 0x4C, 0x4A, }, // i = 0x5A + { 0x55, 0x4D, 0x4B, }, // i = 0x5B + { 0x56, 0x4E, 0x4B, }, // i = 0x5C + { 0x57, 0x4F, 0x4C, }, // i = 0x5D + { 0x58, 0x50, 0x4D, }, // i = 0x5E + { 0x59, 0x51, 0x4E, }, // i = 0x5F + { 0x5B, 0x52, 0x4F, }, // i = 0x60 + { 0x5C, 0x53, 0x50, }, // i = 0x61 + { 0x5D, 0x54, 0x51, }, // i = 0x62 + { 0x5E, 0x55, 0x52, }, // i = 0x63 + { 0x5F, 0x56, 0x53, }, // i = 0x64 + { 0x60, 0x57, 0x54, }, // i = 0x65 + { 0x61, 0x58, 0x55, }, // i = 0x66 + { 0x62, 0x59, 0x56, }, // i = 0x67 + { 0x63, 0x5A, 0x57, }, // i = 0x68 + { 0x64, 0x5B, 0x57, }, // i = 0x69 + { 0x65, 0x5C, 0x58, }, // i = 0x6A + { 0x66, 0x5D, 0x59, }, // i = 0x6B + { 0x67, 0x5E, 0x5A, }, // i = 0x6C + { 0x68, 0x5F, 0x5B, }, // i = 0x6D + { 0x69, 0x60, 0x5C, }, // i = 0x6E + { 0x6A, 0x61, 0x5D, }, // i = 0x6F + { 0x6B, 0x62, 0x5E, }, // i = 0x70 + { 0x6C, 0x63, 0x5F, }, // i = 0x71 + { 0x6D, 0x64, 0x60, }, // i = 0x72 + { 0x6E, 0x65, 0x61, }, // i = 0x73 + { 0x6F, 0x66, 0x62, }, // i = 0x74 + { 0x70, 0x67, 0x63, }, // i = 0x75 + { 0x71, 0x68, 0x64, }, // i = 0x76 + { 0x73, 0x69, 0x65, }, // i = 0x77 + { 0x74, 0x6A, 0x66, }, // i = 0x78 + { 0x75, 0x6B, 0x67, }, // i = 0x79 + { 0x76, 0x6C, 0x68, }, // i = 0x7A + { 0x77, 0x6D, 0x68, }, // i = 0x7B + { 0x78, 0x6E, 0x69, }, // i = 0x7C + { 0x79, 0x6F, 0x6A, }, // i = 0x7D + { 0x7A, 0x70, 0x6B, }, // i = 0x7E + { 0x7B, 0x71, 0x6C, }, // i = 0x7F + { 0x7C, 0x72, 0x6D, }, // i = 0x80 + { 0x7D, 0x73, 0x6E, }, // i = 0x81 + { 0x7E, 0x74, 0x6F, }, // i = 0x82 + { 0x7F, 0x75, 0x70, }, // i = 0x83 + { 0x80, 0x76, 0x71, }, // i = 0x84 + { 0x81, 0x77, 0x72, }, // i = 0x85 + { 0x82, 0x78, 0x73, }, // i = 0x86 + { 0x83, 0x79, 0x74, }, // i = 0x87 + { 0x84, 0x7A, 0x75, }, // i = 0x88 + { 0x85, 0x7B, 0x76, }, // i = 0x89 + { 0x86, 0x7C, 0x77, }, // i = 0x8A + { 0x87, 0x7D, 0x78, }, // i = 0x8B + { 0x88, 0x7E, 0x79, }, // i = 0x8C + { 0x89, 0x7F, 0x7A, }, // i = 0x8D + { 0x8A, 0x81, 0x7B, }, // i = 0x8E + { 0x8B, 0x82, 0x7C, }, // i = 0x8F + { 0x8C, 0x83, 0x7C, }, // i = 0x90 + { 0x8D, 0x84, 0x7D, }, // i = 0x91 + { 0x8E, 0x85, 0x7E, }, // i = 0x92 + { 0x8F, 0x86, 0x7F, }, // i = 0x93 + { 0x90, 0x87, 0x80, }, // i = 0x94 + { 0x91, 0x88, 0x81, }, // i = 0x95 + { 0x92, 0x89, 0x82, }, // i = 0x96 + { 0x93, 0x8A, 0x83, }, // i = 0x97 + { 0x94, 0x8B, 0x84, }, // i = 0x98 + { 0x95, 0x8C, 0x85, }, // i = 0x99 + { 0x96, 0x8D, 0x86, }, // i = 0x9A + { 0x97, 0x8E, 0x87, }, // i = 0x9B + { 0x98, 0x8F, 0x88, }, // i = 0x9C + { 0x99, 0x90, 0x89, }, // i = 0x9D + { 0x9A, 0x91, 0x8A, }, // i = 0x9E + { 0x9B, 0x92, 0x8B, }, // i = 0x9F + { 0x9C, 0x93, 0x8C, }, // i = 0xA0 + { 0x9D, 0x94, 0x8D, }, // i = 0xA1 + { 0x9E, 0x95, 0x8E, }, // i = 0xA2 + { 0x9F, 0x96, 0x8F, }, // i = 0xA3 + { 0xA0, 0x97, 0x90, }, // i = 0xA4 + { 0xA1, 0x98, 0x91, }, // i = 0xA5 + { 0xA2, 0x99, 0x92, }, // i = 0xA6 + { 0xA4, 0x9A, 0x93, }, // i = 0xA7 + { 0xA5, 0x9B, 0x94, }, // i = 0xA8 + { 0xA6, 0x9C, 0x95, }, // i = 0xA9 + { 0xA7, 0x9D, 0x96, }, // i = 0xAA + { 0xA8, 0x9F, 0x97, }, // i = 0xAB + { 0xA9, 0xA0, 0x98, }, // i = 0xAC + { 0xAA, 0xA1, 0x99, }, // i = 0xAD + { 0xAB, 0xA2, 0x9A, }, // i = 0xAE + { 0xAC, 0xA3, 0x9B, }, // i = 0xAF + { 0xAD, 0xA4, 0x9C, }, // i = 0xB0 + { 0xAE, 0xA5, 0x9D, }, // i = 0xB1 + { 0xAF, 0xA6, 0x9E, }, // i = 0xB2 + { 0xB0, 0xA7, 0x9F, }, // i = 0xB3 + { 0xB1, 0xA8, 0xA0, }, // i = 0xB4 + { 0xB2, 0xA9, 0xA1, }, // i = 0xB5 + { 0xB3, 0xAA, 0xA2, }, // i = 0xB6 + { 0xB4, 0xAB, 0xA3, }, // i = 0xB7 + { 0xB5, 0xAC, 0xA4, }, // i = 0xB8 + { 0xB6, 0xAD, 0xA5, }, // i = 0xB9 + { 0xB7, 0xAF, 0xA6, }, // i = 0xBA + { 0xB8, 0xB0, 0xA7, }, // i = 0xBB + { 0xB9, 0xB1, 0xA9, }, // i = 0xBC + { 0xBA, 0xB2, 0xAA, }, // i = 0xBD + { 0xBB, 0xB3, 0xAB, }, // i = 0xBE + { 0xBC, 0xB4, 0xAC, }, // i = 0xBF + { 0xBD, 0xB5, 0xAD, }, // i = 0xC0 + { 0xBE, 0xB6, 0xAE, }, // i = 0xC1 + { 0xBF, 0xB7, 0xAF, }, // i = 0xC2 + { 0xC0, 0xB9, 0xB0, }, // i = 0xC3 + { 0xC1, 0xBA, 0xB1, }, // i = 0xC4 + { 0xC3, 0xBB, 0xB2, }, // i = 0xC5 + { 0xC4, 0xBC, 0xB4, }, // i = 0xC6 + { 0xC5, 0xBD, 0xB5, }, // i = 0xC7 + { 0xC6, 0xBE, 0xB6, }, // i = 0xC8 + { 0xC7, 0xBF, 0xB7, }, // i = 0xC9 + { 0xC8, 0xC0, 0xB8, }, // i = 0xCA + { 0xC9, 0xC2, 0xB9, }, // i = 0xCB + { 0xCA, 0xC3, 0xBB, }, // i = 0xCC + { 0xCB, 0xC4, 0xBC, }, // i = 0xCD + { 0xCC, 0xC5, 0xBD, }, // i = 0xCE + { 0xCD, 0xC6, 0xBE, }, // i = 0xCF + { 0xCE, 0xC7, 0xBF, }, // i = 0xD0 + { 0xCF, 0xC8, 0xC1, }, // i = 0xD1 + { 0xD0, 0xCA, 0xC2, }, // i = 0xD2 + { 0xD2, 0xCB, 0xC3, }, // i = 0xD3 + { 0xD3, 0xCC, 0xC4, }, // i = 0xD4 + { 0xD4, 0xCD, 0xC5, }, // i = 0xD5 + { 0xD5, 0xCE, 0xC7, }, // i = 0xD6 + { 0xD6, 0xCF, 0xC8, }, // i = 0xD7 + { 0xD7, 0xD1, 0xC9, }, // i = 0xD8 + { 0xD8, 0xD2, 0xCB, }, // i = 0xD9 + { 0xD9, 0xD3, 0xCC, }, // i = 0xDA + { 0xDA, 0xD4, 0xCD, }, // i = 0xDB + { 0xDB, 0xD5, 0xCE, }, // i = 0xDC + { 0xDC, 0xD7, 0xD0, }, // i = 0xDD + { 0xDE, 0xD8, 0xD1, }, // i = 0xDE + { 0xDF, 0xD9, 0xD2, }, // i = 0xDF + { 0xE0, 0xDA, 0xD4, }, // i = 0xE0 + { 0xE1, 0xDB, 0xD5, }, // i = 0xE1 + { 0xE2, 0xDD, 0xD6, }, // i = 0xE2 + { 0xE3, 0xDE, 0xD8, }, // i = 0xE3 + { 0xE4, 0xDF, 0xD9, }, // i = 0xE4 + { 0xE5, 0xE0, 0xDA, }, // i = 0xE5 + { 0xE6, 0xE1, 0xDC, }, // i = 0xE6 + { 0xE7, 0xE3, 0xDD, }, // i = 0xE7 + { 0xE8, 0xE4, 0xDE, }, // i = 0xE8 + { 0xEA, 0xE5, 0xE0, }, // i = 0xE9 + { 0xEB, 0xE6, 0xE1, }, // i = 0xEA + { 0xEC, 0xE7, 0xE2, }, // i = 0xEB + { 0xED, 0xE9, 0xE4, }, // i = 0xEC + { 0xEE, 0xEA, 0xE5, }, // i = 0xED + { 0xEF, 0xEB, 0xE7, }, // i = 0xEE + { 0xF0, 0xEC, 0xE8, }, // i = 0xEF + { 0xF1, 0xED, 0xE9, }, // i = 0xF0 + { 0xF2, 0xEF, 0xEB, }, // i = 0xF1 + { 0xF3, 0xF0, 0xEC, }, // i = 0xF2 + { 0xF4, 0xF1, 0xEE, }, // i = 0xF3 + { 0xF5, 0xF2, 0xEF, }, // i = 0xF4 + { 0xF6, 0xF3, 0xF1, }, // i = 0xF5 + { 0xF7, 0xF5, 0xF2, }, // i = 0xF6 + { 0xF8, 0xF6, 0xF3, }, // i = 0xF7 + { 0xF9, 0xF7, 0xF5, }, // i = 0xF8 + { 0xFA, 0xF8, 0xF6, }, // i = 0xF9 + { 0xFB, 0xF9, 0xF8, }, // i = 0xFA + { 0xFC, 0xFA, 0xF9, }, // i = 0xFB + { 0xFD, 0xFC, 0xFA, }, // i = 0xFC + { 0xFD, 0xFD, 0xFC, }, // i = 0xFD + { 0xFE, 0xFE, 0xFD, }, // i = 0xFE + { 0xFF, 0xFF, 0xFF, }, // i = 0xFF +}; + +static const u8 ctrToSrgbTableBottom[256][3] = { + { 0x00, 0x00, 0x00, }, // i = 0x00 + { 0x01, 0x00, 0x00, }, // i = 0x01 + { 0x01, 0x00, 0x01, }, // i = 0x02 + { 0x02, 0x01, 0x01, }, // i = 0x03 + { 0x02, 0x01, 0x02, }, // i = 0x04 + { 0x03, 0x01, 0x03, }, // i = 0x05 + { 0x04, 0x02, 0x03, }, // i = 0x06 + { 0x04, 0x02, 0x04, }, // i = 0x07 + { 0x05, 0x02, 0x04, }, // i = 0x08 + { 0x05, 0x03, 0x05, }, // i = 0x09 + { 0x06, 0x03, 0x05, }, // i = 0x0A + { 0x07, 0x04, 0x06, }, // i = 0x0B + { 0x07, 0x04, 0x07, }, // i = 0x0C + { 0x08, 0x05, 0x07, }, // i = 0x0D + { 0x09, 0x05, 0x08, }, // i = 0x0E + { 0x0A, 0x06, 0x08, }, // i = 0x0F + { 0x0A, 0x06, 0x09, }, // i = 0x10 + { 0x0B, 0x07, 0x0A, }, // i = 0x11 + { 0x0C, 0x08, 0x0A, }, // i = 0x12 + { 0x0C, 0x08, 0x0B, }, // i = 0x13 + { 0x0D, 0x09, 0x0C, }, // i = 0x14 + { 0x0E, 0x09, 0x0C, }, // i = 0x15 + { 0x0F, 0x0A, 0x0D, }, // i = 0x16 + { 0x10, 0x0B, 0x0E, }, // i = 0x17 + { 0x10, 0x0B, 0x0F, }, // i = 0x18 + { 0x11, 0x0C, 0x0F, }, // i = 0x19 + { 0x12, 0x0D, 0x10, }, // i = 0x1A + { 0x13, 0x0D, 0x11, }, // i = 0x1B + { 0x14, 0x0E, 0x12, }, // i = 0x1C + { 0x14, 0x0F, 0x12, }, // i = 0x1D + { 0x15, 0x10, 0x13, }, // i = 0x1E + { 0x16, 0x10, 0x14, }, // i = 0x1F + { 0x17, 0x11, 0x15, }, // i = 0x20 + { 0x18, 0x12, 0x15, }, // i = 0x21 + { 0x19, 0x13, 0x16, }, // i = 0x22 + { 0x19, 0x13, 0x17, }, // i = 0x23 + { 0x1A, 0x14, 0x18, }, // i = 0x24 + { 0x1B, 0x15, 0x18, }, // i = 0x25 + { 0x1C, 0x16, 0x19, }, // i = 0x26 + { 0x1D, 0x17, 0x1A, }, // i = 0x27 + { 0x1E, 0x18, 0x1B, }, // i = 0x28 + { 0x1F, 0x18, 0x1C, }, // i = 0x29 + { 0x20, 0x19, 0x1C, }, // i = 0x2A + { 0x21, 0x1A, 0x1D, }, // i = 0x2B + { 0x22, 0x1B, 0x1E, }, // i = 0x2C + { 0x22, 0x1C, 0x1F, }, // i = 0x2D + { 0x23, 0x1D, 0x20, }, // i = 0x2E + { 0x24, 0x1E, 0x21, }, // i = 0x2F + { 0x25, 0x1E, 0x21, }, // i = 0x30 + { 0x26, 0x1F, 0x22, }, // i = 0x31 + { 0x27, 0x20, 0x23, }, // i = 0x32 + { 0x28, 0x21, 0x24, }, // i = 0x33 + { 0x29, 0x22, 0x25, }, // i = 0x34 + { 0x2A, 0x23, 0x26, }, // i = 0x35 + { 0x2B, 0x24, 0x27, }, // i = 0x36 + { 0x2C, 0x25, 0x27, }, // i = 0x37 + { 0x2D, 0x26, 0x28, }, // i = 0x38 + { 0x2E, 0x27, 0x29, }, // i = 0x39 + { 0x2F, 0x28, 0x2A, }, // i = 0x3A + { 0x30, 0x29, 0x2B, }, // i = 0x3B + { 0x31, 0x2A, 0x2C, }, // i = 0x3C + { 0x32, 0x2A, 0x2D, }, // i = 0x3D + { 0x33, 0x2B, 0x2E, }, // i = 0x3E + { 0x34, 0x2C, 0x2E, }, // i = 0x3F + { 0x35, 0x2D, 0x2F, }, // i = 0x40 + { 0x36, 0x2E, 0x30, }, // i = 0x41 + { 0x37, 0x2F, 0x31, }, // i = 0x42 + { 0x38, 0x30, 0x32, }, // i = 0x43 + { 0x39, 0x31, 0x33, }, // i = 0x44 + { 0x3A, 0x32, 0x34, }, // i = 0x45 + { 0x3B, 0x33, 0x35, }, // i = 0x46 + { 0x3C, 0x34, 0x36, }, // i = 0x47 + { 0x3D, 0x35, 0x36, }, // i = 0x48 + { 0x3E, 0x36, 0x37, }, // i = 0x49 + { 0x3F, 0x37, 0x38, }, // i = 0x4A + { 0x40, 0x38, 0x39, }, // i = 0x4B + { 0x41, 0x39, 0x3A, }, // i = 0x4C + { 0x42, 0x3A, 0x3B, }, // i = 0x4D + { 0x43, 0x3B, 0x3C, }, // i = 0x4E + { 0x44, 0x3C, 0x3D, }, // i = 0x4F + { 0x45, 0x3D, 0x3E, }, // i = 0x50 + { 0x46, 0x3E, 0x3F, }, // i = 0x51 + { 0x47, 0x3F, 0x40, }, // i = 0x52 + { 0x49, 0x40, 0x41, }, // i = 0x53 + { 0x4A, 0x41, 0x42, }, // i = 0x54 + { 0x4B, 0x42, 0x42, }, // i = 0x55 + { 0x4C, 0x43, 0x43, }, // i = 0x56 + { 0x4D, 0x44, 0x44, }, // i = 0x57 + { 0x4E, 0x45, 0x45, }, // i = 0x58 + { 0x4F, 0x46, 0x46, }, // i = 0x59 + { 0x50, 0x47, 0x47, }, // i = 0x5A + { 0x51, 0x48, 0x48, }, // i = 0x5B + { 0x52, 0x49, 0x49, }, // i = 0x5C + { 0x53, 0x4A, 0x4A, }, // i = 0x5D + { 0x54, 0x4B, 0x4B, }, // i = 0x5E + { 0x55, 0x4C, 0x4C, }, // i = 0x5F + { 0x56, 0x4D, 0x4D, }, // i = 0x60 + { 0x57, 0x4E, 0x4E, }, // i = 0x61 + { 0x58, 0x4F, 0x4F, }, // i = 0x62 + { 0x5A, 0x50, 0x50, }, // i = 0x63 + { 0x5B, 0x51, 0x51, }, // i = 0x64 + { 0x5C, 0x52, 0x52, }, // i = 0x65 + { 0x5D, 0x53, 0x53, }, // i = 0x66 + { 0x5E, 0x54, 0x54, }, // i = 0x67 + { 0x5F, 0x55, 0x54, }, // i = 0x68 + { 0x60, 0x56, 0x55, }, // i = 0x69 + { 0x61, 0x57, 0x56, }, // i = 0x6A + { 0x62, 0x58, 0x57, }, // i = 0x6B + { 0x63, 0x59, 0x58, }, // i = 0x6C + { 0x64, 0x5B, 0x59, }, // i = 0x6D + { 0x65, 0x5C, 0x5A, }, // i = 0x6E + { 0x66, 0x5D, 0x5B, }, // i = 0x6F + { 0x68, 0x5E, 0x5C, }, // i = 0x70 + { 0x69, 0x5F, 0x5D, }, // i = 0x71 + { 0x6A, 0x60, 0x5E, }, // i = 0x72 + { 0x6B, 0x61, 0x5F, }, // i = 0x73 + { 0x6C, 0x62, 0x60, }, // i = 0x74 + { 0x6D, 0x63, 0x61, }, // i = 0x75 + { 0x6E, 0x64, 0x62, }, // i = 0x76 + { 0x6F, 0x65, 0x63, }, // i = 0x77 + { 0x70, 0x66, 0x64, }, // i = 0x78 + { 0x71, 0x67, 0x65, }, // i = 0x79 + { 0x72, 0x68, 0x66, }, // i = 0x7A + { 0x73, 0x69, 0x67, }, // i = 0x7B + { 0x74, 0x6A, 0x68, }, // i = 0x7C + { 0x76, 0x6B, 0x69, }, // i = 0x7D + { 0x77, 0x6C, 0x6A, }, // i = 0x7E + { 0x78, 0x6D, 0x6B, }, // i = 0x7F + { 0x79, 0x6E, 0x6C, }, // i = 0x80 + { 0x7A, 0x70, 0x6D, }, // i = 0x81 + { 0x7B, 0x71, 0x6E, }, // i = 0x82 + { 0x7C, 0x72, 0x6F, }, // i = 0x83 + { 0x7D, 0x73, 0x70, }, // i = 0x84 + { 0x7E, 0x74, 0x71, }, // i = 0x85 + { 0x7F, 0x75, 0x72, }, // i = 0x86 + { 0x80, 0x76, 0x73, }, // i = 0x87 + { 0x82, 0x77, 0x74, }, // i = 0x88 + { 0x83, 0x78, 0x75, }, // i = 0x89 + { 0x84, 0x79, 0x76, }, // i = 0x8A + { 0x85, 0x7A, 0x77, }, // i = 0x8B + { 0x86, 0x7B, 0x78, }, // i = 0x8C + { 0x87, 0x7C, 0x79, }, // i = 0x8D + { 0x88, 0x7E, 0x7A, }, // i = 0x8E + { 0x89, 0x7F, 0x7B, }, // i = 0x8F + { 0x8A, 0x80, 0x7C, }, // i = 0x90 + { 0x8B, 0x81, 0x7D, }, // i = 0x91 + { 0x8C, 0x82, 0x7E, }, // i = 0x92 + { 0x8D, 0x83, 0x7F, }, // i = 0x93 + { 0x8F, 0x84, 0x80, }, // i = 0x94 + { 0x90, 0x85, 0x81, }, // i = 0x95 + { 0x91, 0x86, 0x82, }, // i = 0x96 + { 0x92, 0x87, 0x84, }, // i = 0x97 + { 0x93, 0x88, 0x85, }, // i = 0x98 + { 0x94, 0x8A, 0x86, }, // i = 0x99 + { 0x95, 0x8B, 0x87, }, // i = 0x9A + { 0x96, 0x8C, 0x88, }, // i = 0x9B + { 0x97, 0x8D, 0x89, }, // i = 0x9C + { 0x98, 0x8E, 0x8A, }, // i = 0x9D + { 0x99, 0x8F, 0x8B, }, // i = 0x9E + { 0x9B, 0x90, 0x8C, }, // i = 0x9F + { 0x9C, 0x91, 0x8D, }, // i = 0xA0 + { 0x9D, 0x92, 0x8E, }, // i = 0xA1 + { 0x9E, 0x94, 0x8F, }, // i = 0xA2 + { 0x9F, 0x95, 0x90, }, // i = 0xA3 + { 0xA0, 0x96, 0x91, }, // i = 0xA4 + { 0xA1, 0x97, 0x92, }, // i = 0xA5 + { 0xA2, 0x98, 0x93, }, // i = 0xA6 + { 0xA3, 0x99, 0x94, }, // i = 0xA7 + { 0xA4, 0x9A, 0x95, }, // i = 0xA8 + { 0xA5, 0x9B, 0x97, }, // i = 0xA9 + { 0xA7, 0x9C, 0x98, }, // i = 0xAA + { 0xA8, 0x9E, 0x99, }, // i = 0xAB + { 0xA9, 0x9F, 0x9A, }, // i = 0xAC + { 0xAA, 0xA0, 0x9B, }, // i = 0xAD + { 0xAB, 0xA1, 0x9C, }, // i = 0xAE + { 0xAC, 0xA2, 0x9D, }, // i = 0xAF + { 0xAD, 0xA3, 0x9E, }, // i = 0xB0 + { 0xAE, 0xA4, 0x9F, }, // i = 0xB1 + { 0xAF, 0xA5, 0xA0, }, // i = 0xB2 + { 0xB0, 0xA7, 0xA1, }, // i = 0xB3 + { 0xB1, 0xA8, 0xA3, }, // i = 0xB4 + { 0xB3, 0xA9, 0xA4, }, // i = 0xB5 + { 0xB4, 0xAA, 0xA5, }, // i = 0xB6 + { 0xB5, 0xAB, 0xA6, }, // i = 0xB7 + { 0xB6, 0xAC, 0xA7, }, // i = 0xB8 + { 0xB7, 0xAD, 0xA8, }, // i = 0xB9 + { 0xB8, 0xAF, 0xA9, }, // i = 0xBA + { 0xB9, 0xB0, 0xAA, }, // i = 0xBB + { 0xBA, 0xB1, 0xAB, }, // i = 0xBC + { 0xBB, 0xB2, 0xAD, }, // i = 0xBD + { 0xBC, 0xB3, 0xAE, }, // i = 0xBE + { 0xBD, 0xB4, 0xAF, }, // i = 0xBF + { 0xBE, 0xB5, 0xB0, }, // i = 0xC0 + { 0xC0, 0xB7, 0xB1, }, // i = 0xC1 + { 0xC1, 0xB8, 0xB2, }, // i = 0xC2 + { 0xC2, 0xB9, 0xB3, }, // i = 0xC3 + { 0xC3, 0xBA, 0xB5, }, // i = 0xC4 + { 0xC4, 0xBB, 0xB6, }, // i = 0xC5 + { 0xC5, 0xBC, 0xB7, }, // i = 0xC6 + { 0xC6, 0xBE, 0xB8, }, // i = 0xC7 + { 0xC7, 0xBF, 0xB9, }, // i = 0xC8 + { 0xC8, 0xC0, 0xBA, }, // i = 0xC9 + { 0xC9, 0xC1, 0xBB, }, // i = 0xCA + { 0xCA, 0xC2, 0xBD, }, // i = 0xCB + { 0xCC, 0xC3, 0xBE, }, // i = 0xCC + { 0xCD, 0xC4, 0xBF, }, // i = 0xCD + { 0xCE, 0xC6, 0xC0, }, // i = 0xCE + { 0xCF, 0xC7, 0xC1, }, // i = 0xCF + { 0xD0, 0xC8, 0xC2, }, // i = 0xD0 + { 0xD1, 0xC9, 0xC4, }, // i = 0xD1 + { 0xD2, 0xCA, 0xC5, }, // i = 0xD2 + { 0xD3, 0xCB, 0xC6, }, // i = 0xD3 + { 0xD4, 0xCD, 0xC7, }, // i = 0xD4 + { 0xD5, 0xCE, 0xC8, }, // i = 0xD5 + { 0xD6, 0xCF, 0xCA, }, // i = 0xD6 + { 0xD7, 0xD0, 0xCB, }, // i = 0xD7 + { 0xD8, 0xD1, 0xCC, }, // i = 0xD8 + { 0xD9, 0xD2, 0xCD, }, // i = 0xD9 + { 0xDB, 0xD4, 0xCE, }, // i = 0xDA + { 0xDC, 0xD5, 0xD0, }, // i = 0xDB + { 0xDD, 0xD6, 0xD1, }, // i = 0xDC + { 0xDE, 0xD7, 0xD2, }, // i = 0xDD + { 0xDF, 0xD8, 0xD3, }, // i = 0xDE + { 0xE0, 0xD9, 0xD5, }, // i = 0xDF + { 0xE1, 0xDB, 0xD6, }, // i = 0xE0 + { 0xE2, 0xDC, 0xD7, }, // i = 0xE1 + { 0xE3, 0xDD, 0xD8, }, // i = 0xE2 + { 0xE4, 0xDE, 0xDA, }, // i = 0xE3 + { 0xE5, 0xDF, 0xDB, }, // i = 0xE4 + { 0xE6, 0xE0, 0xDC, }, // i = 0xE5 + { 0xE7, 0xE2, 0xDD, }, // i = 0xE6 + { 0xE8, 0xE3, 0xDF, }, // i = 0xE7 + { 0xE9, 0xE4, 0xE0, }, // i = 0xE8 + { 0xEA, 0xE5, 0xE1, }, // i = 0xE9 + { 0xEB, 0xE6, 0xE3, }, // i = 0xEA + { 0xEC, 0xE8, 0xE4, }, // i = 0xEB + { 0xED, 0xE9, 0xE5, }, // i = 0xEC + { 0xEE, 0xEA, 0xE7, }, // i = 0xED + { 0xEF, 0xEB, 0xE8, }, // i = 0xEE + { 0xF0, 0xEC, 0xE9, }, // i = 0xEF + { 0xF1, 0xED, 0xEB, }, // i = 0xF0 + { 0xF2, 0xEF, 0xEC, }, // i = 0xF1 + { 0xF3, 0xF0, 0xED, }, // i = 0xF2 + { 0xF4, 0xF1, 0xEF, }, // i = 0xF3 + { 0xF5, 0xF2, 0xF0, }, // i = 0xF4 + { 0xF6, 0xF3, 0xF1, }, // i = 0xF5 + { 0xF7, 0xF5, 0xF3, }, // i = 0xF6 + { 0xF8, 0xF6, 0xF4, }, // i = 0xF7 + { 0xF9, 0xF7, 0xF6, }, // i = 0xF8 + { 0xFA, 0xF8, 0xF7, }, // i = 0xF9 + { 0xFB, 0xFA, 0xF8, }, // i = 0xFA + { 0xFC, 0xFB, 0xFA, }, // i = 0xFB + { 0xFD, 0xFC, 0xFB, }, // i = 0xFC + { 0xFE, 0xFD, 0xFD, }, // i = 0xFD + { 0xFE, 0xFE, 0xFE, }, // i = 0xFE + { 0xFF, 0xFF, 0xFF, }, // i = 0xFF +}; + +// ------------------------------------------------- + +// For reference, the sRGB to CTR color space LUTs +// Above tables were computed with y = x - (f(x) - x) + +static const u8 srgbToCtrTableTop[256][3] = { + { 0x00, 0x00, 0x00, }, // i = 0x00 + { 0x01, 0x01, 0x01, }, // i = 0x01 + { 0x02, 0x03, 0x02, }, // i = 0x02 + { 0x03, 0x04, 0x03, }, // i = 0x03 + { 0x04, 0x05, 0x04, }, // i = 0x04 + { 0x05, 0x06, 0x05, }, // i = 0x05 + { 0x06, 0x08, 0x06, }, // i = 0x06 + { 0x07, 0x09, 0x08, }, // i = 0x07 + { 0x08, 0x0A, 0x09, }, // i = 0x08 + { 0x0A, 0x0C, 0x0A, }, // i = 0x09 + { 0x0B, 0x0D, 0x0B, }, // i = 0x0A + { 0x0C, 0x0E, 0x0C, }, // i = 0x0B + { 0x0D, 0x0F, 0x0D, }, // i = 0x0C + { 0x0E, 0x11, 0x0F, }, // i = 0x0D + { 0x0F, 0x12, 0x10, }, // i = 0x0E + { 0x10, 0x13, 0x11, }, // i = 0x0F + { 0x11, 0x15, 0x12, }, // i = 0x10 + { 0x12, 0x16, 0x13, }, // i = 0x11 + { 0x14, 0x17, 0x15, }, // i = 0x12 + { 0x15, 0x18, 0x16, }, // i = 0x13 + { 0x16, 0x1A, 0x17, }, // i = 0x14 + { 0x17, 0x1B, 0x18, }, // i = 0x15 + { 0x18, 0x1C, 0x1A, }, // i = 0x16 + { 0x19, 0x1D, 0x1B, }, // i = 0x17 + { 0x1A, 0x1F, 0x1C, }, // i = 0x18 + { 0x1C, 0x20, 0x1D, }, // i = 0x19 + { 0x1D, 0x21, 0x1F, }, // i = 0x1A + { 0x1E, 0x22, 0x20, }, // i = 0x1B + { 0x1F, 0x24, 0x21, }, // i = 0x1C + { 0x20, 0x25, 0x22, }, // i = 0x1D + { 0x21, 0x26, 0x24, }, // i = 0x1E + { 0x22, 0x27, 0x25, }, // i = 0x1F + { 0x24, 0x29, 0x26, }, // i = 0x20 + { 0x25, 0x2A, 0x27, }, // i = 0x21 + { 0x26, 0x2B, 0x29, }, // i = 0x22 + { 0x27, 0x2C, 0x2A, }, // i = 0x23 + { 0x28, 0x2D, 0x2B, }, // i = 0x24 + { 0x29, 0x2F, 0x2C, }, // i = 0x25 + { 0x2A, 0x30, 0x2E, }, // i = 0x26 + { 0x2B, 0x31, 0x2F, }, // i = 0x27 + { 0x2D, 0x32, 0x30, }, // i = 0x28 + { 0x2E, 0x33, 0x31, }, // i = 0x29 + { 0x2F, 0x35, 0x33, }, // i = 0x2A + { 0x30, 0x36, 0x34, }, // i = 0x2B + { 0x31, 0x37, 0x35, }, // i = 0x2C + { 0x32, 0x38, 0x36, }, // i = 0x2D + { 0x33, 0x39, 0x38, }, // i = 0x2E + { 0x34, 0x3A, 0x39, }, // i = 0x2F + { 0x35, 0x3C, 0x3A, }, // i = 0x30 + { 0x36, 0x3D, 0x3B, }, // i = 0x31 + { 0x37, 0x3E, 0x3C, }, // i = 0x32 + { 0x38, 0x3F, 0x3E, }, // i = 0x33 + { 0x3A, 0x40, 0x3F, }, // i = 0x34 + { 0x3B, 0x41, 0x40, }, // i = 0x35 + { 0x3C, 0x42, 0x41, }, // i = 0x36 + { 0x3D, 0x43, 0x43, }, // i = 0x37 + { 0x3E, 0x45, 0x44, }, // i = 0x38 + { 0x3F, 0x46, 0x45, }, // i = 0x39 + { 0x40, 0x47, 0x46, }, // i = 0x3A + { 0x41, 0x48, 0x47, }, // i = 0x3B + { 0x42, 0x49, 0x48, }, // i = 0x3C + { 0x43, 0x4A, 0x4A, }, // i = 0x3D + { 0x44, 0x4B, 0x4B, }, // i = 0x3E + { 0x45, 0x4C, 0x4C, }, // i = 0x3F + { 0x46, 0x4D, 0x4D, }, // i = 0x40 + { 0x47, 0x4E, 0x4E, }, // i = 0x41 + { 0x48, 0x4F, 0x50, }, // i = 0x42 + { 0x49, 0x51, 0x51, }, // i = 0x43 + { 0x4A, 0x52, 0x52, }, // i = 0x44 + { 0x4B, 0x53, 0x53, }, // i = 0x45 + { 0x4C, 0x54, 0x54, }, // i = 0x46 + { 0x4D, 0x55, 0x55, }, // i = 0x47 + { 0x4E, 0x56, 0x56, }, // i = 0x48 + { 0x4F, 0x57, 0x58, }, // i = 0x49 + { 0x50, 0x58, 0x59, }, // i = 0x4A + { 0x51, 0x59, 0x5A, }, // i = 0x4B + { 0x52, 0x5A, 0x5B, }, // i = 0x4C + { 0x53, 0x5B, 0x5C, }, // i = 0x4D + { 0x54, 0x5C, 0x5D, }, // i = 0x4E + { 0x55, 0x5D, 0x5E, }, // i = 0x4F + { 0x56, 0x5E, 0x5F, }, // i = 0x50 + { 0x57, 0x5F, 0x61, }, // i = 0x51 + { 0x58, 0x60, 0x62, }, // i = 0x52 + { 0x59, 0x61, 0x63, }, // i = 0x53 + { 0x5A, 0x62, 0x64, }, // i = 0x54 + { 0x5B, 0x63, 0x65, }, // i = 0x55 + { 0x5C, 0x64, 0x66, }, // i = 0x56 + { 0x5D, 0x65, 0x67, }, // i = 0x57 + { 0x5E, 0x66, 0x68, }, // i = 0x58 + { 0x5F, 0x67, 0x69, }, // i = 0x59 + { 0x60, 0x68, 0x6A, }, // i = 0x5A + { 0x61, 0x69, 0x6B, }, // i = 0x5B + { 0x62, 0x6A, 0x6D, }, // i = 0x5C + { 0x63, 0x6B, 0x6E, }, // i = 0x5D + { 0x64, 0x6C, 0x6F, }, // i = 0x5E + { 0x65, 0x6D, 0x70, }, // i = 0x5F + { 0x65, 0x6E, 0x71, }, // i = 0x60 + { 0x66, 0x6F, 0x72, }, // i = 0x61 + { 0x67, 0x70, 0x73, }, // i = 0x62 + { 0x68, 0x71, 0x74, }, // i = 0x63 + { 0x69, 0x72, 0x75, }, // i = 0x64 + { 0x6A, 0x73, 0x76, }, // i = 0x65 + { 0x6B, 0x74, 0x77, }, // i = 0x66 + { 0x6C, 0x75, 0x78, }, // i = 0x67 + { 0x6D, 0x76, 0x79, }, // i = 0x68 + { 0x6E, 0x77, 0x7B, }, // i = 0x69 + { 0x6F, 0x78, 0x7C, }, // i = 0x6A + { 0x70, 0x79, 0x7D, }, // i = 0x6B + { 0x71, 0x7A, 0x7E, }, // i = 0x6C + { 0x72, 0x7B, 0x7F, }, // i = 0x6D + { 0x73, 0x7C, 0x80, }, // i = 0x6E + { 0x74, 0x7D, 0x81, }, // i = 0x6F + { 0x75, 0x7E, 0x82, }, // i = 0x70 + { 0x76, 0x7F, 0x83, }, // i = 0x71 + { 0x77, 0x80, 0x84, }, // i = 0x72 + { 0x78, 0x81, 0x85, }, // i = 0x73 + { 0x79, 0x82, 0x86, }, // i = 0x74 + { 0x7A, 0x83, 0x87, }, // i = 0x75 + { 0x7B, 0x84, 0x88, }, // i = 0x76 + { 0x7B, 0x85, 0x89, }, // i = 0x77 + { 0x7C, 0x86, 0x8A, }, // i = 0x78 + { 0x7D, 0x87, 0x8B, }, // i = 0x79 + { 0x7E, 0x88, 0x8C, }, // i = 0x7A + { 0x7F, 0x89, 0x8E, }, // i = 0x7B + { 0x80, 0x8A, 0x8F, }, // i = 0x7C + { 0x81, 0x8B, 0x90, }, // i = 0x7D + { 0x82, 0x8C, 0x91, }, // i = 0x7E + { 0x83, 0x8D, 0x92, }, // i = 0x7F + { 0x84, 0x8E, 0x93, }, // i = 0x80 + { 0x85, 0x8F, 0x94, }, // i = 0x81 + { 0x86, 0x90, 0x95, }, // i = 0x82 + { 0x87, 0x91, 0x96, }, // i = 0x83 + { 0x88, 0x92, 0x97, }, // i = 0x84 + { 0x89, 0x93, 0x98, }, // i = 0x85 + { 0x8A, 0x94, 0x99, }, // i = 0x86 + { 0x8B, 0x95, 0x9A, }, // i = 0x87 + { 0x8C, 0x96, 0x9B, }, // i = 0x88 + { 0x8D, 0x97, 0x9C, }, // i = 0x89 + { 0x8E, 0x98, 0x9D, }, // i = 0x8A + { 0x8F, 0x99, 0x9E, }, // i = 0x8B + { 0x90, 0x9A, 0x9F, }, // i = 0x8C + { 0x91, 0x9B, 0xA0, }, // i = 0x8D + { 0x92, 0x9B, 0xA1, }, // i = 0x8E + { 0x93, 0x9C, 0xA2, }, // i = 0x8F + { 0x94, 0x9D, 0xA4, }, // i = 0x90 + { 0x95, 0x9E, 0xA5, }, // i = 0x91 + { 0x96, 0x9F, 0xA6, }, // i = 0x92 + { 0x97, 0xA0, 0xA7, }, // i = 0x93 + { 0x98, 0xA1, 0xA8, }, // i = 0x94 + { 0x99, 0xA2, 0xA9, }, // i = 0x95 + { 0x9A, 0xA3, 0xAA, }, // i = 0x96 + { 0x9B, 0xA4, 0xAB, }, // i = 0x97 + { 0x9C, 0xA5, 0xAC, }, // i = 0x98 + { 0x9D, 0xA6, 0xAD, }, // i = 0x99 + { 0x9E, 0xA7, 0xAE, }, // i = 0x9A + { 0x9F, 0xA8, 0xAF, }, // i = 0x9B + { 0xA0, 0xA9, 0xB0, }, // i = 0x9C + { 0xA1, 0xAA, 0xB1, }, // i = 0x9D + { 0xA2, 0xAB, 0xB2, }, // i = 0x9E + { 0xA3, 0xAC, 0xB3, }, // i = 0x9F + { 0xA4, 0xAD, 0xB4, }, // i = 0xA0 + { 0xA5, 0xAE, 0xB5, }, // i = 0xA1 + { 0xA6, 0xAF, 0xB6, }, // i = 0xA2 + { 0xA7, 0xB0, 0xB7, }, // i = 0xA3 + { 0xA8, 0xB1, 0xB8, }, // i = 0xA4 + { 0xA9, 0xB2, 0xB9, }, // i = 0xA5 + { 0xAA, 0xB3, 0xBA, }, // i = 0xA6 + { 0xAA, 0xB4, 0xBB, }, // i = 0xA7 + { 0xAB, 0xB5, 0xBC, }, // i = 0xA8 + { 0xAC, 0xB6, 0xBD, }, // i = 0xA9 + { 0xAD, 0xB7, 0xBE, }, // i = 0xAA + { 0xAE, 0xB7, 0xBF, }, // i = 0xAB + { 0xAF, 0xB8, 0xC0, }, // i = 0xAC + { 0xB0, 0xB9, 0xC1, }, // i = 0xAD + { 0xB1, 0xBA, 0xC2, }, // i = 0xAE + { 0xB2, 0xBB, 0xC3, }, // i = 0xAF + { 0xB3, 0xBC, 0xC4, }, // i = 0xB0 + { 0xB4, 0xBD, 0xC5, }, // i = 0xB1 + { 0xB5, 0xBE, 0xC6, }, // i = 0xB2 + { 0xB6, 0xBF, 0xC7, }, // i = 0xB3 + { 0xB7, 0xC0, 0xC8, }, // i = 0xB4 + { 0xB8, 0xC1, 0xC9, }, // i = 0xB5 + { 0xB9, 0xC2, 0xCA, }, // i = 0xB6 + { 0xBA, 0xC3, 0xCB, }, // i = 0xB7 + { 0xBB, 0xC4, 0xCC, }, // i = 0xB8 + { 0xBC, 0xC5, 0xCD, }, // i = 0xB9 + { 0xBD, 0xC5, 0xCE, }, // i = 0xBA + { 0xBE, 0xC6, 0xCF, }, // i = 0xBB + { 0xBF, 0xC7, 0xCF, }, // i = 0xBC + { 0xC0, 0xC8, 0xD0, }, // i = 0xBD + { 0xC1, 0xC9, 0xD1, }, // i = 0xBE + { 0xC2, 0xCA, 0xD2, }, // i = 0xBF + { 0xC3, 0xCB, 0xD3, }, // i = 0xC0 + { 0xC4, 0xCC, 0xD4, }, // i = 0xC1 + { 0xC5, 0xCD, 0xD5, }, // i = 0xC2 + { 0xC6, 0xCD, 0xD6, }, // i = 0xC3 + { 0xC7, 0xCE, 0xD7, }, // i = 0xC4 + { 0xC7, 0xCF, 0xD8, }, // i = 0xC5 + { 0xC8, 0xD0, 0xD8, }, // i = 0xC6 + { 0xC9, 0xD1, 0xD9, }, // i = 0xC7 + { 0xCA, 0xD2, 0xDA, }, // i = 0xC8 + { 0xCB, 0xD3, 0xDB, }, // i = 0xC9 + { 0xCC, 0xD4, 0xDC, }, // i = 0xCA + { 0xCD, 0xD4, 0xDD, }, // i = 0xCB + { 0xCE, 0xD5, 0xDD, }, // i = 0xCC + { 0xCF, 0xD6, 0xDE, }, // i = 0xCD + { 0xD0, 0xD7, 0xDF, }, // i = 0xCE + { 0xD1, 0xD8, 0xE0, }, // i = 0xCF + { 0xD2, 0xD9, 0xE1, }, // i = 0xD0 + { 0xD3, 0xDA, 0xE1, }, // i = 0xD1 + { 0xD4, 0xDA, 0xE2, }, // i = 0xD2 + { 0xD4, 0xDB, 0xE3, }, // i = 0xD3 + { 0xD5, 0xDC, 0xE4, }, // i = 0xD4 + { 0xD6, 0xDD, 0xE5, }, // i = 0xD5 + { 0xD7, 0xDE, 0xE5, }, // i = 0xD6 + { 0xD8, 0xDF, 0xE6, }, // i = 0xD7 + { 0xD9, 0xDF, 0xE7, }, // i = 0xD8 + { 0xDA, 0xE0, 0xE7, }, // i = 0xD9 + { 0xDB, 0xE1, 0xE8, }, // i = 0xDA + { 0xDC, 0xE2, 0xE9, }, // i = 0xDB + { 0xDD, 0xE3, 0xEA, }, // i = 0xDC + { 0xDE, 0xE3, 0xEA, }, // i = 0xDD + { 0xDE, 0xE4, 0xEB, }, // i = 0xDE + { 0xDF, 0xE5, 0xEC, }, // i = 0xDF + { 0xE0, 0xE6, 0xEC, }, // i = 0xE0 + { 0xE1, 0xE7, 0xED, }, // i = 0xE1 + { 0xE2, 0xE7, 0xEE, }, // i = 0xE2 + { 0xE3, 0xE8, 0xEE, }, // i = 0xE3 + { 0xE4, 0xE9, 0xEF, }, // i = 0xE4 + { 0xE5, 0xEA, 0xF0, }, // i = 0xE5 + { 0xE6, 0xEB, 0xF0, }, // i = 0xE6 + { 0xE7, 0xEB, 0xF1, }, // i = 0xE7 + { 0xE8, 0xEC, 0xF2, }, // i = 0xE8 + { 0xE8, 0xED, 0xF2, }, // i = 0xE9 + { 0xE9, 0xEE, 0xF3, }, // i = 0xEA + { 0xEA, 0xEF, 0xF4, }, // i = 0xEB + { 0xEB, 0xEF, 0xF4, }, // i = 0xEC + { 0xEC, 0xF0, 0xF5, }, // i = 0xED + { 0xED, 0xF1, 0xF5, }, // i = 0xEE + { 0xEE, 0xF2, 0xF6, }, // i = 0xEF + { 0xEF, 0xF3, 0xF7, }, // i = 0xF0 + { 0xF0, 0xF3, 0xF7, }, // i = 0xF1 + { 0xF1, 0xF4, 0xF8, }, // i = 0xF2 + { 0xF2, 0xF5, 0xF8, }, // i = 0xF3 + { 0xF3, 0xF6, 0xF9, }, // i = 0xF4 + { 0xF4, 0xF7, 0xF9, }, // i = 0xF5 + { 0xF5, 0xF7, 0xFA, }, // i = 0xF6 + { 0xF6, 0xF8, 0xFB, }, // i = 0xF7 + { 0xF7, 0xF9, 0xFB, }, // i = 0xF8 + { 0xF8, 0xFA, 0xFC, }, // i = 0xF9 + { 0xF9, 0xFB, 0xFC, }, // i = 0xFA + { 0xFA, 0xFC, 0xFD, }, // i = 0xFB + { 0xFB, 0xFC, 0xFE, }, // i = 0xFC + { 0xFD, 0xFD, 0xFE, }, // i = 0xFD + { 0xFE, 0xFE, 0xFF, }, // i = 0xFE + { 0xFF, 0xFF, 0xFF, }, // i = 0xFF +}; + +static const u8 srgbToCtrTableBottom[256][3] = { + { 0x00, 0x00, 0x00, }, // i = 0x00 + { 0x01, 0x02, 0x02, }, // i = 0x01 + { 0x03, 0x04, 0x03, }, // i = 0x02 + { 0x04, 0x05, 0x05, }, // i = 0x03 + { 0x06, 0x07, 0x06, }, // i = 0x04 + { 0x07, 0x09, 0x07, }, // i = 0x05 + { 0x08, 0x0A, 0x09, }, // i = 0x06 + { 0x0A, 0x0C, 0x0A, }, // i = 0x07 + { 0x0B, 0x0E, 0x0C, }, // i = 0x08 + { 0x0D, 0x0F, 0x0D, }, // i = 0x09 + { 0x0E, 0x11, 0x0F, }, // i = 0x0A + { 0x0F, 0x12, 0x10, }, // i = 0x0B + { 0x11, 0x14, 0x11, }, // i = 0x0C + { 0x12, 0x15, 0x13, }, // i = 0x0D + { 0x13, 0x17, 0x14, }, // i = 0x0E + { 0x14, 0x18, 0x16, }, // i = 0x0F + { 0x16, 0x1A, 0x17, }, // i = 0x10 + { 0x17, 0x1B, 0x18, }, // i = 0x11 + { 0x18, 0x1C, 0x1A, }, // i = 0x12 + { 0x1A, 0x1E, 0x1B, }, // i = 0x13 + { 0x1B, 0x1F, 0x1C, }, // i = 0x14 + { 0x1C, 0x21, 0x1E, }, // i = 0x15 + { 0x1D, 0x22, 0x1F, }, // i = 0x16 + { 0x1E, 0x23, 0x20, }, // i = 0x17 + { 0x20, 0x25, 0x21, }, // i = 0x18 + { 0x21, 0x26, 0x23, }, // i = 0x19 + { 0x22, 0x27, 0x24, }, // i = 0x1A + { 0x23, 0x29, 0x25, }, // i = 0x1B + { 0x24, 0x2A, 0x26, }, // i = 0x1C + { 0x26, 0x2B, 0x28, }, // i = 0x1D + { 0x27, 0x2C, 0x29, }, // i = 0x1E + { 0x28, 0x2E, 0x2A, }, // i = 0x1F + { 0x29, 0x2F, 0x2B, }, // i = 0x20 + { 0x2A, 0x30, 0x2D, }, // i = 0x21 + { 0x2B, 0x31, 0x2E, }, // i = 0x22 + { 0x2D, 0x33, 0x2F, }, // i = 0x23 + { 0x2E, 0x34, 0x30, }, // i = 0x24 + { 0x2F, 0x35, 0x32, }, // i = 0x25 + { 0x30, 0x36, 0x33, }, // i = 0x26 + { 0x31, 0x37, 0x34, }, // i = 0x27 + { 0x32, 0x38, 0x35, }, // i = 0x28 + { 0x33, 0x3A, 0x36, }, // i = 0x29 + { 0x34, 0x3B, 0x38, }, // i = 0x2A + { 0x35, 0x3C, 0x39, }, // i = 0x2B + { 0x36, 0x3D, 0x3A, }, // i = 0x2C + { 0x38, 0x3E, 0x3B, }, // i = 0x2D + { 0x39, 0x3F, 0x3C, }, // i = 0x2E + { 0x3A, 0x40, 0x3D, }, // i = 0x2F + { 0x3B, 0x42, 0x3F, }, // i = 0x30 + { 0x3C, 0x43, 0x40, }, // i = 0x31 + { 0x3D, 0x44, 0x41, }, // i = 0x32 + { 0x3E, 0x45, 0x42, }, // i = 0x33 + { 0x3F, 0x46, 0x43, }, // i = 0x34 + { 0x40, 0x47, 0x44, }, // i = 0x35 + { 0x41, 0x48, 0x45, }, // i = 0x36 + { 0x42, 0x49, 0x47, }, // i = 0x37 + { 0x43, 0x4A, 0x48, }, // i = 0x38 + { 0x44, 0x4B, 0x49, }, // i = 0x39 + { 0x45, 0x4C, 0x4A, }, // i = 0x3A + { 0x46, 0x4D, 0x4B, }, // i = 0x3B + { 0x47, 0x4E, 0x4C, }, // i = 0x3C + { 0x48, 0x50, 0x4D, }, // i = 0x3D + { 0x49, 0x51, 0x4E, }, // i = 0x3E + { 0x4A, 0x52, 0x50, }, // i = 0x3F + { 0x4B, 0x53, 0x51, }, // i = 0x40 + { 0x4C, 0x54, 0x52, }, // i = 0x41 + { 0x4D, 0x55, 0x53, }, // i = 0x42 + { 0x4E, 0x56, 0x54, }, // i = 0x43 + { 0x4F, 0x57, 0x55, }, // i = 0x44 + { 0x50, 0x58, 0x56, }, // i = 0x45 + { 0x51, 0x59, 0x57, }, // i = 0x46 + { 0x52, 0x5A, 0x58, }, // i = 0x47 + { 0x53, 0x5B, 0x5A, }, // i = 0x48 + { 0x54, 0x5C, 0x5B, }, // i = 0x49 + { 0x55, 0x5D, 0x5C, }, // i = 0x4A + { 0x56, 0x5E, 0x5D, }, // i = 0x4B + { 0x57, 0x5F, 0x5E, }, // i = 0x4C + { 0x58, 0x60, 0x5F, }, // i = 0x4D + { 0x59, 0x61, 0x60, }, // i = 0x4E + { 0x5A, 0x62, 0x61, }, // i = 0x4F + { 0x5B, 0x63, 0x62, }, // i = 0x50 + { 0x5C, 0x64, 0x63, }, // i = 0x51 + { 0x5D, 0x65, 0x64, }, // i = 0x52 + { 0x5D, 0x66, 0x65, }, // i = 0x53 + { 0x5E, 0x67, 0x66, }, // i = 0x54 + { 0x5F, 0x68, 0x68, }, // i = 0x55 + { 0x60, 0x69, 0x69, }, // i = 0x56 + { 0x61, 0x6A, 0x6A, }, // i = 0x57 + { 0x62, 0x6B, 0x6B, }, // i = 0x58 + { 0x63, 0x6C, 0x6C, }, // i = 0x59 + { 0x64, 0x6D, 0x6D, }, // i = 0x5A + { 0x65, 0x6E, 0x6E, }, // i = 0x5B + { 0x66, 0x6F, 0x6F, }, // i = 0x5C + { 0x67, 0x70, 0x70, }, // i = 0x5D + { 0x68, 0x71, 0x71, }, // i = 0x5E + { 0x69, 0x72, 0x72, }, // i = 0x5F + { 0x6A, 0x73, 0x73, }, // i = 0x60 + { 0x6B, 0x74, 0x74, }, // i = 0x61 + { 0x6C, 0x75, 0x75, }, // i = 0x62 + { 0x6C, 0x76, 0x76, }, // i = 0x63 + { 0x6D, 0x77, 0x77, }, // i = 0x64 + { 0x6E, 0x78, 0x78, }, // i = 0x65 + { 0x6F, 0x79, 0x79, }, // i = 0x66 + { 0x70, 0x7A, 0x7A, }, // i = 0x67 + { 0x71, 0x7B, 0x7C, }, // i = 0x68 + { 0x72, 0x7C, 0x7D, }, // i = 0x69 + { 0x73, 0x7D, 0x7E, }, // i = 0x6A + { 0x74, 0x7E, 0x7F, }, // i = 0x6B + { 0x75, 0x7F, 0x80, }, // i = 0x6C + { 0x76, 0x7F, 0x81, }, // i = 0x6D + { 0x77, 0x80, 0x82, }, // i = 0x6E + { 0x78, 0x81, 0x83, }, // i = 0x6F + { 0x78, 0x82, 0x84, }, // i = 0x70 + { 0x79, 0x83, 0x85, }, // i = 0x71 + { 0x7A, 0x84, 0x86, }, // i = 0x72 + { 0x7B, 0x85, 0x87, }, // i = 0x73 + { 0x7C, 0x86, 0x88, }, // i = 0x74 + { 0x7D, 0x87, 0x89, }, // i = 0x75 + { 0x7E, 0x88, 0x8A, }, // i = 0x76 + { 0x7F, 0x89, 0x8B, }, // i = 0x77 + { 0x80, 0x8A, 0x8C, }, // i = 0x78 + { 0x81, 0x8B, 0x8D, }, // i = 0x79 + { 0x82, 0x8C, 0x8E, }, // i = 0x7A + { 0x83, 0x8D, 0x8F, }, // i = 0x7B + { 0x84, 0x8E, 0x90, }, // i = 0x7C + { 0x84, 0x8F, 0x91, }, // i = 0x7D + { 0x85, 0x90, 0x92, }, // i = 0x7E + { 0x86, 0x91, 0x93, }, // i = 0x7F + { 0x87, 0x92, 0x94, }, // i = 0x80 + { 0x88, 0x92, 0x95, }, // i = 0x81 + { 0x89, 0x93, 0x96, }, // i = 0x82 + { 0x8A, 0x94, 0x97, }, // i = 0x83 + { 0x8B, 0x95, 0x98, }, // i = 0x84 + { 0x8C, 0x96, 0x99, }, // i = 0x85 + { 0x8D, 0x97, 0x9A, }, // i = 0x86 + { 0x8E, 0x98, 0x9B, }, // i = 0x87 + { 0x8E, 0x99, 0x9C, }, // i = 0x88 + { 0x8F, 0x9A, 0x9D, }, // i = 0x89 + { 0x90, 0x9B, 0x9E, }, // i = 0x8A + { 0x91, 0x9C, 0x9F, }, // i = 0x8B + { 0x92, 0x9D, 0xA0, }, // i = 0x8C + { 0x93, 0x9E, 0xA1, }, // i = 0x8D + { 0x94, 0x9E, 0xA2, }, // i = 0x8E + { 0x95, 0x9F, 0xA3, }, // i = 0x8F + { 0x96, 0xA0, 0xA4, }, // i = 0x90 + { 0x97, 0xA1, 0xA5, }, // i = 0x91 + { 0x98, 0xA2, 0xA6, }, // i = 0x92 + { 0x99, 0xA3, 0xA7, }, // i = 0x93 + { 0x99, 0xA4, 0xA8, }, // i = 0x94 + { 0x9A, 0xA5, 0xA9, }, // i = 0x95 + { 0x9B, 0xA6, 0xAA, }, // i = 0x96 + { 0x9C, 0xA7, 0xAA, }, // i = 0x97 + { 0x9D, 0xA8, 0xAB, }, // i = 0x98 + { 0x9E, 0xA8, 0xAC, }, // i = 0x99 + { 0x9F, 0xA9, 0xAD, }, // i = 0x9A + { 0xA0, 0xAA, 0xAE, }, // i = 0x9B + { 0xA1, 0xAB, 0xAF, }, // i = 0x9C + { 0xA2, 0xAC, 0xB0, }, // i = 0x9D + { 0xA3, 0xAD, 0xB1, }, // i = 0x9E + { 0xA3, 0xAE, 0xB2, }, // i = 0x9F + { 0xA4, 0xAF, 0xB3, }, // i = 0xA0 + { 0xA5, 0xB0, 0xB4, }, // i = 0xA1 + { 0xA6, 0xB0, 0xB5, }, // i = 0xA2 + { 0xA7, 0xB1, 0xB6, }, // i = 0xA3 + { 0xA8, 0xB2, 0xB7, }, // i = 0xA4 + { 0xA9, 0xB3, 0xB8, }, // i = 0xA5 + { 0xAA, 0xB4, 0xB9, }, // i = 0xA6 + { 0xAB, 0xB5, 0xBA, }, // i = 0xA7 + { 0xAC, 0xB6, 0xBB, }, // i = 0xA8 + { 0xAD, 0xB7, 0xBB, }, // i = 0xA9 + { 0xAD, 0xB8, 0xBC, }, // i = 0xAA + { 0xAE, 0xB8, 0xBD, }, // i = 0xAB + { 0xAF, 0xB9, 0xBE, }, // i = 0xAC + { 0xB0, 0xBA, 0xBF, }, // i = 0xAD + { 0xB1, 0xBB, 0xC0, }, // i = 0xAE + { 0xB2, 0xBC, 0xC1, }, // i = 0xAF + { 0xB3, 0xBD, 0xC2, }, // i = 0xB0 + { 0xB4, 0xBE, 0xC3, }, // i = 0xB1 + { 0xB5, 0xBF, 0xC4, }, // i = 0xB2 + { 0xB6, 0xBF, 0xC5, }, // i = 0xB3 + { 0xB7, 0xC0, 0xC5, }, // i = 0xB4 + { 0xB7, 0xC1, 0xC6, }, // i = 0xB5 + { 0xB8, 0xC2, 0xC7, }, // i = 0xB6 + { 0xB9, 0xC3, 0xC8, }, // i = 0xB7 + { 0xBA, 0xC4, 0xC9, }, // i = 0xB8 + { 0xBB, 0xC5, 0xCA, }, // i = 0xB9 + { 0xBC, 0xC5, 0xCB, }, // i = 0xBA + { 0xBD, 0xC6, 0xCC, }, // i = 0xBB + { 0xBE, 0xC7, 0xCD, }, // i = 0xBC + { 0xBF, 0xC8, 0xCD, }, // i = 0xBD + { 0xC0, 0xC9, 0xCE, }, // i = 0xBE + { 0xC1, 0xCA, 0xCF, }, // i = 0xBF + { 0xC2, 0xCB, 0xD0, }, // i = 0xC0 + { 0xC2, 0xCB, 0xD1, }, // i = 0xC1 + { 0xC3, 0xCC, 0xD2, }, // i = 0xC2 + { 0xC4, 0xCD, 0xD3, }, // i = 0xC3 + { 0xC5, 0xCE, 0xD3, }, // i = 0xC4 + { 0xC6, 0xCF, 0xD4, }, // i = 0xC5 + { 0xC7, 0xD0, 0xD5, }, // i = 0xC6 + { 0xC8, 0xD0, 0xD6, }, // i = 0xC7 + { 0xC9, 0xD1, 0xD7, }, // i = 0xC8 + { 0xCA, 0xD2, 0xD8, }, // i = 0xC9 + { 0xCB, 0xD3, 0xD9, }, // i = 0xCA + { 0xCC, 0xD4, 0xD9, }, // i = 0xCB + { 0xCC, 0xD5, 0xDA, }, // i = 0xCC + { 0xCD, 0xD6, 0xDB, }, // i = 0xCD + { 0xCE, 0xD6, 0xDC, }, // i = 0xCE + { 0xCF, 0xD7, 0xDD, }, // i = 0xCF + { 0xD0, 0xD8, 0xDE, }, // i = 0xD0 + { 0xD1, 0xD9, 0xDE, }, // i = 0xD1 + { 0xD2, 0xDA, 0xDF, }, // i = 0xD2 + { 0xD3, 0xDB, 0xE0, }, // i = 0xD3 + { 0xD4, 0xDB, 0xE1, }, // i = 0xD4 + { 0xD5, 0xDC, 0xE2, }, // i = 0xD5 + { 0xD6, 0xDD, 0xE2, }, // i = 0xD6 + { 0xD7, 0xDE, 0xE3, }, // i = 0xD7 + { 0xD8, 0xDF, 0xE4, }, // i = 0xD8 + { 0xD9, 0xE0, 0xE5, }, // i = 0xD9 + { 0xD9, 0xE0, 0xE6, }, // i = 0xDA + { 0xDA, 0xE1, 0xE6, }, // i = 0xDB + { 0xDB, 0xE2, 0xE7, }, // i = 0xDC + { 0xDC, 0xE3, 0xE8, }, // i = 0xDD + { 0xDD, 0xE4, 0xE9, }, // i = 0xDE + { 0xDE, 0xE5, 0xE9, }, // i = 0xDF + { 0xDF, 0xE5, 0xEA, }, // i = 0xE0 + { 0xE0, 0xE6, 0xEB, }, // i = 0xE1 + { 0xE1, 0xE7, 0xEC, }, // i = 0xE2 + { 0xE2, 0xE8, 0xEC, }, // i = 0xE3 + { 0xE3, 0xE9, 0xED, }, // i = 0xE4 + { 0xE4, 0xEA, 0xEE, }, // i = 0xE5 + { 0xE5, 0xEA, 0xEF, }, // i = 0xE6 + { 0xE6, 0xEB, 0xEF, }, // i = 0xE7 + { 0xE7, 0xEC, 0xF0, }, // i = 0xE8 + { 0xE8, 0xED, 0xF1, }, // i = 0xE9 + { 0xE9, 0xEE, 0xF1, }, // i = 0xEA + { 0xEA, 0xEE, 0xF2, }, // i = 0xEB + { 0xEB, 0xEF, 0xF3, }, // i = 0xEC + { 0xEC, 0xF0, 0xF3, }, // i = 0xED + { 0xED, 0xF1, 0xF4, }, // i = 0xEE + { 0xEE, 0xF2, 0xF5, }, // i = 0xEF + { 0xEF, 0xF3, 0xF5, }, // i = 0xF0 + { 0xF0, 0xF3, 0xF6, }, // i = 0xF1 + { 0xF1, 0xF4, 0xF7, }, // i = 0xF2 + { 0xF2, 0xF5, 0xF7, }, // i = 0xF3 + { 0xF3, 0xF6, 0xF8, }, // i = 0xF4 + { 0xF4, 0xF7, 0xF9, }, // i = 0xF5 + { 0xF5, 0xF7, 0xF9, }, // i = 0xF6 + { 0xF6, 0xF8, 0xFA, }, // i = 0xF7 + { 0xF7, 0xF9, 0xFA, }, // i = 0xF8 + { 0xF8, 0xFA, 0xFB, }, // i = 0xF9 + { 0xF9, 0xFA, 0xFC, }, // i = 0xFA + { 0xFA, 0xFB, 0xFC, }, // i = 0xFB + { 0xFB, 0xFC, 0xFD, }, // i = 0xFC + { 0xFC, 0xFD, 0xFD, }, // i = 0xFD + { 0xFE, 0xFE, 0xFE, }, // i = 0xFE + { 0xFF, 0xFE, 0xFE, }, // i = 0xFF +}; \ No newline at end of file diff --git a/sysmodules/rosalina/source/luma_config.c b/sysmodules/rosalina/source/luma_config.c index d4e6a3a9..5b877474 100644 --- a/sysmodules/rosalina/source/luma_config.c +++ b/sysmodules/rosalina/source/luma_config.c @@ -180,6 +180,7 @@ static size_t LumaConfig_SaveLumaIniConfigToStr(char *out, const CfgData *cfg) (int)cfg->ntpTzOffetMinutes, (int)cfg->topScreenFilter.cct, (int)cfg->bottomScreenFilter.cct, + (int)cfg->topScreenFilter.colorCurveCorrection, (int)cfg->bottomScreenFilter.colorCurveCorrection, topScreenFilterGammaStr, bottomScreenFilterGammaStr, topScreenFilterContrastStr, bottomScreenFilterContrastStr, topScreenFilterBrightnessStr, bottomScreenFilterBrightnessStr, diff --git a/sysmodules/rosalina/source/menus/screen_filters.c b/sysmodules/rosalina/source/menus/screen_filters.c index 53f9c620..002cfb19 100644 --- a/sysmodules/rosalina/source/menus/screen_filters.c +++ b/sysmodules/rosalina/source/menus/screen_filters.c @@ -29,6 +29,7 @@ #include "memory.h" #include "menu.h" #include "menus/screen_filters.h" +#include "menus/screen_filters_srgb_tables.h" #include "draw.h" #include "redshift/colorramp.h" @@ -53,6 +54,7 @@ static inline bool ScreenFiltersMenu_IsDefaultSettingsFilter(const ScreenFilter ok = ok && filter->gamma == 1.0f; ok = ok && filter->contrast == 1.0f; ok = ok && filter->brightness == 0.0f; + ok = ok && filter->colorCurveCorrection == 0; return ok; } @@ -89,7 +91,7 @@ static u8 ScreenFilterMenu_CalculatePolynomialColorLutComponent(const float coef return (u8)CLAMP(levelInt, 0, 255); // clamp again just to be sure } -static void ScreenFilterMenu_WritePolynomialColorLut(bool top, const float coeffs[][3], bool invert, float gamma, u32 dim) +static void ScreenFilterMenu_WritePolynomialColorLut(bool top, u8 curveCorrection, const float coeffs[][3], bool invert, float gamma, u32 dim) { if (top) GPU_FB_TOP_COL_LUT_INDEX = 0; @@ -99,9 +101,15 @@ static void ScreenFilterMenu_WritePolynomialColorLut(bool top, const float coeff for (int i = 0; i <= 255; i++) { Pixel px; int inLevel = invert ? 255 - i : i; - px.r = ScreenFilterMenu_CalculatePolynomialColorLutComponent(coeffs, 0, gamma, dim, inLevel); - px.g = ScreenFilterMenu_CalculatePolynomialColorLutComponent(coeffs, 1, gamma, dim, inLevel); - px.b = ScreenFilterMenu_CalculatePolynomialColorLutComponent(coeffs, 2, gamma, dim, inLevel); + const u8 (*tbl)[3] = curveCorrection == 2 ? ctrToSrgbTableTop : ctrToSrgbTableBottom; + + u8 inLevelR = curveCorrection > 0 ? tbl[inLevel][0] : inLevel; + u8 inLevelG = curveCorrection > 0 ? tbl[inLevel][1] : inLevel; + u8 inLevelB = curveCorrection > 0 ? tbl[inLevel][2] : inLevel; + + px.r = ScreenFilterMenu_CalculatePolynomialColorLutComponent(coeffs, 0, gamma, dim, inLevelR); + px.g = ScreenFilterMenu_CalculatePolynomialColorLutComponent(coeffs, 1, gamma, dim, inLevelG); + px.b = ScreenFilterMenu_CalculatePolynomialColorLutComponent(coeffs, 2, gamma, dim, inLevelB); px.z = 0; if (top) @@ -127,7 +135,7 @@ static void ScreenFiltersMenu_ApplyColorSettings(bool top) { a * wp[0], a * wp[1], a * wp[2] }, // x^1 }; - ScreenFilterMenu_WritePolynomialColorLut(top, poly, inv, g, 1); + ScreenFilterMenu_WritePolynomialColorLut(top, filter->colorCurveCorrection, poly, inv, g, 1); } static void ScreenFiltersMenu_SetCct(u16 cct) @@ -138,6 +146,30 @@ static void ScreenFiltersMenu_SetCct(u16 cct) ScreenFiltersMenu_ApplyColorSettings(false); } +static void ScreenFiltersMenu_UpdateEntries(void) +{ + if (topScreenFilter.colorCurveCorrection == 0 || bottomScreenFilter.colorCurveCorrection == 0) + { + screenFiltersMenu.items[10].title = "Adjust both screens color curve to sRGB"; + screenFiltersMenu.items[10].method = &ScreenFiltersMenu_SetSrgbColorCurves; + } + else + { + screenFiltersMenu.items[10].title = "Restore both screens color curve"; + screenFiltersMenu.items[10].method = &ScreenFiltersMenu_RestoreColorCurves; + } +} +static void ScreenFiltersMenu_SetColorCurveCorrection(bool top, u8 colorCurveCorrection) +{ + if (top) + topScreenFilter.colorCurveCorrection = colorCurveCorrection; + else + bottomScreenFilter.colorCurveCorrection = colorCurveCorrection; + + ScreenFiltersMenu_ApplyColorSettings(top); + ScreenFiltersMenu_UpdateEntries(); +} + Menu screenFiltersMenu = { "Screen filters menu", { @@ -151,7 +183,8 @@ 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 }, + { "Adjust both screen color curve to sRGB", METHOD, .method = &ScreenFiltersMenu_SetSrgbColorCurves }, + { "Advanced configuration...", METHOD, .method = &ScreenFiltersMenu_AdvancedConfiguration }, {}, } }; @@ -162,6 +195,12 @@ void ScreenFiltersMenu_Set##name(void)\ ScreenFiltersMenu_SetCct(temp);\ } +#define DEF_SRGB_SETTER(top, profile, name)\ +void ScreenFiltersMenu_##name(void)\ +{\ + ScreenFiltersMenu_SetColorCurveCorrection(top, profile);\ +} + void ScreenFiltersMenu_RestoreSettings(void) { // Precondition: menu has not been entered @@ -214,6 +253,9 @@ void ScreenFiltersMenu_LoadConfig(void) svcGetSystemInfo(&out, 0x10000, 0x107); topScreenFilter.invert = (bool)out; + svcGetSystemInfo(&out, 0x10000, 0x10D); + topScreenFilter.colorCurveCorrection = (u8)out; + svcGetSystemInfo(&out, 0x10000, 0x108); bottomScreenFilter.cct = (u16)out; if (bottomScreenFilter.cct < 1000 || bottomScreenFilter.cct > 25100) @@ -236,6 +278,11 @@ void ScreenFiltersMenu_LoadConfig(void) svcGetSystemInfo(&out, 0x10000, 0x10C); bottomScreenFilter.invert = (bool)out; + + svcGetSystemInfo(&out, 0x10000, 0x10E); + bottomScreenFilter.colorCurveCorrection = (u8)out; + + ScreenFiltersMenu_UpdateEntries(); } DEF_CCT_SETTER(6500, Default) @@ -250,6 +297,18 @@ DEF_CCT_SETTER(2300, WarmIncandescent) DEF_CCT_SETTER(1900, Candle) DEF_CCT_SETTER(1200, Ember) +void ScreenFiltersMenu_SetSrgbColorCurves(void) +{ + ScreenFiltersMenu_SetColorCurveCorrection(true, 1); + ScreenFiltersMenu_SetColorCurveCorrection(false, 2); +} + +void ScreenFiltersMenu_RestoreColorCurves(void) +{ + ScreenFiltersMenu_SetColorCurveCorrection(true, 0); + ScreenFiltersMenu_SetColorCurveCorrection(false, 0); +} + static void ScreenFiltersMenu_ClampFilter(ScreenFilter *filter) { filter->cct = CLAMP(filter->cct, 1000, 25100);