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