Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qddshandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Ivan Komissarov.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:critical reason:data-parser
5
6#include "qddshandler.h"
7
8#include <QtCore/qdebug.h>
9#include <QtGui/qimage.h>
10
11#include <cmath>
12
13#include "ddsheader.h"
14
15#include <cmath>
16
17#ifndef QT_NO_DATASTREAM
18
19QT_BEGIN_NAMESPACE
20
21enum Colors {
22 Red = 0,
23 Green,
24 Blue,
25 Alpha,
26 ColorCount
27};
28
30 One = 1,
31 Two = 2,
32 Three = 3,
33 Four = 4,
34 Five = 5,
35 RXGB = 6
36};
37
38// All magic numbers are little-endian as long as dds format has little
39// endian byte order
40static const quint32 ddsMagic = 0x20534444; // "DDS "
41static const quint32 dx10Magic = 0x30315844; // "DX10"
42
43static const qint64 headerSize = 128;
44static const quint32 ddsSize = 124; // headerSize without magic
45static const quint32 pixelFormatSize = 32;
46
48{
49 int x, y;
50};
51
52static const FaceOffset faceOffsets[6] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {3, 1} };
53
62
73
74static const FormatInfo formatInfos[] = {
75 { FormatA8R8G8B8, DDSPixelFormat::FlagRGBA, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 },
76 { FormatX8R8G8B8, DDSPixelFormat::FlagRGB, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 },
77 { FormatA2B10G10R10, DDSPixelFormat::FlagRGBA, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 },
78 { FormatA8B8G8R8, DDSPixelFormat::FlagRGBA, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
79 { FormatX8B8G8R8, DDSPixelFormat::FlagRGB, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 },
80 { FormatG16R16, DDSPixelFormat::FlagRGBA, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 },
81 { FormatG16R16, DDSPixelFormat::FlagRGB, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 },
82 { FormatA2R10G10B10, DDSPixelFormat::FlagRGBA, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 },
83
84 { FormatR8G8B8, DDSPixelFormat::FlagRGB, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000 },
85
86 { FormatR5G6B5, DDSPixelFormat::FlagRGB, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000 },
87 { FormatX1R5G5B5, DDSPixelFormat::FlagRGB, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00000000 },
88 { FormatA1R5G5B5, DDSPixelFormat::FlagRGBA, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000 },
89 { FormatA4R4G4B4, DDSPixelFormat::FlagRGBA, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000 },
90 { FormatA8R3G3B2, DDSPixelFormat::FlagRGBA, 16, 0x000000e0, 0x0000001c, 0x00000003, 0x0000ff00 },
91 { FormatX4R4G4B4, DDSPixelFormat::FlagRGB, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x00000000 },
92 { FormatA8L8, DDSPixelFormat::FlagLA, 16, 0x000000ff, 0x00000000, 0x00000000, 0x0000ff00 },
93 { FormatL16, DDSPixelFormat::FlagLuminance, 16, 0x0000ffff, 0x00000000, 0x00000000, 0x00000000 },
94
95 { FormatR3G3B2, DDSPixelFormat::FlagRGB, 8, 0x000000e0, 0x0000001c, 0x00000003, 0x00000000 },
96 { FormatA8, DDSPixelFormat::FlagAlpha, 8, 0x00000000, 0x00000000, 0x00000000, 0x000000ff },
97 { FormatL8, DDSPixelFormat::FlagLuminance, 8, 0x000000ff, 0x00000000, 0x00000000, 0x00000000 },
98 { FormatA4L4, DDSPixelFormat::FlagLA, 8, 0x0000000f, 0x00000000, 0x00000000, 0x000000f0 },
99
100 { FormatV8U8, DDSPixelFormat::FlagNormal, 16, 0x000000ff, 0x0000ff00, 0x00000000, 0x00000000 },
101 { FormatL6V5U5, 0, 16, 0x0000001f, 0x000003e0, 0x0000fc00, 0x00000000 },
102 { FormatX8L8V8U8, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 },
103 { FormatQ8W8V8U8, DDSPixelFormat::FlagNormal, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 },
104 { FormatV16U16, DDSPixelFormat::FlagNormal, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000 },
105 { FormatA2W10V10U10, DDSPixelFormat::FlagNormal, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 }
106};
107static const size_t formatInfosSize = sizeof(formatInfos)/sizeof(FormatInfo);
108
109static const Format knownFourCCs[] = {
110 FormatA16B16G16R16,
111 FormatV8U8,
112 FormatUYVY,
113 FormatR8G8B8G8,
114 FormatYUY2,
115 FormatG8R8G8B8,
116 FormatDXT1,
117 FormatDXT2,
118 FormatDXT3,
119 FormatDXT4,
120 FormatDXT5,
121 FormatRXGB,
122 FormatATI2,
123 FormatQ16W16V16U16,
124 FormatR16F,
125 FormatG16R16F,
126 FormatA16B16G16R16F,
127 FormatR32F,
128 FormatG32R32F,
129 FormatA32B32G32R32F,
130 FormatCxV8U8
131};
132static const size_t knownFourCCsSize = sizeof(knownFourCCs)/sizeof(Format);
133
135{
136 Format format;
137 const char *const name;
138};
139static const FormatName formatNames[] = {
140 { FormatUnknown, "unknown" },
141
142 { FormatR8G8B8, "R8G8B8" },
143 { FormatA8R8G8B8, "A8R8G8B8" },
144 { FormatX8R8G8B8, "X8R8G8B8" },
145 { FormatR5G6B5, "R5G6B5" },
146 { FormatX1R5G5B5, "X1R5G5B5" },
147 { FormatA1R5G5B5, "A1R5G5B5" },
148 { FormatA4R4G4B4, "A4R4G4B4" },
149 { FormatR3G3B2, "R3G3B2" },
150 { FormatA8, "A8" },
151 { FormatA8R3G3B2, "A8R3G3B2" },
152 { FormatX4R4G4B4, "X4R4G4B4" },
153 { FormatA2B10G10R10, "A2B10G10R10" },
154 { FormatA8B8G8R8, "A8B8G8R8" },
155 { FormatX8B8G8R8, "X8B8G8R8" },
156 { FormatG16R16, "G16R16" },
157 { FormatA2R10G10B10, "A2R10G10B10" },
158 { FormatA16B16G16R16, "A16B16G16R16" },
159
160 { FormatA8P8, "A8P8" },
161 { FormatP8, "P8" },
162
163 { FormatL8, "L8" },
164 { FormatA8L8, "A8L8" },
165 { FormatA4L4, "A4L4" },
166
167 { FormatV8U8, "V8U8" },
168 { FormatL6V5U5, "L6V5U5" },
169 { FormatX8L8V8U8, "X8L8V8U8" },
170 { FormatQ8W8V8U8, "Q8W8V8U8" },
171 { FormatV16U16, "V16U16" },
172 { FormatA2W10V10U10, "A2W10V10U10" },
173
174 { FormatUYVY, "UYVY" },
175 { FormatR8G8B8G8, "R8G8_B8G8" },
176 { FormatYUY2, "YUY2" },
177 { FormatG8R8G8B8, "G8R8_G8B8" },
178 { FormatDXT1, "DXT1" },
179 { FormatDXT2, "DXT2" },
180 { FormatDXT3, "DXT3" },
181 { FormatDXT4, "DXT4" },
182 { FormatDXT5, "DXT5" },
183 { FormatRXGB, "RXGB" },
184 { FormatATI2, "ATI2" },
185
186 { FormatD16Lockable, "D16Lockable" },
187 { FormatD32, "D32" },
188 { FormatD15S1, "D15S1" },
189 { FormatD24S8, "D24S8" },
190 { FormatD24X8, "D24X8" },
191 { FormatD24X4S4, "D24X4S4" },
192 { FormatD16, "D16" },
193
194 { FormatD32FLockable, "D32FLockable" },
195 { FormatD24FS8, "D24FS8" },
196
197 { FormatD32Lockable, "D32Lockable" },
198 { FormatS8Lockable, "S8Lockable" },
199
200 { FormatL16, "L16" },
201
202 { FormatVertexData, "VertexData" },
203 { FormatIndex32, "Index32" },
204 { FormatIndex32, "Index32" },
205
206 { FormatQ16W16V16U16, "Q16W16V16U16" },
207
208 { FormatMulti2ARGB8, "Multi2ARGB8" },
209
210 { FormatR16F, "R16F" },
211 { FormatG16R16F, "G16R16F" },
212 { FormatA16B16G16R16F, "A16B16G16R16F" },
213
214 { FormatR32F, "R32F" },
215 { FormatG32R32F, "G32R32F" },
216 { FormatA32B32G32R32F, "A32B32G32R32F" },
217
218 { FormatCxV8U8, "CxV8U8" },
219
220 { FormatA1, "A1" },
221 { FormatA2B10G10R10_XR_BIAS, "A2B10G10R10_XR_BIAS" },
222 { FormatBinaryBuffer, "BinaryBuffer" },
223
224 { FormatP4, "P4" },
225 { FormatA4P4, "A4P4" }
226};
227static const size_t formatNamesSize = sizeof(formatNames)/sizeof(FormatName);
228
229static inline int maskToShift(quint32 mask)
230{
231 if (mask == 0)
232 return 0;
233
234 int result = 0;
235 while (!((mask >> result) & 1))
236 result++;
237 return result;
238}
239
240static inline int maskLength(quint32 mask)
241{
242 int result = 0;
243 while (mask) {
244 if (mask & 1)
245 result++;
246 mask >>= 1;
247 }
248 return result;
249}
250
251static inline quint32 readValue(QDataStream &s, quint32 size)
252{
253 Q_ASSERT(size == 8 || size == 16 || size == 24 || size == 32);
254
255 quint32 value = 0;
256 quint8 tmp;
257 for (unsigned bit = 0; bit < size; bit += 8) {
258 s >> tmp;
259 value += (quint32(tmp) << bit);
260 }
261 return value;
262}
263
264static inline bool hasAlpha(const DDSHeader &dds)
265{
266 return (dds.pixelFormat.flags & (DDSPixelFormat::FlagAlphaPixels | DDSPixelFormat::FlagAlpha)) != 0;
267}
268
269static inline bool isCubeMap(const DDSHeader &dds)
270{
271 return (dds.caps2 & DDSHeader::Caps2CubeMap) != 0;
272}
273
274static inline QRgb yuv2rgb(quint8 Y, quint8 U, quint8 V)
275{
276 return qRgb(quint8(Y + 1.13983 * (V - 128)),
277 quint8(Y - 0.39465 * (U - 128) - 0.58060 * (V - 128)),
278 quint8(Y + 2.03211 * (U - 128)));
279}
280
281static Format getFormat(const DDSHeader &dds)
282{
283 const DDSPixelFormat &format = dds.pixelFormat;
284 if (format.flags & DDSPixelFormat::FlagPaletteIndexed4) {
285 return FormatP4;
286 } else if (format.flags & DDSPixelFormat::FlagPaletteIndexed8) {
287 return FormatP8;
288 } else if (format.flags & DDSPixelFormat::FlagFourCC) {
289 for (size_t i = 0; i < knownFourCCsSize; ++i) {
290 if (dds.pixelFormat.fourCC == knownFourCCs[i])
291 return knownFourCCs[i];
292 }
293 } else {
294 for (size_t i = 0; i < formatInfosSize; ++i) {
295 const FormatInfo &info = formatInfos[i];
296 if ((format.flags & info.flags) == info.flags &&
297 format.rgbBitCount == info.bitCount &&
298 format.rBitMask == info.rBitMask &&
299 format.gBitMask == info.gBitMask &&
300 format.bBitMask == info.bBitMask &&
301 format.aBitMask == info.aBitMask) {
302 return info.format;
303 }
304 }
305 }
306
307 return FormatUnknown;
308}
309
310static inline quint8 getNormalZ(quint8 nx, quint8 ny)
311{
312 const double fx = nx / 127.5 - 1.0;
313 const double fy = ny / 127.5 - 1.0;
314 const double fxfy = 1.0 - fx * fx - fy * fy;
315 return fxfy > 0 ? 255 * std::sqrt(fxfy) : 0;
316}
317
318static inline void decodeColor(quint16 color, quint8 &red, quint8 &green, quint8 &blue)
319{
320 red = ((color >> 11) & 0x1f) << 3;
321 green = ((color >> 5) & 0x3f) << 2;
322 blue = (color & 0x1f) << 3;
323}
324
325static inline quint8 calcC2(quint8 c0, quint8 c1)
326{
327 return 2.0 * c0 / 3.0 + c1 / 3.0;
328}
329
330static inline quint8 calcC2a(quint8 c0, quint8 c1)
331{
332 return c0 / 2.0 + c1 / 2.0;
333}
334
335static inline quint8 calcC3(quint8 c0, quint8 c1)
336{
337 return c0 / 3.0 + 2.0 * c1 / 3.0;
338}
339
340static void DXTFillColors(QRgb *result, quint16 c0, quint16 c1, quint32 table, bool dxt1a = false)
341{
342 quint8 r[4];
343 quint8 g[4];
344 quint8 b[4];
345 quint8 a[4];
346
347 a[0] = a[1] = a[2] = a[3] = 255;
348
349 decodeColor(c0, r[0], g[0], b[0]);
350 decodeColor(c1, r[1], g[1], b[1]);
351 if (!dxt1a) {
352 r[2] = calcC2(r[0], r[1]);
353 g[2] = calcC2(g[0], g[1]);
354 b[2] = calcC2(b[0], b[1]);
355 r[3] = calcC3(r[0], r[1]);
356 g[3] = calcC3(g[0], g[1]);
357 b[3] = calcC3(b[0], b[1]);
358 } else {
359 r[2] = calcC2a(r[0], r[1]);
360 g[2] = calcC2a(g[0], g[1]);
361 b[2] = calcC2a(b[0], b[1]);
362 r[3] = g[3] = b[3] = a[3] = 0;
363 }
364
365 for (int k = 0; k < 4; k++)
366 for (int l = 0; l < 4; l++) {
367 unsigned index = table & 0x0003;
368 table >>= 2;
369
370 result[k * 4 + l] = qRgba(r[index], g[index], b[index], a[index]);
371 }
372}
373
374template <DXTVersions version>
375inline void setAlphaDXT32Helper(QRgb *rgbArr, quint64 alphas)
376{
377 Q_STATIC_ASSERT(version == Two || version == Three);
378 for (int i = 0; i < 16; i++) {
379 quint8 alpha = 16 * (alphas & 0x0f);
380 QRgb rgb = rgbArr[i];
381 if (version == Two) // DXT2
382 rgbArr[i] = qRgba(qRed(rgb) * alpha / 0xff, qGreen(rgb) * alpha / 0xff, qBlue(rgb) * alpha / 0xff, alpha);
383 else if (version == Three) // DXT3
384 rgbArr[i] = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), alpha);
385 alphas = alphas >> 4;
386 }
387}
388
389template <DXTVersions version>
390inline void setAlphaDXT45Helper(QRgb *rgbArr, quint64 alphas)
391{
392 Q_STATIC_ASSERT(version == Four || version == Five);
393 quint8 a[8];
394 a[0] = alphas & 0xff;
395 a[1] = (alphas >> 8) & 0xff;
396 if (a[0] > a[1]) {
397 a[2] = (6*a[0] + 1*a[1]) / 7;
398 a[3] = (5*a[0] + 2*a[1]) / 7;
399 a[4] = (4*a[0] + 3*a[1]) / 7;
400 a[5] = (3*a[0] + 4*a[1]) / 7;
401 a[6] = (2*a[0] + 5*a[1]) / 7;
402 a[7] = (1*a[0] + 6*a[1]) / 7;
403 } else {
404 a[2] = (4*a[0] + 1*a[1]) / 5;
405 a[3] = (3*a[0] + 2*a[1]) / 5;
406 a[4] = (2*a[0] + 3*a[1]) / 5;
407 a[5] = (1*a[0] + 4*a[1]) / 5;
408 a[6] = 0;
409 a[7] = 255;
410 }
411 alphas >>= 16;
412 for (int i = 0; i < 16; i++) {
413 quint8 index = alphas & 0x07;
414 quint8 alpha = a[index];
415 QRgb rgb = rgbArr[i];
416 if (version == Four) // DXT4
417 rgbArr[i] = qRgba(qRed(rgb) * alpha / 0xff, qGreen(rgb) * alpha / 0xff, qBlue(rgb) * alpha / 0xff, alpha);
418 else if (version == Five) // DXT5
419 rgbArr[i] = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), alpha);
420 alphas = alphas >> 3;
421 }
422}
423
424template <DXTVersions version>
425inline void setAlphaDXT(QRgb *rgbArr, quint64 alphas)
426{
427 Q_UNUSED(rgbArr);
428 Q_UNUSED(alphas);
429}
430
431template <>
432inline void setAlphaDXT<Two>(QRgb *rgbArr, quint64 alphas)
433{
434 setAlphaDXT32Helper<Two>(rgbArr, alphas);
435}
436
437template <>
438inline void setAlphaDXT<Three>(QRgb *rgbArr, quint64 alphas)
439{
440 setAlphaDXT32Helper<Three>(rgbArr, alphas);
441}
442
443template <>
444inline void setAlphaDXT<Four>(QRgb *rgbArr, quint64 alphas)
445{
446 setAlphaDXT45Helper<Four>(rgbArr, alphas);
447}
448
449template <>
450inline void setAlphaDXT<Five>(QRgb *rgbArr, quint64 alphas)
451{
452 setAlphaDXT45Helper<Five>(rgbArr, alphas);
453}
454
455template <>
456inline void setAlphaDXT<RXGB>(QRgb *rgbArr, quint64 alphas)
457{
458 setAlphaDXT45Helper<Five>(rgbArr, alphas);
459}
460
461static inline QRgb invertRXGBColors(QRgb pixel)
462{
463 return qRgb(qAlpha(pixel), qGreen(pixel), qBlue(pixel));
464}
465
466template <DXTVersions version>
467static QImage readDXT(QDataStream &s, quint32 width, quint32 height)
468{
469 QImage::Format format = (version == Two || version == Four) ?
470 QImage::Format_ARGB32_Premultiplied : QImage::Format_ARGB32;
471
472 QImage image(width, height, format);
473
474 for (quint32 i = 0; i < height; i += 4) {
475 for (quint32 j = 0; j < width; j += 4) {
476 quint64 alpha = 0;
477 quint16 c0, c1;
478 quint32 table;
479 if (version != One)
480 s >> alpha;
481 s >> c0;
482 s >> c1;
483 s >> table;
484
485 QRgb arr[16];
486
487 DXTFillColors(arr, c0, c1, table, version == One && c0 <= c1);
488 setAlphaDXT<version>(arr, alpha);
489
490 const quint32 kMax = qMin<quint32>(4, height - i);
491 const quint32 lMax = qMin<quint32>(4, width - j);
492 for (quint32 k = 0; k < kMax; k++) {
493 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(i + k));
494 for (quint32 l = 0; l < lMax; l++) {
495 QRgb pixel = arr[k * 4 + l];
496 if (version == RXGB)
497 pixel = invertRXGBColors(pixel);
498
499 line[j + l] = pixel;
500 }
501 }
502 }
503 }
504 return image;
505}
506
507static inline QImage readDXT1(QDataStream &s, quint32 width, quint32 height)
508{
509 return readDXT<One>(s, width, height);
510}
511
512static inline QImage readDXT2(QDataStream &s, quint32 width, quint32 height)
513{
514 return readDXT<Two>(s, width, height);
515}
516
517static inline QImage readDXT3(QDataStream &s, quint32 width, quint32 height)
518{
519 return readDXT<Three>(s, width, height);
520}
521
522static inline QImage readDXT4(QDataStream &s, quint32 width, quint32 height)
523{
524 return readDXT<Four>(s, width, height);
525}
526
527static inline QImage readDXT5(QDataStream &s, quint32 width, quint32 height)
528{
529 return readDXT<Five>(s, width, height);
530}
531
532static inline QImage readRXGB(QDataStream &s, quint32 width, quint32 height)
533{
534 return readDXT<RXGB>(s, width, height);
535}
536
537static QImage readATI2(QDataStream &s, quint32 width, quint32 height)
538{
539 QImage image(width, height, QImage::Format_RGB32);
540
541 for (quint32 i = 0; i < height; i += 4) {
542 for (quint32 j = 0; j < width; j += 4) {
543 quint64 alpha1;
544 quint64 alpha2;
545 s >> alpha1;
546 s >> alpha2;
547
548 QRgb arr[16];
549 memset(arr, 0, sizeof(QRgb) * 16);
550 setAlphaDXT<Five>(arr, alpha1);
551 for (int k = 0; k < 16; ++k) {
552 quint8 a = qAlpha(arr[k]);
553 arr[k] = qRgba(0, 0, a, 0);
554 }
555 setAlphaDXT<Five>(arr, alpha2);
556
557 const quint32 kMax = qMin<quint32>(4, height - i);
558 const quint32 lMax = qMin<quint32>(4, width - j);
559 for (quint32 k = 0; k < kMax; k++) {
560 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(i + k));
561 for (quint32 l = 0; l < lMax; l++) {
562 QRgb pixel = arr[k * 4 + l];
563 const quint8 nx = qAlpha(pixel);
564 const quint8 ny = qBlue(pixel);
565 const quint8 nz = getNormalZ(nx, ny);
566 line[j + l] = qRgb(nx, ny, nz);
567 }
568 }
569 }
570 }
571 return image;
572}
573
574static QImage readUnsignedImage(QDataStream &s, const DDSHeader &dds, quint32 width, quint32 height, bool hasAlpha)
575{
576 quint32 flags = dds.pixelFormat.flags;
577
578 quint32 masks[ColorCount];
579 quint8 shifts[ColorCount];
580 quint8 bits[ColorCount];
581 masks[Red] = dds.pixelFormat.rBitMask;
582 masks[Green] = dds.pixelFormat.gBitMask;
583 masks[Blue] = dds.pixelFormat.bBitMask;
584 masks[Alpha] = hasAlpha ? dds.pixelFormat.aBitMask : 0;
585 for (int i = 0; i < ColorCount; ++i) {
586 shifts[i] = maskToShift(masks[i]);
587 bits[i] = maskLength(masks[i]);
588
589 // move mask to the left
590 if (bits[i] <= 8)
591 masks[i] = (masks[i] >> shifts[i]) << (8 - bits[i]);
592 }
593
594 const QImage::Format format = hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32;
595
596 QImage image(width, height, format);
597
598 for (quint32 y = 0; y < height; y++) {
599 for (quint32 x = 0; x < width; x++) {
600 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
601
602 quint32 value = readValue(s, dds.pixelFormat.rgbBitCount);
603 quint8 colors[ColorCount];
604
605 for (int c = 0; c < ColorCount; ++c) {
606 if (bits[c] > 8) {
607 // truncate unneseccary bits
608 colors[c] = (value & masks[c]) >> shifts[c] >> (bits[c] - 8);
609 } else {
610 // move color to the left
611 quint8 color = value >> shifts[c] << (8 - bits[c]) & masks[c];
612 if (masks[c])
613 colors[c] = color * 0xff / masks[c];
614 else
615 colors[c] = 0;
616 }
617 }
618
620 line[x] = qRgba(colors[Red], colors[Red], colors[Red], colors[Alpha]);
621 else if (flags & DDSPixelFormat::FlagYUV)
622 line[x] = yuv2rgb(colors[Red], colors[Green], colors[Blue]);
623 else
624 line[x] = qRgba(colors[Red], colors[Green], colors[Blue], colors[Alpha]);
625 }
626 }
627
628 return image;
629}
630
631static double readFloat16(QDataStream &s)
632{
633 quint16 value;
634 s >> value;
635
636 double sign = (value & 0x8000) == 0x8000 ? -1.0 : 1.0;
637 qint8 exp = (value & 0x7C00) >> 10;
638 quint16 fraction = value & 0x3FF;
639
640 if (exp == 0)
641 return sign * std::pow(2.0, -14.0) * fraction / 1024.0;
642 else
643 return sign * std::pow(2.0, exp - 15) * (1 + fraction / 1024.0);
644}
645
646static inline float readFloat32(QDataStream &s)
647{
648 Q_ASSERT(sizeof(float) == 4);
649 float value;
650 // TODO: find better way to avoid setting precision each time
651 QDataStream::FloatingPointPrecision precision = s.floatingPointPrecision();
652 s.setFloatingPointPrecision(QDataStream::SinglePrecision);
653 s >> value;
654 s.setFloatingPointPrecision(precision);
655 return value;
656}
657
658static QImage readR16F(QDataStream &s, const quint32 width, const quint32 height)
659{
660 QImage image(width, height, QImage::Format_RGB32);
661
662 for (quint32 y = 0; y < height; y++) {
663 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
664 for (quint32 x = 0; x < width; x++) {
665 quint8 r = readFloat16(s) * 255;
666 line[x] = qRgba(r, 0, 0, 0);
667 }
668 }
669
670 return image;
671}
672
673static QImage readRG16F(QDataStream &s, const quint32 width, const quint32 height)
674{
675 QImage image(width, height, QImage::Format_RGB32);
676
677 for (quint32 y = 0; y < height; y++) {
678 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
679 for (quint32 x = 0; x < width; x++) {
680 quint8 r = readFloat16(s) * 255;
681 quint8 g = readFloat16(s) * 255;
682 line[x] = qRgba(r, g, 0, 0);
683 }
684 }
685
686 return image;
687}
688
689static QImage readARGB16F(QDataStream &s, const quint32 width, const quint32 height)
690{
691 QImage image(width, height, QImage::Format_ARGB32);
692
693 for (quint32 y = 0; y < height; y++) {
694 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
695 for (quint32 x = 0; x < width; x++) {
696 quint8 colors[ColorCount];
697 for (int c = 0; c < ColorCount; ++c)
698 colors[c] = readFloat16(s) * 255;
699
700 line[x] = qRgba(colors[Red], colors[Green], colors[Blue], colors[Alpha]);
701 }
702 }
703
704 return image;
705}
706
707static QImage readR32F(QDataStream &s, const quint32 width, const quint32 height)
708{
709 QImage image(width, height, QImage::Format_RGB32);
710
711 for (quint32 y = 0; y < height; y++) {
712 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
713 for (quint32 x = 0; x < width; x++) {
714 quint8 r = readFloat32(s) * 255;
715 line[x] = qRgba(r, 0, 0, 0);
716 }
717 }
718
719 return image;
720}
721
722static QImage readRG32F(QDataStream &s, const quint32 width, const quint32 height)
723{
724 QImage image(width, height, QImage::Format_RGB32);
725
726 for (quint32 y = 0; y < height; y++) {
727 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
728 for (quint32 x = 0; x < width; x++) {
729 quint8 r = readFloat32(s) * 255;
730 quint8 g = readFloat32(s) * 255;
731 line[x] = qRgba(r, g, 0, 0);
732 }
733 }
734
735 return image;
736}
737
738static QImage readARGB32F(QDataStream &s, const quint32 width, const quint32 height)
739{
740 QImage image(width, height, QImage::Format_ARGB32);
741
742 for (quint32 y = 0; y < height; y++) {
743 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
744 for (quint32 x = 0; x < width; x++) {
745 quint8 colors[ColorCount];
746 for (int c = 0; c < ColorCount; ++c)
747 colors[c] = readFloat32(s) * 255;
748 line[x] = qRgba(colors[Red], colors[Green], colors[Blue], colors[Alpha]);
749 }
750 }
751
752 return image;
753}
754
755static QImage readQ16W16V16U16(QDataStream &s, const quint32 width, const quint32 height)
756{
757 QImage image(width, height, QImage::Format_ARGB32);
758
759 quint8 colors[ColorCount];
760 qint16 tmp;
761 for (quint32 y = 0; y < height; y++) {
762 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
763 for (quint32 x = 0; x < width; x++) {
764 for (int i = 0; i < ColorCount; i++) {
765 s >> tmp;
766 colors[i] = (tmp + 0x7FFF) >> 8;
767 }
768 line[x] = qRgba(colors[Red], colors[Green], colors[Blue], colors[Alpha]);
769 }
770 }
771
772 return image;
773}
774
775static QImage readCxV8U8(QDataStream &s, const quint32 width, const quint32 height)
776{
777 QImage image(width, height, QImage::Format_RGB32);
778
779 for (quint32 y = 0; y < height; y++) {
780 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
781 for (quint32 x = 0; x < width; x++) {
782 qint8 v, u;
783 s >> v >> u;
784
785 const quint8 vn = v + 128;
786 const quint8 un = u + 128;
787 const quint8 c = getNormalZ(vn, un);
788
789 line[x] = qRgb(vn, un, c);
790 }
791 }
792
793 return image;
794}
795
796static QImage readPalette8Image(QDataStream &s, quint32 width, quint32 height)
797{
798 QImage image(width, height, QImage::Format_Indexed8);
799 for (int i = 0; i < 256; ++i) {
800 quint8 r, g, b, a;
801 s >> r >> g >> b >> a;
802 image.setColor(i, qRgba(r, g, b, a));
803 }
804
805 for (quint32 y = 0; y < height; y++) {
806 for (quint32 x = 0; x < width; x++) {
807 quint8 index;
808 s >> index;
809 image.setPixel(x, y, index);
810 }
811 }
812
813 return image;
814}
815
816static QImage readPalette4Image(QDataStream &s, quint32 width, quint32 height)
817{
818 QImage image(width, height, QImage::Format_Indexed8);
819 for (int i = 0; i < 16; ++i) {
820 quint8 r, g, b, a;
821 s >> r >> g >> b >> a;
822 image.setColor(i, qRgba(r, g, b, a));
823 }
824
825 for (quint32 y = 0; y < height; y++) {
826 quint8 index;
827 for (quint32 x = 0; x < width - 1; ) {
828 s >> index;
829 image.setPixel(x++, y, (index & 0x0f) >> 0);
830 image.setPixel(x++, y, (index & 0xf0) >> 4);
831 }
832 if (width % 2 == 1) {
833 s >> index;
834 image.setPixel(width - 1, y, (index & 0x0f) >> 0);
835 }
836 }
837
838 return image;
839}
840
841static QImage readARGB16(QDataStream &s, quint32 width, quint32 height)
842{
843 QImage image(width, height, QImage::Format_ARGB32);
844
845 for (quint32 y = 0; y < height; y++) {
846 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
847 for (quint32 x = 0; x < width; x++) {
848 quint8 colors[ColorCount];
849 for (int i = 0; i < ColorCount; ++i) {
850 quint16 color;
851 s >> color;
852 colors[i] = quint8(color >> 8);
853 }
854 line[x] = qRgba(colors[Red], colors[Green], colors[Blue], colors[Alpha]);
855 }
856 }
857
858 return image;
859}
860
861static QImage readV8U8(QDataStream &s, quint32 width, quint32 height)
862{
863 QImage image(width, height, QImage::Format_RGB32);
864
865 for (quint32 y = 0; y < height; y++) {
866 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
867 for (quint32 x = 0; x < width; x++) {
868 qint8 v, u;
869 s >> v >> u;
870 line[x] = qRgb(v + 128, u + 128, 255);
871 }
872 }
873
874 return image;
875}
876
877static QImage readL6V5U5(QDataStream &s, quint32 width, quint32 height)
878{
879 QImage image(width, height, QImage::Format_ARGB32);
880
881 quint16 tmp;
882 for (quint32 y = 0; y < height; y++) {
883 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
884 for (quint32 x = 0; x < width; x++) {
885 s >> tmp;
886 quint8 r = qint8((tmp & 0x001f) >> 0) * 0xff/0x1f + 128;
887 quint8 g = qint8((tmp & 0x03e0) >> 5) * 0xff/0x1f + 128;
888 quint8 b = quint8((tmp & 0xfc00) >> 10) * 0xff/0x3f;
889 line[x] = qRgba(r, g, 0xff, b);
890 }
891 }
892 return image;
893}
894
895static QImage readX8L8V8U8(QDataStream &s, quint32 width, quint32 height)
896{
897 QImage image(width, height, QImage::Format_ARGB32);
898
899 quint8 a, l;
900 qint8 v, u;
901 for (quint32 y = 0; y < height; y++) {
902 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
903 for (quint32 x = 0; x < width; x++) {
904 s >> v >> u >> a >> l;
905 line[x] = qRgba(v + 128, u + 128, 255, a);
906 }
907 }
908
909 return image;
910}
911
912static QImage readQ8W8V8U8(QDataStream &s, quint32 width, quint32 height)
913{
914 QImage image(width, height, QImage::Format_ARGB32);
915
916 quint8 colors[ColorCount];
917 qint8 tmp;
918 for (quint32 y = 0; y < height; y++) {
919 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
920 for (quint32 x = 0; x < width; x++) {
921 for (int i = 0; i < ColorCount; i++) {
922 s >> tmp;
923 colors[i] = tmp + 128;
924 }
925 line[x] = qRgba(colors[Red], colors[Green], colors[Blue], colors[Alpha]);
926 }
927 }
928
929 return image;
930}
931
932static QImage readV16U16(QDataStream &s, quint32 width, quint32 height)
933{
934 QImage image(width, height, QImage::Format_RGB32);
935
936 for (quint32 y = 0; y < height; y++) {
937 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
938 for (quint32 x = 0; x < width; x++) {
939 qint16 v, u;
940 s >> v >> u;
941 v = (v + 0x8000) >> 8;
942 u = (u + 0x8000) >> 8;
943 line[x] = qRgb(v, u, 255);
944 }
945 }
946
947 return image;
948}
949
950static QImage readA2W10V10U10(QDataStream &s, quint32 width, quint32 height)
951{
952 QImage image(width, height, QImage::Format_ARGB32);
953
954 quint32 tmp;
955 for (quint32 y = 0; y < height; y++) {
956 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
957 for (quint32 x = 0; x < width; x++) {
958 s >> tmp;
959 quint8 r = qint8((tmp & 0x3ff00000) >> 20 >> 2) + 128;
960 quint8 g = qint8((tmp & 0x000ffc00) >> 10 >> 2) + 128;
961 quint8 b = qint8((tmp & 0x000003ff) >> 0 >> 2) + 128;
962 quint8 a = 0xff * ((tmp & 0xc0000000) >> 30) / 3;
963 // dunno why we should swap b and r here
964 std::swap(b, r);
965 line[x] = qRgba(r, g, b, a);
966 }
967 }
968
969 return image;
970}
971
972static QImage readUYVY(QDataStream &s, quint32 width, quint32 height)
973{
974 QImage image(width, height, QImage::Format_RGB32);
975
976 quint8 uyvy[4];
977 for (quint32 y = 0; y < height; y++) {
978 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
979 for (quint32 x = 0; x < width - 1; ) {
980 s >> uyvy[0] >> uyvy[1] >> uyvy[2] >> uyvy[3];
981 line[x++] = yuv2rgb(uyvy[1], uyvy[0], uyvy[2]);
982 line[x++] = yuv2rgb(uyvy[3], uyvy[0], uyvy[2]);
983 }
984 if (width % 2 == 1) {
985 s >> uyvy[0] >> uyvy[1] >> uyvy[2] >> uyvy[3];
986 line[width - 1] = yuv2rgb(uyvy[1], uyvy[0], uyvy[2]);
987 }
988 }
989
990 return image;
991}
992
993static QImage readR8G8B8G8(QDataStream &s, quint32 width, quint32 height)
994{
995 QImage image(width, height, QImage::Format_RGB32);
996 quint8 rgbg[4];
997 for (quint32 y = 0; y < height; y++) {
998 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
999 for (quint32 x = 0; x < width - 1; ) {
1000 s >> rgbg[1] >> rgbg[0] >> rgbg[3] >> rgbg[2];
1001 line[x++] = qRgb(rgbg[0], rgbg[1], rgbg[2]);
1002 line[x++] = qRgb(rgbg[0], rgbg[3], rgbg[2]);
1003 }
1004 if (width % 2 == 1) {
1005 s >> rgbg[1] >> rgbg[0] >> rgbg[3] >> rgbg[2];
1006 line[width - 1] = qRgb(rgbg[0], rgbg[1], rgbg[2]);
1007 }
1008 }
1009
1010 return image;
1011}
1012
1013static QImage readYUY2(QDataStream &s, quint32 width, quint32 height)
1014{
1015 QImage image(width, height, QImage::Format_RGB32);
1016
1017 quint8 yuyv[4];
1018 for (quint32 y = 0; y < height; y++) {
1019 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
1020 for (quint32 x = 0; x < width - 1; ) {
1021 s >> yuyv[0] >> yuyv[1] >> yuyv[2] >> yuyv[3];
1022 line[x++] = yuv2rgb(yuyv[0], yuyv[1], yuyv[3]);
1023 line[x++] = yuv2rgb(yuyv[2], yuyv[1], yuyv[3]);
1024 }
1025 if (width % 2 == 1) {
1026 s >> yuyv[0] >> yuyv[1] >> yuyv[2] >> yuyv[3];
1027 line[width - 1] = yuv2rgb(yuyv[2], yuyv[1], yuyv[3]);
1028 }
1029 }
1030
1031 return image;
1032}
1033
1034static QImage readG8R8G8B8(QDataStream &s, quint32 width, quint32 height)
1035{
1036 QImage image(width, height, QImage::Format_RGB32);
1037 quint8 grgb[4];
1038 for (quint32 y = 0; y < height; y++) {
1039 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
1040 for (quint32 x = 0; x < width - 1; ) {
1041 s >> grgb[1] >> grgb[0] >> grgb[3] >> grgb[2];
1042 line[x++] = qRgb(grgb[1], grgb[0], grgb[3]);
1043 line[x++] = qRgb(grgb[1], grgb[2], grgb[3]);
1044 }
1045 if (width % 2 == 1) {
1046 s >> grgb[1] >> grgb[0] >> grgb[3] >> grgb[2];
1047 line[width - 1] = qRgb(grgb[1], grgb[0], grgb[3]);
1048 }
1049 }
1050
1051 return image;
1052}
1053
1054static QImage readA2R10G10B10(QDataStream &s, const DDSHeader &dds, quint32 width, quint32 height)
1055{
1056 QImage image = readUnsignedImage(s, dds, width, height, true);
1057 for (quint32 y = 0; y < height; y++) {
1058 QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(y));
1059 for (quint32 x = 0; x < width; x++) {
1060 QRgb pixel = image.pixel(x, y);
1061 line[x] = qRgba(qBlue(pixel), qGreen(pixel), qRed(pixel), qAlpha(pixel));
1062 }
1063 }
1064 return image;
1065}
1066
1067static QImage readLayer(QDataStream &s, const DDSHeader &dds, const int format, quint32 width, quint32 height)
1068{
1069 if (width * height == 0)
1070 return QImage();
1071
1072 switch (format) {
1073 case FormatR8G8B8:
1074 case FormatX8R8G8B8:
1075 case FormatR5G6B5:
1076 case FormatR3G3B2:
1077 case FormatX1R5G5B5:
1078 case FormatX4R4G4B4:
1079 case FormatX8B8G8R8:
1080 case FormatG16R16:
1081 case FormatL8:
1082 case FormatL16:
1083 return readUnsignedImage(s, dds, width, height, false);
1084 case FormatA8R8G8B8:
1085 case FormatA1R5G5B5:
1086 case FormatA4R4G4B4:
1087 case FormatA8:
1088 case FormatA8R3G3B2:
1089 case FormatA8B8G8R8:
1090 case FormatA8L8:
1091 case FormatA4L4:
1092 return readUnsignedImage(s, dds, width, height, true);
1093 case FormatA2R10G10B10:
1094 case FormatA2B10G10R10:
1095 return readA2R10G10B10(s, dds, width, height);
1096 case FormatP8:
1097 case FormatA8P8:
1098 return readPalette8Image(s, width, height);
1099 case FormatP4:
1100 case FormatA4P4:
1101 return readPalette4Image(s, width, height);
1102 case FormatA16B16G16R16:
1103 return readARGB16(s, width, height);
1104 case FormatV8U8:
1105 return readV8U8(s, width, height);
1106 case FormatL6V5U5:
1107 return readL6V5U5(s, width, height);
1108 case FormatX8L8V8U8:
1109 return readX8L8V8U8(s, width, height);
1110 case FormatQ8W8V8U8:
1111 return readQ8W8V8U8(s, width, height);
1112 case FormatV16U16:
1113 return readV16U16(s, width, height);
1114 case FormatA2W10V10U10:
1115 return readA2W10V10U10(s, width, height);
1116 case FormatUYVY:
1117 return readUYVY(s, width, height);
1118 case FormatR8G8B8G8:
1119 return readR8G8B8G8(s, width, height);
1120 case FormatYUY2:
1121 return readYUY2(s, width, height);
1122 case FormatG8R8G8B8:
1123 return readG8R8G8B8(s, width, height);
1124 case FormatDXT1:
1125 return readDXT1(s, width, height);
1126 case FormatDXT2:
1127 return readDXT2(s, width, height);
1128 case FormatDXT3:
1129 return readDXT3(s, width, height);
1130 case FormatDXT4:
1131 return readDXT4(s, width, height);
1132 case FormatDXT5:
1133 return readDXT5(s, width, height);
1134 case FormatRXGB:
1135 return readRXGB(s, width, height);
1136 case FormatATI2:
1137 return readATI2(s, width, height);
1138 case FormatR16F:
1139 return readR16F(s, width, height);
1140 case FormatG16R16F:
1141 return readRG16F(s, width, height);
1142 case FormatA16B16G16R16F:
1143 return readARGB16F(s, width, height);
1144 case FormatR32F:
1145 return readR32F(s, width, height);
1146 case FormatG32R32F:
1147 return readRG32F(s, width, height);
1148 case FormatA32B32G32R32F:
1149 return readARGB32F(s, width, height);
1150 case FormatD16Lockable:
1151 case FormatD32:
1152 case FormatD15S1:
1153 case FormatD24S8:
1154 case FormatD24X8:
1155 case FormatD24X4S4:
1156 case FormatD16:
1157 case FormatD32FLockable:
1158 case FormatD24FS8:
1159 case FormatD32Lockable:
1160 case FormatS8Lockable:
1161 case FormatVertexData:
1162 case FormatIndex16:
1163 case FormatIndex32:
1164 break;
1165 case FormatQ16W16V16U16:
1166 return readQ16W16V16U16(s, width, height);
1167 case FormatMulti2ARGB8:
1168 break;
1169 case FormatCxV8U8:
1170 return readCxV8U8(s, width, height);
1171 case FormatA1:
1172 case FormatA2B10G10R10_XR_BIAS:
1173 case FormatBinaryBuffer:
1174 case FormatLast:
1175 break;
1176 }
1177
1178 return QImage();
1179}
1180
1181static inline QImage readTexture(QDataStream &s, const DDSHeader &dds, const int format, const int mipmapLevel)
1182{
1183 quint32 width = dds.width / (1 << mipmapLevel);
1184 quint32 height = dds.height / (1 << mipmapLevel);
1185 return readLayer(s, dds, format, width, height);
1186}
1187
1188static qint64 mipmapSize(const DDSHeader &dds, const int format, const int level)
1189{
1190 quint32 w = dds.width/(1 << level);
1191 quint32 h = dds.height/(1 << level);
1192
1193 switch (format) {
1194 case FormatR8G8B8:
1195 case FormatX8R8G8B8:
1196 case FormatR5G6B5:
1197 case FormatX1R5G5B5:
1198 case FormatX4R4G4B4:
1199 case FormatX8B8G8R8:
1200 case FormatG16R16:
1201 case FormatL8:
1202 case FormatL16:
1203 return w * h * dds.pixelFormat.rgbBitCount / 8;
1204 case FormatA8R8G8B8:
1205 case FormatA1R5G5B5:
1206 case FormatA4R4G4B4:
1207 case FormatA8:
1208 case FormatA8R3G3B2:
1209 case FormatA2B10G10R10:
1210 case FormatA8B8G8R8:
1211 case FormatA2R10G10B10:
1212 case FormatA8L8:
1213 case FormatA4L4:
1214 return w * h * dds.pixelFormat.rgbBitCount / 8;
1215 case FormatP8:
1216 return 256 + w * h * 8;
1217 case FormatA16B16G16R16:
1218 return w * h * 4 * 2;
1219 case FormatA8P8:
1220 break;
1221 case FormatV8U8:
1222 case FormatL6V5U5:
1223 return w * h * 2;
1224 case FormatX8L8V8U8:
1225 case FormatQ8W8V8U8:
1226 case FormatV16U16:
1227 case FormatA2W10V10U10:
1228 return w * h * 4;
1229 case FormatUYVY:
1230 case FormatR8G8B8G8:
1231 case FormatYUY2:
1232 case FormatG8R8G8B8:
1233 return w * h * 2;
1234 case FormatDXT1:
1235 return ((w + 3)/4) * ((h + 3)/4) * 8;
1236 case FormatDXT2:
1237 case FormatDXT3:
1238 case FormatDXT4:
1239 case FormatDXT5:
1240 return ((w + 3)/4) * ((h + 3)/4) * 16;
1241 case FormatD16Lockable:
1242 case FormatD32:
1243 case FormatD15S1:
1244 case FormatD24S8:
1245 case FormatD24X8:
1246 case FormatD24X4S4:
1247 case FormatD16:
1248 case FormatD32FLockable:
1249 case FormatD24FS8:
1250 case FormatD32Lockable:
1251 case FormatS8Lockable:
1252 case FormatVertexData:
1253 case FormatIndex16:
1254 case FormatIndex32:
1255 break;
1256 case FormatQ16W16V16U16:
1257 return w * h * 4 * 2;
1258 case FormatMulti2ARGB8:
1259 break;
1260 case FormatR16F:
1261 return w * h * 1 * 2;
1262 case FormatG16R16F:
1263 return w * h * 2 * 2;
1264 case FormatA16B16G16R16F:
1265 return w * h * 4 * 2;
1266 case FormatR32F:
1267 return w * h * 1 * 4;
1268 case FormatG32R32F:
1269 return w * h * 2 * 4;
1270 case FormatA32B32G32R32F:
1271 return w * h * 4 * 4;
1272 case FormatCxV8U8:
1273 return w * h * 2;
1274 case FormatA1:
1275 case FormatA2B10G10R10_XR_BIAS:
1276 case FormatBinaryBuffer:
1277 case FormatLast:
1278 break;
1279 }
1280
1281 return 0;
1282}
1283
1284static qint64 mipmapOffset(const DDSHeader &dds, const int format, const int level)
1285{
1286 qint64 result = 0;
1287 for (int i = 0; i < level; ++i)
1288 result += mipmapSize(dds, format, i);
1289 return result;
1290}
1291
1292static QImage readCubeMap(QDataStream &s, const DDSHeader &dds, const int fmt)
1293{
1294 QImage::Format format = hasAlpha(dds) ? QImage::Format_ARGB32 : QImage::Format_RGB32;
1295 QImage image(4 * dds.width, 3 * dds.height, format);
1296
1297 image.fill(0);
1298
1299 for (int i = 0; i < 6; i++) {
1300 if (!(dds.caps2 & faceFlags[i]))
1301 continue; // Skip face.
1302
1303 const QImage face = readLayer(s, dds, fmt, dds.width, dds.height);
1304
1305 // Compute face offsets.
1306 int offset_x = faceOffsets[i].x * dds.width;
1307 int offset_y = faceOffsets[i].y * dds.height;
1308
1309 // Copy face on the image.
1310 for (quint32 y = 0; y < dds.height; y++) {
1311 const QRgb *src = reinterpret_cast<const QRgb *>(face.scanLine(y));
1312 QRgb *dst = reinterpret_cast<QRgb *>(image.scanLine(y + offset_y)) + offset_x;
1313 memcpy(dst, src, sizeof(QRgb) * dds.width);
1314 }
1315 }
1316
1317 return image;
1318}
1319
1320static QByteArray formatName(int format)
1321{
1322 for (size_t i = 0; i < formatNamesSize; ++i) {
1323 if (formatNames[i].format == format)
1324 return formatNames[i].name;
1325 }
1326
1327 return formatNames[0].name;
1328}
1329
1330static int formatByName(const QByteArray &name)
1331{
1332 const QByteArray loweredName = name.toLower();
1333 for (size_t i = 0; i < formatNamesSize; ++i) {
1334 if (QByteArray(formatNames[i].name).toLower() == loweredName)
1335 return formatNames[i].format;
1336 }
1337
1338 return FormatUnknown;
1339}
1340
1342 m_header(),
1343 m_format(FormatA8R8G8B8),
1344 m_header10(),
1345 m_currentImage(0),
1346 m_scanState(ScanNotScanned)
1347{
1348}
1349
1351{
1352 if (m_scanState == ScanNotScanned && !canRead(device()))
1353 return false;
1354
1355 if (m_scanState != ScanError) {
1356 setFormat(QByteArrayLiteral("dds"));
1357 return true;
1358 }
1359
1360 return false;
1361}
1362
1363bool QDDSHandler::read(QImage *outImage)
1364{
1365 if (!ensureScanned() || device()->isSequential())
1366 return false;
1367
1368 qint64 pos = headerSize + mipmapOffset(m_header, m_format, m_currentImage);
1369 if (!device()->seek(pos))
1370 return false;
1371 QDataStream s(device());
1372 s.setByteOrder(QDataStream::LittleEndian);
1373
1374 QImage image = isCubeMap(m_header) ?
1375 readCubeMap(s, m_header, m_format) :
1376 readTexture(s, m_header, m_format, m_currentImage);
1377
1378 bool ok = s.status() == QDataStream::Ok && !image.isNull();
1379 if (ok)
1380 *outImage = image;
1381 return ok;
1382}
1383
1384bool QDDSHandler::write(const QImage &outImage)
1385{
1386 if (m_format != FormatA8R8G8B8) {
1387 qWarning() << "Format" << formatName(m_format) << "is not supported";
1388 return false;
1389 }
1390
1391 const QImage image = outImage.convertToFormat(QImage::Format_ARGB32);
1392
1393 QDataStream s(device());
1394 s.setByteOrder(QDataStream::LittleEndian);
1395
1396 DDSHeader dds;
1397 // Filling header
1398 dds.magic = ddsMagic;
1399 dds.size = 124;
1402 dds.height = image.height();
1403 dds.width = image.width();
1404 dds.pitchOrLinearSize = 128;
1405 dds.depth = 0;
1406 dds.mipMapCount = 0;
1407 for (int i = 0; i < DDSHeader::ReservedCount; i++)
1408 dds.reserved1[i] = 0;
1409 dds.caps = DDSHeader::CapsTexture;
1410 dds.caps2 = 0;
1411 dds.caps3 = 0;
1412 dds.caps4 = 0;
1413 dds.reserved2 = 0;
1414
1415 // Filling pixelformat
1416 dds.pixelFormat.size = 32;
1418 dds.pixelFormat.fourCC = 0;
1419 dds.pixelFormat.rgbBitCount = 32;
1420 dds.pixelFormat.aBitMask = 0xff000000;
1421 dds.pixelFormat.rBitMask = 0x00ff0000;
1422 dds.pixelFormat.gBitMask = 0x0000ff00;
1423 dds.pixelFormat.bBitMask = 0x000000ff;
1424
1425 s << dds;
1426 for (int height = 0; height < image.height(); height++) {
1427 for (int width = 0; width < image.width(); width++) {
1428 QRgb pixel = image.pixel(width, height);
1429 quint32 color;
1430 quint8 alpha = qAlpha(pixel);
1431 quint8 red = qRed(pixel);
1432 quint8 green = qGreen(pixel);
1433 quint8 blue = qBlue(pixel);
1434 color = (alpha << 24) + (red << 16) + (green << 8) + blue;
1435 s << color;
1436 }
1437 }
1438
1439 return true;
1440}
1441
1442QVariant QDDSHandler::option(QImageIOHandler::ImageOption option) const
1443{
1444 if (!supportsOption(option) || !ensureScanned())
1445 return QVariant();
1446
1447 switch (option) {
1448 case QImageIOHandler::Size:
1449 return QSize(m_header.width, m_header.height);
1450 case QImageIOHandler::SubType:
1451 return formatName(m_format);
1452 case QImageIOHandler::SupportedSubTypes:
1453 return QVariant::fromValue(QList<QByteArray>() << formatName(FormatA8R8G8B8));
1454 default:
1455 break;
1456 }
1457
1458 return QVariant();
1459}
1460
1461void QDDSHandler::setOption(QImageIOHandler::ImageOption option, const QVariant &value)
1462{
1463 if (option == QImageIOHandler::SubType) {
1464 const QByteArray subType = value.toByteArray();
1465 m_format = formatByName(subType.toUpper());
1466 if (m_format == FormatUnknown)
1467 qWarning() << "unknown format" << subType;
1468 }
1469}
1470
1471bool QDDSHandler::supportsOption(QImageIOHandler::ImageOption option) const
1472{
1473 return (option == QImageIOHandler::Size)
1474 || (option == QImageIOHandler::SubType)
1475 || (option == QImageIOHandler::SupportedSubTypes);
1476}
1477
1479{
1480 if (!ensureScanned())
1481 return 0;
1482
1483 return qMax<quint32>(1, m_header.mipMapCount);
1484}
1485
1486bool QDDSHandler::jumpToImage(int imageNumber)
1487{
1488 if (imageNumber >= imageCount())
1489 return false;
1490
1491 m_currentImage = imageNumber;
1492 return true;
1493}
1494
1495bool QDDSHandler::canRead(QIODevice *device)
1496{
1497 if (!device) {
1498 qWarning() << "DDSHandler::canRead() called with no device";
1499 return false;
1500 }
1501
1502 if (device->isSequential())
1503 return false;
1504
1505 return device->peek(4) == QByteArrayLiteral("DDS ");
1506}
1507
1508bool QDDSHandler::ensureScanned() const
1509{
1510 if (m_scanState != ScanNotScanned)
1511 return m_scanState == ScanSuccess;
1512
1513 m_scanState = ScanError;
1514
1515 QDDSHandler *that = const_cast<QDDSHandler *>(this);
1516 that->m_format = FormatUnknown;
1517
1518 if (device()->isSequential()) {
1519 qWarning() << "Sequential devices are not supported";
1520 return false;
1521 }
1522
1523 qint64 oldPos = device()->pos();
1524 device()->seek(0);
1525
1526 QDataStream s(device());
1527 s.setByteOrder(QDataStream::LittleEndian);
1528 s >> that->m_header;
1529 if (m_header.pixelFormat.fourCC == dx10Magic)
1530 s >> that->m_header10;
1531
1532 device()->seek(oldPos);
1533
1534 if (s.status() != QDataStream::Ok)
1535 return false;
1536
1537 if (!verifyHeader(m_header))
1538 return false;
1539
1540 that->m_format = getFormat(m_header);
1541 if (that->m_format == FormatUnknown)
1542 return false;
1543
1544 m_scanState = ScanSuccess;
1545 return true;
1546}
1547
1548bool QDDSHandler::verifyHeader(const DDSHeader &dds) const
1549{
1550 quint32 flags = dds.flags;
1551 quint32 requiredFlags = DDSHeader::FlagCaps | DDSHeader::FlagHeight
1553 if ((flags & requiredFlags) != requiredFlags) {
1554 qWarning() << "Wrong dds.flags - not all required flags present. "
1555 "Actual flags :" << flags;
1556 return false;
1557 }
1558
1559 if (dds.size != ddsSize) {
1560 qWarning() << "Wrong dds.size: actual =" << dds.size
1561 << "expected =" << ddsSize;
1562 return false;
1563 }
1564
1565 if (dds.pixelFormat.size != pixelFormatSize) {
1566 qWarning() << "Wrong dds.pixelFormat.size: actual =" << dds.pixelFormat.size
1567 << "expected =" << pixelFormatSize;
1568 return false;
1569 }
1570
1571 if (dds.width > INT_MAX || dds.height > INT_MAX) {
1572 qWarning() << "Can't read image with w/h bigger than INT_MAX";
1573 return false;
1574 }
1575
1576 return true;
1577}
1578
1579QT_END_NAMESPACE
1580
1581#endif // QT_NO_DATASTREAM
bool canRead() const override
Returns true if an image can be read from the device (i.e., the image format is supported,...
QVariant option(QImageIOHandler::ImageOption option) const override
Returns the value assigned to option as a QVariant.
int imageCount() const override
For image formats that support animation, this function returns the number of images in the animation...
bool read(QImage *image) override
Read an image from the device, and stores it in image.
bool jumpToImage(int imageNumber) override
For image formats that support animation, this function jumps to the image whose sequence number is i...
bool write(const QImage &image) override
Writes the image image to the assigned device.
static quint8 calcC3(quint8 c0, quint8 c1)
static const quint32 pixelFormatSize
DXTVersions
@ Four
@ One
@ Three
@ Two
@ RXGB
@ Five
static QImage readUYVY(QDataStream &s, quint32 width, quint32 height)
static const FaceOffset faceOffsets[6]
static bool isCubeMap(const DDSHeader &dds)
static double readFloat16(QDataStream &s)
static QImage readQ16W16V16U16(QDataStream &s, const quint32 width, const quint32 height)
static QImage readR32F(QDataStream &s, const quint32 width, const quint32 height)
static const Format knownFourCCs[]
static QImage readPalette4Image(QDataStream &s, quint32 width, quint32 height)
static const quint32 dx10Magic
static quint8 calcC2a(quint8 c0, quint8 c1)
static QImage readYUY2(QDataStream &s, quint32 width, quint32 height)
static QImage readDXT4(QDataStream &s, quint32 width, quint32 height)
static QImage readR16F(QDataStream &s, const quint32 width, const quint32 height)
static QImage readDXT(QDataStream &s, quint32 width, quint32 height)
static QImage readDXT1(QDataStream &s, quint32 width, quint32 height)
static QImage readLayer(QDataStream &s, const DDSHeader &dds, const int format, quint32 width, quint32 height)
static QImage readCxV8U8(QDataStream &s, const quint32 width, const quint32 height)
static const FormatName formatNames[]
static QImage readTexture(QDataStream &s, const DDSHeader &dds, const int format, const int mipmapLevel)
static QImage readDXT3(QDataStream &s, quint32 width, quint32 height)
void setAlphaDXT45Helper(QRgb *rgbArr, quint64 alphas)
static QImage readRG32F(QDataStream &s, const quint32 width, const quint32 height)
static int maskLength(quint32 mask)
static const quint32 ddsSize
static QImage readDXT2(QDataStream &s, quint32 width, quint32 height)
static QImage readARGB32F(QDataStream &s, const quint32 width, const quint32 height)
static quint32 readValue(QDataStream &s, quint32 size)
static QImage readRG16F(QDataStream &s, const quint32 width, const quint32 height)
static QImage readATI2(QDataStream &s, quint32 width, quint32 height)
static QRgb yuv2rgb(quint8 Y, quint8 U, quint8 V)
static QImage readRXGB(QDataStream &s, quint32 width, quint32 height)
static QImage readR8G8B8G8(QDataStream &s, quint32 width, quint32 height)
static QImage readA2R10G10B10(QDataStream &s, const DDSHeader &dds, quint32 width, quint32 height)
static qint64 mipmapOffset(const DDSHeader &dds, const int format, const int level)
static const quint32 ddsMagic
static int formatByName(const QByteArray &name)
static QImage readUnsignedImage(QDataStream &s, const DDSHeader &dds, quint32 width, quint32 height, bool hasAlpha)
static Format getFormat(const DDSHeader &dds)
static QImage readX8L8V8U8(QDataStream &s, quint32 width, quint32 height)
static float readFloat32(QDataStream &s)
static QImage readV8U8(QDataStream &s, quint32 width, quint32 height)
void setAlphaDXT< Two >(QRgb *rgbArr, quint64 alphas)
static QImage readL6V5U5(QDataStream &s, quint32 width, quint32 height)
static int maskToShift(quint32 mask)
static int faceFlags[6]
static QImage readARGB16(QDataStream &s, quint32 width, quint32 height)
static QImage readARGB16F(QDataStream &s, const quint32 width, const quint32 height)
static const size_t knownFourCCsSize
static const FormatInfo formatInfos[]
static QImage readA2W10V10U10(QDataStream &s, quint32 width, quint32 height)
static const qint64 headerSize
static QImage readQ8W8V8U8(QDataStream &s, quint32 width, quint32 height)
void setAlphaDXT< Three >(QRgb *rgbArr, quint64 alphas)
static QImage readV16U16(QDataStream &s, quint32 width, quint32 height)
static void decodeColor(quint16 color, quint8 &red, quint8 &green, quint8 &blue)
static QImage readG8R8G8B8(QDataStream &s, quint32 width, quint32 height)
static QByteArray formatName(int format)
static void DXTFillColors(QRgb *result, quint16 c0, quint16 c1, quint32 table, bool dxt1a=false)
static QImage readDXT5(QDataStream &s, quint32 width, quint32 height)
static qint64 mipmapSize(const DDSHeader &dds, const int format, const int level)
static bool hasAlpha(const DDSHeader &dds)
static quint8 getNormalZ(quint8 nx, quint8 ny)
static QImage readCubeMap(QDataStream &s, const DDSHeader &dds, const int fmt)
static quint8 calcC2(quint8 c0, quint8 c1)
void setAlphaDXT(QRgb *rgbArr, quint64 alphas)
static QRgb invertRXGBColors(QRgb pixel)
static const size_t formatNamesSize
static const size_t formatInfosSize
static QImage readPalette8Image(QDataStream &s, quint32 width, quint32 height)
void setAlphaDXT32Helper(QRgb *rgbArr, quint64 alphas)
@ Caps2CubeMapPositiveY
Definition ddsheader.h:158
@ Caps2CubeMapPositiveX
Definition ddsheader.h:156
@ Caps2CubeMapNegativeX
Definition ddsheader.h:157
@ Caps2CubeMapPositiveZ
Definition ddsheader.h:160
@ Caps2CubeMapNegativeZ
Definition ddsheader.h:161
@ Caps2CubeMapNegativeY
Definition ddsheader.h:159
@ FlagPixelFormat
Definition ddsheader.h:142
@ ReservedCount
Definition ddsheader.h:165
quint32 bBitMask
quint32 bitCount
quint32 gBitMask
Format format
quint32 flags
quint32 aBitMask
quint32 rBitMask
const char *const name