From 0e32b900021f770282ba957f045708ac0cd911dd Mon Sep 17 00:00:00 2001 From: Andy Vandijck Date: Thu, 7 Aug 2025 10:41:49 +0200 Subject: [PATCH] Fix LCD color filter --- src/components/CMakeLists.txt | 1 + src/components/filters_agb/filters_agb.cpp | 491 +++++++++++++-------- src/components/filters_agb/filters_agb.h | 2 + src/components/filters_cgb/CMakeLists.txt | 6 + src/components/filters_cgb/filters_cgb.cpp | 386 ++++++++++++++++ src/components/filters_cgb/filters_cgb.h | 13 + src/libretro/Makefile.common | 1 + src/libretro/libretro.cpp | 1 + src/sdl/CMakeLists.txt | 1 + src/sdl/SDL.cpp | 2 + src/wx/CMakeLists.txt | 1 + src/wx/config/internal/option-internal.cpp | 4 +- src/wx/panel.cpp | 37 +- src/wx/xrc/DisplayConfig.xrc | 4 +- 14 files changed, 749 insertions(+), 201 deletions(-) create mode 100644 src/components/filters_cgb/CMakeLists.txt create mode 100644 src/components/filters_cgb/filters_cgb.cpp create mode 100644 src/components/filters_cgb/filters_cgb.h diff --git a/src/components/CMakeLists.txt b/src/components/CMakeLists.txt index a753e095..2ee3eec8 100644 --- a/src/components/CMakeLists.txt +++ b/src/components/CMakeLists.txt @@ -2,5 +2,6 @@ add_subdirectory(av_recording) add_subdirectory(draw_text) add_subdirectory(filters) add_subdirectory(filters_agb) +add_subdirectory(filters_cgb) add_subdirectory(filters_interframe) add_subdirectory(user_config) diff --git a/src/components/filters_agb/filters_agb.cpp b/src/components/filters_agb/filters_agb.cpp index e5eacc6e..7a435dee 100644 --- a/src/components/filters_agb/filters_agb.cpp +++ b/src/components/filters_agb/filters_agb.cpp @@ -1,4 +1,17 @@ +/* + * GBA Color Correction Shader Implementation + * + * Shader modified by Pokefan531. + * Color Mangler + * Original Author: hunterk + * Original License: Public domain + * + * This code is adapted from the original shader logic. + */ + #include "components/filters_agb/filters_agb.h" +#include +#include extern int systemColorDepth; extern int systemRedShift; @@ -9,205 +22,337 @@ extern uint8_t systemColorMap8[0x10000]; extern uint16_t systemColorMap16[0x10000]; extern uint32_t systemColorMap32[0x10000]; -static const unsigned char curve[32] = { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0e, 0x10, 0x12, - 0x14, 0x16, 0x18, 0x1c, 0x20, 0x28, 0x30, 0x38, - 0x40, 0x48, 0x50, 0x58, 0x60, 0x68, 0x70, 0x80, - 0x88, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0 }; +// --- Global Constants and Variables for GBA Color Correction --- +// Define the color profile matrix as a static const float 2D array +// This replicates the column-major order of GLSL mat4 for easier translation. +// Format: { {col0_row0, col0_row1, col0_row2, col0_row3}, ... } +static const float GBA_sRGB[4][4] = { + {0.905f, 0.10f, 0.1575f, 0.0f}, // Column 0 (R output contributions from R, G, B, A) + {0.195f, 0.65f, 0.1425f, 0.0f}, // Column 1 (G output contributions from R, G, B, A) + {-0.10f, 0.25f, 0.70f, 0.0f}, // Column 2 (B output contributions from R, G, B, A) + {0.0f, 0.0f, 0.0f, 0.91f} // Column 3 (A/Luminance contribution) +}; -// output R G B -static const unsigned char influence[3 * 3] = { 16, 4, 4, // red - 8, 16, 8, // green - 0, 8, 16 }; // blue +static const float GBA_DCI[4][4] = { + {0.76f, 0.125f, 0.16f, 0.0f}, + {0.27f, 0.6375f, 0.18f, 0.0f}, + {-0.03f, 0.2375f, 0.66f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.97f} +}; -inline void swap(short& a, short& b) -{ - short temp = a; - a = b; - b = temp; +static const float GBA_Rec2020[4][4] = { + {0.61f, 0.155f, 0.16f, 0.0f}, + {0.345f, 0.615f, 0.1875f, 0.0f}, + {0.045f, 0.23f, 0.6525f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f} +}; + +// Screen darkening factor. Default to 0.0f +static float darken_screen = 0.0f; + +// Color mode (0 for sRGB, 1 for DCI, 2 for Rec2020). Default to sRGB (0). +static int color_mode = 0; + +// Pointer to the currently selected color profile matrix. +static const float (*profile)[4]; + +// Global constants from the shader for gamma correction values +static const float target_gamma = 2.2f; +static const float display_gamma = 2.2f; + + +// --- Function Implementations --- + +// Forward declaration of a helper function to set the profile based on color_mode +static void set_profile_from_mode(); + +// This constructor-like function runs once when the program starts. +struct GbafilterInitializer { + GbafilterInitializer() { + set_profile_from_mode(); + } +}; +static GbafilterInitializer __gbafilter_initializer; + + +// Helper function to set the 'profile' pointer based on the 'color_mode' variable. +static void set_profile_from_mode() { + if (color_mode == 0) { + profile = GBA_sRGB; + } + else if (color_mode == 1) { + profile = GBA_DCI; + } + else if (color_mode == 2) { + profile = GBA_Rec2020; + } + else { + profile = GBA_sRGB; // Default to sRGB if an invalid mode is set + } +} + + +// Public function to set color mode and darken screen from external calls +void gbafilter_set_params(int new_color_mode, float new_darken_screen) { + color_mode = new_color_mode; + darken_screen = fmaxf(0.0f, fminf(1.0f, new_darken_screen)); // Clamp to 0.0-1.0 + + // Call the helper to update 'profile' based on the new 'color_mode' + set_profile_from_mode(); } void gbafilter_update_colors(bool lcd) { switch (systemColorDepth) { - case 8: { - for (int i = 0; i < 0x10000; i++) { - systemColorMap8[i] = (uint8_t)((((i & 0x1f) << 3) & 0xE0) | - ((((i & 0x3e0) >> 5) << 0) & 0x1C) | - ((((i & 0x7c00) >> 10) >> 3) & 0x3)); - } - } break; - case 16: { - for (int i = 0; i < 0x10000; i++) { - systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | - (((i & 0x3e0) >> 5) << systemGreenShift) | - (((i & 0x7c00) >> 10) << systemBlueShift); - } - if (lcd) - gbafilter_pal(systemColorMap16, 0x10000); - } break; - case 24: - case 32: { - for (int i = 0; i < 0x10000; i++) { - systemColorMap32[i] = ((i & 0x1f) << systemRedShift) | - (((i & 0x3e0) >> 5) << systemGreenShift) | - (((i & 0x7c00) >> 10) << systemBlueShift); - } - if (lcd) - gbafilter_pal32(systemColorMap32, 0x10000); - } break; + case 8: { + for (int i = 0; i < 0x10000; i++) { + systemColorMap8[i] = (uint8_t)((((i & 0x1f) << 3) & 0xE0) | + ((((i & 0x3e0) >> 5) << 0) & 0x1C) | + ((((i & 0x7c00) >> 10) >> 3) & 0x3)); + } + if (lcd) + gbafilter_pal8(systemColorMap8, 0x10000); + } break; + case 16: { + for (int i = 0x0; i < 0x10000; i++) { + systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | + (((i & 0x3e0) >> 5) << systemGreenShift) | + (((i & 0x7c00) >> 10) << systemBlueShift); + } + if (lcd) + gbafilter_pal(systemColorMap16, 0x10000); + } break; + case 24: + case 32: { + for (int i = 0; i < 0x10000; i++) { + systemColorMap32[i] = ((i & 0x1f) << systemRedShift) | + (((i & 0x3e0) >> 5) << systemGreenShift) | + (((i & 0x7c00) >> 10) << systemBlueShift); + } + if (lcd) + gbafilter_pal32(systemColorMap32, 0x10000); + } break; + } +} + +void gbafilter_pal8(uint8_t* buf, int count) +{ + // Pre-calculate constants for efficiency within function scope + const float target_gamma_exponent = target_gamma + darken_screen; + const float display_gamma_reciprocal = 1.0f / display_gamma; + const float luminance_factor = profile[3][3]; // profile[3].w from GLSL + + while (count--) { + uint8_t pix = *buf; + + uint8_t original_r_val_3bit = (uint8_t)((pix & 0xE0) >> 5); + uint8_t original_g_val_3bit = (uint8_t)((pix & 0x1C) >> 2); + uint8_t original_b_val_2bit = (uint8_t)(pix & 0x3); + + // Normalize to 0.0-1.0 for calculations + float r = (float)original_r_val_3bit / 7.0f; + float g = (float)original_g_val_3bit / 7.0f; + float b = (float)original_b_val_2bit / 3.0f; + + // 1. Apply initial gamma (including darken_screen as exponent) to convert to linear space. + // This step will affect non-"white" values. + r = powf(r, target_gamma_exponent); + g = powf(g, target_gamma_exponent); + b = powf(b, target_gamma_exponent); + + // 2. Apply luminance factor and clamp. + r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor)); + g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor)); + b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor)); + + // 3. Apply color profile matrix (using profile[column][row] access) + float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b; + float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b; + float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b; + + // 4. Apply display gamma to convert back for display. + transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r); + transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g); + transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b); + + // Final clamp: ensure values are within 0.0-1.0 range + transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r)); + transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g)); + transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b)); + + // Convert back to 3-bit or 2-bit (0-7 or 0-3) integer and combine into uint8_t + // Apply 5-bit to 5-bit conversion, as this palette is for 16-bit output. + uint8_t final_red = (uint8_t)(transformed_r * 7.0f + 0.5f); + uint8_t final_green = (uint8_t)(transformed_g * 7.0f + 0.5f); + uint8_t final_blue = (uint8_t)(transformed_b * 3.0f + 0.5f); + + // Ensure values are strictly within 0-7 or 0-3 range after rounding + if (final_red > 7) final_red = 7; + if (final_green > 7) final_green = 7; + if (final_blue > 3) final_blue = 3; + + *buf++ = ((final_red & 0x7) << 5) | + ((final_green & 0x7) << 2) | + (final_blue & 0x3); } } void gbafilter_pal(uint16_t* buf, int count) { - short temp[3 * 3], s; - uint16_t pix; - uint8_t red, green, blue; + // Pre-calculate constants for efficiency within function scope + const float target_gamma_exponent = target_gamma + darken_screen; + const float display_gamma_reciprocal = 1.0f / display_gamma; + const float luminance_factor = profile[3][3]; // profile[3].w from GLSL while (count--) { - pix = *buf; + uint16_t pix = *buf; - s = curve[(pix >> systemGreenShift) & 0x1f]; - temp[3] = s * influence[3]; - temp[4] = s * influence[4]; - temp[5] = s * influence[5]; + uint8_t original_r_val_5bit = (uint8_t)((pix >> systemRedShift) & 0x1f); + uint8_t original_g_val_5bit = (uint8_t)((pix >> systemGreenShift) & 0x1f); + uint8_t original_b_val_5bit = (uint8_t)((pix >> systemBlueShift) & 0x1f); - s = curve[(pix >> systemRedShift) & 0x1f]; - temp[0] = s * influence[0]; - temp[1] = s * influence[1]; - temp[2] = s * influence[2]; + // Normalize to 0.0-1.0 for calculations + float r = (float)original_r_val_5bit / 31.0f; + float g = (float)original_g_val_5bit / 31.0f; + float b = (float)original_b_val_5bit / 31.0f; - s = curve[(pix >> systemBlueShift) & 0x1f]; - temp[6] = s * influence[6]; - temp[7] = s * influence[7]; - temp[8] = s * influence[8]; + // 1. Apply initial gamma (including darken_screen as exponent) to convert to linear space. + // This step will affect non-"white" values. + r = powf(r, target_gamma_exponent); + g = powf(g, target_gamma_exponent); + b = powf(b, target_gamma_exponent); - if (temp[0] < temp[3]) - swap(temp[0], temp[3]); - if (temp[0] < temp[6]) - swap(temp[0], temp[6]); - if (temp[3] < temp[6]) - swap(temp[3], temp[6]); - temp[3] <<= 1; - temp[0] <<= 2; - temp[0] += temp[3] + temp[6]; + // 2. Apply luminance factor and clamp. + r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor)); + g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor)); + b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor)); - red = ((int(temp[0]) * 160) >> 17) + 4; - if (red > 31) - red = 31; + // 3. Apply color profile matrix (using profile[column][row] access) + float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b; + float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b; + float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b; - if (temp[2] < temp[5]) - swap(temp[2], temp[5]); - if (temp[2] < temp[8]) - swap(temp[2], temp[8]); - if (temp[5] < temp[8]) - swap(temp[5], temp[8]); - temp[5] <<= 1; - temp[2] <<= 2; - temp[2] += temp[5] + temp[8]; + // 4. Apply display gamma to convert back for display. + transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r); + transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g); + transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b); - blue = ((int(temp[2]) * 160) >> 17) + 4; - if (blue > 31) - blue = 31; + // Final clamp: ensure values are within 0.0-1.0 range + transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r)); + transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g)); + transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b)); - if (temp[1] < temp[4]) - swap(temp[1], temp[4]); - if (temp[1] < temp[7]) - swap(temp[1], temp[7]); - if (temp[4] < temp[7]) - swap(temp[4], temp[7]); - temp[4] <<= 1; - temp[1] <<= 2; - temp[1] += temp[4] + temp[7]; + // Convert back to 5-bit (0-31) integer and combine into uint16_t + // Apply 5-bit to 5-bit conversion, as this palette is for 16-bit output. + uint8_t final_red = (uint8_t)(transformed_r * 31.0f + 0.5f); + uint8_t final_green = (uint8_t)(transformed_g * 31.0f + 0.5f); + uint8_t final_blue = (uint8_t)(transformed_b * 31.0f + 0.5f); - green = ((int(temp[1]) * 160) >> 17) + 4; - if (green > 31) - green = 31; + // Ensure values are strictly within 0-31 range after rounding + if (final_red > 31) final_red = 31; + if (final_green > 31) final_green = 31; + if (final_blue > 31) final_blue = 31; - pix = red << systemRedShift; - pix += green << systemGreenShift; - pix += blue << systemBlueShift; - - *buf++ = pix; + *buf++ = (final_red << systemRedShift) | + (final_green << systemGreenShift) | + (final_blue << systemBlueShift); } } void gbafilter_pal32(uint32_t* buf, int count) { - short temp[3 * 3], s; - unsigned pix; - uint8_t red, green, blue; + // Pre-calculate constants for efficiency within function scope + const float target_gamma_exponent = target_gamma + darken_screen; + const float display_gamma_reciprocal = 1.0f / display_gamma; + const float luminance_factor = profile[3][3]; // profile[3].w from GLSL while (count--) { - pix = *buf; + uint32_t pix = *buf; - s = curve[(pix >> systemGreenShift) & 0x1f]; - temp[3] = s * influence[3]; - temp[4] = s * influence[4]; - temp[5] = s * influence[5]; + // Extract original 5-bit R, G, B values from the shifted positions in the 32-bit pixel. + // These shifts pull out the 5-bit value from its shifted position (e.g., bits 3-7 for Red). + uint8_t original_r_val_5bit = (uint8_t)((pix >> systemRedShift) & 0x1f); + uint8_t original_g_val_5bit = (uint8_t)((pix >> systemGreenShift) & 0x1f); + uint8_t original_b_val_5bit = (uint8_t)((pix >> systemBlueShift) & 0x1f); - s = curve[(pix >> systemRedShift) & 0x1f]; - temp[0] = s * influence[0]; - temp[1] = s * influence[1]; - temp[2] = s * influence[2]; - s = curve[(pix >> systemBlueShift) & 0x1f]; - temp[6] = s * influence[6]; - temp[7] = s * influence[7]; - temp[8] = s * influence[8]; + // Normalize to 0.0-1.0 for calculations + float r = (float)original_r_val_5bit / 31.0f; + float g = (float)original_g_val_5bit / 31.0f; + float b = (float)original_b_val_5bit / 31.0f; - if (temp[0] < temp[3]) - swap(temp[0], temp[3]); - if (temp[0] < temp[6]) - swap(temp[0], temp[6]); - if (temp[3] < temp[6]) - swap(temp[3], temp[6]); - temp[3] <<= 1; - temp[0] <<= 2; - temp[0] += temp[3] + temp[6]; + // 1. Apply initial gamma (including darken_screen as exponent) to convert to linear space. + r = powf(r, target_gamma_exponent); + g = powf(g, target_gamma_exponent); + b = powf(b, target_gamma_exponent); - //red = ((int(temp[0]) * 160) >> 17) + 4; - red = ((int(temp[0]) * 160) >> 14) + 32; + // 2. Apply luminance factor and clamp. + r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor)); + g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor)); + b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor)); - if (temp[2] < temp[5]) - swap(temp[2], temp[5]); - if (temp[2] < temp[8]) - swap(temp[2], temp[8]); - if (temp[5] < temp[8]) - swap(temp[5], temp[8]); - temp[5] <<= 1; - temp[2] <<= 2; - temp[2] += temp[5] + temp[8]; + // 3. Apply color profile matrix + float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b; + float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b; + float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b; - //blue = ((int(temp[2]) * 160) >> 17) + 4; - blue = ((int(temp[2]) * 160) >> 14) + 32; + // 4. Apply display gamma. + transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r); + transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g); + transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b); - if (temp[1] < temp[4]) - swap(temp[1], temp[4]); - if (temp[1] < temp[7]) - swap(temp[1], temp[7]); - if (temp[4] < temp[7]) - swap(temp[4], temp[7]); - temp[4] <<= 1; - temp[1] <<= 2; - temp[1] += temp[4] + temp[7]; + // Final clamp: ensure values are within 0.0-1.0 range + transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r)); + transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g)); + transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b)); - //green = ((int(temp[1]) * 160) >> 17) + 4; - green = ((int(temp[1]) * 160) >> 14) + 32; - //pix = red << redshift; - //pix += green << greenshift; - //pix += blue << blueshift; + // Convert the floating-point values to 8-bit integer components (0-255). + uint8_t final_red_8bit = (uint8_t)(transformed_r * 255.0f + 0.5f); + uint8_t final_green_8bit = (uint8_t)(transformed_g * 255.0f + 0.5f); + uint8_t final_blue_8bit = (uint8_t)(transformed_b * 255.0f + 0.5f); - pix = red << (systemRedShift - 3); - pix += green << (systemGreenShift - 3); - pix += blue << (systemBlueShift - 3); + // Ensure values are strictly within 0-255 range after rounding + if (final_red_8bit > 255) final_red_8bit = 255; + if (final_green_8bit > 255) final_green_8bit = 255; + if (final_blue_8bit > 255) final_blue_8bit = 255; - *buf++ = pix; + // --- NEW PACKING LOGIC --- + // This is the critical change to correctly map 8-bit color to the 5-bit shifted format, + // while allowing FFFFFF. + // It uses the top 5 bits of the 8-bit value for the GBA's 5-bit component position, + // and the bottom 3 bits to fill the lower, normally zeroed, positions. + + uint32_t final_pix = 0; + + // Red component + // 5 most significant bits (MSBs) for the 'systemRedShift' position + final_pix |= ((final_red_8bit >> 3) & 0x1f) << systemRedShift; + // 3 least significant bits (LSBs) for the 'base' position (systemRedShift - 3) + final_pix |= (final_red_8bit & 0x07) << (systemRedShift - 3); + + + // Green component + // 5 MSBs for the 'systemGreenShift' position + final_pix |= ((final_green_8bit >> 3) & 0x1f) << systemGreenShift; + // 3 LSBs for the 'base' position (systemGreenShift - 3) + final_pix |= (final_green_8bit & 0x07) << (systemGreenShift - 3); + + // Blue component + // 5 MSBs for the 'systemBlueShift' position + final_pix |= ((final_blue_8bit >> 3) & 0x1f) << systemBlueShift; + // 3 LSBs for the 'base' position (systemBlueShift - 3) + final_pix |= (final_blue_8bit & 0x07) << (systemBlueShift - 3); + + // Preserve existing alpha if present (assuming it's at bits 24-31 for 32-bit depth) + if (systemColorDepth == 32) { + final_pix |= (pix & (0xFF << 24)); + } + + *buf++ = final_pix; } } -// for palette mode to work with the three spoony filters in 32bpp depth - +// gbafilter_pad remains unchanged as it's for masking. void gbafilter_pad(uint8_t* buf, int count) { union { @@ -240,41 +385,3 @@ void gbafilter_pad(uint8_t* buf, int count) } } } - -/* -void UpdateSystemColorMaps(int lcd) -{ - switch(systemColorDepth) { - case 8: - { - for(int i = 0; i < 0x10000; i++) { - systemColorMap8[i] = (((i & 0x1f) << systemRedShift) & 0xE0) | - ((((i & 0x3e0) >> 5) << systemGreenShift) & 0x1C) | - ((((i & 0x7c00) >> 10) << systemBlueShift) & 0x3); - } - } - break; - case 16: - { - for(int i = 0; i < 0x10000; i++) { - systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | - (((i & 0x3e0) >> 5) << systemGreenShift) | - (((i & 0x7c00) >> 10) << systemBlueShift); - } - if (lcd == 1) gbafilter_pal(systemColorMap16, 0x10000); - } - break; - case 24: - case 32: - { - for(int i = 0; i < 0x10000; i++) { - systemColorMap32[i] = ((i & 0x1f) << systemRedShift) | - (((i & 0x3e0) >> 5) << systemGreenShift) | - (((i & 0x7c00) >> 10) << systemBlueShift); - } - if (lcd == 1) gbafilter_pal32(systemColorMap32, 0x10000); - } - break; - } -} -*/ diff --git a/src/components/filters_agb/filters_agb.h b/src/components/filters_agb/filters_agb.h index 6e40fe49..608de1d8 100644 --- a/src/components/filters_agb/filters_agb.h +++ b/src/components/filters_agb/filters_agb.h @@ -4,8 +4,10 @@ #include void gbafilter_update_colors(bool lcd = false); +void gbafilter_pal8(uint8_t* buf, int count); void gbafilter_pal(uint16_t* buf, int count); void gbafilter_pal32(uint32_t* buf, int count); void gbafilter_pad(uint8_t* buf, int count); +void gbafilter_set_params(int color_mode, float darken_screen); #endif // VBAM_COMPONENTS_FILTERS_AGB_FILTERS_AGB_H_ diff --git a/src/components/filters_cgb/CMakeLists.txt b/src/components/filters_cgb/CMakeLists.txt new file mode 100644 index 00000000..4e08fab4 --- /dev/null +++ b/src/components/filters_cgb/CMakeLists.txt @@ -0,0 +1,6 @@ +add_library(vbam-components-filters-cgb OBJECT) + +target_sources(vbam-components-filters-cgb + PRIVATE filters_cgb.cpp + PUBLIC filters_cgb.h +) diff --git a/src/components/filters_cgb/filters_cgb.cpp b/src/components/filters_cgb/filters_cgb.cpp new file mode 100644 index 00000000..1f0ae9d9 --- /dev/null +++ b/src/components/filters_cgb/filters_cgb.cpp @@ -0,0 +1,386 @@ +/* + * GBC Color Correction Shader Implementation + * + * Shader modified by Pokefan531. + * Color Mangler + * Original Author: hunterk + * Original License: Public domain + * + * This code is adapted from the original shader logic. + */ + +#include "components/filters_cgb/filters_cgb.h" +#include +#include + +extern int systemColorDepth; +extern int systemRedShift; +extern int systemGreenShift; +extern int systemBlueShift; + +extern uint8_t systemColorMap8[0x10000]; +extern uint16_t systemColorMap16[0x10000]; +extern uint32_t systemColorMap32[0x10000]; + +// --- Global Constants and Variables for GBC Color Correction --- +// Define the color profile matrix as a static const float 2D array +// This replicates the column-major order of GLSL mat4 for easier translation. +// Format: { {col0_row0, col0_row1, col0_row2, col0_row3}, ... } +static const float GBC_sRGB[4][4] = { + {0.905f, 0.10f, 0.1575f, 0.0f}, // Column 0 (R output contributions from R, G, B, A) + {0.195f, 0.65f, 0.1425f, 0.0f}, // Column 1 (G output contributions from R, G, B, A) + {-0.10f, 0.25f, 0.70f, 0.0f}, // Column 2 (B output contributions from R, G, B, A) + {0.0f, 0.0f, 0.0f, 0.91f} // Column 3 (A/Luminance contribution) +}; + +static const float GBC_DCI[4][4] = { + {0.76f, 0.125f, 0.16f, 0.0f}, + {0.27f, 0.6375f, 0.18f, 0.0f}, + {-0.03f, 0.2375f, 0.66f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.97f} +}; + +static const float GBC_Rec2020[4][4] = { + {0.61f, 0.155f, 0.16f, 0.0f}, + {0.345f, 0.615f, 0.1875f, 0.0f}, + {0.045f, 0.23f, 0.6525f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f} +}; + +// Screen darkening factor. Default to 0.0f. +static float lighten_screen = 0.0f; + +// Color mode (0 for sRGB, 1 for DCI, 2 for Rec2020). Default to sRGB (0). +static int color_mode = 0; + +// Pointer to the currently selected color profile matrix. +static const float (*profile)[4]; + +// Global constants from the shader for gamma correction values +static const float target_gamma = 2.2f; +static const float display_gamma = 2.2f; + + +// --- Function Implementations --- + +// Forward declaration of a helper function to set the profile based on color_mode +static void set_profile_from_mode(); + +// This constructor-like function runs once when the program starts. +struct GbcfilterInitializer { + GbcfilterInitializer() { + set_profile_from_mode(); + } +}; +static GbcfilterInitializer __gbcfilter_initializer; + + +// Helper function to set the 'profile' pointer based on the 'color_mode' variable. +static void set_profile_from_mode() { + if (color_mode == 0) { + profile = GBC_sRGB; + } + else if (color_mode == 1) { + profile = GBC_DCI; + } + else if (color_mode == 2) { + profile = GBC_Rec2020; + } + else { + profile = GBC_sRGB; // Default to sRGB if an invalid mode is set + } +} + + +// Public function to set color mode and darken screen from external calls +void gbcfilter_set_params(int new_color_mode, float new_lighten_screen) { + color_mode = new_color_mode; + lighten_screen = fmaxf(0.0f, fminf(1.0f, new_lighten_screen)); // Clamp to 0.0-1.0 + + // Call the helper to update 'profile' based on the new 'color_mode' + set_profile_from_mode(); +} + +void gbcfilter_update_colors(bool lcd) { + switch (systemColorDepth) { + case 8: { + for (int i = 0; i < 0x10000; i++) { + systemColorMap8[i] = (uint8_t)((((i & 0x1f) << 3) & 0xE0) | + ((((i & 0x3e0) >> 5) << 0) & 0x1C) | + ((((i & 0x7c00) >> 10) >> 3) & 0x3)); + } + if (lcd) + gbcfilter_pal8(systemColorMap8, 0x10000); + } break; + case 16: { + for (int i = 0x0; i < 0x10000; i++) { + systemColorMap16[i] = ((i & 0x1f) << systemRedShift) | + (((i & 0x3e0) >> 5) << systemGreenShift) | + (((i & 0x7c00) >> 10) << systemBlueShift); + } + if (lcd) + gbcfilter_pal(systemColorMap16, 0x10000); + } break; + case 24: + case 32: { + for (int i = 0; i < 0x10000; i++) { + systemColorMap32[i] = ((i & 0x1f) << systemRedShift) | + (((i & 0x3e0) >> 5) << systemGreenShift) | + (((i & 0x7c00) >> 10) << systemBlueShift); + } + if (lcd) + gbcfilter_pal32(systemColorMap32, 0x10000); + } break; + } +} + +void gbcfilter_pal8(uint8_t* buf, int count) +{ + // Pre-calculate constants for efficiency within function scope + const float target_gamma_exponent = target_gamma + (lighten_screen * -1.0f); + const float display_gamma_reciprocal = 1.0f / display_gamma; + const float luminance_factor = profile[3][3]; // profile[3].w from GLSL + + while (count--) { + uint8_t pix = *buf; + + uint8_t original_r_val_3bit = (uint8_t)((pix & 0xE0) >> 5); + uint8_t original_g_val_3bit = (uint8_t)((pix & 0x1C) >> 2); + uint8_t original_b_val_2bit = (uint8_t)(pix & 0x3); + + // Normalize to 0.0-1.0 for calculations + float r = (float)original_r_val_3bit / 7.0f; + float g = (float)original_g_val_3bit / 7.0f; + float b = (float)original_b_val_2bit / 3.0f; + + // 1. Apply initial gamma (including lighten_screen as exponent) to convert to linear space. + // This step will affect non-"white" values. + r = powf(r, target_gamma_exponent); + g = powf(g, target_gamma_exponent); + b = powf(b, target_gamma_exponent); + + // 2. Apply luminance factor and clamp. + r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor)); + g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor)); + b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor)); + + // 3. Apply color profile matrix (using profile[column][row] access) + float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b; + float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b; + float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b; + + // 4. Apply display gamma to convert back for display. + transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r); + transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g); + transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b); + + // Final clamp: ensure values are within 0.0-1.0 range + transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r)); + transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g)); + transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b)); + + // Convert back to 3-bit or 2-bit (0-7 or 0-3) integer and combine into uint8_t + // Apply 3-bit or 2-bit to 8-bit conversion, as this palette is for 8-bit output. + uint8_t final_red = (uint8_t)(transformed_r * 7.0f + 0.5f); + uint8_t final_green = (uint8_t)(transformed_g * 7.0f + 0.5f); + uint8_t final_blue = (uint8_t)(transformed_b * 3.0f + 0.5f); + + // Ensure values are strictly within 0-7 or 0-3 range after rounding + if (final_red > 7) final_red = 7; + if (final_green > 7) final_green = 7; + if (final_blue > 3) final_blue = 3; + + *buf++ = ((final_red & 0x7) << 5) | + ((final_green & 0x7) << 2) | + (final_blue & 0x3); + } +} +void gbcfilter_pal(uint16_t* buf, int count) +{ + // Pre-calculate constants for efficiency within function scope + const float target_gamma_exponent = target_gamma + (lighten_screen * -1.0f); + const float display_gamma_reciprocal = 1.0f / display_gamma; + const float luminance_factor = profile[3][3]; // profile[3].w from GLSL + + while (count--) { + uint16_t pix = *buf; + + uint8_t original_r_val_5bit = (uint8_t)((pix >> systemRedShift) & 0x1f); + uint8_t original_g_val_5bit = (uint8_t)((pix >> systemGreenShift) & 0x1f); + uint8_t original_b_val_5bit = (uint8_t)((pix >> systemBlueShift) & 0x1f); + + // Normalize to 0.0-1.0 for calculations + float r = (float)original_r_val_5bit / 31.0f; + float g = (float)original_g_val_5bit / 31.0f; + float b = (float)original_b_val_5bit / 31.0f; + + // 1. Apply initial gamma (including lighten_screen as exponent) to convert to linear space. + // This step will affect non-"white" values. + r = powf(r, target_gamma_exponent); + g = powf(g, target_gamma_exponent); + b = powf(b, target_gamma_exponent); + + // 2. Apply luminance factor and clamp. + r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor)); + g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor)); + b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor)); + + // 3. Apply color profile matrix (using profile[column][row] access) + float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b; + float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b; + float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b; + + // 4. Apply display gamma to convert back for display. + transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r); + transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g); + transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b); + + // Final clamp: ensure values are within 0.0-1.0 range + transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r)); + transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g)); + transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b)); + + // Convert back to 5-bit (0-31) integer and combine into uint16_t + // Apply 5-bit to 5-bit conversion, as this palette is for 16-bit output. + uint8_t final_red = (uint8_t)(transformed_r * 31.0f + 0.5f); + uint8_t final_green = (uint8_t)(transformed_g * 31.0f + 0.5f); + uint8_t final_blue = (uint8_t)(transformed_b * 31.0f + 0.5f); + + // Ensure values are strictly within 0-31 range after rounding + if (final_red > 31) final_red = 31; + if (final_green > 31) final_green = 31; + if (final_blue > 31) final_blue = 31; + + *buf++ = (final_red << systemRedShift) | + (final_green << systemGreenShift) | + (final_blue << systemBlueShift); + } +} + +void gbcfilter_pal32(uint32_t* buf, int count) +{ + // Pre-calculate constants for efficiency within function scope + const float target_gamma_exponent = target_gamma + (lighten_screen * -1.0f); + const float display_gamma_reciprocal = 1.0f / display_gamma; + const float luminance_factor = profile[3][3]; // profile[3].w from GLSL + + while (count--) { + uint32_t pix = *buf; + + // Extract original 5-bit R, G, B values from the shifted positions in the 32-bit pixel. + // These shifts pull out the 5-bit value from its shifted position (e.g., bits 3-7 for Red). + uint8_t original_r_val_5bit = (uint8_t)((pix >> systemRedShift) & 0x1f); + uint8_t original_g_val_5bit = (uint8_t)((pix >> systemGreenShift) & 0x1f); + uint8_t original_b_val_5bit = (uint8_t)((pix >> systemBlueShift) & 0x1f); + + + // Normalize to 0.0-1.0 for calculations + float r = (float)original_r_val_5bit / 31.0f; + float g = (float)original_g_val_5bit / 31.0f; + float b = (float)original_b_val_5bit / 31.0f; + + // 1. Apply initial gamma (including lighten_screen as exponent) to convert to linear space. + r = powf(r, target_gamma_exponent); + g = powf(g, target_gamma_exponent); + b = powf(b, target_gamma_exponent); + + // 2. Apply luminance factor and clamp. + r = fmaxf(0.0f, fminf(1.0f, r * luminance_factor)); + g = fmaxf(0.0f, fminf(1.0f, g * luminance_factor)); + b = fmaxf(0.0f, fminf(1.0f, b * luminance_factor)); + + // 3. Apply color profile matrix + float transformed_r = profile[0][0] * r + profile[1][0] * g + profile[2][0] * b; + float transformed_g = profile[0][1] * r + profile[1][1] * g + profile[2][1] * b; + float transformed_b = profile[0][2] * r + profile[1][2] * g + profile[2][2] * b; + + // 4. Apply display gamma. + transformed_r = copysignf(powf(fabsf(transformed_r), display_gamma_reciprocal), transformed_r); + transformed_g = copysignf(powf(fabsf(transformed_g), display_gamma_reciprocal), transformed_g); + transformed_b = copysignf(powf(fabsf(transformed_b), display_gamma_reciprocal), transformed_b); + + // Final clamp: ensure values are within 0.0-1.0 range + transformed_r = fmaxf(0.0f, fminf(1.0f, transformed_r)); + transformed_g = fmaxf(0.0f, fminf(1.0f, transformed_g)); + transformed_b = fmaxf(0.0f, fminf(1.0f, transformed_b)); + + + // Convert the floating-point values to 8-bit integer components (0-255). + uint8_t final_red_8bit = (uint8_t)(transformed_r * 255.0f + 0.5f); + uint8_t final_green_8bit = (uint8_t)(transformed_g * 255.0f + 0.5f); + uint8_t final_blue_8bit = (uint8_t)(transformed_b * 255.0f + 0.5f); + + // Ensure values are strictly within 0-255 range after rounding + if (final_red_8bit > 255) final_red_8bit = 255; + if (final_green_8bit > 255) final_green_8bit = 255; + if (final_blue_8bit > 255) final_blue_8bit = 255; + + // --- NEW PACKING LOGIC --- + // This is the critical change to correctly map 8-bit color to the 5-bit shifted format, + // while allowing FFFFFF. + // It uses the top 5 bits of the 8-bit value for the GBC's 5-bit component position, + // and the bottom 3 bits to fill the lower, normally zeroed, positions. + + uint32_t final_pix = 0; + + // Red component + // 5 most significant bits (MSBs) for the 'systemRedShift' position + final_pix |= ((final_red_8bit >> 3) & 0x1f) << systemRedShift; + // 3 least significant bits (LSBs) for the 'base' position (systemRedShift - 3) + final_pix |= (final_red_8bit & 0x07) << (systemRedShift - 3); + + + // Green component + // 5 MSBs for the 'systemGreenShift' position + final_pix |= ((final_green_8bit >> 3) & 0x1f) << systemGreenShift; + // 3 LSBs for the 'base' position (systemGreenShift - 3) + final_pix |= (final_green_8bit & 0x07) << (systemGreenShift - 3); + + // Blue component + // 5 MSBs for the 'systemBlueShift' position + final_pix |= ((final_blue_8bit >> 3) & 0x1f) << systemBlueShift; + // 3 LSBs for the 'base' position (systemBlueShift - 3) + final_pix |= (final_blue_8bit & 0x07) << (systemBlueShift - 3); + + // Preserve existing alpha if present (assuming it's at bits 24-31 for 32-bit depth) + if (systemColorDepth == 32) { + final_pix |= (pix & (0xFF << 24)); + } + + *buf++ = final_pix; + } +} + +// gbcfilter_pad remains unchanged as it's for masking. +void gbcfilter_pad(uint8_t* buf, int count) +{ + union { + struct + { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + } part; + unsigned whole; + } mask; + + mask.whole = 0x1f << systemRedShift; + mask.whole += 0x1f << systemGreenShift; + mask.whole += 0x1f << systemBlueShift; + + switch (systemColorDepth) { + case 24: + while (count--) { + *buf++ &= mask.part.r; + *buf++ &= mask.part.g; + *buf++ &= mask.part.b; + } + break; + case 32: + while (count--) { + *((uint32_t*)buf) &= mask.whole; + buf += 4; + } + } +} diff --git a/src/components/filters_cgb/filters_cgb.h b/src/components/filters_cgb/filters_cgb.h new file mode 100644 index 00000000..75a42c1a --- /dev/null +++ b/src/components/filters_cgb/filters_cgb.h @@ -0,0 +1,13 @@ +#ifndef VBAM_COMPONENTS_FILTERS_CGB_FILTERS_CGB_H_ +#define VBAM_COMPONENTS_FILTERS_CGB_FILTERS_CGB_H_ + +#include + +void gbcfilter_update_colors(bool lcd = false); +void gbcfilter_pal8(uint8_t* buf, int count); +void gbcfilter_pal(uint16_t* buf, int count); +void gbcfilter_pal32(uint32_t* buf, int count); +void gbcfilter_pad(uint8_t* buf, int count); +void gbcfilter_set_params(int color_mode, float lighten_screen); + +#endif // VBAM_COMPONENTS_FILTERS_CGB_FILTERS_CGB_H_ diff --git a/src/libretro/Makefile.common b/src/libretro/Makefile.common index d906b74c..9bebd37d 100644 --- a/src/libretro/Makefile.common +++ b/src/libretro/Makefile.common @@ -70,4 +70,5 @@ SOURCES_CXX += \ # Filters SOURCES_CXX += \ $(CORE_DIR)/components/filters_agb/filters_agb.cpp \ + $(CORE_DIR)/components/filters_cgb/filters_cgb.cpp \ $(CORE_DIR)/components/filters_interframe/interframe.cpp diff --git a/src/libretro/libretro.cpp b/src/libretro/libretro.cpp index d8d649b9..7bd8d14a 100644 --- a/src/libretro/libretro.cpp +++ b/src/libretro/libretro.cpp @@ -10,6 +10,7 @@ #include "scrc32.h" #include "components/filters_agb/filters_agb.h" +#include "components/filters_cgb/filters_cgb.h" #include "components/filters_interframe/interframe.h" #include "core/base/check.h" #include "core/base/system.h" diff --git a/src/sdl/CMakeLists.txt b/src/sdl/CMakeLists.txt index d98adf02..0af54fff 100644 --- a/src/sdl/CMakeLists.txt +++ b/src/sdl/CMakeLists.txt @@ -55,6 +55,7 @@ target_link_libraries(vbam vbam-components-draw-text vbam-components-filters vbam-components-filters-agb + vbam-components-filters-cgb vbam-components-filters-interframe vbam-components-user-config ${OPENGL_LIBRARIES} diff --git a/src/sdl/SDL.cpp b/src/sdl/SDL.cpp index 0bba1319..cb40610f 100644 --- a/src/sdl/SDL.cpp +++ b/src/sdl/SDL.cpp @@ -111,6 +111,7 @@ #include "components/draw_text/draw_text.h" #include "components/filters_agb/filters_agb.h" +#include "components/filters_cgb/filters_cgb.h" #include "components/user_config/user_config.h" #include "core/base/file_util.h" #include "core/base/message.h" @@ -2376,6 +2377,7 @@ int main(int argc, char** argv) fprintf(stdout, "Color depth: %d\n", systemColorDepth); gbafilter_update_colors(); + gbcfilter_update_colors(); if (delta == NULL) { delta = (uint8_t*)malloc(delta_size); diff --git a/src/wx/CMakeLists.txt b/src/wx/CMakeLists.txt index adebdd5c..48a96e4a 100644 --- a/src/wx/CMakeLists.txt +++ b/src/wx/CMakeLists.txt @@ -424,6 +424,7 @@ target_link_libraries( vbam-components-draw-text vbam-components-filters vbam-components-filters-agb + vbam-components-filters-cgb vbam-components-filters-interframe vbam-components-user-config vbam-wx-config diff --git a/src/wx/config/internal/option-internal.cpp b/src/wx/config/internal/option-internal.cpp index 41f86e6c..3c95ca38 100644 --- a/src/wx/config/internal/option-internal.cpp +++ b/src/wx/config/internal/option-internal.cpp @@ -182,7 +182,7 @@ std::array& Option::All() { bool print_screen_cap = false; wxString gb_rom_dir = wxEmptyString; wxString gbc_rom_dir = wxEmptyString; - uint32_t gb_lighten = 70; + uint32_t gb_lighten = 0; /// GBA bool gba_lcd_filter = false; @@ -192,7 +192,7 @@ std::array& Option::All() { bool link_proto = false; #endif wxString gba_rom_dir; - uint32_t gba_darken = 70; + uint32_t gba_darken = 0; /// Core bool agb_print = false; diff --git a/src/wx/panel.cpp b/src/wx/panel.cpp index ec38f74f..057697ef 100644 --- a/src/wx/panel.cpp +++ b/src/wx/panel.cpp @@ -35,6 +35,7 @@ #include "components/draw_text/draw_text.h" #include "components/filters/filters.h" #include "components/filters_agb/filters_agb.h" +#include "components/filters_cgb/filters_cgb.h" #include "components/filters_interframe/interframe.h" #include "core/base/check.h" #include "core/base/file_util.h" @@ -175,7 +176,7 @@ GameArea::GameArea() gb_declick_observer_( config::OptionID::kSoundGBDeclicking, [&](config::Option* option) { gbSoundSetDeclicking(option->GetBool()); }), - lcd_filters_observer_({config::OptionID::kGBLCDFilter, config::OptionID::kGBALCDFilter}, + lcd_filters_observer_({config::OptionID::kGBLCDFilter, config::OptionID::kGBADarken, config::OptionID::kGBLighten, config::OptionID::kDispColorCorrectionProfile, config::OptionID::kGBALCDFilter}, std::bind(&GameArea::UpdateLcdFilter, this)), audio_rate_observer_(config::OptionID::kSoundAudioRate, std::bind(&GameArea::OnAudioRateChanged, this)), @@ -3420,12 +3421,38 @@ void GameArea::OnGBBorderChanged(config::Option* option) { } void GameArea::UpdateLcdFilter() { - if (loaded == IMAGE_GBA) + int DCCP = 0; + + switch (OPTION(kDispColorCorrectionProfile)) { + case config::ColorCorrectionProfile::kSRGB: + DCCP = 0; + break; + + case config::ColorCorrectionProfile::kDCI: + DCCP = 1; + break; + + case config::ColorCorrectionProfile::kRec2020: + DCCP = 2; + break; + + case config::ColorCorrectionProfile::kLast: + DCCP = 0; + break; + } + + if (loaded == IMAGE_GBA) { + gbafilter_set_params(DCCP, (((float)OPTION(kGBADarken)) / 100)); gbafilter_update_colors(OPTION(kGBALCDFilter)); - else if (loaded == IMAGE_GB) - gbafilter_update_colors(OPTION(kGBLCDFilter)); - else + } else if (loaded == IMAGE_GB) { + gbcfilter_set_params(DCCP, (((float)OPTION(kGBLighten)) / 100)); + gbcfilter_update_colors(OPTION(kGBLCDFilter)); + } else { + gbafilter_set_params(0, 0); + gbcfilter_set_params(0, 0); gbafilter_update_colors(false); + gbcfilter_update_colors(false); + } } void GameArea::SuspendScreenSaver() { diff --git a/src/wx/xrc/DisplayConfig.xrc b/src/wx/xrc/DisplayConfig.xrc index 39692a58..06755f08 100644 --- a/src/wx/xrc/DisplayConfig.xrc +++ b/src/wx/xrc/DisplayConfig.xrc @@ -266,7 +266,7 @@ - 70 + 0 0 100 @@ -312,7 +312,7 @@ - 70 + 0 0 100