51 NotifyCategoryDeclNoExport(maxloader);
52 NotifyCategoryDef(maxloader,
"");
57 bool ConvertEggData(
EggData *data,
bool merge,
bool model,
bool anim);
58 bool ConvertEggFile(
const char *name,
bool merge,
bool model,
bool anim);
63 MaxEggJoint *FindJoint(
EggGroup *joint);
65 MaxEggTex *GetTex(
const Filename &fn);
66 void CreateSkinModifier(MaxEggMesh *M);
68 typedef phash_map<EggVertexPool *, MaxEggMesh *> MeshTable;
70 typedef phash_map<EggGroup *, MaxEggJoint *> JointTable;
72 typedef phash_map<std::string, MaxEggTex *> TexTable;
76 JointTable _joint_tab;
81 Point3 MakeMaxPoint(LVector3d vec)
83 return Point3(vec[0], vec[1], vec[2]);
97 MaxEggTex *MaxEggLoader::GetTex(
const Filename &fn)
99 if (_tex_tab.count(fn))
102 BitmapTex *bmt = NewDefaultBitmapTex();
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);
116 MaxEggTex *res =
new MaxEggTex;
118 res->_id = _next_tex ++;
136 SimpleObject2 *_bone;
139 MaxEggJoint *_parent;
140 vector <MaxEggJoint *> _children;
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);
150 void MaxEggJoint::GetRotation(LVector3d &xv, LVector3d &yv, LVector3d &zv)
152 xv = _trans.get_row3(0);
153 yv = _trans.get_row3(1);
154 zv = _trans.get_row3(2);
162 MaxEggJoint *MaxEggLoader::FindJoint(
EggGroup *joint)
164 if (joint==0)
return 0;
165 return _joint_tab[joint];
170 MaxEggJoint *parent = FindJoint(context);
171 MaxEggJoint *result =
new MaxEggJoint;
174 result->_trans = t * parent->_trans;
178 result->_endpos = LVector3d(0,0,0);
179 result->_perp = LVector3d(0,0,0);
180 result->_thickness = 0.0;
181 result->_inskin =
false;
184 result->_egg_joint = joint;
185 result->_parent = parent;
186 if (parent) parent->_children.push_back(result);
187 _joint_tab[joint] = result;
191 MaxEggJoint *MaxEggJoint::ChooseBestChild(LVector3d dir)
193 if (dir.length() < 0.001)
return 0;
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;
205 double quality = trydir.dot(dir);
206 if (quality > firstbest) {
207 secondbest = firstbest;
209 firstpos = child->GetPos();
211 }
else if (quality > secondbest) {
212 secondbest = quality;
216 if (firstbest > secondbest + 0.1)
221 void MaxEggJoint::ChooseEndPos(
double thickness)
223 LVector3d parentpos(0,0,0);
224 LVector3d parentendpos(0,0,1);
226 parentpos = _parent->GetPos();
227 parentendpos = _parent->_endpos;
229 LVector3d fwd = GetPos() - parentpos;
230 if (fwd.length() < 0.001) {
231 fwd = parentendpos - parentpos;
234 MaxEggJoint *child = ChooseBestChild(fwd);
236 _endpos = fwd * thickness * 0.8 + GetPos();
237 _thickness = thickness * 0.8;
239 _endpos = child->GetPos();
240 _thickness = (_endpos - GetPos()).length();
241 if (_thickness > thickness) _thickness = thickness;
243 LVector3d orient = _endpos - GetPos();
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);
251 void MaxEggJoint::CreateMaxBone(
void)
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));
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));
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);
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);
289 mbstowcs(wname, _egg_joint->get_name().c_str(), 1023);
290 _node->SetName(wname);
292 _node->SetName((
char*) _egg_joint->get_name().c_str());
295 _node->SetObjOffsetRot(ooquat);
298 _parent->_node->AttachChild(_node, 1);
304 typedef std::pair<double, EggGroup *> MaxEggWeight;
310 vector<MaxEggWeight> _weights;
316 size_t operator()(
const MaxEggVertex &key)
const 318 return key._pos.add_hash(key._normal.get_hash());
320 bool operator()(
const MaxEggVertex &k1,
const MaxEggVertex &k2)
const 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;
344 typedef phash_set<MaxEggVertex, MEV_Compare> VertTable;
345 typedef phash_map<LTexCoordd, int> TVertTable;
346 typedef phash_map<LColor, int> CVertTable;
356 IDerivedObject *_dobj;
359 ISkinImportData *_iskin_import;
366 TVertTable _tvert_tab;
367 CVertTable _cvert_tab;
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);
376 #define CTRLJOINT_DEFORM ((EggGroup*)((char*)(-1))) 382 vtx._normal = vert->get_normal();
385 EggVertex::GroupRef::const_iterator gri;
389 vtx._weights.push_back(MaxEggWeight(membership, egg_joint));
391 if (vtx._weights.size()==0) {
393 vtx._weights.push_back(MaxEggWeight(1.0, context));
396 VertTable::const_iterator vti = _vert_tab.find(vtx);
397 if (vti != _vert_tab.end())
400 if (_vert_count == _mesh->numVerts) {
401 int nsize = _vert_count*2 + 100;
402 _mesh->setNumVerts(nsize, _vert_count?TRUE:FALSE);
404 vtx._index = _vert_count++;
405 _vert_tab.insert(vtx);
406 _mesh->setVert(vtx._index, MakeMaxPoint(vtx._pos));
410 int MaxEggMesh::GetTVert(
const LTexCoordd &uv)
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);
418 int idx = _tvert_count++;
419 _mesh->setTVert(idx, uv.get_x(), uv.get_y(), 0.0);
420 _tvert_tab[uv] = idx;
424 int MaxEggMesh::GetCVert(
const LColor &col)
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);
432 int idx = _cvert_count++;
433 _mesh->vertCol[idx] = Point3(col.get_x(), col.get_y(), col.get_z());
434 _cvert_tab[col] = idx;
440 MaxEggMesh *result = _mesh_tab[pool];
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);
453 result->_skin_mod = 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;
463 mbstowcs(wname, name.c_str(), 1023);
464 result->_node->SetName(wname);
466 result->_node->SetName((
char*) name.c_str());
468 _mesh_tab[pool] = result;
473 int MaxEggMesh::AddFace(
int v0,
int v1,
int v2,
int tv0,
int tv1,
int tv2,
int cv0,
int cv1,
int cv2,
int tex)
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);
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);
493 EggGroup *MaxEggMesh::GetControlJoint(
void)
496 VertTable::const_iterator vert = _vert_tab.begin();
497 if (vert == _vert_tab.end())
return 0;
498 switch (vert->_weights.size()) {
500 for (++vert; vert != _vert_tab.end(); ++vert)
501 if (vert->_weights.size() != 0)
502 return CTRLJOINT_DEFORM;
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;
511 return CTRLJOINT_DEFORM;
515 void MaxEggLoader::CreateSkinModifier(MaxEggMesh *M)
517 vector <MaxEggJoint *> joints;
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();
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);
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;
546 GetCOREInterface()->SetCommandPanelTaskMode(TASK_MODE_MODIFY);
547 GetCOREInterface()->SelectNode(M->_node);
548 GetCOREInterface()->ForceCompleteRedraw();
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));
561 M->_iskin_import->AddWeights(M->_node, vert->_index, maxJoints, maxWeights);
570 vector<int> vertIndices;
571 vector<int> tvertIndices;
572 vector<int> cvertIndices;
574 if (node->
is_of_type(EggPolygon::get_class_type())) {
578 LMatrix3d uvtrans = LMatrix3d::ident_mat();
588 EggPolygon::const_iterator ci;
589 MaxEggMesh *mesh = GetMesh(poly->
get_pool());
591 tvertIndices.clear();
592 cvertIndices.clear();
593 for (ci = poly->begin(); ci != poly->end(); ++ci) {
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()));
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],
606 }
else if (node->
is_of_type(EggGroupNode::get_class_type())) {
608 if (node->
is_of_type(EggGroup::get_class_type())) {
611 MakeJoint(group, context);
615 EggGroupNode::const_iterator ci;
616 for (ci = group->begin(); ci != group->end(); ++ci) {
617 TraverseEggNode(*ci, context);
622 bool MaxEggLoader::ConvertEggData(
EggData *data,
bool merge,
bool model,
bool anim)
625 maxloader_cat.error() <<
"Currently, only 'merge' mode is implemented.\n";
629 if ((anim) || (!model)) {
630 maxloader_cat.error() <<
"Currently, only model-loading is implemented.\n";
638 data->set_coordinate_system(CS_zup_right);
645 TraverseEggNode(data,
nullptr);
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();
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;
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();
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);
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);
686 for (ci = _mesh_tab.begin(); ci != _mesh_tab.end(); ++ci) {
687 MaxEggMesh *mesh = *ci;
688 mesh->_node->SetMtl(mtl);
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;
699 maxloader_cat.info() <<
"Egg import successful\n";
703 bool MaxEggLoader::ConvertEggFile(
const char *name,
bool merge,
bool model,
bool anim)
707 if (!data.read(datafn)) {
708 maxloader_cat.error() <<
"Cannot read Egg file for import\n";
711 return ConvertEggData(&data, merge, model, anim);
716 bool MaxLoadEggData(
EggData *data,
bool merge,
bool model,
bool anim)
719 return loader.ConvertEggData(data, merge, model, anim);
722 bool MaxLoadEggFile(
const char *name,
bool merge,
bool model,
bool anim)
725 return loader.ConvertEggFile(name, merge, model, anim);
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GroupRef::const_iterator gref_end() const
Returns an iterator that can, in conjunction with gref_begin(), be used to traverse the entire set of...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A base class for nodes in the hierarchy that are not leaf nodes.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
LTexCoordd get_uv() const
Returns the unnamed UV coordinate pair on the vertex.
Defines a texture map that may be applied to geometry.
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...
LVertexd get_pos3() const
Valid if get_num_dimensions() returns 3 or 4.
This is the primary interface into all the egg data, and the root of the egg file structure.
LColor get_color() const
Returns the color set on this particular attribute.
std::wstring to_os_specific_w() const
The wide-string variant on to_os_specific().
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...
The name of a file, such as a texture file or an Egg file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
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.
bool has_texture() const
Returns true if the primitive has any textures specified, false otherwise.
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...
get_pool
Returns the vertex pool associated with the vertices of the primitive, or NULL if the primitive has n...
A base class for things that may be directly added into the egg hierarchy.
get_texture
Returns the first texture on the primitive, if any, or NULL if there are no textures on the primitive...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A collection of vertices.
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,...