mirror of
https://github.com/fabiangreffrath/woof.git
synced 2025-09-27 23:22:06 -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)
|
if (mapcolor_preset == AM_PRESET_CRISPY)
|
||||||
{
|
{
|
||||||
byte *playpal = W_CacheLumpName("PLAYPAL", PU_CACHE);
|
byte *playpal = W_CacheLumpName("PLAYPAL", PU_CACHE);
|
||||||
mapcolor_secr = I_GetPaletteIndex(playpal, 255, 0, 255);
|
mapcolor_secr = I_GetNearestColor(playpal, 255, 0, 255);
|
||||||
mapcolor_revsecr = I_GetPaletteIndex(playpal, 119, 255, 111);
|
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
|
// 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;
|
byte best;
|
||||||
int best_diff, diff;
|
int best_diff, diff;
|
||||||
|
@ -82,7 +82,7 @@ extern boolean correct_aspect_ratio;
|
|||||||
extern boolean screenvisible;
|
extern boolean screenvisible;
|
||||||
|
|
||||||
extern int gamma2;
|
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
|
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 r = *p++;
|
||||||
int g = *p++;
|
int g = *p++;
|
||||||
int b = *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
|
// 0 is transparent, last is border color
|
||||||
|
@ -111,7 +111,7 @@ static byte R_SkyBlendColor(int tex)
|
|||||||
b = colors[width/3].b;
|
b = colors[width/3].b;
|
||||||
Z_Free(colors);
|
Z_Free(colors);
|
||||||
|
|
||||||
return I_GetPaletteIndex(pal, r, g, b);
|
return I_GetNearestColor(pal, r, g, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct skycolor_s
|
typedef struct skycolor_s
|
||||||
|
@ -370,7 +370,7 @@ static void ST_DrawSolidBackground(int st_x)
|
|||||||
b /= 2 * depth * (v1 - v0);
|
b /= 2 * depth * (v1 - v0);
|
||||||
|
|
||||||
// [FG] tune down to half saturation (for empiric reasons)
|
// [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);
|
V_FillRect(0, v0, video.unscaledw, v1 - v0, col);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ void V_InitFlexTranTable(void)
|
|||||||
{
|
{
|
||||||
for (b = 0; b < 32; ++b)
|
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));
|
MAKECOLOR(g), MAKECOLOR(b));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
169
src/v_fmt.c
169
src/v_fmt.c
@ -268,6 +268,82 @@ static void *DummyFlat(int lump, pu_tag tag)
|
|||||||
return lumpcache[lump];
|
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
|
typedef struct
|
||||||
{
|
{
|
||||||
spng_ctx *ctx;
|
spng_ctx *ctx;
|
||||||
@ -340,8 +416,7 @@ static boolean DecodePNG(png_t *png)
|
|||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
{
|
{
|
||||||
I_Printf(VB_ERROR, "DecodeImage: spng_get_ihdr %s\n",
|
I_Printf(VB_ERROR, "DecodePNG: spng_get_ihdr %s\n", spng_strerror(ret));
|
||||||
spng_strerror(ret));
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,7 +443,7 @@ static boolean DecodePNG(png_t *png)
|
|||||||
|
|
||||||
if (ret)
|
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));
|
spng_strerror(ret));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -378,7 +453,7 @@ static boolean DecodePNG(png_t *png)
|
|||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
{
|
{
|
||||||
I_Printf(VB_ERROR, "DecodeImage: spng_decode_image %s",
|
I_Printf(VB_ERROR, "DecodePNG: spng_decode_image %s",
|
||||||
spng_strerror(ret));
|
spng_strerror(ret));
|
||||||
free(image);
|
free(image);
|
||||||
return false;
|
return false;
|
||||||
@ -391,6 +466,8 @@ static boolean DecodePNG(png_t *png)
|
|||||||
int indexed_size = image_size / 3;
|
int indexed_size = image_size / 3;
|
||||||
byte *indexed_image = malloc(indexed_size);
|
byte *indexed_image = malloc(indexed_size);
|
||||||
|
|
||||||
|
uniform_quantizer_t q = {0};
|
||||||
|
|
||||||
byte *roller = image;
|
byte *roller = image;
|
||||||
|
|
||||||
for (int i = 0; i < indexed_size; ++i)
|
for (int i = 0; i < indexed_size; ++i)
|
||||||
@ -399,7 +476,31 @@ static boolean DecodePNG(png_t *png)
|
|||||||
int g = *roller++;
|
int g = *roller++;
|
||||||
int b = *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);
|
free(image);
|
||||||
@ -412,6 +513,8 @@ static boolean DecodePNG(png_t *png)
|
|||||||
int indexed_size = image_size / 4;
|
int indexed_size = image_size / 4;
|
||||||
byte *indexed_image = malloc(indexed_size);
|
byte *indexed_image = malloc(indexed_size);
|
||||||
|
|
||||||
|
uniform_quantizer_t q = {0};
|
||||||
|
|
||||||
byte *roller = image;
|
byte *roller = image;
|
||||||
|
|
||||||
byte used_colors[256] = {0};
|
byte used_colors[256] = {0};
|
||||||
@ -423,22 +526,34 @@ static boolean DecodePNG(png_t *png)
|
|||||||
int g = *roller++;
|
int g = *roller++;
|
||||||
int b = *roller++;
|
int b = *roller++;
|
||||||
int a = *roller++;
|
int a = *roller++;
|
||||||
|
|
||||||
if (a < 255)
|
if (a < 255)
|
||||||
{
|
{
|
||||||
has_alpha = true;
|
has_alpha = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte c = I_GetPaletteIndex(playpal, r, g, b);
|
AddColor(&q, r, g, b);
|
||||||
used_colors[c] = 1;
|
|
||||||
indexed_image[i] = c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
if (has_alpha)
|
||||||
{
|
{
|
||||||
int color_key = NO_COLOR_KEY;
|
|
||||||
|
|
||||||
for (int i = 0; i < 256; ++i)
|
for (int i = 0; i < 256; ++i)
|
||||||
{
|
{
|
||||||
if (used_colors[i] == 0)
|
if (used_colors[i] == 0)
|
||||||
@ -447,20 +562,24 @@ static boolean DecodePNG(png_t *png)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (color_key != NO_COLOR_KEY)
|
|
||||||
{
|
|
||||||
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;
|
png->color_key = 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)
|
||||||
|
{
|
||||||
|
indexed_image[i] = color_key;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
indexed_image[i] = translate[GetPaletteIndex(r, g, b)];
|
||||||
}
|
}
|
||||||
|
|
||||||
free(image);
|
free(image);
|
||||||
@ -475,7 +594,7 @@ static boolean DecodePNG(png_t *png)
|
|||||||
|
|
||||||
if (ret)
|
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));
|
spng_strerror(ret));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -500,7 +619,7 @@ static boolean DecodePNG(png_t *png)
|
|||||||
|
|
||||||
need_translation = true;
|
need_translation = true;
|
||||||
translate[i] =
|
translate[i] =
|
||||||
I_GetPaletteIndex(playpal, e->red, e->green, e->blue);
|
I_GetNearestColor(playpal, e->red, e->green, e->blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_translation)
|
if (need_translation)
|
||||||
|
@ -285,5 +285,5 @@ byte V_Colorize(byte *playpal, int cr, byte source)
|
|||||||
rgb.y *= 255.0;
|
rgb.y *= 255.0;
|
||||||
rgb.z *= 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);
|
cr_bright[i] = V_Colorize(playpal, CR_BRIGHT, (byte)i);
|
||||||
}
|
}
|
||||||
|
|
||||||
v_lightest_color = I_GetPaletteIndex(playpal, 0xFF, 0xFF, 0xFF);
|
v_lightest_color = I_GetNearestColor(playpal, 0xFF, 0xFF, 0xFF);
|
||||||
v_darkest_color = I_GetPaletteIndex(playpal, 0x00, 0x00, 0x00);
|
v_darkest_color = I_GetNearestColor(playpal, 0x00, 0x00, 0x00);
|
||||||
|
|
||||||
byte *palsrc = playpal;
|
byte *palsrc = playpal;
|
||||||
for (int i = 0; i < 256; ++i)
|
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"
|
// formula is taken from dcolors.c preseving "Carmack's typo"
|
||||||
// https://doomwiki.org/wiki/Carmack%27s_typo
|
// https://doomwiki.org/wiki/Carmack%27s_typo
|
||||||
int gray = (red * 0.299 + green * 0.587 + blue * 0.144) * 255;
|
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