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);
LColor get_color() const
Returns the color set on this particular attribute.
This is the primary interface into all the egg data, and the root of the egg file structure.
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.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
virtual bool is_joint() const
Returns true if this particular node represents a <Joint> entry or not.
double get_vertex_membership(const EggVertex *vert) const
Returns the amount of membership of the indicated vertex in this group.
A base class for things that may be directly added into the egg hierarchy.
get_pool
Returns the vertex pool associated with the vertices of the primitive, or NULL if the primitive has n...
bool has_texture() const
Returns true if the primitive has any textures specified, false otherwise.
get_texture
Returns the first texture on the primitive, if any, or NULL if there are no textures on the primitive...
Defines a texture map that may be applied to geometry.
A collection of vertices.
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal.
LTexCoordd get_uv() const
Returns the unnamed UV coordinate pair on the vertex.
GroupRef::const_iterator gref_end() const
Returns an iterator that can, in conjunction with gref_begin(), be used to traverse the entire set of...
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.
The name of a file, such as a texture file or an Egg file.
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
std::wstring to_os_specific_w() const
The wide-string variant on to_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,...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
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.