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();
1214 state->release_new();
1215 state->remove_cache_pointers();
1216 state->cache_unref_only();
1224 if (stop_at_element > 0) {
1229 si = (si + 1) % size;
1230 }
while (si != stop_at_element);
1231 _garbage_index = si;
1243 return (
int)orig_size - (int)size;
1259 void TransformState::
1260 list_cycles(ostream &out) {
1261 if (_states ==
nullptr) {
1267 VisitedStates visited;
1268 CompositionCycleDesc cycle_desc;
1271 for (
size_t si = 0; si < size; ++si) {
1274 bool inserted = visited.insert(state).second;
1276 ++_last_cycle_detect;
1277 if (r_detect_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
1279 CompositionCycleDesc::reverse_iterator csi;
1281 out <<
"\nCycle detected of length " << cycle_desc.size() + 1 <<
":\n"
1282 <<
"state " << (
void *)state <<
":" << state->
get_ref_count()
1284 state->write(out, 2);
1285 for (csi = cycle_desc.rbegin(); csi != cycle_desc.rend(); ++csi) {
1286 const CompositionCycleDescEntry &entry = (*csi);
1287 if (entry._inverted) {
1288 out <<
"invert composed with ";
1290 out <<
"composed with ";
1292 out << (
const void *)entry._obj <<
":" << entry._obj->get_ref_count()
1293 <<
" " << *entry._obj <<
"\n"
1294 <<
"produces " << (
const void *)entry._result <<
":"
1295 << entry._result->get_ref_count() <<
" =\n";
1296 entry._result->write(out, 2);
1297 visited.insert(entry._result);
1302 ++_last_cycle_detect;
1303 if (r_detect_reverse_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
1305 CompositionCycleDesc::iterator csi;
1307 out <<
"\nReverse cycle detected of length " << cycle_desc.size() + 1 <<
":\n"
1309 for (csi = cycle_desc.begin(); csi != cycle_desc.end(); ++csi) {
1310 const CompositionCycleDescEntry &entry = (*csi);
1311 out << (
const void *)entry._result <<
":"
1312 << entry._result->get_ref_count() <<
" =\n";
1313 entry._result->write(out, 2);
1314 out << (
const void *)entry._obj <<
":"
1315 << entry._obj->get_ref_count() <<
" =\n";
1316 entry._obj->write(out, 2);
1317 visited.insert(entry._result);
1319 out << (
void *)state <<
":"
1321 state->write(out, 2);
1336 void TransformState::
1337 list_states(ostream &out) {
1338 if (_states ==
nullptr) {
1339 out <<
"0 states:\n";
1345 out << size <<
" states:\n";
1346 for (
size_t si = 0; si < size; ++si) {
1348 state->write(out, 2);
1358 bool TransformState::
1360 if (_states ==
nullptr) {
1364 PStatTimer timer(_transform_validate_pcollector);
1373 <<
"TransformState::_states cache is invalid!\n";
1379 nassertr(si < size,
false);
1380 nassertr(_states->
get_key(si)->get_ref_count() >= 0,
false);
1383 while (snext < size) {
1384 nassertr(_states->
get_key(snext)->get_ref_count() >= 0,
false);
1386 if (!ssi->validate_composition_cache()) {
1390 bool c = (*ssi) == (*ssnext);
1391 bool ci = (*ssnext) == (*ssi);
1394 <<
"TransformState::operator == () not defined properly!\n";
1395 pgraph_cat.error(
false)
1396 <<
"(a, b): " << c <<
"\n";
1397 pgraph_cat.error(
false)
1398 <<
"(b, a): " << ci <<
"\n";
1399 ssi->write(pgraph_cat.error(
false), 2);
1400 ssnext->write(pgraph_cat.error(
false), 2);
1417 void TransformState::
1419 _states =
new States;
1422 (
"uniquify-matrix",
true,
1423 PRC_DESC(
"Set this true to look up arbitrary 4x4 transform matrices in "
1424 "the cache, to ensure that two differently-computed transforms "
1425 "that happen to encode the same matrix will be collapsed into "
1426 "a single pointer. Nowadays, with the transforms stored in a "
1427 "hashtable, we're generally better off with this set true."));
1431 _uniquify_matrix = uniquify_matrix;
1437 _states_lock =
new LightReMutex(
"TransformState::_states_lock");
1438 _cache_stats.
init();
1451 nassertr(state !=
nullptr, state);
1452 if (!uniquify_transforms && !state->
is_identity()) {
1456 return return_unique(state);
1470 nassertr(state !=
nullptr, state);
1472 if (!transform_cache) {
1477 if (paranoid_const) {
1478 nassertr(validate_states(), state);
1486 if (state->_saved_entry != -1) {
1496 int si = _states->
find(state);
1503 if (garbage_collect_states) {
1509 si = _states->
store(state,
nullptr);
1512 state->_saved_entry = si;
1522 PStatTimer timer(_transform_compose_pcollector);
1524 nassertr((_flags & F_is_invalid) == 0,
this);
1525 nassertr((other->_flags & F_is_invalid) == 0, other);
1527 if (compose_componentwise &&
1543 LPoint3 op = quat.xform(other->
get_pos());
1544 pos += LVecBase2(op[0], op[1]) * scale;
1547 LVecBase2 new_scale = other->
get_scale2d() * scale;
1549 result = make_pos_rotate_scale2d(pos, rotate, new_scale);
1557 pos += quat.xform(other->
get_pos()) * scale;
1559 LVecBase3 new_scale = other->
get_scale() * scale;
1561 result = make_pos_quat_scale(pos, quat, new_scale);
1565 if (paranoid_compose) {
1569 if (!new_mat.almost_equal(result->
get_mat(), 0.1)) {
1571 pgraph_cat.warning()
1572 <<
"Componentwise composition of " << *
this <<
" and " << *other
1574 << *result <<
"\n instead of:\n" << *correct <<
"\n";
1586 return make_mat3(new_mat);
1590 return make_mat(new_mat);
1599 PStatTimer timer(_transform_invert_pcollector);
1601 nassertr((_flags & F_is_invalid) == 0,
this);
1602 nassertr((other->_flags & F_is_invalid) == 0, other);
1604 if (compose_componentwise &&
1621 if (scale == 0.0f) {
1622 ((
TransformState *)
this)->_flags |= F_is_singular | F_singular_known;
1623 return make_invalid();
1625 scale = 1.0f / scale;
1626 quat.invert_in_place();
1628 LVecBase3 mp = quat.xform(-LVecBase3(pos[0], pos[1], 0.0f));
1629 pos = LVecBase2(mp[0], mp[1]) * scale;
1630 LVecBase2 new_scale(scale, scale);
1634 LPoint3 op = quat.xform(other->
get_pos());
1635 pos += LVecBase2(op[0], op[1]) * scale;
1641 result = make_pos_rotate_scale2d(pos, rotate, new_scale);
1650 if (scale == 0.0f) {
1651 ((
TransformState *)
this)->_flags |= F_is_singular | F_singular_known;
1652 return make_invalid();
1654 scale = 1.0f / scale;
1655 quat.invert_in_place();
1656 pos = quat.xform(-pos) * scale;
1657 LVecBase3 new_scale(scale, scale, scale);
1661 pos += quat.xform(other->
get_pos()) * scale;
1666 result = make_pos_quat_scale(pos, quat, new_scale);
1670 if (paranoid_compose) {
1673 pgraph_cat.warning()
1674 <<
"Unexpected singular matrix found for " << *
this <<
"\n";
1676 nassertr(_inv_mat !=
nullptr, make_invalid());
1678 new_mat.multiply(other->
get_mat(), *_inv_mat);
1679 if (!new_mat.almost_equal(result->
get_mat(), 0.1)) {
1681 pgraph_cat.warning()
1682 <<
"Componentwise invert-composition of " << *
this <<
" and " << *other
1684 << *result <<
"\n instead of:\n" << *correct <<
"\n";
1695 return make_invalid();
1700 nassertr(_inv_mat !=
nullptr, make_invalid());
1703 const LMatrix4 &i = *_inv_mat;
1704 LMatrix3 inv3(i(0, 0), i(0, 1), i(0, 3),
1705 i(1, 0), i(1, 1), i(1, 3),
1706 i(3, 0), i(3, 1), i(3, 3));
1708 return make_mat3(inv3);
1710 return make_mat3(other->
get_mat3() * inv3);
1714 return make_mat(*_inv_mat);
1716 return make_mat(other->
get_mat() * (*_inv_mat));
1725 void TransformState::
1726 detect_and_break_cycles() {
1727 PStatTimer timer(_transform_break_cycles_pcollector);
1729 ++_last_cycle_detect;
1730 if (r_detect_cycles(
this,
this, 1, _last_cycle_detect,
nullptr)) {
1733 if (pgraph_cat.is_debug()) {
1735 <<
"Breaking cycle involving " << (*this) <<
"\n";
1738 remove_cache_pointers();
1740 ++_last_cycle_detect;
1741 if (r_detect_reverse_cycles(
this,
this, 1, _last_cycle_detect,
nullptr)) {
1742 if (pgraph_cat.is_debug()) {
1744 <<
"Breaking cycle involving " << (*this) <<
"\n";
1747 remove_cache_pointers();
1759 bool TransformState::
1764 if (current_state->_cycle_detect == this_seq) {
1770 return (current_state == start_state && length > 2);
1775 size_t cache_size = current_state->_composition_cache.
get_num_entries();
1776 for (i = 0; i < cache_size; ++i) {
1778 if (result !=
nullptr) {
1779 if (r_detect_cycles(start_state, result, length + 1,
1780 this_seq, cycle_desc)) {
1782 if (cycle_desc !=
nullptr) {
1784 CompositionCycleDescEntry entry(other, result,
false);
1785 cycle_desc->push_back(entry);
1792 cache_size = current_state->_invert_composition_cache.
get_num_entries();
1793 for (i = 0; i < cache_size; ++i) {
1795 if (result !=
nullptr) {
1796 if (r_detect_cycles(start_state, result, length + 1,
1797 this_seq, cycle_desc)) {
1799 if (cycle_desc !=
nullptr) {
1801 CompositionCycleDescEntry entry(other, result,
true);
1802 cycle_desc->push_back(entry);
1818 bool TransformState::
1823 if (current_state->_cycle_detect == this_seq) {
1829 return (current_state == start_state && length > 2);
1834 size_t cache_size = current_state->_composition_cache.
get_num_entries();
1835 for (i = 0; i < cache_size; ++i) {
1837 if (other != current_state) {
1838 int oi = other->_composition_cache.
find(current_state);
1839 nassertr(oi != -1,
false);
1842 if (result !=
nullptr) {
1843 if (r_detect_reverse_cycles(start_state, result, length + 1,
1844 this_seq, cycle_desc)) {
1846 if (cycle_desc !=
nullptr) {
1848 CompositionCycleDescEntry entry(other, result,
false);
1849 cycle_desc->push_back(entry);
1857 cache_size = current_state->_invert_composition_cache.
get_num_entries();
1858 for (i = 0; i < cache_size; ++i) {
1860 if (other != current_state) {
1861 int oi = other->_invert_composition_cache.
find(current_state);
1862 nassertr(oi != -1,
false);
1865 if (result !=
nullptr) {
1866 if (r_detect_reverse_cycles(start_state, result, length + 1,
1867 this_seq, cycle_desc)) {
1869 if (cycle_desc !=
nullptr) {
1871 CompositionCycleDescEntry entry(other, result,
false);
1872 cycle_desc->push_back(entry);
1891 void TransformState::
1895 if (_saved_entry != -1) {
1897 nassertv_always(_states->
remove(
this));
1908 void TransformState::
1909 remove_cache_pointers() {
1928 if (_composition_cache.
is_empty() && _invert_composition_cache.
is_empty()) {
1937 while (!_composition_cache.
is_empty()) {
1949 Composition comp = _composition_cache.
get_data(i);
1958 if (other !=
this) {
1959 int oi = other->_composition_cache.
find(
this);
1965 Composition ocomp = other->_composition_cache.
get_data(oi);
1974 if (ocomp._result !=
nullptr && ocomp._result != other) {
1982 if (comp._result !=
nullptr && comp._result !=
this) {
1989 while (!_invert_composition_cache.
is_empty()) {
1991 nassertv(other !=
this);
1992 Composition comp = _invert_composition_cache.
get_data(i);
1996 if (other !=
this) {
1997 int oi = other->_invert_composition_cache.
find(
this);
1999 Composition ocomp = other->_invert_composition_cache.
get_data(oi);
2003 if (ocomp._result !=
nullptr && ocomp._result != other) {
2008 if (comp._result !=
nullptr && comp._result !=
this) {
2017 void TransformState::
2019 PStatTimer timer(_transform_hash_pcollector);
2022 static const int significant_flags =
2023 (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_is_2d);
2025 int flags = (_flags & significant_flags);
2028 if ((_flags & (F_is_invalid | F_is_identity)) == 0) {
2032 if ((_flags & F_components_given) != 0) {
2034 _hash = _pos.add_hash(_hash);
2035 if ((_flags & F_hpr_given) != 0) {
2036 _hash = _hpr.add_hash(_hash);
2038 }
else if ((_flags & F_quat_given) != 0) {
2039 _hash = _quat.add_hash(_hash);
2042 _hash = _scale.add_hash(_hash);
2043 _hash = _shear.add_hash(_hash);
2047 if (_uniquify_matrix) {
2049 if ((_flags & F_mat_known) == 0) {
2053 _hash = _mat.add_hash(_hash);
2065 _flags |= F_hash_known;
2072 void TransformState::
2075 if ((_flags & F_singular_known) != 0) {
2080 PStatTimer timer(_transform_calc_pcollector);
2082 nassertv((_flags & F_is_invalid) == 0);
2090 nassertv(_inv_mat ==
nullptr);
2091 _inv_mat =
new LMatrix4;
2093 if ((_flags & F_mat_known) == 0) {
2096 bool inverted = _inv_mat->invert_from(_mat);
2099 _flags |= F_is_singular;
2103 _flags |= F_singular_known;
2110 void TransformState::
2111 do_calc_components() {
2112 if ((_flags & F_components_known) != 0) {
2117 PStatTimer timer(_transform_calc_pcollector);
2119 nassertv((_flags & F_is_invalid) == 0);
2120 if ((_flags & F_is_identity) != 0) {
2121 _scale.set(1.0f, 1.0f, 1.0f);
2122 _shear.set(0.0f, 0.0f, 0.0f);
2123 _hpr.set(0.0f, 0.0f, 0.0f);
2124 _quat = LQuaternion::ident_quat();
2125 _pos.set(0.0f, 0.0f, 0.0f);
2126 _flags |= F_has_components | F_components_known | F_hpr_known | F_quat_known | F_uniform_scale | F_identity_scale;
2131 nassertv((_flags & F_mat_known) != 0);
2133 if ((_flags & F_mat_known) == 0) {
2136 bool possible = decompose_matrix(_mat, _scale, _shear, _hpr, _pos);
2141 _flags |= F_components_known | F_hpr_known;
2145 _flags |= F_has_components | F_components_known | F_hpr_known;
2146 check_uniform_scale();
2150 _mat.get_row3(_pos, 3);
2158 void TransformState::
2160 if ((_flags & F_hpr_known) != 0) {
2165 PStatTimer timer(_transform_calc_pcollector);
2167 nassertv((_flags & F_is_invalid) == 0);
2168 if ((_flags & F_components_known) == 0) {
2169 do_calc_components();
2171 if ((_flags & F_hpr_known) == 0) {
2174 nassertv((_flags & F_quat_known) != 0);
2175 _hpr = _quat.get_hpr();
2176 _flags |= F_hpr_known;
2183 void TransformState::
2186 if ((_flags & F_quat_known) != 0) {
2191 PStatTimer timer(_transform_calc_pcollector);
2193 nassertv((_flags & F_is_invalid) == 0);
2194 if ((_flags & F_components_known) == 0) {
2195 do_calc_components();
2197 if ((_flags & F_quat_known) == 0) {
2200 nassertv((_flags & F_hpr_known) != 0);
2201 _quat.set_hpr(_hpr);
2202 _flags |= F_quat_known;
2209 void TransformState::
2211 PStatTimer timer(_transform_calc_pcollector);
2216 _norm_quat.normalize();
2217 _flags |= F_norm_quat_known;
2224 void TransformState::
2226 if ((_flags & F_mat_known) != 0) {
2231 PStatTimer timer(_transform_calc_pcollector);
2233 nassertv((_flags & F_is_invalid) == 0);
2234 if ((_flags & F_is_identity) != 0) {
2235 _mat = LMatrix4::ident_mat();
2240 nassertv((_flags & F_components_known) != 0);
2241 if ((_flags & F_hpr_known) == 0) {
2245 compose_matrix(_mat, _scale, _shear,
get_hpr(), _pos);
2247 _flags |= F_mat_known;
2255 void TransformState::
2256 update_pstats(
int old_referenced_bits,
int new_referenced_bits) {
2258 if ((old_referenced_bits & R_node) != 0) {
2259 _node_counter.sub_level(1);
2260 }
else if ((old_referenced_bits & R_cache) != 0) {
2261 _cache_counter.sub_level(1);
2263 if ((new_referenced_bits & R_node) != 0) {
2264 _node_counter.add_level(1);
2265 }
else if ((new_referenced_bits & R_cache) != 0) {
2266 _cache_counter.add_level(1);
2274 void TransformState::
2275 register_with_read_factory() {
2287 if ((_flags & F_is_identity) != 0) {
2289 int flags = F_is_identity | F_singular_known | F_is_2d;
2292 }
else if ((_flags & F_is_invalid) != 0) {
2294 int flags = F_is_invalid | F_singular_known | F_is_singular | F_components_known | F_mat_known;
2297 }
else if ((_flags & F_components_given) != 0) {
2299 int flags = F_components_given | F_components_known | F_has_components;
2300 flags |= (_flags & F_is_2d);
2301 if ((_flags & F_quat_given) != 0) {
2302 flags |= (F_quat_given | F_quat_known);
2303 }
else if ((_flags & F_hpr_given) != 0) {
2304 flags |= (F_hpr_given | F_hpr_known);
2309 _pos.write_datagram(dg);
2310 if ((_flags & F_quat_given) != 0) {
2311 _quat.write_datagram(dg);
2315 _scale.write_datagram(dg);
2316 _shear.write_datagram(dg);
2320 nassertv((_flags & F_mat_known) != 0);
2321 int flags = F_mat_known;
2322 flags |= (_flags & F_is_2d);
2324 _mat.write_datagram(dg);
2359 state->fillin(scan, manager);
2369 void TransformState::
2374 if ((_flags & F_components_given) != 0) {
2376 _pos.read_datagram(scan);
2377 if ((_flags & F_quat_given) != 0) {
2378 _quat.read_datagram(scan);
2380 _hpr.read_datagram(scan);
2382 _scale.read_datagram(scan);
2383 _shear.read_datagram(scan);
2385 check_uniform_scale();
2388 if ((_flags & F_mat_known) != 0) {
2390 _mat.read_datagram(scan);