123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- #include <string.h>
- #include "squish.h"
- #include "colourset.h"
- #include "maths.h"
- #include "rangefit.h"
- #include "clusterfit.h"
- #include "colourblock.h"
- #include "alpha.h"
- #include "singlecolourfit.h"
- namespace squish {
- static int FixFlags( int flags )
- {
-
- int method = flags & ( kDxt1 | kDxt3 | kDxt5 | kBc4 | kBc5 );
- int fit = flags & ( kColourIterativeClusterFit | kColourClusterFit | kColourRangeFit );
- int extra = flags & kWeightColourByAlpha;
-
- if ( method != kDxt3
- && method != kDxt5
- && method != kBc4
- && method != kBc5 )
- {
- method = kDxt1;
- }
- if( fit != kColourRangeFit && fit != kColourIterativeClusterFit )
- fit = kColourClusterFit;
-
- return method | fit | extra;
- }
- void CompressMasked( u8 const* rgba, int mask, void* block, int flags, float* metric )
- {
-
- flags = FixFlags( flags );
- if ( ( flags & ( kBc4 | kBc5 ) ) != 0 )
- {
- u8 alpha[16*4];
- for( int i = 0; i < 16; ++i )
- {
- alpha[i*4 + 3] = rgba[i*4 + 0];
- }
- u8* rBlock = reinterpret_cast< u8* >( block );
- CompressAlphaDxt5( alpha, mask, rBlock );
- if ( ( flags & ( kBc5 ) ) != 0 )
- {
- for( int i = 0; i < 16; ++i )
- {
- alpha[i*4 + 3] = rgba[i*4 + 1];
- }
- u8* gBlock = reinterpret_cast< u8* >( block ) + 8;
- CompressAlphaDxt5( alpha, mask, gBlock );
- }
- return;
- }
-
- void* colourBlock = block;
- void* alphaBlock = block;
- if( ( flags & ( kDxt3 | kDxt5 ) ) != 0 )
- colourBlock = reinterpret_cast< u8* >( block ) + 8;
-
- ColourSet colours( rgba, mask, flags );
-
- if( colours.GetCount() == 1 )
- {
-
- SingleColourFit fit( &colours, flags );
- fit.Compress( colourBlock );
- }
- else if( ( flags & kColourRangeFit ) != 0 || colours.GetCount() == 0 )
- {
-
- RangeFit fit( &colours, flags, metric );
- fit.Compress( colourBlock );
- }
- else
- {
-
- ClusterFit fit( &colours, flags, metric );
- fit.Compress( colourBlock );
- }
-
- if( ( flags & kDxt3 ) != 0 )
- CompressAlphaDxt3( rgba, mask, alphaBlock );
- else if( ( flags & kDxt5 ) != 0 )
- CompressAlphaDxt5( rgba, mask, alphaBlock );
- }
- void Decompress( u8* rgba, void const* block, int flags )
- {
-
- flags = FixFlags( flags );
-
- void const* colourBlock = block;
- void const* alphaBlock = block;
- if( ( flags & ( kDxt3 | kDxt5 ) ) != 0 )
- colourBlock = reinterpret_cast< u8 const* >( block ) + 8;
-
-
-
- if(( flags & ( kBc5 ) ) != 0)
- DecompressColourBc5( rgba, colourBlock);
- else
- DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 );
-
-
- if( ( flags & kDxt3 ) != 0 )
- DecompressAlphaDxt3( rgba, alphaBlock );
- else if( ( flags & kDxt5 ) != 0 )
- DecompressAlphaDxt5( rgba, alphaBlock );
- }
- int GetStorageRequirements( int width, int height, int flags )
- {
-
- flags = FixFlags( flags );
-
- int blockcount = ( ( width + 3 )/4 ) * ( ( height + 3 )/4 );
- int blocksize = ( ( flags & ( kDxt1 | kBc4 ) ) != 0 ) ? 8 : 16;
- return blockcount*blocksize;
- }
- void CopyRGBA( u8 const* source, u8* dest, int flags )
- {
- if (flags & kSourceBGRA)
- {
-
- dest[0] = source[2];
- dest[1] = source[1];
- dest[2] = source[0];
- dest[3] = source[3];
- }
- else
- {
- for( int i = 0; i < 4; ++i )
- *dest++ = *source++;
- }
- }
- void CompressImage( u8 const* rgba, int width, int height, int pitch, void* blocks, int flags, float* metric )
- {
-
- flags = FixFlags( flags );
-
- #ifdef SQUISH_USE_OPENMP
- # pragma omp parallel for
- #endif
- for( int y = 0; y < height; y += 4 )
- {
-
- u8* targetBlock = reinterpret_cast< u8* >( blocks );
- int bytesPerBlock = ( ( flags & ( kDxt1 | kBc4 ) ) != 0 ) ? 8 : 16;
- targetBlock += ( (y / 4) * ( (width + 3) / 4) ) * bytesPerBlock;
- for( int x = 0; x < width; x += 4 )
- {
-
- u8 sourceRgba[16*4];
- u8* targetPixel = sourceRgba;
- int mask = 0;
- for( int py = 0; py < 4; ++py )
- {
- for( int px = 0; px < 4; ++px )
- {
-
- int sx = x + px;
- int sy = y + py;
-
- if( sx < width && sy < height )
- {
-
- u8 const* sourcePixel = rgba + pitch*sy + 4*sx;
- CopyRGBA(sourcePixel, targetPixel, flags);
-
- mask |= ( 1 << ( 4*py + px ) );
- }
-
- targetPixel += 4;
- }
- }
-
- CompressMasked( sourceRgba, mask, targetBlock, flags, metric );
-
- targetBlock += bytesPerBlock;
- }
- }
- }
- void CompressImage( u8 const* rgba, int width, int height, void* blocks, int flags, float* metric )
- {
- CompressImage(rgba, width, height, width*4, blocks, flags, metric);
- }
- void DecompressImage( u8* rgba, int width, int height, int pitch, void const* blocks, int flags )
- {
-
- flags = FixFlags( flags );
-
- #ifdef SQUISH_USE_OPENMP
- # pragma omp parallel for
- #endif
- for( int y = 0; y < height; y += 4 )
- {
-
- u8 const* sourceBlock = reinterpret_cast< u8 const* >( blocks );
- int bytesPerBlock = ( ( flags & ( kDxt1 | kBc4 ) ) != 0 ) ? 8 : 16;
- sourceBlock += ( (y / 4) * ( (width + 3) / 4) ) * bytesPerBlock;
- for( int x = 0; x < width; x += 4 )
- {
-
- u8 targetRgba[4*16];
- Decompress( targetRgba, sourceBlock, flags );
-
- u8 const* sourcePixel = targetRgba;
- for( int py = 0; py < 4; ++py )
- {
- for( int px = 0; px < 4; ++px )
- {
-
- int sx = x + px;
- int sy = y + py;
-
- if( sx < width && sy < height )
- {
-
- u8* targetPixel = rgba + pitch*sy + 4*sx;
- CopyRGBA(sourcePixel, targetPixel, flags);
- }
-
- sourcePixel += 4;
- }
- }
-
- sourceBlock += bytesPerBlock;
- }
- }
- }
- void DecompressImage( u8* rgba, int width, int height, void const* blocks, int flags )
- {
- DecompressImage( rgba, width, height, width*4, blocks, flags );
- }
- static double ErrorSq(double x, double y)
- {
- return (x - y) * (x - y);
- }
- static void ComputeBlockWMSE(u8 const *original, u8 const *compressed, unsigned int w, unsigned int h, double &cmse, double &amse)
- {
-
-
-
-
-
-
-
-
- cmse = amse = 0;
- unsigned int sum_p[4];
- unsigned int sum_p2[4];
- memset(sum_p, 0, sizeof(sum_p));
- memset(sum_p2, 0, sizeof(sum_p2));
- for( unsigned int py = 0; py < 4; ++py )
- {
- for( unsigned int px = 0; px < 4; ++px )
- {
- if( px < w && py < h )
- {
- double pixelCMSE = 0;
- for( int i = 0; i < 3; ++i )
- {
- pixelCMSE += ErrorSq(original[i], compressed[i]);
- sum_p[i] += original[i];
- sum_p2[i] += (unsigned int)original[i]*original[i];
- }
- if( original[3] == 0 && compressed[3] == 0 )
- pixelCMSE = 0;
- amse += ErrorSq(original[3], compressed[3]);
- cmse += pixelCMSE;
- sum_p[3] += original[3];
- sum_p2[3] += (unsigned int)original[3]*original[3];
- }
- original += 4;
- compressed += 4;
- }
- }
- unsigned int variance = 0;
- for( int i = 0; i < 4; ++i )
- variance += w*h*sum_p2[i] - sum_p[i]*sum_p[i];
- if( variance < 4 * w * w * h * h )
- {
- amse *= 5;
- cmse *= 5;
- }
- }
- void ComputeMSE( u8 const *rgba, int width, int height, int pitch, u8 const *dxt, int flags, double &colourMSE, double &alphaMSE )
- {
-
- flags = FixFlags( flags );
- colourMSE = alphaMSE = 0;
-
- squish::u8 const* sourceBlock = dxt;
- int bytesPerBlock = ( ( flags & squish::kDxt1 ) != 0 ) ? 8 : 16;
-
- for( int y = 0; y < height; y += 4 )
- {
- for( int x = 0; x < width; x += 4 )
- {
-
- u8 targetRgba[4*16];
- Decompress( targetRgba, sourceBlock, flags );
- u8 const* sourcePixel = targetRgba;
-
- u8 originalRgba[4*16];
- u8* originalPixel = originalRgba;
- for( int py = 0; py < 4; ++py )
- {
- for( int px = 0; px < 4; ++px )
- {
- int sx = x + px;
- int sy = y + py;
- if( sx < width && sy < height )
- {
- u8 const* targetPixel = rgba + pitch*sy + 4*sx;
- CopyRGBA(targetPixel, originalPixel, flags);
- }
- sourcePixel += 4;
- originalPixel += 4;
- }
- }
-
- double blockCMSE, blockAMSE;
- ComputeBlockWMSE(originalRgba, targetRgba, std::min(4, width - x), std::min(4, height - y), blockCMSE, blockAMSE);
- colourMSE += blockCMSE;
- alphaMSE += blockAMSE;
-
- sourceBlock += bytesPerBlock;
- }
- }
- colourMSE /= (width * height * 3);
- alphaMSE /= (width * height);
- }
- void ComputeMSE( u8 const *rgba, int width, int height, u8 const *dxt, int flags, double &colourMSE, double &alphaMSE )
- {
- ComputeMSE(rgba, width, height, width*4, dxt, flags, colourMSE, alphaMSE);
- }
- }
|