rangefit.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /* -----------------------------------------------------------------------------
  2. Copyright (c) 2006 Simon Brown si@sjbrown.co.uk
  3. Permission is hereby granted, free of charge, to any person obtaining
  4. a copy of this software and associated documentation files (the
  5. "Software"), to deal in the Software without restriction, including
  6. without limitation the rights to use, copy, modify, merge, publish,
  7. distribute, sublicense, and/or sell copies of the Software, and to
  8. permit persons to whom the Software is furnished to do so, subject to
  9. the following conditions:
  10. The above copyright notice and this permission notice shall be included
  11. in all copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  13. OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  14. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  15. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  16. CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  17. TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  18. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  19. -------------------------------------------------------------------------- */
  20. #include "rangefit.h"
  21. #include "colourset.h"
  22. #include "colourblock.h"
  23. #include <cfloat>
  24. namespace squish {
  25. RangeFit::RangeFit( ColourSet const* colours, int flags )
  26. : ColourFit( colours, flags )
  27. {
  28. // initialise the metric
  29. bool perceptual = ( ( m_flags & kColourMetricPerceptual ) != 0 );
  30. if( perceptual )
  31. m_metric = Vec3( 0.2126f, 0.7152f, 0.0722f );
  32. else
  33. m_metric = Vec3( 1.0f );
  34. // initialise the best error
  35. m_besterror = FLT_MAX;
  36. // cache some values
  37. int const count = m_colours->GetCount();
  38. Vec3 const* values = m_colours->GetPoints();
  39. float const* weights = m_colours->GetWeights();
  40. // get the covariance matrix
  41. Sym3x3 covariance = ComputeWeightedCovariance( count, values, weights );
  42. // compute the principle component
  43. Vec3 principle = ComputePrincipleComponent( covariance );
  44. // get the min and max range as the codebook endpoints
  45. Vec3 start( 0.0f );
  46. Vec3 end( 0.0f );
  47. if( count > 0 )
  48. {
  49. float min, max;
  50. // compute the range
  51. start = end = values[0];
  52. min = max = Dot( values[0], principle );
  53. for( int i = 1; i < count; ++i )
  54. {
  55. float val = Dot( values[i], principle );
  56. if( val < min )
  57. {
  58. start = values[i];
  59. min = val;
  60. }
  61. else if( val > max )
  62. {
  63. end = values[i];
  64. max = val;
  65. }
  66. }
  67. }
  68. // clamp the output to [0, 1]
  69. Vec3 const one( 1.0f );
  70. Vec3 const zero( 0.0f );
  71. start = Min( one, Max( zero, start ) );
  72. end = Min( one, Max( zero, end ) );
  73. // clamp to the grid and save
  74. Vec3 const grid( 31.0f, 63.0f, 31.0f );
  75. Vec3 const gridrcp( 1.0f/31.0f, 1.0f/63.0f, 1.0f/31.0f );
  76. Vec3 const half( 0.5f );
  77. m_start = Truncate( grid*start + half )*gridrcp;
  78. m_end = Truncate( grid*end + half )*gridrcp;
  79. }
  80. void RangeFit::Compress3( void* block )
  81. {
  82. // cache some values
  83. int const count = m_colours->GetCount();
  84. Vec3 const* values = m_colours->GetPoints();
  85. // create a codebook
  86. Vec3 codes[3];
  87. codes[0] = m_start;
  88. codes[1] = m_end;
  89. codes[2] = 0.5f*m_start + 0.5f*m_end;
  90. // match each point to the closest code
  91. u8 closest[16];
  92. float error = 0.0f;
  93. for( int i = 0; i < count; ++i )
  94. {
  95. // find the closest code
  96. float dist = FLT_MAX;
  97. int idx = 0;
  98. for( int j = 0; j < 3; ++j )
  99. {
  100. float d = LengthSquared( m_metric*( values[i] - codes[j] ) );
  101. if( d < dist )
  102. {
  103. dist = d;
  104. idx = j;
  105. }
  106. }
  107. // save the index
  108. closest[i] = ( u8 )idx;
  109. // accumulate the error
  110. error += dist;
  111. }
  112. // save this scheme if it wins
  113. if( error < m_besterror )
  114. {
  115. // remap the indices
  116. u8 indices[16];
  117. m_colours->RemapIndices( closest, indices );
  118. // save the block
  119. WriteColourBlock3( m_start, m_end, indices, block );
  120. // save the error
  121. m_besterror = error;
  122. }
  123. }
  124. void RangeFit::Compress4( void* block )
  125. {
  126. // cache some values
  127. int const count = m_colours->GetCount();
  128. Vec3 const* values = m_colours->GetPoints();
  129. // create a codebook
  130. Vec3 codes[4];
  131. codes[0] = m_start;
  132. codes[1] = m_end;
  133. codes[2] = ( 2.0f/3.0f )*m_start + ( 1.0f/3.0f )*m_end;
  134. codes[3] = ( 1.0f/3.0f )*m_start + ( 2.0f/3.0f )*m_end;
  135. // match each point to the closest code
  136. u8 closest[16];
  137. float error = 0.0f;
  138. for( int i = 0; i < count; ++i )
  139. {
  140. // find the closest code
  141. float dist = FLT_MAX;
  142. int idx = 0;
  143. for( int j = 0; j < 4; ++j )
  144. {
  145. float d = LengthSquared( m_metric*( values[i] - codes[j] ) );
  146. if( d < dist )
  147. {
  148. dist = d;
  149. idx = j;
  150. }
  151. }
  152. // save the index
  153. closest[i] = ( u8 )idx;
  154. // accumulate the error
  155. error += dist;
  156. }
  157. // save this scheme if it wins
  158. if( error < m_besterror )
  159. {
  160. // remap the indices
  161. u8 indices[16];
  162. m_colours->RemapIndices( closest, indices );
  163. // save the block
  164. WriteColourBlock4( m_start, m_end, indices, block );
  165. // save the error
  166. m_besterror = error;
  167. }
  168. }
  169. } // namespace squish