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