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