Browse Source

add PfmFile::gamma_correct(), PfmFile::apply_mask(), PNMImage::copy_channel_bits()

David Rose 10 years ago
parent
commit
8876f0939e

+ 69 - 4
panda/src/pnmimage/pfmFile.I

@@ -16,7 +16,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::is_valid
 //     Function: PfmFile::is_valid
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool PfmFile::
 INLINE bool PfmFile::
 is_valid() const {
 is_valid() const {
@@ -155,7 +155,7 @@ set_point2(int x, int y, const LVecBase2f &point) {
   case 4:
   case 4:
     (*(LPoint4f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1], 0.0, 0.0);
     (*(LPoint4f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1], 0.0, 0.0);
     break;
     break;
-  } 
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -276,7 +276,7 @@ set_point3(int x, int y, const LVecBase3f &point) {
   case 4:
   case 4:
     (*(LPoint4f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1], 0.0f, 0.0f);
     (*(LPoint4f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1], 0.0f, 0.0f);
     break;
     break;
-  } 
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -350,7 +350,7 @@ set_point4(int x, int y, const LVecBase4f &point) {
   case 4:
   case 4:
     *(LPoint4f *)&_table[(y * _x_size + x) * _num_channels] = point;
     *(LPoint4f *)&_table[(y * _x_size + x) * _num_channels] = point;
     break;
     break;
-  } 
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -593,6 +593,71 @@ compute_planar_bounds(const LPoint2d &center, PN_float32 point_dist, PN_float32
   return compute_planar_bounds(LCAST(PN_float32, center), point_dist, sample_radius, points_only);
   return compute_planar_bounds(LCAST(PN_float32, center), point_dist, sample_radius, points_only);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::gamma_correct
+//       Access: Published
+//  Description: Assuming the image was constructed with a gamma curve
+//               of from_gamma in the RGB channels, converts it to an
+//               image with a gamma curve of to_gamma in the RGB
+//               channels.  Does not affect the alpha channel.
+////////////////////////////////////////////////////////////////////
+INLINE void PfmFile::
+gamma_correct(float from_gamma, float to_gamma) {
+  apply_exponent(from_gamma / to_gamma);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::gamma_correct_alpha
+//       Access: Published
+//  Description: Assuming the image was constructed with a gamma curve
+//               of from_gamma in the alpha channel, converts it to an
+//               image with a gamma curve of to_gamma in the alpha
+//               channel.  Does not affect the RGB channels.
+////////////////////////////////////////////////////////////////////
+INLINE void PfmFile::
+gamma_correct_alpha(float from_gamma, float to_gamma) {
+  apply_exponent(1.0, from_gamma / to_gamma);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::apply_exponent
+//       Access: Published
+//  Description: Adjusts each channel of the image by raising the
+//               corresponding component value to the indicated
+//               exponent, such that L' = L ^ exponent.
+////////////////////////////////////////////////////////////////////
+INLINE void PfmFile::
+apply_exponent(float gray_exponent) {
+  apply_exponent(gray_exponent, gray_exponent, gray_exponent, 1.0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::apply_exponent
+//       Access: Published
+//  Description: Adjusts each channel of the image by raising the
+//               corresponding component value to the indicated
+//               exponent, such that L' = L ^ exponent.
+////////////////////////////////////////////////////////////////////
+INLINE void PfmFile::
+apply_exponent(float gray_exponent, float alpha_exponent) {
+  apply_exponent(gray_exponent, gray_exponent, gray_exponent, alpha_exponent);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::apply_exponent
+//       Access: Published
+//  Description: Adjusts each channel of the image by raising the
+//               corresponding component value to the indicated
+//               exponent, such that L' = L ^ exponent.  For a
+//               grayscale image, the blue_exponent value is used for
+//               the grayscale value, and red_exponent and
+//               green_exponent are unused.
+////////////////////////////////////////////////////////////////////
+INLINE void PfmFile::
+apply_exponent(float c0_exponent, float c1_exponent, float c2_exponent) {
+  apply_exponent(c0_exponent, c1_exponent, c2_exponent, 1.0);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::get_table
 //     Function: PfmFile::get_table
 //       Access: Public
 //       Access: Public

+ 153 - 56
panda/src/pnmimage/pfmFile.cxx

@@ -233,7 +233,7 @@ write(const Filename &fullpath) {
       << "Unable to open " << filename << "\n";
       << "Unable to open " << filename << "\n";
     return false;
     return false;
   }
   }
-  
+
   if (pnmimage_cat.is_debug()) {
   if (pnmimage_cat.is_debug()) {
     pnmimage_cat.debug()
     pnmimage_cat.debug()
       << "Writing PFM file " << filename << "\n";
       << "Writing PFM file " << filename << "\n";
@@ -514,7 +514,7 @@ fill(const LPoint4f &value) {
       }
       }
     }
     }
     break;
     break;
-  } 
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -767,7 +767,7 @@ calc_min_max(LVecBase3f &min_depth, LVecBase3f &max_depth) const {
       if (!has_point(xi, yi)) {
       if (!has_point(xi, yi)) {
         continue;
         continue;
       }
       }
-      
+
       const LPoint3f &p = get_point(xi, yi);
       const LPoint3f &p = get_point(xi, yi);
       if (!any_points) {
       if (!any_points) {
         min_depth = p;
         min_depth = p;
@@ -783,7 +783,7 @@ calc_min_max(LVecBase3f &min_depth, LVecBase3f &max_depth) const {
       }
       }
     }
     }
   }
   }
-    
+
   return any_points;
   return any_points;
 }
 }
 
 
@@ -839,7 +839,7 @@ calc_autocrop(int &x_begin, int &x_end, int &y_begin, int &y_end) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 is_row_empty(int y, int x_begin, int x_end) const {
 is_row_empty(int y, int x_begin, int x_end) const {
-  nassertr(y >= 0 && y < _y_size && 
+  nassertr(y >= 0 && y < _y_size &&
            x_begin >= 0 && x_begin <= x_end && x_end <= _x_size, false);
            x_begin >= 0 && x_begin <= x_end && x_end <= _x_size, false);
 
 
   if (!_has_no_data_value) {
   if (!_has_no_data_value) {
@@ -863,7 +863,7 @@ is_row_empty(int y, int x_begin, int x_end) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 is_column_empty(int x, int y_begin, int y_end) const {
 is_column_empty(int x, int y_begin, int y_end) const {
-  nassertr(x >= 0 && x < _x_size && 
+  nassertr(x >= 0 && x < _x_size &&
            y_begin >= 0 && y_begin <= y_end && y_end <= _y_size, false);
            y_begin >= 0 && y_begin <= y_end && y_end <= _y_size, false);
 
 
   if (!_has_no_data_value) {
   if (!_has_no_data_value) {
@@ -1012,7 +1012,7 @@ resize(int new_x_size, int new_y_size) {
   if (pfm_resize_quick && new_x_size <= _x_size && new_y_size <= _y_size) {
   if (pfm_resize_quick && new_x_size <= _x_size && new_y_size <= _y_size) {
     // If we're downscaling, we can use quick_filter, which is faster.
     // If we're downscaling, we can use quick_filter, which is faster.
     result.quick_filter_from(*this);
     result.quick_filter_from(*this);
-    
+
   } else {
   } else {
     // Otherwise, we should use box_filter() or gaussian_filter, which
     // Otherwise, we should use box_filter() or gaussian_filter, which
     // are more general.
     // are more general.
@@ -1068,18 +1068,18 @@ quick_filter_from(const PfmFile &from) {
       for (int to_y = 0; to_y < _y_size; ++to_y) {
       for (int to_y = 0; to_y < _y_size; ++to_y) {
         from_y1 = (to_y + 1.0) * y_scale;
         from_y1 = (to_y + 1.0) * y_scale;
         from_y1 = min(from_y1, (PN_float32)orig_y_size);
         from_y1 = min(from_y1, (PN_float32)orig_y_size);
-        
+
         from_x0 = 0.0;
         from_x0 = 0.0;
         for (int to_x = 0; to_x < _x_size; ++to_x) {
         for (int to_x = 0; to_x < _x_size; ++to_x) {
           from_x1 = (to_x + 1.0) * x_scale;
           from_x1 = (to_x + 1.0) * x_scale;
           from_x1 = min(from_x1, (PN_float32)orig_x_size);
           from_x1 = min(from_x1, (PN_float32)orig_x_size);
-          
+
           // Now the box from (from_x0, from_y0) - (from_x1, from_y1)
           // Now the box from (from_x0, from_y0) - (from_x1, from_y1)
           // but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
           // but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
           PN_float32 result;
           PN_float32 result;
           from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
           from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
           new_data.push_back(result);
           new_data.push_back(result);
-          
+
           from_x0 = from_x1;
           from_x0 = from_x1;
         }
         }
         from_y0 = from_y1;
         from_y0 = from_y1;
@@ -1093,19 +1093,19 @@ quick_filter_from(const PfmFile &from) {
       for (int to_y = 0; to_y < _y_size; ++to_y) {
       for (int to_y = 0; to_y < _y_size; ++to_y) {
         from_y1 = (to_y + 1.0) * y_scale;
         from_y1 = (to_y + 1.0) * y_scale;
         from_y1 = min(from_y1, (PN_float32)orig_y_size);
         from_y1 = min(from_y1, (PN_float32)orig_y_size);
-        
+
         from_x0 = 0.0;
         from_x0 = 0.0;
         for (int to_x = 0; to_x < _x_size; ++to_x) {
         for (int to_x = 0; to_x < _x_size; ++to_x) {
           from_x1 = (to_x + 1.0) * x_scale;
           from_x1 = (to_x + 1.0) * x_scale;
           from_x1 = min(from_x1, (PN_float32)orig_x_size);
           from_x1 = min(from_x1, (PN_float32)orig_x_size);
-          
+
           // Now the box from (from_x0, from_y0) - (from_x1, from_y1)
           // Now the box from (from_x0, from_y0) - (from_x1, from_y1)
           // but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
           // but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
           LPoint2f result;
           LPoint2f result;
           from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
           from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
           new_data.push_back(result[0]);
           new_data.push_back(result[0]);
           new_data.push_back(result[1]);
           new_data.push_back(result[1]);
-          
+
           from_x0 = from_x1;
           from_x0 = from_x1;
         }
         }
         from_y0 = from_y1;
         from_y0 = from_y1;
@@ -1119,12 +1119,12 @@ quick_filter_from(const PfmFile &from) {
       for (int to_y = 0; to_y < _y_size; ++to_y) {
       for (int to_y = 0; to_y < _y_size; ++to_y) {
         from_y1 = (to_y + 1.0) * y_scale;
         from_y1 = (to_y + 1.0) * y_scale;
         from_y1 = min(from_y1, (PN_float32)orig_y_size);
         from_y1 = min(from_y1, (PN_float32)orig_y_size);
-        
+
         from_x0 = 0.0;
         from_x0 = 0.0;
         for (int to_x = 0; to_x < _x_size; ++to_x) {
         for (int to_x = 0; to_x < _x_size; ++to_x) {
           from_x1 = (to_x + 1.0) * x_scale;
           from_x1 = (to_x + 1.0) * x_scale;
           from_x1 = min(from_x1, (PN_float32)orig_x_size);
           from_x1 = min(from_x1, (PN_float32)orig_x_size);
-          
+
           // Now the box from (from_x0, from_y0) - (from_x1, from_y1)
           // Now the box from (from_x0, from_y0) - (from_x1, from_y1)
           // but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
           // but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
           LPoint3f result;
           LPoint3f result;
@@ -1132,7 +1132,7 @@ quick_filter_from(const PfmFile &from) {
           new_data.push_back(result[0]);
           new_data.push_back(result[0]);
           new_data.push_back(result[1]);
           new_data.push_back(result[1]);
           new_data.push_back(result[2]);
           new_data.push_back(result[2]);
-          
+
           from_x0 = from_x1;
           from_x0 = from_x1;
         }
         }
         from_y0 = from_y1;
         from_y0 = from_y1;
@@ -1146,12 +1146,12 @@ quick_filter_from(const PfmFile &from) {
       for (int to_y = 0; to_y < _y_size; ++to_y) {
       for (int to_y = 0; to_y < _y_size; ++to_y) {
         from_y1 = (to_y + 1.0) * y_scale;
         from_y1 = (to_y + 1.0) * y_scale;
         from_y1 = min(from_y1, (PN_float32)orig_y_size);
         from_y1 = min(from_y1, (PN_float32)orig_y_size);
-        
+
         from_x0 = 0.0;
         from_x0 = 0.0;
         for (int to_x = 0; to_x < _x_size; ++to_x) {
         for (int to_x = 0; to_x < _x_size; ++to_x) {
           from_x1 = (to_x + 1.0) * x_scale;
           from_x1 = (to_x + 1.0) * x_scale;
           from_x1 = min(from_x1, (PN_float32)orig_x_size);
           from_x1 = min(from_x1, (PN_float32)orig_x_size);
-          
+
           // Now the box from (from_x0, from_y0) - (from_x1, from_y1)
           // Now the box from (from_x0, from_y0) - (from_x1, from_y1)
           // but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
           // but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
           LPoint4f result;
           LPoint4f result;
@@ -1160,14 +1160,14 @@ quick_filter_from(const PfmFile &from) {
           new_data.push_back(result[1]);
           new_data.push_back(result[1]);
           new_data.push_back(result[2]);
           new_data.push_back(result[2]);
           new_data.push_back(result[3]);
           new_data.push_back(result[3]);
-          
+
           from_x0 = from_x1;
           from_x0 = from_x1;
         }
         }
         from_y0 = from_y1;
         from_y0 = from_y1;
       }
       }
     }
     }
     break;
     break;
-    
+
   default:
   default:
     nassertv(false);
     nassertv(false);
   }
   }
@@ -1196,7 +1196,7 @@ reverse_rows() {
   for (int yi = 0; yi < _y_size; ++yi) {
   for (int yi = 0; yi < _y_size; ++yi) {
     int source_yi = _y_size - 1 - yi;
     int source_yi = _y_size - 1 - yi;
     int start = source_yi * row_size;
     int start = source_yi * row_size;
-    reversed.insert(reversed.end(), 
+    reversed.insert(reversed.end(),
                     _table.begin() + start, _table.begin() + start + row_size);
                     _table.begin() + start, _table.begin() + start + row_size);
   }
   }
 
 
@@ -1290,7 +1290,7 @@ xform(const LMatrix4f &transform) {
 //  Description: Applies the distortion indicated in the supplied dist
 //  Description: Applies the distortion indicated in the supplied dist
 //               map to the current map.  The dist map is understood
 //               map to the current map.  The dist map is understood
 //               to be a mapping of points in the range 0..1 in the
 //               to be a mapping of points in the range 0..1 in the
-//               first two dimensions.  
+//               first two dimensions.
 //
 //
 //               The operation can be expressed symbolically as:
 //               The operation can be expressed symbolically as:
 //
 //
@@ -1334,7 +1334,7 @@ forward_distort(const PfmFile &dist, PN_float32 scale_factor) {
 
 
   PfmFile result;
   PfmFile result;
   result.clear(working_x_size, working_y_size, _num_channels);
   result.clear(working_x_size, working_y_size, _num_channels);
-    
+
   if (_has_no_data_value) {
   if (_has_no_data_value) {
     result.set_no_data_value(_no_data_value);
     result.set_no_data_value(_no_data_value);
     result.fill(_no_data_value);
     result.fill(_no_data_value);
@@ -1412,7 +1412,7 @@ reverse_distort(const PfmFile &dist, PN_float32 scale_factor) {
 
 
   PfmFile result;
   PfmFile result;
   result.clear(working_x_size, working_y_size, _num_channels);
   result.clear(working_x_size, working_y_size, _num_channels);
-    
+
   if (_has_no_data_value) {
   if (_has_no_data_value) {
     result.set_no_data_value(_no_data_value);
     result.set_no_data_value(_no_data_value);
     result.fill(_no_data_value);
     result.fill(_no_data_value);
@@ -1466,6 +1466,36 @@ merge(const PfmFile &other) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::apply_mask
+//       Access: Published
+//  Description: Wherever there is missing data in the other PfmFile,
+//               set this the corresponding point in this PfmFile to
+//               missing as well, so that this PfmFile has only points
+//               where both files have points.
+//
+//               The point is set to "missing" by setting it the
+//               no_data_value.
+////////////////////////////////////////////////////////////////////
+void PfmFile::
+apply_mask(const PfmFile &other) {
+  nassertv(is_valid() && other.is_valid());
+  nassertv(other._x_size == _x_size && other._y_size == _y_size);
+
+  if (!other._has_no_data_value || !_has_no_data_value) {
+    // Trivial no-op.
+    return;
+  }
+
+  for (int yi = 0; yi < _y_size; ++yi) {
+    for (int xi = 0; xi < _x_size; ++xi) {
+      if (!other.has_point(xi, yi)) {
+        set_point4(xi, yi, _no_data_value);
+      }
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::copy_channel
 //     Function: PfmFile::copy_channel
 //       Access: Published
 //       Access: Published
@@ -1774,7 +1804,7 @@ compute_planar_bounds(const LPoint2f &center, PN_float32 point_dist, PN_float32
   }
   }
 
 
   PT(BoundingHexahedron) bounds;
   PT(BoundingHexahedron) bounds;
-  
+
   // We create a BoundingHexahedron with the points in a particular
   // We create a BoundingHexahedron with the points in a particular
   // well-defined order, based on the current coordinate system.
   // well-defined order, based on the current coordinate system.
   CoordinateSystem cs = get_default_coordinate_system();
   CoordinateSystem cs = get_default_coordinate_system();
@@ -1941,7 +1971,7 @@ copy_sub_image(const PfmFile &copy, int xto, int yto,
       }
       }
     }
     }
     break;
     break;
-  } 
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -2008,7 +2038,7 @@ add_sub_image(const PfmFile &copy, int xto, int yto,
       }
       }
     }
     }
     break;
     break;
-  } 
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -2101,7 +2131,11 @@ divide_sub_image(const PfmFile &copy, int xto, int yto,
       for (y = ymin; y < ymax; y++) {
       for (y = ymin; y < ymax; y++) {
         for (x = xmin; x < xmax; x++) {
         for (x = xmin; x < xmax; x++) {
           if (has_point(x, y) && copy.has_point(x - xmin + xfrom, y - ymin + yfrom)) {
           if (has_point(x, y) && copy.has_point(x - xmin + xfrom, y - ymin + yfrom)) {
-            set_point1(x, y, get_point1(x, y) / copy.get_point1(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale);
+            float val = get_point1(x, y) / copy.get_point1(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale;
+            if (cnan(val)) {
+              val = 0.0f;
+            }
+            set_point1(x, y, val);
           }
           }
         }
         }
       }
       }
@@ -2224,6 +2258,69 @@ operator *= (float multiplier) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::apply_exponent
+//       Access: Published
+//  Description: Adjusts each channel of the image by raising the
+//               corresponding component value to the indicated
+//               exponent, such that L' = L ^ exponent.
+////////////////////////////////////////////////////////////////////
+void PfmFile::
+apply_exponent(float c0_exponent, float c1_exponent, float c2_exponent,
+               float c3_exponent) {
+  switch (_num_channels) {
+  case 1:
+    {
+      for (int yi = 0; yi < _y_size; ++yi) {
+        for (int xi = 0; xi < _x_size; ++xi) {
+          float *val = &_table[(yi * _x_size + xi)];
+          val[0] = cpow(val[0], c0_exponent);
+        }
+      }
+    }
+    break;
+
+  case 2:
+    {
+      for (int yi = 0; yi < _y_size; ++yi) {
+        for (int xi = 0; xi < _x_size; ++xi) {
+          float *val = &_table[(yi * _x_size + xi) * _num_channels];
+          val[0] = cpow(val[0], c0_exponent);
+          val[1] = cpow(val[1], c1_exponent);
+        }
+      }
+    }
+    break;
+
+  case 3:
+    {
+      for (int yi = 0; yi < _y_size; ++yi) {
+        for (int xi = 0; xi < _x_size; ++xi) {
+          float *val = &_table[(yi * _x_size + xi) * _num_channels];
+          val[0] = cpow(val[0], c0_exponent);
+          val[1] = cpow(val[1], c1_exponent);
+          val[2] = cpow(val[2], c2_exponent);
+        }
+      }
+    }
+    break;
+
+  case 4:
+    {
+      for (int yi = 0; yi < _y_size; ++yi) {
+        for (int xi = 0; xi < _x_size; ++xi) {
+          float *val = &_table[(yi * _x_size + xi) * _num_channels];
+          val[0] = cpow(val[0], c0_exponent);
+          val[1] = cpow(val[1], c1_exponent);
+          val[2] = cpow(val[2], c2_exponent);
+          val[3] = cpow(val[3], c3_exponent);
+        }
+      }
+    }
+    break;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::output
 //     Function: PfmFile::output
 //       Access: Published
 //       Access: Published
@@ -2418,7 +2515,7 @@ box_filter_region(LPoint4f &result,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::box_filter_line
 //     Function: PfmFile::box_filter_line
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PfmFile::
 void PfmFile::
 box_filter_line(PN_float32 &result, PN_float32 &coverage,
 box_filter_line(PN_float32 &result, PN_float32 &coverage,
@@ -2447,7 +2544,7 @@ box_filter_line(PN_float32 &result, PN_float32 &coverage,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::box_filter_line
 //     Function: PfmFile::box_filter_line
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PfmFile::
 void PfmFile::
 box_filter_line(LPoint2f &result, PN_float32 &coverage,
 box_filter_line(LPoint2f &result, PN_float32 &coverage,
@@ -2476,7 +2573,7 @@ box_filter_line(LPoint2f &result, PN_float32 &coverage,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::box_filter_line
 //     Function: PfmFile::box_filter_line
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PfmFile::
 void PfmFile::
 box_filter_line(LPoint3f &result, PN_float32 &coverage,
 box_filter_line(LPoint3f &result, PN_float32 &coverage,
@@ -2505,7 +2602,7 @@ box_filter_line(LPoint3f &result, PN_float32 &coverage,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::box_filter_line
 //     Function: PfmFile::box_filter_line
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PfmFile::
 void PfmFile::
 box_filter_line(LPoint4f &result, PN_float32 &coverage,
 box_filter_line(LPoint4f &result, PN_float32 &coverage,
@@ -2534,7 +2631,7 @@ box_filter_line(LPoint4f &result, PN_float32 &coverage,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::box_filter_point
 //     Function: PfmFile::box_filter_point
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PfmFile::
 void PfmFile::
 box_filter_point(PN_float32 &result, PN_float32 &coverage,
 box_filter_point(PN_float32 &result, PN_float32 &coverage,
@@ -2552,7 +2649,7 @@ box_filter_point(PN_float32 &result, PN_float32 &coverage,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::box_filter_point
 //     Function: PfmFile::box_filter_point
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PfmFile::
 void PfmFile::
 box_filter_point(LPoint2f &result, PN_float32 &coverage,
 box_filter_point(LPoint2f &result, PN_float32 &coverage,
@@ -2570,7 +2667,7 @@ box_filter_point(LPoint2f &result, PN_float32 &coverage,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::box_filter_point
 //     Function: PfmFile::box_filter_point
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PfmFile::
 void PfmFile::
 box_filter_point(LPoint3f &result, PN_float32 &coverage,
 box_filter_point(LPoint3f &result, PN_float32 &coverage,
@@ -2588,7 +2685,7 @@ box_filter_point(LPoint3f &result, PN_float32 &coverage,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::box_filter_point
 //     Function: PfmFile::box_filter_point
 //       Access: Private
 //       Access: Private
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PfmFile::
 void PfmFile::
 box_filter_point(LPoint4f &result, PN_float32 &coverage,
 box_filter_point(LPoint4f &result, PN_float32 &coverage,
@@ -2611,7 +2708,7 @@ box_filter_point(LPoint4f &result, PN_float32 &coverage,
 //               with the index to the nearest value.
 //               with the index to the nearest value.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PfmFile::
 void PfmFile::
-fill_mini_grid(MiniGridCell *mini_grid, int x_size, int y_size, 
+fill_mini_grid(MiniGridCell *mini_grid, int x_size, int y_size,
                int xi, int yi, int dist, int sxi, int syi) const {
                int xi, int yi, int dist, int sxi, int syi) const {
   if (xi < 0 || xi >= x_size || yi < 0 || yi >= y_size) {
   if (xi < 0 || xi >= x_size || yi < 0 || yi >= y_size) {
     // Out of bounds.
     // Out of bounds.
@@ -2634,12 +2731,12 @@ fill_mini_grid(MiniGridCell *mini_grid, int x_size, int y_size,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::has_point_noop
 //     Function: PfmFile::has_point_noop
 //       Access: Private, Static
 //       Access: Private, Static
-//  Description: The implementation of has_point() for 
+//  Description: The implementation of has_point() for
 //               files without a no_data_value.
 //               files without a no_data_value.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_noop(const PfmFile *self, int x, int y) {
 has_point_noop(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     return true;
     return true;
   }
   }
@@ -2654,7 +2751,7 @@ has_point_noop(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_1(const PfmFile *self, int x, int y) {
 has_point_1(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     return self->_table[(y * self->_x_size + x)] != self->_no_data_value[0];
     return self->_table[(y * self->_x_size + x)] != self->_no_data_value[0];
   }
   }
@@ -2669,7 +2766,7 @@ has_point_1(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_2(const PfmFile *self, int x, int y) {
 has_point_2(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     return *(LPoint2f *)&self->_table[(y * self->_x_size + x) * 2] != *(LPoint2f *)&self->_no_data_value;
     return *(LPoint2f *)&self->_table[(y * self->_x_size + x) * 2] != *(LPoint2f *)&self->_no_data_value;
   }
   }
@@ -2684,7 +2781,7 @@ has_point_2(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_3(const PfmFile *self, int x, int y) {
 has_point_3(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     return *(LPoint3f *)&self->_table[(y * self->_x_size + x) * 3] != *(LPoint3f *)&self->_no_data_value;
     return *(LPoint3f *)&self->_table[(y * self->_x_size + x) * 3] != *(LPoint3f *)&self->_no_data_value;
   }
   }
@@ -2699,7 +2796,7 @@ has_point_3(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_4(const PfmFile *self, int x, int y) {
 has_point_4(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     return *(LPoint4f *)&self->_table[(y * self->_x_size + x) * 4] != *(LPoint4f *)&self->_no_data_value;
     return *(LPoint4f *)&self->_table[(y * self->_x_size + x) * 4] != *(LPoint4f *)&self->_no_data_value;
   }
   }
@@ -2714,7 +2811,7 @@ has_point_4(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_threshold_1(const PfmFile *self, int x, int y) {
 has_point_threshold_1(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     const float *table = &self->_table[(y * self->_x_size + x)];
     const float *table = &self->_table[(y * self->_x_size + x)];
     return table[0] >= self->_no_data_value[0];
     return table[0] >= self->_no_data_value[0];
@@ -2730,7 +2827,7 @@ has_point_threshold_1(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_threshold_2(const PfmFile *self, int x, int y) {
 has_point_threshold_2(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     const float *table = &self->_table[(y * self->_x_size + x) * 2];
     const float *table = &self->_table[(y * self->_x_size + x) * 2];
     return (table[0] >= self->_no_data_value[0] ||
     return (table[0] >= self->_no_data_value[0] ||
@@ -2747,7 +2844,7 @@ has_point_threshold_2(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_threshold_3(const PfmFile *self, int x, int y) {
 has_point_threshold_3(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     const float *table = &self->_table[(y * self->_x_size + x) * 3];
     const float *table = &self->_table[(y * self->_x_size + x) * 3];
     return (table[0] >= self->_no_data_value[0] ||
     return (table[0] >= self->_no_data_value[0] ||
@@ -2765,7 +2862,7 @@ has_point_threshold_3(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_threshold_4(const PfmFile *self, int x, int y) {
 has_point_threshold_4(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     const float *table = &self->_table[(y * self->_x_size + x) * 4];
     const float *table = &self->_table[(y * self->_x_size + x) * 4];
     return (table[0] >= self->_no_data_value[0] ||
     return (table[0] >= self->_no_data_value[0] ||
@@ -2785,7 +2882,7 @@ has_point_threshold_4(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_chan4(const PfmFile *self, int x, int y) {
 has_point_chan4(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     return self->_table[(y * self->_x_size + x) * 4 + 3] >= 0.0;
     return self->_table[(y * self->_x_size + x) * 4 + 3] >= 0.0;
   }
   }
@@ -2795,13 +2892,13 @@ has_point_chan4(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::has_point_nan_1
 //     Function: PfmFile::has_point_nan_1
 //       Access: Private, Static
 //       Access: Private, Static
-//  Description: The implementation of has_point() for 
+//  Description: The implementation of has_point() for
 //               files with set_no_data_nan() in effect.  This means
 //               files with set_no_data_nan() in effect.  This means
 //               that the data is valid iff no components involve NaN.
 //               that the data is valid iff no components involve NaN.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_nan_1(const PfmFile *self, int x, int y) {
 has_point_nan_1(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     return !cnan(self->_table[(y * self->_x_size + x) * self->_num_channels]);
     return !cnan(self->_table[(y * self->_x_size + x) * self->_num_channels]);
   }
   }
@@ -2811,13 +2908,13 @@ has_point_nan_1(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::has_point_nan_2
 //     Function: PfmFile::has_point_nan_2
 //       Access: Private, Static
 //       Access: Private, Static
-//  Description: The implementation of has_point() for 
+//  Description: The implementation of has_point() for
 //               files with set_no_data_nan() in effect.  This means
 //               files with set_no_data_nan() in effect.  This means
 //               that the data is valid iff no components involve NaN.
 //               that the data is valid iff no components involve NaN.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_nan_2(const PfmFile *self, int x, int y) {
 has_point_nan_2(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     return !((LVecBase2f *)&self->_table[(y * self->_x_size + x) * self->_num_channels])->is_nan();
     return !((LVecBase2f *)&self->_table[(y * self->_x_size + x) * self->_num_channels])->is_nan();
   }
   }
@@ -2827,13 +2924,13 @@ has_point_nan_2(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::has_point_nan_3
 //     Function: PfmFile::has_point_nan_3
 //       Access: Private, Static
 //       Access: Private, Static
-//  Description: The implementation of has_point() for 
+//  Description: The implementation of has_point() for
 //               files with set_no_data_nan() in effect.  This means
 //               files with set_no_data_nan() in effect.  This means
 //               that the data is valid iff no components involve NaN.
 //               that the data is valid iff no components involve NaN.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_nan_3(const PfmFile *self, int x, int y) {
 has_point_nan_3(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     return !((LVecBase3f *)&self->_table[(y * self->_x_size + x) * self->_num_channels])->is_nan();
     return !((LVecBase3f *)&self->_table[(y * self->_x_size + x) * self->_num_channels])->is_nan();
   }
   }
@@ -2843,13 +2940,13 @@ has_point_nan_3(const PfmFile *self, int x, int y) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::has_point_nan_4
 //     Function: PfmFile::has_point_nan_4
 //       Access: Private, Static
 //       Access: Private, Static
-//  Description: The implementation of has_point() for 
+//  Description: The implementation of has_point() for
 //               files with set_no_data_nan() in effect.  This means
 //               files with set_no_data_nan() in effect.  This means
 //               that the data is valid iff no components involve NaN.
 //               that the data is valid iff no components involve NaN.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PfmFile::
 bool PfmFile::
 has_point_nan_4(const PfmFile *self, int x, int y) {
 has_point_nan_4(const PfmFile *self, int x, int y) {
-  if ((x >= 0 && x < self->_x_size) && 
+  if ((x >= 0 && x < self->_x_size) &&
       (y >= 0 && y < self->_y_size)) {
       (y >= 0 && y < self->_y_size)) {
     return !((LVecBase4f *)&self->_table[(y * self->_x_size + x) * self->_num_channels])->is_nan();
     return !((LVecBase4f *)&self->_table[(y * self->_x_size + x) * self->_num_channels])->is_nan();
   }
   }

+ 9 - 1
panda/src/pnmimage/pfmFile.h

@@ -123,6 +123,7 @@ PUBLISHED:
   BLOCKING void forward_distort(const PfmFile &dist, PN_float32 scale_factor = 1.0);
   BLOCKING void forward_distort(const PfmFile &dist, PN_float32 scale_factor = 1.0);
   BLOCKING void reverse_distort(const PfmFile &dist, PN_float32 scale_factor = 1.0);
   BLOCKING void reverse_distort(const PfmFile &dist, PN_float32 scale_factor = 1.0);
   BLOCKING void merge(const PfmFile &other);
   BLOCKING void merge(const PfmFile &other);
+  BLOCKING void apply_mask(const PfmFile &other);
   BLOCKING void copy_channel(int to_channel, const PfmFile &other, int from_channel);
   BLOCKING void copy_channel(int to_channel, const PfmFile &other, int from_channel);
   BLOCKING void copy_channel_masked(int to_channel, const PfmFile &other, int from_channel);
   BLOCKING void copy_channel_masked(int to_channel, const PfmFile &other, int from_channel);
   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);
@@ -155,6 +156,13 @@ PUBLISHED:
 
 
   void operator *= (float multiplier);
   void operator *= (float multiplier);
 
 
+  INLINE void gamma_correct(float from_gamma, float to_gamma);
+  INLINE void gamma_correct_alpha(float from_gamma, float to_gamma);
+  INLINE void apply_exponent(float gray_exponent);
+  INLINE void apply_exponent(float gray_exponent, float alpha_exponent);
+  INLINE void apply_exponent(float c0_exponent, float c1_exponent, float c2_exponent);
+  void apply_exponent(float c0_exponent, float c1_exponent, float c2_exponent, float c3_exponent);
+
   void output(ostream &out) const;
   void output(ostream &out) const;
 
 
   EXTENSION(PyObject *get_points() const);
   EXTENSION(PyObject *get_points() const);
@@ -204,7 +212,7 @@ private:
     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 sxi, int syi) 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_noop(const PfmFile *file, int x, int y);

+ 59 - 2
panda/src/pnmimage/pnmImage.cxx

@@ -152,6 +152,57 @@ copy_channel(const PNMImage &copy, int src_channel, int dest_channel) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PNMImage::copy_channel_bits
+//       Access: Published
+//  Description: Copies some subset of the bits of the specified
+//               channel from one image into some subset of the bits
+//               of the specified channel in another image.  Images
+//               must be the same size.
+//
+//               If right_shift is negative, it means a left shift.
+////////////////////////////////////////////////////////////////////
+void PNMImage::
+copy_channel_bits(const PNMImage &copy, int src_channel, int dest_channel, xelval src_mask, int right_shift) {
+  // Make sure the channels are in range
+  nassertv(src_channel >= 0 && src_channel <= 3);
+  nassertv(dest_channel >= 0 && dest_channel <= 3);
+  // Make sure that images are valid
+  if (!copy.is_valid() || !is_valid()) {
+    pnmimage_cat.error() << "One of the images is invalid!\n";
+    return;
+  }
+  // Make sure the images are the same size
+  if (_x_size != copy.get_x_size() || _y_size != copy.get_y_size()){
+    pnmimage_cat.error() << "Image size doesn't match!\n";
+    return;
+  }
+
+  // Do the actual copying.
+  if (right_shift >= 0) {
+    xelval dest_mask = ~(src_mask >> right_shift);
+    for (int x = 0; x < _x_size; x++) {
+      for (int y = 0; y < _y_size; y++) {
+        xelval src = copy.get_channel_val(x, y, src_channel);
+        xelval dest = get_channel_val(x, y, dest_channel);
+        dest = (dest & dest_mask) | ((src & src_mask) >> right_shift);
+        set_channel_val(x, y, dest_channel, dest);
+      }
+    }
+  } else {
+    int left_shift = -right_shift;
+    xelval dest_mask = ~(src_mask << left_shift);
+    for (int x = 0; x < _x_size; x++) {
+      for (int y = 0; y < _y_size; y++) {
+        xelval src = copy.get_channel_val(x, y, src_channel);
+        xelval dest = get_channel_val(x, y, dest_channel);
+        dest = (dest & dest_mask) | ((src & src_mask) << left_shift);
+        set_channel_val(x, y, dest_channel, dest);
+      }
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::copy_header_from
 //     Function: PNMImage::copy_header_from
 //       Access: Published
 //       Access: Published
@@ -165,6 +216,12 @@ copy_header_from(const PNMImageHeader &header) {
   clear();
   clear();
   PNMImageHeader::operator = (header);
   PNMImageHeader::operator = (header);
 
 
+  if (_maxval == 0) {
+    _inv_maxval = 0.0f;
+  } else {
+    _inv_maxval = 1.0f / (float)_maxval;
+  }
+
   if (has_alpha()) {
   if (has_alpha()) {
     allocate_alpha();
     allocate_alpha();
   }
   }
@@ -1708,7 +1765,7 @@ rescale(float min_val, float max_val) {
     for (int y = 0; y < get_y_size(); y++) {
     for (int y = 0; y < get_y_size(); y++) {
       for (int x = 0; x < get_x_size(); x++) {
       for (int x = 0; x < get_x_size(); x++) {
         LRGBColorf xel = get_xel(x, y);
         LRGBColorf xel = get_xel(x, y);
-        set_xel(x, y, 
+        set_xel(x, y,
                 (xel[0] - min_val) / scale,
                 (xel[0] - min_val) / scale,
                 (xel[1] - min_val) / scale,
                 (xel[1] - min_val) / scale,
                 (xel[2] - min_val) / scale);
                 (xel[2] - min_val) / scale);
@@ -1899,7 +1956,7 @@ unfiltered_stretch_from(const PNMImage &copy) {
     }
     }
   }
   }
 
 
-  if (has_alpha() && copy.has_alpha()) { 
+  if (has_alpha() && copy.has_alpha()) {
     for (int yt = 0; yt < get_y_size(); yt++) {
     for (int yt = 0; yt < get_y_size(); yt++) {
       int ys = yt * copy.get_y_size() / get_y_size();
       int ys = yt * copy.get_y_size() / get_y_size();
       for (int xt = 0; xt < get_x_size(); xt++) {
       for (int xt = 0; xt < get_x_size(); xt++) {

+ 1 - 0
panda/src/pnmimage/pnmImage.h

@@ -90,6 +90,7 @@ PUBLISHED:
 
 
   void copy_from(const PNMImage &copy);
   void copy_from(const PNMImage &copy);
   void copy_channel(const PNMImage &copy, int src_channel, int dest_channel);
   void copy_channel(const PNMImage &copy, int src_channel, int dest_channel);
+  void copy_channel_bits(const PNMImage &copy, int src_channel, int dest_channel, xelval src_mask, int right_shift);
   void copy_header_from(const PNMImageHeader &header);
   void copy_header_from(const PNMImageHeader &header);
   void take_from(PNMImage &orig);
   void take_from(PNMImage &orig);
 
 

+ 23 - 23
panda/src/pnmimage/pnmImageHeader.I

@@ -255,7 +255,7 @@ set_type(PNMFileType *type) {
 //  Description: Records the indicated color in the histogram.
 //  Description: Records the indicated color in the histogram.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void PNMImageHeader::
 INLINE void PNMImageHeader::
-record_color(PNMImageHeader::HistMap &hist, 
+record_color(PNMImageHeader::HistMap &hist,
              const PNMImageHeader::PixelSpec &color) {
              const PNMImageHeader::PixelSpec &color) {
   // First, try to add the color with a count of 0, in case it does
   // First, try to add the color with a count of 0, in case it does
   // not already exist in the table.
   // not already exist in the table.
@@ -270,7 +270,7 @@ record_color(PNMImageHeader::HistMap &hist,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::Constructor
 //     Function: PNMImageHeader::PixelSpec::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImageHeader::PixelSpec::
 INLINE PNMImageHeader::PixelSpec::
 PixelSpec(xelval gray_value) :
 PixelSpec(xelval gray_value) :
@@ -284,7 +284,7 @@ PixelSpec(xelval gray_value) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::Constructor
 //     Function: PNMImageHeader::PixelSpec::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImageHeader::PixelSpec::
 INLINE PNMImageHeader::PixelSpec::
 PixelSpec(xelval gray_value, xelval alpha) :
 PixelSpec(xelval gray_value, xelval alpha) :
@@ -298,7 +298,7 @@ PixelSpec(xelval gray_value, xelval alpha) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::Constructor
 //     Function: PNMImageHeader::PixelSpec::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImageHeader::PixelSpec::
 INLINE PNMImageHeader::PixelSpec::
 PixelSpec(xelval red, xelval green, xelval blue) :
 PixelSpec(xelval red, xelval green, xelval blue) :
@@ -312,7 +312,7 @@ PixelSpec(xelval red, xelval green, xelval blue) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::Constructor
 //     Function: PNMImageHeader::PixelSpec::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImageHeader::PixelSpec::
 INLINE PNMImageHeader::PixelSpec::
 PixelSpec(xelval red, xelval green, xelval blue, xelval alpha) :
 PixelSpec(xelval red, xelval green, xelval blue, xelval alpha) :
@@ -326,7 +326,7 @@ PixelSpec(xelval red, xelval green, xelval blue, xelval alpha) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::Constructor
 //     Function: PNMImageHeader::PixelSpec::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImageHeader::PixelSpec::
 INLINE PNMImageHeader::PixelSpec::
 PixelSpec(const xel &rgb) :
 PixelSpec(const xel &rgb) :
@@ -340,7 +340,7 @@ PixelSpec(const xel &rgb) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::Constructor
 //     Function: PNMImageHeader::PixelSpec::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImageHeader::PixelSpec::
 INLINE PNMImageHeader::PixelSpec::
 PixelSpec(const xel &rgb, xelval alpha) :
 PixelSpec(const xel &rgb, xelval alpha) :
@@ -354,7 +354,7 @@ PixelSpec(const xel &rgb, xelval alpha) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::Copy Constructor
 //     Function: PNMImageHeader::PixelSpec::Copy Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImageHeader::PixelSpec::
 INLINE PNMImageHeader::PixelSpec::
 PixelSpec(const PixelSpec &copy) :
 PixelSpec(const PixelSpec &copy) :
@@ -368,7 +368,7 @@ PixelSpec(const PixelSpec &copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::Copy Assignment Operator
 //     Function: PNMImageHeader::PixelSpec::Copy Assignment Operator
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void PNMImageHeader::PixelSpec::
 INLINE void PNMImageHeader::PixelSpec::
 operator = (const PixelSpec &copy) {
 operator = (const PixelSpec &copy) {
@@ -381,7 +381,7 @@ operator = (const PixelSpec &copy) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::operator <
 //     Function: PNMImageHeader::PixelSpec::operator <
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool PNMImageHeader::PixelSpec::
 INLINE bool PNMImageHeader::PixelSpec::
 operator < (const PixelSpec &other) const {
 operator < (const PixelSpec &other) const {
@@ -391,7 +391,7 @@ operator < (const PixelSpec &other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::operator ==
 //     Function: PNMImageHeader::PixelSpec::operator ==
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool PNMImageHeader::PixelSpec::
 INLINE bool PNMImageHeader::PixelSpec::
 operator == (const PixelSpec &other) const {
 operator == (const PixelSpec &other) const {
@@ -401,7 +401,7 @@ operator == (const PixelSpec &other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::operator !=
 //     Function: PNMImageHeader::PixelSpec::operator !=
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool PNMImageHeader::PixelSpec::
 INLINE bool PNMImageHeader::PixelSpec::
 operator != (const PixelSpec &other) const {
 operator != (const PixelSpec &other) const {
@@ -411,7 +411,7 @@ operator != (const PixelSpec &other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::compare_to
 //     Function: PNMImageHeader::PixelSpec::compare_to
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int PNMImageHeader::PixelSpec::
 INLINE int PNMImageHeader::PixelSpec::
 compare_to(const PixelSpec &other) const {
 compare_to(const PixelSpec &other) const {
@@ -433,7 +433,7 @@ compare_to(const PixelSpec &other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::get_red
 //     Function: PNMImageHeader::PixelSpec::get_red
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE xelval PNMImageHeader::PixelSpec::
 INLINE xelval PNMImageHeader::PixelSpec::
 get_red() const {
 get_red() const {
@@ -443,7 +443,7 @@ get_red() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::get_green
 //     Function: PNMImageHeader::PixelSpec::get_green
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE xelval PNMImageHeader::PixelSpec::
 INLINE xelval PNMImageHeader::PixelSpec::
 get_green() const {
 get_green() const {
@@ -453,7 +453,7 @@ get_green() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::get_blue
 //     Function: PNMImageHeader::PixelSpec::get_blue
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE xelval PNMImageHeader::PixelSpec::
 INLINE xelval PNMImageHeader::PixelSpec::
 get_blue() const {
 get_blue() const {
@@ -463,7 +463,7 @@ get_blue() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::get_alpha
 //     Function: PNMImageHeader::PixelSpec::get_alpha
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE xelval PNMImageHeader::PixelSpec::
 INLINE xelval PNMImageHeader::PixelSpec::
 get_alpha() const {
 get_alpha() const {
@@ -473,7 +473,7 @@ get_alpha() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::set_red
 //     Function: PNMImageHeader::PixelSpec::set_red
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void PNMImageHeader::PixelSpec::
 INLINE void PNMImageHeader::PixelSpec::
 set_red(xelval red) {
 set_red(xelval red) {
@@ -483,7 +483,7 @@ set_red(xelval red) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::set_green
 //     Function: PNMImageHeader::PixelSpec::set_green
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void PNMImageHeader::PixelSpec::
 INLINE void PNMImageHeader::PixelSpec::
 set_green(xelval green) {
 set_green(xelval green) {
@@ -493,7 +493,7 @@ set_green(xelval green) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::set_blue
 //     Function: PNMImageHeader::PixelSpec::set_blue
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void PNMImageHeader::PixelSpec::
 INLINE void PNMImageHeader::PixelSpec::
 set_blue(xelval blue) {
 set_blue(xelval blue) {
@@ -503,7 +503,7 @@ set_blue(xelval blue) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpec::set_alpha
 //     Function: PNMImageHeader::PixelSpec::set_alpha
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void PNMImageHeader::PixelSpec::
 INLINE void PNMImageHeader::PixelSpec::
 set_alpha(xelval alpha) {
 set_alpha(xelval alpha) {
@@ -541,7 +541,7 @@ size() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::PixelSpecCount::Constructor
 //     Function: PNMImageHeader::PixelSpecCount::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImageHeader::PixelSpecCount::
 INLINE PNMImageHeader::PixelSpecCount::
 PixelSpecCount(const PNMImageHeader::PixelSpec &pixel, int count) :
 PixelSpecCount(const PNMImageHeader::PixelSpec &pixel, int count) :
@@ -565,7 +565,7 @@ operator < (const PNMImageHeader::PixelSpecCount &other) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::Histogram::Constructor
 //     Function: PNMImageHeader::Histogram::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImageHeader::Histogram::
 INLINE PNMImageHeader::Histogram::
 Histogram() {
 Histogram() {