mirror of
https://github.com/fabiangreffrath/woof.git
synced 2025-09-26 06:20:16 -04:00
uniform color quantization (#1868)
* rename I_GetPaletteIndex->I_GetNearestColor
This commit is contained in:
parent
af359bac43
commit
b5070cb54f
@ -2369,8 +2369,8 @@ void AM_ColorPreset(void)
|
||||
if (mapcolor_preset == AM_PRESET_CRISPY)
|
||||
{
|
||||
byte *playpal = W_CacheLumpName("PLAYPAL", PU_CACHE);
|
||||
mapcolor_secr = I_GetPaletteIndex(playpal, 255, 0, 255);
|
||||
mapcolor_revsecr = I_GetPaletteIndex(playpal, 119, 255, 111);
|
||||
mapcolor_secr = I_GetNearestColor(playpal, 255, 0, 255);
|
||||
mapcolor_revsecr = I_GetNearestColor(playpal, 119, 255, 111);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1025,7 +1025,7 @@ void I_SetPalette(byte *palette)
|
||||
|
||||
// Taken from Chocolate Doom chocolate-doom/src/i_video.c:L841-867
|
||||
|
||||
byte I_GetPaletteIndex(byte *palette, int r, int g, int b)
|
||||
byte I_GetNearestColor(byte *palette, int r, int g, int b)
|
||||
{
|
||||
byte best;
|
||||
int best_diff, diff;
|
||||
|
@ -82,7 +82,7 @@ extern boolean correct_aspect_ratio;
|
||||
extern boolean screenvisible;
|
||||
|
||||
extern int gamma2;
|
||||
byte I_GetPaletteIndex(byte *palette, int r, int g, int b);
|
||||
byte I_GetNearestColor(byte *palette, int r, int g, int b);
|
||||
|
||||
boolean I_WritePNGfile(char *filename); // [FG] screenshots in PNG format
|
||||
|
||||
|
@ -111,7 +111,7 @@ boolean MN_LoadFon2(const byte *gfx_data, int size)
|
||||
int r = *p++;
|
||||
int g = *p++;
|
||||
int b = *p++;
|
||||
translate[i] = I_GetPaletteIndex(playpal, r, g, b);
|
||||
translate[i] = I_GetNearestColor(playpal, r, g, b);
|
||||
}
|
||||
|
||||
// 0 is transparent, last is border color
|
||||
|
@ -111,7 +111,7 @@ static byte R_SkyBlendColor(int tex)
|
||||
b = colors[width/3].b;
|
||||
Z_Free(colors);
|
||||
|
||||
return I_GetPaletteIndex(pal, r, g, b);
|
||||
return I_GetNearestColor(pal, r, g, b);
|
||||
}
|
||||
|
||||
typedef struct skycolor_s
|
||||
|
@ -370,7 +370,7 @@ static void ST_DrawSolidBackground(int st_x)
|
||||
b /= 2 * depth * (v1 - v0);
|
||||
|
||||
// [FG] tune down to half saturation (for empiric reasons)
|
||||
col = I_GetPaletteIndex(pal, r/2, g/2, b/2);
|
||||
col = I_GetNearestColor(pal, r/2, g/2, b/2);
|
||||
|
||||
V_FillRect(0, v0, video.unscaledw, v1 - v0, col);
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ void V_InitFlexTranTable(void)
|
||||
{
|
||||
for (b = 0; b < 32; ++b)
|
||||
{
|
||||
RGB32k[r][g][b] = I_GetPaletteIndex(palette, MAKECOLOR(r),
|
||||
RGB32k[r][g][b] = I_GetNearestColor(palette, MAKECOLOR(r),
|
||||
MAKECOLOR(g), MAKECOLOR(b));
|
||||
}
|
||||
}
|
||||
|
167
src/v_fmt.c
167
src/v_fmt.c
@ -268,6 +268,82 @@ static void *DummyFlat(int lump, pu_tag tag)
|
||||
return lumpcache[lump];
|
||||
}
|
||||
|
||||
// Uniform Color Quantization
|
||||
//
|
||||
// Each color component axis (red, green and blue) is divided into a few fixed
|
||||
// segments (8-8-4 in 256 colors). Each found color is placed into a
|
||||
// corresponding segment slot. After all the colors are added, an average
|
||||
// color is calculated for each slot. Those are the colors of the palette.
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int value;
|
||||
int pixel_count;
|
||||
} color_slot_t;
|
||||
|
||||
static void AddValue(color_slot_t *s, int component)
|
||||
{
|
||||
s->value += component;
|
||||
s->pixel_count++;
|
||||
}
|
||||
|
||||
static int GetAverage(color_slot_t *s)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (s->pixel_count > 0)
|
||||
{
|
||||
result = (s->pixel_count == 1) ? s->value : (s->value / s->pixel_count);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
color_slot_t red_slots[8];
|
||||
color_slot_t green_slots[8];
|
||||
color_slot_t blue_slots[4];
|
||||
|
||||
byte palette[768];
|
||||
} uniform_quantizer_t;
|
||||
|
||||
static void AddColor(uniform_quantizer_t *q, int r, int g, int b)
|
||||
{
|
||||
int red_index = r >> 5;
|
||||
int green_index = g >> 5;
|
||||
int blue_index = b >> 6;
|
||||
AddValue(&q->red_slots[red_index], r);
|
||||
AddValue(&q->green_slots[green_index], g);
|
||||
AddValue(&q->blue_slots[blue_index], b);
|
||||
}
|
||||
|
||||
static void GetPalette(uniform_quantizer_t *q)
|
||||
{
|
||||
byte *roller = q->palette;
|
||||
|
||||
for (int rs = 0; rs < arrlen(q->red_slots); ++rs)
|
||||
{
|
||||
for (int gs = 0; gs < arrlen(q->green_slots); ++gs)
|
||||
{
|
||||
for (int bs = 0; bs < arrlen(q->blue_slots); ++bs)
|
||||
{
|
||||
*roller++ = GetAverage(&q->red_slots[rs]);
|
||||
*roller++ = GetAverage(&q->green_slots[gs]);
|
||||
*roller++ = GetAverage(&q->blue_slots[bs]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int GetPaletteIndex(int r, int g, int b)
|
||||
{
|
||||
int red_index = r >> 5;
|
||||
int green_index = g >> 5;
|
||||
int blue_index = b >> 6;
|
||||
return (red_index << 5) + (green_index << 2) + blue_index;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
spng_ctx *ctx;
|
||||
@ -340,8 +416,7 @@ static boolean DecodePNG(png_t *png)
|
||||
|
||||
if (ret)
|
||||
{
|
||||
I_Printf(VB_ERROR, "DecodeImage: spng_get_ihdr %s\n",
|
||||
spng_strerror(ret));
|
||||
I_Printf(VB_ERROR, "DecodePNG: spng_get_ihdr %s\n", spng_strerror(ret));
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -368,7 +443,7 @@ static boolean DecodePNG(png_t *png)
|
||||
|
||||
if (ret)
|
||||
{
|
||||
I_Printf(VB_ERROR, "DecodeImage: spng_decoded_image_size %s",
|
||||
I_Printf(VB_ERROR, "DecodePNG: spng_decoded_image_size %s",
|
||||
spng_strerror(ret));
|
||||
return false;
|
||||
}
|
||||
@ -378,7 +453,7 @@ static boolean DecodePNG(png_t *png)
|
||||
|
||||
if (ret)
|
||||
{
|
||||
I_Printf(VB_ERROR, "DecodeImage: spng_decode_image %s",
|
||||
I_Printf(VB_ERROR, "DecodePNG: spng_decode_image %s",
|
||||
spng_strerror(ret));
|
||||
free(image);
|
||||
return false;
|
||||
@ -391,6 +466,8 @@ static boolean DecodePNG(png_t *png)
|
||||
int indexed_size = image_size / 3;
|
||||
byte *indexed_image = malloc(indexed_size);
|
||||
|
||||
uniform_quantizer_t q = {0};
|
||||
|
||||
byte *roller = image;
|
||||
|
||||
for (int i = 0; i < indexed_size; ++i)
|
||||
@ -399,7 +476,31 @@ static boolean DecodePNG(png_t *png)
|
||||
int g = *roller++;
|
||||
int b = *roller++;
|
||||
|
||||
indexed_image[i] = I_GetPaletteIndex(playpal, r, g, b);
|
||||
AddColor(&q, r, g, b);
|
||||
}
|
||||
|
||||
GetPalette(&q);
|
||||
|
||||
byte translate[256];
|
||||
byte *palette = q.palette;
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
int r = *palette++;
|
||||
int g = *palette++;
|
||||
int b = *palette++;
|
||||
|
||||
translate[i] = I_GetNearestColor(playpal, r, g, b);
|
||||
}
|
||||
|
||||
roller = image;
|
||||
|
||||
for (int i = 0; i < indexed_size; ++i)
|
||||
{
|
||||
int r = *roller++;
|
||||
int g = *roller++;
|
||||
int b = *roller++;
|
||||
|
||||
indexed_image[i] = translate[GetPaletteIndex(r, g, b)];
|
||||
}
|
||||
|
||||
free(image);
|
||||
@ -412,6 +513,8 @@ static boolean DecodePNG(png_t *png)
|
||||
int indexed_size = image_size / 4;
|
||||
byte *indexed_image = malloc(indexed_size);
|
||||
|
||||
uniform_quantizer_t q = {0};
|
||||
|
||||
byte *roller = image;
|
||||
|
||||
byte used_colors[256] = {0};
|
||||
@ -423,22 +526,34 @@ static boolean DecodePNG(png_t *png)
|
||||
int g = *roller++;
|
||||
int b = *roller++;
|
||||
int a = *roller++;
|
||||
|
||||
if (a < 255)
|
||||
{
|
||||
has_alpha = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
byte c = I_GetPaletteIndex(playpal, r, g, b);
|
||||
used_colors[c] = 1;
|
||||
indexed_image[i] = c;
|
||||
AddColor(&q, r, g, b);
|
||||
}
|
||||
|
||||
GetPalette(&q);
|
||||
|
||||
byte translate[256];
|
||||
byte *palette = q.palette;
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
int r = *palette++;
|
||||
int g = *palette++;
|
||||
int b = *palette++;
|
||||
|
||||
byte c = I_GetNearestColor(playpal, r, g, b);
|
||||
used_colors[c] = 1;
|
||||
translate[i] = c;
|
||||
}
|
||||
|
||||
int color_key = NO_COLOR_KEY;
|
||||
|
||||
if (has_alpha)
|
||||
{
|
||||
int color_key = NO_COLOR_KEY;
|
||||
|
||||
for (int i = 0; i < 256; ++i)
|
||||
{
|
||||
if (used_colors[i] == 0)
|
||||
@ -447,20 +562,24 @@ static boolean DecodePNG(png_t *png)
|
||||
break;
|
||||
}
|
||||
}
|
||||
png->color_key = color_key;
|
||||
}
|
||||
|
||||
if (color_key != NO_COLOR_KEY)
|
||||
roller = image;
|
||||
|
||||
for (int i = 0; i < indexed_size; ++i)
|
||||
{
|
||||
int r = *roller++;
|
||||
int g = *roller++;
|
||||
int b = *roller++;
|
||||
int a = *roller++;
|
||||
if (a < 255)
|
||||
{
|
||||
roller = image;
|
||||
for (int i = 0; i < indexed_size; ++i)
|
||||
{
|
||||
roller += 3;
|
||||
if (*roller++ < 255)
|
||||
{
|
||||
indexed_image[i] = color_key;
|
||||
}
|
||||
}
|
||||
png->color_key = color_key;
|
||||
indexed_image[i] = color_key;
|
||||
continue;
|
||||
}
|
||||
|
||||
indexed_image[i] = translate[GetPaletteIndex(r, g, b)];
|
||||
}
|
||||
|
||||
free(image);
|
||||
@ -475,7 +594,7 @@ static boolean DecodePNG(png_t *png)
|
||||
|
||||
if (ret)
|
||||
{
|
||||
I_Printf(VB_ERROR, "DecodeImage: spng_get_plte %s\n",
|
||||
I_Printf(VB_ERROR, "DecodePNG: spng_get_plte %s\n",
|
||||
spng_strerror(ret));
|
||||
return false;
|
||||
}
|
||||
@ -500,7 +619,7 @@ static boolean DecodePNG(png_t *png)
|
||||
|
||||
need_translation = true;
|
||||
translate[i] =
|
||||
I_GetPaletteIndex(playpal, e->red, e->green, e->blue);
|
||||
I_GetNearestColor(playpal, e->red, e->green, e->blue);
|
||||
}
|
||||
|
||||
if (need_translation)
|
||||
|
@ -285,5 +285,5 @@ byte V_Colorize(byte *playpal, int cr, byte source)
|
||||
rgb.y *= 255.0;
|
||||
rgb.z *= 255.0;
|
||||
|
||||
return I_GetPaletteIndex(playpal, (int)rgb.x, (int)rgb.y, (int)rgb.z);
|
||||
return I_GetNearestColor(playpal, (int)rgb.x, (int)rgb.y, (int)rgb.z);
|
||||
}
|
||||
|
@ -200,8 +200,8 @@ void V_InitColorTranslation(void)
|
||||
cr_bright[i] = V_Colorize(playpal, CR_BRIGHT, (byte)i);
|
||||
}
|
||||
|
||||
v_lightest_color = I_GetPaletteIndex(playpal, 0xFF, 0xFF, 0xFF);
|
||||
v_darkest_color = I_GetPaletteIndex(playpal, 0x00, 0x00, 0x00);
|
||||
v_lightest_color = I_GetNearestColor(playpal, 0xFF, 0xFF, 0xFF);
|
||||
v_darkest_color = I_GetNearestColor(playpal, 0x00, 0x00, 0x00);
|
||||
|
||||
byte *palsrc = playpal;
|
||||
for (int i = 0; i < 256; ++i)
|
||||
@ -213,7 +213,7 @@ void V_InitColorTranslation(void)
|
||||
// formula is taken from dcolors.c preseving "Carmack's typo"
|
||||
// https://doomwiki.org/wiki/Carmack%27s_typo
|
||||
int gray = (red * 0.299 + green * 0.587 + blue * 0.144) * 255;
|
||||
invul_gray[i] = I_GetPaletteIndex(playpal, gray, gray, gray);
|
||||
invul_gray[i] = I_GetNearestColor(playpal, gray, gray, gray);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user