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::
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
// probably meaningless.
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat PfmFile::
INLINE PN_float32 PfmFile::
get_scale() const {
return _scale;
}
@ -79,11 +79,7 @@ get_num_channels() const {
////////////////////////////////////////////////////////////////////
INLINE bool PfmFile::
has_point(int x, int y) const {
if ((x >= 0 && x < _x_size) &&
(y >= 0 && y < _y_size)) {
return (!_has_no_data_value || _table[y * _x_size + x] != _no_data_value);
}
return false;
return _has_point(this, x, y);
}
////////////////////////////////////////////////////////////////////
@ -93,11 +89,11 @@ has_point(int x, int y) const {
// point. In a 1-channel image, the channel value is in
// the x component.
////////////////////////////////////////////////////////////////////
INLINE const LPoint3 &PfmFile::
INLINE const LPoint3f &PfmFile::
get_point(int x, int y) const {
nassertr(x >= 0 && x < _x_size, LPoint3::zero());
nassertr(y >= 0 && y < _y_size, LPoint3::zero());
return _table[y * _x_size + x];
nassertr(x >= 0 && x < _x_size, LPoint3f::zero());
nassertr(y >= 0 && y < _y_size, LPoint3f::zero());
return *(LPoint3f *)&_table[(y * _x_size + x) * _num_channels];
}
////////////////////////////////////////////////////////////////////
@ -108,11 +104,20 @@ get_point(int x, int y) const {
// the x component.
////////////////////////////////////////////////////////////////////
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(x >= 0 && x < _x_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
// indicated point.
////////////////////////////////////////////////////////////////////
INLINE LPoint3 &PfmFile::
INLINE LPoint3f &PfmFile::
modify_point(int x, int y) {
#ifndef NDEBUG
static LPoint3 dummy_value = LPoint3::zero();
static LPoint3f dummy_value = LPoint3f::zero();
nassertr(x >= 0 && x < _x_size, dummy_value);
nassertr(y >= 0 && y < _y_size, dummy_value);
#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::
set_zero_special(bool zero_special) {
if (zero_special) {
set_no_data_value(LPoint3::zero());
set_no_data_value(LPoint4f::zero());
} else {
clear_no_data_value();
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::set_no_data_value
// Function: PfmFile::set_no_data_chan4
// Access: Published
// Description: Sets the special value that means "no data" when it
// appears in the pfm file.
// Description: Sets the no_data_chan4 flag. When this flag is true,
// 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::
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;
_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::
clear_no_data_value() {
_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
// particular "no data" value.
////////////////////////////////////////////////////////////////////
INLINE const LPoint3 &PfmFile::
INLINE const LPoint4f &PfmFile::
get_no_data_value() const {
nassertr(_has_no_data_value, LPoint3::zero());
nassertr(_has_no_data_value, LPoint4f::zero());
return _no_data_value;
}

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,8 @@ class PNMImage;
////////////////////////////////////////////////////////////////////
// Class : PfmFile
// 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 {
PUBLISHED:
@ -52,16 +53,19 @@ PUBLISHED:
INLINE int get_x_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 bool has_point(int x, int y) const;
INLINE const LPoint3 &get_point(int x, int y) const;
INLINE void set_point(int x, int y, const LVecBase3 &point);
INLINE LPoint3 &modify_point(int x, int y);
INLINE const LPoint3f &get_point(int x, int y) const;
INLINE void set_point(int x, int y, const LVecBase3f &point);
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_min_max(LVecBase3 &min_points, LVecBase3 &max_points) const;
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;
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;
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 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 reverse_rows();
@ -82,10 +87,10 @@ PUBLISHED:
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 &center, PN_stdfloat point_dist, PN_stdfloat sample_radius, bool points_only) const;
void compute_sample_point(LPoint3 &result,
PN_stdfloat x, PN_stdfloat y, 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_float32 point_dist, PN_float32 sample_radius, bool points_only) const;
void compute_sample_point(LPoint3f &result,
PN_float32 x, PN_float32 y, PN_float32 sample_radius) const;
INLINE void set_vis_inverse(bool vis_inverse);
INLINE bool get_vis_inverse() const;
@ -107,37 +112,47 @@ PUBLISHED:
private:
void make_vis_mesh_geom(GeomNode *gnode, bool inverted) const;
void box_filter_region(LPoint3 &result,
PN_stdfloat x0, PN_stdfloat y0, PN_stdfloat x1, PN_stdfloat y1) const;
void box_filter_line(LPoint3 &result, PN_stdfloat &coverage,
PN_stdfloat x0, int y, PN_stdfloat x1, PN_stdfloat y_contrib) const;
void box_filter_point(LPoint3 &result, PN_stdfloat &coverage,
int x, int y, PN_stdfloat x_contrib, PN_stdfloat y_contrib) const;
void box_filter_region(LPoint4f &result,
PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
void box_filter_line(LPoint4f &result, PN_float32 &coverage,
PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const;
void box_filter_point(LPoint4f &result, PN_float32 &coverage,
int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const;
class MiniGridCell {
public:
MiniGridCell() : _ti(-1), _dist(-1) { }
int _ti;
MiniGridCell() : _sxi(-1), _syi(-1), _dist(-1) { }
int _sxi, _syi;
int _dist;
};
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:
typedef pvector<LPoint3> Table;
typedef pvector<PN_float32> Table;
Table _table;
int _x_size;
int _y_size;
PN_stdfloat _scale;
PN_float32 _scale;
int _num_channels;
bool _has_no_data_value;
LPoint3 _no_data_value;
LPoint4f _no_data_value;
bool _vis_inverse;
PT(InternalName) _flat_texcoord_name;
bool _vis_2d;
typedef bool HasPointFunc(const PfmFile *file, int x, int y);
HasPointFunc *_has_point;
};
#include "pfmFile.I"

View File

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