1 /* This file is part of the KDE project
2 Copyright (C) 2003 Ignacio CastaƱo <castano@ludicon.com>
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the Lesser GNU General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 Almost all this code is based on nVidia's DDS-loading example
10 and the DevIl's source code by Denton Woods.
13 /* this code supports:
15 * rgb and dxt dds files
17 * volume dds files -- TODO
19 * rgb dds files only -- TODO
24 #include <QtCore/QStringList>
25 #include <QtGui/QImage>
26 #include <QtCore/QDataStream>
31 #include <math.h> // sqrtf
34 #define sqrtf(x) ((float)sqrt(x))
38 typedef quint16 ushort
;
41 #if !defined(MAKEFOURCC)
42 # define MAKEFOURCC(ch0, ch1, ch2, ch3) \
43 (uint(uchar(ch0)) | (uint(uchar(ch1)) << 8) | \
44 (uint(uchar(ch2)) << 16) | (uint(uchar(ch3)) << 24 ))
49 #define CUBE_LAYOUT HORIZONTAL
87 static const uint FOURCC_DDS
= MAKEFOURCC('D', 'D', 'S', ' ');
88 static const uint FOURCC_DXT1
= MAKEFOURCC('D', 'X', 'T', '1');
89 static const uint FOURCC_DXT2
= MAKEFOURCC('D', 'X', 'T', '2');
90 static const uint FOURCC_DXT3
= MAKEFOURCC('D', 'X', 'T', '3');
91 static const uint FOURCC_DXT4
= MAKEFOURCC('D', 'X', 'T', '4');
92 static const uint FOURCC_DXT5
= MAKEFOURCC('D', 'X', 'T', '5');
93 static const uint FOURCC_RXGB
= MAKEFOURCC('R', 'X', 'G', 'B');
94 static const uint FOURCC_ATI2
= MAKEFOURCC('A', 'T', 'I', '2');
96 static const uint DDSD_CAPS
= 0x00000001l
;
97 static const uint DDSD_PIXELFORMAT
= 0x00001000l
;
98 static const uint DDSD_WIDTH
= 0x00000004l
;
99 static const uint DDSD_HEIGHT
= 0x00000002l
;
100 static const uint DDSD_PITCH
= 0x00000008l
;
102 static const uint DDSCAPS_TEXTURE
= 0x00001000l
;
103 static const uint DDSCAPS2_VOLUME
= 0x00200000l
;
104 static const uint DDSCAPS2_CUBEMAP
= 0x00000200l
;
106 static const uint DDSCAPS2_CUBEMAP_POSITIVEX
= 0x00000400l
;
107 static const uint DDSCAPS2_CUBEMAP_NEGATIVEX
= 0x00000800l
;
108 static const uint DDSCAPS2_CUBEMAP_POSITIVEY
= 0x00001000l
;
109 static const uint DDSCAPS2_CUBEMAP_NEGATIVEY
= 0x00002000l
;
110 static const uint DDSCAPS2_CUBEMAP_POSITIVEZ
= 0x00004000l
;
111 static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ
= 0x00008000l
;
113 static const uint DDPF_RGB
= 0x00000040l
;
114 static const uint DDPF_FOURCC
= 0x00000004l
;
115 static const uint DDPF_ALPHAPIXELS
= 0x00000001l
;
134 struct DDSPixelFormat
{
145 static QDataStream
& operator>> ( QDataStream
& s
, DDSPixelFormat
& pf
)
165 static QDataStream
& operator>> ( QDataStream
& s
, DDSCaps
& caps
)
188 static QDataStream
& operator>> ( QDataStream
& s
, DDSHeader
& header
)
196 s
>> header
.mipmapcount
;
197 for( int i
= 0; i
< 11; i
++ ) {
198 s
>> header
.reserved
[i
];
206 static bool IsValid( const DDSHeader
& header
)
208 if( header
.size
!= 124 ) {
211 const uint required
= (DDSD_WIDTH
|DDSD_HEIGHT
|DDSD_PIXELFORMAT
);
212 if( (header
.flags
& required
) != required
) {
215 if( header
.pf
.size
!= 32 ) {
218 if( !(header
.caps
.caps1
& DDSCAPS_TEXTURE
) ) {
225 // Get supported type. We currently support 10 different types.
226 static DDSType
GetType( const DDSHeader
& header
)
228 if( header
.pf
.flags
& DDPF_RGB
) {
229 if( header
.pf
.flags
& DDPF_ALPHAPIXELS
) {
230 switch( header
.pf
.bitcount
) {
232 return (header
.pf
.amask
== 0x8000) ? DDS_A1R5G5B5
: DDS_A4R4G4B4
;
238 switch( header
.pf
.bitcount
) {
246 else if( header
.pf
.flags
& DDPF_FOURCC
) {
247 switch( header
.pf
.fourcc
) {
267 static bool HasAlpha( const DDSHeader
& header
)
269 return header
.pf
.flags
& DDPF_ALPHAPIXELS
;
272 static bool IsCubeMap( const DDSHeader
& header
)
274 return header
.caps
.caps2
& DDSCAPS2_CUBEMAP
;
277 static bool IsSupported( const DDSHeader
& header
)
279 if( header
.caps
.caps2
& DDSCAPS2_VOLUME
) {
282 if( GetType(header
) == DDS_UNKNOWN
) {
288 static bool LoadA8R8G8B8( QDataStream
& s
, const DDSHeader
& header
, QImage
& img
)
290 const uint w
= header
.width
;
291 const uint h
= header
.height
;
293 for( uint y
= 0; y
< h
; y
++ ) {
294 QRgb
* scanline
= (QRgb
*) img
.scanLine( y
);
295 for( uint x
= 0; x
< w
; x
++ ) {
297 s
>> b
>> g
>> r
>> a
;
298 scanline
[x
] = qRgba(r
, g
, b
, a
);
305 static bool LoadR8G8B8( QDataStream
& s
, const DDSHeader
& header
, QImage
& img
)
307 const uint w
= header
.width
;
308 const uint h
= header
.height
;
310 for( uint y
= 0; y
< h
; y
++ ) {
311 QRgb
* scanline
= (QRgb
*) img
.scanLine( y
);
312 for( uint x
= 0; x
< w
; x
++ ) {
315 scanline
[x
] = qRgb(r
, g
, b
);
322 static bool LoadA1R5G5B5( QDataStream
& s
, const DDSHeader
& header
, QImage
& img
)
324 const uint w
= header
.width
;
325 const uint h
= header
.height
;
327 for( uint y
= 0; y
< h
; y
++ ) {
328 QRgb
* scanline
= (QRgb
*) img
.scanLine( y
);
329 for( uint x
= 0; x
< w
; x
++ ) {
332 uchar a
= (color
.c
.a
!= 0) ? 0xFF : 0;
333 uchar r
= (color
.c
.r
<< 3) | (color
.c
.r
>> 2);
334 uchar g
= (color
.c
.g
<< 3) | (color
.c
.g
>> 2);
335 uchar b
= (color
.c
.b
<< 3) | (color
.c
.b
>> 2);
336 scanline
[x
] = qRgba(r
, g
, b
, a
);
343 static bool LoadA4R4G4B4( QDataStream
& s
, const DDSHeader
& header
, QImage
& img
)
345 const uint w
= header
.width
;
346 const uint h
= header
.height
;
348 for( uint y
= 0; y
< h
; y
++ ) {
349 QRgb
* scanline
= (QRgb
*) img
.scanLine( y
);
350 for( uint x
= 0; x
< w
; x
++ ) {
353 uchar a
= (color
.c
.a
<< 4) | color
.c
.a
;
354 uchar r
= (color
.c
.r
<< 4) | color
.c
.r
;
355 uchar g
= (color
.c
.g
<< 4) | color
.c
.g
;
356 uchar b
= (color
.c
.b
<< 4) | color
.c
.b
;
357 scanline
[x
] = qRgba(r
, g
, b
, a
);
364 static bool LoadR5G6B5( QDataStream
& s
, const DDSHeader
& header
, QImage
& img
)
366 const uint w
= header
.width
;
367 const uint h
= header
.height
;
369 for( uint y
= 0; y
< h
; y
++ ) {
370 QRgb
* scanline
= (QRgb
*) img
.scanLine( y
);
371 for( uint x
= 0; x
< w
; x
++ ) {
374 uchar r
= (color
.c
.r
<< 3) | (color
.c
.r
>> 2);
375 uchar g
= (color
.c
.g
<< 2) | (color
.c
.g
>> 4);
376 uchar b
= (color
.c
.b
<< 3) | (color
.c
.b
>> 2);
377 scanline
[x
] = qRgb(r
, g
, b
);
384 static QDataStream
& operator>> ( QDataStream
& s
, Color565
& c
)
396 void GetColors( Color8888 color_array
[4] )
398 color_array
[0].r
= (col0
.c
.r
<< 3) | (col0
.c
.r
>> 2);
399 color_array
[0].g
= (col0
.c
.g
<< 2) | (col0
.c
.g
>> 4);
400 color_array
[0].b
= (col0
.c
.b
<< 3) | (col0
.c
.b
>> 2);
401 color_array
[0].a
= 0xFF;
403 color_array
[1].r
= (col1
.c
.r
<< 3) | (col1
.c
.r
>> 2);
404 color_array
[1].g
= (col1
.c
.g
<< 2) | (col1
.c
.g
>> 4);
405 color_array
[1].b
= (col1
.c
.b
<< 3) | (col1
.c
.b
>> 2);
406 color_array
[1].a
= 0xFF;
408 if( col0
.u
> col1
.u
) {
409 // Four-color block: derive the other two colors.
410 color_array
[2].r
= (2 * color_array
[0].r
+ color_array
[1].r
) / 3;
411 color_array
[2].g
= (2 * color_array
[0].g
+ color_array
[1].g
) / 3;
412 color_array
[2].b
= (2 * color_array
[0].b
+ color_array
[1].b
) / 3;
413 color_array
[2].a
= 0xFF;
415 color_array
[3].r
= (2 * color_array
[1].r
+ color_array
[0].r
) / 3;
416 color_array
[3].g
= (2 * color_array
[1].g
+ color_array
[0].g
) / 3;
417 color_array
[3].b
= (2 * color_array
[1].b
+ color_array
[0].b
) / 3;
418 color_array
[3].a
= 0xFF;
421 // Three-color block: derive the other color.
422 color_array
[2].r
= (color_array
[0].r
+ color_array
[1].r
) / 2;
423 color_array
[2].g
= (color_array
[0].g
+ color_array
[1].g
) / 2;
424 color_array
[2].b
= (color_array
[0].b
+ color_array
[1].b
) / 2;
425 color_array
[2].a
= 0xFF;
427 // Set all components to 0 to match DXT specs.
428 color_array
[3].r
= 0x00; // color_array[2].r;
429 color_array
[3].g
= 0x00; // color_array[2].g;
430 color_array
[3].b
= 0x00; // color_array[2].b;
431 color_array
[3].a
= 0x00;
437 static QDataStream
& operator>> ( QDataStream
& s
, BlockDXT
& c
)
439 return s
>> c
.col0
>> c
.col1
>> c
.row
[0] >> c
.row
[1] >> c
.row
[2] >> c
.row
[3];
442 struct BlockDXTAlphaExplicit
{
446 static QDataStream
& operator>> ( QDataStream
& s
, BlockDXTAlphaExplicit
& c
)
448 return s
>> c
.row
[0] >> c
.row
[1] >> c
.row
[2] >> c
.row
[3];
451 struct BlockDXTAlphaLinear
{
456 void GetAlphas( uchar alpha_array
[8] )
458 alpha_array
[0] = alpha0
;
459 alpha_array
[1] = alpha1
;
461 // 8-alpha or 6-alpha block?
462 if( alpha_array
[0] > alpha_array
[1] )
464 // 8-alpha block: derive the other 6 alphas.
465 // 000 = alpha_0, 001 = alpha_1, others are interpolated
467 alpha_array
[2] = ( 6 * alpha0
+ alpha1
) / 7; // bit code 010
468 alpha_array
[3] = ( 5 * alpha0
+ 2 * alpha1
) / 7; // Bit code 011
469 alpha_array
[4] = ( 4 * alpha0
+ 3 * alpha1
) / 7; // Bit code 100
470 alpha_array
[5] = ( 3 * alpha0
+ 4 * alpha1
) / 7; // Bit code 101
471 alpha_array
[6] = ( 2 * alpha0
+ 5 * alpha1
) / 7; // Bit code 110
472 alpha_array
[7] = ( alpha0
+ 6 * alpha1
) / 7; // Bit code 111
476 // 6-alpha block: derive the other alphas.
477 // 000 = alpha_0, 001 = alpha_1, others are interpolated
479 alpha_array
[2] = (4 * alpha0
+ alpha1
) / 5; // Bit code 010
480 alpha_array
[3] = (3 * alpha0
+ 2 * alpha1
) / 5; // Bit code 011
481 alpha_array
[4] = (2 * alpha0
+ 3 * alpha1
) / 5; // Bit code 100
482 alpha_array
[5] = ( alpha0
+ 4 * alpha1
) / 5; // Bit code 101
483 alpha_array
[6] = 0x00; // Bit code 110
484 alpha_array
[7] = 0xFF; // Bit code 111
488 void GetBits( uchar bit_array
[16] )
490 uint b
= (uint
&) bits
[0];
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); b
>>= 3;
500 b
= (uint
&) bits
[3];
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); b
>>= 3;
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 ) {
532 // Read 64bit color block.
535 // Decode color block.
536 Color8888 color_array
[4];
537 block
.GetColors(color_array
);
539 // bit masks = 00000011, 00001100, 00110000, 11000000
540 const uint masks
[4] = { 3, 3<<2, 3<<4, 3<<6 };
541 const int shift
[4] = { 0, 2, 4, 6 };
543 // Write color block.
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 ) {
572 // Read 128bit color block.
576 // Decode color block.
577 Color8888 color_array
[4];
578 block
.GetColors(color_array
);
580 // bit masks = 00000011, 00001100, 00110000, 11000000
581 const uint masks
[4] = { 3, 3<<2, 3<<4, 3<<6 };
582 const int shift
[4] = { 0, 2, 4, 6 };
584 // Write color block.
585 for( uint j
= 0; j
< 4; j
++ ) {
586 ushort a
= alpha
.row
[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;
605 //UndoPremultiplyAlpha(img);
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 ) {
624 // Read 128bit color block.
628 // Decode color block.
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
);
638 // bit masks = 00000011, 00001100, 00110000, 11000000
639 const uint masks
[4] = { 3, 3<<2, 3<<4, 3<<6 };
640 const int shift
[4] = { 0, 2, 4, 6 };
642 // Write color block.
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;
660 //UndoPremultiplyAlpha(img);
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 ) {
679 // Read 128bit color block.
683 // Decode color block.
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
);
693 // bit masks = 00000011, 00001100, 00110000, 11000000
694 const uint masks
[4] = { 3, 3<<2, 3<<4, 3<<6 };
695 const int shift
[4] = { 0, 2, 4, 6 };
697 // Write color block.
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 ) {
728 // Read 128bit color block.
732 // Decode color block.
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
);
745 // Write color block.
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
);
755 const uchar nz
= uchar((fz
+ 1.0f
) * 127.5f
);
757 scanline
[j
][x
+i
] = qRgb(nx
, ny
, nz
);
769 typedef bool (* TextureLoader
)( QDataStream
& s
, const DDSHeader
& header
, QImage
& img
);
771 // Get an appropriate texture loader for the given type.
772 static TextureLoader
GetTextureLoader( DDSType type
) {
804 // Load a 2d texture.
805 static bool LoadTexture( QDataStream
& s
, const DDSHeader
& header
, QImage
& img
)
808 img
= QImage( header
.width
, header
.height
, QImage::Format_RGB32
);
811 DDSType type
= GetType( header
);
813 // Enable alpha buffer for transparent or DDS images.
814 if( HasAlpha( header
) || type
>= DDS_DXT1
) {
815 img
= img
.convertToFormat( QImage::Format_ARGB32
);
818 TextureLoader loader
= GetTextureLoader( type
);
819 if( loader
== NULL
) {
823 return loader( s
, header
, img
);
827 static int FaceOffset( const DDSHeader
& header
) {
829 DDSType type
= GetType( header
);
831 int mipmap
= qMax(header
.mipmapcount
, 1U);
833 int w
= header
.width
;
834 int h
= header
.height
;
836 if( type
>= DDS_DXT1
) {
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} };
863 static int face_flags
[6] = {
864 DDSCAPS2_CUBEMAP_POSITIVEX
,
865 DDSCAPS2_CUBEMAP_NEGATIVEX
,
866 DDSCAPS2_CUBEMAP_POSITIVEY
,
867 DDSCAPS2_CUBEMAP_NEGATIVEY
,
868 DDSCAPS2_CUBEMAP_POSITIVEZ
,
869 DDSCAPS2_CUBEMAP_NEGATIVEZ
872 // Load unwrapped cube map.
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
);
882 DDSType type
= GetType( header
);
884 // Enable alpha buffer for transparent or DDS images.
885 if( HasAlpha( header
) || type
>= DDS_DXT1
) {
886 img
= img
.convertToFormat( QImage::Format_ARGB32
);
889 // Select texture loader.
890 TextureLoader loader
= GetTextureLoader( type
);
891 if( loader
== NULL
) {
898 // Create face image.
899 QImage
face(header
.width
, header
.height
, QImage::Format_RGB32
);
901 int offset
= s
.device()->pos();
902 int size
= FaceOffset( header
);
904 for( int i
= 0; i
< 6; i
++ ) {
906 if( !(header
.caps
.caps2
& face_flags
[i
]) ) {
912 s
.device()->seek( offset
);
915 // Load face from stream.
916 if( !loader( s
, header
, face
) ) {
920 #if CUBE_LAYOUT == VERTICAL
922 face
= face
.mirror(true, true);
926 // Compute face offsets.
927 int offset_x
= face_offset
[i
][0] * header
.width
;
928 int offset_y
= face_offset
[i
][1] * header
.height
;
930 // Copy face on the image.
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
);
943 DDSHandler::DDSHandler()
947 bool DDSHandler::canRead() const
949 if (canRead(device())) {
956 bool DDSHandler::read(QImage
*image
)
958 QDataStream
s( device() );
959 s
.setByteOrder( QDataStream::LittleEndian
);
964 if( fourcc
!= FOURCC_DDS
) {
965 kDebug(399) << "This is not a DDS file.";
969 // Read image header.
973 // Check image file format.
974 if( s
.atEnd() || !IsValid( header
) ) {
975 kDebug(399) << "This DDS file is not valid.";
979 // Determine image type, by now, we only support 2d textures.
980 if( !IsSupported( header
) ) {
981 kDebug(399) << "This DDS file is not supported.";
987 if( IsCubeMap( header
) ) {
988 result
= LoadCubeMap( s
, header
, *image
);
991 result
= LoadTexture( s
, header
, *image
);
997 bool DDSHandler::write(const QImage
&)
1003 QByteArray
DDSHandler::name() const
1008 bool DDSHandler::canRead(QIODevice
*device
)
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())
1062 if (device
->isReadable() && DDSHandler::canRead(device
))
1067 QImageIOHandler
*DDSPlugin::create(QIODevice
*device
, const QByteArray
&format
) const
1069 QImageIOHandler
*handler
= new DDSHandler
;
1070 handler
->setDevice(device
);
1071 handler
->setFormat(format
);
1075 Q_EXPORT_STATIC_PLUGIN(DDSPlugin
)
1076 Q_EXPORT_PLUGIN2(dds
, DDSPlugin
)