Panda3D
characterMaker.cxx
1 // Filename: characterMaker.cxx
2 // Created by: drose (06Mar02)
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 "characterMaker.h"
16 #include "eggLoader.h"
17 #include "config_egg2pg.h"
18 #include "eggBinner.h"
19 #include "eggGroup.h"
20 #include "eggPrimitive.h"
21 #include "eggBin.h"
22 #include "partGroup.h"
23 #include "characterJoint.h"
24 #include "characterJointBundle.h"
25 #include "characterSlider.h"
26 #include "character.h"
27 #include "geomNode.h"
28 #include "transformState.h"
29 #include "eggSurface.h"
30 #include "eggCurve.h"
31 #include "modelNode.h"
32 #include "characterVertexSlider.h"
33 #include "jointVertexTransform.h"
34 #include "userVertexTransform.h"
35 #include "eggAnimPreload.h"
36 #include "animPreloadTable.h"
37 
38 
39 
40 
41 
42 ////////////////////////////////////////////////////////////////////
43 // Function: CharacterMaker::Construtor
44 // Access: Public
45 // Description:
46 ////////////////////////////////////////////////////////////////////
47 CharacterMaker::
48 CharacterMaker(EggGroup *root, EggLoader &loader, bool structured)
49  : _loader(loader), _egg_root(root) {
50 
51  _character_node = new Character(_egg_root->get_name());
52  _bundle = _character_node->get_bundle(0);
53 
54  _morph_root = (PartGroup *)NULL;
55  _skeleton_root = new PartGroup(_bundle, "<skeleton>");
56  _structured = structured;
57 }
58 
59 ////////////////////////////////////////////////////////////////////
60 // Function: CharacterMaker::make_node
61 // Access: Public
62 // Description:
63 ////////////////////////////////////////////////////////////////////
64 Character *CharacterMaker::
65 make_node() {
66  make_bundle();
67  return _character_node;
68 }
69 
70 ////////////////////////////////////////////////////////////////////
71 // Function: CharacterMaker::get_name
72 // Access: Public
73 // Description: Returns the name of the character.
74 ////////////////////////////////////////////////////////////////////
75 string CharacterMaker::
76 get_name() const {
77  return _egg_root->get_name();
78 }
79 
80 ////////////////////////////////////////////////////////////////////
81 // Function: CharacterMaker::egg_to_part
82 // Access: Public
83 // Description: Returns the PartGroup node associated with the given
84 // egg node. If the egg node is not a node in the
85 // character's hierarchy, returns the top of the
86 // character's hierarchy.
87 ////////////////////////////////////////////////////////////////////
89 egg_to_part(EggNode *egg_node) const {
90  int index = egg_to_index(egg_node);
91  if (index < 0) {
92  // If there's a reference to the geometry outside of the
93  // character, just return the root of the character.
94  return _bundle;
95  }
96  nassertr(index < (int)_parts.size(), NULL);
97  return _parts[index];
98 }
99 
100 ////////////////////////////////////////////////////////////////////
101 // Function: CharacterMaker::egg_to_transform
102 // Access: Public
103 // Description: Returns a JointVertexTransform suitable for
104 // applying the animation associated with the given
105 // egg node (which should be a joint). Returns an
106 // identity transform if the egg node is not a joint in
107 // the character's hierarchy.
108 ////////////////////////////////////////////////////////////////////
111  int index = egg_to_index(egg_node);
112  if (index < 0) {
113  // Not a joint in the hierarchy.
114  return get_identity_transform();
115  }
116 
117  VertexTransforms::iterator vi = _vertex_transforms.find(index);
118  if (vi != _vertex_transforms.end()) {
119  return (*vi).second;
120  }
121 
122  PartGroup *part = _parts[index];
123  CharacterJoint *joint;
124  DCAST_INTO_R(joint, part, get_identity_transform());
125 
126  PT(VertexTransform) vt = new JointVertexTransform(joint);
127  _vertex_transforms[index] = vt;
128 
129  return vt;
130 }
131 
132 ////////////////////////////////////////////////////////////////////
133 // Function: CharacterMaker::egg_to_index
134 // Access: Public
135 // Description: Returns the index number associated with the
136 // PartGroup node for the given egg node, or -1.
137 ////////////////////////////////////////////////////////////////////
139 egg_to_index(EggNode *egg_node) const {
140  NodeMap::const_iterator nmi = _node_map.find(egg_node);
141  if (nmi == _node_map.end()) {
142  return -1;
143  }
144  return (*nmi).second;
145 }
146 
147 ////////////////////////////////////////////////////////////////////
148 // Function: CharacterMaker::part_to_node
149 // Access: Public
150 // Description: Returns the scene graph node associated with the
151 // given PartGroup node, if there is one. If the
152 // PartGroup does not have an associated node, returns
153 // the character's top node.
154 ////////////////////////////////////////////////////////////////////
156 part_to_node(PartGroup *part, const string &name) const {
157  PandaNode *node = _character_node;
158 
159  if (part->is_of_type(CharacterJoint::get_class_type())) {
160  CharacterJoint *joint = DCAST(CharacterJoint, part);
161  if (joint->_geom_node != (PandaNode *)NULL) {
162  node = joint->_geom_node;
163  }
164  }
165 
166  // We should always return a GeomNode, so that all polysets
167  // created at the same level will get added into the same
168  // GeomNode. Look for a child of this node. If it doesn't have a
169  // child yet, add a GeomNode and return it. Otherwise, if it
170  // already has a child, return that.
171  if (node->is_geom_node() && node->get_name() == name) {
172  return node;
173  }
174  for (int i = 0; i < node->get_num_children(); i++) {
175  PandaNode *child = node->get_child(i);
176  if (child->is_geom_node() && child->get_name() == name) {
177  return child;
178  }
179  }
180  PT(GeomNode) geom_node = new GeomNode(name);
181  node->add_child(geom_node);
182  return geom_node;
183 }
184 
185 
186 ////////////////////////////////////////////////////////////////////
187 // Function: CharacterMaker::create_slider
188 // Access: Public
189 // Description: Creates a new morph slider of the given name, and
190 // returns its index.
191 ////////////////////////////////////////////////////////////////////
193 create_slider(const string &name) {
194  if (_morph_root == (PartGroup *)NULL) {
195  _morph_root = new PartGroup(_bundle, "morph");
196  }
197  CharacterSlider *slider = new CharacterSlider(_morph_root, name);
198  int index = _parts.size();
199  _parts.push_back(slider);
200  return index;
201 }
202 
203 ////////////////////////////////////////////////////////////////////
204 // Function: CharacterMaker::egg_to_slider
205 // Access: Public
206 // Description: Returns the VertexSlider corresponding to the
207 // indicated egg slider name.
208 ////////////////////////////////////////////////////////////////////
210 egg_to_slider(const string &name) {
211  VertexSliders::iterator vi = _vertex_sliders.find(name);
212  if (vi != _vertex_sliders.end()) {
213  return (*vi).second;
214  }
215 
216  int index = create_slider(name);
217  PT(VertexSlider) slider =
218  new CharacterVertexSlider(DCAST(CharacterSlider, _parts[index]));
219  _vertex_sliders[name] = slider;
220  return slider;
221 }
222 
223 
224 ////////////////////////////////////////////////////////////////////
225 // Function: CharacterMaker::make_bundle
226 // Access: Private
227 // Description:
228 ////////////////////////////////////////////////////////////////////
229 CharacterJointBundle *CharacterMaker::
230 make_bundle() {
231  build_joint_hierarchy(_egg_root, _skeleton_root, -1);
232 
233  //if we are structured, the egg loader is going to take care of making the geometry
234  if(!_structured) {
235  make_geometry(_egg_root);
236  }
237  _bundle->sort_descendants();
238  parent_joint_nodes(_skeleton_root);
239 
240  // Now call update() one more time, to ensure that all of the joints
241  // have their correct transform (since we might have modified the
242  // default transform after construction).
243  _bundle->force_update();
244 
245  return _bundle;
246 }
247 
248 ////////////////////////////////////////////////////////////////////
249 // Function: CharacterMaker::build_joint_hierarchy
250 // Access: Private
251 // Description:
252 ////////////////////////////////////////////////////////////////////
253 void CharacterMaker::
254 build_joint_hierarchy(EggNode *egg_node, PartGroup *part, int index) {
255  if (egg_node->is_of_type(EggAnimPreload::get_class_type())) {
256  EggAnimPreload *egg_anim_preload = DCAST(EggAnimPreload, egg_node);
257 
258  double fps = 24.0;
259  if (egg_anim_preload->has_fps()) {
260  fps = egg_anim_preload->get_fps();
261  }
262 
263  int num_frames = 1;
264  if (egg_anim_preload->has_num_frames()) {
265  num_frames = egg_anim_preload->get_num_frames();
266  }
267 
268  PT(AnimPreloadTable) anim_preload = _bundle->modify_anim_preload();
269  if (anim_preload == (AnimPreloadTable *)NULL) {
270  anim_preload = new AnimPreloadTable;
271  _bundle->set_anim_preload(anim_preload);
272  }
273  anim_preload->add_anim(egg_node->get_name(), fps, num_frames);
274  return;
275  }
276 
277  if (egg_node->is_of_type(EggGroup::get_class_type())) {
278  EggGroup *egg_group = DCAST(EggGroup, egg_node);
279 
280  // Each joint we come across is significant, and gets added to the
281  // hierarchy. Non-joints we encounter are ignored.
282  if (egg_group->get_group_type() == EggGroup::GT_joint) {
283  // We need to get the transform of the joint, and then convert
284  // it to single-precision.
285  LMatrix4d matd;
286 
287  // First, we get the original, initial transform from the
288  // <Transform> entry.
289  if (egg_group->has_transform()) {
290  matd = egg_group->get_transform3d();
291  } else {
292  matd = LMatrix4d::ident_mat();
293  }
294 
295  LMatrix4 matf = LCAST(PN_stdfloat, matd);
296 
297  CharacterJoint *joint =
298  new CharacterJoint(_character_node, _character_node->get_bundle(0),
299  part, egg_group->get_name(), matf);
300  index = _parts.size();
301  _parts.push_back(joint);
302 
303  // Now that we have computed _net_transform (which we need to
304  // convert the vertices), update the default transform from the
305  // <DefaultPose> entry.
306  if (egg_group->get_default_pose().has_transform()) {
307  matd = egg_group->get_default_pose().get_transform3d();
308  matf = LCAST(PN_stdfloat, matd);
309  joint->_default_value = matf;
310  joint->_value = matf;
311  }
312 
313  if (egg_group->has_dcs_type()) {
314  // If the joint requested an explicit DCS, create a node for
315  // it.
316  PT(ModelNode) geom_node = new ModelNode(egg_group->get_name());
317 
318  // To prevent flattening from messing with geometry on
319  // exposed joints
320  geom_node->set_preserve_transform(ModelNode::PT_net);
321 
322  joint->_geom_node = geom_node.p();
323  }
324 
325  part = joint;
326  }
327 
328  EggGroup::const_iterator ci;
329  for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
330  build_joint_hierarchy((*ci), part, index);
331  }
332  }
333 
334  _node_map[egg_node] = index;
335 }
336 
337 ////////////////////////////////////////////////////////////////////
338 // Function: CharacterMaker::parent_joint_nodes
339 // Access: Private
340 // Description: Walks the joint hierarchy, and parents any explicit
341 // nodes created for the joints under the character
342 // node.
343 ////////////////////////////////////////////////////////////////////
344 void CharacterMaker::
345 parent_joint_nodes(PartGroup *part) {
346  if (part->is_of_type(CharacterJoint::get_class_type())) {
347  CharacterJoint *joint = DCAST(CharacterJoint, part);
348  PandaNode *joint_node = joint->_geom_node;
349  if (joint_node != NULL) {
350  _character_node->add_child(joint_node);
351  joint->add_net_transform(joint_node);
352  joint_node->set_transform(TransformState::make_mat(joint->_net_transform));
353  }
354  }
355 
356  for (int i = 0; i < part->get_num_children(); i++) {
357  parent_joint_nodes(part->get_child(i));
358  }
359 }
360 
361 ////////////////////////////////////////////////////////////////////
362 // Function: CharacterMaker::make_geometry
363 // Access: Private
364 // Description: Walks the hierarchy, looking for bins that represent
365 // polysets, which are to be animated with the
366 // character. Invokes the egg loader to create the
367 // animated geometry.
368 ////////////////////////////////////////////////////////////////////
369 void CharacterMaker::
370 make_geometry(EggNode *egg_node) {
371  if (egg_node->is_of_type(EggBin::get_class_type())) {
372  EggBin *egg_bin = DCAST(EggBin, egg_node);
373 
374  if (!egg_bin->empty() &&
375  (egg_bin->get_bin_number() == EggBinner::BN_polyset ||
376  egg_bin->get_bin_number() == EggBinner::BN_patches)) {
377  EggGroupNode *bin_home = determine_bin_home(egg_bin);
378 
379  bool is_dynamic;
380  if (bin_home == (EggGroupNode *)NULL) {
381  // This is a dynamic polyset that lives under the character's
382  // root node.
383  bin_home = _egg_root;
384  is_dynamic = true;
385  } else {
386  // This is a totally static polyset that is parented under
387  // some animated joint node.
388  is_dynamic = false;
389  }
390 
391  PandaNode *parent = part_to_node(egg_to_part(bin_home), egg_bin->get_name());
392  LMatrix4d transform =
393  egg_bin->get_vertex_frame() *
394  bin_home->get_node_frame_inv();
395 
396  _loader.make_polyset(egg_bin, parent, &transform, is_dynamic,
397  this);
398  }
399  }
400 
401  if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
402  EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
403 
404  EggGroupNode::const_iterator ci;
405  for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
406  make_geometry(*ci);
407  }
408  }
409 }
410 
411 ////////////////////////////////////////////////////////////////////
412 // Function: CharacterMaker::determine_primitive_home
413 // Access: Private
414 // Description:
415 ////////////////////////////////////////////////////////////////////
416 EggGroupNode *CharacterMaker::
417 determine_primitive_home(EggPrimitive *egg_primitive) {
418  // A primitive's vertices may be referenced by any joint in the
419  // character. Or, the primitive itself may be explicitly placed
420  // under a joint.
421 
422  // If any of the vertices are referenced by multiple joints, or if
423  // any two vertices are referenced by different joints, then the
424  // entire primitive must be considered dynamic. (We'll indicate a
425  // dynamic primitive by returning NULL.)
426 
427  // We need to keep track of the one joint we've encountered so far,
428  // to see if all the vertices are referenced by the same joint.
429  EggGroupNode *home = NULL;
430 
431  EggPrimitive::const_iterator vi;
432  for (vi = egg_primitive->begin();
433  vi != egg_primitive->end();
434  ++vi) {
435  EggVertex *vertex = (*vi);
436  if (vertex->gref_size() > 1) {
437  // This vertex is referenced by multiple joints; the primitive
438  // is dynamic.
439  return NULL;
440  }
441 
442  if (!vertex->_dxyzs.empty() ||
443  !vertex->_dnormals.empty() ||
444  !vertex->_drgbas.empty()) {
445  // This vertex has some morph slider definitions; therefore, the
446  // primitive is dynamic.
447  return NULL;
448  }
450  for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
451  if (!(*uvi)->_duvs.empty()) {
452  // Ditto: the vertex has some UV morphs; therefore the
453  // primitive is dynamic.
454  return NULL;
455  }
456  }
457 
458  EggGroupNode *vertex_home;
459 
460  if (vertex->gref_size() == 0) {
461  // This vertex is not referenced at all, which means it belongs
462  // right where it is.
463  vertex_home = egg_primitive->get_parent();
464  } else {
465  nassertr(vertex->gref_size() == 1, NULL);
466  // This vertex is referenced exactly once.
467  vertex_home = *vertex->gref_begin();
468  }
469 
470  if (home != NULL && home != vertex_home) {
471  // Oops, two vertices are referenced by different joints! The
472  // primitive is dynamic.
473  return NULL;
474  }
475 
476  home = vertex_home;
477  }
478 
479  // This shouldn't be possible, unless there are no vertices--but we
480  // check for that before calling this function.
481  nassertr(home != NULL, NULL);
482 
483  // So, all the vertices are assigned to the same group. This means
484  // the polygon belongs entirely to one joint.
485 
486  // If the group is not, in fact, a joint then we return the first
487  // joint above the group.
488  EggGroup *egg_group = (EggGroup *)NULL;
489  if (home->is_of_type(EggGroup::get_class_type())) {
490  egg_group = DCAST(EggGroup, home);
491  }
492  while (egg_group != (EggGroup *)NULL &&
493  egg_group->get_group_type() != EggGroup::GT_joint &&
494  egg_group->get_dart_type() == EggGroup::DT_none) {
495  nassertr(egg_group->get_parent() != (EggGroupNode *)NULL, NULL);
496  home = egg_group->get_parent();
497  egg_group = (EggGroup *)NULL;
498  if (home->is_of_type(EggGroup::get_class_type())) {
499  egg_group = DCAST(EggGroup, home);
500  }
501  }
502 
503  if (egg_group != (EggGroup *)NULL &&
504  egg_group->get_group_type() == EggGroup::GT_joint &&
505  !egg_group->has_dcs_type()) {
506  // If the home is a joint without a <DCS> flag--this is the normal
507  // case--we'll move the polygon under the character node and
508  // animate it from there explicitly.
509  return NULL;
510  }
511 
512  // Otherwise, if the joint *does* have a <DCS> flag, we'll create
513  // static geometry that we parent directly to the joint node.
514  // We'll also create static geometry for polygons that have no
515  // explicit joint assignment.
516  return home;
517 }
518 
519 ////////////////////////////////////////////////////////////////////
520 // Function: CharacterMaker::determine_bin_home
521 // Access: Private
522 // Description: Examines the joint assignment of the vertices of all
523 // of the primitives within this bin to determine which
524 // parent node the bin's polyset should be created
525 // under.
526 ////////////////////////////////////////////////////////////////////
527 EggGroupNode *CharacterMaker::
528 determine_bin_home(EggBin *egg_bin) {
529  // A primitive's vertices may be referenced by any joint in the
530  // character. Or, the primitive itself may be explicitly placed
531  // under a joint.
532 
533  // If any of the vertices, in any primitive, are referenced by
534  // multiple joints, or if any two vertices are referenced by
535  // different joints, then the entire bin must be considered dynamic.
536  // (We'll indicate a dynamic bin by returning NULL.)
537 
538  if (!egg_rigid_geometry) {
539  // If we don't have egg-rigid-geometry enabled, then all geometry
540  // is considered dynamic.
541  return NULL;
542  }
543 
544  // We need to keep track of the one joint we've encountered so far,
545  // to see if all the vertices are referenced by the same joint.
546  EggGroupNode *home = NULL;
547 
548  EggGroupNode::const_iterator ci;
549  for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
550  CPT(EggPrimitive) egg_primitive = DCAST(EggPrimitive, (*ci));
551 
552  EggPrimitive::const_iterator vi;
553  for (vi = egg_primitive->begin();
554  vi != egg_primitive->end();
555  ++vi) {
556  EggVertex *vertex = (*vi);
557  if (vertex->gref_size() > 1) {
558  // This vertex is referenced by multiple joints; the primitive
559  // is dynamic.
560  return NULL;
561  }
562 
563  if (!vertex->_dxyzs.empty() ||
564  !vertex->_dnormals.empty() ||
565  !vertex->_drgbas.empty()) {
566  // This vertex has some morph slider definitions; therefore, the
567  // primitive is dynamic.
568  return NULL;
569  }
571  for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
572  if (!(*uvi)->_duvs.empty()) {
573  // Ditto: the vertex has some UV morphs; therefore the
574  // primitive is dynamic.
575  return NULL;
576  }
577  }
578 
579  EggGroupNode *vertex_home;
580 
581  if (vertex->gref_size() == 0) {
582  // This vertex is not referenced at all, which means it belongs
583  // right where it is.
584  vertex_home = egg_primitive->get_parent();
585  } else {
586  nassertr(vertex->gref_size() == 1, NULL);
587  // This vertex is referenced exactly once.
588  vertex_home = *vertex->gref_begin();
589  }
590 
591  if (home != NULL && home != vertex_home) {
592  // Oops, two vertices are referenced by different joints! The
593  // primitive is dynamic.
594  return NULL;
595  }
596 
597  home = vertex_home;
598  }
599  }
600 
601  // This shouldn't be possible, unless there are no vertices--but we
602  // eliminate invalid primitives before we begin, so all primitives
603  // should have vertices, and all bins should have primitives.
604  nassertr(home != NULL, NULL);
605 
606  // So, all the vertices are assigned to the same group. This means
607  // all the primitives in the bin belong entirely to one joint.
608 
609  // If the group is not, in fact, a joint then we return the first
610  // joint above the group.
611  EggGroup *egg_group = (EggGroup *)NULL;
612  if (home->is_of_type(EggGroup::get_class_type())) {
613  egg_group = DCAST(EggGroup, home);
614  }
615  while (egg_group != (EggGroup *)NULL &&
616  egg_group->get_group_type() != EggGroup::GT_joint &&
617  egg_group->get_dart_type() == EggGroup::DT_none) {
618  nassertr(egg_group->get_parent() != (EggGroupNode *)NULL, NULL);
619  home = egg_group->get_parent();
620  egg_group = (EggGroup *)NULL;
621  if (home->is_of_type(EggGroup::get_class_type())) {
622  egg_group = DCAST(EggGroup, home);
623  }
624  }
625 
626  if (egg_group != (EggGroup *)NULL &&
627  egg_group->get_group_type() == EggGroup::GT_joint &&
628  !egg_group->has_dcs_type()) {
629  // If we have rigid geometry that is assigned to a joint without a
630  // <DCS> flag, which means the joint didn't get created as its own
631  // node, go ahead and make an implicit node for the joint.
632 
633  if (egg_group->get_dcs_type() == EggGroup::DC_none) {
634  // Unless the user specifically forbade exposing the joint by
635  // putting an explicit "<DCS> { none }" entry in the joint. In
636  // this case, we return NULL to treat the geometry as dynamic
637  // (and animate it by animating its vertices), but display lists
638  // and vertex buffers will perform better if more geometry is
639  // rigid. There's a tradeoff, though, since the cull traverser
640  // will have to do more work with additional transforms in the
641  // scene graph, and this may also break up the geometry into
642  // more individual pieces, which is the biggest limiting factor
643  // on modern PC graphics cards.
644  return NULL;
645  }
646 
647  CharacterJoint *joint;
648  DCAST_INTO_R(joint, egg_to_part(egg_group), home);
649  egg_group->set_dcs_type(EggGroup::DC_default);
650 
651  PT(ModelNode) geom_node = new ModelNode(egg_group->get_name());
652  geom_node->set_preserve_transform(ModelNode::PT_local);
653  joint->_geom_node = geom_node.p();
654  }
655 
656  return home;
657 }
658 
659 ////////////////////////////////////////////////////////////////////
660 // Function: CharacterMaker::get_identity_transform
661 // Access: Private
662 // Description: Returns a VertexTransform that represents the root of
663 // the character--it never animates.
664 ////////////////////////////////////////////////////////////////////
665 VertexTransform *CharacterMaker::
666 get_identity_transform() {
667  if (_identity_transform == (VertexTransform *)NULL) {
668  _identity_transform = new UserVertexTransform("root");
669  }
670  return _identity_transform;
671 }
A base class for any of a number of kinds of geometry primitives: polygons, point lights...
Definition: eggPrimitive.h:51
GroupRef::size_type gref_size() const
Returns the number of elements between gref_begin() and gref_end().
Definition: eggVertex.cxx:819
A basic node of the scene graph or data graph.
Definition: pandaNode.h:72
const EggTransform & get_default_pose() const
Returns a read-only accessor to the initial pose transform.
Definition: eggGroup.I:942
const LMatrix4d & get_transform3d() const
Returns the overall transform as a 4x4 matrix.
Definition: eggTransform.I:251
This is an iterator adaptor that converts any iterator that returns a pair (e.g.
This table records data about a list of animations for a particular model, such as number of frames a...
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:4716
The collection of all the joints and sliders in the character.
const LMatrix4d & get_node_frame_inv() const
Returns the inverse of the matrix returned by get_node_frame().
Definition: eggNode.I:183
An animated character, with skeleton-morph animation and either soft-skinned or hard-skinned vertices...
Definition: character.h:41
int get_num_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of child nodes this node has.
Definition: pandaNode.I:68
const LMatrix4d & get_vertex_frame() const
Returns the coordinate frame of the vertices referenced by primitives at or under this node...
Definition: eggNode.I:135
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
PandaNode * get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns the nth child node of this node.
Definition: pandaNode.I:82
double get_fps() const
This is only valid if has_fps() returns true.
int get_num_children() const
Returns the number of child nodes of the group.
Definition: partGroup.cxx:111
This is a specialization on VertexSlider that returns the slider value associated with a particular C...
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...
Definition: eggVertex.cxx:789
This is an abstract base class that retains some slider value, which is a linear value that typically...
Definition: vertexSlider.h:41
bool add_net_transform(PandaNode *node)
Adds the indicated node to the list of nodes that will be updated each frame with the joint&#39;s net tra...
This is a morph slider within the character.
PartGroup * egg_to_part(EggNode *egg_node) const
Returns the PartGroup node associated with the given egg node.
string get_name() const
Returns the name of the character.
VertexSlider * egg_to_slider(const string &name)
Returns the VertexSlider corresponding to the indicated egg slider name.
int create_slider(const string &name)
Creates a new morph slider of the given name, and returns its index.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition: eggGroup.h:36
PartGroup * get_child(int n) const
Returns the nth child of the group.
Definition: partGroup.cxx:122
This node is placed at key points within the scene graph to indicate the roots of "models": subtrees ...
Definition: modelNode.h:34
int get_num_frames() const
This is only valid if has_num_frames() returns true.
This is an abstract base class that holds a pointer to some transform, computed in some arbitrary way...
This is a 4-by-4 transform matrix.
Definition: lmatrix.h:451
This corresponds to an <AnimPreload> entry.
static const LMatrix4d & ident_mat()
Returns an identity matrix.
Definition: lmatrix.h:5168
Any one-, two-, three-, or four-component vertex, possibly with attributes such as a normal...
Definition: eggVertex.h:41
int egg_to_index(EggNode *egg_node) const
Returns the index number associated with the PartGroup node for the given egg node, or -1.
This is a specialization on VertexTransform that returns the transform necessary to move vertices as ...
PandaNode * part_to_node(PartGroup *part, const string &name) const
Returns the scene graph node associated with the given PartGroup node, if there is one...
const_uv_iterator uv_begin() const
Returns an iterator that allows walking through the complete set of named UV&#39;s on the vertex...
Definition: eggVertex.I:273
This is a specialization on VertexTransform that allows the user to specify any arbitrary transform m...
A base class for things that may be directly added into the egg hierarchy.
Definition: eggNode.h:38
This represents one joint of the character&#39;s animation, containing an animating transform matrix...
bool has_dcs_type() const
Returns true if the specified DCS type is not DC_none and not DC_unspecified.
Definition: eggGroup.I:244
void force_update()
Recalculates the character even if we think it doesn&#39;t need it.
Definition: character.cxx:531
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:63
VertexTransform * egg_to_transform(EggNode *egg_node)
Returns a JointVertexTransform suitable for applying the animation associated with the given egg node...
void set_preserve_transform(PreserveTransform preserve_transform)
Sets the preserve_transform flag.
Definition: modelNode.I:65
virtual bool is_geom_node() const
A simple downcast check.
Definition: pandaNode.cxx:2486
void set_transform(const TransformState *transform, Thread *current_thread=Thread::get_current_thread())
Sets the transform that will be applied to this node and below.
Definition: pandaNode.cxx:1267
A node that holds Geom objects, renderable pieces of geometry.
Definition: geomNode.h:37
void make_polyset(EggBin *egg_bin, PandaNode *parent, const LMatrix4d *transform, bool is_dynamic, CharacterMaker *character_maker)
Creates a polyset–that is, a Geom–from the primitives that have already been grouped into a bin...
Definition: eggLoader.cxx:321
const_uv_iterator uv_end() const
Returns an iterator that allows walking through the complete set of named UV&#39;s on the vertex...
Definition: eggVertex.I:301
Converts an egg data structure, possibly read from an egg file but not necessarily, into a scene graph suitable for rendering.
Definition: eggLoader.h:70
A type of group node that holds related subnodes.
Definition: eggBin.h:30
bool has_transform() const
Returns true if the transform is nonempty, false if it is empty (no transform components have been ad...
Definition: eggTransform.I:163
This is the base class for PartRoot and MovingPart.
Definition: partGroup.h:45