00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "transformState.h"
00016 #include "compose_matrix.h"
00017 #include "bamReader.h"
00018 #include "bamWriter.h"
00019 #include "datagramIterator.h"
00020 #include "indent.h"
00021 #include "compareTo.h"
00022 #include "pStatTimer.h"
00023 #include "config_pgraph.h"
00024 #include "lightReMutexHolder.h"
00025 #include "lightMutexHolder.h"
00026 #include "thread.h"
00027 #include "py_panda.h"
00028
00029 LightReMutex *TransformState::_states_lock = NULL;
00030 TransformState::States *TransformState::_states = NULL;
00031 CPT(TransformState) TransformState::_identity_state;
00032 CPT(TransformState) TransformState::_invalid_state;
00033 UpdateSeq TransformState::_last_cycle_detect;
00034 int TransformState::_garbage_index = 0;
00035
00036 PStatCollector TransformState::_cache_update_pcollector("*:State Cache:Update");
00037 PStatCollector TransformState::_garbage_collect_pcollector("*:State Cache:Garbage Collect");
00038 PStatCollector TransformState::_transform_compose_pcollector("*:State Cache:Compose Transform");
00039 PStatCollector TransformState::_transform_invert_pcollector("*:State Cache:Invert Transform");
00040 PStatCollector TransformState::_transform_calc_pcollector("*:State Cache:Calc Components");
00041 PStatCollector TransformState::_transform_break_cycles_pcollector("*:State Cache:Break Cycles");
00042 PStatCollector TransformState::_transform_new_pcollector("*:State Cache:New");
00043 PStatCollector TransformState::_transform_validate_pcollector("*:State Cache:Validate");
00044 PStatCollector TransformState::_transform_hash_pcollector("*:State Cache:Calc Hash");
00045 PStatCollector TransformState::_node_counter("TransformStates:On nodes");
00046 PStatCollector TransformState::_cache_counter("TransformStates:Cached");
00047
00048 CacheStats TransformState::_cache_stats;
00049
00050 TypeHandle TransformState::_type_handle;
00051
00052
00053
00054
00055
00056
00057
00058
00059 TransformState::
00060 TransformState() : _lock("TransformState") {
00061 if (_states == (States *)NULL) {
00062 init_states();
00063 }
00064 _saved_entry = -1;
00065 _flags = F_is_identity | F_singular_known | F_is_2d;
00066 _inv_mat = (LMatrix4 *)NULL;
00067 _cache_stats.add_num_states(1);
00068 }
00069
00070
00071
00072
00073
00074
00075 TransformState::
00076 TransformState(const TransformState &) {
00077 nassertv(false);
00078 }
00079
00080
00081
00082
00083
00084
00085 void TransformState::
00086 operator = (const TransformState &) {
00087 nassertv(false);
00088 }
00089
00090
00091
00092
00093
00094
00095
00096 TransformState::
00097 ~TransformState() {
00098
00099 nassertv(!is_destructing());
00100 set_destructing();
00101
00102
00103 if (_inv_mat != (LMatrix4 *)NULL) {
00104 delete _inv_mat;
00105 _inv_mat = (LMatrix4 *)NULL;
00106 }
00107
00108 LightReMutexHolder holder(*_states_lock);
00109
00110
00111 nassertv(_saved_entry == -1);
00112 nassertv(_composition_cache.is_empty() && _invert_composition_cache.is_empty());
00113
00114
00115
00116 nassertv(get_ref_count() == 0);
00117 _cache_stats.add_num_states(-1);
00118 }
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 int TransformState::
00134 compare_to(const TransformState &other, bool uniquify_matrix) const {
00135 static const int significant_flags =
00136 (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_quat_given | F_is_2d);
00137
00138 int flags = (_flags & significant_flags);
00139 int other_flags = (other._flags & significant_flags);
00140 if (flags != other_flags) {
00141 return flags < other_flags ? -1 : 1;
00142 }
00143
00144 if ((_flags & (F_is_invalid | F_is_identity)) != 0) {
00145
00146
00147 return 0;
00148 }
00149
00150 if ((_flags & F_components_given) != 0) {
00151
00152
00153 int c = _pos.compare_to(other._pos);
00154 if (c != 0) {
00155 return c;
00156 }
00157
00158 if ((_flags & F_hpr_given) != 0) {
00159 c = _hpr.compare_to(other._hpr);
00160 if (c != 0) {
00161 return c;
00162 }
00163 } else if ((_flags & F_quat_given) != 0) {
00164 c = _quat.compare_to(other._quat);
00165 if (c != 0) {
00166 return c;
00167 }
00168 }
00169
00170 c = _scale.compare_to(other._scale);
00171 if (c != 0) {
00172 return c;
00173 }
00174
00175 c = _shear.compare_to(other._shear);
00176 return c;
00177 }
00178
00179
00180 if (uniquify_matrix) {
00181
00182
00183 return get_mat().compare_to(other.get_mat());
00184
00185 } else {
00186
00187 if (this != &other) {
00188 return (this < &other) ? -1 : 1;
00189 }
00190 return 0;
00191 }
00192 }
00193
00194
00195
00196
00197
00198
00199 CPT(TransformState) TransformState::
00200 make_identity() {
00201
00202
00203 if (_identity_state == (TransformState *)NULL) {
00204 TransformState *state = new TransformState;
00205 _identity_state = return_unique(state);
00206 }
00207
00208 return _identity_state;
00209 }
00210
00211
00212
00213
00214
00215
00216
00217 CPT(TransformState) TransformState::
00218 make_invalid() {
00219 if (_invalid_state == (TransformState *)NULL) {
00220 TransformState *state = new TransformState;
00221 state->_flags = F_is_invalid | F_singular_known | F_is_singular | F_components_known | F_mat_known;
00222 _invalid_state = return_unique(state);
00223 }
00224
00225 return _invalid_state;
00226 }
00227
00228
00229
00230
00231
00232
00233
00234 CPT(TransformState) TransformState::
00235 make_pos_hpr_scale_shear(const LVecBase3 &pos, const LVecBase3 &hpr,
00236 const LVecBase3 &scale, const LVecBase3 &shear) {
00237 nassertr(!(pos.is_nan() || hpr.is_nan() || scale.is_nan() || shear.is_nan()) , make_invalid());
00238
00239 if (pos == LVecBase3(0.0f, 0.0f, 0.0f) &&
00240 hpr == LVecBase3(0.0f, 0.0f, 0.0f) &&
00241 scale == LVecBase3(1.0f, 1.0f, 1.0f) &&
00242 shear == LVecBase3(0.0f, 0.0f, 0.0f)) {
00243 return make_identity();
00244 }
00245
00246 TransformState *state = new TransformState;
00247 state->_pos = pos;
00248 state->_hpr = hpr;
00249 state->_scale = scale;
00250 state->_shear = shear;
00251 state->_flags = F_components_given | F_hpr_given | F_components_known | F_hpr_known | F_has_components;
00252 state->check_uniform_scale();
00253 return return_new(state);
00254 }
00255
00256
00257
00258
00259
00260
00261
00262 CPT(TransformState) TransformState::
00263 make_pos_quat_scale_shear(const LVecBase3 &pos, const LQuaternion &quat,
00264 const LVecBase3 &scale, const LVecBase3 &shear) {
00265 nassertr(!(pos.is_nan() || quat.is_nan() || scale.is_nan() || shear.is_nan()) , make_invalid());
00266
00267 if (pos == LVecBase3(0.0f, 0.0f, 0.0f) &&
00268 quat == LQuaternion::ident_quat() &&
00269 scale == LVecBase3(1.0f, 1.0f, 1.0f) &&
00270 shear == LVecBase3(0.0f, 0.0f, 0.0f)) {
00271 return make_identity();
00272 }
00273
00274 TransformState *state = new TransformState;
00275 state->_pos = pos;
00276 state->_quat = quat;
00277 state->_scale = scale;
00278 state->_shear = shear;
00279 state->_flags = F_components_given | F_quat_given | F_components_known | F_quat_known | F_has_components;
00280 state->check_uniform_scale();
00281 return return_new(state);
00282 }
00283
00284
00285
00286
00287
00288
00289
00290 CPT(TransformState) TransformState::
00291 make_mat(const LMatrix4 &mat) {
00292 nassertr(!mat.is_nan(), make_invalid());
00293
00294 if (mat == LMatrix4::ident_mat()) {
00295 return make_identity();
00296 }
00297
00298 TransformState *state = new TransformState;
00299 state->_mat = mat;
00300 state->_flags = F_mat_known;
00301 return return_new(state);
00302 }
00303
00304
00305
00306
00307
00308
00309
00310
00311 CPT(TransformState) TransformState::
00312 make_pos_rotate_scale_shear2d(const LVecBase2 &pos, PN_stdfloat rotate,
00313 const LVecBase2 &scale,
00314 PN_stdfloat shear) {
00315 nassertr(!(pos.is_nan() || cnan(rotate) || scale.is_nan() || cnan(shear)) , make_invalid());
00316
00317 if (pos == LVecBase2(0.0f, 0.0f) &&
00318 rotate == 0.0f &&
00319 scale == LVecBase2(1.0f, 1.0f) &&
00320 shear == 0.0f) {
00321 return make_identity();
00322 }
00323
00324 TransformState *state = new TransformState;
00325 state->_pos.set(pos[0], pos[1], 0.0f);
00326 switch (get_default_coordinate_system()) {
00327 default:
00328 case CS_zup_right:
00329 state->_hpr.set(rotate, 0.0f, 0.0f);
00330 break;
00331 case CS_zup_left:
00332 state->_hpr.set(-rotate, 0.0f, 0.0f);
00333 break;
00334 case CS_yup_right:
00335 state->_hpr.set(0.0f, 0.0f, -rotate);
00336 break;
00337 case CS_yup_left:
00338 state->_hpr.set(0.0, 0.0f, rotate);
00339 break;
00340 }
00341 state->_scale.set(scale[0], scale[1], 1.0f);
00342 state->_shear.set(shear, 0.0f, 0.0f);
00343 state->_flags = F_components_given | F_hpr_given | F_components_known | F_hpr_known | F_has_components | F_is_2d;
00344 state->check_uniform_scale2d();
00345 return return_new(state);
00346 }
00347
00348
00349
00350
00351
00352
00353
00354
00355 CPT(TransformState) TransformState::
00356 make_mat3(const LMatrix3 &mat) {
00357 nassertr(!mat.is_nan(), make_invalid());
00358
00359 if (mat == LMatrix3::ident_mat()) {
00360 return make_identity();
00361 }
00362
00363 TransformState *state = new TransformState;
00364 state->_mat.set(mat(0, 0), mat(0, 1), 0.0f, mat(0, 2),
00365 mat(1, 0), mat(1, 1), 0.0f, mat(1, 2),
00366 0.0f, 0.0f, 1.0f, 0.0f,
00367 mat(2, 0), mat(2, 1), 0.0f, mat(2, 2));
00368 state->_flags = F_mat_known | F_is_2d;
00369 return return_new(state);
00370 }
00371
00372
00373
00374
00375
00376
00377
00378
00379 CPT(TransformState) TransformState::
00380 set_pos(const LVecBase3 &pos) const {
00381 nassertr(!pos.is_nan(), this);
00382 nassertr(!is_invalid(), this);
00383 if (is_identity() || components_given()) {
00384
00385
00386 if (quat_given()) {
00387 return make_pos_quat_scale_shear(pos, get_quat(), get_scale(), get_shear());
00388 } else {
00389 return make_pos_hpr_scale_shear(pos, get_hpr(), get_scale(), get_shear());
00390 }
00391
00392 } else {
00393
00394 LMatrix4 mat = get_mat();
00395 mat.set_row(3, pos);
00396 return make_mat(mat);
00397 }
00398 }
00399
00400
00401
00402
00403
00404
00405
00406
00407 CPT(TransformState) TransformState::
00408 set_hpr(const LVecBase3 &hpr) const {
00409 nassertr(!hpr.is_nan(), this);
00410 nassertr(!is_invalid(), this);
00411
00412 return make_pos_hpr_scale_shear(get_pos(), hpr, get_scale(), get_shear());
00413 }
00414
00415
00416
00417
00418
00419
00420
00421
00422 CPT(TransformState) TransformState::
00423 set_quat(const LQuaternion &quat) const {
00424 nassertr(!quat.is_nan(), this);
00425 nassertr(!is_invalid(), this);
00426
00427 return make_pos_quat_scale_shear(get_pos(), quat, get_scale(), get_shear());
00428 }
00429
00430
00431
00432
00433
00434
00435
00436
00437 CPT(TransformState) TransformState::
00438 set_scale(const LVecBase3 &scale) const {
00439 nassertr(!scale.is_nan(), this);
00440 nassertr(!is_invalid(), this);
00441
00442 if (is_2d() && scale[0] == scale[1] && scale[1] == scale[2]) {
00443
00444
00445 return make_pos_rotate_scale_shear2d(get_pos2d(), get_rotate2d(),
00446 LVecBase2(scale[0], scale[0]),
00447 get_shear2d());
00448 }
00449
00450
00451 if (quat_given()) {
00452 return make_pos_quat_scale_shear(get_pos(), get_quat(), scale, get_shear());
00453 } else {
00454 return make_pos_hpr_scale_shear(get_pos(), get_hpr(), scale, get_shear());
00455 }
00456 }
00457
00458
00459
00460
00461
00462
00463
00464
00465 CPT(TransformState) TransformState::
00466 set_shear(const LVecBase3 &shear) const {
00467 nassertr(!shear.is_nan(), this);
00468 nassertr(!is_invalid(), this);
00469
00470 if (quat_given()) {
00471 return make_pos_quat_scale_shear(get_pos(), get_quat(), get_scale(), shear);
00472 } else {
00473 return make_pos_hpr_scale_shear(get_pos(), get_hpr(), get_scale(), shear);
00474 }
00475 }
00476
00477
00478
00479
00480
00481
00482
00483
00484 CPT(TransformState) TransformState::
00485 set_pos2d(const LVecBase2 &pos) const {
00486 nassertr(!pos.is_nan(), this);
00487 nassertr(!is_invalid(), this);
00488 if (!is_2d()) {
00489 return set_pos(LVecBase3(pos[0], pos[1], 0.0f));
00490 }
00491
00492 if (is_identity() || components_given()) {
00493
00494
00495 return make_pos_rotate_scale_shear2d(pos, get_rotate2d(), get_scale2d(),
00496 get_shear2d());
00497
00498 } else {
00499
00500 LMatrix3 mat = get_mat3();
00501 mat.set_row(2, pos);
00502 return make_mat3(mat);
00503 }
00504 }
00505
00506
00507
00508
00509
00510
00511
00512
00513 CPT(TransformState) TransformState::
00514 set_rotate2d(PN_stdfloat rotate) const {
00515 nassertr(!cnan(rotate), this);
00516 nassertr(!is_invalid(), this);
00517
00518 if (!is_2d()) {
00519 switch (get_default_coordinate_system()) {
00520 default:
00521 case CS_zup_right:
00522 return set_hpr(LVecBase3(rotate, 0.0f, 0.0f));
00523 case CS_zup_left:
00524 return set_hpr(LVecBase3(-rotate, 0.0f, 0.0f));
00525 case CS_yup_right:
00526 return set_hpr(LVecBase3(0.0f, 0.0f, -rotate));
00527 case CS_yup_left:
00528 return set_hpr(LVecBase3(0.0f, 0.0f, rotate));
00529 }
00530 }
00531
00532 return make_pos_rotate_scale_shear2d(get_pos2d(), rotate, get_scale2d(),
00533 get_shear2d());
00534 }
00535
00536
00537
00538
00539
00540
00541
00542
00543 CPT(TransformState) TransformState::
00544 set_scale2d(const LVecBase2 &scale) const {
00545 nassertr(!scale.is_nan(), this);
00546 nassertr(!is_invalid(), this);
00547
00548 if (!is_2d()) {
00549 return set_scale(LVecBase3(scale[0], scale[1], 1.0f));
00550 }
00551 return make_pos_rotate_scale_shear2d(get_pos2d(), get_rotate2d(),
00552 scale, get_shear2d());
00553 }
00554
00555
00556
00557
00558
00559
00560
00561
00562 CPT(TransformState) TransformState::
00563 set_shear2d(PN_stdfloat shear) const {
00564 nassertr(!cnan(shear), this);
00565 nassertr(!is_invalid(), this);
00566 if (!is_2d()) {
00567 return set_shear(LVecBase3(shear, 0.0f, 0.0f));
00568 }
00569 return make_pos_rotate_scale_shear2d(get_pos2d(), get_rotate2d(),
00570 get_scale2d(), shear);
00571 }
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586 CPT(TransformState) TransformState::
00587 compose(const TransformState *other) const {
00588
00589 if (is_identity()) {
00590 return other;
00591 }
00592 if (other->is_identity()) {
00593 return this;
00594 }
00595
00596
00597 if (is_invalid()) {
00598 return this;
00599 }
00600 if (other->is_invalid()) {
00601 return other;
00602 }
00603
00604 if (!transform_cache) {
00605 return do_compose(other);
00606 }
00607
00608
00609 CPT(TransformState) result;
00610 {
00611 LightReMutexHolder holder(*_states_lock);
00612 int index = _composition_cache.find(other);
00613 if (index != -1) {
00614 const Composition &comp = _composition_cache.get_data(index);
00615 result = comp._result;
00616 }
00617 if (result != (TransformState *)NULL) {
00618 _cache_stats.inc_hits();
00619 }
00620 }
00621
00622 if (result != (TransformState *)NULL) {
00623
00624 return result;
00625 }
00626
00627
00628
00629
00630 result = do_compose(other);
00631
00632
00633
00634 return ((TransformState *)this)->store_compose(other, result);
00635 }
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648 CPT(TransformState) TransformState::
00649 invert_compose(const TransformState *other) const {
00650
00651
00652
00653
00654
00655 if (is_identity()) {
00656 return other;
00657 }
00658
00659
00660
00661
00662 if (is_invalid()) {
00663 return this;
00664 }
00665 if (other->is_invalid()) {
00666 return other;
00667 }
00668
00669 if (other == this) {
00670
00671 return make_identity();
00672 }
00673
00674 if (!transform_cache) {
00675 return do_invert_compose(other);
00676 }
00677
00678 LightReMutexHolder holder(*_states_lock);
00679
00680 CPT(TransformState) result;
00681 {
00682 LightReMutexHolder holder(*_states_lock);
00683 int index = _invert_composition_cache.find(other);
00684 if (index != -1) {
00685 const Composition &comp = _invert_composition_cache.get_data(index);
00686 result = comp._result;
00687 }
00688 if (result != (TransformState *)NULL) {
00689 _cache_stats.inc_hits();
00690 }
00691 }
00692
00693 if (result != (TransformState *)NULL) {
00694
00695 return result;
00696 }
00697
00698
00699
00700
00701 result = do_invert_compose(other);
00702
00703
00704
00705 return ((TransformState *)this)->store_invert_compose(other, result);
00706 }
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718 bool TransformState::
00719 unref() const {
00720 if (!transform_cache || garbage_collect_states) {
00721
00722
00723 return ReferenceCount::unref();
00724 }
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734 LightReMutexHolder holder(*_states_lock);
00735
00736 if (auto_break_cycles && uniquify_transforms) {
00737 if (get_cache_ref_count() > 0 &&
00738 get_ref_count() == get_cache_ref_count() + 1) {
00739
00740
00741
00742
00743 ((TransformState *)this)->detect_and_break_cycles();
00744 }
00745 }
00746
00747 if (ReferenceCount::unref()) {
00748
00749 return true;
00750 }
00751
00752
00753
00754
00755 ((TransformState *)this)->release_new();
00756 ((TransformState *)this)->remove_cache_pointers();
00757
00758 return false;
00759 }
00760
00761
00762
00763
00764
00765
00766
00767
00768 bool TransformState::
00769 validate_composition_cache() const {
00770 LightReMutexHolder holder(*_states_lock);
00771
00772 int size = _composition_cache.get_size();
00773 for (int i = 0; i < size; ++i) {
00774 if (!_composition_cache.has_element(i)) {
00775 continue;
00776 }
00777 const TransformState *source = _composition_cache.get_key(i);
00778 if (source != (TransformState *)NULL) {
00779
00780
00781 int ri = source->_composition_cache.find(this);
00782 if (ri == -1) {
00783
00784 pgraph_cat.error()
00785 << "TransformState::composition cache is inconsistent!\n";
00786 pgraph_cat.error(false)
00787 << *this << " compose " << *source << "\n";
00788 pgraph_cat.error(false)
00789 << "but no reverse\n";
00790 return false;
00791 }
00792 }
00793 }
00794
00795 size = _invert_composition_cache.get_size();
00796 for (int i = 0; i < size; ++i) {
00797 if (!_invert_composition_cache.has_element(i)) {
00798 continue;
00799 }
00800 const TransformState *source = _invert_composition_cache.get_key(i);
00801 if (source != (TransformState *)NULL) {
00802
00803
00804 int ri = source->_invert_composition_cache.find(this);
00805 if (ri == -1) {
00806
00807 pgraph_cat.error()
00808 << "TransformState::invert composition cache is inconsistent!\n";
00809 pgraph_cat.error(false)
00810 << *this << " invert compose " << *source << "\n";
00811 pgraph_cat.error(false)
00812 << "but no reverse\n";
00813 return false;
00814 }
00815 }
00816 }
00817
00818 return true;
00819 }
00820
00821 #ifdef HAVE_PYTHON
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00832
00833
00834
00835
00836 PyObject *TransformState::
00837 get_composition_cache() const {
00838 IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState;
00839 LightReMutexHolder holder(*_states_lock);
00840
00841 size_t num_states = _composition_cache.get_num_entries();
00842 PyObject *list = PyList_New(num_states);
00843 size_t i = 0;
00844
00845 int size = _composition_cache.get_size();
00846 for (int si = 0; si < size; ++si) {
00847 if (!_composition_cache.has_element(si)) {
00848 continue;
00849 }
00850
00851 PyObject *tuple = PyTuple_New(2);
00852 PyObject *a, *b;
00853
00854 const TransformState *source = _composition_cache.get_key(si);
00855 if (source == (TransformState *)NULL) {
00856 a = Py_None;
00857 Py_INCREF(a);
00858 } else {
00859 source->ref();
00860 a = DTool_CreatePyInstanceTyped((void *)source, Dtool_TransformState,
00861 true, true, source->get_type_index());
00862 }
00863 const TransformState *result = _composition_cache.get_data(si)._result;
00864 if (result == (TransformState *)NULL) {
00865 b = Py_None;
00866 Py_INCREF(b);
00867 } else {
00868 result->ref();
00869 b = DTool_CreatePyInstanceTyped((void *)result, Dtool_TransformState,
00870 true, true, result->get_type_index());
00871 }
00872
00873 PyTuple_SET_ITEM(tuple, 0, a);
00874 PyTuple_SET_ITEM(tuple, 1, b);
00875
00876 nassertr(i < num_states, list);
00877 PyList_SET_ITEM(list, i, tuple);
00878 ++i;
00879 }
00880 nassertr(i == num_states, list);
00881 return list;
00882 }
00883 #endif // HAVE_PYTHON
00884
00885 #ifdef HAVE_PYTHON
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900 PyObject *TransformState::
00901 get_invert_composition_cache() const {
00902 IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState;
00903 LightReMutexHolder holder(*_states_lock);
00904
00905 size_t num_states = _invert_composition_cache.get_num_entries();
00906 PyObject *list = PyList_New(num_states);
00907 size_t i = 0;
00908
00909 int size = _invert_composition_cache.get_size();
00910 for (int si = 0; si < size; ++si) {
00911 if (!_invert_composition_cache.has_element(si)) {
00912 continue;
00913 }
00914
00915 PyObject *tuple = PyTuple_New(2);
00916 PyObject *a, *b;
00917
00918 const TransformState *source = _invert_composition_cache.get_key(si);
00919 if (source == (TransformState *)NULL) {
00920 a = Py_None;
00921 Py_INCREF(a);
00922 } else {
00923 source->ref();
00924 a = DTool_CreatePyInstanceTyped((void *)source, Dtool_TransformState,
00925 true, true, source->get_type_index());
00926 }
00927 const TransformState *result = _invert_composition_cache.get_data(si)._result;
00928 if (result == (TransformState *)NULL) {
00929 b = Py_None;
00930 Py_INCREF(b);
00931 } else {
00932 result->ref();
00933 b = DTool_CreatePyInstanceTyped((void *)result, Dtool_TransformState,
00934 true, true, result->get_type_index());
00935 }
00936
00937 PyTuple_SET_ITEM(tuple, 0, a);
00938 PyTuple_SET_ITEM(tuple, 1, b);
00939
00940 nassertr(i < num_states, list);
00941 PyList_SET_ITEM(list, i, tuple);
00942 ++i;
00943 }
00944 nassertr(i == num_states, list);
00945 return list;
00946 }
00947 #endif // HAVE_PYTHON
00948
00949
00950
00951
00952
00953
00954 void TransformState::
00955 output(ostream &out) const {
00956 out << "T:";
00957 if (is_invalid()) {
00958 out << "(invalid)";
00959
00960 } else if (is_identity()) {
00961 out << "(identity)";
00962
00963 } else if (has_components()) {
00964 bool output_hpr = !get_hpr().almost_equal(LVecBase3(0.0f, 0.0f, 0.0f));
00965
00966 if (!components_given()) {
00967
00968
00969
00970 out << "m";
00971
00972 } else if (output_hpr && quat_given()) {
00973
00974
00975
00976
00977 out << "q";
00978 }
00979
00980 char lead = '(';
00981 if (is_2d()) {
00982 if (!get_pos2d().almost_equal(LVecBase2(0.0f, 0.0f))) {
00983 out << lead << "pos " << get_pos2d();
00984 lead = ' ';
00985 }
00986 if (output_hpr) {
00987 out << lead << "rotate " << get_rotate2d();
00988 lead = ' ';
00989 }
00990 if (!get_scale2d().almost_equal(LVecBase2(1.0f, 1.0f))) {
00991 if (has_uniform_scale()) {
00992 out << lead << "scale " << get_uniform_scale();
00993 lead = ' ';
00994 } else {
00995 out << lead << "scale " << get_scale2d();
00996 lead = ' ';
00997 }
00998 }
00999 if (has_nonzero_shear()) {
01000 out << lead << "shear " << get_shear2d();
01001 lead = ' ';
01002 }
01003 } else {
01004 if (!get_pos().almost_equal(LVecBase3(0.0f, 0.0f, 0.0f))) {
01005 out << lead << "pos " << get_pos();
01006 lead = ' ';
01007 }
01008 if (output_hpr) {
01009 out << lead << "hpr " << get_hpr();
01010 lead = ' ';
01011 }
01012 if (!get_scale().almost_equal(LVecBase3(1.0f, 1.0f, 1.0f))) {
01013 if (has_uniform_scale()) {
01014 out << lead << "scale " << get_uniform_scale();
01015 lead = ' ';
01016 } else {
01017 out << lead << "scale " << get_scale();
01018 lead = ' ';
01019 }
01020 }
01021 if (has_nonzero_shear()) {
01022 out << lead << "shear " << get_shear();
01023 lead = ' ';
01024 }
01025 }
01026 if (lead == '(') {
01027 out << "(almost identity)";
01028 } else {
01029 out << ")";
01030 }
01031
01032 } else {
01033 if (is_2d()) {
01034 out << get_mat3();
01035 } else {
01036 out << get_mat();
01037 }
01038 }
01039 }
01040
01041
01042
01043
01044
01045
01046 void TransformState::
01047 write(ostream &out, int indent_level) const {
01048 indent(out, indent_level) << *this << "\n";
01049 }
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059 void TransformState::
01060 write_composition_cache(ostream &out, int indent_level) const {
01061 indent(out, indent_level + 2) << _composition_cache << "\n";
01062 indent(out, indent_level + 2) << _invert_composition_cache << "\n";
01063 }
01064
01065
01066
01067
01068
01069
01070
01071
01072 int TransformState::
01073 get_num_states() {
01074 if (_states == (States *)NULL) {
01075 return 0;
01076 }
01077 LightReMutexHolder holder(*_states_lock);
01078 return _states->get_num_entries();
01079 }
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099 int TransformState::
01100 get_num_unused_states() {
01101 if (_states == (States *)NULL) {
01102 return 0;
01103 }
01104 LightReMutexHolder holder(*_states_lock);
01105
01106
01107
01108
01109 typedef pmap<const TransformState *, int> StateCount;
01110 StateCount state_count;
01111
01112 int size = _states->get_size();
01113 for (int si = 0; si < size; ++si) {
01114 if (!_states->has_element(si)) {
01115 continue;
01116 }
01117 const TransformState *state = _states->get_key(si);
01118
01119 int i;
01120 int cache_size = state->_composition_cache.get_size();
01121 for (i = 0; i < cache_size; ++i) {
01122 if (state->_composition_cache.has_element(i)) {
01123 const TransformState *result = state->_composition_cache.get_data(i)._result;
01124 if (result != (const TransformState *)NULL && result != state) {
01125
01126
01127 pair<StateCount::iterator, bool> ir =
01128 state_count.insert(StateCount::value_type(result, 1));
01129 if (!ir.second) {
01130
01131
01132 (*(ir.first)).second++;
01133 }
01134 }
01135 }
01136 }
01137 cache_size = state->_invert_composition_cache.get_size();
01138 for (i = 0; i < cache_size; ++i) {
01139 if (state->_invert_composition_cache.has_element(i)) {
01140 const TransformState *result = state->_invert_composition_cache.get_data(i)._result;
01141 if (result != (const TransformState *)NULL && result != state) {
01142 pair<StateCount::iterator, bool> ir =
01143 state_count.insert(StateCount::value_type(result, 1));
01144 if (!ir.second) {
01145 (*(ir.first)).second++;
01146 }
01147 }
01148 }
01149 }
01150 }
01151
01152
01153
01154
01155 int num_unused = 0;
01156
01157 StateCount::iterator sci;
01158 for (sci = state_count.begin(); sci != state_count.end(); ++sci) {
01159 const TransformState *state = (*sci).first;
01160 int count = (*sci).second;
01161 nassertr(count == state->get_cache_ref_count(), num_unused);
01162 nassertr(count <= state->get_ref_count(), num_unused);
01163 if (count == state->get_ref_count()) {
01164 num_unused++;
01165
01166 if (pgraph_cat.is_debug()) {
01167 pgraph_cat.debug()
01168 << "Unused state: " << (void *)state << ":"
01169 << state->get_ref_count() << " =\n";
01170 state->write(pgraph_cat.debug(false), 2);
01171 }
01172 }
01173 }
01174
01175 return num_unused;
01176 }
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198 int TransformState::
01199 clear_cache() {
01200 if (_states == (States *)NULL) {
01201 return 0;
01202 }
01203 LightReMutexHolder holder(*_states_lock);
01204
01205 PStatTimer timer(_cache_update_pcollector);
01206 int orig_size = _states->get_num_entries();
01207
01208
01209
01210
01211
01212 {
01213 typedef pvector< CPT(TransformState) > TempStates;
01214 TempStates temp_states;
01215 temp_states.reserve(orig_size);
01216
01217 int size = _states->get_size();
01218 for (int si = 0; si < size; ++si) {
01219 if (!_states->has_element(si)) {
01220 continue;
01221 }
01222 const TransformState *state = _states->get_key(si);
01223 temp_states.push_back(state);
01224 }
01225
01226
01227
01228
01229 TempStates::iterator ti;
01230 for (ti = temp_states.begin(); ti != temp_states.end(); ++ti) {
01231 TransformState *state = (TransformState *)(*ti).p();
01232
01233 int i;
01234 int cache_size = state->_composition_cache.get_size();
01235 for (i = 0; i < cache_size; ++i) {
01236 if (state->_composition_cache.has_element(i)) {
01237 const TransformState *result = state->_composition_cache.get_data(i)._result;
01238 if (result != (const TransformState *)NULL && result != state) {
01239 result->cache_unref();
01240 nassertr(result->get_ref_count() > 0, 0);
01241 }
01242 }
01243 }
01244 _cache_stats.add_total_size(-state->_composition_cache.get_num_entries());
01245 state->_composition_cache.clear();
01246
01247 cache_size = state->_invert_composition_cache.get_size();
01248 for (i = 0; i < cache_size; ++i) {
01249 if (state->_invert_composition_cache.has_element(i)) {
01250 const TransformState *result = state->_invert_composition_cache.get_data(i)._result;
01251 if (result != (const TransformState *)NULL && result != state) {
01252 result->cache_unref();
01253 nassertr(result->get_ref_count() > 0, 0);
01254 }
01255 }
01256 }
01257 _cache_stats.add_total_size(-state->_invert_composition_cache.get_num_entries());
01258 state->_invert_composition_cache.clear();
01259 }
01260
01261
01262
01263
01264 }
01265
01266 int new_size = _states->get_num_entries();
01267 return orig_size - new_size;
01268 }
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280 int TransformState::
01281 garbage_collect() {
01282 if (_states == (States *)NULL || !garbage_collect_states) {
01283 return 0;
01284 }
01285 LightReMutexHolder holder(*_states_lock);
01286
01287 PStatTimer timer(_garbage_collect_pcollector);
01288 int orig_size = _states->get_num_entries();
01289
01290
01291 int size = _states->get_size();
01292 int num_this_pass = int(size * garbage_collect_states_rate);
01293 if (num_this_pass <= 0) {
01294 return 0;
01295 }
01296 num_this_pass = min(num_this_pass, size);
01297 int stop_at_element = (_garbage_index + num_this_pass) % size;
01298
01299 int num_elements = 0;
01300 int si = _garbage_index;
01301 do {
01302 if (_states->has_element(si)) {
01303 ++num_elements;
01304 TransformState *state = (TransformState *)_states->get_key(si);
01305 if (auto_break_cycles && uniquify_transforms) {
01306 if (state->get_cache_ref_count() > 0 &&
01307 state->get_ref_count() == state->get_cache_ref_count()) {
01308
01309
01310
01311
01312 state->detect_and_break_cycles();
01313 }
01314 }
01315
01316 if (state->get_ref_count() == 1) {
01317
01318
01319
01320
01321
01322
01323 state->release_new();
01324 state->remove_cache_pointers();
01325 state->cache_unref();
01326 delete state;
01327 }
01328 }
01329
01330 si = (si + 1) % size;
01331 } while (si != stop_at_element);
01332 _garbage_index = si;
01333 nassertr(_states->validate(), 0);
01334
01335 int new_size = _states->get_num_entries();
01336 return orig_size - new_size;
01337 }
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357 void TransformState::
01358 list_cycles(ostream &out) {
01359 if (_states == (States *)NULL) {
01360 return;
01361 }
01362 LightReMutexHolder holder(*_states_lock);
01363
01364 typedef pset<const TransformState *> VisitedStates;
01365 VisitedStates visited;
01366 CompositionCycleDesc cycle_desc;
01367
01368 int size = _states->get_size();
01369 for (int si = 0; si < size; ++si) {
01370 if (!_states->has_element(si)) {
01371 continue;
01372 }
01373 const TransformState *state = _states->get_key(si);
01374
01375 bool inserted = visited.insert(state).second;
01376 if (inserted) {
01377 ++_last_cycle_detect;
01378 if (r_detect_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
01379
01380 CompositionCycleDesc::reverse_iterator csi;
01381
01382 out << "\nCycle detected of length " << cycle_desc.size() + 1 << ":\n"
01383 << "state " << (void *)state << ":" << state->get_ref_count()
01384 << " =\n";
01385 state->write(out, 2);
01386 for (csi = cycle_desc.rbegin(); csi != cycle_desc.rend(); ++csi) {
01387 const CompositionCycleDescEntry &entry = (*csi);
01388 if (entry._inverted) {
01389 out << "invert composed with ";
01390 } else {
01391 out << "composed with ";
01392 }
01393 out << (const void *)entry._obj << ":" << entry._obj->get_ref_count()
01394 << " " << *entry._obj << "\n"
01395 << "produces " << (const void *)entry._result << ":"
01396 << entry._result->get_ref_count() << " =\n";
01397 entry._result->write(out, 2);
01398 visited.insert(entry._result);
01399 }
01400
01401 cycle_desc.clear();
01402 } else {
01403 ++_last_cycle_detect;
01404 if (r_detect_reverse_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
01405
01406 CompositionCycleDesc::iterator csi;
01407
01408 out << "\nReverse cycle detected of length " << cycle_desc.size() + 1 << ":\n"
01409 << "state ";
01410 for (csi = cycle_desc.begin(); csi != cycle_desc.end(); ++csi) {
01411 const CompositionCycleDescEntry &entry = (*csi);
01412 out << (const void *)entry._result << ":"
01413 << entry._result->get_ref_count() << " =\n";
01414 entry._result->write(out, 2);
01415 out << (const void *)entry._obj << ":"
01416 << entry._obj->get_ref_count() << " =\n";
01417 entry._obj->write(out, 2);
01418 visited.insert(entry._result);
01419 }
01420 out << (void *)state << ":"
01421 << state->get_ref_count() << " =\n";
01422 state->write(out, 2);
01423
01424 cycle_desc.clear();
01425 }
01426 }
01427 }
01428 }
01429 }
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439 void TransformState::
01440 list_states(ostream &out) {
01441 if (_states == (States *)NULL) {
01442 out << "0 states:\n";
01443 return;
01444 }
01445 LightReMutexHolder holder(*_states_lock);
01446
01447 out << _states->get_num_entries() << " states:\n";
01448
01449 int size = _states->get_size();
01450 for (int si = 0; si < size; ++si) {
01451 if (!_states->has_element(si)) {
01452 continue;
01453 }
01454 const TransformState *state = _states->get_key(si);
01455 state->write(out, 2);
01456 }
01457 }
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469 bool TransformState::
01470 validate_states() {
01471 if (_states == (States *)NULL) {
01472 return true;
01473 }
01474
01475 PStatTimer timer(_transform_validate_pcollector);
01476
01477 LightReMutexHolder holder(*_states_lock);
01478 if (_states->is_empty()) {
01479 return true;
01480 }
01481
01482 if (!_states->validate()) {
01483 pgraph_cat.error()
01484 << "TransformState::_states cache is invalid!\n";
01485 return false;
01486 }
01487
01488 int size = _states->get_size();
01489 int si = 0;
01490 while (si < size && !_states->has_element(si)) {
01491 ++si;
01492 }
01493 nassertr(si < size, false);
01494 nassertr(_states->get_key(si)->get_ref_count() >= 0, false);
01495 int snext = si;
01496 ++snext;
01497 while (snext < size && !_states->has_element(snext)) {
01498 ++snext;
01499 }
01500 while (snext < size) {
01501 nassertr(_states->get_key(snext)->get_ref_count() >= 0, false);
01502 const TransformState *ssi = _states->get_key(si);
01503 if (!ssi->validate_composition_cache()) {
01504 return false;
01505 }
01506 const TransformState *ssnext = _states->get_key(snext);
01507 int c = ssi->compare_to(*ssnext);
01508 int ci = ssnext->compare_to(*ssi);
01509 if ((ci < 0) != (c > 0) ||
01510 (ci > 0) != (c < 0) ||
01511 (ci == 0) != (c == 0)) {
01512 pgraph_cat.error()
01513 << "TransformState::compare_to() not defined properly!\n";
01514 pgraph_cat.error(false)
01515 << "(a, b): " << c << "\n";
01516 pgraph_cat.error(false)
01517 << "(b, a): " << ci << "\n";
01518 ssi->write(pgraph_cat.error(false), 2);
01519 ssnext->write(pgraph_cat.error(false), 2);
01520 return false;
01521 }
01522 si = snext;
01523 ++snext;
01524 while (snext < size && !_states->has_element(snext)) {
01525 ++snext;
01526 }
01527 }
01528
01529 return true;
01530 }
01531
01532 #ifdef HAVE_PYTHON
01533
01534
01535
01536
01537
01538
01539
01540 PyObject *TransformState::
01541 get_states() {
01542 IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState;
01543 if (_states == (States *)NULL) {
01544 return PyList_New(0);
01545 }
01546 LightReMutexHolder holder(*_states_lock);
01547
01548 size_t num_states = _states->get_num_entries();
01549 PyObject *list = PyList_New(num_states);
01550 size_t i = 0;
01551
01552 int size = _states->get_size();
01553 for (int si = 0; si < size; ++si) {
01554 if (!_states->has_element(si)) {
01555 continue;
01556 }
01557 const TransformState *state = _states->get_key(si);
01558 state->ref();
01559 PyObject *a =
01560 DTool_CreatePyInstanceTyped((void *)state, Dtool_TransformState,
01561 true, true, state->get_type_index());
01562 nassertr(i < num_states, list);
01563 PyList_SET_ITEM(list, i, a);
01564 ++i;
01565 }
01566 nassertr(i == num_states, list);
01567 return list;
01568 }
01569 #endif // HAVE_PYTHON
01570
01571 #ifdef HAVE_PYTHON
01572
01573
01574
01575
01576
01577
01578
01579 PyObject *TransformState::
01580 get_unused_states() {
01581 IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState;
01582 if (_states == (States *)NULL) {
01583 return PyList_New(0);
01584 }
01585 LightReMutexHolder holder(*_states_lock);
01586
01587 PyObject *list = PyList_New(0);
01588 int size = _states->get_size();
01589 for (int si = 0; si < size; ++si) {
01590 if (!_states->has_element(si)) {
01591 continue;
01592 }
01593 const TransformState *state = _states->get_key(si);
01594 if (state->get_cache_ref_count() == state->get_ref_count()) {
01595 state->ref();
01596 PyObject *a =
01597 DTool_CreatePyInstanceTyped((void *)state, Dtool_TransformState,
01598 true, true, state->get_type_index());
01599 PyList_Append(list, a);
01600 Py_DECREF(a);
01601 }
01602 }
01603 return list;
01604 }
01605 #endif // HAVE_PYTHON
01606
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617 void TransformState::
01618 init_states() {
01619 _states = new States;
01620
01621
01622
01623
01624
01625
01626 _states_lock = new LightReMutex("TransformState::_states_lock");
01627 _cache_stats.init();
01628 nassertv(Thread::get_current_thread() == Thread::get_main_thread());
01629 }
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641 CPT(TransformState) TransformState::
01642 return_new(TransformState *state) {
01643 nassertr(state != (TransformState *)NULL, state);
01644 if (!uniquify_transforms && !state->is_identity()) {
01645 return state;
01646 }
01647
01648 return return_unique(state);
01649 }
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663 CPT(TransformState) TransformState::
01664 return_unique(TransformState *state) {
01665 nassertr(state != (TransformState *)NULL, state);
01666
01667 if (!transform_cache) {
01668 return state;
01669 }
01670
01671 #ifndef NDEBUG
01672 if (paranoid_const) {
01673 nassertr(validate_states(), state);
01674 }
01675 #endif
01676
01677 PStatTimer timer(_transform_new_pcollector);
01678
01679 LightReMutexHolder holder(*_states_lock);
01680
01681 if (state->_saved_entry != -1) {
01682
01683
01684 return state;
01685 }
01686
01687
01688
01689 CPT(TransformState) pt_state = state;
01690
01691 int si = _states->find(state);
01692 if (si != -1) {
01693
01694 return _states->get_key(si);
01695 }
01696
01697
01698 if (garbage_collect_states) {
01699
01700
01701
01702 state->cache_ref();
01703 }
01704 si = _states->store(state, Empty());
01705
01706
01707 state->_saved_entry = si;
01708 return pt_state;
01709 }
01710
01711
01712
01713
01714
01715
01716
01717
01718 CPT(TransformState) TransformState::
01719 do_compose(const TransformState *other) const {
01720 PStatTimer timer(_transform_compose_pcollector);
01721
01722 nassertr((_flags & F_is_invalid) == 0, this);
01723 nassertr((other->_flags & F_is_invalid) == 0, other);
01724
01725 if (compose_componentwise &&
01726 has_uniform_scale() &&
01727 !has_nonzero_shear() && !other->has_nonzero_shear() &&
01728 ((components_given() && other->has_components()) ||
01729 (other->components_given() && has_components()))) {
01730
01731
01732
01733
01734 CPT(TransformState) result;
01735 if (is_2d() && other->is_2d()) {
01736
01737 LVecBase2 pos = get_pos2d();
01738 PN_stdfloat rotate = get_rotate2d();
01739 LQuaternion quat = get_norm_quat();
01740 PN_stdfloat scale = get_uniform_scale();
01741
01742 LPoint3 op = quat.xform(other->get_pos());
01743 pos += LVecBase2(op[0], op[1]) * scale;
01744
01745 rotate += other->get_rotate2d();
01746 LVecBase2 new_scale = other->get_scale2d() * scale;
01747
01748 result = make_pos_rotate_scale2d(pos, rotate, new_scale);
01749
01750 } else {
01751
01752 LVecBase3 pos = get_pos();
01753 LQuaternion quat = get_norm_quat();
01754 PN_stdfloat scale = get_uniform_scale();
01755
01756 pos += quat.xform(other->get_pos()) * scale;
01757 quat = other->get_norm_quat() * quat;
01758 LVecBase3 new_scale = other->get_scale() * scale;
01759
01760 result = make_pos_quat_scale(pos, quat, new_scale);
01761 }
01762
01763 #ifndef NDEBUG
01764 if (paranoid_compose) {
01765
01766 LMatrix4 new_mat;
01767 new_mat.multiply(other->get_mat(), get_mat());
01768 if (!new_mat.almost_equal(result->get_mat(), 0.1)) {
01769 CPT(TransformState) correct = make_mat(new_mat);
01770 pgraph_cat.warning()
01771 << "Componentwise composition of " << *this << " and " << *other
01772 << " produced:\n"
01773 << *result << "\n instead of:\n" << *correct << "\n";
01774 result = correct;
01775 }
01776 }
01777 #endif // NDEBUG
01778
01779 return result;
01780 }
01781
01782
01783 if (is_2d() && other->is_2d()) {
01784 LMatrix3 new_mat = other->get_mat3() * get_mat3();
01785 return make_mat3(new_mat);
01786 } else {
01787 LMatrix4 new_mat;
01788 new_mat.multiply(other->get_mat(), get_mat());
01789 return make_mat(new_mat);
01790 }
01791 }
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801 CPT(TransformState) TransformState::
01802 store_compose(const TransformState *other, const TransformState *result) {
01803
01804 nassertr(!is_identity(), other);
01805 nassertr(!other->is_identity(), this);
01806
01807
01808 nassertr(!is_invalid(), this);
01809 nassertr(!other->is_invalid(), other);
01810
01811 LightReMutexHolder holder(*_states_lock);
01812
01813
01814 int index = _composition_cache.find(other);
01815 if (index != -1) {
01816 Composition &comp = _composition_cache.modify_data(index);
01817 if (comp._result == (const TransformState *)NULL) {
01818
01819
01820
01821 comp._result = result;
01822
01823 if (result != (const TransformState *)this) {
01824
01825
01826 result->cache_ref();
01827 }
01828 }
01829
01830 _cache_stats.inc_hits();
01831 return comp._result;
01832 }
01833 _cache_stats.inc_misses();
01834
01835
01836
01837
01838
01839
01840
01841
01842 _cache_stats.add_total_size(1);
01843 _cache_stats.inc_adds(_composition_cache.get_size() == 0);
01844
01845 _composition_cache[other]._result = result;
01846
01847 if (other != this) {
01848 _cache_stats.add_total_size(1);
01849 _cache_stats.inc_adds(other->_composition_cache.get_size() == 0);
01850 ((TransformState *)other)->_composition_cache[this]._result = NULL;
01851 }
01852
01853 if (result != (TransformState *)this) {
01854
01855
01856
01857
01858 result->cache_ref();
01859
01860
01861
01862
01863 }
01864
01865 _cache_stats.maybe_report("TransformState");
01866
01867 return result;
01868 }
01869
01870
01871
01872
01873
01874
01875
01876
01877
01878 CPT(TransformState) TransformState::
01879 store_invert_compose(const TransformState *other, const TransformState *result) {
01880
01881 nassertr(!is_identity(), other);
01882
01883
01884 nassertr(!is_invalid(), this);
01885 nassertr(!other->is_invalid(), other);
01886
01887 nassertr(other != this, make_identity());
01888
01889 LightReMutexHolder holder(*_states_lock);
01890
01891
01892 int index = _invert_composition_cache.find(other);
01893 if (index != -1) {
01894 Composition &comp = ((TransformState *)this)->_invert_composition_cache.modify_data(index);
01895 if (comp._result == (const TransformState *)NULL) {
01896
01897
01898
01899 comp._result = result;
01900
01901 if (result != (const TransformState *)this) {
01902
01903
01904 result->cache_ref();
01905 }
01906 }
01907
01908 _cache_stats.inc_hits();
01909 return comp._result;
01910 }
01911 _cache_stats.inc_misses();
01912
01913
01914
01915
01916
01917
01918
01919
01920 _cache_stats.add_total_size(1);
01921 _cache_stats.inc_adds(_invert_composition_cache.get_size() == 0);
01922 _invert_composition_cache[other]._result = result;
01923
01924 if (other != this) {
01925 _cache_stats.add_total_size(1);
01926 _cache_stats.inc_adds(other->_invert_composition_cache.get_size() == 0);
01927 ((TransformState *)other)->_invert_composition_cache[this]._result = NULL;
01928 }
01929
01930 if (result != (TransformState *)this) {
01931
01932
01933
01934
01935 result->cache_ref();
01936
01937
01938
01939
01940 }
01941
01942 return result;
01943 }
01944
01945
01946
01947
01948
01949
01950 CPT(TransformState) TransformState::
01951 do_invert_compose(const TransformState *other) const {
01952 PStatTimer timer(_transform_invert_pcollector);
01953
01954 nassertr((_flags & F_is_invalid) == 0, this);
01955 nassertr((other->_flags & F_is_invalid) == 0, other);
01956
01957 if (compose_componentwise &&
01958 has_uniform_scale() &&
01959 !has_nonzero_shear() && !other->has_nonzero_shear() &&
01960 ((components_given() && other->has_components()) ||
01961 (other->components_given() && has_components()))) {
01962
01963
01964
01965
01966 CPT(TransformState) result;
01967 if (is_2d() && other->is_2d()) {
01968
01969 LVecBase2 pos = get_pos2d();
01970 PN_stdfloat rotate = get_rotate2d();
01971 LQuaternion quat = get_norm_quat();
01972 PN_stdfloat scale = get_uniform_scale();
01973
01974
01975 if (scale == 0.0f) {
01976 ((TransformState *)this)->_flags |= F_is_singular | F_singular_known;
01977 return make_invalid();
01978 }
01979 scale = 1.0f / scale;
01980 quat.invert_in_place();
01981 rotate = -rotate;
01982 LVecBase3 mp = quat.xform(-LVecBase3(pos[0], pos[1], 0.0f));
01983 pos = LVecBase2(mp[0], mp[1]) * scale;
01984 LVecBase2 new_scale(scale, scale);
01985
01986
01987 if (!other->is_identity()) {
01988 LPoint3 op = quat.xform(other->get_pos());
01989 pos += LVecBase2(op[0], op[1]) * scale;
01990
01991 rotate += other->get_rotate2d();
01992 new_scale = other->get_scale2d() * scale;
01993 }
01994
01995 result = make_pos_rotate_scale2d(pos, rotate, new_scale);
01996
01997 } else {
01998
01999 LVecBase3 pos = get_pos();
02000 LQuaternion quat = get_norm_quat();
02001 PN_stdfloat scale = get_uniform_scale();
02002
02003
02004 if (scale == 0.0f) {
02005 ((TransformState *)this)->_flags |= F_is_singular | F_singular_known;
02006 return make_invalid();
02007 }
02008 scale = 1.0f / scale;
02009 quat.invert_in_place();
02010 pos = quat.xform(-pos) * scale;
02011 LVecBase3 new_scale(scale, scale, scale);
02012
02013
02014 if (!other->is_identity()) {
02015 pos += quat.xform(other->get_pos()) * scale;
02016 quat = other->get_norm_quat() * quat;
02017 new_scale = other->get_scale() * scale;
02018 }
02019
02020 result = make_pos_quat_scale(pos, quat, new_scale);
02021 }
02022
02023 #ifndef NDEBUG
02024 if (paranoid_compose) {
02025
02026 if (is_singular()) {
02027 pgraph_cat.warning()
02028 << "Unexpected singular matrix found for " << *this << "\n";
02029 } else {
02030 nassertr(_inv_mat != (LMatrix4 *)NULL, make_invalid());
02031 LMatrix4 new_mat;
02032 new_mat.multiply(other->get_mat(), *_inv_mat);
02033 if (!new_mat.almost_equal(result->get_mat(), 0.1)) {
02034 CPT(TransformState) correct = make_mat(new_mat);
02035 pgraph_cat.warning()
02036 << "Componentwise invert-composition of " << *this << " and " << *other
02037 << " produced:\n"
02038 << *result << "\n instead of:\n" << *correct << "\n";
02039 result = correct;
02040 }
02041 }
02042 }
02043 #endif // NDEBUG
02044
02045 return result;
02046 }
02047
02048 if (is_singular()) {
02049 return make_invalid();
02050 }
02051
02052
02053
02054 nassertr(_inv_mat != (LMatrix4 *)NULL, make_invalid());
02055
02056 if (is_2d() && other->is_2d()) {
02057 const LMatrix4 &i = *_inv_mat;
02058 LMatrix3 inv3(i(0, 0), i(0, 1), i(0, 3),
02059 i(1, 0), i(1, 1), i(1, 3),
02060 i(3, 0), i(3, 1), i(3, 3));
02061 if (other->is_identity()) {
02062 return make_mat3(inv3);
02063 } else {
02064 return make_mat3(other->get_mat3() * inv3);
02065 }
02066 } else {
02067 if (other->is_identity()) {
02068 return make_mat(*_inv_mat);
02069 } else {
02070 return make_mat(other->get_mat() * (*_inv_mat));
02071 }
02072 }
02073 }
02074
02075
02076
02077
02078
02079
02080
02081
02082 void TransformState::
02083 detect_and_break_cycles() {
02084 PStatTimer timer(_transform_break_cycles_pcollector);
02085
02086 ++_last_cycle_detect;
02087 if (r_detect_cycles(this, this, 1, _last_cycle_detect, NULL)) {
02088
02089
02090 if (pgraph_cat.is_debug()) {
02091 pgraph_cat.debug()
02092 << "Breaking cycle involving " << (*this) << "\n";
02093 }
02094
02095 remove_cache_pointers();
02096 } else {
02097 ++_last_cycle_detect;
02098 if (r_detect_reverse_cycles(this, this, 1, _last_cycle_detect, NULL)) {
02099 if (pgraph_cat.is_debug()) {
02100 pgraph_cat.debug()
02101 << "Breaking cycle involving " << (*this) << "\n";
02102 }
02103
02104 remove_cache_pointers();
02105 }
02106 }
02107 }
02108
02109
02110
02111
02112
02113
02114
02115
02116
02117
02118
02119
02120 bool TransformState::
02121 r_detect_cycles(const TransformState *start_state,
02122 const TransformState *current_state,
02123 int length, UpdateSeq this_seq,
02124 TransformState::CompositionCycleDesc *cycle_desc) {
02125 if (current_state->_cycle_detect == this_seq) {
02126
02127
02128
02129
02130
02131
02132 return (current_state == start_state && length > 2);
02133 }
02134 ((TransformState *)current_state)->_cycle_detect = this_seq;
02135
02136 int i;
02137 int cache_size = current_state->_composition_cache.get_size();
02138 for (i = 0; i < cache_size; ++i) {
02139 if (current_state->_composition_cache.has_element(i)) {
02140 const TransformState *result = current_state->_composition_cache.get_data(i)._result;
02141 if (result != (const TransformState *)NULL) {
02142 if (r_detect_cycles(start_state, result, length + 1,
02143 this_seq, cycle_desc)) {
02144
02145 if (cycle_desc != (CompositionCycleDesc *)NULL) {
02146 const TransformState *other = current_state->_composition_cache.get_key(i);
02147 CompositionCycleDescEntry entry(other, result, false);
02148 cycle_desc->push_back(entry);
02149 }
02150 return true;
02151 }
02152 }
02153 }
02154 }
02155
02156 cache_size = current_state->_invert_composition_cache.get_size();
02157 for (i = 0; i < cache_size; ++i) {
02158 if (current_state->_invert_composition_cache.has_element(i)) {
02159 const TransformState *result = current_state->_invert_composition_cache.get_data(i)._result;
02160 if (result != (const TransformState *)NULL) {
02161 if (r_detect_cycles(start_state, result, length + 1,
02162 this_seq, cycle_desc)) {
02163
02164 if (cycle_desc != (CompositionCycleDesc *)NULL) {
02165 const TransformState *other = current_state->_invert_composition_cache.get_key(i);
02166 CompositionCycleDescEntry entry(other, result, true);
02167 cycle_desc->push_back(entry);
02168 }
02169 return true;
02170 }
02171 }
02172 }
02173 }
02174
02175
02176 return false;
02177 }
02178
02179
02180
02181
02182
02183
02184
02185
02186
02187 bool TransformState::
02188 r_detect_reverse_cycles(const TransformState *start_state,
02189 const TransformState *current_state,
02190 int length, UpdateSeq this_seq,
02191 TransformState::CompositionCycleDesc *cycle_desc) {
02192 if (current_state->_cycle_detect == this_seq) {
02193
02194
02195
02196
02197
02198
02199 return (current_state == start_state && length > 2);
02200 }
02201 ((TransformState *)current_state)->_cycle_detect = this_seq;
02202
02203 int i;
02204 int cache_size = current_state->_composition_cache.get_size();
02205 for (i = 0; i < cache_size; ++i) {
02206 if (current_state->_composition_cache.has_element(i)) {
02207 const TransformState *other = current_state->_composition_cache.get_key(i);
02208 if (other != current_state) {
02209 int oi = other->_composition_cache.find(current_state);
02210 nassertr(oi != -1, false);
02211
02212 const TransformState *result = other->_composition_cache.get_data(oi)._result;
02213 if (result != (const TransformState *)NULL) {
02214 if (r_detect_reverse_cycles(start_state, result, length + 1,
02215 this_seq, cycle_desc)) {
02216
02217 if (cycle_desc != (CompositionCycleDesc *)NULL) {
02218 const TransformState *other = current_state->_composition_cache.get_key(i);
02219 CompositionCycleDescEntry entry(other, result, false);
02220 cycle_desc->push_back(entry);
02221 }
02222 return true;
02223 }
02224 }
02225 }
02226 }
02227 }
02228
02229 cache_size = current_state->_invert_composition_cache.get_size();
02230 for (i = 0; i < cache_size; ++i) {
02231 if (current_state->_invert_composition_cache.has_element(i)) {
02232 const TransformState *other = current_state->_invert_composition_cache.get_key(i);
02233 if (other != current_state) {
02234 int oi = other->_invert_composition_cache.find(current_state);
02235 nassertr(oi != -1, false);
02236
02237 const TransformState *result = other->_invert_composition_cache.get_data(oi)._result;
02238 if (result != (const TransformState *)NULL) {
02239 if (r_detect_reverse_cycles(start_state, result, length + 1,
02240 this_seq, cycle_desc)) {
02241
02242 if (cycle_desc != (CompositionCycleDesc *)NULL) {
02243 const TransformState *other = current_state->_invert_composition_cache.get_key(i);
02244 CompositionCycleDescEntry entry(other, result, false);
02245 cycle_desc->push_back(entry);
02246 }
02247 return true;
02248 }
02249 }
02250 }
02251 }
02252 }
02253
02254
02255 return false;
02256 }
02257
02258
02259
02260
02261
02262
02263
02264
02265
02266
02267
02268 void TransformState::
02269 release_new() {
02270 nassertv(_states_lock->debug_is_locked());
02271
02272 if (_saved_entry != -1) {
02273
02274 _saved_entry = _states->find(this);
02275 _states->remove_element(_saved_entry);
02276 _saved_entry = -1;
02277 }
02278 }
02279
02280
02281
02282
02283
02284
02285
02286
02287
02288
02289
02290
02291 void TransformState::
02292 remove_cache_pointers() {
02293 nassertv(_states_lock->debug_is_locked());
02294
02295
02296
02297
02298
02299
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310 #ifdef DO_PSTATS
02311 if (_composition_cache.is_empty() && _invert_composition_cache.is_empty()) {
02312 return;
02313 }
02314 PStatTimer timer(_cache_update_pcollector);
02315 #endif // DO_PSTATS
02316
02317
02318
02319 int i = 0;
02320 while (!_composition_cache.is_empty()) {
02321
02322 while (!_composition_cache.has_element(i)) {
02323 ++i;
02324 }
02325
02326
02327
02328
02329
02330
02331
02332
02333 TransformState *other = (TransformState *)_composition_cache.get_key(i);
02334
02335
02336
02337 Composition comp = _composition_cache.get_data(i);
02338
02339
02340
02341
02342
02343 _composition_cache.remove_element(i);
02344 _cache_stats.add_total_size(-1);
02345 _cache_stats.inc_dels();
02346
02347 if (other != this) {
02348 int oi = other->_composition_cache.find(this);
02349
02350
02351
02352
02353 if (oi != -1) {
02354
02355 Composition ocomp = other->_composition_cache.get_data(oi);
02356
02357 other->_composition_cache.remove_element(oi);
02358 _cache_stats.add_total_size(-1);
02359 _cache_stats.inc_dels();
02360
02361
02362
02363
02364
02365 if (ocomp._result != (const TransformState *)NULL && ocomp._result != other) {
02366 cache_unref_delete(ocomp._result);
02367 }
02368 }
02369 }
02370
02371
02372
02373 if (comp._result != (const TransformState *)NULL && comp._result != this) {
02374 cache_unref_delete(comp._result);
02375 }
02376 }
02377
02378
02379 i = 0;
02380 while (!_invert_composition_cache.is_empty()) {
02381 while (!_invert_composition_cache.has_element(i)) {
02382 ++i;
02383 }
02384
02385 TransformState *other = (TransformState *)_invert_composition_cache.get_key(i);
02386 nassertv(other != this);
02387 Composition comp = _invert_composition_cache.get_data(i);
02388 _invert_composition_cache.remove_element(i);
02389 _cache_stats.add_total_size(-1);
02390 _cache_stats.inc_dels();
02391 if (other != this) {
02392 int oi = other->_invert_composition_cache.find(this);
02393 if (oi != -1) {
02394 Composition ocomp = other->_invert_composition_cache.get_data(oi);
02395 other->_invert_composition_cache.remove_element(oi);
02396 _cache_stats.add_total_size(-1);
02397 _cache_stats.inc_dels();
02398 if (ocomp._result != (const TransformState *)NULL && ocomp._result != other) {
02399 cache_unref_delete(ocomp._result);
02400 }
02401 }
02402 }
02403 if (comp._result != (const TransformState *)NULL && comp._result != this) {
02404 cache_unref_delete(comp._result);
02405 }
02406 }
02407 }
02408
02409
02410
02411
02412
02413
02414 void TransformState::
02415 do_calc_hash() {
02416 PStatTimer timer(_transform_hash_pcollector);
02417 _hash = 0;
02418
02419 static const int significant_flags =
02420 (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_is_2d);
02421
02422 int flags = (_flags & significant_flags);
02423 _hash = int_hash::add_hash(_hash, flags);
02424
02425 if ((_flags & (F_is_invalid | F_is_identity)) == 0) {
02426
02427
02428
02429 if ((_flags & F_components_given) != 0) {
02430
02431
02432 _hash = _pos.add_hash(_hash);
02433 if ((_flags & F_hpr_given) != 0) {
02434 _hash = _hpr.add_hash(_hash);
02435
02436 } else if ((_flags & F_quat_given) != 0) {
02437 _hash = _quat.add_hash(_hash);
02438 }
02439
02440 _hash = _scale.add_hash(_hash);
02441 _hash = _shear.add_hash(_hash);
02442
02443 } else {
02444
02445 if (uniquify_matrix) {
02446
02447 if ((_flags & F_mat_known) == 0) {
02448
02449 do_calc_mat();
02450 }
02451 _hash = _mat.add_hash(_hash);
02452
02453 } else {
02454
02455
02456
02457
02458 _hash = pointer_hash::add_hash(_hash, this);
02459 }
02460 }
02461 }
02462
02463 _flags |= F_hash_known;
02464 }
02465
02466
02467
02468
02469
02470
02471
02472 void TransformState::
02473 calc_singular() {
02474 LightMutexHolder holder(_lock);
02475 if ((_flags & F_singular_known) != 0) {
02476
02477 return;
02478 }
02479
02480 PStatTimer timer(_transform_calc_pcollector);
02481
02482 nassertv((_flags & F_is_invalid) == 0);
02483
02484
02485
02486
02487
02488
02489
02490 nassertv(_inv_mat == (LMatrix4 *)NULL);
02491 _inv_mat = new LMatrix4;
02492
02493 if ((_flags & F_mat_known) == 0) {
02494 do_calc_mat();
02495 }
02496 bool inverted = _inv_mat->invert_from(_mat);
02497
02498 if (!inverted) {
02499 _flags |= F_is_singular;
02500 delete _inv_mat;
02501 _inv_mat = (LMatrix4 *)NULL;
02502 }
02503 _flags |= F_singular_known;
02504 }
02505
02506
02507
02508
02509
02510
02511
02512 void TransformState::
02513 do_calc_components() {
02514 if ((_flags & F_components_known) != 0) {
02515
02516 return;
02517 }
02518
02519 PStatTimer timer(_transform_calc_pcollector);
02520
02521 nassertv((_flags & F_is_invalid) == 0);
02522 if ((_flags & F_is_identity) != 0) {
02523 _scale.set(1.0f, 1.0f, 1.0f);
02524 _shear.set(0.0f, 0.0f, 0.0f);
02525 _hpr.set(0.0f, 0.0f, 0.0f);
02526 _quat = LQuaternion::ident_quat();
02527 _pos.set(0.0f, 0.0f, 0.0f);
02528 _flags |= F_has_components | F_components_known | F_hpr_known | F_quat_known | F_uniform_scale;
02529
02530 } else {
02531
02532
02533 nassertv((_flags & F_mat_known) != 0);
02534
02535 if ((_flags & F_mat_known) == 0) {
02536 do_calc_mat();
02537 }
02538 bool possible = decompose_matrix(_mat, _scale, _shear, _hpr, _pos);
02539 if (!possible) {
02540
02541
02542
02543 _flags |= F_components_known | F_hpr_known;
02544
02545 } else {
02546
02547 _flags |= F_has_components | F_components_known | F_hpr_known;
02548 check_uniform_scale();
02549 }
02550
02551
02552 _mat.get_row3(_pos, 3);
02553 }
02554 }
02555
02556
02557
02558
02559
02560
02561
02562 void TransformState::
02563 do_calc_hpr() {
02564 if ((_flags & F_hpr_known) != 0) {
02565
02566 return;
02567 }
02568
02569 PStatTimer timer(_transform_calc_pcollector);
02570
02571 nassertv((_flags & F_is_invalid) == 0);
02572 if ((_flags & F_components_known) == 0) {
02573 do_calc_components();
02574 }
02575 if ((_flags & F_hpr_known) == 0) {
02576
02577
02578 nassertv((_flags & F_quat_known) != 0);
02579 _hpr = _quat.get_hpr();
02580 _flags |= F_hpr_known;
02581 }
02582 }
02583
02584
02585
02586
02587
02588
02589 void TransformState::
02590 calc_quat() {
02591 LightMutexHolder holder(_lock);
02592 if ((_flags & F_quat_known) != 0) {
02593
02594 return;
02595 }
02596
02597 PStatTimer timer(_transform_calc_pcollector);
02598
02599 nassertv((_flags & F_is_invalid) == 0);
02600 if ((_flags & F_components_known) == 0) {
02601 do_calc_components();
02602 }
02603 if ((_flags & F_quat_known) == 0) {
02604
02605
02606 nassertv((_flags & F_hpr_known) != 0);
02607 _quat.set_hpr(_hpr);
02608 _flags |= F_quat_known;
02609 }
02610 }
02611
02612
02613
02614
02615
02616
02617 void TransformState::
02618 calc_norm_quat() {
02619 PStatTimer timer(_transform_calc_pcollector);
02620
02621 LQuaternion quat = get_quat();
02622 LightMutexHolder holder(_lock);
02623 _norm_quat = quat;
02624 _norm_quat.normalize();
02625 _flags |= F_norm_quat_known;
02626 }
02627
02628
02629
02630
02631
02632
02633
02634 void TransformState::
02635 do_calc_mat() {
02636 if ((_flags & F_mat_known) != 0) {
02637
02638 return;
02639 }
02640
02641 PStatTimer timer(_transform_calc_pcollector);
02642
02643 nassertv((_flags & F_is_invalid) == 0);
02644 if ((_flags & F_is_identity) != 0) {
02645 _mat = LMatrix4::ident_mat();
02646
02647 } else {
02648
02649
02650 nassertv((_flags & F_components_known) != 0);
02651 if ((_flags & F_hpr_known) == 0) {
02652 do_calc_hpr();
02653 }
02654
02655 compose_matrix(_mat, _scale, _shear, get_hpr(), _pos);
02656 }
02657 _flags |= F_mat_known;
02658 }
02659
02660
02661
02662
02663
02664
02665
02666
02667
02668 void TransformState::
02669 update_pstats(int old_referenced_bits, int new_referenced_bits) {
02670 #ifdef DO_PSTATS
02671 if ((old_referenced_bits & R_node) != 0) {
02672 _node_counter.sub_level(1);
02673 } else if ((old_referenced_bits & R_cache) != 0) {
02674 _cache_counter.sub_level(1);
02675 }
02676 if ((new_referenced_bits & R_node) != 0) {
02677 _node_counter.add_level(1);
02678 } else if ((new_referenced_bits & R_cache) != 0) {
02679 _cache_counter.add_level(1);
02680 }
02681 #endif // DO_PSTATS
02682 }
02683
02684
02685
02686
02687
02688
02689
02690 void TransformState::
02691 register_with_read_factory() {
02692 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
02693 }
02694
02695
02696
02697
02698
02699
02700
02701 void TransformState::
02702 write_datagram(BamWriter *manager, Datagram &dg) {
02703 TypedWritable::write_datagram(manager, dg);
02704
02705 if ((_flags & F_is_identity) != 0) {
02706
02707 int flags = F_is_identity | F_singular_known | F_is_2d;
02708 dg.add_uint32(flags);
02709
02710 } else if ((_flags & F_is_invalid) != 0) {
02711
02712 int flags = F_is_invalid | F_singular_known | F_is_singular | F_components_known | F_mat_known;
02713 dg.add_uint32(flags);
02714
02715 } else if ((_flags & F_components_given) != 0) {
02716
02717 int flags = F_components_given | F_components_known | F_has_components;
02718 flags |= (_flags & F_is_2d);
02719 if ((_flags & F_quat_given) != 0) {
02720 flags |= (F_quat_given | F_quat_known);
02721 } else if ((_flags & F_hpr_given) != 0) {
02722 flags |= (F_hpr_given | F_hpr_known);
02723 }
02724
02725 dg.add_uint32(flags);
02726
02727 _pos.write_datagram(dg);
02728 if ((_flags & F_quat_given) != 0) {
02729 _quat.write_datagram(dg);
02730 } else {
02731 get_hpr().write_datagram(dg);
02732 }
02733 _scale.write_datagram(dg);
02734 _shear.write_datagram(dg);
02735
02736 } else {
02737
02738 nassertv((_flags & F_mat_known) != 0);
02739 int flags = F_mat_known;
02740 flags |= (_flags & F_is_2d);
02741 dg.add_uint32(flags);
02742 _mat.write_datagram(dg);
02743 }
02744 }
02745
02746
02747
02748
02749
02750
02751
02752
02753
02754
02755
02756
02757 PT(TypedWritableReferenceCount) TransformState::
02758 change_this(TypedWritableReferenceCount *old_ptr, BamReader *manager) {
02759
02760 TransformState *state = DCAST(TransformState, old_ptr);
02761 CPT(TransformState) pointer = return_unique(state);
02762
02763
02764
02765 return (TransformState *)pointer.p();
02766 }
02767
02768
02769
02770
02771
02772
02773
02774
02775
02776 TypedWritable *TransformState::
02777 make_from_bam(const FactoryParams ¶ms) {
02778 TransformState *state = new TransformState;
02779 DatagramIterator scan;
02780 BamReader *manager;
02781
02782 parse_params(params, scan, manager);
02783 state->fillin(scan, manager);
02784 manager->register_change_this(change_this, state);
02785
02786 return state;
02787 }
02788
02789
02790
02791
02792
02793
02794
02795
02796 void TransformState::
02797 fillin(DatagramIterator &scan, BamReader *manager) {
02798 TypedWritable::fillin(scan, manager);
02799 _flags = scan.get_uint32();
02800
02801 if ((_flags & F_components_given) != 0) {
02802
02803 _pos.read_datagram(scan);
02804 if ((_flags & F_quat_given) != 0) {
02805 _quat.read_datagram(scan);
02806 } else {
02807 _hpr.read_datagram(scan);
02808 }
02809 _scale.read_datagram(scan);
02810 _shear.read_datagram(scan);
02811
02812 check_uniform_scale();
02813 }
02814
02815 if ((_flags & F_mat_known) != 0) {
02816
02817 _mat.read_datagram(scan);
02818 }
02819 }