Panda3D
xFileToEggConverter.cxx
1 // Filename: xFileToEggConverter.cxx
2 // Created by: drose (21Jun01)
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 #include "xFileToEggConverter.h"
16 #include "xFileMesh.h"
17 #include "xFileMaterial.h"
18 #include "xFileAnimationSet.h"
19 #include "config_xfile.h"
20 
21 #include "eggData.h"
22 #include "eggGroup.h"
23 #include "eggXfmSAnim.h"
24 #include "eggGroupUniquifier.h"
25 #include "datagram.h"
26 #include "eggMaterialCollection.h"
27 #include "eggTextureCollection.h"
28 #include "dcast.h"
29 
30 ////////////////////////////////////////////////////////////////////
31 // Function: XFileToEggConverter::Constructor
32 // Access: Public
33 // Description:
34 ////////////////////////////////////////////////////////////////////
35 XFileToEggConverter::
36 XFileToEggConverter() {
37  _make_char = false;
38  _frame_rate = 0.0;
39  _x_file = new XFile(true);
40  _dart_node = NULL;
41 }
42 
43 ////////////////////////////////////////////////////////////////////
44 // Function: XFileToEggConverter::Copy Constructor
45 // Access: Public
46 // Description:
47 ////////////////////////////////////////////////////////////////////
48 XFileToEggConverter::
49 XFileToEggConverter(const XFileToEggConverter &copy) :
51  _make_char(copy._make_char)
52 {
53  _x_file = new XFile(true);
54  _dart_node = NULL;
55 }
56 
57 ////////////////////////////////////////////////////////////////////
58 // Function: XFileToEggConverter::Destructor
59 // Access: Public
60 // Description:
61 ////////////////////////////////////////////////////////////////////
62 XFileToEggConverter::
63 ~XFileToEggConverter() {
64  close();
65 }
66 
67 ////////////////////////////////////////////////////////////////////
68 // Function: XFileToEggConverter::make_copy
69 // Access: Public, Virtual
70 // Description: Allocates and returns a new copy of the converter.
71 ////////////////////////////////////////////////////////////////////
74  return new XFileToEggConverter(*this);
75 }
76 
77 
78 ////////////////////////////////////////////////////////////////////
79 // Function: XFileToEggConverter::get_name
80 // Access: Public, Virtual
81 // Description: Returns the English name of the file type this
82 // converter supports.
83 ////////////////////////////////////////////////////////////////////
85 get_name() const {
86  return "DirectX";
87 }
88 
89 ////////////////////////////////////////////////////////////////////
90 // Function: XFileToEggConverter::get_extension
91 // Access: Public, Virtual
92 // Description: Returns the common extension of the file type this
93 // converter supports.
94 ////////////////////////////////////////////////////////////////////
96 get_extension() const {
97  return "x";
98 }
99 
100 ////////////////////////////////////////////////////////////////////
101 // Function: XFileToEggConverter::supports_compressed
102 // Access: Published, Virtual
103 // Description: Returns true if this file type can transparently load
104 // compressed files (with a .pz extension), false
105 // otherwise.
106 ////////////////////////////////////////////////////////////////////
109  return true;
110 }
111 
112 ////////////////////////////////////////////////////////////////////
113 // Function: XFileToEggConverter::convert_file
114 // Access: Public, Virtual
115 // Description: Handles the reading of the input file and converting
116 // it to egg. Returns true if successful, false
117 // otherwise.
118 //
119 // This is designed to be as generic as possible,
120 // generally in support of run-time loading.
121 // Command-line converters may choose to use
122 // convert_flt() instead, as it provides more control.
123 ////////////////////////////////////////////////////////////////////
125 convert_file(const Filename &filename) {
126  close();
127  clear_error();
128 
129  if (!_x_file->read(filename)) {
130  nout << "Unable to open X file: " << filename << "\n";
131  return false;
132  }
133 
134  if (_char_name.empty()) {
135  _char_name = filename.get_basename_wo_extension();
136  }
137 
138  if (_egg_data->get_coordinate_system() == CS_default) {
139  _egg_data->set_coordinate_system(CS_yup_left);
140  }
141 
142  if (!get_toplevel()) {
143  return false;
144  }
145 
146  if (!create_polygons()) {
147  return false;
148  }
149 
150  if (_make_char) {
151  // Now make sure that each joint has a unique name.
152  EggGroupUniquifier uniquifier(false);
153  uniquifier.uniquify(_dart_node);
154  }
155 
156  if (!create_hierarchy()) {
157  return false;
158  }
159 
160  if (_keep_model && !_keep_animation) {
161  strip_nodes(EggTable::get_class_type());
162  }
163 
164  if (_keep_animation && !_keep_model) {
165  strip_nodes(EggGroup::get_class_type());
166  }
167 
168  return !had_error();
169 }
170 
171 ////////////////////////////////////////////////////////////////////
172 // Function: XFileToEggConverter::close
173 // Access: Public
174 // Description: Finalizes and closes the file previously opened via
175 // convert_file().
176 ////////////////////////////////////////////////////////////////////
178 close() {
179  _x_file->clear();
180 
181  // Clean up all the other stuff.
182  Meshes::const_iterator mi;
183  for (mi = _meshes.begin(); mi != _meshes.end(); ++mi) {
184  delete (*mi);
185  }
186  _meshes.clear();
187 
188  AnimationSets::const_iterator asi;
189  for (asi = _animation_sets.begin(); asi != _animation_sets.end(); ++asi) {
190  delete (*asi);
191  }
192  _animation_sets.clear();
193 
194  _joints.clear();
195 }
196 
197 ////////////////////////////////////////////////////////////////////
198 // Function: XFileToEggConverter::strip_nodes
199 // Access: Public
200 // Description: Removes all groups of the given type. This is used
201 // to implement the -anim and -model options.
202 ////////////////////////////////////////////////////////////////////
205  pvector <EggNode *> garbage;
206  EggGroupNode::iterator i;
207  for (i=_egg_data->begin(); i!=_egg_data->end(); ++i) {
208  EggNode *node = (*i);
209  if (node->is_of_type(t)) {
210  garbage.push_back(node);
211  }
212  }
213  for (int n=0; n<(int)garbage.size(); n++) {
214  _egg_data->remove_child(garbage[n]);
215  }
216 }
217 
218 ////////////////////////////////////////////////////////////////////
219 // Function: XFileToEggConverter::get_dart_node
220 // Access: Public
221 // Description: Returns the root of the joint hierarchy, if
222 // _make_char is true, or NULL otherwise.
223 ////////////////////////////////////////////////////////////////////
225 get_dart_node() const {
226  return _dart_node;
227 }
228 
229 ////////////////////////////////////////////////////////////////////
230 // Function: XFileToEggConverter::create_unique_texture
231 // Access: Public
232 // Description: Returns an EggTexture pointer whose properties match
233 // that of the the given EggTexture, except for the tref
234 // name.
235 ////////////////////////////////////////////////////////////////////
238  return _textures.create_unique_texture(copy, ~EggTexture::E_tref_name);
239 }
240 
241 ////////////////////////////////////////////////////////////////////
242 // Function: XFileToEggConverter::create_unique_material
243 // Access: Public
244 // Description: Returns an EggMaterial pointer whose properties match
245 // that of the the given EggMaterial, except for the mref
246 // name.
247 ////////////////////////////////////////////////////////////////////
250  return _materials.create_unique_material(copy, ~EggMaterial::E_mref_name);
251 }
252 
253 ////////////////////////////////////////////////////////////////////
254 // Function: XFileToEggConverter::find_joint
255 // Access: Public
256 // Description: This is called by set_animation_frame, for
257 // the purposes of building the frame data for the
258 // animation--it needs to know the original rest frame
259 // transform.
260 ////////////////////////////////////////////////////////////////////
262 find_joint(const string &joint_name) {
263  Joints::iterator ji;
264  ji = _joints.find(joint_name);
265  if (ji != _joints.end()) {
266  EggGroup *joint = (*ji).second;
267  if (joint == (EggGroup *)NULL) {
268  // An invalid joint detected earlier.
269  return NULL;
270  }
271 
272  return joint;
273  }
274 
275  // Joint name is unknown. Issue a warning, then insert NULL into
276  // the table so we don't get the same warning again with the next
277  // polygon.
278  if (_make_char) {
279  xfile_cat.warning()
280  << "Joint name " << joint_name << " in animation data is undefined.\n";
281  }
282  _joints[joint_name] = NULL;
283 
284  return NULL;
285 }
286 
287 ////////////////////////////////////////////////////////////////////
288 // Function: XFileToEggConverter::get_toplevel
289 // Access: Private
290 // Description: Pulls off all of the top-level objects in the .x file
291 // and converts them, and their descendents, to the
292 // appropriate egg structures.
293 ////////////////////////////////////////////////////////////////////
294 bool XFileToEggConverter::
295 get_toplevel() {
296  int num_objects = _x_file->get_num_objects();
297  int i;
298 
299  _ticks_per_second = 4800; // X File default.
300 
301  // First, make a pass through the toplevel objects and see if we
302  // have frames and/or animation.
303  _any_frames = false;
304  _any_animation = false;
305  for (i = 0; i < num_objects; i++) {
306  XFileDataNode *child = _x_file->get_object(i);
307  if (child->is_standard_object("Frame")) {
308  _any_frames = true;
309  } else if (child->is_standard_object("AnimationSet")) {
310  _any_animation = true;
311  }
312  }
313 
314  // If we have animation, assume we want to convert it as a character.
315  if (_any_animation) {
316  _make_char = true;
317  }
318 
319  EggGroupNode *egg_parent = _egg_data;
320 
321  // If we are converting an animatable model, make an extra node to
322  // represent the root of the hierarchy.
323  if (_make_char) {
324  _dart_node = new EggGroup(_char_name);
325  egg_parent->add_child(_dart_node);
326  _dart_node->set_dart_type(EggGroup::DT_default);
327  egg_parent = _dart_node;
328  }
329 
330  // Now go back through and convert the objects.
331  for (i = 0; i < num_objects; i++) {
332  if (!convert_toplevel_object(_x_file->get_object(i), egg_parent)) {
333  return false;
334  }
335  }
336 
337  return true;
338 }
339 
340 ////////////////////////////////////////////////////////////////////
341 // Function: XFileToEggConverter::convert_toplevel_object
342 // Access: Private
343 // Description: Converts the indicated object, encountered outside of
344 // any Frames, to the appropriate egg structures.
345 ////////////////////////////////////////////////////////////////////
346 bool XFileToEggConverter::
347 convert_toplevel_object(XFileDataNode *obj, EggGroupNode *egg_parent) {
348  if (obj->is_standard_object("Header")) {
349  // Quietly ignore headers.
350 
351  } else if (obj->is_standard_object("Material")) {
352  // Quietly ignore toplevel materials. These will presumably be
353  // referenced below.
354 
355  } else if (obj->is_standard_object("Frame")) {
356  if (!convert_frame(obj, egg_parent)) {
357  return false;
358  }
359 
360  } else if (obj->is_standard_object("AnimationSet")) {
361  if (!convert_animation_set(obj)) {
362  return false;
363  }
364 
365  } else if (obj->is_standard_object("AnimTicksPerSecond")) {
366  _ticks_per_second = (*obj)[0].i();
367 
368  } else if (obj->is_standard_object("Mesh")) {
369  // If there are any Frames at all in the file, then assume a Mesh
370  // at the toplevel is just present to define a reference that will
371  // be included below--so we ignore it here. On the other hand, if
372  // the file has no Frames, then a Mesh at the toplevel must be
373  // actual geometry, so convert it now.
374  if (!_any_frames) {
375  if (!convert_mesh(obj, egg_parent)) {
376  return false;
377  }
378  }
379 
380  } else {
381  if (xfile_cat.is_debug()) {
382  xfile_cat.debug()
383  << "Ignoring toplevel object of unknown type: "
384  << obj->get_template_name() << "\n";
385  }
386  }
387 
388  return true;
389 }
390 
391 ////////////////////////////////////////////////////////////////////
392 // Function: XFileToEggConverter::convert_object
393 // Access: Private
394 // Description: Converts the indicated object to the appropriate egg
395 // structures.
396 ////////////////////////////////////////////////////////////////////
397 bool XFileToEggConverter::
398 convert_object(XFileDataNode *obj, EggGroupNode *egg_parent) {
399  if (obj->is_standard_object("Header")) {
400  // Quietly ignore headers.
401 
402  } else if (obj->is_standard_object("Frame")) {
403  if (!convert_frame(obj, egg_parent)) {
404  return false;
405  }
406 
407  } else if (obj->is_standard_object("FrameTransformMatrix")) {
408  if (!convert_transform(obj, egg_parent)) {
409  return false;
410  }
411 
412  } else if (obj->is_standard_object("Mesh")) {
413  if (!convert_mesh(obj, egg_parent)) {
414  return false;
415  }
416 
417  } else {
418  if (xfile_cat.is_debug()) {
419  xfile_cat.debug()
420  << "Ignoring object of unknown type: "
421  << obj->get_template_name() << "\n";
422  }
423  }
424 
425  return true;
426 }
427 
428 ////////////////////////////////////////////////////////////////////
429 // Function: XFileToEggConverter::convert_frame
430 // Access: Private
431 // Description: Converts the indicated frame to the appropriate egg
432 // structures.
433 ////////////////////////////////////////////////////////////////////
434 bool XFileToEggConverter::
435 convert_frame(XFileDataNode *obj, EggGroupNode *egg_parent) {
436 
437  string name = obj->get_name();
438  EggGroup *group = new EggGroup(name);
439  egg_parent->add_child(group);
440 
441  if (_make_char) {
442  group->set_group_type(EggGroup::GT_joint);
443  if (name.empty()) {
444  // Make up a name for this unnamed joint.
445  group->set_name("unnamed");
446 
447  } else {
448  bool inserted = _joints.insert(Joints::value_type(name, group)).second;
449  if (!inserted) {
450  xfile_cat.warning()
451  << "Nonunique Frame name " << name
452  << " encountered; animation will be ambiguous.\n";
453  }
454  }
455  }
456 
457  // Now walk through the children of the frame.
458  int num_objects = obj->get_num_objects();
459  for (int i = 0; i < num_objects; i++) {
460  if (!convert_object(obj->get_object(i), group)) {
461  return false;
462  }
463  }
464 
465  return true;
466 }
467 
468 ////////////////////////////////////////////////////////////////////
469 // Function: XFileToEggConverter::convert_transform
470 // Access: Private
471 // Description: Reads a transform matrix, a child of a given frame,
472 // and applies it to the node. Normally this can only
473 // be done if the node in question is an EggGroup, which
474 // should be the case if the transform was a child of a
475 // frame.
476 ////////////////////////////////////////////////////////////////////
477 bool XFileToEggConverter::
478 convert_transform(XFileDataNode *obj, EggGroupNode *egg_parent) {
479  LMatrix4d mat = (*obj)["frameMatrix"]["matrix"].mat4();
480 
481  if (egg_parent->is_of_type(EggGroup::get_class_type())) {
482  EggGroup *egg_group = DCAST(EggGroup, egg_parent);
483  egg_group->set_transform3d(mat);
484 
485  } else {
486  xfile_cat.error()
487  << "Transform " << obj->get_name()
488  << " encountered without frame!\n";
489  }
490 
491  return true;
492 }
493 
494 ////////////////////////////////////////////////////////////////////
495 // Function: XFileToEggConverter::convert_animation_set
496 // Access: Private
497 // Description: Begins an AnimationSet. This is the root of one
498 // particular animation (table of frames per joint) to
499 // be applied to the model within this file.
500 ////////////////////////////////////////////////////////////////////
501 bool XFileToEggConverter::
502 convert_animation_set(XFileDataNode *obj) {
503  XFileAnimationSet *animation_set = new XFileAnimationSet();
504  animation_set->set_name(obj->get_name());
505 
506  _total_tick_deltas = 0;
507  _num_ticks = 0;
508 
509  // Now walk through the children of the set; each one animates a
510  // different joint.
511  int num_objects = obj->get_num_objects();
512  for (int i = 0; i < num_objects; i++) {
513  if (!convert_animation_set_object(obj->get_object(i), *animation_set)) {
514  return false;
515  }
516  }
517 
518  animation_set->_frame_rate = _frame_rate;
519  if (_num_ticks != 0 && _frame_rate == 0.0) {
520  // Compute the frame rate from the timing information.
521  double delta = (double)_total_tick_deltas / (double)_num_ticks;
522  if (delta != 0.0) {
523  animation_set->_frame_rate = (double)_ticks_per_second / delta;
524  }
525  }
526 
527  _animation_sets.push_back(animation_set);
528 
529  return true;
530 }
531 
532 ////////////////////////////////////////////////////////////////////
533 // Function: XFileToEggConverter::convert_animation_set_object
534 // Access: Private
535 // Description: Converts the indicated object, a child of a
536 // AnimationSet.
537 ////////////////////////////////////////////////////////////////////
538 bool XFileToEggConverter::
539 convert_animation_set_object(XFileDataNode *obj,
540  XFileAnimationSet &animation_set) {
541  if (obj->is_standard_object("Animation")) {
542  if (!convert_animation(obj, animation_set)) {
543  return false;
544  }
545 
546  } else {
547  if (xfile_cat.is_debug()) {
548  xfile_cat.debug()
549  << "Ignoring animation set object of unknown type: "
550  << obj->get_template_name() << "\n";
551  }
552  }
553 
554  return true;
555 }
556 
557 ////////////////////////////////////////////////////////////////////
558 // Function: XFileToEggConverter::convert_animation
559 // Access: Private
560 // Description: Converts the indicated Animation template object.
561 ////////////////////////////////////////////////////////////////////
562 bool XFileToEggConverter::
563 convert_animation(XFileDataNode *obj, XFileAnimationSet &animation_set) {
564  // Within an Animation template, we expect to find a reference to a
565  // frame, possibly an AnimationOptions object, and one or more
566  // AnimationKey objects.
567 
568  // First, walk through the list of children, to find the one that is
569  // the frame reference. We need to know this up front so we know
570  // which table we should be building up.
571  string frame_name;
572  bool got_frame_name = false;
573 
574  int num_objects = obj->get_num_objects();
575  int i;
576  for (i = 0; i < num_objects; i++) {
577  XFileDataNode *child = obj->get_object(i);
578  if (child->is_reference() && child->is_standard_object("Frame")) {
579  frame_name = child->get_name();
580  got_frame_name = true;
581  }
582  }
583 
584  if (!got_frame_name) {
585  xfile_cat.error()
586  << "Animation " << obj->get_name()
587  << " includes no reference to a frame.\n";
588  return false;
589  }
590 
591  FrameData &table = animation_set.create_frame_data(frame_name);
592 
593  // Now go back again and get the actual data.
594  for (i = 0; i < num_objects; i++) {
595  if (!convert_animation_object(obj->get_object(i), frame_name, table)) {
596  return false;
597  }
598  }
599 
600  return true;
601 }
602 
603 ////////////////////////////////////////////////////////////////////
604 // Function: XFileToEggConverter::convert_animation_object
605 // Access: Private
606 // Description: Converts the indicated object, a child of a
607 // Animation.
608 ////////////////////////////////////////////////////////////////////
609 bool XFileToEggConverter::
610 convert_animation_object(XFileDataNode *obj, const string &joint_name,
612  if (obj->is_standard_object("AnimationOptions")) {
613  // Quietly ignore AnimationOptions.
614 
615  } else if (obj->is_standard_object("Frame")) {
616  // Quietly ignore frames, since we already got the frame name.
617 
618  } else if (obj->is_standard_object("AnimationKey")) {
619  if (!convert_animation_key(obj, joint_name, table)) {
620  return false;
621  }
622 
623  } else {
624  if (xfile_cat.is_debug()) {
625  xfile_cat.debug()
626  << "Ignoring animation object of unknown type: "
627  << obj->get_template_name() << "\n";
628  }
629  }
630 
631  return true;
632 }
633 
634 ////////////////////////////////////////////////////////////////////
635 // Function: XFileToEggConverter::convert_animation_key
636 // Access: Private
637 // Description: Converts the indicated AnimationKey template object.
638 ////////////////////////////////////////////////////////////////////
639 bool XFileToEggConverter::
640 convert_animation_key(XFileDataNode *obj, const string &joint_name,
642  int key_type = (*obj)["keyType"].i();
643 
644  const XFileDataObject &keys = (*obj)["keys"];
645 
646  int last_time = 0;
647  for (int i = 0; i < keys.size(); i++) {
648  // The time value is problematic, since it allows x files to
649  // specify keyframes of arbitrary duration. Panda doesn't support
650  // this; all frames in Panda must be of a constant duration.
651  // Thus, we largely ignore the time value, but we take the average
652  // of all deltas as the duration. This will correctly handle .x
653  // files with uniform keyframes, at least.
654 
655  int this_time = keys[i]["time"].i();
656  if (i != 0) {
657  int delta = this_time - last_time;
658  _total_tick_deltas += delta;
659  ++_num_ticks;
660  }
661  last_time = this_time;
662 
663  const XFileDataObject &values = keys[i]["tfkeys"]["values"];
664  if (!set_animation_frame(joint_name, table, i, key_type, values)) {
665  return false;
666  }
667  }
668 
669  return true;
670 }
671 
672 ////////////////////////////////////////////////////////////////////
673 // Function: XFileToEggConverter::set_animation_frame
674 // Access: Private
675 // Description: Sets a single frame of the animation data.
676 ////////////////////////////////////////////////////////////////////
677 bool XFileToEggConverter::
678 set_animation_frame(const string &joint_name,
679  XFileToEggConverter::FrameData &table, int frame,
680  int key_type, const XFileDataObject &values) {
681  if ((int)table._entries.size() <= frame) {
682  nassertr((int)table._entries.size() == frame, false);
683  table._entries.push_back(XFileAnimationSet::FrameEntry());
684  }
685 
686  XFileAnimationSet::FrameEntry &frame_entry = table._entries[frame];
687 
688  // Now modify the last row in the table.
689  switch (key_type) {
690  case 0:
691  // Key type 0: rotation.
692  // This appears to be a quaternion. Hope we get the coordinate
693  // system right.
694  if (values.size() != 4) {
695  xfile_cat.error()
696  << "Incorrect number of values in animation table: "
697  << values.size() << " for rotation data.\n";
698  return false;
699  }
700  frame_entry._rot.invert_from(LQuaterniond(values.vec4()));
701  table._flags |= XFileAnimationSet::FDF_rot;
702  break;
703 
704  case 1:
705  if (values.size() != 3) {
706  xfile_cat.error()
707  << "Incorrect number of values in animation table: "
708  << values.size() << " for scale data.\n";
709  return false;
710  }
711  frame_entry._scale = values.vec3();
712  table._flags |= XFileAnimationSet::FDF_scale;
713  break;
714 
715  case 2:
716  // Key type 2: position
717  if (values.size() != 3) {
718  xfile_cat.error()
719  << "Incorrect number of values in animation table: "
720  << values.size() << " for position data.\n";
721  return false;
722  }
723  frame_entry._trans = values.vec3();
724  table._flags |= XFileAnimationSet::FDF_trans;
725  break;
726 
727  /*
728  case 3:
729  // Key type 3: ????
730  break;
731  */
732 
733  case 4:
734  // Key type 4: full matrix
735  if (values.size() != 16) {
736  xfile_cat.error()
737  << "Incorrect number of values in animation table: "
738  << values.size() << " for matrix data.\n";
739  return false;
740  }
741  frame_entry._mat = values.mat4();
742  table._flags |= XFileAnimationSet::FDF_mat;
743  break;
744 
745  default:
746  xfile_cat.error()
747  << "Unsupported key type " << key_type << " in animation table.\n";
748  return false;
749  }
750 
751  return true;
752 }
753 
754 ////////////////////////////////////////////////////////////////////
755 // Function: XFileToEggConverter::convert_mesh
756 // Access: Private
757 // Description: Converts the indicated mesh to the appropriate egg
758 // structures.
759 ////////////////////////////////////////////////////////////////////
760 bool XFileToEggConverter::
761 convert_mesh(XFileDataNode *obj, EggGroupNode *egg_parent) {
762  XFileMesh *mesh = new XFileMesh(_egg_data->get_coordinate_system());
763  mesh->set_name(obj->get_name());
764  mesh->set_egg_parent(egg_parent);
765 
766  if (!mesh->fill_mesh(obj)) {
767  delete mesh;
768  return false;
769  }
770 
771  _meshes.push_back(mesh);
772 
773  return true;
774 }
775 
776 ////////////////////////////////////////////////////////////////////
777 // Function: XFileToEggConverter::create_polygons
778 // Access: Private
779 // Description: Creates all the polygons associated with
780 // previously-saved meshes.
781 ////////////////////////////////////////////////////////////////////
782 bool XFileToEggConverter::
783 create_polygons() {
784  bool okflag = true;
785 
786  Meshes::const_iterator mi;
787  for (mi = _meshes.begin(); mi != _meshes.end(); ++mi) {
788  if (!(*mi)->create_polygons(this)) {
789  okflag = false;
790  }
791  delete (*mi);
792  }
793  _meshes.clear();
794 
795  return okflag;
796 }
797 
798 ////////////////////////////////////////////////////////////////////
799 // Function: XFileToEggConverter::create_hierarchy
800 // Access: Private
801 // Description: Creates the animation table hierarchies for the
802 // previously-saved animation sets.
803 ////////////////////////////////////////////////////////////////////
804 bool XFileToEggConverter::
805 create_hierarchy() {
806  bool okflag = true;
807 
808  AnimationSets::const_iterator asi;
809  for (asi = _animation_sets.begin(); asi != _animation_sets.end(); ++asi) {
810  if (_make_char) {
811  if (!(*asi)->create_hierarchy(this)) {
812  okflag = false;
813  }
814  }
815  delete (*asi);
816  }
817  _animation_sets.clear();
818 
819  return okflag;
820 }
EggGroup * get_dart_node() const
Returns the root of the joint hierarchy, if _make_char is true, or NULL otherwise.
EggGroup * find_joint(const string &joint_name)
This is called by set_animation_frame, for the purposes of building the frame data for the animationâ€...
bool fill_mesh(XFileDataNode *obj)
Fills the structure based on the raw data from the X file&#39;s Mesh object.
Definition: xFileMesh.cxx:675
EggTexture * create_unique_texture(const EggTexture &copy, int eq)
Creates a new texture if there is not already one equivalent (according to eq, see EggTexture::is_equ...
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:4716
void close()
Finalizes and closes the file previously opened via convert_file().
FrameData & create_frame_data(const string &joint_name)
Returns a reference to a new FrameData table corresponding to the indicated joint.
bool had_error() const
Returns true if an error was detected during the conversion process (unless _allow_errors is true)...
This is a collection of polygons; i.e.
Definition: xFileMesh.h:45
virtual bool supports_compressed() const
Returns true if this file type can transparently load compressed files (with a .pz extension)...
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
int i() const
Unambiguously returns the object&#39;s representation as an integer, or 0 if the object has no integer re...
This is the base quaternion class.
Definition: lquaternion.h:974
Defines a texture map that may be applied to geometry.
Definition: eggTexture.h:33
This is a specialization of EggNameUniquifier to generate unique names for EggGroup nodes...
virtual string get_name() const
Returns the English name of the file type this converter supports.
This represents a tree of EggTables, corresponding to Animation entries in the X file.
EggMaterial * create_unique_material(const EggMaterial &copy)
Returns an EggMaterial pointer whose properties match that of the the given EggMaterial, except for the mref name.
int get_num_objects() const
Returns the list of child objects of this node.
Definition: xFileNode.I:58
const string & get_template_name() const
A convenience function to return the name of the template used to define this data object...
Definition: xFileDataNode.I:53
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:36
void clear_error()
Resets the error flag to the no-error state.
void set_transform3d(const LMatrix4d &mat)
Sets the overall transform as a 4x4 matrix.
Definition: eggTransform.I:222
void strip_nodes(TypeHandle t)
Removes all groups of the given type.
virtual bool convert_file(const Filename &filename)
Handles the reading of the input file and converting it to egg.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
void set_egg_parent(EggGroupNode *egg_parent)
Specifies the egg node that will eventually be the parent of this mesh, when create_polygons() is lat...
Definition: xFileMesh.cxx:276
virtual string get_extension() const
Returns the common extension of the file type this converter supports.
LVecBase4d vec4() const
Returns the object&#39;s representation as an LVecBase4d.
void uniquify(EggNode *node)
Begins the traversal from the indicated node.
virtual bool is_reference() const
Returns true if this node represents an indirect reference to an object defined previously in the fil...
Definition: xFileNode.cxx:185
string get_basename_wo_extension() const
Returns the basename part of the filename, without the file extension.
Definition: filename.I:460
int size() const
Returns the number of nested data objects within this object.
bool invert_from(const LQuaterniond &other)
Computes the inverse of the other quat, and stores the result in this quat.
Definition: lquaternion.h:1682
virtual bool is_standard_object(const string &template_name) const
Returns true if this node represents an instance of the standard template with the indicated name...
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
LMatrix4d mat4() const
Returns the object&#39;s representation as an LMatrix4d.
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:38
This is an abstract base class for an XFileNode which is also an XFileDataObject. ...
Definition: xFileDataNode.h:36
EggMaterial * create_unique_material(const EggMaterial &copy, int eq)
Creates a new material if there is not already one equivalent (according to eq, see EggMaterial::is_e...
This represents the complete contents of an X file (file.x) in memory.
Definition: xFile.h:35
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
EggTexture * create_unique_texture(const EggTexture &copy)
Returns an EggTexture pointer whose properties match that of the the given EggTexture, except for the tref name.
XFileDataNode * get_object(int n) const
Returns the nth child object of this node.
Definition: xFileNode.I:71
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
LVecBase3d vec3() const
Returns the object&#39;s representation as an LVecBase3d.
This is a base class for a family of converter classes that manage a conversion from some file type t...
The abstract base class for a number of different types of data elements that may be stored in the X ...
virtual SomethingToEggConverter * make_copy()
Allocates and returns a new copy of the converter.