mirror of
https://github.com/Gericom/GBARunner3.git
synced 2025-06-18 19:25:41 -04:00
Implemented 12 bit fixed point in gamma LUT calculations
This commit is contained in:
parent
1e57e8d025
commit
0aafeddbdc
@ -6,16 +6,10 @@
|
||||
|
||||
u16 gColorLut[COLOR_LUT_SIZE] __attribute__((section(".lutram")));
|
||||
|
||||
const ColorProfile* gCurrentPreset = &Agb001; // Initialize the color matrix preset, default is AGB_001
|
||||
const ColorProfile* gCurrentPreset = &Agb001; // Default is AGB_001
|
||||
|
||||
// Scale from 5 bits to 8 bits (0–255)
|
||||
inline u8 rgb5ToRgb8(u8 val5)
|
||||
{
|
||||
return (val5 * 255) / 31;
|
||||
}
|
||||
|
||||
// Convert RGB8 to RGB5
|
||||
inline u32 rgb8ToRgb5(u32 value8)
|
||||
// When the 2d engine converts from 5 to 6 bit, the lsb bit will always be zero (i.e. 31 -> 62)
|
||||
inline constexpr u32 rgb8ToRgb5(u32 value8)
|
||||
{
|
||||
u32 value5 = (value8 * 63 + 255) / (255 * 2);
|
||||
if (value5 > 31)
|
||||
@ -24,43 +18,36 @@ inline u32 rgb8ToRgb5(u32 value8)
|
||||
}
|
||||
|
||||
// Convert RGB8 to RGB6 (for the 6-bit green)
|
||||
inline u32 rgb8ToRgb6(u32 value8)
|
||||
inline constexpr u32 rgb8ToRgb6(u32 value8)
|
||||
{
|
||||
return (value8 * 63 + 128) / 255;
|
||||
}
|
||||
|
||||
// Simple and optimal clamping
|
||||
inline u8 clamp255(int val)
|
||||
inline constexpr u8 clamp255(int val)
|
||||
{
|
||||
return val < 0
|
||||
? 0 : (val > 255 ? 255 : val);
|
||||
}
|
||||
|
||||
// Apply Luminance from the selected color profile (0–100 values)
|
||||
inline u8 applyLuminance(u8 val, int luminance)
|
||||
{
|
||||
return clamp255((val * luminance) / 100);
|
||||
return val < 0 ? 0 : (val > 255 ? 255 : val);
|
||||
}
|
||||
|
||||
// Apply correction matrix from selected color profile
|
||||
inline void applyColorMatrix(const int matrix[3][3], u8 r, u8 g, u8 b, u8& outR, u8& outG, u8& outB)
|
||||
inline void applyColorMatrix(const fix32<12> matrix[3][3], fix32<12> r, fix32<12> g, fix32<12> b, fix32<12>& outR, fix32<12>& outG, fix32<12>& outB)
|
||||
{
|
||||
// Assuming no alpha channel in original calculation.
|
||||
int newR = (matrix[0][0] * r + matrix[0][1] * g + matrix[0][2] * b) / 1000;
|
||||
int newG = (matrix[1][0] * r + matrix[1][1] * g + matrix[1][2] * b) / 1000;
|
||||
int newB = (matrix[2][0] * r + matrix[2][1] * g + matrix[2][2] * b) / 1000;
|
||||
fix32<12> newR = (matrix[0][0] * r + matrix[0][1] * g + matrix[0][2] * b);
|
||||
fix32<12> newG = (matrix[1][0] * r + matrix[1][1] * g + matrix[1][2] * b);
|
||||
fix32<12> newB = (matrix[2][0] * r + matrix[2][1] * g + matrix[2][2] * b);
|
||||
|
||||
outR = clamp255(newR);
|
||||
outG = clamp255(newG);
|
||||
outB = clamp255(newB);
|
||||
// We need to clamp specifically at this step or else color will get ruined
|
||||
outR = clamp255(newR.Int());
|
||||
outG = clamp255(newG.Int());
|
||||
outB = clamp255(newB.Int());
|
||||
}
|
||||
|
||||
// Convert corrected RGB8 channels to RGB555 values (with the extra green bit)
|
||||
inline u16 packToRGB5(u8 r, u8 g, u8 b)
|
||||
inline constexpr u16 packToRGB5(fix32<12> r, fix32<12> g, fix32<12> b)
|
||||
{
|
||||
u16 r5 = rgb8ToRgb5(r);
|
||||
u16 g6 = rgb8ToRgb6(g); // 6-bit green
|
||||
u16 b5 = rgb8ToRgb5(b);
|
||||
u16 r5 = rgb8ToRgb5(r.Int());
|
||||
u16 g6 = rgb8ToRgb6(g.Int()); // 6-bit green
|
||||
u16 b5 = rgb8ToRgb5(b.Int());
|
||||
|
||||
return (b5 << 10) | ((g6 >> 1) << 5) | r5 | (g6 << 15); // bit 15 = extra green bit
|
||||
}
|
||||
@ -72,34 +59,33 @@ static u16 applyColorCorrection(const u16 rgb5)
|
||||
return rgb5; // fallback
|
||||
|
||||
// Extract RGB chanels
|
||||
u8 r5, g5, b5;
|
||||
r5 = (rgb5 & 0x1F);
|
||||
g5 = (rgb5 >> 5) & 0x1F;
|
||||
b5 = (rgb5 >> 10) & 0x1F;
|
||||
fix32<12> r5 = (rgb5 & 0x1F);
|
||||
fix32<12> g5 = (rgb5 >> 5) & 0x1F;
|
||||
fix32<12> b5 = (rgb5 >> 10) & 0x1F;
|
||||
|
||||
u8 r8 = rgb5ToRgb8(r5);
|
||||
u8 g8 = rgb5ToRgb8(g5);
|
||||
u8 b8 = rgb5ToRgb8(b5);
|
||||
// Scale from 5 bits to 8 bits (0–255)
|
||||
fix32<12> r8 = (r5 * 255) / 31;
|
||||
fix32<12> g8 = (g5 * 255) / 31;
|
||||
fix32<12> b8 = (b5 * 255) / 31;
|
||||
|
||||
// Convert to linear gamma (encode)
|
||||
u8 rLin = encodeGamma(r8);
|
||||
u8 gLin = encodeGamma(g8);
|
||||
u8 bLin = encodeGamma(b8);
|
||||
fix32<12> rLin = encodeGamma(r8.Int());
|
||||
fix32<12> gLin = encodeGamma(g8.Int());
|
||||
fix32<12> bLin = encodeGamma(b8.Int());
|
||||
|
||||
// Apply luminance
|
||||
int luminance = gCurrentPreset->luminance;
|
||||
rLin = applyLuminance(rLin, luminance);
|
||||
gLin = applyLuminance(gLin, luminance);
|
||||
bLin = applyLuminance(bLin, luminance);
|
||||
rLin = (rLin * gCurrentPreset->luminance);
|
||||
gLin = (gLin * gCurrentPreset->luminance);
|
||||
bLin = (bLin * gCurrentPreset->luminance);
|
||||
|
||||
// Apply color correction
|
||||
u8 outR, outG, outB;
|
||||
// Apply color correction matrix
|
||||
fix32<12> outR, outG, outB;
|
||||
applyColorMatrix(gCurrentPreset->matrix, rLin, gLin, bLin, outR, outG, outB);
|
||||
|
||||
// Convert to display gamma (decode).
|
||||
outR = decodeGamma(outR);
|
||||
outG = decodeGamma(outG);
|
||||
outB = decodeGamma(outB);
|
||||
outR = decodeGamma(outR.Int());
|
||||
outG = decodeGamma(outG.Int());
|
||||
outB = decodeGamma(outB.Int());
|
||||
|
||||
// Denormalize and convert to RGB8.
|
||||
return packToRGB5(outR, outG, outB);
|
||||
|
@ -1,14 +1,15 @@
|
||||
#pragma once
|
||||
#include "ColorLut.h"
|
||||
#include "Core/Math/fixed.h"
|
||||
|
||||
struct ColorProfile
|
||||
{
|
||||
int matrix[3][3]; // coeficients multiplied by 1000
|
||||
int luminance; // multiplier *100, i.g. 93
|
||||
fix32<12> matrix[3][3]; // 3x3 correction matrix
|
||||
fix32<12> luminance; // Luminance factor
|
||||
};
|
||||
|
||||
// libretro shader values. Credits: hunterk and Pokefan531.
|
||||
// Last updated 2025-12-03.
|
||||
// Libretro shader values. Credits: hunterk and Pokefan531.
|
||||
// https://forums.libretro.com/t/real-gba-and-ds-phat-colors/1540/238
|
||||
// Last updated 10-05-2025.
|
||||
|
||||
// const ColorProfile PRESET_NAME =
|
||||
//{
|
||||
@ -21,124 +22,124 @@ struct ColorProfile
|
||||
//};
|
||||
|
||||
// libretro GBA AGB-001 color (sRGB).
|
||||
constexpr inline ColorProfile Agb001 =
|
||||
const ColorProfile Agb001 =
|
||||
{
|
||||
{
|
||||
{ 905, 195, -100 },
|
||||
{ 100, 650, 250 },
|
||||
{ 158, 143, 700 }
|
||||
{ fix32<12>(0.905f), fix32<12>(0.195f), fix32<12>(-0.1f) },
|
||||
{ fix32<12>(0.1f), fix32<12>(0.65f), fix32<12>(0.25f) },
|
||||
{ fix32<12>(0.1575f), fix32<12>(0.1425f), fix32<12>(0.7f) }
|
||||
},
|
||||
91
|
||||
fix32<12>(0.91f)
|
||||
};
|
||||
|
||||
// libretro GBA SP (AGS-101) color (sRGB).
|
||||
constexpr inline ColorProfile Ags101 =
|
||||
const ColorProfile Ags101 =
|
||||
{
|
||||
{
|
||||
{ 960, 110, -70 },
|
||||
{ 33, 890, 78 },
|
||||
{ 1, -30, 1029 }
|
||||
{ fix32<12>(0.96f), fix32<12>(0.11f), fix32<12>(-0.07f) },
|
||||
{ fix32<12>(0.0325f), fix32<12>(0.89f), fix32<12>(0.0775f) },
|
||||
{ fix32<12>(0.001f), fix32<12>(-0.03f), fix32<12>(1.029f) }
|
||||
},
|
||||
94
|
||||
fix32<12>(0.935f)
|
||||
};
|
||||
|
||||
// libretro GB micro OXY-001 color (sRGB).
|
||||
constexpr inline ColorProfile Oxy001 =
|
||||
const ColorProfile Oxy001 =
|
||||
{
|
||||
{
|
||||
{ 803, 310, -113 },
|
||||
{ 100, 688, 213 },
|
||||
{ 123, 113, 765 }
|
||||
{ fix32<12>(0.8025f), fix32<12>(0.31f), fix32<12>(-0.1125f) },
|
||||
{ fix32<12>(0.1f), fix32<12>(0.6875f), fix32<12>(0.2125f) },
|
||||
{ fix32<12>(0.1225f), fix32<12>(0.1125f), fix32<12>(0.765f) }
|
||||
},
|
||||
90
|
||||
fix32<12>(0.9f)
|
||||
};
|
||||
|
||||
//// libretro NDS Phat NTR-001 color (sRGB).
|
||||
constexpr inline ColorProfile Ntr001 =
|
||||
const ColorProfile Ntr001 =
|
||||
{
|
||||
{
|
||||
{ 835, 270, -105 },
|
||||
{ 100, 638, 263 },
|
||||
{ 105, 175, 720 }
|
||||
{ fix32<12>(0.835f), fix32<12>(0.27f), fix32<12>(-0.105f) },
|
||||
{ fix32<12>(0.1f), fix32<12>(0.6375f), fix32<12>(0.2625f) },
|
||||
{ fix32<12>(0.105f), fix32<12>(0.175f), fix32<12>(0.72f) }
|
||||
},
|
||||
91
|
||||
fix32<12>(0.905f)
|
||||
};
|
||||
|
||||
// libretro NDS lite USG-001 color (sRGB).
|
||||
constexpr inline ColorProfile Usg001 =
|
||||
const ColorProfile Usg001 =
|
||||
{
|
||||
{
|
||||
{ 930, 140, -70 },
|
||||
{ 25, 900, 75 },
|
||||
{ 8, -30, 1022 }
|
||||
{ fix32<12>(0.93f), fix32<12>(0.14f), fix32<12>(-0.07f) },
|
||||
{ fix32<12>(0.025f), fix32<12>(0.9f), fix32<12>(0.075f) },
|
||||
{ fix32<12>(0.008f), fix32<12>(-0.03f), fix32<12>(1.022f) }
|
||||
},
|
||||
94
|
||||
fix32<12>(0.935f)
|
||||
};
|
||||
|
||||
// libretro PSP 1000 color (sRGB).
|
||||
constexpr inline ColorProfile Psp01g =
|
||||
const ColorProfile Psp01g =
|
||||
{
|
||||
{
|
||||
{ 835, 160, -130 },
|
||||
{ 43, 745, 155 },
|
||||
{ 23, 15, 963 }
|
||||
{ fix32<12>(0.835f), fix32<12>(0.155f), fix32<12>(-0.135f) },
|
||||
{ fix32<12>(0.0425f), fix32<12>(0.745f), fix32<12>(0.155f) },
|
||||
{ fix32<12>(0.0225f), fix32<12>(0.0145f), fix32<12>(0.963f) }
|
||||
},
|
||||
99
|
||||
fix32<12>(0.99f)
|
||||
};
|
||||
|
||||
// libretro Nintendo Switch GBA Classics color (sRGB).
|
||||
constexpr inline ColorProfile NswIps =
|
||||
const ColorProfile NswIps =
|
||||
{
|
||||
{
|
||||
{ 865, 123, 13 },
|
||||
{ 58, 925, 13 },
|
||||
{ 58, 123, 820 }
|
||||
{ fix32<12>(0.865f), fix32<12>(0.1225f), fix32<12>(0.0125f) },
|
||||
{ fix32<12>(0.0575f), fix32<12>(0.925f), fix32<12>(0.0125f) },
|
||||
{ fix32<12>(0.0575f), fix32<12>(0.1225f), fix32<12>(0.82f) }
|
||||
},
|
||||
100
|
||||
fix32<12>(1.f)
|
||||
};
|
||||
|
||||
// libretro Nintendo Switch GBA Classics Oled color (sRGB).
|
||||
constexpr inline ColorProfile NswOle =
|
||||
const ColorProfile NswOle =
|
||||
{
|
||||
{
|
||||
{ 1540, -480, -60 },
|
||||
{ -45, 1063, -18 },
|
||||
{ -23, -75, 1103 }
|
||||
{ fix32<12>(1.54f), fix32<12>(-0.48f), fix32<12>(-0.06f) },
|
||||
{ fix32<12>(-0.045f), fix32<12>(1.0625f), fix32<12>(-0.0175f) },
|
||||
{ fix32<12>(-0.0225f), fix32<12>(-0.075f), fix32<12>(1.1025f) }
|
||||
},
|
||||
100
|
||||
fix32<12>(1.f)
|
||||
};
|
||||
|
||||
// libretro Visual Boy Advance color.
|
||||
constexpr inline ColorProfile VbaEmu =
|
||||
const ColorProfile VbaEmu =
|
||||
{
|
||||
{
|
||||
{ 730, 270, 0 },
|
||||
{ 85, 675, 240 },
|
||||
{ 85, 240, 675 }
|
||||
{ fix32<12>(0.73f), fix32<12>(0.27f), fix32<12>(0.f) },
|
||||
{ fix32<12>(0.0825f), fix32<12>(0.6775f), fix32<12>(0.24f) },
|
||||
{ fix32<12>(0.0825f), fix32<12>(0.24f), fix32<12>(0.6775f) }
|
||||
},
|
||||
100
|
||||
fix32<12>(1.f)
|
||||
};
|
||||
|
||||
// libretro No$GBA full color.
|
||||
constexpr inline ColorProfile NoCash =
|
||||
const ColorProfile NoCash =
|
||||
{
|
||||
{
|
||||
{ 730, 270, 0 },
|
||||
{ 83, 678, 240 },
|
||||
{ 83, 240, 678 }
|
||||
{ fix32<12>(0.62f), fix32<12>(0.1913f), fix32<12>(-0.0917f) },
|
||||
{ fix32<12>(0.004f), fix32<12>(0.56f), fix32<12>(0.167f) },
|
||||
{ fix32<12>(0.004f), fix32<12>(0.167f), fix32<12>(0.56f) },
|
||||
},
|
||||
100
|
||||
fix32<12>(0.649f)
|
||||
};
|
||||
|
||||
// libretro mGBA GBA shader color.
|
||||
constexpr inline ColorProfile mGba01 =
|
||||
const ColorProfile mGba01 =
|
||||
{
|
||||
{
|
||||
{ 840, 180, 0 },
|
||||
{ 90, 670, 260 },
|
||||
{ 150, 100, 730 }
|
||||
{ fix32<12>(0.84f), fix32<12>(0.18f), fix32<12>(0.f) },
|
||||
{ fix32<12>(0.09f), fix32<12>(0.67f), fix32<12>(0.26f) },
|
||||
{ fix32<12>(0.15f), fix32<12>(0.10f), fix32<12>(0.73f) }
|
||||
},
|
||||
99
|
||||
fix32<12>(0.99f)
|
||||
};
|
||||
|
||||
constexpr const ColorProfile* colorProfileLut[] =
|
||||
@ -149,7 +150,7 @@ constexpr const ColorProfile* colorProfileLut[] =
|
||||
/* GbaColorCorrection::Oxy001 */ &Oxy001,
|
||||
/* GbaColorCorrection::Ntr001 */ &Ntr001,
|
||||
/* GbaColorCorrection::Usg001 */ &Usg001,
|
||||
/* GbaColorCorrection::PspO1g */ &PspO1g,
|
||||
/* GbaColorCorrection::Psp01g */ &Psp01g,
|
||||
/* GbaColorCorrection::NswIps */ &NswIps,
|
||||
/* GbaColorCorrection::NswOle */ &NswOle,
|
||||
/* GbaColorCorrection::VbaEmu */ &VbaEmu,
|
||||
|
Loading…
Reference in New Issue
Block a user