Panda3D
|
00001 // Filename: transformState.cxx 00002 // Created by: drose (25Feb02) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "transformState.h" 00016 #include "compose_matrix.h" 00017 #include "bamReader.h" 00018 #include "bamWriter.h" 00019 #include "datagramIterator.h" 00020 #include "indent.h" 00021 #include "compareTo.h" 00022 #include "pStatTimer.h" 00023 #include "config_pgraph.h" 00024 #include "lightReMutexHolder.h" 00025 #include "lightMutexHolder.h" 00026 #include "thread.h" 00027 #include "py_panda.h" 00028 00029 LightReMutex *TransformState::_states_lock = NULL; 00030 TransformState::States *TransformState::_states = NULL; 00031 CPT(TransformState) TransformState::_identity_state; 00032 CPT(TransformState) TransformState::_invalid_state; 00033 UpdateSeq TransformState::_last_cycle_detect; 00034 int TransformState::_garbage_index = 0; 00035 00036 PStatCollector TransformState::_cache_update_pcollector("*:State Cache:Update"); 00037 PStatCollector TransformState::_garbage_collect_pcollector("*:State Cache:Garbage Collect"); 00038 PStatCollector TransformState::_transform_compose_pcollector("*:State Cache:Compose Transform"); 00039 PStatCollector TransformState::_transform_invert_pcollector("*:State Cache:Invert Transform"); 00040 PStatCollector TransformState::_transform_calc_pcollector("*:State Cache:Calc Components"); 00041 PStatCollector TransformState::_transform_break_cycles_pcollector("*:State Cache:Break Cycles"); 00042 PStatCollector TransformState::_transform_new_pcollector("*:State Cache:New"); 00043 PStatCollector TransformState::_transform_validate_pcollector("*:State Cache:Validate"); 00044 PStatCollector TransformState::_transform_hash_pcollector("*:State Cache:Calc Hash"); 00045 PStatCollector TransformState::_node_counter("TransformStates:On nodes"); 00046 PStatCollector TransformState::_cache_counter("TransformStates:Cached"); 00047 00048 CacheStats TransformState::_cache_stats; 00049 00050 TypeHandle TransformState::_type_handle; 00051 00052 //////////////////////////////////////////////////////////////////// 00053 // Function: TransformState::Constructor 00054 // Access: Protected 00055 // Description: Actually, this could be a private constructor, since 00056 // no one inherits from TransformState, but gcc gives us a 00057 // spurious warning if all constructors are private. 00058 //////////////////////////////////////////////////////////////////// 00059 TransformState:: 00060 TransformState() : _lock("TransformState") { 00061 if (_states == (States *)NULL) { 00062 init_states(); 00063 } 00064 _saved_entry = -1; 00065 _flags = F_is_identity | F_singular_known | F_is_2d; 00066 _inv_mat = (LMatrix4 *)NULL; 00067 _cache_stats.add_num_states(1); 00068 } 00069 00070 //////////////////////////////////////////////////////////////////// 00071 // Function: TransformState::Copy Constructor 00072 // Access: Private 00073 // Description: TransformStates are not meant to be copied. 00074 //////////////////////////////////////////////////////////////////// 00075 TransformState:: 00076 TransformState(const TransformState &) { 00077 nassertv(false); 00078 } 00079 00080 //////////////////////////////////////////////////////////////////// 00081 // Function: TransformState::Copy Assignment Operator 00082 // Access: Private 00083 // Description: TransformStates are not meant to be copied. 00084 //////////////////////////////////////////////////////////////////// 00085 void TransformState:: 00086 operator = (const TransformState &) { 00087 nassertv(false); 00088 } 00089 00090 //////////////////////////////////////////////////////////////////// 00091 // Function: TransformState::Destructor 00092 // Access: Public, Virtual 00093 // Description: The destructor is responsible for removing the 00094 // TransformState from the global set if it is there. 00095 //////////////////////////////////////////////////////////////////// 00096 TransformState:: 00097 ~TransformState() { 00098 // We'd better not call the destructor twice on a particular object. 00099 nassertv(!is_destructing()); 00100 set_destructing(); 00101 00102 // Free the inverse matrix computation, if it has been stored. 00103 if (_inv_mat != (LMatrix4 *)NULL) { 00104 delete _inv_mat; 00105 _inv_mat = (LMatrix4 *)NULL; 00106 } 00107 00108 LightReMutexHolder holder(*_states_lock); 00109 00110 // unref() should have cleared these. 00111 nassertv(_saved_entry == -1); 00112 nassertv(_composition_cache.is_empty() && _invert_composition_cache.is_empty()); 00113 00114 // If this was true at the beginning of the destructor, but is no 00115 // longer true now, probably we've been double-deleted. 00116 nassertv(get_ref_count() == 0); 00117 _cache_stats.add_num_states(-1); 00118 } 00119 00120 //////////////////////////////////////////////////////////////////// 00121 // Function: TransformState::compare_to 00122 // Access: Published 00123 // Description: Provides an arbitrary ordering among all unique 00124 // TransformStates, so we can store the essentially 00125 // different ones in a big set and throw away the rest. 00126 // 00127 // If uniquify_matrix is true, then matrix-defined 00128 // TransformStates are also uniqified. If 00129 // uniquify_matrix is false, then only component-defined 00130 // TransformStates are uniquified, which is less 00131 // expensive. 00132 //////////////////////////////////////////////////////////////////// 00133 int TransformState:: 00134 compare_to(const TransformState &other, bool uniquify_matrix) const { 00135 static const int significant_flags = 00136 (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_quat_given | F_is_2d); 00137 00138 int flags = (_flags & significant_flags); 00139 int other_flags = (other._flags & significant_flags); 00140 if (flags != other_flags) { 00141 return flags < other_flags ? -1 : 1; 00142 } 00143 00144 if ((_flags & (F_is_invalid | F_is_identity)) != 0) { 00145 // All invalid transforms are equivalent to each other, and all 00146 // identity transforms are equivalent to each other. 00147 return 0; 00148 } 00149 00150 if ((_flags & F_components_given) != 0) { 00151 // If the transform was specified componentwise, compare them 00152 // componentwise. 00153 int c = _pos.compare_to(other._pos); 00154 if (c != 0) { 00155 return c; 00156 } 00157 00158 if ((_flags & F_hpr_given) != 0) { 00159 c = _hpr.compare_to(other._hpr); 00160 if (c != 0) { 00161 return c; 00162 } 00163 } else if ((_flags & F_quat_given) != 0) { 00164 c = _quat.compare_to(other._quat); 00165 if (c != 0) { 00166 return c; 00167 } 00168 } 00169 00170 c = _scale.compare_to(other._scale); 00171 if (c != 0) { 00172 return c; 00173 } 00174 00175 c = _shear.compare_to(other._shear); 00176 return c; 00177 } 00178 00179 // Otherwise, compare the matrices . . . 00180 if (uniquify_matrix) { 00181 // . . . but only if the user thinks that's a worthwhile 00182 // comparison. 00183 return get_mat().compare_to(other.get_mat()); 00184 00185 } else { 00186 // If not, we just compare the pointers. 00187 if (this != &other) { 00188 return (this < &other) ? -1 : 1; 00189 } 00190 return 0; 00191 } 00192 } 00193 00194 //////////////////////////////////////////////////////////////////// 00195 // Function: TransformState::make_identity 00196 // Access: Published, Static 00197 // Description: Constructs an identity transform. 00198 //////////////////////////////////////////////////////////////////// 00199 CPT(TransformState) TransformState:: 00200 make_identity() { 00201 // The identity state is asked for so often, we make it a special case 00202 // and store a pointer forever once we find it the first time. 00203 if (_identity_state == (TransformState *)NULL) { 00204 TransformState *state = new TransformState; 00205 _identity_state = return_unique(state); 00206 } 00207 00208 return _identity_state; 00209 } 00210 00211 //////////////////////////////////////////////////////////////////// 00212 // Function: TransformState::make_invalid 00213 // Access: Published, Static 00214 // Description: Constructs an invalid transform; for instance, the 00215 // result of inverting a singular matrix. 00216 //////////////////////////////////////////////////////////////////// 00217 CPT(TransformState) TransformState:: 00218 make_invalid() { 00219 if (_invalid_state == (TransformState *)NULL) { 00220 TransformState *state = new TransformState; 00221 state->_flags = F_is_invalid | F_singular_known | F_is_singular | F_components_known | F_mat_known; 00222 _invalid_state = return_unique(state); 00223 } 00224 00225 return _invalid_state; 00226 } 00227 00228 //////////////////////////////////////////////////////////////////// 00229 // Function: TransformState::make_pos_hpr_scale_shear 00230 // Access: Published, Static 00231 // Description: Makes a new TransformState with the specified 00232 // components. 00233 //////////////////////////////////////////////////////////////////// 00234 CPT(TransformState) TransformState:: 00235 make_pos_hpr_scale_shear(const LVecBase3 &pos, const LVecBase3 &hpr, 00236 const LVecBase3 &scale, const LVecBase3 &shear) { 00237 nassertr(!(pos.is_nan() || hpr.is_nan() || scale.is_nan() || shear.is_nan()) , make_invalid()); 00238 // Make a special-case check for the identity transform. 00239 if (pos == LVecBase3(0.0f, 0.0f, 0.0f) && 00240 hpr == LVecBase3(0.0f, 0.0f, 0.0f) && 00241 scale == LVecBase3(1.0f, 1.0f, 1.0f) && 00242 shear == LVecBase3(0.0f, 0.0f, 0.0f)) { 00243 return make_identity(); 00244 } 00245 00246 TransformState *state = new TransformState; 00247 state->_pos = pos; 00248 state->_hpr = hpr; 00249 state->_scale = scale; 00250 state->_shear = shear; 00251 state->_flags = F_components_given | F_hpr_given | F_components_known | F_hpr_known | F_has_components; 00252 state->check_uniform_scale(); 00253 return return_new(state); 00254 } 00255 00256 //////////////////////////////////////////////////////////////////// 00257 // Function: TransformState::make_pos_quat_scale_shear 00258 // Access: Published, Static 00259 // Description: Makes a new TransformState with the specified 00260 // components. 00261 //////////////////////////////////////////////////////////////////// 00262 CPT(TransformState) TransformState:: 00263 make_pos_quat_scale_shear(const LVecBase3 &pos, const LQuaternion &quat, 00264 const LVecBase3 &scale, const LVecBase3 &shear) { 00265 nassertr(!(pos.is_nan() || quat.is_nan() || scale.is_nan() || shear.is_nan()) , make_invalid()); 00266 // Make a special-case check for the identity transform. 00267 if (pos == LVecBase3(0.0f, 0.0f, 0.0f) && 00268 quat == LQuaternion::ident_quat() && 00269 scale == LVecBase3(1.0f, 1.0f, 1.0f) && 00270 shear == LVecBase3(0.0f, 0.0f, 0.0f)) { 00271 return make_identity(); 00272 } 00273 00274 TransformState *state = new TransformState; 00275 state->_pos = pos; 00276 state->_quat = quat; 00277 state->_scale = scale; 00278 state->_shear = shear; 00279 state->_flags = F_components_given | F_quat_given | F_components_known | F_quat_known | F_has_components; 00280 state->check_uniform_scale(); 00281 return return_new(state); 00282 } 00283 00284 //////////////////////////////////////////////////////////////////// 00285 // Function: TransformState::make_mat 00286 // Access: Published, Static 00287 // Description: Makes a new TransformState with the specified 00288 // transformation matrix. 00289 //////////////////////////////////////////////////////////////////// 00290 CPT(TransformState) TransformState:: 00291 make_mat(const LMatrix4 &mat) { 00292 nassertr(!mat.is_nan(), make_invalid()); 00293 // Make a special-case check for the identity matrix. 00294 if (mat == LMatrix4::ident_mat()) { 00295 return make_identity(); 00296 } 00297 00298 TransformState *state = new TransformState; 00299 state->_mat = mat; 00300 state->_flags = F_mat_known; 00301 return return_new(state); 00302 } 00303 00304 00305 //////////////////////////////////////////////////////////////////// 00306 // Function: TransformState::make_pos_rotate_scale_shear2d 00307 // Access: Published, Static 00308 // Description: Makes a new two-dimensional TransformState with the 00309 // specified components. 00310 //////////////////////////////////////////////////////////////////// 00311 CPT(TransformState) TransformState:: 00312 make_pos_rotate_scale_shear2d(const LVecBase2 &pos, PN_stdfloat rotate, 00313 const LVecBase2 &scale, 00314 PN_stdfloat shear) { 00315 nassertr(!(pos.is_nan() || cnan(rotate) || scale.is_nan() || cnan(shear)) , make_invalid()); 00316 // Make a special-case check for the identity transform. 00317 if (pos == LVecBase2(0.0f, 0.0f) && 00318 rotate == 0.0f && 00319 scale == LVecBase2(1.0f, 1.0f) && 00320 shear == 0.0f) { 00321 return make_identity(); 00322 } 00323 00324 TransformState *state = new TransformState; 00325 state->_pos.set(pos[0], pos[1], 0.0f); 00326 switch (get_default_coordinate_system()) { 00327 default: 00328 case CS_zup_right: 00329 state->_hpr.set(rotate, 0.0f, 0.0f); 00330 break; 00331 case CS_zup_left: 00332 state->_hpr.set(-rotate, 0.0f, 0.0f); 00333 break; 00334 case CS_yup_right: 00335 state->_hpr.set(0.0f, 0.0f, -rotate); 00336 break; 00337 case CS_yup_left: 00338 state->_hpr.set(0.0, 0.0f, rotate); 00339 break; 00340 } 00341 state->_scale.set(scale[0], scale[1], 1.0f); 00342 state->_shear.set(shear, 0.0f, 0.0f); 00343 state->_flags = F_components_given | F_hpr_given | F_components_known | F_hpr_known | F_has_components | F_is_2d; 00344 state->check_uniform_scale2d(); 00345 return return_new(state); 00346 } 00347 00348 00349 //////////////////////////////////////////////////////////////////// 00350 // Function: TransformState::make_mat3 00351 // Access: Published, Static 00352 // Description: Makes a new two-dimensional TransformState with the 00353 // specified 3x3 transformation matrix. 00354 //////////////////////////////////////////////////////////////////// 00355 CPT(TransformState) TransformState:: 00356 make_mat3(const LMatrix3 &mat) { 00357 nassertr(!mat.is_nan(), make_invalid()); 00358 // Make a special-case check for the identity matrix. 00359 if (mat == LMatrix3::ident_mat()) { 00360 return make_identity(); 00361 } 00362 00363 TransformState *state = new TransformState; 00364 state->_mat.set(mat(0, 0), mat(0, 1), 0.0f, mat(0, 2), 00365 mat(1, 0), mat(1, 1), 0.0f, mat(1, 2), 00366 0.0f, 0.0f, 1.0f, 0.0f, 00367 mat(2, 0), mat(2, 1), 0.0f, mat(2, 2)); 00368 state->_flags = F_mat_known | F_is_2d; 00369 return return_new(state); 00370 } 00371 00372 //////////////////////////////////////////////////////////////////// 00373 // Function: TransformState::set_pos 00374 // Access: Published 00375 // Description: Returns a new TransformState object that represents the 00376 // original TransformState with its pos component 00377 // replaced with the indicated value. 00378 //////////////////////////////////////////////////////////////////// 00379 CPT(TransformState) TransformState:: 00380 set_pos(const LVecBase3 &pos) const { 00381 nassertr(!pos.is_nan(), this); 00382 nassertr(!is_invalid(), this); 00383 if (is_identity() || components_given()) { 00384 // If we started with a componentwise transform, we keep it that 00385 // way. 00386 if (quat_given()) { 00387 return make_pos_quat_scale_shear(pos, get_quat(), get_scale(), get_shear()); 00388 } else { 00389 return make_pos_hpr_scale_shear(pos, get_hpr(), get_scale(), get_shear()); 00390 } 00391 00392 } else { 00393 // Otherwise, we have a matrix transform, and we keep it that way. 00394 LMatrix4 mat = get_mat(); 00395 mat.set_row(3, pos); 00396 return make_mat(mat); 00397 } 00398 } 00399 00400 //////////////////////////////////////////////////////////////////// 00401 // Function: TransformState::set_hpr 00402 // Access: Published 00403 // Description: Returns a new TransformState object that represents the 00404 // original TransformState with its rotation component 00405 // replaced with the indicated value, if possible. 00406 //////////////////////////////////////////////////////////////////// 00407 CPT(TransformState) TransformState:: 00408 set_hpr(const LVecBase3 &hpr) const { 00409 nassertr(!hpr.is_nan(), this); 00410 nassertr(!is_invalid(), this); 00411 // nassertr(has_components(), this); 00412 return make_pos_hpr_scale_shear(get_pos(), hpr, get_scale(), get_shear()); 00413 } 00414 00415 //////////////////////////////////////////////////////////////////// 00416 // Function: TransformState::set_quat 00417 // Access: Published 00418 // Description: Returns a new TransformState object that represents the 00419 // original TransformState with its rotation component 00420 // replaced with the indicated value, if possible. 00421 //////////////////////////////////////////////////////////////////// 00422 CPT(TransformState) TransformState:: 00423 set_quat(const LQuaternion &quat) const { 00424 nassertr(!quat.is_nan(), this); 00425 nassertr(!is_invalid(), this); 00426 // nassertr(has_components(), this); 00427 return make_pos_quat_scale_shear(get_pos(), quat, get_scale(), get_shear()); 00428 } 00429 00430 //////////////////////////////////////////////////////////////////// 00431 // Function: TransformState::set_scale 00432 // Access: Published 00433 // Description: Returns a new TransformState object that represents the 00434 // original TransformState with its scale component 00435 // replaced with the indicated value, if possible. 00436 //////////////////////////////////////////////////////////////////// 00437 CPT(TransformState) TransformState:: 00438 set_scale(const LVecBase3 &scale) const { 00439 nassertr(!scale.is_nan(), this); 00440 nassertr(!is_invalid(), this); 00441 00442 if (is_2d() && scale[0] == scale[1] && scale[1] == scale[2]) { 00443 // Don't inflate from 2-d to 3-d just because we got a uniform 00444 // scale. 00445 return make_pos_rotate_scale_shear2d(get_pos2d(), get_rotate2d(), 00446 LVecBase2(scale[0], scale[0]), 00447 get_shear2d()); 00448 } 00449 00450 // nassertr(has_components(), this); 00451 if (quat_given()) { 00452 return make_pos_quat_scale_shear(get_pos(), get_quat(), scale, get_shear()); 00453 } else { 00454 return make_pos_hpr_scale_shear(get_pos(), get_hpr(), scale, get_shear()); 00455 } 00456 } 00457 00458 //////////////////////////////////////////////////////////////////// 00459 // Function: TransformState::set_shear 00460 // Access: Published 00461 // Description: Returns a new TransformState object that represents the 00462 // original TransformState with its shear component 00463 // replaced with the indicated value, if possible. 00464 //////////////////////////////////////////////////////////////////// 00465 CPT(TransformState) TransformState:: 00466 set_shear(const LVecBase3 &shear) const { 00467 nassertr(!shear.is_nan(), this); 00468 nassertr(!is_invalid(), this); 00469 // nassertr(has_components(), this); 00470 if (quat_given()) { 00471 return make_pos_quat_scale_shear(get_pos(), get_quat(), get_scale(), shear); 00472 } else { 00473 return make_pos_hpr_scale_shear(get_pos(), get_hpr(), get_scale(), shear); 00474 } 00475 } 00476 00477 //////////////////////////////////////////////////////////////////// 00478 // Function: TransformState::set_pos2d 00479 // Access: Published 00480 // Description: Returns a new TransformState object that represents the 00481 // original 2-d TransformState with its pos component 00482 // replaced with the indicated value. 00483 //////////////////////////////////////////////////////////////////// 00484 CPT(TransformState) TransformState:: 00485 set_pos2d(const LVecBase2 &pos) const { 00486 nassertr(!pos.is_nan(), this); 00487 nassertr(!is_invalid(), this); 00488 if (!is_2d()) { 00489 return set_pos(LVecBase3(pos[0], pos[1], 0.0f)); 00490 } 00491 00492 if (is_identity() || components_given()) { 00493 // If we started with a componentwise transform, we keep it that 00494 // way. 00495 return make_pos_rotate_scale_shear2d(pos, get_rotate2d(), get_scale2d(), 00496 get_shear2d()); 00497 00498 } else { 00499 // Otherwise, we have a matrix transform, and we keep it that way. 00500 LMatrix3 mat = get_mat3(); 00501 mat.set_row(2, pos); 00502 return make_mat3(mat); 00503 } 00504 } 00505 00506 //////////////////////////////////////////////////////////////////// 00507 // Function: TransformState::set_rotate2d 00508 // Access: Published 00509 // Description: Returns a new TransformState object that represents the 00510 // original 2-d TransformState with its rotation component 00511 // replaced with the indicated value, if possible. 00512 //////////////////////////////////////////////////////////////////// 00513 CPT(TransformState) TransformState:: 00514 set_rotate2d(PN_stdfloat rotate) const { 00515 nassertr(!cnan(rotate), this); 00516 nassertr(!is_invalid(), this); 00517 00518 if (!is_2d()) { 00519 switch (get_default_coordinate_system()) { 00520 default: 00521 case CS_zup_right: 00522 return set_hpr(LVecBase3(rotate, 0.0f, 0.0f)); 00523 case CS_zup_left: 00524 return set_hpr(LVecBase3(-rotate, 0.0f, 0.0f)); 00525 case CS_yup_right: 00526 return set_hpr(LVecBase3(0.0f, 0.0f, -rotate)); 00527 case CS_yup_left: 00528 return set_hpr(LVecBase3(0.0f, 0.0f, rotate)); 00529 } 00530 } 00531 00532 return make_pos_rotate_scale_shear2d(get_pos2d(), rotate, get_scale2d(), 00533 get_shear2d()); 00534 } 00535 00536 //////////////////////////////////////////////////////////////////// 00537 // Function: TransformState::set_scale2d 00538 // Access: Published 00539 // Description: Returns a new TransformState object that represents the 00540 // original 2-d TransformState with its scale component 00541 // replaced with the indicated value, if possible. 00542 //////////////////////////////////////////////////////////////////// 00543 CPT(TransformState) TransformState:: 00544 set_scale2d(const LVecBase2 &scale) const { 00545 nassertr(!scale.is_nan(), this); 00546 nassertr(!is_invalid(), this); 00547 00548 if (!is_2d()) { 00549 return set_scale(LVecBase3(scale[0], scale[1], 1.0f)); 00550 } 00551 return make_pos_rotate_scale_shear2d(get_pos2d(), get_rotate2d(), 00552 scale, get_shear2d()); 00553 } 00554 00555 //////////////////////////////////////////////////////////////////// 00556 // Function: TransformState::set_shear2d 00557 // Access: Published 00558 // Description: Returns a new TransformState object that represents the 00559 // original 2-d TransformState with its shear component 00560 // replaced with the indicated value, if possible. 00561 //////////////////////////////////////////////////////////////////// 00562 CPT(TransformState) TransformState:: 00563 set_shear2d(PN_stdfloat shear) const { 00564 nassertr(!cnan(shear), this); 00565 nassertr(!is_invalid(), this); 00566 if (!is_2d()) { 00567 return set_shear(LVecBase3(shear, 0.0f, 0.0f)); 00568 } 00569 return make_pos_rotate_scale_shear2d(get_pos2d(), get_rotate2d(), 00570 get_scale2d(), shear); 00571 } 00572 00573 //////////////////////////////////////////////////////////////////// 00574 // Function: TransformState::compose 00575 // Access: Published 00576 // Description: Returns a new TransformState object that represents the 00577 // composition of this state with the other state. 00578 // 00579 // The result of this operation is cached, and will be 00580 // retained as long as both this TransformState object and 00581 // the other TransformState object continue to exist. 00582 // Should one of them destruct, the cached entry will be 00583 // removed, and its pointer will be allowed to destruct 00584 // as well. 00585 //////////////////////////////////////////////////////////////////// 00586 CPT(TransformState) TransformState:: 00587 compose(const TransformState *other) const { 00588 // We handle identity as a trivial special case. 00589 if (is_identity()) { 00590 return other; 00591 } 00592 if (other->is_identity()) { 00593 return this; 00594 } 00595 00596 // If either transform is invalid, the result is invalid. 00597 if (is_invalid()) { 00598 return this; 00599 } 00600 if (other->is_invalid()) { 00601 return other; 00602 } 00603 00604 if (!transform_cache) { 00605 return do_compose(other); 00606 } 00607 00608 // Is this composition already cached? 00609 CPT(TransformState) result; 00610 { 00611 LightReMutexHolder holder(*_states_lock); 00612 int index = _composition_cache.find(other); 00613 if (index != -1) { 00614 const Composition &comp = _composition_cache.get_data(index); 00615 result = comp._result; 00616 } 00617 if (result != (TransformState *)NULL) { 00618 _cache_stats.inc_hits(); 00619 } 00620 } 00621 00622 if (result != (TransformState *)NULL) { 00623 // Success! 00624 return result; 00625 } 00626 00627 // Not in the cache. Compute a new result. It's important that we 00628 // don't hold the lock while we do this, or we lose the benefit of 00629 // parallelization. 00630 result = do_compose(other); 00631 00632 // It's OK to cast away the constness of this pointer, because the 00633 // cache is a transparent property of the class. 00634 return ((TransformState *)this)->store_compose(other, result); 00635 } 00636 00637 //////////////////////////////////////////////////////////////////// 00638 // Function: TransformState::invert_compose 00639 // Access: Published 00640 // Description: Returns a new TransformState object that represents the 00641 // composition of this state's inverse with the other 00642 // state. 00643 // 00644 // This is similar to compose(), but is particularly 00645 // useful for computing the relative state of a node as 00646 // viewed from some other node. 00647 //////////////////////////////////////////////////////////////////// 00648 CPT(TransformState) TransformState:: 00649 invert_compose(const TransformState *other) const { 00650 // This method isn't strictly const, because it updates the cache, 00651 // but we pretend that it is because it's only a cache which is 00652 // transparent to the rest of the interface. 00653 00654 // We handle identity as a trivial special case. 00655 if (is_identity()) { 00656 return other; 00657 } 00658 // Unlike compose(), the case of other->is_identity() is not quite as 00659 // trivial for invert_compose(). 00660 00661 // If either transform is invalid, the result is invalid. 00662 if (is_invalid()) { 00663 return this; 00664 } 00665 if (other->is_invalid()) { 00666 return other; 00667 } 00668 00669 if (other == this) { 00670 // a->invert_compose(a) always produces identity. 00671 return make_identity(); 00672 } 00673 00674 if (!transform_cache) { 00675 return do_invert_compose(other); 00676 } 00677 00678 LightReMutexHolder holder(*_states_lock); 00679 00680 CPT(TransformState) result; 00681 { 00682 LightReMutexHolder holder(*_states_lock); 00683 int index = _invert_composition_cache.find(other); 00684 if (index != -1) { 00685 const Composition &comp = _invert_composition_cache.get_data(index); 00686 result = comp._result; 00687 } 00688 if (result != (TransformState *)NULL) { 00689 _cache_stats.inc_hits(); 00690 } 00691 } 00692 00693 if (result != (TransformState *)NULL) { 00694 // Success! 00695 return result; 00696 } 00697 00698 // Not in the cache. Compute a new result. It's important that we 00699 // don't hold the lock while we do this, or we lose the benefit of 00700 // parallelization. 00701 result = do_invert_compose(other); 00702 00703 // It's OK to cast away the constness of this pointer, because the 00704 // cache is a transparent property of the class. 00705 return ((TransformState *)this)->store_invert_compose(other, result); 00706 } 00707 00708 //////////////////////////////////////////////////////////////////// 00709 // Function: TransformState::unref 00710 // Access: Published, Virtual 00711 // Description: This method overrides ReferenceCount::unref() to 00712 // check whether the remaining reference count is 00713 // entirely in the cache, and if so, it checks for and 00714 // breaks a cycle in the cache involving this object. 00715 // This is designed to prevent leaks from cyclical 00716 // references within the cache. 00717 //////////////////////////////////////////////////////////////////// 00718 bool TransformState:: 00719 unref() const { 00720 if (!transform_cache || garbage_collect_states) { 00721 // If we're not using the cache at all, or if we're relying on 00722 // garbage collection, just allow the pointer to unref normally. 00723 return ReferenceCount::unref(); 00724 } 00725 00726 // Here is the normal refcounting case, with a normal cache, and 00727 // without garbage collection in effect. In this case we will pull 00728 // the object out of the cache when its reference count goes to 0. 00729 00730 // We always have to grab the lock, since we will definitely need to 00731 // be holding it if we happen to drop the reference count to 0. 00732 // Having to grab the lock at every call to unref() is a big 00733 // limiting factor on parallelization. 00734 LightReMutexHolder holder(*_states_lock); 00735 00736 if (auto_break_cycles && uniquify_transforms) { 00737 if (get_cache_ref_count() > 0 && 00738 get_ref_count() == get_cache_ref_count() + 1) { 00739 // If we are about to remove the one reference that is not in the 00740 // cache, leaving only references in the cache, then we need to 00741 // check for a cycle involving this TransformState and break it if 00742 // it exists. 00743 ((TransformState *)this)->detect_and_break_cycles(); 00744 } 00745 } 00746 00747 if (ReferenceCount::unref()) { 00748 // The reference count is still nonzero. 00749 return true; 00750 } 00751 00752 // The reference count has just reached zero. Make sure the object 00753 // is removed from the global object pool, before anyone else finds 00754 // it and tries to ref it. 00755 ((TransformState *)this)->release_new(); 00756 ((TransformState *)this)->remove_cache_pointers(); 00757 00758 return false; 00759 } 00760 00761 //////////////////////////////////////////////////////////////////// 00762 // Function: TransformState::validate_composition_cache 00763 // Access: Published 00764 // Description: Returns true if the composition cache and invert 00765 // composition cache for this particular TransformState 00766 // are self-consistent and valid, false otherwise. 00767 //////////////////////////////////////////////////////////////////// 00768 bool TransformState:: 00769 validate_composition_cache() const { 00770 LightReMutexHolder holder(*_states_lock); 00771 00772 int size = _composition_cache.get_size(); 00773 for (int i = 0; i < size; ++i) { 00774 if (!_composition_cache.has_element(i)) { 00775 continue; 00776 } 00777 const TransformState *source = _composition_cache.get_key(i); 00778 if (source != (TransformState *)NULL) { 00779 // Check that the source also has a pointer back to this one. We 00780 // always add entries to the composition cache in pairs. 00781 int ri = source->_composition_cache.find(this); 00782 if (ri == -1) { 00783 // Failure! There is no back-pointer. 00784 pgraph_cat.error() 00785 << "TransformState::composition cache is inconsistent!\n"; 00786 pgraph_cat.error(false) 00787 << *this << " compose " << *source << "\n"; 00788 pgraph_cat.error(false) 00789 << "but no reverse\n"; 00790 return false; 00791 } 00792 } 00793 } 00794 00795 size = _invert_composition_cache.get_size(); 00796 for (int i = 0; i < size; ++i) { 00797 if (!_invert_composition_cache.has_element(i)) { 00798 continue; 00799 } 00800 const TransformState *source = _invert_composition_cache.get_key(i); 00801 if (source != (TransformState *)NULL) { 00802 // Check that the source also has a pointer back to this one. We 00803 // always add entries to the composition cache in pairs. 00804 int ri = source->_invert_composition_cache.find(this); 00805 if (ri == -1) { 00806 // Failure! There is no back-pointer. 00807 pgraph_cat.error() 00808 << "TransformState::invert composition cache is inconsistent!\n"; 00809 pgraph_cat.error(false) 00810 << *this << " invert compose " << *source << "\n"; 00811 pgraph_cat.error(false) 00812 << "but no reverse\n"; 00813 return false; 00814 } 00815 } 00816 } 00817 00818 return true; 00819 } 00820 00821 #ifdef HAVE_PYTHON 00822 //////////////////////////////////////////////////////////////////// 00823 // Function: TransformState::get_composition_cache 00824 // Access: Published 00825 // Description: Returns a list of 2-tuples that represents the 00826 // composition cache. For each tuple in the list, the 00827 // first element is the source transform, and the second 00828 // is the result transform. If both are None, there is 00829 // no entry in the cache at that slot. 00830 // 00831 // In general, a->compose(source) == result. 00832 // 00833 // This has no practical value other than for examining 00834 // the cache for performance analysis. 00835 //////////////////////////////////////////////////////////////////// 00836 PyObject *TransformState:: 00837 get_composition_cache() const { 00838 IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState; 00839 LightReMutexHolder holder(*_states_lock); 00840 00841 size_t num_states = _composition_cache.get_num_entries(); 00842 PyObject *list = PyList_New(num_states); 00843 size_t i = 0; 00844 00845 int size = _composition_cache.get_size(); 00846 for (int si = 0; si < size; ++si) { 00847 if (!_composition_cache.has_element(si)) { 00848 continue; 00849 } 00850 00851 PyObject *tuple = PyTuple_New(2); 00852 PyObject *a, *b; 00853 00854 const TransformState *source = _composition_cache.get_key(si); 00855 if (source == (TransformState *)NULL) { 00856 a = Py_None; 00857 Py_INCREF(a); 00858 } else { 00859 source->ref(); 00860 a = DTool_CreatePyInstanceTyped((void *)source, Dtool_TransformState, 00861 true, true, source->get_type_index()); 00862 } 00863 const TransformState *result = _composition_cache.get_data(si)._result; 00864 if (result == (TransformState *)NULL) { 00865 b = Py_None; 00866 Py_INCREF(b); 00867 } else { 00868 result->ref(); 00869 b = DTool_CreatePyInstanceTyped((void *)result, Dtool_TransformState, 00870 true, true, result->get_type_index()); 00871 } 00872 00873 PyTuple_SET_ITEM(tuple, 0, a); 00874 PyTuple_SET_ITEM(tuple, 1, b); 00875 00876 nassertr(i < num_states, list); 00877 PyList_SET_ITEM(list, i, tuple); 00878 ++i; 00879 } 00880 nassertr(i == num_states, list); 00881 return list; 00882 } 00883 #endif // HAVE_PYTHON 00884 00885 #ifdef HAVE_PYTHON 00886 //////////////////////////////////////////////////////////////////// 00887 // Function: TransformState::get_invert_composition_cache 00888 // Access: Published 00889 // Description: Returns a list of 2-tuples that represents the 00890 // invert_composition cache. For each tuple in the list, the 00891 // first element is the source transform, and the second 00892 // is the result transform. If both are None, there is 00893 // no entry in the cache at that slot. 00894 // 00895 // In general, a->invert_compose(source) == result. 00896 // 00897 // This has no practical value other than for examining 00898 // the cache for performance analysis. 00899 //////////////////////////////////////////////////////////////////// 00900 PyObject *TransformState:: 00901 get_invert_composition_cache() const { 00902 IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState; 00903 LightReMutexHolder holder(*_states_lock); 00904 00905 size_t num_states = _invert_composition_cache.get_num_entries(); 00906 PyObject *list = PyList_New(num_states); 00907 size_t i = 0; 00908 00909 int size = _invert_composition_cache.get_size(); 00910 for (int si = 0; si < size; ++si) { 00911 if (!_invert_composition_cache.has_element(si)) { 00912 continue; 00913 } 00914 00915 PyObject *tuple = PyTuple_New(2); 00916 PyObject *a, *b; 00917 00918 const TransformState *source = _invert_composition_cache.get_key(si); 00919 if (source == (TransformState *)NULL) { 00920 a = Py_None; 00921 Py_INCREF(a); 00922 } else { 00923 source->ref(); 00924 a = DTool_CreatePyInstanceTyped((void *)source, Dtool_TransformState, 00925 true, true, source->get_type_index()); 00926 } 00927 const TransformState *result = _invert_composition_cache.get_data(si)._result; 00928 if (result == (TransformState *)NULL) { 00929 b = Py_None; 00930 Py_INCREF(b); 00931 } else { 00932 result->ref(); 00933 b = DTool_CreatePyInstanceTyped((void *)result, Dtool_TransformState, 00934 true, true, result->get_type_index()); 00935 } 00936 00937 PyTuple_SET_ITEM(tuple, 0, a); 00938 PyTuple_SET_ITEM(tuple, 1, b); 00939 00940 nassertr(i < num_states, list); 00941 PyList_SET_ITEM(list, i, tuple); 00942 ++i; 00943 } 00944 nassertr(i == num_states, list); 00945 return list; 00946 } 00947 #endif // HAVE_PYTHON 00948 00949 //////////////////////////////////////////////////////////////////// 00950 // Function: TransformState::output 00951 // Access: Published 00952 // Description: 00953 //////////////////////////////////////////////////////////////////// 00954 void TransformState:: 00955 output(ostream &out) const { 00956 out << "T:"; 00957 if (is_invalid()) { 00958 out << "(invalid)"; 00959 00960 } else if (is_identity()) { 00961 out << "(identity)"; 00962 00963 } else if (has_components()) { 00964 bool output_hpr = !get_hpr().almost_equal(LVecBase3(0.0f, 0.0f, 0.0f)); 00965 00966 if (!components_given()) { 00967 // A leading "m" indicates the transform was described as a full 00968 // matrix, and we are decomposing it for the benefit of the 00969 // user. 00970 out << "m"; 00971 00972 } else if (output_hpr && quat_given()) { 00973 // A leading "q" indicates that the pos, scale, and shear are 00974 // exactly as specified, but the rotation was described as a 00975 // quaternion, and we are decomposing that to hpr for the 00976 // benefit of the user. 00977 out << "q"; 00978 } 00979 00980 char lead = '('; 00981 if (is_2d()) { 00982 if (!get_pos2d().almost_equal(LVecBase2(0.0f, 0.0f))) { 00983 out << lead << "pos " << get_pos2d(); 00984 lead = ' '; 00985 } 00986 if (output_hpr) { 00987 out << lead << "rotate " << get_rotate2d(); 00988 lead = ' '; 00989 } 00990 if (!get_scale2d().almost_equal(LVecBase2(1.0f, 1.0f))) { 00991 if (has_uniform_scale()) { 00992 out << lead << "scale " << get_uniform_scale(); 00993 lead = ' '; 00994 } else { 00995 out << lead << "scale " << get_scale2d(); 00996 lead = ' '; 00997 } 00998 } 00999 if (has_nonzero_shear()) { 01000 out << lead << "shear " << get_shear2d(); 01001 lead = ' '; 01002 } 01003 } else { 01004 if (!get_pos().almost_equal(LVecBase3(0.0f, 0.0f, 0.0f))) { 01005 out << lead << "pos " << get_pos(); 01006 lead = ' '; 01007 } 01008 if (output_hpr) { 01009 out << lead << "hpr " << get_hpr(); 01010 lead = ' '; 01011 } 01012 if (!get_scale().almost_equal(LVecBase3(1.0f, 1.0f, 1.0f))) { 01013 if (has_uniform_scale()) { 01014 out << lead << "scale " << get_uniform_scale(); 01015 lead = ' '; 01016 } else { 01017 out << lead << "scale " << get_scale(); 01018 lead = ' '; 01019 } 01020 } 01021 if (has_nonzero_shear()) { 01022 out << lead << "shear " << get_shear(); 01023 lead = ' '; 01024 } 01025 } 01026 if (lead == '(') { 01027 out << "(almost identity)"; 01028 } else { 01029 out << ")"; 01030 } 01031 01032 } else { 01033 if (is_2d()) { 01034 out << get_mat3(); 01035 } else { 01036 out << get_mat(); 01037 } 01038 } 01039 } 01040 01041 //////////////////////////////////////////////////////////////////// 01042 // Function: TransformState::write 01043 // Access: Published 01044 // Description: 01045 //////////////////////////////////////////////////////////////////// 01046 void TransformState:: 01047 write(ostream &out, int indent_level) const { 01048 indent(out, indent_level) << *this << "\n"; 01049 } 01050 01051 //////////////////////////////////////////////////////////////////// 01052 // Function: TransformState::write_composition_cache 01053 // Access: Published 01054 // Description: Writes a brief description of the composition cache 01055 // and invert composition cache to the indicated 01056 // ostream. This is not useful except for performance 01057 // analysis, to examine the cache structure. 01058 //////////////////////////////////////////////////////////////////// 01059 void TransformState:: 01060 write_composition_cache(ostream &out, int indent_level) const { 01061 indent(out, indent_level + 2) << _composition_cache << "\n"; 01062 indent(out, indent_level + 2) << _invert_composition_cache << "\n"; 01063 } 01064 01065 //////////////////////////////////////////////////////////////////// 01066 // Function: TransformState::get_num_states 01067 // Access: Published, Static 01068 // Description: Returns the total number of unique TransformState 01069 // objects allocated in the world. This will go up and 01070 // down during normal operations. 01071 //////////////////////////////////////////////////////////////////// 01072 int TransformState:: 01073 get_num_states() { 01074 if (_states == (States *)NULL) { 01075 return 0; 01076 } 01077 LightReMutexHolder holder(*_states_lock); 01078 return _states->get_num_entries(); 01079 } 01080 01081 //////////////////////////////////////////////////////////////////// 01082 // Function: TransformState::get_num_unused_states 01083 // Access: Published, Static 01084 // Description: Returns the total number of TransformState objects that 01085 // have been allocated but have no references outside of 01086 // the internal TransformState cache. 01087 // 01088 // A nonzero return value is not necessarily indicative 01089 // of leaked references; it is normal for two 01090 // TransformState objects, both of which have references 01091 // held outside the cache, to have the result of their 01092 // composition stored within the cache. This result 01093 // will be retained within the cache until one of the 01094 // base TransformStates is released. 01095 // 01096 // Use list_cycles() to get an idea of the number of 01097 // actual "leaked" TransformState objects. 01098 //////////////////////////////////////////////////////////////////// 01099 int TransformState:: 01100 get_num_unused_states() { 01101 if (_states == (States *)NULL) { 01102 return 0; 01103 } 01104 LightReMutexHolder holder(*_states_lock); 01105 01106 // First, we need to count the number of times each TransformState 01107 // object is recorded in the cache. We could just trust 01108 // get_cache_ref_count(), but we'll be extra cautious for now. 01109 typedef pmap<const TransformState *, int> StateCount; 01110 StateCount state_count; 01111 01112 int size = _states->get_size(); 01113 for (int si = 0; si < size; ++si) { 01114 if (!_states->has_element(si)) { 01115 continue; 01116 } 01117 const TransformState *state = _states->get_key(si); 01118 01119 int i; 01120 int cache_size = state->_composition_cache.get_size(); 01121 for (i = 0; i < cache_size; ++i) { 01122 if (state->_composition_cache.has_element(i)) { 01123 const TransformState *result = state->_composition_cache.get_data(i)._result; 01124 if (result != (const TransformState *)NULL && result != state) { 01125 // Here's a TransformState that's recorded in the cache. 01126 // Count it. 01127 pair<StateCount::iterator, bool> ir = 01128 state_count.insert(StateCount::value_type(result, 1)); 01129 if (!ir.second) { 01130 // If the above insert operation fails, then it's already in 01131 // the cache; increment its value. 01132 (*(ir.first)).second++; 01133 } 01134 } 01135 } 01136 } 01137 cache_size = state->_invert_composition_cache.get_size(); 01138 for (i = 0; i < cache_size; ++i) { 01139 if (state->_invert_composition_cache.has_element(i)) { 01140 const TransformState *result = state->_invert_composition_cache.get_data(i)._result; 01141 if (result != (const TransformState *)NULL && result != state) { 01142 pair<StateCount::iterator, bool> ir = 01143 state_count.insert(StateCount::value_type(result, 1)); 01144 if (!ir.second) { 01145 (*(ir.first)).second++; 01146 } 01147 } 01148 } 01149 } 01150 } 01151 01152 // Now that we have the appearance count of each TransformState 01153 // object, we can tell which ones are unreferenced outside of the 01154 // TransformState cache, by comparing these to the reference counts. 01155 int num_unused = 0; 01156 01157 StateCount::iterator sci; 01158 for (sci = state_count.begin(); sci != state_count.end(); ++sci) { 01159 const TransformState *state = (*sci).first; 01160 int count = (*sci).second; 01161 nassertr(count == state->get_cache_ref_count(), num_unused); 01162 nassertr(count <= state->get_ref_count(), num_unused); 01163 if (count == state->get_ref_count()) { 01164 num_unused++; 01165 01166 if (pgraph_cat.is_debug()) { 01167 pgraph_cat.debug() 01168 << "Unused state: " << (void *)state << ":" 01169 << state->get_ref_count() << " =\n"; 01170 state->write(pgraph_cat.debug(false), 2); 01171 } 01172 } 01173 } 01174 01175 return num_unused; 01176 } 01177 01178 //////////////////////////////////////////////////////////////////// 01179 // Function: TransformState::clear_cache 01180 // Access: Published, Static 01181 // Description: Empties the cache of composed TransformStates. This 01182 // makes every TransformState forget what results when 01183 // it is composed with other TransformStates. 01184 // 01185 // This will eliminate any TransformState objects that 01186 // have been allocated but have no references outside of 01187 // the internal TransformState map. It will not 01188 // eliminate TransformState objects that are still in 01189 // use. 01190 // 01191 // Nowadays, this method should not be necessary, as 01192 // reference-count cycles in the composition cache 01193 // should be automatically detected and broken. 01194 // 01195 // The return value is the number of TransformStates 01196 // freed by this operation. 01197 //////////////////////////////////////////////////////////////////// 01198 int TransformState:: 01199 clear_cache() { 01200 if (_states == (States *)NULL) { 01201 return 0; 01202 } 01203 LightReMutexHolder holder(*_states_lock); 01204 01205 PStatTimer timer(_cache_update_pcollector); 01206 int orig_size = _states->get_num_entries(); 01207 01208 // First, we need to copy the entire set of states to a temporary 01209 // vector, reference-counting each object. That way we can walk 01210 // through the copy, without fear of dereferencing (and deleting) 01211 // the objects in the map as we go. 01212 { 01213 typedef pvector< CPT(TransformState) > TempStates; 01214 TempStates temp_states; 01215 temp_states.reserve(orig_size); 01216 01217 int size = _states->get_size(); 01218 for (int si = 0; si < size; ++si) { 01219 if (!_states->has_element(si)) { 01220 continue; 01221 } 01222 const TransformState *state = _states->get_key(si); 01223 temp_states.push_back(state); 01224 } 01225 01226 // Now it's safe to walk through the list, destroying the cache 01227 // within each object as we go. Nothing will be destructed till 01228 // we're done. 01229 TempStates::iterator ti; 01230 for (ti = temp_states.begin(); ti != temp_states.end(); ++ti) { 01231 TransformState *state = (TransformState *)(*ti).p(); 01232 01233 int i; 01234 int cache_size = state->_composition_cache.get_size(); 01235 for (i = 0; i < cache_size; ++i) { 01236 if (state->_composition_cache.has_element(i)) { 01237 const TransformState *result = state->_composition_cache.get_data(i)._result; 01238 if (result != (const TransformState *)NULL && result != state) { 01239 result->cache_unref(); 01240 nassertr(result->get_ref_count() > 0, 0); 01241 } 01242 } 01243 } 01244 _cache_stats.add_total_size(-state->_composition_cache.get_num_entries()); 01245 state->_composition_cache.clear(); 01246 01247 cache_size = state->_invert_composition_cache.get_size(); 01248 for (i = 0; i < cache_size; ++i) { 01249 if (state->_invert_composition_cache.has_element(i)) { 01250 const TransformState *result = state->_invert_composition_cache.get_data(i)._result; 01251 if (result != (const TransformState *)NULL && result != state) { 01252 result->cache_unref(); 01253 nassertr(result->get_ref_count() > 0, 0); 01254 } 01255 } 01256 } 01257 _cache_stats.add_total_size(-state->_invert_composition_cache.get_num_entries()); 01258 state->_invert_composition_cache.clear(); 01259 } 01260 01261 // Once this block closes and the temp_states object goes away, 01262 // all the destruction will begin. Anything whose reference was 01263 // held only within the various objects' caches will go away. 01264 } 01265 01266 int new_size = _states->get_num_entries(); 01267 return orig_size - new_size; 01268 } 01269 01270 //////////////////////////////////////////////////////////////////// 01271 // Function: TransformState::garbage_collect 01272 // Access: Published, Static 01273 // Description: Performs a garbage-collection cycle. This must be 01274 // called periodically if garbage-collect-states is true 01275 // to ensure that TransformStates get cleaned up 01276 // appropriately. It does no harm to call it even if 01277 // this variable is not true, but there is probably no 01278 // advantage in that case. 01279 //////////////////////////////////////////////////////////////////// 01280 int TransformState:: 01281 garbage_collect() { 01282 if (_states == (States *)NULL || !garbage_collect_states) { 01283 return 0; 01284 } 01285 LightReMutexHolder holder(*_states_lock); 01286 01287 PStatTimer timer(_garbage_collect_pcollector); 01288 int orig_size = _states->get_num_entries(); 01289 01290 // How many elements to process this pass? 01291 int size = _states->get_size(); 01292 int num_this_pass = int(size * garbage_collect_states_rate); 01293 if (num_this_pass <= 0) { 01294 return 0; 01295 } 01296 num_this_pass = min(num_this_pass, size); 01297 int stop_at_element = (_garbage_index + num_this_pass) % size; 01298 01299 int num_elements = 0; 01300 int si = _garbage_index; 01301 do { 01302 if (_states->has_element(si)) { 01303 ++num_elements; 01304 TransformState *state = (TransformState *)_states->get_key(si); 01305 if (auto_break_cycles && uniquify_transforms) { 01306 if (state->get_cache_ref_count() > 0 && 01307 state->get_ref_count() == state->get_cache_ref_count()) { 01308 // If we have removed all the references to this state not in 01309 // the cache, leaving only references in the cache, then we 01310 // need to check for a cycle involving this TransformState and 01311 // break it if it exists. 01312 state->detect_and_break_cycles(); 01313 } 01314 } 01315 01316 if (state->get_ref_count() == 1) { 01317 // This state has recently been unreffed to 1 (the one we 01318 // added when we stored it in the cache). Now it's time to 01319 // delete it. This is safe, because we're holding the 01320 // _states_lock, so it's not possible for some other thread to 01321 // find the state in the cache and ref it while we're doing 01322 // this. 01323 state->release_new(); 01324 state->remove_cache_pointers(); 01325 state->cache_unref(); 01326 delete state; 01327 } 01328 } 01329 01330 si = (si + 1) % size; 01331 } while (si != stop_at_element); 01332 _garbage_index = si; 01333 nassertr(_states->validate(), 0); 01334 01335 int new_size = _states->get_num_entries(); 01336 return orig_size - new_size; 01337 } 01338 01339 //////////////////////////////////////////////////////////////////// 01340 // Function: TransformState::list_cycles 01341 // Access: Published, Static 01342 // Description: Detects all of the reference-count cycles in the 01343 // cache and reports them to standard output. 01344 // 01345 // These cycles may be inadvertently created when state 01346 // compositions cycle back to a starting point. 01347 // Nowadays, these cycles should be automatically 01348 // detected and broken, so this method should never list 01349 // any cycles unless there is a bug in that detection 01350 // logic. 01351 // 01352 // The cycles listed here are not leaks in the strictest 01353 // sense of the word, since they can be reclaimed by a 01354 // call to clear_cache(); but they will not be reclaimed 01355 // automatically. 01356 //////////////////////////////////////////////////////////////////// 01357 void TransformState:: 01358 list_cycles(ostream &out) { 01359 if (_states == (States *)NULL) { 01360 return; 01361 } 01362 LightReMutexHolder holder(*_states_lock); 01363 01364 typedef pset<const TransformState *> VisitedStates; 01365 VisitedStates visited; 01366 CompositionCycleDesc cycle_desc; 01367 01368 int size = _states->get_size(); 01369 for (int si = 0; si < size; ++si) { 01370 if (!_states->has_element(si)) { 01371 continue; 01372 } 01373 const TransformState *state = _states->get_key(si); 01374 01375 bool inserted = visited.insert(state).second; 01376 if (inserted) { 01377 ++_last_cycle_detect; 01378 if (r_detect_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) { 01379 // This state begins a cycle. 01380 CompositionCycleDesc::reverse_iterator csi; 01381 01382 out << "\nCycle detected of length " << cycle_desc.size() + 1 << ":\n" 01383 << "state " << (void *)state << ":" << state->get_ref_count() 01384 << " =\n"; 01385 state->write(out, 2); 01386 for (csi = cycle_desc.rbegin(); csi != cycle_desc.rend(); ++csi) { 01387 const CompositionCycleDescEntry &entry = (*csi); 01388 if (entry._inverted) { 01389 out << "invert composed with "; 01390 } else { 01391 out << "composed with "; 01392 } 01393 out << (const void *)entry._obj << ":" << entry._obj->get_ref_count() 01394 << " " << *entry._obj << "\n" 01395 << "produces " << (const void *)entry._result << ":" 01396 << entry._result->get_ref_count() << " =\n"; 01397 entry._result->write(out, 2); 01398 visited.insert(entry._result); 01399 } 01400 01401 cycle_desc.clear(); 01402 } else { 01403 ++_last_cycle_detect; 01404 if (r_detect_reverse_cycles(state, state, 1, _last_cycle_detect, &cycle_desc)) { 01405 // This state begins a cycle. 01406 CompositionCycleDesc::iterator csi; 01407 01408 out << "\nReverse cycle detected of length " << cycle_desc.size() + 1 << ":\n" 01409 << "state "; 01410 for (csi = cycle_desc.begin(); csi != cycle_desc.end(); ++csi) { 01411 const CompositionCycleDescEntry &entry = (*csi); 01412 out << (const void *)entry._result << ":" 01413 << entry._result->get_ref_count() << " =\n"; 01414 entry._result->write(out, 2); 01415 out << (const void *)entry._obj << ":" 01416 << entry._obj->get_ref_count() << " =\n"; 01417 entry._obj->write(out, 2); 01418 visited.insert(entry._result); 01419 } 01420 out << (void *)state << ":" 01421 << state->get_ref_count() << " =\n"; 01422 state->write(out, 2); 01423 01424 cycle_desc.clear(); 01425 } 01426 } 01427 } 01428 } 01429 } 01430 01431 01432 //////////////////////////////////////////////////////////////////// 01433 // Function: TransformState::list_states 01434 // Access: Published, Static 01435 // Description: Lists all of the TransformStates in the cache to the 01436 // output stream, one per line. This can be quite a lot 01437 // of output if the cache is large, so be prepared. 01438 //////////////////////////////////////////////////////////////////// 01439 void TransformState:: 01440 list_states(ostream &out) { 01441 if (_states == (States *)NULL) { 01442 out << "0 states:\n"; 01443 return; 01444 } 01445 LightReMutexHolder holder(*_states_lock); 01446 01447 out << _states->get_num_entries() << " states:\n"; 01448 01449 int size = _states->get_size(); 01450 for (int si = 0; si < size; ++si) { 01451 if (!_states->has_element(si)) { 01452 continue; 01453 } 01454 const TransformState *state = _states->get_key(si); 01455 state->write(out, 2); 01456 } 01457 } 01458 01459 //////////////////////////////////////////////////////////////////// 01460 // Function: TransformState::validate_states 01461 // Access: Published, Static 01462 // Description: Ensures that the cache is still stored in sorted 01463 // order, and that none of the cache elements have been 01464 // inadvertently deleted. Returns true if so, false if 01465 // there is a problem (which implies someone has 01466 // modified one of the supposedly-const TransformState 01467 // objects). 01468 //////////////////////////////////////////////////////////////////// 01469 bool TransformState:: 01470 validate_states() { 01471 if (_states == (States *)NULL) { 01472 return true; 01473 } 01474 01475 PStatTimer timer(_transform_validate_pcollector); 01476 01477 LightReMutexHolder holder(*_states_lock); 01478 if (_states->is_empty()) { 01479 return true; 01480 } 01481 01482 if (!_states->validate()) { 01483 pgraph_cat.error() 01484 << "TransformState::_states cache is invalid!\n"; 01485 return false; 01486 } 01487 01488 int size = _states->get_size(); 01489 int si = 0; 01490 while (si < size && !_states->has_element(si)) { 01491 ++si; 01492 } 01493 nassertr(si < size, false); 01494 nassertr(_states->get_key(si)->get_ref_count() >= 0, false); 01495 int snext = si; 01496 ++snext; 01497 while (snext < size && !_states->has_element(snext)) { 01498 ++snext; 01499 } 01500 while (snext < size) { 01501 nassertr(_states->get_key(snext)->get_ref_count() >= 0, false); 01502 const TransformState *ssi = _states->get_key(si); 01503 if (!ssi->validate_composition_cache()) { 01504 return false; 01505 } 01506 const TransformState *ssnext = _states->get_key(snext); 01507 int c = ssi->compare_to(*ssnext); 01508 int ci = ssnext->compare_to(*ssi); 01509 if ((ci < 0) != (c > 0) || 01510 (ci > 0) != (c < 0) || 01511 (ci == 0) != (c == 0)) { 01512 pgraph_cat.error() 01513 << "TransformState::compare_to() not defined properly!\n"; 01514 pgraph_cat.error(false) 01515 << "(a, b): " << c << "\n"; 01516 pgraph_cat.error(false) 01517 << "(b, a): " << ci << "\n"; 01518 ssi->write(pgraph_cat.error(false), 2); 01519 ssnext->write(pgraph_cat.error(false), 2); 01520 return false; 01521 } 01522 si = snext; 01523 ++snext; 01524 while (snext < size && !_states->has_element(snext)) { 01525 ++snext; 01526 } 01527 } 01528 01529 return true; 01530 } 01531 01532 #ifdef HAVE_PYTHON 01533 //////////////////////////////////////////////////////////////////// 01534 // Function: TransformState::get_states 01535 // Access: Published, Static 01536 // Description: Returns a list of all of the TransformState objects 01537 // in the state cache. The order of elements in this 01538 // cache is arbitrary. 01539 //////////////////////////////////////////////////////////////////// 01540 PyObject *TransformState:: 01541 get_states() { 01542 IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState; 01543 if (_states == (States *)NULL) { 01544 return PyList_New(0); 01545 } 01546 LightReMutexHolder holder(*_states_lock); 01547 01548 size_t num_states = _states->get_num_entries(); 01549 PyObject *list = PyList_New(num_states); 01550 size_t i = 0; 01551 01552 int size = _states->get_size(); 01553 for (int si = 0; si < size; ++si) { 01554 if (!_states->has_element(si)) { 01555 continue; 01556 } 01557 const TransformState *state = _states->get_key(si); 01558 state->ref(); 01559 PyObject *a = 01560 DTool_CreatePyInstanceTyped((void *)state, Dtool_TransformState, 01561 true, true, state->get_type_index()); 01562 nassertr(i < num_states, list); 01563 PyList_SET_ITEM(list, i, a); 01564 ++i; 01565 } 01566 nassertr(i == num_states, list); 01567 return list; 01568 } 01569 #endif // HAVE_PYTHON 01570 01571 #ifdef HAVE_PYTHON 01572 //////////////////////////////////////////////////////////////////// 01573 // Function: TransformState::get_unused_states 01574 // Access: Published, Static 01575 // Description: Returns a list of all of the "unused" TransformState 01576 // objects in the state cache. See 01577 // get_num_unused_states(). 01578 //////////////////////////////////////////////////////////////////// 01579 PyObject *TransformState:: 01580 get_unused_states() { 01581 IMPORT_THIS struct Dtool_PyTypedObject Dtool_TransformState; 01582 if (_states == (States *)NULL) { 01583 return PyList_New(0); 01584 } 01585 LightReMutexHolder holder(*_states_lock); 01586 01587 PyObject *list = PyList_New(0); 01588 int size = _states->get_size(); 01589 for (int si = 0; si < size; ++si) { 01590 if (!_states->has_element(si)) { 01591 continue; 01592 } 01593 const TransformState *state = _states->get_key(si); 01594 if (state->get_cache_ref_count() == state->get_ref_count()) { 01595 state->ref(); 01596 PyObject *a = 01597 DTool_CreatePyInstanceTyped((void *)state, Dtool_TransformState, 01598 true, true, state->get_type_index()); 01599 PyList_Append(list, a); 01600 Py_DECREF(a); 01601 } 01602 } 01603 return list; 01604 } 01605 #endif // HAVE_PYTHON 01606 01607 //////////////////////////////////////////////////////////////////// 01608 // Function: TransformState::init_states 01609 // Access: Public, Static 01610 // Description: Make sure the global _states map is allocated. This 01611 // only has to be done once. We could make this map 01612 // static, but then we run into problems if anyone 01613 // creates a TransformState object at static init time; 01614 // it also seems to cause problems when the Panda shared 01615 // library is unloaded at application exit time. 01616 //////////////////////////////////////////////////////////////////// 01617 void TransformState:: 01618 init_states() { 01619 _states = new States; 01620 01621 // TODO: we should have a global Panda mutex to allow us to safely 01622 // create _states_lock without a startup race condition. For the 01623 // meantime, this is OK because we guarantee that this method is 01624 // called at static init time, presumably when there is still only 01625 // one thread in the world. 01626 _states_lock = new LightReMutex("TransformState::_states_lock"); 01627 _cache_stats.init(); 01628 nassertv(Thread::get_current_thread() == Thread::get_main_thread()); 01629 } 01630 01631 //////////////////////////////////////////////////////////////////// 01632 // Function: TransformState::return_new 01633 // Access: Private, Static 01634 // Description: This function is used to share a common TransformState 01635 // pointer for all equivalent TransformState objects. 01636 // 01637 // This is different from return_unique() in that it 01638 // does not actually guarantee a unique pointer, unless 01639 // uniquify-transforms is set. 01640 //////////////////////////////////////////////////////////////////// 01641 CPT(TransformState) TransformState:: 01642 return_new(TransformState *state) { 01643 nassertr(state != (TransformState *)NULL, state); 01644 if (!uniquify_transforms && !state->is_identity()) { 01645 return state; 01646 } 01647 01648 return return_unique(state); 01649 } 01650 01651 //////////////////////////////////////////////////////////////////// 01652 // Function: TransformState::return_unique 01653 // Access: Private, Static 01654 // Description: This function is used to share a common TransformState 01655 // pointer for all equivalent TransformState objects. 01656 // 01657 // See the similar logic in RenderState. The idea is to 01658 // create a new TransformState object and pass it 01659 // through this function, which will share the pointer 01660 // with a previously-created TransformState object if it 01661 // is equivalent. 01662 //////////////////////////////////////////////////////////////////// 01663 CPT(TransformState) TransformState:: 01664 return_unique(TransformState *state) { 01665 nassertr(state != (TransformState *)NULL, state); 01666 01667 if (!transform_cache) { 01668 return state; 01669 } 01670 01671 #ifndef NDEBUG 01672 if (paranoid_const) { 01673 nassertr(validate_states(), state); 01674 } 01675 #endif 01676 01677 PStatTimer timer(_transform_new_pcollector); 01678 01679 LightReMutexHolder holder(*_states_lock); 01680 01681 if (state->_saved_entry != -1) { 01682 // This state is already in the cache. 01683 //nassertr(_states->find(state) == state->_saved_entry, state); 01684 return state; 01685 } 01686 01687 // Save the state in a local PointerTo so that it will be freed at 01688 // the end of this function if no one else uses it. 01689 CPT(TransformState) pt_state = state; 01690 01691 int si = _states->find(state); 01692 if (si != -1) { 01693 // There's an equivalent state already in the set. Return it. 01694 return _states->get_key(si); 01695 } 01696 01697 // Not already in the set; add it. 01698 if (garbage_collect_states) { 01699 // If we'll be garbage collecting states explicitly, we'll 01700 // increment the reference count when we store it in the cache, so 01701 // that it won't be deleted while it's in it. 01702 state->cache_ref(); 01703 } 01704 si = _states->store(state, Empty()); 01705 01706 // Save the index and return the input state. 01707 state->_saved_entry = si; 01708 return pt_state; 01709 } 01710 01711 //////////////////////////////////////////////////////////////////// 01712 // Function: TransformState::do_compose 01713 // Access: Private 01714 // Description: The private implemention of compose(); this actually 01715 // composes two TransformStates, without bothering with the 01716 // cache. 01717 //////////////////////////////////////////////////////////////////// 01718 CPT(TransformState) TransformState:: 01719 do_compose(const TransformState *other) const { 01720 PStatTimer timer(_transform_compose_pcollector); 01721 01722 nassertr((_flags & F_is_invalid) == 0, this); 01723 nassertr((other->_flags & F_is_invalid) == 0, other); 01724 01725 if (compose_componentwise && 01726 has_uniform_scale() && 01727 !has_nonzero_shear() && !other->has_nonzero_shear() && 01728 ((components_given() && other->has_components()) || 01729 (other->components_given() && has_components()))) { 01730 // We will do this operation componentwise if *either* transform 01731 // was given componentwise (and there is no non-uniform scale in 01732 // the way). 01733 01734 CPT(TransformState) result; 01735 if (is_2d() && other->is_2d()) { 01736 // Do a 2-d compose. 01737 LVecBase2 pos = get_pos2d(); 01738 PN_stdfloat rotate = get_rotate2d(); 01739 LQuaternion quat = get_norm_quat(); 01740 PN_stdfloat scale = get_uniform_scale(); 01741 01742 LPoint3 op = quat.xform(other->get_pos()); 01743 pos += LVecBase2(op[0], op[1]) * scale; 01744 01745 rotate += other->get_rotate2d(); 01746 LVecBase2 new_scale = other->get_scale2d() * scale; 01747 01748 result = make_pos_rotate_scale2d(pos, rotate, new_scale); 01749 01750 } else { 01751 // A normal 3-d compose. 01752 LVecBase3 pos = get_pos(); 01753 LQuaternion quat = get_norm_quat(); 01754 PN_stdfloat scale = get_uniform_scale(); 01755 01756 pos += quat.xform(other->get_pos()) * scale; 01757 quat = other->get_norm_quat() * quat; 01758 LVecBase3 new_scale = other->get_scale() * scale; 01759 01760 result = make_pos_quat_scale(pos, quat, new_scale); 01761 } 01762 01763 #ifndef NDEBUG 01764 if (paranoid_compose) { 01765 // Now verify against the matrix. 01766 LMatrix4 new_mat; 01767 new_mat.multiply(other->get_mat(), get_mat()); 01768 if (!new_mat.almost_equal(result->get_mat(), 0.1)) { 01769 CPT(TransformState) correct = make_mat(new_mat); 01770 pgraph_cat.warning() 01771 << "Componentwise composition of " << *this << " and " << *other 01772 << " produced:\n" 01773 << *result << "\n instead of:\n" << *correct << "\n"; 01774 result = correct; 01775 } 01776 } 01777 #endif // NDEBUG 01778 01779 return result; 01780 } 01781 01782 // Do the operation with matrices. 01783 if (is_2d() && other->is_2d()) { 01784 LMatrix3 new_mat = other->get_mat3() * get_mat3(); 01785 return make_mat3(new_mat); 01786 } else { 01787 LMatrix4 new_mat; 01788 new_mat.multiply(other->get_mat(), get_mat()); 01789 return make_mat(new_mat); 01790 } 01791 } 01792 01793 //////////////////////////////////////////////////////////////////// 01794 // Function: TransformState::store_compose 01795 // Access: Private 01796 // Description: Stores the result of a composition in the cache. 01797 // Returns the stored result (it may be a different 01798 // object than the one passed in, due to another thread 01799 // having computed the composition first). 01800 //////////////////////////////////////////////////////////////////// 01801 CPT(TransformState) TransformState:: 01802 store_compose(const TransformState *other, const TransformState *result) { 01803 // Identity should have already been screened. 01804 nassertr(!is_identity(), other); 01805 nassertr(!other->is_identity(), this); 01806 01807 // So should have validity. 01808 nassertr(!is_invalid(), this); 01809 nassertr(!other->is_invalid(), other); 01810 01811 LightReMutexHolder holder(*_states_lock); 01812 01813 // Is this composition already cached? 01814 int index = _composition_cache.find(other); 01815 if (index != -1) { 01816 Composition &comp = _composition_cache.modify_data(index); 01817 if (comp._result == (const TransformState *)NULL) { 01818 // Well, it wasn't cached already, but we already had an entry 01819 // (probably created for the reverse direction), so use the same 01820 // entry to store the new result. 01821 comp._result = result; 01822 01823 if (result != (const TransformState *)this) { 01824 // See the comments below about the need to up the reference 01825 // count only when the result is not the same as this. 01826 result->cache_ref(); 01827 } 01828 } 01829 // Here's the cache! 01830 _cache_stats.inc_hits(); 01831 return comp._result; 01832 } 01833 _cache_stats.inc_misses(); 01834 01835 // We need to make a new cache entry, both in this object and in the 01836 // other object. We make both records so the other TransformState 01837 // object will know to delete the entry from this object when it 01838 // destructs, and vice-versa. 01839 01840 // The cache entry in this object is the only one that indicates the 01841 // result; the other will be NULL for now. 01842 _cache_stats.add_total_size(1); 01843 _cache_stats.inc_adds(_composition_cache.get_size() == 0); 01844 01845 _composition_cache[other]._result = result; 01846 01847 if (other != this) { 01848 _cache_stats.add_total_size(1); 01849 _cache_stats.inc_adds(other->_composition_cache.get_size() == 0); 01850 ((TransformState *)other)->_composition_cache[this]._result = NULL; 01851 } 01852 01853 if (result != (TransformState *)this) { 01854 // If the result of do_compose() is something other than this, 01855 // explicitly increment the reference count. We have to be sure 01856 // to decrement it again later, when the composition entry is 01857 // removed from the cache. 01858 result->cache_ref(); 01859 01860 // (If the result was just this again, we still store the 01861 // result, but we don't increment the reference count, since 01862 // that would be a self-referential leak.) 01863 } 01864 01865 _cache_stats.maybe_report("TransformState"); 01866 01867 return result; 01868 } 01869 01870 //////////////////////////////////////////////////////////////////// 01871 // Function: TransformState::store_invert_compose 01872 // Access: Private 01873 // Description: Stores the result of a composition in the cache. 01874 // Returns the stored result (it may be a different 01875 // object than the one passed in, due to another thread 01876 // having computed the composition first). 01877 //////////////////////////////////////////////////////////////////// 01878 CPT(TransformState) TransformState:: 01879 store_invert_compose(const TransformState *other, const TransformState *result) { 01880 // Identity should have already been screened. 01881 nassertr(!is_identity(), other); 01882 01883 // So should have validity. 01884 nassertr(!is_invalid(), this); 01885 nassertr(!other->is_invalid(), other); 01886 01887 nassertr(other != this, make_identity()); 01888 01889 LightReMutexHolder holder(*_states_lock); 01890 01891 // Is this composition already cached? 01892 int index = _invert_composition_cache.find(other); 01893 if (index != -1) { 01894 Composition &comp = ((TransformState *)this)->_invert_composition_cache.modify_data(index); 01895 if (comp._result == (const TransformState *)NULL) { 01896 // Well, it wasn't cached already, but we already had an entry 01897 // (probably created for the reverse direction), so use the same 01898 // entry to store the new result. 01899 comp._result = result; 01900 01901 if (result != (const TransformState *)this) { 01902 // See the comments below about the need to up the reference 01903 // count only when the result is not the same as this. 01904 result->cache_ref(); 01905 } 01906 } 01907 // Here's the cache! 01908 _cache_stats.inc_hits(); 01909 return comp._result; 01910 } 01911 _cache_stats.inc_misses(); 01912 01913 // We need to make a new cache entry, both in this object and in the 01914 // other object. We make both records so the other TransformState 01915 // object will know to delete the entry from this object when it 01916 // destructs, and vice-versa. 01917 01918 // The cache entry in this object is the only one that indicates the 01919 // result; the other will be NULL for now. 01920 _cache_stats.add_total_size(1); 01921 _cache_stats.inc_adds(_invert_composition_cache.get_size() == 0); 01922 _invert_composition_cache[other]._result = result; 01923 01924 if (other != this) { 01925 _cache_stats.add_total_size(1); 01926 _cache_stats.inc_adds(other->_invert_composition_cache.get_size() == 0); 01927 ((TransformState *)other)->_invert_composition_cache[this]._result = NULL; 01928 } 01929 01930 if (result != (TransformState *)this) { 01931 // If the result of compose() is something other than this, 01932 // explicitly increment the reference count. We have to be sure 01933 // to decrement it again later, when the composition entry is 01934 // removed from the cache. 01935 result->cache_ref(); 01936 01937 // (If the result was just this again, we still store the 01938 // result, but we don't increment the reference count, since 01939 // that would be a self-referential leak.) 01940 } 01941 01942 return result; 01943 } 01944 01945 //////////////////////////////////////////////////////////////////// 01946 // Function: TransformState::do_invert_compose 01947 // Access: Private 01948 // Description: The private implemention of invert_compose(). 01949 //////////////////////////////////////////////////////////////////// 01950 CPT(TransformState) TransformState:: 01951 do_invert_compose(const TransformState *other) const { 01952 PStatTimer timer(_transform_invert_pcollector); 01953 01954 nassertr((_flags & F_is_invalid) == 0, this); 01955 nassertr((other->_flags & F_is_invalid) == 0, other); 01956 01957 if (compose_componentwise && 01958 has_uniform_scale() && 01959 !has_nonzero_shear() && !other->has_nonzero_shear() && 01960 ((components_given() && other->has_components()) || 01961 (other->components_given() && has_components()))) { 01962 // We will do this operation componentwise if *either* transform 01963 // was given componentwise (and there is no non-uniform scale in 01964 // the way). 01965 01966 CPT(TransformState) result; 01967 if (is_2d() && other->is_2d()) { 01968 // Do a 2-d invert compose. 01969 LVecBase2 pos = get_pos2d(); 01970 PN_stdfloat rotate = get_rotate2d(); 01971 LQuaternion quat = get_norm_quat(); 01972 PN_stdfloat scale = get_uniform_scale(); 01973 01974 // First, invert our own transform. 01975 if (scale == 0.0f) { 01976 ((TransformState *)this)->_flags |= F_is_singular | F_singular_known; 01977 return make_invalid(); 01978 } 01979 scale = 1.0f / scale; 01980 quat.invert_in_place(); 01981 rotate = -rotate; 01982 LVecBase3 mp = quat.xform(-LVecBase3(pos[0], pos[1], 0.0f)); 01983 pos = LVecBase2(mp[0], mp[1]) * scale; 01984 LVecBase2 new_scale(scale, scale); 01985 01986 // Now compose the inverted transform with the other transform. 01987 if (!other->is_identity()) { 01988 LPoint3 op = quat.xform(other->get_pos()); 01989 pos += LVecBase2(op[0], op[1]) * scale; 01990 01991 rotate += other->get_rotate2d(); 01992 new_scale = other->get_scale2d() * scale; 01993 } 01994 01995 result = make_pos_rotate_scale2d(pos, rotate, new_scale); 01996 01997 } else { 01998 // Do a normal, 3-d invert compose. 01999 LVecBase3 pos = get_pos(); 02000 LQuaternion quat = get_norm_quat(); 02001 PN_stdfloat scale = get_uniform_scale(); 02002 02003 // First, invert our own transform. 02004 if (scale == 0.0f) { 02005 ((TransformState *)this)->_flags |= F_is_singular | F_singular_known; 02006 return make_invalid(); 02007 } 02008 scale = 1.0f / scale; 02009 quat.invert_in_place(); 02010 pos = quat.xform(-pos) * scale; 02011 LVecBase3 new_scale(scale, scale, scale); 02012 02013 // Now compose the inverted transform with the other transform. 02014 if (!other->is_identity()) { 02015 pos += quat.xform(other->get_pos()) * scale; 02016 quat = other->get_norm_quat() * quat; 02017 new_scale = other->get_scale() * scale; 02018 } 02019 02020 result = make_pos_quat_scale(pos, quat, new_scale); 02021 } 02022 02023 #ifndef NDEBUG 02024 if (paranoid_compose) { 02025 // Now verify against the matrix. 02026 if (is_singular()) { 02027 pgraph_cat.warning() 02028 << "Unexpected singular matrix found for " << *this << "\n"; 02029 } else { 02030 nassertr(_inv_mat != (LMatrix4 *)NULL, make_invalid()); 02031 LMatrix4 new_mat; 02032 new_mat.multiply(other->get_mat(), *_inv_mat); 02033 if (!new_mat.almost_equal(result->get_mat(), 0.1)) { 02034 CPT(TransformState) correct = make_mat(new_mat); 02035 pgraph_cat.warning() 02036 << "Componentwise invert-composition of " << *this << " and " << *other 02037 << " produced:\n" 02038 << *result << "\n instead of:\n" << *correct << "\n"; 02039 result = correct; 02040 } 02041 } 02042 } 02043 #endif // NDEBUG 02044 02045 return result; 02046 } 02047 02048 if (is_singular()) { 02049 return make_invalid(); 02050 } 02051 02052 // Now that is_singular() has returned false, we can assume that 02053 // _inv_mat has been allocated and filled in. 02054 nassertr(_inv_mat != (LMatrix4 *)NULL, make_invalid()); 02055 02056 if (is_2d() && other->is_2d()) { 02057 const LMatrix4 &i = *_inv_mat; 02058 LMatrix3 inv3(i(0, 0), i(0, 1), i(0, 3), 02059 i(1, 0), i(1, 1), i(1, 3), 02060 i(3, 0), i(3, 1), i(3, 3)); 02061 if (other->is_identity()) { 02062 return make_mat3(inv3); 02063 } else { 02064 return make_mat3(other->get_mat3() * inv3); 02065 } 02066 } else { 02067 if (other->is_identity()) { 02068 return make_mat(*_inv_mat); 02069 } else { 02070 return make_mat(other->get_mat() * (*_inv_mat)); 02071 } 02072 } 02073 } 02074 02075 //////////////////////////////////////////////////////////////////// 02076 // Function: TransformState::detect_and_break_cycles 02077 // Access: Private 02078 // Description: Detects whether there is a cycle in the cache that 02079 // begins with this state. If any are detected, breaks 02080 // them by removing this state from the cache. 02081 //////////////////////////////////////////////////////////////////// 02082 void TransformState:: 02083 detect_and_break_cycles() { 02084 PStatTimer timer(_transform_break_cycles_pcollector); 02085 02086 ++_last_cycle_detect; 02087 if (r_detect_cycles(this, this, 1, _last_cycle_detect, NULL)) { 02088 // Ok, we have a cycle. This will be a leak unless we break the 02089 // cycle by freeing the cache on this object. 02090 if (pgraph_cat.is_debug()) { 02091 pgraph_cat.debug() 02092 << "Breaking cycle involving " << (*this) << "\n"; 02093 } 02094 02095 remove_cache_pointers(); 02096 } else { 02097 ++_last_cycle_detect; 02098 if (r_detect_reverse_cycles(this, this, 1, _last_cycle_detect, NULL)) { 02099 if (pgraph_cat.is_debug()) { 02100 pgraph_cat.debug() 02101 << "Breaking cycle involving " << (*this) << "\n"; 02102 } 02103 02104 remove_cache_pointers(); 02105 } 02106 } 02107 } 02108 02109 //////////////////////////////////////////////////////////////////// 02110 // Function: TransformState::r_detect_cycles 02111 // Access: Private, Static 02112 // Description: Detects whether there is a cycle in the cache that 02113 // begins with the indicated state. Returns true if at 02114 // least one cycle is found, false if this state is not 02115 // part of any cycles. If a cycle is found and 02116 // cycle_desc is not NULL, then cycle_desc is filled in 02117 // with the list of the steps of the cycle, in reverse 02118 // order. 02119 //////////////////////////////////////////////////////////////////// 02120 bool TransformState:: 02121 r_detect_cycles(const TransformState *start_state, 02122 const TransformState *current_state, 02123 int length, UpdateSeq this_seq, 02124 TransformState::CompositionCycleDesc *cycle_desc) { 02125 if (current_state->_cycle_detect == this_seq) { 02126 // We've already seen this state; therefore, we've found a cycle. 02127 02128 // However, we only care about cycles that return to the starting 02129 // state and involve more than two steps. If only one or two 02130 // nodes are involved, it doesn't represent a memory leak, so no 02131 // problem there. 02132 return (current_state == start_state && length > 2); 02133 } 02134 ((TransformState *)current_state)->_cycle_detect = this_seq; 02135 02136 int i; 02137 int cache_size = current_state->_composition_cache.get_size(); 02138 for (i = 0; i < cache_size; ++i) { 02139 if (current_state->_composition_cache.has_element(i)) { 02140 const TransformState *result = current_state->_composition_cache.get_data(i)._result; 02141 if (result != (const TransformState *)NULL) { 02142 if (r_detect_cycles(start_state, result, length + 1, 02143 this_seq, cycle_desc)) { 02144 // Cycle detected. 02145 if (cycle_desc != (CompositionCycleDesc *)NULL) { 02146 const TransformState *other = current_state->_composition_cache.get_key(i); 02147 CompositionCycleDescEntry entry(other, result, false); 02148 cycle_desc->push_back(entry); 02149 } 02150 return true; 02151 } 02152 } 02153 } 02154 } 02155 02156 cache_size = current_state->_invert_composition_cache.get_size(); 02157 for (i = 0; i < cache_size; ++i) { 02158 if (current_state->_invert_composition_cache.has_element(i)) { 02159 const TransformState *result = current_state->_invert_composition_cache.get_data(i)._result; 02160 if (result != (const TransformState *)NULL) { 02161 if (r_detect_cycles(start_state, result, length + 1, 02162 this_seq, cycle_desc)) { 02163 // Cycle detected. 02164 if (cycle_desc != (CompositionCycleDesc *)NULL) { 02165 const TransformState *other = current_state->_invert_composition_cache.get_key(i); 02166 CompositionCycleDescEntry entry(other, result, true); 02167 cycle_desc->push_back(entry); 02168 } 02169 return true; 02170 } 02171 } 02172 } 02173 } 02174 02175 // No cycle detected. 02176 return false; 02177 } 02178 02179 //////////////////////////////////////////////////////////////////// 02180 // Function: TransformState::r_detect_reverse_cycles 02181 // Access: Private, Static 02182 // Description: Works the same as r_detect_cycles, but checks for 02183 // cycles in the reverse direction along the cache 02184 // chain. (A cycle may appear in either direction, and 02185 // we must check both.) 02186 //////////////////////////////////////////////////////////////////// 02187 bool TransformState:: 02188 r_detect_reverse_cycles(const TransformState *start_state, 02189 const TransformState *current_state, 02190 int length, UpdateSeq this_seq, 02191 TransformState::CompositionCycleDesc *cycle_desc) { 02192 if (current_state->_cycle_detect == this_seq) { 02193 // We've already seen this state; therefore, we've found a cycle. 02194 02195 // However, we only care about cycles that return to the starting 02196 // state and involve more than two steps. If only one or two 02197 // nodes are involved, it doesn't represent a memory leak, so no 02198 // problem there. 02199 return (current_state == start_state && length > 2); 02200 } 02201 ((TransformState *)current_state)->_cycle_detect = this_seq; 02202 02203 int i; 02204 int cache_size = current_state->_composition_cache.get_size(); 02205 for (i = 0; i < cache_size; ++i) { 02206 if (current_state->_composition_cache.has_element(i)) { 02207 const TransformState *other = current_state->_composition_cache.get_key(i); 02208 if (other != current_state) { 02209 int oi = other->_composition_cache.find(current_state); 02210 nassertr(oi != -1, false); 02211 02212 const TransformState *result = other->_composition_cache.get_data(oi)._result; 02213 if (result != (const TransformState *)NULL) { 02214 if (r_detect_reverse_cycles(start_state, result, length + 1, 02215 this_seq, cycle_desc)) { 02216 // Cycle detected. 02217 if (cycle_desc != (CompositionCycleDesc *)NULL) { 02218 const TransformState *other = current_state->_composition_cache.get_key(i); 02219 CompositionCycleDescEntry entry(other, result, false); 02220 cycle_desc->push_back(entry); 02221 } 02222 return true; 02223 } 02224 } 02225 } 02226 } 02227 } 02228 02229 cache_size = current_state->_invert_composition_cache.get_size(); 02230 for (i = 0; i < cache_size; ++i) { 02231 if (current_state->_invert_composition_cache.has_element(i)) { 02232 const TransformState *other = current_state->_invert_composition_cache.get_key(i); 02233 if (other != current_state) { 02234 int oi = other->_invert_composition_cache.find(current_state); 02235 nassertr(oi != -1, false); 02236 02237 const TransformState *result = other->_invert_composition_cache.get_data(oi)._result; 02238 if (result != (const TransformState *)NULL) { 02239 if (r_detect_reverse_cycles(start_state, result, length + 1, 02240 this_seq, cycle_desc)) { 02241 // Cycle detected. 02242 if (cycle_desc != (CompositionCycleDesc *)NULL) { 02243 const TransformState *other = current_state->_invert_composition_cache.get_key(i); 02244 CompositionCycleDescEntry entry(other, result, false); 02245 cycle_desc->push_back(entry); 02246 } 02247 return true; 02248 } 02249 } 02250 } 02251 } 02252 } 02253 02254 // No cycle detected. 02255 return false; 02256 } 02257 02258 02259 //////////////////////////////////////////////////////////////////// 02260 // Function: TransformState::release_new 02261 // Access: Private 02262 // Description: This inverse of return_new, this releases this object 02263 // from the global TransformState table. 02264 // 02265 // You must already be holding _states_lock before you 02266 // call this method. 02267 //////////////////////////////////////////////////////////////////// 02268 void TransformState:: 02269 release_new() { 02270 nassertv(_states_lock->debug_is_locked()); 02271 02272 if (_saved_entry != -1) { 02273 //nassertv(_states->find(this) == _saved_entry); 02274 _saved_entry = _states->find(this); 02275 _states->remove_element(_saved_entry); 02276 _saved_entry = -1; 02277 } 02278 } 02279 02280 //////////////////////////////////////////////////////////////////// 02281 // Function: TransformState::remove_cache_pointers 02282 // Access: Private 02283 // Description: Remove all pointers within the cache from and to this 02284 // particular TransformState. The pointers to this 02285 // object may be scattered around in the various 02286 // CompositionCaches from other TransformState objects. 02287 // 02288 // You must already be holding _states_lock before you 02289 // call this method. 02290 //////////////////////////////////////////////////////////////////// 02291 void TransformState:: 02292 remove_cache_pointers() { 02293 nassertv(_states_lock->debug_is_locked()); 02294 02295 // Fortunately, since we added CompositionCache records in pairs, we 02296 // know exactly the set of TransformState objects that have us in their 02297 // cache: it's the same set of TransformState objects that we have in 02298 // our own cache. 02299 02300 // We do need to put considerable thought into this loop, because as 02301 // we clear out cache entries we'll cause other TransformState 02302 // objects to destruct, which could cause things to get pulled out 02303 // of our own _composition_cache map. We want to allow this (so 02304 // that we don't encounter any just-destructed pointers in our 02305 // cache), but we don't want to get bitten by this cascading effect. 02306 // Instead of walking through the map from beginning to end, 02307 // therefore, we just pull out the first one each time, and erase 02308 // it. 02309 02310 #ifdef DO_PSTATS 02311 if (_composition_cache.is_empty() && _invert_composition_cache.is_empty()) { 02312 return; 02313 } 02314 PStatTimer timer(_cache_update_pcollector); 02315 #endif // DO_PSTATS 02316 02317 // There are lots of ways to do this loop wrong. Be very careful if 02318 // you need to modify it for any reason. 02319 int i = 0; 02320 while (!_composition_cache.is_empty()) { 02321 // Scan for the next used slot in the table. 02322 while (!_composition_cache.has_element(i)) { 02323 ++i; 02324 } 02325 02326 // It is possible that the "other" TransformState object is 02327 // currently within its own destructor. We therefore can't use a 02328 // PT() to hold its pointer; that could end up calling its 02329 // destructor twice. Fortunately, we don't need to hold its 02330 // reference count to ensure it doesn't destruct while we process 02331 // this loop; as long as we ensure that no *other* TransformState 02332 // objects destruct, there will be no reason for that one to. 02333 TransformState *other = (TransformState *)_composition_cache.get_key(i); 02334 02335 // We hold a copy of the composition result so we can dereference 02336 // it later. 02337 Composition comp = _composition_cache.get_data(i); 02338 02339 // Now we can remove the element from our cache. We do this now, 02340 // rather than later, before any other TransformState objects have 02341 // had a chance to destruct, so we are confident that our iterator 02342 // is still valid. 02343 _composition_cache.remove_element(i); 02344 _cache_stats.add_total_size(-1); 02345 _cache_stats.inc_dels(); 02346 02347 if (other != this) { 02348 int oi = other->_composition_cache.find(this); 02349 02350 // We may or may not still be listed in the other's cache (it 02351 // might be halfway through pulling entries out, from within its 02352 // own destructor). 02353 if (oi != -1) { 02354 // Hold a copy of the other composition result, too. 02355 Composition ocomp = other->_composition_cache.get_data(oi); 02356 02357 other->_composition_cache.remove_element(oi); 02358 _cache_stats.add_total_size(-1); 02359 _cache_stats.inc_dels(); 02360 02361 // It's finally safe to let our held pointers go away. This may 02362 // have cascading effects as other TransformState objects are 02363 // destructed, but there will be no harm done if they destruct 02364 // now. 02365 if (ocomp._result != (const TransformState *)NULL && ocomp._result != other) { 02366 cache_unref_delete(ocomp._result); 02367 } 02368 } 02369 } 02370 02371 // It's finally safe to let our held pointers go away. (See 02372 // comment above.) 02373 if (comp._result != (const TransformState *)NULL && comp._result != this) { 02374 cache_unref_delete(comp._result); 02375 } 02376 } 02377 02378 // A similar bit of code for the invert cache. 02379 i = 0; 02380 while (!_invert_composition_cache.is_empty()) { 02381 while (!_invert_composition_cache.has_element(i)) { 02382 ++i; 02383 } 02384 02385 TransformState *other = (TransformState *)_invert_composition_cache.get_key(i); 02386 nassertv(other != this); 02387 Composition comp = _invert_composition_cache.get_data(i); 02388 _invert_composition_cache.remove_element(i); 02389 _cache_stats.add_total_size(-1); 02390 _cache_stats.inc_dels(); 02391 if (other != this) { 02392 int oi = other->_invert_composition_cache.find(this); 02393 if (oi != -1) { 02394 Composition ocomp = other->_invert_composition_cache.get_data(oi); 02395 other->_invert_composition_cache.remove_element(oi); 02396 _cache_stats.add_total_size(-1); 02397 _cache_stats.inc_dels(); 02398 if (ocomp._result != (const TransformState *)NULL && ocomp._result != other) { 02399 cache_unref_delete(ocomp._result); 02400 } 02401 } 02402 } 02403 if (comp._result != (const TransformState *)NULL && comp._result != this) { 02404 cache_unref_delete(comp._result); 02405 } 02406 } 02407 } 02408 02409 //////////////////////////////////////////////////////////////////// 02410 // Function: TransformState::do_calc_hash 02411 // Access: Private 02412 // Description: Computes a suitable hash value for phash_map. 02413 //////////////////////////////////////////////////////////////////// 02414 void TransformState:: 02415 do_calc_hash() { 02416 PStatTimer timer(_transform_hash_pcollector); 02417 _hash = 0; 02418 02419 static const int significant_flags = 02420 (F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_is_2d); 02421 02422 int flags = (_flags & significant_flags); 02423 _hash = int_hash::add_hash(_hash, flags); 02424 02425 if ((_flags & (F_is_invalid | F_is_identity)) == 0) { 02426 // Only bother to put the rest of the stuff in the hash if the 02427 // transform is not invalid or empty. 02428 02429 if ((_flags & F_components_given) != 0) { 02430 // If the transform was specified componentwise, hash it 02431 // componentwise. 02432 _hash = _pos.add_hash(_hash); 02433 if ((_flags & F_hpr_given) != 0) { 02434 _hash = _hpr.add_hash(_hash); 02435 02436 } else if ((_flags & F_quat_given) != 0) { 02437 _hash = _quat.add_hash(_hash); 02438 } 02439 02440 _hash = _scale.add_hash(_hash); 02441 _hash = _shear.add_hash(_hash); 02442 02443 } else { 02444 // Otherwise, hash the matrix . . . 02445 if (uniquify_matrix) { 02446 // . . . but only if the user thinks that's worthwhile. 02447 if ((_flags & F_mat_known) == 0) { 02448 // Calculate the matrix without doubly-locking. 02449 do_calc_mat(); 02450 } 02451 _hash = _mat.add_hash(_hash); 02452 02453 } else { 02454 // Otherwise, hash the pointer only--any two different 02455 // matrix-based TransformStates are considered to be different, 02456 // even if their matrices have the same values. 02457 02458 _hash = pointer_hash::add_hash(_hash, this); 02459 } 02460 } 02461 } 02462 02463 _flags |= F_hash_known; 02464 } 02465 02466 //////////////////////////////////////////////////////////////////// 02467 // Function: TransformState::calc_singular 02468 // Access: Private 02469 // Description: Determines whether the transform is singular (i.e. it 02470 // scales to zero, and has no inverse). 02471 //////////////////////////////////////////////////////////////////// 02472 void TransformState:: 02473 calc_singular() { 02474 LightMutexHolder holder(_lock); 02475 if ((_flags & F_singular_known) != 0) { 02476 // Someone else computed it first. 02477 return; 02478 } 02479 02480 PStatTimer timer(_transform_calc_pcollector); 02481 02482 nassertv((_flags & F_is_invalid) == 0); 02483 02484 // We determine if a matrix is singular by attempting to invert it 02485 // (and we save the result of this invert operation for a subsequent 02486 // do_invert_compose() call, which is almost certain to be made if 02487 // someone is asking whether we're singular). 02488 02489 // This should be NULL if no one has called calc_singular() yet. 02490 nassertv(_inv_mat == (LMatrix4 *)NULL); 02491 _inv_mat = new LMatrix4; 02492 02493 if ((_flags & F_mat_known) == 0) { 02494 do_calc_mat(); 02495 } 02496 bool inverted = _inv_mat->invert_from(_mat); 02497 02498 if (!inverted) { 02499 _flags |= F_is_singular; 02500 delete _inv_mat; 02501 _inv_mat = (LMatrix4 *)NULL; 02502 } 02503 _flags |= F_singular_known; 02504 } 02505 02506 //////////////////////////////////////////////////////////////////// 02507 // Function: TransformState::do_calc_components 02508 // Access: Private 02509 // Description: This is the implementation of calc_components(); it 02510 // assumes the lock is already held. 02511 //////////////////////////////////////////////////////////////////// 02512 void TransformState:: 02513 do_calc_components() { 02514 if ((_flags & F_components_known) != 0) { 02515 // Someone else computed it first. 02516 return; 02517 } 02518 02519 PStatTimer timer(_transform_calc_pcollector); 02520 02521 nassertv((_flags & F_is_invalid) == 0); 02522 if ((_flags & F_is_identity) != 0) { 02523 _scale.set(1.0f, 1.0f, 1.0f); 02524 _shear.set(0.0f, 0.0f, 0.0f); 02525 _hpr.set(0.0f, 0.0f, 0.0f); 02526 _quat = LQuaternion::ident_quat(); 02527 _pos.set(0.0f, 0.0f, 0.0f); 02528 _flags |= F_has_components | F_components_known | F_hpr_known | F_quat_known | F_uniform_scale; 02529 02530 } else { 02531 // If we don't have components and we're not identity, the only 02532 // other explanation is that we were constructed via a matrix. 02533 nassertv((_flags & F_mat_known) != 0); 02534 02535 if ((_flags & F_mat_known) == 0) { 02536 do_calc_mat(); 02537 } 02538 bool possible = decompose_matrix(_mat, _scale, _shear, _hpr, _pos); 02539 if (!possible) { 02540 // Some matrices can't be decomposed into scale, hpr, pos. In 02541 // this case, we now know that we cannot compute the components; 02542 // but the closest approximations are stored, at least. 02543 _flags |= F_components_known | F_hpr_known; 02544 02545 } else { 02546 // Otherwise, we do have the components, or at least the hpr. 02547 _flags |= F_has_components | F_components_known | F_hpr_known; 02548 check_uniform_scale(); 02549 } 02550 02551 // However, we can always get at least the pos. 02552 _mat.get_row3(_pos, 3); 02553 } 02554 } 02555 02556 //////////////////////////////////////////////////////////////////// 02557 // Function: TransformState::do_calc_hpr 02558 // Access: Private 02559 // Description: This is the implementation of calc_hpr(); it 02560 // assumes the lock is already held. 02561 //////////////////////////////////////////////////////////////////// 02562 void TransformState:: 02563 do_calc_hpr() { 02564 if ((_flags & F_hpr_known) != 0) { 02565 // Someone else computed it first. 02566 return; 02567 } 02568 02569 PStatTimer timer(_transform_calc_pcollector); 02570 02571 nassertv((_flags & F_is_invalid) == 0); 02572 if ((_flags & F_components_known) == 0) { 02573 do_calc_components(); 02574 } 02575 if ((_flags & F_hpr_known) == 0) { 02576 // If we don't know the hpr yet, we must have been given a quat. 02577 // Decompose it. 02578 nassertv((_flags & F_quat_known) != 0); 02579 _hpr = _quat.get_hpr(); 02580 _flags |= F_hpr_known; 02581 } 02582 } 02583 02584 //////////////////////////////////////////////////////////////////// 02585 // Function: TransformState::calc_quat 02586 // Access: Private 02587 // Description: Derives the quat from the hpr. 02588 //////////////////////////////////////////////////////////////////// 02589 void TransformState:: 02590 calc_quat() { 02591 LightMutexHolder holder(_lock); 02592 if ((_flags & F_quat_known) != 0) { 02593 // Someone else computed it first. 02594 return; 02595 } 02596 02597 PStatTimer timer(_transform_calc_pcollector); 02598 02599 nassertv((_flags & F_is_invalid) == 0); 02600 if ((_flags & F_components_known) == 0) { 02601 do_calc_components(); 02602 } 02603 if ((_flags & F_quat_known) == 0) { 02604 // If we don't know the quat yet, we must have been given a hpr. 02605 // Decompose it. 02606 nassertv((_flags & F_hpr_known) != 0); 02607 _quat.set_hpr(_hpr); 02608 _flags |= F_quat_known; 02609 } 02610 } 02611 02612 //////////////////////////////////////////////////////////////////// 02613 // Function: TransformState::calc_norm_quat 02614 // Access: Private 02615 // Description: Derives the normalized quat from the quat. 02616 //////////////////////////////////////////////////////////////////// 02617 void TransformState:: 02618 calc_norm_quat() { 02619 PStatTimer timer(_transform_calc_pcollector); 02620 02621 LQuaternion quat = get_quat(); 02622 LightMutexHolder holder(_lock); 02623 _norm_quat = quat; 02624 _norm_quat.normalize(); 02625 _flags |= F_norm_quat_known; 02626 } 02627 02628 //////////////////////////////////////////////////////////////////// 02629 // Function: TransformState::do_calc_mat 02630 // Access: Private 02631 // Description: This is the implementation of calc_mat(); it 02632 // assumes the lock is already held. 02633 //////////////////////////////////////////////////////////////////// 02634 void TransformState:: 02635 do_calc_mat() { 02636 if ((_flags & F_mat_known) != 0) { 02637 // Someone else computed it first. 02638 return; 02639 } 02640 02641 PStatTimer timer(_transform_calc_pcollector); 02642 02643 nassertv((_flags & F_is_invalid) == 0); 02644 if ((_flags & F_is_identity) != 0) { 02645 _mat = LMatrix4::ident_mat(); 02646 02647 } else { 02648 // If we don't have a matrix and we're not identity, the only 02649 // other explanation is that we were constructed via components. 02650 nassertv((_flags & F_components_known) != 0); 02651 if ((_flags & F_hpr_known) == 0) { 02652 do_calc_hpr(); 02653 } 02654 02655 compose_matrix(_mat, _scale, _shear, get_hpr(), _pos); 02656 } 02657 _flags |= F_mat_known; 02658 } 02659 02660 //////////////////////////////////////////////////////////////////// 02661 // Function: TransformState::update_pstats 02662 // Access: Private 02663 // Description: Moves the TransformState object from one PStats category 02664 // to another, so that we can track in PStats how many 02665 // pointers are held by nodes, and how many are held in 02666 // the cache only. 02667 //////////////////////////////////////////////////////////////////// 02668 void TransformState:: 02669 update_pstats(int old_referenced_bits, int new_referenced_bits) { 02670 #ifdef DO_PSTATS 02671 if ((old_referenced_bits & R_node) != 0) { 02672 _node_counter.sub_level(1); 02673 } else if ((old_referenced_bits & R_cache) != 0) { 02674 _cache_counter.sub_level(1); 02675 } 02676 if ((new_referenced_bits & R_node) != 0) { 02677 _node_counter.add_level(1); 02678 } else if ((new_referenced_bits & R_cache) != 0) { 02679 _cache_counter.add_level(1); 02680 } 02681 #endif // DO_PSTATS 02682 } 02683 02684 //////////////////////////////////////////////////////////////////// 02685 // Function: TransformState::register_with_read_factory 02686 // Access: Public, Static 02687 // Description: Tells the BamReader how to create objects of type 02688 // TransformState. 02689 //////////////////////////////////////////////////////////////////// 02690 void TransformState:: 02691 register_with_read_factory() { 02692 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 02693 } 02694 02695 //////////////////////////////////////////////////////////////////// 02696 // Function: TransformState::write_datagram 02697 // Access: Public, Virtual 02698 // Description: Writes the contents of this object to the datagram 02699 // for shipping out to a Bam file. 02700 //////////////////////////////////////////////////////////////////// 02701 void TransformState:: 02702 write_datagram(BamWriter *manager, Datagram &dg) { 02703 TypedWritable::write_datagram(manager, dg); 02704 02705 if ((_flags & F_is_identity) != 0) { 02706 // Identity, nothing much to that. 02707 int flags = F_is_identity | F_singular_known | F_is_2d; 02708 dg.add_uint32(flags); 02709 02710 } else if ((_flags & F_is_invalid) != 0) { 02711 // Invalid, nothing much to that either. 02712 int flags = F_is_invalid | F_singular_known | F_is_singular | F_components_known | F_mat_known; 02713 dg.add_uint32(flags); 02714 02715 } else if ((_flags & F_components_given) != 0) { 02716 // A component-based transform. 02717 int flags = F_components_given | F_components_known | F_has_components; 02718 flags |= (_flags & F_is_2d); 02719 if ((_flags & F_quat_given) != 0) { 02720 flags |= (F_quat_given | F_quat_known); 02721 } else if ((_flags & F_hpr_given) != 0) { 02722 flags |= (F_hpr_given | F_hpr_known); 02723 } 02724 02725 dg.add_uint32(flags); 02726 02727 _pos.write_datagram(dg); 02728 if ((_flags & F_quat_given) != 0) { 02729 _quat.write_datagram(dg); 02730 } else { 02731 get_hpr().write_datagram(dg); 02732 } 02733 _scale.write_datagram(dg); 02734 _shear.write_datagram(dg); 02735 02736 } else { 02737 // A general matrix. 02738 nassertv((_flags & F_mat_known) != 0); 02739 int flags = F_mat_known; 02740 flags |= (_flags & F_is_2d); 02741 dg.add_uint32(flags); 02742 _mat.write_datagram(dg); 02743 } 02744 } 02745 02746 //////////////////////////////////////////////////////////////////// 02747 // Function: TransformState::change_this 02748 // Access: Public, Static 02749 // Description: Called immediately after complete_pointers(), this 02750 // gives the object a chance to adjust its own pointer 02751 // if desired. Most objects don't change pointers after 02752 // completion, but some need to. 02753 // 02754 // Once this function has been called, the old pointer 02755 // will no longer be accessed. 02756 //////////////////////////////////////////////////////////////////// 02757 PT(TypedWritableReferenceCount) TransformState:: 02758 change_this(TypedWritableReferenceCount *old_ptr, BamReader *manager) { 02759 // First, uniquify the pointer. 02760 TransformState *state = DCAST(TransformState, old_ptr); 02761 CPT(TransformState) pointer = return_unique(state); 02762 02763 // We have to cast the pointer back to non-const, because the bam 02764 // reader expects that. 02765 return (TransformState *)pointer.p(); 02766 } 02767 02768 //////////////////////////////////////////////////////////////////// 02769 // Function: TransformState::make_from_bam 02770 // Access: Protected, Static 02771 // Description: This function is called by the BamReader's factory 02772 // when a new object of type TransformState is encountered 02773 // in the Bam file. It should create the TransformState 02774 // and extract its information from the file. 02775 //////////////////////////////////////////////////////////////////// 02776 TypedWritable *TransformState:: 02777 make_from_bam(const FactoryParams ¶ms) { 02778 TransformState *state = new TransformState; 02779 DatagramIterator scan; 02780 BamReader *manager; 02781 02782 parse_params(params, scan, manager); 02783 state->fillin(scan, manager); 02784 manager->register_change_this(change_this, state); 02785 02786 return state; 02787 } 02788 02789 //////////////////////////////////////////////////////////////////// 02790 // Function: TransformState::fillin 02791 // Access: Protected 02792 // Description: This internal function is called by make_from_bam to 02793 // read in all of the relevant data from the BamFile for 02794 // the new TransformState. 02795 //////////////////////////////////////////////////////////////////// 02796 void TransformState:: 02797 fillin(DatagramIterator &scan, BamReader *manager) { 02798 TypedWritable::fillin(scan, manager); 02799 _flags = scan.get_uint32(); 02800 02801 if ((_flags & F_components_given) != 0) { 02802 // Componentwise transform. 02803 _pos.read_datagram(scan); 02804 if ((_flags & F_quat_given) != 0) { 02805 _quat.read_datagram(scan); 02806 } else { 02807 _hpr.read_datagram(scan); 02808 } 02809 _scale.read_datagram(scan); 02810 _shear.read_datagram(scan); 02811 02812 check_uniform_scale(); 02813 } 02814 02815 if ((_flags & F_mat_known) != 0) { 02816 // General matrix. 02817 _mat.read_datagram(scan); 02818 } 02819 }