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 }
LColor get_color() const
Returns the color set on this particular attribute.
Definition: eggAttributes.I:91
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
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
bool has_texture() const
Returns true if the primitive has any textures specified, false otherwise.
Definition: eggPrimitive.I:128
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
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
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
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
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
std::wstring to_os_specific_w() const
The wide-string variant on to_os_specific().
Definition: filename.cxx:1163
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 is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
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.