// Filename: geom.h // Created by: drose (06Mar05) // //////////////////////////////////////////////////////////////////// // // 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 GEOM_H #define GEOM_H #include "pandabase.h" #include "copyOnWriteObject.h" #include "copyOnWritePointer.h" #include "cycleData.h" #include "cycleDataLockedReader.h" #include "cycleDataReader.h" #include "cycleDataWriter.h" #include "cycleDataStageReader.h" #include "cycleDataStageWriter.h" #include "pipelineCycler.h" #include "geomVertexData.h" #include "geomPrimitive.h" #include "geomMunger.h" #include "geomEnums.h" #include "geomCacheEntry.h" #include "textureStage.h" #include "updateSeq.h" #include "pointerTo.h" #include "indirectLess.h" #include "pset.h" #include "pmap.h" #include "boundingVolume.h" #include "pStatCollector.h" #include "deletedChain.h" #include "pmutex.h" class GeomContext; class PreparedGraphicsObjects; //////////////////////////////////////////////////////////////////// // Class : Geom // Description : A container for geometry primitives. This class // associates one or more GeomPrimitive objects with a // table of vertices defined by a GeomVertexData object. // All of the primitives stored in a particular Geom are // drawn from the same set of vertices (each primitive // uses a subset of all of the vertices in the table), // and all of them must be rendered at the same time, in // the same graphics state. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA Geom : public CopyOnWriteObject, public GeomEnums { protected: virtual PT(CopyOnWriteObject) make_cow_copy(); PUBLISHED: Geom(const GeomVertexData *data); protected: Geom(const Geom ©); PUBLISHED: void operator = (const Geom ©); virtual ~Geom(); ALLOC_DELETED_CHAIN(Geom); virtual Geom *make_copy() const; INLINE PrimitiveType get_primitive_type() const; INLINE ShadeModel get_shade_model() const; INLINE int get_geom_rendering() const; INLINE UsageHint get_usage_hint() const; void set_usage_hint(UsageHint usage_hint); INLINE CPT(GeomVertexData) get_vertex_data(Thread *current_thread = Thread::get_current_thread()) const; PT(GeomVertexData) modify_vertex_data(); void set_vertex_data(const GeomVertexData *data); void offset_vertices(const GeomVertexData *data, int offset); int make_nonindexed(bool composite_only); INLINE int get_num_primitives() const; INLINE CPT(GeomPrimitive) get_primitive(int i) const; INLINE PT(GeomPrimitive) modify_primitive(int i); void set_primitive(int i, const GeomPrimitive *primitive); void add_primitive(const GeomPrimitive *primitive); void remove_primitive(int i); void clear_primitives(); INLINE PT(Geom) decompose() const; INLINE PT(Geom) doubleside() const; INLINE PT(Geom) reverse() const; INLINE PT(Geom) rotate() const; INLINE PT(Geom) unify(int max_indices, bool preserve_order) const; void decompose_in_place(); void doubleside_in_place(); void reverse_in_place(); void rotate_in_place(); void unify_in_place(int max_indices, bool preserve_order); virtual bool copy_primitives_from(const Geom *other); int get_num_bytes() const; INLINE UpdateSeq get_modified(Thread *current_thread = Thread::get_current_thread()) const; bool request_resident() const; void transform_vertices(const LMatrix4f &mat); bool check_valid() const; bool check_valid(const GeomVertexData *vertex_data) const; CPT(BoundingVolume) get_bounds(Thread *current_thread = Thread::get_current_thread()) const; int get_nested_vertices(Thread *current_thread = Thread::get_current_thread()) const; INLINE void mark_bounds_stale() const; INLINE void set_bounds(const BoundingVolume *volume); INLINE void clear_bounds(); virtual void output(ostream &out) const; virtual void write(ostream &out, int indent_level = 0) const; void clear_cache(); void clear_cache_stage(Thread *current_thread); void prepare(PreparedGraphicsObjects *prepared_objects); bool is_prepared(PreparedGraphicsObjects *prepared_objects) const; bool release(PreparedGraphicsObjects *prepared_objects); int release_all(); GeomContext *prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg); public: bool draw(GraphicsStateGuardianBase *gsg, const GeomMunger *munger, const GeomVertexData *vertex_data, bool force, Thread *current_thread) const; INLINE void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, const GeomVertexData *vertex_data, bool got_mat, const LMatrix4f &mat, Thread *current_thread) const; INLINE void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, Thread *current_thread) const; static UpdateSeq get_next_modified(); public: typedef pvector< PT(TextureStage) > ActiveTextureStages; typedef pset NoTexCoordStages; private: class CData; INLINE void mark_internal_bounds_stale(CData *cdata); void compute_internal_bounds(CData *cdata, Thread *current_thread) const; void do_calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, const GeomVertexData *vertex_data, bool got_mat, const LMatrix4f &mat, const CData *cdata, Thread *current_thread) const; void clear_prepared(PreparedGraphicsObjects *prepared_objects); bool check_will_be_valid(const GeomVertexData *vertex_data) const; void reset_usage_hint(CData *cdata); void reset_geom_rendering(CData *cdata); void combine_primitives(GeomPrimitive *a_prim, const GeomPrimitive *b_prim, Thread *current_thread); private: typedef pvector Primitives; // We have to use reference-counting pointers here instead of having // explicit cleanup in the GeomVertexFormat destructor, because the // cache needs to be stored in the CycleData, which makes accurate // cleanup more difficult. We use the GeomCacheManager class to // avoid cache bloat. // Note: the above comment is no longer true. The cache is not // stored in the CycleData, which just causes problems; instead, we // cycle each individual CacheEntry as needed. Need to investigate // if we could simplify the cache system now. // The pipelined data with each CacheEntry. class CDataCache : public CycleData { public: INLINE CDataCache(); INLINE CDataCache(const CDataCache ©); virtual ~CDataCache(); ALLOC_DELETED_CHAIN(CDataCache); virtual CycleData *make_copy() const; virtual TypeHandle get_parent_type() const { return Geom::get_class_type(); } INLINE void set_result(const Geom *geom_result, const GeomVertexData *data_result); Geom *_source; // A back pointer to the containing Geom const Geom *_geom_result; // ref-counted if not NULL and not same as _source CPT(GeomVertexData) _data_result; public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { register_type(_type_handle, "Geom::CDataCache"); } private: static TypeHandle _type_handle; }; typedef CycleDataReader CDCacheReader; typedef CycleDataWriter CDCacheWriter; public: // The CacheKey class separates out just the part of CacheEntry that // is used to key the cache entry within the map. We have this as a // separate class so we can easily look up a new entry in the map, // without having to execute the relatively expensive CacheEntry // constructor. class CacheKey { public: INLINE CacheKey(const GeomVertexData *source_data, const GeomMunger *modifier); INLINE bool operator < (const CacheKey &other) const; CPT(GeomVertexData) _source_data; CPT(GeomMunger) _modifier; }; // It is not clear why MSVC7 needs this class to be public. class CacheEntry : public GeomCacheEntry { public: INLINE CacheEntry(Geom *source, const GeomVertexData *source_data, const GeomMunger *modifier); ALLOC_DELETED_CHAIN(CacheEntry); virtual void evict_callback(); virtual void output(ostream &out) const; Geom *_source; // A back pointer to the containing Geom CacheKey _key; PipelineCycler _cycler; public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { register_type(_type_handle, "Geom::CacheEntry"); } private: static TypeHandle _type_handle; }; typedef pmap > Cache; private: // This is the data that must be cycled between pipeline stages. class EXPCL_PANDA CData : public CycleData { public: INLINE CData(); INLINE CData(const CData ©); ALLOC_DELETED_CHAIN(CData); virtual CycleData *make_copy() const; virtual void write_datagram(BamWriter *manager, Datagram &dg) const; virtual int complete_pointers(TypedWritable **plist, BamReader *manager); virtual void fillin(DatagramIterator &scan, BamReader *manager); virtual TypeHandle get_parent_type() const { return Geom::get_class_type(); } COWPT(GeomVertexData) _data; Primitives _primitives; PrimitiveType _primitive_type; ShadeModel _shade_model; int _geom_rendering; UsageHint _usage_hint; bool _got_usage_hint; UpdateSeq _modified; CPT(BoundingVolume) _internal_bounds; int _nested_vertices; bool _internal_bounds_stale; CPT(BoundingVolume) _user_bounds; public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { register_type(_type_handle, "Geom::CData"); } private: static TypeHandle _type_handle; }; PipelineCycler _cycler; typedef CycleDataLockedReader CDLockedReader; typedef CycleDataReader CDReader; typedef CycleDataWriter CDWriter; typedef CycleDataStageReader CDStageReader; typedef CycleDataStageWriter CDStageWriter; Cache _cache; Mutex _cache_lock; // This works just like the Texture contexts: each Geom keeps a // record of all the PGO objects that hold the Geom, and vice-versa. typedef pmap Contexts; Contexts _contexts; static UpdateSeq _next_modified; static PStatCollector _draw_primitive_setup_pcollector; public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); 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() { CopyOnWriteObject::init_type(); register_type(_type_handle, "Geom", CopyOnWriteObject::get_class_type()); CDataCache::init_type(); CacheEntry::init_type(); CData::init_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 CacheEntry; friend class GeomMunger; friend class GeomContext; friend class GeomPipelineReader; friend class PreparedGraphicsObjects; }; //////////////////////////////////////////////////////////////////// // Class : GeomPipelineReader // Description : Encapsulates the data from a Geom, // pre-fetched for one stage of the pipeline. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA GeomPipelineReader : public GeomEnums { public: INLINE GeomPipelineReader(const Geom *object, Thread *current_thread); private: INLINE GeomPipelineReader(const GeomPipelineReader ©); INLINE void operator = (const GeomPipelineReader ©); public: INLINE ~GeomPipelineReader(); ALLOC_DELETED_CHAIN(GeomPipelineReader); INLINE const Geom *get_object() const; INLINE Thread *get_current_thread() const; void check_usage_hint() const; INLINE PrimitiveType get_primitive_type() const; INLINE ShadeModel get_shade_model() const; INLINE int get_geom_rendering() const; INLINE UsageHint get_usage_hint() const; INLINE CPT(GeomVertexData) get_vertex_data() const; INLINE int get_num_primitives() const; INLINE CPT(GeomPrimitive) get_primitive(int i) const; INLINE UpdateSeq get_modified() const; bool check_valid(const GeomVertexDataPipelineReader *data_reader) const; bool draw(GraphicsStateGuardianBase *gsg, const GeomMunger *munger, const GeomVertexDataPipelineReader *data_reader, bool force) const; private: CPT(Geom) _object; Thread *_current_thread; const Geom::CData *_cdata; public: static TypeHandle get_class_type() { return _type_handle; } static void init_type() { register_type(_type_handle, "GeomPipelineReader"); } private: static TypeHandle _type_handle; }; INLINE ostream &operator << (ostream &out, const Geom &obj); #include "geom.I" #endif