Panda3D
 All Classes Functions Variables Enumerations
transformState.cxx
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 &params) {
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 }
 All Classes Functions Variables Enumerations