Browse Source

officially support 2-channel PfmFile; load pfm into RGB, not BGR for texture loads

David Rose 12 years ago
parent
commit
7e645bdca6

+ 97 - 9
panda/src/gobj/texture.cxx

@@ -5912,13 +5912,61 @@ convert_from_pfm(PTA_uchar &image, size_t page_size, int z,
   nassertv(idx + page_size <= image.size());
   nassertv(idx + page_size <= image.size());
   PN_float32 *p = (PN_float32 *)&image[idx];
   PN_float32 *p = (PN_float32 *)&image[idx];
 
 
-  for (int j = y_size-1; j >= 0; j--) {
-    for (int i = 0; i < x_size; i++) {
-      for (int c = 0; c < num_components; ++c) {
-        *p = pfm.get_channel(i, j, c);
-        ++p;
+  switch (num_components) {
+  case 1:
+    {
+      for (int j = y_size-1; j >= 0; j--) {
+        for (int i = 0; i < x_size; i++) {
+          p[0] = pfm.get_channel(i, j, 0);
+          ++p;
+        }
+      }
+    }
+    break;
+
+  case 2:
+    {
+      for (int j = y_size-1; j >= 0; j--) {
+        for (int i = 0; i < x_size; i++) {
+          p[0] = pfm.get_channel(i, j, 0);
+          p[1] = pfm.get_channel(i, j, 1);
+          p += 2;
+        }
+      }
+    }
+    break;
+
+  case 3:
+    {
+      // RGB -> BGR
+      for (int j = y_size-1; j >= 0; j--) {
+        for (int i = 0; i < x_size; i++) {
+          p[0] = pfm.get_channel(i, j, 2);
+          p[1] = pfm.get_channel(i, j, 1);
+          p[2] = pfm.get_channel(i, j, 0);
+          p += 3;
+        }
+      }
+    }
+    break;
+
+  case 4:
+    {
+      // RGBA -> BGRA
+      for (int j = y_size-1; j >= 0; j--) {
+        for (int i = 0; i < x_size; i++) {
+          p[0] = pfm.get_channel(i, j, 2);
+          p[1] = pfm.get_channel(i, j, 1);
+          p[2] = pfm.get_channel(i, j, 0);
+          p[3] = pfm.get_channel(i, j, 3);
+          p += 4;
+        }
       }
       }
     }
     }
+    break;
+
+  default:
+    nassertv(false);
   }
   }
 
 
   nassertv((unsigned char *)p == &image[idx] + page_size);
   nassertv((unsigned char *)p == &image[idx] + page_size);
@@ -6003,13 +6051,53 @@ convert_to_pfm(PfmFile &pfm, int x_size, int y_size,
   nassertr(idx + page_size <= image.size(), false);
   nassertr(idx + page_size <= image.size(), false);
   const PN_float32 *p = (const PN_float32 *)&image[idx];
   const PN_float32 *p = (const PN_float32 *)&image[idx];
 
 
-  for (int j = y_size-1; j >= 0; j--) {
-    for (int i = 0; i < x_size; i++) {
-      for (int c = 0; c < num_components; ++c) {
-        pfm.set_channel(i, j, c, *p);
+  switch (num_components) {
+  case 1:
+    for (int j = y_size-1; j >= 0; j--) {
+      for (int i = 0; i < x_size; i++) {
+        pfm.set_channel(i, j, 0, p[0]);
         ++p;
         ++p;
       }
       }
     }
     }
+    break;
+
+  case 2:
+    for (int j = y_size-1; j >= 0; j--) {
+      for (int i = 0; i < x_size; i++) {
+        pfm.set_channel(i, j, 0, p[0]);
+        pfm.set_channel(i, j, 1, p[1]);
+        p += 2;
+      }
+    }
+    break;
+
+  case 3:
+    // BGR -> RGB
+    for (int j = y_size-1; j >= 0; j--) {
+      for (int i = 0; i < x_size; i++) {
+        pfm.set_channel(i, j, 2, p[0]);
+        pfm.set_channel(i, j, 1, p[1]);
+        pfm.set_channel(i, j, 0, p[2]);
+        p += 3;
+      }
+    }
+    break;
+
+  case 4:
+    // BGRA -> RGBA
+    for (int j = y_size-1; j >= 0; j--) {
+      for (int i = 0; i < x_size; i++) {
+        pfm.set_channel(i, j, 2, p[0]);
+        pfm.set_channel(i, j, 1, p[1]);
+        pfm.set_channel(i, j, 0, p[2]);
+        pfm.set_channel(i, j, 3, p[3]);
+        p += 4;
+      }
+    }
+    break;
+
+  default:
+    nassertr(false, false);
   }
   }
 
 
   nassertr((unsigned char *)p == &image[idx] + page_size, false);
   nassertr((unsigned char *)p == &image[idx] + page_size, false);

+ 159 - 22
panda/src/pnmimage/pfmFile.cxx

@@ -87,11 +87,16 @@ clear() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::clear
 //     Function: PfmFile::clear
 //       Access: Published
 //       Access: Published
-//  Description: Resets to an empty table with a specific size.
+//  Description: Resets to an empty table with a specific size.  The
+//               case of num_channels == 0 is allowed only in the case
+//               that x_size and y_size are also == 0; and this makes
+//               an empty (and invalid) PfmFile.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PfmFile::
 void PfmFile::
 clear(int x_size, int y_size, int num_channels) {
 clear(int x_size, int y_size, int num_channels) {
   nassertv(x_size >= 0 && y_size >= 0);
   nassertv(x_size >= 0 && y_size >= 0);
+  nassertv(num_channels > 0 && num_channels <= 4 || (x_size == 0 && y_size == 0 && num_channels == 0));
+
   _x_size = x_size;
   _x_size = x_size;
   _y_size = y_size;
   _y_size = y_size;
   _scale = 1.0;
   _scale = 1.0;
@@ -323,25 +328,7 @@ load(const PNMImage &pnmimage) {
     return false;
     return false;
   }
   }
 
 
-  // Get the number of channels, ignoring alpha.
-  int num_channels;
-  switch (pnmimage.get_num_channels()) {
-  case 4:
-    num_channels = 4;
-    break;
-
-  case 3:
-    num_channels = 3;
-    break;
-
-  case 2:
-  case 1:
-    num_channels = 1;
-    break;
-
-  default:
-    num_channels = 3;
-  }
+  int num_channels = pnmimage.get_num_channels();
 
 
   clear(pnmimage.get_x_size(), pnmimage.get_y_size(), num_channels);
   clear(pnmimage.get_x_size(), pnmimage.get_y_size(), num_channels);
   switch (num_channels) {
   switch (num_channels) {
@@ -355,6 +342,18 @@ load(const PNMImage &pnmimage) {
     }
     }
     break;
     break;
 
 
+  case 2:
+    {
+      for (int yi = 0; yi < pnmimage.get_y_size(); ++yi) {
+        for (int xi = 0; xi < pnmimage.get_x_size(); ++xi) {
+          PN_float32 *point = &_table[(yi * _x_size + xi) * _num_channels];
+          point[0] = pnmimage.get_gray(xi, yi);
+          point[1] = pnmimage.get_alpha(xi, yi);
+        }
+      }
+    }
+    break;
+
   case 3:
   case 3:
     {
     {
       for (int yi = 0; yi < pnmimage.get_y_size(); ++yi) {
       for (int yi = 0; yi < pnmimage.get_y_size(); ++yi) {
@@ -417,11 +416,23 @@ store(PNMImage &pnmimage) const {
     }
     }
     break;
     break;
 
 
+  case 2:
+    {
+      for (int yi = 0; yi < get_y_size(); ++yi) {
+        for (int xi = 0; xi < get_x_size(); ++xi) {
+          const LPoint2f &point = get_point2(xi, yi);
+          pnmimage.set_gray(xi, yi, point[0]);
+          pnmimage.set_alpha(xi, yi, point[1]);
+        }
+      }
+    }
+    break;
+
   case 3:
   case 3:
     {
     {
       for (int yi = 0; yi < get_y_size(); ++yi) {
       for (int yi = 0; yi < get_y_size(); ++yi) {
         for (int xi = 0; xi < get_x_size(); ++xi) {
         for (int xi = 0; xi < get_x_size(); ++xi) {
-          const LPoint3f &point = get_point(xi, yi);
+          const LPoint3f &point = get_point3(xi, yi);
           pnmimage.set_xel(xi, yi, point[0], point[1], point[2]);
           pnmimage.set_xel(xi, yi, point[0], point[1], point[2]);
         }
         }
       }
       }
@@ -1055,6 +1066,32 @@ quick_filter_from(const PfmFile &from) {
     }
     }
     break;
     break;
 
 
+  case 2:
+    {
+      from_y0 = 0.0;
+      for (int to_y = 0; to_y < _y_size; ++to_y) {
+        from_y1 = (to_y + 1.0) * y_scale;
+        from_y1 = min(from_y1, (PN_float32)orig_y_size);
+        
+        from_x0 = 0.0;
+        for (int to_x = 0; to_x < _x_size; ++to_x) {
+          from_x1 = (to_x + 1.0) * x_scale;
+          from_x1 = min(from_x1, (PN_float32)orig_x_size);
+          
+          // 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).
+          LPoint2f result;
+          from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
+          new_data.push_back(result[0]);
+          new_data.push_back(result[1]);
+          
+          from_x0 = from_x1;
+        }
+        from_y0 = from_y1;
+      }
+    }
+    break;
+
   case 3:
   case 3:
     {
     {
       from_y0 = 0.0;
       from_y0 = 0.0;
@@ -1725,6 +1762,14 @@ compute_sample_point(LPoint3f &result,
     }
     }
     break;
     break;
 
 
+  case 2:
+    {
+      LPoint2f result2;
+      box_filter_region(result2, x - xr, y - yr, x + xr, y + yr);
+      result.set(result2[0], result2[1], 0.0);
+    }
+    break;
+
   case 3:
   case 3:
     box_filter_region(result, x - xr, y - yr, x + xr, y + yr);
     box_filter_region(result, x - xr, y - yr, x + xr, y + yr);
     break;
     break;
@@ -1860,6 +1905,51 @@ box_filter_region(PN_float32 &result,
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::box_filter_region
+//       Access: Private
+//  Description: Averages all the points in the rectangle from x0
+//               .. y0 to x1 .. y1 into result.  The region may be
+//               defined by floating-point boundaries; the result will
+//               be weighted by the degree of coverage of each
+//               included point.
+////////////////////////////////////////////////////////////////////
+void PfmFile::
+box_filter_region(LPoint2f &result,
+                  PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const {
+  result = LPoint2f::zero();
+  PN_float32 coverage = 0.0;
+
+  if (x1 < x0 || y1 < y0) {
+    return;
+  }
+  nassertv(y0 >= 0.0 && y1 >= 0.0);
+
+  int y = (int)y0;
+  // Get the first (partial) row
+  box_filter_line(result, coverage, x0, y, x1, (PN_float32)(y+1)-y0);
+
+  int y_last = (int)y1;
+  if (y < y_last) {
+    y++;
+    while (y < y_last) {
+      // Get each consecutive (complete) row
+      box_filter_line(result, coverage, x0, y, x1, 1.0);
+      y++;
+    }
+
+    // Get the final (partial) row
+    PN_float32 y_contrib = y1 - (PN_float32)y_last;
+    if (y_contrib > 0.0001) {
+      box_filter_line(result, coverage, x0, y, x1, y_contrib);
+    }
+  }
+
+  if (coverage != 0.0) {
+    result /= coverage;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::box_filter_region
 //     Function: PfmFile::box_filter_region
 //       Access: Private
 //       Access: Private
@@ -1979,6 +2069,35 @@ box_filter_line(PN_float32 &result, PN_float32 &coverage,
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::box_filter_line
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PfmFile::
+box_filter_line(LPoint2f &result, PN_float32 &coverage,
+                PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const {
+  int x = (int)x0;
+  // Get the first (partial) xel
+  box_filter_point(result, coverage, x, y, (PN_float32)(x+1)-x0, y_contrib);
+
+  int x_last = (int)x1;
+  if (x < x_last) {
+    x++;
+    while (x < x_last) {
+      // Get each consecutive (complete) xel
+      box_filter_point(result, coverage, x, y, 1.0, y_contrib);
+      x++;
+    }
+
+    // Get the final (partial) xel
+    PN_float32 x_contrib = x1 - (PN_float32)x_last;
+    if (x_contrib > 0.0001) {
+      box_filter_point(result, coverage, x, y, x_contrib, y_contrib);
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::box_filter_line
 //     Function: PfmFile::box_filter_line
 //       Access: Private
 //       Access: Private
@@ -2055,6 +2174,24 @@ box_filter_point(PN_float32 &result, PN_float32 &coverage,
   coverage += contrib;
   coverage += contrib;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::box_filter_point
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PfmFile::
+box_filter_point(LPoint2f &result, PN_float32 &coverage,
+                 int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const {
+  if (!has_point(x, y)) {
+    return;
+  }
+  const LPoint2f &point = get_point2(x, y);
+
+  PN_float32 contrib = x_contrib * y_contrib;
+  result += point * contrib;
+  coverage += contrib;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::box_filter_point
 //     Function: PfmFile::box_filter_point
 //       Access: Private
 //       Access: Private
@@ -2066,7 +2203,7 @@ box_filter_point(LPoint3f &result, PN_float32 &coverage,
   if (!has_point(x, y)) {
   if (!has_point(x, y)) {
     return;
     return;
   }
   }
-  const LPoint3f &point = get_point(x, y);
+  const LPoint3f &point = get_point3(x, y);
 
 
   PN_float32 contrib = x_contrib * y_contrib;
   PN_float32 contrib = x_contrib * y_contrib;
   result += point * contrib;
   result += point * contrib;

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

@@ -29,7 +29,7 @@ class PNMWriter;
 //       Class : PfmFile
 //       Class : PfmFile
 // Description : Defines a pfm file, a 2-d table of floating-point
 // Description : Defines a pfm file, a 2-d table of floating-point
 //               numbers, either 3-component or 1-component, or with a
 //               numbers, either 3-component or 1-component, or with a
-//               special extension, 4-component.
+//               special extension, 2- or 4-component.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA_PNMIMAGE PfmFile : public PNMImageHeader {
 class EXPCL_PANDA_PNMIMAGE PfmFile : public PNMImageHeader {
 PUBLISHED:
 PUBLISHED:
@@ -147,18 +147,24 @@ private:
 
 
   void box_filter_region(PN_float32 &result,
   void box_filter_region(PN_float32 &result,
                          PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
                          PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
+  void box_filter_region(LPoint2f &result,
+                         PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
   void box_filter_region(LPoint3f &result,
   void box_filter_region(LPoint3f &result,
                          PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
                          PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
   void box_filter_region(LPoint4f &result,
   void box_filter_region(LPoint4f &result,
                          PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
                          PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
   void box_filter_line(PN_float32 &result, PN_float32 &coverage,
   void box_filter_line(PN_float32 &result, PN_float32 &coverage,
                        PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const;
                        PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const;
+  void box_filter_line(LPoint2f &result, PN_float32 &coverage,
+                       PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const;
   void box_filter_line(LPoint3f &result, PN_float32 &coverage,
   void box_filter_line(LPoint3f &result, PN_float32 &coverage,
                        PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const;
                        PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const;
   void box_filter_line(LPoint4f &result, PN_float32 &coverage,
   void box_filter_line(LPoint4f &result, PN_float32 &coverage,
                        PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const;
                        PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const;
   void box_filter_point(PN_float32 &result, PN_float32 &coverage,
   void box_filter_point(PN_float32 &result, PN_float32 &coverage,
                         int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const;
                         int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const;
+  void box_filter_point(LPoint2f &result, PN_float32 &coverage,
+                        int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const;
   void box_filter_point(LPoint3f &result, PN_float32 &coverage,
   void box_filter_point(LPoint3f &result, PN_float32 &coverage,
                         int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const;
                         int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const;
   void box_filter_point(LPoint4f &result, PN_float32 &coverage,
   void box_filter_point(LPoint4f &result, PN_float32 &coverage,

+ 8 - 0
panda/src/pnmimagetypes/pnmFileTypePfm.cxx

@@ -150,6 +150,10 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
   } else if (magic_number == "Pf") {
   } else if (magic_number == "Pf") {
     _num_channels = 1;
     _num_channels = 1;
 
 
+  } else if (magic_number == "pf2c") {
+    // Special DRZ extension.
+    _num_channels = 2;
+
   } else if (magic_number == "pf4c") {
   } else if (magic_number == "pf4c") {
     // Special DRZ extension.
     // Special DRZ extension.
     _num_channels = 4;
     _num_channels = 4;
@@ -299,6 +303,10 @@ write_pfm(const PfmFile &pfm) {
     (*_file) << "Pf\n";
     (*_file) << "Pf\n";
     break;
     break;
 
 
+  case 2:
+    (*_file) << "pf2c\n";
+    break;
+
   case 3:
   case 3:
     (*_file) << "PF\n";
     (*_file) << "PF\n";
     break;
     break;