00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "xFileToEggConverter.h"
00016 #include "xFileMesh.h"
00017 #include "xFileMaterial.h"
00018 #include "xFileAnimationSet.h"
00019 #include "config_xfile.h"
00020
00021 #include "eggData.h"
00022 #include "eggGroup.h"
00023 #include "eggXfmSAnim.h"
00024 #include "eggGroupUniquifier.h"
00025 #include "datagram.h"
00026 #include "eggMaterialCollection.h"
00027 #include "eggTextureCollection.h"
00028 #include "dcast.h"
00029
00030
00031
00032
00033
00034
00035 XFileToEggConverter::
00036 XFileToEggConverter() {
00037 _make_char = false;
00038 _frame_rate = 0.0;
00039 _x_file = new XFile(true);
00040 _dart_node = NULL;
00041 }
00042
00043
00044
00045
00046
00047
00048 XFileToEggConverter::
00049 XFileToEggConverter(const XFileToEggConverter ©) :
00050 SomethingToEggConverter(copy),
00051 _make_char(copy._make_char)
00052 {
00053 _x_file = new XFile(true);
00054 _dart_node = NULL;
00055 }
00056
00057
00058
00059
00060
00061
00062 XFileToEggConverter::
00063 ~XFileToEggConverter() {
00064 close();
00065 }
00066
00067
00068
00069
00070
00071
00072 SomethingToEggConverter *XFileToEggConverter::
00073 make_copy() {
00074 return new XFileToEggConverter(*this);
00075 }
00076
00077
00078
00079
00080
00081
00082
00083
00084 string XFileToEggConverter::
00085 get_name() const {
00086 return "DirectX";
00087 }
00088
00089
00090
00091
00092
00093
00094
00095 string XFileToEggConverter::
00096 get_extension() const {
00097 return "x";
00098 }
00099
00100
00101
00102
00103
00104
00105
00106
00107 bool XFileToEggConverter::
00108 supports_compressed() const {
00109 return true;
00110 }
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 bool XFileToEggConverter::
00125 convert_file(const Filename &filename) {
00126 close();
00127 clear_error();
00128
00129 if (!_x_file->read(filename)) {
00130 nout << "Unable to open X file: " << filename << "\n";
00131 return false;
00132 }
00133
00134 if (_char_name.empty()) {
00135 _char_name = filename.get_basename_wo_extension();
00136 }
00137
00138 if (_egg_data->get_coordinate_system() == CS_default) {
00139 _egg_data->set_coordinate_system(CS_yup_left);
00140 }
00141
00142 if (!get_toplevel()) {
00143 return false;
00144 }
00145
00146 if (!create_polygons()) {
00147 return false;
00148 }
00149
00150 if (_make_char) {
00151
00152 EggGroupUniquifier uniquifier(false);
00153 uniquifier.uniquify(_dart_node);
00154 }
00155
00156 if (!create_hierarchy()) {
00157 return false;
00158 }
00159
00160 if (_keep_model && !_keep_animation) {
00161 strip_nodes(EggTable::get_class_type());
00162 }
00163
00164 if (_keep_animation && !_keep_model) {
00165 strip_nodes(EggGroup::get_class_type());
00166 }
00167
00168 return !had_error();
00169 }
00170
00171
00172
00173
00174
00175
00176
00177 void XFileToEggConverter::
00178 close() {
00179 _x_file->clear();
00180
00181
00182 Meshes::const_iterator mi;
00183 for (mi = _meshes.begin(); mi != _meshes.end(); ++mi) {
00184 delete (*mi);
00185 }
00186 _meshes.clear();
00187
00188 AnimationSets::const_iterator asi;
00189 for (asi = _animation_sets.begin(); asi != _animation_sets.end(); ++asi) {
00190 delete (*asi);
00191 }
00192 _animation_sets.clear();
00193
00194 _joints.clear();
00195 }
00196
00197
00198
00199
00200
00201
00202
00203 void XFileToEggConverter::
00204 strip_nodes(TypeHandle t) {
00205 pvector <EggNode *> garbage;
00206 EggGroupNode::iterator i;
00207 for (i=_egg_data->begin(); i!=_egg_data->end(); ++i) {
00208 EggNode *node = (*i);
00209 if (node->is_of_type(t)) {
00210 garbage.push_back(node);
00211 }
00212 }
00213 for (int n=0; n<(int)garbage.size(); n++) {
00214 _egg_data->remove_child(garbage[n]);
00215 }
00216 }
00217
00218
00219
00220
00221
00222
00223
00224 EggGroup *XFileToEggConverter::
00225 get_dart_node() const {
00226 return _dart_node;
00227 }
00228
00229
00230
00231
00232
00233
00234
00235
00236 EggTexture *XFileToEggConverter::
00237 create_unique_texture(const EggTexture ©) {
00238 return _textures.create_unique_texture(copy, ~EggTexture::E_tref_name);
00239 }
00240
00241
00242
00243
00244
00245
00246
00247
00248 EggMaterial *XFileToEggConverter::
00249 create_unique_material(const EggMaterial ©) {
00250 return _materials.create_unique_material(copy, ~EggMaterial::E_mref_name);
00251 }
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 EggGroup *XFileToEggConverter::
00262 find_joint(const string &joint_name) {
00263 Joints::iterator ji;
00264 ji = _joints.find(joint_name);
00265 if (ji != _joints.end()) {
00266 EggGroup *joint = (*ji).second;
00267 if (joint == (EggGroup *)NULL) {
00268
00269 return NULL;
00270 }
00271
00272 return joint;
00273 }
00274
00275
00276
00277
00278 if (_make_char) {
00279 xfile_cat.warning()
00280 << "Joint name " << joint_name << " in animation data is undefined.\n";
00281 }
00282 _joints[joint_name] = NULL;
00283
00284 return NULL;
00285 }
00286
00287
00288
00289
00290
00291
00292
00293
00294 bool XFileToEggConverter::
00295 get_toplevel() {
00296 int num_objects = _x_file->get_num_objects();
00297 int i;
00298
00299 _ticks_per_second = 4800;
00300
00301
00302
00303 _any_frames = false;
00304 _any_animation = false;
00305 for (i = 0; i < num_objects; i++) {
00306 XFileDataNode *child = _x_file->get_object(i);
00307 if (child->is_standard_object("Frame")) {
00308 _any_frames = true;
00309 } else if (child->is_standard_object("AnimationSet")) {
00310 _any_animation = true;
00311 }
00312 }
00313
00314
00315 if (_any_animation) {
00316 _make_char = true;
00317 }
00318
00319 EggGroupNode *egg_parent = _egg_data;
00320
00321
00322
00323 if (_make_char) {
00324 _dart_node = new EggGroup(_char_name);
00325 egg_parent->add_child(_dart_node);
00326 _dart_node->set_dart_type(EggGroup::DT_default);
00327 egg_parent = _dart_node;
00328 }
00329
00330
00331 for (i = 0; i < num_objects; i++) {
00332 if (!convert_toplevel_object(_x_file->get_object(i), egg_parent)) {
00333 return false;
00334 }
00335 }
00336
00337 return true;
00338 }
00339
00340
00341
00342
00343
00344
00345
00346 bool XFileToEggConverter::
00347 convert_toplevel_object(XFileDataNode *obj, EggGroupNode *egg_parent) {
00348 if (obj->is_standard_object("Header")) {
00349
00350
00351 } else if (obj->is_standard_object("Material")) {
00352
00353
00354
00355 } else if (obj->is_standard_object("Frame")) {
00356 if (!convert_frame(obj, egg_parent)) {
00357 return false;
00358 }
00359
00360 } else if (obj->is_standard_object("AnimationSet")) {
00361 if (!convert_animation_set(obj)) {
00362 return false;
00363 }
00364
00365 } else if (obj->is_standard_object("AnimTicksPerSecond")) {
00366 _ticks_per_second = (*obj)[0].i();
00367
00368 } else if (obj->is_standard_object("Mesh")) {
00369
00370
00371
00372
00373
00374 if (!_any_frames) {
00375 if (!convert_mesh(obj, egg_parent)) {
00376 return false;
00377 }
00378 }
00379
00380 } else {
00381 if (xfile_cat.is_debug()) {
00382 xfile_cat.debug()
00383 << "Ignoring toplevel object of unknown type: "
00384 << obj->get_template_name() << "\n";
00385 }
00386 }
00387
00388 return true;
00389 }
00390
00391
00392
00393
00394
00395
00396
00397 bool XFileToEggConverter::
00398 convert_object(XFileDataNode *obj, EggGroupNode *egg_parent) {
00399 if (obj->is_standard_object("Header")) {
00400
00401
00402 } else if (obj->is_standard_object("Frame")) {
00403 if (!convert_frame(obj, egg_parent)) {
00404 return false;
00405 }
00406
00407 } else if (obj->is_standard_object("FrameTransformMatrix")) {
00408 if (!convert_transform(obj, egg_parent)) {
00409 return false;
00410 }
00411
00412 } else if (obj->is_standard_object("Mesh")) {
00413 if (!convert_mesh(obj, egg_parent)) {
00414 return false;
00415 }
00416
00417 } else {
00418 if (xfile_cat.is_debug()) {
00419 xfile_cat.debug()
00420 << "Ignoring object of unknown type: "
00421 << obj->get_template_name() << "\n";
00422 }
00423 }
00424
00425 return true;
00426 }
00427
00428
00429
00430
00431
00432
00433
00434 bool XFileToEggConverter::
00435 convert_frame(XFileDataNode *obj, EggGroupNode *egg_parent) {
00436
00437 string name = obj->get_name();
00438 EggGroup *group = new EggGroup(name);
00439 egg_parent->add_child(group);
00440
00441 if (_make_char) {
00442 group->set_group_type(EggGroup::GT_joint);
00443 if (name.empty()) {
00444
00445 group->set_name("unnamed");
00446
00447 } else {
00448 bool inserted = _joints.insert(Joints::value_type(name, group)).second;
00449 if (!inserted) {
00450 xfile_cat.warning()
00451 << "Nonunique Frame name " << name
00452 << " encountered; animation will be ambiguous.\n";
00453 }
00454 }
00455 }
00456
00457
00458 int num_objects = obj->get_num_objects();
00459 for (int i = 0; i < num_objects; i++) {
00460 if (!convert_object(obj->get_object(i), group)) {
00461 return false;
00462 }
00463 }
00464
00465 return true;
00466 }
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 bool XFileToEggConverter::
00478 convert_transform(XFileDataNode *obj, EggGroupNode *egg_parent) {
00479 LMatrix4d mat = (*obj)["frameMatrix"]["matrix"].mat4();
00480
00481 if (egg_parent->is_of_type(EggGroup::get_class_type())) {
00482 EggGroup *egg_group = DCAST(EggGroup, egg_parent);
00483 egg_group->set_transform3d(mat);
00484
00485 } else {
00486 xfile_cat.error()
00487 << "Transform " << obj->get_name()
00488 << " encountered without frame!\n";
00489 }
00490
00491 return true;
00492 }
00493
00494
00495
00496
00497
00498
00499
00500
00501 bool XFileToEggConverter::
00502 convert_animation_set(XFileDataNode *obj) {
00503 XFileAnimationSet *animation_set = new XFileAnimationSet();
00504 animation_set->set_name(obj->get_name());
00505
00506 _total_tick_deltas = 0;
00507 _num_ticks = 0;
00508
00509
00510
00511 int num_objects = obj->get_num_objects();
00512 for (int i = 0; i < num_objects; i++) {
00513 if (!convert_animation_set_object(obj->get_object(i), *animation_set)) {
00514 return false;
00515 }
00516 }
00517
00518 animation_set->_frame_rate = _frame_rate;
00519 if (_num_ticks != 0 && _frame_rate == 0.0) {
00520
00521 double delta = (double)_total_tick_deltas / (double)_num_ticks;
00522 if (delta != 0.0) {
00523 animation_set->_frame_rate = (double)_ticks_per_second / delta;
00524 }
00525 }
00526
00527 _animation_sets.push_back(animation_set);
00528
00529 return true;
00530 }
00531
00532
00533
00534
00535
00536
00537
00538 bool XFileToEggConverter::
00539 convert_animation_set_object(XFileDataNode *obj,
00540 XFileAnimationSet &animation_set) {
00541 if (obj->is_standard_object("Animation")) {
00542 if (!convert_animation(obj, animation_set)) {
00543 return false;
00544 }
00545
00546 } else {
00547 if (xfile_cat.is_debug()) {
00548 xfile_cat.debug()
00549 << "Ignoring animation set object of unknown type: "
00550 << obj->get_template_name() << "\n";
00551 }
00552 }
00553
00554 return true;
00555 }
00556
00557
00558
00559
00560
00561
00562 bool XFileToEggConverter::
00563 convert_animation(XFileDataNode *obj, XFileAnimationSet &animation_set) {
00564
00565
00566
00567
00568
00569
00570
00571 string frame_name;
00572 bool got_frame_name = false;
00573
00574 int num_objects = obj->get_num_objects();
00575 int i;
00576 for (i = 0; i < num_objects; i++) {
00577 XFileDataNode *child = obj->get_object(i);
00578 if (child->is_reference() && child->is_standard_object("Frame")) {
00579 frame_name = child->get_name();
00580 got_frame_name = true;
00581 }
00582 }
00583
00584 if (!got_frame_name) {
00585 xfile_cat.error()
00586 << "Animation " << obj->get_name()
00587 << " includes no reference to a frame.\n";
00588 return false;
00589 }
00590
00591 FrameData &table = animation_set.create_frame_data(frame_name);
00592
00593
00594 for (i = 0; i < num_objects; i++) {
00595 if (!convert_animation_object(obj->get_object(i), frame_name, table)) {
00596 return false;
00597 }
00598 }
00599
00600 return true;
00601 }
00602
00603
00604
00605
00606
00607
00608
00609 bool XFileToEggConverter::
00610 convert_animation_object(XFileDataNode *obj, const string &joint_name,
00611 XFileToEggConverter::FrameData &table) {
00612 if (obj->is_standard_object("AnimationOptions")) {
00613
00614
00615 } else if (obj->is_standard_object("Frame")) {
00616
00617
00618 } else if (obj->is_standard_object("AnimationKey")) {
00619 if (!convert_animation_key(obj, joint_name, table)) {
00620 return false;
00621 }
00622
00623 } else {
00624 if (xfile_cat.is_debug()) {
00625 xfile_cat.debug()
00626 << "Ignoring animation object of unknown type: "
00627 << obj->get_template_name() << "\n";
00628 }
00629 }
00630
00631 return true;
00632 }
00633
00634
00635
00636
00637
00638
00639 bool XFileToEggConverter::
00640 convert_animation_key(XFileDataNode *obj, const string &joint_name,
00641 XFileToEggConverter::FrameData &table) {
00642 int key_type = (*obj)["keyType"].i();
00643
00644 const XFileDataObject &keys = (*obj)["keys"];
00645
00646 int last_time = 0;
00647 for (int i = 0; i < keys.size(); i++) {
00648
00649
00650
00651
00652
00653
00654
00655 int this_time = keys[i]["time"].i();
00656 if (i != 0) {
00657 int delta = this_time - last_time;
00658 _total_tick_deltas += delta;
00659 ++_num_ticks;
00660 }
00661 last_time = this_time;
00662
00663 const XFileDataObject &values = keys[i]["tfkeys"]["values"];
00664 if (!set_animation_frame(joint_name, table, i, key_type, values)) {
00665 return false;
00666 }
00667 }
00668
00669 return true;
00670 }
00671
00672
00673
00674
00675
00676
00677 bool XFileToEggConverter::
00678 set_animation_frame(const string &joint_name,
00679 XFileToEggConverter::FrameData &table, int frame,
00680 int key_type, const XFileDataObject &values) {
00681 if ((int)table._entries.size() <= frame) {
00682 nassertr((int)table._entries.size() == frame, false);
00683 table._entries.push_back(XFileAnimationSet::FrameEntry());
00684 }
00685
00686 XFileAnimationSet::FrameEntry &frame_entry = table._entries[frame];
00687
00688
00689 switch (key_type) {
00690 case 0:
00691
00692
00693
00694 if (values.size() != 4) {
00695 xfile_cat.error()
00696 << "Incorrect number of values in animation table: "
00697 << values.size() << " for rotation data.\n";
00698 return false;
00699 }
00700 frame_entry._rot.invert_from(LQuaterniond(values.vec4()));
00701 table._flags |= XFileAnimationSet::FDF_rot;
00702 break;
00703
00704 case 1:
00705 if (values.size() != 3) {
00706 xfile_cat.error()
00707 << "Incorrect number of values in animation table: "
00708 << values.size() << " for scale data.\n";
00709 return false;
00710 }
00711 frame_entry._scale = values.vec3();
00712 table._flags |= XFileAnimationSet::FDF_scale;
00713 break;
00714
00715 case 2:
00716
00717 if (values.size() != 3) {
00718 xfile_cat.error()
00719 << "Incorrect number of values in animation table: "
00720 << values.size() << " for position data.\n";
00721 return false;
00722 }
00723 frame_entry._trans = values.vec3();
00724 table._flags |= XFileAnimationSet::FDF_trans;
00725 break;
00726
00727
00728
00729
00730
00731
00732
00733 case 4:
00734
00735 if (values.size() != 16) {
00736 xfile_cat.error()
00737 << "Incorrect number of values in animation table: "
00738 << values.size() << " for matrix data.\n";
00739 return false;
00740 }
00741 frame_entry._mat = values.mat4();
00742 table._flags |= XFileAnimationSet::FDF_mat;
00743 break;
00744
00745 default:
00746 xfile_cat.error()
00747 << "Unsupported key type " << key_type << " in animation table.\n";
00748 return false;
00749 }
00750
00751 return true;
00752 }
00753
00754
00755
00756
00757
00758
00759
00760 bool XFileToEggConverter::
00761 convert_mesh(XFileDataNode *obj, EggGroupNode *egg_parent) {
00762 XFileMesh *mesh = new XFileMesh(_egg_data->get_coordinate_system());
00763 mesh->set_name(obj->get_name());
00764 mesh->set_egg_parent(egg_parent);
00765
00766 if (!mesh->fill_mesh(obj)) {
00767 delete mesh;
00768 return false;
00769 }
00770
00771 _meshes.push_back(mesh);
00772
00773 return true;
00774 }
00775
00776
00777
00778
00779
00780
00781
00782 bool XFileToEggConverter::
00783 create_polygons() {
00784 bool okflag = true;
00785
00786 Meshes::const_iterator mi;
00787 for (mi = _meshes.begin(); mi != _meshes.end(); ++mi) {
00788 if (!(*mi)->create_polygons(this)) {
00789 okflag = false;
00790 }
00791 delete (*mi);
00792 }
00793 _meshes.clear();
00794
00795 return okflag;
00796 }
00797
00798
00799
00800
00801
00802
00803
00804 bool XFileToEggConverter::
00805 create_hierarchy() {
00806 bool okflag = true;
00807
00808 AnimationSets::const_iterator asi;
00809 for (asi = _animation_sets.begin(); asi != _animation_sets.end(); ++asi) {
00810 if (_make_char) {
00811 if (!(*asi)->create_hierarchy(this)) {
00812 okflag = false;
00813 }
00814 }
00815 delete (*asi);
00816 }
00817 _animation_sets.clear();
00818
00819 return okflag;
00820 }