From 08be795296e81540103b006f1dfe896a901d2e10 Mon Sep 17 00:00:00 2001 From: Relintai Date: Wed, 9 Feb 2022 13:12:16 +0100 Subject: [PATCH] Brought over the prop job step code from Terraman. (It's not yet enabled.) --- world/jobs/voxel_prop_job.cpp | 484 +++++++++++++++++++++++++++++++++- world/jobs/voxel_prop_job.h | 25 ++ 2 files changed, 508 insertions(+), 1 deletion(-) diff --git a/world/jobs/voxel_prop_job.cpp b/world/jobs/voxel_prop_job.cpp index 96bcaa5..efa8c87 100644 --- a/world/jobs/voxel_prop_job.cpp +++ b/world/jobs/voxel_prop_job.cpp @@ -24,12 +24,15 @@ SOFTWARE. #include "../../defines.h" -#include "../../library/voxel_surface.h" #include "../../library/voxel_library.h" +#include "../../library/voxel_surface.h" #include "../../meshers/voxel_mesher.h" #include "../default/voxel_chunk_default.h" +#include "../../library/voxel_material_cache.h" +#include "../default/voxel_chunk_default.h" + #ifdef MESH_DATA_RESOURCE_PRESENT #include "../../../mesh_data_resource/mesh_data_resource.h" #endif @@ -47,6 +50,28 @@ void VoxelPropJob::set_prop_mesher(const Ref &mesher) { _prop_mesher = mesher; } +Ref VoxelPropJob::get_jobs_step(int index) const { + ERR_FAIL_INDEX_V(index, _job_steps.size(), Ref()); + + return _job_steps.get(index); +} +void VoxelPropJob::set_jobs_step(int index, const Ref &step) { + ERR_FAIL_INDEX(index, _job_steps.size()); + + _job_steps.set(index, step); +} +void VoxelPropJob::remove_jobs_step(const int index) { + ERR_FAIL_INDEX(index, _job_steps.size()); + + _job_steps.remove(index); +} +void VoxelPropJob::add_jobs_step(const Ref &step) { + _job_steps.push_back(step); +} +int VoxelPropJob::get_jobs_step_count() const { + return _job_steps.size(); +} + void VoxelPropJob::phase_physics_process() { Ref chunk = _chunk; @@ -330,6 +355,94 @@ void VoxelPropJob::phase_prop() { next_job(); } +void VoxelPropJob::new_phase_prop() { +#ifdef MESH_DATA_RESOURCE_PRESENT + Ref chunk = _chunk; + + if (!get_prop_mesher().is_valid()) { + set_complete(true); //So threadpool knows it's done + next_job(); + return; + } + + if (should_do()) { + if (chunk->mesh_data_resource_get_count() == 0) { + reset_stages(); + set_complete(true); //So threadpool knows it's done + next_job(); + return; + } + + for (int i = 0; i < chunk->mesh_data_resource_get_count(); ++i) { + if (chunk->mesh_data_resource_get_is_inside(i)) { + get_prop_mesher()->add_mesh_data_resource_transform(chunk->mesh_data_resource_get(i), chunk->mesh_data_resource_get_transform(i), chunk->mesh_data_resource_get_uv_rect(i)); + } + } + + if (should_return()) { + return; + } + } + + if (should_do()) { + if ((chunk->get_build_flags() & VoxelChunkDefault::BUILD_FLAG_USE_LIGHTING) != 0) { + get_prop_mesher()->bake_colors(_chunk); + } + + if (should_return()) { + return; + } + } + + if (should_do()) { + if ((chunk->get_build_flags() & VoxelChunkDefault::BUILD_FLAG_USE_LIGHTING) != 0) { + VoxelWorldDefault *world = Object::cast_to(chunk->get_voxel_world()); + + if (world) { + for (int i = 0; i < chunk->mesh_data_resource_get_count(); ++i) { + if (!chunk->mesh_data_resource_get_is_inside(i)) { + Ref mdr = chunk->mesh_data_resource_get(i); + + ERR_CONTINUE(!mdr.is_valid()); + + Transform trf = chunk->mesh_data_resource_get_transform(i); + + Array arr = mdr->get_array(); + + if (arr.size() <= Mesh::ARRAY_VERTEX) { + continue; + } + + PoolVector3Array varr = arr[Mesh::ARRAY_VERTEX]; + + if (varr.size() == 0) { + continue; + } + + PoolColorArray carr = world->get_vertex_colors(trf, varr); + + get_prop_mesher()->add_mesh_data_resource_transform_colored(mdr, trf, carr, chunk->mesh_data_resource_get_uv_rect(i)); + } + } + } + } + } + + if (get_prop_mesher()->get_vertex_count() == 0) { + reset_stages(); + + set_complete(true); //So threadpool knows it's done + next_job(); + return; + } + +#endif + + reset_stages(); + next_phase(); +} + + void VoxelPropJob::_physics_process(float delta) { if (_phase == 0) phase_physics_process(); @@ -363,12 +476,47 @@ void VoxelPropJob::_execute_phase() { } } +void VoxelPropJob::new_execute_phase() { + ERR_FAIL_COND(!_chunk.is_valid()); + + Ref library = _chunk->get_library(); + + ERR_FAIL_COND(!library.is_valid()); + + Ref chunk = _chunk; + + if (!chunk.is_valid() +#ifdef MESH_DATA_RESOURCE_PRESENT + || chunk->mesh_data_resource_get_count() == 0 +#endif + ) { + set_complete(true); + next_job(); + return; + } + + if (_phase == 1) { + phase_setup(); + } else if (_phase == 2) { + new_phase_prop(); + } else if (_phase == 3) { + phase_steps(); + } else if (_phase > 3) { + set_complete(true); //So threadpool knows it's done + next_job(); + ERR_FAIL_MSG("VoxelPropJob: _phase is too high!"); + } +} + void VoxelPropJob::_reset() { VoxelJob::_reset(); _build_done = false; _phase = 0; + _current_job_step = 0; + _current_mesh = 0; + if (get_prop_mesher().is_valid()) { get_prop_mesher()->reset(); get_prop_mesher()->set_library(_chunk->get_library()); @@ -377,8 +525,336 @@ void VoxelPropJob::_reset() { set_build_phase_type(BUILD_PHASE_TYPE_PHYSICS_PROCESS); } +void VoxelPropJob::phase_setup() { + Ref library = _chunk->get_library(); + + if (!library->supports_caching()) { + next_phase(); + return; + } + + if (library->supports_caching()) { + if (!_chunk->prop_material_cache_key_has()) { + library->prop_material_cache_get_key(_chunk); + + if (!_chunk->prop_material_cache_key_has()) { + //chunk does not need a key + next_phase(); + return; + } + } + + Ref cache = library->prop_material_cache_get(_chunk->prop_material_cache_key_get()); + + //Note: without threadpool and threading none of this can happen, as cache will get initialized the first time a thread requests it! + while (!cache->get_initialized()) { + //Means it's currently merging the atlases on a different thread. + //Let's just wait + OS::get_singleton()->delay_usec(100); + } + +#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; + + Rect2 r = cache->additional_texture_get_uv_rect(tex); + + _chunk->mesh_data_resource_set_uv_rect(i, r); + } +#endif + } + + next_phase(); + + if (should_return()) { + return; + } +} + +void VoxelPropJob::phase_steps() { + Ref chunk = _chunk; + + ERR_FAIL_COND(!_prop_mesher.is_valid()); + + if (should_return()) { + return; + } + + if (_prop_mesher->get_vertex_count() == 0) { + reset_stages(); + //next_phase(); + set_complete(true); //So threadpool knows it's done + next_job(); + + return; + } + + //set up the meshes + if (should_do()) { + RID mesh_rid = chunk->mesh_rid_get_index(VoxelChunkDefault::MESH_INDEX_PROP, VoxelChunkDefault::MESH_TYPE_INDEX_MESH, 0); + + if (mesh_rid == RID()) { + //need to allocate the meshes + + //first count how many we need + int count = 0; + for (int i = 0; i < _job_steps.size(); ++i) { + Ref step = _job_steps[i]; + + ERR_FAIL_COND(!step.is_valid()); + + switch (step->get_job_type()) { + case VoxelMesherJobStep::TYPE_NORMAL: + ++count; + break; + case VoxelMesherJobStep::TYPE_NORMAL_LOD: + ++count; + break; + case VoxelMesherJobStep::TYPE_DROP_UV2: + ++count; + break; + case VoxelMesherJobStep::TYPE_MERGE_VERTS: + ++count; + break; + case VoxelMesherJobStep::TYPE_BAKE_TEXTURE: + ++count; + break; + case VoxelMesherJobStep::TYPE_SIMPLIFY_MESH: +#ifdef MESH_UTILS_PRESENT + count += step->get_simplification_steps(); +#endif + break; + default: + break; + } + } + + //allocate + if (count > 0) + chunk->meshes_create(VoxelChunkDefault::MESH_INDEX_PROP, count); + + } else { + //we have the meshes, just clear + int count = chunk->mesh_rid_get_count(VoxelChunkDefault::MESH_INDEX_PROP, VoxelChunkDefault::MESH_TYPE_INDEX_MESH); + + for (int i = 0; i < count; ++i) { + mesh_rid = chunk->mesh_rid_get_index(VoxelChunkDefault::MESH_INDEX_PROP, VoxelChunkDefault::MESH_TYPE_INDEX_MESH, i); + + if (VS::get_singleton()->mesh_get_surface_count(mesh_rid) > 0) +#if !GODOT4 + VS::get_singleton()->mesh_remove_surface(mesh_rid, 0); +#else + VS::get_singleton()->mesh_clear(mesh_rid); +#endif + } + } + } + + for (; _current_job_step < _job_steps.size();) { + Ref step = _job_steps[_current_job_step]; + + ERR_FAIL_COND(!step.is_valid()); + + switch (step->get_job_type()) { + case VoxelMesherJobStep::TYPE_NORMAL: + step_type_normal(); + break; + case VoxelMesherJobStep::TYPE_NORMAL_LOD: + step_type_normal_lod(); + break; + case VoxelMesherJobStep::TYPE_DROP_UV2: + step_type_drop_uv2(); + break; + case VoxelMesherJobStep::TYPE_MERGE_VERTS: + step_type_merge_verts(); + break; + case VoxelMesherJobStep::TYPE_BAKE_TEXTURE: + step_type_bake_texture(); + break; + case VoxelMesherJobStep::TYPE_SIMPLIFY_MESH: + step_type_simplify_mesh(); + break; + case VoxelMesherJobStep::TYPE_OTHER: + //do nothing + break; + } + + ++_current_job_step; + + if (should_return()) { + return; + } + } + + reset_stages(); + //next_phase(); + + set_complete(true); //So threadpool knows it's done + next_job(); +} + +void VoxelPropJob::step_type_normal() { + //TODO add a lighting generation step + + Ref chunk = _chunk; + + temp_mesh_arr = _prop_mesher->build_mesh(); + + RID mesh_rid = chunk->mesh_rid_get_index(VoxelChunkDefault::MESH_INDEX_PROP, VoxelChunkDefault::MESH_TYPE_INDEX_MESH, _current_mesh); + + VS::get_singleton()->mesh_add_surface_from_arrays(mesh_rid, VisualServer::PRIMITIVE_TRIANGLES, temp_mesh_arr); + + Ref lmat; + + if (chunk->prop_material_cache_key_has()) { + lmat = chunk->get_library()->prop_material_cache_get(_chunk->prop_material_cache_key_get())->material_lod_get(_current_mesh); + } else { + lmat = chunk->get_library()->prop_material_lod_get(_current_mesh); + } + + if (lmat.is_valid()) { + VisualServer::get_singleton()->mesh_surface_set_material(mesh_rid, 0, lmat->get_rid()); + } + + ++_current_mesh; +} + +void VoxelPropJob::step_type_normal_lod() { + print_error("Error: step_type_normal_lod doesn't work for VoxelPropJobs!"); + + ++_current_mesh; +} + +void VoxelPropJob::step_type_drop_uv2() { + Ref chunk = _chunk; + + RID mesh_rid = chunk->mesh_rid_get_index(VoxelChunkDefault::MESH_INDEX_PROP, VoxelChunkDefault::MESH_TYPE_INDEX_MESH, _current_mesh); + + temp_mesh_arr[VisualServer::ARRAY_TEX_UV2] = Variant(); + + VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh_rid, VisualServer::PRIMITIVE_TRIANGLES, temp_mesh_arr); + + Ref lmat; + + if (chunk->prop_material_cache_key_has()) { + lmat = chunk->get_library()->prop_material_cache_get(_chunk->prop_material_cache_key_get())->material_lod_get(_current_mesh); + } else { + lmat = chunk->get_library()->prop_material_lod_get(_current_mesh); + } + + if (lmat.is_valid()) { + VisualServer::get_singleton()->mesh_surface_set_material(mesh_rid, 0, lmat->get_rid()); + } + + ++_current_mesh; +} + +void VoxelPropJob::step_type_merge_verts() { + Array temp_mesh_arr2 = merge_mesh_array(temp_mesh_arr); + temp_mesh_arr = temp_mesh_arr2; + + Ref chunk = _chunk; + RID mesh_rid = chunk->mesh_rid_get_index(VoxelChunkDefault::MESH_INDEX_PROP, VoxelChunkDefault::MESH_TYPE_INDEX_MESH, _current_mesh); + + VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh_rid, VisualServer::PRIMITIVE_TRIANGLES, temp_mesh_arr); + + Ref lmat; + + if (chunk->prop_material_cache_key_has()) { + lmat = chunk->get_library()->prop_material_cache_get(_chunk->prop_material_cache_key_get())->material_lod_get(_current_mesh); + } else { + lmat = chunk->get_library()->prop_material_lod_get(_current_mesh); + } + + if (lmat.is_valid()) { + VisualServer::get_singleton()->mesh_surface_set_material(mesh_rid, 0, lmat->get_rid()); + } + + ++_current_mesh; +} + +void VoxelPropJob::step_type_bake_texture() { + Ref chunk = _chunk; + + Ref mat = chunk->get_library()->material_lod_get(0); + Ref spmat = chunk->get_library()->material_lod_get(0); + Ref tex; + + if (mat.is_valid()) { + tex = mat->get_shader_param("texture_albedo"); + } else if (spmat.is_valid()) { + tex = spmat->get_texture(SpatialMaterial::TEXTURE_ALBEDO); + } + + if (tex.is_valid()) { + temp_mesh_arr = bake_mesh_array_uv(temp_mesh_arr, tex); + temp_mesh_arr[VisualServer::ARRAY_TEX_UV] = Variant(); + + RID mesh_rid = chunk->mesh_rid_get_index(VoxelChunkDefault::MESH_INDEX_PROP, VoxelChunkDefault::MESH_TYPE_INDEX_MESH, _current_mesh); + + VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh_rid, VisualServer::PRIMITIVE_TRIANGLES, temp_mesh_arr); + + Ref lmat; + + if (chunk->prop_material_cache_key_has()) { + lmat = chunk->get_library()->prop_material_cache_get(_chunk->prop_material_cache_key_get())->material_lod_get(_current_mesh); + } else { + lmat = chunk->get_library()->prop_material_lod_get(_current_mesh); + } + + if (lmat.is_valid()) { + VisualServer::get_singleton()->mesh_surface_set_material(mesh_rid, 0, lmat->get_rid()); + } + } + + ++_current_mesh; +} + +void VoxelPropJob::step_type_simplify_mesh() { +#ifdef MESH_UTILS_PRESENT + + Ref chunk = _chunk; + Ref step = _job_steps[_current_job_step]; + ERR_FAIL_COND(!step.is_valid()); + Ref fqms = step->get_fqms(); + ERR_FAIL_COND(!fqms.is_valid()); + + fqms->initialize(temp_mesh_arr); + + for (int i = 0; i < step->get_simplification_steps(); ++i) { + fqms->simplify_mesh(temp_mesh_arr.size() * step->get_simplification_step_ratio(), step->get_simplification_agressiveness()); + temp_mesh_arr = fqms->get_arrays(); + + RID mesh_rid = chunk->mesh_rid_get_index(VoxelChunkDefault::MESH_INDEX_PROP, VoxelChunkDefault::MESH_TYPE_INDEX_MESH, _current_mesh); + + VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh_rid, VisualServer::PRIMITIVE_TRIANGLES, temp_mesh_arr); + + Ref lmat; + + if (chunk->prop_material_cache_key_has()) { + lmat = chunk->get_library()->prop_material_cache_get(_chunk->prop_material_cache_key_get())->material_lod_get(_current_mesh); + } else { + lmat = chunk->get_library()->prop_material_lod_get(_current_mesh); + } + + if (lmat.is_valid()) { + VisualServer::get_singleton()->mesh_surface_set_material(mesh_rid, 0, lmat->get_rid()); + } + + ++_current_mesh; + } + +#endif +} + VoxelPropJob::VoxelPropJob() { set_build_phase_type(BUILD_PHASE_TYPE_PHYSICS_PROCESS); + + _current_job_step = 0; + _current_mesh = 0; } VoxelPropJob::~VoxelPropJob() { @@ -389,5 +865,11 @@ void VoxelPropJob::_bind_methods() { ClassDB::bind_method(D_METHOD("set_prop_mesher", "mesher"), &VoxelPropJob::set_prop_mesher); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "prop_mesher", PROPERTY_HINT_RESOURCE_TYPE, "VoxelMesher", 0), "set_prop_mesher", "get_prop_mesher"); + ClassDB::bind_method(D_METHOD("get_jobs_step", "index"), &VoxelPropJob::get_jobs_step); + ClassDB::bind_method(D_METHOD("set_jobs_step", "index", "mesher"), &VoxelPropJob::set_jobs_step); + ClassDB::bind_method(D_METHOD("remove_jobs_step", "index"), &VoxelPropJob::remove_jobs_step); + ClassDB::bind_method(D_METHOD("add_jobs_step", "mesher"), &VoxelPropJob::add_jobs_step); + ClassDB::bind_method(D_METHOD("get_jobs_step_count"), &VoxelPropJob::get_jobs_step_count); + ClassDB::bind_method(D_METHOD("_physics_process", "delta"), &VoxelPropJob::_physics_process); } diff --git a/world/jobs/voxel_prop_job.h b/world/jobs/voxel_prop_job.h index 9fc68eb..e50d77f 100644 --- a/world/jobs/voxel_prop_job.h +++ b/world/jobs/voxel_prop_job.h @@ -25,6 +25,8 @@ SOFTWARE. #include "voxel_job.h" +#include "voxel_mesher_job_step.h" + class VoxelMesher; class VoxelPropJob : public VoxelJob { @@ -34,13 +36,32 @@ public: Ref get_prop_mesher() const; void set_prop_mesher(const Ref &mesher); + Ref get_jobs_step(const int index) const; + void set_jobs_step(const int index, const Ref &step); + void remove_jobs_step(const int index); + void add_jobs_step(const Ref &step); + int get_jobs_step_count() const; + void phase_physics_process(); void phase_prop(); + void new_phase_prop(); void _physics_process(float delta); void _execute_phase(); + void new_execute_phase(); void _reset(); + void phase_setup(); + + void phase_steps(); + + void step_type_normal(); + void step_type_normal_lod(); + void step_type_drop_uv2(); + void step_type_merge_verts(); + void step_type_bake_texture(); + void step_type_simplify_mesh(); + VoxelPropJob(); ~VoxelPropJob(); @@ -49,6 +70,10 @@ protected: Ref _prop_mesher; + Vector> _job_steps; + int _current_job_step; + int _current_mesh; + Array temp_mesh_arr; };