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