/* Copies the loaded external palette into current palette - without applying adjustments. */ static void CopyExternalWithoutAdjustments(void) { int i; unsigned char *ext_ptr; for (i = 0, ext_ptr = Colours_external->palette; i < 256; i ++, ext_ptr += 3) Colours_SetRGB(i, *ext_ptr, *(ext_ptr + 1), *(ext_ptr + 2), Colours_table); }
/* Applies the colours setup to the external palette. Writes output to COLOURTABLE. */ static void AdjustExternal(int colourtable[256]) { const double gamma = 1 - COLOURS_PAL_setup.gamma / 2.0; unsigned char *ext_ptr = COLOURS_PAL_external.palette; int n; for (n = 0; n < 256; n ++) { /* Convert RGB values from external palette to YIQ. */ double r = (double)*ext_ptr++ / 255.0; double g = (double)*ext_ptr++ / 255.0; double b = (double)*ext_ptr++ / 255.0; double y = 0.299 * r + 0.587 * g + 0.114 * b; double u = -0.14713 * r - 0.28886 * g + 0.436 * b; double v = 0.615 * r - 0.51499 * g - 0.10001 * b; y = pow(y, gamma); y *= COLOURS_PAL_setup.contrast * 0.5 + 1; y += COLOURS_PAL_setup.brightness * 0.5; if (y > 1.0) y = 1.0; else if (y < 0.0) y = 0.0; u *= COLOURS_PAL_setup.saturation + 1.0; v *= COLOURS_PAL_setup.saturation + 1.0; r = y + 1.13983 * v; g = y - 0.39465 * u - 0.58060 * v; b = y + 2.03211 * u; Colours_SetRGB(n, (int) (r * 255), (int) (g * 255), (int) (b * 255), colourtable); } }
/* Averages YUV values from YUV_TABLE and converts them to RGB values. Stores them in COLOURTABLE. */ static void YUV2RGB(int colourtable[256], double const yuv_table[256*5]) { double const *yuv_ptr = yuv_table; int n; for (n = 0; n < 256; ++n) { double y = *yuv_ptr++; double even_u = *yuv_ptr++; double odd_u = *yuv_ptr++; double even_v = *yuv_ptr++; double odd_v = *yuv_ptr++; double r, g, b; /* The different colors in odd and even lines are not emulated - instead the palette contains averaged values. */ double u = (even_u + odd_u) / 2.0; double v = (even_v + odd_v) / 2.0; Colours_YUV2RGB(y, u, v, &r, &g, &b); if (!COLOURS_PAL_external.loaded || COLOURS_PAL_external.adjust) { /* The r, g, b values derived from the YUV signal are non-linear (ie. gamma-corrected). We convert them to linear values, assuming the CRT TV's gamma = COLOURS_PAL_setup.gamma. */ r = Colours_Gamma2Linear(r, COLOURS_PAL_setup.gamma); g = Colours_Gamma2Linear(g, COLOURS_PAL_setup.gamma); b = Colours_Gamma2Linear(b, COLOURS_PAL_setup.gamma); /* Now we convert the linear values to the sRGB colourspace. */ r = Colours_Linear2sRGB(r); g = Colours_Linear2sRGB(g); b = Colours_Linear2sRGB(b); } Colours_SetRGB(n, (int) (r * 255), (int) (g * 255), (int) (b * 255), colourtable); } }
/* Generates a PAL palette, based on colour setup. Result is written into COLOURTABLE. */ static void GeneratePalette(int colourtable[256]) { int cr, lm; double scaled_black_level = (double)COLOURS_PAL_setup.black_level / 255.0f; double scaled_white_level = (double)COLOURS_PAL_setup.white_level / 255.0f; const double gamma = 1 - COLOURS_PAL_setup.gamma / 2.0; /* NTSC luma multipliers from CGIA.PDF */ double luma_mult[16] = { 0.6941, 0.7091, 0.7241, 0.7401, 0.7560, 0.7741, 0.7931, 0.8121, 0.8260, 0.8470, 0.8700, 0.8930, 0.9160, 0.9420, 0.9690, 1.0000}; /* TODO Angles were chosen based on examination of several PAL screenshots. A thorough examination of PAL GTIA color generation is needed instead, to determine a mathematical formula that stands behind these values. */ double color_angles[16] = { 0.0, 2.267095, 1.927638, 1.715966, 1.228852, 0.863367, 0.447344, -0.361837, -0.815415, -1.198193, 4.568137, 4.014433, 3.568811, 3.134938, 2.71825, 2.279574 }; for (cr = 0; cr < 16; cr ++) { double angle = color_angles[cr]; double saturation = (cr ? (COLOURS_PAL_setup.saturation + 1) * 0.175f: 0.0f); double u = cos(angle) * saturation; double v = sin(angle) * saturation; for (lm = 0; lm < 16; lm ++) { /* calculate yiq for color entry */ double y = (luma_mult[lm] - luma_mult[0]) / (luma_mult[15] - luma_mult[0]); double r, g, b; y = pow(y, gamma); y *= COLOURS_PAL_setup.contrast * 0.5 + 1; y += COLOURS_PAL_setup.brightness * 0.5; /* Scale the Y signal's range from 0..1 to * scaled_black_level..scaled_white_level */ y = y * (scaled_white_level - scaled_black_level) + scaled_black_level; /* if (y < scaled_black_level) y = scaled_black_level; else if (y > scaled_white_level) y = scaled_white_level; */ r = y + 1.13983 * v; g = y - 0.39465 * u - 0.58060 * v; b = y + 2.03211 * u; Colours_SetRGB(cr * 16 + lm, (int) (r * 255), (int) (g * 255), (int) (b * 255), colourtable); } } }