diff --git a/SCsub b/SCsub index 7d56ca6..2bb6c40 100644 --- a/SCsub +++ b/SCsub @@ -32,6 +32,7 @@ sources = [ "library/voxel_surface.cpp", "library/voxel_surface_simple.cpp", + "library/voxel_material_cache.cpp", "data/voxel_light.cpp", @@ -84,6 +85,8 @@ sources = [ if has_texture_packer: sources.append("library/voxel_library_merger.cpp") sources.append("library/voxel_surface_merger.cpp") + sources.append("library/voxel_library_merger_pcm.cpp") + sources.append("library/voxel_material_cache_pcm.cpp") if ARGUMENTS.get('custom_modules_shared', 'no') == 'yes': # Shared lib compilation diff --git a/config.py b/config.py index be52a38..5d24018 100644 --- a/config.py +++ b/config.py @@ -24,6 +24,10 @@ def get_doc_classes(): "VoxelLibraryMerger", "VoxelLibrarySimple", "VoxelLibrary", + "VoxelLibraryMergerPCM", + + "VoxelMaterialCache", + "VoxelMaterialCachePCM", "VoxelCubePoints", "VoxelMesherCubic", diff --git a/doc_classes/VoxelChunk.xml b/doc_classes/VoxelChunk.xml index 5d404c6..8982108 100644 --- a/doc_classes/VoxelChunk.xml +++ b/doc_classes/VoxelChunk.xml @@ -702,16 +702,28 @@ + + + + + + + + + + + + diff --git a/doc_classes/VoxelLibraryMergerPCM.xml b/doc_classes/VoxelLibraryMergerPCM.xml new file mode 100644 index 0000000..33ac332 --- /dev/null +++ b/doc_classes/VoxelLibraryMergerPCM.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc_classes/VoxelMaterialCache.xml b/doc_classes/VoxelMaterialCache.xml new file mode 100644 index 0000000..5dd3e9f --- /dev/null +++ b/doc_classes/VoxelMaterialCache.xml @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc_classes/VoxelMaterialCachePCM.xml b/doc_classes/VoxelMaterialCachePCM.xml new file mode 100644 index 0000000..80caef9 --- /dev/null +++ b/doc_classes/VoxelMaterialCachePCM.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library/voxel_library.h b/library/voxel_library.h index b2af09d..84dfdcc 100644 --- a/library/voxel_library.h +++ b/library/voxel_library.h @@ -135,7 +135,6 @@ public: protected: static void _bind_methods(); -private: bool _initialized; Vector > _materials; Vector > _liquid_materials; diff --git a/library/voxel_library_merger.h b/library/voxel_library_merger.h index c668ec6..a75c77b 100644 --- a/library/voxel_library_merger.h +++ b/library/voxel_library_merger.h @@ -104,7 +104,6 @@ protected: static void _bind_methods(); -private: Vector > _voxel_surfaces; #ifdef PROPS_PRESENT Vector > _props; diff --git a/library/voxel_library_merger_pcm.cpp b/library/voxel_library_merger_pcm.cpp new file mode 100644 index 0000000..4b10d88 --- /dev/null +++ b/library/voxel_library_merger_pcm.cpp @@ -0,0 +1,813 @@ +/* +Copyright (c) 2019-2022 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 "voxel_library_merger_pcm.h" + +#include "../../texture_packer/texture_packer.h" +#include "scene/resources/packed_scene.h" +#include "scene/resources/texture.h" + +#ifdef PROPS_PRESENT +#include "../../props/props/prop_data.h" + +#include "../../props/props/prop_data_prop.h" + +#if MESH_DATA_RESOURCE_PRESENT +#include "../../mesh_data_resource/props/prop_data_mesh_data.h" +#endif +#endif + +#include "voxel_material_cache_pcm.h" + +#include "../defines.h" + +#include "../world/default/voxel_chunk_default.h" + +#include "core/hashfuncs.h" + +bool VoxelLibraryMergerPCM::_supports_caching() { + return true; +} + +void VoxelLibraryMergerPCM::_material_cache_get_key(Ref chunk) { + uint8_t *ch = chunk->channel_get(VoxelChunkDefault::DEFAULT_CHANNEL_TYPE); + + if (!ch) { + chunk->material_cache_key_set(0); + chunk->material_cache_key_has_set(false); + + return; + } + + Vector surfaces; + + uint32_t size = chunk->get_data_size(); + + for (uint32_t i = 0; i < size; ++i) { + uint8_t v = ch[i]; + + if (v == 0) { + continue; + } + + int ssize = surfaces.size(); + bool found = false; + for (uint8_t j = 0; j < ssize; ++j) { + if (surfaces[j] == v) { + found = true; + break; + } + } + + if (!found) { + surfaces.push_back(v); + } + } + + if (surfaces.size() == 0) { + chunk->material_cache_key_set(0); + chunk->material_cache_key_has_set(false); + + return; + } + + surfaces.sort(); + + String hstr; + + for (int i = 0; i < surfaces.size(); ++i) { + hstr += String::num(surfaces[i]) + "|"; + } + + int hash = static_cast(hstr.hash()); + + chunk->material_cache_key_set(hash); + chunk->material_cache_key_has_set(true); + + _material_cache_mutex.lock(); + + if (_material_cache.has(hash)) { + Ref cc = _material_cache[hash]; + + if (cc.is_valid()) { + cc->inc_ref_count(); + } + + _material_cache_mutex.unlock(); + + return; + } + + //print_error("New cache: " + hstr); + + Ref cache; + cache.instance(); + cache->inc_ref_count(); + + cache->set_texture_flags(get_texture_flags()); + cache->set_max_atlas_size(get_max_atlas_size()); + cache->set_keep_original_atlases(get_keep_original_atlases()); + cache->set_background_color(get_background_color()); + cache->set_margin(get_margin()); + + for (int i = 0; i < surfaces.size(); ++i) { + int s = surfaces[i] - 1; + + if (_voxel_surfaces.size() <= s) { + continue; + } + + Ref ms = _voxel_surfaces[s]; + + if (!ms.is_valid()) { + continue; + } + + Ref nms = ms->duplicate(); + nms->set_library(Ref(this)); + nms->set_id(s); + + cache->surface_add(nms); + } + + for (int i = 0; i < _materials.size(); ++i) { + Ref m = _materials[i]; + + if (!m.is_valid()) { + continue; + } + + Ref nm = m->duplicate(); + + cache->material_add(nm); + } + + _material_cache[hash] = cache; + + //unlock here, so if a different thread need the cache it will be able to immediately access the materials and surfaces when it gets it. + _material_cache_mutex.unlock(); + + //this will generate the atlases + cache->refresh_rects(); +} + +Ref VoxelLibraryMergerPCM::_material_cache_get(const int key) { + _material_cache_mutex.lock(); + + ERR_FAIL_COND_V(!_material_cache.has(key), Ref()); + + Ref c = _material_cache[key]; + + _material_cache_mutex.unlock(); + + return c; +} + +void VoxelLibraryMergerPCM::_material_cache_unref(const int key) { + _material_cache_mutex.lock(); + + if (!_material_cache.has(key)) { + return; + } + + Ref cc = _material_cache[key]; + + if (!cc.is_valid()) { + return; + } + + cc->dec_ref_count(); + + if (cc->get_ref_count() <= 0) { + _material_cache.erase(key); + } + + _material_cache_mutex.unlock(); +} + +void VoxelLibraryMergerPCM::_prop_material_cache_get_key(Ref chunk) { + Vector props; + +/* +#ifdef PROPS_PRESENT + for (int i = 0; i < chunk->prop_get_count(); ++i) { + Ref prop = chunk->prop_get(i); + + ERR_CONTINUE(!prop.is_valid()); + + //get pointer's value as uint64 + uint64_t v = make_uint64_t(*prop); + + int psize = props.size(); + bool found = false; + for (int j = 0; j < psize; ++j) { + if (props[j] == v) { + found = true; + break; + } + } + + if (!found) { + props.push_back(v); + } + } +#endif +*/ + +#if MESH_DATA_RESOURCE_PRESENT + for (int i = 0; i < chunk->mesh_data_resource_get_count(); ++i) { + Ref tex = chunk->mesh_data_resource_get_texture(i); + + if (!tex.is_valid()) + continue; + + //get pointer's value as uint64 + uint64_t v = make_uint64_t(*tex); + + int psize = props.size(); + bool found = false; + for (int j = 0; j < psize; ++j) { + if (props[j] == v) { + found = true; + break; + } + } + + if (!found) { + props.push_back(v); + } + } +#endif + + if (props.size() == 0) { + chunk->prop_material_cache_key_set(0); + chunk->prop_material_cache_key_has_set(false); + + return; + } + + props.sort(); + + String hstr; + + for (int i = 0; i < props.size(); ++i) { + hstr += String::num_uint64(props[i]) + "|"; + } + + int hash = static_cast(hstr.hash()); + + chunk->prop_material_cache_key_set(hash); + chunk->prop_material_cache_key_has_set(true); + + _prop_material_cache_mutex.lock(); + + if (_prop_material_cache.has(hash)) { + Ref cc = _prop_material_cache[hash]; + + if (cc.is_valid()) { + cc->inc_ref_count(); + } + + _prop_material_cache_mutex.unlock(); + + return; + } + + //print_error("New prop cache: " + hstr); + + Ref cache; + cache.instance(); + cache->inc_ref_count(); + + cache->set_texture_flags(get_texture_flags()); + cache->set_max_atlas_size(get_max_atlas_size()); + cache->set_keep_original_atlases(get_keep_original_atlases()); + cache->set_background_color(get_background_color()); + cache->set_margin(get_margin()); + + for (int i = 0; i < _prop_materials.size(); ++i) { + Ref m = _prop_materials[i]; + + if (!m.is_valid()) { + continue; + } + + Ref nm = m->duplicate(); + + cache->material_add(nm); + } + +/* +#ifdef PROPS_PRESENT + for (int i = 0; i < chunk->prop_get_count(); ++i) { + Ref prop = chunk->prop_get(i); + + ERR_CONTINUE(!prop.is_valid()); + + cache->prop_add_textures(prop); + } +#endif +*/ + +#if MESH_DATA_RESOURCE_PRESENT + for (int i = 0; i < chunk->mesh_data_resource_get_count(); ++i) { + Ref tex = chunk->mesh_data_resource_get_texture(i); + + if (!tex.is_valid()) + continue; + + cache->additional_texture_add(tex); + } +#endif + + _prop_material_cache[hash] = cache; + + //unlock here, so if a different thread need the cache it will be able to immediately access the materials and surfaces when it gets it. + _prop_material_cache_mutex.unlock(); + + //this will generate the atlases + cache->refresh_rects(); +} +Ref VoxelLibraryMergerPCM::_prop_material_cache_get(const int key) { + _prop_material_cache_mutex.lock(); + + ERR_FAIL_COND_V(!_prop_material_cache.has(key), Ref()); + + Ref c = _prop_material_cache[key]; + + _prop_material_cache_mutex.unlock(); + + return c; +} +void VoxelLibraryMergerPCM::_prop_material_cache_unref(const int key) { + _prop_material_cache_mutex.lock(); + + if (!_prop_material_cache.has(key)) { + return; + } + + Ref cc = _prop_material_cache[key]; + + if (!cc.is_valid()) { + return; + } + + cc->dec_ref_count(); + + if (cc->get_ref_count() <= 0) { + _prop_material_cache.erase(key); + } + + _prop_material_cache_mutex.unlock(); +} + +int VoxelLibraryMergerPCM::get_texture_flags() const { + return _packer->get_texture_flags(); +} +void VoxelLibraryMergerPCM::set_texture_flags(const int flags) { + _packer->set_texture_flags(flags); + _prop_packer->set_texture_flags(flags); +} + +int VoxelLibraryMergerPCM::get_max_atlas_size() const { + return _packer->get_max_atlas_size(); +} +void VoxelLibraryMergerPCM::set_max_atlas_size(const int size) { + _packer->set_max_atlas_size(size); + _prop_packer->set_max_atlas_size(size); +} + +bool VoxelLibraryMergerPCM::get_keep_original_atlases() const { + return _packer->get_keep_original_atlases(); +} +void VoxelLibraryMergerPCM::set_keep_original_atlases(const bool value) { + _packer->set_keep_original_atlases(value); + _prop_packer->set_keep_original_atlases(value); +} + +Color VoxelLibraryMergerPCM::get_background_color() const { + return _packer->get_background_color(); +} +void VoxelLibraryMergerPCM::set_background_color(const Color &color) { + _packer->set_background_color(color); + _prop_packer->set_background_color(color); +} + +int VoxelLibraryMergerPCM::get_margin() const { + return _packer->get_margin(); +} +void VoxelLibraryMergerPCM::set_margin(const int margin) { + _packer->set_margin(margin); + _prop_packer->set_margin(margin); +} + +//Surfaces +Ref VoxelLibraryMergerPCM::voxel_surface_get(const int index) { + ERR_FAIL_INDEX_V(index, _voxel_surfaces.size(), Ref(NULL)); + + return _voxel_surfaces[index]; +} + +void VoxelLibraryMergerPCM::voxel_surface_add(Ref value) { + ERR_FAIL_COND(!value.is_valid()); + + value->set_library(Ref(this)); + value->set_id(_voxel_surfaces.size()); + + _voxel_surfaces.push_back(value); +} + +void VoxelLibraryMergerPCM::voxel_surface_set(const int index, Ref value) { + ERR_FAIL_COND(index < 0); + + if (_voxel_surfaces.size() < index) { + _voxel_surfaces.resize(index + 1); + } + + if (_voxel_surfaces[index].is_valid()) { + _voxel_surfaces.get(index)->set_library(Ref(NULL)); + } + + if (value.is_valid()) { + value->set_library(Ref(this)); + + _voxel_surfaces.set(index, value); + } +} + +void VoxelLibraryMergerPCM::voxel_surface_remove(const int index) { + _voxel_surfaces.remove(index); +} + +int VoxelLibraryMergerPCM::voxel_surface_get_num() const { + return _voxel_surfaces.size(); +} + +void VoxelLibraryMergerPCM::voxel_surfaces_clear() { + _packer->clear(); + + for (int i = 0; i < _voxel_surfaces.size(); i++) { + Ref surface = _voxel_surfaces[i]; + + if (surface.is_valid()) { + surface->set_library(NULL); + } + } + + _voxel_surfaces.clear(); +} + +Vector VoxelLibraryMergerPCM::get_voxel_surfaces() { + VARIANT_ARRAY_GET(_voxel_surfaces); +} + +void VoxelLibraryMergerPCM::set_voxel_surfaces(const Vector &surfaces) { + _voxel_surfaces.clear(); + + for (int i = 0; i < surfaces.size(); i++) { + Ref surface = Ref(surfaces[i]); + + if (surface.is_valid()) { + surface->set_library(Ref(this)); + } + + _voxel_surfaces.push_back(surface); + } +} + +#ifdef PROPS_PRESENT +Ref VoxelLibraryMergerPCM::get_prop(const int index) { + ERR_FAIL_INDEX_V(index, _props.size(), Ref()); + + return _props[index]; +} +void VoxelLibraryMergerPCM::add_prop(Ref value) { + _props.push_back(value); +} +bool VoxelLibraryMergerPCM::has_prop(const Ref &value) const { + return _props.find(value) != -1; +} +void VoxelLibraryMergerPCM::set_prop(const int index, const Ref &value) { + ERR_FAIL_INDEX(index, _props.size()); + + _props.write[index] = value; +} +void VoxelLibraryMergerPCM::remove_prop(const int index) { + ERR_FAIL_INDEX(index, _props.size()); + + _props.remove(index); +} +int VoxelLibraryMergerPCM::get_num_props() const { + return _props.size(); +} +void VoxelLibraryMergerPCM::clear_props() { + _props.clear(); +} + +Vector VoxelLibraryMergerPCM::get_props() { + VARIANT_ARRAY_GET(_props); +} + +void VoxelLibraryMergerPCM::set_props(const Vector &props) { + VARIANT_ARRAY_SET(props, _props, PropData); +} + +Rect2 VoxelLibraryMergerPCM::get_prop_uv_rect(const Ref &texture) { + if (!texture.is_valid()) { + return Rect2(0, 0, 1, 1); + } + + Ref at = _prop_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; +} + +Ref VoxelLibraryMergerPCM::get_prop_packer() { + return _prop_packer; +} +#endif + +void VoxelLibraryMergerPCM::refresh_rects() { + bool texture_added = false; + for (int i = 0; i < _voxel_surfaces.size(); i++) { + Ref surface = Ref(_voxel_surfaces[i]); + + if (surface.is_valid()) { + for (int j = 0; j < VoxelSurface::VOXEL_SIDES_COUNT; ++j) { + Ref tex = surface->get_texture(static_cast(j)); + + if (!tex.is_valid()) + continue; + + if (!_packer->contains_texture(tex)) { + texture_added = true; + surface->set_region(static_cast(j), _packer->add_texture(tex)); + } else { + surface->set_region(static_cast(j), _packer->get_texture(tex)); + } + } + } + } + + if (texture_added) { + _packer->merge(); + + ERR_FAIL_COND(_packer->get_texture_count() == 0); + + Ref tex = _packer->get_generated_texture(0); + + setup_material_albedo(MATERIAL_INDEX_VOXELS, tex); + setup_material_albedo(MATERIAL_INDEX_LIQUID, tex); + } + +#ifdef PROPS_PRESENT + //todo add this back + //texture_added = false; + for (int i = 0; i < _props.size(); i++) { + Ref prop = _props.get(i); + + if (prop.is_valid()) { + if (process_prop_textures(prop)) + texture_added = true; + } + } + + //if (texture_added) { + if (_prop_packer->get_texture_count() > 0) { + _prop_packer->merge(); + + //ERR_FAIL_COND(_prop_packer->get_texture_count() == 0); + + Ref tex = _prop_packer->get_generated_texture(0); + + setup_material_albedo(MATERIAL_INDEX_PROP, tex); + } +#endif + + for (int i = 0; i < _voxel_surfaces.size(); i++) { + Ref surface = _voxel_surfaces[i]; + + if (surface.is_valid()) { + surface->refresh_rects(); + } + } + + set_initialized(true); +} + +void VoxelLibraryMergerPCM::_setup_material_albedo(const int material_index, const Ref &texture) { + Ref mat; + + int count = 0; + + switch (material_index) { + case MATERIAL_INDEX_VOXELS: + count = material_get_num(); + break; + case MATERIAL_INDEX_LIQUID: + count = liquid_material_get_num(); + break; + case MATERIAL_INDEX_PROP: + count = prop_material_get_num(); + break; + } + + for (int i = 0; i < count; ++i) { + switch (material_index) { + case MATERIAL_INDEX_VOXELS: + mat = material_get(i); + break; + case MATERIAL_INDEX_LIQUID: + mat = liquid_material_get(i); + break; + case MATERIAL_INDEX_PROP: + mat = prop_material_get(i); + break; + } + + Ref spmat; + + if (spmat.is_valid()) { + spmat->set_texture(SpatialMaterial::TEXTURE_ALBEDO, texture); + return; + } + + Ref shmat; + + switch (material_index) { + case MATERIAL_INDEX_VOXELS: + shmat = material_get(i); + break; + case MATERIAL_INDEX_LIQUID: + shmat = liquid_material_get(i); + break; + case MATERIAL_INDEX_PROP: + shmat = prop_material_get(i); + break; + } + + if (shmat.is_valid()) { + shmat->set_shader_param("texture_albedo", texture); + } + } +} + +VoxelLibraryMergerPCM::VoxelLibraryMergerPCM() { + _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); + + _prop_packer.instance(); + +#if GODOT4 +#warning implement +#else + _prop_packer->set_texture_flags(Texture::FLAG_MIPMAPS | Texture::FLAG_FILTER); +#endif + + _prop_packer->set_max_atlas_size(1024); + _prop_packer->set_keep_original_atlases(false); + _prop_packer->set_margin(0); +} + +VoxelLibraryMergerPCM::~VoxelLibraryMergerPCM() { + for (int i = 0; i < _voxel_surfaces.size(); ++i) { + Ref surface = _voxel_surfaces[i]; + + if (surface.is_valid()) { + surface->set_library(Ref()); + } + } + + _voxel_surfaces.clear(); + + _packer->clear(); + _packer.unref(); + + _prop_packer->clear(); + _prop_packer.unref(); +} + +#ifdef PROPS_PRESENT +bool VoxelLibraryMergerPCM::process_prop_textures(Ref prop) { + if (!prop.is_valid()) { + return false; + } + + bool texture_added = false; + + for (int i = 0; i < prop->get_prop_count(); ++i) { + Ref pdm = prop->get_prop(i); + + if (pdm.is_valid()) { + Ref tex = pdm->get_texture(); + + if (!tex.is_valid()) + continue; + + if (!_prop_packer->contains_texture(tex)) { + _prop_packer->add_texture(tex); + texture_added = true; + } + } + + Ref pdp = prop->get_prop(i); + + if (pdp.is_valid()) { + if (process_prop_textures(pdp)) + texture_added = true; + } + } + + return texture_added; +} +#endif + +void VoxelLibraryMergerPCM::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_texture_flags"), &VoxelLibraryMergerPCM::get_texture_flags); + ClassDB::bind_method(D_METHOD("set_texture_flags", "flags"), &VoxelLibraryMergerPCM::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"), &VoxelLibraryMergerPCM::get_max_atlas_size); + ClassDB::bind_method(D_METHOD("set_max_atlas_size", "size"), &VoxelLibraryMergerPCM::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"), &VoxelLibraryMergerPCM::get_keep_original_atlases); + ClassDB::bind_method(D_METHOD("set_keep_original_atlases", "value"), &VoxelLibraryMergerPCM::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"), &VoxelLibraryMergerPCM::get_background_color); + ClassDB::bind_method(D_METHOD("set_background_color", "color"), &VoxelLibraryMergerPCM::set_background_color); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "background_color"), "set_background_color", "get_background_color"); + + ClassDB::bind_method(D_METHOD("get_margin"), &VoxelLibraryMergerPCM::get_margin); + ClassDB::bind_method(D_METHOD("set_margin", "size"), &VoxelLibraryMergerPCM::set_margin); + ADD_PROPERTY(PropertyInfo(Variant::INT, "margin"), "set_margin", "get_margin"); + + ClassDB::bind_method(D_METHOD("get_voxel_surfaces"), &VoxelLibraryMergerPCM::get_voxel_surfaces); + ClassDB::bind_method(D_METHOD("set_voxel_surfaces"), &VoxelLibraryMergerPCM::set_voxel_surfaces); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "voxel_surfaces", PROPERTY_HINT_NONE, "17/17:VoxelSurfaceMerger", PROPERTY_USAGE_DEFAULT, "VoxelSurfaceMerger"), "set_voxel_surfaces", "get_voxel_surfaces"); + +#ifdef PROPS_PRESENT + ClassDB::bind_method(D_METHOD("get_props"), &VoxelLibraryMergerPCM::get_props); + ClassDB::bind_method(D_METHOD("set_props"), &VoxelLibraryMergerPCM::set_props); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "props", PROPERTY_HINT_NONE, "17/17:PropData", PROPERTY_USAGE_DEFAULT, "PropData"), "set_props", "get_props"); + + ClassDB::bind_method(D_METHOD("get_prop_uv_rect", "texture"), &VoxelLibraryMergerPCM::get_prop_uv_rect); + + ClassDB::bind_method(D_METHOD("get_prop_packer"), &VoxelLibraryMergerPCM::get_prop_packer); +#endif + + ClassDB::bind_method(D_METHOD("_setup_material_albedo", "material_index", "texture"), &VoxelLibraryMergerPCM::_setup_material_albedo); +} diff --git a/library/voxel_library_merger_pcm.h b/library/voxel_library_merger_pcm.h new file mode 100644 index 0000000..818c87d --- /dev/null +++ b/library/voxel_library_merger_pcm.h @@ -0,0 +1,140 @@ +/* +Copyright (c) 2019-2022 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 VOXEL_LIBRARY_MERGER_PCM_H +#define VOXEL_LIBRARY_MERGER_PCM_H + +#include "core/version.h" + +#if VERSION_MAJOR > 3 +#include "core/io/resource.h" +#include "core/templates/map.h" +#else +#include "core/resource.h" +#include "core/map.h" +#endif + +#include "voxel_library.h" + +#include "scene/resources/material.h" + +#include "../data/voxel_light.h" +#include "voxel_surface_merger.h" + +#include "core/os/mutex.h" + +class VoxelSurfaceSimple; +class VoxelMesher; +class PackedScene; +class VoxelMaterialCache; +class VoxelMaterialCachePCM; +class TexturePacker; +class VoxelChunk; + +//pcm = per chunk material +class VoxelLibraryMergerPCM : public VoxelLibrary { + GDCLASS(VoxelLibraryMergerPCM, VoxelLibrary); + +public: + bool _supports_caching(); + + void _material_cache_get_key(Ref chunk); + Ref _material_cache_get(const int key); + void _material_cache_unref(const int key); + + void _prop_material_cache_get_key(Ref chunk); + Ref _prop_material_cache_get(const int key); + void _prop_material_cache_unref(const int key); + + 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 voxel_surface_get(const int index); + void voxel_surface_add(Ref value); + void voxel_surface_set(const int index, Ref value); + void voxel_surface_remove(const int index); + int voxel_surface_get_num() const; + void voxel_surfaces_clear(); + + Vector get_voxel_surfaces(); + void set_voxel_surfaces(const Vector &surfaces); + +#ifdef PROPS_PRESENT + Ref get_prop(const int index); + void add_prop(Ref value); + bool has_prop(const Ref &value) const; + void set_prop(const int index, const Ref &value); + void remove_prop(const int index); + int get_num_props() const; + void clear_props(); + + Vector get_props(); + void set_props(const Vector &props); + + Rect2 get_prop_uv_rect(const Ref &texture); + + Ref get_prop_packer(); +#endif + + void refresh_rects(); + + void _setup_material_albedo(const int material_index, const Ref &texture); + + VoxelLibraryMergerPCM(); + ~VoxelLibraryMergerPCM(); + +protected: +#ifdef PROPS_PRESENT + bool process_prop_textures(Ref prop); +#endif + + static void _bind_methods(); + + Map > _material_cache; + Map > _prop_material_cache; + + Vector > _voxel_surfaces; +#ifdef PROPS_PRESENT + Vector > _props; +#endif + + //todo remove these + Ref _packer; + Ref _prop_packer; + + Mutex _material_cache_mutex; + Mutex _prop_material_cache_mutex; +}; + +#endif diff --git a/library/voxel_library_simple.h b/library/voxel_library_simple.h index 164215d..e04d09a 100644 --- a/library/voxel_library_simple.h +++ b/library/voxel_library_simple.h @@ -72,7 +72,6 @@ public: protected: static void _bind_methods(); -private: Vector > _voxel_surfaces; //atlas diff --git a/library/voxel_material_cache.cpp b/library/voxel_material_cache.cpp new file mode 100644 index 0000000..47b8ed4 --- /dev/null +++ b/library/voxel_material_cache.cpp @@ -0,0 +1,334 @@ +/* +Copyright (c) 2019-2022 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 "voxel_material_cache.h" + +#include "../defines.h" + +#ifdef PROPS_PRESENT +#include "../../props/props/prop_data.h" +#include "../../props/props/prop_data_prop.h" + +#if MESH_DATA_RESOURCE_PRESENT +#include "../../mesh_data_resource/props/prop_data_mesh_data.h" +#endif +#endif + +bool VoxelMaterialCache::get_initialized() { + return _initialized; +} +void VoxelMaterialCache::set_initialized(const bool value) { + _initialized = value; +} + +int VoxelMaterialCache::get_ref_count() { + return _ref_count; +} +void VoxelMaterialCache::set_ref_count(const int value) { + _ref_count = value; +} +void VoxelMaterialCache::inc_ref_count() { + _ref_count += 1; +} +void VoxelMaterialCache::dec_ref_count() { + _ref_count -= 1; +} + +//Materials +Ref VoxelMaterialCache::material_get(const int index) { + ERR_FAIL_INDEX_V(index, _materials.size(), Ref(NULL)); + + return _materials[index]; +} + +Ref VoxelMaterialCache::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 VoxelMaterialCache::material_add(const Ref &value) { + ERR_FAIL_COND(!value.is_valid()); + + _materials.push_back(value); +} + +void VoxelMaterialCache::material_set(const int index, const Ref &value) { + ERR_FAIL_INDEX(index, _materials.size()); + + _materials.set(index, value); +} + +void VoxelMaterialCache::material_remove(const int index) { + _materials.VREMOVE(index); +} + +int VoxelMaterialCache::material_get_num() const { + return _materials.size(); +} + +void VoxelMaterialCache::materials_clear() { + _materials.clear(); +} + +Vector VoxelMaterialCache::materials_get() { + VARIANT_ARRAY_GET(_materials); +} + +void VoxelMaterialCache::materials_set(const Vector &materials) { + _materials.clear(); + + for (int i = 0; i < materials.size(); i++) { + Ref material = Ref(materials[i]); + + _materials.push_back(material); + } +} + +//Surfaces +Ref VoxelMaterialCache::surface_get(const int index) { + ERR_FAIL_INDEX_V(index, _surfaces.size(), Ref()); + + return _surfaces[index]; +} +Ref VoxelMaterialCache::surface_id_get(const int id) { + Ref surface; + + for (int i = 0; i < _surfaces.size(); ++i) { + surface = _surfaces[i]; + + if (surface.is_valid()) { + if (surface->get_id() == id) { + break; + } + } + } + + return surface; +} +void VoxelMaterialCache::surface_add(Ref value) { + ERR_FAIL_COND(!value.is_valid()); + + _surfaces.push_back(value); +} +void VoxelMaterialCache::surface_set(int index, Ref value) { + ERR_FAIL_COND(index < 0); + + if (_surfaces.size() < index) { + _surfaces.resize(index + 1); + } + + _surfaces.set(index, value); +} +void VoxelMaterialCache::surface_remove(const int index) { + _surfaces.VREMOVE(index); +} +int VoxelMaterialCache::surface_get_num() const { + return _surfaces.size(); +} +void VoxelMaterialCache::surfaces_clear() { + _surfaces.clear(); +} + +void VoxelMaterialCache::additional_texture_add(const Ref &texture) { + _additional_textures.push_back(texture); +} +void VoxelMaterialCache::additional_texture_remove(const Ref &texture) { + for (int i = 0; i < _additional_textures.size(); ++i) { + if (_additional_textures[i] == texture) { + _additional_textures.VREMOVE(i); + return; + } + } +} +void VoxelMaterialCache::additional_texture_remove_index(const int index) { + ERR_FAIL_INDEX(index, _additional_textures.size()); + + _additional_textures.VREMOVE(index); +} +void VoxelMaterialCache::additional_textures_clear() { + _additional_textures.clear(); +} +int VoxelMaterialCache::additional_texture_count() { + return _additional_textures.size(); +} +Ref VoxelMaterialCache::additional_texture_get(const int index) { + ERR_FAIL_INDEX_V(index, _additional_textures.size(), Ref()); + + return _additional_textures[index]; +} +Ref VoxelMaterialCache::additional_texture_get_atlas(const int index) { + ERR_FAIL_INDEX_V(index, _additional_textures.size(), Ref()); + + return additional_texture_get_atlas_tex(_additional_textures[index]); +} +Ref VoxelMaterialCache::additional_texture_get_atlas_tex(const Ref &texture) { + return Ref(); +} +Rect2 VoxelMaterialCache::additional_texture_get_uv_rect(const Ref &texture) { + return Rect2(0, 0, 1, 1); +} + +#ifdef PROPS_PRESENT +void VoxelMaterialCache::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; + + additional_texture_add(tex); + } +#endif + + Ref pdp = prop->get_prop(i); + + if (pdp.is_valid()) { + prop_add_textures(pdp); + } + } +} +void VoxelMaterialCache::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; + + additional_texture_remove(tex); + } +#endif + + Ref pdp = prop->get_prop(i); + + if (pdp.is_valid()) { + prop_remove_textures(pdp); + } + } +} +#endif + +void VoxelMaterialCache::refresh_rects() { + _initialized = true; +} + +void VoxelMaterialCache::setup_material_albedo(Ref texture) { +#if VERSION_MAJOR < 4 + if (has_method("_setup_material_albedo")) { + call("_setup_material_albedo", texture); + } +#else + GDVIRTUAL_CALL(_setup_material_albedo, texture); +#endif +} + +VoxelMaterialCache::VoxelMaterialCache() { + _ref_count = 0; + _initialized = false; +} + +VoxelMaterialCache::~VoxelMaterialCache() { + _materials.clear(); + _surfaces.clear(); +} + +void VoxelMaterialCache::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_initialized"), &VoxelMaterialCache::get_initialized); + ClassDB::bind_method(D_METHOD("set_initialized", "value"), &VoxelMaterialCache::set_initialized); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "initialized"), "set_initialized", "get_initialized"); + + ClassDB::bind_method(D_METHOD("get_ref_count"), &VoxelMaterialCache::get_ref_count); + ClassDB::bind_method(D_METHOD("set_ref_count", "value"), &VoxelMaterialCache::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"), &VoxelMaterialCache::inc_ref_count); + ClassDB::bind_method(D_METHOD("dec_ref_count"), &VoxelMaterialCache::dec_ref_count); + +#if VERSION_MAJOR < 4 + BIND_VMETHOD(MethodInfo("_setup_material_albedo", PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"))); +#else + GDVIRTUAL_BIND(_setup_material_albedo, "texture"); +#endif + + ClassDB::bind_method(D_METHOD("material_get", "index"), &VoxelMaterialCache::material_get); + ClassDB::bind_method(D_METHOD("material_lod_get", "index"), &VoxelMaterialCache::material_lod_get); + ClassDB::bind_method(D_METHOD("material_add", "value"), &VoxelMaterialCache::material_add); + ClassDB::bind_method(D_METHOD("material_set", "index", "value"), &VoxelMaterialCache::material_set); + ClassDB::bind_method(D_METHOD("material_remove", "index"), &VoxelMaterialCache::material_remove); + ClassDB::bind_method(D_METHOD("material_get_num"), &VoxelMaterialCache::material_get_num); + ClassDB::bind_method(D_METHOD("materials_clear"), &VoxelMaterialCache::materials_clear); + + ClassDB::bind_method(D_METHOD("materials_get"), &VoxelMaterialCache::materials_get); + ClassDB::bind_method(D_METHOD("materials_set"), &VoxelMaterialCache::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("surface_get", "index"), &VoxelMaterialCache::surface_get); + ClassDB::bind_method(D_METHOD("surface_id_get", "index"), &VoxelMaterialCache::surface_id_get); + + ClassDB::bind_method(D_METHOD("surface_add", "value"), &VoxelMaterialCache::surface_add); + ClassDB::bind_method(D_METHOD("surface_set", "index", "surface"), &VoxelMaterialCache::surface_set); + ClassDB::bind_method(D_METHOD("surface_remove", "index"), &VoxelMaterialCache::surface_remove); + ClassDB::bind_method(D_METHOD("surface_get_num"), &VoxelMaterialCache::surface_get_num); + ClassDB::bind_method(D_METHOD("surfaces_clear"), &VoxelMaterialCache::surfaces_clear); + + ClassDB::bind_method(D_METHOD("additional_texture_add", "texture"), &VoxelMaterialCache::additional_texture_add); + ClassDB::bind_method(D_METHOD("additional_texture_remove", "texture"), &VoxelMaterialCache::additional_texture_remove); + ClassDB::bind_method(D_METHOD("additional_texture_remove_index", "index"), &VoxelMaterialCache::additional_texture_remove_index); + ClassDB::bind_method(D_METHOD("additional_textures_clear"), &VoxelMaterialCache::additional_textures_clear); + ClassDB::bind_method(D_METHOD("additional_texture_count"), &VoxelMaterialCache::additional_texture_count); + ClassDB::bind_method(D_METHOD("additional_texture_get", "index"), &VoxelMaterialCache::additional_texture_get); + ClassDB::bind_method(D_METHOD("additional_texture_get_atlas", "index"), &VoxelMaterialCache::additional_texture_get_atlas); + ClassDB::bind_method(D_METHOD("additional_texture_get_atlas_tex", "index"), &VoxelMaterialCache::additional_texture_get_atlas_tex); + ClassDB::bind_method(D_METHOD("additional_texture_get_uv_rect", "texture"), &VoxelMaterialCache::additional_texture_get_uv_rect); + +#ifdef PROPS_PRESENT + ClassDB::bind_method(D_METHOD("prop_add_textures", "prop"), &VoxelMaterialCache::prop_add_textures); + ClassDB::bind_method(D_METHOD("prop_remove_textures", "prop"), &VoxelMaterialCache::prop_remove_textures); +#endif + + ClassDB::bind_method(D_METHOD("refresh_rects"), &VoxelMaterialCache::refresh_rects); + + ClassDB::bind_method(D_METHOD("setup_material_albedo", "texture"), &VoxelMaterialCache::setup_material_albedo); +} diff --git a/library/voxel_material_cache.h b/library/voxel_material_cache.h new file mode 100644 index 0000000..98773c7 --- /dev/null +++ b/library/voxel_material_cache.h @@ -0,0 +1,116 @@ +/* +Copyright (c) 2019-2022 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 VOXEL_MATERIAL_CACHE_H +#define VOXEL_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 "voxel_library.h" + +#include "../defines.h" + +class VoxelLibrary; + +class VoxelMaterialCache : public Resource { + GDCLASS(VoxelMaterialCache, Resource) + +public: + bool get_initialized(); + void set_initialized(const bool value); + + 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 Ref surface_get(const int index); + virtual Ref surface_id_get(const int id); + virtual void surface_add(Ref value); + virtual void surface_set(const int index, Ref value); + virtual void surface_remove(const int index); + virtual int surface_get_num() const; + virtual void surfaces_clear(); + + virtual void additional_texture_add(const Ref &texture); + virtual void additional_texture_remove(const Ref &texture); + virtual void additional_texture_remove_index(const int index); + virtual void additional_textures_clear(); + virtual int additional_texture_count(); + virtual Ref additional_texture_get(const int index); + virtual Ref additional_texture_get_atlas(const int index); + virtual Ref additional_texture_get_atlas_tex(const Ref &texture); + virtual Rect2 additional_texture_get_uv_rect(const Ref &texture); + +#ifdef PROPS_PRESENT + void prop_add_textures(const Ref &prop); + void prop_remove_textures(const Ref &prop); +#endif + + virtual void refresh_rects(); + + void setup_material_albedo(Ref texture); + +#if VERSION_MAJOR >= 4 + GDVIRTUAL1(_setup_material_albedo, Ref); +#endif + + VoxelMaterialCache(); + ~VoxelMaterialCache(); + +protected: + static void _bind_methods(); + + bool _initialized; + + Vector> _surfaces; + Vector> _materials; + Vector> _additional_textures; + + int _ref_count; +}; + +#endif diff --git a/library/voxel_material_cache_pcm.cpp b/library/voxel_material_cache_pcm.cpp new file mode 100644 index 0000000..c64c2bc --- /dev/null +++ b/library/voxel_material_cache_pcm.cpp @@ -0,0 +1,232 @@ +/* +Copyright (c) 2019-2022 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 "voxel_material_cache_pcm.h" + +#include "../../texture_packer/texture_packer.h" +#include "scene/resources/texture.h" +#include "voxel_surface.h" +#include "voxel_surface_merger.h" + +int VoxelMaterialCachePCM::get_texture_flags() const { + return _packer->get_texture_flags(); +} +void VoxelMaterialCachePCM::set_texture_flags(const int flags) { + _packer->set_texture_flags(flags); +} + +int VoxelMaterialCachePCM::get_max_atlas_size() const { + return _packer->get_max_atlas_size(); +} +void VoxelMaterialCachePCM::set_max_atlas_size(const int size) { + _packer->set_max_atlas_size(size); +} + +bool VoxelMaterialCachePCM::get_keep_original_atlases() const { + return _packer->get_keep_original_atlases(); +} +void VoxelMaterialCachePCM::set_keep_original_atlases(const bool value) { + _packer->set_keep_original_atlases(value); +} + +Color VoxelMaterialCachePCM::get_background_color() const { + return _packer->get_background_color(); +} +void VoxelMaterialCachePCM::set_background_color(const Color &color) { + _packer->set_background_color(color); +} + +int VoxelMaterialCachePCM::get_margin() const { + return _packer->get_margin(); +} +void VoxelMaterialCachePCM::set_margin(const int margin) { + _packer->set_margin(margin); +} + +Ref VoxelMaterialCachePCM::additional_texture_get_atlas_tex(const Ref &texture) { + if (!_packer->contains_texture(texture)) { + return Ref(); + } + + return _packer->get_texture(texture); +} +Rect2 VoxelMaterialCachePCM::additional_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 VoxelMaterialCachePCM::refresh_rects() { + bool texture_added = false; + for (int i = 0; i < _surfaces.size(); i++) { + Ref surface = Ref(_surfaces[i]); + + if (surface.is_valid()) { + for (int j = 0; j < VoxelSurface::VOXEL_SIDES_COUNT; ++j) { + Ref tex = surface->get_texture(static_cast(j)); + + if (!tex.is_valid()) + continue; + + if (!_packer->contains_texture(tex)) { + texture_added = true; + surface->set_region(static_cast(j), _packer->add_texture(tex)); + } else { + surface->set_region(static_cast(j), _packer->get_texture(tex)); + } + } + } + } + + for (int i = 0; i < _additional_textures.size(); i++) { + Ref tex = _additional_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); + } + + for (int i = 0; i < _surfaces.size(); i++) { + Ref surface = _surfaces[i]; + + if (surface.is_valid()) { + surface->refresh_rects(); + } + } + + _initialized = true; +} + +void VoxelMaterialCachePCM::_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); + } + } +} + +VoxelMaterialCachePCM::VoxelMaterialCachePCM() { + _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); +} + +VoxelMaterialCachePCM::~VoxelMaterialCachePCM() { + for (int i = 0; i < _surfaces.size(); ++i) { + Ref surface = _surfaces[i]; + + if (surface.is_valid()) { + surface->set_library(Ref()); + } + } + + _surfaces.clear(); + + _packer->clear(); + _packer.unref(); +} + +void VoxelMaterialCachePCM::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_texture_flags"), &VoxelMaterialCachePCM::get_texture_flags); + ClassDB::bind_method(D_METHOD("set_texture_flags", "flags"), &VoxelMaterialCachePCM::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"), &VoxelMaterialCachePCM::get_max_atlas_size); + ClassDB::bind_method(D_METHOD("set_max_atlas_size", "size"), &VoxelMaterialCachePCM::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"), &VoxelMaterialCachePCM::get_keep_original_atlases); + ClassDB::bind_method(D_METHOD("set_keep_original_atlases", "value"), &VoxelMaterialCachePCM::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"), &VoxelMaterialCachePCM::get_background_color); + ClassDB::bind_method(D_METHOD("set_background_color", "color"), &VoxelMaterialCachePCM::set_background_color); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "background_color"), "set_background_color", "get_background_color"); + + ClassDB::bind_method(D_METHOD("get_margin"), &VoxelMaterialCachePCM::get_margin); + ClassDB::bind_method(D_METHOD("set_margin", "size"), &VoxelMaterialCachePCM::set_margin); + ADD_PROPERTY(PropertyInfo(Variant::INT, "margin"), "set_margin", "get_margin"); + + ClassDB::bind_method(D_METHOD("_setup_material_albedo", "texture"), &VoxelMaterialCachePCM::_setup_material_albedo); +} diff --git a/library/voxel_material_cache_pcm.h b/library/voxel_material_cache_pcm.h new file mode 100644 index 0000000..70e850e --- /dev/null +++ b/library/voxel_material_cache_pcm.h @@ -0,0 +1,84 @@ +/* +Copyright (c) 2019-2022 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 VOXEL_MATERIAL_CACHE_PCM_H +#define VOXEL_MATERIAL_CACHE_PCM_H + +#include "voxel_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 "../defines.h" + +class VoxelSurface; +class TexturePacker; +class PropData; + +class VoxelMaterialCachePCM : public VoxelMaterialCache { + GDCLASS(VoxelMaterialCachePCM, VoxelMaterialCache); + +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 additional_texture_get_atlas_tex(const Ref &texture); + Rect2 additional_texture_get_uv_rect(const Ref &texture); + + void refresh_rects(); + + void _setup_material_albedo(Ref texture); + + VoxelMaterialCachePCM(); + ~VoxelMaterialCachePCM(); + +protected: + static void _bind_methods(); + + Ref _packer; +}; + +#endif diff --git a/register_types.cpp b/register_types.cpp index 7e0fbb6..3d78d65 100644 --- a/register_types.cpp +++ b/register_types.cpp @@ -27,10 +27,13 @@ SOFTWARE. #include "library/voxel_library.h" #include "library/voxel_library_simple.h" +#include "library/voxel_material_cache.h" #ifdef TEXTURE_PACKER_PRESENT -#include "library/voxel_surface_merger.h" #include "library/voxel_library_merger.h" +#include "library/voxel_library_merger_pcm.h" +#include "library/voxel_material_cache_pcm.h" +#include "library/voxel_surface_merger.h" #endif #include "data/voxel_light.h" @@ -90,9 +93,13 @@ void register_voxelman_types() { ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); + #ifdef TEXTURE_PACKER_PRESENT ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); + ClassDB::register_class(); #endif ClassDB::register_class(); diff --git a/world/voxel_chunk.cpp b/world/voxel_chunk.cpp index e5351a6..a24948d 100644 --- a/world/voxel_chunk.cpp +++ b/world/voxel_chunk.cpp @@ -188,6 +188,48 @@ _FORCE_INLINE_ void VoxelChunk::set_margin_end(const int value) { _margin_end = value; } +int VoxelChunk::material_cache_key_get() const { + return _material_cache_key; +} +void VoxelChunk::material_cache_key_set(const int value) { + _material_cache_key = value; +} + +bool VoxelChunk::material_cache_key_has() const { + return _material_cache_key_has; +} +void VoxelChunk::material_cache_key_has_set(const bool value) { + _material_cache_key_has = value; +} + +int VoxelChunk::liquid_material_cache_key_get() const { + return _liquid_material_cache_key; +} +void VoxelChunk::liquid_material_cache_key_set(const int value) { + _liquid_material_cache_key = value; +} + +bool VoxelChunk::liquid_material_cache_key_has() const { + return _liquid_material_cache_key_has; +} +void VoxelChunk::liquid_material_cache_key_has_set(const bool value) { + _liquid_material_cache_key_has = value; +} + +int VoxelChunk::prop_material_cache_key_get() const { + return _prop_material_cache_key; +} +void VoxelChunk::prop_material_cache_key_set(const int value) { + _prop_material_cache_key = value; +} + +bool VoxelChunk::prop_material_cache_key_has() const { + return _prop_material_cache_key_has; +} +void VoxelChunk::prop_material_cache_key_has_set(const bool value) { + _prop_material_cache_key_has = value; +} + Ref VoxelChunk::get_library() { return _library; } @@ -1137,6 +1179,15 @@ VoxelChunk::VoxelChunk() { _margin_start = 0; _margin_end = 0; + _material_cache_key = 0; + _material_cache_key_has = false; + + _liquid_material_cache_key = 0; + _liquid_material_cache_key_has = false; + + _prop_material_cache_key = 0; + _prop_material_cache_key_has = false; + _current_job = -1; _queued_generation = false; @@ -1456,6 +1507,30 @@ void VoxelChunk::_bind_methods() { ClassDB::bind_method(D_METHOD("set_margin_end"), &VoxelChunk::set_margin_end); ADD_PROPERTY(PropertyInfo(Variant::INT, "margin_end"), "set_margin_end", "get_margin_end"); + ClassDB::bind_method(D_METHOD("material_cache_key_get"), &VoxelChunk::material_cache_key_get); + ClassDB::bind_method(D_METHOD("material_cache_key_set"), &VoxelChunk::material_cache_key_set); + ADD_PROPERTY(PropertyInfo(Variant::INT, "material_cache_key"), "material_cache_key_set", "material_cache_key_get"); + + ClassDB::bind_method(D_METHOD("material_cache_key_has"), &VoxelChunk::material_cache_key_has); + ClassDB::bind_method(D_METHOD("material_cache_key_has_set"), &VoxelChunk::material_cache_key_has_set); + ADD_PROPERTY(PropertyInfo(Variant::INT, "material_cache_key_has"), "material_cache_key_has_set", "material_cache_key_has"); + + ClassDB::bind_method(D_METHOD("liquid_material_cache_key_get"), &VoxelChunk::liquid_material_cache_key_get); + ClassDB::bind_method(D_METHOD("liquid_material_cache_key_set"), &VoxelChunk::liquid_material_cache_key_set); + ADD_PROPERTY(PropertyInfo(Variant::INT, "liquid_material_cache_key"), "liquid_material_cache_key_set", "liquid_material_cache_key_get"); + + ClassDB::bind_method(D_METHOD("liquid_material_cache_key_has"), &VoxelChunk::liquid_material_cache_key_has); + ClassDB::bind_method(D_METHOD("liquid_material_cache_key_has_set"), &VoxelChunk::liquid_material_cache_key_has_set); + ADD_PROPERTY(PropertyInfo(Variant::INT, "liquid_material_cache_key_has"), "liquid_material_cache_key_has_set", "liquid_material_cache_key_has"); + + ClassDB::bind_method(D_METHOD("prop_material_cache_key_get"), &VoxelChunk::prop_material_cache_key_get); + ClassDB::bind_method(D_METHOD("prop_material_cache_key_set"), &VoxelChunk::prop_material_cache_key_set); + ADD_PROPERTY(PropertyInfo(Variant::INT, "prop_material_cache_key"), "prop_material_cache_key_set", "prop_material_cache_key_get"); + + ClassDB::bind_method(D_METHOD("prop_material_cache_key_has"), &VoxelChunk::prop_material_cache_key_has); + ClassDB::bind_method(D_METHOD("prop_material_cache_key_has_set"), &VoxelChunk::prop_material_cache_key_has_set); + ADD_PROPERTY(PropertyInfo(Variant::INT, "prop_material_cache_key_has"), "prop_material_cache_key_has_set", "prop_material_cache_key_has"); + ClassDB::bind_method(D_METHOD("get_library"), &VoxelChunk::get_library); ClassDB::bind_method(D_METHOD("set_library", "value"), &VoxelChunk::set_library); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "VoxelLibrary"), "set_library", "get_library"); diff --git a/world/voxel_chunk.h b/world/voxel_chunk.h index bfd7e9d..dd51360 100644 --- a/world/voxel_chunk.h +++ b/world/voxel_chunk.h @@ -67,8 +67,8 @@ include_pool_vector typedef class Transform3D Transform; #endif -#include "../library/voxel_surface.h" #include "../library/voxel_library.h" +#include "../library/voxel_surface.h" ; //hackfix for a clang format issue class VoxelJob; @@ -144,6 +144,24 @@ public: void set_margin_start(const int value); void set_margin_end(const int value); + int material_cache_key_get() const; + void material_cache_key_set(const int value); + + bool material_cache_key_has() const; + void material_cache_key_has_set(const bool value); + + int liquid_material_cache_key_get() const; + void liquid_material_cache_key_set(const int value); + + bool liquid_material_cache_key_has() const; + void liquid_material_cache_key_has_set(const bool value); + + int prop_material_cache_key_get() const; + void prop_material_cache_key_set(const int value); + + bool prop_material_cache_key_has() const; + void prop_material_cache_key_has_set(const bool value); + Ref get_library(); void set_library(const Ref &value); @@ -395,6 +413,15 @@ protected: int _margin_start; int _margin_end; + int _material_cache_key; + bool _material_cache_key_has; + + int _liquid_material_cache_key; + bool _liquid_material_cache_key_has; + + int _prop_material_cache_key; + bool _prop_material_cache_key_has; + Vector _channels; float _voxel_scale;