Alien-FreeImage

 view release on metacpan or  search on metacpan

src/Source/FreeImage/PluginDDS.cpp  view on Meta::CPAN


#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;

src/Source/FreeImage/PluginDDS.cpp  view on Meta::CPAN

			// 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);

#if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB 
			INPLACESWAP(dst[FI_RGBA_RED], dst[FI_RGBA_BLUE]);
#endif 
			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/x-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;
}



( run in 0.811 second using v1.01-cache-2.11-cpan-63c85eba8c4 )