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();
1438 nassertv(Thread::get_current_thread() == Thread::get_main_thread());
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);
get_ref_count
Returns the current reference count.
static size_t add_hash(size_t start, const void *key)
Adds the indicated key into a running hash.
This is our own Panda specialization on the default STL map.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Value & modify_data(size_t n)
Returns a modifiable reference to the data in the nth entry of the table.
void inc_dels()
Increments by 1 the count of elements removed from the cache.
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
This is a convenience class to specialize ConfigVariable as a boolean type.
void cache_unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
Base class for objects that can be written to and read from Bam files.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool debug_is_locked() const
Returns true if the current thread has locked the LightReMutex, false otherwise.
A lightweight reentrant mutex.
const Value & get_data(size_t n) const
Returns the data in the nth entry of the table.
int store(const Key &key, const Value &data)
Records the indicated key/data pair in the map.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
This template class implements an unordered map of keys to data, implemented as a hashtable.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void clear()
Completely empties the table.
virtual void fillin(DatagramIterator &scan, BamReader *manager)
This internal function is intended to be called by each class's make_from_bam() method to read in all...
void register_change_this(ChangeThisFunc func, TypedWritable *whom)
Called by an object reading itself from the bam file to indicate that the object pointer that will be...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
This is our own Panda specialization on the default STL vector.
static size_t add_hash(size_t start, const Key &key)
Adds the indicated key into a running hash.
size_t get_num_entries() const
Returns the number of active entries in the table.
A lightweight class that represents a single element that may be timed and/or counted via stats.
void maybe_report(const char *name)
Outputs a report if enough time has elapsed.
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
void inc_hits()
Increments by 1 the count of cache hits.
void inc_misses()
Increments by 1 the count of cache misses.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Similar to MutexHolder, but for a light mutex.
void init()
Initializes the CacheStats for the first time.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
const Key & get_key(size_t n) const
Returns the key in the nth entry of the table.
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
void add_total_size(int count)
Adds the indicated count (positive or negative) to the total number of entries for the cache (net occ...
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool validate() const
Returns true if the internal table appears to be consistent, false if there are some internal errors.
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
Similar to MutexHolder, but for a light reentrant mutex.
void remove_element(size_t n)
Removes the nth entry from the table.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool consider_shrink_table()
Shrinks the table if the allocated storage is significantly larger than the number of elements in it.
static void update_type(ReferenceCount *ptr, TypeHandle type)
Associates the indicated type with the given pointer.
get_cache_ref_count
Returns the current reference count.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
void add_num_states(int count)
Adds the indicated count (positive or negative) to the total count of individual RenderState or Trans...
This is used to track the utilization of the TransformState and RenderState caches,...
bool is_empty() const
Returns true if the table is empty; i.e.
This is our own Panda specialization on the default STL set.
A class to retrieve the individual data elements previously stored in a Datagram.
TypeHandle is the identifier used to differentiate C++ class types.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a sequence number that increments monotonically.
void inc_adds(bool is_new)
Increments by 1 the count of elements added to the cache.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
bool remove(const Key &key)
Removes the indicated key and its associated data from the table.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool unref() const
Explicitly decrements the reference count.
int find(const Key &key) const
Searches for the indicated key in the table.