diff --git a/pandatool/src/eggbase/eggFilter.cxx b/pandatool/src/eggbase/eggFilter.cxx index 708e65a2e5..a8f8597b02 100644 --- a/pandatool/src/eggbase/eggFilter.cxx +++ b/pandatool/src/eggbase/eggFilter.cxx @@ -61,3 +61,13 @@ handle_args(ProgramBase::Args &args) { return EggReader::handle_args(args); } + +//////////////////////////////////////////////////////////////////// +// Function: EggFilter::post_command_line +// Access: Protected, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +bool EggFilter:: +post_command_line() { + return EggReader::post_command_line() && EggWriter::post_command_line(); +} diff --git a/pandatool/src/eggbase/eggFilter.h b/pandatool/src/eggbase/eggFilter.h index 1a11f6da68..f011806443 100644 --- a/pandatool/src/eggbase/eggFilter.h +++ b/pandatool/src/eggbase/eggFilter.h @@ -36,6 +36,7 @@ public: protected: virtual bool handle_args(Args &args); + virtual bool post_command_line(); }; #endif diff --git a/pandatool/src/eggbase/eggReader.cxx b/pandatool/src/eggbase/eggReader.cxx index 19d08bbaa1..5ed5d66b51 100644 --- a/pandatool/src/eggbase/eggReader.cxx +++ b/pandatool/src/eggbase/eggReader.cxx @@ -18,6 +18,10 @@ #include "eggReader.h" +#include "pnmImage.h" +#include "config_util.h" +#include "eggTextureCollection.h" + //////////////////////////////////////////////////////////////////// // Function: EggReader::Constructor // Access: Public @@ -39,6 +43,43 @@ EggReader() { "Force complete loading: load up the egg file along with all of its " "external references.", &EggReader::dispatch_none, &_force_complete); + + _tex_type = (PNMFileType *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: EggRead::add_texture_options +// Access: Public +// Description: Adds -td, -te, etc. as valid options for this +// program. If the user specifies one of the options on +// the command line, the textures will be copied and +// converted as each egg file is read. +//////////////////////////////////////////////////////////////////// +void EggReader:: +add_texture_options() { + add_option + ("td", "dirname", 40, + "Copy textures to the indicated directory. The copy is performed " + "only if the destination file does not exist or is older than the " + "source file.", + &EggReader::dispatch_filename, &_got_tex_dirname, &_tex_dirname); + + add_option + ("te", "ext", 40, + "Rename textures to have the indicated extension. This also " + "automatically copies them to the new filename (possibly in a " + "different directory if -td is also specified), and may implicitly " + "convert to a different image format according to the extension.", + &EggReader::dispatch_string, &_got_tex_extension, &_tex_extension); + + add_option + ("tt", "type", 40, + "Explicitly specifies the image format to convert textures to " + "when copying them via -td or -te. Normally, this is unnecessary as " + "the image format can be determined by the extension, but sometimes " + "the extension is insufficient to unambiguously specify an image " + "type.", + &EggReader::dispatch_image_type, NULL, &_tex_type); } //////////////////////////////////////////////////////////////////// @@ -99,3 +140,90 @@ handle_args(ProgramBase::Args &args) { return true; } + +//////////////////////////////////////////////////////////////////// +// Function: EggReader::post_command_line +// Access: Protected, Virtual +// Description: This is called after the command line has been +// completely processed, and it gives the program a +// chance to do some last-minute processing and +// validation of the options and arguments. It should +// return true if everything is fine, false if there is +// an error. +//////////////////////////////////////////////////////////////////// +bool EggReader:: +post_command_line() { + if (!copy_textures()) { + exit(1); + } + + return EggBase::post_command_line(); +} + +//////////////////////////////////////////////////////////////////// +// Function: EggReader::copy_textures +// Access: Protected +// Description: Renames and copies the textures referenced in the egg +// file, if so specified by the -td and -te options. +// Returns true if all textures are copied successfully, +// false if any one of them failed. +//////////////////////////////////////////////////////////////////// +bool EggReader:: +copy_textures() { + if (!_got_tex_dirname && !_got_tex_extension) { + return true; + } + + bool success = true; + EggTextureCollection textures; + textures.find_used_textures(&_data); + + EggTextureCollection::const_iterator ti; + for (ti = textures.begin(); ti != textures.end(); ++ti) { + EggTexture *tex = (*ti); + Filename orig_filename = tex->get_filename(); + if (!orig_filename.exists()) { + bool found = + orig_filename.resolve_filename(get_texture_path()) || + orig_filename.resolve_filename(get_model_path()); + if (!found) { + nout << "Cannot find " << orig_filename << "\n"; + success = false; + continue; + } + } + + Filename new_filename = orig_filename; + if (_got_tex_dirname) { + new_filename.set_dirname(_tex_dirname); + } + if (_got_tex_extension) { + new_filename.set_extension(_tex_extension); + } + + if (orig_filename != new_filename) { + tex->set_filename(new_filename); + + // The new filename is different; does it need copying? + int compare = + orig_filename.compare_timestamps(new_filename, true, true); + if (compare > 0) { + // Yes, it does. Copy it! + nout << "Reading " << orig_filename << "\n"; + PNMImage image; + if (!image.read(orig_filename)) { + nout << " unable to read!\n"; + success = false; + } else { + nout << "Writing " << new_filename << "\n"; + if (!image.write(new_filename, _tex_type)) { + nout << " unable to write!\n"; + success = false; + } + } + } + } + } + + return success; +} diff --git a/pandatool/src/eggbase/eggReader.h b/pandatool/src/eggbase/eggReader.h index 873b9bd6f9..aadd639367 100644 --- a/pandatool/src/eggbase/eggReader.h +++ b/pandatool/src/eggbase/eggReader.h @@ -19,10 +19,12 @@ #ifndef EGGREADER_H #define EGGREADER_H -#include +#include "pandatoolbase.h" #include "eggBase.h" +#include "filename.h" +class PNMFileType; //////////////////////////////////////////////////////////////////// // Class : EggReader @@ -33,12 +35,23 @@ class EggReader : virtual public EggBase { public: EggReader(); + void add_texture_options(); + virtual EggReader *as_reader(); protected: virtual bool handle_args(Args &args); + virtual bool post_command_line(); + +private: + bool copy_textures(); bool _force_complete; + Filename _tex_dirname; + bool _got_tex_dirname; + string _tex_extension; + bool _got_tex_extension; + PNMFileType *_tex_type; }; #endif diff --git a/pandatool/src/eggprogs/eggTrans.cxx b/pandatool/src/eggprogs/eggTrans.cxx index 1bcaf88664..0581a51e7d 100644 --- a/pandatool/src/eggprogs/eggTrans.cxx +++ b/pandatool/src/eggprogs/eggTrans.cxx @@ -29,6 +29,7 @@ EggTrans:: EggTrans() { add_normals_options(); add_transform_options(); + add_texture_options(); set_program_description ("egg-trans reads an egg file and writes an essentially equivalent " diff --git a/pandatool/src/progbase/programBase.cxx b/pandatool/src/progbase/programBase.cxx index 8fc8b67ece..e6a375b33b 100644 --- a/pandatool/src/progbase/programBase.cxx +++ b/pandatool/src/progbase/programBase.cxx @@ -19,17 +19,18 @@ #include "programBase.h" #include "wordWrapStream.h" -#include +#include "pystub.h" // Since programBase.cxx includes pystub.h, no program that links with // progbase needs to do so. No Python code should attempt to link // with libprogbase.so. -#include -#include -#include -#include -#include -#include +#include "pnmFileTypeRegistry.h" +#include "indent.h" +#include "dSearchPath.h" +#include "coordinateSystem.h" +#include "dconfig.h" +#include "config_dconfig.h" +#include "string_utils.h" #include #include @@ -939,6 +940,32 @@ dispatch_units(const string &opt, const string &arg, void *var) { return true; } +//////////////////////////////////////////////////////////////////// +// Function: ProgramBase::dispatch_image_type +// Access: Protected, Static +// Description: Standard dispatch function for an option that takes +// one parameter, which is to indicate an image file +// type, like rgb, bmp, jpg, etc. The data pointer is +// to a PNMFileType pointer. +//////////////////////////////////////////////////////////////////// +bool ProgramBase:: +dispatch_image_type(const string &opt, const string &arg, void *var) { + PNMFileType **ip = (PNMFileType **)var; + + PNMFileTypeRegistry *reg = PNMFileTypeRegistry::get_ptr(); + + (*ip) = reg->get_type_from_extension(arg); + + if ((*ip) == (PNMFileType *)NULL) { + nout << "Invalid image type for -" << opt << ": " << arg << "\n" + << "The following image types are known:\n"; + reg->write_types(nout, 2); + 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 c067222d54..e2b069ab69 100644 --- a/pandatool/src/progbase/programBase.h +++ b/pandatool/src/progbase/programBase.h @@ -95,6 +95,7 @@ protected: static bool dispatch_search_path(const string &opt, const string &arg, void *var); 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 handle_help_option(const string &opt, const string &arg, void *);