alpha.cpp0000644000076500000240000002252612771161730012401 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #include "alpha.h" #include #include namespace squish { static int FloatToInt( float a, int limit ) { // use ANSI round-to-zero behaviour to get round-to-nearest int i = ( int )( a + 0.5f ); // clamp to the limit if( i < 0 ) i = 0; else if( i > limit ) i = limit; // done return i; } void CompressAlphaDxt3( u8 const* rgba, int mask, void* block ) { u8* bytes = reinterpret_cast< u8* >( block ); // quantise and pack the alpha values pairwise for( int i = 0; i < 8; ++i ) { // quantise down to 4 bits float alpha1 = ( float )rgba[8*i + 3] * ( 15.0f/255.0f ); float alpha2 = ( float )rgba[8*i + 7] * ( 15.0f/255.0f ); int quant1 = FloatToInt( alpha1, 15 ); int quant2 = FloatToInt( alpha2, 15 ); // set alpha to zero where masked int bit1 = 1 << ( 2*i ); int bit2 = 1 << ( 2*i + 1 ); if( ( mask & bit1 ) == 0 ) quant1 = 0; if( ( mask & bit2 ) == 0 ) quant2 = 0; // pack into the byte bytes[i] = ( u8 )( quant1 | ( quant2 << 4 ) ); } } void DecompressAlphaDxt3( u8* rgba, void const* block ) { u8 const* bytes = reinterpret_cast< u8 const* >( block ); // unpack the alpha values pairwise for( int i = 0; i < 8; ++i ) { // quantise down to 4 bits u8 quant = bytes[i]; // unpack the values u8 lo = quant & 0x0f; u8 hi = quant & 0xf0; // convert back up to bytes rgba[8*i + 3] = lo | ( lo << 4 ); rgba[8*i + 7] = hi | ( hi >> 4 ); } } static void FixRange( int& min, int& max, int steps ) { if( max - min < steps ) max = std::min( min + steps, 255 ); if( max - min < steps ) min = std::max( 0, max - steps ); } static int FitCodes( u8 const* rgba, int mask, u8 const* codes, u8* indices ) { // fit each alpha value to the codebook int err = 0; for( int i = 0; i < 16; ++i ) { // check this pixel is valid int bit = 1 << i; if( ( mask & bit ) == 0 ) { // use the first code indices[i] = 0; continue; } // find the least error and corresponding index int value = rgba[4*i + 3]; int least = INT_MAX; int index = 0; for( int j = 0; j < 8; ++j ) { // get the squared error from this code int dist = ( int )value - ( int )codes[j]; dist *= dist; // compare with the best so far if( dist < least ) { least = dist; index = j; } } // save this index and accumulate the error indices[i] = ( u8 )index; err += least; } // return the total error return err; } static void WriteAlphaBlock( int alpha0, int alpha1, u8 const* indices, void* block ) { u8* bytes = reinterpret_cast< u8* >( block ); // write the first two bytes bytes[0] = ( u8 )alpha0; bytes[1] = ( u8 )alpha1; // pack the indices with 3 bits each u8* dest = bytes + 2; u8 const* src = indices; for( int i = 0; i < 2; ++i ) { // pack 8 3-bit values int value = 0; for( int j = 0; j < 8; ++j ) { int index = *src++; value |= ( index << 3*j ); } // store in 3 bytes for( int j = 0; j < 3; ++j ) { int byte = ( value >> 8*j ) & 0xff; *dest++ = ( u8 )byte; } } } static void WriteAlphaBlock5( int alpha0, int alpha1, u8 const* indices, void* block ) { // check the relative values of the endpoints if( alpha0 > alpha1 ) { // swap the indices u8 swapped[16]; for( int i = 0; i < 16; ++i ) { u8 index = indices[i]; if( index == 0 ) swapped[i] = 1; else if( index == 1 ) swapped[i] = 0; else if( index <= 5 ) swapped[i] = 7 - index; else swapped[i] = index; } // write the block WriteAlphaBlock( alpha1, alpha0, swapped, block ); } else { // write the block WriteAlphaBlock( alpha0, alpha1, indices, block ); } } static void WriteAlphaBlock7( int alpha0, int alpha1, u8 const* indices, void* block ) { // check the relative values of the endpoints if( alpha0 < alpha1 ) { // swap the indices u8 swapped[16]; for( int i = 0; i < 16; ++i ) { u8 index = indices[i]; if( index == 0 ) swapped[i] = 1; else if( index == 1 ) swapped[i] = 0; else swapped[i] = 9 - index; } // write the block WriteAlphaBlock( alpha1, alpha0, swapped, block ); } else { // write the block WriteAlphaBlock( alpha0, alpha1, indices, block ); } } void CompressAlphaDxt5( u8 const* rgba, int mask, void* block ) { // get the range for 5-alpha and 7-alpha interpolation int min5 = 255; int max5 = 0; int min7 = 255; int max7 = 0; for( int i = 0; i < 16; ++i ) { // check this pixel is valid int bit = 1 << i; if( ( mask & bit ) == 0 ) continue; // incorporate into the min/max int value = rgba[4*i + 3]; if( value < min7 ) min7 = value; if( value > max7 ) max7 = value; if( value != 0 && value < min5 ) min5 = value; if( value != 255 && value > max5 ) max5 = value; } // handle the case that no valid range was found if( min5 > max5 ) min5 = max5; if( min7 > max7 ) min7 = max7; // fix the range to be the minimum in each case FixRange( min5, max5, 5 ); FixRange( min7, max7, 7 ); // set up the 5-alpha code book u8 codes5[8]; codes5[0] = ( u8 )min5; codes5[1] = ( u8 )max5; for( int i = 1; i < 5; ++i ) codes5[1 + i] = ( u8 )( ( ( 5 - i )*min5 + i*max5 )/5 ); codes5[6] = 0; codes5[7] = 255; // set up the 7-alpha code book u8 codes7[8]; codes7[0] = ( u8 )min7; codes7[1] = ( u8 )max7; for( int i = 1; i < 7; ++i ) codes7[1 + i] = ( u8 )( ( ( 7 - i )*min7 + i*max7 )/7 ); // fit the data to both code books u8 indices5[16]; u8 indices7[16]; int err5 = FitCodes( rgba, mask, codes5, indices5 ); int err7 = FitCodes( rgba, mask, codes7, indices7 ); // save the block with least error if( err5 <= err7 ) WriteAlphaBlock5( min5, max5, indices5, block ); else WriteAlphaBlock7( min7, max7, indices7, block ); } void DecompressAlphaDxt5( u8* rgba, void const* block ) { // get the two alpha values u8 const* bytes = reinterpret_cast< u8 const* >( block ); int alpha0 = bytes[0]; int alpha1 = bytes[1]; // compare the values to build the codebook u8 codes[8]; codes[0] = ( u8 )alpha0; codes[1] = ( u8 )alpha1; if( alpha0 <= alpha1 ) { // use 5-alpha codebook for( int i = 1; i < 5; ++i ) codes[1 + i] = ( u8 )( ( ( 5 - i )*alpha0 + i*alpha1 )/5 ); codes[6] = 0; codes[7] = 255; } else { // use 7-alpha codebook for( int i = 1; i < 7; ++i ) codes[1 + i] = ( u8 )( ( ( 7 - i )*alpha0 + i*alpha1 )/7 ); } // decode the indices u8 indices[16]; u8 const* src = bytes + 2; u8* dest = indices; for( int i = 0; i < 2; ++i ) { // grab 3 bytes int value = 0; for( int j = 0; j < 3; ++j ) { int byte = *src++; value |= ( byte << 8*j ); } // unpack 8 3-bit values from it for( int j = 0; j < 8; ++j ) { int index = ( value >> 3*j ) & 0x7; *dest++ = ( u8 )index; } } // write out the indexed codebook values for( int i = 0; i < 16; ++i ) rgba[4*i + 3] = codes[indices[i]]; } } // namespace squish clusterfit.cpp0000644000076500000240000003412512771161730013476 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Copyright (c) 2007 Ignacio Castano icastano@nvidia.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #include "clusterfit.h" #include "colourset.h" #include "colourblock.h" #include namespace squish { ClusterFit::ClusterFit( ColourSet const* colours, int flags, float* metric ) : ColourFit( colours, flags ) { // set the iteration count m_iterationCount = ( m_flags & kColourIterativeClusterFit ) ? kMaxIterations : 1; // initialise the metric (old perceptual = 0.2126f, 0.7152f, 0.0722f) if( metric ) m_metric = Vec4( metric[0], metric[1], metric[2], 1.0f ); else m_metric = VEC4_CONST( 1.0f ); // initialise the best error m_besterror = VEC4_CONST( FLT_MAX ); // cache some values int const count = m_colours->GetCount(); Vec3 const* values = m_colours->GetPoints(); // get the covariance matrix Sym3x3 covariance = ComputeWeightedCovariance( count, values, m_colours->GetWeights() ); // compute the principle component m_principle = ComputePrincipleComponent( covariance ); } bool ClusterFit::ConstructOrdering( Vec3 const& axis, int iteration ) { // cache some values int const count = m_colours->GetCount(); Vec3 const* values = m_colours->GetPoints(); // build the list of dot products float dps[16]; u8* order = ( u8* )m_order + 16*iteration; for( int i = 0; i < count; ++i ) { dps[i] = Dot( values[i], axis ); order[i] = ( u8 )i; } // stable sort using them for( int i = 0; i < count; ++i ) { for( int j = i; j > 0 && dps[j] < dps[j - 1]; --j ) { std::swap( dps[j], dps[j - 1] ); std::swap( order[j], order[j - 1] ); } } // check this ordering is unique for( int it = 0; it < iteration; ++it ) { u8 const* prev = ( u8* )m_order + 16*it; bool same = true; for( int i = 0; i < count; ++i ) { if( order[i] != prev[i] ) { same = false; break; } } if( same ) return false; } // copy the ordering and weight all the points Vec3 const* unweighted = m_colours->GetPoints(); float const* weights = m_colours->GetWeights(); m_xsum_wsum = VEC4_CONST( 0.0f ); for( int i = 0; i < count; ++i ) { int j = order[i]; Vec4 p( unweighted[j].X(), unweighted[j].Y(), unweighted[j].Z(), 1.0f ); Vec4 w( weights[j] ); Vec4 x = p*w; m_points_weights[i] = x; m_xsum_wsum += x; } return true; } void ClusterFit::Compress3( void* block ) { // declare variables int const count = m_colours->GetCount(); Vec4 const two = VEC4_CONST( 2.0 ); Vec4 const one = VEC4_CONST( 1.0f ); Vec4 const half_half2( 0.5f, 0.5f, 0.5f, 0.25f ); Vec4 const zero = VEC4_CONST( 0.0f ); Vec4 const half = VEC4_CONST( 0.5f ); Vec4 const grid( 31.0f, 63.0f, 31.0f, 0.0f ); Vec4 const gridrcp( 1.0f/31.0f, 1.0f/63.0f, 1.0f/31.0f, 0.0f ); // prepare an ordering using the principle axis ConstructOrdering( m_principle, 0 ); // check all possible clusters and iterate on the total order Vec4 beststart = VEC4_CONST( 0.0f ); Vec4 bestend = VEC4_CONST( 0.0f ); Vec4 besterror = m_besterror; u8 bestindices[16]; int bestiteration = 0; int besti = 0, bestj = 0; // loop over iterations (we avoid the case that all points in first or last cluster) for( int iterationIndex = 0;; ) { // first cluster [0,i) is at the start Vec4 part0 = VEC4_CONST( 0.0f ); for( int i = 0; i < count; ++i ) { // second cluster [i,j) is half along Vec4 part1 = ( i == 0 ) ? m_points_weights[0] : VEC4_CONST( 0.0f ); int jmin = ( i == 0 ) ? 1 : i; for( int j = jmin;; ) { // last cluster [j,count) is at the end Vec4 part2 = m_xsum_wsum - part1 - part0; // compute least squares terms directly Vec4 alphax_sum = MultiplyAdd( part1, half_half2, part0 ); Vec4 alpha2_sum = alphax_sum.SplatW(); Vec4 betax_sum = MultiplyAdd( part1, half_half2, part2 ); Vec4 beta2_sum = betax_sum.SplatW(); Vec4 alphabeta_sum = ( part1*half_half2 ).SplatW(); // compute the least-squares optimal points Vec4 factor = Reciprocal( NegativeMultiplySubtract( alphabeta_sum, alphabeta_sum, alpha2_sum*beta2_sum ) ); Vec4 a = NegativeMultiplySubtract( betax_sum, alphabeta_sum, alphax_sum*beta2_sum )*factor; Vec4 b = NegativeMultiplySubtract( alphax_sum, alphabeta_sum, betax_sum*alpha2_sum )*factor; // clamp to the grid a = Min( one, Max( zero, a ) ); b = Min( one, Max( zero, b ) ); a = Truncate( MultiplyAdd( grid, a, half ) )*gridrcp; b = Truncate( MultiplyAdd( grid, b, half ) )*gridrcp; // compute the error (we skip the constant xxsum) Vec4 e1 = MultiplyAdd( a*a, alpha2_sum, b*b*beta2_sum ); Vec4 e2 = NegativeMultiplySubtract( a, alphax_sum, a*b*alphabeta_sum ); Vec4 e3 = NegativeMultiplySubtract( b, betax_sum, e2 ); Vec4 e4 = MultiplyAdd( two, e3, e1 ); // apply the metric to the error term Vec4 e5 = e4*m_metric; Vec4 error = e5.SplatX() + e5.SplatY() + e5.SplatZ(); // keep the solution if it wins if( CompareAnyLessThan( error, besterror ) ) { beststart = a; bestend = b; besti = i; bestj = j; besterror = error; bestiteration = iterationIndex; } // advance if( j == count ) break; part1 += m_points_weights[j]; ++j; } // advance part0 += m_points_weights[i]; } // stop if we didn't improve in this iteration if( bestiteration != iterationIndex ) break; // advance if possible ++iterationIndex; if( iterationIndex == m_iterationCount ) break; // stop if a new iteration is an ordering that has already been tried Vec3 axis = ( bestend - beststart ).GetVec3(); if( !ConstructOrdering( axis, iterationIndex ) ) break; } // save the block if necessary if( CompareAnyLessThan( besterror, m_besterror ) ) { // remap the indices u8 const* order = ( u8* )m_order + 16*bestiteration; u8 unordered[16]; for( int m = 0; m < besti; ++m ) unordered[order[m]] = 0; for( int m = besti; m < bestj; ++m ) unordered[order[m]] = 2; for( int m = bestj; m < count; ++m ) unordered[order[m]] = 1; m_colours->RemapIndices( unordered, bestindices ); // save the block WriteColourBlock3( beststart.GetVec3(), bestend.GetVec3(), bestindices, block ); // save the error m_besterror = besterror; } } void ClusterFit::Compress4( void* block ) { // declare variables int const count = m_colours->GetCount(); Vec4 const two = VEC4_CONST( 2.0f ); Vec4 const one = VEC4_CONST( 1.0f ); Vec4 const onethird_onethird2( 1.0f/3.0f, 1.0f/3.0f, 1.0f/3.0f, 1.0f/9.0f ); Vec4 const twothirds_twothirds2( 2.0f/3.0f, 2.0f/3.0f, 2.0f/3.0f, 4.0f/9.0f ); Vec4 const twonineths = VEC4_CONST( 2.0f/9.0f ); Vec4 const zero = VEC4_CONST( 0.0f ); Vec4 const half = VEC4_CONST( 0.5f ); Vec4 const grid( 31.0f, 63.0f, 31.0f, 0.0f ); Vec4 const gridrcp( 1.0f/31.0f, 1.0f/63.0f, 1.0f/31.0f, 0.0f ); // prepare an ordering using the principle axis ConstructOrdering( m_principle, 0 ); // check all possible clusters and iterate on the total order Vec4 beststart = VEC4_CONST( 0.0f ); Vec4 bestend = VEC4_CONST( 0.0f ); Vec4 besterror = m_besterror; u8 bestindices[16]; int bestiteration = 0; int besti = 0, bestj = 0, bestk = 0; // loop over iterations (we avoid the case that all points in first or last cluster) for( int iterationIndex = 0;; ) { // first cluster [0,i) is at the start Vec4 part0 = VEC4_CONST( 0.0f ); for( int i = 0; i < count; ++i ) { // second cluster [i,j) is one third along Vec4 part1 = VEC4_CONST( 0.0f ); for( int j = i;; ) { // third cluster [j,k) is two thirds along Vec4 part2 = ( j == 0 ) ? m_points_weights[0] : VEC4_CONST( 0.0f ); int kmin = ( j == 0 ) ? 1 : j; for( int k = kmin;; ) { // last cluster [k,count) is at the end Vec4 part3 = m_xsum_wsum - part2 - part1 - part0; // compute least squares terms directly Vec4 const alphax_sum = MultiplyAdd( part2, onethird_onethird2, MultiplyAdd( part1, twothirds_twothirds2, part0 ) ); Vec4 const alpha2_sum = alphax_sum.SplatW(); Vec4 const betax_sum = MultiplyAdd( part1, onethird_onethird2, MultiplyAdd( part2, twothirds_twothirds2, part3 ) ); Vec4 const beta2_sum = betax_sum.SplatW(); Vec4 const alphabeta_sum = twonineths*( part1 + part2 ).SplatW(); // compute the least-squares optimal points Vec4 factor = Reciprocal( NegativeMultiplySubtract( alphabeta_sum, alphabeta_sum, alpha2_sum*beta2_sum ) ); Vec4 a = NegativeMultiplySubtract( betax_sum, alphabeta_sum, alphax_sum*beta2_sum )*factor; Vec4 b = NegativeMultiplySubtract( alphax_sum, alphabeta_sum, betax_sum*alpha2_sum )*factor; // clamp to the grid a = Min( one, Max( zero, a ) ); b = Min( one, Max( zero, b ) ); a = Truncate( MultiplyAdd( grid, a, half ) )*gridrcp; b = Truncate( MultiplyAdd( grid, b, half ) )*gridrcp; // compute the error (we skip the constant xxsum) Vec4 e1 = MultiplyAdd( a*a, alpha2_sum, b*b*beta2_sum ); Vec4 e2 = NegativeMultiplySubtract( a, alphax_sum, a*b*alphabeta_sum ); Vec4 e3 = NegativeMultiplySubtract( b, betax_sum, e2 ); Vec4 e4 = MultiplyAdd( two, e3, e1 ); // apply the metric to the error term Vec4 e5 = e4*m_metric; Vec4 error = e5.SplatX() + e5.SplatY() + e5.SplatZ(); // keep the solution if it wins if( CompareAnyLessThan( error, besterror ) ) { beststart = a; bestend = b; besterror = error; besti = i; bestj = j; bestk = k; bestiteration = iterationIndex; } // advance if( k == count ) break; part2 += m_points_weights[k]; ++k; } // advance if( j == count ) break; part1 += m_points_weights[j]; ++j; } // advance part0 += m_points_weights[i]; } // stop if we didn't improve in this iteration if( bestiteration != iterationIndex ) break; // advance if possible ++iterationIndex; if( iterationIndex == m_iterationCount ) break; // stop if a new iteration is an ordering that has already been tried Vec3 axis = ( bestend - beststart ).GetVec3(); if( !ConstructOrdering( axis, iterationIndex ) ) break; } // save the block if necessary if( CompareAnyLessThan( besterror, m_besterror ) ) { // remap the indices u8 const* order = ( u8* )m_order + 16*bestiteration; u8 unordered[16]; for( int m = 0; m < besti; ++m ) unordered[order[m]] = 0; for( int m = besti; m < bestj; ++m ) unordered[order[m]] = 2; for( int m = bestj; m < bestk; ++m ) unordered[order[m]] = 3; for( int m = bestk; m < count; ++m ) unordered[order[m]] = 1; m_colours->RemapIndices( unordered, bestindices ); // save the block WriteColourBlock4( beststart.GetVec3(), bestend.GetVec3(), bestindices, block ); // save the error m_besterror = besterror; } } } // namespace squish colourblock.cpp0000644000076500000240000001336412771161730013632 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #include "colourblock.h" namespace squish { static int FloatToInt( float a, int limit ) { // use ANSI round-to-zero behaviour to get round-to-nearest int i = ( int )( a + 0.5f ); // clamp to the limit if( i < 0 ) i = 0; else if( i > limit ) i = limit; // done return i; } static int FloatTo565( Vec3::Arg colour ) { // get the components in the correct range int r = FloatToInt( 31.0f*colour.X(), 31 ); int g = FloatToInt( 63.0f*colour.Y(), 63 ); int b = FloatToInt( 31.0f*colour.Z(), 31 ); // pack into a single value return ( r << 11 ) | ( g << 5 ) | b; } static void WriteColourBlock( int a, int b, u8* indices, void* block ) { // get the block as bytes u8* bytes = ( u8* )block; // write the endpoints bytes[0] = ( u8 )( a & 0xff ); bytes[1] = ( u8 )( a >> 8 ); bytes[2] = ( u8 )( b & 0xff ); bytes[3] = ( u8 )( b >> 8 ); // write the indices for( int i = 0; i < 4; ++i ) { u8 const* ind = indices + 4*i; bytes[4 + i] = ind[0] | ( ind[1] << 2 ) | ( ind[2] << 4 ) | ( ind[3] << 6 ); } } void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ) { // get the packed values int a = FloatTo565( start ); int b = FloatTo565( end ); // remap the indices u8 remapped[16]; if( a <= b ) { // use the indices directly for( int i = 0; i < 16; ++i ) remapped[i] = indices[i]; } else { // swap a and b std::swap( a, b ); for( int i = 0; i < 16; ++i ) { if( indices[i] == 0 ) remapped[i] = 1; else if( indices[i] == 1 ) remapped[i] = 0; else remapped[i] = indices[i]; } } // write the block WriteColourBlock( a, b, remapped, block ); } void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ) { // get the packed values int a = FloatTo565( start ); int b = FloatTo565( end ); // remap the indices u8 remapped[16]; if( a < b ) { // swap a and b std::swap( a, b ); for( int i = 0; i < 16; ++i ) remapped[i] = ( indices[i] ^ 0x1 ) & 0x3; } else if( a == b ) { // use index 0 for( int i = 0; i < 16; ++i ) remapped[i] = 0; } else { // use the indices directly for( int i = 0; i < 16; ++i ) remapped[i] = indices[i]; } // write the block WriteColourBlock( a, b, remapped, block ); } static int Unpack565( u8 const* packed, u8* colour ) { // build the packed value int value = ( int )packed[0] | ( ( int )packed[1] << 8 ); // get the components in the stored range u8 red = ( u8 )( ( value >> 11 ) & 0x1f ); u8 green = ( u8 )( ( value >> 5 ) & 0x3f ); u8 blue = ( u8 )( value & 0x1f ); // scale up to 8 bits colour[0] = ( red << 3 ) | ( red >> 2 ); colour[1] = ( green << 2 ) | ( green >> 4 ); colour[2] = ( blue << 3 ) | ( blue >> 2 ); colour[3] = 255; // return the value return value; } void DecompressColour( u8* rgba, void const* block, bool isDxt1 ) { // get the block bytes u8 const* bytes = reinterpret_cast< u8 const* >( block ); // unpack the endpoints u8 codes[16]; int a = Unpack565( bytes, codes ); int b = Unpack565( bytes + 2, codes + 4 ); // generate the midpoints for( int i = 0; i < 3; ++i ) { int c = codes[i]; int d = codes[4 + i]; if( isDxt1 && a <= b ) { codes[8 + i] = ( u8 )( ( c + d )/2 ); codes[12 + i] = 0; } else { codes[8 + i] = ( u8 )( ( 2*c + d )/3 ); codes[12 + i] = ( u8 )( ( c + 2*d )/3 ); } } // fill in alpha for the intermediate values codes[8 + 3] = 255; codes[12 + 3] = ( isDxt1 && a <= b ) ? 0 : 255; // unpack the indices u8 indices[16]; for( int i = 0; i < 4; ++i ) { u8* ind = indices + 4*i; u8 packed = bytes[4 + i]; ind[0] = packed & 0x3; ind[1] = ( packed >> 2 ) & 0x3; ind[2] = ( packed >> 4 ) & 0x3; ind[3] = ( packed >> 6 ) & 0x3; } // store out the colours for( int i = 0; i < 16; ++i ) { u8 offset = 4*indices[i]; for( int j = 0; j < 4; ++j ) rgba[4*i + j] = codes[offset + j]; } } } // namespace squish colourfit.cpp0000644000076500000240000000343512771161730013320 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #include "colourfit.h" #include "colourset.h" namespace squish { ColourFit::ColourFit( ColourSet const* colours, int flags ) : m_colours( colours ), m_flags( flags ) { } ColourFit::~ColourFit() { } void ColourFit::Compress( void* block ) { bool isDxt1 = ( ( m_flags & kDxt1 ) != 0 ); if( isDxt1 ) { Compress3( block ); if( !m_colours->IsTransparent() ) Compress4( block ); } else Compress4( block ); } } // namespace squish colourset.cpp0000644000076500000240000001001512771161730013321 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #include "colourset.h" namespace squish { ColourSet::ColourSet( u8 const* rgba, int mask, int flags ) : m_count( 0 ), m_transparent( false ) { // check the compression mode for dxt1 bool isDxt1 = ( ( flags & kDxt1 ) != 0 ); bool weightByAlpha = ( ( flags & kWeightColourByAlpha ) != 0 ); // create the minimal set for( int i = 0; i < 16; ++i ) { // check this pixel is enabled int bit = 1 << i; if( ( mask & bit ) == 0 ) { m_remap[i] = -1; continue; } // check for transparent pixels when using dxt1 if( isDxt1 && rgba[4*i + 3] < 128 ) { m_remap[i] = -1; m_transparent = true; continue; } // loop over previous points for a match for( int j = 0;; ++j ) { // allocate a new point if( j == i ) { // normalise coordinates to [0,1] float x = ( float )rgba[4*i] / 255.0f; float y = ( float )rgba[4*i + 1] / 255.0f; float z = ( float )rgba[4*i + 2] / 255.0f; // ensure there is always non-zero weight even for zero alpha float w = ( float )( rgba[4*i + 3] + 1 ) / 256.0f; // add the point m_points[m_count] = Vec3( x, y, z ); m_weights[m_count] = ( weightByAlpha ? w : 1.0f ); m_remap[i] = m_count; // advance ++m_count; break; } // check for a match int oldbit = 1 << j; bool match = ( ( mask & oldbit ) != 0 ) && ( rgba[4*i] == rgba[4*j] ) && ( rgba[4*i + 1] == rgba[4*j + 1] ) && ( rgba[4*i + 2] == rgba[4*j + 2] ) && ( rgba[4*j + 3] >= 128 || !isDxt1 ); if( match ) { // get the index of the match int index = m_remap[j]; // ensure there is always non-zero weight even for zero alpha float w = ( float )( rgba[4*i + 3] + 1 ) / 256.0f; // map to this point and increase the weight m_weights[index] += ( weightByAlpha ? w : 1.0f ); m_remap[i] = index; break; } } } // square root the weights for( int i = 0; i < m_count; ++i ) m_weights[i] = std::sqrt( m_weights[i] ); } void ColourSet::RemapIndices( u8 const* source, u8* target ) const { for( int i = 0; i < 16; ++i ) { int j = m_remap[i]; if( j == -1 ) target[i] = 3; else target[i] = source[j]; } } } // namespace squish maths.cpp0000644000076500000240000001607612771161730012433 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ /*! @file The symmetric eigensystem solver algorithm is from http://www.geometrictools.com/Documentation/EigenSymmetric3x3.pdf */ #include "maths.h" #include "simd.h" #include namespace squish { Sym3x3 ComputeWeightedCovariance( int n, Vec3 const* points, float const* weights ) { // compute the centroid float total = 0.0f; Vec3 centroid( 0.0f ); for( int i = 0; i < n; ++i ) { total += weights[i]; centroid += weights[i]*points[i]; } if( total > FLT_EPSILON ) centroid /= total; // accumulate the covariance matrix Sym3x3 covariance( 0.0f ); for( int i = 0; i < n; ++i ) { Vec3 a = points[i] - centroid; Vec3 b = weights[i]*a; covariance[0] += a.X()*b.X(); covariance[1] += a.X()*b.Y(); covariance[2] += a.X()*b.Z(); covariance[3] += a.Y()*b.Y(); covariance[4] += a.Y()*b.Z(); covariance[5] += a.Z()*b.Z(); } // return it return covariance; } #if 0 static Vec3 GetMultiplicity1Evector( Sym3x3 const& matrix, float evalue ) { // compute M Sym3x3 m; m[0] = matrix[0] - evalue; m[1] = matrix[1]; m[2] = matrix[2]; m[3] = matrix[3] - evalue; m[4] = matrix[4]; m[5] = matrix[5] - evalue; // compute U Sym3x3 u; u[0] = m[3]*m[5] - m[4]*m[4]; u[1] = m[2]*m[4] - m[1]*m[5]; u[2] = m[1]*m[4] - m[2]*m[3]; u[3] = m[0]*m[5] - m[2]*m[2]; u[4] = m[1]*m[2] - m[4]*m[0]; u[5] = m[0]*m[3] - m[1]*m[1]; // find the largest component float mc = std::fabs( u[0] ); int mi = 0; for( int i = 1; i < 6; ++i ) { float c = std::fabs( u[i] ); if( c > mc ) { mc = c; mi = i; } } // pick the column with this component switch( mi ) { case 0: return Vec3( u[0], u[1], u[2] ); case 1: case 3: return Vec3( u[1], u[3], u[4] ); default: return Vec3( u[2], u[4], u[5] ); } } static Vec3 GetMultiplicity2Evector( Sym3x3 const& matrix, float evalue ) { // compute M Sym3x3 m; m[0] = matrix[0] - evalue; m[1] = matrix[1]; m[2] = matrix[2]; m[3] = matrix[3] - evalue; m[4] = matrix[4]; m[5] = matrix[5] - evalue; // find the largest component float mc = std::fabs( m[0] ); int mi = 0; for( int i = 1; i < 6; ++i ) { float c = std::fabs( m[i] ); if( c > mc ) { mc = c; mi = i; } } // pick the first eigenvector based on this index switch( mi ) { case 0: case 1: return Vec3( -m[1], m[0], 0.0f ); case 2: return Vec3( m[2], 0.0f, -m[0] ); case 3: case 4: return Vec3( 0.0f, -m[4], m[3] ); default: return Vec3( 0.0f, -m[5], m[4] ); } } Vec3 ComputePrincipleComponent( Sym3x3 const& matrix ) { // compute the cubic coefficients float c0 = matrix[0]*matrix[3]*matrix[5] + 2.0f*matrix[1]*matrix[2]*matrix[4] - matrix[0]*matrix[4]*matrix[4] - matrix[3]*matrix[2]*matrix[2] - matrix[5]*matrix[1]*matrix[1]; float c1 = matrix[0]*matrix[3] + matrix[0]*matrix[5] + matrix[3]*matrix[5] - matrix[1]*matrix[1] - matrix[2]*matrix[2] - matrix[4]*matrix[4]; float c2 = matrix[0] + matrix[3] + matrix[5]; // compute the quadratic coefficients float a = c1 - ( 1.0f/3.0f )*c2*c2; float b = ( -2.0f/27.0f )*c2*c2*c2 + ( 1.0f/3.0f )*c1*c2 - c0; // compute the root count check float Q = 0.25f*b*b + ( 1.0f/27.0f )*a*a*a; // test the multiplicity if( FLT_EPSILON < Q ) { // only one root, which implies we have a multiple of the identity return Vec3( 1.0f ); } else if( Q < -FLT_EPSILON ) { // three distinct roots float theta = std::atan2( std::sqrt( -Q ), -0.5f*b ); float rho = std::sqrt( 0.25f*b*b - Q ); float rt = std::pow( rho, 1.0f/3.0f ); float ct = std::cos( theta/3.0f ); float st = std::sin( theta/3.0f ); float l1 = ( 1.0f/3.0f )*c2 + 2.0f*rt*ct; float l2 = ( 1.0f/3.0f )*c2 - rt*( ct + ( float )sqrt( 3.0f )*st ); float l3 = ( 1.0f/3.0f )*c2 - rt*( ct - ( float )sqrt( 3.0f )*st ); // pick the larger if( std::fabs( l2 ) > std::fabs( l1 ) ) l1 = l2; if( std::fabs( l3 ) > std::fabs( l1 ) ) l1 = l3; // get the eigenvector return GetMultiplicity1Evector( matrix, l1 ); } else // if( -FLT_EPSILON <= Q && Q <= FLT_EPSILON ) { // two roots float rt; if( b < 0.0f ) rt = -std::pow( -0.5f*b, 1.0f/3.0f ); else rt = std::pow( 0.5f*b, 1.0f/3.0f ); float l1 = ( 1.0f/3.0f )*c2 + rt; // repeated float l2 = ( 1.0f/3.0f )*c2 - 2.0f*rt; // get the eigenvector if( std::fabs( l1 ) > std::fabs( l2 ) ) return GetMultiplicity2Evector( matrix, l1 ); else return GetMultiplicity1Evector( matrix, l2 ); } } #else #define POWER_ITERATION_COUNT 8 Vec3 ComputePrincipleComponent( Sym3x3 const& matrix ) { Vec4 const row0( matrix[0], matrix[1], matrix[2], 0.0f ); Vec4 const row1( matrix[1], matrix[3], matrix[4], 0.0f ); Vec4 const row2( matrix[2], matrix[4], matrix[5], 0.0f ); Vec4 v = VEC4_CONST( 1.0f ); for( int i = 0; i < POWER_ITERATION_COUNT; ++i ) { // matrix multiply Vec4 w = row0*v.SplatX(); w = MultiplyAdd(row1, v.SplatY(), w); w = MultiplyAdd(row2, v.SplatZ(), w); // get max component from xyz in all channels Vec4 a = Max(w.SplatX(), Max(w.SplatY(), w.SplatZ())); // divide through and advance v = w*Reciprocal(a); } return v.GetVec3(); } #endif } // namespace squish rangefit.cpp0000644000076500000240000001320112771161730013101 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #include "rangefit.h" #include "colourset.h" #include "colourblock.h" #include namespace squish { RangeFit::RangeFit( ColourSet const* colours, int flags, float* metric ) : ColourFit( colours, flags ) { // initialise the metric (old perceptual = 0.2126f, 0.7152f, 0.0722f) if( metric ) m_metric = Vec3( metric[0], metric[1], metric[2] ); else m_metric = Vec3( 1.0f ); // initialise the best error m_besterror = FLT_MAX; // cache some values int const count = m_colours->GetCount(); Vec3 const* values = m_colours->GetPoints(); float const* weights = m_colours->GetWeights(); // get the covariance matrix Sym3x3 covariance = ComputeWeightedCovariance( count, values, weights ); // compute the principle component Vec3 principle = ComputePrincipleComponent( covariance ); // get the min and max range as the codebook endpoints Vec3 start( 0.0f ); Vec3 end( 0.0f ); if( count > 0 ) { float min, max; // compute the range start = end = values[0]; min = max = Dot( values[0], principle ); for( int i = 1; i < count; ++i ) { float val = Dot( values[i], principle ); if( val < min ) { start = values[i]; min = val; } else if( val > max ) { end = values[i]; max = val; } } } // clamp the output to [0, 1] Vec3 const one( 1.0f ); Vec3 const zero( 0.0f ); start = Min( one, Max( zero, start ) ); end = Min( one, Max( zero, end ) ); // clamp to the grid and save Vec3 const grid( 31.0f, 63.0f, 31.0f ); Vec3 const gridrcp( 1.0f/31.0f, 1.0f/63.0f, 1.0f/31.0f ); Vec3 const half( 0.5f ); m_start = Truncate( grid*start + half )*gridrcp; m_end = Truncate( grid*end + half )*gridrcp; } void RangeFit::Compress3( void* block ) { // cache some values int const count = m_colours->GetCount(); Vec3 const* values = m_colours->GetPoints(); // create a codebook Vec3 codes[3]; codes[0] = m_start; codes[1] = m_end; codes[2] = 0.5f*m_start + 0.5f*m_end; // match each point to the closest code u8 closest[16]; float error = 0.0f; for( int i = 0; i < count; ++i ) { // find the closest code float dist = FLT_MAX; int idx = 0; for( int j = 0; j < 3; ++j ) { float d = LengthSquared( m_metric*( values[i] - codes[j] ) ); if( d < dist ) { dist = d; idx = j; } } // save the index closest[i] = ( u8 )idx; // accumulate the error error += dist; } // save this scheme if it wins if( error < m_besterror ) { // remap the indices u8 indices[16]; m_colours->RemapIndices( closest, indices ); // save the block WriteColourBlock3( m_start, m_end, indices, block ); // save the error m_besterror = error; } } void RangeFit::Compress4( void* block ) { // cache some values int const count = m_colours->GetCount(); Vec3 const* values = m_colours->GetPoints(); // create a codebook Vec3 codes[4]; codes[0] = m_start; codes[1] = m_end; codes[2] = ( 2.0f/3.0f )*m_start + ( 1.0f/3.0f )*m_end; codes[3] = ( 1.0f/3.0f )*m_start + ( 2.0f/3.0f )*m_end; // match each point to the closest code u8 closest[16]; float error = 0.0f; for( int i = 0; i < count; ++i ) { // find the closest code float dist = FLT_MAX; int idx = 0; for( int j = 0; j < 4; ++j ) { float d = LengthSquared( m_metric*( values[i] - codes[j] ) ); if( d < dist ) { dist = d; idx = j; } } // save the index closest[i] = ( u8 )idx; // accumulate the error error += dist; } // save this scheme if it wins if( error < m_besterror ) { // remap the indices u8 indices[16]; m_colours->RemapIndices( closest, indices ); // save the block WriteColourBlock4( m_start, m_end, indices, block ); // save the error m_besterror = error; } } } // namespace squish singlecolourfit.cpp0000644000076500000240000001147212771161730014522 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #include "singlecolourfit.h" #include "colourset.h" #include "colourblock.h" namespace squish { struct SourceBlock { u8 start; u8 end; u8 error; }; struct SingleColourLookup { SourceBlock sources[2]; }; #include "singlecolourlookup.inl" static int FloatToInt( float a, int limit ) { // use ANSI round-to-zero behaviour to get round-to-nearest int i = ( int )( a + 0.5f ); // clamp to the limit if( i < 0 ) i = 0; else if( i > limit ) i = limit; // done return i; } SingleColourFit::SingleColourFit( ColourSet const* colours, int flags ) : ColourFit( colours, flags ) { // grab the single colour Vec3 const* values = m_colours->GetPoints(); m_colour[0] = ( u8 )FloatToInt( 255.0f*values->X(), 255 ); m_colour[1] = ( u8 )FloatToInt( 255.0f*values->Y(), 255 ); m_colour[2] = ( u8 )FloatToInt( 255.0f*values->Z(), 255 ); // initialise the best error m_besterror = INT_MAX; } void SingleColourFit::Compress3( void* block ) { // build the table of lookups SingleColourLookup const* const lookups[] = { lookup_5_3, lookup_6_3, lookup_5_3 }; // find the best end-points and index ComputeEndPoints( lookups ); // build the block if we win if( m_error < m_besterror ) { // remap the indices u8 indices[16]; m_colours->RemapIndices( &m_index, indices ); // save the block WriteColourBlock3( m_start, m_end, indices, block ); // save the error m_besterror = m_error; } } void SingleColourFit::Compress4( void* block ) { // build the table of lookups SingleColourLookup const* const lookups[] = { lookup_5_4, lookup_6_4, lookup_5_4 }; // find the best end-points and index ComputeEndPoints( lookups ); // build the block if we win if( m_error < m_besterror ) { // remap the indices u8 indices[16]; m_colours->RemapIndices( &m_index, indices ); // save the block WriteColourBlock4( m_start, m_end, indices, block ); // save the error m_besterror = m_error; } } void SingleColourFit::ComputeEndPoints( SingleColourLookup const* const* lookups ) { // check each index combination (endpoint or intermediate) m_error = INT_MAX; for( int index = 0; index < 2; ++index ) { // check the error for this codebook index SourceBlock const* sources[3]; int error = 0; for( int channel = 0; channel < 3; ++channel ) { // grab the lookup table and index for this channel SingleColourLookup const* lookup = lookups[channel]; int target = m_colour[channel]; // store a pointer to the source for this channel sources[channel] = lookup[target].sources + index; // accumulate the error int diff = sources[channel]->error; error += diff*diff; } // keep it if the error is lower if( error < m_error ) { m_start = Vec3( ( float )sources[0]->start/31.0f, ( float )sources[1]->start/63.0f, ( float )sources[2]->start/31.0f ); m_end = Vec3( ( float )sources[0]->end/31.0f, ( float )sources[1]->end/63.0f, ( float )sources[2]->end/31.0f ); m_index = ( u8 )( 2*index ); m_error = error; } } } } // namespace squish squish.cpp0000644000076500000240000003212213061741227012617 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #include #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 ) { // grab the flag bits int method = flags & ( kDxt1 | kDxt3 | kDxt5 | kBc4 | kBc5 ); int fit = flags & ( kColourIterativeClusterFit | kColourClusterFit | kColourRangeFit ); int extra = flags & kWeightColourByAlpha; // set defaults if ( method != kDxt3 && method != kDxt5 && method != kBc4 && method != kBc5 ) { method = kDxt1; } if( fit != kColourRangeFit && fit != kColourIterativeClusterFit ) fit = kColourClusterFit; // done return method | fit | extra; } void CompressMasked( u8 const* rgba, int mask, void* block, int flags, float* metric ) { // fix any bad flags 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]; // copy R to A } 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]; // copy G to A } u8* gBlock = reinterpret_cast< u8* >( block ) + 8; CompressAlphaDxt5( alpha, mask, gBlock ); } return; } // get the block locations void* colourBlock = block; void* alphaBlock = block; if( ( flags & ( kDxt3 | kDxt5 ) ) != 0 ) colourBlock = reinterpret_cast< u8* >( block ) + 8; // create the minimal point set ColourSet colours( rgba, mask, flags ); // check the compression type and compress colour if( colours.GetCount() == 1 ) { // always do a single colour fit SingleColourFit fit( &colours, flags ); fit.Compress( colourBlock ); } else if( ( flags & kColourRangeFit ) != 0 || colours.GetCount() == 0 ) { // do a range fit RangeFit fit( &colours, flags, metric ); fit.Compress( colourBlock ); } else { // default to a cluster fit (could be iterative or not) ClusterFit fit( &colours, flags, metric ); fit.Compress( colourBlock ); } // compress alpha separately if necessary 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 ) { // fix any bad flags flags = FixFlags( flags ); // get the block locations void const* colourBlock = block; void const* alphaBlock = block; if( ( flags & ( kDxt3 | kDxt5 ) ) != 0 ) colourBlock = reinterpret_cast< u8 const* >( block ) + 8; // decompress colour DecompressColour( rgba, colourBlock, ( flags & kDxt1 ) != 0 ); // decompress alpha separately if necessary if( ( flags & kDxt3 ) != 0 ) DecompressAlphaDxt3( rgba, alphaBlock ); else if( ( flags & kDxt5 ) != 0 ) DecompressAlphaDxt5( rgba, alphaBlock ); } int GetStorageRequirements( int width, int height, int flags ) { // fix any bad flags flags = FixFlags( flags ); // compute the storage requirements 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) { // convert from bgra to rgba 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 ) { // fix any bad flags flags = FixFlags( flags ); // loop over blocks #ifdef SQUISH_USE_OPENMP # pragma omp parallel for #endif for( int y = 0; y < height; y += 4 ) { // initialise the block output 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 ) { // build the 4x4 block of pixels u8 sourceRgba[16*4]; u8* targetPixel = sourceRgba; int mask = 0; for( int py = 0; py < 4; ++py ) { for( int px = 0; px < 4; ++px ) { // get the source pixel in the image int sx = x + px; int sy = y + py; // enable if we're in the image if( sx < width && sy < height ) { // copy the rgba value u8 const* sourcePixel = rgba + pitch*sy + 4*sx; CopyRGBA(sourcePixel, targetPixel, flags); // enable this pixel mask |= ( 1 << ( 4*py + px ) ); } // advance to the next pixel targetPixel += 4; } } // compress it into the output CompressMasked( sourceRgba, mask, targetBlock, flags, metric ); // advance 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 ) { // fix any bad flags flags = FixFlags( flags ); // loop over blocks #ifdef SQUISH_USE_OPENMP # pragma omp parallel for #endif for( int y = 0; y < height; y += 4 ) { // initialise the block input 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 ) { // decompress the block u8 targetRgba[4*16]; Decompress( targetRgba, sourceBlock, flags ); // write the decompressed pixels to the correct image locations u8 const* sourcePixel = targetRgba; for( int py = 0; py < 4; ++py ) { for( int px = 0; px < 4; ++px ) { // get the target location int sx = x + px; int sy = y + py; // write if we're in the image if( sx < width && sy < height ) { // copy the rgba value u8* targetPixel = rgba + pitch*sy + 4*sx; CopyRGBA(sourcePixel, targetPixel, flags); } // advance to the next pixel sourcePixel += 4; } } // advance 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) { // Computes the MSE for the block and weights it by the variance of the original block. // If the variance of the original block is less than 4 (i.e. a standard deviation of 1 per channel) // then the block is close to being a single colour. Quantisation errors in single colour blocks // are easier to see than similar errors in blocks that contain more colours, particularly when there // are many such blocks in a large area (eg a blue sky background) as they cause banding. Given that // banding is easier to see than small errors in "complex" blocks, we weight the errors by a factor // of 5. This implies that images with large, single colour areas will have a higher potential WMSE // than images with lots of detail. cmse = amse = 0; unsigned int sum_p[4]; // per channel sum of pixels unsigned int sum_p2[4]; // per channel sum of pixels squared 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; // transparent in both, so colour is inconsequential 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 ) { // fix any bad flags flags = FixFlags( flags ); colourMSE = alphaMSE = 0; // initialise the block input squish::u8 const* sourceBlock = dxt; int bytesPerBlock = ( ( flags & squish::kDxt1 ) != 0 ) ? 8 : 16; // loop over blocks for( int y = 0; y < height; y += 4 ) { for( int x = 0; x < width; x += 4 ) { // decompress the block u8 targetRgba[4*16]; Decompress( targetRgba, sourceBlock, flags ); u8 const* sourcePixel = targetRgba; // copy across to a similar pixel block 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; } } // compute the weighted MSE of the block double blockCMSE, blockAMSE; ComputeBlockWMSE(originalRgba, targetRgba, std::min(4, width - x), std::min(4, height - y), blockCMSE, blockAMSE); colourMSE += blockCMSE; alphaMSE += blockAMSE; // advance 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); } } // namespace squish alpha.h0000644000076500000240000000326512771161730012045 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_ALPHA_H #define SQUISH_ALPHA_H #include "squish.h" namespace squish { void CompressAlphaDxt3( u8 const* rgba, int mask, void* block ); void CompressAlphaDxt5( u8 const* rgba, int mask, void* block ); void DecompressAlphaDxt3( u8* rgba, void const* block ); void DecompressAlphaDxt5( u8* rgba, void const* block ); } // namespace squish #endif // ndef SQUISH_ALPHA_H clusterfit.h0000644000076500000240000000410312771161730013134 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Copyright (c) 2007 Ignacio Castano icastano@nvidia.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_CLUSTERFIT_H #define SQUISH_CLUSTERFIT_H #include "squish.h" #include "maths.h" #include "simd.h" #include "colourfit.h" namespace squish { class ClusterFit : public ColourFit { public: ClusterFit( ColourSet const* colours, int flags, float* metric ); private: bool ConstructOrdering( Vec3 const& axis, int iteration ); virtual void Compress3( void* block ); virtual void Compress4( void* block ); enum { kMaxIterations = 8 }; int m_iterationCount; Vec3 m_principle; u8 m_order[16*kMaxIterations]; Vec4 m_points_weights[16]; Vec4 m_xsum_wsum; Vec4 m_metric; Vec4 m_besterror; }; } // namespace squish #endif // ndef SQUISH_CLUSTERFIT_H colourblock.h0000644000076500000240000000333512771161730013274 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_COLOURBLOCK_H #define SQUISH_COLOURBLOCK_H #include "squish.h" #include "maths.h" namespace squish { void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ); void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block ); void DecompressColour( u8* rgba, void const* block, bool isDxt1 ); } // namespace squish #endif // ndef SQUISH_COLOURBLOCK_H colourfit.h0000644000076500000240000000346112771161730012764 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_COLOURFIT_H #define SQUISH_COLOURFIT_H #include "squish.h" #include "maths.h" #include namespace squish { class ColourSet; class ColourFit { public: ColourFit( ColourSet const* colours, int flags ); virtual ~ColourFit(); void Compress( void* block ); protected: virtual void Compress3( void* block ) = 0; virtual void Compress4( void* block ) = 0; ColourSet const* m_colours; int m_flags; }; } // namespace squish #endif // ndef SQUISH_COLOURFIT_H colourset.h0000644000076500000240000000375712771161730013005 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_COLOURSET_H #define SQUISH_COLOURSET_H #include "squish.h" #include "maths.h" namespace squish { /*! @brief Represents a set of block colours */ class ColourSet { public: ColourSet( u8 const* rgba, int mask, int flags ); int GetCount() const { return m_count; } Vec3 const* GetPoints() const { return m_points; } float const* GetWeights() const { return m_weights; } bool IsTransparent() const { return m_transparent; } void RemapIndices( u8 const* source, u8* target ) const; private: int m_count; Vec3 m_points[16]; float m_weights[16]; int m_remap[16]; bool m_transparent; }; } // namespace sqish #endif // ndef SQUISH_COLOURSET_H maths.h0000644000076500000240000001171112771161730012067 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_MATHS_H #define SQUISH_MATHS_H #include #include #include "config.h" namespace squish { class Vec3 { public: typedef Vec3 const& Arg; Vec3() { } explicit Vec3( float s ) { m_x = s; m_y = s; m_z = s; } Vec3( float x, float y, float z ) { m_x = x; m_y = y; m_z = z; } float X() const { return m_x; } float Y() const { return m_y; } float Z() const { return m_z; } Vec3 operator-() const { return Vec3( -m_x, -m_y, -m_z ); } Vec3& operator+=( Arg v ) { m_x += v.m_x; m_y += v.m_y; m_z += v.m_z; return *this; } Vec3& operator-=( Arg v ) { m_x -= v.m_x; m_y -= v.m_y; m_z -= v.m_z; return *this; } Vec3& operator*=( Arg v ) { m_x *= v.m_x; m_y *= v.m_y; m_z *= v.m_z; return *this; } Vec3& operator*=( float s ) { m_x *= s; m_y *= s; m_z *= s; return *this; } Vec3& operator/=( Arg v ) { m_x /= v.m_x; m_y /= v.m_y; m_z /= v.m_z; return *this; } Vec3& operator/=( float s ) { float t = 1.0f/s; m_x *= t; m_y *= t; m_z *= t; return *this; } friend Vec3 operator+( Arg left, Arg right ) { Vec3 copy( left ); return copy += right; } friend Vec3 operator-( Arg left, Arg right ) { Vec3 copy( left ); return copy -= right; } friend Vec3 operator*( Arg left, Arg right ) { Vec3 copy( left ); return copy *= right; } friend Vec3 operator*( Arg left, float right ) { Vec3 copy( left ); return copy *= right; } friend Vec3 operator*( float left, Arg right ) { Vec3 copy( right ); return copy *= left; } friend Vec3 operator/( Arg left, Arg right ) { Vec3 copy( left ); return copy /= right; } friend Vec3 operator/( Arg left, float right ) { Vec3 copy( left ); return copy /= right; } friend float Dot( Arg left, Arg right ) { return left.m_x*right.m_x + left.m_y*right.m_y + left.m_z*right.m_z; } friend Vec3 Min( Arg left, Arg right ) { return Vec3( std::min( left.m_x, right.m_x ), std::min( left.m_y, right.m_y ), std::min( left.m_z, right.m_z ) ); } friend Vec3 Max( Arg left, Arg right ) { return Vec3( std::max( left.m_x, right.m_x ), std::max( left.m_y, right.m_y ), std::max( left.m_z, right.m_z ) ); } friend Vec3 Truncate( Arg v ) { return Vec3( v.m_x > 0.0f ? std::floor( v.m_x ) : std::ceil( v.m_x ), v.m_y > 0.0f ? std::floor( v.m_y ) : std::ceil( v.m_y ), v.m_z > 0.0f ? std::floor( v.m_z ) : std::ceil( v.m_z ) ); } private: float m_x; float m_y; float m_z; }; inline float LengthSquared( Vec3::Arg v ) { return Dot( v, v ); } class Sym3x3 { public: Sym3x3() { } Sym3x3( float s ) { for( int i = 0; i < 6; ++i ) m_x[i] = s; } float operator[]( int index ) const { return m_x[index]; } float& operator[]( int index ) { return m_x[index]; } private: float m_x[6]; }; Sym3x3 ComputeWeightedCovariance( int n, Vec3 const* points, float const* weights ); Vec3 ComputePrincipleComponent( Sym3x3 const& matrix ); } // namespace squish #endif // ndef SQUISH_MATHS_H rangefit.h0000644000076500000240000000343312771161730012554 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_RANGEFIT_H #define SQUISH_RANGEFIT_H #include "squish.h" #include "colourfit.h" #include "maths.h" namespace squish { class ColourSet; class RangeFit : public ColourFit { public: RangeFit( ColourSet const* colours, int flags, float* metric ); private: virtual void Compress3( void* block ); virtual void Compress4( void* block ); Vec3 m_metric; Vec3 m_start; Vec3 m_end; float m_besterror; }; } // squish #endif // ndef SQUISH_RANGEFIT_H singlecolourfit.h0000644000076500000240000000365112771161730014167 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_SINGLECOLOURFIT_H #define SQUISH_SINGLECOLOURFIT_H #include "squish.h" #include "colourfit.h" namespace squish { class ColourSet; struct SingleColourLookup; class SingleColourFit : public ColourFit { public: SingleColourFit( ColourSet const* colours, int flags ); private: virtual void Compress3( void* block ); virtual void Compress4( void* block ); void ComputeEndPoints( SingleColourLookup const* const* lookups ); u8 m_colour[3]; Vec3 m_start; Vec3 m_end; u8 m_index; int m_error; int m_besterror; }; } // namespace squish #endif // ndef SQUISH_SINGLECOLOURFIT_H squish.h0000644000076500000240000003304313061712027012263 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_H #define SQUISH_H //! All squish API functions live in this namespace. namespace squish { // ----------------------------------------------------------------------------- //! Typedef a quantity that is a single unsigned byte. typedef unsigned char u8; // ----------------------------------------------------------------------------- enum { //! Use DXT1 compression. kDxt1 = ( 1 << 0 ), //! Use DXT3 compression. kDxt3 = ( 1 << 1 ), //! Use DXT5 compression. kDxt5 = ( 1 << 2 ), //! Use BC4 compression. kBc4 = ( 1 << 3 ), //! Use BC5 compression. kBc5 = ( 1 << 4 ), //! Use a slow but high quality colour compressor (the default). kColourClusterFit = ( 1 << 5 ), //! Use a fast but low quality colour compressor. kColourRangeFit = ( 1 << 6 ), //! Weight the colour by alpha during cluster fit (disabled by default). kWeightColourByAlpha = ( 1 << 7 ), //! Use a very slow but very high quality colour compressor. kColourIterativeClusterFit = ( 1 << 8 ), //! Source is BGRA rather than RGBA kSourceBGRA = ( 1 << 9 ) }; // ----------------------------------------------------------------------------- /*! @brief Compresses a 4x4 block of pixels. @param rgba The rgba values of the 16 source pixels. @param mask The valid pixel mask. @param block Storage for the compressed DXT block. @param flags Compression flags. @param metric An optional perceptual metric. The source pixels should be presented as a contiguous array of 16 rgba values, with each component as 1 byte each. In memory this should be: { r1, g1, b1, a1, .... , r16, g16, b16, a16 } The mask parameter enables only certain pixels within the block. The lowest bit enables the first pixel and so on up to the 16th bit. Bits beyond the 16th bit are ignored. Pixels that are not enabled are allowed to take arbitrary colours in the output block. An example of how this can be used is in the CompressImage function to disable pixels outside the bounds of the image when the width or height is not divisible by 4. The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, however, DXT1 will be used by default if none is specified. When using DXT1 compression, 8 bytes of storage are required for the compressed DXT block. DXT3 and DXT5 compression require 16 bytes of storage per block. The flags parameter can also specify a preferred colour compressor to use when fitting the RGB components of the data. Possible colour compressors are: kColourClusterFit (the default), kColourRangeFit (very fast, low quality) or kColourIterativeClusterFit (slowest, best quality). When using kColourClusterFit or kColourIterativeClusterFit, an additional flag can be specified to weight the importance of each pixel by its alpha value. For images that are rendered using alpha blending, this can significantly increase the perceived quality. The metric parameter can be used to weight the relative importance of each colour channel, or pass NULL to use the default uniform weight of { 1.0f, 1.0f, 1.0f }. This replaces the previous flag-based control that allowed either uniform or "perceptual" weights with the fixed values { 0.2126f, 0.7152f, 0.0722f }. If non-NULL, the metric should point to a contiguous array of 3 floats. */ void CompressMasked( u8 const* rgba, int mask, void* block, int flags, float* metric = 0 ); // ----------------------------------------------------------------------------- /*! @brief Compresses a 4x4 block of pixels. @param rgba The rgba values of the 16 source pixels. @param block Storage for the compressed DXT block. @param flags Compression flags. @param metric An optional perceptual metric. The source pixels should be presented as a contiguous array of 16 rgba values, with each component as 1 byte each. In memory this should be: { r1, g1, b1, a1, .... , r16, g16, b16, a16 } The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, however, DXT1 will be used by default if none is specified. When using DXT1 compression, 8 bytes of storage are required for the compressed DXT block. DXT3 and DXT5 compression require 16 bytes of storage per block. The flags parameter can also specify a preferred colour compressor to use when fitting the RGB components of the data. Possible colour compressors are: kColourClusterFit (the default), kColourRangeFit (very fast, low quality) or kColourIterativeClusterFit (slowest, best quality). When using kColourClusterFit or kColourIterativeClusterFit, an additional flag can be specified to weight the importance of each pixel by its alpha value. For images that are rendered using alpha blending, this can significantly increase the perceived quality. The metric parameter can be used to weight the relative importance of each colour channel, or pass NULL to use the default uniform weight of { 1.0f, 1.0f, 1.0f }. This replaces the previous flag-based control that allowed either uniform or "perceptual" weights with the fixed values { 0.2126f, 0.7152f, 0.0722f }. If non-NULL, the metric should point to a contiguous array of 3 floats. This method is an inline that calls CompressMasked with a mask of 0xffff, provided for compatibility with older versions of squish. */ inline void Compress( u8 const* rgba, void* block, int flags, float* metric = 0 ) { CompressMasked( rgba, 0xffff, block, flags, metric ); } // ----------------------------------------------------------------------------- /*! @brief Decompresses a 4x4 block of pixels. @param rgba Storage for the 16 decompressed pixels. @param block The compressed DXT block. @param flags Compression flags. The decompressed pixels will be written as a contiguous array of 16 rgba values, with each component as 1 byte each. In memory this is: { r1, g1, b1, a1, .... , r16, g16, b16, a16 } The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, however, DXT1 will be used by default if none is specified. All other flags are ignored. */ void Decompress( u8* rgba, void const* block, int flags ); // ----------------------------------------------------------------------------- /*! @brief Computes the amount of compressed storage required. @param width The width of the image. @param height The height of the image. @param flags Compression flags. The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, however, DXT1 will be used by default if none is specified. All other flags are ignored. Most DXT images will be a multiple of 4 in each dimension, but this function supports arbitrary size images by allowing the outer blocks to be only partially used. */ int GetStorageRequirements( int width, int height, int flags ); // ----------------------------------------------------------------------------- /*! @brief Compresses an image in memory. @param rgba The pixels of the source. @param width The width of the source image. @param height The height of the source image. @param pitch The pitch of the source image. @param blocks Storage for the compressed output. @param flags Compression flags. @param metric An optional perceptual metric. The source pixels should be presented as a contiguous array of width*height rgba values, with each component as 1 byte each. In memory this should be: { r1, g1, b1, a1, .... , rn, gn, bn, an } for n = width*height The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, however, DXT1 will be used by default if none is specified. When using DXT1 compression, 8 bytes of storage are required for each compressed DXT block. DXT3 and DXT5 compression require 16 bytes of storage per block. The flags parameter can also specify a preferred colour compressor to use when fitting the RGB components of the data. Possible colour compressors are: kColourClusterFit (the default), kColourRangeFit (very fast, low quality) or kColourIterativeClusterFit (slowest, best quality). When using kColourClusterFit or kColourIterativeClusterFit, an additional flag can be specified to weight the importance of each pixel by its alpha value. For images that are rendered using alpha blending, this can significantly increase the perceived quality. The metric parameter can be used to weight the relative importance of each colour channel, or pass NULL to use the default uniform weight of { 1.0f, 1.0f, 1.0f }. This replaces the previous flag-based control that allowed either uniform or "perceptual" weights with the fixed values { 0.2126f, 0.7152f, 0.0722f }. If non-NULL, the metric should point to a contiguous array of 3 floats. Internally this function calls squish::CompressMasked for each block, which allows for pixels outside the image to take arbitrary values. The function squish::GetStorageRequirements can be called to compute the amount of memory to allocate for the compressed output. Note on compression quality: When compressing textures with libsquish it is recommended to apply a gamma-correction beforehand. This will reduce the blockiness in dark areas. The level of necessary gamma-correction is platform dependent. For example, a gamma correction with gamma = 0.5 before compression and gamma = 2.0 after decompression yields good results on the Windows platform but for other platforms like MacOS X a different gamma value may be more suitable. */ void CompressImage( u8 const* rgba, int width, int height, int pitch, void* blocks, int flags, float* metric = 0 ); void CompressImage( u8 const* rgba, int width, int height, void* blocks, int flags, float* metric = 0 ); // ----------------------------------------------------------------------------- /*! @brief Decompresses an image in memory. @param rgba Storage for the decompressed pixels. @param width The width of the source image. @param height The height of the source image. @param pitch The pitch of the decompressed pixels. @param blocks The compressed DXT blocks. @param flags Compression flags. The decompressed pixels will be written as a contiguous array of width*height 16 rgba values, with each component as 1 byte each. In memory this is: { r1, g1, b1, a1, .... , rn, gn, bn, an } for n = width*height The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, however, DXT1 will be used by default if none is specified. All other flags are ignored. Internally this function calls squish::Decompress for each block. */ void DecompressImage( u8* rgba, int width, int height, int pitch, void const* blocks, int flags ); void DecompressImage( u8* rgba, int width, int height, void const* blocks, int flags ); // ----------------------------------------------------------------------------- /*! @brief Computes MSE of an compressed image in memory. @param rgba The original image pixels. @param width The width of the source image. @param height The height of the source image. @param pitch The pitch of the source image. @param dxt The compressed dxt blocks @param flags Compression flags. @param colourMSE The MSE of the colour values. @param alphaMSE The MSE of the alpha values. The colour MSE and alpha MSE are computed across all pixels. The colour MSE is averaged across all rgb values (i.e. colourMSE = sum sum_k ||dxt.k - rgba.k||/3) The flags parameter should specify kDxt1, kDxt3, kDxt5, kBc4, or kBc5 compression, however, DXT1 will be used by default if none is specified. All other flags are ignored. Internally this function calls squish::Decompress for each block. */ void ComputeMSE(u8 const *rgba, int width, int height, int pitch, u8 const *dxt, int flags, double &colourMSE, double &alphaMSE); void ComputeMSE(u8 const *rgba, int width, int height, u8 const *dxt, int flags, double &colourMSE, double &alphaMSE); // ----------------------------------------------------------------------------- } // namespace squish #endif // ndef SQUISH_H config.h0000644000076500000240000000362212771161730012222 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_CONFIG_H #define SQUISH_CONFIG_H // Set to 1 when building squish to use Altivec instructions. #ifndef SQUISH_USE_ALTIVEC #define SQUISH_USE_ALTIVEC 0 #endif // Set to 1 or 2 when building squish to use SSE or SSE2 instructions. #ifndef SQUISH_USE_SSE #define SQUISH_USE_SSE 0 #endif // Internally set SQUISH_USE_SIMD when either Altivec or SSE is available. #if SQUISH_USE_ALTIVEC && SQUISH_USE_SSE #error "Cannot enable both Altivec and SSE!" #endif #if SQUISH_USE_ALTIVEC || SQUISH_USE_SSE #define SQUISH_USE_SIMD 1 #else #define SQUISH_USE_SIMD 0 #endif #endif // ndef SQUISH_CONFIG_H simd.h0000644000076500000240000000301612771161730011706 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_SIMD_H #define SQUISH_SIMD_H #include "maths.h" #if SQUISH_USE_ALTIVEC #include "simd_ve.h" #elif SQUISH_USE_SSE #include "simd_sse.h" #else #include "simd_float.h" #endif #endif // ndef SQUISH_SIMD_H simd_float.h0000644000076500000240000001103412771161730013072 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_SIMD_FLOAT_H #define SQUISH_SIMD_FLOAT_H #include namespace squish { #define VEC4_CONST( X ) Vec4( X ) class Vec4 { public: typedef Vec4 const& Arg; Vec4() {} explicit Vec4( float s ) : m_x( s ), m_y( s ), m_z( s ), m_w( s ) { } Vec4( float x, float y, float z, float w ) : m_x( x ), m_y( y ), m_z( z ), m_w( w ) { } Vec3 GetVec3() const { return Vec3( m_x, m_y, m_z ); } Vec4 SplatX() const { return Vec4( m_x ); } Vec4 SplatY() const { return Vec4( m_y ); } Vec4 SplatZ() const { return Vec4( m_z ); } Vec4 SplatW() const { return Vec4( m_w ); } Vec4& operator+=( Arg v ) { m_x += v.m_x; m_y += v.m_y; m_z += v.m_z; m_w += v.m_w; return *this; } Vec4& operator-=( Arg v ) { m_x -= v.m_x; m_y -= v.m_y; m_z -= v.m_z; m_w -= v.m_w; return *this; } Vec4& operator*=( Arg v ) { m_x *= v.m_x; m_y *= v.m_y; m_z *= v.m_z; m_w *= v.m_w; return *this; } friend Vec4 operator+( Vec4::Arg left, Vec4::Arg right ) { Vec4 copy( left ); return copy += right; } friend Vec4 operator-( Vec4::Arg left, Vec4::Arg right ) { Vec4 copy( left ); return copy -= right; } friend Vec4 operator*( Vec4::Arg left, Vec4::Arg right ) { Vec4 copy( left ); return copy *= right; } //! Returns a*b + c friend Vec4 MultiplyAdd( Vec4::Arg a, Vec4::Arg b, Vec4::Arg c ) { return a*b + c; } //! Returns -( a*b - c ) friend Vec4 NegativeMultiplySubtract( Vec4::Arg a, Vec4::Arg b, Vec4::Arg c ) { return c - a*b; } friend Vec4 Reciprocal( Vec4::Arg v ) { return Vec4( 1.0f/v.m_x, 1.0f/v.m_y, 1.0f/v.m_z, 1.0f/v.m_w ); } friend Vec4 Min( Vec4::Arg left, Vec4::Arg right ) { return Vec4( std::min( left.m_x, right.m_x ), std::min( left.m_y, right.m_y ), std::min( left.m_z, right.m_z ), std::min( left.m_w, right.m_w ) ); } friend Vec4 Max( Vec4::Arg left, Vec4::Arg right ) { return Vec4( std::max( left.m_x, right.m_x ), std::max( left.m_y, right.m_y ), std::max( left.m_z, right.m_z ), std::max( left.m_w, right.m_w ) ); } friend Vec4 Truncate( Vec4::Arg v ) { return Vec4( v.m_x > 0.0f ? std::floor( v.m_x ) : std::ceil( v.m_x ), v.m_y > 0.0f ? std::floor( v.m_y ) : std::ceil( v.m_y ), v.m_z > 0.0f ? std::floor( v.m_z ) : std::ceil( v.m_z ), v.m_w > 0.0f ? std::floor( v.m_w ) : std::ceil( v.m_w ) ); } friend bool CompareAnyLessThan( Vec4::Arg left, Vec4::Arg right ) { return left.m_x < right.m_x || left.m_y < right.m_y || left.m_z < right.m_z || left.m_w < right.m_w; } private: float m_x; float m_y; float m_z; float m_w; }; } // namespace squish #endif // ndef SQUISH_SIMD_FLOAT_H simd_sse.h0000644000076500000240000001252312771161730012563 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_SIMD_SSE_H #define SQUISH_SIMD_SSE_H #include #if ( SQUISH_USE_SSE > 1 ) #include #endif #define SQUISH_SSE_SPLAT( a ) \ ( ( a ) | ( ( a ) << 2 ) | ( ( a ) << 4 ) | ( ( a ) << 6 ) ) #define SQUISH_SSE_SHUF( x, y, z, w ) \ ( ( x ) | ( ( y ) << 2 ) | ( ( z ) << 4 ) | ( ( w ) << 6 ) ) namespace squish { #define VEC4_CONST( X ) Vec4( X ) class Vec4 { public: typedef Vec4 const& Arg; Vec4() {} explicit Vec4( __m128 v ) : m_v( v ) {} Vec4( Vec4 const& arg ) : m_v( arg.m_v ) {} Vec4& operator=( Vec4 const& arg ) { m_v = arg.m_v; return *this; } explicit Vec4( float s ) : m_v( _mm_set1_ps( s ) ) {} Vec4( float x, float y, float z, float w ) : m_v( _mm_setr_ps( x, y, z, w ) ) {} Vec3 GetVec3() const { #ifdef __GNUC__ __attribute__ ((__aligned__ (16))) float c[4]; #else __declspec(align(16)) float c[4]; #endif _mm_store_ps( c, m_v ); return Vec3( c[0], c[1], c[2] ); } Vec4 SplatX() const { return Vec4( _mm_shuffle_ps( m_v, m_v, SQUISH_SSE_SPLAT( 0 ) ) ); } Vec4 SplatY() const { return Vec4( _mm_shuffle_ps( m_v, m_v, SQUISH_SSE_SPLAT( 1 ) ) ); } Vec4 SplatZ() const { return Vec4( _mm_shuffle_ps( m_v, m_v, SQUISH_SSE_SPLAT( 2 ) ) ); } Vec4 SplatW() const { return Vec4( _mm_shuffle_ps( m_v, m_v, SQUISH_SSE_SPLAT( 3 ) ) ); } Vec4& operator+=( Arg v ) { m_v = _mm_add_ps( m_v, v.m_v ); return *this; } Vec4& operator-=( Arg v ) { m_v = _mm_sub_ps( m_v, v.m_v ); return *this; } Vec4& operator*=( Arg v ) { m_v = _mm_mul_ps( m_v, v.m_v ); return *this; } friend Vec4 operator+( Vec4::Arg left, Vec4::Arg right ) { return Vec4( _mm_add_ps( left.m_v, right.m_v ) ); } friend Vec4 operator-( Vec4::Arg left, Vec4::Arg right ) { return Vec4( _mm_sub_ps( left.m_v, right.m_v ) ); } friend Vec4 operator*( Vec4::Arg left, Vec4::Arg right ) { return Vec4( _mm_mul_ps( left.m_v, right.m_v ) ); } //! Returns a*b + c friend Vec4 MultiplyAdd( Vec4::Arg a, Vec4::Arg b, Vec4::Arg c ) { return Vec4( _mm_add_ps( _mm_mul_ps( a.m_v, b.m_v ), c.m_v ) ); } //! Returns -( a*b - c ) friend Vec4 NegativeMultiplySubtract( Vec4::Arg a, Vec4::Arg b, Vec4::Arg c ) { return Vec4( _mm_sub_ps( c.m_v, _mm_mul_ps( a.m_v, b.m_v ) ) ); } friend Vec4 Reciprocal( Vec4::Arg v ) { // get the reciprocal estimate __m128 estimate = _mm_rcp_ps( v.m_v ); // one round of Newton-Rhaphson refinement __m128 diff = _mm_sub_ps( _mm_set1_ps( 1.0f ), _mm_mul_ps( estimate, v.m_v ) ); return Vec4( _mm_add_ps( _mm_mul_ps( diff, estimate ), estimate ) ); } friend Vec4 Min( Vec4::Arg left, Vec4::Arg right ) { return Vec4( _mm_min_ps( left.m_v, right.m_v ) ); } friend Vec4 Max( Vec4::Arg left, Vec4::Arg right ) { return Vec4( _mm_max_ps( left.m_v, right.m_v ) ); } friend Vec4 Truncate( Vec4::Arg v ) { #if ( SQUISH_USE_SSE == 1 ) // convert to ints __m128 input = v.m_v; __m64 lo = _mm_cvttps_pi32( input ); __m64 hi = _mm_cvttps_pi32( _mm_movehl_ps( input, input ) ); // convert to floats __m128 part = _mm_movelh_ps( input, _mm_cvtpi32_ps( input, hi ) ); __m128 truncated = _mm_cvtpi32_ps( part, lo ); // clear out the MMX multimedia state to allow FP calls later _mm_empty(); return Vec4( truncated ); #else // use SSE2 instructions return Vec4( _mm_cvtepi32_ps( _mm_cvttps_epi32( v.m_v ) ) ); #endif } friend bool CompareAnyLessThan( Vec4::Arg left, Vec4::Arg right ) { __m128 bits = _mm_cmplt_ps( left.m_v, right.m_v ); int value = _mm_movemask_ps( bits ); return value != 0; } private: __m128 m_v; }; } // namespace squish #endif // ndef SQUISH_SIMD_SSE_H simd_ve.h0000644000076500000240000001071712771161730012406 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #ifndef SQUISH_SIMD_VE_H #define SQUISH_SIMD_VE_H #include #undef bool namespace squish { #define VEC4_CONST( X ) Vec4( ( vector float ){ X } ) class Vec4 { public: typedef Vec4 Arg; Vec4() {} explicit Vec4( vector float v ) : m_v( v ) {} Vec4( Vec4 const& arg ) : m_v( arg.m_v ) {} Vec4& operator=( Vec4 const& arg ) { m_v = arg.m_v; return *this; } explicit Vec4( float s ) { union { vector float v; float c[4]; } u; u.c[0] = s; u.c[1] = s; u.c[2] = s; u.c[3] = s; m_v = u.v; } Vec4( float x, float y, float z, float w ) { union { vector float v; float c[4]; } u; u.c[0] = x; u.c[1] = y; u.c[2] = z; u.c[3] = w; m_v = u.v; } Vec3 GetVec3() const { union { vector float v; float c[4]; } u; u.v = m_v; return Vec3( u.c[0], u.c[1], u.c[2] ); } Vec4 SplatX() const { return Vec4( vec_splat( m_v, 0 ) ); } Vec4 SplatY() const { return Vec4( vec_splat( m_v, 1 ) ); } Vec4 SplatZ() const { return Vec4( vec_splat( m_v, 2 ) ); } Vec4 SplatW() const { return Vec4( vec_splat( m_v, 3 ) ); } Vec4& operator+=( Arg v ) { m_v = vec_add( m_v, v.m_v ); return *this; } Vec4& operator-=( Arg v ) { m_v = vec_sub( m_v, v.m_v ); return *this; } Vec4& operator*=( Arg v ) { m_v = vec_madd( m_v, v.m_v, ( vector float ){ -0.0f } ); return *this; } friend Vec4 operator+( Vec4::Arg left, Vec4::Arg right ) { return Vec4( vec_add( left.m_v, right.m_v ) ); } friend Vec4 operator-( Vec4::Arg left, Vec4::Arg right ) { return Vec4( vec_sub( left.m_v, right.m_v ) ); } friend Vec4 operator*( Vec4::Arg left, Vec4::Arg right ) { return Vec4( vec_madd( left.m_v, right.m_v, ( vector float ){ -0.0f } ) ); } //! Returns a*b + c friend Vec4 MultiplyAdd( Vec4::Arg a, Vec4::Arg b, Vec4::Arg c ) { return Vec4( vec_madd( a.m_v, b.m_v, c.m_v ) ); } //! Returns -( a*b - c ) friend Vec4 NegativeMultiplySubtract( Vec4::Arg a, Vec4::Arg b, Vec4::Arg c ) { return Vec4( vec_nmsub( a.m_v, b.m_v, c.m_v ) ); } friend Vec4 Reciprocal( Vec4::Arg v ) { // get the reciprocal estimate vector float estimate = vec_re( v.m_v ); // one round of Newton-Rhaphson refinement vector float diff = vec_nmsub( estimate, v.m_v, ( vector float ){ 1.0f } ); return Vec4( vec_madd( diff, estimate, estimate ) ); } friend Vec4 Min( Vec4::Arg left, Vec4::Arg right ) { return Vec4( vec_min( left.m_v, right.m_v ) ); } friend Vec4 Max( Vec4::Arg left, Vec4::Arg right ) { return Vec4( vec_max( left.m_v, right.m_v ) ); } friend Vec4 Truncate( Vec4::Arg v ) { return Vec4( vec_trunc( v.m_v ) ); } friend bool CompareAnyLessThan( Vec4::Arg left, Vec4::Arg right ) { return vec_any_lt( left.m_v, right.m_v ) != 0; } private: vector float m_v; }; } // namespace squish #endif // ndef SQUISH_SIMD_VE_H singlecolourlookup.inl0000644000076500000240000012323212771161730015247 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ static SingleColourLookup const lookup_5_3[] = { { { { 0, 0, 0 }, { 0, 0, 0 } } }, { { { 0, 0, 1 }, { 0, 0, 1 } } }, { { { 0, 0, 2 }, { 0, 0, 2 } } }, { { { 0, 0, 3 }, { 0, 1, 1 } } }, { { { 0, 0, 4 }, { 0, 1, 0 } } }, { { { 1, 0, 3 }, { 0, 1, 1 } } }, { { { 1, 0, 2 }, { 0, 1, 2 } } }, { { { 1, 0, 1 }, { 0, 2, 1 } } }, { { { 1, 0, 0 }, { 0, 2, 0 } } }, { { { 1, 0, 1 }, { 0, 2, 1 } } }, { { { 1, 0, 2 }, { 0, 2, 2 } } }, { { { 1, 0, 3 }, { 0, 3, 1 } } }, { { { 1, 0, 4 }, { 0, 3, 0 } } }, { { { 2, 0, 3 }, { 0, 3, 1 } } }, { { { 2, 0, 2 }, { 0, 3, 2 } } }, { { { 2, 0, 1 }, { 0, 4, 1 } } }, { { { 2, 0, 0 }, { 0, 4, 0 } } }, { { { 2, 0, 1 }, { 0, 4, 1 } } }, { { { 2, 0, 2 }, { 0, 4, 2 } } }, { { { 2, 0, 3 }, { 0, 5, 1 } } }, { { { 2, 0, 4 }, { 0, 5, 0 } } }, { { { 3, 0, 3 }, { 0, 5, 1 } } }, { { { 3, 0, 2 }, { 0, 5, 2 } } }, { { { 3, 0, 1 }, { 0, 6, 1 } } }, { { { 3, 0, 0 }, { 0, 6, 0 } } }, { { { 3, 0, 1 }, { 0, 6, 1 } } }, { { { 3, 0, 2 }, { 0, 6, 2 } } }, { { { 3, 0, 3 }, { 0, 7, 1 } } }, { { { 3, 0, 4 }, { 0, 7, 0 } } }, { { { 4, 0, 4 }, { 0, 7, 1 } } }, { { { 4, 0, 3 }, { 0, 7, 2 } } }, { { { 4, 0, 2 }, { 1, 7, 1 } } }, { { { 4, 0, 1 }, { 1, 7, 0 } } }, { { { 4, 0, 0 }, { 0, 8, 0 } } }, { { { 4, 0, 1 }, { 0, 8, 1 } } }, { { { 4, 0, 2 }, { 2, 7, 1 } } }, { { { 4, 0, 3 }, { 2, 7, 0 } } }, { { { 4, 0, 4 }, { 0, 9, 0 } } }, { { { 5, 0, 3 }, { 0, 9, 1 } } }, { { { 5, 0, 2 }, { 3, 7, 1 } } }, { { { 5, 0, 1 }, { 3, 7, 0 } } }, { { { 5, 0, 0 }, { 0, 10, 0 } } }, { { { 5, 0, 1 }, { 0, 10, 1 } } }, { { { 5, 0, 2 }, { 0, 10, 2 } } }, { { { 5, 0, 3 }, { 0, 11, 1 } } }, { { { 5, 0, 4 }, { 0, 11, 0 } } }, { { { 6, 0, 3 }, { 0, 11, 1 } } }, { { { 6, 0, 2 }, { 0, 11, 2 } } }, { { { 6, 0, 1 }, { 0, 12, 1 } } }, { { { 6, 0, 0 }, { 0, 12, 0 } } }, { { { 6, 0, 1 }, { 0, 12, 1 } } }, { { { 6, 0, 2 }, { 0, 12, 2 } } }, { { { 6, 0, 3 }, { 0, 13, 1 } } }, { { { 6, 0, 4 }, { 0, 13, 0 } } }, { { { 7, 0, 3 }, { 0, 13, 1 } } }, { { { 7, 0, 2 }, { 0, 13, 2 } } }, { { { 7, 0, 1 }, { 0, 14, 1 } } }, { { { 7, 0, 0 }, { 0, 14, 0 } } }, { { { 7, 0, 1 }, { 0, 14, 1 } } }, { { { 7, 0, 2 }, { 0, 14, 2 } } }, { { { 7, 0, 3 }, { 0, 15, 1 } } }, { { { 7, 0, 4 }, { 0, 15, 0 } } }, { { { 8, 0, 4 }, { 0, 15, 1 } } }, { { { 8, 0, 3 }, { 0, 15, 2 } } }, { { { 8, 0, 2 }, { 1, 15, 1 } } }, { { { 8, 0, 1 }, { 1, 15, 0 } } }, { { { 8, 0, 0 }, { 0, 16, 0 } } }, { { { 8, 0, 1 }, { 0, 16, 1 } } }, { { { 8, 0, 2 }, { 2, 15, 1 } } }, { { { 8, 0, 3 }, { 2, 15, 0 } } }, { { { 8, 0, 4 }, { 0, 17, 0 } } }, { { { 9, 0, 3 }, { 0, 17, 1 } } }, { { { 9, 0, 2 }, { 3, 15, 1 } } }, { { { 9, 0, 1 }, { 3, 15, 0 } } }, { { { 9, 0, 0 }, { 0, 18, 0 } } }, { { { 9, 0, 1 }, { 0, 18, 1 } } }, { { { 9, 0, 2 }, { 0, 18, 2 } } }, { { { 9, 0, 3 }, { 0, 19, 1 } } }, { { { 9, 0, 4 }, { 0, 19, 0 } } }, { { { 10, 0, 3 }, { 0, 19, 1 } } }, { { { 10, 0, 2 }, { 0, 19, 2 } } }, { { { 10, 0, 1 }, { 0, 20, 1 } } }, { { { 10, 0, 0 }, { 0, 20, 0 } } }, { { { 10, 0, 1 }, { 0, 20, 1 } } }, { { { 10, 0, 2 }, { 0, 20, 2 } } }, { { { 10, 0, 3 }, { 0, 21, 1 } } }, { { { 10, 0, 4 }, { 0, 21, 0 } } }, { { { 11, 0, 3 }, { 0, 21, 1 } } }, { { { 11, 0, 2 }, { 0, 21, 2 } } }, { { { 11, 0, 1 }, { 0, 22, 1 } } }, { { { 11, 0, 0 }, { 0, 22, 0 } } }, { { { 11, 0, 1 }, { 0, 22, 1 } } }, { { { 11, 0, 2 }, { 0, 22, 2 } } }, { { { 11, 0, 3 }, { 0, 23, 1 } } }, { { { 11, 0, 4 }, { 0, 23, 0 } } }, { { { 12, 0, 4 }, { 0, 23, 1 } } }, { { { 12, 0, 3 }, { 0, 23, 2 } } }, { { { 12, 0, 2 }, { 1, 23, 1 } } }, { { { 12, 0, 1 }, { 1, 23, 0 } } }, { { { 12, 0, 0 }, { 0, 24, 0 } } }, { { { 12, 0, 1 }, { 0, 24, 1 } } }, { { { 12, 0, 2 }, { 2, 23, 1 } } }, { { { 12, 0, 3 }, { 2, 23, 0 } } }, { { { 12, 0, 4 }, { 0, 25, 0 } } }, { { { 13, 0, 3 }, { 0, 25, 1 } } }, { { { 13, 0, 2 }, { 3, 23, 1 } } }, { { { 13, 0, 1 }, { 3, 23, 0 } } }, { { { 13, 0, 0 }, { 0, 26, 0 } } }, { { { 13, 0, 1 }, { 0, 26, 1 } } }, { { { 13, 0, 2 }, { 0, 26, 2 } } }, { { { 13, 0, 3 }, { 0, 27, 1 } } }, { { { 13, 0, 4 }, { 0, 27, 0 } } }, { { { 14, 0, 3 }, { 0, 27, 1 } } }, { { { 14, 0, 2 }, { 0, 27, 2 } } }, { { { 14, 0, 1 }, { 0, 28, 1 } } }, { { { 14, 0, 0 }, { 0, 28, 0 } } }, { { { 14, 0, 1 }, { 0, 28, 1 } } }, { { { 14, 0, 2 }, { 0, 28, 2 } } }, { { { 14, 0, 3 }, { 0, 29, 1 } } }, { { { 14, 0, 4 }, { 0, 29, 0 } } }, { { { 15, 0, 3 }, { 0, 29, 1 } } }, { { { 15, 0, 2 }, { 0, 29, 2 } } }, { { { 15, 0, 1 }, { 0, 30, 1 } } }, { { { 15, 0, 0 }, { 0, 30, 0 } } }, { { { 15, 0, 1 }, { 0, 30, 1 } } }, { { { 15, 0, 2 }, { 0, 30, 2 } } }, { { { 15, 0, 3 }, { 0, 31, 1 } } }, { { { 15, 0, 4 }, { 0, 31, 0 } } }, { { { 16, 0, 4 }, { 0, 31, 1 } } }, { { { 16, 0, 3 }, { 0, 31, 2 } } }, { { { 16, 0, 2 }, { 1, 31, 1 } } }, { { { 16, 0, 1 }, { 1, 31, 0 } } }, { { { 16, 0, 0 }, { 4, 28, 0 } } }, { { { 16, 0, 1 }, { 4, 28, 1 } } }, { { { 16, 0, 2 }, { 2, 31, 1 } } }, { { { 16, 0, 3 }, { 2, 31, 0 } } }, { { { 16, 0, 4 }, { 4, 29, 0 } } }, { { { 17, 0, 3 }, { 4, 29, 1 } } }, { { { 17, 0, 2 }, { 3, 31, 1 } } }, { { { 17, 0, 1 }, { 3, 31, 0 } } }, { { { 17, 0, 0 }, { 4, 30, 0 } } }, { { { 17, 0, 1 }, { 4, 30, 1 } } }, { { { 17, 0, 2 }, { 4, 30, 2 } } }, { { { 17, 0, 3 }, { 4, 31, 1 } } }, { { { 17, 0, 4 }, { 4, 31, 0 } } }, { { { 18, 0, 3 }, { 4, 31, 1 } } }, { { { 18, 0, 2 }, { 4, 31, 2 } } }, { { { 18, 0, 1 }, { 5, 31, 1 } } }, { { { 18, 0, 0 }, { 5, 31, 0 } } }, { { { 18, 0, 1 }, { 5, 31, 1 } } }, { { { 18, 0, 2 }, { 5, 31, 2 } } }, { { { 18, 0, 3 }, { 6, 31, 1 } } }, { { { 18, 0, 4 }, { 6, 31, 0 } } }, { { { 19, 0, 3 }, { 6, 31, 1 } } }, { { { 19, 0, 2 }, { 6, 31, 2 } } }, { { { 19, 0, 1 }, { 7, 31, 1 } } }, { { { 19, 0, 0 }, { 7, 31, 0 } } }, { { { 19, 0, 1 }, { 7, 31, 1 } } }, { { { 19, 0, 2 }, { 7, 31, 2 } } }, { { { 19, 0, 3 }, { 8, 31, 1 } } }, { { { 19, 0, 4 }, { 8, 31, 0 } } }, { { { 20, 0, 4 }, { 8, 31, 1 } } }, { { { 20, 0, 3 }, { 8, 31, 2 } } }, { { { 20, 0, 2 }, { 9, 31, 1 } } }, { { { 20, 0, 1 }, { 9, 31, 0 } } }, { { { 20, 0, 0 }, { 12, 28, 0 } } }, { { { 20, 0, 1 }, { 12, 28, 1 } } }, { { { 20, 0, 2 }, { 10, 31, 1 } } }, { { { 20, 0, 3 }, { 10, 31, 0 } } }, { { { 20, 0, 4 }, { 12, 29, 0 } } }, { { { 21, 0, 3 }, { 12, 29, 1 } } }, { { { 21, 0, 2 }, { 11, 31, 1 } } }, { { { 21, 0, 1 }, { 11, 31, 0 } } }, { { { 21, 0, 0 }, { 12, 30, 0 } } }, { { { 21, 0, 1 }, { 12, 30, 1 } } }, { { { 21, 0, 2 }, { 12, 30, 2 } } }, { { { 21, 0, 3 }, { 12, 31, 1 } } }, { { { 21, 0, 4 }, { 12, 31, 0 } } }, { { { 22, 0, 3 }, { 12, 31, 1 } } }, { { { 22, 0, 2 }, { 12, 31, 2 } } }, { { { 22, 0, 1 }, { 13, 31, 1 } } }, { { { 22, 0, 0 }, { 13, 31, 0 } } }, { { { 22, 0, 1 }, { 13, 31, 1 } } }, { { { 22, 0, 2 }, { 13, 31, 2 } } }, { { { 22, 0, 3 }, { 14, 31, 1 } } }, { { { 22, 0, 4 }, { 14, 31, 0 } } }, { { { 23, 0, 3 }, { 14, 31, 1 } } }, { { { 23, 0, 2 }, { 14, 31, 2 } } }, { { { 23, 0, 1 }, { 15, 31, 1 } } }, { { { 23, 0, 0 }, { 15, 31, 0 } } }, { { { 23, 0, 1 }, { 15, 31, 1 } } }, { { { 23, 0, 2 }, { 15, 31, 2 } } }, { { { 23, 0, 3 }, { 16, 31, 1 } } }, { { { 23, 0, 4 }, { 16, 31, 0 } } }, { { { 24, 0, 4 }, { 16, 31, 1 } } }, { { { 24, 0, 3 }, { 16, 31, 2 } } }, { { { 24, 0, 2 }, { 17, 31, 1 } } }, { { { 24, 0, 1 }, { 17, 31, 0 } } }, { { { 24, 0, 0 }, { 20, 28, 0 } } }, { { { 24, 0, 1 }, { 20, 28, 1 } } }, { { { 24, 0, 2 }, { 18, 31, 1 } } }, { { { 24, 0, 3 }, { 18, 31, 0 } } }, { { { 24, 0, 4 }, { 20, 29, 0 } } }, { { { 25, 0, 3 }, { 20, 29, 1 } } }, { { { 25, 0, 2 }, { 19, 31, 1 } } }, { { { 25, 0, 1 }, { 19, 31, 0 } } }, { { { 25, 0, 0 }, { 20, 30, 0 } } }, { { { 25, 0, 1 }, { 20, 30, 1 } } }, { { { 25, 0, 2 }, { 20, 30, 2 } } }, { { { 25, 0, 3 }, { 20, 31, 1 } } }, { { { 25, 0, 4 }, { 20, 31, 0 } } }, { { { 26, 0, 3 }, { 20, 31, 1 } } }, { { { 26, 0, 2 }, { 20, 31, 2 } } }, { { { 26, 0, 1 }, { 21, 31, 1 } } }, { { { 26, 0, 0 }, { 21, 31, 0 } } }, { { { 26, 0, 1 }, { 21, 31, 1 } } }, { { { 26, 0, 2 }, { 21, 31, 2 } } }, { { { 26, 0, 3 }, { 22, 31, 1 } } }, { { { 26, 0, 4 }, { 22, 31, 0 } } }, { { { 27, 0, 3 }, { 22, 31, 1 } } }, { { { 27, 0, 2 }, { 22, 31, 2 } } }, { { { 27, 0, 1 }, { 23, 31, 1 } } }, { { { 27, 0, 0 }, { 23, 31, 0 } } }, { { { 27, 0, 1 }, { 23, 31, 1 } } }, { { { 27, 0, 2 }, { 23, 31, 2 } } }, { { { 27, 0, 3 }, { 24, 31, 1 } } }, { { { 27, 0, 4 }, { 24, 31, 0 } } }, { { { 28, 0, 4 }, { 24, 31, 1 } } }, { { { 28, 0, 3 }, { 24, 31, 2 } } }, { { { 28, 0, 2 }, { 25, 31, 1 } } }, { { { 28, 0, 1 }, { 25, 31, 0 } } }, { { { 28, 0, 0 }, { 28, 28, 0 } } }, { { { 28, 0, 1 }, { 28, 28, 1 } } }, { { { 28, 0, 2 }, { 26, 31, 1 } } }, { { { 28, 0, 3 }, { 26, 31, 0 } } }, { { { 28, 0, 4 }, { 28, 29, 0 } } }, { { { 29, 0, 3 }, { 28, 29, 1 } } }, { { { 29, 0, 2 }, { 27, 31, 1 } } }, { { { 29, 0, 1 }, { 27, 31, 0 } } }, { { { 29, 0, 0 }, { 28, 30, 0 } } }, { { { 29, 0, 1 }, { 28, 30, 1 } } }, { { { 29, 0, 2 }, { 28, 30, 2 } } }, { { { 29, 0, 3 }, { 28, 31, 1 } } }, { { { 29, 0, 4 }, { 28, 31, 0 } } }, { { { 30, 0, 3 }, { 28, 31, 1 } } }, { { { 30, 0, 2 }, { 28, 31, 2 } } }, { { { 30, 0, 1 }, { 29, 31, 1 } } }, { { { 30, 0, 0 }, { 29, 31, 0 } } }, { { { 30, 0, 1 }, { 29, 31, 1 } } }, { { { 30, 0, 2 }, { 29, 31, 2 } } }, { { { 30, 0, 3 }, { 30, 31, 1 } } }, { { { 30, 0, 4 }, { 30, 31, 0 } } }, { { { 31, 0, 3 }, { 30, 31, 1 } } }, { { { 31, 0, 2 }, { 30, 31, 2 } } }, { { { 31, 0, 1 }, { 31, 31, 1 } } }, { { { 31, 0, 0 }, { 31, 31, 0 } } } }; static SingleColourLookup const lookup_6_3[] = { { { { 0, 0, 0 }, { 0, 0, 0 } } }, { { { 0, 0, 1 }, { 0, 1, 1 } } }, { { { 0, 0, 2 }, { 0, 1, 0 } } }, { { { 1, 0, 1 }, { 0, 2, 1 } } }, { { { 1, 0, 0 }, { 0, 2, 0 } } }, { { { 1, 0, 1 }, { 0, 3, 1 } } }, { { { 1, 0, 2 }, { 0, 3, 0 } } }, { { { 2, 0, 1 }, { 0, 4, 1 } } }, { { { 2, 0, 0 }, { 0, 4, 0 } } }, { { { 2, 0, 1 }, { 0, 5, 1 } } }, { { { 2, 0, 2 }, { 0, 5, 0 } } }, { { { 3, 0, 1 }, { 0, 6, 1 } } }, { { { 3, 0, 0 }, { 0, 6, 0 } } }, { { { 3, 0, 1 }, { 0, 7, 1 } } }, { { { 3, 0, 2 }, { 0, 7, 0 } } }, { { { 4, 0, 1 }, { 0, 8, 1 } } }, { { { 4, 0, 0 }, { 0, 8, 0 } } }, { { { 4, 0, 1 }, { 0, 9, 1 } } }, { { { 4, 0, 2 }, { 0, 9, 0 } } }, { { { 5, 0, 1 }, { 0, 10, 1 } } }, { { { 5, 0, 0 }, { 0, 10, 0 } } }, { { { 5, 0, 1 }, { 0, 11, 1 } } }, { { { 5, 0, 2 }, { 0, 11, 0 } } }, { { { 6, 0, 1 }, { 0, 12, 1 } } }, { { { 6, 0, 0 }, { 0, 12, 0 } } }, { { { 6, 0, 1 }, { 0, 13, 1 } } }, { { { 6, 0, 2 }, { 0, 13, 0 } } }, { { { 7, 0, 1 }, { 0, 14, 1 } } }, { { { 7, 0, 0 }, { 0, 14, 0 } } }, { { { 7, 0, 1 }, { 0, 15, 1 } } }, { { { 7, 0, 2 }, { 0, 15, 0 } } }, { { { 8, 0, 1 }, { 0, 16, 1 } } }, { { { 8, 0, 0 }, { 0, 16, 0 } } }, { { { 8, 0, 1 }, { 0, 17, 1 } } }, { { { 8, 0, 2 }, { 0, 17, 0 } } }, { { { 9, 0, 1 }, { 0, 18, 1 } } }, { { { 9, 0, 0 }, { 0, 18, 0 } } }, { { { 9, 0, 1 }, { 0, 19, 1 } } }, { { { 9, 0, 2 }, { 0, 19, 0 } } }, { { { 10, 0, 1 }, { 0, 20, 1 } } }, { { { 10, 0, 0 }, { 0, 20, 0 } } }, { { { 10, 0, 1 }, { 0, 21, 1 } } }, { { { 10, 0, 2 }, { 0, 21, 0 } } }, { { { 11, 0, 1 }, { 0, 22, 1 } } }, { { { 11, 0, 0 }, { 0, 22, 0 } } }, { { { 11, 0, 1 }, { 0, 23, 1 } } }, { { { 11, 0, 2 }, { 0, 23, 0 } } }, { { { 12, 0, 1 }, { 0, 24, 1 } } }, { { { 12, 0, 0 }, { 0, 24, 0 } } }, { { { 12, 0, 1 }, { 0, 25, 1 } } }, { { { 12, 0, 2 }, { 0, 25, 0 } } }, { { { 13, 0, 1 }, { 0, 26, 1 } } }, { { { 13, 0, 0 }, { 0, 26, 0 } } }, { { { 13, 0, 1 }, { 0, 27, 1 } } }, { { { 13, 0, 2 }, { 0, 27, 0 } } }, { { { 14, 0, 1 }, { 0, 28, 1 } } }, { { { 14, 0, 0 }, { 0, 28, 0 } } }, { { { 14, 0, 1 }, { 0, 29, 1 } } }, { { { 14, 0, 2 }, { 0, 29, 0 } } }, { { { 15, 0, 1 }, { 0, 30, 1 } } }, { { { 15, 0, 0 }, { 0, 30, 0 } } }, { { { 15, 0, 1 }, { 0, 31, 1 } } }, { { { 15, 0, 2 }, { 0, 31, 0 } } }, { { { 16, 0, 2 }, { 1, 31, 1 } } }, { { { 16, 0, 1 }, { 1, 31, 0 } } }, { { { 16, 0, 0 }, { 0, 32, 0 } } }, { { { 16, 0, 1 }, { 2, 31, 0 } } }, { { { 16, 0, 2 }, { 0, 33, 0 } } }, { { { 17, 0, 1 }, { 3, 31, 0 } } }, { { { 17, 0, 0 }, { 0, 34, 0 } } }, { { { 17, 0, 1 }, { 4, 31, 0 } } }, { { { 17, 0, 2 }, { 0, 35, 0 } } }, { { { 18, 0, 1 }, { 5, 31, 0 } } }, { { { 18, 0, 0 }, { 0, 36, 0 } } }, { { { 18, 0, 1 }, { 6, 31, 0 } } }, { { { 18, 0, 2 }, { 0, 37, 0 } } }, { { { 19, 0, 1 }, { 7, 31, 0 } } }, { { { 19, 0, 0 }, { 0, 38, 0 } } }, { { { 19, 0, 1 }, { 8, 31, 0 } } }, { { { 19, 0, 2 }, { 0, 39, 0 } } }, { { { 20, 0, 1 }, { 9, 31, 0 } } }, { { { 20, 0, 0 }, { 0, 40, 0 } } }, { { { 20, 0, 1 }, { 10, 31, 0 } } }, { { { 20, 0, 2 }, { 0, 41, 0 } } }, { { { 21, 0, 1 }, { 11, 31, 0 } } }, { { { 21, 0, 0 }, { 0, 42, 0 } } }, { { { 21, 0, 1 }, { 12, 31, 0 } } }, { { { 21, 0, 2 }, { 0, 43, 0 } } }, { { { 22, 0, 1 }, { 13, 31, 0 } } }, { { { 22, 0, 0 }, { 0, 44, 0 } } }, { { { 22, 0, 1 }, { 14, 31, 0 } } }, { { { 22, 0, 2 }, { 0, 45, 0 } } }, { { { 23, 0, 1 }, { 15, 31, 0 } } }, { { { 23, 0, 0 }, { 0, 46, 0 } } }, { { { 23, 0, 1 }, { 0, 47, 1 } } }, { { { 23, 0, 2 }, { 0, 47, 0 } } }, { { { 24, 0, 1 }, { 0, 48, 1 } } }, { { { 24, 0, 0 }, { 0, 48, 0 } } }, { { { 24, 0, 1 }, { 0, 49, 1 } } }, { { { 24, 0, 2 }, { 0, 49, 0 } } }, { { { 25, 0, 1 }, { 0, 50, 1 } } }, { { { 25, 0, 0 }, { 0, 50, 0 } } }, { { { 25, 0, 1 }, { 0, 51, 1 } } }, { { { 25, 0, 2 }, { 0, 51, 0 } } }, { { { 26, 0, 1 }, { 0, 52, 1 } } }, { { { 26, 0, 0 }, { 0, 52, 0 } } }, { { { 26, 0, 1 }, { 0, 53, 1 } } }, { { { 26, 0, 2 }, { 0, 53, 0 } } }, { { { 27, 0, 1 }, { 0, 54, 1 } } }, { { { 27, 0, 0 }, { 0, 54, 0 } } }, { { { 27, 0, 1 }, { 0, 55, 1 } } }, { { { 27, 0, 2 }, { 0, 55, 0 } } }, { { { 28, 0, 1 }, { 0, 56, 1 } } }, { { { 28, 0, 0 }, { 0, 56, 0 } } }, { { { 28, 0, 1 }, { 0, 57, 1 } } }, { { { 28, 0, 2 }, { 0, 57, 0 } } }, { { { 29, 0, 1 }, { 0, 58, 1 } } }, { { { 29, 0, 0 }, { 0, 58, 0 } } }, { { { 29, 0, 1 }, { 0, 59, 1 } } }, { { { 29, 0, 2 }, { 0, 59, 0 } } }, { { { 30, 0, 1 }, { 0, 60, 1 } } }, { { { 30, 0, 0 }, { 0, 60, 0 } } }, { { { 30, 0, 1 }, { 0, 61, 1 } } }, { { { 30, 0, 2 }, { 0, 61, 0 } } }, { { { 31, 0, 1 }, { 0, 62, 1 } } }, { { { 31, 0, 0 }, { 0, 62, 0 } } }, { { { 31, 0, 1 }, { 0, 63, 1 } } }, { { { 31, 0, 2 }, { 0, 63, 0 } } }, { { { 32, 0, 2 }, { 1, 63, 1 } } }, { { { 32, 0, 1 }, { 1, 63, 0 } } }, { { { 32, 0, 0 }, { 16, 48, 0 } } }, { { { 32, 0, 1 }, { 2, 63, 0 } } }, { { { 32, 0, 2 }, { 16, 49, 0 } } }, { { { 33, 0, 1 }, { 3, 63, 0 } } }, { { { 33, 0, 0 }, { 16, 50, 0 } } }, { { { 33, 0, 1 }, { 4, 63, 0 } } }, { { { 33, 0, 2 }, { 16, 51, 0 } } }, { { { 34, 0, 1 }, { 5, 63, 0 } } }, { { { 34, 0, 0 }, { 16, 52, 0 } } }, { { { 34, 0, 1 }, { 6, 63, 0 } } }, { { { 34, 0, 2 }, { 16, 53, 0 } } }, { { { 35, 0, 1 }, { 7, 63, 0 } } }, { { { 35, 0, 0 }, { 16, 54, 0 } } }, { { { 35, 0, 1 }, { 8, 63, 0 } } }, { { { 35, 0, 2 }, { 16, 55, 0 } } }, { { { 36, 0, 1 }, { 9, 63, 0 } } }, { { { 36, 0, 0 }, { 16, 56, 0 } } }, { { { 36, 0, 1 }, { 10, 63, 0 } } }, { { { 36, 0, 2 }, { 16, 57, 0 } } }, { { { 37, 0, 1 }, { 11, 63, 0 } } }, { { { 37, 0, 0 }, { 16, 58, 0 } } }, { { { 37, 0, 1 }, { 12, 63, 0 } } }, { { { 37, 0, 2 }, { 16, 59, 0 } } }, { { { 38, 0, 1 }, { 13, 63, 0 } } }, { { { 38, 0, 0 }, { 16, 60, 0 } } }, { { { 38, 0, 1 }, { 14, 63, 0 } } }, { { { 38, 0, 2 }, { 16, 61, 0 } } }, { { { 39, 0, 1 }, { 15, 63, 0 } } }, { { { 39, 0, 0 }, { 16, 62, 0 } } }, { { { 39, 0, 1 }, { 16, 63, 1 } } }, { { { 39, 0, 2 }, { 16, 63, 0 } } }, { { { 40, 0, 1 }, { 17, 63, 1 } } }, { { { 40, 0, 0 }, { 17, 63, 0 } } }, { { { 40, 0, 1 }, { 18, 63, 1 } } }, { { { 40, 0, 2 }, { 18, 63, 0 } } }, { { { 41, 0, 1 }, { 19, 63, 1 } } }, { { { 41, 0, 0 }, { 19, 63, 0 } } }, { { { 41, 0, 1 }, { 20, 63, 1 } } }, { { { 41, 0, 2 }, { 20, 63, 0 } } }, { { { 42, 0, 1 }, { 21, 63, 1 } } }, { { { 42, 0, 0 }, { 21, 63, 0 } } }, { { { 42, 0, 1 }, { 22, 63, 1 } } }, { { { 42, 0, 2 }, { 22, 63, 0 } } }, { { { 43, 0, 1 }, { 23, 63, 1 } } }, { { { 43, 0, 0 }, { 23, 63, 0 } } }, { { { 43, 0, 1 }, { 24, 63, 1 } } }, { { { 43, 0, 2 }, { 24, 63, 0 } } }, { { { 44, 0, 1 }, { 25, 63, 1 } } }, { { { 44, 0, 0 }, { 25, 63, 0 } } }, { { { 44, 0, 1 }, { 26, 63, 1 } } }, { { { 44, 0, 2 }, { 26, 63, 0 } } }, { { { 45, 0, 1 }, { 27, 63, 1 } } }, { { { 45, 0, 0 }, { 27, 63, 0 } } }, { { { 45, 0, 1 }, { 28, 63, 1 } } }, { { { 45, 0, 2 }, { 28, 63, 0 } } }, { { { 46, 0, 1 }, { 29, 63, 1 } } }, { { { 46, 0, 0 }, { 29, 63, 0 } } }, { { { 46, 0, 1 }, { 30, 63, 1 } } }, { { { 46, 0, 2 }, { 30, 63, 0 } } }, { { { 47, 0, 1 }, { 31, 63, 1 } } }, { { { 47, 0, 0 }, { 31, 63, 0 } } }, { { { 47, 0, 1 }, { 32, 63, 1 } } }, { { { 47, 0, 2 }, { 32, 63, 0 } } }, { { { 48, 0, 2 }, { 33, 63, 1 } } }, { { { 48, 0, 1 }, { 33, 63, 0 } } }, { { { 48, 0, 0 }, { 48, 48, 0 } } }, { { { 48, 0, 1 }, { 34, 63, 0 } } }, { { { 48, 0, 2 }, { 48, 49, 0 } } }, { { { 49, 0, 1 }, { 35, 63, 0 } } }, { { { 49, 0, 0 }, { 48, 50, 0 } } }, { { { 49, 0, 1 }, { 36, 63, 0 } } }, { { { 49, 0, 2 }, { 48, 51, 0 } } }, { { { 50, 0, 1 }, { 37, 63, 0 } } }, { { { 50, 0, 0 }, { 48, 52, 0 } } }, { { { 50, 0, 1 }, { 38, 63, 0 } } }, { { { 50, 0, 2 }, { 48, 53, 0 } } }, { { { 51, 0, 1 }, { 39, 63, 0 } } }, { { { 51, 0, 0 }, { 48, 54, 0 } } }, { { { 51, 0, 1 }, { 40, 63, 0 } } }, { { { 51, 0, 2 }, { 48, 55, 0 } } }, { { { 52, 0, 1 }, { 41, 63, 0 } } }, { { { 52, 0, 0 }, { 48, 56, 0 } } }, { { { 52, 0, 1 }, { 42, 63, 0 } } }, { { { 52, 0, 2 }, { 48, 57, 0 } } }, { { { 53, 0, 1 }, { 43, 63, 0 } } }, { { { 53, 0, 0 }, { 48, 58, 0 } } }, { { { 53, 0, 1 }, { 44, 63, 0 } } }, { { { 53, 0, 2 }, { 48, 59, 0 } } }, { { { 54, 0, 1 }, { 45, 63, 0 } } }, { { { 54, 0, 0 }, { 48, 60, 0 } } }, { { { 54, 0, 1 }, { 46, 63, 0 } } }, { { { 54, 0, 2 }, { 48, 61, 0 } } }, { { { 55, 0, 1 }, { 47, 63, 0 } } }, { { { 55, 0, 0 }, { 48, 62, 0 } } }, { { { 55, 0, 1 }, { 48, 63, 1 } } }, { { { 55, 0, 2 }, { 48, 63, 0 } } }, { { { 56, 0, 1 }, { 49, 63, 1 } } }, { { { 56, 0, 0 }, { 49, 63, 0 } } }, { { { 56, 0, 1 }, { 50, 63, 1 } } }, { { { 56, 0, 2 }, { 50, 63, 0 } } }, { { { 57, 0, 1 }, { 51, 63, 1 } } }, { { { 57, 0, 0 }, { 51, 63, 0 } } }, { { { 57, 0, 1 }, { 52, 63, 1 } } }, { { { 57, 0, 2 }, { 52, 63, 0 } } }, { { { 58, 0, 1 }, { 53, 63, 1 } } }, { { { 58, 0, 0 }, { 53, 63, 0 } } }, { { { 58, 0, 1 }, { 54, 63, 1 } } }, { { { 58, 0, 2 }, { 54, 63, 0 } } }, { { { 59, 0, 1 }, { 55, 63, 1 } } }, { { { 59, 0, 0 }, { 55, 63, 0 } } }, { { { 59, 0, 1 }, { 56, 63, 1 } } }, { { { 59, 0, 2 }, { 56, 63, 0 } } }, { { { 60, 0, 1 }, { 57, 63, 1 } } }, { { { 60, 0, 0 }, { 57, 63, 0 } } }, { { { 60, 0, 1 }, { 58, 63, 1 } } }, { { { 60, 0, 2 }, { 58, 63, 0 } } }, { { { 61, 0, 1 }, { 59, 63, 1 } } }, { { { 61, 0, 0 }, { 59, 63, 0 } } }, { { { 61, 0, 1 }, { 60, 63, 1 } } }, { { { 61, 0, 2 }, { 60, 63, 0 } } }, { { { 62, 0, 1 }, { 61, 63, 1 } } }, { { { 62, 0, 0 }, { 61, 63, 0 } } }, { { { 62, 0, 1 }, { 62, 63, 1 } } }, { { { 62, 0, 2 }, { 62, 63, 0 } } }, { { { 63, 0, 1 }, { 63, 63, 1 } } }, { { { 63, 0, 0 }, { 63, 63, 0 } } } }; static SingleColourLookup const lookup_5_4[] = { { { { 0, 0, 0 }, { 0, 0, 0 } } }, { { { 0, 0, 1 }, { 0, 1, 1 } } }, { { { 0, 0, 2 }, { 0, 1, 0 } } }, { { { 0, 0, 3 }, { 0, 1, 1 } } }, { { { 0, 0, 4 }, { 0, 2, 1 } } }, { { { 1, 0, 3 }, { 0, 2, 0 } } }, { { { 1, 0, 2 }, { 0, 2, 1 } } }, { { { 1, 0, 1 }, { 0, 3, 1 } } }, { { { 1, 0, 0 }, { 0, 3, 0 } } }, { { { 1, 0, 1 }, { 1, 2, 1 } } }, { { { 1, 0, 2 }, { 1, 2, 0 } } }, { { { 1, 0, 3 }, { 0, 4, 0 } } }, { { { 1, 0, 4 }, { 0, 5, 1 } } }, { { { 2, 0, 3 }, { 0, 5, 0 } } }, { { { 2, 0, 2 }, { 0, 5, 1 } } }, { { { 2, 0, 1 }, { 0, 6, 1 } } }, { { { 2, 0, 0 }, { 0, 6, 0 } } }, { { { 2, 0, 1 }, { 2, 3, 1 } } }, { { { 2, 0, 2 }, { 2, 3, 0 } } }, { { { 2, 0, 3 }, { 0, 7, 0 } } }, { { { 2, 0, 4 }, { 1, 6, 1 } } }, { { { 3, 0, 3 }, { 1, 6, 0 } } }, { { { 3, 0, 2 }, { 0, 8, 0 } } }, { { { 3, 0, 1 }, { 0, 9, 1 } } }, { { { 3, 0, 0 }, { 0, 9, 0 } } }, { { { 3, 0, 1 }, { 0, 9, 1 } } }, { { { 3, 0, 2 }, { 0, 10, 1 } } }, { { { 3, 0, 3 }, { 0, 10, 0 } } }, { { { 3, 0, 4 }, { 2, 7, 1 } } }, { { { 4, 0, 4 }, { 2, 7, 0 } } }, { { { 4, 0, 3 }, { 0, 11, 0 } } }, { { { 4, 0, 2 }, { 1, 10, 1 } } }, { { { 4, 0, 1 }, { 1, 10, 0 } } }, { { { 4, 0, 0 }, { 0, 12, 0 } } }, { { { 4, 0, 1 }, { 0, 13, 1 } } }, { { { 4, 0, 2 }, { 0, 13, 0 } } }, { { { 4, 0, 3 }, { 0, 13, 1 } } }, { { { 4, 0, 4 }, { 0, 14, 1 } } }, { { { 5, 0, 3 }, { 0, 14, 0 } } }, { { { 5, 0, 2 }, { 2, 11, 1 } } }, { { { 5, 0, 1 }, { 2, 11, 0 } } }, { { { 5, 0, 0 }, { 0, 15, 0 } } }, { { { 5, 0, 1 }, { 1, 14, 1 } } }, { { { 5, 0, 2 }, { 1, 14, 0 } } }, { { { 5, 0, 3 }, { 0, 16, 0 } } }, { { { 5, 0, 4 }, { 0, 17, 1 } } }, { { { 6, 0, 3 }, { 0, 17, 0 } } }, { { { 6, 0, 2 }, { 0, 17, 1 } } }, { { { 6, 0, 1 }, { 0, 18, 1 } } }, { { { 6, 0, 0 }, { 0, 18, 0 } } }, { { { 6, 0, 1 }, { 2, 15, 1 } } }, { { { 6, 0, 2 }, { 2, 15, 0 } } }, { { { 6, 0, 3 }, { 0, 19, 0 } } }, { { { 6, 0, 4 }, { 1, 18, 1 } } }, { { { 7, 0, 3 }, { 1, 18, 0 } } }, { { { 7, 0, 2 }, { 0, 20, 0 } } }, { { { 7, 0, 1 }, { 0, 21, 1 } } }, { { { 7, 0, 0 }, { 0, 21, 0 } } }, { { { 7, 0, 1 }, { 0, 21, 1 } } }, { { { 7, 0, 2 }, { 0, 22, 1 } } }, { { { 7, 0, 3 }, { 0, 22, 0 } } }, { { { 7, 0, 4 }, { 2, 19, 1 } } }, { { { 8, 0, 4 }, { 2, 19, 0 } } }, { { { 8, 0, 3 }, { 0, 23, 0 } } }, { { { 8, 0, 2 }, { 1, 22, 1 } } }, { { { 8, 0, 1 }, { 1, 22, 0 } } }, { { { 8, 0, 0 }, { 0, 24, 0 } } }, { { { 8, 0, 1 }, { 0, 25, 1 } } }, { { { 8, 0, 2 }, { 0, 25, 0 } } }, { { { 8, 0, 3 }, { 0, 25, 1 } } }, { { { 8, 0, 4 }, { 0, 26, 1 } } }, { { { 9, 0, 3 }, { 0, 26, 0 } } }, { { { 9, 0, 2 }, { 2, 23, 1 } } }, { { { 9, 0, 1 }, { 2, 23, 0 } } }, { { { 9, 0, 0 }, { 0, 27, 0 } } }, { { { 9, 0, 1 }, { 1, 26, 1 } } }, { { { 9, 0, 2 }, { 1, 26, 0 } } }, { { { 9, 0, 3 }, { 0, 28, 0 } } }, { { { 9, 0, 4 }, { 0, 29, 1 } } }, { { { 10, 0, 3 }, { 0, 29, 0 } } }, { { { 10, 0, 2 }, { 0, 29, 1 } } }, { { { 10, 0, 1 }, { 0, 30, 1 } } }, { { { 10, 0, 0 }, { 0, 30, 0 } } }, { { { 10, 0, 1 }, { 2, 27, 1 } } }, { { { 10, 0, 2 }, { 2, 27, 0 } } }, { { { 10, 0, 3 }, { 0, 31, 0 } } }, { { { 10, 0, 4 }, { 1, 30, 1 } } }, { { { 11, 0, 3 }, { 1, 30, 0 } } }, { { { 11, 0, 2 }, { 4, 24, 0 } } }, { { { 11, 0, 1 }, { 1, 31, 1 } } }, { { { 11, 0, 0 }, { 1, 31, 0 } } }, { { { 11, 0, 1 }, { 1, 31, 1 } } }, { { { 11, 0, 2 }, { 2, 30, 1 } } }, { { { 11, 0, 3 }, { 2, 30, 0 } } }, { { { 11, 0, 4 }, { 2, 31, 1 } } }, { { { 12, 0, 4 }, { 2, 31, 0 } } }, { { { 12, 0, 3 }, { 4, 27, 0 } } }, { { { 12, 0, 2 }, { 3, 30, 1 } } }, { { { 12, 0, 1 }, { 3, 30, 0 } } }, { { { 12, 0, 0 }, { 4, 28, 0 } } }, { { { 12, 0, 1 }, { 3, 31, 1 } } }, { { { 12, 0, 2 }, { 3, 31, 0 } } }, { { { 12, 0, 3 }, { 3, 31, 1 } } }, { { { 12, 0, 4 }, { 4, 30, 1 } } }, { { { 13, 0, 3 }, { 4, 30, 0 } } }, { { { 13, 0, 2 }, { 6, 27, 1 } } }, { { { 13, 0, 1 }, { 6, 27, 0 } } }, { { { 13, 0, 0 }, { 4, 31, 0 } } }, { { { 13, 0, 1 }, { 5, 30, 1 } } }, { { { 13, 0, 2 }, { 5, 30, 0 } } }, { { { 13, 0, 3 }, { 8, 24, 0 } } }, { { { 13, 0, 4 }, { 5, 31, 1 } } }, { { { 14, 0, 3 }, { 5, 31, 0 } } }, { { { 14, 0, 2 }, { 5, 31, 1 } } }, { { { 14, 0, 1 }, { 6, 30, 1 } } }, { { { 14, 0, 0 }, { 6, 30, 0 } } }, { { { 14, 0, 1 }, { 6, 31, 1 } } }, { { { 14, 0, 2 }, { 6, 31, 0 } } }, { { { 14, 0, 3 }, { 8, 27, 0 } } }, { { { 14, 0, 4 }, { 7, 30, 1 } } }, { { { 15, 0, 3 }, { 7, 30, 0 } } }, { { { 15, 0, 2 }, { 8, 28, 0 } } }, { { { 15, 0, 1 }, { 7, 31, 1 } } }, { { { 15, 0, 0 }, { 7, 31, 0 } } }, { { { 15, 0, 1 }, { 7, 31, 1 } } }, { { { 15, 0, 2 }, { 8, 30, 1 } } }, { { { 15, 0, 3 }, { 8, 30, 0 } } }, { { { 15, 0, 4 }, { 10, 27, 1 } } }, { { { 16, 0, 4 }, { 10, 27, 0 } } }, { { { 16, 0, 3 }, { 8, 31, 0 } } }, { { { 16, 0, 2 }, { 9, 30, 1 } } }, { { { 16, 0, 1 }, { 9, 30, 0 } } }, { { { 16, 0, 0 }, { 12, 24, 0 } } }, { { { 16, 0, 1 }, { 9, 31, 1 } } }, { { { 16, 0, 2 }, { 9, 31, 0 } } }, { { { 16, 0, 3 }, { 9, 31, 1 } } }, { { { 16, 0, 4 }, { 10, 30, 1 } } }, { { { 17, 0, 3 }, { 10, 30, 0 } } }, { { { 17, 0, 2 }, { 10, 31, 1 } } }, { { { 17, 0, 1 }, { 10, 31, 0 } } }, { { { 17, 0, 0 }, { 12, 27, 0 } } }, { { { 17, 0, 1 }, { 11, 30, 1 } } }, { { { 17, 0, 2 }, { 11, 30, 0 } } }, { { { 17, 0, 3 }, { 12, 28, 0 } } }, { { { 17, 0, 4 }, { 11, 31, 1 } } }, { { { 18, 0, 3 }, { 11, 31, 0 } } }, { { { 18, 0, 2 }, { 11, 31, 1 } } }, { { { 18, 0, 1 }, { 12, 30, 1 } } }, { { { 18, 0, 0 }, { 12, 30, 0 } } }, { { { 18, 0, 1 }, { 14, 27, 1 } } }, { { { 18, 0, 2 }, { 14, 27, 0 } } }, { { { 18, 0, 3 }, { 12, 31, 0 } } }, { { { 18, 0, 4 }, { 13, 30, 1 } } }, { { { 19, 0, 3 }, { 13, 30, 0 } } }, { { { 19, 0, 2 }, { 16, 24, 0 } } }, { { { 19, 0, 1 }, { 13, 31, 1 } } }, { { { 19, 0, 0 }, { 13, 31, 0 } } }, { { { 19, 0, 1 }, { 13, 31, 1 } } }, { { { 19, 0, 2 }, { 14, 30, 1 } } }, { { { 19, 0, 3 }, { 14, 30, 0 } } }, { { { 19, 0, 4 }, { 14, 31, 1 } } }, { { { 20, 0, 4 }, { 14, 31, 0 } } }, { { { 20, 0, 3 }, { 16, 27, 0 } } }, { { { 20, 0, 2 }, { 15, 30, 1 } } }, { { { 20, 0, 1 }, { 15, 30, 0 } } }, { { { 20, 0, 0 }, { 16, 28, 0 } } }, { { { 20, 0, 1 }, { 15, 31, 1 } } }, { { { 20, 0, 2 }, { 15, 31, 0 } } }, { { { 20, 0, 3 }, { 15, 31, 1 } } }, { { { 20, 0, 4 }, { 16, 30, 1 } } }, { { { 21, 0, 3 }, { 16, 30, 0 } } }, { { { 21, 0, 2 }, { 18, 27, 1 } } }, { { { 21, 0, 1 }, { 18, 27, 0 } } }, { { { 21, 0, 0 }, { 16, 31, 0 } } }, { { { 21, 0, 1 }, { 17, 30, 1 } } }, { { { 21, 0, 2 }, { 17, 30, 0 } } }, { { { 21, 0, 3 }, { 20, 24, 0 } } }, { { { 21, 0, 4 }, { 17, 31, 1 } } }, { { { 22, 0, 3 }, { 17, 31, 0 } } }, { { { 22, 0, 2 }, { 17, 31, 1 } } }, { { { 22, 0, 1 }, { 18, 30, 1 } } }, { { { 22, 0, 0 }, { 18, 30, 0 } } }, { { { 22, 0, 1 }, { 18, 31, 1 } } }, { { { 22, 0, 2 }, { 18, 31, 0 } } }, { { { 22, 0, 3 }, { 20, 27, 0 } } }, { { { 22, 0, 4 }, { 19, 30, 1 } } }, { { { 23, 0, 3 }, { 19, 30, 0 } } }, { { { 23, 0, 2 }, { 20, 28, 0 } } }, { { { 23, 0, 1 }, { 19, 31, 1 } } }, { { { 23, 0, 0 }, { 19, 31, 0 } } }, { { { 23, 0, 1 }, { 19, 31, 1 } } }, { { { 23, 0, 2 }, { 20, 30, 1 } } }, { { { 23, 0, 3 }, { 20, 30, 0 } } }, { { { 23, 0, 4 }, { 22, 27, 1 } } }, { { { 24, 0, 4 }, { 22, 27, 0 } } }, { { { 24, 0, 3 }, { 20, 31, 0 } } }, { { { 24, 0, 2 }, { 21, 30, 1 } } }, { { { 24, 0, 1 }, { 21, 30, 0 } } }, { { { 24, 0, 0 }, { 24, 24, 0 } } }, { { { 24, 0, 1 }, { 21, 31, 1 } } }, { { { 24, 0, 2 }, { 21, 31, 0 } } }, { { { 24, 0, 3 }, { 21, 31, 1 } } }, { { { 24, 0, 4 }, { 22, 30, 1 } } }, { { { 25, 0, 3 }, { 22, 30, 0 } } }, { { { 25, 0, 2 }, { 22, 31, 1 } } }, { { { 25, 0, 1 }, { 22, 31, 0 } } }, { { { 25, 0, 0 }, { 24, 27, 0 } } }, { { { 25, 0, 1 }, { 23, 30, 1 } } }, { { { 25, 0, 2 }, { 23, 30, 0 } } }, { { { 25, 0, 3 }, { 24, 28, 0 } } }, { { { 25, 0, 4 }, { 23, 31, 1 } } }, { { { 26, 0, 3 }, { 23, 31, 0 } } }, { { { 26, 0, 2 }, { 23, 31, 1 } } }, { { { 26, 0, 1 }, { 24, 30, 1 } } }, { { { 26, 0, 0 }, { 24, 30, 0 } } }, { { { 26, 0, 1 }, { 26, 27, 1 } } }, { { { 26, 0, 2 }, { 26, 27, 0 } } }, { { { 26, 0, 3 }, { 24, 31, 0 } } }, { { { 26, 0, 4 }, { 25, 30, 1 } } }, { { { 27, 0, 3 }, { 25, 30, 0 } } }, { { { 27, 0, 2 }, { 28, 24, 0 } } }, { { { 27, 0, 1 }, { 25, 31, 1 } } }, { { { 27, 0, 0 }, { 25, 31, 0 } } }, { { { 27, 0, 1 }, { 25, 31, 1 } } }, { { { 27, 0, 2 }, { 26, 30, 1 } } }, { { { 27, 0, 3 }, { 26, 30, 0 } } }, { { { 27, 0, 4 }, { 26, 31, 1 } } }, { { { 28, 0, 4 }, { 26, 31, 0 } } }, { { { 28, 0, 3 }, { 28, 27, 0 } } }, { { { 28, 0, 2 }, { 27, 30, 1 } } }, { { { 28, 0, 1 }, { 27, 30, 0 } } }, { { { 28, 0, 0 }, { 28, 28, 0 } } }, { { { 28, 0, 1 }, { 27, 31, 1 } } }, { { { 28, 0, 2 }, { 27, 31, 0 } } }, { { { 28, 0, 3 }, { 27, 31, 1 } } }, { { { 28, 0, 4 }, { 28, 30, 1 } } }, { { { 29, 0, 3 }, { 28, 30, 0 } } }, { { { 29, 0, 2 }, { 30, 27, 1 } } }, { { { 29, 0, 1 }, { 30, 27, 0 } } }, { { { 29, 0, 0 }, { 28, 31, 0 } } }, { { { 29, 0, 1 }, { 29, 30, 1 } } }, { { { 29, 0, 2 }, { 29, 30, 0 } } }, { { { 29, 0, 3 }, { 29, 30, 1 } } }, { { { 29, 0, 4 }, { 29, 31, 1 } } }, { { { 30, 0, 3 }, { 29, 31, 0 } } }, { { { 30, 0, 2 }, { 29, 31, 1 } } }, { { { 30, 0, 1 }, { 30, 30, 1 } } }, { { { 30, 0, 0 }, { 30, 30, 0 } } }, { { { 30, 0, 1 }, { 30, 31, 1 } } }, { { { 30, 0, 2 }, { 30, 31, 0 } } }, { { { 30, 0, 3 }, { 30, 31, 1 } } }, { { { 30, 0, 4 }, { 31, 30, 1 } } }, { { { 31, 0, 3 }, { 31, 30, 0 } } }, { { { 31, 0, 2 }, { 31, 30, 1 } } }, { { { 31, 0, 1 }, { 31, 31, 1 } } }, { { { 31, 0, 0 }, { 31, 31, 0 } } } }; static SingleColourLookup const lookup_6_4[] = { { { { 0, 0, 0 }, { 0, 0, 0 } } }, { { { 0, 0, 1 }, { 0, 1, 0 } } }, { { { 0, 0, 2 }, { 0, 2, 0 } } }, { { { 1, 0, 1 }, { 0, 3, 1 } } }, { { { 1, 0, 0 }, { 0, 3, 0 } } }, { { { 1, 0, 1 }, { 0, 4, 0 } } }, { { { 1, 0, 2 }, { 0, 5, 0 } } }, { { { 2, 0, 1 }, { 0, 6, 1 } } }, { { { 2, 0, 0 }, { 0, 6, 0 } } }, { { { 2, 0, 1 }, { 0, 7, 0 } } }, { { { 2, 0, 2 }, { 0, 8, 0 } } }, { { { 3, 0, 1 }, { 0, 9, 1 } } }, { { { 3, 0, 0 }, { 0, 9, 0 } } }, { { { 3, 0, 1 }, { 0, 10, 0 } } }, { { { 3, 0, 2 }, { 0, 11, 0 } } }, { { { 4, 0, 1 }, { 0, 12, 1 } } }, { { { 4, 0, 0 }, { 0, 12, 0 } } }, { { { 4, 0, 1 }, { 0, 13, 0 } } }, { { { 4, 0, 2 }, { 0, 14, 0 } } }, { { { 5, 0, 1 }, { 0, 15, 1 } } }, { { { 5, 0, 0 }, { 0, 15, 0 } } }, { { { 5, 0, 1 }, { 0, 16, 0 } } }, { { { 5, 0, 2 }, { 1, 15, 0 } } }, { { { 6, 0, 1 }, { 0, 17, 0 } } }, { { { 6, 0, 0 }, { 0, 18, 0 } } }, { { { 6, 0, 1 }, { 0, 19, 0 } } }, { { { 6, 0, 2 }, { 3, 14, 0 } } }, { { { 7, 0, 1 }, { 0, 20, 0 } } }, { { { 7, 0, 0 }, { 0, 21, 0 } } }, { { { 7, 0, 1 }, { 0, 22, 0 } } }, { { { 7, 0, 2 }, { 4, 15, 0 } } }, { { { 8, 0, 1 }, { 0, 23, 0 } } }, { { { 8, 0, 0 }, { 0, 24, 0 } } }, { { { 8, 0, 1 }, { 0, 25, 0 } } }, { { { 8, 0, 2 }, { 6, 14, 0 } } }, { { { 9, 0, 1 }, { 0, 26, 0 } } }, { { { 9, 0, 0 }, { 0, 27, 0 } } }, { { { 9, 0, 1 }, { 0, 28, 0 } } }, { { { 9, 0, 2 }, { 7, 15, 0 } } }, { { { 10, 0, 1 }, { 0, 29, 0 } } }, { { { 10, 0, 0 }, { 0, 30, 0 } } }, { { { 10, 0, 1 }, { 0, 31, 0 } } }, { { { 10, 0, 2 }, { 9, 14, 0 } } }, { { { 11, 0, 1 }, { 0, 32, 0 } } }, { { { 11, 0, 0 }, { 0, 33, 0 } } }, { { { 11, 0, 1 }, { 2, 30, 0 } } }, { { { 11, 0, 2 }, { 0, 34, 0 } } }, { { { 12, 0, 1 }, { 0, 35, 0 } } }, { { { 12, 0, 0 }, { 0, 36, 0 } } }, { { { 12, 0, 1 }, { 3, 31, 0 } } }, { { { 12, 0, 2 }, { 0, 37, 0 } } }, { { { 13, 0, 1 }, { 0, 38, 0 } } }, { { { 13, 0, 0 }, { 0, 39, 0 } } }, { { { 13, 0, 1 }, { 5, 30, 0 } } }, { { { 13, 0, 2 }, { 0, 40, 0 } } }, { { { 14, 0, 1 }, { 0, 41, 0 } } }, { { { 14, 0, 0 }, { 0, 42, 0 } } }, { { { 14, 0, 1 }, { 6, 31, 0 } } }, { { { 14, 0, 2 }, { 0, 43, 0 } } }, { { { 15, 0, 1 }, { 0, 44, 0 } } }, { { { 15, 0, 0 }, { 0, 45, 0 } } }, { { { 15, 0, 1 }, { 8, 30, 0 } } }, { { { 15, 0, 2 }, { 0, 46, 0 } } }, { { { 16, 0, 2 }, { 0, 47, 0 } } }, { { { 16, 0, 1 }, { 1, 46, 0 } } }, { { { 16, 0, 0 }, { 0, 48, 0 } } }, { { { 16, 0, 1 }, { 0, 49, 0 } } }, { { { 16, 0, 2 }, { 0, 50, 0 } } }, { { { 17, 0, 1 }, { 2, 47, 0 } } }, { { { 17, 0, 0 }, { 0, 51, 0 } } }, { { { 17, 0, 1 }, { 0, 52, 0 } } }, { { { 17, 0, 2 }, { 0, 53, 0 } } }, { { { 18, 0, 1 }, { 4, 46, 0 } } }, { { { 18, 0, 0 }, { 0, 54, 0 } } }, { { { 18, 0, 1 }, { 0, 55, 0 } } }, { { { 18, 0, 2 }, { 0, 56, 0 } } }, { { { 19, 0, 1 }, { 5, 47, 0 } } }, { { { 19, 0, 0 }, { 0, 57, 0 } } }, { { { 19, 0, 1 }, { 0, 58, 0 } } }, { { { 19, 0, 2 }, { 0, 59, 0 } } }, { { { 20, 0, 1 }, { 7, 46, 0 } } }, { { { 20, 0, 0 }, { 0, 60, 0 } } }, { { { 20, 0, 1 }, { 0, 61, 0 } } }, { { { 20, 0, 2 }, { 0, 62, 0 } } }, { { { 21, 0, 1 }, { 8, 47, 0 } } }, { { { 21, 0, 0 }, { 0, 63, 0 } } }, { { { 21, 0, 1 }, { 1, 62, 0 } } }, { { { 21, 0, 2 }, { 1, 63, 0 } } }, { { { 22, 0, 1 }, { 10, 46, 0 } } }, { { { 22, 0, 0 }, { 2, 62, 0 } } }, { { { 22, 0, 1 }, { 2, 63, 0 } } }, { { { 22, 0, 2 }, { 3, 62, 0 } } }, { { { 23, 0, 1 }, { 11, 47, 0 } } }, { { { 23, 0, 0 }, { 3, 63, 0 } } }, { { { 23, 0, 1 }, { 4, 62, 0 } } }, { { { 23, 0, 2 }, { 4, 63, 0 } } }, { { { 24, 0, 1 }, { 13, 46, 0 } } }, { { { 24, 0, 0 }, { 5, 62, 0 } } }, { { { 24, 0, 1 }, { 5, 63, 0 } } }, { { { 24, 0, 2 }, { 6, 62, 0 } } }, { { { 25, 0, 1 }, { 14, 47, 0 } } }, { { { 25, 0, 0 }, { 6, 63, 0 } } }, { { { 25, 0, 1 }, { 7, 62, 0 } } }, { { { 25, 0, 2 }, { 7, 63, 0 } } }, { { { 26, 0, 1 }, { 16, 45, 0 } } }, { { { 26, 0, 0 }, { 8, 62, 0 } } }, { { { 26, 0, 1 }, { 8, 63, 0 } } }, { { { 26, 0, 2 }, { 9, 62, 0 } } }, { { { 27, 0, 1 }, { 16, 48, 0 } } }, { { { 27, 0, 0 }, { 9, 63, 0 } } }, { { { 27, 0, 1 }, { 10, 62, 0 } } }, { { { 27, 0, 2 }, { 10, 63, 0 } } }, { { { 28, 0, 1 }, { 16, 51, 0 } } }, { { { 28, 0, 0 }, { 11, 62, 0 } } }, { { { 28, 0, 1 }, { 11, 63, 0 } } }, { { { 28, 0, 2 }, { 12, 62, 0 } } }, { { { 29, 0, 1 }, { 16, 54, 0 } } }, { { { 29, 0, 0 }, { 12, 63, 0 } } }, { { { 29, 0, 1 }, { 13, 62, 0 } } }, { { { 29, 0, 2 }, { 13, 63, 0 } } }, { { { 30, 0, 1 }, { 16, 57, 0 } } }, { { { 30, 0, 0 }, { 14, 62, 0 } } }, { { { 30, 0, 1 }, { 14, 63, 0 } } }, { { { 30, 0, 2 }, { 15, 62, 0 } } }, { { { 31, 0, 1 }, { 16, 60, 0 } } }, { { { 31, 0, 0 }, { 15, 63, 0 } } }, { { { 31, 0, 1 }, { 24, 46, 0 } } }, { { { 31, 0, 2 }, { 16, 62, 0 } } }, { { { 32, 0, 2 }, { 16, 63, 0 } } }, { { { 32, 0, 1 }, { 17, 62, 0 } } }, { { { 32, 0, 0 }, { 25, 47, 0 } } }, { { { 32, 0, 1 }, { 17, 63, 0 } } }, { { { 32, 0, 2 }, { 18, 62, 0 } } }, { { { 33, 0, 1 }, { 18, 63, 0 } } }, { { { 33, 0, 0 }, { 27, 46, 0 } } }, { { { 33, 0, 1 }, { 19, 62, 0 } } }, { { { 33, 0, 2 }, { 19, 63, 0 } } }, { { { 34, 0, 1 }, { 20, 62, 0 } } }, { { { 34, 0, 0 }, { 28, 47, 0 } } }, { { { 34, 0, 1 }, { 20, 63, 0 } } }, { { { 34, 0, 2 }, { 21, 62, 0 } } }, { { { 35, 0, 1 }, { 21, 63, 0 } } }, { { { 35, 0, 0 }, { 30, 46, 0 } } }, { { { 35, 0, 1 }, { 22, 62, 0 } } }, { { { 35, 0, 2 }, { 22, 63, 0 } } }, { { { 36, 0, 1 }, { 23, 62, 0 } } }, { { { 36, 0, 0 }, { 31, 47, 0 } } }, { { { 36, 0, 1 }, { 23, 63, 0 } } }, { { { 36, 0, 2 }, { 24, 62, 0 } } }, { { { 37, 0, 1 }, { 24, 63, 0 } } }, { { { 37, 0, 0 }, { 32, 47, 0 } } }, { { { 37, 0, 1 }, { 25, 62, 0 } } }, { { { 37, 0, 2 }, { 25, 63, 0 } } }, { { { 38, 0, 1 }, { 26, 62, 0 } } }, { { { 38, 0, 0 }, { 32, 50, 0 } } }, { { { 38, 0, 1 }, { 26, 63, 0 } } }, { { { 38, 0, 2 }, { 27, 62, 0 } } }, { { { 39, 0, 1 }, { 27, 63, 0 } } }, { { { 39, 0, 0 }, { 32, 53, 0 } } }, { { { 39, 0, 1 }, { 28, 62, 0 } } }, { { { 39, 0, 2 }, { 28, 63, 0 } } }, { { { 40, 0, 1 }, { 29, 62, 0 } } }, { { { 40, 0, 0 }, { 32, 56, 0 } } }, { { { 40, 0, 1 }, { 29, 63, 0 } } }, { { { 40, 0, 2 }, { 30, 62, 0 } } }, { { { 41, 0, 1 }, { 30, 63, 0 } } }, { { { 41, 0, 0 }, { 32, 59, 0 } } }, { { { 41, 0, 1 }, { 31, 62, 0 } } }, { { { 41, 0, 2 }, { 31, 63, 0 } } }, { { { 42, 0, 1 }, { 32, 61, 0 } } }, { { { 42, 0, 0 }, { 32, 62, 0 } } }, { { { 42, 0, 1 }, { 32, 63, 0 } } }, { { { 42, 0, 2 }, { 41, 46, 0 } } }, { { { 43, 0, 1 }, { 33, 62, 0 } } }, { { { 43, 0, 0 }, { 33, 63, 0 } } }, { { { 43, 0, 1 }, { 34, 62, 0 } } }, { { { 43, 0, 2 }, { 42, 47, 0 } } }, { { { 44, 0, 1 }, { 34, 63, 0 } } }, { { { 44, 0, 0 }, { 35, 62, 0 } } }, { { { 44, 0, 1 }, { 35, 63, 0 } } }, { { { 44, 0, 2 }, { 44, 46, 0 } } }, { { { 45, 0, 1 }, { 36, 62, 0 } } }, { { { 45, 0, 0 }, { 36, 63, 0 } } }, { { { 45, 0, 1 }, { 37, 62, 0 } } }, { { { 45, 0, 2 }, { 45, 47, 0 } } }, { { { 46, 0, 1 }, { 37, 63, 0 } } }, { { { 46, 0, 0 }, { 38, 62, 0 } } }, { { { 46, 0, 1 }, { 38, 63, 0 } } }, { { { 46, 0, 2 }, { 47, 46, 0 } } }, { { { 47, 0, 1 }, { 39, 62, 0 } } }, { { { 47, 0, 0 }, { 39, 63, 0 } } }, { { { 47, 0, 1 }, { 40, 62, 0 } } }, { { { 47, 0, 2 }, { 48, 46, 0 } } }, { { { 48, 0, 2 }, { 40, 63, 0 } } }, { { { 48, 0, 1 }, { 41, 62, 0 } } }, { { { 48, 0, 0 }, { 41, 63, 0 } } }, { { { 48, 0, 1 }, { 48, 49, 0 } } }, { { { 48, 0, 2 }, { 42, 62, 0 } } }, { { { 49, 0, 1 }, { 42, 63, 0 } } }, { { { 49, 0, 0 }, { 43, 62, 0 } } }, { { { 49, 0, 1 }, { 48, 52, 0 } } }, { { { 49, 0, 2 }, { 43, 63, 0 } } }, { { { 50, 0, 1 }, { 44, 62, 0 } } }, { { { 50, 0, 0 }, { 44, 63, 0 } } }, { { { 50, 0, 1 }, { 48, 55, 0 } } }, { { { 50, 0, 2 }, { 45, 62, 0 } } }, { { { 51, 0, 1 }, { 45, 63, 0 } } }, { { { 51, 0, 0 }, { 46, 62, 0 } } }, { { { 51, 0, 1 }, { 48, 58, 0 } } }, { { { 51, 0, 2 }, { 46, 63, 0 } } }, { { { 52, 0, 1 }, { 47, 62, 0 } } }, { { { 52, 0, 0 }, { 47, 63, 0 } } }, { { { 52, 0, 1 }, { 48, 61, 0 } } }, { { { 52, 0, 2 }, { 48, 62, 0 } } }, { { { 53, 0, 1 }, { 56, 47, 0 } } }, { { { 53, 0, 0 }, { 48, 63, 0 } } }, { { { 53, 0, 1 }, { 49, 62, 0 } } }, { { { 53, 0, 2 }, { 49, 63, 0 } } }, { { { 54, 0, 1 }, { 58, 46, 0 } } }, { { { 54, 0, 0 }, { 50, 62, 0 } } }, { { { 54, 0, 1 }, { 50, 63, 0 } } }, { { { 54, 0, 2 }, { 51, 62, 0 } } }, { { { 55, 0, 1 }, { 59, 47, 0 } } }, { { { 55, 0, 0 }, { 51, 63, 0 } } }, { { { 55, 0, 1 }, { 52, 62, 0 } } }, { { { 55, 0, 2 }, { 52, 63, 0 } } }, { { { 56, 0, 1 }, { 61, 46, 0 } } }, { { { 56, 0, 0 }, { 53, 62, 0 } } }, { { { 56, 0, 1 }, { 53, 63, 0 } } }, { { { 56, 0, 2 }, { 54, 62, 0 } } }, { { { 57, 0, 1 }, { 62, 47, 0 } } }, { { { 57, 0, 0 }, { 54, 63, 0 } } }, { { { 57, 0, 1 }, { 55, 62, 0 } } }, { { { 57, 0, 2 }, { 55, 63, 0 } } }, { { { 58, 0, 1 }, { 56, 62, 1 } } }, { { { 58, 0, 0 }, { 56, 62, 0 } } }, { { { 58, 0, 1 }, { 56, 63, 0 } } }, { { { 58, 0, 2 }, { 57, 62, 0 } } }, { { { 59, 0, 1 }, { 57, 63, 1 } } }, { { { 59, 0, 0 }, { 57, 63, 0 } } }, { { { 59, 0, 1 }, { 58, 62, 0 } } }, { { { 59, 0, 2 }, { 58, 63, 0 } } }, { { { 60, 0, 1 }, { 59, 62, 1 } } }, { { { 60, 0, 0 }, { 59, 62, 0 } } }, { { { 60, 0, 1 }, { 59, 63, 0 } } }, { { { 60, 0, 2 }, { 60, 62, 0 } } }, { { { 61, 0, 1 }, { 60, 63, 1 } } }, { { { 61, 0, 0 }, { 60, 63, 0 } } }, { { { 61, 0, 1 }, { 61, 62, 0 } } }, { { { 61, 0, 2 }, { 61, 63, 0 } } }, { { { 62, 0, 1 }, { 62, 62, 1 } } }, { { { 62, 0, 0 }, { 62, 62, 0 } } }, { { { 62, 0, 1 }, { 62, 63, 0 } } }, { { { 62, 0, 2 }, { 63, 62, 0 } } }, { { { 63, 0, 1 }, { 63, 63, 1 } } }, { { { 63, 0, 0 }, { 63, 63, 0 } } } }; Makefile0000644000076500000240000000373313061741227012245 0ustar roettgerstaffinclude config VER = 1.15 SOVER = 0 SRC = alpha.cpp clusterfit.cpp colourblock.cpp colourfit.cpp colourset.cpp maths.cpp rangefit.cpp singlecolourfit.cpp squish.cpp HDR = alpha.h clusterfit.h colourblock.h colourfit.h colourset.h maths.h rangefit.h singlecolourfit.h squish.h HDR += config.h simd.h simd_float.h simd_sse.h simd_ve.h singlecolourlookup.inl OBJ = $(SRC:%.cpp=%.o) SOLIB = libsquish.so.$(SOVER) LIB = $(SOLIB).0 CPPFLAGS += -fPIC LIBA = libsquish.a .PHONY: all install uninstall docs tgz clean all: $(LIB) $(LIBA) docs libsquish.pc install: $(LIB) $(LIBA) libsquish.pc $(INSTALL_DIRECTORY) $(INSTALL_DIR)/include $(INSTALL_DIR)/$(LIB_PATH) $(INSTALL_FILE) squish.h $(INSTALL_DIR)/include $(INSTALL_FILE) $(LIBA) $(INSTALL_DIR)/$(LIB_PATH) ifneq ($(USE_SHARED),0) $(INSTALL_FILE) $(LIB) $(INSTALL_DIR)/$(LIB_PATH) ln -s $(LIB) $(INSTALL_DIR)/$(LIB_PATH)/$(SOLIB) ln -s $(LIB) $(INSTALL_DIR)/$(LIB_PATH)/libsquish.so $(INSTALL_DIRECTORY) $(INSTALL_DIR)/$(LIB_PATH)/pkgconfig $(INSTALL_FILE) libsquish.pc $(INSTALL_DIR)/$(LIB_PATH)/pkgconfig endif uninstall: $(RM) $(INSTALL_DIR)/include/squish.h $(RM) $(INSTALL_DIR)/$(LIB_PATH)/$(LIBA) -$(RM) $(INSTALL_DIR)/$(LIB_PATH)/$(LIB) -$(RM) $(INSTALL_DIR)/$(LIB_PATH)/$(SOLIB) -$(RM) $(INSTALL_DIR)/$(LIB_PATH)/libsquish.so -$(RM) $(INSTALL_DIR)/$(LIB_PATH)/pkgconfig/libsquish.pc $(LIB): $(OBJ) ifneq ($(USE_SHARED),0) $(CXX) $(LDFLAGS) -shared -Wl,-soname,$(SOLIB) -o $@ $(OBJ) endif $(LIBA): $(OBJ) $(AR) cr $@ $? @ranlib $@ docs: $(SRC) $(HDR) @if [ -x "`command -v doxygen`" ]; then doxygen; fi libsquish.pc: libsquish.pc.in @sed 's|@PREFIX@|$(PREFIX)|;s|@LIB_PATH@|$(LIB_PATH)|' $@.in > $@ tgz: clean tar zcf libsquish-$(VER).tgz $(SRC) $(HDR) Makefile config CMakeLists.txt CMakeModules libSquish.* README.txt LICENSE.txt ChangeLog.txt Doxyfile libsquish.pc.in extra --exclude \*.svn\* %.o: %.cpp $(CXX) $(CPPFLAGS) -I. $(CXXFLAGS) -o $@ -c $< clean: $(RM) $(OBJ) $(LIB) $(LIBA) libsquish.pc @-$(RM) -rf docs config0000644000076500000240000000142613061741432011770 0ustar roettgerstaff# config file for GNUmake # define to 1 to use OpenMP parallelization USE_OPENMP ?= 0 # define to 1 to install shared library USE_SHARED ?= 0 # define to 1 to use Altivec instructions USE_ALTIVEC ?= 0 # define to 1 to use SSE2 instructions USE_SSE ?= 0 # default flags CXXFLAGS ?= -O2 -Wall ifeq ($(USE_OPENMP),1) CPPFLAGS += -DSQUISH_USE_OPENMP CXXFLAGS += -fopenmp endif ifeq ($(USE_ALTIVEC),1) CPPFLAGS += -DSQUISH_USE_ALTIVEC=1 CXXFLAGS += -maltivec endif ifeq ($(USE_SSE),1) CPPFLAGS += -DSQUISH_USE_SSE=2 CXXFLAGS += -msse endif # install options INSTALL = install INSTALL_FILE = $(INSTALL) -p -m 644 INSTALL_PROGRAM = $(INSTALL) -p -m 755 INSTALL_DIRECTORY = $(INSTALL) -d -m 755 # where should we install to INSTALL_DIR ?= /usr/local LIB_PATH ?= lib CMakeLists.txt0000644000076500000240000000636113061717135013346 0ustar roettgerstaff# cmake build file for squish # by Stefan Roettger (snroettg@gmail.com) # updated by Simon Brown (si@sjbrown.co.uk) # features: # uses -fopenmp when available # use BUILD_SQUISH_WITH_OPENMP to override # Xcode: builds universal binaries, uses SSE2 on i386 and Altivec on ppc # Unix and VS: SSE2 support is enabled by default # use BUILD_SQUISH_WITH_SSE2 and BUILD_SQUISH_WITH_ALTIVEC to override PROJECT(squish) CMAKE_MINIMUM_REQUIRED(VERSION 2.8.3) OPTION(BUILD_SQUISH_WITH_OPENMP "Build with OpenMP." ON) OPTION(BUILD_SQUISH_WITH_SSE2 "Build with SSE2." ON) OPTION(BUILD_SQUISH_WITH_ALTIVEC "Build with Altivec." OFF) OPTION(BUILD_SHARED_LIBS "Build shared libraries." OFF) OPTION(BUILD_SQUISH_EXTRA "Build extra source code." OFF) IF (BUILD_SQUISH_WITH_OPENMP) FIND_PACKAGE(OpenMP) IF (OPENMP_FOUND) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") ADD_DEFINITIONS(-DSQUISH_USE_OPENMP) ENDIF() ENDIF() IF (CMAKE_GENERATOR STREQUAL "Xcode") SET(CMAKE_OSX_ARCHITECTURES "i386;ppc") ELSE (CMAKE_GENERATOR STREQUAL "Xcode") IF (BUILD_SQUISH_WITH_SSE2 AND NOT WIN32) ADD_DEFINITIONS(-DSQUISH_USE_SSE=2 -msse2) ENDIF (BUILD_SQUISH_WITH_SSE2 AND NOT WIN32) IF (BUILD_SQUISH_WITH_ALTIVEC AND NOT WIN32) ADD_DEFINITIONS(-DSQUISH_USE_ALTIVEC=1 -maltivec) ENDIF (BUILD_SQUISH_WITH_ALTIVEC AND NOT WIN32) ENDIF (CMAKE_GENERATOR STREQUAL "Xcode") SET(SQUISH_HDRS squish.h ) SET(SQUISH_SRCS alpha.cpp alpha.h clusterfit.cpp clusterfit.h colourblock.cpp colourblock.h colourfit.cpp colourfit.h colourset.cpp colourset.h maths.cpp maths.h rangefit.cpp rangefit.h simd.h simd_float.h simd_sse.h simd_ve.h singlecolourfit.cpp singlecolourfit.h singlecolourlookup.inl squish.cpp ) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) ADD_LIBRARY(squish ${SQUISH_SRCS} ${SQUISH_HDRS}) SET_TARGET_PROPERTIES( squish PROPERTIES PUBLIC_HEADER "${SQUISH_HDRS}" VERSION 0.0 SOVERSION 0.0 DEBUG_POSTFIX "d" XCODE_ATTRIBUTE_GCC_PREPROCESSOR_DEFINITIONS "$(SQUISH_CPP_$(CURRENT_ARCH))" XCODE_ATTRIBUTE_OTHER_CFLAGS "$(SQUISH_CFLAGS_$(CURRENT_ARCH))" XCODE_ATTRIBUTE_SQUISH_CPP_i386 "SQUISH_USE_SSE=2" XCODE_ATTRIBUTE_SQUISH_CFLAGS_i386 "" XCODE_ATTRIBUTE_SQUISH_CPP_ppc "SQUISH_USE_ALTIVEC=1" XCODE_ATTRIBUTE_SQUISH_CFLAGS_ppc "-maltivec" ) IF (BUILD_SQUISH_EXTRA) SET(SQUISHTEST_SRCS extra/squishtest.cpp) ADD_EXECUTABLE(squishtest ${SQUISHTEST_SRCS}) SET_TARGET_PROPERTIES(squishtest PROPERTIES DEBUG_POSTFIX "d") TARGET_LINK_LIBRARIES(squishtest squish) SET(SQUISHPNG_SRCS extra/squishpng.cpp) FIND_PACKAGE(PNG) IF (PNG_FOUND) SET(CMAKE_PLATFORM_IMPLICIT_INCLUDE_DIRECTORIES) INCLUDE_DIRECTORIES(${PNG_INCLUDE_DIR}) ADD_EXECUTABLE(squishpng ${SQUISHPNG_SRCS}) SET_TARGET_PROPERTIES(squishpng PROPERTIES DEBUG_POSTFIX "d") TARGET_LINK_LIBRARIES(squishpng squish ${PNG_LIBRARIES}) ENDIF (PNG_FOUND) ENDIF (BUILD_SQUISH_EXTRA) INSTALL( TARGETS squish LIBRARY DESTINATION lib ARCHIVE DESTINATION lib PUBLIC_HEADER DESTINATION include ) CMakeModules/0000755000076500000240000000000012771161730013112 5ustar roettgerstaffCMakeModules/.svn/0000755000076500000240000000000013061741574014001 5ustar roettgerstaffCMakeModules/.svn/all-wcprops0000444000076500000240000000033212771161730016160 0ustar roettgerstaffK 25 svn:wc:ra_dav:version-url V 48 /p/libsquish/code/!svn/ver/67/trunk/CMakeModules END FindlibSquish.cmake K 25 svn:wc:ra_dav:version-url V 68 /p/libsquish/code/!svn/ver/67/trunk/CMakeModules/FindlibSquish.cmake END CMakeModules/.svn/entries0000444000076500000240000000060613061741230015362 0ustar roettgerstaff8 dir 103 https://svn.code.sf.net/p/libsquish/code/trunk/CMakeModules https://svn.code.sf.net/p/libsquish/code 2015-10-08T08:01:47.212130Z 67 roettger svn:special svn:externals svn:needs-lock d1da18a7-0d7c-4e8b-a45e-7863643f1f45 FindlibSquish.cmake file 2016-09-23T08:12:08.000000Z 4198fd5097a17032a5aa39355b11abc8 2015-10-08T08:01:47.212130Z 67 roettger has-props CMakeModules/.svn/format0000444000076500000240000000000212771161730015177 0ustar roettgerstaff8 CMakeModules/.svn/prop-base/0000755000076500000240000000000012771161730015666 5ustar roettgerstaffCMakeModules/.svn/prop-base/FindlibSquish.cmake.svn-base0000444000076500000240000000004212771161730023143 0ustar roettgerstaffK 13 svn:eol-style V 6 native END CMakeModules/.svn/props/0000755000076500000240000000000012771161730015141 5ustar roettgerstaffCMakeModules/.svn/text-base/0000755000076500000240000000000012771161730015672 5ustar roettgerstaffCMakeModules/.svn/text-base/FindlibSquish.cmake.svn-base0000444000076500000240000000113312771161730023151 0ustar roettgerstaff# Defines # LIBSQUISH_FOUND # LIBSQUISH_INCLUDE_DIR # LIBSQUISH_LIBRARIES FIND_PATH(LIBSQUISH_INCLUDE_DIR squish.h PATHS . squish .. ../squish DOC "Directory containing libSquish headers") FIND_LIBRARY(LIBSQUISH_LIBRARY NAMES squish libsquish PATHS . squish .. ../squish PATH_SUFFIXES lib lib64 release minsizerel relwithdebinfo DOC "Path to libSquish library") SET(LIBSQUISH_LIBRARIES ${LIBSQUISH_LIBRARY}) IF (LIBSQUISH_LIBRARY AND LIBSQUISH_INCLUDE_DIR) SET(LIBSQUISH_FOUND TRUE) MESSAGE(STATUS "Found libSquish: ${LIBSQUISH_LIBRARY}") ENDIF (LIBSQUISH_LIBRARY AND LIBSQUISH_INCLUDE_DIR) CMakeModules/.svn/tmp/0000755000076500000240000000000013061741230014566 5ustar roettgerstaffCMakeModules/.svn/tmp/prop-base/0000755000076500000240000000000012771161730016466 5ustar roettgerstaffCMakeModules/.svn/tmp/props/0000755000076500000240000000000012771161730015741 5ustar roettgerstaffCMakeModules/.svn/tmp/text-base/0000755000076500000240000000000012771161730016472 5ustar roettgerstaffCMakeModules/FindlibSquish.cmake0000644000076500000240000000113312771161730016656 0ustar roettgerstaff# Defines # LIBSQUISH_FOUND # LIBSQUISH_INCLUDE_DIR # LIBSQUISH_LIBRARIES FIND_PATH(LIBSQUISH_INCLUDE_DIR squish.h PATHS . squish .. ../squish DOC "Directory containing libSquish headers") FIND_LIBRARY(LIBSQUISH_LIBRARY NAMES squish libsquish PATHS . squish .. ../squish PATH_SUFFIXES lib lib64 release minsizerel relwithdebinfo DOC "Path to libSquish library") SET(LIBSQUISH_LIBRARIES ${LIBSQUISH_LIBRARY}) IF (LIBSQUISH_LIBRARY AND LIBSQUISH_INCLUDE_DIR) SET(LIBSQUISH_FOUND TRUE) MESSAGE(STATUS "Found libSquish: ${LIBSQUISH_LIBRARY}") ENDIF (LIBSQUISH_LIBRARY AND LIBSQUISH_INCLUDE_DIR) libSquish.png0000644000076500000240000004276312771161730013266 0ustar roettgerstaff‰PNG  IHDRH3 #ðsBIT|dˆ pHYsttÞfxtEXtSoftwarewww.inkscape.org›î< IDATxœìÝyxÕ-ðs{©[Õ-ɲä[^d[xÀ1‹Øì;ìûbÀ6^df&ׯ6Iúõ@ J“¼L&3/L™ÉË› Ì„ Y†ìì0@ØÌæx·%kénµZ½Ü÷‡ZÂK­–nU÷ù}_}’-W÷±–VºU÷ ­5ˆˆˆˆˆˆð™@DDDDDä,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDy,HDDDDDDyÓˆˆˆˆ¨|455Y!€Èo¾ÞÿðŸ?îc½ÎHèÊo}ï+¥º‡çG¥@h­Mg """"—ijj yˆ­@(—Ë…3™Le.—«ÌårZëJô”žGá!¤Ïç³}>Ÿåóù,!„?—Ëe3™L6›Íf3™L®÷XTküûú€÷ñ¡÷5är¹|L@ €@ €/žÏçóй\.›ËåÒZën­uZkêÝÐS¦’º„1¿ßßöûýþv±mñÿY)•ª¯ /$"""¢ÖÔÔT `€ZPt2™Ìèt:=6—ËÑZ× !ªý~ÿ¿ß_á÷ûL&“éîîN'“ÉL2™D"‘‰DŸH$¬T*èîîö§ÓinëîîF:F&“é{¿·Ø˜ „€ßïG @0ì-Sm½oY¤”R¶í¬mÛiÇqÒ¶mgÇÑRJ-¥–eù,Ë ƒÁ€Ïçóçr¹îl6›Ìf³mZëýöúýþ]–eíôù|û´h>ð­R*aì“B‡Ä‚DDDDäQMMM#ÐS~&˜Íf뻺ºfh­ëý~ÿx˲j3™L.‹u' $ _"‘ðÇãqÙÙÙéO&“èììD2™Äï§R)ðqàz‹U(B(B8î}_WVV¦*++»+**²pÇç8NÐï÷ûó¥ª=—˵Ø)¥üs0| À{ùí/J©ŒÙÿ]ù`A""""r©¦¦¦J ŽÎår³S©ÔŒ\.7Õçóƒ£r¹œŽÅb©ÖÖV´´´Xû÷ïwÚÚÚD[[ÚÛÛÑÞÞŽL†ÇÕngÛv_©ª¬¬Dmm-F3fLWmm­¯²²ÒÎf³ñt:½]ñ¶mÛ¯úýþ·ñAÚ¥”âA}‘° ”¿×§·ÍH&“'˜ 'ær¹ÀþýûS{öì ìÝ»7ÜÚÚêë-?mmm,?e¤¢¢555¨­­EMM3fLçèÑ£Ó555Û¶­îîî–l6»UJù»`0ø[O)¥šMçö"$"""¢!ÖÔÔBO jÈ— ¹fƒÁIZë`kkkjÏž=þÝ»wWìÛ·Ï×ÜÜŒææf¤R¼ïŸŽÌï÷£ºº555?~|îè£î˜4iRPÏf³ ‡ÃOø€W”RYÓyÝŽ‰ˆˆˆ¨HšššjÌ0+•JÍK§Óó‚Á`ƒ"ÔÚÚÚµwï^ÿ®]»Âûöíó÷– ®®.Ó±©DUWWcòäɘ:uj²¡¡!5räHÙÝÝýf0ü•eY¿AÏ(Ó>Ó9݆‰ˆˆˆh€šššÆ#_„ºººNÌf³sƒÁà´\.çß·o_jÇŽrçΡ={ö`Ïž=H$8Q™0aÂÔ××çb“'Oˆg³Ù§Âáðø=zF™Êº ° BSS“Àd³ÌJ&“'i­³,«¾»»;»wïÞôŽ;œ]»vÙ½E(™LNM40#GŽìeêš1cFª²²Ò—N§ÿ …ðk¥ÔÓ‡ €¦¦& `~&“YÔÝÝ}±”rV2™LíÝ»7»}ûöЮ]»¬={ö`ïÞ½%o–eÁ¶í¾õ€Ü,Ë‚ßï‡ßï‡ÏçƒÏçûÈšB½kõ¾íý7½û¸ï[ gØ\.‡l6û‘·Ùl™L¦ïýÞ?¸ø±ÞýÒé4R©Ôa·l–·åô ‡ÃhhhÀŒ3:gΜ™µ,+Ëåžtçß<®”j3q¨± QYjjj²œ’Éd¥R©‹,ËšµgÏžÔk¯½VñöÛo¶oߎt:m:fA¤”¨¨¨@ee%***‡ûÊM8î[ŸÇqœ¾¿ƒƒðûýB@k !Dß«½E§· }¸äôþÛ·ÃýýÇ},—ËAk}Øíã>Þû±—¬Þ‚t`‰êý·Bè+[½‹Ü¦R©ƒÖ‡ŠÇã}kD%“IÄb1ÄãqÄb1$“É’]7ªºº 8î¸ã:¦M›Ìd2¯;Žó!Ä(¥Þ1o(° QÙÈß;ta"‘XjYÖ)ûöíë~ýõ×Ã[¶l lݺÕÕÓfK)û OïÛªª*ÔÖÖbäÈ‘¨¬¬D(‚”²oŸÞBÓ[„lÛ>h„çÀQžßï- åäãS‡z¿wÄ)™L¢«« étº¯d¥Óé¾âÔÞÞŽ––´··T¤b±:;;=[¦ü~?¦L™‚9sæ$;î¸t0ìðù|?²,ëJ©÷Mç+$"""*iMMM'§ÓéË2™ÌµBˆq¯¿þº~ùå—Ã[¶lqÍ¥rBTWWcÔ¨Q¨­­Å˜1cPWW‡êêj„B!X–Õ÷ïzKO½#:½[0ì»\†OïÈÓ["‘@<ï+S¹\®¯Luuu!‹a×®]صkZZZÐÜÜŒ––Wõ=sçÎÍœqÆÝZë'Çù‚RêÓ¹‹‰ˆˆˆJNSSÓ„l6{K&“iL$¡—^z)ôç?ÿ9°mÛ6cgïý~?FŽÙW‚ÆqãÆ¡¦¦Žã,ËBUUUßßX~ÊqT§TX¦’É$:::ÐÚÚÚw©^&“A{{;vïÞíÛ·÷§––WN  1þüÜyç—ôù|Ï9Žs§Rê¦sЉˆˆˆJBþž¢K“Éäí~¿Þ /¼ žzê){ÇŽÚò,ÔÕÕa„ ˜4iŽ:ê(TWW÷•ÇqP]]#FÀqœ¾"ÄD½z/×K&“ˆÇãØ¿?‰Dß½S±X {÷îÅöíÛ±mÛ6lÛ¶ ¦cÃï÷ã„NÐ\pA\JùŽã8«”RÏšÎ5P,HDDDäiMMMál6Û˜Íf7íܹÓÿ‡?ü¡êÕW_–Ë”‚Á êêê0qâD}ôј4iÇeY=z4ª««ûJPïerDƒ‘ÍfûÊS"‘ÀîÝ»ûÊÓîÝ»ñÖ[oaë֭ؾ};b±˜‘ŒBÌ™3W]uU< F7mÚÔd$HXˆˆˆÈ“šššF¦ÓéÏj­?óÚk¯ùžxâ‰ð¾}û†ìù‚Á Æ &`úôé˜4iB¡‚Á FÚÚZTVVö].G4œÒétß½‹g2™”¦x<>l™*++qóÍ7ÇÇŒó”mÛ—)¥<±b2 yJSSÓØT*u§bù‹/¾èûÕ¯~å´¶¶ÉsM˜0ÇwæÍ›‡ÊÊJƒAÔÖÖbÔ¨Q}³Æ¹Uww÷A¥©³³éto½õž{î9lÙ²eȧ²÷ù|¸âŠ+ºŽ?þøçmÛ>[)åú¹óYˆˆˆÈ3î»ï¾+ÒéôƒO=õ”ýä“OZž„Èï÷£¡¡óæÍÃ1Ç)%&Nœˆ£Ž: áp˜÷ ‘ç¥R)ìß¿ï½÷:;;±mÛ6<óÌ3xíµ×H ÍË–-K644üÂqœË”R®. ,HDDDäzMMMd2ù½ÎÎÎKz衊;wí±ÇÁ¬Y³pòÉ'cÊ”)°mõõõ=zôAk •š\.‡ýû÷ã/ù Z[[±ÿ~<óÌ3xå•WÐÜÜ\ÔçòûýX½zug]]ÝÝ›7o¾§¨^d,HDDDäzwÝu×wß}÷Ýk¿ÿýÙlQ³¡¡K–,Á„ PYY‰úúzÔÔÔ åñ‰¼DkŽŽìܹ»víB"‘À/~ñ <ûì³E» ¯ººJ©)奔™$ú¯DDDäj÷ÜsÏÚx<~Í~ðƒA—#ŸÏ‡¹sçbÉ’%¨©©ÁìÙ³1jÔ(^:GeO#F`Ĉ˜5kâñ8Ƈ‹.ºüãñä“Oz‚‡¶¶6¼ôÒKÁN8á³þWQ‚Ž ‘k555U¤Óé}÷ÝwŸ=؉Ƈ›nº uuu˜5kª««‹”’¨tuuuáwÞÁŽ;ðè£â™gžÔãUUUaÆ ®Eâ¹Ù‰{öìIµ¶¶Ú…>€]t,X€9sæ`ìØ±ÅÌGTÒlÛÆ1ǃ)S¦  áÔSOŃ>Xð´xï½÷ôÌ™3ÏðÓâ¦-ŸéDDDD‡“Ëåæ¿ýöÛƒšKûÚk¯Å\€3Î8ƒåˆ¨@¡P§Ÿ~:.\ˆÛo¿}PSÜoݺµ"›ÍžTÄxEÅ‚DDDD®•L&ÏÙºuk°ÐýÏ:ë,ÌŸ?'Ÿ|2‚Á‚†ˆÐ3[__9sæ`ݺu?ÎŽ;üÉdòŒ"F+*$"""r-ŸÏ7cÏž=ïÖYgaÞ¼yðûýELETÞ¦M›†1cÆ`üøñí¿sçN㊫hXˆˆˆÈµr¹\¬ÐµˆFŒÇq‡‹œŠˆÆŽ‹£>º }‰@e‘# ¹YK¡'‹!—Ëm "ú@kk+ ÝÕZC¸xn}$"""r-!ľBoÏårxã7ðÎ;ï9Qy‹ÅbH$xûí· ÚßíË qšo"""r-¿ß¿{0³eýèG?Âĉá8&Ož\ÄdD婳³O?ý4|ðAd2™‚ƒ#HDDDD²,kW8.øts2™Ä7¾ñ ¼ôÒKxþùçy¹Q´Öغu+þøÇ?âá‡Æ–-[ ~,˲Ëå\ûÃÈ$"""r-!ÄõõõFúííí¸çž{pÁ ­­ ³f͸qãàâØD®ÒÞÞŽW^yï¾û.zè!´µµ êñFŒt:½·HñŠŽ‰ˆˆˆÜìד'O–>Ÿ¹\®àÉd2øéOŠçŸW]u&NœˆiÓ¦aâĉœœè0š››ñú믣½½=öžþù¢=$^,HDDDäj@àgsæÌi|â‰'ª‹ý؉DO?ý4ž~úiƒA̘1'žx"f̘)%&OžŒ1cÆ`03é¹M&“AKK ¶nÝŠŽŽìÙ³O?ý4þüç?£½½}ÈŸÿ˜cŽI !ò'* ¹ÝÓ£F²lÛFWW×=I:Æ«¯¾ŠW_}BÔ××cîܹ˜;w.ÇAuu5ÆŽ‹ÊÊJTTTÀçãdÀä ÉdØ¿?öíÛ‡T*…wÞyÏ>û,Þ|óÍ!ý¹ú°ÚÚZH)»”R…-¢4 XˆˆˆÈÕ”R™»îºëg§œrÊe¿ýío‡åØEk÷Þ{ï½÷yäŒ5 “'OÆÔ©S1mÚ4Œ9>Ÿï Ò‡YšÈ¸d2‰X,ÖW†º»»‘L&±mÛ6¼õÖ[ضm¶mÛ†l6k$ߌ3´Öú§Fž¼ŸXˆˆˆÈõÇY¿hÑ¢ÅÏ<óLÅpžíîÕÜÜŒæææ¾Y¼|>F & ¡¡S§Ní½ñ#GŽì+M¡Pˆ¥‰†„Ö©Tª¯ íÝ»·¯ mß¾½¯ íܹ©TÊtÜ>Ç{l‡mÛšÎñqD1g¤ ÷"z1€p»oÑ:Rœù=NˆèƸûÛZGž+fž#Dt€†ëù Iè°À{ZGÌœ#¢!s÷ÝwûOúÓÍ?ûÙϤé,‡âóù0vìXÔÕÕ¡¡¡S¦LÁˆ# „@0DEEjjj …à8ÇA ÀsÕtx¹\]]]H&“H&“hkkC{{;R©´ÖH&“عs'Þ|óMlÛ¶ ;vìpUú0¿ß»îº«+ ŽVJÅMç9þT–Ÿo˜Tྀ©Ç>Yà¾ÿ`Ø € |uŸÏ ’BD_AÏ÷ë¿xRëHá ¨‘+ضýùÓN;méïÿ{ÙÑÑa:ÎGär9ìÚµ »víÂsÏ}ð2 …P[[‹Q£Fõ:3UUUðûýðù|…B¨©©Aeee_yâ,zå!›Íö ÎÎN´´´ #Nè™H¤¥¥Û·oÇž={ÐÜÜŒ––´µµuêíá0eʤÓé×7mÚäÚr° Qirœ’ßÖØ)Dô~hIMFDSJí»çž{¾¾xñâ¿ùÑ~ä™iå:;;ÑÙÙ‰mÛ¶}äcRJÔÖÖö¨ºº:uÔQ¨®®F0ÐsÖ]J‰P(„ÊÊJض ˲ú¶`0Èõ›\Fkt:îîî¾-•J!#‘H «« ™LZkär9Äb1ìÛ·Û·oǾ}ûúJP,3ý_)ª3Î8#fÛöwMç8$"*ãÜ`¹Ñe¼T”È»‚Áà—?þøÛ~ó›ß„öìÙc:Π¥R)ìܹ;wîüÈÇ*++û¶ŠŠ TVV¢¦¦555¨ªªB8†”B=eʲ¬¾2Õ;Õ[¢ü~?@ßÈ™ÖÙlÙl™L¦ïmoé‰Åbèìì<¨ôè»(‹¡­­ ÍÍÍèèè@<G,ëÛLÜSgB]]¦Nšôù|ß1åHXˆ¨œÌðK!¢çkyÖt"8¥Tü¾ûî»eåÊ•ßÿÚ×¾V‘L&MG2™L­­­hmm=â¿ }ª¢¢UUU}÷<ÕÔÔ ¢¢RʃʒÏçë;˜BÀçóÁï÷# " BJÙ·Oo©:°` !Ú|>ßGþîÃ[±ô޼h­¸år9är¹ƒ N6›E:FWWR©Òé4Òé42™Lß¿ïý¼ô¤KQ2™Dkk+ZZZ*=½oË¥ô Ä¥—^ÚaYÖz¥T·é,G‚DDå¦ÀÏ…ˆÎÐ:Òl:  Üúõëýâ¿øµ[n¹åo¾ýíoWôÌ–³L&ƒ¶¶6´µµ h¿`0Û¶ûÊЇ7Û¶á8***š\²¬¾’uàv¤¢Ô«{g>¼ÿèÃeèÃŨ· uuu!‘Hôm©Tê ­·0¸yí>7:þøãsãÇß'„xØt–þ`A"¢rTà.ôÜŸDDtçwFîºë®y—^zé¹<òˆc:WõŽœ ç½.ŽV}ø-€¾Rs`Á9pT‡¼eôèѸúê«RÊK”Ržø"òâS"*W· c:ÎqœkæÍ›·mþüùœÖßCz/YëîîîÑé½O§­­ H$H&“H¥R}—½‘÷X–…[o½5fYÖZ¥Ôk¦óô •+?€Å¦CQá”RI۶Ͻøâ‹Û§L™b:Àï÷cåÊ•±P(ôðúõë`:Ï@° Q9[d: ŽRj»”ò¢[n¹%>räHÓqˆ=‹&ßrË-ññãÇÿ\J¹Îtžâ=HDôq^C϶nà ` €ùŠð˜õEx "2L)õ§{ï½÷öU«V=pÿý÷Wtw»~’,¢’%„ÀÒ¥Kõõõ¿—R^¯”òÜ,,HDôqÞ×:òuÓ!EˆèBô¬m43¶HqˆÈ°7~÷‹_üâIË–-ûÔw¿ûÝ0g#2㪫®êœ1cÆ‹RÊK•Rž¼?—Ø‘'iù€ó¼0ˆ‡©)R"r)å§ëëë_Z¼x1‡ˆ ¸øâ‹»Ž?þø7¤”xa½£ÃaA""ÏÒ:Òàƒxˆâ­ZHDÆ)¥²¶m_túé§ï;þøã9„D4Œ-Z”š?þûRʳ•R¦ó  yÝŸL "÷PJµI)Ͻúê«ãuuu¦ã•…… ¦Ï<óÌ]RÊJ©Óy‹‰ˆ¼nøV7$"OPJ½)¥¼æÖ[oMTVVšŽCTÒN9å”ìâÅ‹÷I)OSJµ˜ÎS ,HDDDTr”R?·,ëoo½õÖx À9©ˆ†ÂñÇŸ»ôÒK÷[–uºRj—é<Å‚DDDD%iÓ¦M_9räã×^{­§ï‡ r£™3gêk®¹¦Ý²¬…J©÷Mç)&$"""*Y¶m/›9sæ;guVÆt¢R1mÚ4,[¶,fYÖ9J©7Mç)6$"*g<`"*qJ©”mÛç/Z´¨õ˜cŽáÌvDƒ4qâDÜrË-1˲+¥^2g(° ‘× æì}EKAD®¥”ÚmYÖ97ÜpCÇÔ©SMÇ!ò¬qãÆaÕªUq)ååJ©’E–‰ˆ¼îÔA컵h)ˆÈÕ”R¯Z–uáòåËããÇ7‡ÈsF…µkׯmÛ¾A)õ+Óy† y–Ñ*ŸÄCüºXYˆÈý”RR^·fÍšDmm­é8DžQ]]uëÖÅmÛ^¥”zÌtž¡Æ‚DDž$Dt!€'Ì+ð!ºü[ñ‘(¥~*¥\רØçIDGVYY‰Ûn»- …ÔúõëÿÕtžáÀ…ˆèãÔ ý+Ó!ò£Œ0@à ï[ZGx‰QÚ°aÃ÷î½÷Þ£?÷ÀTtuu™ŽDäJ¡PëÖ­‹…Ãá¿Ý°aÃ?˜Î3\XˆèãÌp¿éCài›L‡ "s6nÜøå/}éKG­Zµjå·¾õ­ŠL†“ZHJ‰µkׯªªªþnãÆM¦ó '^bGDåæ·.Ö:ÂSÆDenóæÍ=f̘Çn¾ùæ„ÏÇC"¢^Á`«W¯ŽÕÔÔ|oÓ¦MŸ3g¸ñÕ€ˆÊE Àœ«u„Ó{@J¹¬¾¾þO×\sM§é,Dnà÷û±bÅŠøØ±cݼyó`&Bò,$"*u¯¸ÀT­#wiáu4DÔG)••R^|êSŸŠO˜0á—–eÝl:),HDTŠÞðW¦i9NëÈ—´Ž4›EDê’Ržsê©§n?ãŒ3x…Ê’×]w]bÚ´iOI)¯VJåLg2…‰ˆJÑ4_ð¸ѯ=Öt "r7¥T»”ráùçŸßðÀ•‰¯>¢Ò0gÎ}ÅW´Z–uºRj‡é„ð7EŒDD%hãÆßª¬¬¼÷ÓŸþt< ™ŽC4hÓ§OÇõ×_ßnYÖ™J©wMçq#$"òº/ˆ¸ï¥Å BD¥iãÆ_ªªªz`ݺu1Û¶MÇ!*Ø”)SpÓM7uX–u®Rê5ÓyÜŠ‰ˆN‘û„ÃaÜvÛmñP(tdž ¾o:—ð'šˆˆˆh€”R9)åÕõõõ¿Y¶lK¹Šã8¸í¶Ûb÷ÜqÇß2ÇkøÓLD¥€‹“ѰSJemÛ¾¬¡¡á©ë¯Çƒ IDAT¿¾Sa:,Ëš5kb#FŒøÖÆ¿d:± Q)˜c:•'¥TÚ¶í gΜùÂ5×\“dI"“n½õÖØ¨Q£þeÓ¦MMçñ*$"*sM ¢ò¥”JÙ¶}þœ9s^¹üòË“¦óPyòù|¸å–[âãÆ{̲¬µ¦óx yšÑËŒ5ƒˆÊ›R*iÛö9'œp›_|qÊt*/BÜxã‰É“'ÿ·”r™RJ›Îäe,HDäYBDÏð¯ƒ|þ!¢¢PJ%lÛ>sþüùï,^¼¸Ût*×\sMçôéÓŸÍ/›3Çë¸Â Ä!¢^ŸC?®uäFÓ!<¤FˆèY¦CäI#óÛdKW„ÇÝW„Ç "(¥:ššš,X°àét:=ùW¿ú•e:•¶K/½4yì±ÇþYJ¹D)•6§° Ñ@Ôç7/k5Àc>à¿M‡bÛL ¢Ò¢”jmjj:íì³Ï~6“ÉLøÍo~Ãã-\pAêä“O~WJyŽRªËtžRÁK숨œuØj:•¥T³”ò‹-Ú}úé§gLç¡Òsæ™gv/\¸p»”r¡R*n:O)aA"¢rö˜Ö‘„éDTš”R{¤”ŸX²dIóI'”5‡JÇüùó3‹-Ú+¥<])Å«cŠŒ‰ˆÊÙ?›@D¥M)µCJyÚå—_Þ>{ölN Cƒ6wîÜÜ%—\²_JyšRjé<¥ˆ‰ˆÊÕ£ZG~b:•>¥Ô{–e³téÒØ”)SLÇ!›={¶¾úê«Û,Ë:])Å{h‡ •£wÜl:•¥ÔÿX–uáŠ+âãÇ7‡<¨¡¡K—.í°,ëL¥ÔÛ¦ó”2$"*7¿°@ëH»é DT^”R¿—R^·fÍšø¨Q£LÇ!™§u„Óí‘Q6lø¾ã8_X·n]ÜqÓqÈÅF5kÖÄmÛ¾F)õÓyÊ •š]~ `€Ôi¹KëÈ~³±ˆˆ>°qãÆû+**¾¹víÚX04‡\häÈ‘X·n]ܶíåJ©ÇMç)'\Ù¹üÜ Útƒ’Ezœ(t˜ûù"eè¯?ˆós%ž^;$òo;¼à]­#æ¢õßæÍ›7}ñ‹_½råÊk¿óïTd³\*‰zTUUá¶Ûn‹Û¶}ûúõëÿŸé<åFhÍ)ù‰ˆˆˆLhjjò¥R©oٲ弇z(Ìã2 …B¸ýöÛcUUUŸß¸qã¦ó”#^bGDDDdˆR*'¥¼º¡¡áù+¯¼²XW9GÙ¶uëÖÅ*++¿Êrd ‘AJ©´mÛKæÎ»eÉ’%)ÓyÈŒ`0ˆÕ«WǪ««ÿqÓ¦M¥ti¼ç° ¦”ê”Ržuúé§ï\¸paÚt^~¿+W®Œ=úG›7oþ¬é<厉ˆˆˆÈ”R­RÊ‹/n9ñÄs¦óÐððù|¸é¦›âuuuK)o5‡Xˆˆˆˆ\C)µÓ²¬…W\qEû¬Y³8cC‰Bà†nHL:õ÷RÊë•Rüš» ‘‹(¥Þ¶,ëœo¼1>eÊÓqh]yå•3fÌxQJy©RŠó¼» ‘Ë(¥^²,ëÂåË—ÇÇo: ‹.º¨kîܹoض}¾RªÛtú ‘ )¥~gÛöõ«W¯NÔÖÖšŽCEtÞyçuâŸxOJy¶RŠÓ»» ‘K)¥~bÛvãºuëUUU¦ãP,X° }ÖYgí”R.TJu˜ÎCÅ‚DDDDäb6lxÈqœHcccÜqÓqhN:é¤ìâÅ‹÷I)OSJµ˜ÎC‡Æ‚DDDDär7nüjeeå·Ö¬Yƒ¦ãPŽ=öX}ùå—ïÏ—£]¦óÐá± yÀæÍ›ï¨­­ý·+V$ü~¿é843fÌÐ×]w]›eY •R[Mç¡Ç‚DDDDäRÊuuuÿ½téÒN!„é8ÔS§NŲeË:,Ë:[)õ¦éüðÃŽÖ¥½žl0Äš5kb#FŒøÖ¦M›î1‡ÜA”ê7¾Q Ày®p>€:³‰†]€ÿðïÓ:Òf8y@SS“ÕÕÕõÛ_|qîüci:ÏPñûýX³fM|ܸqßyçkMç!÷(¹‚$DÔð9ëTŽãi?°‘#KDDDt$MMM]]]Ïüîw¿kxâ‰'Jî¦$ŸÏ‡åË—ÇëëëÿSJy£Rª´ˆiPJª =À?8Út—Šø‚Ö‘ûM!"""wkjjªM¥R/>þøããÿð‡?øMç)!n¼ñÆÄôéÓmÛöeJ©œéLä.^¹ç戄ˆžàç`9ú8¾&Dt“é DDDänJ©)åiK–,Ù '”Ìõ«¯¾ºsúôéÏæ‚e9¢(‰‚$Dt €GÐ3ÑÙ—„ˆ~Êt"""r7¥Ôv)å«®ºªcÆŒ¦ã Ú%—\Òuì±Ç¾jÛö¥TÚtr§’(H>`¢éÓ$D4d:¹›RêM˲Î]¶lY|òäɦãlÑ¢E©“O>ùmÛ¶ÏUJu™ÎCîåù‚$D4 €£!7ÀjÓ!ˆˆˆÈý”RÏK)?}ÞyçÅLg)ÔYg¥mÛ^¤”Š›ÎBîæù‚`)€*Ó!<êoL """Ïx7 eM‡(T Øc:¹_)¤‹Mð° BDgšADDDžÐî8Ž0¢Á`Zë §ó¦þ(…‚4Ït;Ýt"""ò„6Û¶=yì(¥D6›MšÎAÞàÉoò^BDÇo:‡Ç-0€ˆˆˆ<¡Í²,O.kÛ6r¹\ÂtòO$pô¨¦›@DDDž ƒž,HRJär9ÏN0AÃ+`:À fô(«uÄëÿ€Ñߡ𑠑ÅÌ2„ˆV¢gàéÆ°Ùø9Žhð.€·l×:âª{„ˆ~Àˆwÿ•Ö‘ÿWÌ<ÃIˆèÕÎ-p÷·´Ž|­˜y¼B)•»÷Þ{ÓÁ`ПN{k !Û¶€‰úÅë³× žë ’Ñ ç¸ÀyêÌ&2Gˆè.¿ð(€ÿÒ:bòò€™(|jøVž)H0¸ið¿€áýE¼ À„÷}À“Å‹R8!¢U.p€3ÔšMTT]BDŸð?Ñ:ò¦é@èY"ã¨÷íàÙ‚à4þ3þeY ›Ív:Žc{´ µ™ÎAÞÀ‚D®)HBDƒ>ƒžƒK~m{ŒCÏÁï2mBD?à﵎xvšU¢˯g÷9 @Ž3Tlgå·&!¢?ð9­#/™ E4PÙl6fÛvMG‡k.pè)%|>_«éä ^¿©Òt€ …ˆ/ÊBDk¼  ,G‡S à~Ÿ¿ìÈó„ˆàuQºåèP.ð‚ÑϘB4ZëÇqLÇ0Û¶áóùö›ÎAÞÀ‚D-¦µ<`Žé,ñ æ?oDž%Dt<€ÇL4Åà!¢«L!ê/­u[þr5O±m[ƒÁfÓ9ȼ^¼ž¸å¼à;n0SëÈ(­#³±° =÷Pÿ`éDƒôP¾åè@_":Út¢þBì÷â’ã8i!„·® $cŒ_ZECª ÀÓþàOžvÓ¬h DT¸Ítú+!¢ÿ›÷#‘ =ÀbÓ9\" `€õ¦ƒ‰Ïçköâ’ã8i®:"÷bA*Àè)B½…èu·M+{g˜a:„GMAÏl›BT€¿2Àen"ºÁ¯ÙTæ‚Áà^Ž eÀ‚DýÄ‚TnðžÖ/ÎÎRèúMÔcXÈ›Î6ÀeF˜à5ÓAˆ>N hÉ— OC:Ž“ õ“§¾¹éÐ´Ž¼`:à œd:€ÇÍ7€h „ˆŽ0ÙtZ$r¿¶p8Ü C:Ž£Á…b©Ÿ8É™v¢éÇÏyOŒÚ4Óˆú¡=›žÜiÀlÛàõ“§Ú?•¤1ƒØ· ÀŽb1h$zÇ-DµQKëHw1 ±ñîw€gŠd­ÃÀ' ©Š DEÖ–¿\ÍS,Ëòƒ‰úÉëÉs? ôüµƒYò_´Ž¼X¬<¦„ г°.×v /Yà~Ñ:òFQ“ !¢…üLÖ=Qñµ…B!Ó̲¬X¨Ÿ¼~‰]Ât.ô[U¦ P¡©Ô0€¨Úó—«yJ0 ‚‰úÉë‰ßèÞ6 D°h’×°§‘´I)=u’ÏçƒB(¥Ò¦³7xêü3‰"zYÑ’ ? …žQ´·=ZG¼òàõ‚îü<’×ð{Øà¹7­#»ÍF"ê—öühŒgH)‘Íf“¦swx½ æl›À#Å â"!¢ï gÑØ7гhìiI™EDT¶š<ƒËÐv³‘ˆ £”êþò—¿,|>r9oÜ nÛ6²Ùl§éä^/H<ÛöQ3òÛ¥ù¿ë"úÔ:ò߯’•_ø3zÊÐû†³U6›í´m{Dg§7:‡mÛÐZÇMç ïðzAòü fä À2Ë„ˆþ_·kÙc8QÉÒ:ò;Óˆ†J6›;Žã™‚$¥„Öš‹ÄR¿yú:ðü% ûLçð˜k¼.DôXÓAˆˆˆÈ{´Ö1Û¶MÇè7)%´›ÎAÞáé‚”÷‚é4À m:y‹ÖºÍK)ŸµÍtòŽR(H›àQõ2‚ˆÊ’WfÚ$¢CksÇt†~³m~¿¿éä¥P¾ÀÁºÏb!¢Ç™ADe‡gr‰<Ìçó5{iIJ‰@ Ðb:y‡×'i€Ö‘6!¢ÿ `…é,u;ø¹#¢áÕZà~s…ˆ5ÈHãàµé:´Ž”âìYK…ˆže:Ä Œ7ÀËÀ^/ 9Ž“õûý…¾îPò|AÊ»ÀåjLñ „ˆ~FëHÂt"*…Ž Ý_ÔÃDˆè|°6ÝSþCëˆ×ÖFå7*CÁ`°Ùqœ.Dt¡ÙXDk ‡ÃݦCôW(Ê€‰ $ hù%€¥èY±œæ$Óˆ¨¬< g:„AA‹üVˆè? ­4ˆh€ÚB¡g&[q' $€’)H uäÿ˜ à»2†ãx  ­#1ošÎá7ø¡Q¿é DÐ …`sàíÂX ¢À}G3Q?|=³hrä¤Çg„ˆ~%?ºFävm¶m Ó!ú˲,$€’-HÒ:’ðJ~+IBDpQ»W3 Ñ‘hy_ˆèÑsï(õ¼/ð€é DýÐnÛ¶gNnH)`A¢ðòˆ  ™°ÀŸM‡p‘KM ê§6˲‚¦CôW0 ‚‰€‰À"j™á6BD…Ñ3„ˆ~Gˆè[BD ½„‘ˆAëH;€ ¼h:‹Kœ$D”¿—Éõ”R‰@ à™«ü~@)Åõ©ßøBL½Xò„ˆÎ"z€÷üÀ­Žð“¹ˆJ‘Ö‘­è™IóVïŽcZ%€¦CõG6›MI)MÇ8"˲Ëå<³f¹ƒgÚ?ÑP"Zàz78þ0ÿL ýßù³ÞDT$ZGrþ À? =ÀåNGÏä:Q^'ó¼n:Ñ‘d³Ù„mÛáT*e:ÊDzmÙl¶Ótò$*[BDîAO): G> àoD†6QùÒ:ò2€—{ÿ,DÔFÏÌ£Uè™m´wsûý§¢°Qg¯,ûm›L‡„/Xk:„—år¹˜mÛcÚÛÝ}ÎPJ‰\.ÇËëh@X¨œÜMsþWBDÐ:²ˆ2Ñ´ŽtxÍtŽ"ªQXAòʽŽ)­#m¦CJˆ¨»‡=<@kÝî8ŽéGdÛ6´Öœ>Ÿ¤œ.[€Q·Ÿq¤a”ÿå~ÿw«°aâÞ)HD­ùX]‰ Q²#HùÅap"€yùíX!¢ZG2FÑ›|=‹UŽÀ>· ýšÖ‘½C”‰ˆÊ'Ì!OBì÷Â’”BÏŽv’%Q„ˆ†Ðsc}o:Àl¸ÿu2LëH»ѯ¸{»…lDÏýHDDDeÇï÷ïóÊ’Ïçk5ƒ¼ÅsIˆh%€¹8xdh&ϬèL®ówþ@íöY+D´IëÈÎ!ÊDDDäZ–eíuG¦³|)%ü~?ï¦ñâ=H?ð[ôÜ;² À1`9¢AÐ:pßw³Ü9qˆˆˆ\OÑ …\¿¾mÛ:4›ÎAÞâ¹$¢!òMŸ0zû¬"ú•üB—D4BD€)è¹w´w;ÀWµŽü“ÉlDtHmáp8 ÀÕ«Å:ŽÓ-„è0ƒ¼Å‹‰Ss ןJZGBD¿‚$Y>`åФ"*MBDGáà"t,z®8Ô n^ü=ETÚÂá°ë'½ …Bi,H4 ^üÅÃoòâKi)ë‚”÷- ÀØìs“Ñ{´Ž¼3D™ˆJ‚Ñè¹ßïXã Ç!¢Ákw'g:Ä‘8Ž“i€¼x¿É‹ŸSZG:Ü;ÀÝ"C‡¨Ôà|°•Š6Çq\=AäKsh@ÊqiƒQןñ(@à ö5õÂáÆË%¿ `=€ñØg©Ñ/iycˆ2I×0=GûŸ«âç¤øy"¯h³mÛõ'ÚóS‘s¡X/¤öAîÿÅ¢¤(-¦P‹zÞÃÒ:Ò%DôßÀn>Q×Mª#®‚Ë3pýÇÏÕGñsÒ?®{]$:Œv)¥ë#mÛàë 뿱áϦ” #ŸÓüÄ9~©ç±BD‡böœWÐsr¨Æçj!¢?°«€çÈ=O‡2Ø“n{¯‹k)ÅQêÁâ÷Oÿ° ‘W´ƒAËtˆ#‘RúÁ‚DäÅ‚ô‚é%è9ƒÏPUà¾ß+fAèY£k¸e$†é¹s€[-DÔÔHe!‚ƒØ—EàÐ =@ùšÑÞè…~ñR ò¥TîÞ{ïÍúýþ`6›5ç°‚Á`,H4@ž+HZGþ"D´@­é,%ÄdAzÀ)Ÿßë^×:¢‡é¹ÞP舟0¢¸q\ëmÓÜHëH‡Ñf£¸«“ßÊgÄ$ÏÈf³¶mÛ‰Äp§¸`0  ëo®;Œ§L(! /|þg >w)¶Ÿ­#1o×óy¿§ïyÓ\.†ž“FDžËåâŽãÞó~¿Zk­”rï¹’W Òÿ1 „<¤u$iðùy098Ã}²€_¯#ãçèðX>Þó¼¼$—˵çg‰s%)%²Ù¬Écò(¯¤ÿ°Ýtˆ Ñ³p£I?ÅðMS]jRèùYN?æçóšN¿4ÂÅ~f:€Ëñ狼¦ÍÍ#H¶m#—˹÷ú?r-O$­#Y_7£øÙjqùI†«z§´ñËmµŽ$Ðs_[ßeŠBDƒFâà×lî?9’ÆÁ¯Ë.~]¾€,p_¯¼oø÷uåU†´…B!מ(r7UHXIDAT'ãóùøõ¢+É‚t(ùƒÏ.ôœ';àë9l„ˆ~ÀøhäE&h)« E´Žô– bZG†{Áà!§u$ `¯é¥LëÈŸLg0EëÈ;Þ1£´‡B!ÓËqœn¦s÷xuô„hØiéFaÓ8 ôLeNDDTJÚlÛví¨®ã8Y° QXˆæ2#ÎBD/+v"""ƒÚ¤”®½‰‰ Å‚D4ù{ ¾Qàî_ÉßWADDT Ú-Ëríï5Çq4€˜éä=,HD÷w(ìÞš£¬-r"""#”R)ŸÏçÂWÙåŠå  Ñå§"ÿÇw­.f"""S²Ùl—”…N†8´¤”>° QXˆ Ó„žé|ª= y^.—‹çGj\Dz¬X¨,HDÈ/òøp»ß&Dtj1ó™ËåbŽã˜ŽqHÁ`0$* Qá¾  ÅC­ü¾DDDž¦µnsã’>ŸÏ¯”JšÎBÞÂDT ­#ox¤Àݯ"zZ1óÐêÆ‚$¥D.—K™ÎAÞÄ‚D48÷ bßB%""r ŸÏ×ìÆK줔Èf³…Ì8KÄ‚D4ZGžð‹wŸ/Dôºbæ!""NÁ`pŸ‹G¦s7±  Þ`F‘îâÿ·wÿ®×qÇßßË·IHZüуRh»—â~ЩcíRqpqõ‹àtˆ“ð]ýtrá¡rËd­”v‘C©ÛËIÒøuù¸Ü"\›~›ãñX2}ÉkÌ“/ù|>»ç£ÀÿÈóüN§3©{dzÚívTUõ´îÌ&WTU÷ˆˆŸóñµˆøàúÖÀ:ët:·î¿>)ÎëÞÁlÊë/ˆ·"bý9Ÿ\ç¸AçÝn÷yùùùȲì¬îÌ&× ªî?ŽˆÇuï€ö×úúzãîÝ»qzzZ÷–˜››‹íííáÖÖÖ°Ñh|U÷fSVUUݘAeYÞ™L&ï^^^~qppÐ~ðàAçÉ“zîfÝÜÜŒ½½½§yžÛn·?,Šâ÷Z†0óWR–eg4}RUÕG=j=|ø°yqq3‡È­­­Åîîî`iié—v»ýNQýùb^X €kQ–å«Ãáðó,ËÞî÷ûýýýö´Þ(­®®ÆÎÎÎ`yyyÐjµŠˆø¦( ?l¹2Àµ*Ëò•ÑhôqD¼ttý~áøø8&“«Þjµbss3îÝ»÷diiéïf³ùi–e_EqëŽgv $¦¢,Ëùˆxóâââ½<Ï_?<<¬NNNºçççqvvÿ}>NyžG¯×‹ÅÅÅèõzÑëõbeeå鯯Æñxü}·Ûý2"ö…Ó ˜º²,_Žˆ7.//_‡UU­6åf³ùÒx<þg0 ³,ËZF#ÆãñŸ“Éä·,Ë~nµZÇyžÿßEáX¦J P«²,{±“ˆøµ( wRÜ©{Àm!$€D $ H‰@H@"$€D $ H‰@H@"$€D $ H‰@H@"$€D $ H‰@H@"ü 7ÒO™¥,IEND®B`‚libSquish.pri0000644000076500000240000000065612771161730013267 0ustar roettgerstaffHEADERS += \ squish.h SOURCES += \ alpha.cpp \ alpha.h \ clusterfit.cpp \ clusterfit.h \ colourblock.cpp \ colourblock.h \ colourfit.cpp \ colourfit.h \ colourset.cpp \ colourset.h \ maths.cpp \ maths.h \ rangefit.cpp \ rangefit.h \ simd.h \ simd_float.h \ simd_sse.h \ simd_ve.h \ singlecolourfit.cpp \ singlecolourfit.h \ singlecolourlookup.inl \ squish.cpp libSquish.pro0000644000076500000240000000126113061741230013256 0ustar roettgerstaffTARGET = squish TEMPLATE = lib include(libSquish.pri) QT -= gui CONFIG += staticlib thread CONFIG += debug_and_release CONFIG(debug, debug|release) { unix:TARGET = $$join(TARGET,,,_debug) } MOC_DIR = mocs OBJECTS_DIR = objs RCC_DIR = rccs UI_DIR = uics CONFIG(debug, debug|release) { unix:MOC_DIR = $$join(MOC_DIR,,,_debug) unix:OBJECTS_DIR = $$join(OBJECTS_DIR,,,_debug) unix:RCC_DIR = $$join(RCC_DIR,,,_debug) unix:UI_DIR = $$join(UI_DIR,,,_debug) win32:MOC_DIR = $$join(MOC_DIR,,,d) win32:OBJECTS_DIR = $$join(OBJECTS_DIR,,,d) win32:RCC_DIR = $$join(RCC_DIR,,,d) win32:UI_DIR = $$join(UI_DIR,,,d) } unix:QMAKE_CXXFLAGS += -DSQUISH_USE_OPENMP -fopenmp libSquish.svg0000644000076500000240000002530712771161730013274 0ustar roettgerstaff image/svg+xml lib Squish README.txt0000644000076500000240000000115313061741230012267 0ustar roettgerstaffLICENSE ------- The squish library is distributed under the terms and conditions of the MIT license. This license is specified at the top of each source file and must be preserved in its entirety. BUILDING AND INSTALLING THE LIBRARY ----------------------------------- The preferred way to install the library on Unix/Mac (and Windows) is via cmake: cmake . && make && sudo make install REPORTING BUGS OR FEATURE REQUESTS ---------------------------------- Feedback can be sent to Simon Brown (the developer) at si@sjbrown.co.uk Feedback can also be sent to Stefan Roettger (the maintainer) at snroettg@gmail.com LICENSE.txt0000644000076500000240000000214113061741230012412 0ustar roettgerstaff Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ChangeLog.txt0000644000076500000240000000422513061741230013164 0ustar roettgerstaff1.15 * parallel compression using openmp with cmake (Marian Krivos / Stefan Roettger) * parallel decompression using openmp with cmake (Stefan Roettger) 1.14 * backport BGRA support * backport BC4 and BC5 support * backport BlockMSE support 1.11-1.13 * added support for CMake and QMake (Stefan Roettger) * misc. minor changes on the build system (Stefan Roettger) * added svg icon (Stefan Roettger) 1.10 * Iterative cluster fit is now considered to be a new compression mode * The core cluster fit is now 4x faster using contributions by Ignacio Castano from NVIDIA * The single colour lookup table has been halved by exploiting symmetry 1.9 * Added contributed SSE1 truncate implementation * Changed use of SQUISH_USE_SSE to be 1 for SSE and 2 for SSE2 instructions * Cluster fit is now iterative to further reduce image error 1.8 * Switched from using floor to trunc for much better SSE performance (again) * Xcode build now expects libpng in /usr/local for extra/squishpng 1.7 * Fixed floating-point equality issue in clusterfit sort (x86 affected only) * Implemented proper SSE(2) floor function for 50% speedup on SSE builds * The range fit implementation now uses the correct colour metric 1.6 * Fixed bug in CompressImage where masked pixels were not skipped over * DXT3 and DXT5 alpha compression now properly use the mask to ignore pixels * Fixed major DXT1 bug that can generate unexpected transparent pixels 1.5 * Added CompressMasked function to handle incomplete DXT blocks more cleanly * Added kWeightColourByAlpha flag for better quality images when alpha blending 1.4 * Fixed stack overflow in rangefit 1.3 * Worked around SSE floor implementation bug, proper fix needed! * This release has visual studio and makefile builds that work 1.2 * Added provably optimal single colour compressor * Added extra/squishgen.cpp that generates single colour lookup tables 1.1 * Fixed a DXT1 colour output bug * Changed argument order for Decompress function to match Compress * Added GetStorageRequirements function * Added CompressImage function * Added DecompressImage function * Moved squishtool.cpp to extra/squishpng.cpp * Added extra/squishtest.cpp 1.0 * Initial release Doxyfile0000644000076500000240000001764512771161730012324 0ustar roettgerstaff# Doxyfile 1.4.6 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = squish PROJECT_NUMBER = 1.14 OUTPUT_DIRECTORY = docs CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO BUILTIN_STL_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = YES WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = squish.h FILE_PATTERNS = RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOTFILE_DIRS = MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO libsquish.pc.in0000644000076500000240000000041012771454551013536 0ustar roettgerstaffprefix=@PREFIX@ exec_prefix=${prefix} libdir=${prefix}/@LIB_PATH@ sharedlibdir=${libdir} includedir=${prefix}/include Name: libsquish Description: squish DXT library Version: 1.14 Requires: Libs: -L${libdir} -L${sharedlibdir} -llibsquish Cflags: -I${includedir} extra/0000755000076500000240000000000012771161730011724 5ustar roettgerstaffextra/.svn/0000755000076500000240000000000013061741574012613 5ustar roettgerstaffextra/.svn/all-wcprops0000444000076500000240000000063612771161730015001 0ustar roettgerstaffK 25 svn:wc:ra_dav:version-url V 41 /p/libsquish/code/!svn/ver/84/trunk/extra END squishpng.cpp K 25 svn:wc:ra_dav:version-url V 55 /p/libsquish/code/!svn/ver/84/trunk/extra/squishpng.cpp END squishgen.cpp K 25 svn:wc:ra_dav:version-url V 55 /p/libsquish/code/!svn/ver/84/trunk/extra/squishgen.cpp END squishtest.cpp K 25 svn:wc:ra_dav:version-url V 56 /p/libsquish/code/!svn/ver/84/trunk/extra/squishtest.cpp END extra/.svn/entries0000444000076500000240000000121213061741230014166 0ustar roettgerstaff8 dir 103 https://svn.code.sf.net/p/libsquish/code/trunk/extra https://svn.code.sf.net/p/libsquish/code 2016-09-23T08:06:40.065860Z 84 roettger svn:special svn:externals svn:needs-lock d1da18a7-0d7c-4e8b-a45e-7863643f1f45 squishpng.cpp file 2016-09-23T08:12:08.000000Z affbc7b695b1378e2ceef496007fec94 2016-09-23T08:06:40.065860Z 84 roettger has-props squishgen.cpp file 2016-09-23T08:12:08.000000Z 76e848e896171d337bb38bb7e7e85fa6 2016-09-23T08:06:40.065860Z 84 roettger has-props squishtest.cpp file 2016-09-23T08:12:08.000000Z 6f933ea41dbd2bf96433df3d08bb9d4c 2016-09-23T08:06:40.065860Z 84 roettger has-props extra/.svn/format0000444000076500000240000000000212771161730014011 0ustar roettgerstaff8 extra/.svn/prop-base/0000755000076500000240000000000012771161730014500 5ustar roettgerstaffextra/.svn/prop-base/squishgen.cpp.svn-base0000444000076500000240000000004212771161730020721 0ustar roettgerstaffK 13 svn:eol-style V 6 native END extra/.svn/prop-base/squishpng.cpp.svn-base0000444000076500000240000000004212771161730020734 0ustar roettgerstaffK 13 svn:eol-style V 6 native END extra/.svn/prop-base/squishtest.cpp.svn-base0000444000076500000240000000004212771161730021127 0ustar roettgerstaffK 13 svn:eol-style V 6 native END extra/.svn/props/0000755000076500000240000000000012771161730013753 5ustar roettgerstaffextra/.svn/text-base/0000755000076500000240000000000012771161730014504 5ustar roettgerstaffextra/.svn/text-base/squishgen.cpp.svn-base0000444000076500000240000001175512771161730020742 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #include struct SourceBlock { int start; int end; int error; }; struct TargetValue { SourceBlock sources[2]; }; static void GenerateData( std::string const& name, int bits, int colours ) { TargetValue values[256]; // initialise the data for( int target = 0; target < 256; ++target ) for( int index = 0; index < colours; ++index ) values[target].sources[index].error = 255; // loop over all possible source points int count = ( 1 << bits ); for( int value1 = 0; value1 < count; ++value1 ) { for( int value2 = 0; value2 < count; ++value2 ) { // compute the 8-bit endpoints int a = ( value1 << ( 8 - bits ) ) | ( value1 >> ( 2*bits - 8 ) ); int b = ( value2 << ( 8 - bits ) ) | ( value2 >> ( 2*bits - 8 ) ); // fill in the codebook with the these and intermediates int codes[2]; codes[0] = a; if( colours == 3 ) codes[1] = ( a + b )/2; else codes[1] = ( 2*a + b )/3; // mark each target point with the endpoints and index needed for it for( int index = 0; index < 2; ++index ) { int target = codes[index]; SourceBlock& block = values[target].sources[index]; if( block.error != 0 ) { block.start = value1; block.end = value2; block.error = 0; } } } } // iteratively fill in the missing values for( ;; ) { bool stable = true; for( int index = 0; index < 2; ++index ) { for( int target = 0; target < 256; ++target ) { if( target != 255 ) { SourceBlock& current = values[target].sources[index]; SourceBlock& next = values[target + 1].sources[index]; if( current.error > next.error + 1 ) { current.start = next.start; current.end = next.end; current.error = next.error + 1; stable = false; } } if( target != 0 ) { SourceBlock& current = values[target].sources[index]; SourceBlock& previous = values[target - 1].sources[index]; if( current.error > previous.error + 1 ) { current.start = previous.start; current.end = previous.end; current.error = previous.error + 1; stable = false; } } } } if( stable ) break; } // debug std::cout << "\nstatic SingleColourLookup const " << name << "[] = \n{\n"; for( int i = 0;; ) { std::cout << "\t{ { "; for( int j = 0;; ) { SourceBlock const& block = values[i].sources[j]; if( j < colours ) std::cout << "{ " << block.start << ", " << block.end << ", " << block.error << " }"; else std::cout << "{ 0, 0, 0 }"; if( ++j == 2 ) break; std::cout << ", "; } std::cout << " } }"; if( ++i == 256 ) break; std::cout << ",\n"; } std::cout << "\n};\n"; } int main() { GenerateData( "lookup_5_3", 5, 3 ); GenerateData( "lookup_6_3", 6, 3 ); GenerateData( "lookup_5_4", 5, 4 ); GenerateData( "lookup_6_4", 6, 4 ); } extra/.svn/text-base/squishpng.cpp.svn-base0000444000076500000240000003575612771161730020764 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ /*! @file @brief Test program that compresses images loaded using the PNG format. This program requires libpng for PNG input and output, and is designed to test the RMS error for DXT compression for a set of test images. This program uses the high-level image compression and decompression functions that process an entire image at a time. */ #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning( disable: 4511 4512 ) #endif // def _MSC_VER using namespace squish; //! Simple exception class. class Error : public std::exception { public: Error( std::string const& excuse ) : m_excuse( excuse ) {} ~Error() throw() {} virtual char const* what() const throw() { return m_excuse.c_str(); } private: std::string m_excuse; }; //! Base class to make derived classes non-copyable class NonCopyable { public: NonCopyable() {} private: NonCopyable( NonCopyable const& ); NonCopyable& operator=( NonCopyable const& ); }; //! Memory object. class Mem : NonCopyable { public: Mem() : m_p( 0 ) {} explicit Mem( int size ) : m_p( new u8[size] ) {} ~Mem() { delete[] m_p; } void Reset( int size ) { u8 *p = new u8[size]; delete m_p; m_p = p; } u8* Get() const { return m_p; } private: u8* m_p; }; //! File object. class File : NonCopyable { public: explicit File( FILE* fp ) : m_fp( fp ) {} ~File() { if( m_fp ) fclose( m_fp ); } bool IsValid() const { return m_fp != 0; } FILE* Get() const { return m_fp; } private: FILE* m_fp; }; //! PNG read object. class PngReadStruct : NonCopyable { public: PngReadStruct() : m_png( 0 ), m_info( 0 ), m_end( 0 ) { m_png = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); if( !m_png ) throw Error( "failed to create png read struct" ); m_info = png_create_info_struct( m_png ); m_end = png_create_info_struct( m_png ); if( !m_info || !m_end ) { png_infopp info = m_info ? &m_info : 0; png_infopp end = m_end ? &m_end : 0; png_destroy_read_struct( &m_png, info, end ); throw Error( "failed to create png info structs" ); } } ~PngReadStruct() { png_destroy_read_struct( &m_png, &m_info, &m_end ); } png_structp GetPng() const { return m_png; } png_infop GetInfo() const { return m_info; } private: png_structp m_png; png_infop m_info, m_end; }; //! PNG write object. class PngWriteStruct : NonCopyable { public: PngWriteStruct() : m_png( 0 ), m_info( 0 ) { m_png = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); if( !m_png ) throw Error( "failed to create png read struct" ); m_info = png_create_info_struct( m_png ); if( !m_info ) { png_infopp info = m_info ? &m_info : 0; png_destroy_write_struct( &m_png, info ); throw Error( "failed to create png info structs" ); } } ~PngWriteStruct() { png_destroy_write_struct( &m_png, &m_info ); } png_structp GetPng() const { return m_png; } png_infop GetInfo() const { return m_info; } private: png_structp m_png; png_infop m_info; }; //! PNG rows object. class PngRows : NonCopyable { public: PngRows( int pitch, int height ) : m_height( height ) { m_rows = new png_bytep[m_height]; for( int i = 0; i < m_height; ++i ) m_rows[i] = new png_byte[pitch]; } ~PngRows() { for( int i = 0; i < m_height; ++i ) delete[] m_rows[i]; delete[] m_rows; } png_bytep* Get() const { return m_rows; } png_bytep operator[](int y) const { return m_rows[y]; } private: png_bytep* m_rows; int m_height; }; //! Represents a DXT compressed image in memory. struct DxtData { int width; int height; int format; //!< Either kDxt1, kDxt3 or kDxt5. Mem data; bool isColour; bool isAlpha; }; //! Represents an uncompressed RGBA image in memory. class Image { public: Image(); void LoadPng( std::string const& fileName ); void SavePng( std::string const& fileName ) const; void Decompress( DxtData const& dxt ); void Compress( DxtData& dxt, int flags ) const; double GetRmsError( Image const& image ) const; private: int m_width; int m_height; bool m_isColour; //!< Either colour or luminance. bool m_isAlpha; //!< Either alpha or not. Mem m_pixels; }; Image::Image() : m_width( 0 ), m_height( 0 ), m_isColour( false ), m_isAlpha( false ) { } void Image::LoadPng( std::string const& fileName ) { // open the source file File file( fopen( fileName.c_str(), "rb" ) ); if( !file.IsValid() ) { std::ostringstream oss; oss << "failed to open \"" << fileName << "\" for reading"; throw Error( oss.str() ); } // check the signature bytes png_byte header[8]; size_t check = fread( header, 1, 8, file.Get() ); if( check != 8 ) throw Error( "file read error" ); if( png_sig_cmp( header, 0, 8 ) ) { std::ostringstream oss; oss << "\"" << fileName << "\" does not look like a png file"; throw Error( oss.str() ); } // read the image into memory PngReadStruct png; png_init_io( png.GetPng(), file.Get() ); png_set_sig_bytes( png.GetPng(), 8 ); png_read_png( png.GetPng(), png.GetInfo(), PNG_TRANSFORM_EXPAND, 0 ); // get the image info png_uint_32 width; png_uint_32 height; int bitDepth; int colourType; png_get_IHDR( png.GetPng(), png.GetInfo(), &width, &height, &bitDepth, &colourType, 0, 0, 0 ); // check the image is 8 bit if( bitDepth != 8 ) { std::ostringstream oss; oss << "cannot process " << bitDepth << "-bit image (bit depth must be 8)"; throw Error( oss.str() ); } // copy the data into a contiguous array m_width = width; m_height = height; m_isColour = ( ( colourType & PNG_COLOR_MASK_COLOR ) != 0 ); m_isAlpha = ( ( colourType & PNG_COLOR_MASK_ALPHA ) != 0 ); m_pixels.Reset(4*width*height); // get the image rows png_bytep const *rows = png_get_rows( png.GetPng(), png.GetInfo() ); if( !rows ) throw Error( "failed to get image rows" ); // copy the pixels into the storage u8 *dest = m_pixels.Get(); for( int y = 0; y < m_height; ++y ) { u8 const *src = rows[y]; for( int x = 0; x < m_width; ++x ) { if( m_isColour ) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; src += 3; } else { u8 lum = *src++; dest[0] = lum; dest[1] = lum; dest[2] = lum; } if( m_isAlpha ) dest[3] = *src++; else dest[3] = 255; dest += 4; } } } void Image::SavePng( std::string const& fileName ) const { // create the target rows int const pixelSize = ( m_isColour ? 3 : 1 ) + ( m_isAlpha ? 1 : 0 ); PngRows rows( m_width*pixelSize, m_height ); // fill the rows with pixel data u8 const *src = m_pixels.Get(); for( int y = 0; y < m_height; ++y ) { u8 *dest = rows[y]; for( int x = 0; x < m_width; ++x ) { if( m_isColour ) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest += 3; } else *dest++ = src[1]; if( m_isAlpha ) *dest++ = src[3]; src += 4; } } // set up the image PngWriteStruct png; png_set_IHDR( png.GetPng(), png.GetInfo(), m_width, m_height, 8, ( m_isColour ? PNG_COLOR_MASK_COLOR : 0) | ( m_isAlpha ? PNG_COLOR_MASK_ALPHA : 0 ), PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); // open the target file File file( fopen( fileName.c_str(), "wb" ) ); if( !file.IsValid() ) { std::ostringstream oss; oss << "failed to open \"" << fileName << "\" for writing"; throw Error( oss.str() ); } // write the image png_set_rows( png.GetPng(), png.GetInfo(), rows.Get() ); png_init_io( png.GetPng(), file.Get() ); png_write_png( png.GetPng(), png.GetInfo(), PNG_TRANSFORM_IDENTITY, 0 ); } void Image::Decompress( DxtData const& dxt ) { // allocate storage m_width = dxt.width; m_height = dxt.height; m_isColour = dxt.isColour; m_isAlpha = dxt.isAlpha; m_pixels.Reset( 4*m_width*m_height ); // use the whole image decompression function to do the work DecompressImage( m_pixels.Get(), m_width, m_height, dxt.data.Get(), dxt.format ); } void Image::Compress( DxtData& dxt, int flags ) const { // work out how much memory we need int storageSize = GetStorageRequirements( m_width, m_height, flags ); // set the structure fields and allocate it dxt.width = m_width; dxt.height = m_height; dxt.format = flags & ( kDxt1 | kDxt3 | kDxt5 ); dxt.isColour = m_isColour; dxt.isAlpha = m_isAlpha; dxt.data.Reset( storageSize ); // use the whole image compression function to do the work CompressImage( m_pixels.Get(), m_width, m_height, dxt.data.Get(), flags ); } double Image::GetRmsError( Image const& image ) const { if( m_width != image.m_width || m_height != image.m_height ) throw Error( "image dimensions mismatch when computing RMS error" ); // accumulate colour error double difference = 0; u8 const *a = m_pixels.Get(); u8 const *b = image.m_pixels.Get(); for( int y = 0; y < m_height; ++y ) { for( int x = 0; x < m_width; ++x ) { int d0 = ( int )a[0] - ( int )b[0]; int d1 = ( int )a[1] - ( int )b[1]; int d2 = ( int )a[2] - ( int )b[2]; difference += ( double )( d0*d0 + d1*d1 + d2*d2 ); a += 4; b += 4; } } return std::sqrt( difference/( double )( m_width*m_height ) ); } int main( int argc, char* argv[] ) { try { // parse the command-line std::string sourceFileName; std::string targetFileName; int format = kDxt1; int fit = kColourClusterFit; int extra = 0; bool help = false; bool arguments = true; bool error = false; for( int i = 1; i < argc; ++i ) { // check for options char const* word = argv[i]; if( arguments && word[0] == '-' ) { for( int j = 1; word[j] != '\0'; ++j ) { switch( word[j] ) { case 'h': help = true; break; case '1': format = kDxt1; break; case '3': format = kDxt3; break; case '5': format = kDxt5; break; case 'r': fit = kColourRangeFit; break; case 'i': fit = kColourIterativeClusterFit; break; case 'w': extra = kWeightColourByAlpha; break; case '-': arguments = false; break; default: std::cerr << "squishpng error: unknown option '" << word[j] << "'" << std::endl; error = true; } } } else { if( sourceFileName.empty() ) sourceFileName.assign( word ); else if( targetFileName.empty() ) targetFileName.assign( word ); else { std::cerr << "squishpng error: unexpected argument \"" << word << "\"" << std::endl; error = true; } } } // check arguments if( sourceFileName.empty() ) { std::cerr << "squishpng error: no source file given" << std::endl; error = true; } if( help || error ) { std::cout << "SYNTAX" << std::endl << "\tsquishpng [-135riw] []" << std::endl << "OPTIONS" << std::endl << "\t-h\tPrint this help message" << std::endl << "\t-135\tSpecifies whether to use DXT1 (default), DXT3 or DXT5 compression" << std::endl << "\t-r\tUse the fast but inferior range-based colour compressor" << std::endl << "\t-i\tUse the very slow but slightly better iterative colour compressor" << std::endl << "\t-w\tWeight colour values by alpha in the cluster colour compressor" << std::endl ; return error ? -1 : 0; } // load the source image Image sourceImage; sourceImage.LoadPng( sourceFileName ); // compress to DXT DxtData dxt; sourceImage.Compress( dxt, format | fit | extra ); // decompress back Image targetImage; targetImage.Decompress( dxt ); // compare the images double rmsError = sourceImage.GetRmsError( targetImage ); std::cout << sourceFileName << " " << rmsError << std::endl; // save the target image if necessary if( !targetFileName.empty() ) targetImage.SavePng( targetFileName ); } catch( std::exception& excuse ) { // complain std::cerr << "squishpng error: " << excuse.what() << std::endl; return -1; } // done return 0; } extra/.svn/text-base/squishtest.cpp.svn-base0000444000076500000240000001365012771161730021144 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ /*! @file @brief This program tests the error for 1 and 2-colour DXT compression. This tests the effectiveness of the DXT compression algorithm for all possible 1 and 2-colour blocks of pixels. */ #include #include #include #include #include using namespace squish; double GetColourError( u8 const* a, u8 const* b ) { double error = 0.0; for( int i = 0; i < 16; ++i ) { for( int j = 0; j < 3; ++j ) { int index = 4*i + j; int diff = ( int )a[index] - ( int )b[index]; error += ( double )( diff*diff ); } } return error / 16.0; } void TestOneColour( int flags ) { u8 input[4*16]; u8 output[4*16]; u8 block[16]; double avg = 0.0, min = DBL_MAX, max = -DBL_MAX; int counter = 0; // test all single-channel colours for( int i = 0; i < 16*4; ++i ) input[i] = ( ( i % 4 ) == 3 ) ? 255 : 0; for( int channel = 0; channel < 3; ++channel ) { for( int value = 0; value < 255; ++value ) { // set the channnel value for( int i = 0; i < 16; ++i ) input[4*i + channel] = ( u8 )value; // compress and decompress Compress( input, block, flags ); Decompress( output, block, flags ); // test the results double rm = GetColourError( input, output ); double rms = std::sqrt( rm ); // accumulate stats min = std::min( min, rms ); max = std::max( max, rms ); avg += rm; ++counter; } // reset the channel value for( int i = 0; i < 16; ++i ) input[4*i + channel] = 0; } // finish stats avg = std::sqrt( avg/counter ); // show stats std::cout << "one colour error (min, max, avg): " << min << ", " << max << ", " << avg << std::endl; } void TestOneColourRandom( int flags ) { u8 input[4*16]; u8 output[4*16]; u8 block[16]; double avg = 0.0, min = DBL_MAX, max = -DBL_MAX; int counter = 0; // test all single-channel colours for( int test = 0; test < 1000; ++test ) { // set a constant random colour for( int channel = 0; channel < 3; ++channel ) { u8 value = ( u8 )( rand() & 0xff ); for( int i = 0; i < 16; ++i ) input[4*i + channel] = value; } for( int i = 0; i < 16; ++i ) input[4*i + 3] = 255; // compress and decompress Compress( input, block, flags ); Decompress( output, block, flags ); // test the results double rm = GetColourError( input, output ); double rms = std::sqrt( rm ); // accumulate stats min = std::min( min, rms ); max = std::max( max, rms ); avg += rm; ++counter; } // finish stats avg = std::sqrt( avg/counter ); // show stats std::cout << "random one colour error (min, max, avg): " << min << ", " << max << ", " << avg << std::endl; } void TestTwoColour( int flags ) { u8 input[4*16]; u8 output[4*16]; u8 block[16]; double avg = 0.0, min = DBL_MAX, max = -DBL_MAX; int counter = 0; // test all single-channel colours for( int i = 0; i < 16*4; ++i ) input[i] = ( ( i % 4 ) == 3 ) ? 255 : 0; for( int channel = 0; channel < 3; ++channel ) { for( int value1 = 0; value1 < 255; ++value1 ) { for( int value2 = value1 + 1; value2 < 255; ++value2 ) { // set the channnel value for( int i = 0; i < 16; ++i ) input[4*i + channel] = ( u8 )( ( i < 8 ) ? value1 : value2 ); // compress and decompress Compress( input, block, flags ); Decompress( output, block, flags ); // test the results double rm = GetColourError( input, output ); double rms = std::sqrt( rm ); // accumulate stats min = std::min( min, rms ); max = std::max( max, rms ); avg += rm; ++counter; } } // reset the channel value for( int i = 0; i < 16; ++i ) input[4*i + channel] = 0; } // finish stats avg = std::sqrt( avg/counter ); // show stats std::cout << "two colour error (min, max, avg): " << min << ", " << max << ", " << avg << std::endl; } int main() { TestOneColourRandom( kDxt1 | kColourRangeFit ); TestOneColour( kDxt1 ); TestTwoColour( kDxt1 ); } extra/.svn/tmp/0000755000076500000240000000000013061741230013400 5ustar roettgerstaffextra/.svn/tmp/prop-base/0000755000076500000240000000000012771161730015300 5ustar roettgerstaffextra/.svn/tmp/props/0000755000076500000240000000000012771161730014553 5ustar roettgerstaffextra/.svn/tmp/text-base/0000755000076500000240000000000012771161730015304 5ustar roettgerstaffextra/squishgen.cpp0000644000076500000240000001175512771161730014447 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ #include struct SourceBlock { int start; int end; int error; }; struct TargetValue { SourceBlock sources[2]; }; static void GenerateData( std::string const& name, int bits, int colours ) { TargetValue values[256]; // initialise the data for( int target = 0; target < 256; ++target ) for( int index = 0; index < colours; ++index ) values[target].sources[index].error = 255; // loop over all possible source points int count = ( 1 << bits ); for( int value1 = 0; value1 < count; ++value1 ) { for( int value2 = 0; value2 < count; ++value2 ) { // compute the 8-bit endpoints int a = ( value1 << ( 8 - bits ) ) | ( value1 >> ( 2*bits - 8 ) ); int b = ( value2 << ( 8 - bits ) ) | ( value2 >> ( 2*bits - 8 ) ); // fill in the codebook with the these and intermediates int codes[2]; codes[0] = a; if( colours == 3 ) codes[1] = ( a + b )/2; else codes[1] = ( 2*a + b )/3; // mark each target point with the endpoints and index needed for it for( int index = 0; index < 2; ++index ) { int target = codes[index]; SourceBlock& block = values[target].sources[index]; if( block.error != 0 ) { block.start = value1; block.end = value2; block.error = 0; } } } } // iteratively fill in the missing values for( ;; ) { bool stable = true; for( int index = 0; index < 2; ++index ) { for( int target = 0; target < 256; ++target ) { if( target != 255 ) { SourceBlock& current = values[target].sources[index]; SourceBlock& next = values[target + 1].sources[index]; if( current.error > next.error + 1 ) { current.start = next.start; current.end = next.end; current.error = next.error + 1; stable = false; } } if( target != 0 ) { SourceBlock& current = values[target].sources[index]; SourceBlock& previous = values[target - 1].sources[index]; if( current.error > previous.error + 1 ) { current.start = previous.start; current.end = previous.end; current.error = previous.error + 1; stable = false; } } } } if( stable ) break; } // debug std::cout << "\nstatic SingleColourLookup const " << name << "[] = \n{\n"; for( int i = 0;; ) { std::cout << "\t{ { "; for( int j = 0;; ) { SourceBlock const& block = values[i].sources[j]; if( j < colours ) std::cout << "{ " << block.start << ", " << block.end << ", " << block.error << " }"; else std::cout << "{ 0, 0, 0 }"; if( ++j == 2 ) break; std::cout << ", "; } std::cout << " } }"; if( ++i == 256 ) break; std::cout << ",\n"; } std::cout << "\n};\n"; } int main() { GenerateData( "lookup_5_3", 5, 3 ); GenerateData( "lookup_6_3", 6, 3 ); GenerateData( "lookup_5_4", 5, 4 ); GenerateData( "lookup_6_4", 6, 4 ); } extra/squishpng.cpp0000644000076500000240000003575612771161730014471 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ /*! @file @brief Test program that compresses images loaded using the PNG format. This program requires libpng for PNG input and output, and is designed to test the RMS error for DXT compression for a set of test images. This program uses the high-level image compression and decompression functions that process an entire image at a time. */ #include #include #include #include #include #include #include #ifdef _MSC_VER #pragma warning( disable: 4511 4512 ) #endif // def _MSC_VER using namespace squish; //! Simple exception class. class Error : public std::exception { public: Error( std::string const& excuse ) : m_excuse( excuse ) {} ~Error() throw() {} virtual char const* what() const throw() { return m_excuse.c_str(); } private: std::string m_excuse; }; //! Base class to make derived classes non-copyable class NonCopyable { public: NonCopyable() {} private: NonCopyable( NonCopyable const& ); NonCopyable& operator=( NonCopyable const& ); }; //! Memory object. class Mem : NonCopyable { public: Mem() : m_p( 0 ) {} explicit Mem( int size ) : m_p( new u8[size] ) {} ~Mem() { delete[] m_p; } void Reset( int size ) { u8 *p = new u8[size]; delete m_p; m_p = p; } u8* Get() const { return m_p; } private: u8* m_p; }; //! File object. class File : NonCopyable { public: explicit File( FILE* fp ) : m_fp( fp ) {} ~File() { if( m_fp ) fclose( m_fp ); } bool IsValid() const { return m_fp != 0; } FILE* Get() const { return m_fp; } private: FILE* m_fp; }; //! PNG read object. class PngReadStruct : NonCopyable { public: PngReadStruct() : m_png( 0 ), m_info( 0 ), m_end( 0 ) { m_png = png_create_read_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); if( !m_png ) throw Error( "failed to create png read struct" ); m_info = png_create_info_struct( m_png ); m_end = png_create_info_struct( m_png ); if( !m_info || !m_end ) { png_infopp info = m_info ? &m_info : 0; png_infopp end = m_end ? &m_end : 0; png_destroy_read_struct( &m_png, info, end ); throw Error( "failed to create png info structs" ); } } ~PngReadStruct() { png_destroy_read_struct( &m_png, &m_info, &m_end ); } png_structp GetPng() const { return m_png; } png_infop GetInfo() const { return m_info; } private: png_structp m_png; png_infop m_info, m_end; }; //! PNG write object. class PngWriteStruct : NonCopyable { public: PngWriteStruct() : m_png( 0 ), m_info( 0 ) { m_png = png_create_write_struct( PNG_LIBPNG_VER_STRING, 0, 0, 0 ); if( !m_png ) throw Error( "failed to create png read struct" ); m_info = png_create_info_struct( m_png ); if( !m_info ) { png_infopp info = m_info ? &m_info : 0; png_destroy_write_struct( &m_png, info ); throw Error( "failed to create png info structs" ); } } ~PngWriteStruct() { png_destroy_write_struct( &m_png, &m_info ); } png_structp GetPng() const { return m_png; } png_infop GetInfo() const { return m_info; } private: png_structp m_png; png_infop m_info; }; //! PNG rows object. class PngRows : NonCopyable { public: PngRows( int pitch, int height ) : m_height( height ) { m_rows = new png_bytep[m_height]; for( int i = 0; i < m_height; ++i ) m_rows[i] = new png_byte[pitch]; } ~PngRows() { for( int i = 0; i < m_height; ++i ) delete[] m_rows[i]; delete[] m_rows; } png_bytep* Get() const { return m_rows; } png_bytep operator[](int y) const { return m_rows[y]; } private: png_bytep* m_rows; int m_height; }; //! Represents a DXT compressed image in memory. struct DxtData { int width; int height; int format; //!< Either kDxt1, kDxt3 or kDxt5. Mem data; bool isColour; bool isAlpha; }; //! Represents an uncompressed RGBA image in memory. class Image { public: Image(); void LoadPng( std::string const& fileName ); void SavePng( std::string const& fileName ) const; void Decompress( DxtData const& dxt ); void Compress( DxtData& dxt, int flags ) const; double GetRmsError( Image const& image ) const; private: int m_width; int m_height; bool m_isColour; //!< Either colour or luminance. bool m_isAlpha; //!< Either alpha or not. Mem m_pixels; }; Image::Image() : m_width( 0 ), m_height( 0 ), m_isColour( false ), m_isAlpha( false ) { } void Image::LoadPng( std::string const& fileName ) { // open the source file File file( fopen( fileName.c_str(), "rb" ) ); if( !file.IsValid() ) { std::ostringstream oss; oss << "failed to open \"" << fileName << "\" for reading"; throw Error( oss.str() ); } // check the signature bytes png_byte header[8]; size_t check = fread( header, 1, 8, file.Get() ); if( check != 8 ) throw Error( "file read error" ); if( png_sig_cmp( header, 0, 8 ) ) { std::ostringstream oss; oss << "\"" << fileName << "\" does not look like a png file"; throw Error( oss.str() ); } // read the image into memory PngReadStruct png; png_init_io( png.GetPng(), file.Get() ); png_set_sig_bytes( png.GetPng(), 8 ); png_read_png( png.GetPng(), png.GetInfo(), PNG_TRANSFORM_EXPAND, 0 ); // get the image info png_uint_32 width; png_uint_32 height; int bitDepth; int colourType; png_get_IHDR( png.GetPng(), png.GetInfo(), &width, &height, &bitDepth, &colourType, 0, 0, 0 ); // check the image is 8 bit if( bitDepth != 8 ) { std::ostringstream oss; oss << "cannot process " << bitDepth << "-bit image (bit depth must be 8)"; throw Error( oss.str() ); } // copy the data into a contiguous array m_width = width; m_height = height; m_isColour = ( ( colourType & PNG_COLOR_MASK_COLOR ) != 0 ); m_isAlpha = ( ( colourType & PNG_COLOR_MASK_ALPHA ) != 0 ); m_pixels.Reset(4*width*height); // get the image rows png_bytep const *rows = png_get_rows( png.GetPng(), png.GetInfo() ); if( !rows ) throw Error( "failed to get image rows" ); // copy the pixels into the storage u8 *dest = m_pixels.Get(); for( int y = 0; y < m_height; ++y ) { u8 const *src = rows[y]; for( int x = 0; x < m_width; ++x ) { if( m_isColour ) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; src += 3; } else { u8 lum = *src++; dest[0] = lum; dest[1] = lum; dest[2] = lum; } if( m_isAlpha ) dest[3] = *src++; else dest[3] = 255; dest += 4; } } } void Image::SavePng( std::string const& fileName ) const { // create the target rows int const pixelSize = ( m_isColour ? 3 : 1 ) + ( m_isAlpha ? 1 : 0 ); PngRows rows( m_width*pixelSize, m_height ); // fill the rows with pixel data u8 const *src = m_pixels.Get(); for( int y = 0; y < m_height; ++y ) { u8 *dest = rows[y]; for( int x = 0; x < m_width; ++x ) { if( m_isColour ) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; dest += 3; } else *dest++ = src[1]; if( m_isAlpha ) *dest++ = src[3]; src += 4; } } // set up the image PngWriteStruct png; png_set_IHDR( png.GetPng(), png.GetInfo(), m_width, m_height, 8, ( m_isColour ? PNG_COLOR_MASK_COLOR : 0) | ( m_isAlpha ? PNG_COLOR_MASK_ALPHA : 0 ), PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT ); // open the target file File file( fopen( fileName.c_str(), "wb" ) ); if( !file.IsValid() ) { std::ostringstream oss; oss << "failed to open \"" << fileName << "\" for writing"; throw Error( oss.str() ); } // write the image png_set_rows( png.GetPng(), png.GetInfo(), rows.Get() ); png_init_io( png.GetPng(), file.Get() ); png_write_png( png.GetPng(), png.GetInfo(), PNG_TRANSFORM_IDENTITY, 0 ); } void Image::Decompress( DxtData const& dxt ) { // allocate storage m_width = dxt.width; m_height = dxt.height; m_isColour = dxt.isColour; m_isAlpha = dxt.isAlpha; m_pixels.Reset( 4*m_width*m_height ); // use the whole image decompression function to do the work DecompressImage( m_pixels.Get(), m_width, m_height, dxt.data.Get(), dxt.format ); } void Image::Compress( DxtData& dxt, int flags ) const { // work out how much memory we need int storageSize = GetStorageRequirements( m_width, m_height, flags ); // set the structure fields and allocate it dxt.width = m_width; dxt.height = m_height; dxt.format = flags & ( kDxt1 | kDxt3 | kDxt5 ); dxt.isColour = m_isColour; dxt.isAlpha = m_isAlpha; dxt.data.Reset( storageSize ); // use the whole image compression function to do the work CompressImage( m_pixels.Get(), m_width, m_height, dxt.data.Get(), flags ); } double Image::GetRmsError( Image const& image ) const { if( m_width != image.m_width || m_height != image.m_height ) throw Error( "image dimensions mismatch when computing RMS error" ); // accumulate colour error double difference = 0; u8 const *a = m_pixels.Get(); u8 const *b = image.m_pixels.Get(); for( int y = 0; y < m_height; ++y ) { for( int x = 0; x < m_width; ++x ) { int d0 = ( int )a[0] - ( int )b[0]; int d1 = ( int )a[1] - ( int )b[1]; int d2 = ( int )a[2] - ( int )b[2]; difference += ( double )( d0*d0 + d1*d1 + d2*d2 ); a += 4; b += 4; } } return std::sqrt( difference/( double )( m_width*m_height ) ); } int main( int argc, char* argv[] ) { try { // parse the command-line std::string sourceFileName; std::string targetFileName; int format = kDxt1; int fit = kColourClusterFit; int extra = 0; bool help = false; bool arguments = true; bool error = false; for( int i = 1; i < argc; ++i ) { // check for options char const* word = argv[i]; if( arguments && word[0] == '-' ) { for( int j = 1; word[j] != '\0'; ++j ) { switch( word[j] ) { case 'h': help = true; break; case '1': format = kDxt1; break; case '3': format = kDxt3; break; case '5': format = kDxt5; break; case 'r': fit = kColourRangeFit; break; case 'i': fit = kColourIterativeClusterFit; break; case 'w': extra = kWeightColourByAlpha; break; case '-': arguments = false; break; default: std::cerr << "squishpng error: unknown option '" << word[j] << "'" << std::endl; error = true; } } } else { if( sourceFileName.empty() ) sourceFileName.assign( word ); else if( targetFileName.empty() ) targetFileName.assign( word ); else { std::cerr << "squishpng error: unexpected argument \"" << word << "\"" << std::endl; error = true; } } } // check arguments if( sourceFileName.empty() ) { std::cerr << "squishpng error: no source file given" << std::endl; error = true; } if( help || error ) { std::cout << "SYNTAX" << std::endl << "\tsquishpng [-135riw] []" << std::endl << "OPTIONS" << std::endl << "\t-h\tPrint this help message" << std::endl << "\t-135\tSpecifies whether to use DXT1 (default), DXT3 or DXT5 compression" << std::endl << "\t-r\tUse the fast but inferior range-based colour compressor" << std::endl << "\t-i\tUse the very slow but slightly better iterative colour compressor" << std::endl << "\t-w\tWeight colour values by alpha in the cluster colour compressor" << std::endl ; return error ? -1 : 0; } // load the source image Image sourceImage; sourceImage.LoadPng( sourceFileName ); // compress to DXT DxtData dxt; sourceImage.Compress( dxt, format | fit | extra ); // decompress back Image targetImage; targetImage.Decompress( dxt ); // compare the images double rmsError = sourceImage.GetRmsError( targetImage ); std::cout << sourceFileName << " " << rmsError << std::endl; // save the target image if necessary if( !targetFileName.empty() ) targetImage.SavePng( targetFileName ); } catch( std::exception& excuse ) { // complain std::cerr << "squishpng error: " << excuse.what() << std::endl; return -1; } // done return 0; } extra/squishtest.cpp0000644000076500000240000001365012771161730014651 0ustar roettgerstaff/* ----------------------------------------------------------------------------- Copyright (c) 2006 Simon Brown si@sjbrown.co.uk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------- */ /*! @file @brief This program tests the error for 1 and 2-colour DXT compression. This tests the effectiveness of the DXT compression algorithm for all possible 1 and 2-colour blocks of pixels. */ #include #include #include #include #include using namespace squish; double GetColourError( u8 const* a, u8 const* b ) { double error = 0.0; for( int i = 0; i < 16; ++i ) { for( int j = 0; j < 3; ++j ) { int index = 4*i + j; int diff = ( int )a[index] - ( int )b[index]; error += ( double )( diff*diff ); } } return error / 16.0; } void TestOneColour( int flags ) { u8 input[4*16]; u8 output[4*16]; u8 block[16]; double avg = 0.0, min = DBL_MAX, max = -DBL_MAX; int counter = 0; // test all single-channel colours for( int i = 0; i < 16*4; ++i ) input[i] = ( ( i % 4 ) == 3 ) ? 255 : 0; for( int channel = 0; channel < 3; ++channel ) { for( int value = 0; value < 255; ++value ) { // set the channnel value for( int i = 0; i < 16; ++i ) input[4*i + channel] = ( u8 )value; // compress and decompress Compress( input, block, flags ); Decompress( output, block, flags ); // test the results double rm = GetColourError( input, output ); double rms = std::sqrt( rm ); // accumulate stats min = std::min( min, rms ); max = std::max( max, rms ); avg += rm; ++counter; } // reset the channel value for( int i = 0; i < 16; ++i ) input[4*i + channel] = 0; } // finish stats avg = std::sqrt( avg/counter ); // show stats std::cout << "one colour error (min, max, avg): " << min << ", " << max << ", " << avg << std::endl; } void TestOneColourRandom( int flags ) { u8 input[4*16]; u8 output[4*16]; u8 block[16]; double avg = 0.0, min = DBL_MAX, max = -DBL_MAX; int counter = 0; // test all single-channel colours for( int test = 0; test < 1000; ++test ) { // set a constant random colour for( int channel = 0; channel < 3; ++channel ) { u8 value = ( u8 )( rand() & 0xff ); for( int i = 0; i < 16; ++i ) input[4*i + channel] = value; } for( int i = 0; i < 16; ++i ) input[4*i + 3] = 255; // compress and decompress Compress( input, block, flags ); Decompress( output, block, flags ); // test the results double rm = GetColourError( input, output ); double rms = std::sqrt( rm ); // accumulate stats min = std::min( min, rms ); max = std::max( max, rms ); avg += rm; ++counter; } // finish stats avg = std::sqrt( avg/counter ); // show stats std::cout << "random one colour error (min, max, avg): " << min << ", " << max << ", " << avg << std::endl; } void TestTwoColour( int flags ) { u8 input[4*16]; u8 output[4*16]; u8 block[16]; double avg = 0.0, min = DBL_MAX, max = -DBL_MAX; int counter = 0; // test all single-channel colours for( int i = 0; i < 16*4; ++i ) input[i] = ( ( i % 4 ) == 3 ) ? 255 : 0; for( int channel = 0; channel < 3; ++channel ) { for( int value1 = 0; value1 < 255; ++value1 ) { for( int value2 = value1 + 1; value2 < 255; ++value2 ) { // set the channnel value for( int i = 0; i < 16; ++i ) input[4*i + channel] = ( u8 )( ( i < 8 ) ? value1 : value2 ); // compress and decompress Compress( input, block, flags ); Decompress( output, block, flags ); // test the results double rm = GetColourError( input, output ); double rms = std::sqrt( rm ); // accumulate stats min = std::min( min, rms ); max = std::max( max, rms ); avg += rm; ++counter; } } // reset the channel value for( int i = 0; i < 16; ++i ) input[4*i + channel] = 0; } // finish stats avg = std::sqrt( avg/counter ); // show stats std::cout << "two colour error (min, max, avg): " << min << ", " << max << ", " << avg << std::endl; } int main() { TestOneColourRandom( kDxt1 | kColourRangeFit ); TestOneColour( kDxt1 ); TestTwoColour( kDxt1 ); }