diff --git a/panda/src/pnmimage/pfmFile.I b/panda/src/pnmimage/pfmFile.I index 1158b675c0..b985cda877 100644 --- a/panda/src/pnmimage/pfmFile.I +++ b/panda/src/pnmimage/pfmFile.I @@ -144,13 +144,17 @@ set_point2(int x, int y, const LVecBase2f &point) { _table[(y * _x_size + x)] = point[0]; break; - case 3: - (*(LPoint3f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1], point[2]); - break; - case 2: *(LPoint2f *)&_table[(y * _x_size + x) * _num_channels] = point; break; + + case 3: + (*(LPoint3f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1], 0.0); + break; + + case 4: + (*(LPoint4f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1], 0.0, 0.0); + break; } } @@ -214,10 +218,17 @@ set_point(int x, int y, const LVecBase3f &point) { _table[(y * _x_size + x)] = point[0]; break; + case 2: + (*(LPoint2f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1]); + break; + case 3: - case 4: *(LPoint3f *)&_table[(y * _x_size + x) * _num_channels] = point; break; + + case 4: + (*(LPoint4f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1], 0.0f, 0.0f); + break; } } @@ -281,6 +292,10 @@ set_point4(int x, int y, const LVecBase4f &point) { _table[(y * _x_size + x)] = point[0]; break; + case 2: + (*(LPoint2f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1]); + break; + case 3: (*(LPoint3f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1], point[2]); break; @@ -320,6 +335,36 @@ modify_point4(int x, int y) { return *(LPoint4f *)&_table[(y * _x_size + x) * _num_channels]; } +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::fill +// Access: Published +// Description: Fills the table with all of the same value. +//////////////////////////////////////////////////////////////////// +INLINE void PfmFile:: +fill(PN_float32 value) { + fill(LPoint4f(value, 0.0f, 0.0f, 0.0f)); +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::fill +// Access: Published +// Description: Fills the table with all of the same value. +//////////////////////////////////////////////////////////////////// +INLINE void PfmFile:: +fill(const LPoint2f &value) { + fill(LPoint4f(value[0], value[1], 0.0f, 0.0f)); +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::fill +// Access: Published +// Description: Fills the table with all of the same value. +//////////////////////////////////////////////////////////////////// +INLINE void PfmFile:: +fill(const LPoint3f &value) { + fill(LPoint4f(value[0], value[1], value[2], 0.0f)); +} + //////////////////////////////////////////////////////////////////// // Function: PfmFile::calc_autocrop // Access: Published diff --git a/panda/src/pnmimage/pfmFile.cxx b/panda/src/pnmimage/pfmFile.cxx index 619026a446..739108c0b5 100644 --- a/panda/src/pnmimage/pfmFile.cxx +++ b/panda/src/pnmimage/pfmFile.cxx @@ -470,6 +470,56 @@ store_mask(PNMImage &pnmimage) const { return true; } +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::fill +// Access: Published +// Description: Fills the table with all of the same value. +//////////////////////////////////////////////////////////////////// +void PfmFile:: +fill(const LPoint4f &value) { + switch (_num_channels) { + case 1: + { + for (int yi = 0; yi < _y_size; ++yi) { + for (int xi = 0; xi < _x_size; ++xi) { + _table[(yi * _x_size + xi)] = value[0]; + } + } + } + break; + + case 2: + { + for (int yi = 0; yi < _y_size; ++yi) { + for (int xi = 0; xi < _x_size; ++xi) { + (*(LPoint2f *)&_table[(yi * _x_size + xi) * _num_channels]).set(value[0], value[1]); + } + } + } + break; + + case 3: + { + for (int yi = 0; yi < _y_size; ++yi) { + for (int xi = 0; xi < _x_size; ++xi) { + (*(LPoint3f *)&_table[(yi * _x_size + xi) * _num_channels]).set(value[0], value[1], value[2]); + } + } + } + break; + + case 4: + { + for (int yi = 0; yi < _y_size; ++yi) { + for (int xi = 0; xi < _x_size; ++xi) { + *(LPoint4f *)&_table[(yi * _x_size + xi) * _num_channels] = value; + } + } + } + break; + } +} + //////////////////////////////////////////////////////////////////// // Function: PfmFile::calc_average_point // Access: Published @@ -736,41 +786,73 @@ resize(int new_x_size, int new_y_size) { return; } - int new_size = new_x_size * new_y_size * _num_channels; + PfmFile result; + result.clear(new_x_size, new_y_size, _num_channels); + + if (new_x_size < _x_size && new_y_size < _y_size) { + // If we're downscaling, we can use quick_filter, which is faster. + result.quick_filter_from(*this); + + } else { + // Otherwise, we should use box_filter(), which is more general. + result.box_filter_from(0.5, *this); + } + + _table.swap(result._table); + _x_size = new_x_size; + _y_size = new_y_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::quick_filter_from +// Access: Public +// Description: Resizes from the given image, with a fixed radius of +// 0.5. This is a very specialized and simple algorithm +// that doesn't handle dropping below the Nyquist rate +// very well, but is quite a bit faster than the more +// general box_filter(), above. +//////////////////////////////////////////////////////////////////// +void PfmFile:: +quick_filter_from(const PfmFile &from) { + if (_x_size == 0 || _y_size == 0) { + return; + } - // We allocate a little bit bigger to allow safe overflow. Table new_data; - new_data.reserve(new_size + 4); + new_data.reserve(_table.size()); PN_float32 from_x0, from_x1, from_y0, from_y1; + int orig_x_size = from.get_x_size(); + int orig_y_size = from.get_y_size(); + PN_float32 x_scale = 1.0; PN_float32 y_scale = 1.0; - if (new_x_size > 1) { - x_scale = (PN_float32)_x_size / (PN_float32)new_x_size; + if (_x_size > 1) { + x_scale = (PN_float32)orig_x_size / (PN_float32)_x_size; } - if (new_y_size > 1) { - y_scale = (PN_float32)_y_size / (PN_float32)new_y_size; + if (_y_size > 1) { + y_scale = (PN_float32)orig_y_size / (PN_float32)_y_size; } switch (_num_channels) { case 1: { from_y0 = 0.0; - for (int to_y = 0; to_y < new_y_size; ++to_y) { + for (int to_y = 0; to_y < _y_size; ++to_y) { from_y1 = (to_y + 1.0) * y_scale; - from_y1 = min(from_y1, (PN_float32) _y_size); + from_y1 = min(from_y1, (PN_float32)orig_y_size); from_x0 = 0.0; - for (int to_x = 0; to_x < new_x_size; ++to_x) { + for (int to_x = 0; to_x < _x_size; ++to_x) { from_x1 = (to_x + 1.0) * x_scale; - from_x1 = min(from_x1, (PN_float32) _x_size); + from_x1 = min(from_x1, (PN_float32)orig_x_size); // Now the box from (from_x0, from_y0) - (from_x1, from_y1) // but not including (from_x1, from_y1) maps to the pixel (to_x, to_y). PN_float32 result; - box_filter_region(result, from_x0, from_y0, from_x1, from_y1); + from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1); new_data.push_back(result); from_x0 = from_x1; @@ -783,19 +865,19 @@ resize(int new_x_size, int new_y_size) { case 3: { from_y0 = 0.0; - for (int to_y = 0; to_y < new_y_size; ++to_y) { + for (int to_y = 0; to_y < _y_size; ++to_y) { from_y1 = (to_y + 1.0) * y_scale; - from_y1 = min(from_y1, (PN_float32) _y_size); + from_y1 = min(from_y1, (PN_float32)orig_y_size); from_x0 = 0.0; - for (int to_x = 0; to_x < new_x_size; ++to_x) { + for (int to_x = 0; to_x < _x_size; ++to_x) { from_x1 = (to_x + 1.0) * x_scale; - from_x1 = min(from_x1, (PN_float32) _x_size); + from_x1 = min(from_x1, (PN_float32)orig_x_size); // Now the box from (from_x0, from_y0) - (from_x1, from_y1) // but not including (from_x1, from_y1) maps to the pixel (to_x, to_y). LPoint3f result; - box_filter_region(result, from_x0, from_y0, from_x1, from_y1); + from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1); new_data.push_back(result[0]); new_data.push_back(result[1]); new_data.push_back(result[2]); @@ -810,19 +892,19 @@ resize(int new_x_size, int new_y_size) { case 4: { from_y0 = 0.0; - for (int to_y = 0; to_y < new_y_size; ++to_y) { + for (int to_y = 0; to_y < _y_size; ++to_y) { from_y1 = (to_y + 1.0) * y_scale; - from_y1 = min(from_y1, (PN_float32) _y_size); + from_y1 = min(from_y1, (PN_float32)orig_y_size); from_x0 = 0.0; - for (int to_x = 0; to_x < new_x_size; ++to_x) { + for (int to_x = 0; to_x < _x_size; ++to_x) { from_x1 = (to_x + 1.0) * x_scale; - from_x1 = min(from_x1, (PN_float32) _x_size); + from_x1 = min(from_x1, (PN_float32)orig_x_size); // Now the box from (from_x0, from_y0) - (from_x1, from_y1) // but not including (from_x1, from_y1) maps to the pixel (to_x, to_y). LPoint4f result; - box_filter_region(result, from_x0, from_y0, from_x1, from_y1); + from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1); new_data.push_back(result[0]); new_data.push_back(result[1]); new_data.push_back(result[2]); @@ -844,10 +926,8 @@ resize(int new_x_size, int new_y_size) { new_data.push_back(0.0); new_data.push_back(0.0); - nassertv(new_data.size() == new_size + 4); + nassertv(new_data.size() == _table.size()); _table.swap(new_data); - _x_size = new_x_size; - _y_size = new_y_size; } //////////////////////////////////////////////////////////////////// @@ -963,53 +1043,72 @@ xform(const LMatrix4f &transform) { // current file is replaced with the point from the same // file at (x,y), where (x,y) is the point value from // the dist map. +// +// If scale_factor is not 1, it should be a value > 1, +// and it specifies the factor to upscale the working +// table while processing, to reduce artifacts from +// integer truncation. //////////////////////////////////////////////////////////////////// void PfmFile:: -forward_distort(const PfmFile &dist) { - PfmFile result; +forward_distort(const PfmFile &dist, PN_float32 scale_factor) { + int working_x_size = (int)cceil(_x_size * scale_factor); + int working_y_size = (int)cceil(_y_size * scale_factor); + + working_x_size = max(working_x_size, dist.get_x_size()); + working_y_size = max(working_y_size, dist.get_y_size()); + + const PfmFile *source_p = this; + PfmFile scaled_source; + if ((*this).get_x_size() != working_x_size || (*this).get_y_size() != working_y_size) { + // Rescale the source file as needed. + scaled_source = (*this); + scaled_source.resize(working_x_size, working_y_size); + source_p = &scaled_source; + } + const PfmFile *dist_p = &dist; PfmFile scaled_dist; - if (dist.get_x_size() != _x_size || dist.get_y_size() != _y_size) { + if (dist.get_x_size() != working_x_size || dist.get_y_size() != working_y_size) { // Rescale the dist file as needed. scaled_dist = dist; - scaled_dist.resize(_x_size, _y_size); + scaled_dist.resize(working_x_size, working_y_size); dist_p = &scaled_dist; } + PfmFile result; + result.clear(working_x_size, working_y_size, _num_channels); + if (_has_no_data_value) { - result = *this; - for (int yi = 0; yi < _y_size; ++yi) { - for (int xi = 0; xi < _x_size; ++xi) { - result.set_point4(xi, yi, _no_data_value); - } - } - - } else { - result.clear(_x_size, _y_size, _num_channels); + result.set_no_data_value(_no_data_value); + result.fill(_no_data_value); } - for (int yi = 0; yi < _y_size; ++yi) { - for (int xi = 0; xi < _x_size; ++xi) { + for (int yi = 0; yi < working_y_size; ++yi) { + for (int xi = 0; xi < working_x_size; ++xi) { if (!dist_p->has_point(xi, yi)) { continue; } LPoint2f uv = dist_p->get_point2(xi, yi); - int dist_xi = (int)cfloor(uv[0] * (double)_x_size); - int dist_yi = (int)cfloor(uv[1] * (double)_y_size); - if (dist_xi < 0 || dist_xi >= _x_size || - dist_yi < 0 || dist_yi >= _y_size) { + int dist_xi = (int)cfloor(uv[0] * (PN_float32)working_x_size); + int dist_yi = (int)cfloor(uv[1] * (PN_float32)working_y_size); + if (dist_xi < 0 || dist_xi >= working_x_size || + dist_yi < 0 || dist_yi >= working_y_size) { continue; } - if (!has_point(dist_xi, dist_yi)) { + if (!source_p->has_point(dist_xi, dist_yi)) { continue; } - result.set_point(xi, yi, get_point(dist_xi, dist_yi)); + result.set_point(xi, yi, source_p->get_point(dist_xi, dist_yi)); } } - (*this) = result; + // Resize to the target size for completion. + result.resize(_x_size, _y_size); + + nassertv(result._table.size() == _table.size()); + _table.swap(result._table); } //////////////////////////////////////////////////////////////////// @@ -1022,51 +1121,75 @@ forward_distort(const PfmFile &dist) { // current file is replaced with the point from the same // file at (u,v), where (x,y) is the point value from // the dist map. +// +// If scale_factor is not 1, it should be a value > 1, +// and it specifies the factor to upscale the working +// table while processing, to reduce artifacts from +// integer truncation. //////////////////////////////////////////////////////////////////// void PfmFile:: -reverse_distort(const PfmFile &dist) { - PfmFile result; +reverse_distort(const PfmFile &dist, PN_float32 scale_factor) { + int working_x_size = (int)cceil(_x_size * scale_factor); + int working_y_size = (int)cceil(_y_size * scale_factor); + + working_x_size = max(working_x_size, dist.get_x_size()); + working_y_size = max(working_y_size, dist.get_y_size()); + + const PfmFile *source_p = this; + PfmFile scaled_source; + if ((*this).get_x_size() != working_x_size || (*this).get_y_size() != working_y_size) { + // Rescale the source file as needed. + scaled_source = (*this); + scaled_source.resize(working_x_size, working_y_size); + source_p = &scaled_source; + } + const PfmFile *dist_p = &dist; PfmFile scaled_dist; - if (dist.get_x_size() != _x_size || dist.get_y_size() != _y_size) { + if (dist.get_x_size() != working_x_size || dist.get_y_size() != working_y_size) { // Rescale the dist file as needed. scaled_dist = dist; - scaled_dist.resize(_x_size, _y_size); + scaled_dist.resize(working_x_size, working_y_size); dist_p = &scaled_dist; } + PfmFile result; + result.clear(working_x_size, working_y_size, _num_channels); + if (_has_no_data_value) { - result = *this; - for (int yi = 0; yi < _y_size; ++yi) { - for (int xi = 0; xi < _x_size; ++xi) { - result.set_point4(xi, yi, _no_data_value); - } - } - } else { - result.clear(_x_size, _y_size, _num_channels); + result.set_no_data_value(_no_data_value); + result.fill(_no_data_value); } - for (int yi = 0; yi < _y_size; ++yi) { - for (int xi = 0; xi < _x_size; ++xi) { - if (!has_point(xi, yi)) { + for (int yi = 0; yi < working_y_size; ++yi) { + for (int xi = 0; xi < working_x_size; ++xi) { + if (!source_p->has_point(xi, yi)) { continue; } if (!dist_p->has_point(xi, yi)) { continue; } LPoint2f uv = dist_p->get_point2(xi, yi); - int dist_xi = (int)cfloor(uv[0] * (double)_x_size); - int dist_yi = (int)cfloor(uv[1] * (double)_y_size); - if (dist_xi < 0 || dist_xi >= _x_size || - dist_yi < 0 || dist_yi >= _y_size) { + int dist_xi = (int)cfloor(uv[0] * (PN_float32)working_x_size); + int dist_yi = (int)cfloor(uv[1] * (PN_float32)working_y_size); + if (dist_xi < 0 || dist_xi >= working_x_size || + dist_yi < 0 || dist_yi >= working_y_size) { continue; } - result.set_point(dist_xi, dist_yi, get_point(xi, yi)); + if (!source_p->has_point(dist_xi, dist_yi)) { + continue; + } + + result.set_point(dist_xi, dist_yi, source_p->get_point(xi, yi)); } } - (*this) = result; + // Resize to the target size for completion. + result.resize(_x_size, _y_size); + + nassertv(result._table.size() == _table.size()); + _table.swap(result._table); } //////////////////////////////////////////////////////////////////// @@ -1089,7 +1212,7 @@ merge(const PfmFile &other) { for (int yi = 0; yi < _y_size; ++yi) { for (int xi = 0; xi < _x_size; ++xi) { - if (!has_point(xi, yi)) { + if (!has_point(xi, yi) && other.has_point(xi, yi)) { set_point(xi, yi, other.get_point(xi, yi)); } } @@ -1180,6 +1303,47 @@ clear_to_texcoords(int x_size, int y_size) { } } +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::calc_tight_bounds +// Access: Published +// Description: Calculates the minimum and maximum vertices of all +// points within the table. Assumes the table contains +// 3-D points. +// +// The return value is true if any points in the table, +// or false if none are. +//////////////////////////////////////////////////////////////////// +bool PfmFile:: +calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point) const { + min_point.set(0.0f, 0.0f, 0.0f); + max_point.set(0.0f, 0.0f, 0.0f); + + bool found_any = false; + for (int yi = 0; yi < _y_size; ++yi) { + for (int xi = 0; xi < _x_size; ++xi) { + if (!has_point(xi, yi)) { + continue; + } + + const LPoint3f &point = get_point(xi, yi); + if (!found_any) { + min_point = point; + max_point = point; + found_any = true; + } else { + min_point.set(min(min_point[0], point[0]), + min(min_point[0], point[0]), + min(min_point[0], point[0])); + max_point.set(max(max_point[0], point[0]), + max(max_point[0], point[0]), + max(max_point[0], point[0])); + } + } + } + + return found_any; +} + //////////////////////////////////////////////////////////////////// // Function: PfmFile::compute_planar_bounds // Access: Published diff --git a/panda/src/pnmimage/pfmFile.h b/panda/src/pnmimage/pfmFile.h index 5a8e3e6a28..08a2ac2c80 100644 --- a/panda/src/pnmimage/pfmFile.h +++ b/panda/src/pnmimage/pfmFile.h @@ -74,6 +74,11 @@ PUBLISHED: INLINE void set_point4(int x, int y, const LVecBase4d &point); INLINE LPoint4f &modify_point4(int x, int y); + INLINE void fill(PN_float32 value); + INLINE void fill(const LPoint2f &value); + INLINE void fill(const LPoint3f &value); + void fill(const LPoint4f &value); + BLOCKING bool calc_average_point(LPoint3f &result, PN_float32 x, PN_float32 y, PN_float32 radius) const; BLOCKING bool calc_min_max(LVecBase3f &min_points, LVecBase3f &max_points) const; BLOCKING bool calc_autocrop(int &x_begin, int &x_end, int &y_begin, int &y_end) const; @@ -92,17 +97,22 @@ PUBLISHED: INLINE const LPoint4f &get_no_data_value() const; BLOCKING void resize(int new_x_size, int new_y_size); + BLOCKING void box_filter_from(double radius, const PfmFile ©); + BLOCKING void gaussian_filter_from(double radius, const PfmFile ©); + BLOCKING void quick_filter_from(const PfmFile ©); + BLOCKING void reverse_rows(); BLOCKING void flip(bool flip_x, bool flip_y, bool transpose); BLOCKING void xform(const LMatrix4f &transform); INLINE BLOCKING void xform(const LMatrix4d &transform); - BLOCKING void forward_distort(const PfmFile &dist); - BLOCKING void reverse_distort(const PfmFile &dist); + BLOCKING void forward_distort(const PfmFile &dist, PN_float32 scale_factor = 1.0); + BLOCKING void reverse_distort(const PfmFile &dist, PN_float32 scale_factor = 1.0); BLOCKING void merge(const PfmFile &other); BLOCKING void copy_channel(int to_channel, const PfmFile &other, int from_channel); BLOCKING void apply_crop(int x_begin, int x_end, int y_begin, int y_end); BLOCKING void clear_to_texcoords(int x_size, int y_size); + bool calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point) const; BLOCKING PT(BoundingHexahedron) compute_planar_bounds(const LPoint2f ¢er, PN_float32 point_dist, PN_float32 sample_radius, bool points_only) const; INLINE BLOCKING PT(BoundingHexahedron) compute_planar_bounds(const LPoint2d ¢er, PN_float32 point_dist, PN_float32 sample_radius, bool points_only) const; void compute_sample_point(LPoint3f &result, diff --git a/panda/src/pnmimage/pnm-image-filter-core.cxx b/panda/src/pnmimage/pnm-image-filter-core.cxx index ef77b67910..c9817da095 100644 --- a/panda/src/pnmimage/pnm-image-filter-core.cxx +++ b/panda/src/pnmimage/pnm-image-filter-core.cxx @@ -18,8 +18,8 @@ static void -FUNCTION_NAME(PNMImage &dest, const PNMImage &source, - double width, FilterFunction *make_filter) { +FUNCTION_NAME(IMAGETYPE &dest, const IMAGETYPE &source, + double width, FilterFunction *make_filter, int channel) { if (!dest.is_valid() || !source.is_valid()) { return; } @@ -37,20 +37,22 @@ FUNCTION_NAME(PNMImage &dest, const PNMImage &source, matrix[a] = (StoreType *)PANDA_MALLOC_ARRAY(source.BSIZE() * sizeof(StoreType)); } - // Now, scale the image in the A direction. - double scale = (double)dest.ASIZE() / (double)source.ASIZE(); + // First, scale the image in the A direction. + double scale; + StoreType *temp_source, *temp_dest; - StoreType *temp_source = (StoreType *)PANDA_MALLOC_ARRAY(source.ASIZE() * sizeof(StoreType)); - StoreType *temp_dest = (StoreType *)PANDA_MALLOC_ARRAY(dest.ASIZE() * sizeof(StoreType)); + scale = (double)dest.ASIZE() / (double)source.ASIZE(); + temp_source = (StoreType *)PANDA_MALLOC_ARRAY(source.ASIZE() * sizeof(StoreType)); + temp_dest = (StoreType *)PANDA_MALLOC_ARRAY(dest.ASIZE() * sizeof(StoreType)); WorkType *filter; double filter_width; make_filter(scale, width, filter, filter_width); - for (b=0; b0) { + if (net_weight > 0) { dest[dest_x] = (StoreType)(net_value / net_weight); } else { dest[dest_x] = 0; @@ -163,6 +164,68 @@ filter_row(StoreType dest[], int dest_len, Thread::consider_yield(); } +// As above, but we also accept an array of weight values per +// element, to support scaling a sparse array (as in a PfmFile). +static void +filter_sparse_row(StoreType dest[], StoreType dest_weight[], int dest_len, + const StoreType source[], const StoreType source_weight[], int source_len, + double scale, // == dest_len / source_len + const WorkType filter[], + double filter_width) { + // If we are expanding the row (scale>1.0), we need to look at a fractional + // granularity. Hence, we scale our filter index by scale. If we are + // compressing (scale<1.0), we don't need to fiddle with the filter index, so + // we leave it at one. + double iscale = max(scale, 1.0); + + // Similarly, if we are expanding the row, we want to start the new row at + // the far left edge of the original pixel, not in the center. So we will + // have a non-zero offset. + int offset = (int)cfloor(iscale*0.5); + + for (int dest_x = 0; dest_x < dest_len; dest_x++) { + double center = (dest_x - offset) / scale; + + // left and right are the starting and ending ranges of the radius of + // interest of the filter function. We need to apply the filter to each + // value in this range. + int left = max((int)cfloor(center - filter_width), 0); + int right = min((int)cceil(center + filter_width), source_len-1); + + // right_center is the point just to the right of the center. This + // allows us to flip the sign of the offset when we cross the center point. + int right_center = (int)cceil(center); + + WorkType net_weight = 0; + WorkType net_value = 0; + + int index, source_x; + + // This loop is broken into two pieces--the left of center and the right + // of center--so we don't have to incur the overhead of calling fabs() + // each time through the loop. + for (source_x = left; source_x < right_center; source_x++) { + index = (int)(iscale * (center - source_x)); + net_value += filter[index] * source[source_x] * source_weight[source_x]; + net_weight += filter[index] * source_weight[source_x]; + } + + for (; source_x <= right; source_x++) { + index = (int)(iscale * (source_x - center)); + net_value += filter[index] * source[source_x] * source_weight[source_x]; + net_weight += filter[index] * source_weight[source_x]; + } + + if (net_weight > 0) { + dest[dest_x] = (StoreType)(net_value / net_weight); + } else { + dest[dest_x] = 0; + } + dest_weight[dest_x] = (StoreType)net_weight; + } + Thread::consider_yield(); +} + // The various filter functions are called before each axis scaling to build // an kernel array suitable for the given scaling factor. Given a scaling @@ -186,20 +249,20 @@ box_filter_impl(double scale, double width, // the filter function to prevent dropping below the Nyquist rate. // Hence, we divide by scale. fscale = 1.0 / scale; - } else { + } else { // If we are expanding the image, we want to increase the granularity // of the filter function since we will need to access fractional cel // values. Hence, we multiply by scale. fscale = scale; } filter_width = width; - int actual_width = (int)cceil((filter_width+1) * fscale); + int actual_width = (int)cceil((filter_width + 1) * fscale); filter = (WorkType *)PANDA_MALLOC_ARRAY(actual_width * sizeof(WorkType)); - for (int i=0; i