Browse Source

add mayacopy

David Rose 23 years ago
parent
commit
06181a343d

+ 3 - 1
pandatool/src/cvscopy/cvsCopy.cxx

@@ -317,7 +317,7 @@ copy_binary_file(Filename source, Filename dest) {
     c = in.get();
   }
 
-  if (in.fail()) {
+  if (!in.eof() && in.fail()) {
     nout << "Error reading " << source << "\n";
     return false;
   }
@@ -342,6 +342,8 @@ cvs_add(const Filename &filename) {
     return true;
   }
 
+  Filename canon = filename;
+
   if (!CVSSourceTree::temp_chdir(filename.get_dirname())) {
     nout << "Invalid directory: " << filename.get_dirname() << "\n";
     return false;

+ 2 - 1
pandatool/src/cvscopy/cvsSourceDirectory.cxx

@@ -186,7 +186,7 @@ find_relpath(const string &relpath) {
     return (CVSSourceDirectory *)NULL;
   }
 
-  // Check for a child named "first".
+  // Check for a child with the name indicated by first.
   Children::const_iterator ci;
   for (ci = _children.begin(); ci != _children.end(); ++ci) {
     if ((*ci)->get_dirname() == first) {
@@ -247,6 +247,7 @@ scan(const Filename &directory, const string &key_filename) {
     // Is this possibly a subdirectory name?
     Filename next_path(directory, filename);
     Filename key(next_path, key_filename);
+
     if (key.exists()) {
       CVSSourceDirectory *subdir =
         new CVSSourceDirectory(_tree, this, filename);

+ 2 - 2
pandatool/src/cvscopy/cvsSourceDirectory.h

@@ -19,8 +19,8 @@
 #ifndef CVSSOURCEDIRECTORY_H
 #define CVSSOURCEDIRECTORY_H
 
-#include <pandatoolbase.h>
-#include <filename.h>
+#include "pandatoolbase.h"
+#include "filename.h"
 
 #include "pvector.h"
 

+ 34 - 40
pandatool/src/cvscopy/cvsSourceTree.cxx

@@ -19,21 +19,21 @@
 #include "cvsSourceTree.h"
 #include "cvsSourceDirectory.h"
 
-#include <filename.h>
-#include <executionEnvironment.h>
-#include <notify.h>
+#include "filename.h"
+#include "executionEnvironment.h"
+#include "notify.h"
 
 #include <algorithm>
 #include <ctype.h>
 #include <stdio.h> // for perror
 #include <errno.h>
 
-#if defined(WIN32_VC)
-#include <direct.h>
+#ifdef WIN32_VC
+#include <direct.h>  // for chdir
 #endif
 
 bool CVSSourceTree::_got_start_fullpath = false;
-string CVSSourceTree::_start_fullpath;
+Filename CVSSourceTree::_start_fullpath;
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CVSSourceTree::Constructor
@@ -66,7 +66,7 @@ CVSSourceTree::
 //               than once.
 ////////////////////////////////////////////////////////////////////
 void CVSSourceTree::
-set_root(const string &root_path) {
+set_root(const Filename &root_path) {
   nassertv(_path.empty());
   _path = root_path;
 }
@@ -80,7 +80,7 @@ set_root(const string &root_path) {
 //               is an error.
 ////////////////////////////////////////////////////////////////////
 bool CVSSourceTree::
-scan(const string &key_filename) {
+scan(const Filename &key_filename) {
   nassertr(_root == (CVSSourceDirectory *)NULL, false);
   Filename root_fullpath = get_root_fullpath();
   _root = new CVSSourceDirectory(this, NULL, root_fullpath.get_basename());
@@ -105,7 +105,7 @@ get_root() const {
 //               the source tree.
 ////////////////////////////////////////////////////////////////////
 CVSSourceDirectory *CVSSourceTree::
-find_directory(const string &path) {
+find_directory(const Filename &path) {
   string root_fullpath = get_root_fullpath();
   string fullpath = get_actual_fullpath(path);
 
@@ -118,7 +118,7 @@ find_directory(const string &path) {
   }
 
   // The relative name is the part of fullpath not in root_fullpath.
-  string relpath = fullpath.substr(root_fullpath.length());
+  Filename relpath = fullpath.substr(root_fullpath.length());
 
   return _root->find_relpath(relpath);
 }
@@ -141,8 +141,8 @@ find_relpath(const string &relpath) {
   // Check for the root dirname at the front of the path, and remove
   // it if it's there.
   size_t slash = relpath.find('/');
-  string first = relpath.substr(0, slash);
-  string rest;
+  Filename first = relpath.substr(0, slash);
+  Filename rest;
   if (slash != string::npos) {
     rest = relpath.substr(slash + 1);
   }
@@ -177,7 +177,7 @@ find_dirname(const string &dirname) {
 //               directory, or uses suggested_dir.
 ////////////////////////////////////////////////////////////////////
 CVSSourceDirectory *CVSSourceTree::
-choose_directory(const string &filename, CVSSourceDirectory *suggested_dir,
+choose_directory(const Filename &filename, CVSSourceDirectory *suggested_dir,
                  bool force, bool interactive) {
   static Directories empty_dirs;
 
@@ -202,9 +202,9 @@ choose_directory(const string &filename, CVSSourceDirectory *suggested_dir,
 //  Description: Returns the full path from the root to the top of
 //               the source hierarchy.
 ////////////////////////////////////////////////////////////////////
-string CVSSourceTree::
+Filename CVSSourceTree::
 get_root_fullpath() {
-  nassertr(!_path.empty(), string());
+  nassertr(!_path.empty(), Filename());
   if (!_got_root_fullpath) {
     _root_fullpath = get_actual_fullpath(_path);
     _got_root_fullpath = true;
@@ -218,9 +218,9 @@ get_root_fullpath() {
 //  Description: Returns the local directory name of the root of the
 //               tree.
 ////////////////////////////////////////////////////////////////////
-string CVSSourceTree::
+Filename CVSSourceTree::
 get_root_dirname() const {
-  nassertr(_root != (CVSSourceDirectory *)NULL, string());
+  nassertr(_root != (CVSSourceDirectory *)NULL, Filename());
   return _root->get_dirname();
 }
 
@@ -232,7 +232,7 @@ get_root_dirname() const {
 //               should not be called directly by the user.
 ////////////////////////////////////////////////////////////////////
 void CVSSourceTree::
-add_file(const string &filename, CVSSourceDirectory *dir) {
+add_file(const Filename &filename, CVSSourceDirectory *dir) {
   _filenames[filename].push_back(dir);
 }
 
@@ -245,12 +245,13 @@ add_file(const string &filename, CVSSourceDirectory *dir) {
 //               original directory later.
 ////////////////////////////////////////////////////////////////////
 bool CVSSourceTree::
-temp_chdir(const string &path) {
+temp_chdir(const Filename &path) {
   // We have to call this first to guarantee that we have already
   // determined our starting directory.
   get_start_fullpath();
 
-  if (chdir(path.c_str()) < 0) {
+  string os_path = path.to_os_specific();
+  if (chdir(os_path.c_str()) < 0) {
     return false;
   }
   return true;
@@ -264,11 +265,12 @@ temp_chdir(const string &path) {
 ////////////////////////////////////////////////////////////////////
 void CVSSourceTree::
 restore_cwd() {
-  string start_fullpath = get_start_fullpath();
+  Filename start_fullpath = get_start_fullpath();
+  string os_path = start_fullpath.to_os_specific();
 
-  if (chdir(start_fullpath.c_str()) < 0) {
+  if (chdir(os_path.c_str()) < 0) {
     // Hey!  We can't get back to the directory we started from!
-    perror(start_fullpath.c_str());
+    perror(os_path.c_str());
     nout << "Can't continue, aborting.\n";
     exit(1);
   }
@@ -498,21 +500,13 @@ prompt(const string &message) {
 //     Function: CVSSourceTree::get_actual_fullpath
 //       Access: Private, Static
 //  Description: Determines the actual full path from the root to the
-//               named directory.  It does this essentially by cd'ing
-//               to the directory and doing pwd, then cd'ing back.
-//               Returns the empty string if the directory is invalid
-//               or cannot be cd'ed into.
+//               named directory.
 ////////////////////////////////////////////////////////////////////
-string CVSSourceTree::
-get_actual_fullpath(const string &path) {
-  if (!temp_chdir(path)) {
-    return string();
-  }
-
-  string cwd = ExecutionEnvironment::get_cwd();
-  restore_cwd();
-
-  return cwd;
+Filename CVSSourceTree::
+get_actual_fullpath(const Filename &path) {
+  Filename canon = path;
+  canon.make_canonical();
+  return canon;
 }
 
 
@@ -522,11 +516,11 @@ get_actual_fullpath(const string &path) {
 //  Description: Returns the full path from the root to the directory
 //               in which the user started the program.
 ////////////////////////////////////////////////////////////////////
-string CVSSourceTree::
+Filename CVSSourceTree::
 get_start_fullpath() {
   if (!_got_start_fullpath) {
-    _start_fullpath = ExecutionEnvironment::get_cwd();
-    _got_start_fullpath = true;
+    Filename cwd = ExecutionEnvironment::get_cwd();
+    _start_fullpath = cwd.to_os_specific();
   }
   return _start_fullpath;
 }

+ 16 - 15
pandatool/src/cvscopy/cvsSourceTree.h

@@ -19,10 +19,11 @@
 #ifndef CVSSOURCETREE_H
 #define CVSSOURCETREE_H
 
-#include <pandatoolbase.h>
+#include "pandatoolbase.h"
 
 #include "pvector.h"
 #include "pmap.h"
+#include "filename.h"
 
 class CVSSourceDirectory;
 
@@ -36,26 +37,26 @@ public:
   CVSSourceTree();
   ~CVSSourceTree();
 
-  void set_root(const string &root_path);
-  bool scan(const string &key_filename);
+  void set_root(const Filename &root_path);
+  bool scan(const Filename &key_filename);
 
   CVSSourceDirectory *get_root() const;
-  CVSSourceDirectory *find_directory(const string &path);
+  CVSSourceDirectory *find_directory(const Filename &path);
   CVSSourceDirectory *find_relpath(const string &relpath);
   CVSSourceDirectory *find_dirname(const string &dirname);
 
-  CVSSourceDirectory *choose_directory(const string &filename,
+  CVSSourceDirectory *choose_directory(const Filename &filename,
                                        CVSSourceDirectory *suggested_dir,
                                        bool force, bool interactive);
 
-  string get_root_fullpath();
-  string get_root_dirname() const;
+  Filename get_root_fullpath();
+  Filename get_root_dirname() const;
 
-  static bool temp_chdir(const string &path);
+  static bool temp_chdir(const Filename &path);
   static void restore_cwd();
 
 public:
-  void add_file(const string &filename, CVSSourceDirectory *dir);
+  void add_file(const Filename &filename, CVSSourceDirectory *dir);
 
 private:
   typedef pvector<CVSSourceDirectory *> Directories;
@@ -74,20 +75,20 @@ private:
 
   string prompt(const string &message);
 
-  static string get_actual_fullpath(const string &path);
-  static string get_start_fullpath();
+  static Filename get_actual_fullpath(const Filename &path);
+  static Filename get_start_fullpath();
 
 private:
-  string _path;
+  Filename _path;
   CVSSourceDirectory *_root;
 
-  typedef pmap<string, Directories> Filenames;
+  typedef pmap<Filename, Directories> Filenames;
   Filenames _filenames;
 
   static bool _got_start_fullpath;
-  static string _start_fullpath;
+  static Filename _start_fullpath;
   bool _got_root_fullpath;
-  string _root_fullpath;
+  Filename _root_fullpath;
 };
 
 #endif

+ 2 - 4
pandatool/src/maya/mayaApi.cxx

@@ -161,7 +161,7 @@ read(const Filename &filename) {
 
   MStatus stat = MFileIO::open(os_filename.c_str());
   if (!stat) {
-    stat.perror(filename.c_str());
+    stat.perror(os_filename.c_str());
     return false;
   }
   return true;
@@ -175,8 +175,6 @@ read(const Filename &filename) {
 ////////////////////////////////////////////////////////////////////
 bool MayaApi::
 write(const Filename &filename) {
-  MFileIO::newFile(true);
-
   maya_cat.info() << "Writing " << filename << "\n";
   string os_filename = filename.to_os_specific();
 #ifdef WIN32
@@ -191,7 +189,7 @@ write(const Filename &filename) {
 
   MStatus stat = MFileIO::saveAs(os_filename.c_str(), type, true);
   if (!stat) {
-    stat.perror(filename.c_str());
+    stat.perror(os_filename.c_str());
     return false;
   }
   return true;

+ 42 - 0
pandatool/src/maya/mayaShader.cxx

@@ -57,6 +57,8 @@ MayaShader(MObject engine) {
   _offset.set(0.0, 0.0);
   _rotate_uv = 0.0;
 
+  _color_object = (MObject *)NULL;
+
   MFnDependencyNode engine_fn(engine);
 
   _name = engine_fn.name().asChar();
@@ -79,6 +81,18 @@ MayaShader(MObject engine) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: MayaShader::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+MayaShader::
+~MayaShader() {
+  if (_color_object != (MObject *)NULL) {
+    delete _color_object;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: MayaShader::compute_texture_matrix
 //       Access: Public
@@ -126,6 +140,32 @@ output(ostream &out) const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: MayaShader::reset_maya_texture
+//       Access: Public
+//  Description: Changes the texture filename stored in the Maya file
+//               for this particular shader.
+////////////////////////////////////////////////////////////////////
+bool MayaShader::
+reset_maya_texture(const Filename &texture) {
+  if (_color_object != (MObject *)NULL) {
+    _has_texture = set_string_attribute(*_color_object, "fileTextureName", 
+                                        texture);
+    _texture = texture;
+
+    if (!_has_texture) {
+      maya_cat.error()
+        << "Unable to reset texture filename.\n";
+    }
+
+    return _has_texture;
+  }
+
+  maya_cat.error()
+    << "Attempt to reset texture on Maya object that has no color set.\n";
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: MayaShader::read_surface_shader
 //       Access: Public
@@ -185,6 +225,8 @@ read_surface_shader(MObject shader) {
 ////////////////////////////////////////////////////////////////////
 void MayaShader::
 read_surface_color(MObject color) {
+  _color_object = new MObject(color);
+
   if (color.hasFn(MFn::kFileTexture)) {
     string filename;
     _has_texture = get_string_attribute(color, "fileTextureName", filename);

+ 4 - 0
pandatool/src/maya/mayaShader.h

@@ -37,10 +37,12 @@ class MObject;
 class MayaShader {
 public:
   MayaShader(MObject engine);
+  ~MayaShader();
 
   LMatrix3d compute_texture_matrix() const;
 
   void output(ostream &out) const;
+  bool reset_maya_texture(const Filename &texture);
 
   string _name;
 
@@ -65,6 +67,8 @@ public:
   double _rotate_uv;
 
 private:
+  MObject *_color_object;
+
   bool read_surface_shader(MObject shader);
   void read_surface_color(MObject color);
 };

+ 28 - 3
pandatool/src/maya/mayaShaders.cxx

@@ -125,9 +125,33 @@ find_shader_for_shading_engine(MObject engine) {
 
   // Record this for the future.
   _shaders.insert(Shaders::value_type(engine_name, shader));
+  _shaders_in_order.push_back(shader);
   return shader;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: MayaShaders::get_num_shaders
+//       Access: Public
+//  Description: Returns the number of unique MayaShaders that have
+//               been discovered so far.
+////////////////////////////////////////////////////////////////////
+int MayaShaders::
+get_num_shaders() const {
+  return _shaders_in_order.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaShaders::get_shader
+//       Access: Public
+//  Description: Returns the nth MayaShader that has been discovered
+//               so far.
+////////////////////////////////////////////////////////////////////
+MayaShader *MayaShaders::
+get_shader(int n) const {
+  nassertr(n >= 0 && n < (int)_shaders_in_order.size(), NULL);
+  return _shaders_in_order[n];
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: MayaShaders::clear
 //       Access: Public
@@ -136,10 +160,11 @@ find_shader_for_shading_engine(MObject engine) {
 ////////////////////////////////////////////////////////////////////
 void MayaShaders::
 clear() {
-  Shaders::iterator si;
-  for (si = _shaders.begin(); si != _shaders.end(); ++si) {
-    delete (*si).second;
+  ShadersInOrder::iterator si;
+  for (si = _shaders_in_order.begin(); si != _shaders_in_order.end(); ++si) {
+    delete (*si);
   }
 
   _shaders.clear();
+  _shaders_in_order.clear();
 }

+ 6 - 0
pandatool/src/maya/mayaShaders.h

@@ -22,6 +22,7 @@
 #include "pandatoolbase.h"
 
 #include "pmap.h"
+#include "pvector.h"
 
 class MayaShader;
 class MObject;
@@ -38,11 +39,16 @@ public:
   MayaShader *find_shader_for_node(MObject node);
   MayaShader *find_shader_for_shading_engine(MObject engine);
 
+  int get_num_shaders() const;
+  MayaShader *get_shader(int n) const;
+
   void clear();
 
 private:
   typedef pmap<string, MayaShader *> Shaders;
   Shaders _shaders;
+  typedef pvector<MayaShader *> ShadersInOrder;
+  ShadersInOrder _shaders_in_order;
 };
 
 #endif

+ 22 - 22
pandatool/src/maya/maya_funcs.T

@@ -27,32 +27,32 @@ template<class ValueType>
 bool
 get_maya_attribute(MObject &node, const string &attribute_name,
                    ValueType &value) {
-  MStatus status;
-  MFnDependencyNode node_fn(node, &status);
-  if (!status) {
-    maya_cat.error()
-      << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
-    return false;
-  }
+  bool status = false;
 
-  MObject attr = node_fn.attribute(attribute_name.c_str(), &status);
-  if (!status) {
-    maya_cat.error()
-      << "Object " << node_fn.name() << " does not support attribute "
-      << attribute_name << "\n";
-    return false;
+  MPlug plug;
+  if (get_maya_plug(node, attribute_name, plug)) {
+    status = plug.getValue(value);
   }
 
-  MFnAttribute attr_fn(attr, &status);
-  if (!status) {
-    maya_cat.error()
-      << "Attribute " << attribute_name << " on " << node_fn.name()
-      << " is a " << attr.apiTypeStr() << ", not an Attribute.\n";
-    return false;
-  }
+  return status;
+}
 
-  MPlug plug(node, attr);
-  status = plug.getValue(value);
+////////////////////////////////////////////////////////////////////
+//     Function: set_maya_attribute
+//  Description: A generic function to set an attribute of some
+//               type on an MObject.  This is used to implement
+//               set_bool_attribute(), etc.
+////////////////////////////////////////////////////////////////////
+template<class ValueType>
+bool
+set_maya_attribute(MObject &node, const string &attribute_name,
+                   ValueType &value) {
+  bool status = false;
+
+  MPlug plug;
+  if (get_maya_plug(node, attribute_name, plug)) {
+    status = plug.setValue(value);
+  }
 
   return status;
 }

+ 80 - 0
pandatool/src/maya/maya_funcs.cxx

@@ -27,6 +27,40 @@
 #include <maya/MFnNumericData.h>
 #include "post_maya_include.h"
 
+////////////////////////////////////////////////////////////////////
+//     Function: get_maya_plug
+//  Description: Gets the named MPlug associated, if any.
+////////////////////////////////////////////////////////////////////
+bool
+get_maya_plug(MObject &node, const string &attribute_name, MPlug &plug) {
+  MStatus status;
+  MFnDependencyNode node_fn(node, &status);
+  if (!status) {
+    maya_cat.error()
+      << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
+    return false;
+  }
+
+  MObject attr = node_fn.attribute(attribute_name.c_str(), &status);
+  if (!status) {
+    maya_cat.error()
+      << "Object " << node_fn.name() << " does not support attribute "
+      << attribute_name << "\n";
+    return false;
+  }
+
+  MFnAttribute attr_fn(attr, &status);
+  if (!status) {
+    maya_cat.error()
+      << "Attribute " << attribute_name << " on " << node_fn.name()
+      << " is a " << attr.apiTypeStr() << ", not an Attribute.\n";
+    return false;
+  }
+
+  plug = MPlug(node, attr);
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: get_bool_attribute
 //  Description: Extracts the named boolean attribute from the
@@ -170,6 +204,52 @@ get_string_attribute(MObject &node, const string &attribute_name,
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: set_string_attribute
+//  Description: Sets the named string attribute on the
+//               MObject.
+////////////////////////////////////////////////////////////////////
+bool
+set_string_attribute(MObject &node, const string &attribute_name,
+                     const string &value) {
+  MStatus status;
+
+  // First, we get the string_object, then we set its string.
+  MObject string_object;
+  if (!get_maya_attribute(node, attribute_name, string_object)) {
+    maya_cat.error()
+      << "Attribute " << attribute_name
+      << " does not have an string object value.\n";
+    describe_maya_attribute(node, attribute_name);
+    return false;
+  }
+
+  MFnStringData data(string_object, &status);
+  if (!status) {
+    maya_cat.error()
+      << "Attribute " << attribute_name << " is of type "
+      << string_object.apiTypeStr() << ", not a StringData.\n";
+    return false;
+  }
+
+  MString mstring_value(value.data(), value.length());
+  status = data.set(mstring_value);
+  if (!status) {
+    status.perror(attribute_name.c_str());
+    return false;
+  }
+
+  // And it appears we now need to set the string object back.
+  if (!set_maya_attribute(node, attribute_name, string_object)) {
+    maya_cat.error()
+      << "Attribute " << attribute_name
+      << " suddenly does not have an string object value.\n";
+    return false;
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: describe_maya_attribute
 //  Description: Writes some error output about the indicated Maya

+ 12 - 0
pandatool/src/maya/maya_funcs.h

@@ -35,11 +35,19 @@
 
 class MObject;
 
+bool
+get_maya_plug(MObject &node, const string &attribute_name, MPlug &plug);
+
 template<class ValueType>
 bool
 get_maya_attribute(MObject &node, const string &attribute_name,
                    ValueType &value);
 
+template<class ValueType>
+bool
+set_maya_attribute(MObject &node, const string &attribute_name,
+                   ValueType &value);
+
 bool
 get_bool_attribute(MObject &node, const string &attribute_name,
                    bool &value);
@@ -60,6 +68,10 @@ bool
 get_string_attribute(MObject &node, const string &attribute_name,
                      string &value);
 
+bool
+set_string_attribute(MObject &node, const string &attribute_name,
+                     const string &value);
+
 void
 describe_maya_attribute(MObject &node, const string &attribute_name);
 

+ 15 - 0
pandatool/src/mayaprogs/Sources.pp

@@ -40,3 +40,18 @@
 
 #end bin_target
 
+
+#begin bin_target
+  #define USE_MAYA yes
+  #define TARGET mayacopy
+  #define LOCAL_LIBS cvscopy maya progbase
+
+  #define OTHER_LIBS \
+    linmath:c panda:m \
+    express:c pandaexpress:m \
+    dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m pystub
+
+  #define SOURCES \
+    mayaCopy.cxx mayaCopy.h
+
+#end bin_target

+ 160 - 27
pandatool/src/mayaprogs/mayaCopy.cxx

@@ -17,10 +17,23 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "mayaCopy.h"
-
+#include "config_maya.h"
 #include "cvsSourceDirectory.h"
+#include "mayaShader.h"
 #include "dcast.h"
 
+#include "pre_maya_include.h"
+#include <maya/MStringArray.h>
+#include <maya/MFileIO.h>
+#include <maya/MItDag.h>
+#include <maya/MFnDagNode.h>
+#include <maya/MFnNurbsSurface.h>
+#include <maya/MFnMesh.h>
+#include <maya/MObject.h>
+#include <maya/MDagPath.h>
+#include <maya/MIntArray.h>
+#include "post_maya_include.h"
+
 ////////////////////////////////////////////////////////////////////
 //     Function: MayaCopy::Constructor
 //       Access: Public
@@ -50,6 +63,12 @@ MayaCopy() {
 ////////////////////////////////////////////////////////////////////
 void MayaCopy::
 run() {
+  _maya = MayaApi::open_api(_program_name);
+  if (!_maya->is_valid()) {
+    nout << "Unable to initialize Maya.\n";
+    exit(1);
+  }
+
   SourceFiles::iterator fi;
   for (fi = _source_files.begin(); fi != _source_files.end(); ++fi) {
     ExtraData ed;
@@ -95,17 +114,78 @@ bool MayaCopy::
 copy_maya_file(const Filename &source, const Filename &dest,
                CVSSourceDirectory *dir) {
   if (!_maya->read(source)) {
-    mayaegg_cat.error()
+    maya_cat.error()
       << "Unable to read " << source << "\n";
     return false;
   }
 
+  // Get all the shaders so we can determine the set of textures.
+  _shaders.clear();
+  collect_shaders();
+  int num_shaders = _shaders.get_num_shaders();
+  for (int i = 0; i < num_shaders; i++) {
+    MayaShader *shader = _shaders.get_shader(i);
+    if (shader->_has_texture) {
+      Filename texture_filename = shader->_texture;
+      if (!texture_filename.exists()) {
+        nout << "*** Warning: texture " << texture_filename
+             << " does not exist.\n";
+      } else {
+        ExtraData ed;
+        ed._type = FT_texture;
+
+        CVSSourceDirectory *texture_dir =
+          import(texture_filename, &ed, _map_dir);
+        if (texture_dir == (CVSSourceDirectory *)NULL) {
+          return false;
+        }
+
+        // Update the texture reference to point to the new texture
+        // filename, relative to the flt file.  Not sure how to do
+        // this right now.
+        Filename new_filename = dir->get_rel_to(texture_dir) + "/" +
+          texture_filename.get_basename();
+        shader->reset_maya_texture(new_filename);
+      }
+    }
+  }
+
+  // Get the set of externally referenced Maya files.
+  MStringArray refs;
+  MStatus status = MFileIO::getReferences(refs);
+  if (!status) {
+    status.perror("MItDag constructor");
+    return false;
+  }
+
+  // Now write out the Maya file.
   if (!_maya->write(dest)) {
-    mayaegg_cat.error()
+    maya_cat.error()
       << "Cannot write " << dest << "\n";
     return false;
   }
 
+  // Finally, copy in any referenced Maya files.  This is untested code.
+  unsigned int num_refs = refs.length();
+  if (num_refs != 0) {
+    maya_cat.warning()
+      << "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();
+    maya_cat.warning()
+      << "External ref: " << filename << "\n";
+    /*
+    ExtraData ed;
+    ed._type = FT_maya;
+
+    CVSSourceDirectory *dest = import(filename, &ed, _model_dir);
+    if (dest == (CVSSourceDirectory *)NULL) {
+      exit(1);
+    }
+    */
+  }
+
   return true;
 }
 
@@ -124,42 +204,95 @@ copy_texture(const Filename &source, const Filename &dest,
   return true;
 }
 
-/*
 ////////////////////////////////////////////////////////////////////
-//     Function: MayaCopy::scan_maya
+//     Function: MayaCopy::collect_shaders
 //       Access: Private
-//  Description: Recursively walks through the maya file hierarchy,
-//               looking for texture references and external maya file
-//               references.
+//  Description: Recursively walks through the maya scene graph
+//               hierarchy, looking for shaders.
 ////////////////////////////////////////////////////////////////////
-void MayaCopy::
-scan_maya(MayaRecord *record, MayaCopy::Refs &refs, MayaCopy::Textures &textures) {
-  if (record->is_of_type(MayaFace::get_class_type())) {
-    MayaFace *face;
-    DCAST_INTO_V(face, record);
-    if (face->has_texture()) {
-      textures.insert(face->get_texture());
+bool MayaCopy::
+collect_shaders() {
+  MStatus status;
+
+  MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status);
+  if (!status) {
+    status.perror("MItDag constructor");
+    return false;
+  }
+
+  // This while loop walks through the entire Maya hierarchy, one node
+  // at a time.  Maya's MItDag object automatically performs a
+  // depth-first traversal of its scene graph.
+  bool all_ok = true;
+  while (!dag_iterator.isDone()) {
+    MDagPath dag_path;
+    status = dag_iterator.getPath(dag_path);
+    if (!status) {
+      status.perror("MItDag::getPath");
+    } else {
+      if (!collect_shader_for_node(dag_path)) {
+        all_ok = false;
+      }
     }
 
-  } else if (record->is_of_type(MayaExternalReference::get_class_type())) {
-    MayaExternalReference *ref;
-    DCAST_INTO_V(ref, record);
+    dag_iterator.next();
+  }
 
-    refs.insert(ref);
+  if (!all_ok) {
+    nout << "Errors encountered in traversal.\n";
+    return false;
   }
 
-  int i;
-  int num_subfaces = record->get_num_subfaces();
-  for (i = 0; i < num_subfaces; i++) {
-    scan_maya(record->get_subface(i), refs, textures);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MayaCopy::collect_shader_for_node
+//       Access: Private
+//  Description: Gets the relevant shader on the current node, if it
+//               has one.
+////////////////////////////////////////////////////////////////////
+bool MayaCopy::
+collect_shader_for_node(const MDagPath &dag_path) {
+  MStatus status;
+  MFnDagNode dag_node(dag_path, &status);
+  if (!status) {
+    status.perror("MFnDagNode constructor");
+    return false;
   }
 
-  int num_children = record->get_num_children();
-  for (i = 0; i < num_children; i++) {
-    scan_maya(record->get_child(i), refs, textures);
+  if (dag_path.hasFn(MFn::kNurbsSurface)) {
+    MFnNurbsSurface surface(dag_path, &status);
+    if (status) {
+      _shaders.find_shader_for_node(surface.object());
+    }
+
+  } else if (dag_path.hasFn(MFn::kMesh)) {
+    MFnMesh mesh(dag_path, &status);
+    if (status) {
+      // Meshes may have multiple different shaders.
+      MObjectArray shaders;
+      MIntArray poly_shader_indices;
+
+      status = mesh.getConnectedShaders(dag_path.instanceNumber(),
+                                        shaders, poly_shader_indices);
+      if (status) {
+        unsigned int num_shaders = shaders.length();
+        for (unsigned int shader_index = 0;
+             shader_index < num_shaders; 
+             shader_index++) {
+          MObject engine = shaders[shader_index];
+          _shaders.find_shader_for_shading_engine(engine);
+        }
+      }
+    }
+
+  } else {
+    // Ignoring other kinds of node.
   }
+
+  return true;
 }
-*/
 
 
 int main(int argc, char *argv[]) {

+ 7 - 6
pandatool/src/mayaprogs/mayaCopy.h

@@ -20,15 +20,16 @@
 #define MAYACOPY_H
 
 #include "pandatoolbase.h"
-
 #include "cvsCopy.h"
-
+#include "mayaApi.h"
+#include "mayaShaders.h"
 #include "dSearchPath.h"
 #include "pointerTo.h"
 
 #include "pset.h"
 
 class MayaShader;
+class MDagPath;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : MayaCopy
@@ -63,11 +64,11 @@ private:
   bool copy_texture(const Filename &source, const Filename &dest,
                     CVSSourceDirectory *dir);
 
+  bool collect_shaders();
+  bool collect_shader_for_node(const MDagPath &dag_path);
 
-  typedef pset< PT(MayaExternalReference) > Refs;
-  typedef pset< PT(MayaTexture) > Textures;
-
-  void scan_maya(MayaRecord *record, Refs &refs, Textures &textures);
+  PT(MayaApi) _maya;
+  MayaShaders _shaders;
 };
 
 #endif