diff --git a/panda/src/grutil/pfmFile.I b/panda/src/grutil/pfmFile.I index 938acb5d00..1ef556cd5a 100755 --- a/panda/src/grutil/pfmFile.I +++ b/panda/src/grutil/pfmFile.I @@ -132,6 +132,23 @@ modify_point(int x, int y) { return _table[y * _x_size + x]; } +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::calc_autocrop +// Access: Published +// Description: Computes the minimum range of x and y across the PFM +// file that include all points. If there are no points +// with no_data_value in the grid--that is, all points +// are included--then this will return (0, get_x_size(), +// 0, get_y_size()). +//////////////////////////////////////////////////////////////////// +INLINE bool PfmFile:: +calc_autocrop(LVecBase4 &range) const { + int x_begin, x_end, y_begin, y_end; + bool result = calc_autocrop(x_begin, x_end, y_begin, y_end); + range.set(x_begin, x_end, y_begin, y_end); + return result; +} + //////////////////////////////////////////////////////////////////// // Function: PfmFile::set_zero_special // Access: Published diff --git a/panda/src/grutil/pfmFile.cxx b/panda/src/grutil/pfmFile.cxx index e47238d737..643ca9058e 100755 --- a/panda/src/grutil/pfmFile.cxx +++ b/panda/src/grutil/pfmFile.cxx @@ -564,6 +564,97 @@ calc_min_max(LVecBase3 &min_depth, LVecBase3 &max_depth) const { return any_points; } +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::calc_autocrop +// Access: Published +// Description: Computes the minimum range of x and y across the PFM +// file that include all points. If there are no points +// with no_data_value in the grid--that is, all points +// are included--then this will return (0, get_x_size(), +// 0, get_y_size()). +//////////////////////////////////////////////////////////////////// +bool PfmFile:: +calc_autocrop(int &x_begin, int &x_end, int &y_begin, int &y_end) const { + y_begin = 0; + while (is_row_empty(y_begin, 0, _x_size)) { + ++y_begin; + if (y_begin >= _y_size) { + // We've reached the end; the entire grid is empty. + x_begin = x_end = y_begin = y_end = 0; + return false; + } + } + + y_end = _y_size; + while (is_row_empty(y_end - 1, 0, _x_size)) { + --y_end; + nassertr(y_end > y_begin, false); + } + + // Now we've got the top and bottom bounds. + x_begin = 0; + while (is_column_empty(x_begin, y_begin, y_end)) { + ++x_begin; + nassertr(x_begin < _x_size, false); + } + + x_end = _x_size; + while (is_column_empty(x_end - 1, y_begin, y_end)) { + --x_end; + nassertr(x_end > x_begin, false); + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::is_row_empty +// Access: Published +// Description: Returns true if all of the points on row y, in the range +// [x_begin, x_end), are the no_data value, or false if +// any one of these points has a value. +//////////////////////////////////////////////////////////////////// +bool PfmFile:: +is_row_empty(int y, int x_begin, int x_end) const { + nassertr(y >= 0 && y < _y_size && + x_begin >= 0 && x_begin <= x_end && x_end <= _x_size, false); + + if (!_has_no_data_value) { + return false; + } + for (int x = x_begin; x < x_end; ++x) { + if (_table[y * _x_size + x] != _no_data_value) { + return false; + } + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::is_column_empty +// Access: Published +// Description: Returns true if all of the points on column x, from +// [y_begin, y_end), are the no_data value, or false if +// any one of these points has a value. +//////////////////////////////////////////////////////////////////// +bool PfmFile:: +is_column_empty(int x, int y_begin, int y_end) const { + nassertr(x >= 0 && x < _x_size && + y_begin >= 0 && y_begin <= y_end && y_end <= _y_size, false); + + if (!_has_no_data_value) { + return false; + } + for (int y = y_begin; y < y_end; ++y) { + if (_table[y * _x_size + x] != _no_data_value) { + return false; + } + } + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: PfmFile::resize // Access: Published @@ -772,6 +863,35 @@ merge(const PfmFile &other) { } } +//////////////////////////////////////////////////////////////////// +// Function: PfmFile::apply_crop +// Access: Published +// Description: Reduces the PFM file to the cells in the rectangle +// bounded by (x_begin, x_end, y_begin, y_end), where +// the _end cells are not included. +//////////////////////////////////////////////////////////////////// +void PfmFile:: +apply_crop(int x_begin, int x_end, int y_begin, int y_end) { + nassertv(x_begin >= 0 && x_begin <= x_end && x_end <= _x_size); + nassertv(y_begin >= 0 && y_begin <= y_end && y_end <= _y_size); + + int new_x_size = x_end - x_begin; + int new_y_size = y_end - y_begin; + Table new_table; + int new_size = new_x_size * new_y_size; + new_table.insert(new_table.end(), new_size, LPoint3::zero()); + + for (int yi = 0; yi < new_y_size; ++yi) { + memcpy(&new_table[yi * new_x_size], + &_table[(yi + y_begin) * _x_size + x_begin], + new_x_size * sizeof(LPoint3)); + } + + _table.swap(new_table); + _x_size = new_x_size; + _y_size = new_y_size; +} + //////////////////////////////////////////////////////////////////// // Function: PfmFile::compute_planar_bounds // Access: Published diff --git a/panda/src/grutil/pfmFile.h b/panda/src/grutil/pfmFile.h index 6646889b12..b7e34b8580 100755 --- a/panda/src/grutil/pfmFile.h +++ b/panda/src/grutil/pfmFile.h @@ -62,6 +62,11 @@ PUBLISHED: BLOCKING bool calc_average_point(LPoint3 &result, PN_stdfloat x, PN_stdfloat y, PN_stdfloat radius) const; BLOCKING bool calc_min_max(LVecBase3 &min_points, LVecBase3 &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(LVecBase4 &range) const; + + bool is_row_empty(int y, int x_begin, int x_end) const; + bool is_column_empty(int x, int y_begin, int y_end) const; INLINE void set_zero_special(bool zero_special); INLINE void set_no_data_value(const LPoint3 &no_data_value); @@ -75,6 +80,7 @@ PUBLISHED: BLOCKING void xform(const LMatrix4 &transform); BLOCKING void project(const Lens *lens); BLOCKING void merge(const PfmFile &other); + BLOCKING void apply_crop(int x_begin, int x_end, int y_begin, int y_end); BLOCKING PT(BoundingHexahedron) compute_planar_bounds(PN_stdfloat point_dist, PN_stdfloat sample_radius) const; BLOCKING PT(BoundingHexahedron) compute_planar_bounds(const LPoint2 ¢er, PN_stdfloat point_dist, PN_stdfloat sample_radius, bool points_only) const; diff --git a/pandatool/src/pfmprogs/pfmTrans.cxx b/pandatool/src/pfmprogs/pfmTrans.cxx index 587cf7a109..4917dc1b01 100755 --- a/pandatool/src/pfmprogs/pfmTrans.cxx +++ b/pandatool/src/pfmprogs/pfmTrans.cxx @@ -53,6 +53,17 @@ PfmTrans() { "change the number of points.", &PfmTrans::dispatch_int_pair, &_got_resize, &_resize); + add_option + ("crop", "xbegin,xend,ybegin,yend", 0, + "Crops the pfm file to the indicated subregion.", + &PfmTrans::dispatch_int_quad, &_got_crop, &_crop); + + add_option + ("autocrop", "", 0, + "Automatically crops to the smallest possible rectangle that includes " + "all points. Requires -z.", + &PfmTrans::dispatch_none, &_got_autocrop); + add_option ("rotate", "degrees", 0, "Rotates the pfm file the specified number of degrees counterclockwise, " @@ -153,6 +164,14 @@ process_pfm(const Filename &input_filename, PfmFile &file) { file.set_vis_inverse(_got_vis_inverse); file.set_vis_2d(_got_vis_2d); + if (_got_autocrop) { + _got_crop = file.calc_autocrop(_crop[0], _crop[1], _crop[2], _crop[3]); + } + + if (_got_crop) { + file.apply_crop(_crop[0], _crop[1], _crop[2], _crop[3]); + } + if (_got_resize) { file.resize(_resize[0], _resize[1]); } diff --git a/pandatool/src/pfmprogs/pfmTrans.h b/pandatool/src/pfmprogs/pfmTrans.h index 67eabf66e4..e9a151e059 100755 --- a/pandatool/src/pfmprogs/pfmTrans.h +++ b/pandatool/src/pfmprogs/pfmTrans.h @@ -56,6 +56,9 @@ private: bool _got_vis_2d; bool _got_resize; int _resize[2]; + bool _got_crop; + int _crop[4]; + bool _got_autocrop; int _rotate; bool _got_mirror_x; bool _got_mirror_y; diff --git a/pandatool/src/progbase/programBase.cxx b/pandatool/src/progbase/programBase.cxx index c5f3051748..5b906b72d2 100644 --- a/pandatool/src/progbase/programBase.cxx +++ b/pandatool/src/progbase/programBase.cxx @@ -830,6 +830,38 @@ dispatch_int_pair(const string &opt, const string &arg, void *var) { return true; } +//////////////////////////////////////////////////////////////////// +// Function: ProgramBase::dispatch_int_quad +// Access: Protected, Static +// Description: Standard dispatch function for an option that takes +// a quad of integer parameters. The data pointer is to +// an array of four integers. +//////////////////////////////////////////////////////////////////// +bool ProgramBase:: +dispatch_int_quad(const string &opt, const string &arg, void *var) { + int *ip = (int *)var; + + vector_string words; + tokenize(arg, words, ","); + + bool okflag = false; + if (words.size() == 4) { + okflag = + string_to_int(words[0], ip[0]) && + string_to_int(words[1], ip[1]) && + string_to_int(words[1], ip[2]) && + string_to_int(words[1], ip[3]); + } + + if (!okflag) { + nout << "-" << opt + << " requires a quad of integers separated by a comma.\n"; + return false; + } + + return true; +} + //////////////////////////////////////////////////////////////////// // Function: ProgramBase::dispatch_double // Access: Protected, Static diff --git a/pandatool/src/progbase/programBase.h b/pandatool/src/progbase/programBase.h index c84c8e4742..1f2ddcb664 100644 --- a/pandatool/src/progbase/programBase.h +++ b/pandatool/src/progbase/programBase.h @@ -87,6 +87,7 @@ protected: static bool dispatch_count(const string &opt, const string &arg, void *var); static bool dispatch_int(const string &opt, const string &arg, void *var); static bool dispatch_int_pair(const string &opt, const string &arg, void *var); + static bool dispatch_int_quad(const string &opt, const string &arg, void *var); static bool dispatch_double(const string &opt, const string &arg, void *var); static bool dispatch_double_pair(const string &opt, const string &arg, void *var); static bool dispatch_double_triple(const string &opt, const string &arg, void *var);