24 #include <QtCore/QStringList>
25 #include <QtGui/QImage>
26 #include <QtCore/QDataStream>
33 #define sqrtf(x) ((float)sqrt(x))
40 #if !defined(MAKEFOURCC)
41 # define MAKEFOURCC(ch0, ch1, ch2, ch3) \
42 (uint(uchar(ch0)) | (uint(uchar(ch1)) << 8) | \
43 (uint(uchar(ch2)) << 16) | (uint(uchar(ch3)) << 24 ))
48 #define CUBE_LAYOUT HORIZONTAL
133 struct DDSPixelFormat {
144 static QDataStream &
operator>> ( QDataStream & s, DDSPixelFormat & pf )
164 static QDataStream &
operator>> ( QDataStream & s, DDSCaps & caps )
187 static QDataStream &
operator>> ( QDataStream & s, DDSHeader & header )
195 s >> header.mipmapcount;
196 for(
int i = 0; i < 11; i++ ) {
197 s >> header.reserved[i];
205 static bool IsValid(
const DDSHeader & header )
207 if( header.size != 124 ) {
211 if( (header.flags & required) != required ) {
214 if( header.pf.size != 32 ) {
229 switch( header.pf.bitcount ) {
237 switch( header.pf.bitcount ) {
246 switch( header.pf.fourcc ) {
287 static bool LoadA8R8G8B8( QDataStream & s,
const DDSHeader & header, QImage & img )
289 const uint w = header.width;
290 const uint h = header.height;
292 for(
uint y = 0; y < h; y++ ) {
293 QRgb * scanline = (QRgb *) img.scanLine( y );
294 for(
uint x = 0; x < w; x++ ) {
296 s >> b >> g >> r >> a;
297 scanline[x] =
qRgba(r, g, b, a);
304 static bool LoadR8G8B8( QDataStream & s,
const DDSHeader & header, QImage & img )
306 const uint w = header.width;
307 const uint h = header.height;
309 for(
uint y = 0; y < h; y++ ) {
310 QRgb * scanline = (QRgb *) img.scanLine( y );
311 for(
uint x = 0; x < w; x++ ) {
314 scanline[x] = qRgb(r, g, b);
321 static bool LoadA1R5G5B5( QDataStream & s,
const DDSHeader & header, QImage & img )
323 const uint w = header.width;
324 const uint h = header.height;
326 for(
uint y = 0; y < h; y++ ) {
327 QRgb * scanline = (QRgb *) img.scanLine( y );
328 for(
uint x = 0; x < w; x++ ) {
331 uchar a = (color.c.a != 0) ? 0xFF : 0;
332 uchar r = (color.c.r << 3) | (color.c.r >> 2);
333 uchar g = (color.c.g << 3) | (color.c.g >> 2);
334 uchar b = (color.c.b << 3) | (color.c.b >> 2);
335 scanline[x] =
qRgba(r, g, b, a);
342 static bool LoadA4R4G4B4( QDataStream & s,
const DDSHeader & header, QImage & img )
344 const uint w = header.width;
345 const uint h = header.height;
347 for(
uint y = 0; y < h; y++ ) {
348 QRgb * scanline = (QRgb *) img.scanLine( y );
349 for(
uint x = 0; x < w; x++ ) {
352 uchar a = (color.c.a << 4) | color.c.a;
353 uchar r = (color.c.r << 4) | color.c.r;
354 uchar g = (color.c.g << 4) | color.c.g;
355 uchar b = (color.c.b << 4) | color.c.b;
356 scanline[x] =
qRgba(r, g, b, a);
363 static bool LoadR5G6B5( QDataStream & s,
const DDSHeader & header, QImage & img )
365 const uint w = header.width;
366 const uint h = header.height;
368 for(
uint y = 0; y < h; y++ ) {
369 QRgb * scanline = (QRgb *) img.scanLine( y );
370 for(
uint x = 0; x < w; x++ ) {
373 uchar r = (color.c.r << 3) | (color.c.r >> 2);
374 uchar g = (color.c.g << 2) | (color.c.g >> 4);
375 uchar b = (color.c.b << 3) | (color.c.b >> 2);
376 scanline[x] = qRgb(r, g, b);
383 static QDataStream &
operator>> ( QDataStream & s, Color565 & c )
395 void GetColors( Color8888 color_array[4] )
397 color_array[0].r = (col0.c.r << 3) | (col0.c.r >> 2);
398 color_array[0].g = (col0.c.g << 2) | (col0.c.g >> 4);
399 color_array[0].b = (col0.c.b << 3) | (col0.c.b >> 2);
400 color_array[0].a = 0xFF;
402 color_array[1].r = (col1.c.r << 3) | (col1.c.r >> 2);
403 color_array[1].g = (col1.c.g << 2) | (col1.c.g >> 4);
404 color_array[1].b = (col1.c.b << 3) | (col1.c.b >> 2);
405 color_array[1].a = 0xFF;
407 if( col0.u > col1.u ) {
409 color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3;
410 color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3;
411 color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3;
412 color_array[2].a = 0xFF;
414 color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3;
415 color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3;
416 color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3;
417 color_array[3].a = 0xFF;
421 color_array[2].r = (color_array[0].r + color_array[1].r) / 2;
422 color_array[2].g = (color_array[0].g + color_array[1].g) / 2;
423 color_array[2].b = (color_array[0].b + color_array[1].b) / 2;
424 color_array[2].a = 0xFF;
427 color_array[3].r = 0x00;
428 color_array[3].g = 0x00;
429 color_array[3].b = 0x00;
430 color_array[3].a = 0x00;
436 static QDataStream &
operator>> ( QDataStream & s, BlockDXT & c )
438 return s >> c.col0 >> c.col1 >> c.row[0] >> c.row[1] >> c.row[2] >> c.row[3];
441 struct BlockDXTAlphaExplicit {
445 static QDataStream &
operator>> ( QDataStream & s, BlockDXTAlphaExplicit & c )
447 return s >> c.row[0] >> c.row[1] >> c.row[2] >> c.row[3];
450 struct BlockDXTAlphaLinear {
455 void GetAlphas(
uchar alpha_array[8] )
457 alpha_array[0] = alpha0;
458 alpha_array[1] = alpha1;
461 if( alpha_array[0] > alpha_array[1] )
466 alpha_array[2] = ( 6 * alpha0 + alpha1) / 7;
467 alpha_array[3] = ( 5 * alpha0 + 2 * alpha1) / 7;
468 alpha_array[4] = ( 4 * alpha0 + 3 * alpha1) / 7;
469 alpha_array[5] = ( 3 * alpha0 + 4 * alpha1) / 7;
470 alpha_array[6] = ( 2 * alpha0 + 5 * alpha1) / 7;
471 alpha_array[7] = ( alpha0 + 6 * alpha1) / 7;
478 alpha_array[2] = (4 * alpha0 + alpha1) / 5;
479 alpha_array[3] = (3 * alpha0 + 2 * alpha1) / 5;
480 alpha_array[4] = (2 * alpha0 + 3 * alpha1) / 5;
481 alpha_array[5] = ( alpha0 + 4 * alpha1) / 5;
482 alpha_array[6] = 0x00;
483 alpha_array[7] = 0xFF;
487 void GetBits(
uchar bit_array[16] )
490 uint b = bits[0] | bits[1] << 8 | bits[2] << 16;
491 bit_array[0] =
uchar(b & 0x07); b >>= 3;
492 bit_array[1] =
uchar(b & 0x07); b >>= 3;
493 bit_array[2] =
uchar(b & 0x07); b >>= 3;
494 bit_array[3] =
uchar(b & 0x07); b >>= 3;
495 bit_array[4] =
uchar(b & 0x07); b >>= 3;
496 bit_array[5] =
uchar(b & 0x07); b >>= 3;
497 bit_array[6] =
uchar(b & 0x07); b >>= 3;
498 bit_array[7] =
uchar(b & 0x07);
500 b = bits[3] | bits[4] << 8 | bits[5] << 16;
501 bit_array[8] =
uchar(b & 0x07); b >>= 3;
502 bit_array[9] =
uchar(b & 0x07); b >>= 3;
503 bit_array[10] =
uchar(b & 0x07); b >>= 3;
504 bit_array[11] =
uchar(b & 0x07); b >>= 3;
505 bit_array[12] =
uchar(b & 0x07); b >>= 3;
506 bit_array[13] =
uchar(b & 0x07); b >>= 3;
507 bit_array[14] =
uchar(b & 0x07); b >>= 3;
508 bit_array[15] =
uchar(b & 0x07);
512 static QDataStream &
operator>> ( QDataStream & s, BlockDXTAlphaLinear & c )
514 s >> c.alpha0 >> c.alpha1;
515 return s >> c.bits[0] >> c.bits[1] >> c.bits[2] >> c.bits[3] >> c.bits[4] >> c.bits[5];
518 static bool LoadDXT1( QDataStream & s,
const DDSHeader & header, QImage & img )
520 const uint w = header.width;
521 const uint h = header.height;
526 for(
uint y = 0; y < h; y += 4 ) {
527 for(
uint j = 0; j < 4; j++ ) {
528 scanline[j] = (QRgb *) img.scanLine( y + j );
530 for(
uint x = 0; x < w; x += 4 ) {
536 Color8888 color_array[4];
537 block.GetColors(color_array);
540 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
541 const int shift[4] = { 0, 2, 4, 6 };
544 for(
uint j = 0; j < 4; j++ ) {
545 for(
uint i = 0; i < 4; i++ ) {
546 if( img.valid( x+i, y+j ) ) {
547 uint idx = (block.row[j] & masks[i]) >> shift[i];
548 scanline[j][x+i] =
qRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a);
557 static bool LoadDXT3( QDataStream & s,
const DDSHeader & header, QImage & img )
559 const uint w = header.width;
560 const uint h = header.height;
563 BlockDXTAlphaExplicit alpha;
566 for(
uint y = 0; y < h; y += 4 ) {
567 for(
uint j = 0; j < 4; j++ ) {
568 scanline[j] = (QRgb *) img.scanLine( y + j );
570 for(
uint x = 0; x < w; x += 4 ) {
577 Color8888 color_array[4];
578 block.GetColors(color_array);
581 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
582 const int shift[4] = { 0, 2, 4, 6 };
585 for(
uint j = 0; j < 4; j++ ) {
587 for(
uint i = 0; i < 4; i++ ) {
588 if( img.valid( x+i, y+j ) ) {
589 uint idx = (block.row[j] & masks[i]) >> shift[i];
590 color_array[idx].a = a & 0x0f;
591 color_array[idx].a = color_array[idx].a | (color_array[idx].a << 4);
592 scanline[j][x+i] =
qRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a);
602 static bool LoadDXT2( QDataStream & s,
const DDSHeader & header, QImage & img )
604 if( !
LoadDXT3(s, header, img) )
return false;
609 static bool LoadDXT5( QDataStream & s,
const DDSHeader & header, QImage & img )
611 const uint w = header.width;
612 const uint h = header.height;
615 BlockDXTAlphaLinear alpha;
618 for(
uint y = 0; y < h; y += 4 ) {
619 for(
uint j = 0; j < 4; j++ ) {
620 scanline[j] = (QRgb *) img.scanLine( y + j );
622 for(
uint x = 0; x < w; x += 4 ) {
629 Color8888 color_array[4];
630 block.GetColors(color_array);
632 uchar alpha_array[8];
633 alpha.GetAlphas(alpha_array);
636 alpha.GetBits(bit_array);
639 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
640 const int shift[4] = { 0, 2, 4, 6 };
643 for(
uint j = 0; j < 4; j++ ) {
644 for(
uint i = 0; i < 4; i++ ) {
645 if( img.valid( x+i, y+j ) ) {
646 uint idx = (block.row[j] & masks[i]) >> shift[i];
647 color_array[idx].a = alpha_array[bit_array[j*4+i]];
648 scanline[j][x+i] =
qRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a);
657 static bool LoadDXT4( QDataStream & s,
const DDSHeader & header, QImage & img )
659 if( !
LoadDXT5(s, header, img) )
return false;
664 static bool LoadRXGB( QDataStream & s,
const DDSHeader & header, QImage & img )
666 const uint w = header.width;
667 const uint h = header.height;
670 BlockDXTAlphaLinear alpha;
673 for(
uint y = 0; y < h; y += 4 ) {
674 for(
uint j = 0; j < 4; j++ ) {
675 scanline[j] = (QRgb *) img.scanLine( y + j );
677 for(
uint x = 0; x < w; x += 4 ) {
684 Color8888 color_array[4];
685 block.GetColors(color_array);
687 uchar alpha_array[8];
688 alpha.GetAlphas(alpha_array);
691 alpha.GetBits(bit_array);
694 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
695 const int shift[4] = { 0, 2, 4, 6 };
698 for(
uint j = 0; j < 4; j++ ) {
699 for(
uint i = 0; i < 4; i++ ) {
700 if( img.valid( x+i, y+j ) ) {
701 uint idx = (block.row[j] & masks[i]) >> shift[i];
702 color_array[idx].a = alpha_array[bit_array[j*4+i]];
703 scanline[j][x+i] = qRgb(color_array[idx].a, color_array[idx].g, color_array[idx].b);
713 static bool LoadATI2( QDataStream & s,
const DDSHeader & header, QImage & img )
715 const uint w = header.width;
716 const uint h = header.height;
718 BlockDXTAlphaLinear xblock;
719 BlockDXTAlphaLinear yblock;
722 for(
uint y = 0; y < h; y += 4 ) {
723 for(
uint j = 0; j < 4; j++ ) {
724 scanline[j] = (QRgb *) img.scanLine( y + j );
726 for(
uint x = 0; x < w; x += 4 ) {
733 uchar xblock_array[8];
734 xblock.GetAlphas(xblock_array);
736 uchar xbit_array[16];
737 xblock.GetBits(xbit_array);
739 uchar yblock_array[8];
740 yblock.GetAlphas(yblock_array);
742 uchar ybit_array[16];
743 yblock.GetBits(ybit_array);
746 for(
uint j = 0; j < 4; j++ ) {
747 for(
uint i = 0; i < 4; i++ ) {
748 if( img.valid( x+i, y+j ) ) {
749 const uchar nx = xblock_array[xbit_array[j*4+i]];
750 const uchar ny = yblock_array[ybit_array[j*4+i]];
752 const float fx = float(nx) / 127.5f - 1.0f;
753 const float fy = float(ny) / 127.5f - 1.0f;
754 const float fz =
sqrtf(1.0f - fx*fx - fy*fy);
757 scanline[j][x+i] = qRgb(nx, ny, nz);
769 typedef bool (*
TextureLoader)( QDataStream & s,
const DDSHeader & header, QImage & img );
805 static bool LoadTexture( QDataStream & s,
const DDSHeader & header, QImage & img )
808 img = QImage( header.width, header.height, QImage::Format_RGB32 );
815 img = img.convertToFormat( QImage::Format_ARGB32 );
819 if( loader == NULL ) {
823 return loader( s, header, img );
831 int mipmap = qMax(header.mipmapcount, 1U);
833 int w = header.width;
834 int h = header.height;
837 int multiplier = (type ==
DDS_DXT1) ? 8 : 16;
839 int face_size = qMax(w/4,1) * qMax(h/4,1) * multiplier;
846 int multiplier = header.pf.bitcount / 8;
848 int face_size = w * h * multiplier;
858 #if CUBE_LAYOUT == HORIZONTAL
859 static int face_offset[6][2] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {3, 1} };
860 #elif CUBE_LAYOUT == VERTICAL
861 static int face_offset[6][2] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {1, 3} };
873 static bool LoadCubeMap( QDataStream & s,
const DDSHeader & header, QImage & img )
876 #if CUBE_LAYOUT == HORIZONTAL
877 img = QImage( 4 * header.width, 3 * header.height, QImage::Format_RGB32 );
878 #elif CUBE_LAYOUT == VERTICAL
879 img = QImage( 3 * header.width, 4 * header.height, QImage::Format_RGB32 );
886 img = img.convertToFormat( QImage::Format_ARGB32 );
891 if( loader == NULL ) {
899 QImage face(header.width, header.height, QImage::Format_RGB32);
901 int offset = s.device()->pos();
904 for(
int i = 0; i < 6; i++ ) {
906 if( !(header.caps.caps2 & face_flags[i]) ) {
912 s.device()->seek( offset );
916 if( !loader( s, header, face ) ) {
920 #if CUBE_LAYOUT == VERTICAL
922 face = face.mirror(
true,
true);
927 int offset_x = face_offset[i][0] * header.width;
928 int offset_y = face_offset[i][1] * header.height;
931 for(
uint y = 0; y < header.height; y++ ) {
932 QRgb * src = (QRgb *) face.scanLine( y );
933 QRgb * dst = (QRgb *) img.scanLine( y + offset_y ) + offset_x;
934 memcpy( dst, src,
sizeof(QRgb) * header.width );
958 QDataStream s( device() );
959 s.setByteOrder( QDataStream::LittleEndian );
965 kDebug(399) <<
"This is not a DDS file.";
974 if( s.atEnd() || !
IsValid( header ) ) {
975 kDebug(399) <<
"This DDS file is not valid.";
981 kDebug(399) <<
"This DDS file is not supported.";
1011 qWarning(
"DDSHandler::canRead() called with no device");
1015 qint64 oldPos = device->pos();
1018 qint64 readBytes = device->read(head,
sizeof(head));
1019 if (readBytes !=
sizeof(head)) {
1020 if (device->isSequential()) {
1021 while (readBytes > 0)
1022 device->ungetChar(head[readBytes-- - 1]);
1024 device->seek(oldPos);
1029 if (device->isSequential()) {
1030 while (readBytes > 0)
1031 device->ungetChar(head[readBytes-- - 1]);
1033 device->seek(oldPos);
1036 return qstrncmp(head,
"DDS", 3) == 0;
1039 class DDSPlugin :
public QImageIOPlugin
1042 QStringList keys()
const;
1043 Capabilities capabilities(QIODevice *device,
const QByteArray &format)
const;
1044 QImageIOHandler *create(QIODevice *device,
const QByteArray &format = QByteArray())
const;
1047 QStringList DDSPlugin::keys()
const
1049 return QStringList() <<
"dds";
1052 QImageIOPlugin::Capabilities DDSPlugin::capabilities(QIODevice *device,
const QByteArray &format)
const
1054 if (format ==
"dds")
1055 return Capabilities(CanRead);
1056 if (!format.isEmpty())
1058 if (!device->isOpen())
1067 QImageIOHandler *DDSPlugin::create(QIODevice *device,
const QByteArray &format)
const
1070 handler->setDevice(device);
1071 handler->setFormat(format);
1075 Q_EXPORT_STATIC_PLUGIN(DDSPlugin)
1076 Q_EXPORT_PLUGIN2(dds, DDSPlugin)
static DDSType GetType(const DDSHeader &header)
static const uint FOURCC_DXT2
static bool LoadRXGB(QDataStream &s, const DDSHeader &header, QImage &img)
static const uint FOURCC_DXT1
static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ
bool(* TextureLoader)(QDataStream &s, const DDSHeader &header, QImage &img)
static const uint DDSCAPS2_VOLUME
static int FaceOffset(const DDSHeader &header)
#define MAKEFOURCC(ch0, ch1, ch2, ch3)
static bool LoadR5G6B5(QDataStream &s, const DDSHeader &header, QImage &img)
static bool LoadDXT1(QDataStream &s, const DDSHeader &header, QImage &img)
static const uint DDPF_FOURCC
static int face_offset[6][2]
static const uint DDSCAPS2_CUBEMAP_NEGATIVEY
static const uint DDSD_PITCH
static const uint DDSD_HEIGHT
static const uint DDSD_CAPS
static const uint DDPF_RGB
static bool LoadATI2(QDataStream &s, const DDSHeader &header, QImage &img)
static const uint DDSCAPS2_CUBEMAP_POSITIVEZ
static QDataStream & operator>>(QDataStream &s, DDSPixelFormat &pf)
static bool IsCubeMap(const DDSHeader &header)
bool write(const QImage &image)
static const uint FOURCC_ATI2
static bool IsSupported(const DDSHeader &header)
static const uint DDPF_ALPHAPIXELS
static const uint DDSD_WIDTH
static bool HasAlpha(const DDSHeader &header)
static bool IsValid(const DDSHeader &header)
static bool LoadA8R8G8B8(QDataStream &s, const DDSHeader &header, QImage &img)
static const uint FOURCC_DXT4
static const uint FOURCC_DDS
static bool LoadA4R4G4B4(QDataStream &s, const DDSHeader &header, QImage &img)
static bool LoadDXT4(QDataStream &s, const DDSHeader &header, QImage &img)
static bool LoadDXT2(QDataStream &s, const DDSHeader &header, QImage &img)
static bool LoadCubeMap(QDataStream &s, const DDSHeader &header, QImage &img)
static bool LoadA1R5G5B5(QDataStream &s, const DDSHeader &header, QImage &img)
QRgb qRgba(const QRgb &rgb, int a)
Change a QRgb value's alpha only.
static bool LoadDXT5(QDataStream &s, const DDSHeader &header, QImage &img)
static const uint DDSCAPS2_CUBEMAP_POSITIVEX
static const uint FOURCC_DXT3
static TextureLoader GetTextureLoader(DDSType type)
static const uint DDSCAPS2_CUBEMAP
static bool LoadDXT3(QDataStream &s, const DDSHeader &header, QImage &img)
static const uint FOURCC_RXGB
static const uint DDSCAPS_TEXTURE
static const uint DDSCAPS2_CUBEMAP_NEGATIVEX
static bool LoadR8G8B8(QDataStream &s, const DDSHeader &header, QImage &img)
static const uint FOURCC_DXT5
static const uint DDSCAPS2_CUBEMAP_POSITIVEY
static const uint DDSD_PIXELFORMAT
static bool LoadTexture(QDataStream &s, const DDSHeader &header, QImage &img)