Browse Source

NodePath: Implement replace_material

Closes #472
loblao 7 years ago
parent
commit
68b7986557
2 changed files with 63 additions and 0 deletions
  1. 60 0
      panda/src/pgraph/nodePath.cxx
  2. 3 0
      panda/src/pgraph/nodePath.h

+ 60 - 0
panda/src/pgraph/nodePath.cxx

@@ -4163,6 +4163,20 @@ get_material() const {
   return nullptr;
 }
 
+/**
+ * Recursively searches the scene graph for references to the given material,
+ * and replaces them with the new material.
+ */
+void NodePath::
+replace_material(Material *mat, Material *new_mat) {
+  nassertv_always(!is_empty());
+  nassertv(mat != nullptr);
+  nassertv(new_mat != nullptr);
+
+  CPT(RenderAttrib) new_attrib = MaterialAttrib::make(new_mat);
+  r_replace_material(node(), mat, (const MaterialAttrib *)new_attrib.p());
+}
+
 /**
  * Sets the geometry at this level and below to render using the indicated
  * fog.
@@ -6632,6 +6646,52 @@ r_find_all_materials(PandaNode *node, const RenderState *state,
   }
 }
 
+/**
+ *
+ */
+void NodePath::
+r_replace_material(PandaNode *node, Material *mat,
+                   const MaterialAttrib *new_attrib) {
+  // Consider the state of the node itself.
+  {
+    CPT(RenderState) node_state = node->get_state();
+    const MaterialAttrib *ma;
+    if (node_state->get_attrib(ma)) {
+      if (mat == ma->get_material()) {
+        node->set_state(node_state->set_attrib(new_attrib));
+      }
+    }
+  }
+
+  // If this is a GeomNode, consider the state of any of its Geoms.
+  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 = gnode->get_geom_state(i);
+
+      // Look for a MaterialAttrib on the state.
+      const MaterialAttrib *ma;
+      if (geom_state->get_attrib(ma)) {
+        if (mat == ma->get_material()) {
+          // Replace it
+          gnode->set_geom_state(i, geom_state->set_attrib(new_attrib));
+        }
+      }
+    }
+  }
+
+  // Now consider children.
+  PandaNode::Children cr = node->get_children();
+  size_t num_children = cr.get_num_children();
+  for (size_t i = 0; i < num_children; ++i) {
+    PandaNode *child = cr.get_child(i);
+    r_replace_material(child, mat, new_attrib);
+  }
+}
+
 /**
  * Writes the contents of this object to the datagram for shipping out to a
  * Bam file.

+ 3 - 0
panda/src/pgraph/nodePath.h

@@ -771,6 +771,7 @@ PUBLISHED:
   void clear_material();
   bool has_material() const;
   PT(Material) get_material() const;
+  void replace_material(Material *mat, Material *new_mat);
 
   void set_fog(Fog *fog, int priority = 0);
   void set_fog_off(int priority = 0);
@@ -1016,6 +1017,8 @@ private:
                           const GlobPattern &glob) const;
   void r_find_all_materials(PandaNode *node, const RenderState *state,
                            Materials &materials) const;
+  static void r_replace_material(PandaNode *node, Material *mat,
+                                 const MaterialAttrib *new_attrib);
 
   PT(NodePathComponent) _head;
   int _backup_key;