Panda3D
|
00001 // Filename: transformState.h 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 #ifndef TRANSFORMSTATE_H 00016 #define TRANSFORMSTATE_H 00017 00018 #include "pandabase.h" 00019 00020 #include "nodeCachedReferenceCount.h" 00021 #include "pointerTo.h" 00022 #include "luse.h" 00023 #include "pset.h" 00024 #include "event.h" 00025 #include "updateSeq.h" 00026 #include "pStatCollector.h" 00027 #include "geomEnums.h" 00028 #include "lightReMutex.h" 00029 #include "lightReMutexHolder.h" 00030 #include "lightMutex.h" 00031 #include "lightMutexHolder.h" 00032 #include "config_pgraph.h" 00033 #include "deletedChain.h" 00034 #include "simpleHashMap.h" 00035 #include "cacheStats.h" 00036 00037 class GraphicsStateGuardianBase; 00038 class FactoryParams; 00039 00040 //////////////////////////////////////////////////////////////////// 00041 // Class : TransformState 00042 // Description : Indicates a coordinate-system transform on vertices. 00043 // TransformStates are the primary means for storing 00044 // transformations on the scene graph. 00045 // 00046 // Transforms may be specified in one of two ways: 00047 // componentwise, with a pos-hpr-scale, or with an 00048 // arbitrary transform matrix. If you specify a 00049 // transform componentwise, it will remember its 00050 // original components. 00051 // 00052 // TransformState objects are managed very much like 00053 // RenderState objects. They are immutable and 00054 // reference-counted automatically. 00055 // 00056 // You should not attempt to create or modify a 00057 // TransformState object directly. Instead, call one of 00058 // the make() functions to create one for you. And 00059 // instead of modifying a TransformState object, create a 00060 // new one. 00061 //////////////////////////////////////////////////////////////////// 00062 class EXPCL_PANDA_PGRAPH TransformState : public NodeCachedReferenceCount { 00063 protected: 00064 TransformState(); 00065 00066 private: 00067 TransformState(const TransformState ©); 00068 void operator = (const TransformState ©); 00069 00070 public: 00071 virtual ~TransformState(); 00072 ALLOC_DELETED_CHAIN(TransformState); 00073 00074 PUBLISHED: 00075 INLINE bool operator < (const TransformState &other) const; 00076 bool sorts_less(const TransformState &other, bool uniquify_matrix) const; 00077 INLINE size_t get_hash() const; 00078 00079 static CPT(TransformState) make_identity(); 00080 static CPT(TransformState) make_invalid(); 00081 INLINE static CPT(TransformState) make_pos(const LVecBase3f &pos); 00082 INLINE static CPT(TransformState) make_hpr(const LVecBase3f &hpr); 00083 INLINE static CPT(TransformState) make_quat(const LQuaternionf &quat); 00084 INLINE static CPT(TransformState) make_pos_hpr(const LVecBase3f &pos, 00085 const LVecBase3f &hpr); 00086 INLINE static CPT(TransformState) make_scale(float scale); 00087 INLINE static CPT(TransformState) make_scale(const LVecBase3f &scale); 00088 INLINE static CPT(TransformState) make_shear(const LVecBase3f &shear); 00089 INLINE static CPT(TransformState) make_pos_hpr_scale(const LVecBase3f &pos, 00090 const LVecBase3f &hpr, 00091 const LVecBase3f &scale); 00092 INLINE static CPT(TransformState) make_pos_quat_scale(const LVecBase3f &pos, 00093 const LQuaternionf &quat, 00094 const LVecBase3f &scale); 00095 static CPT(TransformState) make_pos_hpr_scale_shear(const LVecBase3f &pos, 00096 const LVecBase3f &hpr, 00097 const LVecBase3f &scale, 00098 const LVecBase3f &shear); 00099 static CPT(TransformState) make_pos_quat_scale_shear(const LVecBase3f &pos, 00100 const LQuaternionf &quat, 00101 const LVecBase3f &scale, 00102 const LVecBase3f &shear); 00103 static CPT(TransformState) make_mat(const LMatrix4f &mat); 00104 00105 00106 INLINE static CPT(TransformState) make_pos2d(const LVecBase2f &pos); 00107 INLINE static CPT(TransformState) make_rotate2d(float rotate); 00108 INLINE static CPT(TransformState) make_pos_rotate2d(const LVecBase2f &pos, 00109 float rotate); 00110 INLINE static CPT(TransformState) make_scale2d(float scale); 00111 INLINE static CPT(TransformState) make_scale2d(const LVecBase2f &scale); 00112 INLINE static CPT(TransformState) make_shear2d(float shear); 00113 INLINE static CPT(TransformState) make_pos_rotate_scale2d(const LVecBase2f &pos, 00114 float rotate, 00115 const LVecBase2f &scale); 00116 static CPT(TransformState) make_pos_rotate_scale_shear2d(const LVecBase2f &pos, 00117 float rotate, 00118 const LVecBase2f &scale, 00119 float shear); 00120 static CPT(TransformState) make_mat3(const LMatrix3f &mat); 00121 00122 00123 INLINE bool is_identity() const; 00124 INLINE bool is_invalid() const; 00125 INLINE bool is_singular() const; 00126 INLINE bool is_2d() const; 00127 00128 INLINE bool has_components() const; 00129 INLINE bool components_given() const; 00130 INLINE bool hpr_given() const; 00131 INLINE bool quat_given() const; 00132 INLINE bool has_pos() const; 00133 INLINE bool has_hpr() const; 00134 INLINE bool has_quat() const; 00135 INLINE bool has_scale() const; 00136 INLINE bool has_identity_scale() const; 00137 INLINE bool has_uniform_scale() const; 00138 INLINE bool has_shear() const; 00139 INLINE bool has_nonzero_shear() const; 00140 INLINE bool has_mat() const; 00141 00142 INLINE const LPoint3f &get_pos() const; 00143 INLINE const LVecBase3f &get_hpr() const; 00144 INLINE const LQuaternionf &get_quat() const; 00145 INLINE const LQuaternionf &get_norm_quat() const; 00146 INLINE const LVecBase3f &get_scale() const; 00147 INLINE float get_uniform_scale() const; 00148 INLINE const LVecBase3f &get_shear() const; 00149 INLINE const LMatrix4f &get_mat() const; 00150 00151 INLINE LVecBase2f get_pos2d() const; 00152 INLINE float get_rotate2d() const; 00153 INLINE LVecBase2f get_scale2d() const; 00154 INLINE float get_shear2d() const; 00155 INLINE LMatrix3f get_mat3() const; 00156 00157 CPT(TransformState) set_pos(const LVecBase3f &pos) const; 00158 CPT(TransformState) set_hpr(const LVecBase3f &hpr) const; 00159 CPT(TransformState) set_quat(const LQuaternionf &quat) const; 00160 CPT(TransformState) set_scale(const LVecBase3f &scale) const; 00161 CPT(TransformState) set_shear(const LVecBase3f &shear) const; 00162 00163 CPT(TransformState) set_pos2d(const LVecBase2f &pos) const; 00164 CPT(TransformState) set_rotate2d(float rotate) const; 00165 CPT(TransformState) set_scale2d(const LVecBase2f &scale) const; 00166 CPT(TransformState) set_shear2d(float shear) const; 00167 00168 CPT(TransformState) compose(const TransformState *other) const; 00169 CPT(TransformState) invert_compose(const TransformState *other) const; 00170 00171 INLINE CPT(TransformState) get_inverse() const; 00172 INLINE CPT(TransformState) get_unique() const; 00173 00174 INLINE int get_geom_rendering(int geom_rendering) const; 00175 00176 virtual bool unref() const; 00177 00178 INLINE void cache_ref() const; 00179 INLINE bool cache_unref() const; 00180 INLINE void node_ref() const; 00181 INLINE bool node_unref() const; 00182 00183 INLINE int get_composition_cache_num_entries() const; 00184 INLINE int get_invert_composition_cache_num_entries() const; 00185 00186 INLINE int get_composition_cache_size() const; 00187 INLINE const TransformState *get_composition_cache_source(int n) const; 00188 INLINE const TransformState *get_composition_cache_result(int n) const; 00189 INLINE int get_invert_composition_cache_size() const; 00190 INLINE const TransformState *get_invert_composition_cache_source(int n) const; 00191 INLINE const TransformState *get_invert_composition_cache_result(int n) const; 00192 #ifdef HAVE_PYTHON 00193 PyObject *get_composition_cache() const; 00194 PyObject *get_invert_composition_cache() const; 00195 #endif // HAVE_PYTHON 00196 00197 void output(ostream &out) const; 00198 void write(ostream &out, int indent_level) const; 00199 void write_composition_cache(ostream &out, int indent_level) const; 00200 00201 static int get_num_states(); 00202 static int get_num_unused_states(); 00203 static int clear_cache(); 00204 static void list_cycles(ostream &out); 00205 static void list_states(ostream &out); 00206 static bool validate_states(); 00207 #ifdef HAVE_PYTHON 00208 static PyObject *get_states(); 00209 #endif // HAVE_PYTHON 00210 00211 00212 public: 00213 static void init_states(); 00214 00215 INLINE static void flush_level(); 00216 00217 private: 00218 INLINE bool do_cache_unref() const; 00219 INLINE bool do_node_unref() const; 00220 00221 class CompositionCycleDescEntry { 00222 public: 00223 INLINE CompositionCycleDescEntry(const TransformState *obj, 00224 const TransformState *result, 00225 bool inverted); 00226 00227 const TransformState *_obj; 00228 const TransformState *_result; 00229 bool _inverted; 00230 }; 00231 typedef pvector<CompositionCycleDescEntry> CompositionCycleDesc; 00232 00233 static CPT(TransformState) return_new(TransformState *state); 00234 static CPT(TransformState) return_unique(TransformState *state); 00235 00236 CPT(TransformState) do_compose(const TransformState *other) const; 00237 CPT(TransformState) do_invert_compose(const TransformState *other) const; 00238 static bool r_detect_cycles(const TransformState *start_state, 00239 const TransformState *current_state, 00240 int length, UpdateSeq this_seq, 00241 CompositionCycleDesc *cycle_desc); 00242 static bool r_detect_reverse_cycles(const TransformState *start_state, 00243 const TransformState *current_state, 00244 int length, UpdateSeq this_seq, 00245 CompositionCycleDesc *cycle_desc); 00246 00247 void release_new(); 00248 void remove_cache_pointers(); 00249 00250 private: 00251 // This mutex protects _states. It also protects any modification 00252 // to the cache, which is encoded in _composition_cache and 00253 // _invert_composition_cache. 00254 static LightReMutex *_states_lock; 00255 typedef phash_set<const TransformState *, indirect_less_hash<const TransformState *> > States; 00256 static States *_states; 00257 static CPT(TransformState) _identity_state; 00258 static CPT(TransformState) _invalid_state; 00259 00260 // This iterator records the entry corresponding to this TransformState 00261 // object in the above global set. We keep the iterator around so 00262 // we can remove it when the TransformState destructs. 00263 States::iterator _saved_entry; 00264 00265 // This data structure manages the job of caching the composition of 00266 // two TransformStates. It's complicated because we have to be sure to 00267 // remove the entry if *either* of the input TransformStates destructs. 00268 // To implement this, we always record Composition entries in pairs, 00269 // one in each of the two involved TransformState objects. 00270 00271 // The first element of the map is the object we compose with. This 00272 // is not reference counted within this map; instead we store a 00273 // companion pointer in the other object, and remove the references 00274 // explicitly when either object destructs. 00275 class Composition { 00276 public: 00277 INLINE Composition(); 00278 INLINE Composition(const Composition ©); 00279 00280 // _result is reference counted if and only if it is not the same 00281 // pointer as this. 00282 const TransformState *_result; 00283 }; 00284 00285 typedef SimpleHashMap<const TransformState *, Composition, pointer_hash> CompositionCache; 00286 CompositionCache _composition_cache; 00287 CompositionCache _invert_composition_cache; 00288 00289 // This is used to mark nodes as we visit them to detect cycles. 00290 UpdateSeq _cycle_detect; 00291 static UpdateSeq _last_cycle_detect; 00292 00293 static PStatCollector _cache_update_pcollector; 00294 static PStatCollector _transform_compose_pcollector; 00295 static PStatCollector _transform_invert_pcollector; 00296 static PStatCollector _transform_calc_pcollector; 00297 static PStatCollector _transform_break_cycles_pcollector; 00298 static PStatCollector _transform_new_pcollector; 00299 static PStatCollector _transform_validate_pcollector; 00300 static PStatCollector _transform_hash_pcollector; 00301 00302 static PStatCollector _node_counter; 00303 static PStatCollector _cache_counter; 00304 00305 private: 00306 // This is the actual data within the TransformState. 00307 INLINE void check_hash() const; 00308 INLINE void check_singular() const; 00309 INLINE void check_components() const; 00310 INLINE void check_hpr() const; 00311 INLINE void check_quat() const; 00312 INLINE void check_norm_quat() const; 00313 INLINE void check_mat() const; 00314 INLINE void calc_hash(); 00315 void do_calc_hash(); 00316 void calc_singular(); 00317 INLINE void calc_components(); 00318 void do_calc_components(); 00319 INLINE void calc_hpr(); 00320 void do_calc_hpr(); 00321 void calc_quat(); 00322 void calc_norm_quat(); 00323 INLINE void calc_mat(); 00324 void do_calc_mat(); 00325 00326 INLINE void check_uniform_scale(); 00327 INLINE void check_uniform_scale2d(); 00328 00329 INLINE void set_destructing(); 00330 INLINE bool is_destructing() const; 00331 00332 INLINE void consider_update_pstats(int old_referenced_bits) const; 00333 static void update_pstats(int old_referenced_bits, int new_referenced_bits); 00334 00335 enum Flags { 00336 F_is_identity = 0x00000001, 00337 F_is_singular = 0x00000002, 00338 F_singular_known = 0x00000004, // set if we know F_is_singular 00339 F_components_given = 0x00000008, 00340 F_components_known = 0x00000010, // set if we know F_has_components 00341 F_has_components = 0x00000020, 00342 F_mat_known = 0x00000040, // set if _mat is defined 00343 F_is_invalid = 0x00000080, 00344 F_quat_given = 0x00000100, 00345 F_quat_known = 0x00000200, // set if _quat is defined 00346 F_hpr_given = 0x00000400, 00347 F_hpr_known = 0x00000800, // set if _hpr is defined 00348 F_uniform_scale = 0x00001000, 00349 F_identity_scale = 0x00002000, 00350 F_has_nonzero_shear = 0x00004000, 00351 F_is_destructing = 0x00008000, 00352 F_is_2d = 0x00010000, 00353 F_hash_known = 0x00020000, 00354 F_norm_quat_known = 0x00040000, 00355 }; 00356 LPoint3f _pos; 00357 LVecBase3f _hpr, _scale, _shear; 00358 LQuaternionf _quat, _norm_quat; 00359 LMatrix4f _mat; 00360 LMatrix4f *_inv_mat; 00361 size_t _hash; 00362 00363 unsigned int _flags; 00364 00365 // This mutex protects _flags, and all of the above computed values. 00366 LightMutex _lock; 00367 00368 static CacheStats _cache_stats; 00369 00370 public: 00371 static void register_with_read_factory(); 00372 virtual void write_datagram(BamWriter *manager, Datagram &dg); 00373 static PT(TypedWritableReferenceCount) change_this(TypedWritableReferenceCount *old_ptr, BamReader *manager); 00374 00375 protected: 00376 static TypedWritable *make_from_bam(const FactoryParams ¶ms); 00377 void fillin(DatagramIterator &scan, BamReader *manager); 00378 00379 public: 00380 static TypeHandle get_class_type() { 00381 return _type_handle; 00382 } 00383 static void init_type() { 00384 NodeCachedReferenceCount::init_type(); 00385 register_type(_type_handle, "TransformState", 00386 NodeCachedReferenceCount::get_class_type()); 00387 } 00388 virtual TypeHandle get_type() const { 00389 return get_class_type(); 00390 } 00391 virtual TypeHandle force_init_type() {init_type(); return get_class_type();} 00392 00393 private: 00394 static TypeHandle _type_handle; 00395 }; 00396 00397 INLINE ostream &operator << (ostream &out, const TransformState &state) { 00398 state.output(out); 00399 return out; 00400 } 00401 00402 #include "transformState.I" 00403 00404 #endif 00405