Panda3D
 All Classes Functions Variables Enumerations
mayaEggLoader.cxx
1 // Filename: mayaEggImport.cxx
2 // Created by: jyelon (20Jul05)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 //
15 // This file contains the code for class MayaEggLoader. This class
16 // does the actual work of copying an EggData tree into the maya scene.
17 //
18 ////////////////////////////////////////////////////////////////////
19 
20 
21 #include "pandatoolbase.h"
22 #include "notifyCategoryProxy.h"
23 
24 #include "eggBin.h"
25 #include "eggData.h"
26 #include "eggTable.h"
27 #include "eggVertex.h"
28 #include "eggPolygon.h"
29 #include "eggComment.h"
30 #include "eggXfmSAnim.h"
31 #include "eggSAnimData.h"
32 #include "eggPrimitive.h"
33 #include "eggGroupNode.h"
34 #include "eggVertexPool.h"
35 #include "eggPolysetMaker.h"
36 #include "eggNurbsSurface.h"
37 #include "texture.h"
38 #include "texturePool.h"
39 
40 #include "pre_maya_include.h"
41 #include <maya/MStatus.h>
42 #include <maya/MPxCommand.h>
43 #include <maya/MString.h>
44 #include <maya/MStringArray.h>
45 #include <maya/MArgList.h>
46 #include <maya/MGlobal.h>
47 #include <maya/MObject.h>
48 #include <maya/MFloatPoint.h>
49 #include <maya/MFloatPointArray.h>
50 #include <maya/MFloatArray.h>
51 #include <maya/MPointArray.h>
52 #include <maya/MFnMesh.h>
53 #include <maya/MFnDependencyNode.h>
54 #include <maya/MFnTransform.h>
55 #include <maya/MFnLambertShader.h>
56 #include <maya/MPlug.h>
57 #include <maya/MFnSet.h>
58 #include <maya/MDGModifier.h>
59 #include <maya/MSelectionList.h>
60 #include <maya/MDagPath.h>
61 #include <maya/MFnSingleIndexedComponent.h>
62 #include <maya/MFnDoubleIndexedComponent.h>
63 #include <maya/MPlugArray.h>
64 #include <maya/MDagPathArray.h>
65 #include <maya/MMatrix.h>
66 #include <maya/MTransformationMatrix.h>
67 #include <maya/MFnIkJoint.h>
68 #include <maya/MFnSkinCluster.h>
69 #include <maya/MAnimControl.h>
70 #include <maya/MFnAnimCurve.h>
71 #include <maya/MFnNurbsSurface.h>
72 #include <maya/MFnEnumAttribute.h>
73 #include <maya/MFnSet.h>
74 #include "post_maya_include.h"
75 
76 #include "mayaEggLoader.h"
77 
78 class MayaEggGroup;
79 class MayaEggGeom;
80 class MayaEggMesh;
81 class MayaEggJoint;
82 class MayaEggTex;
83 class MayaAnim;
85 
86 NotifyCategoryDeclNoExport(mayaloader);
87 NotifyCategoryDef(mayaloader, "");
88 
90 {
91 public:
92  bool ConvertEggData(EggData *data, bool merge, bool model, bool anim, bool respect_normals);
93  bool ConvertEggFile(const char *name, bool merge, bool model, bool anim, bool respect_normals);
94 
95 
96 public:
97  void TraverseEggNode(EggNode *node, EggGroup *context, string delim);
98  MayaEggMesh *GetMesh(EggVertexPool *pool, EggGroup *parent);
99  MayaEggJoint *FindJoint(EggGroup *joint);
100  MayaEggJoint *MakeJoint(EggGroup *joint, EggGroup *context);
101  MayaEggGroup *FindGroup(EggGroup *group);
102  MayaEggGroup *MakeGroup(EggGroup *group, EggGroup *context);
103  MayaEggTex *GetTex(EggTexture *etex);
104  void CreateSkinCluster(MayaEggGeom *M);
105 
106  MayaAnim *GetAnim(EggXfmSAnim *pool);
107  MObject GetDependencyNode(string givenName);
108 
109  MayaEggNurbsSurface *GetSurface(EggVertexPool *pool, EggGroup *parent);
110 
111  typedef phash_map<EggGroup *, MayaEggMesh *, pointer_hash> MeshTable;
112  typedef phash_map<EggXfmSAnim *, MayaAnim *, pointer_hash> AnimTable;
113  typedef phash_map<EggGroup *, MayaEggJoint *, pointer_hash> JointTable;
114  typedef phash_map<EggGroup *, MayaEggGroup *, pointer_hash> GroupTable;
115  typedef phash_map<string, MayaEggTex *, string_hash> TexTable;
116  typedef phash_map<EggGroup *, MayaEggNurbsSurface *, pointer_hash> SurfaceTable;
117 
118  MeshTable _mesh_tab;
119  AnimTable _anim_tab;
120  JointTable _joint_tab;
121  GroupTable _group_tab;
122  TexTable _tex_tab;
123  SurfaceTable _surface_tab;
124 
125  vector <MayaEggJoint *> _joint_list;
126 
127  int _start_frame;
128  int _end_frame;
129  int _frame_rate;
130  MTime::Unit _timeUnit;
131 
132  void ParseFrameInfo(string comment);
133  void PrintData(MayaEggMesh *mesh);
134 
135 private:
136  int _unnamed_idx;
137  MSelectionList _collision_nodes;
138 };
139 
140 MPoint MakeMPoint(const LVector3d &vec)
141 {
142  return MPoint(vec[0], vec[1], vec[2]);
143 }
144 
145 MFloatPoint MakeMayaPoint(const LVector3d &vec)
146 {
147  return MFloatPoint(vec[0], vec[1], vec[2]);
148 }
149 
150 MVector MakeMayaVector(const LVector3d &vec)
151 {
152  return MVector(vec[0], vec[1], vec[2]);
153 }
154 
155 MColor MakeMayaColor(const LColor &vec)
156 {
157  return MColor(vec[0], vec[1], vec[2], vec[3]);
158 }
159 
160 // [gjeon] to create enum attribute,
161 // fieldNames is a stringArray of enum names, and filedIndex is the default index value
162 MStatus create_enum_attribute(MObject &node, MString fullName, MString briefName,
163  MStringArray fieldNames, unsigned fieldIndex) {
164  MStatus stat;
165 
166  MFnDependencyNode fnDN( node, &stat );
167  if ( MS::kSuccess != stat ) {
168  mayaloader_cat.error()
169  << "Could not create MFnDependencyNode" << "\n";
170  return stat;
171  }
172 
173  MFnEnumAttribute fnAttr;
174  MObject newAttr = fnAttr.create( fullName, briefName,
175  0, &stat );
176  if ( MS::kSuccess != stat ) {
177  mayaloader_cat.error()
178  << "Could not create new enum attribute " << fullName.asChar() << "\n";
179  return stat;
180  }
181  for (unsigned i = 0; i < fieldNames.length(); i++){
182  fnAttr.addField(fieldNames[i], i);
183  }
184 
185  stat = fnAttr.setDefault(fieldIndex);
186  if ( MS::kSuccess != stat ) {
187  mayaloader_cat.error()
188  << "Could not set value for enum attribute " << fullName.asChar() << "\n";
189  return stat;
190  }
191 
192  fnAttr.setKeyable( true );
193  fnAttr.setReadable( true );
194  fnAttr.setWritable( true );
195  fnAttr.setStorable( true );
196 
197  // Now add the new attribute to this dependency node
198  stat = fnDN.addAttribute(newAttr, MFnDependencyNode::kLocalDynamicAttr);
199  if ( MS::kSuccess != stat ) {
200  mayaloader_cat.error()
201  << "Could not add new enum attribute " << fullName.asChar() << "\n";
202  return stat;
203  }
204 
205  return stat;
206 }
207 
208 ////////////////////////////////////////////////////////////////////////////////////////////////////
209 //
210 // MayaEggTex
211 //
212 ////////////////////////////////////////////////////////////////////////////////////////////////////
213 
215 {
216 public:
217  string _name;
218  string _path;
219  MObject _file_texture;
220  MObject _shader;
221  MObject _shading_group;
222 
223  MFnSingleIndexedComponent _component;
224  void AssignNames(void);
225 };
226 
227 void MayaEggTex::AssignNames(void)
228 {
229  if (_name == "") {
230  return;
231  }
232  MFnDependencyNode shader(_shader);
233  MFnDependencyNode sgroup(_shading_group);
234  MFnDependencyNode filetex(_file_texture);
235  shader.setName(MString(_name.c_str())+"Shader");
236  sgroup.setName(MString(_name.c_str()));
237  if (_file_texture != MObject::kNullObj) {
238  filetex.setName(MString(_name.c_str())+"File");
239  }
240 }
241 
242 MayaEggTex *MayaEggLoader::GetTex(EggTexture* etex)
243 {
244  string name = "";
245  string fn = "";
246  if (etex != NULL) {
247  name = etex->get_name();
248  fn = etex->get_fullpath().to_os_specific();
249  }
250 
251  if (_tex_tab.count(fn)) {
252  return _tex_tab[fn];
253  }
254 
255  MStatus status;
256  MFnLambertShader shader;
257  MFnDependencyNode filetex;
258  MFnSet sgroup;
259  MPlugArray oldplugs;
260  MDGModifier dgmod;
261 
262  /*
263  if (fn=="") {
264  MSelectionList selection;
265  MObject initGroup;
266  selection.clear();
267  MGlobal::getSelectionListByName("initialShadingGroup",selection);
268  selection.getDependNode(0, initGroup);
269  sgroup.setObject(initGroup);
270  } else {
271  */
272  if (1) {
273  shader.create(true,&status);
274  MColor firstColor(1.0,1.0,1.0,1.0);
275  status = shader.setColor(firstColor);
276  if (status != MStatus::kSuccess) {
277  mayaloader_cat.error() << "setColor failed on LambertShader\n";
278  status.perror("shader setColor failed!");
279  }
280  sgroup.create(MSelectionList(), MFnSet::kRenderableOnly, &status);
281  MPlug surfplug = sgroup.findPlug("surfaceShader");
282  if (surfplug.connectedTo(oldplugs,true,false)) {
283  for (unsigned int i=0; i<oldplugs.length(); i++) {
284  MPlug src = oldplugs[i];
285  status = dgmod.disconnect(src, surfplug);
286  if (status != MStatus::kSuccess) {
287  status.perror("Disconnecting old shader");
288  }
289  }
290  }
291  status = dgmod.connect(shader.findPlug("outColor"),surfplug);
292  if (status != MStatus::kSuccess) {
293  status.perror("Connecting shader");
294  }
295  if (fn != "") {
296  filetex.create("file",&status);
297  MString fn_str(fn.c_str());
298  filetex.findPlug("fileTextureName").setValue(fn_str);
299  dgmod.connect(filetex.findPlug("outColor"),shader.findPlug("color"));
300 
301  // [gjeon] to create alpha channel connection
302  LoaderOptions options;
303  PT(Texture) tex = TexturePool::load_texture(etex->get_fullpath(), 0, false, options);
304  if (((tex != NULL) && (tex->get_num_components() == 4))
305  || (etex->get_format() == EggTexture::F_alpha)
306  || (etex->get_format() == EggTexture::F_luminance_alpha))
307  dgmod.connect(filetex.findPlug("outTransparency"),shader.findPlug("transparency"));
308  }
309  status = dgmod.doIt();
310  if (status != MStatus::kSuccess) {
311  status.perror("DGMod doIt");
312  }
313  }
314 
315  MayaEggTex *res = new MayaEggTex;
316  res->_name = name;
317  res->_path = fn;
318  res->_file_texture = filetex.object();
319  res->_shader = shader.object();
320  res->_shading_group = sgroup.object();
321 
322  _tex_tab[fn] = res;
323  return res;
324 }
325 
326 ////////////////////////////////////////////////////////////////////////////////////////////////////
327 //
328 // MayaEggGroup
329 //
330 ////////////////////////////////////////////////////////////////////////////////////////////////////
331 
333 {
334 public:
335  string _name;
336  MObject _parent;
337  MObject _group;
338 
339  bool _addedEggFlag;
340 };
341 
342 MayaEggGroup *MayaEggLoader::MakeGroup(EggGroup *group, EggGroup *context)
343 {
344  MStatus status;
345  MayaEggGroup *pg = FindGroup(context);
346  MayaEggGroup *result = new MayaEggGroup;
347  MFnDagNode dgn;
348 
349  MObject parent = MObject::kNullObj;
350  if (pg) {
351  parent = pg->_group;
352  if (mayaloader_cat.is_debug()) {
353  mayaloader_cat.debug() << "parent (group) :" << ((MFnDagNode)parent).name().asChar() << endl;
354  }
355  }
356 
357  result->_name = group->get_name();
358  result->_group = dgn.create("transform", MString(result->_name.c_str()), parent, &status);
359  result->_addedEggFlag = false;
360 
361  if (group->get_cs_type() != EggGroup::CST_none)
362  _collision_nodes.add(result->_group, true);
363 
364  if (group->has_transform3d()) {
365  LMatrix4d tMat = group->get_transform3d();
366  double matData[4][4] = {{tMat.get_cell(0,0), tMat.get_cell(0,1), tMat.get_cell(0,2), tMat.get_cell(0,3)},
367  {tMat.get_cell(1,0), tMat.get_cell(1,1), tMat.get_cell(1,2), tMat.get_cell(1,3)},
368  {tMat.get_cell(2,0), tMat.get_cell(2,1), tMat.get_cell(2,2), tMat.get_cell(2,3)},
369  {tMat.get_cell(3,0), tMat.get_cell(3,1), tMat.get_cell(3,2), tMat.get_cell(3,3)}};
370  MMatrix mat(matData);
371 
372  MTransformationMatrix matrix = MTransformationMatrix(mat);
373  MFnTransform tFn(result->_group, &status);
374  if (status != MStatus::kSuccess) {
375  status.perror("MFnTransformNode:create failed!");
376  } else {
377  tFn.set(matrix);
378  }
379  }
380 
381  if (status != MStatus::kSuccess) {
382  status.perror("MFnDagNode:create failed!");
383  }
384 
385  if ((pg) && (pg->_addedEggFlag == false)){
386  // [gjeon] to handle other flags
387  MStringArray eggFlags;
388  for (int i = 0; i < context->get_num_object_types(); i++) {
389  eggFlags.append(MString(context->get_object_type(i).c_str()));
390  }
391 
392  for (unsigned i = 0; i < eggFlags.length(); i++) {
393  MString attrName = "eggObjectTypes";
394  attrName += (int)(i + 1);
395  status = create_enum_attribute(parent, attrName, attrName, eggFlags, i);
396  if (status != MStatus::kSuccess) {
397  status.perror("create_enum_attribute failed!");
398  }
399  }
400  pg->_addedEggFlag = true;
401  }
402 
403  _group_tab[group] = result;
404  return result;
405 }
406 
407 MayaEggGroup *MayaEggLoader::FindGroup(EggGroup *group)
408 {
409  if (group==0) {
410  return 0;
411  }
412  return _group_tab[group];
413 }
414 
415 ////////////////////////////////////////////////////////////////////////////////////////////////////
416 //
417 // MayaEggJoint
418 //
419 ////////////////////////////////////////////////////////////////////////////////////////////////////
420 
422 {
423 public:
424  LMatrix4d _trans;
425  LVector3d _endpos;
426  LVector3d _perp;
427  double _thickness;
428  MObject _joint;
429  MMatrix _joint_abs;
430  MDagPath _joint_dag_path;
431  bool _inskin;
432  int _index;
433  EggGroup *_egg_joint;
434  EggGroup *_egg_parent;
435  MayaEggJoint *_parent;
436  vector <MayaEggJoint *> _children;
437 
438 public:
439  void GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv);
440  LVector3d GetPos(void) { return _trans.get_row3(3); }
441  MayaEggJoint *ChooseBestChild(LVector3d dir);
442  void ChooseEndPos(double thickness);
443  void CreateMayaBone(MayaEggGroup *eggParent);
444  void AssignNames(void);
445 };
446 
447 void MayaEggJoint::GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv)
448 {
449  xv = _trans.get_row3(0);
450  yv = _trans.get_row3(1);
451  zv = _trans.get_row3(2);
452  xv.normalize();
453  yv.normalize();
454  zv = xv.cross(yv);
455  zv.normalize();
456  yv = zv.cross(xv);
457 }
458 
459 void MayaEggJoint::AssignNames(void)
460 {
461  string name = _egg_joint->get_name();
462  MFnDependencyNode joint(_joint);
463  joint.setName(name.c_str());
464  if (mayaloader_cat.is_spam()) {
465  mayaloader_cat.spam() << "joint " << joint.name().asChar() << ": -> " << name << endl;
466  }
467 }
468 
469 MayaEggJoint *MayaEggLoader::FindJoint(EggGroup *joint)
470 {
471  if (joint==(EggGroup *)NULL) {
472  if (mayaloader_cat.is_spam()) {
473  mayaloader_cat.spam() << "joint:" << joint->get_name() << " is null: " << endl;
474  }
475  return 0;
476  }
477  if (!joint->is_joint()) {
478  if (mayaloader_cat.is_spam()) {
479  mayaloader_cat.spam() << "joint:" << joint->get_name() << " is not a joint: " << endl;
480  }
481  return 0;
482  }
483  return _joint_tab[joint];
484 }
485 
486 MayaEggJoint *MayaEggLoader::MakeJoint(EggGroup *joint, EggGroup *context)
487 {
488  MayaEggJoint *parent = FindJoint(context);
489  if (mayaloader_cat.is_debug()) {
490  string parent_name = "";
491  if (parent)
492  parent_name = context->get_name();
493  }
494  MayaEggJoint *result = new MayaEggJoint;
495  LMatrix4d t = joint->get_transform3d();
496  if (parent) {
497  result->_trans = t * parent->_trans;
498  } else {
499  result->_trans = t;
500  }
501  result->_endpos = LVector3d(0,0,0);
502  result->_perp = LVector3d(0,0,0);
503  result->_thickness = 0.0;
504  result->_egg_joint = joint;
505  result->_egg_parent = context;
506  result->_parent = parent;
507  result->_joint = MObject::kNullObj;
508  result->_inskin = false;
509  result->_index = -1;
510  if (parent) {
511  parent->_children.push_back(result);
512  }
513  _joint_tab[joint] = result;
514 
515  // [gjeon] since _joint_tab is not always properly sorted
516  _joint_list.push_back(result);
517 
518  return result;
519 }
520 
521 MayaEggJoint *MayaEggJoint::ChooseBestChild(LVector3d dir)
522 {
523  if (dir.length() < 0.001) {
524  return 0;
525  }
526  dir.normalize();
527  double firstbest = -1000;
528  MayaEggJoint *firstchild = 0;
529  LVector3d firstpos = GetPos();
530  double secondbest = 0;
531  for (unsigned int i=0; i<_children.size(); i++) {
532  MayaEggJoint *child = _children[i];
533  LVector3d tryfwd = child->GetPos() - GetPos();
534  if ((child->GetPos() != firstpos) && (tryfwd.length() > 0.001)) {
535  LVector3d trydir = tryfwd;
536  trydir.normalize();
537  double quality = trydir.dot(dir);
538  if (quality > firstbest) {
539  secondbest = firstbest;
540  firstbest = quality;
541  firstpos = child->GetPos();
542  firstchild = child;
543  } else if (quality > secondbest) {
544  secondbest = quality;
545  }
546  }
547  }
548  if (firstbest > secondbest + 0.1) {
549  return firstchild;
550  }
551  return 0;
552 }
553 
554 void MayaEggJoint::ChooseEndPos(double thickness)
555 {
556  LVector3d parentpos(0,0,0);
557  LVector3d parentendpos(0,0,1);
558  if (_parent) {
559  parentpos = _parent->GetPos();
560  parentendpos = _parent->_endpos;
561  }
562  LVector3d fwd = GetPos() - parentpos;
563  if (fwd.length() < 0.001) {
564  fwd = parentendpos - parentpos;
565  }
566  //mayaloader_cat.debug() << "fwd : " << fwd << endl;
567  fwd.normalize();
568  MayaEggJoint *child = ChooseBestChild(fwd);
569  if (child == 0) {
570  _endpos = fwd * thickness * 0.8 + GetPos();
571  _thickness = thickness * 0.8;
572  } else {
573  _endpos = child->GetPos();
574  _thickness = (_endpos - GetPos()).length();
575  if (_thickness > thickness) _thickness = thickness;
576  }
577  LVector3d orient = _endpos - GetPos();
578  orient.normalize();
579  LVector3d altaxis = orient.cross(LVector3d(0,-1,0));
580  if (altaxis.length() < 0.001) {
581  altaxis = orient.cross(LVector3d(0,0,1));
582  }
583  _perp = altaxis.cross(orient);
584  _perp.normalize();
585 }
586 
587 void MayaEggJoint::CreateMayaBone(MayaEggGroup *eggParent)
588 {
589  LVector3d rxv, ryv, rzv;
590  //GetRotation(rxv, ryv, rzv);
591  // [gjeon] I think we shouldn't need to use this GetRotation function here
592  // since this function removes scale information from the matrix.
593  // Let's just use the matrix directly.
594  rxv = _trans.get_row3(0);
595  ryv = _trans.get_row3(1);
596  rzv = _trans.get_row3(2);
597 
598  MFloatPoint xv(MakeMayaPoint(rxv));
599  MFloatPoint yv(MakeMayaPoint(ryv));
600  MFloatPoint zv(MakeMayaPoint(rzv));
601  MFloatPoint pos(MakeMayaPoint(GetPos()));
602  MFloatPoint endpos(MakeMayaPoint(_endpos));
603  MFloatPoint tzv(MakeMayaPoint(_perp));
604  double m[4][4];
605  m[0][0]=xv.x; m[0][1]=xv.y; m[0][2]=xv.z; m[0][3]=0;
606  m[1][0]=yv.x; m[1][1]=yv.y; m[1][2]=yv.z; m[1][3]=0;
607  m[2][0]=zv.x; m[2][1]=zv.y; m[2][2]=zv.z; m[2][3]=0;
608  m[3][0]=pos.x; m[3][1]=pos.y; m[3][2]=pos.z; m[3][3]=1;
609  MMatrix trans(m);
610  _joint_abs = trans;
611  if (_parent) {
612  trans = trans * _parent->_joint_abs.inverse();
613  }
614  MTransformationMatrix mtm(trans);
615 
616  MFnIkJoint ikj;
617  if (_parent) {
618  ikj.create(_parent->_joint);
619  }
620  else {
621  if (eggParent) {
622  // must be part of a group that is not a joint
623  ikj.create(eggParent->_group);
624  } else {
625  ikj.create();
626  }
627  }
628  ikj.set(mtm);
629 
630  _joint = ikj.object();
631  ikj.getPath(_joint_dag_path);
632 }
633 
634 
635 ////////////////////////////////////////////////////////////////////////////////////////////////////
636 //
637 // MayaEggGeom : base abstract class of MayaEggMesh and MayaEggNurbsSurface
638 //
639 ////////////////////////////////////////////////////////////////////////////////////////////////////
640 
641 typedef pair<double, EggGroup *> MayaEggWeight;
642 
644 {
645  LVertexd _pos;
646  LNormald _normal;
647  LTexCoordd _uv;
648  vector<MayaEggWeight> _weights;
649  double _sumWeights; // [gjeon] to be used in normalizing weights
650  int _index;
651  int _external_index; // masad: use egg's index directly
652 };
653 
654 struct MEV_Compare: public stl_hash_compare<MayaEggVertex>
655 {
656  size_t operator()(const MayaEggVertex &key) const
657  {
658  return key._pos.add_hash(key._normal.get_hash());
659  }
660  bool operator()(const MayaEggVertex &k1, const MayaEggVertex &k2) const
661  {
662  int n = k1._pos.compare_to(k2._pos);
663  if (n < 0) {
664  return true;
665  }
666  if (n > 0) {
667  return false;
668  }
669  n = k1._normal.compare_to(k2._normal);
670  if (n < 0) {
671  return true;
672  }
673  if (n > 0) {
674  return false;
675  }
676  n = k1._uv.compare_to(k2._uv);
677  if (n < 0) {
678  return true;
679  }
680  if (n > 0) {
681  return false;
682  }
683  n = k1._weights.size() - k2._weights.size();
684  if (n < 0) {
685  return true;
686  }
687  if (n > 0) {
688  return false;
689  }
690  for (unsigned int i=0; i<k1._weights.size(); i++) {
691  double d = k1._weights[i].first - k2._weights[i].first;
692  if (d < 0) {
693  return true;
694  }
695  if (d > 0) {
696  return false;
697  }
698  EggGroup *g1 = k1._weights[i].second;
699  EggGroup *g2 = k2._weights[i].second;
700  if (g1 < g2) {
701  return true;
702  }
703  if (g1 > g2) {
704  return false;
705  }
706  }
707  n = k1._external_index - k2._external_index;
708 
709  if (n < 0) {
710  return true;
711  }
712  if (n > 0) {
713  return false;
714  }
715 
716  return false;
717  }
718 };
719 
720 typedef phash_set<MayaEggVertex, MEV_Compare> VertTable;
721 
723 {
724 public:
725 
726  EggVertexPool *_pool;
727  MObject _transNode;
728  MObject _shapeNode;
729  EggGroup *_parent;
730  MDagPath _shape_dag_path;
731  int _vert_count;
732 
733  string _name;
734 
735  MFloatPointArray _vertexArray;
736  MVectorArray _normalArray;
737  MColorArray _vertColorArray;
738  MIntArray _vertColorIndices;
739  MIntArray _vertNormalIndices;
740 
741  MStringArray _eggObjectTypes;
742  VertTable _vert_tab;
743 
744  bool _renameTrans;
745 
746  int GetVert(EggVertex *vert, EggGroup *context);
747  EggGroup *GetControlJoint(void);
748 
749  virtual void ConnectTextures(void) = 0;
750  void AssignNames(void);
751  void AddEggFlag(MString);
752 };
753 
754 // [gjeon] moved from MayaEggMesh to MayaEggGeom
755 int MayaEggGeom::GetVert(EggVertex *vert, EggGroup *context)
756 {
757  MayaEggVertex vtx;
758  vtx._sumWeights = 0.0;
759 
760  const LMatrix4d &xform = context->get_vertex_to_node();
761 
762  vtx._pos = vert->get_pos3() * xform;
763  if (vert->has_normal()) {
764  vtx._normal = vert->get_normal() * xform;
765  }
766  if (vert->has_uv()) {
767  vtx._uv = vert->get_uv();
768  }
769  vtx._index = 0;
770  vtx._external_index = vert->get_index()-1;
771 
772  EggVertex::GroupRef::const_iterator gri;
773  //double remaining_weight = 1.0;
774  for (gri = vert->gref_begin(); gri != vert->gref_end(); ++gri) {
775  EggGroup *egg_joint = (*gri);
776  double membership = egg_joint->get_vertex_membership(vert);
777 
778  if (membership < 0)
779  {
780  mayaloader_cat.warning() << "negative weight value " << membership << " is replaced with 0 on: " << context->get_name() << endl;
781  membership = 0.0;
782  }
783  //remaining_weight -= membership;
784  vtx._weights.push_back(MayaEggWeight(membership, egg_joint));
785  vtx._sumWeights += membership; // [gjeon] to be used in normalizing weights
786  }
787 
788  if (vtx._weights.size()==0) {
789  if (context != 0) {
790  vtx._weights.push_back(MayaEggWeight(1.0, context));
791  vtx._sumWeights = 1.0; // [gjeon] to be used in normalizing weights
792  }
793  //remaining_weight = 0.0;
794  }/* else {
795  // some soft models came up short of 1.0 on vertex membership
796  // add the remainder of the weight on first joint in the membership
797  if ((remaining_weight) > 0.01) {
798  gri = vert->gref_begin();
799  EggGroup *egg_joint = (*gri);
800  double membership = egg_joint->get_vertex_membership(vert);
801  vtx._weights.push_back(MayaEggWeight(membership+remaining_weight, egg_joint));
802  vtx._sumWeights += (membership + remaining_weight);
803  }
804  }*/ //[gjeon] we had better nomarlize weights than add remaining weight to first weight
805 
806  VertTable::const_iterator vti = _vert_tab.find(vtx);
807  if (vti != _vert_tab.end()) {
808  /* if ((remaining_weight) > 0.01) {
809  mayaloader_cat.warning() << "weight munged to 1.0 by " << remaining_weight << " on: " << context->get_name() << " idx:" << vti->_index << endl;
810  } */
811  if (mayaloader_cat.is_spam()) {
812  ostringstream stream;
813  stream << "(" << vti->_pos << " " << vti->_normal << " " << vti->_uv << ")\n";
814  stream << "[" << vtx._pos << " " << vtx._normal << " " << vtx._uv << "]\n";
815  stream << "{" << vert->get_pos3() << " ";
816  if (vert->has_normal()) {
817  stream << vert->get_normal() << " ";
818  }
819  if (vert->has_uv()) {
820  stream << vert->get_uv();
821  }
822  stream << "}";
823  mayaloader_cat.spam() << "found a matching vertex: " << *vert << endl << stream.str() << endl;
824  }
825  return vti->_index;
826  }
827 
828  //_vert_count++;
829  vtx._index = _vert_count++;
830  /*
831  if ((remaining_weight) > 0.01) {
832  mayaloader_cat.warning() << "weight munged to 1.0 by " << remaining_weight << " on: " << context->get_name() << " idx:" << vtx._index << endl;
833  } */
834 
835  _vertexArray.append(MakeMayaPoint(vtx._pos));
836  if (vert->has_normal()) {
837  _normalArray.append(MakeMayaVector(vtx._normal));
838  _vertNormalIndices.append(vtx._index);
839  }
840  if (vert->has_color()) {
841  if (mayaloader_cat.is_spam()) {
842  mayaloader_cat.spam() << "found a vertex color\n";
843  }
844  _vertColorArray.append(MakeMayaColor(vert->get_color()));
845  _vertColorIndices.append(vtx._index);
846  }
847  _vert_tab.insert(vtx);
848  return vtx._index;
849 }
850 
851 // [gjeon] moved from MayaEggMesh to MayaEggGeom
852 void MayaEggGeom::AssignNames(void)
853 {
854  string name = _pool->get_name();
855  int nsize = name.size();
856  if ((nsize > 6) && (name.rfind(".verts")==(nsize-6))) {
857  name.resize(nsize-6);
858  }
859  if ((nsize > 4) && (name.rfind(".cvs")==(nsize-4))) {
860  name.resize(nsize-4);
861  }
862 
863  MFnDependencyNode dnshape(_shapeNode);
864  MFnDependencyNode dntrans(_transNode);
865 
866  if (_renameTrans) {
867  dntrans.setName(MString(name.c_str()));
868  }
869 
870  string shape_name = string(dntrans.name().asChar());
871  string numbers ("0123456789");
872  size_t found;
873 
874  found=shape_name.find_last_not_of(numbers);
875  if (found!=string::npos)
876  shape_name.insert(found+1, "Shape");
877  else
878  shape_name.append("Shape");
879 
880  dnshape.setName(MString(shape_name.c_str()));
881 }
882 
883 #define CTRLJOINT_DEFORM ((EggGroup*)((char*)(-1)))
884 
885 // [gjeon] moved from MayaEggMesh to MayaEggGeom
886 EggGroup *MayaEggGeom::GetControlJoint(void)
887 {
888  EggGroup *result;
889  VertTable::const_iterator vert = _vert_tab.begin();
890  if (vert == _vert_tab.end()) {
891  return 0;
892  }
893  switch (vert->_weights.size()) {
894  case 0:
895  for (++vert; vert != _vert_tab.end(); ++vert) {
896  if (vert->_weights.size() != 0) {
897  return CTRLJOINT_DEFORM;
898  }
899  }
900  return 0;
901  case 1:
902  result = vert->_weights[0].second;
903  for (++vert; vert != _vert_tab.end(); ++vert) {
904  if ((vert->_weights.size() != 1) || (vert->_weights[0].second != result)) {
905  return CTRLJOINT_DEFORM;
906  }
907  }
908  return result;
909  default:
910  return CTRLJOINT_DEFORM;
911  }
912 }
913 
914 void MayaEggGeom::AddEggFlag(MString fieldName) {
915  bool addNewFlag = true;
916  for (unsigned i = 0; i < _eggObjectTypes.length(); i++) {
917  if (_eggObjectTypes[i] == fieldName) {
918  addNewFlag = false;
919  break;
920  }
921  }
922  if (addNewFlag) {
923  _eggObjectTypes.append(fieldName);
924  }
925 }
926 
927 ////////////////////////////////////////////////////////////////////////////////////////////////////
928 //
929 // MayaEggMesh
930 //
931 ////////////////////////////////////////////////////////////////////////////////////////////////////
932 typedef phash_map<LTexCoordd, int> TVertTable;
933 typedef phash_map<LColor, int> CVertTable;
934 
935 class MayaEggMesh : public MayaEggGeom
936 {
937 public:
938  MColorArray _faceColorArray;
939  MIntArray _faceIndices;
940  MIntArray _polygonCounts;
941  MIntArray _polygonConnects;
942  MFloatArray _uarray;
943  MFloatArray _varray;
944  MIntArray _uvIds;
945 
946 
947  int _tvert_count;
948  int _cvert_count;
949  int _face_count;
950  vector<MayaEggTex*> _face_tex;
951 
952  TVertTable _tvert_tab;
953  CVertTable _cvert_tab;
954 
955  int GetTVert(const LTexCoordd &uv);
956  int GetCVert(const LColor &col);
957  int AddFace(unsigned numVertices, MIntArray mvertIndices, MIntArray mtvertIndices, MayaEggTex *tex);
958 
959  void ConnectTextures(void);
960 };
961 
962 int MayaEggMesh::GetTVert(const LTexCoordd &uv)
963 {
964  if (_tvert_tab.count(uv)) {
965  if (mayaloader_cat.is_spam()) {
966  mayaloader_cat.spam() << "found uv coords idx: " << _tvert_tab[uv] << endl;
967  }
968  return _tvert_tab[uv];
969  }
970  int idx = _tvert_count++;
971  _uarray.append(uv.get_x());
972  _varray.append(uv.get_y());
973  _tvert_tab[uv] = idx;
974  if (mayaloader_cat.is_spam()) {
975  mayaloader_cat.spam() << "adding uv coords idx:" << idx << endl;
976  }
977  return idx;
978 }
979 
980 int MayaEggMesh::GetCVert(const LColor &col)
981 {
982  // if (_cvert_tab.count(col))
983  // return _cvert_tab[col];
984  // if (_cvert_count == _mesh->numCVerts) {
985  // int nsize = _cvert_count*2 + 100;
986  // _mesh->setNumVertCol(nsize, _cvert_count?TRUE:FALSE);
987  // }
988  // int idx = _cvert_count++;
989  // _mesh->vertCol[idx] = Point3(col.get_x(), col.get_y(), col.get_z());
990  // _cvert_tab[col] = idx;
991  // return idx;
992  return 0;
993 }
994 
995 MayaEggMesh *MayaEggLoader::GetMesh(EggVertexPool *pool, EggGroup *parent)
996 {
997  MayaEggMesh *result = _mesh_tab[parent];
998  if (result == 0) {
999  result = new MayaEggMesh;
1000  result->_name = parent->get_name();
1001  result->_pool = pool;
1002  result->_parent = parent;
1003  result->_vert_count = 0;
1004  result->_tvert_count = 0;
1005  result->_cvert_count = 0;
1006  result->_face_count = 0;
1007  result->_vertColorArray.clear();
1008  result->_vertNormalIndices.clear();
1009  result->_vertColorIndices.clear();
1010  result->_faceColorArray.clear();
1011  result->_faceIndices.clear();
1012  result->_eggObjectTypes.clear();
1013  result->_renameTrans = false;
1014  _mesh_tab[parent] = result;
1015  }
1016  return result;
1017 }
1018 
1019 int MayaEggMesh::AddFace(unsigned numVertices, MIntArray mvertIndices, MIntArray mtvertIndices, MayaEggTex *tex)
1020 {
1021  int idx = _face_count++;
1022  _polygonCounts.append(numVertices);
1023  for (unsigned i = 0; i < mvertIndices.length(); i++)
1024  {
1025  _polygonConnects.append(mvertIndices[i]);
1026  _uvIds.append(mtvertIndices[i]);
1027  }
1028  _face_tex.push_back(tex);
1029  return idx;
1030 }
1031 
1032 void MayaEggMesh::ConnectTextures(void)
1033 {
1034  bool subtex = false;
1035  for (int i=1; i<_face_count; i++) {
1036  if (_face_tex[i] != _face_tex[0]) {
1037  subtex = true;
1038  }
1039  }
1040  if (!subtex) {
1041  MFnSet sg(_face_tex[0]->_shading_group);
1042  sg.addMember(_shapeNode);
1043  return;
1044  }
1045  for (int i=0; i<_face_count; i++) {
1046  MayaEggTex *tex = _face_tex[i];
1047  if (tex->_component.object()==MObject::kNullObj) {
1048  tex->_component.create(MFn::kMeshPolygonComponent);
1049  }
1050  tex->_component.addElement(i);
1051  }
1052  for (int i=0; i<_face_count; i++) {
1053  MayaEggTex *tex = _face_tex[i];
1054  if (tex->_component.object()!=MObject::kNullObj) {
1055  MFnSet sg(tex->_shading_group);
1056  sg.addMember(_shape_dag_path, tex->_component.object());
1057  tex->_component.setObject(MObject::kNullObj);
1058  }
1059  }
1060 }
1061 
1062 
1063 ////////////////////////////////////////////////////////////////////////////////////////////////////
1064 //
1065 // MayaEggNurbsSurface
1066 //
1067 ////////////////////////////////////////////////////////////////////////////////////////////////////
1069 {
1070 public:
1071 
1072 
1073  MPointArray _cvArray;
1074  MDoubleArray _uKnotArray;
1075  MDoubleArray _vKnotArray;
1076  unsigned _uDegree;
1077  unsigned _vDegree;
1078  unsigned _uNumCvs;
1079  unsigned _vNumCvs;
1080 
1081  MFnNurbsSurface::Form _uForm;
1082  MFnNurbsSurface::Form _vForm;
1083 
1084  MayaEggTex *_tex;
1085 
1086  void ConnectTextures(void);
1087  void PrintData(void);
1088 };
1089 
1090 MayaEggNurbsSurface *MayaEggLoader::GetSurface(EggVertexPool *pool, EggGroup *parent)
1091 {
1092  MayaEggNurbsSurface *result = _surface_tab[parent];
1093  if (result == 0) {
1094  result = new MayaEggNurbsSurface;
1095  result->_pool = pool;
1096  result->_parent = parent;
1097  result->_name = parent->get_name();
1098 
1099  result->_vert_count = 0;
1100  result->_vertColorArray.clear();
1101  result->_vertNormalIndices.clear();
1102  result->_vertColorIndices.clear();
1103 
1104  result->_cvArray.clear();
1105  result->_uKnotArray.clear();
1106  result->_vKnotArray.clear();
1107 
1108  result->_uDegree = 0;
1109  result->_vDegree = 0;
1110  result->_uNumCvs = 0;
1111  result->_vNumCvs = 0;
1112  result->_uForm = MFnNurbsSurface::kClosed;
1113  result->_vForm = MFnNurbsSurface::kClosed;
1114 
1115  result->_eggObjectTypes.clear();
1116  result->_renameTrans = false;
1117  _surface_tab[parent] = result;
1118  }
1119  return result;
1120 }
1121 
1122 void MayaEggNurbsSurface::ConnectTextures(void)
1123 {
1124  // masad: since nurbs surfaces do not support vertex colors
1125  // I am infusing the surface's first vertex color (if any)
1126  // into the shader to achive the color.
1127  // masad: check if there is any vertex color for this surface
1128  MStatus status;
1129  MColor firstColor(0.5,0.5,0.5,1.0);
1130  if (_vertColorArray.length() > 0) {
1131  firstColor = _vertColorArray[0];
1132  MFnLambertShader sh(_tex->_shader);
1133  status = sh.setColor(firstColor);
1134  if (status != MStatus::kSuccess) {
1135  mayaloader_cat.error() << "setColor failed on " << _name;
1136  status.perror("shader setColor failed!");
1137  }
1138  }
1139  MFnSet sg(_tex->_shading_group);
1140  status = sg.addMember(_shapeNode);
1141  if (status != MStatus::kSuccess) {
1142  mayaloader_cat.error() << "addMember failed on " << _name;
1143  status.perror("shader addMember failed!");
1144  }
1145  return;
1146 }
1147 
1148 void MayaEggNurbsSurface::PrintData(void)
1149 {
1150  if (mayaloader_cat.is_debug()) {
1151  mayaloader_cat.debug() << "nurbsSurface : " << _name << endl;
1152 
1153  mayaloader_cat.debug() << "u_form : " << _uForm << endl;
1154  mayaloader_cat.debug() << "v_form : " << _vForm << endl;
1155  }
1156 
1157  /*
1158  for (unsigned i = 0; i < _cvArray.length(); i++)
1159  {
1160  MPoint cv =_cvArray[i];
1161  mayaloader_cat.debug() << cv[0] << " " << cv[1] << " " << cv[2] << endl;
1162  }
1163 
1164  for (unsigned i = 0; i < _uKnotArray.length(); i++)
1165  {
1166  mayaloader_cat.debug() << _uKnotArray[i] << endl;
1167  }
1168 
1169  for (unsigned i = 0; i < _vKnotArray.length(); i++)
1170  {
1171  mayaloader_cat.debug() << _vKnotArray[i] << endl;
1172  }
1173  */
1174 }
1175 
1176 ///////////////////////////////////////////////////////////////////////////////////////////////////
1177 //
1178 // MayaAnim:
1179 //
1180 ///////////////////////////////////////////////////////////////////////////////////////////////////
1182 {
1183 public:
1184  string _name;
1185  EggTable *_joint;
1186  EggXfmSAnim *_pool;
1187  void PrintData(void);
1188 };
1189 
1190 MayaAnim *MayaEggLoader::GetAnim(EggXfmSAnim *pool)
1191 {
1192  MayaAnim *result = _anim_tab[pool];
1193  if (result == 0) {
1194  result = new MayaAnim;
1195  result->_pool = pool;
1196  result->_name = pool->get_name();
1197  _anim_tab[pool] = result;
1198  EggNode *jointNode = (DCAST(EggNode, pool))->get_parent();
1199  EggTable *joint = DCAST(EggTable, jointNode);
1200  result->_joint = joint;
1201 
1202  }
1203  return result;
1204 }
1205 
1206 void MayaAnim::PrintData(void)
1207 {
1208  if (mayaloader_cat.is_debug()) {
1209  mayaloader_cat.debug() << "anim on joint : " << _joint->get_name() << endl;
1210  }
1211  _pool->write(mayaloader_cat.debug(), 0);
1212 }
1213 
1214 ///////////////////////////////////////////////////////////////////////////////////////////////////
1215 //
1216 // MayaEggLoader functions
1217 //
1218 ///////////////////////////////////////////////////////////////////////////////////////////////////
1219 
1220 void MayaEggLoader::CreateSkinCluster(MayaEggGeom *M)
1221 {
1222  MString cmd("skinCluster -mi ");
1223  vector <MayaEggJoint *> joints;
1224 
1225  VertTable::const_iterator vert;
1226  int maxInfluences = 0;
1227  for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) {
1228  if ((int)(vert->_weights.size()) > maxInfluences) {
1229  maxInfluences = vert->_weights.size();
1230  }
1231  for (unsigned int i=0; i<vert->_weights.size(); i++) {
1232  MayaEggJoint *joint = FindJoint(vert->_weights[i].second);
1233  if (joint && !joint->_inskin) {
1234  joint->_inskin = true;
1235  joint->_index = joints.size();
1236  joints.push_back(joint);
1237  /*
1238  if (mayaloader_cat.is_spam()) {
1239  mayaloader_cat.spam() << joints[i]->_egg_joint->get_name() << ": adding to skin\n";
1240  }
1241  */
1242  }
1243  }
1244  }
1245  cmd += maxInfluences;
1246 
1247  /*
1248  if (mayaloader_cat.is_spam()) {
1249  mayaloader_cat.spam() << joints.size() << " joints have weights on " << M->_pool->get_name() << endl;
1250  }
1251  */
1252  if (joints.size() == 0) {
1253  // no need to cluster; there are no weights
1254  return;
1255  }
1256 
1257  for (unsigned int i=0; i<joints.size(); i++) {
1258  MFnDependencyNode joint(joints[i]->_joint);
1259  cmd = cmd + " ";
1260  cmd = cmd + joint.name();
1261  }
1262 
1263  MFnDependencyNode shape(M->_shapeNode);
1264  cmd = cmd + " ";
1265  cmd = cmd + shape.name();
1266 
1267  MStatus status;
1268  MDGModifier dgmod;
1269  if (mayaloader_cat.is_spam()) {
1270  mayaloader_cat.spam() << cmd.asChar() << endl;
1271  string spamCmd = M->_pool->get_name();
1272  for (unsigned int i=0; i<joints.size(); i++) {
1273  spamCmd = spamCmd + " ";
1274  spamCmd = spamCmd + joints[i]->_egg_joint->get_name();
1275  }
1276  mayaloader_cat.spam() << spamCmd << ": total = " << joints.size() << endl;
1277  }
1278  status = dgmod.commandToExecute(cmd);
1279  if (status != MStatus::kSuccess) {
1280  perror("skinCluster commandToExecute");
1281  return;
1282  }
1283  status = dgmod.doIt();
1284  if (status != MStatus::kSuccess) {
1285  perror("skinCluster doIt");
1286  return;
1287  }
1288 
1289  MPlugArray oldplugs;
1290  MPlug inPlug;
1291  if (shape.typeName() == "mesh") {
1292  inPlug = shape.findPlug("inMesh");
1293  } else if (shape.typeName() == "nurbsSurface") {
1294  inPlug = shape.findPlug("create");
1295  } else {
1296  // we only support mesh and nurbsSurface
1297  return;
1298  }
1299 
1300  if ((!inPlug.connectedTo(oldplugs,true,false))||(oldplugs.length() != 1)) {
1301  cerr << "skinCluster command failed";
1302  return;
1303  }
1304  MFnSkinCluster skinCluster(oldplugs[0].node());
1305  MIntArray influenceIndices;
1306  MFnSingleIndexedComponent component;
1307  component.create(MFn::kMeshVertComponent); // [gjeon] Interestingly, we can use MFn::kMeshVertComponent for NURBS surface, too
1308  component.setCompleteData(M->_vert_count);
1309  for (unsigned int i=0; i<joints.size(); i++) {
1310  unsigned int index = skinCluster.indexForInfluenceObject(joints[i]->_joint_dag_path, &status);
1311  if (status != MStatus::kSuccess) {
1312  perror("skinCluster index");
1313  return;
1314  }
1315  influenceIndices.append((int)index);
1316  }
1317 
1318  MDagPathArray paths;
1319  unsigned infcount = skinCluster.influenceObjects(paths, &status);
1320  if (status != MStatus::kSuccess) {
1321  perror("influenceObjects");
1322  return;
1323  }
1324  for (unsigned int i=0; i<infcount; i++) {
1325  unsigned int index = skinCluster.indexForInfluenceObject(paths[i], &status);
1326  if (status != MStatus::kSuccess) {
1327  perror("skinCluster index");
1328  return;
1329  }
1330  skinCluster.setWeights(M->_shape_dag_path, component.object(), index, 0.0, false, NULL);
1331  }
1332 
1333  MFloatArray values;
1334  int tot = M->_vert_count * joints.size();
1335  values.setLength(tot);
1336  for (int i=0; i<tot; i++) {
1337  values[i] = 0.0;
1338  }
1339  for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) {
1340  for (unsigned int i=0; i<vert->_weights.size(); i++) {
1341  double strength = vert->_weights[i].first / vert->_sumWeights; // [gjeon] nomalizing weights
1342  MayaEggJoint *joint = FindJoint(vert->_weights[i].second);
1343  values[vert->_index * joints.size() + joint->_index] = (PN_stdfloat)strength;
1344  }
1345  }
1346  skinCluster.setWeights(M->_shape_dag_path, component.object(), influenceIndices, values, false, NULL);
1347 
1348  for (unsigned int i=0; i<joints.size(); i++) {
1349  /*
1350  if (mayaloader_cat.is_spam()) {
1351  mayaloader_cat.spam() << joints[i]->_egg_joint->get_name() << ": clearing skin\n";
1352  }
1353  */
1354  joints[i]->_inskin = false;
1355  joints[i]->_index = -1;
1356  }
1357 }
1358 
1359 ////////////////////////////////////////////////////////////////////////////////////////////////////
1360 //
1361 // TraverseEggData
1362 //
1363 // We have an EggData in memory, and now we're going to copy that
1364 // over into the maya scene graph.
1365 //
1366 ////////////////////////////////////////////////////////////////////////////////////////////////////
1367 
1368 void MayaEggLoader::TraverseEggNode(EggNode *node, EggGroup *context, string delim)
1369 {
1370  vector<int> vertIndices;
1371  vector<int> tvertIndices;
1372  vector<int> cvertIndices;
1373 
1374  string delstring = " ";
1375 
1376  if (node->is_of_type(EggPolygon::get_class_type())) {
1377  /*
1378  if (mayaloader_cat.is_debug()) {
1379  mayaloader_cat.debug() << delim+delstring << "found an EggMesh: " << node->get_name() << endl;
1380  }
1381  */
1382  EggPolygon *poly = DCAST(EggPolygon, node);
1383  if (poly->empty()) {
1384  return;
1385  }
1386  poly->cleanup();
1387 
1388  MayaEggTex *tex = 0;
1389  LMatrix3d uvtrans = LMatrix3d::ident_mat();
1390 
1391  if (poly->has_texture()) {
1392  EggTexture *etex = poly->get_texture(0);
1393  if (mayaloader_cat.is_spam()) {
1394  mayaloader_cat.spam() << "Texture format : " << etex->get_format() << endl;
1395  }
1396  tex = GetTex(etex);
1397  if (etex->has_transform())
1398  uvtrans = etex->get_transform2d();
1399  } else {
1400  tex = GetTex(NULL);
1401  }
1402 
1403  EggPolygon::const_iterator ci;
1404  MayaEggMesh *mesh = GetMesh(poly->get_pool(), context);
1405  if (mayaloader_cat.is_spam()) {
1406  mayaloader_cat.spam() << "traverse mesh pointer " << mesh << "\n";
1407  }
1408  vertIndices.clear();
1409  tvertIndices.clear();
1410  cvertIndices.clear();
1411  int numVertices = 0;
1412  for (ci = poly->begin(); ci != poly->end(); ++ci) {
1413  EggVertex *vtx = (*ci);
1414  EggVertexPool *pool = poly->get_pool();
1415  LTexCoordd uv(0,0);
1416  if (vtx->has_uv()) {
1417  uv = vtx->get_uv();
1418  }
1419  vertIndices.push_back(mesh->GetVert(vtx, context));
1420  tvertIndices.push_back(mesh->GetTVert(uv * uvtrans));
1421  cvertIndices.push_back(mesh->GetCVert(vtx->get_color()));
1422  numVertices++;
1423  }
1424  if (mayaloader_cat.is_spam()) {
1425  mayaloader_cat.spam() << "num vertices: " << vertIndices.size() << "\n";
1426  }
1427 
1428  if (numVertices < 3)
1429  return;
1430 
1431  MIntArray mvertIndices;
1432  MIntArray mtvertIndices;
1433  for (int i = 0; i < numVertices; i++) {
1434  mvertIndices.append(vertIndices[i]);
1435  mtvertIndices.append(tvertIndices[i]);
1436  }
1437  if (poly->has_color()) {
1438  if (mayaloader_cat.is_spam()) {
1439  mayaloader_cat.spam() << "found a face color of " << poly->get_color() << endl;
1440  }
1441  mesh->_faceIndices.append(mesh->_face_count);
1442  mesh->_faceColorArray.append(MakeMayaColor(poly->get_color()));
1443  }
1444  mesh->AddFace(numVertices, mvertIndices, mtvertIndices, tex);
1445 
1446  // [gjeon] to handle double-sided flag
1447  if (poly->get_bface_flag()) {
1448  mesh->AddEggFlag("double-sided");
1449  }
1450 
1451  // [gjeon] to handle model flag
1452  if (context->get_model_flag()) {
1453  mesh->AddEggFlag("model");
1454  }
1455 
1456  // [gjeon] to handle billboard flag
1457  switch (context->get_billboard_type()) {
1458  case EggGroup::BT_axis:
1459  mesh->AddEggFlag("billboard");
1460  break;
1461 
1462  case EggGroup::BT_point_camera_relative:
1463  mesh->AddEggFlag("billboard-point");
1464  break;
1465 
1466  default:
1467  ;
1468  }
1469 
1470  // [gjeon] to handle other flags
1471  for (int i = 0; i < context->get_num_object_types(); i++) {
1472  mesh->AddEggFlag(MString(context->get_object_type(i).c_str()));
1473  }
1474 
1475  } else if (node->is_of_type(EggNurbsSurface::get_class_type())) {
1476  // [gjeon] to convert nurbsSurface
1477  EggNurbsSurface *eggNurbsSurface = DCAST(EggNurbsSurface, node);
1478 
1479  EggNurbsSurface::const_iterator ci;
1480  EggVertexPool *pool = eggNurbsSurface->get_pool();
1481  MayaEggNurbsSurface *surface = GetSurface(pool, context);
1482 
1483  for (ci = eggNurbsSurface->begin(); ci != eggNurbsSurface->end(); ++ci) {
1484  EggVertex *vtx = (*ci);
1485  surface->GetVert(vtx, context);
1486  }
1487 
1488  // [gjeon] finding textures
1489  MayaEggTex *tex = 0;
1490  LMatrix3d uvtrans = LMatrix3d::ident_mat();
1491 
1492  if (eggNurbsSurface->has_texture()) {
1493  EggTexture *etex = eggNurbsSurface->get_texture(0);
1494  tex = GetTex(etex);
1495  if (etex->has_transform())
1496  {
1497  mayaloader_cat.debug() << "uvtrans?" << endl;
1498  uvtrans = etex->get_transform2d();
1499  }
1500  } else {
1501  tex = GetTex(NULL);
1502  }
1503 
1504  surface->_tex = tex;
1505  surface->_uNumCvs = eggNurbsSurface->get_num_u_cvs();
1506  surface->_vNumCvs = eggNurbsSurface->get_num_v_cvs();
1507 
1508  // [gjeon] building cvArray
1509  for (uint ui = 0; ui < surface->_uNumCvs; ui++) {
1510  for (uint vi = 0; vi < surface->_vNumCvs; vi++) {
1511  EggVertex *vtx = eggNurbsSurface->get_vertex(eggNurbsSurface->get_vertex_index(ui, vi));
1512  surface->_cvArray.append(MakeMPoint(vtx->get_pos3()));
1513  }
1514  }
1515 
1516  // [gjeon] building u knotArray
1517  for (int i = 1; i < eggNurbsSurface->get_num_u_knots()-1; i++) {
1518  surface->_uKnotArray.append(eggNurbsSurface->get_u_knot(i));
1519  }
1520 
1521  // [gjeon] building v knotArray
1522  for (int i = 1; i < eggNurbsSurface->get_num_v_knots()-1; i++) {
1523  surface->_vKnotArray.append(eggNurbsSurface->get_v_knot(i));
1524  }
1525 
1526  surface->_uDegree = eggNurbsSurface->get_u_degree();
1527  surface->_vDegree = eggNurbsSurface->get_v_degree();
1528 
1529  if (eggNurbsSurface->is_closed_u()) {
1530  surface->_uForm = MFnNurbsSurface::kClosed;
1531  } else {
1532  surface->_vForm = MFnNurbsSurface::kOpen;
1533  }
1534 
1535  if (eggNurbsSurface->is_closed_v()) {
1536  surface->_vForm = MFnNurbsSurface::kClosed;
1537  } else {
1538  surface->_vForm = MFnNurbsSurface::kOpen;
1539  }
1540 
1541  // [gjeon] to handle double-sided flag
1542  if (eggNurbsSurface->get_bface_flag()) {
1543  surface->AddEggFlag("double-sided");
1544  }
1545 
1546  // [gjeon] to handle model flag
1547  if (context->get_model_flag()) {
1548  surface->AddEggFlag("model");
1549  }
1550 
1551  // [gjeon] to handle other flags
1552  for (int i = 0; i < context->get_num_object_types(); i++) {
1553  surface->AddEggFlag(MString(context->get_object_type(i).c_str()));
1554  }
1555 
1556  } else if (node->is_of_type(EggComment::get_class_type())) {
1557  string comment = (DCAST(EggComment, node))->get_comment();
1558  if (comment.find("2egg") != string::npos) {
1559  if (mayaloader_cat.is_spam()) {
1560  mayaloader_cat.spam() << delim+delstring << "found an EggComment: " << comment << endl;
1561  }
1562  if (comment.find("chan") != string::npos) {
1563  ParseFrameInfo(comment);
1564  }
1565  }
1566  } else if (node->is_of_type(EggSAnimData::get_class_type())) {
1567  if (mayaloader_cat.is_debug()) {
1568  mayaloader_cat.debug() << delim+delstring << "found an EggSAnimData: " << node->get_name() << endl;
1569  }
1570  //EggSAnimData *anim = DCAST(EggSAnimData, node);
1571  //MayaAnimData *animData = GetAnimData(anim, DCAST(EggXfmSAnim, node->get_parent()));
1572  //animData->PrintData();
1573  //if (_end_frame < animData->_pool->get_num_rows()) {
1574  // _end_frame = animData->_pool->get_num_rows();
1575  //}
1576  } else if (node->is_of_type(EggGroupNode::get_class_type())) {
1577  EggGroupNode *group = DCAST(EggGroupNode, node);
1578  if (node->is_of_type(EggGroup::get_class_type())) {
1579  EggGroup *group = DCAST(EggGroup, node);
1580 
1581  if (group->get_name() == "") {
1582  ostringstream stream;
1583  stream << _unnamed_idx;
1584  group->set_name("unnamed" + stream.str());
1585  _unnamed_idx++;
1586  }
1587 
1588  string group_name = group->get_name();
1589  size_t found = group_name.find(":");
1590  if (found != string::npos)
1591  group->set_name(group_name.replace(int(found), 1, "_"));
1592 
1593  string parent_name = "";
1594  if (context)
1595  parent_name = context->get_name();
1596  if (group->is_joint()) {
1597  if (mayaloader_cat.is_debug()) {
1598  mayaloader_cat.debug() << delim+delstring << group->get_name() << ":" << parent_name << endl;
1599  }
1600  MakeJoint(group, context);
1601  context = group;
1602  } else {
1603  // lets create a group node for it so that it is reflected in Maya
1604  if (mayaloader_cat.is_debug()) {
1605  mayaloader_cat.debug() << delim+delstring << group->get_name() << "@" << parent_name << endl;
1606  }
1607  MakeGroup(group, context);
1608  context = group;
1609  }
1610  } else if (node->is_of_type(EggTable::get_class_type())) {
1611  //EggTable *anim = DCAST(EggTable, node);
1612  if (mayaloader_cat.is_debug()) {
1613  mayaloader_cat.debug() << delim+delstring << "found an EggTable: " << node->get_name() << endl;
1614  }
1615  } else if (node->is_of_type(EggXfmSAnim::get_class_type())) {
1616  MayaAnim *anim = GetAnim(DCAST(EggXfmSAnim, node));
1617  //anim->PrintData();
1618  if (mayaloader_cat.is_debug()) {
1619  mayaloader_cat.debug() << delim+delstring << "found an EggXfmSAnim: " << node->get_name() << endl;
1620  }
1621  }
1622 
1623  EggGroupNode::const_iterator ci;
1624  for (ci = group->begin(); ci != group->end(); ++ci) {
1625  TraverseEggNode(*ci, context, delim+delstring);
1626  }
1627  }
1628 }
1629 
1630 bool MayaEggLoader::ConvertEggData(EggData *data, bool merge, bool model, bool anim, bool respect_normals)
1631 {
1632  if (!merge) {
1633  mayaloader_cat.error() << "Currently, only 'merge' mode is implemented.\n";
1634  return false;
1635  }
1636 
1637  /*
1638  if ((anim) || (!model)) {
1639  mayaloader_cat.error() << "Currently, only model-loading is implemented.\n";
1640  return false;
1641  }
1642  */
1643 
1644  _start_frame = 0;
1645  _end_frame = 0;
1646  _frame_rate = 24;
1647  _timeUnit = MTime::kFilm;
1648  _unnamed_idx = 1;
1649 
1650  MeshTable::const_iterator ci;
1651  JointTable::const_iterator ji;
1652  TexTable::const_iterator ti;
1653  SurfaceTable::const_iterator si;
1654  AnimTable::const_iterator ei;
1655 
1656  if (MGlobal::isYAxisUp()) {
1657  data->set_coordinate_system(CS_yup_right);
1658  } else {
1659  data->set_coordinate_system(CS_zup_right);
1660  }
1661 
1662  if (mayaloader_cat.is_debug()) {
1663  mayaloader_cat.debug() << "root node: " << data->get_type() << endl;
1664  }
1665  TraverseEggNode(data, NULL, "");
1666 
1667  MStatus status;
1668 
1669  MFnSet collision_set;
1670  collision_set.create(_collision_nodes, MFnSet::kNone, &status);
1671 
1672  if (mayaloader_cat.is_spam()) {
1673  mayaloader_cat.spam() << "num meshes : " << _mesh_tab.size() << endl;
1674  }
1675  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
1676  MayaEggMesh *mesh = (*ci).second;
1677  if (mesh->_face_count==0) {
1678  continue;
1679  }
1680 
1681  // MStatus status;
1682  MFnMesh mfn;
1683  MString cset;
1684 
1685  MayaEggGroup *parentNode = FindGroup(mesh->_parent);
1686  MObject parent = MObject::kNullObj;
1687  if (parentNode) {
1688  parent = parentNode->_group;
1689  if (mayaloader_cat.is_debug()) {
1690  mayaloader_cat.debug() << "mesh's parent (group) : " << parentNode->_name << endl;
1691  }
1692  } else {
1693  mesh->_renameTrans = true;
1694  if (mayaloader_cat.is_debug()) {
1695  mayaloader_cat.debug() << "mesh's parent (null) : " << endl;
1696  }
1697  }
1698  if (mayaloader_cat.is_spam()) {
1699  mayaloader_cat.spam() << "mesh pointer : " << mesh << " and parent_pointer: " << &parent << endl;
1700  mayaloader_cat.spam() << "mesh vert_count : " << mesh->_vert_count << endl;
1701  mayaloader_cat.spam() << "mesh face_count : " << mesh->_face_count << endl;
1702  mayaloader_cat.spam() << "mesh vertexArray size: " << mesh->_vertexArray.length() << endl;
1703  mayaloader_cat.spam() << "mesh polygonCounts size: " << mesh->_polygonCounts.length() << endl;
1704  mayaloader_cat.spam() << "mesh polygonConnects size: " << mesh->_polygonConnects.length() << endl;
1705  mayaloader_cat.spam() << "mesh uarray size: " << mesh->_uarray.length() << endl;
1706  mayaloader_cat.spam() << "mesh varray size: " << mesh->_varray.length() << endl;
1707  }
1708  mesh->_transNode = mfn.create(mesh->_vert_count, mesh->_face_count,
1709  mesh->_vertexArray, mesh->_polygonCounts, mesh->_polygonConnects,
1710  mesh->_uarray, mesh->_varray,
1711  parent, &status);
1712  if (mayaloader_cat.is_spam()) {
1713  mayaloader_cat.spam() << "transNode created." << endl;
1714  }
1715 
1716  if (!mesh->_renameTrans) {
1717  mesh->_transNode = parent;
1718  }
1719 
1720  // [gjeon] add eggFlag attributes if any exists
1721  for (unsigned i = 0; i < mesh->_eggObjectTypes.length(); i++) {
1722  MString attrName = "eggObjectTypes";
1723  attrName += (int)(i + 1);
1724  status = create_enum_attribute(mesh->_transNode, attrName, attrName, mesh->_eggObjectTypes, i);
1725  if (status != MStatus::kSuccess) {
1726  status.perror("create_enum_attribute failed!");
1727  }
1728  }
1729 
1730  // Check the "Display Colors" box by default, so that vertex
1731  // colors (if any) will be visible.
1732  MPlug displayColors = mfn.findPlug("displayColors");
1733  displayColors.setValue((bool)true);
1734 
1735  mesh->_shapeNode = mfn.object();
1736  mfn.getPath(mesh->_shape_dag_path);
1737  mesh->ConnectTextures();
1738 
1739  if (mayaloader_cat.is_spam()) {
1740  mayaloader_cat.spam() << "textures connected." << endl;
1741  }
1742 
1743  mfn.getCurrentUVSetName(cset);
1744  status = mfn.assignUVs(mesh->_polygonCounts, mesh->_uvIds, &cset);
1745 
1746  if (status != MStatus::kSuccess) {
1747  status.perror("assignUVs failed");
1748  if (mayaloader_cat.is_spam()) {
1749  PrintData(mesh);
1750  }
1751  }
1752  else {
1753  if (mayaloader_cat.is_spam()) {
1754  mayaloader_cat.spam() << "uvs assigned." << endl;
1755  }
1756  }
1757 
1758  // lets try to set normals per vertex
1759  if (respect_normals) {
1760  status = mfn.setVertexNormals(mesh->_normalArray, mesh->_vertNormalIndices, MSpace::kTransform);
1761  if (status != MStatus::kSuccess) {
1762  status.perror("setVertexNormals failed!");
1763  }
1764  }
1765 
1766  if (mayaloader_cat.is_spam()) {
1767  mayaloader_cat.spam() << "vertex normals set." << endl;
1768  }
1769 
1770  // lets try to set colors per vertex
1771  /*
1772  MDGModifier dgmod;
1773  status = dgmod.doIt();
1774  if (status != MStatus::kSuccess) {
1775  status.perror("setVertexColors doIt");
1776  }
1777  status = mfn.setVertexColors(mesh->_vertColorArray, mesh->_vertColorIndices, &dgmod);
1778  */
1779  status = mfn.setVertexColors(mesh->_vertColorArray, mesh->_vertColorIndices);
1780  if (status != MStatus::kSuccess) {
1781  status.perror("setVertexColors failed!");
1782  }
1783  status = mfn.setFaceColors(mesh->_faceColorArray, mesh->_faceIndices);
1784  /*
1785  if (status != MStatus::kSuccess) {
1786  status.perror("setFaceColors failed!");
1787  }
1788  */
1789  }
1790 
1791  for (si = _surface_tab.begin(); si != _surface_tab.end(); ++si) {
1792  MayaEggNurbsSurface *surface = (*si).second;
1793  if (surface->_cvArray.length()==0) {
1794  continue;
1795  }
1796 
1797  // MStatus status;
1798  MFnNurbsSurface mfnNurbsSurface;
1799 
1800  MayaEggGroup *parentNode = FindGroup(surface->_parent);
1801  MObject parent = MObject::kNullObj;
1802  if (parentNode) {
1803  parent = parentNode->_group;
1804  if (mayaloader_cat.is_debug()) {
1805  mayaloader_cat.debug() << "surface's parent (group) : " << parentNode->_name << endl;
1806  }
1807  } else {
1808  surface->_renameTrans = true;
1809  if (mayaloader_cat.is_debug()) {
1810  mayaloader_cat.debug() << "surface's parent (null) : " << endl;
1811  }
1812  }
1813 
1814  surface->_transNode = mfnNurbsSurface.create(surface->_cvArray, surface->_uKnotArray, surface->_vKnotArray,
1815  surface->_uDegree, surface->_vDegree, surface->_uForm, surface->_vForm,
1816  true, parent, &status);
1817 
1818  if (!surface->_renameTrans) {
1819  surface->_transNode = parent;
1820  }
1821 
1822  // [gjeon] add eggFlag attributes if any exists
1823  for (unsigned i = 0; i < surface->_eggObjectTypes.length(); i++) {
1824  MString attrName = "eggObjectTypes";
1825  attrName += (int)(i + 1);
1826  status = create_enum_attribute(surface->_transNode, attrName, attrName, surface->_eggObjectTypes, i);
1827  if (status != MStatus::kSuccess) {
1828  status.perror("create_enum_attribute failed!");
1829  }
1830  }
1831  surface->_shapeNode = mfnNurbsSurface.object();
1832  mfnNurbsSurface.getPath(surface->_shape_dag_path);
1833  surface->ConnectTextures();
1834 
1835  mayaloader_cat.debug() << status.errorString().asChar() << endl;
1836  }
1837 
1838 
1839  double thickness = 0.0;
1840  for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
1841  MayaEggJoint *joint = (*ji).second;
1842  double dfo = ((*ji).second->GetPos()).length();
1843  if (dfo > thickness) {
1844  thickness = dfo;
1845  }
1846  }
1847  if (mayaloader_cat.is_spam()) {
1848  mayaloader_cat.spam() << "thickness from joints: " << thickness << endl;
1849  }
1850  thickness = thickness * 0.025;
1851  for (unsigned int i=0; i<_joint_list.size(); i++) {
1852  MayaEggJoint *joint = _joint_list[i];
1853  if (mayaloader_cat.is_spam()) {
1854  mayaloader_cat.spam() << "creating a joint: " << joint->_egg_joint->get_name() << endl;
1855  }
1856  joint->ChooseEndPos(thickness);
1857  joint->CreateMayaBone(FindGroup(joint->_egg_parent));
1858  }
1859  if (mayaloader_cat.is_spam()) {
1860  mayaloader_cat.spam() << "went past all the joints" << endl;
1861  }
1862  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
1863  MayaEggMesh *mesh = (*ci).second;
1864  EggGroup *joint = mesh->GetControlJoint();
1865  if (joint) {
1866  CreateSkinCluster(mesh);
1867  }
1868  }
1869  for (si = _surface_tab.begin(); si != _surface_tab.end(); ++si) {
1870  MayaEggNurbsSurface *surface = (*si).second;
1871  EggGroup *joint = surface->GetControlJoint();
1872  if (joint) {
1873  CreateSkinCluster(surface);
1874  }
1875  }
1876  if (mayaloader_cat.is_spam()) {
1877  mayaloader_cat.spam() << "went past creating skin cluster" << endl;
1878  }
1879  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
1880  (*ci).second->AssignNames();
1881  }
1882  for (si = _surface_tab.begin(); si != _surface_tab.end(); ++si) {
1883  (*si).second->AssignNames();
1884  }
1885  if (mayaloader_cat.is_spam()) {
1886  mayaloader_cat.spam() << "went past mesh AssignNames" << endl;
1887  }
1888  for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
1889  (*ji).second->AssignNames();
1890  }
1891  if (mayaloader_cat.is_spam()) {
1892  mayaloader_cat.spam() << "went past joint AssignNames" << endl;
1893  }
1894  for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) {
1895  (*ti).second->AssignNames();
1896  }
1897  if (mayaloader_cat.is_spam()) {
1898  mayaloader_cat.spam() << "went past tex AssignNames" << endl;
1899  }
1900 
1901  if (mayaloader_cat.is_debug()) {
1902  mayaloader_cat.debug() << "-fri: " << _frame_rate << " -sf: " << _start_frame
1903  << " -ef: " << _end_frame << endl;
1904  }
1905 
1906  // masad: keep track of maximum frames of animation on all these joints
1907  MTime maxFrame(_start_frame - 1, _timeUnit);
1908  MTime minFrame = maxFrame;
1909 
1910  for (ei = _anim_tab.begin(); ei != _anim_tab.end(); ++ei) {
1911  MayaAnim *anim = (*ei).second;
1912  MObject node = GetDependencyNode(anim->_joint->get_name());
1913  MFnDagNode mfnNode(node, &status);
1914 
1915  MMatrix mMat = mfnNode.transformationMatrix(&status);
1916 
1917  MObject attrTX = mfnNode.attribute("translateX", &status);
1918  MObject attrTY = mfnNode.attribute("translateY", &status);
1919  MObject attrTZ = mfnNode.attribute("translateZ", &status);
1920  MObject attrRX = mfnNode.attribute("rotateX", &status);
1921  MObject attrRY = mfnNode.attribute("rotateY", &status);
1922  MObject attrRZ = mfnNode.attribute("rotateZ", &status);
1923  MObject attrSX = mfnNode.attribute("scaleX", &status);
1924  MObject attrSY = mfnNode.attribute("scaleY", &status);
1925  MObject attrSZ = mfnNode.attribute("scaleZ", &status);
1926 
1927  MFnAnimCurve mfnAnimCurveTX;
1928  MFnAnimCurve mfnAnimCurveTY;
1929  MFnAnimCurve mfnAnimCurveTZ;
1930  MFnAnimCurve mfnAnimCurveRX;
1931  MFnAnimCurve mfnAnimCurveRY;
1932  MFnAnimCurve mfnAnimCurveRZ;
1933  MFnAnimCurve mfnAnimCurveSX;
1934  MFnAnimCurve mfnAnimCurveSY;
1935  MFnAnimCurve mfnAnimCurveSZ;
1936 
1937  mfnAnimCurveTX.create(node, attrTX, MFnAnimCurve::kAnimCurveTL, NULL, &status);
1938  mfnAnimCurveTY.create(node, attrTY, MFnAnimCurve::kAnimCurveTL, NULL, &status);
1939  mfnAnimCurveTZ.create(node, attrTZ, MFnAnimCurve::kAnimCurveTL, NULL, &status);
1940  mfnAnimCurveRX.create(node, attrRX, MFnAnimCurve::kAnimCurveTA, NULL, &status);
1941  mfnAnimCurveRY.create(node, attrRY, MFnAnimCurve::kAnimCurveTA, NULL, &status);
1942  mfnAnimCurveRZ.create(node, attrRZ, MFnAnimCurve::kAnimCurveTA, NULL, &status);
1943  mfnAnimCurveSX.create(node, attrSX, MFnAnimCurve::kAnimCurveTU, NULL, &status);
1944  mfnAnimCurveSY.create(node, attrSY, MFnAnimCurve::kAnimCurveTU, NULL, &status);
1945  mfnAnimCurveSZ.create(node, attrSZ, MFnAnimCurve::kAnimCurveTU, NULL, &status);
1946 
1947  MTransformationMatrix matrix( mMat );
1948  MVector trans = matrix.translation(MSpace::kTransform, &status);
1949 
1950  double rot[3];
1951  MTransformationMatrix::RotationOrder order = MTransformationMatrix::kXYZ;
1952  status = matrix.getRotation(rot, order);
1953 
1954  double scale[3];
1955  status = matrix.getScale(scale, MSpace::kTransform);
1956  MFnAnimCurve::TangentType tangent = MFnAnimCurve::kTangentClamped;
1957  MTime time(_start_frame - 1, _timeUnit);
1958 
1959  mfnAnimCurveTX.addKey(time, trans.x, tangent, tangent, NULL, &status);
1960  mfnAnimCurveTY.addKey(time, trans.y, tangent, tangent, NULL, &status);
1961  mfnAnimCurveTZ.addKey(time, trans.z, tangent, tangent, NULL, &status);
1962  mfnAnimCurveRX.addKey(time, rot[0], tangent, tangent, NULL, &status);
1963  mfnAnimCurveRY.addKey(time, rot[1], tangent, tangent, NULL, &status);
1964  mfnAnimCurveRZ.addKey(time, rot[2], tangent, tangent, NULL, &status);
1965  mfnAnimCurveSX.addKey(time, scale[0], tangent, tangent, NULL, &status);
1966  mfnAnimCurveSY.addKey(time, scale[1], tangent, tangent, NULL, &status);
1967  mfnAnimCurveSZ.addKey(time, scale[2], tangent, tangent, NULL, &status);
1968 
1969  for (int frame = 0; frame < anim->_pool->get_num_rows(); frame++)
1970  {
1971  LMatrix4d tMat;
1972  anim->_pool->get_value(frame, tMat);
1973 
1974  double matData[4][4] = {{tMat.get_cell(0,0), tMat.get_cell(0,1), tMat.get_cell(0,2), tMat.get_cell(0,3)},
1975  {tMat.get_cell(1,0), tMat.get_cell(1,1), tMat.get_cell(1,2), tMat.get_cell(1,3)},
1976  {tMat.get_cell(2,0), tMat.get_cell(2,1), tMat.get_cell(2,2), tMat.get_cell(2,3)},
1977  {tMat.get_cell(3,0), tMat.get_cell(3,1), tMat.get_cell(3,2), tMat.get_cell(3,3)}};
1978  MMatrix mat(matData);
1979 
1980  matrix = MTransformationMatrix(mat);
1981  trans = matrix.translation(MSpace::kTransform, &status);
1982  status = matrix.getRotation(rot, order);
1983  status = matrix.getScale(scale, MSpace::kTransform);
1984  time = MTime(frame + _start_frame, _timeUnit);
1985 
1986  mfnAnimCurveTX.addKey(time, trans.x, tangent, tangent, NULL, &status);
1987  mfnAnimCurveTY.addKey(time, trans.y, tangent, tangent, NULL, &status);
1988  mfnAnimCurveTZ.addKey(time, trans.z, tangent, tangent, NULL, &status);
1989  mfnAnimCurveRX.addKey(time, rot[0], tangent, tangent, NULL, &status);
1990  mfnAnimCurveRY.addKey(time, rot[1], tangent, tangent, NULL, &status);
1991  mfnAnimCurveRZ.addKey(time, rot[2], tangent, tangent, NULL, &status);
1992  mfnAnimCurveSX.addKey(time, scale[0], tangent, tangent, NULL, &status);
1993  mfnAnimCurveSY.addKey(time, scale[1], tangent, tangent, NULL, &status);
1994  mfnAnimCurveSZ.addKey(time, scale[2], tangent, tangent, NULL, &status);
1995  }
1996  if (maxFrame < time) {
1997  maxFrame = time;
1998  }
1999  }
2000  if (anim) {
2001  // masad: set the control's max time with maxFrame
2002  MAnimControl::setMaxTime(maxFrame);
2003  MAnimControl::setMinTime(minFrame);
2004  }
2005 
2006  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
2007  delete (*ci).second;
2008  }
2009  for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
2010  delete (*ji).second;
2011  }
2012  for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) {
2013  delete (*ti).second;
2014  }
2015  for (ei = _anim_tab.begin(); ei != _anim_tab.end(); ++ei) {
2016  delete (*ei).second;
2017  }
2018 
2019  // ResumeSetKeyMode();
2020  // ResumeAnimate();
2021 
2022  mayaloader_cat.info() << "Egg import successful\n";
2023  return true;
2024 }
2025 
2026 void MayaEggLoader::PrintData(MayaEggMesh *mesh)
2027 {
2028  if (mayaloader_cat.is_spam()) {
2029  mayaloader_cat.spam() << "Mesh: " << mesh->_name << endl;
2030  mayaloader_cat.spam() << "num vertexArray: " << mesh->_vertexArray.length() << endl;
2031  ostringstream stream3;
2032  for (unsigned int i=0; i < mesh->_vertexArray.length(); ++i) {
2033  stream3 << "[" << mesh->_vertexArray[i].x << " " << mesh->_vertexArray[i].y << " " << mesh->_vertexArray[i].z << "]" << endl;
2034  }
2035 
2036  mayaloader_cat.spam() << "vertexArray: \n" << stream3.str() << endl;
2037  mayaloader_cat.spam() << "num polygonConnects: " << mesh->_polygonConnects.length() << endl;
2038  mayaloader_cat.spam() << "num uvCounts: " << mesh->_polygonCounts.length() << endl;
2039  mayaloader_cat.spam() << "num uvIds: " << mesh->_uvIds.length() << endl;
2040  ostringstream stream1, stream4;
2041  unsigned int k=0;
2042  for (unsigned int i=0; i < mesh->_polygonCounts.length(); ++i) {
2043  stream1 << mesh->_polygonCounts[i] << ":->";
2044  stream4 << mesh->_polygonCounts[i] << ":->";
2045  for (int j=0; j < mesh->_polygonCounts[i]; ++j, ++k) {
2046  stream1 << mesh->_uvIds[k] << ",";
2047  stream4 << mesh->_polygonConnects[k] << ",";
2048  }
2049  stream1 << endl;
2050  stream4 << endl;
2051  }
2052  mayaloader_cat.spam() << "uvCounts:->uvIds " << endl << stream1.str() << endl;
2053  mayaloader_cat.spam() << "vertexCount:->polygonConnects" << endl << stream4.str() << endl;
2054  }
2055 }
2056 
2057 void MayaEggLoader::ParseFrameInfo(string comment)
2058 {
2059  int length = 0;
2060  int pos, ls, le;
2061 
2062  pos = comment.find("-fri");
2063  if (pos != string::npos) {
2064  ls = comment.find(" ", pos+4);
2065  le = comment.find(" ", ls+1);
2066  if (mayaloader_cat.is_debug()) {
2067  mayaloader_cat.debug() << comment.substr(ls+1, le-ls-1) << endl;
2068  }
2069  _frame_rate = atoi(comment.substr(ls+1,le-ls-1).data());
2070  //mayaloader_cat.debug() << "le = " << le << "; and ls = " << ls << "; frame_rate = " << _frame_rate << endl;
2071 
2072  switch (_frame_rate) {
2073  case 15:
2074  _timeUnit = MTime::kGames;
2075  break;
2076  case 24:
2077  _timeUnit = MTime::kFilm;
2078  break;
2079  case 25:
2080  _timeUnit = MTime::kPALFrame;
2081  break;
2082  case 30:
2083  _timeUnit = MTime::kNTSCFrame;
2084  break;
2085  case 48:
2086  _timeUnit = MTime::kShowScan;
2087  break;
2088  case 50:
2089  _timeUnit = MTime::kPALField;
2090  break;
2091  case 60:
2092  _timeUnit = MTime::kNTSCField;
2093  break;
2094  case 2:
2095  _timeUnit = MTime::k2FPS;
2096  break;
2097  case 3:
2098  _timeUnit = MTime::k3FPS;
2099  break;
2100  case 4:
2101  _timeUnit = MTime::k4FPS;
2102  break;
2103  case 5:
2104  _timeUnit = MTime::k5FPS;
2105  break;
2106  case 6:
2107  _timeUnit = MTime::k6FPS;
2108  break;
2109  case 8:
2110  _timeUnit = MTime::k8FPS;
2111  break;
2112  case 10:
2113  _timeUnit = MTime::k10FPS;
2114  break;
2115  case 12:
2116  _timeUnit = MTime::k12FPS;
2117  break;
2118  case 16:
2119  _timeUnit = MTime::k16FPS;
2120  break;
2121  case 20:
2122  _timeUnit = MTime::k20FPS;
2123  break;
2124  case 40:
2125  _timeUnit = MTime::k40FPS;
2126  break;
2127  case 75:
2128  _timeUnit = MTime::k75FPS;
2129  break;
2130  case 80:
2131  _timeUnit = MTime::k80FPS;
2132  break;
2133  case 100:
2134  _timeUnit = MTime::k100FPS;
2135  break;
2136  default:
2137  _timeUnit = MTime::kFilm;
2138  }
2139 
2140  }
2141 
2142  pos = comment.find("-sf");
2143  if (pos != string::npos) {
2144  ls = comment.find(" ", pos+3);
2145  le = comment.find(" ", ls+1);
2146  if (mayaloader_cat.is_debug()) {
2147  mayaloader_cat.debug() << comment.substr(ls+1, le-ls-1) << endl;
2148  }
2149  if (le == string::npos) {
2150  _start_frame = atoi(comment.substr(ls+1,le).data());
2151  } else {
2152  _start_frame = atoi(comment.substr(ls+1,le-ls-1).data());
2153  }
2154  //mayaloader_cat.debug() << "le = " << le << "; and ls = " << ls << "; start_frame = " << _start_frame << endl;
2155  }
2156  pos = comment.find("-ef");
2157  if (pos != string::npos) {
2158  ls = comment.find(" ", pos+3);
2159  le = comment.find(" ", ls+1);
2160  if (mayaloader_cat.is_debug()) {
2161  mayaloader_cat.debug() << comment.substr(ls+1, le-ls-1) << endl;
2162  }
2163  if (le == string::npos) {
2164  _end_frame = atoi(comment.substr(ls+1,le).data());
2165  } else {
2166  _end_frame = atoi(comment.substr(ls+1,le-ls-1).data());
2167  }
2168  //mayaloader_cat.debug() << "le = " << le << "; and ls = " << ls << "; end_frame = " << _end_frame << endl;
2169  }
2170 
2171 
2172 }
2173 
2174 bool MayaEggLoader::ConvertEggFile(const char *name, bool merge, bool model, bool anim, bool respect_normals)
2175 {
2176  EggData data;
2177  Filename datafn = Filename::from_os_specific(name);
2178  if (!data.read(datafn)) {
2179  mayaloader_cat.error() << "Cannot read Egg file for import\n";
2180  return false;
2181  }
2182  return ConvertEggData(&data, merge, model, anim, respect_normals);
2183 }
2184 
2185 MObject MayaEggLoader::GetDependencyNode(string givenName)
2186 {
2187  MObject node = MObject::kNullObj;
2188  int pos;
2189  string name;
2190 
2191  pos = givenName.find(":");
2192  if (pos != string::npos) {
2193  name = givenName.substr(pos+1);
2194  } else
2195  name = givenName;
2196 
2197  /*
2198  //masad: I do not think you want to return a mesh node
2199  //because keyframes should only apply to joint nodes.
2200  MeshTable::const_iterator ci;
2201  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
2202  MayaEggMesh *mesh = (*ci).second;
2203 
2204  string meshName = mesh->_pool->get_name();
2205  int nsize = meshName.size();
2206  if ((nsize > 6) && (meshName.rfind(".verts")==(nsize-6))) {
2207  meshName.resize(nsize-6);
2208  }
2209  if (meshName == name)
2210  {
2211  node = mesh->_transNode;
2212  cerr << "foo get dependency node returning a mesh's transNode? why? : " << givenName << endl;
2213  return node;
2214  }
2215  }
2216  */
2217 
2218  JointTable::const_iterator ji;
2219  for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
2220  MayaEggJoint *joint = (*ji).second;
2221  if (mayaloader_cat.is_spam()) {
2222  mayaloader_cat.spam() << "traversing a joint: " << joint->_egg_joint->get_name() << endl;
2223  }
2224  string jointName = joint->_egg_joint->get_name();
2225  if (jointName == name)
2226  {
2227  node = joint->_joint;
2228  return node;
2229  }
2230  }
2231 
2232  return node;
2233 }
2234 
2235 ////////////////////////////////////////////////////////////////////////////////////////////////////
2236 //
2237 // The two global functions that form the API of this module.
2238 //
2239 ////////////////////////////////////////////////////////////////////////////////////////////////////
2240 
2241 bool MayaLoadEggData(EggData *data, bool merge, bool model, bool anim, bool respect_normals)
2242 {
2243  MayaEggLoader loader;
2244  bool temp = loader.ConvertEggData(data, merge, model, anim, respect_normals);
2245  return temp;
2246 }
2247 
2248 bool MayaLoadEggFile(const char *name, bool merge, bool model, bool anim, bool respect_normals)
2249 {
2250  MayaEggLoader loader;
2251  return loader.ConvertEggFile(name, merge, model, anim, respect_normals);
2252 }
2253 
int get_u_degree() const
Returns the degree of the surface in the U direction.
LTexCoordd get_uv() const
Returns the unnamed UV coordinate pair on the vertex.
Definition: eggVertex.I:222
const LMatrix4d & get_transform3d() const
Returns the overall transform as a 4x4 matrix.
Definition: eggTransform.I:251
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:4716
static int size()
Returns 2: the number of components of a LVecBase2.
Definition: lvecBase2.h:1555
LColor get_color() const
Returns the color set on this particular attribute.
size_t get_hash() const
Returns a suitable hash for phash_map.
Definition: lvecBase3.h:2297
int get_num_u_knots() const
Returns the number of knots in the U direction.
bool get_bface_flag() const
Retrieves the backfacing flag of the polygon.
Definition: eggPrimitive.I:301
Specifies parameters that may be passed to the loader.
Definition: loaderOptions.h:26
double get_u_knot(int k) const
Returns the nth knot value defined in the U direction.
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
bool has_uv() const
Returns true if the vertex has an unnamed UV coordinate pair, false otherwise.
Definition: eggVertex.I:194
A comment that appears in an egg file within a &lt;Comment&gt; entry.
Definition: eggComment.h:27
virtual bool is_joint() const
Returns true if this particular node represents a &lt;Joint&gt; entry or not.
Definition: eggGroup.cxx:508
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:33
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:75
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
LVertexd get_pos3() const
Valid if get_num_dimensions() returns 3 or 4.
Definition: eggVertex.I:160
LMatrix3d get_transform2d() const
Returns the overall transform as a 3x3 matrix.
Definition: eggTransform.I:234
GroupRef::const_iterator gref_end() const
Returns an iterator that can, in conjunction with gref_begin(), be used to traverse the entire set of...
Definition: eggVertex.cxx:805
This is a two-component point in space.
Definition: lpoint2.h:411
const LMatrix4d & get_vertex_to_node() const
Returns the transformation matrix suitable for converting the vertices as read from the egg file into...
Definition: eggNode.I:203
EggTexture * get_texture() const
Returns the first texture on the primitive, if any, or NULL if there are no textures on the primitive...
Definition: eggPrimitive.I:182
GroupRef::const_iterator gref_begin() const
Returns an iterator that can, in conjunction with gref_end(), be used to traverse the entire set of g...
Definition: eggVertex.cxx:789
This is the primary interface into all the egg data, and the root of the egg file structure...
Definition: eggData.h:41
void set_coordinate_system(CoordinateSystem coordsys)
Changes the coordinate system of the EggData.
Definition: eggData.cxx:279
virtual bool cleanup()
Cleans up modeling errors in whatever context this makes sense.
Definition: eggPolygon.cxx:36
bool is_closed_u() const
Returns true if the surface appears to be closed in the U direction.
bool normalize()
Normalizes the vector in place.
Definition: lvecBase3.h:2132
The main glue of the egg hierarchy, this corresponds to the &lt;Group&gt;, &lt;Instance&gt;, and &lt;Joint&gt; type nod...
Definition: eggGroup.h:36
This is a 3-by-3 transform matrix.
Definition: lmatrix.h:4375
int get_num_rows() const
Returns the effective number of rows in the table.
bool has_transform3d() const
Returns true if the transform is specified as a 3-d transform, e.g.
Definition: eggTransform.I:210
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
double get_cell(int row, int col) const
Returns a particular element of the matrix.
Definition: lmatrix.h:5709
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
Definition: eggVertex.h:41
This corresponds to an &lt;Xfm$Anim_S$&gt; entry, which is a collection of up to nine &lt;S$Anim&gt; entries that...
Definition: eggXfmSAnim.h:33
const Filename & get_fullpath() const
Returns the full pathname to the file, if it is known; otherwise, returns the same thing as get_filen...
bool read(Filename filename, string display_name=string())
Opens the indicated filename and reads the egg data contents from it.
Definition: eggData.cxx:71
int get_v_degree() const
Returns the degree of the surface in the V direction.
double length() const
Returns the length of the vector, by the Pythagorean theorem.
Definition: lvecBase3.h:2115
double get_vertex_membership(const EggVertex *vert) const
Returns the amount of membership of the indicated vertex in this group.
Definition: eggGroup.cxx:756
bool has_transform() const
Returns true if the transform is nonempty, false if it is empty (no transform components have been ad...
Definition: eggTransform.I:163
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
Definition: filename.cxx:1196
A single polygon.
Definition: eggPolygon.h:26
This corresponds to a.
Definition: eggTable.h:31
This is the base class for all three-component vectors and points.
Definition: lvecBase4.h:111
int get_vertex_index(int ui, int vi) const
Returns the index number within the EggPrimitive&#39;s list of the control vertex at position ui...
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
Definition: lvector3.h:746
int compare_to(const LVecBase2d &other) const
This flavor of compare_to uses a default threshold value based on the numeric type.
Definition: lvecBase2.h:1890
This is a three-component point in space (as opposed to a three-component vector, which represents a ...
Definition: lpoint3.h:531
size_t add_hash(size_t hash) const
Adds the vector into the running hash.
Definition: lvecBase3.h:2308
int compare_to(const LVecBase3d &other) const
This flavor of compare_to uses a default threshold value based on the numeric type.
Definition: lvecBase3.h:2273
bool is_closed_v() const
Returns true if the surface appears to be closed in the V direction.
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:38
A parametric NURBS surface.
static const LMatrix3d & ident_mat()
Returns an identity matrix.
Definition: lmatrix.h:7128
int get_num_u_cvs() const
Returns the number of control vertices that should be present in the U direction. ...
This is the preferred interface for loading textures from image files.
Definition: texturePool.h:40
EggVertex * get_vertex(int index) const
Returns a particular index based on its index number.
Definition: eggPrimitive.I:466
int get_num_v_knots() const
Returns the number of knots in the V direction.
double get_v_knot(int k) const
Returns the nth knot value defined in the V direction.
int get_num_v_cvs() const
Returns the number of control vertices that should be present in the V direction. ...
A collection of vertices.
Definition: eggVertexPool.h:46
bool has_texture() const
Returns true if the primitive has any textures specified, false otherwise.
Definition: eggPrimitive.I:155
void get_value(int row, LMatrix4d &mat) const
Returns the value of the aggregate row of the table as a matrix.
int get_index() const
Returns the index number of the vertex within its pool.
Definition: eggVertex.I:346
EggVertexPool * get_pool() const
Returns the vertex pool associated with the vertices of the primitive, or NULL if the primitive has n...
Definition: eggPrimitive.I:480
static Filename from_os_specific(const string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).
Definition: filename.cxx:332