- Added JPEG texture support, courtesy of Ken's Picture Library. I will

probably switch to the IJG library once I pare it down. (Ken's code is 18K
  of C source but does not support progressive JPEG. The IJG library is over
  a megabyte of source and supports pretty much everything you would ever
  need ever.)
- Fixed endianness issue in FTextureManager::CreateTexture().
- Added support for interlaced PNGs. Now ZDoom is a mostly complete PNG
  reader. The only thing missing is 48-bit RGB and 16-bit grayscale support,
  which are just wastes of bits here, but also less likely to appear than
  an interlaced PNG. (However, if you are using interlaced PNGs for textures,
  then you are needlessly wasting space, since the image won't display
  progressively.)
- Fixed: Writing named screenshots didn't work.

SVN r292 (trunk)
This commit is contained in:
Randy Heit 2006-08-15 04:34:35 +00:00
parent 89396964f5
commit 21869a6c08
9 changed files with 941 additions and 94 deletions

View File

@ -1,3 +1,18 @@
August 14, 2006
- Added JPEG texture support, courtesy of Ken's Picture Library. I will
probably switch to the IJG library once I pare it down. (Ken's code is 18K
of C source but does not support progressive JPEG. The IJG library is over
a megabyte of source and supports pretty much everything you would ever
need ever.)
- Fixed endianness issue in FTextureManager::CreateTexture().
- Added support for interlaced PNGs. Now ZDoom is a mostly complete PNG
reader. The only thing missing is 48-bit RGB and 16-bit grayscale support,
which are just wastes of bits here, but also less likely to appear than
an interlaced PNG. (However, if you are using interlaced PNGs for textures,
then you are needlessly wasting space, since the image won't display
progressively.)
- Fixed: Writing named screenshots didn't work.
August 12, 2006
- Added support for truecolor PNG textures. They still get resampled to the
global palette, but at least they are visible now.

View File

@ -187,7 +187,7 @@ FString savegamefile;
char savedescription[SAVESTRINGSIZE];
// [RH] Name of screenshot file to generate (usually NULL)
char *shotfile;
FString shotfile;
AActor* bodyque[BODYQUESIZE];
int bodyqueslot;
@ -890,11 +890,7 @@ void G_Ticker ()
break;
case ga_screenshot:
M_ScreenShot (shotfile);
if (shotfile)
{
free (shotfile);
shotfile = NULL;
}
shotfile = "";
gameaction = ga_nothing;
break;
case ga_fullconsole:

571
src/kplib.cpp Normal file
View File

@ -0,0 +1,571 @@
/**************************************************************************************************
KPLIB.C: Ken's Picture LIBrary written by Ken Silverman
Copyright (c) 1998-2005 Ken Silverman
Ken Silverman's official web site: http://www.advsys.net/ken
This source file includes routines for decompression of the following picture formats:
JPG,PNG,GIF,PCX,TGA,BMP,CEL
It also includes code to handle ZIP decompression.
Brief history:
1998?: Wrote KPEG, a JPEG viewer for DOS
2000: Wrote KPNG, a PNG viewer for DOS
2001: Combined KPEG&KPNG, ported to Visual C, and made it into a nice library called KPLIB.C
2002: Added support for: TGA,GIF,CEL,ZIP
2003: Added support for: BMP
05/18/2004: Added support for 8/24 bit PCX
I offer this code to the community for the benefit of Jonathon Fowler's Duke3D port.
-Ken S.
**************************************************************************************************/
// [RH] Removed everything but JPEG support.
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include "m_swap.h"
#include "m_fixed.h"
#if !defined(_WIN32) && !defined(__DOS__)
#include <unistd.h>
static __inline unsigned long _lrotl (unsigned long i, int sh)
{ return((i>>(-sh))|(i<<sh)); }
#define _fileno fileno
#else
#include <io.h>
#endif
#if !defined(max)
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#if !defined(min)
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#if defined(__GNUC__)
#define _inline inline
#endif
//use GCC-specific extension to force symbol name to be something in particular to override underscoring.
static int bytesperline, xres, yres, globxoffs, globyoffs;
static unsigned char *frameplace;
static const int pow2mask[32] =
{
0x00000000,0x00000001,0x00000003,0x00000007,
0x0000000f,0x0000001f,0x0000003f,0x0000007f,
0x000000ff,0x000001ff,0x000003ff,0x000007ff,
0x00000fff,0x00001fff,0x00003fff,0x00007fff,
0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff,
0x000fffff,0x001fffff,0x003fffff,0x007fffff,
0x00ffffff,0x01ffffff,0x03ffffff,0x07ffffff,
0x0fffffff,0x1fffffff,0x3fffffff,0x7fffffff,
};
//Initialized tables (can't be in union)
//jpg: png:
// crmul 16384 abstab10 4096
// cbmul 16384 hxbit 472
// dct 4608 pow2mask 128*
// colclip 4096
// colclipup8 4096
// colclipup16 4096
// unzig 256
// pow2mask 128*
// dcflagor 64
int palcol[256], paleng;
unsigned char coltype, bitdepth;
//============================ KPEGILIB begins ===============================
//11/01/2000: This code was originally from KPEG.C
// All non 32-bit color drawing was removed
// "Motion" JPG code was removed
// A lot of parameters were added to kpeg() for library usage
static int clipxdim, clipydim;
static int hufquickcnt[8];
static int hufmaxatbit[8][20], hufvalatbit[8][20], hufcnt[8];
static unsigned char hufnumatbit[8][20], huftable[8][256];
static unsigned char gnumcomponents, dcflagor[64];
static int gcompid[4], gcomphsamp[4], gcompvsamp[4], gcompquantab[4];
static int lcompid[4], lcompdc[4], lcompac[4];
static int lcomphsamp[4], lcompvsamp[4], lcomphvsamp[4], lcompquantab[4];
static int lcomphsampmask[4], lcomphsampshift[4], lcompvsampshift[4];
static int quantab[4][64], dct[19][64], lastdc[4], unzig[64];
static const unsigned char pow2char[8] = {1,2,4,8,16,32,64,128};
#define SQRT2 23726566 //(sqrt(2))<<24
#define C182 31000253 //(cos(PI/8)*2)<<24
#define C18S22 43840978 //(cos(PI/8)*sqrt(2)*2)<<24
#define C38S22 18159528 //(cos(PI*3/8)*sqrt(2)*2)<<24
static const int cosqr16[8] = //cosqr16[i] = ((cos(PI*i/16)*sqrt(2))<<24);
{23726566,23270667,21920489,19727919,16777216,13181774,9079764,4628823};
// [RH] Moved the bigger tables into a dynamically allocated struct so that
// they don't waste space if a JPEG is never loaded.
struct kpegtables
{
int hufquickval[8][1024], hufquickbits[8][1024];
int colclip[1024], colclipup8[1024], colclipup16[1024];
int crmul[4096], cbmul[4096];
};
static kpegtables *kpeg;
static void initkpeg ()
{
int i, x, y;
kpeg = new kpegtables;
x = 0; //Back & forth diagonal pattern (aligning bytes for best compression)
for(i=0;i<16;i+=2)
{
for(y=7;y>=0;y--)
if ((unsigned)(i-y) < (unsigned)8) unzig[x++] = (y<<3)+i-y;
for(y=0;y<8;y++)
if ((unsigned)(i+1-y) < (unsigned)8) unzig[x++] = (y<<3)+i+1-y;
}
for(i=63;i>=0;i--) dcflagor[i] = (unsigned char)(1<<(unzig[i]>>3));
for(i=0;i<128;i++) kpeg->colclip[i] = i+128;
for(i=128;i<512;i++) kpeg->colclip[i] = 255;
for(i=512;i<896;i++) kpeg->colclip[i] = 0;
for(i=896;i<1024;i++) kpeg->colclip[i] = i-896;
for(i=0;i<1024;i++)
{
kpeg->colclipup8[i] = (kpeg->colclip[i]<<8);
kpeg->colclipup16[i] = (kpeg->colclip[i]<<16)+0xff000000; //Hack: set alphas to 255
}
for(i=0;i<2048;i++)
{
kpeg->crmul[(i<<1)+0] = (i-1024)*1470104; //1.402*1048576
kpeg->crmul[(i<<1)+1] = (i-1024)*-748830; //-0.71414*1048576
kpeg->cbmul[(i<<1)+0] = (i-1024)*-360857; //-0.34414*1048576
kpeg->cbmul[(i<<1)+1] = (i-1024)*1858077; //1.772*1048576
}
memset((void *)&dct[16][0],0,64*2*sizeof(dct[0][0]));
memset((void *)&dct[18][0],0xa0,64*sizeof(dct[0][0]));
}
static void huffgetval (int index, int curbits, int num, int *daval, int *dabits)
{
int b, v, pow2, *hmax;
hmax = &hufmaxatbit[index][0];
pow2 = pow2mask[curbits-1]+1;
if (num&pow2) v = 1; else v = 0;
for(b=1;b<=16;b++)
{
if (v < hmax[b])
{
*dabits = b;
*daval = huftable[index][hufvalatbit[index][b]+v];
return;
}
pow2 >>= 1; v <<= 1;
if (num&pow2) v++;
}
*dabits = 16;
*daval = 0;
}
int kpegrend (const char *kfilebuf, int kfilength,
unsigned char *daframeplace, int dabytesperline, int daxres, int dayres,
int daglobxoffs, int daglobyoffs)
{
int i, j, v, leng, xdim = 0, ydim = 0, index, prec, restartinterval;
int restartcnt, num, curbits, x, y, z, dctcnt, c, cc, daval, dabits;
int xx, yy, zz, xxx, yyy, r, g, b, t0, t1, t2, t3, t4, t5, t6, t7;
int yv, cr = 0, cb = 0, *dc, *dc2, xxxend, yyyend;
int *hqval, *hqbits, hqcnt, *quanptr;
unsigned char ch, marker, numbits, lnumcomponents, dcflag, *p;
const unsigned char *kfileptr;
if (kpeg == NULL) { initkpeg(); }
kfileptr = (unsigned char *)kfilebuf;
if (*(unsigned short *)kfileptr == 0xd8ff) kfileptr += 2;
else return(-1); //"%s is not a JPEG file\n",filename
restartinterval = 0;
for(i=0;i<4;i++) lastdc[i] = 0;
for(i=0;i<8;i++) hufcnt[i] = 0;
coltype = 0; bitdepth = 8; //For PNGOUT
do
{
ch = *kfileptr++; if (ch != 255) continue;
marker = *kfileptr++;
leng = ((int)kfileptr[0]<<8)+(int)kfileptr[1]-2;
kfileptr += 2;
switch(marker)
{
case 0xc0: case 0xc1: case 0xc2:
//processit!
numbits = *kfileptr++;
ydim = ((int)kfileptr[0]<<8)+(int)kfileptr[1];
xdim = ((int)kfileptr[2]<<8)+(int)kfileptr[3];
//printf("%s: %ld / %ld = %ld\n",filename,xdim*ydim*3,kfilength,(xdim*ydim*3)/kfilength);
frameplace = daframeplace;
bytesperline = dabytesperline;
xres = daxres;
yres = dayres;
globxoffs = daglobxoffs;
globyoffs = daglobyoffs;
gnumcomponents = kfileptr[4];
kfileptr += 5;
for(z=0;z<gnumcomponents;z++)
{
gcompid[z] = kfileptr[0];
gcomphsamp[z] = (kfileptr[1]>>4);
gcompvsamp[z] = (kfileptr[1]&15);
gcompquantab[z] = kfileptr[2];
kfileptr += 3;
}
break;
case 0xc4: //Huffman table
do
{
ch = *kfileptr++; leng--;
if (ch >= 16) { index = ch-12; }
else { index = ch; }
memcpy((void *)&hufnumatbit[index][1],(void *)kfileptr,16); kfileptr += 16;
leng -= 16;
v = 0; hufcnt[index] = 0;
hufquickcnt[index] = 0; c = 0;
for(b=1;b<=16;b++)
{
hufmaxatbit[index][b] = v+hufnumatbit[index][b];
hufvalatbit[index][b] = hufcnt[index]-v;
memcpy((void *)&huftable[index][hufcnt[index]],(void *)kfileptr,(int)hufnumatbit[index][b]);
if (b <= 10)
for(c=0;c<hufnumatbit[index][b];c++)
for(j=(1<<(10-b));j>0;j--)
{
kpeg->hufquickval[index][hufquickcnt[index]] = huftable[index][hufcnt[index]+c];
kpeg->hufquickbits[index][hufquickcnt[index]] = b;
hufquickcnt[index]++;
}
kfileptr += hufnumatbit[index][b];
leng -= hufnumatbit[index][b];
hufcnt[index] += hufnumatbit[index][b];
v = ((v+hufnumatbit[index][b])<<1);
}
} while (leng > 0);
break;
case 0xdb:
do
{
ch = *kfileptr++; leng--;
index = (ch&15);
prec = (ch>>4);
for(z=0;z<64;z++)
{
v = (int)(*kfileptr++);
if (prec) v = (v<<8)+((int)(*kfileptr++));
v <<= 19;
if (unzig[z]&7) v = MulScale24(v,cosqr16[unzig[z]&7]);
if (unzig[z]>>3) v = MulScale24(v,cosqr16[unzig[z]>>3]);
if (index) v >>= 6;
quantab[index][unzig[z]] = v;
}
leng -= 64;
if (prec) leng -= 64;
} while (leng > 0);
break;
case 0xdd:
restartinterval = (((int)kfileptr[0])<<8)+((int)kfileptr[1]);
kfileptr += leng;
break;
case 0xda: case 0xd9:
if ((xdim <= 0) || (ydim <= 0)) return(-1);
lnumcomponents = *kfileptr++;
if (lnumcomponents > 1) coltype = 2;
for(z=0;z<lnumcomponents;z++)
{
lcompid[z] = kfileptr[0];
lcompdc[z] = (kfileptr[1]>>4);
lcompac[z] = (kfileptr[1]&15);
kfileptr += 2;
for(zz=0;zz<gnumcomponents;zz++)
if (lcompid[z] == gcompid[zz])
{
lcomphsamp[z] = gcomphsamp[zz];
lcompvsamp[z] = gcompvsamp[zz];
lcomphvsamp[z] = lcomphsamp[z]*lcompvsamp[z];
lcompquantab[z] = gcompquantab[zz];
for(i=0;i<8;i++)
if (pow2mask[i]+1 == lcomphsamp[z])
{
lcomphsampmask[z] = pow2mask[i];
lcomphsampshift[z] = i;
break;
}
for(i=0;i<8;i++)
if (pow2mask[i]+1 == lcompvsamp[z])
{
lcompvsampshift[z] = i;
break;
}
}
}
//Ss = kfileptr[0];
//Se = kfileptr[1];
//Ah = (kfileptr[2]>>4);
//Al = (kfileptr[2]&15);
kfileptr += 3;
if ((hufcnt[0] == 0) || (hufcnt[4] == 0)) return(-1);
clipxdim = min(xdim+globxoffs,xres);
clipydim = min(ydim+globyoffs,yres);
xx = max(globxoffs,0); xxx = min(globxoffs+xdim,xres);
yy = max(globyoffs,0); yyy = min(globyoffs+ydim,yres);
if ((xx >= xres) || (yy >= yres) || (xxx <= 0) || (yyy <= 0)) return(0);
restartcnt = restartinterval; marker = 0xd0;
num = 0; curbits = 0; x = 0; y = 0;
while (1)
{
if (kfileptr-(unsigned char *)kfilebuf >= kfilength)
lnumcomponents = 0; //rest of file is missing!
dctcnt = 0;
for(c=0;c<lnumcomponents;c++)
{
hqval = &kpeg->hufquickval[lcompac[c]+4][0];
hqbits = &kpeg->hufquickbits[lcompac[c]+4][0];
hqcnt = hufquickcnt[lcompac[c]+4];
quanptr = &quantab[lcompquantab[c]][0];
for(cc=lcomphvsamp[c];cc>0;cc--)
{
dc = &dct[dctcnt][0];
//Get DC
while (curbits < 16) //Getbits
{
ch = *kfileptr++; if (ch == 255) kfileptr++;
num = (num<<8)+((int)ch); curbits += 8;
}
i = ((num>>(curbits-10))&1023);
if (i < hufquickcnt[lcompdc[c]])
{ dabits = kpeg->hufquickbits[lcompdc[c]][i]; daval = kpeg->hufquickval[lcompdc[c]][i]; }
else
huffgetval(lcompdc[c],curbits,num,&daval,&dabits);
curbits -= dabits;
if (daval)
{
while (curbits < 16) //Getbits
{
ch = *kfileptr++; if (ch == 255) kfileptr++;
num = (num<<8)+((int)ch); curbits += 8;
}
v = ((unsigned)num >> (curbits-daval)) & pow2mask[daval];
if (v <= pow2mask[daval-1]) v -= pow2mask[daval];
lastdc[c] += v;
curbits -= daval;
}
dc[0] = lastdc[c]*quanptr[0];
//Get AC
memset((void *)&dc[1],0,63*4);
dcflag = 1;
for(z=1;z<64;z++)
{
while (curbits < 16) //Getbits
{
ch = *kfileptr++; if (ch == 255) kfileptr++;
num = (num<<8)+((int)ch); curbits += 8;
}
i = ((num>>(curbits-10))&1023);
if (i < hqcnt)
{ daval = hqval[i]; curbits -= hqbits[i]; }
else
{
huffgetval(lcompac[c]+4,curbits,num,&daval,&dabits);
curbits -= dabits;
}
if (!daval) break;
z += (daval>>4); if (z >= 64) break;
daval &= 15;
while (curbits < 16) //Getbits
{
ch = *kfileptr++; if (ch == 255) kfileptr++;
num = (num<<8)+((int)ch); curbits += 8;
}
v = ((unsigned)num >> (curbits-daval)) & pow2mask[daval];
if (v <= pow2mask[daval-1]) v -= pow2mask[daval];
dcflag |= dcflagor[z];
dc[unzig[z]] = v*quanptr[unzig[z]];
curbits -= daval;
}
for(z=0;z<8;z++,dc+=8)
{
if (!(dcflag&pow2char[z])) continue;
t3 = dc[2] + dc[6];
t2 = (MulScale32(dc[2]-dc[6],SQRT2<<6)<<2) - t3;
t4 = dc[0] + dc[4]; t5 = dc[0] - dc[4];
t0 = t4+t3; t3 = t4-t3; t1 = t5+t2; t2 = t5-t2;
t4 = (MulScale32(dc[5]-dc[3]+dc[1]-dc[7],C182<<6)<<2);
t7 = dc[1] + dc[7] + dc[5] + dc[3];
t6 = (MulScale32(dc[3]-dc[5],C18S22<<5)<<3) + t4 - t7;
t5 = (MulScale32(dc[1]+dc[7]-dc[5]-dc[3],SQRT2<<6)<<2) - t6;
t4 = (MulScale32(dc[1]-dc[7],C38S22<<6)<<2) - t4 + t5;
dc[0] = t0+t7; dc[7] = t0-t7; dc[1] = t1+t6; dc[6] = t1-t6;
dc[2] = t2+t5; dc[5] = t2-t5; dc[4] = t3+t4; dc[3] = t3-t4;
}
dc = &dct[dctcnt][0];
for(z=7;z>=0;z--,dc++)
{
t3 = dc[2<<3] + dc[6<<3];
t2 = (MulScale32(dc[2<<3]-dc[6<<3],SQRT2<<6)<<2) - t3;
t4 = dc[0<<3] + dc[4<<3]; t5 = dc[0<<3] - dc[4<<3];
t0 = t4+t3; t3 = t4-t3; t1 = t5+t2; t2 = t5-t2;
t4 = (MulScale32(dc[5<<3]-dc[3<<3]+dc[1<<3]-dc[7<<3],C182<<6)<<2);
t7 = dc[1<<3] + dc[7<<3] + dc[5<<3] + dc[3<<3];
t6 = (MulScale32(dc[3<<3]-dc[5<<3],C18S22<<5)<<3) + t4 - t7;
t5 = (MulScale32(dc[1<<3]+dc[7<<3]-dc[5<<3]-dc[3<<3],SQRT2<<6)<<2) - t6;
t4 = (MulScale32(dc[1<<3]-dc[7<<3],C38S22<<6)<<2) - t4 + t5;
dc[0<<3] = t0+t7; dc[7<<3] = t0-t7; dc[1<<3] = t1+t6; dc[6<<3] = t1-t6;
dc[2<<3] = t2+t5; dc[5<<3] = t2-t5; dc[4<<3] = t3+t4; dc[3<<3] = t3-t4;
}
dctcnt++;
}
}
dctcnt = 0; dc = &dct[18][0]; dc2 = &dct[16][0];
r = g = b = 0; cc = 0;
for(yy=0;yy<(lcompvsamp[0]<<3);yy+=8)
for(xx=0;xx<(lcomphsamp[0]<<3);xx+=8,dctcnt++)
{
yyy = y+yy+globyoffs; if ((unsigned)yyy >= (unsigned)clipydim) continue;
xxx = x+xx+globxoffs; if ((unsigned)xxx >= (unsigned)clipxdim) continue;
p = yyy*bytesperline + xxx*4 + frameplace;
if (lnumcomponents > 0) dc = &dct[dctcnt][0];
if (lnumcomponents > 1) dc2 = &dct[lcomphvsamp[0]][((yy>>lcompvsampshift[0])<<3)+(xx>>lcomphsampshift[0])];
xxxend = min(clipxdim-(x+xx+globxoffs),8);
yyyend = min(clipydim-(y+yy+globyoffs),8);
if ((lcomphsamp[0] == 1) && (xxxend == 8))
{
for(yyy=0;yyy<yyyend;yyy++)
{
for(xxx=0;xxx<8;xxx++)
{
yv = dc[xxx];
cr = (dc2[xxx+64]>>13)&~1;
cb = (dc2[xxx]>>13)&~1;
((int *)p)[xxx] = kpeg->colclipup16[(unsigned)(yv+kpeg->crmul[cr+2048])>>22]+
kpeg->colclipup8[(unsigned)(yv+kpeg->crmul[cr+2049]+kpeg->cbmul[cb+2048])>>22]+
kpeg->colclip[(unsigned)(yv+kpeg->cbmul[cb+2049])>>22];
}
p += bytesperline;
dc += 8;
if (!((yyy+1)&(lcompvsamp[0]-1))) dc2 += 8;
}
}
else if ((lcomphsamp[0] == 2) && (xxxend == 8))
{
for(yyy=0;yyy<yyyend;yyy++)
{
for(xxx=0;xxx<8;xxx+=2)
{
yv = dc[xxx];
cr = (dc2[(xxx>>1)+64]>>13)&~1;
cb = (dc2[(xxx>>1)]>>13)&~1;
i = kpeg->crmul[cr+2049]+kpeg->cbmul[cb+2048];
cr = kpeg->crmul[cr+2048];
cb = kpeg->cbmul[cb+2049];
((int *)p)[xxx] = kpeg->colclipup16[(unsigned)(yv+cr)>>22]+
kpeg->colclipup8[(unsigned)(yv+i)>>22]+
kpeg->colclip[(unsigned)(yv+cb)>>22];
yv = dc[xxx+1];
((int *)p)[xxx+1] = kpeg->colclipup16[(unsigned)(yv+cr)>>22]+
kpeg->colclipup8[(unsigned)(yv+i)>>22]+
kpeg->colclip[(unsigned)(yv+cb)>>22];
}
p += bytesperline;
dc += 8;
if (!((yyy+1)&(lcompvsamp[0]-1))) dc2 += 8;
}
}
else
{
for(yyy=0;yyy<yyyend;yyy++)
{
i = 0; j = 1;
for(xxx=0;xxx<xxxend;xxx++)
{
yv = dc[xxx];
j--;
if (!j)
{
j = lcomphsamp[0];
cr = (dc2[i+64]>>13)&~1;
cb = (dc2[i]>>13)&~1;
i++;
}
((int *)p)[xxx] = kpeg->colclipup16[(unsigned)(yv+kpeg->crmul[cr+2048])>>22]+
kpeg->colclipup8[(unsigned)(yv+kpeg->crmul[cr+2049]+kpeg->cbmul[cb+2048])>>22]+
kpeg->colclip[(unsigned)(yv+kpeg->cbmul[cb+2049])>>22];
}
p += bytesperline;
dc += 8;
if (!((yyy+1)&(lcompvsamp[0]-1))) dc2 += 8;
}
}
}
if (lnumcomponents) //do only when not EOF...
{
restartcnt--;
if (!restartcnt)
{
kfileptr += 1-(curbits>>3); curbits = 0;
if ((kfileptr[-2] != 255) || (kfileptr[-1] != marker)) kfileptr--;
marker++; if (marker >= 0xd8) marker = 0xd0;
restartcnt = restartinterval;
for(i=0;i<4;i++) lastdc[i] = 0;
}
}
x += (lcomphsamp[0]<<3);
if (x >= xdim) { x = 0; y += (lcompvsamp[0]<<3); if (y >= ydim) return(0); }
}
default:
kfileptr += leng;
break;
}
} while (kfileptr-(unsigned char *)kfilebuf < kfilength);
return(0);
}
//============================== KPEGILIB ends ==============================

View File

@ -537,14 +537,14 @@ static BOOL FindFreeName (FString &fullname, const char *extension)
return false;
}
void M_ScreenShot (char *filename)
void M_ScreenShot (const char *filename)
{
FILE *file;
FString autoname;
bool writepcx = (stricmp (screenshot_type, "pcx") == 0); // PNG is the default
// find a file name to save it to
if (filename == NULL)
if (filename == NULL || filename[0] == '\0')
{
#ifndef unix
if (Args.CheckParm ("-cdrom"))

View File

@ -36,7 +36,7 @@ void M_FindResponseFile (void);
// [RH] M_ScreenShot now accepts a filename parameter.
// Pass a NULL to get the original behavior.
void M_ScreenShot (char *filename);
void M_ScreenShot (const char *filename);
void M_LoadDefaults ();

View File

@ -100,7 +100,7 @@ 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, int bpp);
static void UnpackPixels (int width, int bytesPerRow, int bitdepth, BYTE *row);
static void UnpackPixels (int width, int bytesPerRow, int bitdepth, const BYTE *rowin, BYTE *rowout);
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
@ -525,14 +525,21 @@ DCanvas *M_CreateCanvasFromPNG (PNGHandle *png)
bool M_ReadIDAT (FileReader *file, BYTE *buffer, int width, int height, int pitch,
BYTE bitdepth, BYTE colortype, BYTE interlace, unsigned int chunklen)
{
Byte *inputLine, *prev, *curr;
// Uninterlaced images are treated as a conceptual eighth pass by these tables.
static const BYTE passwidthshift[8] = { 3, 3, 2, 2, 1, 1, 0, 0 };
static const BYTE passheightshift[8] = { 3, 3, 3, 2, 2, 1, 1, 0 };
static const BYTE passrowoffset[8] = { 0, 0, 4, 0, 2, 0, 1, 0 };
static const BYTE passcoloffset[8] = { 0, 4, 0, 2, 0, 1, 0, 0 };
Byte *inputLine, *prev, *curr, *adam7buff[3], *bufferend;
Byte chunkbuffer[4096];
z_stream stream;
int err;
int y;
int i, pass, passbuff, passpitch, passwidth;
bool lastIDAT;
int bytesPerRowIn;
int bytesPerRowIn, bytesPerRowOut;
int bytesPerPixel;
bool initpass;
switch (colortype)
{
@ -541,23 +548,18 @@ bool M_ReadIDAT (FileReader *file, BYTE *buffer, int width, int height, int pitc
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)
bytesPerRowOut = width * bytesPerPixel;
i = 4 + bytesPerRowOut * 2;
if (interlace)
{
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;
i += bytesPerRowOut * 2;
}
inputLine = (Byte *)alloca (i);
adam7buff[0] = inputLine + 4 + bytesPerRowOut;
adam7buff[1] = adam7buff[0] + bytesPerRowOut;
adam7buff[2] = adam7buff[1] + bytesPerRowOut;
bufferend = buffer + pitch * height;
stream.next_in = Z_NULL;
stream.avail_in = 0;
@ -568,67 +570,166 @@ bool M_ReadIDAT (FileReader *file, BYTE *buffer, int width, int height, int pitc
{
return false;
}
y = 0;
curr = buffer;
stream.next_out = inputLine;
stream.avail_out = bytesPerRowIn+1;
lastIDAT = false;
initpass = true;
pass = interlace ? 0 : 7;
do
while (err != Z_STREAM_END && pass < 8 - interlace)
{
while (err != Z_STREAM_END)
if (initpass)
{
if (stream.avail_in == 0 && chunklen > 0)
{
stream.next_in = chunkbuffer;
stream.avail_in = (uInt)file->Read (chunkbuffer, MIN<long>(chunklen,sizeof(chunkbuffer)));
chunklen -= stream.avail_in;
}
int rowoffset, coloffset;
err = inflate (&stream, Z_SYNC_FLUSH);
if (err != Z_OK && err != Z_STREAM_END)
{ // something unexpected happened
inflateEnd (&stream);
return false;
}
if (stream.avail_out == 0)
initpass = false;
pass--;
do
{
pass++;
rowoffset = passrowoffset[pass];
coloffset = passcoloffset[pass];
}
while ((rowoffset >= height || coloffset >= width) && pass < 7);
if (pass == 7 && interlace)
{
break;
}
passwidth = (width + (1 << passwidthshift[pass]) - 1 - coloffset) >> passwidthshift[pass];
prev = adam7buff[0];
passbuff = 1;
memset (prev, 0, passwidth * bytesPerPixel);
switch (bitdepth)
{
case 8: bytesPerRowIn = passwidth * bytesPerPixel; break;
case 4: bytesPerRowIn = (passwidth+1)/2; break;
case 2: bytesPerRowIn = (passwidth+3)/4; break;
case 1: bytesPerRowIn = (passwidth+7)/8; break;
default: return false;
}
curr = buffer + rowoffset*pitch + coloffset*bytesPerPixel;
passpitch = pitch << passheightshift[pass];
stream.next_out = inputLine;
stream.avail_out = bytesPerRowIn + 1;
}
if (stream.avail_in == 0 && chunklen > 0)
{
stream.next_in = chunkbuffer;
stream.avail_in = (uInt)file->Read (chunkbuffer, MIN<long>(chunklen,sizeof(chunkbuffer)));
chunklen -= stream.avail_in;
}
err = inflate (&stream, Z_SYNC_FLUSH);
if (err != Z_OK && err != Z_STREAM_END)
{ // something unexpected happened
inflateEnd (&stream);
return false;
}
if (stream.avail_out == 0)
{
if (pass >= 6)
{
// Store pixels directly into the output buffer
UnfilterRow (bytesPerRowIn, curr, inputLine, prev, bytesPerPixel);
prev = curr;
curr += pitch;
y++;
stream.next_out = inputLine;
stream.avail_out = bytesPerRowIn+1;
}
if (chunklen == 0 && !lastIDAT)
else
{
DWORD x[3];
const BYTE *in;
BYTE *out;
int colstep, x;
if (file->Read (x, 12) != 12)
// Store pixels into a temporary buffer
UnfilterRow (bytesPerRowIn, adam7buff[passbuff], inputLine, prev, bytesPerPixel);
prev = adam7buff[passbuff];
passbuff ^= 1;
in = prev;
if (bitdepth < 8)
{
lastIDAT = true;
UnpackPixels (passwidth, bytesPerRowIn, bitdepth, in, adam7buff[2]);
in = adam7buff[2];
}
else if (x[2] != MAKE_ID('I','D','A','T'))
// Distribute pixels into the output buffer
out = curr;
colstep = bytesPerPixel << passwidthshift[pass];
switch (bytesPerPixel)
{
lastIDAT = true;
}
else
{
chunklen = BigLong((unsigned int)x[1]);
case 1:
for (x = passwidth; x > 0; --x)
{
*out = *in;
out += colstep;
in += 1;
}
break;
case 2:
for (x = passwidth; x > 0; --x)
{
*(WORD *)out = *(WORD *)in;
out += colstep;
in += 2;
}
break;
case 3:
for (x = passwidth; x > 0; --x)
{
out[0] = in[0];
out[1] = in[1];
out[2] = in[2];
out += colstep;
in += 3;
}
break;
case 4:
for (x = passwidth; x > 0; --x)
{
*(DWORD *)out = *(DWORD *)in;
out += colstep;
in += 4;
}
break;
}
}
if ((curr += passpitch) >= bufferend)
{
++pass;
initpass = true;
}
stream.next_out = inputLine;
stream.avail_out = bytesPerRowIn + 1;
}
if (chunklen == 0 && !lastIDAT)
{
DWORD x[3];
if (file->Read (x, 12) != 12)
{
lastIDAT = true;
}
else if (x[2] != MAKE_ID('I','D','A','T'))
{
lastIDAT = true;
}
else
{
chunklen = BigLong((unsigned int)x[1]);
}
}
} while (err == Z_OK && y < height);
}
inflateEnd (&stream);
if (bitdepth < 8)
{
for (curr = buffer; curr <= prev; curr += pitch)
// Noninterlaced images must be unpacked completely.
// Interlaced images only need their final pass unpacked.
passpitch = pitch << interlace;
for (curr = buffer + pitch * interlace; curr <= prev; curr += passpitch)
{
UnpackPixels (width, bytesPerRowIn, bitdepth, curr);
UnpackPixels (width, bytesPerRowIn, bitdepth, curr, curr);
}
}
return true;
@ -897,32 +998,33 @@ void UnfilterRow (int width, BYTE *dest, BYTE *row, BYTE *prev, int bpp)
//
// UnpackPixels
//
// Unpacks a row of pixels whose depth is less than 8 into so that each
// pixel occupies a single byte. The packed pixels must be at the start
// of the row, and the row must be "width" bytes long. "bytesPerRow" is
// the number of bytes for the packed row.
// Unpacks a row of pixels whose depth is less than 8 so that each pixel
// occupies a single byte. The outrow must be "width" bytes long.
// "bytesPerRow" is the number of bytes for the packed row. The in and out
// rows may overlap, but only if rowin == rowout.
//
//==========================================================================
static void UnpackPixels (int width, int bytesPerRow, int bitdepth, BYTE *row)
static void UnpackPixels (int width, int bytesPerRow, int bitdepth, const BYTE *rowin, BYTE *rowout)
{
BYTE *out, *in;
const BYTE *in;
BYTE *out;
BYTE pack;
int lastbyte;
out = row + width;
in = row + bytesPerRow;
out = rowout + width;
in = rowin + bytesPerRow;
switch (bitdepth)
{
case 1:
lastbyte=width&7;
if (lastbyte!=0)
lastbyte = width & 7;
if (lastbyte != 0)
{
in--;
pack = *in;
out-=lastbyte;
out -= lastbyte;
out[0] = (pack >> 7) & 1;
if (lastbyte >= 2) out[1] = (pack >> 6) & 1;
if (lastbyte >= 3) out[2] = (pack >> 5) & 1;
@ -932,7 +1034,7 @@ static void UnpackPixels (int width, int bytesPerRow, int bitdepth, BYTE *row)
if (lastbyte == 7) out[6] = (pack >> 1) & 1;
}
while (in-- > row)
while (in-- > rowin)
{
pack = *in;
out -= 8;
@ -949,18 +1051,18 @@ static void UnpackPixels (int width, int bytesPerRow, int bitdepth, BYTE *row)
case 2:
lastbyte=width&3;
if (lastbyte!=0)
lastbyte = width & 3;
if (lastbyte != 0)
{
in--;
pack = *in;
out-=lastbyte;
out -= lastbyte;
out[0] = pack >> 6;
if (lastbyte >= 2) out[1] = (pack >> 4) & 3;
if (lastbyte == 3) out[2] = (pack >> 2) & 3;
}
while (in-- > row)
while (in-- > rowin)
{
pack = *in;
out -= 4;
@ -972,16 +1074,16 @@ static void UnpackPixels (int width, int bytesPerRow, int bitdepth, BYTE *row)
break;
case 4:
lastbyte=width&1;
if (lastbyte!=0)
lastbyte = width & 1;
if (lastbyte != 0)
{
in--;
pack = *in;
out-=lastbyte;
out -= lastbyte;
out[0] = pack >> 4;
}
while (in-- > row)
while (in-- > rowin)
{
pack = *in;
out -= 2;

View File

@ -238,6 +238,7 @@ int FTextureManager::CreateTexture (int lumpnum, int usetype)
{
DWORD dw;
WORD w[2];
BYTE b[4];
} first4bytes;
// Must check the length of the lump. Zero length flat markers (F1_START etc.) will come through here.
@ -250,7 +251,7 @@ int FTextureManager::CreateTexture (int lumpnum, int usetype)
{
FWadLump data = Wads.OpenLumpNum (lumpnum);
data >> first4bytes.dw;
data.Read (first4bytes.b, 4);
if (first4bytes.dw == MAKE_ID('I','M','G','Z'))
{
type = t_imgz;
@ -263,11 +264,11 @@ int FTextureManager::CreateTexture (int lumpnum, int usetype)
// This is most likely a PNG, but make sure. (Note that if the
// first 4 bytes match, but later bytes don't, we assume it's
// a corrupt PNG.)
data >> first4bytes.dw;
data.Read (first4bytes.b, 4);
if (first4bytes.dw != MAKE_ID(13,10,26,10)) return -1;
data >> first4bytes.dw;
data.Read (first4bytes.b, 4);
if (first4bytes.dw != MAKE_ID(0,0,0,13)) return -1;
data >> first4bytes.dw;
data.Read (first4bytes.b, 4);
if (first4bytes.dw != MAKE_ID('I','H','D','R')) return -1;
// The PNG looks valid so far. Check the IHDR to make sure it's a
@ -275,7 +276,7 @@ int FTextureManager::CreateTexture (int lumpnum, int usetype)
data >> width >> height
>> bitdepth >> colortype >> compression >> filter >> interlace;
if (compression != 0 || filter != 0 || interlace != 0)
if (compression != 0 || filter != 0 || interlace > 1)
{
return -1;
}
@ -290,10 +291,11 @@ int FTextureManager::CreateTexture (int lumpnum, int usetype)
// Just for completeness, make sure the PNG has something more than an
// IHDR.
data >> first4bytes.dw >> first4bytes.dw;
data.Seek (4, SEEK_CUR);
data.Read (first4bytes.b, 4);
if (first4bytes.dw == 0)
{
data >> first4bytes.dw;
data.Read (first4bytes.b, 4);
if (first4bytes.dw == MAKE_ID('I','E','N','D'))
{
return -1;
@ -304,6 +306,39 @@ int FTextureManager::CreateTexture (int lumpnum, int usetype)
out = new FPNGTexture (lumpnum, BigLong((int)width), BigLong((int)height),
bitdepth, colortype, interlace);
}
else if (first4bytes.b[0] == 0xFF && first4bytes.b[1] == 0xD8 && first4bytes.b[2] == 0xFF)
{
// JPEG, I presume
// Find the SOFn marker to extract the image dimensions,
// where n is 0, 1, or 2 (other types are unsupported).
while ((unsigned)first4bytes.b[3] - 0xC0 >= 3)
{
if (data.Read (first4bytes.w, 2) != 2)
{
return -1;
}
data.Seek (BigShort(first4bytes.w[0]) - 2, SEEK_CUR);
if (data.Read (first4bytes.b + 2, 2) != 2 || first4bytes.b[2] != 0xFF)
{
return -1;
}
}
if (data.Read (first4bytes.b, 3) != 3)
{
return -1;
}
if (BigShort (first4bytes.w[0]) <5)
{
return -1;
}
if (data.Read (first4bytes.b, 4) != 4)
{
return -1;
}
type = t_png;
out = new FJPEGTexture (lumpnum, BigShort(first4bytes.w[1]), BigShort(first4bytes.w[0]));
}
else if (usetype == FTexture::TEX_Flat)
{
// allow PNGs as flats but not Doom patches.
@ -2091,6 +2126,111 @@ void FPNGTexture::MakeTexture ()
}
}
int kpegrend (const char *kfilebuf, int kfilength,
unsigned char *daframeplace, int dabytesperline, int daxres, int dayres,
int daglobxoffs, int daglobyoffs);
FJPEGTexture::FJPEGTexture (int lumpnum, int width, int height)
: SourceLump(lumpnum), Pixels(0)
{
Wads.GetLumpName (Name, lumpnum);
Name[8] = 0;
UseType = TEX_MiscPatch;
LeftOffset = 0;
TopOffset = 0;
bMasked = false;
Width = width;
Height = height;
CalcBitSize ();
DummySpans[0].TopOffset = 0;
DummySpans[0].Length = Height;
DummySpans[1].TopOffset = 0;
DummySpans[1].Length = 0;
}
FJPEGTexture::~FJPEGTexture ()
{
Unload ();
}
void FJPEGTexture::Unload ()
{
if (Pixels != NULL)
{
delete[] Pixels;
Pixels = NULL;
}
}
const BYTE *FJPEGTexture::GetColumn (unsigned int column, const Span **spans_out)
{
if (Pixels == NULL)
{
MakeTexture ();
}
if ((unsigned)column >= (unsigned)Width)
{
if (WidthMask + 1 == Width)
{
column &= WidthMask;
}
else
{
column %= Width;
}
}
if (spans_out != NULL)
{
*spans_out = DummySpans;
}
return Pixels + column*Height;
}
const BYTE *FJPEGTexture::GetPixels ()
{
if (Pixels == NULL)
{
MakeTexture ();
}
return Pixels;
}
void FJPEGTexture::MakeTexture ()
{
FMemLump lump = Wads.ReadLump (SourceLump);
BYTE *rgb = new BYTE[Width * Height * 4];
Pixels = new BYTE[Width * Height];
if (kpegrend ((char *)lump.GetMem(), Wads.LumpLength (SourceLump), rgb, Width * 4, Width, Height, 0, 0) < 0)
{ // Failed to read the JPEG
memset (Pixels, 0xBA, Width * Height);
}
else
{
BYTE *in, *out;
int x, y, pitch, backstep;
in = rgb;
out = Pixels;
// Convert from source format to paletted, column-major.
pitch = Width * 4;
backstep = Height * pitch - 4;
for (x = Width; x > 0; --x)
{
for (y = Height; y > 0; --y)
{
*out++ = RGB32k[in[2]>>3][in[1]>>3][in[0]>>3];
in += pitch;
}
in -= backstep;
}
}
delete[] rgb;
}
FBuildTexture::FBuildTexture (int tilenum, const BYTE *pixels, int width, int height, int left, int top)
: Pixels (pixels), Spans (NULL)

View File

@ -212,6 +212,25 @@ protected:
};
// A JPEG image
class FJPEGTexture : public FTexture
{
public:
FJPEGTexture (int lumpnum, int width, int height);
~FJPEGTexture ();
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
const BYTE *GetPixels ();
void Unload ();
protected:
int SourceLump;
BYTE *Pixels;
Span DummySpans[2];
void MakeTexture ();
};
// A texture that returns a wiggly version of another texture.
class FWarpTexture : public FTexture
{

View File

@ -1924,6 +1924,10 @@
/>
</FileConfiguration>
</File>
<File
RelativePath=".\src\kplib.cpp"
>
</File>
<File
RelativePath=".\src\lumpconfigfile.cpp"
>
@ -5381,7 +5385,7 @@
<Tool
Name="VCCustomBuildTool"
Description="Assembling $(InputPath)..."
CommandLine="nasmw -o &quot;$(IntDir)\$(InputName).obj&quot; -d OBJ_FORMAT_win32 -f win32 &quot;$(InputPath)&quot;"
CommandLine="nasmw -o &quot;$(IntDir)\$(InputName).obj&quot; -d OBJ_FORMAT_win32 -f win32 &quot;$(InputPath)&quot;&#x0D;&#x0A;"
Outputs="$(IntDir)\$(InputName).obj"
/>
</FileConfiguration>
@ -5399,7 +5403,7 @@
<Tool
Name="VCCustomBuildTool"
Description="Assembling $(InputPath)..."
CommandLine="nasmw -o &quot;$(IntDir)\$(InputName).obj&quot; -d OBJ_FORMAT_win32 -f win32 &quot;$(InputPath)&quot;"
CommandLine="nasmw -o &quot;$(IntDir)\$(InputName).obj&quot; -d OBJ_FORMAT_win32 -f win32 &quot;$(InputPath)&quot;&#x0D;&#x0A;"
Outputs="$(IntDir)\$(InputName).obj"
/>
</FileConfiguration>