diff --git a/include/EMaterialTypes.h b/include/EMaterialTypes.h index b313692f..90554917 100644 --- a/include/EMaterialTypes.h +++ b/include/EMaterialTypes.h @@ -5,6 +5,8 @@ #ifndef __E_MATERIAL_TYPES_H_INCLUDED__ #define __E_MATERIAL_TYPES_H_INCLUDED__ +#include "irrTypes.h" + namespace irr { namespace video @@ -67,6 +69,9 @@ namespace video 0 }; + constexpr u32 numBuiltInMaterials = + sizeof(sBuiltInMaterialTypeNames) / sizeof(char*) - 1; + } // end namespace video } // end namespace irr diff --git a/include/IGPUProgrammingServices.h b/include/IGPUProgrammingServices.h index 885eee4c..f172314f 100644 --- a/include/IGPUProgrammingServices.h +++ b/include/IGPUProgrammingServices.h @@ -356,6 +356,15 @@ public: scene::EPT_TRIANGLES, scene::EPT_TRIANGLE_STRIP, 0, callback, baseMaterial, userData); } + + //! Delete a shader material and associated data. + /** + After you have deleted a material it is invalid to still use and doing + so might result in a crash. The ID may be reused in the future when new + materials are added. + \param material Number of the material type. Must not be a built-in + material. */ + virtual void deleteShaderMaterial(s32 material) = 0; }; diff --git a/source/Irrlicht/CNullDriver.cpp b/source/Irrlicht/CNullDriver.cpp index 0e7a426b..b35e7193 100644 --- a/source/Irrlicht/CNullDriver.cpp +++ b/source/Irrlicht/CNullDriver.cpp @@ -41,6 +41,14 @@ IImageWriter* createImageWriterJPG(); //! creates a writer which is able to save png images IImageWriter* createImageWriterPNG(); +namespace { + //! no-op material renderer + class CDummyMaterialRenderer : public IMaterialRenderer { + public: + CDummyMaterialRenderer() {} + }; +} + //! constructor CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize) @@ -1525,7 +1533,7 @@ s32 CNullDriver::addMaterialRenderer(IMaterialRenderer* renderer, const char* na r.Renderer = renderer; r.Name = name; - if (name == 0 && (MaterialRenderers.size() < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 )) + if (name == 0 && MaterialRenderers.size() < numBuiltInMaterials) { // set name of built in renderer so that we don't have to implement name // setting in all available renderers. @@ -1542,8 +1550,7 @@ s32 CNullDriver::addMaterialRenderer(IMaterialRenderer* renderer, const char* na //! Sets the name of a material renderer. void CNullDriver::setMaterialRendererName(u32 idx, const char* name) { - if (idx < (sizeof(sBuiltInMaterialTypeNames) / sizeof(char*))-1 || - idx >= MaterialRenderers.size()) + if (idx < numBuiltInMaterials || idx >= MaterialRenderers.size()) return; MaterialRenderers[idx].Name = name; @@ -1786,6 +1793,27 @@ s32 CNullDriver::addHighLevelShaderMaterialFromFiles( return result; } +void CNullDriver::deleteShaderMaterial(s32 material) +{ + const u32 idx = (u32)material; + if (idx < numBuiltInMaterials || idx >= MaterialRenderers.size()) + return; + + // if this is the last material we can drop it without consequence + if (idx == MaterialRenderers.size() - 1) { + if (MaterialRenderers[idx].Renderer) + MaterialRenderers[idx].Renderer->drop(); + MaterialRenderers.erase(idx); + return; + } + // otherwise replace with a dummy renderer, we have to preserve the IDs + auto &ref = MaterialRenderers[idx]; + if (ref.Renderer) + ref.Renderer->drop(); + ref.Renderer = new CDummyMaterialRenderer(); + ref.Name.clear(); +} + //! Creates a render target texture. ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d& size, diff --git a/source/Irrlicht/CNullDriver.h b/source/Irrlicht/CNullDriver.h index e9493723..77b9f7b2 100644 --- a/source/Irrlicht/CNullDriver.h +++ b/source/Irrlicht/CNullDriver.h @@ -525,6 +525,8 @@ namespace video E_MATERIAL_TYPE baseMaterial = video::EMT_SOLID, s32 userData = 0) override; + virtual void deleteShaderMaterial(s32 material) override; + //! Returns a pointer to the mesh manipulator. scene::IMeshManipulator* getMeshManipulator() override;