From 8876f0939e48c9c026c706b18405c64ad15d2aee Mon Sep 17 00:00:00 2001 From: David Rose Date: Sat, 25 Apr 2015 07:23:54 -0700 Subject: [PATCH] add PfmFile::gamma_correct(), PfmFile::apply_mask(), PNMImage::copy_channel_bits() --- panda/src/pnmimage/pfmFile.I | 73 +++++++++- panda/src/pnmimage/pfmFile.cxx | 209 ++++++++++++++++++++-------- panda/src/pnmimage/pfmFile.h | 10 +- panda/src/pnmimage/pnmImage.cxx | 61 +++++++- panda/src/pnmimage/pnmImage.h | 1 + panda/src/pnmimage/pnmImageHeader.I | 46 +++--- 6 files changed, 314 insertions(+), 86 deletions(-) diff --git a/panda/src/pnmimage/pfmFile.I b/panda/src/pnmimage/pfmFile.I index 928677ca65..f3ae0cb5a5 100644 --- a/panda/src/pnmimage/pfmFile.I +++ b/panda/src/pnmimage/pfmFile.I @@ -16,7 +16,7 @@ //////////////////////////////////////////////////////////////////// // Function: PfmFile::is_valid // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE bool PfmFile:: is_valid() const { @@ -155,7 +155,7 @@ set_point2(int x, int y, const LVecBase2f &point) { case 4: (*(LPoint4f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1], 0.0, 0.0); break; - } + } } //////////////////////////////////////////////////////////////////// @@ -276,7 +276,7 @@ set_point3(int x, int y, const LVecBase3f &point) { case 4: (*(LPoint4f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1], 0.0f, 0.0f); break; - } + } } //////////////////////////////////////////////////////////////////// @@ -350,7 +350,7 @@ set_point4(int x, int y, const LVecBase4f &point) { case 4: *(LPoint4f *)&_table[(y * _x_size + x) * _num_channels] = point; break; - } + } } //////////////////////////////////////////////////////////////////// @@ -593,6 +593,71 @@ compute_planar_bounds(const LPoint2d ¢er, PN_float32 point_dist, PN_float32 return compute_planar_bounds(LCAST(PN_float32, center), point_dist, sample_radius, points_only); } +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::gamma_correct +// Access: Published +// Description: Assuming the image was constructed with a gamma curve +// of from_gamma in the RGB channels, converts it to an +// image with a gamma curve of to_gamma in the RGB +// channels. Does not affect the alpha channel. +//////////////////////////////////////////////////////////////////// +INLINE void PfmFile:: +gamma_correct(float from_gamma, float to_gamma) { + apply_exponent(from_gamma / to_gamma); +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::gamma_correct_alpha +// Access: Published +// Description: Assuming the image was constructed with a gamma curve +// of from_gamma in the alpha channel, converts it to an +// image with a gamma curve of to_gamma in the alpha +// channel. Does not affect the RGB channels. +//////////////////////////////////////////////////////////////////// +INLINE void PfmFile:: +gamma_correct_alpha(float from_gamma, float to_gamma) { + apply_exponent(1.0, from_gamma / to_gamma); +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::apply_exponent +// Access: Published +// Description: Adjusts each channel of the image by raising the +// corresponding component value to the indicated +// exponent, such that L' = L ^ exponent. +//////////////////////////////////////////////////////////////////// +INLINE void PfmFile:: +apply_exponent(float gray_exponent) { + apply_exponent(gray_exponent, gray_exponent, gray_exponent, 1.0); +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::apply_exponent +// Access: Published +// Description: Adjusts each channel of the image by raising the +// corresponding component value to the indicated +// exponent, such that L' = L ^ exponent. +//////////////////////////////////////////////////////////////////// +INLINE void PfmFile:: +apply_exponent(float gray_exponent, float alpha_exponent) { + apply_exponent(gray_exponent, gray_exponent, gray_exponent, alpha_exponent); +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::apply_exponent +// Access: Published +// Description: Adjusts each channel of the image by raising the +// corresponding component value to the indicated +// exponent, such that L' = L ^ exponent. For a +// grayscale image, the blue_exponent value is used for +// the grayscale value, and red_exponent and +// green_exponent are unused. +//////////////////////////////////////////////////////////////////// +INLINE void PfmFile:: +apply_exponent(float c0_exponent, float c1_exponent, float c2_exponent) { + apply_exponent(c0_exponent, c1_exponent, c2_exponent, 1.0); +} + //////////////////////////////////////////////////////////////////// // Function: PfmFile::get_table // Access: Public diff --git a/panda/src/pnmimage/pfmFile.cxx b/panda/src/pnmimage/pfmFile.cxx index 071985a4d6..3cad7c7e99 100644 --- a/panda/src/pnmimage/pfmFile.cxx +++ b/panda/src/pnmimage/pfmFile.cxx @@ -233,7 +233,7 @@ write(const Filename &fullpath) { << "Unable to open " << filename << "\n"; return false; } - + if (pnmimage_cat.is_debug()) { pnmimage_cat.debug() << "Writing PFM file " << filename << "\n"; @@ -514,7 +514,7 @@ fill(const LPoint4f &value) { } } break; - } + } } //////////////////////////////////////////////////////////////////// @@ -767,7 +767,7 @@ calc_min_max(LVecBase3f &min_depth, LVecBase3f &max_depth) const { if (!has_point(xi, yi)) { continue; } - + const LPoint3f &p = get_point(xi, yi); if (!any_points) { min_depth = p; @@ -783,7 +783,7 @@ calc_min_max(LVecBase3f &min_depth, LVecBase3f &max_depth) const { } } } - + return any_points; } @@ -839,7 +839,7 @@ calc_autocrop(int &x_begin, int &x_end, int &y_begin, int &y_end) const { //////////////////////////////////////////////////////////////////// bool PfmFile:: is_row_empty(int y, int x_begin, int x_end) const { - nassertr(y >= 0 && y < _y_size && + nassertr(y >= 0 && y < _y_size && x_begin >= 0 && x_begin <= x_end && x_end <= _x_size, false); if (!_has_no_data_value) { @@ -863,7 +863,7 @@ is_row_empty(int y, int x_begin, int x_end) const { //////////////////////////////////////////////////////////////////// bool PfmFile:: is_column_empty(int x, int y_begin, int y_end) const { - nassertr(x >= 0 && x < _x_size && + nassertr(x >= 0 && x < _x_size && y_begin >= 0 && y_begin <= y_end && y_end <= _y_size, false); if (!_has_no_data_value) { @@ -1012,7 +1012,7 @@ resize(int new_x_size, int new_y_size) { if (pfm_resize_quick && 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() or gaussian_filter, which // are more general. @@ -1068,18 +1068,18 @@ quick_filter_from(const PfmFile &from) { 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)orig_y_size); - + from_x0 = 0.0; 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)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; from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1); new_data.push_back(result); - + from_x0 = from_x1; } from_y0 = from_y1; @@ -1093,19 +1093,19 @@ quick_filter_from(const PfmFile &from) { 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)orig_y_size); - + from_x0 = 0.0; 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)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). LPoint2f result; 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]); - + from_x0 = from_x1; } from_y0 = from_y1; @@ -1119,12 +1119,12 @@ quick_filter_from(const PfmFile &from) { 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)orig_y_size); - + from_x0 = 0.0; 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)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; @@ -1132,7 +1132,7 @@ quick_filter_from(const PfmFile &from) { new_data.push_back(result[0]); new_data.push_back(result[1]); new_data.push_back(result[2]); - + from_x0 = from_x1; } from_y0 = from_y1; @@ -1146,12 +1146,12 @@ quick_filter_from(const PfmFile &from) { 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)orig_y_size); - + from_x0 = 0.0; 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)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; @@ -1160,14 +1160,14 @@ quick_filter_from(const PfmFile &from) { new_data.push_back(result[1]); new_data.push_back(result[2]); new_data.push_back(result[3]); - + from_x0 = from_x1; } from_y0 = from_y1; } } break; - + default: nassertv(false); } @@ -1196,7 +1196,7 @@ reverse_rows() { for (int yi = 0; yi < _y_size; ++yi) { int source_yi = _y_size - 1 - yi; int start = source_yi * row_size; - reversed.insert(reversed.end(), + reversed.insert(reversed.end(), _table.begin() + start, _table.begin() + start + row_size); } @@ -1290,7 +1290,7 @@ xform(const LMatrix4f &transform) { // Description: Applies the distortion indicated in the supplied dist // map to the current map. The dist map is understood // to be a mapping of points in the range 0..1 in the -// first two dimensions. +// first two dimensions. // // The operation can be expressed symbolically as: // @@ -1334,7 +1334,7 @@ forward_distort(const PfmFile &dist, PN_float32 scale_factor) { PfmFile result; result.clear(working_x_size, working_y_size, _num_channels); - + if (_has_no_data_value) { result.set_no_data_value(_no_data_value); result.fill(_no_data_value); @@ -1412,7 +1412,7 @@ reverse_distort(const PfmFile &dist, PN_float32 scale_factor) { PfmFile result; result.clear(working_x_size, working_y_size, _num_channels); - + if (_has_no_data_value) { result.set_no_data_value(_no_data_value); result.fill(_no_data_value); @@ -1466,6 +1466,36 @@ merge(const PfmFile &other) { } } +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::apply_mask +// Access: Published +// Description: Wherever there is missing data in the other PfmFile, +// set this the corresponding point in this PfmFile to +// missing as well, so that this PfmFile has only points +// where both files have points. +// +// The point is set to "missing" by setting it the +// no_data_value. +//////////////////////////////////////////////////////////////////// +void PfmFile:: +apply_mask(const PfmFile &other) { + nassertv(is_valid() && other.is_valid()); + nassertv(other._x_size == _x_size && other._y_size == _y_size); + + if (!other._has_no_data_value || !_has_no_data_value) { + // Trivial no-op. + return; + } + + for (int yi = 0; yi < _y_size; ++yi) { + for (int xi = 0; xi < _x_size; ++xi) { + if (!other.has_point(xi, yi)) { + set_point4(xi, yi, _no_data_value); + } + } + } +} + //////////////////////////////////////////////////////////////////// // Function: PfmFile::copy_channel // Access: Published @@ -1774,7 +1804,7 @@ compute_planar_bounds(const LPoint2f ¢er, PN_float32 point_dist, PN_float32 } PT(BoundingHexahedron) bounds; - + // We create a BoundingHexahedron with the points in a particular // well-defined order, based on the current coordinate system. CoordinateSystem cs = get_default_coordinate_system(); @@ -1941,7 +1971,7 @@ copy_sub_image(const PfmFile ©, int xto, int yto, } } break; - } + } } //////////////////////////////////////////////////////////////////// @@ -2008,7 +2038,7 @@ add_sub_image(const PfmFile ©, int xto, int yto, } } break; - } + } } //////////////////////////////////////////////////////////////////// @@ -2101,7 +2131,11 @@ divide_sub_image(const PfmFile ©, int xto, int yto, for (y = ymin; y < ymax; y++) { for (x = xmin; x < xmax; x++) { if (has_point(x, y) && copy.has_point(x - xmin + xfrom, y - ymin + yfrom)) { - set_point1(x, y, get_point1(x, y) / copy.get_point1(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale); + float val = get_point1(x, y) / copy.get_point1(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale; + if (cnan(val)) { + val = 0.0f; + } + set_point1(x, y, val); } } } @@ -2224,6 +2258,69 @@ operator *= (float multiplier) { } } +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::apply_exponent +// Access: Published +// Description: Adjusts each channel of the image by raising the +// corresponding component value to the indicated +// exponent, such that L' = L ^ exponent. +//////////////////////////////////////////////////////////////////// +void PfmFile:: +apply_exponent(float c0_exponent, float c1_exponent, float c2_exponent, + float c3_exponent) { + switch (_num_channels) { + case 1: + { + for (int yi = 0; yi < _y_size; ++yi) { + for (int xi = 0; xi < _x_size; ++xi) { + float *val = &_table[(yi * _x_size + xi)]; + val[0] = cpow(val[0], c0_exponent); + } + } + } + break; + + case 2: + { + for (int yi = 0; yi < _y_size; ++yi) { + for (int xi = 0; xi < _x_size; ++xi) { + float *val = &_table[(yi * _x_size + xi) * _num_channels]; + val[0] = cpow(val[0], c0_exponent); + val[1] = cpow(val[1], c1_exponent); + } + } + } + break; + + case 3: + { + for (int yi = 0; yi < _y_size; ++yi) { + for (int xi = 0; xi < _x_size; ++xi) { + float *val = &_table[(yi * _x_size + xi) * _num_channels]; + val[0] = cpow(val[0], c0_exponent); + val[1] = cpow(val[1], c1_exponent); + val[2] = cpow(val[2], c2_exponent); + } + } + } + break; + + case 4: + { + for (int yi = 0; yi < _y_size; ++yi) { + for (int xi = 0; xi < _x_size; ++xi) { + float *val = &_table[(yi * _x_size + xi) * _num_channels]; + val[0] = cpow(val[0], c0_exponent); + val[1] = cpow(val[1], c1_exponent); + val[2] = cpow(val[2], c2_exponent); + val[3] = cpow(val[3], c3_exponent); + } + } + } + break; + } +} + //////////////////////////////////////////////////////////////////// // Function: PfmFile::output // Access: Published @@ -2418,7 +2515,7 @@ box_filter_region(LPoint4f &result, //////////////////////////////////////////////////////////////////// // Function: PfmFile::box_filter_line // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void PfmFile:: box_filter_line(PN_float32 &result, PN_float32 &coverage, @@ -2447,7 +2544,7 @@ box_filter_line(PN_float32 &result, PN_float32 &coverage, //////////////////////////////////////////////////////////////////// // Function: PfmFile::box_filter_line // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void PfmFile:: box_filter_line(LPoint2f &result, PN_float32 &coverage, @@ -2476,7 +2573,7 @@ box_filter_line(LPoint2f &result, PN_float32 &coverage, //////////////////////////////////////////////////////////////////// // Function: PfmFile::box_filter_line // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void PfmFile:: box_filter_line(LPoint3f &result, PN_float32 &coverage, @@ -2505,7 +2602,7 @@ box_filter_line(LPoint3f &result, PN_float32 &coverage, //////////////////////////////////////////////////////////////////// // Function: PfmFile::box_filter_line // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void PfmFile:: box_filter_line(LPoint4f &result, PN_float32 &coverage, @@ -2534,7 +2631,7 @@ box_filter_line(LPoint4f &result, PN_float32 &coverage, //////////////////////////////////////////////////////////////////// // Function: PfmFile::box_filter_point // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void PfmFile:: box_filter_point(PN_float32 &result, PN_float32 &coverage, @@ -2552,7 +2649,7 @@ box_filter_point(PN_float32 &result, PN_float32 &coverage, //////////////////////////////////////////////////////////////////// // Function: PfmFile::box_filter_point // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void PfmFile:: box_filter_point(LPoint2f &result, PN_float32 &coverage, @@ -2570,7 +2667,7 @@ box_filter_point(LPoint2f &result, PN_float32 &coverage, //////////////////////////////////////////////////////////////////// // Function: PfmFile::box_filter_point // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void PfmFile:: box_filter_point(LPoint3f &result, PN_float32 &coverage, @@ -2588,7 +2685,7 @@ box_filter_point(LPoint3f &result, PN_float32 &coverage, //////////////////////////////////////////////////////////////////// // Function: PfmFile::box_filter_point // Access: Private -// Description: +// Description: //////////////////////////////////////////////////////////////////// void PfmFile:: box_filter_point(LPoint4f &result, PN_float32 &coverage, @@ -2611,7 +2708,7 @@ box_filter_point(LPoint4f &result, PN_float32 &coverage, // with the index to the nearest value. //////////////////////////////////////////////////////////////////// void PfmFile:: -fill_mini_grid(MiniGridCell *mini_grid, int x_size, int y_size, +fill_mini_grid(MiniGridCell *mini_grid, int x_size, int y_size, int xi, int yi, int dist, int sxi, int syi) const { if (xi < 0 || xi >= x_size || yi < 0 || yi >= y_size) { // Out of bounds. @@ -2634,12 +2731,12 @@ fill_mini_grid(MiniGridCell *mini_grid, int x_size, int y_size, //////////////////////////////////////////////////////////////////// // Function: PfmFile::has_point_noop // Access: Private, Static -// Description: The implementation of has_point() for +// Description: The implementation of has_point() for // files without a no_data_value. //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_noop(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { return true; } @@ -2654,7 +2751,7 @@ has_point_noop(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_1(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { return self->_table[(y * self->_x_size + x)] != self->_no_data_value[0]; } @@ -2669,7 +2766,7 @@ has_point_1(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_2(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { return *(LPoint2f *)&self->_table[(y * self->_x_size + x) * 2] != *(LPoint2f *)&self->_no_data_value; } @@ -2684,7 +2781,7 @@ has_point_2(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_3(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { return *(LPoint3f *)&self->_table[(y * self->_x_size + x) * 3] != *(LPoint3f *)&self->_no_data_value; } @@ -2699,7 +2796,7 @@ has_point_3(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_4(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { return *(LPoint4f *)&self->_table[(y * self->_x_size + x) * 4] != *(LPoint4f *)&self->_no_data_value; } @@ -2714,7 +2811,7 @@ has_point_4(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_threshold_1(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { const float *table = &self->_table[(y * self->_x_size + x)]; return table[0] >= self->_no_data_value[0]; @@ -2730,7 +2827,7 @@ has_point_threshold_1(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_threshold_2(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { const float *table = &self->_table[(y * self->_x_size + x) * 2]; return (table[0] >= self->_no_data_value[0] || @@ -2747,7 +2844,7 @@ has_point_threshold_2(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_threshold_3(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { const float *table = &self->_table[(y * self->_x_size + x) * 3]; return (table[0] >= self->_no_data_value[0] || @@ -2765,7 +2862,7 @@ has_point_threshold_3(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_threshold_4(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { const float *table = &self->_table[(y * self->_x_size + x) * 4]; return (table[0] >= self->_no_data_value[0] || @@ -2785,7 +2882,7 @@ has_point_threshold_4(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_chan4(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { return self->_table[(y * self->_x_size + x) * 4 + 3] >= 0.0; } @@ -2795,13 +2892,13 @@ has_point_chan4(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// // Function: PfmFile::has_point_nan_1 // Access: Private, Static -// Description: The implementation of has_point() for +// Description: The implementation of has_point() for // files with set_no_data_nan() in effect. This means // that the data is valid iff no components involve NaN. //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_nan_1(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { return !cnan(self->_table[(y * self->_x_size + x) * self->_num_channels]); } @@ -2811,13 +2908,13 @@ has_point_nan_1(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// // Function: PfmFile::has_point_nan_2 // Access: Private, Static -// Description: The implementation of has_point() for +// Description: The implementation of has_point() for // files with set_no_data_nan() in effect. This means // that the data is valid iff no components involve NaN. //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_nan_2(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { return !((LVecBase2f *)&self->_table[(y * self->_x_size + x) * self->_num_channels])->is_nan(); } @@ -2827,13 +2924,13 @@ has_point_nan_2(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// // Function: PfmFile::has_point_nan_3 // Access: Private, Static -// Description: The implementation of has_point() for +// Description: The implementation of has_point() for // files with set_no_data_nan() in effect. This means // that the data is valid iff no components involve NaN. //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_nan_3(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { return !((LVecBase3f *)&self->_table[(y * self->_x_size + x) * self->_num_channels])->is_nan(); } @@ -2843,13 +2940,13 @@ has_point_nan_3(const PfmFile *self, int x, int y) { //////////////////////////////////////////////////////////////////// // Function: PfmFile::has_point_nan_4 // Access: Private, Static -// Description: The implementation of has_point() for +// Description: The implementation of has_point() for // files with set_no_data_nan() in effect. This means // that the data is valid iff no components involve NaN. //////////////////////////////////////////////////////////////////// bool PfmFile:: has_point_nan_4(const PfmFile *self, int x, int y) { - if ((x >= 0 && x < self->_x_size) && + if ((x >= 0 && x < self->_x_size) && (y >= 0 && y < self->_y_size)) { return !((LVecBase4f *)&self->_table[(y * self->_x_size + x) * self->_num_channels])->is_nan(); } diff --git a/panda/src/pnmimage/pfmFile.h b/panda/src/pnmimage/pfmFile.h index 0249b71331..ab0347f739 100644 --- a/panda/src/pnmimage/pfmFile.h +++ b/panda/src/pnmimage/pfmFile.h @@ -123,6 +123,7 @@ PUBLISHED: 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 apply_mask(const PfmFile &other); BLOCKING void copy_channel(int to_channel, const PfmFile &other, int from_channel); BLOCKING void copy_channel_masked(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); @@ -155,6 +156,13 @@ PUBLISHED: void operator *= (float multiplier); + INLINE void gamma_correct(float from_gamma, float to_gamma); + INLINE void gamma_correct_alpha(float from_gamma, float to_gamma); + INLINE void apply_exponent(float gray_exponent); + INLINE void apply_exponent(float gray_exponent, float alpha_exponent); + INLINE void apply_exponent(float c0_exponent, float c1_exponent, float c2_exponent); + void apply_exponent(float c0_exponent, float c1_exponent, float c2_exponent, float c3_exponent); + void output(ostream &out) const; EXTENSION(PyObject *get_points() const); @@ -204,7 +212,7 @@ private: int _dist; }; - void fill_mini_grid(MiniGridCell *mini_grid, int x_size, int y_size, + void fill_mini_grid(MiniGridCell *mini_grid, int x_size, int y_size, int xi, int yi, int dist, int sxi, int syi) const; static bool has_point_noop(const PfmFile *file, int x, int y); diff --git a/panda/src/pnmimage/pnmImage.cxx b/panda/src/pnmimage/pnmImage.cxx index 692e26b11d..b4b98ad6c8 100644 --- a/panda/src/pnmimage/pnmImage.cxx +++ b/panda/src/pnmimage/pnmImage.cxx @@ -152,6 +152,57 @@ copy_channel(const PNMImage ©, int src_channel, int dest_channel) { } } +//////////////////////////////////////////////////////////////////// +// Function: PNMImage::copy_channel_bits +// Access: Published +// Description: Copies some subset of the bits of the specified +// channel from one image into some subset of the bits +// of the specified channel in another image. Images +// must be the same size. +// +// If right_shift is negative, it means a left shift. +//////////////////////////////////////////////////////////////////// +void PNMImage:: +copy_channel_bits(const PNMImage ©, int src_channel, int dest_channel, xelval src_mask, int right_shift) { + // Make sure the channels are in range + nassertv(src_channel >= 0 && src_channel <= 3); + nassertv(dest_channel >= 0 && dest_channel <= 3); + // Make sure that images are valid + if (!copy.is_valid() || !is_valid()) { + pnmimage_cat.error() << "One of the images is invalid!\n"; + return; + } + // Make sure the images are the same size + if (_x_size != copy.get_x_size() || _y_size != copy.get_y_size()){ + pnmimage_cat.error() << "Image size doesn't match!\n"; + return; + } + + // Do the actual copying. + if (right_shift >= 0) { + xelval dest_mask = ~(src_mask >> right_shift); + for (int x = 0; x < _x_size; x++) { + for (int y = 0; y < _y_size; y++) { + xelval src = copy.get_channel_val(x, y, src_channel); + xelval dest = get_channel_val(x, y, dest_channel); + dest = (dest & dest_mask) | ((src & src_mask) >> right_shift); + set_channel_val(x, y, dest_channel, dest); + } + } + } else { + int left_shift = -right_shift; + xelval dest_mask = ~(src_mask << left_shift); + for (int x = 0; x < _x_size; x++) { + for (int y = 0; y < _y_size; y++) { + xelval src = copy.get_channel_val(x, y, src_channel); + xelval dest = get_channel_val(x, y, dest_channel); + dest = (dest & dest_mask) | ((src & src_mask) << left_shift); + set_channel_val(x, y, dest_channel, dest); + } + } + } +} + //////////////////////////////////////////////////////////////////// // Function: PNMImage::copy_header_from // Access: Published @@ -165,6 +216,12 @@ copy_header_from(const PNMImageHeader &header) { clear(); PNMImageHeader::operator = (header); + if (_maxval == 0) { + _inv_maxval = 0.0f; + } else { + _inv_maxval = 1.0f / (float)_maxval; + } + if (has_alpha()) { allocate_alpha(); } @@ -1708,7 +1765,7 @@ rescale(float min_val, float max_val) { for (int y = 0; y < get_y_size(); y++) { for (int x = 0; x < get_x_size(); x++) { LRGBColorf xel = get_xel(x, y); - set_xel(x, y, + set_xel(x, y, (xel[0] - min_val) / scale, (xel[1] - min_val) / scale, (xel[2] - min_val) / scale); @@ -1899,7 +1956,7 @@ unfiltered_stretch_from(const PNMImage ©) { } } - if (has_alpha() && copy.has_alpha()) { + if (has_alpha() && copy.has_alpha()) { for (int yt = 0; yt < get_y_size(); yt++) { int ys = yt * copy.get_y_size() / get_y_size(); for (int xt = 0; xt < get_x_size(); xt++) { diff --git a/panda/src/pnmimage/pnmImage.h b/panda/src/pnmimage/pnmImage.h index b01d5ec974..dd75fda118 100644 --- a/panda/src/pnmimage/pnmImage.h +++ b/panda/src/pnmimage/pnmImage.h @@ -90,6 +90,7 @@ PUBLISHED: void copy_from(const PNMImage ©); void copy_channel(const PNMImage ©, int src_channel, int dest_channel); + void copy_channel_bits(const PNMImage ©, int src_channel, int dest_channel, xelval src_mask, int right_shift); void copy_header_from(const PNMImageHeader &header); void take_from(PNMImage &orig); diff --git a/panda/src/pnmimage/pnmImageHeader.I b/panda/src/pnmimage/pnmImageHeader.I index 0e22848fdd..18d7d5b3df 100644 --- a/panda/src/pnmimage/pnmImageHeader.I +++ b/panda/src/pnmimage/pnmImageHeader.I @@ -255,7 +255,7 @@ set_type(PNMFileType *type) { // Description: Records the indicated color in the histogram. //////////////////////////////////////////////////////////////////// INLINE void PNMImageHeader:: -record_color(PNMImageHeader::HistMap &hist, +record_color(PNMImageHeader::HistMap &hist, const PNMImageHeader::PixelSpec &color) { // First, try to add the color with a count of 0, in case it does // not already exist in the table. @@ -270,7 +270,7 @@ record_color(PNMImageHeader::HistMap &hist, //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE PNMImageHeader::PixelSpec:: PixelSpec(xelval gray_value) : @@ -284,7 +284,7 @@ PixelSpec(xelval gray_value) : //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE PNMImageHeader::PixelSpec:: PixelSpec(xelval gray_value, xelval alpha) : @@ -298,7 +298,7 @@ PixelSpec(xelval gray_value, xelval alpha) : //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE PNMImageHeader::PixelSpec:: PixelSpec(xelval red, xelval green, xelval blue) : @@ -312,7 +312,7 @@ PixelSpec(xelval red, xelval green, xelval blue) : //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE PNMImageHeader::PixelSpec:: PixelSpec(xelval red, xelval green, xelval blue, xelval alpha) : @@ -326,7 +326,7 @@ PixelSpec(xelval red, xelval green, xelval blue, xelval alpha) : //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE PNMImageHeader::PixelSpec:: PixelSpec(const xel &rgb) : @@ -340,7 +340,7 @@ PixelSpec(const xel &rgb) : //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE PNMImageHeader::PixelSpec:: PixelSpec(const xel &rgb, xelval alpha) : @@ -354,7 +354,7 @@ PixelSpec(const xel &rgb, xelval alpha) : //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::Copy Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE PNMImageHeader::PixelSpec:: PixelSpec(const PixelSpec ©) : @@ -368,7 +368,7 @@ PixelSpec(const PixelSpec ©) : //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::Copy Assignment Operator // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE void PNMImageHeader::PixelSpec:: operator = (const PixelSpec ©) { @@ -381,7 +381,7 @@ operator = (const PixelSpec ©) { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::operator < // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE bool PNMImageHeader::PixelSpec:: operator < (const PixelSpec &other) const { @@ -391,7 +391,7 @@ operator < (const PixelSpec &other) const { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::operator == // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE bool PNMImageHeader::PixelSpec:: operator == (const PixelSpec &other) const { @@ -401,7 +401,7 @@ operator == (const PixelSpec &other) const { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::operator != // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE bool PNMImageHeader::PixelSpec:: operator != (const PixelSpec &other) const { @@ -411,7 +411,7 @@ operator != (const PixelSpec &other) const { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::compare_to // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE int PNMImageHeader::PixelSpec:: compare_to(const PixelSpec &other) const { @@ -433,7 +433,7 @@ compare_to(const PixelSpec &other) const { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::get_red // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE xelval PNMImageHeader::PixelSpec:: get_red() const { @@ -443,7 +443,7 @@ get_red() const { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::get_green // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE xelval PNMImageHeader::PixelSpec:: get_green() const { @@ -453,7 +453,7 @@ get_green() const { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::get_blue // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE xelval PNMImageHeader::PixelSpec:: get_blue() const { @@ -463,7 +463,7 @@ get_blue() const { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::get_alpha // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE xelval PNMImageHeader::PixelSpec:: get_alpha() const { @@ -473,7 +473,7 @@ get_alpha() const { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::set_red // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE void PNMImageHeader::PixelSpec:: set_red(xelval red) { @@ -483,7 +483,7 @@ set_red(xelval red) { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::set_green // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE void PNMImageHeader::PixelSpec:: set_green(xelval green) { @@ -493,7 +493,7 @@ set_green(xelval green) { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::set_blue // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE void PNMImageHeader::PixelSpec:: set_blue(xelval blue) { @@ -503,7 +503,7 @@ set_blue(xelval blue) { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpec::set_alpha // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE void PNMImageHeader::PixelSpec:: set_alpha(xelval alpha) { @@ -541,7 +541,7 @@ size() { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::PixelSpecCount::Constructor // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE PNMImageHeader::PixelSpecCount:: PixelSpecCount(const PNMImageHeader::PixelSpec &pixel, int count) : @@ -565,7 +565,7 @@ operator < (const PNMImageHeader::PixelSpecCount &other) const { //////////////////////////////////////////////////////////////////// // Function: PNMImageHeader::Histogram::Constructor // Access: Published -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE PNMImageHeader::Histogram:: Histogram() {