basisu_pvrtc1_4.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // basisu_pvrtc1_4.cpp
  2. // Copyright (C) 2019 Binomial LLC. All Rights Reserved.
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. #pragma once
  16. #include "basisu_gpu_texture.h"
  17. namespace basisu
  18. {
  19. enum
  20. {
  21. PVRTC2_MIN_WIDTH = 16,
  22. PVRTC2_MIN_HEIGHT = 8,
  23. PVRTC4_MIN_WIDTH = 8,
  24. PVRTC4_MIN_HEIGHT = 8
  25. };
  26. struct pvrtc4_block
  27. {
  28. uint32_t m_modulation;
  29. uint32_t m_endpoints;
  30. pvrtc4_block() : m_modulation(0), m_endpoints(0) { }
  31. inline bool operator== (const pvrtc4_block& rhs) const
  32. {
  33. return (m_modulation == rhs.m_modulation) && (m_endpoints == rhs.m_endpoints);
  34. }
  35. inline void clear()
  36. {
  37. m_modulation = 0;
  38. m_endpoints = 0;
  39. }
  40. inline bool get_block_uses_transparent_modulation() const
  41. {
  42. return (m_endpoints & 1) != 0;
  43. }
  44. inline bool is_endpoint_opaque(uint32_t endpoint_index) const
  45. {
  46. static const uint32_t s_bitmasks[2] = { 0x8000U, 0x80000000U };
  47. return (m_endpoints & s_bitmasks[open_range_check(endpoint_index, 2U)]) != 0;
  48. }
  49. // Returns raw endpoint or 8888
  50. color_rgba get_endpoint(uint32_t endpoint_index, bool unpack) const;
  51. color_rgba get_endpoint_5554(uint32_t endpoint_index) const;
  52. static uint32_t get_component_precision_in_bits(uint32_t c, uint32_t endpoint_index, bool opaque_endpoint)
  53. {
  54. static const uint32_t s_comp_prec[4][4] =
  55. {
  56. // R0 G0 B0 A0 R1 G1 B1 A1
  57. { 4, 4, 3, 3 }, { 4, 4, 4, 3 }, // transparent endpoint
  58. { 5, 5, 4, 0 }, { 5, 5, 5, 0 } // opaque endpoint
  59. };
  60. return s_comp_prec[open_range_check(endpoint_index, 2U) + (opaque_endpoint * 2)][open_range_check(c, 4U)];
  61. }
  62. static color_rgba get_color_precision_in_bits(uint32_t endpoint_index, bool opaque_endpoint)
  63. {
  64. static const color_rgba s_color_prec[4] =
  65. {
  66. color_rgba(4, 4, 3, 3), color_rgba(4, 4, 4, 3), // transparent endpoint
  67. color_rgba(5, 5, 4, 0), color_rgba(5, 5, 5, 0) // opaque endpoint
  68. };
  69. return s_color_prec[open_range_check(endpoint_index, 2U) + (opaque_endpoint * 2)];
  70. }
  71. inline uint32_t get_modulation(uint32_t x, uint32_t y) const
  72. {
  73. assert((x < 4) && (y < 4));
  74. return (m_modulation >> ((y * 4 + x) * 2)) & 3;
  75. }
  76. // Scaled by 8
  77. inline const uint32_t* get_scaled_modulation_values(bool block_uses_transparent_modulation) const
  78. {
  79. static const uint32_t s_block_scales[2][4] = { { 0, 3, 5, 8 }, { 0, 4, 4, 8 } };
  80. return s_block_scales[block_uses_transparent_modulation];
  81. }
  82. // Scaled by 8
  83. inline uint32_t get_scaled_modulation(uint32_t x, uint32_t y) const
  84. {
  85. return get_scaled_modulation_values(get_block_uses_transparent_modulation())[get_modulation(x, y)];
  86. }
  87. inline void byte_swap()
  88. {
  89. m_modulation = byteswap32(m_modulation);
  90. m_endpoints = byteswap32(m_endpoints);
  91. }
  92. // opaque endpoints: 554, 555
  93. // transparent endpoints: 3443 or 3444
  94. inline void set_endpoint_raw(uint32_t endpoint_index, const color_rgba& c, bool opaque_endpoint)
  95. {
  96. assert(endpoint_index < 2);
  97. const uint32_t m = m_endpoints & 1;
  98. uint32_t r = c[0], g = c[1], b = c[2], a = c[3];
  99. uint32_t packed;
  100. if (opaque_endpoint)
  101. {
  102. if (!endpoint_index)
  103. {
  104. // 554
  105. // 1RRRRRGGGGGBBBBM
  106. assert((r < 32) && (g < 32) && (b < 16));
  107. packed = 0x8000 | (r << 10) | (g << 5) | (b << 1) | m;
  108. }
  109. else
  110. {
  111. // 555
  112. // 1RRRRRGGGGGBBBBB
  113. assert((r < 32) && (g < 32) && (b < 32));
  114. packed = 0x8000 | (r << 10) | (g << 5) | b;
  115. }
  116. }
  117. else
  118. {
  119. if (!endpoint_index)
  120. {
  121. // 3443
  122. // 0AAA RRRR GGGG BBBM
  123. assert((r < 16) && (g < 16) && (b < 8) && (a < 8));
  124. packed = (a << 12) | (r << 8) | (g << 4) | (b << 1) | m;
  125. }
  126. else
  127. {
  128. // 3444
  129. // 0AAA RRRR GGGG BBBB
  130. assert((r < 16) && (g < 16) && (b < 16) && (a < 8));
  131. packed = (a << 12) | (r << 8) | (g << 4) | b;
  132. }
  133. }
  134. assert(packed <= 0xFFFF);
  135. if (endpoint_index)
  136. m_endpoints = (m_endpoints & 0xFFFFU) | (packed << 16);
  137. else
  138. m_endpoints = (m_endpoints & 0xFFFF0000U) | packed;
  139. }
  140. };
  141. typedef vector2D<pvrtc4_block> pvrtc4_block_vector2D;
  142. uint32_t pvrtc4_swizzle_uv(uint32_t XSize, uint32_t YSize, uint32_t XPos, uint32_t YPos);
  143. class pvrtc4_image
  144. {
  145. public:
  146. inline pvrtc4_image() :
  147. m_width(0), m_height(0), m_block_width(0), m_block_height(0), m_wrap_addressing(false), m_uses_alpha(false)
  148. {
  149. }
  150. inline pvrtc4_image(uint32_t width, uint32_t height, bool wrap_addressing = false) :
  151. m_width(0), m_height(0), m_block_width(0), m_block_height(0), m_wrap_addressing(false), m_uses_alpha(false)
  152. {
  153. resize(width, height);
  154. set_wrap_addressing(wrap_addressing);
  155. }
  156. inline void clear()
  157. {
  158. m_width = 0;
  159. m_height = 0;
  160. m_block_width = 0;
  161. m_block_height = 0;
  162. m_blocks.clear();
  163. m_uses_alpha = false;
  164. m_wrap_addressing = false;
  165. }
  166. inline void resize(uint32_t width, uint32_t height)
  167. {
  168. if ((width == m_width) && (height == m_height))
  169. return;
  170. m_width = width;
  171. m_height = height;
  172. m_block_width = (width + 3) >> 2;
  173. m_block_height = (height + 3) >> 2;
  174. m_blocks.resize(m_block_width, m_block_height);
  175. }
  176. inline uint32_t get_width() const { return m_width; }
  177. inline uint32_t get_height() const { return m_height; }
  178. inline uint32_t get_block_width() const { return m_block_width; }
  179. inline uint32_t get_block_height() const { return m_block_height; }
  180. inline const pvrtc4_block_vector2D &get_blocks() const { return m_blocks; }
  181. inline pvrtc4_block_vector2D &get_blocks() { return m_blocks; }
  182. inline uint32_t get_total_blocks() const { return m_block_width * m_block_height; }
  183. inline bool get_uses_alpha() const { return m_uses_alpha; }
  184. inline void set_uses_alpha(bool uses_alpha) { m_uses_alpha = uses_alpha; }
  185. inline void set_wrap_addressing(bool wrapping) { m_wrap_addressing = wrapping; }
  186. inline bool get_wrap_addressing() const { return m_wrap_addressing; }
  187. inline bool are_blocks_equal(const pvrtc4_image& rhs) const
  188. {
  189. return m_blocks == rhs.m_blocks;
  190. }
  191. inline void set_to_black()
  192. {
  193. memset(m_blocks.get_ptr(), 0, m_blocks.size_in_bytes());
  194. }
  195. inline bool get_block_uses_transparent_modulation(uint32_t bx, uint32_t by) const
  196. {
  197. return m_blocks(bx, by).get_block_uses_transparent_modulation();
  198. }
  199. inline bool is_endpoint_opaque(uint32_t bx, uint32_t by, uint32_t endpoint_index) const
  200. {
  201. return m_blocks(bx, by).is_endpoint_opaque(endpoint_index);
  202. }
  203. color_rgba get_endpoint(uint32_t bx, uint32_t by, uint32_t endpoint_index, bool unpack) const
  204. {
  205. assert((bx < m_block_width) && (by < m_block_height));
  206. return m_blocks(bx, by).get_endpoint(endpoint_index, unpack);
  207. }
  208. inline uint32_t get_modulation(uint32_t x, uint32_t y) const
  209. {
  210. assert((x < m_width) && (y < m_height));
  211. return m_blocks(x >> 2, y >> 2).get_modulation(x & 3, y & 3);
  212. }
  213. // Returns true if the block uses transparent modulation.
  214. bool get_interpolated_colors(uint32_t x, uint32_t y, color_rgba* pColors) const;
  215. color_rgba get_pixel(uint32_t x, uint32_t y, uint32_t m) const;
  216. inline color_rgba get_pixel(uint32_t x, uint32_t y) const
  217. {
  218. assert((x < m_width) && (y < m_height));
  219. return get_pixel(x, y, m_blocks(x >> 2, y >> 2).get_modulation(x & 3, y & 3));
  220. }
  221. void deswizzle()
  222. {
  223. pvrtc4_block_vector2D temp(m_blocks);
  224. for (uint32_t y = 0; y < m_block_height; y++)
  225. for (uint32_t x = 0; x < m_block_width; x++)
  226. m_blocks(x, y) = temp[pvrtc4_swizzle_uv(m_block_width, m_block_height, x, y)];
  227. }
  228. void swizzle()
  229. {
  230. pvrtc4_block_vector2D temp(m_blocks);
  231. for (uint32_t y = 0; y < m_block_height; y++)
  232. for (uint32_t x = 0; x < m_block_width; x++)
  233. m_blocks[pvrtc4_swizzle_uv(m_block_width, m_block_height, x, y)] = temp(x, y);
  234. }
  235. void unpack_all_pixels(image& img) const
  236. {
  237. img.crop(m_width, m_height);
  238. for (uint32_t y = 0; y < m_height; y++)
  239. for (uint32_t x = 0; x < m_width; x++)
  240. img(x, y) = get_pixel(x, y);
  241. }
  242. void unpack_block(image &dst, uint32_t block_x, uint32_t block_y)
  243. {
  244. for (uint32_t y = 0; y < 4; y++)
  245. for (uint32_t x = 0; x < 4; x++)
  246. dst(x, y) = get_pixel(block_x * 4 + x, block_y * 4 + y);
  247. }
  248. inline int wrap_or_clamp_x(int x) const
  249. {
  250. return m_wrap_addressing ? posmod(x, m_width) : clamp<int>(x, 0, m_width - 1);
  251. }
  252. inline int wrap_or_clamp_y(int y) const
  253. {
  254. return m_wrap_addressing ? posmod(y, m_height) : clamp<int>(y, 0, m_height - 1);
  255. }
  256. inline int wrap_or_clamp_block_x(int bx) const
  257. {
  258. return m_wrap_addressing ? posmod(bx, m_block_width) : clamp<int>(bx, 0, m_block_width - 1);
  259. }
  260. inline int wrap_or_clamp_block_y(int by) const
  261. {
  262. return m_wrap_addressing ? posmod(by, m_block_height) : clamp<int>(by, 0, m_block_height - 1);
  263. }
  264. inline vec2F get_interpolation_factors(uint32_t x, uint32_t y) const
  265. {
  266. // 0 1 2 3
  267. // 2 3 0 1
  268. // .5 .75 0 .25
  269. static const float s_interp[4] = { 2, 3, 0, 1 };
  270. return vec2F(s_interp[x & 3], s_interp[y & 3]);
  271. }
  272. inline color_rgba interpolate(int x, int y,
  273. const color_rgba& p, const color_rgba& q,
  274. const color_rgba& r, const color_rgba& s) const
  275. {
  276. static const int s_interp[4] = { 2, 3, 0, 1 };
  277. const int u_interp = s_interp[x & 3];
  278. const int v_interp = s_interp[y & 3];
  279. color_rgba result;
  280. for (uint32_t c = 0; c < 4; c++)
  281. {
  282. int t = p[c] * 4 + u_interp * ((int)q[c] - (int)p[c]);
  283. int b = r[c] * 4 + u_interp * ((int)s[c] - (int)r[c]);
  284. int v = t * 4 + v_interp * (b - t);
  285. if (c < 3)
  286. {
  287. v >>= 1;
  288. v += (v >> 5);
  289. }
  290. else
  291. {
  292. v += (v >> 4);
  293. }
  294. assert((v >= 0) && (v < 256));
  295. result[c] = static_cast<uint8_t>(v);
  296. }
  297. return result;
  298. }
  299. uint32_t m_width, m_height;
  300. pvrtc4_block_vector2D m_blocks;
  301. uint32_t m_block_width, m_block_height;
  302. bool m_wrap_addressing;
  303. bool m_uses_alpha;
  304. };
  305. } // namespace basisu