// Filename: transformState.h // Created by: drose (25Feb02) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license // along with this source code; you will also find a current copy of // the license at http://etc.cmu.edu/panda3d/docs/license/ . // // To contact the maintainers of this program write to // panda3d-general@lists.sourceforge.net . // //////////////////////////////////////////////////////////////////// #ifndef TRANSFORMSTATE_H #define TRANSFORMSTATE_H #include "pandabase.h" #include "nodeCachedReferenceCount.h" #include "pointerTo.h" #include "luse.h" #include "pset.h" #include "event.h" #include "updateSeq.h" #include "pStatCollector.h" #include "geomEnums.h" #include "reMutex.h" #include "pmutex.h" #include "config_pgraph.h" #include "deletedChain.h" class GraphicsStateGuardianBase; class FactoryParams; //////////////////////////////////////////////////////////////////// // Class : TransformState // Description : Indicates a coordinate-system transform on vertices. // TransformStates are the primary means for storing // transformations on the scene graph. // // Transforms may be specified in one of two ways: // componentwise, with a pos-hpr-scale, or with an // arbitrary transform matrix. If you specify a // transform componentwise, it will remember its // original components. // // TransformState objects are managed very much like // RenderState objects. They are immutable and // reference-counted automatically. // // You should not attempt to create or modify a // TransformState object directly. Instead, call one of // the make() functions to create one for you. And // instead of modifying a TransformState object, create a // new one. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA TransformState : public NodeCachedReferenceCount { protected: TransformState(); private: TransformState(const TransformState ©); void operator = (const TransformState ©); public: virtual ~TransformState(); ALLOC_DELETED_CHAIN(TransformState); PUBLISHED: INLINE bool operator < (const TransformState &other) const; bool sorts_less(const TransformState &other, bool uniquify_matrix) const; INLINE size_t get_hash() const; static CPT(TransformState) make_identity(); static CPT(TransformState) make_invalid(); INLINE static CPT(TransformState) make_pos(const LVecBase3f &pos); INLINE static CPT(TransformState) make_hpr(const LVecBase3f &hpr); INLINE static CPT(TransformState) make_quat(const LQuaternionf &quat); INLINE static CPT(TransformState) make_pos_hpr(const LVecBase3f &pos, const LVecBase3f &hpr); INLINE static CPT(TransformState) make_scale(float scale); INLINE static CPT(TransformState) make_scale(const LVecBase3f &scale); INLINE static CPT(TransformState) make_shear(const LVecBase3f &shear); INLINE static CPT(TransformState) make_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr, const LVecBase3f &scale); INLINE static CPT(TransformState) make_pos_quat_scale(const LVecBase3f &pos, const LQuaternionf &quat, const LVecBase3f &scale); static CPT(TransformState) make_pos_hpr_scale_shear(const LVecBase3f &pos, const LVecBase3f &hpr, const LVecBase3f &scale, const LVecBase3f &shear); static CPT(TransformState) make_pos_quat_scale_shear(const LVecBase3f &pos, const LQuaternionf &quat, const LVecBase3f &scale, const LVecBase3f &shear); static CPT(TransformState) make_mat(const LMatrix4f &mat); INLINE static CPT(TransformState) make_pos2d(const LVecBase2f &pos); INLINE static CPT(TransformState) make_rotate2d(float rotate); INLINE static CPT(TransformState) make_pos_rotate2d(const LVecBase2f &pos, float rotate); INLINE static CPT(TransformState) make_scale2d(float scale); INLINE static CPT(TransformState) make_scale2d(const LVecBase2f &scale); INLINE static CPT(TransformState) make_shear2d(float shear); INLINE static CPT(TransformState) make_pos_rotate_scale2d(const LVecBase2f &pos, float rotate, const LVecBase2f &scale); static CPT(TransformState) make_pos_rotate_scale_shear2d(const LVecBase2f &pos, float rotate, const LVecBase2f &scale, float shear); static CPT(TransformState) make_mat3(const LMatrix3f &mat); INLINE bool is_identity() const; INLINE bool is_invalid() const; INLINE bool is_singular() const; INLINE bool is_2d() const; INLINE bool has_components() const; INLINE bool components_given() const; INLINE bool hpr_given() const; INLINE bool quat_given() const; INLINE bool has_pos() const; INLINE bool has_hpr() const; INLINE bool has_quat() const; INLINE bool has_scale() const; INLINE bool has_identity_scale() const; INLINE bool has_uniform_scale() const; INLINE bool has_shear() const; INLINE bool has_nonzero_shear() const; INLINE bool has_mat() const; INLINE const LPoint3f &get_pos() const; INLINE const LVecBase3f &get_hpr() const; INLINE const LQuaternionf &get_quat() const; INLINE const LQuaternionf &get_norm_quat() const; INLINE const LVecBase3f &get_scale() const; INLINE float get_uniform_scale() const; INLINE const LVecBase3f &get_shear() const; INLINE const LMatrix4f &get_mat() const; INLINE LVecBase2f get_pos2d() const; INLINE float get_rotate2d() const; INLINE LVecBase2f get_scale2d() const; INLINE float get_shear2d() const; INLINE LMatrix3f get_mat3() const; CPT(TransformState) set_pos(const LVecBase3f &pos) const; CPT(TransformState) set_hpr(const LVecBase3f &hpr) const; CPT(TransformState) set_quat(const LQuaternionf &quat) const; CPT(TransformState) set_scale(const LVecBase3f &scale) const; CPT(TransformState) set_shear(const LVecBase3f &shear) const; CPT(TransformState) set_pos2d(const LVecBase2f &pos) const; CPT(TransformState) set_rotate2d(float rotate) const; CPT(TransformState) set_scale2d(const LVecBase2f &scale) const; CPT(TransformState) set_shear2d(float shear) const; CPT(TransformState) compose(const TransformState *other) const; CPT(TransformState) invert_compose(const TransformState *other) const; INLINE CPT(TransformState) get_inverse() const; INLINE int get_geom_rendering(int geom_rendering) const; bool unref() const; INLINE void cache_ref() const; INLINE bool cache_unref() const; INLINE void node_ref() const; INLINE bool node_unref() const; void output(ostream &out) const; void write(ostream &out, int indent_level) const; static int get_num_states(); static int get_num_unused_states(); static int clear_cache(); static void list_cycles(ostream &out); static void list_states(ostream &out); static bool validate_states(); public: static void init_states(); INLINE static void flush_level(); private: class CompositionCycleDescEntry { public: INLINE CompositionCycleDescEntry(const TransformState *obj, const TransformState *result, bool inverted); const TransformState *_obj; const TransformState *_result; bool _inverted; }; typedef pvector CompositionCycleDesc; static CPT(TransformState) return_new(TransformState *state); CPT(TransformState) do_compose(const TransformState *other) const; CPT(TransformState) do_invert_compose(const TransformState *other) const; static bool r_detect_cycles(const TransformState *start_state, const TransformState *current_state, int length, UpdateSeq this_seq, CompositionCycleDesc *cycle_desc); void remove_cache_pointers(); private: // This mutex protects _states. It also protects any modification // to the cache, which is encoded in _composition_cache and // _invert_composition_cache. static ReMutex *_states_lock; typedef phash_set > States; static States *_states; static CPT(TransformState) _identity_state; // This iterator records the entry corresponding to this TransformState // object in the above global set. We keep the iterator around so // we can remove it when the TransformState destructs. States::iterator _saved_entry; // This data structure manages the job of caching the composition of // two TransformStates. It's complicated because we have to be sure to // remove the entry if *either* of the input TransformStates destructs. // To implement this, we always record Composition entries in pairs, // one in each of the two involved TransformState objects. class Composition { public: INLINE Composition(); INLINE Composition(const Composition ©); // _result is reference counted if and only if it is not the same // pointer as this. const TransformState *_result; }; // The first element of the map is the object we compose with. This // is not reference counted within this map; instead we store a // companion pointer in the other object, and remove the references // explicitly when either object destructs. typedef phash_map CompositionCache; CompositionCache _composition_cache; CompositionCache _invert_composition_cache; // This is used to mark nodes as we visit them to detect cycles. UpdateSeq _cycle_detect; static UpdateSeq _last_cycle_detect; static PStatCollector _cache_update_pcollector; static PStatCollector _transform_compose_pcollector; static PStatCollector _transform_invert_pcollector; static PStatCollector _node_counter; static PStatCollector _cache_counter; private: // This is the actual data within the TransformState. INLINE void check_hash() const; INLINE void check_singular() const; INLINE void check_components() const; INLINE void check_hpr() const; INLINE void check_quat() const; INLINE void check_norm_quat() const; INLINE void check_mat() const; INLINE void calc_hash(); void do_calc_hash(); void calc_singular(); INLINE void calc_components(); void do_calc_components(); INLINE void calc_hpr(); void do_calc_hpr(); void calc_quat(); void calc_norm_quat(); INLINE void calc_mat(); void do_calc_mat(); INLINE void check_uniform_scale(); INLINE void check_uniform_scale2d(); INLINE void set_destructing(); INLINE bool is_destructing() const; INLINE void consider_update_pstats(int old_referenced_bits) const; static void update_pstats(int old_referenced_bits, int new_referenced_bits); enum Flags { F_is_identity = 0x00000001, F_is_singular = 0x00000002, F_singular_known = 0x00000004, // set if we know F_is_singular F_components_given = 0x00000008, F_components_known = 0x00000010, // set if we know F_has_components F_has_components = 0x00000020, F_mat_known = 0x00000040, // set if _mat is defined F_is_invalid = 0x00000080, F_quat_given = 0x00000100, F_quat_known = 0x00000200, // set if _quat is defined F_hpr_given = 0x00000400, F_hpr_known = 0x00000800, // set if _hpr is defined F_uniform_scale = 0x00001000, F_identity_scale = 0x00002000, F_has_nonzero_shear = 0x00004000, F_is_destructing = 0x00008000, F_is_2d = 0x00010000, F_hash_known = 0x00020000, F_norm_quat_known = 0x00040000, }; LPoint3f _pos; LVecBase3f _hpr, _scale, _shear; LQuaternionf _quat, _norm_quat; LMatrix4f _mat; LMatrix4f *_inv_mat; size_t _hash; unsigned int _flags; // This mutex protects _flags, and all of the above computed values. Mutex _lock; public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); static TypedWritable *change_this(TypedWritable *old_ptr, BamReader *manager); virtual void finalize(BamReader *manager); protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); void fillin(DatagramIterator &scan, BamReader *manager); public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { NodeCachedReferenceCount::init_type(); register_type(_type_handle, "TransformState", NodeCachedReferenceCount::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); } virtual TypeHandle force_init_type() {init_type(); return get_class_type();} private: static TypeHandle _type_handle; }; INLINE ostream &operator << (ostream &out, const TransformState &state) { state.output(out); return out; } #include "transformState.I" #endif