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