From f24647dc4df0cf70be7eb684fd30c2c68b237410 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 10 Sep 2020 01:43:46 -0300 Subject: [PATCH 1/3] Change method of color look-up table generation --- src/m_anigif.c | 4 ++-- src/v_video.c | 57 ++++++++++++++++++++++++++++++++++++-------------- src/v_video.h | 15 ++++++++----- 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/m_anigif.c b/src/m_anigif.c index 83bc3dddc..8113e20d8 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -505,14 +505,14 @@ static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr) size_t src = 0, dest = 0; size_t size = (vid.width * vid.height * 3); - InitColorLUT(gif_framepalette); + InitColorLUT(gif_framepalette, true); while (src < size) { r = (UINT8)linear[src]; g = (UINT8)linear[src + 1]; b = (UINT8)linear[src + 2]; - scr[dest] = colorlookup[r >> SHIFTCOLORBITS][g >> SHIFTCOLORBITS][b >> SHIFTCOLORBITS]; + scr[dest] = GetColorLUTDirect(r, g, b); src += (3 * scrbuf_downscaleamt); dest += scrbuf_downscaleamt; } diff --git a/src/v_video.c b/src/v_video.c index b88c4838b..3ac694dd4 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -3666,28 +3666,53 @@ Unoptimized version #endif } -// Generates a color look-up table -// which has up to 64 colors at each channel -// (see the defines in v_video.h) +// Generates a RGB565 color look-up table +static colorlookup_t colorlookup; -UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE]; - -void InitColorLUT(RGBA_t *palette) +void InitColorLUT(RGBA_t *palette, boolean makecolors) { - UINT8 r, g, b; - static boolean clutinit = false; - static RGBA_t *lastpalette = NULL; - if ((!clutinit) || (lastpalette != palette)) + size_t palsize = (sizeof(RGBA_t) * 256); + + if (!colorlookup.init || memcmp(colorlookup.palette, palette, palsize)) { - for (r = 0; r < CLUTSIZE; r++) - for (g = 0; g < CLUTSIZE; g++) - for (b = 0; b < CLUTSIZE; b++) - colorlookup[r][g][b] = NearestPaletteColor(r << SHIFTCOLORBITS, g << SHIFTCOLORBITS, b << SHIFTCOLORBITS, palette); - clutinit = true; - lastpalette = palette; + INT32 i; + + colorlookup.init = true; + memcpy(colorlookup.palette, palette, palsize); + + for (i = 0; i < 0xFFFF; i++) + colorlookup.table[i] = 0xFFFF; + + if (makecolors) + { + UINT8 r, g, b; + + for (r = 0; r < 0xFF; r++) + for (g = 0; g < 0xFF; g++) + for (b = 0; b < 0xFF; b++) + { + i = CLUTINDEX(r, g, b); + if (colorlookup.table[i] == 0xFFFF) + colorlookup.table[i] = NearestPaletteColor(r, g, b, palette); + } + } } } +UINT8 GetColorLUT(UINT8 r, UINT8 g, UINT8 b) +{ + INT32 i = CLUTINDEX(r, g, b); + if (colorlookup.table[i] == 0xFFFF) + colorlookup.table[i] = NearestPaletteColor(r << 3, g << 2, b << 3, colorlookup.palette); + return colorlookup.table[i]; +} + +UINT8 GetColorLUTDirect(UINT8 r, UINT8 g, UINT8 b) +{ + INT32 i = CLUTINDEX(r, g, b); + return colorlookup.table[i]; +} + // V_Init // old software stuff, buffers are allocated at video mode setup // here we set the screens[x] pointers accordingly diff --git a/src/v_video.h b/src/v_video.h index 9f7a9a9e9..6cd10f606 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -38,13 +38,18 @@ cv_allcaps; void V_Init(void); // Color look-up table -#define COLORBITS 6 -#define SHIFTCOLORBITS (8-COLORBITS) -#define CLUTSIZE (1<> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3) -extern UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE]; +void InitColorLUT(RGBA_t *palette, boolean makecolors); +UINT8 GetColorLUT(UINT8 r, UINT8 g, UINT8 b); +UINT8 GetColorLUTDirect(UINT8 r, UINT8 g, UINT8 b); -void InitColorLUT(RGBA_t *palette); +typedef struct +{ + boolean init; + RGBA_t palette[256]; + UINT16 table[0xFFFF]; +} colorlookup_t; // Set the current RGB palette lookup to use for palettized graphics void V_SetPalette(INT32 palettenum); From 4e437076c10fd3184c5320ccaa2ca2a53834aadb Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 10 Sep 2020 02:10:31 -0300 Subject: [PATCH 2/3] Use color look-up table for PNG conversion --- src/m_anigif.c | 6 ++++-- src/r_picformats.c | 13 +++++++++++++ src/r_picformats.h | 2 ++ src/v_video.c | 28 +++++++++++++--------------- src/v_video.h | 8 ++++---- 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/m_anigif.c b/src/m_anigif.c index 8113e20d8..7c2bb359e 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -499,20 +499,22 @@ static size_t gifframe_size = 8192; // converts an RGB frame to a frame with a palette. // #ifdef HWRENDER +static colorlookup_t gif_colorlookup; + static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr) { UINT8 r, g, b; size_t src = 0, dest = 0; size_t size = (vid.width * vid.height * 3); - InitColorLUT(gif_framepalette, true); + InitColorLUT(&gif_colorlookup, gif_framepalette, true); while (src < size) { r = (UINT8)linear[src]; g = (UINT8)linear[src + 1]; b = (UINT8)linear[src + 2]; - scr[dest] = GetColorLUTDirect(r, g, b); + scr[dest] = GetColorLUTDirect(&gif_colorlookup, r, g, b); src += (3 * scrbuf_downscaleamt); dest += scrbuf_downscaleamt; } diff --git a/src/r_picformats.c b/src/r_picformats.c index 39aaeef64..dbd090fc7 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -52,6 +52,10 @@ static unsigned char imgbuf[1<<26]; +#ifdef PICTURE_PNG_USELOOKUP +static colorlookup_t png_colorlookup; +#endif + /** Converts a picture between two formats. * * \param informat Input picture format. @@ -964,6 +968,11 @@ void *Picture_PNGConvert( if (outbpp == PICDEPTH_8BPP) memset(flat, TRANSPARENTPIXEL, (width * height)); +#ifdef PICTURE_PNG_USELOOKUP + if (outbpp != PICDEPTH_32BPP) + InitColorLUT(&png_colorlookup, pMasterPalette, false); +#endif + for (y = 0; y < height; y++) { png_bytep row = row_pointers[y]; @@ -988,7 +997,11 @@ void *Picture_PNGConvert( } else { +#ifdef PICTURE_PNG_USELOOKUP + UINT8 palidx = GetColorLUT(&png_colorlookup, red, green, blue); +#else UINT8 palidx = NearestColor(red, green, blue); +#endif if (outbpp == PICDEPTH_16BPP) { UINT16 *outflat = (UINT16 *)flat; diff --git a/src/r_picformats.h b/src/r_picformats.h index 58c84b2c8..32754d64e 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -113,6 +113,8 @@ void *Picture_PNGConvert( boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size); #endif +#define PICTURE_PNG_USELOOKUP + // SpriteInfo extern spriteinfo_t spriteinfo[NUMSPRITES]; void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps); diff --git a/src/v_video.c b/src/v_video.c index 3ac694dd4..26403b520 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -3667,21 +3667,19 @@ Unoptimized version } // Generates a RGB565 color look-up table -static colorlookup_t colorlookup; - -void InitColorLUT(RGBA_t *palette, boolean makecolors) +void InitColorLUT(colorlookup_t *lut, RGBA_t *palette, boolean makecolors) { size_t palsize = (sizeof(RGBA_t) * 256); - if (!colorlookup.init || memcmp(colorlookup.palette, palette, palsize)) + if (!lut->init || memcmp(lut->palette, palette, palsize)) { INT32 i; - colorlookup.init = true; - memcpy(colorlookup.palette, palette, palsize); + lut->init = true; + memcpy(lut->palette, palette, palsize); for (i = 0; i < 0xFFFF; i++) - colorlookup.table[i] = 0xFFFF; + lut->table[i] = 0xFFFF; if (makecolors) { @@ -3692,25 +3690,25 @@ void InitColorLUT(RGBA_t *palette, boolean makecolors) for (b = 0; b < 0xFF; b++) { i = CLUTINDEX(r, g, b); - if (colorlookup.table[i] == 0xFFFF) - colorlookup.table[i] = NearestPaletteColor(r, g, b, palette); + if (lut->table[i] == 0xFFFF) + lut->table[i] = NearestPaletteColor(r, g, b, palette); } } } } -UINT8 GetColorLUT(UINT8 r, UINT8 g, UINT8 b) +UINT8 GetColorLUT(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b) { INT32 i = CLUTINDEX(r, g, b); - if (colorlookup.table[i] == 0xFFFF) - colorlookup.table[i] = NearestPaletteColor(r << 3, g << 2, b << 3, colorlookup.palette); - return colorlookup.table[i]; + if (lut->table[i] == 0xFFFF) + lut->table[i] = NearestPaletteColor(r, g, b, lut->palette); + return lut->table[i]; } -UINT8 GetColorLUTDirect(UINT8 r, UINT8 g, UINT8 b) +UINT8 GetColorLUTDirect(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b) { INT32 i = CLUTINDEX(r, g, b); - return colorlookup.table[i]; + return lut->table[i]; } // V_Init diff --git a/src/v_video.h b/src/v_video.h index 6cd10f606..a6ca197bb 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -40,10 +40,6 @@ void V_Init(void); // Color look-up table #define CLUTINDEX(r, g, b) (((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3) -void InitColorLUT(RGBA_t *palette, boolean makecolors); -UINT8 GetColorLUT(UINT8 r, UINT8 g, UINT8 b); -UINT8 GetColorLUTDirect(UINT8 r, UINT8 g, UINT8 b); - typedef struct { boolean init; @@ -51,6 +47,10 @@ typedef struct UINT16 table[0xFFFF]; } colorlookup_t; +void InitColorLUT(colorlookup_t *lut, RGBA_t *palette, boolean makecolors); +UINT8 GetColorLUT(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b); +UINT8 GetColorLUTDirect(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b); + // Set the current RGB palette lookup to use for palettized graphics void V_SetPalette(INT32 palettenum); From 0750d273a6004ce73e9ce11f4b01c6eb7799b74e Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 10 Sep 2020 03:16:21 -0300 Subject: [PATCH 3/3] Attempt to use the PNG image's palette, if it is present --- src/r_picformats.c | 193 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 163 insertions(+), 30 deletions(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index dbd090fc7..d48bbaaf2 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -798,13 +798,24 @@ static void PNG_warn(png_structp PNG, png_const_charp pngtext) CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext); } -static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffset, INT16 *leftoffset, size_t size) +static png_bytep *PNG_Read( + const UINT8 *png, + INT32 *w, INT32 *h, INT16 *topoffset, INT16 *leftoffset, + boolean *use_palette, size_t size) { png_structp png_ptr; png_infop png_info_ptr; png_uint_32 width, height; int bit_depth, color_type; png_uint_32 y; + + png_colorp palette; + int palette_size; + + png_bytep trans; + int trans_num; + png_color_16p trans_values; + #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD jmp_buf jmpbuf; @@ -864,10 +875,48 @@ static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffse if (bit_depth == 16) png_set_strip_16(png_ptr); + palette = NULL; + *use_palette = false; + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); else if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png_ptr); + { + boolean usepal = false; + + // Lactozilla: Check if the PNG has a palette, and if its color count + // matches the color count of SRB2's palette: 256 colors. + if (png_get_PLTE(png_ptr, png_info_ptr, &palette, &palette_size)) + { + if (palette_size == 256) + usepal = true; + } + + // If any of the tRNS colors have an alpha lower than 0xFF, and that + // color is present on the image, the palette flag is disabled. + png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values); + + if (trans_num == 256) + { + int i; + for (i = 0; i < trans_num; i++) + { + // libpng will transform this image into RGB even if + // the transparent index does not exist in the image, + // and there is no way around that. + if (trans[i] < 0xFF) + { + usepal = false; + break; + } + } + } + + if (usepal) + *use_palette = true; + else + png_set_palette_to_rgb(png_ptr); + } if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); @@ -908,6 +957,7 @@ static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffse *w = (INT32)width; *h = (INT32)height; + return row_pointers; } @@ -935,12 +985,17 @@ void *Picture_PNGConvert( INT32 outbpp; size_t flatsize; png_uint_32 x, y; - png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, insize); + png_bytep row; + boolean palette = false; + png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, &palette, insize); png_uint_32 width = *w, height = *h; if (png == NULL) I_Error("Picture_PNGConvert: picture was NULL!"); + if (row_pointers == NULL) + I_Error("Picture_PNGConvert: row_pointers was NULL!"); + // Find the output format's bits per pixel amount outbpp = Picture_FormatBPP(outformat); @@ -973,43 +1028,119 @@ void *Picture_PNGConvert( InitColorLUT(&png_colorlookup, pMasterPalette, false); #endif - for (y = 0; y < height; y++) + if (outbpp == PICDEPTH_32BPP) { - png_bytep row = row_pointers[y]; - for (x = 0; x < width; x++) + RGBA_t out; + UINT32 *outflat = (UINT32 *)flat; + + if (palette) { - png_bytep px = &(row[x * 4]); - if ((UINT8)px[3]) + for (y = 0; y < height; y++) { - UINT8 red = (UINT8)px[0]; - UINT8 green = (UINT8)px[1]; - UINT8 blue = (UINT8)px[2]; - UINT8 alpha = (UINT8)px[3]; - if (outbpp == PICDEPTH_32BPP) + row = row_pointers[y]; + for (x = 0; x < width; x++) { - UINT32 *outflat = (UINT32 *)flat; - RGBA_t out; - out.s.red = red; - out.s.green = green; - out.s.blue = blue; - out.s.alpha = alpha; + out = V_GetColor(row[x]); outflat[((y * width) + x)] = out.rgba; } - else + } + } + else + { + for (y = 0; y < height; y++) + { + row = row_pointers[y]; + for (x = 0; x < width; x++) { -#ifdef PICTURE_PNG_USELOOKUP - UINT8 palidx = GetColorLUT(&png_colorlookup, red, green, blue); -#else - UINT8 palidx = NearestColor(red, green, blue); -#endif - if (outbpp == PICDEPTH_16BPP) + png_bytep px = &(row[x * 4]); + if ((UINT8)px[3]) { - UINT16 *outflat = (UINT16 *)flat; - outflat[((y * width) + x)] = (alpha << 8) | palidx; + out.s.red = (UINT8)px[0]; + out.s.green = (UINT8)px[1]; + out.s.blue = (UINT8)px[2]; + out.s.alpha = (UINT8)px[3]; + outflat[((y * width) + x)] = out.rgba; } - else // 8bpp + else + outflat[((y * width) + x)] = 0x00000000; + } + } + } + } + else if (outbpp == PICDEPTH_16BPP) + { + UINT16 *outflat = (UINT16 *)flat; + + if (palette) + { + for (y = 0; y < height; y++) + { + row = row_pointers[y]; + for (x = 0; x < width; x++) + outflat[((y * width) + x)] = (0xFF << 8) | row[x]; + } + } + else + { + for (y = 0; y < height; y++) + { + row = row_pointers[y]; + for (x = 0; x < width; x++) + { + png_bytep px = &(row[x * 4]); + UINT8 red = (UINT8)px[0]; + UINT8 green = (UINT8)px[1]; + UINT8 blue = (UINT8)px[2]; + UINT8 alpha = (UINT8)px[3]; + + if (alpha) { - UINT8 *outflat = (UINT8 *)flat; +#ifdef PICTURE_PNG_USELOOKUP + UINT8 palidx = GetColorLUT(&png_colorlookup, red, green, blue); +#else + UINT8 palidx = NearestColor(red, green, blue); +#endif + outflat[((y * width) + x)] = (0xFF << 8) | palidx; + } + else + outflat[((y * width) + x)] = 0x0000; + } + } + } + } + else // 8bpp + { + UINT8 *outflat = (UINT8 *)flat; + + if (palette) + { + for (y = 0; y < height; y++) + { + row = row_pointers[y]; + for (x = 0; x < width; x++) + outflat[((y * width) + x)] = row[x]; + } + } + else + { + for (y = 0; y < height; y++) + { + row = row_pointers[y]; + for (x = 0; x < width; x++) + { + png_bytep px = &(row[x * 4]); + UINT8 red = (UINT8)px[0]; + UINT8 green = (UINT8)px[1]; + UINT8 blue = (UINT8)px[2]; + UINT8 alpha = (UINT8)px[3]; + + if (alpha) + { +#ifdef PICTURE_PNG_USELOOKUP + UINT8 palidx = GetColorLUT(&png_colorlookup, red, green, blue); +#else + UINT8 palidx = NearestColor(red, green, blue); +#endif outflat[((y * width) + x)] = palidx; } } @@ -1018,6 +1149,8 @@ void *Picture_PNGConvert( } // Free the row pointers that we allocated for libpng. + for (y = 0; y < height; y++) + free(row_pointers[y]); free(row_pointers); // But wait, there's more!