diff --git a/SCsub b/SCsub index d34f991..fd6c345 100644 --- a/SCsub +++ b/SCsub @@ -10,6 +10,12 @@ if os.path.isdir('../mesh_data_resource'): if os.path.isdir('../props'): module_env.Append(CPPDEFINES=['PROPS_PRESENT']) +has_texture_packer = False + +if os.path.isdir('../texture_packer'): + has_texture_packer = True + module_env.Append(CPPDEFINES=['TEXTURE_PACKER_PRESENT']) + sources = [ "register_types.cpp", @@ -122,8 +128,13 @@ sources = [ "editor/ess_editor_plugin.cpp", "props/prop_data_entity.cpp", + + "material_cache/ess_material_cache.cpp" ] +if has_texture_packer: + sources.append("material_cache/ess_material_cache_pcm.cpp") + if ARGUMENTS.get('custom_modules_shared', 'no') == 'yes': # Shared lib compilation module_env.Append(CCFLAGS=['-fPIC']) diff --git a/config.py b/config.py index b0e06dd..5cd0b4b 100644 --- a/config.py +++ b/config.py @@ -103,6 +103,9 @@ def get_doc_classes(): "ESSEntitySpawner", "PropDataEntity", + + "ESSMaterialCache", + "ESSMaterialCachePCM", ] def get_doc_path(): diff --git a/material_cache/ess_material_cache.cpp b/material_cache/ess_material_cache.cpp new file mode 100644 index 0000000..f64e240 --- /dev/null +++ b/material_cache/ess_material_cache.cpp @@ -0,0 +1,370 @@ +/* +Copyright (c) 2019-2021 Péter Magyar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "ess_material_cache.h" + +#if PROPS_PRESENT +#include "../../props/props/prop_data.h" +#include "../../props/props/prop_data_prop.h" +#include "../../props/props/prop_data_tiled_wall.h" +#include "../../props/tiled_wall/tiled_wall_data.h" +#endif + +#include "../singletons/ess.h" + +#if MESH_DATA_RESOURCE_PRESENT +#define PROPS_PRESENT 1 +#include "../../mesh_data_resource/props/prop_data_mesh_data.h" +#undef PROPS_PRESENT +#endif + +#if VERSION_MAJOR > 3 + +#define VARIANT_ARRAY_GET(arr) \ + Vector r; \ + for (int i = 0; i < arr.size(); i++) { \ + r.push_back(arr[i]); \ + } \ + return r; + +#else + +#define VARIANT_ARRAY_GET(arr) \ + Vector r; \ + for (int i = 0; i < arr.size(); i++) { \ + r.push_back(arr[i].get_ref_ptr()); \ + } \ + return r; + +#endif + +bool ESSMaterialCache::get_initialized() { + return _initialized; +} +void ESSMaterialCache::set_initialized(const bool value) { + _initialized = value; +} + +bool ESSMaterialCache::mutex_locked() { + return _locked; +} +void ESSMaterialCache::mutex_lock() { + _mutex.lock(); +} +void ESSMaterialCache::mutex_unlock() { + _mutex.unlock(); +} + +int ESSMaterialCache::get_ref_count() { + return _ref_count; +} +void ESSMaterialCache::set_ref_count(const int value) { + _ref_count = value; +} +void ESSMaterialCache::inc_ref_count() { + _ref_count += 1; +} +void ESSMaterialCache::dec_ref_count() { + _ref_count -= 1; +} + +//Materials +Ref ESSMaterialCache::material_get(const int index) { + ERR_FAIL_INDEX_V(index, _materials.size(), Ref(NULL)); + + return _materials[index]; +} + +Ref ESSMaterialCache::material_lod_get(const int index) { + ERR_FAIL_COND_V(_materials.size() == 0, Ref(NULL)); + + if (index < 0) { + return _materials[0]; + } + + if (index >= _materials.size()) { + return _materials[_materials.size() - 1]; + } + + return _materials[index]; +} + +void ESSMaterialCache::material_add(const Ref &value) { + ERR_FAIL_COND(!value.is_valid()); + + _materials.push_back(value); +} + +void ESSMaterialCache::material_set(const int index, const Ref &value) { + ERR_FAIL_INDEX(index, _materials.size()); + + _materials.set(index, value); +} + +void ESSMaterialCache::material_remove(const int index) { + _materials.remove(index); +} + +int ESSMaterialCache::material_get_num() const { + return _materials.size(); +} + +void ESSMaterialCache::materials_clear() { + _materials.clear(); +} + +Vector ESSMaterialCache::materials_get() { + VARIANT_ARRAY_GET(_materials); +} + +void ESSMaterialCache::materials_set(const Vector &materials) { + _materials.clear(); + + for (int i = 0; i < materials.size(); i++) { + Ref material = Ref(materials[i]); + + _materials.push_back(material); + } +} + +void ESSMaterialCache::texture_add(const Ref &texture) { + _textures.push_back(texture); +} +void ESSMaterialCache::texture_remove(const Ref &texture) { + for (int i = 0; i < _textures.size(); ++i) { + if (_textures[i] == texture) { + _textures.remove(i); + return; + } + } +} +void ESSMaterialCache::texture_remove_index(const int index) { + ERR_FAIL_INDEX(index, _textures.size()); + + _textures.remove(index); +} +void ESSMaterialCache::textures_clear() { + _textures.clear(); +} +int ESSMaterialCache::texture_count() { + return _textures.size(); +} +Ref ESSMaterialCache::texture_get(const int index) { + ERR_FAIL_INDEX_V(index, _textures.size(), Ref()); + + return _textures[index]; +} +Ref ESSMaterialCache::texture_get_atlas(const int index) { + ERR_FAIL_INDEX_V(index, _textures.size(), Ref()); + + return texture_get_atlas_tex(_textures[index]); +} +Ref ESSMaterialCache::texture_get_atlas_tex(const Ref &texture) { + return Ref(); +} +Rect2 ESSMaterialCache::texture_get_uv_rect(const Ref &texture) { + return Rect2(0, 0, 1, 1); +} + +#if PROPS_PRESENT +void ESSMaterialCache::prop_add_textures(const Ref &prop) { + if (!prop.is_valid()) { + return; + } + + for (int i = 0; i < prop->get_prop_count(); ++i) { +#if MESH_DATA_RESOURCE_PRESENT + Ref pdm = prop->get_prop(i); + + if (pdm.is_valid()) { + Ref tex = pdm->get_texture(); + + if (!tex.is_valid()) + continue; + + texture_add(tex); + + continue; + } +#endif + + Ref pdtw = prop->get_prop(i); + + if (pdtw.is_valid()) { + Ref twd = pdtw->get_data(); + + if (!twd.is_valid()) + continue; + + twd->setup_cache(Ref(this)); + + continue; + } + + Ref pdp = prop->get_prop(i); + + if (pdp.is_valid()) { + prop_add_textures(pdp->get_prop()); + } + } +} +void ESSMaterialCache::prop_remove_textures(const Ref &prop) { + if (!prop.is_valid()) { + return; + } + + for (int i = 0; i < prop->get_prop_count(); ++i) { +#if MESH_DATA_RESOURCE_PRESENT + Ref pdm = prop->get_prop(i); + + if (pdm.is_valid()) { + Ref tex = pdm->get_texture(); + + if (!tex.is_valid()) + continue; + + texture_remove(tex); + } +#endif + + Ref pdtw = prop->get_prop(i); + + if (pdtw.is_valid()) { + Ref twd = pdtw->get_data(); + + if (!twd.is_valid()) + continue; + + for (int j = 0; j < twd->get_texture_count(); ++j) { + const Ref &tex = twd->get_texture(j); + + if (tex.is_valid()) { + texture_remove(tex); + } + } + + for (int j = 0; j < twd->get_flavour_texture_count(); ++j) { + const Ref &tex = twd->get_flavour_texture(j); + + if (tex.is_valid()) { + texture_remove(tex); + } + } + + continue; + } + + Ref pdp = prop->get_prop(i); + + if (pdp.is_valid()) { + prop_remove_textures(pdp); + } + } +} +#endif + +void ESSMaterialCache::refresh_rects() { + _initialized = true; +} + +void ESSMaterialCache::initial_setup_default() { + //Note: call only on the main thread! Shader->duplicate() can crash if done from an another thread! + + ESS *ess = ESS::get_singleton(); + + ess->ensure_materials_loaded(); + + int matc = ess->material_get_num(); + for (int i = 0; i < matc; ++i) { + Ref m = ess->material_get(i); + + ERR_CONTINUE(!m.is_valid()); + + Ref md = m->duplicate(); + + _materials.push_back(md); + } +} + +void ESSMaterialCache::setup_material_albedo(Ref texture) { + if (has_method("_setup_material_albedo")) + call("_setup_material_albedo", texture); +} + +ESSMaterialCache::ESSMaterialCache() { + _ref_count = 0; + _initialized = false; + _locked = false; +} + +ESSMaterialCache::~ESSMaterialCache() { + _materials.clear(); +} + +void ESSMaterialCache::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_initialized"), &ESSMaterialCache::get_initialized); + ClassDB::bind_method(D_METHOD("set_initialized", "value"), &ESSMaterialCache::set_initialized); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "initialized"), "set_initialized", "get_initialized"); + + ClassDB::bind_method(D_METHOD("mutex_locked"), &ESSMaterialCache::mutex_locked); + ClassDB::bind_method(D_METHOD("mutex_lock"), &ESSMaterialCache::mutex_lock); + ClassDB::bind_method(D_METHOD("mutex_unlock"), &ESSMaterialCache::mutex_unlock); + + ClassDB::bind_method(D_METHOD("get_ref_count"), &ESSMaterialCache::get_ref_count); + ClassDB::bind_method(D_METHOD("set_ref_count", "value"), &ESSMaterialCache::set_ref_count); + ADD_PROPERTY(PropertyInfo(Variant::INT, "mat_ref_count"), "set_ref_count", "get_ref_count"); + ClassDB::bind_method(D_METHOD("inc_ref_count"), &ESSMaterialCache::inc_ref_count); + ClassDB::bind_method(D_METHOD("dec_ref_count"), &ESSMaterialCache::dec_ref_count); + + BIND_VMETHOD(MethodInfo("_setup_material_albedo", PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"))); + + ClassDB::bind_method(D_METHOD("material_get", "index"), &ESSMaterialCache::material_get); + ClassDB::bind_method(D_METHOD("material_lod_get", "index"), &ESSMaterialCache::material_lod_get); + ClassDB::bind_method(D_METHOD("material_add", "value"), &ESSMaterialCache::material_add); + ClassDB::bind_method(D_METHOD("material_set", "index", "value"), &ESSMaterialCache::material_set); + ClassDB::bind_method(D_METHOD("material_remove", "index"), &ESSMaterialCache::material_remove); + ClassDB::bind_method(D_METHOD("material_get_num"), &ESSMaterialCache::material_get_num); + ClassDB::bind_method(D_METHOD("materials_clear"), &ESSMaterialCache::materials_clear); + + ClassDB::bind_method(D_METHOD("materials_get"), &ESSMaterialCache::materials_get); + ClassDB::bind_method(D_METHOD("materials_set"), &ESSMaterialCache::materials_set); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "materials", PROPERTY_HINT_NONE, "17/17:Material", PROPERTY_USAGE_DEFAULT, "Material"), "materials_set", "materials_get"); + + ClassDB::bind_method(D_METHOD("texture_add", "texture"), &ESSMaterialCache::texture_add); + ClassDB::bind_method(D_METHOD("texture_remove", "texture"), &ESSMaterialCache::texture_remove); + ClassDB::bind_method(D_METHOD("texture_remove_index", "index"), &ESSMaterialCache::texture_remove_index); + ClassDB::bind_method(D_METHOD("textures_clear"), &ESSMaterialCache::textures_clear); + ClassDB::bind_method(D_METHOD("texture_count"), &ESSMaterialCache::texture_count); + ClassDB::bind_method(D_METHOD("texture_get", "index"), &ESSMaterialCache::texture_get); + ClassDB::bind_method(D_METHOD("texture_get_atlas", "index"), &ESSMaterialCache::texture_get_atlas); + ClassDB::bind_method(D_METHOD("texture_get_atlas_tex", "index"), &ESSMaterialCache::texture_get_atlas_tex); + ClassDB::bind_method(D_METHOD("texture_get_uv_rect", "texture"), &ESSMaterialCache::texture_get_uv_rect); + +#if PROPS_PRESENT + ClassDB::bind_method(D_METHOD("prop_add_textures", "prop"), &ESSMaterialCache::prop_add_textures); + ClassDB::bind_method(D_METHOD("prop_remove_textures", "prop"), &ESSMaterialCache::prop_remove_textures); +#endif + + ClassDB::bind_method(D_METHOD("refresh_rects"), &ESSMaterialCache::refresh_rects); + + ClassDB::bind_method(D_METHOD("setup_material_albedo", "texture"), &ESSMaterialCache::setup_material_albedo); +} diff --git a/material_cache/ess_material_cache.h b/material_cache/ess_material_cache.h new file mode 100644 index 0000000..cf6e8b4 --- /dev/null +++ b/material_cache/ess_material_cache.h @@ -0,0 +1,109 @@ +/* +Copyright (c) 2019-2021 Péter Magyar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef ESS_MATERIAL_CACHE_H +#define ESS_MATERIAL_CACHE_H + +#include "core/version.h" + +#if VERSION_MAJOR > 3 +#include "core/io/resource.h" +#include "core/math/color.h" +#include "core/templates/vector.h" +#else +#include "core/color.h" +#include "core/resource.h" +#include "core/vector.h" +#endif + +#include "core/math/rect2.h" +#include "scene/resources/material.h" +#include "core/os/mutex.h" + +class PropData; + +class ESSMaterialCache : public Resource { + GDCLASS(ESSMaterialCache, Resource) + +public: + bool get_initialized(); + void set_initialized(const bool value); + + bool mutex_locked(); + void mutex_lock(); + void mutex_unlock(); + + int get_ref_count(); + void set_ref_count(const int value); + void inc_ref_count(); + void dec_ref_count(); + + Ref material_get(const int index); + Ref material_lod_get(const int index); + void material_add(const Ref &value); + void material_set(const int index, const Ref &value); + void material_remove(const int index); + int material_get_num() const; + void materials_clear(); + + Vector materials_get(); + void materials_set(const Vector &materials); + + virtual void texture_add(const Ref &texture); + virtual void texture_remove(const Ref &texture); + virtual void texture_remove_index(const int index); + virtual void textures_clear(); + virtual int texture_count(); + virtual Ref texture_get(const int index); + virtual Ref texture_get_atlas(const int index); + virtual Ref texture_get_atlas_tex(const Ref &texture); + virtual Rect2 texture_get_uv_rect(const Ref &texture); + +#if PROPS_PRESENT + void prop_add_textures(const Ref &prop); + void prop_remove_textures(const Ref &prop); +#endif + + virtual void refresh_rects(); + + virtual void initial_setup_default(); + + void setup_material_albedo(Ref texture); + + ESSMaterialCache(); + ~ESSMaterialCache(); + +protected: + static void _bind_methods(); + + bool _locked; + bool _initialized; + + Vector> _materials; + Vector> _textures; + + int _ref_count; + + Mutex _mutex; +}; + +#endif diff --git a/material_cache/ess_material_cache_pcm.cpp b/material_cache/ess_material_cache_pcm.cpp new file mode 100644 index 0000000..0a42d34 --- /dev/null +++ b/material_cache/ess_material_cache_pcm.cpp @@ -0,0 +1,206 @@ +/* +Copyright (c) 2019-2021 Péter Magyar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "ess_material_cache_pcm.h" + +#include "../../texture_packer/texture_packer.h" +#include "../singletons/ess.h" +#include "scene/resources/texture.h" + +int ESSMaterialCachePCM::get_texture_flags() const { + return _packer->get_texture_flags(); +} +void ESSMaterialCachePCM::set_texture_flags(const int flags) { + _packer->set_texture_flags(flags); +} + +int ESSMaterialCachePCM::get_max_atlas_size() const { + return _packer->get_max_atlas_size(); +} +void ESSMaterialCachePCM::set_max_atlas_size(const int size) { + _packer->set_max_atlas_size(size); +} + +bool ESSMaterialCachePCM::get_keep_original_atlases() const { + return _packer->get_keep_original_atlases(); +} +void ESSMaterialCachePCM::set_keep_original_atlases(const bool value) { + _packer->set_keep_original_atlases(value); +} + +Color ESSMaterialCachePCM::get_background_color() const { + return _packer->get_background_color(); +} +void ESSMaterialCachePCM::set_background_color(const Color &color) { + _packer->set_background_color(color); +} + +int ESSMaterialCachePCM::get_margin() const { + return _packer->get_margin(); +} +void ESSMaterialCachePCM::set_margin(const int margin) { + _packer->set_margin(margin); +} + +Ref ESSMaterialCachePCM::texture_get_atlas_tex(const Ref &texture) { + if (!_packer->contains_texture(texture)) { + return Ref(); + } + + return _packer->get_texture(texture); +} +Rect2 ESSMaterialCachePCM::texture_get_uv_rect(const Ref &texture) { + if (!texture.is_valid()) { + return Rect2(0, 0, 1, 1); + } + + Ref at = _packer->get_texture(texture); + + if (!at.is_valid()) { + return Rect2(0, 0, 1, 1); + } + + Rect2 region = at->get_region(); + + Ref tex = at->get_atlas(); + + if (!tex.is_valid()) { + return Rect2(0, 0, 1, 1); + } + + Ref image = tex->get_data(); + + if (!image.is_valid()) { + return Rect2(0, 0, 1, 1); + } + + float w = image->get_width(); + float h = image->get_height(); + + region.position = Size2(region.position.x / w, region.position.y / h); + region.size = Size2(region.size.x / w, region.size.y / h); + + return region; +} + +void ESSMaterialCachePCM::refresh_rects() { + bool texture_added = false; + + for (int i = 0; i < _textures.size(); i++) { + Ref tex = _textures.get(i); + + ERR_CONTINUE(!tex.is_valid()); + + if (!_packer->contains_texture(tex)) { + _packer->add_texture(tex); + texture_added = true; + } + } + + if (texture_added) { + _packer->merge(); + + ERR_FAIL_COND(_packer->get_texture_count() == 0); + + Ref tex = _packer->get_generated_texture(0); + + setup_material_albedo(tex); + } + + _initialized = true; +} + +void ESSMaterialCachePCM::initial_setup_default() { + ESSMaterialCache::initial_setup_default(); + + ESS *ess = ESS::get_singleton(); + + set_texture_flags(ess->get_texture_flags()); + set_max_atlas_size(ess->get_max_atlas_size()); + set_keep_original_atlases(ess->get_keep_original_atlases()); + set_background_color(ess->get_background_color()); + set_margin(ess->get_margin()); +} + +void ESSMaterialCachePCM::_setup_material_albedo(Ref texture) { + int count = material_get_num(); + + for (int i = 0; i < count; ++i) { + Ref m = material_get(i); + + Ref spmat = m; + + if (spmat.is_valid()) { + spmat->set_texture(SpatialMaterial::TEXTURE_ALBEDO, texture); + return; + } + + Ref shmat = m; + + if (shmat.is_valid()) { + shmat->set_shader_param("texture_albedo", texture); + } + } +} + +ESSMaterialCachePCM::ESSMaterialCachePCM() { + _packer.instance(); + +#if GODOT4 +#warning implement +#else + _packer->set_texture_flags(Texture::FLAG_MIPMAPS | Texture::FLAG_FILTER); +#endif + + _packer->set_max_atlas_size(1024); + _packer->set_keep_original_atlases(false); + _packer->set_margin(0); +} + +ESSMaterialCachePCM::~ESSMaterialCachePCM() { + _packer->clear(); + _packer.unref(); +} + +void ESSMaterialCachePCM::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_texture_flags"), &ESSMaterialCachePCM::get_texture_flags); + ClassDB::bind_method(D_METHOD("set_texture_flags", "flags"), &ESSMaterialCachePCM::set_texture_flags); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic Linear,Convert to Linear,Mirrored Repeat,Video Surface"), "set_texture_flags", "get_texture_flags"); + + ClassDB::bind_method(D_METHOD("get_max_atlas_size"), &ESSMaterialCachePCM::get_max_atlas_size); + ClassDB::bind_method(D_METHOD("set_max_atlas_size", "size"), &ESSMaterialCachePCM::set_max_atlas_size); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_atlas_size"), "set_max_atlas_size", "get_max_atlas_size"); + + ClassDB::bind_method(D_METHOD("get_keep_original_atlases"), &ESSMaterialCachePCM::get_keep_original_atlases); + ClassDB::bind_method(D_METHOD("set_keep_original_atlases", "value"), &ESSMaterialCachePCM::set_keep_original_atlases); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_original_atlases"), "set_keep_original_atlases", "get_keep_original_atlases"); + + ClassDB::bind_method(D_METHOD("get_background_color"), &ESSMaterialCachePCM::get_background_color); + ClassDB::bind_method(D_METHOD("set_background_color", "color"), &ESSMaterialCachePCM::set_background_color); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "background_color"), "set_background_color", "get_background_color"); + + ClassDB::bind_method(D_METHOD("get_margin"), &ESSMaterialCachePCM::get_margin); + ClassDB::bind_method(D_METHOD("set_margin", "size"), &ESSMaterialCachePCM::set_margin); + ADD_PROPERTY(PropertyInfo(Variant::INT, "margin"), "set_margin", "get_margin"); + + ClassDB::bind_method(D_METHOD("_setup_material_albedo", "texture"), &ESSMaterialCachePCM::_setup_material_albedo); +} diff --git a/material_cache/ess_material_cache_pcm.h b/material_cache/ess_material_cache_pcm.h new file mode 100644 index 0000000..5390f35 --- /dev/null +++ b/material_cache/ess_material_cache_pcm.h @@ -0,0 +1,83 @@ +/* +Copyright (c) 2019-2021 Péter Magyar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef ESS_MATERIAL_CACHE_PCM_H +#define ESS_MATERIAL_CACHE_PCM_H + +#include "ess_material_cache.h" + +#include "core/version.h" + +#if VERSION_MAJOR > 3 +#include "core/io/resource.h" +#include "core/math/color.h" +#include "core/templates/vector.h" +#else +#include "core/color.h" +#include "core/resource.h" +#include "core/vector.h" +#endif + +#include "core/math/rect2.h" +#include "scene/resources/material.h" + +class TexturePacker; +class PropData; + +class ESSMaterialCachePCM : public ESSMaterialCache { + GDCLASS(ESSMaterialCachePCM, ESSMaterialCache); + +public: + int get_texture_flags() const; + void set_texture_flags(const int flags); + + int get_max_atlas_size() const; + void set_max_atlas_size(const int size); + + bool get_keep_original_atlases() const; + void set_keep_original_atlases(const bool value); + + Color get_background_color() const; + void set_background_color(const Color &color); + + int get_margin() const; + void set_margin(const int margin); + + Ref texture_get_atlas_tex(const Ref &texture); + Rect2 texture_get_uv_rect(const Ref &texture); + + void refresh_rects(); + + void initial_setup_default(); + + void _setup_material_albedo(Ref texture); + + ESSMaterialCachePCM(); + ~ESSMaterialCachePCM(); + +protected: + static void _bind_methods(); + + Ref _packer; +}; + +#endif diff --git a/register_types.cpp b/register_types.cpp index f3bd398..968626d 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -131,6 +131,9 @@ SOFTWARE. #include "database/ess_resource_db_map.h" #include "database/ess_resource_db_static.h" +#include "material_cache/ess_material_cache.h" +#include "material_cache/ess_material_cache_pcm.h" + #if PROPS_PRESENT #include "props/prop_data_entity.h" #endif @@ -263,6 +266,9 @@ void register_entity_spell_system_types() { ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); + entity_data_manager = memnew(ESS); ClassDB::register_class(); Engine::get_singleton()->add_singleton(Engine::Singleton("ESS", ESS::get_singleton())); diff --git a/singletons/ess.cpp b/singletons/ess.cpp index ef7ebf8..3fd39b5 100644 --- a/singletons/ess.cpp +++ b/singletons/ess.cpp @@ -23,6 +23,7 @@ SOFTWARE. #include "ess.h" #include "../database/ess_resource_db.h" +#include "../material_cache/ess_material_cache.h" #include "../spawners/ess_entity_spawner.h" #include "../utility/entity_create_info.h" @@ -127,22 +128,6 @@ void ESS::load_resource_db() { _ess_resource_db = d; } -Ref ESS::load_resource(const String &path, const String &type_hint) { - _ResourceLoader *rl = _ResourceLoader::get_singleton(); - -#if VERSION_MAJOR < 4 - Ref resl = rl->load_interactive(path, type_hint); - - ERR_FAIL_COND_V(!resl.is_valid(), Ref()); - - resl->wait(); - - return resl->get_resource(); -#else - return rl->load(path, type_hint); -#endif -} - void ESS::load_all() { load_resource_db(); @@ -509,6 +494,187 @@ void ESS::set_class_xp_data(const PoolIntArray &data) { _class_xps = data; } +#ifdef TEXTURE_PACKER_PRESENT +int ESS::get_texture_flags() const { + return _texture_flags; +} +void ESS::set_texture_flags(const int flags) { + _texture_flags = flags; +} + +int ESS::get_max_atlas_size() const { + return _max_atlas_size; +} +void ESS::set_max_atlas_size(const int size) { + _max_atlas_size = size; +} + +bool ESS::get_keep_original_atlases() const { + return _keep_original_atlases; +} +void ESS::set_keep_original_atlases(const bool value) { + _keep_original_atlases = value; +} + +Color ESS::get_background_color() const { + return _background_color; +} +void ESS::set_background_color(const Color &color) { + _background_color = color; +} + +int ESS::get_margin() const { + return _margin; +} +void ESS::set_margin(const int margin) { + _margin = margin; +} +#endif + +StringName ESS::get_default_ess_material_cache_class() { + return _default_ess_material_cache_class; +} +void ESS::set_default_ess_material_cache_class(const StringName &cls_name) { + _default_ess_material_cache_class = cls_name; +} + +PoolStringArray ESS::material_paths_get() const { + return _material_paths; +} +void ESS::material_paths_set(const PoolStringArray &value) { + _material_paths = value; +} + +void ESS::material_add(const Ref &value) { + ERR_FAIL_COND(!value.is_valid()); + + _materials.push_back(value); +} + +Ref ESS::material_get(const int index) { + ERR_FAIL_INDEX_V(index, _materials.size(), Ref()); + + return _materials[index]; +} + +void ESS::material_set(const int index, const Ref &value) { + ERR_FAIL_INDEX(index, _materials.size()); + + _materials.set(index, value); +} + +void ESS::material_remove(const int index) { + _materials.remove(index); +} + +int ESS::material_get_num() const { + return _materials.size(); +} + +void ESS::materials_clear() { + _materials.clear(); +} + +void ESS::materials_load() { + _materials.clear(); + + for (int i = 0; i < _material_paths.size(); ++i) { + StringName path = _material_paths[i]; + + ERR_CONTINUE(path == ""); + + Ref d = load_resource(path, "Material"); + + ERR_CONTINUE(!d.is_valid()); + + _materials.push_back(d); + } +} + +void ESS::ensure_materials_loaded() { + if (_materials.size() != _material_paths.size()) { + materials_load(); + } +} + +Vector ESS::materials_get() { + VARIANT_ARRAY_GET(_materials); +} + +void ESS::materials_set(const Vector &materials) { + _materials.clear(); + + for (int i = 0; i < materials.size(); i++) { + Ref material = Ref(materials[i]); + + _materials.push_back(material); + } +} + +Ref ESS::material_cache_get(const uint64_t key) { + _material_cache_mutex.lock(); + + if (_material_cache.has(key)) { + Ref m = _material_cache[key]; + + m->inc_ref_count(); + + _material_cache_mutex.unlock(); + + return m; + } + + ESSMaterialCache *p = Object::cast_to(ClassDB::instance(_default_ess_material_cache_class)); + + if (!p) { + ERR_PRINT("Can't instance the given ESSMaterialCache! class_name: " + String(_default_ess_material_cache_class)); + } + + Ref m(p); + + _material_cache[key] = m; + + _material_cache_mutex.unlock(); + + return m; +} +void ESS::material_cache_unref(const uint64_t key) { + _material_cache_mutex.lock(); + + if (!_material_cache.has(key)) { + _material_cache_mutex.unlock(); + + ERR_PRINT("ESS::material_cache_custom_key_unref: can't find cache!"); + + return; + } + + Ref m = _material_cache[key]; + + m->dec_ref_count(); + if (m->get_ref_count() <= 0) { + _material_cache.erase(key); + } + + _material_cache_mutex.unlock(); +} + +Ref ESS::load_resource(const String &path, const String &type_hint) { + _ResourceLoader *rl = _ResourceLoader::get_singleton(); + +#if VERSION_MAJOR < 4 + Ref resl = rl->load_interactive(path, type_hint); + + ERR_FAIL_COND_V(!resl.is_valid(), Ref()); + + resl->wait(); + + return resl->get_resource(); +#else + return rl->load(path, type_hint); +#endif +} + void ESS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_use_spell_points"), &ESS::get_use_spell_points); ClassDB::bind_method(D_METHOD("set_use_spell_points", "value"), &ESS::set_use_spell_points); @@ -650,6 +816,52 @@ void ESS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_class_xp_data"), &ESS::get_class_xp_data); ClassDB::bind_method(D_METHOD("set_class_xp_data", "data"), &ESS::set_character_xp_data); ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "class_xp_data"), "set_class_xp_data", "get_class_xp_data"); + +#ifdef TEXTURE_PACKER_PRESENT + ClassDB::bind_method(D_METHOD("get_texture_flags"), &ESS::get_texture_flags); + ClassDB::bind_method(D_METHOD("set_texture_flags", "flags"), &ESS::set_texture_flags); + ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic Linear,Convert to Linear,Mirrored Repeat,Video Surface"), "set_texture_flags", "get_texture_flags"); + + ClassDB::bind_method(D_METHOD("get_max_atlas_size"), &ESS::get_max_atlas_size); + ClassDB::bind_method(D_METHOD("set_max_atlas_size", "size"), &ESS::set_max_atlas_size); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_atlas_size"), "set_max_atlas_size", "get_max_atlas_size"); + + ClassDB::bind_method(D_METHOD("get_keep_original_atlases"), &ESS::get_keep_original_atlases); + ClassDB::bind_method(D_METHOD("set_keep_original_atlases", "value"), &ESS::set_keep_original_atlases); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_original_atlases"), "set_keep_original_atlases", "get_keep_original_atlases"); + + ClassDB::bind_method(D_METHOD("get_background_color"), &ESS::get_background_color); + ClassDB::bind_method(D_METHOD("set_background_color", "color"), &ESS::set_background_color); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "background_color"), "set_background_color", "get_background_color"); + + ClassDB::bind_method(D_METHOD("get_margin"), &ESS::get_margin); + ClassDB::bind_method(D_METHOD("set_margin", "size"), &ESS::set_margin); + ADD_PROPERTY(PropertyInfo(Variant::INT, "margin"), "set_margin", "get_margin"); +#endif + + ClassDB::bind_method(D_METHOD("get_default_ess_material_cache_class"), &ESS::get_default_ess_material_cache_class); + ClassDB::bind_method(D_METHOD("set_default_ess_material_cache_class", "cls_name"), &ESS::set_default_ess_material_cache_class); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "default_ess_material_cache_class"), "set_default_ess_material_cache_class", "get_default_ess_material_cache_class"); + + ClassDB::bind_method(D_METHOD("material_paths_get"), &ESS::material_paths_get); + ClassDB::bind_method(D_METHOD("material_paths_set", "value"), &ESS::material_paths_set); + ADD_PROPERTY(PropertyInfo(Variant::POOL_STRING_ARRAY, "material_paths"), "material_paths_set", "material_paths_get"); + + ClassDB::bind_method(D_METHOD("material_add", "value"), &ESS::material_add); + ClassDB::bind_method(D_METHOD("material_get", "index"), &ESS::material_get); + ClassDB::bind_method(D_METHOD("material_set", "index", "value"), &ESS::material_set); + ClassDB::bind_method(D_METHOD("material_remove", "index"), &ESS::material_remove); + ClassDB::bind_method(D_METHOD("material_get_num"), &ESS::material_get_num); + ClassDB::bind_method(D_METHOD("materials_clear"), &ESS::materials_clear); + ClassDB::bind_method(D_METHOD("materials_load"), &ESS::materials_load); + ClassDB::bind_method(D_METHOD("ensure_materials_loaded"), &ESS::ensure_materials_loaded); + + ClassDB::bind_method(D_METHOD("materials_get"), &ESS::materials_get); + ClassDB::bind_method(D_METHOD("materials_set"), &ESS::materials_set); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "materials", PROPERTY_HINT_NONE, "17/17:Material", PROPERTY_USAGE_DEFAULT, "Material"), "materials_set", "materials_get"); + + ClassDB::bind_method(D_METHOD("material_cache_get", "key"), &ESS::material_cache_get); + ClassDB::bind_method(D_METHOD("material_cache_unref", "key"), &ESS::material_cache_unref); } ESS::ESS() { @@ -690,6 +902,27 @@ ESS::ESS() { _class_xps = GLOBAL_DEF("ess/xp/class_xps", PoolIntArray()); _character_xps = GLOBAL_DEF("ess/xp/character_xps", PoolIntArray()); +#if TEXTURE_PACKER_PRESENT + _default_ess_material_cache_class = GLOBAL_DEF("ess/material_cache/default_ess_material_cache_class", "ESSMaterialCachePCM"); +#else + _default_ess_material_cache_class = GLOBAL_DEF("ess/material_cache/default_ess_material_cache_class", "ESSMaterialCache"); +#endif + +#ifdef TEXTURE_PACKER_PRESENT +#if VERSION_MAJOR < 4 + _texture_flags = GLOBAL_DEF("ess/material_cache/texture_flags", Texture::FLAG_MIPMAPS | Texture::FLAG_FILTER); +#else + _texture_flags = GLOBAL_DEF("ess/material_cache/texture_flags", 0); +#endif + + _max_atlas_size = GLOBAL_DEF("ess/material_cache/max_atlas_size", 1024); + _keep_original_atlases = GLOBAL_DEF("ess/material_cache/keep_original_atlases", false); + _background_color = GLOBAL_DEF("ess/material_cache/background_color", Color()); + _margin = GLOBAL_DEF("ess/material_cache/margin", 0); +#endif + + _material_paths = GLOBAL_DEF("ess/material_cache/material_paths", PoolStringArray()); + if (!Engine::get_singleton()->is_editor_hint() && _automatic_load) { call_deferred("load_all"); } diff --git a/singletons/ess.h b/singletons/ess.h index a6d2002..b895569 100644 --- a/singletons/ess.h +++ b/singletons/ess.h @@ -26,17 +26,17 @@ SOFTWARE. #include "core/version.h" #if VERSION_MAJOR > 3 -#include "core/object/object.h" -#include "core/io/resource.h" -#include "core/string/ustring.h" #include "core/config/engine.h" #include "core/core_bind.h" +#include "core/io/resource.h" +#include "core/object/object.h" +#include "core/string/ustring.h" #else +#include "core/bind/core_bind.h" +#include "core/engine.h" #include "core/object.h" #include "core/resource.h" #include "core/ustring.h" -#include "core/engine.h" -#include "core/bind/core_bind.h" #endif #include "scene/main/node.h" @@ -46,6 +46,7 @@ SOFTWARE. class ESSResourceDB; class ESSEntitySpawner; class EntityCreateInfo; +class ESSMaterialCache; class ESS : public Object { GDCLASS(ESS, Object); @@ -181,6 +182,44 @@ public: PoolIntArray get_class_xp_data(); void set_class_xp_data(const PoolIntArray &data); +#ifdef TEXTURE_PACKER_PRESENT + int get_texture_flags() const; + void set_texture_flags(const int flags); + + int get_max_atlas_size() const; + void set_max_atlas_size(const int size); + + bool get_keep_original_atlases() const; + void set_keep_original_atlases(const bool value); + + Color get_background_color() const; + void set_background_color(const Color &color); + + int get_margin() const; + void set_margin(const int margin); +#endif + + StringName get_default_ess_material_cache_class(); + void set_default_ess_material_cache_class(const StringName &cls_name); + + PoolStringArray material_paths_get() const; + void material_paths_set(const PoolStringArray &array); + + void material_add(const Ref &value); + Ref material_get(const int index); + void material_set(const int index, const Ref &value); + void material_remove(const int index); + int material_get_num() const; + void materials_clear(); + void materials_load(); + void ensure_materials_loaded(); + + Vector materials_get(); + void materials_set(const Vector &materials); + + Ref material_cache_get(const uint64_t key); + void material_cache_unref(const uint64_t key); + ESS(); ~ESS(); @@ -242,6 +281,23 @@ private: //Levels/XP PoolIntArray _class_xps; PoolIntArray _character_xps; + + StringName _default_ess_material_cache_class; + + Mutex _material_cache_mutex; + + Map> _material_cache; + +#ifdef TEXTURE_PACKER_PRESENT + int _texture_flags; + int _max_atlas_size; + bool _keep_original_atlases; + Color _background_color; + int _margin; +#endif + + PoolStringArray _material_paths; + Vector> _materials; }; #endif