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