Panda3D
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"
16 #include "jointVertexTransform.h"
17 #include "characterJointEffect.h"
18 #include "datagram.h"
19 #include "datagramIterator.h"
20 #include "bamReader.h"
21 #include "bamWriter.h"
22 
23 TypeHandle CharacterJoint::_type_handle;
24 
25 /**
26  * For internal use only.
27  */
28 CharacterJoint::
29 CharacterJoint() :
30  _character(nullptr)
31 {
32 }
33 
34 /**
35  *
36  */
37 CharacterJoint::
38 CharacterJoint(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  */
51 CharacterJoint::
52 CharacterJoint(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  */
75 CharacterJoint::
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  */
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  */
95 make_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  */
110 bool CharacterJoint::
111 update_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  */
178 void CharacterJoint::
179 do_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  */
195 bool CharacterJoint::
197  if (_character != nullptr) {
198  node->set_effect(CharacterJointEffect::make(_character));
199  }
200  CPT(TransformState) t = TransformState::make_mat(_net_transform);
201  node->set_transform(t, Thread::get_current_thread());
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  */
213 bool CharacterJoint::
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  */
228 bool CharacterJoint::
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  */
237 void CharacterJoint::
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  */
262  NodePathCollection npc;
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  */
287 bool CharacterJoint::
289  if (_character != nullptr) {
290  node->set_effect(CharacterJointEffect::make(_character));
291  }
292  CPT(TransformState) t = TransformState::make_mat(_value);
293  node->set_transform(t, Thread::get_current_thread());
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  */
305 bool CharacterJoint::
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  */
320 bool CharacterJoint::
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  */
329 void CharacterJoint::
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  */
354  NodePathCollection npc;
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  */
370 void CharacterJoint::
371 get_transform(LMatrix4 &transform) const {
372  transform = _value;
373 }
374 
375 CPT(TransformState) CharacterJoint::
376 get_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  */
384 void CharacterJoint::
385 get_net_transform(LMatrix4 &transform) const {
386  transform = _net_transform;
387 }
388 
389 /**
390  * Returns the Character that owns this joint.
391  */
392 Character *CharacterJoint::
393 get_character() const {
394  return _character;
395 }
396 
397 /**
398  * Changes the Character that owns this joint.
399  */
400 void CharacterJoint::
401 set_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  */
455 void CharacterJoint::
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  */
484 void CharacterJoint::
485 fillin(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  */
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  */
539  CharacterJoint *me = new CharacterJoint;
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  */
551 void CharacterJoint::
554 }
A basic node of the scene graph or data graph.
Definition: pandaNode.h:64
Indicates a coordinate-system transform on vertices.
void add_path(const NodePath &node_path)
Adds a new NodePath to the collection.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
An animated character, with skeleton-morph animation and either soft- skinned or hard-skinned vertice...
Definition: character.h:38
size_type_0 size() const
Returns the number of elements in the ordered vector.
void clear()
Removes all elements from the ordered vector.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
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...
This effect will be added automatically to a node by CharacterJoint::add_net_transform() and Characte...
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
iterator_0 begin()
Returns the iterator that marks the first element in 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.
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 the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
This is the base class for a number of special render effects that may be set on scene graph nodes to...
Definition: renderEffect.h:48
CPT(TransformState) CharacterJoint
Copies the joint's current net transform (composed from the root of the character joint hierarchy) in...
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
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...
Definition: partGroup.cxx:490
bool empty() const
Returns true if the ordered vector is empty, false otherwise.
virtual void write_datagram(BamWriter *manager, Datagram &me)
Function to write the important information in the particular object to a Datagram.
Definition: movingPart.I:100
int get_file_minor_ver() const
Returns the minor version number of the Bam file currently being read.
Definition: bamReader.I:83
void clear_local_transforms()
Removes all nodes from the list of nodes that will be updated each frame with the joint's local trans...
static TypedWritable * make_CharacterJoint(const FactoryParams &params)
Factory method to generate a CharacterJoint object.
set_transform
Sets the transform that will be applied to this node and below.
Definition: pandaNode.h:183
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
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...
static void register_with_read_factory()
Factory method to generate a CharacterJoint object.
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
void add_uint16(uint16_t value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:85
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...
get_current_thread
Returns a pointer to the currently-executing Thread object.
Definition: thread.h:109
get_root_xform
Returns the transform matrix which is implicitly applied at the root of the animated hierarchy.
Definition: partBundle.h:119
virtual bool is_character_joint() const
Returns true if this part is a CharacterJoint, false otherwise.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
void set_effect(const RenderEffect *effect)
Adds the indicated render effect to the scene graph on this node.
Definition: pandaNode.cxx:1005
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
virtual bool is_character_joint() const
Returns true if this part is a CharacterJoint, false otherwise.
Definition: partGroup.cxx:58
This is a particular kind of MovingPart that accepts a matrix each frame.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
A thread; that is, a lightweight process.
Definition: thread.h:46
This is the root of a MovingPart hierarchy.
Definition: partBundle.h:46
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.
This represents one joint of the character's animation, containing an animating transform matrix.
bool read_pointer(DatagramIterator &scan)
The interface for reading a pointer to another object from a Bam file.
Definition: bamReader.cxx:610
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...
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 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...
virtual int complete_pointers(TypedWritable **plist, BamReader *manager)
Receives an array of pointers, one for each time manager->read_pointer() was called in fillin().
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A class to retrieve the individual data elements previously stored in a Datagram.
NodePathCollection get_local_transforms()
Returns a list of the local transforms set for this node.
void clear_effect(TypeHandle type)
Removes the render effect of the given type from this node.
Definition: pandaNode.cxx:1022
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
NodePathCollection get_net_transforms()
Returns a list of the net transforms set for this node.
const LMatrix4 & get_transform() const
Returns the transform matrix of the joint.
virtual PartGroup * make_copy() const
Allocates and returns a new copy of the node.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void write_pointer(Datagram &packet, const TypedWritable *dest)
The interface for writing a pointer to another object to a Bam file.
Definition: bamWriter.cxx:317
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.
This is a set of zero or more NodePaths.
This is the base class for PartRoot and MovingPart.
Definition: partGroup.h:43