Bläddra i källkod

pgraph: Support None as second arg of replace_texture/replace_material

This removes the relevant texture or material
rdb 3 år sedan
förälder
incheckning
41f0c9d48d

+ 18 - 5
panda/src/pgraph/nodePath.cxx

@@ -3207,13 +3207,14 @@ get_texture(TextureStage *stage) const {
  * Recursively searches the scene graph for references to the given texture,
  * and replaces them with the new texture.
  *
+ * As of Panda3D 1.10.13, new_tex may be null to remove the texture.
+ *
  * @since 1.10.4
  */
 void NodePath::
 replace_texture(Texture *tex, Texture *new_tex) {
   nassertv_always(!is_empty());
   nassertv(tex != nullptr);
-  nassertv(new_tex != nullptr);
 
   r_replace_texture(node(), tex, new_tex);
 }
@@ -4249,15 +4250,19 @@ get_material() const {
  * Recursively searches the scene graph for references to the given material,
  * and replaces them with the new material.
  *
+ * As of Panda3D 1.10.13, new_mat may be null to remove the material.
+ *
  * @since 1.10.0
  */
 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);
+  CPT(RenderAttrib) new_attrib;
+  if (new_mat != nullptr) {
+    new_attrib = MaterialAttrib::make(new_mat);
+  }
   r_replace_material(node(), mat, (const MaterialAttrib *)new_attrib.p());
 }
 
@@ -6841,7 +6846,11 @@ r_replace_material(PandaNode *node, Material *mat,
     const MaterialAttrib *ma;
     if (node_state->get_attrib(ma)) {
       if (mat == ma->get_material()) {
-        node->set_state(node_state->set_attrib(new_attrib));
+        if (new_attrib != nullptr) {
+          node->set_state(node_state->set_attrib(new_attrib));
+        } else {
+          node->set_state(node_state->remove_attrib(MaterialAttrib::get_class_slot()));
+        }
       }
     }
   }
@@ -6860,7 +6869,11 @@ r_replace_material(PandaNode *node, Material *mat,
       if (geom_state->get_attrib(ma)) {
         if (mat == ma->get_material()) {
           // Replace it
-          gnode->set_geom_state(i, geom_state->set_attrib(new_attrib));
+          if (new_attrib != nullptr) {
+            gnode->set_geom_state(i, geom_state->set_attrib(new_attrib));
+          } else {
+            gnode->set_geom_state(i, geom_state->remove_attrib(MaterialAttrib::get_class_slot()));
+          }
         }
       }
     }

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

@@ -619,6 +619,9 @@ PUBLISHED:
   Texture *get_texture() const;
   Texture *get_texture(TextureStage *stage) const;
   void replace_texture(Texture *tex, Texture *new_tex);
+#ifdef CPPPARSER  // Let interrogate know this also accepts None
+  void replace_texture(Texture *tex, std::nullptr_t new_tex);
+#endif
   const SamplerState &get_texture_sampler() const;
   const SamplerState &get_texture_sampler(TextureStage *stage) const;
 
@@ -771,6 +774,9 @@ PUBLISHED:
   bool has_material() const;
   PT(Material) get_material() const;
   void replace_material(Material *mat, Material *new_mat);
+#ifdef CPPPARSER  // Let interrogate know this also accepts None
+  void replace_material(Material *mat, std::nullptr_t new_mat);
+#endif
 
   void set_fog(Fog *fog, int priority = 0);
   void set_fog_off(int priority = 0);

+ 10 - 1
panda/src/pgraph/textureAttrib.cxx

@@ -253,12 +253,15 @@ unify_texture_stages(TextureStage *stage) const {
  * Returns a new TextureAttrib, just like this one, but with all references to
  * the given texture replaced with the new texture.
  *
+ * As of Panda3D 1.10.13, new_tex may be null to remove the texture.
+ *
  * @since 1.10.4
  */
 CPT(RenderAttrib) TextureAttrib::
 replace_texture(Texture *tex, Texture *new_tex) const {
   TextureAttrib *attrib = nullptr;
 
+  size_t j = 0;
   for (size_t i = 0; i < _on_stages.size(); ++i) {
     const StageNode &sn = _on_stages[i];
     if (sn._texture == tex) {
@@ -266,8 +269,14 @@ replace_texture(Texture *tex, Texture *new_tex) const {
         attrib = new TextureAttrib(*this);
       }
 
-      attrib->_on_stages[i]._texture = new_tex;
+      if (new_tex != nullptr) {
+        attrib->_on_stages[j]._texture = new_tex;
+      } else {
+        attrib->_on_stages.erase(attrib->_on_stages.begin() + j);
+        continue;
+      }
     }
+    ++j;
   }
 
   if (attrib != nullptr) {

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

@@ -90,6 +90,9 @@ PUBLISHED:
   CPT(RenderAttrib) remove_off_stage(TextureStage *stage) const;
   CPT(RenderAttrib) unify_texture_stages(TextureStage *stage) const;
   CPT(RenderAttrib) replace_texture(Texture *tex, Texture *new_tex) const;
+#ifdef CPPPARSER  // Let interrogate know this also accepts None
+  CPT(RenderAttrib) replace_texture(Texture *tex, std::nullptr_t new_tex) const;
+#endif
 
 public:
   CPT(TextureAttrib) filter_to_max(int max_texture_stages) const;

+ 21 - 0
tests/pgraph/test_nodepath.py

@@ -248,3 +248,24 @@ def test_nodepath_replace_texture():
     path1.replace_texture(tex1, tex2)
     assert not path1.has_texture()
     assert path2.get_texture() == tex2
+
+
+def test_nodepath_replace_texture_none():
+    from panda3d.core import NodePath, Texture
+
+    tex1 = Texture("tex1")
+
+    path1 = NodePath("node1")
+    assert path1.get_texture() is None
+    path1.set_texture(tex1)
+    assert path1.get_texture() == tex1
+    path1.replace_texture(tex1, None)
+    assert path1.get_texture() is None
+
+    path1 = NodePath("node1")
+    path2 = path1.attach_new_node("node2")
+    assert path2.get_texture() is None
+    path2.set_texture(tex1)
+    assert path2.get_texture() == tex1
+    path1.replace_texture(tex1, None)
+    assert path2.get_texture() is None