mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-24 04:51:19 +00:00
- Fixed: FTexture::~FTexture() must destroy the associated native texture
if present. - Modified GZDoom's true color texture copy functions and added them to generate 32 bit D3D textures. Paletted TGAs and PCXs are also handled this way but I don't think these 2 formats are worth some more special handling. (Question: Is it worth it to implement special handling for paletted PNGs so that they are used as 8 bit textures internally?) SVN r608 (trunk)
This commit is contained in:
parent
457976d88d
commit
28db2d9f15
12 changed files with 773 additions and 21 deletions
|
@ -1,4 +1,12 @@
|
|||
December 20, 2007 (Changes by Graf Zahl)
|
||||
- Fixed: FTexture::~FTexture() must destroy the associated native texture
|
||||
if present.
|
||||
- Modified GZDoom's true color texture copy functions and added them
|
||||
to generate 32 bit D3D textures. Paletted TGAs and PCXs are also handled
|
||||
this way but I don't think these 2 formats are worth some more special
|
||||
handling.
|
||||
(Question: Is it worth it to implement special handling for paletted PNGs
|
||||
so that they are used as 8 bit textures internally?)
|
||||
- Fixed: DCanvas::Blit unlocked the destination twice instead of unlocking
|
||||
both dest and src. Also changed this function so that it is owned by the
|
||||
destination canvas of the operation which is necessary if it needs to
|
||||
|
|
14
src/r_data.h
14
src/r_data.h
|
@ -85,9 +85,12 @@ public:
|
|||
|
||||
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
|
||||
const BYTE *GetPixels ();
|
||||
FTextureFormat GetFormat();
|
||||
void Unload ();
|
||||
virtual void SetFrontSkyLayer ();
|
||||
|
||||
int CopyTrueColorPixels(BYTE * buffer, int buf_width, int buf_height, int x, int y);
|
||||
|
||||
protected:
|
||||
BYTE *Pixels;
|
||||
Span **Spans;
|
||||
|
@ -237,6 +240,8 @@ public:
|
|||
const BYTE *GetPixels ();
|
||||
void Unload ();
|
||||
FTextureFormat GetFormat ();
|
||||
int CopyTrueColorPixels(BYTE * buffer, int buf_width, int buf_height, int x, int y);
|
||||
bool UseBasePalette();
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -312,6 +317,8 @@ public:
|
|||
const BYTE *GetPixels ();
|
||||
void Unload ();
|
||||
FTextureFormat GetFormat ();
|
||||
int CopyTrueColorPixels(BYTE * buffer, int buf_width, int buf_height, int x, int y);
|
||||
bool UseBasePalette();
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -361,6 +368,9 @@ public:
|
|||
void Unload ();
|
||||
FTextureFormat GetFormat ();
|
||||
|
||||
int CopyTrueColorPixels(BYTE * buffer, int buf_width, int buf_height, int x, int y);
|
||||
bool UseBasePalette();
|
||||
|
||||
protected:
|
||||
int SourceLump;
|
||||
BYTE *Pixels;
|
||||
|
@ -412,6 +422,10 @@ public:
|
|||
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
|
||||
const BYTE *GetPixels ();
|
||||
void Unload ();
|
||||
FTextureFormat GetFormat ();
|
||||
|
||||
int CopyTrueColorPixels(BYTE * buffer, int buf_width, int buf_height, int x, int y);
|
||||
bool UseBasePalette();
|
||||
|
||||
protected:
|
||||
int SourceLump;
|
||||
|
|
|
@ -664,6 +664,9 @@ public:
|
|||
|
||||
// Returns the whole texture, stored in column-major order
|
||||
virtual const BYTE *GetPixels () = 0;
|
||||
|
||||
virtual int CopyTrueColorPixels(BYTE * buffer, int buf_width, int buf_height, int x, int y);
|
||||
virtual bool UseBasePalette();
|
||||
|
||||
virtual void Unload () = 0;
|
||||
|
||||
|
@ -677,7 +680,7 @@ public:
|
|||
void KillNative();
|
||||
|
||||
// Fill the native texture buffer with pixel data for this image
|
||||
virtual void FillBuffer(BYTE *buff, int pitch, FTextureFormat fmt);
|
||||
virtual void FillBuffer(BYTE *buff, int pitch, int height, FTextureFormat fmt);
|
||||
|
||||
int GetWidth () { return Width; }
|
||||
int GetHeight () { return Height; }
|
||||
|
|
|
@ -323,3 +323,91 @@ void FJPEGTexture::MakeTexture ()
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FJPEGTexture::CopyTrueColorPixels
|
||||
//
|
||||
// Preserves the full color information (unlike software mode)
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FJPEGTexture::CopyTrueColorPixels(BYTE * buffer, int buf_width, int buf_height, int x, int y)
|
||||
{
|
||||
PalEntry pe[256];
|
||||
|
||||
FWadLump lump = Wads.OpenLumpNum (SourceLump);
|
||||
JSAMPLE *buff = NULL;
|
||||
|
||||
jpeg_decompress_struct cinfo;
|
||||
jpeg_error_mgr jerr;
|
||||
|
||||
cinfo.err = jpeg_std_error(&jerr);
|
||||
cinfo.err->output_message = JPEG_OutputMessage;
|
||||
cinfo.err->error_exit = JPEG_ErrorExit;
|
||||
jpeg_create_decompress(&cinfo);
|
||||
|
||||
try
|
||||
{
|
||||
FLumpSourceMgr sourcemgr(&lump, &cinfo);
|
||||
jpeg_read_header(&cinfo, TRUE);
|
||||
|
||||
if (!((cinfo.out_color_space == JCS_RGB && cinfo.num_components == 3) ||
|
||||
(cinfo.out_color_space == JCS_CMYK && cinfo.num_components == 4) ||
|
||||
(cinfo.out_color_space == JCS_GRAYSCALE && cinfo.num_components == 1)))
|
||||
{
|
||||
Printf (TEXTCOLOR_ORANGE "Unsupported color format\n");
|
||||
throw -1;
|
||||
}
|
||||
jpeg_start_decompress(&cinfo);
|
||||
|
||||
int yc = 0;
|
||||
buff = new BYTE[cinfo.output_height * cinfo.output_width * cinfo.output_components];
|
||||
|
||||
|
||||
while (cinfo.output_scanline < cinfo.output_height)
|
||||
{
|
||||
BYTE * ptr = buff + cinfo.output_width * cinfo.output_components * yc;
|
||||
jpeg_read_scanlines(&cinfo, &ptr, 1);
|
||||
yc++;
|
||||
}
|
||||
|
||||
switch (cinfo.out_color_space)
|
||||
{
|
||||
case JCS_RGB:
|
||||
screen->CopyPixelDataRGB(buffer, buf_width, buf_height, x, y, buff, cinfo.output_width, cinfo.output_height,
|
||||
3, cinfo.output_width * cinfo.output_components, CF_RGB);
|
||||
break;
|
||||
|
||||
case JCS_GRAYSCALE:
|
||||
for(int i=0;i<256;i++) pe[i]=PalEntry(0,i,i,i); // default to a gray map
|
||||
screen->CopyPixelData(buffer, buf_width, buf_height, x, y, buff, cinfo.output_width, cinfo.output_height,
|
||||
1, cinfo.output_width, pe);
|
||||
break;
|
||||
|
||||
case JCS_CMYK:
|
||||
screen->CopyPixelDataRGB(buffer, buf_width, buf_height, x, y, buff, cinfo.output_width, cinfo.output_height,
|
||||
4, cinfo.output_width * cinfo.output_components, CF_CMYK);
|
||||
break;
|
||||
}
|
||||
jpeg_finish_decompress(&cinfo);
|
||||
}
|
||||
catch(int)
|
||||
{
|
||||
Printf (TEXTCOLOR_ORANGE " in JPEG texture %s\n", Name);
|
||||
}
|
||||
jpeg_destroy_decompress(&cinfo);
|
||||
if (buff != NULL) delete [] buff;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FJPEGTexture::UseBasePalette()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -371,6 +371,40 @@ void FMultiPatchTexture::CheckForHacks ()
|
|||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FMultipatchTexture::CopyTrueColorPixels
|
||||
//
|
||||
// Preserves the palettes of each individual patch
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FMultiPatchTexture::CopyTrueColorPixels(BYTE * buffer, int buf_width, int buf_height, int x, int y)
|
||||
{
|
||||
int retv = -1;
|
||||
|
||||
for(int i=0;i<NumParts;i++)
|
||||
{
|
||||
int ret = Parts[i].Texture->CopyTrueColorPixels(buffer, buf_width, buf_height,
|
||||
x+Parts[i].OriginX, y+Parts[i].OriginY);
|
||||
|
||||
if (ret > retv) retv = ret;
|
||||
}
|
||||
return retv;
|
||||
}
|
||||
|
||||
FTextureFormat FMultiPatchTexture::GetFormat()
|
||||
{
|
||||
if (NumParts == 1) return Parts[0].Texture->GetFormat();
|
||||
|
||||
for(int i=0;i<NumParts;i++)
|
||||
{
|
||||
if (!Parts[i].Texture->UseBasePalette()) return TEX_RGB;
|
||||
}
|
||||
return TEX_Pal;
|
||||
}
|
||||
|
||||
|
||||
void FTextureManager::AddTexturesLump (const void *lumpdata, int lumpsize, int patcheslump, int firstdup, bool texture1)
|
||||
{
|
||||
FPatchLookup *patchlookup;
|
||||
|
|
|
@ -111,6 +111,12 @@ void FPCXTexture::Unload ()
|
|||
}
|
||||
}
|
||||
|
||||
FTextureFormat FPCXTexture::GetFormat()
|
||||
{
|
||||
return TEX_RGB;
|
||||
}
|
||||
|
||||
|
||||
const BYTE *FPCXTexture::GetColumn (unsigned int column, const Span **spans_out)
|
||||
{
|
||||
if (Pixels == NULL)
|
||||
|
@ -404,3 +410,88 @@ void FPCXTexture::MakeTexture()
|
|||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FPCXTexture::CopyTrueColorPixels
|
||||
//
|
||||
// Preserves the full color information (unlike software mode)
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FPCXTexture::CopyTrueColorPixels(BYTE * buffer, int buf_width, int buf_height, int x, int y)
|
||||
{
|
||||
PalEntry pe[256];
|
||||
PCXHeader header;
|
||||
int bitcount;
|
||||
BYTE * Pixels;
|
||||
|
||||
FWadLump lump = Wads.OpenLumpNum(SourceLump);
|
||||
|
||||
lump.Read(&header, sizeof(header));
|
||||
|
||||
bitcount = header.bitsPerPixel * header.numColorPlanes;
|
||||
|
||||
if (bitcount < 24)
|
||||
{
|
||||
Pixels = new BYTE[Width*Height];
|
||||
if (bitcount < 8)
|
||||
{
|
||||
for (int i=0;i<16;i++)
|
||||
{
|
||||
pe[i] = PalEntry(header.palette[i*3],header.palette[i*3+1],header.palette[i*3+2]);
|
||||
}
|
||||
|
||||
switch (bitcount)
|
||||
{
|
||||
default:
|
||||
case 1:
|
||||
ReadPCX1bit (Pixels, lump, &header);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
ReadPCX4bits (Pixels, lump, &header);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (bitcount == 8)
|
||||
{
|
||||
BYTE c;
|
||||
lump.Seek(-769, SEEK_END);
|
||||
lump >> c;
|
||||
c=0x0c; // Apparently there's many non-compliant PCXs out there...
|
||||
if (c !=0x0c)
|
||||
{
|
||||
for(int i=0;i<256;i++) pe[i]=PalEntry(0,i,i,i); // default to a gray map
|
||||
}
|
||||
else for(int i=0;i<256;i++)
|
||||
{
|
||||
BYTE r,g,b;
|
||||
lump >> r >> g >> b;
|
||||
pe[i] = PalEntry(r,g,b);
|
||||
}
|
||||
lump.Seek(sizeof(header), SEEK_SET);
|
||||
ReadPCX8bits (Pixels, lump, &header);
|
||||
}
|
||||
screen->CopyPixelData(buffer, buf_width, buf_height, x, y, Pixels, Width, Height, 1, Width, pe);
|
||||
}
|
||||
else
|
||||
{
|
||||
Pixels = new BYTE[Width*Height * 3];
|
||||
BYTE * row = buffer;
|
||||
ReadPCX24bits (Pixels, lump, &header, 3);
|
||||
screen->CopyPixelDataRGB(buffer, buf_width, buf_height, x, y, Pixels, Width, Height, 3, Width*3, CF_RGB);
|
||||
}
|
||||
delete [] Pixels;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FPCXTexture::UseBasePalette()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -438,3 +438,99 @@ void FPNGTexture::MakeTexture ()
|
|||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FPNGTexture::CopyTrueColorPixels
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FPNGTexture::CopyTrueColorPixels(BYTE * buffer, int buf_width, int buf_height, int x, int y)
|
||||
{
|
||||
// Parse pre-IDAT chunks. I skip the CRCs. Is that bad?
|
||||
PalEntry pe[256];
|
||||
DWORD len, id;
|
||||
FWadLump lump = Wads.OpenLumpNum (SourceLump);
|
||||
static char bpp[]={1, 0, 3, 1, 2, 0, 4};
|
||||
int pixwidth = Width * bpp[ColorType];
|
||||
int transpal=false;
|
||||
|
||||
lump.Seek (33, SEEK_SET);
|
||||
for(int i=0;i<256;i++) pe[i]=PalEntry(0,i,i,i); // default to a gray map
|
||||
|
||||
lump >> len >> id;
|
||||
while (id != MAKE_ID('I','D','A','T') && id != MAKE_ID('I','E','N','D'))
|
||||
{
|
||||
len = BigLong((unsigned int)len);
|
||||
switch (id)
|
||||
{
|
||||
default:
|
||||
lump.Seek (len, SEEK_CUR);
|
||||
break;
|
||||
|
||||
case MAKE_ID('P','L','T','E'):
|
||||
for(int i=0;i<PaletteSize;i++)
|
||||
lump >> pe[i].r >> pe[i].g >> pe[i].b;
|
||||
break;
|
||||
|
||||
case MAKE_ID('t','R','N','S'):
|
||||
for(DWORD i=0;i<len;i++)
|
||||
{
|
||||
lump >> pe[i].a;
|
||||
pe[i].a=255-pe[i].a; // use inverse alpha so the default palette can be used unchanged
|
||||
if (pe[i].a!=0 && pe[i].a!=255) transpal = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
lump >> len >> len; // Skip CRC
|
||||
id = MAKE_ID('I','E','N','D');
|
||||
lump >> id;
|
||||
}
|
||||
|
||||
BYTE * Pixels = new BYTE[pixwidth * Height];
|
||||
|
||||
lump.Seek (StartOfIDAT, SEEK_SET);
|
||||
lump >> len >> id;
|
||||
M_ReadIDAT (&lump, Pixels, Width, Height, pixwidth, BitDepth, ColorType, Interlace, BigLong((unsigned int)len));
|
||||
|
||||
switch (ColorType)
|
||||
{
|
||||
case 0:
|
||||
case 3:
|
||||
screen->CopyPixelData(buffer, buf_width, buf_height, x, y, Pixels, Width, Height, 1, Width, pe);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
screen->CopyPixelDataRGB(buffer, buf_width, buf_height, x, y, Pixels, Width, Height, 3, pixwidth, CF_RGB);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
screen->CopyPixelDataRGB(buffer, buf_width, buf_height, x, y, Pixels, Width, Height, 2, pixwidth, CF_IA);
|
||||
transpal = -1;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
screen->CopyPixelDataRGB(buffer, buf_width, buf_height, x, y, Pixels, Width, Height, 4, pixwidth, CF_RGBA);
|
||||
transpal = -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
delete[] Pixels;
|
||||
return transpal;
|
||||
}
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// This doesn't check if the palette is identical with the base palette
|
||||
// I don't think it's worth the hassle because it's only of importance
|
||||
// when compositing multipatch textures.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FPNGTexture::UseBasePalette()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -125,6 +125,7 @@ FTexture::FTexture ()
|
|||
|
||||
FTexture::~FTexture ()
|
||||
{
|
||||
KillNative();
|
||||
}
|
||||
|
||||
bool FTexture::CheckModified ()
|
||||
|
@ -428,19 +429,19 @@ void FTexture::KillNative()
|
|||
// color data. Note that the buffer expects row-major data, since that's
|
||||
// generally more convenient for any non-Doom image formats, and it doesn't
|
||||
// need to be used by any of Doom's column drawing routines.
|
||||
void FTexture::FillBuffer(BYTE *buff, int pitch, FTextureFormat fmt)
|
||||
void FTexture::FillBuffer(BYTE *buff, int pitch, int height, FTextureFormat fmt)
|
||||
{
|
||||
const BYTE *pix;
|
||||
int x, y, w, h, stride;
|
||||
|
||||
w = GetWidth();
|
||||
h = GetHeight();
|
||||
pix = GetPixels();
|
||||
|
||||
switch (fmt)
|
||||
{
|
||||
case TEX_Pal:
|
||||
case TEX_Gray:
|
||||
pix = GetPixels();
|
||||
stride = pitch - w;
|
||||
for (y = 0; y < h; ++y)
|
||||
{
|
||||
|
@ -456,23 +457,7 @@ void FTexture::FillBuffer(BYTE *buff, int pitch, FTextureFormat fmt)
|
|||
break;
|
||||
|
||||
case TEX_RGB:
|
||||
stride = pitch - w * 4;
|
||||
for (y = 0; y < h; ++y)
|
||||
{
|
||||
const BYTE *pix2 = pix;
|
||||
for (x = 0; x < w; ++x)
|
||||
{
|
||||
const PalEntry *pal = &GPalette.BaseColors[*pix2];
|
||||
buff[0] = pal->b;
|
||||
buff[1] = pal->g;
|
||||
buff[2] = pal->r;
|
||||
buff[3] = pal->a;
|
||||
buff += 4;
|
||||
pix2 += h;
|
||||
}
|
||||
pix++;
|
||||
buff += stride;
|
||||
}
|
||||
CopyTrueColorPixels(buff, pitch, height, 0, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -480,6 +465,37 @@ void FTexture::FillBuffer(BYTE *buff, int pitch, FTextureFormat fmt)
|
|||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FTexture::CopyTrueColorPixels
|
||||
//
|
||||
// this is the generic case that can handle
|
||||
// any properly implemented texture for software rendering.
|
||||
// Its drawback is that it is limited to the base palette which is
|
||||
// why all classes that handle different palettes should subclass this
|
||||
// method
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FTexture::CopyTrueColorPixels(BYTE * buffer, int buf_width, int buf_height, int x, int y)
|
||||
{
|
||||
PalEntry * palette = screen->GetPalette();
|
||||
palette[0].a=255; // temporarily modify the first color's alpha
|
||||
screen->CopyPixelData(buffer, buf_width, buf_height, x, y,
|
||||
GetPixels(), Width, Height, Height, 1,
|
||||
palette);
|
||||
|
||||
palette[0].a=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool FTexture::UseBasePalette()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FDummyTexture::FDummyTexture ()
|
||||
{
|
||||
Width = 64;
|
||||
|
|
|
@ -378,5 +378,159 @@ void FTGATexture::MakeTexture ()
|
|||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FTGATexture::CopyTrueColorPixels
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
int FTGATexture::CopyTrueColorPixels(BYTE * buffer, int buf_width, int buf_height, int x, int y)
|
||||
{
|
||||
PalEntry pe[256];
|
||||
FWadLump lump = Wads.OpenLumpNum (SourceLump);
|
||||
TGAHeader hdr;
|
||||
WORD w;
|
||||
BYTE r,g,b,a;
|
||||
BYTE * sbuffer;
|
||||
int transval = 0;
|
||||
|
||||
lump.Read(&hdr, sizeof(hdr));
|
||||
lump.Seek(hdr.id_len, SEEK_CUR);
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
hdr.width = LittleShort(hdr.width);
|
||||
hdr.height = LittleShort(hdr.height);
|
||||
hdr.cm_first = LittleShort(hdr.cm_first);
|
||||
hdr.cm_length = LittleShort(hdr.cm_length);
|
||||
#endif
|
||||
|
||||
if (hdr.has_cm)
|
||||
{
|
||||
memset(pe, 0, 256*sizeof(PalEntry));
|
||||
for (int i = hdr.cm_first; i < hdr.cm_first + hdr.cm_length && i < 256; i++)
|
||||
{
|
||||
switch (hdr.cm_size)
|
||||
{
|
||||
case 15:
|
||||
case 16:
|
||||
lump >> w;
|
||||
r = (w & 0x001F) << 3;
|
||||
g = (w & 0x03E0) >> 2;
|
||||
b = (w & 0x7C00) >> 7;
|
||||
a = 255;
|
||||
break;
|
||||
|
||||
case 24:
|
||||
lump >> b >> g >> r;
|
||||
a=255;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
lump >> b >> g >> r >> a;
|
||||
if ((hdr.img_desc&15)!=8) a=255;
|
||||
else if (a!=0 && a!=255) transval = true;
|
||||
break;
|
||||
|
||||
default: // should never happen
|
||||
r=g=b=a=0;
|
||||
break;
|
||||
}
|
||||
pe[i] = PalEntry(255-a, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
int Size = Width * Height * (hdr.bpp>>3);
|
||||
sbuffer = new BYTE[Size];
|
||||
|
||||
if (hdr.img_type < 4) // uncompressed
|
||||
{
|
||||
lump.Read(sbuffer, Size);
|
||||
}
|
||||
else // compressed
|
||||
{
|
||||
ReadCompressed(lump, sbuffer, hdr.bpp>>3);
|
||||
}
|
||||
|
||||
BYTE * ptr = sbuffer;
|
||||
int step_x = (hdr.bpp>>3);
|
||||
int Pitch = Width * step_x;
|
||||
|
||||
if (hdr.img_desc&32)
|
||||
{
|
||||
ptr += (Width-1) * step_x;
|
||||
step_x =- step_x;
|
||||
}
|
||||
if (!(hdr.img_desc&64))
|
||||
{
|
||||
ptr += (Height-1) * Pitch;
|
||||
Pitch = -Pitch;
|
||||
}
|
||||
|
||||
switch (hdr.img_type & 7)
|
||||
{
|
||||
case 1: // paletted
|
||||
screen->CopyPixelData(buffer, buf_width, buf_height, x, y, ptr, Width, Height, step_x, Pitch, pe);
|
||||
break;
|
||||
|
||||
case 2: // RGB
|
||||
switch (hdr.bpp)
|
||||
{
|
||||
case 15:
|
||||
case 16:
|
||||
screen->CopyPixelDataRGB(buffer, buf_width, buf_height, x, y, ptr, Width, Height, step_x, Pitch, CF_RGB555);
|
||||
break;
|
||||
|
||||
case 24:
|
||||
screen->CopyPixelDataRGB(buffer, buf_width, buf_height, x, y, ptr, Width, Height, step_x, Pitch, CF_BGR);
|
||||
break;
|
||||
|
||||
case 32:
|
||||
if ((hdr.img_desc&15)!=8) // 32 bits without a valid alpha channel
|
||||
{
|
||||
screen->CopyPixelDataRGB(buffer, buf_width, buf_height, x, y, ptr, Width, Height, step_x, Pitch, CF_BGR);
|
||||
}
|
||||
else
|
||||
{
|
||||
screen->CopyPixelDataRGB(buffer, buf_width, buf_height, x, y, ptr, Width, Height, step_x, Pitch, CF_BGRA);
|
||||
transval = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // Grayscale
|
||||
switch (hdr.bpp)
|
||||
{
|
||||
case 8:
|
||||
for(int i=0;i<256;i++) pe[i]=PalEntry(0,i,i,i); // gray map
|
||||
screen->CopyPixelData(buffer, buf_width, buf_height, x, y, ptr, Width, Height, step_x, Pitch, pe);
|
||||
break;
|
||||
|
||||
case 16:
|
||||
screen->CopyPixelDataRGB(buffer, buf_width, buf_height, x, y, ptr, Width, Height, step_x, Pitch, CF_I16);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
delete [] sbuffer;
|
||||
return transval;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
bool FTGATexture::UseBasePalette()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
131
src/v_video.cpp
131
src/v_video.cpp
|
@ -797,6 +797,137 @@ FNativeTexture *DFrameBuffer::CreatePalette(const PalEntry *pal)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// multi-format pixel copy with colormap application
|
||||
// requires one of the previously defined conversion classes to work
|
||||
//
|
||||
//===========================================================================
|
||||
template<class T>
|
||||
void iCopyColors(unsigned char * pout, const unsigned char * pin, int count, int step)
|
||||
{
|
||||
for(int i=0;i<count;i++)
|
||||
{
|
||||
pout[0]=T::R(pin);
|
||||
pout[1]=T::G(pin);
|
||||
pout[2]=T::B(pin);
|
||||
pout[3]=T::A(pin);
|
||||
pout+=4;
|
||||
pin+=step;
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*CopyFunc)(unsigned char * pout, const unsigned char * pin, int count, int step);
|
||||
|
||||
static CopyFunc copyfuncs[]={
|
||||
iCopyColors<cRGB>,
|
||||
iCopyColors<cRGBA>,
|
||||
iCopyColors<cIA>,
|
||||
iCopyColors<cCMYK>,
|
||||
iCopyColors<cBGR>,
|
||||
iCopyColors<cBGRA>,
|
||||
iCopyColors<cI16>,
|
||||
iCopyColors<cRGB555>,
|
||||
iCopyColors<cPalEntry>
|
||||
};
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Clips the copy area for CopyPixelData functions
|
||||
//
|
||||
//===========================================================================
|
||||
bool DFrameBuffer::ClipCopyPixelRect(int texwidth, int texheight, int &originx, int &originy,
|
||||
const BYTE *&patch, int &srcwidth, int &srcheight, int step_x, int step_y)
|
||||
{
|
||||
// clip source rectangle to destination
|
||||
if (originx<0)
|
||||
{
|
||||
srcwidth+=originx;
|
||||
patch-=originx*step_x;
|
||||
originx=0;
|
||||
if (srcwidth<=0) return false;
|
||||
}
|
||||
if (originx+srcwidth>texwidth)
|
||||
{
|
||||
srcwidth=texwidth-originx;
|
||||
if (srcwidth<=0) return false;
|
||||
}
|
||||
|
||||
if (originy<0)
|
||||
{
|
||||
srcheight+=originy;
|
||||
patch-=originy*step_y;
|
||||
originy=0;
|
||||
if (srcheight<=0) return false;
|
||||
}
|
||||
if (originy+srcheight>texheight)
|
||||
{
|
||||
srcheight=texheight-originy;
|
||||
if (srcheight<=0) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// True Color texture copy function
|
||||
//
|
||||
//===========================================================================
|
||||
void DFrameBuffer::CopyPixelDataRGB(BYTE * buffer, int texwidth, int texheight, int originx, int originy,
|
||||
const BYTE * patch, int srcwidth, int srcheight, int step_x, int step_y,
|
||||
int ct)
|
||||
{
|
||||
if (ClipCopyPixelRect(texwidth, texheight, originx, originy, patch, srcwidth, srcheight, step_x, step_y))
|
||||
{
|
||||
buffer+=4*originx + 4*texwidth*originy;
|
||||
for (int y=0;y<srcheight;y++)
|
||||
{
|
||||
copyfuncs[ct](&buffer[4*y*texwidth], &patch[y*step_y], srcwidth, step_x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Paletted to True Color texture copy function
|
||||
//
|
||||
//===========================================================================
|
||||
void DFrameBuffer::CopyPixelData(BYTE * buffer, int texwidth, int texheight, int originx, int originy,
|
||||
const BYTE * patch, int srcwidth, int srcheight,
|
||||
int step_x, int step_y, PalEntry * palette)
|
||||
{
|
||||
int x,y,pos;
|
||||
|
||||
if (ClipCopyPixelRect(texwidth, texheight, originx, originy, patch, srcwidth, srcheight, step_x, step_y))
|
||||
{
|
||||
buffer+=4*originx + 4*texwidth*originy;
|
||||
|
||||
for (y=0;y<srcheight;y++)
|
||||
{
|
||||
pos=4*(y*texwidth);
|
||||
for (x=0;x<srcwidth;x++,pos+=4)
|
||||
{
|
||||
int v=(unsigned char)patch[y*step_y+x*step_x];
|
||||
if (palette[v].a==0)
|
||||
{
|
||||
buffer[pos]=palette[v].r;
|
||||
buffer[pos+1]=palette[v].g;
|
||||
buffer[pos+2]=palette[v].b;
|
||||
buffer[pos+3]=255-palette[v].a;
|
||||
}
|
||||
else if (palette[v].a!=255)
|
||||
{
|
||||
buffer[pos ] = (buffer[pos ] * palette[v].a + palette[v].r * (1-palette[v].a)) / 255;
|
||||
buffer[pos+1] = (buffer[pos+1] * palette[v].a + palette[v].g * (1-palette[v].a)) / 255;
|
||||
buffer[pos+2] = (buffer[pos+2] * palette[v].a + palette[v].b * (1-palette[v].a)) / 255;
|
||||
buffer[pos+3] = clamp<int>(buffer[pos+3] + (( 255-buffer[pos+3]) * (255-palette[v].a))/255, 0, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FNativeTexture::~FNativeTexture()
|
||||
{
|
||||
}
|
||||
|
|
117
src/v_video.h
117
src/v_video.h
|
@ -316,6 +316,16 @@ public:
|
|||
// Create a palette texture from a 256-entry palette.
|
||||
virtual FNativeTexture *CreatePalette(const PalEntry *pal);
|
||||
|
||||
// texture copy functions
|
||||
virtual void CopyPixelDataRGB(BYTE * buffer, int texwidth, int texheight, int originx, int originy,
|
||||
const BYTE * patch, int pix_width, int pix_height, int step_x, int step_y,
|
||||
int ct);
|
||||
|
||||
virtual void CopyPixelData(BYTE * buffer, int texwidth, int texheight, int originx, int originy,
|
||||
const BYTE * patch, int pix_width, int pix_height,
|
||||
int step_x, int step_y, PalEntry * palette);
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
virtual void PaletteChanged () = 0;
|
||||
virtual int QueryNewPalette () = 0;
|
||||
|
@ -327,6 +337,10 @@ protected:
|
|||
|
||||
DFrameBuffer () {}
|
||||
|
||||
bool ClipCopyPixelRect(int texwidth, int texheight, int &originx, int &originy,
|
||||
const BYTE *&patch, int &srcwidth, int &srcheight, int step_x, int step_y);
|
||||
|
||||
|
||||
int RateX;
|
||||
|
||||
private:
|
||||
|
@ -385,4 +399,107 @@ extern "C" void ASM_PatchPitch (void);
|
|||
int CheckRatio (int width, int height);
|
||||
extern const int BaseRatioSizes[5][4];
|
||||
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// True color conversion classes for the different pixel formats
|
||||
// used by the supported texture formats
|
||||
//
|
||||
//===========================================================================
|
||||
struct cRGB
|
||||
{
|
||||
static unsigned char R(const unsigned char * p) { return p[0]; }
|
||||
static unsigned char G(const unsigned char * p) { return p[1]; }
|
||||
static unsigned char B(const unsigned char * p) { return p[2]; }
|
||||
static unsigned char A(const unsigned char * p) { return 255; }
|
||||
static int Gray(const unsigned char * p) { return (p[0]*77 + p[1]*143 + p[2]*36)>>8; }
|
||||
};
|
||||
|
||||
struct cRGBA
|
||||
{
|
||||
static unsigned char R(const unsigned char * p) { return p[0]; }
|
||||
static unsigned char G(const unsigned char * p) { return p[1]; }
|
||||
static unsigned char B(const unsigned char * p) { return p[2]; }
|
||||
static unsigned char A(const unsigned char * p) { return p[3]; }
|
||||
static int Gray(const unsigned char * p) { return (p[0]*77 + p[1]*143 + p[2]*36)>>8; }
|
||||
};
|
||||
|
||||
struct cIA
|
||||
{
|
||||
static unsigned char R(const unsigned char * p) { return p[0]; }
|
||||
static unsigned char G(const unsigned char * p) { return p[0]; }
|
||||
static unsigned char B(const unsigned char * p) { return p[0]; }
|
||||
static unsigned char A(const unsigned char * p) { return p[1]; }
|
||||
static int Gray(const unsigned char * p) { return p[0]; }
|
||||
};
|
||||
|
||||
struct cCMYK
|
||||
{
|
||||
static unsigned char R(const unsigned char * p) { return p[3] - (((256-p[0])*p[3]) >> 8); }
|
||||
static unsigned char G(const unsigned char * p) { return p[3] - (((256-p[1])*p[3]) >> 8); }
|
||||
static unsigned char B(const unsigned char * p) { return p[3] - (((256-p[2])*p[3]) >> 8); }
|
||||
static unsigned char A(const unsigned char * p) { return 255; }
|
||||
static int Gray(const unsigned char * p) { return (R(p)*77 + G(p)*143 + B(p)*36)>>8; }
|
||||
};
|
||||
|
||||
struct cBGR
|
||||
{
|
||||
static unsigned char R(const unsigned char * p) { return p[2]; }
|
||||
static unsigned char G(const unsigned char * p) { return p[1]; }
|
||||
static unsigned char B(const unsigned char * p) { return p[0]; }
|
||||
static unsigned char A(const unsigned char * p) { return 255; }
|
||||
static int Gray(const unsigned char * p) { return (p[2]*77 + p[1]*143 + p[0]*36)>>8; }
|
||||
};
|
||||
|
||||
struct cBGRA
|
||||
{
|
||||
static unsigned char R(const unsigned char * p) { return p[2]; }
|
||||
static unsigned char G(const unsigned char * p) { return p[1]; }
|
||||
static unsigned char B(const unsigned char * p) { return p[0]; }
|
||||
static unsigned char A(const unsigned char * p) { return p[3]; }
|
||||
static int Gray(const unsigned char * p) { return (p[2]*77 + p[1]*143 + p[0]*36)>>8; }
|
||||
};
|
||||
|
||||
struct cI16
|
||||
{
|
||||
static unsigned char R(const unsigned char * p) { return p[1]; }
|
||||
static unsigned char G(const unsigned char * p) { return p[1]; }
|
||||
static unsigned char B(const unsigned char * p) { return p[1]; }
|
||||
static unsigned char A(const unsigned char * p) { return 255; }
|
||||
static int Gray(const unsigned char * p) { return p[1]; }
|
||||
};
|
||||
|
||||
struct cRGB555
|
||||
{
|
||||
static unsigned char R(const unsigned char * p) { return (((*(WORD*)p)&0x1f)<<3); }
|
||||
static unsigned char G(const unsigned char * p) { return (((*(WORD*)p)&0x3e0)>>2); }
|
||||
static unsigned char B(const unsigned char * p) { return (((*(WORD*)p)&0x7c00)>>7); }
|
||||
static unsigned char A(const unsigned char * p) { return p[1]; }
|
||||
static int Gray(const unsigned char * p) { return (R(p)*77 + G(p)*143 + B(p)*36)>>8; }
|
||||
};
|
||||
|
||||
struct cPalEntry
|
||||
{
|
||||
static unsigned char R(const unsigned char * p) { return ((PalEntry*)p)->r; }
|
||||
static unsigned char G(const unsigned char * p) { return ((PalEntry*)p)->g; }
|
||||
static unsigned char B(const unsigned char * p) { return ((PalEntry*)p)->b; }
|
||||
static unsigned char A(const unsigned char * p) { return ((PalEntry*)p)->a; }
|
||||
static int Gray(const unsigned char * p) { return (R(p)*77 + G(p)*143 + B(p)*36)>>8; }
|
||||
};
|
||||
|
||||
enum ColorType
|
||||
{
|
||||
CF_RGB,
|
||||
CF_RGBA,
|
||||
CF_IA,
|
||||
CF_CMYK,
|
||||
CF_BGR,
|
||||
CF_BGRA,
|
||||
CF_I16,
|
||||
CF_RGB555,
|
||||
CF_PalEntry
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // __V_VIDEO_H__
|
||||
|
|
|
@ -1200,7 +1200,7 @@ bool D3DTex::Update()
|
|||
{
|
||||
return false;
|
||||
}
|
||||
GameTex->FillBuffer((BYTE *)lrect.pBits, lrect.Pitch, ToTexFmt(desc.Format));
|
||||
GameTex->FillBuffer((BYTE *)lrect.pBits, lrect.Pitch, rect.bottom, ToTexFmt(desc.Format));
|
||||
Tex->UnlockRect(0);
|
||||
return true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue