From 74d002cb4e3672ec61c43cb3536af6979ac302f4 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sat, 7 Jun 2003 01:26:02 +0000 Subject: [PATCH] build a tree of NodeDesc's first, then use to generate joints and tables --- pandatool/src/mayaegg/Sources.pp | 2 + pandatool/src/mayaegg/config_mayaegg.cxx | 2 + pandatool/src/mayaegg/mayaNodeDesc.cxx | 191 ++++++ pandatool/src/mayaegg/mayaNodeDesc.h | 98 +++ pandatool/src/mayaegg/mayaNodeTree.cxx | 387 +++++++++++ pandatool/src/mayaegg/mayaNodeTree.h | 67 ++ pandatool/src/mayaegg/mayaToEggConverter.cxx | 670 +++++-------------- pandatool/src/mayaegg/mayaToEggConverter.h | 35 +- 8 files changed, 924 insertions(+), 528 deletions(-) create mode 100755 pandatool/src/mayaegg/mayaNodeDesc.cxx create mode 100755 pandatool/src/mayaegg/mayaNodeDesc.h create mode 100755 pandatool/src/mayaegg/mayaNodeTree.cxx create mode 100755 pandatool/src/mayaegg/mayaNodeTree.h diff --git a/pandatool/src/mayaegg/Sources.pp b/pandatool/src/mayaegg/Sources.pp index 08e58a3bae..a2ef347359 100644 --- a/pandatool/src/mayaegg/Sources.pp +++ b/pandatool/src/mayaegg/Sources.pp @@ -17,6 +17,8 @@ #define SOURCES \ config_mayaegg.cxx config_mayaegg.h \ mayaEggGroupUserData.cxx mayaEggGroupUserData.I mayaEggGroupUserData.h \ + mayaNodeDesc.cxx mayaNodeDesc.h \ + mayaNodeTree.cxx mayaNodeTree.h \ mayaToEggConverter.cxx mayaToEggConverter.h #end ss_lib_target diff --git a/pandatool/src/mayaegg/config_mayaegg.cxx b/pandatool/src/mayaegg/config_mayaegg.cxx index 90138abcfe..de642cf9d3 100644 --- a/pandatool/src/mayaegg/config_mayaegg.cxx +++ b/pandatool/src/mayaegg/config_mayaegg.cxx @@ -18,6 +18,7 @@ #include "config_mayaegg.h" #include "mayaEggGroupUserData.h" +#include "mayaNodeDesc.h" #include "dconfig.h" @@ -45,5 +46,6 @@ init_libmayaegg() { initialized = true; MayaEggGroupUserData::init_type(); + MayaNodeDesc::init_type(); } diff --git a/pandatool/src/mayaegg/mayaNodeDesc.cxx b/pandatool/src/mayaegg/mayaNodeDesc.cxx new file mode 100755 index 0000000000..ecf3ddd7d4 --- /dev/null +++ b/pandatool/src/mayaegg/mayaNodeDesc.cxx @@ -0,0 +1,191 @@ +// Filename: mayaNodeDesc.cxx +// Created by: drose (06Jun03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "mayaNodeDesc.h" + +TypeHandle MayaNodeDesc::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +MayaNodeDesc:: +MayaNodeDesc(MayaNodeDesc *parent, const string &name) : + Namable(name), + _parent(parent) +{ + _dag_path = (MDagPath *)NULL; + _egg_group = (EggGroup *)NULL; + _egg_table = (EggTable *)NULL; + _anim = (EggXfmSAnim *)NULL; + _joint_type = JT_none; + + // Add ourselves to our parent. + if (_parent != (MayaNodeDesc *)NULL) { + _parent->_children.push_back(this); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +MayaNodeDesc:: +~MayaNodeDesc() { + if (_dag_path != (MDagPath *)NULL) { + delete _dag_path; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::from_dag_path +// Access: Public +// Description: Indicates an associated between the MayaNodeDesc and +// some Maya instance. +//////////////////////////////////////////////////////////////////// +void MayaNodeDesc:: +from_dag_path(const MDagPath &dag_path) { + if (_dag_path == (MDagPath *)NULL) { + _dag_path = new MDagPath(dag_path); + + if (_dag_path->hasFn(MFn::kJoint)) { + // This node is a joint. + _joint_type = JT_joint; + if (_parent != (MayaNodeDesc *)NULL) { + _parent->mark_joint_parent(); + } + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::has_dag_path +// Access: Public +// Description: Returns true if a Maya dag path has been associated +// with this node, false otherwise. +//////////////////////////////////////////////////////////////////// +bool MayaNodeDesc:: +has_dag_path() const { + return (_dag_path != (MDagPath *)NULL); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::get_dag_path +// Access: Public +// Description: Returns the dag path associated with this node. It +// is an error to call this unless has_dag_path() +// returned true. +//////////////////////////////////////////////////////////////////// +const MDagPath &MayaNodeDesc:: +get_dag_path() const { + nassertr(_dag_path != (MDagPath *)NULL, *_dag_path); + return *_dag_path; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::is_joint +// Access: Private +// Description: Returns true if the node should be treated as a joint +// by the converter. +//////////////////////////////////////////////////////////////////// +bool MayaNodeDesc:: +is_joint() const { + return _joint_type == JT_joint || _joint_type == JT_pseudo_joint; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::is_joint_parent +// Access: Private +// Description: Returns true if the node is the parent or ancestor of +// a joint. +//////////////////////////////////////////////////////////////////// +bool MayaNodeDesc:: +is_joint_parent() const { + return _joint_type == JT_joint_parent; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::clear_egg +// Access: Private +// Description: Recursively clears the egg pointers from this node +// and all children. +//////////////////////////////////////////////////////////////////// +void MayaNodeDesc:: +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) { + MayaNodeDesc *child = (*ci); + child->clear_egg(); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::mark_joint_parent +// Access: Private +// Description: Indicates that this node has at least one child that +// is a joint or a pseudo-joint. +//////////////////////////////////////////////////////////////////// +void MayaNodeDesc:: +mark_joint_parent() { + if (_joint_type == JT_none) { + _joint_type = JT_joint_parent; + if (_parent != (MayaNodeDesc *)NULL) { + _parent->mark_joint_parent(); + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeDesc::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 MayaNodeDesc:: +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) { + Children::const_iterator ci; + for (ci = _children.begin(); ci != _children.end(); ++ci) { + MayaNodeDesc *child = (*ci); + child->check_pseudo_joints(joint_above); + } + } +} diff --git a/pandatool/src/mayaegg/mayaNodeDesc.h b/pandatool/src/mayaegg/mayaNodeDesc.h new file mode 100755 index 0000000000..8e4678641d --- /dev/null +++ b/pandatool/src/mayaegg/mayaNodeDesc.h @@ -0,0 +1,98 @@ +// Filename: mayaNodeDesc.h +// Created by: drose (06Jun03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef MAYANODEDESC_H +#define MAYANODEDESC_H + +#include "pandatoolbase.h" + +#include "referenceCount.h" +#include "pointerTo.h" +#include "namable.h" + +#include "pre_maya_include.h" +#include +#include "post_maya_include.h" + +class EggGroup; +class EggTable; +class EggXfmSAnim; + +//////////////////////////////////////////////////////////////////// +// Class : MayaNodeDesc +// Description : Describes a single instance of a node in the Maya +// scene graph, relating it to the corresponding egg +// structures (e.g. node, group, or table entry) that +// will be created. +//////////////////////////////////////////////////////////////////// +class MayaNodeDesc : public ReferenceCount, public Namable { +public: + MayaNodeDesc(MayaNodeDesc *parent = NULL, const string &name = string()); + ~MayaNodeDesc(); + + void from_dag_path(const MDagPath &dag_path); + bool has_dag_path() const; + const MDagPath &get_dag_path() const; + + bool is_joint() const; + bool is_joint_parent() const; + + MayaNodeDesc *_parent; + typedef pvector< PT(MayaNodeDesc) > Children; + Children _children; + +private: + void clear_egg(); + void mark_joint_parent(); + void check_pseudo_joints(bool joint_above); + + MDagPath *_dag_path; + + EggGroup *_egg_group; + EggTable *_egg_table; + EggXfmSAnim *_anim; + + enum JointType { + JT_none, // Not a joint. + JT_joint, // An actual joint in Maya. + JT_pseudo_joint, // Not a joint in Maya, 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, "MayaNodeDesc", + ReferenceCount::get_class_type(), + Namable::get_class_type()); + } + +private: + static TypeHandle _type_handle; + + friend class MayaNodeTree; +}; + +#endif diff --git a/pandatool/src/mayaegg/mayaNodeTree.cxx b/pandatool/src/mayaegg/mayaNodeTree.cxx new file mode 100755 index 0000000000..e33b48cc3f --- /dev/null +++ b/pandatool/src/mayaegg/mayaNodeTree.cxx @@ -0,0 +1,387 @@ +// Filename: mayaNodeTree.cxx +// Created by: drose (06Jun03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "mayaNodeTree.h" +#include "mayaEggGroupUserData.h" +#include "config_mayaegg.h" +#include "maya_funcs.h" +#include "eggGroup.h" +#include "eggTable.h" +#include "eggXfmSAnim.h" +#include "eggData.h" + +#include "pre_maya_include.h" +#include +#include +#include +#include +#include "post_maya_include.h" + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +MayaNodeTree:: +MayaNodeTree() { + _root = new MayaNodeDesc; + _fps = 0.0; + _egg_data = (EggData *)NULL; + _egg_root = (EggGroupNode *)NULL; + _skeleton_node = (EggGroupNode *)NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::build_node +// Access: Public +// Description: Returns a pointer to the node corresponding to the +// indicated dag_path object, creating it first if +// necessary. +//////////////////////////////////////////////////////////////////// +MayaNodeDesc *MayaNodeTree:: +build_node(const MDagPath &dag_path) { + MayaNodeDesc *node_desc = r_build_node(dag_path.fullPathName().asChar()); + node_desc->from_dag_path(dag_path); + return node_desc; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::build_complete_hierarchy +// Access: Public +// Description: Walks through the complete Maya hierarchy and builds +// up the corresponding tree. +//////////////////////////////////////////////////////////////////// +bool MayaNodeTree:: +build_complete_hierarchy() { + MStatus status; + + MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status); + if (!status) { + status.perror("MItDag constructor"); + return false; + } + + // Get the entire Maya scene. + + // This while loop walks through the entire Maya hierarchy, one + // node at a time. Maya's MItDag object automatically performs a + // depth-first traversal of its scene graph. + + bool all_ok = true; + while (!dag_iterator.isDone()) { + MDagPath dag_path; + status = dag_iterator.getPath(dag_path); + if (!status) { + status.perror("MItDag::getPath"); + } else { + build_node(dag_path); + } + + dag_iterator.next(); + } + + if (all_ok) { + _root->check_pseudo_joints(false); + } + + return all_ok; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::build_selected_hierarchy +// Access: Public +// Description: Walks through the selected subset of the Maya +// hierarchy (or the complete hierarchy, if nothing is +// selected) and builds up the corresponding tree. +//////////////////////////////////////////////////////////////////// +bool MayaNodeTree:: +build_selected_hierarchy() { + 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()) { + mayaegg_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; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::get_num_nodes +// Access: Public +// Description: Returns the total number of nodes in the hierarchy, +// not counting the root node. +//////////////////////////////////////////////////////////////////// +int MayaNodeTree:: +get_num_nodes() const { + return _nodes.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::get_node +// Access: Public +// Description: Returns the nth node in the hierarchy, in an +// arbitrary ordering. +//////////////////////////////////////////////////////////////////// +MayaNodeDesc *MayaNodeTree:: +get_node(int n) const { + nassertr(n >= 0 && n < (int)_nodes.size(), NULL); + return _nodes[n]; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::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 MayaNodeTree:: +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: MayaNodeTree::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 *MayaNodeTree:: +get_egg_group(MayaNodeDesc *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; + + nassertr(node_desc->_parent != (MayaNodeDesc *)NULL, NULL); + egg_group = new EggGroup(node_desc->get_name()); + if (node_desc->is_joint()) { + egg_group->set_group_type(EggGroup::GT_joint); + } + + 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 (node_desc->has_dag_path()) { + // 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); + } + + // 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" has meaning only to this converter. + if (egg_group->has_object_type("vertex-color")) { + egg_group->remove_object_type("vertex-color"); + MayaEggGroupUserData *user_data = new MayaEggGroupUserData; + user_data->_vertex_color = true; + egg_group->set_user_data(user_data); + } + } + + node_desc->_egg_group = egg_group; + } + + return node_desc->_egg_group; +} + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::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 *MayaNodeTree:: +get_egg_table(MayaNodeDesc *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 != (MayaNodeDesc *)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: MayaNodeTree::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 *MayaNodeTree:: +get_egg_anim(MayaNodeDesc *node_desc) { + get_egg_table(node_desc); + return node_desc->_anim; +} + + +//////////////////////////////////////////////////////////////////// +// Function: MayaNodeTree::r_build_node +// Access: Private +// Description: The recursive implementation of build_node(). +//////////////////////////////////////////////////////////////////// +MayaNodeDesc *MayaNodeTree:: +r_build_node(const string &path) { + // If we have already encountered this pathname, return the + // corresponding MayaNodeDesc immediately. + NodesByPath::const_iterator ni = _nodes_by_path.find(path); + if (ni != _nodes_by_path.end()) { + return (*ni).second; + } + + // Otherwise, we have to create it. Do this recursively, so we + // create each node along the path. + MayaNodeDesc *node_desc; + + if (path.empty()) { + // This is the top. + node_desc = _root; + + } else { + // Maya uses vertical bars to separate path components. Remove + // everything from the rightmost bar on; this will give us the + // parent's path name. + size_t bar = path.rfind("|"); + string parent_path, local_name; + if (bar != string::npos) { + parent_path = path.substr(0, bar); + local_name = path.substr(bar + 1); + } else { + local_name = path; + } + + MayaNodeDesc *parent_node_desc = r_build_node(parent_path); + node_desc = new MayaNodeDesc(parent_node_desc, local_name); + _nodes.push_back(node_desc); + } + + _nodes_by_path.insert(NodesByPath::value_type(path, node_desc)); + return node_desc; +} diff --git a/pandatool/src/mayaegg/mayaNodeTree.h b/pandatool/src/mayaegg/mayaNodeTree.h new file mode 100755 index 0000000000..24c7175e9b --- /dev/null +++ b/pandatool/src/mayaegg/mayaNodeTree.h @@ -0,0 +1,67 @@ +// Filename: mayaNodeTree.h +// Created by: drose (06Jun03) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://www.panda3d.org/license.txt . +// +// To contact the maintainers of this program write to +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef MAYANODETREE_H +#define MAYANODETREE_H + +#include "pandatoolbase.h" + +#include "mayaNodeDesc.h" + +class EggData; +class EggGroupNode; + +//////////////////////////////////////////////////////////////////// +// Class : MayaNodeTree +// Description : Describes a complete tree of maya nodes for +// conversion. +//////////////////////////////////////////////////////////////////// +class MayaNodeTree { +public: + MayaNodeTree(); + MayaNodeDesc *build_node(const MDagPath &dag_path); + bool build_complete_hierarchy(); + bool build_selected_hierarchy(); + + int get_num_nodes() const; + MayaNodeDesc *get_node(int n) const; + + void clear_egg(EggData *egg_data, EggGroupNode *egg_root, + EggGroupNode *skeleton_node); + EggGroup *get_egg_group(MayaNodeDesc *node_desc); + EggTable *get_egg_table(MayaNodeDesc *node_desc); + EggXfmSAnim *get_egg_anim(MayaNodeDesc *node_desc); + + PT(MayaNodeDesc) _root; + float _fps; + +private: + EggData *_egg_data; + EggGroupNode *_egg_root; + EggGroupNode *_skeleton_node; + + MayaNodeDesc *r_build_node(const string &path); + + typedef pmap NodesByPath; + NodesByPath _nodes_by_path; + + typedef pvector Nodes; + Nodes _nodes; +}; + +#endif diff --git a/pandatool/src/mayaegg/mayaToEggConverter.cxx b/pandatool/src/mayaegg/mayaToEggConverter.cxx index 1d0536ca53..876984c69c 100644 --- a/pandatool/src/mayaegg/mayaToEggConverter.cxx +++ b/pandatool/src/mayaegg/mayaToEggConverter.cxx @@ -188,8 +188,6 @@ convert_maya(bool from_selection) { _from_selection = from_selection; _textures.clear(); _shaders.clear(); - _groups.clear(); - _tables.clear(); if (!open_api()) { mayaegg_cat.error() @@ -235,53 +233,61 @@ convert_maya(bool from_selection) { bool all_ok = true; - switch (get_animation_convert()) { - case AC_pose: - // pose: set to a specific frame, then get out the static geometry. - mayaegg_cat.info(false) - << "frame " << start_frame << "\n"; - MGlobal::viewFrame(MTime(start_frame, MTime::uiUnit())); - // fall through + if (_from_selection) { + all_ok = _tree.build_selected_hierarchy(); + } else { + all_ok = _tree.build_complete_hierarchy(); + } - case AC_none: - // none: just get out a static model, no animation. - all_ok = convert_hierarchy(&get_egg_data()); - break; + if (all_ok) { + switch (get_animation_convert()) { + case AC_pose: + // pose: set to a specific frame, then get out the static geometry. + mayaegg_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: + // flip: get out a series of static models, one per frame, under a + // sequence node. + all_ok = convert_flip(start_frame, end_frame, frame_inc, + output_frame_rate); + break; - case AC_flip: - // flip: get out a series of static models, one per frame, under a - // sequence node. - 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_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; + }; - 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()); + reparent_decals(&get_egg_data()); + } if (all_ok) { mayaegg_cat.info() @@ -355,10 +361,9 @@ convert_flip(double start_frame, double end_frame, double frame_inc, sequence_node->add_child(frame_root); MGlobal::viewFrame(frame); - if (!convert_hierarchy(frame_root)) { + if (!convert_hierarchy(&get_egg_data())) { all_ok = false; } - _groups.clear(); frame += frame_inc; } @@ -408,38 +413,10 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc, EggTable *skeleton_node = new EggTable(""); bundle_node->add_child(skeleton_node); - // First, walk through the scene graph and build up the table of - // joints. - MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status); - if (!status) { - status.perror("MItDag constructor"); - return false; - } - bool all_ok = true; - while (!dag_iterator.isDone()) { - MDagPath dag_path; - status = dag_iterator.getPath(dag_path); - if (!status) { - status.perror("MItDag::getPath"); - } else { - if (!process_chan_node(dag_path, skeleton_node)) { - all_ok = false; - } - } - - dag_iterator.next(); - } - - // Now walk through the joints in that table and make sure they're - // all set to use the correct frame frame. - double fps = output_frame_rate / frame_inc; - Tables::iterator ti; - for (ti = _tables.begin(); ti != _tables.end(); ++ti) { - JointAnim *joint_anim = (*ti).second; - nassertr(joint_anim != (JointAnim *)NULL && - joint_anim->_anim != (EggXfmSAnim *)NULL, false); - joint_anim->_anim->set_fps(fps); - } + // Set the frame rate before we start asking for anim tables to be + // created. + _tree._fps = output_frame_rate / frame_inc; + _tree.clear_egg(&get_egg_data(), NULL, skeleton_node); // Now we can get the animation data by walking through all of the // frames, one at a time, and getting the joint angles at each @@ -449,6 +426,9 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc, // each joint each frame. PT(EggGroup) tgroup = new EggGroup; + int num_nodes = _tree.get_num_nodes(); + int i; + MTime frame(start_frame, MTime::uiUnit()); MTime frame_stop(end_frame, MTime::uiUnit()); while (frame <= frame_stop) { @@ -461,114 +441,50 @@ convert_char_chan(double start_frame, double end_frame, double frame_inc, } MGlobal::viewFrame(frame); - for (ti = _tables.begin(); ti != _tables.end(); ++ti) { - JointAnim *joint_anim = (*ti).second; - get_joint_transform(joint_anim->_dag_path, tgroup); - joint_anim->_anim->add_data(tgroup->get_transform()); + for (i = 0; i < num_nodes; i++) { + MayaNodeDesc *node_desc = _tree.get_node(i); + if (node_desc->is_joint()) { + get_joint_transform(node_desc->get_dag_path(), tgroup); + _tree.get_egg_anim(node_desc)->add_data(tgroup->get_transform()); + } } frame += frame_inc; } + + // Now optimize all of the tables we just filled up, for no real + // good reason. + for (i = 0; i < num_nodes; i++) { + MayaNodeDesc *node_desc = _tree.get_node(i); + if (node_desc->is_joint()) { + _tree.get_egg_anim(node_desc)->optimize(); + } + } + mayaegg_cat.info(false) << "\n"; - // Finally, clean up by deleting all of the JointAnim structures we - // created. - for (ti = _tables.begin(); ti != _tables.end(); ++ti) { - JointAnim *joint_anim = (*ti).second; - delete joint_anim; - } - _tables.clear(); - - return all_ok; + return true; } //////////////////////////////////////////////////////////////////// // Function: MayaToEggConverter::convert_hierarchy // Access: Private -// Description: Walks the entire Maya hierarchy, converting it to a -// corresponding egg hierarchy under the indicated root -// node. +// Description: Generates egg structures for each node in the Maya +// hierarchy. //////////////////////////////////////////////////////////////////// bool MayaToEggConverter:: convert_hierarchy(EggGroupNode *egg_root) { - MStatus status; + int num_nodes = _tree.get_num_nodes(); - MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status); - if (!status) { - status.perror("MItDag constructor"); - return false; - } - - if (_from_selection) { - // Get only the selected geometry. - MSelectionList selection; - status = MGlobal::getActiveSelectionList(selection); - if (!status) { - status.perror("MGlobal::getActiveSelectionList"); + _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; } - - // Get the selected geometry only if the selection is nonempty; - // otherwise, get the whole scene anyway. - if (!selection.isEmpty()) { - 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 { - if (!process_model_node(dag_path, egg_root)) { - all_ok = false; - } - } - - dag_iterator.next(); - } - } - } - return all_ok; - - } else { - mayaegg_cat.info() - << "Selection list is empty.\n"; - // Fall through. - } } - // Get the entire Maya scene. - - // This while loop walks through the entire Maya hierarchy, one - // node at a time. Maya's MItDag object automatically performs a - // depth-first traversal of its scene graph. - - bool all_ok = true; - while (!dag_iterator.isDone()) { - MDagPath dag_path; - status = dag_iterator.getPath(dag_path); - if (!status) { - status.perror("MItDag::getPath"); - } else { - if (!process_model_node(dag_path, egg_root)) { - all_ok = false; - } - } - - dag_iterator.next(); - } - - return all_ok; + return true; } //////////////////////////////////////////////////////////////////// @@ -580,7 +496,14 @@ convert_hierarchy(EggGroupNode *egg_root) { // successful, false if an error was encountered. //////////////////////////////////////////////////////////////////// bool MayaToEggConverter:: -process_model_node(const MDagPath &dag_path, EggGroupNode *egg_root) { +process_model_node(MayaNodeDesc *node_desc) { + if (!node_desc->has_dag_path()) { + // If the node has no Maya equivalent, never mind. + return true; + } + + MDagPath dag_path = node_desc->get_dag_path(); + MStatus status; MFnDagNode dag_node(dag_path, &status); if (!status) { @@ -588,9 +511,11 @@ process_model_node(const MDagPath &dag_path, EggGroupNode *egg_root) { return false; } + string path = dag_path.fullPathName().asChar(); + if (mayaegg_cat.is_debug()) { mayaegg_cat.debug() - << dag_path.fullPathName().asChar() << ": " << dag_node.typeName(); + << path << ": " << dag_node.typeName(); if (MAnimUtil::isAnimated(dag_path)) { mayaegg_cat.debug(false) @@ -600,70 +525,54 @@ process_model_node(const MDagPath &dag_path, EggGroupNode *egg_root) { mayaegg_cat.debug(false) << "\n"; } - if (dag_node.inUnderWorld()) { + if (node_desc->is_joint()) { + // Don't bother with joints unless we're getting an animatable + // model. + if (_animation_convert == AC_model) { + EggGroup *egg_group = _tree.get_egg_group(node_desc); + get_joint_transform(dag_path, egg_group); + } + + } else if (dag_node.inUnderWorld()) { if (mayaegg_cat.is_debug()) { mayaegg_cat.debug() - << "Ignoring underworld node " << dag_path.fullPathName().asChar() + << "Ignoring underworld node " << path << "\n"; } } else if (dag_node.isIntermediateObject()) { if (mayaegg_cat.is_debug()) { mayaegg_cat.debug() - << "Ignoring intermediate object " << dag_path.fullPathName().asChar() + << "Ignoring intermediate object " << path << "\n"; } } else if (dag_path.hasFn(MFn::kCamera)) { if (mayaegg_cat.is_debug()) { mayaegg_cat.debug() - << "Ignoring camera node " << dag_path.fullPathName().asChar() + << "Ignoring camera node " << path << "\n"; } } else if (dag_path.hasFn(MFn::kLight)) { if (mayaegg_cat.is_debug()) { mayaegg_cat.debug() - << "Ignoring light node " << dag_path.fullPathName().asChar() + << "Ignoring light node " << path << "\n"; } - } else if (dag_path.hasFn(MFn::kJoint)) { - // A joint. - - // Don't bother with joints unless we're getting an animatable - // model. - if (_animation_convert == AC_model) { - EggGroup *egg_group = get_egg_group(dag_path, egg_root); - - if (egg_group != (EggGroup *)NULL) { - egg_group->set_group_type(EggGroup::GT_joint); - get_joint_transform(dag_path, egg_group); - } - } - } else if (dag_path.hasFn(MFn::kNurbsSurface)) { - EggGroup *egg_group = get_egg_group(dag_path, egg_root); - - if (egg_group == (EggGroup *)NULL) { - mayaegg_cat.error() - << "Cannot determine group node.\n"; - return false; - + EggGroup *egg_group = _tree.get_egg_group(node_desc); + get_transform(dag_path, egg_group); + + MFnNurbsSurface surface(dag_path, &status); + if (!status) { + mayaegg_cat.info() + << "Error in node " << path + << ":\n" + << " it appears to have a NURBS surface, but does not.\n"; } else { - if (_animation_convert != AC_model) { - get_transform(dag_path, egg_group); - } - - MFnNurbsSurface surface(dag_path, &status); - if (!status) { - mayaegg_cat.info() - << "Error in node " << dag_path.fullPathName().asChar() - << ":\n" - << " it appears to have a NURBS surface, but does not.\n"; - } else { - make_nurbs_surface(dag_path, surface, egg_group, egg_root); - } + make_nurbs_surface(dag_path, surface, egg_group); } } else if (dag_path.hasFn(MFn::kNurbsCurve)) { @@ -671,124 +580,57 @@ process_model_node(const MDagPath &dag_path, EggGroupNode *egg_root) { // Animated models, as a general rule, don't want these sorts of // things in them. if (_animation_convert != AC_model) { - EggGroup *egg_group = get_egg_group(dag_path, egg_root); + EggGroup *egg_group = _tree.get_egg_group(node_desc); + get_transform(dag_path, egg_group); - if (egg_group == (EggGroup *)NULL) { - mayaegg_cat.error() - << "Cannot determine group node.\n"; - + MFnNurbsCurve curve(dag_path, &status); + if (!status) { + mayaegg_cat.info() + << "Error in node " << path << ":\n" + << " it appears to have a NURBS curve, but does not.\n"; } else { - get_transform(dag_path, egg_group); - - MFnNurbsCurve curve(dag_path, &status); - if (!status) { - mayaegg_cat.info() - << "Error in node " << dag_path.fullPathName().asChar() << ":\n" - << " it appears to have a NURBS curve, but does not.\n"; - } else { - make_nurbs_curve(dag_path, curve, egg_group, egg_root); - } + make_nurbs_curve(dag_path, curve, egg_group); } } } else if (dag_path.hasFn(MFn::kMesh)) { - EggGroup *egg_group = get_egg_group(dag_path, egg_root); - - if (egg_group == (EggGroup *)NULL) { - mayaegg_cat.error() - << "Cannot determine group node.\n"; - return false; + EggGroup *egg_group = _tree.get_egg_group(node_desc); + get_transform(dag_path, egg_group); + MFnMesh mesh(dag_path, &status); + if (!status) { + mayaegg_cat.info() + << "Error in node " << path << ":\n" + << " it appears to have a polygon mesh, but does not.\n"; } else { - if (_animation_convert != AC_model) { - get_transform(dag_path, egg_group); - } - - MFnMesh mesh(dag_path, &status); - if (!status) { - mayaegg_cat.info() - << "Error in node " << dag_path.fullPathName().asChar() << ":\n" - << " it appears to have a polygon mesh, but does not.\n"; - } else { - make_polyset(dag_path, mesh, egg_group, egg_root); - } + make_polyset(dag_path, mesh, egg_group); } } else if (dag_path.hasFn(MFn::kLocator)) { - EggGroup *egg_group = get_egg_group(dag_path, egg_root); - - if (egg_group == (EggGroup *)NULL) { - mayaegg_cat.error() - << "Cannot determine group node.\n"; - return false; - - } else { - if (mayaegg_cat.is_debug()) { - mayaegg_cat.debug() - << "Locator at " << dag_path.fullPathName().asChar() << "\n"; - } - - // Presumably, the locator's position has some meaning to the - // end-user, so we will implicitly tag it with the DCS flag so it - // won't get flattened out. - if (_animation_convert != AC_model) { - // For now, don't set the DCS flag on locators within - // character models, since egg-optchar doesn't understand - // this. Perhaps there's no reason to ever change this, since - // locators within character models may not be meaningful. - egg_group->set_dcs_type(EggGroup::DC_net); - get_transform(dag_path, egg_group); - } - make_locator(dag_path, dag_node, egg_group, egg_root); - } - - } else { - // Get the translation/rotation/scale data - EggGroup *egg_group = get_egg_group(dag_path, egg_root); - - if (egg_group != (EggGroup *)NULL) { - if (_animation_convert != AC_model) { - get_transform(dag_path, egg_group); - } - } - } - - return true; -} - -//////////////////////////////////////////////////////////////////// -// Function: MayaToEggConverter::process_chan_node -// Access: Private -// Description: Similar to process_model_node(), but this code path -// is followed only when we are building a table of -// animation data (AC_chan). It just builds up the -// EggTable hierarchy according to the joint table. -//////////////////////////////////////////////////////////////////// -bool MayaToEggConverter:: -process_chan_node(const MDagPath &dag_path, EggGroupNode *egg_root) { - MStatus status; - MFnDagNode dag_node(dag_path, &status); - if (!status) { - status.perror("MFnDagNode constructor"); - return false; - } - - if (dag_path.hasFn(MFn::kJoint)) { - // A joint. + EggGroup *egg_group = _tree.get_egg_group(node_desc); if (mayaegg_cat.is_debug()) { mayaegg_cat.debug() - << dag_path.fullPathName().asChar() << ": " << dag_node.typeName(); - - if (MAnimUtil::isAnimated(dag_path)) { - mayaegg_cat.debug(false) - << " (animated)"; - } - - mayaegg_cat.debug(false) << "\n"; + << "Locator at " << path << "\n"; } + + // Presumably, the locator's position has some meaning to the + // end-user, so we will implicitly tag it with the DCS flag so it + // won't get flattened out. + if (_animation_convert != AC_model) { + // For now, don't set the DCS flag on locators within + // character models, since egg-optchar doesn't understand + // this. Perhaps there's no reason to ever change this, since + // locators within character models may not be meaningful. + egg_group->set_dcs_type(EggGroup::DC_net); + } + get_transform(dag_path, egg_group); + make_locator(dag_path, dag_node, egg_group); - get_egg_table(dag_path, egg_root); + } else { + // Just a generic node. + EggGroup *egg_group = _tree.get_egg_group(node_desc); + get_transform(dag_path, egg_group); } return true; @@ -802,6 +644,12 @@ process_chan_node(const MDagPath &dag_path, EggGroupNode *egg_root) { //////////////////////////////////////////////////////////////////// void MayaToEggConverter:: get_transform(const MDagPath &dag_path, EggGroup *egg_group) { + if (_animation_convert == AC_model) { + // When we're getting an animated model, we only get transforms + // for joints. + return; + } + MStatus status; MObject transformNode = dag_path.transform(&status); if (!status && status.statusCode() == MStatus::kInvalidParameter) { @@ -959,7 +807,7 @@ get_joint_transform(const MDagPath &dag_path, EggGroup *egg_group) { //////////////////////////////////////////////////////////////////// void MayaToEggConverter:: make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface, - EggGroup *egg_group, EggGroupNode *egg_root) { + EggGroup *egg_group) { MStatus status; string name = surface.name().asChar(); @@ -1015,7 +863,7 @@ make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface, status.perror("MFnMesh constructor"); return; } - make_polyset(polyset_path, polyset_fn, egg_group, egg_root, shader); + make_polyset(polyset_path, polyset_fn, egg_group, shader); // Now remove the polyset we created. MFnDagNode parent_node(polyset_parent, &status); @@ -1271,7 +1119,7 @@ make_trim_curve(const MFnNurbsCurve &curve, const string &nurbs_name, //////////////////////////////////////////////////////////////////// void MayaToEggConverter:: make_nurbs_curve(const MDagPath &, const MFnNurbsCurve &curve, - EggGroup *egg_group, EggGroupNode *) { + EggGroup *egg_group) { MStatus status; string name = curve.name().asChar(); @@ -1360,8 +1208,7 @@ make_nurbs_curve(const MDagPath &, const MFnNurbsCurve &curve, //////////////////////////////////////////////////////////////////// void MayaToEggConverter:: make_polyset(const MDagPath &dag_path, const MFnMesh &mesh, - EggGroup *egg_group, EggGroupNode *egg_root, - MayaShader *default_shader) { + EggGroup *egg_group, MayaShader *default_shader) { MStatus status; string name = mesh.name().asChar(); @@ -1556,10 +1403,10 @@ make_polyset(const MDagPath &dag_path, const MFnMesh &mesh, MFloatArray weights; if (_animation_convert == AC_model) { got_weights = - get_vertex_weights(dag_path, mesh, egg_root, joints, weights); + get_vertex_weights(dag_path, mesh, joints, weights); } - if (got_weights) { + if (got_weights && !joints.empty()) { int num_joints = joints.size(); int num_weights = (int)weights.length(); int num_verts = num_weights / num_joints; @@ -1598,7 +1445,7 @@ make_polyset(const MDagPath &dag_path, const MFnMesh &mesh, //////////////////////////////////////////////////////////////////// void MayaToEggConverter:: make_locator(const MDagPath &dag_path, const MFnDagNode &dag_node, - EggGroup *egg_group, EggGroupNode *egg_root) { + EggGroup *egg_group) { MStatus status; unsigned int num_children = dag_node.childCount(); @@ -1650,7 +1497,6 @@ make_locator(const MDagPath &dag_path, const MFnDagNode &dag_node, //////////////////////////////////////////////////////////////////// bool MayaToEggConverter:: get_vertex_weights(const MDagPath &dag_path, const MFnMesh &mesh, - EggGroupNode *egg_root, pvector &joints, MFloatArray &weights) { MStatus status; @@ -1696,7 +1542,8 @@ get_vertex_weights(const MDagPath &dag_path, const MFnMesh &mesh, joints.clear(); for (unsigned oi = 0; oi < influence_objects.length(); oi++) { MDagPath joint_dag_path = influence_objects[oi]; - EggGroup *joint = get_egg_group(joint_dag_path, egg_root); + MayaNodeDesc *joint_node_desc = _tree.build_node(joint_dag_path); + EggGroup *joint = _tree.get_egg_group(joint_node_desc); joints.push_back(joint); } @@ -1736,189 +1583,6 @@ get_vertex_weights(const MDagPath &dag_path, const MFnMesh &mesh, return false; } - -//////////////////////////////////////////////////////////////////// -// Function: MayaToEggConverter::get_egg_group -// Access: Private -// Description: Returns the EggGroup corresponding to the indicated -// fully-qualified Maya path name. If there is not -// already an EggGroup corresponding to this Maya path, -// creates one and returns it. -// -// In this way we generate a unique EggGroup for each -// Maya node we care about about, and also preserve the -// Maya hierarchy sensibly. -//////////////////////////////////////////////////////////////////// -EggGroup *MayaToEggConverter:: -get_egg_group(const MDagPath &dag_path, EggGroupNode *egg_root) { - return r_get_egg_group(dag_path.fullPathName().asChar(), dag_path, egg_root); -} - -//////////////////////////////////////////////////////////////////// -// Function: MayaToEggConverter::r_get_egg_group -// Access: Private -// Description: The recursive implementation of get_egg_group(). -//////////////////////////////////////////////////////////////////// -EggGroup *MayaToEggConverter:: -r_get_egg_group(const string &name, const MDagPath &dag_path, - EggGroupNode *egg_root) { - // If we have already encountered this pathname, return the - // corresponding EggGroup immediately. - Groups::const_iterator gi = _groups.find(name); - if (gi != _groups.end()) { - return (*gi).second; - } - - // Otherwise, we have to create it. Do this recursively, so we - // create each node along the path. - EggGroup *egg_group; - - if (name.empty()) { - // This is the top. - egg_group = (EggGroup *)NULL; - - } else { - // Maya uses vertical bars to separate path components. Remove - // everything from the rightmost bar on; this will give us the - // parent's path name. - size_t bar = name.rfind("|"); - string parent_name, local_name; - if (bar != string::npos) { - parent_name = name.substr(0, bar); - local_name = name.substr(bar + 1); - } else { - local_name = name; - } - - EggGroup *parent_egg_group = - r_get_egg_group(parent_name, dag_path, egg_root); - egg_group = new EggGroup(local_name); - - if (parent_egg_group != (EggGroup *)NULL) { - parent_egg_group->add_child(egg_group); - } else { - egg_root->add_child(egg_group); - } - - // Check for an object type setting, from Oliver's plug-in. - MObject dag_object = 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); - } - - // 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" has meaning only to this converter. - if (egg_group->has_object_type("vertex-color")) { - egg_group->remove_object_type("vertex-color"); - MayaEggGroupUserData *user_data = new MayaEggGroupUserData; - user_data->_vertex_color = true; - egg_group->set_user_data(user_data); - } - } - - _groups.insert(Groups::value_type(name, egg_group)); - return egg_group; -} - -//////////////////////////////////////////////////////////////////// -// Function: MayaToEggConverter::get_egg_table -// Access: Private -// Description: Returns the EggTable corresponding to the indicated -// fully-qualified Maya path name. This is similar to -// get_egg_group(), but this variant is used only when -// we are building a channel file, which is just a -// hierarchical collection of animation tables. -//////////////////////////////////////////////////////////////////// -MayaToEggConverter::JointAnim *MayaToEggConverter:: -get_egg_table(const MDagPath &dag_path, EggGroupNode *egg_root) { - string name = dag_path.fullPathName().asChar(); - - // If we have already encountered this pathname, return the - // corresponding EggTable immediately. - Tables::const_iterator ti = _tables.find(name); - if (ti != _tables.end()) { - return (*ti).second; - } - - // Otherwise, we have to create it. - JointAnim *joint_anim; - - if (name.empty()) { - // This is the top. - joint_anim = (JointAnim *)NULL; - - } else { - // Maya uses vertical bars to separate path components. Remove - // everything from the rightmost bar on; this will give us the - // parent's path name. - size_t bar = name.rfind("|"); - string parent_name, local_name; - if (bar != string::npos) { - parent_name = name.substr(0, bar); - local_name = name.substr(bar + 1); - } else { - local_name = name; - } - - // Look only one level up for the parent. If it hasn't been - // defined yet, don't define it; instead, just start from the - // root. - JointAnim *parent_joint_anim = NULL; - if (!parent_name.empty()) { - ti = _tables.find(parent_name); - if (ti != _tables.end()) { - parent_joint_anim = (*ti).second; - } - } - - joint_anim = new JointAnim; - joint_anim->_dag_path = dag_path; - joint_anim->_table = new EggTable(local_name); - joint_anim->_anim = new EggXfmSAnim("xform", _egg_data->get_coordinate_system()); - joint_anim->_table->add_child(joint_anim->_anim); - - if (parent_joint_anim != (JointAnim *)NULL) { - parent_joint_anim->_table->add_child(joint_anim->_table); - } else { - egg_root->add_child(joint_anim->_table); - } - } - - _tables.insert(Tables::value_type(name, joint_anim)); - return joint_anim; -} - //////////////////////////////////////////////////////////////////// // Function: MayaShader::set_shader_attributes // Access: Private diff --git a/pandatool/src/mayaegg/mayaToEggConverter.h b/pandatool/src/mayaegg/mayaToEggConverter.h index 32c23e4666..d446b4ab52 100644 --- a/pandatool/src/mayaegg/mayaToEggConverter.h +++ b/pandatool/src/mayaegg/mayaToEggConverter.h @@ -21,6 +21,7 @@ #include "pandatoolbase.h" #include "somethingToEggConverter.h" +#include "mayaNodeTree.h" #include "mayaApi.h" #include "mayaShaders.h" @@ -79,12 +80,13 @@ public: 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(const MDagPath &dag_path, EggGroupNode *egg_root); - bool process_chan_node(const MDagPath &dag_path, EggGroupNode *egg_root); + bool process_model_node(MayaNodeDesc *node_desc); + void get_transform(const MDagPath &dag_path, EggGroup *egg_group); void get_joint_transform(const MDagPath &dag_path, EggGroup *egg_group); @@ -93,35 +95,22 @@ private: // reference. void make_nurbs_surface(const MDagPath &dag_path, MFnNurbsSurface &surface, - EggGroup *group, EggGroupNode *egg_root); + 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, EggGroupNode *egg_root); + EggGroup *group); void make_polyset(const MDagPath &dag_path, const MFnMesh &mesh, - EggGroup *egg_group, EggGroupNode *egg_root, + EggGroup *egg_group, MayaShader *default_shader = NULL); void make_locator(const MDagPath &dag_path, const MFnDagNode &dag_node, - EggGroup *egg_group, EggGroupNode *egg_root); + EggGroup *egg_group); bool get_vertex_weights(const MDagPath &dag_path, const MFnMesh &mesh, - EggGroupNode *egg_root, pvector &joints, MFloatArray &weights); - class JointAnim { - public: - MDagPath _dag_path; - EggTable *_table; - EggXfmSAnim *_anim; - }; - - EggGroup *get_egg_group(const MDagPath &dag_path, EggGroupNode *egg_root); - EggGroup *r_get_egg_group(const string &name, const MDagPath &dag_path, - EggGroupNode *egg_root); - JointAnim *get_egg_table(const MDagPath &dag_path, EggGroupNode *egg_root); - JointAnim *get_egg_table(const string &name, EggGroupNode *egg_root); void set_shader_attributes(EggPrimitive &primitive, const MayaShader &shader); void apply_texture_properties(EggTexture &tex, @@ -131,15 +120,11 @@ private: bool reparent_decals(EggGroupNode *egg_parent); - typedef pmap Groups; - Groups _groups; - - typedef pmap Tables; - Tables _tables; - string _program_name; bool _from_selection; + MayaNodeTree _tree; + public: MayaShaders _shaders; EggTextureCollection _textures;