dds.cpp
00001 /* This file is part of the KDE project 00002 Copyright (C) 2003 Ignacio Castaņo <castano@ludicon.com> 00003 00004 This program is free software; you can redistribute it and/or 00005 modify it under the terms of the Lesser GNU General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 Almost all this code is based on nVidia's DDS-loading example 00010 and the DevIl's source code by Denton Woods. 00011 */ 00012 00013 /* this code supports: 00014 * reading: 00015 * rgb and dxt dds files 00016 * cubemap dds files 00017 * volume dds files -- TODO 00018 * writing: 00019 * rgb dds files only -- TODO 00020 */ 00021 00022 #include "dds.h" 00023 00024 #include <tqimage.h> 00025 #include <tqdatastream.h> 00026 00027 #include <kglobal.h> 00028 #include <kdebug.h> 00029 00030 #include <math.h> // sqrtf 00031 00032 #ifndef __USE_ISOC99 00033 #define sqrtf(x) ((float)sqrt(x)) 00034 #endif 00035 00036 typedef TQ_UINT32 uint; 00037 typedef TQ_UINT16 ushort; 00038 typedef TQ_UINT8 uchar; 00039 00040 namespace { // Private. 00041 00042 #if !defined(MAKEFOURCC) 00043 # define MAKEFOURCC(ch0, ch1, ch2, ch3) \ 00044 (uint(uchar(ch0)) | (uint(uchar(ch1)) << 8) | \ 00045 (uint(uchar(ch2)) << 16) | (uint(uchar(ch3)) << 24 )) 00046 #endif 00047 00048 #define HORIZONTAL 1 00049 #define VERTICAL 2 00050 #define CUBE_LAYOUT HORIZONTAL 00051 00052 struct Color8888 00053 { 00054 uchar r, g, b, a; 00055 }; 00056 00057 union Color565 00058 { 00059 struct { 00060 ushort b : 5; 00061 ushort g : 6; 00062 ushort r : 5; 00063 } c; 00064 ushort u; 00065 }; 00066 00067 union Color1555 { 00068 struct { 00069 ushort b : 5; 00070 ushort g : 5; 00071 ushort r : 5; 00072 ushort a : 1; 00073 } c; 00074 ushort u; 00075 }; 00076 00077 union Color4444 { 00078 struct { 00079 ushort b : 4; 00080 ushort g : 4; 00081 ushort r : 4; 00082 ushort a : 4; 00083 } c; 00084 ushort u; 00085 }; 00086 00087 00088 static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' '); 00089 static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1'); 00090 static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2'); 00091 static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3'); 00092 static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4'); 00093 static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5'); 00094 static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B'); 00095 static const uint FOURCC_ATI2 = MAKEFOURCC('A', 'T', 'I', '2'); 00096 00097 static const uint DDSD_CAPS = 0x00000001l; 00098 static const uint DDSD_PIXELFORMAT = 0x00001000l; 00099 static const uint DDSD_WIDTH = 0x00000004l; 00100 static const uint DDSD_HEIGHT = 0x00000002l; 00101 static const uint DDSD_PITCH = 0x00000008l; 00102 00103 static const uint DDSCAPS_TEXTURE = 0x00001000l; 00104 static const uint DDSCAPS2_VOLUME = 0x00200000l; 00105 static const uint DDSCAPS2_CUBEMAP = 0x00000200l; 00106 00107 static const uint DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400l; 00108 static const uint DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800l; 00109 static const uint DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000l; 00110 static const uint DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000l; 00111 static const uint DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000l; 00112 static const uint DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000l; 00113 00114 static const uint DDPF_RGB = 0x00000040l; 00115 static const uint DDPF_FOURCC = 0x00000004l; 00116 static const uint DDPF_ALPHAPIXELS = 0x00000001l; 00117 00118 enum DDSType { 00119 DDS_A8R8G8B8 = 0, 00120 DDS_A1R5G5B5 = 1, 00121 DDS_A4R4G4B4 = 2, 00122 DDS_R8G8B8 = 3, 00123 DDS_R5G6B5 = 4, 00124 DDS_DXT1 = 5, 00125 DDS_DXT2 = 6, 00126 DDS_DXT3 = 7, 00127 DDS_DXT4 = 8, 00128 DDS_DXT5 = 9, 00129 DDS_RXGB = 10, 00130 DDS_ATI2 = 11, 00131 DDS_UNKNOWN 00132 }; 00133 00134 00135 struct DDSPixelFormat { 00136 uint size; 00137 uint flags; 00138 uint fourcc; 00139 uint bitcount; 00140 uint rmask; 00141 uint gmask; 00142 uint bmask; 00143 uint amask; 00144 }; 00145 00146 static TQDataStream & operator>> ( TQDataStream & s, DDSPixelFormat & pf ) 00147 { 00148 s >> pf.size; 00149 s >> pf.flags; 00150 s >> pf.fourcc; 00151 s >> pf.bitcount; 00152 s >> pf.rmask; 00153 s >> pf.gmask; 00154 s >> pf.bmask; 00155 s >> pf.amask; 00156 return s; 00157 } 00158 00159 struct DDSCaps { 00160 uint caps1; 00161 uint caps2; 00162 uint caps3; 00163 uint caps4; 00164 }; 00165 00166 static TQDataStream & operator>> ( TQDataStream & s, DDSCaps & caps ) 00167 { 00168 s >> caps.caps1; 00169 s >> caps.caps2; 00170 s >> caps.caps3; 00171 s >> caps.caps4; 00172 return s; 00173 } 00174 00175 struct DDSHeader { 00176 uint size; 00177 uint flags; 00178 uint height; 00179 uint width; 00180 uint pitch; 00181 uint depth; 00182 uint mipmapcount; 00183 uint reserved[11]; 00184 DDSPixelFormat pf; 00185 DDSCaps caps; 00186 uint notused; 00187 }; 00188 00189 static TQDataStream & operator>> ( TQDataStream & s, DDSHeader & header ) 00190 { 00191 s >> header.size; 00192 s >> header.flags; 00193 s >> header.height; 00194 s >> header.width; 00195 s >> header.pitch; 00196 s >> header.depth; 00197 s >> header.mipmapcount; 00198 for( int i = 0; i < 11; i++ ) { 00199 s >> header.reserved[i]; 00200 } 00201 s >> header.pf; 00202 s >> header.caps; 00203 s >> header.notused; 00204 return s; 00205 } 00206 00207 static bool IsValid( const DDSHeader & header ) 00208 { 00209 if( header.size != 124 ) { 00210 return false; 00211 } 00212 const uint required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT); 00213 if( (header.flags & required) != required ) { 00214 return false; 00215 } 00216 if( header.pf.size != 32 ) { 00217 return false; 00218 } 00219 if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) { 00220 return false; 00221 } 00222 return true; 00223 } 00224 00225 00226 // Get supported type. We currently support 10 different types. 00227 static DDSType GetType( const DDSHeader & header ) 00228 { 00229 if( header.pf.flags & DDPF_RGB ) { 00230 if( header.pf.flags & DDPF_ALPHAPIXELS ) { 00231 switch( header.pf.bitcount ) { 00232 case 16: 00233 return (header.pf.amask == 0x8000) ? DDS_A1R5G5B5 : DDS_A4R4G4B4; 00234 case 32: 00235 return DDS_A8R8G8B8; 00236 } 00237 } 00238 else { 00239 switch( header.pf.bitcount ) { 00240 case 16: 00241 return DDS_R5G6B5; 00242 case 24: 00243 return DDS_R8G8B8; 00244 } 00245 } 00246 } 00247 else if( header.pf.flags & DDPF_FOURCC ) { 00248 switch( header.pf.fourcc ) { 00249 case FOURCC_DXT1: 00250 return DDS_DXT1; 00251 case FOURCC_DXT2: 00252 return DDS_DXT2; 00253 case FOURCC_DXT3: 00254 return DDS_DXT3; 00255 case FOURCC_DXT4: 00256 return DDS_DXT4; 00257 case FOURCC_DXT5: 00258 return DDS_DXT5; 00259 case FOURCC_RXGB: 00260 return DDS_RXGB; 00261 case FOURCC_ATI2: 00262 return DDS_ATI2; 00263 } 00264 } 00265 return DDS_UNKNOWN; 00266 } 00267 00268 00269 static bool HasAlpha( const DDSHeader & header ) 00270 { 00271 return header.pf.flags & DDPF_ALPHAPIXELS; 00272 } 00273 00274 static bool IsCubeMap( const DDSHeader & header ) 00275 { 00276 return header.caps.caps2 & DDSCAPS2_CUBEMAP; 00277 } 00278 00279 static bool IsSupported( const DDSHeader & header ) 00280 { 00281 if( header.caps.caps2 & DDSCAPS2_VOLUME ) { 00282 return false; 00283 } 00284 if( GetType(header) == DDS_UNKNOWN ) { 00285 return false; 00286 } 00287 return true; 00288 } 00289 00290 00291 static bool LoadA8R8G8B8( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00292 { 00293 const uint w = header.width; 00294 const uint h = header.height; 00295 00296 for( uint y = 0; y < h; y++ ) { 00297 QRgb * scanline = (QRgb *) img.scanLine( y ); 00298 for( uint x = 0; x < w; x++ ) { 00299 uchar r, g, b, a; 00300 s >> b >> g >> r >> a; 00301 scanline[x] = tqRgba(r, g, b, a); 00302 } 00303 } 00304 00305 return true; 00306 } 00307 00308 static bool LoadR8G8B8( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00309 { 00310 const uint w = header.width; 00311 const uint h = header.height; 00312 00313 for( uint y = 0; y < h; y++ ) { 00314 QRgb * scanline = (QRgb *) img.scanLine( y ); 00315 for( uint x = 0; x < w; x++ ) { 00316 uchar r, g, b; 00317 s >> b >> g >> r; 00318 scanline[x] = tqRgb(r, g, b); 00319 } 00320 } 00321 00322 return true; 00323 } 00324 00325 static bool LoadA1R5G5B5( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00326 { 00327 const uint w = header.width; 00328 const uint h = header.height; 00329 00330 for( uint y = 0; y < h; y++ ) { 00331 QRgb * scanline = (QRgb *) img.scanLine( y ); 00332 for( uint x = 0; x < w; x++ ) { 00333 Color1555 color; 00334 s >> color.u; 00335 uchar a = (color.c.a != 0) ? 0xFF : 0; 00336 uchar r = (color.c.r << 3) | (color.c.r >> 2); 00337 uchar g = (color.c.g << 3) | (color.c.g >> 2); 00338 uchar b = (color.c.b << 3) | (color.c.b >> 2); 00339 scanline[x] = tqRgba(r, g, b, a); 00340 } 00341 } 00342 00343 return true; 00344 } 00345 00346 static bool LoadA4R4G4B4( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00347 { 00348 const uint w = header.width; 00349 const uint h = header.height; 00350 00351 for( uint y = 0; y < h; y++ ) { 00352 QRgb * scanline = (QRgb *) img.scanLine( y ); 00353 for( uint x = 0; x < w; x++ ) { 00354 Color4444 color; 00355 s >> color.u; 00356 uchar a = (color.c.a << 4) | color.c.a; 00357 uchar r = (color.c.r << 4) | color.c.r; 00358 uchar g = (color.c.g << 4) | color.c.g; 00359 uchar b = (color.c.b << 4) | color.c.b; 00360 scanline[x] = tqRgba(r, g, b, a); 00361 } 00362 } 00363 00364 return true; 00365 } 00366 00367 static bool LoadR5G6B5( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00368 { 00369 const uint w = header.width; 00370 const uint h = header.height; 00371 00372 for( uint y = 0; y < h; y++ ) { 00373 QRgb * scanline = (QRgb *) img.scanLine( y ); 00374 for( uint x = 0; x < w; x++ ) { 00375 Color565 color; 00376 s >> color.u; 00377 uchar r = (color.c.r << 3) | (color.c.r >> 2); 00378 uchar g = (color.c.g << 2) | (color.c.g >> 4); 00379 uchar b = (color.c.b << 3) | (color.c.b >> 2); 00380 scanline[x] = tqRgb(r, g, b); 00381 } 00382 } 00383 00384 return true; 00385 } 00386 00387 static TQDataStream & operator>> ( TQDataStream & s, Color565 & c ) 00388 { 00389 return s >> c.u; 00390 } 00391 00392 00393 struct BlockDXT 00394 { 00395 Color565 col0; 00396 Color565 col1; 00397 uchar row[4]; 00398 00399 void GetColors( Color8888 color_array[4] ) 00400 { 00401 color_array[0].r = (col0.c.r << 3) | (col0.c.r >> 2); 00402 color_array[0].g = (col0.c.g << 2) | (col0.c.g >> 4); 00403 color_array[0].b = (col0.c.b << 3) | (col0.c.b >> 2); 00404 color_array[0].a = 0xFF; 00405 00406 color_array[1].r = (col1.c.r << 3) | (col1.c.r >> 2); 00407 color_array[1].g = (col1.c.g << 2) | (col1.c.g >> 4); 00408 color_array[1].b = (col1.c.b << 3) | (col1.c.b >> 2); 00409 color_array[1].a = 0xFF; 00410 00411 if( col0.u > col1.u ) { 00412 // Four-color block: derive the other two colors. 00413 color_array[2].r = (2 * color_array[0].r + color_array[1].r) / 3; 00414 color_array[2].g = (2 * color_array[0].g + color_array[1].g) / 3; 00415 color_array[2].b = (2 * color_array[0].b + color_array[1].b) / 3; 00416 color_array[2].a = 0xFF; 00417 00418 color_array[3].r = (2 * color_array[1].r + color_array[0].r) / 3; 00419 color_array[3].g = (2 * color_array[1].g + color_array[0].g) / 3; 00420 color_array[3].b = (2 * color_array[1].b + color_array[0].b) / 3; 00421 color_array[3].a = 0xFF; 00422 } 00423 else { 00424 // Three-color block: derive the other color. 00425 color_array[2].r = (color_array[0].r + color_array[1].r) / 2; 00426 color_array[2].g = (color_array[0].g + color_array[1].g) / 2; 00427 color_array[2].b = (color_array[0].b + color_array[1].b) / 2; 00428 color_array[2].a = 0xFF; 00429 00430 // Set all components to 0 to match DXT specs. 00431 color_array[3].r = 0x00; // color_array[2].r; 00432 color_array[3].g = 0x00; // color_array[2].g; 00433 color_array[3].b = 0x00; // color_array[2].b; 00434 color_array[3].a = 0x00; 00435 } 00436 } 00437 }; 00438 00439 00440 static TQDataStream & operator>> ( TQDataStream & s, BlockDXT & c ) 00441 { 00442 return s >> c.col0 >> c.col1 >> c.row[0] >> c.row[1] >> c.row[2] >> c.row[3]; 00443 } 00444 00445 struct BlockDXTAlphaExplicit { 00446 ushort row[4]; 00447 }; 00448 00449 static TQDataStream & operator>> ( TQDataStream & s, BlockDXTAlphaExplicit & c ) 00450 { 00451 return s >> c.row[0] >> c.row[1] >> c.row[2] >> c.row[3]; 00452 } 00453 00454 struct BlockDXTAlphaLinear { 00455 uchar alpha0; 00456 uchar alpha1; 00457 uchar bits[6]; 00458 00459 void GetAlphas( uchar alpha_array[8] ) 00460 { 00461 alpha_array[0] = alpha0; 00462 alpha_array[1] = alpha1; 00463 00464 // 8-alpha or 6-alpha block? 00465 if( alpha_array[0] > alpha_array[1] ) 00466 { 00467 // 8-alpha block: derive the other 6 alphas. 00468 // 000 = alpha_0, 001 = alpha_1, others are interpolated 00469 00470 alpha_array[2] = ( 6 * alpha0 + alpha1) / 7; // bit code 010 00471 alpha_array[3] = ( 5 * alpha0 + 2 * alpha1) / 7; // Bit code 011 00472 alpha_array[4] = ( 4 * alpha0 + 3 * alpha1) / 7; // Bit code 100 00473 alpha_array[5] = ( 3 * alpha0 + 4 * alpha1) / 7; // Bit code 101 00474 alpha_array[6] = ( 2 * alpha0 + 5 * alpha1) / 7; // Bit code 110 00475 alpha_array[7] = ( alpha0 + 6 * alpha1) / 7; // Bit code 111 00476 } 00477 else 00478 { 00479 // 6-alpha block: derive the other alphas. 00480 // 000 = alpha_0, 001 = alpha_1, others are interpolated 00481 00482 alpha_array[2] = (4 * alpha0 + alpha1) / 5; // Bit code 010 00483 alpha_array[3] = (3 * alpha0 + 2 * alpha1) / 5; // Bit code 011 00484 alpha_array[4] = (2 * alpha0 + 3 * alpha1) / 5; // Bit code 100 00485 alpha_array[5] = ( alpha0 + 4 * alpha1) / 5; // Bit code 101 00486 alpha_array[6] = 0x00; // Bit code 110 00487 alpha_array[7] = 0xFF; // Bit code 111 00488 } 00489 } 00490 00491 void GetBits( uchar bit_array[16] ) 00492 { 00493 uint b = static_cast<uint>(bits[0]); 00494 bit_array[0] = uchar(b & 0x07); b >>= 3; 00495 bit_array[1] = uchar(b & 0x07); b >>= 3; 00496 bit_array[2] = uchar(b & 0x07); b >>= 3; 00497 bit_array[3] = uchar(b & 0x07); b >>= 3; 00498 bit_array[4] = uchar(b & 0x07); b >>= 3; 00499 bit_array[5] = uchar(b & 0x07); b >>= 3; 00500 bit_array[6] = uchar(b & 0x07); b >>= 3; 00501 bit_array[7] = uchar(b & 0x07); b >>= 3; 00502 00503 b = static_cast<uint>(bits[3]); 00504 bit_array[8] = uchar(b & 0x07); b >>= 3; 00505 bit_array[9] = uchar(b & 0x07); b >>= 3; 00506 bit_array[10] = uchar(b & 0x07); b >>= 3; 00507 bit_array[11] = uchar(b & 0x07); b >>= 3; 00508 bit_array[12] = uchar(b & 0x07); b >>= 3; 00509 bit_array[13] = uchar(b & 0x07); b >>= 3; 00510 bit_array[14] = uchar(b & 0x07); b >>= 3; 00511 bit_array[15] = uchar(b & 0x07); b >>= 3; 00512 } 00513 }; 00514 00515 static TQDataStream & operator>> ( TQDataStream & s, BlockDXTAlphaLinear & c ) 00516 { 00517 s >> c.alpha0 >> c.alpha1; 00518 return s >> c.bits[0] >> c.bits[1] >> c.bits[2] >> c.bits[3] >> c.bits[4] >> c.bits[5]; 00519 } 00520 00521 static bool LoadDXT1( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00522 { 00523 const uint w = header.width; 00524 const uint h = header.height; 00525 00526 BlockDXT block; 00527 QRgb * scanline[4]; 00528 00529 for( uint y = 0; y < h; y += 4 ) { 00530 for( uint j = 0; j < 4; j++ ) { 00531 scanline[j] = (QRgb *) img.scanLine( y + j ); 00532 } 00533 for( uint x = 0; x < w; x += 4 ) { 00534 00535 // Read 64bit color block. 00536 s >> block; 00537 00538 // Decode color block. 00539 Color8888 color_array[4]; 00540 block.GetColors(color_array); 00541 00542 // bit masks = 00000011, 00001100, 00110000, 11000000 00543 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 }; 00544 const int shift[4] = { 0, 2, 4, 6 }; 00545 00546 // Write color block. 00547 for( uint j = 0; j < 4; j++ ) { 00548 for( uint i = 0; i < 4; i++ ) { 00549 if( img.valid( x+i, y+j ) ) { 00550 uint idx = (block.row[j] & masks[i]) >> shift[i]; 00551 scanline[j][x+i] = tqRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a); 00552 } 00553 } 00554 } 00555 } 00556 } 00557 return true; 00558 } 00559 00560 static bool LoadDXT3( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00561 { 00562 const uint w = header.width; 00563 const uint h = header.height; 00564 00565 BlockDXT block; 00566 BlockDXTAlphaExplicit alpha; 00567 QRgb * scanline[4]; 00568 00569 for( uint y = 0; y < h; y += 4 ) { 00570 for( uint j = 0; j < 4; j++ ) { 00571 scanline[j] = (QRgb *) img.scanLine( y + j ); 00572 } 00573 for( uint x = 0; x < w; x += 4 ) { 00574 00575 // Read 128bit color block. 00576 s >> alpha; 00577 s >> block; 00578 00579 // Decode color block. 00580 Color8888 color_array[4]; 00581 block.GetColors(color_array); 00582 00583 // bit masks = 00000011, 00001100, 00110000, 11000000 00584 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 }; 00585 const int shift[4] = { 0, 2, 4, 6 }; 00586 00587 // Write color block. 00588 for( uint j = 0; j < 4; j++ ) { 00589 ushort a = alpha.row[j]; 00590 for( uint i = 0; i < 4; i++ ) { 00591 if( img.valid( x+i, y+j ) ) { 00592 uint idx = (block.row[j] & masks[i]) >> shift[i]; 00593 color_array[idx].a = a & 0x0f; 00594 color_array[idx].a = color_array[idx].a | (color_array[idx].a << 4); 00595 scanline[j][x+i] = tqRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a); 00596 } 00597 a >>= 4; 00598 } 00599 } 00600 } 00601 } 00602 return true; 00603 } 00604 00605 static bool LoadDXT2( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00606 { 00607 if( !LoadDXT3(s, header, img) ) return false; 00608 //UndoPremultiplyAlpha(img); 00609 return true; 00610 } 00611 00612 static bool LoadDXT5( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00613 { 00614 const uint w = header.width; 00615 const uint h = header.height; 00616 00617 BlockDXT block; 00618 BlockDXTAlphaLinear alpha; 00619 QRgb * scanline[4]; 00620 00621 for( uint y = 0; y < h; y += 4 ) { 00622 for( uint j = 0; j < 4; j++ ) { 00623 scanline[j] = (QRgb *) img.scanLine( y + j ); 00624 } 00625 for( uint x = 0; x < w; x += 4 ) { 00626 00627 // Read 128bit color block. 00628 s >> alpha; 00629 s >> block; 00630 00631 // Decode color block. 00632 Color8888 color_array[4]; 00633 block.GetColors(color_array); 00634 00635 uchar alpha_array[8]; 00636 alpha.GetAlphas(alpha_array); 00637 00638 uchar bit_array[16]; 00639 alpha.GetBits(bit_array); 00640 00641 // bit masks = 00000011, 00001100, 00110000, 11000000 00642 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 }; 00643 const int shift[4] = { 0, 2, 4, 6 }; 00644 00645 // Write color block. 00646 for( uint j = 0; j < 4; j++ ) { 00647 for( uint i = 0; i < 4; i++ ) { 00648 if( img.valid( x+i, y+j ) ) { 00649 uint idx = (block.row[j] & masks[i]) >> shift[i]; 00650 color_array[idx].a = alpha_array[bit_array[j*4+i]]; 00651 scanline[j][x+i] = tqRgba(color_array[idx].r, color_array[idx].g, color_array[idx].b, color_array[idx].a); 00652 } 00653 } 00654 } 00655 } 00656 } 00657 00658 return true; 00659 } 00660 static bool LoadDXT4( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00661 { 00662 if( !LoadDXT5(s, header, img) ) return false; 00663 //UndoPremultiplyAlpha(img); 00664 return true; 00665 } 00666 00667 static bool LoadRXGB( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00668 { 00669 const uint w = header.width; 00670 const uint h = header.height; 00671 00672 BlockDXT block; 00673 BlockDXTAlphaLinear alpha; 00674 QRgb * scanline[4]; 00675 00676 for( uint y = 0; y < h; y += 4 ) { 00677 for( uint j = 0; j < 4; j++ ) { 00678 scanline[j] = (QRgb *) img.scanLine( y + j ); 00679 } 00680 for( uint x = 0; x < w; x += 4 ) { 00681 00682 // Read 128bit color block. 00683 s >> alpha; 00684 s >> block; 00685 00686 // Decode color block. 00687 Color8888 color_array[4]; 00688 block.GetColors(color_array); 00689 00690 uchar alpha_array[8]; 00691 alpha.GetAlphas(alpha_array); 00692 00693 uchar bit_array[16]; 00694 alpha.GetBits(bit_array); 00695 00696 // bit masks = 00000011, 00001100, 00110000, 11000000 00697 const uint masks[4] = { 3, 3<<2, 3<<4, 3<<6 }; 00698 const int shift[4] = { 0, 2, 4, 6 }; 00699 00700 // Write color block. 00701 for( uint j = 0; j < 4; j++ ) { 00702 for( uint i = 0; i < 4; i++ ) { 00703 if( img.valid( x+i, y+j ) ) { 00704 uint idx = (block.row[j] & masks[i]) >> shift[i]; 00705 color_array[idx].a = alpha_array[bit_array[j*4+i]]; 00706 scanline[j][x+i] = tqRgb(color_array[idx].a, color_array[idx].g, color_array[idx].b); 00707 } 00708 } 00709 } 00710 } 00711 } 00712 00713 return true; 00714 } 00715 00716 static bool LoadATI2( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00717 { 00718 const uint w = header.width; 00719 const uint h = header.height; 00720 00721 BlockDXTAlphaLinear xblock; 00722 BlockDXTAlphaLinear yblock; 00723 QRgb * scanline[4]; 00724 00725 for( uint y = 0; y < h; y += 4 ) { 00726 for( uint j = 0; j < 4; j++ ) { 00727 scanline[j] = (QRgb *) img.scanLine( y + j ); 00728 } 00729 for( uint x = 0; x < w; x += 4 ) { 00730 00731 // Read 128bit color block. 00732 s >> xblock; 00733 s >> yblock; 00734 00735 // Decode color block. 00736 uchar xblock_array[8]; 00737 xblock.GetAlphas(xblock_array); 00738 00739 uchar xbit_array[16]; 00740 xblock.GetBits(xbit_array); 00741 00742 uchar yblock_array[8]; 00743 yblock.GetAlphas(yblock_array); 00744 00745 uchar ybit_array[16]; 00746 yblock.GetBits(ybit_array); 00747 00748 // Write color block. 00749 for( uint j = 0; j < 4; j++ ) { 00750 for( uint i = 0; i < 4; i++ ) { 00751 if( img.valid( x+i, y+j ) ) { 00752 const uchar nx = xblock_array[xbit_array[j*4+i]]; 00753 const uchar ny = yblock_array[ybit_array[j*4+i]]; 00754 00755 const float fx = float(nx) / 127.5f - 1.0f; 00756 const float fy = float(ny) / 127.5f - 1.0f; 00757 const float fz = sqrtf(1.0f - fx*fx - fy*fy); 00758 const uchar nz = uchar((fz + 1.0f) * 127.5f); 00759 00760 scanline[j][x+i] = tqRgb(nx, ny, nz); 00761 } 00762 } 00763 } 00764 } 00765 } 00766 00767 return true; 00768 } 00769 00770 00771 00772 typedef bool (* TextureLoader)( TQDataStream & s, const DDSHeader & header, TQImage & img ); 00773 00774 // Get an appropiate texture loader for the given type. 00775 static TextureLoader GetTextureLoader( DDSType type ) { 00776 switch( type ) { 00777 case DDS_A8R8G8B8: 00778 return LoadA8R8G8B8; 00779 case DDS_A1R5G5B5: 00780 return LoadA1R5G5B5; 00781 case DDS_A4R4G4B4: 00782 return LoadA4R4G4B4; 00783 case DDS_R8G8B8: 00784 return LoadR8G8B8; 00785 case DDS_R5G6B5: 00786 return LoadR5G6B5; 00787 case DDS_DXT1: 00788 return LoadDXT1; 00789 case DDS_DXT2: 00790 return LoadDXT2; 00791 case DDS_DXT3: 00792 return LoadDXT3; 00793 case DDS_DXT4: 00794 return LoadDXT4; 00795 case DDS_DXT5: 00796 return LoadDXT5; 00797 case DDS_RXGB: 00798 return LoadRXGB; 00799 case DDS_ATI2: 00800 return LoadATI2; 00801 default: 00802 return NULL; 00803 }; 00804 } 00805 00806 00807 // Load a 2d texture. 00808 static bool LoadTexture( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00809 { 00810 // Create dst image. 00811 if( !img.create( header.width, header.height, 32 )) { 00812 return false; 00813 } 00814 00815 // Read image. 00816 DDSType type = GetType( header ); 00817 00818 // Enable alpha buffer for transparent or DDS images. 00819 if( HasAlpha( header ) || type >= DDS_DXT1 ) { 00820 img.setAlphaBuffer( true ); 00821 } 00822 00823 TextureLoader loader = GetTextureLoader( type ); 00824 if( loader == NULL ) { 00825 return false; 00826 } 00827 00828 return loader( s, header, img ); 00829 } 00830 00831 00832 static int FaceOffset( const DDSHeader & header ) { 00833 00834 DDSType type = GetType( header ); 00835 00836 int mipmap = kMax(int(header.mipmapcount), 1); 00837 int size = 0; 00838 int w = header.width; 00839 int h = header.height; 00840 00841 if( type >= DDS_DXT1 ) { 00842 int multiplier = (type == DDS_DXT1) ? 8 : 16; 00843 do { 00844 int face_size = kMax(w/4,1) * kMax(h/4,1) * multiplier; 00845 size += face_size; 00846 w >>= 1; 00847 h >>= 1; 00848 } while( --mipmap ); 00849 } 00850 else { 00851 int multiplier = header.pf.bitcount / 8; 00852 do { 00853 int face_size = w * h * multiplier; 00854 size += face_size; 00855 w = kMax( w>>1, 1 ); 00856 h = kMax( h>>1, 1 ); 00857 } while( --mipmap ); 00858 } 00859 00860 return size; 00861 } 00862 00863 #if CUBE_LAYOUT == HORIZONTAL 00864 static int face_offset[6][2] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {3, 1} }; 00865 #elif CUBE_LAYOUT == VERTICAL 00866 static int face_offset[6][2] = { {2, 1}, {0, 1}, {1, 0}, {1, 2}, {1, 1}, {1, 3} }; 00867 #endif 00868 static int face_flags[6] = { 00869 DDSCAPS2_CUBEMAP_POSITIVEX, 00870 DDSCAPS2_CUBEMAP_NEGATIVEX, 00871 DDSCAPS2_CUBEMAP_POSITIVEY, 00872 DDSCAPS2_CUBEMAP_NEGATIVEY, 00873 DDSCAPS2_CUBEMAP_POSITIVEZ, 00874 DDSCAPS2_CUBEMAP_NEGATIVEZ 00875 }; 00876 00877 // Load unwrapped cube map. 00878 static bool LoadCubeMap( TQDataStream & s, const DDSHeader & header, TQImage & img ) 00879 { 00880 // Create dst image. 00881 #if CUBE_LAYOUT == HORIZONTAL 00882 if( !img.create( 4 * header.width, 3 * header.height, 32 )) { 00883 return false; // duplicate code for correct syntax coloring. 00884 } 00885 #elif CUBE_LAYOUT == VERTICAL 00886 if( !img.create( 3 * header.width, 4 * header.height, 32 )) { 00887 return false; 00888 } 00889 #endif 00890 00891 DDSType type = GetType( header ); 00892 00893 // Enable alpha buffer for transparent or DDS images. 00894 if( HasAlpha( header ) || type >= DDS_DXT1 ) { 00895 img.setAlphaBuffer( true ); 00896 } 00897 00898 // Select texture loader. 00899 TextureLoader loader = GetTextureLoader( type ); 00900 if( loader == NULL ) { 00901 return false; 00902 } 00903 00904 // Clear background. 00905 img.fill( 0 ); 00906 00907 // Create face image. 00908 TQImage face; 00909 if( !face.create( header.width, header.height, 32 )) { 00910 return false; 00911 } 00912 00913 int offset = s.device()->at(); 00914 int size = FaceOffset( header ); 00915 00916 for( int i = 0; i < 6; i++ ) { 00917 00918 if( !(header.caps.caps2 & face_flags[i]) ) { 00919 // Skip face. 00920 continue; 00921 } 00922 00923 // Seek device. 00924 s.device()->at( offset ); 00925 offset += size; 00926 00927 // Load face from stream. 00928 if( !loader( s, header, face ) ) { 00929 return false; 00930 } 00931 00932 #if CUBE_LAYOUT == VERTICAL 00933 if( i == 5 ) { 00934 face = face.mirror(true, true); 00935 } 00936 #endif 00937 00938 // Compute face offsets. 00939 int offset_x = face_offset[i][0] * header.width; 00940 int offset_y = face_offset[i][1] * header.height; 00941 00942 // Copy face on the image. 00943 for( uint y = 0; y < header.height; y++ ) { 00944 QRgb * src = (QRgb *) face.scanLine( y ); 00945 QRgb * dst = (QRgb *) img.scanLine( y + offset_y ) + offset_x; 00946 memcpy( dst, src, sizeof(QRgb) * header.width ); 00947 } 00948 } 00949 00950 return true; 00951 } 00952 00953 } 00954 00955 00956 KDE_EXPORT void kimgio_dds_read( TQImageIO *io ) 00957 { 00958 TQDataStream s( io->ioDevice() ); 00959 s.setByteOrder( TQDataStream::LittleEndian ); 00960 00961 // Validate header. 00962 uint fourcc; 00963 s >> fourcc; 00964 if( fourcc != FOURCC_DDS ) { 00965 kdDebug(399) << "This is not a DDS file." << endl; 00966 io->setImage( TQImage() ); 00967 io->setStatus( -1 ); 00968 return; 00969 } 00970 00971 // Read image header. 00972 DDSHeader header; 00973 s >> header; 00974 00975 // Check image file format. 00976 if( s.atEnd() || !IsValid( header ) ) { 00977 kdDebug(399) << "This DDS file is not valid." << endl; 00978 io->setImage( TQImage() ); 00979 io->setStatus( -1 ); 00980 return; 00981 } 00982 00983 // Determine image type, by now, we only support 2d textures. 00984 if( !IsSupported( header ) ) { 00985 kdDebug(399) << "This DDS file is not supported." << endl; 00986 io->setImage( TQImage() ); 00987 io->setStatus( -1 ); 00988 return; 00989 } 00990 00991 00992 TQImage img; 00993 bool result; 00994 00995 if( IsCubeMap( header ) ) { 00996 result = LoadCubeMap( s, header, img ); 00997 } 00998 else { 00999 result = LoadTexture( s, header, img ); 01000 } 01001 01002 if( result == false ) { 01003 kdDebug(399) << "Error loading DDS file." << endl; 01004 io->setImage( TQImage() ); 01005 io->setStatus( -1 ); 01006 return; 01007 } 01008 01009 io->setImage( img ); 01010 io->setStatus( 0 ); 01011 } 01012 01013 01014 KDE_EXPORT void kimgio_dds_write( TQImageIO * ) 01015 { 01016 // TODO Stub! 01017 } 01018