diff --git a/pandatool/src/converter/somethingToEggConverter.I b/pandatool/src/converter/somethingToEggConverter.I index df0fa25e98..55940a0440 100644 --- a/pandatool/src/converter/somethingToEggConverter.I +++ b/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); } diff --git a/pandatool/src/converter/somethingToEggConverter.cxx b/pandatool/src/converter/somethingToEggConverter.cxx index 45f7600b1a..044327a99b 100644 --- a/pandatool/src/converter/somethingToEggConverter.cxx +++ b/pandatool/src/converter/somethingToEggConverter.cxx @@ -18,8 +18,8 @@ #include "somethingToEggConverter.h" -#include -#include +#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 ©) : _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; -} diff --git a/pandatool/src/converter/somethingToEggConverter.h b/pandatool/src/converter/somethingToEggConverter.h index 061425d476..4fabf33f09 100644 --- a/pandatool/src/converter/somethingToEggConverter.h +++ b/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; diff --git a/pandatool/src/egg-palettize/eggFile.cxx b/pandatool/src/egg-palettize/eggFile.cxx index aa17c3b587..b47b2ad5bc 100644 --- a/pandatool/src/egg-palettize/eggFile.cxx +++ b/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; diff --git a/pandatool/src/eggbase/eggBase.cxx b/pandatool/src/eggbase/eggBase.cxx index 6225f4382c..b8671bc53b 100644 --- a/pandatool/src/eggbase/eggBase.cxx +++ b/pandatool/src/eggbase/eggBase.cxx @@ -18,7 +18,11 @@ #include "eggBase.h" -#include +#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 diff --git a/pandatool/src/eggbase/eggBase.h b/pandatool/src/eggbase/eggBase.h index d8beb4b22a..dc12ae7d7e 100644 --- a/pandatool/src/eggbase/eggBase.h +++ b/pandatool/src/eggbase/eggBase.h @@ -19,14 +19,16 @@ #ifndef EGGBASE_H #define EGGBASE_H -#include +#include "pandatoolbase.h" -#include -#include -#include +#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); diff --git a/pandatool/src/eggbase/eggFilter.cxx b/pandatool/src/eggbase/eggFilter.cxx index 7b597f06a0..3fda42737e 100644 --- a/pandatool/src/eggbase/eggFilter.cxx +++ b/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(); } diff --git a/pandatool/src/eggbase/eggMultiBase.cxx b/pandatool/src/eggbase/eggMultiBase.cxx index f3d797ec75..72750d2595 100644 --- a/pandatool/src/eggbase/eggMultiBase.cxx +++ b/pandatool/src/eggbase/eggMultiBase.cxx @@ -17,10 +17,11 @@ //////////////////////////////////////////////////////////////////// #include "eggMultiBase.h" - -#include -#include -#include +#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; } } diff --git a/pandatool/src/eggbase/eggMultiFilter.cxx b/pandatool/src/eggbase/eggMultiFilter.cxx index 4bce47b219..78442d71d9 100644 --- a/pandatool/src/eggbase/eggMultiFilter.cxx +++ b/pandatool/src/eggbase/eggMultiFilter.cxx @@ -18,8 +18,8 @@ #include "eggMultiFilter.h" -#include -#include +#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) { diff --git a/pandatool/src/eggbase/eggReader.cxx b/pandatool/src/eggbase/eggReader.cxx index 1464bc1538..310740d085 100644 --- a/pandatool/src/eggbase/eggReader.cxx +++ b/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; diff --git a/pandatool/src/eggbase/eggWriter.cxx b/pandatool/src/eggbase/eggWriter.cxx index d22db396c5..6a46bb4d0e 100644 --- a/pandatool/src/eggbase/eggWriter.cxx +++ b/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; } diff --git a/pandatool/src/eggbase/somethingToEgg.cxx b/pandatool/src/eggbase/somethingToEgg.cxx index 5b10847fb1..8467981c2b 100644 --- a/pandatool/src/eggbase/somethingToEgg.cxx +++ b/pandatool/src/eggbase/somethingToEgg.cxx @@ -17,8 +17,9 @@ //////////////////////////////////////////////////////////////////// #include "somethingToEgg.h" +#include "somethingToEggConverter.h" -#include +#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; -} diff --git a/pandatool/src/eggbase/somethingToEgg.h b/pandatool/src/eggbase/somethingToEgg.h index dcf73cfb54..c5c267b8b0 100644 --- a/pandatool/src/eggbase/somethingToEgg.h +++ b/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; }; diff --git a/pandatool/src/eggprogs/eggTrans.cxx b/pandatool/src/eggprogs/eggTrans.cxx index 8d531aa441..95dc3f565c 100644 --- a/pandatool/src/eggprogs/eggTrans.cxx +++ b/pandatool/src/eggprogs/eggTrans.cxx @@ -17,8 +17,7 @@ //////////////////////////////////////////////////////////////////// #include "eggTrans.h" - -#include +#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(); diff --git a/pandatool/src/flt/fltExternalReference.cxx b/pandatool/src/flt/fltExternalReference.cxx index f12da2cb69..8f15273a71 100644 --- a/pandatool/src/flt/fltExternalReference.cxx +++ b/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); } //////////////////////////////////////////////////////////////////// diff --git a/pandatool/src/flt/fltExternalReference.h b/pandatool/src/flt/fltExternalReference.h index 14436d443d..fdd426d8fa 100644 --- a/pandatool/src/flt/fltExternalReference.h +++ b/pandatool/src/flt/fltExternalReference.h @@ -19,11 +19,11 @@ #ifndef FLTEXTERNALREFERENCE_H #define FLTEXTERNALREFERENCE_H -#include +#include "pandatoolbase.h" #include "fltBead.h" -#include +#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 { diff --git a/pandatool/src/flt/fltHeader.cxx b/pandatool/src/flt/fltHeader.cxx index 628f3332ff..029553343e 100644 --- a/pandatool/src/flt/fltHeader.cxx +++ b/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 diff --git a/pandatool/src/flt/fltHeader.h b/pandatool/src/flt/fltHeader.h index b1abde331b..0c9f26c52a 100644 --- a/pandatool/src/flt/fltHeader.h +++ b/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. diff --git a/pandatool/src/flt/fltRecord.cxx b/pandatool/src/flt/fltRecord.cxx index 63ff0279c9..a5880ff37b 100644 --- a/pandatool/src/flt/fltRecord.cxx +++ b/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 diff --git a/pandatool/src/flt/fltRecord.h b/pandatool/src/flt/fltRecord.h index 34e2920af1..947e85f33e 100644 --- a/pandatool/src/flt/fltRecord.h +++ b/pandatool/src/flt/fltRecord.h @@ -19,19 +19,20 @@ #ifndef FLTRECORD_H #define FLTRECORD_H -#include +#include "pandatoolbase.h" #include "fltOpcode.h" #include "fltError.h" -#include -#include -#include +#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; diff --git a/pandatool/src/flt/fltTexture.cxx b/pandatool/src/flt/fltTexture.cxx index 82900468fa..c91b8261ca 100644 --- a/pandatool/src/flt/fltTexture.cxx +++ b/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); } //////////////////////////////////////////////////////////////////// diff --git a/pandatool/src/flt/fltTexture.h b/pandatool/src/flt/fltTexture.h index 4c27a784b3..8c963fb25b 100644 --- a/pandatool/src/flt/fltTexture.h +++ b/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; diff --git a/pandatool/src/fltegg/fltToEggConverter.cxx b/pandatool/src/fltegg/fltToEggConverter.cxx index 8020bbba4b..e6aad60a55 100644 --- a/pandatool/src/fltegg/fltToEggConverter.cxx +++ b/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); diff --git a/pandatool/src/fltegg/fltToEggConverter.h b/pandatool/src/fltegg/fltToEggConverter.h index 2bc0e6b2e4..09c7b55be8 100644 --- a/pandatool/src/fltegg/fltToEggConverter.h +++ b/pandatool/src/fltegg/fltToEggConverter.h @@ -19,18 +19,17 @@ #ifndef FLTTOEGGCONVERTER_H #define FLTTOEGGCONVERTER_H -#include +#include "pandatoolbase.h" #include "fltToEggLevelState.h" - -#include -#include -#include -#include -#include -#include -#include -#include +#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; diff --git a/pandatool/src/fltprogs/fltCopy.cxx b/pandatool/src/fltprogs/fltCopy.cxx index 05b8df3f3c..e6a572cf2c 100644 --- a/pandatool/src/fltprogs/fltCopy.cxx +++ b/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 diff --git a/pandatool/src/fltprogs/fltToEgg.cxx b/pandatool/src/fltprogs/fltToEgg.cxx index 799623f0c0..e729b55a74 100644 --- a/pandatool/src/fltprogs/fltToEgg.cxx +++ b/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); diff --git a/pandatool/src/fltprogs/fltTrans.cxx b/pandatool/src/fltprogs/fltTrans.cxx index f299117d79..cd36b5b1f7 100644 --- a/pandatool/src/fltprogs/fltTrans.cxx +++ b/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"; diff --git a/pandatool/src/fltprogs/fltTrans.h b/pandatool/src/fltprogs/fltTrans.h index aaa4dff9be..3f842c72d1 100644 --- a/pandatool/src/fltprogs/fltTrans.h +++ b/pandatool/src/fltprogs/fltTrans.h @@ -19,12 +19,10 @@ #ifndef FLTTRANS_H #define FLTTRANS_H -#include +#include "pandatoolbase.h" -#include -#include - -#include +#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; }; diff --git a/pandatool/src/lwoprogs/lwoToEgg.cxx b/pandatool/src/lwoprogs/lwoToEgg.cxx index 92873e025a..4963d06e57 100644 --- a/pandatool/src/lwoprogs/lwoToEgg.cxx +++ b/pandatool/src/lwoprogs/lwoToEgg.cxx @@ -18,10 +18,10 @@ #include "lwoToEgg.h" -#include -#include -#include -#include +#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"; diff --git a/pandatool/src/lwoprogs/lwoToEgg.h b/pandatool/src/lwoprogs/lwoToEgg.h index 04e68332ba..8bae0e871a 100644 --- a/pandatool/src/lwoprogs/lwoToEgg.h +++ b/pandatool/src/lwoprogs/lwoToEgg.h @@ -19,12 +19,12 @@ #ifndef LWOTOEGG_H #define LWOTOEGG_H -#include +#include "pandatoolbase.h" -#include -#include +#include "somethingToEgg.h" +#include "lwoToEggConverter.h" -#include +#include "dSearchPath.h" //////////////////////////////////////////////////////////////////// // Class : LwoToEgg @@ -36,8 +36,6 @@ public: LwoToEgg(); void run(); - -protected: }; #endif diff --git a/pandatool/src/mayaprogs/mayaCopy.cxx b/pandatool/src/mayaprogs/mayaCopy.cxx index 267b84d4eb..fc7bfc855e 100644 --- a/pandatool/src/mayaprogs/mayaCopy.cxx +++ b/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"; /* diff --git a/pandatool/src/mayaprogs/mayaToEgg.cxx b/pandatool/src/mayaprogs/mayaToEgg.cxx index 4911a9fddb..4e400d9133 100644 --- a/pandatool/src/mayaprogs/mayaToEgg.cxx +++ b/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"; diff --git a/pandatool/src/pandatoolbase/Sources.pp b/pandatool/src/pandatoolbase/Sources.pp index 2af3870f58..2f50398d09 100644 --- a/pandatool/src/pandatoolbase/Sources.pp +++ b/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 diff --git a/pandatool/src/pandatoolbase/pathReplace.I b/pandatool/src/pandatoolbase/pathReplace.I new file mode 100755 index 0000000000..c6c9b33ec8 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// 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 ©) : + _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 ©) { + _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 ©) : + _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 ©) { + _orig_prefix = copy._orig_prefix; + _orig_components = copy._orig_components; + _is_local = copy._is_local; + _replacement_prefix = copy._replacement_prefix; +} diff --git a/pandatool/src/pandatoolbase/pathReplace.cxx b/pandatool/src/pandatoolbase/pathReplace.cxx new file mode 100755 index 0000000000..c8d6ca5f6b --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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; +} diff --git a/pandatool/src/pandatoolbase/pathReplace.h b/pandatool/src/pandatoolbase/pathReplace.h new file mode 100755 index 0000000000..a7b5b00e06 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 ©); + INLINE void operator = (const Component ©); + + GlobPattern _orig_prefix; + bool _double_star; + }; + typedef pvector Components; + + class Entry { + public: + Entry(const string &orig_prefix, const string &replacement_prefix); + INLINE Entry(const Entry ©); + INLINE void operator = (const Entry ©); + + 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 Entries; + Entries _entries; +}; + +#include "pathReplace.I" + +#endif + + + diff --git a/pandatool/src/pandatoolbase/pathStore.cxx b/pandatool/src/pandatoolbase/pathStore.cxx new file mode 100755 index 0000000000..1c0f35ec32 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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; + } +} diff --git a/pandatool/src/pandatoolbase/pathStore.h b/pandatool/src/pandatoolbase/pathStore.h new file mode 100755 index 0000000000..3c5b2cb9d1 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 diff --git a/pandatool/src/progbase/programBase.cxx b/pandatool/src/progbase/programBase.cxx index 1ee054a458..2d6e51282c 100644 --- a/pandatool/src/progbase/programBase.cxx +++ b/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 diff --git a/pandatool/src/progbase/programBase.h b/pandatool/src/progbase/programBase.h index bf8c2e3edf..4ee2adcbae 100644 --- a/pandatool/src/progbase/programBase.h +++ b/pandatool/src/progbase/programBase.h @@ -19,13 +19,14 @@ #ifndef PROGRAMBASE_H #define PROGRAMBASE_H -#include +#include "pandatoolbase.h" -#include -#include -#include - -#include +#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();