mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-24 21:21:04 +00:00
- 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:
parent
89396964f5
commit
21869a6c08
9 changed files with 941 additions and 94 deletions
|
@ -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
|
August 12, 2006
|
||||||
- Added support for truecolor PNG textures. They still get resampled to the
|
- Added support for truecolor PNG textures. They still get resampled to the
|
||||||
global palette, but at least they are visible now.
|
global palette, but at least they are visible now.
|
||||||
|
|
|
@ -187,7 +187,7 @@ FString savegamefile;
|
||||||
char savedescription[SAVESTRINGSIZE];
|
char savedescription[SAVESTRINGSIZE];
|
||||||
|
|
||||||
// [RH] Name of screenshot file to generate (usually NULL)
|
// [RH] Name of screenshot file to generate (usually NULL)
|
||||||
char *shotfile;
|
FString shotfile;
|
||||||
|
|
||||||
AActor* bodyque[BODYQUESIZE];
|
AActor* bodyque[BODYQUESIZE];
|
||||||
int bodyqueslot;
|
int bodyqueslot;
|
||||||
|
@ -890,11 +890,7 @@ void G_Ticker ()
|
||||||
break;
|
break;
|
||||||
case ga_screenshot:
|
case ga_screenshot:
|
||||||
M_ScreenShot (shotfile);
|
M_ScreenShot (shotfile);
|
||||||
if (shotfile)
|
shotfile = "";
|
||||||
{
|
|
||||||
free (shotfile);
|
|
||||||
shotfile = NULL;
|
|
||||||
}
|
|
||||||
gameaction = ga_nothing;
|
gameaction = ga_nothing;
|
||||||
break;
|
break;
|
||||||
case ga_fullconsole:
|
case ga_fullconsole:
|
||||||
|
|
571
src/kplib.cpp
Normal file
571
src/kplib.cpp
Normal 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 ==============================
|
|
@ -537,14 +537,14 @@ static BOOL FindFreeName (FString &fullname, const char *extension)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void M_ScreenShot (char *filename)
|
void M_ScreenShot (const char *filename)
|
||||||
{
|
{
|
||||||
FILE *file;
|
FILE *file;
|
||||||
FString autoname;
|
FString autoname;
|
||||||
bool writepcx = (stricmp (screenshot_type, "pcx") == 0); // PNG is the default
|
bool writepcx = (stricmp (screenshot_type, "pcx") == 0); // PNG is the default
|
||||||
|
|
||||||
// find a file name to save it to
|
// find a file name to save it to
|
||||||
if (filename == NULL)
|
if (filename == NULL || filename[0] == '\0')
|
||||||
{
|
{
|
||||||
#ifndef unix
|
#ifndef unix
|
||||||
if (Args.CheckParm ("-cdrom"))
|
if (Args.CheckParm ("-cdrom"))
|
||||||
|
|
|
@ -36,7 +36,7 @@ void M_FindResponseFile (void);
|
||||||
|
|
||||||
// [RH] M_ScreenShot now accepts a filename parameter.
|
// [RH] M_ScreenShot now accepts a filename parameter.
|
||||||
// Pass a NULL to get the original behavior.
|
// Pass a NULL to get the original behavior.
|
||||||
void M_ScreenShot (char *filename);
|
void M_ScreenShot (const char *filename);
|
||||||
|
|
||||||
void M_LoadDefaults ();
|
void M_LoadDefaults ();
|
||||||
|
|
||||||
|
|
254
src/m_png.cpp
254
src/m_png.cpp
|
@ -100,7 +100,7 @@ static inline void StuffPalette (const PalEntry *from, BYTE *to);
|
||||||
static bool StuffBitmap (const DCanvas *canvas, FILE *file);
|
static bool StuffBitmap (const DCanvas *canvas, FILE *file);
|
||||||
static bool WriteIDAT (FILE *file, const BYTE *data, int len);
|
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 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 ----------------------------------------------
|
// 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,
|
bool M_ReadIDAT (FileReader *file, BYTE *buffer, int width, int height, int pitch,
|
||||||
BYTE bitdepth, BYTE colortype, BYTE interlace, unsigned int chunklen)
|
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];
|
Byte chunkbuffer[4096];
|
||||||
z_stream stream;
|
z_stream stream;
|
||||||
int err;
|
int err;
|
||||||
int y;
|
int i, pass, passbuff, passpitch, passwidth;
|
||||||
bool lastIDAT;
|
bool lastIDAT;
|
||||||
int bytesPerRowIn;
|
int bytesPerRowIn, bytesPerRowOut;
|
||||||
int bytesPerPixel;
|
int bytesPerPixel;
|
||||||
|
bool initpass;
|
||||||
|
|
||||||
switch (colortype)
|
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
|
case 6: bytesPerPixel = 4; break; // RGBA
|
||||||
default: bytesPerPixel = 1; break;
|
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)
|
bytesPerRowOut = width * bytesPerPixel;
|
||||||
{ // This is an invalid combination for PNG files
|
i = 4 + bytesPerRowOut * 2;
|
||||||
return false;
|
if (interlace)
|
||||||
}
|
|
||||||
|
|
||||||
switch (bitdepth)
|
|
||||||
{
|
{
|
||||||
case 8: bytesPerRowIn = width * bytesPerPixel; break;
|
i += bytesPerRowOut * 2;
|
||||||
case 4: bytesPerRowIn = (width+1)/2; break;
|
|
||||||
case 2: bytesPerRowIn = (width+3)/4; break;
|
|
||||||
case 1: bytesPerRowIn = (width+7)/8; break;
|
|
||||||
default: return false;
|
|
||||||
}
|
}
|
||||||
|
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.next_in = Z_NULL;
|
||||||
stream.avail_in = 0;
|
stream.avail_in = 0;
|
||||||
|
@ -568,67 +570,166 @@ bool M_ReadIDAT (FileReader *file, BYTE *buffer, int width, int height, int pitc
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
y = 0;
|
|
||||||
curr = buffer;
|
|
||||||
stream.next_out = inputLine;
|
|
||||||
stream.avail_out = bytesPerRowIn+1;
|
|
||||||
lastIDAT = false;
|
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)
|
int rowoffset, coloffset;
|
||||||
{
|
|
||||||
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);
|
initpass = false;
|
||||||
if (err != Z_OK && err != Z_STREAM_END)
|
pass--;
|
||||||
{ // something unexpected happened
|
do
|
||||||
inflateEnd (&stream);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream.avail_out == 0)
|
|
||||||
{
|
{
|
||||||
|
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);
|
UnfilterRow (bytesPerRowIn, curr, inputLine, prev, bytesPerPixel);
|
||||||
prev = curr;
|
prev = curr;
|
||||||
curr += pitch;
|
|
||||||
y++;
|
|
||||||
stream.next_out = inputLine;
|
|
||||||
stream.avail_out = bytesPerRowIn+1;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (chunklen == 0 && !lastIDAT)
|
|
||||||
{
|
{
|
||||||
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;
|
case 1:
|
||||||
}
|
for (x = passwidth; x > 0; --x)
|
||||||
else
|
{
|
||||||
{
|
*out = *in;
|
||||||
chunklen = BigLong((unsigned int)x[1]);
|
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);
|
inflateEnd (&stream);
|
||||||
|
|
||||||
if (bitdepth < 8)
|
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;
|
return true;
|
||||||
|
@ -897,32 +998,33 @@ void UnfilterRow (int width, BYTE *dest, BYTE *row, BYTE *prev, int bpp)
|
||||||
//
|
//
|
||||||
// UnpackPixels
|
// UnpackPixels
|
||||||
//
|
//
|
||||||
// Unpacks a row of pixels whose depth is less than 8 into so that each
|
// Unpacks a row of pixels whose depth is less than 8 so that each pixel
|
||||||
// pixel occupies a single byte. The packed pixels must be at the start
|
// occupies a single byte. The outrow must be "width" bytes long.
|
||||||
// of the row, and the row must be "width" bytes long. "bytesPerRow" is
|
// "bytesPerRow" is the number of bytes for the packed row. The in and out
|
||||||
// the number of bytes for the packed row.
|
// 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;
|
BYTE pack;
|
||||||
int lastbyte;
|
int lastbyte;
|
||||||
|
|
||||||
out = row + width;
|
out = rowout + width;
|
||||||
in = row + bytesPerRow;
|
in = rowin + bytesPerRow;
|
||||||
|
|
||||||
switch (bitdepth)
|
switch (bitdepth)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
|
|
||||||
lastbyte=width&7;
|
lastbyte = width & 7;
|
||||||
if (lastbyte!=0)
|
if (lastbyte != 0)
|
||||||
{
|
{
|
||||||
in--;
|
in--;
|
||||||
pack = *in;
|
pack = *in;
|
||||||
out-=lastbyte;
|
out -= lastbyte;
|
||||||
out[0] = (pack >> 7) & 1;
|
out[0] = (pack >> 7) & 1;
|
||||||
if (lastbyte >= 2) out[1] = (pack >> 6) & 1;
|
if (lastbyte >= 2) out[1] = (pack >> 6) & 1;
|
||||||
if (lastbyte >= 3) out[2] = (pack >> 5) & 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;
|
if (lastbyte == 7) out[6] = (pack >> 1) & 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (in-- > row)
|
while (in-- > rowin)
|
||||||
{
|
{
|
||||||
pack = *in;
|
pack = *in;
|
||||||
out -= 8;
|
out -= 8;
|
||||||
|
@ -949,18 +1051,18 @@ static void UnpackPixels (int width, int bytesPerRow, int bitdepth, BYTE *row)
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
|
|
||||||
lastbyte=width&3;
|
lastbyte = width & 3;
|
||||||
if (lastbyte!=0)
|
if (lastbyte != 0)
|
||||||
{
|
{
|
||||||
in--;
|
in--;
|
||||||
pack = *in;
|
pack = *in;
|
||||||
out-=lastbyte;
|
out -= lastbyte;
|
||||||
out[0] = pack >> 6;
|
out[0] = pack >> 6;
|
||||||
if (lastbyte >= 2) out[1] = (pack >> 4) & 3;
|
if (lastbyte >= 2) out[1] = (pack >> 4) & 3;
|
||||||
if (lastbyte == 3) out[2] = (pack >> 2) & 3;
|
if (lastbyte == 3) out[2] = (pack >> 2) & 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (in-- > row)
|
while (in-- > rowin)
|
||||||
{
|
{
|
||||||
pack = *in;
|
pack = *in;
|
||||||
out -= 4;
|
out -= 4;
|
||||||
|
@ -972,16 +1074,16 @@ static void UnpackPixels (int width, int bytesPerRow, int bitdepth, BYTE *row)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
lastbyte=width&1;
|
lastbyte = width & 1;
|
||||||
if (lastbyte!=0)
|
if (lastbyte != 0)
|
||||||
{
|
{
|
||||||
in--;
|
in--;
|
||||||
pack = *in;
|
pack = *in;
|
||||||
out-=lastbyte;
|
out -= lastbyte;
|
||||||
out[0] = pack >> 4;
|
out[0] = pack >> 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (in-- > row)
|
while (in-- > rowin)
|
||||||
{
|
{
|
||||||
pack = *in;
|
pack = *in;
|
||||||
out -= 2;
|
out -= 2;
|
||||||
|
|
154
src/r_data.cpp
154
src/r_data.cpp
|
@ -238,6 +238,7 @@ int FTextureManager::CreateTexture (int lumpnum, int usetype)
|
||||||
{
|
{
|
||||||
DWORD dw;
|
DWORD dw;
|
||||||
WORD w[2];
|
WORD w[2];
|
||||||
|
BYTE b[4];
|
||||||
} first4bytes;
|
} first4bytes;
|
||||||
|
|
||||||
// Must check the length of the lump. Zero length flat markers (F1_START etc.) will come through here.
|
// 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);
|
FWadLump data = Wads.OpenLumpNum (lumpnum);
|
||||||
|
|
||||||
data >> first4bytes.dw;
|
data.Read (first4bytes.b, 4);
|
||||||
if (first4bytes.dw == MAKE_ID('I','M','G','Z'))
|
if (first4bytes.dw == MAKE_ID('I','M','G','Z'))
|
||||||
{
|
{
|
||||||
type = t_imgz;
|
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
|
// 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
|
// first 4 bytes match, but later bytes don't, we assume it's
|
||||||
// a corrupt PNG.)
|
// a corrupt PNG.)
|
||||||
data >> first4bytes.dw;
|
data.Read (first4bytes.b, 4);
|
||||||
if (first4bytes.dw != MAKE_ID(13,10,26,10)) return -1;
|
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;
|
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;
|
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
|
// 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
|
data >> width >> height
|
||||||
>> bitdepth >> colortype >> compression >> filter >> interlace;
|
>> bitdepth >> colortype >> compression >> filter >> interlace;
|
||||||
|
|
||||||
if (compression != 0 || filter != 0 || interlace != 0)
|
if (compression != 0 || filter != 0 || interlace > 1)
|
||||||
{
|
{
|
||||||
return -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
|
// Just for completeness, make sure the PNG has something more than an
|
||||||
// IHDR.
|
// IHDR.
|
||||||
data >> first4bytes.dw >> first4bytes.dw;
|
data.Seek (4, SEEK_CUR);
|
||||||
|
data.Read (first4bytes.b, 4);
|
||||||
if (first4bytes.dw == 0)
|
if (first4bytes.dw == 0)
|
||||||
{
|
{
|
||||||
data >> first4bytes.dw;
|
data.Read (first4bytes.b, 4);
|
||||||
if (first4bytes.dw == MAKE_ID('I','E','N','D'))
|
if (first4bytes.dw == MAKE_ID('I','E','N','D'))
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -304,6 +306,39 @@ int FTextureManager::CreateTexture (int lumpnum, int usetype)
|
||||||
out = new FPNGTexture (lumpnum, BigLong((int)width), BigLong((int)height),
|
out = new FPNGTexture (lumpnum, BigLong((int)width), BigLong((int)height),
|
||||||
bitdepth, colortype, interlace);
|
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)
|
else if (usetype == FTexture::TEX_Flat)
|
||||||
{
|
{
|
||||||
// allow PNGs as flats but not Doom patches.
|
// 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)
|
FBuildTexture::FBuildTexture (int tilenum, const BYTE *pixels, int width, int height, int left, int top)
|
||||||
: Pixels (pixels), Spans (NULL)
|
: Pixels (pixels), Spans (NULL)
|
||||||
|
|
19
src/r_data.h
19
src/r_data.h
|
@ -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.
|
// A texture that returns a wiggly version of another texture.
|
||||||
class FWarpTexture : public FTexture
|
class FWarpTexture : public FTexture
|
||||||
{
|
{
|
||||||
|
|
|
@ -1924,6 +1924,10 @@
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\kplib.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\lumpconfigfile.cpp"
|
RelativePath=".\src\lumpconfigfile.cpp"
|
||||||
>
|
>
|
||||||
|
@ -5381,7 +5385,7 @@
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCCustomBuildTool"
|
Name="VCCustomBuildTool"
|
||||||
Description="Assembling $(InputPath)..."
|
Description="Assembling $(InputPath)..."
|
||||||
CommandLine="nasmw -o "$(IntDir)\$(InputName).obj" -d OBJ_FORMAT_win32 -f win32 "$(InputPath)""
|
CommandLine="nasmw -o "$(IntDir)\$(InputName).obj" -d OBJ_FORMAT_win32 -f win32 "$(InputPath)"
"
|
||||||
Outputs="$(IntDir)\$(InputName).obj"
|
Outputs="$(IntDir)\$(InputName).obj"
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
|
@ -5399,7 +5403,7 @@
|
||||||
<Tool
|
<Tool
|
||||||
Name="VCCustomBuildTool"
|
Name="VCCustomBuildTool"
|
||||||
Description="Assembling $(InputPath)..."
|
Description="Assembling $(InputPath)..."
|
||||||
CommandLine="nasmw -o "$(IntDir)\$(InputName).obj" -d OBJ_FORMAT_win32 -f win32 "$(InputPath)""
|
CommandLine="nasmw -o "$(IntDir)\$(InputName).obj" -d OBJ_FORMAT_win32 -f win32 "$(InputPath)"
"
|
||||||
Outputs="$(IntDir)\$(InputName).obj"
|
Outputs="$(IntDir)\$(InputName).obj"
|
||||||
/>
|
/>
|
||||||
</FileConfiguration>
|
</FileConfiguration>
|
||||||
|
|
Loading…
Reference in a new issue