mirror of
https://git.do.srb2.org/STJr/SRB2.git
synced 2024-11-15 17:22:12 +00:00
Merge branch 'png-conversion-fixes' into 'pictureformats'
Optimize PNG conversion See merge request STJr/SRB2!1143
This commit is contained in:
commit
c2e6c0c0ad
5 changed files with 228 additions and 50 deletions
|
@ -499,20 +499,22 @@ static size_t gifframe_size = 8192;
|
||||||
// converts an RGB frame to a frame with a palette.
|
// converts an RGB frame to a frame with a palette.
|
||||||
//
|
//
|
||||||
#ifdef HWRENDER
|
#ifdef HWRENDER
|
||||||
|
static colorlookup_t gif_colorlookup;
|
||||||
|
|
||||||
static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr)
|
static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr)
|
||||||
{
|
{
|
||||||
UINT8 r, g, b;
|
UINT8 r, g, b;
|
||||||
size_t src = 0, dest = 0;
|
size_t src = 0, dest = 0;
|
||||||
size_t size = (vid.width * vid.height * 3);
|
size_t size = (vid.width * vid.height * 3);
|
||||||
|
|
||||||
InitColorLUT(gif_framepalette);
|
InitColorLUT(&gif_colorlookup, gif_framepalette, true);
|
||||||
|
|
||||||
while (src < size)
|
while (src < size)
|
||||||
{
|
{
|
||||||
r = (UINT8)linear[src];
|
r = (UINT8)linear[src];
|
||||||
g = (UINT8)linear[src + 1];
|
g = (UINT8)linear[src + 1];
|
||||||
b = (UINT8)linear[src + 2];
|
b = (UINT8)linear[src + 2];
|
||||||
scr[dest] = colorlookup[r >> SHIFTCOLORBITS][g >> SHIFTCOLORBITS][b >> SHIFTCOLORBITS];
|
scr[dest] = GetColorLUTDirect(&gif_colorlookup, r, g, b);
|
||||||
src += (3 * scrbuf_downscaleamt);
|
src += (3 * scrbuf_downscaleamt);
|
||||||
dest += scrbuf_downscaleamt;
|
dest += scrbuf_downscaleamt;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,10 @@
|
||||||
|
|
||||||
static unsigned char imgbuf[1<<26];
|
static unsigned char imgbuf[1<<26];
|
||||||
|
|
||||||
|
#ifdef PICTURE_PNG_USELOOKUP
|
||||||
|
static colorlookup_t png_colorlookup;
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Converts a picture between two formats.
|
/** Converts a picture between two formats.
|
||||||
*
|
*
|
||||||
* \param informat Input picture format.
|
* \param informat Input picture format.
|
||||||
|
@ -794,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);
|
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_structp png_ptr;
|
||||||
png_infop png_info_ptr;
|
png_infop png_info_ptr;
|
||||||
png_uint_32 width, height;
|
png_uint_32 width, height;
|
||||||
int bit_depth, color_type;
|
int bit_depth, color_type;
|
||||||
png_uint_32 y;
|
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 PNG_SETJMP_SUPPORTED
|
||||||
#ifdef USE_FAR_KEYWORD
|
#ifdef USE_FAR_KEYWORD
|
||||||
jmp_buf jmpbuf;
|
jmp_buf jmpbuf;
|
||||||
|
@ -860,10 +875,48 @@ static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffse
|
||||||
if (bit_depth == 16)
|
if (bit_depth == 16)
|
||||||
png_set_strip_16(png_ptr);
|
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)
|
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
|
||||||
png_set_gray_to_rgb(png_ptr);
|
png_set_gray_to_rgb(png_ptr);
|
||||||
else if (color_type == PNG_COLOR_TYPE_PALETTE)
|
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))
|
if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS))
|
||||||
png_set_tRNS_to_alpha(png_ptr);
|
png_set_tRNS_to_alpha(png_ptr);
|
||||||
|
@ -904,6 +957,7 @@ static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffse
|
||||||
|
|
||||||
*w = (INT32)width;
|
*w = (INT32)width;
|
||||||
*h = (INT32)height;
|
*h = (INT32)height;
|
||||||
|
|
||||||
return row_pointers;
|
return row_pointers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -931,12 +985,17 @@ void *Picture_PNGConvert(
|
||||||
INT32 outbpp;
|
INT32 outbpp;
|
||||||
size_t flatsize;
|
size_t flatsize;
|
||||||
png_uint_32 x, y;
|
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;
|
png_uint_32 width = *w, height = *h;
|
||||||
|
|
||||||
if (png == NULL)
|
if (png == NULL)
|
||||||
I_Error("Picture_PNGConvert: picture was 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
|
// Find the output format's bits per pixel amount
|
||||||
outbpp = Picture_FormatBPP(outformat);
|
outbpp = Picture_FormatBPP(outformat);
|
||||||
|
|
||||||
|
@ -964,39 +1023,124 @@ void *Picture_PNGConvert(
|
||||||
if (outbpp == PICDEPTH_8BPP)
|
if (outbpp == PICDEPTH_8BPP)
|
||||||
memset(flat, TRANSPARENTPIXEL, (width * height));
|
memset(flat, TRANSPARENTPIXEL, (width * height));
|
||||||
|
|
||||||
for (y = 0; y < height; y++)
|
#ifdef PICTURE_PNG_USELOOKUP
|
||||||
|
if (outbpp != PICDEPTH_32BPP)
|
||||||
|
InitColorLUT(&png_colorlookup, pMasterPalette, false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (outbpp == PICDEPTH_32BPP)
|
||||||
{
|
{
|
||||||
png_bytep row = row_pointers[y];
|
RGBA_t out;
|
||||||
for (x = 0; x < width; x++)
|
UINT32 *outflat = (UINT32 *)flat;
|
||||||
|
|
||||||
|
if (palette)
|
||||||
{
|
{
|
||||||
png_bytep px = &(row[x * 4]);
|
for (y = 0; y < height; y++)
|
||||||
if ((UINT8)px[3])
|
|
||||||
{
|
{
|
||||||
UINT8 red = (UINT8)px[0];
|
row = row_pointers[y];
|
||||||
UINT8 green = (UINT8)px[1];
|
for (x = 0; x < width; x++)
|
||||||
UINT8 blue = (UINT8)px[2];
|
|
||||||
UINT8 alpha = (UINT8)px[3];
|
|
||||||
if (outbpp == PICDEPTH_32BPP)
|
|
||||||
{
|
{
|
||||||
UINT32 *outflat = (UINT32 *)flat;
|
out = V_GetColor(row[x]);
|
||||||
RGBA_t out;
|
|
||||||
out.s.red = red;
|
|
||||||
out.s.green = green;
|
|
||||||
out.s.blue = blue;
|
|
||||||
out.s.alpha = alpha;
|
|
||||||
outflat[((y * width) + x)] = out.rgba;
|
outflat[((y * width) + x)] = out.rgba;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
row = row_pointers[y];
|
||||||
|
for (x = 0; x < width; x++)
|
||||||
{
|
{
|
||||||
UINT8 palidx = NearestColor(red, green, blue);
|
png_bytep px = &(row[x * 4]);
|
||||||
if (outbpp == PICDEPTH_16BPP)
|
if ((UINT8)px[3])
|
||||||
{
|
{
|
||||||
UINT16 *outflat = (UINT16 *)flat;
|
out.s.red = (UINT8)px[0];
|
||||||
outflat[((y * width) + x)] = (alpha << 8) | palidx;
|
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;
|
outflat[((y * width) + x)] = palidx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1005,6 +1149,8 @@ void *Picture_PNGConvert(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free the row pointers that we allocated for libpng.
|
// Free the row pointers that we allocated for libpng.
|
||||||
|
for (y = 0; y < height; y++)
|
||||||
|
free(row_pointers[y]);
|
||||||
free(row_pointers);
|
free(row_pointers);
|
||||||
|
|
||||||
// But wait, there's more!
|
// But wait, there's more!
|
||||||
|
|
|
@ -113,6 +113,8 @@ void *Picture_PNGConvert(
|
||||||
boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size);
|
boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define PICTURE_PNG_USELOOKUP
|
||||||
|
|
||||||
// SpriteInfo
|
// SpriteInfo
|
||||||
extern spriteinfo_t spriteinfo[NUMSPRITES];
|
extern spriteinfo_t spriteinfo[NUMSPRITES];
|
||||||
void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps);
|
void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps);
|
||||||
|
|
|
@ -3666,28 +3666,51 @@ Unoptimized version
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generates a color look-up table
|
// Generates a RGB565 color look-up table
|
||||||
// which has up to 64 colors at each channel
|
void InitColorLUT(colorlookup_t *lut, RGBA_t *palette, boolean makecolors)
|
||||||
// (see the defines in v_video.h)
|
|
||||||
|
|
||||||
UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE];
|
|
||||||
|
|
||||||
void InitColorLUT(RGBA_t *palette)
|
|
||||||
{
|
{
|
||||||
UINT8 r, g, b;
|
size_t palsize = (sizeof(RGBA_t) * 256);
|
||||||
static boolean clutinit = false;
|
|
||||||
static RGBA_t *lastpalette = NULL;
|
if (!lut->init || memcmp(lut->palette, palette, palsize))
|
||||||
if ((!clutinit) || (lastpalette != palette))
|
|
||||||
{
|
{
|
||||||
for (r = 0; r < CLUTSIZE; r++)
|
INT32 i;
|
||||||
for (g = 0; g < CLUTSIZE; g++)
|
|
||||||
for (b = 0; b < CLUTSIZE; b++)
|
lut->init = true;
|
||||||
colorlookup[r][g][b] = NearestPaletteColor(r << SHIFTCOLORBITS, g << SHIFTCOLORBITS, b << SHIFTCOLORBITS, palette);
|
memcpy(lut->palette, palette, palsize);
|
||||||
clutinit = true;
|
|
||||||
lastpalette = palette;
|
for (i = 0; i < 0xFFFF; i++)
|
||||||
|
lut->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 (lut->table[i] == 0xFFFF)
|
||||||
|
lut->table[i] = NearestPaletteColor(r, g, b, palette);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT8 GetColorLUT(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b)
|
||||||
|
{
|
||||||
|
INT32 i = CLUTINDEX(r, g, b);
|
||||||
|
if (lut->table[i] == 0xFFFF)
|
||||||
|
lut->table[i] = NearestPaletteColor(r, g, b, lut->palette);
|
||||||
|
return lut->table[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8 GetColorLUTDirect(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b)
|
||||||
|
{
|
||||||
|
INT32 i = CLUTINDEX(r, g, b);
|
||||||
|
return lut->table[i];
|
||||||
|
}
|
||||||
|
|
||||||
// V_Init
|
// V_Init
|
||||||
// old software stuff, buffers are allocated at video mode setup
|
// old software stuff, buffers are allocated at video mode setup
|
||||||
// here we set the screens[x] pointers accordingly
|
// here we set the screens[x] pointers accordingly
|
||||||
|
|
|
@ -38,13 +38,18 @@ cv_allcaps;
|
||||||
void V_Init(void);
|
void V_Init(void);
|
||||||
|
|
||||||
// Color look-up table
|
// Color look-up table
|
||||||
#define COLORBITS 6
|
#define CLUTINDEX(r, g, b) (((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3)
|
||||||
#define SHIFTCOLORBITS (8-COLORBITS)
|
|
||||||
#define CLUTSIZE (1<<COLORBITS)
|
|
||||||
|
|
||||||
extern UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE];
|
typedef struct
|
||||||
|
{
|
||||||
|
boolean init;
|
||||||
|
RGBA_t palette[256];
|
||||||
|
UINT16 table[0xFFFF];
|
||||||
|
} colorlookup_t;
|
||||||
|
|
||||||
void InitColorLUT(RGBA_t *palette);
|
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
|
// Set the current RGB palette lookup to use for palettized graphics
|
||||||
void V_SetPalette(INT32 palettenum);
|
void V_SetPalette(INT32 palettenum);
|
||||||
|
|
Loading…
Reference in a new issue