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