crn_dxt_endpoint_refiner.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. // File: crn_dxt_endpoint_refiner.cpp
  2. // See Copyright Notice and license at the end of inc/crnlib.h
  3. #include "crn_core.h"
  4. #include "crn_dxt_endpoint_refiner.h"
  5. #include "crn_dxt1.h"
  6. namespace crnlib
  7. {
  8. dxt_endpoint_refiner::dxt_endpoint_refiner() :
  9. m_pParams(NULL),
  10. m_pResults(NULL)
  11. {
  12. }
  13. bool dxt_endpoint_refiner::refine(const params& p, results& r)
  14. {
  15. if (!p.m_num_pixels)
  16. return false;
  17. m_pParams = &p;
  18. m_pResults = &r;
  19. r.m_error = cUINT64_MAX;
  20. r.m_low_color = 0;
  21. r.m_high_color = 0;
  22. double alpha2_sum = 0.0f;
  23. double beta2_sum = 0.0f;
  24. double alphabeta_sum = 0.0f;
  25. vec<3, double> alphax_sum( 0.0f );
  26. vec<3, double> betax_sum( 0.0f );
  27. vec<3, double> first_color( 0.0f );
  28. // This linear solver is from Squish.
  29. for( uint i = 0; i < p.m_num_pixels; ++i )
  30. {
  31. uint8 c = p.m_pSelectors[i];
  32. double k;
  33. if (p.m_dxt1_selectors)
  34. k = g_dxt1_to_linear[c] * 1.0f/3.0f;
  35. else
  36. k = g_dxt5_to_linear[c] * 1.0f/7.0f;
  37. double alpha = 1.0f - k;
  38. double beta = k;
  39. vec<3, double> x;
  40. if (p.m_dxt1_selectors)
  41. x.set( p.m_pPixels[i][0] * 1.0f/255.0f, p.m_pPixels[i][1] * 1.0f/255.0f, p.m_pPixels[i][2] * 1.0f/255.0f );
  42. else
  43. x.set( p.m_pPixels[i][p.m_alpha_comp_index]/255.0f );
  44. if (!i)
  45. first_color = x;
  46. alpha2_sum += alpha*alpha;
  47. beta2_sum += beta*beta;
  48. alphabeta_sum += alpha*beta;
  49. alphax_sum += alpha*x;
  50. betax_sum += beta*x;
  51. }
  52. // zero where non-determinate
  53. vec<3, double> a, b;
  54. if( beta2_sum == 0.0f )
  55. {
  56. a = alphax_sum / alpha2_sum;
  57. b.clear();
  58. }
  59. else if( alpha2_sum == 0.0f )
  60. {
  61. a.clear();
  62. b = betax_sum / beta2_sum;
  63. }
  64. else
  65. {
  66. double factor = alpha2_sum*beta2_sum - alphabeta_sum*alphabeta_sum;
  67. if (factor != 0.0f)
  68. {
  69. a = ( alphax_sum*beta2_sum - betax_sum*alphabeta_sum ) / factor;
  70. b = ( betax_sum*alpha2_sum - alphax_sum*alphabeta_sum ) / factor;
  71. }
  72. else
  73. {
  74. a = first_color;
  75. b = first_color;
  76. }
  77. }
  78. vec3F l(0.0f), h(0.0f);
  79. l = a;
  80. h = b;
  81. l.clamp(0.0f, 1.0f);
  82. h.clamp(0.0f, 1.0f);
  83. if (p.m_dxt1_selectors)
  84. optimize_dxt1(l, h);
  85. else
  86. optimize_dxt5(l, h);
  87. //if (r.m_low_color < r.m_high_color)
  88. // utils::swap(r.m_low_color, r.m_high_color);
  89. return r.m_error < p.m_error_to_beat;
  90. }
  91. void dxt_endpoint_refiner::optimize_dxt5(vec3F low_color, vec3F high_color)
  92. {
  93. float nl = low_color[0];
  94. float nh = high_color[0];
  95. #if CRNLIB_DXT_ALT_ROUNDING
  96. nl = math::clamp(nl, 0.0f, .999f);
  97. nh = math::clamp(nh, 0.0f, .999f);
  98. uint il = (int)floor(nl * 256.0f);
  99. uint ih = (int)floor(nh * 256.0f);
  100. #else
  101. uint il = (int)floor(.5f + math::clamp(nl, 0.0f, 1.0f) * 255.0f);
  102. uint ih = (int)floor(.5f + math::clamp(nh, 0.0f, 1.0f) * 255.0f);
  103. #endif
  104. crnlib::vector<uint> trial_solutions;
  105. trial_solutions.reserve(256);
  106. trial_solutions.push_back(il | (ih << 8));
  107. sparse_bit_array flags;
  108. flags.resize(256 * 256);
  109. flags.set_bit((il * 256) + ih);
  110. const int cProbeAmount = 11;
  111. for (int l_delta = -cProbeAmount; l_delta <= cProbeAmount; l_delta++)
  112. {
  113. const int l = il + l_delta;
  114. if (l < 0)
  115. continue;
  116. else if (l > 255)
  117. break;
  118. const uint bit_index = l * 256;
  119. for (int h_delta = -cProbeAmount; h_delta <= cProbeAmount; h_delta++)
  120. {
  121. const int h = ih + h_delta;
  122. if (h < 0)
  123. continue;
  124. else if (h > 255)
  125. break;
  126. if ((flags.get_bit(bit_index + h)) || (flags.get_bit(h * 256 + l)))
  127. continue;
  128. flags.set_bit(bit_index + h);
  129. trial_solutions.push_back(l | (h << 8));
  130. }
  131. }
  132. for (uint trial = 0; trial < trial_solutions.size(); trial++)
  133. {
  134. uint l = trial_solutions[trial] & 0xFF;
  135. uint h = trial_solutions[trial] >> 8;
  136. if (l == h)
  137. {
  138. if (h)
  139. h--;
  140. else
  141. l++;
  142. }
  143. else if (l < h)
  144. {
  145. utils::swap(l, h);
  146. }
  147. CRNLIB_ASSERT(l > h);
  148. uint values[cDXT5SelectorValues];
  149. dxt5_block::get_block_values8(values, l, h);
  150. uint total_error = 0;
  151. for (uint j = 0; j < m_pParams->m_num_pixels; j++)
  152. {
  153. int p = m_pParams->m_pPixels[j][m_pParams->m_alpha_comp_index];
  154. int c = values[m_pParams->m_pSelectors[j]];
  155. int error = p - c;
  156. error *= error;
  157. total_error += error;
  158. if (total_error > m_pResults->m_error)
  159. break;
  160. }
  161. if (total_error < m_pResults->m_error)
  162. {
  163. m_pResults->m_error = total_error;
  164. m_pResults->m_low_color = static_cast<uint16>(l);
  165. m_pResults->m_high_color = static_cast<uint16>(h);
  166. if (m_pResults->m_error == 0)
  167. return;
  168. }
  169. }
  170. }
  171. void dxt_endpoint_refiner::optimize_dxt1(vec3F low_color, vec3F high_color)
  172. {
  173. uint selector_hist[4];
  174. utils::zero_object(selector_hist);
  175. for (uint i = 0; i < m_pParams->m_num_pixels; i++)
  176. selector_hist[m_pParams->m_pSelectors[i]]++;
  177. dxt1_solution_coordinates c(low_color, high_color);
  178. for (uint pass = 0; pass < 8; pass++)
  179. {
  180. const uint64 initial_error = m_pResults->m_error;
  181. dxt1_solution_coordinates_vec coords_to_try;
  182. coords_to_try.resize(0);
  183. color_quad_u8 lc(dxt1_block::unpack_color(c.m_low_color, false));
  184. color_quad_u8 hc(dxt1_block::unpack_color(c.m_high_color, false));
  185. for (int i = 0; i < 27; i++)
  186. {
  187. if (13 == i) continue;
  188. const int ir = (i % 3) - 1;
  189. const int ig = ((i / 3) % 3) - 1;
  190. const int ib = ((i / 9) % 3) - 1;
  191. int r = lc.r + ir;
  192. int g = lc.g + ig;
  193. int b = lc.b + ib;
  194. if ((r < 0) || (r > 31)|| (g < 0) || (g > 63) || (b < 0) || (b > 31)) continue;
  195. coords_to_try.push_back(
  196. dxt1_solution_coordinates(dxt1_block::pack_color(r, g, b, false), c.m_high_color)
  197. );
  198. }
  199. for (int i = 0; i < 27; i++)
  200. {
  201. if (13 == i) continue;
  202. const int ir = (i % 3) - 1;
  203. const int ig = ((i / 3) % 3) - 1;
  204. const int ib = ((i / 9) % 3) - 1;
  205. int r = hc.r + ir;
  206. int g = hc.g + ig;
  207. int b = hc.b + ib;
  208. if ((r < 0) || (r > 31)|| (g < 0) || (g > 63) || (b < 0) || (b > 31)) continue;
  209. coords_to_try.push_back(dxt1_solution_coordinates(c.m_low_color, dxt1_block::pack_color(r, g, b, false)));
  210. }
  211. std::sort(coords_to_try.begin(), coords_to_try.end());
  212. dxt1_solution_coordinates_vec::const_iterator p_last = std::unique(coords_to_try.begin(), coords_to_try.end());
  213. uint num_coords_to_try = (uint)(p_last - coords_to_try.begin());
  214. for (uint i = 0; i < num_coords_to_try; i++)
  215. {
  216. color_quad_u8 block_colors[4];
  217. uint16 l = coords_to_try[i].m_low_color;
  218. uint16 h = coords_to_try[i].m_high_color;
  219. if (l < h)
  220. utils::swap(l, h);
  221. else if (l == h)
  222. {
  223. color_quad_u8 lc(dxt1_block::unpack_color(l, false));
  224. color_quad_u8 hc(dxt1_block::unpack_color(h, false));
  225. bool retry = false;
  226. if ((selector_hist[0] + selector_hist[2]) > (selector_hist[1] + selector_hist[3]))
  227. {
  228. // l affects the output more than h, so muck with h
  229. if (hc[2] != 0)
  230. hc[2]--;
  231. else if (hc[0] != 0)
  232. hc[0]--;
  233. else if (hc[1] != 0)
  234. hc[1]--;
  235. else
  236. retry = true;
  237. }
  238. else
  239. {
  240. // h affects the output more than l, so muck with l
  241. if (lc[2] != 31)
  242. lc[2]++;
  243. else if (lc[0] != 31)
  244. lc[0]++;
  245. else if (lc[1] != 63)
  246. lc[1]++;
  247. else
  248. retry = true;
  249. }
  250. if (retry)
  251. {
  252. if (l == 0)
  253. l++;
  254. else
  255. h--;
  256. }
  257. else
  258. {
  259. l = dxt1_block::pack_color(lc, false);
  260. h = dxt1_block::pack_color(hc, false);
  261. }
  262. CRNLIB_ASSERT(l > h);
  263. }
  264. dxt1_block::get_block_colors4(block_colors, l, h);
  265. uint total_error = 0;
  266. for (uint j = 0; j < m_pParams->m_num_pixels; j++)
  267. {
  268. const color_quad_u8& c = block_colors[m_pParams->m_pSelectors[j]];
  269. total_error += color::color_distance(m_pParams->m_perceptual, c, m_pParams->m_pPixels[j], false);
  270. if (total_error > m_pResults->m_error)
  271. break;
  272. }
  273. if (total_error < m_pResults->m_error)
  274. {
  275. m_pResults->m_error = total_error;
  276. m_pResults->m_low_color = l;
  277. m_pResults->m_high_color = h;
  278. CRNLIB_ASSERT(l > h);
  279. if (m_pResults->m_error == 0)
  280. return;
  281. }
  282. }
  283. if (m_pResults->m_error == initial_error)
  284. break;
  285. c.m_low_color = m_pResults->m_low_color;
  286. c.m_high_color = m_pResults->m_high_color;
  287. }
  288. }
  289. } // namespace crnlib