// Filename: geom.I // Created by: drose (06Mar05) // //////////////////////////////////////////////////////////////////// // // 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." // //////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////// // Function: Geom::get_primitive_type // Access: Published // Description: Returns the fundamental primitive type that is common // to all GeomPrimitives added within the Geom. All // nested primitives within a particular Geom must be // the same type (that is, you can mix triangles and // tristrips, because they are both the same fundamental // type PT_polygons, but you cannot mix triangles and // points withn the same Geom). //////////////////////////////////////////////////////////////////// INLINE Geom::PrimitiveType Geom:: get_primitive_type() const { CDReader cdata(_cycler); return cdata->_primitive_type; } //////////////////////////////////////////////////////////////////// // Function: Geom::get_shade_model // Access: Published // Description: Returns the shade model common to all of the // individual GeomPrimitives that have been added to the // geom. //////////////////////////////////////////////////////////////////// INLINE Geom::ShadeModel Geom:: get_shade_model() const { CDReader cdata(_cycler); return cdata->_shade_model; } //////////////////////////////////////////////////////////////////// // Function: Geom::get_geom_rendering // Access: Published // Description: Returns the set of GeomRendering bits that represent // the rendering properties required to properly render // this Geom. //////////////////////////////////////////////////////////////////// INLINE int Geom:: get_geom_rendering() const { CDReader cdata(_cycler); return cdata->_geom_rendering; } //////////////////////////////////////////////////////////////////// // Function: Geom::get_usage_hint // Access: Published // Description: Returns the minimum (i.e. most dynamic) usage_hint // among all of the individual GeomPrimitives that have // been added to the geom. //////////////////////////////////////////////////////////////////// INLINE Geom::UsageHint Geom:: get_usage_hint() const { CDLockedReader cdata(_cycler); if (!cdata->_got_usage_hint) { CDWriter cdataw(((Geom *)this)->_cycler, cdata, false); ((Geom *)this)->reset_usage_hint(cdataw); return cdataw->_usage_hint; } return cdata->_usage_hint; } //////////////////////////////////////////////////////////////////// // Function: Geom::get_vertex_data // Access: Published // Description: Returns a const pointer to the GeomVertexData, // for application code to directly examine (but not // modify) the geom's underlying data. //////////////////////////////////////////////////////////////////// INLINE CPT(GeomVertexData) Geom:: get_vertex_data(Thread *current_thread) const { CDReader cdata(_cycler, current_thread); return cdata->_data.get_read_pointer(); } //////////////////////////////////////////////////////////////////// // Function: Geom::is_empty // Access: Published // Description: Returns true if there appear to be no vertices to be // rendered by this Geom, false if has some actual data. //////////////////////////////////////////////////////////////////// INLINE bool Geom:: is_empty() const { CDReader cdata(_cycler); return (cdata->_data.get_read_pointer()->get_num_rows() == 0 || cdata->_primitives.empty()); } //////////////////////////////////////////////////////////////////// // Function: Geom::get_num_primitives // Access: Published // Description: Returns the number of GeomPrimitive objects stored // within the Geom, each of which represents a number of // primitives of a particular type. //////////////////////////////////////////////////////////////////// INLINE int Geom:: get_num_primitives() const { CDReader cdata(_cycler); return cdata->_primitives.size(); } //////////////////////////////////////////////////////////////////// // Function: Geom::get_primitive // Access: Published // Description: Returns a const pointer to the ith GeomPrimitive // object stored within the Geom. Use this call only to // inspect the ith object; use modify_primitive() or // set_primitive() if you want to modify it. //////////////////////////////////////////////////////////////////// INLINE CPT(GeomPrimitive) Geom:: get_primitive(int i) const { CDReader cdata(_cycler); nassertr(i >= 0 && i < (int)cdata->_primitives.size(), NULL); return cdata->_primitives[i].get_read_pointer(); } //////////////////////////////////////////////////////////////////// // Function: Geom::modify_primitive // Access: Published // Description: Returns a modifiable pointer to the ith GeomPrimitive // object stored within the Geom, so application code // can directly manipulate the properties of this // primitive. // // Don't call this in a downstream thread unless you // don't mind it blowing away other changes you might // have recently made in an upstream thread. //////////////////////////////////////////////////////////////////// INLINE PT(GeomPrimitive) Geom:: modify_primitive(int i) { Thread *current_thread = Thread::get_current_thread(); CDWriter cdata(_cycler, true, current_thread); nassertr(i >= 0 && i < (int)cdata->_primitives.size(), NULL); cdata->_got_usage_hint = false; cdata->_modified = Geom::get_next_modified(); clear_cache_stage(current_thread); return cdata->_primitives[i].get_write_pointer(); } //////////////////////////////////////////////////////////////////// // Function: Geom::decompose // Access: Published // Description: Decomposes all of the primitives within this Geom, // returning the result. See // GeomPrimitive::decompose(). //////////////////////////////////////////////////////////////////// INLINE PT(Geom) Geom:: decompose() const { PT(Geom) new_geom = make_copy(); new_geom->decompose_in_place(); return new_geom; } //////////////////////////////////////////////////////////////////// // Function: Geom::doubleside // Access: Published // Description: Doublesides all of the primitives within this Geom, // returning the result. See // GeomPrimitive::doubleside(). //////////////////////////////////////////////////////////////////// INLINE PT(Geom) Geom:: doubleside() const { PT(Geom) new_geom = make_copy(); new_geom->doubleside_in_place(); return new_geom; } //////////////////////////////////////////////////////////////////// // Function: Geom::reverse // Access: Published // Description: Reverses all of the primitives within this Geom, // returning the result. See // GeomPrimitive::reverse(). //////////////////////////////////////////////////////////////////// INLINE PT(Geom) Geom:: reverse() const { PT(Geom) new_geom = make_copy(); new_geom->reverse_in_place(); return new_geom; } //////////////////////////////////////////////////////////////////// // Function: Geom::rotate // Access: Published // Description: Rotates all of the primitives within this Geom, // returning the result. See // GeomPrimitive::rotate(). //////////////////////////////////////////////////////////////////// INLINE PT(Geom) Geom:: rotate() const { PT(Geom) new_geom = make_copy(); new_geom->rotate_in_place(); return new_geom; } //////////////////////////////////////////////////////////////////// // Function: Geom::unify // Access: Published // Description: Unifies all of the primitives contained within this // Geom into a single (or as few as possible, within the // constraints of max_indices) primitive objects. This // may require decomposing the primitives if, for // instance, the Geom contains both triangle strips and // triangle fans. // // max_indices represents the maximum number of indices // that will be put in any one GeomPrimitive. If // preserve_order is true, then the primitives will not // be reordered during the operation, even if this // results in a suboptimal result. //////////////////////////////////////////////////////////////////// INLINE PT(Geom) Geom:: unify(int max_indices, bool preserve_order) const { PT(Geom) new_geom = make_copy(); new_geom->unify_in_place(max_indices, preserve_order); return new_geom; } //////////////////////////////////////////////////////////////////// // Function: Geom::make_points // Access: Published // Description: Returns a new Geom with points at all the vertices. // See GeomPrimitive::make_points(). //////////////////////////////////////////////////////////////////// INLINE PT(Geom) Geom:: make_points() const { PT(Geom) new_geom = make_copy(); new_geom->make_points_in_place(); return new_geom; } //////////////////////////////////////////////////////////////////// // Function: Geom::get_modified // Access: Published // Description: Returns a sequence number which is guaranteed to // change at least every time any of the primitives in // the Geom is modified, or the set of primitives is // modified. However, this does not include // modifications to the vertex data, which should be // tested separately. //////////////////////////////////////////////////////////////////// INLINE UpdateSeq Geom:: get_modified(Thread *current_thread) const { CDReader cdata(_cycler, current_thread); return cdata->_modified; } //////////////////////////////////////////////////////////////////// // Function: Geom::mark_bounds_stale // Access: Published // Description: Marks the bounding volume of the Geom as stale so // that it should be recomputed. Usually it is not // necessary to call this explicitly. //////////////////////////////////////////////////////////////////// INLINE void Geom:: mark_bounds_stale() const { CDWriter cdata(((Geom *)this)->_cycler, false); ((Geom *)this)->mark_internal_bounds_stale(cdata); } //////////////////////////////////////////////////////////////////// // Function: Geom::set_bounds_type // Access: Published // Description: Specifies the desired type of bounding volume that // will be created for this Geom. This is normally // BoundingVolume::BT_default, which means to set the // type according to the config variable "bounds-type". // // If this is BT_sphere or BT_box, a BoundingSphere or // BoundingBox is explicitly created. If it is BT_best, // a BoundingBox is created. // // This affects the implicit bounding volume only. If // an explicit bounding volume is set on the Geom with // set_bounds(), that bounding volume type is used. // (This is different behavior from the similar method // on PandaNode.) //////////////////////////////////////////////////////////////////// INLINE void Geom:: set_bounds_type(BoundingVolume::BoundsType bounds_type) { CDWriter cdata(_cycler, true); cdata->_bounds_type = bounds_type; mark_internal_bounds_stale(cdata); } //////////////////////////////////////////////////////////////////// // Function: Geom::get_bounds_type // Access: Published // Description: Returns the bounding volume type set with // set_bounds_type(). //////////////////////////////////////////////////////////////////// INLINE BoundingVolume::BoundsType Geom:: get_bounds_type() const { CDReader cdata(_cycler); return cdata->_bounds_type; } //////////////////////////////////////////////////////////////////// // Function: Geom::set_bounds // Access: Published // Description: Resets the bounding volume so that it is the // indicated volume. When it is explicitly set, the // bounding volume will no longer be automatically // computed; call clear_bounds() if you would like to // return the bounding volume to its default behavior. // // Don't call this in a downstream thread unless you // don't mind it blowing away other changes you might // have recently made in an upstream thread. //////////////////////////////////////////////////////////////////// INLINE void Geom:: set_bounds(const BoundingVolume *volume) { CDWriter cdata(_cycler, true); if (volume == NULL) { cdata->_user_bounds = NULL; } else { cdata->_user_bounds = volume->make_copy(); } } //////////////////////////////////////////////////////////////////// // Function: Geom::clear_bounds // Access: Published // Description: Reverses the effect of a previous call to // set_bounds(), and allows the bounding volume to be // automatically computed once more based on the // vertices. // // Don't call this in a downstream thread unless you // don't mind it blowing away other changes you might // have recently made in an upstream thread. //////////////////////////////////////////////////////////////////// INLINE void Geom:: clear_bounds() { CDWriter cdata(_cycler, true); cdata->_user_bounds = NULL; mark_internal_bounds_stale(cdata); } //////////////////////////////////////////////////////////////////// // Function: Geom::calc_tight_bounds // Access: Public // Description: Expands min_point and max_point to include all of the // vertices in the Geom, if any. found_any is set true // if any points are found. It is the caller's // responsibility to initialize min_point, max_point, // and found_any before calling this function. // // This version of the method allows the Geom to specify // an alternate vertex data table (for instance, if the // vertex data has already been munged), and also allows // the result to be computed in any coordinate space by // specifying a transform matrix. //////////////////////////////////////////////////////////////////// INLINE void Geom:: 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 { CDReader cdata(_cycler, current_thread); do_calc_tight_bounds(min_point, max_point, found_any, vertex_data, got_mat, mat, InternalName::get_vertex(), cdata, current_thread); } //////////////////////////////////////////////////////////////////// // Function: Geom::calc_tight_bounds // Access: Public, Virtual // Description: Expands min_point and max_point to include all of the // vertices in the Geom, if any. found_any is set true // if any points are found. It is the caller's // responsibility to initialize min_point, max_point, // and found_any before calling this function. // // This version of the method assumes the Geom will use // its own vertex data, and the results are computed in // the Geom's own coordinate space. //////////////////////////////////////////////////////////////////// INLINE void Geom:: calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, Thread *current_thread) const { calc_tight_bounds(min_point, max_point, found_any, get_vertex_data(current_thread), false, LMatrix4f::ident_mat(), current_thread); } //////////////////////////////////////////////////////////////////// // Function: Geom::calc_tight_bounds // Access: Public // Description: Similar to calc_tight_bounds(), for UV coordinates or // other named columns. //////////////////////////////////////////////////////////////////// INLINE void Geom:: calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, const GeomVertexData *vertex_data, bool got_mat, const LMatrix4f &mat, const InternalName *column_name, Thread *current_thread) const { CDReader cdata(_cycler, current_thread); do_calc_tight_bounds(min_point, max_point, found_any, vertex_data, got_mat, mat, column_name, cdata, current_thread); } //////////////////////////////////////////////////////////////////// // Function: Geom::mark_internal_bounds_stale // Access: Private // Description: Should be called to mark the internal bounding // volume stale, so that recompute_internal_bounds() // will be called when the bounding volume is next // requested. //////////////////////////////////////////////////////////////////// INLINE void Geom:: mark_internal_bounds_stale(CData *cdata) { cdata->_internal_bounds_stale = true; } //////////////////////////////////////////////////////////////////// // Function: Geom::CDataCache::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE Geom::CDataCache:: CDataCache() : _source(NULL), _geom_result(NULL), _data_result(NULL) { } //////////////////////////////////////////////////////////////////// // Function: Geom::CDataCache::Copy Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE Geom::CDataCache:: CDataCache(const Geom::CDataCache ©) : _source(copy._source), _geom_result(copy._geom_result), _data_result(copy._data_result) { if (_geom_result != _source && _geom_result != (Geom *)NULL) { _geom_result->ref(); } } //////////////////////////////////////////////////////////////////// // Function: Geom::CDataCache::set_result // Access: Public // Description: Stores the geom_result and data_result on the cache, // upping and/or dropping the reference count // appropriately. //////////////////////////////////////////////////////////////////// INLINE void Geom::CDataCache:: set_result(const Geom *geom_result, const GeomVertexData *data_result) { if (geom_result != _geom_result) { if (_geom_result != _source && _geom_result != (Geom *)NULL) { unref_delete(_geom_result); } _geom_result = geom_result; if (_geom_result != _source && _geom_result != (Geom *)NULL) { _geom_result->ref(); } } _data_result = data_result; } //////////////////////////////////////////////////////////////////// // Function: Geom::CacheKey::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE Geom::CacheKey:: CacheKey(const GeomVertexData *source_data, const GeomMunger *modifier) : _source_data(source_data), _modifier(modifier) { } //////////////////////////////////////////////////////////////////// // Function: Geom::CacheKey::operator < // Access: Public // Description: Provides a unique ordering within the map. //////////////////////////////////////////////////////////////////// INLINE bool Geom::CacheKey:: operator < (const CacheKey &other) const { if (_modifier != other._modifier) { int compare = _modifier->geom_compare_to(*other._modifier); if (compare != 0) { return (compare < 0); } } if (_source_data != other._source_data) { return (_source_data < other._source_data); } return 0; } //////////////////////////////////////////////////////////////////// // Function: Geom::CacheEntry::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE Geom::CacheEntry:: CacheEntry(Geom *source, const GeomVertexData *source_data, const GeomMunger *modifier) : _source(source), _key(source_data, modifier) { } //////////////////////////////////////////////////////////////////// // Function: Geom::CData::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE Geom::CData:: CData() : _primitive_type(PT_none), _shade_model(SM_uniform), _geom_rendering(0), _usage_hint(UH_unspecified), _got_usage_hint(false), _nested_vertices(0), _internal_bounds_stale(true), _bounds_type(BoundingVolume::BT_default) { } //////////////////////////////////////////////////////////////////// // Function: Geom::CData::Copy Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE Geom::CData:: CData(const Geom::CData ©) : _data(copy._data), _primitives(copy._primitives), _primitive_type(copy._primitive_type), _shade_model(copy._shade_model), _geom_rendering(copy._geom_rendering), _usage_hint(copy._usage_hint), _got_usage_hint(copy._got_usage_hint), _modified(copy._modified), _internal_bounds(copy._internal_bounds), _nested_vertices(copy._nested_vertices), _internal_bounds_stale(copy._internal_bounds_stale), _bounds_type(copy._bounds_type), _user_bounds(copy._user_bounds) { } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE GeomPipelineReader:: GeomPipelineReader(const Geom *object, Thread *current_thread) : _object(object), _current_thread(current_thread), _cdata(object->_cycler.read_unlocked(current_thread)) { #ifdef _DEBUG nassertv(_object->test_ref_count_nonzero()); #endif // _DEBUG #ifdef DO_PIPELINING _cdata->ref(); #endif // DO_PIPELINING } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::Copy Constructor // Access: Private // Description: Don't attempt to copy these objects. //////////////////////////////////////////////////////////////////// INLINE GeomPipelineReader:: GeomPipelineReader(const GeomPipelineReader &) { nassertv(false); } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::Copy Assignment Operator // Access: Private // Description: Don't attempt to copy these objects. //////////////////////////////////////////////////////////////////// INLINE void GeomPipelineReader:: operator = (const GeomPipelineReader &) { nassertv(false); } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::Destructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE GeomPipelineReader:: ~GeomPipelineReader() { #ifdef _DEBUG nassertv(_object->test_ref_count_nonzero()); #endif // _DEBUG // _object->_cycler.release_read(_cdata); #ifdef DO_PIPELINING unref_delete((CycleData *)_cdata); #endif // DO_PIPELINING #ifdef _DEBUG _object = NULL; _cdata = NULL; #endif // _DEBUG } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::get_object // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE const Geom *GeomPipelineReader:: get_object() const { return _object; } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::get_current_thread // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE Thread *GeomPipelineReader:: get_current_thread() const { return _current_thread; } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::get_primitive_type // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE GeomPipelineReader::PrimitiveType GeomPipelineReader:: get_primitive_type() const { return _cdata->_primitive_type; } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::get_shade_model // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE GeomPipelineReader::ShadeModel GeomPipelineReader:: get_shade_model() const { return _cdata->_shade_model; } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::get_geom_rendering // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE int GeomPipelineReader:: get_geom_rendering() const { return _cdata->_geom_rendering; } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::get_usage_hint // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE GeomPipelineReader::UsageHint GeomPipelineReader:: get_usage_hint() const { nassertr(_cdata->_got_usage_hint, UH_static); return _cdata->_usage_hint; } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::get_vertex_data // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE CPT(GeomVertexData) GeomPipelineReader:: get_vertex_data() const { return _cdata->_data.get_read_pointer(); } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::get_num_primitives // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE int GeomPipelineReader:: get_num_primitives() const { return _cdata->_primitives.size(); } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::get_primitive // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE CPT(GeomPrimitive) GeomPipelineReader:: get_primitive(int i) const { nassertr(i >= 0 && i < (int)_cdata->_primitives.size(), NULL); return _cdata->_primitives[i].get_read_pointer(); } //////////////////////////////////////////////////////////////////// // Function: GeomPipelineReader::get_modified // Access: Public // Description: //////////////////////////////////////////////////////////////////// INLINE UpdateSeq GeomPipelineReader:: get_modified() const { return _cdata->_modified; } INLINE ostream & operator << (ostream &out, const Geom &obj) { obj.output(out); return out; }