Coverage Report

Created: 2026-09-28 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/imagemagick/coders/dds.c
Line
Count
Source
1
/*
2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3
%                                                                             %
4
%                                                                             %
5
%                                                                             %
6
%                            DDDD   DDDD   SSSSS                              %
7
%                            D   D  D   D  SS                                 %
8
%                            D   D  D   D   SSS                               %
9
%                            D   D  D   D     SS                              %
10
%                            DDDD   DDDD   SSSSS                              %
11
%                                                                             %
12
%                                                                             %
13
%           Read/Write Microsoft Direct Draw Surface Image Format             %
14
%                                                                             %
15
%                              Software Design                                %
16
%                             Bianca van Schaik                               %
17
%                                March 2008                                   %
18
%                               Dirk Lemstra                                  %
19
%                              September 2013                                 %
20
%                                                                             %
21
%                                                                             %
22
%  Copyright @ 1999 ImageMagick Studio LLC, a non-profit organization         %
23
%  dedicated to making software imaging solutions freely available.           %
24
%                                                                             %
25
%  You may not use this file except in compliance with the License.  You may  %
26
%  obtain a copy of the License at                                            %
27
%                                                                             %
28
%    https://imagemagick.org/license/                                         %
29
%                                                                             %
30
%  Unless required by applicable law or agreed to in writing, software        %
31
%  distributed under the License is distributed on an "AS IS" BASIS,          %
32
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
33
%  See the License for the specific language governing permissions and        %
34
%  limitations under the License.                                             %
35
%                                                                             %
36
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37
%
38
%
39
*/
40

41
/*
42
  Include declarations.
43
*/
44
#include "MagickCore/studio.h"
45
#include "MagickCore/attribute.h"
46
#include "MagickCore/blob.h"
47
#include "MagickCore/blob-private.h"
48
#include "MagickCore/cache.h"
49
#include "MagickCore/colorspace.h"
50
#include "MagickCore/colorspace-private.h"
51
#include "MagickCore/exception.h"
52
#include "MagickCore/exception-private.h"
53
#include "MagickCore/image.h"
54
#include "MagickCore/image-private.h"
55
#include "MagickCore/list.h"
56
#include "MagickCore/log.h"
57
#include "MagickCore/magick.h"
58
#include "MagickCore/memory_.h"
59
#include "MagickCore/monitor.h"
60
#include "MagickCore/monitor-private.h"
61
#include "MagickCore/option.h"
62
#include "MagickCore/pixel-accessor.h"
63
#include "MagickCore/profile.h"
64
#include "MagickCore/quantum.h"
65
#include "MagickCore/quantum-private.h"
66
#include "MagickCore/resource_.h"
67
#include "MagickCore/static.h"
68
#include "MagickCore/string_.h"
69
#include "MagickCore/string-private.h"
70
#include "MagickCore/module.h"
71
#include "MagickCore/transform.h"
72

73
/*
74
  Definitions
75
*/
76
11.7k
#define DDSD_CAPS         0x00000001
77
11.7k
#define DDSD_HEIGHT       0x00000002
78
11.7k
#define DDSD_WIDTH        0x00000004
79
0
#define DDSD_PITCH        0x00000008
80
11.7k
#define DDSD_PIXELFORMAT  0x00001000
81
1.18k
#define DDSD_MIPMAPCOUNT  0x00020000
82
2.73k
#define DDSD_LINEARSIZE   0x00080000
83
#define DDSD_DEPTH        0x00800000
84
85
4.52k
#define DDPF_ALPHAPIXELS  0x00000001
86
5.79k
#define DDPF_ALPHA        0x00000002
87
38.5k
#define DDPF_FOURCC       0x00000004
88
8.86k
#define DDPF_RGB          0x00000040
89
5.07k
#define DDPF_LUMINANCE    0x00020000
90
91
341
#define FOURCC_ATI2       0x32495441
92
353
#define FOURCC_BC5U       0x55354342
93
5.47k
#define FOURCC_DXT1       0x31545844
94
204
#define FOURCC_DXT3       0x33545844
95
2.16M
#define FOURCC_DXT5       0x35545844
96
7.75k
#define FOURCC_DX10       0x30315844
97
98
1.18k
#define DDSCAPS_COMPLEX   0x00000008
99
11.7k
#define DDSCAPS_TEXTURE   0x00001000
100
17.5k
#define DDSCAPS_MIPMAP    0x00400000
101
102
11.1k
#define DDSCAPS2_CUBEMAP  0x00000200
103
2.52k
#define DDSCAPS2_CUBEMAP_POSITIVEX  0x00000400
104
2.52k
#define DDSCAPS2_CUBEMAP_NEGATIVEX  0x00000800
105
2.52k
#define DDSCAPS2_CUBEMAP_POSITIVEY  0x00001000
106
2.52k
#define DDSCAPS2_CUBEMAP_NEGATIVEY  0x00002000
107
2.52k
#define DDSCAPS2_CUBEMAP_POSITIVEZ  0x00004000
108
2.52k
#define DDSCAPS2_CUBEMAP_NEGATIVEZ  0x00008000
109
17.7k
#define DDSCAPS2_VOLUME   0x00200000
110
111
756
#define DDSEXT_DIMENSION_TEX2D      0x00000003
112
660
#define DDSEXTFLAGS_CUBEMAP         0x00000004
113
114
typedef enum DXGI_FORMAT 
115
{
116
  DXGI_FORMAT_UNKNOWN,
117
  DXGI_FORMAT_R32G32B32A32_TYPELESS,
118
  DXGI_FORMAT_R32G32B32A32_FLOAT,
119
  DXGI_FORMAT_R32G32B32A32_UINT,
120
  DXGI_FORMAT_R32G32B32A32_SINT,
121
  DXGI_FORMAT_R32G32B32_TYPELESS,
122
  DXGI_FORMAT_R32G32B32_FLOAT,
123
  DXGI_FORMAT_R32G32B32_UINT,
124
  DXGI_FORMAT_R32G32B32_SINT,
125
  DXGI_FORMAT_R16G16B16A16_TYPELESS,
126
  DXGI_FORMAT_R16G16B16A16_FLOAT,
127
  DXGI_FORMAT_R16G16B16A16_UNORM,
128
  DXGI_FORMAT_R16G16B16A16_UINT,
129
  DXGI_FORMAT_R16G16B16A16_SNORM,
130
  DXGI_FORMAT_R16G16B16A16_SINT,
131
  DXGI_FORMAT_R32G32_TYPELESS,
132
  DXGI_FORMAT_R32G32_FLOAT,
133
  DXGI_FORMAT_R32G32_UINT,
134
  DXGI_FORMAT_R32G32_SINT,
135
  DXGI_FORMAT_R32G8X24_TYPELESS,
136
  DXGI_FORMAT_D32_FLOAT_S8X24_UINT,
137
  DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS,
138
  DXGI_FORMAT_X32_TYPELESS_G8X24_UINT,
139
  DXGI_FORMAT_R10G10B10A2_TYPELESS,
140
  DXGI_FORMAT_R10G10B10A2_UNORM,
141
  DXGI_FORMAT_R10G10B10A2_UINT,
142
  DXGI_FORMAT_R11G11B10_FLOAT,
143
  DXGI_FORMAT_R8G8B8A8_TYPELESS,
144
  DXGI_FORMAT_R8G8B8A8_UNORM,
145
  DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
146
  DXGI_FORMAT_R8G8B8A8_UINT,
147
  DXGI_FORMAT_R8G8B8A8_SNORM,
148
  DXGI_FORMAT_R8G8B8A8_SINT,
149
  DXGI_FORMAT_R16G16_TYPELESS,
150
  DXGI_FORMAT_R16G16_FLOAT,
151
  DXGI_FORMAT_R16G16_UNORM,
152
  DXGI_FORMAT_R16G16_UINT,
153
  DXGI_FORMAT_R16G16_SNORM,
154
  DXGI_FORMAT_R16G16_SINT,
155
  DXGI_FORMAT_R32_TYPELESS,
156
  DXGI_FORMAT_D32_FLOAT,
157
  DXGI_FORMAT_R32_FLOAT,
158
  DXGI_FORMAT_R32_UINT,
159
  DXGI_FORMAT_R32_SINT,
160
  DXGI_FORMAT_R24G8_TYPELESS,
161
  DXGI_FORMAT_D24_UNORM_S8_UINT,
162
  DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
163
  DXGI_FORMAT_X24_TYPELESS_G8_UINT,
164
  DXGI_FORMAT_R8G8_TYPELESS,
165
  DXGI_FORMAT_R8G8_UNORM,
166
  DXGI_FORMAT_R8G8_UINT,
167
  DXGI_FORMAT_R8G8_SNORM,
168
  DXGI_FORMAT_R8G8_SINT,
169
  DXGI_FORMAT_R16_TYPELESS,
170
  DXGI_FORMAT_R16_FLOAT,
171
  DXGI_FORMAT_D16_UNORM,
172
  DXGI_FORMAT_R16_UNORM,
173
  DXGI_FORMAT_R16_UINT,
174
  DXGI_FORMAT_R16_SNORM,
175
  DXGI_FORMAT_R16_SINT,
176
  DXGI_FORMAT_R8_TYPELESS,
177
  DXGI_FORMAT_R8_UNORM,
178
  DXGI_FORMAT_R8_UINT,
179
  DXGI_FORMAT_R8_SNORM,
180
  DXGI_FORMAT_R8_SINT,
181
  DXGI_FORMAT_A8_UNORM,
182
  DXGI_FORMAT_R1_UNORM,
183
  DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
184
  DXGI_FORMAT_R8G8_B8G8_UNORM,
185
  DXGI_FORMAT_G8R8_G8B8_UNORM,
186
  DXGI_FORMAT_BC1_TYPELESS,
187
  DXGI_FORMAT_BC1_UNORM,
188
  DXGI_FORMAT_BC1_UNORM_SRGB,
189
  DXGI_FORMAT_BC2_TYPELESS,
190
  DXGI_FORMAT_BC2_UNORM,
191
  DXGI_FORMAT_BC2_UNORM_SRGB,
192
  DXGI_FORMAT_BC3_TYPELESS,
193
  DXGI_FORMAT_BC3_UNORM,
194
  DXGI_FORMAT_BC3_UNORM_SRGB,
195
  DXGI_FORMAT_BC4_TYPELESS,
196
  DXGI_FORMAT_BC4_UNORM,
197
  DXGI_FORMAT_BC4_SNORM,
198
  DXGI_FORMAT_BC5_TYPELESS,
199
  DXGI_FORMAT_BC5_UNORM,
200
  DXGI_FORMAT_BC5_SNORM,
201
  DXGI_FORMAT_B5G6R5_UNORM,
202
  DXGI_FORMAT_B5G5R5A1_UNORM,
203
  DXGI_FORMAT_B8G8R8A8_UNORM,
204
  DXGI_FORMAT_B8G8R8X8_UNORM,
205
  DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM,
206
  DXGI_FORMAT_B8G8R8A8_TYPELESS,
207
  DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
208
  DXGI_FORMAT_B8G8R8X8_TYPELESS,
209
  DXGI_FORMAT_B8G8R8X8_UNORM_SRGB,
210
  DXGI_FORMAT_BC6H_TYPELESS,
211
  DXGI_FORMAT_BC6H_UF16,
212
  DXGI_FORMAT_BC6H_SF16,
213
  DXGI_FORMAT_BC7_TYPELESS,
214
  DXGI_FORMAT_BC7_UNORM,
215
  DXGI_FORMAT_BC7_UNORM_SRGB,
216
  DXGI_FORMAT_AYUV,
217
  DXGI_FORMAT_Y410,
218
  DXGI_FORMAT_Y416,
219
  DXGI_FORMAT_NV12,
220
  DXGI_FORMAT_P010,
221
  DXGI_FORMAT_P016,
222
  DXGI_FORMAT_420_OPAQUE,
223
  DXGI_FORMAT_YUY2,
224
  DXGI_FORMAT_Y210,
225
  DXGI_FORMAT_Y216,
226
  DXGI_FORMAT_NV11,
227
  DXGI_FORMAT_AI44,
228
  DXGI_FORMAT_IA44,
229
  DXGI_FORMAT_P8,
230
  DXGI_FORMAT_A8P8,
231
  DXGI_FORMAT_B4G4R4A4_UNORM,
232
  DXGI_FORMAT_P208,
233
  DXGI_FORMAT_V208,
234
  DXGI_FORMAT_V408,
235
  DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE,
236
  DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE,
237
  DXGI_FORMAT_FORCE_UINT
238
} DXGI_FORMAT;
239
240
241
#ifndef SIZE_MAX
242
#define SIZE_MAX ((size_t) -1)
243
#endif
244
245
/*
246
  Structure declarations.
247
*/
248
typedef struct _DDSPixelFormat
249
{
250
  size_t
251
    flags,
252
    fourcc,
253
    rgb_bitcount,
254
    r_bitmask,
255
    g_bitmask,
256
    b_bitmask,
257
    alpha_bitmask;
258
} DDSPixelFormat;
259
260
typedef struct _DDSInfo
261
{
262
  size_t
263
    flags,
264
    height,
265
    width,
266
    pitchOrLinearSize,
267
    depth,
268
    mipmapcount,
269
    ddscaps1,
270
    ddscaps2,
271
    extFormat,
272
    extDimension,
273
    extFlags,
274
    extArraySize,
275
    extFlags2;
276
  
277
  DDSPixelFormat
278
    pixelformat;
279
} DDSInfo;
280
281
typedef struct _DDSColors
282
{
283
  unsigned char
284
    r[4],
285
    g[4],
286
    b[4],
287
    a[4];
288
} DDSColors;
289
290
typedef struct _BC5Colors
291
{
292
  unsigned char
293
    r[8],
294
    g[8];
295
} BC5Colors;
296
297
typedef struct _BC7Colors
298
{
299
  unsigned char
300
    r[6],
301
    g[6],
302
    b[6],
303
    a[6];
304
} BC7Colors;
305
306
typedef struct _DDSVector4
307
{
308
  float
309
    x,
310
    y,
311
    z,
312
    w;
313
} DDSVector4;
314
315
typedef struct _DDSVector3
316
{
317
  float
318
    x,
319
    y,
320
    z;
321
} DDSVector3;
322
323
typedef struct _DDSSourceBlock
324
{
325
  unsigned char
326
    start,
327
    end,
328
    error;
329
} DDSSourceBlock;
330
331
typedef struct _DDSSingleColorLookup
332
{
333
  DDSSourceBlock sources[2];
334
} DDSSingleColorLookup;
335
336
typedef struct _BC7ModeInfo
337
{
338
  unsigned char
339
    partition_bits,
340
    num_subsets,
341
    color_precision,
342
    alpha_precision,
343
    num_pbits,
344
    index_precision,
345
    index2_precision;
346
} BC7ModeInfo;
347
348
typedef MagickBooleanType
349
  DDSDecoder(const ImageInfo *,Image *,const DDSInfo *,const MagickBooleanType,
350
    ExceptionInfo *);
351
352
typedef MagickBooleanType
353
  DDSPixelDecoder(Image *,const DDSInfo *,ExceptionInfo *);
354
355
static const DDSSingleColorLookup DDSLookup_5_4[] =
356
{
357
  { { { 0, 0, 0 }, { 0, 0, 0 } } },
358
  { { { 0, 0, 1 }, { 0, 1, 1 } } },
359
  { { { 0, 0, 2 }, { 0, 1, 0 } } },
360
  { { { 0, 0, 3 }, { 0, 1, 1 } } },
361
  { { { 0, 0, 4 }, { 0, 2, 1 } } },
362
  { { { 1, 0, 3 }, { 0, 2, 0 } } },
363
  { { { 1, 0, 2 }, { 0, 2, 1 } } },
364
  { { { 1, 0, 1 }, { 0, 3, 1 } } },
365
  { { { 1, 0, 0 }, { 0, 3, 0 } } },
366
  { { { 1, 0, 1 }, { 1, 2, 1 } } },
367
  { { { 1, 0, 2 }, { 1, 2, 0 } } },
368
  { { { 1, 0, 3 }, { 0, 4, 0 } } },
369
  { { { 1, 0, 4 }, { 0, 5, 1 } } },
370
  { { { 2, 0, 3 }, { 0, 5, 0 } } },
371
  { { { 2, 0, 2 }, { 0, 5, 1 } } },
372
  { { { 2, 0, 1 }, { 0, 6, 1 } } },
373
  { { { 2, 0, 0 }, { 0, 6, 0 } } },
374
  { { { 2, 0, 1 }, { 2, 3, 1 } } },
375
  { { { 2, 0, 2 }, { 2, 3, 0 } } },
376
  { { { 2, 0, 3 }, { 0, 7, 0 } } },
377
  { { { 2, 0, 4 }, { 1, 6, 1 } } },
378
  { { { 3, 0, 3 }, { 1, 6, 0 } } },
379
  { { { 3, 0, 2 }, { 0, 8, 0 } } },
380
  { { { 3, 0, 1 }, { 0, 9, 1 } } },
381
  { { { 3, 0, 0 }, { 0, 9, 0 } } },
382
  { { { 3, 0, 1 }, { 0, 9, 1 } } },
383
  { { { 3, 0, 2 }, { 0, 10, 1 } } },
384
  { { { 3, 0, 3 }, { 0, 10, 0 } } },
385
  { { { 3, 0, 4 }, { 2, 7, 1 } } },
386
  { { { 4, 0, 4 }, { 2, 7, 0 } } },
387
  { { { 4, 0, 3 }, { 0, 11, 0 } } },
388
  { { { 4, 0, 2 }, { 1, 10, 1 } } },
389
  { { { 4, 0, 1 }, { 1, 10, 0 } } },
390
  { { { 4, 0, 0 }, { 0, 12, 0 } } },
391
  { { { 4, 0, 1 }, { 0, 13, 1 } } },
392
  { { { 4, 0, 2 }, { 0, 13, 0 } } },
393
  { { { 4, 0, 3 }, { 0, 13, 1 } } },
394
  { { { 4, 0, 4 }, { 0, 14, 1 } } },
395
  { { { 5, 0, 3 }, { 0, 14, 0 } } },
396
  { { { 5, 0, 2 }, { 2, 11, 1 } } },
397
  { { { 5, 0, 1 }, { 2, 11, 0 } } },
398
  { { { 5, 0, 0 }, { 0, 15, 0 } } },
399
  { { { 5, 0, 1 }, { 1, 14, 1 } } },
400
  { { { 5, 0, 2 }, { 1, 14, 0 } } },
401
  { { { 5, 0, 3 }, { 0, 16, 0 } } },
402
  { { { 5, 0, 4 }, { 0, 17, 1 } } },
403
  { { { 6, 0, 3 }, { 0, 17, 0 } } },
404
  { { { 6, 0, 2 }, { 0, 17, 1 } } },
405
  { { { 6, 0, 1 }, { 0, 18, 1 } } },
406
  { { { 6, 0, 0 }, { 0, 18, 0 } } },
407
  { { { 6, 0, 1 }, { 2, 15, 1 } } },
408
  { { { 6, 0, 2 }, { 2, 15, 0 } } },
409
  { { { 6, 0, 3 }, { 0, 19, 0 } } },
410
  { { { 6, 0, 4 }, { 1, 18, 1 } } },
411
  { { { 7, 0, 3 }, { 1, 18, 0 } } },
412
  { { { 7, 0, 2 }, { 0, 20, 0 } } },
413
  { { { 7, 0, 1 }, { 0, 21, 1 } } },
414
  { { { 7, 0, 0 }, { 0, 21, 0 } } },
415
  { { { 7, 0, 1 }, { 0, 21, 1 } } },
416
  { { { 7, 0, 2 }, { 0, 22, 1 } } },
417
  { { { 7, 0, 3 }, { 0, 22, 0 } } },
418
  { { { 7, 0, 4 }, { 2, 19, 1 } } },
419
  { { { 8, 0, 4 }, { 2, 19, 0 } } },
420
  { { { 8, 0, 3 }, { 0, 23, 0 } } },
421
  { { { 8, 0, 2 }, { 1, 22, 1 } } },
422
  { { { 8, 0, 1 }, { 1, 22, 0 } } },
423
  { { { 8, 0, 0 }, { 0, 24, 0 } } },
424
  { { { 8, 0, 1 }, { 0, 25, 1 } } },
425
  { { { 8, 0, 2 }, { 0, 25, 0 } } },
426
  { { { 8, 0, 3 }, { 0, 25, 1 } } },
427
  { { { 8, 0, 4 }, { 0, 26, 1 } } },
428
  { { { 9, 0, 3 }, { 0, 26, 0 } } },
429
  { { { 9, 0, 2 }, { 2, 23, 1 } } },
430
  { { { 9, 0, 1 }, { 2, 23, 0 } } },
431
  { { { 9, 0, 0 }, { 0, 27, 0 } } },
432
  { { { 9, 0, 1 }, { 1, 26, 1 } } },
433
  { { { 9, 0, 2 }, { 1, 26, 0 } } },
434
  { { { 9, 0, 3 }, { 0, 28, 0 } } },
435
  { { { 9, 0, 4 }, { 0, 29, 1 } } },
436
  { { { 10, 0, 3 }, { 0, 29, 0 } } },
437
  { { { 10, 0, 2 }, { 0, 29, 1 } } },
438
  { { { 10, 0, 1 }, { 0, 30, 1 } } },
439
  { { { 10, 0, 0 }, { 0, 30, 0 } } },
440
  { { { 10, 0, 1 }, { 2, 27, 1 } } },
441
  { { { 10, 0, 2 }, { 2, 27, 0 } } },
442
  { { { 10, 0, 3 }, { 0, 31, 0 } } },
443
  { { { 10, 0, 4 }, { 1, 30, 1 } } },
444
  { { { 11, 0, 3 }, { 1, 30, 0 } } },
445
  { { { 11, 0, 2 }, { 4, 24, 0 } } },
446
  { { { 11, 0, 1 }, { 1, 31, 1 } } },
447
  { { { 11, 0, 0 }, { 1, 31, 0 } } },
448
  { { { 11, 0, 1 }, { 1, 31, 1 } } },
449
  { { { 11, 0, 2 }, { 2, 30, 1 } } },
450
  { { { 11, 0, 3 }, { 2, 30, 0 } } },
451
  { { { 11, 0, 4 }, { 2, 31, 1 } } },
452
  { { { 12, 0, 4 }, { 2, 31, 0 } } },
453
  { { { 12, 0, 3 }, { 4, 27, 0 } } },
454
  { { { 12, 0, 2 }, { 3, 30, 1 } } },
455
  { { { 12, 0, 1 }, { 3, 30, 0 } } },
456
  { { { 12, 0, 0 }, { 4, 28, 0 } } },
457
  { { { 12, 0, 1 }, { 3, 31, 1 } } },
458
  { { { 12, 0, 2 }, { 3, 31, 0 } } },
459
  { { { 12, 0, 3 }, { 3, 31, 1 } } },
460
  { { { 12, 0, 4 }, { 4, 30, 1 } } },
461
  { { { 13, 0, 3 }, { 4, 30, 0 } } },
462
  { { { 13, 0, 2 }, { 6, 27, 1 } } },
463
  { { { 13, 0, 1 }, { 6, 27, 0 } } },
464
  { { { 13, 0, 0 }, { 4, 31, 0 } } },
465
  { { { 13, 0, 1 }, { 5, 30, 1 } } },
466
  { { { 13, 0, 2 }, { 5, 30, 0 } } },
467
  { { { 13, 0, 3 }, { 8, 24, 0 } } },
468
  { { { 13, 0, 4 }, { 5, 31, 1 } } },
469
  { { { 14, 0, 3 }, { 5, 31, 0 } } },
470
  { { { 14, 0, 2 }, { 5, 31, 1 } } },
471
  { { { 14, 0, 1 }, { 6, 30, 1 } } },
472
  { { { 14, 0, 0 }, { 6, 30, 0 } } },
473
  { { { 14, 0, 1 }, { 6, 31, 1 } } },
474
  { { { 14, 0, 2 }, { 6, 31, 0 } } },
475
  { { { 14, 0, 3 }, { 8, 27, 0 } } },
476
  { { { 14, 0, 4 }, { 7, 30, 1 } } },
477
  { { { 15, 0, 3 }, { 7, 30, 0 } } },
478
  { { { 15, 0, 2 }, { 8, 28, 0 } } },
479
  { { { 15, 0, 1 }, { 7, 31, 1 } } },
480
  { { { 15, 0, 0 }, { 7, 31, 0 } } },
481
  { { { 15, 0, 1 }, { 7, 31, 1 } } },
482
  { { { 15, 0, 2 }, { 8, 30, 1 } } },
483
  { { { 15, 0, 3 }, { 8, 30, 0 } } },
484
  { { { 15, 0, 4 }, { 10, 27, 1 } } },
485
  { { { 16, 0, 4 }, { 10, 27, 0 } } },
486
  { { { 16, 0, 3 }, { 8, 31, 0 } } },
487
  { { { 16, 0, 2 }, { 9, 30, 1 } } },
488
  { { { 16, 0, 1 }, { 9, 30, 0 } } },
489
  { { { 16, 0, 0 }, { 12, 24, 0 } } },
490
  { { { 16, 0, 1 }, { 9, 31, 1 } } },
491
  { { { 16, 0, 2 }, { 9, 31, 0 } } },
492
  { { { 16, 0, 3 }, { 9, 31, 1 } } },
493
  { { { 16, 0, 4 }, { 10, 30, 1 } } },
494
  { { { 17, 0, 3 }, { 10, 30, 0 } } },
495
  { { { 17, 0, 2 }, { 10, 31, 1 } } },
496
  { { { 17, 0, 1 }, { 10, 31, 0 } } },
497
  { { { 17, 0, 0 }, { 12, 27, 0 } } },
498
  { { { 17, 0, 1 }, { 11, 30, 1 } } },
499
  { { { 17, 0, 2 }, { 11, 30, 0 } } },
500
  { { { 17, 0, 3 }, { 12, 28, 0 } } },
501
  { { { 17, 0, 4 }, { 11, 31, 1 } } },
502
  { { { 18, 0, 3 }, { 11, 31, 0 } } },
503
  { { { 18, 0, 2 }, { 11, 31, 1 } } },
504
  { { { 18, 0, 1 }, { 12, 30, 1 } } },
505
  { { { 18, 0, 0 }, { 12, 30, 0 } } },
506
  { { { 18, 0, 1 }, { 14, 27, 1 } } },
507
  { { { 18, 0, 2 }, { 14, 27, 0 } } },
508
  { { { 18, 0, 3 }, { 12, 31, 0 } } },
509
  { { { 18, 0, 4 }, { 13, 30, 1 } } },
510
  { { { 19, 0, 3 }, { 13, 30, 0 } } },
511
  { { { 19, 0, 2 }, { 16, 24, 0 } } },
512
  { { { 19, 0, 1 }, { 13, 31, 1 } } },
513
  { { { 19, 0, 0 }, { 13, 31, 0 } } },
514
  { { { 19, 0, 1 }, { 13, 31, 1 } } },
515
  { { { 19, 0, 2 }, { 14, 30, 1 } } },
516
  { { { 19, 0, 3 }, { 14, 30, 0 } } },
517
  { { { 19, 0, 4 }, { 14, 31, 1 } } },
518
  { { { 20, 0, 4 }, { 14, 31, 0 } } },
519
  { { { 20, 0, 3 }, { 16, 27, 0 } } },
520
  { { { 20, 0, 2 }, { 15, 30, 1 } } },
521
  { { { 20, 0, 1 }, { 15, 30, 0 } } },
522
  { { { 20, 0, 0 }, { 16, 28, 0 } } },
523
  { { { 20, 0, 1 }, { 15, 31, 1 } } },
524
  { { { 20, 0, 2 }, { 15, 31, 0 } } },
525
  { { { 20, 0, 3 }, { 15, 31, 1 } } },
526
  { { { 20, 0, 4 }, { 16, 30, 1 } } },
527
  { { { 21, 0, 3 }, { 16, 30, 0 } } },
528
  { { { 21, 0, 2 }, { 18, 27, 1 } } },
529
  { { { 21, 0, 1 }, { 18, 27, 0 } } },
530
  { { { 21, 0, 0 }, { 16, 31, 0 } } },
531
  { { { 21, 0, 1 }, { 17, 30, 1 } } },
532
  { { { 21, 0, 2 }, { 17, 30, 0 } } },
533
  { { { 21, 0, 3 }, { 20, 24, 0 } } },
534
  { { { 21, 0, 4 }, { 17, 31, 1 } } },
535
  { { { 22, 0, 3 }, { 17, 31, 0 } } },
536
  { { { 22, 0, 2 }, { 17, 31, 1 } } },
537
  { { { 22, 0, 1 }, { 18, 30, 1 } } },
538
  { { { 22, 0, 0 }, { 18, 30, 0 } } },
539
  { { { 22, 0, 1 }, { 18, 31, 1 } } },
540
  { { { 22, 0, 2 }, { 18, 31, 0 } } },
541
  { { { 22, 0, 3 }, { 20, 27, 0 } } },
542
  { { { 22, 0, 4 }, { 19, 30, 1 } } },
543
  { { { 23, 0, 3 }, { 19, 30, 0 } } },
544
  { { { 23, 0, 2 }, { 20, 28, 0 } } },
545
  { { { 23, 0, 1 }, { 19, 31, 1 } } },
546
  { { { 23, 0, 0 }, { 19, 31, 0 } } },
547
  { { { 23, 0, 1 }, { 19, 31, 1 } } },
548
  { { { 23, 0, 2 }, { 20, 30, 1 } } },
549
  { { { 23, 0, 3 }, { 20, 30, 0 } } },
550
  { { { 23, 0, 4 }, { 22, 27, 1 } } },
551
  { { { 24, 0, 4 }, { 22, 27, 0 } } },
552
  { { { 24, 0, 3 }, { 20, 31, 0 } } },
553
  { { { 24, 0, 2 }, { 21, 30, 1 } } },
554
  { { { 24, 0, 1 }, { 21, 30, 0 } } },
555
  { { { 24, 0, 0 }, { 24, 24, 0 } } },
556
  { { { 24, 0, 1 }, { 21, 31, 1 } } },
557
  { { { 24, 0, 2 }, { 21, 31, 0 } } },
558
  { { { 24, 0, 3 }, { 21, 31, 1 } } },
559
  { { { 24, 0, 4 }, { 22, 30, 1 } } },
560
  { { { 25, 0, 3 }, { 22, 30, 0 } } },
561
  { { { 25, 0, 2 }, { 22, 31, 1 } } },
562
  { { { 25, 0, 1 }, { 22, 31, 0 } } },
563
  { { { 25, 0, 0 }, { 24, 27, 0 } } },
564
  { { { 25, 0, 1 }, { 23, 30, 1 } } },
565
  { { { 25, 0, 2 }, { 23, 30, 0 } } },
566
  { { { 25, 0, 3 }, { 24, 28, 0 } } },
567
  { { { 25, 0, 4 }, { 23, 31, 1 } } },
568
  { { { 26, 0, 3 }, { 23, 31, 0 } } },
569
  { { { 26, 0, 2 }, { 23, 31, 1 } } },
570
  { { { 26, 0, 1 }, { 24, 30, 1 } } },
571
  { { { 26, 0, 0 }, { 24, 30, 0 } } },
572
  { { { 26, 0, 1 }, { 26, 27, 1 } } },
573
  { { { 26, 0, 2 }, { 26, 27, 0 } } },
574
  { { { 26, 0, 3 }, { 24, 31, 0 } } },
575
  { { { 26, 0, 4 }, { 25, 30, 1 } } },
576
  { { { 27, 0, 3 }, { 25, 30, 0 } } },
577
  { { { 27, 0, 2 }, { 28, 24, 0 } } },
578
  { { { 27, 0, 1 }, { 25, 31, 1 } } },
579
  { { { 27, 0, 0 }, { 25, 31, 0 } } },
580
  { { { 27, 0, 1 }, { 25, 31, 1 } } },
581
  { { { 27, 0, 2 }, { 26, 30, 1 } } },
582
  { { { 27, 0, 3 }, { 26, 30, 0 } } },
583
  { { { 27, 0, 4 }, { 26, 31, 1 } } },
584
  { { { 28, 0, 4 }, { 26, 31, 0 } } },
585
  { { { 28, 0, 3 }, { 28, 27, 0 } } },
586
  { { { 28, 0, 2 }, { 27, 30, 1 } } },
587
  { { { 28, 0, 1 }, { 27, 30, 0 } } },
588
  { { { 28, 0, 0 }, { 28, 28, 0 } } },
589
  { { { 28, 0, 1 }, { 27, 31, 1 } } },
590
  { { { 28, 0, 2 }, { 27, 31, 0 } } },
591
  { { { 28, 0, 3 }, { 27, 31, 1 } } },
592
  { { { 28, 0, 4 }, { 28, 30, 1 } } },
593
  { { { 29, 0, 3 }, { 28, 30, 0 } } },
594
  { { { 29, 0, 2 }, { 30, 27, 1 } } },
595
  { { { 29, 0, 1 }, { 30, 27, 0 } } },
596
  { { { 29, 0, 0 }, { 28, 31, 0 } } },
597
  { { { 29, 0, 1 }, { 29, 30, 1 } } },
598
  { { { 29, 0, 2 }, { 29, 30, 0 } } },
599
  { { { 29, 0, 3 }, { 29, 30, 1 } } },
600
  { { { 29, 0, 4 }, { 29, 31, 1 } } },
601
  { { { 30, 0, 3 }, { 29, 31, 0 } } },
602
  { { { 30, 0, 2 }, { 29, 31, 1 } } },
603
  { { { 30, 0, 1 }, { 30, 30, 1 } } },
604
  { { { 30, 0, 0 }, { 30, 30, 0 } } },
605
  { { { 30, 0, 1 }, { 30, 31, 1 } } },
606
  { { { 30, 0, 2 }, { 30, 31, 0 } } },
607
  { { { 30, 0, 3 }, { 30, 31, 1 } } },
608
  { { { 30, 0, 4 }, { 31, 30, 1 } } },
609
  { { { 31, 0, 3 }, { 31, 30, 0 } } },
610
  { { { 31, 0, 2 }, { 31, 30, 1 } } },
611
  { { { 31, 0, 1 }, { 31, 31, 1 } } },
612
  { { { 31, 0, 0 }, { 31, 31, 0 } } }
613
};
614
615
static const DDSSingleColorLookup DDSLookup_6_4[] =
616
{
617
  { { { 0, 0, 0 }, { 0, 0, 0 } } },
618
  { { { 0, 0, 1 }, { 0, 1, 0 } } },
619
  { { { 0, 0, 2 }, { 0, 2, 0 } } },
620
  { { { 1, 0, 1 }, { 0, 3, 1 } } },
621
  { { { 1, 0, 0 }, { 0, 3, 0 } } },
622
  { { { 1, 0, 1 }, { 0, 4, 0 } } },
623
  { { { 1, 0, 2 }, { 0, 5, 0 } } },
624
  { { { 2, 0, 1 }, { 0, 6, 1 } } },
625
  { { { 2, 0, 0 }, { 0, 6, 0 } } },
626
  { { { 2, 0, 1 }, { 0, 7, 0 } } },
627
  { { { 2, 0, 2 }, { 0, 8, 0 } } },
628
  { { { 3, 0, 1 }, { 0, 9, 1 } } },
629
  { { { 3, 0, 0 }, { 0, 9, 0 } } },
630
  { { { 3, 0, 1 }, { 0, 10, 0 } } },
631
  { { { 3, 0, 2 }, { 0, 11, 0 } } },
632
  { { { 4, 0, 1 }, { 0, 12, 1 } } },
633
  { { { 4, 0, 0 }, { 0, 12, 0 } } },
634
  { { { 4, 0, 1 }, { 0, 13, 0 } } },
635
  { { { 4, 0, 2 }, { 0, 14, 0 } } },
636
  { { { 5, 0, 1 }, { 0, 15, 1 } } },
637
  { { { 5, 0, 0 }, { 0, 15, 0 } } },
638
  { { { 5, 0, 1 }, { 0, 16, 0 } } },
639
  { { { 5, 0, 2 }, { 1, 15, 0 } } },
640
  { { { 6, 0, 1 }, { 0, 17, 0 } } },
641
  { { { 6, 0, 0 }, { 0, 18, 0 } } },
642
  { { { 6, 0, 1 }, { 0, 19, 0 } } },
643
  { { { 6, 0, 2 }, { 3, 14, 0 } } },
644
  { { { 7, 0, 1 }, { 0, 20, 0 } } },
645
  { { { 7, 0, 0 }, { 0, 21, 0 } } },
646
  { { { 7, 0, 1 }, { 0, 22, 0 } } },
647
  { { { 7, 0, 2 }, { 4, 15, 0 } } },
648
  { { { 8, 0, 1 }, { 0, 23, 0 } } },
649
  { { { 8, 0, 0 }, { 0, 24, 0 } } },
650
  { { { 8, 0, 1 }, { 0, 25, 0 } } },
651
  { { { 8, 0, 2 }, { 6, 14, 0 } } },
652
  { { { 9, 0, 1 }, { 0, 26, 0 } } },
653
  { { { 9, 0, 0 }, { 0, 27, 0 } } },
654
  { { { 9, 0, 1 }, { 0, 28, 0 } } },
655
  { { { 9, 0, 2 }, { 7, 15, 0 } } },
656
  { { { 10, 0, 1 }, { 0, 29, 0 } } },
657
  { { { 10, 0, 0 }, { 0, 30, 0 } } },
658
  { { { 10, 0, 1 }, { 0, 31, 0 } } },
659
  { { { 10, 0, 2 }, { 9, 14, 0 } } },
660
  { { { 11, 0, 1 }, { 0, 32, 0 } } },
661
  { { { 11, 0, 0 }, { 0, 33, 0 } } },
662
  { { { 11, 0, 1 }, { 2, 30, 0 } } },
663
  { { { 11, 0, 2 }, { 0, 34, 0 } } },
664
  { { { 12, 0, 1 }, { 0, 35, 0 } } },
665
  { { { 12, 0, 0 }, { 0, 36, 0 } } },
666
  { { { 12, 0, 1 }, { 3, 31, 0 } } },
667
  { { { 12, 0, 2 }, { 0, 37, 0 } } },
668
  { { { 13, 0, 1 }, { 0, 38, 0 } } },
669
  { { { 13, 0, 0 }, { 0, 39, 0 } } },
670
  { { { 13, 0, 1 }, { 5, 30, 0 } } },
671
  { { { 13, 0, 2 }, { 0, 40, 0 } } },
672
  { { { 14, 0, 1 }, { 0, 41, 0 } } },
673
  { { { 14, 0, 0 }, { 0, 42, 0 } } },
674
  { { { 14, 0, 1 }, { 6, 31, 0 } } },
675
  { { { 14, 0, 2 }, { 0, 43, 0 } } },
676
  { { { 15, 0, 1 }, { 0, 44, 0 } } },
677
  { { { 15, 0, 0 }, { 0, 45, 0 } } },
678
  { { { 15, 0, 1 }, { 8, 30, 0 } } },
679
  { { { 15, 0, 2 }, { 0, 46, 0 } } },
680
  { { { 16, 0, 2 }, { 0, 47, 0 } } },
681
  { { { 16, 0, 1 }, { 1, 46, 0 } } },
682
  { { { 16, 0, 0 }, { 0, 48, 0 } } },
683
  { { { 16, 0, 1 }, { 0, 49, 0 } } },
684
  { { { 16, 0, 2 }, { 0, 50, 0 } } },
685
  { { { 17, 0, 1 }, { 2, 47, 0 } } },
686
  { { { 17, 0, 0 }, { 0, 51, 0 } } },
687
  { { { 17, 0, 1 }, { 0, 52, 0 } } },
688
  { { { 17, 0, 2 }, { 0, 53, 0 } } },
689
  { { { 18, 0, 1 }, { 4, 46, 0 } } },
690
  { { { 18, 0, 0 }, { 0, 54, 0 } } },
691
  { { { 18, 0, 1 }, { 0, 55, 0 } } },
692
  { { { 18, 0, 2 }, { 0, 56, 0 } } },
693
  { { { 19, 0, 1 }, { 5, 47, 0 } } },
694
  { { { 19, 0, 0 }, { 0, 57, 0 } } },
695
  { { { 19, 0, 1 }, { 0, 58, 0 } } },
696
  { { { 19, 0, 2 }, { 0, 59, 0 } } },
697
  { { { 20, 0, 1 }, { 7, 46, 0 } } },
698
  { { { 20, 0, 0 }, { 0, 60, 0 } } },
699
  { { { 20, 0, 1 }, { 0, 61, 0 } } },
700
  { { { 20, 0, 2 }, { 0, 62, 0 } } },
701
  { { { 21, 0, 1 }, { 8, 47, 0 } } },
702
  { { { 21, 0, 0 }, { 0, 63, 0 } } },
703
  { { { 21, 0, 1 }, { 1, 62, 0 } } },
704
  { { { 21, 0, 2 }, { 1, 63, 0 } } },
705
  { { { 22, 0, 1 }, { 10, 46, 0 } } },
706
  { { { 22, 0, 0 }, { 2, 62, 0 } } },
707
  { { { 22, 0, 1 }, { 2, 63, 0 } } },
708
  { { { 22, 0, 2 }, { 3, 62, 0 } } },
709
  { { { 23, 0, 1 }, { 11, 47, 0 } } },
710
  { { { 23, 0, 0 }, { 3, 63, 0 } } },
711
  { { { 23, 0, 1 }, { 4, 62, 0 } } },
712
  { { { 23, 0, 2 }, { 4, 63, 0 } } },
713
  { { { 24, 0, 1 }, { 13, 46, 0 } } },
714
  { { { 24, 0, 0 }, { 5, 62, 0 } } },
715
  { { { 24, 0, 1 }, { 5, 63, 0 } } },
716
  { { { 24, 0, 2 }, { 6, 62, 0 } } },
717
  { { { 25, 0, 1 }, { 14, 47, 0 } } },
718
  { { { 25, 0, 0 }, { 6, 63, 0 } } },
719
  { { { 25, 0, 1 }, { 7, 62, 0 } } },
720
  { { { 25, 0, 2 }, { 7, 63, 0 } } },
721
  { { { 26, 0, 1 }, { 16, 45, 0 } } },
722
  { { { 26, 0, 0 }, { 8, 62, 0 } } },
723
  { { { 26, 0, 1 }, { 8, 63, 0 } } },
724
  { { { 26, 0, 2 }, { 9, 62, 0 } } },
725
  { { { 27, 0, 1 }, { 16, 48, 0 } } },
726
  { { { 27, 0, 0 }, { 9, 63, 0 } } },
727
  { { { 27, 0, 1 }, { 10, 62, 0 } } },
728
  { { { 27, 0, 2 }, { 10, 63, 0 } } },
729
  { { { 28, 0, 1 }, { 16, 51, 0 } } },
730
  { { { 28, 0, 0 }, { 11, 62, 0 } } },
731
  { { { 28, 0, 1 }, { 11, 63, 0 } } },
732
  { { { 28, 0, 2 }, { 12, 62, 0 } } },
733
  { { { 29, 0, 1 }, { 16, 54, 0 } } },
734
  { { { 29, 0, 0 }, { 12, 63, 0 } } },
735
  { { { 29, 0, 1 }, { 13, 62, 0 } } },
736
  { { { 29, 0, 2 }, { 13, 63, 0 } } },
737
  { { { 30, 0, 1 }, { 16, 57, 0 } } },
738
  { { { 30, 0, 0 }, { 14, 62, 0 } } },
739
  { { { 30, 0, 1 }, { 14, 63, 0 } } },
740
  { { { 30, 0, 2 }, { 15, 62, 0 } } },
741
  { { { 31, 0, 1 }, { 16, 60, 0 } } },
742
  { { { 31, 0, 0 }, { 15, 63, 0 } } },
743
  { { { 31, 0, 1 }, { 24, 46, 0 } } },
744
  { { { 31, 0, 2 }, { 16, 62, 0 } } },
745
  { { { 32, 0, 2 }, { 16, 63, 0 } } },
746
  { { { 32, 0, 1 }, { 17, 62, 0 } } },
747
  { { { 32, 0, 0 }, { 25, 47, 0 } } },
748
  { { { 32, 0, 1 }, { 17, 63, 0 } } },
749
  { { { 32, 0, 2 }, { 18, 62, 0 } } },
750
  { { { 33, 0, 1 }, { 18, 63, 0 } } },
751
  { { { 33, 0, 0 }, { 27, 46, 0 } } },
752
  { { { 33, 0, 1 }, { 19, 62, 0 } } },
753
  { { { 33, 0, 2 }, { 19, 63, 0 } } },
754
  { { { 34, 0, 1 }, { 20, 62, 0 } } },
755
  { { { 34, 0, 0 }, { 28, 47, 0 } } },
756
  { { { 34, 0, 1 }, { 20, 63, 0 } } },
757
  { { { 34, 0, 2 }, { 21, 62, 0 } } },
758
  { { { 35, 0, 1 }, { 21, 63, 0 } } },
759
  { { { 35, 0, 0 }, { 30, 46, 0 } } },
760
  { { { 35, 0, 1 }, { 22, 62, 0 } } },
761
  { { { 35, 0, 2 }, { 22, 63, 0 } } },
762
  { { { 36, 0, 1 }, { 23, 62, 0 } } },
763
  { { { 36, 0, 0 }, { 31, 47, 0 } } },
764
  { { { 36, 0, 1 }, { 23, 63, 0 } } },
765
  { { { 36, 0, 2 }, { 24, 62, 0 } } },
766
  { { { 37, 0, 1 }, { 24, 63, 0 } } },
767
  { { { 37, 0, 0 }, { 32, 47, 0 } } },
768
  { { { 37, 0, 1 }, { 25, 62, 0 } } },
769
  { { { 37, 0, 2 }, { 25, 63, 0 } } },
770
  { { { 38, 0, 1 }, { 26, 62, 0 } } },
771
  { { { 38, 0, 0 }, { 32, 50, 0 } } },
772
  { { { 38, 0, 1 }, { 26, 63, 0 } } },
773
  { { { 38, 0, 2 }, { 27, 62, 0 } } },
774
  { { { 39, 0, 1 }, { 27, 63, 0 } } },
775
  { { { 39, 0, 0 }, { 32, 53, 0 } } },
776
  { { { 39, 0, 1 }, { 28, 62, 0 } } },
777
  { { { 39, 0, 2 }, { 28, 63, 0 } } },
778
  { { { 40, 0, 1 }, { 29, 62, 0 } } },
779
  { { { 40, 0, 0 }, { 32, 56, 0 } } },
780
  { { { 40, 0, 1 }, { 29, 63, 0 } } },
781
  { { { 40, 0, 2 }, { 30, 62, 0 } } },
782
  { { { 41, 0, 1 }, { 30, 63, 0 } } },
783
  { { { 41, 0, 0 }, { 32, 59, 0 } } },
784
  { { { 41, 0, 1 }, { 31, 62, 0 } } },
785
  { { { 41, 0, 2 }, { 31, 63, 0 } } },
786
  { { { 42, 0, 1 }, { 32, 61, 0 } } },
787
  { { { 42, 0, 0 }, { 32, 62, 0 } } },
788
  { { { 42, 0, 1 }, { 32, 63, 0 } } },
789
  { { { 42, 0, 2 }, { 41, 46, 0 } } },
790
  { { { 43, 0, 1 }, { 33, 62, 0 } } },
791
  { { { 43, 0, 0 }, { 33, 63, 0 } } },
792
  { { { 43, 0, 1 }, { 34, 62, 0 } } },
793
  { { { 43, 0, 2 }, { 42, 47, 0 } } },
794
  { { { 44, 0, 1 }, { 34, 63, 0 } } },
795
  { { { 44, 0, 0 }, { 35, 62, 0 } } },
796
  { { { 44, 0, 1 }, { 35, 63, 0 } } },
797
  { { { 44, 0, 2 }, { 44, 46, 0 } } },
798
  { { { 45, 0, 1 }, { 36, 62, 0 } } },
799
  { { { 45, 0, 0 }, { 36, 63, 0 } } },
800
  { { { 45, 0, 1 }, { 37, 62, 0 } } },
801
  { { { 45, 0, 2 }, { 45, 47, 0 } } },
802
  { { { 46, 0, 1 }, { 37, 63, 0 } } },
803
  { { { 46, 0, 0 }, { 38, 62, 0 } } },
804
  { { { 46, 0, 1 }, { 38, 63, 0 } } },
805
  { { { 46, 0, 2 }, { 47, 46, 0 } } },
806
  { { { 47, 0, 1 }, { 39, 62, 0 } } },
807
  { { { 47, 0, 0 }, { 39, 63, 0 } } },
808
  { { { 47, 0, 1 }, { 40, 62, 0 } } },
809
  { { { 47, 0, 2 }, { 48, 46, 0 } } },
810
  { { { 48, 0, 2 }, { 40, 63, 0 } } },
811
  { { { 48, 0, 1 }, { 41, 62, 0 } } },
812
  { { { 48, 0, 0 }, { 41, 63, 0 } } },
813
  { { { 48, 0, 1 }, { 48, 49, 0 } } },
814
  { { { 48, 0, 2 }, { 42, 62, 0 } } },
815
  { { { 49, 0, 1 }, { 42, 63, 0 } } },
816
  { { { 49, 0, 0 }, { 43, 62, 0 } } },
817
  { { { 49, 0, 1 }, { 48, 52, 0 } } },
818
  { { { 49, 0, 2 }, { 43, 63, 0 } } },
819
  { { { 50, 0, 1 }, { 44, 62, 0 } } },
820
  { { { 50, 0, 0 }, { 44, 63, 0 } } },
821
  { { { 50, 0, 1 }, { 48, 55, 0 } } },
822
  { { { 50, 0, 2 }, { 45, 62, 0 } } },
823
  { { { 51, 0, 1 }, { 45, 63, 0 } } },
824
  { { { 51, 0, 0 }, { 46, 62, 0 } } },
825
  { { { 51, 0, 1 }, { 48, 58, 0 } } },
826
  { { { 51, 0, 2 }, { 46, 63, 0 } } },
827
  { { { 52, 0, 1 }, { 47, 62, 0 } } },
828
  { { { 52, 0, 0 }, { 47, 63, 0 } } },
829
  { { { 52, 0, 1 }, { 48, 61, 0 } } },
830
  { { { 52, 0, 2 }, { 48, 62, 0 } } },
831
  { { { 53, 0, 1 }, { 56, 47, 0 } } },
832
  { { { 53, 0, 0 }, { 48, 63, 0 } } },
833
  { { { 53, 0, 1 }, { 49, 62, 0 } } },
834
  { { { 53, 0, 2 }, { 49, 63, 0 } } },
835
  { { { 54, 0, 1 }, { 58, 46, 0 } } },
836
  { { { 54, 0, 0 }, { 50, 62, 0 } } },
837
  { { { 54, 0, 1 }, { 50, 63, 0 } } },
838
  { { { 54, 0, 2 }, { 51, 62, 0 } } },
839
  { { { 55, 0, 1 }, { 59, 47, 0 } } },
840
  { { { 55, 0, 0 }, { 51, 63, 0 } } },
841
  { { { 55, 0, 1 }, { 52, 62, 0 } } },
842
  { { { 55, 0, 2 }, { 52, 63, 0 } } },
843
  { { { 56, 0, 1 }, { 61, 46, 0 } } },
844
  { { { 56, 0, 0 }, { 53, 62, 0 } } },
845
  { { { 56, 0, 1 }, { 53, 63, 0 } } },
846
  { { { 56, 0, 2 }, { 54, 62, 0 } } },
847
  { { { 57, 0, 1 }, { 62, 47, 0 } } },
848
  { { { 57, 0, 0 }, { 54, 63, 0 } } },
849
  { { { 57, 0, 1 }, { 55, 62, 0 } } },
850
  { { { 57, 0, 2 }, { 55, 63, 0 } } },
851
  { { { 58, 0, 1 }, { 56, 62, 1 } } },
852
  { { { 58, 0, 0 }, { 56, 62, 0 } } },
853
  { { { 58, 0, 1 }, { 56, 63, 0 } } },
854
  { { { 58, 0, 2 }, { 57, 62, 0 } } },
855
  { { { 59, 0, 1 }, { 57, 63, 1 } } },
856
  { { { 59, 0, 0 }, { 57, 63, 0 } } },
857
  { { { 59, 0, 1 }, { 58, 62, 0 } } },
858
  { { { 59, 0, 2 }, { 58, 63, 0 } } },
859
  { { { 60, 0, 1 }, { 59, 62, 1 } } },
860
  { { { 60, 0, 0 }, { 59, 62, 0 } } },
861
  { { { 60, 0, 1 }, { 59, 63, 0 } } },
862
  { { { 60, 0, 2 }, { 60, 62, 0 } } },
863
  { { { 61, 0, 1 }, { 60, 63, 1 } } },
864
  { { { 61, 0, 0 }, { 60, 63, 0 } } },
865
  { { { 61, 0, 1 }, { 61, 62, 0 } } },
866
  { { { 61, 0, 2 }, { 61, 63, 0 } } },
867
  { { { 62, 0, 1 }, { 62, 62, 1 } } },
868
  { { { 62, 0, 0 }, { 62, 62, 0 } } },
869
  { { { 62, 0, 1 }, { 62, 63, 0 } } },
870
  { { { 62, 0, 2 }, { 63, 62, 0 } } },
871
  { { { 63, 0, 1 }, { 63, 63, 1 } } },
872
  { { { 63, 0, 0 }, { 63, 63, 0 } } }
873
};
874
875
static const DDSSingleColorLookup*
876
  DDS_LOOKUP[] =
877
{
878
  DDSLookup_5_4,
879
  DDSLookup_6_4,
880
  DDSLookup_5_4
881
};
882
883
static const unsigned char BC7_weight2[] = { 0, 21, 43, 64 };
884
static const unsigned char BC7_weight3[] = { 0, 9, 18, 27, 37, 46, 55, 64 };
885
static const unsigned char BC7_weight4[] = { 0, 4, 9, 13, 17, 21, 26, 30, 34,
886
  38, 43, 47, 51, 55, 60, 64 };
887
888
/* stores info for each mode of BC7 */
889
static const BC7ModeInfo BC7_mode_info[8] =
890
{
891
  { 4, 3, 4, 0, 6, 3, 0 },   /* mode 0 */
892
  { 6, 2, 6, 0, 2, 3, 0 },   /* mode 1 */
893
  { 6, 3, 5, 0, 0, 2, 0 },   /* mode 2 */
894
  { 6, 2, 7, 0, 4, 2, 0 },   /* mode 3 */
895
  { 0, 1, 5, 6, 0, 2, 3 },   /* mode 4 */
896
  { 0, 1, 7, 8, 0, 2, 2 },   /* mode 5 */
897
  { 0, 1, 7, 7, 2, 4, 0 },   /* mode 6 */
898
  { 6, 2, 5, 5, 4, 2, 0 },   /* mode 7 */
899
};
900
901
static const unsigned char BC7_partition_table[2][64][16] =
902
{
903
  { /* BC7 Partition Set for 2 Subsets */
904
    { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
905
    { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1 },
906
    { 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
907
    { 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
908
    { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1 },
909
    { 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
910
    { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
911
    { 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1 },
912
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1 },
913
    { 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
914
    { 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
915
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1 },
916
    { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
917
    { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
918
    { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
919
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 },
920
    { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1 },
921
    { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
922
    { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0 },
923
    { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
924
    { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
925
    { 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0 },
926
    { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
927
    { 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1 },
928
    { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0 },
929
    { 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 },
930
    { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0 },
931
    { 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0 },
932
    { 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 },
933
    { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
934
    { 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0 },
935
    { 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
936
    { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1 },
937
    { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1 },
938
    { 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0 },
939
    { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0 },
940
    { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0 },
941
    { 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0 },
942
    { 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1 },
943
    { 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1 },
944
    { 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0 },
945
    { 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 },
946
    { 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0 },
947
    { 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0 },
948
    { 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 },
949
    { 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1 },
950
    { 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1 },
951
    { 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
952
    { 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
953
    { 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0 },
954
    { 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0 },
955
    { 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0 },
956
    { 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1 },
957
    { 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
958
    { 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0 },
959
    { 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0 },
960
    { 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 },
961
    { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1 },
962
    { 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1 },
963
    { 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1 },
964
    { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1 },
965
    { 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 },
966
    { 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0 },
967
    { 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1 } 
968
  },
969
970
  {  /* BC7 Partition Set for 3 Subsets */
971
    { 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 1, 2, 2, 2, 2 },
972
    { 0, 0, 0, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 2, 1 },
973
    { 0, 0, 0, 0, 2, 0, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1 },
974
    { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 1, 0, 1, 1, 1 },
975
    { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2 },
976
    { 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 2, 2 },
977
    { 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1 },
978
    { 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1 },
979
    { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2 },
980
    { 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2 },
981
    { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2 },
982
    { 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2 },
983
    { 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2, 0, 1, 1, 2 },
984
    { 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2, 0, 1, 2, 2 },
985
    { 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2, 1, 2, 2, 2 },
986
    { 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0, 2, 2, 2, 0 },
987
    { 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 2, 1, 1, 2, 2 },
988
    { 0, 1, 1, 1, 0, 0, 1, 1, 2, 0, 0, 1, 2, 2, 0, 0 },
989
    { 0, 0, 0, 0, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2 },
990
    { 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1 },
991
    { 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2, 0, 2, 2, 2 },
992
    { 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 1, 2, 2, 2, 1 },
993
    { 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2 },
994
    { 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 1, 0, 2, 2, 1, 0 },
995
    { 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1, 0, 0, 0, 0 },
996
    { 0, 0, 1, 2, 0, 0, 1, 2, 1, 1, 2, 2, 2, 2, 2, 2 },
997
    { 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1, 0, 1, 1, 0 },
998
    { 0, 0, 0, 0, 0, 1, 1, 0, 1, 2, 2, 1, 1, 2, 2, 1 },
999
    { 0, 0, 2, 2, 1, 1, 0, 2, 1, 1, 0, 2, 0, 0, 2, 2 },
1000
    { 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 0, 2, 2, 2, 2, 2 },
1001
    { 0, 0, 1, 1, 0, 1, 2, 2, 0, 1, 2, 2, 0, 0, 1, 1 },
1002
    { 0, 0, 0, 0, 2, 0, 0, 0, 2, 2, 1, 1, 2, 2, 2, 1 },
1003
    { 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 2, 2, 2 },
1004
    { 0, 2, 2, 2, 0, 0, 2, 2, 0, 0, 1, 2, 0, 0, 1, 1 },
1005
    { 0, 0, 1, 1, 0, 0, 1, 2, 0, 0, 2, 2, 0, 2, 2, 2 },
1006
    { 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2, 0 },
1007
    { 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0 },
1008
    { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 },
1009
    { 0, 1, 2, 0, 2, 0, 1, 2, 1, 2, 0, 1, 0, 1, 2, 0 },
1010
    { 0, 0, 1, 1, 2, 2, 0, 0, 1, 1, 2, 2, 0, 0, 1, 1 },
1011
    { 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 0, 0, 1, 1 },
1012
    { 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2 },
1013
    { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1 },
1014
    { 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 2, 2 },
1015
    { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1 },
1016
    { 0, 2, 2, 0, 1, 2, 2, 1, 0, 2, 2, 0, 1, 2, 2, 1 },
1017
    { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 0, 1 },
1018
    { 0, 0, 0, 0, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1 },
1019
    { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 2, 2, 2 },
1020
    { 0, 2, 2, 2, 0, 1, 1, 1, 0, 2, 2, 2, 0, 1, 1, 1 },
1021
    { 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 2, 1, 1, 1, 2 },
1022
    { 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2 },
1023
    { 0, 2, 2, 2, 0, 1, 1, 1, 0, 1, 1, 1, 0, 2, 2, 2 },
1024
    { 0, 0, 0, 2, 1, 1, 1, 2, 1, 1, 1, 2, 0, 0, 0, 2 },
1025
    { 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2 },
1026
    { 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2, 2, 1, 1, 2 },
1027
    { 0, 1, 1, 0, 0, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 2 },
1028
    { 0, 0, 2, 2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 2, 2 },
1029
    { 0, 0, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 0, 0, 2, 2 },
1030
    { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 1, 2 },
1031
    { 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1 },
1032
    { 0, 2, 2, 2, 1, 2, 2, 2, 0, 2, 2, 2, 1, 2, 2, 2 },
1033
    { 0, 1, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
1034
    { 0, 1, 1, 1, 2, 0, 1, 1, 2, 2, 0, 1, 2, 2, 2, 0 }
1035
  }
1036
};
1037
1038
static const unsigned char BC7_anchor_index_table[4][64] =
1039
{
1040
  /* Anchor index values for the first subset */
1041
  {
1042
    0, 0, 0, 0, 0, 0, 0, 0,
1043
    0, 0, 0, 0, 0, 0, 0, 0,
1044
    0, 0, 0, 0, 0, 0, 0, 0,
1045
    0, 0, 0, 0, 0, 0, 0, 0,
1046
    0, 0, 0, 0, 0, 0, 0, 0,
1047
    0, 0, 0, 0, 0, 0, 0, 0,
1048
    0, 0, 0, 0, 0, 0, 0, 0,
1049
    0, 0, 0, 0, 0, 0, 0, 0
1050
  },
1051
  /* Anchor index values for the second subset of two-subset partitioning */
1052
  {
1053
    15,15,15,15,15,15,15,15,
1054
    15,15,15,15,15,15,15,15,
1055
    15, 2, 8, 2, 2, 8, 8,15,
1056
    2, 8, 2, 2, 8, 8, 2, 2,
1057
    15,15, 6, 8, 2, 8,15,15,
1058
    2, 8, 2, 2, 2,15,15, 6,
1059
    6, 2, 6, 8,15,15, 2, 2,
1060
    15,15,15,15,15, 2, 2,15
1061
  },
1062
  /* Anchor index values for the second subset of three-subset partitioning */
1063
  {
1064
    3, 3,15,15, 8, 3,15,15,
1065
    8, 8, 6, 6, 6, 5, 3, 3,
1066
    3, 3, 8,15, 3, 3, 6,10,
1067
    5, 8, 8, 6, 8, 5,15,15,
1068
    8,15, 3, 5, 6,10, 8,15,
1069
    15, 3,15, 5,15,15,15,15,
1070
    3,15, 5, 5, 5, 8, 5,10,
1071
    5,10, 8,13,15,12, 3, 3
1072
  },
1073
  /* Anchor index values for the third subset of three-subset partitioning */
1074
  {
1075
    15, 8, 8, 3,15,15, 3, 8,
1076
    15,15,15,15,15,15,15, 8,
1077
    15, 8,15, 3,15, 8,15, 8,
1078
    3,15, 6,10,15,15,10, 8,
1079
    15, 3,15,10,10, 8, 9,10,
1080
    6,15, 8,15, 3, 6, 6, 8,
1081
    15, 3,15,15,15,15,15,15,
1082
    15,15,15,15, 3,15,15, 8
1083
  }
1084
};
1085
1086
/*
1087
  Macros
1088
*/
1089
285k
#define C565_r(x) (((x) & 0xF800) >> 11)
1090
285k
#define C565_g(x) (((x) & 0x07E0) >> 5)
1091
285k
#define C565_b(x)  ((x) & 0x001F)
1092
1093
142k
#define C565_red(x)   ( (C565_r(x) << 3 | C565_r(x) >> 2))
1094
142k
#define C565_green(x) ( (C565_g(x) << 2 | C565_g(x) >> 4))
1095
142k
#define C565_blue(x)  ( (C565_b(x) << 3 | C565_b(x) >> 2))
1096
1097
36.8k
#define DIV2(x)  ((x) > 1 ? ((x) >> 1) : 1)
1098
1099
118k
#define FixRange(min, max, steps) \
1100
118k
if (min > max) \
1101
118k
  min = max; \
1102
118k
if ((max-min) < steps) \
1103
118k
  max = MagickMin(min+(ssize_t) steps, 255); \
1104
118k
if ((max- min) < steps) \
1105
118k
  min = (size_t) MagickMax(0L, (ssize_t) max-(ssize_t) steps)
1106
1107
1.27M
#define Dot(left, right) (left.x*right.x) + (left.y*right.y) + (left.z*right.z)
1108
1109
143k
#define VectorInit(vector, value) vector.x = vector.y = vector.z = vector.w \
1110
143k
  = value
1111
286k
#define VectorInit3(vector, value) vector.x = vector.y = vector.z = value
1112
1113
7.37k
#define IsBitMask(mask, r, g, b, a) (mask.r_bitmask == r && mask.g_bitmask == \
1114
2.09k
  g && mask.b_bitmask == b && mask.alpha_bitmask == a)
1115
1116
/*
1117
  Forward declarations
1118
*/
1119
static MagickBooleanType
1120
  WriteDDSImage(const ImageInfo *,Image *,ExceptionInfo *);
1121
1122
static inline void VectorAdd(const DDSVector4 left, const DDSVector4 right,
1123
  DDSVector4 *destination)
1124
0
{
1125
0
  destination->x = left.x + right.x;
1126
0
  destination->y = left.y + right.y;
1127
0
  destination->z = left.z + right.z;
1128
0
  destination->w = left.w + right.w;
1129
0
}
1130
1131
static inline void VectorClamp(DDSVector4 *value)
1132
0
{
1133
0
  value->x = MagickMin(1.0f,MagickMax(0.0f,value->x));
1134
0
  value->y = MagickMin(1.0f,MagickMax(0.0f,value->y));
1135
0
  value->z = MagickMin(1.0f,MagickMax(0.0f,value->z));
1136
0
  value->w = MagickMin(1.0f,MagickMax(0.0f,value->w));
1137
0
}
1138
1139
static inline void VectorClamp3(DDSVector3 *value)
1140
143k
{
1141
143k
  value->x = MagickMin(1.0f,MagickMax(0.0f,value->x));
1142
143k
  value->y = MagickMin(1.0f,MagickMax(0.0f,value->y));
1143
143k
  value->z = MagickMin(1.0f,MagickMax(0.0f,value->z));
1144
143k
}
1145
1146
static inline void VectorCopy43(const DDSVector4 source,
1147
  DDSVector3 *destination)
1148
346k
{
1149
346k
  destination->x = source.x;
1150
346k
  destination->y = source.y;
1151
346k
  destination->z = source.z;
1152
346k
}
1153
1154
static inline void VectorCopy44(const DDSVector4 source,
1155
  DDSVector4 *destination)
1156
0
{
1157
0
  destination->x = source.x;
1158
0
  destination->y = source.y;
1159
0
  destination->z = source.z;
1160
0
  destination->w = source.w;
1161
0
}
1162
1163
static inline void VectorNegativeMultiplySubtract(const DDSVector4 a,
1164
  const DDSVector4 b, const DDSVector4 c, DDSVector4 *destination)
1165
0
{
1166
0
  destination->x = c.x - (a.x * b.x);
1167
0
  destination->y = c.y - (a.y * b.y);
1168
0
  destination->z = c.z - (a.z * b.z);
1169
0
  destination->w = c.w - (a.w * b.w);
1170
0
}
1171
1172
static inline void VectorMultiply(const DDSVector4 left,
1173
  const DDSVector4 right, DDSVector4 *destination)
1174
0
{
1175
0
  destination->x = left.x * right.x;
1176
0
  destination->y = left.y * right.y;
1177
0
  destination->z = left.z * right.z;
1178
0
  destination->w = left.w * right.w;
1179
0
}
1180
1181
static inline void VectorMultiply3(const DDSVector3 left,
1182
  const DDSVector3 right, DDSVector3 *destination)
1183
143k
{
1184
143k
  destination->x = left.x * right.x;
1185
143k
  destination->y = left.y * right.y;
1186
143k
  destination->z = left.z * right.z;
1187
143k
}
1188
1189
static inline void VectorMultiplyAdd(const DDSVector4 a, const DDSVector4 b,
1190
  const DDSVector4 c, DDSVector4 *destination)
1191
0
{
1192
0
  destination->x = (a.x * b.x) + c.x;
1193
0
  destination->y = (a.y * b.y) + c.y;
1194
0
  destination->z = (a.z * b.z) + c.z;
1195
0
  destination->w = (a.w * b.w) + c.w;
1196
0
}
1197
1198
static inline void VectorMultiplyAdd3(const DDSVector3 a, const DDSVector3 b,
1199
  const DDSVector3 c, DDSVector3 *destination)
1200
143k
{
1201
143k
  destination->x = (a.x * b.x) + c.x;
1202
143k
  destination->y = (a.y * b.y) + c.y;
1203
143k
  destination->z = (a.z * b.z) + c.z;
1204
143k
}
1205
1206
static inline void VectorReciprocal(const DDSVector4 value,
1207
  DDSVector4 *destination)
1208
0
{
1209
0
  destination->x = 1.0f / value.x;
1210
0
  destination->y = 1.0f / value.y;
1211
0
  destination->z = 1.0f / value.z;
1212
0
  destination->w = 1.0f / value.w;
1213
0
}
1214
1215
static inline void VectorSubtract(const DDSVector4 left,
1216
  const DDSVector4 right, DDSVector4 *destination)
1217
0
{
1218
0
  destination->x = left.x - right.x;
1219
0
  destination->y = left.y - right.y;
1220
0
  destination->z = left.z - right.z;
1221
0
  destination->w = left.w - right.w;
1222
0
}
1223
1224
static inline void VectorSubtract3(const DDSVector3 left,
1225
  const DDSVector3 right, DDSVector3 *destination)
1226
0
{
1227
0
  destination->x = left.x - right.x;
1228
0
  destination->y = left.y - right.y;
1229
0
  destination->z = left.z - right.z;
1230
0
}
1231
1232
static inline void VectorTruncate(DDSVector4 *value)
1233
0
{
1234
0
  value->x = value->x > 0.0f ? floorf(value->x) : ceilf(value->x);
1235
0
  value->y = value->y > 0.0f ? floorf(value->y) : ceilf(value->y);
1236
0
  value->z = value->z > 0.0f ? floorf(value->z) : ceilf(value->z);
1237
0
  value->w = value->w > 0.0f ? floorf(value->w) : ceilf(value->w);
1238
0
}
1239
1240
static inline void VectorTruncate3(DDSVector3 *value)
1241
143k
{
1242
143k
  value->x = value->x > 0.0f ? floorf(value->x) : ceilf(value->x);
1243
143k
  value->y = value->y > 0.0f ? floorf(value->y) : ceilf(value->y);
1244
143k
  value->z = value->z > 0.0f ? floorf(value->z) : ceilf(value->z);
1245
143k
}
1246
1247
static inline size_t ClampToLimit(const float value, const size_t limit)
1248
985k
{
1249
985k
  size_t
1250
985k
    result = (size_t) (value + 0.5f);
1251
1252
985k
  if (result < 0.0f)
1253
0
    return(0);
1254
985k
  if (result > limit)
1255
0
    return(limit);
1256
985k
  return result;
1257
985k
}
1258
1259
static inline size_t ColorTo565(const DDSVector3 point)
1260
266k
{
1261
266k
  size_t r = ClampToLimit(31.0f*point.x,31);
1262
266k
  size_t g = ClampToLimit(63.0f*point.y,63);
1263
266k
  size_t b = ClampToLimit(31.0f*point.z,31);
1264
1265
266k
  return (r << 11) | (g << 5) | b;
1266
266k
}
1267
1268
static inline unsigned char GetSubsetIndex(unsigned char numSubsets,
1269
  unsigned char partition_id,size_t pixelIndex)
1270
264k
{
1271
264k
  if (numSubsets == 2)
1272
60.9k
    return BC7_partition_table[0][partition_id][pixelIndex];
1273
203k
  if (numSubsets == 3)
1274
75.9k
    return BC7_partition_table[1][partition_id][pixelIndex];
1275
127k
  return 0;
1276
203k
}
1277
1278
/*
1279
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1280
%                                                                             %
1281
%                                                                             %
1282
%                                                                             %
1283
%   I s D D S                                                                 %
1284
%                                                                             %
1285
%                                                                             %
1286
%                                                                             %
1287
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1288
%
1289
%  IsDDS() returns MagickTrue if the image format type, identified by the
1290
%  magick string, is DDS.
1291
%
1292
%  The format of the IsDDS method is:
1293
%
1294
%      MagickBooleanType IsDDS(const unsigned char *magick,const size_t length)
1295
%
1296
%  A description of each parameter follows:
1297
%
1298
%    o magick: compare image format pattern against these bytes.
1299
%
1300
%    o length: Specifies the length of the magick string.
1301
%
1302
*/
1303
static MagickBooleanType IsDDS(const unsigned char *magick, const size_t length)
1304
0
{
1305
0
  if (length < 4)
1306
0
    return(MagickFalse);
1307
0
  if (LocaleNCompare((char *) magick,"DDS ", 4) == 0)
1308
0
    return(MagickTrue);
1309
0
  return(MagickFalse);
1310
0
}
1311
1312
static MagickBooleanType ReadDDSInfo(Image *image, DDSInfo *dds_info)
1313
9.18k
{
1314
9.18k
  size_t
1315
9.18k
    hdr_size,
1316
9.18k
    required;
1317
1318
  /* Seek to start of header */
1319
9.18k
  (void) SeekBlob(image, 4, SEEK_SET);
1320
1321
  /* Check header field */
1322
9.18k
  hdr_size = ReadBlobLSBLong(image);
1323
9.18k
  if (hdr_size != 124)
1324
144
    return MagickFalse;
1325
1326
  /* Fill in DDS info struct */
1327
9.04k
  dds_info->flags = ReadBlobLSBLong(image);
1328
1329
  /* Check required flags */
1330
9.04k
  required=(size_t) (DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT);
1331
9.04k
  if ((dds_info->flags & required) != required)
1332
16
    return MagickFalse;
1333
1334
9.02k
  dds_info->height = ReadBlobLSBLong(image);
1335
9.02k
  dds_info->width = ReadBlobLSBLong(image);
1336
9.02k
  dds_info->pitchOrLinearSize = ReadBlobLSBLong(image);
1337
9.02k
  dds_info->depth = ReadBlobLSBLong(image);
1338
9.02k
  dds_info->mipmapcount = ReadBlobLSBLong(image);
1339
  
1340
9.02k
  (void) SeekBlob(image, 44, SEEK_CUR);   /* reserved region of 11 DWORDs */
1341
1342
  /* Read pixel format structure */
1343
9.02k
  hdr_size = ReadBlobLSBLong(image);
1344
9.02k
  if (hdr_size != 32)
1345
168
    return MagickFalse;
1346
1347
8.86k
  dds_info->pixelformat.flags = ReadBlobLSBLong(image);
1348
8.86k
  dds_info->pixelformat.fourcc = ReadBlobLSBLong(image);
1349
8.86k
  dds_info->pixelformat.rgb_bitcount = ReadBlobLSBLong(image);
1350
8.86k
  dds_info->pixelformat.r_bitmask = ReadBlobLSBLong(image);
1351
8.86k
  dds_info->pixelformat.g_bitmask = ReadBlobLSBLong(image);
1352
8.86k
  dds_info->pixelformat.b_bitmask = ReadBlobLSBLong(image);
1353
8.86k
  dds_info->pixelformat.alpha_bitmask = ReadBlobLSBLong(image);
1354
1355
8.86k
  dds_info->ddscaps1 = ReadBlobLSBLong(image);
1356
8.86k
  dds_info->ddscaps2 = ReadBlobLSBLong(image);
1357
8.86k
  (void) SeekBlob(image, 12, SEEK_CUR); /* 3 reserved DWORDs */
1358
1359
  /* Read optional DX10 header if available */
1360
8.86k
  if ((dds_info->pixelformat.flags & DDPF_FOURCC) &&
1361
6.99k
      (dds_info->pixelformat.fourcc == FOURCC_DX10))
1362
1.19k
    {
1363
1.19k
      dds_info->extFormat = ReadBlobLSBLong(image);
1364
1.19k
      dds_info->extDimension = ReadBlobLSBLong(image);
1365
1.19k
      dds_info->extFlags = ReadBlobLSBLong(image);
1366
1.19k
      dds_info->extArraySize = ReadBlobLSBLong(image);
1367
1.19k
      dds_info->extFlags2 = ReadBlobLSBLong(image);
1368
1.19k
    }
1369
7.66k
  else
1370
7.66k
    {
1371
7.66k
      dds_info->extFormat = 0;
1372
7.66k
      dds_info->extDimension = 0;
1373
7.66k
      dds_info->extFlags = 0;
1374
7.66k
      dds_info->extArraySize = 0;
1375
7.66k
      dds_info->extFlags2 = 0;
1376
7.66k
    }
1377
1378
8.86k
  return(MagickTrue);
1379
9.02k
}
1380
1381
static MagickBooleanType SetDXT1Pixels(Image *image,ssize_t x,ssize_t y,
1382
  DDSColors colors,size_t bits,Quantum *q)
1383
62.2k
{
1384
62.2k
  ssize_t
1385
62.2k
    i;
1386
1387
62.2k
  ssize_t
1388
62.2k
    j;
1389
1390
62.2k
  unsigned char
1391
62.2k
    code;
1392
1393
302k
  for (j = 0; j < 4; j++)
1394
242k
  {
1395
1.20M
    for (i = 0; i < 4; i++)
1396
965k
    {
1397
965k
      if ((x + i) < (ssize_t) image->columns &&
1398
880k
          (y + j) < (ssize_t) image->rows)
1399
778k
        {
1400
778k
          code=(unsigned char) ((bits >> ((j*4+i)*2)) & 0x3);
1401
778k
          SetPixelRed(image,ScaleCharToQuantum(colors.r[code]),q);
1402
778k
          SetPixelGreen(image,ScaleCharToQuantum(colors.g[code]),q);
1403
778k
          SetPixelBlue(image,ScaleCharToQuantum(colors.b[code]),q);
1404
778k
          SetPixelOpacity(image,ScaleCharToQuantum(colors.a[code]),q);
1405
778k
          if ((colors.a[code] != 0) &&
1406
166k
              ((image->alpha_trait & BlendPixelTrait) == 0))
1407
2.63k
            return(MagickFalse);
1408
776k
          q+=(ptrdiff_t) GetPixelChannels(image);
1409
776k
        }
1410
965k
    }
1411
242k
  }
1412
59.6k
  return(MagickTrue);
1413
62.2k
}
1414
1415
static MagickBooleanType ReadMipmaps(const ImageInfo *image_info,Image *image,
1416
  const DDSInfo *dds_info,DDSPixelDecoder decoder,ExceptionInfo *exception)
1417
0
{
1418
0
  MagickBooleanType
1419
0
    status;
1420
1421
  /*
1422
    Only read mipmaps for textures and cube maps
1423
  */
1424
0
  if (EOFBlob(image) != MagickFalse)
1425
0
    {
1426
0
      ThrowFileException(exception,CorruptImageWarning,"UnexpectedEndOfFile",
1427
0
        image->filename);
1428
0
      return(MagickFalse);
1429
0
    }
1430
0
  status=MagickTrue;
1431
0
  if (dds_info->ddscaps1 & DDSCAPS_MIPMAP
1432
0
      && (dds_info->ddscaps1 & DDSCAPS_TEXTURE
1433
0
          || dds_info->ddscaps2 & DDSCAPS2_CUBEMAP))
1434
0
    {
1435
0
      ssize_t
1436
0
        i;
1437
1438
0
      size_t
1439
0
        h,
1440
0
        w;
1441
1442
0
      w=DIV2(dds_info->width);
1443
0
      h=DIV2(dds_info->height);
1444
1445
      /*
1446
        Mipmapcount includes the main image, so start from one
1447
      */
1448
0
      for (i = 1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)
1449
0
      {
1450
0
        AcquireNextImage(image_info,image,exception);
1451
0
        if (image->next == (Image *) NULL)
1452
0
          return(MagickFalse);
1453
0
        image->next->alpha_trait=image->alpha_trait;
1454
0
        image=SyncNextImageInList(image);
1455
0
        status=SetImageExtent(image,w,h,exception);
1456
0
        if (status == MagickFalse)
1457
0
          break;
1458
0
        status=decoder(image,dds_info,exception);
1459
0
        if (status == MagickFalse)
1460
0
          break;
1461
0
        if ((w == 1) && (h == 1))
1462
0
          break;
1463
1464
0
        w=DIV2(w);
1465
0
        h=DIV2(h);
1466
0
      }
1467
0
    }
1468
0
  return(status);
1469
0
}
1470
1471
static void CalculateColors(unsigned short c0, unsigned short c1,
1472
  DDSColors *c, MagickBooleanType ignoreAlpha)
1473
71.3k
{
1474
71.3k
  c->a[0] = c->a[1] = c->a[2] = c->a[3] = 0;
1475
1476
71.3k
  c->r[0] = (unsigned char) C565_red(c0);
1477
71.3k
  c->g[0] = (unsigned char) C565_green(c0);
1478
71.3k
  c->b[0] = (unsigned char) C565_blue(c0);
1479
1480
71.3k
  c->r[1] = (unsigned char) C565_red(c1);
1481
71.3k
  c->g[1] = (unsigned char) C565_green(c1);
1482
71.3k
  c->b[1] = (unsigned char) C565_blue(c1);
1483
1484
71.3k
  if (ignoreAlpha != MagickFalse || c0 > c1)
1485
27.2k
    {
1486
27.2k
      c->r[2] = (unsigned char) ((2 * c->r[0] + c->r[1]) / 3);
1487
27.2k
      c->g[2] = (unsigned char) ((2 * c->g[0] + c->g[1]) / 3);
1488
27.2k
      c->b[2] = (unsigned char) ((2 * c->b[0] + c->b[1]) / 3);
1489
1490
27.2k
      c->r[3] = (unsigned char) ((c->r[0] + 2 * c->r[1]) / 3);
1491
27.2k
      c->g[3] = (unsigned char) ((c->g[0] + 2 * c->g[1]) / 3);
1492
27.2k
      c->b[3] = (unsigned char) ((c->b[0] + 2 * c->b[1]) / 3);
1493
27.2k
    }
1494
44.0k
  else
1495
44.0k
    {
1496
44.0k
      c->r[2] = (unsigned char) ((c->r[0] + c->r[1]) / 2);
1497
44.0k
      c->g[2] = (unsigned char) ((c->g[0] + c->g[1]) / 2);
1498
44.0k
      c->b[2] = (unsigned char) ((c->b[0] + c->b[1]) / 2);
1499
1500
44.0k
      c->r[3] = c->g[3] = c->b[3] = 0;
1501
44.0k
      c->a[3] = 255;
1502
44.0k
    }
1503
71.3k
}
1504
1505
static MagickBooleanType ReadDXT1Pixels(Image *image,
1506
  const DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
1507
3.83k
{
1508
3.83k
  DDSColors
1509
3.83k
    colors;
1510
1511
3.83k
  Quantum
1512
3.83k
    *q;
1513
1514
3.83k
  ssize_t
1515
3.83k
    x;
1516
1517
3.83k
  size_t
1518
3.83k
    bits;
1519
1520
3.83k
  ssize_t
1521
3.83k
    y;
1522
1523
3.83k
  unsigned short
1524
3.83k
    c0,
1525
3.83k
    c1;
1526
1527
3.83k
  magick_unreferenced(dds_info);
1528
22.5k
  for (y = 0; y < (ssize_t) image->rows; y += 4)
1529
19.6k
  {
1530
79.3k
    for (x = 0; x < (ssize_t) image->columns; x += 4)
1531
60.6k
    {
1532
      /* Get 4x4 patch of pixels to write on */
1533
60.6k
      q=QueueAuthenticPixels(image,x,y,(size_t)
1534
60.6k
        (MagickMin(4,(ssize_t) image->columns-x)),(size_t)
1535
60.6k
        (MagickMin(4,(ssize_t) image->rows-y)),exception);
1536
1537
60.6k
      if (q == (Quantum *) NULL)
1538
0
        return(MagickFalse);
1539
1540
      /* Read 8 bytes of data from the image */
1541
60.6k
      c0=ReadBlobLSBShort(image);
1542
60.6k
      c1=ReadBlobLSBShort(image);
1543
60.6k
      bits=ReadBlobLSBLong(image);
1544
1545
60.6k
      CalculateColors(c0,c1,&colors,MagickFalse);
1546
60.6k
      if (EOFBlob(image) != MagickFalse)
1547
991
        return(MagickFalse);
1548
1549
      /* Write the pixels */
1550
59.6k
      if (SetDXT1Pixels(image,x,y,colors,bits,q) == MagickFalse)
1551
2.63k
        {
1552
          /* Correct alpha */
1553
2.63k
          SetImageAlpha(image,QuantumRange,exception);
1554
2.63k
          q=QueueAuthenticPixels(image,x,y,(size_t) MagickMin(4,(ssize_t)
1555
2.63k
            image->columns-x),(size_t) MagickMin(4,(ssize_t) image->rows-y),
1556
2.63k
            exception);
1557
2.63k
          if (q != (Quantum *) NULL)
1558
2.63k
            SetDXT1Pixels(image,x,y,colors,bits,q);
1559
2.63k
        }
1560
59.6k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
1561
0
        return(MagickFalse);
1562
59.6k
    }
1563
18.6k
    if (EOFBlob(image) != MagickFalse)
1564
0
      return(MagickFalse);
1565
18.6k
  }
1566
2.84k
  return(MagickTrue);
1567
3.83k
}
1568
1569
/*
1570
  Skip the mipmap images for compressed (DXTn) dds files
1571
*/
1572
static MagickBooleanType SkipMipmaps(Image *image,const DDSInfo *dds_info,
1573
  int texel_size,ExceptionInfo *exception)
1574
3.75k
{
1575
  /*
1576
    Only skip mipmaps for textures and cube maps
1577
  */
1578
3.75k
  if (EOFBlob(image) != MagickFalse)
1579
0
    {
1580
0
      ThrowFileException(exception,CorruptImageWarning,"UnexpectedEndOfFile",
1581
0
        image->filename);
1582
0
      return(MagickFalse);
1583
0
    }
1584
3.75k
  if (dds_info->ddscaps1 & DDSCAPS_MIPMAP
1585
2.06k
      && (dds_info->ddscaps1 & DDSCAPS_TEXTURE
1586
1.03k
          || dds_info->ddscaps2 & DDSCAPS2_CUBEMAP))
1587
1.49k
    {
1588
1.49k
      MagickOffsetType
1589
1.49k
        offset;
1590
1591
1.49k
      size_t
1592
1.49k
        h,
1593
1.49k
        w;
1594
1595
1.49k
      ssize_t
1596
1.49k
        i;
1597
1598
1.49k
      w=DIV2(dds_info->width);
1599
1.49k
      h=DIV2(dds_info->height);
1600
1601
      /*
1602
        Mipmapcount includes the main image, so start from one
1603
      */
1604
3.40k
      for (i = 1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)
1605
2.44k
      {
1606
2.44k
        offset=(MagickOffsetType) (((w+3U)/4U)*((h+3U)/4U)*(size_t)
1607
2.44k
          texel_size);
1608
2.44k
        if (SeekBlob(image,offset,SEEK_CUR) < 0)
1609
0
          break;
1610
2.44k
        if ((w == 1) && (h == 1))
1611
536
          break;
1612
1.91k
        w=DIV2(w);
1613
1.91k
        h=DIV2(h);
1614
1.91k
      }
1615
1.49k
    }
1616
3.75k
  return(MagickTrue);
1617
3.75k
}
1618
1619
static MagickBooleanType ReadDXT1(const ImageInfo *image_info,Image *image,
1620
  const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1621
  ExceptionInfo *exception)
1622
3.83k
{
1623
3.83k
  if (ReadDXT1Pixels(image,dds_info,exception) == MagickFalse)
1624
991
    return(MagickFalse);
1625
1626
2.84k
  if (read_mipmaps != MagickFalse)
1627
0
    return(ReadMipmaps(image_info,image,dds_info,ReadDXT1Pixels,exception));
1628
2.84k
  else
1629
2.84k
    return(SkipMipmaps(image,dds_info,8,exception));
1630
2.84k
}
1631
1632
static MagickBooleanType ReadDXT3Pixels(Image *image,
1633
  const DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
1634
369
{
1635
369
  DDSColors
1636
369
    colors;
1637
1638
369
  Quantum
1639
369
    *q;
1640
1641
369
  ssize_t
1642
369
    i,
1643
369
    x;
1644
1645
369
  unsigned char
1646
369
    alpha;
1647
1648
369
  size_t
1649
369
    a0,
1650
369
    a1,
1651
369
    bits,
1652
369
    code;
1653
1654
369
  ssize_t
1655
369
    j,
1656
369
    y;
1657
1658
369
  unsigned short
1659
369
    c0,
1660
369
    c1;
1661
1662
369
  magick_unreferenced(dds_info);
1663
2.12k
  for (y = 0; y < (ssize_t) image->rows; y += 4)
1664
1.94k
  {
1665
6.86k
    for (x = 0; x < (ssize_t) image->columns; x += 4)
1666
5.10k
    {
1667
      /* Get 4x4 patch of pixels to write on */
1668
5.10k
      q = QueueAuthenticPixels(image, x, y, (size_t)
1669
5.10k
        MagickMin(4, (ssize_t) image->columns - x),(size_t)
1670
5.10k
        MagickMin(4, (ssize_t) image->rows - y),exception);
1671
1672
5.10k
      if (q == (Quantum *) NULL)
1673
0
        return(MagickFalse);
1674
1675
      /* Read alpha values (8 bytes) */
1676
5.10k
      a0 = ReadBlobLSBLong(image);
1677
5.10k
      a1 = ReadBlobLSBLong(image);
1678
1679
      /* Read 8 bytes of data from the image */
1680
5.10k
      c0 = ReadBlobLSBShort(image);
1681
5.10k
      c1 = ReadBlobLSBShort(image);
1682
5.10k
      bits = ReadBlobLSBLong(image);
1683
1684
5.10k
      CalculateColors(c0, c1, &colors, MagickTrue);
1685
1686
5.10k
      if (EOFBlob(image) != MagickFalse)
1687
187
        return(MagickFalse);
1688
1689
      /* Write the pixels */
1690
24.5k
      for (j = 0; j < 4; j++)
1691
19.6k
      {
1692
98.3k
        for (i = 0; i < 4; i++)
1693
78.6k
        {
1694
78.6k
          if ((x + i) < (ssize_t) image->columns && (y + j) < (ssize_t) image->rows)
1695
55.9k
            {
1696
55.9k
              code = (bits >> ((4*j+i)*2)) & 0x3;
1697
55.9k
              SetPixelRed(image,ScaleCharToQuantum(colors.r[code]),q);
1698
55.9k
              SetPixelGreen(image,ScaleCharToQuantum(colors.g[code]),q);
1699
55.9k
              SetPixelBlue(image,ScaleCharToQuantum(colors.b[code]),q);
1700
              /*
1701
                Extract alpha value: multiply 0..15 by 17 to get range 0..255
1702
              */
1703
55.9k
              if (j < 2)
1704
30.3k
                alpha = 17U * (unsigned char) ((a0 >> (4*(4*j+i))) & 0xf);
1705
25.5k
              else
1706
25.5k
                alpha = 17U * (unsigned char) ((a1 >> (4*(4*(j-2)+i))) & 0xf);
1707
55.9k
              SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) alpha),q);
1708
55.9k
              q+=(ptrdiff_t) GetPixelChannels(image);
1709
55.9k
            }
1710
78.6k
        }
1711
19.6k
      }
1712
4.91k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
1713
0
        return(MagickFalse);
1714
4.91k
    }
1715
1.75k
    if (EOFBlob(image) != MagickFalse)
1716
0
      return(MagickFalse);
1717
1.75k
  }
1718
182
  return(MagickTrue);
1719
369
}
1720
1721
static MagickBooleanType ReadDXT3(const ImageInfo *image_info,Image *image,
1722
  const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1723
  ExceptionInfo *exception)
1724
369
{
1725
369
  if (ReadDXT3Pixels(image,dds_info,exception) == MagickFalse)
1726
187
    return(MagickFalse);
1727
1728
182
  if (read_mipmaps != MagickFalse)
1729
0
    return(ReadMipmaps(image_info,image,dds_info,ReadDXT3Pixels,exception));
1730
182
  else
1731
182
    return(SkipMipmaps(image,dds_info,16,exception));
1732
182
}
1733
1734
static MagickBooleanType ReadDXT5Pixels(Image *image,
1735
  const DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
1736
507
{
1737
507
  DDSColors
1738
507
    colors;
1739
1740
507
  MagickSizeType
1741
507
    alpha_bits;
1742
1743
507
  Quantum
1744
507
    *q;
1745
1746
507
  ssize_t
1747
507
    i,
1748
507
    x;
1749
1750
507
  unsigned char
1751
507
    a0,
1752
507
    a1;
1753
1754
507
  size_t
1755
507
    alpha,
1756
507
    bits,
1757
507
    code,
1758
507
    alpha_code;
1759
1760
507
  ssize_t
1761
507
    j,
1762
507
    y;
1763
1764
507
  unsigned short
1765
507
    c0,
1766
507
    c1;
1767
1768
507
  magick_unreferenced(dds_info);
1769
2.95k
  for (y = 0; y < (ssize_t) image->rows; y += 4)
1770
2.69k
  {
1771
8.04k
    for (x = 0; x < (ssize_t) image->columns; x += 4)
1772
5.59k
    {
1773
      /* Get 4x4 patch of pixels to write on */
1774
5.59k
      q = QueueAuthenticPixels(image, x, y, (size_t) MagickMin(4, (ssize_t) image->columns - x),(size_t)
1775
5.59k
       MagickMin(4, (ssize_t) image->rows - y),exception);
1776
1777
5.59k
      if (q == (Quantum *) NULL)
1778
0
        return(MagickFalse);
1779
1780
      /* Read alpha values (8 bytes) */
1781
5.59k
      a0 = (unsigned char) ReadBlobByte(image);
1782
5.59k
      a1 = (unsigned char) ReadBlobByte(image);
1783
1784
5.59k
      alpha_bits = (MagickSizeType)ReadBlobLSBLong(image);
1785
5.59k
      alpha_bits = alpha_bits | ((MagickSizeType)ReadBlobLSBShort(image) << 32);
1786
1787
      /* Read 8 bytes of data from the image */
1788
5.59k
      c0 = ReadBlobLSBShort(image);
1789
5.59k
      c1 = ReadBlobLSBShort(image);
1790
5.59k
      bits = ReadBlobLSBLong(image);
1791
1792
5.59k
      CalculateColors(c0, c1, &colors, MagickTrue);
1793
5.59k
      if (EOFBlob(image) != MagickFalse)
1794
254
        return(MagickFalse);
1795
1796
      /* Write the pixels */
1797
26.7k
      for (j = 0; j < 4; j++)
1798
21.3k
      {
1799
106k
        for (i = 0; i < 4; i++)
1800
85.5k
        {
1801
85.5k
          if ((x + i) < (ssize_t) image->columns &&
1802
67.5k
              (y + j) < (ssize_t) image->rows)
1803
59.3k
            {
1804
59.3k
              code = (bits >> ((4*j+i)*2)) & 0x3;
1805
59.3k
              SetPixelRed(image,ScaleCharToQuantum(colors.r[code]),q);
1806
59.3k
              SetPixelGreen(image,ScaleCharToQuantum(colors.g[code]),q);
1807
59.3k
              SetPixelBlue(image,ScaleCharToQuantum(colors.b[code]),q);
1808
              /* Extract alpha value */
1809
59.3k
              alpha_code = (size_t) (alpha_bits >> (3*(4*j+i))) & 0x7;
1810
59.3k
              if (alpha_code == 0)
1811
19.8k
                alpha = a0;
1812
39.5k
              else if (alpha_code == 1)
1813
5.02k
                alpha = a1;
1814
34.5k
              else if (a0 > a1)
1815
5.55k
                alpha = ((8-alpha_code) * a0 + (alpha_code-1) * a1) / 7;
1816
28.9k
              else if (alpha_code == 6)
1817
3.93k
                alpha = 0;
1818
25.0k
              else if (alpha_code == 7)
1819
10.6k
                alpha = 255;
1820
14.4k
              else
1821
14.4k
                alpha = (((6-alpha_code) * a0 + (alpha_code-1) * a1) / 5);
1822
59.3k
              SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) alpha),q);
1823
59.3k
              q+=(ptrdiff_t) GetPixelChannels(image);
1824
59.3k
            }
1825
85.5k
        }
1826
21.3k
      }
1827
5.34k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
1828
0
        return(MagickFalse);
1829
5.34k
    }
1830
2.44k
    if (EOFBlob(image) != MagickFalse)
1831
0
      return(MagickFalse);
1832
2.44k
  }
1833
253
  return(MagickTrue);
1834
507
}
1835
1836
static MagickBooleanType ReadDXT5(const ImageInfo *image_info,Image *image,
1837
  const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1838
  ExceptionInfo *exception)
1839
507
{
1840
507
  if (ReadDXT5Pixels(image,dds_info,exception) == MagickFalse)
1841
254
    return(MagickFalse);
1842
1843
253
  if (read_mipmaps != MagickFalse)
1844
0
    return(ReadMipmaps(image_info,image,dds_info,ReadDXT5Pixels,exception));
1845
253
  else
1846
253
    return(SkipMipmaps(image,dds_info,16,exception));
1847
253
}
1848
1849
static unsigned char GetBit(const unsigned char *block,size_t *start_bit)
1850
113k
{
1851
113k
  size_t
1852
113k
    base,
1853
113k
    index;
1854
1855
113k
  index=(*start_bit) >> 3;
1856
113k
  base=(*start_bit) - (index << 3);
1857
113k
  (*start_bit)++;
1858
113k
  if (index > 15)
1859
0
    return(0);
1860
113k
  return((block[index] >> base) & 0x01);
1861
113k
}
1862
1863
static unsigned char GetBits(const unsigned char *block,size_t *start_bit,
1864
  unsigned char num_bits)
1865
774k
{
1866
774k
  size_t
1867
774k
    base,
1868
774k
    first_bits,
1869
774k
    index,
1870
774k
    next_bits;
1871
1872
774k
  unsigned char
1873
774k
    ret;
1874
1875
774k
  index=(*start_bit) >> 3;
1876
774k
  base=(*start_bit)-(index << 3);
1877
774k
  if (index > 15)
1878
0
    return(0);
1879
774k
  if (base + num_bits > 8)
1880
237k
    {
1881
237k
      first_bits=8-base;
1882
237k
      next_bits=num_bits-first_bits;
1883
237k
      ret=((block[index] >> base) | (((block[index + 1]) &
1884
237k
        ((1u << next_bits) - 1)) << first_bits));
1885
237k
    }
1886
537k
  else
1887
537k
    {
1888
537k
      ret=((block[index] >> base) & ((1 << num_bits) - 1));
1889
537k
    }
1890
774k
  (*start_bit)+=num_bits;
1891
774k
  return(ret);
1892
774k
}
1893
1894
static MagickBooleanType IsPixelAnchorIndex(unsigned char subset_index,
1895
  unsigned char num_subsets,size_t pixelIndex,unsigned char partition_id)
1896
264k
{
1897
264k
  size_t
1898
264k
    table_index;
1899
1900
  /* for first subset */
1901
264k
  if (subset_index == 0)
1902
182k
    table_index=0;
1903
  /* for second subset of two subset partitioning */
1904
82.1k
  else if ((subset_index == 1) && (num_subsets == 2))
1905
32.8k
    table_index=1;
1906
  /* for second subset of three subset partitioning */
1907
49.2k
  else if ((subset_index == 1) && (num_subsets == 3))
1908
21.5k
    table_index=2;
1909
  /* for third subset of three subset partitioning */
1910
27.6k
  else
1911
27.6k
    table_index=3;
1912
1913
264k
  if (BC7_anchor_index_table[table_index][partition_id] == pixelIndex)
1914
29.8k
    return(MagickTrue);
1915
234k
  else
1916
234k
    return(MagickFalse);
1917
264k
}
1918
1919
static void ReadEndpoints(BC7Colors *endpoints,const unsigned char *block,
1920
  size_t mode,size_t *start_bit)
1921
16.5k
{
1922
16.5k
  MagickBooleanType
1923
16.5k
    has_alpha,
1924
16.5k
    has_pbits;
1925
1926
16.5k
  unsigned char
1927
16.5k
    alpha_bits,
1928
16.5k
    color_bits,
1929
16.5k
    pbit,
1930
16.5k
    pbit0,
1931
16.5k
    pbit1;
1932
1933
16.5k
  size_t
1934
16.5k
    num_subsets,
1935
16.5k
    i;
1936
1937
16.5k
  num_subsets=(size_t) BC7_mode_info[mode].num_subsets;
1938
16.5k
  color_bits=BC7_mode_info[mode].color_precision;
1939
1940
  /* red */
1941
76.2k
  for (i=0; i < num_subsets * 2; i++)
1942
59.6k
    endpoints->r[i]=GetBits(block,start_bit,color_bits);
1943
1944
  /* green */
1945
76.2k
  for (i=0; i < num_subsets * 2; i++)
1946
59.6k
    endpoints->g[i]=GetBits(block,start_bit,color_bits);
1947
1948
  /* blue */
1949
76.2k
  for (i=0; i < num_subsets * 2; i++)
1950
59.6k
    endpoints->b[i]=GetBits(block,start_bit,color_bits);
1951
1952
  /* alpha */
1953
76.2k
  for (i=0; i < num_subsets * 2; i++)
1954
59.6k
    endpoints->a[i]=255;
1955
16.5k
  alpha_bits=BC7_mode_info[mode].alpha_precision;
1956
16.5k
  has_alpha=mode >= 4 ? MagickTrue : MagickFalse;
1957
1958
16.5k
  if (has_alpha != MagickFalse)
1959
9.57k
    {
1960
31.8k
      for (i=0; i < num_subsets * 2; i++)
1961
22.3k
        endpoints->a[i]=GetBits(block,start_bit,alpha_bits);
1962
9.57k
    }
1963
1964
  /* handle modes that have p bits */
1965
16.5k
  has_pbits=(mode == 0) || (mode == 1) || (mode == 3) || (mode == 6) || (mode == 7) ? MagickTrue : MagickFalse;
1966
1967
16.5k
  if (has_pbits != MagickFalse)
1968
7.67k
    {
1969
42.8k
      for (i=0; i < num_subsets * 2; i++)
1970
35.1k
      {
1971
35.1k
        endpoints->r[i] <<= 1;
1972
35.1k
        endpoints->g[i] <<= 1;
1973
35.1k
        endpoints->b[i] <<= 1;
1974
35.1k
        endpoints->a[i] <<= 1;
1975
35.1k
      }
1976
1977
      /* mode 1 shares a p-bit for both endpoints */
1978
7.67k
      if (mode == 1)
1979
1.12k
        {
1980
1.12k
          pbit0=GetBit(block,start_bit);
1981
1.12k
          pbit1=GetBit(block,start_bit);
1982
1983
1.12k
          endpoints->r[0] |= pbit0;
1984
1.12k
          endpoints->g[0] |= pbit0;
1985
1.12k
          endpoints->b[0] |= pbit0;
1986
1.12k
          endpoints->r[1] |= pbit0;
1987
1.12k
          endpoints->g[1] |= pbit0;
1988
1.12k
          endpoints->b[1] |= pbit0;
1989
1990
1.12k
          endpoints->r[2] |= pbit1;
1991
1.12k
          endpoints->g[2] |= pbit1;
1992
1.12k
          endpoints->b[2] |= pbit1;
1993
1.12k
          endpoints->r[3] |= pbit1;
1994
1.12k
          endpoints->g[3] |= pbit1;
1995
1.12k
          endpoints->b[3] |= pbit1;
1996
1.12k
        }
1997
6.55k
      else
1998
6.55k
      {
1999
37.2k
        for (i=0; i < num_subsets * 2; i++)
2000
30.6k
        {
2001
30.6k
          pbit=GetBit(block,start_bit);
2002
30.6k
          endpoints->r[i] |= pbit;
2003
30.6k
          endpoints->g[i] |= pbit;
2004
30.6k
          endpoints->b[i] |= pbit;
2005
30.6k
          endpoints->a[i] |= pbit;
2006
30.6k
        }
2007
6.55k
      }
2008
7.67k
    }
2009
2010
  /* 1 bit increased due to the pbit */
2011
16.5k
  if (has_pbits != MagickFalse)
2012
7.67k
    {
2013
7.67k
      color_bits++;
2014
7.67k
      alpha_bits++;
2015
7.67k
    }
2016
2017
  /* color and alpha bit shifting so that MSB lies in bit 7 */
2018
76.2k
  for (i=0; i < num_subsets * 2; i++)
2019
59.6k
  {
2020
59.6k
    endpoints->r[i] <<= (8 - color_bits);
2021
59.6k
    endpoints->g[i] <<= (8 - color_bits);
2022
59.6k
    endpoints->b[i] <<= (8 - color_bits);
2023
59.6k
    endpoints->a[i] <<= (8 - alpha_bits);
2024
2025
59.6k
    endpoints->r[i]=endpoints->r[i] | (endpoints->r[i] >> color_bits);
2026
59.6k
    endpoints->g[i]=endpoints->g[i] | (endpoints->g[i] >> color_bits);
2027
59.6k
    endpoints->b[i]=endpoints->b[i] | (endpoints->b[i] >> color_bits);
2028
59.6k
    endpoints->a[i]=endpoints->a[i] | (endpoints->a[i] >> alpha_bits);
2029
59.6k
  }
2030
2031
16.5k
  if (has_alpha == MagickFalse)
2032
6.97k
    {
2033
44.3k
      for (i=0; i < num_subsets * 2; i++)
2034
37.3k
        endpoints->a[i]=255;
2035
6.97k
    }
2036
16.5k
}
2037
2038
static MagickBooleanType ReadBC5Pixels(Image *image,
2039
  const DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
2040
549
{
2041
549
  BC5Colors
2042
549
    colors = { { 0 }, { 0 } };
2043
2044
549
  Quantum
2045
549
    *q;
2046
2047
549
  size_t
2048
549
    start_bit_g,
2049
549
    start_bit_r;
2050
2051
549
  ssize_t
2052
549
    i,
2053
549
    x,
2054
549
    y;
2055
2056
549
  unsigned char
2057
549
    block[16],
2058
549
    mode;
2059
2060
549
  magick_unreferenced(dds_info);
2061
4.17k
  for (y = 0; y < (ssize_t)image->rows; y += 4)
2062
3.96k
  {
2063
12.8k
    for (x = 0; x < (ssize_t)image->columns; x += 4)
2064
9.19k
    {
2065
9.19k
      size_t
2066
9.19k
        area;
2067
2068
9.19k
      ssize_t
2069
9.19k
        count;
2070
2071
      /* Get 4x4 patch of pixels to write on */
2072
9.19k
      q=QueueAuthenticPixels(image,x,y,(size_t)
2073
9.19k
        MagickMin(4,(ssize_t) image->columns-x),(size_t)
2074
9.19k
        MagickMin(4,(ssize_t) image->rows-y),exception);
2075
2076
9.19k
      if (q == (Quantum *)NULL)
2077
0
        return(MagickFalse);
2078
2079
      /* Read 16 bytes of data from the image */
2080
9.19k
      count=ReadBlob(image,16,block);
2081
9.19k
      if ((count != 16) || (EOFBlob(image) != MagickFalse))
2082
345
        return(MagickFalse);
2083
2084
      /* Get the mode of the block, 6 colors or 4 colors */
2085
8.84k
      colors.r[0]=block[0];
2086
8.84k
      colors.r[1]=block[1];
2087
8.84k
      colors.g[0]=block[8];
2088
8.84k
      colors.g[1]=block[9];
2089
2090
      /* Red palette */
2091
8.84k
      mode=4;
2092
8.84k
      if (colors.r[0] > colors.r[1])
2093
2.86k
        mode=6;
2094
49.9k
      for (i = 0; i < mode; i++)
2095
41.1k
      {
2096
41.1k
        colors.r[i+2]=(unsigned char) (((mode-i)*(float)colors.r[0]+(i+1)*
2097
41.1k
          (float)colors.r[1])/((float)(mode+1)));
2098
41.1k
      }
2099
8.84k
      if (mode == 4)
2100
5.97k
        {
2101
5.97k
          colors.r[6]=0;
2102
5.97k
          colors.r[7]=255;
2103
5.97k
        }
2104
2105
      /* Green palette */
2106
8.84k
      mode=4;
2107
8.84k
      if (colors.g[0] > colors.g[1])
2108
2.96k
        mode=6;
2109
50.1k
      for (i = 0; i < mode; i++)
2110
41.3k
      {
2111
41.3k
        colors.g[i+2]=(unsigned char) (((mode-i)*(float)colors.g[0]+(i+1)*
2112
41.3k
          (float)colors.g[1])/((float)(mode+1)));
2113
41.3k
      }
2114
8.84k
      if (mode == 4) {
2115
5.88k
        colors.g[6]=0;
2116
5.88k
        colors.g[7]=255;
2117
5.88k
      }
2118
2119
      /* Write the pixels */
2120
8.84k
      area=(size_t) (MagickMin(MagickMin(4,(ssize_t) image->columns-x)*
2121
8.84k
        MagickMin(4,(ssize_t) image->rows-y),16));
2122
8.84k
      start_bit_r=16;
2123
8.84k
      start_bit_g=80;
2124
100k
      for (i = 0; i < (ssize_t) area; i++)
2125
91.3k
      {
2126
91.3k
        SetPixelRed(image,ScaleCharToQuantum(colors.r[GetBits(block,
2127
91.3k
          &start_bit_r,3)]),q);
2128
91.3k
        SetPixelGreen(image,ScaleCharToQuantum(colors.g[GetBits(block,
2129
91.3k
          &start_bit_g,3)]),q);
2130
91.3k
        SetPixelBlue(image,(Quantum) 0,q);
2131
2132
91.3k
        q+=(ptrdiff_t) GetPixelChannels(image);
2133
91.3k
      }
2134
8.84k
      if (SyncAuthenticPixels(image, exception) == MagickFalse)
2135
0
        return(MagickFalse);
2136
8.84k
    }
2137
3.62k
    if (EOFBlob(image) != MagickFalse)
2138
0
      return(MagickFalse);
2139
3.62k
  }
2140
204
  return(MagickTrue);
2141
549
}
2142
2143
static MagickBooleanType ReadBC5(const ImageInfo *image_info,Image *image,
2144
  const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
2145
  ExceptionInfo *exception)
2146
549
{
2147
549
  if (ReadBC5Pixels(image,dds_info,exception) == MagickFalse)
2148
345
    return(MagickFalse);
2149
2150
204
  if (read_mipmaps != MagickFalse)
2151
0
    return(ReadMipmaps(image_info,image,dds_info,ReadBC5Pixels,exception));
2152
204
  else
2153
204
    return(SkipMipmaps(image,dds_info,16,exception));
2154
204
}
2155
2156
static MagickBooleanType ReadBC7Pixels(Image *image,
2157
  const DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
2158
838
{
2159
838
  BC7Colors
2160
838
    colors = { { 0 }, { 0 }, { 0 }, { 0 } };
2161
2162
838
  Quantum
2163
838
    *q;
2164
2165
838
  size_t
2166
838
    mode,
2167
838
    start_bit;
2168
2169
838
  ssize_t
2170
838
    count,
2171
838
    i,
2172
838
    x,
2173
838
    y;
2174
2175
838
  unsigned char
2176
838
    a,
2177
838
    alpha_indices[16],
2178
838
    b,
2179
838
    block[16],
2180
838
    c0,
2181
838
    c1,
2182
838
    color_indices[16],
2183
838
    g,
2184
838
    index_prec,
2185
838
    index2_prec,
2186
838
    num_bits,
2187
838
    num_subsets,
2188
838
    partition_id,
2189
838
    r,
2190
838
    rotation,
2191
838
    selector_bit,
2192
838
    subset_indices[16],
2193
838
    weight;
2194
2195
838
  magick_unreferenced(dds_info);
2196
2197
838
  memset(alpha_indices,0,sizeof(alpha_indices));
2198
838
  memset(block,0,sizeof(block));
2199
838
  memset(color_indices,0,sizeof(color_indices));
2200
838
  memset(subset_indices,0,sizeof(subset_indices));
2201
2202
4.84k
  for (y = 0; y < (ssize_t) image->rows; y += 4)
2203
4.57k
  {
2204
21.1k
    for (x = 0; x < (ssize_t) image->columns; x += 4)
2205
17.1k
    {
2206
17.1k
      size_t
2207
17.1k
        area;
2208
2209
      /* Get 4x4 patch of pixels to write on */
2210
17.1k
      q=QueueAuthenticPixels(image,x,y,(size_t)
2211
17.1k
        MagickMin(4,(ssize_t) image->columns-x),(size_t)
2212
17.1k
        MagickMin(4,(ssize_t) image->rows-y),exception);
2213
2214
17.1k
      if (q == (Quantum *) NULL)
2215
0
        return(MagickFalse);
2216
2217
      /* Read 16 bytes of data from the image */
2218
17.1k
      count=ReadBlob(image,16,block);
2219
      
2220
17.1k
      if (count != 16)
2221
550
        return(MagickFalse);
2222
2223
16.5k
      if (EOFBlob(image) != MagickFalse)
2224
0
        return(MagickFalse);
2225
2226
      /* Get the mode of the block */
2227
16.5k
      start_bit=0;
2228
70.4k
      while (start_bit <= 8 && !GetBit(block, &start_bit)) {}
2229
16.5k
      mode=start_bit-1;
2230
2231
16.5k
      if (mode > 7)
2232
21
        return(MagickFalse);
2233
2234
16.5k
      num_subsets=BC7_mode_info[mode].num_subsets;
2235
16.5k
      partition_id=0;
2236
2237
      /* only these modes have more than 1 subset */
2238
16.5k
      if ((mode == 0) || (mode == 1) || (mode == 2) || (mode == 3) || (mode == 7))
2239
8.55k
        {
2240
8.55k
          partition_id=GetBits(block,&start_bit,BC7_mode_info[mode].partition_bits);
2241
8.55k
          if (partition_id > 63)
2242
0
            return(MagickFalse);
2243
8.55k
        }
2244
2245
16.5k
      rotation=0;
2246
16.5k
      if ((mode == 4) || (mode == 5))
2247
7.16k
        rotation=GetBits(block,&start_bit,2);
2248
      
2249
16.5k
      selector_bit=0;
2250
16.5k
      if (mode == 4)
2251
5.95k
        selector_bit=GetBit(block, &start_bit);
2252
2253
16.5k
      ReadEndpoints(&colors,block,mode,&start_bit);
2254
2255
16.5k
      index_prec=BC7_mode_info[mode].index_precision;
2256
16.5k
      index2_prec=BC7_mode_info[mode].index2_precision;
2257
2258
16.5k
      if ((mode == 4) && (selector_bit == 1))
2259
4.35k
        {
2260
4.35k
          index_prec=3;
2261
4.35k
          alpha_indices[0]=GetBit(block,&start_bit);
2262
69.7k
          for (i = 1; i < 16; i++)
2263
65.3k
            alpha_indices[i]=GetBits(block,&start_bit,2);
2264
4.35k
        }
2265
2266
      /* get color and subset indices */
2267
281k
      for (i=0; i < 16; i++)
2268
264k
      {
2269
264k
        subset_indices[i]=GetSubsetIndex(num_subsets,partition_id,(size_t) i);
2270
264k
        num_bits=index_prec;
2271
264k
        if (IsPixelAnchorIndex(subset_indices[i],num_subsets,(size_t) i,partition_id))
2272
29.8k
          num_bits--;
2273
264k
        color_indices[i]=GetBits(block,&start_bit,num_bits);
2274
264k
      }
2275
2276
      /* get alpha indices if the block has it */
2277
16.5k
      if ((mode == 5) || ((mode == 4) && (selector_bit == 0)))
2278
2.80k
        {
2279
2.80k
          alpha_indices[0]=GetBits(block,&start_bit,index2_prec - 1);
2280
44.8k
          for (i=1; i < 16; i++)
2281
42.0k
            alpha_indices[i]=GetBits(block,&start_bit,index2_prec);
2282
2.80k
        }
2283
2284
      /* Write the pixels */
2285
16.5k
      area=(size_t) (MagickMin(MagickMin(4,(ssize_t) image->columns-x)*
2286
16.5k
        MagickMin(4,(ssize_t) image->rows-y),16));
2287
205k
      for (i=0; i < (ssize_t) area; i++)
2288
188k
      {
2289
188k
        unsigned char
2290
188k
          c2;
2291
2292
188k
        c0=2 * subset_indices[i];
2293
188k
        c1=(2 * subset_indices[i]) + 1;
2294
188k
        c2=color_indices[i];
2295
2296
188k
        weight=64;
2297
        /* Color Interpolation */
2298
188k
        switch(index_prec)
2299
188k
        {
2300
88.0k
          case 2:
2301
88.0k
            if (c2 < sizeof(BC7_weight2))
2302
88.0k
              weight=BC7_weight2[c2];
2303
88.0k
            break;
2304
91.1k
          case 3:
2305
91.1k
            if (c2 < sizeof(BC7_weight3))
2306
91.1k
              weight=BC7_weight3[c2];
2307
91.1k
            break;
2308
9.34k
          default:
2309
9.34k
            if (c2 < sizeof(BC7_weight4))
2310
9.34k
              weight=BC7_weight4[c2];
2311
188k
        }
2312
188k
        r=((64 - weight) * colors.r[c0] + weight * colors.r[c1] + 32) >> 6;
2313
188k
        g=((64 - weight) * colors.g[c0] + weight * colors.g[c1] + 32) >> 6;
2314
188k
        b=((64 - weight) * colors.b[c0] + weight * colors.b[c1] + 32) >> 6;
2315
188k
        a=((64 - weight) * colors.a[c0] + weight * colors.a[c1] + 32) >> 6;
2316
2317
        /* Interpolate alpha for mode 4 and 5 blocks */
2318
188k
        if (mode == 4 || mode == 5)
2319
83.7k
          {
2320
83.7k
            unsigned char
2321
83.7k
              a0;
2322
2323
83.7k
            a0=alpha_indices[i];
2324
83.7k
            if (a0 < sizeof(BC7_weight2))
2325
78.3k
              weight=BC7_weight2[a0];
2326
83.7k
            if ((mode == 4) && (selector_bit == 0) && (a0 < sizeof(BC7_weight3)))
2327
18.7k
              weight=BC7_weight3[a0];
2328
83.7k
            if ((c0 < sizeof(colors.a)) && (c1 < sizeof(colors.a)))
2329
83.7k
              a=((64 - weight) * colors.a[c0] + weight * colors.a[c1] + 32) >> 6;
2330
83.7k
          }
2331
188k
        switch (rotation)
2332
188k
        {
2333
46.8k
          case 1:
2334
46.8k
            Swap(a,r);
2335
46.8k
            break;
2336
7.67k
          case 2:
2337
7.67k
            Swap(a,g);
2338
7.67k
            break;
2339
9.47k
          case 3:
2340
9.47k
            Swap(a,b);
2341
9.47k
            break;
2342
188k
        }
2343
2344
188k
        SetPixelRed(image,ScaleCharToQuantum((unsigned char)r),q);
2345
188k
        SetPixelGreen(image,ScaleCharToQuantum((unsigned char)g),q);
2346
188k
        SetPixelBlue(image,ScaleCharToQuantum((unsigned char)b),q);
2347
188k
        SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)a),q);
2348
2349
188k
        q+=(ptrdiff_t) GetPixelChannels(image);
2350
188k
      }
2351
16.5k
      if (SyncAuthenticPixels(image,exception) == MagickFalse)
2352
0
        return(MagickFalse);
2353
16.5k
    }
2354
4.00k
    if (EOFBlob(image) != MagickFalse)
2355
0
      return(MagickFalse);
2356
4.00k
  }
2357
267
  return(MagickTrue);
2358
838
}
2359
2360
static MagickBooleanType ReadBC7(const ImageInfo *image_info,Image *image,
2361
  const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
2362
  ExceptionInfo *exception)
2363
838
{
2364
838
  if (ReadBC7Pixels(image,dds_info,exception) == MagickFalse)
2365
571
    return(MagickFalse);
2366
2367
267
  if (read_mipmaps != MagickFalse)
2368
0
    return(ReadMipmaps(image_info,image,dds_info,ReadBC7Pixels,exception));
2369
267
  else
2370
267
    return(SkipMipmaps(image,dds_info,16,exception));
2371
267
}
2372
2373
static inline void GetMaskShiftAndMaxval(const size_t mask, size_t *shift,
2374
  size_t *max_val)
2375
23.0k
{
2376
23.0k
  *shift=0;
2377
23.0k
  *max_val=0;
2378
23.0k
  if (mask == 0)
2379
5.64k
    return;
2380
108k
  while (((mask >> *shift) & 1) == 0)
2381
90.6k
    (*shift)++;
2382
17.3k
  *max_val=mask >> *shift;
2383
17.3k
}
2384
2385
static inline unsigned char ExtractChannelFromMask(unsigned short color,
2386
  size_t mask, size_t shift, size_t max_val)
2387
413k
{
2388
413k
  size_t
2389
413k
    value;
2390
2391
413k
  if (max_val == 0)
2392
194k
    return(0);
2393
219k
  value=(((size_t) color & mask) >> shift) * 255U + max_val / 2U;
2394
219k
  return((unsigned char) (value / max_val));
2395
413k
}
2396
2397
static MagickBooleanType ReadUncompressedRGBPixels(Image *image,
2398
  const DDSInfo *dds_info,ExceptionInfo *exception)
2399
4.39k
{
2400
4.39k
  MagickBooleanType
2401
4.39k
    is_rgb;
2402
2403
4.39k
  Quantum
2404
4.39k
    *q;
2405
2406
4.39k
  size_t
2407
4.39k
    b_mask,
2408
4.39k
    b_max,
2409
4.39k
    b_shift,
2410
4.39k
    g_mask,
2411
4.39k
    g_max,
2412
4.39k
    g_shift,
2413
4.39k
    r_mask,
2414
4.39k
    r_max,
2415
4.39k
    r_shift;
2416
2417
4.39k
  ssize_t
2418
4.39k
    x,
2419
4.39k
    y;
2420
2421
4.39k
  unsigned short
2422
4.39k
    color;
2423
2424
4.39k
  r_mask=dds_info->pixelformat.r_bitmask;
2425
4.39k
  g_mask=dds_info->pixelformat.g_bitmask;
2426
4.39k
  b_mask=dds_info->pixelformat.b_bitmask;
2427
4.39k
  if ((r_mask == 0) && (g_mask == 0) && (b_mask == 0))
2428
404
    {
2429
404
      r_mask=0xf800;
2430
404
      g_mask=0x07e0;
2431
404
      b_mask=0x001f;
2432
404
    }
2433
2434
4.39k
  GetMaskShiftAndMaxval(r_mask,&r_shift,&r_max);
2435
4.39k
  GetMaskShiftAndMaxval(g_mask,&g_shift,&g_max);
2436
4.39k
  GetMaskShiftAndMaxval(b_mask,&b_shift,&b_max);
2437
2438
4.39k
  is_rgb=IsBitMask(dds_info->pixelformat,0x000000ff,0x0000ff00,0x00ff0000,0x0000000) ? MagickTrue : MagickFalse;
2439
125k
  for (y = 0; y < (ssize_t) image->rows; y++)
2440
123k
  {
2441
123k
    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2442
2443
123k
    if (q == (Quantum *) NULL)
2444
0
      return(MagickFalse);
2445
2446
874k
    for (x = 0; x < (ssize_t) image->columns; x++)
2447
751k
    {
2448
751k
      if ((dds_info->pixelformat.rgb_bitcount == 8) ||
2449
353k
          (dds_info->extFormat == DXGI_FORMAT_R8_UNORM))
2450
408k
        SetPixelGray(image,ScaleCharToQuantum((unsigned char) ReadBlobByte(image)),q);
2451
343k
      else if ((dds_info->pixelformat.rgb_bitcount == 16) ||
2452
339k
               (dds_info->extFormat == DXGI_FORMAT_B5G6R5_UNORM))
2453
8.76k
        {
2454
8.76k
           color=ReadBlobShort(image);
2455
8.76k
           SetPixelRed(image,ScaleCharToQuantum(ExtractChannelFromMask(
2456
8.76k
             color,r_mask,r_shift,r_max)),q);
2457
8.76k
           SetPixelGreen(image,ScaleCharToQuantum(ExtractChannelFromMask(
2458
8.76k
             color,g_mask,g_shift,g_max)),q);
2459
8.76k
           SetPixelBlue(image,ScaleCharToQuantum(ExtractChannelFromMask(
2460
8.76k
             color,b_mask,b_shift,b_max)),q);
2461
8.76k
        }
2462
334k
      else
2463
334k
        {
2464
334k
          if (is_rgb != MagickFalse)
2465
1.83k
            {
2466
1.83k
              SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2467
1.83k
                ReadBlobByte(image)),q);
2468
1.83k
              SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2469
1.83k
                ReadBlobByte(image)),q);
2470
1.83k
              SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2471
1.83k
                ReadBlobByte(image)),q);
2472
1.83k
            }
2473
332k
          else
2474
332k
            {
2475
332k
              SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2476
332k
                ReadBlobByte(image)),q);
2477
332k
              SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2478
332k
                ReadBlobByte(image)),q);
2479
332k
              SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2480
332k
                ReadBlobByte(image)),q);
2481
332k
            }
2482
334k
          if (dds_info->pixelformat.rgb_bitcount == 32 || 
2483
320k
              dds_info->extFormat == DXGI_FORMAT_B8G8R8X8_UNORM)
2484
17.3k
            (void) ReadBlobByte(image);
2485
334k
        }
2486
751k
      q+=(ptrdiff_t) GetPixelChannels(image);
2487
751k
    }
2488
123k
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
2489
0
      return(MagickFalse);
2490
123k
    if (EOFBlob(image) != MagickFalse)
2491
1.92k
      return(MagickFalse);
2492
123k
  }
2493
2.46k
  return(MagickTrue);
2494
4.39k
}
2495
2496
static MagickBooleanType ReadUncompressedAlphaPixels(Image *image,
2497
  const DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
2498
1.60k
{
2499
1.60k
  Quantum
2500
1.60k
    *q;
2501
2502
1.60k
  ssize_t
2503
1.60k
    x,
2504
1.60k
    y;
2505
2506
1.60k
  magick_unreferenced(dds_info);
2507
32.7k
  for (y = 0; y < (ssize_t) image->rows; y++)
2508
31.5k
  {
2509
31.5k
    q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
2510
2511
31.5k
    if (q == (Quantum *) NULL)
2512
0
      return(MagickFalse);
2513
2514
203k
    for (x = 0; x < (ssize_t) image->columns; x++)
2515
172k
    {
2516
172k
      SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
2517
172k
        ReadBlobByte(image)),q);
2518
172k
      q+=(ptrdiff_t) GetPixelChannels(image);
2519
172k
    }
2520
31.5k
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
2521
0
      return(MagickFalse);
2522
31.5k
    if (EOFBlob(image) != MagickFalse)
2523
392
      return(MagickFalse);
2524
31.5k
  }
2525
1.21k
  return(MagickTrue);
2526
1.60k
}
2527
2528
/*
2529
  Skip the mipmap images for uncompressed (RGB or RGBA) dds files
2530
*/
2531
static MagickBooleanType SkipRGBMipmaps(Image *image,const DDSInfo *dds_info,
2532
  int pixel_size,ExceptionInfo *exception)
2533
4.44k
{
2534
  /*
2535
    Only skip mipmaps for textures and cube maps
2536
  */
2537
4.44k
  if (EOFBlob(image) != MagickFalse)
2538
0
    {
2539
0
      ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
2540
0
        image->filename);
2541
0
      return(MagickFalse);
2542
0
    }
2543
4.44k
  if (dds_info->ddscaps1 & DDSCAPS_MIPMAP
2544
2.44k
      && (dds_info->ddscaps1 & DDSCAPS_TEXTURE
2545
1.22k
          || dds_info->ddscaps2 & DDSCAPS2_CUBEMAP))
2546
1.90k
    {
2547
1.90k
      MagickOffsetType
2548
1.90k
        offset;
2549
  
2550
1.90k
      ssize_t
2551
1.90k
        i;
2552
2553
1.90k
      size_t
2554
1.90k
        h,
2555
1.90k
        w;
2556
2557
1.90k
      w=DIV2(dds_info->width);
2558
1.90k
      h=DIV2(dds_info->height);
2559
2560
      /*
2561
        Mipmapcount includes the main image, so start from one
2562
      */
2563
4.35k
      for (i=1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)
2564
3.60k
      {
2565
3.60k
        offset=(MagickOffsetType) (w*h*(size_t) pixel_size);
2566
3.60k
        if (SeekBlob(image,offset,SEEK_CUR) < 0)
2567
0
          break;
2568
3.60k
        w=DIV2(w);
2569
3.60k
        h=DIV2(h);
2570
3.60k
        if ((w == 1) && (h == 1))
2571
1.16k
          break;
2572
3.60k
      }
2573
1.90k
    }
2574
4.44k
  return(MagickTrue);
2575
4.44k
}
2576
2577
static MagickBooleanType ReadUncompressedRGB(const ImageInfo *image_info,
2578
  Image *image,const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
2579
  ExceptionInfo *exception)
2580
4.78k
{
2581
4.78k
  if (dds_info->pixelformat.rgb_bitcount == 8 || 
2582
1.73k
      dds_info->extFormat == DXGI_FORMAT_R8_UNORM)
2583
3.13k
    (void) SetImageType(image,GrayscaleType,exception);
2584
1.65k
  else if (dds_info->pixelformat.rgb_bitcount == 16 && !IsBitMask(
2585
1.65k
    dds_info->pixelformat,0xf800,0x07e0,0x001f,0x0000))
2586
393
    ThrowBinaryException(ImageError,"ImageTypeNotSupported",
2587
4.78k
      image->filename);
2588
2589
4.39k
  if (ReadUncompressedRGBPixels(image,dds_info,exception) == MagickFalse)
2590
1.92k
    return(MagickFalse);
2591
2592
2.46k
  if (read_mipmaps != MagickFalse)
2593
0
    return(ReadMipmaps(image_info,image,dds_info,ReadUncompressedRGBPixels,
2594
0
      exception));
2595
2.46k
  else
2596
2.46k
    return(SkipRGBMipmaps(image,dds_info,3,exception));
2597
2.46k
}
2598
2599
static MagickBooleanType ReadUncompressedAlpha(const ImageInfo *image_info,
2600
  Image *image,const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
2601
  ExceptionInfo *exception)
2602
1.70k
{
2603
1.70k
  if (dds_info->pixelformat.rgb_bitcount != 8)
2604
104
    ThrowBinaryException(ImageError,"ImageTypeNotSupported",
2605
1.70k
      image->filename);
2606
2607
1.60k
  if (ReadUncompressedAlphaPixels(image,dds_info,exception) == MagickFalse)
2608
392
    return(MagickFalse);
2609
2610
1.21k
  if (read_mipmaps != MagickFalse)
2611
0
    return(ReadMipmaps(image_info,image,dds_info,ReadUncompressedAlphaPixels,
2612
0
      exception));
2613
1.21k
  else
2614
1.21k
    return(SkipRGBMipmaps(image,dds_info,1,exception));
2615
1.21k
}
2616
2617
static MagickBooleanType ReadUncompressedRGBAPixels(Image *image,
2618
  const DDSInfo *dds_info,ExceptionInfo *exception)
2619
2.46k
{
2620
2.46k
  MagickBooleanType
2621
2.46k
    is_grayscale,
2622
2.46k
    is_rgba;
2623
2624
2.46k
  Quantum
2625
2.46k
    *q;
2626
2627
2.46k
  size_t
2628
2.46k
    a_mask,
2629
2.46k
    a_max,
2630
2.46k
    a_shift,
2631
2.46k
    b_mask,
2632
2.46k
    b_max,
2633
2.46k
    b_shift,
2634
2.46k
    g_mask,
2635
2.46k
    g_max,
2636
2.46k
    g_shift,
2637
2.46k
    r_mask,
2638
2.46k
    r_max,
2639
2.46k
    r_shift;
2640
2641
2.46k
  ssize_t
2642
2.46k
    x,
2643
2.46k
    y;
2644
2645
2.46k
  unsigned short
2646
2.46k
    color;
2647
2648
2.46k
  a_mask=dds_info->pixelformat.alpha_bitmask;
2649
2.46k
  b_mask=dds_info->pixelformat.b_bitmask;
2650
2.46k
  g_mask=dds_info->pixelformat.g_bitmask;
2651
2.46k
  r_mask=dds_info->pixelformat.r_bitmask;
2652
2653
2.46k
  is_grayscale=MagickFalse;
2654
2.46k
  if ((dds_info->pixelformat.rgb_bitcount == 16) ||
2655
923
      (dds_info->extFormat == DXGI_FORMAT_B5G5R5A1_UNORM))
2656
1.62k
    {
2657
1.62k
      if ((r_mask == 0) && (g_mask == 0) && (b_mask == 0) && (a_mask == 0))
2658
84
        {
2659
84
          r_mask=0x7c00;
2660
84
          g_mask=0x03e0;
2661
84
          b_mask=0x001f;
2662
84
          a_mask=0x8000;
2663
84
        }
2664
1.62k
      if ((r_mask == g_mask && g_mask == b_mask) || 
2665
1.35k
          (g_mask == 0 && b_mask == 0))
2666
566
        {
2667
566
          is_grayscale=MagickTrue;
2668
566
          (void) SetImageType(image,GrayscaleAlphaType,exception);
2669
566
        }
2670
1.62k
    }
2671
2672
2.46k
  GetMaskShiftAndMaxval(a_mask,&a_shift,&a_max);
2673
2.46k
  GetMaskShiftAndMaxval(r_mask,&r_shift,&r_max);
2674
2.46k
  GetMaskShiftAndMaxval(g_mask,&g_shift,&g_max);
2675
2.46k
  GetMaskShiftAndMaxval(b_mask,&b_shift,&b_max);
2676
2677
2.46k
  is_rgba=IsBitMask(dds_info->pixelformat,0x000000ff,0x0000ff00,0x00ff0000,0xff00000) ? MagickTrue : MagickFalse;
2678
8.12k
  for (y = 0; y < (ssize_t) image->rows; y++)
2679
7.35k
  {
2680
7.35k
    q = QueueAuthenticPixels(image, 0, y, image->columns, 1,exception);
2681
2682
7.35k
    if (q == (Quantum *) NULL)
2683
0
      return(MagickFalse);
2684
2685
417k
    for (x = 0; x < (ssize_t) image->columns; x++)
2686
410k
    {
2687
410k
      if ((dds_info->pixelformat.rgb_bitcount == 16) ||
2688
270k
          (dds_info->extFormat == DXGI_FORMAT_B5G5R5A1_UNORM))
2689
145k
        {
2690
145k
           color=ReadBlobShort(image);
2691
145k
           SetPixelAlpha(image,ScaleCharToQuantum(ExtractChannelFromMask(
2692
145k
             color,a_mask,a_shift,a_max)),q);
2693
145k
           if (is_grayscale != MagickFalse)
2694
64.5k
             SetPixelGray(image,ScaleCharToQuantum((unsigned char) color),q);
2695
80.7k
           else
2696
80.7k
             {
2697
80.7k
               SetPixelRed(image,ScaleCharToQuantum(ExtractChannelFromMask(
2698
80.7k
                 color,r_mask,r_shift,r_max)),q);
2699
80.7k
               SetPixelGreen(image,ScaleCharToQuantum(ExtractChannelFromMask(
2700
80.7k
                 color,g_mask,g_shift,g_max)),q);
2701
80.7k
               SetPixelBlue(image,ScaleCharToQuantum(ExtractChannelFromMask(
2702
80.7k
                 color,b_mask,b_shift,b_max)),q);
2703
80.7k
             }
2704
145k
        }
2705
265k
      else if (dds_info->extFormat == DXGI_FORMAT_R10G10B10A2_UNORM)
2706
7.76k
        {
2707
7.76k
          const unsigned int
2708
7.76k
            pixel=ReadBlobLSBLong(image);
2709
2710
7.76k
          SetPixelRed(image,ScaleShortToQuantum((unsigned short)
2711
7.76k
            ((pixel & 0x3ff)/1023.0)*65535),q);
2712
7.76k
          SetPixelBlue(image,ScaleShortToQuantum((unsigned short)
2713
7.76k
            (((pixel >> 10) & 0x3ff)/1023.0)*65535),q);
2714
7.76k
          SetPixelGreen(image,ScaleShortToQuantum((unsigned short)
2715
7.76k
            (((pixel >> 20) & 0x3ff)/1023.0)*65535),q);
2716
7.76k
          SetPixelAlpha(image,ScaleShortToQuantum((unsigned short)
2717
7.76k
            (((pixel >> 30) & 3)/3.0)*65535),q);
2718
7.76k
        }
2719
257k
      else if ((dds_info->extFormat == DXGI_FORMAT_R8G8B8A8_UNORM) ||
2720
253k
               (is_rgba != MagickFalse))
2721
8.42k
        {
2722
8.42k
          SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2723
8.42k
            ReadBlobByte(image)),q);
2724
8.42k
          SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2725
8.42k
            ReadBlobByte(image)),q);
2726
8.42k
          SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2727
8.42k
            ReadBlobByte(image)),q);
2728
8.42k
          SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
2729
8.42k
            ReadBlobByte(image)),q);
2730
8.42k
        }
2731
248k
      else
2732
248k
        {
2733
248k
          SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
2734
248k
            ReadBlobByte(image)),q);
2735
248k
          SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
2736
248k
            ReadBlobByte(image)),q);
2737
248k
          SetPixelRed(image,ScaleCharToQuantum((unsigned char)
2738
248k
            ReadBlobByte(image)),q);
2739
248k
          SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
2740
248k
            ReadBlobByte(image)),q);
2741
248k
        }
2742
410k
      q+=(ptrdiff_t) GetPixelChannels(image);
2743
410k
    }
2744
7.35k
    if (SyncAuthenticPixels(image,exception) == MagickFalse)
2745
0
      return(MagickFalse);
2746
7.35k
    if (EOFBlob(image) != MagickFalse)
2747
1.69k
      return(MagickFalse);
2748
7.35k
  }
2749
774
  return(MagickTrue);
2750
2.46k
}
2751
2752
static MagickBooleanType ReadUncompressedRGBA(const ImageInfo *image_info,
2753
  Image *image,const DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
2754
  ExceptionInfo *exception)
2755
2.46k
{
2756
2.46k
  if (ReadUncompressedRGBAPixels(image,dds_info,exception) == MagickFalse)
2757
1.69k
    return(MagickFalse);
2758
2759
774
  if (read_mipmaps != MagickFalse)
2760
0
    return(ReadMipmaps(image_info,image,dds_info,ReadUncompressedRGBAPixels,
2761
0
      exception));
2762
774
  else
2763
774
    return(SkipRGBMipmaps(image,dds_info,4,exception));
2764
774
}
2765

2766
/*
2767
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2768
%                                                                             %
2769
%                                                                             %
2770
%                                                                             %
2771
%   R e a d D D S I m a g e                                                   %
2772
%                                                                             %
2773
%                                                                             %
2774
%                                                                             %
2775
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2776
%
2777
%  ReadDDSImage() reads a DirectDraw Surface image file and returns it.  It
2778
%  allocates the memory necessary for the new Image structure and returns a
2779
%  pointer to the new image.
2780
%
2781
%  The format of the ReadDDSImage method is:
2782
%
2783
%      Image *ReadDDSImage(const ImageInfo *image_info,ExceptionInfo *exception)
2784
%
2785
%  A description of each parameter follows:
2786
%
2787
%    o image_info: The image info.
2788
%
2789
%    o exception: return any errors or warnings in this structure.
2790
%
2791
*/
2792
static Image *ReadDDSImage(const ImageInfo *image_info,ExceptionInfo *exception)
2793
9.18k
{
2794
9.18k
  const char
2795
9.18k
    *option;
2796
2797
9.18k
  CompressionType
2798
9.18k
    compression;
2799
2800
9.18k
  DDSInfo
2801
9.18k
    dds_info;
2802
2803
9.18k
  DDSDecoder
2804
9.18k
    *decoder;
2805
2806
9.18k
  Image
2807
9.18k
    *image;
2808
2809
9.18k
  MagickBooleanType
2810
9.18k
    status,
2811
9.18k
    cubemap,
2812
9.18k
    volume,
2813
9.18k
    read_mipmaps;
2814
2815
9.18k
  PixelTrait
2816
9.18k
    alpha_trait;
2817
2818
9.18k
  size_t
2819
9.18k
    n,
2820
9.18k
    num_images;
2821
2822
  /*
2823
    Open image file.
2824
  */
2825
9.18k
  assert(image_info != (const ImageInfo *) NULL);
2826
9.18k
  assert(image_info->signature == MagickCoreSignature);
2827
9.18k
  assert(exception != (ExceptionInfo *) NULL);
2828
9.18k
  assert(exception->signature == MagickCoreSignature);
2829
9.18k
  if (IsEventLogging() != MagickFalse)
2830
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2831
0
      image_info->filename);
2832
9.18k
  cubemap=MagickFalse,
2833
9.18k
  volume=MagickFalse,
2834
9.18k
  read_mipmaps=MagickFalse;
2835
9.18k
  image=AcquireImage(image_info,exception);
2836
9.18k
  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2837
9.18k
  if (status == MagickFalse)
2838
0
    {
2839
0
      image=DestroyImageList(image);
2840
0
      return((Image *) NULL);
2841
0
    }
2842
  
2843
  /*
2844
    Initialize image structure.
2845
  */
2846
9.18k
  if (ReadDDSInfo(image,&dds_info) != MagickTrue)
2847
8.86k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2848
2849
8.86k
  if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP)
2850
2.32k
    cubemap=MagickTrue;
2851
2852
8.86k
  if (dds_info.ddscaps2 & DDSCAPS2_VOLUME && dds_info.depth > 0)
2853
2.08k
    volume=MagickTrue;
2854
2855
  /*
2856
    Determine pixel format
2857
  */
2858
8.86k
  if (dds_info.pixelformat.flags & DDPF_RGB)
2859
3.07k
    {
2860
3.07k
      compression=NoCompression;
2861
3.07k
      if (dds_info.pixelformat.flags & DDPF_ALPHAPIXELS)
2862
1.46k
        {
2863
1.46k
          alpha_trait=BlendPixelTrait;
2864
1.46k
          decoder=ReadUncompressedRGBA;
2865
1.46k
        }
2866
1.61k
      else
2867
1.61k
        {
2868
1.61k
          alpha_trait=UndefinedPixelTrait;
2869
1.61k
          decoder=ReadUncompressedRGB;
2870
1.61k
        }
2871
3.07k
    }
2872
5.79k
  else if (dds_info.pixelformat.flags & DDPF_ALPHA)
2873
716
    {
2874
716
      compression=NoCompression;
2875
716
      alpha_trait=BlendPixelTrait;
2876
716
      decoder=ReadUncompressedAlpha;
2877
716
    }
2878
5.07k
  else if (dds_info.pixelformat.flags & DDPF_LUMINANCE)
2879
1.45k
   {
2880
1.45k
      compression=NoCompression;
2881
1.45k
      if (dds_info.pixelformat.flags & DDPF_ALPHAPIXELS)
2882
400
        {
2883
400
          alpha_trait=BlendPixelTrait;
2884
400
          decoder=ReadUncompressedRGBA;
2885
400
        }
2886
1.05k
      else
2887
1.05k
        {
2888
1.05k
          alpha_trait=UndefinedPixelTrait;
2889
1.05k
          decoder=ReadUncompressedRGB;
2890
1.05k
        }
2891
1.45k
    }
2892
3.62k
  else if (dds_info.pixelformat.flags & DDPF_FOURCC)
2893
3.62k
    {
2894
3.62k
      switch (dds_info.pixelformat.fourcc)
2895
3.62k
      {
2896
341
        case FOURCC_ATI2:
2897
353
        case FOURCC_BC5U:
2898
353
        {
2899
353
          alpha_trait=UndefinedPixelTrait;
2900
353
          compression=BC5Compression;
2901
353
          decoder=ReadBC5;
2902
353
          break;
2903
341
        }
2904
1.18k
        case FOURCC_DXT1:
2905
1.18k
        {
2906
1.18k
          alpha_trait=UndefinedPixelTrait;
2907
1.18k
          compression=DXT1Compression;
2908
1.18k
          decoder=ReadDXT1;
2909
1.18k
          break;
2910
341
        }
2911
204
        case FOURCC_DXT3:
2912
204
        {
2913
204
          alpha_trait=BlendPixelTrait;
2914
204
          compression=DXT3Compression;
2915
204
          decoder=ReadDXT3;
2916
204
          break;
2917
341
        }
2918
281
        case FOURCC_DXT5:
2919
281
        {
2920
281
          alpha_trait=BlendPixelTrait;
2921
281
          compression=DXT5Compression;
2922
281
          decoder=ReadDXT5;
2923
281
          break;
2924
341
        }
2925
756
        case FOURCC_DX10:
2926
756
        {
2927
756
          if (dds_info.extDimension != DDSEXT_DIMENSION_TEX2D)
2928
93
            {
2929
93
              ThrowReaderException(ImageError,"ImageTypeNotSupported");
2930
0
            }
2931
2932
663
          switch (dds_info.extFormat)
2933
663
          {
2934
16
            case DXGI_FORMAT_R8_UNORM:
2935
16
            {
2936
16
              alpha_trait=UndefinedPixelTrait;
2937
16
              compression=NoCompression;
2938
16
              decoder=ReadUncompressedRGB;
2939
16
              break;
2940
0
            }
2941
3
            case DXGI_FORMAT_B5G6R5_UNORM:
2942
3
            {
2943
3
              alpha_trait=UndefinedPixelTrait;
2944
3
              compression=NoCompression;
2945
3
              decoder=ReadUncompressedRGB;
2946
3
              break;
2947
0
            }
2948
12
            case DXGI_FORMAT_B5G5R5A1_UNORM:
2949
12
            {
2950
12
              alpha_trait=BlendPixelTrait;
2951
12
              compression=NoCompression;
2952
12
              decoder=ReadUncompressedRGBA;
2953
12
              break;
2954
0
            }
2955
3
            case DXGI_FORMAT_B8G8R8A8_UNORM:
2956
3
            {
2957
3
              alpha_trait=BlendPixelTrait;
2958
3
              compression=NoCompression;
2959
3
              decoder=ReadUncompressedRGBA;
2960
3
              break;
2961
0
            }
2962
4
            case DXGI_FORMAT_R8G8B8A8_UNORM:
2963
4
            {
2964
4
              alpha_trait=BlendPixelTrait;
2965
4
              compression=NoCompression;
2966
4
              decoder=ReadUncompressedRGBA;
2967
4
              break;
2968
0
            }
2969
9
            case DXGI_FORMAT_R10G10B10A2_UNORM:
2970
9
            {
2971
9
              compression=NoCompression;
2972
9
              alpha_trait=BlendPixelTrait;
2973
9
              decoder=ReadUncompressedRGBA;
2974
9
              break;
2975
0
            }
2976
3
            case DXGI_FORMAT_B8G8R8X8_UNORM:
2977
3
            {
2978
3
              alpha_trait=UndefinedPixelTrait;
2979
3
              compression=NoCompression;
2980
3
              decoder=ReadUncompressedRGB;
2981
3
              break;
2982
0
            }
2983
9
            case DXGI_FORMAT_BC1_UNORM:
2984
9
            {
2985
9
              alpha_trait = UndefinedPixelTrait;
2986
9
              compression = DXT1Compression;
2987
9
              decoder = ReadDXT1;
2988
9
              break;
2989
0
            }
2990
4
            case DXGI_FORMAT_BC2_UNORM:
2991
4
            {
2992
4
              alpha_trait=BlendPixelTrait;
2993
4
              compression=DXT3Compression;
2994
4
              decoder=ReadDXT3;
2995
4
              break;
2996
0
            }
2997
3
            case DXGI_FORMAT_BC3_UNORM:
2998
3
            {
2999
3
              alpha_trait = BlendPixelTrait;
3000
3
              compression = DXT5Compression;
3001
3
              decoder = ReadDXT5;
3002
3
              break;
3003
0
            }
3004
3
            case DXGI_FORMAT_BC5_UNORM:
3005
3
            {
3006
3
              alpha_trait=UndefinedPixelTrait;
3007
3
              compression=BC5Compression;
3008
3
              decoder=ReadBC5;
3009
3
              break;
3010
0
            }
3011
367
            case DXGI_FORMAT_BC7_UNORM:
3012
591
            case DXGI_FORMAT_BC7_UNORM_SRGB:
3013
591
            {
3014
591
              alpha_trait=BlendPixelTrait;
3015
591
              compression=BC7Compression;
3016
591
              decoder=ReadBC7;
3017
591
              break;
3018
367
            }
3019
3
            default:
3020
3
            {
3021
              /* Unknown format */
3022
3
              ThrowReaderException(ImageError,"ImageTypeNotSupported");
3023
0
            }
3024
663
          }
3025
3026
660
          if (dds_info.extFlags & DDSEXTFLAGS_CUBEMAP)
3027
290
            cubemap=MagickTrue;
3028
3029
660
          num_images=dds_info.extArraySize;
3030
660
          break;
3031
663
        }
3032
840
        default:
3033
840
        {
3034
          /* Unknown FOURCC */
3035
840
          ThrowReaderException(ImageError,"ImageTypeNotSupported");
3036
0
        }
3037
3.62k
      }
3038
3.62k
    }
3039
4
  else
3040
4
    {
3041
      /* Neither compressed nor uncompressed... thus unsupported */
3042
4
      ThrowReaderException(ImageError,"ImageTypeNotSupported");
3043
0
    }
3044
  
3045
7.92k
  num_images = 1;
3046
7.92k
  if (cubemap)
3047
2.52k
    {
3048
      /*
3049
        Determine number of faces defined in the cubemap
3050
      */
3051
2.52k
      num_images = 0;
3052
2.52k
      if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_POSITIVEX) num_images++;
3053
2.52k
      if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) num_images++;
3054
2.52k
      if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_POSITIVEY) num_images++;
3055
2.52k
      if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) num_images++;
3056
2.52k
      if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) num_images++;
3057
2.52k
      if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) num_images++;
3058
2.52k
    }
3059
  
3060
7.92k
  if (volume)
3061
2.03k
    num_images = dds_info.depth;
3062
3063
7.92k
  if ((num_images == 0) || (num_images > GetBlobSize(image)))
3064
7.77k
    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3065
3066
7.77k
  if (AcquireMagickResource(ListLengthResource,num_images) == MagickFalse)
3067
7.72k
    ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
3068
3069
7.72k
  option=GetImageOption(image_info,"dds:skip-mipmaps");
3070
7.72k
  if (IsStringFalse(option) != MagickFalse)
3071
0
    read_mipmaps=MagickTrue;
3072
3073
15.9k
  for (n = 0; n < num_images; n++)
3074
15.3k
  {
3075
15.3k
    if (n != 0)
3076
7.61k
      {
3077
        /* Start a new image */
3078
7.61k
        if (EOFBlob(image) != MagickFalse)
3079
7.61k
          ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
3080
7.61k
        AcquireNextImage(image_info,image,exception);
3081
7.61k
        if (GetNextImageInList(image) == (Image *) NULL)
3082
0
          return(DestroyImageList(image));
3083
7.61k
        image=SyncNextImageInList(image);
3084
7.61k
      }
3085
    
3086
15.3k
    image->alpha_trait=alpha_trait;
3087
15.3k
    image->compression=compression;
3088
15.3k
    image->columns=dds_info.width;
3089
15.3k
    image->rows=dds_info.height;
3090
15.3k
    image->storage_class=DirectClass;
3091
15.3k
    image->endian=LSBEndian;
3092
15.3k
    image->depth=8;
3093
15.3k
    if (image_info->ping != MagickFalse)
3094
0
      continue;
3095
15.3k
    status=SetImageExtent(image,image->columns,image->rows,exception);
3096
15.3k
    if (status == MagickFalse)
3097
291
      return(DestroyImageList(image));
3098
15.0k
    (void) SetImageBackgroundColor(image,exception);
3099
15.0k
    status=(decoder)(image_info,image,&dds_info,read_mipmaps,exception);
3100
15.0k
    if (status == MagickFalse)
3101
6.85k
      {
3102
6.85k
        (void) CloseBlob(image);
3103
6.85k
        if (n == 0)
3104
4.70k
          return(DestroyImageList(image));
3105
2.15k
        return(GetFirstImageInList(image));
3106
6.85k
      }
3107
15.0k
  }
3108
581
  if (CloseBlob(image) == MagickFalse)
3109
0
    status=MagickFalse;
3110
581
  if (status == MagickFalse)
3111
0
    return(DestroyImageList(image));
3112
581
  return(GetFirstImageInList(image));
3113
581
}
3114

3115
/*
3116
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3117
%                                                                             %
3118
%                                                                             %
3119
%                                                                             %
3120
%   R e g i s t e r D D S I m a g e                                           %
3121
%                                                                             %
3122
%                                                                             %
3123
%                                                                             %
3124
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3125
%
3126
%  RegisterDDSImage() adds attributes for the DDS image format to
3127
%  the list of supported formats.  The attributes include the image format
3128
%  tag, a method to read and/or write the format, whether the format
3129
%  supports the saving of more than one frame to the same file or blob,
3130
%  whether the format supports native in-memory I/O, and a brief
3131
%  description of the format.
3132
%
3133
%  The format of the RegisterDDSImage method is:
3134
%
3135
%      RegisterDDSImage(void)
3136
%
3137
*/
3138
ModuleExport size_t RegisterDDSImage(void)
3139
12
{
3140
12
  MagickInfo
3141
12
    *entry;
3142
3143
12
  entry = AcquireMagickInfo("DDS","DDS","Microsoft DirectDraw Surface");
3144
12
  entry->decoder = (DecodeImageHandler *) ReadDDSImage;
3145
12
  entry->encoder = (EncodeImageHandler *) WriteDDSImage;
3146
12
  entry->magick = (IsImageFormatHandler *) IsDDS;
3147
12
  entry->flags|=CoderDecoderSeekableStreamFlag;
3148
12
  (void) RegisterMagickInfo(entry);
3149
12
  entry = AcquireMagickInfo("DDS","DXT1","Microsoft DirectDraw Surface");
3150
12
  entry->decoder = (DecodeImageHandler *) ReadDDSImage;
3151
12
  entry->encoder = (EncodeImageHandler *) WriteDDSImage;
3152
12
  entry->magick = (IsImageFormatHandler *) IsDDS;
3153
12
  entry->flags|=CoderDecoderSeekableStreamFlag;
3154
12
  (void) RegisterMagickInfo(entry);
3155
12
  entry = AcquireMagickInfo("DDS","DXT5","Microsoft DirectDraw Surface");
3156
12
  entry->decoder = (DecodeImageHandler *) ReadDDSImage;
3157
12
  entry->encoder = (EncodeImageHandler *) WriteDDSImage;
3158
12
  entry->magick = (IsImageFormatHandler *) IsDDS;
3159
12
  entry->flags|=CoderDecoderSeekableStreamFlag;
3160
12
  (void) RegisterMagickInfo(entry);
3161
12
  return(MagickImageCoderSignature);
3162
12
}
3163
3164
static void RemapIndices(const ssize_t *map, const unsigned char *source,
3165
  unsigned char *target)
3166
133k
{
3167
133k
  ssize_t
3168
133k
    i;
3169
3170
2.26M
  for (i = 0; i < 16; i++)
3171
2.13M
  {
3172
2.13M
    if (map[i] == -1)
3173
1.17M
      target[i] = 3;
3174
958k
    else
3175
958k
      target[i] = source[map[i]];
3176
2.13M
  }
3177
133k
}
3178

3179
/*
3180
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3181
%                                                                             %
3182
%                                                                             %
3183
%                                                                             %
3184
%   U n r e g i s t e r D D S I m a g e                                       %
3185
%                                                                             %
3186
%                                                                             %
3187
%                                                                             %
3188
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3189
%
3190
%  UnregisterDDSImage() removes format registrations made by the
3191
%  DDS module from the list of supported formats.
3192
%
3193
%  The format of the UnregisterDDSImage method is:
3194
%
3195
%      UnregisterDDSImage(void)
3196
%
3197
*/
3198
ModuleExport void UnregisterDDSImage(void)
3199
0
{
3200
0
  (void) UnregisterMagickInfo("DDS");
3201
0
  (void) UnregisterMagickInfo("DXT1");
3202
0
  (void) UnregisterMagickInfo("DXT5");
3203
0
}
3204
3205
/*
3206
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3207
%                                                                             %
3208
%                                                                             %
3209
%                                                                             %
3210
%   W r i t e D D S I m a g e                                                 %
3211
%                                                                             %
3212
%                                                                             %
3213
%                                                                             %
3214
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3215
%
3216
%  WriteDDSImage() writes a DirectDraw Surface image file in the DXT5 format.
3217
%
3218
%  The format of the WriteDDSImage method is:
3219
%
3220
%     MagickBooleanType WriteDDSImage(const ImageInfo *image_info,Image *image)
3221
%
3222
%  A description of each parameter follows.
3223
%
3224
%    o image_info: the image info.
3225
%
3226
%    o image:  The image.
3227
%
3228
*/
3229
3230
static size_t CompressAlpha(const size_t min, const size_t max,
3231
  const size_t steps, const ssize_t *alphas, unsigned char* indices)
3232
118k
{
3233
118k
  unsigned char
3234
118k
    codes[8];
3235
3236
118k
  size_t
3237
118k
    error,
3238
118k
    index,
3239
118k
    j,
3240
118k
    least,
3241
118k
    value;
3242
3243
118k
  ssize_t
3244
118k
    i;
3245
3246
118k
  codes[0] = (unsigned char) min;
3247
118k
  codes[1] = (unsigned char) max;
3248
118k
  codes[6] = 0;
3249
118k
  codes[7] = 255;
3250
3251
711k
  for (i=1; i <  (ssize_t) steps; i++)
3252
592k
    codes[i+1] = (unsigned char) ((((ssize_t) steps-i)*(ssize_t) min +
3253
592k
      i*(ssize_t) max) / (ssize_t) steps);
3254
3255
118k
  error = 0;
3256
2.01M
  for (i=0; i<16; i++)
3257
1.89M
  {
3258
1.89M
    if (alphas[i] == -1)
3259
886k
      {
3260
886k
        indices[i] = 0;
3261
886k
        continue;
3262
886k
      }
3263
3264
1.01M
    value = (size_t) alphas[i];
3265
1.01M
    least = SIZE_MAX;
3266
1.01M
    index = 0;
3267
9.09M
    for (j=0; j<8; j++)
3268
8.08M
    {
3269
8.08M
      size_t
3270
8.08M
        dist;
3271
3272
8.08M
      dist = value - (size_t)codes[j];
3273
8.08M
      dist *= dist;
3274
3275
8.08M
      if (dist < least)
3276
2.15M
        {
3277
2.15M
          least = dist;
3278
2.15M
          index = j;
3279
2.15M
        }
3280
8.08M
    }
3281
3282
1.01M
    indices[i] = (unsigned char)index;
3283
1.01M
    error += least;
3284
1.01M
  }
3285
3286
118k
  return error;
3287
118k
}
3288
3289
static MagickBooleanType ConstructOrdering(const size_t count,
3290
  const DDSVector4 *points, const DDSVector3 axis, DDSVector4 *pointsWeights,
3291
  DDSVector4 *xSumwSum, unsigned char *order, size_t iteration)
3292
0
{
3293
0
  float
3294
0
     dps[16],
3295
0
     f;
3296
3297
0
  ssize_t
3298
0
    i,
3299
0
    j;
3300
3301
0
  unsigned char
3302
0
    c,
3303
0
    *o,
3304
0
    *p;
3305
3306
0
  o = order + (16*iteration);
3307
3308
0
  for (i=0; i < (ssize_t) count; i++)
3309
0
  {
3310
0
    dps[i] = Dot(points[i],axis);
3311
0
    o[i] = (unsigned char)i;
3312
0
  }
3313
3314
0
  for (i=0; i < (ssize_t) count; i++)
3315
0
  {
3316
0
    for (j=i; j > 0 && dps[j] < dps[j - 1]; j--)
3317
0
    {
3318
0
      f = dps[j];
3319
0
      dps[j] = dps[j - 1];
3320
0
      dps[j - 1] = f;
3321
3322
0
      c = o[j];
3323
0
      o[j] = o[j - 1];
3324
0
      o[j - 1] = c;
3325
0
    }
3326
0
  }
3327
3328
0
  for (i=0; i < (ssize_t) iteration; i++)
3329
0
  {
3330
0
    MagickBooleanType
3331
0
      same;
3332
3333
0
    p = order + (16*i);
3334
0
    same = MagickTrue;
3335
3336
0
    for (j=0; j < (ssize_t) count; j++)
3337
0
    {
3338
0
      if (o[j] != p[j])
3339
0
        {
3340
0
          same = MagickFalse;
3341
0
          break;
3342
0
        }
3343
0
    }
3344
3345
0
    if (same != MagickFalse)
3346
0
      return MagickFalse;
3347
0
  }
3348
3349
0
  xSumwSum->x = 0;
3350
0
  xSumwSum->y = 0;
3351
0
  xSumwSum->z = 0;
3352
0
  xSumwSum->w = 0;
3353
3354
0
  for (i=0; i < (ssize_t) count; i++)
3355
0
  {
3356
0
    DDSVector4
3357
0
      v;
3358
3359
0
    j = (ssize_t) o[i];
3360
3361
0
    v.x = points[j].w * points[j].x;
3362
0
    v.y = points[j].w * points[j].y;
3363
0
    v.z = points[j].w * points[j].z;
3364
0
    v.w = points[j].w * 1.0f;
3365
3366
0
    VectorCopy44(v,&pointsWeights[i]);
3367
0
    VectorAdd(*xSumwSum,v,xSumwSum);
3368
0
  }
3369
3370
0
  return MagickTrue;
3371
0
}
3372
3373
static void CompressClusterFit(const size_t count,
3374
  const DDSVector4 *points, const ssize_t *map, const DDSVector3 principle,
3375
  const DDSVector4 metric, DDSVector3 *start, DDSVector3* end,
3376
  unsigned char *indices)
3377
0
{
3378
0
  DDSVector3
3379
0
    axis;
3380
3381
0
  DDSVector4
3382
0
    grid,
3383
0
    gridrcp,
3384
0
    half,
3385
0
    onethird_onethird2,
3386
0
    pointsWeights[16],
3387
0
    two,
3388
0
    twonineths,
3389
0
    twothirds_twothirds2,
3390
0
    xSumwSum;
3391
3392
0
  float
3393
0
    bestError = 1e+37f;
3394
3395
0
  size_t
3396
0
    bestIteration = 0,
3397
0
    iterationIndex;
3398
3399
0
  ssize_t
3400
0
    besti = 0,
3401
0
    bestj = 0,
3402
0
    bestk = 0,
3403
0
    i;
3404
3405
0
  unsigned char
3406
0
    *o,
3407
0
    order[128],
3408
0
    unordered[16];
3409
3410
0
  VectorInit(half,0.5f);
3411
0
  VectorInit(two,2.0f);
3412
3413
0
  VectorInit(onethird_onethird2,1.0f/3.0f);
3414
0
  onethird_onethird2.w = 1.0f/9.0f;
3415
0
  VectorInit(twothirds_twothirds2,2.0f/3.0f);
3416
0
  twothirds_twothirds2.w = 4.0f/9.0f;
3417
0
  VectorInit(twonineths,2.0f/9.0f);
3418
3419
0
  grid.x = 31.0f;
3420
0
  grid.y = 63.0f;
3421
0
  grid.z = 31.0f;
3422
0
  grid.w = 0.0f;
3423
3424
0
  gridrcp.x = 1.0f/31.0f;
3425
0
  gridrcp.y = 1.0f/63.0f;
3426
0
  gridrcp.z = 1.0f/31.0f;
3427
0
  gridrcp.w = 0.0f;
3428
3429
0
  xSumwSum.x = 0.0f;
3430
0
  xSumwSum.y = 0.0f;
3431
0
  xSumwSum.z = 0.0f;
3432
0
  xSumwSum.w = 0.0f;
3433
3434
0
  ConstructOrdering(count,points,principle,pointsWeights,&xSumwSum,order,0);
3435
3436
0
  for (iterationIndex = 0;;)
3437
0
  {
3438
#if defined(MAGICKCORE_OPENMP_SUPPORT)
3439
  #pragma omp parallel for schedule(dynamic,1) \
3440
    num_threads((int) GetMagickResourceLimit(ThreadResource))
3441
#endif
3442
0
    for (i=0; i < (ssize_t) count; i++)
3443
0
    {
3444
0
      DDSVector4
3445
0
        part0,
3446
0
        part1,
3447
0
        part2;
3448
3449
0
      ssize_t
3450
0
        ii,
3451
0
        j,
3452
0
        k,
3453
0
        kmin;
3454
3455
0
      VectorInit(part0,0.0f);
3456
0
      for (ii=0; ii < i; ii++)
3457
0
        VectorAdd(pointsWeights[ii],part0,&part0);
3458
3459
0
      VectorInit(part1,0.0f);
3460
0
      for (j=i; ; )
3461
0
      {
3462
0
        if (j == 0)
3463
0
          {
3464
0
            VectorCopy44(pointsWeights[0],&part2);
3465
0
            kmin = 1;
3466
0
          }
3467
0
          else
3468
0
          {
3469
0
            VectorInit(part2,0.0f);
3470
0
            kmin = j;
3471
0
          }
3472
3473
0
        for (k=kmin;;)
3474
0
        {
3475
0
          DDSVector4
3476
0
            a,
3477
0
            alpha2_sum,
3478
0
            alphax_sum,
3479
0
            alphabeta_sum,
3480
0
            b,
3481
0
            beta2_sum,
3482
0
            betax_sum,
3483
0
            e1,
3484
0
            e2,
3485
0
            factor,
3486
0
            part3;
3487
3488
0
          float
3489
0
            error;
3490
3491
0
          VectorSubtract(xSumwSum,part2,&part3);
3492
0
          VectorSubtract(part3,part1,&part3);
3493
0
          VectorSubtract(part3,part0,&part3);
3494
3495
0
          VectorMultiplyAdd(part1,twothirds_twothirds2,part0,&alphax_sum);
3496
0
          VectorMultiplyAdd(part2,onethird_onethird2,alphax_sum,&alphax_sum);
3497
0
          VectorInit(alpha2_sum,alphax_sum.w);
3498
3499
0
          VectorMultiplyAdd(part2,twothirds_twothirds2,part3,&betax_sum);
3500
0
          VectorMultiplyAdd(part1,onethird_onethird2,betax_sum,&betax_sum);
3501
0
          VectorInit(beta2_sum,betax_sum.w);
3502
3503
0
          VectorAdd(part1,part2,&alphabeta_sum);
3504
0
          VectorInit(alphabeta_sum,alphabeta_sum.w);
3505
0
          VectorMultiply(twonineths,alphabeta_sum,&alphabeta_sum);
3506
3507
0
          VectorMultiply(alpha2_sum,beta2_sum,&factor);
3508
0
          VectorNegativeMultiplySubtract(alphabeta_sum,alphabeta_sum,factor,
3509
0
            &factor);
3510
0
          VectorReciprocal(factor,&factor);
3511
3512
0
          VectorMultiply(alphax_sum,beta2_sum,&a);
3513
0
          VectorNegativeMultiplySubtract(betax_sum,alphabeta_sum,a,&a);
3514
0
          VectorMultiply(a,factor,&a);
3515
3516
0
          VectorMultiply(betax_sum,alpha2_sum,&b);
3517
0
          VectorNegativeMultiplySubtract(alphax_sum,alphabeta_sum,b,&b);
3518
0
          VectorMultiply(b,factor,&b);
3519
3520
0
          VectorClamp(&a);
3521
0
          VectorMultiplyAdd(grid,a,half,&a);
3522
0
          VectorTruncate(&a);
3523
0
          VectorMultiply(a,gridrcp,&a);
3524
3525
0
          VectorClamp(&b);
3526
0
          VectorMultiplyAdd(grid,b,half,&b);
3527
0
          VectorTruncate(&b);
3528
0
          VectorMultiply(b,gridrcp,&b);
3529
3530
0
          VectorMultiply(b,b,&e1);
3531
0
          VectorMultiply(e1,beta2_sum,&e1);
3532
0
          VectorMultiply(a,a,&e2);
3533
0
          VectorMultiplyAdd(e2,alpha2_sum,e1,&e1);
3534
3535
0
          VectorMultiply(a,b,&e2);
3536
0
          VectorMultiply(e2,alphabeta_sum,&e2);
3537
0
          VectorNegativeMultiplySubtract(a,alphax_sum,e2,&e2);
3538
0
          VectorNegativeMultiplySubtract(b,betax_sum,e2,&e2);
3539
0
          VectorMultiplyAdd(two,e2,e1,&e2);
3540
0
          VectorMultiply(e2,metric,&e2);
3541
3542
0
          error = e2.x + e2.y + e2.z;
3543
3544
0
          if (error < bestError)
3545
0
            {
3546
#if defined(MAGICKCORE_OPENMP_SUPPORT)
3547
              #pragma omp critical (DDS_CompressClusterFit)
3548
#endif
3549
0
              {
3550
0
                if (error < bestError)
3551
0
                  {
3552
0
                    VectorCopy43(a,start);
3553
0
                    VectorCopy43(b,end);
3554
0
                    bestError = error;
3555
0
                    besti = i;
3556
0
                    bestj = j;
3557
0
                    bestk = k;
3558
0
                    bestIteration = iterationIndex;
3559
0
                  }
3560
0
              }
3561
0
            }
3562
3563
0
          if (k == (ssize_t) count)
3564
0
            break;
3565
3566
0
          VectorAdd(pointsWeights[k],part2,&part2);
3567
0
          k++;
3568
0
        }
3569
3570
0
        if (j == (ssize_t) count)
3571
0
          break;
3572
3573
0
        VectorAdd(pointsWeights[j],part1,&part1);
3574
0
        j++;
3575
0
      }
3576
0
    }
3577
3578
0
    if (bestIteration != iterationIndex)
3579
0
      break;
3580
3581
0
    iterationIndex++;
3582
0
    if (iterationIndex == 8)
3583
0
      break;
3584
3585
0
    VectorSubtract3(*end,*start,&axis);
3586
0
    if (ConstructOrdering(count,points,axis,pointsWeights,&xSumwSum,order,
3587
0
      iterationIndex) == MagickFalse)
3588
0
      break;
3589
0
  }
3590
3591
0
  o = order + (16*bestIteration);
3592
3593
0
  for (i=0; i < (ssize_t) besti; i++)
3594
0
    unordered[o[i]] = 0;
3595
0
  for (i=besti; i < (ssize_t) bestj; i++)
3596
0
    unordered[o[i]] = 2;
3597
0
  for (i=bestj; i < (ssize_t) bestk; i++)
3598
0
    unordered[o[i]] = 3;
3599
0
  for (i=bestk; i < (ssize_t) count; i++)
3600
0
    unordered[o[i]] = 1;
3601
3602
0
  RemapIndices(map,unordered,indices);
3603
0
}
3604
3605
static void CompressRangeFit(const size_t count,
3606
  const DDSVector4* points, const ssize_t *map, const DDSVector3 principle,
3607
  const DDSVector4 metric, DDSVector3 *start, DDSVector3 *end,
3608
  unsigned char *indices)
3609
71.7k
{
3610
71.7k
  float
3611
71.7k
    d,
3612
71.7k
    bestDist,
3613
71.7k
    max,
3614
71.7k
    min,
3615
71.7k
    val;
3616
3617
71.7k
  DDSVector3
3618
71.7k
    codes[4],
3619
71.7k
    grid,
3620
71.7k
    gridrcp,
3621
71.7k
    half,
3622
71.7k
    dist;
3623
3624
71.7k
  ssize_t
3625
71.7k
    i;
3626
3627
71.7k
  size_t
3628
71.7k
    bestj,
3629
71.7k
    j;
3630
3631
71.7k
  unsigned char
3632
71.7k
    closest[16];
3633
3634
71.7k
  VectorInit3(half,0.5f);
3635
3636
71.7k
  grid.x = 31.0f;
3637
71.7k
  grid.y = 63.0f;
3638
71.7k
  grid.z = 31.0f;
3639
3640
71.7k
  gridrcp.x = 1.0f/31.0f;
3641
71.7k
  gridrcp.y = 1.0f/63.0f;
3642
71.7k
  gridrcp.z = 1.0f/31.0f;
3643
3644
71.7k
  if (count > 0)
3645
71.7k
    {
3646
71.7k
      VectorCopy43(points[0],start);
3647
71.7k
      VectorCopy43(points[0],end);
3648
3649
71.7k
      min = max = Dot(points[0],principle);
3650
255k
      for (i=1; i < (ssize_t) count; i++)
3651
183k
      {
3652
183k
        val = Dot(points[i],principle);
3653
183k
        if (val < min)
3654
67.0k
        {
3655
67.0k
          VectorCopy43(points[i],start);
3656
67.0k
          min = val;
3657
67.0k
        }
3658
116k
        else if (val > max)
3659
64.2k
        {
3660
64.2k
          VectorCopy43(points[i],end);
3661
64.2k
          max = val;
3662
64.2k
        }
3663
183k
      }
3664
71.7k
    }
3665
3666
71.7k
  VectorClamp3(start);
3667
71.7k
  VectorMultiplyAdd3(grid,*start,half,start);
3668
71.7k
  VectorTruncate3(start);
3669
71.7k
  VectorMultiply3(*start,gridrcp,start);
3670
3671
71.7k
  VectorClamp3(end);
3672
71.7k
  VectorMultiplyAdd3(grid,*end,half,end);
3673
71.7k
  VectorTruncate3(end);
3674
71.7k
  VectorMultiply3(*end,gridrcp,end);
3675
3676
71.7k
  codes[0] = *start;
3677
71.7k
  codes[1] = *end;
3678
71.7k
  codes[2].x = (start->x * (2.0f/3.0f)) + (end->x * (1.0f/3.0f));
3679
71.7k
  codes[2].y = (start->y * (2.0f/3.0f)) + (end->y * (1.0f/3.0f));
3680
71.7k
  codes[2].z = (start->z * (2.0f/3.0f)) + (end->z * (1.0f/3.0f));
3681
71.7k
  codes[3].x = (start->x * (1.0f/3.0f)) + (end->x * (2.0f/3.0f));
3682
71.7k
  codes[3].y = (start->y * (1.0f/3.0f)) + (end->y * (2.0f/3.0f));
3683
71.7k
  codes[3].z = (start->z * (1.0f/3.0f)) + (end->z * (2.0f/3.0f));
3684
3685
326k
  for (i=0; i < (ssize_t) count; i++)
3686
255k
  {
3687
255k
    bestDist = 1e+37f;
3688
255k
    bestj = 0;
3689
1.27M
    for (j=0; j < 4; j++)
3690
1.02M
    {
3691
1.02M
      dist.x = (points[i].x - codes[j].x) * metric.x;
3692
1.02M
      dist.y = (points[i].y - codes[j].y) * metric.y;
3693
1.02M
      dist.z = (points[i].z - codes[j].z) * metric.z;
3694
3695
1.02M
      d = Dot(dist,dist);
3696
1.02M
      if (d < bestDist)
3697
464k
        {
3698
464k
          bestDist = d;
3699
464k
          bestj = j;
3700
464k
        }
3701
1.02M
    }
3702
3703
255k
    closest[i] = (unsigned char) bestj;
3704
255k
  }
3705
3706
71.7k
  RemapIndices(map, closest, indices);
3707
71.7k
}
3708
3709
static void ComputeEndPoints(const DDSSingleColorLookup *lookup[],
3710
  const unsigned char *color, DDSVector3 *start, DDSVector3 *end,
3711
  unsigned char *index)
3712
61.6k
{
3713
61.6k
  ssize_t
3714
61.6k
    i;
3715
3716
61.6k
  size_t
3717
61.6k
    c,
3718
61.6k
    maxError = SIZE_MAX;
3719
3720
185k
  for (i=0; i < 2; i++)
3721
123k
  {
3722
123k
    const DDSSourceBlock*
3723
123k
      sources[3];
3724
3725
123k
      size_t
3726
123k
        error = 0;
3727
3728
493k
    for (c=0; c < 3; c++)
3729
370k
    {
3730
370k
      sources[c] = &lookup[c][color[c]].sources[i];
3731
370k
      error += ((size_t) sources[c]->error) * ((size_t) sources[c]->error);
3732
370k
    }
3733
3734
123k
    if (error > maxError)
3735
0
      continue;
3736
3737
123k
    start->x = (float) sources[0]->start / 31.0f;
3738
123k
    start->y = (float) sources[1]->start / 63.0f;
3739
123k
    start->z = (float) sources[2]->start / 31.0f;
3740
3741
123k
    end->x = (float) sources[0]->end / 31.0f;
3742
123k
    end->y = (float) sources[1]->end / 63.0f;
3743
123k
    end->z = (float) sources[2]->end / 31.0f;
3744
3745
123k
    *index = (unsigned char) (2*i);
3746
123k
    maxError = error;
3747
123k
  }
3748
61.6k
}
3749
3750
static void ComputePrincipleComponent(const float *covariance,
3751
  DDSVector3 *principle)
3752
71.7k
{
3753
71.7k
  DDSVector4
3754
71.7k
    row0,
3755
71.7k
    row1,
3756
71.7k
    row2,
3757
71.7k
    v;
3758
3759
71.7k
  ssize_t
3760
71.7k
    i;
3761
3762
71.7k
  row0.x = covariance[0];
3763
71.7k
  row0.y = covariance[1];
3764
71.7k
  row0.z = covariance[2];
3765
71.7k
  row0.w = 0.0f;
3766
3767
71.7k
  row1.x = covariance[1];
3768
71.7k
  row1.y = covariance[3];
3769
71.7k
  row1.z = covariance[4];
3770
71.7k
  row1.w = 0.0f;
3771
3772
71.7k
  row2.x = covariance[2];
3773
71.7k
  row2.y = covariance[4];
3774
71.7k
  row2.z = covariance[5];
3775
71.7k
  row2.w = 0.0f;
3776
3777
71.7k
  VectorInit(v,1.0f);
3778
3779
645k
  for (i=0; i < 8; i++)
3780
573k
  {
3781
573k
    DDSVector4
3782
573k
      w;
3783
3784
573k
    float
3785
573k
      a;
3786
3787
573k
    w.x = row0.x * v.x;
3788
573k
    w.y = row0.y * v.x;
3789
573k
    w.z = row0.z * v.x;
3790
573k
    w.w = row0.w * v.x;
3791
3792
573k
    w.x = (row1.x * v.y) + w.x;
3793
573k
    w.y = (row1.y * v.y) + w.y;
3794
573k
    w.z = (row1.z * v.y) + w.z;
3795
573k
    w.w = (row1.w * v.y) + w.w;
3796
3797
573k
    w.x = (row2.x * v.z) + w.x;
3798
573k
    w.y = (row2.y * v.z) + w.y;
3799
573k
    w.z = (row2.z * v.z) + w.z;
3800
573k
    w.w = (row2.w * v.z) + w.w;
3801
3802
573k
    a = (float) MagickSafeReciprocal(MagickMax(w.x,MagickMax(w.y,w.z)));
3803
3804
573k
    v.x = w.x * a;
3805
573k
    v.y = w.y * a;
3806
573k
    v.z = w.z * a;
3807
573k
    v.w = w.w * a;
3808
573k
  }
3809
3810
71.7k
  VectorCopy43(v,principle);
3811
71.7k
}
3812
3813
static void ComputeWeightedCovariance(const size_t count,
3814
  const DDSVector4 *points, float *covariance)
3815
71.7k
{
3816
71.7k
  DDSVector3
3817
71.7k
    centroid;
3818
3819
71.7k
  float
3820
71.7k
    total;
3821
3822
71.7k
  size_t
3823
71.7k
    i;
3824
3825
71.7k
  total = 0.0f;
3826
71.7k
  VectorInit3(centroid,0.0f);
3827
3828
326k
  for (i=0; i < count; i++)
3829
255k
  {
3830
255k
    total += points[i].w;
3831
255k
    centroid.x += (points[i].x * points[i].w);
3832
255k
    centroid.y += (points[i].y * points[i].w);
3833
255k
    centroid.z += (points[i].z * points[i].w);
3834
255k
  }
3835
3836
71.7k
  if( total > 1.192092896e-07F)
3837
71.7k
    {
3838
71.7k
      centroid.x /= total;
3839
71.7k
      centroid.y /= total;
3840
71.7k
      centroid.z /= total;
3841
71.7k
    }
3842
3843
501k
  for (i=0; i < 6; i++)
3844
430k
    covariance[i] = 0.0f;
3845
3846
326k
  for (i = 0; i < count; i++)
3847
255k
  {
3848
255k
    DDSVector3
3849
255k
      a,
3850
255k
      b;
3851
3852
255k
    a.x = points[i].x - centroid.x;
3853
255k
    a.y = points[i].y - centroid.y;
3854
255k
    a.z = points[i].z - centroid.z;
3855
3856
255k
    b.x = points[i].w * a.x;
3857
255k
    b.y = points[i].w * a.y;
3858
255k
    b.z = points[i].w * a.z;
3859
3860
255k
    covariance[0] += a.x*b.x;
3861
255k
    covariance[1] += a.x*b.y;
3862
255k
    covariance[2] += a.x*b.z;
3863
255k
    covariance[3] += a.y*b.y;
3864
255k
    covariance[4] += a.y*b.z;
3865
255k
    covariance[5] += a.z*b.z;
3866
255k
  }
3867
71.7k
}
3868
3869
static void WriteAlphas(Image *image, const ssize_t *alphas, size_t min5,
3870
  size_t max5, size_t min7, size_t max7)
3871
59.2k
{
3872
59.2k
  size_t
3873
59.2k
    err5,
3874
59.2k
    err7;
3875
3876
59.2k
  ssize_t
3877
59.2k
    i,
3878
59.2k
    j;
3879
3880
59.2k
  unsigned char
3881
59.2k
    indices5[16],
3882
59.2k
    indices7[16];
3883
3884
59.2k
  FixRange(min5,max5,5);
3885
59.2k
  err5 = CompressAlpha(min5,max5,5,alphas,indices5);
3886
3887
59.2k
  FixRange(min7,max7,7);
3888
59.2k
  err7 = CompressAlpha(min7,max7,7,alphas,indices7);
3889
3890
59.2k
  if (err7 < err5)
3891
8.30k
  {
3892
141k
    for (i=0; i < 16; i++)
3893
132k
    {
3894
132k
      unsigned char
3895
132k
        index;
3896
3897
132k
      index = indices7[i];
3898
132k
      if( index == 0 )
3899
95.5k
        indices5[i] = 1;
3900
37.2k
      else if (index == 1)
3901
14.7k
        indices5[i] = 0;
3902
22.4k
      else
3903
22.4k
        indices5[i] = 9 - index;
3904
132k
    }
3905
3906
8.30k
    min5 = max7;
3907
8.30k
    max5 = min7;
3908
8.30k
  }
3909
  
3910
59.2k
  (void) WriteBlobByte(image,(unsigned char) min5);
3911
59.2k
  (void) WriteBlobByte(image,(unsigned char) max5);
3912
  
3913
177k
  for(i=0; i < 2; i++)
3914
118k
  {
3915
118k
    size_t
3916
118k
      value = 0;
3917
3918
1.06M
    for (j=0; j < 8; j++)
3919
948k
    {
3920
948k
      size_t index = (size_t) indices5[j + i*8];
3921
948k
      value |= ( index << 3*j );
3922
948k
    }
3923
3924
474k
    for (j=0; j < 3; j++)
3925
355k
    {
3926
355k
      size_t byte = (value >> 8*j) & 0xff;
3927
355k
      (void) WriteBlobByte(image,(unsigned char) byte);
3928
355k
    }
3929
118k
  }
3930
59.2k
}
3931
3932
static void WriteIndices(Image *image, const DDSVector3 start,
3933
  const DDSVector3 end, unsigned char *indices)
3934
133k
{
3935
133k
  ssize_t
3936
133k
    i;
3937
3938
133k
  size_t
3939
133k
    a,
3940
133k
    b;
3941
3942
133k
  unsigned char
3943
133k
    remapped[16];
3944
3945
133k
  const unsigned char
3946
133k
    *ind;
3947
3948
133k
  a = ColorTo565(start);
3949
133k
  b = ColorTo565(end);
3950
3951
2.26M
  for (i=0; i<16; i++)
3952
2.13M
  {
3953
2.13M
    if( a < b )
3954
1.34M
      remapped[i] = (indices[i] ^ 0x1) & 0x3;
3955
784k
    else if( a == b )
3956
695k
      remapped[i] = 0;
3957
89.4k
    else
3958
89.4k
      remapped[i] = indices[i];
3959
2.13M
  }
3960
3961
133k
  if( a < b )
3962
84.3k
    Swap(a,b);
3963
3964
133k
  (void) WriteBlobByte(image,(unsigned char) (a & 0xff));
3965
133k
  (void) WriteBlobByte(image,(unsigned char) (a >> 8));
3966
133k
  (void) WriteBlobByte(image,(unsigned char) (b & 0xff));
3967
133k
  (void) WriteBlobByte(image,(unsigned char) (b >> 8));
3968
3969
666k
  for (i=0; i<4; i++)
3970
533k
  {
3971
533k
     ind = remapped + 4*i;
3972
533k
     (void) WriteBlobByte(image,ind[0] | (ind[1] << 2) | (ind[2] << 4) |
3973
533k
       (ind[3] << 6));
3974
533k
  }
3975
133k
}
3976
3977
static void WriteCompressed(Image *image, const size_t count,
3978
  DDSVector4 *points, const ssize_t *map, const MagickBooleanType clusterFit)
3979
71.7k
{
3980
71.7k
  float
3981
71.7k
    covariance[16];
3982
3983
71.7k
  DDSVector3
3984
71.7k
    end,
3985
71.7k
    principle,
3986
71.7k
    start;
3987
3988
71.7k
  DDSVector4
3989
71.7k
    metric;
3990
3991
71.7k
  unsigned char
3992
71.7k
    indices[16];
3993
3994
71.7k
  VectorInit(metric,1.0f);
3995
71.7k
  VectorInit3(start,0.0f);
3996
71.7k
  VectorInit3(end,0.0f);
3997
3998
71.7k
  ComputeWeightedCovariance(count,points,covariance);
3999
71.7k
  ComputePrincipleComponent(covariance,&principle);
4000
4001
71.7k
  if ((clusterFit == MagickFalse) || (count == 0))
4002
71.7k
    CompressRangeFit(count,points,map,principle,metric,&start,&end,indices);
4003
0
  else
4004
0
    CompressClusterFit(count,points,map,principle,metric,&start,&end,indices);
4005
4006
71.7k
  WriteIndices(image,start,end,indices);
4007
71.7k
}
4008
4009
static void WriteSingleColorFit(Image *image, const DDSVector4 *points,
4010
  const ssize_t *map)
4011
61.6k
{
4012
61.6k
  DDSVector3
4013
61.6k
    start,
4014
61.6k
    end;
4015
4016
61.6k
  ssize_t
4017
61.6k
    i;
4018
4019
61.6k
  unsigned char
4020
61.6k
    color[3],
4021
61.6k
    index,
4022
61.6k
    indexes[16],
4023
61.6k
    indices[16];
4024
4025
61.6k
  color[0] = (unsigned char) ClampToLimit(255.0f*points->x,255);
4026
61.6k
  color[1] = (unsigned char) ClampToLimit(255.0f*points->y,255);
4027
61.6k
  color[2] = (unsigned char) ClampToLimit(255.0f*points->z,255);
4028
4029
61.6k
  index=0;
4030
61.6k
  ComputeEndPoints(DDS_LOOKUP,color,&start,&end,&index);
4031
4032
1.04M
  for (i=0; i< 16; i++)
4033
986k
    indexes[i]=index;
4034
61.6k
  RemapIndices(map,indexes,indices);
4035
61.6k
  WriteIndices(image,start,end,indices);
4036
61.6k
}
4037
4038
static void WriteFourCC(Image *image, const size_t compression,
4039
  const MagickBooleanType clusterFit, const MagickBooleanType weightByAlpha,
4040
  ExceptionInfo *exception)
4041
6.90k
{
4042
6.90k
  ssize_t
4043
6.90k
    bx,
4044
6.90k
    by,
4045
6.90k
    i,
4046
6.90k
    y,
4047
6.90k
    x;
4048
4049
6.90k
  const Quantum
4050
6.90k
    *p;
4051
4052
66.7k
  for (y=0; y < (ssize_t) image->rows; y+=4)
4053
59.8k
  {
4054
193k
    for (x=0; x < (ssize_t) image->columns; x+=4)
4055
133k
    {
4056
133k
      MagickBooleanType
4057
133k
        match;
4058
4059
133k
      DDSVector4
4060
133k
        point,
4061
133k
        points[16] = { { 0, 0, 0, 0 } };
4062
4063
133k
      size_t
4064
133k
        count = 0,
4065
133k
        max5 = 0,
4066
133k
        max7 = 0,
4067
133k
        min5 = 255,
4068
133k
        min7 = 255,
4069
133k
        columns = 4,
4070
133k
        rows = 4;
4071
4072
133k
      ssize_t
4073
133k
        alphas[16],
4074
133k
        map[16];
4075
4076
133k
      unsigned char
4077
133k
        alpha;
4078
4079
133k
      if ((size_t) (x+(ssize_t) columns) >= image->columns)
4080
59.8k
        columns = (size_t) ((ssize_t) image->columns-x);
4081
4082
133k
      if ((size_t) (y+(ssize_t) rows) >= image->rows)
4083
68.0k
        rows = (size_t) ((ssize_t) image->rows-y);
4084
4085
133k
      p=GetVirtualPixels(image,x,y,columns,rows,exception);
4086
133k
      if (p == (const Quantum *) NULL)
4087
0
        break;
4088
4089
2.26M
      for (i=0; i<16; i++)
4090
2.13M
      {
4091
2.13M
        map[i] = -1;
4092
2.13M
        alphas[i] = -1;
4093
2.13M
      }
4094
4095
511k
      for (by=0; by < (ssize_t) rows; by++)
4096
378k
      {
4097
1.33M
        for (bx=0; bx < (ssize_t) columns; bx++)
4098
958k
        {
4099
958k
          if (compression == FOURCC_DXT5)
4100
505k
            alpha = ScaleQuantumToChar(GetPixelAlpha(image,p));
4101
453k
          else
4102
453k
            alpha = 255;
4103
4104
958k
          if (compression == FOURCC_DXT5)
4105
505k
            {
4106
505k
              if (alpha < min7)
4107
63.1k
                min7 = alpha;
4108
505k
              if (alpha > max7)
4109
73.1k
                max7 = alpha;
4110
505k
              if (alpha != 0 && alpha < min5)
4111
46.2k
                min5 = alpha;
4112
505k
              if (alpha != 255 && alpha > max5)
4113
44.7k
                max5 = alpha;
4114
505k
            }
4115
          
4116
958k
          alphas[4*by + bx] = (ssize_t)alpha;
4117
4118
958k
          point.x = (float)ScaleQuantumToChar(GetPixelRed(image,p)) / 255.0f;
4119
958k
          point.y = (float)ScaleQuantumToChar(GetPixelGreen(image,p)) / 255.0f;
4120
958k
          point.z = (float)ScaleQuantumToChar(GetPixelBlue(image,p)) / 255.0f;
4121
958k
          point.w = weightByAlpha ? (float)(alpha + 1) / 256.0f : 1.0f;
4122
958k
          p+=(ptrdiff_t) GetPixelChannels(image);
4123
4124
958k
          match = MagickFalse;
4125
1.67M
          for (i=0; i < (ssize_t) count; i++)
4126
1.36M
          {
4127
1.36M
            if ((points[i].x == point.x) &&
4128
724k
                (points[i].y == point.y) &&
4129
654k
                (points[i].z == point.z) &&
4130
642k
                (alpha       >= 128 || compression == FOURCC_DXT5))
4131
642k
              {
4132
642k
                points[i].w += point.w;
4133
642k
                map[4*by + bx] = i;
4134
642k
                match = MagickTrue;
4135
642k
                break;
4136
642k
              }
4137
1.36M
          }
4138
4139
958k
          if (match != MagickFalse)
4140
642k
            continue;
4141
4142
316k
          points[count].x = point.x;
4143
316k
          points[count].y = point.y;
4144
316k
          points[count].z = point.z;
4145
316k
          points[count].w = point.w;
4146
316k
          map[4*by + bx] = (ssize_t) count;
4147
316k
          count++;
4148
316k
        }
4149
378k
      }
4150
4151
450k
      for (i=0; i < (ssize_t) count; i++)
4152
316k
        points[i].w=sqrtf(points[i].w);
4153
4154
133k
      if (compression == FOURCC_DXT5)
4155
59.2k
        WriteAlphas(image,alphas,min5,max5,min7,max7);
4156
4157
133k
      if (count == 1)
4158
61.6k
        WriteSingleColorFit(image,points,map);
4159
71.7k
      else
4160
71.7k
        WriteCompressed(image,count,points,map,clusterFit);
4161
133k
    }
4162
59.8k
  }
4163
6.90k
}
4164
4165
static void WriteUncompressed(Image *image, ExceptionInfo *exception)
4166
0
{
4167
0
  const Quantum
4168
0
    *p;
4169
4170
0
  ssize_t
4171
0
    x;
4172
4173
0
  ssize_t
4174
0
    y;
4175
4176
0
  for (y=0; y < (ssize_t) image->rows; y++)
4177
0
  {
4178
0
    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
4179
0
    if (p == (const Quantum *) NULL)
4180
0
      break;
4181
4182
0
    for (x=0; x < (ssize_t) image->columns; x++)
4183
0
    {
4184
0
      (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelBlue(image,p)));
4185
0
      (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelGreen(image,p)));
4186
0
      (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelRed(image,p)));
4187
0
      if (image->alpha_trait != UndefinedPixelTrait)
4188
0
        (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelAlpha(image,p)));
4189
0
      p+=(ptrdiff_t) GetPixelChannels(image);
4190
0
    }
4191
0
  }
4192
0
}
4193
4194
static void WriteImageData(Image *image, const size_t pixelFormat,
4195
  const size_t compression,const MagickBooleanType clusterFit,
4196
  const MagickBooleanType weightByAlpha, ExceptionInfo *exception)
4197
6.90k
{
4198
6.90k
  if (pixelFormat == DDPF_FOURCC)
4199
6.90k
    WriteFourCC(image,compression,clusterFit,weightByAlpha,exception);
4200
0
  else
4201
0
    WriteUncompressed(image,exception);
4202
6.90k
}
4203
4204
static MagickBooleanType WriteMipmaps(Image *image,const ImageInfo *image_info,
4205
  const size_t pixelFormat,const size_t compression,const size_t mipmaps,
4206
  const MagickBooleanType fromlist,const MagickBooleanType clusterFit,
4207
  const MagickBooleanType weightByAlpha,ExceptionInfo *exception)
4208
1.18k
{
4209
1.18k
  const char
4210
1.18k
    *option;
4211
4212
1.18k
  Image
4213
1.18k
    *mipmap_image,
4214
1.18k
    *resize_image;
4215
4216
1.18k
  MagickBooleanType
4217
1.18k
    fast_mipmaps,
4218
1.18k
    status;
4219
4220
1.18k
  ssize_t
4221
1.18k
    i;
4222
4223
1.18k
  size_t
4224
1.18k
    columns,
4225
1.18k
    rows;
4226
4227
1.18k
  columns=DIV2(image->columns);
4228
1.18k
  rows=DIV2(image->rows);
4229
4230
1.18k
  option=GetImageOption(image_info,"dds:fast-mipmaps");
4231
1.18k
  fast_mipmaps=IsStringTrue(option);
4232
1.18k
  mipmap_image=image;
4233
1.18k
  resize_image=image;
4234
1.18k
  status=MagickTrue;
4235
5.35k
  for (i=0; i < (ssize_t) mipmaps; i++)
4236
4.16k
  {
4237
4.16k
    if (fromlist == MagickFalse)
4238
4.16k
      {
4239
4.16k
        mipmap_image=ResizeImage(resize_image,columns,rows,TriangleFilter,
4240
4.16k
          exception);
4241
4242
4.16k
        if (mipmap_image == (Image *) NULL)
4243
0
          {
4244
0
            status=MagickFalse;
4245
0
            break;
4246
0
          }
4247
4.16k
      }
4248
0
    else
4249
0
      {
4250
0
        mipmap_image=mipmap_image->next;
4251
0
        if ((mipmap_image->columns != columns) || (mipmap_image->rows != rows))
4252
0
          ThrowBinaryException(CoderError,"ImageColumnOrRowSizeIsNotSupported",
4253
0
            image->filename);
4254
0
      }
4255
4256
4.16k
    DestroyBlob(mipmap_image);
4257
4.16k
    mipmap_image->blob=ReferenceBlob(image->blob);
4258
4259
4.16k
    WriteImageData(mipmap_image,pixelFormat,compression,weightByAlpha,
4260
4.16k
      clusterFit,exception);
4261
4262
4.16k
    if (fromlist == MagickFalse)
4263
4.16k
      {
4264
4.16k
        if (fast_mipmaps == MagickFalse)
4265
4.16k
          mipmap_image=DestroyImage(mipmap_image);
4266
0
        else
4267
0
          {
4268
0
            if (resize_image != image)
4269
0
              resize_image=DestroyImage(resize_image);
4270
0
            resize_image=mipmap_image;
4271
0
          }
4272
4.16k
      }
4273
4274
4.16k
    columns=DIV2(columns);
4275
4.16k
    rows=DIV2(rows);
4276
4.16k
  }
4277
4278
1.18k
  if (resize_image != image)
4279
0
    resize_image=DestroyImage(resize_image);
4280
4281
1.18k
  return(status);
4282
1.18k
}
4283
4284
static void WriteDDSInfo(Image *image, const size_t pixelFormat,
4285
  const size_t compression, const size_t mipmaps)
4286
2.73k
{
4287
2.73k
  char
4288
2.73k
    software[MagickPathExtent];
4289
4290
2.73k
  ssize_t
4291
2.73k
    i;
4292
4293
2.73k
  unsigned int
4294
2.73k
    format,
4295
2.73k
    caps,
4296
2.73k
    flags;
4297
4298
2.73k
  flags=(unsigned int) (DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT |
4299
2.73k
    DDSD_PIXELFORMAT);
4300
2.73k
  caps=(unsigned int) DDSCAPS_TEXTURE;
4301
2.73k
  format=(unsigned int) pixelFormat;
4302
4303
2.73k
  if (format == DDPF_FOURCC)
4304
2.73k
      flags=flags | DDSD_LINEARSIZE;
4305
0
  else
4306
0
      flags=flags | DDSD_PITCH;
4307
4308
2.73k
  if (mipmaps > 0)
4309
1.18k
    {
4310
1.18k
      flags=flags | (unsigned int) DDSD_MIPMAPCOUNT;
4311
1.18k
      caps=caps | (unsigned int) (DDSCAPS_MIPMAP | DDSCAPS_COMPLEX);
4312
1.18k
    }
4313
4314
2.73k
  if (format != DDPF_FOURCC && image->alpha_trait != UndefinedPixelTrait)
4315
0
    format=format | DDPF_ALPHAPIXELS;
4316
4317
2.73k
  (void) WriteBlob(image,4,(unsigned char *) "DDS ");
4318
2.73k
  (void) WriteBlobLSBLong(image,124);
4319
2.73k
  (void) WriteBlobLSBLong(image,flags);
4320
2.73k
  (void) WriteBlobLSBLong(image,(unsigned int) image->rows);
4321
2.73k
  (void) WriteBlobLSBLong(image,(unsigned int) image->columns);
4322
4323
2.73k
  if (pixelFormat == DDPF_FOURCC)
4324
2.73k
    {
4325
      /* Compressed DDS requires linear compressed size of first image */
4326
2.73k
      if (compression == FOURCC_DXT1)
4327
1.55k
        (void) WriteBlobLSBLong(image,(unsigned int) (MagickMax(1,
4328
1.55k
          (image->columns+3)/4)*MagickMax(1,(image->rows+3)/4)*8));
4329
1.17k
      else /* DXT5 */
4330
1.17k
        (void) WriteBlobLSBLong(image,(unsigned int) (MagickMax(1,
4331
1.17k
          (image->columns+3)/4)*MagickMax(1,(image->rows+3)/4)*16));
4332
2.73k
    }
4333
0
  else
4334
0
    {
4335
      /* Uncompressed DDS requires byte pitch of first image */
4336
0
      if (image->alpha_trait != UndefinedPixelTrait)
4337
0
        (void) WriteBlobLSBLong(image,(unsigned int) (image->columns * 4));
4338
0
      else
4339
0
        (void) WriteBlobLSBLong(image,(unsigned int) (image->columns * 3));
4340
0
    }
4341
4342
2.73k
  (void) WriteBlobLSBLong(image,0x00);
4343
2.73k
  (void) WriteBlobLSBLong(image,(unsigned int) mipmaps+1);
4344
2.73k
  (void) memset(software,0,sizeof(software));
4345
2.73k
  (void) CopyMagickString(software,"IMAGEMAGICK",MagickPathExtent);
4346
2.73k
  (void) WriteBlob(image,44,(unsigned char *) software);
4347
4348
2.73k
  (void) WriteBlobLSBLong(image,32);
4349
2.73k
  (void) WriteBlobLSBLong(image,format);
4350
4351
2.73k
  if (pixelFormat == DDPF_FOURCC)
4352
2.73k
    {
4353
2.73k
      (void) WriteBlobLSBLong(image,(unsigned int) compression);
4354
16.4k
      for(i=0;i < 5;i++)  /* bitcount / masks */
4355
13.6k
        (void) WriteBlobLSBLong(image,0x00);
4356
2.73k
    }
4357
0
  else
4358
0
    {
4359
0
      (void) WriteBlobLSBLong(image,0x00);
4360
0
      if (image->alpha_trait != UndefinedPixelTrait)
4361
0
        {
4362
0
          (void) WriteBlobLSBLong(image,32);
4363
0
          (void) WriteBlobLSBLong(image,0xff0000);
4364
0
          (void) WriteBlobLSBLong(image,0xff00);
4365
0
          (void) WriteBlobLSBLong(image,0xff);
4366
0
          (void) WriteBlobLSBLong(image,0xff000000);
4367
0
        }
4368
0
      else
4369
0
        {
4370
0
          (void) WriteBlobLSBLong(image,24);
4371
0
          (void) WriteBlobLSBLong(image,0xff0000);
4372
0
          (void) WriteBlobLSBLong(image,0xff00);
4373
0
          (void) WriteBlobLSBLong(image,0xff);
4374
0
          (void) WriteBlobLSBLong(image,0x00);
4375
0
        }
4376
0
    }
4377
  
4378
2.73k
  (void) WriteBlobLSBLong(image,caps);
4379
13.6k
  for(i=0;i < 4;i++)   /* ddscaps2 + reserved region */
4380
10.9k
    (void) WriteBlobLSBLong(image,0x00);
4381
2.73k
}
4382
4383
static MagickBooleanType WriteDDSImage(const ImageInfo *image_info,
4384
  Image *image, ExceptionInfo *exception)
4385
2.73k
{
4386
2.73k
  const char
4387
2.73k
    *option;
4388
4389
2.73k
  size_t
4390
2.73k
    compression,
4391
2.73k
    columns,
4392
2.73k
    maxMipmaps,
4393
2.73k
    mipmaps,
4394
2.73k
    pixelFormat,
4395
2.73k
    rows;
4396
4397
2.73k
  MagickBooleanType
4398
2.73k
    clusterFit,
4399
2.73k
    fromlist,
4400
2.73k
    status,
4401
2.73k
    weightByAlpha;
4402
4403
2.73k
  assert(image_info != (const ImageInfo *) NULL);
4404
2.73k
  assert(image_info->signature == MagickCoreSignature);
4405
2.73k
  assert(image != (Image *) NULL);
4406
2.73k
  assert(image->signature == MagickCoreSignature);
4407
2.73k
  if (IsEventLogging() != MagickFalse)
4408
0
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
4409
2.73k
  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
4410
2.73k
  if (status == MagickFalse)
4411
0
    return(status);
4412
2.73k
  if (IssRGBCompatibleColorspace(image->colorspace) == MagickFalse)
4413
0
    (void) TransformImageColorspace(image,sRGBColorspace,exception);
4414
2.73k
  pixelFormat=DDPF_FOURCC;
4415
2.73k
  compression=FOURCC_DXT5;
4416
2.73k
  if (((image->alpha_trait & BlendPixelTrait) == 0) ||
4417
1.65k
      (LocaleCompare(image_info->magick,"dxt1") == 0) ||
4418
1.17k
      (image_info->compression == DXT1Compression))
4419
1.55k
    compression=FOURCC_DXT1;
4420
1.17k
  else if (image_info->compression == NoCompression)
4421
0
    pixelFormat=DDPF_RGB;
4422
2.73k
  option=GetImageOption(image_info,"dds:compression");
4423
2.73k
  if (option != (char *) NULL)
4424
0
    {
4425
0
       if (LocaleCompare(option,"dxt1") == 0)
4426
0
         compression=FOURCC_DXT1;
4427
0
       if (LocaleCompare(option,"dxt5") == 0)
4428
0
         compression=FOURCC_DXT5;
4429
0
       if (LocaleCompare(option,"none") == 0)
4430
0
         pixelFormat=DDPF_RGB;
4431
0
    }
4432
2.73k
  clusterFit=MagickFalse;
4433
2.73k
  weightByAlpha=MagickFalse;
4434
2.73k
  if (pixelFormat == DDPF_FOURCC)
4435
2.73k
    {
4436
2.73k
      option=GetImageOption(image_info,"dds:cluster-fit");
4437
2.73k
      if (IsStringTrue(option) != MagickFalse)
4438
0
        {
4439
0
          clusterFit=MagickTrue;
4440
0
          if (compression != FOURCC_DXT1)
4441
0
            {
4442
0
              option=GetImageOption(image_info,"dds:weight-by-alpha");
4443
0
              if (IsStringTrue(option) != MagickFalse)
4444
0
                weightByAlpha=MagickTrue;
4445
0
            }
4446
0
        }
4447
2.73k
    }
4448
2.73k
  mipmaps=0;
4449
2.73k
  fromlist=MagickFalse;
4450
2.73k
  option=GetImageOption(image_info,"dds:mipmaps");
4451
2.73k
  if (option != (char *) NULL)
4452
0
    {
4453
0
      if (LocaleNCompare(option,"fromlist",8) == 0)
4454
0
        {
4455
0
          Image
4456
0
            *next;
4457
4458
0
          fromlist=MagickTrue;
4459
0
          next=image->next;
4460
0
          while(next != (Image *) NULL)
4461
0
          {
4462
0
            mipmaps++;
4463
0
            next=next->next;
4464
0
          }
4465
0
        }
4466
0
    }
4467
2.73k
  if ((mipmaps == 0) &&
4468
2.73k
      ((image->columns & (image->columns - 1)) == 0) &&
4469
2.12k
      ((image->rows & (image->rows - 1)) == 0))
4470
1.75k
    {
4471
1.75k
      maxMipmaps=SIZE_MAX;
4472
1.75k
      if (option != (char *) NULL)
4473
0
        maxMipmaps=StringToUnsignedLong(option);
4474
4475
1.75k
      if (maxMipmaps != 0)
4476
1.75k
        {
4477
1.75k
          columns=image->columns;
4478
1.75k
          rows=image->rows;
4479
5.91k
          while ((columns != 1 || rows != 1) && mipmaps != maxMipmaps)
4480
4.16k
          {
4481
4.16k
            columns=DIV2(columns);
4482
4.16k
            rows=DIV2(rows);
4483
4.16k
            mipmaps++;
4484
4.16k
          }
4485
1.75k
        }
4486
1.75k
    }
4487
2.73k
  option=GetImageOption(image_info,"dds:raw");
4488
2.73k
  if (IsStringTrue(option) == MagickFalse)
4489
2.73k
    WriteDDSInfo(image,pixelFormat,compression,mipmaps);
4490
0
  else
4491
0
    mipmaps=0;
4492
2.73k
  WriteImageData(image,pixelFormat,compression,clusterFit,weightByAlpha,
4493
2.73k
    exception);
4494
2.73k
  if ((mipmaps > 0) && (WriteMipmaps(image,image_info,pixelFormat,compression,
4495
1.18k
       mipmaps,fromlist,clusterFit,weightByAlpha,exception) == MagickFalse))
4496
0
    return(MagickFalse);
4497
2.73k
  if (CloseBlob(image) == MagickFalse)
4498
0
    status=MagickFalse;
4499
2.73k
  return(status);
4500
2.73k
}