Browse Source

replace -rta, etc. options with -pr, -pp, -ps, -pd

David Rose 23 years ago
parent
commit
7481abba57
40 changed files with 1146 additions and 665 deletions
  1. 30 89
      pandatool/src/converter/somethingToEggConverter.I
  2. 9 84
      pandatool/src/converter/somethingToEggConverter.cxx
  3. 8 29
      pandatool/src/converter/somethingToEggConverter.h
  4. 1 1
      pandatool/src/egg-palettize/eggFile.cxx
  5. 35 1
      pandatool/src/eggbase/eggBase.cxx
  6. 9 4
      pandatool/src/eggbase/eggBase.h
  7. 8 1
      pandatool/src/eggbase/eggFilter.cxx
  8. 11 13
      pandatool/src/eggbase/eggMultiBase.cxx
  9. 11 2
      pandatool/src/eggbase/eggMultiFilter.cxx
  10. 12 8
      pandatool/src/eggbase/eggReader.cxx
  11. 5 0
      pandatool/src/eggbase/eggWriter.cxx
  12. 16 225
      pandatool/src/eggbase/somethingToEgg.cxx
  13. 3 22
      pandatool/src/eggbase/somethingToEgg.h
  14. 3 2
      pandatool/src/eggprogs/eggTrans.cxx
  15. 28 8
      pandatool/src/flt/fltExternalReference.cxx
  16. 3 2
      pandatool/src/flt/fltExternalReference.h
  17. 0 76
      pandatool/src/flt/fltHeader.cxx
  18. 0 14
      pandatool/src/flt/fltHeader.h
  19. 23 0
      pandatool/src/flt/fltRecord.cxx
  20. 7 4
      pandatool/src/flt/fltRecord.h
  21. 27 7
      pandatool/src/flt/fltTexture.cxx
  22. 2 0
      pandatool/src/flt/fltTexture.h
  23. 2 5
      pandatool/src/fltegg/fltToEggConverter.cxx
  24. 9 10
      pandatool/src/fltegg/fltToEggConverter.h
  25. 6 4
      pandatool/src/fltprogs/fltCopy.cxx
  26. 10 9
      pandatool/src/fltprogs/fltToEgg.cxx
  27. 4 7
      pandatool/src/fltprogs/fltTrans.cxx
  28. 3 6
      pandatool/src/fltprogs/fltTrans.h
  29. 7 9
      pandatool/src/lwoprogs/lwoToEgg.cxx
  30. 4 6
      pandatool/src/lwoprogs/lwoToEgg.h
  31. 6 2
      pandatool/src/mayaprogs/mayaCopy.cxx
  32. 5 6
      pandatool/src/mayaprogs/mayaToEgg.cxx
  33. 6 2
      pandatool/src/pandatoolbase/Sources.pp
  34. 161 0
      pandatool/src/pandatoolbase/pathReplace.I
  35. 278 0
      pandatool/src/pandatoolbase/pathReplace.cxx
  36. 108 0
      pandatool/src/pandatoolbase/pathReplace.h
  37. 90 0
      pandatool/src/pandatoolbase/pathStore.cxx
  38. 44 0
      pandatool/src/pandatoolbase/pathStore.h
  39. 134 0
      pandatool/src/progbase/programBase.cxx
  40. 18 7
      pandatool/src/progbase/programBase.h

+ 30 - 89
pandatool/src/converter/somethingToEggConverter.I

@@ -16,53 +16,43 @@
 //
 ////////////////////////////////////////////////////////////////////
 
+
 ////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEggConverter::set_texture_path_convert
+//     Function: SomethingToEggConverter::set_path_replace
 //       Access: Public
-//  Description: Sets the mode for converting texture paths extracted
-//               from the source file.  The following options are
-//               defined:
-//
-//                 PC_relative - texture pathnames are made relative
-//                 to the indicated tpc_directory.
-//
-//                 PC_absolute - textures are looked up along the
-//                 search path and then converted to absolute
-//                 filenames.  tpc_directory is ignored.
-//
-//                 PC_rel_abs - as above, but the resulting filename
-//                 is guaranteed to be relative to tpc_directory, and
-//                 may include a number of ../ paths to guarantee
-//                 this, if necessary.
-//
-//                 PC_strip - pathname components are stripped from
-//                 the texture names, and only the base filename is
-//                 retained.
-//
-//                 PC_unchanged - texture pathnames are left exactly
-//                 as they appear in the source file.
+//  Description: Replaces the PathReplace object (which specifies how
+//               to mangle paths from the source to the destination
+//               egg file) with a new one.
 ////////////////////////////////////////////////////////////////////
 INLINE void SomethingToEggConverter::
-set_texture_path_convert(PathConvert tpc,
-                         const Filename &tpc_directory) {
-  _tpc = tpc;
-  _tpc_directory = tpc_directory;
+set_path_replace(PathReplace *path_replace) {
+  _path_replace = path_replace;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEggConverter::set_model_path_convert
+//     Function: SomethingToEggConverter::get_path_replace
 //       Access: Public
-//  Description: Sets the mode for converting model paths extracted
-//               from the source file.  These are typically for
-//               external references.  See set_texture_path_convert
-//               for a complete list of PathConvert values and their
-//               interpretations.
+//  Description: Returns a pointer to the PathReplace object
+//               associated with this converter.  If the converter is
+//               non-const, this returns a non-const pointer, which
+//               can be adjusted.
 ////////////////////////////////////////////////////////////////////
-INLINE void SomethingToEggConverter::
-set_model_path_convert(PathConvert mpc,
-                       const Filename &mpc_directory) {
-  _mpc = mpc;
-  _mpc_directory = mpc_directory;
+INLINE PathReplace *SomethingToEggConverter::
+get_path_replace() {
+  return _path_replace;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SomethingToEggConverter::get_path_replace
+//       Access: Public
+//  Description: Returns a pointer to the PathReplace object
+//               associated with this converter.  If the converter is
+//               non-const, this returns a non-const pointer, which
+//               can be adjusted.
+////////////////////////////////////////////////////////////////////
+INLINE const PathReplace *SomethingToEggConverter::
+get_path_replace() const {
+  return _path_replace;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -486,29 +476,6 @@ get_egg_data() {
   return *_egg_data;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEggConverter::handle_external_reference
-//       Access: Public
-//  Description: Handles an external reference in the source file.  If
-//               the merge_externals flag is true (see
-//               set_merge_externals()), this causes the named file to
-//               be read in and converted, and the converted egg
-//               geometry is parented to egg_parent.  Otherwise, only
-//               a reference to a similarly named egg file is parented
-//               to egg_parent.
-//
-//               The parameters orig_filename and searchpath are as
-//               those passed to convert_model_path().
-//
-//               Returns true on success, false on failure.
-////////////////////////////////////////////////////////////////////
-bool SomethingToEggConverter::
-handle_external_reference(EggGroupNode *egg_parent,
-                          const Filename &orig_filename) {
-  return handle_external_reference(egg_parent, orig_filename, get_model_path());
-}
-
-
 ////////////////////////////////////////////////////////////////////
 //     Function: SomethingToEggConverter::convert_texture_path
 //       Access: Public
@@ -518,20 +485,7 @@ handle_external_reference(EggGroupNode *egg_parent,
 ////////////////////////////////////////////////////////////////////
 INLINE Filename SomethingToEggConverter::
 convert_texture_path(const Filename &orig_filename) {
-  return convert_path(orig_filename, get_texture_path(), _tpc_directory, _tpc);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEggConverter::convert_texture_path
-//       Access: Public
-//  Description: Converts the indicated texture filename to a relative
-//               or absolute or whatever filename, according to _tpc
-//               and _tpc_directory.  See convert_path().
-////////////////////////////////////////////////////////////////////
-INLINE Filename SomethingToEggConverter::
-convert_texture_path(const Filename &orig_filename,
-                     const DSearchPath &searchpath) {
-  return convert_path(orig_filename, searchpath, _tpc_directory, _tpc);
+  return _path_replace->convert_path(orig_filename, get_texture_path());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -543,18 +497,5 @@ convert_texture_path(const Filename &orig_filename,
 ////////////////////////////////////////////////////////////////////
 INLINE Filename SomethingToEggConverter::
 convert_model_path(const Filename &orig_filename) {
-  return convert_path(orig_filename, get_model_path(), _mpc_directory, _mpc);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEggConverter::convert_model_path
-//       Access: Public
-//  Description: Converts the indicated model filename to a relative
-//               or absolute or whatever filename, according to _mpc
-//               and _mpc_directory.  See convert_path().
-////////////////////////////////////////////////////////////////////
-INLINE Filename SomethingToEggConverter::
-convert_model_path(const Filename &orig_filename,
-                   const DSearchPath &searchpath) {
-  return convert_path(orig_filename, searchpath, _mpc_directory, _mpc);
+  return _path_replace->convert_path(orig_filename);
 }

+ 9 - 84
pandatool/src/converter/somethingToEggConverter.cxx

@@ -18,8 +18,8 @@
 
 #include "somethingToEggConverter.h"
 
-#include <eggData.h>
-#include <eggExternalReference.h>
+#include "eggData.h"
+#include "eggExternalReference.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: SomethingToEggConverter::Constructor
@@ -29,8 +29,7 @@
 SomethingToEggConverter::
 SomethingToEggConverter() {
   _allow_errors = false;
-  _tpc = PC_absolute;
-  _mpc = PC_absolute;
+  _path_replace = new PathReplace;
   _animation_convert = AC_none;
   _start_frame = 0.0;
   _end_frame = 0.0;
@@ -53,10 +52,7 @@ SomethingToEggConverter() {
 SomethingToEggConverter::
 SomethingToEggConverter(const SomethingToEggConverter &copy) :
   _allow_errors(copy._allow_errors),
-  _tpc(copy._tpc),
-  _tpc_directory(copy._tpc_directory),
-  _mpc(copy._mpc),
-  _mpc_directory(copy._mpc_directory),
+  _path_replace(copy._path_replace),
   _merge_externals(copy._merge_externals)
 {
   _egg_data = (EggData *)NULL;
@@ -119,18 +115,10 @@ handle_external_reference(EggGroupNode *egg_parent,
     egg_data.set_coordinate_system(get_egg_data().get_coordinate_system());
     ext->set_egg_data(&egg_data, false);
 
-    // If we're reading references directly, don't mamby around with
-    // the path conversion stuff, just look for the file and read it.
-    Filename as_found = orig_filename;
-    if (!as_found.resolve_filename(searchpath)) {
-      // If the filename can't be found, try just the truncated
-      // filename.
-      Filename truncated = orig_filename.get_basename();
-      if (truncated.resolve_filename(searchpath)) {
-        as_found = truncated;
-      }
-    }
-
+    // If we're reading references directly, we don't need to convert
+    // the pathname to something appropriate for storing, but we do
+    // need to hunt for it.
+    Filename as_found = _path_replace->match_path(orig_filename, searchpath);
     if (!ext->convert_file(as_found)) {
       delete ext;
       nout << "Unable to read external reference: " << orig_filename << "\n";
@@ -147,8 +135,7 @@ handle_external_reference(EggGroupNode *egg_parent,
   } else {
     // If we're installing external references instead of reading
     // them, we should massage the filename as specified.
-    Filename filename = convert_model_path(orig_filename, searchpath);
-
+    Filename filename = _path_replace->convert_path(orig_filename, searchpath);
     filename.set_extension("egg");
 
     EggExternalReference *egg_ref = new EggExternalReference("", filename);
@@ -157,65 +144,3 @@ handle_external_reference(EggGroupNode *egg_parent,
 
   return true;
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEggConverter::convert_path
-//       Access: Public, Static
-//  Description: Converts the pathname reference by the source 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 source file; searchpath is the search path to
-//               look for it along.  rel_dir is the directory to make
-//               the pathname relative to in the case of PC_relative
-//               or PC_rel_abs.
-////////////////////////////////////////////////////////////////////
-Filename SomethingToEggConverter::
-convert_path(const Filename &orig_filename, const DSearchPath &searchpath,
-             const Filename &rel_dir, PathConvert path_convert) {
-  // Try to look up the filename along the search path.
-  Filename as_found = orig_filename;
-  if (!as_found.resolve_filename(searchpath)) {
-    // If the filename can't be found, try just the truncated
-    // filename.
-    Filename truncated = orig_filename.get_basename();
-    if (truncated.resolve_filename(searchpath)) {
-      as_found = truncated;
-    }
-  }
-
-  Filename result;
-
-  switch (path_convert) {
-  case PC_relative:
-    result = as_found;
-    result.make_relative_to(rel_dir);
-    return result;
-
-  case PC_absolute:
-    result = as_found;
-    if (!result.exists()) {
-      nout << "Warning: file " << orig_filename << " not found.\n";
-      return result;
-    }
-    result.make_absolute();
-    return result;
-
-  case PC_rel_abs:
-    result = as_found;
-    result.make_relative_to(rel_dir);
-    result = Filename(rel_dir, result);
-    return result;
-
-  case PC_strip:
-    return orig_filename.get_basename();
-
-  case PC_unchanged:
-    return orig_filename;
-  }
-
-  // Error case.
-  nout << "Invalid PathConvert type: " << (int)path_convert << "\n";
-  return orig_filename;
-}

+ 8 - 29
pandatool/src/converter/somethingToEggConverter.h

@@ -24,6 +24,8 @@
 #include "filename.h"
 #include "config_util.h"  // for get_texture_path() and get_model_path()
 #include "animationConvert.h"
+#include "pathReplace.h"
+#include "pointerTo.h"
 
 class EggData;
 class EggGroupNode;
@@ -46,17 +48,10 @@ public:
 
   virtual SomethingToEggConverter *make_copy()=0;
 
-  enum PathConvert {
-    PC_relative,
-    PC_absolute,
-    PC_rel_abs,
-    PC_strip,
-    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());
+  INLINE void set_path_replace(PathReplace *path_replace);
+  INLINE PathReplace *get_path_replace();
+  INLINE const PathReplace *get_path_replace() const;
+
   // These methods dealing with animation and frame rate are only
   // relevant to converter types that understand animation.
   INLINE void set_animation_convert(AnimationConvert animation_convert);
@@ -111,33 +106,17 @@ public:
 
   bool handle_external_reference(EggGroupNode *egg_parent,
                                  const Filename &orig_filename,
-                                 const DSearchPath &searchpath);
-  INLINE bool handle_external_reference(EggGroupNode *egg_parent,
-                                        const Filename &orig_filename);
-
+                                 const DSearchPath &searchpath = DSearchPath());
 
   INLINE Filename convert_texture_path(const Filename &orig_filename);
-  INLINE Filename convert_texture_path(const Filename &orig_filename,
-                                       const DSearchPath &searchpath);
   INLINE Filename convert_model_path(const Filename &orig_filename);
-  INLINE Filename convert_model_path(const Filename &orig_filename,
-                                     const DSearchPath &searchpath);
-
-  static Filename convert_path(const Filename &orig_filename,
-                               const DSearchPath &searchpath,
-                               const Filename &rel_dir,
-                               PathConvert path_convert);
-
 
   // Set this true to treat errors as warnings and generate output
   // anyway.
   bool _allow_errors;
 
 protected:
-  PathConvert _tpc;
-  Filename _tpc_directory;
-  PathConvert _mpc;
-  Filename _mpc_directory;
+  PT(PathReplace) _path_replace;
 
   AnimationConvert _animation_convert;
   string _character_name;

+ 1 - 1
pandatool/src/egg-palettize/eggFile.cxx

@@ -442,7 +442,7 @@ read_egg() {
   dir.append_directory(_current_directory);
   data->resolve_filenames(dir);
 
-  if (!data->resolve_externals()) {
+  if (!data->load_externals()) {
     // Failure reading an external.
     delete data;
     return false;

+ 35 - 1
pandatool/src/eggbase/eggBase.cxx

@@ -18,7 +18,11 @@
 
 #include "eggBase.h"
 
-#include <eggComment.h>
+#include "eggGroupNode.h"
+#include "eggTexture.h"
+#include "eggFilenameNode.h"
+#include "eggComment.h"
+#include "dcast.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: EggBase::Constructor
@@ -71,6 +75,36 @@ as_writer() {
   return (EggWriter *)NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggBase::convert_paths
+//       Access: Public, Static
+//  Description: Recursively walks the egg hierarchy.  Any filenames
+//               encountered are replaced according to the indicated
+//               PathReplace.
+////////////////////////////////////////////////////////////////////
+void EggBase::
+convert_paths(EggNode *node, PathReplace *path_replace,
+              const DSearchPath &additional_path) {
+  if (node->is_of_type(EggTexture::get_class_type())) {
+    EggTexture *egg_tex = DCAST(EggTexture, node);
+    egg_tex->set_filename(path_replace->convert_path(egg_tex->get_filename(),
+                                                     additional_path));
+    if (egg_tex->has_alpha_file()) {
+      egg_tex->set_alpha_file(path_replace->convert_path(egg_tex->get_alpha_file(), additional_path));
+    }
+
+  } else if (node->is_of_type(EggFilenameNode::get_class_type())) {
+    EggFilenameNode *egg_fname = DCAST(EggFilenameNode, node);
+    egg_fname->set_filename(path_replace->convert_path(egg_fname->get_filename(), additional_path));
+  } else if (node->is_of_type(EggGroupNode::get_class_type())) {
+    EggGroupNode *egg_group = DCAST(EggGroupNode, node);
+    EggGroupNode::const_iterator ci;
+    for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
+      convert_paths(*ci, path_replace, additional_path);
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggBase::post_command_line
 //       Access: Protected, Virtual

+ 9 - 4
pandatool/src/eggbase/eggBase.h

@@ -19,14 +19,16 @@
 #ifndef EGGBASE_H
 #define EGGBASE_H
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
-#include <programBase.h>
-#include <coordinateSystem.h>
-#include <eggData.h>
+#include "programBase.h"
+#include "coordinateSystem.h"
+#include "eggData.h"
 
 class EggReader;
 class EggWriter;
+class EggNode;
+class PathReplace;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : EggBase
@@ -45,6 +47,9 @@ public:
   virtual EggReader *as_reader();
   virtual EggWriter *as_writer();
 
+  static void convert_paths(EggNode *node, PathReplace *path_replace,
+                            const DSearchPath &additional_path);
+
 protected:
   virtual bool post_command_line();
   void append_command_comment(EggData &_data);

+ 8 - 1
pandatool/src/eggbase/eggFilter.cxx

@@ -59,6 +59,11 @@ handle_args(ProgramBase::Args &args) {
     return false;
   }
 
+  if (!_got_path_directory && _got_output_filename) {
+    // Put in the name of the output directory.
+    _path_replace->_path_directory = _output_filename.get_dirname();
+  }
+
   return EggReader::handle_args(args);
 }
 
@@ -69,5 +74,7 @@ handle_args(ProgramBase::Args &args) {
 ////////////////////////////////////////////////////////////////////
 bool EggFilter::
 post_command_line() {
-  return EggReader::post_command_line() && EggWriter::post_command_line();
+  // writer first, so we can fiddle with the _path_replace options if
+  // necessary.
+  return EggWriter::post_command_line() && EggReader::post_command_line();
 }

+ 11 - 13
pandatool/src/eggbase/eggMultiBase.cxx

@@ -17,10 +17,11 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "eggMultiBase.h"
-
-#include <eggData.h>
-#include <eggComment.h>
-#include <filename.h>
+#include "eggBase.h"
+#include "eggData.h"
+#include "eggComment.h"
+#include "filename.h"
+#include "dSearchPath.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: EggMultiBase::Constructor
@@ -116,20 +117,17 @@ PT(EggData) EggMultiBase::
 read_egg(const Filename &filename) {
   PT(EggData) data = new EggData;
 
-  // First, we always try to resolve a filename from the current
-  // directory.  This means a local filename will always be found
-  // before the model path is searched.
-  Filename local_filename = filename;
-  DSearchPath local_path(".");
-  local_filename.resolve_filename(local_path);
-
-  if (!data->read(local_filename)) {
+  if (!data->read(filename)) {
     // Failure reading.
     return (EggData *)NULL;
   }
 
+  DSearchPath file_path;
+  file_path.append_directory(filename.get_dirname());
+  EggBase::convert_paths(data, _path_replace, file_path);
+
   if (_force_complete) {
-    if (!data->resolve_externals()) {
+    if (!data->load_externals()) {
       return (EggData *)NULL;
     }
   }

+ 11 - 2
pandatool/src/eggbase/eggMultiFilter.cxx

@@ -18,8 +18,8 @@
 
 #include "eggMultiFilter.h"
 
-#include <notify.h>
-#include <eggData.h>
+#include "notify.h"
+#include "eggData.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: EggMultiFilter::Constructor
@@ -103,6 +103,15 @@ handle_args(ProgramBase::Args &args) {
     }
   }
 
+  // We need to set up _path_replace before we call read_egg().
+  if (!_got_path_directory) {
+    // Put in the name of the output directory.
+    if (_got_output_filename) {
+      _path_replace->_path_directory = _output_filename.get_dirname();
+    } else if (_got_output_dirname) {
+      _path_replace->_path_directory = _output_dirname;
+    }
+  }
 
   Args::const_iterator ai;
   for (ai = args.begin(); ai != args.end(); ++ai) {

+ 12 - 8
pandatool/src/eggbase/eggReader.cxx

@@ -159,28 +159,32 @@ handle_args(ProgramBase::Args &args) {
   // Any separate egg files that are listed on the command line will
   // get implicitly loaded up into one big egg file.
 
-  DSearchPath local_path(".");
-
+  if (!args.empty()) {
+    _data.set_egg_filename(args[0]);
+  }
   Args::const_iterator ai;
   for (ai = args.begin(); ai != args.end(); ++ai) {
     Filename filename = *ai;
-    // First, we always try to resolve a filename from the current
-    // directory.  This means a local filename will always be found
-    // before the model path is searched.
-    filename.resolve_filename(local_path);
 
-    if (!_data.read(filename)) {
+    EggData file_data;
+    if (!file_data.read(filename)) {
       // Rather than returning false, we simply exit here, so the
       // ProgramBase won't try to tell the user how to run the program
       // just because we got a bad egg file.
       exit(1);
     }
 
+    DSearchPath file_path;
+    file_path.append_directory(filename.get_dirname());
+    convert_paths(&file_data, _path_replace, file_path);
+    
     if (_force_complete) {
-      if (!_data.resolve_externals()) {
+      if (!file_data.load_externals()) {
         exit(1);
       }
     }
+
+    _data.merge(file_data);
   }
 
   return true;

+ 5 - 0
pandatool/src/eggbase/eggWriter.cxx

@@ -282,6 +282,11 @@ handle_args(ProgramBase::Args &args) {
     return false;
   }
 
+  if (!_got_path_directory && _got_output_filename) {
+    // Put in the name of the output directory.
+    _path_replace->_path_directory = _output_filename.get_dirname();
+  }
+
   return true;
 }
 

+ 16 - 225
pandatool/src/eggbase/somethingToEgg.cxx

@@ -17,8 +17,9 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "somethingToEgg.h"
+#include "somethingToEggConverter.h"
 
-#include <config_util.h>
+#include "config_util.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: SomethingToEgg::Constructor
@@ -65,9 +66,6 @@ SomethingToEgg(const string &format_name,
   _got_neutral_frame = false;
   _got_input_frame_rate = false;
   _got_output_frame_rate = false;
-  _texture_path_convert = SomethingToEggConverter::PC_unchanged;
-  _model_path_convert = SomethingToEggConverter::PC_unchanged;
-  _append_to_sys_paths = false;
   _merge_externals = false;
 }
 
@@ -161,131 +159,6 @@ add_animation_options() {
      &SomethingToEgg::dispatch_double, &_got_output_frame_rate, &_output_frame_rate);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEgg::add_texture_path_options
-//       Access: Public
-//  Description: Adds -rt etc. as valid options for this program.
-//               These specify how the texture pathnames that appear
-//               in the source file should be changed for the egg
-//               file.
-////////////////////////////////////////////////////////////////////
-void SomethingToEgg::
-add_texture_path_options() {
-  add_option
-    ("rt", "", 40,
-     "Convert texture filenames to relative pathnames, relative to the "
-     "directory specified by -rd.",
-     &SomethingToEgg::dispatch_path_convert_relative, NULL, &_texture_path_convert);
-
-  add_option
-    ("rta", "", 40,
-     "Convert texture filenames to absolute pathnames.",
-     &SomethingToEgg::dispatch_path_convert_absolute, NULL, &_texture_path_convert);
-
-  add_option
-    ("rtA", "", 40,
-     "Convert texture filenames to absolute pathnames that begin with the "
-     "prefix specified by -rd.",
-     &SomethingToEgg::dispatch_path_convert_rel_abs, NULL, &_texture_path_convert);
-
-  add_option
-    ("rts", "", 40,
-     "Strip paths from texture filenames.  Only the basename of the texture "
-     "will be preserved.",
-     &SomethingToEgg::dispatch_path_convert_strip, NULL, &_texture_path_convert);
-
-  add_option
-    ("rtu", "", 40,
-     "Leave texture filenames unchanged.  They will be relative if they "
-     "are relative in the source file, or absolute if they are absolute in "
-     "the source file.",
-     &SomethingToEgg::dispatch_path_convert_unchanged, NULL, &_texture_path_convert);
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEgg::add_model_path_options
-//       Access: Public
-//  Description: Adds -re etc. as valid options for this program.
-//               These specify how the model pathnames that appear
-//               in the source file should be changed for the egg
-//               file.
-////////////////////////////////////////////////////////////////////
-void SomethingToEgg::
-add_model_path_options() {
-  add_option
-    ("re", "", 40,
-     "Convert model filenames (external references) to relative pathnames, "
-     "relative to the directory specified by -rd.",
-     &SomethingToEgg::dispatch_path_convert_relative, NULL, &_model_path_convert);
-
-  add_option
-    ("rea", "", 40,
-     "Convert model filenames to absolute pathnames.",
-     &SomethingToEgg::dispatch_path_convert_absolute, NULL, &_model_path_convert);
-
-  add_option
-    ("reA", "", 40,
-     "Convert model filenames to absolute pathnames that begin with the "
-     "prefix specified by -rd.",
-     &SomethingToEgg::dispatch_path_convert_rel_abs, NULL, &_model_path_convert);
-
-  add_option
-    ("res", "", 40,
-     "Strip paths from model filenames.  Only the basename of the model "
-     "will be preserved.",
-     &SomethingToEgg::dispatch_path_convert_strip, NULL, &_model_path_convert);
-
-  add_option
-    ("reu", "", 40,
-     "Leave model filenames unchanged.  They will be relative if they "
-     "are relative in the source file, or absolute if they are absolute in "
-     "the source file.",
-     &SomethingToEgg::dispatch_path_convert_unchanged, NULL, &_model_path_convert);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEgg::add_rel_dir_options
-//       Access: Public
-//  Description: Adds -rd.  This should generally be called if
-//               add_texture_path_options() or
-//               add_model_path_options() is called.
-////////////////////////////////////////////////////////////////////
-void SomethingToEgg::
-add_rel_dir_options() {
-  add_option
-    ("rd", "dir", 40,
-     "Specify the directory to make relative to.  This is the "
-     "directory that all pathnames given in the source 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.",
-     &SomethingToEgg::dispatch_string, &_got_make_rel_dir, &_make_rel_dir);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEgg::add_search_path_options
-//       Access: Public
-//  Description: Adds -rs.  If append_to_sys_paths is true, the
-//               specified search path is prepended to the system
-//               paths returned by get_texture_path() and
-//               get_model_path(); otherwise, it's up to the caller to
-//               do the right thing with the _search_path.
-////////////////////////////////////////////////////////////////////
-void SomethingToEgg::
-add_search_path_options(bool append_to_sys_paths) {
-  _append_to_sys_paths = append_to_sys_paths;
-  add_option
-    ("rs", "path", 40,
-     "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 source file.  It "
-     "is unrelated to -re and -rt, and is used only if the source file "
-     "does not store absolute pathnames.  The directory containing "
-     "the source filename is always implicitly included.",
-     &SomethingToEgg::dispatch_search_path, &_got_search_path, &_search_path);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: SomethingToEgg::add_merge_externals_options
 //       Access: Public
@@ -318,14 +191,17 @@ apply_units_scale(EggData &data) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEgg::apply_animation_parameters
+//     Function: SomethingToEgg::apply_parameters
 //       Access: Protected
-//  Description: Copies the animation parameters specified by the user
-//               on the command line (if add_animation_options() was
-//               used) to the converter.
+//  Description: Copies the relevant parameters specified by the user
+//               on the command line (if add_path_replace_options(),
+//               add_path_store_options(), or add_animation_options()
+//               was used) to the converter.
 ////////////////////////////////////////////////////////////////////
 void SomethingToEgg::
-apply_animation_parameters(SomethingToEggConverter &converter) {
+apply_parameters(SomethingToEggConverter &converter) {
+  converter.set_path_replace(_path_replace);
+
   converter.set_animation_convert(_animation_convert);
   converter.set_character_name(_character_name);
   if (_got_start_frame) {
@@ -412,28 +288,13 @@ handle_args(Args &args) {
 ////////////////////////////////////////////////////////////////////
 bool SomethingToEgg::
 post_command_line() {
-  if (!_got_make_rel_dir) {
-    _make_rel_dir = _input_filename.get_dirname();
-  }
-
-  if (_append_to_sys_paths) {
-    DSearchPath &texture_path = get_texture_path();
-    DSearchPath &model_path = get_model_path();
-
-    // Prepend the source filename to the search paths.
-    Filename directory = _input_filename.get_dirname();
-    if (directory.empty()) {
-      directory = ".";
-    }
-    texture_path.prepend_directory(directory);
-    model_path.prepend_directory(directory);
-
-    // Then prepend whatever the user specified on the command line.
-    if (_got_search_path) {
-      texture_path.prepend_path(_search_path);
-      model_path.prepend_path(_search_path);
-    }
+  // Prepend the source filename to the model path.
+  DSearchPath &model_path = get_model_path();
+  Filename directory = _input_filename.get_dirname();
+  if (directory.empty()) {
+    directory = ".";
   }
+  model_path.prepend_directory(directory);
 
   return EggConverter::post_command_line();
 }
@@ -474,73 +335,3 @@ dispatch_animation_convert(const string &opt, const string &arg, void *var) {
 
   return true;
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEgg::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
-//               SomethingToEggConverter::PathConvert variable.
-////////////////////////////////////////////////////////////////////
-bool SomethingToEgg::
-dispatch_path_convert_relative(const string &opt, const string &, void *var) {
-  SomethingToEggConverter::PathConvert *ip = (SomethingToEggConverter::PathConvert *)var;
-  (*ip) = SomethingToEggConverter::PC_relative;
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEgg::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
-//               SomethingToEggConverter::PathConvert variable.
-////////////////////////////////////////////////////////////////////
-bool SomethingToEgg::
-dispatch_path_convert_absolute(const string &opt, const string &, void *var) {
-  SomethingToEggConverter::PathConvert *ip = (SomethingToEggConverter::PathConvert *)var;
-  (*ip) = SomethingToEggConverter::PC_absolute;
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEgg::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
-//               SomethingToEggConverter::PathConvert variable.
-////////////////////////////////////////////////////////////////////
-bool SomethingToEgg::
-dispatch_path_convert_rel_abs(const string &opt, const string &, void *var) {
-  SomethingToEggConverter::PathConvert *ip = (SomethingToEggConverter::PathConvert *)var;
-  (*ip) = SomethingToEggConverter::PC_rel_abs;
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEgg::dispatch_path_convert_strip
-//       Access: Protected, Static
-//  Description: Dispatch function to set the given path convert mode
-//               to PC_strip.  var is a pointer to a
-//               SomethingToEggConverter::PathConvert variable.
-////////////////////////////////////////////////////////////////////
-bool SomethingToEgg::
-dispatch_path_convert_strip(const string &opt, const string &, void *var) {
-  SomethingToEggConverter::PathConvert *ip = (SomethingToEggConverter::PathConvert *)var;
-  (*ip) = SomethingToEggConverter::PC_strip;
-  return true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: SomethingToEgg::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
-//               SomethingToEggConverter::PathConvert variable.
-////////////////////////////////////////////////////////////////////
-bool SomethingToEgg::
-dispatch_path_convert_unchanged(const string &opt, const string &, void *var) {
-  SomethingToEggConverter::PathConvert *ip = (SomethingToEggConverter::PathConvert *)var;
-  (*ip) = SomethingToEggConverter::PC_unchanged;
-  return true;
-}

+ 3 - 22
pandatool/src/eggbase/somethingToEgg.h

@@ -22,10 +22,10 @@
 #include "pandatoolbase.h"
 
 #include "eggConverter.h"
-
 #include "distanceUnit.h"
-#include "somethingToEggConverter.h"
+#include "animationConvert.h"
 
+class SomethingToEggConverter;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : SomethingToEgg
@@ -42,26 +42,17 @@ public:
 
   void add_units_options();
   void add_animation_options();
-  void add_texture_path_options();
-  void add_model_path_options();
-  void add_rel_dir_options();
-  void add_search_path_options(bool append_to_sys_paths);
   void add_merge_externals_options();
 
 protected:
   void apply_units_scale(EggData &data);
-  void apply_animation_parameters(SomethingToEggConverter &converter);
+  void apply_parameters(SomethingToEggConverter &converter);
 
   virtual bool handle_args(Args &args);
   virtual bool post_command_line();
   virtual void post_process_egg_file();
 
   static bool dispatch_animation_convert(const string &opt, const string &arg, void *var);
-  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_strip(const string &opt, const string &arg, void *var);
-  static bool dispatch_path_convert_unchanged(const string &opt, const string &arg, void *var);
 
 
   Filename _input_filename;
@@ -84,16 +75,6 @@ protected:
   bool _got_input_frame_rate;
   bool _got_output_frame_rate;
 
-  SomethingToEggConverter::PathConvert _texture_path_convert;
-  SomethingToEggConverter::PathConvert _model_path_convert;
-
-  Filename _make_rel_dir;
-  bool _got_make_rel_dir;
-
-  DSearchPath _search_path;
-  bool _got_search_path;
-  bool _append_to_sys_paths;
-
   bool _merge_externals;
   bool _allow_errors;
 };

+ 3 - 2
pandatool/src/eggprogs/eggTrans.cxx

@@ -17,8 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "eggTrans.h"
-
-#include <eggGroupUniquifier.h>
+#include "eggGroupUniquifier.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: EggTrans::Constructor
@@ -27,6 +26,8 @@
 ////////////////////////////////////////////////////////////////////
 EggTrans::
 EggTrans() {
+  add_path_replace_options();
+  add_path_store_options();
   add_normals_options();
   add_transform_options();
   add_texture_options();

+ 28 - 8
pandatool/src/flt/fltExternalReference.cxx

@@ -20,6 +20,7 @@
 #include "fltRecordReader.h"
 #include "fltRecordWriter.h"
 #include "fltHeader.h"
+#include "pathReplace.h"
 
 TypeHandle FltExternalReference::_type_handle;
 
@@ -33,9 +34,33 @@ FltExternalReference(FltHeader *header) : FltBead(header) {
   _flags = 0;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltExternalReference::convert_paths
+//       Access: Public, Virtual
+//  Description: Converts all of the paths referenced by this record
+//               and below according to the indicated path replace
+//               parameters.  If the resulting paths are absolute
+//               (beginning with a slash), they are converted to
+//               os-specific form before writing them out; otherwise,
+//               if they are relative, they are left in panda-specific
+//               form (under the assumption that a slash-delimited set
+//               of directory names is universally understood).
+////////////////////////////////////////////////////////////////////
+void FltExternalReference::
+convert_paths(PathReplace *path_replace) {
+  Filename new_filename = path_replace->convert_path(get_ref_filename());
+  if (new_filename.is_local()) {
+    _filename = new_filename;
+  } else {
+    _filename = new_filename.to_os_specific();
+  }
+  
+  FltRecord::convert_paths(path_replace);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltExternalReference::output
-//       Access: Public
+//       Access: Public, Virtual
 //  Description: Writes a quick one-line description of the record, but
 //               not its children.  This is a human-readable
 //               description, primarily for debugging; to write a flt
@@ -52,16 +77,11 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: FltTexture::get_ref_filename
 //       Access: Public
-//  Description: Returns the name of the referenced file.  If it
-//               appears to be a relative filename, it will be
-//               converted to the correct full pathname according to
-//               the model_path specified in the header.
+//  Description: Returns the name of the referenced file.
 ////////////////////////////////////////////////////////////////////
 Filename FltExternalReference::
 get_ref_filename() const {
-  Filename file = Filename::from_os_specific(_filename);
-  file.resolve_filename(_header->get_model_path());
-  return file;
+  return Filename::from_os_specific(_filename);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 2
pandatool/src/flt/fltExternalReference.h

@@ -19,11 +19,11 @@
 #ifndef FLTEXTERNALREFERENCE_H
 #define FLTEXTERNALREFERENCE_H
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
 #include "fltBead.h"
 
-#include <filename.h>
+#include "filename.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : FltExternalReference
@@ -34,6 +34,7 @@ class FltExternalReference : public FltBead {
 public:
   FltExternalReference(FltHeader *header);
 
+  virtual void convert_paths(PathReplace *path_replace);
   virtual void output(ostream &out) const;
 
   enum Flags {

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

@@ -111,14 +111,6 @@ read_flt(Filename filename) {
     return FE_could_not_open;
   }
 
-  // By default, the filename's directory is added to the texture and
-  // model search path.
-  string dirname = filename.get_dirname();
-  if (!dirname.empty()) {
-    _texture_path.prepend_directory(dirname);
-    _model_path.prepend_directory(dirname);
-  }
-
   return read_flt(in);
 }
 
@@ -925,74 +917,6 @@ remove_texture(int texture_index) {
   _textures.erase(texture_index);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: FltHeader::set_texture_path
-//       Access: Public
-//  Description: Sets the search path that relative texture filenames
-//               will be looked for along.
-////////////////////////////////////////////////////////////////////
-void FltHeader::
-set_texture_path(const DSearchPath &path) {
-  _texture_path = path;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltHeader::update_texture_path
-//       Access: Public
-//  Description: Returns a non-const reference to the texture search
-//               path, so that it may be appended to or otherwise
-//               modified.
-////////////////////////////////////////////////////////////////////
-DSearchPath &FltHeader::
-update_texture_path() {
-  return _texture_path;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltHeader::get_texture_path
-//       Access: Public
-//  Description: Returns the search path for looking up texture
-//               filenames.
-////////////////////////////////////////////////////////////////////
-const DSearchPath &FltHeader::
-get_texture_path() const {
-  return _texture_path;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltHeader::set_model_path
-//       Access: Public
-//  Description: Sets the search path that relative external
-//               references will be looked for along.
-////////////////////////////////////////////////////////////////////
-void FltHeader::
-set_model_path(const DSearchPath &path) {
-  _model_path = path;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltHeader::update_model_path
-//       Access: Public
-//  Description: Returns a non-const reference to the model search
-//               path, so that it may be appended to or otherwise
-//               modified.
-////////////////////////////////////////////////////////////////////
-DSearchPath &FltHeader::
-update_model_path() {
-  return _model_path;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: FltHeader::get_model_path
-//       Access: Public
-//  Description: Returns the search path for looking up external
-//               references.
-////////////////////////////////////////////////////////////////////
-const DSearchPath &FltHeader::
-get_model_path() const {
-  return _model_path;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: FltHeader::has_light_source
 //       Access: Public

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

@@ -207,17 +207,6 @@ public:
   void add_texture(FltTexture *texture);
   void remove_texture(int texture_index);
 
-  // Sometimes Flt files store textures and external references as
-  // relative pathnames.  Setting these search paths helps resolve
-  // that tendency.
-  void set_texture_path(const DSearchPath &path);
-  DSearchPath &update_texture_path();
-  const DSearchPath &get_texture_path() const;
-
-  void set_model_path(const DSearchPath &path);
-  DSearchPath &update_model_path();
-  const DSearchPath &get_model_path() const;
-
 
   // Accessors into the light source palette.
   bool has_light_source(int light_index) const;
@@ -237,9 +226,6 @@ public:
   FltTrackplane *get_trackplane(int n);
 
 private:
-  DSearchPath _texture_path;
-  DSearchPath _model_path;
-
   // Instance subtrees.  These are standalone subtrees, which may be
   // referenced by various points in the hierarchy, stored by instance
   // ID number.

+ 23 - 0
pandatool/src/flt/fltRecord.cxx

@@ -330,6 +330,29 @@ check_remaining_size(const DatagramIterator &di, const string &name) const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltRecord::convert_paths
+//       Access: Public, Virtual
+//  Description: Converts all of the paths referenced by this record
+//               and below according to the indicated path replace
+//               parameters.  If the resulting paths are absolute
+//               (beginning with a slash), they are converted to
+//               os-specific form before writing them out; otherwise,
+//               if they are relative, they are left in panda-specific
+//               form (under the assumption that a slash-delimited set
+//               of directory names is universally understood).
+////////////////////////////////////////////////////////////////////
+void FltRecord::
+convert_paths(PathReplace *path_replace) {
+  Records::const_iterator ci;
+  for (ci = _subfaces.begin(); ci != _subfaces.end(); ++ci) {
+    (*ci)->convert_paths(path_replace);
+  }
+  for (ci = _children.begin(); ci != _children.end(); ++ci) {
+    (*ci)->convert_paths(path_replace);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltRecord::output
 //       Access: Public

+ 7 - 4
pandatool/src/flt/fltRecord.h

@@ -19,19 +19,20 @@
 #ifndef FLTRECORD_H
 #define FLTRECORD_H
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
 #include "fltOpcode.h"
 #include "fltError.h"
 
-#include <typedObject.h>
-#include <typedReferenceCount.h>
-#include <pointerTo.h>
+#include "typedObject.h"
+#include "typedReferenceCount.h"
+#include "pointerTo.h"
 
 class FltHeader;
 class FltRecordReader;
 class FltRecordWriter;
 class DatagramIterator;
+class PathReplace;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : FltRecord
@@ -74,6 +75,8 @@ public:
   void check_remaining_size(const DatagramIterator &di, 
                             const string &name = string()) const;
 
+  virtual void convert_paths(PathReplace *path_replace);
+
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level = 0) const;
 

+ 27 - 7
pandatool/src/flt/fltTexture.cxx

@@ -20,6 +20,7 @@
 #include "fltRecordReader.h"
 #include "fltRecordWriter.h"
 #include "fltHeader.h"
+#include "pathReplace.h"
 
 TypeHandle FltTexture::_type_handle;
 
@@ -87,19 +88,38 @@ FltTexture(FltHeader *header) : FltRecord(header) {
   _file_version = 1501;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: FltTexture::convert_paths
+//       Access: Public, Virtual
+//  Description: Converts all of the paths referenced by this record
+//               and below according to the indicated path replace
+//               parameters.  If the resulting paths are absolute
+//               (beginning with a slash), they are converted to
+//               os-specific form before writing them out; otherwise,
+//               if they are relative, they are left in panda-specific
+//               form (under the assumption that a slash-delimited set
+//               of directory names is universally understood).
+////////////////////////////////////////////////////////////////////
+void FltTexture::
+convert_paths(PathReplace *path_replace) {
+  Filename new_filename = path_replace->convert_path(get_texture_filename());
+  if (new_filename.is_local()) {
+    _filename = new_filename;
+  } else {
+    _filename = new_filename.to_os_specific();
+  }
+  
+  FltRecord::convert_paths(path_replace);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: FltTexture::get_texture_filename
 //       Access: Public
-//  Description: Returns the name of the texture image file.  If it
-//               appears to be a relative filename, it will be
-//               converted to the correct full pathname according to
-//               the texture_path specified in the header.
+//  Description: Returns the name of the texture image file.
 ////////////////////////////////////////////////////////////////////
 Filename FltTexture::
 get_texture_filename() const {
-  Filename file = Filename::from_os_specific(_filename);
-  file.resolve_filename(_header->get_texture_path());
-  return file;
+  return Filename::from_os_specific(_filename);
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -34,6 +34,8 @@ class FltTexture : public FltRecord {
 public:
   FltTexture(FltHeader *header);
 
+  virtual void convert_paths(PathReplace *path_replace);
+
   string _filename;
   int _pattern_index;
   int _x_location;

+ 2 - 5
pandatool/src/fltegg/fltToEggConverter.cxx

@@ -408,8 +408,7 @@ convert_ext_ref(const FltExternalReference *flt_ext, FltToEggLevelState &state)
   EggGroupNode *egg_parent =
     state.get_synthetic_group("", flt_ext);
 
-  handle_external_reference(egg_parent,
-                            flt_ext->_filename, _flt_header->get_model_path());
+  handle_external_reference(egg_parent, flt_ext->get_ref_filename());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -745,9 +744,7 @@ make_egg_texture(const FltTexture *flt_texture) {
 
   // Create a new one.
   string tref_name = format_string(flt_texture->_pattern_index);
-  Filename filename =
-    convert_texture_path(flt_texture->_filename,
-                         _flt_header->get_texture_path());
+  Filename filename = convert_texture_path(flt_texture->get_texture_filename());
 
   PT_EggTexture egg_texture = new EggTexture(tref_name, filename);
 

+ 9 - 10
pandatool/src/fltegg/fltToEggConverter.h

@@ -19,18 +19,17 @@
 #ifndef FLTTOEGGCONVERTER_H
 #define FLTTOEGGCONVERTER_H
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
 #include "fltToEggLevelState.h"
-
-#include <somethingToEggConverter.h>
-#include <fltHeader.h>
-#include <eggVertex.h>
-#include <eggVertexPool.h>
-#include <eggTexture.h>
-#include <pt_EggTexture.h>
-#include <pt_EggVertex.h>
-#include <pointerTo.h>
+#include "somethingToEggConverter.h"
+#include "fltHeader.h"
+#include "eggVertex.h"
+#include "eggVertexPool.h"
+#include "eggTexture.h"
+#include "pt_EggTexture.h"
+#include "pt_EggVertex.h"
+#include "pointerTo.h"
 
 class FltRecord;
 class FltLOD;

+ 6 - 4
pandatool/src/fltprogs/fltCopy.cxx

@@ -55,6 +55,8 @@ FltCopy() {
      "repeated multiple times on the command line; each time it appears "
      "its named directories will be appended to the search path.",
      &FltCopy::dispatch_search_path, NULL, &_search_path);
+
+  add_path_replace_options();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -109,8 +111,6 @@ bool FltCopy::
 copy_flt_file(const Filename &source, const Filename &dest,
               CVSSourceDirectory *dir) {
   PT(FltHeader) header = new FltHeader;
-  header->set_texture_path(_search_path);
-  header->set_model_path(_search_path);
 
   // We don't want to automatically generate .attr files--we'd rather
   // write them out explicitly.
@@ -132,7 +132,8 @@ copy_flt_file(const Filename &source, const Filename &dest,
   Refs::const_iterator ri;
   for (ri = refs.begin(); ri != refs.end(); ++ri) {
     FltExternalReference *ref = (*ri);
-    Filename ref_filename = ref->get_ref_filename();
+    Filename ref_filename = 
+      _path_replace->convert_path(ref->get_ref_filename());
 
     if (!ref_filename.exists()) {
       nout << "*** Warning: external reference " << ref_filename
@@ -162,7 +163,8 @@ copy_flt_file(const Filename &source, const Filename &dest,
   Textures::const_iterator ti;
   for (ti = textures.begin(); ti != textures.end(); ++ti) {
     FltTexture *tex = (*ti);
-    Filename texture_filename = tex->get_texture_filename();
+    Filename texture_filename = 
+      _path_replace->convert_path(tex->get_texture_filename());
 
     if (!texture_filename.exists()) {
       nout << "*** Warning: texture " << texture_filename

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

@@ -30,13 +30,11 @@ FltToEgg::
 FltToEgg() :
   SomethingToEgg("MultiGen", ".flt")
 {
+  add_path_replace_options();
+  add_path_store_options();
   add_units_options();
   add_normals_options();
   add_transform_options();
-  add_texture_path_options();
-  add_model_path_options();
-  add_rel_dir_options();
-  add_search_path_options(false);
   add_merge_externals_options();
 
   set_program_description
@@ -48,12 +46,17 @@ FltToEgg() :
      "Specify the coordinate system of the input " + _format_name +
      " file.  Normally, this is z-up.");
 
+  // Does anyone really care about this option?  It's mainly useful
+  // for debugging the flt2egg logic.
+  /*
   add_option
     ("C", "", 0,
      "Compose node transforms into a single matrix before writing them to "
      "the egg file, instead of writing them as individual scale, rotate, and "
-     "translate operations",
+     "translate operations.",
      &FltToEgg::dispatch_none, &_compose_transforms);
+  */
+  _compose_transforms = false;
 
   _coordinate_system = CS_zup_right;
 }
@@ -66,8 +69,6 @@ FltToEgg() :
 void FltToEgg::
 run() {
   PT(FltHeader) header = new FltHeader;
-  header->set_texture_path(_search_path);
-  header->set_model_path(_search_path);
 
   nout << "Reading " << _input_filename << "\n";
   FltError result = header->read_flt(_input_filename);
@@ -87,11 +88,11 @@ run() {
   FltToEggConverter converter;
   converter.set_merge_externals(_merge_externals);
   converter.set_egg_data(&_data, false);
-  converter.set_texture_path_convert(_texture_path_convert, _make_rel_dir);
-  converter.set_model_path_convert(_model_path_convert, _make_rel_dir);
   converter._compose_transforms = _compose_transforms;
   converter._allow_errors = _allow_errors;
 
+  apply_parameters(converter);
+
   if (!converter.convert_flt(header)) {
     nout << "Errors in conversion.\n";
     exit(1);

+ 4 - 7
pandatool/src/fltprogs/fltTrans.cxx

@@ -42,12 +42,8 @@ FltTrans() :
   add_runline("[opts] input.flt output.flt");
   add_runline("[opts] -o output.flt input.flt");
 
-  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.",
-     &FltTrans::dispatch_search_path, NULL, &_texture_path);
+  add_path_replace_options();
+  add_path_store_options();
 
   add_option
     ("v", "version", 0,
@@ -84,7 +80,6 @@ run() {
   }
 
   PT(FltHeader) header = new FltHeader;
-  header->set_texture_path(_texture_path);
 
   nout << "Reading " << _input_filename << "\n";
   FltError result = header->read_flt(_input_filename);
@@ -102,6 +97,8 @@ run() {
     header->set_flt_version(new_version);
   }
 
+  header->convert_paths(_path_replace);
+
   result = header->write_flt(get_output());
   if (result != FE_ok) {
     nout << "Unable to write: " << result << "\n";

+ 3 - 6
pandatool/src/fltprogs/fltTrans.h

@@ -19,12 +19,10 @@
 #ifndef FLTTRANS_H
 #define FLTTRANS_H
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
-#include <programBase.h>
-#include <withOutputFile.h>
-
-#include <dSearchPath.h>
+#include "programBase.h"
+#include "withOutputFile.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : FltTrans
@@ -42,7 +40,6 @@ protected:
   virtual bool handle_args(Args &args);
 
   Filename _input_filename;
-  DSearchPath _texture_path;
   bool _got_new_version;
   double _new_version;
 };

+ 7 - 9
pandatool/src/lwoprogs/lwoToEgg.cxx

@@ -18,10 +18,10 @@
 
 #include "lwoToEgg.h"
 
-#include <lwoToEggConverter.h>
-#include <lwoHeader.h>
-#include <lwoInputFile.h>
-#include <config_lwo.h>
+#include "lwoToEggConverter.h"
+#include "lwoHeader.h"
+#include "lwoInputFile.h"
+#include "config_lwo.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: LwoToEgg::Constructor
@@ -32,12 +32,11 @@ LwoToEgg::
 LwoToEgg() :
   SomethingToEgg("Lightwave", ".lwo")
 {
+  add_path_replace_options();
+  add_path_store_options();
   add_units_options();
   add_normals_options();
   add_transform_options();
-  add_texture_path_options();
-  add_rel_dir_options();
-  add_search_path_options(true);
 
   set_program_description
     ("This program converts Lightwave Object (.lwo) files to egg.  Many "
@@ -75,8 +74,7 @@ run() {
 
   LwoToEggConverter converter;
   converter.set_egg_data(&_data, false);
-  converter.set_texture_path_convert(_texture_path_convert, _make_rel_dir);
-  converter.set_model_path_convert(_model_path_convert, _make_rel_dir);
+  apply_parameters(converter);
 
   if (!converter.convert_file(_input_filename)) {
     nout << "Errors in conversion.\n";

+ 4 - 6
pandatool/src/lwoprogs/lwoToEgg.h

@@ -19,12 +19,12 @@
 #ifndef LWOTOEGG_H
 #define LWOTOEGG_H
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
-#include <somethingToEgg.h>
-#include <lwoToEggConverter.h>
+#include "somethingToEgg.h"
+#include "lwoToEggConverter.h"
 
-#include <dSearchPath.h>
+#include "dSearchPath.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : LwoToEgg
@@ -36,8 +36,6 @@ public:
   LwoToEgg();
 
   void run();
-
-protected:
 };
 
 #endif

+ 6 - 2
pandatool/src/mayaprogs/mayaCopy.cxx

@@ -60,6 +60,8 @@ MayaCopy() {
      "Don't attempt to strip the Maya version number from the tail of the "
      "source filename before it is copied into the tree.",
      &CVSCopy::dispatch_none, &_keep_ver);
+
+  add_path_replace_options();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -158,7 +160,8 @@ copy_maya_file(const Filename &source, const Filename &dest,
   for (int i = 0; i < num_shaders; i++) {
     MayaShader *shader = _shaders.get_shader(i);
     if (shader->_has_texture) {
-      Filename texture_filename = shader->_texture;
+      Filename texture_filename = 
+        _path_replace->convert_path(shader->_texture);
       if (!texture_filename.exists()) {
         nout << "*** Warning: texture " << texture_filename
              << " does not exist.\n";
@@ -204,7 +207,8 @@ copy_maya_file(const Filename &source, const Filename &dest,
       << "External references are not yet properly supported by mayacopy!\n";
   }
   for (unsigned int ref_index = 0; ref_index < num_refs; ref_index++) {
-    Filename filename = refs[ref_index].asChar();
+    Filename filename = 
+      _path_replace->convert_path(refs[ref_index].asChar());
     maya_cat.warning()
       << "External ref: " << filename << "\n";
     /*

+ 5 - 6
pandatool/src/mayaprogs/mayaToEgg.cxx

@@ -29,13 +29,12 @@ MayaToEgg::
 MayaToEgg() :
   SomethingToEgg("Maya", ".mb")
 {
+  add_path_replace_options();
+  add_path_store_options();
   add_animation_options();
   add_units_options();
   add_normals_options();
   add_transform_options();
-  add_texture_path_options();
-  add_rel_dir_options();
-  add_search_path_options(false);
 
   set_program_description
     ("This program converts Maya model files to egg.  Nothing fancy yet.");
@@ -98,8 +97,8 @@ run() {
   converter._polygon_tolerance = _polygon_tolerance;
   converter._ignore_transforms = _ignore_transforms;
 
-  // Copy in the animation parameters.
-  apply_animation_parameters(converter);
+  // Copy in the path and animation parameters.
+  apply_parameters(converter);
 
   // Set the coordinate system to match Maya's.
   if (!_got_coordinate_system) {
@@ -113,7 +112,7 @@ run() {
   }
 
   converter.set_egg_data(&_data, false);
-  converter.set_texture_path_convert(_texture_path_convert, _make_rel_dir);
+  apply_parameters(converter);
 
   if (!converter.convert_file(_input_filename)) {
     nout << "Errors in conversion.\n";

+ 6 - 2
pandatool/src/pandatoolbase/Sources.pp

@@ -4,11 +4,15 @@
   #define SOURCES \
     animationConvert.cxx animationConvert.h \
     distanceUnit.cxx distanceUnit.h \
-    pandatoolbase.cxx pandatoolbase.h pandatoolsymbols.h
+    pandatoolbase.cxx pandatoolbase.h pandatoolsymbols.h \
+    pathReplace.cxx pathReplace.I pathReplace.h \
+    pathStore.cxx pathStore.h
 
   #define INSTALL_HEADERS \
     animationConvert.h \
     distanceUnit.h \
-    pandatoolbase.h pandatoolsymbols.h
+    pandatoolbase.h pandatoolsymbols.h \
+    pathReplace.I pathReplace.h \
+    pathStore.h
 
 #end ss_lib_target

+ 161 - 0
pandatool/src/pandatoolbase/pathReplace.I

@@ -0,0 +1,161 @@
+// Filename: pathReplace.I
+// Created by:  drose (07Feb03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::clear
+//       Access: Public
+//  Description: Removes all the patterns from the specification.
+////////////////////////////////////////////////////////////////////
+INLINE void PathReplace::
+clear() {
+  _entries.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::add_pattern
+//       Access: Public
+//  Description: Adds the indicated original/replace pattern to the
+//               specification.  If a filename is encountered whose
+//               initial prefix matches the indicated orig_prefix,
+//               that prefix will be replaced with replacement_prefix.
+////////////////////////////////////////////////////////////////////
+INLINE void PathReplace::
+add_pattern(const string &orig_prefix, const string &replacement_prefix) {
+  _entries.push_back(Entry(orig_prefix, replacement_prefix));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::get_num_patterns
+//       Access: Public
+//  Description: Returns the number of original/replace patterns that
+//               have been added.
+////////////////////////////////////////////////////////////////////
+INLINE int PathReplace::
+get_num_patterns() const {
+  return _entries.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::get_orig_prefix
+//       Access: Public
+//  Description: Returns the original prefix associated with the nth
+//               pattern.
+////////////////////////////////////////////////////////////////////
+INLINE const string &PathReplace::
+get_orig_prefix(int n) const {
+  nassertr(n >= 0 && n < (int)_entries.size(), _entries[0]._orig_prefix);
+  return _entries[n]._orig_prefix;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::get_replacement_prefix
+//       Access: Public
+//  Description: Returns the replacement prefix associated with the nth
+//               pattern.
+////////////////////////////////////////////////////////////////////
+INLINE const string &PathReplace::
+get_replacement_prefix(int n) const {
+  nassertr(n >= 0 && n < (int)_entries.size(), _entries[0]._replacement_prefix);
+  return _entries[n]._replacement_prefix;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::is_empty
+//       Access: Public
+//  Description: Returns true if the PathReplace object specifies no
+//               action, or false if convert_path() may do something.
+////////////////////////////////////////////////////////////////////
+INLINE bool PathReplace::
+is_empty() const {
+  return (_entries.empty() && _path.is_empty() && _path_store == PS_keep);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::convert_path
+//       Access: Public
+//  Description: Calls match_path() followed by store_path(), to
+//               replace the initial prefix and then convert the file
+//               for storing, as the user indicated.
+////////////////////////////////////////////////////////////////////
+INLINE Filename PathReplace::
+convert_path(const Filename &orig_filename, const DSearchPath &additional_path) {
+  return store_path(match_path(orig_filename, additional_path));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::Component::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE PathReplace::Component::
+Component(const string &component) :
+  _orig_prefix(component),
+  _double_star(component == "**")
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::Component::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE PathReplace::Component::
+Component(const PathReplace::Component &copy) :
+  _orig_prefix(copy._orig_prefix),
+  _double_star(copy._double_star)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::Component::Copy Assignment
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void PathReplace::Component::
+operator = (const PathReplace::Component &copy) {
+  _orig_prefix = copy._orig_prefix;
+  _double_star = copy._double_star;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::Entry::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE PathReplace::Entry::
+Entry(const PathReplace::Entry &copy) :
+  _orig_prefix(copy._orig_prefix),
+  _orig_components(copy._orig_components),
+  _is_local(copy._is_local),
+  _replacement_prefix(copy._replacement_prefix)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::Entry::Copy Assignment
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void PathReplace::Entry::
+operator = (const PathReplace::Entry &copy) {
+  _orig_prefix = copy._orig_prefix;
+  _orig_components = copy._orig_components;
+  _is_local = copy._is_local;
+  _replacement_prefix = copy._replacement_prefix;
+}

+ 278 - 0
pandatool/src/pandatoolbase/pathReplace.cxx

@@ -0,0 +1,278 @@
+// Filename: pathReplace.cxx
+// Created by:  drose (07Feb03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pathReplace.h"
+#include "config_util.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+PathReplace::
+PathReplace() {
+  _path_store = PS_keep;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::Destructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+PathReplace::
+~PathReplace() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::match_path
+//       Access: Public
+//  Description: Looks for a match for the given filename among all
+//               the replacement patterns, and returns the first match
+//               found.  If additional_path is nonempty, it is an
+//               additional search path on which to look for the file.
+//               The model_path is always implicitly searched.
+////////////////////////////////////////////////////////////////////
+Filename PathReplace::
+match_path(const Filename &orig_filename, 
+           const DSearchPath &additional_path) {
+  Filename match;
+  bool got_match = false;
+
+  if (_entries.empty()) {
+    // If we have no entries, still look up the file on the search
+    // path (unless _path_store is PS_keep).
+    if (_path_store != PS_keep) {
+      Filename new_filename = orig_filename;
+      if (new_filename.resolve_filename(_path) ||
+          new_filename.resolve_filename(additional_path) ||
+          new_filename.resolve_filename(get_model_path())) {
+        // Found it!
+        return new_filename;
+      }
+    }
+
+  } else {
+    Entries::const_iterator ei;
+    for (ei = _entries.begin(); ei != _entries.end(); ++ei) {
+      const Entry &entry = (*ei);
+      Filename new_filename;
+      if (entry.try_match(orig_filename, new_filename)) {
+        // The prefix matches.  Save the resulting filename for
+        // posterity.
+        got_match = true;
+        match = new_filename;
+        
+        if (new_filename.is_fully_qualified()) {
+          // If the resulting filename is fully qualified, it's a match
+          // if and only if it exists.
+          if (new_filename.exists()) {
+            return new_filename;
+          }
+          
+        } else {
+          // Otherwise, if it's a relative filename, attempt to look it
+          // up on the search path.
+          if (new_filename.resolve_filename(_path) ||
+              new_filename.resolve_filename(additional_path) ||
+              new_filename.resolve_filename(get_model_path())) {
+            // Found it!
+            if (_path_store == PS_keep) {
+              // If we asked to "keep" the pathname, we return the
+              // matched path, but not the found path.
+              return match;
+            } else {
+              // Otherwise, we return the actual, found path.
+              return new_filename;
+            }
+          }
+        }
+        
+        // The prefix matched, but it didn't exist.  Keep looking.
+      }
+    }
+  }
+
+  // The file couldn't be found anywhere.  Did we at least get any
+  // prefix match?
+  if (got_match) {
+    return match;
+  }
+
+  // Nope, couldn't find anything.  Just return the original filename.
+  return orig_filename;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::store_path
+//       Access: Public
+//  Description: Given a path to an existing filename, converts it as
+//               specified in the _path_store and or _path_directory
+//               properties to a form suitable for storing in an
+//               output file.
+////////////////////////////////////////////////////////////////////
+Filename PathReplace::
+store_path(const Filename &orig_filename) {
+  if (_path_directory.is_local()) {
+    _path_directory.make_absolute();
+  }
+  Filename filename = orig_filename;
+
+  switch (_path_store) {
+  case PS_relative:
+    filename.make_absolute();
+    filename.make_relative_to(_path_directory);
+    break;
+
+  case PS_absolute:
+    filename.make_absolute();
+    break;
+
+  case PS_rel_abs:
+    filename.make_absolute();
+    filename.make_relative_to(_path_directory, false);
+    break;
+
+  case PS_strip:
+    filename = filename.get_basename();
+    break;
+
+  case PS_keep:
+    break;
+
+  case PS_invalid:
+    break;
+  }
+
+  return filename;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::Entry::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PathReplace::Entry::
+Entry(const string &orig_prefix, const string &replacement_prefix) :
+  _orig_prefix(orig_prefix),
+  _replacement_prefix(replacement_prefix)
+{
+  // Eliminate trailing slashes; they're implicit.
+  if (_orig_prefix.length() > 1 &&
+      _orig_prefix[_orig_prefix.length() - 1] == '/') {
+    _orig_prefix = _orig_prefix.substr(0, _orig_prefix.length() - 1);
+  }
+  if (_replacement_prefix.length() > 1 &&
+      _replacement_prefix[_replacement_prefix.length() - 1] == '/') {
+    _replacement_prefix = _replacement_prefix.substr(0, _replacement_prefix.length() - 1);
+  }
+
+  Filename filename(_orig_prefix);
+  _is_local = filename.is_local();
+
+  vector_string components;
+  filename.extract_components(components);
+  vector_string::const_iterator ci;
+  for (ci = components.begin(); ci != components.end(); ++ci) {
+    _orig_components.push_back(Component(*ci));
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::Entry::try_match
+//       Access: Public
+//  Description: Considers whether the indicated filename matches
+//               this entry's prefix.  If so, switches the prefix and
+//               stores the result in new_filename, and returns true;
+//               otherwise, returns false.
+////////////////////////////////////////////////////////////////////
+bool PathReplace::Entry::
+try_match(const Filename &filename, Filename &new_filename) const {
+  if (_is_local != filename.is_local()) {
+    return false;
+  }
+  vector_string components;
+  filename.extract_components(components);
+  size_t mi = r_try_match(components, 0, 0);
+  if (mi == 0) {
+    // Sorry, no match.
+    return false;
+  }
+
+  // We found a match.  Construct the replacement string.
+  string result = _replacement_prefix;
+  while (mi < components.size()) {
+    if (!result.empty()) {
+      result += '/';
+    }
+    result += components[mi];
+    ++mi;
+  }
+  new_filename = result;
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::Entry::r_try_match
+//       Access: Public
+//  Description: The recursive implementation of try_match().
+//               Actually, this is doubly-recursive, to implement the
+//               "**" feature.
+//
+//               The return value is the number of the "components"
+//               vector that successfully matched against all of the
+//               orig_components.  (It's a variable number because
+//               there might be one or more "**" entries.)
+////////////////////////////////////////////////////////////////////
+size_t PathReplace::Entry::
+r_try_match(const vector_string &components, size_t oi, size_t ci) const {
+  if (oi >= _orig_components.size()) {
+    // If we ran out of user-supplied components, we're done.
+    return ci;
+  }
+  if (ci >= components.size()) {
+    // If we reached the end of the string, but we still have
+    // user-supplied components, we failed.  (Arguably there should be
+    // a special case here for a user-supplied string that ends in
+    // "**", but I don't think the user ever wants to match the
+    // complete string.)
+    return 0;
+  }
+
+  const Component &orig_component = _orig_components[oi];
+  if (orig_component._double_star) {
+    // If we have a double star, first consider the match if it were
+    // expanded as far as possible.
+    size_t mi = r_try_match(components, oi, ci + 1);
+    if (mi != 0) {
+      return mi;
+    }
+
+    // Then try the match as if it there were no double star entry.
+    return r_try_match(components, oi + 1, ci);
+  }
+
+  // We don't have a double star, it's just a one-for-one component
+  // entry.  Does it match?
+  if (orig_component._orig_prefix.matches(components[ci])) {
+    // It does!  Keep going.
+    return r_try_match(components, oi + 1, ci + 1);
+  }
+
+  // It doesn't match, sorry.
+  return 0;
+}

+ 108 - 0
pandatool/src/pandatoolbase/pathReplace.h

@@ -0,0 +1,108 @@
+// Filename: pathReplace.h
+// Created by:  drose (07Feb03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PATHREPLACE_H
+#define PATHREPLACE_H
+
+#include "pandatoolbase.h"
+#include "pathStore.h"
+#include "referenceCount.h"
+#include "globPattern.h"
+#include "filename.h"
+#include "dSearchPath.h"
+#include "pvector.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : PathReplace
+// Description : This encapsulates the user's command-line request to
+//               replace existing, incorrect pathnames to models and
+//               textures from a file with correct pathnames.  It
+//               corresponds to a sequence of -pr command-line
+//               options, as well as the -pp option.
+//
+//               This can also go the next step, which is to convert a
+//               known file into a suitable form for storing in a
+//               model file.  In this capacity, it corresponds to the
+//               -ps and -pd options.
+////////////////////////////////////////////////////////////////////
+class PathReplace : public ReferenceCount {
+public:
+  PathReplace();
+  ~PathReplace();
+
+  INLINE void clear();
+  INLINE void add_pattern(const string &orig_prefix, const string &replacement_prefix);
+
+  INLINE int get_num_patterns() const;
+  INLINE const string &get_orig_prefix(int n) const;
+  INLINE const string &get_replacement_prefix(int n) const;
+
+  INLINE bool is_empty() const;
+
+  Filename match_path(const Filename &orig_filename, 
+                      const DSearchPath &additional_path = DSearchPath());
+  Filename store_path(const Filename &orig_filename);
+
+  INLINE Filename convert_path(const Filename &orig_filename,
+                               const DSearchPath &additional_path = DSearchPath());
+
+public:
+  // This is used (along with _entries) to support match_path().
+  DSearchPath _path;
+
+  // These are used to support store_path().
+  PathStore _path_store;
+  Filename _path_directory;
+
+private:
+  class Component {
+  public:
+    INLINE Component(const string &component);
+    INLINE Component(const Component &copy);
+    INLINE void operator = (const Component &copy);
+
+    GlobPattern _orig_prefix;
+    bool _double_star;
+  };
+  typedef pvector<Component> Components;
+
+  class Entry {
+  public:
+    Entry(const string &orig_prefix, const string &replacement_prefix);
+    INLINE Entry(const Entry &copy);
+    INLINE void operator = (const Entry &copy);
+
+    bool try_match(const Filename &filename, Filename &new_filename) const;
+    size_t r_try_match(const vector_string &components, size_t oi, size_t ci) const;
+
+    string _orig_prefix;
+    Components _orig_components;
+    bool _is_local;
+    string _replacement_prefix;
+  };
+
+  typedef pvector<Entry> Entries;
+  Entries _entries;
+};
+
+#include "pathReplace.I"
+
+#endif
+
+  
+  

+ 90 - 0
pandatool/src/pandatoolbase/pathStore.cxx

@@ -0,0 +1,90 @@
+// Filename: pathStore.cxx
+// Created by:  drose (10Feb03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pathStore.h"
+
+#include "string_utils.h"
+#include "notify.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: format_path_store
+//  Description: Returns the string corresponding to this method.
+////////////////////////////////////////////////////////////////////
+string
+format_path_store(PathStore store) {
+  switch (store) {
+  case PS_invalid:
+    return "invalid";
+
+  case PS_relative:
+    return "relative";
+
+  case PS_absolute:
+    return "absolute";
+
+  case PS_rel_abs:
+    return "rel_abs";
+
+  case PS_strip:
+    return "strip";
+
+  case PS_keep:
+    return "keep";
+  }
+  nout << "**unexpected PathStore value: (" << (int)store << ")**";
+  return "**";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathStore output operator
+//  Description:
+////////////////////////////////////////////////////////////////////
+ostream &
+operator << (ostream &out, PathStore store) {
+  return out << format_path_store(store);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: string_path_store
+//  Description: Stores from a string, as might be input by the
+//               user, to one of the known PathStore types.
+//               Returns PS_invalid if the string is unknown.
+////////////////////////////////////////////////////////////////////
+PathStore
+string_path_store(const string &str) {
+  if (cmp_nocase(str, "relative") == 0 || 
+      cmp_nocase(str, "rel") == 0) {
+    return PS_relative;
+
+  } else if (cmp_nocase(str, "absolute") == 0 ||
+             cmp_nocase(str, "abs") == 0) {
+    return PS_absolute;
+
+  } else if (cmp_nocase_uh(str, "rel_abs") == 0) {
+    return PS_rel_abs;
+
+  } else if (cmp_nocase(str, "strip") == 0) {
+    return PS_strip;
+
+  } else if (cmp_nocase(str, "keep") == 0) {
+    return PS_keep;
+
+  } else {
+    return PS_invalid;
+  }
+}

+ 44 - 0
pandatool/src/pandatoolbase/pathStore.h

@@ -0,0 +1,44 @@
+// Filename: pathStore.h
+// Created by:  drose (10Feb03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PATHSTORE_H
+#define PATHSTORE_H
+
+#include "pandatoolbase.h"
+
+////////////////////////////////////////////////////////////////////
+//        Enum : PathStore
+// Description : This enumerated type lists the methods by which
+//               a filename path might be mangled before storing in a
+//               destination file.
+////////////////////////////////////////////////////////////////////
+enum PathStore {
+  PS_invalid,    // Never use this.
+  PS_relative,   // Make relative to a user-specified directory.
+  PS_absolute,   // Make absolute.
+  PS_rel_abs,    // Make relative if within the directory, otherwise absolute.
+  PS_strip,      // Strip prefix and just store the basename.
+  PS_keep,       // Don't change the filename at all.
+};
+
+string format_path_store(PathStore unit);
+
+ostream &operator << (ostream &out, PathStore unit);
+PathStore string_path_store(const string &str);
+
+#endif

+ 134 - 0
pandatool/src/progbase/programBase.cxx

@@ -87,6 +87,15 @@ ProgramBase() {
   // And we'll want to be sure to flush that in all normal exit cases.
   atexit(&flush_nout);
 
+  _path_replace = new PathReplace;
+
+  // If a program never adds the path store options, the default path
+  // store is PS_absolute.  This is the most robust solution for
+  // programs that read files but do not need to write them.
+  _path_replace->_path_store = PS_absolute;
+  _got_path_store = false;
+  _got_path_directory = false;
+
   _next_sequence = 0;
   _sorted_options = false;
   _last_newline = false;
@@ -618,6 +627,86 @@ remove_option(const string &option) {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ProgramBase::add_path_replace_options
+//       Access: Public
+//  Description: Adds -pr etc. as valid options for this program.
+//               These are appropriate for a model converter or model
+//               reader type program, and specify how to locate
+//               possibly-invalid pathnames in the source model file.
+////////////////////////////////////////////////////////////////////
+void ProgramBase::
+add_path_replace_options() {
+  add_option
+    ("pr", "path_replace", 40,
+     "Sometimes references to other files (textures, external references) "
+     "are stored with a full path that is appropriate for some other system, "
+     "but does not exist here.  This option may be used to specify how "
+     "those invalid paths map to correct paths.  Generally, this is of "
+     "the form 'orig_prefix=replacement_prefix', which indicates a "
+     "particular initial sequence of characters that should be replaced "
+     "with a new sequence; e.g. '/c/home/models=/beta/fish'.  "
+     "If the replacement prefix does not begin with a slash, the file "
+     "will then be searched for along the search path specified by -pp.  "
+     "You may use standard filename matching characters ('*', '?', etc.) in "
+     "the original prefix, and '**' as a component by itself stands for "
+     "any number of components.\n\n"
+
+     "This option may be repeated as necessary; each file will be tried "
+     "against each specified method, in the order in which they appear in "
+     "the command line, until the file is found.  If the file is not found, "
+     "the last matching prefix is used anyway.",
+     &ProgramBase::dispatch_path_replace, NULL, _path_replace.p());
+
+  add_option
+    ("pp", "dirname", 40,
+     "Adds the indicated directory name to the list of directories to "
+     "search for filenames referenced by the source file.  This is used "
+     "only for relative paths, or for paths that are made relative by a "
+     "-pr replacement string that doesn't begin with a leading slash.  "
+     "The model-path is always implicitly searched anyway.",
+     &ProgramBase::dispatch_search_path, NULL, &(_path_replace->_path));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProgramBase::add_path_store_options
+//       Access: Public
+//  Description: Adds -ps etc. as valid options for this program.
+//               These are appropriate for a model converter type
+//               program, and specify how to represent filenames in
+//               the output file.
+////////////////////////////////////////////////////////////////////
+void ProgramBase::
+add_path_store_options() {
+  // If a program has path store options at all, the default path
+  // store is relative.
+  _path_replace->_path_store = PS_relative;
+
+  add_option
+    ("ps", "path_store", 40,
+     "Specifies the way an externally referenced file is to be "
+     "represented in the resulting output file.  This "
+     "assumes the named filename actually exists; "
+     "see -pr to indicate how to deal with external "
+     "references that have bad pathnames.  "
+     "This option will not help you to find a missing file, but simply "
+     "controls how filenames are represented in the output.\n\n"
+
+     "The option may be one of: rel, abs, rel_abs, strip, or keep.  If "
+     "either rel or rel_abs is specified, the files are made relative to "
+     "the directory specified by -pd.  The default is rel.",
+     &ProgramBase::dispatch_path_store, &_got_path_store, 
+     &(_path_replace->_path_store));
+
+  add_option
+    ("pd", "path_directory", 40,
+     "Specifies the name of a directory to make paths relative to, if "
+     "'-ps rel' or '-ps rel_abs' is specified.  If this is omitted, the "
+     "directory name is taken from the name of the output file.",
+     &ProgramBase::dispatch_filename, &_got_path_directory, 
+     &(_path_replace->_path_directory));
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ProgramBase::dispatch_none
 //       Access: Protected, Static
@@ -1019,6 +1108,51 @@ dispatch_image_type(const string &opt, const string &arg, void *var) {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ProgramBase::dispatch_path_replace
+//       Access: Protected, Static
+//  Description: Standard dispatch function for an option that takes
+//               one parameter, which is to be interpreted as a
+//               single component of a path replace request.  The data
+//               pointer is to a PathReplace variable.
+////////////////////////////////////////////////////////////////////
+bool ProgramBase::
+dispatch_path_replace(const string &opt, const string &arg, void *var) {
+  PathReplace *ip = (PathReplace *)var;
+  size_t equals = arg.find('=');
+  if (equals == string::npos) {
+    nout << "Invalid path replacement string for -" << opt << ": " << arg << "\n"
+         << "String should be of the form 'old-prefix=new-prefix'.\n";
+    return false;
+  }
+  ip->add_pattern(arg.substr(0, equals), arg.substr(equals + 1));
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProgramBase::dispatch_path_store
+//       Access: Protected, Static
+//  Description: Standard dispatch function for an option that takes
+//               one parameter, which is to be interpreted as a
+//               path store string.  The data pointer is to a
+//               PathStore variable.
+////////////////////////////////////////////////////////////////////
+bool ProgramBase::
+dispatch_path_store(const string &opt, const string &arg, void *var) {
+  PathStore *ip = (PathStore *)var;
+  (*ip) = string_path_store(arg);
+
+  if ((*ip) == PS_invalid) {
+    nout << "Invalid path store for -" << opt << ": " << arg << "\n"
+         << "Valid path store strings are any of 'rel', 'abs', "
+         << "'rel_abs', 'strip', or 'keep'.\n";
+    return false;
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ProgramBase::handle_help_option
 //       Access: Protected, Static

+ 18 - 7
pandatool/src/progbase/programBase.h

@@ -19,13 +19,14 @@
 #ifndef PROGRAMBASE_H
 #define PROGRAMBASE_H
 
-#include <pandatoolbase.h>
-
-#include <distanceUnit.h>
-#include <filename.h>
-#include <vector_string.h>
-
-#include <string>
+#include "pandatoolbase.h"
+
+#include "distanceUnit.h"
+#include "pathReplace.h"
+#include "pathStore.h"
+#include "filename.h"
+#include "pointerTo.h"
+#include "vector_string.h"
 #include "pvector.h"
 #include "pdeque.h"
 #include "pmap.h"
@@ -81,6 +82,9 @@ protected:
   bool redescribe_option(const string &option, const string &description);
   bool remove_option(const string &option);
 
+  void add_path_replace_options();
+  void add_path_store_options();
+
   static bool dispatch_none(const string &opt, const string &arg, void *);
   static bool dispatch_true(const string &opt, const string &arg, void *var);
   static bool dispatch_false(const string &opt, const string &arg, void *var);
@@ -98,6 +102,8 @@ protected:
   static bool dispatch_coordinate_system(const string &opt, const string &arg, void *var);
   static bool dispatch_units(const string &opt, const string &arg, void *var);
   static bool dispatch_image_type(const string &opt, const string &arg, void *var);
+  static bool dispatch_path_replace(const string &opt, const string &arg, void *var);
+  static bool dispatch_path_store(const string &opt, const string &arg, void *var);
 
   static bool handle_help_option(const string &opt, const string &arg, void *);
 
@@ -105,6 +111,11 @@ protected:
                           const string &prefix, int indent_width,
                           const string &text, int line_width);
 
+  PT(PathReplace) _path_replace;
+  bool _got_path_store;
+  bool _got_path_directory;
+
+
 private:
   void sort_options();
   void get_terminal_width();