Przeglądaj źródła

first submit: converts the model only on this version. No animation yet.

Asad M. Zaman 22 lat temu
rodzic
commit
d01bc14649

+ 27 - 0
pandatool/src/softegg/Sources.pp

@@ -0,0 +1,27 @@
+#define BUILD_DIRECTORY $[HAVE_SOFTIMAGE]
+
+#begin lib_target
+  #define USE_PACKAGES softimage
+  #define TARGET softegg
+  #define LOCAL_LIBS \
+    converter pandatoolbase
+  #define OTHER_LIBS \
+    egg:c pandaegg:m \
+    linmath:c putil:c panda:m \
+    express:c pandaexpress:m \
+    dtoolutil:c dtoolbase:c dconfig:c dtoolconfig:m dtool:m pystub
+
+  #define BUILDING_DLL BUILDING_MISC
+  #define UNIX_SYS_LIBS \
+    m
+
+  #define SOURCES \
+    config_softegg.cxx config_softegg.h \
+    softEggGroupUserData.cxx softEggGroupUserData.I softEggGroupUserData.h \
+    softToEggConverter.cxx softToEggConverter.h \
+    soft2Egg.c \
+    softNodeTree.cxx softNodeTree.h \
+    softNodeDesc.cxx softNodeDesc.h
+
+#end lib_target
+

+ 63 - 0
pandatool/src/softegg/config_softegg.cxx

@@ -0,0 +1,63 @@
+// Filename: config_softegg.cxx
+// Created by:  masad (25Sep03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2003, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "config_softegg.h"
+#include "softEggGroupUserData.h"
+
+#include "dconfig.h"
+
+Configure(config_softegg);
+NotifyCategoryDef(softegg, ":soft");
+
+ConfigureFn(config_softegg) {
+  init_libsoftegg();
+}
+
+// These control the default behavior of the softegg converter, but
+// not necessarily the default behavior of the soft2egg command-line
+// tool (which has its own defaults).
+
+// Should we respect the Soft? double-sided flag (true) or ignore it
+// and assume everything is single-sided (false)?
+const bool soft_default_double_sided = config_softegg.GetBool("soft-default-double-sided", false);
+
+// Should we apply vertex color even when a texture is applied (true)
+// or only when no texture is applied or the vertex-color egg flag is
+// set (false)?
+const bool soft_default_vertex_color = config_softegg.GetBool("soft-default-vertex-color", true);
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libsoftegg
+//  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_libsoftegg() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  initialized = true;
+
+  SoftEggGroupUserData::init_type();
+  //  SoftNodeDesc::init_type();
+}
+

+ 32 - 0
pandatool/src/softegg/config_softegg.h

@@ -0,0 +1,32 @@
+// Filename: config_softegg.h
+// Created by:  masad (25Sep03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIG_SOFTEGG_H
+#define CONFIG_SOFTEGG_H
+
+#include "pandatoolbase.h"
+#include "notifyCategoryProxy.h"
+
+NotifyCategoryDeclNoExport(softegg);
+
+extern const bool soft_default_double_sided;
+extern const bool soft_default_vertex_color;
+
+extern void init_libsoftegg();
+
+#endif

+ 56 - 0
pandatool/src/softegg/softEggGroupUserData.I

@@ -0,0 +1,56 @@
+// Filename: softEggGroupUserData.I
+// Created by:  masad (25Sep03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2003, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftEggGroupUserData::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE SoftEggGroupUserData::
+SoftEggGroupUserData() {
+  _vertex_color = false;
+  _double_sided = false;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftEggGroupUserData::Copy constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE SoftEggGroupUserData::
+SoftEggGroupUserData(const SoftEggGroupUserData &copy) : 
+  EggUserData(copy),
+  _vertex_color(copy._vertex_color),
+  _double_sided(copy._double_sided)
+{
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftEggGroupUserData::Copy assignment operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void SoftEggGroupUserData::
+operator = (const SoftEggGroupUserData &copy) {
+  EggUserData::operator = (copy);
+  _vertex_color = copy._vertex_color;
+  _double_sided = copy._double_sided;
+}

+ 21 - 0
pandatool/src/softegg/softEggGroupUserData.cxx

@@ -0,0 +1,21 @@
+// Filename: softEggGroupUserData.cxx
+// Created by:  masad (25Sep03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2003, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "softEggGroupUserData.h"
+
+TypeHandle SoftEggGroupUserData::_type_handle;

+ 60 - 0
pandatool/src/softegg/softEggGroupUserData.h

@@ -0,0 +1,60 @@
+// Filename: softEggGroupUserData.h
+// Created by:  masad (25Sep03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2003, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef SOFTEGGGROUPUSERDATA_H
+#define SOFTEGGGROUPUSERDATA_H
+
+#include "pandatoolbase.h"
+#include "eggUserData.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : SoftEggGroupUserData
+// Description : This class contains extra user data which is
+//               piggybacked onto EggGroup objects for the purpose of
+//               the softimage converter.
+////////////////////////////////////////////////////////////////////
+class SoftEggGroupUserData : public EggUserData {
+public:
+  INLINE SoftEggGroupUserData();
+  INLINE SoftEggGroupUserData(const SoftEggGroupUserData &copy);
+  INLINE void operator = (const SoftEggGroupUserData &copy);
+
+  bool _vertex_color;
+  bool _double_sided;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    EggUserData::init_type();
+    register_type(_type_handle, "SoftEggGroupUserData",
+                  EggUserData::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "softEggGroupUserData.I"
+
+#endif

+ 209 - 0
pandatool/src/softegg/softNodeDesc.cxx

@@ -0,0 +1,209 @@
+// Filename: softNodeDesc.cxx
+// Created by:  masad (03Oct03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2003, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "softNodeDesc.h"
+
+TypeHandle SoftNodeDesc::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeDesc::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SoftNodeDesc::
+SoftNodeDesc(const string &name) :
+  Namable(name)
+  //  _parent(parent)
+{
+  _model = (SAA_Elem *)NULL;
+  _egg_group = (EggGroup *)NULL;
+  _egg_table = (EggTable *)NULL;
+  _anim = (EggXfmSAnim *)NULL;
+  _joint_type = JT_none;
+#if 0
+  // Add ourselves to our parent.
+  if (_parent != (SoftNodeDesc *)NULL) {
+    _parent->_children.push_back(this);
+  }
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeDesc::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SoftNodeDesc::
+~SoftNodeDesc() {
+  if (_model != (SAA_Elem *)NULL) {
+    delete _model;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeDesc::set_model
+//       Access: Public
+//  Description: Indicates an associated between the SoftNodeDesc and
+//               some SAA_Elem instance.
+////////////////////////////////////////////////////////////////////
+void SoftNodeDesc::
+set_model(SAA_Elem *model) {
+  _model = model;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeDesc::has_model
+//       Access: Public
+//  Description: Returns true if a Soft dag path has been associated
+//               with this node, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool SoftNodeDesc::
+has_model() const {
+  return (_model != (SAA_Elem *)NULL);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeDesc::get_model
+//       Access: Public
+//  Description: Returns the SAA_Elem * associated with this node.  It
+//               is an error to call this unless has_model()
+//               returned true.
+////////////////////////////////////////////////////////////////////
+SAA_Elem *SoftNodeDesc::
+get_model() const {
+  nassertr(_model != (SAA_Elem *)NULL, _model);
+  return _model;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeDesc::is_joint
+//       Access: Private
+//  Description: Returns true if the node should be treated as a joint
+//               by the converter.
+////////////////////////////////////////////////////////////////////
+bool SoftNodeDesc::
+is_joint() const {
+  return _joint_type == JT_joint || _joint_type == JT_pseudo_joint;
+}
+#if 0
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeDesc::is_joint_parent
+//       Access: Private
+//  Description: Returns true if the node is the parent or ancestor of
+//               a joint.
+////////////////////////////////////////////////////////////////////
+bool SoftNodeDesc::
+is_joint_parent() const {
+  return _joint_type == JT_joint_parent;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeDesc::clear_egg
+//       Access: Private
+//  Description: Recursively clears the egg pointers from this node
+//               and all children.
+////////////////////////////////////////////////////////////////////
+void SoftNodeDesc::
+clear_egg() {
+  _egg_group = (EggGroup *)NULL;
+  _egg_table = (EggTable *)NULL;
+  _anim = (EggXfmSAnim *)NULL;
+
+  Children::const_iterator ci;
+  for (ci = _children.begin(); ci != _children.end(); ++ci) {
+    SoftNodeDesc *child = (*ci);
+    child->clear_egg();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeDesc::mark_joint_parent
+//       Access: Private
+//  Description: Indicates that this node has at least one child that
+//               is a joint or a pseudo-joint.
+////////////////////////////////////////////////////////////////////
+void SoftNodeDesc::
+mark_joint_parent() {
+  if (_joint_type == JT_none) {
+    _joint_type = JT_joint_parent;
+    if (_parent != (SoftNodeDesc *)NULL) {
+      _parent->mark_joint_parent();
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeDesc::check_pseudo_joints
+//       Access: Private
+//  Description: Walks the hierarchy, looking for non-joint nodes that
+//               are both children and parents of a joint.  These
+//               nodes are deemed to be pseudo joints, since the
+//               converter must treat them as joints.
+////////////////////////////////////////////////////////////////////
+void SoftNodeDesc::
+check_pseudo_joints(bool joint_above) {
+  if (_joint_type == JT_joint_parent && joint_above) {
+    // This is one such node: it is the parent of a joint
+    // (JT_joint_parent is set), and it is the child of a joint
+    // (joint_above is set).
+    _joint_type = JT_pseudo_joint;
+  }
+
+  if (_joint_type == JT_joint) {
+    // If this node is itself a joint, then joint_above is true for
+    // all child nodes.
+    joint_above = true;
+  }
+
+  // Don't bother traversing further if _joint_type is none, since
+  // that means this node has no joint children.
+  if (_joint_type != JT_none) {
+
+    bool any_joints = false;
+    Children::const_iterator ci;
+    for (ci = _children.begin(); ci != _children.end(); ++ci) {
+      SoftNodeDesc *child = (*ci);
+      child->check_pseudo_joints(joint_above);
+      if (child->is_joint()) {
+        any_joints = true;
+      }
+    }
+
+    // If any children qualify as joints, then any sibling nodes that
+    // are parents of joints are also elevated to joints.
+    if (any_joints) {
+      bool all_joints = true;
+      for (ci = _children.begin(); ci != _children.end(); ++ci) {
+        SoftNodeDesc *child = (*ci);
+        if (child->_joint_type == JT_joint_parent) {
+          child->_joint_type = JT_pseudo_joint;
+        } else if (child->_joint_type == JT_none) {
+          all_joints = false;
+        }
+      }
+
+      if (all_joints) {
+        // Finally, if all children are joints, then we are too.
+        if (_joint_type == JT_joint_parent) {
+          _joint_type = JT_pseudo_joint;
+        }
+      }
+    }
+  }
+}
+#endif

+ 96 - 0
pandatool/src/softegg/softNodeDesc.h

@@ -0,0 +1,96 @@
+// Filename: softNodeDesc.h
+// Created by:  masad (03Oct03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef SOFTNODEDESC_H
+#define SOFTNODEDESC_H
+
+#include "pandatoolbase.h"
+
+#include "referenceCount.h"
+#include "pointerTo.h"
+#include "namable.h"
+
+#include <SAA.h>
+
+class EggGroup;
+class EggTable;
+class EggXfmSAnim;
+
+////////////////////////////////////////////////////////////////////
+//       Class : SoftNodeDesc
+// Description : Describes a single instance of a node aka element in the Soft
+//               scene graph, relating it to the corresponding egg
+//               structures (e.g. node, group, or table entry) that
+//               will be created.
+////////////////////////////////////////////////////////////////////
+class SoftNodeDesc : public ReferenceCount, public Namable {
+public:
+  SoftNodeDesc(const string &name = string());
+  ~SoftNodeDesc();
+
+  void set_model(SAA_Elem *model);
+  bool has_model() const;
+  SAA_Elem *get_model() const;
+
+  bool is_joint() const;
+  //  bool is_joint_parent() const;
+
+  //  SoftNodeDesc *_parent;
+  //  typedef pvector< PT(SoftNodeDesc) > Children;
+  //  Children _children;
+  
+private:
+  void clear_egg();
+  //  void mark_joint_parent();
+  //  void check_pseudo_joints(bool joint_above);
+
+  SAA_Elem *_model;
+
+  EggGroup *_egg_group;
+  EggTable *_egg_table;
+  EggXfmSAnim *_anim;
+
+  enum JointType {
+    JT_none,         // Not a joint.
+    JT_joint,        // An actual joint in Soft.
+    JT_pseudo_joint, // Not a joint in Soft, but treated just like a
+                     // joint for the purposes of the converter.
+    JT_joint_parent, // A parent or ancestor of a joint or pseudo joint.
+  };
+  JointType _joint_type;
+
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    ReferenceCount::init_type();
+    Namable::init_type();
+    register_type(_type_handle, "SoftNodeDesc",
+                  ReferenceCount::get_class_type(),
+                  Namable::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class SoftNodeTree;
+};
+
+#endif

+ 454 - 0
pandatool/src/softegg/softNodeTree.cxx

@@ -0,0 +1,454 @@
+// Filename: softNodeTree.cxx
+// Created by:  masad (26Sep03)
+// 
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2003, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+// Includes
+////////////////////////////////////////////////////////////////////
+
+#include "softNodeTree.h"
+#include "softEggGroupUserData.h"
+#include "config_softegg.h"
+#include "eggGroup.h"
+#include "eggTable.h"
+#include "eggXfmSAnim.h"
+#include "eggData.h"
+#include "dcast.h"
+
+#include <SAA.h>
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeTree::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SoftNodeTree::
+SoftNodeTree() {
+  //  _root = new SoftNodeDesc;
+  _root = NULL;
+  _fps = 0.0;
+  _egg_data = (EggData *)NULL;
+  _egg_root = (EggGroupNode *)NULL;
+  _skeleton_node = (EggGroupNode *)NULL;
+}
+////////////////////////////////////////////////////////////////////
+//     Function: GetName
+//       Access: Public
+//  Description: Given an element, return a copy of the element's 
+//                 name WITHOUT prefix. 
+////////////////////////////////////////////////////////////////////
+char *SoftNodeTree::
+GetName( SAA_Scene *scene, SAA_Elem *element ) {
+  int nameLen;
+  char *name;
+
+  // get the name
+  SAA_elementGetNameLength( scene, element, &nameLen ); 
+  name = new char[++nameLen];
+  SAA_elementGetName( scene, element, nameLen, name );
+
+  return name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GetFullName
+//       Access: Public
+//  Description: Given an element, return a copy of the element's 
+//                 name complete with prefix. 
+////////////////////////////////////////////////////////////////////
+char *SoftNodeTree::
+GetFullName( SAA_Scene *scene, SAA_Elem *element )
+{
+  int nameLen, prefixLen;
+  char *name, *prefix;
+
+  // get the name length
+  SAA_elementGetNameLength( scene, element, &nameLen );
+  // get the prefix length
+  SAA_elementGetPrefixLength( scene, element, &prefixLen );
+  // allocate the array to hold name
+  name = new char[++nameLen];
+  // allocate the array to hold prefix and length + hyphen
+  prefix = new char[++prefixLen + nameLen + 4];
+  // get the name
+  SAA_elementGetName( scene, element, nameLen, name );
+  // get the prefix
+  SAA_elementGetPrefix( scene, element, prefixLen, prefix );
+  // add 'em together
+  strcat(prefix, "-");
+  strcat(prefix, name);
+
+  // return string
+  return prefix;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeTree::build_node
+//       Access: Public
+//  Description: Returns a pointer to the node corresponding to the
+//               indicated dag_path object, creating it first if
+//               necessary.
+////////////////////////////////////////////////////////////////////
+SoftNodeDesc *SoftNodeTree::
+build_node(SAA_Elem *model, const char *name) {
+  string node_name = name;
+  SoftNodeDesc *node_desc = r_build_node(node_name);
+  node_desc->set_model(model);
+  return node_desc;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeTree::build_complete_hierarchy
+//       Access: Public
+//  Description: Walks through the complete Soft hierarchy and builds
+//               up the corresponding tree.
+////////////////////////////////////////////////////////////////////
+bool SoftNodeTree::
+build_complete_hierarchy(SAA_Scene &scene, SAA_Database &database, char **root_name) {
+  SI_Error status;
+
+  // Get the entire Soft scene.
+  int numModels;
+  SAA_Elem *models;
+  
+  SAA_sceneGetNbModels( &scene, &numModels ); 
+  cout << "Scene has " << numModels << " model(s)...\n";
+  
+  // This while loop walks through the entire Soft hierarchy, one
+  // node at a time. 
+  bool all_ok = true;
+  if ( numModels ) {
+    // allocate array of models
+    models = (SAA_Elem *) new SAA_Elem[numModels];
+    if ( models != NULL ) {
+      if ((status = SAA_sceneGetModels( &scene, numModels, models )) != SI_SUCCESS) {
+        return false;
+      }
+      for ( int i = 0; i < numModels; i++ ) {
+        int level;
+        status = SAA_elementGetHierarchyLevel( &scene, &models[i], &level );
+        cout << "level " << level << endl;
+        char *name = GetName(&scene, &models[i]);
+        if ( !level ) {
+          // this is the root node, so this should be the name of the model
+          *root_name = name;
+        }
+        SoftNodeDesc *node_desc = build_node(&models[i], name);
+        cout << "status is " << status << "\n";
+      }
+    }
+  }
+# if 0  
+  if (all_ok) {
+    _root->check_pseudo_joints(false);
+  }
+#endif  
+  return all_ok;
+}
+#if 0
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeTree::build_selected_hierarchy
+//       Access: Public
+//  Description: Walks through the selected subset of the Soft
+//               hierarchy (or the complete hierarchy, if nothing is
+//               selected) and builds up the corresponding tree.
+////////////////////////////////////////////////////////////////////
+bool SoftNodeTree::
+build_selected_hierarchy(char *scene_name) {
+  MStatus status;
+
+  MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status);
+  if (!status) {
+    status.perror("MItDag constructor");
+    return false;
+  }
+
+  // Get only the selected geometry.
+  MSelectionList selection;
+  status = MGlobal::getActiveSelectionList(selection);
+  if (!status) {
+    status.perror("MGlobal::getActiveSelectionList");
+    return false;
+  }
+  
+  // Get the selected geometry only if the selection is nonempty;
+  // otherwise, get the whole scene anyway.
+  if (selection.isEmpty()) {
+    softegg_cat.info()
+      << "Selection list is empty.\n";
+    return build_complete_hierarchy();
+  }
+
+  bool all_ok = true;
+  unsigned int length = selection.length();
+  for (unsigned int i = 0; i < length; i++) {
+    MDagPath root_path;
+    status = selection.getDagPath(i, root_path);
+    if (!status) {
+      status.perror("MSelectionList::getDagPath");
+    } else {
+      // Now traverse through the selected dag path and all nested
+      // dag paths.
+      dag_iterator.reset(root_path);
+      while (!dag_iterator.isDone()) {
+        MDagPath dag_path;
+        status = dag_iterator.getPath(dag_path);
+        if (!status) {
+          status.perror("MItDag::getPath");
+        } else {
+          build_node(dag_path);
+        }
+        
+        dag_iterator.next();
+      }
+    }
+  }
+
+  if (all_ok) {
+    _root->check_pseudo_joints(false);
+  }
+
+  return all_ok;
+}
+#endif
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeTree::get_num_nodes
+//       Access: Public
+//  Description: Returns the total number of nodes in the hierarchy,
+//               not counting the root node.
+////////////////////////////////////////////////////////////////////
+int SoftNodeTree::
+get_num_nodes() const {
+  return _nodes.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeTree::get_node
+//       Access: Public
+//  Description: Returns the nth node in the hierarchy, in an
+//               arbitrary ordering.
+////////////////////////////////////////////////////////////////////
+SoftNodeDesc *SoftNodeTree::
+get_node(int n) const {
+  nassertr(n >= 0 && n < (int)_nodes.size(), NULL);
+  return _nodes[n];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeTree::clear_egg
+//       Access: Public
+//  Description: Removes all of the references to generated egg
+//               structures from the tree, and prepares the tree for
+//               generating new egg structures.
+////////////////////////////////////////////////////////////////////
+void SoftNodeTree::
+clear_egg(EggData *egg_data, EggGroupNode *egg_root, 
+          EggGroupNode *skeleton_node) {
+  //  _root->clear_egg();
+  _egg_data = egg_data;
+  _egg_root = egg_root;
+  _skeleton_node = skeleton_node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeTree::get_egg_group
+//       Access: Public
+//  Description: Returns the EggGroupNode corresponding to the group
+//               or joint for the indicated node.  Creates the group
+//               node if it has not already been created.
+////////////////////////////////////////////////////////////////////
+EggGroup *SoftNodeTree::
+get_egg_group(SoftNodeDesc *node_desc) {
+  nassertr(_egg_root != (EggGroupNode *)NULL, NULL);
+
+  if (node_desc->_egg_group == (EggGroup *)NULL) {
+    // We need to make a new group node.
+    EggGroup *egg_group;
+    
+    egg_group = new EggGroup(node_desc->get_name());
+    if (node_desc->is_joint()) {
+      egg_group->set_group_type(EggGroup::GT_joint);
+    }
+    // For now lets add this group to egg_root.
+    _egg_root->add_child(egg_group);
+
+#if 0
+    SoftEggGroupUserData *parent_user_data = NULL;
+
+    if (node_desc->_parent == _root) {
+      // The parent is the root.
+      _egg_root->add_child(egg_group);
+
+    } else {
+      // The parent is another node.
+      EggGroup *parent_egg_group = get_egg_group(node_desc->_parent);
+      parent_egg_group->add_child(egg_group);
+
+      if (parent_egg_group->has_user_data()) {
+        DCAST_INTO_R(parent_user_data, parent_egg_group->get_user_data(), NULL);
+      }
+    }
+
+    if (node_desc->has_models()) {
+      // Check for an object type setting, from Oliver's plug-in.
+      MObject dag_object = node_desc->get_dag_path().node();
+      string object_type;
+      if (get_enum_attribute(dag_object, "eggObjectTypes1", object_type)) {
+        egg_group->add_object_type(object_type);
+      }
+      if (get_enum_attribute(dag_object, "eggObjectTypes2", object_type)) {
+        egg_group->add_object_type(object_type);
+      }
+      if (get_enum_attribute(dag_object, "eggObjectTypes3", object_type)) {
+        egg_group->add_object_type(object_type);
+      }
+
+      // Is the node flagged to be invisible?  If it is, and is has no
+      // other egg flags, it is implicitly tagged "backstage", so it
+      // won't get converted.  (But it might be an invisible collision
+      // solid, which is why we do this only if it has no other egg
+      // flags.)
+      bool visible = true;
+      get_bool_attribute(dag_object, "visibility", visible);
+      if (!visible && egg_group->get_num_object_types() == 0) {
+        egg_group->add_object_type("backstage");
+      }
+
+      // We treat the object type "billboard" as a special case: we
+      // apply this one right away and also flag the group as an
+      // instance.
+      if (egg_group->has_object_type("billboard")) {    
+        egg_group->remove_object_type("billboard");
+        egg_group->set_group_type(EggGroup::GT_instance);
+        egg_group->set_billboard_type(EggGroup::BT_axis);
+        
+      } else if (egg_group->has_object_type("billboard-point")) {    
+        egg_group->remove_object_type("billboard-point");
+        egg_group->set_group_type(EggGroup::GT_instance);
+        egg_group->set_billboard_type(EggGroup::BT_point_camera_relative);
+      }
+      
+      // We also treat the object type "dcs" and "model" as a special
+      // case, so we can test for these flags later.
+      if (egg_group->has_object_type("dcs")) {
+        egg_group->remove_object_type("dcs");
+        egg_group->set_dcs_type(EggGroup::DC_default);
+      }
+      if (egg_group->has_object_type("model")) {
+        egg_group->remove_object_type("model");
+        egg_group->set_model_flag(true);
+      }
+      
+      // And "vertex-color" and "double-sided" have meaning only to
+      // this converter.
+      SoftEggGroupUserData *user_data;
+      if (parent_user_data == (SoftEggGroupUserData *)NULL) {
+        user_data = new SoftEggGroupUserData;
+      } else {
+        // Inherit the flags from above.
+        user_data = new SoftEggGroupUserData(*parent_user_data);
+      }
+
+      if (egg_group->has_object_type("vertex-color")) {
+        egg_group->remove_object_type("vertex-color");
+        user_data->_vertex_color = true;
+      }
+      if (egg_group->has_object_type("double-sided")) {
+        egg_group->remove_object_type("double-sided");
+        user_data->_double_sided = true;
+      }
+      egg_group->set_user_data(user_data);
+    }
+#endif
+    //    EggUserData *user_data = new EggUserData;
+    //    egg_group->set_user_data(user_data);
+    node_desc->_egg_group = egg_group;
+  }
+
+  return node_desc->_egg_group;
+}
+#if 0
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeTree::get_egg_table
+//       Access: Public
+//  Description: Returns the EggTable corresponding to the joint
+//               for the indicated node.  Creates the table node if it
+//               has not already been created.
+////////////////////////////////////////////////////////////////////
+EggTable *SoftNodeTree::
+get_egg_table(SoftNodeDesc *node_desc) {
+  nassertr(_skeleton_node != (EggGroupNode *)NULL, NULL);
+  nassertr(node_desc->is_joint(), NULL);
+
+  if (node_desc->_egg_table == (EggTable *)NULL) {
+    // We need to make a new table node.
+    nassertr(node_desc->_parent != (SoftNodeDesc *)NULL, NULL);
+
+    EggTable *egg_table = new EggTable(node_desc->get_name());
+    node_desc->_anim = new EggXfmSAnim("xform", _egg_data->get_coordinate_system());
+    node_desc->_anim->set_fps(_fps);
+    egg_table->add_child(node_desc->_anim);
+
+    if (!node_desc->_parent->is_joint()) {
+      // The parent is not a joint; put it at the top.
+      _skeleton_node->add_child(egg_table);
+
+    } else {
+      // The parent is another joint.
+      EggTable *parent_egg_table = get_egg_table(node_desc->_parent);
+      parent_egg_table->add_child(egg_table);
+    }
+
+    node_desc->_egg_table = egg_table;
+  }
+
+  return node_desc->_egg_table;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeTree::get_egg_anim
+//       Access: Public
+//  Description: Returns the anim table corresponding to the joint
+//               for the indicated node.  Creates the table node if it
+//               has not already been created.
+////////////////////////////////////////////////////////////////////
+EggXfmSAnim *SoftNodeTree::
+get_egg_anim(SoftNodeDesc *node_desc) {
+  get_egg_table(node_desc);
+  return node_desc->_anim;
+}
+#endif
+////////////////////////////////////////////////////////////////////
+//     Function: SoftNodeTree::r_build_node
+//       Access: Private
+//  Description: The recursive implementation of build_node().
+////////////////////////////////////////////////////////////////////
+SoftNodeDesc *SoftNodeTree::
+r_build_node(const string &name) {
+  // Otherwise, we have to create it.  Do this recursively, so we
+  // create each node along the path.
+  SoftNodeDesc *node_desc;
+
+  node_desc = new SoftNodeDesc(name);
+  _nodes.push_back(node_desc);
+
+  return node_desc;
+}
+
+//
+//
+//

+ 76 - 0
pandatool/src/softegg/softNodeTree.h

@@ -0,0 +1,76 @@
+// Filename: softNodeTree.h
+// Created by:  masad (03Oct03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2003, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef SOFTNODETREE_H
+#define SOFTNODETREE_H
+
+#include "pandatoolbase.h"
+#include "softNodeDesc.h"
+
+#include <SAA.h>
+
+class EggGroup;
+class EggTable;
+class EggXfmSAnim;
+class EggData;
+class EggGroupNode;
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : SoftNodeTree
+// Description : Describes a complete tree of soft nodes for
+//               conversion.
+////////////////////////////////////////////////////////////////////
+class SoftNodeTree {
+public:
+  SoftNodeTree();
+  SoftNodeDesc *build_node(SAA_Elem *model, const char *name);
+  bool build_complete_hierarchy(SAA_Scene &scene, SAA_Database &database, char **root_name);
+  //  bool build_selected_hierarchy(SAA_Scene *s, SAA_Database *d, char *scene_name);
+
+  int get_num_nodes() const;
+  SoftNodeDesc *get_node(int n) const;
+
+  char *GetName(SAA_Scene *scene, SAA_Elem *element);
+  char *GetFullName(SAA_Scene *scene, SAA_Elem *element);
+
+  void clear_egg(EggData *egg_data, EggGroupNode *egg_root, 
+                 EggGroupNode *skeleton_node);
+  EggGroup *get_egg_group(SoftNodeDesc *node_desc);
+  EggTable *get_egg_table(SoftNodeDesc *node_desc);
+  EggXfmSAnim *get_egg_anim(SoftNodeDesc *node_desc);
+
+  PT(SoftNodeDesc) _root;
+  float _fps;
+
+private:
+
+  EggData *_egg_data;
+  EggGroupNode *_egg_root;
+  EggGroupNode *_skeleton_node;
+
+  SoftNodeDesc *r_build_node(const string &path);
+#if 0
+  typedef pmap<string, SoftNodeDesc *> NodesByPath;
+  NodesByPath _nodes_by_path;
+#endif
+  typedef pvector<SoftNodeDesc *> Nodes;
+  Nodes _nodes;
+};
+
+#endif

+ 1743 - 0
pandatool/src/softegg/softToEggConverter.cxx

@@ -0,0 +1,1743 @@
+// Filename: softToEggConverter.cxx
+// Created by:  masad (25Sep03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2003, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+#include "softToEggConverter.h"
+#include "config_softegg.h"
+#include "softEggGroupUserData.h"
+
+#include "eggData.h"
+#include "eggGroup.h"
+#include "eggTable.h"
+#include "eggVertex.h"
+#include "eggVertexPool.h"
+#include "eggNurbsSurface.h"
+#include "eggNurbsCurve.h"
+#include "eggPolygon.h"
+#include "eggPrimitive.h"
+#include "eggTexture.h"
+#include "eggTextureCollection.h"
+#include "eggXfmSAnim.h"
+#include "string_utils.h"
+#include "dcast.h"
+
+static const int    TEX_PER_MAT = 1;
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SoftToEggConverter::
+SoftToEggConverter(const string &program_name) :
+  _program_name(program_name)
+{
+  _from_selection = false;
+  _polygon_output = false;
+  _polygon_tolerance = 0.01;
+  /*
+  _respect_maya_double_sided = maya_default_double_sided;
+  _always_show_vertex_color = maya_default_vertex_color;
+  */
+  _transform_type = TT_model;
+
+  database_name = NULL;
+  scene_name = NULL;
+  model_name = NULL;
+  animFileName = NULL;
+  eggFileName = NULL;
+  tex_path = NULL;
+  eggGroupName = NULL;
+  tex_filename = NULL;
+  search_prefix = NULL;
+  result = SI_SUCCESS;
+  
+  // skeleton = new EggGroup();
+  foundRoot = FALSE;
+  //  animRoot = NULL;
+  //  morphRoot = NULL;
+  geom_as_joint = 0;
+  make_anim = 0;
+  make_nurbs = 0;
+  make_poly = 0;
+  make_soft = 0;
+  make_morph = 1;
+  make_duv = 1;
+  make_dart = TRUE;
+  has_morph = 0;
+  make_pose = 0;
+  //  animData.is_z_up = FALSE;
+  nurbs_step = 1;
+  anim_start = -1000;
+  anim_end = -1000;
+  anim_rate = 24;
+  pose_frame = -1;
+  verbose = 0;
+  flatten = 0;
+  shift_textures = 0;
+  ignore_tex_offsets = 0;
+  use_prefix = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+
+//     Function: SoftToEggConverter::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SoftToEggConverter::
+SoftToEggConverter(const SoftToEggConverter &copy) :
+  _from_selection(copy._from_selection),
+  /*
+  _maya(copy._maya),
+  */
+  _polygon_output(copy._polygon_output),
+  _polygon_tolerance(copy._polygon_tolerance),
+  /*
+  _respect_maya_double_sided(copy._respect_maya_double_sided),
+  _always_show_vertex_color(copy._always_show_vertex_color),
+  */
+  _transform_type(copy._transform_type)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+SoftToEggConverter::
+~SoftToEggConverter() {
+  /*
+  close_api();
+  */
+}
+////////////////////////////////////////////////////////////////////
+//     Function: Help
+//       Access: Public
+//  Description: Displays the "what is this program" message, along
+//               with the usage message.  Should be overridden in base
+//               classes to describe the current program.
+////////////////////////////////////////////////////////////////////
+void SoftToEggConverter::
+Help() 
+{
+    softegg_cat.info() <<
+      "soft2egg takes a SoftImage scene or model\n"
+      "and outputs its contents as an egg file\n";
+    
+    Usage();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Usage
+//       Access: Public
+//  Description: Displays the usage message.
+////////////////////////////////////////////////////////////////////
+void SoftToEggConverter::
+Usage() {
+  softegg_cat.info()
+    << "\nUsage:\n"
+    //    << _commandName << " [opts] (must specify -m or -s)\n\n"
+    << "soft" << " [opts] (must specify -m or -s)\n\n"
+    << "Options:\n";
+  
+  ShowOpts();
+  softegg_cat.info() << "\n";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ShowOpts
+//       Access: Public
+//  Description: Displays the valid options.  Should be extended in
+//               base classes to show additional options relevant to
+//               the current program.
+////////////////////////////////////////////////////////////////////
+void SoftToEggConverter::
+ShowOpts() 
+{
+  softegg_cat.info() <<
+    "  -r <path>  - Used to provide soft with the resource\n" 
+    "               Defaults to '/ful/ufs/soft371_mips2/3D/rsrc'.\n"
+    "  -d <path>  - Database path.\n"
+    "  -s <scene> - Indicates that a scene will be converted.\n"
+    "  -m <model> - Indicates that a model will be converted.\n"
+    "  -t <path>  - Specify path to place converted textures.\n"
+    "  -T <name>  - Specify filename for texture map listing.\n"
+    "  -S <step>  - Specify step for nurbs surface triangulation.\n"
+    "  -M <name>  - Specify model output filename. Defaults to scene name.\n"
+    "  -A <name>  - Specify anim output filename. Defaults to scene name.\n"
+    "  -N <name>  - Specify egg group name.\n"
+    "  -k         - Enable soft assignment for geometry.\n"
+    "  -n         - Specify egg NURBS representation instead of poly's.\n"
+    "  -p         - Specify egg polygon output for geometry.\n"
+    "  -P <frame> - Specify frame number for static pose.\n"
+    "  -b <frame> - Specify starting frame for animation (default = first).\n"
+    "  -e <frame> - Specify ending frame for animation (default = last).\n"
+    "  -f <fps>   - Specify frame rate for animation playback.\n"
+    "  -a         - Compile animation tables if animation present.\n"
+    "  -F         - Ignore hierarchy and build a completely flat skeleton.\n"
+    "  -v <level> - Set debug level.\n"
+    "  -x         - Shift NURBS parameters to preserve Alias textures.\n"
+    "  -i         - Ignore Soft texture uv offsets.\n"
+    "  -u         - Use Soft prefix in model names.\n"
+    "  -c         - Cancel morph conversion.\n"
+    "  -C         - Cancel duv conversion.\n"
+    "  -D         - Don't make the output model a character.\n"
+    "  -o <prefix>- Convert only models with given prefix.\n";
+
+  //  EggBase::ShowOpts();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DoGetopts
+//       Access: Public
+//  Description: Calls getopt() to parse the command-line switches.
+//               Calls HandleGetopts() to interpret each switch.
+//               Returns true if the parsing was successful; false if
+//               there was an error.  Adjusts argc and argv to remove
+//               the switches from the parameter list.
+////////////////////////////////////////////////////////////////////
+bool SoftToEggConverter::
+DoGetopts(int &argc, char **&argv) {
+  bool okflag = true;
+  int i = 1;
+  softegg_cat.info() << "argc " << argc << "\n";
+  if (argc <2) {
+    Usage();
+    okflag = false;
+  }
+  while ((i < argc-1) && (argv[i][0] == '-') && okflag) {
+    softegg_cat.info() << "arg " << i << " is " << argv[i] << "\n";
+    //    softegg_cat.info() << argv[i] << ", " << argv[i+1];
+    okflag = HandleGetopts(i, argc, argv);
+  }
+  return okflag;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HandleGetopts
+//       Access: Public
+//  Description: increment idx based on what kind of option parsed
+//               Supported options are as follows:
+//               r:d:s:m:t:P:b:e:f:T:S:M:A:N:v:o:FhknpaxiucCD
+////////////////////////////////////////////////////////////////////
+bool SoftToEggConverter::
+HandleGetopts(int &idx, int argc, char **argv) 
+{
+  bool okflag = true;
+
+  char flag = argv[idx][1];    // skip the '-' from option
+  
+  switch (flag) 
+    {
+    case 'r':       // Set the resource path for soft.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        // Get the path.
+        rsrc_path = argv[idx+1];
+        softegg_cat.info() << "using rsrc path " << rsrc_path << "\n";
+      }
+      ++idx;
+      break;
+
+    case 'd':       // Set the database path.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        // Get the path.
+        database_name = argv[idx+1];
+        softegg_cat.info() << "using database " << database_name << "\n";
+      }
+      ++idx;
+      break;
+      
+    case 's':     // Check if its a scene.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        // Get scene name.
+        scene_name = argv[idx+1];
+        softegg_cat.info() << "loading scene " << scene_name << "\n";
+      }
+      ++idx;
+      break;
+      
+    case 'm':     // Check if its a model.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        // Get model name.
+        model_name = argv[idx+1];
+        softegg_cat.info() << "loading model %s\n" <<  model_name;
+      }
+      ++idx;
+      break;
+      
+    case 't':     // Get converted texture path.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        // Get tex path name.
+        tex_path = argv[idx+1];
+        softegg_cat.info() << "texture path:  %s\n" << tex_path;
+      }
+      ++idx;
+      break;
+      
+    case 'T':      // Specify texture list filename. 
+      if ( strcmp( argv[idx+1], "") ) {
+        // Get the name.
+        tex_filename = argv[idx+1];
+        softegg_cat.info() << "creating texture list file: %s\n" << tex_filename;
+      }
+      ++idx;
+      break;
+
+    case 'S':     // Set NURBS step.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        nurbs_step = atoi(argv[idx+1]);
+        softegg_cat.info() << "NURBS step:  %d\n" << nurbs_step;
+      }
+      ++idx;
+      break;
+      
+    case 'M':     // Set model output file name.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        eggFileName = argv[idx+1];
+        softegg_cat.info() << "Model output filename:  %s\n" << eggFileName;
+      }
+      ++idx;
+      break;
+      
+    case 'A':     // Set anim output file name.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        animFileName = argv[idx+1];
+        softegg_cat.info() << "Anim output filename:  %s\n" << animFileName;
+      }
+      ++idx;
+      break;
+      
+    case 'N':     // Set egg model name.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        eggGroupName = argv[idx+1];
+        softegg_cat.info() << "Egg group name:  %s\n" << eggGroupName;
+      }
+      ++idx;
+      break;
+      
+    case 'o':     // Set search_prefix.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        search_prefix = argv[idx+1]; 
+        softegg_cat.info() << "Only converting models with prefix:  %s\n" << search_prefix;
+      }
+      ++idx;
+      break;
+      
+    case 'h':    // print help message
+      Help();
+      exit(1);
+      break;
+      
+    case 'c':    // Cancel morph animation conversion
+      make_morph = FALSE;
+      softegg_cat.info() << "canceling morph conversion\n";
+      break;
+
+    case 'C':    // Cancel uv animation conversion
+      make_duv = FALSE;
+      softegg_cat.info() << "canceling uv animation conversion\n";
+      break;
+      
+    case 'D':    // Omit the Dart flag
+      make_dart = FALSE;
+      softegg_cat.info() << "making a non-character model\n";
+      break;
+      
+    case 'k':    // Enable soft skinning
+      //make_soft = TRUE;
+      //fprintf( outStream, "enabling soft skinning\n" );
+      softegg_cat.info() << "-k flag no longer necessary\n";
+      break;
+      
+    case 'n':    // Generate egg NURBS output
+      make_nurbs = TRUE;
+      softegg_cat.info() << "outputting egg NURBS info\n";
+      break;
+      
+    case 'p':    // Generate egg polygon output
+      make_poly = TRUE;
+      softegg_cat.info() << "outputting egg polygon info\n";
+      break;
+      
+    case 'P':    // Generate static pose from given frame
+      if ( strcmp( argv[idx+1], "" ) ) {
+        make_pose = TRUE;
+        pose_frame = atoi(argv[idx+1]);
+        softegg_cat.info() << "generating static pose from frame %d\n" << pose_frame;
+      }
+      ++idx;
+      break;
+      
+    case 'a':     // Compile animation tables.
+      make_anim = TRUE;
+      softegg_cat.info() << "attempting to compile anim tables\n";
+      break;
+      
+    case 'F':     // Build a flat skeleton.
+      flatten = TRUE;
+      softegg_cat.info() << "building a flat skeleton!!!\n";
+      break;
+      
+    case 'x':     // Shift NURBS parameters to preserve Alias textures.
+      shift_textures = TRUE;
+      softegg_cat.info() << "shifting NURBS parameters...\n";
+      break;
+      
+    case 'i':     // Ignore Soft uv texture offsets 
+      ignore_tex_offsets = TRUE;
+      softegg_cat.info() << "ignoring texture offsets...\n";
+      break;
+      
+    case 'u':     // Use Soft prefix in model names 
+      use_prefix = TRUE;
+      softegg_cat.info() << "using prefix in model names...\n";
+      break;
+      
+      
+    case 'v':     // print debug messages.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        verbose = atoi(argv[idx+1]);
+        softegg_cat.info() << "using debug level %d\n" << verbose;
+      }
+      ++idx;
+      break;
+      
+    case 'b':     // Set animation start frame.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        anim_start = atoi(argv[idx+1]);
+        softegg_cat.info() << "animation starting at frame:  %d\n" << anim_start;
+      }
+      break;
+      
+    case 'e':     /// Set animation end frame.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        anim_end = atoi(argv[idx+1]);
+        softegg_cat.info() << "animation ending at frame:  %d\n" << anim_end;
+      }
+      ++idx;
+      break;
+      
+    case 'f':     /// Set animation frame rate.
+      if ( strcmp( argv[idx+1], "" ) ) {
+        anim_rate = atoi(argv[idx+1]);
+        softegg_cat.info() << "animation frame rate:  %d\n" << anim_rate;
+      }
+      ++idx;
+      break;
+
+    default:
+      softegg_cat.info() << flag << " flag not supported\n";
+      okflag = false;
+    }
+  idx++;
+  return (okflag);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::make_copy
+//       Access: Public, Virtual
+//  Description: Allocates and returns a new copy of the converter.
+////////////////////////////////////////////////////////////////////
+SomethingToEggConverter *SoftToEggConverter::
+make_copy() {
+  return new SoftToEggConverter(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::get_name
+//       Access: Public, Virtual
+//  Description: Returns the English name of the file type this
+//               converter supports.
+////////////////////////////////////////////////////////////////////
+string SoftToEggConverter::
+get_name() const {
+  return "Soft";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::get_extension
+//       Access: Public, Virtual
+//  Description: Returns the common extension of the file type this
+//               converter supports.
+////////////////////////////////////////////////////////////////////
+string SoftToEggConverter::
+get_extension() const {
+  return "mb";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GetTextureName
+//       Access: Public
+//  Description: Given a texture element, return texture name 
+//               with given tex_path
+////////////////////////////////////////////////////////////////////
+char *SoftToEggConverter::
+GetTextureName( SAA_Scene *scene, SAA_Elem *texture ) {
+  char *fileName = new char[_MAX_PATH];
+  char tempName[_MAX_PATH];
+  SAA_texture2DGetPicName( scene, texture, _MAX_PATH, tempName );
+
+  if (tex_path) {
+    //  cout << "tempName :" << tempName << endl;
+    strcpy(fileName, tex_path);
+
+    // do some processing on the name string
+    char *tmpName = NULL;
+    tmpName = strrchr(tempName, '/');
+    if (tmpName)
+      tmpName++;
+    else
+      tmpName = tempName;
+
+    //    cout << "tmpName : " << tmpName << endl;
+    strcat(fileName, "/");
+    strcat(fileName, tmpName);
+  }
+  else {
+    strcpy(fileName, tempName);
+  }
+
+  strcat(fileName, ".pic");
+  //  cout << "fileName : " << fileName << endl;
+
+  return fileName;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GetModelNoteInfo
+//       Access: Public
+//  Description: Given an element, return a string containing the
+//                 contents of its MODEL NOTE entry 
+////////////////////////////////////////////////////////////////////
+char *SoftToEggConverter::
+GetModelNoteInfo( SAA_Scene *scene, SAA_Elem *model ) {
+  int size;
+  char *modelNote = NULL;
+  SAA_Boolean bigEndian;
+
+  SAA_elementGetUserDataSize( scene, model, "MNOT", &size );
+
+  if ( size != 0 ) {
+    // allocate modelNote string
+    modelNote = new char[size + 1];
+    
+    // get ModelNote data from this model
+    SAA_elementGetUserData( scene, model, "MNOT", size, 
+                            &bigEndian, (void *)modelNote );
+    
+    //strip off newline, if present
+    char *eol = strchr( modelNote, '\n' );
+    if ( eol != NULL)
+      *eol = '\0';
+    else
+      modelNote[size] = '\0';
+    
+    cout << "\nmodelNote = " << modelNote << endl;    
+  }
+  
+  return modelNote;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::convert_file
+//       Access: Public, Virtual
+//  Description: Handles the reading of the input file and converting
+//               it to egg.  Returns true if successful, false
+//               otherwise.
+//
+//               This is designed to be as generic as possible,
+//               generally in support of run-time loading.
+//               Also see convert_soft().
+////////////////////////////////////////////////////////////////////
+bool SoftToEggConverter::
+convert_file(const Filename &filename) {
+  if (!open_api()) {
+    softegg_cat.error()
+      << "Soft is not available.\n";
+    return false;
+  }
+  if (_character_name.empty()) {
+    _character_name = filename.get_basename_wo_extension();
+  }
+  return convert_soft(false);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::convert_soft
+//       Access: Public
+//  Description: Fills up the egg_data structure according to the
+//               global soft model data.  Returns true if successful,
+//               false if there is an error.  If from_selection is
+//               true, the converted geometry is based on that which
+//               is selected; otherwise, it is the entire Soft scene.
+////////////////////////////////////////////////////////////////////
+bool SoftToEggConverter::
+convert_soft(bool from_selection) {
+  bool all_ok = true;
+
+  _from_selection = from_selection;
+  _textures.clear();
+
+  EggData egg_data;
+  set_egg_data(&egg_data, false);
+  cout << "eggData " << &get_egg_data() << "\n";
+
+  if (_egg_data->get_coordinate_system() != CS_default) {
+    cout << "coordinate system is not default\n";
+    exit(1);
+  }
+
+  char *temp = NULL;
+  all_ok = _tree.build_complete_hierarchy(scene, database, &temp);
+  if (temp)
+    _character_name = temp;
+
+  if (!convert_char_model()) {
+    all_ok = false;
+  }
+  //  reparent_decals(&get_egg_data());
+  cout << softegg_cat.info() << "Converted Softimage file\n";
+
+  // write out the egg file
+  _egg_data->write_egg(Filename(eggFileName));
+  cout << softegg_cat.info() << "Write Egg file\n";
+
+  /*
+  _shaders.clear();
+
+  if (!open_api()) {
+    softegg_cat.error()
+      << "Soft is not available.\n";
+    return false;
+  }
+
+  if (_egg_data->get_coordinate_system() == CS_default) {
+    _egg_data->set_coordinate_system(_maya->get_coordinate_system());
+  }
+
+  softegg_cat.info()
+    << "Converting from Soft.\n";
+
+  // Figure out the animation parameters.
+  double start_frame, end_frame, frame_inc, input_frame_rate, output_frame_rate;
+  if (has_start_frame()) {
+    start_frame = get_start_frame();
+  } else {
+    start_frame = MAnimControl::minTime().value();
+  }
+  if (has_end_frame()) {
+    end_frame = get_end_frame();
+  } else {
+    end_frame = MAnimControl::maxTime().value();
+  }
+  if (has_frame_inc()) {
+    frame_inc = get_frame_inc();
+  } else {
+    frame_inc = 1.0;
+  }
+  if (has_input_frame_rate()) {
+    input_frame_rate = get_input_frame_rate();
+  } else {
+    MTime time(1.0, MTime::kSeconds);
+    input_frame_rate = time.as(MTime::uiUnit());
+  }
+  if (has_output_frame_rate()) {
+    output_frame_rate = get_output_frame_rate();
+  } else {
+    output_frame_rate = input_frame_rate;
+  }
+
+  bool all_ok = true;
+
+  if (_from_selection) {
+    all_ok = _tree.build_selected_hierarchy();
+  } else {
+    all_ok = _tree.build_complete_hierarchy();
+  }
+
+  if (all_ok) {
+    switch (get_animation_convert()) {
+    case AC_pose:
+      // pose: set to a specific frame, then get out the static geometry.
+      softegg_cat.info(false)
+        << "frame " << start_frame << "\n";
+      MGlobal::viewFrame(MTime(start_frame, MTime::uiUnit()));
+      // fall through
+      
+    case AC_none:
+      // none: just get out a static model, no animation.
+      all_ok = convert_hierarchy(&get_egg_data());
+      break;
+      
+    case AC_flip:
+    case AC_strobe:
+      // flip or strobe: get out a series of static models, one per
+      // frame, under a sequence node for AC_flip.
+      all_ok = convert_flip(start_frame, end_frame, frame_inc,
+                            output_frame_rate);
+      break;
+
+    case AC_model:
+      // model: get out an animatable model with joints and vertex
+      // membership.
+      all_ok = convert_char_model();
+      break;
+
+    case AC_chan:
+      // chan: get out a series of animation tables.
+      all_ok = convert_char_chan(start_frame, end_frame, frame_inc,
+                                 output_frame_rate);
+      break;
+      
+    case AC_both:
+      // both: Put a model and its animation into the same egg file.
+      _animation_convert = AC_model;
+      if (!convert_char_model()) {
+        all_ok = false;
+      }
+      _animation_convert = AC_chan;
+      if (!convert_char_chan(start_frame, end_frame, frame_inc,
+                             output_frame_rate)) {
+        all_ok = false;
+      }
+      break;
+    };
+
+    reparent_decals(&get_egg_data());
+  }
+  if (all_ok) {
+    softegg_cat.info()
+      << "Converted, no errors.\n";
+  } else {
+    softegg_cat.info()
+      << "Errors encountered in conversion.\n";
+  }
+  */
+  return all_ok;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::open_api
+//       Access: Public
+//  Description: Attempts to open the Soft API if it was not already
+//               open, and returns true if successful, or false if
+//               there is an error.
+////////////////////////////////////////////////////////////////////
+bool SoftToEggConverter::
+open_api() {
+  if ((scene_name == NULL && model_name == NULL) || database_name == NULL) {
+    Usage();
+    exit( 1 );
+  }
+  if ((result = SAA_Init(rsrc_path, FALSE)) != SI_SUCCESS) {
+    softegg_cat.info() << "Error: Couldn't get resource path!\n";
+    exit( 1 );
+  }
+  if ((result = SAA_databaseLoad(database_name, &database)) != SI_SUCCESS) {
+    softegg_cat.info() << "Error: Couldn't load database!\n";
+    exit( 1 );
+  }
+  if ((result = SAA_sceneGetCurrent(&scene)) != SI_SUCCESS) {
+    softegg_cat.info() << "Error: Couldn't get current scene!\n";
+    exit( 1 );
+  }
+  if ((result = SAA_sceneLoad( &database, scene_name, &scene )) != SI_SUCCESS) {
+    softegg_cat.info() << "Error: Couldn't load scene " << scene_name << "!\n";
+    exit( 1 );
+  }
+  // if no egg filename specified, make up a name
+  if ( eggFileName == NULL ) {
+    string madeName;
+    string tempName(scene_name);
+    string::size_type end = tempName.find(".dsc");
+    if (end != string::npos) {
+      madeName.assign(tempName.substr(0,end));
+      if ( make_nurbs )
+        madeName.insert(madeName.size(), "-nurb");
+      madeName.insert(madeName.size(), ".egg" );
+    }
+    eggFileName = new char[madeName.size()+1];
+    strcpy(eggFileName, madeName.c_str());
+  }
+  
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::close_api
+//       Access: Public
+//  Description: Closes the Soft API, if it was previously opened.
+//               Caution!  Soft appears to call exit() when its API is
+//               closed.
+////////////////////////////////////////////////////////////////////
+void SoftToEggConverter::
+close_api() {
+  // don't know yet
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::convert_char_model
+//       Access: Private
+//  Description: Converts the file as an animatable character
+//               model, with joints and vertex membership.
+////////////////////////////////////////////////////////////////////
+bool SoftToEggConverter::
+convert_char_model() {
+#if 0
+  if (has_neutral_frame()) {
+    MTime frame(get_neutral_frame(), MTime::uiUnit());
+    softegg_cat.info(false)
+      << "neutral frame " << frame.value() << "\n";
+    MGlobal::viewFrame(frame);
+  }
+#endif
+  cout << "character name " << _character_name << "\n";
+  EggGroup *char_node = new EggGroup(_character_name);
+  get_egg_data().add_child(char_node);
+  char_node->set_dart_type(EggGroup::DT_default);
+
+  return convert_hierarchy(char_node);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::convert_hierarchy
+//       Access: Private
+//  Description: Generates egg structures for each node in the Soft
+//               hierarchy.
+////////////////////////////////////////////////////////////////////
+bool SoftToEggConverter::
+convert_hierarchy(EggGroupNode *egg_root) {
+  int num_nodes = _tree.get_num_nodes();
+
+  _tree.clear_egg(&get_egg_data(), egg_root, NULL);
+  for (int i = 0; i < num_nodes; i++) {
+    if (!process_model_node(_tree.get_node(i))) {
+      return false;
+    }
+  }
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::process_model_node
+//       Access: Private
+//  Description: Converts the indicated Soft node (given a MDagPath,
+//               similar in concept to Panda's NodePath) to the
+//               corresponding Egg structure.  Returns true if
+//               successful, false if an error was encountered.
+////////////////////////////////////////////////////////////////////
+bool SoftToEggConverter::
+process_model_node(SoftNodeDesc *node_desc) {
+  SAA_ModelType type;
+  char *name = NULL;
+  char *fullname = NULL;
+  EggGroup *egg_group = NULL;
+
+  // Get the name of the model
+  if ( use_prefix ) {
+    // Get the FULL name of the model
+    name = fullname = _tree.GetFullName( &scene, node_desc->get_model() );
+  }
+  else {
+    // Get the name of the trim curve
+    name = _tree.GetName( &scene, node_desc->get_model() );
+  }
+  cout << "element name <" << name << ">\n";
+
+  // find out what type of node we're dealing with
+  result = SAA_modelGetType( &scene, node_desc->get_model(), &type );
+  cout << "encountered ";
+  switch(type){
+  case SAA_MNILL:
+    cout << "null\n";
+    break;
+  case SAA_MPTCH:
+    cout << "patch\n";
+    break;
+  case SAA_MFACE:
+    cout << "face\n";
+    break;
+  case SAA_MSMSH:
+    cout << "mesh\n";
+    egg_group = _tree.get_egg_group(node_desc);
+    get_transform(node_desc, egg_group);
+    make_polyset(node_desc->get_model(), egg_group, type, name);
+    break;
+  case SAA_MJNT:
+    cout << "joint\n";
+    break;
+  case SAA_MSPLN:
+    cout << "spline\n";
+    break;
+  case SAA_MMETA:
+    cout << "meta element\n";
+    break;
+  case SAA_MBALL:
+    cout << "meta ball\n";
+    break;
+  case SAA_MNCRV:
+    cout << "nurbs curve\n";
+    break;
+  case SAA_MNSRF:
+    cout << "nurbs surf\n";
+    break;
+  default:
+    cout << "unknown type: " << type << "\n";
+  }
+
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::get_transform
+//       Access: Private
+//  Description: Extracts the transform on the indicated Soft node,
+//               and applies it to the corresponding Egg node.
+////////////////////////////////////////////////////////////////////
+void SoftToEggConverter::
+get_transform(SoftNodeDesc *node_desc, EggGroup *egg_group) {
+  // Get the model's matrix
+  SAA_modelGetMatrix( &scene, node_desc->get_model(), SAA_COORDSYS_GLOBAL,  matrix );
+
+  cout << "model matrix = " << matrix[0][0] << " " << matrix[0][1] << " " << matrix[0][2] << " " << matrix[0][3] << "\n";
+  cout << "model matrix = " << matrix[1][0] << " " << matrix[1][1] << " " << matrix[1][2] << " " << matrix[1][3] << "\n";
+  cout << "model matrix = " << matrix[2][0] << " " << matrix[2][1] << " " << matrix[2][2] << " " << matrix[2][3] << "\n";
+  cout << "model matrix = " << matrix[3][0] << " " << matrix[3][1] << " " << matrix[3][2] << " " << matrix[3][3] << "\n";
+
+  LMatrix4d m4d(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3],
+                matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3],
+                matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3],
+                matrix[3][0], matrix[3][1], matrix[3][2], matrix[3][3]);
+  if (!m4d.almost_equal(LMatrix4d::ident_mat(), 0.0001)) {
+    egg_group->add_matrix(m4d);
+    cout << "added matrix in egg_group\n";
+  }
+  return;
+}
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::make_polyset
+//       Access: Private
+//  Description: Converts the indicated Soft polyset to a bunch of
+//               EggPolygons and parents them to the indicated egg
+//               group.
+////////////////////////////////////////////////////////////////////
+void SoftToEggConverter::
+make_polyset(SAA_Elem *model, EggGroup *egg_group, SAA_ModelType type, char *node_name) {
+  string name = node_name;
+  int id = 0;
+  int numTri;
+  int numShapes;
+  int numTexLoc = 0;
+  int numTexGlb = 0;
+
+  float *uScale = NULL; 
+  float *vScale = NULL;
+  float *uOffset = NULL;
+  float *vOffset = NULL;
+  float *uCoords = NULL;
+  float *vCoords = NULL;
+  
+  SAA_Boolean valid;
+  SAA_Boolean uv_swap;
+  SAA_Boolean visible;
+  SAA_Elem *textures = NULL;
+  SAA_Elem *materials = NULL;
+  SAA_SubElem *triangles = NULL;
+  SAA_GeomType gtype = SAA_GEOM_ORIGINAL;
+
+  int i, idx;
+  
+  // Get the number of key shapes
+  SAA_modelGetNbShapes( &scene, model, &numShapes );
+  cout << "make_polyset: num shapes: " << numShapes << "\n";
+
+  SAA_modelGetNodeVisibility( &scene, model, &visible ); 
+  cout << "model visibility: " << visible << "\n";
+
+  ///////////////////////////////////////////////////////////////////////
+  // Only create egg polygon data if: the node is visible, and its not
+  // a NULL or a Joint, and we're outputing polys (or if we are outputing 
+  // NURBS and the model is a poly mesh or a face) 
+  ///////////////////////////////////////////////////////////////////////
+  if ( visible &&  
+       (type != SAA_MNILL) &&
+       (type != SAA_MJNT) && 
+       ((make_poly || 
+         (make_nurbs && ((type == SAA_MSMSH) || (type == SAA_MFACE )) )) ||
+        (!make_poly && !make_nurbs && make_duv && 
+         ((type == SAA_MSMSH) || (type == SAA_MFACE )) ))
+       )
+    {
+      // If the model is a NURBS in soft, set its step before tesselating
+      if ( type == SAA_MNSRF )
+        SAA_nurbsSurfaceSetStep( &scene, model, nurbs_step, nurbs_step );
+
+      // If the model is a PATCH in soft, set its step before tesselating
+      else if ( type == SAA_MPTCH )
+        SAA_patchSetStep( &scene, model, nurbs_step, nurbs_step );
+ 
+      // Get the number of triangles    
+      result = SAA_modelGetNbTriangles( &scene, model, gtype, id, &numTri);
+      cout << "triangles: " << numTri << "\n";
+
+      if ( result != SI_SUCCESS ) {
+        cout << "Error: couldn't get number of triangles!\n";
+        cout << "\tbailing on model: " << name << "\n";
+        return;    
+      }
+
+      // check to see if surface is also skeleton...
+      SAA_Boolean isSkeleton = FALSE;
+      
+      SAA_modelIsSkeleton( &scene, model, &isSkeleton );
+
+      // check to see if this surface is used as a skeleton
+      // or is animated via constraint only ( these nodes are
+      // tagged by the animator with the keyword "joint"
+      // somewhere in the nodes name)
+      cout << "is Skeleton? " << isSkeleton << "\n";
+
+      /*************************************************************************************/
+
+      // model is not a null and has no triangles!
+      if ( !numTri ) {
+        cout << "no triangles!\n";
+      }
+      else {
+        // allocate array of triangles
+        triangles = (SAA_SubElem *) new SAA_SubElem[numTri];
+        if (!triangles) {
+          cout << "Not enough Memory for triangles...\n";
+          exit(1);
+        }
+        // triangulate model and read the triangles into array
+        SAA_modelGetTriangles( &scene, model, gtype, id, numTri, triangles );
+        cout << "got triangles\n";
+
+        /***********************************************************************************/
+        
+        // allocate array of materials (Asad: it gives a warning if try top get one triangle
+        //                                    at a time...investigate later
+        // read each triangle's material into array  
+        materials = (SAA_Elem*) new SAA_Elem[numTri];
+        SAA_triangleGetMaterials( &scene, model, numTri, triangles, materials );
+        if (!materials) {
+          cout << "Not enough Memory for materials...\n";
+          exit(1);
+        }
+        cout << "got materials\n";
+        
+        /***********************************************************************************/
+        
+        // allocate array of textures per triangle
+        int *numTexTri = new int[numTri];
+        const void *relinfo;
+        
+        // find out how many local textures per triangle
+        for (i = 0; i < numTri; i++) {    
+          result = SAA_materialRelationGetT2DLocNbElements( &scene, &materials[i], FALSE, 
+                                                            &relinfo, &numTexTri[i] );
+          // polytex    
+          if ( result == SI_SUCCESS )
+            numTexLoc += numTexTri[i];
+        }
+        
+        // don't need this anymore...
+        //free( numTexTri ); 
+        
+        // get local textures if present
+        if ( numTexLoc ) {
+          cout << "numTexLoc = " << numTexLoc << endl;
+
+          // allocate arrays of texture info
+          uScale = new float[numTri];
+          vScale = new float[numTri];
+          uOffset = new float[numTri];
+          vOffset = new float[numTri];
+          texNameArray = new char *[numTri];
+
+          // ASSUME only one texture per material
+          textures = new SAA_Elem[numTri];
+
+          for ( i = 0; i < numTri; i++ ) {
+            // and read all referenced local textures into array
+            SAA_materialRelationGetT2DLocElements( &scene, &materials[i],
+                                                   TEX_PER_MAT , &textures[i] );
+            // initialize the array value
+            texNameArray[i] = NULL;
+
+            // check to see if texture is present
+            result = SAA_elementIsValid( &scene, &textures[i], &valid );
+               
+            if ( result != SI_SUCCESS )
+              cout << "SAA_elementIsValid failed!!!!\n";
+ 
+            // texture present - get the name and uv info 
+            if ( valid ) {
+              // according to drose, we don't need to convert .pic files to .rgb,
+              // panda can now read the .pic files.
+              texNameArray[i] = GetTextureName(&scene, &textures[i]);
+             
+              cout << " tritex[" << i << "] named: " << texNameArray[i] << endl;
+
+              SAA_texture2DGetUVSwap( &scene, &textures[i], &uv_swap );
+
+              if ( uv_swap == TRUE )
+                cout << " swapping u and v...\n" ;
+
+              SAA_texture2DGetUScale( &scene, &textures[i], &uScale[i] );
+              SAA_texture2DGetVScale( &scene, &textures[i], &vScale[i] );
+              SAA_texture2DGetUOffset( &scene, &textures[i], &uOffset[i] );
+              SAA_texture2DGetVOffset( &scene, &textures[i], &vOffset[i] );
+
+              cout << "tritex[" << i << "] uScale: " << uScale[i] << " vScale: " << vScale[i] << endl;
+              cout << " uOffset: " << uOffset[i] << " vOffset: " << vOffset[i] << endl;
+              
+              SAA_texture2DGetRepeats( &scene, &textures[i], &uRepeat, &vRepeat );
+              cout << "uRepeat = " << uRepeat << ", vRepeat = " << vRepeat << endl;
+            }
+            else {
+              cout << "Invalid texture...\n";
+              cout << " tritex[" << i << "] named: (null)\n";
+            }
+          }
+        }
+        else { // if no local textures, try to get global textures
+          SAA_modelRelationGetT2DGlbNbElements( &scene, model,
+                                                FALSE, &relinfo, &numTexGlb );
+          if ( numTexGlb ) {
+            // ASSUME only one texture per model
+            textures = new SAA_Elem;
+            // get the referenced texture
+            SAA_modelRelationGetT2DGlbElements( &scene, model, 
+                                                TEX_PER_MAT, textures ); 
+            cout << "numTexGlb = " << numTexGlb << endl;
+            // check to see if texture is present
+            SAA_elementIsValid( &scene, textures, &valid );
+            if ( valid ) {  // texture present - get the name and uv info 
+              SAA_texture2DGetUVSwap( &scene, textures, &uv_swap );
+              
+              if ( uv_swap == TRUE )
+                cout << " swapping u and v...\n";
+            
+              // according to drose, we don't need to convert .pic files to .rgb,
+              // panda can now read the .pic files.
+              texNameArray = new char *[1];
+              *texNameArray = GetTextureName(&scene, textures);
+              
+              cout << " global tex named: " << *texNameArray << endl;
+              
+              // allocate arrays of texture info
+              uScale = new float;
+              vScale = new float;
+              uOffset = new float;
+              vOffset = new float;
+              
+              SAA_texture2DGetUScale( &scene, textures, uScale );
+              SAA_texture2DGetVScale( &scene, textures, vScale );
+              SAA_texture2DGetUOffset( &scene, textures, uOffset );
+              SAA_texture2DGetVOffset( &scene, textures, vOffset );
+              
+              cout << " global tex uScale: " << *uScale << " vScale: " << *vScale << endl;
+              cout << "            uOffset: " << *uOffset << " vOffset: " << *vOffset << endl;
+              
+              SAA_texture2DGetRepeats(  &scene, textures, &uRepeat, &vRepeat );
+              cout << "uRepeat = " << uRepeat << ", vRepeat = " << vRepeat << endl;
+            }
+            else {
+              cout << "Invalid Texture...\n";
+            }
+          }
+        }
+      }
+      cout << "got textures" << endl;
+  /***************************************************************************************/
+  
+      string vpool_name = name + ".verts";
+      EggVertexPool *vpool = new EggVertexPool(vpool_name);
+      egg_group->add_child(vpool);
+      
+      // little detour...bear with me for now...TODO: move these to a new function
+      
+      // We will need to transform all vertices from world coordinate
+      // space into the vertex space appropriate to this node.  Usually,
+      // this is the same thing as world coordinate space, and this matrix
+      // will be identity; but if the node is under an instance
+      // (particularly, for instance, a billboard) then the vertex space
+      // will be different from world space.
+      LMatrix4d vertex_frame_inv = egg_group->get_vertex_frame_inv();
+      
+      // Asad: change from soft2egg.c. Here I am trying to get one triangles vertices not all
+      for (idx=0; idx<numTri; ++idx) {
+        EggPolygon *egg_poly = new EggPolygon;
+        egg_group->add_child(egg_poly);
+        
+        // Is this a double sided polygon? meaning check for back face flag
+        char *modelNoteStr = GetModelNoteInfo( &scene, model );
+        if ( modelNoteStr != NULL ) {
+          if ( strstr( modelNoteStr, "bface" ) != NULL )
+            egg_poly->set_bface_flag(TRUE);
+        }
+        
+        // read each triangle's control vertices into array
+        SAA_SubElem cvertices[3];
+        SAA_triangleGetCtrlVertices( &scene, model, gtype, id, 1, triangles+idx, cvertices );
+        
+        // read control vertices in this triangle
+        SAA_DVector cvertPos[3];
+        SAA_ctrlVertexGetPositions( &scene, model, 3, cvertices, cvertPos);
+        
+        // read indices of each vertices in this triangle
+        int indices[3];
+        indices[0] = indices[1] = indices[2] = 0;
+        SAA_ctrlVertexGetIndices( &scene, model, 3, cvertices, indices );
+        
+        // read each control vertex's normals into an array
+        SAA_DVector normals[3];
+        SAA_ctrlVertexGetNormals( &scene, model, 3, cvertices, normals );
+        for (i=0; i<3; ++i)
+          cout << "normals[" << i <<"] = " << normals[i].x << " " <<  normals[i].y
+               << " " << normals[i].z << " " <<  normals[i].w << "\n";
+        
+        // allocate arrays for u & v coords
+        if (textures) {
+          if (numTexLoc) {
+            // allocate arrays for u & v coords
+            // I think there are one texture per triangle hence we need only 3 corrdinates
+            uCoords = new float[3];
+            vCoords = new float[3];
+            
+            // read the u & v coords into the arrays
+            if ( uCoords != NULL && vCoords != NULL) {
+              for ( i = 0; i < 3; i++ )
+                uCoords[i] = vCoords[i] = 0.0f;
+              
+              // TODO: investigate the coord_cnt parameter...
+              SAA_ctrlVertexGetUVTxtCoords( &scene, model, 3, cvertices,
+                                            3, uCoords, vCoords );
+            }
+            else
+              cout << "Not enough Memory for texture coords...\n";
+            
+#if 1
+            for ( i=0; i<3; i++ )
+              cout << "texcoords[" << i << "] = ( " << uCoords[i] << " , " << vCoords[i] <<" )\n";
+#endif
+          }
+          else if (numTexGlb) {
+            // allocate arrays for u & v coords
+            uCoords = new float[numTexGlb*3];
+            vCoords = new float[numTexGlb*3];
+            
+            for ( i = 0; i < numTexGlb*3; i++ ) {
+              uCoords[i] = vCoords[i] = 0.0f;
+            }                
+            
+            // read the u & v coords into the arrays
+            if ( uCoords != NULL && vCoords != NULL) {
+              SAA_triCtrlVertexGetGlobalUVTxtCoords( &scene, model, 3, cvertices, 
+                                                     numTexGlb, textures, uCoords, vCoords );
+            }
+            else
+              cout << "Not enough Memory for texture coords...\n";
+          }
+        }
+        
+        for ( i=0; i < 3; i++ ) {
+          EggVertex vert;
+          
+          // There are some conversions needed from local matrix to global coords
+          SAA_DVector local = cvertPos[i];
+          SAA_DVector global = {0};
+          
+          _VCT_X_MAT( global, local, matrix );
+          
+          cout << "indices[" << i << "] = " << indices[i] << "\n";
+          cout << "cvert[" << i << "] = " << cvertPos[i].x << " " << cvertPos[i].y
+               << " " << cvertPos[i].z << " " << cvertPos[i].w << "\n";
+          cout << " global cvert[" << i << "] = " << global.x << " " << global.y
+               << " " << global.z << " " << global.w << "\n";
+          
+          //      LPoint3d p3d(cvertPos[i].x, cvertPos[i].y, cvertPos[i].z);
+          LPoint3d p3d(global.x, global.y, global.z);
+          p3d = p3d * vertex_frame_inv;
+          vert.set_pos(p3d);
+          
+          local = normals[i];
+          _VCT_X_MAT( global, local, matrix );
+          
+          cout << "normals[" << i <<"] = " << normals[i].x << " " <<  normals[i].y
+               << " " << normals[i].z << " " <<  normals[i].w << "\n";
+          cout << " global normals[" << i <<"] = " << global.x << " " <<  global.y
+               << " " << global.z << " " <<  global.w << "\n";
+          
+          LVector3d n3d(global.x, global.y, global.z);
+          n3d = n3d * vertex_frame_inv;
+          vert.set_normal(n3d);
+          
+          // check to see if material is present
+          float r,g,b,a;
+          SAA_elementIsValid( &scene, &materials[idx/3], &valid );
+          // material present - get the color 
+          if ( valid ) {
+            SAA_materialGetDiffuse( &scene, &materials[idx/3], &r, &g, &b );
+            SAA_materialGetTransparency( &scene, &materials[idx/3], &a );
+            vert.set_color(Colorf(r, g, b, 1.0));
+            cout << "color r = " << r << " g = " << g << " b = " << b << " a = " << a << "\n";
+          }
+          else {     // no material - default to white
+            vert.set_color(Colorf(1.0, 1.0, 1.0, 1.0));
+            cout << "default color\n";
+          }
+          
+          // if texture present set the texture coordinates
+          if (textures) {
+            float u, v;
+            
+            u = uCoords[i];
+            v = 1.0f - vCoords[i];
+            cout << "texcoords[" << i << "] = " << u << " " 
+                 << v << endl;
+            
+            vert.set_uv(TexCoordd(u, v));
+            //        vert.set_uv(TexCoordd(uCoords[i], vCoords[i]));
+          }
+          vert.set_external_index(indices[i]);
+          egg_poly->add_vertex(vpool->create_unique_vertex(vert));
+          cout << "\n";
+        }
+        
+        // Now apply the shader.
+        if (textures != NULL) {
+          if (numTexLoc)
+            set_shader_attributes(*egg_poly, textures[idx]);
+          else
+            set_shader_attributes(*egg_poly, textures[0]);
+        }
+      }
+#if 0
+  come back to it later
+  // Now that we've added all the polygons (and created all the
+  // vertices), go back through the vertex pool and set up the
+  // appropriate joint membership for each of the vertices.
+  bool got_weights = false;
+
+  pvector<EggGroup *> joints;
+  MFloatArray weights;
+  if (_animation_convert == AC_model) {
+    got_weights = 
+      get_vertex_weights(dag_path, mesh, joints, weights);
+  }
+
+  if (got_weights && !joints.empty()) {
+    int num_joints = joints.size();
+    int num_weights = (int)weights.length();
+    int num_verts = num_weights / num_joints;
+    // The number of weights should be an even multiple of verts *
+    // joints.
+    nassertv(num_weights == num_verts * num_joints);
+
+    EggVertexPool::iterator vi;
+    for (vi = vpool->begin(); vi != vpool->end(); ++vi) {
+      EggVertex *vert = (*vi);
+      int maya_vi = vert->get_external_index();
+      nassertv(maya_vi >= 0 && maya_vi < num_verts);
+
+      for (int ji = 0; ji < num_joints; ++ji) {
+        float weight = weights[maya_vi * num_joints + ji];
+        if (weight != 0.0f) {
+          EggGroup *joint = joints[ji];
+          if (joint != (EggGroup *)NULL) {
+            joint->ref_vertex(vert, weight);
+          }
+        }
+      }
+    }
+  }
+#endif
+    }
+}
+#if 0
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::make_locator
+//       Access: Private
+//  Description: Locators are used in Soft to indicate a particular
+//               position in space to the user or the modeler.  We
+//               represent that in egg with an ordinary Group node,
+//               which we transform by the locator's position, so that
+//               the indicated point becomes the origin at this node
+//               and below.
+////////////////////////////////////////////////////////////////////
+void SoftToEggConverter::
+make_locator(const MDagPath &dag_path, const MFnDagNode &dag_node,
+             EggGroup *egg_group) {
+  MStatus status;
+
+  unsigned int num_children = dag_node.childCount();
+  MObject locator;
+  bool found_locator = false;
+  for (unsigned int ci = 0; ci < num_children && !found_locator; ci++) {
+    locator = dag_node.child(ci);
+    found_locator = (locator.apiType() == MFn::kLocator);
+  }
+
+  if (!found_locator) {
+    softegg_cat.error()
+      << "Couldn't find locator within locator node " 
+      << dag_path.fullPathName().asChar() << "\n";
+    return;
+  }
+
+  LPoint3d p3d;
+  if (!get_vec3d_attribute(locator, "localPosition", p3d)) {
+    softegg_cat.error()
+      << "Couldn't get position of locator " 
+      << dag_path.fullPathName().asChar() << "\n";
+    return;
+  }
+
+  // We need to convert the position to world coordinates.  For some
+  // reason, Soft can only tell it to us in local coordinates.
+  MMatrix mat = dag_path.inclusiveMatrix(&status);
+  if (!status) {
+    status.perror("Can't get coordinate space for locator");
+    return;
+  }
+  LMatrix4d n2w(mat[0][0], mat[0][1], mat[0][2], mat[0][3],
+                mat[1][0], mat[1][1], mat[1][2], mat[1][3],
+                mat[2][0], mat[2][1], mat[2][2], mat[2][3],
+                mat[3][0], mat[3][1], mat[3][2], mat[3][3]);
+  p3d = p3d * n2w;
+
+  // Now convert the locator point into the group's space.
+  p3d = p3d * egg_group->get_node_frame_inv();
+
+  egg_group->add_translate(p3d);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftToEggConverter::get_vertex_weights
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+bool SoftToEggConverter::
+get_vertex_weights(const MDagPath &dag_path, const MFnMesh &mesh,
+                   pvector<EggGroup *> &joints, MFloatArray &weights) {
+  MStatus status;
+  
+  // Since we are working with a mesh the input attribute that 
+  // creates the mesh is named "inMesh" 
+  // 
+  MObject attr = mesh.attribute("inMesh"); 
+  
+  // Create the plug to the "inMesh" attribute then use the 
+  // DG iterator to walk through the DG, at the node level.
+  // 
+  MPlug history(mesh.object(), attr); 
+  MItDependencyGraph it(history, MFn::kDependencyNode, 
+                        MItDependencyGraph::kUpstream, 
+                        MItDependencyGraph::kDepthFirst, 
+                        MItDependencyGraph::kNodeLevel);
+
+  while (!it.isDone()) {
+    // We will walk along the node level of the DG until we 
+    // spot a skinCluster node.
+    // 
+    MObject c_node = it.thisNode(); 
+    if (c_node.hasFn(MFn::kSkinClusterFilter)) { 
+      // We've found the cluster handle. Try to get the weight
+      // data.
+      // 
+      MFnSkinCluster cluster(c_node, &status); 
+      if (!status) {
+        status.perror("MFnSkinCluster constructor");
+        return false;
+      }
+
+      // Get the set of objects that influence the vertices of this
+      // mesh.  Hopefully these will all be joints.
+      MDagPathArray influence_objects;
+      cluster.influenceObjects(influence_objects, &status); 
+      if (!status) {
+        status.perror("MFnSkinCluster::influenceObjects");
+
+      } else {
+        // Fill up the vector with the corresponding table of egg
+        // groups for each joint.
+        joints.clear();
+        for (unsigned oi = 0; oi < influence_objects.length(); oi++) {
+          MDagPath joint_dag_path = influence_objects[oi];
+          SoftNodeDesc *joint_node_desc = _tree.build_node(joint_dag_path);
+          EggGroup *joint = _tree.get_egg_group(joint_node_desc);
+          joints.push_back(joint);
+        }
+
+        // Now use a component object to retrieve all of the weight
+        // data in one API call.
+        MFnSingleIndexedComponent sic; 
+        MObject sic_object = sic.create(MFn::kMeshVertComponent); 
+        sic.setCompleteData(mesh.numVertices()); 
+        unsigned influence_count; 
+
+        status = cluster.getWeights(dag_path, sic_object, 
+                                    weights, influence_count); 
+        if (!status) {
+          status.perror("MFnSkinCluster::getWeights");
+        } else {
+          if (influence_count != influence_objects.length()) {
+            softegg_cat.error()
+              << "MFnSkinCluster::influenceObjects() returns " 
+              << influence_objects.length()
+              << " objects, but MFnSkinCluster::getWeights() reports "
+              << influence_count << " objects.\n";
+            
+          } else {
+            // We've got the weights and the set of objects.  That's all
+            // we need.
+            return true;
+          }
+        }
+      }
+    }
+
+    it.next();
+  }
+  
+  softegg_cat.error()
+    << "Unable to find a cluster handle for the DG node.\n"; 
+  return false;
+}
+#endif
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftShader::set_shader_attributes
+//       Access: Private
+//  Description: Applies the known shader attributes to the indicated
+//               egg primitive.
+////////////////////////////////////////////////////////////////////
+void SoftToEggConverter::
+set_shader_attributes(EggPrimitive &primitive, SAA_Elem &shader) {
+  EggTexture tex(*texNameArray, "");
+
+  Filename filename = Filename::from_os_specific(*texNameArray);
+  Filename fullpath = _path_replace->match_path(filename, get_texture_path());
+  tex.set_filename(_path_replace->store_path(fullpath));
+  tex.set_fullpath(fullpath);
+  //  tex.set_format(EggTexture::F_rgb);
+  apply_texture_properties(tex);
+
+  EggTexture *new_tex = _textures.create_unique_texture(tex, ~EggTexture::E_tref_name);
+  primitive.set_texture(new_tex);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftShader::apply_texture_properties
+//       Access: Private
+//  Description: Applies all the appropriate texture properties to the
+//               EggTexture object, including wrap modes and texture
+//               matrix.
+////////////////////////////////////////////////////////////////////
+void SoftToEggConverter::
+apply_texture_properties(EggTexture &tex) {
+  // Let's mipmap all textures by default.
+  tex.set_minfilter(EggTexture::FT_linear_mipmap_linear);
+  tex.set_magfilter(EggTexture::FT_linear);
+
+  EggTexture::WrapMode wrap_u = uRepeat > 0 ? EggTexture::WM_repeat : EggTexture::WM_clamp;
+  EggTexture::WrapMode wrap_v = vRepeat > 0 ? EggTexture::WM_repeat : EggTexture::WM_clamp;
+
+  tex.set_wrap_u(wrap_u);
+  tex.set_wrap_v(wrap_v);
+  /*  
+  LMatrix3d mat = color_def.compute_texture_matrix();
+  if (!mat.almost_equal(LMatrix3d::ident_mat())) {
+    tex.set_transform(mat);
+  }
+  */
+}
+#if 0
+////////////////////////////////////////////////////////////////////
+//     Function: SoftShader::compare_texture_properties
+//       Access: Private
+//  Description: Compares the texture properties already on the
+//               texture (presumably set by a previous call to
+//               apply_texture_properties()) and returns false if they
+//               differ from that specified by the indicated color_def
+//               object, or true if they match.
+////////////////////////////////////////////////////////////////////
+bool SoftToEggConverter::
+compare_texture_properties(EggTexture &tex, 
+                           const SoftShaderColorDef &color_def) {
+  bool okflag = true;
+
+  EggTexture::WrapMode wrap_u = color_def._wrap_u ? EggTexture::WM_repeat : EggTexture::WM_clamp;
+  EggTexture::WrapMode wrap_v = color_def._wrap_v ? EggTexture::WM_repeat : EggTexture::WM_clamp;
+  
+  if (wrap_u != tex.determine_wrap_u()) {
+    // Choose the more general of the two.
+    if (wrap_u == EggTexture::WM_repeat) {
+      tex.set_wrap_u(wrap_u);
+    }
+    okflag = false;
+  }
+  if (wrap_v != tex.determine_wrap_v()) {
+    if (wrap_v == EggTexture::WM_repeat) {
+      tex.set_wrap_v(wrap_v);
+    }
+    okflag = false;
+  }
+  
+  LMatrix3d mat = color_def.compute_texture_matrix();
+  if (!mat.almost_equal(tex.get_transform())) {
+    okflag = false;
+  }
+
+  return okflag;
+}
+#endif
+////////////////////////////////////////////////////////////////////
+//     Function: SoftShader::reparent_decals
+//       Access: Private
+//  Description: Recursively walks the egg hierarchy, reparenting
+//               "decal" type nodes below their corresponding
+//               "decalbase" type nodes, and setting the flags.
+//
+//               Returns true on success, false if some nodes were
+//               incorrect.
+////////////////////////////////////////////////////////////////////
+bool SoftToEggConverter::
+reparent_decals(EggGroupNode *egg_parent) {
+  bool okflag = true;
+
+  // First, walk through all children of this node, looking for the
+  // one decal base, if any.
+  EggGroup *decal_base = (EggGroup *)NULL;
+  pvector<EggGroup *> decal_children;
+
+  EggGroupNode::iterator ci;
+  for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) {
+    EggNode *child =  (*ci);
+    if (child->is_of_type(EggGroup::get_class_type())) {
+      EggGroup *child_group = DCAST(EggGroup, child);
+      if (child_group->has_object_type("decalbase")) {
+        if (decal_base != (EggNode *)NULL) {
+          softegg_cat.error()
+            << "Two children of " << egg_parent->get_name()
+            << " both have decalbase set: " << decal_base->get_name()
+            << " and " << child_group->get_name() << "\n";
+          okflag = false;
+        }
+        child_group->remove_object_type("decalbase");
+        decal_base = child_group;
+
+      } else if (child_group->has_object_type("decal")) {
+        child_group->remove_object_type("decal");
+        decal_children.push_back(child_group);
+      }
+    }
+  }
+
+  if (decal_base == (EggGroup *)NULL) {
+    if (!decal_children.empty()) {
+      softegg_cat.warning()
+        << decal_children.front()->get_name()
+        << " has decal, but no sibling node has decalbase.\n";
+    }
+
+  } else {
+    if (decal_children.empty()) {
+      softegg_cat.warning()
+        << decal_base->get_name()
+        << " has decalbase, but no sibling nodes have decal.\n";
+
+    } else {
+      // All the decal children get moved to be a child of decal base.
+      // This usually will not affect the vertex positions, but it
+      // could if the decal base has a transform and the decal child
+      // is an instance node.  So don't do that.
+      pvector<EggGroup *>::iterator di;
+      for (di = decal_children.begin(); di != decal_children.end(); ++di) {
+        EggGroup *child_group = (*di);
+        decal_base->add_child(child_group);
+      }
+
+      // Also set the decal state on the base.
+      decal_base->set_decal_flag(true);
+    }
+  }
+
+  // Now recurse on each of the child nodes.
+  for (ci = egg_parent->begin(); ci != egg_parent->end(); ++ci) {
+    EggNode *child =  (*ci);
+    if (child->is_of_type(EggGroupNode::get_class_type())) {
+      EggGroupNode *child_group = DCAST(EggGroupNode, child);
+      if (!reparent_decals(child_group)) {
+        okflag = false;
+      }
+    }
+  }
+
+  return okflag;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: SoftShader::string_transform_type
+//       Access: Public, Static
+//  Description: Returns the TransformType value corresponding to the
+//               indicated string, or TT_invalid.
+////////////////////////////////////////////////////////////////////
+SoftToEggConverter::TransformType SoftToEggConverter::
+string_transform_type(const string &arg) {
+  if (cmp_nocase(arg, "all") == 0) {
+    return TT_all;
+  } else if (cmp_nocase(arg, "model") == 0) {
+    return TT_model;
+  } else if (cmp_nocase(arg, "dcs") == 0) {
+    return TT_dcs;
+  } else if (cmp_nocase(arg, "none") == 0) {
+    return TT_none;
+  } else {
+    return TT_invalid;
+  }
+}
+
+/////////////////////////////////////////////////////////////////////////
+//      Function: init_soft2egg
+//        Access: 
+//   Description: Invokes the softToEggConverter class
+/////////////////////////////////////////////////////////////////////////
+extern "C" int init_soft2egg (int argc, char **argv)
+{
+  SoftToEggConverter stec;
+
+  stec._commandName = argv[0];
+  stec.rsrc_path = "c:\\Softimage\\SOFT3D_3.9.2\\3D\\rsrc";
+  if (stec.DoGetopts(argc, argv)) {
+
+    // create a Filename object and convert the file
+    Filename softFile(argv[1]);
+    stec.convert_file(softFile);
+  }
+
+  return 0;
+}
+//
+//
+//

+ 210 - 0
pandatool/src/softegg/softToEggConverter.h

@@ -0,0 +1,210 @@
+// Filename: softToEggConverter.h
+// Created by:  masad (25Sep03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2003, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef SOFTTOEGGCONVERTER_H
+#define SOFTTOEGGCONVERTER_H
+
+#ifdef _MIN
+#undef _MIN
+#endif
+#ifdef _MAX
+#undef _MAX
+#endif
+
+#include "pandatoolbase.h"
+#include "somethingToEggConverter.h"
+#include "softNodeTree.h"
+
+#include <SAA.h>
+#include <SI_macros.h>
+
+#include "eggTextureCollection.h"
+#include "distanceUnit.h"
+#include "coordinateSystem.h"
+
+class EggData;
+class EggGroup;
+class EggTable;
+class EggVertexPool;
+class EggNurbsCurve;
+class EggPrimitive;
+class EggXfmSAnim;
+//class MayaShaderColorDef;
+
+
+////////////////////////////////////////////////////////////////////
+//       Class : SoftToEggConverter
+// Description : This class supervises the construction of an EggData
+//               structure from a single Softimage file, or from the data
+//               already in th    cout << "egg name = " << eggFilename << endl;e global Softimage model space.
+//
+////////////////////////////////////////////////////////////////////
+class SoftToEggConverter : public SomethingToEggConverter {
+public:
+  SoftToEggConverter(const string &program_name = "");
+  SoftToEggConverter(const SoftToEggConverter &copy);
+  virtual ~SoftToEggConverter();
+
+  void Help();
+  void Usage();
+  void ShowOpts();
+
+  bool HandleGetopts(int &idx, int argc, char **argv);
+  bool DoGetopts(int &argc, char **&argv);
+
+  virtual SomethingToEggConverter *make_copy();
+  virtual string get_name() const;
+  virtual string get_extension() const;
+
+  virtual bool convert_file(const Filename &filename);
+  bool convert_soft(bool from_selection);
+  bool open_api();
+  void close_api();
+
+private:
+  bool convert_flip(double start_frame, double end_frame, 
+                    double frame_inc, double output_frame_rate);
+
+  bool convert_char_model();
+  bool convert_char_chan(double start_frame, double end_frame, 
+                         double frame_inc, double output_frame_rate);
+  bool convert_hierarchy(EggGroupNode *egg_root);
+  bool process_model_node(SoftNodeDesc *node_desc);
+
+  void get_transform(SoftNodeDesc *node_Desc, EggGroup *egg_group);
+  /*
+  void get_joint_transform(const MDagPath &dag_path, EggGroup *egg_group);
+
+  // I ran into core dumps trying to pass around a MFnMesh object by
+  // value.  From now on, all MFn* objects will be passed around by
+  // reference.
+  void make_nurbs_surface(const MDagPath &dag_path, 
+                          MFnNurbsSurface &surface,
+                          EggGroup *group);
+  EggNurbsCurve *make_trim_curve(const MFnNurbsCurve &curve,
+                                 const string &nurbs_name,
+                                 EggGroupNode *egg_group,
+                                 int trim_curve_index);
+  void make_nurbs_curve(const MDagPath &dag_path, 
+                        const MFnNurbsCurve &curve,
+                        EggGroup *group);
+  */
+  void make_polyset(SAA_Elem *model, EggGroup *egg_group, SAA_ModelType type, char *node_name);
+  /*
+  void make_locator(const MDagPath &dag_path, const MFnDagNode &dag_node,
+                    EggGroup *egg_group);
+  bool get_vertex_weights(const MDagPath &dag_path, const MFnMesh &mesh,
+                          pvector<EggGroup *> &joints, MFloatArray &weights);
+  */
+  char *GetTextureName( SAA_Scene *scene, SAA_Elem *texture );
+  char *GetModelNoteInfo( SAA_Scene *, SAA_Elem * );
+  void set_shader_attributes(EggPrimitive &primitive,
+                             SAA_Elem &shader);
+  void apply_texture_properties(EggTexture &tex);
+  /*
+  bool compare_texture_properties(EggTexture &tex, 
+                                  const MayaShaderColorDef &color_def);
+  */
+  bool reparent_decals(EggGroupNode *egg_parent);
+
+  string _program_name;
+  bool _from_selection;
+
+  SoftNodeTree _tree;
+
+  SI_Error            result;
+  SAA_Scene           scene;
+  SAA_Elem            model;
+  SAA_Database        database;
+
+public:
+
+  char *_getopts;
+  
+  // This is argv[0].
+  const char *_commandName;
+
+  // This is the entire command line.
+  const char *_commandLine;
+
+  char        *rsrc_path;
+  char        *database_name;
+  char        *scene_name;
+  char        *model_name;
+  char        *eggFileName;
+  char        *animFileName;
+  char        *eggGroupName;
+  char        *tex_path;
+  char        *tex_filename;
+  char        *search_prefix;
+
+  char **texNameArray;
+  int uRepeat, vRepeat;
+  float        matrix[4][4];
+
+  int                    nurbs_step;
+  int                    anim_start;
+  int                    anim_end;
+  int                    anim_rate;
+  int                    pose_frame;
+  int                    verbose;
+  int                    flatten;
+  int                    shift_textures;
+  int                    ignore_tex_offsets;
+  int                    use_prefix;
+  
+  bool                foundRoot;
+  bool                geom_as_joint;
+  bool                make_anim;
+  bool                make_nurbs;
+  bool                make_poly;
+  bool                make_soft;
+  bool                make_morph;
+  bool                make_duv;
+  bool                make_dart;
+  bool                has_morph;
+  bool                make_pose;
+  
+  /*
+  MayaShaders _shaders;
+  */
+  EggTextureCollection _textures;
+  /*
+  PT(MayaApi) _maya;
+  */
+
+  bool _polygon_output;
+  double _polygon_tolerance;
+  /*
+  bool _respect_maya_double_sided;
+  bool _always_show_vertex_color;
+  */
+  enum TransformType {
+    TT_invalid,
+    TT_all,
+    TT_model,
+    TT_dcs,
+    TT_none,
+  };
+  TransformType _transform_type;
+
+  static TransformType string_transform_type(const string &arg);
+};
+
+
+#endif