colourblock.cpp 6.5 KB

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