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;
69 typedef second_of_pair_iterator<MeshTable::const_iterator> MeshIterator;
70 typedef phash_map<EggGroup *, MaxEggJoint *> JointTable;
71 typedef second_of_pair_iterator<JointTable::const_iterator> JointIterator;
72 typedef phash_map<std::string, MaxEggTex *> TexTable;
73 typedef second_of_pair_iterator<TexTable::const_iterator> TexIterator;
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 }
EggAttributes::get_color
LColor get_color() const
Returns the color set on this particular attribute.
Definition: eggAttributes.I:91
EggData
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition: eggData.h:37
EggFilenameNode::get_fullpath
const Filename & get_fullpath() const
Returns the full pathname to the file, if it is known; otherwise, returns the same thing as get_filen...
Definition: eggFilenameNode.I:82
EggGroupNode
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:46
EggGroup
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:34
EggGroup::is_joint
virtual bool is_joint() const
Returns true if this particular node represents a <Joint> entry or not.
Definition: eggGroup.cxx:468
EggGroup::get_vertex_membership
double get_vertex_membership(const EggVertex *vert) const
Returns the amount of membership of the indicated vertex in this group.
Definition: eggGroup.cxx:677
EggNode
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:36
EggPolygon
A single polygon.
Definition: eggPolygon.h:24
EggPrimitive::get_pool
get_pool
Returns the vertex pool associated with the vertices of the primitive, or NULL if the primitive has n...
Definition: eggPrimitive.h:192
EggPrimitive::has_texture
bool has_texture() const
Returns true if the primitive has any textures specified, false otherwise.
Definition: eggPrimitive.I:128
EggPrimitive::get_texture
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
EggTexture
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:30
EggTransform::get_transform3d
const LMatrix4d & get_transform3d() const
Returns the overall transform as a 4x4 matrix.
Definition: eggTransform.I:212
EggTransform::has_transform
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
EggTransform::get_transform2d
LMatrix3d get_transform2d() const
Returns the overall transform as a 3x3 matrix.
Definition: eggTransform.I:198
EggVertexPool
A collection of vertices.
Definition: eggVertexPool.h:41
EggVertex
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
Definition: eggVertex.h:39
EggVertex::get_uv
LTexCoordd get_uv() const
Returns the unnamed UV coordinate pair on the vertex.
Definition: eggVertex.I:179
EggVertex::gref_end
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
EggVertex::gref_begin
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
EggVertex::get_pos3
LVertexd get_pos3() const
Valid if get_num_dimensions() returns 3 or 4.
Definition: eggVertex.I:131
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
Filename::to_os_specific
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
Filename::to_os_specific_w
std::wstring to_os_specific_w() const
The wide-string variant on to_os_specific().
Definition: filename.cxx:1163
Filename::from_os_specific
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
TypedObject::is_of_type
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
second_of_pair_iterator
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
Definition: iterator_types.h:43
stl_hash_compare
Definition: stl_compares.h:41
eggBin.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggData.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggGroupNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggPolygon.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggPolysetMaker.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggPrimitive.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggVertexPool.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
eggVertex.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
maxEggLoader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
notifyCategoryProxy.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pandatoolbase.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.