Browse Source

*** empty log message ***

David Rose 25 years ago
parent
commit
0b8e32771e

+ 4 - 4
pandatool/src/eggbase/eggWriter.cxx

@@ -104,24 +104,24 @@ add_normals_options() {
   static NormalsMode preserve = NM_preserve;
 
   add_option
-    ("no", "", 49, 
+    ("no", "", 48, 
      "Strip all normals.",
      &EggWriter::dispatch_normals, NULL, &strip);
 
   add_option
-    ("np", "", 49, 
+    ("np", "", 48, 
      "Strip existing normals and redefine polygon normals.",
      &EggWriter::dispatch_normals, NULL, &polygon);
 
   add_option
-    ("nv", "threshold", 49, 
+    ("nv", "threshold", 48, 
      "Strip existing normals and redefine vertex normals.  Consider an edge "
      "between adjacent polygons to be smooth if the angle between them "
      "is less than threshold degrees.",
      &EggWriter::dispatch_normals, NULL, &vertex);
 
   add_option
-    ("nn", "", 49, 
+    ("nn", "", 48, 
      "Preserve normals exactly as they are.  This is the default.",
      &EggWriter::dispatch_normals, NULL, &preserve);
 }

+ 57 - 2
pandatool/src/eggbase/somethingToEgg.cxx

@@ -34,12 +34,49 @@ SomethingToEgg(const string &format_name,
   redescribe_option
     ("cs",
      "Specify the coordinate system of the input " + _format_name +
-     "file.  Normally, this can inferred from the file itself.");
+     " file.  Normally, this can inferred from the file itself.");
+
+  add_option
+    ("ui", "units", 40, 
+     "Specify the units of the input " + _format_name +
+     " file.  Normally, this can be inferred from the file itself.",
+     &SomethingToEgg::dispatch_units, NULL, &_input_units);
+
+  add_option
+    ("uo", "units", 40, 
+     "Specify the units of the resulting egg file.  If this is "
+     "specified, the vertices in the egg file will be scaled as "
+     "necessary to make the appropriate units conversion; otherwise, "
+     "the vertices in the input file will be converted exactly as they are.",
+     &SomethingToEgg::dispatch_units, NULL, &_output_units);
+
+  _input_units = DU_invalid;
+  _output_units = DU_invalid;
+
+  add_transform_options();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SomethingToEgg::apply_units_scale
+//       Access: Protected
+//  Description: Applies the scale indicated by the input and output
+//               units to the indicated egg file.  This is normally
+//               done automatically when the file is written out.
+////////////////////////////////////////////////////////////////////
+void SomethingToEgg::
+apply_units_scale(EggData &data) {
+  if (_output_units != DU_invalid && _input_units != DU_invalid &&
+      _input_units != _output_units) {
+    nout << "Converting from " << format_long_unit(_input_units)
+	 << " to " << format_long_unit(_output_units) << "\n";
+    double scale = convert_units(_input_units, _output_units);
+    data.transform(LMatrix4d::scale_mat(scale));
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: SomethingToEgg::handle_args
-//       Access: Public
+//       Access: Protected
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 bool SomethingToEgg::
@@ -85,3 +122,21 @@ handle_args(Args &args) {
 
   return true;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: SomethingToEgg::post_process_egg_file
+//       Access: Protected, Virtual
+//  Description: Performs any processing of the egg file that is
+//               appropriate before writing it out.  This includes any
+//               normal adjustments the user requested via -np, etc.
+//
+//               Normally, you should not need to call this function
+//               directly; write_egg_file() calls it for you.  You
+//               should call this only if you do not use
+//               write_egg_file() to write out the resulting egg file.
+////////////////////////////////////////////////////////////////////
+void SomethingToEgg::
+post_process_egg_file() {
+  apply_units_scale(_data);
+  EggConverter::post_process_egg_file();
+}

+ 9 - 0
pandatool/src/eggbase/somethingToEgg.h

@@ -10,6 +10,9 @@
 
 #include "eggConverter.h"
 
+#include <distanceUnit.h>
+
+
 ////////////////////////////////////////////////////////////////////
 // 	 Class : SomethingToEgg
 // Description : This is the general base class for a file-converter
@@ -24,9 +27,15 @@ public:
 		 bool allow_stdout = true);
 
 protected:
+  void apply_units_scale(EggData &data);
+
   virtual bool handle_args(Args &args);
+  virtual void post_process_egg_file();
 
   Filename _input_filename;
+
+  DistanceUnit _input_units;
+  DistanceUnit _output_units;
 };
 
 #endif

+ 1 - 1
pandatool/src/flt/Sources.pp

@@ -1,6 +1,6 @@
 #begin ss_lib_target
   #define TARGET flt
-  #define LOCAL_LIBS pandatoolbase
+  #define LOCAL_LIBS progbase pandatoolbase
   #define OTHER_LIBS \
     mathutil:c linmath:c putil:c express:c panda:m dtoolconfig dtool
   #define UNIX_SYS_LIBS \

+ 30 - 0
pandatool/src/flt/fltHeader.cxx

@@ -306,6 +306,36 @@ check_version() const {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltHeader::get_units
+//       Access: Public
+//  Description: Returns the units indicated by the flt header, or
+//               DU_invalid if the units in the header are not
+//               understood.
+////////////////////////////////////////////////////////////////////
+DistanceUnit FltHeader::
+get_units() const {
+  switch (_vertex_units) {
+  case FltHeader::U_meters:
+    return DU_meters;
+    
+  case FltHeader::U_kilometers:
+    return DU_kilometers;
+    
+  case FltHeader::U_feet:
+    return DU_feet;
+    
+  case FltHeader::U_inches:
+    return DU_inches;
+    
+  case FltHeader::U_nautical_miles:
+    return DU_nautical_miles;
+  }
+
+  // Unknown units.
+  return DU_invalid;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltHeader::has_instance
 //       Access: Public

+ 2 - 0
pandatool/src/flt/fltHeader.h

@@ -19,6 +19,7 @@
 
 #include <filename.h>
 #include <dSearchPath.h>
+#include <distanceUnit.h>
 
 ////////////////////////////////////////////////////////////////////
 // 	 Class : FltHeader
@@ -133,6 +134,7 @@ public:
   static double max_flt_version();
   bool check_version() const;
 
+  DistanceUnit get_units() const;
 
   // Accessors into the instance pool.
   bool has_instance(int instance_index) const;

+ 2 - 1
pandatool/src/flt/fltRecord.cxx

@@ -257,7 +257,8 @@ has_comment() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: FltRecord::get_comment
 //       Access: Public
-//  Description: Retrieves the comment for this record.
+//  Description: Retrieves the comment for this record, or empty
+//               string if the record has no comment.
 ////////////////////////////////////////////////////////////////////
 const string &FltRecord::
 get_comment() const {

+ 24 - 11
pandatool/src/fltegg/fltToEggConverter.I

@@ -14,24 +14,37 @@ INLINE FltToEggConverter::
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: FltToEggConverter::set_input_units
+//     Function: FltToEggConverter::set_texture_path_convert
 //       Access: Public
-//  Description: Sets the units the input flt file is considered to
-//               represent.  If this is unset or DU_invalid, the units
-//               are taken from the flt header.
+//  Description: Sets the mode for converting texture paths extracted
+//               from the flt file.  If this is PC_relative, the
+//               texture paths are made relative to the indicated
+//               directory; if it is PC_absolute, they are made
+//               absolute to the indicated directory.  PC_unchanged
+//               leaves them alone (and the directory, if specified,
+//               is ignored).
 ////////////////////////////////////////////////////////////////////
 INLINE void FltToEggConverter::
-set_input_units(DistanceUnit input_units) {
-  _input_units = input_units;
+set_texture_path_convert(PathConvert tpc,
+			 const Filename &tpc_directory) {
+  _tpc = tpc;
+  _tpc_directory = tpc_directory;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: FltToEggConverter::set_output_units
+//     Function: FltToEggConverter::set_model_path_convert
 //       Access: Public
-//  Description: Sets the units to generate in the resulting egg file.
-//               If this is unset, no units conversion is performed.
+//  Description: Sets the mode for converting model paths extracted
+//               from the flt file.  If this is PC_relative, the
+//               model paths are made relative to the indicated
+//               directory; if it is PC_absolute, they are made
+//               absolute to the indicated directory.  PC_unchanged
+//               leaves them alone (and the directory, if specified,
+//               is ignored).
 ////////////////////////////////////////////////////////////////////
 INLINE void FltToEggConverter::
-set_output_units(DistanceUnit output_units) {
-  _output_units = output_units;
+set_model_path_convert(PathConvert mpc,
+		       const Filename &mpc_directory) {
+  _mpc = mpc;
+  _mpc_directory = mpc_directory;
 }

+ 287 - 35
pandatool/src/fltegg/fltToEggConverter.cxx

@@ -33,8 +33,8 @@
 ////////////////////////////////////////////////////////////////////
 FltToEggConverter::
 FltToEggConverter(EggData &egg_data) : _egg_data(egg_data) {
-  _input_units = DU_invalid;
-  _output_units = DU_invalid;
+  _tpc = PC_unchanged;
+  _mpc = PC_unchanged;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -47,30 +47,6 @@ bool FltToEggConverter::
 convert_flt(const FltHeader *flt_header) {
   _error = false;
   _flt_header = flt_header;
-  
-  if (_input_units == DU_invalid) {
-    switch (_flt_header->_vertex_units) {
-    case FltHeader::U_meters:
-      _input_units = DU_meters;
-      break;
-
-    case FltHeader::U_kilometers:
-      _input_units = DU_kilometers;
-      break;
-
-    case FltHeader::U_feet:
-      _input_units = DU_feet;
-      break;
-
-    case FltHeader::U_inches:
-      _input_units = DU_inches;
-      break;
-
-    case FltHeader::U_nautical_miles:
-      _input_units = DU_nautical_miles;
-      break;
-    }
-  }
 
   // Generate a default vertex pool.
   _main_egg_vpool = new EggVertexPool("vpool");
@@ -245,7 +221,7 @@ convert_bead(const FltBead *flt_bead, FltToEggLevelState &state) {
   state._egg_parent->add_child(egg_group);
 
   set_transform(flt_bead, egg_group);
-  parse_comment(flt_bead, "anonymous", egg_group);
+  parse_comment(flt_bead, egg_group);
 
   FltToEggLevelState next_state(state);
   next_state._egg_parent = egg_group;
@@ -312,7 +288,12 @@ convert_ext_ref(const FltExternalReference *flt_ext, FltToEggLevelState &state)
   EggGroupNode *egg_parent = 
     state.get_synthetic_group("", flt_ext->get_transform());
 
-  Filename filename = flt_ext->get_ref_filename();
+  Filename filename = 
+    convert_path(flt_ext->_filename,
+		 flt_ext->get_ref_filename(),
+		 _mpc_directory,
+		 _mpc);
+
   filename.set_extension("egg");
 
   EggExternalReference *egg_ref = new EggExternalReference("", filename);
@@ -335,7 +316,8 @@ setup_geometry(const FltGeometry *flt_geom, FltToEggLevelState &state,
 
   // Determine what the appropriate parent will be.
   EggGroupNode *egg_parent = 
-    state.get_synthetic_group(flt_geom->get_id(), flt_geom->get_transform());
+    state.get_synthetic_group(flt_geom->get_id(), flt_geom->get_transform(),
+			      flt_geom->_billboard_type);
 
   // Create a new state to reflect the new parent.
   FltToEggLevelState next_state(state);
@@ -499,7 +481,35 @@ set_transform(const FltBead *flt_bead, EggGroup *egg_group) {
 ////////////////////////////////////////////////////////////////////
 bool FltToEggConverter::
 parse_comment(const FltBeadID *flt_bead, EggNode *egg_node) {
-  return parse_comment(flt_bead, flt_bead->get_id(), egg_node);
+  return parse_comment(flt_bead->get_comment(), flt_bead->get_id(), egg_node);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::parse_comment
+//       Access: Private
+//  Description: Scans the comment on this record for "<egg> { ... }"
+//               and parses the enclosed string as if it appeared in
+//               the egg file.  Returns true on success, false on
+//               syntax error (in which case _error is also set to
+//               true).
+////////////////////////////////////////////////////////////////////
+bool FltToEggConverter::
+parse_comment(const FltBead *flt_bead, EggNode *egg_node) {
+  return parse_comment(flt_bead->get_comment(), "anonymous", egg_node);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::parse_comment
+//       Access: Private
+//  Description: Scans the comment on this record for "<egg> { ... }"
+//               and parses the enclosed string as if it appeared in
+//               the egg file.  Returns true on success, false on
+//               syntax error (in which case _error is also set to
+//               true).
+////////////////////////////////////////////////////////////////////
+bool FltToEggConverter::
+parse_comment(const FltTexture *flt_texture, EggNode *egg_node) {
+  return parse_comment(flt_texture->_comment, flt_texture->_filename, egg_node);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -512,13 +522,12 @@ parse_comment(const FltBeadID *flt_bead, EggNode *egg_node) {
 //               true).
 ////////////////////////////////////////////////////////////////////
 bool FltToEggConverter::
-parse_comment(const FltRecord *flt_record, const string &name,
+parse_comment(const string &comment, const string &name,
 	      EggNode *egg_node) {
-  if (!flt_record->has_comment()) {
+  if (comment.empty()) {
     // No comment.
     return true;
   }
-  string comment = flt_record->get_comment();
 
   // Scan for <egg>.
   static const string egg_str = "<egg>";
@@ -574,6 +583,59 @@ parse_comment(const FltRecord *flt_record, const string &name,
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEggConverter::convert_path
+//       Access: Private, Static
+//  Description: Converts the pathname reference by the flt file as
+//               requested.  This may either make it absolute,
+//               relative, or leave it alone.
+//
+//               orig_filename is the filename as it actually appeared
+//               in the flt file; as_found is the full pathname to the
+//               file as it actually exists on disk, assuming it was
+//               found on the search path.  rel_dir is the directory
+//               to make the pathname relative to in the case of
+//               PC_relative or PC_rel_abs.
+////////////////////////////////////////////////////////////////////
+Filename FltToEggConverter::
+convert_path(const Filename &orig_filename, const Filename &as_found,
+	     const Filename &rel_dir, PathConvert path_convert) {
+  Filename result;
+
+  switch (path_convert) {
+  case PC_relative:
+    result = as_found;
+    if (!result.make_relative_to(rel_dir)) {
+      nout << "Cannot make " << result << " relative to " << rel_dir << "\n";
+    }
+    return result;
+
+  case PC_absolute:
+    result = as_found;
+    if (as_found.is_local()) {
+      nout << "Warning: file " << as_found << " not found; cannot make absolute.\n";
+      return result;
+    }
+    result.make_absolute();
+    return result;
+
+  case PC_rel_abs:
+    result = as_found;
+    if (!result.make_relative_to(rel_dir)) {
+      nout << "Cannot make " << result << " relative to " << rel_dir << "\n";
+    }
+    result = Filename(rel_dir, result);
+    return result;
+
+  case PC_unchanged:
+    return orig_filename;
+  }
+
+  // Error case.
+  nout << "Invalid PathConvert type: " << (int)path_convert << "\n";
+  return orig_filename;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltToEggConverter::make_egg_vertex
 //       Access: Private
@@ -619,12 +681,202 @@ make_egg_texture(const FltTexture *flt_texture) {
 
   // Create a new one.
   string tref_name = format_string(flt_texture->_pattern_index);
-  Filename filename = flt_texture->get_texture_filename();
+  Filename filename = 
+    convert_path(flt_texture->_filename,
+		 flt_texture->get_texture_filename(),
+		 _tpc_directory,
+		 _tpc);
+		 
   PT(EggTexture) egg_texture = new EggTexture(tref_name, filename);
 
   _textures.insert(Textures::value_type(flt_texture, egg_texture));
 
-  ////*** Texture properties.
+  // Set up the texture properties.
+
+  switch (flt_texture->_min_filter) {
+  case FltTexture::MN_point:
+    egg_texture->set_minfilter(EggTexture::FT_nearest);
+    break;
+
+  case FltTexture::MN_bilinear:
+    egg_texture->set_minfilter(EggTexture::FT_linear);
+    break;
+
+  case FltTexture::MN_mipmap_point:
+    egg_texture->set_minfilter(EggTexture::FT_nearest_mipmap_nearest);
+    break;
+
+  case FltTexture::MN_mipmap_linear:
+    egg_texture->set_minfilter(EggTexture::FT_nearest_mipmap_linear);
+    break;
+
+  case FltTexture::MN_mipmap_bilinear:
+    egg_texture->set_minfilter(EggTexture::FT_linear_mipmap_nearest);
+    break;
+
+  case FltTexture::MN_mipmap_trilinear:
+  case FltTexture::MN_OB_mipmap:
+    egg_texture->set_minfilter(EggTexture::FT_linear_mipmap_linear);
+    break;
+
+  case FltTexture::MN_bicubic:
+  case FltTexture::MN_bilinear_gequal:
+  case FltTexture::MN_bilinear_lequal:
+  case FltTexture::MN_bicubic_gequal:
+  case FltTexture::MN_bicubic_lequal:
+    // Not supported.
+    break;
+  }
+ 
+  switch (flt_texture->_mag_filter) {
+  case FltTexture::MG_point:
+    egg_texture->set_magfilter(EggTexture::FT_nearest);
+    break;
+
+  case FltTexture::MG_bilinear:
+    egg_texture->set_magfilter(EggTexture::FT_linear);
+    break;
+
+  case FltTexture::MG_bicubic:
+  case FltTexture::MG_sharpen:
+  case FltTexture::MG_add_detail:
+  case FltTexture::MG_modulate_detail:
+  case FltTexture::MG_bilinear_gequal:
+  case FltTexture::MG_bilinear_lequal:
+  case FltTexture::MG_bicubic_gequal:
+  case FltTexture::MG_bicubic_lequal:
+    // Not supported.
+    break;
+  }
+
+  switch (flt_texture->_repeat) {
+  case FltTexture::RT_repeat:
+    egg_texture->set_wrap_mode(EggTexture::WM_repeat);
+    break;
+
+  case FltTexture::RT_clamp:
+    egg_texture->set_wrap_mode(EggTexture::WM_clamp);
+    break;
+  }
+
+  switch (flt_texture->_repeat_u) {
+  case FltTexture::RT_repeat:
+    egg_texture->set_wrap_u(EggTexture::WM_repeat);
+    break;
+
+  case FltTexture::RT_clamp:
+    egg_texture->set_wrap_u(EggTexture::WM_clamp);
+    break;
+  }
+
+  switch (flt_texture->_repeat_v) {
+  case FltTexture::RT_repeat:
+    egg_texture->set_wrap_v(EggTexture::WM_repeat);
+    break;
+
+  case FltTexture::RT_clamp:
+    egg_texture->set_wrap_v(EggTexture::WM_clamp);
+    break;
+  }
+
+  switch (flt_texture->_env_type) {
+  case FltTexture::ET_modulate:
+    egg_texture->set_env_type(EggTexture::ET_modulate);
+    break;
+
+  case FltTexture::ET_decal:
+    egg_texture->set_env_type(EggTexture::ET_decal);
+    break;
+
+  case FltTexture::ET_blend:
+  case FltTexture::ET_color:
+    // Not supported.
+    break;
+  }
+
+  switch (flt_texture->_internal_format) {
+  case FltTexture::IF_default:
+    break;
+
+  case FltTexture::IF_i_12a_4:
+  case FltTexture::IF_ia_12:
+  case FltTexture::IF_ia_8:
+    egg_texture->set_format(EggTexture::F_luminance_alpha);
+    break;
+
+  case FltTexture::IF_rgb_5:
+    egg_texture->set_format(EggTexture::F_rgb5);
+    break;
+
+  case FltTexture::IF_rgba_4:
+    egg_texture->set_format(EggTexture::F_rgba4);
+    break;
+
+
+  case FltTexture::IF_rgba_8:
+    egg_texture->set_format(EggTexture::F_rgba8);
+    break;
+
+  case FltTexture::IF_rgba_12:
+    egg_texture->set_format(EggTexture::F_rgba12);
+    break;
+
+  case FltTexture::IF_i_16:
+    if (flt_texture->_intensity_is_alpha) {
+      egg_texture->set_format(EggTexture::F_alpha);
+    } else {
+      egg_texture->set_format(EggTexture::F_luminance);
+    }
+    break;
+
+  case FltTexture::IF_rgb_12:
+    egg_texture->set_format(EggTexture::F_rgb12);
+    break;
+  }
+ 
+  switch (flt_texture->_mag_filter_alpha) {
+  case FltTexture::MG_point:
+    egg_texture->set_magfilteralpha(EggTexture::FT_nearest);
+    break;
+
+  case FltTexture::MG_bilinear:
+    egg_texture->set_magfilteralpha(EggTexture::FT_linear);
+    break;
+
+  case FltTexture::MG_bicubic:
+  case FltTexture::MG_sharpen:
+  case FltTexture::MG_add_detail:
+  case FltTexture::MG_modulate_detail:
+  case FltTexture::MG_bilinear_gequal:
+  case FltTexture::MG_bilinear_lequal:
+  case FltTexture::MG_bicubic_gequal:
+  case FltTexture::MG_bicubic_lequal:
+    // Not supported.
+    break;
+  }
+ 
+  switch (flt_texture->_mag_filter_color) {
+  case FltTexture::MG_point:
+    egg_texture->set_magfiltercolor(EggTexture::FT_nearest);
+    break;
+
+  case FltTexture::MG_bilinear:
+    egg_texture->set_magfiltercolor(EggTexture::FT_linear);
+    break;
+
+  case FltTexture::MG_bicubic:
+  case FltTexture::MG_sharpen:
+  case FltTexture::MG_add_detail:
+  case FltTexture::MG_modulate_detail:
+  case FltTexture::MG_bilinear_gequal:
+  case FltTexture::MG_bilinear_lequal:
+  case FltTexture::MG_bicubic_gequal:
+  case FltTexture::MG_bicubic_lequal:
+    // Not supported.
+    break;
+  }
+
 
+  parse_comment(flt_texture, egg_texture);
   return egg_texture;
 }

+ 22 - 5
pandatool/src/fltegg/fltToEggConverter.h

@@ -45,8 +45,16 @@ public:
   FltToEggConverter(EggData &egg_data);
   INLINE ~FltToEggConverter();
 
-  INLINE void set_input_units(DistanceUnit input_units);
-  INLINE void set_output_units(DistanceUnit output_units);
+  enum PathConvert {
+    PC_relative,
+    PC_absolute,
+    PC_rel_abs,
+    PC_unchanged
+  };
+  INLINE void set_texture_path_convert(PathConvert tpc,
+				       const Filename &tpc_directory = Filename());
+  INLINE void set_model_path_convert(PathConvert mpc,
+				     const Filename &mpc_directory = Filename());
 
   bool convert_flt(const FltHeader *flt_header);
 
@@ -71,14 +79,23 @@ private:
 
   void set_transform(const FltBead *flt_bead, EggGroup *egg_group);
   bool parse_comment(const FltBeadID *flt_bead, EggNode *egg_node);
-  bool parse_comment(const FltRecord *flt_record, const string &name,
+  bool parse_comment(const FltBead *flt_bead, EggNode *egg_node);
+  bool parse_comment(const FltTexture *flt_texture, EggNode *egg_node);
+  bool parse_comment(const string &comment, const string &name,
 		     EggNode *egg_node);
 
+  static Filename convert_path(const Filename &orig_filename,
+			       const Filename &as_found,
+			       const Filename &rel_dir,
+			       PathConvert path_convert);
+
   PT(EggVertex) make_egg_vertex(const FltVertex *flt_vertex);
   PT(EggTexture) make_egg_texture(const FltTexture *flt_texture);
 
-  DistanceUnit _input_units;
-  DistanceUnit _output_units;
+  PathConvert _tpc;
+  Filename _tpc_directory;
+  PathConvert _mpc;
+  Filename _mpc_directory;
 
   EggData &_egg_data;
   CPT(FltHeader) _flt_header;

+ 139 - 9
pandatool/src/fltprogs/fltToEgg.cxx

@@ -19,21 +19,83 @@ FltToEgg() :
   add_normals_options();
 
   set_program_description
-    ("This program converts MultiGen OpenFlight (.flt) files to egg.  "
-     "Nothing fancy yet.");
+    ("This program converts MultiGen OpenFlight (.flt) files to egg.  Most "
+     "features of MultiGen that are also recognized by egg are supported.");
 
   add_option
-    ("tp", "path", 0, 
-     "Add the indicated colon-delimited paths to the path that is searched "
-     "for textures referenced by the flt file.  This "
-     "option may also be repeated to add multiple paths.",
-     &FltToEgg::dispatch_search_path, NULL, &_texture_path);
+    ("rt", "", 0,
+     "Convert texture filenames to relative pathnames, relative to the "
+     "directory specified by -rd.",
+     &FltToEgg::dispatch_path_convert_relative, NULL, &_texture_path_convert);
+
+  add_option
+    ("rta", "", 0,
+     "Convert texture filenames to absolute pathnames.",
+     &FltToEgg::dispatch_path_convert_absolute, NULL, &_texture_path_convert);
+
+  add_option
+    ("rtA", "", 0,
+     "Convert texture filenames to absolute pathnames that begin with the "
+     "prefix specified by -rd.",
+     &FltToEgg::dispatch_path_convert_rel_abs, NULL, &_texture_path_convert);
+
+  add_option
+    ("rtu", "", 0,
+     "Leave texture filenames unchanged.  They will be relative if they "
+     "are relative in the flt file, or absolute if they are absolute in "
+     "the flt file.",
+     &FltToEgg::dispatch_path_convert_unchanged, NULL, &_texture_path_convert);
+
+  add_option
+    ("re", "", 0,
+     "Convert model filenames (external references) to relative pathnames, "
+     "relative to the directory specified by -rd.",
+     &FltToEgg::dispatch_path_convert_relative, NULL, &_model_path_convert);
+
+  add_option
+    ("rea", "", 0,
+     "Convert model filenames to absolute pathnames.",
+     &FltToEgg::dispatch_path_convert_absolute, NULL, &_model_path_convert);
+
+  add_option
+    ("reA", "", 0,
+     "Convert model filenames to absolute pathnames that begin with the "
+     "prefix specified by -rd.",
+     &FltToEgg::dispatch_path_convert_rel_abs, NULL, &_model_path_convert);
+
+  add_option
+    ("reu", "", 0,
+     "Leave model filenames unchanged.  They will be relative if they "
+     "are relative in the flt file, or absolute if they are absolute in "
+     "the flt file.",
+     &FltToEgg::dispatch_path_convert_unchanged, NULL, &_model_path_convert);
+
+  add_option
+    ("rd", "dir", 0,
+     "Specify the directory to make relative to.  This is the "
+     "directory that all pathnames given in the flt file will be "
+     "rewritten to be relative to, if -re or -rt is given.  It is "
+     "ignored if one of these options is not given.  If omitted, it "
+     "is taken from the source filename.",
+     &FltToEgg::dispatch_string, &_got_make_rel_dir, &_make_rel_dir);
+
+  add_option
+    ("rs", "path", 0, 
+     "A search path for textures and external file references.  This "
+     "is a colon-separated set of directories that will be searched "
+     "for filenames that are not fully specified in the flt file.  It "
+     "is unrelated to -re and -rt, and is used only if the flt file "
+     "does not store absolute pathnames.  The directory containing "
+     "the source filename is always implicitly included.",
+     &FltToEgg::dispatch_search_path, NULL, &_search_path);
 
   redescribe_option
     ("cs",
      "Specify the coordinate system of the input " + _format_name +
-     "file.  Normally, this is z-up.");
+     " file.  Normally, this is z-up.");
 
+  _texture_path_convert = FltToEggConverter::PC_unchanged;
+  _model_path_convert = FltToEggConverter::PC_unchanged;
   _coordinate_system = CS_zup_right;
 }
 
@@ -44,8 +106,13 @@ FltToEgg() :
 ////////////////////////////////////////////////////////////////////
 void FltToEgg::
 run() {
+  if (!_got_make_rel_dir) {
+    _make_rel_dir = _input_filename.get_dirname();
+  }
+
   PT(FltHeader) header = new FltHeader;
-  header->set_texture_path(_texture_path);
+  header->set_texture_path(_search_path);
+  header->set_model_path(_search_path);
 
   nout << "Reading " << _input_filename << "\n";
   FltError result = header->read_flt(_input_filename);
@@ -58,7 +125,14 @@ run() {
 
   _data.set_coordinate_system(_coordinate_system);
 
+  if (_input_units == DU_invalid) {
+    _input_units = header->get_units();
+  }
+
   FltToEggConverter converter(_data);
+  converter.set_texture_path_convert(_texture_path_convert, _make_rel_dir);
+  converter.set_model_path_convert(_model_path_convert, _make_rel_dir);
+
   if (!converter.convert_flt(header)) {
     nout << "Errors in conversion.\n";
     exit(1);
@@ -68,6 +142,62 @@ run() {
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEgg::dispatch_path_convert_relative
+//       Access: Protected, Static
+//  Description: Dispatch function to set the given path convert mode
+//               to PC_relative.  var is a pointer to a
+//               FltToEggConverter::PathConvert variable.
+////////////////////////////////////////////////////////////////////
+bool FltToEgg::
+dispatch_path_convert_relative(const string &opt, const string &, void *var) {
+  FltToEggConverter::PathConvert *ip = (FltToEggConverter::PathConvert *)var;
+  (*ip) = FltToEggConverter::PC_relative;
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEgg::dispatch_path_convert_absolute
+//       Access: Protected, Static
+//  Description: Dispatch function to set the given path convert mode
+//               to PC_absolute.  var is a pointer to a
+//               FltToEggConverter::PathConvert variable.
+////////////////////////////////////////////////////////////////////
+bool FltToEgg::
+dispatch_path_convert_absolute(const string &opt, const string &, void *var) {
+  FltToEggConverter::PathConvert *ip = (FltToEggConverter::PathConvert *)var;
+  (*ip) = FltToEggConverter::PC_absolute;
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEgg::dispatch_path_convert_rel_abs
+//       Access: Protected, Static
+//  Description: Dispatch function to set the given path convert mode
+//               to PC_rel_abs.  var is a pointer to a
+//               FltToEggConverter::PathConvert variable.
+////////////////////////////////////////////////////////////////////
+bool FltToEgg::
+dispatch_path_convert_rel_abs(const string &opt, const string &, void *var) {
+  FltToEggConverter::PathConvert *ip = (FltToEggConverter::PathConvert *)var;
+  (*ip) = FltToEggConverter::PC_rel_abs;
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: FltToEgg::dispatch_path_convert_unchanged
+//       Access: Protected, Static
+//  Description: Dispatch function to set the given path convert mode
+//               to PC_unchanged.  var is a pointer to a
+//               FltToEggConverter::PathConvert variable.
+////////////////////////////////////////////////////////////////////
+bool FltToEgg::
+dispatch_path_convert_unchanged(const string &opt, const string &, void *var) {
+  FltToEggConverter::PathConvert *ip = (FltToEggConverter::PathConvert *)var;
+  (*ip) = FltToEggConverter::PC_unchanged;
+  return true;
+}
+
 int main(int argc, char *argv[]) {
   FltToEgg prog;
   prog.parse_command_line(argc, argv);

+ 12 - 1
pandatool/src/fltprogs/fltToEgg.h

@@ -9,6 +9,7 @@
 #include <pandatoolbase.h>
 
 #include <somethingToEgg.h>
+#include <fltToEggConverter.h>
 
 #include <dSearchPath.h>
 
@@ -24,7 +25,17 @@ public:
   void run();
 
 protected:
-  DSearchPath _texture_path;
+  static bool dispatch_path_convert_relative(const string &opt, const string &arg, void *var);
+  static bool dispatch_path_convert_absolute(const string &opt, const string &arg, void *var);
+  static bool dispatch_path_convert_rel_abs(const string &opt, const string &arg, void *var);
+  static bool dispatch_path_convert_unchanged(const string &opt, const string &arg, void *var);
+
+
+  DSearchPath _search_path;
+  FltToEggConverter::PathConvert _texture_path_convert;
+  FltToEggConverter::PathConvert _model_path_convert;
+  Filename _make_rel_dir;
+  bool _got_make_rel_dir;
 };
 
 #endif

+ 69 - 15
pandatool/src/progbase/distanceUnit.cxx

@@ -6,45 +6,99 @@
 #include "distanceUnit.h"
 
 #include <string_utils.h>
+#include <notify.h>
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DistanceUnit output operator
-//  Description: 
+//     Function: format_abbrev_unit
+//  Description: Returns the string representing the common
+//               abbreviation for the given unit.
 ////////////////////////////////////////////////////////////////////
-ostream &
-operator << (ostream &out, DistanceUnit unit) {
+string
+format_abbrev_unit(DistanceUnit unit) {
   switch (unit) {
   case DU_millimeters:
-    return out << "mm";
+    return "mm";
 
   case DU_centimeters:
-    return out << "cm";
+    return "cm";
 
   case DU_meters:
-    return out << "m";
+    return "m";
 
   case DU_kilometers:
-    return out << "km";
+    return "km";
 
   case DU_yards:
-    return out << "yd";
+    return "yd";
 
   case DU_feet:
-    return out << "ft";
+    return "ft";
 
   case DU_inches:
-    return out << "in";
+    return "in";
 
   case DU_nautical_miles:
-    return out << "nmi";
+    return "nmi";
 
   case DU_statute_miles:
-    return out << "mi";
+    return "mi";
 
   case DU_invalid:
-    return out << "invalid";
+    return "invalid";
   }
-  return out << "**unexpected DistanceUnit value: (" << (int)unit << ")**";
+  nout << "**unexpected DistanceUnit value: (" << (int)unit << ")**";
+  return "**";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: format_long_unit
+//  Description: Returns the string representing the full name (plural)
+//               for the given unit.
+////////////////////////////////////////////////////////////////////
+string
+format_long_unit(DistanceUnit unit) {
+  switch (unit) {
+  case DU_millimeters:
+    return "millimeters";
+
+  case DU_centimeters:
+    return "centimeters";
+
+  case DU_meters:
+    return "meters";
+
+  case DU_kilometers:
+    return "kilometers";
+
+  case DU_yards:
+    return "yards";
+
+  case DU_feet:
+    return "feet";
+
+  case DU_inches:
+    return "inches";
+
+  case DU_nautical_miles:
+    return "nautical miles";
+
+  case DU_statute_miles:
+    return "miles";
+
+  case DU_invalid:
+    return "invalid";
+  }
+  nout << "**unexpected DistanceUnit value: (" << (int)unit << ")**";
+  return "**";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DistanceUnit output operator
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ostream &
+operator << (ostream &out, DistanceUnit unit) {
+  return out << format_abbrev_unit(unit);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 0
pandatool/src/progbase/distanceUnit.h

@@ -27,6 +27,9 @@ enum DistanceUnit {
   DU_invalid
 };
 
+string format_abbrev_unit(DistanceUnit unit);
+string format_long_unit(DistanceUnit unit);
+
 ostream &operator << (ostream &out, DistanceUnit unit);
 DistanceUnit string_distance_unit(const string &str);