Răsfoiți Sursa

add NodePath::find_material(), find_all_texcoords(), etc. Make Material be directly modifiable.

David Rose 20 ani în urmă
părinte
comite
cf01ef9cd6
37 a modificat fișierele cu 1198 adăugiri și 103 ștergeri
  1. 1 1
      panda/src/distort/projectionScreen.h
  2. 1 1
      panda/src/dxgsg8/dxGeomMunger8.cxx
  3. 1 1
      panda/src/dxgsg9/dxGeomMunger9.cxx
  4. 1 2
      panda/src/egg2pg/eggLoader.cxx
  5. 2 2
      panda/src/egg2pg/eggRenderState.cxx
  6. 11 11
      panda/src/gobj/geomVertexArrayFormat.cxx
  7. 11 11
      panda/src/gobj/geomVertexArrayFormat.h
  8. 4 4
      panda/src/gobj/geomVertexColumn.I
  9. 5 5
      panda/src/gobj/geomVertexColumn.h
  10. 1 1
      panda/src/gobj/geomVertexData.cxx
  11. 1 1
      panda/src/gobj/geomVertexData.h
  12. 22 1
      panda/src/gobj/internalName.cxx
  13. 1 0
      panda/src/gobj/internalName.h
  14. 2 2
      panda/src/gobj/material.I
  15. 16 10
      panda/src/gobj/material.cxx
  16. 3 2
      panda/src/gobj/material.h
  17. 5 8
      panda/src/gobj/materialPool.I
  18. 22 10
      panda/src/gobj/materialPool.cxx
  19. 12 8
      panda/src/gobj/materialPool.h
  20. 6 0
      panda/src/pgraph/Sources.pp
  21. 3 3
      panda/src/pgraph/cullableObject.cxx
  22. 1 1
      panda/src/pgraph/geomNode.cxx
  23. 2 2
      panda/src/pgraph/geomTransformer.cxx
  24. 2 4
      panda/src/pgraph/geomTransformer.h
  25. 27 0
      panda/src/pgraph/internalNameCollection.I
  26. 263 0
      panda/src/pgraph/internalNameCollection.cxx
  27. 66 0
      panda/src/pgraph/internalNameCollection.h
  28. 1 1
      panda/src/pgraph/materialAttrib.I
  29. 1 1
      panda/src/pgraph/materialAttrib.cxx
  30. 4 4
      panda/src/pgraph/materialAttrib.h
  31. 27 0
      panda/src/pgraph/materialCollection.I
  32. 282 0
      panda/src/pgraph/materialCollection.cxx
  33. 68 0
      panda/src/pgraph/materialCollection.h
  34. 300 5
      panda/src/pgraph/nodePath.cxx
  35. 19 0
      panda/src/pgraph/nodePath.h
  36. 2 0
      panda/src/pgraph/pgraph_composite3.cxx
  37. 2 1
      panda/src/putil/bam.h

+ 1 - 1
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;

+ 1 - 1
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);

+ 1 - 1
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);

+ 1 - 2
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

+ 2 - 2
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);

+ 11 - 11
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) {

+ 11 - 11
panda/src/gobj/geomVertexArrayFormat.h

@@ -57,25 +57,25 @@ class EXPCL_PANDA GeomVertexArrayFormat : public TypedWritableReferenceCount, pu
 PUBLISHED:
   GeomVertexArrayFormat();
   GeomVertexArrayFormat(const GeomVertexArrayFormat &copy);
-  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 &copy);
   ~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);

+ 4 - 4
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;
 }

+ 5 - 5
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 &copy);
   void operator = (const GeomVertexColumn &copy);
   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;

+ 1 - 1
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);

+ 1 - 1
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;

+ 22 - 1
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()) {

+ 1 - 0
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;

+ 2 - 2
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 &copy) {
+Material(const Material &copy) : Namable(copy) {
   operator = (copy);
 }
 

+ 16 - 10
panda/src/gobj/material.cxx

@@ -33,6 +33,7 @@ TypeHandle Material::_type_handle;
 ////////////////////////////////////////////////////////////////////
 void Material::
 operator = (const Material &copy) {
+  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 &params) {
 //               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);

+ 3 - 2
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 &copy);
   void operator = (const Material &copy);
   INLINE ~Material();

+ 5 - 8
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);
 }
 

+ 22 - 10
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";
   }
 }
 

+ 12 - 8
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<const Material *> > 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<const Material *> > Materials;
   Materials _materials;
 };
 

+ 6 - 0
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 \

+ 3 - 3
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)) {

+ 1 - 1
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.

+ 2 - 2
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);

+ 2 - 4
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);

+ 27 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalNameCollection::Destructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE InternalNameCollection::
+~InternalNameCollection() {
+}

+ 263 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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 &copy) :
+  _names(copy._names)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalNameCollection::Copy Assignment Operator
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+void InternalNameCollection::
+operator = (const InternalNameCollection &copy) {
+  _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";
+  }
+}

+ 66 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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 &copy);
+  void operator = (const InternalNameCollection &copy);
+  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
+
+

+ 1 - 1
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;
 }

+ 1 - 1
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);

+ 4 - 4
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();

+ 27 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: MaterialCollection::Destructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE MaterialCollection::
+~MaterialCollection() {
+}

+ 282 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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 &copy) :
+  _materials(copy._materials)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MaterialCollection::Copy Assignment Operator
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+void MaterialCollection::
+operator = (const MaterialCollection &copy) {
+  _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";
+  }
+}

+ 68 - 0
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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#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 &copy);
+  void operator = (const MaterialCollection &copy);
+  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
+
+

+ 300 - 5
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

+ 19 - 0
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<InternalName *, pointer_hash> 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<Texture *, pointer_hash> 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<Material *, pointer_hash> 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);
 

+ 2 - 0
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"

+ 2 - 1
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