Panda3D

mayaEggLoader.cxx

00001 // Filename: mayaEggImport.cxx
00002 // Created by:  jyelon (20Jul05)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 //
00015 // This file contains the code for class MayaEggLoader.  This class
00016 // does the actual work of copying an EggData tree into the maya scene.
00017 //
00018 ////////////////////////////////////////////////////////////////////
00019 
00020 
00021 #include "pandatoolbase.h"
00022 #include "notifyCategoryProxy.h"
00023 
00024 #include "eggBin.h"
00025 #include "eggData.h"
00026 #include "eggTable.h"
00027 #include "eggVertex.h"
00028 #include "eggPolygon.h"
00029 #include "eggComment.h"
00030 #include "eggXfmSAnim.h"
00031 #include "eggSAnimData.h"
00032 #include "eggPrimitive.h"
00033 #include "eggGroupNode.h"
00034 #include "eggVertexPool.h"
00035 #include "eggPolysetMaker.h"
00036 #include "eggNurbsSurface.h"
00037 #include "texture.h"
00038 #include "texturePool.h"
00039 
00040 #include "pre_maya_include.h"
00041 #include <maya/MStatus.h>
00042 #include <maya/MPxCommand.h>
00043 #include <maya/MString.h>
00044 #include <maya/MStringArray.h>
00045 #include <maya/MArgList.h>
00046 #include <maya/MGlobal.h>
00047 #include <maya/MObject.h>
00048 #include <maya/MFloatPoint.h>
00049 #include <maya/MFloatPointArray.h>
00050 #include <maya/MFloatArray.h>
00051 #include <maya/MPointArray.h>
00052 #include <maya/MFnMesh.h>
00053 #include <maya/MFnDependencyNode.h>
00054 #include <maya/MFnTransform.h>
00055 #include <maya/MFnLambertShader.h>
00056 #include <maya/MPlug.h>
00057 #include <maya/MFnSet.h>
00058 #include <maya/MDGModifier.h>
00059 #include <maya/MSelectionList.h>
00060 #include <maya/MDagPath.h>
00061 #include <maya/MFnSingleIndexedComponent.h>
00062 #include <maya/MFnDoubleIndexedComponent.h>
00063 #include <maya/MPlugArray.h>
00064 #include <maya/MDagPathArray.h>
00065 #include <maya/MMatrix.h>
00066 #include <maya/MTransformationMatrix.h>
00067 #include <maya/MFnIkJoint.h>
00068 #include <maya/MFnSkinCluster.h>
00069 #include <maya/MAnimControl.h>
00070 #include <maya/MFnAnimCurve.h>
00071 #include <maya/MFnNurbsSurface.h>
00072 #include <maya/MFnEnumAttribute.h>
00073 #include <maya/MFnSet.h>
00074 #include "post_maya_include.h"
00075 
00076 #include "mayaEggLoader.h"
00077 
00078 class MayaEggGroup;
00079 class MayaEggGeom;
00080 class MayaEggMesh;
00081 class MayaEggJoint;
00082 class MayaEggTex;
00083 class MayaAnim;
00084 class MayaEggNurbsSurface;
00085 
00086 NotifyCategoryDeclNoExport(mayaloader);
00087 NotifyCategoryDef(mayaloader, "");
00088 
00089 class MayaEggLoader
00090 {
00091 public:
00092   bool ConvertEggData(EggData *data,    bool merge, bool model, bool anim, bool respect_normals);
00093   bool ConvertEggFile(const char *name, bool merge, bool model, bool anim, bool respect_normals);
00094   
00095   
00096 public:
00097   void          TraverseEggNode(EggNode *node, EggGroup *context, string delim);
00098   MayaEggMesh  *GetMesh(EggVertexPool *pool, EggGroup *parent);
00099   MayaEggJoint *FindJoint(EggGroup *joint);
00100   MayaEggJoint *MakeJoint(EggGroup *joint, EggGroup *context);
00101   MayaEggGroup *FindGroup(EggGroup *group);
00102   MayaEggGroup *MakeGroup(EggGroup *group, EggGroup *context);
00103   MayaEggTex   *GetTex(EggTexture *etex);
00104   void          CreateSkinCluster(MayaEggGeom *M);
00105 
00106   MayaAnim *GetAnim(EggXfmSAnim *pool);
00107   MObject GetDependencyNode(string givenName);
00108 
00109   MayaEggNurbsSurface  *GetSurface(EggVertexPool *pool, EggGroup *parent);
00110 
00111   typedef phash_map<EggGroup *, MayaEggMesh *, pointer_hash> MeshTable;
00112   typedef phash_map<EggXfmSAnim *, MayaAnim *, pointer_hash> AnimTable;
00113   typedef phash_map<EggGroup *, MayaEggJoint *, pointer_hash> JointTable;
00114   typedef phash_map<EggGroup *, MayaEggGroup *, pointer_hash> GroupTable;
00115   typedef phash_map<string, MayaEggTex *, string_hash> TexTable;
00116   typedef phash_map<EggGroup *, MayaEggNurbsSurface *, pointer_hash> SurfaceTable;
00117 
00118   MeshTable        _mesh_tab;
00119   AnimTable        _anim_tab;
00120   JointTable       _joint_tab;
00121   GroupTable       _group_tab;
00122   TexTable         _tex_tab;
00123   SurfaceTable     _surface_tab;
00124 
00125   vector <MayaEggJoint *> _joint_list;
00126 
00127   int _start_frame;
00128   int _end_frame;
00129   int _frame_rate;
00130   MTime::Unit     _timeUnit;
00131 
00132   void ParseFrameInfo(string comment);
00133   void PrintData(MayaEggMesh *mesh);
00134 
00135 private:
00136   int _unnamed_idx;
00137   MSelectionList _collision_nodes;
00138 };
00139 
00140 MPoint MakeMPoint(const LVector3d &vec)
00141 {
00142   return MPoint(vec[0], vec[1], vec[2]);
00143 }
00144 
00145 MFloatPoint MakeMayaPoint(const LVector3d &vec)
00146 {
00147   return MFloatPoint(vec[0], vec[1], vec[2]);
00148 }
00149 
00150 MVector MakeMayaVector(const LVector3d &vec)
00151 {
00152   return MVector(vec[0], vec[1], vec[2]);
00153 }
00154 
00155 MColor MakeMayaColor(const LColor &vec)
00156 {
00157   return MColor(vec[0], vec[1], vec[2], vec[3]);
00158 }
00159 
00160 // [gjeon] to create enum attribute, 
00161 // fieldNames is a stringArray of enum names, and filedIndex is the default index value
00162 MStatus create_enum_attribute(MObject &node, MString fullName, MString briefName, 
00163                               MStringArray fieldNames, unsigned fieldIndex) {
00164   MStatus stat;
00165 
00166   MFnDependencyNode fnDN( node, &stat );
00167   if ( MS::kSuccess != stat ) {
00168     mayaloader_cat.error()
00169       << "Could not create MFnDependencyNode" << "\n";
00170     return stat;
00171   }
00172 
00173   MFnEnumAttribute fnAttr;
00174   MObject newAttr = fnAttr.create( fullName, briefName, 
00175                                    0, &stat );
00176   if ( MS::kSuccess != stat ) {
00177     mayaloader_cat.error()
00178       << "Could not create new enum attribute " << fullName << "\n";
00179     return stat;
00180   }
00181   for (unsigned i = 0; i < fieldNames.length(); i++){
00182     fnAttr.addField(fieldNames[i], i);
00183   }
00184 
00185   stat = fnAttr.setDefault(fieldIndex);
00186   if ( MS::kSuccess != stat ) {
00187     mayaloader_cat.error()
00188       << "Could not set value for enum attribute " << fullName << "\n";
00189     return stat;
00190   }
00191 
00192   fnAttr.setKeyable( true ); 
00193   fnAttr.setReadable( true ); 
00194   fnAttr.setWritable( true ); 
00195   fnAttr.setStorable( true ); 
00196 
00197   // Now add the new attribute to this dependency node
00198   stat = fnDN.addAttribute(newAttr,MFnDependencyNode::kLocalDynamicAttr);
00199   if ( MS::kSuccess != stat ) {
00200     mayaloader_cat.error()
00201       << "Could not add new enum attribute " << fullName << "\n";
00202     return stat;
00203   }
00204 
00205   return stat;
00206 }
00207 
00208 ////////////////////////////////////////////////////////////////////////////////////////////////////
00209 //
00210 // MayaEggTex
00211 //
00212 ////////////////////////////////////////////////////////////////////////////////////////////////////
00213 
00214 class MayaEggTex
00215 {
00216 public:
00217   string  _name;
00218   string  _path;
00219   MObject _file_texture;
00220   MObject _shader;
00221   MObject _shading_group;
00222   
00223   MFnSingleIndexedComponent _component;
00224   void AssignNames(void);
00225 };
00226 
00227 void MayaEggTex::AssignNames(void)
00228 {
00229   if (_name == "") {
00230     return;
00231   }
00232   MFnDependencyNode shader(_shader);
00233   MFnDependencyNode sgroup(_shading_group);
00234   MFnDependencyNode filetex(_file_texture);
00235   shader.setName(MString(_name.c_str())+"Shader");
00236   sgroup.setName(MString(_name.c_str()));
00237   if (_file_texture != MObject::kNullObj) {
00238     filetex.setName(MString(_name.c_str())+"File");
00239   }
00240 }
00241 
00242 MayaEggTex *MayaEggLoader::GetTex(EggTexture* etex)
00243 {
00244   string name = "";
00245   string fn = "";
00246   if (etex != NULL) {
00247     name = etex->get_name();
00248     fn = etex->get_fullpath().to_os_specific();
00249   }
00250 
00251   if (_tex_tab.count(fn)) {
00252     return _tex_tab[fn];
00253   }
00254 
00255   MStatus status;
00256   MFnLambertShader shader;
00257   MFnDependencyNode filetex;
00258   MFnSet sgroup;
00259   MPlugArray oldplugs;
00260   MDGModifier dgmod;
00261 
00262   /*
00263   if (fn=="") {
00264     MSelectionList selection;
00265     MObject initGroup;
00266     selection.clear();
00267     MGlobal::getSelectionListByName("initialShadingGroup",selection);
00268     selection.getDependNode(0, initGroup);
00269     sgroup.setObject(initGroup);
00270   } else {
00271   */
00272   if (1) {
00273     shader.create(true,&status);
00274     MColor firstColor(1.0,1.0,1.0,1.0);
00275     status = shader.setColor(firstColor);
00276     if (status != MStatus::kSuccess) {
00277       mayaloader_cat.error() << "setColor failed on LambertShader\n";
00278       status.perror("shader setColor failed!");
00279     }
00280     sgroup.create(MSelectionList(), MFnSet::kRenderableOnly, &status);
00281     MPlug surfplug = sgroup.findPlug("surfaceShader");
00282     if (surfplug.connectedTo(oldplugs,true,false)) {
00283       for (unsigned int i=0; i<oldplugs.length(); i++) {
00284         MPlug src = oldplugs[i];
00285         status = dgmod.disconnect(src, surfplug);
00286         if (status != MStatus::kSuccess) {
00287           status.perror("Disconnecting old shader");
00288         }
00289       }
00290     }
00291     status = dgmod.connect(shader.findPlug("outColor"),surfplug);
00292     if (status != MStatus::kSuccess) {
00293       status.perror("Connecting shader");
00294     }
00295     if (fn != "") {
00296       filetex.create("file",&status);
00297       MString fn_str(fn.c_str());
00298       filetex.findPlug("fileTextureName").setValue(fn_str);
00299       dgmod.connect(filetex.findPlug("outColor"),shader.findPlug("color"));
00300 
00301       // [gjeon] to create alpha channel connection
00302       LoaderOptions options;
00303       PT(Texture) tex = TexturePool::load_texture(etex->get_fullpath(), 0, false, options);
00304       if (((tex != NULL) && (tex->get_num_components() == 4)) 
00305           || (etex->get_format() == EggTexture::F_alpha) 
00306           || (etex->get_format() == EggTexture::F_luminance_alpha))
00307         dgmod.connect(filetex.findPlug("outTransparency"),shader.findPlug("transparency"));
00308     }
00309     status = dgmod.doIt();
00310     if (status != MStatus::kSuccess) {
00311       status.perror("DGMod doIt");
00312     }
00313   }
00314 
00315   MayaEggTex *res = new MayaEggTex;
00316   res->_name = name;
00317   res->_path = fn;
00318   res->_file_texture = filetex.object();
00319   res->_shader = shader.object();
00320   res->_shading_group = sgroup.object();
00321   
00322   _tex_tab[fn] = res;
00323   return res;
00324 }
00325 
00326 ////////////////////////////////////////////////////////////////////////////////////////////////////
00327 //
00328 // MayaEggGroup
00329 //
00330 ////////////////////////////////////////////////////////////////////////////////////////////////////
00331 
00332 class MayaEggGroup
00333 {
00334 public:
00335   string  _name;
00336   MObject _parent;
00337   MObject _group;
00338 
00339   bool _addedEggFlag;
00340 };
00341 
00342 MayaEggGroup *MayaEggLoader::MakeGroup(EggGroup *group, EggGroup *context)
00343 {
00344   MStatus status;
00345   MayaEggGroup *pg = FindGroup(context);
00346   MayaEggGroup *result = new MayaEggGroup;
00347   MFnDagNode dgn;
00348 
00349   MObject parent = MObject::kNullObj;
00350   if (pg) {
00351     parent = pg->_group;
00352     if (mayaloader_cat.is_debug()) {
00353       mayaloader_cat.debug() << "parent (group) :" << ((MFnDagNode)parent).name().asChar() << endl;
00354     }
00355   }
00356 
00357   result->_name = group->get_name();
00358   result->_group = dgn.create("transform", MString(result->_name.c_str()), parent, &status);
00359   result->_addedEggFlag = false;
00360 
00361   if (group->get_cs_type() != EggGroup::CST_none)
00362     _collision_nodes.add(result->_group, true);
00363 
00364   if (group->has_transform3d()) {
00365     LMatrix4d tMat = group->get_transform3d();
00366     double matData[4][4] = {{tMat.get_cell(0,0), tMat.get_cell(0,1), tMat.get_cell(0,2), tMat.get_cell(0,3)},
00367                   {tMat.get_cell(1,0), tMat.get_cell(1,1), tMat.get_cell(1,2), tMat.get_cell(1,3)},
00368                   {tMat.get_cell(2,0), tMat.get_cell(2,1), tMat.get_cell(2,2), tMat.get_cell(2,3)},
00369                   {tMat.get_cell(3,0), tMat.get_cell(3,1), tMat.get_cell(3,2), tMat.get_cell(3,3)}};
00370     MMatrix mat(matData);
00371 
00372     MTransformationMatrix matrix = MTransformationMatrix(mat);
00373     MFnTransform tFn = MFnTransform(result->_group, &status);
00374     if (status != MStatus::kSuccess) {
00375       status.perror("MFnTransformNode:create failed!");
00376     } else {
00377       tFn.set(matrix);
00378     }
00379   }
00380 
00381   if (status != MStatus::kSuccess) {
00382     status.perror("MFnDagNode:create failed!");
00383   }
00384 
00385   if ((pg) && (pg->_addedEggFlag == false)){
00386     // [gjeon] to handle other flags
00387     MStringArray eggFlags;
00388     for (int i = 0; i < context->get_num_object_types(); i++) {
00389       eggFlags.append(MString(context->get_object_type(i).c_str()));
00390     }    
00391 
00392     for (unsigned i = 0; i < eggFlags.length(); i++) {
00393       MString attrName = "eggObjectTypes";
00394       attrName += (int)(i + 1);
00395       status = create_enum_attribute(parent, attrName, attrName, eggFlags, i);
00396       if (status != MStatus::kSuccess) {
00397         status.perror("create_enum_attribute failed!");
00398       }
00399     }
00400     pg->_addedEggFlag = true;
00401   }
00402 
00403   _group_tab[group] = result;
00404   return result;
00405 }
00406 
00407 MayaEggGroup *MayaEggLoader::FindGroup(EggGroup *group)
00408 {
00409   if (group==0) {
00410     return 0;
00411   }
00412   return _group_tab[group];
00413 }
00414 
00415 ////////////////////////////////////////////////////////////////////////////////////////////////////
00416 //
00417 // MayaEggJoint
00418 //
00419 ////////////////////////////////////////////////////////////////////////////////////////////////////
00420 
00421 class MayaEggJoint
00422 {
00423 public:
00424   LMatrix4d      _trans;
00425   LVector3d      _endpos;
00426   LVector3d      _perp;
00427   double         _thickness;
00428   MObject        _joint;
00429   MMatrix        _joint_abs;
00430   MDagPath       _joint_dag_path;
00431   bool           _inskin;
00432   int            _index;
00433   EggGroup       *_egg_joint;
00434   EggGroup       *_egg_parent;
00435   MayaEggJoint   *_parent;
00436   vector <MayaEggJoint *> _children;
00437 
00438 public:
00439   void GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv);
00440   LVector3d GetPos(void) { return _trans.get_row3(3); }
00441   MayaEggJoint *ChooseBestChild(LVector3d dir);
00442   void ChooseEndPos(double thickness);
00443   void CreateMayaBone(MayaEggGroup *eggParent);
00444   void AssignNames(void);
00445 };
00446 
00447 void MayaEggJoint::GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv)
00448 {
00449   xv = _trans.get_row3(0);
00450   yv = _trans.get_row3(1);
00451   zv = _trans.get_row3(2);
00452   xv.normalize();
00453   yv.normalize();
00454   zv = xv.cross(yv);
00455   zv.normalize();
00456   yv = zv.cross(xv);
00457 }
00458 
00459 void MayaEggJoint::AssignNames(void)
00460 {
00461   string name = _egg_joint->get_name();
00462   MFnDependencyNode joint(_joint);
00463   joint.setName(name.c_str());
00464   if (mayaloader_cat.is_spam()) {
00465     mayaloader_cat.spam() << "joint " << joint.name().asChar() << ": -> " << name << endl;
00466   }
00467 }
00468 
00469 MayaEggJoint *MayaEggLoader::FindJoint(EggGroup *joint)
00470 {
00471   if (joint==(EggGroup *)NULL) {
00472     if (mayaloader_cat.is_spam()) {
00473       mayaloader_cat.spam() << "joint:" << joint->get_name() << " is null: " << endl;
00474     }
00475     return 0;
00476   }
00477   if (!joint->is_joint()) {
00478     if (mayaloader_cat.is_spam()) {
00479       mayaloader_cat.spam() << "joint:" << joint->get_name() << " is not a joint: " << endl;
00480     }
00481     return 0;
00482   }
00483   return _joint_tab[joint];
00484 }
00485 
00486 MayaEggJoint *MayaEggLoader::MakeJoint(EggGroup *joint, EggGroup *context)
00487 {
00488   MayaEggJoint *parent = FindJoint(context);
00489   if (mayaloader_cat.is_debug()) {
00490     string parent_name = "";
00491     if (parent)
00492       parent_name = context->get_name();
00493   }
00494   MayaEggJoint *result = new MayaEggJoint;
00495   LMatrix4d t = joint->get_transform3d();
00496   if (parent) {
00497     result->_trans = t * parent->_trans;
00498   } else {
00499     result->_trans = t;
00500   }
00501   result->_endpos = LVector3d(0,0,0);
00502   result->_perp = LVector3d(0,0,0);
00503   result->_thickness = 0.0;
00504   result->_egg_joint = joint;
00505   result->_egg_parent = context;
00506   result->_parent = parent;
00507   result->_joint = MObject::kNullObj;
00508   result->_inskin = false;
00509   result->_index = -1;
00510   if (parent) {
00511     parent->_children.push_back(result);
00512   }
00513   _joint_tab[joint] = result;
00514 
00515   // [gjeon] since _joint_tab is not always properly sorted
00516   _joint_list.push_back(result);
00517 
00518   return result;
00519 }
00520 
00521 MayaEggJoint *MayaEggJoint::ChooseBestChild(LVector3d dir)
00522 {
00523   if (dir.length() < 0.001) {
00524     return 0;
00525   }
00526   dir.normalize();
00527   double firstbest = -1000;
00528   MayaEggJoint *firstchild = 0;
00529   LVector3d firstpos = GetPos();
00530   double secondbest = 0;
00531   for (unsigned int i=0; i<_children.size(); i++) {
00532     MayaEggJoint *child = _children[i];
00533     LVector3d tryfwd = child->GetPos() - GetPos();
00534     if ((child->GetPos() != firstpos) && (tryfwd.length() > 0.001)) {
00535       LVector3d trydir = tryfwd;
00536       trydir.normalize();
00537       double quality = trydir.dot(dir);
00538       if (quality > firstbest) {
00539         secondbest = firstbest;
00540         firstbest = quality;
00541         firstpos = child->GetPos();
00542         firstchild = child;
00543       } else if (quality > secondbest) {
00544         secondbest = quality;
00545       }
00546     }
00547   }
00548   if (firstbest > secondbest + 0.1) {
00549     return firstchild;
00550   }
00551   return 0;
00552 }
00553 
00554 void MayaEggJoint::ChooseEndPos(double thickness)
00555 {
00556   LVector3d parentpos(0,0,0);
00557   LVector3d parentendpos(0,0,1);
00558   if (_parent) {
00559     parentpos = _parent->GetPos();
00560     parentendpos = _parent->_endpos;
00561   }
00562   LVector3d fwd = GetPos() - parentpos;
00563   if (fwd.length() < 0.001) {
00564     fwd = parentendpos - parentpos;
00565   }
00566   //mayaloader_cat.debug() << "fwd : " << fwd << endl;
00567   fwd.normalize();
00568   MayaEggJoint *child = ChooseBestChild(fwd);
00569   if (child == 0) {
00570     _endpos = fwd * thickness * 0.8 + GetPos();
00571     _thickness = thickness * 0.8;
00572   } else {
00573     _endpos = child->GetPos();
00574     _thickness = (_endpos - GetPos()).length();
00575     if (_thickness > thickness) _thickness = thickness;
00576   }
00577   LVector3d orient = _endpos - GetPos();
00578   orient.normalize();
00579   LVector3d altaxis = orient.cross(LVector3d(0,-1,0));
00580   if (altaxis.length() < 0.001) {
00581     altaxis = orient.cross(LVector3d(0,0,1));
00582   }
00583   _perp = altaxis.cross(orient);
00584   _perp.normalize();
00585 }
00586 
00587 void MayaEggJoint::CreateMayaBone(MayaEggGroup *eggParent)
00588 {
00589   LVector3d rxv, ryv, rzv;
00590   //GetRotation(rxv, ryv, rzv);
00591   // [gjeon] I think we shouldn't need to use this GetRotation function here
00592   // since this function removes scale information from the matrix.
00593   // Let's just use the matrix directly.
00594   rxv = _trans.get_row3(0);
00595   ryv = _trans.get_row3(1);
00596   rzv = _trans.get_row3(2);
00597 
00598   MFloatPoint xv(MakeMayaPoint(rxv));
00599   MFloatPoint yv(MakeMayaPoint(ryv));
00600   MFloatPoint zv(MakeMayaPoint(rzv));
00601   MFloatPoint pos(MakeMayaPoint(GetPos()));
00602   MFloatPoint endpos(MakeMayaPoint(_endpos));
00603   MFloatPoint tzv(MakeMayaPoint(_perp));
00604   double m[4][4];
00605   m[0][0]=xv.x;  m[0][1]=xv.y;  m[0][2]=xv.z;  m[0][3]=0;
00606   m[1][0]=yv.x;  m[1][1]=yv.y;  m[1][2]=yv.z;  m[1][3]=0;
00607   m[2][0]=zv.x;  m[2][1]=zv.y;  m[2][2]=zv.z;  m[2][3]=0;
00608   m[3][0]=pos.x; m[3][1]=pos.y; m[3][2]=pos.z; m[3][3]=1;
00609   MMatrix trans(m);
00610   _joint_abs = trans;
00611   if (_parent) {
00612     trans = trans * _parent->_joint_abs.inverse();
00613   }
00614   MTransformationMatrix mtm(trans);
00615 
00616   MFnIkJoint ikj;
00617   if (_parent) {
00618     ikj.create(_parent->_joint);
00619   }
00620   else {
00621     if (eggParent) {
00622       // must be part of a group that is not a joint
00623       ikj.create(eggParent->_group);
00624     } else {
00625       ikj.create();
00626     }
00627   }
00628   ikj.set(mtm);
00629   
00630   _joint = ikj.object();
00631   ikj.getPath(_joint_dag_path);
00632 }
00633 
00634 
00635 ////////////////////////////////////////////////////////////////////////////////////////////////////
00636 //
00637 // MayaEggGeom : base abstract class of MayaEggMesh and MayaEggNurbsSurface
00638 //
00639 ////////////////////////////////////////////////////////////////////////////////////////////////////
00640 
00641 typedef pair<double, EggGroup *> MayaEggWeight;
00642 
00643 struct MayaEggVertex
00644 {
00645   LVertexd               _pos;
00646   LNormald               _normal;
00647   LTexCoordd             _uv;
00648   vector<MayaEggWeight> _weights;
00649   double                _sumWeights; // [gjeon] to be used in normalizing weights
00650   int                   _index; 
00651   int                   _external_index; // masad: use egg's index directly
00652 };
00653 
00654 struct MEV_Compare: public stl_hash_compare<MayaEggVertex>
00655 {
00656   size_t operator()(const MayaEggVertex &key) const
00657   {
00658     return key._pos.add_hash(key._normal.get_hash());
00659   }
00660   bool operator()(const MayaEggVertex &k1, const MayaEggVertex &k2) const
00661   {
00662     int n = k1._pos.compare_to(k2._pos);
00663     if (n < 0) {
00664       return true;
00665     }
00666     if (n > 0) {
00667       return false;
00668     }
00669     n = k1._normal.compare_to(k2._normal);
00670     if (n < 0) {
00671       return true;
00672     }
00673     if (n > 0) {
00674       return false;
00675     }
00676     n = k1._uv.compare_to(k2._uv);
00677     if (n < 0) {
00678       return true;
00679     }
00680     if (n > 0) {
00681       return false;
00682     }
00683     n = k1._weights.size() - k2._weights.size();
00684     if (n < 0) {
00685       return true;
00686     }
00687     if (n > 0) {
00688       return false;
00689     }
00690     for (unsigned int i=0; i<k1._weights.size(); i++) {
00691       double d = k1._weights[i].first - k2._weights[i].first;
00692       if (d < 0) {
00693         return true;
00694       }
00695       if (d > 0) {
00696         return false;
00697       }
00698       EggGroup *g1 = k1._weights[i].second;
00699       EggGroup *g2 = k2._weights[i].second;
00700       if (g1 < g2) {
00701         return true;
00702       }
00703       if (g1 > g2) {
00704         return false;
00705       }
00706     }
00707     n = k1._external_index - k2._external_index;
00708 
00709     if (n < 0) {
00710       return true;
00711     }
00712     if (n > 0) {
00713       return false;
00714     }
00715 
00716     return false;
00717   }
00718 };
00719 
00720 typedef phash_set<MayaEggVertex, MEV_Compare> VertTable;
00721 
00722 class MayaEggGeom
00723 {
00724 public:
00725   
00726   EggVertexPool      *_pool;
00727   MObject             _transNode;
00728   MObject             _shapeNode;
00729   EggGroup            *_parent;
00730   MDagPath            _shape_dag_path;
00731   int                 _vert_count;  
00732 
00733   string _name;
00734   
00735   MFloatPointArray    _vertexArray;
00736   MVectorArray        _normalArray;
00737   MColorArray         _vertColorArray;
00738   MIntArray           _vertColorIndices;
00739   MIntArray           _vertNormalIndices;
00740 
00741   MStringArray        _eggObjectTypes;
00742   VertTable  _vert_tab;
00743   
00744   bool                _renameTrans;
00745 
00746   int GetVert(EggVertex *vert, EggGroup *context);
00747   EggGroup *GetControlJoint(void);
00748 
00749   virtual void ConnectTextures(void) = 0;
00750   void AssignNames(void);
00751   void AddEggFlag(MString);
00752 };
00753 
00754 // [gjeon] moved from MayaEggMesh to MayaEggGeom
00755 int MayaEggGeom::GetVert(EggVertex *vert, EggGroup *context)
00756 {
00757   MayaEggVertex vtx;
00758   vtx._sumWeights = 0.0;
00759 
00760   const LMatrix4d &xform = context->get_vertex_to_node();
00761 
00762   vtx._pos = vert->get_pos3() * xform;
00763   if (vert->has_normal()) {
00764     vtx._normal = vert->get_normal() * xform;
00765   }
00766   if (vert->has_uv()) {
00767     vtx._uv = vert->get_uv();
00768   }
00769   vtx._index = 0;
00770   vtx._external_index = vert->get_index()-1;
00771 
00772   EggVertex::GroupRef::const_iterator gri;
00773   //double remaining_weight = 1.0;
00774   for (gri = vert->gref_begin(); gri != vert->gref_end(); ++gri) {
00775     EggGroup *egg_joint = (*gri);
00776     double membership = egg_joint->get_vertex_membership(vert);
00777 
00778     if (membership < 0)
00779     {
00780       mayaloader_cat.warning() << "negative weight value " << membership << " is replaced with 0 on: " << context->get_name() << endl;
00781       membership = 0.0;
00782     }
00783     //remaining_weight -= membership;
00784     vtx._weights.push_back(MayaEggWeight(membership, egg_joint));
00785     vtx._sumWeights += membership; // [gjeon] to be used in normalizing weights
00786   }
00787   
00788   if (vtx._weights.size()==0) {
00789     if (context != 0) {
00790       vtx._weights.push_back(MayaEggWeight(1.0, context));
00791       vtx._sumWeights = 1.0; // [gjeon] to be used in normalizing weights
00792     }
00793     //remaining_weight = 0.0;
00794   }/* else {
00795     // some soft models came up short of 1.0 on vertex membership
00796     // add the remainder of the weight on first joint in the membership
00797         if ((remaining_weight) > 0.01) {
00798       gri = vert->gref_begin();
00799       EggGroup *egg_joint = (*gri);
00800       double membership = egg_joint->get_vertex_membership(vert);
00801       vtx._weights.push_back(MayaEggWeight(membership+remaining_weight, egg_joint));
00802       vtx._sumWeights += (membership + remaining_weight);
00803     }
00804     }*/ //[gjeon] we had better nomarlize weights than add remaining weight to first weight
00805 
00806   VertTable::const_iterator vti = _vert_tab.find(vtx);
00807   if (vti != _vert_tab.end()) {
00808     /*    if ((remaining_weight) > 0.01) {
00809       mayaloader_cat.warning() << "weight munged to 1.0 by " << remaining_weight << " on: " << context->get_name() << " idx:" << vti->_index << endl;
00810       } */   
00811     if (mayaloader_cat.is_spam()) {
00812       ostringstream stream;
00813       stream << "(" << vti->_pos << " " << vti->_normal << " " << vti->_uv << ")\n";
00814       stream << "[" << vtx._pos << " " << vtx._normal << " " << vtx._uv << "]\n";
00815       stream << "{" << vert->get_pos3() << " ";
00816       if (vert->has_normal()) {
00817         stream << vert->get_normal() << " ";
00818       }
00819       if (vert->has_uv()) {
00820         stream << vert->get_uv();
00821       }
00822       stream << "}";
00823       mayaloader_cat.spam() << "found a matching vertex: " << *vert << endl << stream.str() << endl;
00824     }
00825     return vti->_index;
00826   }
00827   
00828   //_vert_count++;
00829   vtx._index = _vert_count++;
00830   /*
00831   if ((remaining_weight) > 0.01) {
00832     mayaloader_cat.warning() << "weight munged to 1.0 by " << remaining_weight << " on: " << context->get_name() << " idx:" << vtx._index << endl;
00833     } */   
00834 
00835   _vertexArray.append(MakeMayaPoint(vtx._pos));
00836   if (vert->has_normal()) {
00837     _normalArray.append(MakeMayaVector(vtx._normal));
00838     _vertNormalIndices.append(vtx._index);
00839   }
00840   if (vert->has_color()) {
00841     if (mayaloader_cat.is_spam()) {
00842       mayaloader_cat.spam() << "found a vertex color\n";
00843     }
00844     _vertColorArray.append(MakeMayaColor(vert->get_color()));
00845     _vertColorIndices.append(vtx._index);
00846   }
00847   _vert_tab.insert(vtx);
00848   return vtx._index;
00849 }
00850 
00851 // [gjeon] moved from MayaEggMesh to MayaEggGeom
00852 void MayaEggGeom::AssignNames(void)
00853 {
00854   string name = _pool->get_name();
00855   int nsize = name.size();
00856   if ((nsize > 6) && (name.rfind(".verts")==(nsize-6))) {
00857     name.resize(nsize-6);
00858   }
00859   if ((nsize > 4) && (name.rfind(".cvs")==(nsize-4))) {
00860     name.resize(nsize-4);
00861   }
00862 
00863   MFnDependencyNode dnshape(_shapeNode);
00864   MFnDependencyNode dntrans(_transNode);
00865 
00866   if (_renameTrans) {
00867     dntrans.setName(MString(name.c_str()));
00868   }
00869 
00870   string shape_name = string(dntrans.name().asChar());
00871   string numbers ("0123456789");
00872   size_t found;
00873   
00874   found=shape_name.find_last_not_of(numbers);
00875   if (found!=string::npos)
00876     shape_name.insert(found+1, "Shape");
00877   else
00878     shape_name.append("Shape");
00879 
00880   dnshape.setName(MString(shape_name.c_str()));
00881 }
00882 
00883 #define CTRLJOINT_DEFORM ((EggGroup*)((char*)(-1)))
00884 
00885 // [gjeon] moved from MayaEggMesh to MayaEggGeom
00886 EggGroup *MayaEggGeom::GetControlJoint(void)
00887 {
00888   EggGroup *result;
00889   VertTable::const_iterator vert = _vert_tab.begin();
00890   if (vert == _vert_tab.end()) {
00891     return 0;
00892   }
00893   switch (vert->_weights.size()) {
00894   case 0: 
00895     for (++vert; vert != _vert_tab.end(); ++vert) {
00896       if (vert->_weights.size() != 0) {
00897         return CTRLJOINT_DEFORM;
00898       }
00899     }
00900     return 0;
00901   case 1:
00902     result = vert->_weights[0].second;
00903     for (++vert; vert != _vert_tab.end(); ++vert) {
00904       if ((vert->_weights.size() != 1) || (vert->_weights[0].second != result)) {
00905         return CTRLJOINT_DEFORM;
00906       }
00907     }
00908     return result;
00909   default:
00910     return CTRLJOINT_DEFORM;
00911   }
00912 }
00913 
00914 void MayaEggGeom::AddEggFlag(MString fieldName) {
00915   bool addNewFlag = true;
00916   for (unsigned i = 0; i < _eggObjectTypes.length(); i++) {
00917     if (_eggObjectTypes[i] == fieldName) {
00918       addNewFlag = false;
00919       break;
00920     }
00921   }
00922   if (addNewFlag) {
00923     _eggObjectTypes.append(fieldName);
00924   }
00925 }
00926 
00927 ////////////////////////////////////////////////////////////////////////////////////////////////////
00928 //
00929 // MayaEggMesh
00930 //
00931 ////////////////////////////////////////////////////////////////////////////////////////////////////
00932 typedef phash_map<LTexCoordd, int>             TVertTable;
00933 typedef phash_map<LColor, int>                CVertTable;
00934 
00935 class MayaEggMesh : public MayaEggGeom
00936 {
00937 public:
00938   MColorArray         _faceColorArray;
00939   MIntArray           _faceIndices;
00940   MIntArray           _polygonCounts;
00941   MIntArray           _polygonConnects;
00942   MFloatArray         _uarray;
00943   MFloatArray         _varray;
00944   MIntArray           _uvIds;
00945 
00946 
00947   int                 _tvert_count;
00948   int                 _cvert_count;
00949   int                 _face_count;
00950   vector<MayaEggTex*> _face_tex;
00951   
00952   TVertTable _tvert_tab;
00953   CVertTable _cvert_tab;
00954   
00955   int GetTVert(const LTexCoordd &uv);
00956   int GetCVert(const LColor &col);
00957   int AddFace(unsigned numVertices, MIntArray mvertIndices, MIntArray mtvertIndices, MayaEggTex *tex);
00958 
00959   void ConnectTextures(void);
00960 };
00961 
00962 int MayaEggMesh::GetTVert(const LTexCoordd &uv)
00963 {
00964   if (_tvert_tab.count(uv)) {
00965     if (mayaloader_cat.is_spam()) {
00966       mayaloader_cat.spam() << "found uv coords idx: " << _tvert_tab[uv] << endl;
00967     }
00968     return _tvert_tab[uv];
00969   }
00970   int idx = _tvert_count++;
00971   _uarray.append(uv.get_x());
00972   _varray.append(uv.get_y());
00973   _tvert_tab[uv] = idx;
00974   if (mayaloader_cat.is_spam()) {
00975     mayaloader_cat.spam() << "adding uv coords idx:" << idx << endl;
00976   }
00977   return idx;
00978 }
00979 
00980 int MayaEggMesh::GetCVert(const LColor &col)
00981 {
00982   //  if (_cvert_tab.count(col))
00983   //    return _cvert_tab[col];
00984   //  if (_cvert_count == _mesh->numCVerts) {
00985   //    int nsize = _cvert_count*2 + 100;
00986   //    _mesh->setNumVertCol(nsize, _cvert_count?TRUE:FALSE);
00987   //  }
00988   //  int idx = _cvert_count++;
00989   //  _mesh->vertCol[idx] = Point3(col.get_x(), col.get_y(), col.get_z());
00990   //  _cvert_tab[col] = idx;
00991   //  return idx;
00992   return 0;
00993 }
00994 
00995 MayaEggMesh *MayaEggLoader::GetMesh(EggVertexPool *pool, EggGroup *parent)
00996 {
00997   MayaEggMesh *result = _mesh_tab[parent];
00998   if (result == 0) {
00999     result = new MayaEggMesh;
01000     result->_name = parent->get_name();
01001     result->_pool = pool;
01002     result->_parent = parent;
01003     result->_vert_count = 0;
01004     result->_tvert_count = 0;
01005     result->_cvert_count = 0;
01006     result->_face_count = 0;
01007     result->_vertColorArray.clear();
01008     result->_vertNormalIndices.clear();
01009     result->_vertColorIndices.clear();
01010     result->_faceColorArray.clear();
01011     result->_faceIndices.clear();
01012     result->_eggObjectTypes.clear();
01013     result->_renameTrans = false;
01014     _mesh_tab[parent] = result;
01015   }
01016   return result;
01017 }
01018 
01019 int MayaEggMesh::AddFace(unsigned numVertices, MIntArray mvertIndices, MIntArray mtvertIndices, MayaEggTex *tex)
01020 {
01021   int idx = _face_count++;
01022   _polygonCounts.append(numVertices);
01023   for (unsigned i = 0; i < mvertIndices.length(); i++)
01024   {
01025     _polygonConnects.append(mvertIndices[i]);
01026     _uvIds.append(mtvertIndices[i]);
01027   }
01028   _face_tex.push_back(tex);
01029   return idx;
01030 }
01031 
01032 void MayaEggMesh::ConnectTextures(void)
01033 {
01034   bool subtex = false;
01035   for (int i=1; i<_face_count; i++) {
01036     if (_face_tex[i] != _face_tex[0]) {
01037       subtex = true;
01038     }
01039   }
01040   if (!subtex) {
01041     MFnSet sg(_face_tex[0]->_shading_group);
01042     sg.addMember(_shapeNode);
01043     return;
01044   }
01045   for (int i=0; i<_face_count; i++) {
01046     MayaEggTex *tex = _face_tex[i];
01047     if (tex->_component.object()==MObject::kNullObj) {
01048       tex->_component.create(MFn::kMeshPolygonComponent);
01049     }
01050     tex->_component.addElement(i);
01051   }
01052   for (int i=0; i<_face_count; i++) {
01053     MayaEggTex *tex = _face_tex[i];
01054     if (tex->_component.object()!=MObject::kNullObj) {
01055       MFnSet sg(tex->_shading_group);
01056       sg.addMember(_shape_dag_path, tex->_component.object());
01057       tex->_component.setObject(MObject::kNullObj);
01058     }
01059   }
01060 }
01061 
01062 
01063 ////////////////////////////////////////////////////////////////////////////////////////////////////
01064 //
01065 // MayaEggNurbsSurface
01066 //
01067 ////////////////////////////////////////////////////////////////////////////////////////////////////
01068 class MayaEggNurbsSurface : public MayaEggGeom
01069 {
01070 public:
01071 
01072 
01073   MPointArray         _cvArray;
01074   MDoubleArray        _uKnotArray;
01075   MDoubleArray        _vKnotArray;
01076   unsigned            _uDegree;
01077   unsigned            _vDegree;
01078   unsigned            _uNumCvs;
01079   unsigned            _vNumCvs;
01080 
01081   MFnNurbsSurface::Form _uForm;
01082   MFnNurbsSurface::Form _vForm;
01083 
01084   MayaEggTex          *_tex;
01085 
01086   void ConnectTextures(void);
01087   void PrintData(void);
01088 };
01089 
01090 MayaEggNurbsSurface *MayaEggLoader::GetSurface(EggVertexPool *pool, EggGroup *parent)
01091 {
01092   MayaEggNurbsSurface *result = _surface_tab[parent];
01093   if (result == 0) {
01094     result = new MayaEggNurbsSurface;
01095     result->_pool = pool;
01096     result->_parent = parent;
01097     result->_name = parent->get_name();
01098 
01099     result->_vert_count = 0;
01100     result->_vertColorArray.clear();
01101     result->_vertNormalIndices.clear();
01102     result->_vertColorIndices.clear();
01103 
01104     result->_cvArray.clear();
01105     result->_uKnotArray.clear();
01106     result->_vKnotArray.clear();
01107 
01108     result->_uDegree = 0;
01109     result->_vDegree = 0;
01110     result->_uNumCvs = 0;
01111     result->_vNumCvs = 0;
01112     result->_uForm = MFnNurbsSurface::kClosed;
01113     result->_vForm = MFnNurbsSurface::kClosed;
01114 
01115     result->_eggObjectTypes.clear();
01116     result->_renameTrans = false;
01117     _surface_tab[parent] = result;
01118   }
01119   return result;
01120 }
01121 
01122 void MayaEggNurbsSurface::ConnectTextures(void)
01123 {
01124   // masad: since nurbs surfaces do not support vertex colors
01125   // I am infusing the surface's first vertex color (if any)
01126   // into the shader to achive the color.
01127   // masad: check if there is any vertex color for this surface
01128   MStatus status;
01129   MColor firstColor(0.5,0.5,0.5,1.0);
01130   if (_vertColorArray.length() > 0) {
01131     firstColor = _vertColorArray[0];
01132     MFnLambertShader sh(_tex->_shader);
01133     status = sh.setColor(firstColor);
01134     if (status != MStatus::kSuccess) {
01135       mayaloader_cat.error() << "setColor failed on " << _name;
01136       status.perror("shader setColor failed!");
01137     }
01138   }
01139   MFnSet sg(_tex->_shading_group);
01140   status = sg.addMember(_shapeNode);
01141   if (status != MStatus::kSuccess) {
01142     mayaloader_cat.error() << "addMember failed on " << _name;
01143     status.perror("shader addMember failed!");
01144   }
01145   return;
01146 }
01147 
01148 void MayaEggNurbsSurface::PrintData(void)
01149 {
01150   if (mayaloader_cat.is_debug()) {
01151     mayaloader_cat.debug() << "nurbsSurface : " << _name << endl;
01152     
01153     mayaloader_cat.debug() << "u_form : " << _uForm << endl;
01154     mayaloader_cat.debug() << "v_form : " << _vForm << endl;
01155   }
01156 
01157   /*
01158   for (unsigned i = 0; i < _cvArray.length(); i++)
01159   {
01160     MPoint cv =_cvArray[i];
01161     mayaloader_cat.debug() << cv[0] << " " << cv[1] << " " << cv[2] << endl;
01162   }
01163   
01164   for (unsigned i = 0; i < _uKnotArray.length(); i++)
01165   {
01166     mayaloader_cat.debug() << _uKnotArray[i] << endl;
01167   }
01168 
01169   for (unsigned i = 0; i < _vKnotArray.length(); i++)
01170   {
01171     mayaloader_cat.debug() << _vKnotArray[i] << endl;
01172   }
01173   */
01174 }
01175 
01176 ///////////////////////////////////////////////////////////////////////////////////////////////////
01177 //
01178 // MayaAnim: 
01179 //
01180 ///////////////////////////////////////////////////////////////////////////////////////////////////
01181 class MayaAnim
01182 {
01183 public:
01184   string  _name;
01185   EggTable *_joint;
01186   EggXfmSAnim *_pool;
01187   void PrintData(void);
01188 };
01189 
01190 MayaAnim *MayaEggLoader::GetAnim(EggXfmSAnim *pool)
01191 {
01192   MayaAnim *result = _anim_tab[pool];
01193   if (result == 0) {
01194     result = new MayaAnim;
01195     result->_pool = pool;
01196     result->_name = pool->get_name();
01197     _anim_tab[pool] = result;
01198     EggNode *jointNode = (DCAST(EggNode, pool))->get_parent();
01199     EggTable *joint = DCAST(EggTable, jointNode);
01200     result->_joint = joint;
01201 
01202   }
01203   return result;
01204 }
01205 
01206 void MayaAnim::PrintData(void)
01207 {
01208   if (mayaloader_cat.is_debug()) {
01209     mayaloader_cat.debug() << "anim on joint : " << _joint->get_name() << endl;
01210   }
01211   _pool->write(mayaloader_cat.debug(), 0);
01212 }
01213 
01214 ///////////////////////////////////////////////////////////////////////////////////////////////////
01215 //
01216 // MayaEggLoader functions
01217 //
01218 ///////////////////////////////////////////////////////////////////////////////////////////////////
01219 
01220 void MayaEggLoader::CreateSkinCluster(MayaEggGeom *M)
01221 {
01222   MString cmd("skinCluster -mi ");
01223   vector <MayaEggJoint *> joints;
01224 
01225   VertTable::const_iterator vert;
01226   int maxInfluences = 0;
01227   for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) {
01228     if ((int)(vert->_weights.size()) > maxInfluences) {
01229       maxInfluences = vert->_weights.size();
01230     }
01231     for (unsigned int i=0; i<vert->_weights.size(); i++) {
01232       MayaEggJoint *joint = FindJoint(vert->_weights[i].second);
01233       if (joint && !joint->_inskin) {
01234         joint->_inskin = true;
01235         joint->_index = joints.size();
01236         joints.push_back(joint);
01237         /*
01238         if (mayaloader_cat.is_spam()) {
01239           mayaloader_cat.spam() << joints[i]->_egg_joint->get_name() << ": adding to skin\n";
01240         }
01241         */
01242       }
01243     }
01244   }
01245   cmd += maxInfluences;
01246 
01247   /*
01248   if (mayaloader_cat.is_spam()) {
01249     mayaloader_cat.spam() << joints.size() << " joints have weights on " << M->_pool->get_name() << endl;
01250   }
01251   */
01252   if (joints.size() == 0) {
01253     // no need to cluster; there are no weights
01254     return;
01255   }
01256 
01257   for (unsigned int i=0; i<joints.size(); i++) {
01258     MFnDependencyNode joint(joints[i]->_joint);
01259     cmd = cmd + " ";
01260     cmd = cmd + joint.name();
01261   }
01262   
01263   MFnDependencyNode shape(M->_shapeNode);
01264   cmd = cmd + " ";
01265   cmd = cmd + shape.name();
01266   
01267   MStatus status;
01268   MDGModifier dgmod;
01269   if (mayaloader_cat.is_spam()) {
01270     mayaloader_cat.spam() << cmd.asChar() << endl;
01271     string spamCmd = M->_pool->get_name();
01272     for (unsigned int i=0; i<joints.size(); i++) {
01273       spamCmd = spamCmd + " ";
01274       spamCmd = spamCmd + joints[i]->_egg_joint->get_name();
01275     }
01276     mayaloader_cat.spam() << spamCmd << ": total = " << joints.size() << endl;
01277   }
01278   status = dgmod.commandToExecute(cmd);
01279   if (status != MStatus::kSuccess) { 
01280     perror("skinCluster commandToExecute");
01281     return; 
01282   }
01283   status = dgmod.doIt();
01284   if (status != MStatus::kSuccess) {
01285     perror("skinCluster doIt");
01286     return; 
01287   }
01288   
01289   MPlugArray oldplugs;
01290   MPlug inPlug;
01291   if (shape.typeName() == "mesh") {
01292     inPlug = shape.findPlug("inMesh");
01293   } else if (shape.typeName() == "nurbsSurface") {
01294     inPlug = shape.findPlug("create");
01295   } else {
01296     // we only support mesh and nurbsSurface    
01297     return;
01298   }
01299 
01300   if ((!inPlug.connectedTo(oldplugs,true,false))||(oldplugs.length() != 1)) {
01301     cerr << "skinCluster command failed";
01302     return;
01303   }
01304   MFnSkinCluster skinCluster(oldplugs[0].node());
01305   MIntArray influenceIndices;
01306   MFnSingleIndexedComponent component;
01307   component.create(MFn::kMeshVertComponent); // [gjeon] Interestingly, we can use MFn::kMeshVertComponent for NURBS surface, too
01308   component.setCompleteData(M->_vert_count);  
01309   for (unsigned int i=0; i<joints.size(); i++) {
01310     unsigned int index = skinCluster.indexForInfluenceObject(joints[i]->_joint_dag_path, &status);
01311     if (status != MStatus::kSuccess) {
01312       perror("skinCluster index"); 
01313       return;
01314     }
01315     influenceIndices.append((int)index);
01316   }
01317 
01318   MDagPathArray paths;
01319   unsigned infcount = skinCluster.influenceObjects(paths, &status);
01320   if (status != MStatus::kSuccess) {
01321     perror("influenceObjects");
01322     return;
01323   }
01324   for (unsigned int i=0; i<infcount; i++) {
01325     unsigned int index = skinCluster.indexForInfluenceObject(paths[i], &status);
01326     if (status != MStatus::kSuccess) {
01327       perror("skinCluster index");
01328       return;
01329     }
01330     skinCluster.setWeights(M->_shape_dag_path, component.object(), index, 0.0, false, NULL);
01331   }
01332 
01333   MFloatArray values;
01334   int tot = M->_vert_count * joints.size();
01335   values.setLength(tot);
01336   for (int i=0; i<tot; i++) {
01337     values[i] = 0.0;
01338   }
01339   for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) {
01340     for (unsigned int i=0; i<vert->_weights.size(); i++) {
01341       double strength = vert->_weights[i].first / vert->_sumWeights; // [gjeon] nomalizing weights
01342       MayaEggJoint *joint = FindJoint(vert->_weights[i].second);
01343       values[vert->_index * joints.size() + joint->_index] = (PN_stdfloat)strength;
01344     }
01345   }
01346   skinCluster.setWeights(M->_shape_dag_path, component.object(), influenceIndices, values, false, NULL);
01347 
01348   for (unsigned int i=0; i<joints.size(); i++) {
01349     /*
01350     if (mayaloader_cat.is_spam()) {
01351       mayaloader_cat.spam() << joints[i]->_egg_joint->get_name() << ": clearing skin\n";
01352     }
01353     */
01354     joints[i]->_inskin = false;
01355     joints[i]->_index = -1;
01356   }
01357 }
01358 
01359 ////////////////////////////////////////////////////////////////////////////////////////////////////
01360 //
01361 // TraverseEggData
01362 //
01363 // We have an EggData in memory, and now we're going to copy that
01364 // over into the maya scene graph.
01365 //
01366 ////////////////////////////////////////////////////////////////////////////////////////////////////
01367 
01368 void MayaEggLoader::TraverseEggNode(EggNode *node, EggGroup *context, string delim)
01369 {
01370   vector<int> vertIndices;
01371   vector<int> tvertIndices;
01372   vector<int> cvertIndices;
01373   
01374   string delstring = " ";
01375 
01376   if (node->is_of_type(EggPolygon::get_class_type())) {
01377     /*
01378     if (mayaloader_cat.is_debug()) {
01379       mayaloader_cat.debug() << delim+delstring << "found an EggMesh: " << node->get_name() << endl;
01380     }
01381     */
01382     EggPolygon *poly = DCAST(EggPolygon, node);
01383     if (poly->empty()) {
01384       return;
01385     }
01386     poly->cleanup();
01387 
01388     MayaEggTex *tex = 0;
01389     LMatrix3d uvtrans = LMatrix3d::ident_mat();
01390  
01391     if (poly->has_texture()) {
01392       EggTexture *etex = poly->get_texture(0);
01393       if (mayaloader_cat.is_spam()) {
01394         mayaloader_cat.spam() << "Texture format : " << etex->get_format() << endl;
01395       }
01396       tex = GetTex(etex);
01397       if (etex->has_transform())
01398         uvtrans = etex->get_transform2d();
01399     } else {
01400       tex = GetTex(NULL);
01401     }
01402     
01403     EggPolygon::const_iterator ci;
01404     MayaEggMesh *mesh = GetMesh(poly->get_pool(), context);
01405     if (mayaloader_cat.is_spam()) {
01406       mayaloader_cat.spam() << "traverse mesh pointer " << mesh << "\n";
01407     }
01408     vertIndices.clear();
01409     tvertIndices.clear();
01410     cvertIndices.clear();
01411     int numVertices = 0;
01412     for (ci = poly->begin(); ci != poly->end(); ++ci) {
01413       EggVertex *vtx = (*ci);
01414       EggVertexPool *pool = poly->get_pool();
01415       LTexCoordd uv(0,0);
01416       if (vtx->has_uv()) {
01417         uv = vtx->get_uv();
01418       }
01419       vertIndices.push_back(mesh->GetVert(vtx, context));
01420       tvertIndices.push_back(mesh->GetTVert(uv * uvtrans));
01421       cvertIndices.push_back(mesh->GetCVert(vtx->get_color()));
01422       numVertices++;
01423     }
01424     if (mayaloader_cat.is_spam()) {
01425       mayaloader_cat.spam() << "num vertices: " << vertIndices.size() << "\n";
01426     }
01427 
01428     if (numVertices < 3)
01429       return;
01430 
01431     MIntArray mvertIndices;
01432     MIntArray mtvertIndices;
01433     for (int i = 0; i < numVertices; i++) {
01434       mvertIndices.append(vertIndices[i]);
01435       mtvertIndices.append(tvertIndices[i]);
01436     }
01437     if (poly->has_color()) {
01438       if (mayaloader_cat.is_spam()) {
01439           mayaloader_cat.spam() << "found a face color of " << poly->get_color() << endl;
01440       }
01441       mesh->_faceIndices.append(mesh->_face_count);
01442       mesh->_faceColorArray.append(MakeMayaColor(poly->get_color()));
01443     }
01444     mesh->AddFace(numVertices, mvertIndices, mtvertIndices, tex);
01445     
01446     // [gjeon] to handle double-sided flag
01447     if (poly->get_bface_flag()) {
01448       mesh->AddEggFlag("double-sided");
01449     }
01450 
01451     // [gjeon] to handle model flag
01452     if (context->get_model_flag()) {
01453       mesh->AddEggFlag("model");
01454     }
01455 
01456     // [gjeon] to handle billboard flag
01457     switch (context->get_billboard_type()) {
01458     case EggGroup::BT_axis:
01459       mesh->AddEggFlag("billboard");
01460       break;
01461 
01462     case EggGroup::BT_point_camera_relative:
01463       mesh->AddEggFlag("billboard-point");
01464       break;
01465      
01466     default:
01467       ;
01468     }
01469 
01470     // [gjeon] to handle other flags
01471     for (int i = 0; i < context->get_num_object_types(); i++) {
01472       mesh->AddEggFlag(MString(context->get_object_type(i).c_str()));
01473     }
01474 
01475   } else if (node->is_of_type(EggNurbsSurface::get_class_type())) {
01476     // [gjeon] to convert nurbsSurface
01477     EggNurbsSurface *eggNurbsSurface = DCAST(EggNurbsSurface, node);
01478 
01479     EggNurbsSurface::const_iterator ci;
01480     EggVertexPool *pool = eggNurbsSurface->get_pool();
01481     MayaEggNurbsSurface *surface = GetSurface(pool, context);
01482 
01483     for (ci = eggNurbsSurface->begin(); ci != eggNurbsSurface->end(); ++ci) {
01484       EggVertex *vtx = (*ci);
01485       surface->GetVert(vtx, context);
01486     }
01487 
01488     // [gjeon] finding textures
01489     MayaEggTex *tex = 0;
01490     LMatrix3d uvtrans = LMatrix3d::ident_mat();
01491  
01492     if (eggNurbsSurface->has_texture()) {
01493       EggTexture *etex = eggNurbsSurface->get_texture(0);
01494       tex = GetTex(etex);
01495       if (etex->has_transform())
01496       {
01497         mayaloader_cat.debug() << "uvtrans?" << endl;
01498         uvtrans = etex->get_transform2d();
01499       }
01500     } else {
01501       tex = GetTex(NULL);
01502     }
01503 
01504     surface->_tex = tex;
01505     surface->_uNumCvs = eggNurbsSurface->get_num_u_cvs();
01506     surface->_vNumCvs = eggNurbsSurface->get_num_v_cvs();
01507 
01508     // [gjeon] building cvArray
01509     for (uint ui = 0; ui < surface->_uNumCvs; ui++) {
01510       for (uint vi = 0; vi < surface->_vNumCvs; vi++) {
01511         EggVertex *vtx = eggNurbsSurface->get_vertex(eggNurbsSurface->get_vertex_index(ui, vi));
01512         surface->_cvArray.append(MakeMPoint(vtx->get_pos3()));
01513       }
01514     }
01515     
01516     // [gjeon] building u knotArray
01517     for (int i = 1; i < eggNurbsSurface->get_num_u_knots()-1; i++) {
01518       surface->_uKnotArray.append(eggNurbsSurface->get_u_knot(i));
01519     }
01520 
01521     // [gjeon] building v knotArray
01522     for (int i = 1; i < eggNurbsSurface->get_num_v_knots()-1; i++) {
01523       surface->_vKnotArray.append(eggNurbsSurface->get_v_knot(i));
01524     }
01525 
01526     surface->_uDegree = eggNurbsSurface->get_u_degree();
01527     surface->_vDegree = eggNurbsSurface->get_v_degree();
01528 
01529     if (eggNurbsSurface->is_closed_u()) {
01530       surface->_uForm = MFnNurbsSurface::kClosed;
01531     } else {
01532       surface->_vForm = MFnNurbsSurface::kOpen;
01533     }
01534 
01535     if (eggNurbsSurface->is_closed_v()) {
01536       surface->_vForm = MFnNurbsSurface::kClosed;
01537     } else {
01538       surface->_vForm = MFnNurbsSurface::kOpen;
01539     }
01540 
01541     // [gjeon] to handle double-sided flag
01542     if (eggNurbsSurface->get_bface_flag()) {
01543       surface->AddEggFlag("double-sided");
01544     }
01545 
01546     // [gjeon] to handle model flag
01547     if (context->get_model_flag()) {
01548       surface->AddEggFlag("model");
01549     }
01550 
01551     // [gjeon] to handle other flags
01552     for (int i = 0; i < context->get_num_object_types(); i++) {
01553      surface->AddEggFlag(MString(context->get_object_type(i).c_str()));
01554     }
01555 
01556   } else if (node->is_of_type(EggComment::get_class_type())) {
01557     string comment = (DCAST(EggComment, node))->get_comment();
01558     if (comment.find("2egg") != string::npos) {
01559       if (mayaloader_cat.is_spam()) {
01560         mayaloader_cat.spam() << delim+delstring << "found an EggComment: " << comment << endl;
01561       }
01562       if (comment.find("chan") != string::npos) {
01563         ParseFrameInfo(comment);
01564       }
01565     }
01566   } else if (node->is_of_type(EggSAnimData::get_class_type())) {
01567     if (mayaloader_cat.is_debug()) {
01568       mayaloader_cat.debug() << delim+delstring << "found an EggSAnimData: " << node->get_name() << endl;
01569     }
01570     //EggSAnimData *anim = DCAST(EggSAnimData, node);
01571     //MayaAnimData *animData = GetAnimData(anim, DCAST(EggXfmSAnim, node->get_parent()));
01572     //animData->PrintData();
01573     //if (_end_frame < animData->_pool->get_num_rows()) {
01574     //  _end_frame = animData->_pool->get_num_rows();
01575     //}
01576   } else if (node->is_of_type(EggGroupNode::get_class_type())) {
01577     EggGroupNode *group = DCAST(EggGroupNode, node);
01578     if (node->is_of_type(EggGroup::get_class_type())) {
01579       EggGroup *group = DCAST(EggGroup, node);
01580 
01581       if (group->get_name() == "") {
01582         ostringstream stream;
01583         stream << _unnamed_idx;
01584         group->set_name("unnamed" + stream.str());
01585         _unnamed_idx++;
01586       }
01587 
01588       string group_name = group->get_name();
01589       size_t found = group_name.find(":");
01590       if (found != string::npos)
01591         group->set_name(group_name.replace(int(found), 1, "_"));
01592 
01593       string parent_name = "";
01594       if (context)
01595         parent_name = context->get_name();
01596       if (group->is_joint()) {
01597         if (mayaloader_cat.is_debug()) {
01598           mayaloader_cat.debug() << delim+delstring << group->get_name() << ":" << parent_name << endl;
01599         }
01600         MakeJoint(group, context);
01601         context = group;
01602       } else {
01603         // lets create a group node for it so that it is reflected in Maya
01604         if (mayaloader_cat.is_debug()) {
01605           mayaloader_cat.debug() << delim+delstring << group->get_name() << "@" << parent_name << endl;
01606         }
01607         MakeGroup(group, context);
01608         context = group;
01609       }
01610     } else if (node->is_of_type(EggTable::get_class_type())) {
01611       //EggTable *anim = DCAST(EggTable, node);
01612       if (mayaloader_cat.is_debug()) {
01613         mayaloader_cat.debug() << delim+delstring << "found an EggTable: " << node->get_name() << endl;
01614       }
01615     } else if (node->is_of_type(EggXfmSAnim::get_class_type())) {
01616       MayaAnim *anim = GetAnim(DCAST(EggXfmSAnim, node));
01617       //anim->PrintData();
01618       if (mayaloader_cat.is_debug()) {
01619         mayaloader_cat.debug() << delim+delstring << "found an EggXfmSAnim: " << node->get_name() << endl;
01620       }
01621     }
01622     
01623     EggGroupNode::const_iterator ci;
01624     for (ci = group->begin(); ci != group->end(); ++ci) {
01625       TraverseEggNode(*ci, context, delim+delstring);
01626     }
01627   } 
01628 }
01629 
01630 bool MayaEggLoader::ConvertEggData(EggData *data, bool merge, bool model, bool anim, bool respect_normals)
01631 {
01632   if (!merge) {
01633     mayaloader_cat.error() << "Currently, only 'merge' mode is implemented.\n";
01634     return false;
01635   }
01636 
01637   /*  
01638   if ((anim) || (!model)) {
01639     mayaloader_cat.error() << "Currently, only model-loading is implemented.\n";
01640     return false;
01641   }
01642   */
01643 
01644   _start_frame = 0;
01645   _end_frame = 0;
01646   _frame_rate = 24;
01647   _timeUnit = MTime::kFilm;
01648   _unnamed_idx = 1;
01649 
01650   MeshTable::const_iterator ci;
01651   JointTable::const_iterator ji;
01652   TexTable::const_iterator ti;
01653   SurfaceTable::const_iterator si;
01654   AnimTable::const_iterator ei;
01655   
01656   if (MGlobal::isYAxisUp()) {
01657     data->set_coordinate_system(CS_yup_right);
01658   } else {
01659     data->set_coordinate_system(CS_zup_right);
01660   }
01661 
01662   if (mayaloader_cat.is_debug()) {
01663     mayaloader_cat.debug() << "root node: " << data->get_type() << endl;
01664   }
01665   TraverseEggNode(data, NULL, "");
01666   
01667   MStatus status;
01668 
01669   MFnSet collision_set;
01670   collision_set.create(_collision_nodes, MFnSet::kNone, &status);
01671 
01672   if (mayaloader_cat.is_spam()) {
01673     mayaloader_cat.spam() << "num meshes : " << _mesh_tab.size() << endl;
01674   }
01675   for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
01676     MayaEggMesh *mesh = (*ci).second;
01677     if (mesh->_face_count==0) {
01678       continue;
01679     }
01680 
01681     //    MStatus status;
01682     MFnMesh mfn;
01683     MString cset;
01684     
01685     MayaEggGroup *parentNode = FindGroup(mesh->_parent);
01686     MObject parent = MObject::kNullObj;
01687     if (parentNode) {
01688       parent = parentNode->_group;
01689       if (mayaloader_cat.is_debug()) {
01690         mayaloader_cat.debug() << "mesh's parent (group) : " << parentNode->_name << endl;
01691       }
01692     } else {
01693       mesh->_renameTrans = true;
01694       if (mayaloader_cat.is_debug()) {
01695         mayaloader_cat.debug() << "mesh's parent (null) : " << endl;
01696       }
01697     }
01698     if (mayaloader_cat.is_spam()) {
01699       mayaloader_cat.spam() << "mesh pointer : " << mesh << " and parent_pointer: " << &parent << endl;
01700       mayaloader_cat.spam() << "mesh vert_count : " << mesh->_vert_count << endl;
01701       mayaloader_cat.spam() << "mesh face_count : " << mesh->_face_count << endl;
01702       mayaloader_cat.spam() << "mesh vertexArray size: " << mesh->_vertexArray.length() << endl;
01703       mayaloader_cat.spam() << "mesh polygonCounts size: " << mesh->_polygonCounts.length() << endl;
01704       mayaloader_cat.spam() << "mesh polygonConnects size: " << mesh->_polygonConnects.length() << endl;
01705       mayaloader_cat.spam() << "mesh uarray size: " << mesh->_uarray.length() << endl;
01706       mayaloader_cat.spam() << "mesh varray size: " << mesh->_varray.length() << endl;
01707     }
01708     mesh->_transNode = mfn.create(mesh->_vert_count, mesh->_face_count,
01709                                   mesh->_vertexArray, mesh->_polygonCounts, mesh->_polygonConnects,
01710                                   mesh->_uarray, mesh->_varray,
01711                                   parent, &status);
01712     if (mayaloader_cat.is_spam()) {
01713       mayaloader_cat.spam() << "transNode created." << endl;
01714     }
01715 
01716     if (!mesh->_renameTrans) {
01717       mesh->_transNode = parent;
01718     }
01719 
01720     // [gjeon] add eggFlag attributes if any exists
01721     for (unsigned i = 0; i < mesh->_eggObjectTypes.length(); i++) {
01722       MString attrName = "eggObjectTypes";
01723       attrName += (int)(i + 1);
01724       status = create_enum_attribute(mesh->_transNode, attrName, attrName, mesh->_eggObjectTypes, i);
01725       if (status != MStatus::kSuccess) {
01726         status.perror("create_enum_attribute failed!");
01727       }
01728     }
01729 
01730     mesh->_shapeNode = mfn.object();
01731     mfn.getPath(mesh->_shape_dag_path);
01732     mesh->ConnectTextures();
01733 
01734     if (mayaloader_cat.is_spam()) {
01735       mayaloader_cat.spam() << "textures connected." << endl;
01736     }
01737 
01738     mfn.getCurrentUVSetName(cset);
01739     status = mfn.assignUVs(mesh->_polygonCounts, mesh->_uvIds, &cset);
01740 
01741     if (status != MStatus::kSuccess) {
01742       status.perror("assignUVs failed");
01743       if (mayaloader_cat.is_spam()) {
01744         PrintData(mesh);
01745       }
01746     }
01747     else {
01748       if (mayaloader_cat.is_spam()) {
01749         mayaloader_cat.spam() << "uvs assigned." << endl;
01750       }
01751     }
01752 
01753     // lets try to set normals per vertex 
01754     if (respect_normals) {
01755       status = mfn.setVertexNormals(mesh->_normalArray, mesh->_vertNormalIndices, MSpace::kTransform);
01756       if (status != MStatus::kSuccess) {
01757         status.perror("setVertexNormals failed!");
01758       }
01759     }
01760 
01761     if (mayaloader_cat.is_spam()) {
01762       mayaloader_cat.spam() << "vertex normals set." << endl;
01763     }
01764    
01765     // lets try to set colors per vertex
01766     /*
01767     MDGModifier dgmod;
01768     status = dgmod.doIt();
01769     if (status != MStatus::kSuccess) {
01770       status.perror("setVertexColors doIt");
01771     }
01772     status = mfn.setVertexColors(mesh->_vertColorArray, mesh->_vertColorIndices, &dgmod);
01773     */
01774     status = mfn.setVertexColors(mesh->_vertColorArray, mesh->_vertColorIndices);
01775     if (status != MStatus::kSuccess) {
01776       status.perror("setVertexColors failed!");
01777     }
01778     status = mfn.setFaceColors(mesh->_faceColorArray, mesh->_faceIndices);
01779     /*
01780     if (status != MStatus::kSuccess) {
01781       status.perror("setFaceColors failed!");
01782     }
01783     */
01784   }
01785 
01786   for (si = _surface_tab.begin(); si != _surface_tab.end(); ++si) {
01787     MayaEggNurbsSurface *surface = (*si).second;
01788     if (surface->_cvArray.length()==0) {
01789       continue;
01790     }
01791 
01792     //    MStatus status;
01793     MFnNurbsSurface mfnNurbsSurface;
01794     
01795     MayaEggGroup *parentNode = FindGroup(surface->_parent);
01796     MObject parent = MObject::kNullObj;
01797     if (parentNode) {
01798       parent = parentNode->_group;
01799       if (mayaloader_cat.is_debug()) {
01800         mayaloader_cat.debug() << "surface's parent (group) : " << parentNode->_name << endl;
01801       }
01802     } else {
01803       surface->_renameTrans = true;
01804       if (mayaloader_cat.is_debug()) {
01805         mayaloader_cat.debug() << "surface's parent (null) : " << endl;
01806       }
01807     }
01808 
01809     surface->_transNode = mfnNurbsSurface.create(surface->_cvArray, surface->_uKnotArray, surface->_vKnotArray,
01810                                                  surface->_uDegree, surface->_vDegree, surface->_uForm, surface->_vForm,
01811                                                  true, parent, &status);
01812 
01813     if (!surface->_renameTrans) {
01814       surface->_transNode = parent;
01815     }
01816 
01817     // [gjeon] add eggFlag attributes if any exists   
01818     for (unsigned i = 0; i < surface->_eggObjectTypes.length(); i++) {
01819       MString attrName = "eggObjectTypes";
01820       attrName += (int)(i + 1);
01821       status = create_enum_attribute(surface->_transNode, attrName, attrName, surface->_eggObjectTypes, i);
01822       if (status != MStatus::kSuccess) {
01823         status.perror("create_enum_attribute failed!");
01824       }
01825     }
01826     surface->_shapeNode = mfnNurbsSurface.object();
01827     mfnNurbsSurface.getPath(surface->_shape_dag_path);
01828     surface->ConnectTextures();
01829 
01830     mayaloader_cat.debug() << status.errorString().asChar() << endl;
01831   }
01832 
01833 
01834   double thickness = 0.0;
01835   for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
01836     MayaEggJoint *joint = (*ji).second;
01837     double dfo = ((*ji).second->GetPos()).length();
01838     if (dfo > thickness) {
01839       thickness = dfo;
01840     }
01841   }
01842   if (mayaloader_cat.is_spam()) {
01843     mayaloader_cat.spam() << "thickness from joints: " << thickness << endl;
01844   }
01845   thickness = thickness * 0.025;
01846   for (unsigned int i=0; i<_joint_list.size(); i++) {
01847     MayaEggJoint *joint = _joint_list[i];
01848     if (mayaloader_cat.is_spam()) {
01849       mayaloader_cat.spam() << "creating a joint: " << joint->_egg_joint->get_name() << endl;
01850     }
01851     joint->ChooseEndPos(thickness);
01852     joint->CreateMayaBone(FindGroup(joint->_egg_parent));
01853   }
01854   if (mayaloader_cat.is_spam()) {
01855     mayaloader_cat.spam() << "went past all the joints" << endl;
01856   }
01857   for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
01858     MayaEggMesh *mesh = (*ci).second;
01859     EggGroup *joint = mesh->GetControlJoint();
01860     if (joint) {
01861       CreateSkinCluster(mesh);
01862     }
01863   }
01864   for (si = _surface_tab.begin(); si != _surface_tab.end(); ++si) {
01865     MayaEggNurbsSurface *surface = (*si).second;
01866     EggGroup *joint = surface->GetControlJoint();
01867     if (joint) {
01868       CreateSkinCluster(surface);
01869     }
01870   }
01871   if (mayaloader_cat.is_spam()) {
01872     mayaloader_cat.spam() << "went past creating skin cluster" << endl;
01873   }
01874   for (ci = _mesh_tab.begin();  ci != _mesh_tab.end();  ++ci) {
01875     (*ci).second->AssignNames();
01876   }
01877   for (si = _surface_tab.begin();  si != _surface_tab.end();  ++si) {
01878     (*si).second->AssignNames();
01879   }
01880   if (mayaloader_cat.is_spam()) {
01881     mayaloader_cat.spam() << "went past mesh AssignNames" << endl;
01882   }
01883   for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
01884     (*ji).second->AssignNames();
01885   }
01886   if (mayaloader_cat.is_spam()) {
01887     mayaloader_cat.spam() << "went past joint AssignNames" << endl;
01888   }
01889   for (ti = _tex_tab.begin();   ti != _tex_tab.end();   ++ti) {
01890     (*ti).second->AssignNames();
01891   }
01892   if (mayaloader_cat.is_spam()) {
01893     mayaloader_cat.spam() << "went past tex AssignNames" << endl;
01894   }
01895  
01896   if (mayaloader_cat.is_debug()) {
01897     mayaloader_cat.debug() << "-fri: " << _frame_rate << " -sf: " << _start_frame 
01898                            << " -ef: " << _end_frame << endl;
01899   }
01900 
01901   // masad: keep track of maximum frames of animation on all these joints
01902   MTime maxFrame(_start_frame - 1, _timeUnit);
01903   MTime minFrame = maxFrame;
01904 
01905   for (ei = _anim_tab.begin(); ei != _anim_tab.end(); ++ei) {
01906     MayaAnim *anim = (*ei).second;
01907     MObject node = GetDependencyNode(anim->_joint->get_name());
01908     MFnDagNode mfnNode(node, &status);
01909 
01910     MMatrix mMat = mfnNode.transformationMatrix(&status);
01911 
01912     MObject attrTX = mfnNode.attribute("translateX", &status);
01913     MObject attrTY = mfnNode.attribute("translateY", &status);
01914     MObject attrTZ = mfnNode.attribute("translateZ", &status);
01915     MObject attrRX = mfnNode.attribute("rotateX", &status);
01916     MObject attrRY = mfnNode.attribute("rotateY", &status);
01917     MObject attrRZ = mfnNode.attribute("rotateZ", &status);
01918     MObject attrSX = mfnNode.attribute("scaleX", &status);
01919     MObject attrSY = mfnNode.attribute("scaleY", &status);
01920     MObject attrSZ = mfnNode.attribute("scaleZ", &status);
01921 
01922     MFnAnimCurve mfnAnimCurveTX;
01923     MFnAnimCurve mfnAnimCurveTY;
01924     MFnAnimCurve mfnAnimCurveTZ;
01925     MFnAnimCurve mfnAnimCurveRX;
01926     MFnAnimCurve mfnAnimCurveRY;
01927     MFnAnimCurve mfnAnimCurveRZ;
01928     MFnAnimCurve mfnAnimCurveSX;
01929     MFnAnimCurve mfnAnimCurveSY;
01930     MFnAnimCurve mfnAnimCurveSZ;
01931 
01932     mfnAnimCurveTX.create(node, attrTX, MFnAnimCurve::kAnimCurveTL, NULL, &status);
01933     mfnAnimCurveTY.create(node, attrTY, MFnAnimCurve::kAnimCurveTL, NULL, &status);
01934     mfnAnimCurveTZ.create(node, attrTZ, MFnAnimCurve::kAnimCurveTL, NULL, &status);
01935     mfnAnimCurveRX.create(node, attrRX, MFnAnimCurve::kAnimCurveTA, NULL, &status);
01936     mfnAnimCurveRY.create(node, attrRY, MFnAnimCurve::kAnimCurveTA, NULL, &status);
01937     mfnAnimCurveRZ.create(node, attrRZ, MFnAnimCurve::kAnimCurveTA, NULL, &status);
01938     mfnAnimCurveSX.create(node, attrSX, MFnAnimCurve::kAnimCurveTU, NULL, &status);
01939     mfnAnimCurveSY.create(node, attrSY, MFnAnimCurve::kAnimCurveTU, NULL, &status);
01940     mfnAnimCurveSZ.create(node, attrSZ, MFnAnimCurve::kAnimCurveTU, NULL, &status);
01941 
01942     MTransformationMatrix matrix( mMat );
01943     MVector trans = matrix.translation(MSpace::kTransform, &status);
01944       
01945     double rot[3];
01946     MTransformationMatrix::RotationOrder order = MTransformationMatrix::kXYZ;
01947     status = matrix.getRotation(rot, order);
01948 
01949     double scale[3];
01950     status = matrix.getScale(scale, MSpace::kTransform);
01951     MFnAnimCurve::TangentType tangent = MFnAnimCurve::kTangentClamped;
01952     MTime time(_start_frame - 1, _timeUnit);
01953 
01954     mfnAnimCurveTX.addKey(time, trans.x, tangent, tangent, NULL, &status);
01955     mfnAnimCurveTY.addKey(time, trans.y, tangent, tangent, NULL, &status);
01956     mfnAnimCurveTZ.addKey(time, trans.z, tangent, tangent, NULL, &status);
01957     mfnAnimCurveRX.addKey(time, rot[0], tangent, tangent, NULL, &status);
01958     mfnAnimCurveRY.addKey(time, rot[1], tangent, tangent, NULL, &status);
01959     mfnAnimCurveRZ.addKey(time, rot[2], tangent, tangent, NULL, &status);
01960     mfnAnimCurveSX.addKey(time, scale[0], tangent, tangent, NULL, &status);
01961     mfnAnimCurveSY.addKey(time, scale[1], tangent, tangent, NULL, &status);
01962     mfnAnimCurveSZ.addKey(time, scale[2], tangent, tangent, NULL, &status);
01963 
01964     for (int frame = 0; frame < anim->_pool->get_num_rows(); frame++)
01965     {
01966       LMatrix4d tMat;
01967       anim->_pool->get_value(frame, tMat);
01968 
01969       double matData[4][4] = {{tMat.get_cell(0,0), tMat.get_cell(0,1), tMat.get_cell(0,2), tMat.get_cell(0,3)},
01970                   {tMat.get_cell(1,0), tMat.get_cell(1,1), tMat.get_cell(1,2), tMat.get_cell(1,3)},
01971                   {tMat.get_cell(2,0), tMat.get_cell(2,1), tMat.get_cell(2,2), tMat.get_cell(2,3)},
01972                   {tMat.get_cell(3,0), tMat.get_cell(3,1), tMat.get_cell(3,2), tMat.get_cell(3,3)}};
01973       MMatrix mat(matData);
01974 
01975       matrix = MTransformationMatrix(mat);
01976       trans = matrix.translation(MSpace::kTransform, &status);
01977       status = matrix.getRotation(rot, order);
01978       status = matrix.getScale(scale, MSpace::kTransform);
01979       time = MTime(frame + _start_frame, _timeUnit);
01980 
01981       mfnAnimCurveTX.addKey(time, trans.x, tangent, tangent, NULL, &status);
01982       mfnAnimCurveTY.addKey(time, trans.y, tangent, tangent, NULL, &status);
01983       mfnAnimCurveTZ.addKey(time, trans.z, tangent, tangent, NULL, &status);
01984       mfnAnimCurveRX.addKey(time, rot[0], tangent, tangent, NULL, &status);
01985       mfnAnimCurveRY.addKey(time, rot[1], tangent, tangent, NULL, &status);
01986       mfnAnimCurveRZ.addKey(time, rot[2], tangent, tangent, NULL, &status);
01987       mfnAnimCurveSX.addKey(time, scale[0], tangent, tangent, NULL, &status);
01988       mfnAnimCurveSY.addKey(time, scale[1], tangent, tangent, NULL, &status);
01989       mfnAnimCurveSZ.addKey(time, scale[2], tangent, tangent, NULL, &status);
01990     }
01991     if (maxFrame < time) {
01992       maxFrame = time;
01993     }
01994   }
01995   if (anim) {
01996     // masad: set the control's max time with maxFrame
01997     MAnimControl::setMaxTime(maxFrame);
01998     MAnimControl::setMinTime(minFrame);
01999   }
02000 
02001   for (ci = _mesh_tab.begin();  ci != _mesh_tab.end();  ++ci) {
02002     delete (*ci).second;
02003   }
02004   for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
02005     delete (*ji).second;
02006   }
02007   for (ti = _tex_tab.begin();   ti != _tex_tab.end();   ++ti) {
02008     delete (*ti).second;
02009   }
02010   for (ei = _anim_tab.begin();  ei != _anim_tab.end();  ++ei) {
02011     delete (*ei).second;
02012   }
02013 
02014   //  ResumeSetKeyMode();
02015   //  ResumeAnimate();
02016   
02017   mayaloader_cat.info() << "Egg import successful\n";
02018   return true;
02019 }
02020 
02021 void MayaEggLoader::PrintData(MayaEggMesh *mesh)
02022 {
02023     if (mayaloader_cat.is_spam()) {
02024       mayaloader_cat.spam() << "Mesh: " << mesh->_name << endl;
02025       mayaloader_cat.spam() << "num vertexArray: " << mesh->_vertexArray.length() << endl;
02026       ostringstream stream3;
02027       for (unsigned int i=0; i < mesh->_vertexArray.length(); ++i) {
02028         stream3 << "[" << mesh->_vertexArray[i].x << " " << mesh->_vertexArray[i].y << " " << mesh->_vertexArray[i].z << "]" << endl;
02029       }
02030 
02031       mayaloader_cat.spam() << "vertexArray: \n" << stream3.str() << endl;
02032       mayaloader_cat.spam() << "num polygonConnects: " << mesh->_polygonConnects.length() << endl;
02033       mayaloader_cat.spam() << "num uvCounts: " << mesh->_polygonCounts.length() << endl;
02034       mayaloader_cat.spam() << "num uvIds: " << mesh->_uvIds.length() << endl;
02035       ostringstream stream1, stream4;
02036       unsigned int k=0;
02037       for (unsigned int i=0; i < mesh->_polygonCounts.length(); ++i) {
02038         stream1 << mesh->_polygonCounts[i] << ":->";
02039         stream4 << mesh->_polygonCounts[i] << ":->";
02040         for (int j=0; j < mesh->_polygonCounts[i]; ++j, ++k) {
02041           stream1 << mesh->_uvIds[k] << ",";
02042           stream4 << mesh->_polygonConnects[k] << ",";
02043         }
02044         stream1 << endl;
02045         stream4 << endl;
02046       }
02047       mayaloader_cat.spam() << "uvCounts:->uvIds " << endl << stream1.str() << endl;
02048       mayaloader_cat.spam() << "vertexCount:->polygonConnects" << endl << stream4.str() << endl;
02049     }
02050 }
02051 
02052 void MayaEggLoader::ParseFrameInfo(string comment)
02053 {
02054   int length = 0;
02055   int pos, ls, le;
02056 
02057   pos = comment.find("-fri");
02058   if (pos != string::npos) {
02059     ls = comment.find(" ", pos+4);
02060     le = comment.find(" ", ls+1);
02061     if (mayaloader_cat.is_debug()) {
02062       mayaloader_cat.debug() <<    comment.substr(ls+1, le-ls-1) << endl;
02063     }
02064     _frame_rate = atoi(comment.substr(ls+1,le-ls-1).data());
02065     //mayaloader_cat.debug() << "le = " << le << "; and ls = " << ls << "; frame_rate = " << _frame_rate << endl;
02066 
02067     switch (_frame_rate) {
02068     case 15:
02069       _timeUnit = MTime::kGames;
02070       break;
02071     case 24:
02072       _timeUnit = MTime::kFilm;
02073       break;
02074     case 25:
02075       _timeUnit = MTime::kPALFrame;
02076       break;
02077     case 30:
02078       _timeUnit = MTime::kNTSCFrame;
02079       break;
02080     case 48:
02081       _timeUnit = MTime::kShowScan;
02082       break;
02083     case 50:
02084       _timeUnit = MTime::kPALField;
02085       break;
02086     case 60:
02087       _timeUnit = MTime::kNTSCField;
02088       break;
02089     case 2:
02090       _timeUnit = MTime::k2FPS;
02091       break;
02092     case 3:
02093       _timeUnit = MTime::k3FPS;
02094       break;
02095     case 4:
02096       _timeUnit = MTime::k4FPS;
02097       break;
02098     case 5:
02099       _timeUnit = MTime::k5FPS;
02100       break;
02101     case 6:
02102       _timeUnit = MTime::k6FPS;
02103       break;
02104     case 8:
02105       _timeUnit = MTime::k8FPS;
02106       break;
02107     case 10:
02108       _timeUnit = MTime::k10FPS;
02109       break;
02110     case 12:
02111       _timeUnit = MTime::k12FPS;
02112       break;
02113     case 16:
02114       _timeUnit = MTime::k16FPS;
02115       break;
02116     case 20:
02117       _timeUnit = MTime::k20FPS;
02118       break;
02119     case 40:
02120       _timeUnit = MTime::k40FPS;
02121       break;
02122     case 75:
02123       _timeUnit = MTime::k75FPS;
02124       break;
02125     case 80:
02126       _timeUnit = MTime::k80FPS;
02127       break;
02128     case 100:
02129       _timeUnit = MTime::k100FPS;
02130       break;
02131     default:
02132       _timeUnit = MTime::kFilm;
02133     }
02134 
02135   }
02136 
02137   pos = comment.find("-sf");
02138   if (pos != string::npos) {
02139     ls = comment.find(" ", pos+3);
02140     le = comment.find(" ", ls+1);
02141     if (mayaloader_cat.is_debug()) {
02142       mayaloader_cat.debug() <<    comment.substr(ls+1, le-ls-1) << endl;
02143     }
02144     if (le == string::npos) {
02145       _start_frame = atoi(comment.substr(ls+1,le).data());
02146     } else {
02147       _start_frame = atoi(comment.substr(ls+1,le-ls-1).data());
02148     }
02149     //mayaloader_cat.debug() << "le = " << le << "; and ls = " << ls << "; start_frame = " << _start_frame << endl;
02150   }
02151   pos = comment.find("-ef");
02152   if (pos != string::npos) {
02153     ls = comment.find(" ", pos+3);
02154     le = comment.find(" ", ls+1);
02155     if (mayaloader_cat.is_debug()) {
02156       mayaloader_cat.debug() <<    comment.substr(ls+1, le-ls-1) << endl;
02157     }
02158     if (le == string::npos) {
02159       _end_frame = atoi(comment.substr(ls+1,le).data());
02160     } else {
02161       _end_frame = atoi(comment.substr(ls+1,le-ls-1).data());
02162     }
02163     //mayaloader_cat.debug() << "le = " << le << "; and ls = " << ls << "; end_frame = " << _end_frame << endl;
02164   }
02165 
02166 
02167 }
02168 
02169 bool MayaEggLoader::ConvertEggFile(const char *name, bool merge, bool model, bool anim, bool respect_normals)
02170 {
02171   EggData data;
02172   Filename datafn = Filename::from_os_specific(name);
02173   if (!data.read(datafn)) {
02174     mayaloader_cat.error() << "Cannot read Egg file for import\n";
02175     return false;
02176   }
02177   return ConvertEggData(&data, merge, model, anim, respect_normals);
02178 }
02179 
02180 MObject MayaEggLoader::GetDependencyNode(string givenName)
02181 {
02182   MObject node = MObject::kNullObj;
02183   int pos;
02184   string name;
02185 
02186   pos = givenName.find(":");
02187   if (pos != string::npos) {
02188     name = givenName.substr(pos+1);
02189   } else
02190     name = givenName;
02191 
02192   /* 
02193   //masad: I do not think you want to return a mesh node 
02194   //because keyframes should only apply to joint nodes.
02195   MeshTable::const_iterator ci;
02196   for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
02197     MayaEggMesh *mesh = (*ci).second;
02198     
02199     string meshName = mesh->_pool->get_name();
02200     int nsize = meshName.size();
02201     if ((nsize > 6) && (meshName.rfind(".verts")==(nsize-6))) {
02202       meshName.resize(nsize-6);
02203     }
02204     if (meshName == name)
02205     {
02206       node = mesh->_transNode;
02207       cerr << "foo get dependency node returning a mesh's transNode? why? : " << givenName << endl;
02208       return node;
02209     }
02210   }
02211   */
02212 
02213   JointTable::const_iterator ji;
02214   for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
02215     MayaEggJoint *joint = (*ji).second;
02216     if (mayaloader_cat.is_spam()) {
02217       mayaloader_cat.spam() << "traversing a joint: " << joint->_egg_joint->get_name() << endl;
02218     }
02219     string jointName = joint->_egg_joint->get_name();
02220     if (jointName == name)
02221     {
02222       node = joint->_joint;
02223       return node;
02224     }
02225   }  
02226   
02227   return node;
02228 }
02229 
02230 ////////////////////////////////////////////////////////////////////////////////////////////////////
02231 //
02232 // The two global functions that form the API of this module.
02233 //
02234 ////////////////////////////////////////////////////////////////////////////////////////////////////
02235 
02236 bool MayaLoadEggData(EggData *data, bool merge, bool model, bool anim, bool respect_normals)
02237 {
02238   MayaEggLoader loader;
02239   bool temp = loader.ConvertEggData(data, merge, model, anim, respect_normals);
02240   return temp;
02241 }
02242 
02243 bool MayaLoadEggFile(const char *name, bool merge, bool model, bool anim, bool respect_normals)
02244 {
02245   MayaEggLoader loader;
02246   return loader.ConvertEggFile(name, merge, model, anim, respect_normals);
02247 }
02248 
 All Classes Functions Variables Enumerations