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);
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.