- Added support for truecolor PNG textures. They still get resampled to the

global palette, but at least they are visible now.
- Optimized UnfilterRow() in m_png.cpp a little.


SVN r291 (trunk)
This commit is contained in:
Randy Heit 2006-08-13 03:38:18 +00:00
parent 8ecfe6a8ac
commit 89396964f5
3 changed files with 195 additions and 59 deletions

View file

@ -1,3 +1,8 @@
August 12, 2006
- Added support for truecolor PNG textures. They still get resampled to the
global palette, but at least they are visible now.
- Optimized UnfilterRow() in m_png.cpp a little.
August 11, 2006 (Changes by Graf Zahl)
- Fixed: P_CheckOnMobjZ returned the first thing an actor could stand on,
not the highest possible.

View file

@ -99,7 +99,7 @@ static inline void MakeChunk (void *where, DWORD type, size_t len);
static inline void StuffPalette (const PalEntry *from, BYTE *to);
static bool StuffBitmap (const DCanvas *canvas, FILE *file);
static bool WriteIDAT (FILE *file, const BYTE *data, int len);
static void UnfilterRow (int width, BYTE *dest, BYTE *stream, BYTE *prev);
static void UnfilterRow (int width, BYTE *dest, BYTE *stream, BYTE *prev, int bpp);
static void UnpackPixels (int width, int bytesPerRow, int bitdepth, BYTE *row);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
@ -532,17 +532,30 @@ bool M_ReadIDAT (FileReader *file, BYTE *buffer, int width, int height, int pitc
int y;
bool lastIDAT;
int bytesPerRowIn;
int bytesPerPixel;
inputLine = (Byte *)alloca (1+width*2);
prev = inputLine + 1 + width;
memset (prev, 0, width);
switch (colortype)
{
case 2: bytesPerPixel = 3; break; // RGB
case 4: bytesPerPixel = 2; break; // LA
case 6: bytesPerPixel = 4; break; // RGBA
default: bytesPerPixel = 1; break;
}
inputLine = (Byte *)alloca (1 + width*bytesPerPixel*2);
prev = inputLine + 1 + width*bytesPerPixel;
memset (prev, 0, width*bytesPerPixel);
if (bytesPerPixel == 1 && bitdepth != 8)
{ // This is an invalid combination for PNG files
return false;
}
switch (bitdepth)
{
case 8: bytesPerRowIn = width; break;
case 4: bytesPerRowIn = (width+1)/2; break;
case 2: bytesPerRowIn = (width+3)/4; break;
case 1: bytesPerRowIn = (width+7)/8; break;
case 8: bytesPerRowIn = width * bytesPerPixel; break;
case 4: bytesPerRowIn = (width+1)/2; break;
case 2: bytesPerRowIn = (width+3)/4; break;
case 1: bytesPerRowIn = (width+7)/8; break;
default: return false;
}
@ -581,7 +594,7 @@ bool M_ReadIDAT (FileReader *file, BYTE *buffer, int width, int height, int pitc
if (stream.avail_out == 0)
{
UnfilterRow (bytesPerRowIn, curr, inputLine, prev);
UnfilterRow (bytesPerRowIn, curr, inputLine, prev, bytesPerPixel);
prev = curr;
curr += pitch;
y++;
@ -800,51 +813,77 @@ static bool WriteIDAT (FILE *file, const BYTE *data, int len)
// UnfilterRow
//
// Unfilters the given row. Unknown filter types are silently ignored.
// bpp is bytes per pixel, not bits per pixel.
// width is in bytes, not pixels.
//
//==========================================================================
void UnfilterRow (int width, BYTE *dest, BYTE *row, BYTE *prev)
void UnfilterRow (int width, BYTE *dest, BYTE *row, BYTE *prev, int bpp)
{
int x;
switch (*row++)
{
case 1: // Sub
dest[0] = row[0];
for (x = 1; x < width; ++x)
x = bpp;
do
{
dest[x] = row[x] + dest[x-1];
*dest++ = *row++;
}
while (--x);
for (x = width - bpp; x > 0; --x)
{
*dest = *row++ + *(dest - bpp);
dest++;
}
break;
case 2: // Up
for (x = 0; x < width; ++x)
x = width;
do
{
dest[x] = row[x] + prev[x];
*dest++ = *row++ + *prev++;
}
while (--x);
break;
case 3: // Average
dest[0] = row[0] + prev[0]/2;
for (x = 1; x < width; ++x)
x = bpp;
do
{
dest[x] = row[x] + (BYTE)(((unsigned)dest[x-1] + (unsigned)prev[x])/2);
*dest++ = *row++ + (*prev++)/2;
}
while (--x);
for (x = width - bpp; x > 0; --x)
{
*dest = *row++ + (BYTE)((unsigned(*(dest - bpp)) + unsigned(*prev++)) >> 1);
dest++;
}
break;
case 4: // Paeth
dest[0] = row[0] + prev[0];
for (x = 1; x < width; ++x)
x = bpp;
do
{
*dest++ = *row++ + *prev++;
}
while (--x);
for (x = width - bpp; x > 0; --x)
{
int a, b, c, pa, pb, pc;
a = dest[x-1];
b = prev[x];
c = prev[x-1];
pa = abs (b - c);
pb = abs (a - c);
pc = abs (a + b - c - c);
dest[x] = row[x] + (BYTE)((pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c);
a = *(dest - bpp);
b = *(prev);
c = *(prev - bpp);
pa = b - c;
pb = a - c;
pc = abs (pa + pb);
pa = abs (pa);
pb = abs (pb);
*dest = *row + (BYTE)((pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c);
dest++;
row++;
prev++;
}
break;

View file

@ -279,7 +279,11 @@ int FTextureManager::CreateTexture (int lumpnum, int usetype)
{
return -1;
}
if (colortype != 0 && colortype != 3)
if (!((1 << colortype) & 0x5D))
{
return -1;
}
if (!((1 << bitdepth) & 0x116))
{
return -1;
}
@ -1853,21 +1857,13 @@ FPNGTexture::FPNGTexture (int lumpnum, int width, int height,
}
StartOfIDAT = lump.Tell() - 8;
if (colortype == 3)
{
PaletteMap = new BYTE[PaletteSize];
GPalette.MakeRemap (palette, PaletteMap, trans, PaletteSize);
for (i = 0; i < PaletteSize; ++i)
{
if (trans[i] == 0)
{
bMasked = true;
PaletteMap[i] = 0;
}
}
}
else if (colortype == 0)
switch (colortype)
{
case 4: // Grayscale + Alpha
bMasked = true;
// intentional fall-through
case 0: // Grayscale
if (!bAlphaTexture)
{
if (GrayMap[0] == GrayMap[255])
@ -1877,7 +1873,7 @@ FPNGTexture::FPNGTexture (int lumpnum, int width, int height,
GrayMap[i] = ColorMatcher.Pick (i, i, i);
}
}
if (havetRNS && trans[0] != 0)
if (colortype == 0 && havetRNS && trans[0] != 0)
{
bMasked = true;
PaletteSize = 256;
@ -1890,6 +1886,24 @@ FPNGTexture::FPNGTexture (int lumpnum, int width, int height,
PaletteMap = GrayMap;
}
}
break;
case 3: // Paletted
PaletteMap = new BYTE[PaletteSize];
GPalette.MakeRemap (palette, PaletteMap, trans, PaletteSize);
for (i = 0; i < PaletteSize; ++i)
{
if (trans[i] == 0)
{
bMasked = true;
PaletteMap[i] = 0;
}
}
break;
case 6: // RGB + Alpha
bMasked = true;
break;
}
}
@ -1964,33 +1978,111 @@ void FPNGTexture::MakeTexture ()
DWORD len, id;
lump.Seek (StartOfIDAT, SEEK_SET);
lump >> len >> id;
M_ReadIDAT (&lump, Pixels, Width, Height, Width, BitDepth, ColorType, Interlace, BigLong((unsigned int)len));
if (Width == Height)
if (ColorType == 0 || ColorType == 3) /* Grayscale and paletted */
{
if (PaletteMap != NULL)
M_ReadIDAT (&lump, Pixels, Width, Height, Width, BitDepth, ColorType, Interlace, BigLong((unsigned int)len));
if (Width == Height)
{
FlipSquareBlockRemap (Pixels, Width, Height, PaletteMap);
if (PaletteMap != NULL)
{
FlipSquareBlockRemap (Pixels, Width, Height, PaletteMap);
}
else
{
FlipSquareBlock (Pixels, Width, Height);
}
}
else
{
FlipSquareBlock (Pixels, Width, Height);
BYTE *newpix = new BYTE[Width*Height];
if (PaletteMap != NULL)
{
FlipNonSquareBlockRemap (newpix, Pixels, Width, Height, PaletteMap);
}
else
{
FlipNonSquareBlock (newpix, Pixels, Width, Height, Width);
}
BYTE *oldpix = Pixels;
Pixels = newpix;
delete[] oldpix;
}
}
else
else /* RGB and/or Alpha present */
{
BYTE *newpix = new BYTE[Width*Height];
if (PaletteMap != NULL)
int bytesPerPixel = ColorType == 2 ? 3 : ColorType == 4 ? 2 : 4;
BYTE *tempix = new BYTE[Width * Height * bytesPerPixel];
BYTE *in, *out;
int x, y, pitch, backstep;
M_ReadIDAT (&lump, tempix, Width, Height, Width*bytesPerPixel, BitDepth, ColorType, Interlace, BigLong((unsigned int)len));
in = tempix;
out = Pixels;
// Convert from source format to paletted, column-major.
// Formats with alpha maps are reduced to only 1 bit of alpha.
switch (ColorType)
{
FlipNonSquareBlockRemap (newpix, Pixels, Width, Height, PaletteMap);
case 2: // RGB
pitch = Width * 3;
backstep = Height * pitch - 3;
for (x = Width; x > 0; --x)
{
for (y = Height; y > 0; --y)
{
*out++ = RGB32k[in[0]>>3][in[1]>>3][in[2]>>3];
in += pitch;
}
in -= backstep;
}
break;
case 4: // Grayscale + Alpha
pitch = Width * 2;
backstep = Height * pitch - 2;
if (PaletteMap != NULL)
{
for (x = Width; x > 0; --x)
{
for (y = Height; y > 0; --y)
{
*out++ = in[1] < 128 ? 0 : PaletteMap[in[0]];
in += pitch;
}
in -= backstep;
}
}
else
{
for (x = Width; x > 0; --x)
{
for (y = Height; y > 0; --y)
{
*out++ = in[1] < 128 ? 0 : in[0];
in += pitch;
}
in -= backstep;
}
}
break;
case 6: // RGB + Alpha
pitch = Width * 4;
backstep = Height * pitch - 4;
for (x = Width; x > 0; --x)
{
for (y = Height; y > 0; --y)
{
*out++ = in[3] < 128 ? 0 : RGB32k[in[0]>>3][in[1]>>3][in[2]>>3];
in += pitch;
}
in -= backstep;
}
break;
}
else
{
FlipNonSquareBlock (newpix, Pixels, Width, Height, Width);
}
BYTE *oldpix = Pixels;
Pixels = newpix;
delete[] oldpix;
delete[] tempix;
}
}
if (Spans == NULL)