Panda3D
eggJointData.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 eggJointData.cxx
10  * @author drose
11  * @date 2001-02-23
12  */
13 
14 #include "eggJointData.h"
15 
16 #include "eggCharacterDb.h"
17 #include "eggJointNodePointer.h"
18 #include "eggMatrixTablePointer.h"
19 #include "pvector.h"
20 #include "dcast.h"
21 #include "eggGroup.h"
22 #include "eggTable.h"
23 #include "indent.h"
24 #include "fftCompressor.h"
25 #include "zStream.h"
26 
27 using std::string;
28 
29 TypeHandle EggJointData::_type_handle;
30 
31 
32 /**
33  *
34  */
35 EggJointData::
36 EggJointData(EggCharacterCollection *collection,
37  EggCharacterData *char_data) :
38  EggComponentData(collection, char_data)
39 {
40  _parent = nullptr;
41  _new_parent = nullptr;
42  _has_rest_frame = false;
43  _rest_frames_differ = false;
44 }
45 
46 /**
47  * Returns the local transform matrix corresponding to this joint position in
48  * the nth frame in the indicated model.
49  */
50 LMatrix4d EggJointData::
51 get_frame(int model_index, int n) const {
52  EggBackPointer *back = get_model(model_index);
53  if (back == nullptr) {
54  return LMatrix4d::ident_mat();
55  }
56 
57  EggJointPointer *joint;
58  DCAST_INTO_R(joint, back, LMatrix4d::ident_mat());
59 
60  return joint->get_frame(n);
61 }
62 
63 /**
64  * Returns the complete transform from the root corresponding to this joint
65  * position in the nth frame in the indicated model.
66  */
67 LMatrix4d EggJointData::
68 get_net_frame(int model_index, int n, EggCharacterDb &db) const {
69  EggBackPointer *back = get_model(model_index);
70  if (back == nullptr) {
71  return LMatrix4d::ident_mat();
72  }
73 
74  EggJointPointer *joint;
75  DCAST_INTO_R(joint, back, LMatrix4d::ident_mat());
76 
77  LMatrix4d mat;
78  if (!db.get_matrix(joint, EggCharacterDb::TT_net_frame, n, mat)) {
79  // Compute this frame's net, and stuff it in.
80  mat = get_frame(model_index, n);
81  if (_parent != nullptr) {
82  mat = mat * _parent->get_net_frame(model_index, n, db);
83  }
84  db.set_matrix(joint, EggCharacterDb::TT_net_frame, n, mat);
85  }
86 
87  return mat;
88 }
89 
90 /**
91  * Returns the inverse of get_net_frame().
92  */
93 LMatrix4d EggJointData::
94 get_net_frame_inv(int model_index, int n, EggCharacterDb &db) const {
95  EggBackPointer *back = get_model(model_index);
96  if (back == nullptr) {
97  return LMatrix4d::ident_mat();
98  }
99 
100  EggJointPointer *joint;
101  DCAST_INTO_R(joint, back, LMatrix4d::ident_mat());
102 
103  LMatrix4d mat;
104  if (!db.get_matrix(joint, EggCharacterDb::TT_net_frame_inv, n, mat)) {
105  // Compute this frame's net inverse, and stuff it in.
106  LMatrix4d mat = get_net_frame(model_index, n, db);
107  mat.invert_in_place();
108  db.set_matrix(joint, EggCharacterDb::TT_net_frame_inv, n, mat);
109  }
110 
111  return mat;
112 }
113 
114 /**
115  * Forces all of the joints to have the same rest frame value as the first
116  * joint read in. This is a drastic way to repair models whose rest frame
117  * values are completely bogus, but should not be performed on models that are
118  * otherwise correct.
119  */
122  if (!has_rest_frame()) {
123  return;
124  }
125  int num_models = get_num_models();
126  for (int model_index = 0; model_index < num_models; model_index++) {
127  if (has_model(model_index)) {
128  EggJointPointer *joint;
129  DCAST_INTO_V(joint, get_model(model_index));
130  if (joint->is_of_type(EggJointNodePointer::get_class_type())) {
131  joint->set_frame(0, get_rest_frame());
132  }
133  }
134  }
135  _rest_frames_differ = false;
136 }
137 
138 /**
139  * Moves the vertices assigned to this joint into the indicated joint, without
140  * changing their weight assignments.
141  */
143 move_vertices_to(EggJointData *new_owner) {
144  int num_models = get_num_models();
145 
146  if (new_owner == nullptr) {
147  for (int model_index = 0; model_index < num_models; model_index++) {
148  if (has_model(model_index)) {
149  EggJointPointer *joint;
150  DCAST_INTO_V(joint, get_model(model_index));
151  joint->move_vertices_to(nullptr);
152  }
153  }
154  } else {
155  for (int model_index = 0; model_index < num_models; model_index++) {
156  if (has_model(model_index) && new_owner->has_model(model_index)) {
157  EggJointPointer *joint, *new_joint;
158  DCAST_INTO_V(joint, get_model(model_index));
159  DCAST_INTO_V(new_joint, new_owner->get_model(model_index));
160  joint->move_vertices_to(new_joint);
161  }
162  }
163  }
164 }
165 
166 /**
167  * Computes a score >= 0 reflecting the similarity of the current joint's
168  * animation (in world space) to that of the indicated potential parent joint
169  * (in world space). The lower the number, the more similar the motion, and
170  * the more suitable is the proposed parent-child relationship. Returns -1 if
171  * there is an error.
172  */
176  // If we don't have compression compiled in, we can't meaningfully score
177  // the joints.
178  return -1;
179  }
180 
181  // First, build up a big array of the new transforms this joint would
182  // receive in all frames of all models, were it reparented to the indicated
183  // joint.
184  vector_stdfloat i, j, k, a, b, c, x, y, z;
185  pvector<LVecBase3> hprs;
186  int num_rows = 0;
187 
188  int num_models = get_num_models();
189  for (int model_index = 0; model_index < num_models; model_index++) {
190  EggBackPointer *back = get_model(model_index);
191  if (back != nullptr) {
192  EggJointPointer *joint;
193  DCAST_INTO_R(joint, back, false);
194 
195  int num_frames = get_num_frames(model_index);
196  for (int n = 0; n < num_frames; n++) {
197  LMatrix4d transform;
198  if (_parent == new_parent) {
199  // We already have this parent.
200  transform = LMatrix4d::ident_mat();
201 
202  } else if (_parent == nullptr) {
203  // We are moving from outside the joint hierarchy to within it.
204  transform = new_parent->get_net_frame_inv(model_index, n, db);
205 
206  } else if (new_parent == nullptr) {
207  // We are moving from within the hierarchy to outside it.
208  transform = _parent->get_net_frame(model_index, n, db);
209 
210  } else {
211  // We are changing parents within the hierarchy.
212  transform =
213  _parent->get_net_frame(model_index, n, db) *
214  new_parent->get_net_frame_inv(model_index, n, db);
215  }
216 
217  transform = joint->get_frame(n) * transform;
218  LVecBase3d scale, shear, hpr, translate;
219  if (!decompose_matrix(transform, scale, shear, hpr, translate)) {
220  // Invalid transform.
221  return -1;
222  }
223  i.push_back(scale[0]);
224  j.push_back(scale[1]);
225  k.push_back(scale[2]);
226  a.push_back(shear[0]);
227  b.push_back(shear[1]);
228  c.push_back(shear[2]);
229  hprs.push_back(LCAST(PN_stdfloat, hpr));
230  x.push_back(translate[0]);
231  y.push_back(translate[1]);
232  z.push_back(translate[2]);
233  num_rows++;
234  }
235  }
236  }
237 
238  if (num_rows == 0) {
239  // No data, no score.
240  return -1;
241  }
242 
243  // Now, we derive a score, by the simple expedient of using the
244  // FFTCompressor to compress the generated transforms, and measuring the
245  // length of the resulting bitstream.
246  FFTCompressor compressor;
247  Datagram dg;
248  compressor.write_reals(dg, &i[0], num_rows);
249  compressor.write_reals(dg, &j[0], num_rows);
250  compressor.write_reals(dg, &k[0], num_rows);
251  compressor.write_reals(dg, &a[0], num_rows);
252  compressor.write_reals(dg, &b[0], num_rows);
253  compressor.write_reals(dg, &c[0], num_rows);
254  compressor.write_hprs(dg, &hprs[0], num_rows);
255  compressor.write_reals(dg, &x[0], num_rows);
256  compressor.write_reals(dg, &y[0], num_rows);
257  compressor.write_reals(dg, &z[0], num_rows);
258 
259 
260 #ifndef HAVE_ZLIB
261  return dg.get_length();
262 
263 #else
264  // The FFTCompressor does minimal run-length encoding, but to really get an
265  // accurate measure we should zlib-compress the resulting stream.
266  std::ostringstream sstr;
267  OCompressStream zstr(&sstr, false);
268  zstr.write((const char *)dg.get_data(), dg.get_length());
269  zstr.flush();
270  return sstr.str().length();
271 #endif
272 }
273 
274 /**
275  * Calls do_rebuild() on all models, and recursively on all joints at this
276  * node and below. Returns true if all models returned true, false otherwise.
277  */
280  bool all_ok = true;
281 
282  BackPointers::iterator bpi;
283  for (bpi = _back_pointers.begin(); bpi != _back_pointers.end(); ++bpi) {
284  EggBackPointer *back = (*bpi);
285  if (back != nullptr) {
286  EggJointPointer *joint;
287  DCAST_INTO_R(joint, back, false);
288  if (!joint->do_rebuild(db)) {
289  all_ok = false;
290  }
291  }
292  }
293 
294  Children::iterator ci;
295  for (ci = _children.begin(); ci != _children.end(); ++ci) {
296  EggJointData *child = (*ci);
297  if (!child->do_rebuild_all(db)) {
298  all_ok = false;
299  }
300  }
301 
302  return all_ok;
303 }
304 
305 /**
306  * Calls optimize() on all models, and recursively on all joints at this node
307  * and below.
308  */
310 optimize() {
311  BackPointers::iterator bpi;
312  for (bpi = _back_pointers.begin(); bpi != _back_pointers.end(); ++bpi) {
313  EggBackPointer *back = (*bpi);
314  if (back != nullptr) {
315  EggJointPointer *joint;
316  DCAST_INTO_V(joint, back);
317  joint->optimize();
318  }
319  }
320 
321  Children::iterator ci;
322  for (ci = _children.begin(); ci != _children.end(); ++ci) {
323  EggJointData *child = (*ci);
324  child->optimize();
325  }
326 }
327 
328 /**
329  * Calls expose() on all models for this joint, but does not recurse
330  * downwards.
331  */
333 expose(EggGroup::DCSType dcs_type) {
334  BackPointers::iterator bpi;
335  for (bpi = _back_pointers.begin(); bpi != _back_pointers.end(); ++bpi) {
336  EggBackPointer *back = (*bpi);
337  if (back != nullptr) {
338  EggJointPointer *joint;
339  DCAST_INTO_V(joint, back);
340  joint->expose(dcs_type);
341  }
342  }
343 }
344 
345 /**
346  * Calls zero_channels() on all models for this joint, but does not recurse
347  * downwards.
348  */
350 zero_channels(const string &components) {
351  BackPointers::iterator bpi;
352  for (bpi = _back_pointers.begin(); bpi != _back_pointers.end(); ++bpi) {
353  EggBackPointer *back = (*bpi);
354  if (back != nullptr) {
355  EggJointPointer *joint;
356  DCAST_INTO_V(joint, back);
357  joint->zero_channels(components);
358  }
359  }
360 }
361 
362 /**
363  * Calls quantize_channels() on all models for this joint, and then recurses
364  * downwards to all joints below.
365  */
367 quantize_channels(const string &components, double quantum) {
368  BackPointers::iterator bpi;
369  for (bpi = _back_pointers.begin(); bpi != _back_pointers.end(); ++bpi) {
370  EggBackPointer *back = (*bpi);
371  if (back != nullptr) {
372  EggJointPointer *joint;
373  DCAST_INTO_V(joint, back);
374  joint->quantize_channels(components, quantum);
375  }
376  }
377 
378  Children::iterator ci;
379  for (ci = _children.begin(); ci != _children.end(); ++ci) {
380  EggJointData *child = (*ci);
381  child->quantize_channels(components, quantum);
382  }
383 }
384 
385 /**
386  * Applies the pose from the indicated frame of the indicated source
387  * model_index as the initial pose for this joint, and does this recursively
388  * on all joints below.
389  */
391 apply_default_pose(int source_model, int frame) {
392  if (has_model(source_model)) {
393  EggJointPointer *source_joint;
394  DCAST_INTO_V(source_joint, _back_pointers[source_model]);
395  BackPointers::iterator bpi;
396  for (bpi = _back_pointers.begin(); bpi != _back_pointers.end(); ++bpi) {
397  EggBackPointer *back = (*bpi);
398  if (back != nullptr) {
399  EggJointPointer *joint;
400  DCAST_INTO_V(joint, back);
401  joint->apply_default_pose(source_joint, frame);
402  }
403  }
404  }
405 
406  Children::iterator ci;
407  for (ci = _children.begin(); ci != _children.end(); ++ci) {
408  EggJointData *child = (*ci);
409  child->apply_default_pose(source_model, frame);
410  }
411 }
412 
413 /**
414  * Adds the indicated model joint or anim table to the data.
415  */
417 add_back_pointer(int model_index, EggObject *egg_object) {
418  nassertv(egg_object != nullptr);
419  if (egg_object->is_of_type(EggGroup::get_class_type())) {
420  // It must be a <Joint>.
421  EggJointNodePointer *joint = new EggJointNodePointer(egg_object);
422  set_model(model_index, joint);
423  if (!_has_rest_frame) {
424  _rest_frame = joint->get_frame(0);
425  _has_rest_frame = true;
426 
427  } else {
428  // If this new node doesn't come within an acceptable tolerance of our
429  // first reading of this joint's rest frame, set a warning flag.
430  if (!_rest_frame.almost_equal(joint->get_frame(0), 0.0001)) {
431  _rest_frames_differ = true;
432  }
433  }
434 
435  } else if (egg_object->is_of_type(EggTable::get_class_type())) {
436  // It's a <Table> with an "xform" child beneath it.
437  EggMatrixTablePointer *xform = new EggMatrixTablePointer(egg_object);
438  set_model(model_index, xform);
439 
440  } else {
441  nout << "Invalid object added to joint for back pointer.\n";
442  }
443 }
444 
445 /**
446  *
447  */
448 void EggJointData::
449 write(std::ostream &out, int indent_level) const {
450  indent(out, indent_level)
451  << "Joint " << get_name()
452  << " (models:";
453  int num_models = get_num_models();
454  for (int model_index = 0; model_index < num_models; model_index++) {
455  if (has_model(model_index)) {
456  out << " " << model_index;
457  }
458  }
459  out << ") {\n";
460 
461  Children::const_iterator ci;
462  for (ci = _children.begin(); ci != _children.end(); ++ci) {
463  (*ci)->write(out, indent_level + 2);
464  }
465 
466  indent(out, indent_level) << "}\n";
467 }
468 
469 /**
470  * Clears out the _children vector in preparation for refilling it from the
471  * _new_parent information.
472  */
473 void EggJointData::
474 do_begin_reparent() {
475  _got_new_parent_depth = false;
476  _children.clear();
477 }
478 
479 /**
480  * Calculates the number of joints above this joint in its intended position,
481  * as specified by a recent call to reparent_to(), and also checks for a cycle
482  * in the new parent chain. Returns true if a cycle is detected, and false
483  * otherwise. If a cycle is not detected, _new_parent_depth can be consulted
484  * for the depth in the new hierarchy.
485  *
486  * This is used by EggCharacterData::do_reparent() to determine the order in
487  * which to apply the reparent operations. It should be called after
488  * do_begin_reparent().
489  */
490 bool EggJointData::
491 calc_new_parent_depth(pset<EggJointData *> &chain) {
492  if (_got_new_parent_depth) {
493  return false;
494  }
495  if (_new_parent == nullptr) {
496  // Here's the top of the new hierarchy.
497  _got_new_parent_depth = true;
498  _new_parent_depth = 0;
499  return false;
500  }
501  if (!chain.insert(this).second) {
502  // We've already visited this joint; that means there's a cycle.
503  return true;
504  }
505  bool cycle = _new_parent->calc_new_parent_depth(chain);
506  _new_parent_depth = _new_parent->_new_parent_depth + 1;
507  return cycle;
508 }
509 
510 /**
511  * Eliminates any cached values before beginning a walk through all the joints
512  * for do_compute_reparent(), for a given model/frame.
513  */
514 void EggJointData::
515 do_begin_compute_reparent() {
516  _got_new_net_frame = false;
517  _got_new_net_frame_inv = false;
518  _computed_reparent = false;
519 }
520 
521 /**
522  * Prepares the reparent operation by computing a new transform for each frame
523  * of each model, designed to keep the net transform the same when the joint
524  * is moved to its new parent. Returns true on success, false on failure.
525  */
526 bool EggJointData::
527 do_compute_reparent(int model_index, int n, EggCharacterDb &db) {
528  if (_computed_reparent) {
529  // We've already done this joint. This is possible because we have to
530  // recursively compute joints upwards, so we might visit the same joint
531  // more than once.
532  return _computed_ok;
533  }
534  _computed_reparent = true;
535 
536  if (_parent == _new_parent) {
537  // Trivial (and most common) case: we are not moving the joint. No
538  // recomputation necessary.
539  _computed_ok = true;
540  return true;
541  }
542 
543  EggBackPointer *back = get_model(model_index);
544  if (back == nullptr) {
545  // This joint doesn't have any data to modify.
546  _computed_ok = true;
547  return true;
548  }
549 
550  EggJointPointer *joint;
551  DCAST_INTO_R(joint, back, false);
552 
553  LMatrix4d transform;
554  if (_parent == nullptr) {
555  // We are moving from outside the joint hierarchy to within it.
556  transform = _new_parent->get_new_net_frame_inv(model_index, n, db);
557 
558  } else if (_new_parent == nullptr) {
559  // We are moving from within the hierarchy to outside it.
560  transform = _parent->get_net_frame(model_index, n, db);
561 
562  } else {
563  // We are changing parents within the hierarchy.
564  transform =
565  _parent->get_net_frame(model_index, n, db) *
566  _new_parent->get_new_net_frame_inv(model_index, n, db);
567  }
568 
569  db.set_matrix(joint, EggCharacterDb::TT_rebuild_frame, n,
570  joint->get_frame(n) * transform);
571  _computed_ok = true;
572 
573  return _computed_ok;
574 }
575 
576 /**
577  * Calls do_rebuild() on the joint for the indicated model index. Returns
578  * true on success, false on failure (false shouldn't be possible).
579  */
580 bool EggJointData::
581 do_joint_rebuild(int model_index, EggCharacterDb &db) {
582  bool all_ok = true;
583 
584  EggJointPointer *parent_joint = nullptr;
585  if (_new_parent != nullptr && _new_parent->has_model(model_index)) {
586  DCAST_INTO_R(parent_joint, _new_parent->get_model(model_index), false);
587  }
588 
589  if (has_model(model_index)) {
590  EggJointPointer *joint;
591  DCAST_INTO_R(joint, get_model(model_index), false);
592  if (!joint->do_rebuild(db)) {
593  all_ok = false;
594  }
595  }
596 
597  return all_ok;
598 }
599 
600 /**
601  * Performs the actual reparenting operation by removing all of the old
602  * children and replacing them with the set of new children.
603  */
604 void EggJointData::
605 do_finish_reparent() {
606  int num_models = get_num_models();
607  for (int model_index = 0; model_index < num_models; model_index++) {
608  EggJointPointer *parent_joint = nullptr;
609  if (_new_parent != nullptr && _new_parent->has_model(model_index)) {
610  DCAST_INTO_V(parent_joint, _new_parent->get_model(model_index));
611  }
612 
613  if (has_model(model_index)) {
614  EggJointPointer *joint;
615  DCAST_INTO_V(joint, get_model(model_index));
616  joint->do_finish_reparent(parent_joint);
617  }
618  }
619 
620  _parent = _new_parent;
621  if (_parent != nullptr) {
622  _parent->_children.push_back(this);
623  }
624 }
625 
626 /**
627  * Creates a new joint as a child of this joint and returns it. This is
628  * intended to be called only from EggCharacterData::make_new_joint().
629  */
630 EggJointData *EggJointData::
631 make_new_joint(const string &name) {
632  EggJointData *child = new EggJointData(_collection, _char_data);
633  child->set_name(name);
634  child->_parent = this;
635  child->_new_parent = this;
636  _children.push_back(child);
637 
638  // Also create new back pointers in each of the models.
639  int num_models = get_num_models();
640  for (int i = 0; i < num_models; i++) {
641  if (has_model(i)) {
642  EggJointPointer *joint;
643  DCAST_INTO_R(joint, get_model(i), nullptr);
644  EggJointPointer *new_joint = joint->make_new_joint(name);
645  child->set_model(i, new_joint);
646  }
647  }
648 
649  return child;
650 }
651 
652 /**
653  * The recursive implementation of find_joint, this flavor searches
654  * recursively for an exact match of the preferred joint name.
655  */
656 EggJointData *EggJointData::
657 find_joint_exact(const string &name) {
658  Children::const_iterator ci;
659  for (ci = _children.begin(); ci != _children.end(); ++ci) {
660  EggJointData *child = (*ci);
661  if (child->get_name() == name) {
662  return child;
663  }
664  EggJointData *result = child->find_joint_exact(name);
665  if (result != nullptr) {
666  return result;
667  }
668  }
669 
670  return nullptr;
671 }
672 
673 /**
674  * The recursive implementation of find_joint, this flavor searches
675  * recursively for any acceptable match.
676  */
677 EggJointData *EggJointData::
678 find_joint_matches(const string &name) {
679  Children::const_iterator ci;
680  for (ci = _children.begin(); ci != _children.end(); ++ci) {
681  EggJointData *child = (*ci);
682  if (child->matches_name(name)) {
683  return child;
684  }
685  EggJointData *result = child->find_joint_matches(name);
686  if (result != nullptr) {
687  return result;
688  }
689  }
690 
691  return nullptr;
692 }
693 
694 /**
695  * Returns true if this joint is an ancestor of the indicated joint, in the
696  * "new" hierarchy (that is, the one defined by _new_parent, as set by
697  * reparent_to() before do_finish_reparent() is called).
698  */
699 bool EggJointData::
700 is_new_ancestor(EggJointData *child) const {
701  if (child == this) {
702  return true;
703  }
704 
705  if (child->_new_parent == nullptr) {
706  return false;
707  }
708 
709  return is_new_ancestor(child->_new_parent);
710 }
711 
712 /**
713  * Similar to get_net_frame(), but computed for the prospective new parentage
714  * of the node, before do_finish_reparent() is called. This is generally
715  * useful only when called within do_compute_reparent().
716  */
717 const LMatrix4d &EggJointData::
718 get_new_net_frame(int model_index, int n, EggCharacterDb &db) {
719  if (!_got_new_net_frame) {
720  _new_net_frame = get_new_frame(model_index, n, db);
721  if (_new_parent != nullptr) {
722  _new_net_frame = _new_net_frame * _new_parent->get_new_net_frame(model_index, n, db);
723  }
724  _got_new_net_frame = true;
725  }
726  return _new_net_frame;
727 }
728 
729 /**
730  * Returns the inverse of get_new_net_frame().
731  */
732 const LMatrix4d &EggJointData::
733 get_new_net_frame_inv(int model_index, int n, EggCharacterDb &db) {
734  if (!_got_new_net_frame_inv) {
735  _new_net_frame_inv.invert_from(get_new_frame(model_index, n, db));
736  if (_new_parent != nullptr) {
737  _new_net_frame_inv = _new_parent->get_new_net_frame_inv(model_index, n, db) * _new_net_frame_inv;
738  }
739  _got_new_net_frame_inv = true;
740  }
741  return _new_net_frame_inv;
742 }
743 
744 /**
745  * Returns the local transform matrix corresponding to this joint position in
746  * the nth frame in the indicated model, as it will be when
747  * do_finish_reparent() is called.
748  */
749 LMatrix4d EggJointData::
750 get_new_frame(int model_index, int n, EggCharacterDb &db) {
751  do_compute_reparent(model_index, n, db);
752 
753  EggBackPointer *back = get_model(model_index);
754  if (back == nullptr) {
755  return LMatrix4d::ident_mat();
756  }
757 
758  EggJointPointer *joint;
759  DCAST_INTO_R(joint, back, LMatrix4d::ident_mat());
760 
761  LMatrix4d mat;
762  if (!db.get_matrix(joint, EggCharacterDb::TT_rebuild_frame, n, mat)) {
763  // No rebuild frame; return the regular frame.
764  return joint->get_frame(n);
765  }
766 
767  // Return the rebuild frame, as computed.
768  return mat;
769 }
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
size_t get_length() const
Returns the number of bytes in the datagram.
Definition: datagram.I:335
const void * get_data() const
Returns a pointer to the beginning of the datagram's data.
Definition: datagram.I:327
This stores a pointer from an EggJointData or EggSliderData object back to the referencing data in an...
Represents a set of characters, as read and collected from possibly several model and/or animation eg...
Represents a single character, as read and collected from several models and animation files.
This class is used during joint optimization or restructuring to store the table of interim joint com...
void set_matrix(const EggJointPointer *joint, TableType type, int frame, const LMatrix4d &mat)
Stores the matrix for the indicated joint, type, and frame in the database.
bool get_matrix(const EggJointPointer *joint, TableType type, int frame, LMatrix4d &mat) const
Looks up the data for the indicated joint, type, and frame, and fills it in result (and returns true)...
This is the base class of both EggJointData and EggSliderData.
int get_num_frames(int model_index) const
Returns the number of frames of animation for this particular component in the indicated model.
EggBackPointer * get_model(int model_index) const
Returns the back pointer to an egg file for the indicated model if it exists, or NULL if it does not.
int get_num_models() const
Returns the maximum number of back pointers this component may have.
bool matches_name(const std::string &name) const
Returns true if the indicated name matches any name that was ever matched with this particular joint,...
bool has_model(int model_index) const
Returns true if the component has a back pointer to an egg file somewhere for the indicated model,...
void set_model(int model_index, EggBackPointer *back)
Sets the back_pointer associated with the given model_index.
This is one node of a hierarchy of EggJointData nodes, each of which represents a single joint of the...
Definition: eggJointData.h:31
int score_reparent_to(EggJointData *new_parent, EggCharacterDb &db)
Computes a score >= 0 reflecting the similarity of the current joint's animation (in world space) to ...
virtual void add_back_pointer(int model_index, EggObject *egg_object)
Adds the indicated model joint or anim table to the data.
const LMatrix4d & get_rest_frame() const
Returns the rest frame of the joint.
Definition: eggJointData.I:79
LMatrix4d get_net_frame(int model_index, int n, EggCharacterDb &db) const
Returns the complete transform from the root corresponding to this joint position in the nth frame in...
void move_vertices_to(EggJointData *new_owner)
Moves the vertices assigned to this joint into the indicated joint, without changing their weight ass...
void optimize()
Calls optimize() on all models, and recursively on all joints at this node and below.
void expose(EggGroup::DCSType dcs_type=EggGroup::DC_default)
Calls expose() on all models for this joint, but does not recurse downwards.
bool has_rest_frame() const
Returns true if the joint knows its rest frame, false otherwise.
Definition: eggJointData.I:59
bool do_rebuild_all(EggCharacterDb &db)
Calls do_rebuild() on all models, and recursively on all joints at this node and below.
LMatrix4d get_net_frame_inv(int model_index, int n, EggCharacterDb &db) const
Returns the inverse of get_net_frame().
void zero_channels(const std::string &components)
Calls zero_channels() on all models for this joint, but does not recurse downwards.
void force_initial_rest_frame()
Forces all of the joints to have the same rest frame value as the first joint read in.
void quantize_channels(const std::string &components, double quantum)
Calls quantize_channels() on all models for this joint, and then recurses downwards to all joints bel...
LMatrix4d get_frame(int model_index, int n) const
Returns the local transform matrix corresponding to this joint position in the nth frame in the indic...
void apply_default_pose(int source_model, int frame)
Applies the pose from the indicated frame of the indicated source model_index as the initial pose for...
This stores a pointer back to a <Joint> node.
virtual LMatrix4d get_frame(int n) const
Returns the transform matrix corresponding to this joint position in the nth frame.
This is a base class for EggJointNodePointer and EggMatrixTablePointer.
virtual void zero_channels(const std::string &components)
Zeroes out the named components of the transform in the animation frames.
virtual void optimize()
Resets the table before writing to disk so that redundant rows (e.g.
virtual void apply_default_pose(EggJointPointer *source_joint, int frame)
Applies the pose from the indicated frame of the indicated source joint as the initial pose for this ...
virtual void expose(EggGroup::DCSType dcs_type)
Flags the joint with the indicated DCS flag so that it will be loaded as a separate node in the playe...
virtual void move_vertices_to(EggJointPointer *new_joint)
Moves the vertices assigned to this joint into the other joint (which should be of the same type).
virtual bool do_rebuild(EggCharacterDb &db)
Rebuilds the entire table all at once, based on the frames added by repeated calls to add_rebuild_fra...
virtual void quantize_channels(const std::string &components, double quantum)
Rounds the named components of the transform to the nearest multiple of quantum.
This stores a pointer back to an EggXfmSAnim table (i.e.
The highest-level base class in the egg directory.
Definition: eggObject.h:29
This class manages a lossy compression and decompression of a stream of floating-point numbers to a d...
Definition: fftCompressor.h:40
static bool is_compression_available()
Returns true if the FFTW library is compiled in, so that this class is actually capable of doing usef...
void write_reals(Datagram &datagram, const PN_stdfloat *array, int length)
Writes an array of floating-point numbers to the indicated datagram.
void write_hprs(Datagram &datagram, const LVecBase3 *array, int length)
Writes an array of HPR angles to the indicated datagram.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
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 our own Panda specialization on the default STL set.
Definition: pset.h:49
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
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.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.