Browse Source

support for 4-channel pfm files

David Rose 13 years ago
parent
commit
8cc85e4024
4 changed files with 502 additions and 292 deletions
  1. 100 26
      panda/src/grutil/pfmFile.I
  2. 347 234
      panda/src/grutil/pfmFile.cxx
  3. 41 26
      panda/src/grutil/pfmFile.h
  4. 14 6
      panda/src/grutil/pnmFileTypePfm.cxx

+ 100 - 26
panda/src/grutil/pfmFile.I

@@ -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) {
-  _has_no_data_value = true;
-  _no_data_value = no_data_value;
+set_no_data_chan4(bool chan4) {
+  if (chan4 && _num_channels == 4) {
+    _has_no_data_value = true;
+    _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
+ 347 - 234
panda/src/grutil/pfmFile.cxx


+ 41 - 26
panda/src/grutil/pfmFile.h

@@ -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);
-
-  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;
+  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(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"

+ 14 - 6
panda/src/grutil/pnmFileTypePfm.cxx

@@ -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)) {

Some files were not shown because too many files changed in this diff