• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KImgIO

dds.cpp

Go to the documentation of this file.
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 <qimage.h>
00025 #include <qdatastream.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 Q_UINT32 uint;
00037 typedef Q_UINT16 ushort;
00038 typedef Q_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 QDataStream & operator>> ( QDataStream & 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 QDataStream & operator>> ( QDataStream & 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 QDataStream & operator>> ( QDataStream & 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( QDataStream & s, const DDSHeader & header, QImage & 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] = qRgba(r, g, b, a);
00302             }
00303         }
00304 
00305         return true;
00306     }
00307 
00308     static bool LoadR8G8B8( QDataStream & s, const DDSHeader & header, QImage & 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] = qRgb(r, g, b);
00319             }
00320         }
00321 
00322         return true;
00323     }
00324 
00325     static bool LoadA1R5G5B5( QDataStream & s, const DDSHeader & header, QImage & 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] = qRgba(r, g, b, a);
00340             }
00341         }
00342 
00343         return true;
00344     }
00345 
00346     static bool LoadA4R4G4B4( QDataStream & s, const DDSHeader & header, QImage & 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] = qRgba(r, g, b, a);
00361             }
00362         }
00363 
00364         return true;
00365     }
00366 
00367     static bool LoadR5G6B5( QDataStream & s, const DDSHeader & header, QImage & 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] = qRgb(r, g, b);
00381             }
00382         }
00383 
00384         return true;
00385     }
00386 
00387     static QDataStream & operator>> ( QDataStream & 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 QDataStream & operator>> ( QDataStream & 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 QDataStream & operator>> ( QDataStream & 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 = (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 = (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 QDataStream & operator>> ( QDataStream & 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( QDataStream & s, const DDSHeader & header, QImage & 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] = qRgba(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( QDataStream & s, const DDSHeader & header, QImage & 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] = qRgba(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( QDataStream & s, const DDSHeader & header, QImage & img )
00606     {
00607         if( !LoadDXT3(s, header, img) ) return false;
00608         //UndoPremultiplyAlpha(img);
00609         return true;
00610     }
00611 
00612     static bool LoadDXT5( QDataStream & s, const DDSHeader & header, QImage & 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] = qRgba(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( QDataStream & s, const DDSHeader & header, QImage & img )
00661     {
00662         if( !LoadDXT5(s, header, img) ) return false;
00663         //UndoPremultiplyAlpha(img);
00664         return true;
00665     }
00666 
00667     static bool LoadRXGB( QDataStream & s, const DDSHeader & header, QImage & 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] = qRgb(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( QDataStream & s, const DDSHeader & header, QImage & 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] = qRgb(nx, ny, nz);
00761                         }
00762                     }
00763                 }
00764             }
00765         }
00766 
00767         return true;
00768     }
00769 
00770 
00771 
00772     typedef bool (* TextureLoader)( QDataStream & s, const DDSHeader & header, QImage & 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( QDataStream & s, const DDSHeader & header, QImage & 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( QDataStream & s, const DDSHeader & header, QImage & 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         QImage 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( QImageIO *io )
00957 {
00958     QDataStream s( io->ioDevice() );
00959     s.setByteOrder( QDataStream::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( 0 );
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( 0 );
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( 0 );
00987         io->setStatus( -1 );
00988         return;
00989     }
00990 
00991 
00992     QImage 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( 0 );
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( QImageIO * )
01015 {
01016     // TODO Stub!
01017 }
01018 

KImgIO

Skip menu "KImgIO"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal