basisu_resampler.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. // basisu_resampler.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. #include "basisu_resampler.h"
  16. #include "basisu_resampler_filters.h"
  17. #ifndef max
  18. #define max(a, b) (((a) > (b)) ? (a) : (b))
  19. #endif
  20. #ifndef min
  21. #define min(a, b) (((a) < (b)) ? (a) : (b))
  22. #endif
  23. #define RESAMPLER_DEBUG 0
  24. namespace basisu
  25. {
  26. static inline int resampler_range_check(int v, int h)
  27. {
  28. BASISU_NOTE_UNUSED(h);
  29. assert((v >= 0) && (v < h));
  30. return v;
  31. }
  32. // Float to int cast with truncation.
  33. static inline int cast_to_int(Resample_Real i)
  34. {
  35. return (int)i;
  36. }
  37. // Ensure that the contributing source sample is within bounds. If not, reflect, clamp, or wrap.
  38. int Resampler::reflect(const int j, const int src_x, const Boundary_Op boundary_op)
  39. {
  40. int n;
  41. if (j < 0)
  42. {
  43. if (boundary_op == BOUNDARY_REFLECT)
  44. {
  45. n = -j;
  46. if (n >= src_x)
  47. n = src_x - 1;
  48. }
  49. else if (boundary_op == BOUNDARY_WRAP)
  50. n = posmod(j, src_x);
  51. else
  52. n = 0;
  53. }
  54. else if (j >= src_x)
  55. {
  56. if (boundary_op == BOUNDARY_REFLECT)
  57. {
  58. n = (src_x - j) + (src_x - 1);
  59. if (n < 0)
  60. n = 0;
  61. }
  62. else if (boundary_op == BOUNDARY_WRAP)
  63. n = posmod(j, src_x);
  64. else
  65. n = src_x - 1;
  66. }
  67. else
  68. n = j;
  69. return n;
  70. }
  71. // The make_clist() method generates, for all destination samples,
  72. // the list of all source samples with non-zero weighted contributions.
  73. Resampler::Contrib_List * Resampler::make_clist(
  74. int src_x, int dst_x, Boundary_Op boundary_op,
  75. Resample_Real(*Pfilter)(Resample_Real),
  76. Resample_Real filter_support,
  77. Resample_Real filter_scale,
  78. Resample_Real src_ofs)
  79. {
  80. struct Contrib_Bounds
  81. {
  82. // The center of the range in DISCRETE coordinates (pixel center = 0.0f).
  83. Resample_Real center;
  84. int left, right;
  85. };
  86. int i, j, k, n, left, right;
  87. Resample_Real total_weight;
  88. Resample_Real xscale, center, half_width, weight;
  89. Contrib_List* Pcontrib;
  90. Contrib* Pcpool;
  91. Contrib* Pcpool_next;
  92. Contrib_Bounds* Pcontrib_bounds;
  93. if ((Pcontrib = (Contrib_List*)calloc(dst_x, sizeof(Contrib_List))) == NULL)
  94. return NULL;
  95. Pcontrib_bounds = (Contrib_Bounds*)calloc(dst_x, sizeof(Contrib_Bounds));
  96. if (!Pcontrib_bounds)
  97. {
  98. free(Pcontrib);
  99. return (NULL);
  100. }
  101. const Resample_Real oo_filter_scale = 1.0f / filter_scale;
  102. const Resample_Real NUDGE = 0.5f;
  103. xscale = dst_x / (Resample_Real)src_x;
  104. if (xscale < 1.0f)
  105. {
  106. int total;
  107. (void)total;
  108. // Handle case when there are fewer destination samples than source samples (downsampling/minification).
  109. // stretched half width of filter
  110. half_width = (filter_support / xscale) * filter_scale;
  111. // Find the range of source sample(s) that will contribute to each destination sample.
  112. for (i = 0, n = 0; i < dst_x; i++)
  113. {
  114. // Convert from discrete to continuous coordinates, scale, then convert back to discrete.
  115. center = ((Resample_Real)i + NUDGE) / xscale;
  116. center -= NUDGE;
  117. center += src_ofs;
  118. left = cast_to_int((Resample_Real)floor(center - half_width));
  119. right = cast_to_int((Resample_Real)ceil(center + half_width));
  120. Pcontrib_bounds[i].center = center;
  121. Pcontrib_bounds[i].left = left;
  122. Pcontrib_bounds[i].right = right;
  123. n += (right - left + 1);
  124. }
  125. // Allocate memory for contributors.
  126. if ((n == 0) || ((Pcpool = (Contrib*)calloc(n, sizeof(Contrib))) == NULL))
  127. {
  128. free(Pcontrib);
  129. free(Pcontrib_bounds);
  130. return NULL;
  131. }
  132. total = n;
  133. Pcpool_next = Pcpool;
  134. // Create the list of source samples which contribute to each destination sample.
  135. for (i = 0; i < dst_x; i++)
  136. {
  137. int max_k = -1;
  138. Resample_Real max_w = -1e+20f;
  139. center = Pcontrib_bounds[i].center;
  140. left = Pcontrib_bounds[i].left;
  141. right = Pcontrib_bounds[i].right;
  142. Pcontrib[i].n = 0;
  143. Pcontrib[i].p = Pcpool_next;
  144. Pcpool_next += (right - left + 1);
  145. assert((Pcpool_next - Pcpool) <= total);
  146. total_weight = 0;
  147. for (j = left; j <= right; j++)
  148. total_weight += (*Pfilter)((center - (Resample_Real)j) * xscale * oo_filter_scale);
  149. const Resample_Real norm = static_cast<Resample_Real>(1.0f / total_weight);
  150. total_weight = 0;
  151. #if RESAMPLER_DEBUG
  152. printf("%i: ", i);
  153. #endif
  154. for (j = left; j <= right; j++)
  155. {
  156. weight = (*Pfilter)((center - (Resample_Real)j) * xscale * oo_filter_scale) * norm;
  157. if (weight == 0.0f)
  158. continue;
  159. n = reflect(j, src_x, boundary_op);
  160. #if RESAMPLER_DEBUG
  161. printf("%i(%f), ", n, weight);
  162. #endif
  163. // Increment the number of source samples which contribute to the current destination sample.
  164. k = Pcontrib[i].n++;
  165. Pcontrib[i].p[k].pixel = (unsigned short)n; /* store src sample number */
  166. Pcontrib[i].p[k].weight = weight; /* store src sample weight */
  167. total_weight += weight; /* total weight of all contributors */
  168. if (weight > max_w)
  169. {
  170. max_w = weight;
  171. max_k = k;
  172. }
  173. }
  174. #if RESAMPLER_DEBUG
  175. printf("\n\n");
  176. #endif
  177. //assert(Pcontrib[i].n);
  178. //assert(max_k != -1);
  179. if ((max_k == -1) || (Pcontrib[i].n == 0))
  180. {
  181. free(Pcpool);
  182. free(Pcontrib);
  183. free(Pcontrib_bounds);
  184. return NULL;
  185. }
  186. if (total_weight != 1.0f)
  187. Pcontrib[i].p[max_k].weight += 1.0f - total_weight;
  188. }
  189. }
  190. else
  191. {
  192. // Handle case when there are more destination samples than source samples (upsampling).
  193. half_width = filter_support * filter_scale;
  194. // Find the source sample(s) that contribute to each destination sample.
  195. for (i = 0, n = 0; i < dst_x; i++)
  196. {
  197. // Convert from discrete to continuous coordinates, scale, then convert back to discrete.
  198. center = ((Resample_Real)i + NUDGE) / xscale;
  199. center -= NUDGE;
  200. center += src_ofs;
  201. left = cast_to_int((Resample_Real)floor(center - half_width));
  202. right = cast_to_int((Resample_Real)ceil(center + half_width));
  203. Pcontrib_bounds[i].center = center;
  204. Pcontrib_bounds[i].left = left;
  205. Pcontrib_bounds[i].right = right;
  206. n += (right - left + 1);
  207. }
  208. /* Allocate memory for contributors. */
  209. int total = n;
  210. if ((total == 0) || ((Pcpool = (Contrib*)calloc(total, sizeof(Contrib))) == NULL))
  211. {
  212. free(Pcontrib);
  213. free(Pcontrib_bounds);
  214. return NULL;
  215. }
  216. Pcpool_next = Pcpool;
  217. // Create the list of source samples which contribute to each destination sample.
  218. for (i = 0; i < dst_x; i++)
  219. {
  220. int max_k = -1;
  221. Resample_Real max_w = -1e+20f;
  222. center = Pcontrib_bounds[i].center;
  223. left = Pcontrib_bounds[i].left;
  224. right = Pcontrib_bounds[i].right;
  225. Pcontrib[i].n = 0;
  226. Pcontrib[i].p = Pcpool_next;
  227. Pcpool_next += (right - left + 1);
  228. assert((Pcpool_next - Pcpool) <= total);
  229. total_weight = 0;
  230. for (j = left; j <= right; j++)
  231. total_weight += (*Pfilter)((center - (Resample_Real)j) * oo_filter_scale);
  232. const Resample_Real norm = static_cast<Resample_Real>(1.0f / total_weight);
  233. total_weight = 0;
  234. #if RESAMPLER_DEBUG
  235. printf("%i: ", i);
  236. #endif
  237. for (j = left; j <= right; j++)
  238. {
  239. weight = (*Pfilter)((center - (Resample_Real)j) * oo_filter_scale) * norm;
  240. if (weight == 0.0f)
  241. continue;
  242. n = reflect(j, src_x, boundary_op);
  243. #if RESAMPLER_DEBUG
  244. printf("%i(%f), ", n, weight);
  245. #endif
  246. // Increment the number of source samples which contribute to the current destination sample.
  247. k = Pcontrib[i].n++;
  248. Pcontrib[i].p[k].pixel = (unsigned short)n; /* store src sample number */
  249. Pcontrib[i].p[k].weight = weight; /* store src sample weight */
  250. total_weight += weight; /* total weight of all contributors */
  251. if (weight > max_w)
  252. {
  253. max_w = weight;
  254. max_k = k;
  255. }
  256. }
  257. #if RESAMPLER_DEBUG
  258. printf("\n\n");
  259. #endif
  260. //assert(Pcontrib[i].n);
  261. //assert(max_k != -1);
  262. if ((max_k == -1) || (Pcontrib[i].n == 0))
  263. {
  264. free(Pcpool);
  265. free(Pcontrib);
  266. free(Pcontrib_bounds);
  267. return NULL;
  268. }
  269. if (total_weight != 1.0f)
  270. Pcontrib[i].p[max_k].weight += 1.0f - total_weight;
  271. }
  272. }
  273. #if RESAMPLER_DEBUG
  274. printf("*******\n");
  275. #endif
  276. free(Pcontrib_bounds);
  277. return Pcontrib;
  278. }
  279. void Resampler::resample_x(Sample * Pdst, const Sample * Psrc)
  280. {
  281. assert(Pdst);
  282. assert(Psrc);
  283. int i, j;
  284. Sample total;
  285. Contrib_List* Pclist = m_Pclist_x;
  286. Contrib* p;
  287. for (i = m_resample_dst_x; i > 0; i--, Pclist++)
  288. {
  289. #if BASISU_RESAMPLER_DEBUG_OPS
  290. total_ops += Pclist->n;
  291. #endif
  292. for (j = Pclist->n, p = Pclist->p, total = 0; j > 0; j--, p++)
  293. total += Psrc[p->pixel] * p->weight;
  294. *Pdst++ = total;
  295. }
  296. }
  297. void Resampler::scale_y_mov(Sample * Ptmp, const Sample * Psrc, Resample_Real weight, int dst_x)
  298. {
  299. int i;
  300. #if BASISU_RESAMPLER_DEBUG_OPS
  301. total_ops += dst_x;
  302. #endif
  303. // Not += because temp buf wasn't cleared.
  304. for (i = dst_x; i > 0; i--)
  305. * Ptmp++ = *Psrc++ * weight;
  306. }
  307. void Resampler::scale_y_add(Sample * Ptmp, const Sample * Psrc, Resample_Real weight, int dst_x)
  308. {
  309. #if BASISU_RESAMPLER_DEBUG_OPS
  310. total_ops += dst_x;
  311. #endif
  312. for (int i = dst_x; i > 0; i--)
  313. (*Ptmp++) += *Psrc++ * weight;
  314. }
  315. void Resampler::clamp(Sample * Pdst, int n)
  316. {
  317. while (n > 0)
  318. {
  319. Sample x = *Pdst;
  320. *Pdst++ = clamp_sample(x);
  321. n--;
  322. }
  323. }
  324. void Resampler::resample_y(Sample * Pdst)
  325. {
  326. int i, j;
  327. Sample* Psrc;
  328. Contrib_List* Pclist = &m_Pclist_y[m_cur_dst_y];
  329. Sample* Ptmp = m_delay_x_resample ? m_Ptmp_buf : Pdst;
  330. assert(Ptmp);
  331. /* Process each contributor. */
  332. for (i = 0; i < Pclist->n; i++)
  333. {
  334. // locate the contributor's location in the scan buffer -- the contributor must always be found!
  335. for (j = 0; j < MAX_SCAN_BUF_SIZE; j++)
  336. if (m_Pscan_buf->scan_buf_y[j] == Pclist->p[i].pixel)
  337. break;
  338. assert(j < MAX_SCAN_BUF_SIZE);
  339. Psrc = m_Pscan_buf->scan_buf_l[j];
  340. if (!i)
  341. scale_y_mov(Ptmp, Psrc, Pclist->p[i].weight, m_intermediate_x);
  342. else
  343. scale_y_add(Ptmp, Psrc, Pclist->p[i].weight, m_intermediate_x);
  344. /* If this source line doesn't contribute to any
  345. * more destination lines then mark the scanline buffer slot
  346. * which holds this source line as free.
  347. * (The max. number of slots used depends on the Y
  348. * axis sampling factor and the scaled filter width.)
  349. */
  350. if (--m_Psrc_y_count[resampler_range_check(Pclist->p[i].pixel, m_resample_src_y)] == 0)
  351. {
  352. m_Psrc_y_flag[resampler_range_check(Pclist->p[i].pixel, m_resample_src_y)] = false;
  353. m_Pscan_buf->scan_buf_y[j] = -1;
  354. }
  355. }
  356. /* Now generate the destination line */
  357. if (m_delay_x_resample) // Was X resampling delayed until after Y resampling?
  358. {
  359. assert(Pdst != Ptmp);
  360. resample_x(Pdst, Ptmp);
  361. }
  362. else
  363. {
  364. assert(Pdst == Ptmp);
  365. }
  366. if (m_lo < m_hi)
  367. clamp(Pdst, m_resample_dst_x);
  368. }
  369. bool Resampler::put_line(const Sample * Psrc)
  370. {
  371. int i;
  372. if (m_cur_src_y >= m_resample_src_y)
  373. return false;
  374. /* Does this source line contribute
  375. * to any destination line? if not,
  376. * exit now.
  377. */
  378. if (!m_Psrc_y_count[resampler_range_check(m_cur_src_y, m_resample_src_y)])
  379. {
  380. m_cur_src_y++;
  381. return true;
  382. }
  383. /* Find an empty slot in the scanline buffer. (FIXME: Perf. is terrible here with extreme scaling ratios.) */
  384. for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
  385. if (m_Pscan_buf->scan_buf_y[i] == -1)
  386. break;
  387. /* If the buffer is full, exit with an error. */
  388. if (i == MAX_SCAN_BUF_SIZE)
  389. {
  390. m_status = STATUS_SCAN_BUFFER_FULL;
  391. return false;
  392. }
  393. m_Psrc_y_flag[resampler_range_check(m_cur_src_y, m_resample_src_y)] = true;
  394. m_Pscan_buf->scan_buf_y[i] = m_cur_src_y;
  395. /* Does this slot have any memory allocated to it? */
  396. if (!m_Pscan_buf->scan_buf_l[i])
  397. {
  398. if ((m_Pscan_buf->scan_buf_l[i] = (Sample*)malloc(m_intermediate_x * sizeof(Sample))) == NULL)
  399. {
  400. m_status = STATUS_OUT_OF_MEMORY;
  401. return false;
  402. }
  403. }
  404. // Resampling on the X axis first?
  405. if (m_delay_x_resample)
  406. {
  407. assert(m_intermediate_x == m_resample_src_x);
  408. // Y-X resampling order
  409. memcpy(m_Pscan_buf->scan_buf_l[i], Psrc, m_intermediate_x * sizeof(Sample));
  410. }
  411. else
  412. {
  413. assert(m_intermediate_x == m_resample_dst_x);
  414. // X-Y resampling order
  415. resample_x(m_Pscan_buf->scan_buf_l[i], Psrc);
  416. }
  417. m_cur_src_y++;
  418. return true;
  419. }
  420. const Resampler::Sample* Resampler::get_line()
  421. {
  422. int i;
  423. /* If all the destination lines have been
  424. * generated, then always return NULL.
  425. */
  426. if (m_cur_dst_y == m_resample_dst_y)
  427. return NULL;
  428. /* Check to see if all the required
  429. * contributors are present, if not,
  430. * return NULL.
  431. */
  432. for (i = 0; i < m_Pclist_y[m_cur_dst_y].n; i++)
  433. if (!m_Psrc_y_flag[resampler_range_check(m_Pclist_y[m_cur_dst_y].p[i].pixel, m_resample_src_y)])
  434. return NULL;
  435. resample_y(m_Pdst_buf);
  436. m_cur_dst_y++;
  437. return m_Pdst_buf;
  438. }
  439. Resampler::~Resampler()
  440. {
  441. int i;
  442. #if BASISU_RESAMPLER_DEBUG_OPS
  443. printf("actual ops: %i\n", total_ops);
  444. #endif
  445. free(m_Pdst_buf);
  446. m_Pdst_buf = NULL;
  447. if (m_Ptmp_buf)
  448. {
  449. free(m_Ptmp_buf);
  450. m_Ptmp_buf = NULL;
  451. }
  452. /* Don't deallocate a contibutor list
  453. * if the user passed us one of their own.
  454. */
  455. if ((m_Pclist_x) && (!m_clist_x_forced))
  456. {
  457. free(m_Pclist_x->p);
  458. free(m_Pclist_x);
  459. m_Pclist_x = NULL;
  460. }
  461. if ((m_Pclist_y) && (!m_clist_y_forced))
  462. {
  463. free(m_Pclist_y->p);
  464. free(m_Pclist_y);
  465. m_Pclist_y = NULL;
  466. }
  467. free(m_Psrc_y_count);
  468. m_Psrc_y_count = NULL;
  469. free(m_Psrc_y_flag);
  470. m_Psrc_y_flag = NULL;
  471. if (m_Pscan_buf)
  472. {
  473. for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
  474. free(m_Pscan_buf->scan_buf_l[i]);
  475. free(m_Pscan_buf);
  476. m_Pscan_buf = NULL;
  477. }
  478. }
  479. void Resampler::restart()
  480. {
  481. if (STATUS_OKAY != m_status)
  482. return;
  483. m_cur_src_y = m_cur_dst_y = 0;
  484. int i, j;
  485. for (i = 0; i < m_resample_src_y; i++)
  486. {
  487. m_Psrc_y_count[i] = 0;
  488. m_Psrc_y_flag[i] = false;
  489. }
  490. for (i = 0; i < m_resample_dst_y; i++)
  491. {
  492. for (j = 0; j < m_Pclist_y[i].n; j++)
  493. m_Psrc_y_count[resampler_range_check(m_Pclist_y[i].p[j].pixel, m_resample_src_y)]++;
  494. }
  495. for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
  496. {
  497. m_Pscan_buf->scan_buf_y[i] = -1;
  498. free(m_Pscan_buf->scan_buf_l[i]);
  499. m_Pscan_buf->scan_buf_l[i] = NULL;
  500. }
  501. }
  502. Resampler::Resampler(int src_x, int src_y,
  503. int dst_x, int dst_y,
  504. Boundary_Op boundary_op,
  505. Resample_Real sample_low, Resample_Real sample_high,
  506. const char* Pfilter_name,
  507. Contrib_List * Pclist_x,
  508. Contrib_List * Pclist_y,
  509. Resample_Real filter_x_scale,
  510. Resample_Real filter_y_scale,
  511. Resample_Real src_x_ofs,
  512. Resample_Real src_y_ofs)
  513. {
  514. int i, j;
  515. Resample_Real support, (*func)(Resample_Real);
  516. assert(src_x > 0);
  517. assert(src_y > 0);
  518. assert(dst_x > 0);
  519. assert(dst_y > 0);
  520. #if BASISU_RESAMPLER_DEBUG_OPS
  521. total_ops = 0;
  522. #endif
  523. m_lo = sample_low;
  524. m_hi = sample_high;
  525. m_delay_x_resample = false;
  526. m_intermediate_x = 0;
  527. m_Pdst_buf = NULL;
  528. m_Ptmp_buf = NULL;
  529. m_clist_x_forced = false;
  530. m_Pclist_x = NULL;
  531. m_clist_y_forced = false;
  532. m_Pclist_y = NULL;
  533. m_Psrc_y_count = NULL;
  534. m_Psrc_y_flag = NULL;
  535. m_Pscan_buf = NULL;
  536. m_status = STATUS_OKAY;
  537. m_resample_src_x = src_x;
  538. m_resample_src_y = src_y;
  539. m_resample_dst_x = dst_x;
  540. m_resample_dst_y = dst_y;
  541. m_boundary_op = boundary_op;
  542. if ((m_Pdst_buf = (Sample*)malloc(m_resample_dst_x * sizeof(Sample))) == NULL)
  543. {
  544. m_status = STATUS_OUT_OF_MEMORY;
  545. return;
  546. }
  547. // Find the specified filter.
  548. if (Pfilter_name == NULL)
  549. Pfilter_name = BASISU_RESAMPLER_DEFAULT_FILTER;
  550. for (i = 0; i < g_num_resample_filters; i++)
  551. if (strcmp(Pfilter_name, g_resample_filters[i].name) == 0)
  552. break;
  553. if (i == g_num_resample_filters)
  554. {
  555. m_status = STATUS_BAD_FILTER_NAME;
  556. return;
  557. }
  558. func = g_resample_filters[i].func;
  559. support = g_resample_filters[i].support;
  560. /* Create contributor lists, unless the user supplied custom lists. */
  561. if (!Pclist_x)
  562. {
  563. m_Pclist_x = make_clist(m_resample_src_x, m_resample_dst_x, m_boundary_op, func, support, filter_x_scale, src_x_ofs);
  564. if (!m_Pclist_x)
  565. {
  566. m_status = STATUS_OUT_OF_MEMORY;
  567. return;
  568. }
  569. }
  570. else
  571. {
  572. m_Pclist_x = Pclist_x;
  573. m_clist_x_forced = true;
  574. }
  575. if (!Pclist_y)
  576. {
  577. m_Pclist_y = make_clist(m_resample_src_y, m_resample_dst_y, m_boundary_op, func, support, filter_y_scale, src_y_ofs);
  578. if (!m_Pclist_y)
  579. {
  580. m_status = STATUS_OUT_OF_MEMORY;
  581. return;
  582. }
  583. }
  584. else
  585. {
  586. m_Pclist_y = Pclist_y;
  587. m_clist_y_forced = true;
  588. }
  589. if ((m_Psrc_y_count = (int*)calloc(m_resample_src_y, sizeof(int))) == NULL)
  590. {
  591. m_status = STATUS_OUT_OF_MEMORY;
  592. return;
  593. }
  594. if ((m_Psrc_y_flag = (unsigned char*)calloc(m_resample_src_y, sizeof(unsigned char))) == NULL)
  595. {
  596. m_status = STATUS_OUT_OF_MEMORY;
  597. return;
  598. }
  599. // Count how many times each source line contributes to a destination line.
  600. for (i = 0; i < m_resample_dst_y; i++)
  601. for (j = 0; j < m_Pclist_y[i].n; j++)
  602. m_Psrc_y_count[resampler_range_check(m_Pclist_y[i].p[j].pixel, m_resample_src_y)]++;
  603. if ((m_Pscan_buf = (Scan_Buf*)malloc(sizeof(Scan_Buf))) == NULL)
  604. {
  605. m_status = STATUS_OUT_OF_MEMORY;
  606. return;
  607. }
  608. for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
  609. {
  610. m_Pscan_buf->scan_buf_y[i] = -1;
  611. m_Pscan_buf->scan_buf_l[i] = NULL;
  612. }
  613. m_cur_src_y = m_cur_dst_y = 0;
  614. {
  615. // Determine which axis to resample first by comparing the number of multiplies required
  616. // for each possibility.
  617. int x_ops = count_ops(m_Pclist_x, m_resample_dst_x);
  618. int y_ops = count_ops(m_Pclist_y, m_resample_dst_y);
  619. // Hack 10/2000: Weight Y axis ops a little more than X axis ops.
  620. // (Y axis ops use more cache resources.)
  621. int xy_ops = x_ops * m_resample_src_y +
  622. (4 * y_ops * m_resample_dst_x) / 3;
  623. int yx_ops = (4 * y_ops * m_resample_src_x) / 3 +
  624. x_ops * m_resample_dst_y;
  625. #if BASISU_RESAMPLER_DEBUG_OPS
  626. printf("src: %i %i\n", m_resample_src_x, m_resample_src_y);
  627. printf("dst: %i %i\n", m_resample_dst_x, m_resample_dst_y);
  628. printf("x_ops: %i\n", x_ops);
  629. printf("y_ops: %i\n", y_ops);
  630. printf("xy_ops: %i\n", xy_ops);
  631. printf("yx_ops: %i\n", yx_ops);
  632. #endif
  633. // Now check which resample order is better. In case of a tie, choose the order
  634. // which buffers the least amount of data.
  635. if ((xy_ops > yx_ops) ||
  636. ((xy_ops == yx_ops) && (m_resample_src_x < m_resample_dst_x)))
  637. {
  638. m_delay_x_resample = true;
  639. m_intermediate_x = m_resample_src_x;
  640. }
  641. else
  642. {
  643. m_delay_x_resample = false;
  644. m_intermediate_x = m_resample_dst_x;
  645. }
  646. #if BASISU_RESAMPLER_DEBUG_OPS
  647. printf("delaying: %i\n", m_delay_x_resample);
  648. #endif
  649. }
  650. if (m_delay_x_resample)
  651. {
  652. if ((m_Ptmp_buf = (Sample*)malloc(m_intermediate_x * sizeof(Sample))) == NULL)
  653. {
  654. m_status = STATUS_OUT_OF_MEMORY;
  655. return;
  656. }
  657. }
  658. }
  659. void Resampler::get_clists(Contrib_List * *ptr_clist_x, Contrib_List * *ptr_clist_y)
  660. {
  661. if (ptr_clist_x)
  662. * ptr_clist_x = m_Pclist_x;
  663. if (ptr_clist_y)
  664. * ptr_clist_y = m_Pclist_y;
  665. }
  666. int Resampler::get_filter_num()
  667. {
  668. return g_num_resample_filters;
  669. }
  670. const char* Resampler::get_filter_name(int filter_num)
  671. {
  672. if ((filter_num < 0) || (filter_num >= g_num_resample_filters))
  673. return NULL;
  674. else
  675. return g_resample_filters[filter_num].name;
  676. }
  677. } // namespace basisu