diff --git a/src/device/device.cpp b/src/device/device.cpp index 4f076c993..81d7a1d47 100644 --- a/src/device/device.cpp +++ b/src/device/device.cpp @@ -873,10 +873,13 @@ void Device::refresh(const char *json) StringId64 resource_type(type); StringId64 resource_name(resource.c_str(), len); - _resource_manager->reload(resource_type, resource_name); + const void *old_resource = _resource_manager->get(resource_type, resource_name); + const void *new_resource = _resource_manager->reload(resource_type, resource_name); if (resource_type == RESOURCE_TYPE_SCRIPT) { refresh_lua = true; + } else if (resource_type == RESOURCE_TYPE_TEXTURE) { + _material_manager->reload_textures((TextureResource *)old_resource, (TextureResource *)new_resource); } } diff --git a/src/world/material.cpp b/src/world/material.cpp index 9818b69d1..275a5e00b 100644 --- a/src/world/material.cpp +++ b/src/world/material.cpp @@ -3,6 +3,7 @@ * SPDX-License-Identifier: MIT */ +#include "core/containers/array.inl" #include "core/strings/string_id.inl" #include "resource/material_resource.h" #include "resource/resource_manager.h" @@ -13,6 +14,14 @@ namespace crown { +Material::Material(Allocator &a) +#if CROWN_CAN_RELOAD + : _texture_resources(a) +#endif +{ + CE_UNUSED(a); +} + void Material::bind(ShaderManager &sm, u8 view, s32 depth) const { using namespace material_resource; @@ -88,6 +97,26 @@ void Material::set_texture(StringId32 sampler_name, ResourceId texture_resource) u32 idx = material_resource::texture_data_index(_resource, td, sampler_name); TextureHandle *th = (TextureHandle *)material_resource::texture_handle(td, idx, _data); th->texture_handle = tr->handle.idx; +#if CROWN_CAN_RELOAD + u32 index = material_resource::texture_data_index(_resource, td, sampler_name); + _texture_resources[index] = (TextureResource *)tr; +#endif +} + +void Material::reload_textures(const TextureResource *old_resource, const TextureResource *new_resource) +{ +#if CROWN_CAN_RELOAD + const TextureData *td = material_resource::texture_data_array(_resource); + for (u32 i = 0; i < array::size(_texture_resources); ++i) { + if (_texture_resources[i] == old_resource) { + _texture_resources[i] = (TextureResource *)new_resource; + TextureHandle *th = material_resource::texture_handle(td, i, _data); + th->texture_handle = new_resource->handle.idx; + } + } +#else + CE_UNUSED_2(old_resource, new_resource); +#endif } } // namespace crown diff --git a/src/world/material.h b/src/world/material.h index a86dae61d..512aaaebf 100644 --- a/src/world/material.h +++ b/src/world/material.h @@ -5,6 +5,7 @@ #pragma once +#include "config.h" #include "core/math/types.h" #include "resource/resource_id.h" #include "resource/types.h" @@ -20,6 +21,12 @@ struct Material ResourceManager *_resource_manager; const MaterialResource *_resource; char *_data; +#if CROWN_CAN_RELOAD + Array _texture_resources; +#endif + + /// + explicit Material(Allocator &a); /// void bind(ShaderManager &sm, u8 view, s32 depth = 0) const; @@ -41,6 +48,9 @@ struct Material /// Sets the @a texture_resource of the sampler @a sampler_name. void set_texture(StringId32 sampler_name, ResourceId texture_resource); + + /// + void reload_textures(const TextureResource *old_resource, const TextureResource *new_resource); }; } // namespace crown diff --git a/src/world/material_manager.cpp b/src/world/material_manager.cpp index 59506fca8..9eacb5ed8 100644 --- a/src/world/material_manager.cpp +++ b/src/world/material_manager.cpp @@ -3,6 +3,7 @@ * SPDX-License-Identifier: MIT */ +#include "core/containers/array.inl" #include "core/containers/hash_map.inl" #include "core/filesystem/file.h" #include "core/strings/string_id.inl" @@ -48,39 +49,36 @@ void MaterialManager::online(StringId64 id, ResourceManager &rm) using namespace material_resource; MaterialResource *mr = (MaterialResource *)rm.get(RESOURCE_TYPE_MATERIAL, id); - - char *base = (char *)mr + mr->dynamic_data_offset; + Material *material = create_material(mr); const TextureData *td = texture_data_array(mr); for (u32 i = 0; i < mr->num_textures; ++i) { - TextureHandle *th = texture_handle(td, i, base); + TextureHandle *th = texture_handle(td, i, material->_data); TextureResource *tr = (TextureResource *)rm.get(RESOURCE_TYPE_TEXTURE, td->id); th->sampler_handle = bgfx::createUniform(texture_name(mr, td, i), bgfx::UniformType::Sampler).idx; th->texture_handle = tr->handle.idx; +#if CROWN_CAN_RELOAD + material->_texture_resources[i] = tr; +#endif } const UniformData *ud = uniform_data_array(mr); for (u32 i = 0; i < mr->num_uniforms; ++i) { - UniformHandle *uh = uniform_handle(ud, i, base); + UniformHandle *uh = uniform_handle(ud, i, material->_data); uh->uniform_handle = bgfx::createUniform(uniform_name(mr, ud, i), s_bgfx_uniform_type[ud->type]).idx; } - - create_material(mr); } void MaterialManager::offline(StringId64 id, ResourceManager &rm) { using namespace material_resource; - MaterialResource *mr = (MaterialResource *)rm.get(RESOURCE_TYPE_MATERIAL, id); - - destroy_material(mr); - - char *base = (char *)mr + mr->dynamic_data_offset; + const MaterialResource *mr = (MaterialResource *)rm.get(RESOURCE_TYPE_MATERIAL, id); + Material *material = hash_map::get(_materials, mr, (Material *)NULL); const TextureData *td = texture_data_array(mr); for (u32 i = 0; i < mr->num_textures; ++i) { - TextureHandle *th = texture_handle(td, i, base); + TextureHandle *th = texture_handle(td, i, material->_data); bgfx::UniformHandle sh; sh.idx = th->sampler_handle; bgfx::destroy(sh); @@ -88,38 +86,38 @@ void MaterialManager::offline(StringId64 id, ResourceManager &rm) const UniformData *ud = uniform_data_array(mr); for (u32 i = 0; i < mr->num_uniforms; ++i) { - UniformHandle *uh = uniform_handle(ud, i, base); + UniformHandle *uh = uniform_handle(ud, i, material->_data); bgfx::UniformHandle bgfx_uh; bgfx_uh.idx = uh->uniform_handle; bgfx::destroy(bgfx_uh); } + + CE_DELETE(*_allocator, material); + hash_map::remove(_materials, mr); } Material *MaterialManager::create_material(const MaterialResource *resource) { - Material *mat = hash_map::get(_materials, resource, (Material *)NULL); - if (mat != NULL) - return mat; + Material *material = hash_map::get(_materials, resource, (Material *)NULL); + if (material != NULL) + return material; const u32 size = sizeof(Material) + resource->dynamic_data_size; - mat = (Material *)_allocator->allocate(size); - mat->_resource_manager = _resource_manager; - mat->_resource = resource; - mat->_data = (char *)&mat[1]; - - const char *data = (char *)resource + resource->dynamic_data_offset; - memcpy(mat->_data, data, resource->dynamic_data_size); + material = (Material *)_allocator->allocate(size); + new (material) Material(*_allocator); + material->_resource_manager = _resource_manager; + material->_resource = resource; + material->_data = (char *)&material[1]; - hash_map::set(_materials, resource, mat); - return mat; -} + const char *dynamic_data = (char *)resource + resource->dynamic_data_offset; + memcpy(material->_data, dynamic_data, resource->dynamic_data_size); -void MaterialManager::destroy_material(const MaterialResource *resource) -{ - Material *mat = hash_map::get(_materials, resource, (Material *)NULL); - _allocator->deallocate(mat); +#if CROWN_CAN_RELOAD + array::resize(material->_texture_resources, resource->num_textures); +#endif - hash_map::remove(_materials, resource); + hash_map::set(_materials, resource, material); + return material; } Material *MaterialManager::get(const MaterialResource *resource) @@ -128,4 +126,19 @@ Material *MaterialManager::get(const MaterialResource *resource) return hash_map::get(_materials, resource, (Material *)NULL); } +void MaterialManager::reload_textures(const TextureResource *old_resource, const TextureResource *new_resource) +{ +#if CROWN_CAN_RELOAD + auto cur = hash_map::begin(_materials); + auto end = hash_map::end(_materials); + for (; cur != end; ++cur) { + HASH_MAP_SKIP_HOLE(_materials, cur); + + cur->second->reload_textures(old_resource, new_resource); + } +#else + CE_UNUSED_2(old_resource, new_resource); +#endif +} + } // namespace crown diff --git a/src/world/material_manager.h b/src/world/material_manager.h index 36a0f70f1..605849c2a 100644 --- a/src/world/material_manager.h +++ b/src/world/material_manager.h @@ -35,11 +35,11 @@ struct MaterialManager /// Instantiates the material @a resource. Material *create_material(const MaterialResource *resource); - /// Destroys the instance of the material @a resource. - void destroy_material(const MaterialResource *resource); - /// Returns the instance of the material @a resource. Material *get(const MaterialResource *resource); + + /// + void reload_textures(const TextureResource *old_resource, const TextureResource *new_resource); }; } // namespace crown