mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-03 23:21:15 +00:00 
			
		
		
		
	
		
			
	
	
		
			853 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			853 lines
		
	
	
	
		
			19 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								// basisu_resampler.cpp
							 | 
						||
| 
								 | 
							
								// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Licensed under the Apache License, Version 2.0 (the "License");
							 | 
						||
| 
								 | 
							
								// you may not use this file except in compliance with the License.
							 | 
						||
| 
								 | 
							
								// You may obtain a copy of the License at
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								//    http://www.apache.org/licenses/LICENSE-2.0
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// Unless required by applicable law or agreed to in writing, software
							 | 
						||
| 
								 | 
							
								// distributed under the License is distributed on an "AS IS" BASIS,
							 | 
						||
| 
								 | 
							
								// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
							 | 
						||
| 
								 | 
							
								// See the License for the specific language governing permissions and
							 | 
						||
| 
								 | 
							
								// limitations under the License.
							 | 
						||
| 
								 | 
							
								#include "basisu_resampler.h"
							 | 
						||
| 
								 | 
							
								#include "basisu_resampler_filters.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef max
							 | 
						||
| 
								 | 
							
								#define max(a, b) (((a) > (b)) ? (a) : (b))
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#ifndef min
							 | 
						||
| 
								 | 
							
								#define min(a, b) (((a) < (b)) ? (a) : (b))
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define RESAMPLER_DEBUG 0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace basisu
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
									static inline int resampler_range_check(int v, int h)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										BASISU_NOTE_UNUSED(h);
							 | 
						||
| 
								 | 
							
										assert((v >= 0) && (v < h));
							 | 
						||
| 
								 | 
							
										return v;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Float to int cast with truncation.
							 | 
						||
| 
								 | 
							
									static inline int cast_to_int(Resample_Real i)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										return (int)i;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Ensure that the contributing source sample is within bounds. If not, reflect, clamp, or wrap.
							 | 
						||
| 
								 | 
							
									int Resampler::reflect(const int j, const int src_x, const Boundary_Op boundary_op)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										int n;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (j < 0)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											if (boundary_op == BOUNDARY_REFLECT)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												n = -j;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (n >= src_x)
							 | 
						||
| 
								 | 
							
													n = src_x - 1;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											else if (boundary_op == BOUNDARY_WRAP)
							 | 
						||
| 
								 | 
							
												n = posmod(j, src_x);
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
												n = 0;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else if (j >= src_x)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											if (boundary_op == BOUNDARY_REFLECT)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												n = (src_x - j) + (src_x - 1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (n < 0)
							 | 
						||
| 
								 | 
							
													n = 0;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											else if (boundary_op == BOUNDARY_WRAP)
							 | 
						||
| 
								 | 
							
												n = posmod(j, src_x);
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
												n = src_x - 1;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else
							 | 
						||
| 
								 | 
							
											n = j;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return n;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// The make_clist() method generates, for all destination samples,
							 | 
						||
| 
								 | 
							
									// the list of all source samples with non-zero weighted contributions.
							 | 
						||
| 
								 | 
							
									Resampler::Contrib_List * Resampler::make_clist(
							 | 
						||
| 
								 | 
							
										int src_x, int dst_x, Boundary_Op boundary_op,
							 | 
						||
| 
								 | 
							
										Resample_Real(*Pfilter)(Resample_Real),
							 | 
						||
| 
								 | 
							
										Resample_Real filter_support,
							 | 
						||
| 
								 | 
							
										Resample_Real filter_scale,
							 | 
						||
| 
								 | 
							
										Resample_Real src_ofs)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										struct Contrib_Bounds
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											// The center of the range in DISCRETE coordinates (pixel center = 0.0f).
							 | 
						||
| 
								 | 
							
											Resample_Real center;
							 | 
						||
| 
								 | 
							
											int left, right;
							 | 
						||
| 
								 | 
							
										};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										int i, j, k, n, left, right;
							 | 
						||
| 
								 | 
							
										Resample_Real total_weight;
							 | 
						||
| 
								 | 
							
										Resample_Real xscale, center, half_width, weight;
							 | 
						||
| 
								 | 
							
										Contrib_List* Pcontrib;
							 | 
						||
| 
								 | 
							
										Contrib* Pcpool;
							 | 
						||
| 
								 | 
							
										Contrib* Pcpool_next;
							 | 
						||
| 
								 | 
							
										Contrib_Bounds* Pcontrib_bounds;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ((Pcontrib = (Contrib_List*)calloc(dst_x, sizeof(Contrib_List))) == NULL)
							 | 
						||
| 
								 | 
							
											return NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										Pcontrib_bounds = (Contrib_Bounds*)calloc(dst_x, sizeof(Contrib_Bounds));
							 | 
						||
| 
								 | 
							
										if (!Pcontrib_bounds)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											free(Pcontrib);
							 | 
						||
| 
								 | 
							
											return (NULL);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const Resample_Real oo_filter_scale = 1.0f / filter_scale;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										const Resample_Real NUDGE = 0.5f;
							 | 
						||
| 
								 | 
							
										xscale = dst_x / (Resample_Real)src_x;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (xscale < 1.0f)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											int total;
							 | 
						||
| 
								 | 
							
											(void)total;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Handle case when there are fewer destination samples than source samples (downsampling/minification).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// stretched half width of filter
							 | 
						||
| 
								 | 
							
											half_width = (filter_support / xscale) * filter_scale;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Find the range of source sample(s) that will contribute to each destination sample.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											for (i = 0, n = 0; i < dst_x; i++)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												// Convert from discrete to continuous coordinates, scale, then convert back to discrete.
							 | 
						||
| 
								 | 
							
												center = ((Resample_Real)i + NUDGE) / xscale;
							 | 
						||
| 
								 | 
							
												center -= NUDGE;
							 | 
						||
| 
								 | 
							
												center += src_ofs;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												left = cast_to_int((Resample_Real)floor(center - half_width));
							 | 
						||
| 
								 | 
							
												right = cast_to_int((Resample_Real)ceil(center + half_width));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												Pcontrib_bounds[i].center = center;
							 | 
						||
| 
								 | 
							
												Pcontrib_bounds[i].left = left;
							 | 
						||
| 
								 | 
							
												Pcontrib_bounds[i].right = right;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												n += (right - left + 1);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Allocate memory for contributors. 
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if ((n == 0) || ((Pcpool = (Contrib*)calloc(n, sizeof(Contrib))) == NULL))
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												free(Pcontrib);
							 | 
						||
| 
								 | 
							
												free(Pcontrib_bounds);
							 | 
						||
| 
								 | 
							
												return NULL;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											total = n;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											Pcpool_next = Pcpool;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Create the list of source samples which contribute to each destination sample.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											for (i = 0; i < dst_x; i++)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												int max_k = -1;
							 | 
						||
| 
								 | 
							
												Resample_Real max_w = -1e+20f;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												center = Pcontrib_bounds[i].center;
							 | 
						||
| 
								 | 
							
												left = Pcontrib_bounds[i].left;
							 | 
						||
| 
								 | 
							
												right = Pcontrib_bounds[i].right;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												Pcontrib[i].n = 0;
							 | 
						||
| 
								 | 
							
												Pcontrib[i].p = Pcpool_next;
							 | 
						||
| 
								 | 
							
												Pcpool_next += (right - left + 1);
							 | 
						||
| 
								 | 
							
												assert((Pcpool_next - Pcpool) <= total);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												total_weight = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												for (j = left; j <= right; j++)
							 | 
						||
| 
								 | 
							
													total_weight += (*Pfilter)((center - (Resample_Real)j) * xscale * oo_filter_scale);
							 | 
						||
| 
								 | 
							
												const Resample_Real norm = static_cast<Resample_Real>(1.0f / total_weight);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												total_weight = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if RESAMPLER_DEBUG
							 | 
						||
| 
								 | 
							
												printf("%i: ", i);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												for (j = left; j <= right; j++)
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													weight = (*Pfilter)((center - (Resample_Real)j) * xscale * oo_filter_scale) * norm;
							 | 
						||
| 
								 | 
							
													if (weight == 0.0f)
							 | 
						||
| 
								 | 
							
														continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													n = reflect(j, src_x, boundary_op);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if RESAMPLER_DEBUG
							 | 
						||
| 
								 | 
							
													printf("%i(%f), ", n, weight);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// Increment the number of source samples which contribute to the current destination sample.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													k = Pcontrib[i].n++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													Pcontrib[i].p[k].pixel = (unsigned short)n; /* store src sample number */
							 | 
						||
| 
								 | 
							
													Pcontrib[i].p[k].weight = weight;           /* store src sample weight */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													total_weight += weight; /* total weight of all contributors */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if (weight > max_w)
							 | 
						||
| 
								 | 
							
													{
							 | 
						||
| 
								 | 
							
														max_w = weight;
							 | 
						||
| 
								 | 
							
														max_k = k;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if RESAMPLER_DEBUG
							 | 
						||
| 
								 | 
							
												printf("\n\n");
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												//assert(Pcontrib[i].n);
							 | 
						||
| 
								 | 
							
												//assert(max_k != -1);
							 | 
						||
| 
								 | 
							
												if ((max_k == -1) || (Pcontrib[i].n == 0))
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													free(Pcpool);
							 | 
						||
| 
								 | 
							
													free(Pcontrib);
							 | 
						||
| 
								 | 
							
													free(Pcontrib_bounds);
							 | 
						||
| 
								 | 
							
													return NULL;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (total_weight != 1.0f)
							 | 
						||
| 
								 | 
							
													Pcontrib[i].p[max_k].weight += 1.0f - total_weight;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											// Handle case when there are more destination samples than source samples (upsampling).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											half_width = filter_support * filter_scale;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Find the source sample(s) that contribute to each destination sample.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											for (i = 0, n = 0; i < dst_x; i++)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												// Convert from discrete to continuous coordinates, scale, then convert back to discrete.
							 | 
						||
| 
								 | 
							
												center = ((Resample_Real)i + NUDGE) / xscale;
							 | 
						||
| 
								 | 
							
												center -= NUDGE;
							 | 
						||
| 
								 | 
							
												center += src_ofs;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												left = cast_to_int((Resample_Real)floor(center - half_width));
							 | 
						||
| 
								 | 
							
												right = cast_to_int((Resample_Real)ceil(center + half_width));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												Pcontrib_bounds[i].center = center;
							 | 
						||
| 
								 | 
							
												Pcontrib_bounds[i].left = left;
							 | 
						||
| 
								 | 
							
												Pcontrib_bounds[i].right = right;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												n += (right - left + 1);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											/* Allocate memory for contributors. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											int total = n;
							 | 
						||
| 
								 | 
							
											if ((total == 0) || ((Pcpool = (Contrib*)calloc(total, sizeof(Contrib))) == NULL))
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												free(Pcontrib);
							 | 
						||
| 
								 | 
							
												free(Pcontrib_bounds);
							 | 
						||
| 
								 | 
							
												return NULL;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											Pcpool_next = Pcpool;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Create the list of source samples which contribute to each destination sample.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											for (i = 0; i < dst_x; i++)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												int max_k = -1;
							 | 
						||
| 
								 | 
							
												Resample_Real max_w = -1e+20f;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												center = Pcontrib_bounds[i].center;
							 | 
						||
| 
								 | 
							
												left = Pcontrib_bounds[i].left;
							 | 
						||
| 
								 | 
							
												right = Pcontrib_bounds[i].right;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												Pcontrib[i].n = 0;
							 | 
						||
| 
								 | 
							
												Pcontrib[i].p = Pcpool_next;
							 | 
						||
| 
								 | 
							
												Pcpool_next += (right - left + 1);
							 | 
						||
| 
								 | 
							
												assert((Pcpool_next - Pcpool) <= total);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												total_weight = 0;
							 | 
						||
| 
								 | 
							
												for (j = left; j <= right; j++)
							 | 
						||
| 
								 | 
							
													total_weight += (*Pfilter)((center - (Resample_Real)j) * oo_filter_scale);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												const Resample_Real norm = static_cast<Resample_Real>(1.0f / total_weight);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												total_weight = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if RESAMPLER_DEBUG
							 | 
						||
| 
								 | 
							
												printf("%i: ", i);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												for (j = left; j <= right; j++)
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													weight = (*Pfilter)((center - (Resample_Real)j) * oo_filter_scale) * norm;
							 | 
						||
| 
								 | 
							
													if (weight == 0.0f)
							 | 
						||
| 
								 | 
							
														continue;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													n = reflect(j, src_x, boundary_op);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if RESAMPLER_DEBUG
							 | 
						||
| 
								 | 
							
													printf("%i(%f), ", n, weight);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													// Increment the number of source samples which contribute to the current destination sample.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													k = Pcontrib[i].n++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													Pcontrib[i].p[k].pixel = (unsigned short)n; /* store src sample number */
							 | 
						||
| 
								 | 
							
													Pcontrib[i].p[k].weight = weight;           /* store src sample weight */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													total_weight += weight; /* total weight of all contributors */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if (weight > max_w)
							 | 
						||
| 
								 | 
							
													{
							 | 
						||
| 
								 | 
							
														max_w = weight;
							 | 
						||
| 
								 | 
							
														max_k = k;
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if RESAMPLER_DEBUG
							 | 
						||
| 
								 | 
							
												printf("\n\n");
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												//assert(Pcontrib[i].n);
							 | 
						||
| 
								 | 
							
												//assert(max_k != -1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if ((max_k == -1) || (Pcontrib[i].n == 0))
							 | 
						||
| 
								 | 
							
												{
							 | 
						||
| 
								 | 
							
													free(Pcpool);
							 | 
						||
| 
								 | 
							
													free(Pcontrib);
							 | 
						||
| 
								 | 
							
													free(Pcontrib_bounds);
							 | 
						||
| 
								 | 
							
													return NULL;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												if (total_weight != 1.0f)
							 | 
						||
| 
								 | 
							
													Pcontrib[i].p[max_k].weight += 1.0f - total_weight;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if RESAMPLER_DEBUG
							 | 
						||
| 
								 | 
							
										printf("*******\n");
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										free(Pcontrib_bounds);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return Pcontrib;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									void Resampler::resample_x(Sample * Pdst, const Sample * Psrc)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										assert(Pdst);
							 | 
						||
| 
								 | 
							
										assert(Psrc);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										int i, j;
							 | 
						||
| 
								 | 
							
										Sample total;
							 | 
						||
| 
								 | 
							
										Contrib_List* Pclist = m_Pclist_x;
							 | 
						||
| 
								 | 
							
										Contrib* p;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (i = m_resample_dst_x; i > 0; i--, Pclist++)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
								#if BASISU_RESAMPLER_DEBUG_OPS
							 | 
						||
| 
								 | 
							
											total_ops += Pclist->n;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											for (j = Pclist->n, p = Pclist->p, total = 0; j > 0; j--, p++)
							 | 
						||
| 
								 | 
							
												total += Psrc[p->pixel] * p->weight;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											*Pdst++ = total;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									void Resampler::scale_y_mov(Sample * Ptmp, const Sample * Psrc, Resample_Real weight, int dst_x)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if BASISU_RESAMPLER_DEBUG_OPS
							 | 
						||
| 
								 | 
							
										total_ops += dst_x;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Not += because temp buf wasn't cleared.
							 | 
						||
| 
								 | 
							
										for (i = dst_x; i > 0; i--)
							 | 
						||
| 
								 | 
							
											* Ptmp++ = *Psrc++ * weight;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									void Resampler::scale_y_add(Sample * Ptmp, const Sample * Psrc, Resample_Real weight, int dst_x)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
								#if BASISU_RESAMPLER_DEBUG_OPS
							 | 
						||
| 
								 | 
							
										total_ops += dst_x;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (int i = dst_x; i > 0; i--)
							 | 
						||
| 
								 | 
							
											(*Ptmp++) += *Psrc++ * weight;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									void Resampler::clamp(Sample * Pdst, int n)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										while (n > 0)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											Sample x = *Pdst;
							 | 
						||
| 
								 | 
							
											*Pdst++ = clamp_sample(x);
							 | 
						||
| 
								 | 
							
											n--;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									void Resampler::resample_y(Sample * Pdst)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										int i, j;
							 | 
						||
| 
								 | 
							
										Sample* Psrc;
							 | 
						||
| 
								 | 
							
										Contrib_List* Pclist = &m_Pclist_y[m_cur_dst_y];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										Sample* Ptmp = m_delay_x_resample ? m_Ptmp_buf : Pdst;
							 | 
						||
| 
								 | 
							
										assert(Ptmp);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Process each contributor. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (i = 0; i < Pclist->n; i++)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											// locate the contributor's location in the scan buffer -- the contributor must always be found!
							 | 
						||
| 
								 | 
							
											for (j = 0; j < MAX_SCAN_BUF_SIZE; j++)
							 | 
						||
| 
								 | 
							
												if (m_Pscan_buf->scan_buf_y[j] == Pclist->p[i].pixel)
							 | 
						||
| 
								 | 
							
													break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											assert(j < MAX_SCAN_BUF_SIZE);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											Psrc = m_Pscan_buf->scan_buf_l[j];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (!i)
							 | 
						||
| 
								 | 
							
												scale_y_mov(Ptmp, Psrc, Pclist->p[i].weight, m_intermediate_x);
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
												scale_y_add(Ptmp, Psrc, Pclist->p[i].weight, m_intermediate_x);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											/* If this source line doesn't contribute to any
							 | 
						||
| 
								 | 
							
											* more destination lines then mark the scanline buffer slot
							 | 
						||
| 
								 | 
							
											* which holds this source line as free.
							 | 
						||
| 
								 | 
							
											* (The max. number of slots used depends on the Y
							 | 
						||
| 
								 | 
							
											* axis sampling factor and the scaled filter width.)
							 | 
						||
| 
								 | 
							
											*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											if (--m_Psrc_y_count[resampler_range_check(Pclist->p[i].pixel, m_resample_src_y)] == 0)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												m_Psrc_y_flag[resampler_range_check(Pclist->p[i].pixel, m_resample_src_y)] = false;
							 | 
						||
| 
								 | 
							
												m_Pscan_buf->scan_buf_y[j] = -1;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Now generate the destination line */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (m_delay_x_resample) // Was X resampling delayed until after Y resampling?
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											assert(Pdst != Ptmp);
							 | 
						||
| 
								 | 
							
											resample_x(Pdst, Ptmp);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											assert(Pdst == Ptmp);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (m_lo < m_hi)
							 | 
						||
| 
								 | 
							
											clamp(Pdst, m_resample_dst_x);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									bool Resampler::put_line(const Sample * Psrc)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (m_cur_src_y >= m_resample_src_y)
							 | 
						||
| 
								 | 
							
											return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Does this source line contribute
							 | 
						||
| 
								 | 
							
										* to any destination line? if not,
							 | 
						||
| 
								 | 
							
										* exit now.
							 | 
						||
| 
								 | 
							
										*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (!m_Psrc_y_count[resampler_range_check(m_cur_src_y, m_resample_src_y)])
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_cur_src_y++;
							 | 
						||
| 
								 | 
							
											return true;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Find an empty slot in the scanline buffer. (FIXME: Perf. is terrible here with extreme scaling ratios.) */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
							 | 
						||
| 
								 | 
							
											if (m_Pscan_buf->scan_buf_y[i] == -1)
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* If the buffer is full, exit with an error. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (i == MAX_SCAN_BUF_SIZE)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_status = STATUS_SCAN_BUFFER_FULL;
							 | 
						||
| 
								 | 
							
											return false;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_Psrc_y_flag[resampler_range_check(m_cur_src_y, m_resample_src_y)] = true;
							 | 
						||
| 
								 | 
							
										m_Pscan_buf->scan_buf_y[i] = m_cur_src_y;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Does this slot have any memory allocated to it? */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (!m_Pscan_buf->scan_buf_l[i])
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											if ((m_Pscan_buf->scan_buf_l[i] = (Sample*)malloc(m_intermediate_x * sizeof(Sample))) == NULL)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												m_status = STATUS_OUT_OF_MEMORY;
							 | 
						||
| 
								 | 
							
												return false;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Resampling on the X axis first?
							 | 
						||
| 
								 | 
							
										if (m_delay_x_resample)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											assert(m_intermediate_x == m_resample_src_x);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Y-X resampling order
							 | 
						||
| 
								 | 
							
											memcpy(m_Pscan_buf->scan_buf_l[i], Psrc, m_intermediate_x * sizeof(Sample));
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											assert(m_intermediate_x == m_resample_dst_x);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// X-Y resampling order
							 | 
						||
| 
								 | 
							
											resample_x(m_Pscan_buf->scan_buf_l[i], Psrc);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_cur_src_y++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return true;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const Resampler::Sample* Resampler::get_line()
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* If all the destination lines have been
							 | 
						||
| 
								 | 
							
										* generated, then always return NULL.
							 | 
						||
| 
								 | 
							
										*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (m_cur_dst_y == m_resample_dst_y)
							 | 
						||
| 
								 | 
							
											return NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Check to see if all the required
							 | 
						||
| 
								 | 
							
										* contributors are present, if not,
							 | 
						||
| 
								 | 
							
										* return NULL.
							 | 
						||
| 
								 | 
							
										*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (i = 0; i < m_Pclist_y[m_cur_dst_y].n; i++)
							 | 
						||
| 
								 | 
							
											if (!m_Psrc_y_flag[resampler_range_check(m_Pclist_y[m_cur_dst_y].p[i].pixel, m_resample_src_y)])
							 | 
						||
| 
								 | 
							
												return NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										resample_y(m_Pdst_buf);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_cur_dst_y++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return m_Pdst_buf;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									Resampler::~Resampler()
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										int i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if BASISU_RESAMPLER_DEBUG_OPS
							 | 
						||
| 
								 | 
							
										printf("actual ops: %i\n", total_ops);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										free(m_Pdst_buf);
							 | 
						||
| 
								 | 
							
										m_Pdst_buf = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (m_Ptmp_buf)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											free(m_Ptmp_buf);
							 | 
						||
| 
								 | 
							
											m_Ptmp_buf = NULL;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Don't deallocate a contibutor list
							 | 
						||
| 
								 | 
							
										* if the user passed us one of their own.
							 | 
						||
| 
								 | 
							
									*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ((m_Pclist_x) && (!m_clist_x_forced))
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											free(m_Pclist_x->p);
							 | 
						||
| 
								 | 
							
											free(m_Pclist_x);
							 | 
						||
| 
								 | 
							
											m_Pclist_x = NULL;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ((m_Pclist_y) && (!m_clist_y_forced))
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											free(m_Pclist_y->p);
							 | 
						||
| 
								 | 
							
											free(m_Pclist_y);
							 | 
						||
| 
								 | 
							
											m_Pclist_y = NULL;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										free(m_Psrc_y_count);
							 | 
						||
| 
								 | 
							
										m_Psrc_y_count = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										free(m_Psrc_y_flag);
							 | 
						||
| 
								 | 
							
										m_Psrc_y_flag = NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (m_Pscan_buf)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
							 | 
						||
| 
								 | 
							
												free(m_Pscan_buf->scan_buf_l[i]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											free(m_Pscan_buf);
							 | 
						||
| 
								 | 
							
											m_Pscan_buf = NULL;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									void Resampler::restart()
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										if (STATUS_OKAY != m_status)
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_cur_src_y = m_cur_dst_y = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										int i, j;
							 | 
						||
| 
								 | 
							
										for (i = 0; i < m_resample_src_y; i++)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_Psrc_y_count[i] = 0;
							 | 
						||
| 
								 | 
							
											m_Psrc_y_flag[i] = false;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (i = 0; i < m_resample_dst_y; i++)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											for (j = 0; j < m_Pclist_y[i].n; j++)
							 | 
						||
| 
								 | 
							
												m_Psrc_y_count[resampler_range_check(m_Pclist_y[i].p[j].pixel, m_resample_src_y)]++;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_Pscan_buf->scan_buf_y[i] = -1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											free(m_Pscan_buf->scan_buf_l[i]);
							 | 
						||
| 
								 | 
							
											m_Pscan_buf->scan_buf_l[i] = NULL;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									Resampler::Resampler(int src_x, int src_y,
							 | 
						||
| 
								 | 
							
										int dst_x, int dst_y,
							 | 
						||
| 
								 | 
							
										Boundary_Op boundary_op,
							 | 
						||
| 
								 | 
							
										Resample_Real sample_low, Resample_Real sample_high,
							 | 
						||
| 
								 | 
							
										const char* Pfilter_name,
							 | 
						||
| 
								 | 
							
										Contrib_List * Pclist_x,
							 | 
						||
| 
								 | 
							
										Contrib_List * Pclist_y,
							 | 
						||
| 
								 | 
							
										Resample_Real filter_x_scale,
							 | 
						||
| 
								 | 
							
										Resample_Real filter_y_scale,
							 | 
						||
| 
								 | 
							
										Resample_Real src_x_ofs,
							 | 
						||
| 
								 | 
							
										Resample_Real src_y_ofs)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										int i, j;
							 | 
						||
| 
								 | 
							
										Resample_Real support, (*func)(Resample_Real);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										assert(src_x > 0);
							 | 
						||
| 
								 | 
							
										assert(src_y > 0);
							 | 
						||
| 
								 | 
							
										assert(dst_x > 0);
							 | 
						||
| 
								 | 
							
										assert(dst_y > 0);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if BASISU_RESAMPLER_DEBUG_OPS
							 | 
						||
| 
								 | 
							
										total_ops = 0;
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_lo = sample_low;
							 | 
						||
| 
								 | 
							
										m_hi = sample_high;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_delay_x_resample = false;
							 | 
						||
| 
								 | 
							
										m_intermediate_x = 0;
							 | 
						||
| 
								 | 
							
										m_Pdst_buf = NULL;
							 | 
						||
| 
								 | 
							
										m_Ptmp_buf = NULL;
							 | 
						||
| 
								 | 
							
										m_clist_x_forced = false;
							 | 
						||
| 
								 | 
							
										m_Pclist_x = NULL;
							 | 
						||
| 
								 | 
							
										m_clist_y_forced = false;
							 | 
						||
| 
								 | 
							
										m_Pclist_y = NULL;
							 | 
						||
| 
								 | 
							
										m_Psrc_y_count = NULL;
							 | 
						||
| 
								 | 
							
										m_Psrc_y_flag = NULL;
							 | 
						||
| 
								 | 
							
										m_Pscan_buf = NULL;
							 | 
						||
| 
								 | 
							
										m_status = STATUS_OKAY;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_resample_src_x = src_x;
							 | 
						||
| 
								 | 
							
										m_resample_src_y = src_y;
							 | 
						||
| 
								 | 
							
										m_resample_dst_x = dst_x;
							 | 
						||
| 
								 | 
							
										m_resample_dst_y = dst_y;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_boundary_op = boundary_op;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ((m_Pdst_buf = (Sample*)malloc(m_resample_dst_x * sizeof(Sample))) == NULL)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_status = STATUS_OUT_OF_MEMORY;
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Find the specified filter.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (Pfilter_name == NULL)
							 | 
						||
| 
								 | 
							
											Pfilter_name = BASISU_RESAMPLER_DEFAULT_FILTER;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (i = 0; i < g_num_resample_filters; i++)
							 | 
						||
| 
								 | 
							
											if (strcmp(Pfilter_name, g_resample_filters[i].name) == 0)
							 | 
						||
| 
								 | 
							
												break;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (i == g_num_resample_filters)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_status = STATUS_BAD_FILTER_NAME;
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										func = g_resample_filters[i].func;
							 | 
						||
| 
								 | 
							
										support = g_resample_filters[i].support;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										/* Create contributor lists, unless the user supplied custom lists. */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (!Pclist_x)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_Pclist_x = make_clist(m_resample_src_x, m_resample_dst_x, m_boundary_op, func, support, filter_x_scale, src_x_ofs);
							 | 
						||
| 
								 | 
							
											if (!m_Pclist_x)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												m_status = STATUS_OUT_OF_MEMORY;
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_Pclist_x = Pclist_x;
							 | 
						||
| 
								 | 
							
											m_clist_x_forced = true;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (!Pclist_y)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_Pclist_y = make_clist(m_resample_src_y, m_resample_dst_y, m_boundary_op, func, support, filter_y_scale, src_y_ofs);
							 | 
						||
| 
								 | 
							
											if (!m_Pclist_y)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												m_status = STATUS_OUT_OF_MEMORY;
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_Pclist_y = Pclist_y;
							 | 
						||
| 
								 | 
							
											m_clist_y_forced = true;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ((m_Psrc_y_count = (int*)calloc(m_resample_src_y, sizeof(int))) == NULL)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_status = STATUS_OUT_OF_MEMORY;
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ((m_Psrc_y_flag = (unsigned char*)calloc(m_resample_src_y, sizeof(unsigned char))) == NULL)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_status = STATUS_OUT_OF_MEMORY;
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Count how many times each source line contributes to a destination line.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (i = 0; i < m_resample_dst_y; i++)
							 | 
						||
| 
								 | 
							
											for (j = 0; j < m_Pclist_y[i].n; j++)
							 | 
						||
| 
								 | 
							
												m_Psrc_y_count[resampler_range_check(m_Pclist_y[i].p[j].pixel, m_resample_src_y)]++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if ((m_Pscan_buf = (Scan_Buf*)malloc(sizeof(Scan_Buf))) == NULL)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_status = STATUS_OUT_OF_MEMORY;
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											m_Pscan_buf->scan_buf_y[i] = -1;
							 | 
						||
| 
								 | 
							
											m_Pscan_buf->scan_buf_l[i] = NULL;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										m_cur_src_y = m_cur_dst_y = 0;
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											// Determine which axis to resample first by comparing the number of multiplies required
							 | 
						||
| 
								 | 
							
											// for each possibility.
							 | 
						||
| 
								 | 
							
											int x_ops = count_ops(m_Pclist_x, m_resample_dst_x);
							 | 
						||
| 
								 | 
							
											int y_ops = count_ops(m_Pclist_y, m_resample_dst_y);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Hack 10/2000: Weight Y axis ops a little more than X axis ops.
							 | 
						||
| 
								 | 
							
											// (Y axis ops use more cache resources.)
							 | 
						||
| 
								 | 
							
											int xy_ops = x_ops * m_resample_src_y +
							 | 
						||
| 
								 | 
							
												(4 * y_ops * m_resample_dst_x) / 3;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											int yx_ops = (4 * y_ops * m_resample_src_x) / 3 +
							 | 
						||
| 
								 | 
							
												x_ops * m_resample_dst_y;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#if BASISU_RESAMPLER_DEBUG_OPS
							 | 
						||
| 
								 | 
							
											printf("src: %i %i\n", m_resample_src_x, m_resample_src_y);
							 | 
						||
| 
								 | 
							
											printf("dst: %i %i\n", m_resample_dst_x, m_resample_dst_y);
							 | 
						||
| 
								 | 
							
											printf("x_ops: %i\n", x_ops);
							 | 
						||
| 
								 | 
							
											printf("y_ops: %i\n", y_ops);
							 | 
						||
| 
								 | 
							
											printf("xy_ops: %i\n", xy_ops);
							 | 
						||
| 
								 | 
							
											printf("yx_ops: %i\n", yx_ops);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											// Now check which resample order is better. In case of a tie, choose the order
							 | 
						||
| 
								 | 
							
											// which buffers the least amount of data.
							 | 
						||
| 
								 | 
							
											if ((xy_ops > yx_ops) ||
							 | 
						||
| 
								 | 
							
												((xy_ops == yx_ops) && (m_resample_src_x < m_resample_dst_x)))
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												m_delay_x_resample = true;
							 | 
						||
| 
								 | 
							
												m_intermediate_x = m_resample_src_x;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												m_delay_x_resample = false;
							 | 
						||
| 
								 | 
							
												m_intermediate_x = m_resample_dst_x;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								#if BASISU_RESAMPLER_DEBUG_OPS
							 | 
						||
| 
								 | 
							
											printf("delaying: %i\n", m_delay_x_resample);
							 | 
						||
| 
								 | 
							
								#endif
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (m_delay_x_resample)
							 | 
						||
| 
								 | 
							
										{
							 | 
						||
| 
								 | 
							
											if ((m_Ptmp_buf = (Sample*)malloc(m_intermediate_x * sizeof(Sample))) == NULL)
							 | 
						||
| 
								 | 
							
											{
							 | 
						||
| 
								 | 
							
												m_status = STATUS_OUT_OF_MEMORY;
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									void Resampler::get_clists(Contrib_List * *ptr_clist_x, Contrib_List * *ptr_clist_y)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										if (ptr_clist_x)
							 | 
						||
| 
								 | 
							
											* ptr_clist_x = m_Pclist_x;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (ptr_clist_y)
							 | 
						||
| 
								 | 
							
											* ptr_clist_y = m_Pclist_y;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									int Resampler::get_filter_num()
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										return g_num_resample_filters;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const char* Resampler::get_filter_name(int filter_num)
							 | 
						||
| 
								 | 
							
									{
							 | 
						||
| 
								 | 
							
										if ((filter_num < 0) || (filter_num >= g_num_resample_filters))
							 | 
						||
| 
								 | 
							
											return NULL;
							 | 
						||
| 
								 | 
							
										else
							 | 
						||
| 
								 | 
							
											return g_resample_filters[filter_num].name;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
								} // namespace basisu
							 |