Panda3D
Loading...
Searching...
No Matches
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"
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
27using std::string;
28
29TypeHandle EggJointData::_type_handle;
30
31
32/**
33 *
34 */
35EggJointData::
36EggJointData(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 */
51get_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 */
68get_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 */
94get_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 */
143move_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;
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 */
310optimize() {
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 */
333expose(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 */
350zero_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 */
367quantize_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 */
391apply_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 */
417add_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 */
448void EggJointData::
449write(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 */
473void EggJointData::
474do_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 */
490bool EggJointData::
491calc_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 */
514void EggJointData::
515do_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 */
526bool EggJointData::
527do_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 */
580bool EggJointData::
581do_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 */
604void EggJointData::
605do_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 */
630EggJointData *EggJointData::
631make_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 */
656EggJointData *EggJointData::
657find_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 */
677EggJointData *EggJointData::
678find_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 */
699bool EggJointData::
700is_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 */
717const LMatrix4d &EggJointData::
718get_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 */
732const LMatrix4d &EggJointData::
733get_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 */
749LMatrix4d EggJointData::
750get_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...
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.
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.
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...
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.