25 #include <tqdatastream.h>
27 #include <tdeglobal.h>
33 #define sqrtf(x) ((float)sqrt(x))
36 typedef TQ_UINT32 uint;
37 typedef TQ_UINT16 ushort;
38 typedef TQ_UINT8 uchar;
42 #if !defined(MAKEFOURCC)
43 # define MAKEFOURCC(ch0, ch1, ch2, ch3) \
44 (uint(uchar(ch0)) | (uint(uchar(ch1)) << 8) | \
45 (uint(uchar(ch2)) << 16) | (uint(uchar(ch3)) << 24 ))
50 #define CUBE_LAYOUT HORIZONTAL
88 static const uint FOURCC_DDS = MAKEFOURCC(
'D',
'D',
'S',
' ');
89 static const uint FOURCC_DXT1 = MAKEFOURCC(
'D',
'X',
'T',
'1');
90 static const uint FOURCC_DXT2 = MAKEFOURCC(
'D',
'X',
'T',
'2');
91 static const uint FOURCC_DXT3 = MAKEFOURCC(
'D',
'X',
'T',
'3');
92 static const uint FOURCC_DXT4 = MAKEFOURCC(
'D',
'X',
'T',
'4');
93 static const uint FOURCC_DXT5 = MAKEFOURCC(
'D',
'X',
'T',
'5');
94 static const uint FOURCC_RXGB = MAKEFOURCC(
'R',
'X',
'G',
'B');
95 static const uint FOURCC_ATI2 = MAKEFOURCC(
'A',
'T',
'I',
'2');
97 static const uint DDSD_CAPS = 0x00000001l;
98 static const uint DDSD_PIXELFORMAT = 0x00001000l;
99 static const uint DDSD_WIDTH = 0x00000004l;
100 static const uint DDSD_HEIGHT = 0x00000002l;
101 static const uint DDSD_PITCH = 0x00000008l;
103 static const uint DDSCAPS_TEXTURE = 0x00001000l;
104 static const uint DDSCAPS2_VOLUME = 0x00200000l;
105 static const uint DDSCAPS2_CUBEMAP = 0x00000200l;
107 static const uint DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400l;
108 static const uint DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800l;
109 static const uint DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000l;
110 static const uint DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000l;
111 static const uint DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000l;
112 static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000l;
114 static const uint DDPF_RGB = 0x00000040l;
115 static const uint DDPF_FOURCC = 0x00000004l;
116 static const uint DDPF_ALPHAPIXELS = 0x00000001l;
135 struct DDSPixelFormat {
146 static TQDataStream & operator>> ( TQDataStream & s, DDSPixelFormat & pf )
166 static TQDataStream & operator>> ( TQDataStream & s, DDSCaps & caps )
189 static TQDataStream & operator>> ( TQDataStream & s, DDSHeader & header )
197 s >> header.mipmapcount;
198 for(
int i = 0; i < 11; i++ ) {
199 s >> header.reserved[i];
207 static bool IsValid(
const DDSHeader & header )
209 if( header.size != 124 ) {
212 const uint required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT);
213 if( (header.flags & required) != required ) {
216 if( header.pf.size != 32 ) {
219 if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) {
227 static DDSType GetType(
const DDSHeader & header )
229 if( header.pf.flags & DDPF_RGB ) {
230 if( header.pf.flags & DDPF_ALPHAPIXELS ) {
231 switch( header.pf.bitcount ) {
233 return (header.pf.amask == 0x8000) ? DDS_A1R5G5B5 : DDS_A4R4G4B4;
239 switch( header.pf.bitcount ) {
247 else if( header.pf.flags & DDPF_FOURCC ) {
248 switch( header.pf.fourcc ) {
269 static bool HasAlpha(
const DDSHeader & header )
271 return header.pf.flags & DDPF_ALPHAPIXELS;
274 static bool IsCubeMap(
const DDSHeader & header )
276 return header.caps.caps2 & DDSCAPS2_CUBEMAP;
279 static bool IsSupported(
const DDSHeader & header )
281 if( header.caps.caps2 & DDSCAPS2_VOLUME ) {
284 if( GetType(header) == DDS_UNKNOWN ) {
291 static bool LoadA8R8G8B8( TQDataStream & s,
const DDSHeader & header, TQImage & img )
293 const uint w = header.width;
294 const uint h = header.height;
296 for( uint y = 0; y < h; y++ ) {
297 TQRgb * scanline = (TQRgb *) img.scanLine( y );
298 for( uint x = 0; x < w; x++ ) {
300 s >> b >> g >> r >> a;
301 scanline[x] = tqRgba(r, g, b, a);
308 static bool LoadR8G8B8( TQDataStream & s,
const DDSHeader & header, TQImage & img )
310 const uint w = header.width;
311 const uint h = header.height;
313 for( uint y = 0; y < h; y++ ) {
314 TQRgb * scanline = (TQRgb *) img.scanLine( y );
315 for( uint x = 0; x < w; x++ ) {
318 scanline[x] = tqRgb(r, g, b);
325 static bool LoadA1R5G5B5( TQDataStream & s,
const DDSHeader & header, TQImage & img )
327 const uint w = header.width;
328 const uint h = header.height;
330 for( uint y = 0; y < h; y++ ) {
331 TQRgb * scanline = (TQRgb *) img.scanLine( y );
332 for( uint x = 0; x < w; x++ ) {
335 uchar a = (color.c.a != 0) ? 0xFF : 0;
336 uchar r = (color.c.r << 3) | (color.c.r >> 2);
337 uchar g = (color.c.g << 3) | (color.c.g >> 2);
338 uchar b = (color.c.b << 3) | (color.c.b >> 2);
339 scanline[x] = tqRgba(r, g, b, a);
346 static bool LoadA4R4G4B4( TQDataStream & s,
const DDSHeader & header, TQImage & img )
348 const uint w = header.width;
349 const uint h = header.height;
351 for( uint y = 0; y < h; y++ ) {
352 TQRgb * scanline = (TQRgb *) img.scanLine( y );
353 for( uint x = 0; x < w; x++ ) {
356 uchar a = (color.c.a << 4) | color.c.a;
357 uchar r = (color.c.r << 4) | color.c.r;
358 uchar g = (color.c.g << 4) | color.c.g;
359 uchar b = (color.c.b << 4) | color.c.b;
360 scanline[x] = tqRgba(r, g, b, a);
367 static bool LoadR5G6B5( TQDataStream & s,
const DDSHeader & header, TQImage & img )
369 const uint w = header.width;
370 const uint h = header.height;
372 for( uint y = 0; y < h; y++ ) {
373 TQRgb * scanline = (TQRgb *) img.scanLine( y );
374 for( uint x = 0; x < w; x++ ) {
377 uchar r = (color.c.r << 3) | (color.c.r >> 2);
378 uchar g = (color.c.g << 2) | (color.c.g >> 4);
379 uchar b = (color.c.b << 3) | (color.c.b >> 2);
380 scanline[x] = tqRgb(r, g, b);
387 static TQDataStream & operator>> ( TQDataStream & s, Color565 & c )
399 void GetColors( Color8888 color_array[4] )
401 color_array[0].r = (col0.c.r << 3) | (col0.c.r >> 2);
402 color_array[0].g = (col0.c.g << 2) | (col0.c.g >> 4);
403 color_array[0].b = (col0.c.b << 3) | (col0.c.b >> 2);
404 color_array[0].a = 0xFF;
406 color_array[1].r = (col1.c.r << 3) | (col1.c.r >> 2);
407 color_array[1].g = (col1.c.g << 2) | (col1.c.g >> 4);
408 color_array[1].b = (col1.c.b << 3) | (col1.c.b >> 2);
409 color_array[1].a = 0xFF;
411 if( col0.u > col1.u ) {
413 color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3;
414 color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3;
415 color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3;
416 color_array[2].a = 0xFF;
418 color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3;
419 color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3;
420 color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3;
421 color_array[3].a = 0xFF;
425 color_array[2].r = (color_array[0].r + color_array[1].r) / 2;
426 color_array[2].g = (color_array[0].g + color_array[1].g) / 2;
427 color_array[2].b = (color_array[0].b + color_array[1].b) / 2;
428 color_array[2].a = 0xFF;
431 color_array[3].r = 0x00;
432 color_array[3].g = 0x00;
433 color_array[3].b = 0x00;
434 color_array[3].a = 0x00;
440 static TQDataStream & operator>> ( TQDataStream & s, BlockDXT & c )
442 return s >> c.col0 >> c.col1 >> c.row[0] >> c.row[1] >> c.row[2] >> c.row[3];
445 struct BlockDXTAlphaExplicit {
449 static TQDataStream & operator>> ( TQDataStream & s, BlockDXTAlphaExplicit & c )
451 return s >> c.row[0] >> c.row[1] >> c.row[2] >> c.row[3];
454 struct BlockDXTAlphaLinear {
459 void GetAlphas( uchar alpha_array[8] )
461 alpha_array[0] = alpha0;
462 alpha_array[1] = alpha1;
465 if( alpha_array[0] > alpha_array[1] )
470 alpha_array[2] = ( 6 * alpha0 + alpha1) / 7;
471 alpha_array[3] = ( 5 * alpha0 + 2 * alpha1) / 7;
472 alpha_array[4] = ( 4 * alpha0 + 3 * alpha1) / 7;
473 alpha_array[5] = ( 3 * alpha0 + 4 * alpha1) / 7;
474 alpha_array[6] = ( 2 * alpha0 + 5 * alpha1) / 7;
475 alpha_array[7] = ( alpha0 + 6 * alpha1) / 7;
482 alpha_array[2] = (4 * alpha0 + alpha1) / 5;
483 alpha_array[3] = (3 * alpha0 + 2 * alpha1) / 5;
484 alpha_array[4] = (2 * alpha0 + 3 * alpha1) / 5;
485 alpha_array[5] = ( alpha0 + 4 * alpha1) / 5;
486 alpha_array[6] = 0x00;
487 alpha_array[7] = 0xFF;
491 void GetBits( uchar bit_array[16] )
493 uint b =
static_cast<uint
>(bits[0]);
494 bit_array[0] = uchar(b & 0x07); b >>= 3;
495 bit_array[1] = uchar(b & 0x07); b >>= 3;
496 bit_array[2] = uchar(b & 0x07); b >>= 3;
497 bit_array[3] = uchar(b & 0x07); b >>= 3;
498 bit_array[4] = uchar(b & 0x07); b >>= 3;
499 bit_array[5] = uchar(b & 0x07); b >>= 3;
500 bit_array[6] = uchar(b & 0x07); b >>= 3;
501 bit_array[7] = uchar(b & 0x07); b >>= 3;
503 b =
static_cast<uint
>(bits[3]);
504 bit_array[8] = uchar(b & 0x07); b >>= 3;
505 bit_array[9] = uchar(b & 0x07); b >>= 3;
506 bit_array[10] = uchar(b & 0x07); b >>= 3;
507 bit_array[11] = uchar(b & 0x07); b >>= 3;
508 bit_array[12] = uchar(b & 0x07); b >>= 3;
509 bit_array[13] = uchar(b & 0x07); b >>= 3;
510 bit_array[14] = uchar(b & 0x07); b >>= 3;
511 bit_array[15] = uchar(b & 0x07); b >>= 3;
515 static TQDataStream & operator>> ( TQDataStream & s, BlockDXTAlphaLinear & c )
517 s >> c.alpha0 >> c.alpha1;
518 return s >> c.bits[0] >> c.bits[1] >> c.bits[2] >> c.bits[3] >> c.bits[4] >> c.bits[5];
521 static bool LoadDXT1( TQDataStream & s,
const DDSHeader & header, TQImage & img )
523 const uint w = header.width;
524 const uint h = header.height;
529 for( uint y = 0; y < h; y += 4 ) {
530 for( uint j = 0; j < 4; j++ ) {
531 scanline[j] = (TQRgb *) img.scanLine( y + j );
533 for( uint x = 0; x < w; x += 4 ) {
539 Color8888 color_array[4];
540 block.GetColors(color_array);
543 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
544 const int shift[4] = { 0, 2, 4, 6 };
547 for( uint j = 0; j < 4; j++ ) {
548 for( uint i = 0; i < 4; i++ ) {
549 if( img.valid( x+i, y+j ) ) {
550 uint idx = (block.row[j] & masks[i]) >> shift[i];
551 scanline[j][x+i] = tqRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a);
560 static bool LoadDXT3( TQDataStream & s,
const DDSHeader & header, TQImage & img )
562 const uint w = header.width;
563 const uint h = header.height;
566 BlockDXTAlphaExplicit alpha;
569 for( uint y = 0; y < h; y += 4 ) {
570 for( uint j = 0; j < 4; j++ ) {
571 scanline[j] = (TQRgb *) img.scanLine( y + j );
573 for( uint x = 0; x < w; x += 4 ) {
580 Color8888 color_array[4];
581 block.GetColors(color_array);
584 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
585 const int shift[4] = { 0, 2, 4, 6 };
588 for( uint j = 0; j < 4; j++ ) {
589 ushort a = alpha.row[j];
590 for( uint i = 0; i < 4; i++ ) {
591 if( img.valid( x+i, y+j ) ) {
592 uint idx = (block.row[j] & masks[i]) >> shift[i];
593 color_array[idx].a = a & 0x0f;
594 color_array[idx].a = color_array[idx].a | (color_array[idx].a << 4);
595 scanline[j][x+i] = tqRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a);
605 static bool LoadDXT2( TQDataStream & s,
const DDSHeader & header, TQImage & img )
607 if( !LoadDXT3(s, header, img) )
return false;
612 static bool LoadDXT5( TQDataStream & s,
const DDSHeader & header, TQImage & img )
614 const uint w = header.width;
615 const uint h = header.height;
618 BlockDXTAlphaLinear alpha;
621 for( uint y = 0; y < h; y += 4 ) {
622 for( uint j = 0; j < 4; j++ ) {
623 scanline[j] = (TQRgb *) img.scanLine( y + j );
625 for( uint x = 0; x < w; x += 4 ) {
632 Color8888 color_array[4];
633 block.GetColors(color_array);
635 uchar alpha_array[8];
636 alpha.GetAlphas(alpha_array);
639 alpha.GetBits(bit_array);
642 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
643 const int shift[4] = { 0, 2, 4, 6 };
646 for( uint j = 0; j < 4; j++ ) {
647 for( uint i = 0; i < 4; i++ ) {
648 if( img.valid( x+i, y+j ) ) {
649 uint idx = (block.row[j] & masks[i]) >> shift[i];
650 color_array[idx].a = alpha_array[bit_array[j*4+i]];
651 scanline[j][x+i] = tqRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a);
660 static bool LoadDXT4( TQDataStream & s,
const DDSHeader & header, TQImage & img )
662 if( !LoadDXT5(s, header, img) )
return false;
667 static bool LoadRXGB( TQDataStream & s,
const DDSHeader & header, TQImage & img )
669 const uint w = header.width;
670 const uint h = header.height;
673 BlockDXTAlphaLinear alpha;
676 for( uint y = 0; y < h; y += 4 ) {
677 for( uint j = 0; j < 4; j++ ) {
678 scanline[j] = (TQRgb *) img.scanLine( y + j );
680 for( uint x = 0; x < w; x += 4 ) {
687 Color8888 color_array[4];
688 block.GetColors(color_array);
690 uchar alpha_array[8];
691 alpha.GetAlphas(alpha_array);
694 alpha.GetBits(bit_array);
697 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 };
698 const int shift[4] = { 0, 2, 4, 6 };
701 for( uint j = 0; j < 4; j++ ) {
702 for( uint i = 0; i < 4; i++ ) {
703 if( img.valid( x+i, y+j ) ) {
704 uint idx = (block.row[j] & masks[i]) >> shift[i];
705 color_array[idx].a = alpha_array[bit_array[j*4+i]];
706 scanline[j][x+i] = tqRgb(color_array[idx].a, color_array[idx].g, color_array[idx].b);
716 static bool LoadATI2( TQDataStream & s,
const DDSHeader & header, TQImage & img )
718 const uint w = header.width;
719 const uint h = header.height;
721 BlockDXTAlphaLinear xblock;
722 BlockDXTAlphaLinear yblock;
725 for( uint y = 0; y < h; y += 4 ) {
726 for( uint j = 0; j < 4; j++ ) {
727 scanline[j] = (TQRgb *) img.scanLine( y + j );
729 for( uint x = 0; x < w; x += 4 ) {
736 uchar xblock_array[8];
737 xblock.GetAlphas(xblock_array);
739 uchar xbit_array[16];
740 xblock.GetBits(xbit_array);
742 uchar yblock_array[8];
743 yblock.GetAlphas(yblock_array);
745 uchar ybit_array[16];
746 yblock.GetBits(ybit_array);
749 for( uint j = 0; j < 4; j++ ) {
750 for( uint i = 0; i < 4; i++ ) {
751 if( img.valid( x+i, y+j ) ) {
752 const uchar nx = xblock_array[xbit_array[j*4+i]];
753 const uchar ny = yblock_array[ybit_array[j*4+i]];
755 const float fx = float(nx) / 127.5f - 1.0f;
756 const float fy = float(ny) / 127.5f - 1.0f;
757 const float fz = sqrtf(1.0f - fx*fx - fy*fy);
758 const uchar nz = uchar((fz + 1.0f) * 127.5f);
760 scanline[j][x+i] = tqRgb(nx, ny, nz);
772 typedef bool (* TextureLoader)( TQDataStream & s,
const DDSHeader & header, TQImage & img );
775 static TextureLoader GetTextureLoader( DDSType type ) {
808 static bool LoadTexture( TQDataStream & s,
const DDSHeader & header, TQImage & img )
811 if( !img.create( header.width, header.height, 32 )) {
816 DDSType type = GetType( header );
819 if( HasAlpha( header ) || type >= DDS_DXT1 ) {
820 img.setAlphaBuffer(
true );
823 TextureLoader loader = GetTextureLoader( type );
824 if( loader == NULL ) {
828 return loader( s, header, img );
832 static int FaceOffset(
const DDSHeader & header ) {
834 DDSType type = GetType( header );
836 int mipmap = kMax(
int(header.mipmapcount), 1);
838 int w = header.width;
839 int h = header.height;
841 if( type >= DDS_DXT1 ) {
842 int multiplier = (type == DDS_DXT1) ? 8 : 16;
844 int face_size = kMax(w/4,1) * kMax(h/4,1) * multiplier;
851 int multiplier = header.pf.bitcount / 8;
853 int face_size = w * h * multiplier;
863 #if CUBE_LAYOUT == HORIZONTAL
864 static int face_offset[6][2] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {3, 1} };
865 #elif CUBE_LAYOUT == VERTICAL
866 static int face_offset[6][2] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {1, 3} };
868 static int face_flags[6] = {
869 DDSCAPS2_CUBEMAP_POSITIVEX,
870 DDSCAPS2_CUBEMAP_NEGATIVEX,
871 DDSCAPS2_CUBEMAP_POSITIVEY,
872 DDSCAPS2_CUBEMAP_NEGATIVEY,
873 DDSCAPS2_CUBEMAP_POSITIVEZ,
874 DDSCAPS2_CUBEMAP_NEGATIVEZ
878 static bool LoadCubeMap( TQDataStream & s,
const DDSHeader & header, TQImage & img )
881 #if CUBE_LAYOUT == HORIZONTAL
882 if( !img.create( 4 * header.width, 3 * header.height, 32 )) {
885 #elif CUBE_LAYOUT == VERTICAL
886 if( !img.create( 3 * header.width, 4 * header.height, 32 )) {
891 DDSType type = GetType( header );
894 if( HasAlpha( header ) || type >= DDS_DXT1 ) {
895 img.setAlphaBuffer(
true );
899 TextureLoader loader = GetTextureLoader( type );
900 if( loader == NULL ) {
909 if( !face.create( header.width, header.height, 32 )) {
913 int offset = s.device()->at();
914 int size = FaceOffset( header );
916 for(
int i = 0; i < 6; i++ ) {
918 if( !(header.caps.caps2 & face_flags[i]) ) {
924 s.device()->at( offset );
928 if( !loader( s, header, face ) ) {
932 #if CUBE_LAYOUT == VERTICAL
934 face = face.mirror(
true,
true);
939 int offset_x = face_offset[i][0] * header.width;
940 int offset_y = face_offset[i][1] * header.height;
943 for( uint y = 0; y < header.height; y++ ) {
944 TQRgb * src = (TQRgb *) face.scanLine( y );
945 TQRgb * dst = (TQRgb *) img.scanLine( y + offset_y ) + offset_x;
946 memcpy( dst, src,
sizeof(TQRgb) * header.width );
956 TDE_EXPORT
void kimgio_dds_read( TQImageIO *io )
958 TQDataStream s( io->ioDevice() );
959 s.setByteOrder( TQDataStream::LittleEndian );
964 if( fourcc != FOURCC_DDS ) {
965 kdDebug(399) <<
"This is not a DDS file." << endl;
966 io->setImage( TQImage() );
976 if( s.atEnd() || !IsValid( header ) ) {
977 kdDebug(399) <<
"This DDS file is not valid." << endl;
978 io->setImage( TQImage() );
984 if( !IsSupported( header ) ) {
985 kdDebug(399) <<
"This DDS file is not supported." << endl;
986 io->setImage( TQImage() );
995 if( IsCubeMap( header ) ) {
996 result = LoadCubeMap( s, header, img );
999 result = LoadTexture( s, header, img );
1002 if( result ==
false ) {
1003 kdDebug(399) <<
"Error loading DDS file." << endl;
1004 io->setImage( TQImage() );
1005 io->setStatus( -1 );
1009 io->setImage( img );
1014 TDE_EXPORT
void kimgio_dds_write( TQImageIO * )