diff --git a/panda/src/distort/projectionScreen.cxx b/panda/src/distort/projectionScreen.cxx index f8b62d0deb..26d0e2deb4 100644 --- a/panda/src/distort/projectionScreen.cxx +++ b/panda/src/distort/projectionScreen.cxx @@ -593,17 +593,13 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) { LPoint3 uvw = film * to_uv; if (good && _has_undist_lut) { - int x_size = _undist_lut.get_x_size(); - int y_size = _undist_lut.get_y_size(); - - int dist_xi = (int)cfloor(uvw[0] * (PN_float32)x_size); - int dist_yi = (int)cfloor(uvw[1] * (PN_float32)y_size); - if (!_undist_lut.has_point(dist_xi, y_size - 1 - dist_yi)) { + LPoint3 p; + if (!_undist_lut.calc_bilinear_point(p, uvw[0], 1.0 - uvw[1])) { // Point is missing. uvw.set(0, 0, 0); good = false; } else { - uvw = _undist_lut.get_point(dist_xi, y_size - 1 - dist_yi); + uvw = p; uvw[1] = 1.0 - uvw[1]; } } @@ -767,17 +763,13 @@ make_mesh_geom(const Geom *geom, Lens *lens, LMatrix4 &rel_mat) { // Rescale these to [0, 1]. LPoint3 uvw = film * lens_to_uv; - int x_size = _undist_lut.get_x_size(); - int y_size = _undist_lut.get_y_size(); - - int dist_xi = (int)cfloor(uvw[0] * (PN_float32)x_size); - int dist_yi = (int)cfloor(uvw[1] * (PN_float32)y_size); - if (!_undist_lut.has_point(dist_xi, y_size - 1 - dist_yi)) { + LPoint3 p; + if (!_undist_lut.calc_bilinear_point(p, uvw[0], 1.0 - uvw[1])) { // Point is missing. uvw.set(0, 0, 0); good = false; } else { - uvw = _undist_lut.get_point(dist_xi, y_size - 1 - dist_yi); + uvw = p; uvw[1] = 1.0 - uvw[1]; } diff --git a/panda/src/grutil/pfmVizzer.cxx b/panda/src/grutil/pfmVizzer.cxx index 7e91aad19f..8048bbeb2a 100644 --- a/panda/src/grutil/pfmVizzer.cxx +++ b/panda/src/grutil/pfmVizzer.cxx @@ -1022,17 +1022,13 @@ transform_point(LPoint3f &point) const { } if (_undist_lut != NULL) { - int x_size = _undist_lut->get_x_size(); - int y_size = _undist_lut->get_y_size(); - - int dist_xi = (int)cfloor(point[0] * (PN_float32)x_size); - int dist_yi = (int)cfloor(point[1] * (PN_float32)y_size); - if (!_undist_lut->has_point(dist_xi, y_size - 1 - dist_yi)) { + LPoint3 p; + if (!_undist_lut->calc_bilinear_point(p, point[0], 1.0 - point[1])) { // Point is missing. point.set(0, 0, 0); success = false; } else { - point = _undist_lut->get_point(dist_xi, y_size - 1 - dist_yi); + point = p; point[1] = 1.0 - point[1]; } } diff --git a/panda/src/pnmimage/pfmFile.I b/panda/src/pnmimage/pfmFile.I index 7fc18a5528..18a6f39a68 100644 --- a/panda/src/pnmimage/pfmFile.I +++ b/panda/src/pnmimage/pfmFile.I @@ -196,9 +196,7 @@ modify_point2(int x, int y) { //////////////////////////////////////////////////////////////////// INLINE const LPoint3f &PfmFile:: get_point(int x, int y) const { - nassertr(x >= 0 && x < _x_size && - y >= 0 && y < _y_size, LPoint3f::zero()); - return *(LPoint3f *)&_table[(y * _x_size + x) * _num_channels]; + return get_point3(x, y); } //////////////////////////////////////////////////////////////////// @@ -210,6 +208,55 @@ get_point(int x, int y) const { //////////////////////////////////////////////////////////////////// INLINE void PfmFile:: set_point(int x, int y, const LVecBase3f &point) { + set_point3(x, y, point); +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::set_point +// Access: Published +// Description: Replaces the 3-component point value at the indicated +// point. In a 1-channel image, the channel value is in +// the x component. +//////////////////////////////////////////////////////////////////// +INLINE void PfmFile:: +set_point(int x, int y, const LVecBase3d &point) { + set_point3(x, y, point); +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::modify_point +// Access: Published +// Description: Returns a modifiable 3-component point value at the +// indicated point. +//////////////////////////////////////////////////////////////////// +INLINE LPoint3f &PfmFile:: +modify_point(int x, int y) { + return modify_point3(x, y); +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::get_point3 +// Access: Published +// Description: Returns the 3-component point value at the indicated +// point. In a 1-channel image, the channel value is in +// the x component. +//////////////////////////////////////////////////////////////////// +INLINE const LPoint3f &PfmFile:: +get_point3(int x, int y) const { + nassertr(x >= 0 && x < _x_size && + y >= 0 && y < _y_size, LPoint3f::zero()); + return *(LPoint3f *)&_table[(y * _x_size + x) * _num_channels]; +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::set_point3 +// Access: Published +// Description: Replaces the 3-component point value at the indicated +// point. In a 1-channel image, the channel value is in +// the x component. +//////////////////////////////////////////////////////////////////// +INLINE void PfmFile:: +set_point3(int x, int y, const LVecBase3f &point) { nassertv(!point.is_nan()); nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size); @@ -233,25 +280,25 @@ set_point(int x, int y, const LVecBase3f &point) { } //////////////////////////////////////////////////////////////////// -// Function: PfmFile::set_point +// Function: PfmFile::set_point3 // Access: Published // Description: Replaces the 3-component point value at the indicated // point. In a 1-channel image, the channel value is in // the x component. //////////////////////////////////////////////////////////////////// INLINE void PfmFile:: -set_point(int x, int y, const LVecBase3d &point) { - set_point(x, y, LCAST(PN_float32, point)); +set_point3(int x, int y, const LVecBase3d &point) { + set_point3(x, y, LCAST(PN_float32, point)); } //////////////////////////////////////////////////////////////////// -// Function: PfmFile::modify_point +// Function: PfmFile::modify_point3 // Access: Published // Description: Returns a modifiable 3-component point value at the // indicated point. //////////////////////////////////////////////////////////////////// INLINE LPoint3f &PfmFile:: -modify_point(int x, int y) { +modify_point3(int x, int y) { #ifndef NDEBUG static LPoint3f dummy_value = LPoint3f::zero(); nassertr(x >= 0 && x < _x_size && diff --git a/panda/src/pnmimage/pfmFile.cxx b/panda/src/pnmimage/pfmFile.cxx index c6decbf218..1e5dfa9ffc 100644 --- a/panda/src/pnmimage/pfmFile.cxx +++ b/panda/src/pnmimage/pfmFile.cxx @@ -610,6 +610,56 @@ calc_average_point(LPoint3f &result, PN_float32 x, PN_float32 y, PN_float32 radi return true; } +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::calc_bilinear_point +// Access: Published +// Description: Computes the weighted average of the four nearest +// points to the floating-point index (x, y). Returns +// true if the point has any contributors, false if the +// point is unknown. +//////////////////////////////////////////////////////////////////// +bool PfmFile:: +calc_bilinear_point(LPoint3f &result, PN_float32 x, PN_float32 y) const { + result = LPoint3f::zero(); + + x *= _x_size; + y *= _y_size; + + int min_x = int(floor(x)); + int min_y = int(floor(y)); + + PN_float32 frac_x = x - min_x; + PN_float32 frac_y = y - min_y; + + LPoint3f p00, p01, p10, p11; + PN_float32 w00 = 0.0, w01 = 0.0, w10 = 0.0, w11 = 0.0; + + if (has_point(min_x, min_y)) { + w00 = (1.0 - frac_y) * (1.0 - frac_x); + p00 = get_point(min_x, min_y); + } + if (has_point(min_x + 1, min_y)) { + w10 = (1.0 - frac_y) * frac_x; + p10 = get_point(min_x + 1, min_y); + } + if (has_point(min_x, min_y + 1)) { + w01 = frac_y * (1.0 - frac_x); + p01 = get_point(min_x, min_y + 1); + } + if (has_point(min_x + 1, min_y + 1)) { + w11 = frac_y * frac_x; + p11 = get_point(min_x + 1, min_y + 1); + } + + PN_float32 net_w = w00 + w01 + w10 + w11; + if (net_w == 0.0) { + return false; + } + + result = (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11) / net_w; + return true; +} + //////////////////////////////////////////////////////////////////// // Function: PfmFile::calc_min_max // Access: Published @@ -1093,14 +1143,12 @@ forward_distort(const PfmFile &dist, PN_float32 scale_factor) { if (!dist_p->has_point(xi, yi)) { continue; } - LPoint2f uv = dist_p->get_point2(xi, yi); - 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 (!source_p->has_point(dist_xi, working_y_size - 1 - dist_yi)) { + LPoint2 uv = dist_p->get_point2(xi, yi); + LPoint3 p; + if (!calc_bilinear_point(p, uv[0], 1.0 - uv[1])) { continue; } - - result.set_point(xi, working_y_size - 1 - yi, source_p->get_point(dist_xi, working_y_size - 1 - dist_yi)); + result.set_point(xi, working_y_size - 1 - yi, p); } } @@ -1302,8 +1350,8 @@ clear_to_texcoords(int x_size, int y_size) { for (int yi = 0; yi < _y_size; ++yi) { for (int xi = 0; xi < _x_size; ++xi) { - LPoint3f uv(PN_float32(xi) * uv_scale[0] + 0.5, - PN_float32(yi) * uv_scale[1] + 0.5, + LPoint3f uv((PN_float32(xi) + 0.5) * uv_scale[0], + (PN_float32(yi) + 0.5) * uv_scale[1], 0.0f); set_point(xi, yi, uv); } diff --git a/panda/src/pnmimage/pfmFile.h b/panda/src/pnmimage/pfmFile.h index 99f1fed955..7bc4a442ab 100644 --- a/panda/src/pnmimage/pfmFile.h +++ b/panda/src/pnmimage/pfmFile.h @@ -69,6 +69,10 @@ PUBLISHED: INLINE void set_point(int x, int y, const LVecBase3f &point); INLINE void set_point(int x, int y, const LVecBase3d &point); INLINE LPoint3f &modify_point(int x, int y); + INLINE const LPoint3f &get_point3(int x, int y) const; + INLINE void set_point3(int x, int y, const LVecBase3f &point); + INLINE void set_point3(int x, int y, const LVecBase3d &point); + INLINE LPoint3f &modify_point3(int x, int y); INLINE const LPoint4f &get_point4(int x, int y) const; INLINE void set_point4(int x, int y, const LVecBase4f &point); INLINE void set_point4(int x, int y, const LVecBase4d &point); @@ -80,6 +84,7 @@ PUBLISHED: 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_bilinear_point(LPoint3f &result, PN_float32 x, PN_float32 y) 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; BLOCKING INLINE bool calc_autocrop(LVecBase4f &range) const;