colourblock.cpp 5.1 KB

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