diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 3e2430aa3c..8e0f986436 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/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())); + } } } } diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 187129d30c..43dd2ec6f4 100644 --- a/panda/src/pgraph/nodePath.h +++ b/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); diff --git a/panda/src/pgraph/textureAttrib.cxx b/panda/src/pgraph/textureAttrib.cxx index d08344fc4d..7303ee9245 100644 --- a/panda/src/pgraph/textureAttrib.cxx +++ b/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) { diff --git a/panda/src/pgraph/textureAttrib.h b/panda/src/pgraph/textureAttrib.h index 0858cc68a7..ba0eae0d19 100644 --- a/panda/src/pgraph/textureAttrib.h +++ b/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; diff --git a/tests/pgraph/test_nodepath.py b/tests/pgraph/test_nodepath.py index 6a7d0990b4..1ef0c15bef 100644 --- a/tests/pgraph/test_nodepath.py +++ b/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