support for 4-channel pfm files

This commit is contained in:
David Rose 2012-07-23 02:10:21 +00:00
parent bd6100bcab
commit 8cc85e4024
4 changed files with 591 additions and 308 deletions

View File

@ -20,7 +20,7 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE bool PfmFile:: INLINE bool PfmFile::
is_valid() const { is_valid() const {
return _num_channels != 0 && (_x_size * _y_size == (int)_table.size()); return _num_channels != 0 && (_x_size * _y_size * _num_channels == (int)_table.size());
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -49,7 +49,7 @@ get_y_size() const {
// Description: The "scale" is reported in the pfm header and is // Description: The "scale" is reported in the pfm header and is
// probably meaningless. // probably meaningless.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat PfmFile:: INLINE PN_float32 PfmFile::
get_scale() const { get_scale() const {
return _scale; return _scale;
} }
@ -79,11 +79,7 @@ get_num_channels() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE bool PfmFile:: INLINE bool PfmFile::
has_point(int x, int y) const { has_point(int x, int y) const {
if ((x >= 0 && x < _x_size) && return _has_point(this, x, y);
(y >= 0 && y < _y_size)) {
return (!_has_no_data_value || _table[y * _x_size + x] != _no_data_value);
}
return false;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -93,11 +89,11 @@ has_point(int x, int y) const {
// point. In a 1-channel image, the channel value is in // point. In a 1-channel image, the channel value is in
// the x component. // the x component.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE const LPoint3 &PfmFile:: INLINE const LPoint3f &PfmFile::
get_point(int x, int y) const { get_point(int x, int y) const {
nassertr(x >= 0 && x < _x_size, LPoint3::zero()); nassertr(x >= 0 && x < _x_size, LPoint3f::zero());
nassertr(y >= 0 && y < _y_size, LPoint3::zero()); nassertr(y >= 0 && y < _y_size, LPoint3f::zero());
return _table[y * _x_size + x]; return *(LPoint3f *)&_table[(y * _x_size + x) * _num_channels];
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -108,11 +104,20 @@ get_point(int x, int y) const {
// the x component. // the x component.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE void PfmFile:: INLINE void PfmFile::
set_point(int x, int y, const LVecBase3 &point) { set_point(int x, int y, const LVecBase3f &point) {
nassertv(!point.is_nan()); nassertv(!point.is_nan());
nassertv(x >= 0 && x < _x_size); nassertv(x >= 0 && x < _x_size);
nassertv(y >= 0 && y < _y_size); nassertv(y >= 0 && y < _y_size);
_table[y * _x_size + x] = point; switch (_num_channels) {
case 1:
_table[(y * _x_size + x)] = point[0];
break;
case 3:
case 4:
*(LPoint3f *)&_table[(y * _x_size + x) * _num_channels] = point;
break;
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -121,15 +126,73 @@ set_point(int x, int y, const LVecBase3 &point) {
// Description: Returns a modifiable 3-component point value at the // Description: Returns a modifiable 3-component point value at the
// indicated point. // indicated point.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE LPoint3 &PfmFile:: INLINE LPoint3f &PfmFile::
modify_point(int x, int y) { modify_point(int x, int y) {
#ifndef NDEBUG #ifndef NDEBUG
static LPoint3 dummy_value = LPoint3::zero(); static LPoint3f dummy_value = LPoint3f::zero();
nassertr(x >= 0 && x < _x_size, dummy_value); nassertr(x >= 0 && x < _x_size, dummy_value);
nassertr(y >= 0 && y < _y_size, dummy_value); nassertr(y >= 0 && y < _y_size, dummy_value);
#endif #endif
return _table[y * _x_size + x]; return *(LPoint3f *)&_table[(y * _x_size + x) * _num_channels];
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_point4
// Access: Published
// Description: Returns the 4-component point value at the indicated
// point. In a 1-channel image, the channel value is in
// the x component.
////////////////////////////////////////////////////////////////////
INLINE const LPoint4f &PfmFile::
get_point4(int x, int y) const {
nassertr(x >= 0 && x < _x_size, LPoint4f::zero());
nassertr(y >= 0 && y < _y_size, LPoint4f::zero());
return *(LPoint4f *)&_table[(y * _x_size + x) * _num_channels];
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::set_point4
// Access: Published
// Description: Replaces the 4-component point value at the indicated
// point. In a 1-channel image, the channel value is in
// the x component.
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
set_point4(int x, int y, const LVecBase4f &point) {
nassertv(!point.is_nan());
nassertv(x >= 0 && x < _x_size);
nassertv(y >= 0 && y < _y_size);
switch (_num_channels) {
case 1:
_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 4:
*(LPoint4f *)&_table[(y * _x_size + x) * _num_channels] = point;
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::modify_point4
// Access: Published
// Description: Returns a modifiable 4-component point value at the
// indicated point.
////////////////////////////////////////////////////////////////////
INLINE LPoint4f &PfmFile::
modify_point4(int x, int y) {
#ifndef NDEBUG
static LPoint4f dummy_value = LPoint4f::zero();
nassertr(x >= 0 && x < _x_size, dummy_value);
nassertr(y >= 0 && y < _y_size, dummy_value);
#endif
return *(LPoint4f *)&_table[(y * _x_size + x) * _num_channels];
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -161,22 +224,32 @@ calc_autocrop(LVecBase4 &range) const {
INLINE void PfmFile:: INLINE void PfmFile::
set_zero_special(bool zero_special) { set_zero_special(bool zero_special) {
if (zero_special) { if (zero_special) {
set_no_data_value(LPoint3::zero()); set_no_data_value(LPoint4f::zero());
} else { } else {
clear_no_data_value(); clear_no_data_value();
} }
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PfmFile::set_no_data_value // Function: PfmFile::set_no_data_chan4
// Access: Published // Access: Published
// Description: Sets the special value that means "no data" when it // Description: Sets the no_data_chan4 flag. When this flag is true,
// appears in the pfm file. // and the pfm file has 4 channels, then a negative
// value in the fourth channel indicates no data. When
// it is false, a zero or positive value in the fourth
// channel indicates valid data.
//
// This is a special case of set_no_data_value().
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE void PfmFile:: INLINE void PfmFile::
set_no_data_value(const LPoint3 &no_data_value) { set_no_data_chan4(bool chan4) {
if (chan4 && _num_channels == 4) {
_has_no_data_value = true; _has_no_data_value = true;
_no_data_value = no_data_value; _no_data_value = LPoint4f::zero();
_has_point = has_point_chan4;
} else {
clear_no_data_value();
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -189,7 +262,8 @@ set_no_data_value(const LPoint3 &no_data_value) {
INLINE void PfmFile:: INLINE void PfmFile::
clear_no_data_value() { clear_no_data_value() {
_has_no_data_value = false; _has_no_data_value = false;
_no_data_value = LPoint3::zero(); _no_data_value = LPoint4f::zero();
_has_point = has_point_noop;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -209,9 +283,9 @@ has_no_data_value() const {
// Description: If has_no_data_value() returns true, this returns the // Description: If has_no_data_value() returns true, this returns the
// particular "no data" value. // particular "no data" value.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE const LPoint3 &PfmFile:: INLINE const LPoint4f &PfmFile::
get_no_data_value() const { get_no_data_value() const {
nassertr(_has_no_data_value, LPoint3::zero()); nassertr(_has_no_data_value, LPoint4f::zero());
return _no_data_value; return _no_data_value;
} }

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,8 @@ class PNMImage;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : PfmFile // Class : PfmFile
// Description : Defines a pfm file, a 2-d table of floating-point // Description : Defines a pfm file, a 2-d table of floating-point
// numbers, either 3-component or 1-component. // numbers, either 3-component or 1-component, or with a
// special extension, 4-component.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_GRUTIL PfmFile { class EXPCL_PANDA_GRUTIL PfmFile {
PUBLISHED: PUBLISHED:
@ -52,16 +53,19 @@ PUBLISHED:
INLINE int get_x_size() const; INLINE int get_x_size() const;
INLINE int get_y_size() const; INLINE int get_y_size() const;
INLINE PN_stdfloat get_scale() const; INLINE PN_float32 get_scale() const;
INLINE int get_num_channels() const; INLINE int get_num_channels() const;
INLINE bool has_point(int x, int y) const; INLINE bool has_point(int x, int y) const;
INLINE const LPoint3 &get_point(int x, int y) const; INLINE const LPoint3f &get_point(int x, int y) const;
INLINE void set_point(int x, int y, const LVecBase3 &point); INLINE void set_point(int x, int y, const LVecBase3f &point);
INLINE LPoint3 &modify_point(int x, int y); INLINE LPoint3f &modify_point(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 LPoint4f &modify_point4(int x, int y);
BLOCKING bool calc_average_point(LPoint3 &result, PN_stdfloat x, PN_stdfloat y, PN_stdfloat radius) const; BLOCKING bool calc_average_point(LPoint3f &result, PN_float32 x, PN_float32 y, PN_float32 radius) const;
BLOCKING bool calc_min_max(LVecBase3 &min_points, LVecBase3 &max_points) 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 bool calc_autocrop(int &x_begin, int &x_end, int &y_begin, int &y_end) const;
BLOCKING INLINE bool calc_autocrop(LVecBase4 &range) const; BLOCKING INLINE bool calc_autocrop(LVecBase4 &range) const;
@ -69,10 +73,11 @@ PUBLISHED:
bool is_column_empty(int x, int y_begin, int y_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_zero_special(bool zero_special);
INLINE void set_no_data_value(const LPoint3 &no_data_value); INLINE void set_no_data_chan4(bool chan4);
void set_no_data_value(const LPoint4f &no_data_value);
INLINE void clear_no_data_value(); INLINE void clear_no_data_value();
INLINE bool has_no_data_value() const; INLINE bool has_no_data_value() const;
INLINE const LPoint3 &get_no_data_value() const; INLINE const LPoint4f &get_no_data_value() const;
BLOCKING void resize(int new_x_size, int new_y_size); BLOCKING void resize(int new_x_size, int new_y_size);
BLOCKING void reverse_rows(); BLOCKING void reverse_rows();
@ -82,10 +87,10 @@ PUBLISHED:
BLOCKING void merge(const PfmFile &other); BLOCKING void merge(const PfmFile &other);
BLOCKING void apply_crop(int x_begin, int x_end, int y_begin, int y_end); 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(PN_float32 point_dist, PN_float32 sample_radius) const;
BLOCKING PT(BoundingHexahedron) compute_planar_bounds(const LPoint2 &center, PN_stdfloat point_dist, PN_stdfloat sample_radius, bool points_only) const; BLOCKING PT(BoundingHexahedron) compute_planar_bounds(const LPoint2 &center, PN_float32 point_dist, PN_float32 sample_radius, bool points_only) const;
void compute_sample_point(LPoint3 &result, void compute_sample_point(LPoint3f &result,
PN_stdfloat x, PN_stdfloat y, PN_stdfloat sample_radius) const; PN_float32 x, PN_float32 y, PN_float32 sample_radius) const;
INLINE void set_vis_inverse(bool vis_inverse); INLINE void set_vis_inverse(bool vis_inverse);
INLINE bool get_vis_inverse() const; INLINE bool get_vis_inverse() const;
@ -107,37 +112,47 @@ PUBLISHED:
private: private:
void make_vis_mesh_geom(GeomNode *gnode, bool inverted) const; void make_vis_mesh_geom(GeomNode *gnode, bool inverted) const;
void box_filter_region(LPoint3 &result, void box_filter_region(LPoint4f &result,
PN_stdfloat x0, PN_stdfloat y0, PN_stdfloat x1, PN_stdfloat y1) const; PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
void box_filter_line(LPoint3 &result, PN_stdfloat &coverage, void box_filter_line(LPoint4f &result, PN_float32 &coverage,
PN_stdfloat x0, int y, PN_stdfloat x1, PN_stdfloat y_contrib) const; PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const;
void box_filter_point(LPoint3 &result, PN_stdfloat &coverage, void box_filter_point(LPoint4f &result, PN_float32 &coverage,
int x, int y, PN_stdfloat x_contrib, PN_stdfloat y_contrib) const; int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const;
class MiniGridCell { class MiniGridCell {
public: public:
MiniGridCell() : _ti(-1), _dist(-1) { } MiniGridCell() : _sxi(-1), _syi(-1), _dist(-1) { }
int _ti; int _sxi, _syi;
int _dist; 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 ti) const; int xi, int yi, int dist, int sxi, int syi) const;
static bool has_point_noop(const PfmFile *file, int x, int y);
static bool has_point_1(const PfmFile *file, int x, int y);
static bool has_point_3(const PfmFile *file, int x, int y);
static bool has_point_4(const PfmFile *file, int x, int y);
static bool has_point_chan4(const PfmFile *file, int x, int y);
private: private:
typedef pvector<LPoint3> Table; typedef pvector<PN_float32> Table;
Table _table; Table _table;
int _x_size; int _x_size;
int _y_size; int _y_size;
PN_stdfloat _scale; PN_float32 _scale;
int _num_channels; int _num_channels;
bool _has_no_data_value; bool _has_no_data_value;
LPoint3 _no_data_value; LPoint4f _no_data_value;
bool _vis_inverse; bool _vis_inverse;
PT(InternalName) _flat_texcoord_name; PT(InternalName) _flat_texcoord_name;
bool _vis_2d; bool _vis_2d;
typedef bool HasPointFunc(const PfmFile *file, int x, int y);
HasPointFunc *_has_point;
}; };
#include "pfmFile.I" #include "pfmFile.I"

View File

@ -95,8 +95,9 @@ has_magic_number() const {
bool PNMFileTypePfm:: bool PNMFileTypePfm::
matches_magic_number(const string &magic_number) const { matches_magic_number(const string &magic_number) const {
return (magic_number.size() >= 2) && return (magic_number.size() >= 2) &&
magic_number[0] == 'P' && (magic_number.substr(0, 2) == "PF" ||
(magic_number[1] == 'F' || magic_number[1] == 'f'); magic_number.substr(0, 2) == "Pf" ||
magic_number.substr(0, 2) == "pf");
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -164,8 +165,13 @@ read_data(xel *array, xelval *alpha) {
nassertr(_image.get_x_size() == get_x_size() && nassertr(_image.get_x_size() == get_x_size() &&
_image.get_y_size() == get_y_size(), 0); _image.get_y_size() == get_y_size(), 0);
memcpy(array, _image[0], get_x_size() * get_y_size() * sizeof(xel));
nassertr(!has_alpha(), 0); memcpy(array, _image.get_array(), get_x_size() * get_y_size() * sizeof(xel));
if (has_alpha()) {
memcpy(alpha, _image.get_alpha_array(), get_x_size() * get_y_size() * sizeof(xelval));
}
return get_y_size(); return get_y_size();
} }
@ -213,8 +219,10 @@ write_data(xel *array, xelval *alpha) {
image.copy_header_from(*this); image.copy_header_from(*this);
nassertr(image.get_x_size() == get_x_size() && nassertr(image.get_x_size() == get_x_size() &&
image.get_y_size() == get_y_size(), 0); image.get_y_size() == get_y_size(), 0);
memcpy(image[0], array, get_x_size() * get_y_size() * sizeof(xel)); memcpy(image.get_array(), array, get_x_size() * get_y_size() * sizeof(xel));
nassertr(!has_alpha(), 0); if (has_alpha()) {
memcpy(image.get_alpha_array(), alpha, get_x_size() * get_y_size() * sizeof(xelval));
}
PfmFile pfm; PfmFile pfm;
if (!pfm.load(image)) { if (!pfm.load(image)) {