mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 14:51:40 +00:00
- Added support for DDS textures compressed with DXT1, DXT3, or DXT5.
SVN r309 (trunk)
This commit is contained in:
parent
848097cd2e
commit
a69d7f529e
5 changed files with 1424 additions and 710 deletions
|
@ -1,3 +1,6 @@
|
|||
August 24, 2006
|
||||
- Added support for DDS textures compressed with DXT1, DXT3, or DXT5.
|
||||
|
||||
August 23, 2006
|
||||
- Fixed incorrect spawn ID for cell pack.
|
||||
|
||||
|
|
40
src/r_data.h
40
src/r_data.h
|
@ -28,6 +28,7 @@
|
|||
#include "r_state.h"
|
||||
#include "v_video.h"
|
||||
|
||||
class FWadLump;
|
||||
|
||||
|
||||
// A texture that doesn't really exist
|
||||
|
@ -242,7 +243,6 @@ protected:
|
|||
static FTexture *Create (FileReader &file, int lumpnum);
|
||||
FPNGTexture (FileReader &lump, int lumpnum, int width, int height, BYTE bitdepth, BYTE colortype, BYTE interlace);
|
||||
|
||||
|
||||
int SourceLump;
|
||||
BYTE *Pixels;
|
||||
Span **Spans;
|
||||
|
@ -261,6 +261,44 @@ protected:
|
|||
};
|
||||
|
||||
|
||||
// A DDS image, with DXTx compression
|
||||
class FDDSTexture : public FTexture
|
||||
{
|
||||
public:
|
||||
~FDDSTexture ();
|
||||
|
||||
const BYTE *GetColumn (unsigned int column, const Span **spans_out);
|
||||
const BYTE *GetPixels ();
|
||||
void Unload ();
|
||||
|
||||
protected:
|
||||
static bool Check (FileReader &file);
|
||||
static FTexture *Create (FileReader &file, int lumpnum);
|
||||
FDDSTexture (FileReader &lump, int lumpnum, void *surfdesc);
|
||||
|
||||
int SourceLump;
|
||||
BYTE *Pixels;
|
||||
Span **Spans;
|
||||
|
||||
DWORD Format;
|
||||
|
||||
DWORD RMask, GMask, BMask, AMask;
|
||||
BYTE RShiftL, GShiftL, BShiftL, AShiftL;
|
||||
BYTE RShiftR, GShiftR, BShiftR, AShiftR;
|
||||
|
||||
SDWORD Pitch;
|
||||
DWORD LinearSize;
|
||||
|
||||
static void CalcBitShift (DWORD mask, BYTE *lshift, BYTE *rshift);
|
||||
|
||||
void MakeTexture ();
|
||||
void ReadRGB (FWadLump &lump);
|
||||
void DecompressDXT1 (FWadLump &lump);
|
||||
void DecompressDXT3 (FWadLump &lump, bool premultiplied);
|
||||
void DecompressDXT5 (FWadLump &lump, bool premultiplied);
|
||||
|
||||
friend class FTexture;
|
||||
};
|
||||
|
||||
// A JPEG image
|
||||
class FJPEGTexture : public FTexture
|
||||
|
|
668
src/textures/ddstexture.cpp
Normal file
668
src/textures/ddstexture.cpp
Normal file
|
@ -0,0 +1,668 @@
|
|||
/*
|
||||
** pngtexture.cpp
|
||||
** Texture class for DDS images
|
||||
**
|
||||
**---------------------------------------------------------------------------
|
||||
** Copyright 2006 Randy Heit
|
||||
** All rights reserved.
|
||||
**
|
||||
** Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions
|
||||
** are met:
|
||||
**
|
||||
** 1. Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** 2. Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in the
|
||||
** documentation and/or other materials provided with the distribution.
|
||||
** 3. The name of the author may not be used to endorse or promote products
|
||||
** derived from this software without specific prior written permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
**---------------------------------------------------------------------------
|
||||
**
|
||||
** DDS is short for "DirectDraw Surface" and is essentially that. It's
|
||||
** interesting to us because it is a standard file format for DXTC/S3TC
|
||||
** encoded images. Look up "DDS File Reference" in the DirectX SDK or
|
||||
** the online MSDN documentation to the specs for this file format. Look up
|
||||
** "Compressed Texture Resources" for information about DXTC encoding.
|
||||
**
|
||||
** Perhaps the most important part of DXTC to realize is that every 4x4
|
||||
** pixel block can only have four different colors, and only two of those
|
||||
** are discrete. So depending on the texture, there may be very noticable
|
||||
** quality degradation, or it may look virtually indistinguishable from
|
||||
** the uncompressed texture.
|
||||
**
|
||||
** Note: Although this class supports reading RGB textures from a DDS,
|
||||
** DO NOT use DDS images with plain RGB data. PNG does everything useful
|
||||
** better. Since DDS lets the R, G, B, and A components lie anywhere in
|
||||
** the pixel data, it is fairly inefficient to process.
|
||||
*/
|
||||
|
||||
#include "doomtype.h"
|
||||
#include "files.h"
|
||||
#include "r_local.h"
|
||||
#include "w_wad.h"
|
||||
#include "templates.h"
|
||||
|
||||
// Since we want this to compile under Linux too, we need to define this
|
||||
// stuff ourselves instead of including a DirectX header.
|
||||
|
||||
#define ID_DDS MAKE_ID('D','D','S',' ')
|
||||
#define ID_DXT1 MAKE_ID('D','X','T','1')
|
||||
#define ID_DXT2 MAKE_ID('D','X','T','2')
|
||||
#define ID_DXT3 MAKE_ID('D','X','T','3')
|
||||
#define ID_DXT4 MAKE_ID('D','X','T','4')
|
||||
#define ID_DXT5 MAKE_ID('D','X','T','5')
|
||||
|
||||
// Bits in dwFlags
|
||||
#define DDSD_CAPS 0x00000001
|
||||
#define DDSD_HEIGHT 0x00000002
|
||||
#define DDSD_WIDTH 0x00000004
|
||||
#define DDSD_PITCH 0x00000008
|
||||
#define DDSD_PIXELFORMAT 0x00001000
|
||||
#define DDSD_MIPMAPCOUNT 0x00020000
|
||||
#define DDSD_LINEARSIZE 0x00080000
|
||||
#define DDSD_DEPTH 0x00800000
|
||||
|
||||
// Bits in ddpfPixelFormat
|
||||
#define DDPF_ALPHAPIXELS 0x00000001
|
||||
#define DDPF_FOURCC 0x00000004
|
||||
#define DDPF_RGB 0x00000040
|
||||
|
||||
// Bits in DDSCAPS2.dwCaps1
|
||||
#define DDSCAPS_COMPLEX 0x00000008
|
||||
#define DDSCAPS_TEXTURE 0x00001000
|
||||
#define DDSCAPS_MIPMAP 0x00400000
|
||||
|
||||
// Bits in DDSCAPS2.dwCaps2
|
||||
#define DDSCAPS2_CUBEMAP 0x00000200
|
||||
#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
|
||||
#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
|
||||
#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
|
||||
#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
|
||||
#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
|
||||
#define DDSCAPS2_CUBEMAP_NEGATIZEZ 0x00008000
|
||||
#define DDSCAPS2_VOLUME 0x00200000
|
||||
|
||||
struct DDPIXELFORMAT
|
||||
{
|
||||
DWORD Size; // Must be 32
|
||||
DWORD Flags;
|
||||
DWORD FourCC;
|
||||
DWORD RGBBitCount;
|
||||
DWORD RBitMask, GBitMask, BBitMask;
|
||||
DWORD RGBAlphaBitMask;
|
||||
};
|
||||
|
||||
struct DDCAPS2
|
||||
{
|
||||
DWORD Caps1, Caps2;
|
||||
DWORD Reserved[2];
|
||||
};
|
||||
|
||||
struct DDSURFACEDESC2
|
||||
{
|
||||
DWORD Size; // Must be 124. DevIL claims some writers set it to 'DDS ' instead.
|
||||
DWORD Flags;
|
||||
DWORD Height;
|
||||
DWORD Width;
|
||||
union
|
||||
{
|
||||
SDWORD Pitch;
|
||||
DWORD LinearSize;
|
||||
};
|
||||
DWORD Depth;
|
||||
DWORD MipMapCount;
|
||||
DWORD Reserved1[11];
|
||||
DDPIXELFORMAT PixelFormat;
|
||||
DDCAPS2 Caps;
|
||||
DWORD Reserved2;
|
||||
};
|
||||
|
||||
struct DDSFileHeader
|
||||
{
|
||||
DWORD Magic;
|
||||
DDSURFACEDESC2 Desc;
|
||||
};
|
||||
|
||||
bool FDDSTexture::Check (FileReader &file)
|
||||
{
|
||||
DDSFileHeader Header;
|
||||
|
||||
file.Seek (0, SEEK_SET);
|
||||
if (file.Read (&Header, sizeof(Header)) != sizeof(Header))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Header.Magic == ID_DDS &&
|
||||
(LittleLong(Header.Desc.Size) == sizeof(DDSURFACEDESC2) || Header.Desc.Size == ID_DDS) &&
|
||||
LittleLong(Header.Desc.PixelFormat.Size) == sizeof(DDPIXELFORMAT) &&
|
||||
(LittleLong(Header.Desc.Flags) & (DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT)) == (DDSD_CAPS | DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT) &&
|
||||
Header.Desc.Width != 0 &&
|
||||
Header.Desc.Height != 0;
|
||||
}
|
||||
|
||||
FTexture *FDDSTexture::Create (FileReader &data, int lumpnum)
|
||||
{
|
||||
union
|
||||
{
|
||||
DDSURFACEDESC2 surfdesc;
|
||||
DWORD byteswapping[sizeof(DDSURFACEDESC2) / 4];
|
||||
};
|
||||
|
||||
data.Seek (4, SEEK_SET);
|
||||
data.Read (&surfdesc, sizeof(surfdesc));
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
// Every single element of the header is a DWORD
|
||||
for (unsigned int i = 0; i < sizeof(DDSURFACEDESC2) / 4; ++i)
|
||||
{
|
||||
byteswapping[i] = LittleLong(byteswapping[i]);
|
||||
}
|
||||
// Undo the byte swap for the pixel format
|
||||
surfdesc.PixelFormat.FourCC = LittleLong(surfdesc.PixelFormat.FourCC);
|
||||
#endif
|
||||
|
||||
if (surfdesc.PixelFormat.Flags & DDPF_FOURCC)
|
||||
{
|
||||
// Check for supported FourCC
|
||||
if (surfdesc.PixelFormat.FourCC != ID_DXT1 &&
|
||||
surfdesc.PixelFormat.FourCC != ID_DXT2 &&
|
||||
surfdesc.PixelFormat.FourCC != ID_DXT3 &&
|
||||
surfdesc.PixelFormat.FourCC != ID_DXT4 &&
|
||||
surfdesc.PixelFormat.FourCC != ID_DXT5)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (!(surfdesc.Flags & DDSD_LINEARSIZE))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (surfdesc.PixelFormat.Flags & DDPF_RGB)
|
||||
{
|
||||
if ((surfdesc.PixelFormat.RGBBitCount >> 3) < 1 ||
|
||||
(surfdesc.PixelFormat.RGBBitCount >> 3) > 4)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if ((surfdesc.Flags & DDSD_PITCH) && (surfdesc.Pitch <= 0))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return new FDDSTexture (data, lumpnum, &surfdesc);
|
||||
}
|
||||
|
||||
FDDSTexture::FDDSTexture (FileReader &lump, int lumpnum, void *vsurfdesc)
|
||||
: SourceLump(lumpnum), Pixels(0), Spans(0)
|
||||
{
|
||||
DDSURFACEDESC2 *surf = (DDSURFACEDESC2 *)vsurfdesc;
|
||||
|
||||
Wads.GetLumpName (Name, lumpnum);
|
||||
Name[8] = 0;
|
||||
|
||||
UseType = TEX_MiscPatch;
|
||||
LeftOffset = 0;
|
||||
TopOffset = 0;
|
||||
bMasked = false;
|
||||
|
||||
Width = WORD(surf->Width);
|
||||
Height = WORD(surf->Height);
|
||||
CalcBitSize ();
|
||||
|
||||
if (surf->PixelFormat.Flags & DDPF_FOURCC)
|
||||
{
|
||||
Format = surf->PixelFormat.FourCC;
|
||||
Pitch = 0;
|
||||
LinearSize = surf->LinearSize;
|
||||
}
|
||||
else // DDPF_RGB
|
||||
{
|
||||
Format = surf->PixelFormat.RGBBitCount >> 3;
|
||||
CalcBitShift (RMask = surf->PixelFormat.RBitMask, &RShiftL, &RShiftR);
|
||||
CalcBitShift (GMask = surf->PixelFormat.GBitMask, &GShiftL, &GShiftR);
|
||||
CalcBitShift (BMask = surf->PixelFormat.BBitMask, &BShiftL, &BShiftR);
|
||||
if (surf->PixelFormat.Flags & DDPF_ALPHAPIXELS)
|
||||
{
|
||||
CalcBitShift (AMask = surf->PixelFormat.RGBAlphaBitMask, &AShiftL, &AShiftR);
|
||||
}
|
||||
else
|
||||
{
|
||||
AMask = 0;
|
||||
AShiftL = AShiftR = 0;
|
||||
}
|
||||
if (surf->Flags & DDSD_PITCH)
|
||||
{
|
||||
Pitch = surf->Pitch;
|
||||
}
|
||||
else
|
||||
{
|
||||
Pitch = (Width * Format + 3) & ~3;
|
||||
}
|
||||
LinearSize = Pitch * Height;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the number of bits the color must be shifted to produce
|
||||
// an 8-bit value, as in:
|
||||
//
|
||||
// c = (color & mask) << lshift;
|
||||
// c |= c >> rshift;
|
||||
// c >>= 24;
|
||||
//
|
||||
// For any color of at least 4 bits, this ensures that the result
|
||||
// of the calculation for c will be fully saturated, given a maximum
|
||||
// value for the input bit mask.
|
||||
void FDDSTexture::CalcBitShift (DWORD mask, BYTE *lshiftp, BYTE *rshiftp)
|
||||
{
|
||||
BYTE shift;
|
||||
|
||||
if (mask == 0)
|
||||
{
|
||||
*lshiftp = *rshiftp = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
shift = 0;
|
||||
while ((mask & 0x80000000) == 0)
|
||||
{
|
||||
mask <<= 1;
|
||||
shift++;
|
||||
}
|
||||
*lshiftp = shift;
|
||||
|
||||
shift = 0;
|
||||
while (mask & 0x80000000)
|
||||
{
|
||||
mask <<= 1;
|
||||
shift++;
|
||||
}
|
||||
*rshiftp = shift;
|
||||
}
|
||||
|
||||
FDDSTexture::~FDDSTexture ()
|
||||
{
|
||||
Unload ();
|
||||
if (Spans != NULL)
|
||||
{
|
||||
FreeSpans (Spans);
|
||||
Spans = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void FDDSTexture::Unload ()
|
||||
{
|
||||
if (Pixels != NULL)
|
||||
{
|
||||
delete[] Pixels;
|
||||
Pixels = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const BYTE *FDDSTexture::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 = Spans[column];
|
||||
}
|
||||
return Pixels + column*Height;
|
||||
}
|
||||
|
||||
const BYTE *FDDSTexture::GetPixels ()
|
||||
{
|
||||
if (Pixels == NULL)
|
||||
{
|
||||
MakeTexture ();
|
||||
}
|
||||
return Pixels;
|
||||
}
|
||||
|
||||
void FDDSTexture::MakeTexture ()
|
||||
{
|
||||
FWadLump lump = Wads.OpenLumpNum (SourceLump);
|
||||
|
||||
Pixels = new BYTE[Width*Height];
|
||||
|
||||
lump.Seek (sizeof(DDSURFACEDESC2) + 4, SEEK_SET);
|
||||
|
||||
if (Format >= 1 && Format <= 4) // RGB: Format is # of bytes per pixel
|
||||
{
|
||||
ReadRGB (lump);
|
||||
}
|
||||
else if (Format == ID_DXT1)
|
||||
{
|
||||
DecompressDXT1 (lump);
|
||||
}
|
||||
else if (Format == ID_DXT3 || Format == ID_DXT2)
|
||||
{
|
||||
DecompressDXT3 (lump, Format == ID_DXT2);
|
||||
}
|
||||
else if (Format == ID_DXT5 || Format == ID_DXT4)
|
||||
{
|
||||
DecompressDXT5 (lump, Format == ID_DXT4);
|
||||
}
|
||||
if (Spans == NULL)
|
||||
{
|
||||
Spans = CreateSpans (Pixels);
|
||||
}
|
||||
}
|
||||
|
||||
void FDDSTexture::ReadRGB (FWadLump &lump)
|
||||
{
|
||||
DWORD x, y;
|
||||
DWORD amask = AMask == 0 ? 0 : 0x80000000 >> AShiftL;
|
||||
BYTE *linebuff = new BYTE[Pitch];
|
||||
|
||||
for (y = Height; y > 0; --y)
|
||||
{
|
||||
BYTE *buffp = linebuff;
|
||||
BYTE *pixelp = Pixels + y;
|
||||
lump.Read (linebuff, Pitch);
|
||||
for (x = Width; x > 0; --x)
|
||||
{
|
||||
DWORD c;
|
||||
if (Format == 4)
|
||||
{
|
||||
c = LittleLong(*(DWORD *)buffp); buffp += 4;
|
||||
}
|
||||
else if (Format == 2)
|
||||
{
|
||||
c = LittleShort(*(WORD *)buffp); buffp += 2;
|
||||
}
|
||||
else if (Format == 3)
|
||||
{
|
||||
c = buffp[0] | (buffp[1] << 8) | (buffp[2] << 16); buffp += 3;
|
||||
}
|
||||
else // Format == 1
|
||||
{
|
||||
c = *buffp++;
|
||||
}
|
||||
if (amask == 0 || (c & amask))
|
||||
{
|
||||
DWORD r = (c & RMask) << RShiftL; r |= r >> RShiftR;
|
||||
DWORD g = (c & GMask) << GShiftL; g |= g >> GShiftR;
|
||||
DWORD b = (c & BMask) << BShiftL; b |= b >> BShiftR;
|
||||
*pixelp = RGB32k[r >> 27][g >> 27][b >> 27];
|
||||
}
|
||||
else
|
||||
{
|
||||
*pixelp = 0;
|
||||
bMasked = true;
|
||||
}
|
||||
pixelp += Height;
|
||||
}
|
||||
}
|
||||
delete[] linebuff;
|
||||
}
|
||||
|
||||
void FDDSTexture::DecompressDXT1 (FWadLump &lump)
|
||||
{
|
||||
const long blocklinelen = ((Width + 3) >> 2) << 3;
|
||||
BYTE *blockbuff = new BYTE[blocklinelen];
|
||||
BYTE *block;
|
||||
PalEntry color[4];
|
||||
BYTE palcol[4];
|
||||
int ox, oy, x, y, i;
|
||||
|
||||
color[0].a = 255;
|
||||
color[1].a = 255;
|
||||
color[2].a = 255;
|
||||
|
||||
for (oy = 0; oy < Height; oy += 4)
|
||||
{
|
||||
lump.Read (blockbuff, blocklinelen);
|
||||
block = blockbuff;
|
||||
for (ox = 0; ox < Width; ox += 4)
|
||||
{
|
||||
WORD color16[2] = { LittleShort(((WORD *)block)[0]), LittleShort(((WORD *)block)[1]) };
|
||||
|
||||
// Convert color from R5G6B5 to R8G8B8.
|
||||
for (i = 1; i >= 0; --i)
|
||||
{
|
||||
color[i].r = ((color16[i] & 0xF800) >> 8) | (color16[i] >> 13);
|
||||
color[i].g = ((color16[i] & 0x07E0) >> 3) | ((color16[i] & 0x0600) >> 9);
|
||||
color[i].b = ((color16[i] & 0x001F) << 3) | ((color16[i] & 0x001C) >> 2);
|
||||
}
|
||||
if (color16[0] > color16[1])
|
||||
{ // Four-color block: derive the other two colors.
|
||||
color[2].r = (color[0].r + color[0].r + color[1].r + 1) / 3;
|
||||
color[2].g = (color[0].g + color[0].g + color[1].g + 1) / 3;
|
||||
color[2].b = (color[0].b + color[0].b + color[1].b + 1) / 3;
|
||||
|
||||
color[3].r = (color[0].r + color[1].r + color[1].r + 1) / 3;
|
||||
color[3].g = (color[0].g + color[1].g + color[1].g + 1) / 3;
|
||||
color[3].b = (color[0].b + color[1].b + color[1].b + 1) / 3;
|
||||
color[3].a = 255;
|
||||
}
|
||||
else
|
||||
{ // Three-color block: derive the other color.
|
||||
color[2].r = (color[0].r + color[1].r) / 2;
|
||||
color[2].g = (color[0].g + color[1].g) / 2;
|
||||
color[2].b = (color[0].b + color[1].b) / 2;
|
||||
|
||||
color[3].a = color[3].b = color[3].g = color[3].r = 0;
|
||||
|
||||
// If you have a three-color block, presumably that transparent
|
||||
// color is going to be used.
|
||||
bMasked = true;
|
||||
}
|
||||
// Pick colors from the palette for each of the four colors.
|
||||
for (i = 3; i >= 0; --i)
|
||||
{
|
||||
palcol[i] = color[i].a ? RGB32k[color[i].r >> 3][color[i].g >> 3][color[i].b >> 3] : 0;
|
||||
}
|
||||
// Now decode this 4x4 block to the pixel buffer.
|
||||
for (y = 0; y < 4; ++y)
|
||||
{
|
||||
if (oy + y >= Height)
|
||||
{
|
||||
break;
|
||||
}
|
||||
BYTE yslice = block[4 + y];
|
||||
for (x = 0; x < 4; ++x)
|
||||
{
|
||||
if (ox + x >= Width)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Pixels[oy + y + (ox + x) * Height] = palcol[(yslice >> (x + x)) & 3];
|
||||
}
|
||||
}
|
||||
block += 8;
|
||||
}
|
||||
}
|
||||
delete[] blockbuff;
|
||||
}
|
||||
|
||||
// DXT3: Decompression is identical to DXT1, except every 64-bit block is
|
||||
// preceded by another 64-bit block with explicit alpha values.
|
||||
|
||||
void FDDSTexture::DecompressDXT3 (FWadLump &lump, bool premultiplied)
|
||||
{
|
||||
const long blocklinelen = ((Width + 3) >> 2) << 4;
|
||||
BYTE *blockbuff = new BYTE[blocklinelen];
|
||||
BYTE *block;
|
||||
PalEntry color[4];
|
||||
BYTE palcol[4];
|
||||
int ox, oy, x, y, i;
|
||||
|
||||
for (oy = 0; oy < Height; oy += 4)
|
||||
{
|
||||
lump.Read (blockbuff, blocklinelen);
|
||||
block = blockbuff;
|
||||
for (ox = 0; ox < Width; ox += 4)
|
||||
{
|
||||
WORD color16[2] = { LittleShort(((WORD *)block)[4]), LittleShort(((WORD *)block)[5]) };
|
||||
|
||||
// Convert color from R5G6B5 to R8G8B8.
|
||||
for (i = 1; i >= 0; --i)
|
||||
{
|
||||
color[i].r = ((color16[i] & 0xF800) >> 8) | (color16[i] >> 13);
|
||||
color[i].g = ((color16[i] & 0x07E0) >> 3) | ((color16[i] & 0x0600) >> 9);
|
||||
color[i].b = ((color16[i] & 0x001F) << 3) | ((color16[i] & 0x001C) >> 2);
|
||||
}
|
||||
// Derive the other two colors.
|
||||
color[2].r = (color[0].r + color[0].r + color[1].r + 1) / 3;
|
||||
color[2].g = (color[0].g + color[0].g + color[1].g + 1) / 3;
|
||||
color[2].b = (color[0].b + color[0].b + color[1].b + 1) / 3;
|
||||
|
||||
color[3].r = (color[0].r + color[1].r + color[1].r + 1) / 3;
|
||||
color[3].g = (color[0].g + color[1].g + color[1].g + 1) / 3;
|
||||
color[3].b = (color[0].b + color[1].b + color[1].b + 1) / 3;
|
||||
|
||||
// Pick colors from the palette for each of the four colors.
|
||||
for (i = 3; i >= 0; --i)
|
||||
{
|
||||
palcol[i] = RGB32k[color[i].r >> 3][color[i].g >> 3][color[i].b >> 3];
|
||||
}
|
||||
// Now decode this 4x4 block to the pixel buffer.
|
||||
for (y = 0; y < 4; ++y)
|
||||
{
|
||||
if (oy + y >= Height)
|
||||
{
|
||||
break;
|
||||
}
|
||||
BYTE yslice = block[12 + y];
|
||||
WORD yalphaslice = LittleShort(((WORD *)block)[y]);
|
||||
for (x = 0; x < 4; ++x)
|
||||
{
|
||||
if (ox + x >= Width)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Pixels[oy + y + (ox + x) * Height] = ((yalphaslice >> (x*4)) & 15) < 8 ?
|
||||
(bMasked = true, 0) : palcol[(yslice >> (x + x)) & 3];
|
||||
}
|
||||
}
|
||||
block += 16;
|
||||
}
|
||||
}
|
||||
delete[] blockbuff;
|
||||
}
|
||||
|
||||
// DXT5: Decompression is identical to DXT3, except every 64-bit alpha block
|
||||
// contains interpolated alpha values, similar to the 64-bit color block.
|
||||
|
||||
void FDDSTexture::DecompressDXT5 (FWadLump &lump, bool premultiplied)
|
||||
{
|
||||
const long blocklinelen = ((Width + 3) >> 2) << 4;
|
||||
BYTE *blockbuff = new BYTE[blocklinelen];
|
||||
BYTE *block;
|
||||
PalEntry color[4];
|
||||
BYTE palcol[4];
|
||||
DWORD yalphaslice;
|
||||
int ox, oy, x, y, i;
|
||||
|
||||
for (oy = 0; oy < Height; oy += 4)
|
||||
{
|
||||
lump.Read (blockbuff, blocklinelen);
|
||||
block = blockbuff;
|
||||
for (ox = 0; ox < Width; ox += 4)
|
||||
{
|
||||
WORD color16[2] = { LittleShort(((WORD *)block)[4]), LittleShort(((WORD *)block)[5]) };
|
||||
BYTE alpha[8];
|
||||
|
||||
// Calculate the eight alpha values.
|
||||
alpha[0] = block[0];
|
||||
alpha[1] = block[1];
|
||||
|
||||
if (alpha[0] > alpha[1])
|
||||
{ // Eight-alpha block: derive the other six alphas.
|
||||
for (i = 0; i < 6; ++i)
|
||||
{
|
||||
alpha[i + 2] = ((6 - i) * alpha[0] + (i + 1) * alpha[1] + 3) / 7;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Six-alpha block: derive the other four alphas.
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
alpha[i + 2] = ((4 - i) * alpha[0] + (i + 1) * alpha[1] + 2) / 5;
|
||||
}
|
||||
alpha[6] = 0;
|
||||
alpha[7] = 255;
|
||||
}
|
||||
|
||||
// Convert color from R5G6B5 to R8G8B8.
|
||||
for (i = 1; i >= 0; --i)
|
||||
{
|
||||
color[i].r = ((color16[i] & 0xF800) >> 8) | (color16[i] >> 13);
|
||||
color[i].g = ((color16[i] & 0x07E0) >> 3) | ((color16[i] & 0x0600) >> 9);
|
||||
color[i].b = ((color16[i] & 0x001F) << 3) | ((color16[i] & 0x001C) >> 2);
|
||||
}
|
||||
// Derive the other two colors.
|
||||
color[2].r = (color[0].r + color[0].r + color[1].r + 1) / 3;
|
||||
color[2].g = (color[0].g + color[0].g + color[1].g + 1) / 3;
|
||||
color[2].b = (color[0].b + color[0].b + color[1].b + 1) / 3;
|
||||
|
||||
color[3].r = (color[0].r + color[1].r + color[1].r + 1) / 3;
|
||||
color[3].g = (color[0].g + color[1].g + color[1].g + 1) / 3;
|
||||
color[3].b = (color[0].b + color[1].b + color[1].b + 1) / 3;
|
||||
|
||||
// Pick colors from the palette for each of the four colors.
|
||||
for (i = 3; i >= 0; --i)
|
||||
{
|
||||
palcol[i] = RGB32k[color[i].r >> 3][color[i].g >> 3][color[i].b >> 3];
|
||||
}
|
||||
// Now decode this 4x4 block to the pixel buffer.
|
||||
for (y = 0; y < 4; ++y)
|
||||
{
|
||||
if (oy + y >= Height)
|
||||
{
|
||||
break;
|
||||
}
|
||||
// Alpha values are stored in 3 bytes for 2 rows
|
||||
if ((y & 0) == 0)
|
||||
{
|
||||
yalphaslice = block[y*3] | (block[y*3+1] << 8) | (block[y*3+2] << 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
yalphaslice >>= 12;
|
||||
}
|
||||
BYTE yslice = block[12 + y];
|
||||
for (x = 0; x < 4; ++x)
|
||||
{
|
||||
if (ox + x >= Width)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Pixels[oy + y + (ox + x) * Height] = alpha[((yalphaslice >> (x*3)) & 7)] < 128 ?
|
||||
(bMasked = true, 0) : palcol[(yslice >> (x + x)) & 3];
|
||||
}
|
||||
}
|
||||
block += 16;
|
||||
}
|
||||
}
|
||||
delete[] blockbuff;
|
||||
}
|
|
@ -67,8 +67,9 @@ FTexture * FTexture::CreateTexture (int lumpnum, int usetype)
|
|||
{ FIMGZTexture::Check, FIMGZTexture::Create, FTexture::TEX_Any },
|
||||
{ FPNGTexture::Check, FPNGTexture::Create, FTexture::TEX_Any },
|
||||
{ FJPEGTexture::Check, FJPEGTexture::Create, FTexture::TEX_Any },
|
||||
{ FTGATexture::Check, FTGATexture::Create, FTexture::TEX_Any },
|
||||
{ FDDSTexture::Check, FDDSTexture::Create, FTexture::TEX_Any },
|
||||
{ FPCXTexture::Check, FPCXTexture::Create, FTexture::TEX_Any },
|
||||
{ FTGATexture::Check, FTGATexture::Create, FTexture::TEX_Any },
|
||||
{ FRawPageTexture::Check, FRawPageTexture::Create, FTexture::TEX_MiscPatch },
|
||||
{ FFlatTexture::Check, FFlatTexture::Create, FTexture::TEX_Flat },
|
||||
{ FPatchTexture::Check, FPatchTexture::Create, FTexture::TEX_Any },
|
||||
|
|
1412
zdoom.vcproj
1412
zdoom.vcproj
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue