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