1 // ==========================================================
2 // DDS Loader
3 //
4 // Design and implementation by
5 // - Volker G�rtner (volkerg@gmx.at)
6 // - Sherman Wilcox
7 // - Herv� Drolon (drolon@infonie.fr)
8 //
9 // This file is part of FreeImage 3
10 //
11 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
12 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
13 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
14 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
15 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
16 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
17 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
18 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
19 // THIS DISCLAIMER.
20 //
21 // Use at your own risk!
22 // ==========================================================
23 
24 #include "FreeImage.h"
25 #include "Utilities.h"
26 
27 // ----------------------------------------------------------
28 //   Definitions for the RGB 444 format
29 // ----------------------------------------------------------
30 #define FI16_444_RED_MASK	0x0F00
31 #define FI16_444_GREEN_MASK	0x00F0
32 #define FI16_444_BLUE_MASK	0x000F
33 #define FI16_444_RED_SHIFT		8
34 #define FI16_444_GREEN_SHIFT	4
35 #define FI16_444_BLUE_SHIFT		0
36 
37 // ----------------------------------------------------------
38 //   Definitions for RGB16 handling
39 // ----------------------------------------------------------
40 
41 /**
42 The list of possible 16-bit formats
43 */
44 typedef enum {
45 	RGB_UNKNOWN = -1,
46 	RGB444 = 1,
47 	RGB555 = 2,
48 	RGB565 = 3
49 } DDSFormat16;
50 
51 /**
52 Get the 16-bit format of an image
53 @param dwRBitMask Red mask
54 @param dwGBitMask Green mask
55 @param dwBBitMask Blue mask
56 @return Returns the 16-bit format or RGB_UNKNOWN
57 */
58 static inline DDSFormat16
GetRGB16Format(DWORD dwRBitMask,DWORD dwGBitMask,DWORD dwBBitMask)59 GetRGB16Format(DWORD dwRBitMask, DWORD dwGBitMask, DWORD dwBBitMask) {
60 	if ((dwRBitMask == FI16_444_RED_MASK) && (dwGBitMask == FI16_444_GREEN_MASK) && (dwBBitMask == FI16_444_BLUE_MASK)) {
61 		return RGB444;
62 	}
63 	if ((dwRBitMask == FI16_555_RED_MASK) && (dwGBitMask == FI16_555_GREEN_MASK) && (dwBBitMask == FI16_555_BLUE_MASK)) {
64 		return RGB555;
65 	}
66 	if ((dwRBitMask == FI16_565_RED_MASK) && (dwGBitMask == FI16_565_GREEN_MASK) && (dwBBitMask == FI16_565_BLUE_MASK)) {
67 		return RGB565;
68 	}
69 
70 	return RGB_UNKNOWN;
71 }
72 
73 /**
74 Convert a 16-bit RGB line to a 24-bit RGB line
75 @param target 24-bit Destination line
76 @param source 16-bit Source line
77 @param format 16-bit format
78 @param width_in_pixels Size of the line in pixels
79 */
80 static void
ConvertLine16To24(BYTE * target,const WORD * source,DDSFormat16 format,int width_in_pixels)81 ConvertLine16To24(BYTE *target, const WORD *source, DDSFormat16 format, int width_in_pixels) {
82 
83 	// convert from RGB 16-bit to RGB 24-bit
84 	switch (format) {
85 		case RGB444:
86 			for (int cols = 0; cols < width_in_pixels; cols++) {
87 				// extract source RGB444 pixel, set to 24-bit target
88 				target[FI_RGBA_BLUE] = (BYTE)((((source[cols] & FI16_444_BLUE_MASK) >> FI16_444_BLUE_SHIFT) * 0xFF) / 0x0F);
89 				target[FI_RGBA_GREEN] = (BYTE)((((source[cols] & FI16_444_GREEN_MASK) >> FI16_444_GREEN_SHIFT) * 0xFF) / 0x0F);
90 				target[FI_RGBA_RED] = (BYTE)((((source[cols] & FI16_444_RED_MASK) >> FI16_444_RED_SHIFT) * 0xFF) / 0x0F);
91 				target += 3;
92 			}
93 			break;
94 
95 		case RGB555:
96 			for (int cols = 0; cols < width_in_pixels; cols++) {
97 				target[FI_RGBA_RED] = (BYTE)((((source[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
98 				target[FI_RGBA_GREEN] = (BYTE)((((source[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
99 				target[FI_RGBA_BLUE] = (BYTE)((((source[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
100 				target += 3;
101 			}
102 			break;
103 
104 		case RGB565:
105 			for (int cols = 0; cols < width_in_pixels; cols++) {
106 				target[FI_RGBA_RED] = (BYTE)((((source[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
107 				target[FI_RGBA_GREEN] = (BYTE)((((source[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
108 				target[FI_RGBA_BLUE] = (BYTE)((((source[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
109 				target += 3;
110 			}
111 			break;
112 
113 		default:
114 			break;
115 	}
116 }
117 
118 // ----------------------------------------------------------
119 //   Definitions for the DDS format
120 // ----------------------------------------------------------
121 
122 #ifdef _WIN32
123 #pragma pack(push, 1)
124 #else
125 #pragma pack(1)
126 #endif
127 
128 /**
129 DDS_PIXELFORMAT structure
130 */
131 typedef struct tagDDPIXELFORMAT {
132 	/**
133 	Size of this structure (must be 32)
134 	*/
135 	DWORD dwSize;
136 	/**
137 	Values which indicate what type of data is in the surface, see DDPF_*
138 	*/
139 	DWORD dwFlags;
140 	/**
141 	Four-character codes for specifying compressed or custom formats. Possible values include: DXT1, DXT2, DXT3, DXT4, or DXT5.
142 	A FourCC of DX10 indicates the prescense of the DDS_HEADER_DXT10 extended header, and the dxgiFormat member of that structure
143 	indicates the true format. When using a four-character code, dwFlags must include DDPF_FOURCC.
144 	*/
145 	DWORD dwFourCC;
146 	/**
147     Number of bits in an RGB (possibly including alpha) format. Valid when dwFlags includes DDPF_RGB, DDPF_LUMINANCE, or DDPF_YUV.
148 	*/
149 	DWORD dwRGBBitCount;	//! Total number of bits for RGB formats
150 	/**
151 	Red (or luminance or Y) mask for reading color data. For instance, given the A8R8G8B8 format, the red mask would be 0x00ff0000.
152 	*/
153 	DWORD dwRBitMask;
154 	/**
155 	Green (or U) mask for reading color data. For instance, given the A8R8G8B8 format, the green mask would be 0x0000ff00.
156 	*/
157 	DWORD dwGBitMask;
158 	/**
159 	Blue (or V) mask for reading color data. For instance, given the A8R8G8B8 format, the blue mask would be 0x000000ff.
160 	*/
161 	DWORD dwBBitMask;
162 	/**
163 	Alpha mask for reading alpha data. dwFlags must include DDPF_ALPHAPIXELS or DDPF_ALPHA.
164 	For instance, given the A8R8G8B8 format, the alpha mask would be 0xff000000.
165 	*/
166 	DWORD dwRGBAlphaBitMask;
167 } DDPIXELFORMAT;
168 
169 /** DIRECTDRAW PIXELFORMAT FLAGS */
170 enum {
171 	/** Texture contains alpha data; dwRGBAlphaBitMask contains valid data. */
172 	DDPF_ALPHAPIXELS = 0x1,
173 	/** Used in some older DDS files for alpha channel only uncompressed data (dwRGBBitCount contains the alpha channel bitcount; dwABitMask contains valid data) */
174 	DDPF_ALPHA = 0x2,
175 	/** Texture contains compressed RGB data; dwFourCC contains valid data. */
176 	DDPF_FOURCC = 0x4,
177 	/** Texture contains uncompressed RGB data; dwRGBBitCount and the RGB masks (dwRBitMask, dwGBitMask, dwBBitMask) contain valid data. */
178 	DDPF_RGB = 0x40,
179 	/**
180 	Used in some older DDS files for YUV uncompressed data (dwRGBBitCount contains the YUV bit count;
181 	dwRBitMask contains the Y mask, dwGBitMask contains the U mask, dwBBitMask contains the V mask)
182 	*/
183 	DDPF_YUV = 0x200,
184 	/**
185 	Used in some older DDS files for single channel color uncompressed data (dwRGBBitCount contains the luminance channel bit count;
186 	dwRBitMask contains the channel mask). Can be combined with DDPF_ALPHAPIXELS for a two channel DDS file.
187 	*/
188 	DDPF_LUMINANCE = 0x20000
189 };
190 
191 typedef struct tagDDCAPS2 {
192 	DWORD dwCaps1;	//! zero or more of the DDSCAPS_* members
193 	DWORD dwCaps2;	//! zero or more of the DDSCAPS2_* members
194 	DWORD dwReserved[2];
195 } DDCAPS2;
196 
197 /**
198 DIRECTDRAWSURFACE CAPABILITY FLAGS
199 */
200 enum {
201 	/** Alpha only surface */
202 	DDSCAPS_ALPHA = 0x00000002,
203 	/**
204 	Optional; must be used on any file that contains more than one surface
205 	(a mipmap, a cubic environment map, or mipmapped volume texture).
206 	*/
207 	DDSCAPS_COMPLEX	= 0x8,
208 	/** Used as texture (should always be set) */
209 	DDSCAPS_TEXTURE	= 0x1000,
210 	/**
211 	Optional; should be used for a mipmap.
212 	*/
213 	DDSCAPS_MIPMAP	= 0x400000
214 };
215 
216 /**
217 Additional detail about the surfaces stored.
218 */
219 enum {
220 	DDSCAPS2_CUBEMAP			= 0x200,	//! Required for a cube map.
221 	DDSCAPS2_CUBEMAP_POSITIVEX	= 0x400,	//! Required when these surfaces are stored in a cube map.
222 	DDSCAPS2_CUBEMAP_NEGATIVEX	= 0x800,	//! Required when these surfaces are stored in a cube map.
223 	DDSCAPS2_CUBEMAP_POSITIVEY	= 0x1000,	//! Required when these surfaces are stored in a cube map.
224 	DDSCAPS2_CUBEMAP_NEGATIVEY	= 0x2000,	//! Required when these surfaces are stored in a cube map.
225 	DDSCAPS2_CUBEMAP_POSITIVEZ	= 0x4000,	//! Required when these surfaces are stored in a cube map.
226 	DDSCAPS2_CUBEMAP_NEGATIVEZ	= 0x8000,	//! Required when these surfaces are stored in a cube map.
227 	DDSCAPS2_VOLUME				= 0x200000	//! Required for a volume texture.
228 };
229 
230 /**
231 DDS_HEADER structure
232 */
233 typedef struct tagDDSURFACEDESC2 {
234 	/**	Size of structure. This member must be set to 124 */
235 	DWORD dwSize;
236 	/** Combination of the DDSD_* flags */
237 	DWORD dwFlags;
238 	/**	Surface height (in pixels) */
239 	DWORD dwHeight;
240 	/**	Surface width (in pixels) */
241 	DWORD dwWidth;
242 	/**
243 	The pitch or number of bytes per scan line in an uncompressed texture;
244 	the total number of bytes in the top level texture for a compressed texture.
245 	For information about how to compute the pitch, see the DDS File Layout section of the Programming Guide for DDS.
246 	*/
247 	DWORD dwPitchOrLinearSize;
248 	/**	Depth of a volume texture (in pixels), otherwise unused */
249 	DWORD dwDepth;
250 	/**	Number of mipmap levels, otherwise unused */
251 	DWORD dwMipMapCount;
252 	/** Unused */
253 	DWORD dwReserved1[11];
254 	/** The pixel format(see DDS_PIXELFORMAT). */
255 	DDPIXELFORMAT ddspf;
256 	/** Specifies the complexity of the surfaces stored. */
257 	DDCAPS2 ddsCaps;
258 	DWORD dwReserved2;
259 } DDSURFACEDESC2;
260 
261 /**
262 Flags to indicate which members contain valid data.
263 */
264 enum {
265 	DDSD_CAPS = 0x1,			//! Required in every .dds file
266 	DDSD_HEIGHT = 0x2,			//! Required in every .dds file
267 	DDSD_WIDTH = 0x4,			//! Required in every .dds file
268 	DDSD_PITCH = 0x8,			//! Required when pitch is provided for an uncompressed texture
269 	DDSD_ALPHABITDEPTH = 0x80,	//! unknown use
270 	DDSD_PIXELFORMAT = 0x1000,	//! Required in every .dds file
271 	DDSD_MIPMAPCOUNT = 0x20000,	//! Required in a mipmapped texture
272 	DDSD_LINEARSIZE = 0x80000,	//! Required when pitch is provided for a compressed texture
273 	DDSD_DEPTH = 0x800000		//! Required in a depth texture
274 };
275 
276 typedef struct tagDDSHEADER {
277 	DWORD dwMagic;			//! FOURCC: "DDS "
278 	DDSURFACEDESC2 surfaceDesc;
279 } DDSHEADER;
280 
281 #define MAKEFOURCC(ch0, ch1, ch2, ch3) \
282 	((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) |   \
283     ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
284 
285 #define FOURCC_DXT1	MAKEFOURCC('D','X','T','1')
286 #define FOURCC_DXT2	MAKEFOURCC('D','X','T','2')
287 #define FOURCC_DXT3	MAKEFOURCC('D','X','T','3')
288 #define FOURCC_DXT4	MAKEFOURCC('D','X','T','4')
289 #define FOURCC_DXT5	MAKEFOURCC('D','X','T','5')
290 
291 // ----------------------------------------------------------
292 //   Structures used by DXT textures
293 // ----------------------------------------------------------
294 
295 typedef struct tagColor8888 {
296 	BYTE b;
297 	BYTE g;
298 	BYTE r;
299 	BYTE a;
300 } Color8888;
301 
302 typedef struct tagColor565 {
303 	WORD b : 5;
304 	WORD g : 6;
305 	WORD r : 5;
306 } Color565;
307 
308 typedef struct tagDXTColBlock {
309 	Color565 colors[2];
310 	BYTE row[4];
311 } DXTColBlock;
312 
313 typedef struct tagDXTAlphaBlockExplicit {
314 	WORD row[4];
315 } DXTAlphaBlockExplicit;
316 
317 typedef struct tagDXTAlphaBlock3BitLinear {
318 	BYTE alpha[2];
319 	BYTE data[6];
320 } DXTAlphaBlock3BitLinear;
321 
322 typedef struct tagDXT1Block {
323 	DXTColBlock color;
324 } DXT1Block;
325 
326 typedef struct tagDXT3Block {		// also used by dxt2
327 	DXTAlphaBlockExplicit alpha;
328 	DXTColBlock color;
329 } DXT3Block;
330 
331 typedef struct tagDXT5Block {		// also used by dxt4
332 	DXTAlphaBlock3BitLinear alpha;
333 	DXTColBlock color;
334 } DXT5Block;
335 
336 #ifdef _WIN32
337 #	pragma pack(pop)
338 #else
339 #	pragma pack()
340 #endif
341 
342 // ----------------------------------------------------------
343 //   Internal functions
344 // ----------------------------------------------------------
345 #ifdef FREEIMAGE_BIGENDIAN
346 static void
SwapHeader(DDSHEADER * header)347 SwapHeader(DDSHEADER *header) {
348 	SwapLong(&header->dwMagic);
349 	SwapLong(&header->surfaceDesc.dwSize);
350 	SwapLong(&header->surfaceDesc.dwFlags);
351 	SwapLong(&header->surfaceDesc.dwHeight);
352 	SwapLong(&header->surfaceDesc.dwWidth);
353 	SwapLong(&header->surfaceDesc.dwPitchOrLinearSize);
354 	SwapLong(&header->surfaceDesc.dwDepth);
355 	SwapLong(&header->surfaceDesc.dwMipMapCount);
356 	for(int i=0; i<11; i++) {
357 		SwapLong(&header->surfaceDesc.dwReserved1[i]);
358 	}
359 	SwapLong(&header->surfaceDesc.ddsCaps.dwCaps1);
360 	SwapLong(&header->surfaceDesc.ddsCaps.dwCaps2);
361 	SwapLong(&header->surfaceDesc.ddsCaps.dwReserved[0]);
362 	SwapLong(&header->surfaceDesc.ddsCaps.dwReserved[1]);
363 	SwapLong(&header->surfaceDesc.dwReserved2);
364 }
365 #endif
366 
367 // ==========================================================
368 
369 /**
370 Get the 4 possible colors for a block
371 */
372 static void
GetBlockColors(const DXTColBlock * block,Color8888 colors[4],bool isDXT1)373 GetBlockColors(const DXTColBlock *block, Color8888 colors[4], bool isDXT1) {
374 
375 	// expand from 565 to 888
376 	for (int i = 0; i < 2; i++)	{
377 		colors[i].a = 0xFF;
378 		/*
379 		colors[i].r = (BYTE)(unsigned(block->colors[i].r) * 0xFF / 0x1F);
380 		colors[i].g = (BYTE)(unsigned(block->colors[i].g) * 0xFF / 0x3F);
381 		colors[i].b = (BYTE)(unsigned(block->colors[i].b) * 0xFF / 0x1F);
382 		*/
383 		colors[i].r = (BYTE)((unsigned(block->colors[i].r) << 3U) | (unsigned(block->colors[i].r) >> 2U));
384 		colors[i].g = (BYTE)((unsigned(block->colors[i].g) << 2U) | (unsigned(block->colors[i].g) >> 4U));
385 		colors[i].b = (BYTE)((unsigned(block->colors[i].b) << 3U) | (unsigned(block->colors[i].b) >> 2U));
386 	}
387 
388 	const WORD *wCol = (WORD *)block->colors;
389 	if ((wCol[0] > wCol[1]) || !isDXT1) {
390 		// 4 color block
391 		for (unsigned i = 0; i < 2; i++)	{
392 			colors[i + 2].a = 0xFF;
393 			colors[i + 2].r = (BYTE)((unsigned(colors[0].r) * (2 - i) + unsigned(colors[1].r) * (1 + i)) / 3);
394 			colors[i + 2].g = (BYTE)((unsigned(colors[0].g) * (2 - i) + unsigned(colors[1].g) * (1 + i)) / 3);
395 			colors[i + 2].b = (BYTE)((unsigned(colors[0].b) * (2 - i) + unsigned(colors[1].b) * (1 + i)) / 3);
396 		}
397 	}
398 	else {
399 		// 3 color block, number 4 is transparent
400 		colors[2].a = 0xFF;
401 		colors[2].r = (BYTE)((unsigned(colors[0].r) + unsigned(colors[1].r)) / 2);
402 		colors[2].g = (BYTE)((unsigned(colors[0].g) + unsigned(colors[1].g)) / 2);
403 		colors[2].b = (BYTE)((unsigned(colors[0].b) + unsigned(colors[1].b)) / 2);
404 
405 		colors[3].a = 0x00;
406 		colors[3].g = 0x00;
407 		colors[3].b = 0x00;
408 		colors[3].r = 0x00;
409 	}
410 }
411 
412 typedef struct DXT_INFO_1 {
413 	typedef DXT1Block Block;
414 	enum {
415 		isDXT1 = 1,
416 		bytesPerBlock = 8
417 	};
418 } DXT_INFO_1;
419 
420 typedef struct DXT_INFO_3 {
421 	typedef DXT3Block Block;
422 	enum {
423 		isDXT1 = 1,
424 		bytesPerBlock = 16
425 	};
426 } DXT_INFO_3;
427 
428 typedef struct DXT_INFO_5 {
429 	typedef DXT5Block Block;
430 	enum {
431 		isDXT1 = 1,
432 		bytesPerBlock = 16
433 	};
434 } DXT_INFO_5;
435 
436 /**
437 Base decoder
438 */
439 template <class DXT_INFO> class DXT_BLOCKDECODER_BASE {
440 protected:
441 	Color8888 m_colors[4];
442 	const typename DXT_INFO::Block *m_pBlock;
443 	unsigned m_colorRow;
444 
445 public:
Setup(const BYTE * pBlock)446 	void Setup(const BYTE *pBlock) {
447 		// get a pointer to the block
448 		m_pBlock = (const typename DXT_INFO::Block *)pBlock;
449 
450 		// get the 4 possible colors for a block
451 		GetBlockColors(&m_pBlock->color, m_colors, DXT_INFO::isDXT1);
452 	}
453 
454 	/**
455 	Update y scanline
456 	*/
SetY(const int y)457 	void SetY(const int y) {
458 		m_colorRow = m_pBlock->color.row[y];
459 	}
460 
461 	/**
462 	Get Color at (x, y) where y is set by SetY
463 	@see SetY
464 	*/
GetColor(const int x,Color8888 * color)465 	void GetColor(const int x, Color8888 *color) {
466 		unsigned bits = (m_colorRow >> (x * 2)) & 3;
467 		memcpy(color, &m_colors[bits], sizeof(Color8888));
468 	}
469 
470 };
471 
472 class DXT_BLOCKDECODER_1 : public DXT_BLOCKDECODER_BASE<DXT_INFO_1> {
473 public:
474 	typedef DXT_INFO_1 INFO;
475 };
476 
477 class DXT_BLOCKDECODER_3 : public DXT_BLOCKDECODER_BASE<DXT_INFO_3> {
478 public:
479 	typedef DXT_BLOCKDECODER_BASE<DXT_INFO_3> base;
480 	typedef DXT_INFO_3 INFO;
481 
482 protected:
483 	unsigned m_alphaRow;
484 
485 public:
SetY(int y)486 	void SetY(int y) {
487 		base::SetY(y);
488 		m_alphaRow = m_pBlock->alpha.row[y];
489 	}
490 
491 	/**
492 	Get the color at (x, y) where y is set by SetY
493 	@see SetY
494 	*/
GetColor(int x,Color8888 * color)495 	void GetColor(int x, Color8888 *color) {
496 		base::GetColor(x, color);
497 		const unsigned bits = (m_alphaRow >> (x * 4)) & 0xF;
498 		color->a = (BYTE)((bits * 0xFF) / 0xF);
499 	}
500 };
501 
502 class DXT_BLOCKDECODER_5 : public DXT_BLOCKDECODER_BASE<DXT_INFO_5> {
503 public:
504 	typedef DXT_BLOCKDECODER_BASE<DXT_INFO_5> base;
505 	typedef DXT_INFO_5 INFO;
506 
507 protected:
508 	unsigned m_alphas[8];
509 	unsigned m_alphaBits;
510 	int m_offset;
511 
512 public:
Setup(const BYTE * pBlock)513 	void Setup (const BYTE *pBlock) {
514 		base::Setup (pBlock);
515 
516 		const DXTAlphaBlock3BitLinear &block = m_pBlock->alpha;
517 		m_alphas[0] = block.alpha[0];
518 		m_alphas[1] = block.alpha[1];
519 		if (m_alphas[0] > m_alphas[1]) {
520 			// 8 alpha block
521 			for (int i = 0; i < 6; i++) {
522 				m_alphas[i + 2] = ((6 - i) * m_alphas[0] + (1 + i) * m_alphas[1] + 3) / 7;
523 			}
524 		}
525 		else {
526 			// 6 alpha block
527 			for (int i = 0; i < 4; i++) {
528 				m_alphas[i + 2] = ((4 - i) * m_alphas[0] + (1 + i) * m_alphas[1] + 2) / 5;
529 			}
530 			m_alphas[6] = 0;
531 			m_alphas[7] = 0xFF;
532 		}
533 	}
534 
SetY(const int y)535 	void SetY(const int y) {
536 		base::SetY(y);
537 		const int i = y / 2;
538 		const DXTAlphaBlock3BitLinear &block = m_pBlock->alpha;
539 		const BYTE *data = &block.data[i * 3];
540 		m_alphaBits = unsigned(data[0]) | (unsigned(data[1]) << 8) | (unsigned(data[2]) << 16);
541 		m_offset = (y & 1) * 12;
542 	}
543 
544 	/**
545 	Get the color at (x, y) where y is set by SetY
546 	@see SetY
547 	*/
GetColor(int x,Color8888 * color)548 	void GetColor(int x, Color8888 *color) {
549 		base::GetColor(x, color);
550 		unsigned bits = (m_alphaBits >> (x * 3 + m_offset)) & 7;
551 		color->a = (BYTE)m_alphas[bits];
552 	}
553 };
554 
DecodeDXTBlock(BYTE * dstData,const BYTE * srcBlock,long dstPitch,int bw,int bh)555 template <class DECODER> void DecodeDXTBlock (BYTE *dstData, const BYTE *srcBlock, long dstPitch, int bw, int bh) {
556 	DECODER decoder;
557 	decoder.Setup(srcBlock);
558 	for (int y = 0; y < bh; y++) {
559 		BYTE *dst = dstData - y * dstPitch;
560 		// update scanline
561 		decoder.SetY(y);
562 		for (int x = 0; x < bw; x++) {
563 			// GetColor(x, y, dst)
564 			Color8888 *color = (Color8888*)dst;
565 			decoder.GetColor(x, color);
566 
567 #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
568 			INPLACESWAP(dst[FI_RGBA_RED], dst[FI_RGBA_BLUE]);
569 #endif
570 			dst += 4;
571 		}
572 	}
573 }
574 
575 // ==========================================================
576 // Plugin Interface
577 // ==========================================================
578 
579 static int s_format_id;
580 
581 // ==========================================================
582 // Internal functions
583 // ==========================================================
584 
585 /**
586 @param desc DDS_HEADER structure
587 @param io FreeImage IO
588 @param handle FreeImage handle
589 */
590 static FIBITMAP *
LoadRGB(const DDSURFACEDESC2 * desc,FreeImageIO * io,fi_handle handle)591 LoadRGB(const DDSURFACEDESC2 *desc, FreeImageIO *io, fi_handle handle) {
592 	FIBITMAP *dib = NULL;
593 	DDSFormat16 format16 = RGB_UNKNOWN;	// for 16-bit formats
594 
595 	const DDPIXELFORMAT *ddspf = &(desc->ddspf);
596 
597 	// it is perfectly valid for an uncompressed DDS file to have a width or height which is not a multiple of 4
598 	// (only the packed image formats need to be a multiple of 4)
599 	const int width = (int)desc->dwWidth;
600 	const int height = (int)desc->dwHeight;
601 
602 	// check the bitdepth, then allocate a new dib
603 	const int bpp = (int)ddspf->dwRGBBitCount;
604 	if (bpp == 16) {
605 		// get the 16-bit format
606 		format16 = GetRGB16Format(ddspf->dwRBitMask, ddspf->dwGBitMask, ddspf->dwBBitMask);
607 		// allocate a 24-bit dib, conversion from 16- to 24-bit will be done later
608 		dib = FreeImage_Allocate(width, height, 24);
609 	}
610 	else {
611 		dib = FreeImage_Allocate(width, height, bpp, ddspf->dwRBitMask, ddspf->dwGBitMask, ddspf->dwBBitMask);
612 	}
613 	if (dib == NULL) {
614 		return NULL;
615 	}
616 
617 	// read the file
618 	// -------------------------------------------------------------------------
619 
620 	const int line = CalculateLine(width, bpp);
621 	const int filePitch = ((desc->dwFlags & DDSD_PITCH) == DDSD_PITCH) ? (int)desc->dwPitchOrLinearSize : line;
622 	const long delta = (long)filePitch - (long)line;
623 
624 	if (bpp == 16) {
625 		BYTE *pixels = (BYTE*)malloc(line * sizeof(BYTE));
626 		if (pixels) {
627 			for (int y = 0; y < height; y++) {
628 				BYTE *dst_bits = FreeImage_GetScanLine(dib, height - y - 1);
629 				// get the 16-bit RGB pixels
630 				io->read_proc(pixels, 1, line, handle);
631 				io->seek_proc(handle, delta, SEEK_CUR);
632 				// convert to 24-bit
633 				ConvertLine16To24(dst_bits, (const WORD*)pixels, format16, width);
634 			}
635 		}
636 		free(pixels);
637 	}
638 	else {
639 		for (int y = 0; y < height; y++) {
640 			BYTE *pixels = FreeImage_GetScanLine(dib, height - y - 1);
641 			io->read_proc(pixels, 1, line, handle);
642 			io->seek_proc(handle, delta, SEEK_CUR);
643 		}
644 	}
645 
646 #if FREEIMAGE_COLORORDER == FREEIMAGE_COLORORDER_RGB
647 	// Calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit)
648 	const int bytespp = FreeImage_GetLine(dib) / width;
649 
650 	for (int y = 0; y < height; y++) {
651 		BYTE *pixels = FreeImage_GetScanLine(dib, y);
652 		for (int x = 0; x < width; x++) {
653 			INPLACESWAP(pixels[FI_RGBA_RED], pixels[FI_RGBA_BLUE]);
654 			pixels += bytespp;
655 		}
656 	}
657 #endif
658 
659 	// enable transparency
660 	BOOL bIsTransparent = (bpp != 16) && ((ddspf->dwFlags & DDPF_ALPHAPIXELS) == DDPF_ALPHAPIXELS) ? TRUE : FALSE;
661 	FreeImage_SetTransparent(dib, bIsTransparent);
662 
663 	if (!bIsTransparent && bpp == 32) {
664 		// no transparency: convert to 24-bit
665 		FIBITMAP *old = dib;
666 		dib = FreeImage_ConvertTo24Bits(old);
667 		FreeImage_Unload(old);
668 	}
669 
670 	return dib;
671 }
672 
673 /**
674 @param io FreeImage IO
675 @param handle FreeImage handle
676 @param dib Returned dib (already allocated)
677 @param width Image width
678 @param height Image height
679 */
680 template <class DECODER> static void
LoadDXT_Helper(FreeImageIO * io,fi_handle handle,FIBITMAP * dib,int width,int height)681 LoadDXT_Helper(FreeImageIO *io, fi_handle handle, FIBITMAP *dib, int width, int height) {
682 	typedef typename DECODER::INFO INFO;
683 	typedef typename INFO::Block Block;
684 
685 	// get the size of a line in bytes
686 	int line = CalculateLine(width, FreeImage_GetBPP(dib));
687 
688 	Block *input_buffer = new(std::nothrow) Block[(width + 3) / 4];
689 	if (!input_buffer) {
690 		return;
691 	}
692 
693 	const int widthRest = (int) width & 3;
694 	const int heightRest = (int) height & 3;
695 	const int inputLine = (width + 3) / 4;
696 	int y = 0;
697 
698 	if (height >= 4) {
699 		for (; y < height; y += 4) {
700 			io->read_proc (input_buffer, sizeof(typename INFO::Block), inputLine, handle);
701 			// TODO: probably need some endian work here
702 			const BYTE *pbSrc = (BYTE *)input_buffer;
703 			BYTE *pbDst = FreeImage_GetScanLine (dib, height - y - 1);
704 
705 			if (width >= 4) {
706 				for (int x = 0; x < width; x += 4) {
707 					DecodeDXTBlock<DECODER>(pbDst, pbSrc, line, 4, 4);
708 					pbSrc += INFO::bytesPerBlock;
709 					pbDst += 16;	// 4 * 4;
710 				}
711 			}
712 			if (widthRest) {
713 				DecodeDXTBlock<DECODER>(pbDst, pbSrc, line, widthRest, 4);
714 			}
715 		}
716 	}
717 	if (heightRest)	{
718 		io->read_proc (input_buffer, sizeof (typename INFO::Block), inputLine, handle);
719 		// TODO: probably need some endian work here
720 		const BYTE *pbSrc = (BYTE *)input_buffer;
721 		BYTE *pbDst = FreeImage_GetScanLine (dib, height - y - 1);
722 
723 		if (width >= 4) {
724 			for (int x = 0; x < width; x += 4) {
725 				DecodeDXTBlock<DECODER>(pbDst, pbSrc, line, 4, heightRest);
726 				pbSrc += INFO::bytesPerBlock;
727 				pbDst += 16;	// 4 * 4;
728 			}
729 		}
730 		if (widthRest) {
731 			DecodeDXTBlock<DECODER>(pbDst, pbSrc, line, widthRest, heightRest);
732 		}
733 
734 	}
735 
736 	delete [] input_buffer;
737 }
738 
739 /**
740 @param decoder_type Decoder to be used, either 1 (DXT1), 3 (DXT3) or 5 (DXT5)
741 @param desc DDS_HEADER structure
742 @param io FreeImage IO
743 @param handle FreeImage handle
744 */
745 static FIBITMAP *
LoadDXT(int decoder_type,const DDSURFACEDESC2 * desc,FreeImageIO * io,fi_handle handle)746 LoadDXT(int decoder_type, const DDSURFACEDESC2 *desc, FreeImageIO *io, fi_handle handle) {
747 	// get image size, rounded to 32-bit
748 	int width = (int)desc->dwWidth & ~3;
749 	int height = (int)desc->dwHeight & ~3;
750 
751 	// allocate a 32-bit dib
752 	FIBITMAP *dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
753 	if (dib == NULL) {
754 		return NULL;
755 	}
756 
757 	// select the right decoder, then decode the image
758 	switch (decoder_type) {
759 		case 1:
760 			LoadDXT_Helper<DXT_BLOCKDECODER_1>(io, handle, dib, width, height);
761 			break;
762 		case 3:
763 			LoadDXT_Helper<DXT_BLOCKDECODER_3>(io, handle, dib, width, height);
764 			break;
765 		case 5:
766 			LoadDXT_Helper<DXT_BLOCKDECODER_5>(io, handle, dib, width, height);
767 			break;
768 		default:
769 			break;
770 	}
771 
772 	return dib;
773 }
774 // ==========================================================
775 // Plugin Implementation
776 // ==========================================================
777 
778 static const char * DLL_CALLCONV
Format()779 Format() {
780 	return "DDS";
781 }
782 
783 static const char * DLL_CALLCONV
Description()784 Description() {
785 	return "DirectX Surface";
786 }
787 
788 static const char * DLL_CALLCONV
Extension()789 Extension() {
790 	return "dds";
791 }
792 
793 static const char * DLL_CALLCONV
RegExpr()794 RegExpr() {
795 	return NULL;
796 }
797 
798 static const char * DLL_CALLCONV
MimeType()799 MimeType() {
800 	return "image/x-dds";
801 }
802 
803 static BOOL DLL_CALLCONV
Validate(FreeImageIO * io,fi_handle handle)804 Validate(FreeImageIO *io, fi_handle handle) {
805 	DDSHEADER header;
806 	memset(&header, 0, sizeof(header));
807 	io->read_proc(&header, 1, sizeof(header), handle);
808 #ifdef FREEIMAGE_BIGENDIAN
809 	SwapHeader(&header);
810 #endif
811 	if (header.dwMagic != MAKEFOURCC('D', 'D', 'S', ' ')) {
812 		return FALSE;
813 	}
814 	if (header.surfaceDesc.dwSize != sizeof(header.surfaceDesc) || header.surfaceDesc.ddspf.dwSize != sizeof(header.surfaceDesc.ddspf)) {
815 		return FALSE;
816 	}
817 	return TRUE;
818 }
819 
820 static BOOL DLL_CALLCONV
SupportsExportDepth(int depth)821 SupportsExportDepth(int depth) {
822 	return FALSE;
823 }
824 
825 static BOOL DLL_CALLCONV
SupportsExportType(FREE_IMAGE_TYPE type)826 SupportsExportType(FREE_IMAGE_TYPE type) {
827 	return FALSE;
828 }
829 
830 // ----------------------------------------------------------
831 
832 static void * DLL_CALLCONV
Open(FreeImageIO * io,fi_handle handle,BOOL read)833 Open(FreeImageIO *io, fi_handle handle, BOOL read) {
834 	return NULL;
835 }
836 
837 static void DLL_CALLCONV
Close(FreeImageIO * io,fi_handle handle,void * data)838 Close(FreeImageIO *io, fi_handle handle, void *data) {
839 }
840 
841 // ----------------------------------------------------------
842 
843 static FIBITMAP * DLL_CALLCONV
Load(FreeImageIO * io,fi_handle handle,int page,int flags,void * data)844 Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
845 	DDSHEADER header;
846 	FIBITMAP *dib = NULL;
847 
848 	memset(&header, 0, sizeof(header));
849 	io->read_proc(&header, 1, sizeof(header), handle);
850 #ifdef FREEIMAGE_BIGENDIAN
851 	SwapHeader(&header);
852 #endif
853 
854 	// values which indicate what type of data is in the surface, see DDPF_*
855 	const DWORD dwFlags = header.surfaceDesc.ddspf.dwFlags;
856 
857 	const DDSURFACEDESC2 *surfaceDesc = &(header.surfaceDesc);
858 
859 	if ((dwFlags & DDPF_RGB) == DDPF_RGB) {
860 		// uncompressed data
861 		dib = LoadRGB(surfaceDesc, io, handle);
862 	}
863 	else if ((dwFlags & DDPF_FOURCC) == DDPF_FOURCC) {
864 		// compressed data
865 		switch (surfaceDesc->ddspf.dwFourCC) {
866 			case FOURCC_DXT1:
867 				dib = LoadDXT(1, surfaceDesc, io, handle);
868 				break;
869 			case FOURCC_DXT3:
870 				dib = LoadDXT(3, surfaceDesc, io, handle);
871 				break;
872 			case FOURCC_DXT5:
873 				dib = LoadDXT(5, surfaceDesc, io, handle);
874 				break;
875 		}
876 	}
877 
878 	return dib;
879 }
880 
881 /*
882 static BOOL DLL_CALLCONV
883 Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
884 	return FALSE;
885 }
886 */
887 
888 // ==========================================================
889 //   Init
890 // ==========================================================
891 
892 void DLL_CALLCONV
InitDDS(Plugin * plugin,int format_id)893 InitDDS(Plugin *plugin, int format_id) {
894 	s_format_id = format_id;
895 
896 	plugin->format_proc = Format;
897 	plugin->description_proc = Description;
898 	plugin->extension_proc = Extension;
899 	plugin->regexpr_proc = RegExpr;
900 	plugin->open_proc = Open;
901 	plugin->close_proc = Close;
902 	plugin->pagecount_proc = NULL;
903 	plugin->pagecapability_proc = NULL;
904 	plugin->load_proc = Load;
905 	plugin->save_proc = NULL;	//Save;	// not implemented (yet?)
906 	plugin->validate_proc = Validate;
907 	plugin->mime_proc = MimeType;
908 	plugin->supports_export_bpp_proc = SupportsExportDepth;
909 	plugin->supports_export_type_proc = SupportsExportType;
910 	plugin->supports_icc_profiles_proc = NULL;
911 }
912