Git Product home page Git Product logo

Comments (16)

Rangi42 avatar Rangi42 commented on June 6, 2024 1

Is the curve there identical to that in SameBoy?

Yes.

from rgbds.

Rangi42 avatar Rangi42 commented on June 6, 2024

rgba.cpp credits its color curve to LIJI32/SameBoy@65dd02c. SameBoy's color correction is designed to make PC colors appear like GBC hardware ones, with less contrast and brightness. RGBGFX would want to do the reverse, and exaggerate the colors so playing on real hardware would look like the designer's PC mockups.

To do: fill in the gaps in this reversed mapping:

static std::array<uint8_t, 256> reverse_curve{
    0, __,  1, __,  2, __, __,  3, __, __, __, __,  4, __, __, __, // These
    __, __,  5, __, __, __, __, __, __,  6, __, __, __, __, __, __, // comments
    __, __,  7, __, __, __, __, __, __, __,  8, __, __, __, __, __, // prevent
    __, __, __, __,  9, __, __, __, __, __, __, __, __, __, 10, __, // clang-format
    __, __, __, __, __, __, __, __, __, 11, __, __, __, __, __, __, // from
    __, __, __, __, __, 12, __, __, __, __, __, __, __, __, __, __, // reflowing
    __, 13, __, __, __, __, __, __, __, __, __, __, __, 14, __, __, // these
    __, __, __, __, __, __, __, __, __, 15, __, __, __, __, __, __, // sixteen
    __, __, __, __, __, __, 16, __, __, __, __, __, __, __, __, __, // 16-item
    __, __, 17, __, __, __, __, __, __, __, __, __, __, __, 18, __, // lines,
    __, __, __, __, __, __, __, __, __, __, 19, __, __, __, __, __, // which,
    __, __, __, __, __, __, 20, __, __, __, __, __, __, __, __, __, // in
    __, 21, __, __, __, __, __, __, __, __, __, 22, __, __, __, __, // my
    __, __, __, __, __, 23, __, __, __, __, __, __, __, 24, __, __, // opinion,
    __, __, __, __, __, __, 25, __, __, __, __, __, __, 26, __, __, // help
    __, __, __, 27, __, __, __, __, 28, __, __, 29, __, 30, __, 31, // visualization!
};

image

from rgbds.

ISSOtm avatar ISSOtm commented on June 6, 2024

Is the curve there identical to that in SameBoy?

from rgbds.

ISSOtm avatar ISSOtm commented on June 6, 2024

SameBoy has a lot of colour correction settings, but I think we should stick to GB_COLOR_CORRECTION_CORRECT_CURVES (which, I believe, corresponds to what @LIJI32 calls "Harsh Reality"). Then comes the question of which curve we want to stick to; I'd favour the "default" one over SGB or AGB.

from rgbds.

ISSOtm avatar ISSOtm commented on June 6, 2024

I was slightly lazy and linearly interpolated between those points:

static std::array<uint8_t, 256> reverse_curve{
	 0,  0,  0,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2, // These
	 3,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  4,  4,  4, // comments
	 5,  5,  5,  5,  5,  5,  5,  5,  5,  6,  6,  6,  6,  6,  6,  6, // prevent
	 6,  6,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  8,  8,  8, // clang-format
	 8,  8,  8,  8,  8,  8,  8,  9,  9,  9,  9,  9,  9,  9,  9,  9, // from
	 9,  9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, // reflowing
	11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, // these
	12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, // sixteen
	13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, // 16-item
	15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, // lines,
	16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, // which
	17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, // in my
	19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, // opinion,
	21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, // improves
	23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, // the
	25, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 29, 29, 30, 30, 31, // readability!
};
Code used to generate this:
const CURVE: [u8; 32] = [
    0, 6, 12, 20, 28, 36, 45, 56, 66, 76, 88, 100, 113, 125, 137, 149, 161, 172, 182, 192, 202,
    210, 218, 225, 232, 238, 243, 247, 250, 252, 254, 255,
];

fn main() {
    for i in 0..=255 {
        let rev = match CURVE.binary_search(&i) {
            Ok(idx) => idx,
            Err(insert_idx) => {
                let lower = CURVE[insert_idx - 1];
                let higher = CURVE[insert_idx];
                // Linearly interpolate between these two.
                if i - lower < higher - i {
                    insert_idx - 1
                } else {
                    insert_idx
                }
            }
        };
        print!("{rev:2}, ");
        if i % 16 == 15 {
            println!();
        }
    }
}

from rgbds.

aaaaaa123456789 avatar aaaaaa123456789 commented on June 6, 2024

Just by looking at the data, I can't recognize the function itself, but the second derivative is small enough that a linear interpolation shouldn't be too far off.

from rgbds.

ISSOtm avatar ISSOtm commented on June 6, 2024

I got a polynomial regression of -0.0134x³ + 0.5484x² + 4.2072x - 5.3585 to match with R² = 0.9998. I don't know if that helps.

from rgbds.

Rangi42 avatar Rangi42 commented on June 6, 2024

I was slightly lazy and linearly interpolated between those points:

That curve is still the reverse of what we need. It should be identical to the reverse_curve above, but with the __s filled in.

I generated one with NumPy; here's the code:

curve.py
#!/usr/bin/env python3

import numpy

# Copied from https://github.com/LIJI32/SameBoy/commit/65dd02cc#diff-34ffdb0f13b7232c28e80c9e78e86d5ea95bc08ca0a45d8c3ab195f18e4e1921R230
xs = [0,2,4,7,12,18,25,34,42,52,62,73,85,97,109,121,134,146,158,170,182,193,203,213,221,230,237,243,248,251,253,255]
ys = [(v << 3) | (v >> 2) for v in range(32)]

degree = 9 # minimum need to not have errors greater than 1
fit = numpy.polynomial.polynomial.polyfit(xs, ys, deg=degree)

def interpolate(x):
	return int(round(sum(fit[i]*x**i for i in range(degree + 1))))

print('x', 'y', 'interpolated', sep='\t')
for x, y in zip(xs, ys):
	interpolated = interpolate(x)
	error = ['!'] if abs(y - interpolated) > 1 else []
	print(*[x, y, interpolated, *error], sep='\t')
print()

data = [(ys[xs.index(x)] if x in xs else interpolate(x)) >> 3 for x in range(256)]

comments = ['These', 'comments', 'prevent', 'clang-format', 'from', 'reflowing', 'these', 'sixteen',
	'16-item', 'lines,', 'which,', 'in', 'my', 'opinion,', 'help', 'visualization!',]
print('static std::array<uint8_t, 256> reverse_curve{')
for i in range(16):
	print(f"    {', '.join(f'{v:2}' for v in data[i*16:i*16+16])}, // {comments[i]}")
print('};')

This is the completely interpolated array:

static std::array<uint8_t, 256> reverse_curve{
    0,  0,  1,  1,  2,  2,  2,  3,  3,  3,  3,  4,  4,  4,  4,  4, // These
    4,  5,  5,  5,  5,  5,  5,  5,  6,  6,  6,  6,  6,  6,  6,  6, // comments
    7,  7,  7,  7,  7,  7,  7,  7,  7,  8,  8,  8,  8,  8,  8,  8, // prevent
    8,  8,  9,  9,  9,  9,  9,  9,  9,  9,  9, 10, 10, 10, 10, 10, // clang-format
    10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, // from
    12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, // reflowing
    13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, // these
    14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, // sixteen
    16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, // 16-item
    17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, // lines,
    18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, // which,
    20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, // in
    21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, // my
    23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, // opinion,
    25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 27, // help
    27, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 30, 30, 31, 31, // visualization!
};

from rgbds.

Rangi42 avatar Rangi42 commented on June 6, 2024

Hmm, that's based on an old curve; https://github.com/LIJI32/SameBoy/blob/master/Core/display.c#L257 is different.

When I use those values for xs in the above curve.py script, I get this reverse curve:

static std::array<uint8_t, 256> reverse_curve{
    0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2, // These
    2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4, // comments
    4,  4,  4,  4,  5,  5,  5,  5,  5,  5,  5,  5,  6,  6,  6,  6, // prevent
    6,  6,  6,  6,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  8, // clang-format
    8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  9,  9,  9,  9,  9,  9, // from
    9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, // reflowing
    10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, // these
    12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, // sixteen
    13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, // 16-item
    15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, // lines,
    16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, // which,
    17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, // in
    19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, // my
    21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, // opinion,
    23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, // help
    26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 29, 29, 30, 30, 31, // visualization!
};

I've updated #1241 to use this data.

from rgbds.

Rangi42 avatar Rangi42 commented on June 6, 2024

If that's still desaturated, then swapping xs and ys gives this:

static std::array<uint8_t, 256> reverse_curve{
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1, // These
    1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3, // comments
    3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  4,  4,  5,  5,  5,  5, // prevent
    5,  5,  5,  6,  6,  6,  6,  6,  6,  7,  7,  7,  7,  7,  7,  7, // clang-format
    7,  8,  8,  8,  8,  8,  8,  9,  9,  9,  9,  9, 10, 10, 10, 10, // from
    10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, // reflowing
    13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, // these
    16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 19, 19, // sixteen
    19, 19, 19, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 22, // 16-item
    22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, // lines,
    24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, // which,
    26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, // in
    28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, // my
    29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, // opinion,
    31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, // help
    31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, // visualization!
};

from rgbds.

Rangi42 avatar Rangi42 commented on June 6, 2024

Testing all the possible colors:

Without a reverse curve:
raw

With the first curve:
rev1

With the second curve:
rev2

Code:

colors.py
#!/usr/bin/env python3

import sys
import png

mode = sys.argv[1] if len(sys.argv) > 1 else 'raw'
if mode not in {'raw', 'rev1', 'rev2'}:
	print(f'Usage: {sys.argv[0]} (raw | rev1 | rev2)', file=sys.stderr)
	exit(1)

def up(c):
	if mode == 'rev1':
		# https://github.com/gbdev/rgbds/issues/1226#issuecomment-1809210877
		c = [
			0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  2,  2,  2,  2,
			2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3,  4,  4,  4,  4,
			4,  4,  4,  4,  5,  5,  5,  5,  5,  5,  5,  5,  6,  6,  6,  6,
			6,  6,  6,  6,  6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  8,
			8,  8,  8,  8,  8,  8,  8,  8,  8,  8,  9,  9,  9,  9,  9,  9,
			9,  9,  9,  9,  9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
			10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12,
			12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13,
			13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15,
			15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16,
			16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17,
			17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19,
			19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21,
			21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23,
			23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25,
			26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 29, 29, 30, 30, 31,
		][(c << 3) | (c >> 2)]
	elif mode == 'rev2':
		# https://github.com/gbdev/rgbds/issues/1226#issuecomment-1809231223
		c = [
			0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,
			1,  1,  1,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,
			3,  3,  3,  3,  3,  4,  4,  4,  4,  4,  4,  4,  5,  5,  5,  5,
			5,  5,  5,  6,  6,  6,  6,  6,  6,  7,  7,  7,  7,  7,  7,  7,
			7,  8,  8,  8,  8,  8,  8,  9,  9,  9,  9,  9, 10, 10, 10, 10,
			10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13,
			13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16,
			16, 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 19, 19,
			19, 19, 19, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 22,
			22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24,
			24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26,
			26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28,
			28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
			29, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
			31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
			31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31,
		][(c << 3) | (c >> 2)]
	return (c << 3) | (c >> 2)

ch_bits = 5
ch_size = 2**ch_bits  # 32

width_sq = 8
height_sq = 4
assert width_sq * height_sq == ch_size

width_px = width_sq * ch_size  # 256
height_px = height_sq * ch_size  # 128

rows = [[(0, 0, 0)] * width_px for _ in range(height_px)]

for r in range(32):
	for g in range(32):
		for b in range(32):
			x = (r % width_sq) * ch_size + b
			y = (r // width_sq) * ch_size + g
			rows[y][x] = (up(r), up(g), up(b))

rows = [sum(row, ()) for row in rows]

writer = png.Writer(width_px, height_px, greyscale=False, bitdepth=8, compression=9)
with open(f'colors_{mode}.png', 'wb') as file:
	writer.write(file, rows)

On that basis I've updated the PR to use rev2.

from rgbds.

Rangi42 avatar Rangi42 commented on June 6, 2024

Hmm, so SameBoy's "Harsh reality" color correction, which is presumably the closest to real GBC hardware, does more than just map through that curve array. Here's the reduced code for CGB with GB_COLOR_CORRECTION_LOW_CONTRAST:

static inline uint8_t scale_channel_with_curve(uint8_t x)
{
    return inline_const(uint8_t[], {0,6,12,20,28,36,45,56,66,76,88,100,113,125,137,149,161,172,182,192,202,210,218,225,232,238,243,247,250,252,254,255})[x];
}

// given r,g,b in 0-31 range, update their values to be harshly realistic
r = scale_channel_with_curve(r);
g = scale_channel_with_curve(g);
b = scale_channel_with_curve(b);
if (g != b) {
  g = round(pow((pow(g / 255.0, 2.2) * 3 + pow(b / 255.0, 2.2)) / 4, 1 / 2.2) * 255);
}
uint8_t new_r = r * 15 / 16 + (    g + b) / 32;
uint8_t new_g = g * 15 / 16 + (r   +   b) / 32;
uint8_t new_b = b * 15 / 16 + (r + g    ) / 32;
r = new_r;
g = new_g;
b = new_b;
r = r * (162 - 45) / 255 + 45;
g = g * (167 - 41) / 255 + 41;
b = b * (157 - 38) / 255 + 38;
r >>= 3;
g >>= 3;
b >>= 3;

Maybe we should figure out a more complex reverse transformation than just a per-channel lookup table.

from rgbds.

Rangi42 avatar Rangi42 commented on June 6, 2024

This will print out all 32,768 raw->scaled colors. Ideally we'd want to reverse-map every color on the right to its original on the left.

#include <stdio.h>
#include <math.h>

int main() {
    static int scale_channel_with_curve[32] = {
        0,6,12,20,28,36,45,56,66,76,88,100,113,125,137,149,161,172,
        182,192,202,210,218,225,232,238,243,247,250,252,254,255
    };
    for (int raw_r = 0; raw_r < 32; raw_r++) {
        for (int raw_g = 0; raw_g < 32; raw_g++) {
            for (int raw_b = 0; raw_b < 32; raw_b++) {
                int scaled_r = scale_channel_with_curve[raw_r];
                int scaled_g = scale_channel_with_curve[raw_g];
                int scaled_b = scale_channel_with_curve[raw_b];
                if (scaled_g != scaled_b) {
                    scaled_g = round(pow((pow(scaled_g / 255.0, 2.2) * 3 +
                        pow(scaled_b / 255.0, 2.2)) / 4, 1 / 2.2) * 255);
                }
                int new_r = scaled_r * 15 / 16 + (scaled_g + scaled_b) / 32;
                int new_g = scaled_g * 15 / 16 + (scaled_r + scaled_b) / 32;
                int new_b = scaled_b * 15 / 16 + (scaled_r + scaled_g) / 32;
                new_r = new_r * (162 - 45) / 255 + 45;
                new_g = new_g * (167 - 41) / 255 + 41;
                new_b = new_b * (157 - 38) / 255 + 38;
                new_r >>= 3;
                new_g >>= 3;
                new_b >>= 3;
                printf("%02d,%02d,%02d -> %02d,%02d,%02d\n",
                    raw_r, raw_g, raw_b, new_r, new_g, new_b);
            }
        }
    }
    return 0;
}

from rgbds.

Rangi42 avatar Rangi42 commented on June 6, 2024

These are the ranges of the harsh-reality-scaled values:

min R: [05,05,06,06,07,07,08,08,09,09,10,10,11,12,12,13,14,14,15,15,16,16,17,17,18,18,18,18,19,19,19,19]
max R: [06,06,07,07,07,08,08,09,09,10,11,11,12,13,13,14,15,15,16,16,17,17,18,18,18,19,19,19,19,20,20,20]

min G: [05,05,05,06,06,06,07,07,08,08,09,10,10,11,12,12,13,13,14,14,15,15,16,16,16,17,17,17,17,17,18,18]
max G: [13,13,13,13,13,14,14,14,14,14,14,15,15,15,16,16,17,17,17,18,18,18,19,19,19,20,20,20,20,20,20,20]

min B: [04,05,05,05,06,06,07,07,08,08,09,10,10,11,12,12,13,14,14,15,15,16,16,17,17,17,18,18,18,18,18,18]
max B: [05,05,06,06,07,07,08,08,09,09,10,11,11,12,13,13,14,15,15,16,16,17,17,17,18,18,18,19,19,19,19,19]

The red and blue channels could use lookup tables and only be off by +/- 1, but green needs more complex logic.

from rgbds.

LIJI32 avatar LIJI32 commented on June 6, 2024

I honestly think it's better to use "Modern – Accurate" rather than Harsh Reality in this context. Reversing the "Harsh Reality" color transformation would cause way too much color clipping due to the harshly reduced contrast.

from rgbds.

Rangi42 avatar Rangi42 commented on June 6, 2024

Okay, the GB_COLOR_CORRECTION_MODERN_ACCURATE transformation looks easier to just invert, since it doesn't have the step where each channel gets lerped with 1/16th of the others. Although there's still the way that green depends on blue in the gamma-based formula. But if we ignore that, then it really is just the inverted scale_channel_with_curve table which I've already implemented.

uint8_t r = (color) & 0x1F;
uint8_t g = (color >> 5) & 0x1F;
uint8_t b = (color >> 10) & 0x1F;
r = scale_channel_with_curve(r);
g = scale_channel_with_curve(g);
b = scale_channel_with_curve(b);
uint8_t new_r = r;
uint8_t new_g = g != b ? round(pow((pow(g / 255.0, 2.2) * 3 + pow(b / 255.0, 2.2)) / 4, 1 / 2.2) * 255) : g;
uint8_t new_b = b;
r = new_r;
g = new_g;
b = new_b;

Edit: inverting the gamma step:

g = pow((pow(new_g / 31, 2.2) * 4 - pow(new_b / 31, 2.2)) / 3, 1 / 2.2) * 31;

from rgbds.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.