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