Browse Source

add PfmVizzer::set_aux_pfm() and PfmFile::set_no_data_threshold()

David Rose 11 years ago
parent
commit
dbc6091cf0

+ 45 - 2
panda/src/grutil/pfmVizzer.I

@@ -17,7 +17,7 @@
 //     Function: PfmVizzer::get_pfm
 //     Function: PfmVizzer::get_pfm
 //       Access: Published
 //       Access: Published
 //  Description: Returns the reference to the PfmFile manipulated by
 //  Description: Returns the reference to the PfmFile manipulated by
-//               thiz PfmVizzer.
+//               this PfmVizzer.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PfmFile &PfmVizzer::
 INLINE PfmFile &PfmVizzer::
 get_pfm() {
 get_pfm() {
@@ -28,7 +28,7 @@ get_pfm() {
 //     Function: PfmVizzer::get_pfm
 //     Function: PfmVizzer::get_pfm
 //       Access: Published
 //       Access: Published
 //  Description: Returns the reference to the PfmFile manipulated by
 //  Description: Returns the reference to the PfmFile manipulated by
-//               thiz PfmVizzer.
+//               this PfmVizzer.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE const PfmFile &PfmVizzer::
 INLINE const PfmFile &PfmVizzer::
 get_pfm() const {
 get_pfm() const {
@@ -206,6 +206,49 @@ get_vis_blend() const {
   return _vis_blend;
   return _vis_blend;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmVizzer::set_aux_pfm
+//       Access: Published
+//  Description: Assigns an auxiliary PfmFile to this PfmVizzer.  This
+//               file will be queried by column types
+//               CT_aux_vertex1/2/3, but has no other meaning to the
+//               vizzer.  This size of this PfmFile should exactly
+//               match the base PfmFile.  No reference count is held
+//               and no copy is made; the caller is responsible for
+//               ensuring that the auxiliary PfmFile will persist
+//               throughout the lifetime of the PfmVizzer it is
+//               assigned to.
+////////////////////////////////////////////////////////////////////
+INLINE void PfmVizzer::
+set_aux_pfm(const PfmFile *pfm) {
+  assert(pfm == NULL || (pfm->get_x_size() == _pfm.get_x_size() &&
+                         pfm->get_y_size() == _pfm.get_y_size()));
+  _aux_pfm = pfm;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmVizzer::clear_aux_pfm
+//       Access: Published
+//  Description: Removes the auxiliary PfmFile from this PfmVizzer.
+////////////////////////////////////////////////////////////////////
+INLINE void PfmVizzer::
+clear_aux_pfm() {
+  _aux_pfm = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmVizzer::get_aux_pfm
+//       Access: Published
+//  Description: Returns the reference to the auxiliary PfmFile
+//               queried by this PfmVizzer.  This contains the values
+//               that will be reflected in CT_aux_vertex3 etc.  See
+//               set_aux_pfm().
+////////////////////////////////////////////////////////////////////
+INLINE const PfmFile *PfmVizzer::
+get_aux_pfm() const {
+  return _aux_pfm;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmVizzer::VisColumn::Constructor
 //     Function: PfmVizzer::VisColumn::Constructor
 //       Access: Public
 //       Access: Public

+ 78 - 1
panda/src/grutil/pfmVizzer.cxx

@@ -38,6 +38,7 @@ PfmVizzer(PfmFile &pfm) : _pfm(pfm) {
   _vis_2d = false;
   _vis_2d = false;
   _keep_beyond_lens = false;
   _keep_beyond_lens = false;
   _vis_blend = NULL;
   _vis_blend = NULL;
+  _aux_pfm = NULL;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -253,6 +254,9 @@ NodePath PfmVizzer::
 generate_vis_points() const {
 generate_vis_points() const {
   nassertr(_pfm.is_valid(), NodePath());
   nassertr(_pfm.is_valid(), NodePath());
 
 
+  bool check_aux_pfm = uses_aux_pfm();
+  nassertr(!check_aux_pfm || (_aux_pfm != NULL && _aux_pfm->is_valid()), NodePath());
+
   CPT(GeomVertexFormat) format;
   CPT(GeomVertexFormat) format;
   if (_vis_inverse) {
   if (_vis_inverse) {
     if (_vis_2d) {
     if (_vis_2d) {
@@ -291,6 +295,9 @@ generate_vis_points() const {
       if (!_pfm.has_point(xi, yi)) {
       if (!_pfm.has_point(xi, yi)) {
         continue;
         continue;
       }
       }
+      if (check_aux_pfm && !_aux_pfm->has_point(xi, yi)) {
+        continue;
+      }
 
 
       const LPoint3f &point = _pfm.get_point(xi, yi);
       const LPoint3f &point = _pfm.get_point(xi, yi);
       LPoint2f uv((PN_float32(xi) + 0.5) * uv_scale[0],
       LPoint2f uv((PN_float32(xi) + 0.5) * uv_scale[0],
@@ -330,6 +337,8 @@ generate_vis_points() const {
 NodePath PfmVizzer::
 NodePath PfmVizzer::
 generate_vis_mesh(MeshFace face) const {
 generate_vis_mesh(MeshFace face) const {
   nassertr(_pfm.is_valid(), NodePath());
   nassertr(_pfm.is_valid(), NodePath());
+  bool check_aux_pfm = uses_aux_pfm();
+  nassertr(!check_aux_pfm || (_aux_pfm != NULL && _aux_pfm->is_valid()), NodePath());
   nassertr(face != 0, NodePath());
   nassertr(face != 0, NodePath());
 
 
   if (_pfm.get_num_channels() == 1 && _vis_columns.empty()) {
   if (_pfm.get_num_channels() == 1 && _vis_columns.empty()) {
@@ -512,6 +521,31 @@ make_displacement(PNMImage &result, double max_u, double max_v) const {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmVizzer::uses_aux_pfm
+//       Access: Private
+//  Description: Returns true if any of the vis_column tokens
+//               reference the aux_pfm file, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool PfmVizzer::
+uses_aux_pfm() const {
+  for (VisColumns::const_iterator vci = _vis_columns.begin();
+       vci != _vis_columns.end();
+       ++vci) {
+    const VisColumn &column = *vci;
+    switch (column._source) {
+    case CT_aux_vertex1:
+    case CT_aux_vertex2:
+    case CT_aux_vertex3:
+      return true;
+    default:
+      break;
+    }
+  }
+
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmVizzer::r_fill_displacement
 //     Function: PfmVizzer::r_fill_displacement
 //       Access: Private
 //       Access: Private
@@ -616,6 +650,7 @@ make_vis_mesh_geom(GeomNode *gnode, bool inverted) const {
   if (vis_columns.empty()) {
   if (vis_columns.empty()) {
     build_auto_vis_columns(vis_columns, true);
     build_auto_vis_columns(vis_columns, true);
   }
   }
+  bool check_aux_pfm = uses_aux_pfm();
 
 
   CPT(GeomVertexFormat) format = make_array_format(vis_columns);
   CPT(GeomVertexFormat) format = make_array_format(vis_columns);
 
 
@@ -685,7 +720,13 @@ make_vis_mesh_geom(GeomNode *gnode, bool inverted) const {
               !_pfm.has_point(xi + 1, yi)) {
               !_pfm.has_point(xi + 1, yi)) {
             continue;
             continue;
           }
           }
-
+          if (check_aux_pfm && (!_aux_pfm->has_point(xi, yi) ||
+                                !_aux_pfm->has_point(xi, yi + 1) ||
+                                !_aux_pfm->has_point(xi + 1, yi + 1) ||
+                                !_aux_pfm->has_point(xi + 1, yi))) {
+            continue;
+          }
+          
           if (!keep_beyond_lens &&
           if (!keep_beyond_lens &&
               (skip_points[(yi - y_begin) * x_size + (xi - x_begin)] ||
               (skip_points[(yi - y_begin) * x_size + (xi - x_begin)] ||
                skip_points[(yi - y_begin + 1) * x_size + (xi - x_begin)] ||
                skip_points[(yi - y_begin + 1) * x_size + (xi - x_begin)] ||
@@ -833,18 +874,21 @@ make_array_format(const VisColumns &vis_columns) const {
       break;
       break;
 
 
     case CT_vertex1:
     case CT_vertex1:
+    case CT_aux_vertex1:
       num_components = 1;
       num_components = 1;
       numeric_type = GeomEnums::NT_float32;
       numeric_type = GeomEnums::NT_float32;
       contents = GeomEnums::C_point;
       contents = GeomEnums::C_point;
       break;
       break;
 
 
     case CT_vertex2:
     case CT_vertex2:
+    case CT_aux_vertex2:
       num_components = 2;
       num_components = 2;
       numeric_type = GeomEnums::NT_float32;
       numeric_type = GeomEnums::NT_float32;
       contents = GeomEnums::C_point;
       contents = GeomEnums::C_point;
       break;
       break;
 
 
     case CT_vertex3:
     case CT_vertex3:
+    case CT_aux_vertex3:
       num_components = 3;
       num_components = 3;
       numeric_type = GeomEnums::NT_float32;
       numeric_type = GeomEnums::NT_float32;
       contents = GeomEnums::C_point;
       contents = GeomEnums::C_point;
@@ -917,6 +961,18 @@ add_data(const PfmVizzer &vizzer, GeomVertexWriter &vwriter, int xi, int yi, boo
     }
     }
     break;
     break;
 
 
+  case CT_aux_vertex1:
+    {
+      nassertr(vizzer.get_aux_pfm() != NULL, false);
+      PN_float32 p = vizzer.get_aux_pfm()->get_point1(xi, yi);
+      LPoint2f point(p, 0.0);
+      if (!transform_point(point)) {
+        success = false;
+      }
+      vwriter.set_data2f(point);
+    }
+    break;
+
   case CT_vertex2:
   case CT_vertex2:
     {
     {
       LPoint2f point = pfm.get_point2(xi, yi);
       LPoint2f point = pfm.get_point2(xi, yi);
@@ -927,6 +983,17 @@ add_data(const PfmVizzer &vizzer, GeomVertexWriter &vwriter, int xi, int yi, boo
     }
     }
     break;
     break;
 
 
+  case CT_aux_vertex2:
+    {
+      nassertr(vizzer.get_aux_pfm() != NULL, false);
+      LPoint2f point = vizzer.get_aux_pfm()->get_point2(xi, yi);
+      if (!transform_point(point)) {
+        success = false;
+      }
+      vwriter.set_data2f(point);
+    }
+    break;
+
   case CT_vertex3:
   case CT_vertex3:
     {
     {
       LPoint3f point = pfm.get_point(xi, yi);
       LPoint3f point = pfm.get_point(xi, yi);
@@ -937,6 +1004,16 @@ add_data(const PfmVizzer &vizzer, GeomVertexWriter &vwriter, int xi, int yi, boo
     }
     }
     break;
     break;
 
 
+  case CT_aux_vertex3:
+    {
+      LPoint3f point = vizzer.get_aux_pfm()->get_point(xi, yi);
+      if (!transform_point(point)) {
+        success = false;
+      }
+      vwriter.set_data3f(point);
+    }
+    break;
+
   case CT_normal3:
   case CT_normal3:
     {
     {
       // Calculate the normal based on two neighboring vertices.
       // Calculate the normal based on two neighboring vertices.

+ 9 - 0
panda/src/grutil/pfmVizzer.h

@@ -53,6 +53,10 @@ PUBLISHED:
   INLINE void clear_vis_blend();
   INLINE void clear_vis_blend();
   INLINE const PNMImage *get_vis_blend() const;
   INLINE const PNMImage *get_vis_blend() const;
 
 
+  INLINE void set_aux_pfm(const PfmFile *pfm);
+  INLINE void clear_aux_pfm();
+  INLINE const PfmFile *get_aux_pfm() const;
+
   enum ColumnType {
   enum ColumnType {
     CT_texcoord2,
     CT_texcoord2,
     CT_texcoord3,
     CT_texcoord3,
@@ -61,6 +65,9 @@ PUBLISHED:
     CT_vertex3,
     CT_vertex3,
     CT_normal3,
     CT_normal3,
     CT_blend1,
     CT_blend1,
+    CT_aux_vertex1,
+    CT_aux_vertex2,
+    CT_aux_vertex3,
   };
   };
   void clear_vis_columns();
   void clear_vis_columns();
   void add_vis_column(ColumnType source, ColumnType target,
   void add_vis_column(ColumnType source, ColumnType target,
@@ -82,6 +89,7 @@ PUBLISHED:
   BLOCKING void make_displacement(PNMImage &result, double max_u, double max_v) const;
   BLOCKING void make_displacement(PNMImage &result, double max_u, double max_v) const;
 
 
 private:
 private:
+  bool uses_aux_pfm() const;
   void r_fill_displacement(PNMImage &result, int xi, int yi, 
   void r_fill_displacement(PNMImage &result, int xi, int yi, 
                            double nxi, double nyi, double u_scale, double v_scale,
                            double nxi, double nyi, double u_scale, double v_scale,
                            int distance) const;
                            int distance) const;
@@ -117,6 +125,7 @@ private:
 
 
 private:
 private:
   PfmFile &_pfm;
   PfmFile &_pfm;
+  const PfmFile *_aux_pfm;
 
 
   bool _vis_inverse;
   bool _vis_inverse;
   PT(InternalName) _flat_texcoord_name;
   PT(InternalName) _flat_texcoord_name;

+ 25 - 0
panda/src/pnmimage/pfmFile.I

@@ -478,6 +478,7 @@ INLINE void PfmFile::
 set_no_data_chan4(bool chan4) {
 set_no_data_chan4(bool chan4) {
   if (chan4 && _num_channels == 4) {
   if (chan4 && _num_channels == 4) {
     _has_no_data_value = true;
     _has_no_data_value = true;
+    _has_no_data_threshold = false;
     _no_data_value.set(0.0, 0.0, 0.0, -1.0);
     _no_data_value.set(0.0, 0.0, 0.0, -1.0);
     _has_point = has_point_chan4;
     _has_point = has_point_chan4;
   } else {
   } else {
@@ -496,6 +497,18 @@ set_no_data_value(const LPoint4d &no_data_value) {
   set_no_data_value(LCAST(PN_float32, no_data_value));
   set_no_data_value(LCAST(PN_float32, no_data_value));
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::set_no_data_threshold
+//       Access: Published
+//  Description: Sets the special threshold value.  Points that are
+//               below this value in all components are considered "no
+//               value".
+////////////////////////////////////////////////////////////////////
+INLINE void PfmFile::
+set_no_data_threshold(const LPoint4d &no_data_threshold) {
+  set_no_data_threshold(LCAST(PN_float32, no_data_threshold));
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::set_no_data_value
 //     Function: PfmFile::set_no_data_value
 //       Access: Published
 //       Access: Published
@@ -506,6 +519,7 @@ set_no_data_value(const LPoint4d &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;
+  _has_no_data_threshold = false;
   _no_data_value = LPoint4f::zero();
   _no_data_value = LPoint4f::zero();
   _has_point = has_point_noop;
   _has_point = has_point_noop;
 }
 }
@@ -521,6 +535,17 @@ has_no_data_value() const {
   return _has_no_data_value;
   return _has_no_data_value;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::has_no_data_threshold
+//       Access: Published
+//  Description: Returns whether a "no data" threshold value has been
+//               established by set_no_data_threshold().
+////////////////////////////////////////////////////////////////////
+INLINE bool PfmFile::
+has_no_data_threshold() const {
+  return _has_no_data_threshold;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::get_no_data_value
 //     Function: PfmFile::get_no_data_value
 //       Access: Published
 //       Access: Published

+ 107 - 0
panda/src/pnmimage/pfmFile.cxx

@@ -33,6 +33,7 @@
 PfmFile::
 PfmFile::
 PfmFile() {
 PfmFile() {
   _has_no_data_value = false;
   _has_no_data_value = false;
+  _has_no_data_threshold = false;
   _no_data_value = LPoint4f::zero();
   _no_data_value = LPoint4f::zero();
   _has_point = has_point_noop;
   _has_point = has_point_noop;
   clear();
   clear();
@@ -49,6 +50,7 @@ PfmFile(const PfmFile &copy) :
   _table(copy._table),
   _table(copy._table),
   _scale(copy._scale),
   _scale(copy._scale),
   _has_no_data_value(copy._has_no_data_value),
   _has_no_data_value(copy._has_no_data_value),
+  _has_no_data_threshold(copy._has_no_data_threshold),
   _no_data_value(copy._no_data_value),
   _no_data_value(copy._no_data_value),
   _has_point(copy._has_point)
   _has_point(copy._has_point)
 {
 {
@@ -65,6 +67,7 @@ operator = (const PfmFile &copy) {
   _table = copy._table;
   _table = copy._table;
   _scale = copy._scale;
   _scale = copy._scale;
   _has_no_data_value = copy._has_no_data_value;
   _has_no_data_value = copy._has_no_data_value;
+  _has_no_data_threshold = copy._has_no_data_threshold;
   _no_data_value = copy._no_data_value;
   _no_data_value = copy._no_data_value;
   _has_point = copy._has_point;
   _has_point = copy._has_point;
 }
 }
@@ -908,6 +911,7 @@ set_no_data_nan(int num_channels) {
   if (num_channels > 0) {
   if (num_channels > 0) {
     num_channels = min(num_channels, _num_channels);
     num_channels = min(num_channels, _num_channels);
     _has_no_data_value = true;
     _has_no_data_value = true;
+    _has_no_data_threshold = false;
     _no_data_value = LPoint4f::zero();
     _no_data_value = LPoint4f::zero();
     PN_float32 nan = make_nan((PN_float32)0.0);
     PN_float32 nan = make_nan((PN_float32)0.0);
     for (int i = 0; i < num_channels; ++i) {
     for (int i = 0; i < num_channels; ++i) {
@@ -945,6 +949,7 @@ set_no_data_value(const LPoint4f &no_data_value) {
   nassertv(is_valid());
   nassertv(is_valid());
 
 
   _has_no_data_value = true;
   _has_no_data_value = true;
+  _has_no_data_threshold = false;
   _no_data_value = no_data_value;
   _no_data_value = no_data_value;
   switch (_num_channels) {
   switch (_num_channels) {
   case 1:
   case 1:
@@ -964,6 +969,38 @@ set_no_data_value(const LPoint4f &no_data_value) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::set_no_data_threshold
+//       Access: Published
+//  Description: Sets the special threshold value.  Points that are
+//               below this value in all components are considered "no
+//               value".
+////////////////////////////////////////////////////////////////////
+void PfmFile::
+set_no_data_threshold(const LPoint4f &no_data_value) {
+  nassertv(is_valid());
+
+  _has_no_data_value = true;
+  _has_no_data_threshold = true;
+  _no_data_value = no_data_value;
+  switch (_num_channels) {
+  case 1:
+    _has_point = has_point_threshold_1;
+    break;
+  case 2:
+    _has_point = has_point_threshold_2;
+    break;
+  case 3:
+    _has_point = has_point_threshold_3;
+    break;
+  case 4:
+    _has_point = has_point_threshold_4;
+    break;
+  default:
+    nassertv(false);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::resize
 //     Function: PfmFile::resize
 //       Access: Published
 //       Access: Published
@@ -2395,6 +2432,76 @@ has_point_4(const PfmFile *self, int x, int y) {
   return false;
   return false;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::has_point_threshold_1
+//       Access: Private, Static
+//  Description: The implementation of has_point_threshold() for 1-component
+//               files with a no_data_value.
+////////////////////////////////////////////////////////////////////
+bool PfmFile::
+has_point_threshold_1(const PfmFile *self, int x, int y) {
+  if ((x >= 0 && x < self->_x_size) && 
+      (y >= 0 && y < self->_y_size)) {
+    const float *table = &self->_table[(y * self->_x_size + x)];
+    return table[0] >= self->_no_data_value[0];
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::has_point_threshold_2
+//       Access: Private, Static
+//  Description: The implementation of has_point_threshold() for 2-component
+//               files with a no_data_value.
+////////////////////////////////////////////////////////////////////
+bool PfmFile::
+has_point_threshold_2(const PfmFile *self, int x, int y) {
+  if ((x >= 0 && x < self->_x_size) && 
+      (y >= 0 && y < self->_y_size)) {
+    const float *table = &self->_table[(y * self->_x_size + x) * 2];
+    return (table[0] >= self->_no_data_value[0] ||
+            table[1] >= self->_no_data_value[1]);
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::has_point_threshold_3
+//       Access: Private, Static
+//  Description: The implementation of has_point_threshold() for 3-component
+//               files with a no_data_value.
+////////////////////////////////////////////////////////////////////
+bool PfmFile::
+has_point_threshold_3(const PfmFile *self, int x, int y) {
+  if ((x >= 0 && x < self->_x_size) && 
+      (y >= 0 && y < self->_y_size)) {
+    const float *table = &self->_table[(y * self->_x_size + x) * 3];
+    return (table[0] >= self->_no_data_value[0] ||
+            table[1] >= self->_no_data_value[1] ||
+            table[2] >= self->_no_data_value[2]);
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::has_point_threshold_4
+//       Access: Private, Static
+//  Description: The implementation of has_point_threshold() for 4-component
+//               files with a no_data_value.
+////////////////////////////////////////////////////////////////////
+bool PfmFile::
+has_point_threshold_4(const PfmFile *self, int x, int y) {
+  if ((x >= 0 && x < self->_x_size) && 
+      (y >= 0 && y < self->_y_size)) {
+    const float *table = &self->_table[(y * self->_x_size + x) * 4];
+    return (table[0] >= self->_no_data_value[0] ||
+            table[1] >= self->_no_data_value[1] ||
+            table[2] >= self->_no_data_value[2] ||
+            table[3] >= self->_no_data_value[3]);
+  }
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::has_point_chan4
 //     Function: PfmFile::has_point_chan4
 //       Access: Private, Static
 //       Access: Private, Static

+ 8 - 0
panda/src/pnmimage/pfmFile.h

@@ -104,8 +104,11 @@ PUBLISHED:
   void set_no_data_nan(int num_channels);
   void set_no_data_nan(int num_channels);
   void set_no_data_value(const LPoint4f &no_data_value);
   void set_no_data_value(const LPoint4f &no_data_value);
   INLINE void set_no_data_value(const LPoint4d &no_data_value);
   INLINE void set_no_data_value(const LPoint4d &no_data_value);
+  void set_no_data_threshold(const LPoint4f &no_data_value);
+  INLINE void set_no_data_threshold(const LPoint4d &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 bool has_no_data_threshold() const;
   INLINE const LPoint4f &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);
@@ -195,6 +198,10 @@ private:
   static bool has_point_2(const PfmFile *file, int x, int y);
   static bool has_point_2(const PfmFile *file, int x, int y);
   static bool has_point_3(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_4(const PfmFile *file, int x, int y);
+  static bool has_point_threshold_1(const PfmFile *file, int x, int y);
+  static bool has_point_threshold_2(const PfmFile *file, int x, int y);
+  static bool has_point_threshold_3(const PfmFile *file, int x, int y);
+  static bool has_point_threshold_4(const PfmFile *file, int x, int y);
   static bool has_point_chan4(const PfmFile *file, int x, int y);
   static bool has_point_chan4(const PfmFile *file, int x, int y);
   static bool has_point_nan_1(const PfmFile *file, int x, int y);
   static bool has_point_nan_1(const PfmFile *file, int x, int y);
   static bool has_point_nan_2(const PfmFile *file, int x, int y);
   static bool has_point_nan_2(const PfmFile *file, int x, int y);
@@ -208,6 +215,7 @@ private:
   PN_float32 _scale;
   PN_float32 _scale;
 
 
   bool _has_no_data_value;
   bool _has_no_data_value;
+  bool _has_no_data_threshold;
   LPoint4f _no_data_value;
   LPoint4f _no_data_value;
 
 
   typedef bool HasPointFunc(const PfmFile *file, int x, int y);
   typedef bool HasPointFunc(const PfmFile *file, int x, int y);