colourblock.cpp 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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 "colourblock.h"
  21. namespace squish {
  22. static int FloatToInt( float a, int limit )
  23. {
  24. // use ANSI round-to-zero behaviour to get round-to-nearest
  25. int i = ( int )( a + 0.5f );
  26. // clamp to the limit
  27. if( i < 0 )
  28. i = 0;
  29. else if( i > limit )
  30. i = limit;
  31. // done
  32. return i;
  33. }
  34. static int FloatTo565( Vec3::Arg colour )
  35. {
  36. // get the components in the correct range
  37. int r = FloatToInt( 31.0f*colour.X(), 31 );
  38. int g = FloatToInt( 63.0f*colour.Y(), 63 );
  39. int b = FloatToInt( 31.0f*colour.Z(), 31 );
  40. // pack into a single value
  41. return ( r << 11 ) | ( g << 5 ) | b;
  42. }
  43. static void WriteColourBlock( int a, int b, u8* indices, void* block )
  44. {
  45. // get the block as bytes
  46. u8* bytes = ( u8* )block;
  47. // write the endpoints
  48. bytes[0] = ( u8 )( a & 0xff );
  49. bytes[1] = ( u8 )( a >> 8 );
  50. bytes[2] = ( u8 )( b & 0xff );
  51. bytes[3] = ( u8 )( b >> 8 );
  52. // write the indices
  53. for( int i = 0; i < 4; ++i )
  54. {
  55. u8 const* ind = indices + 4*i;
  56. bytes[4 + i] = ind[0] | ( ind[1] << 2 ) | ( ind[2] << 4 ) | ( ind[3] << 6 );
  57. }
  58. }
  59. void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block )
  60. {
  61. // get the packed values
  62. int a = FloatTo565( start );
  63. int b = FloatTo565( end );
  64. // remap the indices
  65. u8 remapped[16];
  66. if( a <= b )
  67. {
  68. // use the indices directly
  69. for( int i = 0; i < 16; ++i )
  70. remapped[i] = indices[i];
  71. }
  72. else
  73. {
  74. // swap a and b
  75. std::swap( a, b );
  76. for( int i = 0; i < 16; ++i )
  77. {
  78. if( indices[i] == 0 )
  79. remapped[i] = 1;
  80. else if( indices[i] == 1 )
  81. remapped[i] = 0;
  82. else
  83. remapped[i] = indices[i];
  84. }
  85. }
  86. // write the block
  87. WriteColourBlock( a, b, remapped, block );
  88. }
  89. void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block )
  90. {
  91. // get the packed values
  92. int a = FloatTo565( start );
  93. int b = FloatTo565( end );
  94. // remap the indices
  95. u8 remapped[16];
  96. if( a < b )
  97. {
  98. // swap a and b
  99. std::swap( a, b );
  100. for( int i = 0; i < 16; ++i )
  101. remapped[i] = ( indices[i] ^ 0x1 ) & 0x3;
  102. }
  103. else if( a == b )
  104. {
  105. // use index 0
  106. for( int i = 0; i < 16; ++i )
  107. remapped[i] = 0;
  108. }
  109. else
  110. {
  111. // use the indices directly
  112. for( int i = 0; i < 16; ++i )
  113. remapped[i] = indices[i];
  114. }
  115. // write the block
  116. WriteColourBlock( a, b, remapped, block );
  117. }
  118. static int Unpack565( u8 const* packed, u8* colour )
  119. {
  120. // build the packed value
  121. int value = ( int )packed[0] | ( ( int )packed[1] << 8 );
  122. // get the components in the stored range
  123. u8 red = ( u8 )( ( value >> 11 ) & 0x1f );
  124. u8 green = ( u8 )( ( value >> 5 ) & 0x3f );
  125. u8 blue = ( u8 )( value & 0x1f );
  126. // scale up to 8 bits
  127. colour[0] = ( red << 3 ) | ( red >> 2 );
  128. colour[1] = ( green << 2 ) | ( green >> 4 );
  129. colour[2] = ( blue << 3 ) | ( blue >> 2 );
  130. colour[3] = 255;
  131. // return the value
  132. return value;
  133. }
  134. void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
  135. {
  136. // get the block bytes
  137. u8 const* bytes = reinterpret_cast< u8 const* >( block );
  138. // unpack the endpoints
  139. u8 codes[16];
  140. int a = Unpack565( bytes, codes );
  141. int b = Unpack565( bytes + 2, codes + 4 );
  142. // generate the midpoints
  143. for( int i = 0; i < 3; ++i )
  144. {
  145. int c = codes[i];
  146. int d = codes[4 + i];
  147. if( isDxt1 && a <= b )
  148. {
  149. codes[8 + i] = ( u8 )( ( c + d )/2 );
  150. codes[12 + i] = 0;
  151. }
  152. else
  153. {
  154. codes[8 + i] = ( u8 )( ( 2*c + d )/3 );
  155. codes[12 + i] = ( u8 )( ( c + 2*d )/3 );
  156. }
  157. }
  158. // fill in alpha for the intermediate values
  159. codes[8 + 3] = 255;
  160. codes[12 + 3] = ( isDxt1 && a <= b ) ? 0 : 255;
  161. // unpack the indices
  162. u8 indices[16];
  163. for( int i = 0; i < 4; ++i )
  164. {
  165. u8* ind = indices + 4*i;
  166. u8 packed = bytes[4 + i];
  167. ind[0] = packed & 0x3;
  168. ind[1] = ( packed >> 2 ) & 0x3;
  169. ind[2] = ( packed >> 4 ) & 0x3;
  170. ind[3] = ( packed >> 6 ) & 0x3;
  171. }
  172. // store out the colours
  173. for( int i = 0; i < 16; ++i )
  174. {
  175. u8 offset = 4*indices[i];
  176. for( int j = 0; j < 4; ++j )
  177. rgba[4*i + j] = codes[offset + j];
  178. }
  179. }
  180. } // namespace squish