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