diff --git a/docs/rh-log.txt b/docs/rh-log.txt
index 75949ac61..f7f471264 100644
--- a/docs/rh-log.txt
+++ b/docs/rh-log.txt
@@ -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.
diff --git a/src/r_data.h b/src/r_data.h
index 97a860803..7dbb2ae94 100644
--- a/src/r_data.h
+++ b/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
@@ -238,11 +239,10 @@ public:
protected:
- static bool Check(FileReader & file);
- static FTexture *Create(FileReader & file, int lumpnum);
+ static bool Check (FileReader &file);
+ 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
@@ -274,8 +312,8 @@ public:
protected:
- static bool Check(FileReader & file);
- static FTexture *Create(FileReader & file, int lumpnum);
+ static bool Check (FileReader &file);
+ static FTexture *Create (FileReader &file, int lumpnum);
FJPEGTexture (int lumpnum, int width, int height);
int SourceLump;
diff --git a/src/textures/ddstexture.cpp b/src/textures/ddstexture.cpp
new file mode 100644
index 000000000..868bd59d9
--- /dev/null
+++ b/src/textures/ddstexture.cpp
@@ -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;
+}
diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp
index 650271147..7f42303cd 100644
--- a/src/textures/texture.cpp
+++ b/src/textures/texture.cpp
@@ -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 },
diff --git a/zdoom.vcproj b/zdoom.vcproj
index 21ccecdff..dc48972a2 100644
--- a/zdoom.vcproj
+++ b/zdoom.vcproj
@@ -1,7 +1,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -2716,14 +2724,6 @@
GeneratePreprocessedFile="0"
/>
-
-
-
@@ -2746,7 +2746,7 @@
/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -4873,6 +4803,16 @@
Outputs="$(IntDir)/$(InputName).obj"
/>
+
+
+
@@ -4897,16 +4837,6 @@
Outputs="$(IntDir)/$(InputName).obj"
/>
-
-
-
@@ -4917,6 +4847,16 @@
Outputs="$(IntDir)/$(InputName).obj"
/>
+
+
+
@@ -4941,16 +4881,6 @@
Outputs="$(IntDir)\$(InputName).obj"
/>
-
-
-
@@ -4961,6 +4891,16 @@
Outputs="$(IntDir)\$(InputName).obj"
/>
+
+
+
@@ -4985,16 +4925,6 @@
Outputs="$(IntDir)\$(InputName).obj"
/>
-
-
-
@@ -5005,6 +4935,16 @@
Outputs="$(IntDir)\$(InputName).obj"
/>
+
+
+
@@ -5029,16 +4969,6 @@
Outputs="$(IntDir)\$(InputName).obj"
/>
-
-
-
@@ -5049,6 +4979,16 @@
Outputs="$(IntDir)\$(InputName).obj"
/>
+
+
+
@@ -5120,7 +5060,7 @@
/>
+
+
+
@@ -5455,14 +5403,6 @@
Outputs="$(IntDir)\$(InputName).obj"
/>
-
-
-
-
-
-
@@ -5693,6 +5625,14 @@
GeneratePreprocessedFile="0"
/>
+
+
+
@@ -5714,7 +5654,7 @@
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -9607,14 +9619,6 @@
AdditionalIncludeDirectories="src\win32;$(NoInherit)"
/>
-
-
-
@@ -9789,7 +9793,7 @@
/>