33UpdateSeq TransformState::_last_cycle_detect;
34size_t TransformState::_garbage_index = 0;
35bool TransformState::_uniquify_matrix =
true;
37PStatCollector TransformState::_cache_update_pcollector(
"*:State Cache:Update");
38PStatCollector TransformState::_garbage_collect_pcollector(
"*:State Cache:Garbage Collect");
39PStatCollector TransformState::_transform_compose_pcollector(
"*:State Cache:Compose Transform");
40PStatCollector TransformState::_transform_invert_pcollector(
"*:State Cache:Invert Transform");
41PStatCollector TransformState::_transform_calc_pcollector(
"*:State Cache:Calc Components");
42PStatCollector TransformState::_transform_break_cycles_pcollector(
"*:State Cache:Break Cycles");
43PStatCollector TransformState::_transform_new_pcollector(
"*:State Cache:New");
44PStatCollector TransformState::_transform_validate_pcollector(
"*:State Cache:Validate");
45PStatCollector TransformState::_transform_hash_pcollector(
"*:State Cache:Calc Hash");
46PStatCollector TransformState::_node_counter(
"TransformStates:On nodes");
47PStatCollector TransformState::_cache_counter(
"TransformStates:Cached");
59TransformState() : _lock(
"TransformState") {
60 if (_states ==
nullptr) {
64 _flags = F_is_identity | F_singular_known | F_is_2d;
66 _cache_stats.add_num_states(1);
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;
271make_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);
296make_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);
321make_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);
338make_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);
380make_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);
401set_pos(
const LVecBase3 &pos)
const {
402 nassertr(!pos.is_nan(),
this);
416 return make_mat(mat);
426set_hpr(
const LVecBase3 &hpr)
const {
427 nassertr(!hpr.is_nan(),
this);
439set_quat(
const LQuaternion &quat)
const {
440 nassertr(!quat.is_nan(),
this);
452set_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]),
477set_shear(
const LVecBase3 &shear)
const {
478 nassertr(!shear.is_nan(),
this);
493set_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);
519set_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));
547set_scale2d(
const LVecBase2 &scale)
const {
548 nassertr(!scale.is_nan(),
this);
552 return set_scale(LVecBase3(scale[0], scale[1], 1.0f));
564set_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) {
832validate_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";
882output(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)";
970write(ostream &out,
int indent_level)
const {
971 indent(out, indent_level) << *
this <<
"\n";
980write_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) {
1012get_num_unused_states() {
1013 if (_states ==
nullptr) {
1022 StateCount state_count;
1025 for (
size_t si = 0; si < size; ++si) {
1028 std::pair<StateCount::iterator, bool> ir =
1029 state_count.insert(StateCount::value_type(state, 1));
1033 (*(ir.first)).second++;
1038 for (i = 0; i < cache_size; ++i) {
1040 if (result !=
nullptr && result != state) {
1042 std::pair<StateCount::iterator, bool> ir =
1043 state_count.insert(StateCount::value_type(result, 1));
1047 (*(ir.first)).second++;
1052 for (i = 0; i < cache_size; ++i) {
1054 if (result !=
nullptr && result != state) {
1055 std::pair<StateCount::iterator, bool> ir =
1056 state_count.insert(StateCount::value_type(result, 1));
1058 (*(ir.first)).second++;
1069 StateCount::iterator sci;
1070 for (sci = state_count.begin(); sci != state_count.end(); ++sci) {
1072 int count = (*sci).second;
1078 if (pgraph_cat.is_debug()) {
1080 <<
"Unused state: " << (
void *)state <<
":"
1082 state->write(pgraph_cat.debug(
false), 2);
1106 if (_states ==
nullptr) {
1120 TempStates temp_states;
1121 temp_states.reserve(orig_size);
1124 for (
size_t si = 0; si < size; ++si) {
1126 temp_states.push_back(state);
1131 TempStates::iterator ti;
1132 for (ti = temp_states.begin(); ti != temp_states.end(); ++ti) {
1137 for (i = 0; i < cache_size; ++i) {
1139 if (result !=
nullptr && result != state) {
1140 result->cache_unref();
1145 state->_composition_cache.
clear();
1148 for (i = 0; i < cache_size; ++i) {
1150 if (result !=
nullptr && result != state) {
1151 result->cache_unref();
1156 state->_invert_composition_cache.
clear();
1165 return orig_size - new_size;
1176 if (_states ==
nullptr || !garbage_collect_states) {
1182 PStatTimer timer(_garbage_collect_pcollector);
1186 size_t size = orig_size;
1187 size_t num_this_pass = std::max(0,
int(size * garbage_collect_states_rate));
1188 if (num_this_pass <= 0) {
1192 bool break_and_uniquify = (auto_break_cycles && uniquify_transforms);
1194 size_t si = _garbage_index;
1199 num_this_pass = std::min(num_this_pass, size);
1200 size_t stop_at_element = (si + num_this_pass) % size;
1204 if (break_and_uniquify) {
1211 state->detect_and_break_cycles();
1222 state->release_new();
1223 state->remove_cache_pointers();
1224 state->cache_unref_only();
1232 if (stop_at_element > 0) {
1237 si = (si + 1) % size;
1238 }
while (si != stop_at_element);
1239 _garbage_index = si;
1251 return (
int)orig_size - (int)size;
1267void TransformState::
1268list_cycles(ostream &out) {
1269 if (_states ==
nullptr) {
1275 VisitedStates visited;
1276 CompositionCycleDesc cycle_desc;
1279 for (
size_t si = 0; si < size; ++si) {
1282 bool inserted = visited.insert(state).second;
1284 ++_last_cycle_detect;
1285 if (r_detect_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
1287 CompositionCycleDesc::reverse_iterator csi;
1289 out <<
"\nCycle detected of length " << cycle_desc.size() + 1 <<
":\n"
1290 <<
"state " << (
void *)state <<
":" << state->
get_ref_count()
1292 state->write(out, 2);
1293 for (csi = cycle_desc.rbegin(); csi != cycle_desc.rend(); ++csi) {
1294 const CompositionCycleDescEntry &entry = (*csi);
1295 if (entry._inverted) {
1296 out <<
"invert composed with ";
1298 out <<
"composed with ";
1300 out << (
const void *)entry._obj <<
":" << entry._obj->get_ref_count()
1301 <<
" " << *entry._obj <<
"\n"
1302 <<
"produces " << (
const void *)entry._result <<
":"
1303 << entry._result->get_ref_count() <<
" =\n";
1304 entry._result->write(out, 2);
1305 visited.insert(entry._result);
1310 ++_last_cycle_detect;
1311 if (r_detect_reverse_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) {
1313 CompositionCycleDesc::iterator csi;
1315 out <<
"\nReverse cycle detected of length " << cycle_desc.size() + 1 <<
":\n"
1317 for (csi = cycle_desc.begin(); csi != cycle_desc.end(); ++csi) {
1318 const CompositionCycleDescEntry &entry = (*csi);
1319 out << (
const void *)entry._result <<
":"
1320 << entry._result->get_ref_count() <<
" =\n";
1321 entry._result->write(out, 2);
1322 out << (
const void *)entry._obj <<
":"
1323 << entry._obj->get_ref_count() <<
" =\n";
1324 entry._obj->write(out, 2);
1325 visited.insert(entry._result);
1327 out << (
void *)state <<
":"
1329 state->write(out, 2);
1344void TransformState::
1345list_states(ostream &out) {
1346 if (_states ==
nullptr) {
1347 out <<
"0 states:\n";
1353 out << size <<
" states:\n";
1354 for (
size_t si = 0; si < size; ++si) {
1356 state->write(out, 2);
1366bool TransformState::
1368 if (_states ==
nullptr) {
1372 PStatTimer timer(_transform_validate_pcollector);
1381 <<
"TransformState::_states cache is invalid!\n";
1387 nassertr(si < size,
false);
1388 nassertr(_states->
get_key(si)->get_ref_count() >= 0,
false);
1391 while (snext < size) {
1392 nassertr(_states->
get_key(snext)->get_ref_count() >= 0,
false);
1394 if (!ssi->validate_composition_cache()) {
1398 bool c = (*ssi) == (*ssnext);
1399 bool ci = (*ssnext) == (*ssi);
1402 <<
"TransformState::operator == () not defined properly!\n";
1403 pgraph_cat.error(
false)
1404 <<
"(a, b): " << c <<
"\n";
1405 pgraph_cat.error(
false)
1406 <<
"(b, a): " << ci <<
"\n";
1407 ssi->write(pgraph_cat.error(
false), 2);
1408 ssnext->write(pgraph_cat.error(
false), 2);
1425void TransformState::
1427 _states =
new States;
1430 (
"uniquify-matrix",
true,
1431 PRC_DESC(
"Set this true to look up arbitrary 4x4 transform matrices in "
1432 "the cache, to ensure that two differently-computed transforms "
1433 "that happen to encode the same matrix will be collapsed into "
1434 "a single pointer. Nowadays, with the transforms stored in a "
1435 "hashtable, we're generally better off with this set true."));
1439 _uniquify_matrix = uniquify_matrix;
1445 _states_lock =
new LightReMutex(
"TransformState::_states_lock");
1446 _cache_stats.
init();
1459 nassertr(state !=
nullptr, state);
1460 if (!uniquify_transforms && !state->
is_identity()) {
1464 return return_unique(state);
1478 nassertr(state !=
nullptr, state);
1480 if (!transform_cache) {
1485 if (paranoid_const) {
1486 nassertr(validate_states(), state);
1494 if (state->_saved_entry != -1) {
1504 int si = _states->
find(state);
1511 if (garbage_collect_states) {
1517 si = _states->
store(state,
nullptr);
1520 state->_saved_entry = si;
1530 PStatTimer timer(_transform_compose_pcollector);
1532 nassertr((_flags & F_is_invalid) == 0,
this);
1533 nassertr((other->_flags & F_is_invalid) == 0, other);
1535 if (compose_componentwise &&
1551 LPoint3 op = quat.xform(other->
get_pos());
1552 pos += LVecBase2(op[0], op[1]) * scale;
1555 LVecBase2 new_scale = other->
get_scale2d() * scale;
1557 result = make_pos_rotate_scale2d(pos, rotate, new_scale);
1565 pos += quat.xform(other->
get_pos()) * scale;
1567 LVecBase3 new_scale = other->
get_scale() * scale;
1569 result = make_pos_quat_scale(pos, quat, new_scale);
1573 if (paranoid_compose) {
1577 if (!new_mat.almost_equal(result->
get_mat(), 0.1)) {
1579 pgraph_cat.warning()
1580 <<
"Componentwise composition of " << *
this <<
" and " << *other
1582 << *result <<
"\n instead of:\n" << *correct <<
"\n";
1594 return make_mat3(new_mat);
1598 return make_mat(new_mat);
1607 PStatTimer timer(_transform_invert_pcollector);
1609 nassertr((_flags & F_is_invalid) == 0,
this);
1610 nassertr((other->_flags & F_is_invalid) == 0, other);
1612 if (compose_componentwise &&
1629 if (scale == 0.0f) {
1630 ((
TransformState *)
this)->_flags |= F_is_singular | F_singular_known;
1631 return make_invalid();
1633 scale = 1.0f / scale;
1634 quat.invert_in_place();
1636 LVecBase3 mp = quat.xform(-LVecBase3(pos[0], pos[1], 0.0f));
1637 pos = LVecBase2(mp[0], mp[1]) * scale;
1638 LVecBase2 new_scale(scale, scale);
1642 LPoint3 op = quat.xform(other->
get_pos());
1643 pos += LVecBase2(op[0], op[1]) * scale;
1649 result = make_pos_rotate_scale2d(pos, rotate, new_scale);
1658 if (scale == 0.0f) {
1659 ((
TransformState *)
this)->_flags |= F_is_singular | F_singular_known;
1660 return make_invalid();
1662 scale = 1.0f / scale;
1663 quat.invert_in_place();
1664 pos = quat.xform(-pos) * scale;
1665 LVecBase3 new_scale(scale, scale, scale);
1669 pos += quat.xform(other->
get_pos()) * scale;
1674 result = make_pos_quat_scale(pos, quat, new_scale);
1678 if (paranoid_compose) {
1681 pgraph_cat.warning()
1682 <<
"Unexpected singular matrix found for " << *
this <<
"\n";
1684 nassertr(_inv_mat !=
nullptr, make_invalid());
1686 new_mat.multiply(other->
get_mat(), *_inv_mat);
1687 if (!new_mat.almost_equal(result->
get_mat(), 0.1)) {
1689 pgraph_cat.warning()
1690 <<
"Componentwise invert-composition of " << *
this <<
" and " << *other
1692 << *result <<
"\n instead of:\n" << *correct <<
"\n";
1703 return make_invalid();
1708 nassertr(_inv_mat !=
nullptr, make_invalid());
1711 const LMatrix4 &i = *_inv_mat;
1712 LMatrix3 inv3(i(0, 0), i(0, 1), i(0, 3),
1713 i(1, 0), i(1, 1), i(1, 3),
1714 i(3, 0), i(3, 1), i(3, 3));
1716 return make_mat3(inv3);
1718 return make_mat3(other->
get_mat3() * inv3);
1722 return make_mat(*_inv_mat);
1724 return make_mat(other->
get_mat() * (*_inv_mat));
1733void TransformState::
1734detect_and_break_cycles() {
1735 PStatTimer timer(_transform_break_cycles_pcollector);
1737 ++_last_cycle_detect;
1738 if (r_detect_cycles(
this,
this, 1, _last_cycle_detect,
nullptr)) {
1741 if (pgraph_cat.is_debug()) {
1743 <<
"Breaking cycle involving " << (*this) <<
"\n";
1746 remove_cache_pointers();
1748 ++_last_cycle_detect;
1749 if (r_detect_reverse_cycles(
this,
this, 1, _last_cycle_detect,
nullptr)) {
1750 if (pgraph_cat.is_debug()) {
1752 <<
"Breaking cycle involving " << (*this) <<
"\n";
1755 remove_cache_pointers();
1767bool TransformState::
1772 if (current_state->_cycle_detect == this_seq) {
1778 return (current_state == start_state && length > 2);
1783 size_t cache_size = current_state->_composition_cache.
get_num_entries();
1784 for (i = 0; i < cache_size; ++i) {
1786 if (result !=
nullptr) {
1787 if (r_detect_cycles(start_state, result, length + 1,
1788 this_seq, cycle_desc)) {
1790 if (cycle_desc !=
nullptr) {
1792 CompositionCycleDescEntry entry(other, result,
false);
1793 cycle_desc->push_back(entry);
1800 cache_size = current_state->_invert_composition_cache.
get_num_entries();
1801 for (i = 0; i < cache_size; ++i) {
1803 if (result !=
nullptr) {
1804 if (r_detect_cycles(start_state, result, length + 1,
1805 this_seq, cycle_desc)) {
1807 if (cycle_desc !=
nullptr) {
1809 CompositionCycleDescEntry entry(other, result,
true);
1810 cycle_desc->push_back(entry);
1826bool TransformState::
1831 if (current_state->_cycle_detect == this_seq) {
1837 return (current_state == start_state && length > 2);
1842 size_t cache_size = current_state->_composition_cache.
get_num_entries();
1843 for (i = 0; i < cache_size; ++i) {
1845 if (other != current_state) {
1846 int oi = other->_composition_cache.
find(current_state);
1847 nassertr(oi != -1,
false);
1850 if (result !=
nullptr) {
1851 if (r_detect_reverse_cycles(start_state, result, length + 1,
1852 this_seq, cycle_desc)) {
1854 if (cycle_desc !=
nullptr) {
1856 CompositionCycleDescEntry entry(other, result,
false);
1857 cycle_desc->push_back(entry);
1865 cache_size = current_state->_invert_composition_cache.
get_num_entries();
1866 for (i = 0; i < cache_size; ++i) {
1868 if (other != current_state) {
1869 int oi = other->_invert_composition_cache.
find(current_state);
1870 nassertr(oi != -1,
false);
1873 if (result !=
nullptr) {
1874 if (r_detect_reverse_cycles(start_state, result, length + 1,
1875 this_seq, cycle_desc)) {
1877 if (cycle_desc !=
nullptr) {
1879 CompositionCycleDescEntry entry(other, result,
false);
1880 cycle_desc->push_back(entry);
1899void TransformState::
1903 if (_saved_entry != -1) {
1905 nassertv_always(_states->
remove(
this));
1916void TransformState::
1917remove_cache_pointers() {
1936 if (_composition_cache.
is_empty() && _invert_composition_cache.
is_empty()) {
1945 while (!_composition_cache.
is_empty()) {
1957 Composition comp = _composition_cache.
get_data(i);
1966 if (other !=
this) {
1967 int oi = other->_composition_cache.
find(
this);
1973 Composition ocomp = other->_composition_cache.
get_data(oi);
1982 if (ocomp._result !=
nullptr && ocomp._result != other) {
1990 if (comp._result !=
nullptr && comp._result !=
this) {
1997 while (!_invert_composition_cache.
is_empty()) {
1999 nassertv(other !=
this);
2000 Composition comp = _invert_composition_cache.
get_data(i);
2004 if (other !=
this) {
2005 int oi = other->_invert_composition_cache.
find(
this);
2007 Composition ocomp = other->_invert_composition_cache.
get_data(oi);
2011 if (ocomp._result !=
nullptr && ocomp._result != other) {
2016 if (comp._result !=
nullptr && comp._result !=
this) {
2025void TransformState::
2027 PStatTimer timer(_transform_hash_pcollector);
2030 static const int significant_flags =
2031 (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_is_2d);
2033 int flags = (_flags & significant_flags);
2036 if ((_flags & (F_is_invalid | F_is_identity)) == 0) {
2040 if ((_flags & F_components_given) != 0) {
2042 _hash = _pos.add_hash(_hash);
2043 if ((_flags & F_hpr_given) != 0) {
2044 _hash = _hpr.add_hash(_hash);
2046 }
else if ((_flags & F_quat_given) != 0) {
2047 _hash = _quat.add_hash(_hash);
2050 _hash = _scale.add_hash(_hash);
2051 _hash = _shear.add_hash(_hash);
2055 if (_uniquify_matrix) {
2057 if ((_flags & F_mat_known) == 0) {
2061 _hash = _mat.add_hash(_hash);
2073 _flags |= F_hash_known;
2080void TransformState::
2083 if ((_flags & F_singular_known) != 0) {
2088 PStatTimer timer(_transform_calc_pcollector);
2090 nassertv((_flags & F_is_invalid) == 0);
2098 nassertv(_inv_mat ==
nullptr);
2099 _inv_mat =
new LMatrix4;
2101 if ((_flags & F_mat_known) == 0) {
2104 bool inverted = _inv_mat->invert_from(_mat);
2107 _flags |= F_is_singular;
2111 _flags |= F_singular_known;
2118void TransformState::
2119do_calc_components() {
2120 if ((_flags & F_components_known) != 0) {
2125 PStatTimer timer(_transform_calc_pcollector);
2127 nassertv((_flags & F_is_invalid) == 0);
2128 if ((_flags & F_is_identity) != 0) {
2129 _scale.set(1.0f, 1.0f, 1.0f);
2130 _shear.set(0.0f, 0.0f, 0.0f);
2131 _hpr.set(0.0f, 0.0f, 0.0f);
2132 _quat = LQuaternion::ident_quat();
2133 _pos.set(0.0f, 0.0f, 0.0f);
2134 _flags |= F_has_components | F_components_known | F_hpr_known | F_quat_known | F_uniform_scale | F_identity_scale;
2139 nassertv((_flags & F_mat_known) != 0);
2141 if ((_flags & F_mat_known) == 0) {
2144 bool possible = decompose_matrix(_mat, _scale, _shear, _hpr, _pos);
2149 _flags |= F_components_known | F_hpr_known;
2153 _flags |= F_has_components | F_components_known | F_hpr_known;
2154 check_uniform_scale();
2158 _mat.get_row3(_pos, 3);
2166void TransformState::
2168 if ((_flags & F_hpr_known) != 0) {
2173 PStatTimer timer(_transform_calc_pcollector);
2175 nassertv((_flags & F_is_invalid) == 0);
2176 if ((_flags & F_components_known) == 0) {
2177 do_calc_components();
2179 if ((_flags & F_hpr_known) == 0) {
2182 nassertv((_flags & F_quat_known) != 0);
2183 _hpr = _quat.get_hpr();
2184 _flags |= F_hpr_known;
2191void TransformState::
2194 if ((_flags & F_quat_known) != 0) {
2199 PStatTimer timer(_transform_calc_pcollector);
2201 nassertv((_flags & F_is_invalid) == 0);
2202 if ((_flags & F_components_known) == 0) {
2203 do_calc_components();
2205 if ((_flags & F_quat_known) == 0) {
2208 nassertv((_flags & F_hpr_known) != 0);
2209 _quat.set_hpr(_hpr);
2210 _flags |= F_quat_known;
2217void TransformState::
2219 PStatTimer timer(_transform_calc_pcollector);
2224 _norm_quat.normalize();
2225 _flags |= F_norm_quat_known;
2232void TransformState::
2234 if ((_flags & F_mat_known) != 0) {
2239 PStatTimer timer(_transform_calc_pcollector);
2241 nassertv((_flags & F_is_invalid) == 0);
2242 if ((_flags & F_is_identity) != 0) {
2243 _mat = LMatrix4::ident_mat();
2248 nassertv((_flags & F_components_known) != 0);
2249 if ((_flags & F_hpr_known) == 0) {
2253 compose_matrix(_mat, _scale, _shear,
get_hpr(), _pos);
2255 _flags |= F_mat_known;
2263void TransformState::
2264update_pstats(
int old_referenced_bits,
int new_referenced_bits) {
2266 if ((old_referenced_bits & R_node) != 0) {
2267 _node_counter.sub_level(1);
2268 }
else if ((old_referenced_bits & R_cache) != 0) {
2269 _cache_counter.sub_level(1);
2271 if ((new_referenced_bits & R_node) != 0) {
2272 _node_counter.add_level(1);
2273 }
else if ((new_referenced_bits & R_cache) != 0) {
2274 _cache_counter.add_level(1);
2282void TransformState::
2283register_with_read_factory() {
2295 if ((_flags & F_is_identity) != 0) {
2297 int flags = F_is_identity | F_singular_known | F_is_2d;
2300 }
else if ((_flags & F_is_invalid) != 0) {
2302 int flags = F_is_invalid | F_singular_known | F_is_singular | F_components_known | F_mat_known;
2305 }
else if ((_flags & F_components_given) != 0) {
2307 int flags = F_components_given | F_components_known | F_has_components;
2308 flags |= (_flags & F_is_2d);
2309 if ((_flags & F_quat_given) != 0) {
2310 flags |= (F_quat_given | F_quat_known);
2311 }
else if ((_flags & F_hpr_given) != 0) {
2312 flags |= (F_hpr_given | F_hpr_known);
2317 _pos.write_datagram(dg);
2318 if ((_flags & F_quat_given) != 0) {
2319 _quat.write_datagram(dg);
2323 _scale.write_datagram(dg);
2324 _shear.write_datagram(dg);
2328 nassertv((_flags & F_mat_known) != 0);
2329 int flags = F_mat_known;
2330 flags |= (_flags & F_is_2d);
2332 _mat.write_datagram(dg);
2367 state->fillin(scan, manager);
2377void TransformState::
2382 if ((_flags & F_components_given) != 0) {
2384 _pos.read_datagram(scan);
2385 if ((_flags & F_quat_given) != 0) {
2386 _quat.read_datagram(scan);
2388 _hpr.read_datagram(scan);
2390 _scale.read_datagram(scan);
2391 _shear.read_datagram(scan);
2393 check_uniform_scale();
2396 if ((_flags & F_mat_known) != 0) {
2398 _mat.read_datagram(scan);
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void parse_params(const FactoryParams ¶ms, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void cache_unref_delete(RefCountType *ptr)
This global helper function will unref the given ReferenceCount object, and if the reference count re...
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
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...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
This is used to track the utilization of the TransformState and RenderState caches,...
void inc_adds(bool is_new)
Increments by 1 the count of elements added to the cache.
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 add_num_states(int count)
Adds the indicated count (positive or negative) to the total count of individual RenderState or Trans...
void maybe_report(const char *name)
Outputs a report if enough time has elapsed.
void inc_dels()
Increments by 1 the count of elements removed from the cache.
void init()
Initializes the CacheStats for the first time.
void inc_hits()
Increments by 1 the count of cache hits.
void inc_misses()
Increments by 1 the count of cache misses.
get_cache_ref_count
Returns the current reference count.
This is a convenience class to specialize ConfigVariable as a boolean type.
A class to retrieve the individual data elements previously stored in a Datagram.
uint32_t get_uint32()
Extracts an unsigned 32-bit integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
void add_uint32(uint32_t value)
Adds an unsigned 32-bit integer to the datagram.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Similar to MutexHolder, but for a light mutex.
bool debug_is_locked() const
Returns true if the current thread has locked the LightReMutex, false otherwise.
Similar to MutexHolder, but for a light reentrant mutex.
A lightweight reentrant mutex.
static void update_type(ReferenceCount *ptr, TypeHandle type)
Associates the indicated type with the given pointer.
A lightweight class that represents a single element that may be timed and/or counted via stats.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
bool unref_if_one() const
Atomically decreases the reference count of this object if it is one.
get_ref_count
Returns the current reference count.
virtual bool unref() const
Explicitly decrements the reference count.
This template class implements an unordered map of keys to data, implemented as a hashtable.
Value & modify_data(size_t n)
Returns a modifiable reference to the data in the nth entry of the table.
const Key & get_key(size_t n) const
Returns the key in the nth entry of the table.
int store(const Key &key, const Value &data)
Records the indicated key/data pair in the map.
bool validate() const
Returns true if the internal table appears to be consistent, false if there are some internal errors.
void clear()
Completely empties the table.
const Value & get_data(size_t n) const
Returns the data in the nth entry of the table.
int find(const Key &key) const
Searches for the indicated key in the table.
bool remove(const Key &key)
Removes the indicated key and its associated data from the table.
bool consider_shrink_table()
Shrinks the table if the allocated storage is significantly larger than the number of elements in it.
void remove_element(size_t n)
Removes the nth entry from the table.
bool is_empty() const
Returns true if the table is empty; i.e.
size_t get_num_entries() const
Returns the number of active entries in the table.
get_main_thread
Returns a pointer to the "main" Thread object–this is the Thread that started the whole process.
get_current_thread
Returns a pointer to the currently-executing Thread object.
TypeHandle is the identifier used to differentiate C++ class types.
A base class for things which need to inherit from both TypedWritable and from ReferenceCount.
Base class for objects that can be written to and read from Bam files.
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...
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
This is a sequence number that increments monotonically.
static size_t add_hash(size_t start, const Key &key)
Adds the indicated key into a running hash.
This is our own Panda specialization on the default STL map.
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 set.
This is our own Panda specialization on the default STL vector.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.