33 UpdateSeq TransformState::_last_cycle_detect;
34 size_t TransformState::_garbage_index = 0;
35 bool TransformState::_uniquify_matrix =
true;
37 PStatCollector TransformState::_cache_update_pcollector(
"*:State Cache:Update");
38 PStatCollector TransformState::_garbage_collect_pcollector(
"*:State Cache:Garbage Collect");
39 PStatCollector TransformState::_transform_compose_pcollector(
"*:State Cache:Compose Transform");
40 PStatCollector TransformState::_transform_invert_pcollector(
"*:State Cache:Invert Transform");
41 PStatCollector TransformState::_transform_calc_pcollector(
"*:State Cache:Calc Components");
42 PStatCollector TransformState::_transform_break_cycles_pcollector(
"*:State Cache:Break Cycles");
43 PStatCollector TransformState::_transform_new_pcollector(
"*:State Cache:New");
44 PStatCollector TransformState::_transform_validate_pcollector(
"*:State Cache:Validate");
45 PStatCollector TransformState::_transform_hash_pcollector(
"*:State Cache:Calc Hash");
46 PStatCollector TransformState::_node_counter(
"TransformStates:On nodes");
47 PStatCollector TransformState::_cache_counter(
"TransformStates:Cached");
59 TransformState() : _lock(
"TransformState") {
60 if (_states ==
nullptr) {
64 _flags = F_is_identity | F_singular_known | F_is_2d;
66 _cache_stats.add_num_states(1);
68 #ifdef DO_MEMORY_USAGE
80 nassertv(!is_destructing());
84 if (_inv_mat !=
nullptr) {
92 nassertv(_saved_entry == -1);
93 nassertv(_composition_cache.
is_empty() && _invert_composition_cache.
is_empty());
101 _flags = F_is_invalid | F_is_destructing;
118 static const int significant_flags =
119 (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_quat_given | F_is_2d);
121 int flags = (_flags & significant_flags);
122 int other_flags = (other._flags & significant_flags);
123 if (flags != other_flags) {
124 return flags < other_flags ? -1 : 1;
127 if ((_flags & (F_is_invalid | F_is_identity)) != 0) {
133 if ((_flags & F_components_given) != 0) {
136 int c = _pos.compare_to(other._pos);
141 if ((_flags & F_hpr_given) != 0) {
142 c = _hpr.compare_to(other._hpr);
146 }
else if ((_flags & F_quat_given) != 0) {
147 c = _quat.compare_to(other._quat);
153 c = _scale.compare_to(other._scale);
158 c = _shear.compare_to(other._shear);
163 if (uniquify_matrix) {
169 if (
this != &other) {
170 return (
this < &other) ? -1 : 1;
187 static const int significant_flags =
188 (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_quat_given | F_is_2d);
190 int flags = (_flags & significant_flags);
191 int other_flags = (other._flags & significant_flags);
192 if (flags != other_flags) {
196 if ((_flags & (F_is_invalid | F_is_identity)) != 0) {
202 if ((_flags & F_components_given) != 0) {
205 if (_pos != other._pos) {
209 if ((_flags & F_hpr_given) != 0) {
210 if (_hpr != other._hpr) {
213 }
else if ((_flags & F_quat_given) != 0) {
214 if (_quat != other._quat) {
219 if (_scale != other._scale) {
223 return (_shear == other._shear);
227 if (_uniquify_matrix) {
233 return (
this == &other);
244 if (_identity_state ==
nullptr) {
246 _identity_state = return_unique(state);
249 return _identity_state;
258 if (_invalid_state ==
nullptr) {
260 state->_flags = F_is_invalid | F_singular_known | F_is_singular | F_components_known | F_mat_known;
261 _invalid_state = return_unique(state);
264 return _invalid_state;
271 make_pos_hpr_scale_shear(
const LVecBase3 &pos,
const LVecBase3 &hpr,
272 const LVecBase3 &scale,
const LVecBase3 &shear) {
273 nassertr(!(pos.is_nan() || hpr.is_nan() || scale.is_nan() || shear.is_nan()) , make_invalid());
275 if (pos == LVecBase3(0.0f, 0.0f, 0.0f) &&
276 hpr == LVecBase3(0.0f, 0.0f, 0.0f) &&
277 scale == LVecBase3(1.0f, 1.0f, 1.0f) &&
278 shear == LVecBase3(0.0f, 0.0f, 0.0f)) {
279 return make_identity();
285 state->_scale = scale;
286 state->_shear = shear;
287 state->_flags = F_components_given | F_hpr_given | F_components_known | F_hpr_known | F_has_components;
288 state->check_uniform_scale();
289 return return_new(state);
296 make_pos_quat_scale_shear(
const LVecBase3 &pos,
const LQuaternion &quat,
297 const LVecBase3 &scale,
const LVecBase3 &shear) {
298 nassertr(!(pos.is_nan() || quat.is_nan() || scale.is_nan() || shear.is_nan()) , make_invalid());
300 if (pos == LVecBase3(0.0f, 0.0f, 0.0f) &&
301 quat == LQuaternion::ident_quat() &&
302 scale == LVecBase3(1.0f, 1.0f, 1.0f) &&
303 shear == LVecBase3(0.0f, 0.0f, 0.0f)) {
304 return make_identity();
310 state->_scale = scale;
311 state->_shear = shear;
312 state->_flags = F_components_given | F_quat_given | F_components_known | F_quat_known | F_has_components;
313 state->check_uniform_scale();
314 return return_new(state);
321 make_mat(
const LMatrix4 &mat) {
322 nassertr(!mat.is_nan(), make_invalid());
324 if (mat.is_identity()) {
325 return make_identity();
330 state->_flags = F_mat_known;
331 return return_new(state);
338 make_pos_rotate_scale_shear2d(
const LVecBase2 &pos, PN_stdfloat rotate,
339 const LVecBase2 &scale,
341 nassertr(!(pos.is_nan() || cnan(rotate) || scale.is_nan() || cnan(shear)) , make_invalid());
343 if (pos == LVecBase2(0.0f, 0.0f) &&
345 scale == LVecBase2(1.0f, 1.0f) &&
347 return make_identity();
351 state->_pos.set(pos[0], pos[1], 0.0f);
352 switch (get_default_coordinate_system()) {
355 state->_hpr.set(rotate, 0.0f, 0.0f);
358 state->_hpr.set(-rotate, 0.0f, 0.0f);
361 state->_hpr.set(0.0f, 0.0f, -rotate);
364 state->_hpr.set(0.0, 0.0f, rotate);
367 state->_scale.set(scale[0], scale[1], 1.0f);
368 state->_shear.set(shear, 0.0f, 0.0f);
369 state->_flags = F_components_given | F_hpr_given | F_components_known | F_hpr_known | F_has_components | F_is_2d;
370 state->check_uniform_scale2d();
371 return return_new(state);
380 make_mat3(
const LMatrix3 &mat) {
381 nassertr(!mat.is_nan(), make_invalid());
383 if (mat.is_identity()) {
384 return make_identity();
388 state->_mat.set(mat(0, 0), mat(0, 1), 0.0f, mat(0, 2),
389 mat(1, 0), mat(1, 1), 0.0f, mat(1, 2),
390 0.0f, 0.0f, 1.0f, 0.0f,
391 mat(2, 0), mat(2, 1), 0.0f, mat(2, 2));
392 state->_flags = F_mat_known | F_is_2d;
393 return return_new(state);
401 set_pos(
const LVecBase3 &pos)
const {
402 nassertr(!pos.is_nan(),
this);
416 return make_mat(mat);
426 set_hpr(
const LVecBase3 &hpr)
const {
427 nassertr(!hpr.is_nan(),
this);
439 set_quat(
const LQuaternion &quat)
const {
440 nassertr(!quat.is_nan(),
this);
452 set_scale(
const LVecBase3 &scale)
const {
453 nassertr(!scale.is_nan(),
this);
456 if (
is_2d() && scale[0] == scale[1] && scale[1] == scale[2]) {
459 LVecBase2(scale[0], scale[0]),
477 set_shear(
const LVecBase3 &shear)
const {
478 nassertr(!shear.is_nan(),
this);
493 set_pos2d(
const LVecBase2 &pos)
const {
494 nassertr(!pos.is_nan(),
this);
497 return set_pos(LVecBase3(pos[0], pos[1], 0.0f));
509 return make_mat3(mat);
519 set_rotate2d(PN_stdfloat rotate)
const {
520 nassertr(!cnan(rotate),
this);
524 switch (get_default_coordinate_system()) {
527 return set_hpr(LVecBase3(rotate, 0.0f, 0.0f));
529 return set_hpr(LVecBase3(-rotate, 0.0f, 0.0f));
531 return set_hpr(LVecBase3(0.0f, 0.0f, -rotate));
533 return set_hpr(LVecBase3(0.0f, 0.0f, rotate));
547 set_scale2d(
const LVecBase2 &scale)
const {
548 nassertr(!scale.is_nan(),
this);
552 return set_scale(LVecBase3(scale[0], scale[1], 1.0f));
564 set_shear2d(PN_stdfloat shear)
const {
565 nassertr(!cnan(shear),
this);
568 return set_shear(LVecBase3(shear, 0.0f, 0.0f));
601 if (!transform_cache) {
602 return do_compose(other);
608 int index = _composition_cache.
find(other);
610 const Composition &comp = _composition_cache.
get_data(index);
611 if (comp._result !=
nullptr) {
624 Composition &comp = _composition_cache.
modify_data(index);
628 comp._result = result;
651 _composition_cache[other]._result = result;
656 other->_composition_cache[
this]._result =
nullptr;
705 return make_identity();
708 if (!transform_cache) {
709 return do_invert_compose(other);
714 int index = _invert_composition_cache.
find(other);
716 const Composition &comp = _invert_composition_cache.
get_data(index);
717 if (comp._result !=
nullptr) {
731 Composition &comp = _invert_composition_cache.
modify_data(index);
735 comp._result = result;
757 _invert_composition_cache[other]._result = result;
762 other->_invert_composition_cache[
this]._result =
nullptr;
787 if (garbage_collect_states || !transform_cache) {
803 if (auto_break_cycles && uniquify_transforms) {
831 bool TransformState::
832 validate_composition_cache()
const {
836 for (
size_t i = 0; i < size; ++i) {
838 if (source !=
nullptr) {
841 int ri = source->_composition_cache.
find(
this);
845 <<
"TransformState::composition cache is inconsistent!\n";
846 pgraph_cat.error(
false)
847 << *
this <<
" compose " << *source <<
"\n";
848 pgraph_cat.error(
false)
849 <<
"but no reverse\n";
856 for (
size_t i = 0; i < size; ++i) {
858 if (source !=
nullptr) {
861 int ri = source->_invert_composition_cache.
find(
this);
865 <<
"TransformState::invert composition cache is inconsistent!\n";
866 pgraph_cat.error(
false)
867 << *
this <<
" invert compose " << *source <<
"\n";
868 pgraph_cat.error(
false)
869 <<
"but no reverse\n";
881 void TransformState::
882 output(ostream &out)
const {
891 bool output_hpr = !
get_hpr().almost_equal(LVecBase3(0.0f, 0.0f, 0.0f));
907 if (!
get_pos2d().almost_equal(LVecBase2(0.0f, 0.0f))) {
915 if (!
get_scale2d().almost_equal(LVecBase2(1.0f, 1.0f))) {
929 if (!
get_pos().almost_equal(LVecBase3(0.0f, 0.0f, 0.0f))) {
930 out << lead <<
"pos " <<
get_pos();
934 out << lead <<
"hpr " <<
get_hpr();
937 if (!
get_scale().almost_equal(LVecBase3(1.0f, 1.0f, 1.0f))) {
952 out <<
"(almost identity)";
969 void TransformState::
970 write(ostream &out,
int indent_level)
const {
971 indent(out, indent_level) << *
this <<
"\n";
979 void TransformState::
980 write_composition_cache(ostream &out,
int indent_level)
const {
981 indent(out, indent_level + 2) << _composition_cache <<
"\n";
982 indent(out, indent_level + 2) << _invert_composition_cache <<
"\n";
991 if (_states ==
nullptr) {
1011 int TransformState::
1012 get_num_unused_states() {
1013 if (_states ==
nullptr) {
1022 StateCount state_count;
1025 for (
size_t si = 0; si < size; ++si) {
1030 for (i = 0; i < cache_size; ++i) {
1032 if (result !=
nullptr && result != state) {
1034 std::pair<StateCount::iterator, bool> ir =
1035 state_count.insert(StateCount::value_type(result, 1));
1039 (*(ir.first)).second++;
1044 for (i = 0; i < cache_size; ++i) {
1046 if (result !=
nullptr && result != state) {
1047 std::pair<StateCount::iterator, bool> ir =
1048 state_count.insert(StateCount::value_type(result, 1));
1050 (*(ir.first)).second++;
1061 StateCount::iterator sci;
1062 for (sci = state_count.begin(); sci != state_count.end(); ++sci) {
1064 int count = (*sci).second;
1070 if (pgraph_cat.is_debug()) {
1072 <<
"Unused state: " << (
void *)state <<
":"
1074 state->write(pgraph_cat.debug(
false), 2);
1096 int TransformState::
1098 if (_states ==
nullptr) {
1112 TempStates temp_states;
1113 temp_states.reserve(orig_size);
1116 for (
size_t si = 0; si < size; ++si) {
1118 temp_states.push_back(state);
1123 TempStates::iterator ti;
1124 for (ti = temp_states.begin(); ti != temp_states.end(); ++ti) {
1129 for (i = 0; i < cache_size; ++i) {
1131 if (result !=
nullptr && result != state) {
1132 result->cache_unref();
1137 state->_composition_cache.
clear();
1140 for (i = 0; i < cache_size; ++i) {
1142 if (result !=
nullptr && result != state) {
1143 result->cache_unref();
1148 state->_invert_composition_cache.
clear();
1157 return orig_size - new_size;
1166 int TransformState::
1168 if (_states ==
nullptr || !garbage_collect_states) {
1174 PStatTimer timer(_garbage_collect_pcollector);
1178 size_t size = orig_size;
1179 size_t num_this_pass = std::max(0,
int(size * garbage_collect_states_rate));
1180 if (num_this_pass <= 0) {
1184 bool break_and_uniquify = (auto_break_cycles && uniquify_transforms);
1186 size_t si = _garbage_index;
1191 num_this_pass = std::min(num_this_pass, size);
1192 size_t stop_at_element = (si + num_this_pass) % size;
1196 if (break_and_uniquify) {
1203 state->detect_and_break_cycles();
1213 state->release_new();
1214 state->remove_cache_pointers();
1215 state->cache_unref();
1223 if (stop_at_element > 0) {
1228 si = (si + 1) % size;
1229 }
while (si != stop_at_element);
1230 _garbage_index = si;
1242 return (
int)orig_size - (int)size;
1258 void TransformState::
1259 list_cycles(ostream &out) {
1260 if (_states ==
nullptr) {
1266 VisitedStates visited;
1267 CompositionCycleDesc cycle_desc;
1270 for (
size_t si = 0; si < size; ++si) {
1273 bool inserted = visited.insert(state).second;
1275 ++_last_cycle_detect;
1276 if (r_detect_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
1278 CompositionCycleDesc::reverse_iterator csi;
1280 out <<
"\nCycle detected of length " << cycle_desc.size() + 1 <<
":\n"
1281 <<
"state " << (
void *)state <<
":" << state->
get_ref_count()
1283 state->write(out, 2);
1284 for (csi = cycle_desc.rbegin(); csi != cycle_desc.rend(); ++csi) {
1285 const CompositionCycleDescEntry &entry = (*csi);
1286 if (entry._inverted) {
1287 out <<
"invert composed with ";
1289 out <<
"composed with ";
1291 out << (
const void *)entry._obj <<
":" << entry._obj->get_ref_count()
1292 <<
" " << *entry._obj <<
"\n"
1293 <<
"produces " << (
const void *)entry._result <<
":"
1294 << entry._result->get_ref_count() <<
" =\n";
1295 entry._result->write(out, 2);
1296 visited.insert(entry._result);
1301 ++_last_cycle_detect;
1302 if (r_detect_reverse_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
1304 CompositionCycleDesc::iterator csi;
1306 out <<
"\nReverse cycle detected of length " << cycle_desc.size() + 1 <<
":\n"
1308 for (csi = cycle_desc.begin(); csi != cycle_desc.end(); ++csi) {
1309 const CompositionCycleDescEntry &entry = (*csi);
1310 out << (
const void *)entry._result <<
":"
1311 << entry._result->get_ref_count() <<
" =\n";
1312 entry._result->write(out, 2);
1313 out << (
const void *)entry._obj <<
":"
1314 << entry._obj->get_ref_count() <<
" =\n";
1315 entry._obj->write(out, 2);
1316 visited.insert(entry._result);
1318 out << (
void *)state <<
":"
1320 state->write(out, 2);
1335 void TransformState::
1336 list_states(ostream &out) {
1337 if (_states ==
nullptr) {
1338 out <<
"0 states:\n";
1344 out << size <<
" states:\n";
1345 for (
size_t si = 0; si < size; ++si) {
1347 state->write(out, 2);
1357 bool TransformState::
1359 if (_states ==
nullptr) {
1363 PStatTimer timer(_transform_validate_pcollector);
1372 <<
"TransformState::_states cache is invalid!\n";
1378 nassertr(si < size,
false);
1379 nassertr(_states->
get_key(si)->get_ref_count() >= 0,
false);
1382 while (snext < size) {
1383 nassertr(_states->
get_key(snext)->get_ref_count() >= 0,
false);
1385 if (!ssi->validate_composition_cache()) {
1389 bool c = (*ssi) == (*ssnext);
1390 bool ci = (*ssnext) == (*ssi);
1393 <<
"TransformState::operator == () not defined properly!\n";
1394 pgraph_cat.error(
false)
1395 <<
"(a, b): " << c <<
"\n";
1396 pgraph_cat.error(
false)
1397 <<
"(b, a): " << ci <<
"\n";
1398 ssi->write(pgraph_cat.error(
false), 2);
1399 ssnext->write(pgraph_cat.error(
false), 2);
1416 void TransformState::
1418 _states =
new States;
1421 (
"uniquify-matrix",
true,
1422 PRC_DESC(
"Set this true to look up arbitrary 4x4 transform matrices in "
1423 "the cache, to ensure that two differently-computed transforms "
1424 "that happen to encode the same matrix will be collapsed into "
1425 "a single pointer. Nowadays, with the transforms stored in a "
1426 "hashtable, we're generally better off with this set true."));
1430 _uniquify_matrix = uniquify_matrix;
1436 _states_lock =
new LightReMutex(
"TransformState::_states_lock");
1437 _cache_stats.
init();
1450 nassertr(state !=
nullptr, state);
1451 if (!uniquify_transforms && !state->
is_identity()) {
1455 return return_unique(state);
1469 nassertr(state !=
nullptr, state);
1471 if (!transform_cache) {
1476 if (paranoid_const) {
1477 nassertr(validate_states(), state);
1485 if (state->_saved_entry != -1) {
1495 int si = _states->
find(state);
1502 if (garbage_collect_states) {
1508 si = _states->
store(state,
nullptr);
1511 state->_saved_entry = si;
1521 PStatTimer timer(_transform_compose_pcollector);
1523 nassertr((_flags & F_is_invalid) == 0,
this);
1524 nassertr((other->_flags & F_is_invalid) == 0, other);
1526 if (compose_componentwise &&
1542 LPoint3 op = quat.xform(other->
get_pos());
1543 pos += LVecBase2(op[0], op[1]) * scale;
1546 LVecBase2 new_scale = other->
get_scale2d() * scale;
1548 result = make_pos_rotate_scale2d(pos, rotate, new_scale);
1556 pos += quat.xform(other->
get_pos()) * scale;
1558 LVecBase3 new_scale = other->
get_scale() * scale;
1560 result = make_pos_quat_scale(pos, quat, new_scale);
1564 if (paranoid_compose) {
1568 if (!new_mat.almost_equal(result->
get_mat(), 0.1)) {
1570 pgraph_cat.warning()
1571 <<
"Componentwise composition of " << *
this <<
" and " << *other
1573 << *result <<
"\n instead of:\n" << *correct <<
"\n";
1585 return make_mat3(new_mat);
1589 return make_mat(new_mat);
1598 PStatTimer timer(_transform_invert_pcollector);
1600 nassertr((_flags & F_is_invalid) == 0,
this);
1601 nassertr((other->_flags & F_is_invalid) == 0, other);
1603 if (compose_componentwise &&
1620 if (scale == 0.0f) {
1621 ((
TransformState *)
this)->_flags |= F_is_singular | F_singular_known;
1622 return make_invalid();
1624 scale = 1.0f / scale;
1625 quat.invert_in_place();
1627 LVecBase3 mp = quat.xform(-LVecBase3(pos[0], pos[1], 0.0f));
1628 pos = LVecBase2(mp[0], mp[1]) * scale;
1629 LVecBase2 new_scale(scale, scale);
1633 LPoint3 op = quat.xform(other->
get_pos());
1634 pos += LVecBase2(op[0], op[1]) * scale;
1640 result = make_pos_rotate_scale2d(pos, rotate, new_scale);
1649 if (scale == 0.0f) {
1650 ((
TransformState *)
this)->_flags |= F_is_singular | F_singular_known;
1651 return make_invalid();
1653 scale = 1.0f / scale;
1654 quat.invert_in_place();
1655 pos = quat.xform(-pos) * scale;
1656 LVecBase3 new_scale(scale, scale, scale);
1660 pos += quat.xform(other->
get_pos()) * scale;
1665 result = make_pos_quat_scale(pos, quat, new_scale);
1669 if (paranoid_compose) {
1672 pgraph_cat.warning()
1673 <<
"Unexpected singular matrix found for " << *
this <<
"\n";
1675 nassertr(_inv_mat !=
nullptr, make_invalid());
1677 new_mat.multiply(other->
get_mat(), *_inv_mat);
1678 if (!new_mat.almost_equal(result->
get_mat(), 0.1)) {
1680 pgraph_cat.warning()
1681 <<
"Componentwise invert-composition of " << *
this <<
" and " << *other
1683 << *result <<
"\n instead of:\n" << *correct <<
"\n";
1694 return make_invalid();
1699 nassertr(_inv_mat !=
nullptr, make_invalid());
1702 const LMatrix4 &i = *_inv_mat;
1703 LMatrix3 inv3(i(0, 0), i(0, 1), i(0, 3),
1704 i(1, 0), i(1, 1), i(1, 3),
1705 i(3, 0), i(3, 1), i(3, 3));
1707 return make_mat3(inv3);
1709 return make_mat3(other->
get_mat3() * inv3);
1713 return make_mat(*_inv_mat);
1715 return make_mat(other->
get_mat() * (*_inv_mat));
1724 void TransformState::
1725 detect_and_break_cycles() {
1726 PStatTimer timer(_transform_break_cycles_pcollector);
1728 ++_last_cycle_detect;
1729 if (r_detect_cycles(
this,
this, 1, _last_cycle_detect,
nullptr)) {
1732 if (pgraph_cat.is_debug()) {
1734 <<
"Breaking cycle involving " << (*this) <<
"\n";
1737 remove_cache_pointers();
1739 ++_last_cycle_detect;
1740 if (r_detect_reverse_cycles(
this,
this, 1, _last_cycle_detect,
nullptr)) {
1741 if (pgraph_cat.is_debug()) {
1743 <<
"Breaking cycle involving " << (*this) <<
"\n";
1746 remove_cache_pointers();
1758 bool TransformState::
1763 if (current_state->_cycle_detect == this_seq) {
1769 return (current_state == start_state && length > 2);
1774 size_t cache_size = current_state->_composition_cache.
get_num_entries();
1775 for (i = 0; i < cache_size; ++i) {
1777 if (result !=
nullptr) {
1778 if (r_detect_cycles(start_state, result, length + 1,
1779 this_seq, cycle_desc)) {
1781 if (cycle_desc !=
nullptr) {
1783 CompositionCycleDescEntry entry(other, result,
false);
1784 cycle_desc->push_back(entry);
1791 cache_size = current_state->_invert_composition_cache.
get_num_entries();
1792 for (i = 0; i < cache_size; ++i) {
1794 if (result !=
nullptr) {
1795 if (r_detect_cycles(start_state, result, length + 1,
1796 this_seq, cycle_desc)) {
1798 if (cycle_desc !=
nullptr) {
1800 CompositionCycleDescEntry entry(other, result,
true);
1801 cycle_desc->push_back(entry);
1817 bool TransformState::
1822 if (current_state->_cycle_detect == this_seq) {
1828 return (current_state == start_state && length > 2);
1833 size_t cache_size = current_state->_composition_cache.
get_num_entries();
1834 for (i = 0; i < cache_size; ++i) {
1836 if (other != current_state) {
1837 int oi = other->_composition_cache.
find(current_state);
1838 nassertr(oi != -1,
false);
1841 if (result !=
nullptr) {
1842 if (r_detect_reverse_cycles(start_state, result, length + 1,
1843 this_seq, cycle_desc)) {
1845 if (cycle_desc !=
nullptr) {
1847 CompositionCycleDescEntry entry(other, result,
false);
1848 cycle_desc->push_back(entry);
1856 cache_size = current_state->_invert_composition_cache.
get_num_entries();
1857 for (i = 0; i < cache_size; ++i) {
1859 if (other != current_state) {
1860 int oi = other->_invert_composition_cache.
find(current_state);
1861 nassertr(oi != -1,
false);
1864 if (result !=
nullptr) {
1865 if (r_detect_reverse_cycles(start_state, result, length + 1,
1866 this_seq, cycle_desc)) {
1868 if (cycle_desc !=
nullptr) {
1870 CompositionCycleDescEntry entry(other, result,
false);
1871 cycle_desc->push_back(entry);
1890 void TransformState::
1894 if (_saved_entry != -1) {
1896 nassertv_always(_states->
remove(
this));
1907 void TransformState::
1908 remove_cache_pointers() {
1927 if (_composition_cache.
is_empty() && _invert_composition_cache.
is_empty()) {
1936 while (!_composition_cache.
is_empty()) {
1948 Composition comp = _composition_cache.
get_data(i);
1957 if (other !=
this) {
1958 int oi = other->_composition_cache.
find(
this);
1964 Composition ocomp = other->_composition_cache.
get_data(oi);
1973 if (ocomp._result !=
nullptr && ocomp._result != other) {
1981 if (comp._result !=
nullptr && comp._result !=
this) {
1988 while (!_invert_composition_cache.
is_empty()) {
1990 nassertv(other !=
this);
1991 Composition comp = _invert_composition_cache.
get_data(i);
1995 if (other !=
this) {
1996 int oi = other->_invert_composition_cache.
find(
this);
1998 Composition ocomp = other->_invert_composition_cache.
get_data(oi);
2002 if (ocomp._result !=
nullptr && ocomp._result != other) {
2007 if (comp._result !=
nullptr && comp._result !=
this) {
2016 void TransformState::
2018 PStatTimer timer(_transform_hash_pcollector);
2021 static const int significant_flags =
2022 (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_is_2d);
2024 int flags = (_flags & significant_flags);
2027 if ((_flags & (F_is_invalid | F_is_identity)) == 0) {
2031 if ((_flags & F_components_given) != 0) {
2033 _hash = _pos.add_hash(_hash);
2034 if ((_flags & F_hpr_given) != 0) {
2035 _hash = _hpr.add_hash(_hash);
2037 }
else if ((_flags & F_quat_given) != 0) {
2038 _hash = _quat.add_hash(_hash);
2041 _hash = _scale.add_hash(_hash);
2042 _hash = _shear.add_hash(_hash);
2046 if (_uniquify_matrix) {
2048 if ((_flags & F_mat_known) == 0) {
2052 _hash = _mat.add_hash(_hash);
2064 _flags |= F_hash_known;
2071 void TransformState::
2074 if ((_flags & F_singular_known) != 0) {
2079 PStatTimer timer(_transform_calc_pcollector);
2081 nassertv((_flags & F_is_invalid) == 0);
2089 nassertv(_inv_mat ==
nullptr);
2090 _inv_mat =
new LMatrix4;
2092 if ((_flags & F_mat_known) == 0) {
2095 bool inverted = _inv_mat->invert_from(_mat);
2098 _flags |= F_is_singular;
2102 _flags |= F_singular_known;
2109 void TransformState::
2110 do_calc_components() {
2111 if ((_flags & F_components_known) != 0) {
2116 PStatTimer timer(_transform_calc_pcollector);
2118 nassertv((_flags & F_is_invalid) == 0);
2119 if ((_flags & F_is_identity) != 0) {
2120 _scale.set(1.0f, 1.0f, 1.0f);
2121 _shear.set(0.0f, 0.0f, 0.0f);
2122 _hpr.set(0.0f, 0.0f, 0.0f);
2123 _quat = LQuaternion::ident_quat();
2124 _pos.set(0.0f, 0.0f, 0.0f);
2125 _flags |= F_has_components | F_components_known | F_hpr_known | F_quat_known | F_uniform_scale | F_identity_scale;
2130 nassertv((_flags & F_mat_known) != 0);
2132 if ((_flags & F_mat_known) == 0) {
2135 bool possible = decompose_matrix(_mat, _scale, _shear, _hpr, _pos);
2140 _flags |= F_components_known | F_hpr_known;
2144 _flags |= F_has_components | F_components_known | F_hpr_known;
2145 check_uniform_scale();
2149 _mat.get_row3(_pos, 3);
2157 void TransformState::
2159 if ((_flags & F_hpr_known) != 0) {
2164 PStatTimer timer(_transform_calc_pcollector);
2166 nassertv((_flags & F_is_invalid) == 0);
2167 if ((_flags & F_components_known) == 0) {
2168 do_calc_components();
2170 if ((_flags & F_hpr_known) == 0) {
2173 nassertv((_flags & F_quat_known) != 0);
2174 _hpr = _quat.get_hpr();
2175 _flags |= F_hpr_known;
2182 void TransformState::
2185 if ((_flags & F_quat_known) != 0) {
2190 PStatTimer timer(_transform_calc_pcollector);
2192 nassertv((_flags & F_is_invalid) == 0);
2193 if ((_flags & F_components_known) == 0) {
2194 do_calc_components();
2196 if ((_flags & F_quat_known) == 0) {
2199 nassertv((_flags & F_hpr_known) != 0);
2200 _quat.set_hpr(_hpr);
2201 _flags |= F_quat_known;
2208 void TransformState::
2210 PStatTimer timer(_transform_calc_pcollector);
2215 _norm_quat.normalize();
2216 _flags |= F_norm_quat_known;
2223 void TransformState::
2225 if ((_flags & F_mat_known) != 0) {
2230 PStatTimer timer(_transform_calc_pcollector);
2232 nassertv((_flags & F_is_invalid) == 0);
2233 if ((_flags & F_is_identity) != 0) {
2234 _mat = LMatrix4::ident_mat();
2239 nassertv((_flags & F_components_known) != 0);
2240 if ((_flags & F_hpr_known) == 0) {
2244 compose_matrix(_mat, _scale, _shear,
get_hpr(), _pos);
2246 _flags |= F_mat_known;
2254 void TransformState::
2255 update_pstats(
int old_referenced_bits,
int new_referenced_bits) {
2257 if ((old_referenced_bits & R_node) != 0) {
2258 _node_counter.sub_level(1);
2259 }
else if ((old_referenced_bits & R_cache) != 0) {
2260 _cache_counter.sub_level(1);
2262 if ((new_referenced_bits & R_node) != 0) {
2263 _node_counter.add_level(1);
2264 }
else if ((new_referenced_bits & R_cache) != 0) {
2265 _cache_counter.add_level(1);
2273 void TransformState::
2274 register_with_read_factory() {
2286 if ((_flags & F_is_identity) != 0) {
2288 int flags = F_is_identity | F_singular_known | F_is_2d;
2291 }
else if ((_flags & F_is_invalid) != 0) {
2293 int flags = F_is_invalid | F_singular_known | F_is_singular | F_components_known | F_mat_known;
2296 }
else if ((_flags & F_components_given) != 0) {
2298 int flags = F_components_given | F_components_known | F_has_components;
2299 flags |= (_flags & F_is_2d);
2300 if ((_flags & F_quat_given) != 0) {
2301 flags |= (F_quat_given | F_quat_known);
2302 }
else if ((_flags & F_hpr_given) != 0) {
2303 flags |= (F_hpr_given | F_hpr_known);
2308 _pos.write_datagram(dg);
2309 if ((_flags & F_quat_given) != 0) {
2310 _quat.write_datagram(dg);
2314 _scale.write_datagram(dg);
2315 _shear.write_datagram(dg);
2319 nassertv((_flags & F_mat_known) != 0);
2320 int flags = F_mat_known;
2321 flags |= (_flags & F_is_2d);
2323 _mat.write_datagram(dg);
2358 state->fillin(scan, manager);
2368 void TransformState::
2373 if ((_flags & F_components_given) != 0) {
2375 _pos.read_datagram(scan);
2376 if ((_flags & F_quat_given) != 0) {
2377 _quat.read_datagram(scan);
2379 _hpr.read_datagram(scan);
2381 _scale.read_datagram(scan);
2382 _shear.read_datagram(scan);
2384 check_uniform_scale();
2387 if ((_flags & F_mat_known) != 0) {
2389 _mat.read_datagram(scan);