418 lines
16 KiB
C
418 lines
16 KiB
C
|
/**
|
||
|
* PANDA 3D SOFTWARE
|
||
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||
|
*
|
||
|
* All use of this software is subject to the terms of the revised BSD
|
||
|
* license. You should have received a copy of this license along
|
||
|
* with this source code in a file named "LICENSE."
|
||
|
*
|
||
|
* @file transformState.h
|
||
|
* @author drose
|
||
|
* @date 2002-02-25
|
||
|
*/
|
||
|
|
||
|
#ifndef TRANSFORMSTATE_H
|
||
|
#define TRANSFORMSTATE_H
|
||
|
|
||
|
#include "pandabase.h"
|
||
|
|
||
|
#include "nodeCachedReferenceCount.h"
|
||
|
#include "pointerTo.h"
|
||
|
#include "luse.h"
|
||
|
#include "event.h"
|
||
|
#include "updateSeq.h"
|
||
|
#include "pStatCollector.h"
|
||
|
#include "geomEnums.h"
|
||
|
#include "lightReMutex.h"
|
||
|
#include "lightReMutexHolder.h"
|
||
|
#include "lightMutex.h"
|
||
|
#include "lightMutexHolder.h"
|
||
|
#include "config_pgraph.h"
|
||
|
#include "deletedChain.h"
|
||
|
#include "simpleHashMap.h"
|
||
|
#include "cacheStats.h"
|
||
|
#include "extension.h"
|
||
|
|
||
|
class GraphicsStateGuardianBase;
|
||
|
class FactoryParams;
|
||
|
|
||
|
/**
|
||
|
* 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_PGRAPH TransformState final : public NodeCachedReferenceCount {
|
||
|
protected:
|
||
|
TransformState();
|
||
|
|
||
|
public:
|
||
|
TransformState(const TransformState ©) = delete;
|
||
|
virtual ~TransformState();
|
||
|
ALLOC_DELETED_CHAIN(TransformState);
|
||
|
|
||
|
TransformState &operator = (const TransformState ©) = delete;
|
||
|
|
||
|
PUBLISHED:
|
||
|
INLINE bool operator != (const TransformState &other) const;
|
||
|
INLINE int compare_to(const TransformState &other) const;
|
||
|
int compare_to(const TransformState &other, bool uniquify_matrix) const;
|
||
|
bool operator == (const TransformState &other) const;
|
||
|
INLINE size_t get_hash() const;
|
||
|
|
||
|
static CPT(TransformState) make_identity();
|
||
|
static CPT(TransformState) make_invalid();
|
||
|
INLINE static CPT(TransformState) make_pos(const LVecBase3 &pos);
|
||
|
INLINE static CPT(TransformState) make_hpr(const LVecBase3 &hpr);
|
||
|
INLINE static CPT(TransformState) make_quat(const LQuaternion &quat);
|
||
|
INLINE static CPT(TransformState) make_pos_hpr(const LVecBase3 &pos,
|
||
|
const LVecBase3 &hpr);
|
||
|
INLINE static CPT(TransformState) make_scale(PN_stdfloat scale);
|
||
|
INLINE static CPT(TransformState) make_scale(const LVecBase3 &scale);
|
||
|
INLINE static CPT(TransformState) make_shear(const LVecBase3 &shear);
|
||
|
INLINE static CPT(TransformState) make_pos_hpr_scale(const LVecBase3 &pos,
|
||
|
const LVecBase3 &hpr,
|
||
|
const LVecBase3 &scale);
|
||
|
INLINE static CPT(TransformState) make_pos_quat_scale(const LVecBase3 &pos,
|
||
|
const LQuaternion &quat,
|
||
|
const LVecBase3 &scale);
|
||
|
static CPT(TransformState) make_pos_hpr_scale_shear(const LVecBase3 &pos,
|
||
|
const LVecBase3 &hpr,
|
||
|
const LVecBase3 &scale,
|
||
|
const LVecBase3 &shear);
|
||
|
static CPT(TransformState) make_pos_quat_scale_shear(const LVecBase3 &pos,
|
||
|
const LQuaternion &quat,
|
||
|
const LVecBase3 &scale,
|
||
|
const LVecBase3 &shear);
|
||
|
static CPT(TransformState) make_mat(const LMatrix4 &mat);
|
||
|
|
||
|
|
||
|
INLINE static CPT(TransformState) make_pos2d(const LVecBase2 &pos);
|
||
|
INLINE static CPT(TransformState) make_rotate2d(PN_stdfloat rotate);
|
||
|
INLINE static CPT(TransformState) make_pos_rotate2d(const LVecBase2 &pos,
|
||
|
PN_stdfloat rotate);
|
||
|
INLINE static CPT(TransformState) make_scale2d(PN_stdfloat scale);
|
||
|
INLINE static CPT(TransformState) make_scale2d(const LVecBase2 &scale);
|
||
|
INLINE static CPT(TransformState) make_shear2d(PN_stdfloat shear);
|
||
|
INLINE static CPT(TransformState) make_pos_rotate_scale2d(const LVecBase2 &pos,
|
||
|
PN_stdfloat rotate,
|
||
|
const LVecBase2 &scale);
|
||
|
static CPT(TransformState) make_pos_rotate_scale_shear2d(const LVecBase2 &pos,
|
||
|
PN_stdfloat rotate,
|
||
|
const LVecBase2 &scale,
|
||
|
PN_stdfloat shear);
|
||
|
static CPT(TransformState) make_mat3(const LMatrix3 &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 LPoint3 &get_pos() const;
|
||
|
INLINE const LVecBase3 &get_hpr() const;
|
||
|
INLINE const LQuaternion &get_quat() const;
|
||
|
INLINE const LQuaternion &get_norm_quat() const;
|
||
|
INLINE const LVecBase3 &get_scale() const;
|
||
|
INLINE PN_stdfloat get_uniform_scale() const;
|
||
|
INLINE const LVecBase3 &get_shear() const;
|
||
|
INLINE const LMatrix4 &get_mat() const;
|
||
|
|
||
|
INLINE LVecBase2 get_pos2d() const;
|
||
|
INLINE PN_stdfloat get_rotate2d() const;
|
||
|
INLINE LVecBase2 get_scale2d() const;
|
||
|
INLINE PN_stdfloat get_shear2d() const;
|
||
|
INLINE LMatrix3 get_mat3() const;
|
||
|
|
||
|
MAKE_PROPERTY(pos, get_pos);
|
||
|
MAKE_PROPERTY(hpr, get_hpr);
|
||
|
MAKE_PROPERTY(quat, get_quat);
|
||
|
MAKE_PROPERTY(norm_quat, get_norm_quat);
|
||
|
MAKE_PROPERTY(scale, get_scale);
|
||
|
MAKE_PROPERTY(shear, get_shear);
|
||
|
MAKE_PROPERTY(mat, get_mat);
|
||
|
|
||
|
CPT(TransformState) set_pos(const LVecBase3 &pos) const;
|
||
|
CPT(TransformState) set_hpr(const LVecBase3 &hpr) const;
|
||
|
CPT(TransformState) set_quat(const LQuaternion &quat) const;
|
||
|
CPT(TransformState) set_scale(const LVecBase3 &scale) const;
|
||
|
CPT(TransformState) set_shear(const LVecBase3 &shear) const;
|
||
|
|
||
|
CPT(TransformState) set_pos2d(const LVecBase2 &pos) const;
|
||
|
CPT(TransformState) set_rotate2d(PN_stdfloat rotate) const;
|
||
|
CPT(TransformState) set_scale2d(const LVecBase2 &scale) const;
|
||
|
CPT(TransformState) set_shear2d(PN_stdfloat shear) const;
|
||
|
|
||
|
CPT(TransformState) compose(const TransformState *other) const;
|
||
|
CPT(TransformState) invert_compose(const TransformState *other) const;
|
||
|
|
||
|
INLINE CPT(TransformState) get_inverse() const;
|
||
|
INLINE CPT(TransformState) get_unique() const;
|
||
|
|
||
|
INLINE int get_geom_rendering(int geom_rendering) const;
|
||
|
|
||
|
virtual bool unref() const;
|
||
|
|
||
|
INLINE void cache_ref() const;
|
||
|
INLINE bool cache_unref() const;
|
||
|
INLINE void node_ref() const;
|
||
|
INLINE bool node_unref() const;
|
||
|
|
||
|
INLINE size_t get_composition_cache_num_entries() const;
|
||
|
INLINE size_t get_invert_composition_cache_num_entries() const;
|
||
|
|
||
|
INLINE size_t get_composition_cache_size() const;
|
||
|
INLINE const TransformState *get_composition_cache_source(size_t n) const;
|
||
|
INLINE const TransformState *get_composition_cache_result(size_t n) const;
|
||
|
INLINE size_t get_invert_composition_cache_size() const;
|
||
|
INLINE const TransformState *get_invert_composition_cache_source(size_t n) const;
|
||
|
INLINE const TransformState *get_invert_composition_cache_result(size_t n) const;
|
||
|
bool validate_composition_cache() const;
|
||
|
EXTENSION(PyObject *get_composition_cache() const);
|
||
|
EXTENSION(PyObject *get_invert_composition_cache() const);
|
||
|
|
||
|
void output(std::ostream &out) const;
|
||
|
void write(std::ostream &out, int indent_level) const;
|
||
|
void write_composition_cache(std::ostream &out, int indent_level) const;
|
||
|
|
||
|
static int get_num_states();
|
||
|
static int get_num_unused_states();
|
||
|
static int clear_cache();
|
||
|
static int garbage_collect();
|
||
|
static void list_cycles(std::ostream &out);
|
||
|
static void list_states(std::ostream &out);
|
||
|
static bool validate_states();
|
||
|
EXTENSION(static PyObject *get_states());
|
||
|
EXTENSION(static PyObject *get_unused_states());
|
||
|
|
||
|
public:
|
||
|
static void init_states();
|
||
|
|
||
|
INLINE static void flush_level();
|
||
|
|
||
|
private:
|
||
|
INLINE bool do_cache_unref() const;
|
||
|
INLINE bool do_node_unref() const;
|
||
|
|
||
|
class CompositionCycleDescEntry {
|
||
|
public:
|
||
|
INLINE CompositionCycleDescEntry(const TransformState *obj,
|
||
|
const TransformState *result,
|
||
|
bool inverted);
|
||
|
|
||
|
const TransformState *_obj;
|
||
|
const TransformState *_result;
|
||
|
bool _inverted;
|
||
|
};
|
||
|
typedef pvector<CompositionCycleDescEntry> CompositionCycleDesc;
|
||
|
|
||
|
static CPT(TransformState) return_new(TransformState *state);
|
||
|
static CPT(TransformState) return_unique(TransformState *state);
|
||
|
|
||
|
CPT(TransformState) do_compose(const TransformState *other) const;
|
||
|
CPT(TransformState) do_invert_compose(const TransformState *other) const;
|
||
|
void detect_and_break_cycles();
|
||
|
static bool r_detect_cycles(const TransformState *start_state,
|
||
|
const TransformState *current_state,
|
||
|
int length, UpdateSeq this_seq,
|
||
|
CompositionCycleDesc *cycle_desc);
|
||
|
static bool r_detect_reverse_cycles(const TransformState *start_state,
|
||
|
const TransformState *current_state,
|
||
|
int length, UpdateSeq this_seq,
|
||
|
CompositionCycleDesc *cycle_desc);
|
||
|
|
||
|
void release_new();
|
||
|
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 LightReMutex *_states_lock;
|
||
|
typedef SimpleHashMap<const TransformState *, std::nullptr_t, indirect_equals_hash<const TransformState *> > States;
|
||
|
static States _states;
|
||
|
static CPT(TransformState) _identity_state;
|
||
|
static CPT(TransformState) _invalid_state;
|
||
|
|
||
|
// This iterator records the entry corresponding to this TransformState
|
||
|
// object in the above global set. We keep the index around so we can
|
||
|
// remove it when the TransformState destructs.
|
||
|
int _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.
|
||
|
|
||
|
// 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.
|
||
|
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;
|
||
|
};
|
||
|
|
||
|
typedef SimpleHashMap<const TransformState *, Composition, pointer_hash> CompositionCache;
|
||
|
mutable CompositionCache _composition_cache;
|
||
|
mutable 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;
|
||
|
|
||
|
// This keeps track of our current position through the garbage collection
|
||
|
// cycle.
|
||
|
static size_t _garbage_index;
|
||
|
|
||
|
static bool _uniquify_matrix;
|
||
|
|
||
|
static PStatCollector _cache_update_pcollector;
|
||
|
static PStatCollector _garbage_collect_pcollector;
|
||
|
static PStatCollector _transform_compose_pcollector;
|
||
|
static PStatCollector _transform_invert_pcollector;
|
||
|
static PStatCollector _transform_calc_pcollector;
|
||
|
static PStatCollector _transform_break_cycles_pcollector;
|
||
|
static PStatCollector _transform_new_pcollector;
|
||
|
static PStatCollector _transform_validate_pcollector;
|
||
|
static PStatCollector _transform_hash_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,
|
||
|
};
|
||
|
LPoint3 _pos;
|
||
|
LVecBase3 _hpr, _scale, _shear;
|
||
|
LQuaternion _quat, _norm_quat;
|
||
|
LMatrix4 _mat;
|
||
|
LMatrix4 *_inv_mat;
|
||
|
size_t _hash;
|
||
|
|
||
|
unsigned int _flags;
|
||
|
|
||
|
// This mutex protects _flags, and all of the above computed values.
|
||
|
LightMutex _lock;
|
||
|
|
||
|
static CacheStats _cache_stats;
|
||
|
|
||
|
public:
|
||
|
static void register_with_read_factory();
|
||
|
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||
|
static PT(TypedWritableReferenceCount) change_this(TypedWritableReferenceCount *old_ptr, 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;
|
||
|
|
||
|
friend class Extension<TransformState>;
|
||
|
};
|
||
|
|
||
|
// We can safely redefine this as a no-op.
|
||
|
template<>
|
||
|
INLINE void PointerToBase<TransformState>::update_type(To *ptr) {}
|
||
|
|
||
|
INLINE std::ostream &operator << (std::ostream &out, const TransformState &state) {
|
||
|
state.output(out);
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
#include "transformState.I"
|
||
|
|
||
|
#endif
|