diff --git a/pandatool/src/softegg/Sources.pp b/pandatool/src/softegg/Sources.pp new file mode 100755 index 0000000000..54dda0ea3b --- /dev/null +++ b/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 + diff --git a/pandatool/src/softegg/config_softegg.cxx b/pandatool/src/softegg/config_softegg.cxx new file mode 100755 index 0000000000..435a7ad00f --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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(); +} + diff --git a/pandatool/src/softegg/config_softegg.h b/pandatool/src/softegg/config_softegg.h new file mode 100755 index 0000000000..e0390cbf46 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 diff --git a/pandatool/src/softegg/softEggGroupUserData.I b/pandatool/src/softegg/softEggGroupUserData.I new file mode 100755 index 0000000000..1947473b78 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// 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 ©) : + 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 ©) { + EggUserData::operator = (copy); + _vertex_color = copy._vertex_color; + _double_sided = copy._double_sided; +} diff --git a/pandatool/src/softegg/softEggGroupUserData.cxx b/pandatool/src/softegg/softEggGroupUserData.cxx new file mode 100755 index 0000000000..f22667ceac --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#include "softEggGroupUserData.h" + +TypeHandle SoftEggGroupUserData::_type_handle; diff --git a/pandatool/src/softegg/softEggGroupUserData.h b/pandatool/src/softegg/softEggGroupUserData.h new file mode 100755 index 0000000000..3db88bfc02 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 ©); + INLINE void operator = (const SoftEggGroupUserData ©); + + 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 diff --git a/pandatool/src/softegg/softNodeDesc.cxx b/pandatool/src/softegg/softNodeDesc.cxx new file mode 100755 index 0000000000..377cfa5569 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 diff --git a/pandatool/src/softegg/softNodeDesc.h b/pandatool/src/softegg/softNodeDesc.h new file mode 100755 index 0000000000..90946920f8 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef SOFTNODEDESC_H +#define SOFTNODEDESC_H + +#include "pandatoolbase.h" + +#include "referenceCount.h" +#include "pointerTo.h" +#include "namable.h" + +#include + +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 diff --git a/pandatool/src/softegg/softNodeTree.cxx b/pandatool/src/softegg/softNodeTree.cxx new file mode 100755 index 0000000000..910ead6d40 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////// +// 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 + +//////////////////////////////////////////////////////////////////// +// 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; +} + +// +// +// diff --git a/pandatool/src/softegg/softNodeTree.h b/pandatool/src/softegg/softNodeTree.h new file mode 100755 index 0000000000..94dfcd6c1b --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#ifndef SOFTNODETREE_H +#define SOFTNODETREE_H + +#include "pandatoolbase.h" +#include "softNodeDesc.h" + +#include + +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 NodesByPath; + NodesByPath _nodes_by_path; +#endif + typedef pvector Nodes; + Nodes _nodes; +}; + +#endif diff --git a/pandatool/src/softegg/softToEggConverter.cxx b/pandatool/src/softegg/softToEggConverter.cxx new file mode 100755 index 0000000000..43ef8ae0df --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +#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 ©) : + _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 - Used to provide soft with the resource\n" + " Defaults to '/ful/ufs/soft371_mips2/3D/rsrc'.\n" + " -d - Database path.\n" + " -s - Indicates that a scene will be converted.\n" + " -m - Indicates that a model will be converted.\n" + " -t - Specify path to place converted textures.\n" + " -T - Specify filename for texture map listing.\n" + " -S - Specify step for nurbs surface triangulation.\n" + " -M - Specify model output filename. Defaults to scene name.\n" + " -A - Specify anim output filename. Defaults to scene name.\n" + " -N - 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 - Specify frame number for static pose.\n" + " -b - Specify starting frame for animation (default = first).\n" + " -e - Specify ending frame for animation (default = last).\n" + " -f - 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 - 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 - 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; idxadd_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 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 &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 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::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; +} +// +// +// diff --git a/pandatool/src/softegg/softToEggConverter.h b/pandatool/src/softegg/softToEggConverter.h new file mode 100755 index 0000000000..8292714108 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + +#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 +#include + +#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 ©); + 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 &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