Panda3D
maxEggLoader.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 maxEggLoader.cxx
10  * @author jyelon
11  * @date 2005-07-15
12  *
13  * This file contains the code for class MaxEggLoader. This class
14  * does the actual work of copying an EggData tree into the max scene.
15  */
16 
17 #include "pandatoolbase.h"
18 #include "notifyCategoryProxy.h"
19 
20 #include "eggData.h"
21 #include "eggVertexPool.h"
22 #include "eggVertex.h"
23 #include "eggPolygon.h"
24 #include "eggPrimitive.h"
25 #include "eggGroupNode.h"
26 #include "eggPolysetMaker.h"
27 #include "eggBin.h"
28 
29 using std::min;
30 using std::max;
31 
32 #include <stdio.h>
33 #include <Max.h>
34 #include <istdplug.h>
35 #include <stdmat.h>
36 #include <decomp.h>
37 #include <shape.h>
38 #include <simpobj.h>
39 #include <iparamb2.h>
40 #include <iskin.h>
41 #include <modstack.h>
42 
43 #include "maxEggLoader.h"
44 
45 using std::vector;
46 
47 class MaxEggMesh;
48 class MaxEggJoint;
49 class MaxEggTex;
50 
51 NotifyCategoryDeclNoExport(maxloader);
52 NotifyCategoryDef(maxloader, "");
53 
54 class MaxEggLoader
55 {
56 public:
57  bool ConvertEggData(EggData *data, bool merge, bool model, bool anim);
58  bool ConvertEggFile(const char *name, bool merge, bool model, bool anim);
59 
60 public:
61  void TraverseEggNode(EggNode *node, EggGroup *context);
62  MaxEggMesh *GetMesh(EggVertexPool *pool);
63  MaxEggJoint *FindJoint(EggGroup *joint);
64  MaxEggJoint *MakeJoint(EggGroup *joint, EggGroup *context);
65  MaxEggTex *GetTex(const Filename &fn);
66  void CreateSkinModifier(MaxEggMesh *M);
67 
68  typedef phash_map<EggVertexPool *, MaxEggMesh *> MeshTable;
70  typedef phash_map<EggGroup *, MaxEggJoint *> JointTable;
72  typedef phash_map<std::string, MaxEggTex *> TexTable;
74 
75  MeshTable _mesh_tab;
76  JointTable _joint_tab;
77  TexTable _tex_tab;
78  int _next_tex;
79 };
80 
81 Point3 MakeMaxPoint(LVector3d vec)
82 {
83  return Point3(vec[0], vec[1], vec[2]);
84 }
85 
86 // MaxEggTex
87 
88 class MaxEggTex
89 {
90 public:
91  Filename _path;
92  int _id;
93  StdMat *_mat;
94  BitmapTex *_bmt;
95 };
96 
97 MaxEggTex *MaxEggLoader::GetTex(const Filename &fn)
98 {
99  if (_tex_tab.count(fn))
100  return _tex_tab[fn];
101 
102  BitmapTex *bmt = NewDefaultBitmapTex();
103 #ifdef _UNICODE
104  bmt->SetMapName((TCHAR*) fn.to_os_specific_w().c_str());
105 #else
106  bmt->SetMapName((char*) fn.to_os_specific().c_str());
107 #endif
108 
109  StdMat *mat = NewDefaultStdMat();
110  mat->SetSubTexmap(ID_DI, bmt);
111  mat->SetTexmapAmt(ID_DI, 1.0, 0);
112  mat->EnableMap(ID_DI, TRUE);
113  mat->SetActiveTexmap(bmt);
114  GetCOREInterface()->ActivateTexture(bmt, mat);
115 
116  MaxEggTex *res = new MaxEggTex;
117  res->_path = fn;
118  res->_id = _next_tex ++;
119  res->_bmt = bmt;
120  res->_mat = mat;
121 
122  _tex_tab[fn] = res;
123  return res;
124 }
125 
126 // MaxEggJoint
127 
128 class MaxEggJoint
129 {
130 public:
131  LMatrix4d _trans;
132  LVector3d _endpos;
133  LVector3d _perp;
134  double _thickness;
135  bool _inskin;
136  SimpleObject2 *_bone;
137  INode *_node;
138  EggGroup *_egg_joint;
139  MaxEggJoint *_parent;
140  vector <MaxEggJoint *> _children;
141 
142 public:
143  void GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv);
144  LVector3d GetPos(void) { return _trans.get_row3(3); }
145  MaxEggJoint *ChooseBestChild(LVector3d dir);
146  void ChooseEndPos(double thickness);
147  void CreateMaxBone(void);
148 };
149 
150 void MaxEggJoint::GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv)
151 {
152  xv = _trans.get_row3(0);
153  yv = _trans.get_row3(1);
154  zv = _trans.get_row3(2);
155  xv.normalize();
156  yv.normalize();
157  zv = xv.cross(yv);
158  zv.normalize();
159  yv = zv.cross(xv);
160 }
161 
162 MaxEggJoint *MaxEggLoader::FindJoint(EggGroup *joint)
163 {
164  if (joint==0) return 0;
165  return _joint_tab[joint];
166 }
167 
168 MaxEggJoint *MaxEggLoader::MakeJoint(EggGroup *joint, EggGroup *context)
169 {
170  MaxEggJoint *parent = FindJoint(context);
171  MaxEggJoint *result = new MaxEggJoint;
172  LMatrix4d t = joint->get_transform3d();
173  if (parent) {
174  result->_trans = t * parent->_trans;
175  } else {
176  result->_trans = t;
177  }
178  result->_endpos = LVector3d(0,0,0);
179  result->_perp = LVector3d(0,0,0);
180  result->_thickness = 0.0;
181  result->_inskin = false;
182  result->_bone = 0;
183  result->_node = 0;
184  result->_egg_joint = joint;
185  result->_parent = parent;
186  if (parent) parent->_children.push_back(result);
187  _joint_tab[joint] = result;
188  return result;
189 }
190 
191 MaxEggJoint *MaxEggJoint::ChooseBestChild(LVector3d dir)
192 {
193  if (dir.length() < 0.001) return 0;
194  dir.normalize();
195  double firstbest = -1000;
196  MaxEggJoint *firstchild = 0;
197  LVector3d firstpos = GetPos();
198  double secondbest = 0;
199  for (int i=0; i<_children.size(); i++) {
200  MaxEggJoint *child = _children[i];
201  LVector3d tryfwd = child->GetPos() - GetPos();
202  if ((child->GetPos() != firstpos) && (tryfwd.length() > 0.001)) {
203  LVector3d trydir = tryfwd;
204  trydir.normalize();
205  double quality = trydir.dot(dir);
206  if (quality > firstbest) {
207  secondbest = firstbest;
208  firstbest = quality;
209  firstpos = child->GetPos();
210  firstchild = child;
211  } else if (quality > secondbest) {
212  secondbest = quality;
213  }
214  }
215  }
216  if (firstbest > secondbest + 0.1)
217  return firstchild;
218  return 0;
219 }
220 
221 void MaxEggJoint::ChooseEndPos(double thickness)
222 {
223  LVector3d parentpos(0,0,0);
224  LVector3d parentendpos(0,0,1);
225  if (_parent) {
226  parentpos = _parent->GetPos();
227  parentendpos = _parent->_endpos;
228  }
229  LVector3d fwd = GetPos() - parentpos;
230  if (fwd.length() < 0.001) {
231  fwd = parentendpos - parentpos;
232  }
233  fwd.normalize();
234  MaxEggJoint *child = ChooseBestChild(fwd);
235  if (child == 0) {
236  _endpos = fwd * thickness * 0.8 + GetPos();
237  _thickness = thickness * 0.8;
238  } else {
239  _endpos = child->GetPos();
240  _thickness = (_endpos - GetPos()).length();
241  if (_thickness > thickness) _thickness = thickness;
242  }
243  LVector3d orient = _endpos - GetPos();
244  orient.normalize();
245  LVector3d altaxis = orient.cross(LVector3d(0,-1,0));
246  if (altaxis.length() < 0.001) altaxis = orient.cross(LVector3d(0,0,1));
247  _perp = altaxis.cross(orient);
248  _perp.normalize();
249 }
250 
251 void MaxEggJoint::CreateMaxBone(void)
252 {
253  LVector3d rxv,ryv,rzv;
254  GetRotation(rxv, ryv, rzv);
255  Point3 xv(MakeMaxPoint(rxv));
256  Point3 yv(MakeMaxPoint(ryv));
257  Point3 zv(MakeMaxPoint(rzv));
258  Point3 pos(MakeMaxPoint(GetPos()));
259  Point3 endpos(MakeMaxPoint(_endpos));
260  Point3 tzv(MakeMaxPoint(_perp));
261 
262  Point3 fwd = endpos - pos;
263  double len = fwd.Length();
264  Point3 txv = fwd * ((PN_stdfloat)(1.0/len));
265  Point3 tyv = tzv ^ txv;
266  Point3 row1 = Point3(txv % xv, txv % yv, txv % zv);
267  Point3 row2 = Point3(tyv % xv, tyv % yv, tyv % zv);
268  Point3 row3 = Point3(tzv % xv, tzv % yv, tzv % zv);
269  Matrix3 oomat(row1,row2,row3,Point3(0,0,0));
270  Quat ooquat(oomat);
271  _bone = (SimpleObject2*)CreateInstance(GEOMOBJECT_CLASS_ID, BONE_OBJ_CLASSID);
272  _node = GetCOREInterface()->CreateObjectNode(_bone);
273  _node->SetNodeTM(0, Matrix3(xv, yv, zv, pos));
274  IParamBlock2 *blk = _bone->pblock2;
275  for (int i=0; i<blk->NumParams(); i++) {
276  TSTR n = blk->GetLocalName(i);
277  if (_tcscmp(n, _T("Length")) == 0) blk->SetValue(i, 0, (PN_stdfloat) len);
278  else if (_tcscmp(n, _T("Width")) == 0) blk->SetValue(i, 0, (PN_stdfloat) _thickness);
279  else if (_tcscmp(n, _T("Height")) == 0) blk->SetValue(i, 0, (PN_stdfloat) _thickness);
280  }
281  Point3 boneColor = GetUIColor(COLOR_BONES);
282  _node->SetWireColor(RGB(int(boneColor.x*255.0f), int(boneColor.y*255.0f), int(boneColor.z*255.0f) ));
283  _node->SetBoneNodeOnOff(TRUE, 0);
284  _node->SetRenderable(FALSE);
285 
286 #ifdef _UNICODE
287  TCHAR wname[1024];
288  wname[1023] = 0;
289  mbstowcs(wname, _egg_joint->get_name().c_str(), 1023);
290  _node->SetName(wname);
291 #else
292  _node->SetName((char*) _egg_joint->get_name().c_str());
293 #endif
294 
295  _node->SetObjOffsetRot(ooquat);
296  if (_parent) {
297  _node->Detach(0, 1);
298  _parent->_node->AttachChild(_node, 1);
299  }
300 }
301 
302 // MaxEggMesh
303 
304 typedef std::pair<double, EggGroup *> MaxEggWeight;
305 
306 struct MaxEggVertex
307 {
308  LVertexd _pos;
309  LNormald _normal;
310  vector<MaxEggWeight> _weights;
311  int _index;
312 };
313 
314 struct MEV_Compare: public stl_hash_compare<MaxEggVertex>
315 {
316  size_t operator()(const MaxEggVertex &key) const
317  {
318  return key._pos.add_hash(key._normal.get_hash());
319  }
320  bool operator()(const MaxEggVertex &k1, const MaxEggVertex &k2) const
321  {
322  int n = k1._pos.compare_to(k2._pos);
323  if (n < 0) return true;
324  if (n > 0) return false;
325  n = k1._normal.compare_to(k2._normal);
326  if (n < 0) return true;
327  if (n > 0) return false;
328  n = k1._weights.size() - k2._weights.size();
329  if (n < 0) return true;
330  if (n > 0) return false;
331  for (int i=0; i<k1._weights.size(); i++) {
332  double d = k1._weights[i].first - k2._weights[i].first;
333  if (d < 0) return true;
334  if (d > 0) return false;
335  EggGroup *g1 = k1._weights[i].second;
336  EggGroup *g2 = k2._weights[i].second;
337  if (g1 < g2) return true;
338  if (g1 > g2) return false;
339  }
340  return false;
341  }
342 };
343 
344 typedef phash_set<MaxEggVertex, MEV_Compare> VertTable;
345 typedef phash_map<LTexCoordd, int> TVertTable;
346 typedef phash_map<LColor, int> CVertTable;
347 
348 class MaxEggMesh
349 {
350 public:
351 
352  std::string _name;
353  TriObject *_obj;
354  Mesh *_mesh;
355  INode *_node;
356  IDerivedObject *_dobj;
357  Modifier *_skin_mod;
358  ISkin *_iskin;
359  ISkinImportData *_iskin_import;
360  int _vert_count;
361  int _tvert_count;
362  int _cvert_count;
363  int _face_count;
364 
365  VertTable _vert_tab;
366  TVertTable _tvert_tab;
367  CVertTable _cvert_tab;
368 
369  int GetVert(EggVertex *vert, EggGroup *context);
370  int GetTVert(const LTexCoordd &uv);
371  int GetCVert(const LColor &col);
372  int AddFace(int v0, int v1, int v2, int tv0, int tv1, int tv2, int cv0, int cv1, int cv2, int tex);
373  EggGroup *GetControlJoint(void);
374 };
375 
376 #define CTRLJOINT_DEFORM ((EggGroup*)((char*)(-1)))
377 
378 int MaxEggMesh::GetVert(EggVertex *vert, EggGroup *context)
379 {
380  MaxEggVertex vtx;
381  vtx._pos = vert->get_pos3();
382  vtx._normal = vert->get_normal();
383  vtx._index = 0;
384 
385  EggVertex::GroupRef::const_iterator gri;
386  for (gri = vert->gref_begin(); gri != vert->gref_end(); ++gri) {
387  EggGroup *egg_joint = (*gri);
388  double membership = egg_joint->get_vertex_membership(vert);
389  vtx._weights.push_back(MaxEggWeight(membership, egg_joint));
390  }
391  if (vtx._weights.size()==0) {
392  if (context != 0)
393  vtx._weights.push_back(MaxEggWeight(1.0, context));
394  }
395 
396  VertTable::const_iterator vti = _vert_tab.find(vtx);
397  if (vti != _vert_tab.end())
398  return vti->_index;
399 
400  if (_vert_count == _mesh->numVerts) {
401  int nsize = _vert_count*2 + 100;
402  _mesh->setNumVerts(nsize, _vert_count?TRUE:FALSE);
403  }
404  vtx._index = _vert_count++;
405  _vert_tab.insert(vtx);
406  _mesh->setVert(vtx._index, MakeMaxPoint(vtx._pos));
407  return vtx._index;
408 }
409 
410 int MaxEggMesh::GetTVert(const LTexCoordd &uv)
411 {
412  if (_tvert_tab.count(uv))
413  return _tvert_tab[uv];
414  if (_tvert_count == _mesh->numTVerts) {
415  int nsize = _tvert_count*2 + 100;
416  _mesh->setNumTVerts(nsize, _tvert_count?TRUE:FALSE);
417  }
418  int idx = _tvert_count++;
419  _mesh->setTVert(idx, uv.get_x(), uv.get_y(), 0.0);
420  _tvert_tab[uv] = idx;
421  return idx;
422 }
423 
424 int MaxEggMesh::GetCVert(const LColor &col)
425 {
426  if (_cvert_tab.count(col))
427  return _cvert_tab[col];
428  if (_cvert_count == _mesh->numCVerts) {
429  int nsize = _cvert_count*2 + 100;
430  _mesh->setNumVertCol(nsize, _cvert_count?TRUE:FALSE);
431  }
432  int idx = _cvert_count++;
433  _mesh->vertCol[idx] = Point3(col.get_x(), col.get_y(), col.get_z());
434  _cvert_tab[col] = idx;
435  return idx;
436 }
437 
438 MaxEggMesh *MaxEggLoader::GetMesh(EggVertexPool *pool)
439 {
440  MaxEggMesh *result = _mesh_tab[pool];
441  if (result == 0) {
442  std::string name = pool->get_name();
443  int nsize = name.size();
444  if ((nsize > 6) && (name.rfind(".verts")==(nsize-6)))
445  name.resize(nsize-6);
446  result = new MaxEggMesh;
447  result->_name = name;
448  result->_obj = CreateNewTriObject();
449  result->_mesh = &result->_obj->GetMesh();
450  result->_mesh->setMapSupport(0, TRUE);
451  result->_node = GetCOREInterface()->CreateObjectNode(result->_obj);
452  result->_dobj = 0;
453  result->_skin_mod = 0;
454  result->_iskin = 0;
455  result->_iskin_import = 0;
456  result->_vert_count = 0;
457  result->_tvert_count = 0;
458  result->_cvert_count = 0;
459  result->_face_count = 0;
460 #ifdef _UNICODE
461  TCHAR wname[1024];
462  wname[1023] = 0;
463  mbstowcs(wname, name.c_str(), 1023);
464  result->_node->SetName(wname);
465 #else
466  result->_node->SetName((char*) name.c_str());
467 #endif
468  _mesh_tab[pool] = result;
469  }
470  return result;
471 }
472 
473 int MaxEggMesh::AddFace(int v0, int v1, int v2, int tv0, int tv1, int tv2, int cv0, int cv1, int cv2, int tex)
474 {
475  static int dump = 0;
476  if (_face_count == _mesh->numFaces) {
477  int nsize = _face_count*2 + 100;
478  BOOL keep = _mesh->numFaces ? TRUE : FALSE;
479  _mesh->setNumFaces(nsize, keep);
480  _mesh->setNumTVFaces(nsize, keep, _face_count);
481  _mesh->setNumVCFaces(nsize, keep, _face_count);
482  }
483  int idx = _face_count++;
484  _mesh->faces[idx].setVerts(v0,v1,v2);
485  _mesh->faces[idx].smGroup = 1;
486  _mesh->faces[idx].flags = EDGE_ALL | HAS_TVERTS;
487  _mesh->faces[idx].setMatID(tex);
488  _mesh->tvFace[idx].setTVerts(tv0,tv1,tv2);
489  _mesh->vcFace[idx].setTVerts(cv0,cv1,cv2);
490  return idx;
491 }
492 
493 EggGroup *MaxEggMesh::GetControlJoint(void)
494 {
495  EggGroup *result;
496  VertTable::const_iterator vert = _vert_tab.begin();
497  if (vert == _vert_tab.end()) return 0;
498  switch (vert->_weights.size()) {
499  case 0:
500  for (++vert; vert != _vert_tab.end(); ++vert)
501  if (vert->_weights.size() != 0)
502  return CTRLJOINT_DEFORM;
503  return 0;
504  case 1:
505  result = vert->_weights[0].second;
506  for (++vert; vert != _vert_tab.end(); ++vert)
507  if ((vert->_weights.size() != 1) || (vert->_weights[0].second != result))
508  return CTRLJOINT_DEFORM;
509  return result;
510  default:
511  return CTRLJOINT_DEFORM;
512  }
513 }
514 
515 void MaxEggLoader::CreateSkinModifier(MaxEggMesh *M)
516 {
517  vector <MaxEggJoint *> joints;
518 
519  M->_dobj = CreateDerivedObject(M->_obj);
520  M->_node->SetObjectRef(M->_dobj);
521  M->_skin_mod = (Modifier*)CreateInstance(OSM_CLASS_ID, SKIN_CLASSID);
522  M->_iskin = (ISkin*)M->_skin_mod->GetInterface(I_SKIN);
523  M->_iskin_import = (ISkinImportData*)M->_skin_mod->GetInterface(I_SKINIMPORTDATA);
524  M->_dobj->SetAFlag(A_LOCK_TARGET);
525  M->_dobj->AddModifier(M->_skin_mod);
526  M->_dobj->ClearAFlag(A_LOCK_TARGET);
527  GetCOREInterface()->ForceCompleteRedraw();
528 
529  VertTable::const_iterator vert;
530  for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) {
531  for (int i=0; i<vert->_weights.size(); i++) {
532  double strength = vert->_weights[i].first;
533  MaxEggJoint *joint = FindJoint(vert->_weights[i].second);
534  if (!joint->_inskin) {
535  joint->_inskin = true;
536  joints.push_back(joint);
537  }
538  }
539  }
540  for (int i=0; i<joints.size(); i++) {
541  BOOL last = (i == (joints.size()-1)) ? TRUE : FALSE;
542  M->_iskin_import->AddBoneEx(joints[i]->_node, last);
543  joints[i]->_inskin = false;
544  }
545 
546  GetCOREInterface()->SetCommandPanelTaskMode(TASK_MODE_MODIFY);
547  GetCOREInterface()->SelectNode(M->_node);
548  GetCOREInterface()->ForceCompleteRedraw();
549 
550  for (vert=M->_vert_tab.begin(); vert != M->_vert_tab.end(); ++vert) {
551  Tab<INode*> maxJoints;
552  Tab<PN_stdfloat> maxWeights;
553  maxJoints.ZeroCount();
554  maxWeights.ZeroCount();
555  for (int i=0; i<vert->_weights.size(); i++) {
556  PN_stdfloat strength = (PN_stdfloat)(vert->_weights[i].first);
557  MaxEggJoint *joint = FindJoint(vert->_weights[i].second);
558  maxWeights.Append(1,&strength);
559  maxJoints.Append(1,&(joint->_node));
560  }
561  M->_iskin_import->AddWeights(M->_node, vert->_index, maxJoints, maxWeights);
562  }
563 }
564 
565 // TraverseEggData We have an EggData in memory, and now we're going to copy
566 // that over into the max scene graph.
567 
568 void MaxEggLoader::TraverseEggNode(EggNode *node, EggGroup *context)
569 {
570  vector<int> vertIndices;
571  vector<int> tvertIndices;
572  vector<int> cvertIndices;
573 
574  if (node->is_of_type(EggPolygon::get_class_type())) {
575  EggPolygon *poly = DCAST(EggPolygon, node);
576 
577  int texid;
578  LMatrix3d uvtrans = LMatrix3d::ident_mat();
579  if (poly->has_texture()) {
580  EggTexture *tex = poly->get_texture(0);
581  texid = GetTex(tex->get_fullpath())->_id;
582  if (tex->has_transform())
583  uvtrans = tex->get_transform2d();
584  } else {
585  texid = GetTex(Filename())->_id;
586  }
587 
588  EggPolygon::const_iterator ci;
589  MaxEggMesh *mesh = GetMesh(poly->get_pool());
590  vertIndices.clear();
591  tvertIndices.clear();
592  cvertIndices.clear();
593  for (ci = poly->begin(); ci != poly->end(); ++ci) {
594  EggVertex *vtx = (*ci);
595  EggVertexPool *pool = poly->get_pool();
596  LTexCoordd uv = vtx->get_uv();
597  vertIndices.push_back(mesh->GetVert(vtx, context));
598  tvertIndices.push_back(mesh->GetTVert(uv * uvtrans));
599  cvertIndices.push_back(mesh->GetCVert(vtx->get_color()));
600  }
601  for (int i=1; i<vertIndices.size()-1; i++)
602  mesh->AddFace(vertIndices[0], vertIndices[i], vertIndices[i+1],
603  tvertIndices[0], tvertIndices[i], tvertIndices[i+1],
604  cvertIndices[0], cvertIndices[i], cvertIndices[i+1],
605  texid);
606  } else if (node->is_of_type(EggGroupNode::get_class_type())) {
607  EggGroupNode *group = DCAST(EggGroupNode, node);
608  if (node->is_of_type(EggGroup::get_class_type())) {
609  EggGroup *group = DCAST(EggGroup, node);
610  if (group->is_joint()) {
611  MakeJoint(group, context);
612  context = group;
613  }
614  }
615  EggGroupNode::const_iterator ci;
616  for (ci = group->begin(); ci != group->end(); ++ci) {
617  TraverseEggNode(*ci, context);
618  }
619  }
620 }
621 
622 bool MaxEggLoader::ConvertEggData(EggData *data, bool merge, bool model, bool anim)
623 {
624  if (!merge) {
625  maxloader_cat.error() << "Currently, only 'merge' mode is implemented.\n";
626  return false;
627  }
628 
629  if ((anim) || (!model)) {
630  maxloader_cat.error() << "Currently, only model-loading is implemented.\n";
631  return false;
632  }
633 
634  MeshIterator ci;
635  JointIterator ji;
636  TexIterator ti;
637 
638  data->set_coordinate_system(CS_zup_right);
639 
640  SuspendAnimate();
641  SuspendSetKeyMode();
642  AnimateOff();
643  _next_tex = 0;
644 
645  TraverseEggNode(data, nullptr);
646 
647  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
648  MaxEggMesh *mesh = (*ci);
649  mesh->_mesh->setNumVerts(mesh->_vert_count, TRUE);
650  mesh->_mesh->setNumTVerts(mesh->_tvert_count, TRUE);
651  mesh->_mesh->setNumVertCol(mesh->_cvert_count, TRUE);
652  mesh->_mesh->setNumFaces(mesh->_face_count, TRUE);
653  mesh->_mesh->setNumTVFaces(mesh->_face_count, TRUE, mesh->_face_count);
654  mesh->_mesh->setNumVCFaces(mesh->_face_count, TRUE, mesh->_face_count);
655  mesh->_mesh->InvalidateTopologyCache();
656  mesh->_mesh->InvalidateGeomCache();
657  mesh->_mesh->buildNormals();
658  }
659 
660  double thickness = 0.0;
661  for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
662  double dfo = ((*ji)->GetPos()).length();
663  if (dfo > thickness) thickness = dfo;
664  }
665  thickness = thickness * 0.025;
666  for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) {
667  MaxEggJoint *joint = *ji;
668  joint->ChooseEndPos(thickness);
669  joint->CreateMaxBone();
670  }
671 
672  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
673  MaxEggMesh *mesh = (*ci);
674  EggGroup *joint = mesh->GetControlJoint();
675  if (joint) CreateSkinModifier(mesh);
676  }
677 
678  if (_next_tex) {
679  TSTR name;
680  MultiMtl *mtl = NewDefaultMultiMtl();
681  mtl->SetNumSubMtls(_next_tex);
682  for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) {
683  MaxEggTex *tex = *ti;
684  mtl->SetSubMtlAndName(tex->_id, tex->_mat, name);
685  }
686  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
687  MaxEggMesh *mesh = *ci;
688  mesh->_node->SetMtl(mtl);
689  }
690  }
691 
692  for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) delete *ci;
693  for (ji = _joint_tab.begin(); ji != _joint_tab.end(); ++ji) delete *ji;
694  for (ti = _tex_tab.begin(); ti != _tex_tab.end(); ++ti) delete *ti;
695 
696  ResumeSetKeyMode();
697  ResumeAnimate();
698 
699  maxloader_cat.info() << "Egg import successful\n";
700  return true;
701 }
702 
703 bool MaxEggLoader::ConvertEggFile(const char *name, bool merge, bool model, bool anim)
704 {
705  EggData data;
706  Filename datafn = Filename::from_os_specific(name);
707  if (!data.read(datafn)) {
708  maxloader_cat.error() << "Cannot read Egg file for import\n";
709  return false;
710  }
711  return ConvertEggData(&data, merge, model, anim);
712 }
713 
714 // The two global functions that form the API of this module.
715 
716 bool MaxLoadEggData(EggData *data, bool merge, bool model, bool anim)
717 {
718  MaxEggLoader loader;
719  return loader.ConvertEggData(data, merge, model, anim);
720 }
721 
722 bool MaxLoadEggFile(const char *name, bool merge, bool model, bool anim)
723 {
724  MaxEggLoader loader;
725  return loader.ConvertEggFile(name, merge, model, anim);
726 }
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
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
virtual bool is_joint() const
Returns true if this particular node represents a <Joint> entry or not.
Definition: eggGroup.cxx:468
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
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.
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 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
std::wstring to_os_specific_w() const
The wide-string variant on to_os_specific().
Definition: filename.cxx:1163
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
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.
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
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
get_pool
Returns the vertex pool associated with the vertices of the primitive, or NULL if the primitive has n...
Definition: eggPrimitive.h:192
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:35
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
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.
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
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