Panda3D
Loading...
Searching...
No Matches
characterJoint.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 characterJoint.cxx
10 * @author drose
11 * @date 1999-02-23
12 */
13
14#include "characterJoint.h"
15#include "config_char.h"
18#include "datagram.h"
19#include "datagramIterator.h"
20#include "bamReader.h"
21#include "bamWriter.h"
22
23TypeHandle CharacterJoint::_type_handle;
24
25/**
26 * For internal use only.
27 */
28CharacterJoint::
29CharacterJoint() :
30 _character(nullptr)
31{
32}
33
34/**
35 *
36 */
37CharacterJoint::
38CharacterJoint(const CharacterJoint &copy) :
39 MovingPartMatrix(copy),
40 _character(nullptr),
41 _net_transform(copy._net_transform),
42 _initial_net_transform_inverse(copy._initial_net_transform_inverse),
43 _skinning_matrix(copy._skinning_matrix)
44{
45 // We don't copy the sets of transform nodes.
46}
47
48/**
49 *
50 */
51CharacterJoint::
52CharacterJoint(Character *character,
53 PartBundle *root, PartGroup *parent, const std::string &name,
54 const LMatrix4 &default_value) :
55 MovingPartMatrix(parent, name, default_value),
56 _character(character)
57{
58 Thread *current_thread = Thread::get_current_thread();
59
60 // Now that we've constructed and we're in the tree, let's call
61 // update_internals() to get our _net_transform set properly.
62 update_internals(root, parent, true, false, current_thread);
63
64 // And then compute its inverse. This is needed to track changes in
65 // _net_transform as the joint moves, so we can recompute _skinning_matrix,
66 // which maps vertices from their initial positions to their animated
67 // positions.
68 _initial_net_transform_inverse = invert(_net_transform);
69 _skinning_matrix = LMatrix4::ident_mat();
70}
71
72/**
73 *
74 */
75CharacterJoint::
76~CharacterJoint() {
77 nassertv(_vertex_transforms.empty());
78 nassertv(_character == nullptr);
79}
80
81/**
82 * Returns true if this part is a CharacterJoint, false otherwise. This is a
83 * tiny optimization over is_of_type(CharacterType::get_class_type()).
84 */
86is_character_joint() const {
87 return true;
88}
89
90/**
91 * Allocates and returns a new copy of the node. Children are not copied, but
92 * see copy_subgraph().
93 */
95make_copy() const {
96 return new CharacterJoint(*this);
97}
98
99/**
100 * This is called by do_update() whenever the part or some ancestor has
101 * changed values. It is a hook for derived classes to update whatever cache
102 * they may have that depends on these.
103 *
104 * The return value is true if the part has changed as a result of the update,
105 * or false otherwise.
106 *
107 * In the case of a CharacterJoint, of course, it means to recompute the joint
108 * angles and associated transforms for this particular joint.
109 */
111update_internals(PartBundle *root, PartGroup *parent, bool self_changed,
112 bool parent_changed, Thread *current_thread) {
113 nassertr(parent != nullptr, false);
114
115 bool net_changed = false;
116 if (parent->is_character_joint()) {
117 // The joint is not a toplevel joint; its parent therefore affects its net
118 // transform.
119 if (parent_changed || self_changed) {
120 CharacterJoint *parent_joint = DCAST(CharacterJoint, parent);
121
122 _net_transform = _value * parent_joint->_net_transform;
123 net_changed = true;
124 }
125
126 } else {
127 // The joint is a toplevel joint, so therefore it gets its root transform
128 // from the bundle.
129 if (self_changed) {
130 _net_transform = _value * root->get_root_xform();
131 net_changed = true;
132 }
133 }
134
135 if (net_changed) {
136 if (!_net_transform_nodes.empty()) {
137 CPT(TransformState) t = TransformState::make_mat(_net_transform);
138
139 NodeList::iterator ai;
140 for (ai = _net_transform_nodes.begin();
141 ai != _net_transform_nodes.end();
142 ++ai) {
143 PandaNode *node = *ai;
144 node->set_transform(t, current_thread);
145 }
146 }
147
148 // Recompute the transform used by any vertices animated by this joint.
149 _skinning_matrix = _initial_net_transform_inverse * _net_transform;
150
151 // Also tell our related JointVertexTransforms that we've changed their
152 // underlying matrix.
153 VertexTransforms::iterator vti;
154 for (vti = _vertex_transforms.begin(); vti != _vertex_transforms.end(); ++vti) {
155 (*vti)->mark_modified(current_thread);
156 }
157 }
158
159 if (self_changed && !_local_transform_nodes.empty()) {
160 CPT(TransformState) t = TransformState::make_mat(_value);
161
162 NodeList::iterator ai;
163 for (ai = _local_transform_nodes.begin();
164 ai != _local_transform_nodes.end();
165 ++ai) {
166 PandaNode *node = *ai;
167 node->set_transform(t, current_thread);
168 }
169 }
170
171 return self_changed || net_changed;
172}
173
174/**
175 * Called by PartBundle::xform(), this indicates the indicated transform is
176 * being applied to the root joint.
177 */
179do_xform(const LMatrix4 &mat, const LMatrix4 &inv_mat) {
180 _initial_net_transform_inverse = inv_mat * _initial_net_transform_inverse;
181
182 MovingPartMatrix::do_xform(mat, inv_mat);
183}
184
185
186
187/**
188 * Adds the indicated node to the list of nodes that will be updated each
189 * frame with the joint's net transform from the root. Returns true if the
190 * node is successfully added, false if it had already been added.
191 *
192 * A CharacterJointEffect for this joint's Character will automatically be
193 * added to the specified node.
194 */
197 if (_character != nullptr) {
198 node->set_effect(CharacterJointEffect::make(_character));
199 }
200 CPT(TransformState) t = TransformState::make_mat(_net_transform);
202 return _net_transform_nodes.insert(node).second;
203}
204
205/**
206 * Removes the indicated node from the list of nodes that will be updated each
207 * frame with the joint's net transform from the root. Returns true if the
208 * node is successfully removed, false if it was not on the list.
209 *
210 * If the node has a CharacterJointEffect that matches this joint's Character,
211 * it will be cleared.
212 */
215 CPT(RenderEffect) effect = node->get_effect(CharacterJointEffect::get_class_type());
216 if (effect != nullptr &&
217 DCAST(CharacterJointEffect, effect)->matches_character(_character)) {
218 node->clear_effect(CharacterJointEffect::get_class_type());
219 }
220
221 return (_net_transform_nodes.erase(node) > 0);
222}
223
224/**
225 * Returns true if the node is on the list of nodes that will be updated each
226 * frame with the joint's net transform from the root, false otherwise.
227 */
229has_net_transform(PandaNode *node) const {
230 return (_net_transform_nodes.count(node) > 0);
231}
232
233/**
234 * Removes all nodes from the list of nodes that will be updated each frame
235 * with the joint's net transform from the root.
236 */
239 NodeList::iterator ai;
240 for (ai = _net_transform_nodes.begin();
241 ai != _net_transform_nodes.end();
242 ++ai) {
243 PandaNode *node = *ai;
244
245 CPT(RenderEffect) effect = node->get_effect(CharacterJointEffect::get_class_type());
246 if (effect != nullptr &&
247 DCAST(CharacterJointEffect, effect)->matches_character(_character)) {
248 node->clear_effect(CharacterJointEffect::get_class_type());
249 }
250 }
251
252 _net_transform_nodes.clear();
253}
254
255/**
256 * Returns a list of the net transforms set for this node. Note that this
257 * returns a list of NodePaths, even though the net transforms are actually a
258 * list of PandaNodes.
259 */
263
264 NodeList::iterator ai;
265 for (ai = _net_transform_nodes.begin();
266 ai != _net_transform_nodes.end();
267 ++ai) {
268 PandaNode *node = *ai;
269 npc.add_path(NodePath::any_path(node));
270 }
271
272 return npc;
273}
274
275/**
276 * Adds the indicated node to the list of nodes that will be updated each
277 * frame with the joint's local transform from its parent. Returns true if
278 * the node is successfully added, false if it had already been added.
279 *
280 * The Character pointer should be the Character object that owns this joint;
281 * this will be used to create a CharacterJointEffect for this node. If it is
282 * NULL, no such effect will be created.
283 *
284 * A CharacterJointEffect for this joint's Character will automatically be
285 * added to the specified node.
286 */
289 if (_character != nullptr) {
290 node->set_effect(CharacterJointEffect::make(_character));
291 }
292 CPT(TransformState) t = TransformState::make_mat(_value);
294 return _local_transform_nodes.insert(node).second;
295}
296
297/**
298 * Removes the indicated node from the list of nodes that will be updated each
299 * frame with the joint's local transform from its parent. Returns true if
300 * the node is successfully removed, false if it was not on the list.
301 *
302 * If the node has a CharacterJointEffect that matches this joint's Character,
303 * it will be cleared.
304 */
307 CPT(RenderEffect) effect = node->get_effect(CharacterJointEffect::get_class_type());
308 if (effect != nullptr &&
309 DCAST(CharacterJointEffect, effect)->matches_character(_character)) {
310 node->clear_effect(CharacterJointEffect::get_class_type());
311 }
312
313 return (_local_transform_nodes.erase(node) > 0);
314}
315
316/**
317 * Returns true if the node is on the list of nodes that will be updated each
318 * frame with the joint's local transform from its parent, false otherwise.
319 */
321has_local_transform(PandaNode *node) const {
322 return (_local_transform_nodes.count(node) > 0);
323}
324
325/**
326 * Removes all nodes from the list of nodes that will be updated each frame
327 * with the joint's local transform from its parent.
328 */
331 NodeList::iterator ai;
332 for (ai = _local_transform_nodes.begin();
333 ai != _local_transform_nodes.end();
334 ++ai) {
335 PandaNode *node = *ai;
336
337 CPT(RenderEffect) effect = node->get_effect(CharacterJointEffect::get_class_type());
338 if (effect != nullptr &&
339 DCAST(CharacterJointEffect, effect)->matches_character(_character)) {
340 node->clear_effect(CharacterJointEffect::get_class_type());
341 }
342 }
343
344 _local_transform_nodes.clear();
345}
346
347/**
348 * Returns a list of the local transforms set for this node. Note that this
349 * returns a list of NodePaths, even though the local transforms are actually
350 * a list of PandaNodes.
351 */
355
356 NodeList::iterator ai;
357 for (ai = _local_transform_nodes.begin();
358 ai != _local_transform_nodes.end();
359 ++ai) {
360 PandaNode *node = *ai;
361 npc.add_path(NodePath::any_path(node));
362 }
363
364 return npc;
365}
366
367/**
368 * Copies the joint's current transform into the indicated matrix.
369 */
371get_transform(LMatrix4 &transform) const {
372 transform = _value;
373}
374
375CPT(TransformState) CharacterJoint::
376get_transform_state() const {
377 return TransformState::make_mat( _value );
378}
379
380/**
381 * Copies the joint's current net transform (composed from the root of the
382 * character joint hierarchy) into the indicated matrix.
383 */
384void CharacterJoint::
385get_net_transform(LMatrix4 &transform) const {
386 transform = _net_transform;
387}
388
389/**
390 * Returns the Character that owns this joint.
391 */
392Character *CharacterJoint::
393get_character() const {
394 return _character;
395}
396
397/**
398 * Changes the Character that owns this joint.
399 */
400void CharacterJoint::
401set_character(Character *character) {
402 if (character != _character) {
403
404 if (character != nullptr) {
405 // Change or set a _character pointer on each joint's exposed node.
406 NodeList::iterator ai;
407 for (ai = _net_transform_nodes.begin();
408 ai != _net_transform_nodes.end();
409 ++ai) {
410 PandaNode *node = *ai;
411 node->set_effect(CharacterJointEffect::make(character));
412 }
413 for (ai = _local_transform_nodes.begin();
414 ai != _local_transform_nodes.end();
415 ++ai) {
416 PandaNode *node = *ai;
417 node->set_effect(CharacterJointEffect::make(character));
418 }
419
420 } else { // (character == (Character *)NULL)
421 // Clear the _character pointer on each joint's exposed node.
422 NodeList::iterator ai;
423 for (ai = _net_transform_nodes.begin();
424 ai != _net_transform_nodes.end();
425 ++ai) {
426 PandaNode *node = *ai;
427
428 CPT(RenderEffect) effect = node->get_effect(CharacterJointEffect::get_class_type());
429 if (effect != nullptr &&
430 DCAST(CharacterJointEffect, effect)->matches_character(_character)) {
431 node->clear_effect(CharacterJointEffect::get_class_type());
432 }
433 }
434 for (ai = _local_transform_nodes.begin();
435 ai != _local_transform_nodes.end();
436 ++ai) {
437 PandaNode *node = *ai;
438
439 CPT(RenderEffect) effect = node->get_effect(CharacterJointEffect::get_class_type());
440 if (effect != nullptr &&
441 DCAST(CharacterJointEffect, effect)->matches_character(_character)) {
442 node->clear_effect(CharacterJointEffect::get_class_type());
443 }
444 }
445 }
446 }
447
448 _character = character;
449}
450
451/**
452 * Function to write the important information in the particular object to a
453 * Datagram
454 */
456write_datagram(BamWriter *manager, Datagram &me) {
457 NodeList::iterator ni;
459
460 manager->write_pointer(me, _character);
461
462 me.add_uint16(_net_transform_nodes.size());
463 for (ni = _net_transform_nodes.begin();
464 ni != _net_transform_nodes.end();
465 ni++) {
466 manager->write_pointer(me, (*ni));
467 }
468
469 me.add_uint16(_local_transform_nodes.size());
470 for (ni = _local_transform_nodes.begin();
471 ni != _local_transform_nodes.end();
472 ni++) {
473 manager->write_pointer(me, (*ni));
474 }
475
476 _initial_net_transform_inverse.write_datagram(me);
477}
478
479/**
480 * Function that reads out of the datagram (or asks manager to read) all of
481 * the data that is needed to re-create this object and stores it in the
482 * appropiate place
483 */
484void CharacterJoint::
485fillin(DatagramIterator &scan, BamReader *manager) {
486 int i;
487 MovingPartMatrix::fillin(scan, manager);
488
489 if (manager->get_file_minor_ver() >= 4) {
490 manager->read_pointer(scan);
491 }
492
493 _num_net_nodes = scan.get_uint16();
494 for(i = 0; i < _num_net_nodes; i++) {
495 manager->read_pointer(scan);
496 }
497
498 _num_local_nodes = scan.get_uint16();
499 for(i = 0; i < _num_local_nodes; i++) {
500 manager->read_pointer(scan);
501 }
502
503 _initial_net_transform_inverse.read_datagram(scan);
504}
505
506/**
507 * Takes in a vector of pointers to TypedWritable objects that correspond to
508 * all the requests for pointers that this object made to BamReader.
509 */
511complete_pointers(TypedWritable **p_list, BamReader* manager) {
512 int pi = MovingPartMatrix::complete_pointers(p_list, manager);
513
514 if (manager->get_file_minor_ver() >= 4) {
515 _character = DCAST(Character, p_list[pi++]);
516 } else {
517 _character = nullptr;
518 }
519
520 int i;
521 for (i = 0; i < _num_net_nodes; i++) {
522 PandaNode *node = DCAST(PandaNode, p_list[pi++]);
523 _net_transform_nodes.insert(node);
524 }
525
526 for (i = 0; i < _num_local_nodes; i++) {
527 PandaNode *node = DCAST(PandaNode, p_list[pi++]);
528 _local_transform_nodes.insert(node);
529 }
530
531 return pi;
532}
533
534/**
535 * Factory method to generate a CharacterJoint object
536 */
538make_CharacterJoint(const FactoryParams &params) {
540 DatagramIterator scan;
541 BamReader *manager;
542
543 parse_params(params, scan, manager);
544 me->fillin(scan, manager);
545 return me;
546}
547
548/**
549 * Factory method to generate a CharacterJoint object
550 */
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition bamReader.I:275
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 is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition bamReader.h:110
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition bamReader.I:83
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition bamReader.I:177
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition bamWriter.h:63
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
This effect will be added automatically to a node by CharacterJoint::add_net_transform() and Characte...
This represents one joint of the character's animation, containing an animating transform matrix.
bool has_net_transform(PandaNode *node) const
Returns true if the node is on the list of nodes that will be updated each frame with the joint's net...
NodePathCollection get_local_transforms()
Returns a list of the local transforms set for this node.
const LMatrix4 & get_transform() const
Returns the transform matrix of the joint.
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...
bool has_local_transform(PandaNode *node) const
Returns true if the node is on the list of nodes that will be updated each frame with the joint's loc...
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
virtual void do_xform(const LMatrix4 &mat, const LMatrix4 &inv_mat)
Called by PartBundle::xform(), this indicates the indicated transform is being applied to the root jo...
static TypedWritable * make_CharacterJoint(const FactoryParams &params)
Factory method to generate a CharacterJoint object.
bool remove_local_transform(PandaNode *node)
Removes the indicated node from the list of nodes that will be updated each frame with the joint's lo...
void clear_net_transforms()
Removes all nodes from the list of nodes that will be updated each frame with the joint's net transfo...
bool add_local_transform(PandaNode *node)
Adds the indicated node to the list of nodes that will be updated each frame with the joint's local t...
bool remove_net_transform(PandaNode *node)
Removes the indicated node from the list of nodes that will be updated each frame with the joint's ne...
virtual PartGroup * make_copy() const
Allocates and returns a new copy of the node.
NodePathCollection get_net_transforms()
Returns a list of the net transforms set for this node.
virtual bool is_character_joint() const
Returns true if this part is a CharacterJoint, false otherwise.
void clear_local_transforms()
Removes all nodes from the list of nodes that will be updated each frame with the joint's local trans...
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager)
Takes in a vector of pointers to TypedWritable objects that correspond to all the requests for pointe...
static void register_with_read_factory()
Factory method to generate a CharacterJoint object.
virtual bool update_internals(PartBundle *root, PartGroup *parent, bool self_changed, bool parent_changed, Thread *current_thread)
This is called by do_update() whenever the part or some ancestor has changed values.
An animated character, with skeleton-morph animation and either soft- skinned or hard-skinned vertice...
Definition character.h:38
A class to retrieve the individual data elements previously stored in a Datagram.
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition datagram.I:85
An instance of this class is passed to the Factory when requesting it to do its business and construc...
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition factory.I:73
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
This is a particular kind of MovingPart that accepts a matrix each frame.
This is a set of zero or more NodePaths.
void add_path(const NodePath &node_path)
Adds a new NodePath to the collection.
static NodePath any_path(PandaNode *node, Thread *current_thread=Thread::get_current_thread())
Returns a new NodePath that represents any arbitrary path from the root to the indicated node.
Definition nodePath.I:62
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
void clear_effect(TypeHandle type)
Removes the render effect of the given type from this node.
set_transform
Sets the transform that will be applied to this node and below.
Definition pandaNode.h:183
void set_effect(const RenderEffect *effect)
Adds the indicated render effect to the scene graph on this node.
This is the root of a MovingPart hierarchy.
Definition partBundle.h:46
get_root_xform
Returns the transform matrix which is implicitly applied at the root of the animated hierarchy.
Definition partBundle.h:119
This is the base class for PartRoot and MovingPart.
Definition partGroup.h:43
virtual bool is_character_joint() const
Returns true if this part is a CharacterJoint, false otherwise.
Definition partGroup.cxx:58
virtual void do_xform(const LMatrix4 &mat, const LMatrix4 &inv_mat)
Called by PartBundle::xform(), this indicates the indicated transform is being applied to the root jo...
This is the base class for a number of special render effects that may be set on scene graph nodes to...
A thread; that is, a lightweight process.
Definition thread.h:46
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition thread.h:109
Indicates a coordinate-system transform on vertices.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
size_type_0 count(const key_type_0 &key) const
Returns the number of elements that sort equivalent to the key that are in the vector.
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
size_type_0 size() const
Returns the number of elements in the ordered vector.
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
void clear()
Removes all elements from the ordered vector.
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.