Browse Source

add -noabs to many egg tools

David Rose 21 years ago
parent
commit
b4280f10cf

+ 24 - 0
pandatool/src/converter/somethingToEggConverter.I

@@ -17,6 +17,30 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: SomethingToEggConverter::clear_error
+//       Access: Public
+//  Description: Resets the error flag to the no-error state.
+//               had_error() will return false until a new error is
+//               generated.
+////////////////////////////////////////////////////////////////////
+INLINE void SomethingToEggConverter::
+clear_error() {
+  _error = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SomethingToEggConverter::had_error
+//       Access: Public
+//  Description: Returns true if an error was detected during the
+//               conversion process (unless _allow_errors is true),
+//               false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool SomethingToEggConverter::
+had_error() const {
+  return !_allow_errors && (_error || _path_replace->had_error());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: SomethingToEggConverter::set_path_replace
 //       Access: Public

+ 1 - 3
pandatool/src/converter/somethingToEggConverter.cxx

@@ -144,9 +144,7 @@ handle_external_reference(EggGroupNode *egg_parent,
     if (!ext->convert_file(ref_filename)) {
       delete ext;
       nout << "Unable to read external reference: " << ref_filename << "\n";
-      if (!_allow_errors) {
-        _error = true;
-      }
+      _error = true;
       return false;
     }
 

+ 3 - 0
pandatool/src/converter/somethingToEggConverter.h

@@ -49,6 +49,9 @@ public:
 
   virtual SomethingToEggConverter *make_copy()=0;
 
+  INLINE void clear_error();
+  INLINE bool had_error() const;
+
   INLINE void set_path_replace(PathReplace *path_replace);
   INLINE PathReplace *get_path_replace();
   INLINE const PathReplace *get_path_replace() const;

+ 2 - 2
pandatool/src/dxfegg/dxfToEggConverter.cxx

@@ -91,14 +91,14 @@ get_extension() const {
 ////////////////////////////////////////////////////////////////////
 bool DXFToEggConverter::
 convert_file(const Filename &filename) {
-  _error = false;
+  clear_error();
 
   if (_egg_data->get_coordinate_system() == CS_default) {
     _egg_data->set_coordinate_system(CS_zup_right);
   }
 
   process(filename);
-  return !_error;
+  return !had_error();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 21 - 7
pandatool/src/egg-palettize/eggPalettize.cxx

@@ -657,6 +657,8 @@ run() {
     }
   }
 
+  pal->set_noabs(_noabs);
+
   if (_report_pi) {
     pal->report_pi();
     exit(0);
@@ -724,6 +726,8 @@ run() {
   }
 
   // And process the egg files named for addition.
+  bool all_eggs_valid = true;
+
   string egg_comment = get_exec_command();
   Eggs::const_iterator ei;
   for (ei = _eggs.begin(); ei != _eggs.end(); ++ei) {
@@ -733,10 +737,18 @@ run() {
     string name = source_filename.get_basename();
 
     EggFile *egg_file = pal->get_egg_file(name);
-    egg_file->from_command_line(egg_data, source_filename, dest_filename,
-                                egg_comment);
+    if (!egg_file->from_command_line(egg_data, source_filename, dest_filename,
+                                     egg_comment)) {
+      all_eggs_valid = false;
+
+    } else {
+      pal->add_command_line_egg(egg_file);
+    }
+  }
 
-    pal->add_command_line_egg(egg_file);
+  if (!all_eggs_valid) {
+    nout << "Errors reading egg file(s).\n";
+    exit(1);
   }
 
   if (_optimal) {
@@ -767,10 +779,12 @@ run() {
     }
   }
 
-  pal->generate_images(_redo_all);
-
-  if (!pal->write_eggs()) {
-    okflag = false;
+  if (okflag) {
+    pal->generate_images(_redo_all);
+    
+    if (!pal->write_eggs()) {
+      okflag = false;
+    }
   }
 
   if (!_nodb) {

+ 5 - 2
pandatool/src/eggbase/eggBase.cxx

@@ -39,13 +39,16 @@ EggBase() {
      &EggBase::dispatch_coordinate_system,
      &_got_coordinate_system, &_coordinate_system);
 
-  _coordinate_system = CS_yup_right;
-
   _normals_mode = NM_preserve;
   _normals_threshold = 0.0;
 
   _got_transform = false;
   _transform = LMatrix4d::ident_mat();
+
+  _got_coordinate_system = false;
+  _coordinate_system = CS_yup_right;
+
+  _noabs = false;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 0
pandatool/src/eggbase/eggBase.h

@@ -72,6 +72,8 @@ protected:
 
   bool _got_coordinate_system;
   CoordinateSystem _coordinate_system;
+
+  bool _noabs;
 };
 
 #endif

+ 14 - 0
pandatool/src/eggbase/eggMultiBase.cxx

@@ -35,6 +35,14 @@ EggMultiBase() {
      "Force complete loading: load up the egg file along with all of its "
      "external references.",
      &EggMultiBase::dispatch_none, &_force_complete);
+
+  add_option
+    ("noabs", "", 0,
+     "Don't allow any of the named egg files to have absolute pathnames.  "
+     "If any do, abort with an error.  This option is designed to help "
+     "detect errors when populating or building a standalone model tree, "
+     "which should be self-contained and include only relative pathnames.",
+     &EggReader::dispatch_none, &_noabs);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -124,6 +132,12 @@ read_egg(const Filename &filename) {
     return (EggData *)NULL;
   }
 
+  if (_noabs && data->original_had_absolute_pathnames()) {
+    nout << filename.get_basename()
+         << " includes absolute pathnames!\n";
+    return (EggData *)NULL;
+  }
+
   DSearchPath file_path;
   file_path.append_directory(filename.get_dirname());
 

+ 14 - 0
pandatool/src/eggbase/eggReader.cxx

@@ -49,6 +49,14 @@ EggReader() {
      "external references.",
      &EggReader::dispatch_none, &_force_complete);
 
+  add_option
+    ("noabs", "", 0,
+     "Don't allow the input egg file to have absolute pathnames.  "
+     "If it does, abort with an error.  This option is designed to help "
+     "detect errors when populating or building a standalone model tree, "
+     "which should be self-contained and include only relative pathnames.",
+     &EggReader::dispatch_none, &_noabs);
+
   _tex_type = (PNMFileType *)NULL;
   _delod = -1.0;
 }
@@ -174,6 +182,12 @@ handle_args(ProgramBase::Args &args) {
       exit(1);
     }
 
+    if (_noabs && file_data.original_had_absolute_pathnames()) {
+      nout << filename.get_basename()
+           << " includes absolute pathnames!\n";
+      exit(1);
+    }
+
     DSearchPath file_path;
     file_path.append_directory(filename.get_dirname());
 

+ 10 - 0
pandatool/src/eggbase/somethingToEgg.cxx

@@ -52,6 +52,14 @@ SomethingToEgg(const string &format_name,
      "Specify the coordinate system of the input " + _format_name +
      " file.  Normally, this can inferred from the file itself.");
 
+  add_option
+    ("noabs", "", 0,
+     "Don't allow the input " + _format_name + " file to have absolute pathnames.  "
+     "If it does, abort with an error.  This option is designed to help "
+     "detect errors when populating or building a standalone model tree, "
+     "which should be self-contained and include only relative pathnames.",
+     &SomethingToEgg::dispatch_none, &_noabs);
+
   add_option
     ("ignore", "", 0,
      "Ignore non-fatal errors and generate an egg file anyway.",
@@ -200,6 +208,8 @@ apply_units_scale(EggData &data) {
 ////////////////////////////////////////////////////////////////////
 void SomethingToEgg::
 apply_parameters(SomethingToEggConverter &converter) {
+  _path_replace->_noabs = _noabs;
+  _path_replace->_exists = true;
   converter.set_path_replace(_path_replace);
 
   converter.set_animation_convert(_animation_convert);

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

@@ -163,7 +163,7 @@ convert_flt(const FltHeader *flt_header) {
     _egg_data->set_coordinate_system(CS_zup_right);
   }
 
-  _error = false;
+  clear_error();
   _flt_header = flt_header;
 
   // Generate a default vertex pool.
@@ -188,7 +188,7 @@ convert_flt(const FltHeader *flt_header) {
 
   cleanup();
 
-  return !_error;
+  return !had_error();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -681,9 +681,7 @@ parse_comment(const string &comment, const string &name,
   if (p >= comment.length() || comment[p] != '{') {
     nout << "No opening brace in comment for "
          << name << "\n\n";
-    if (!_allow_errors) {
-      _error = true;
-    }
+    _error = true;
     return false;
   }
 
@@ -697,9 +695,7 @@ parse_comment(const string &comment, const string &name,
   if (q == p) {
     nout << "No closing brace in comment for "
          << name << "\n\n";
-    if (!_allow_errors) {
-      _error = true;
-    }
+    _error = true;
     return false;
   }
 
@@ -708,9 +704,7 @@ parse_comment(const string &comment, const string &name,
   if (!egg_node->parse_egg(egg_syntax)) {
     nout << "Syntax error in comment for "
          << name << "\n\n";
-    if (!_allow_errors) {
-      _error = true;
-    }
+    _error = true;
     return false;
   }
 

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

@@ -68,6 +68,17 @@ FltToEgg() :
 ////////////////////////////////////////////////////////////////////
 void FltToEgg::
 run() {
+  _data.set_coordinate_system(_coordinate_system);
+
+  FltToEggConverter converter;
+  converter.set_merge_externals(_merge_externals);
+  converter.set_egg_data(&_data, false);
+  converter._compose_transforms = _compose_transforms;
+  converter._allow_errors = _allow_errors;
+
+  apply_parameters(converter);
+
+
   PT(FltHeader) header = new FltHeader(_path_replace);
 
   nout << "Reading " << _input_filename << "\n";
@@ -79,15 +90,6 @@ run() {
 
   header->check_version();
 
-  _data.set_coordinate_system(_coordinate_system);
-
-  FltToEggConverter converter;
-  converter.set_merge_externals(_merge_externals);
-  converter.set_egg_data(&_data, false);
-  converter._compose_transforms = _compose_transforms;
-  converter._allow_errors = _allow_errors;
-
-  apply_parameters(converter);
 
   if (!converter.convert_flt(header)) {
     nout << "Errors in conversion.\n";

+ 1 - 1
pandatool/src/lwoegg/lwoToEggConverter.cxx

@@ -167,7 +167,7 @@ convert_lwo(const LwoHeader *lwo_header) {
   _egg_data->remove_unused_vertices();
   cleanup();
 
-  return !_error;
+  return !had_error();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 5 - 0
pandatool/src/mayaegg/mayaToEggConverter.cxx

@@ -272,6 +272,7 @@ get_input_units() {
 bool MayaToEggConverter::
 convert_maya() {
   clear();
+  clear_error();
 
   if (!open_api()) {
     mayaegg_cat.error()
@@ -391,6 +392,10 @@ convert_maya() {
     reparent_decals(&get_egg_data());
   }
 
+  if (had_error()) {
+    all_ok = false;
+  }
+
   if (all_ok) {
     mayaegg_cat.info()
       << "Converted, no errors.\n";

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

@@ -99,6 +99,12 @@ MayaToEgg() :
      "Increase verbosity.  More v's means more verbose.",
      &MayaToEgg::dispatch_count, NULL, &_verbose);
 
+  // Unfortunately, the Maya API doesn't allow us to differentiate
+  // between relative and absolute pathnames--everything comes out as
+  // an absolute pathname, even if it is stored in the Maya file as a
+  // relative path.  So we can't support -noabs.
+  remove_option("noabs");
+
   _verbose = 0;
   _polygon_tolerance = 0.01;
   _transform_type = MayaToEggConverter::TT_model;
@@ -159,7 +165,6 @@ run() {
   _data.set_coordinate_system(_coordinate_system);
 
   converter.set_egg_data(&_data, false);
-  apply_parameters(converter);
 
   if (!converter.convert_file(_input_filename)) {
     nout << "Errors in conversion.\n";

+ 24 - 5
pandatool/src/palettizer/eggFile.cxx

@@ -60,9 +60,10 @@ EggFile() {
 //     Function: EggFile::from_command_line
 //       Access: Public
 //  Description: Accepts the information about the egg file as
-//               supplied from the command line.
+//               supplied from the command line.  Returns true if the
+//               egg file is valid, false otherwise.
 ////////////////////////////////////////////////////////////////////
-void EggFile::
+bool EggFile::
 from_command_line(EggData *data,
                   const Filename &source_filename,
                   const Filename &dest_filename,
@@ -90,8 +91,21 @@ from_command_line(EggData *data,
   // file inherits the default group that was in effect when it was
   // specified on the command line.
   _default_group = pal->get_default_group();
+
+  return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggFile::get_source_filename
+//       Access: Public
+//  Description: Returns the filename this egg file was read from.
+////////////////////////////////////////////////////////////////////
+const Filename &EggFile::
+get_source_filename() const {
+  return _source_filename;
+}
+
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggFile::scan_textures
 //       Access: Public
@@ -536,7 +550,7 @@ remove_egg() {
 //               file.
 ////////////////////////////////////////////////////////////////////
 bool EggFile::
-read_egg() {
+read_egg(bool noabs) {
   nassertr(_data == (EggData *)NULL, false);
   nassertr(!_source_filename.empty(), false);
 
@@ -554,10 +568,15 @@ read_egg() {
     return false;
   }
 
+  if (noabs && data->original_had_absolute_pathnames()) {
+    nout << _source_filename.get_basename()
+         << " references textures using absolute pathnames!\n";
+    return false;
+  }
 
   // Extract the set of textures referenced by this egg file.
   EggTextureCollection tc;
-  tc.find_used_textures(_data);
+  tc.find_used_textures(data);
   
   // Make sure each tref name is unique within a given file.
   tc.uniquify_trefs();
@@ -850,7 +869,7 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
 ////////////////////////////////////////////////////////////////////
 TypedWritable* EggFile::
 make_EggFile(const FactoryParams &params) {
-  EggFile *me = new EggFile;
+  EggFile *me = new EggFile();
   DatagramIterator scan;
   BamReader *manager;
 

+ 5 - 2
pandatool/src/palettizer/eggFile.h

@@ -44,11 +44,13 @@ class EggFile : public TypedWritable, public Namable {
 public:
   EggFile();
 
-  void from_command_line(EggData *data,
+  bool from_command_line(EggData *data,
                          const Filename &source_filename,
                          const Filename &dest_filename,
                          const string &egg_comment);
 
+  const Filename &get_source_filename() const;
+
   void scan_textures();
   void get_textures(pset<TextureImage *> &result) const;
 
@@ -74,7 +76,7 @@ public:
 
   void update_egg();
   void remove_egg();
-  bool read_egg();
+  bool read_egg(bool noabs);
   void release_egg_data();
   bool write_egg();
 
@@ -95,6 +97,7 @@ private:
   typedef pvector<TextureReference *> Textures;
   Textures _textures;
 
+  bool _noabs;
   bool _first_txa_match;
   PaletteGroups _explicitly_assigned_groups;
   PaletteGroup *_default_group;

+ 2 - 2
pandatool/src/palettizer/paletteImage.cxx

@@ -738,12 +738,12 @@ get_image() {
 
   if (!_new_image) {
     if (pal->_shadow_color_type != (PNMFileType *)NULL) {
-      if (_shadow_image.read(_image)) {
+      if (_shadow_image.get_filename().exists() && _shadow_image.read(_image)) {
         _got_image = true;
         return;
       }
     } else {
-      if (read(_image)) {
+      if (get_filename().exists() && read(_image)) {
         _got_image = true;
         return;
       }

+ 55 - 5
pandatool/src/palettizer/palettizer.cxx

@@ -102,6 +102,7 @@ public:
 Palettizer::
 Palettizer() {
   _is_valid = true;
+  _noabs = false;
 
   _generated_image_pattern = "%g_palette_%p_%i";
   _map_dirname = "%g";
@@ -125,6 +126,36 @@ Palettizer() {
   _remap_char_uv = RU_poly;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Palettizer::get_noabs
+//       Access: Public
+//  Description: Returns the current setting of the noabs flag.  See
+//               set_noabs().
+////////////////////////////////////////////////////////////////////
+bool Palettizer::
+get_noabs() const {
+  return _noabs;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Palettizer::set_noabs
+//       Access: Public
+//  Description: Changes the current setting of the noabs flag.
+//
+//               If this flag is true, then it is an error to process
+//               an egg file that contains absolute pathname
+//               references.  This flag is intended to help detect egg
+//               files that are incorrectly built within a model tree
+//               (which should use entirely relative pathnames).
+//
+//               This flag must be set before any egg files are
+//               processed.
+////////////////////////////////////////////////////////////////////
+void Palettizer::
+set_noabs(bool noabs) {
+  _noabs = noabs;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Palettizer::is_valid
 //       Access: Public
@@ -660,7 +691,7 @@ read_stale_eggs(bool redo_all) {
     EggFile *egg_file = (*ei).second;
     if (!egg_file->has_data() &&
         (egg_file->is_stale() || redo_all)) {
-      if (!egg_file->read_egg()) {
+      if (!egg_file->read_egg(_noabs)) {
         invalid_eggs.push_back(ei);
 
       } else {
@@ -676,9 +707,28 @@ read_stale_eggs(bool redo_all) {
   for (ii = invalid_eggs.begin(); ii != invalid_eggs.end(); ++ii) {
     EggFiles::iterator ei = (*ii);
     EggFile *egg_file = (*ei).second;
-    nout << "Removing " << (*ei).first << "\n";
-    egg_file->remove_egg();
-    _egg_files.erase(ei);
+    if (egg_file->get_source_filename().exists()) {
+      // If there is an invalid egg file, remove it; hopefully it will
+      // get rebuilt properly next time.
+      nout << "Removing invalid egg file: " 
+           << FilenameUnifier::make_user_filename(egg_file->get_source_filename())
+           << "\n";
+
+      egg_file->get_source_filename().unlink();
+      okflag = false;
+
+    } else {
+      // If the egg file is simply missing, quietly remove any record
+      // of it from the database.
+      egg_file->remove_egg();
+      _egg_files.erase(ei);
+    }
+  }
+
+  if (!okflag) {
+    nout << "\n"
+         << "Some errors in egg files encountered.\n"
+         << "Re-run make install or make opt-pal to try to regenerate these.\n\n";
   }
 
   return okflag;
@@ -701,7 +751,7 @@ write_eggs() {
     if (egg_file->had_data()) {
       if (!egg_file->has_data()) {
         // Re-read the egg file.
-        bool read_ok = egg_file->read_egg();
+        bool read_ok = egg_file->read_egg(_noabs);
         if (!read_ok) {
           nout << "Error!  Unable to re-read egg file.\n";
           okflag = false;

+ 8 - 4
pandatool/src/palettizer/palettizer.h

@@ -48,6 +48,9 @@ class Palettizer : public TypedWritable {
 public:
   Palettizer();
 
+  bool get_noabs() const;
+  void set_noabs(bool noabs);
+
   bool is_valid() const;
   void report_pi() const;
   void report_statistics() const;
@@ -91,15 +94,16 @@ public:
 
   bool _is_valid;
 
-  // These values are not stored in the bam file, but are specific to
-  // each session.
+  // These values are not stored in the textures.boo file, but are
+  // specific to each session.
   TxaFile _txa_file;
   string _default_groupname;
   string _default_groupdir;
+  bool _noabs;
 
   // The following parameter values specifically relate to textures
-  // and palettes.  These values are stored in the bam file for future
-  // reference.
+  // and palettes.  These values are stored in the textures.boo file
+  // for future reference.
   string _generated_image_pattern;
   string _map_dirname;
   Filename _shadow_dirname;

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

@@ -6,6 +6,7 @@
   
   #define SOURCES \
     animationConvert.cxx animationConvert.h \
+    config_pandatoolbase.cxx config_pandatoolbase.h \
     distanceUnit.cxx distanceUnit.h \
     pandatoolbase.cxx pandatoolbase.h pandatoolsymbols.h \
     pathReplace.cxx pathReplace.I pathReplace.h \
@@ -13,6 +14,7 @@
 
   #define INSTALL_HEADERS \
     animationConvert.h \
+    config_pandatoolbase.h \
     distanceUnit.h \
     pandatoolbase.h pandatoolsymbols.h \
     pathReplace.I pathReplace.h \

+ 39 - 0
pandatool/src/pandatoolbase/config_pandatoolbase.cxx

@@ -0,0 +1,39 @@
+// Filename: config_pandatoolbase.cxx
+// Created by:  drose (29Nov04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "config_pandatoolbase.h"
+
+NotifyCategoryDef(pandatoolbase, "");
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libpandatoolbase
+//  Description: Initializes the library.  This must be called at
+//               least once before any of the functions or classes in
+//               this library can be used.  Normally it will be
+//               called by the static initializers and need not be
+//               called explicitly, but special cases exist.
+////////////////////////////////////////////////////////////////////
+void
+init_libpandatoolbase() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  initialized = true;
+}
+

+ 30 - 0
pandatool/src/pandatoolbase/config_pandatoolbase.h

@@ -0,0 +1,30 @@
+// Filename: config_pandatoolbase.h
+// Created by:  drose (29Nov04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIG_PANDATOOLBASE_H
+#define CONFIG_PANDATOOLBASE_H
+
+#include "pandatoolbase.h"
+
+#include "notifyCategoryProxy.h"
+
+NotifyCategoryDeclNoExport(pandatoolbase);
+
+extern void init_libpandatoolbase();
+
+#endif

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

@@ -17,6 +17,29 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::clear_error
+//       Access: Public
+//  Description: Resets the error flag to the no-error state.
+//               had_error() will return false until a new error is
+//               generated.
+////////////////////////////////////////////////////////////////////
+INLINE void PathReplace::
+clear_error() {
+  _error_flag = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PathReplace::had_error
+//       Access: Public
+//  Description: Returns true if an error was detected since the last
+//               call to clear_error(), false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool PathReplace::
+had_error() const {
+  return _error_flag;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PathReplace::clear
 //       Access: Public
@@ -24,6 +47,7 @@
 ////////////////////////////////////////////////////////////////////
 INLINE void PathReplace::
 clear() {
+  clear_error();
   _entries.clear();
 }
 

+ 45 - 1
pandatool/src/pandatoolbase/pathReplace.cxx

@@ -18,6 +18,7 @@
 
 #include "pathReplace.h"
 #include "config_util.h"
+#include "config_pandatoolbase.h"
 #include "indent.h"
 
 ////////////////////////////////////////////////////////////////////
@@ -28,6 +29,9 @@
 PathReplace::
 PathReplace() {
   _path_store = PS_keep;
+  _noabs = false;
+  _exists = false;
+  _error_flag = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -96,9 +100,31 @@ match_path(const Filename &orig_filename,
   // The file couldn't be found anywhere.  Did we at least get any
   // prefix match?
   if (got_match) {
+    if (_exists) {
+      _error_flag = true;
+      pandatoolbase_cat.error()
+        << "File does not exist: " << match << "\n";
+    } else if (pandatoolbase_cat.is_debug()) {
+      pandatoolbase_cat.debug()
+        << "File does not exist: " << match << "\n";
+    }
+
     return match;
   }
 
+  if (!orig_filename.is_local()) {
+    // Ok, we didn't match any specified prefixes.  If the file is an
+    // absolute pathname and we have _noabs set, that's an error.
+    if (_noabs) {
+      _error_flag = true;
+      pandatoolbase_cat.error()
+        << "Absolute pathname: " << orig_filename << "\n";
+    } else if (pandatoolbase_cat.is_debug()) {
+      pandatoolbase_cat.debug()
+        << "Absolute pathname: " << orig_filename << "\n";
+    }
+  }
+
   // Well, we still haven't found it; look it up on the search path as
   // is.
   if (_path_store != PS_keep) {
@@ -111,7 +137,16 @@ match_path(const Filename &orig_filename,
     }
   }
 
-  // Nope, couldn't find anything.  Just return the original filename.
+  // Nope, couldn't find anything.  This is an error, but just return
+  // the original filename.
+  if (_exists) {
+    _error_flag = true;
+    pandatoolbase_cat.error()
+      << "File does not exist: " << orig_filename << "\n";
+  } else if (pandatoolbase_cat.is_debug()) {
+    pandatoolbase_cat.debug()
+      << "File does not exist: " << orig_filename << "\n";
+  }
   return orig_filename;
 }
 
@@ -125,6 +160,10 @@ match_path(const Filename &orig_filename,
 ////////////////////////////////////////////////////////////////////
 Filename PathReplace::
 store_path(const Filename &orig_filename) {
+  if (orig_filename.empty()) {
+    return orig_filename;
+  }
+
   if (_path_directory.is_local()) {
     _path_directory.make_absolute();
   }
@@ -190,6 +229,11 @@ write(ostream &out, int indent_level) const {
   default:
     break;
   }
+
+  if (_noabs) {
+    indent(out, indent_level)
+      << "-noabs\n";
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -45,6 +45,9 @@ public:
   PathReplace();
   ~PathReplace();
 
+  INLINE void clear_error();
+  INLINE bool had_error() const;
+
   INLINE void clear();
   INLINE void add_pattern(const string &orig_prefix, const string &replacement_prefix);
 
@@ -71,6 +74,16 @@ public:
   PathStore _path_store;
   Filename _path_directory;
 
+  // If this is this true, then the error flag is set (see had_error()
+  // and clear_error()) if any Filename passed to match_path() or
+  // convert_path(), and unmatched by one of the prefixes, happens to
+  // be an absolute pathname.
+  bool _noabs;
+
+  // If this is true, then the error flag is set if any Filename
+  // passed to match_path() or convert_path() cannot be found.
+  bool _exists;
+
 private:
   class Component {
   public:
@@ -100,6 +113,8 @@ private:
 
   typedef pvector<Entry> Entries;
   Entries _entries;
+
+  bool _error_flag;
 };
 
 #include "pathReplace.I"

+ 3 - 1
pandatool/src/vrmlegg/vrmlToEggConverter.cxx

@@ -98,6 +98,8 @@ get_extension() const {
 ////////////////////////////////////////////////////////////////////
 bool VRMLToEggConverter::
 convert_file(const Filename &filename) {
+  clear_error();
+
   VrmlScene *scene = parse_vrml(filename);
   if (scene == (VrmlScene *)NULL) {
     return false;
@@ -122,7 +124,7 @@ convert_file(const Filename &filename) {
     vrml_node((*csi)._node, &get_egg_data(), LMatrix4d::ident_mat());
   }
 
-  return true;
+  return !had_error();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 1
pandatool/src/xfileegg/xFileToEggConverter.cxx

@@ -116,6 +116,7 @@ get_extension() const {
 bool XFileToEggConverter::
 convert_file(const Filename &filename) {
   close();
+  clear_error();
 
   if (!_x_file->read(filename)) {
     nout << "Unable to open X file: " << filename << "\n";
@@ -148,7 +149,7 @@ convert_file(const Filename &filename) {
     return false;
   }
 
-  return true;
+  return !had_error();
 }
 
 ////////////////////////////////////////////////////////////////////