text: // ==========================================================
  // DDS Loader
  //
  // Design and implementation by
  // - Volker Gärtner (volkerg@gmx.at)
  // - Sherman Wilcox
  //
  // This file is part of FreeImage 3
  //
  // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
  // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
  // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
  // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
  // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
  // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
  // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
  // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
  // THIS DISCLAIMER.
  //
  // Use at your own risk!
  // ==========================================================
  
  #include "FreeImage.h"
  #include "Utilities.h"
  
  // ----------------------------------------------------------
  //   Definitions for the DDS format
  // ----------------------------------------------------------
  
  #ifdef _WIN32
  #pragma pack(push, 1)
  #else
  #pragma pack(1)
  #endif
  
  typedef struct tagDDPIXELFORMAT {
  	DWORD dwSize;	// size of this structure (must be 32)
  	DWORD dwFlags;	// see DDPF_*
  	DWORD dwFourCC;
  	DWORD dwRGBBitCount;	// Total number of bits for RGB formats
  	DWORD dwRBitMask;
  	DWORD dwGBitMask;
  	DWORD dwBBitMask;
  	DWORD dwRGBAlphaBitMask;
  } DDPIXELFORMAT;
  
  // DIRECTDRAW PIXELFORMAT FLAGS
  enum {
  	DDPF_ALPHAPIXELS = 0x00000001l,	// surface has alpha channel
  	DDPF_ALPHA		 = 0x00000002l,	// alpha only
  	DDPF_FOURCC		 = 0x00000004l,	// FOURCC available
  	DDPF_RGB		 = 0x00000040l	// RGB(A) bitmap
  };
  
  typedef struct tagDDCAPS2 {
  	DWORD dwCaps1;	// Zero or more of the DDSCAPS_* members
  	DWORD dwCaps2;	// Zero or more of the DDSCAPS2_* members
  	DWORD dwReserved[2];
  } DDCAPS2;
  
  // DIRECTDRAWSURFACE CAPABILITY FLAGS
  enum {
  	DDSCAPS_ALPHA	= 0x00000002l, // alpha only surface
  	DDSCAPS_COMPLEX	= 0x00000008l, // complex surface structure
  	DDSCAPS_TEXTURE	= 0x00001000l, // used as texture (should always be set)
  	DDSCAPS_MIPMAP	= 0x00400000l  // Mipmap present
  };
  
  enum {
  	DDSCAPS2_CUBEMAP			= 0x00000200L,
  	DDSCAPS2_CUBEMAP_POSITIVEX	= 0x00000400L,
  	DDSCAPS2_CUBEMAP_NEGATIVEX	= 0x00000800L,
  	DDSCAPS2_CUBEMAP_POSITIVEY	= 0x00001000L,
  	DDSCAPS2_CUBEMAP_NEGATIVEY	= 0x00002000L,
  	DDSCAPS2_CUBEMAP_POSITIVEZ	= 0x00004000L,
  	DDSCAPS2_CUBEMAP_NEGATIVEZ	= 0x00008000L,
  	DDSCAPS2_VOLUME				= 0x00200000L
  };
  
  typedef struct tagDDSURFACEDESC2 {
  	DWORD dwSize;	// size of this structure (must be 124)
  	DWORD dwFlags;	// combination of the DDSS_* flags
  	DWORD dwHeight;
  	DWORD dwWidth;
  	DWORD dwPitchOrLinearSize;
  	DWORD dwDepth;	// Depth of a volume texture
  	DWORD dwMipMapCount;
  	DWORD dwReserved1[11];
  	DDPIXELFORMAT ddpfPixelFormat;
  	DDCAPS2 ddsCaps;
  	DWORD dwReserved2;
  } DDSURFACEDESC2;
  
  enum {
  	DDSD_CAPS			= 0x00000001l,
  	DDSD_HEIGHT			= 0x00000002l,
  	DDSD_WITH			= 0x00000004l,
  	DDSD_PITCH			= 0x00000008l,
  	DDSD_ALPHABITDEPTH  = 0x00000080l,
  	DDSD_PIXELFORMAT	= 0x00001000l,
  	DDSD_MIPMAPCOUNT	= 0x00020000l,
  	DDSD_LINEARSIZE		= 0x00080000l,
  	DDSD_DEPTH			= 0x00800000l
  };
  
  typedef struct tagDDSHEADER {
  	DWORD dwMagic;			// FOURCC: "DDS "
  	DDSURFACEDESC2 surfaceDesc;
  } DDSHEADER;
  
  #define MAKEFOURCC(ch0, ch1, ch2, ch3) \
  	((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) |   \
      ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
  
  #define FOURCC_DXT1	MAKEFOURCC('D','X','T','1')
  #define FOURCC_DXT2	MAKEFOURCC('D','X','T','2')
  #define FOURCC_DXT3	MAKEFOURCC('D','X','T','3')
  #define FOURCC_DXT4	MAKEFOURCC('D','X','T','4')
  #define FOURCC_DXT5	MAKEFOURCC('D','X','T','5')
  
  // ----------------------------------------------------------
  //   Structures used by DXT textures
  // ----------------------------------------------------------
  
  typedef struct tagColor8888 {
  	BYTE b;
  	BYTE g;
  	BYTE r;
  	BYTE a;
  } Color8888;
  
  typedef struct tagColor565 {
  	WORD b : 5;
  	WORD g : 6;
  	WORD r : 5;
  } Color565;
  
  typedef struct tagDXTColBlock {
  	Color565 colors[2];
  	BYTE row[4];
  } DXTColBlock;
  
  typedef struct tagDXTAlphaBlockExplicit {
  	WORD row[4];
  } DXTAlphaBlockExplicit;
  
  typedef struct tagDXTAlphaBlock3BitLinear {
  	BYTE alpha[2];
  	BYTE data[6];
  } DXTAlphaBlock3BitLinear;
  
  typedef struct tagDXT1Block
  {
  	DXTColBlock color;
  } DXT1Block;
  
  typedef struct tagDXT3Block {		// also used by dxt2
  	DXTAlphaBlockExplicit alpha;
  	DXTColBlock color;
  } DXT3Block;
  
  typedef struct tagDXT5Block {		// also used by dxt4
  	DXTAlphaBlock3BitLinear alpha;
  	DXTColBlock color;
  } DXT5Block;
  
  #ifdef _WIN32
  #	pragma pack(pop)
  #else
  #	pragma pack()
  #endif
  
  // ----------------------------------------------------------
  //   Internal functions
  // ----------------------------------------------------------
  #ifdef FREEIMAGE_BIGENDIAN
  static void
  SwapHeader(DDSHEADER *header) {
  	SwapLong(&header->dwMagic);
  	SwapLong(&header->surfaceDesc.dwSize);
  	SwapLong(&header->surfaceDesc.dwFlags);
  	SwapLong(&header->surfaceDesc.dwHeight);
  	SwapLong(&header->surfaceDesc.dwWidth);
  	SwapLong(&header->surfaceDesc.dwPitchOrLinearSize);
  	SwapLong(&header->surfaceDesc.dwDepth);
  	SwapLong(&header->surfaceDesc.dwMipMapCount);
  	for(int i=0; i<11; i++) {
  		SwapLong(&header->surfaceDesc.dwReserved1[i]);
  	}
  	SwapLong(&header->surfaceDesc.ddpfPixelFormat.dwSize);
  	SwapLong(&header->surfaceDesc.ddpfPixelFormat.dwFlags);
  	SwapLong(&header->surfaceDesc.ddpfPixelFormat.dwFourCC);
  	SwapLong(&header->surfaceDesc.ddpfPixelFormat.dwRGBBitCount);
  	SwapLong(&header->surfaceDesc.ddpfPixelFormat.dwRBitMask);
  	SwapLong(&header->surfaceDesc.ddpfPixelFormat.dwGBitMask);
  	SwapLong(&header->surfaceDesc.ddpfPixelFormat.dwBBitMask);
  	SwapLong(&header->surfaceDesc.ddpfPixelFormat.dwRGBAlphaBitMask);
  	SwapLong(&header->surfaceDesc.ddsCaps.dwCaps1);
  	SwapLong(&header->surfaceDesc.ddsCaps.dwCaps2);
  	SwapLong(&header->surfaceDesc.ddsCaps.dwReserved[0]);
  	SwapLong(&header->surfaceDesc.ddsCaps.dwReserved[1]);
  	SwapLong(&header->surfaceDesc.dwReserved2);
  }
  #endif
  
  // ==========================================================
  
  // Get the 4 possible colors for a block
  //
  static void 
  GetBlockColors (const DXTColBlock &block, Color8888 colors[4], bool isDXT1) {
  	int i;
  	// expand from 565 to 888
  	for (i = 0; i < 2; i++)	{
  		colors[i].a = 0xff;
  		/*
  		colors[i].r = (BYTE)(block.colors[i].r * 0xff / 0x1f);
  		colors[i].g = (BYTE)(block.colors[i].g * 0xff / 0x3f);
  		colors[i].b = (BYTE)(block.colors[i].b * 0xff / 0x1f);
  		*/
  		colors[i].r = (BYTE)((block.colors[i].r << 3U) | (block.colors[i].r >> 2U));
  		colors[i].g = (BYTE)((block.colors[i].g << 2U) | (block.colors[i].g >> 4U));
  		colors[i].b = (BYTE)((block.colors[i].b << 3U) | (block.colors[i].b >> 2U));
  	}
  
  	WORD *wCol = (WORD *)block.colors;
  	if (wCol[0] > wCol[1] || !isDXT1) {
  		// 4 color block
  		for (i = 0; i < 2; i++)	{
  			colors[i + 2].a = 0xff;
  			colors[i + 2].r = (BYTE)((WORD (colors[0].r) * (2 - i) + WORD (colors[1].r) * (1 + i)) / 3);
  			colors[i + 2].g = (BYTE)((WORD (colors[0].g) * (2 - i) + WORD (colors[1].g) * (1 + i)) / 3);
  			colors[i + 2].b = (BYTE)((WORD (colors[0].b) * (2 - i) + WORD (colors[1].b) * (1 + i)) / 3);
  		}
  	}
  	else {
  		// 3 color block, number 4 is transparent
  		colors[2].a = 0xff;
  		colors[2].r = (BYTE)((WORD (colors[0].r) + WORD (colors[1].r)) / 2);
  		colors[2].g = (BYTE)((WORD (colors[0].g) + WORD (colors[1].g)) / 2);
  		colors[2].b = (BYTE)((WORD (colors[0].b) + WORD (colors[1].b)) / 2);
  
  		colors[3].a = 0x00;
  		colors[3].g = 0x00;
  		colors[3].b = 0x00;
  		colors[3].r = 0x00;
  	}
  }
  
  struct DXT_INFO_1 {
  	typedef DXT1Block Block;
  	enum {
  		isDXT1 = 1,
  		bytesPerBlock = 8
  	};
  };
  
  struct DXT_INFO_3 {
  	typedef DXT3Block Block;
  	enum {
  		isDXT1 = 1,
  		bytesPerBlock = 16
  	};
  };
  
  struct DXT_INFO_5 {
  	typedef DXT5Block Block;
  	enum
  	{
  		isDXT1 = 1,
  		bytesPerBlock = 16
  	};
  };
  
  template <class INFO> class DXT_BLOCKDECODER_BASE {
  protected:
  	Color8888 m_colors[4];
  	const typename INFO::Block *m_pBlock;
  	unsigned m_colorRow;
  
  public:
  	void Setup (const BYTE *pBlock) {
  		m_pBlock = (const typename INFO::Block *)pBlock;
  		GetBlockColors (m_pBlock->color, m_colors, INFO::isDXT1);
  	}
  
  	void SetY (int y) {
  		m_colorRow = m_pBlock->color.row[y];
  	}
  
  	void GetColor (int x, int y, Color8888 &color) {
  		unsigned bits = (m_colorRow >> (x * 2)) & 3;
  		color = m_colors[bits];
  	}
  };
  
  class DXT_BLOCKDECODER_1 : public DXT_BLOCKDECODER_BASE <DXT_INFO_1> {
  public:
  	typedef DXT_INFO_1 INFO;
  };
  
  class DXT_BLOCKDECODER_3 : public DXT_BLOCKDECODER_BASE <DXT_INFO_3> {
  public:
  	typedef DXT_BLOCKDECODER_BASE <DXT_INFO_3> base;
  	typedef DXT_INFO_3 INFO;
  
  protected:
  	unsigned m_alphaRow;
  
  public:
  	void SetY (int y) {
  		base::SetY (y);
  		m_alphaRow = m_pBlock->alpha.row[y];
  	}
  
  	void GetColor (int x, int y, Color8888 &color) {
  		base::GetColor (x, y, color);
  		const unsigned bits = (m_alphaRow >> (x * 4)) & 0xF;
  		color.a = (BYTE)((bits * 0xFF) / 0xF);
  	}
  };
  
  class DXT_BLOCKDECODER_5 : public DXT_BLOCKDECODER_BASE <DXT_INFO_5> {
  public:
  	typedef DXT_BLOCKDECODER_BASE <DXT_INFO_5> base;
  	typedef DXT_INFO_5 INFO;
  
  protected:
  	unsigned m_alphas[8];
  	unsigned m_alphaBits;
  	int m_offset;
  
  public:
  	void Setup (const BYTE *pBlock) {
  		base::Setup (pBlock);
  
  		const DXTAlphaBlock3BitLinear &block = m_pBlock->alpha;
  		m_alphas[0] = block.alpha[0];
  		m_alphas[1] = block.alpha[1];
  		if (m_alphas[0] > m_alphas[1]) {
  			// 8 alpha block
  			for (int i = 0; i < 6; i++) {
  				m_alphas[i + 2] = ((6 - i) * m_alphas[0] + (1 + i) * m_alphas[1] + 3) / 7;
  			}
  		}
  		else {
  			// 6 alpha block
  			for (int i = 0; i < 4; i++) {
  				m_alphas[i + 2] = ((4 - i) * m_alphas[0] + (1 + i) * m_alphas[1] + 2) / 5;
  			}
  			m_alphas[6] = 0;
  			m_alphas[7] = 0xFF;
  		}
  
  	}
  
  	void SetY (int y) {
  		base::SetY (y);
  		int i = y / 2;
  		const DXTAlphaBlock3BitLinear &block = m_pBlock->alpha;
  		m_alphaBits = unsigned(block.data[0 + i * 3]) | (unsigned(block.data[1 + i * 3]) << 8)
  			| (unsigned(block.data[2 + i * 3]) << 16);
  		m_offset = (y & 1) * 12;
  	}
  
  	void GetColor (int x, int y, Color8888 &color) {
  		base::GetColor (x, y, color);
  		unsigned bits = (m_alphaBits >> (x * 3 + m_offset)) & 7;
  		color.a = (BYTE)m_alphas[bits];
  	}
  };
  
  template <class DECODER> void DecodeDXTBlock (BYTE *dstData, const BYTE *srcBlock, long dstPitch, int bw, int bh) {
  	DECODER decoder;
  	decoder.Setup (srcBlock);
  	for (int y = 0; y < bh; y++) {
  		BYTE *dst = dstData - y * dstPitch;
  		decoder.SetY (y);
  		for (int x = 0; x < bw; x++) {
  			decoder.GetColor (x, y, (Color8888 &)*dst);
  			dst += 4;
  		}
  	}
  }
  
  // ==========================================================
  // Plugin Interface
  // ==========================================================
  
  static int s_format_id;
  
  // ==========================================================
  // Internal functions
  // ==========================================================
  
  static FIBITMAP *
  LoadRGB (DDSURFACEDESC2 &desc, FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
  	int width = (int)desc.dwWidth & ~3;
  	int height = (int)desc.dwHeight & ~3;
  	int bpp = (int)desc.ddpfPixelFormat.dwRGBBitCount;
  	
  	// allocate a new dib
  	FIBITMAP *dib = FreeImage_Allocate (width, height, bpp, desc.ddpfPixelFormat.dwRBitMask,
  		desc.ddpfPixelFormat.dwGBitMask, desc.ddpfPixelFormat.dwBBitMask);
  	if (dib == NULL)
  		return NULL;
  
  #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
  		// Calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit)
  		int bytespp = FreeImage_GetLine(dib) / FreeImage_GetWidth(dib);
  #endif
  	
  	// read the file
  	int line   = CalculateLine(width, bpp);
  	int filePitch = (desc.dwFlags & DDSD_PITCH) ? (int)desc.dwPitchOrLinearSize : line;
  	long delta = (long)filePitch - (long)line;
  	for (int i = 0; i < height; i++) {
  		BYTE *pixels = FreeImage_GetScanLine(dib, height - i - 1);
  		io->read_proc (pixels, 1, line, handle);
  		io->seek_proc (handle, delta, SEEK_CUR);
  #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
   		for(int x = 0; x < width; x++) {
  			INPLACESWAP(pixels[FI_RGBA_RED],pixels[FI_RGBA_BLUE]);
  			pixels += bytespp;
  		}
  #endif
  	}
  	
  	// enable transparency
  	FreeImage_SetTransparent (dib, (desc.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) ? TRUE : FALSE);
  
  	if (!(desc.ddpfPixelFormat.dwFlags & DDPF_ALPHAPIXELS) && bpp == 32) {
  		// no transparency: convert to 24-bit
  		FIBITMAP *old = dib;
  		dib = FreeImage_ConvertTo24Bits (old);
  		FreeImage_Unload (old);
  	}
  	return dib;
  }
  
  template <class DECODER> static void 
  LoadDXT_Helper (FreeImageIO *io, fi_handle handle, int page, int flags, void *data, FIBITMAP *dib, int width, int height, int line) {
  	typedef typename DECODER::INFO INFO;
  	typedef typename INFO::Block Block;
  
  	Block *input_buffer = new(std::nothrow) Block[(width + 3) / 4];
  	if(!input_buffer) return;
  
  	int widthRest = (int) width & 3;
  	int heightRest = (int) height & 3;
  	int inputLine = (width + 3) / 4;
  	int y = 0;
  
  	if (height >= 4) {
  		for (; y < height; y += 4) {
  			io->read_proc (input_buffer, sizeof (typename INFO::Block), inputLine, handle);
  			// TODO: probably need some endian work here
  			BYTE *pbSrc = (BYTE *)input_buffer;
  			BYTE *pbDst = FreeImage_GetScanLine (dib, height - y - 1);
  
  			if (width >= 4) {
  				for (int x = 0; x < width; x += 4) {
  					DecodeDXTBlock <DECODER> (pbDst, pbSrc,	line, 4, 4);
  					pbSrc += INFO::bytesPerBlock;
  					pbDst += 4 * 4;
  				}
  			}
  			if (widthRest) {
  				DecodeDXTBlock <DECODER> (pbDst, pbSrc, line, widthRest, 4);
  			}
  		}
  	}
  	if (heightRest)	{
  		io->read_proc (input_buffer, sizeof (typename INFO::Block), inputLine, handle);
  		// TODO: probably need some endian work here
  		BYTE *pbSrc = (BYTE *)input_buffer;
  		BYTE *pbDst = FreeImage_GetScanLine (dib, height - y - 1);
  
  		if (width >= 4) {
  			for (int x = 0; x < width; x += 4) {
  				DecodeDXTBlock <DECODER> (pbDst, pbSrc,	line, 4, heightRest);
  				pbSrc += INFO::bytesPerBlock;
  				pbDst += 4 * 4;
  			}
  		}
  		if (widthRest) {
  			DecodeDXTBlock <DECODER> (pbDst, pbSrc,	line, widthRest, heightRest);
  		}
  
  	}
  
  	delete [] input_buffer;
  }
  
  static FIBITMAP *
  LoadDXT (int type, DDSURFACEDESC2 &desc, FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
  	int width = (int)desc.dwWidth & ~3;
  	int height = (int)desc.dwHeight & ~3;
  
  	// allocate a 32-bit dib
  	FIBITMAP *dib = FreeImage_Allocate (width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  	if (dib == NULL)
  		return NULL;
  
  	int bpp = FreeImage_GetBPP (dib);
  	int line = CalculateLine (width, bpp);
  	BYTE *bits = FreeImage_GetBits (dib);
  
  	// select the right decoder
  	switch (type) {
  		case 1:
  			LoadDXT_Helper <DXT_BLOCKDECODER_1> (io, handle, page, flags, data, dib, width, height, line);
  			break;
  		case 3:
  			LoadDXT_Helper <DXT_BLOCKDECODER_3> (io, handle, page, flags, data, dib, width, height, line);
  			break;
  		case 5:
  			LoadDXT_Helper <DXT_BLOCKDECODER_5> (io, handle, page, flags, data, dib, width, height, line);
  			break;
  	}
  	
  	return dib;
  }
  // ==========================================================
  // Plugin Implementation
  // ==========================================================
  
  static const char * DLL_CALLCONV
  Format() {
  	return "DDS";
  }
  
  static const char * DLL_CALLCONV
  Description() {
  	return "DirectX Surface";
  }
  
  static const char * DLL_CALLCONV
  Extension() {
  	return "dds";
  }
  
  static const char * DLL_CALLCONV
  RegExpr() {
  	return NULL;
  }
  
  static const char * DLL_CALLCONV
  MimeType() {
  	return "image/freeimage-dds";
  }
  
  static BOOL DLL_CALLCONV
  Validate(FreeImageIO *io, fi_handle handle) {
  	DDSHEADER header;
  	memset(&header, 0, sizeof(header));
  	io->read_proc(&header, 1, sizeof(header), handle);
  #ifdef FREEIMAGE_BIGENDIAN
  	SwapHeader(&header);
  #endif
  	if (header.dwMagic != MAKEFOURCC ('D','D','S',' '))
  		return FALSE;
  	if (header.surfaceDesc.dwSize != sizeof (header.surfaceDesc) ||
  		header.surfaceDesc.ddpfPixelFormat.dwSize != sizeof (header.surfaceDesc.ddpfPixelFormat))
  		return FALSE;
  	return TRUE;
  }
  
  static BOOL DLL_CALLCONV
  SupportsExportDepth(int depth) {
  	return FALSE;
  }
  
  static BOOL DLL_CALLCONV 
  SupportsExportType(FREE_IMAGE_TYPE type) {
  	return FALSE;
  }
  
  // ----------------------------------------------------------
  
  static void * DLL_CALLCONV
  Open(FreeImageIO *io, fi_handle handle, BOOL read) {
  	return NULL;
  }
  
  static void DLL_CALLCONV
  Close(FreeImageIO *io, fi_handle handle, void *data) {
  }
  
  // ----------------------------------------------------------
  
  static FIBITMAP * DLL_CALLCONV
  Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
  	DDSHEADER header;
  	FIBITMAP *dib = NULL;
  
  	memset(&header, 0, sizeof(header));
  	io->read_proc(&header, 1, sizeof(header), handle);
  #ifdef FREEIMAGE_BIGENDIAN
  	SwapHeader(&header);
  #endif
  	if (header.surfaceDesc.ddpfPixelFormat.dwFlags & DDPF_RGB) {
  		dib = LoadRGB (header.surfaceDesc, io, handle, page, flags, data);
  	}
  	else if (header.surfaceDesc.ddpfPixelFormat.dwFlags & DDPF_FOURCC) {
  		switch (header.surfaceDesc.ddpfPixelFormat.dwFourCC) {
  			case FOURCC_DXT1:
  				dib = LoadDXT (1, header.surfaceDesc, io, handle, page, flags, data);
  				break;
  			case FOURCC_DXT3:
  				dib = LoadDXT (3, header.surfaceDesc, io, handle, page, flags, data);
  				break;
  			case FOURCC_DXT5:
  				dib = LoadDXT (5, header.surfaceDesc, io, handle, page, flags, data);
  				break;
  		}
  	}
  	return dib;
  }
  
  /*
  static BOOL DLL_CALLCONV
  Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
  	return FALSE;
  }
  */
  
  // ==========================================================
  //   Init
  // ==========================================================
  
  void DLL_CALLCONV
  InitDDS(Plugin *plugin, int format_id) {
  	s_format_id = format_id;
  
  	plugin->format_proc = Format;
  	plugin->description_proc = Description;
  	plugin->extension_proc = Extension;
  	plugin->regexpr_proc = RegExpr;
  	plugin->open_proc = Open;
  	plugin->close_proc = Close;
  	plugin->pagecount_proc = NULL;
  	plugin->pagecapability_proc = NULL;
  	plugin->load_proc = Load;
  	plugin->save_proc = NULL;	//Save;	// not implemented (yet?)
  	plugin->validate_proc = Validate;
  	plugin->mime_proc = MimeType;
  	plugin->supports_export_bpp_proc = SupportsExportDepth;
  	plugin->supports_export_type_proc = SupportsExportType;
  	plugin->supports_icc_profiles_proc = NULL;
  }
  