basisu_pvrtc1_4.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. // basisu_pvrtc1_4.cpp
  2. // Copyright (C) 2019-2021 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. #include "basisu_pvrtc1_4.h"
  16. namespace basisu
  17. {
  18. #if 0
  19. static const uint8_t g_pvrtc_5[32] = { 0,8,16,24,33,41,49,57,66,74,82,90,99,107,115,123,132,140,148,156,165,173,181,189,198,206,214,222,231,239,247,255 };
  20. static const uint8_t g_pvrtc_4[16] = { 0,16,33,49,66,82,99,115,140,156,173,189,206,222,239,255 };
  21. static const uint8_t g_pvrtc_3[8] = { 0,33,74,107,148,181,222,255 };
  22. static const uint8_t g_pvrtc_alpha[9] = { 0,34,68,102,136,170,204,238,255 };
  23. #endif
  24. static const uint8_t g_pvrtc_5_nearest[256] = { 0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,31,31,31,31 };
  25. static const uint8_t g_pvrtc_4_nearest[256] = { 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15 };
  26. #if 0
  27. static const uint8_t g_pvrtc_3_nearest[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 };
  28. static const uint8_t g_pvrtc_alpha_nearest[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8 };
  29. #endif
  30. #if 0
  31. static const uint8_t g_pvrtc_5_floor[256] =
  32. {
  33. 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,
  34. 3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,
  35. 7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,
  36. 11,11,11,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,15,15,15,15,
  37. 15,15,15,15,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,
  38. 19,19,19,19,19,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,
  39. 23,23,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,
  40. 27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,31
  41. };
  42. static const uint8_t g_pvrtc_5_ceil[256] =
  43. {
  44. 0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,
  45. 4,4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,
  46. 8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,12,12,12,12,12,
  47. 12,12,12,12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,16,16,16,16,
  48. 16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,20,20,20,
  49. 20,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,24,24,
  50. 24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,28,
  51. 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,31
  52. };
  53. static const uint8_t g_pvrtc_4_floor[256] =
  54. {
  55. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  56. 1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
  57. 3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
  58. 5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,
  59. 7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,
  60. 9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,
  61. 11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,
  62. 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15
  63. };
  64. static const uint8_t g_pvrtc_4_ceil[256] =
  65. {
  66. 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  67. 2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
  68. 4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,
  69. 6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,
  70. 8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,
  71. 10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,
  72. 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,
  73. 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15
  74. };
  75. static const uint8_t g_pvrtc_3_floor[256] =
  76. {
  77. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  78. 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  79. 1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  80. 2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
  81. 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,
  82. 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,
  83. 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,
  84. 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7
  85. };
  86. static const uint8_t g_pvrtc_3_ceil[256] =
  87. {
  88. 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  89. 1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  90. 2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
  91. 3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
  92. 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,
  93. 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,
  94. 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,
  95. 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
  96. };
  97. static const uint8_t g_pvrtc_alpha_floor[256] =
  98. {
  99. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  100. 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  101. 1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  102. 2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
  103. 3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
  104. 4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
  105. 5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
  106. 6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8
  107. };
  108. static const uint8_t g_pvrtc_alpha_ceil[256] =
  109. {
  110. 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  111. 1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  112. 2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
  113. 3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
  114. 4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
  115. 5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
  116. 6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
  117. 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
  118. };
  119. #endif
  120. uint32_t pvrtc4_swizzle_uv(uint32_t width, uint32_t height, uint32_t x, uint32_t y)
  121. {
  122. assert((x < width) && (y < height) && basisu::is_pow2(height) && basisu::is_pow2(width));
  123. uint32_t min_d = width, max_v = y;
  124. if (height < width)
  125. {
  126. min_d = height;
  127. max_v = x;
  128. }
  129. // Interleave the XY LSB's
  130. uint32_t shift_ofs = 0, swizzled = 0;
  131. for (uint32_t s_bit = 1, d_bit = 1; s_bit < min_d; s_bit <<= 1, d_bit <<= 2, ++shift_ofs)
  132. {
  133. if (y & s_bit) swizzled |= d_bit;
  134. if (x & s_bit) swizzled |= (2 * d_bit);
  135. }
  136. max_v >>= shift_ofs;
  137. // OR in the rest of the bits from the largest dimension
  138. swizzled |= (max_v << (2 * shift_ofs));
  139. return swizzled;
  140. }
  141. color_rgba pvrtc4_block::get_endpoint(uint32_t endpoint_index, bool unpack) const
  142. {
  143. assert(endpoint_index < 2);
  144. const uint32_t packed = m_endpoints >> (endpoint_index * 16);
  145. uint32_t r, g, b, a;
  146. if (packed & 0x8000)
  147. {
  148. // opaque 554 or 555
  149. if (!endpoint_index)
  150. {
  151. r = (packed >> 10) & 31;
  152. g = (packed >> 5) & 31;
  153. b = (packed >> 1) & 15;
  154. if (unpack)
  155. {
  156. b = (b << 1) | (b >> 3);
  157. }
  158. }
  159. else
  160. {
  161. r = (packed >> 10) & 31;
  162. g = (packed >> 5) & 31;
  163. b = packed & 31;
  164. }
  165. a = unpack ? 255 : 7;
  166. }
  167. else
  168. {
  169. // translucent 4433 or 4443
  170. if (!endpoint_index)
  171. {
  172. a = (packed >> 12) & 7;
  173. r = (packed >> 8) & 15;
  174. g = (packed >> 4) & 15;
  175. b = (packed >> 1) & 7;
  176. if (unpack)
  177. {
  178. a = (a << 1);
  179. a = (a << 4) | a;
  180. r = (r << 1) | (r >> 3);
  181. g = (g << 1) | (g >> 3);
  182. b = (b << 2) | (b >> 1);
  183. }
  184. }
  185. else
  186. {
  187. a = (packed >> 12) & 7;
  188. r = (packed >> 8) & 15;
  189. g = (packed >> 4) & 15;
  190. b = packed & 15;
  191. if (unpack)
  192. {
  193. a = (a << 1);
  194. a = (a << 4) | a;
  195. r = (r << 1) | (r >> 3);
  196. g = (g << 1) | (g >> 3);
  197. b = (b << 1) | (b >> 3);
  198. }
  199. }
  200. }
  201. if (unpack)
  202. {
  203. r = (r << 3) | (r >> 2);
  204. g = (g << 3) | (g >> 2);
  205. b = (b << 3) | (b >> 2);
  206. }
  207. assert((r < 256) && (g < 256) && (b < 256) && (a < 256));
  208. return color_rgba(r, g, b, a);
  209. }
  210. color_rgba pvrtc4_block::get_endpoint_5554(uint32_t endpoint_index) const
  211. {
  212. assert(endpoint_index < 2);
  213. const uint32_t packed = m_endpoints >> (endpoint_index * 16);
  214. uint32_t r, g, b, a;
  215. if (packed & 0x8000)
  216. {
  217. // opaque 554 or 555
  218. if (!endpoint_index)
  219. {
  220. r = (packed >> 10) & 31;
  221. g = (packed >> 5) & 31;
  222. b = (packed >> 1) & 15;
  223. b = (b << 1) | (b >> 3);
  224. }
  225. else
  226. {
  227. r = (packed >> 10) & 31;
  228. g = (packed >> 5) & 31;
  229. b = packed & 31;
  230. }
  231. a = 15;
  232. }
  233. else
  234. {
  235. // translucent 4433 or 4443
  236. if (!endpoint_index)
  237. {
  238. a = (packed >> 12) & 7;
  239. r = (packed >> 8) & 15;
  240. g = (packed >> 4) & 15;
  241. b = (packed >> 1) & 7;
  242. a = a << 1;
  243. r = (r << 1) | (r >> 3);
  244. g = (g << 1) | (g >> 3);
  245. b = (b << 2) | (b >> 1);
  246. }
  247. else
  248. {
  249. a = (packed >> 12) & 7;
  250. r = (packed >> 8) & 15;
  251. g = (packed >> 4) & 15;
  252. b = packed & 15;
  253. a = a << 1;
  254. r = (r << 1) | (r >> 3);
  255. g = (g << 1) | (g >> 3);
  256. b = (b << 1) | (b >> 3);
  257. }
  258. }
  259. assert((r < 32) && (g < 32) && (b < 32) && (a < 16));
  260. return color_rgba(r, g, b, a);
  261. }
  262. bool pvrtc4_image::get_interpolated_colors(uint32_t x, uint32_t y, color_rgba* pColors) const
  263. {
  264. assert((x < m_width) && (y < m_height));
  265. int block_x0 = (static_cast<int>(x) - 2) >> 2;
  266. int block_x1 = block_x0 + 1;
  267. int block_y0 = (static_cast<int>(y) - 2) >> 2;
  268. int block_y1 = block_y0 + 1;
  269. block_x0 = posmod(block_x0, m_block_width);
  270. block_x1 = posmod(block_x1, m_block_width);
  271. block_y0 = posmod(block_y0, m_block_height);
  272. block_y1 = posmod(block_y1, m_block_height);
  273. pColors[0] = interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));
  274. pColors[3] = interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));
  275. if (get_block_uses_transparent_modulation(x >> 2, y >> 2))
  276. {
  277. for (uint32_t c = 0; c < 4; c++)
  278. {
  279. uint32_t m = (pColors[0][c] + pColors[3][c]) / 2;
  280. pColors[1][c] = static_cast<uint8_t>(m);
  281. pColors[2][c] = static_cast<uint8_t>(m);
  282. }
  283. pColors[2][3] = 0;
  284. return true;
  285. }
  286. for (uint32_t c = 0; c < 4; c++)
  287. {
  288. pColors[1][c] = static_cast<uint8_t>((pColors[0][c] * 5 + pColors[3][c] * 3) / 8);
  289. pColors[2][c] = static_cast<uint8_t>((pColors[0][c] * 3 + pColors[3][c] * 5) / 8);
  290. }
  291. return false;
  292. }
  293. color_rgba pvrtc4_image::get_pixel(uint32_t x, uint32_t y, uint32_t m) const
  294. {
  295. assert((x < m_width) && (y < m_height));
  296. int block_x0 = (static_cast<int>(x) - 2) >> 2;
  297. int block_x1 = block_x0 + 1;
  298. int block_y0 = (static_cast<int>(y) - 2) >> 2;
  299. int block_y1 = block_y0 + 1;
  300. block_x0 = posmod(block_x0, m_block_width);
  301. block_x1 = posmod(block_x1, m_block_width);
  302. block_y0 = posmod(block_y0, m_block_height);
  303. block_y1 = posmod(block_y1, m_block_height);
  304. if (get_block_uses_transparent_modulation(x >> 2, y >> 2))
  305. {
  306. if (m == 0)
  307. return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));
  308. else if (m == 3)
  309. return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));
  310. color_rgba l(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0)));
  311. color_rgba h(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1)));
  312. return color_rgba((l[0] + h[0]) / 2, (l[1] + h[1]) / 2, (l[2] + h[2]) / 2, (m == 2) ? 0 : (l[3] + h[3]) / 2);
  313. }
  314. else
  315. {
  316. if (m == 0)
  317. return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0));
  318. else if (m == 3)
  319. return interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1));
  320. color_rgba l(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(0), m_blocks(block_x1, block_y0).get_endpoint_5554(0), m_blocks(block_x0, block_y1).get_endpoint_5554(0), m_blocks(block_x1, block_y1).get_endpoint_5554(0)));
  321. color_rgba h(interpolate(x, y, m_blocks(block_x0, block_y0).get_endpoint_5554(1), m_blocks(block_x1, block_y0).get_endpoint_5554(1), m_blocks(block_x0, block_y1).get_endpoint_5554(1), m_blocks(block_x1, block_y1).get_endpoint_5554(1)));
  322. if (m == 2)
  323. return color_rgba((l[0] * 3 + h[0] * 5) / 8, (l[1] * 3 + h[1] * 5) / 8, (l[2] * 3 + h[2] * 5) / 8, (l[3] * 3 + h[3] * 5) / 8);
  324. else
  325. return color_rgba((l[0] * 5 + h[0] * 3) / 8, (l[1] * 5 + h[1] * 3) / 8, (l[2] * 5 + h[2] * 3) / 8, (l[3] * 5 + h[3] * 3) / 8);
  326. }
  327. }
  328. uint64_t pvrtc4_image::local_endpoint_optimization_opaque(uint32_t bx, uint32_t by, const image& orig_img, bool perceptual)
  329. {
  330. uint64_t initial_error = evaluate_1x1_endpoint_error(bx, by, orig_img, perceptual, false);
  331. if (!initial_error)
  332. return initial_error;
  333. vec3F c_avg_orig(0);
  334. for (int y = 0; y < 7; y++)
  335. {
  336. const uint32_t py = wrap_y(by * 4 + y - 1);
  337. for (uint32_t x = 0; x < 7; x++)
  338. {
  339. const uint32_t px = wrap_x(bx * 4 + x - 1);
  340. const color_rgba& c = orig_img(px, py);
  341. c_avg_orig[0] += c[0];
  342. c_avg_orig[1] += c[1];
  343. c_avg_orig[2] += c[2];
  344. }
  345. }
  346. c_avg_orig *= 1.0f / 49.0f;
  347. vec3F quant_colors[2];
  348. quant_colors[0].set(c_avg_orig);
  349. quant_colors[0] -= vec3F(.0125f);
  350. quant_colors[1].set(c_avg_orig);
  351. quant_colors[1] += vec3F(.0125f);
  352. float total_weight[2];
  353. bool success = true;
  354. for (uint32_t pass = 0; pass < 4; pass++)
  355. {
  356. vec3F new_colors[2] = { vec3F(0), vec3F(0) };
  357. memset(total_weight, 0, sizeof(total_weight));
  358. static const float s_weights[7][7] =
  359. {
  360. { 1.000000f, 1.637089f, 2.080362f, 2.242640f, 2.080362f, 1.637089f, 1.000000f },
  361. { 1.637089f, 2.414213f, 3.006572f, 3.242640f, 3.006572f, 2.414213f, 1.637089f },
  362. { 2.080362f, 3.006572f, 3.828426f, 4.242640f, 3.828426f, 3.006572f, 2.080362f },
  363. { 2.242640f, 3.242640f, 4.242640f, 5.000000f, 4.242640f, 3.242640f, 2.242640f },
  364. { 2.080362f, 3.006572f, 3.828426f, 4.242640f, 3.828426f, 3.006572f, 2.080362f },
  365. { 1.637089f, 2.414213f, 3.006572f, 3.242640f, 3.006572f, 2.414213f, 1.637089f },
  366. { 1.000000f, 1.637089f, 2.080362f, 2.242640f, 2.080362f, 1.637089f, 1.000000f }
  367. };
  368. for (int y = 0; y < 7; y++)
  369. {
  370. const uint32_t py = wrap_y(by * 4 + y - 1);
  371. for (uint32_t x = 0; x < 7; x++)
  372. {
  373. const uint32_t px = wrap_x(bx * 4 + x - 1);
  374. const color_rgba& orig_c = orig_img(px, py);
  375. vec3F color(orig_c[0], orig_c[1], orig_c[2]);
  376. uint32_t c = quant_colors[0].squared_distance(color) > quant_colors[1].squared_distance(color);
  377. const float weight = s_weights[y][x];
  378. new_colors[c] += color * weight;
  379. total_weight[c] += weight;
  380. }
  381. }
  382. if (!total_weight[0] || !total_weight[1])
  383. success = false;
  384. quant_colors[0] = new_colors[0] / (float)total_weight[0];
  385. quant_colors[1] = new_colors[1] / (float)total_weight[1];
  386. }
  387. if (!success)
  388. {
  389. quant_colors[0] = c_avg_orig;
  390. quant_colors[1] = c_avg_orig;
  391. }
  392. vec4F colors[2] = { quant_colors[0], quant_colors[1] };
  393. colors[0] += vec3F(.5f);
  394. colors[1] += vec3F(.5f);
  395. color_rgba color_0((int)colors[0][0], (int)colors[0][1], (int)colors[0][2], 0);
  396. color_rgba color_1((int)colors[1][0], (int)colors[1][1], (int)colors[1][2], 0);
  397. pvrtc4_block cur_blocks[3][3];
  398. for (int y = -1; y <= 1; y++)
  399. {
  400. for (int x = -1; x <= 1; x++)
  401. {
  402. const uint32_t block_x = wrap_block_x(bx + x);
  403. const uint32_t block_y = wrap_block_y(by + y);
  404. cur_blocks[x + 1][y + 1] = m_blocks(block_x, block_y);
  405. }
  406. }
  407. color_rgba l1(0), h1(0);
  408. l1[0] = g_pvrtc_5_nearest[color_0[0]];
  409. h1[0] = g_pvrtc_5_nearest[color_1[0]];
  410. l1[1] = g_pvrtc_5_nearest[color_0[1]];
  411. h1[1] = g_pvrtc_5_nearest[color_1[1]];
  412. l1[2] = g_pvrtc_4_nearest[color_0[2]];
  413. h1[2] = g_pvrtc_5_nearest[color_0[2]];
  414. l1[3] = 0;
  415. h1[3] = 0;
  416. m_blocks(bx, by).set_endpoint_raw(0, l1, true);
  417. m_blocks(bx, by).set_endpoint_raw(1, h1, true);
  418. uint64_t e03_err_0 = remap_pixels_influenced_by_endpoint(bx, by, orig_img, perceptual, false);
  419. pvrtc4_block blocks0[3][3];
  420. for (int y = -1; y <= 1; y++)
  421. {
  422. for (int x = -1; x <= 1; x++)
  423. {
  424. const uint32_t block_x = wrap_block_x(bx + x);
  425. const uint32_t block_y = wrap_block_y(by + y);
  426. blocks0[x + 1][y + 1] = m_blocks(block_x, block_y);
  427. }
  428. }
  429. l1[0] = g_pvrtc_5_nearest[color_1[0]];
  430. h1[0] = g_pvrtc_5_nearest[color_0[0]];
  431. l1[1] = g_pvrtc_5_nearest[color_1[1]];
  432. h1[1] = g_pvrtc_5_nearest[color_0[1]];
  433. l1[2] = g_pvrtc_4_nearest[color_1[2]];
  434. h1[2] = g_pvrtc_5_nearest[color_0[2]];
  435. l1[3] = 0;
  436. h1[3] = 0;
  437. m_blocks(bx, by).set_endpoint_raw(0, l1, true);
  438. m_blocks(bx, by).set_endpoint_raw(1, h1, true);
  439. uint64_t e03_err_1 = remap_pixels_influenced_by_endpoint(bx, by, orig_img, perceptual, false);
  440. if (initial_error < basisu::minimum(e03_err_0, e03_err_1))
  441. {
  442. for (int y = -1; y <= 1; y++)
  443. {
  444. for (int x = -1; x <= 1; x++)
  445. {
  446. const uint32_t block_x = wrap_block_x(bx + x);
  447. const uint32_t block_y = wrap_block_y(by + y);
  448. m_blocks(block_x, block_y) = cur_blocks[x + 1][y + 1];
  449. }
  450. }
  451. return initial_error;
  452. }
  453. else if (e03_err_0 < e03_err_1)
  454. {
  455. for (int y = -1; y <= 1; y++)
  456. {
  457. for (int x = -1; x <= 1; x++)
  458. {
  459. const uint32_t block_x = wrap_block_x(bx + x);
  460. const uint32_t block_y = wrap_block_y(by + y);
  461. m_blocks(block_x, block_y) = blocks0[x + 1][y + 1];
  462. }
  463. }
  464. assert(e03_err_0 == evaluate_1x1_endpoint_error(bx, by, orig_img, perceptual, false));
  465. return e03_err_0;
  466. }
  467. assert(e03_err_1 == evaluate_1x1_endpoint_error(bx, by, orig_img, perceptual, false));
  468. return e03_err_1;
  469. }
  470. } // basisu