Browse Source

some more texture/pfm integration

David Rose 13 years ago
parent
commit
2ff43ca88e

+ 60 - 0
panda/src/gobj/texture.I

@@ -315,6 +315,42 @@ load(const PNMImage &pnmimage, int z, int n, const LoaderOptions &options) {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::load
+//       Access: Published
+//  Description: Replaces the texture with the indicated image.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+load(const PfmFile &pfm, const LoaderOptions &options) {
+  CDWriter cdata(_cycler, true);
+  do_clear(cdata);
+  ++(cdata->_properties_modified);
+  ++(cdata->_image_modified);
+  if (do_load_one(cdata, pfm, get_name(), 0, 0, options)) {
+    bool generate_mipmaps = ((options.get_texture_flags() & LoaderOptions::TF_generate_mipmaps) != 0);
+    consider_auto_process_ram_image(generate_mipmaps || uses_mipmaps(), true);
+    return true;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::load
+//       Access: Published
+//  Description: Stores the indicated image in the given page and
+//               mipmap level.  See read().
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+load(const PfmFile &pfm, int z, int n, const LoaderOptions &options) {
+  CDWriter cdata(_cycler, true);
+  ++(cdata->_properties_modified);
+  ++(cdata->_image_modified);
+  if (do_load_one(cdata, pfm, get_name(), z, n, options)) {
+    return true;
+  }
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::store
 //       Access: Published
@@ -339,6 +375,30 @@ store(PNMImage &pnmimage, int z, int n) const {
   return ((Texture *)this)->do_store_one(cdata, pnmimage, z, n);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::store
+//       Access: Published
+//  Description: Saves the texture to the indicated PfmFile, but does
+//               not write it to disk.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+store(PfmFile &pfm) const {
+  CDWriter cdata(((Texture *)this)->_cycler, false);
+  return ((Texture *)this)->do_store_one(cdata, pfm, 0, 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Texture::store
+//       Access: Published
+//  Description: Saves the indicated page and mipmap level of the
+//               texture to the PfmFile.
+////////////////////////////////////////////////////////////////////
+INLINE bool Texture::
+store(PfmFile &pfm, int z, int n) const {
+  CDWriter cdata(((Texture *)this)->_cycler, false);
+  return ((Texture *)this)->do_store_one(cdata, pfm, z, n);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Texture::reload
 //       Access: Published

+ 38 - 6
panda/src/gobj/texture.cxx

@@ -2924,10 +2924,8 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
   }
   image.copy_header_from(*image_reader);
 
-  // If it's a single-channel floating-point image file, read it by
-  // default into a floating-point texture.  (Multi-channel image
-  // files are ready as integers by default, since current graphics
-  // API's don't support multi-channel float textures.)
+  // If it's a floating-point image file, read it by default into a
+  // floating-point texture.
   bool read_floating_point;
   int texture_load_type = (options.get_texture_flags() & (LoaderOptions::TF_integer | LoaderOptions::TF_float));
   switch (texture_load_type) {
@@ -2942,7 +2940,7 @@ do_read_one(CData *cdata, const Filename &fullpath, const Filename &alpha_fullpa
   default:
     // Neither TF_integer nor TF_float was specified; determine which
     // way the texture wants to be loaded.
-    read_floating_point = (image_reader->is_floating_point() && image_reader->get_num_channels() == 1);
+    read_floating_point = (image_reader->is_floating_point());
     if (!alpha_fullpath.empty()) {
       read_floating_point = false;
     }
@@ -3843,6 +3841,21 @@ do_store_one(CData *cdata, PNMImage &pnmimage, int z, int n) {
   nassertr(z >= 0 && z < do_get_expected_mipmap_num_pages(cdata, n), false);
   nassertr(cdata->_ram_image_compression == CM_off, false);
 
+  if (cdata->_component_type == T_float) {
+    // PNMImage by way of PfmFile.
+    PfmFile pfm;
+    bool success = convert_to_pfm(pfm,
+                                  do_get_expected_mipmap_x_size(cdata, n),
+                                  do_get_expected_mipmap_y_size(cdata, n),
+                                  cdata->_num_components, cdata->_component_width,
+                                  cdata->_ram_images[n]._image,
+                                  do_get_ram_mipmap_page_size(cdata, n), z);
+    if (!success) {
+      return false;
+    }
+    return pfm.store(pnmimage);
+  }
+
   return convert_to_pnmimage(pnmimage,
                              do_get_expected_mipmap_x_size(cdata, n),
                              do_get_expected_mipmap_y_size(cdata, n),
@@ -3869,6 +3882,21 @@ do_store_one(CData *cdata, PfmFile &pfm, int z, int n) {
   nassertr(z >= 0 && z < do_get_expected_mipmap_num_pages(cdata, n), false);
   nassertr(cdata->_ram_image_compression == CM_off, false);
 
+  if (cdata->_component_type != T_float) {
+    // PfmFile by way of PNMImage.
+    PNMImage pnmimage;
+    bool success = convert_to_pnmimage(pnmimage,
+                                       do_get_expected_mipmap_x_size(cdata, n),
+                                       do_get_expected_mipmap_y_size(cdata, n),
+                                       cdata->_num_components, cdata->_component_width,
+                                       cdata->_ram_images[n]._image,
+                                       do_get_ram_mipmap_page_size(cdata, n), z);
+    if (!success) {
+      return false;
+    }
+    return pfm.load(pnmimage);
+  }
+
   return convert_to_pfm(pfm,
                         do_get_expected_mipmap_x_size(cdata, n),
                         do_get_expected_mipmap_y_size(cdata, n),
@@ -5901,7 +5929,11 @@ bool Texture::
 convert_to_pnmimage(PNMImage &pnmimage, int x_size, int y_size,
                     int num_components, int component_width,
                     CPTA_uchar image, size_t page_size, int z) {
-  pnmimage.clear(x_size, y_size, num_components);
+  xelval maxval = 0xff;
+  if (component_width > 1) {
+    maxval = 0xffff;
+  }
+  pnmimage.clear(x_size, y_size, num_components, maxval);
   bool has_alpha = pnmimage.has_alpha();
   bool is_grayscale = pnmimage.is_grayscale();
 

+ 4 - 0
panda/src/gobj/texture.h

@@ -260,8 +260,12 @@ PUBLISHED:
 
   BLOCKING INLINE bool load(const PNMImage &pnmimage, const LoaderOptions &options = LoaderOptions());
   BLOCKING INLINE bool load(const PNMImage &pnmimage, int z, int n, const LoaderOptions &options = LoaderOptions());
+  BLOCKING INLINE bool load(const PfmFile &pfm, const LoaderOptions &options = LoaderOptions());
+  BLOCKING INLINE bool load(const PfmFile &pfm, int z, int n, const LoaderOptions &options = LoaderOptions());
   BLOCKING INLINE bool store(PNMImage &pnmimage) const;
   BLOCKING INLINE bool store(PNMImage &pnmimage, int z, int n) const;
+  BLOCKING INLINE bool store(PfmFile &pfm) const;
+  BLOCKING INLINE bool store(PfmFile &pfm, int z, int n) const;
 
   BLOCKING INLINE bool reload();
   BLOCKING Texture *load_related(const InternalName *suffix) const;

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

@@ -113,6 +113,76 @@ set_point1(int x, int y, PN_float32 point) {
   _table[(y * _x_size + x) * _num_channels] = point;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::get_point2
+//       Access: Published
+//  Description: Returns the 2-component point value at the indicated
+//               point.  In a 1-channel image, the channel value is in
+//               the x component.
+////////////////////////////////////////////////////////////////////
+INLINE const LPoint2f &PfmFile::
+get_point2(int x, int y) const {
+  nassertr(x >= 0 && x < _x_size &&
+           y >= 0 && y < _y_size, LPoint2f::zero());
+  return *(LPoint2f *)&_table[(y * _x_size + x) * _num_channels];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::set_point2
+//       Access: Published
+//  Description: Replaces the 2-component point value at the indicated
+//               point.  In a 1-channel image, the channel value is in
+//               the x component.
+////////////////////////////////////////////////////////////////////
+INLINE void PfmFile::
+set_point2(int x, int y, const LVecBase2f &point) {
+  nassertv(!point.is_nan());
+  nassertv(x >= 0 && x < _x_size &&
+           y >= 0 && y < _y_size);
+  switch (_num_channels) {
+  case 1:
+    _table[(y * _x_size + x)] = point[0];
+    break;
+
+  case 3:
+    (*(LPoint3f *)&_table[(y * _x_size + x) * _num_channels]).set(point[0], point[1], point[2]);
+    break;
+
+  case 2:
+    *(LPoint2f *)&_table[(y * _x_size + x) * _num_channels] = point;
+    break;
+  } 
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::set_point2
+//       Access: Published
+//  Description: Replaces the 2-component point value at the indicated
+//               point.  In a 1-channel image, the channel value is in
+//               the x component.
+////////////////////////////////////////////////////////////////////
+INLINE void PfmFile::
+set_point2(int x, int y, const LVecBase2d &point) {
+  set_point2(x, y, LCAST(PN_float32, point));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::modify_point2
+//       Access: Published
+//  Description: Returns a modifiable 2-component point value at the
+//               indicated point.
+////////////////////////////////////////////////////////////////////
+INLINE LPoint2f &PfmFile::
+modify_point2(int x, int y) {
+#ifndef NDEBUG
+  static LPoint2f dummy_value = LPoint2f::zero();
+  nassertr(x >= 0 && x < _x_size &&
+           y >= 0 && y < _y_size, dummy_value);
+#endif
+
+  return *(LPoint2f *)&_table[(y * _x_size + x) * _num_channels];
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::get_point
 //       Access: Published

+ 71 - 3
panda/src/pnmimage/pfmFile.cxx

@@ -993,6 +993,27 @@ merge(const PfmFile &other) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::copy_channel
+//       Access: Published
+//  Description: Copies just the specified channel values from the
+//               indicated PfmFile (which could be same as this
+//               PfmFile) into the specified channel of this one.
+////////////////////////////////////////////////////////////////////
+void PfmFile::
+copy_channel(int to_channel, const PfmFile &other, int from_channel) {
+  nassertv(is_valid() && other.is_valid());
+  nassertv(other._x_size == _x_size && other._y_size == _y_size);
+  nassertv(to_channel >= 0 && to_channel < get_num_channels() &&
+           from_channel >= 0 && from_channel < other.get_num_channels());
+
+  for (int yi = 0; yi < _y_size; ++yi) {
+    for (int xi = 0; xi < _x_size; ++xi) {
+      set_component(xi, yi, to_channel, other.get_component(xi, yi, from_channel));
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::apply_crop
 //       Access: Published
@@ -1027,6 +1048,34 @@ apply_crop(int x_begin, int x_end, int y_begin, int y_end) {
   _y_size = new_y_size;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmFile::clear_to_texcoords
+//       Access: Published
+//  Description: Replaces this PfmFile with a new PfmFile of size
+//               x_size x y_size x 3, containing the x y 0 values in
+//               the range 0 .. 1 according to the x y index.
+////////////////////////////////////////////////////////////////////
+void PfmFile::
+clear_to_texcoords(int x_size, int y_size) {
+  clear(x_size, y_size, 3);
+
+  LPoint2f uv_scale(1.0, 1.0);
+  if (_x_size > 1) {
+    uv_scale[0] = 1.0f / PN_float32(_x_size - 1);
+  }
+  if (_y_size > 1) {
+    uv_scale[1] = 1.0f / PN_float32(_y_size - 1);
+  }
+
+  for (int yi = 0; yi < _y_size; ++yi) {
+    for (int xi = 0; xi < _x_size; ++xi) {
+      LPoint3f uv(PN_float32(xi) * uv_scale[0],
+                  PN_float32(yi) * uv_scale[1], 0.0f);
+      set_point(xi, yi, uv);
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::compute_planar_bounds
 //       Access: Published
@@ -1366,6 +1415,16 @@ generate_vis_mesh(MeshFace face) const {
   nassertr(is_valid(), NodePath());
   nassertr(face != 0, NodePath());
 
+  if (_num_channels == 1 && _vis_columns.empty()) {
+    // If we're generating a default mesh from a one-channel pfm file,
+    // expand it to a three-channel pfm file to make the visualization
+    // useful.
+    PfmFile expanded;
+    expanded.clear_to_texcoords(_x_size, _y_size);
+    expanded.copy_channel(2, *this, 0);
+    return expanded.generate_vis_mesh(face);
+  }
+  
   if (_x_size == 1 || _y_size == 1) {
     // Can't generate a 1-d mesh, so generate points in this case.
     return generate_vis_points();
@@ -1864,7 +1923,7 @@ build_auto_vis_columns(VisColumns &vis_columns, bool for_points) const {
 
   if (_vis_2d) {
     // No normals needed if we're just generating a 2-d mesh.
-    add_vis_column(vis_columns, CT_vertex3, CT_vertex3, InternalName::get_vertex());
+    add_vis_column(vis_columns, CT_vertex2, CT_vertex2, InternalName::get_vertex());
     add_vis_column(vis_columns, CT_texcoord2, CT_texcoord2, InternalName::get_texcoord());
 
   } else {
@@ -1920,6 +1979,7 @@ make_array_format(const VisColumns &vis_columns) const {
       contents = GeomEnums::C_texcoord;
       break;
 
+    case CT_vertex1:
     case CT_vertex2:
     case CT_vertex3:
       num_components = 3;
@@ -2069,10 +2129,18 @@ add_data(const PfmFile &file, GeomVertexWriter &vwriter, int xi, int yi, bool re
     }
     break;
 
+  case CT_vertex1:
+    {
+      PN_float32 p = file.get_point1(xi, yi);
+      LPoint2f point(p, 0.0);
+      transform_point(point);
+      vwriter.set_data2f(point);
+    }
+    break;
+
   case CT_vertex2:
     {
-      const LPoint3f &point3 = file.get_point(xi, yi);
-      LPoint2f point(point3[0], point3[1]);
+      LPoint2f point = file.get_point2(xi, yi);
       transform_point(point);
       vwriter.set_data2f(point);
     }

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

@@ -65,6 +65,10 @@ PUBLISHED:
   INLINE void set_component(int x, int y, int c, PN_float32 value);
   INLINE PN_float32 get_point1(int x, int y) const;
   INLINE void set_point1(int x, int y, PN_float32 point);
+  INLINE const LPoint2f &get_point2(int x, int y) const;
+  INLINE void set_point2(int x, int y, const LVecBase2f &point);
+  INLINE void set_point2(int x, int y, const LVecBase2d &point);
+  INLINE LPoint2f &modify_point2(int x, int y);
   INLINE const LPoint3f &get_point(int x, int y) const;
   INLINE void set_point(int x, int y, const LVecBase3f &point);
   INLINE void set_point(int x, int y, const LVecBase3d &point);
@@ -99,7 +103,9 @@ PUBLISHED:
   INLINE BLOCKING void xform(const LMatrix4d &transform);
   BLOCKING void project(const Lens *lens);
   BLOCKING void merge(const PfmFile &other);
+  BLOCKING void copy_channel(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 clear_to_texcoords(int x_size, int y_size);
 
   BLOCKING PT(BoundingHexahedron) compute_planar_bounds(const LPoint2f &center, PN_float32 point_dist, PN_float32 sample_radius, bool points_only) const;
   INLINE BLOCKING PT(BoundingHexahedron) compute_planar_bounds(const LPoint2d &center, PN_float32 point_dist, PN_float32 sample_radius, bool points_only) const;
@@ -117,6 +123,7 @@ PUBLISHED:
   enum ColumnType {
     CT_texcoord2,
     CT_texcoord3,
+    CT_vertex1,
     CT_vertex2,
     CT_vertex3,
     CT_normal3,