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  // Create a MayaAnim equivalent of the EggXfmSAnim
1576  GetAnim(DCAST(EggXfmSAnim, node));
1577  //anim->PrintData();
1578  if (mayaloader_cat.is_debug()) {
1579  mayaloader_cat.debug() << delim+delstring << "found an EggXfmSAnim: " << node->get_name() << endl;
1580  }
1581  }
1582 
1583  EggGroupNode::const_iterator ci;
1584  for (ci = group->begin(); ci != group->end(); ++ci) {
1585  TraverseEggNode(*ci, context, delim+delstring);
1586  }
1587  }
1588 }
1589 
1590 bool MayaEggLoader::ConvertEggData(EggData *data, bool merge, bool model, bool anim, bool respect_normals)
1591 {
1592  if (!merge) {
1593  mayaloader_cat.error() << "Currently, only 'merge' mode is implemented.\n";
1594  return false;
1595  }
1596 
1597  /*
1598  if ((anim) || (!model)) {
1599  mayaloader_cat.error() << "Currently, only model-loading is implemented.\n";
1600  return false;
1601  }
1602  */
1603 
1604  _start_frame = 0;
1605  _end_frame = 0;
1606  _frame_rate = 24;
1607  _timeUnit = MTime::kFilm;
1608  _unnamed_idx = 1;
1609 
1610  MeshTable::const_iterator ci;
1611  JointTable::const_iterator ji;
1612  TexTable::const_iterator ti;
1613  SurfaceTable::const_iterator si;
1614  AnimTable::const_iterator ei;
1615 
1616  if (MGlobal::isYAxisUp()) {
1617  data->set_coordinate_system(CS_yup_right);
1618  } else {
1619  data->set_coordinate_system(CS_zup_right);
1620  }
1621 
1622  if (mayaloader_cat.is_debug()) {
1623  mayaloader_cat.debug() << "root node: " << data->get_type() << endl;
1624  }
1625  TraverseEggNode(data, nullptr, "");
1626 
1627  MStatus status;
1628 
1629  MFnSet collision_set;
1630  collision_set.create(_collision_nodes, MFnSet::kNone, &status);
1631 
1632  if (mayaloader_cat.is_spam()) {
1633  mayaloader_cat.spam() << "num meshes : " << _mesh_tab.size() << endl;
1634  }
1635  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
1636  MayaEggMesh *mesh = (*ci).second;
1637  if (mesh->_face_count==0) {
1638  continue;
1639  }
1640 
1641  // MStatus status;
1642  MFnMesh mfn;
1643  MString cset;
1644 
1645  MayaEggGroup *parentNode = FindGroup(mesh->_parent);
1646  MObject parent = MObject::kNullObj;
1647  if (parentNode) {
1648  parent = parentNode->_group;
1649  if (mayaloader_cat.is_debug()) {
1650  mayaloader_cat.debug() << "mesh's parent (group) : " << parentNode->_name << endl;
1651  }
1652  } else {
1653  mesh->_renameTrans = true;
1654  if (mayaloader_cat.is_debug()) {
1655  mayaloader_cat.debug() << "mesh's parent (null) : " << endl;
1656  }
1657  }
1658  if (mayaloader_cat.is_spam()) {
1659  mayaloader_cat.spam() << "mesh pointer : " << mesh << " and parent_pointer: " << &parent << endl;
1660  mayaloader_cat.spam() << "mesh vert_count : " << mesh->_vert_count << endl;
1661  mayaloader_cat.spam() << "mesh face_count : " << mesh->_face_count << endl;
1662  mayaloader_cat.spam() << "mesh vertexArray size: " << mesh->_vertexArray.length() << endl;
1663  mayaloader_cat.spam() << "mesh polygonCounts size: " << mesh->_polygonCounts.length() << endl;
1664  mayaloader_cat.spam() << "mesh polygonConnects size: " << mesh->_polygonConnects.length() << endl;
1665  mayaloader_cat.spam() << "mesh uarray size: " << mesh->_uarray.length() << endl;
1666  mayaloader_cat.spam() << "mesh varray size: " << mesh->_varray.length() << endl;
1667  }
1668  mesh->_transNode = mfn.create(mesh->_vert_count, mesh->_face_count,
1669  mesh->_vertexArray, mesh->_polygonCounts, mesh->_polygonConnects,
1670  mesh->_uarray, mesh->_varray,
1671  parent, &status);
1672  if (mayaloader_cat.is_spam()) {
1673  mayaloader_cat.spam() << "transNode created." << endl;
1674  }
1675 
1676  if (!mesh->_renameTrans) {
1677  mesh->_transNode = parent;
1678  }
1679 
1680  // [gjeon] add eggFlag attributes if any exists
1681  for (unsigned i = 0; i < mesh->_eggObjectTypes.length(); i++) {
1682  MString attrName = "eggObjectTypes";
1683  attrName += (int)(i + 1);
1684  status = create_enum_attribute(mesh->_transNode, attrName, attrName, mesh->_eggObjectTypes, i);
1685  if (status != MStatus::kSuccess) {
1686  status.perror("create_enum_attribute failed!");
1687  }
1688  }
1689 
1690  // Check the "Display Colors" box by default, so that vertex colors (if
1691  // any) will be visible.
1692  MPlug displayColors = mfn.findPlug("displayColors");
1693  displayColors.setValue((bool)true);
1694 
1695  mesh->_shapeNode = mfn.object();
1696  mfn.getPath(mesh->_shape_dag_path);
1697  mesh->ConnectTextures();
1698 
1699  if (mayaloader_cat.is_spam()) {
1700  mayaloader_cat.spam() << "textures connected." << endl;
1701  }
1702 
1703  mfn.getCurrentUVSetName(cset);
1704  status = mfn.assignUVs(mesh->_polygonCounts, mesh->_uvIds, &cset);
1705 
1706  if (status != MStatus::kSuccess) {
1707  status.perror("assignUVs failed");
1708  if (mayaloader_cat.is_spam()) {
1709  PrintData(mesh);
1710  }
1711  }
1712  else {
1713  if (mayaloader_cat.is_spam()) {
1714  mayaloader_cat.spam() << "uvs assigned." << endl;
1715  }
1716  }
1717 
1718  // lets try to set normals per vertex
1719  if (respect_normals) {
1720  status = mfn.setVertexNormals(mesh->_normalArray, mesh->_vertNormalIndices, MSpace::kTransform);
1721  if (status != MStatus::kSuccess) {
1722  status.perror("setVertexNormals failed!");
1723  }
1724  }
1725 
1726  if (mayaloader_cat.is_spam()) {
1727  mayaloader_cat.spam() << "vertex normals set." << endl;
1728  }
1729 
1730  // lets try to set colors per vertex
1731  /*
1732  MDGModifier dgmod;
1733  status = dgmod.doIt();
1734  if (status != MStatus::kSuccess) {
1735  status.perror("setVertexColors doIt");
1736  }
1737  status = mfn.setVertexColors(mesh->_vertColorArray, mesh->_vertColorIndices, &dgmod);
1738  */
1739  status = mfn.setVertexColors(mesh->_vertColorArray, mesh->_vertColorIndices);
1740  if (status != MStatus::kSuccess) {
1741  status.perror("setVertexColors failed!");
1742  }
1743  status = mfn.setFaceColors(mesh->_faceColorArray, mesh->_faceIndices);
1744  /*
1745  if (status != MStatus::kSuccess) {
1746  status.perror("setFaceColors failed!");
1747  }
1748  */
1749  }
1750 
1751  for (si = _surface_tab.begin(); si != _surface_tab.end(); ++si) {
1752  MayaEggNurbsSurface *surface = (*si).second;
1753  if (surface->_cvArray.length()==0) {
1754  continue;
1755  }
1756 
1757  // MStatus status;
1758  MFnNurbsSurface mfnNurbsSurface;
1759 
1760  MayaEggGroup *parentNode = FindGroup(surface->_parent);
1761  MObject parent = MObject::kNullObj;
1762  if (parentNode) {
1763  parent = parentNode->_group;
1764  if (mayaloader_cat.is_debug()) {
1765  mayaloader_cat.debug() << "surface's parent (group) : " << parentNode->_name << endl;
1766  }
1767  } else {
1768  surface->_renameTrans = true;
1769  if (mayaloader_cat.is_debug()) {
1770  mayaloader_cat.debug() << "surface's parent (null) : " << endl;
1771  }
1772  }
1773 
1774  surface->_transNode = mfnNurbsSurface.create(surface->_cvArray, surface->_uKnotArray, surface->_vKnotArray,
1775  surface->_uDegree, surface->_vDegree, surface->_uForm, surface->_vForm,
1776  true, parent, &status);
1777 
1778  if (!surface->_renameTrans) {
1779  surface->_transNode = parent;
1780  }
1781 
1782  // [gjeon] add eggFlag attributes if any exists
1783  for (unsigned i = 0; i < surface->_eggObjectTypes.length(); i++) {
1784  MString attrName = "eggObjectTypes";
1785  attrName += (int)(i + 1);
1786  status = create_enum_attribute(surface->_transNode, attrName, attrName, surface->_eggObjectTypes, i);
1787  if (status != MStatus::kSuccess) {
1788  status.perror("create_enum_attribute failed!");
1789  }
1790  }
1791  surface->_shapeNode = mfnNurbsSurface.object();
1792  mfnNurbsSurface.getPath(surface->_shape_dag_path);
1793  surface->ConnectTextures();
1794 
1795  mayaloader_cat.debug() << status.errorString().asChar() << endl;
1796  }
1797 
1798 
1799  double thickness = 0.0;
1800  for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
1801  MayaEggJoint *joint = (*ji).second;
1802  double dfo = (joint->GetPos()).length();
1803  if (dfo > thickness) {
1804  thickness = dfo;
1805  }
1806  }
1807  if (mayaloader_cat.is_spam()) {
1808  mayaloader_cat.spam() << "thickness from joints: " << thickness << endl;
1809  }
1810  thickness = thickness * 0.025;
1811  for (unsigned int i=0; i<_joint_list.size(); i++) {
1812  MayaEggJoint *joint = _joint_list[i];
1813  if (mayaloader_cat.is_spam()) {
1814  mayaloader_cat.spam() << "creating a joint: " << joint->_egg_joint->get_name() << endl;
1815  }
1816  joint->ChooseEndPos(thickness);
1817  joint->CreateMayaBone(FindGroup(joint->_egg_parent));
1818  }
1819  if (mayaloader_cat.is_spam()) {
1820  mayaloader_cat.spam() << "went past all the joints" << endl;
1821  }
1822  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
1823  MayaEggMesh *mesh = (*ci).second;
1824  EggGroup *joint = mesh->GetControlJoint();
1825  if (joint) {
1826  CreateSkinCluster(mesh);
1827  }
1828  }
1829  for (si = _surface_tab.begin(); si != _surface_tab.end(); ++si) {
1830  MayaEggNurbsSurface *surface = (*si).second;
1831  EggGroup *joint = surface->GetControlJoint();
1832  if (joint) {
1833  CreateSkinCluster(surface);
1834  }
1835  }
1836  if (mayaloader_cat.is_spam()) {
1837  mayaloader_cat.spam() << "went past creating skin cluster" << endl;
1838  }
1839  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
1840  (*ci).second->AssignNames();
1841  }
1842  for (si = _surface_tab.begin(); si != _surface_tab.end(); ++si) {
1843  (*si).second->AssignNames();
1844  }
1845  if (mayaloader_cat.is_spam()) {
1846  mayaloader_cat.spam() << "went past mesh AssignNames" << endl;
1847  }
1848  for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
1849  (*ji).second->AssignNames();
1850  }
1851  if (mayaloader_cat.is_spam()) {
1852  mayaloader_cat.spam() << "went past joint AssignNames" << endl;
1853  }
1854  for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) {
1855  (*ti).second->AssignNames();
1856  }
1857  if (mayaloader_cat.is_spam()) {
1858  mayaloader_cat.spam() << "went past tex AssignNames" << endl;
1859  }
1860 
1861  if (mayaloader_cat.is_debug()) {
1862  mayaloader_cat.debug() << "-fri: " << _frame_rate << " -sf: " << _start_frame
1863  << " -ef: " << _end_frame << endl;
1864  }
1865 
1866  // masad: keep track of maximum frames of animation on all these joints
1867  MTime maxFrame(_start_frame - 1, _timeUnit);
1868  MTime minFrame = maxFrame;
1869 
1870  for (ei = _anim_tab.begin(); ei != _anim_tab.end(); ++ei) {
1871  MayaAnim *anim = (*ei).second;
1872  MObject node = GetDependencyNode(anim->_joint->get_name());
1873  MFnDagNode mfnNode(node, &status);
1874 
1875  MMatrix mMat = mfnNode.transformationMatrix(&status);
1876 
1877  MObject attrTX = mfnNode.attribute("translateX", &status);
1878  MObject attrTY = mfnNode.attribute("translateY", &status);
1879  MObject attrTZ = mfnNode.attribute("translateZ", &status);
1880  MObject attrRX = mfnNode.attribute("rotateX", &status);
1881  MObject attrRY = mfnNode.attribute("rotateY", &status);
1882  MObject attrRZ = mfnNode.attribute("rotateZ", &status);
1883  MObject attrSX = mfnNode.attribute("scaleX", &status);
1884  MObject attrSY = mfnNode.attribute("scaleY", &status);
1885  MObject attrSZ = mfnNode.attribute("scaleZ", &status);
1886 
1887  MFnAnimCurve mfnAnimCurveTX;
1888  MFnAnimCurve mfnAnimCurveTY;
1889  MFnAnimCurve mfnAnimCurveTZ;
1890  MFnAnimCurve mfnAnimCurveRX;
1891  MFnAnimCurve mfnAnimCurveRY;
1892  MFnAnimCurve mfnAnimCurveRZ;
1893  MFnAnimCurve mfnAnimCurveSX;
1894  MFnAnimCurve mfnAnimCurveSY;
1895  MFnAnimCurve mfnAnimCurveSZ;
1896 
1897  mfnAnimCurveTX.create(node, attrTX, MFnAnimCurve::kAnimCurveTL, nullptr, &status);
1898  mfnAnimCurveTY.create(node, attrTY, MFnAnimCurve::kAnimCurveTL, nullptr, &status);
1899  mfnAnimCurveTZ.create(node, attrTZ, MFnAnimCurve::kAnimCurveTL, nullptr, &status);
1900  mfnAnimCurveRX.create(node, attrRX, MFnAnimCurve::kAnimCurveTA, nullptr, &status);
1901  mfnAnimCurveRY.create(node, attrRY, MFnAnimCurve::kAnimCurveTA, nullptr, &status);
1902  mfnAnimCurveRZ.create(node, attrRZ, MFnAnimCurve::kAnimCurveTA, nullptr, &status);
1903  mfnAnimCurveSX.create(node, attrSX, MFnAnimCurve::kAnimCurveTU, nullptr, &status);
1904  mfnAnimCurveSY.create(node, attrSY, MFnAnimCurve::kAnimCurveTU, nullptr, &status);
1905  mfnAnimCurveSZ.create(node, attrSZ, MFnAnimCurve::kAnimCurveTU, nullptr, &status);
1906 
1907  MTransformationMatrix matrix( mMat );
1908  MVector trans = matrix.translation(MSpace::kTransform, &status);
1909 
1910  double rot[3];
1911  MTransformationMatrix::RotationOrder order = MTransformationMatrix::kXYZ;
1912  status = matrix.getRotation(rot, order);
1913 
1914  double scale[3];
1915  status = matrix.getScale(scale, MSpace::kTransform);
1916  MFnAnimCurve::TangentType tangent = MFnAnimCurve::kTangentClamped;
1917  MTime time(_start_frame - 1, _timeUnit);
1918 
1919  mfnAnimCurveTX.addKey(time, trans.x, tangent, tangent, nullptr, &status);
1920  mfnAnimCurveTY.addKey(time, trans.y, tangent, tangent, nullptr, &status);
1921  mfnAnimCurveTZ.addKey(time, trans.z, tangent, tangent, nullptr, &status);
1922  mfnAnimCurveRX.addKey(time, rot[0], tangent, tangent, nullptr, &status);
1923  mfnAnimCurveRY.addKey(time, rot[1], tangent, tangent, nullptr, &status);
1924  mfnAnimCurveRZ.addKey(time, rot[2], tangent, tangent, nullptr, &status);
1925  mfnAnimCurveSX.addKey(time, scale[0], tangent, tangent, nullptr, &status);
1926  mfnAnimCurveSY.addKey(time, scale[1], tangent, tangent, nullptr, &status);
1927  mfnAnimCurveSZ.addKey(time, scale[2], tangent, tangent, nullptr, &status);
1928 
1929  for (int frame = 0; frame < anim->_pool->get_num_rows(); frame++)
1930  {
1931  LMatrix4d tMat;
1932  anim->_pool->get_value(frame, tMat);
1933 
1934  double matData[4][4] = {{tMat.get_cell(0,0), tMat.get_cell(0,1), tMat.get_cell(0,2), tMat.get_cell(0,3)},
1935  {tMat.get_cell(1,0), tMat.get_cell(1,1), tMat.get_cell(1,2), tMat.get_cell(1,3)},
1936  {tMat.get_cell(2,0), tMat.get_cell(2,1), tMat.get_cell(2,2), tMat.get_cell(2,3)},
1937  {tMat.get_cell(3,0), tMat.get_cell(3,1), tMat.get_cell(3,2), tMat.get_cell(3,3)}};
1938  MMatrix mat(matData);
1939 
1940  matrix = MTransformationMatrix(mat);
1941  trans = matrix.translation(MSpace::kTransform, &status);
1942  status = matrix.getRotation(rot, order);
1943  status = matrix.getScale(scale, MSpace::kTransform);
1944  time = MTime(frame + _start_frame, _timeUnit);
1945 
1946  mfnAnimCurveTX.addKey(time, trans.x, tangent, tangent, nullptr, &status);
1947  mfnAnimCurveTY.addKey(time, trans.y, tangent, tangent, nullptr, &status);
1948  mfnAnimCurveTZ.addKey(time, trans.z, tangent, tangent, nullptr, &status);
1949  mfnAnimCurveRX.addKey(time, rot[0], tangent, tangent, nullptr, &status);
1950  mfnAnimCurveRY.addKey(time, rot[1], tangent, tangent, nullptr, &status);
1951  mfnAnimCurveRZ.addKey(time, rot[2], tangent, tangent, nullptr, &status);
1952  mfnAnimCurveSX.addKey(time, scale[0], tangent, tangent, nullptr, &status);
1953  mfnAnimCurveSY.addKey(time, scale[1], tangent, tangent, nullptr, &status);
1954  mfnAnimCurveSZ.addKey(time, scale[2], tangent, tangent, nullptr, &status);
1955  }
1956  if (maxFrame < time) {
1957  maxFrame = time;
1958  }
1959  }
1960  if (anim) {
1961  // masad: set the control's max time with maxFrame
1962  MAnimControl::setMaxTime(maxFrame);
1963  MAnimControl::setMinTime(minFrame);
1964  }
1965 
1966  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
1967  delete (*ci).second;
1968  }
1969  for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
1970  delete (*ji).second;
1971  }
1972  for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) {
1973  delete (*ti).second;
1974  }
1975  for (ei = _anim_tab.begin(); ei != _anim_tab.end(); ++ei) {
1976  delete (*ei).second;
1977  }
1978 
1979  // ResumeSetKeyMode(); ResumeAnimate();
1980 
1981  mayaloader_cat.info() << "Egg import successful\n";
1982  return true;
1983 }
1984 
1985 void MayaEggLoader::PrintData(MayaEggMesh *mesh)
1986 {
1987  if (mayaloader_cat.is_spam()) {
1988  mayaloader_cat.spam() << "Mesh: " << mesh->_name << endl;
1989  mayaloader_cat.spam() << "num vertexArray: " << mesh->_vertexArray.length() << endl;
1990  ostringstream stream3;
1991  for (unsigned int i=0; i < mesh->_vertexArray.length(); ++i) {
1992  stream3 << "[" << mesh->_vertexArray[i].x << " " << mesh->_vertexArray[i].y << " " << mesh->_vertexArray[i].z << "]" << endl;
1993  }
1994 
1995  mayaloader_cat.spam() << "vertexArray: \n" << stream3.str() << endl;
1996  mayaloader_cat.spam() << "num polygonConnects: " << mesh->_polygonConnects.length() << endl;
1997  mayaloader_cat.spam() << "num uvCounts: " << mesh->_polygonCounts.length() << endl;
1998  mayaloader_cat.spam() << "num uvIds: " << mesh->_uvIds.length() << endl;
1999  ostringstream stream1, stream4;
2000  unsigned int k=0;
2001  for (unsigned int i=0; i < mesh->_polygonCounts.length(); ++i) {
2002  stream1 << mesh->_polygonCounts[i] << ":->";
2003  stream4 << mesh->_polygonCounts[i] << ":->";
2004  for (int j=0; j < mesh->_polygonCounts[i]; ++j, ++k) {
2005  stream1 << mesh->_uvIds[k] << ",";
2006  stream4 << mesh->_polygonConnects[k] << ",";
2007  }
2008  stream1 << endl;
2009  stream4 << endl;
2010  }
2011  mayaloader_cat.spam() << "uvCounts:->uvIds " << endl << stream1.str() << endl;
2012  mayaloader_cat.spam() << "vertexCount:->polygonConnects" << endl << stream4.str() << endl;
2013  }
2014 }
2015 
2016 void MayaEggLoader::ParseFrameInfo(string comment)
2017 {
2018  size_t pos, ls, le;
2019 
2020  pos = comment.find("-fri");
2021  if (pos != string::npos) {
2022  ls = comment.find(" ", pos+4);
2023  le = comment.find(" ", ls+1);
2024  if (mayaloader_cat.is_debug()) {
2025  mayaloader_cat.debug() << comment.substr(ls+1, le-ls-1) << endl;
2026  }
2027  _frame_rate = atoi(comment.substr(ls+1,le-ls-1).data());
2028  // mayaloader_cat.debug() << "le = " << le << "; and ls = " << ls << ";
2029  // frame_rate = " << _frame_rate << endl;
2030 
2031  switch (_frame_rate) {
2032  case 15:
2033  _timeUnit = MTime::kGames;
2034  break;
2035  case 24:
2036  _timeUnit = MTime::kFilm;
2037  break;
2038  case 25:
2039  _timeUnit = MTime::kPALFrame;
2040  break;
2041  case 30:
2042  _timeUnit = MTime::kNTSCFrame;
2043  break;
2044  case 48:
2045  _timeUnit = MTime::kShowScan;
2046  break;
2047  case 50:
2048  _timeUnit = MTime::kPALField;
2049  break;
2050  case 60:
2051  _timeUnit = MTime::kNTSCField;
2052  break;
2053  case 2:
2054  _timeUnit = MTime::k2FPS;
2055  break;
2056  case 3:
2057  _timeUnit = MTime::k3FPS;
2058  break;
2059  case 4:
2060  _timeUnit = MTime::k4FPS;
2061  break;
2062  case 5:
2063  _timeUnit = MTime::k5FPS;
2064  break;
2065  case 6:
2066  _timeUnit = MTime::k6FPS;
2067  break;
2068  case 8:
2069  _timeUnit = MTime::k8FPS;
2070  break;
2071  case 10:
2072  _timeUnit = MTime::k10FPS;
2073  break;
2074  case 12:
2075  _timeUnit = MTime::k12FPS;
2076  break;
2077  case 16:
2078  _timeUnit = MTime::k16FPS;
2079  break;
2080  case 20:
2081  _timeUnit = MTime::k20FPS;
2082  break;
2083  case 40:
2084  _timeUnit = MTime::k40FPS;
2085  break;
2086  case 75:
2087  _timeUnit = MTime::k75FPS;
2088  break;
2089  case 80:
2090  _timeUnit = MTime::k80FPS;
2091  break;
2092  case 100:
2093  _timeUnit = MTime::k100FPS;
2094  break;
2095  default:
2096  _timeUnit = MTime::kFilm;
2097  }
2098 
2099  }
2100 
2101  pos = comment.find("-sf");
2102  if (pos != string::npos) {
2103  ls = comment.find(" ", pos+3);
2104  le = comment.find(" ", ls+1);
2105  if (mayaloader_cat.is_debug()) {
2106  mayaloader_cat.debug() << comment.substr(ls+1, le-ls-1) << endl;
2107  }
2108  if (le == string::npos) {
2109  _start_frame = atoi(comment.substr(ls+1,le).data());
2110  } else {
2111  _start_frame = atoi(comment.substr(ls+1,le-ls-1).data());
2112  }
2113  // mayaloader_cat.debug() << "le = " << le << "; and ls = " << ls << ";
2114  // start_frame = " << _start_frame << endl;
2115  }
2116  pos = comment.find("-ef");
2117  if (pos != string::npos) {
2118  ls = comment.find(" ", pos+3);
2119  le = comment.find(" ", ls+1);
2120  if (mayaloader_cat.is_debug()) {
2121  mayaloader_cat.debug() << comment.substr(ls+1, le-ls-1) << endl;
2122  }
2123  if (le == string::npos) {
2124  _end_frame = atoi(comment.substr(ls+1,le).data());
2125  } else {
2126  _end_frame = atoi(comment.substr(ls+1,le-ls-1).data());
2127  }
2128  // mayaloader_cat.debug() << "le = " << le << "; and ls = " << ls << ";
2129  // end_frame = " << _end_frame << endl;
2130  }
2131 
2132 
2133 }
2134 
2135 bool MayaEggLoader::ConvertEggFile(const char *name, bool merge, bool model, bool anim, bool respect_normals)
2136 {
2137  EggData data;
2138  Filename datafn = Filename::from_os_specific(name);
2139  if (!data.read(datafn)) {
2140  mayaloader_cat.error() << "Cannot read Egg file for import\n";
2141  return false;
2142  }
2143  return ConvertEggData(&data, merge, model, anim, respect_normals);
2144 }
2145 
2146 MObject MayaEggLoader::GetDependencyNode(string givenName)
2147 {
2148  MObject node = MObject::kNullObj;
2149  size_t pos;
2150  string name;
2151 
2152  pos = givenName.find(":");
2153  if (pos != string::npos) {
2154  name = givenName.substr(pos+1);
2155  } else
2156  name = givenName;
2157 
2158  /*
2159  // masad: I do not think you want to return a mesh node because keyframes
2160  // should only apply to joint nodes.
2161  MeshTable::const_iterator ci;
2162  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
2163  MayaEggMesh *mesh = (*ci).second;
2164 
2165  string meshName = mesh->_pool->get_name();
2166  int nsize = meshName.size();
2167  if ((nsize > 6) && (meshName.rfind(".verts")==(nsize-6))) {
2168  meshName.resize(nsize-6);
2169  }
2170  if (meshName == name)
2171  {
2172  node = mesh->_transNode;
2173  cerr << "foo get dependency node returning a mesh's transNode? why? : " << givenName << endl;
2174  return node;
2175  }
2176  }
2177  */
2178 
2179  JointTable::const_iterator ji;
2180  for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
2181  MayaEggJoint *joint = (*ji).second;
2182  if (mayaloader_cat.is_spam()) {
2183  mayaloader_cat.spam() << "traversing a joint: " << joint->_egg_joint->get_name() << endl;
2184  }
2185  string jointName = joint->_egg_joint->get_name();
2186  if (jointName == name)
2187  {
2188  node = joint->_joint;
2189  return node;
2190  }
2191  }
2192 
2193  return node;
2194 }
2195 
2196 // The two global functions that form the API of this module.
2197 
2198 bool MayaLoadEggData(EggData *data, bool merge, bool model, bool anim, bool respect_normals)
2199 {
2200  MayaEggLoader loader;
2201  bool temp = loader.ConvertEggData(data, merge, model, anim, respect_normals);
2202  return temp;
2203 }
2204 
2205 bool MayaLoadEggFile(const char *name, bool merge, bool model, bool anim, bool respect_normals)
2206 {
2207  MayaEggLoader loader;
2208  return loader.ConvertEggFile(name, merge, model, anim, respect_normals);
2209 }
LColor get_color() const
Returns the color set on this particular attribute.
Definition: eggAttributes.I:91
A comment that appears in an egg file within a <Comment> entry.
Definition: eggComment.h:24
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition: eggData.h:37
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 base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:46
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
virtual bool is_joint() const
Returns true if this particular node represents a <Joint> entry or not.
Definition: eggGroup.cxx:468
double get_vertex_membership(const EggVertex *vert) const
Returns the amount of membership of the indicated vertex in this group.
Definition: eggGroup.cxx:677
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:36
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
A parametric NURBS surface.
bool is_closed_u() const
Returns true if the surface appears to be closed in the U direction.
bool is_closed_v() const
Returns true if the surface appears to be closed in the V direction.
get_num_u_knots
Returns the number of knots in the U 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,...
int get_v_degree() const
Returns the degree of the surface in the V direction.
get_v_knot
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.
int get_u_degree() const
Returns the degree of the surface in the U direction.
get_u_knot
Returns the nth knot value defined in the U direction.
int get_num_u_cvs() const
Returns the number of control vertices that should be present in the U direction.
get_num_v_knots
Returns the number of knots in the V direction.
A single polygon.
Definition: eggPolygon.h:24
virtual bool cleanup() override
Cleans up modeling errors in whatever context this makes sense.
Definition: eggPolygon.cxx:39
get_pool
Returns the vertex pool associated with the vertices of the primitive, or NULL if the primitive has n...
Definition: eggPrimitive.h:192
bool has_texture() const
Returns true if the primitive has any textures specified, false otherwise.
Definition: eggPrimitive.I:128
get_vertex
Returns a particular index based on its index number.
Definition: eggPrimitive.h:187
get_bface_flag
Retrieves the backfacing flag of the polygon.
Definition: eggPrimitive.h:116
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
This corresponds to a.
Definition: eggTable.h:27
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:30
const LMatrix4d & get_transform3d() const
Returns the overall transform as a 4x4 matrix.
Definition: eggTransform.I:212
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
bool has_transform3d() const
Returns true if the transform is specified as a 3-d transform, e.g.
Definition: eggTransform.I:179
LMatrix3d get_transform2d() const
Returns the overall transform as a 3x3 matrix.
Definition: eggTransform.I:198
A collection of vertices.
Definition: eggVertexPool.h:41
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
bool has_uv() const
Returns true if the vertex has an unnamed UV coordinate pair, false otherwise.
Definition: eggVertex.I:158
int get_index() const
Returns the index number of the vertex within its pool.
Definition: eggVertex.I:277
LTexCoordd get_uv() const
Returns the unnamed UV coordinate pair on the vertex.
Definition: eggVertex.I:179
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
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
LVertexd get_pos3() const
Valid if get_num_dimensions() returns 3 or 4.
Definition: eggVertex.I:131
This corresponds to an <Xfm$Anim_S$> entry, which is a collection of up to nine <S$Anim> entries that...
Definition: eggXfmSAnim.h:28
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
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
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
Specifies parameters that may be passed to the loader.
Definition: loaderOptions.h:23
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
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
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.