8#include <QtCore/qdebug.h>
9#include <QtGui/qimage.h>
17#ifndef QT_NO_DATASTREAM
52static const FaceOffset faceOffsets[6] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {3, 1} };
101 { FormatL6V5U5, 0, 16, 0x0000001f, 0x000003e0, 0x0000fc00, 0x00000000 },
102 { FormatX8L8V8U8, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000 },
140 { FormatUnknown,
"unknown" },
142 { FormatR8G8B8,
"R8G8B8" },
143 { FormatA8R8G8B8,
"A8R8G8B8" },
144 { FormatX8R8G8B8,
"X8R8G8B8" },
145 { FormatR5G6B5,
"R5G6B5" },
146 { FormatX1R5G5B5,
"X1R5G5B5" },
147 { FormatA1R5G5B5,
"A1R5G5B5" },
148 { FormatA4R4G4B4,
"A4R4G4B4" },
149 { FormatR3G3B2,
"R3G3B2" },
151 { FormatA8R3G3B2,
"A8R3G3B2" },
152 { FormatX4R4G4B4,
"X4R4G4B4" },
153 { FormatA2B10G10R10,
"A2B10G10R10" },
154 { FormatA8B8G8R8,
"A8B8G8R8" },
155 { FormatX8B8G8R8,
"X8B8G8R8" },
156 { FormatG16R16,
"G16R16" },
157 { FormatA2R10G10B10,
"A2R10G10B10" },
158 { FormatA16B16G16R16,
"A16B16G16R16" },
160 { FormatA8P8,
"A8P8" },
164 { FormatA8L8,
"A8L8" },
165 { FormatA4L4,
"A4L4" },
167 { FormatV8U8,
"V8U8" },
168 { FormatL6V5U5,
"L6V5U5" },
169 { FormatX8L8V8U8,
"X8L8V8U8" },
170 { FormatQ8W8V8U8,
"Q8W8V8U8" },
171 { FormatV16U16,
"V16U16" },
172 { FormatA2W10V10U10,
"A2W10V10U10" },
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" },
186 { FormatD16Lockable,
"D16Lockable" },
187 { FormatD32,
"D32" },
188 { FormatD15S1,
"D15S1" },
189 { FormatD24S8,
"D24S8" },
190 { FormatD24X8,
"D24X8" },
191 { FormatD24X4S4,
"D24X4S4" },
192 { FormatD16,
"D16" },
194 { FormatD32FLockable,
"D32FLockable" },
195 { FormatD24FS8,
"D24FS8" },
197 { FormatD32Lockable,
"D32Lockable" },
198 { FormatS8Lockable,
"S8Lockable" },
200 { FormatL16,
"L16" },
202 { FormatVertexData,
"VertexData" },
203 { FormatIndex32,
"Index32" },
204 { FormatIndex32,
"Index32" },
206 { FormatQ16W16V16U16,
"Q16W16V16U16" },
208 { FormatMulti2ARGB8,
"Multi2ARGB8" },
210 { FormatR16F,
"R16F" },
211 { FormatG16R16F,
"G16R16F" },
212 { FormatA16B16G16R16F,
"A16B16G16R16F" },
214 { FormatR32F,
"R32F" },
215 { FormatG32R32F,
"G32R32F" },
216 { FormatA32B32G32R32F,
"A32B32G32R32F" },
218 { FormatCxV8U8,
"CxV8U8" },
221 { FormatA2B10G10R10_XR_BIAS,
"A2B10G10R10_XR_BIAS" },
222 { FormatBinaryBuffer,
"BinaryBuffer" },
225 { FormatA4P4,
"A4P4" }
235 while (!((mask >> result) & 1))
253 Q_ASSERT(size == 8 || size == 16 || size == 24 || size == 32);
257 for (
unsigned bit = 0; bit < size; bit += 8) {
259 value += (quint32(tmp) << bit);
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)));
289 for (size_t i = 0; i < knownFourCCsSize; ++i) {
294 for (size_t i = 0; i < formatInfosSize; ++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) {
307 return FormatUnknown;
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;
318static inline void decodeColor(quint16 color, quint8 &red, quint8 &green, quint8 &blue)
320 red = ((color >> 11) & 0x1f) << 3;
321 green = ((color >> 5) & 0x3f) << 2;
322 blue = (color & 0x1f) << 3;
327 return 2.0 * c0 / 3.0 + c1 / 3.0;
332 return c0 / 2.0 + c1 / 2.0;
337 return c0 / 3.0 + 2.0 * c1 / 3.0;
340static void DXTFillColors(QRgb *result, quint16 c0, quint16 c1, quint32 table,
bool dxt1a =
false)
347 a[0] = a[1] = a[2] = a[3] = 255;
349 decodeColor(c0, r[0], g[0], b[0]);
350 decodeColor(c1, r[1], g[1], b[1]);
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]);
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;
365 for (
int k = 0; k < 4; k++)
366 for (
int l = 0; l < 4; l++) {
367 unsigned index = table & 0x0003;
370 result[k * 4 + l] = qRgba(r[index], g[index], b[index], a[index]);
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];
382 rgbArr[i] = qRgba(qRed(rgb) * alpha / 0xff, qGreen(rgb) * alpha / 0xff, qBlue(rgb) * alpha / 0xff, alpha);
383 else if (version ==
Three)
384 rgbArr[i] = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), alpha);
385 alphas = alphas >> 4;
392 Q_STATIC_ASSERT(version ==
Four || version ==
Five);
394 a[0] = alphas & 0xff;
395 a[1] = (alphas >> 8) & 0xff;
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;
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;
412 for (
int i = 0; i < 16; i++) {
413 quint8 index = alphas & 0x07;
414 quint8 alpha = a[index];
415 QRgb rgb = rgbArr[i];
417 rgbArr[i] = qRgba(qRed(rgb) * alpha / 0xff, qGreen(rgb) * alpha / 0xff, qBlue(rgb) * alpha / 0xff, alpha);
418 else if (version ==
Five)
419 rgbArr[i] = qRgba(qRed(rgb), qGreen(rgb), qBlue(rgb), alpha);
420 alphas = alphas >> 3;
434 setAlphaDXT32Helper<
Two>(rgbArr, alphas);
440 setAlphaDXT32Helper<Three>(rgbArr, alphas);
446 setAlphaDXT45Helper<Four>(rgbArr, alphas);
452 setAlphaDXT45Helper<Five>(rgbArr, alphas);
458 setAlphaDXT45Helper<Five>(rgbArr, alphas);
463 return qRgb(qAlpha(pixel), qGreen(pixel), qBlue(pixel));
469 QImage::Format format = (version == Two || version == Four) ?
470 QImage::Format_ARGB32_Premultiplied : QImage::Format_ARGB32;
472 QImage image(width, height, format);
474 for (quint32 i = 0; i < height; i += 4) {
475 for (quint32 j = 0; j < width; j += 4) {
487 DXTFillColors(arr, c0, c1, table, version == One && c0 <= c1);
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];
497 pixel = invertRXGBColors(pixel);
509 return readDXT<
One>(s, width, height);
514 return readDXT<
Two>(s, width, height);
519 return readDXT<
Three>(s, width, height);
524 return readDXT<
Four>(s, width, height);
529 return readDXT<
Five>(s, width, height);
534 return readDXT<
RXGB>(s, width, height);
539 QImage image(width, height, QImage::Format_RGB32);
541 for (quint32 i = 0; i < height; i += 4) {
542 for (quint32 j = 0; j < width; j += 4) {
549 memset(arr, 0,
sizeof(QRgb) * 16);
551 for (
int k = 0; k < 16; ++k) {
552 quint8 a = qAlpha(arr[k]);
553 arr[k] = qRgba(0, 0, a, 0);
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);
576 quint32 flags = dds.pixelFormat.flags;
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]);
591 masks[i] = (masks[i] >> shifts[i]) << (8 - bits[i]);
594 const QImage::Format format = hasAlpha ? QImage::Format_ARGB32 : QImage::Format_RGB32;
596 QImage image(width, height, format);
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));
602 quint32 value = readValue(s, dds.pixelFormat.rgbBitCount);
603 quint8 colors[ColorCount];
605 for (
int c = 0; c < ColorCount; ++c) {
608 colors[c] = (value & masks[c]) >> shifts[c] >> (bits[c] - 8);
611 quint8 color = value >> shifts[c] << (8 - bits[c]) & masks[c];
613 colors[c] = color * 0xff / masks[c];
620 line[x] = qRgba(colors[Red], colors[Red], colors[Red], colors[Alpha]);
622 line[x] = yuv2rgb(colors[Red], colors[Green], colors[Blue]);
624 line[x] = qRgba(colors[Red], colors[Green], colors[Blue], colors[Alpha]);
636 double sign = (value & 0x8000) == 0x8000 ? -1.0 : 1.0;
637 qint8 exp = (value & 0x7C00) >> 10;
638 quint16 fraction = value & 0x3FF;
641 return sign *
std::pow(2.0, -14.0) * fraction / 1024.0;
643 return sign *
std::pow(2.0, exp - 15) * (1 + fraction / 1024.0);
648 Q_ASSERT(
sizeof(
float) == 4);
651 QDataStream::FloatingPointPrecision precision = s.floatingPointPrecision();
652 s.setFloatingPointPrecision(QDataStream::SinglePrecision);
654 s.setFloatingPointPrecision(precision);
660 QImage image(width, height, QImage::Format_RGB32);
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);
675 QImage image(width, height, QImage::Format_RGB32);
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);
691 QImage image(width, height, QImage::Format_ARGB32);
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;
700 line[x] = qRgba(colors[Red], colors[Green], colors[Blue], colors[Alpha]);
709 QImage image(width, height, QImage::Format_RGB32);
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);
724 QImage image(width, height, QImage::Format_RGB32);
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);
740 QImage image(width, height, QImage::Format_ARGB32);
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]);
757 QImage image(width, height, QImage::Format_ARGB32);
759 quint8 colors[ColorCount];
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++) {
766 colors[i] = (tmp + 0x7FFF) >> 8;
768 line[x] = qRgba(colors[Red], colors[Green], colors[Blue], colors[Alpha]);
777 QImage image(width, height, QImage::Format_RGB32);
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++) {
785 const quint8 vn = v + 128;
786 const quint8 un = u + 128;
787 const quint8 c = getNormalZ(vn, un);
789 line[x] = qRgb(vn, un, c);
798 QImage image(width, height, QImage::Format_Indexed8);
799 for (
int i = 0; i < 256; ++i) {
801 s >> r >> g >> b >> a;
802 image.setColor(i, qRgba(r, g, b, a));
805 for (quint32 y = 0; y < height; y++) {
806 for (quint32 x = 0; x < width; x++) {
809 image.setPixel(x, y, index);
818 QImage image(width, height, QImage::Format_Indexed8);
819 for (
int i = 0; i < 16; ++i) {
821 s >> r >> g >> b >> a;
822 image.setColor(i, qRgba(r, g, b, a));
825 for (quint32 y = 0; y < height; y++) {
827 for (quint32 x = 0; x < width - 1; ) {
829 image.setPixel(x++, y, (index & 0x0f) >> 0);
830 image.setPixel(x++, y, (index & 0xf0) >> 4);
832 if (width % 2 == 1) {
834 image.setPixel(width - 1, y, (index & 0x0f) >> 0);
843 QImage image(width, height, QImage::Format_ARGB32);
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) {
852 colors[i] = quint8(color >> 8);
854 line[x] = qRgba(colors[Red], colors[Green], colors[Blue], colors[Alpha]);
863 QImage image(width, height, QImage::Format_RGB32);
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++) {
870 line[x] = qRgb(v + 128, u + 128, 255);
879 QImage image(width, height, QImage::Format_ARGB32);
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++) {
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);
897 QImage image(width, height, QImage::Format_ARGB32);
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);
914 QImage image(width, height, QImage::Format_ARGB32);
916 quint8 colors[ColorCount];
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++) {
923 colors[i] = tmp + 128;
925 line[x] = qRgba(colors[Red], colors[Green], colors[Blue], colors[Alpha]);
934 QImage image(width, height, QImage::Format_RGB32);
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++) {
941 v = (v + 0x8000) >> 8;
942 u = (u + 0x8000) >> 8;
943 line[x] = qRgb(v, u, 255);
952 QImage image(width, height, QImage::Format_ARGB32);
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++) {
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;
965 line[x] = qRgba(r, g, b, a);
974 QImage image(width, height, QImage::Format_RGB32);
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]);
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]);
995 QImage image(width, height, QImage::Format_RGB32);
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]);
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]);
1015 QImage image(width, height, QImage::Format_RGB32);
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]);
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]);
1036 QImage image(width, height, QImage::Format_RGB32);
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]);
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]);
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));
1069 if (width * height == 0)
1074 case FormatX8R8G8B8:
1077 case FormatX1R5G5B5:
1078 case FormatX4R4G4B4:
1079 case FormatX8B8G8R8:
1083 return readUnsignedImage(s, dds, width, height,
false);
1084 case FormatA8R8G8B8:
1085 case FormatA1R5G5B5:
1086 case FormatA4R4G4B4:
1088 case FormatA8R3G3B2:
1089 case FormatA8B8G8R8:
1092 return readUnsignedImage(s, dds, width, height,
true);
1093 case FormatA2R10G10B10:
1094 case FormatA2B10G10R10:
1095 return readA2R10G10B10(s, dds, width, height);
1098 return readPalette8Image(s, width, height);
1101 return readPalette4Image(s, width, height);
1102 case FormatA16B16G16R16:
1103 return readARGB16(s, width, height);
1105 return readV8U8(s, width, height);
1107 return readL6V5U5(s, width, height);
1108 case FormatX8L8V8U8:
1109 return readX8L8V8U8(s, width, height);
1110 case FormatQ8W8V8U8:
1111 return readQ8W8V8U8(s, width, height);
1113 return readV16U16(s, width, height);
1114 case FormatA2W10V10U10:
1115 return readA2W10V10U10(s, width, height);
1117 return readUYVY(s, width, height);
1118 case FormatR8G8B8G8:
1119 return readR8G8B8G8(s, width, height);
1121 return readYUY2(s, width, height);
1122 case FormatG8R8G8B8:
1123 return readG8R8G8B8(s, width, height);
1125 return readDXT1(s, width, height);
1127 return readDXT2(s, width, height);
1129 return readDXT3(s, width, height);
1131 return readDXT4(s, width, height);
1133 return readDXT5(s, width, height);
1135 return readRXGB(s, width, height);
1137 return readATI2(s, width, height);
1139 return readR16F(s, width, height);
1141 return readRG16F(s, width, height);
1142 case FormatA16B16G16R16F:
1143 return readARGB16F(s, width, height);
1145 return readR32F(s, width, height);
1147 return readRG32F(s, width, height);
1148 case FormatA32B32G32R32F:
1149 return readARGB32F(s, width, height);
1150 case FormatD16Lockable:
1157 case FormatD32FLockable:
1159 case FormatD32Lockable:
1160 case FormatS8Lockable:
1161 case FormatVertexData:
1165 case FormatQ16W16V16U16:
1166 return readQ16W16V16U16(s, width, height);
1167 case FormatMulti2ARGB8:
1170 return readCxV8U8(s, width, height);
1172 case FormatA2B10G10R10_XR_BIAS:
1173 case FormatBinaryBuffer:
1183 quint32 width = dds.width / (1 << mipmapLevel);
1184 quint32 height = dds.height / (1 << mipmapLevel);
1185 return readLayer(s, dds, format, width, height);
1190 quint32 w = dds.width/(1 << level);
1191 quint32 h = dds.height/(1 << level);
1195 case FormatX8R8G8B8:
1197 case FormatX1R5G5B5:
1198 case FormatX4R4G4B4:
1199 case FormatX8B8G8R8:
1203 return w * h * dds.pixelFormat.rgbBitCount / 8;
1204 case FormatA8R8G8B8:
1205 case FormatA1R5G5B5:
1206 case FormatA4R4G4B4:
1208 case FormatA8R3G3B2:
1209 case FormatA2B10G10R10:
1210 case FormatA8B8G8R8:
1211 case FormatA2R10G10B10:
1214 return w * h * dds.pixelFormat.rgbBitCount / 8;
1216 return 256 + w * h * 8;
1217 case FormatA16B16G16R16:
1218 return w * h * 4 * 2;
1224 case FormatX8L8V8U8:
1225 case FormatQ8W8V8U8:
1227 case FormatA2W10V10U10:
1230 case FormatR8G8B8G8:
1232 case FormatG8R8G8B8:
1235 return ((w + 3)/4) * ((h + 3)/4) * 8;
1240 return ((w + 3)/4) * ((h + 3)/4) * 16;
1241 case FormatD16Lockable:
1248 case FormatD32FLockable:
1250 case FormatD32Lockable:
1251 case FormatS8Lockable:
1252 case FormatVertexData:
1256 case FormatQ16W16V16U16:
1257 return w * h * 4 * 2;
1258 case FormatMulti2ARGB8:
1261 return w * h * 1 * 2;
1263 return w * h * 2 * 2;
1264 case FormatA16B16G16R16F:
1265 return w * h * 4 * 2;
1267 return w * h * 1 * 4;
1269 return w * h * 2 * 4;
1270 case FormatA32B32G32R32F:
1271 return w * h * 4 * 4;
1275 case FormatA2B10G10R10_XR_BIAS:
1276 case FormatBinaryBuffer:
1287 for (
int i = 0; i < level; ++i)
1288 result += mipmapSize(dds, format, i);
1294 QImage::Format format = hasAlpha(dds) ? QImage::Format_ARGB32 : QImage::Format_RGB32;
1295 QImage image(4 * dds.width, 3 * dds.height, format);
1299 for (
int i = 0; i < 6; i++) {
1303 const QImage face = readLayer(s, dds, fmt, dds.width, dds.height);
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);
1322 for (size_t i = 0; i < formatNamesSize; ++i) {
1332 const QByteArray loweredName = name.toLower();
1333 for (size_t i = 0; i < formatNamesSize; ++i) {
1334 if (QByteArray(
formatNames[i].name).toLower() == loweredName)
1338 return FormatUnknown;
1343 m_format(FormatA8R8G8B8),
1346 m_scanState(ScanNotScanned)
1352 if (m_scanState == ScanNotScanned && !
canRead(device()
))
1355 if (m_scanState != ScanError) {
1356 setFormat(QByteArrayLiteral(
"dds"));
1365 if (!ensureScanned() || device()->isSequential())
1368 qint64 pos = headerSize + mipmapOffset(m_header, m_format, m_currentImage);
1369 if (!device()->seek(pos))
1371 QDataStream s(device());
1372 s.setByteOrder(QDataStream::LittleEndian);
1374 QImage image = isCubeMap(m_header) ?
1375 readCubeMap(s, m_header, m_format) :
1376 readTexture(s, m_header, m_format, m_currentImage);
1378 bool ok = s.status() == QDataStream::Ok && !image.isNull();
1386 if (m_format != FormatA8R8G8B8) {
1387 qWarning() <<
"Format" << formatName(m_format) <<
"is not supported";
1391 const QImage image = outImage.convertToFormat(QImage::Format_ARGB32);
1393 QDataStream s(device());
1394 s.setByteOrder(QDataStream::LittleEndian);
1398 dds.magic = ddsMagic;
1402 dds.height = image.height();
1403 dds.width = image.width();
1404 dds.pitchOrLinearSize = 128;
1406 dds.mipMapCount = 0;
1408 dds.reserved1[i] = 0;
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;
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);
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;
1444 if (!supportsOption(option) || !ensureScanned())
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));
1461void QDDSHandler::setOption(QImageIOHandler::ImageOption option,
const QVariant &value)
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;
1471bool QDDSHandler::supportsOption(QImageIOHandler::ImageOption option)
const
1473 return (option == QImageIOHandler::Size)
1474 || (option == QImageIOHandler::SubType)
1475 || (option == QImageIOHandler::SupportedSubTypes);
1480 if (!ensureScanned())
1483 return qMax<quint32>(1, m_header.mipMapCount);
1491 m_currentImage = imageNumber;
1498 qWarning() <<
"DDSHandler::canRead() called with no device";
1502 if (device->isSequential())
1505 return device->peek(4) == QByteArrayLiteral(
"DDS ");
1510 if (m_scanState != ScanNotScanned)
1511 return m_scanState == ScanSuccess;
1513 m_scanState = ScanError;
1516 that->m_format = FormatUnknown;
1518 if (device()->isSequential()) {
1519 qWarning() <<
"Sequential devices are not supported";
1523 qint64 oldPos = device()->pos();
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;
1532 device()->seek(oldPos);
1534 if (s.status() != QDataStream::Ok)
1537 if (!verifyHeader(m_header))
1540 that->m_format = getFormat(m_header);
1541 if (that->m_format == FormatUnknown)
1544 m_scanState = ScanSuccess;
1550 quint32 flags = dds.flags;
1553 if ((flags & requiredFlags) != requiredFlags) {
1554 qWarning() <<
"Wrong dds.flags - not all required flags present. "
1555 "Actual flags :" << flags;
1559 if (dds.size != ddsSize) {
1560 qWarning() <<
"Wrong dds.size: actual =" << dds.size
1561 <<
"expected =" << ddsSize;
1565 if (dds.pixelFormat.size != pixelFormatSize) {
1566 qWarning() <<
"Wrong dds.pixelFormat.size: actual =" << dds.pixelFormat.size
1567 <<
"expected =" << pixelFormatSize;
1571 if (dds.width > INT_MAX || dds.height > INT_MAX) {
1572 qWarning() <<
"Can't read image with w/h bigger than INT_MAX";
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
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 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)