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