From cf01ef9cd6e70355d64dcc5e68b5bd69bfaac202 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sun, 15 Jan 2006 06:34:33 +0000 Subject: [PATCH] add NodePath::find_material(), find_all_texcoords(), etc. Make Material be directly modifiable. --- panda/src/distort/projectionScreen.h | 2 +- panda/src/dxgsg8/dxGeomMunger8.cxx | 2 +- panda/src/dxgsg9/dxGeomMunger9.cxx | 2 +- panda/src/egg2pg/eggLoader.cxx | 3 +- panda/src/egg2pg/eggRenderState.cxx | 4 +- panda/src/gobj/geomVertexArrayFormat.cxx | 22 +- panda/src/gobj/geomVertexArrayFormat.h | 22 +- panda/src/gobj/geomVertexColumn.I | 8 +- panda/src/gobj/geomVertexColumn.h | 10 +- panda/src/gobj/geomVertexData.cxx | 2 +- panda/src/gobj/geomVertexData.h | 2 +- panda/src/gobj/internalName.cxx | 23 +- panda/src/gobj/internalName.h | 1 + panda/src/gobj/material.I | 4 +- panda/src/gobj/material.cxx | 26 +- panda/src/gobj/material.h | 5 +- panda/src/gobj/materialPool.I | 13 +- panda/src/gobj/materialPool.cxx | 32 +- panda/src/gobj/materialPool.h | 20 +- panda/src/pgraph/Sources.pp | 6 + panda/src/pgraph/cullableObject.cxx | 6 +- panda/src/pgraph/geomNode.cxx | 2 +- panda/src/pgraph/geomTransformer.cxx | 4 +- panda/src/pgraph/geomTransformer.h | 6 +- panda/src/pgraph/internalNameCollection.I | 27 ++ panda/src/pgraph/internalNameCollection.cxx | 263 +++++++++++++++++ panda/src/pgraph/internalNameCollection.h | 66 +++++ panda/src/pgraph/materialAttrib.I | 2 +- panda/src/pgraph/materialAttrib.cxx | 2 +- panda/src/pgraph/materialAttrib.h | 8 +- panda/src/pgraph/materialCollection.I | 27 ++ panda/src/pgraph/materialCollection.cxx | 282 ++++++++++++++++++ panda/src/pgraph/materialCollection.h | 68 +++++ panda/src/pgraph/nodePath.cxx | 305 +++++++++++++++++++- panda/src/pgraph/nodePath.h | 19 ++ panda/src/pgraph/pgraph_composite3.cxx | 2 + panda/src/putil/bam.h | 3 +- 37 files changed, 1198 insertions(+), 103 deletions(-) create mode 100644 panda/src/pgraph/internalNameCollection.I create mode 100644 panda/src/pgraph/internalNameCollection.cxx create mode 100644 panda/src/pgraph/internalNameCollection.h create mode 100644 panda/src/pgraph/materialCollection.I create mode 100644 panda/src/pgraph/materialCollection.cxx create mode 100644 panda/src/pgraph/materialCollection.h diff --git a/panda/src/distort/projectionScreen.h b/panda/src/distort/projectionScreen.h index a9bf9ad8f4..3aa3f23d57 100644 --- a/panda/src/distort/projectionScreen.h +++ b/panda/src/distort/projectionScreen.h @@ -124,7 +124,7 @@ private: NodePath _projector; PT(LensNode) _projector_node; - CPT(InternalName) _texcoord_name; + PT(InternalName) _texcoord_name; bool _invert_uvs; bool _vignette_on; Colorf _vignette_color; diff --git a/panda/src/dxgsg8/dxGeomMunger8.cxx b/panda/src/dxgsg8/dxGeomMunger8.cxx index de3cf0495b..35f16eeb7c 100644 --- a/panda/src/dxgsg8/dxGeomMunger8.cxx +++ b/panda/src/dxgsg8/dxGeomMunger8.cxx @@ -118,7 +118,7 @@ munge_format_impl(const GeomVertexFormat *orig, for (int i = 0; i < num_stages; ++i) { TextureStage *stage = _texture->get_on_stage(i); - const InternalName *name = stage->get_texcoord_name(); + InternalName *name = stage->get_texcoord_name(); if (used_stages.insert(name).second) { // This is the first time we've encountered this texcoord name. const GeomVertexColumn *texcoord_type = orig->get_column(name); diff --git a/panda/src/dxgsg9/dxGeomMunger9.cxx b/panda/src/dxgsg9/dxGeomMunger9.cxx index 6339e4ef7b..a2af7350a4 100755 --- a/panda/src/dxgsg9/dxGeomMunger9.cxx +++ b/panda/src/dxgsg9/dxGeomMunger9.cxx @@ -118,7 +118,7 @@ munge_format_impl(const GeomVertexFormat *orig, for (int i = 0; i < num_stages; ++i) { TextureStage *stage = _texture->get_on_stage(i); - const InternalName *name = stage->get_texcoord_name(); + InternalName *name = stage->get_texcoord_name(); if (used_stages.insert(name).second) { // This is the first time we've encountered this texcoord name. const GeomVertexColumn *texcoord_type = orig->get_column(name); diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index 047bdf64f5..95b97cb832 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -2156,8 +2156,7 @@ record_morph(GeomVertexArrayFormat *array_format, CharacterMaker *character_maker, const string &morph_name, InternalName *column_name, int num_components) { - CPT(InternalName) slider_name = InternalName::make(morph_name); - CPT(InternalName) delta_name = + PT(InternalName) delta_name = InternalName::get_morph(column_name, morph_name); if (!array_format->has_column(delta_name)) { array_format->add_column diff --git a/panda/src/egg2pg/eggRenderState.cxx b/panda/src/egg2pg/eggRenderState.cxx index 9f25eff587..c86d93e837 100644 --- a/panda/src/egg2pg/eggRenderState.cxx +++ b/panda/src/egg2pg/eggRenderState.cxx @@ -450,7 +450,7 @@ get_material_attrib(const EggMaterial *egg_mat, bool bface) { // Ok, this is the first time we've seen this particular // EggMaterial. Create a new Material that matches it. - PT(Material) mat = new Material; + PT(Material) mat = new Material(egg_mat->get_name()); if (egg_mat->has_diff()) { mat->set_diffuse(egg_mat->get_diff()); // By default, ambient is the same as diffuse, if diffuse is @@ -476,7 +476,7 @@ get_material_attrib(const EggMaterial *egg_mat, bool bface) { mat->set_twoside(bface); // Now get a global Material pointer, shared with other models. - const Material *shared_mat = MaterialPool::get_material(mat); + Material *shared_mat = MaterialPool::get_material(mat); // And create a MaterialAttrib for this Material. CPT(RenderAttrib) mt = MaterialAttrib::make(shared_mat); diff --git a/panda/src/gobj/geomVertexArrayFormat.cxx b/panda/src/gobj/geomVertexArrayFormat.cxx index b2b48cfc63..181e5faef8 100644 --- a/panda/src/gobj/geomVertexArrayFormat.cxx +++ b/panda/src/gobj/geomVertexArrayFormat.cxx @@ -49,7 +49,7 @@ GeomVertexArrayFormat() : // Description: //////////////////////////////////////////////////////////////////// GeomVertexArrayFormat:: -GeomVertexArrayFormat(const InternalName *name0, int num_components0, +GeomVertexArrayFormat(InternalName *name0, int num_components0, GeomVertexArrayFormat::NumericType numeric_type0, GeomVertexArrayFormat::Contents contents0) : _is_registered(false), @@ -67,10 +67,10 @@ GeomVertexArrayFormat(const InternalName *name0, int num_components0, // Description: //////////////////////////////////////////////////////////////////// GeomVertexArrayFormat:: -GeomVertexArrayFormat(const InternalName *name0, int num_components0, +GeomVertexArrayFormat(InternalName *name0, int num_components0, GeomVertexArrayFormat::NumericType numeric_type0, GeomVertexArrayFormat::Contents contents0, - const InternalName *name1, int num_components1, + InternalName *name1, int num_components1, GeomVertexArrayFormat::NumericType numeric_type1, GeomVertexArrayFormat::Contents contents1) : _is_registered(false), @@ -89,13 +89,13 @@ GeomVertexArrayFormat(const InternalName *name0, int num_components0, // Description: //////////////////////////////////////////////////////////////////// GeomVertexArrayFormat:: -GeomVertexArrayFormat(const InternalName *name0, int num_components0, +GeomVertexArrayFormat(InternalName *name0, int num_components0, GeomVertexArrayFormat::NumericType numeric_type0, GeomVertexArrayFormat::Contents contents0, - const InternalName *name1, int num_components1, + InternalName *name1, int num_components1, GeomVertexArrayFormat::NumericType numeric_type1, GeomVertexArrayFormat::Contents contents1, - const InternalName *name2, int num_components2, + InternalName *name2, int num_components2, GeomVertexArrayFormat::NumericType numeric_type2, GeomVertexArrayFormat::Contents contents2) : _is_registered(false), @@ -115,16 +115,16 @@ GeomVertexArrayFormat(const InternalName *name0, int num_components0, // Description: //////////////////////////////////////////////////////////////////// GeomVertexArrayFormat:: -GeomVertexArrayFormat(const InternalName *name0, int num_components0, +GeomVertexArrayFormat(InternalName *name0, int num_components0, GeomVertexArrayFormat::NumericType numeric_type0, GeomVertexArrayFormat::Contents contents0, - const InternalName *name1, int num_components1, + InternalName *name1, int num_components1, GeomVertexArrayFormat::NumericType numeric_type1, GeomVertexArrayFormat::Contents contents1, - const InternalName *name2, int num_components2, + InternalName *name2, int num_components2, GeomVertexArrayFormat::NumericType numeric_type2, GeomVertexArrayFormat::Contents contents2, - const InternalName *name3, int num_components3, + InternalName *name3, int num_components3, GeomVertexArrayFormat::NumericType numeric_type3, GeomVertexArrayFormat::Contents contents3) : _is_registered(false), @@ -208,7 +208,7 @@ GeomVertexArrayFormat:: // type. //////////////////////////////////////////////////////////////////// int GeomVertexArrayFormat:: -add_column(const InternalName *name, int num_components, +add_column(InternalName *name, int num_components, GeomVertexArrayFormat::NumericType numeric_type, GeomVertexArrayFormat::Contents contents, int start) { if (start < 0) { diff --git a/panda/src/gobj/geomVertexArrayFormat.h b/panda/src/gobj/geomVertexArrayFormat.h index 1560e22fad..f6bda642d4 100644 --- a/panda/src/gobj/geomVertexArrayFormat.h +++ b/panda/src/gobj/geomVertexArrayFormat.h @@ -57,25 +57,25 @@ class EXPCL_PANDA GeomVertexArrayFormat : public TypedWritableReferenceCount, pu PUBLISHED: GeomVertexArrayFormat(); GeomVertexArrayFormat(const GeomVertexArrayFormat ©); - GeomVertexArrayFormat(const InternalName *name0, int num_components0, + GeomVertexArrayFormat(InternalName *name0, int num_components0, NumericType numeric_type0, Contents contents0); - GeomVertexArrayFormat(const InternalName *name0, int num_components0, + GeomVertexArrayFormat(InternalName *name0, int num_components0, NumericType numeric_type0, Contents contents0, - const InternalName *name1, int num_components1, + InternalName *name1, int num_components1, NumericType numeric_type1, Contents contents1); - GeomVertexArrayFormat(const InternalName *name0, int num_components0, + GeomVertexArrayFormat(InternalName *name0, int num_components0, NumericType numeric_type0, Contents contents0, - const InternalName *name1, int num_components1, + InternalName *name1, int num_components1, NumericType numeric_type1, Contents contents1, - const InternalName *name2, int num_components2, + InternalName *name2, int num_components2, NumericType numeric_type2, Contents contents2); - GeomVertexArrayFormat(const InternalName *name0, int num_components0, + GeomVertexArrayFormat(InternalName *name0, int num_components0, NumericType numeric_type0, Contents contents0, - const InternalName *name1, int num_components1, + InternalName *name1, int num_components1, NumericType numeric_type1, Contents contents1, - const InternalName *name2, int num_components2, + InternalName *name2, int num_components2, NumericType numeric_type2, Contents contents2, - const InternalName *name3, int num_components3, + InternalName *name3, int num_components3, NumericType numeric_type3, Contents contents3); void operator = (const GeomVertexArrayFormat ©); ~GeomVertexArrayFormat(); @@ -89,7 +89,7 @@ PUBLISHED: INLINE int get_total_bytes() const; INLINE int get_pad_to() const; - int add_column(const InternalName *name, int num_components, + int add_column(InternalName *name, int num_components, NumericType numeric_type, Contents contents, int start = -1); int add_column(const GeomVertexColumn &column); diff --git a/panda/src/gobj/geomVertexColumn.I b/panda/src/gobj/geomVertexColumn.I index 73034e28d2..5048cbfb0d 100644 --- a/panda/src/gobj/geomVertexColumn.I +++ b/panda/src/gobj/geomVertexColumn.I @@ -35,9 +35,9 @@ GeomVertexColumn() : // Description: //////////////////////////////////////////////////////////////////// INLINE GeomVertexColumn:: -GeomVertexColumn(const InternalName *name, int num_components, - NumericType numeric_type, Contents contents, - int start) : +GeomVertexColumn(InternalName *name, int num_components, + NumericType numeric_type, Contents contents, + int start) : _name(name), _num_components(num_components), _numeric_type(numeric_type), @@ -84,7 +84,7 @@ INLINE GeomVertexColumn:: // system-defined field types. Only the system-defined // field types are used for the actual rendering. //////////////////////////////////////////////////////////////////// -INLINE const InternalName *GeomVertexColumn:: +INLINE InternalName *GeomVertexColumn:: get_name() const { return _name; } diff --git a/panda/src/gobj/geomVertexColumn.h b/panda/src/gobj/geomVertexColumn.h index 65e8e18638..d65ce5da47 100644 --- a/panda/src/gobj/geomVertexColumn.h +++ b/panda/src/gobj/geomVertexColumn.h @@ -46,14 +46,14 @@ PUBLISHED: private: INLINE GeomVertexColumn(); PUBLISHED: - INLINE GeomVertexColumn(const InternalName *name, int num_components, - NumericType numeric_type, Contents contents, - int start); + INLINE GeomVertexColumn(InternalName *name, int num_components, + NumericType numeric_type, Contents contents, + int start); INLINE GeomVertexColumn(const GeomVertexColumn ©); void operator = (const GeomVertexColumn ©); INLINE ~GeomVertexColumn(); - INLINE const InternalName *get_name() const; + INLINE InternalName *get_name() const; INLINE int get_num_components() const; INLINE int get_num_values() const; INLINE NumericType get_numeric_type() const; @@ -89,7 +89,7 @@ public: void fillin(DatagramIterator &scan, BamReader *manager); private: - CPT(InternalName) _name; + PT(InternalName) _name; int _num_components; int _num_values; NumericType _numeric_type; diff --git a/panda/src/gobj/geomVertexData.cxx b/panda/src/gobj/geomVertexData.cxx index f52acb6176..c3b55483b3 100644 --- a/panda/src/gobj/geomVertexData.cxx +++ b/panda/src/gobj/geomVertexData.cxx @@ -963,7 +963,7 @@ bytewise_copy(unsigned char *to, int to_stride, // anything else. //////////////////////////////////////////////////////////////////// PT(GeomVertexData) GeomVertexData:: -replace_column(const InternalName *name, int num_components, +replace_column(InternalName *name, int num_components, GeomVertexData::NumericType numeric_type, GeomVertexData::Contents contents) const { PT(GeomVertexFormat) new_format = new GeomVertexFormat(*_format); diff --git a/panda/src/gobj/geomVertexData.h b/panda/src/gobj/geomVertexData.h index 5bcad8cf09..209df10d17 100644 --- a/panda/src/gobj/geomVertexData.h +++ b/panda/src/gobj/geomVertexData.h @@ -136,7 +136,7 @@ PUBLISHED: CPT(GeomVertexData) animate_vertices() const; PT(GeomVertexData) - replace_column(const InternalName *name, int num_components, + replace_column(InternalName *name, int num_components, NumericType numeric_type, Contents contents) const; void output(ostream &out) const; diff --git a/panda/src/gobj/internalName.cxx b/panda/src/gobj/internalName.cxx index 31e8c8f28c..87478d5f58 100644 --- a/panda/src/gobj/internalName.cxx +++ b/panda/src/gobj/internalName.cxx @@ -174,6 +174,24 @@ get_ancestor(int n) const { } } +//////////////////////////////////////////////////////////////////// +// Function: InternalName::get_top +// Access: Published +// Description: Returns the oldest ancestor in the InternalName's +// chain, not counting the root. This will be the first +// name in the string, e.g. "texcoord.foo.bar" will +// return the InternalName "texcoord". +//////////////////////////////////////////////////////////////////// +const InternalName *InternalName:: +get_top() const { + test_ref_count_integrity(); + + if (_parent != (InternalName *)NULL && _parent != get_root()) { + return _parent->get_top(); + } + return this; +} + //////////////////////////////////////////////////////////////////// // Function: InternalName::get_net_basename // Access: Published @@ -184,7 +202,10 @@ get_ancestor(int n) const { //////////////////////////////////////////////////////////////////// string InternalName:: get_net_basename(int n) const { - if (n == 0) { + if (n < 0) { + return ""; + + } else if (n == 0) { return _basename; } else if (_parent != (InternalName *)NULL && _parent != get_root()) { diff --git a/panda/src/gobj/internalName.h b/panda/src/gobj/internalName.h index c60f4ac145..cd84425547 100644 --- a/panda/src/gobj/internalName.h +++ b/panda/src/gobj/internalName.h @@ -57,6 +57,7 @@ PUBLISHED: int find_ancestor(const string &basename) const; const InternalName *get_ancestor(int n) const; + const InternalName *get_top() const; string get_net_basename(int n) const; void output(ostream &out) const; diff --git a/panda/src/gobj/material.I b/panda/src/gobj/material.I index 40ff5975ff..31c425c757 100644 --- a/panda/src/gobj/material.I +++ b/panda/src/gobj/material.I @@ -23,7 +23,7 @@ // Description: //////////////////////////////////////////////////////////////////// INLINE Material:: -Material() { +Material(const string &name) : Namable(name) { _ambient.set(1.0f, 1.0f, 1.0f, 1.0f); _diffuse.set(1.0f, 1.0f, 1.0f, 1.0f); _specular.set(0.0f, 0.0f, 0.0f, 1.0f); @@ -38,7 +38,7 @@ Material() { // Description: //////////////////////////////////////////////////////////////////// INLINE Material:: -Material(const Material ©) { +Material(const Material ©) : Namable(copy) { operator = (copy); } diff --git a/panda/src/gobj/material.cxx b/panda/src/gobj/material.cxx index de892b24e0..0ca7c86ed5 100644 --- a/panda/src/gobj/material.cxx +++ b/panda/src/gobj/material.cxx @@ -33,6 +33,7 @@ TypeHandle Material::_type_handle; //////////////////////////////////////////////////////////////////// void Material:: operator = (const Material ©) { + Namable::operator = (copy); _ambient = copy._ambient; _diffuse = copy._diffuse; _specular = copy._specular; @@ -148,7 +149,7 @@ compare_to(const Material &other) const { return get_shininess() < other.get_shininess() ? -1 : 1; } - return 0; + return strcmp(get_name().c_str(), other.get_name().c_str()); } //////////////////////////////////////////////////////////////////// @@ -158,7 +159,7 @@ compare_to(const Material &other) const { //////////////////////////////////////////////////////////////////// void Material:: output(ostream &out) const { - out << "material"; + out << "Material " << get_name(); if (has_ambient()) { out << " a(" << get_ambient() << ")"; } @@ -183,21 +184,22 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// void Material:: write(ostream &out, int indent_level) const { + indent(out, indent_level) << "Material " << get_name() << "\n"; if (has_ambient()) { - indent(out, indent_level) << "ambient = " << get_ambient() << "\n"; + indent(out, indent_level + 2) << "ambient = " << get_ambient() << "\n"; } if (has_diffuse()) { - indent(out, indent_level) << "diffuse = " << get_diffuse() << "\n"; + indent(out, indent_level + 2) << "diffuse = " << get_diffuse() << "\n"; } if (has_specular()) { - indent(out, indent_level) << "specular = " << get_specular() << "\n"; + indent(out, indent_level + 2) << "specular = " << get_specular() << "\n"; } if (has_emission()) { - indent(out, indent_level) << "emission = " << get_emission() << "\n"; + indent(out, indent_level + 2) << "emission = " << get_emission() << "\n"; } - indent(out, indent_level) << "shininess = " << get_shininess() << "\n"; - indent(out, indent_level) << "local = " << get_local() << "\n"; - indent(out, indent_level) << "twoside = " << get_twoside() << "\n"; + indent(out, indent_level + 2) << "shininess = " << get_shininess() << "\n"; + indent(out, indent_level + 2) << "local = " << get_local() << "\n"; + indent(out, indent_level + 2) << "twoside = " << get_twoside() << "\n"; } @@ -220,6 +222,7 @@ register_with_read_factory() { //////////////////////////////////////////////////////////////////// void Material:: write_datagram(BamWriter *manager, Datagram &me) { + me.add_string(get_name()); _ambient.write_datagram(me); _diffuse.write_datagram(me); _specular.write_datagram(me); @@ -253,7 +256,10 @@ make_Material(const FactoryParams ¶ms) { // place //////////////////////////////////////////////////////////////////// void Material:: -fillin(DatagramIterator& scan, BamReader* manager) { +fillin(DatagramIterator &scan, BamReader *manager) { + if (manager->get_file_minor_ver() >= 6) { + set_name(scan.get_string()); + } _ambient.read_datagram(scan); _diffuse.read_datagram(scan); _specular.read_datagram(scan); diff --git a/panda/src/gobj/material.h b/panda/src/gobj/material.h index f6fb2dcb38..a8464f2a75 100644 --- a/panda/src/gobj/material.h +++ b/panda/src/gobj/material.h @@ -22,6 +22,7 @@ #include "pandabase.h" #include "typedWritableReferenceCount.h" +#include "namable.h" #include "luse.h" class FactoryParams; @@ -32,9 +33,9 @@ class FactoryParams; // lighting. A material is only necessary if lighting // is to be enabled; otherwise, the material isn't used. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA Material : public TypedWritableReferenceCount { +class EXPCL_PANDA Material : public TypedWritableReferenceCount, public Namable { PUBLISHED: - INLINE Material(); + INLINE Material(const string &name = ""); INLINE Material(const Material ©); void operator = (const Material ©); INLINE ~Material(); diff --git a/panda/src/gobj/materialPool.I b/panda/src/gobj/materialPool.I index 1c1ce60588..1e2ec541a7 100644 --- a/panda/src/gobj/materialPool.I +++ b/panda/src/gobj/materialPool.I @@ -20,18 +20,15 @@ //////////////////////////////////////////////////////////////////// // Function: MaterialPool::get_material // Access: Public, Static -// Description: Returns a const Material pointer that represents the +// Description: Returns a Material pointer that represents the // same material described by temp, except that it is a // shared pointer. // // Each call to get_material() passing an equivalent // Material pointer will return the same shared pointer. // -// This shared pointer must not be further modified. -// Doing so will (a) cause global changes to other -// objects that may share this material, and (b) damage -// the sorted container that stores these things, so -// that future pointers may not be properly shared. +// If you modify the shared pointer, it will +// automatically disassociate it from the pool. // // Also, the return value may be a different pointer // than that passed in, or it may be the same pointer. @@ -40,8 +37,8 @@ // again (like any other PointerTo, it will be freed // when the last reference count is removed). //////////////////////////////////////////////////////////////////// -INLINE const Material *MaterialPool:: -get_material(const CPT(Material) &temp) { +INLINE Material *MaterialPool:: +get_material(Material *temp) { return get_ptr()->ns_get_material(temp); } diff --git a/panda/src/gobj/materialPool.cxx b/panda/src/gobj/materialPool.cxx index fe6719e816..38578fabf4 100644 --- a/panda/src/gobj/materialPool.cxx +++ b/panda/src/gobj/materialPool.cxx @@ -39,10 +39,20 @@ write(ostream &out) { // Access: Public // Description: The nonstatic implementation of get_material(). //////////////////////////////////////////////////////////////////// -const Material *MaterialPool:: -ns_get_material(const CPT(Material) &temp) { - Materials::iterator mi = _materials.insert(temp).first; - return (*mi); +Material *MaterialPool:: +ns_get_material(Material *temp) { + CPT(Material) cpttemp = temp; + Materials::iterator mi = _materials.find(cpttemp); + if (mi == _materials.end()) { + mi = _materials.insert(Materials::value_type(new Material(*temp), temp)).first; + } else { + if (*(*mi).first != *(*mi).second) { + // The pointer no longer matches its original value. Save a new + // one. + (*mi).second = temp; + } + } + return (*mi).second; } //////////////////////////////////////////////////////////////////// @@ -57,11 +67,12 @@ ns_garbage_collect() { Materials::iterator mi; for (mi = _materials.begin(); mi != _materials.end(); ++mi) { - const Material *mat = (*mi); - if (mat->get_ref_count() == 1) { + const Material *mat1 = (*mi).first; + Material *mat2 = (*mi).second; + if ((*mat1) != (*mat2) || mat2->get_ref_count() == 1) { if (gobj_cat.is_debug()) { gobj_cat.debug() - << "Releasing " << *mat << "\n"; + << "Releasing " << *mat1 << "\n"; } ++num_released; } else { @@ -83,9 +94,10 @@ ns_list_contents(ostream &out) const { out << _materials.size() << " materials:\n"; Materials::const_iterator mi; for (mi = _materials.begin(); mi != _materials.end(); ++mi) { - const Material *mat = (*mi); - out << " " << *mat - << " (count = " << mat->get_ref_count() << ")\n"; + const Material *mat1 = (*mi).first; + Material *mat2 = (*mi).second; + out << " " << *mat1 + << " (count = " << mat2->get_ref_count() << ")\n"; } } diff --git a/panda/src/gobj/materialPool.h b/panda/src/gobj/materialPool.h index 8002144395..44d2cf9959 100644 --- a/panda/src/gobj/materialPool.h +++ b/panda/src/gobj/materialPool.h @@ -40,15 +40,14 @@ // The idea is to create a temporary Material // representing the lighting state you want to apply, // then call get_material(), passing in your temporary -// Material. The return value will be a constant -// Material object that should be modified (because it -// is now shared among many different geometries), that -// is the same as the temporary Material pointer you -// supplied but may be a different pointer. +// Material. The return value will either be a new +// Material object, or it may be the the same object you +// supplied; in either case, it will have the same +// value. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA MaterialPool { PUBLISHED: - INLINE static const Material *get_material(const CPT(Material) &temp); + INLINE static Material *get_material(Material *temp); INLINE static int garbage_collect(); INLINE static void list_contents(ostream &out); static void write(ostream &out); @@ -56,14 +55,19 @@ PUBLISHED: private: INLINE MaterialPool(); - const Material *ns_get_material(const CPT(Material) &temp); + Material *ns_get_material(Material *temp); int ns_garbage_collect(); void ns_list_contents(ostream &out) const; static MaterialPool *get_ptr(); static MaterialPool *_global_ptr; - typedef pset< CPT(Material), indirect_compare_to > Materials; + + // We store a map of CPT(Material) to PT(Material). These are two + // equivalent structures, but different pointers. The first pointer + // never leaves this class. If the second pointer changes value, + // we'll notice it and return a new one. + typedef pmap< CPT(Material), PT(Material), indirect_compare_to > Materials; Materials _materials; }; diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index af71397a6f..b8709e3eff 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -55,6 +55,7 @@ fogAttrib.I fogAttrib.h \ geomNode.I geomNode.h \ geomTransformer.I geomTransformer.h \ + internalNameCollection.I internalNameCollection.h \ lensNode.I lensNode.h \ light.I light.h \ lightAttrib.I lightAttrib.h \ @@ -67,6 +68,7 @@ loaderOptions.I loaderOptions.h \ lodNode.I lodNode.h \ materialAttrib.I materialAttrib.h \ + materialCollection.I materialCollection.h \ modelNode.I modelNode.h \ modelPool.I modelPool.h \ modelRoot.I modelRoot.h \ @@ -161,6 +163,7 @@ fogAttrib.cxx \ geomNode.cxx \ geomTransformer.cxx \ + internalNameCollection.cxx \ lensNode.cxx \ light.cxx \ lightAttrib.cxx \ @@ -173,6 +176,7 @@ loaderOptions.cxx \ lodNode.cxx \ materialAttrib.cxx \ + materialCollection.cxx \ modelNode.cxx \ modelPool.cxx \ modelRoot.cxx \ @@ -261,6 +265,7 @@ fogAttrib.I fogAttrib.h \ geomNode.I geomNode.h \ geomTransformer.I geomTransformer.h \ + internalNameCollection.I internalNameCollection.h \ lensNode.I lensNode.h \ light.I light.h \ lightAttrib.I lightAttrib.h \ @@ -273,6 +278,7 @@ loaderOptions.I loaderOptions.h \ lodNode.I lodNode.h \ materialAttrib.I materialAttrib.h \ + materialCollection.I materialCollection.h \ modelNode.I modelNode.h \ modelPool.I modelPool.h \ modelRoot.I modelRoot.h \ diff --git a/panda/src/pgraph/cullableObject.cxx b/panda/src/pgraph/cullableObject.cxx index f51dc395ca..0ebc967a65 100644 --- a/panda/src/pgraph/cullableObject.cxx +++ b/panda/src/pgraph/cullableObject.cxx @@ -526,10 +526,10 @@ munge_texcoord_light_vector(const CullTraverser *traverser) { // Determine the names of the tangent and binormal columns // associated with the stage's texcoord name. - CPT(InternalName) tangent_name = InternalName::get_tangent_name(source_name); - CPT(InternalName) binormal_name = InternalName::get_binormal_name(source_name); + PT(InternalName) tangent_name = InternalName::get_tangent_name(source_name); + PT(InternalName) binormal_name = InternalName::get_binormal_name(source_name); - CPT(InternalName) texcoord_name = stage->get_texcoord_name(); + PT(InternalName) texcoord_name = stage->get_texcoord_name(); if (_munged_data->has_column(tangent_name) && _munged_data->has_column(binormal_name)) { diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index 3917b92395..3a494da7c1 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -249,7 +249,7 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, int num_stages = tma->get_num_stages(); for (int i = 0; i < num_stages; i++) { TextureStage *stage = tma->get_stage(i); - const InternalName *name = stage->get_texcoord_name(); + InternalName *name = stage->get_texcoord_name(); if (get_name_count(name_count, name) > 1) { // We can't transform these texcoords, since the name is // used by more than one active stage. diff --git a/panda/src/pgraph/geomTransformer.cxx b/panda/src/pgraph/geomTransformer.cxx index 259b677f90..0fbca62f07 100644 --- a/panda/src/pgraph/geomTransformer.cxx +++ b/panda/src/pgraph/geomTransformer.cxx @@ -152,7 +152,7 @@ transform_vertices(GeomNode *node, const LMatrix4f &mat) { //////////////////////////////////////////////////////////////////// bool GeomTransformer:: transform_texcoords(Geom *geom, const InternalName *from_name, - const InternalName *to_name, const LMatrix4f &mat) { + InternalName *to_name, const LMatrix4f &mat) { PStatTimer timer(apply_texcoord_collector); nassertr(geom != (Geom *)NULL, false); @@ -212,7 +212,7 @@ transform_texcoords(Geom *geom, const InternalName *from_name, //////////////////////////////////////////////////////////////////// bool GeomTransformer:: transform_texcoords(GeomNode *node, const InternalName *from_name, - const InternalName *to_name, const LMatrix4f &mat) { + InternalName *to_name, const LMatrix4f &mat) { bool any_changed = false; GeomNode::CDWriter cdata(node->_cycler); diff --git a/panda/src/pgraph/geomTransformer.h b/panda/src/pgraph/geomTransformer.h index 21dea413e7..ea21b311c4 100644 --- a/panda/src/pgraph/geomTransformer.h +++ b/panda/src/pgraph/geomTransformer.h @@ -58,11 +58,9 @@ public: bool transform_vertices(GeomNode *node, const LMatrix4f &mat); bool transform_texcoords(Geom *geom, const InternalName *from_name, - const InternalName *to_name, - const LMatrix4f &mat); + InternalName *to_name, const LMatrix4f &mat); bool transform_texcoords(GeomNode *node, const InternalName *from_name, - const InternalName *to_name, - const LMatrix4f &mat); + InternalName *to_name, const LMatrix4f &mat); bool set_color(Geom *geom, const Colorf &color); bool set_color(GeomNode *node, const Colorf &color); diff --git a/panda/src/pgraph/internalNameCollection.I b/panda/src/pgraph/internalNameCollection.I new file mode 100644 index 0000000000..c004e2c562 --- /dev/null +++ b/panda/src/pgraph/internalNameCollection.I @@ -0,0 +1,27 @@ +// Filename: internalNameCollection.I +// Created by: drose (16Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE InternalNameCollection:: +~InternalNameCollection() { +} diff --git a/panda/src/pgraph/internalNameCollection.cxx b/panda/src/pgraph/internalNameCollection.cxx new file mode 100644 index 0000000000..43dc96ef54 --- /dev/null +++ b/panda/src/pgraph/internalNameCollection.cxx @@ -0,0 +1,263 @@ +// Filename: internalNameCollection.cxx +// Created by: drose (16Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#include "internalNameCollection.h" + +#include "indent.h" + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +InternalNameCollection:: +InternalNameCollection() { +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::Copy Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +InternalNameCollection:: +InternalNameCollection(const InternalNameCollection ©) : + _names(copy._names) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::Copy Assignment Operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void InternalNameCollection:: +operator = (const InternalNameCollection ©) { + _names = copy._names; +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::add_name +// Access: Published +// Description: Adds a new InternalName to the collection. +//////////////////////////////////////////////////////////////////// +void InternalNameCollection:: +add_name(InternalName *name) { + // If the pointer to our internal array is shared by any other + // InternalNameCollections, we have to copy the array now so we won't + // inadvertently modify any of our brethren InternalNameCollection + // objects. + + if (_names.get_ref_count() > 1) { + InternalNames old_names = _names; + _names = InternalNames::empty_array(0); + _names.v() = old_names.v(); + } + + _names.push_back(name); +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::remove_name +// Access: Published +// Description: Removes the indicated InternalName from the collection. +// Returns true if the name was removed, false if it was +// not a member of the collection. +//////////////////////////////////////////////////////////////////// +bool InternalNameCollection:: +remove_name(InternalName *name) { + int name_index = -1; + for (int i = 0; name_index == -1 && i < (int)_names.size(); i++) { + if (_names[i] == name) { + name_index = i; + } + } + + if (name_index == -1) { + // The indicated name was not a member of the collection. + return false; + } + + // If the pointer to our internal array is shared by any other + // InternalNameCollections, we have to copy the array now so we won't + // inadvertently modify any of our brethren InternalNameCollection + // objects. + + if (_names.get_ref_count() > 1) { + InternalNames old_names = _names; + _names = InternalNames::empty_array(0); + _names.v() = old_names.v(); + } + + _names.erase(_names.begin() + name_index); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::add_names_from +// Access: Published +// Description: Adds all the InternalNames indicated in the other +// collection to this name. The other names are simply +// appended to the end of the names in this list; +// duplicates are not automatically removed. +//////////////////////////////////////////////////////////////////// +void InternalNameCollection:: +add_names_from(const InternalNameCollection &other) { + int other_num_names = other.get_num_names(); + for (int i = 0; i < other_num_names; i++) { + add_name(other.get_name(i)); + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::remove_names_from +// Access: Published +// Description: Removes from this collection all of the InternalNames +// listed in the other collection. +//////////////////////////////////////////////////////////////////// +void InternalNameCollection:: +remove_names_from(const InternalNameCollection &other) { + InternalNames new_names; + int num_names = get_num_names(); + for (int i = 0; i < num_names; i++) { + PT(InternalName) name = get_name(i); + if (!other.has_name(name)) { + new_names.push_back(name); + } + } + _names = new_names; +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::remove_duplicate_names +// Access: Published +// Description: Removes any duplicate entries of the same InternalNames +// on this collection. If a InternalName appears multiple +// times, the first appearance is retained; subsequent +// appearances are removed. +//////////////////////////////////////////////////////////////////// +void InternalNameCollection:: +remove_duplicate_names() { + InternalNames new_names; + + int num_names = get_num_names(); + for (int i = 0; i < num_names; i++) { + PT(InternalName) name = get_name(i); + bool duplicated = false; + + for (int j = 0; j < i && !duplicated; j++) { + duplicated = (name == get_name(j)); + } + + if (!duplicated) { + new_names.push_back(name); + } + } + + _names = new_names; +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::has_name +// Access: Published +// Description: Returns true if the indicated InternalName appears in +// this collection, false otherwise. +//////////////////////////////////////////////////////////////////// +bool InternalNameCollection:: +has_name(InternalName *name) const { + for (int i = 0; i < get_num_names(); i++) { + if (name == get_name(i)) { + return true; + } + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::clear +// Access: Published +// Description: Removes all InternalNames from the collection. +//////////////////////////////////////////////////////////////////// +void InternalNameCollection:: +clear() { + _names.clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::get_num_names +// Access: Published +// Description: Returns the number of InternalNames in the collection. +//////////////////////////////////////////////////////////////////// +int InternalNameCollection:: +get_num_names() const { + return _names.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::get_name +// Access: Published +// Description: Returns the nth InternalName in the collection. +//////////////////////////////////////////////////////////////////// +InternalName *InternalNameCollection:: +get_name(int index) const { + nassertr(index >= 0 && index < (int)_names.size(), NULL); + + return _names[index]; +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::operator [] +// Access: Published +// Description: Returns the nth InternalName in the collection. This is +// the same as get_name(), but it may be a more +// convenient way to access it. +//////////////////////////////////////////////////////////////////// +InternalName *InternalNameCollection:: +operator [] (int index) const { + nassertr(index >= 0 && index < (int)_names.size(), NULL); + + return _names[index]; +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::output +// Access: Published +// Description: Writes a brief one-line description of the +// InternalNameCollection to the indicated output stream. +//////////////////////////////////////////////////////////////////// +void InternalNameCollection:: +output(ostream &out) const { + if (get_num_names() == 1) { + out << "1 InternalName"; + } else { + out << get_num_names() << " InternalNames"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: InternalNameCollection::write +// Access: Published +// Description: Writes a complete multi-line description of the +// InternalNameCollection to the indicated output stream. +//////////////////////////////////////////////////////////////////// +void InternalNameCollection:: +write(ostream &out, int indent_level) const { + for (int i = 0; i < get_num_names(); i++) { + indent(out, indent_level) << *get_name(i) << "\n"; + } +} diff --git a/panda/src/pgraph/internalNameCollection.h b/panda/src/pgraph/internalNameCollection.h new file mode 100644 index 0000000000..e6e5eae796 --- /dev/null +++ b/panda/src/pgraph/internalNameCollection.h @@ -0,0 +1,66 @@ +// Filename: internalNameCollection.h +// Created by: drose (16Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 INTERNALNAMECOLLECTION_H +#define INTERNALNAMECOLLECTION_H + +#include "pandabase.h" +#include "pointerToArray.h" +#include "internalName.h" + +//////////////////////////////////////////////////////////////////// +// Class : InternalNameCollection +// Description : +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA InternalNameCollection { +PUBLISHED: + InternalNameCollection(); + InternalNameCollection(const InternalNameCollection ©); + void operator = (const InternalNameCollection ©); + INLINE ~InternalNameCollection(); + + void add_name(InternalName *name); + bool remove_name(InternalName *name); + void add_names_from(const InternalNameCollection &other); + void remove_names_from(const InternalNameCollection &other); + void remove_duplicate_names(); + bool has_name(InternalName *name) const; + void clear(); + + int get_num_names() const; + InternalName *get_name(int index) const; + InternalName *operator [] (int index) const; + + void output(ostream &out) const; + void write(ostream &out, int indent_level = 0) const; + +private: + typedef PTA(PT(InternalName)) InternalNames; + InternalNames _names; +}; + +INLINE ostream &operator << (ostream &out, const InternalNameCollection &col) { + col.output(out); + return out; +} + +#include "internalNameCollection.I" + +#endif + + diff --git a/panda/src/pgraph/materialAttrib.I b/panda/src/pgraph/materialAttrib.I index 4ea7510292..458dca015c 100644 --- a/panda/src/pgraph/materialAttrib.I +++ b/panda/src/pgraph/materialAttrib.I @@ -46,7 +46,7 @@ is_off() const { // returns the material that is associated. Otherwise, // return NULL. //////////////////////////////////////////////////////////////////// -INLINE const Material *MaterialAttrib:: +INLINE Material *MaterialAttrib:: get_material() const { return _material; } diff --git a/panda/src/pgraph/materialAttrib.cxx b/panda/src/pgraph/materialAttrib.cxx index 216c9f8565..7f9064eca3 100644 --- a/panda/src/pgraph/materialAttrib.cxx +++ b/panda/src/pgraph/materialAttrib.cxx @@ -33,7 +33,7 @@ TypeHandle MaterialAttrib::_type_handle; // rendering the indicated material onto geometry. //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) MaterialAttrib:: -make(const Material *material) { +make(Material *material) { MaterialAttrib *attrib = new MaterialAttrib; attrib->_material = material; return return_new(attrib); diff --git a/panda/src/pgraph/materialAttrib.h b/panda/src/pgraph/materialAttrib.h index 38d52cf70c..5e226059ce 100644 --- a/panda/src/pgraph/materialAttrib.h +++ b/panda/src/pgraph/materialAttrib.h @@ -28,7 +28,7 @@ // Class : MaterialAttrib // Description : Indicates which, if any, material should be applied // to geometry. The material is used primarily to -// control lighting effects, and isn't necessarily (or +// control lighting effects, and isn't necessary (or // useful) in the absence of lighting. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA MaterialAttrib : public RenderAttrib { @@ -36,11 +36,11 @@ private: INLINE MaterialAttrib(); PUBLISHED: - static CPT(RenderAttrib) make(const Material *material); + static CPT(RenderAttrib) make(Material *material); static CPT(RenderAttrib) make_off(); INLINE bool is_off() const; - INLINE const Material *get_material() const; + INLINE Material *get_material() const; public: virtual void output(ostream &out) const; @@ -51,7 +51,7 @@ protected: virtual RenderAttrib *make_default_impl() const; private: - CPT(Material) _material; + PT(Material) _material; public: static void register_with_read_factory(); diff --git a/panda/src/pgraph/materialCollection.I b/panda/src/pgraph/materialCollection.I new file mode 100644 index 0000000000..b2aa82e9e1 --- /dev/null +++ b/panda/src/pgraph/materialCollection.I @@ -0,0 +1,27 @@ +// Filename: materialCollection.I +// Created by: drose (16Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE MaterialCollection:: +~MaterialCollection() { +} diff --git a/panda/src/pgraph/materialCollection.cxx b/panda/src/pgraph/materialCollection.cxx new file mode 100644 index 0000000000..d0e9f27fd6 --- /dev/null +++ b/panda/src/pgraph/materialCollection.cxx @@ -0,0 +1,282 @@ +// Filename: materialCollection.cxx +// Created by: drose (16Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 . +// +//////////////////////////////////////////////////////////////////// + +#include "materialCollection.h" + +#include "indent.h" + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +MaterialCollection:: +MaterialCollection() { +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::Copy Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +MaterialCollection:: +MaterialCollection(const MaterialCollection ©) : + _materials(copy._materials) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::Copy Assignment Operator +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +void MaterialCollection:: +operator = (const MaterialCollection ©) { + _materials = copy._materials; +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::add_material +// Access: Published +// Description: Adds a new Material to the collection. +//////////////////////////////////////////////////////////////////// +void MaterialCollection:: +add_material(Material *node_material) { + // If the pointer to our internal array is shared by any other + // MaterialCollections, we have to copy the array now so we won't + // inadvertently modify any of our brethren MaterialCollection + // objects. + + if (_materials.get_ref_count() > 1) { + Materials old_materials = _materials; + _materials = Materials::empty_array(0); + _materials.v() = old_materials.v(); + } + + _materials.push_back(node_material); +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::remove_material +// Access: Published +// Description: Removes the indicated Material from the collection. +// Returns true if the material was removed, false if it was +// not a member of the collection. +//////////////////////////////////////////////////////////////////// +bool MaterialCollection:: +remove_material(Material *node_material) { + int material_index = -1; + for (int i = 0; material_index == -1 && i < (int)_materials.size(); i++) { + if (_materials[i] == node_material) { + material_index = i; + } + } + + if (material_index == -1) { + // The indicated material was not a member of the collection. + return false; + } + + // If the pointer to our internal array is shared by any other + // MaterialCollections, we have to copy the array now so we won't + // inadvertently modify any of our brethren MaterialCollection + // objects. + + if (_materials.get_ref_count() > 1) { + Materials old_materials = _materials; + _materials = Materials::empty_array(0); + _materials.v() = old_materials.v(); + } + + _materials.erase(_materials.begin() + material_index); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::add_materials_from +// Access: Published +// Description: Adds all the Materials indicated in the other +// collection to this material. The other materials are simply +// appended to the end of the materials in this list; +// duplicates are not automatically removed. +//////////////////////////////////////////////////////////////////// +void MaterialCollection:: +add_materials_from(const MaterialCollection &other) { + int other_num_materials = other.get_num_materials(); + for (int i = 0; i < other_num_materials; i++) { + add_material(other.get_material(i)); + } +} + + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::remove_materials_from +// Access: Published +// Description: Removes from this collection all of the Materials +// listed in the other collection. +//////////////////////////////////////////////////////////////////// +void MaterialCollection:: +remove_materials_from(const MaterialCollection &other) { + Materials new_materials; + int num_materials = get_num_materials(); + for (int i = 0; i < num_materials; i++) { + PT(Material) material = get_material(i); + if (!other.has_material(material)) { + new_materials.push_back(material); + } + } + _materials = new_materials; +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::remove_duplicate_materials +// Access: Published +// Description: Removes any duplicate entries of the same Materials +// on this collection. If a Material appears multiple +// times, the first appearance is retained; subsequent +// appearances are removed. +//////////////////////////////////////////////////////////////////// +void MaterialCollection:: +remove_duplicate_materials() { + Materials new_materials; + + int num_materials = get_num_materials(); + for (int i = 0; i < num_materials; i++) { + PT(Material) material = get_material(i); + bool duplicated = false; + + for (int j = 0; j < i && !duplicated; j++) { + duplicated = (material == get_material(j)); + } + + if (!duplicated) { + new_materials.push_back(material); + } + } + + _materials = new_materials; +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::has_material +// Access: Published +// Description: Returns true if the indicated Material appears in +// this collection, false otherwise. +//////////////////////////////////////////////////////////////////// +bool MaterialCollection:: +has_material(Material *material) const { + for (int i = 0; i < get_num_materials(); i++) { + if (material == get_material(i)) { + return true; + } + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::clear +// Access: Published +// Description: Removes all Materials from the collection. +//////////////////////////////////////////////////////////////////// +void MaterialCollection:: +clear() { + _materials.clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::find_material +// Access: Published +// Description: Returns the material in the collection with the +// indicated name, if any, or NULL if no material has +// that name. +//////////////////////////////////////////////////////////////////// +Material *MaterialCollection:: +find_material(const string &name) const { + int num_materials = get_num_materials(); + for (int i = 0; i < num_materials; i++) { + Material *material = get_material(i); + if (material->get_name() == name) { + return material; + } + } + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::get_num_materials +// Access: Published +// Description: Returns the number of Materials in the collection. +//////////////////////////////////////////////////////////////////// +int MaterialCollection:: +get_num_materials() const { + return _materials.size(); +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::get_material +// Access: Published +// Description: Returns the nth Material in the collection. +//////////////////////////////////////////////////////////////////// +Material *MaterialCollection:: +get_material(int index) const { + nassertr(index >= 0 && index < (int)_materials.size(), NULL); + + return _materials[index]; +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::operator [] +// Access: Published +// Description: Returns the nth Material in the collection. This is +// the same as get_material(), but it may be a more +// convenient way to access it. +//////////////////////////////////////////////////////////////////// +Material *MaterialCollection:: +operator [] (int index) const { + nassertr(index >= 0 && index < (int)_materials.size(), NULL); + + return _materials[index]; +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::output +// Access: Published +// Description: Writes a brief one-line description of the +// MaterialCollection to the indicated output stream. +//////////////////////////////////////////////////////////////////// +void MaterialCollection:: +output(ostream &out) const { + if (get_num_materials() == 1) { + out << "1 Material"; + } else { + out << get_num_materials() << " Materials"; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: MaterialCollection::write +// Access: Published +// Description: Writes a complete multi-line description of the +// MaterialCollection to the indicated output stream. +//////////////////////////////////////////////////////////////////// +void MaterialCollection:: +write(ostream &out, int indent_level) const { + for (int i = 0; i < get_num_materials(); i++) { + indent(out, indent_level) << *get_material(i) << "\n"; + } +} diff --git a/panda/src/pgraph/materialCollection.h b/panda/src/pgraph/materialCollection.h new file mode 100644 index 0000000000..d552df0279 --- /dev/null +++ b/panda/src/pgraph/materialCollection.h @@ -0,0 +1,68 @@ +// Filename: materialCollection.h +// Created by: drose (16Mar02) +// +//////////////////////////////////////////////////////////////////// +// +// 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 MATERIALCOLLECTION_H +#define MATERIALCOLLECTION_H + +#include "pandabase.h" +#include "pointerToArray.h" +#include "material.h" + +//////////////////////////////////////////////////////////////////// +// Class : MaterialCollection +// Description : +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA MaterialCollection { +PUBLISHED: + MaterialCollection(); + MaterialCollection(const MaterialCollection ©); + void operator = (const MaterialCollection ©); + INLINE ~MaterialCollection(); + + void add_material(Material *node_material); + bool remove_material(Material *node_material); + void add_materials_from(const MaterialCollection &other); + void remove_materials_from(const MaterialCollection &other); + void remove_duplicate_materials(); + bool has_material(Material *material) const; + void clear(); + + Material *find_material(const string &name) const; + + int get_num_materials() const; + Material *get_material(int index) const; + Material *operator [] (int index) const; + + void output(ostream &out) const; + void write(ostream &out, int indent_level = 0) const; + +private: + typedef PTA(PT(Material)) Materials; + Materials _materials; +}; + +INLINE ostream &operator << (ostream &out, const MaterialCollection &col) { + col.output(out); + return out; +} + +#include "materialCollection.I" + +#endif + + diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index d75e725fac..2fd80033b0 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -20,6 +20,7 @@ #include "nodePathCollection.h" #include "findApproxPath.h" #include "findApproxLevelEntry.h" +#include "internalNameCollection.h" #include "config_pgraph.h" #include "colorAttrib.h" #include "colorScaleAttrib.h" @@ -28,6 +29,7 @@ #include "texMatrixAttrib.h" #include "texGenAttrib.h" #include "materialAttrib.h" +#include "materialCollection.h" #include "lightAttrib.h" #include "clipPlaneAttrib.h" #include "polylightEffect.h" @@ -3866,6 +3868,113 @@ has_vertex_column(const InternalName *name) const { return r_has_vertex_column(node(), name); } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::find_all_vertex_columns +// Access: Published +// Description: Returns a list of all vertex array columns stored on +// some geometry found at this node level and below. +//////////////////////////////////////////////////////////////////// +InternalNameCollection NodePath:: +find_all_vertex_columns() const { + nassertr_always(!is_empty(), InternalNameCollection()); + InternalNames vertex_columns; + r_find_all_vertex_columns(node(), vertex_columns); + + InternalNameCollection tc; + InternalNames::iterator ti; + for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { + tc.add_name(*ti); + } + return tc; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::find_all_vertex_columns +// Access: Published +// Description: Returns a list of all vertex array columns stored on +// some geometry found at this node level and below that +// match the indicated name (which may contain wildcard +// characters). +//////////////////////////////////////////////////////////////////// +InternalNameCollection NodePath:: +find_all_vertex_columns(const string &name) const { + nassertr_always(!is_empty(), InternalNameCollection()); + InternalNames vertex_columns; + r_find_all_vertex_columns(node(), vertex_columns); + + GlobPattern glob(name); + + InternalNameCollection tc; + InternalNames::iterator ti; + for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { + InternalName *name = (*ti); + if (glob.matches(name->get_name())) { + tc.add_name(name); + } + } + return tc; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::find_all_texcoords +// Access: Published +// Description: Returns a list of all texture coordinate sets used by +// any geometry at this node level and below. +//////////////////////////////////////////////////////////////////// +InternalNameCollection NodePath:: +find_all_texcoords() const { + nassertr_always(!is_empty(), InternalNameCollection()); + InternalNames vertex_columns; + r_find_all_vertex_columns(node(), vertex_columns); + + CPT(InternalName) texcoord_name = InternalName::get_texcoord(); + + InternalNameCollection tc; + InternalNames::iterator ti; + for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { + if ((*ti)->get_top() == texcoord_name) { + tc.add_name(*ti); + } + } + return tc; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::find_all_texcoords +// Access: Published +// Description: Returns a list of all texture coordinate sets used by +// any geometry at this node level and below that match +// the indicated name (which may contain wildcard +// characters). +//////////////////////////////////////////////////////////////////// +InternalNameCollection NodePath:: +find_all_texcoords(const string &name) const { + nassertr_always(!is_empty(), InternalNameCollection()); + InternalNames vertex_columns; + r_find_all_vertex_columns(node(), vertex_columns); + + GlobPattern glob(name); + CPT(InternalName) texcoord_name = InternalName::get_texcoord(); + + InternalNameCollection tc; + InternalNames::iterator ti; + for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) { + InternalName *name = (*ti); + if (name->get_top() == texcoord_name) { + // This is a texture coordinate name. Figure out the basename + // of the texture coordinates. + int index = name->find_ancestor("texcoord"); + nassertr(index != -1, InternalNameCollection()); + string net_basename = name->get_net_basename(index - 1); + + if (glob.matches(net_basename)) { + tc.add_name(name); + } + } + } + return tc; +} + //////////////////////////////////////////////////////////////////// // Function: NodePath::find_texture // Access: Published @@ -4041,6 +4150,67 @@ find_all_texture_stages(const string &name) const { return tc; } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::find_material +// Access: Published +// Description: Returns the first material found applied to geometry +// at this node or below that matches the indicated name +// (which may contain wildcards). Returns the material +// if it is found, or NULL if it is not. +//////////////////////////////////////////////////////////////////// +Material *NodePath:: +find_material(const string &name) const { + nassertr_always(!is_empty(), NULL); + GlobPattern glob(name); + return r_find_material(node(), get_net_state(), glob); +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::find_all_materials +// Access: Published +// Description: Returns a list of a materials applied to geometry at +// this node and below. +//////////////////////////////////////////////////////////////////// +MaterialCollection NodePath:: +find_all_materials() const { + nassertr_always(!is_empty(), MaterialCollection()); + Materials materials; + r_find_all_materials(node(), get_net_state(), materials); + + MaterialCollection tc; + Materials::iterator ti; + for (ti = materials.begin(); ti != materials.end(); ++ti) { + tc.add_material(*ti); + } + return tc; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::find_all_materials +// Access: Published +// Description: Returns a list of a materials applied to geometry at +// this node and below that match the indicated name +// (which may contain wildcard characters). +//////////////////////////////////////////////////////////////////// +MaterialCollection NodePath:: +find_all_materials(const string &name) const { + nassertr_always(!is_empty(), MaterialCollection()); + Materials materials; + r_find_all_materials(node(), get_net_state(), materials); + + GlobPattern glob(name); + + MaterialCollection tc; + Materials::iterator ti; + for (ti = materials.begin(); ti != materials.end(); ++ti) { + Material *material = (*ti); + if (glob.matches(material->get_name())) { + tc.add_material(material); + } + } + return tc; +} + //////////////////////////////////////////////////////////////////// // Function: NodePath::set_material // Access: Published @@ -4115,10 +4285,8 @@ has_material() const { // applied to the geometry at or below this level, as // another material at a higher or lower level may // override. -// -// This function returns a copy of the given material, -// to allow changes, if desired. Once changes are made, -// they should be reapplied via set_material(). + +// See also find_material(). //////////////////////////////////////////////////////////////////// PT(Material) NodePath:: get_material() const { @@ -4127,7 +4295,7 @@ get_material() const { node()->get_attrib(MaterialAttrib::get_class_type()); if (attrib != (const RenderAttrib *)NULL) { const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib); - return new Material(*ma->get_material()); + return ma->get_material(); } return NULL; @@ -5801,6 +5969,43 @@ r_has_vertex_column(PandaNode *node, const InternalName *name) const { return false; } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::r_find_all_vertex_columns +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +void NodePath:: +r_find_all_vertex_columns(PandaNode *node, + NodePath::InternalNames &vertex_columns) const { + if (node->is_geom_node()) { + GeomNode *gnode; + DCAST_INTO_V(gnode, node); + + int num_geoms = gnode->get_num_geoms(); + for (int i = 0; i < num_geoms; ++i) { + const Geom *geom = gnode->get_geom(i); + const GeomVertexFormat *format = geom->get_vertex_data()->get_format(); + int num_arrays = format->get_num_arrays(); + for (int j = 0; j < num_arrays; ++j) { + const GeomVertexArrayFormat *array = format->get_array(j); + int num_columns = array->get_num_columns(); + for (int k = 0; k < num_columns; ++k) { + const GeomVertexColumn *column = array->get_column(k); + vertex_columns.insert(column->get_name()); + } + } + } + } + + // Now consider children. + PandaNode::Children cr = node->get_children(); + int num_children = cr.get_num_children(); + for (int i = 0; i < num_children; i++) { + PandaNode *child = cr.get_child(i); + r_find_all_vertex_columns(child, vertex_columns); + } +} + //////////////////////////////////////////////////////////////////// // Function: NodePath::r_find_texture // Access: Private @@ -6133,6 +6338,96 @@ r_unify_texture_stages(PandaNode *node, TextureStage *stage) { } } +//////////////////////////////////////////////////////////////////// +// Function: NodePath::r_find_material +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +Material *NodePath:: +r_find_material(PandaNode *node, const RenderState *state, + const GlobPattern &glob) const { + if (node->is_geom_node()) { + GeomNode *gnode; + DCAST_INTO_R(gnode, node, NULL); + + int num_geoms = gnode->get_num_geoms(); + for (int i = 0; i < num_geoms; i++) { + CPT(RenderState) geom_state = + state->compose(gnode->get_geom_state(i)); + + // Look for a MaterialAttrib on the state. + const RenderAttrib *attrib = + geom_state->get_attrib(MaterialAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib); + if (!ta->is_off()) { + Material *material = ta->get_material(); + if (material != (Material *)NULL) { + return material; + } + } + } + } + } + + // Now consider children. + PandaNode::Children cr = node->get_children(); + int num_children = cr.get_num_children(); + for (int i = 0; i < num_children; i++) { + PandaNode *child = cr.get_child(i); + CPT(RenderState) next_state = state->compose(child->get_state()); + + Material *result = r_find_material(child, next_state, glob); + if (result != (Material *)NULL) { + return result; + } + } + + return NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: NodePath::r_find_all_materials +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +void NodePath:: +r_find_all_materials(PandaNode *node, const RenderState *state, + NodePath::Materials &materials) const { + if (node->is_geom_node()) { + GeomNode *gnode; + DCAST_INTO_V(gnode, node); + + int num_geoms = gnode->get_num_geoms(); + for (int i = 0; i < num_geoms; i++) { + CPT(RenderState) geom_state = + state->compose(gnode->get_geom_state(i)); + + // Look for a MaterialAttrib on the state. + const RenderAttrib *attrib = + geom_state->get_attrib(MaterialAttrib::get_class_type()); + if (attrib != (const RenderAttrib *)NULL) { + const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib); + if (!ta->is_off()) { + Material *material = ta->get_material(); + if (material != (Material *)NULL) { + materials.insert(material); + } + } + } + } + } + + // Now consider children. + PandaNode::Children cr = node->get_children(); + int num_children = cr.get_num_children(); + for (int i = 0; i < num_children; i++) { + PandaNode *child = cr.get_child(i); + CPT(RenderState) next_state = state->compose(child->get_state()); + r_find_all_materials(child, next_state, materials); + } +} + //////////////////////////////////////////////////////////////////// // Function: NodePath::r_prepare_scene // Access: Private diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 465fa69b74..312e4e5c53 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -37,11 +37,13 @@ class FindApproxPath; class FindApproxLevelEntry; class Light; class PolylightNode; +class InternalNameCollection; class Texture; class TextureStage; class TextureCollection; class TextureStageCollection; class Material; +class MaterialCollection; class Fog; class GlobPattern; class PreparedGraphicsObjects; @@ -648,6 +650,10 @@ PUBLISHED: INLINE bool has_texcoord(const string &texcoord_name) const; bool has_vertex_column(const InternalName *name) const; + InternalNameCollection find_all_vertex_columns() const; + InternalNameCollection find_all_vertex_columns(const string &name) const; + InternalNameCollection find_all_texcoords() const; + InternalNameCollection find_all_texcoords(const string &name) const; Texture *find_texture(const string &name) const; Texture *find_texture(TextureStage *stage) const; @@ -661,6 +667,10 @@ PUBLISHED: void unify_texture_stages(TextureStage *stage); + Material *find_material(const string &name) const; + MaterialCollection find_all_materials() const; + MaterialCollection find_all_materials(const string &name) const; + void set_material(Material *tex, int priority = 0); void set_material_off(int priority = 0); void clear_material(); @@ -823,7 +833,10 @@ private: CollideMask and_mask, CollideMask or_mask, TypeHandle node_type); + typedef phash_set InternalNames; bool r_has_vertex_column(PandaNode *node, const InternalName *name) const; + void r_find_all_vertex_columns(PandaNode *node, + InternalNames &vertex_columns) const; typedef phash_set Textures; Texture *r_find_texture(PandaNode *node, const RenderState *state, @@ -842,6 +855,12 @@ private: void r_unify_texture_stages(PandaNode *node, TextureStage *stage); + typedef phash_set Materials; + Material *r_find_material(PandaNode *node, const RenderState *state, + const GlobPattern &glob) const; + void r_find_all_materials(PandaNode *node, const RenderState *state, + Materials &materials) const; + void r_prepare_scene(PandaNode *node, const RenderState *state, PreparedGraphicsObjects *prepared_objects); diff --git a/panda/src/pgraph/pgraph_composite3.cxx b/panda/src/pgraph/pgraph_composite3.cxx index 5d551c2d74..0ece1a3361 100644 --- a/panda/src/pgraph/pgraph_composite3.cxx +++ b/panda/src/pgraph/pgraph_composite3.cxx @@ -1,3 +1,4 @@ +#include "internalNameCollection.cxx" #include "lensNode.cxx" #include "light.cxx" #include "lightAttrib.cxx" @@ -10,6 +11,7 @@ #include "loaderOptions.cxx" #include "lodNode.cxx" #include "materialAttrib.cxx" +#include "materialCollection.cxx" #include "modelNode.cxx" #include "modelPool.cxx" #include "modelRoot.cxx" diff --git a/panda/src/putil/bam.h b/panda/src/putil/bam.h index c579376edf..1e556eb989 100644 --- a/panda/src/putil/bam.h +++ b/panda/src/putil/bam.h @@ -35,12 +35,13 @@ static const unsigned short _bam_major_ver = 5; // Bumped to major version 4 on 4/10/02 to store new scene graph. // Bumped to major version 5 on 5/6/05 for new Geom implementation. -static const unsigned short _bam_minor_ver = 5; +static const unsigned short _bam_minor_ver = 6; // Bumped to minor version 1 on 7/14/05 to add TextureStage::_saved_result. // Bumped to minor version 2 on 7/21/05 to add TransformState::is_2d. // Bumped to minor version 3 on 8/25/05 to add ModelNode::_preserve_attributes. // Bumped to minor version 4 on 9/27/05 to make SequenceNode inherit from AnimInterface. // Bumped to minor version 5 on 12/22/05 to add Texture::_border_color. +// Bumped to minor version 6 on 1/14/06 to add Material::_name. #endif