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