Coverage Report

Created: 2025-11-24 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/freeimage-svn/FreeImage/trunk/Source/FreeImage/PluginDDS.cpp
Line
Count
Source
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
0
#define FI16_444_RED_MASK 0x0F00
31
0
#define FI16_444_GREEN_MASK 0x00F0
32
0
#define FI16_444_BLUE_MASK  0x000F
33
0
#define FI16_444_RED_SHIFT    8
34
0
#define FI16_444_GREEN_SHIFT  4
35
0
#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
59
0
GetRGB16Format(DWORD dwRBitMask, DWORD dwGBitMask, DWORD dwBBitMask) {
60
0
  if ((dwRBitMask == FI16_444_RED_MASK) && (dwGBitMask == FI16_444_GREEN_MASK) && (dwBBitMask == FI16_444_BLUE_MASK)) {
61
0
    return RGB444;
62
0
  }
63
0
  if ((dwRBitMask == FI16_555_RED_MASK) && (dwGBitMask == FI16_555_GREEN_MASK) && (dwBBitMask == FI16_555_BLUE_MASK)) {
64
0
    return RGB555;
65
0
  }
66
0
  if ((dwRBitMask == FI16_565_RED_MASK) && (dwGBitMask == FI16_565_GREEN_MASK) && (dwBBitMask == FI16_565_BLUE_MASK)) {
67
0
    return RGB565;
68
0
  }
69
70
0
  return RGB_UNKNOWN;
71
0
}
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 
81
0
ConvertLine16To24(BYTE *target, const WORD *source, DDSFormat16 format, int width_in_pixels) {
82
83
  // convert from RGB 16-bit to RGB 24-bit
84
0
  switch (format) {
85
0
    case RGB444:
86
0
      for (int cols = 0; cols < width_in_pixels; cols++) {
87
        // extract source RGB444 pixel, set to 24-bit target
88
0
        target[FI_RGBA_BLUE] = (BYTE)((((source[cols] & FI16_444_BLUE_MASK) >> FI16_444_BLUE_SHIFT) * 0xFF) / 0x0F);
89
0
        target[FI_RGBA_GREEN] = (BYTE)((((source[cols] & FI16_444_GREEN_MASK) >> FI16_444_GREEN_SHIFT) * 0xFF) / 0x0F);
90
0
        target[FI_RGBA_RED] = (BYTE)((((source[cols] & FI16_444_RED_MASK) >> FI16_444_RED_SHIFT) * 0xFF) / 0x0F);
91
0
        target += 3;
92
0
      }
93
0
      break;
94
95
0
    case RGB555:
96
0
      for (int cols = 0; cols < width_in_pixels; cols++) {
97
0
        target[FI_RGBA_RED] = (BYTE)((((source[cols] & FI16_555_RED_MASK) >> FI16_555_RED_SHIFT) * 0xFF) / 0x1F);
98
0
        target[FI_RGBA_GREEN] = (BYTE)((((source[cols] & FI16_555_GREEN_MASK) >> FI16_555_GREEN_SHIFT) * 0xFF) / 0x1F);
99
0
        target[FI_RGBA_BLUE] = (BYTE)((((source[cols] & FI16_555_BLUE_MASK) >> FI16_555_BLUE_SHIFT) * 0xFF) / 0x1F);
100
0
        target += 3;
101
0
      }
102
0
      break;
103
104
0
    case RGB565:
105
0
      for (int cols = 0; cols < width_in_pixels; cols++) {
106
0
        target[FI_RGBA_RED] = (BYTE)((((source[cols] & FI16_565_RED_MASK) >> FI16_565_RED_SHIFT) * 0xFF) / 0x1F);
107
0
        target[FI_RGBA_GREEN] = (BYTE)((((source[cols] & FI16_565_GREEN_MASK) >> FI16_565_GREEN_SHIFT) * 0xFF) / 0x3F);
108
0
        target[FI_RGBA_BLUE] = (BYTE)((((source[cols] & FI16_565_BLUE_MASK) >> FI16_565_BLUE_SHIFT) * 0xFF) / 0x1F);
109
0
        target += 3;
110
0
      }
111
0
      break;
112
113
0
    default:
114
0
      break;
115
0
  }
116
0
}
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
29.2k
  ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) |   \
283
29.2k
    ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 ))
284
285
0
#define FOURCC_DXT1 MAKEFOURCC('D','X','T','1')
286
#define FOURCC_DXT2 MAKEFOURCC('D','X','T','2')
287
0
#define FOURCC_DXT3 MAKEFOURCC('D','X','T','3')
288
#define FOURCC_DXT4 MAKEFOURCC('D','X','T','4')
289
0
#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
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 
373
0
GetBlockColors(const DXTColBlock *block, Color8888 colors[4], bool isDXT1) {
374
375
  // expand from 565 to 888
376
0
  for (int i = 0; i < 2; i++) {
377
0
    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
0
    colors[i].r = (BYTE)((unsigned(block->colors[i].r) << 3U) | (unsigned(block->colors[i].r) >> 2U));
384
0
    colors[i].g = (BYTE)((unsigned(block->colors[i].g) << 2U) | (unsigned(block->colors[i].g) >> 4U));
385
0
    colors[i].b = (BYTE)((unsigned(block->colors[i].b) << 3U) | (unsigned(block->colors[i].b) >> 2U));
386
0
  }
387
388
0
  const WORD *wCol = (WORD *)block->colors;
389
0
  if ((wCol[0] > wCol[1]) || !isDXT1) {
390
    // 4 color block
391
0
    for (unsigned i = 0; i < 2; i++) {
392
0
      colors[i + 2].a = 0xFF;
393
0
      colors[i + 2].r = (BYTE)((unsigned(colors[0].r) * (2 - i) + unsigned(colors[1].r) * (1 + i)) / 3);
394
0
      colors[i + 2].g = (BYTE)((unsigned(colors[0].g) * (2 - i) + unsigned(colors[1].g) * (1 + i)) / 3);
395
0
      colors[i + 2].b = (BYTE)((unsigned(colors[0].b) * (2 - i) + unsigned(colors[1].b) * (1 + i)) / 3);
396
0
    }
397
0
  }
398
0
  else {
399
    // 3 color block, number 4 is transparent
400
0
    colors[2].a = 0xFF;
401
0
    colors[2].r = (BYTE)((unsigned(colors[0].r) + unsigned(colors[1].r)) / 2);
402
0
    colors[2].g = (BYTE)((unsigned(colors[0].g) + unsigned(colors[1].g)) / 2);
403
0
    colors[2].b = (BYTE)((unsigned(colors[0].b) + unsigned(colors[1].b)) / 2);
404
405
0
    colors[3].a = 0x00;
406
0
    colors[3].g = 0x00;
407
0
    colors[3].b = 0x00;
408
0
    colors[3].r = 0x00;
409
0
  }
410
0
}
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:
446
0
  void Setup(const BYTE *pBlock) {
447
    // get a pointer to the block
448
0
    m_pBlock = (const typename DXT_INFO::Block *)pBlock;
449
450
    // get the 4 possible colors for a block
451
0
    GetBlockColors(&m_pBlock->color, m_colors, DXT_INFO::isDXT1);
452
0
  }
Unexecuted instantiation: DXT_BLOCKDECODER_BASE<DXT_INFO_1>::Setup(unsigned char const*)
Unexecuted instantiation: DXT_BLOCKDECODER_BASE<DXT_INFO_3>::Setup(unsigned char const*)
Unexecuted instantiation: DXT_BLOCKDECODER_BASE<DXT_INFO_5>::Setup(unsigned char const*)
453
454
  /**
455
  Update y scanline
456
  */
457
0
  void SetY(const int y) {
458
0
    m_colorRow = m_pBlock->color.row[y];
459
0
  }
Unexecuted instantiation: DXT_BLOCKDECODER_BASE<DXT_INFO_1>::SetY(int)
Unexecuted instantiation: DXT_BLOCKDECODER_BASE<DXT_INFO_3>::SetY(int)
Unexecuted instantiation: DXT_BLOCKDECODER_BASE<DXT_INFO_5>::SetY(int)
460
461
  /**
462
  Get Color at (x, y) where y is set by SetY
463
  @see SetY
464
  */
465
0
  void GetColor(const int x, Color8888 *color) {
466
0
    unsigned bits = (m_colorRow >> (x * 2)) & 3;
467
0
    memcpy(color, &m_colors[bits], sizeof(Color8888));
468
0
  }
Unexecuted instantiation: DXT_BLOCKDECODER_BASE<DXT_INFO_1>::GetColor(int, tagColor8888*)
Unexecuted instantiation: DXT_BLOCKDECODER_BASE<DXT_INFO_3>::GetColor(int, tagColor8888*)
Unexecuted instantiation: DXT_BLOCKDECODER_BASE<DXT_INFO_5>::GetColor(int, tagColor8888*)
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:
486
0
  void SetY(int y) {
487
0
    base::SetY(y);
488
0
    m_alphaRow = m_pBlock->alpha.row[y];
489
0
  }
490
491
  /**
492
  Get the color at (x, y) where y is set by SetY
493
  @see SetY
494
  */
495
0
  void GetColor(int x, Color8888 *color) {
496
0
    base::GetColor(x, color);
497
0
    const unsigned bits = (m_alphaRow >> (x * 4)) & 0xF;
498
0
    color->a = (BYTE)((bits * 0xFF) / 0xF);
499
0
  }
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:
513
0
  void Setup (const BYTE *pBlock) {
514
0
    base::Setup (pBlock);
515
516
0
    const DXTAlphaBlock3BitLinear &block = m_pBlock->alpha;
517
0
    m_alphas[0] = block.alpha[0];
518
0
    m_alphas[1] = block.alpha[1];
519
0
    if (m_alphas[0] > m_alphas[1]) {
520
      // 8 alpha block
521
0
      for (int i = 0; i < 6; i++) {
522
0
        m_alphas[i + 2] = ((6 - i) * m_alphas[0] + (1 + i) * m_alphas[1] + 3) / 7;
523
0
      }
524
0
    }
525
0
    else {
526
      // 6 alpha block
527
0
      for (int i = 0; i < 4; i++) {
528
0
        m_alphas[i + 2] = ((4 - i) * m_alphas[0] + (1 + i) * m_alphas[1] + 2) / 5;
529
0
      }
530
0
      m_alphas[6] = 0;
531
0
      m_alphas[7] = 0xFF;
532
0
    }
533
0
  }
534
535
0
  void SetY(const int y) {
536
0
    base::SetY(y);
537
0
    const int i = y / 2;
538
0
    const DXTAlphaBlock3BitLinear &block = m_pBlock->alpha;
539
0
    const BYTE *data = &block.data[i * 3];
540
0
    m_alphaBits = unsigned(data[0]) | (unsigned(data[1]) << 8) | (unsigned(data[2]) << 16);
541
0
    m_offset = (y & 1) * 12;
542
0
  }
543
544
  /**
545
  Get the color at (x, y) where y is set by SetY
546
  @see SetY
547
  */
548
0
  void GetColor(int x, Color8888 *color) {
549
0
    base::GetColor(x, color);
550
0
    unsigned bits = (m_alphaBits >> (x * 3 + m_offset)) & 7;
551
0
    color->a = (BYTE)m_alphas[bits];
552
0
  }
553
};
554
555
0
template <class DECODER> void DecodeDXTBlock (BYTE *dstData, const BYTE *srcBlock, long dstPitch, int bw, int bh) {
556
0
  DECODER decoder;
557
0
  decoder.Setup(srcBlock);
558
0
  for (int y = 0; y < bh; y++) {
559
0
    BYTE *dst = dstData - y * dstPitch;
560
    // update scanline
561
0
    decoder.SetY(y);
562
0
    for (int x = 0; x < bw; x++) {
563
      // GetColor(x, y, dst)
564
0
      Color8888 *color = (Color8888*)dst;
565
0
      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
0
      dst += 4;
571
0
    }
572
0
  }
573
0
}
Unexecuted instantiation: void DecodeDXTBlock<DXT_BLOCKDECODER_1>(unsigned char*, unsigned char const*, long, int, int)
Unexecuted instantiation: void DecodeDXTBlock<DXT_BLOCKDECODER_3>(unsigned char*, unsigned char const*, long, int, int)
Unexecuted instantiation: void DecodeDXTBlock<DXT_BLOCKDECODER_5>(unsigned char*, unsigned char const*, long, int, int)
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 *
591
0
LoadRGB(const DDSURFACEDESC2 *desc, FreeImageIO *io, fi_handle handle) {
592
0
  FIBITMAP *dib = NULL;
593
0
  DDSFormat16 format16 = RGB_UNKNOWN; // for 16-bit formats
594
595
0
  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
0
  const int width = (int)desc->dwWidth;
600
0
  const int height = (int)desc->dwHeight;
601
602
  // check the bitdepth, then allocate a new dib
603
0
  const int bpp = (int)ddspf->dwRGBBitCount;
604
0
  if (bpp == 16) {
605
    // get the 16-bit format
606
0
    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
0
    dib = FreeImage_Allocate(width, height, 24);
609
0
  }
610
0
  else {
611
0
    dib = FreeImage_Allocate(width, height, bpp, ddspf->dwRBitMask, ddspf->dwGBitMask, ddspf->dwBBitMask);
612
0
  }
613
0
  if (dib == NULL) {
614
0
    return NULL;
615
0
  }
616
617
  // read the file
618
  // -------------------------------------------------------------------------
619
620
0
  const int line = CalculateLine(width, FreeImage_GetBPP(dib));
621
0
  const int filePitch = ((desc->dwFlags & DDSD_PITCH) == DDSD_PITCH) ? (int)desc->dwPitchOrLinearSize : line;
622
0
  const long delta = (long)filePitch - (long)line;
623
624
0
  if (bpp == 16) {
625
0
    BYTE *pixels = (BYTE*)malloc(line * sizeof(BYTE));
626
0
    if (pixels) {
627
0
      for (int y = 0; y < height; y++) {
628
0
        BYTE *dst_bits = FreeImage_GetScanLine(dib, height - y - 1);
629
        // get the 16-bit RGB pixels
630
0
        io->read_proc(pixels, 1, line, handle);
631
0
        io->seek_proc(handle, delta, SEEK_CUR);
632
        // convert to 24-bit
633
0
        ConvertLine16To24(dst_bits, (const WORD*)pixels, format16, width);
634
0
      }
635
0
    }
636
0
    free(pixels);
637
0
  }
638
0
  else {
639
0
    for (int y = 0; y < height; y++) {
640
0
      BYTE *pixels = FreeImage_GetScanLine(dib, height - y - 1);
641
0
      io->read_proc(pixels, 1, line, handle);
642
0
      io->seek_proc(handle, delta, SEEK_CUR);
643
0
    }
644
0
  }
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
0
  BOOL bIsTransparent = (bpp != 16) && ((ddspf->dwFlags & DDPF_ALPHAPIXELS) == DDPF_ALPHAPIXELS) ? TRUE : FALSE;
661
0
  FreeImage_SetTransparent(dib, bIsTransparent);
662
663
0
  if (!bIsTransparent && bpp == 32) {
664
    // no transparency: convert to 24-bit
665
0
    FIBITMAP *old = dib;
666
0
    dib = FreeImage_ConvertTo24Bits(old);
667
0
    FreeImage_Unload(old);
668
0
  }
669
670
0
  return dib;
671
0
}
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 
681
0
LoadDXT_Helper(FreeImageIO *io, fi_handle handle, FIBITMAP *dib, int width, int height) {
682
0
  typedef typename DECODER::INFO INFO;
683
0
  typedef typename INFO::Block Block;
684
685
  // get the size of a line in bytes
686
0
  int line = CalculateLine(width, FreeImage_GetBPP(dib));
687
688
0
  Block *input_buffer = new(std::nothrow) Block[(width + 3) / 4];
689
0
  if (!input_buffer) {
690
0
    return;
691
0
  }
692
693
0
  const int widthRest = (int) width & 3;
694
0
  const int heightRest = (int) height & 3;
695
0
  const int inputLine = (width + 3) / 4;
696
0
  int y = 0;
697
698
0
  if (height >= 4) {
699
0
    for (; y < height; y += 4) {
700
0
      io->read_proc (input_buffer, sizeof(typename INFO::Block), inputLine, handle);
701
      // TODO: probably need some endian work here
702
0
      const BYTE *pbSrc = (BYTE *)input_buffer;
703
0
      BYTE *pbDst = FreeImage_GetScanLine (dib, height - y - 1);
704
705
0
      if (width >= 4) {
706
0
        for (int x = 0; x < width; x += 4) {
707
0
          DecodeDXTBlock<DECODER>(pbDst, pbSrc, line, 4, 4);
708
0
          pbSrc += INFO::bytesPerBlock;
709
0
          pbDst += 16;  // 4 * 4;
710
0
        }
711
0
      }
712
0
      if (widthRest) {
713
0
        DecodeDXTBlock<DECODER>(pbDst, pbSrc, line, widthRest, 4);
714
0
      }
715
0
    }
716
0
  }
717
0
  if (heightRest) {
718
0
    io->read_proc (input_buffer, sizeof (typename INFO::Block), inputLine, handle);
719
    // TODO: probably need some endian work here
720
0
    const BYTE *pbSrc = (BYTE *)input_buffer;
721
0
    BYTE *pbDst = FreeImage_GetScanLine (dib, height - y - 1);
722
723
0
    if (width >= 4) {
724
0
      for (int x = 0; x < width; x += 4) {
725
0
        DecodeDXTBlock<DECODER>(pbDst, pbSrc, line, 4, heightRest);
726
0
        pbSrc += INFO::bytesPerBlock;
727
0
        pbDst += 16;  // 4 * 4;
728
0
      }
729
0
    }
730
0
    if (widthRest) {
731
0
      DecodeDXTBlock<DECODER>(pbDst, pbSrc, line, widthRest, heightRest);
732
0
    }
733
734
0
  }
735
736
0
  delete [] input_buffer;
737
0
}
Unexecuted instantiation: PluginDDS.cpp:void LoadDXT_Helper<DXT_BLOCKDECODER_1>(FreeImageIO*, void*, FIBITMAP*, int, int)
Unexecuted instantiation: PluginDDS.cpp:void LoadDXT_Helper<DXT_BLOCKDECODER_3>(FreeImageIO*, void*, FIBITMAP*, int, int)
Unexecuted instantiation: PluginDDS.cpp:void LoadDXT_Helper<DXT_BLOCKDECODER_5>(FreeImageIO*, void*, FIBITMAP*, int, int)
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 *
746
0
LoadDXT(int decoder_type, const DDSURFACEDESC2 *desc, FreeImageIO *io, fi_handle handle) {
747
  // get image size, rounded to 32-bit
748
0
  int width = (int)desc->dwWidth & ~3;
749
0
  int height = (int)desc->dwHeight & ~3;
750
751
  // allocate a 32-bit dib
752
0
  FIBITMAP *dib = FreeImage_Allocate(width, height, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
753
0
  if (dib == NULL) {
754
0
    return NULL;
755
0
  }
756
757
  // select the right decoder, then decode the image
758
0
  switch (decoder_type) {
759
0
    case 1:
760
0
      LoadDXT_Helper<DXT_BLOCKDECODER_1>(io, handle, dib, width, height);
761
0
      break;
762
0
    case 3:
763
0
      LoadDXT_Helper<DXT_BLOCKDECODER_3>(io, handle, dib, width, height);
764
0
      break;
765
0
    case 5:
766
0
      LoadDXT_Helper<DXT_BLOCKDECODER_5>(io, handle, dib, width, height);
767
0
      break;
768
0
    default:
769
0
      break;
770
0
  }
771
  
772
0
  return dib;
773
0
}
774
// ==========================================================
775
// Plugin Implementation
776
// ==========================================================
777
778
static const char * DLL_CALLCONV
779
2
Format() {
780
2
  return "DDS";
781
2
}
782
783
static const char * DLL_CALLCONV
784
0
Description() {
785
0
  return "DirectX Surface";
786
0
}
787
788
static const char * DLL_CALLCONV
789
0
Extension() {
790
0
  return "dds";
791
0
}
792
793
static const char * DLL_CALLCONV
794
0
RegExpr() {
795
0
  return NULL;
796
0
}
797
798
static const char * DLL_CALLCONV
799
0
MimeType() {
800
0
  return "image/x-dds";
801
0
}
802
803
static BOOL DLL_CALLCONV
804
29.2k
Validate(FreeImageIO *io, fi_handle handle) {
805
29.2k
  DDSHEADER header;
806
29.2k
  memset(&header, 0, sizeof(header));
807
29.2k
  io->read_proc(&header, 1, sizeof(header), handle);
808
#ifdef FREEIMAGE_BIGENDIAN
809
  SwapHeader(&header);
810
#endif
811
29.2k
  if (header.dwMagic != MAKEFOURCC('D', 'D', 'S', ' ')) {
812
29.2k
    return FALSE;
813
29.2k
  }
814
8
  if (header.surfaceDesc.dwSize != sizeof(header.surfaceDesc) || header.surfaceDesc.ddspf.dwSize != sizeof(header.surfaceDesc.ddspf)) {
815
7
    return FALSE;
816
7
  }
817
1
  return TRUE;
818
8
}
819
820
static BOOL DLL_CALLCONV
821
0
SupportsExportDepth(int depth) {
822
0
  return FALSE;
823
0
}
824
825
static BOOL DLL_CALLCONV 
826
0
SupportsExportType(FREE_IMAGE_TYPE type) {
827
0
  return FALSE;
828
0
}
829
830
// ----------------------------------------------------------
831
832
static void * DLL_CALLCONV
833
0
Open(FreeImageIO *io, fi_handle handle, BOOL read) {
834
0
  return NULL;
835
0
}
836
837
static void DLL_CALLCONV
838
0
Close(FreeImageIO *io, fi_handle handle, void *data) {
839
0
}
840
841
// ----------------------------------------------------------
842
843
static FIBITMAP * DLL_CALLCONV
844
0
Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
845
0
  DDSHEADER header;
846
0
  FIBITMAP *dib = NULL;
847
848
0
  memset(&header, 0, sizeof(header));
849
0
  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
0
  const DWORD dwFlags = header.surfaceDesc.ddspf.dwFlags;
856
857
0
  const DDSURFACEDESC2 *surfaceDesc = &(header.surfaceDesc);
858
859
0
  if ((dwFlags & DDPF_RGB) == DDPF_RGB) {
860
    // uncompressed data
861
0
    dib = LoadRGB(surfaceDesc, io, handle);
862
0
  }
863
0
  else if ((dwFlags & DDPF_FOURCC) == DDPF_FOURCC) {
864
    // compressed data
865
0
    switch (surfaceDesc->ddspf.dwFourCC) {
866
0
      case FOURCC_DXT1:
867
0
        dib = LoadDXT(1, surfaceDesc, io, handle);
868
0
        break;
869
0
      case FOURCC_DXT3:
870
0
        dib = LoadDXT(3, surfaceDesc, io, handle);
871
0
        break;
872
0
      case FOURCC_DXT5:
873
0
        dib = LoadDXT(5, surfaceDesc, io, handle);
874
0
        break;
875
0
    }
876
0
  }
877
878
0
  return dib;
879
0
}
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
893
2
InitDDS(Plugin *plugin, int format_id) {
894
2
  s_format_id = format_id;
895
896
2
  plugin->format_proc = Format;
897
2
  plugin->description_proc = Description;
898
2
  plugin->extension_proc = Extension;
899
2
  plugin->regexpr_proc = RegExpr;
900
2
  plugin->open_proc = Open;
901
2
  plugin->close_proc = Close;
902
2
  plugin->pagecount_proc = NULL;
903
2
  plugin->pagecapability_proc = NULL;
904
2
  plugin->load_proc = Load;
905
2
  plugin->save_proc = NULL; //Save; // not implemented (yet?)
906
2
  plugin->validate_proc = Validate;
907
2
  plugin->mime_proc = MimeType;
908
2
  plugin->supports_export_bpp_proc = SupportsExportDepth;
909
2
  plugin->supports_export_type_proc = SupportsExportType;
910
  plugin->supports_icc_profiles_proc = NULL;
911
2
}