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