diff --git a/src/constants.h b/src/constants.h index c2c8f194..c737ca75 100644 --- a/src/constants.h +++ b/src/constants.h @@ -5,9 +5,7 @@ using namespace godot; -////////////////////////////////////// -// Macro Constants & Syntactic Sugar -////////////////////////////////////// +// Constants #define RS RenderingServer::get_singleton() @@ -19,19 +17,56 @@ using namespace godot; #define COLOR_NORMAL Color(0.5f, 0.5f, 1.0f, 1.0f) #define COLOR_CONTROL Color(as_float(enc_auto(true)), 0.f, 0.f, 1.0f) +// For consistency between msvc, gcc, clang + #ifndef __FLT_MAX__ #define __FLT_MAX__ FLT_MAX #endif +// Double precision builds + #ifdef REAL_T_IS_DOUBLE typedef PackedFloat64Array PackedRealArray; #else typedef PackedFloat32Array PackedRealArray; #endif +// Set class name for logger.h + #define CLASS_NAME() const String __class__ = get_class_static() + \ String("#") + String::num_uint64(get_instance_id()).right(4); #define CLASS_NAME_STATIC(p_name) static inline const char *__class__ = p_name; +// Validation macros + +#define NOP // a return value for void, to avoid warnings + +#define IS_INIT(ret) \ + if (_terrain == nullptr) { \ + return ret; \ + } + +#define IS_INIT_MESG(mesg, ret) \ + if (_terrain == nullptr) { \ + LOG(ERROR, mesg); \ + return ret; \ + } + +#define IS_INIT_COND(cond, ret) \ + if (_terrain == nullptr || cond) { \ + return ret; \ + } + +#define IS_STORAGE_INIT(ret) \ + if (_terrain == nullptr || _terrain->get_storage().is_null()) { \ + return ret; \ + } + +#define IS_STORAGE_INIT_MESG(mesg, ret) \ + if (_terrain == nullptr || _terrain->get_storage().is_null()) { \ + LOG(ERROR, mesg); \ + return ret; \ + } + #endif // CONSTANTS_CLASS_H \ No newline at end of file diff --git a/src/terrain_3d.cpp b/src/terrain_3d.cpp index 010f09f3..b6f54480 100644 --- a/src/terrain_3d.cpp +++ b/src/terrain_3d.cpp @@ -51,9 +51,9 @@ void Terrain3D::_initialize() { LOG(DEBUG, "Connecting texture_list.textures_changed to _material->_update_texture_arrays()"); _texture_list->connect("textures_changed", callable_mp(_material.ptr(), &Terrain3DMaterial::_update_texture_arrays)); } - if (!_storage->is_connected("region_size_changed", callable_mp(_material.ptr(), &Terrain3DMaterial::_set_region_size))) { - LOG(DEBUG, "Connecting region_size_changed signal to _material->_set_region_size()"); - _storage->connect("region_size_changed", callable_mp(_material.ptr(), &Terrain3DMaterial::_set_region_size)); + if (!_storage->is_connected("region_size_changed", callable_mp(_material.ptr(), &Terrain3DMaterial::_update_regions))) { + LOG(DEBUG, "Connecting region_size_changed signal to _material->_update_regions()"); + _storage->connect("region_size_changed", callable_mp(_material.ptr(), &Terrain3DMaterial::_update_regions)); } if (!_storage->is_connected("regions_changed", callable_mp(_material.ptr(), &Terrain3DMaterial::_update_regions))) { LOG(DEBUG, "Connecting regions_changed signal to _material->_update_regions()"); @@ -66,9 +66,9 @@ void Terrain3D::_initialize() { // Initialize the system if (!_initialized && _is_inside_world && is_inside_tree()) { - _material->initialize(_storage->get_region_size()); - _material->set_mesh_vertex_spacing(_mesh_vertex_spacing); - _storage->update_regions(true); // generate map arrays + _storage->initialize(this); + _material->initialize(this); + _material->_update_regions(); _texture_list->update_list(); // generate texture arrays _setup_mouse_picking(); _build(_mesh_lods, _mesh_size); @@ -656,9 +656,6 @@ void Terrain3D::set_mesh_vertex_spacing(real_t p_spacing) { if (_mesh_vertex_spacing != p_spacing) { LOG(INFO, "Setting mesh vertex spacing: ", p_spacing); _mesh_vertex_spacing = p_spacing; - if (_storage != nullptr) { - _storage->_mesh_vertex_spacing = p_spacing; - } _clear(); _initialize(); } diff --git a/src/terrain_3d_editor.cpp b/src/terrain_3d_editor.cpp index d36019f8..de7caa50 100644 --- a/src/terrain_3d_editor.cpp +++ b/src/terrain_3d_editor.cpp @@ -508,12 +508,6 @@ void Terrain3DEditor::_apply_undo(const Array &p_set) { // Public Functions /////////////////////////// -Terrain3DEditor::Terrain3DEditor() { -} - -Terrain3DEditor::~Terrain3DEditor() { -} - void Terrain3DEditor::set_brush_data(Dictionary p_data) { if (p_data.is_empty()) { return; @@ -530,10 +524,7 @@ void Terrain3DEditor::set_tool(Tool p_tool) { // Called on mouse click void Terrain3DEditor::start_operation(Vector3 p_global_position) { - if (!_terrain) { - LOG(ERROR, "_terrain not set"); - return; - } + IS_STORAGE_INIT_MESG("Terrain isn't initialized", NOP); _setup_undo(); _pending_undo = true; _modified = false; @@ -547,10 +538,10 @@ void Terrain3DEditor::start_operation(Vector3 p_global_position) { // Called on mouse movement with left mouse button down void Terrain3DEditor::operate(Vector3 p_global_position, real_t p_camera_direction) { + IS_STORAGE_INIT_MESG("Terrain isn't initialized", NOP); if (!_pending_undo) { return; } - _operation_movement = p_global_position - _operation_position; _operation_position = p_global_position; @@ -563,10 +554,7 @@ void Terrain3DEditor::operate(Vector3 p_global_position, real_t p_camera_directi // Called on left mouse button released void Terrain3DEditor::stop_operation() { - if (!_terrain) { - LOG(ERROR, "_terrain not set"); - return; - } + IS_STORAGE_INIT_MESG("Terrain isn't initialized", NOP); if (_pending_undo && _modified) { _store_undo(); _pending_undo = false; diff --git a/src/terrain_3d_editor.h b/src/terrain_3d_editor.h index cd6f2771..4b76df7a 100644 --- a/src/terrain_3d_editor.h +++ b/src/terrain_3d_editor.h @@ -106,7 +106,6 @@ class Terrain3DEditor : public Object { }; private: - // Object references Terrain3D *_terrain = nullptr; // Painter settings & variables @@ -132,8 +131,8 @@ class Terrain3DEditor : public Object { void _apply_undo(const Array &p_set); public: - Terrain3DEditor(); - ~Terrain3DEditor(); + Terrain3DEditor() {} + ~Terrain3DEditor() {} void set_terrain(Terrain3D *p_terrain) { _terrain = p_terrain; } Terrain3D *get_terrain() const { return _terrain; } diff --git a/src/terrain_3d_material.cpp b/src/terrain_3d_material.cpp index d264bfb8..9edc795d 100644 --- a/src/terrain_3d_material.cpp +++ b/src/terrain_3d_material.cpp @@ -231,8 +231,7 @@ void Terrain3DMaterial::_update_shader_if_defines_have_changed() { _update_shader(); } } void Terrain3DMaterial::_update_shader() { - if (!_initialized || _material == Variant::NIL) { - return; } + IS_INIT(NOP); LOG(INFO, "Updating shader"); RID shader_rid; if (_shader_override_enabled && _shader_override.is_valid()) { @@ -270,18 +269,16 @@ void Terrain3DMaterial::_update_shader() { // Fetch saved shader parameters, converting textures to RIDs for (int i = 0; i < _active_params.size(); i++) { StringName param = _active_params[i]; - if (!param.begins_with("_")) { - Variant value = _shader_params[param]; - if (value.get_type() == Variant::OBJECT) { - Ref tex = value; - if (tex.is_valid()) { - RS->material_set_param(_material, param, tex->get_rid()); - } else { - RS->material_set_param(_material, param, Variant()); - } + Variant value = _shader_params[param]; + if (value.get_type() == Variant::OBJECT) { + Ref tex = value; + if (tex.is_valid()) { + RS->material_set_param(_material, param, tex->get_rid()); } else { - RS->material_set_param(_material, param, value); + RS->material_set_param(_material, param, Variant()); } + } else { + RS->material_set_param(_material, param, value); } } @@ -329,63 +326,61 @@ void Terrain3DMaterial::_update_shader() { notify_property_list_changed(); } -// Array expects -// 0: height maps texture array RID -// 1: control maps RID -// 2: color maps RID -// 3: region map packedByteArray -// 4: region offsets array -void Terrain3DMaterial::_update_regions(const Array &p_args) { - if (!_initialized) { - return; - } +void Terrain3DMaterial::_update_regions() { + IS_STORAGE_INIT(NOP); LOG(INFO, "Updating region maps in shader"); - if (p_args.size() != 5) { - LOG(ERROR, "Expected 5 arguments. Received: ", p_args.size()); - return; - } - RID height_rid = p_args[0]; - RID control_rid = p_args[1]; - RID color_rid = p_args[2]; - RS->material_set_param(_material, "_height_maps", height_rid); - RS->material_set_param(_material, "_control_maps", control_rid); - RS->material_set_param(_material, "_color_maps", color_rid); - LOG(DEBUG, "Height map RID: ", height_rid); - LOG(DEBUG, "Control map RID: ", control_rid); - LOG(DEBUG, "Color map RID: ", color_rid); - - _region_map = p_args[3]; - LOG(DEBUG, "_region_map.size(): ", _region_map.size()); - if (_region_map.size() != Terrain3DStorage::REGION_MAP_SIZE * Terrain3DStorage::REGION_MAP_SIZE) { - LOG(ERROR, "Expected _region_map.size() of ", Terrain3DStorage::REGION_MAP_SIZE * Terrain3DStorage::REGION_MAP_SIZE); + Ref storage = _terrain->get_storage(); + RS->material_set_param(_material, "_height_maps", storage->get_height_rid()); + RS->material_set_param(_material, "_control_maps", storage->get_control_rid()); + RS->material_set_param(_material, "_color_maps", storage->get_color_rid()); + LOG(DEBUG, "Height map RID: ", storage->get_height_rid()); + LOG(DEBUG, "Control map RID: ", storage->get_control_rid()); + LOG(DEBUG, "Color map RID: ", storage->get_color_rid()); + + PackedInt32Array region_map = storage->get_region_map(); + LOG(DEBUG, "region_map.size(): ", region_map.size()); + if (region_map.size() != Terrain3DStorage::REGION_MAP_SIZE * Terrain3DStorage::REGION_MAP_SIZE) { + LOG(ERROR, "Expected region_map.size() of ", Terrain3DStorage::REGION_MAP_SIZE * Terrain3DStorage::REGION_MAP_SIZE); } - RS->material_set_param(_material, "_region_map", _region_map); + RS->material_set_param(_material, "_region_map", region_map); RS->material_set_param(_material, "_region_map_size", Terrain3DStorage::REGION_MAP_SIZE); if (Terrain3D::debug_level >= DEBUG) { LOG(DEBUG, "Region map"); - for (int i = 0; i < _region_map.size(); i++) { - if (_region_map[i]) { - LOG(DEBUG, "Region id: ", _region_map[i], " array index: ", i); + for (int i = 0; i < region_map.size(); i++) { + if (region_map[i]) { + LOG(DEBUG, "Region id: ", region_map[i], " array index: ", i); } } } - TypedArray region_offsets = p_args[4]; + TypedArray region_offsets = storage->get_region_offsets(); LOG(DEBUG, "Region_offsets size: ", region_offsets.size(), " ", region_offsets); RS->material_set_param(_material, "_region_offsets", region_offsets); + real_t region_size = real_t(storage->get_region_size()); + LOG(DEBUG, "Setting region size in material: ", region_size); + RS->material_set_param(_material, "_region_size", region_size); + RS->material_set_param(_material, "_region_pixel_size", 1.0f / region_size); + + real_t spacing = _terrain->get_mesh_vertex_spacing(); + LOG(DEBUG, "Setting mesh vertex spacing in material: ", spacing); + RS->material_set_param(_material, "_mesh_vertex_spacing", spacing); + RS->material_set_param(_material, "_mesh_vertex_density", 1.0f / spacing); + _generate_region_blend_map(); } void Terrain3DMaterial::_generate_region_blend_map() { + IS_STORAGE_INIT_MESG("Material not initialized", NOP); + PackedInt32Array region_map = _terrain->get_storage()->get_region_map(); int rsize = Terrain3DStorage::REGION_MAP_SIZE; - if (_region_map.size() == rsize * rsize) { + if (region_map.size() == rsize * rsize) { LOG(DEBUG, "Regenerating ", Vector2i(512, 512), " region blend map"); Ref region_blend_img = Image::create(rsize, rsize, false, Image::FORMAT_RH); for (int y = 0; y < rsize; y++) { for (int x = 0; x < rsize; x++) { - if (_region_map[y * rsize + x] > 0) { + if (region_map[y * rsize + x] > 0) { region_blend_img->set_pixel(x, y, COLOR_WHITE); } } @@ -399,42 +394,33 @@ void Terrain3DMaterial::_generate_region_blend_map() { } // Called from signal connected in Terrain3D, emitted by texture_list -void Terrain3DMaterial::_update_texture_arrays(const Ref p_texture_list) { - if (!_initialized) { - return; - } +void Terrain3DMaterial::_update_texture_arrays() { + IS_STORAGE_INIT_MESG("Material not initialized", NOP); + Ref texture_list = _terrain->get_texture_list(); LOG(INFO, "Updating texture arrays in shader"); - if (p_texture_list.is_null()) { - LOG(ERROR, "Received null p_texture_list"); + if (texture_list.is_null()) { + LOG(ERROR, "Texture_list is null"); return; } - RS->material_set_param(_material, "_texture_array_albedo", p_texture_list->get_albedo_array_rid()); - RS->material_set_param(_material, "_texture_array_normal", p_texture_list->get_normal_array_rid()); - RS->material_set_param(_material, "_texture_color_array", p_texture_list->get_texture_colors()); - RS->material_set_param(_material, "_texture_uv_scale_array", p_texture_list->get_texture_uv_scales()); - RS->material_set_param(_material, "_texture_uv_rotation_array", p_texture_list->get_texture_uv_rotations()); + RS->material_set_param(_material, "_texture_array_albedo", texture_list->get_albedo_array_rid()); + RS->material_set_param(_material, "_texture_array_normal", texture_list->get_normal_array_rid()); + RS->material_set_param(_material, "_texture_color_array", texture_list->get_texture_colors()); + RS->material_set_param(_material, "_texture_uv_scale_array", texture_list->get_texture_uv_scales()); + RS->material_set_param(_material, "_texture_uv_rotation_array", texture_list->get_texture_uv_rotations()); // Enable checkered view if texture_count is 0, disable if not - if (p_texture_list->get_texture_count() == 0) { + if (texture_list->get_texture_count() == 0) { if (_debug_view_checkered == false) { set_debug_view_checkered(true); LOG(DEBUG, "No textures, enabling checkered view"); } } else { set_debug_view_checkered(false); - LOG(DEBUG, "Texture count >0: ", p_texture_list->get_texture_count(), ", disabling checkered view"); + LOG(DEBUG, "Texture count >0: ", texture_list->get_texture_count(), ", disabling checkered view"); } } -void Terrain3DMaterial::_set_region_size(int p_size) { - LOG(INFO, "Setting region size in material: ", p_size); - _region_size = CLAMP(p_size, 64, 4096); - _region_sizev = Vector2i(_region_size, _region_size); - RS->material_set_param(_material, "_region_size", real_t(_region_size)); - RS->material_set_param(_material, "_region_pixel_size", 1.0f / real_t(_region_size)); -} - void Terrain3DMaterial::_set_shader_parameters(const Dictionary &p_dict) { LOG(INFO, "Setting shader params dictionary: ", p_dict.size()); _shader_params = p_dict; @@ -447,25 +433,29 @@ void Terrain3DMaterial::_set_shader_parameters(const Dictionary &p_dict) { // This function serves as the constructor which is initialized by the class Terrain3D. // Godot likes to create resource objects at startup, so this prevents it from creating // uninitialized materials. -void Terrain3DMaterial::initialize(int p_region_size) { +void Terrain3DMaterial::initialize(Terrain3D *p_terrain) { + if (p_terrain != nullptr) { + _terrain = p_terrain; + } else { + LOG(ERROR, "Initialization failed, p_terrain is null"); + return; + } LOG(INFO, "Initializing material"); _preload_shaders(); _material = RS->material_create(); _shader = RS->shader_create(); _shader_tmp.instantiate(); - _set_region_size(p_region_size); LOG(DEBUG, "Mat RID: ", _material, ", _shader RID: ", _shader); - _initialized = true; _update_shader(); + _update_regions(); } Terrain3DMaterial::~Terrain3DMaterial() { + IS_INIT(NOP); LOG(INFO, "Destroying material"); - if (_initialized) { - RS->free_rid(_material); - RS->free_rid(_shader); - _generated_region_blend_map.clear(); - } + RS->free_rid(_material); + RS->free_rid(_shader); + _generated_region_blend_map.clear(); } RID Terrain3DMaterial::get_shader_rid() const { @@ -504,13 +494,6 @@ Variant Terrain3DMaterial::get_shader_param(const StringName &p_name) const { return value; } -void Terrain3DMaterial::set_mesh_vertex_spacing(real_t p_spacing) { - LOG(INFO, "Setting mesh vertex spacing in material: ", p_spacing); - _mesh_vertex_spacing = p_spacing; - RS->material_set_param(_material, "_mesh_vertex_spacing", p_spacing); - RS->material_set_param(_material, "_mesh_vertex_density", 1.0f / p_spacing); -} - void Terrain3DMaterial::save() { LOG(DEBUG, "Generating parameter list from shaders"); // Get shader parameters from default shader (eg bg_world) @@ -563,10 +546,7 @@ void Terrain3DMaterial::save() { // Add shader uniforms to properties. Hides uniforms that begin with _ void Terrain3DMaterial::_get_property_list(List *p_list) const { Resource::_get_property_list(p_list); - if (!_initialized) { - return; - } - + IS_INIT(NOP); Array param_list; if (_shader_override_enabled && _shader_override.is_valid()) { // Get shader parameters from custom shader @@ -592,6 +572,9 @@ void Terrain3DMaterial::_get_property_list(List *p_list) const { pi.usage = PROPERTY_USAGE_EDITOR; p_list->push_back(pi); + // Populate list of public parameters for current shader + _active_params.push_back(name); + // Store this param in a dictionary that is saved in the resource file // Initially set with default value // Also acts as a cache for _get @@ -601,9 +584,6 @@ void Terrain3DMaterial::_get_property_list(List *p_list) const { _property_get_revert(name, _shader_params[name]); } } - - // Populate list of public and private parameters for current shader - _active_params.push_back(name); } return; } @@ -611,9 +591,7 @@ void Terrain3DMaterial::_get_property_list(List *p_list) const { // Flag uniforms with non-default values // This is called 10x more than the others, so be efficient bool Terrain3DMaterial::_property_can_revert(const StringName &p_name) const { - if (!_initialized || !_active_params.has(p_name)) { - return Resource::_property_can_revert(p_name); - } + IS_INIT_COND(!_active_params.has(p_name), Resource::_property_can_revert(p_name)); RID shader; if (_shader_override_enabled && _shader_override.is_valid()) { shader = _shader_override->get_rid(); @@ -630,9 +608,7 @@ bool Terrain3DMaterial::_property_can_revert(const StringName &p_name) const { // Provide uniform default values bool Terrain3DMaterial::_property_get_revert(const StringName &p_name, Variant &r_property) const { - if (!_initialized || !_active_params.has(p_name)) { - return Resource::_property_get_revert(p_name, r_property); - } + IS_INIT_COND(!_active_params.has(p_name), Resource::_property_get_revert(p_name, r_property)); RID shader; if (_shader_override_enabled && _shader_override.is_valid()) { shader = _shader_override->get_rid(); @@ -647,10 +623,7 @@ bool Terrain3DMaterial::_property_get_revert(const StringName &p_name, Variant & } bool Terrain3DMaterial::_set(const StringName &p_name, const Variant &p_property) { - if (!_initialized || !_active_params.has(p_name)) { - return Resource::_set(p_name, p_property); - } - + IS_INIT_COND(!_active_params.has(p_name), Resource::_set(p_name, p_property)); if (p_property.get_type() == Variant::NIL) { RS->material_set_param(_material, p_name, Variant()); _shader_params.erase(p_name); @@ -677,9 +650,7 @@ bool Terrain3DMaterial::_set(const StringName &p_name, const Variant &p_property // This is called 200x more than the others, every second the material is open in the // inspector, so be efficient bool Terrain3DMaterial::_get(const StringName &p_name, Variant &r_property) const { - if (!_initialized || !_active_params.has(p_name)) { - return Resource::_get(p_name, r_property); - } + IS_INIT_COND(!_active_params.has(p_name), Resource::_get(p_name, r_property)); r_property = RS->material_get_param(_material, p_name); // Material server only has RIDs, but inspector needs objects for things like Textures @@ -755,7 +726,7 @@ String Terrain3DMaterial::_format_string_for_inline_help (String _source) { return _source.replace("\n\n", "[__TEMP_CRLF__]").replace("\n", "").replace("[__TEMP_CRLF__]", "\n\n"); } void Terrain3DMaterial::_safe_material_set_param(StringName _param, Variant _value) { - if (_initialized && _material.is_valid()) { + if (_terrain != nullptr && _material.is_valid()) { RS->material_set_param(_material, _param, _value); } } MAKE_MANAGED_FUNCTIONS() diff --git a/src/terrain_3d_material.h b/src/terrain_3d_material.h index fc7fe135..5d6f2647 100644 --- a/src/terrain_3d_material.h +++ b/src/terrain_3d_material.h @@ -39,9 +39,8 @@ class Terrain3DMaterial : public Resource { }; private: - PRIVATE_MANAGED_VARS() + Terrain3D *_terrain = nullptr; - bool _initialized = false; RID _material; RID _shader; bool _shader_override_enabled = false; @@ -51,13 +50,8 @@ class Terrain3DMaterial : public Resource { String _last_generated_defines = ""; mutable TypedArray _active_params; // All shader params in the current shader mutable Dictionary _shader_params; // Public shader params saved to disk - - // Cached data from Storage - int _region_size = 1024; - real_t _mesh_vertex_spacing = 1.0f; - Vector2i _region_sizev = Vector2i(_region_size, _region_size); - PackedInt32Array _region_map; GeneratedTexture _generated_region_blend_map; // 512x512 blurred image of region_map + PRIVATE_MANAGED_VARS() // Static Functions static String _format_string_for_inline_help (String _source); @@ -69,10 +63,9 @@ class Terrain3DMaterial : public Resource { String _generate_shader_code(String _explicitDefines = ""); //String _inject_editor_code(String p_shader); void _update_shader(); - void _update_regions(const Array &p_args); + void _update_regions(); void _generate_region_blend_map(); - void _update_texture_arrays(const Ref p_texture_list); - void _set_region_size(int p_size); + void _update_texture_arrays(); void _set_shader_parameters(const Dictionary &p_dict); Dictionary _get_shader_parameters() const { return _shader_params; } @@ -85,7 +78,7 @@ class Terrain3DMaterial : public Resource { public: Terrain3DMaterial(){}; - void initialize(int p_region_size); + void initialize(Terrain3D *p_terrain); ~Terrain3DMaterial(); RID get_material_rid() const { return _material; } @@ -100,7 +93,6 @@ class Terrain3DMaterial : public Resource { void set_shader_param(const StringName &p_name, const Variant &p_value); Variant get_shader_param(const StringName &p_name) const; - void set_mesh_vertex_spacing(real_t p_spacing); void save(); String _add_if_exists(String _current, String _snippetID_); diff --git a/src/terrain_3d_storage.cpp b/src/terrain_3d_storage.cpp index 1e7d08ec..59d8a9c6 100644 --- a/src/terrain_3d_storage.cpp +++ b/src/terrain_3d_storage.cpp @@ -26,8 +26,16 @@ void Terrain3DStorage::_clear() { // Public Functions /////////////////////////// -Terrain3DStorage::Terrain3DStorage() { +void Terrain3DStorage::initialize(Terrain3D *p_terrain) { + if (p_terrain != nullptr) { + _terrain = p_terrain; + } else { + LOG(ERROR, "Initialization failed, p_terrain is null"); + return; + } + LOG(INFO, "Initializing storage"); _region_map.resize(REGION_MAP_SIZE * REGION_MAP_SIZE); + update_regions(true); // generate map arrays } Terrain3DStorage::~Terrain3DStorage() { @@ -115,7 +123,8 @@ void Terrain3DStorage::set_region_offsets(const TypedArray &p_offsets) /** Returns a region offset given a location */ Vector2i Terrain3DStorage::get_region_offset(Vector3 p_global_position) { - Vector3 descaled_position = p_global_position / _mesh_vertex_spacing; + IS_INIT_MESG("Storage not initialized", Vector2i()); + Vector3 descaled_position = p_global_position / _terrain->get_mesh_vertex_spacing(); return Vector2i((Vector2(descaled_position.x, descaled_position.z) / real_t(_region_size)).floor()); } @@ -138,6 +147,7 @@ int Terrain3DStorage::get_region_index(Vector3 p_global_position) { * p_update - rebuild the maps if true. Set to false if bulk adding many regions. */ Error Terrain3DStorage::add_region(Vector3 p_global_position, const TypedArray &p_images, bool p_update) { + IS_INIT_MESG("Storage not initialized", FAILED); Vector2i uv_offset = get_region_offset(p_global_position); LOG(INFO, "Adding region at ", p_global_position, ", uv_offset ", uv_offset, ", array size: ", p_images.size(), @@ -148,7 +158,7 @@ Error Terrain3DStorage::add_region(Vector3 p_global_position, const TypedArrayget_ticks_msec(); if (time - _last_region_bounds_error > 1000) { _last_region_bounds_error = time; - LOG(ERROR, "Specified position outside of maximum region map size: +/-", real_t((REGION_MAP_SIZE / 2) * _region_size) * _mesh_vertex_spacing); + LOG(ERROR, "Specified position outside of maximum region map size: +/-", real_t((REGION_MAP_SIZE / 2) * _region_size) * _terrain->get_mesh_vertex_spacing()); } return FAILED; } @@ -280,13 +290,7 @@ void Terrain3DStorage::update_regions(bool force_emit) { // Emit if requested or changes were made if (force_emit) { - Array region_signal_args; - region_signal_args.push_back(_generated_height_maps.get_rid()); - region_signal_args.push_back(_generated_control_maps.get_rid()); - region_signal_args.push_back(_generated_color_maps.get_rid()); - region_signal_args.push_back(_region_map); - region_signal_args.push_back(_region_offsets); - emit_signal("regions_changed", region_signal_args); + emit_signal("regions_changed"); } } @@ -410,6 +414,7 @@ TypedArray Terrain3DStorage::get_maps_copy(MapType p_map_type) const { } void Terrain3DStorage::set_pixel(MapType p_map_type, Vector3 p_global_position, Color p_pixel) { + IS_INIT_MESG("Storage not initialized", NOP); if (p_map_type < 0 || p_map_type >= TYPE_MAX) { LOG(ERROR, "Specified map type out of range"); return; @@ -419,7 +424,7 @@ void Terrain3DStorage::set_pixel(MapType p_map_type, Vector3 p_global_position, return; } Vector2i global_offset = Vector2i(get_region_offsets()[region]) * _region_size; - Vector3 descaled_position = p_global_position / _mesh_vertex_spacing; + Vector3 descaled_position = p_global_position / _terrain->get_mesh_vertex_spacing(); Vector2i img_pos = Vector2i( Vector2(descaled_position.x - global_offset.x, descaled_position.z - global_offset.y) @@ -429,6 +434,7 @@ void Terrain3DStorage::set_pixel(MapType p_map_type, Vector3 p_global_position, } Color Terrain3DStorage::get_pixel(MapType p_map_type, Vector3 p_global_position) { + IS_INIT_MESG("Storage not initialized", COLOR_NAN); if (p_map_type < 0 || p_map_type >= TYPE_MAX) { LOG(ERROR, "Specified map type out of range"); return COLOR_NAN; @@ -438,7 +444,7 @@ Color Terrain3DStorage::get_pixel(MapType p_map_type, Vector3 p_global_position) return COLOR_NAN; } Vector2i global_offset = Vector2i(get_region_offsets()[region]) * _region_size; - Vector3 descaled_position = p_global_position / _mesh_vertex_spacing; + Vector3 descaled_position = p_global_position / _terrain->get_mesh_vertex_spacing(); Vector2i img_pos = Vector2i( Vector2(descaled_position.x - global_offset.x, descaled_position.z - global_offset.y) @@ -453,7 +459,7 @@ real_t Terrain3DStorage::get_height(Vector3 p_global_position) { return NAN; } Vector3 &pos = p_global_position; - real_t &step = _mesh_vertex_spacing; + real_t step = _terrain->get_mesh_vertex_spacing(); pos.y = 0.f; // Round to nearest vertex Vector3 pos_round = Vector3( @@ -638,6 +644,7 @@ void Terrain3DStorage::save() { * p_scale - Scale all height values by this factor (applied after offset) */ void Terrain3DStorage::import_images(const TypedArray &p_images, Vector3 p_global_position, real_t p_offset, real_t p_scale) { + IS_INIT_MESG("Storage not initialized", NOP); if (p_images.size() != TYPE_MAX) { LOG(ERROR, "p_images.size() is ", p_images.size(), ". It should be ", TYPE_MAX, " even if some Images are blank or null"); return; @@ -664,16 +671,17 @@ void Terrain3DStorage::import_images(const TypedArray &p_images, Vector3 return; } - Vector3 descaled_position = p_global_position / _mesh_vertex_spacing; + real_t vertex_spacing = _terrain->get_mesh_vertex_spacing(); + Vector3 descaled_position = p_global_position / vertex_spacing; int max_dimension = _region_size * REGION_MAP_SIZE / 2; if ((abs(descaled_position.x) > max_dimension) || (abs(descaled_position.z) > max_dimension)) { - LOG(ERROR, "Specify a position within +/-", Vector3(max_dimension, 0.f, max_dimension) * _mesh_vertex_spacing); + LOG(ERROR, "Specify a position within +/-", Vector3(max_dimension, 0.f, max_dimension) * vertex_spacing); return; } if ((descaled_position.x + img_size.x > max_dimension) || (descaled_position.z + img_size.y > max_dimension)) { LOG(ERROR, img_size, " image will not fit at ", p_global_position, - ". Try ", -(img_size * _mesh_vertex_spacing) / 2.f, " to center"); + ". Try ", -(img_size * vertex_spacing) / 2.f, " to center"); return; } @@ -740,7 +748,7 @@ void Terrain3DStorage::import_images(const TypedArray &p_images, Vector3 } // Add the heightmap slice and only regenerate on the last one Vector3 position = Vector3(descaled_position.x + start_coords.x, 0.f, descaled_position.z + start_coords.y); - add_region(position * _mesh_vertex_spacing, images, (x == slices_width - 1 && y == slices_height - 1)); + add_region(position * vertex_spacing, images, (x == slices_width - 1 && y == slices_height - 1)); } } // for y < slices_height, x < slices_width } @@ -904,7 +912,7 @@ Vector3 Terrain3DStorage::get_mesh_vertex(int32_t p_lod, HeightFilter p_filter, height = get_height(p_global_position); for (int32_t dx = -step / 2; dx < step / 2; dx += 1) { for (int32_t dz = -step / 2; dz < step / 2; dz += 1) { - Vector3 position = p_global_position + Vector3(dx, 0.f, dz) * _mesh_vertex_spacing; + Vector3 position = p_global_position + Vector3(dx, 0.f, dz) * _terrain->get_mesh_vertex_spacing(); if (is_hole(get_control(position))) { height = NAN; break; @@ -925,10 +933,11 @@ Vector3 Terrain3DStorage::get_normal(Vector3 p_global_position) { if (region < 0 || region >= _region_offsets.size() || is_hole(get_control(p_global_position))) { return Vector3(NAN, NAN, NAN); } + real_t vertex_spacing = _terrain->get_mesh_vertex_spacing(); real_t height = get_height(p_global_position); - real_t u = height - get_height(p_global_position + Vector3(_mesh_vertex_spacing, 0.0f, 0.0f)); - real_t v = height - get_height(p_global_position + Vector3(0.f, 0.f, _mesh_vertex_spacing)); - Vector3 normal = Vector3(u, _mesh_vertex_spacing, v); + real_t u = height - get_height(p_global_position + Vector3(vertex_spacing, 0.0f, 0.0f)); + real_t v = height - get_height(p_global_position + Vector3(0.f, 0.f, vertex_spacing)); + Vector3 normal = Vector3(u, vertex_spacing, v); normal.normalize(); return normal; } diff --git a/src/terrain_3d_storage.h b/src/terrain_3d_storage.h index 6e3c72c1..1ffbf4b4 100644 --- a/src/terrain_3d_storage.h +++ b/src/terrain_3d_storage.h @@ -19,8 +19,6 @@ class Terrain3DStorage : public Resource { GDCLASS(Terrain3DStorage, Resource); CLASS_NAME(); - friend class Terrain3D; - public: // Constants static inline const real_t CURRENT_VERSION = 0.842f; static inline const int REGION_MAP_SIZE = 16; @@ -69,13 +67,14 @@ class Terrain3DStorage : public Resource { }; private: + Terrain3D *_terrain = nullptr; + // Storage Settings & flags real_t _version = 0.8f; // Set to ensure Godot always saves this bool _modified = false; bool _save_16_bit = false; RegionSize _region_size = SIZE_1024; Vector2i _region_sizev = Vector2i(_region_size, _region_size); - real_t _mesh_vertex_spacing = 1.0f; // Set by Terrain3D for get_normal() // Stored Data Vector2 _height_range = Vector2(0.f, 0.f); @@ -106,7 +105,8 @@ class Terrain3DStorage : public Resource { void _clear(); public: - Terrain3DStorage(); + Terrain3DStorage() {} + void initialize(Terrain3D *p_terrain); ~Terrain3DStorage(); void set_version(real_t p_version); @@ -127,10 +127,12 @@ class Terrain3DStorage : public Resource { // Regions void set_region_size(RegionSize p_size); RegionSize get_region_size() const { return _region_size; } + Vector2i get_region_sizev() const { return _region_sizev; } void set_region_offsets(const TypedArray &p_offsets); TypedArray get_region_offsets() const { return _region_offsets; } int get_region_count() const { return _region_offsets.size(); } Vector2i get_region_offset(Vector3 p_global_position); + PackedInt32Array get_region_map() const { return _region_map; } int get_region_index(Vector3 p_global_position); bool has_region(Vector3 p_global_position) { return get_region_index(p_global_position) != -1; } Error add_region(Vector3 p_global_position, const TypedArray &p_images = TypedArray(), bool p_update = true); @@ -145,10 +147,13 @@ class Terrain3DStorage : public Resource { TypedArray get_maps_copy(MapType p_map_type) const; void set_height_maps(const TypedArray &p_maps) { set_maps(TYPE_HEIGHT, p_maps); } TypedArray get_height_maps() const { return _height_maps; } + RID get_height_rid() { return _generated_height_maps.get_rid(); } void set_control_maps(const TypedArray &p_maps) { set_maps(TYPE_CONTROL, p_maps); } TypedArray get_control_maps() const { return _control_maps; } + RID get_control_rid() { return _generated_control_maps.get_rid(); } void set_color_maps(const TypedArray &p_maps) { set_maps(TYPE_COLOR, p_maps); } TypedArray get_color_maps() const { return _color_maps; } + RID get_color_rid() { return _generated_color_maps.get_rid(); } void set_pixel(MapType p_map_type, Vector3 p_global_position, Color p_pixel); Color get_pixel(MapType p_map_type, Vector3 p_global_position); void set_height(Vector3 p_global_position, real_t p_height); diff --git a/src/terrain_3d_texture_list.cpp b/src/terrain_3d_texture_list.cpp index 40e27904..96a7975c 100644 --- a/src/terrain_3d_texture_list.cpp +++ b/src/terrain_3d_texture_list.cpp @@ -40,6 +40,7 @@ void Terrain3DTextureList::_update_texture_files() { _generated_albedo_textures.clear(); _generated_normal_textures.clear(); if (_textures.is_empty()) { + emit_signal("textures_changed"); return; } @@ -113,7 +114,6 @@ void Terrain3DTextureList::_update_texture_files() { // Generate TextureArrays and replace nulls with a empty image - bool changed = false; if (_generated_albedo_textures.is_dirty() && albedo_size != Vector2i(0, 0)) { LOG(INFO, "Regenerating albedo texture array"); Array albedo_texture_array; @@ -137,7 +137,6 @@ void Terrain3DTextureList::_update_texture_files() { } if (!albedo_texture_array.is_empty()) { _generated_albedo_textures.create(albedo_texture_array); - changed = true; } } @@ -166,35 +165,31 @@ void Terrain3DTextureList::_update_texture_files() { } if (!normal_texture_array.is_empty()) { _generated_normal_textures.create(normal_texture_array); - changed = true; } } - if (changed) { - emit_signal("textures_changed", Ref(this)); - } + emit_signal("textures_changed"); } void Terrain3DTextureList::_update_texture_settings() { LOG(DEBUG, "Received setting_changed signal"); - if (_textures.is_empty()) { - return; - } - LOG(INFO, "Updating terrain color and scale arrays"); - _texture_colors.clear(); - _texture_uv_scales.clear(); - _texture_uv_rotations.clear(); + if (!_textures.is_empty()) { + LOG(INFO, "Updating terrain color and scale arrays"); + _texture_colors.clear(); + _texture_uv_scales.clear(); + _texture_uv_rotations.clear(); - for (int i = 0; i < _textures.size(); i++) { - Ref texture_set = _textures[i]; - if (texture_set.is_null()) { - continue; + for (int i = 0; i < _textures.size(); i++) { + Ref texture_set = _textures[i]; + if (texture_set.is_null()) { + continue; + } + _texture_colors.push_back(texture_set->get_albedo_color()); + _texture_uv_scales.push_back(texture_set->get_uv_scale()); + _texture_uv_rotations.push_back(texture_set->get_uv_rotation()); } - _texture_colors.push_back(texture_set->get_albedo_color()); - _texture_uv_scales.push_back(texture_set->get_uv_scale()); - _texture_uv_rotations.push_back(texture_set->get_uv_rotation()); } - emit_signal("textures_changed", Ref(this)); + emit_signal("textures_changed"); } ///////////////////////////