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-2021 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/script/license.php %
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 #define DDSD_CAPS 0x00000001
77 #define DDSD_HEIGHT 0x00000002
78 #define DDSD_WIDTH 0x00000004
79 #define DDSD_PITCH 0x00000008
80 #define DDSD_PIXELFORMAT 0x00001000
81 #define DDSD_MIPMAPCOUNT 0x00020000
82 #define DDSD_LINEARSIZE 0x00080000
83 #define DDSD_DEPTH 0x00800000
84
85 #define DDPF_ALPHAPIXELS 0x00000001
86 #define DDPF_FOURCC 0x00000004
87 #define DDPF_RGB 0x00000040
88 #define DDPF_LUMINANCE 0x00020000
89
90 #define FOURCC_DXT1 0x31545844
91 #define FOURCC_DXT3 0x33545844
92 #define FOURCC_DXT5 0x35545844
93 #define FOURCC_DX10 0x30315844
94
95 #define DDSCAPS_COMPLEX 0x00000008
96 #define DDSCAPS_TEXTURE 0x00001000
97 #define DDSCAPS_MIPMAP 0x00400000
98
99 #define DDSCAPS2_CUBEMAP 0x00000200
100 #define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400
101 #define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800
102 #define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000
103 #define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000
104 #define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000
105 #define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000
106 #define DDSCAPS2_VOLUME 0x00200000
107
108 #define DDSEXT_DIMENSION_TEX2D 0x00000003
109 #define DDSEXTFLAGS_CUBEMAP 0x00000004
110
111 typedef enum DXGI_FORMAT
112 {
113 DXGI_FORMAT_UNKNOWN,
114 DXGI_FORMAT_R32G32B32A32_TYPELESS,
115 DXGI_FORMAT_R32G32B32A32_FLOAT,
116 DXGI_FORMAT_R32G32B32A32_UINT,
117 DXGI_FORMAT_R32G32B32A32_SINT,
118 DXGI_FORMAT_R32G32B32_TYPELESS,
119 DXGI_FORMAT_R32G32B32_FLOAT,
120 DXGI_FORMAT_R32G32B32_UINT,
121 DXGI_FORMAT_R32G32B32_SINT,
122 DXGI_FORMAT_R16G16B16A16_TYPELESS,
123 DXGI_FORMAT_R16G16B16A16_FLOAT,
124 DXGI_FORMAT_R16G16B16A16_UNORM,
125 DXGI_FORMAT_R16G16B16A16_UINT,
126 DXGI_FORMAT_R16G16B16A16_SNORM,
127 DXGI_FORMAT_R16G16B16A16_SINT,
128 DXGI_FORMAT_R32G32_TYPELESS,
129 DXGI_FORMAT_R32G32_FLOAT,
130 DXGI_FORMAT_R32G32_UINT,
131 DXGI_FORMAT_R32G32_SINT,
132 DXGI_FORMAT_R32G8X24_TYPELESS,
133 DXGI_FORMAT_D32_FLOAT_S8X24_UINT,
134 DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS,
135 DXGI_FORMAT_X32_TYPELESS_G8X24_UINT,
136 DXGI_FORMAT_R10G10B10A2_TYPELESS,
137 DXGI_FORMAT_R10G10B10A2_UNORM,
138 DXGI_FORMAT_R10G10B10A2_UINT,
139 DXGI_FORMAT_R11G11B10_FLOAT,
140 DXGI_FORMAT_R8G8B8A8_TYPELESS,
141 DXGI_FORMAT_R8G8B8A8_UNORM,
142 DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
143 DXGI_FORMAT_R8G8B8A8_UINT,
144 DXGI_FORMAT_R8G8B8A8_SNORM,
145 DXGI_FORMAT_R8G8B8A8_SINT,
146 DXGI_FORMAT_R16G16_TYPELESS,
147 DXGI_FORMAT_R16G16_FLOAT,
148 DXGI_FORMAT_R16G16_UNORM,
149 DXGI_FORMAT_R16G16_UINT,
150 DXGI_FORMAT_R16G16_SNORM,
151 DXGI_FORMAT_R16G16_SINT,
152 DXGI_FORMAT_R32_TYPELESS,
153 DXGI_FORMAT_D32_FLOAT,
154 DXGI_FORMAT_R32_FLOAT,
155 DXGI_FORMAT_R32_UINT,
156 DXGI_FORMAT_R32_SINT,
157 DXGI_FORMAT_R24G8_TYPELESS,
158 DXGI_FORMAT_D24_UNORM_S8_UINT,
159 DXGI_FORMAT_R24_UNORM_X8_TYPELESS,
160 DXGI_FORMAT_X24_TYPELESS_G8_UINT,
161 DXGI_FORMAT_R8G8_TYPELESS,
162 DXGI_FORMAT_R8G8_UNORM,
163 DXGI_FORMAT_R8G8_UINT,
164 DXGI_FORMAT_R8G8_SNORM,
165 DXGI_FORMAT_R8G8_SINT,
166 DXGI_FORMAT_R16_TYPELESS,
167 DXGI_FORMAT_R16_FLOAT,
168 DXGI_FORMAT_D16_UNORM,
169 DXGI_FORMAT_R16_UNORM,
170 DXGI_FORMAT_R16_UINT,
171 DXGI_FORMAT_R16_SNORM,
172 DXGI_FORMAT_R16_SINT,
173 DXGI_FORMAT_R8_TYPELESS,
174 DXGI_FORMAT_R8_UNORM,
175 DXGI_FORMAT_R8_UINT,
176 DXGI_FORMAT_R8_SNORM,
177 DXGI_FORMAT_R8_SINT,
178 DXGI_FORMAT_A8_UNORM,
179 DXGI_FORMAT_R1_UNORM,
180 DXGI_FORMAT_R9G9B9E5_SHAREDEXP,
181 DXGI_FORMAT_R8G8_B8G8_UNORM,
182 DXGI_FORMAT_G8R8_G8B8_UNORM,
183 DXGI_FORMAT_BC1_TYPELESS,
184 DXGI_FORMAT_BC1_UNORM,
185 DXGI_FORMAT_BC1_UNORM_SRGB,
186 DXGI_FORMAT_BC2_TYPELESS,
187 DXGI_FORMAT_BC2_UNORM,
188 DXGI_FORMAT_BC2_UNORM_SRGB,
189 DXGI_FORMAT_BC3_TYPELESS,
190 DXGI_FORMAT_BC3_UNORM,
191 DXGI_FORMAT_BC3_UNORM_SRGB,
192 DXGI_FORMAT_BC4_TYPELESS,
193 DXGI_FORMAT_BC4_UNORM,
194 DXGI_FORMAT_BC4_SNORM,
195 DXGI_FORMAT_BC5_TYPELESS,
196 DXGI_FORMAT_BC5_UNORM,
197 DXGI_FORMAT_BC5_SNORM,
198 DXGI_FORMAT_B5G6R5_UNORM,
199 DXGI_FORMAT_B5G5R5A1_UNORM,
200 DXGI_FORMAT_B8G8R8A8_UNORM,
201 DXGI_FORMAT_B8G8R8X8_UNORM,
202 DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM,
203 DXGI_FORMAT_B8G8R8A8_TYPELESS,
204 DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,
205 DXGI_FORMAT_B8G8R8X8_TYPELESS,
206 DXGI_FORMAT_B8G8R8X8_UNORM_SRGB,
207 DXGI_FORMAT_BC6H_TYPELESS,
208 DXGI_FORMAT_BC6H_UF16,
209 DXGI_FORMAT_BC6H_SF16,
210 DXGI_FORMAT_BC7_TYPELESS,
211 DXGI_FORMAT_BC7_UNORM,
212 DXGI_FORMAT_BC7_UNORM_SRGB,
213 DXGI_FORMAT_AYUV,
214 DXGI_FORMAT_Y410,
215 DXGI_FORMAT_Y416,
216 DXGI_FORMAT_NV12,
217 DXGI_FORMAT_P010,
218 DXGI_FORMAT_P016,
219 DXGI_FORMAT_420_OPAQUE,
220 DXGI_FORMAT_YUY2,
221 DXGI_FORMAT_Y210,
222 DXGI_FORMAT_Y216,
223 DXGI_FORMAT_NV11,
224 DXGI_FORMAT_AI44,
225 DXGI_FORMAT_IA44,
226 DXGI_FORMAT_P8,
227 DXGI_FORMAT_A8P8,
228 DXGI_FORMAT_B4G4R4A4_UNORM,
229 DXGI_FORMAT_P208,
230 DXGI_FORMAT_V208,
231 DXGI_FORMAT_V408,
232 DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE,
233 DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE,
234 DXGI_FORMAT_FORCE_UINT
235 } DXGI_FORMAT;
236
237
238 #ifndef SIZE_MAX
239 #define SIZE_MAX ((size_t) -1)
240 #endif
241
242 /*
243 Structure declarations.
244 */
245 typedef struct _DDSPixelFormat
246 {
247 size_t
248 flags,
249 fourcc,
250 rgb_bitcount,
251 r_bitmask,
252 g_bitmask,
253 b_bitmask,
254 alpha_bitmask;
255 } DDSPixelFormat;
256
257 typedef struct _DDSInfo
258 {
259 size_t
260 flags,
261 height,
262 width,
263 pitchOrLinearSize,
264 depth,
265 mipmapcount,
266 ddscaps1,
267 ddscaps2,
268 extFormat,
269 extDimension,
270 extFlags,
271 extArraySize,
272 extFlags2;
273
274 DDSPixelFormat
275 pixelformat;
276 } DDSInfo;
277
278 typedef struct _DDSColors
279 {
280 unsigned char
281 r[4],
282 g[4],
283 b[4],
284 a[4];
285 } DDSColors;
286
287 typedef struct _DDSVector4
288 {
289 float
290 x,
291 y,
292 z,
293 w;
294 } DDSVector4;
295
296 typedef struct _DDSVector3
297 {
298 float
299 x,
300 y,
301 z;
302 } DDSVector3;
303
304 typedef struct _DDSSourceBlock
305 {
306 unsigned char
307 start,
308 end,
309 error;
310 } DDSSourceBlock;
311
312 typedef struct _DDSSingleColorLookup
313 {
314 DDSSourceBlock sources[2];
315 } DDSSingleColorLookup;
316
317 typedef MagickBooleanType
318 DDSDecoder(const ImageInfo *,Image *,DDSInfo *,const MagickBooleanType,
319 ExceptionInfo *);
320
321 typedef MagickBooleanType
322 DDSPixelDecoder(Image *,DDSInfo *,ExceptionInfo *);
323
324 static const DDSSingleColorLookup DDSLookup_5_4[] =
325 {
326 { { { 0, 0, 0 }, { 0, 0, 0 } } },
327 { { { 0, 0, 1 }, { 0, 1, 1 } } },
328 { { { 0, 0, 2 }, { 0, 1, 0 } } },
329 { { { 0, 0, 3 }, { 0, 1, 1 } } },
330 { { { 0, 0, 4 }, { 0, 2, 1 } } },
331 { { { 1, 0, 3 }, { 0, 2, 0 } } },
332 { { { 1, 0, 2 }, { 0, 2, 1 } } },
333 { { { 1, 0, 1 }, { 0, 3, 1 } } },
334 { { { 1, 0, 0 }, { 0, 3, 0 } } },
335 { { { 1, 0, 1 }, { 1, 2, 1 } } },
336 { { { 1, 0, 2 }, { 1, 2, 0 } } },
337 { { { 1, 0, 3 }, { 0, 4, 0 } } },
338 { { { 1, 0, 4 }, { 0, 5, 1 } } },
339 { { { 2, 0, 3 }, { 0, 5, 0 } } },
340 { { { 2, 0, 2 }, { 0, 5, 1 } } },
341 { { { 2, 0, 1 }, { 0, 6, 1 } } },
342 { { { 2, 0, 0 }, { 0, 6, 0 } } },
343 { { { 2, 0, 1 }, { 2, 3, 1 } } },
344 { { { 2, 0, 2 }, { 2, 3, 0 } } },
345 { { { 2, 0, 3 }, { 0, 7, 0 } } },
346 { { { 2, 0, 4 }, { 1, 6, 1 } } },
347 { { { 3, 0, 3 }, { 1, 6, 0 } } },
348 { { { 3, 0, 2 }, { 0, 8, 0 } } },
349 { { { 3, 0, 1 }, { 0, 9, 1 } } },
350 { { { 3, 0, 0 }, { 0, 9, 0 } } },
351 { { { 3, 0, 1 }, { 0, 9, 1 } } },
352 { { { 3, 0, 2 }, { 0, 10, 1 } } },
353 { { { 3, 0, 3 }, { 0, 10, 0 } } },
354 { { { 3, 0, 4 }, { 2, 7, 1 } } },
355 { { { 4, 0, 4 }, { 2, 7, 0 } } },
356 { { { 4, 0, 3 }, { 0, 11, 0 } } },
357 { { { 4, 0, 2 }, { 1, 10, 1 } } },
358 { { { 4, 0, 1 }, { 1, 10, 0 } } },
359 { { { 4, 0, 0 }, { 0, 12, 0 } } },
360 { { { 4, 0, 1 }, { 0, 13, 1 } } },
361 { { { 4, 0, 2 }, { 0, 13, 0 } } },
362 { { { 4, 0, 3 }, { 0, 13, 1 } } },
363 { { { 4, 0, 4 }, { 0, 14, 1 } } },
364 { { { 5, 0, 3 }, { 0, 14, 0 } } },
365 { { { 5, 0, 2 }, { 2, 11, 1 } } },
366 { { { 5, 0, 1 }, { 2, 11, 0 } } },
367 { { { 5, 0, 0 }, { 0, 15, 0 } } },
368 { { { 5, 0, 1 }, { 1, 14, 1 } } },
369 { { { 5, 0, 2 }, { 1, 14, 0 } } },
370 { { { 5, 0, 3 }, { 0, 16, 0 } } },
371 { { { 5, 0, 4 }, { 0, 17, 1 } } },
372 { { { 6, 0, 3 }, { 0, 17, 0 } } },
373 { { { 6, 0, 2 }, { 0, 17, 1 } } },
374 { { { 6, 0, 1 }, { 0, 18, 1 } } },
375 { { { 6, 0, 0 }, { 0, 18, 0 } } },
376 { { { 6, 0, 1 }, { 2, 15, 1 } } },
377 { { { 6, 0, 2 }, { 2, 15, 0 } } },
378 { { { 6, 0, 3 }, { 0, 19, 0 } } },
379 { { { 6, 0, 4 }, { 1, 18, 1 } } },
380 { { { 7, 0, 3 }, { 1, 18, 0 } } },
381 { { { 7, 0, 2 }, { 0, 20, 0 } } },
382 { { { 7, 0, 1 }, { 0, 21, 1 } } },
383 { { { 7, 0, 0 }, { 0, 21, 0 } } },
384 { { { 7, 0, 1 }, { 0, 21, 1 } } },
385 { { { 7, 0, 2 }, { 0, 22, 1 } } },
386 { { { 7, 0, 3 }, { 0, 22, 0 } } },
387 { { { 7, 0, 4 }, { 2, 19, 1 } } },
388 { { { 8, 0, 4 }, { 2, 19, 0 } } },
389 { { { 8, 0, 3 }, { 0, 23, 0 } } },
390 { { { 8, 0, 2 }, { 1, 22, 1 } } },
391 { { { 8, 0, 1 }, { 1, 22, 0 } } },
392 { { { 8, 0, 0 }, { 0, 24, 0 } } },
393 { { { 8, 0, 1 }, { 0, 25, 1 } } },
394 { { { 8, 0, 2 }, { 0, 25, 0 } } },
395 { { { 8, 0, 3 }, { 0, 25, 1 } } },
396 { { { 8, 0, 4 }, { 0, 26, 1 } } },
397 { { { 9, 0, 3 }, { 0, 26, 0 } } },
398 { { { 9, 0, 2 }, { 2, 23, 1 } } },
399 { { { 9, 0, 1 }, { 2, 23, 0 } } },
400 { { { 9, 0, 0 }, { 0, 27, 0 } } },
401 { { { 9, 0, 1 }, { 1, 26, 1 } } },
402 { { { 9, 0, 2 }, { 1, 26, 0 } } },
403 { { { 9, 0, 3 }, { 0, 28, 0 } } },
404 { { { 9, 0, 4 }, { 0, 29, 1 } } },
405 { { { 10, 0, 3 }, { 0, 29, 0 } } },
406 { { { 10, 0, 2 }, { 0, 29, 1 } } },
407 { { { 10, 0, 1 }, { 0, 30, 1 } } },
408 { { { 10, 0, 0 }, { 0, 30, 0 } } },
409 { { { 10, 0, 1 }, { 2, 27, 1 } } },
410 { { { 10, 0, 2 }, { 2, 27, 0 } } },
411 { { { 10, 0, 3 }, { 0, 31, 0 } } },
412 { { { 10, 0, 4 }, { 1, 30, 1 } } },
413 { { { 11, 0, 3 }, { 1, 30, 0 } } },
414 { { { 11, 0, 2 }, { 4, 24, 0 } } },
415 { { { 11, 0, 1 }, { 1, 31, 1 } } },
416 { { { 11, 0, 0 }, { 1, 31, 0 } } },
417 { { { 11, 0, 1 }, { 1, 31, 1 } } },
418 { { { 11, 0, 2 }, { 2, 30, 1 } } },
419 { { { 11, 0, 3 }, { 2, 30, 0 } } },
420 { { { 11, 0, 4 }, { 2, 31, 1 } } },
421 { { { 12, 0, 4 }, { 2, 31, 0 } } },
422 { { { 12, 0, 3 }, { 4, 27, 0 } } },
423 { { { 12, 0, 2 }, { 3, 30, 1 } } },
424 { { { 12, 0, 1 }, { 3, 30, 0 } } },
425 { { { 12, 0, 0 }, { 4, 28, 0 } } },
426 { { { 12, 0, 1 }, { 3, 31, 1 } } },
427 { { { 12, 0, 2 }, { 3, 31, 0 } } },
428 { { { 12, 0, 3 }, { 3, 31, 1 } } },
429 { { { 12, 0, 4 }, { 4, 30, 1 } } },
430 { { { 13, 0, 3 }, { 4, 30, 0 } } },
431 { { { 13, 0, 2 }, { 6, 27, 1 } } },
432 { { { 13, 0, 1 }, { 6, 27, 0 } } },
433 { { { 13, 0, 0 }, { 4, 31, 0 } } },
434 { { { 13, 0, 1 }, { 5, 30, 1 } } },
435 { { { 13, 0, 2 }, { 5, 30, 0 } } },
436 { { { 13, 0, 3 }, { 8, 24, 0 } } },
437 { { { 13, 0, 4 }, { 5, 31, 1 } } },
438 { { { 14, 0, 3 }, { 5, 31, 0 } } },
439 { { { 14, 0, 2 }, { 5, 31, 1 } } },
440 { { { 14, 0, 1 }, { 6, 30, 1 } } },
441 { { { 14, 0, 0 }, { 6, 30, 0 } } },
442 { { { 14, 0, 1 }, { 6, 31, 1 } } },
443 { { { 14, 0, 2 }, { 6, 31, 0 } } },
444 { { { 14, 0, 3 }, { 8, 27, 0 } } },
445 { { { 14, 0, 4 }, { 7, 30, 1 } } },
446 { { { 15, 0, 3 }, { 7, 30, 0 } } },
447 { { { 15, 0, 2 }, { 8, 28, 0 } } },
448 { { { 15, 0, 1 }, { 7, 31, 1 } } },
449 { { { 15, 0, 0 }, { 7, 31, 0 } } },
450 { { { 15, 0, 1 }, { 7, 31, 1 } } },
451 { { { 15, 0, 2 }, { 8, 30, 1 } } },
452 { { { 15, 0, 3 }, { 8, 30, 0 } } },
453 { { { 15, 0, 4 }, { 10, 27, 1 } } },
454 { { { 16, 0, 4 }, { 10, 27, 0 } } },
455 { { { 16, 0, 3 }, { 8, 31, 0 } } },
456 { { { 16, 0, 2 }, { 9, 30, 1 } } },
457 { { { 16, 0, 1 }, { 9, 30, 0 } } },
458 { { { 16, 0, 0 }, { 12, 24, 0 } } },
459 { { { 16, 0, 1 }, { 9, 31, 1 } } },
460 { { { 16, 0, 2 }, { 9, 31, 0 } } },
461 { { { 16, 0, 3 }, { 9, 31, 1 } } },
462 { { { 16, 0, 4 }, { 10, 30, 1 } } },
463 { { { 17, 0, 3 }, { 10, 30, 0 } } },
464 { { { 17, 0, 2 }, { 10, 31, 1 } } },
465 { { { 17, 0, 1 }, { 10, 31, 0 } } },
466 { { { 17, 0, 0 }, { 12, 27, 0 } } },
467 { { { 17, 0, 1 }, { 11, 30, 1 } } },
468 { { { 17, 0, 2 }, { 11, 30, 0 } } },
469 { { { 17, 0, 3 }, { 12, 28, 0 } } },
470 { { { 17, 0, 4 }, { 11, 31, 1 } } },
471 { { { 18, 0, 3 }, { 11, 31, 0 } } },
472 { { { 18, 0, 2 }, { 11, 31, 1 } } },
473 { { { 18, 0, 1 }, { 12, 30, 1 } } },
474 { { { 18, 0, 0 }, { 12, 30, 0 } } },
475 { { { 18, 0, 1 }, { 14, 27, 1 } } },
476 { { { 18, 0, 2 }, { 14, 27, 0 } } },
477 { { { 18, 0, 3 }, { 12, 31, 0 } } },
478 { { { 18, 0, 4 }, { 13, 30, 1 } } },
479 { { { 19, 0, 3 }, { 13, 30, 0 } } },
480 { { { 19, 0, 2 }, { 16, 24, 0 } } },
481 { { { 19, 0, 1 }, { 13, 31, 1 } } },
482 { { { 19, 0, 0 }, { 13, 31, 0 } } },
483 { { { 19, 0, 1 }, { 13, 31, 1 } } },
484 { { { 19, 0, 2 }, { 14, 30, 1 } } },
485 { { { 19, 0, 3 }, { 14, 30, 0 } } },
486 { { { 19, 0, 4 }, { 14, 31, 1 } } },
487 { { { 20, 0, 4 }, { 14, 31, 0 } } },
488 { { { 20, 0, 3 }, { 16, 27, 0 } } },
489 { { { 20, 0, 2 }, { 15, 30, 1 } } },
490 { { { 20, 0, 1 }, { 15, 30, 0 } } },
491 { { { 20, 0, 0 }, { 16, 28, 0 } } },
492 { { { 20, 0, 1 }, { 15, 31, 1 } } },
493 { { { 20, 0, 2 }, { 15, 31, 0 } } },
494 { { { 20, 0, 3 }, { 15, 31, 1 } } },
495 { { { 20, 0, 4 }, { 16, 30, 1 } } },
496 { { { 21, 0, 3 }, { 16, 30, 0 } } },
497 { { { 21, 0, 2 }, { 18, 27, 1 } } },
498 { { { 21, 0, 1 }, { 18, 27, 0 } } },
499 { { { 21, 0, 0 }, { 16, 31, 0 } } },
500 { { { 21, 0, 1 }, { 17, 30, 1 } } },
501 { { { 21, 0, 2 }, { 17, 30, 0 } } },
502 { { { 21, 0, 3 }, { 20, 24, 0 } } },
503 { { { 21, 0, 4 }, { 17, 31, 1 } } },
504 { { { 22, 0, 3 }, { 17, 31, 0 } } },
505 { { { 22, 0, 2 }, { 17, 31, 1 } } },
506 { { { 22, 0, 1 }, { 18, 30, 1 } } },
507 { { { 22, 0, 0 }, { 18, 30, 0 } } },
508 { { { 22, 0, 1 }, { 18, 31, 1 } } },
509 { { { 22, 0, 2 }, { 18, 31, 0 } } },
510 { { { 22, 0, 3 }, { 20, 27, 0 } } },
511 { { { 22, 0, 4 }, { 19, 30, 1 } } },
512 { { { 23, 0, 3 }, { 19, 30, 0 } } },
513 { { { 23, 0, 2 }, { 20, 28, 0 } } },
514 { { { 23, 0, 1 }, { 19, 31, 1 } } },
515 { { { 23, 0, 0 }, { 19, 31, 0 } } },
516 { { { 23, 0, 1 }, { 19, 31, 1 } } },
517 { { { 23, 0, 2 }, { 20, 30, 1 } } },
518 { { { 23, 0, 3 }, { 20, 30, 0 } } },
519 { { { 23, 0, 4 }, { 22, 27, 1 } } },
520 { { { 24, 0, 4 }, { 22, 27, 0 } } },
521 { { { 24, 0, 3 }, { 20, 31, 0 } } },
522 { { { 24, 0, 2 }, { 21, 30, 1 } } },
523 { { { 24, 0, 1 }, { 21, 30, 0 } } },
524 { { { 24, 0, 0 }, { 24, 24, 0 } } },
525 { { { 24, 0, 1 }, { 21, 31, 1 } } },
526 { { { 24, 0, 2 }, { 21, 31, 0 } } },
527 { { { 24, 0, 3 }, { 21, 31, 1 } } },
528 { { { 24, 0, 4 }, { 22, 30, 1 } } },
529 { { { 25, 0, 3 }, { 22, 30, 0 } } },
530 { { { 25, 0, 2 }, { 22, 31, 1 } } },
531 { { { 25, 0, 1 }, { 22, 31, 0 } } },
532 { { { 25, 0, 0 }, { 24, 27, 0 } } },
533 { { { 25, 0, 1 }, { 23, 30, 1 } } },
534 { { { 25, 0, 2 }, { 23, 30, 0 } } },
535 { { { 25, 0, 3 }, { 24, 28, 0 } } },
536 { { { 25, 0, 4 }, { 23, 31, 1 } } },
537 { { { 26, 0, 3 }, { 23, 31, 0 } } },
538 { { { 26, 0, 2 }, { 23, 31, 1 } } },
539 { { { 26, 0, 1 }, { 24, 30, 1 } } },
540 { { { 26, 0, 0 }, { 24, 30, 0 } } },
541 { { { 26, 0, 1 }, { 26, 27, 1 } } },
542 { { { 26, 0, 2 }, { 26, 27, 0 } } },
543 { { { 26, 0, 3 }, { 24, 31, 0 } } },
544 { { { 26, 0, 4 }, { 25, 30, 1 } } },
545 { { { 27, 0, 3 }, { 25, 30, 0 } } },
546 { { { 27, 0, 2 }, { 28, 24, 0 } } },
547 { { { 27, 0, 1 }, { 25, 31, 1 } } },
548 { { { 27, 0, 0 }, { 25, 31, 0 } } },
549 { { { 27, 0, 1 }, { 25, 31, 1 } } },
550 { { { 27, 0, 2 }, { 26, 30, 1 } } },
551 { { { 27, 0, 3 }, { 26, 30, 0 } } },
552 { { { 27, 0, 4 }, { 26, 31, 1 } } },
553 { { { 28, 0, 4 }, { 26, 31, 0 } } },
554 { { { 28, 0, 3 }, { 28, 27, 0 } } },
555 { { { 28, 0, 2 }, { 27, 30, 1 } } },
556 { { { 28, 0, 1 }, { 27, 30, 0 } } },
557 { { { 28, 0, 0 }, { 28, 28, 0 } } },
558 { { { 28, 0, 1 }, { 27, 31, 1 } } },
559 { { { 28, 0, 2 }, { 27, 31, 0 } } },
560 { { { 28, 0, 3 }, { 27, 31, 1 } } },
561 { { { 28, 0, 4 }, { 28, 30, 1 } } },
562 { { { 29, 0, 3 }, { 28, 30, 0 } } },
563 { { { 29, 0, 2 }, { 30, 27, 1 } } },
564 { { { 29, 0, 1 }, { 30, 27, 0 } } },
565 { { { 29, 0, 0 }, { 28, 31, 0 } } },
566 { { { 29, 0, 1 }, { 29, 30, 1 } } },
567 { { { 29, 0, 2 }, { 29, 30, 0 } } },
568 { { { 29, 0, 3 }, { 29, 30, 1 } } },
569 { { { 29, 0, 4 }, { 29, 31, 1 } } },
570 { { { 30, 0, 3 }, { 29, 31, 0 } } },
571 { { { 30, 0, 2 }, { 29, 31, 1 } } },
572 { { { 30, 0, 1 }, { 30, 30, 1 } } },
573 { { { 30, 0, 0 }, { 30, 30, 0 } } },
574 { { { 30, 0, 1 }, { 30, 31, 1 } } },
575 { { { 30, 0, 2 }, { 30, 31, 0 } } },
576 { { { 30, 0, 3 }, { 30, 31, 1 } } },
577 { { { 30, 0, 4 }, { 31, 30, 1 } } },
578 { { { 31, 0, 3 }, { 31, 30, 0 } } },
579 { { { 31, 0, 2 }, { 31, 30, 1 } } },
580 { { { 31, 0, 1 }, { 31, 31, 1 } } },
581 { { { 31, 0, 0 }, { 31, 31, 0 } } }
582 };
583
584 static const DDSSingleColorLookup DDSLookup_6_4[] =
585 {
586 { { { 0, 0, 0 }, { 0, 0, 0 } } },
587 { { { 0, 0, 1 }, { 0, 1, 0 } } },
588 { { { 0, 0, 2 }, { 0, 2, 0 } } },
589 { { { 1, 0, 1 }, { 0, 3, 1 } } },
590 { { { 1, 0, 0 }, { 0, 3, 0 } } },
591 { { { 1, 0, 1 }, { 0, 4, 0 } } },
592 { { { 1, 0, 2 }, { 0, 5, 0 } } },
593 { { { 2, 0, 1 }, { 0, 6, 1 } } },
594 { { { 2, 0, 0 }, { 0, 6, 0 } } },
595 { { { 2, 0, 1 }, { 0, 7, 0 } } },
596 { { { 2, 0, 2 }, { 0, 8, 0 } } },
597 { { { 3, 0, 1 }, { 0, 9, 1 } } },
598 { { { 3, 0, 0 }, { 0, 9, 0 } } },
599 { { { 3, 0, 1 }, { 0, 10, 0 } } },
600 { { { 3, 0, 2 }, { 0, 11, 0 } } },
601 { { { 4, 0, 1 }, { 0, 12, 1 } } },
602 { { { 4, 0, 0 }, { 0, 12, 0 } } },
603 { { { 4, 0, 1 }, { 0, 13, 0 } } },
604 { { { 4, 0, 2 }, { 0, 14, 0 } } },
605 { { { 5, 0, 1 }, { 0, 15, 1 } } },
606 { { { 5, 0, 0 }, { 0, 15, 0 } } },
607 { { { 5, 0, 1 }, { 0, 16, 0 } } },
608 { { { 5, 0, 2 }, { 1, 15, 0 } } },
609 { { { 6, 0, 1 }, { 0, 17, 0 } } },
610 { { { 6, 0, 0 }, { 0, 18, 0 } } },
611 { { { 6, 0, 1 }, { 0, 19, 0 } } },
612 { { { 6, 0, 2 }, { 3, 14, 0 } } },
613 { { { 7, 0, 1 }, { 0, 20, 0 } } },
614 { { { 7, 0, 0 }, { 0, 21, 0 } } },
615 { { { 7, 0, 1 }, { 0, 22, 0 } } },
616 { { { 7, 0, 2 }, { 4, 15, 0 } } },
617 { { { 8, 0, 1 }, { 0, 23, 0 } } },
618 { { { 8, 0, 0 }, { 0, 24, 0 } } },
619 { { { 8, 0, 1 }, { 0, 25, 0 } } },
620 { { { 8, 0, 2 }, { 6, 14, 0 } } },
621 { { { 9, 0, 1 }, { 0, 26, 0 } } },
622 { { { 9, 0, 0 }, { 0, 27, 0 } } },
623 { { { 9, 0, 1 }, { 0, 28, 0 } } },
624 { { { 9, 0, 2 }, { 7, 15, 0 } } },
625 { { { 10, 0, 1 }, { 0, 29, 0 } } },
626 { { { 10, 0, 0 }, { 0, 30, 0 } } },
627 { { { 10, 0, 1 }, { 0, 31, 0 } } },
628 { { { 10, 0, 2 }, { 9, 14, 0 } } },
629 { { { 11, 0, 1 }, { 0, 32, 0 } } },
630 { { { 11, 0, 0 }, { 0, 33, 0 } } },
631 { { { 11, 0, 1 }, { 2, 30, 0 } } },
632 { { { 11, 0, 2 }, { 0, 34, 0 } } },
633 { { { 12, 0, 1 }, { 0, 35, 0 } } },
634 { { { 12, 0, 0 }, { 0, 36, 0 } } },
635 { { { 12, 0, 1 }, { 3, 31, 0 } } },
636 { { { 12, 0, 2 }, { 0, 37, 0 } } },
637 { { { 13, 0, 1 }, { 0, 38, 0 } } },
638 { { { 13, 0, 0 }, { 0, 39, 0 } } },
639 { { { 13, 0, 1 }, { 5, 30, 0 } } },
640 { { { 13, 0, 2 }, { 0, 40, 0 } } },
641 { { { 14, 0, 1 }, { 0, 41, 0 } } },
642 { { { 14, 0, 0 }, { 0, 42, 0 } } },
643 { { { 14, 0, 1 }, { 6, 31, 0 } } },
644 { { { 14, 0, 2 }, { 0, 43, 0 } } },
645 { { { 15, 0, 1 }, { 0, 44, 0 } } },
646 { { { 15, 0, 0 }, { 0, 45, 0 } } },
647 { { { 15, 0, 1 }, { 8, 30, 0 } } },
648 { { { 15, 0, 2 }, { 0, 46, 0 } } },
649 { { { 16, 0, 2 }, { 0, 47, 0 } } },
650 { { { 16, 0, 1 }, { 1, 46, 0 } } },
651 { { { 16, 0, 0 }, { 0, 48, 0 } } },
652 { { { 16, 0, 1 }, { 0, 49, 0 } } },
653 { { { 16, 0, 2 }, { 0, 50, 0 } } },
654 { { { 17, 0, 1 }, { 2, 47, 0 } } },
655 { { { 17, 0, 0 }, { 0, 51, 0 } } },
656 { { { 17, 0, 1 }, { 0, 52, 0 } } },
657 { { { 17, 0, 2 }, { 0, 53, 0 } } },
658 { { { 18, 0, 1 }, { 4, 46, 0 } } },
659 { { { 18, 0, 0 }, { 0, 54, 0 } } },
660 { { { 18, 0, 1 }, { 0, 55, 0 } } },
661 { { { 18, 0, 2 }, { 0, 56, 0 } } },
662 { { { 19, 0, 1 }, { 5, 47, 0 } } },
663 { { { 19, 0, 0 }, { 0, 57, 0 } } },
664 { { { 19, 0, 1 }, { 0, 58, 0 } } },
665 { { { 19, 0, 2 }, { 0, 59, 0 } } },
666 { { { 20, 0, 1 }, { 7, 46, 0 } } },
667 { { { 20, 0, 0 }, { 0, 60, 0 } } },
668 { { { 20, 0, 1 }, { 0, 61, 0 } } },
669 { { { 20, 0, 2 }, { 0, 62, 0 } } },
670 { { { 21, 0, 1 }, { 8, 47, 0 } } },
671 { { { 21, 0, 0 }, { 0, 63, 0 } } },
672 { { { 21, 0, 1 }, { 1, 62, 0 } } },
673 { { { 21, 0, 2 }, { 1, 63, 0 } } },
674 { { { 22, 0, 1 }, { 10, 46, 0 } } },
675 { { { 22, 0, 0 }, { 2, 62, 0 } } },
676 { { { 22, 0, 1 }, { 2, 63, 0 } } },
677 { { { 22, 0, 2 }, { 3, 62, 0 } } },
678 { { { 23, 0, 1 }, { 11, 47, 0 } } },
679 { { { 23, 0, 0 }, { 3, 63, 0 } } },
680 { { { 23, 0, 1 }, { 4, 62, 0 } } },
681 { { { 23, 0, 2 }, { 4, 63, 0 } } },
682 { { { 24, 0, 1 }, { 13, 46, 0 } } },
683 { { { 24, 0, 0 }, { 5, 62, 0 } } },
684 { { { 24, 0, 1 }, { 5, 63, 0 } } },
685 { { { 24, 0, 2 }, { 6, 62, 0 } } },
686 { { { 25, 0, 1 }, { 14, 47, 0 } } },
687 { { { 25, 0, 0 }, { 6, 63, 0 } } },
688 { { { 25, 0, 1 }, { 7, 62, 0 } } },
689 { { { 25, 0, 2 }, { 7, 63, 0 } } },
690 { { { 26, 0, 1 }, { 16, 45, 0 } } },
691 { { { 26, 0, 0 }, { 8, 62, 0 } } },
692 { { { 26, 0, 1 }, { 8, 63, 0 } } },
693 { { { 26, 0, 2 }, { 9, 62, 0 } } },
694 { { { 27, 0, 1 }, { 16, 48, 0 } } },
695 { { { 27, 0, 0 }, { 9, 63, 0 } } },
696 { { { 27, 0, 1 }, { 10, 62, 0 } } },
697 { { { 27, 0, 2 }, { 10, 63, 0 } } },
698 { { { 28, 0, 1 }, { 16, 51, 0 } } },
699 { { { 28, 0, 0 }, { 11, 62, 0 } } },
700 { { { 28, 0, 1 }, { 11, 63, 0 } } },
701 { { { 28, 0, 2 }, { 12, 62, 0 } } },
702 { { { 29, 0, 1 }, { 16, 54, 0 } } },
703 { { { 29, 0, 0 }, { 12, 63, 0 } } },
704 { { { 29, 0, 1 }, { 13, 62, 0 } } },
705 { { { 29, 0, 2 }, { 13, 63, 0 } } },
706 { { { 30, 0, 1 }, { 16, 57, 0 } } },
707 { { { 30, 0, 0 }, { 14, 62, 0 } } },
708 { { { 30, 0, 1 }, { 14, 63, 0 } } },
709 { { { 30, 0, 2 }, { 15, 62, 0 } } },
710 { { { 31, 0, 1 }, { 16, 60, 0 } } },
711 { { { 31, 0, 0 }, { 15, 63, 0 } } },
712 { { { 31, 0, 1 }, { 24, 46, 0 } } },
713 { { { 31, 0, 2 }, { 16, 62, 0 } } },
714 { { { 32, 0, 2 }, { 16, 63, 0 } } },
715 { { { 32, 0, 1 }, { 17, 62, 0 } } },
716 { { { 32, 0, 0 }, { 25, 47, 0 } } },
717 { { { 32, 0, 1 }, { 17, 63, 0 } } },
718 { { { 32, 0, 2 }, { 18, 62, 0 } } },
719 { { { 33, 0, 1 }, { 18, 63, 0 } } },
720 { { { 33, 0, 0 }, { 27, 46, 0 } } },
721 { { { 33, 0, 1 }, { 19, 62, 0 } } },
722 { { { 33, 0, 2 }, { 19, 63, 0 } } },
723 { { { 34, 0, 1 }, { 20, 62, 0 } } },
724 { { { 34, 0, 0 }, { 28, 47, 0 } } },
725 { { { 34, 0, 1 }, { 20, 63, 0 } } },
726 { { { 34, 0, 2 }, { 21, 62, 0 } } },
727 { { { 35, 0, 1 }, { 21, 63, 0 } } },
728 { { { 35, 0, 0 }, { 30, 46, 0 } } },
729 { { { 35, 0, 1 }, { 22, 62, 0 } } },
730 { { { 35, 0, 2 }, { 22, 63, 0 } } },
731 { { { 36, 0, 1 }, { 23, 62, 0 } } },
732 { { { 36, 0, 0 }, { 31, 47, 0 } } },
733 { { { 36, 0, 1 }, { 23, 63, 0 } } },
734 { { { 36, 0, 2 }, { 24, 62, 0 } } },
735 { { { 37, 0, 1 }, { 24, 63, 0 } } },
736 { { { 37, 0, 0 }, { 32, 47, 0 } } },
737 { { { 37, 0, 1 }, { 25, 62, 0 } } },
738 { { { 37, 0, 2 }, { 25, 63, 0 } } },
739 { { { 38, 0, 1 }, { 26, 62, 0 } } },
740 { { { 38, 0, 0 }, { 32, 50, 0 } } },
741 { { { 38, 0, 1 }, { 26, 63, 0 } } },
742 { { { 38, 0, 2 }, { 27, 62, 0 } } },
743 { { { 39, 0, 1 }, { 27, 63, 0 } } },
744 { { { 39, 0, 0 }, { 32, 53, 0 } } },
745 { { { 39, 0, 1 }, { 28, 62, 0 } } },
746 { { { 39, 0, 2 }, { 28, 63, 0 } } },
747 { { { 40, 0, 1 }, { 29, 62, 0 } } },
748 { { { 40, 0, 0 }, { 32, 56, 0 } } },
749 { { { 40, 0, 1 }, { 29, 63, 0 } } },
750 { { { 40, 0, 2 }, { 30, 62, 0 } } },
751 { { { 41, 0, 1 }, { 30, 63, 0 } } },
752 { { { 41, 0, 0 }, { 32, 59, 0 } } },
753 { { { 41, 0, 1 }, { 31, 62, 0 } } },
754 { { { 41, 0, 2 }, { 31, 63, 0 } } },
755 { { { 42, 0, 1 }, { 32, 61, 0 } } },
756 { { { 42, 0, 0 }, { 32, 62, 0 } } },
757 { { { 42, 0, 1 }, { 32, 63, 0 } } },
758 { { { 42, 0, 2 }, { 41, 46, 0 } } },
759 { { { 43, 0, 1 }, { 33, 62, 0 } } },
760 { { { 43, 0, 0 }, { 33, 63, 0 } } },
761 { { { 43, 0, 1 }, { 34, 62, 0 } } },
762 { { { 43, 0, 2 }, { 42, 47, 0 } } },
763 { { { 44, 0, 1 }, { 34, 63, 0 } } },
764 { { { 44, 0, 0 }, { 35, 62, 0 } } },
765 { { { 44, 0, 1 }, { 35, 63, 0 } } },
766 { { { 44, 0, 2 }, { 44, 46, 0 } } },
767 { { { 45, 0, 1 }, { 36, 62, 0 } } },
768 { { { 45, 0, 0 }, { 36, 63, 0 } } },
769 { { { 45, 0, 1 }, { 37, 62, 0 } } },
770 { { { 45, 0, 2 }, { 45, 47, 0 } } },
771 { { { 46, 0, 1 }, { 37, 63, 0 } } },
772 { { { 46, 0, 0 }, { 38, 62, 0 } } },
773 { { { 46, 0, 1 }, { 38, 63, 0 } } },
774 { { { 46, 0, 2 }, { 47, 46, 0 } } },
775 { { { 47, 0, 1 }, { 39, 62, 0 } } },
776 { { { 47, 0, 0 }, { 39, 63, 0 } } },
777 { { { 47, 0, 1 }, { 40, 62, 0 } } },
778 { { { 47, 0, 2 }, { 48, 46, 0 } } },
779 { { { 48, 0, 2 }, { 40, 63, 0 } } },
780 { { { 48, 0, 1 }, { 41, 62, 0 } } },
781 { { { 48, 0, 0 }, { 41, 63, 0 } } },
782 { { { 48, 0, 1 }, { 48, 49, 0 } } },
783 { { { 48, 0, 2 }, { 42, 62, 0 } } },
784 { { { 49, 0, 1 }, { 42, 63, 0 } } },
785 { { { 49, 0, 0 }, { 43, 62, 0 } } },
786 { { { 49, 0, 1 }, { 48, 52, 0 } } },
787 { { { 49, 0, 2 }, { 43, 63, 0 } } },
788 { { { 50, 0, 1 }, { 44, 62, 0 } } },
789 { { { 50, 0, 0 }, { 44, 63, 0 } } },
790 { { { 50, 0, 1 }, { 48, 55, 0 } } },
791 { { { 50, 0, 2 }, { 45, 62, 0 } } },
792 { { { 51, 0, 1 }, { 45, 63, 0 } } },
793 { { { 51, 0, 0 }, { 46, 62, 0 } } },
794 { { { 51, 0, 1 }, { 48, 58, 0 } } },
795 { { { 51, 0, 2 }, { 46, 63, 0 } } },
796 { { { 52, 0, 1 }, { 47, 62, 0 } } },
797 { { { 52, 0, 0 }, { 47, 63, 0 } } },
798 { { { 52, 0, 1 }, { 48, 61, 0 } } },
799 { { { 52, 0, 2 }, { 48, 62, 0 } } },
800 { { { 53, 0, 1 }, { 56, 47, 0 } } },
801 { { { 53, 0, 0 }, { 48, 63, 0 } } },
802 { { { 53, 0, 1 }, { 49, 62, 0 } } },
803 { { { 53, 0, 2 }, { 49, 63, 0 } } },
804 { { { 54, 0, 1 }, { 58, 46, 0 } } },
805 { { { 54, 0, 0 }, { 50, 62, 0 } } },
806 { { { 54, 0, 1 }, { 50, 63, 0 } } },
807 { { { 54, 0, 2 }, { 51, 62, 0 } } },
808 { { { 55, 0, 1 }, { 59, 47, 0 } } },
809 { { { 55, 0, 0 }, { 51, 63, 0 } } },
810 { { { 55, 0, 1 }, { 52, 62, 0 } } },
811 { { { 55, 0, 2 }, { 52, 63, 0 } } },
812 { { { 56, 0, 1 }, { 61, 46, 0 } } },
813 { { { 56, 0, 0 }, { 53, 62, 0 } } },
814 { { { 56, 0, 1 }, { 53, 63, 0 } } },
815 { { { 56, 0, 2 }, { 54, 62, 0 } } },
816 { { { 57, 0, 1 }, { 62, 47, 0 } } },
817 { { { 57, 0, 0 }, { 54, 63, 0 } } },
818 { { { 57, 0, 1 }, { 55, 62, 0 } } },
819 { { { 57, 0, 2 }, { 55, 63, 0 } } },
820 { { { 58, 0, 1 }, { 56, 62, 1 } } },
821 { { { 58, 0, 0 }, { 56, 62, 0 } } },
822 { { { 58, 0, 1 }, { 56, 63, 0 } } },
823 { { { 58, 0, 2 }, { 57, 62, 0 } } },
824 { { { 59, 0, 1 }, { 57, 63, 1 } } },
825 { { { 59, 0, 0 }, { 57, 63, 0 } } },
826 { { { 59, 0, 1 }, { 58, 62, 0 } } },
827 { { { 59, 0, 2 }, { 58, 63, 0 } } },
828 { { { 60, 0, 1 }, { 59, 62, 1 } } },
829 { { { 60, 0, 0 }, { 59, 62, 0 } } },
830 { { { 60, 0, 1 }, { 59, 63, 0 } } },
831 { { { 60, 0, 2 }, { 60, 62, 0 } } },
832 { { { 61, 0, 1 }, { 60, 63, 1 } } },
833 { { { 61, 0, 0 }, { 60, 63, 0 } } },
834 { { { 61, 0, 1 }, { 61, 62, 0 } } },
835 { { { 61, 0, 2 }, { 61, 63, 0 } } },
836 { { { 62, 0, 1 }, { 62, 62, 1 } } },
837 { { { 62, 0, 0 }, { 62, 62, 0 } } },
838 { { { 62, 0, 1 }, { 62, 63, 0 } } },
839 { { { 62, 0, 2 }, { 63, 62, 0 } } },
840 { { { 63, 0, 1 }, { 63, 63, 1 } } },
841 { { { 63, 0, 0 }, { 63, 63, 0 } } }
842 };
843
844 static const DDSSingleColorLookup*
845 DDS_LOOKUP[] =
846 {
847 DDSLookup_5_4,
848 DDSLookup_6_4,
849 DDSLookup_5_4
850 };
851
852 /*
853 Macros
854 */
855 #define C565_r(x) (((x) & 0xF800) >> 11)
856 #define C565_g(x) (((x) & 0x07E0) >> 5)
857 #define C565_b(x) ((x) & 0x001F)
858
859 #define C565_red(x) ( (C565_r(x) << 3 | C565_r(x) >> 2))
860 #define C565_green(x) ( (C565_g(x) << 2 | C565_g(x) >> 4))
861 #define C565_blue(x) ( (C565_b(x) << 3 | C565_b(x) >> 2))
862
863 #define DIV2(x) ((x) > 1 ? ((x) >> 1) : 1)
864
865 #define FixRange(min, max, steps) \
866 if (min > max) \
867 min = max; \
868 if ((ssize_t) max - min < steps) \
869 max = MagickMin(min + steps, 255); \
870 if ((ssize_t) max - min < steps) \
871 min = MagickMax(0, (ssize_t) max - steps)
872
873 #define Dot(left, right) (left.x*right.x) + (left.y*right.y) + (left.z*right.z)
874
875 #define VectorInit(vector, value) vector.x = vector.y = vector.z = vector.w \
876 = value
877 #define VectorInit3(vector, value) vector.x = vector.y = vector.z = value
878
879 #define IsBitMask(mask, r, g, b, a) (mask.r_bitmask == r && mask.g_bitmask == \
880 g && mask.b_bitmask == b && mask.alpha_bitmask == a)
881
882 /*
883 Forward declarations
884 */
885 static MagickBooleanType
886 WriteDDSImage(const ImageInfo *,Image *,ExceptionInfo *);
887
VectorAdd(const DDSVector4 left,const DDSVector4 right,DDSVector4 * destination)888 static inline void VectorAdd(const DDSVector4 left, const DDSVector4 right,
889 DDSVector4 *destination)
890 {
891 destination->x = left.x + right.x;
892 destination->y = left.y + right.y;
893 destination->z = left.z + right.z;
894 destination->w = left.w + right.w;
895 }
896
VectorClamp(DDSVector4 * value)897 static inline void VectorClamp(DDSVector4 *value)
898 {
899 value->x = MagickMin(1.0f,MagickMax(0.0f,value->x));
900 value->y = MagickMin(1.0f,MagickMax(0.0f,value->y));
901 value->z = MagickMin(1.0f,MagickMax(0.0f,value->z));
902 value->w = MagickMin(1.0f,MagickMax(0.0f,value->w));
903 }
904
VectorClamp3(DDSVector3 * value)905 static inline void VectorClamp3(DDSVector3 *value)
906 {
907 value->x = MagickMin(1.0f,MagickMax(0.0f,value->x));
908 value->y = MagickMin(1.0f,MagickMax(0.0f,value->y));
909 value->z = MagickMin(1.0f,MagickMax(0.0f,value->z));
910 }
911
VectorCopy43(const DDSVector4 source,DDSVector3 * destination)912 static inline void VectorCopy43(const DDSVector4 source,
913 DDSVector3 *destination)
914 {
915 destination->x = source.x;
916 destination->y = source.y;
917 destination->z = source.z;
918 }
919
VectorCopy44(const DDSVector4 source,DDSVector4 * destination)920 static inline void VectorCopy44(const DDSVector4 source,
921 DDSVector4 *destination)
922 {
923 destination->x = source.x;
924 destination->y = source.y;
925 destination->z = source.z;
926 destination->w = source.w;
927 }
928
VectorNegativeMultiplySubtract(const DDSVector4 a,const DDSVector4 b,const DDSVector4 c,DDSVector4 * destination)929 static inline void VectorNegativeMultiplySubtract(const DDSVector4 a,
930 const DDSVector4 b, const DDSVector4 c, DDSVector4 *destination)
931 {
932 destination->x = c.x - (a.x * b.x);
933 destination->y = c.y - (a.y * b.y);
934 destination->z = c.z - (a.z * b.z);
935 destination->w = c.w - (a.w * b.w);
936 }
937
VectorMultiply(const DDSVector4 left,const DDSVector4 right,DDSVector4 * destination)938 static inline void VectorMultiply(const DDSVector4 left,
939 const DDSVector4 right, DDSVector4 *destination)
940 {
941 destination->x = left.x * right.x;
942 destination->y = left.y * right.y;
943 destination->z = left.z * right.z;
944 destination->w = left.w * right.w;
945 }
946
VectorMultiply3(const DDSVector3 left,const DDSVector3 right,DDSVector3 * destination)947 static inline void VectorMultiply3(const DDSVector3 left,
948 const DDSVector3 right, DDSVector3 *destination)
949 {
950 destination->x = left.x * right.x;
951 destination->y = left.y * right.y;
952 destination->z = left.z * right.z;
953 }
954
VectorMultiplyAdd(const DDSVector4 a,const DDSVector4 b,const DDSVector4 c,DDSVector4 * destination)955 static inline void VectorMultiplyAdd(const DDSVector4 a, const DDSVector4 b,
956 const DDSVector4 c, DDSVector4 *destination)
957 {
958 destination->x = (a.x * b.x) + c.x;
959 destination->y = (a.y * b.y) + c.y;
960 destination->z = (a.z * b.z) + c.z;
961 destination->w = (a.w * b.w) + c.w;
962 }
963
VectorMultiplyAdd3(const DDSVector3 a,const DDSVector3 b,const DDSVector3 c,DDSVector3 * destination)964 static inline void VectorMultiplyAdd3(const DDSVector3 a, const DDSVector3 b,
965 const DDSVector3 c, DDSVector3 *destination)
966 {
967 destination->x = (a.x * b.x) + c.x;
968 destination->y = (a.y * b.y) + c.y;
969 destination->z = (a.z * b.z) + c.z;
970 }
971
VectorReciprocal(const DDSVector4 value,DDSVector4 * destination)972 static inline void VectorReciprocal(const DDSVector4 value,
973 DDSVector4 *destination)
974 {
975 destination->x = 1.0f / value.x;
976 destination->y = 1.0f / value.y;
977 destination->z = 1.0f / value.z;
978 destination->w = 1.0f / value.w;
979 }
980
VectorSubtract(const DDSVector4 left,const DDSVector4 right,DDSVector4 * destination)981 static inline void VectorSubtract(const DDSVector4 left,
982 const DDSVector4 right, DDSVector4 *destination)
983 {
984 destination->x = left.x - right.x;
985 destination->y = left.y - right.y;
986 destination->z = left.z - right.z;
987 destination->w = left.w - right.w;
988 }
989
VectorSubtract3(const DDSVector3 left,const DDSVector3 right,DDSVector3 * destination)990 static inline void VectorSubtract3(const DDSVector3 left,
991 const DDSVector3 right, DDSVector3 *destination)
992 {
993 destination->x = left.x - right.x;
994 destination->y = left.y - right.y;
995 destination->z = left.z - right.z;
996 }
997
VectorTruncate(DDSVector4 * value)998 static inline void VectorTruncate(DDSVector4 *value)
999 {
1000 value->x = value->x > 0.0f ? floor(value->x) : ceil(value->x);
1001 value->y = value->y > 0.0f ? floor(value->y) : ceil(value->y);
1002 value->z = value->z > 0.0f ? floor(value->z) : ceil(value->z);
1003 value->w = value->w > 0.0f ? floor(value->w) : ceil(value->w);
1004 }
1005
VectorTruncate3(DDSVector3 * value)1006 static inline void VectorTruncate3(DDSVector3 *value)
1007 {
1008 value->x = value->x > 0.0f ? floor(value->x) : ceil(value->x);
1009 value->y = value->y > 0.0f ? floor(value->y) : ceil(value->y);
1010 value->z = value->z > 0.0f ? floor(value->z) : ceil(value->z);
1011 }
1012
ClampToLimit(const float value,const size_t limit)1013 static inline size_t ClampToLimit(const float value, const size_t limit)
1014 {
1015 size_t
1016 result = (int) (value + 0.5f);
1017
1018 if (result < 0.0f)
1019 return(0);
1020 if (result > limit)
1021 return(limit);
1022 return result;
1023 }
1024
ColorTo565(const DDSVector3 point)1025 static inline size_t ColorTo565(const DDSVector3 point)
1026 {
1027 size_t r = ClampToLimit(31.0f*point.x,31);
1028 size_t g = ClampToLimit(63.0f*point.y,63);
1029 size_t b = ClampToLimit(31.0f*point.z,31);
1030
1031 return (r << 11) | (g << 5) | b;
1032 }
1033
1034 /*
1035 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1036 % %
1037 % %
1038 % %
1039 % I s D D S %
1040 % %
1041 % %
1042 % %
1043 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1044 %
1045 % IsDDS() returns MagickTrue if the image format type, identified by the
1046 % magick string, is DDS.
1047 %
1048 % The format of the IsDDS method is:
1049 %
1050 % MagickBooleanType IsDDS(const unsigned char *magick,const size_t length)
1051 %
1052 % A description of each parameter follows:
1053 %
1054 % o magick: compare image format pattern against these bytes.
1055 %
1056 % o length: Specifies the length of the magick string.
1057 %
1058 */
IsDDS(const unsigned char * magick,const size_t length)1059 static MagickBooleanType IsDDS(const unsigned char *magick, const size_t length)
1060 {
1061 if (length < 4)
1062 return(MagickFalse);
1063 if (LocaleNCompare((char *) magick,"DDS ", 4) == 0)
1064 return(MagickTrue);
1065 return(MagickFalse);
1066 }
1067
1068 /*
1069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1070 % %
1071 % %
1072 % %
1073 % R e a d D D S I m a g e %
1074 % %
1075 % %
1076 % %
1077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1078 %
1079 % ReadDDSImage() reads a DirectDraw Surface image file and returns it. It
1080 % allocates the memory necessary for the new Image structure and returns a
1081 % pointer to the new image.
1082 %
1083 % The format of the ReadDDSImage method is:
1084 %
1085 % Image *ReadDDSImage(const ImageInfo *image_info,ExceptionInfo *exception)
1086 %
1087 % A description of each parameter follows:
1088 %
1089 % o image_info: The image info.
1090 %
1091 % o exception: return any errors or warnings in this structure.
1092 %
1093 */
ReadDDSInfo(Image * image,DDSInfo * dds_info)1094 static MagickBooleanType ReadDDSInfo(Image *image, DDSInfo *dds_info)
1095 {
1096 size_t
1097 hdr_size,
1098 required;
1099
1100 /* Seek to start of header */
1101 (void) SeekBlob(image, 4, SEEK_SET);
1102
1103 /* Check header field */
1104 hdr_size = ReadBlobLSBLong(image);
1105 if (hdr_size != 124)
1106 return MagickFalse;
1107
1108 /* Fill in DDS info struct */
1109 dds_info->flags = ReadBlobLSBLong(image);
1110
1111 /* Check required flags */
1112 required=(size_t) (DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT);
1113 if ((dds_info->flags & required) != required)
1114 return MagickFalse;
1115
1116 dds_info->height = ReadBlobLSBLong(image);
1117 dds_info->width = ReadBlobLSBLong(image);
1118 dds_info->pitchOrLinearSize = ReadBlobLSBLong(image);
1119 dds_info->depth = ReadBlobLSBLong(image);
1120 dds_info->mipmapcount = ReadBlobLSBLong(image);
1121
1122 (void) SeekBlob(image, 44, SEEK_CUR); /* reserved region of 11 DWORDs */
1123
1124 /* Read pixel format structure */
1125 hdr_size = ReadBlobLSBLong(image);
1126 if (hdr_size != 32)
1127 return MagickFalse;
1128
1129 dds_info->pixelformat.flags = ReadBlobLSBLong(image);
1130 dds_info->pixelformat.fourcc = ReadBlobLSBLong(image);
1131 dds_info->pixelformat.rgb_bitcount = ReadBlobLSBLong(image);
1132 dds_info->pixelformat.r_bitmask = ReadBlobLSBLong(image);
1133 dds_info->pixelformat.g_bitmask = ReadBlobLSBLong(image);
1134 dds_info->pixelformat.b_bitmask = ReadBlobLSBLong(image);
1135 dds_info->pixelformat.alpha_bitmask = ReadBlobLSBLong(image);
1136
1137 dds_info->ddscaps1 = ReadBlobLSBLong(image);
1138 dds_info->ddscaps2 = ReadBlobLSBLong(image);
1139 (void) SeekBlob(image, 12, SEEK_CUR); /* 3 reserved DWORDs */
1140
1141 /* Read optional DX10 header if available */
1142 if ((dds_info->pixelformat.flags & DDPF_FOURCC) &&
1143 (dds_info->pixelformat.fourcc == FOURCC_DX10))
1144 {
1145 dds_info->extFormat = ReadBlobLSBLong(image);
1146 dds_info->extDimension = ReadBlobLSBLong(image);
1147 dds_info->extFlags = ReadBlobLSBLong(image);
1148 dds_info->extArraySize = ReadBlobLSBLong(image);
1149 dds_info->extFlags2 = ReadBlobLSBLong(image);
1150 }
1151 else
1152 {
1153 dds_info->extFormat = 0;
1154 dds_info->extDimension = 0;
1155 dds_info->extFlags = 0;
1156 dds_info->extArraySize = 0;
1157 dds_info->extFlags2 = 0;
1158 }
1159
1160 return MagickTrue;
1161 }
1162
SetDXT1Pixels(Image * image,ssize_t x,ssize_t y,DDSColors colors,size_t bits,Quantum * q)1163 static MagickBooleanType SetDXT1Pixels(Image *image,ssize_t x,ssize_t y,
1164 DDSColors colors,size_t bits,Quantum *q)
1165 {
1166 ssize_t
1167 i;
1168
1169 ssize_t
1170 j;
1171
1172 unsigned char
1173 code;
1174
1175 for (j = 0; j < 4; j++)
1176 {
1177 for (i = 0; i < 4; i++)
1178 {
1179 if ((x + i) < (ssize_t) image->columns &&
1180 (y + j) < (ssize_t) image->rows)
1181 {
1182 code=(unsigned char) ((bits >> ((j*4+i)*2)) & 0x3);
1183 SetPixelRed(image,ScaleCharToQuantum(colors.r[code]),q);
1184 SetPixelGreen(image,ScaleCharToQuantum(colors.g[code]),q);
1185 SetPixelBlue(image,ScaleCharToQuantum(colors.b[code]),q);
1186 SetPixelOpacity(image,ScaleCharToQuantum(colors.a[code]),q);
1187 if ((colors.a[code] != 0) &&
1188 (image->alpha_trait == UndefinedPixelTrait))
1189 return(MagickFalse);
1190 q+=GetPixelChannels(image);
1191 }
1192 }
1193 }
1194 return(MagickTrue);
1195 }
1196
ReadMipmaps(const ImageInfo * image_info,Image * image,DDSInfo * dds_info,DDSPixelDecoder decoder,ExceptionInfo * exception)1197 static MagickBooleanType ReadMipmaps(const ImageInfo *image_info,Image *image,
1198 DDSInfo *dds_info,DDSPixelDecoder decoder,ExceptionInfo *exception)
1199 {
1200 MagickBooleanType
1201 status;
1202
1203 /*
1204 Only skip mipmaps for textures and cube maps
1205 */
1206 if (EOFBlob(image) != MagickFalse)
1207 {
1208 ThrowFileException(exception,CorruptImageWarning,"UnexpectedEndOfFile",
1209 image->filename);
1210 return(MagickFalse);
1211 }
1212 status=MagickTrue;
1213 if (dds_info->ddscaps1 & DDSCAPS_MIPMAP
1214 && (dds_info->ddscaps1 & DDSCAPS_TEXTURE
1215 || dds_info->ddscaps2 & DDSCAPS2_CUBEMAP))
1216 {
1217 ssize_t
1218 i;
1219
1220 size_t
1221 h,
1222 w;
1223
1224 w=DIV2(dds_info->width);
1225 h=DIV2(dds_info->height);
1226
1227 /*
1228 Mipmapcount includes the main image, so start from one
1229 */
1230 for (i = 1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)
1231 {
1232 AcquireNextImage(image_info,image,exception);
1233 if (image->next == (Image *) NULL)
1234 return(MagickFalse);
1235 image->next->alpha_trait=image->alpha_trait;
1236 image=SyncNextImageInList(image);
1237 status=SetImageExtent(image,w,h,exception);
1238 if (status == MagickFalse)
1239 break;
1240 status=decoder(image,dds_info,exception);
1241 if (status == MagickFalse)
1242 break;
1243 if ((w == 1) && (h == 1))
1244 break;
1245
1246 w=DIV2(w);
1247 h=DIV2(h);
1248 }
1249 }
1250 return(status);
1251 }
1252
CalculateColors(unsigned short c0,unsigned short c1,DDSColors * c,MagickBooleanType ignoreAlpha)1253 static void CalculateColors(unsigned short c0, unsigned short c1,
1254 DDSColors *c, MagickBooleanType ignoreAlpha)
1255 {
1256 c->a[0] = c->a[1] = c->a[2] = c->a[3] = 0;
1257
1258 c->r[0] = (unsigned char) C565_red(c0);
1259 c->g[0] = (unsigned char) C565_green(c0);
1260 c->b[0] = (unsigned char) C565_blue(c0);
1261
1262 c->r[1] = (unsigned char) C565_red(c1);
1263 c->g[1] = (unsigned char) C565_green(c1);
1264 c->b[1] = (unsigned char) C565_blue(c1);
1265
1266 if (ignoreAlpha != MagickFalse || c0 > c1)
1267 {
1268 c->r[2] = (unsigned char) ((2 * c->r[0] + c->r[1]) / 3);
1269 c->g[2] = (unsigned char) ((2 * c->g[0] + c->g[1]) / 3);
1270 c->b[2] = (unsigned char) ((2 * c->b[0] + c->b[1]) / 3);
1271
1272 c->r[3] = (unsigned char) ((c->r[0] + 2 * c->r[1]) / 3);
1273 c->g[3] = (unsigned char) ((c->g[0] + 2 * c->g[1]) / 3);
1274 c->b[3] = (unsigned char) ((c->b[0] + 2 * c->b[1]) / 3);
1275 }
1276 else
1277 {
1278 c->r[2] = (unsigned char) ((c->r[0] + c->r[1]) / 2);
1279 c->g[2] = (unsigned char) ((c->g[0] + c->g[1]) / 2);
1280 c->b[2] = (unsigned char) ((c->b[0] + c->b[1]) / 2);
1281
1282 c->r[3] = c->g[3] = c->b[3] = 0;
1283 c->a[3] = 255;
1284 }
1285 }
1286
ReadDXT1Pixels(Image * image,DDSInfo * magick_unused (dds_info),ExceptionInfo * exception)1287 static MagickBooleanType ReadDXT1Pixels(Image *image,
1288 DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
1289 {
1290 DDSColors
1291 colors;
1292
1293 Quantum
1294 *q;
1295
1296 ssize_t
1297 x;
1298
1299 size_t
1300 bits;
1301
1302 ssize_t
1303 y;
1304
1305 unsigned short
1306 c0,
1307 c1;
1308
1309 magick_unreferenced(dds_info);
1310 for (y = 0; y < (ssize_t) image->rows; y += 4)
1311 {
1312 for (x = 0; x < (ssize_t) image->columns; x += 4)
1313 {
1314 /* Get 4x4 patch of pixels to write on */
1315 q=QueueAuthenticPixels(image,x,y,MagickMin(4,image->columns-x),
1316 MagickMin(4,image->rows-y),exception);
1317
1318 if (q == (Quantum *) NULL)
1319 return(MagickFalse);
1320
1321 /* Read 8 bytes of data from the image */
1322 c0=ReadBlobLSBShort(image);
1323 c1=ReadBlobLSBShort(image);
1324 bits=ReadBlobLSBLong(image);
1325
1326 CalculateColors(c0,c1,&colors,MagickFalse);
1327 if (EOFBlob(image) != MagickFalse)
1328 return(MagickFalse);
1329
1330 /* Write the pixels */
1331 if (SetDXT1Pixels(image,x,y,colors,bits,q) == MagickFalse)
1332 {
1333 /* Correct alpha */
1334 SetImageAlpha(image,QuantumRange,exception);
1335 q=QueueAuthenticPixels(image,x,y,MagickMin(4,image->columns-x),
1336 MagickMin(4,image->rows-y),exception);
1337 if (q != (Quantum *) NULL)
1338 SetDXT1Pixels(image,x,y,colors,bits,q);
1339 }
1340 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1341 return(MagickFalse);
1342 }
1343 if (EOFBlob(image) != MagickFalse)
1344 return(MagickFalse);
1345 }
1346 return(MagickTrue);
1347 }
1348
1349 /*
1350 Skip the mipmap images for compressed (DXTn) dds files
1351 */
SkipDXTMipmaps(Image * image,DDSInfo * dds_info,int texel_size,ExceptionInfo * exception)1352 static MagickBooleanType SkipDXTMipmaps(Image *image,DDSInfo *dds_info,
1353 int texel_size,ExceptionInfo *exception)
1354 {
1355 /*
1356 Only skip mipmaps for textures and cube maps
1357 */
1358 if (EOFBlob(image) != MagickFalse)
1359 {
1360 ThrowFileException(exception,CorruptImageWarning,"UnexpectedEndOfFile",
1361 image->filename);
1362 return(MagickFalse);
1363 }
1364 if (dds_info->ddscaps1 & DDSCAPS_MIPMAP
1365 && (dds_info->ddscaps1 & DDSCAPS_TEXTURE
1366 || dds_info->ddscaps2 & DDSCAPS2_CUBEMAP))
1367 {
1368 MagickOffsetType
1369 offset;
1370
1371 ssize_t
1372 i;
1373
1374 size_t
1375 h,
1376 w;
1377
1378 w=DIV2(dds_info->width);
1379 h=DIV2(dds_info->height);
1380
1381 /*
1382 Mipmapcount includes the main image, so start from one
1383 */
1384 for (i = 1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)
1385 {
1386 offset=(MagickOffsetType)((w+3)/4)*((h+3)/4)*texel_size;
1387 if (SeekBlob(image,offset,SEEK_CUR) < 0)
1388 break;
1389 w=DIV2(w);
1390 h=DIV2(h);
1391 if ((w == 1) && (h == 1))
1392 break;
1393 }
1394 }
1395 return(MagickTrue);
1396 }
1397
ReadDXT1(const ImageInfo * image_info,Image * image,DDSInfo * dds_info,const MagickBooleanType read_mipmaps,ExceptionInfo * exception)1398 static MagickBooleanType ReadDXT1(const ImageInfo *image_info,Image *image,
1399 DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1400 ExceptionInfo *exception)
1401 {
1402 if (ReadDXT1Pixels(image,dds_info,exception) == MagickFalse)
1403 return(MagickFalse);
1404
1405 if (read_mipmaps != MagickFalse)
1406 return(ReadMipmaps(image_info,image,dds_info,ReadDXT1Pixels,exception));
1407 else
1408 return(SkipDXTMipmaps(image,dds_info,8,exception));
1409 }
1410
ReadDXT3Pixels(Image * image,DDSInfo * magick_unused (dds_info),ExceptionInfo * exception)1411 static MagickBooleanType ReadDXT3Pixels(Image *image,
1412 DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
1413 {
1414 DDSColors
1415 colors;
1416
1417 Quantum
1418 *q;
1419
1420 ssize_t
1421 i,
1422 x;
1423
1424 unsigned char
1425 alpha;
1426
1427 size_t
1428 a0,
1429 a1,
1430 bits,
1431 code;
1432
1433 ssize_t
1434 j,
1435 y;
1436
1437 unsigned short
1438 c0,
1439 c1;
1440
1441 magick_unreferenced(dds_info);
1442 for (y = 0; y < (ssize_t) image->rows; y += 4)
1443 {
1444 for (x = 0; x < (ssize_t) image->columns; x += 4)
1445 {
1446 /* Get 4x4 patch of pixels to write on */
1447 q = QueueAuthenticPixels(image, x, y, MagickMin(4, image->columns - x),
1448 MagickMin(4, image->rows - y),exception);
1449
1450 if (q == (Quantum *) NULL)
1451 return(MagickFalse);
1452
1453 /* Read alpha values (8 bytes) */
1454 a0 = ReadBlobLSBLong(image);
1455 a1 = ReadBlobLSBLong(image);
1456
1457 /* Read 8 bytes of data from the image */
1458 c0 = ReadBlobLSBShort(image);
1459 c1 = ReadBlobLSBShort(image);
1460 bits = ReadBlobLSBLong(image);
1461
1462 CalculateColors(c0, c1, &colors, MagickTrue);
1463
1464 if (EOFBlob(image) != MagickFalse)
1465 return(MagickFalse);
1466
1467 /* Write the pixels */
1468 for (j = 0; j < 4; j++)
1469 {
1470 for (i = 0; i < 4; i++)
1471 {
1472 if ((x + i) < (ssize_t) image->columns && (y + j) < (ssize_t) image->rows)
1473 {
1474 code = (bits >> ((4*j+i)*2)) & 0x3;
1475 SetPixelRed(image,ScaleCharToQuantum(colors.r[code]),q);
1476 SetPixelGreen(image,ScaleCharToQuantum(colors.g[code]),q);
1477 SetPixelBlue(image,ScaleCharToQuantum(colors.b[code]),q);
1478 /*
1479 Extract alpha value: multiply 0..15 by 17 to get range 0..255
1480 */
1481 if (j < 2)
1482 alpha = 17U * (unsigned char) ((a0 >> (4*(4*j+i))) & 0xf);
1483 else
1484 alpha = 17U * (unsigned char) ((a1 >> (4*(4*(j-2)+i))) & 0xf);
1485 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) alpha),q);
1486 q+=GetPixelChannels(image);
1487 }
1488 }
1489 }
1490 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1491 return(MagickFalse);
1492 }
1493 if (EOFBlob(image) != MagickFalse)
1494 return(MagickFalse);
1495 }
1496 return(MagickTrue);
1497 }
1498
ReadDXT3(const ImageInfo * image_info,Image * image,DDSInfo * dds_info,const MagickBooleanType read_mipmaps,ExceptionInfo * exception)1499 static MagickBooleanType ReadDXT3(const ImageInfo *image_info,Image *image,
1500 DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1501 ExceptionInfo *exception)
1502 {
1503 if (ReadDXT3Pixels(image,dds_info,exception) == MagickFalse)
1504 return(MagickFalse);
1505
1506 if (read_mipmaps != MagickFalse)
1507 return(ReadMipmaps(image_info,image,dds_info,ReadDXT3Pixels,exception));
1508 else
1509 return(SkipDXTMipmaps(image,dds_info,16,exception));
1510 }
1511
ReadDXT5Pixels(Image * image,DDSInfo * magick_unused (dds_info),ExceptionInfo * exception)1512 static MagickBooleanType ReadDXT5Pixels(Image *image,
1513 DDSInfo *magick_unused(dds_info),ExceptionInfo *exception)
1514 {
1515 DDSColors
1516 colors;
1517
1518 MagickSizeType
1519 alpha_bits;
1520
1521 Quantum
1522 *q;
1523
1524 ssize_t
1525 i,
1526 x;
1527
1528 unsigned char
1529 a0,
1530 a1;
1531
1532 size_t
1533 alpha,
1534 bits,
1535 code,
1536 alpha_code;
1537
1538 ssize_t
1539 j,
1540 y;
1541
1542 unsigned short
1543 c0,
1544 c1;
1545
1546 magick_unreferenced(dds_info);
1547 for (y = 0; y < (ssize_t) image->rows; y += 4)
1548 {
1549 for (x = 0; x < (ssize_t) image->columns; x += 4)
1550 {
1551 /* Get 4x4 patch of pixels to write on */
1552 q = QueueAuthenticPixels(image, x, y, MagickMin(4, image->columns - x),
1553 MagickMin(4, image->rows - y),exception);
1554
1555 if (q == (Quantum *) NULL)
1556 return(MagickFalse);
1557
1558 /* Read alpha values (8 bytes) */
1559 a0 = (unsigned char) ReadBlobByte(image);
1560 a1 = (unsigned char) ReadBlobByte(image);
1561
1562 alpha_bits = (MagickSizeType)ReadBlobLSBLong(image);
1563 alpha_bits = alpha_bits | ((MagickSizeType)ReadBlobLSBShort(image) << 32);
1564
1565 /* Read 8 bytes of data from the image */
1566 c0 = ReadBlobLSBShort(image);
1567 c1 = ReadBlobLSBShort(image);
1568 bits = ReadBlobLSBLong(image);
1569
1570 CalculateColors(c0, c1, &colors, MagickTrue);
1571 if (EOFBlob(image) != MagickFalse)
1572 return(MagickFalse);
1573
1574 /* Write the pixels */
1575 for (j = 0; j < 4; j++)
1576 {
1577 for (i = 0; i < 4; i++)
1578 {
1579 if ((x + i) < (ssize_t) image->columns &&
1580 (y + j) < (ssize_t) image->rows)
1581 {
1582 code = (bits >> ((4*j+i)*2)) & 0x3;
1583 SetPixelRed(image,ScaleCharToQuantum(colors.r[code]),q);
1584 SetPixelGreen(image,ScaleCharToQuantum(colors.g[code]),q);
1585 SetPixelBlue(image,ScaleCharToQuantum(colors.b[code]),q);
1586 /* Extract alpha value */
1587 alpha_code = (size_t) (alpha_bits >> (3*(4*j+i))) & 0x7;
1588 if (alpha_code == 0)
1589 alpha = a0;
1590 else if (alpha_code == 1)
1591 alpha = a1;
1592 else if (a0 > a1)
1593 alpha = ((8-alpha_code) * a0 + (alpha_code-1) * a1) / 7;
1594 else if (alpha_code == 6)
1595 alpha = 0;
1596 else if (alpha_code == 7)
1597 alpha = 255;
1598 else
1599 alpha = (((6-alpha_code) * a0 + (alpha_code-1) * a1) / 5);
1600 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char) alpha),q);
1601 q+=GetPixelChannels(image);
1602 }
1603 }
1604 }
1605 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1606 return(MagickFalse);
1607 }
1608 if (EOFBlob(image) != MagickFalse)
1609 return(MagickFalse);
1610 }
1611 return(MagickTrue);
1612 }
1613
ReadDXT5(const ImageInfo * image_info,Image * image,DDSInfo * dds_info,const MagickBooleanType read_mipmaps,ExceptionInfo * exception)1614 static MagickBooleanType ReadDXT5(const ImageInfo *image_info,Image *image,
1615 DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1616 ExceptionInfo *exception)
1617 {
1618 if (ReadDXT5Pixels(image,dds_info,exception) == MagickFalse)
1619 return(MagickFalse);
1620
1621 if (read_mipmaps != MagickFalse)
1622 return(ReadMipmaps(image_info,image,dds_info,ReadDXT5Pixels,exception));
1623 else
1624 return(SkipDXTMipmaps(image,dds_info,16,exception));
1625 }
1626
ReadUncompressedRGBPixels(Image * image,DDSInfo * dds_info,ExceptionInfo * exception)1627 static MagickBooleanType ReadUncompressedRGBPixels(Image *image,
1628 DDSInfo *dds_info,ExceptionInfo *exception)
1629 {
1630 Quantum
1631 *q;
1632
1633 ssize_t
1634 x, y;
1635
1636 unsigned short
1637 color;
1638
1639 for (y = 0; y < (ssize_t) image->rows; y++)
1640 {
1641 q = QueueAuthenticPixels(image, 0, y, image->columns, 1,exception);
1642
1643 if (q == (Quantum *) NULL)
1644 return(MagickFalse);
1645
1646 for (x = 0; x < (ssize_t) image->columns; x++)
1647 {
1648 if (dds_info->pixelformat.rgb_bitcount == 8 ||
1649 dds_info->extFormat == DXGI_FORMAT_R8_UNORM)
1650 SetPixelGray(image,ScaleCharToQuantum(ReadBlobByte(image)),q);
1651 else if (dds_info->pixelformat.rgb_bitcount == 16 ||
1652 dds_info->extFormat == DXGI_FORMAT_B5G6R5_UNORM)
1653 {
1654 color=ReadBlobShort(image);
1655 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1656 (((color >> 11)/31.0)*255)),q);
1657 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1658 ((((unsigned short)(color << 5) >> 10)/63.0)*255)),q);
1659 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1660 ((((unsigned short)(color << 11) >> 11)/31.0)*255)),q);
1661 }
1662 else
1663 {
1664 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1665 ReadBlobByte(image)),q);
1666 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1667 ReadBlobByte(image)),q);
1668 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1669 ReadBlobByte(image)),q);
1670 if (dds_info->pixelformat.rgb_bitcount == 32 ||
1671 dds_info->extFormat == DXGI_FORMAT_B8G8R8X8_UNORM)
1672 (void) ReadBlobByte(image);
1673 }
1674 q+=GetPixelChannels(image);
1675 }
1676 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1677 return(MagickFalse);
1678 if (EOFBlob(image) != MagickFalse)
1679 return(MagickFalse);
1680 }
1681 return(MagickTrue);
1682 }
1683
1684 /*
1685 Skip the mipmap images for uncompressed (RGB or RGBA) dds files
1686 */
SkipRGBMipmaps(Image * image,DDSInfo * dds_info,int pixel_size,ExceptionInfo * exception)1687 static MagickBooleanType SkipRGBMipmaps(Image *image,DDSInfo *dds_info,
1688 int pixel_size,ExceptionInfo *exception)
1689 {
1690 /*
1691 Only skip mipmaps for textures and cube maps
1692 */
1693 if (EOFBlob(image) != MagickFalse)
1694 {
1695 ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
1696 image->filename);
1697 return(MagickFalse);
1698 }
1699 if (dds_info->ddscaps1 & DDSCAPS_MIPMAP
1700 && (dds_info->ddscaps1 & DDSCAPS_TEXTURE
1701 || dds_info->ddscaps2 & DDSCAPS2_CUBEMAP))
1702 {
1703 MagickOffsetType
1704 offset;
1705
1706 ssize_t
1707 i;
1708
1709 size_t
1710 h,
1711 w;
1712
1713 w=DIV2(dds_info->width);
1714 h=DIV2(dds_info->height);
1715
1716 /*
1717 Mipmapcount includes the main image, so start from one
1718 */
1719 for (i=1; (i < (ssize_t) dds_info->mipmapcount) && w && h; i++)
1720 {
1721 offset=(MagickOffsetType)w*h*pixel_size;
1722 if (SeekBlob(image,offset,SEEK_CUR) < 0)
1723 break;
1724 w=DIV2(w);
1725 h=DIV2(h);
1726 if ((w == 1) && (h == 1))
1727 break;
1728 }
1729 }
1730 return(MagickTrue);
1731 }
1732
ReadUncompressedRGB(const ImageInfo * image_info,Image * image,DDSInfo * dds_info,const MagickBooleanType read_mipmaps,ExceptionInfo * exception)1733 static MagickBooleanType ReadUncompressedRGB(const ImageInfo *image_info,
1734 Image *image,DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1735 ExceptionInfo *exception)
1736 {
1737 if (dds_info->pixelformat.rgb_bitcount == 8 ||
1738 dds_info->extFormat == DXGI_FORMAT_R8_UNORM)
1739 (void) SetImageType(image,GrayscaleType,exception);
1740 else if (dds_info->pixelformat.rgb_bitcount == 16 && !IsBitMask(
1741 dds_info->pixelformat,0xf800,0x07e0,0x001f,0x0000))
1742 ThrowBinaryException(CorruptImageError,"ImageTypeNotSupported",
1743 image->filename);
1744
1745 if (ReadUncompressedRGBPixels(image,dds_info,exception) == MagickFalse)
1746 return(MagickFalse);
1747
1748 if (read_mipmaps != MagickFalse)
1749 return(ReadMipmaps(image_info,image,dds_info,ReadUncompressedRGBPixels,
1750 exception));
1751 else
1752 return(SkipRGBMipmaps(image,dds_info,3,exception));
1753 }
1754
ReadUncompressedRGBAPixels(Image * image,DDSInfo * dds_info,ExceptionInfo * exception)1755 static MagickBooleanType ReadUncompressedRGBAPixels(Image *image,
1756 DDSInfo *dds_info,ExceptionInfo *exception)
1757 {
1758 Quantum
1759 *q;
1760
1761 ssize_t
1762 alphaBits,
1763 x,
1764 y;
1765
1766 unsigned short
1767 color;
1768
1769 alphaBits=0;
1770 if (dds_info->pixelformat.rgb_bitcount == 16)
1771 {
1772 if (IsBitMask(dds_info->pixelformat,0x7c00,0x03e0,0x001f,0x8000))
1773 alphaBits=1;
1774 else if (IsBitMask(dds_info->pixelformat,0x00ff,0x00ff,0x00ff,0xff00))
1775 {
1776 alphaBits=2;
1777 (void) SetImageType(image,GrayscaleAlphaType,exception);
1778 }
1779 else if (IsBitMask(dds_info->pixelformat,0x0f00,0x00f0,0x000f,0xf000))
1780 alphaBits=4;
1781 else
1782 ThrowBinaryException(CorruptImageError,"ImageTypeNotSupported",
1783 image->filename);
1784 }
1785
1786 if (dds_info->extFormat == DXGI_FORMAT_B5G5R5A1_UNORM)
1787 alphaBits=1;
1788
1789 for (y = 0; y < (ssize_t) image->rows; y++)
1790 {
1791 q = QueueAuthenticPixels(image, 0, y, image->columns, 1,exception);
1792
1793 if (q == (Quantum *) NULL)
1794 return(MagickFalse);
1795
1796 for (x = 0; x < (ssize_t) image->columns; x++)
1797 {
1798 if (dds_info->pixelformat.rgb_bitcount == 16 ||
1799 dds_info->extFormat == DXGI_FORMAT_B5G5R5A1_UNORM)
1800 {
1801 color=ReadBlobShort(image);
1802 if (alphaBits == 1)
1803 {
1804 SetPixelAlpha(image,(color & (1 << 15)) ? QuantumRange : 0,q);
1805 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1806 ((((unsigned short)(color << 1) >> 11)/31.0)*255)),q);
1807 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1808 ((((unsigned short)(color << 6) >> 11)/31.0)*255)),q);
1809 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1810 ((((unsigned short)(color << 11) >> 11)/31.0)*255)),q);
1811 }
1812 else if (alphaBits == 2)
1813 {
1814 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1815 (color >> 8)),q);
1816 SetPixelGray(image,ScaleCharToQuantum((unsigned char)color),q);
1817 }
1818 else
1819 {
1820 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1821 (((color >> 12)/15.0)*255)),q);
1822 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1823 ((((unsigned short)(color << 4) >> 12)/15.0)*255)),q);
1824 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1825 ((((unsigned short)(color << 8) >> 12)/15.0)*255)),q);
1826 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1827 ((((unsigned short)(color << 12) >> 12)/15.0)*255)),q);
1828 }
1829 }
1830 else if (dds_info->extFormat == DXGI_FORMAT_R8G8B8A8_UNORM ||
1831 IsBitMask(dds_info->pixelformat,0x000000ff,0x0000ff00,0x00ff0000,0xff000000))
1832 {
1833 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1834 ReadBlobByte(image)),q);
1835 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1836 ReadBlobByte(image)),q);
1837 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1838 ReadBlobByte(image)),q);
1839 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1840 ReadBlobByte(image)),q);
1841 }
1842 else
1843 {
1844 SetPixelBlue(image,ScaleCharToQuantum((unsigned char)
1845 ReadBlobByte(image)),q);
1846 SetPixelGreen(image,ScaleCharToQuantum((unsigned char)
1847 ReadBlobByte(image)),q);
1848 SetPixelRed(image,ScaleCharToQuantum((unsigned char)
1849 ReadBlobByte(image)),q);
1850 SetPixelAlpha(image,ScaleCharToQuantum((unsigned char)
1851 ReadBlobByte(image)),q);
1852 }
1853 q+=GetPixelChannels(image);
1854 }
1855 if (SyncAuthenticPixels(image,exception) == MagickFalse)
1856 return(MagickFalse);
1857 if (EOFBlob(image) != MagickFalse)
1858 return(MagickFalse);
1859 }
1860 return(MagickTrue);
1861 }
1862
ReadUncompressedRGBA(const ImageInfo * image_info,Image * image,DDSInfo * dds_info,const MagickBooleanType read_mipmaps,ExceptionInfo * exception)1863 static MagickBooleanType ReadUncompressedRGBA(const ImageInfo *image_info,
1864 Image *image,DDSInfo *dds_info,const MagickBooleanType read_mipmaps,
1865 ExceptionInfo *exception)
1866 {
1867 if (ReadUncompressedRGBAPixels(image,dds_info,exception) == MagickFalse)
1868 return(MagickFalse);
1869
1870 if (read_mipmaps != MagickFalse)
1871 return(ReadMipmaps(image_info,image,dds_info,ReadUncompressedRGBAPixels,
1872 exception));
1873 else
1874 return(SkipRGBMipmaps(image,dds_info,4,exception));
1875 }
1876
ReadDDSImage(const ImageInfo * image_info,ExceptionInfo * exception)1877 static Image *ReadDDSImage(const ImageInfo *image_info,ExceptionInfo *exception)
1878 {
1879 const char
1880 *option;
1881
1882 CompressionType
1883 compression;
1884
1885 DDSInfo
1886 dds_info;
1887
1888 DDSDecoder
1889 *decoder;
1890
1891 Image
1892 *image;
1893
1894 MagickBooleanType
1895 status,
1896 cubemap,
1897 volume,
1898 read_mipmaps;
1899
1900 PixelTrait
1901 alpha_trait;
1902
1903 size_t
1904 n,
1905 num_images;
1906
1907 /*
1908 Open image file.
1909 */
1910 assert(image_info != (const ImageInfo *) NULL);
1911 assert(image_info->signature == MagickCoreSignature);
1912 if (image_info->debug != MagickFalse)
1913 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
1914 image_info->filename);
1915 assert(exception != (ExceptionInfo *) NULL);
1916 assert(exception->signature == MagickCoreSignature);
1917 cubemap=MagickFalse,
1918 volume=MagickFalse,
1919 read_mipmaps=MagickFalse;
1920 image=AcquireImage(image_info,exception);
1921 status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
1922 if (status == MagickFalse)
1923 {
1924 image=DestroyImageList(image);
1925 return((Image *) NULL);
1926 }
1927
1928 /*
1929 Initialize image structure.
1930 */
1931 if (ReadDDSInfo(image, &dds_info) != MagickTrue)
1932 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
1933
1934 if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP)
1935 cubemap = MagickTrue;
1936
1937 if (dds_info.ddscaps2 & DDSCAPS2_VOLUME && dds_info.depth > 0)
1938 volume = MagickTrue;
1939
1940 /*
1941 Determine pixel format
1942 */
1943 if (dds_info.pixelformat.flags & DDPF_RGB)
1944 {
1945 compression = NoCompression;
1946 if (dds_info.pixelformat.flags & DDPF_ALPHAPIXELS)
1947 {
1948 alpha_trait = BlendPixelTrait;
1949 decoder = ReadUncompressedRGBA;
1950 }
1951 else
1952 {
1953 alpha_trait = UndefinedPixelTrait;
1954 decoder = ReadUncompressedRGB;
1955 }
1956 }
1957 else if (dds_info.pixelformat.flags & DDPF_LUMINANCE)
1958 {
1959 compression = NoCompression;
1960 if (dds_info.pixelformat.flags & DDPF_ALPHAPIXELS)
1961 {
1962 /* Not sure how to handle this */
1963 ThrowReaderException(CorruptImageError, "ImageTypeNotSupported");
1964 }
1965 else
1966 {
1967 alpha_trait = UndefinedPixelTrait;
1968 decoder = ReadUncompressedRGB;
1969 }
1970 }
1971 else if (dds_info.pixelformat.flags & DDPF_FOURCC)
1972 {
1973 switch (dds_info.pixelformat.fourcc)
1974 {
1975 case FOURCC_DXT1:
1976 {
1977 alpha_trait = UndefinedPixelTrait;
1978 compression = DXT1Compression;
1979 decoder = ReadDXT1;
1980 break;
1981 }
1982 case FOURCC_DXT3:
1983 {
1984 alpha_trait = BlendPixelTrait;
1985 compression = DXT3Compression;
1986 decoder = ReadDXT3;
1987 break;
1988 }
1989 case FOURCC_DXT5:
1990 {
1991 alpha_trait = BlendPixelTrait;
1992 compression = DXT5Compression;
1993 decoder = ReadDXT5;
1994 break;
1995 }
1996 case FOURCC_DX10:
1997 {
1998 if (dds_info.extDimension != DDSEXT_DIMENSION_TEX2D)
1999 {
2000 ThrowReaderException(CorruptImageError, "ImageTypeNotSupported");
2001 }
2002
2003 switch (dds_info.extFormat)
2004 {
2005 case DXGI_FORMAT_R8_UNORM:
2006 {
2007 compression = NoCompression;
2008 alpha_trait = UndefinedPixelTrait;
2009 decoder = ReadUncompressedRGB;
2010 break;
2011 }
2012 case DXGI_FORMAT_B5G6R5_UNORM:
2013 {
2014 compression = NoCompression;
2015 alpha_trait = UndefinedPixelTrait;
2016 decoder = ReadUncompressedRGB;
2017 break;
2018 }
2019 case DXGI_FORMAT_B5G5R5A1_UNORM:
2020 {
2021 compression = NoCompression;
2022 alpha_trait = BlendPixelTrait;
2023 decoder = ReadUncompressedRGBA;
2024 break;
2025 }
2026 case DXGI_FORMAT_B8G8R8A8_UNORM:
2027 {
2028 compression = NoCompression;
2029 alpha_trait = BlendPixelTrait;
2030 decoder = ReadUncompressedRGBA;
2031 break;
2032 }
2033 case DXGI_FORMAT_R8G8B8A8_UNORM:
2034 {
2035 compression = NoCompression;
2036 alpha_trait = BlendPixelTrait;
2037 decoder = ReadUncompressedRGBA;
2038 break;
2039 }
2040 case DXGI_FORMAT_B8G8R8X8_UNORM:
2041 {
2042 compression = NoCompression;
2043 alpha_trait = UndefinedPixelTrait;
2044 decoder = ReadUncompressedRGB;
2045 break;
2046 }
2047 case DXGI_FORMAT_BC1_UNORM:
2048 {
2049 alpha_trait = UndefinedPixelTrait;
2050 compression = DXT1Compression;
2051 decoder = ReadDXT1;
2052 break;
2053 }
2054 case DXGI_FORMAT_BC2_UNORM:
2055 {
2056 alpha_trait = BlendPixelTrait;
2057 compression = DXT3Compression;
2058 decoder = ReadDXT3;
2059 break;
2060 }
2061 case DXGI_FORMAT_BC3_UNORM:
2062 {
2063 alpha_trait = BlendPixelTrait;
2064 compression = DXT5Compression;
2065 decoder = ReadDXT5;
2066 break;
2067 }
2068 default:
2069 {
2070 /* Unknown format */
2071 ThrowReaderException(CorruptImageError, "ImageTypeNotSupported");
2072 }
2073 }
2074
2075 if (dds_info.extFlags & DDSEXTFLAGS_CUBEMAP)
2076 cubemap = MagickTrue;
2077
2078 num_images = dds_info.extArraySize;
2079 break;
2080 }
2081 default:
2082 {
2083 /* Unknown FOURCC */
2084 ThrowReaderException(CorruptImageError, "ImageTypeNotSupported");
2085 }
2086 }
2087 }
2088 else
2089 {
2090 /* Neither compressed nor uncompressed... thus unsupported */
2091 ThrowReaderException(CorruptImageError, "ImageTypeNotSupported");
2092 }
2093
2094 num_images = 1;
2095 if (cubemap)
2096 {
2097 /*
2098 Determine number of faces defined in the cubemap
2099 */
2100 num_images = 0;
2101 if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_POSITIVEX) num_images++;
2102 if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) num_images++;
2103 if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_POSITIVEY) num_images++;
2104 if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) num_images++;
2105 if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) num_images++;
2106 if (dds_info.ddscaps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) num_images++;
2107 }
2108
2109 if (volume)
2110 num_images = dds_info.depth;
2111
2112 if ((num_images == 0) || (num_images > GetBlobSize(image)))
2113 ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2114
2115 if (AcquireMagickResource(ListLengthResource,num_images) == MagickFalse)
2116 ThrowReaderException(ResourceLimitError,"ListLengthExceedsLimit");
2117
2118 option=GetImageOption(image_info,"dds:skip-mipmaps");
2119 if (IsStringFalse(option) != MagickFalse)
2120 read_mipmaps=MagickTrue;
2121
2122 for (n = 0; n < num_images; n++)
2123 {
2124 if (n != 0)
2125 {
2126 /* Start a new image */
2127 if (EOFBlob(image) != MagickFalse)
2128 ThrowReaderException(CorruptImageError,"UnexpectedEndOfFile");
2129 AcquireNextImage(image_info,image,exception);
2130 if (GetNextImageInList(image) == (Image *) NULL)
2131 return(DestroyImageList(image));
2132 image=SyncNextImageInList(image);
2133 }
2134
2135 image->alpha_trait=alpha_trait;
2136 image->compression=compression;
2137 image->columns=dds_info.width;
2138 image->rows=dds_info.height;
2139 image->storage_class=DirectClass;
2140 image->endian=LSBEndian;
2141 image->depth=8;
2142 if (image_info->ping != MagickFalse)
2143 {
2144 (void) CloseBlob(image);
2145 return(GetFirstImageInList(image));
2146 }
2147 status=SetImageExtent(image,image->columns,image->rows,exception);
2148 if (status == MagickFalse)
2149 return(DestroyImageList(image));
2150 (void) SetImageBackgroundColor(image,exception);
2151 status=(decoder)(image_info,image,&dds_info,read_mipmaps,exception);
2152 if (status == MagickFalse)
2153 {
2154 (void) CloseBlob(image);
2155 if (n == 0)
2156 return(DestroyImageList(image));
2157 return(GetFirstImageInList(image));
2158 }
2159 }
2160 (void) CloseBlob(image);
2161 return(GetFirstImageInList(image));
2162 }
2163
2164 /*
2165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166 % %
2167 % %
2168 % %
2169 % R e g i s t e r D D S I m a g e %
2170 % %
2171 % %
2172 % %
2173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2174 %
2175 % RegisterDDSImage() adds attributes for the DDS image format to
2176 % the list of supported formats. The attributes include the image format
2177 % tag, a method to read and/or write the format, whether the format
2178 % supports the saving of more than one frame to the same file or blob,
2179 % whether the format supports native in-memory I/O, and a brief
2180 % description of the format.
2181 %
2182 % The format of the RegisterDDSImage method is:
2183 %
2184 % RegisterDDSImage(void)
2185 %
2186 */
RegisterDDSImage(void)2187 ModuleExport size_t RegisterDDSImage(void)
2188 {
2189 MagickInfo
2190 *entry;
2191
2192 entry = AcquireMagickInfo("DDS","DDS","Microsoft DirectDraw Surface");
2193 entry->decoder = (DecodeImageHandler *) ReadDDSImage;
2194 entry->encoder = (EncodeImageHandler *) WriteDDSImage;
2195 entry->magick = (IsImageFormatHandler *) IsDDS;
2196 entry->flags|=CoderDecoderSeekableStreamFlag;
2197 (void) RegisterMagickInfo(entry);
2198 entry = AcquireMagickInfo("DDS","DXT1","Microsoft DirectDraw Surface");
2199 entry->decoder = (DecodeImageHandler *) ReadDDSImage;
2200 entry->encoder = (EncodeImageHandler *) WriteDDSImage;
2201 entry->magick = (IsImageFormatHandler *) IsDDS;
2202 entry->flags|=CoderDecoderSeekableStreamFlag;
2203 (void) RegisterMagickInfo(entry);
2204 entry = AcquireMagickInfo("DDS","DXT5","Microsoft DirectDraw Surface");
2205 entry->decoder = (DecodeImageHandler *) ReadDDSImage;
2206 entry->encoder = (EncodeImageHandler *) WriteDDSImage;
2207 entry->magick = (IsImageFormatHandler *) IsDDS;
2208 entry->flags|=CoderDecoderSeekableStreamFlag;
2209 (void) RegisterMagickInfo(entry);
2210 return(MagickImageCoderSignature);
2211 }
2212
RemapIndices(const ssize_t * map,const unsigned char * source,unsigned char * target)2213 static void RemapIndices(const ssize_t *map, const unsigned char *source,
2214 unsigned char *target)
2215 {
2216 ssize_t
2217 i;
2218
2219 for (i = 0; i < 16; i++)
2220 {
2221 if (map[i] == -1)
2222 target[i] = 3;
2223 else
2224 target[i] = source[map[i]];
2225 }
2226 }
2227
2228 /*
2229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2230 % %
2231 % %
2232 % %
2233 % U n r e g i s t e r D D S I m a g e %
2234 % %
2235 % %
2236 % %
2237 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2238 %
2239 % UnregisterDDSImage() removes format registrations made by the
2240 % DDS module from the list of supported formats.
2241 %
2242 % The format of the UnregisterDDSImage method is:
2243 %
2244 % UnregisterDDSImage(void)
2245 %
2246 */
UnregisterDDSImage(void)2247 ModuleExport void UnregisterDDSImage(void)
2248 {
2249 (void) UnregisterMagickInfo("DDS");
2250 (void) UnregisterMagickInfo("DXT1");
2251 (void) UnregisterMagickInfo("DXT5");
2252 }
2253
2254 /*
2255 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2256 % %
2257 % %
2258 % %
2259 % W r i t e D D S I m a g e %
2260 % %
2261 % %
2262 % %
2263 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2264 %
2265 % WriteDDSImage() writes a DirectDraw Surface image file in the DXT5 format.
2266 %
2267 % The format of the WriteBMPImage method is:
2268 %
2269 % MagickBooleanType WriteDDSImage(const ImageInfo *image_info,Image *image)
2270 %
2271 % A description of each parameter follows.
2272 %
2273 % o image_info: the image info.
2274 %
2275 % o image: The image.
2276 %
2277 */
2278
CompressAlpha(const size_t min,const size_t max,const size_t steps,const ssize_t * alphas,unsigned char * indices)2279 static size_t CompressAlpha(const size_t min, const size_t max,
2280 const size_t steps, const ssize_t *alphas, unsigned char* indices)
2281 {
2282 unsigned char
2283 codes[8];
2284
2285 ssize_t
2286 i;
2287
2288 size_t
2289 error,
2290 index,
2291 j,
2292 least,
2293 value;
2294
2295 codes[0] = (unsigned char) min;
2296 codes[1] = (unsigned char) max;
2297 codes[6] = 0;
2298 codes[7] = 255;
2299
2300 for (i=1; i < (ssize_t) steps; i++)
2301 codes[i+1] = (unsigned char) (((steps-i)*min + i*max) / steps);
2302
2303 error = 0;
2304 for (i=0; i<16; i++)
2305 {
2306 if (alphas[i] == -1)
2307 {
2308 indices[i] = 0;
2309 continue;
2310 }
2311
2312 value = alphas[i];
2313 least = SIZE_MAX;
2314 index = 0;
2315 for (j=0; j<8; j++)
2316 {
2317 size_t
2318 dist;
2319
2320 dist = value - (size_t)codes[j];
2321 dist *= dist;
2322
2323 if (dist < least)
2324 {
2325 least = dist;
2326 index = j;
2327 }
2328 }
2329
2330 indices[i] = (unsigned char)index;
2331 error += least;
2332 }
2333
2334 return error;
2335 }
2336
ConstructOrdering(const size_t count,const DDSVector4 * points,const DDSVector3 axis,DDSVector4 * pointsWeights,DDSVector4 * xSumwSum,unsigned char * order,size_t iteration)2337 static MagickBooleanType ConstructOrdering(const size_t count,
2338 const DDSVector4 *points, const DDSVector3 axis, DDSVector4 *pointsWeights,
2339 DDSVector4 *xSumwSum, unsigned char *order, size_t iteration)
2340 {
2341 float
2342 dps[16],
2343 f;
2344
2345 ssize_t
2346 i;
2347
2348 size_t
2349 j;
2350
2351 unsigned char
2352 c,
2353 *o,
2354 *p;
2355
2356 o = order + (16*iteration);
2357
2358 for (i=0; i < (ssize_t) count; i++)
2359 {
2360 dps[i] = Dot(points[i],axis);
2361 o[i] = (unsigned char)i;
2362 }
2363
2364 for (i=0; i < (ssize_t) count; i++)
2365 {
2366 for (j=i; j > 0 && dps[j] < dps[j - 1]; j--)
2367 {
2368 f = dps[j];
2369 dps[j] = dps[j - 1];
2370 dps[j - 1] = f;
2371
2372 c = o[j];
2373 o[j] = o[j - 1];
2374 o[j - 1] = c;
2375 }
2376 }
2377
2378 for (i=0; i < (ssize_t) iteration; i++)
2379 {
2380 MagickBooleanType
2381 same;
2382
2383 p = order + (16*i);
2384 same = MagickTrue;
2385
2386 for (j=0; j < count; j++)
2387 {
2388 if (o[j] != p[j])
2389 {
2390 same = MagickFalse;
2391 break;
2392 }
2393 }
2394
2395 if (same != MagickFalse)
2396 return MagickFalse;
2397 }
2398
2399 xSumwSum->x = 0;
2400 xSumwSum->y = 0;
2401 xSumwSum->z = 0;
2402 xSumwSum->w = 0;
2403
2404 for (i=0; i < (ssize_t) count; i++)
2405 {
2406 DDSVector4
2407 v;
2408
2409 j = (size_t) o[i];
2410
2411 v.x = points[j].w * points[j].x;
2412 v.y = points[j].w * points[j].y;
2413 v.z = points[j].w * points[j].z;
2414 v.w = points[j].w * 1.0f;
2415
2416 VectorCopy44(v,&pointsWeights[i]);
2417 VectorAdd(*xSumwSum,v,xSumwSum);
2418 }
2419
2420 return MagickTrue;
2421 }
2422
CompressClusterFit(const size_t count,const DDSVector4 * points,const ssize_t * map,const DDSVector3 principle,const DDSVector4 metric,DDSVector3 * start,DDSVector3 * end,unsigned char * indices)2423 static void CompressClusterFit(const size_t count,
2424 const DDSVector4 *points, const ssize_t *map, const DDSVector3 principle,
2425 const DDSVector4 metric, DDSVector3 *start, DDSVector3* end,
2426 unsigned char *indices)
2427 {
2428 DDSVector3
2429 axis;
2430
2431 DDSVector4
2432 grid,
2433 gridrcp,
2434 half,
2435 onethird_onethird2,
2436 pointsWeights[16],
2437 two,
2438 twonineths,
2439 twothirds_twothirds2,
2440 xSumwSum;
2441
2442 float
2443 bestError = 1e+37f;
2444
2445 size_t
2446 bestIteration = 0,
2447 besti = 0,
2448 bestj = 0,
2449 bestk = 0,
2450 iterationIndex;
2451
2452 ssize_t
2453 i;
2454
2455 unsigned char
2456 *o,
2457 order[128],
2458 unordered[16];
2459
2460 VectorInit(half,0.5f);
2461 VectorInit(two,2.0f);
2462
2463 VectorInit(onethird_onethird2,1.0f/3.0f);
2464 onethird_onethird2.w = 1.0f/9.0f;
2465 VectorInit(twothirds_twothirds2,2.0f/3.0f);
2466 twothirds_twothirds2.w = 4.0f/9.0f;
2467 VectorInit(twonineths,2.0f/9.0f);
2468
2469 grid.x = 31.0f;
2470 grid.y = 63.0f;
2471 grid.z = 31.0f;
2472 grid.w = 0.0f;
2473
2474 gridrcp.x = 1.0f/31.0f;
2475 gridrcp.y = 1.0f/63.0f;
2476 gridrcp.z = 1.0f/31.0f;
2477 gridrcp.w = 0.0f;
2478
2479 xSumwSum.x = 0.0f;
2480 xSumwSum.y = 0.0f;
2481 xSumwSum.z = 0.0f;
2482 xSumwSum.w = 0.0f;
2483
2484 ConstructOrdering(count,points,principle,pointsWeights,&xSumwSum,order,0);
2485
2486 for (iterationIndex = 0;;)
2487 {
2488 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2489 #pragma omp parallel for schedule(dynamic,1) \
2490 num_threads(GetMagickResourceLimit(ThreadResource))
2491 #endif
2492 for (i=0; i < (ssize_t) count; i++)
2493 {
2494 DDSVector4
2495 part0,
2496 part1,
2497 part2;
2498
2499 size_t
2500 ii,
2501 j,
2502 k,
2503 kmin;
2504
2505 VectorInit(part0,0.0f);
2506 for(ii=0; ii < (size_t) i; ii++)
2507 VectorAdd(pointsWeights[ii],part0,&part0);
2508
2509 VectorInit(part1,0.0f);
2510 for (j=(size_t) i;;)
2511 {
2512 if (j == 0)
2513 {
2514 VectorCopy44(pointsWeights[0],&part2);
2515 kmin = 1;
2516 }
2517 else
2518 {
2519 VectorInit(part2,0.0f);
2520 kmin = j;
2521 }
2522
2523 for (k=kmin;;)
2524 {
2525 DDSVector4
2526 a,
2527 alpha2_sum,
2528 alphax_sum,
2529 alphabeta_sum,
2530 b,
2531 beta2_sum,
2532 betax_sum,
2533 e1,
2534 e2,
2535 factor,
2536 part3;
2537
2538 float
2539 error;
2540
2541 VectorSubtract(xSumwSum,part2,&part3);
2542 VectorSubtract(part3,part1,&part3);
2543 VectorSubtract(part3,part0,&part3);
2544
2545 VectorMultiplyAdd(part1,twothirds_twothirds2,part0,&alphax_sum);
2546 VectorMultiplyAdd(part2,onethird_onethird2,alphax_sum,&alphax_sum);
2547 VectorInit(alpha2_sum,alphax_sum.w);
2548
2549 VectorMultiplyAdd(part2,twothirds_twothirds2,part3,&betax_sum);
2550 VectorMultiplyAdd(part1,onethird_onethird2,betax_sum,&betax_sum);
2551 VectorInit(beta2_sum,betax_sum.w);
2552
2553 VectorAdd(part1,part2,&alphabeta_sum);
2554 VectorInit(alphabeta_sum,alphabeta_sum.w);
2555 VectorMultiply(twonineths,alphabeta_sum,&alphabeta_sum);
2556
2557 VectorMultiply(alpha2_sum,beta2_sum,&factor);
2558 VectorNegativeMultiplySubtract(alphabeta_sum,alphabeta_sum,factor,
2559 &factor);
2560 VectorReciprocal(factor,&factor);
2561
2562 VectorMultiply(alphax_sum,beta2_sum,&a);
2563 VectorNegativeMultiplySubtract(betax_sum,alphabeta_sum,a,&a);
2564 VectorMultiply(a,factor,&a);
2565
2566 VectorMultiply(betax_sum,alpha2_sum,&b);
2567 VectorNegativeMultiplySubtract(alphax_sum,alphabeta_sum,b,&b);
2568 VectorMultiply(b,factor,&b);
2569
2570 VectorClamp(&a);
2571 VectorMultiplyAdd(grid,a,half,&a);
2572 VectorTruncate(&a);
2573 VectorMultiply(a,gridrcp,&a);
2574
2575 VectorClamp(&b);
2576 VectorMultiplyAdd(grid,b,half,&b);
2577 VectorTruncate(&b);
2578 VectorMultiply(b,gridrcp,&b);
2579
2580 VectorMultiply(b,b,&e1);
2581 VectorMultiply(e1,beta2_sum,&e1);
2582 VectorMultiply(a,a,&e2);
2583 VectorMultiplyAdd(e2,alpha2_sum,e1,&e1);
2584
2585 VectorMultiply(a,b,&e2);
2586 VectorMultiply(e2,alphabeta_sum,&e2);
2587 VectorNegativeMultiplySubtract(a,alphax_sum,e2,&e2);
2588 VectorNegativeMultiplySubtract(b,betax_sum,e2,&e2);
2589 VectorMultiplyAdd(two,e2,e1,&e2);
2590 VectorMultiply(e2,metric,&e2);
2591
2592 error = e2.x + e2.y + e2.z;
2593
2594 if (error < bestError)
2595 {
2596 #if defined(MAGICKCORE_OPENMP_SUPPORT)
2597 #pragma omp critical (DDS_CompressClusterFit)
2598 #endif
2599 {
2600 if (error < bestError)
2601 {
2602 VectorCopy43(a,start);
2603 VectorCopy43(b,end);
2604 bestError = error;
2605 besti = i;
2606 bestj = j;
2607 bestk = k;
2608 bestIteration = iterationIndex;
2609 }
2610 }
2611 }
2612
2613 if (k == count)
2614 break;
2615
2616 VectorAdd(pointsWeights[k],part2,&part2);
2617 k++;
2618 }
2619
2620 if (j == count)
2621 break;
2622
2623 VectorAdd(pointsWeights[j],part1,&part1);
2624 j++;
2625 }
2626 }
2627
2628 if (bestIteration != iterationIndex)
2629 break;
2630
2631 iterationIndex++;
2632 if (iterationIndex == 8)
2633 break;
2634
2635 VectorSubtract3(*end,*start,&axis);
2636 if (ConstructOrdering(count,points,axis,pointsWeights,&xSumwSum,order,
2637 iterationIndex) == MagickFalse)
2638 break;
2639 }
2640
2641 o = order + (16*bestIteration);
2642
2643 for (i=0; i < (ssize_t) besti; i++)
2644 unordered[o[i]] = 0;
2645 for (i=besti; i < (ssize_t) bestj; i++)
2646 unordered[o[i]] = 2;
2647 for (i=bestj; i < (ssize_t) bestk; i++)
2648 unordered[o[i]] = 3;
2649 for (i=bestk; i < (ssize_t) count; i++)
2650 unordered[o[i]] = 1;
2651
2652 RemapIndices(map,unordered,indices);
2653 }
2654
CompressRangeFit(const size_t count,const DDSVector4 * points,const ssize_t * map,const DDSVector3 principle,const DDSVector4 metric,DDSVector3 * start,DDSVector3 * end,unsigned char * indices)2655 static void CompressRangeFit(const size_t count,
2656 const DDSVector4* points, const ssize_t *map, const DDSVector3 principle,
2657 const DDSVector4 metric, DDSVector3 *start, DDSVector3 *end,
2658 unsigned char *indices)
2659 {
2660 float
2661 d,
2662 bestDist,
2663 max,
2664 min,
2665 val;
2666
2667 DDSVector3
2668 codes[4],
2669 grid,
2670 gridrcp,
2671 half,
2672 dist;
2673
2674 ssize_t
2675 i;
2676
2677 size_t
2678 bestj,
2679 j;
2680
2681 unsigned char
2682 closest[16];
2683
2684 VectorInit3(half,0.5f);
2685
2686 grid.x = 31.0f;
2687 grid.y = 63.0f;
2688 grid.z = 31.0f;
2689
2690 gridrcp.x = 1.0f/31.0f;
2691 gridrcp.y = 1.0f/63.0f;
2692 gridrcp.z = 1.0f/31.0f;
2693
2694 if (count > 0)
2695 {
2696 VectorCopy43(points[0],start);
2697 VectorCopy43(points[0],end);
2698
2699 min = max = Dot(points[0],principle);
2700 for (i=1; i < (ssize_t) count; i++)
2701 {
2702 val = Dot(points[i],principle);
2703 if (val < min)
2704 {
2705 VectorCopy43(points[i],start);
2706 min = val;
2707 }
2708 else if (val > max)
2709 {
2710 VectorCopy43(points[i],end);
2711 max = val;
2712 }
2713 }
2714 }
2715
2716 VectorClamp3(start);
2717 VectorMultiplyAdd3(grid,*start,half,start);
2718 VectorTruncate3(start);
2719 VectorMultiply3(*start,gridrcp,start);
2720
2721 VectorClamp3(end);
2722 VectorMultiplyAdd3(grid,*end,half,end);
2723 VectorTruncate3(end);
2724 VectorMultiply3(*end,gridrcp,end);
2725
2726 codes[0] = *start;
2727 codes[1] = *end;
2728 codes[2].x = (start->x * (2.0f/3.0f)) + (end->x * (1.0f/3.0f));
2729 codes[2].y = (start->y * (2.0f/3.0f)) + (end->y * (1.0f/3.0f));
2730 codes[2].z = (start->z * (2.0f/3.0f)) + (end->z * (1.0f/3.0f));
2731 codes[3].x = (start->x * (1.0f/3.0f)) + (end->x * (2.0f/3.0f));
2732 codes[3].y = (start->y * (1.0f/3.0f)) + (end->y * (2.0f/3.0f));
2733 codes[3].z = (start->z * (1.0f/3.0f)) + (end->z * (2.0f/3.0f));
2734
2735 for (i=0; i < (ssize_t) count; i++)
2736 {
2737 bestDist = 1e+37f;
2738 bestj = 0;
2739 for (j=0; j < 4; j++)
2740 {
2741 dist.x = (points[i].x - codes[j].x) * metric.x;
2742 dist.y = (points[i].y - codes[j].y) * metric.y;
2743 dist.z = (points[i].z - codes[j].z) * metric.z;
2744
2745 d = Dot(dist,dist);
2746 if (d < bestDist)
2747 {
2748 bestDist = d;
2749 bestj = j;
2750 }
2751 }
2752
2753 closest[i] = (unsigned char) bestj;
2754 }
2755
2756 RemapIndices(map, closest, indices);
2757 }
2758
ComputeEndPoints(const DDSSingleColorLookup * lookup[],const unsigned char * color,DDSVector3 * start,DDSVector3 * end,unsigned char * index)2759 static void ComputeEndPoints(const DDSSingleColorLookup *lookup[],
2760 const unsigned char *color, DDSVector3 *start, DDSVector3 *end,
2761 unsigned char *index)
2762 {
2763 ssize_t
2764 i;
2765
2766 size_t
2767 c,
2768 maxError = SIZE_MAX;
2769
2770 for (i=0; i < 2; i++)
2771 {
2772 const DDSSourceBlock*
2773 sources[3];
2774
2775 size_t
2776 error = 0;
2777
2778 for (c=0; c < 3; c++)
2779 {
2780 sources[c] = &lookup[c][color[c]].sources[i];
2781 error += ((size_t) sources[c]->error) * ((size_t) sources[c]->error);
2782 }
2783
2784 if (error > maxError)
2785 continue;
2786
2787 start->x = (float) sources[0]->start / 31.0f;
2788 start->y = (float) sources[1]->start / 63.0f;
2789 start->z = (float) sources[2]->start / 31.0f;
2790
2791 end->x = (float) sources[0]->end / 31.0f;
2792 end->y = (float) sources[1]->end / 63.0f;
2793 end->z = (float) sources[2]->end / 31.0f;
2794
2795 *index = (unsigned char) (2*i);
2796 maxError = error;
2797 }
2798 }
2799
ComputePrincipleComponent(const float * covariance,DDSVector3 * principle)2800 static void ComputePrincipleComponent(const float *covariance,
2801 DDSVector3 *principle)
2802 {
2803 DDSVector4
2804 row0,
2805 row1,
2806 row2,
2807 v;
2808
2809 ssize_t
2810 i;
2811
2812 row0.x = covariance[0];
2813 row0.y = covariance[1];
2814 row0.z = covariance[2];
2815 row0.w = 0.0f;
2816
2817 row1.x = covariance[1];
2818 row1.y = covariance[3];
2819 row1.z = covariance[4];
2820 row1.w = 0.0f;
2821
2822 row2.x = covariance[2];
2823 row2.y = covariance[4];
2824 row2.z = covariance[5];
2825 row2.w = 0.0f;
2826
2827 VectorInit(v,1.0f);
2828
2829 for (i=0; i < 8; i++)
2830 {
2831 DDSVector4
2832 w;
2833
2834 float
2835 a;
2836
2837 w.x = row0.x * v.x;
2838 w.y = row0.y * v.x;
2839 w.z = row0.z * v.x;
2840 w.w = row0.w * v.x;
2841
2842 w.x = (row1.x * v.y) + w.x;
2843 w.y = (row1.y * v.y) + w.y;
2844 w.z = (row1.z * v.y) + w.z;
2845 w.w = (row1.w * v.y) + w.w;
2846
2847 w.x = (row2.x * v.z) + w.x;
2848 w.y = (row2.y * v.z) + w.y;
2849 w.z = (row2.z * v.z) + w.z;
2850 w.w = (row2.w * v.z) + w.w;
2851
2852 a = (float) PerceptibleReciprocal(MagickMax(w.x,MagickMax(w.y,w.z)));
2853
2854 v.x = w.x * a;
2855 v.y = w.y * a;
2856 v.z = w.z * a;
2857 v.w = w.w * a;
2858 }
2859
2860 VectorCopy43(v,principle);
2861 }
2862
ComputeWeightedCovariance(const size_t count,const DDSVector4 * points,float * covariance)2863 static void ComputeWeightedCovariance(const size_t count,
2864 const DDSVector4 *points, float *covariance)
2865 {
2866 DDSVector3
2867 centroid;
2868
2869 float
2870 total;
2871
2872 size_t
2873 i;
2874
2875 total = 0.0f;
2876 VectorInit3(centroid,0.0f);
2877
2878 for (i=0; i < count; i++)
2879 {
2880 total += points[i].w;
2881 centroid.x += (points[i].x * points[i].w);
2882 centroid.y += (points[i].y * points[i].w);
2883 centroid.z += (points[i].z * points[i].w);
2884 }
2885
2886 if( total > 1.192092896e-07F)
2887 {
2888 centroid.x /= total;
2889 centroid.y /= total;
2890 centroid.z /= total;
2891 }
2892
2893 for (i=0; i < 6; i++)
2894 covariance[i] = 0.0f;
2895
2896 for (i = 0; i < count; i++)
2897 {
2898 DDSVector3
2899 a,
2900 b;
2901
2902 a.x = points[i].x - centroid.x;
2903 a.y = points[i].y - centroid.y;
2904 a.z = points[i].z - centroid.z;
2905
2906 b.x = points[i].w * a.x;
2907 b.y = points[i].w * a.y;
2908 b.z = points[i].w * a.z;
2909
2910 covariance[0] += a.x*b.x;
2911 covariance[1] += a.x*b.y;
2912 covariance[2] += a.x*b.z;
2913 covariance[3] += a.y*b.y;
2914 covariance[4] += a.y*b.z;
2915 covariance[5] += a.z*b.z;
2916 }
2917 }
2918
WriteAlphas(Image * image,const ssize_t * alphas,size_t min5,size_t max5,size_t min7,size_t max7)2919 static void WriteAlphas(Image *image, const ssize_t *alphas, size_t min5,
2920 size_t max5, size_t min7, size_t max7)
2921 {
2922 ssize_t
2923 i;
2924
2925 size_t
2926 err5,
2927 err7,
2928 j;
2929
2930 unsigned char
2931 indices5[16],
2932 indices7[16];
2933
2934 FixRange(min5,max5,5);
2935 err5 = CompressAlpha(min5,max5,5,alphas,indices5);
2936
2937 FixRange(min7,max7,7);
2938 err7 = CompressAlpha(min7,max7,7,alphas,indices7);
2939
2940 if (err7 < err5)
2941 {
2942 for (i=0; i < 16; i++)
2943 {
2944 unsigned char
2945 index;
2946
2947 index = indices7[i];
2948 if( index == 0 )
2949 indices5[i] = 1;
2950 else if (index == 1)
2951 indices5[i] = 0;
2952 else
2953 indices5[i] = 9 - index;
2954 }
2955
2956 min5 = max7;
2957 max5 = min7;
2958 }
2959
2960 (void) WriteBlobByte(image,(unsigned char) min5);
2961 (void) WriteBlobByte(image,(unsigned char) max5);
2962
2963 for(i=0; i < 2; i++)
2964 {
2965 size_t
2966 value = 0;
2967
2968 for (j=0; j < 8; j++)
2969 {
2970 size_t index = (size_t) indices5[j + i*8];
2971 value |= ( index << 3*j );
2972 }
2973
2974 for (j=0; j < 3; j++)
2975 {
2976 size_t byte = (value >> 8*j) & 0xff;
2977 (void) WriteBlobByte(image,(unsigned char) byte);
2978 }
2979 }
2980 }
2981
WriteIndices(Image * image,const DDSVector3 start,const DDSVector3 end,unsigned char * indices)2982 static void WriteIndices(Image *image, const DDSVector3 start,
2983 const DDSVector3 end, unsigned char *indices)
2984 {
2985 ssize_t
2986 i;
2987
2988 size_t
2989 a,
2990 b;
2991
2992 unsigned char
2993 remapped[16];
2994
2995 const unsigned char
2996 *ind;
2997
2998 a = ColorTo565(start);
2999 b = ColorTo565(end);
3000
3001 for (i=0; i<16; i++)
3002 {
3003 if( a < b )
3004 remapped[i] = (indices[i] ^ 0x1) & 0x3;
3005 else if( a == b )
3006 remapped[i] = 0;
3007 else
3008 remapped[i] = indices[i];
3009 }
3010
3011 if( a < b )
3012 Swap(a,b);
3013
3014 (void) WriteBlobByte(image,(unsigned char) (a & 0xff));
3015 (void) WriteBlobByte(image,(unsigned char) (a >> 8));
3016 (void) WriteBlobByte(image,(unsigned char) (b & 0xff));
3017 (void) WriteBlobByte(image,(unsigned char) (b >> 8));
3018
3019 for (i=0; i<4; i++)
3020 {
3021 ind = remapped + 4*i;
3022 (void) WriteBlobByte(image,ind[0] | (ind[1] << 2) | (ind[2] << 4) |
3023 (ind[3] << 6));
3024 }
3025 }
3026
WriteCompressed(Image * image,const size_t count,DDSVector4 * points,const ssize_t * map,const MagickBooleanType clusterFit)3027 static void WriteCompressed(Image *image, const size_t count,
3028 DDSVector4 *points, const ssize_t *map, const MagickBooleanType clusterFit)
3029 {
3030 float
3031 covariance[16];
3032
3033 DDSVector3
3034 end,
3035 principle,
3036 start;
3037
3038 DDSVector4
3039 metric;
3040
3041 unsigned char
3042 indices[16];
3043
3044 VectorInit(metric,1.0f);
3045 VectorInit3(start,0.0f);
3046 VectorInit3(end,0.0f);
3047
3048 ComputeWeightedCovariance(count,points,covariance);
3049 ComputePrincipleComponent(covariance,&principle);
3050
3051 if ((clusterFit == MagickFalse) || (count == 0))
3052 CompressRangeFit(count,points,map,principle,metric,&start,&end,indices);
3053 else
3054 CompressClusterFit(count,points,map,principle,metric,&start,&end,indices);
3055
3056 WriteIndices(image,start,end,indices);
3057 }
3058
WriteSingleColorFit(Image * image,const DDSVector4 * points,const ssize_t * map)3059 static void WriteSingleColorFit(Image *image, const DDSVector4 *points,
3060 const ssize_t *map)
3061 {
3062 DDSVector3
3063 start,
3064 end;
3065
3066 ssize_t
3067 i;
3068
3069 unsigned char
3070 color[3],
3071 index,
3072 indexes[16],
3073 indices[16];
3074
3075 color[0] = (unsigned char) ClampToLimit(255.0f*points->x,255);
3076 color[1] = (unsigned char) ClampToLimit(255.0f*points->y,255);
3077 color[2] = (unsigned char) ClampToLimit(255.0f*points->z,255);
3078
3079 index=0;
3080 ComputeEndPoints(DDS_LOOKUP,color,&start,&end,&index);
3081
3082 for (i=0; i< 16; i++)
3083 indexes[i]=index;
3084 RemapIndices(map,indexes,indices);
3085 WriteIndices(image,start,end,indices);
3086 }
3087
WriteFourCC(Image * image,const size_t compression,const MagickBooleanType clusterFit,const MagickBooleanType weightByAlpha,ExceptionInfo * exception)3088 static void WriteFourCC(Image *image, const size_t compression,
3089 const MagickBooleanType clusterFit, const MagickBooleanType weightByAlpha,
3090 ExceptionInfo *exception)
3091 {
3092 ssize_t
3093 x;
3094
3095 ssize_t
3096 i,
3097 y,
3098 bx,
3099 by;
3100
3101 const Quantum
3102 *p;
3103
3104 for (y=0; y < (ssize_t) image->rows; y+=4)
3105 {
3106 for (x=0; x < (ssize_t) image->columns; x+=4)
3107 {
3108 MagickBooleanType
3109 match;
3110
3111 DDSVector4
3112 point,
3113 points[16];
3114
3115 size_t
3116 count = 0,
3117 max5 = 0,
3118 max7 = 0,
3119 min5 = 255,
3120 min7 = 255,
3121 columns = 4,
3122 rows = 4;
3123
3124 ssize_t
3125 alphas[16],
3126 map[16];
3127
3128 unsigned char
3129 alpha;
3130
3131 if (x + columns >= image->columns)
3132 columns = image->columns - x;
3133
3134 if (y + rows >= image->rows)
3135 rows = image->rows - y;
3136
3137 p=GetVirtualPixels(image,x,y,columns,rows,exception);
3138 if (p == (const Quantum *) NULL)
3139 break;
3140
3141 for (i=0; i<16; i++)
3142 {
3143 map[i] = -1;
3144 alphas[i] = -1;
3145 }
3146
3147 for (by=0; by < (ssize_t) rows; by++)
3148 {
3149 for (bx=0; bx < (ssize_t) columns; bx++)
3150 {
3151 if (compression == FOURCC_DXT5)
3152 alpha = ScaleQuantumToChar(GetPixelAlpha(image,p));
3153 else
3154 alpha = 255;
3155
3156 if (compression == FOURCC_DXT5)
3157 {
3158 if (alpha < min7)
3159 min7 = alpha;
3160 if (alpha > max7)
3161 max7 = alpha;
3162 if (alpha != 0 && alpha < min5)
3163 min5 = alpha;
3164 if (alpha != 255 && alpha > max5)
3165 max5 = alpha;
3166 }
3167
3168 alphas[4*by + bx] = (size_t)alpha;
3169
3170 point.x = (float)ScaleQuantumToChar(GetPixelRed(image,p)) / 255.0f;
3171 point.y = (float)ScaleQuantumToChar(GetPixelGreen(image,p)) / 255.0f;
3172 point.z = (float)ScaleQuantumToChar(GetPixelBlue(image,p)) / 255.0f;
3173 point.w = weightByAlpha ? (float)(alpha + 1) / 256.0f : 1.0f;
3174 p+=GetPixelChannels(image);
3175
3176 match = MagickFalse;
3177 for (i=0; i < (ssize_t) count; i++)
3178 {
3179 if ((points[i].x == point.x) &&
3180 (points[i].y == point.y) &&
3181 (points[i].z == point.z) &&
3182 (alpha >= 128 || compression == FOURCC_DXT5))
3183 {
3184 points[i].w += point.w;
3185 map[4*by + bx] = i;
3186 match = MagickTrue;
3187 break;
3188 }
3189 }
3190
3191 if (match != MagickFalse)
3192 continue;
3193
3194 points[count].x = point.x;
3195 points[count].y = point.y;
3196 points[count].z = point.z;
3197 points[count].w = point.w;
3198 map[4*by + bx] = count;
3199 count++;
3200 }
3201 }
3202
3203 for (i=0; i < (ssize_t) count; i++)
3204 points[i].w = sqrt(points[i].w);
3205
3206 if (compression == FOURCC_DXT5)
3207 WriteAlphas(image,alphas,min5,max5,min7,max7);
3208
3209 if (count == 1)
3210 WriteSingleColorFit(image,points,map);
3211 else
3212 WriteCompressed(image,count,points,map,clusterFit);
3213 }
3214 }
3215 }
3216
WriteUncompressed(Image * image,ExceptionInfo * exception)3217 static void WriteUncompressed(Image *image, ExceptionInfo *exception)
3218 {
3219 const Quantum
3220 *p;
3221
3222 ssize_t
3223 x;
3224
3225 ssize_t
3226 y;
3227
3228 for (y=0; y < (ssize_t) image->rows; y++)
3229 {
3230 p=GetVirtualPixels(image,0,y,image->columns,1,exception);
3231 if (p == (const Quantum *) NULL)
3232 break;
3233
3234 for (x=0; x < (ssize_t) image->columns; x++)
3235 {
3236 (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelBlue(image,p)));
3237 (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelGreen(image,p)));
3238 (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelRed(image,p)));
3239 if (image->alpha_trait != UndefinedPixelTrait)
3240 (void) WriteBlobByte(image,ScaleQuantumToChar(GetPixelAlpha(image,p)));
3241 p+=GetPixelChannels(image);
3242 }
3243 }
3244 }
3245
WriteImageData(Image * image,const size_t pixelFormat,const size_t compression,const MagickBooleanType clusterFit,const MagickBooleanType weightByAlpha,ExceptionInfo * exception)3246 static void WriteImageData(Image *image, const size_t pixelFormat,
3247 const size_t compression,const MagickBooleanType clusterFit,
3248 const MagickBooleanType weightByAlpha, ExceptionInfo *exception)
3249 {
3250 if (pixelFormat == DDPF_FOURCC)
3251 WriteFourCC(image,compression,clusterFit,weightByAlpha,exception);
3252 else
3253 WriteUncompressed(image,exception);
3254 }
3255
WriteMipmaps(Image * image,const ImageInfo * image_info,const size_t pixelFormat,const size_t compression,const size_t mipmaps,const MagickBooleanType fromlist,const MagickBooleanType clusterFit,const MagickBooleanType weightByAlpha,ExceptionInfo * exception)3256 static MagickBooleanType WriteMipmaps(Image *image,const ImageInfo *image_info,
3257 const size_t pixelFormat,const size_t compression,const size_t mipmaps,
3258 const MagickBooleanType fromlist,const MagickBooleanType clusterFit,
3259 const MagickBooleanType weightByAlpha,ExceptionInfo *exception)
3260 {
3261 const char
3262 *option;
3263
3264 Image
3265 *mipmap_image,
3266 *resize_image;
3267
3268 MagickBooleanType
3269 fast_mipmaps,
3270 status;
3271
3272 ssize_t
3273 i;
3274
3275 size_t
3276 columns,
3277 rows;
3278
3279 columns=DIV2(image->columns);
3280 rows=DIV2(image->rows);
3281
3282 option=GetImageOption(image_info,"dds:fast-mipmaps");
3283 fast_mipmaps=IsStringTrue(option);
3284 mipmap_image=image;
3285 resize_image=image;
3286 status=MagickTrue;
3287 for (i=0; i < (ssize_t) mipmaps; i++)
3288 {
3289 if (fromlist == MagickFalse)
3290 {
3291 mipmap_image=ResizeImage(resize_image,columns,rows,TriangleFilter,
3292 exception);
3293
3294 if (mipmap_image == (Image *) NULL)
3295 {
3296 status=MagickFalse;
3297 break;
3298 }
3299 }
3300 else
3301 {
3302 mipmap_image=mipmap_image->next;
3303 if ((mipmap_image->columns != columns) || (mipmap_image->rows != rows))
3304 ThrowBinaryException(CoderError,"ImageColumnOrRowSizeIsNotSupported",
3305 image->filename);
3306 }
3307
3308 DestroyBlob(mipmap_image);
3309 mipmap_image->blob=ReferenceBlob(image->blob);
3310
3311 WriteImageData(mipmap_image,pixelFormat,compression,weightByAlpha,
3312 clusterFit,exception);
3313
3314 if (fromlist == MagickFalse)
3315 {
3316 if (fast_mipmaps == MagickFalse)
3317 mipmap_image=DestroyImage(mipmap_image);
3318 else
3319 {
3320 if (resize_image != image)
3321 resize_image=DestroyImage(resize_image);
3322 resize_image=mipmap_image;
3323 }
3324 }
3325
3326 columns=DIV2(columns);
3327 rows=DIV2(rows);
3328 }
3329
3330 if (resize_image != image)
3331 resize_image=DestroyImage(resize_image);
3332
3333 return(status);
3334 }
3335
WriteDDSInfo(Image * image,const size_t pixelFormat,const size_t compression,const size_t mipmaps)3336 static void WriteDDSInfo(Image *image, const size_t pixelFormat,
3337 const size_t compression, const size_t mipmaps)
3338 {
3339 char
3340 software[MagickPathExtent];
3341
3342 ssize_t
3343 i;
3344
3345 unsigned int
3346 format,
3347 caps,
3348 flags;
3349
3350 flags=(unsigned int) (DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT |
3351 DDSD_PIXELFORMAT);
3352 caps=(unsigned int) DDSCAPS_TEXTURE;
3353 format=(unsigned int) pixelFormat;
3354
3355 if (format == DDPF_FOURCC)
3356 flags=flags | DDSD_LINEARSIZE;
3357 else
3358 flags=flags | DDSD_PITCH;
3359
3360 if (mipmaps > 0)
3361 {
3362 flags=flags | (unsigned int) DDSD_MIPMAPCOUNT;
3363 caps=caps | (unsigned int) (DDSCAPS_MIPMAP | DDSCAPS_COMPLEX);
3364 }
3365
3366 if (format != DDPF_FOURCC && image->alpha_trait != UndefinedPixelTrait)
3367 format=format | DDPF_ALPHAPIXELS;
3368
3369 (void) WriteBlob(image,4,(unsigned char *) "DDS ");
3370 (void) WriteBlobLSBLong(image,124);
3371 (void) WriteBlobLSBLong(image,flags);
3372 (void) WriteBlobLSBLong(image,(unsigned int) image->rows);
3373 (void) WriteBlobLSBLong(image,(unsigned int) image->columns);
3374
3375 if (pixelFormat == DDPF_FOURCC)
3376 {
3377 /* Compressed DDS requires linear compressed size of first image */
3378 if (compression == FOURCC_DXT1)
3379 (void) WriteBlobLSBLong(image,(unsigned int) (MagickMax(1,
3380 (image->columns+3)/4)*MagickMax(1,(image->rows+3)/4)*8));
3381 else /* DXT5 */
3382 (void) WriteBlobLSBLong(image,(unsigned int) (MagickMax(1,
3383 (image->columns+3)/4)*MagickMax(1,(image->rows+3)/4)*16));
3384 }
3385 else
3386 {
3387 /* Uncompressed DDS requires byte pitch of first image */
3388 if (image->alpha_trait != UndefinedPixelTrait)
3389 (void) WriteBlobLSBLong(image,(unsigned int) (image->columns * 4));
3390 else
3391 (void) WriteBlobLSBLong(image,(unsigned int) (image->columns * 3));
3392 }
3393
3394 (void) WriteBlobLSBLong(image,0x00);
3395 (void) WriteBlobLSBLong(image,(unsigned int) mipmaps+1);
3396 (void) memset(software,0,sizeof(software));
3397 (void) CopyMagickString(software,"IMAGEMAGICK",MagickPathExtent);
3398 (void) WriteBlob(image,44,(unsigned char *) software);
3399
3400 (void) WriteBlobLSBLong(image,32);
3401 (void) WriteBlobLSBLong(image,format);
3402
3403 if (pixelFormat == DDPF_FOURCC)
3404 {
3405 (void) WriteBlobLSBLong(image,(unsigned int) compression);
3406 for(i=0;i < 5;i++) /* bitcount / masks */
3407 (void) WriteBlobLSBLong(image,0x00);
3408 }
3409 else
3410 {
3411 (void) WriteBlobLSBLong(image,0x00);
3412 if (image->alpha_trait != UndefinedPixelTrait)
3413 {
3414 (void) WriteBlobLSBLong(image,32);
3415 (void) WriteBlobLSBLong(image,0xff0000);
3416 (void) WriteBlobLSBLong(image,0xff00);
3417 (void) WriteBlobLSBLong(image,0xff);
3418 (void) WriteBlobLSBLong(image,0xff000000);
3419 }
3420 else
3421 {
3422 (void) WriteBlobLSBLong(image,24);
3423 (void) WriteBlobLSBLong(image,0xff0000);
3424 (void) WriteBlobLSBLong(image,0xff00);
3425 (void) WriteBlobLSBLong(image,0xff);
3426 (void) WriteBlobLSBLong(image,0x00);
3427 }
3428 }
3429
3430 (void) WriteBlobLSBLong(image,caps);
3431 for(i=0;i < 4;i++) /* ddscaps2 + reserved region */
3432 (void) WriteBlobLSBLong(image,0x00);
3433 }
3434
WriteDDSImage(const ImageInfo * image_info,Image * image,ExceptionInfo * exception)3435 static MagickBooleanType WriteDDSImage(const ImageInfo *image_info,
3436 Image *image, ExceptionInfo *exception)
3437 {
3438 const char
3439 *option;
3440
3441 size_t
3442 compression,
3443 columns,
3444 maxMipmaps,
3445 mipmaps,
3446 pixelFormat,
3447 rows;
3448
3449 MagickBooleanType
3450 clusterFit,
3451 fromlist,
3452 status,
3453 weightByAlpha;
3454
3455 assert(image_info != (const ImageInfo *) NULL);
3456 assert(image_info->signature == MagickCoreSignature);
3457 assert(image != (Image *) NULL);
3458 assert(image->signature == MagickCoreSignature);
3459 if (image->debug != MagickFalse)
3460 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3461 status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
3462 if (status == MagickFalse)
3463 return(status);
3464 (void) TransformImageColorspace(image,sRGBColorspace,exception);
3465 pixelFormat=DDPF_FOURCC;
3466 compression=FOURCC_DXT5;
3467 if (image->alpha_trait == UndefinedPixelTrait)
3468 compression=FOURCC_DXT1;
3469 if (LocaleCompare(image_info->magick,"dxt1") == 0)
3470 compression=FOURCC_DXT1;
3471 if (image_info->compression == DXT1Compression)
3472 compression=FOURCC_DXT1;
3473 else if (image_info->compression == NoCompression)
3474 pixelFormat=DDPF_RGB;
3475 option=GetImageOption(image_info,"dds:compression");
3476 if (option != (char *) NULL)
3477 {
3478 if (LocaleCompare(option,"dxt1") == 0)
3479 compression=FOURCC_DXT1;
3480 if (LocaleCompare(option,"none") == 0)
3481 pixelFormat=DDPF_RGB;
3482 }
3483 clusterFit=MagickFalse;
3484 weightByAlpha=MagickFalse;
3485 if (pixelFormat == DDPF_FOURCC)
3486 {
3487 option=GetImageOption(image_info,"dds:cluster-fit");
3488 if (IsStringTrue(option) != MagickFalse)
3489 {
3490 clusterFit=MagickTrue;
3491 if (compression != FOURCC_DXT1)
3492 {
3493 option=GetImageOption(image_info,"dds:weight-by-alpha");
3494 if (IsStringTrue(option) != MagickFalse)
3495 weightByAlpha=MagickTrue;
3496 }
3497 }
3498 }
3499 mipmaps=0;
3500 fromlist=MagickFalse;
3501 option=GetImageOption(image_info,"dds:mipmaps");
3502 if (option != (char *) NULL)
3503 {
3504 if (LocaleNCompare(option,"fromlist",8) == 0)
3505 {
3506 Image
3507 *next;
3508
3509 fromlist=MagickTrue;
3510 next=image->next;
3511 while(next != (Image *) NULL)
3512 {
3513 mipmaps++;
3514 next=next->next;
3515 }
3516 }
3517 }
3518 if ((mipmaps == 0) &&
3519 ((image->columns & (image->columns - 1)) == 0) &&
3520 ((image->rows & (image->rows - 1)) == 0))
3521 {
3522 maxMipmaps=SIZE_MAX;
3523 if (option != (char *) NULL)
3524 maxMipmaps=StringToUnsignedLong(option);
3525
3526 if (maxMipmaps != 0)
3527 {
3528 columns=image->columns;
3529 rows=image->rows;
3530 while ((columns != 1 || rows != 1) && mipmaps != maxMipmaps)
3531 {
3532 columns=DIV2(columns);
3533 rows=DIV2(rows);
3534 mipmaps++;
3535 }
3536 }
3537 }
3538 option=GetImageOption(image_info,"dds:raw");
3539 if (IsStringTrue(option) == MagickFalse)
3540 WriteDDSInfo(image,pixelFormat,compression,mipmaps);
3541 else
3542 mipmaps=0;
3543 WriteImageData(image,pixelFormat,compression,clusterFit,weightByAlpha,
3544 exception);
3545 if ((mipmaps > 0) && (WriteMipmaps(image,image_info,pixelFormat,compression,
3546 mipmaps,fromlist,clusterFit,weightByAlpha,exception) == MagickFalse))
3547 return(MagickFalse);
3548 (void) CloseBlob(image);
3549 return(MagickTrue);
3550 }
3551