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  */
120 void EggJointData::
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  */
142 void EggJointData::
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  */
173 int EggJointData::
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  */
278 bool EggJointData::
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  */
309 void EggJointData::
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  */
332 void EggJointData::
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  */
349 void EggJointData::
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  */
366 void EggJointData::
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  */
390 void EggJointData::
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  */
416 void EggJointData::
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 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual void optimize()
Resets the table before writing to disk so that redundant rows (e.g.
int get_num_frames(int model_index) const
Returns the number of frames of animation for this particular component in the indicated model.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_model(int model_index, EggBackPointer *back)
Sets the back_pointer associated with the given model_index.
void optimize()
Calls optimize() on all models, and recursively on all joints at this node and below.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual LMatrix4d get_frame(int n) const
Returns the transform matrix corresponding to this joint position in the nth frame.
int get_num_models() const
Returns the maximum number of back pointers this component may have.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
This class manages a lossy compression and decompression of a stream of floating-point numbers to a d...
Definition: fftCompressor.h:40
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the base class of both EggJointData and EggSliderData.
LMatrix4d get_net_frame_inv(int model_index, int n, EggCharacterDb &db) const
Returns the inverse of get_net_frame().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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).
This stores a pointer back to a <Joint> node.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class is used during joint optimization or restructuring to store the table of interim joint com...
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
bool has_rest_frame() const
Returns true if the joint knows its rest frame, false otherwise.
Definition: eggJointData.I:59
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.
virtual void quantize_channels(const std::string &components, double quantum)
Rounds the named components of the transform to the nearest multiple of quantum.
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...
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 ...
This is a base class for EggJointNodePointer and EggMatrixTablePointer.
void move_vertices_to(EggJointData *new_owner)
Moves the vertices assigned to this joint into the indicated joint, without changing their weight ass...
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,...
Represents a set of characters, as read and collected from possibly several model and/or animation eg...
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,...
Represents a single character, as read and collected from several models and animation files.
void write_reals(Datagram &datagram, const PN_stdfloat *array, int length)
Writes an array of floating-point numbers to the indicated datagram.
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 ...
const LMatrix4d & get_rest_frame() const
Returns the rest frame of the joint.
Definition: eggJointData.I:79
This is one node of a hierarchy of EggJointData nodes, each of which represents a single joint of the...
Definition: eggJointData.h:31
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 add_back_pointer(int model_index, EggObject *egg_object)
Adds the indicated model joint or anim table to the data.
This stores a pointer back to an EggXfmSAnim table (i.e.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void force_initial_rest_frame()
Forces all of the joints to have the same rest frame value as the first joint read in.
virtual void zero_channels(const std::string &components)
Zeroes out the named components of the transform in the animation frames.
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 zero_channels(const std::string &components)
Calls zero_channels() on all models for this joint, but does not recurse downwards.
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...
void write_hprs(Datagram &datagram, const LVecBase3 *array, int length)
Writes an array of HPR angles to the indicated datagram.
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...
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
bool do_rebuild_all(EggCharacterDb &db)
Calls do_rebuild() on all models, and recursively on all joints at this node and below.
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
This stores a pointer from an EggJointData or EggSliderData object back to the referencing data in an...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
void expose(EggGroup::DCSType dcs_type=EggGroup::DC_default)
Calls expose() on all models for this joint, but does not recurse downwards.
The highest-level base class in the egg directory.
Definition: eggObject.h:29
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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)...
static bool is_compression_available()
Returns true if the FFTW library is compiled in, so that this class is actually capable of doing usef...
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