Fix LCD color filter
This commit is contained in:
parent
2640716496
commit
0e32b90002
|
@ -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)
|
||||
|
|
|
@ -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 <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
|
@ -4,8 +4,10 @@
|
|||
#include <cstdint>
|
||||
|
||||
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_
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -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 <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef VBAM_COMPONENTS_FILTERS_CGB_FILTERS_CGB_H_
|
||||
#define VBAM_COMPONENTS_FILTERS_CGB_FILTERS_CGB_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
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_
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -182,7 +182,7 @@ std::array<Option, kNbOptions>& 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, kNbOptions>& 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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -266,7 +266,7 @@
|
|||
<object class="wxBoxSizer">
|
||||
<object class="sizeritem">
|
||||
<object class="wxSlider" name="GBADarken">
|
||||
<value>70</value>
|
||||
<value>0</value>
|
||||
<min>0</min>
|
||||
<max>100</max>
|
||||
</object>
|
||||
|
@ -312,7 +312,7 @@
|
|||
<object class="wxBoxSizer">
|
||||
<object class="sizeritem">
|
||||
<object class="wxSlider" name="GBCLighten">
|
||||
<value>70</value>
|
||||
<value>0</value>
|
||||
<min>0</min>
|
||||
<max>100</max>
|
||||
</object>
|
||||
|
|
Loading…
Reference in New Issue