diff options
116 files changed, 1545 insertions, 1270 deletions
diff --git a/SConstruct b/SConstruct index 01f1ae638e..28395227d2 100644 --- a/SConstruct +++ b/SConstruct @@ -103,11 +103,13 @@ custom_tools = ["default"] platform_arg = ARGUMENTS.get("platform", ARGUMENTS.get("p", False)) -if os.name == "nt" and (platform_arg == "android" or methods.get_cmdline_bool("use_mingw", False)): - custom_tools = ["mingw"] +if platform_arg == "android": + custom_tools = ["clang", "clang++", "as", "ar", "link"] elif platform_arg == "javascript": # Use generic POSIX build toolchain for Emscripten. custom_tools = ["cc", "c++", "ar", "link", "textfile", "zip"] +elif os.name == "nt" and methods.get_cmdline_bool("use_mingw", False): + custom_tools = ["mingw"] # We let SCons build its default ENV as it includes OS-specific things which we don't # want to have to pull in manually. @@ -395,10 +397,7 @@ if selected_platform in platform_list: sys.path.insert(0, tmppath) import detect - if "create" in dir(detect): - env = detect.create(env_base) - else: - env = env_base.Clone() + env = env_base.Clone() if env["compiledb"]: # Generating the compilation DB (`compile_commands.json`) requires SCons 4.0.0 or later. diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp index edd48cf9cd..9d846f87c2 100644 --- a/core/extension/extension_api_dump.cpp +++ b/core/extension/extension_api_dump.cpp @@ -474,6 +474,38 @@ Dictionary NativeExtensionAPIDump::generate_extension_api() { } } { + //enums + Array enums; + + List<StringName> enum_names; + Variant::get_enums_for_type(type, &enum_names); + for (const StringName &enum_name : enum_names) { + Dictionary enum_dict; + enum_dict["name"] = String(enum_name); + + List<StringName> enumeration_names; + Variant::get_enumerations_for_enum(type, enum_name, &enumeration_names); + + Array values; + + for (const StringName &enumeration : enumeration_names) { + Dictionary values_dict; + values_dict["name"] = String(enumeration); + values_dict["value"] = Variant::get_enum_value(type, enum_name, enumeration); + values.push_back(values_dict); + } + + if (values.size()) { + enum_dict["values"] = values; + } + enums.push_back(enum_dict); + } + + if (enums.size()) { + d["enums"] = enums; + } + } + { //operators Array operators; diff --git a/core/io/image.cpp b/core/io/image.cpp index a945d3e6cd..f065dac212 100644 --- a/core/io/image.cpp +++ b/core/io/image.cpp @@ -85,6 +85,7 @@ SaveJPGFunc Image::save_jpg_func = nullptr; SaveEXRFunc Image::save_exr_func = nullptr; SavePNGBufferFunc Image::save_png_buffer_func = nullptr; +SaveEXRBufferFunc Image::save_exr_buffer_func = nullptr; SaveJPGBufferFunc Image::save_jpg_buffer_func = nullptr; SaveWebPFunc Image::save_webp_func = nullptr; @@ -2323,6 +2324,13 @@ Error Image::save_exr(const String &p_path, bool p_grayscale) const { return save_exr_func(p_path, Ref<Image>((Image *)this), p_grayscale); } +Vector<uint8_t> Image::save_exr_to_buffer(bool p_grayscale) const { + if (save_exr_buffer_func == nullptr) { + return Vector<uint8_t>(); + } + return save_exr_buffer_func(Ref<Image>((Image *)this), p_grayscale); +} + Error Image::save_webp(const String &p_path, const bool p_lossy, const float p_quality) const { if (save_webp_func == nullptr) { return ERR_UNAVAILABLE; @@ -3180,6 +3188,7 @@ void Image::_bind_methods() { ClassDB::bind_method(D_METHOD("save_jpg", "path", "quality"), &Image::save_jpg, DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("save_jpg_to_buffer", "quality"), &Image::save_jpg_to_buffer, DEFVAL(0.75)); ClassDB::bind_method(D_METHOD("save_exr", "path", "grayscale"), &Image::save_exr, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("save_exr_to_buffer", "grayscale"), &Image::save_exr_to_buffer, DEFVAL(false)); ClassDB::bind_method(D_METHOD("save_webp", "path", "lossy", "quality"), &Image::save_webp, DEFVAL(false), DEFVAL(0.75f)); ClassDB::bind_method(D_METHOD("save_webp_to_buffer", "lossy", "quality"), &Image::save_webp_to_buffer, DEFVAL(false), DEFVAL(0.75f)); diff --git a/core/io/image.h b/core/io/image.h index 229103f792..2cad26f3e9 100644 --- a/core/io/image.h +++ b/core/io/image.h @@ -52,6 +52,7 @@ typedef Error (*SaveWebPFunc)(const String &p_path, const Ref<Image> &p_img, con typedef Vector<uint8_t> (*SaveWebPBufferFunc)(const Ref<Image> &p_img, const bool p_lossy, const float p_quality); typedef Error (*SaveEXRFunc)(const String &p_path, const Ref<Image> &p_img, bool p_grayscale); +typedef Vector<uint8_t> (*SaveEXRBufferFunc)(const Ref<Image> &p_img, bool p_grayscale); class Image : public Resource { GDCLASS(Image, Resource); @@ -61,6 +62,7 @@ public: static SaveJPGFunc save_jpg_func; static SaveEXRFunc save_exr_func; static SavePNGBufferFunc save_png_buffer_func; + static SaveEXRBufferFunc save_exr_buffer_func; static SaveJPGBufferFunc save_jpg_buffer_func; static SaveWebPFunc save_webp_func; static SaveWebPBufferFunc save_webp_buffer_func; @@ -292,6 +294,7 @@ public: Error save_jpg(const String &p_path, float p_quality = 0.75) const; Vector<uint8_t> save_png_to_buffer() const; Vector<uint8_t> save_jpg_to_buffer(float p_quality = 0.75) const; + Vector<uint8_t> save_exr_to_buffer(bool p_grayscale) const; Error save_exr(const String &p_path, bool p_grayscale) const; Error save_webp(const String &p_path, const bool p_lossy = false, const float p_quality = 0.75f) const; Vector<uint8_t> save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) const; diff --git a/core/io/resource.cpp b/core/io/resource.cpp index ed7228d0b9..fec5ca5c7b 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -52,41 +52,36 @@ void Resource::set_path(const String &p_path, bool p_take_over) { return; } + if (p_path.is_empty()) { + p_take_over = false; // Can't take over an empty path + } + + ResourceCache::lock.lock(); + if (!path_cache.is_empty()) { - ResourceCache::lock.write_lock(); ResourceCache::resources.erase(path_cache); - ResourceCache::lock.write_unlock(); } path_cache = ""; - ResourceCache::lock.read_lock(); - bool has_path = ResourceCache::resources.has(p_path); - ResourceCache::lock.read_unlock(); + Ref<Resource> existing = ResourceCache::get_ref(p_path); - if (has_path) { + if (existing.is_valid()) { if (p_take_over) { - ResourceCache::lock.write_lock(); - Resource **res = ResourceCache::resources.getptr(p_path); - if (res) { - (*res)->set_name(""); - } - ResourceCache::lock.write_unlock(); + existing->path_cache = String(); + ResourceCache::resources.erase(p_path); } else { - ResourceCache::lock.read_lock(); - bool exists = ResourceCache::resources.has(p_path); - ResourceCache::lock.read_unlock(); - - ERR_FAIL_COND_MSG(exists, "Another resource is loaded from path '" + p_path + "' (possible cyclic resource inclusion)."); + ResourceCache::lock.unlock(); + ERR_FAIL_MSG("Another resource is loaded from path '" + p_path + "' (possible cyclic resource inclusion)."); } } + path_cache = p_path; if (!path_cache.is_empty()) { - ResourceCache::lock.write_lock(); ResourceCache::resources[path_cache] = this; - ResourceCache::lock.write_unlock(); } + ResourceCache::lock.unlock(); _resource_path_changed(); } @@ -380,7 +375,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) { return; } - ResourceCache::lock.write_lock(); + ResourceCache::lock.lock(); if (p_remapped) { ResourceLoader::remapped_list.add(&remapped_list); @@ -388,7 +383,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) { ResourceLoader::remapped_list.remove(&remapped_list); } - ResourceCache::lock.write_unlock(); + ResourceCache::lock.unlock(); } bool Resource::is_translation_remapped() const { @@ -455,9 +450,9 @@ Resource::Resource() : Resource::~Resource() { if (!path_cache.is_empty()) { - ResourceCache::lock.write_lock(); + ResourceCache::lock.lock(); ResourceCache::resources.erase(path_cache); - ResourceCache::lock.write_unlock(); + ResourceCache::lock.unlock(); } if (owners.size()) { WARN_PRINT("Resource is still owned."); @@ -469,7 +464,7 @@ HashMap<String, Resource *> ResourceCache::resources; HashMap<String, HashMap<String, String>> ResourceCache::resource_path_cache; #endif -RWLock ResourceCache::lock; +Mutex ResourceCache::lock; #ifdef TOOLS_ENABLED RWLock ResourceCache::path_cache_lock; #endif @@ -491,46 +486,67 @@ void ResourceCache::reload_externals() { } bool ResourceCache::has(const String &p_path) { - lock.read_lock(); - bool b = resources.has(p_path); - lock.read_unlock(); + lock.lock(); + + Resource **res = resources.getptr(p_path); - return b; + if (res && (*res)->reference_get_count() == 0) { + // This resource is in the process of being deleted, ignore its existence. + (*res)->path_cache = String(); + resources.erase(p_path); + res = nullptr; + } + + lock.unlock(); + + if (!res) { + return false; + } + + return true; } -Resource *ResourceCache::get(const String &p_path) { - lock.read_lock(); +Ref<Resource> ResourceCache::get_ref(const String &p_path) { + Ref<Resource> ref; + lock.lock(); Resource **res = resources.getptr(p_path); - lock.read_unlock(); + if (res) { + ref = Ref<Resource>(*res); + } - if (!res) { - return nullptr; + if (res && !ref.is_valid()) { + // This resource is in the process of being deleted, ignore its existence + (*res)->path_cache = String(); + resources.erase(p_path); + res = nullptr; } - return *res; + lock.unlock(); + + return ref; } void ResourceCache::get_cached_resources(List<Ref<Resource>> *p_resources) { - lock.read_lock(); + lock.lock(); for (KeyValue<String, Resource *> &E : resources) { p_resources->push_back(Ref<Resource>(E.value)); } - lock.read_unlock(); + lock.unlock(); } int ResourceCache::get_cached_resource_count() { - lock.read_lock(); + lock.lock(); int rc = resources.size(); - lock.read_unlock(); + lock.unlock(); return rc; } void ResourceCache::dump(const char *p_file, bool p_short) { #ifdef DEBUG_ENABLED - lock.read_lock(); + lock.lock(); HashMap<String, int> type_count; @@ -562,7 +578,7 @@ void ResourceCache::dump(const char *p_file, bool p_short) { } } - lock.read_unlock(); + lock.unlock(); #else WARN_PRINT("ResourceCache::dump only with in debug builds."); #endif diff --git a/core/io/resource.h b/core/io/resource.h index a45bc6e1e4..a2cde87990 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -153,7 +153,7 @@ public: class ResourceCache { friend class Resource; friend class ResourceLoader; //need the lock - static RWLock lock; + static Mutex lock; static HashMap<String, Resource *> resources; #ifdef TOOLS_ENABLED static HashMap<String, HashMap<String, String>> resource_path_cache; // Each tscn has a set of resource paths and IDs. @@ -166,7 +166,7 @@ class ResourceCache { public: static void reload_externals(); static bool has(const String &p_path); - static Resource *get(const String &p_path); + static Ref<Resource> get_ref(const String &p_path); static void dump(const char *p_file = nullptr, bool p_short = false); static void get_cached_resources(List<Ref<Resource>> *p_resources); static int get_cached_resource_count(); diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 2469e1a4be..b1c50e829c 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -693,7 +693,7 @@ Error ResourceLoaderBinary::load() { } if (cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE && ResourceCache::has(path)) { - Ref<Resource> cached = ResourceCache::get(path); + Ref<Resource> cached = ResourceCache::get_ref(path); if (cached.is_valid()) { //already loaded, don't do anything error = OK; @@ -717,10 +717,10 @@ Error ResourceLoaderBinary::load() { if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) { //use the existing one - Resource *r = ResourceCache::get(path); - if (r->get_class() == t) { - r->reset_state(); - res = Ref<Resource>(r); + Ref<Resource> cached = ResourceCache::get_ref(path); + if (cached->get_class() == t) { + cached->reset_state(); + res = cached; } } diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index fb21db1a19..2cd455475c 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -335,23 +335,15 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String & thread_load_mutex->unlock(); ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Attempted to load a resource already being loaded from this thread, cyclic reference?"); } - //lock first if possible - ResourceCache::lock.read_lock(); - - //get ptr - Resource **rptr = ResourceCache::resources.getptr(local_path); - - if (rptr) { - Ref<Resource> res(*rptr); - //it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached - if (res.is_valid()) { - //referencing is fine - load_task.resource = res; - load_task.status = THREAD_LOAD_LOADED; - load_task.progress = 1.0; - } + + Ref<Resource> existing = ResourceCache::get_ref(local_path); + + if (existing.is_valid()) { + //referencing is fine + load_task.resource = existing; + load_task.status = THREAD_LOAD_LOADED; + load_task.progress = 1.0; } - ResourceCache::lock.read_unlock(); } if (!p_source_resource.is_empty()) { @@ -530,27 +522,18 @@ Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hi } //Is it cached? - ResourceCache::lock.read_lock(); - - Resource **rptr = ResourceCache::resources.getptr(local_path); - if (rptr) { - Ref<Resource> res(*rptr); + Ref<Resource> existing = ResourceCache::get_ref(local_path); - //it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached - if (res.is_valid()) { - ResourceCache::lock.read_unlock(); - thread_load_mutex->unlock(); - - if (r_error) { - *r_error = OK; - } + if (existing.is_valid()) { + thread_load_mutex->unlock(); - return res; //use cached + if (r_error) { + *r_error = OK; } - } - ResourceCache::lock.read_unlock(); + return existing; //use cached + } //load using task (but this thread) ThreadLoadTask load_task; @@ -867,7 +850,7 @@ String ResourceLoader::path_remap(const String &p_path) { } void ResourceLoader::reload_translation_remaps() { - ResourceCache::lock.read_lock(); + ResourceCache::lock.lock(); List<Resource *> to_reload; SelfList<Resource> *E = remapped_list.first(); @@ -877,7 +860,7 @@ void ResourceLoader::reload_translation_remaps() { E = E->next(); } - ResourceCache::lock.read_unlock(); + ResourceCache::lock.unlock(); //now just make sure to not delete any of these resources while changing locale.. while (to_reload.front()) { diff --git a/core/object/method_bind.h b/core/object/method_bind.h index 2870195911..d60550c899 100644 --- a/core/object/method_bind.h +++ b/core/object/method_bind.h @@ -33,20 +33,6 @@ #include "core/variant/binder_common.h" -enum MethodFlags { - METHOD_FLAG_NORMAL = 1, - METHOD_FLAG_EDITOR = 2, - METHOD_FLAG_NOSCRIPT = 4, - METHOD_FLAG_CONST = 8, - METHOD_FLAG_REVERSE = 16, // used for events - METHOD_FLAG_VIRTUAL = 32, - METHOD_FLAG_FROM_SCRIPT = 64, - METHOD_FLAG_VARARG = 128, - METHOD_FLAG_STATIC = 256, - METHOD_FLAG_OBJECT_CORE = 512, - METHOD_FLAGS_DEFAULT = METHOD_FLAG_NORMAL, -}; - VARIANT_ENUM_CAST(MethodFlags) // some helpers diff --git a/core/object/object.cpp b/core/object/object.cpp index 96469db8c6..6585c3fa79 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -161,196 +161,6 @@ MethodInfo MethodInfo::from_dict(const Dictionary &p_dict) { return mi; } -MethodInfo::MethodInfo() : - flags(METHOD_FLAG_NORMAL) {} - -MethodInfo::MethodInfo(const String &p_name) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { -} - -MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); -} - -MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); -} - -MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); -} - -MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); -} - -MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); - arguments.push_back(p_param5); -} - -MethodInfo::MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5, const PropertyInfo &p_param6) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); - arguments.push_back(p_param5); - arguments.push_back(p_param6); -} - -MethodInfo::MethodInfo(Variant::Type ret) : - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; - arguments.push_back(p_param1); -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; - arguments.push_back(p_param1); - arguments.push_back(p_param2); -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); - arguments.push_back(p_param5); -} - -MethodInfo::MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5, const PropertyInfo &p_param6) : - name(p_name), - flags(METHOD_FLAG_NORMAL) { - return_val.type = ret; - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); - arguments.push_back(p_param5); - arguments.push_back(p_param6); -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); - arguments.push_back(p_param5); -} - -MethodInfo::MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5, const PropertyInfo &p_param6) : - name(p_name), - return_val(p_ret), - flags(METHOD_FLAG_NORMAL) { - arguments.push_back(p_param1); - arguments.push_back(p_param2); - arguments.push_back(p_param3); - arguments.push_back(p_param4); - arguments.push_back(p_param5); - arguments.push_back(p_param6); -} - Object::Connection::operator Variant() const { Dictionary d; d["signal"] = signal; diff --git a/core/object/object.h b/core/object/object.h index 7631cc6c4c..7dac96bc2b 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -47,7 +47,7 @@ enum PropertyHint { PROPERTY_HINT_NONE, ///< no hint provided. - PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,noslider][,radians][,degrees][,exp][,suffix:<keyword>] range. + PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,no_slider][,radians][,degrees][,exp][,suffix:<keyword>] range. PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc" PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout") @@ -205,10 +205,24 @@ struct PropertyInfo { Array convert_property_list(const List<PropertyInfo> *p_list); +enum MethodFlags { + METHOD_FLAG_NORMAL = 1, + METHOD_FLAG_EDITOR = 2, + METHOD_FLAG_NOSCRIPT = 4, + METHOD_FLAG_CONST = 8, + METHOD_FLAG_REVERSE = 16, // used for events + METHOD_FLAG_VIRTUAL = 32, + METHOD_FLAG_FROM_SCRIPT = 64, + METHOD_FLAG_VARARG = 128, + METHOD_FLAG_STATIC = 256, + METHOD_FLAG_OBJECT_CORE = 512, + METHOD_FLAGS_DEFAULT = METHOD_FLAG_NORMAL, +}; + struct MethodInfo { String name; PropertyInfo return_val; - uint32_t flags; // NOLINT - prevent clang-tidy to assign method_bind.h constant here, it should stay in .cpp. + uint32_t flags = METHOD_FLAGS_DEFAULT; int id = 0; List<PropertyInfo> arguments; Vector<Variant> default_arguments; @@ -220,29 +234,50 @@ struct MethodInfo { static MethodInfo from_dict(const Dictionary &p_dict); - MethodInfo(); - MethodInfo(const String &p_name); - MethodInfo(const String &p_name, const PropertyInfo &p_param1); - MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2); - MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3); - MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4); - MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5); - MethodInfo(const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5, const PropertyInfo &p_param6); - MethodInfo(Variant::Type ret); - MethodInfo(Variant::Type ret, const String &p_name); - MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1); - MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2); - MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3); - MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4); - MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5); - MethodInfo(Variant::Type ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5, const PropertyInfo &p_param6); - MethodInfo(const PropertyInfo &p_ret, const String &p_name); - MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1); - MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2); - MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3); - MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4); - MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5); - MethodInfo(const PropertyInfo &p_ret, const String &p_name, const PropertyInfo &p_param1, const PropertyInfo &p_param2, const PropertyInfo &p_param3, const PropertyInfo &p_param4, const PropertyInfo &p_param5, const PropertyInfo &p_param6); + MethodInfo() {} + + void _push_params(const PropertyInfo &p_param) { + arguments.push_back(p_param); + } + + template <typename... VarArgs> + void _push_params(const PropertyInfo &p_param, VarArgs... p_params) { + arguments.push_back(p_param); + _push_params(p_params...); + } + + MethodInfo(const String &p_name) { name = p_name; } + + template <typename... VarArgs> + MethodInfo(const String &p_name, VarArgs... p_params) { + name = p_name; + _push_params(p_params...); + } + + MethodInfo(Variant::Type ret) { return_val.type = ret; } + MethodInfo(Variant::Type ret, const String &p_name) { + return_val.type = ret; + name = p_name; + } + + template <typename... VarArgs> + MethodInfo(Variant::Type ret, const String &p_name, VarArgs... p_params) { + name = p_name; + return_val.type = ret; + _push_params(p_params...); + } + + MethodInfo(const PropertyInfo &p_ret, const String &p_name) { + return_val = p_ret; + name = p_name; + } + + template <typename... VarArgs> + MethodInfo(const PropertyInfo &p_ret, const String &p_name, VarArgs... p_params) { + return_val = p_ret; + name = p_name; + _push_params(p_params...); + } }; // API used to extend in GDNative and other C compatible compiled languages. diff --git a/core/templates/hash_map.h b/core/templates/hash_map.h index e5f73171a2..191f21a3dd 100644 --- a/core/templates/hash_map.h +++ b/core/templates/hash_map.h @@ -91,9 +91,9 @@ private: return hash; } - _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const { - uint32_t original_pos = p_hash % p_capacity; - return (p_pos - original_pos + p_capacity) % p_capacity; + static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) { + const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity); + return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity); } bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const { @@ -101,9 +101,10 @@ private: return false; // Failed lookups, no elements } - uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; uint32_t hash = _hash(p_key); - uint32_t pos = hash % capacity; + uint32_t pos = fastmod(hash, capacity_inv, capacity); uint32_t distance = 0; while (true) { @@ -111,7 +112,7 @@ private: return false; } - if (distance > _get_probe_length(pos, hashes[pos], capacity)) { + if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) { return false; } @@ -120,17 +121,18 @@ private: return true; } - pos = (pos + 1) % capacity; + pos = fastmod((pos + 1), capacity_inv, capacity); distance++; } } void _insert_with_hash(uint32_t p_hash, HashMapElement<TKey, TValue> *p_value) { - uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; uint32_t hash = p_hash; HashMapElement<TKey, TValue> *value = p_value; uint32_t distance = 0; - uint32_t pos = hash % capacity; + uint32_t pos = fastmod(hash, capacity_inv, capacity); while (true) { if (hashes[pos] == EMPTY_HASH) { @@ -143,14 +145,14 @@ private: } // Not an empty slot, let's check the probing length of the existing one. - uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity); + uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity, capacity_inv); if (existing_probe_len < distance) { SWAP(hash, hashes[pos]); SWAP(value, elements[pos]); distance = existing_probe_len; } - pos = (pos + 1) % capacity; + pos = fastmod((pos + 1), capacity_inv, capacity); distance++; } } @@ -316,13 +318,14 @@ public: return false; } - uint32_t capacity = hash_table_size_primes[capacity_index]; - uint32_t next_pos = (pos + 1) % capacity; - while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) { + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; + uint32_t next_pos = fastmod((pos + 1), capacity_inv, capacity); + while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) { SWAP(hashes[next_pos], hashes[pos]); SWAP(elements[next_pos], elements[pos]); pos = next_pos; - next_pos = (pos + 1) % capacity; + next_pos = fastmod((pos + 1), capacity_inv, capacity); } hashes[pos] = EMPTY_HASH; diff --git a/core/templates/hash_set.h b/core/templates/hash_set.h index 2318067dcc..7b3a5d46f8 100644 --- a/core/templates/hash_set.h +++ b/core/templates/hash_set.h @@ -74,9 +74,9 @@ private: return hash; } - _FORCE_INLINE_ uint32_t _get_probe_length(uint32_t p_pos, uint32_t p_hash, uint32_t p_capacity) const { - uint32_t original_pos = p_hash % p_capacity; - return (p_pos - original_pos + p_capacity) % p_capacity; + static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) { + const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity); + return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity); } bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const { @@ -84,9 +84,10 @@ private: return false; // Failed lookups, no elements } - uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; uint32_t hash = _hash(p_key); - uint32_t pos = hash % capacity; + uint32_t pos = fastmod(hash, capacity_inv, capacity); uint32_t distance = 0; while (true) { @@ -94,7 +95,7 @@ private: return false; } - if (distance > _get_probe_length(pos, hashes[pos], capacity)) { + if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) { return false; } @@ -103,17 +104,18 @@ private: return true; } - pos = (pos + 1) % capacity; + pos = fastmod(pos + 1, capacity_inv, capacity); distance++; } } uint32_t _insert_with_hash(uint32_t p_hash, uint32_t p_index) { - uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; uint32_t hash = p_hash; uint32_t index = p_index; uint32_t distance = 0; - uint32_t pos = hash % capacity; + uint32_t pos = fastmod(hash, capacity_inv, capacity); while (true) { if (hashes[pos] == EMPTY_HASH) { @@ -124,7 +126,7 @@ private: } // Not an empty slot, let's check the probing length of the existing one. - uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity); + uint32_t existing_probe_len = _get_probe_length(pos, hashes[pos], capacity, capacity_inv); if (existing_probe_len < distance) { key_to_hash[index] = pos; SWAP(hash, hashes[pos]); @@ -132,7 +134,7 @@ private: distance = existing_probe_len; } - pos = (pos + 1) % capacity; + pos = fastmod(pos + 1, capacity_inv, capacity); distance++; } } @@ -265,9 +267,10 @@ public: uint32_t key_pos = pos; pos = key_to_hash[pos]; //make hash pos - uint32_t capacity = hash_table_size_primes[capacity_index]; - uint32_t next_pos = (pos + 1) % capacity; - while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity) != 0) { + const uint32_t capacity = hash_table_size_primes[capacity_index]; + const uint64_t capacity_inv = hash_table_size_primes_inv[capacity_index]; + uint32_t next_pos = fastmod(pos + 1, capacity_inv, capacity); + while (hashes[next_pos] != EMPTY_HASH && _get_probe_length(next_pos, hashes[next_pos], capacity, capacity_inv) != 0) { uint32_t kpos = hash_to_key[pos]; uint32_t kpos_next = hash_to_key[next_pos]; SWAP(key_to_hash[kpos], key_to_hash[kpos_next]); @@ -275,7 +278,7 @@ public: SWAP(hash_to_key[next_pos], hash_to_key[pos]); pos = next_pos; - next_pos = (pos + 1) % capacity; + next_pos = fastmod(pos + 1, capacity_inv, capacity); } hashes[pos] = EMPTY_HASH; diff --git a/core/templates/hashfuncs.h b/core/templates/hashfuncs.h index b0371f2ab5..547534f26a 100644 --- a/core/templates/hashfuncs.h +++ b/core/templates/hashfuncs.h @@ -437,4 +437,66 @@ const uint32_t hash_table_size_primes[HASH_TABLE_SIZE_MAX] = { 1610612741, }; +// Computed with elem_i = UINT64_C (0 x FFFFFFFF FFFFFFFF ) / d_i + 1, where d_i is the i-th element of the above array. +const uint64_t hash_table_size_primes_inv[HASH_TABLE_SIZE_MAX] = { + 3689348814741910324, + 1418980313362273202, + 802032351030850071, + 392483916461905354, + 190172619316593316, + 95578984837873325, + 47420935922132524, + 23987963684927896, + 11955116055547344, + 5991147799191151, + 2998982941588287, + 1501077717772769, + 750081082979285, + 375261795343686, + 187625172388393, + 93822606204624, + 46909513691883, + 23456218233098, + 11728086747027, + 5864041509391, + 2932024948977, + 1466014921160, + 733007198436, + 366503839517, + 183251896093, + 91625960335, + 45812983922, + 22906489714, + 11453246088 +}; + +/** + * Fastmod computes ( n mod d ) given the precomputed c much faster than n % d. + * The implementation of fastmod is based on the following paper by Daniel Lemire et al. + * Faster Remainder by Direct Computation: Applications to Compilers and Software Libraries + * https://arxiv.org/abs/1902.01961 + */ +static _FORCE_INLINE_ uint32_t fastmod(const uint32_t n, const uint64_t c, const uint32_t d) { +#if defined(_MSC_VER) + // Returns the upper 64 bits of the product of two 64-bit unsigned integers. + // This intrinsic function is required since MSVC does not support unsigned 128-bit integers. +#if defined(_M_X64) || defined(_M_ARM64) + return __umulh(c * n, d); +#else + // Fallback to the slower method for 32-bit platforms. + return n % d; +#endif // _M_X64 || _M_ARM64 +#else +#ifdef __SIZEOF_INT128__ + // Prevent compiler warning, because we know what we are doing. + uint64_t lowbits = c * n; + __extension__ typedef unsigned __int128 uint128; + return static_cast<uint64_t>(((uint128)lowbits * d) >> 64); +#else + // Fallback to the slower method if no 128-bit unsigned integer type is available. + return n % d; +#endif // __SIZEOF_INT128__ +#endif // _MSC_VER +} + #endif // HASHFUNCS_H diff --git a/core/variant/variant.h b/core/variant/variant.h index 726ba120b5..992d9cad40 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -716,6 +716,10 @@ public: static bool has_constant(Variant::Type p_type, const StringName &p_value); static Variant get_constant_value(Variant::Type p_type, const StringName &p_value, bool *r_valid = nullptr); + static void get_enums_for_type(Variant::Type p_type, List<StringName> *p_enums); + static void get_enumerations_for_enum(Variant::Type p_type, StringName p_enum_name, List<StringName> *p_enumerations); + static int get_enum_value(Variant::Type p_type, StringName p_enum_name, StringName p_enumeration, bool *r_valid = nullptr); + typedef String (*ObjectDeConstruct)(const Variant &p_object, void *ud); typedef void (*ObjectConstruct)(const String &p_text, void *ud, Variant &r_value); diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index cb9dfe478b..8e420ecf04 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -944,9 +944,20 @@ struct _VariantCall { constant_data[p_type].variant_value_ordered.push_back(p_constant_name); #endif } + + struct EnumData { + HashMap<StringName, HashMap<StringName, int>> value; + }; + + static EnumData *enum_data; + + static void add_enum_constant(int p_type, StringName p_enum_type_name, StringName p_enumeration_name, int p_enum_value) { + enum_data[p_type].value[p_enum_type_name][p_enumeration_name] = p_enum_value; + } }; _VariantCall::ConstantData *_VariantCall::constant_data = nullptr; +_VariantCall::EnumData *_VariantCall::enum_data = nullptr; struct VariantBuiltInMethodInfo { void (*call)(Variant *base, const Variant **p_args, int p_argcount, Variant &r_ret, const Vector<Variant> &p_defvals, Callable::CallError &r_error) = nullptr; @@ -1300,6 +1311,54 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va return E->value; } +void Variant::get_enums_for_type(Variant::Type p_type, List<StringName> *p_enums) { + ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX); + + _VariantCall::EnumData &enum_data = _VariantCall::enum_data[p_type]; + + for (const KeyValue<StringName, HashMap<StringName, int>> &E : enum_data.value) { + p_enums->push_back(E.key); + } +} + +void Variant::get_enumerations_for_enum(Variant::Type p_type, StringName p_enum_name, List<StringName> *p_enumerations) { + ERR_FAIL_INDEX(p_type, Variant::VARIANT_MAX); + + _VariantCall::EnumData &enum_data = _VariantCall::enum_data[p_type]; + + for (const KeyValue<StringName, HashMap<StringName, int>> &E : enum_data.value) { + for (const KeyValue<StringName, int> &V : E.value) { + p_enumerations->push_back(V.key); + } + } +} + +int Variant::get_enum_value(Variant::Type p_type, StringName p_enum_name, StringName p_enumeration, bool *r_valid) { + if (r_valid) { + *r_valid = false; + } + + ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, -1); + + _VariantCall::EnumData &enum_data = _VariantCall::enum_data[p_type]; + + HashMap<StringName, HashMap<StringName, int>>::Iterator E = enum_data.value.find(p_enum_name); + if (!E) { + return -1; + } + + HashMap<StringName, int>::Iterator V = E->value.find(p_enumeration); + if (!V) { + return -1; + } + + if (r_valid) { + *r_valid = true; + } + + return V->value; +} + #ifdef DEBUG_METHODS_ENABLED #define bind_method(m_type, m_method, m_arg_names, m_default_args) \ METHOD_CLASS(m_type, m_method, &m_type::m_method); \ @@ -1360,6 +1419,7 @@ Variant Variant::get_constant_value(Variant::Type p_type, const StringName &p_va static void _register_variant_builtin_methods() { _VariantCall::constant_data = memnew_arr(_VariantCall::ConstantData, Variant::VARIANT_MAX); + _VariantCall::enum_data = memnew_arr(_VariantCall::EnumData, Variant::VARIANT_MAX); builtin_method_info = memnew_arr(BuiltinMethodMap, Variant::VARIANT_MAX); builtin_method_names = memnew_arr(List<StringName>, Variant::VARIANT_MAX); @@ -2124,6 +2184,10 @@ static void _register_variant_builtin_methods() { _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Y", Vector3::AXIS_Y); _VariantCall::add_constant(Variant::VECTOR3, "AXIS_Z", Vector3::AXIS_Z); + _VariantCall::add_enum_constant(Variant::VECTOR3, "Axis", "AXIS_X", Vector3::AXIS_X); + _VariantCall::add_enum_constant(Variant::VECTOR3, "Axis", "AXIS_Y", Vector3::AXIS_Y); + _VariantCall::add_enum_constant(Variant::VECTOR3, "Axis", "AXIS_Z", Vector3::AXIS_Z); + _VariantCall::add_variant_constant(Variant::VECTOR3, "ZERO", Vector3(0, 0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR3, "ONE", Vector3(1, 1, 1)); _VariantCall::add_variant_constant(Variant::VECTOR3, "INF", Vector3(INFINITY, INFINITY, INFINITY)); @@ -2138,6 +2202,10 @@ static void _register_variant_builtin_methods() { _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Y", Vector3i::AXIS_Y); _VariantCall::add_constant(Variant::VECTOR3I, "AXIS_Z", Vector3i::AXIS_Z); + _VariantCall::add_enum_constant(Variant::VECTOR3I, "Axis", "AXIS_X", Vector3i::AXIS_X); + _VariantCall::add_enum_constant(Variant::VECTOR3I, "Axis", "AXIS_Y", Vector3i::AXIS_Y); + _VariantCall::add_enum_constant(Variant::VECTOR3I, "Axis", "AXIS_Z", Vector3i::AXIS_Z); + _VariantCall::add_variant_constant(Variant::VECTOR3I, "ZERO", Vector3i(0, 0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR3I, "ONE", Vector3i(1, 1, 1)); _VariantCall::add_variant_constant(Variant::VECTOR3I, "LEFT", Vector3i(-1, 0, 0)); @@ -2150,9 +2218,15 @@ static void _register_variant_builtin_methods() { _VariantCall::add_constant(Variant::VECTOR2, "AXIS_X", Vector2::AXIS_X); _VariantCall::add_constant(Variant::VECTOR2, "AXIS_Y", Vector2::AXIS_Y); + _VariantCall::add_enum_constant(Variant::VECTOR2, "Axis", "AXIS_X", Vector2::AXIS_X); + _VariantCall::add_enum_constant(Variant::VECTOR2, "Axis", "AXIS_Y", Vector2::AXIS_Y); + _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_X", Vector2i::AXIS_X); _VariantCall::add_constant(Variant::VECTOR2I, "AXIS_Y", Vector2i::AXIS_Y); + _VariantCall::add_enum_constant(Variant::VECTOR2I, "Axis", "AXIS_X", Vector2i::AXIS_X); + _VariantCall::add_enum_constant(Variant::VECTOR2I, "Axis", "AXIS_Y", Vector2i::AXIS_Y); + _VariantCall::add_variant_constant(Variant::VECTOR2, "ZERO", Vector2(0, 0)); _VariantCall::add_variant_constant(Variant::VECTOR2, "ONE", Vector2(1, 1)); _VariantCall::add_variant_constant(Variant::VECTOR2, "INF", Vector2(INFINITY, INFINITY)); @@ -2175,6 +2249,13 @@ static void _register_variant_builtin_methods() { _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZXY", Basis::EULER_ORDER_ZXY); _VariantCall::add_constant(Variant::BASIS, "EULER_ORDER_ZYX", Basis::EULER_ORDER_ZYX); + _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_XYZ", Basis::EULER_ORDER_XYZ); + _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_XZY", Basis::EULER_ORDER_XZY); + _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_YXZ", Basis::EULER_ORDER_YXZ); + _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_YZX", Basis::EULER_ORDER_YZX); + _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_ZXY", Basis::EULER_ORDER_ZXY); + _VariantCall::add_enum_constant(Variant::BASIS, "EulerOrder", "EULER_ORDER_ZYX", Basis::EULER_ORDER_ZYX); + _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "IDENTITY", Transform2D()); _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_X", Transform2D(-1, 0, 0, 1, 0, 0)); _VariantCall::add_variant_constant(Variant::TRANSFORM2D, "FLIP_Y", Transform2D(1, 0, 0, -1, 0, 0)); @@ -2213,4 +2294,5 @@ void Variant::_unregister_variant_methods() { memdelete_arr(builtin_method_names); memdelete_arr(builtin_method_info); memdelete_arr(_VariantCall::constant_data); + memdelete_arr(_VariantCall::enum_data); } diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml index 14483abbcb..863ea899ee 100644 --- a/doc/classes/@GlobalScope.xml +++ b/doc/classes/@GlobalScope.xml @@ -2460,7 +2460,7 @@ </constant> <constant name="PROPERTY_HINT_RANGE" value="1" enum="PropertyHint"> Hints that an integer or float property should be within a range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"or_greater"[/code] and/or [code]"or_lesser"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"-360,360,1,or_greater,or_lesser"[/code]. - Additionally, other keywords can be included: "exp" for exponential range editing, "radians" for editing radian angles in degrees, "degrees" to hint at an angle and "noslider" to hide the slider. + Additionally, other keywords can be included: "exp" for exponential range editing, "radians" for editing radian angles in degrees, "degrees" to hint at an angle and "no_slider" to hide the slider. </constant> <constant name="PROPERTY_HINT_ENUM" value="2" enum="PropertyHint"> Hints that an integer, float or string property is an enumerated value to pick in a list specified via a hint string. diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml index 53d35c1a3d..75a715789c 100644 --- a/doc/classes/ColorPickerButton.xml +++ b/doc/classes/ColorPickerButton.xml @@ -6,7 +6,7 @@ <description> Encapsulates a [ColorPicker] making it accessible by pressing a button. Pressing the button will toggle the [ColorPicker] visibility. See also [BaseButton] which contains common properties and methods associated with this node. - [b]Note:[/b] By default, the button may not be wide enough for the color preview swatch to be visible. Make sure to set [member Control.minimum_size] to a big enough value to give the button enough space. + [b]Note:[/b] By default, the button may not be wide enough for the color preview swatch to be visible. Make sure to set [member Control.custom_minimum_size] to a big enough value to give the button enough space. </description> <tutorials> <link title="GUI Drag And Drop Demo">https://godotengine.org/asset-library/asset/133</link> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 2828896eac..2846b564b4 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -100,7 +100,7 @@ <method name="_get_minimum_size" qualifiers="virtual const"> <return type="Vector2" /> <description> - Virtual method to be implemented by the user. Returns the minimum size for this control. Alternative to [member minimum_size] for controlling minimum size via code. The actual minimum size will be the max value of these two (in each axis separately). + Virtual method to be implemented by the user. Returns the minimum size for this control. Alternative to [member custom_minimum_size] for controlling minimum size via code. The actual minimum size will be the max value of these two (in each axis separately). If not overridden, defaults to [constant Vector2.ZERO]. [b]Note:[/b] This method will not be called when the script is attached to a [Control] node that already overrides its minimum size (e.g. [Label], [Button], [PanelContainer] etc.). It can only be used with most basic GUI nodes, like [Control], [Container], [Panel] etc. </description> @@ -157,7 +157,7 @@ Virtual method to be implemented by the user. Returns a [Control] node that should be used as a tooltip instead of the default one. The [code]for_text[/code] includes the contents of the [member hint_tooltip] property. The returned node must be of type [Control] or Control-derived. It can have child nodes of any type. It is freed when the tooltip disappears, so make sure you always provide a new instance (if you want to use a pre-existing node from your scene tree, you can duplicate it and pass the duplicated instance). When [code]null[/code] or a non-Control node is returned, the default tooltip will be used instead. The returned node will be added as child to a [PopupPanel], so you should only provide the contents of that panel. That [PopupPanel] can be themed using [method Theme.set_stylebox] for the type [code]"TooltipPanel"[/code] (see [member hint_tooltip] for an example). - [b]Note:[/b] The tooltip is shrunk to minimal size. If you want to ensure it's fully visible, you might want to set its [member minimum_size] to some non-zero value. + [b]Note:[/b] The tooltip is shrunk to minimal size. If you want to ensure it's fully visible, you might want to set its [member custom_minimum_size] to some non-zero value. [b]Note:[/b] The node (and any relevant children) should be [member CanvasItem.visible] when returned, otherwise, the viewport that instantiates it will not be able to calculate its minimum size reliably. Example of usage with a custom-constructed node: [codeblocks] @@ -357,7 +357,7 @@ <method name="get_combined_minimum_size" qualifiers="const"> <return type="Vector2" /> <description> - Returns combined minimum size from [member minimum_size] and [method get_minimum_size]. + Returns combined minimum size from [member custom_minimum_size] and [method get_minimum_size]. </description> </method> <method name="get_cursor_shape" qualifiers="const"> @@ -389,7 +389,7 @@ <method name="get_minimum_size" qualifiers="const"> <return type="Vector2" /> <description> - Returns the minimum size for this control. See [member minimum_size]. + Returns the minimum size for this control. See [member custom_minimum_size]. </description> </method> <method name="get_offset" qualifiers="const"> @@ -939,7 +939,7 @@ <method name="update_minimum_size"> <return type="void" /> <description> - Invalidates the size cache in this node and in parent nodes up to top level. Intended to be used with [method get_minimum_size] when the return value is changed. Setting [member minimum_size] directly calls this method automatically. + Invalidates the size cache in this node and in parent nodes up to top level. Intended to be used with [method get_minimum_size] when the return value is changed. Setting [member custom_minimum_size] directly calls this method automatically. </description> </method> <method name="warp_mouse"> @@ -970,6 +970,9 @@ <member name="clip_contents" type="bool" setter="set_clip_contents" getter="is_clipping_contents" default="false"> Enables whether rendering of [CanvasItem] based children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered and won't receive input. </member> + <member name="custom_minimum_size" type="Vector2" setter="set_custom_minimum_size" getter="get_custom_minimum_size" default="Vector2(0, 0)"> + The minimum size of the node's bounding rectangle. If you set it to a value greater than (0, 0), the node's bounding rectangle will always have at least this size, even if its content is smaller. If it's set to (0, 0), the node sizes automatically to fit its content, be it a texture or child nodes. + </member> <member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" enum="Control.FocusMode" default="0"> The focus access mode for the control (None, Click or All). Only one Control can be focused at the same time, and it will receive keyboard signals. </member> @@ -1027,9 +1030,6 @@ <member name="layout_direction" type="int" setter="set_layout_direction" getter="get_layout_direction" enum="Control.LayoutDirection" default="0"> Controls layout direction and text writing direction. Right-to-left layouts are necessary for certain languages (e.g. Arabic and Hebrew). </member> - <member name="minimum_size" type="Vector2" setter="set_custom_minimum_size" getter="get_custom_minimum_size" default="Vector2(0, 0)"> - The minimum size of the node's bounding rectangle. If you set it to a value greater than (0, 0), the node's bounding rectangle will always have at least this size, even if its content is smaller. If it's set to (0, 0), the node sizes automatically to fit its content, be it a texture or child nodes. - </member> <member name="mouse_default_cursor_shape" type="int" setter="set_default_cursor_shape" getter="get_default_cursor_shape" enum="Control.CursorShape" default="0"> The default cursor shape for this control. Useful for Godot plugins and applications or games that use the system's mouse cursors. [b]Note:[/b] On Linux, shapes may vary depending on the cursor theme of the system. diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml index 641d73e333..166923314f 100644 --- a/doc/classes/HTTPRequest.xml +++ b/doc/classes/HTTPRequest.xml @@ -15,7 +15,7 @@ # Create an HTTP request node and connect its completion signal. var http_request = HTTPRequest.new() add_child(http_request) - http_request.connect("request_completed", self, "_http_request_completed") + http_request.request_completed.connect(self._http_request_completed) # Perform a GET request. The URL below returns JSON as of writing. var error = http_request.request("https://httpbin.org/get") @@ -25,7 +25,7 @@ # Perform a POST request. The URL below returns JSON as of writing. # Note: Don't make simultaneous requests using a single HTTPRequest node. # The snippet below is provided for reference only. - var body = {"name": "Godette"} + var body = JSON.new().stringify({"name": "Godette"}) error = http_request.request("https://httpbin.org/post", [], true, HTTPClient.METHOD_POST, body) if error != OK: push_error("An error occurred in the HTTP request.") @@ -33,7 +33,9 @@ # Called when the HTTP request is completed. func _http_request_completed(result, response_code, headers, body): - var response = parse_json(body.get_string_from_utf8()) + var json = JSON.new() + json.parse(body.get_string_from_utf8()) + var response = json.get_data() # Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org). print(response.headers["User-Agent"]) @@ -44,7 +46,7 @@ // Create an HTTP request node and connect its completion signal. var httpRequest = new HTTPRequest(); AddChild(httpRequest); - httpRequest.Connect("request_completed", this, nameof(HttpRequestCompleted)); + httpRequest.RequestCompleted += HttpRequestCompleted; // Perform a GET request. The URL below returns JSON as of writing. Error error = httpRequest.Request("https://httpbin.org/get"); @@ -56,21 +58,24 @@ // Perform a POST request. The URL below returns JSON as of writing. // Note: Don't make simultaneous requests using a single HTTPRequest node. // The snippet below is provided for reference only. - string[] body = { "name", "Godette" }; - // GDScript to_json is non existent, so we use JSON.Print() here. - error = httpRequest.Request("https://httpbin.org/post", null, true, HTTPClient.Method.Post, JSON.Print(body)); + string body = new JSON().Stringify(new Godot.Collections.Dictionary + { + { "name", "Godette" } + }); + error = httpRequest.Request("https://httpbin.org/post", null, true, HTTPClient.Method.Post, body); if (error != Error.Ok) { GD.PushError("An error occurred in the HTTP request."); } } - // Called when the HTTP request is completed. private void HttpRequestCompleted(int result, int response_code, string[] headers, byte[] body) { - // GDScript parse_json is non existent so we have to use JSON.parse, which has a slightly different syntax. - var response = JSON.Parse(body.GetStringFromUTF8()).Result as Godot.Collections.Dictionary; + var json = new JSON(); + json.Parse(body.GetStringFromUTF8()); + var response = json.GetData() as Godot.Collections.Dictionary; + // Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org). GD.Print((response["headers"] as Godot.Collections.Dictionary)["User-Agent"]); } @@ -83,7 +88,7 @@ # Create an HTTP request node and connect its completion signal. var http_request = HTTPRequest.new() add_child(http_request) - http_request.connect("request_completed", self, "_http_request_completed") + http_request.request_completed.connect(self._http_request_completed) # Perform the HTTP request. The URL below returns a PNG image as of writing. var error = http_request.request("https://via.placeholder.com/512") @@ -115,7 +120,7 @@ // Create an HTTP request node and connect its completion signal. var httpRequest = new HTTPRequest(); AddChild(httpRequest); - httpRequest.Connect("request_completed", this, nameof(HttpRequestCompleted)); + httpRequest.RequestCompleted += HttpRequestCompleted; // Perform the HTTP request. The URL below returns a PNG image as of writing. Error error = httpRequest.Request("https://via.placeholder.com/512"); @@ -125,7 +130,6 @@ } } - // Called when the HTTP request is completed. private void HttpRequestCompleted(int result, int response_code, string[] headers, byte[] body) { diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml index d2baf78a9e..43b03ce65e 100644 --- a/doc/classes/Image.xml +++ b/doc/classes/Image.xml @@ -380,6 +380,14 @@ [b]Note:[/b] The TinyEXR module is disabled in non-editor builds, which means [method save_exr] will return [constant ERR_UNAVAILABLE] when it is called from an exported project. </description> </method> + <method name="save_exr_to_buffer" qualifiers="const"> + <return type="PackedByteArray" /> + <argument index="0" name="grayscale" type="bool" default="false" /> + <description> + Saves the image as an EXR file to a byte array. If [code]grayscale[/code] is [code]true[/code] and the image has only one channel, it will be saved explicitly as monochrome rather than one red channel. This function will return an empty byte array if Godot was compiled without the TinyEXR module. + [b]Note:[/b] The TinyEXR module is disabled in non-editor builds, which means [method save_exr] will return an empty byte array when it is called from an exported project. + </description> + </method> <method name="save_jpg" qualifiers="const"> <return type="int" enum="Error" /> <argument index="0" name="path" type="String" /> diff --git a/doc/classes/NavigationAgent2D.xml b/doc/classes/NavigationAgent2D.xml index 757b635252..058f1032cb 100644 --- a/doc/classes/NavigationAgent2D.xml +++ b/doc/classes/NavigationAgent2D.xml @@ -136,7 +136,8 @@ The maximum distance the agent is allowed away from the ideal path to the final location. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path. </member> <member name="radius" type="float" setter="set_radius" getter="get_radius" default="10.0"> - The radius of the agent. + The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_dist]). + Does not affect normal pathfinding. To change an actor's pathfinding radius bake [NavigationMesh] resources with a different [member NavigationMesh.agent_radius] property and use different navigation maps for each actor size. </member> <member name="target_desired_distance" type="float" setter="set_target_desired_distance" getter="get_target_desired_distance" default="1.0"> The distance threshold before the final target point is considered to be reached. This will allow an agent to not have to hit the point of the final target exactly, but only the area. If this value is set to low the NavigationAgent will be stuck in a repath loop cause it will constantly overshoot or undershoot the distance to the final target point on each physics frame update. diff --git a/doc/classes/NavigationAgent3D.xml b/doc/classes/NavigationAgent3D.xml index 5e1004165d..c689ddc345 100644 --- a/doc/classes/NavigationAgent3D.xml +++ b/doc/classes/NavigationAgent3D.xml @@ -142,7 +142,8 @@ The maximum distance the agent is allowed away from the ideal path to the final location. This can happen due to trying to avoid collisions. When the maximum distance is exceeded, it recalculates the ideal path. </member> <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0"> - The radius of the agent. + The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_dist]). + Does not affect normal pathfinding. To change an actor's pathfinding radius bake [NavigationMesh] resources with a different [member NavigationMesh.agent_radius] property and use different navigation maps for each actor size. </member> <member name="target_desired_distance" type="float" setter="set_target_desired_distance" getter="get_target_desired_distance" default="1.0"> The distance threshold before the final target point is considered to be reached. This will allow an agent to not have to hit the point of the final target exactly, but only the area. If this value is set to low the NavigationAgent will be stuck in a repath loop cause it will constantly overshoot or undershoot the distance to the final target point on each physics frame update. diff --git a/doc/classes/NavigationMesh.xml b/doc/classes/NavigationMesh.xml index 3c18b56658..966f964b12 100644 --- a/doc/classes/NavigationMesh.xml +++ b/doc/classes/NavigationMesh.xml @@ -107,6 +107,12 @@ The maximum allowed length for contour edges along the border of the mesh. [b]Note:[/b] While baking, this value will be rounded up to the nearest multiple of [member cell_size]. </member> + <member name="filter_baking_aabb" type="AABB" setter="set_filter_baking_aabb" getter="get_filter_baking_aabb" default="AABB(0, 0, 0, 0, 0, 0)"> + If the baking [AABB] has a volume the navigation mesh baking will be restricted to its enclosing area. + </member> + <member name="filter_baking_aabb_offset" type="Vector3" setter="set_filter_baking_aabb_offset" getter="get_filter_baking_aabb_offset" default="Vector3(0, 0, 0)"> + The position offset applied to the [member filter_baking_aabb] [AABB]. + </member> <member name="filter_ledge_spans" type="bool" setter="set_filter_ledge_spans" getter="get_filter_ledge_spans" default="false"> If [code]true[/code], marks spans that are ledges as non-walkable. </member> diff --git a/doc/classes/NavigationMeshGenerator.xml b/doc/classes/NavigationMeshGenerator.xml index b92183fda0..612ce54d34 100644 --- a/doc/classes/NavigationMeshGenerator.xml +++ b/doc/classes/NavigationMeshGenerator.xml @@ -8,6 +8,7 @@ The entire navigation mesh baking is best done in a separate thread as the voxelization, collision tests and mesh optimization steps involved are very performance and time hungry operations. Navigation mesh baking happens in multiple steps and the result depends on 3D source geometry and properties of the [NavigationMesh] resource. In the first step, starting from a root node and depending on [NavigationMesh] properties all valid 3D source geometry nodes are collected from the [SceneTree]. Second, all collected nodes are parsed for their relevant 3D geometry data and a combined 3D mesh is build. Due to the many different types of parsable objects, from normal [MeshInstance3D]s to [CSGShape3D]s or various [CollisionObject3D]s, some operations to collect geometry data can trigger [RenderingServer] and [PhysicsServer3D] synchronizations. Server synchronization can have a negative effect on baking time or framerate as it often involves [Mutex] locking for thread security. Many parsable objects and the continuous synchronization with other threaded Servers can increase the baking time significantly. On the other hand only a few but very large and complex objects will take some time to prepare for the Servers which can noticeably stall the next frame render. As a general rule the total amount of parsable objects and their individual size and complexity should be balanced to avoid framerate issues or very long baking times. The combined mesh is then passed to the Recast Navigation Object to test the source geometry for walkable terrain suitable to [NavigationMesh] agent properties by creating a voxel world around the meshes bounding area. The finalized navigation mesh is then returned and stored inside the [NavigationMesh] for use as a resource inside [NavigationRegion3D] nodes. + [b]Note:[/b] Using meshes to not only define walkable surfaces but also obstruct navigation baking does not always work. The navigation baking has no concept of what is a geometry "inside" when dealing with mesh source geometry and this is intentional. Depending on current baking parameters, as soon as the obstructing mesh is large enough to fit a navigation mesh area inside, the baking will generate navigation mesh areas that are inside the obstructing source geometry mesh. </description> <tutorials> </tutorials> diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml index 220c12ce7f..36379d2531 100644 --- a/doc/classes/NavigationServer2D.xml +++ b/doc/classes/NavigationServer2D.xml @@ -127,12 +127,28 @@ Destroys the given RID. </description> </method> + <method name="get_maps" qualifiers="const"> + <return type="Array" /> + <description> + Returns all created navigation map [RID]s on the NavigationServer. This returns both 2D and 3D created navigation maps as there is technically no distinction between them. + </description> + </method> <method name="map_create" qualifiers="const"> <return type="RID" /> <description> Create a new map. </description> </method> + <method name="map_force_update"> + <return type="void" /> + <argument index="0" name="map" type="RID" /> + <description> + This function immediately forces synchronization of the specified navigation [code]map[/code] [RID]. By default navigation maps are only synchronized at the end of each physics frame. This function can be used to immediately (re)calculate all the navigation meshes and region connections of the navigation map. This makes it possible to query a navigation path for a changed map immediately and in the same frame (multiple times if needed). + Due to technical restrictions the current NavigationServer command queue will be flushed. This means all already queued update commands for this physics frame will be executed, even those intended for other maps, regions and agents not part of the specified map. The expensive computation of the navigation meshes and region connections of a map will only be done for the specified map. Other maps will receive the normal synchronization at the end of the physics frame. Should the specified map receive changes after the forced update it will update again as well when the other maps receive their update. + Avoidance processing and dispatch of the [code]safe_velocity[/code] signals is untouched by this function and continues to happen for all maps and agents at the end of the physics frame. + [b]Note:[/b] With great power comes great responsibility. This function should only be used by users that really know what they are doing and have a good reason for it. Forcing an immediate update of a navigation map requires locking the NavigationServer and flushing the entire NavigationServer command queue. Not only can this severely impact the performance of a game but it can also introduce bugs if used inappropriately without much foresight. + </description> + </method> <method name="map_get_agents" qualifiers="const"> <return type="Array" /> <argument index="0" name="map" type="RID" /> @@ -276,6 +292,16 @@ Returns the [code]travel_cost[/code] of this [code]region[/code]. </description> </method> + <method name="region_owns_point" qualifiers="const"> + <return type="bool" /> + <argument index="0" name="region" type="RID" /> + <argument index="1" name="point" type="Vector2" /> + <description> + Returns [code]true[/code] if the provided [code]point[/code] in world space is currently owned by the provided navigation [code]region[/code]. Owned in this context means that one of the region's navigation mesh polygon faces has a possible position at the closest distance to this point compared to all other navigation meshes from other navigation regions that are also registered on the navigation map of the provided region. + If multiple navigation meshes have positions at equal distance the navigation region whose polygons are processed first wins the ownership. Polygons are processed in the same order that navigation regions were registered on the NavigationServer. + [b]Note:[/b] If navigation meshes from different navigation regions overlap (which should be avoided in general) the result might not be what is expected. + </description> + </method> <method name="region_set_enter_cost" qualifiers="const"> <return type="void" /> <argument index="0" name="region" type="RID" /> diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml index d2eef49cfd..5185b353bc 100644 --- a/doc/classes/NavigationServer3D.xml +++ b/doc/classes/NavigationServer3D.xml @@ -127,12 +127,28 @@ Destroys the given RID. </description> </method> + <method name="get_maps" qualifiers="const"> + <return type="Array" /> + <description> + Returns all created navigation map [RID]s on the NavigationServer. This returns both 2D and 3D created navigation maps as there is technically no distinction between them. + </description> + </method> <method name="map_create" qualifiers="const"> <return type="RID" /> <description> Create a new map. </description> </method> + <method name="map_force_update"> + <return type="void" /> + <argument index="0" name="map" type="RID" /> + <description> + This function immediately forces synchronization of the specified navigation [code]map[/code] [RID]. By default navigation maps are only synchronized at the end of each physics frame. This function can be used to immediately (re)calculate all the navigation meshes and region connections of the navigation map. This makes it possible to query a navigation path for a changed map immediately and in the same frame (multiple times if needed). + Due to technical restrictions the current NavigationServer command queue will be flushed. This means all already queued update commands for this physics frame will be executed, even those intended for other maps, regions and agents not part of the specified map. The expensive computation of the navigation meshes and region connections of a map will only be done for the specified map. Other maps will receive the normal synchronization at the end of the physics frame. Should the specified map receive changes after the forced update it will update again as well when the other maps receive their update. + Avoidance processing and dispatch of the [code]safe_velocity[/code] signals is untouched by this function and continues to happen for all maps and agents at the end of the physics frame. + [b]Note:[/b] With great power comes great responsibility. This function should only be used by users that really know what they are doing and have a good reason for it. Forcing an immediate update of a navigation map requires locking the NavigationServer and flushing the entire NavigationServer command queue. Not only can this severely impact the performance of a game but it can also introduce bugs if used inappropriately without much foresight. + </description> + </method> <method name="map_get_agents" qualifiers="const"> <return type="Array" /> <argument index="0" name="map" type="RID" /> @@ -326,6 +342,16 @@ Returns the [code]travel_cost[/code] of this [code]region[/code]. </description> </method> + <method name="region_owns_point" qualifiers="const"> + <return type="bool" /> + <argument index="0" name="region" type="RID" /> + <argument index="1" name="point" type="Vector3" /> + <description> + Returns [code]true[/code] if the provided [code]point[/code] in world space is currently owned by the provided navigation [code]region[/code]. Owned in this context means that one of the region's navigation mesh polygon faces has a possible position at the closest distance to this point compared to all other navigation meshes from other navigation regions that are also registered on the navigation map of the provided region. + If multiple navigation meshes have positions at equal distance the navigation region whose polygons are processed first wins the ownership. Polygons are processed in the same order that navigation regions were registered on the NavigationServer. + [b]Note:[/b] If navigation meshes from different navigation regions overlap (which should be avoided in general) the result might not be what is expected. + </description> + </method> <method name="region_set_enter_cost" qualifiers="const"> <return type="void" /> <argument index="0" name="region" type="RID" /> diff --git a/doc/classes/ScrollContainer.xml b/doc/classes/ScrollContainer.xml index 658793c4c0..1bbf5cb91b 100644 --- a/doc/classes/ScrollContainer.xml +++ b/doc/classes/ScrollContainer.xml @@ -5,7 +5,7 @@ </brief_description> <description> A ScrollContainer node meant to contain a [Control] child. - ScrollContainers will automatically create a scrollbar child ([HScrollBar], [VScrollBar], or both) when needed and will only draw the Control within the ScrollContainer area. Scrollbars will automatically be drawn at the right (for vertical) or bottom (for horizontal) and will enable dragging to move the viewable Control (and its children) within the ScrollContainer. Scrollbars will also automatically resize the grabber based on the [member Control.minimum_size] of the Control relative to the ScrollContainer. + ScrollContainers will automatically create a scrollbar child ([HScrollBar], [VScrollBar], or both) when needed and will only draw the Control within the ScrollContainer area. Scrollbars will automatically be drawn at the right (for vertical) or bottom (for horizontal) and will enable dragging to move the viewable Control (and its children) within the ScrollContainer. Scrollbars will also automatically resize the grabber based on the [member Control.custom_minimum_size] of the Control relative to the ScrollContainer. Works great with a [Panel] control. You can set [code]EXPAND[/code] on the children's size flags, so they will upscale to the ScrollContainer's size if it's larger (scroll is invisible for the chosen dimension). </description> <tutorials> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 58fdd2d058..2de185903d 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -956,6 +956,9 @@ <member name="deselect_on_focus_loss_enabled" type="bool" setter="set_deselect_on_focus_loss_enabled" getter="is_deselect_on_focus_loss_enabled" default="true"> If [code]true[/code], the selected text will be deselected when focus is lost. </member> + <member name="drag_and_drop_selection_enabled" type="bool" setter="set_drag_and_drop_selection_enabled" getter="is_drag_and_drop_selection_enabled" default="true"> + If [code]true[/code], allow drag and drop of selected text. + </member> <member name="draw_control_chars" type="bool" setter="set_draw_control_chars" getter="get_draw_control_chars" default="false"> If [code]true[/code], control characters are displayed. </member> diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 7c00cf351c..272de725c8 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1024,6 +1024,7 @@ void CodeTextEditor::update_editor_settings() { text_editor->set_scroll_past_end_of_file_enabled(EditorSettings::get_singleton()->get("text_editor/behavior/navigation/scroll_past_end_of_file")); text_editor->set_smooth_scroll_enabled(EditorSettings::get_singleton()->get("text_editor/behavior/navigation/smooth_scrolling")); text_editor->set_v_scroll_speed(EditorSettings::get_singleton()->get("text_editor/behavior/navigation/v_scroll_speed")); + text_editor->set_drag_and_drop_selection_enabled(EditorSettings::get_singleton()->get("text_editor/behavior/navigation/drag_and_drop_selection")); // Behavior: indent text_editor->set_indent_using_spaces(EditorSettings::get_singleton()->get("text_editor/behavior/indent/type")); diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index 97699d0349..9a1b2b5ff5 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -487,7 +487,7 @@ void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector< void DependencyRemoveDialog::ok_pressed() { for (int i = 0; i < files_to_delete.size(); ++i) { if (ResourceCache::has(files_to_delete[i])) { - Resource *res = ResourceCache::get(files_to_delete[i]); + Ref<Resource> res = ResourceCache::get_ref(files_to_delete[i]); res->set_path(""); } diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index f9a4c14c48..adbba98897 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1792,9 +1792,9 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector //if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it //to reload properly - if (ResourceCache::has(file)) { - Resource *r = ResourceCache::get(file); + Ref<Resource> r = ResourceCache::get_ref(file); + if (r.is_valid()) { if (!r->get_import_path().is_empty()) { String dst_path = ResourceFormatImporter::get_singleton()->get_internal_resource_path(file); r->set_import_path(dst_path); @@ -2034,9 +2034,8 @@ void EditorFileSystem::_reimport_file(const String &p_file, const HashMap<String //if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it //to reload properly - if (ResourceCache::has(p_file)) { - Resource *r = ResourceCache::get(p_file); - + Ref<Resource> r = ResourceCache::get_ref(p_file); + if (r.is_valid()) { if (!r->get_import_path().is_empty()) { String dst_path = ResourceFormatImporter::get_singleton()->get_internal_resource_path(p_file); r->set_import_path(dst_path); diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp index 9e1b361f64..8c508494c0 100644 --- a/editor/editor_folding.cpp +++ b/editor/editor_folding.cpp @@ -193,10 +193,7 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) { for (int i = 0; i < res_unfolds.size(); i += 2) { String path2 = res_unfolds[i]; - Ref<Resource> res; - if (ResourceCache::has(path2)) { - res = Ref<Resource>(ResourceCache::get(path2)); - } + Ref<Resource> res = ResourceCache::get_ref(path2); if (res.is_null()) { continue; } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 93caf7944c..9b0ac305d1 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -881,7 +881,7 @@ void EditorNode::_resources_changed(const Vector<String> &p_resources) { int rc = p_resources.size(); for (int i = 0; i < rc; i++) { - Ref<Resource> res(ResourceCache::get(p_resources.get(i))); + Ref<Resource> res = ResourceCache::get_ref(p_resources.get(i)); if (res.is_null()) { continue; } @@ -1011,8 +1011,8 @@ void EditorNode::_resources_reimported(const Vector<String> &p_resources) { continue; } // Reload normally. - Resource *resource = ResourceCache::get(p_resources[i]); - if (resource) { + Ref<Resource> resource = ResourceCache::get_ref(p_resources[i]); + if (resource.is_valid()) { resource->reload_from_file(); } } @@ -1725,7 +1725,7 @@ void EditorNode::_save_scene(String p_file, int idx) { // We must update it, but also let the previous scene state go, as // old version still work for referencing changes in instantiated or inherited scenes. - sdata = Ref<PackedScene>(Object::cast_to<PackedScene>(ResourceCache::get(p_file))); + sdata = ResourceCache::get_ref(p_file); if (sdata.is_valid()) { sdata->recreate_state(); } else { @@ -3717,7 +3717,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b if (ResourceCache::has(lpath)) { // Used from somewhere else? No problem! Update state and replace sdata. - Ref<PackedScene> ps = Ref<PackedScene>(Object::cast_to<PackedScene>(ResourceCache::get(lpath))); + Ref<PackedScene> ps = ResourceCache::get_ref(lpath); if (ps.is_valid()) { ps->replace_state(sdata->get_state()); ps->set_last_modified_time(sdata->get_last_modified_time()); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index ed7fac9990..0e6c9162ce 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -3633,7 +3633,7 @@ static EditorPropertyRangeHint _parse_range_hint(PropertyHint p_hint, const Stri hint.greater = true; } else if (slice == "or_lesser") { hint.lesser = true; - } else if (slice == "noslider") { + } else if (slice == "no_slider") { hint.hide_slider = true; } else if (slice == "exp") { hint.exp_range = true; diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp index 397afc0653..09d2992e07 100644 --- a/editor/editor_property_name_processor.cpp +++ b/editor/editor_property_name_processor.cpp @@ -176,6 +176,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["lowpass"] = "Low-pass"; capitalize_string_remaps["macos"] = "macOS"; capitalize_string_remaps["mb"] = "(MB)"; // Unit. + capitalize_string_remaps["mjpeg"] = "MJPEG"; capitalize_string_remaps["mms"] = "MMS"; capitalize_string_remaps["ms"] = "(ms)"; // Unit capitalize_string_remaps["msaa"] = "MSAA"; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index db9193db06..ad9c547693 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -542,6 +542,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/behavior/navigation/scroll_past_end_of_file", false); _initial_set("text_editor/behavior/navigation/smooth_scrolling", true); EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/behavior/navigation/v_scroll_speed", 80, "1,10000,1") + _initial_set("text_editor/behavior/navigation/drag_and_drop_selection", true); // Behavior: Indent EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/behavior/indent/type", 0, "Tabs,Spaces") diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 7a80cf36a8..10412eac41 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -464,6 +464,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Color icon_hover_color = icon_normal_color * (dark_theme ? 1.15 : 1.45); icon_hover_color.a = 1.0; Color icon_focus_color = icon_hover_color; + Color icon_disabled_color = Color(icon_normal_color, 0.4); // Make the pressed icon color overbright because icons are not completely white on a dark theme. // On a light theme, icons are dark, so we need to modulate them with an even brighter color. Color icon_pressed_color = accent_color * (dark_theme ? 1.15 : 3.5); @@ -738,10 +739,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_focus_color", "Button", font_focus_color); theme->set_color("font_pressed_color", "Button", accent_color); theme->set_color("font_disabled_color", "Button", font_disabled_color); + theme->set_color("icon_normal_color", "Button", icon_normal_color); theme->set_color("icon_hover_color", "Button", icon_hover_color); theme->set_color("icon_focus_color", "Button", icon_focus_color); theme->set_color("icon_pressed_color", "Button", icon_pressed_color); + theme->set_color("icon_disabled_color", "Button", icon_disabled_color); const float ACTION_BUTTON_EXTRA_MARGIN = 32 * EDSCALE; @@ -768,7 +771,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // When pressed, don't tint the icons with the accent color, just leave them normal. theme->set_color("icon_pressed_color", "EditorLogFilterButton", icon_normal_color); // When unpressed, dim the icons. - theme->set_color("icon_normal_color", "EditorLogFilterButton", font_disabled_color); + theme->set_color("icon_normal_color", "EditorLogFilterButton", icon_disabled_color); // When pressed, add a small bottom border to the buttons to better show their active state, // similar to active tabs. Ref<StyleBoxFlat> editor_log_button_pressed = style_widget_pressed->duplicate(); @@ -805,8 +808,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_focus_color", "OptionButton", font_focus_color); theme->set_color("font_pressed_color", "OptionButton", accent_color); theme->set_color("font_disabled_color", "OptionButton", font_disabled_color); + + theme->set_color("icon_normal_color", "OptionButton", icon_normal_color); theme->set_color("icon_hover_color", "OptionButton", icon_hover_color); theme->set_color("icon_focus_color", "OptionButton", icon_focus_color); + theme->set_color("icon_pressed_color", "OptionButton", icon_pressed_color); + theme->set_color("icon_disabled_color", "OptionButton", icon_disabled_color); + theme->set_icon("arrow", "OptionButton", theme->get_icon(SNAME("GuiOptionArrow"), SNAME("EditorIcons"))); theme->set_constant("arrow_margin", "OptionButton", widget_default_margin.x - 2 * EDSCALE); theme->set_constant("modulate_arrow", "OptionButton", true); @@ -833,8 +841,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_focus_color", "CheckButton", font_focus_color); theme->set_color("font_pressed_color", "CheckButton", accent_color); theme->set_color("font_disabled_color", "CheckButton", font_disabled_color); + + theme->set_color("icon_normal_color", "CheckButton", icon_normal_color); theme->set_color("icon_hover_color", "CheckButton", icon_hover_color); theme->set_color("icon_focus_color", "CheckButton", icon_focus_color); + theme->set_color("icon_pressed_color", "CheckButton", icon_pressed_color); + theme->set_color("icon_disabled_color", "CheckButton", icon_disabled_color); theme->set_constant("h_separation", "CheckButton", 8 * EDSCALE); theme->set_constant("check_v_adjust", "CheckButton", 0 * EDSCALE); @@ -864,8 +876,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_focus_color", "CheckBox", font_focus_color); theme->set_color("font_pressed_color", "CheckBox", accent_color); theme->set_color("font_disabled_color", "CheckBox", font_disabled_color); + + theme->set_color("icon_normal_color", "CheckBox", icon_normal_color); theme->set_color("icon_hover_color", "CheckBox", icon_hover_color); theme->set_color("icon_focus_color", "CheckBox", icon_focus_color); + theme->set_color("icon_pressed_color", "CheckBox", icon_pressed_color); + theme->set_color("icon_disabled_color", "CheckBox", icon_disabled_color); theme->set_constant("h_separation", "CheckBox", 8 * EDSCALE); theme->set_constant("check_v_adjust", "CheckBox", 0 * EDSCALE); diff --git a/editor/icons/BaseButton.svg b/editor/icons/BaseButton.svg new file mode 100644 index 0000000000..9aa0ae1c07 --- /dev/null +++ b/editor/icons/BaseButton.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5.5 9c-.831 0-1.5.669-1.5 1.5v1.5h-2v2h12v-2h-2v-1.5c0-.831-.669-1.5-1.5-1.5z" fill="#8eef97"/></svg> diff --git a/editor/icons/GeometryInstance3D.svg b/editor/icons/GeometryInstance3D.svg new file mode 100644 index 0000000000..759d5fe413 --- /dev/null +++ b/editor/icons/GeometryInstance3D.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7304688v6.5410152a2 2 0 0 0 -1 1.728516 2 2 0 0 0 2 2 2 2 0 0 0 1.7304688-1h6.5410152a2 2 0 0 0 1.728516 1 2 2 0 0 0 2-2 2 2 0 0 0 -1.03125-1.75h.03125v-6.5214844a2 2 0 0 0 1-1.7285156 2 2 0 0 0 -2-2 2 2 0 0 0 -1.730469 1h-6.5410154a2 2 0 0 0 -1.7285156-1zm1 3h1.4140625 3.5859375 2.271484a2 2 0 0 0 .728516.7304688v1.2695312 4.585938 1.414062h-1.414062-4.585938-1.2714844a2 2 0 0 0 -.7285156-.730469v-3.269531-2.5859375z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/ImporterMeshInstance3D.svg b/editor/icons/ImporterMeshInstance3D.svg new file mode 100644 index 0000000000..7e7598ac2b --- /dev/null +++ b/editor/icons/ImporterMeshInstance3D.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 1 1.7304688v6.5410152a2 2 0 0 0 -1 1.728516 2 2 0 0 0 2 2 2 2 0 0 0 1.7304688-1h6.5410152a2 2 0 0 0 1.728516 1 2 2 0 0 0 2-2 2 2 0 0 0 -1.03125-1.75h.03125v-6.5214844a2 2 0 0 0 1-1.7285156 2 2 0 0 0 -2-2 2 2 0 0 0 -1.730469 1h-6.5410154a2 2 0 0 0 -1.7285156-1zm1 3h1.4140625 3.5859375 2.271484a2 2 0 0 0 .728516.7304688v1.2695312 4.585938 1.414062h-1.414062-4.585938-1.2714844a2 2 0 0 0 -.7285156-.730469v-3.269531-2.5859375z"/><path d="m7 7h2v4h-2z"/><path d="m7 5h2v1h-2z"/></g></svg> diff --git a/editor/icons/MultiplayerSpawner.svg b/editor/icons/MultiplayerSpawner.svg new file mode 100644 index 0000000000..68ffd3aab4 --- /dev/null +++ b/editor/icons/MultiplayerSpawner.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path style="fill:none;fill-opacity:.996078;stroke:#e0e0e0;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:16.5;stroke-opacity:1;paint-order:stroke markers fill" d="M4.936 7.429A4 4 0 0 1 8 6a4 4 0 0 1 3.064 1.429M1.872 4.858A8 8 0 0 1 8 2a8 8 0 0 1 6.128 2.858"/><path d="M7 9v2H5v2h2v2h2v-2h2v-2H9V9Z" fill="#5fff97"/></svg> diff --git a/editor/icons/MultiplayerSynchronizer.svg b/editor/icons/MultiplayerSynchronizer.svg new file mode 100644 index 0000000000..1547ec5a2b --- /dev/null +++ b/editor/icons/MultiplayerSynchronizer.svg @@ -0,0 +1 @@ +<svg height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path style="fill:#5fff97;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers" d="M5 10h3l-2 4-2-4Z"/><path style="fill:#ff5f5f;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers" d="M9 14h3l-2-4-2 4Z"/><path style="fill:none;fill-opacity:.996078;stroke:#e0e0e0;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:16.5;stroke-opacity:1;paint-order:stroke markers fill" d="M4.936 7.429A4 4 0 0 1 8 6a4 4 0 0 1 3.064 1.429M1.872 4.858A8 8 0 0 1 8 2a8 8 0 0 1 6.128 2.858"/></svg> diff --git a/editor/icons/Range.svg b/editor/icons/Range.svg new file mode 100644 index 0000000000..49311546b0 --- /dev/null +++ b/editor/icons/Range.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7.8027344 2.7714844c-1.0905892.2029663-1.089037 1.7659969.00195 1.9667968l2.8808595.5761719.576172 2.8808594c.231158 1.3504655 2.264924.9453327 1.960937-.390625l-.7070279-3.5371094c-.039663-.1968491-.137665-.3771998-.28125-.5175781-.138135-.1351849-.312483-.2274468-.501953-.265625l-3.5371095-.7070312c-.1291868-.0278728-.262617-.0298643-.3925781-.0058594zm-3.9941406 4.2167968c-.6571498-.0349349-1.1683412.5633914-1.03125 1.2070313l.7070312 3.5371095c.079467.394998.3882047.703736.7832031.783203l3.5371094.707031c1.3359577.303987 1.7410905-1.729779.390625-1.960937l-2.8808594-.576172-.5761719-2.8808595c-.0369237-.1982539-.1329195-.3807141-.2753906-.5234375-.1744016-.1751556-.407488-.2795227-.6542968-.2929688z" fill="#8eef97"/></svg> diff --git a/editor/icons/VisualInstance3D.svg b/editor/icons/VisualInstance3D.svg new file mode 100644 index 0000000000..e5e43b59dd --- /dev/null +++ b/editor/icons/VisualInstance3D.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#fc7f7f"><circle cx="3" cy="3" r="2"/><circle cx="13" cy="3" r="2"/><circle cx="13" cy="13" r="2"/><circle cx="3" cy="13" r="2"/></g></svg> diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index f2975b1d7a..171ef5bf4c 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -1115,7 +1115,7 @@ Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> ani } if (ResourceCache::has(p_save_to_path)) { - Ref<Animation> old_anim = Ref<Resource>(ResourceCache::get(p_save_to_path)); + Ref<Animation> old_anim = ResourceCache::get_ref(p_save_to_path); if (old_anim.is_valid()) { old_anim->copy_from(anim); anim = old_anim; @@ -1711,7 +1711,7 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m } if (!save_to_file.is_empty()) { - Ref<Mesh> existing = Ref<Resource>(ResourceCache::get(save_to_file)); + Ref<Mesh> existing = ResourceCache::get_ref(save_to_file); if (existing.is_valid()) { //if somehow an existing one is useful, create existing->reset_state(); diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp index aa338a6c0d..e5fe99890e 100644 --- a/editor/import/resource_importer_texture_atlas.cpp +++ b/editor/import/resource_importer_texture_atlas.cpp @@ -306,10 +306,8 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file //update cache if existing, else create Ref<Texture2D> cache; - if (ResourceCache::has(p_group_file)) { - Resource *resptr = ResourceCache::get(p_group_file); - cache.reference_ptr(resptr); - } else { + cache = ResourceCache::get_ref(p_group_file); + if (!cache.is_valid()) { Ref<ImageTexture> res_cache; res_cache.instantiate(); res_cache->create_from_image(new_atlas); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 1ea0299d4e..dea4aaded7 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -5455,7 +5455,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & } child->set_name(name); - Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(ResourceCache::get(path))); + Ref<Texture2D> texture = ResourceCache::get_ref(path); if (parent) { editor_data->get_undo_redo().add_do_method(parent, "add_child", child, true); diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 77a3c07548..d914b9c363 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -884,6 +884,9 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over if (atlas_source) { // Get tile data. TileData *tile_data = atlas_source->get_tile_data(E.value.get_atlas_coords(), E.value.alternative_tile); + if (!tile_data) { + continue; + } // Compute the offset Rect2i source_rect = atlas_source->get_tile_texture_region(E.value.get_atlas_coords()); diff --git a/editor/quick_open.cpp b/editor/quick_open.cpp index 53da945868..4938699fc4 100644 --- a/editor/quick_open.cpp +++ b/editor/quick_open.cpp @@ -146,8 +146,8 @@ void EditorQuickOpen::_confirmed() { return; } _cleanup(); - emit_signal(SNAME("quick_open")); hide(); + emit_signal(SNAME("quick_open")); } void EditorQuickOpen::cancel_pressed() { diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 617db883f8..e6aeef2fd1 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1254,6 +1254,14 @@ GDScript::~GDScript() { memdelete(E.value); } + if (implicit_initializer) { + memdelete(implicit_initializer); + } + + if (implicit_ready) { + memdelete(implicit_ready); + } + if (GDScriptCache::singleton) { // Cache may have been already destroyed at engine shutdown. GDScriptCache::remove_script(get_path()); } @@ -1541,6 +1549,18 @@ bool GDScriptInstance::has_method(const StringName &p_method) const { Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) { GDScript *sptr = script.ptr(); + if (unlikely(p_method == SNAME("_ready"))) { + // Call implicit ready first, including for the super classes. + while (sptr) { + if (sptr->implicit_ready) { + sptr->implicit_ready->call(this, nullptr, 0, r_error); + } + sptr = sptr->_base; + } + + // Reset this back for the regular call. + sptr = script.ptr(); + } while (sptr) { HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method); if (E) { diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 0057962d5e..feb0a237df 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -120,6 +120,7 @@ class GDScript : public Script { GDScriptFunction *implicit_initializer = nullptr; GDScriptFunction *initializer = nullptr; //direct pointer to new , faster to locate + GDScriptFunction *implicit_ready = nullptr; int subclass_count = 0; RBSet<Object *> instances; diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 25454030b1..16a0b17d61 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -1990,18 +1990,18 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ // Parse initializer if applies. bool is_implicit_initializer = !p_for_ready && !p_func && !p_for_lambda; - bool is_initializer = p_func && !p_for_lambda && String(p_func->identifier->name) == GDScriptLanguage::get_singleton()->strings._init; - bool is_for_ready = p_for_ready || (p_func && !p_for_lambda && String(p_func->identifier->name) == "_ready"); + bool is_initializer = p_func && !p_for_lambda && p_func->identifier->name == GDScriptLanguage::get_singleton()->strings._init; + bool is_implicit_ready = !p_func && p_for_ready; - if (!p_for_lambda && (is_implicit_initializer || is_for_ready)) { + if (!p_for_lambda && (is_implicit_initializer || is_implicit_ready)) { // Initialize class fields. for (int i = 0; i < p_class->members.size(); i++) { if (p_class->members[i].type != GDScriptParser::ClassNode::Member::VARIABLE) { continue; } const GDScriptParser::VariableNode *field = p_class->members[i].variable; - if (field->onready != is_for_ready) { - // Only initialize in _ready. + if (field->onready != is_implicit_ready) { + // Only initialize in @implicit_ready. continue; } @@ -2123,6 +2123,8 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ p_script->initializer = gd_function; } else if (is_implicit_initializer) { p_script->implicit_initializer = gd_function; + } else if (is_implicit_ready) { + p_script->implicit_ready = gd_function; } if (p_func) { @@ -2140,7 +2142,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ #endif } - if (!p_for_lambda) { + if (!is_implicit_initializer && !is_implicit_ready && !p_for_lambda) { p_script->member_functions[func_name] = gd_function; } @@ -2208,11 +2210,19 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar for (const KeyValue<StringName, GDScriptFunction *> &E : p_script->member_functions) { memdelete(E.value); } + if (p_script->implicit_initializer) { + memdelete(p_script->implicit_initializer); + } + if (p_script->implicit_ready) { + memdelete(p_script->implicit_ready); + } p_script->member_functions.clear(); p_script->member_indices.clear(); p_script->member_info.clear(); p_script->_signals.clear(); p_script->initializer = nullptr; + p_script->implicit_initializer = nullptr; + p_script->implicit_ready = nullptr; p_script->tool = parser->is_tool(); p_script->name = p_class->identifier ? p_class->identifier->name : ""; @@ -2456,15 +2466,10 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { //parse methods - bool has_ready = false; - for (int i = 0; i < p_class->members.size(); i++) { const GDScriptParser::ClassNode::Member &member = p_class->members[i]; if (member.type == member.FUNCTION) { const GDScriptParser::FunctionNode *function = member.function; - if (!has_ready && function->identifier->name == "_ready") { - has_ready = true; - } Error err = OK; _parse_function(err, p_script, p_class, function); if (err) { @@ -2498,8 +2503,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa } } - if (!has_ready && p_class->onready_used) { - //create a _ready constructor + if (p_class->onready_used) { + // Create an implicit_ready constructor. Error err = OK; _parse_function(err, p_script, p_class, nullptr, true); if (err) { diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 5345143271..474c8094f2 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -746,7 +746,7 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a ScriptLanguage::CodeCompletionOption slider2("or_lesser", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); slider2.insert_text = slider2.display.quote(p_quote_style); r_result.insert(slider2.display, slider2); - ScriptLanguage::CodeCompletionOption slider3("noslider", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); + ScriptLanguage::CodeCompletionOption slider3("no_slider", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); slider3.insert_text = slider3.display.quote(p_quote_style); r_result.insert(slider3.display, slider3); } diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 5abbf907c7..9e347eed5a 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -109,31 +109,31 @@ GDScriptParser::GDScriptParser() { // Register valid annotations. // TODO: Should this be static? register_annotation(MethodInfo("@tool"), AnnotationInfo::SCRIPT, &GDScriptParser::tool_annotation); - register_annotation(MethodInfo("@icon", { Variant::STRING, "icon_path" }), AnnotationInfo::SCRIPT, &GDScriptParser::icon_annotation); + register_annotation(MethodInfo("@icon", PropertyInfo(Variant::STRING, "icon_path")), AnnotationInfo::SCRIPT, &GDScriptParser::icon_annotation); register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation); // Export annotations. register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>); - register_annotation(MethodInfo("@export_enum", { Variant::STRING, "names" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::INT>, 0, true); - register_annotation(MethodInfo("@export_file", { Variant::STRING, "filter" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, 1, true); + register_annotation(MethodInfo("@export_enum", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::INT>, 0, true); + register_annotation(MethodInfo("@export_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, 1, true); register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>); - register_annotation(MethodInfo("@export_global_file", { Variant::STRING, "filter" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, 1, true); + register_annotation(MethodInfo("@export_global_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, 1, true); register_annotation(MethodInfo("@export_global_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_DIR, Variant::STRING>); register_annotation(MethodInfo("@export_multiline"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_MULTILINE_TEXT, Variant::STRING>); register_annotation(MethodInfo("@export_placeholder"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>); - register_annotation(MethodInfo("@export_range", { Variant::FLOAT, "min" }, { Variant::FLOAT, "max" }, { Variant::FLOAT, "step" }, { Variant::STRING, "slider1" }, { Variant::STRING, "slider2" }, { Variant::STRING, "slider3" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, 4); - register_annotation(MethodInfo("@export_exp_easing", { Variant::STRING, "hint1" }, { Variant::STRING, "hint2" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, 2); + register_annotation(MethodInfo("@export_range", PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"), PropertyInfo(Variant::FLOAT, "step"), PropertyInfo(Variant::STRING, "slider1"), PropertyInfo(Variant::STRING, "slider2"), PropertyInfo(Variant::STRING, "slider3")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, 4); + register_annotation(MethodInfo("@export_exp_easing", PropertyInfo(Variant::STRING, "hint1"), PropertyInfo(Variant::STRING, "hint2")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, 2); register_annotation(MethodInfo("@export_color_no_alpha"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_COLOR_NO_ALPHA, Variant::COLOR>); - register_annotation(MethodInfo("@export_node_path", { Variant::STRING, "type" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NODE_PATH_VALID_TYPES, Variant::NODE_PATH>, 1, true); - register_annotation(MethodInfo("@export_flags", { Variant::STRING, "names" }), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FLAGS, Variant::INT>, 0, true); + register_annotation(MethodInfo("@export_node_path", PropertyInfo(Variant::STRING, "type")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NODE_PATH_VALID_TYPES, Variant::NODE_PATH>, 1, true); + register_annotation(MethodInfo("@export_flags", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FLAGS, Variant::INT>, 0, true); register_annotation(MethodInfo("@export_flags_2d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_RENDER, Variant::INT>); register_annotation(MethodInfo("@export_flags_2d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_PHYSICS, Variant::INT>); register_annotation(MethodInfo("@export_flags_2d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_2D_NAVIGATION, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_RENDER, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>); register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>); - register_annotation(MethodInfo("@warning_ignore", { Variant::STRING, "warning" }), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, 0, true); + register_annotation(MethodInfo("@warning_ignore", PropertyInfo(Variant::STRING, "warning")), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, 0, true); // Networking. - register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, 4, true); + register_annotation(MethodInfo("@rpc", PropertyInfo(Variant::STRING, "mode"), PropertyInfo(Variant::STRING, "sync"), PropertyInfo(Variant::STRING, "transfer_mode"), PropertyInfo(Variant::INT, "transfer_channel")), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, 4, true); } GDScriptParser::~GDScriptParser() { diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index 214c60091c..2ce3715bea 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -51,7 +51,7 @@ void LightmapperRD::add_mesh(const MeshData &p_mesh) { mesh_instances.push_back(mi); } -void LightmapperRD::add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance) { +void LightmapperRD::add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance, float p_shadow_blur) { Light l; l.type = LIGHT_TYPE_DIRECTIONAL; l.direction[0] = p_direction.x; @@ -62,11 +62,12 @@ void LightmapperRD::add_directional_light(bool p_static, const Vector3 &p_direct l.color[2] = p_color.b; l.energy = p_energy; l.static_bake = p_static; - l.size = p_angular_distance; + l.size = Math::tan(Math::deg2rad(p_angular_distance)); + l.shadow_blur = p_shadow_blur; lights.push_back(l); } -void LightmapperRD::add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size) { +void LightmapperRD::add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) { Light l; l.type = LIGHT_TYPE_OMNI; l.position[0] = p_position.x; @@ -80,10 +81,11 @@ void LightmapperRD::add_omni_light(bool p_static, const Vector3 &p_position, con l.energy = p_energy; l.static_bake = p_static; l.size = p_size; + l.shadow_blur = p_shadow_blur; lights.push_back(l); } -void LightmapperRD::add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size) { +void LightmapperRD::add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) { Light l; l.type = LIGHT_TYPE_SPOT; l.position[0] = p_position.x; @@ -102,6 +104,7 @@ void LightmapperRD::add_spot_light(bool p_static, const Vector3 &p_position, con l.energy = p_energy; l.static_bake = p_static; l.size = p_size; + l.shadow_blur = p_shadow_blur; lights.push_back(l); } @@ -1140,6 +1143,23 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d RID light_uniform_set = rd->uniform_set_create(uniforms, compute_shader_primary, 1); + switch (p_quality) { + case BAKE_QUALITY_LOW: { + push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/low_quality_ray_count"); + } break; + case BAKE_QUALITY_MEDIUM: { + push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/medium_quality_ray_count"); + } break; + case BAKE_QUALITY_HIGH: { + push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/high_quality_ray_count"); + } break; + case BAKE_QUALITY_ULTRA: { + push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/ultra_quality_ray_count"); + } break; + } + + push_constant.ray_count = CLAMP(push_constant.ray_count, 16u, 8192u); + RD::ComputeListID compute_list = rd->compute_list_begin(); rd->compute_list_bind_compute_pipeline(compute_list, compute_shader_primary_pipeline); rd->compute_list_bind_uniform_set(compute_list, compute_base_uniform_set, 0); @@ -1230,23 +1250,6 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d uniforms.write[1].set_id(0, light_dest_tex); secondary_uniform_set[1] = rd->uniform_set_create(uniforms, compute_shader_secondary, 1); - switch (p_quality) { - case BAKE_QUALITY_LOW: { - push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/low_quality_ray_count"); - } break; - case BAKE_QUALITY_MEDIUM: { - push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/medium_quality_ray_count"); - } break; - case BAKE_QUALITY_HIGH: { - push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/high_quality_ray_count"); - } break; - case BAKE_QUALITY_ULTRA: { - push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/ultra_quality_ray_count"); - } break; - } - - push_constant.ray_count = CLAMP(push_constant.ray_count, 16u, 8192u); - int max_region_size = nearest_power_of_2_templated(int(GLOBAL_GET("rendering/lightmapping/bake_performance/region_size"))); int max_rays = GLOBAL_GET("rendering/lightmapping/bake_performance/max_rays_per_pass"); diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h index bf9f9b5954..8cb4b58a18 100644 --- a/modules/lightmapper_rd/lightmapper_rd.h +++ b/modules/lightmapper_rd/lightmapper_rd.h @@ -57,8 +57,9 @@ class LightmapperRD : public Lightmapper { float attenuation = 0.0; float cos_spot_angle = 0.0; float inv_spot_attenuation = 0.0; + float shadow_blur = 0.0; uint32_t static_bake = 0; - uint32_t pad[3] = {}; + uint32_t pad[2] = {}; bool operator<(const Light &p_light) const { return type < p_light.type; @@ -236,9 +237,9 @@ class LightmapperRD : public Lightmapper { public: virtual void add_mesh(const MeshData &p_mesh) override; - virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance) override; - virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size) override; - virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size) override; + virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance, float p_shadow_blur) override; + virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) override; + virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) override; virtual void add_probe(const Vector3 &p_position) override; virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr) override; diff --git a/modules/lightmapper_rd/lm_common_inc.glsl b/modules/lightmapper_rd/lm_common_inc.glsl index 58523dc1f8..e0e8000f56 100644 --- a/modules/lightmapper_rd/lm_common_inc.glsl +++ b/modules/lightmapper_rd/lm_common_inc.glsl @@ -51,8 +51,9 @@ struct Light { float cos_spot_angle; float inv_spot_attenuation; + float shadow_blur; bool static_bake; - uint pad[3]; + uint pad[2]; }; layout(set = 0, binding = 4, std430) restrict readonly buffer Lights { diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl index 0b6b72a310..efa6cd50b4 100644 --- a/modules/lightmapper_rd/lm_compute.glsl +++ b/modules/lightmapper_rd/lm_compute.glsl @@ -316,19 +316,24 @@ void main() { for (uint i = 0; i < params.light_count; i++) { vec3 light_pos; + float dist; float attenuation; + float soft_shadowing_disk_size; if (lights.data[i].type == LIGHT_TYPE_DIRECTIONAL) { vec3 light_vec = lights.data[i].direction; light_pos = position - light_vec * length(params.world_size); + dist = length(params.world_size); attenuation = 1.0; + soft_shadowing_disk_size = lights.data[i].size; } else { light_pos = lights.data[i].position; - float d = distance(position, light_pos); - if (d > lights.data[i].range) { + dist = distance(position, light_pos); + if (dist > lights.data[i].range) { continue; } + soft_shadowing_disk_size = lights.data[i].size / dist; - attenuation = get_omni_attenuation(d, 1.0 / lights.data[i].range, lights.data[i].attenuation); + attenuation = get_omni_attenuation(dist, 1.0 / lights.data[i].range, lights.data[i].attenuation); if (lights.data[i].type == LIGHT_TYPE_SPOT) { vec3 rel = normalize(position - light_pos); @@ -352,27 +357,70 @@ void main() { continue; //no need to do anything } - if (trace_ray(position + light_dir * params.bias, light_pos) == RAY_MISS) { - vec3 light = lights.data[i].color * lights.data[i].energy * attenuation; - if (lights.data[i].static_bake) { - static_light += light; -#ifdef USE_SH_LIGHTMAPS + float penumbra = 0.0; + if (lights.data[i].size > 0.0) { + vec3 light_to_point = -light_dir; + vec3 aux = light_to_point.y < 0.777 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0); + vec3 light_to_point_tan = normalize(cross(light_to_point, aux)); + vec3 light_to_point_bitan = normalize(cross(light_to_point, light_to_point_tan)); + + const uint shadowing_rays_check_penumbra_denom = 2; + uint shadowing_ray_count = params.ray_count; + + uint hits = 0; + uint noise = random_seed(ivec3(atlas_pos, 43573547 /* some prime */)); + vec3 light_disk_to_point = light_to_point; + for (uint j = 0; j < shadowing_ray_count; j++) { + // Optimization: + // Once already traced an important proportion of rays, if all are hits or misses, + // assume we're not in the penumbra so we can infer the rest would have the same result + if (j == shadowing_ray_count / shadowing_rays_check_penumbra_denom) { + if (hits == j) { + // Assume totally lit + hits = shadowing_ray_count; + break; + } else if (hits == 0) { + // Assume totally dark + hits = 0; + break; + } + } - float c[4] = float[]( - 0.282095, //l0 - 0.488603 * light_dir.y, //l1n1 - 0.488603 * light_dir.z, //l1n0 - 0.488603 * light_dir.x //l1p1 - ); + float r = randomize(noise); + float a = randomize(noise) * 2.0 * PI; + vec2 disk_sample = (r * vec2(cos(a), sin(a))) * soft_shadowing_disk_size * lights.data[i].shadow_blur; + light_disk_to_point = normalize(light_to_point + disk_sample.x * light_to_point_tan + disk_sample.y * light_to_point_bitan); - for (uint j = 0; j < 4; j++) { - sh_accum[j].rgb += light * c[j] * (1.0 / 3.0); + if (trace_ray(position - light_disk_to_point * params.bias, position - light_disk_to_point * dist) == RAY_MISS) { + hits++; } -#endif + } + penumbra = float(hits) / float(shadowing_ray_count); + } else { + if (trace_ray(position + light_dir * params.bias, light_pos) == RAY_MISS) { + penumbra = 1.0; + } + } - } else { - dynamic_light += light; + vec3 light = lights.data[i].color * lights.data[i].energy * attenuation * penumbra; + if (lights.data[i].static_bake) { + static_light += light; +#ifdef USE_SH_LIGHTMAPS + + float c[4] = float[]( + 0.282095, //l0 + 0.488603 * light_dir.y, //l1n1 + 0.488603 * light_dir.z, //l1n0 + 0.488603 * light_dir.x //l1p1 + ); + + for (uint j = 0; j < 4; j++) { + sh_accum[j].rgb += light * c[j] * (1.0 / 3.0); } +#endif + + } else { + dynamic_light += light; } } diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj index ae78da27bc..303ca3a293 100644 --- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging.CLI/GodotTools.IdeMessaging.CLI.csproj @@ -12,6 +12,6 @@ <ProjectReference Include="..\GodotTools.IdeMessaging\GodotTools.IdeMessaging.csproj" /> </ItemGroup> <ItemGroup> - <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> + <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> </ItemGroup> </Project> diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj index dad6b9ae7a..02f1764f32 100644 --- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj +++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/GodotTools.IdeMessaging.csproj @@ -19,6 +19,6 @@ A client using this library is only compatible with servers of the same major ve </Description> </PropertyGroup> <ItemGroup> - <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> + <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> </ItemGroup> </Project> diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs index 9e8f7ef1b1..3c020a2589 100644 --- a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs +++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs @@ -126,7 +126,7 @@ namespace GodotTools.Build { base._Ready(); - MinimumSize = new Vector2(0, 228) * EditorScale; + CustomMinimumSize = new Vector2(0, 228) * EditorScale; SizeFlagsVertical = (int)SizeFlags.ExpandFill; var toolBarHBox = new HBoxContainer { SizeFlagsHorizontal = (int)SizeFlags.ExpandFill }; diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj index b9aa760f4d..f1d45463c5 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj +++ b/modules/mono/editor/GodotTools/GodotTools/GodotTools.csproj @@ -19,7 +19,7 @@ <ItemGroup> <PackageReference Include="JetBrains.Annotations" Version="2019.1.3.0" ExcludeAssets="runtime" PrivateAssets="all" /> <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" /> - <PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> + <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <Reference Include="GodotSharp"> <HintPath>$(GodotApiAssembliesDir)/GodotSharp.dll</HintPath> <Private>False</Private> diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp index 2f8cb6c230..bcbc721dbb 100644 --- a/modules/navigation/godot_navigation_server.cpp +++ b/modules/navigation/godot_navigation_server.cpp @@ -123,6 +123,18 @@ void GodotNavigationServer::add_command(SetCommand *command) const { } } +Array GodotNavigationServer::get_maps() const { + Array all_map_rids; + List<RID> maps_owned; + map_owner.get_owned_list(&maps_owned); + if (maps_owned.size()) { + for (const RID &E : maps_owned) { + all_map_rids.push_back(E); + } + } + return all_map_rids; +} + RID GodotNavigationServer::map_create() const { GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this); MutexLock lock(mut_this->operations_mutex); @@ -339,6 +351,16 @@ real_t GodotNavigationServer::region_get_travel_cost(RID p_region) const { return region->get_travel_cost(); } +bool GodotNavigationServer::region_owns_point(RID p_region, const Vector3 &p_point) const { + const NavRegion *region = region_owner.get_or_null(p_region); + ERR_FAIL_COND_V(region == nullptr, false); + if (region->get_map()) { + RID closest_point_owner = map_get_closest_point_owner(region->get_map()->get_self(), p_point); + return closest_point_owner == region->get_self(); + } + return false; +} + COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers) { NavRegion *region = region_owner.get_or_null(p_region); ERR_FAIL_COND(region == nullptr); @@ -580,6 +602,15 @@ void GodotNavigationServer::flush_queries() { commands.clear(); } +void GodotNavigationServer::map_force_update(RID p_map) { + NavMap *map = map_owner.get_or_null(p_map); + ERR_FAIL_COND(map == nullptr); + + flush_queries(); + + map->sync(); +} + void GodotNavigationServer::process(real_t p_delta_time) { flush_queries(); diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h index d931dbaee0..8e7e99888c 100644 --- a/modules/navigation/godot_navigation_server.h +++ b/modules/navigation/godot_navigation_server.h @@ -85,6 +85,8 @@ public: void add_command(SetCommand *command) const; + virtual Array get_maps() const override; + virtual RID map_create() const override; COMMAND_2(map_set_active, RID, p_map, bool, p_active); virtual bool map_is_active(RID p_map) const override; @@ -108,6 +110,8 @@ public: virtual Array map_get_regions(RID p_map) const override; virtual Array map_get_agents(RID p_map) const override; + virtual void map_force_update(RID p_map) override; + virtual RID region_create() const override; COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost); @@ -115,6 +119,8 @@ public: COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost); virtual real_t region_get_travel_cost(RID p_region) const override; + virtual bool region_owns_point(RID p_region, const Vector3 &p_point) const override; + COMMAND_2(region_set_map, RID, p_region, RID, p_map); virtual RID region_get_map(RID p_region) const override; COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers); diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp index e430f5fd59..6e8ac77f79 100644 --- a/modules/navigation/navigation_mesh_generator.cpp +++ b/modules/navigation/navigation_mesh_generator.cpp @@ -482,6 +482,21 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh( cfg.bmax[1] = bmax[1]; cfg.bmax[2] = bmax[2]; + AABB baking_aabb = p_nav_mesh->get_filter_baking_aabb(); + + bool aabb_has_no_volume = baking_aabb.has_no_volume(); + + if (!aabb_has_no_volume) { + Vector3 baking_aabb_offset = p_nav_mesh->get_filter_baking_aabb_offset(); + + cfg.bmin[0] = baking_aabb.position[0] + baking_aabb_offset.x; + cfg.bmin[1] = baking_aabb.position[1] + baking_aabb_offset.y; + cfg.bmin[2] = baking_aabb.position[2] + baking_aabb_offset.z; + cfg.bmax[0] = cfg.bmin[0] + baking_aabb.size[0]; + cfg.bmax[1] = cfg.bmin[1] + baking_aabb.size[1]; + cfg.bmax[2] = cfg.bmin[2] + baking_aabb.size[2]; + } + #ifdef TOOLS_ENABLED if (ep) { ep->step(TTR("Calculating grid size..."), 2); @@ -631,6 +646,13 @@ void NavigationMeshGenerator::bake(Ref<NavigationMesh> p_nav_mesh, Node *p_node) #ifdef TOOLS_ENABLED EditorProgress *ep(nullptr); + // FIXME +#endif +#if 0 + // After discussion on devchat disabled EditorProgress for now as it is not thread-safe and uses hacks and Main::iteration() for steps. + // EditorProgress randomly crashes the Engine when the bake function is used with a thread e.g. inside Editor with a tool script and procedural navigation + // This was not a problem in older versions as previously Godot was unable to (re)bake NavigationMesh at runtime. + // If EditorProgress is fixed and made thread-safe this should be enabled again. if (Engine::get_singleton()->is_editor_hint()) { ep = memnew(EditorProgress("bake", TTR("Navigation Mesh Generator Setup:"), 11)); } diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp index 5fa6ace827..661fe343af 100644 --- a/modules/tinyexr/image_saver_tinyexr.cpp +++ b/modules/tinyexr/image_saver_tinyexr.cpp @@ -141,13 +141,14 @@ static int get_channel_count(Image::Format p_format) { } } -Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale) { +Vector<uint8_t> save_exr_buffer(const Ref<Image> &p_img, bool p_grayscale) { Image::Format format = p_img->get_format(); if (!is_supported_format(format)) { // Format not supported print_error("Image format not supported for saving as EXR. Consider saving as PNG."); - return ERR_UNAVAILABLE; + + return Vector<uint8_t>(); } EXRHeader header; @@ -175,15 +176,15 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale) }; int channel_count = get_channel_count(format); - ERR_FAIL_COND_V(channel_count < 0, ERR_UNAVAILABLE); - ERR_FAIL_COND_V(p_grayscale && channel_count != 1, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(channel_count < 0, Vector<uint8_t>()); + ERR_FAIL_COND_V(p_grayscale && channel_count != 1, Vector<uint8_t>()); int target_pixel_type = get_target_pixel_type(format); - ERR_FAIL_COND_V(target_pixel_type < 0, ERR_UNAVAILABLE); + ERR_FAIL_COND_V(target_pixel_type < 0, Vector<uint8_t>()); int target_pixel_type_size = get_pixel_type_size(target_pixel_type); - ERR_FAIL_COND_V(target_pixel_type_size < 0, ERR_UNAVAILABLE); + ERR_FAIL_COND_V(target_pixel_type_size < 0, Vector<uint8_t>()); SrcPixelType src_pixel_type = get_source_pixel_type(format); - ERR_FAIL_COND_V(src_pixel_type == SRC_UNSUPPORTED, ERR_UNAVAILABLE); + ERR_FAIL_COND_V(src_pixel_type == SRC_UNSUPPORTED, Vector<uint8_t>()); const int pixel_count = p_img->get_width() * p_img->get_height(); const int *channel_mapping = channel_mappings[channel_count - 1]; @@ -270,15 +271,25 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale) const char *err = nullptr; size_t bytes = SaveEXRImageToMemory(&image, &header, &mem, &err); + if (err && *err != OK) { + return Vector<uint8_t>(); + } + Vector<uint8_t> buffer; + buffer.resize(bytes); + memcpy(buffer.ptrw(), mem, bytes); + free(mem); + return buffer; +} - if (bytes == 0) { - print_error(String("Saving EXR failed. Error: {0}").format(varray(err))); +Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale) { + const Vector<uint8_t> buffer = save_exr_buffer(p_img, p_grayscale); + if (buffer.size() == 0) { + print_error(String("Saving EXR failed.")); return ERR_FILE_CANT_WRITE; } else { Ref<FileAccess> ref = FileAccess::open(p_path, FileAccess::WRITE); ERR_FAIL_COND_V(ref.is_null(), ERR_FILE_CANT_WRITE); - ref->store_buffer(mem, bytes); - free(mem); + ref->store_buffer(buffer.ptr(), buffer.size()); } return OK; diff --git a/modules/tinyexr/image_saver_tinyexr.h b/modules/tinyexr/image_saver_tinyexr.h index 5bf95b265e..8f97f55408 100644 --- a/modules/tinyexr/image_saver_tinyexr.h +++ b/modules/tinyexr/image_saver_tinyexr.h @@ -34,5 +34,6 @@ #include "core/os/os.h" Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale); +Vector<uint8_t> save_exr_buffer(const Ref<Image> &p_img, bool p_grayscale); #endif // IMAGE_SAVER_TINYEXR_H diff --git a/modules/tinyexr/register_types.cpp b/modules/tinyexr/register_types.cpp index d49ac23fea..c5897f37c3 100644 --- a/modules/tinyexr/register_types.cpp +++ b/modules/tinyexr/register_types.cpp @@ -44,6 +44,7 @@ void initialize_tinyexr_module(ModuleInitializationLevel p_level) { ImageLoader::add_image_format_loader(image_loader_tinyexr); Image::save_exr_func = save_exr; + Image::save_exr_buffer_func = save_exr_buffer; } void uninitialize_tinyexr_module(ModuleInitializationLevel p_level) { diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp index bbbb995635..19bbd834cc 100644 --- a/modules/visual_script/visual_script_flow_control.cpp +++ b/modules/visual_script/visual_script_flow_control.cpp @@ -803,7 +803,7 @@ public: //if the script is not in use by anyone, we can safely assume whatever we got is not casting to it. return 1; } - Ref<Script> cast_script = Ref<Resource>(ResourceCache::get(script)); + Ref<Script> cast_script = ResourceCache::get_ref(script); if (!cast_script.is_valid()) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; r_error_str = "Script path is not a script: " + script; diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp index 483fc8b6c3..b16358ae38 100644 --- a/modules/visual_script/visual_script_func_nodes.cpp +++ b/modules/visual_script/visual_script_func_nodes.cpp @@ -377,7 +377,7 @@ void VisualScriptFunctionCall::_update_method_cache() { } if (ResourceCache::has(base_script)) { - script = Ref<Resource>(ResourceCache::get(base_script)); + script = ResourceCache::get_ref(base_script); } else { return; } @@ -587,7 +587,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const } if (ResourceCache::has(base_script)) { - Ref<Script> script = Ref<Resource>(ResourceCache::get(base_script)); + Ref<Script> script = ResourceCache::get_ref(base_script); if (script.is_valid()) { property.hint = PROPERTY_HINT_METHOD_OF_SCRIPT; property.hint_string = itos(script->get_instance_id()); @@ -1178,7 +1178,7 @@ void VisualScriptPropertySet::_update_cache() { } if (ResourceCache::has(base_script)) { - script = Ref<Resource>(ResourceCache::get(base_script)); + script = ResourceCache::get_ref(base_script); } else { return; } @@ -1338,7 +1338,7 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const { } if (ResourceCache::has(base_script)) { - Ref<Script> script = Ref<Resource>(ResourceCache::get(base_script)); + Ref<Script> script = ResourceCache::get_ref(base_script); if (script.is_valid()) { property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; property.hint_string = itos(script->get_instance_id()); @@ -1864,7 +1864,7 @@ void VisualScriptPropertyGet::_update_cache() { } if (ResourceCache::has(base_script)) { - script = Ref<Resource>(ResourceCache::get(base_script)); + script = ResourceCache::get_ref(base_script); } else { return; } @@ -2044,7 +2044,7 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const { } if (ResourceCache::has(base_script)) { - Ref<Script> script = Ref<Resource>(ResourceCache::get(base_script)); + Ref<Script> script = ResourceCache::get_ref(base_script); if (script.is_valid()) { property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT; property.hint_string = itos(script->get_instance_id()); diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp index 10f23b320b..81802298d9 100644 --- a/platform/android/android_input_handler.cpp +++ b/platform/android/android_input_handler.cpp @@ -381,13 +381,3 @@ MouseButton AndroidInputHandler::_android_button_mask_to_godot_button_mask(int a return godot_button_mask; } - -void AndroidInputHandler::process_scroll(Point2 p_pos) { - Ref<InputEventPanGesture> ev; - ev.instantiate(); - _set_key_modifier_state(ev); - ev->set_position(p_pos); - ev->set_delta(p_pos - scroll_prev_pos); - Input::get_singleton()->parse_input_event(ev); - scroll_prev_pos = p_pos; -} diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h index e9c0ec1475..1397ca59e4 100644 --- a/platform/android/android_input_handler.h +++ b/platform/android/android_input_handler.h @@ -69,7 +69,6 @@ private: Vector<TouchPos> touch; Point2 hover_prev_pos; // needed to calculate the relative position on hover events - Point2 scroll_prev_pos; // needed to calculate the relative position on scroll events void _set_key_modifier_state(Ref<InputEventWithModifiers> ev); @@ -83,7 +82,6 @@ public: void process_hover(int p_type, Point2 p_pos); void process_mouse_event(int input_device, int event_action, int event_android_buttons_mask, Point2 event_pos, float event_vertical_factor = 0, float event_horizontal_factor = 0); void process_double_tap(int event_android_button_mask, Point2 p_pos); - void process_scroll(Point2 p_pos); void process_joy_event(JoypadEvent p_event); void process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed); }; diff --git a/platform/android/detect.py b/platform/android/detect.py index 0099ac7e0d..47cfade765 100644 --- a/platform/android/detect.py +++ b/platform/android/detect.py @@ -1,7 +1,7 @@ import os import sys import platform -from distutils.version import LooseVersion +import subprocess def is_active(): @@ -13,41 +13,35 @@ def get_name(): def can_build(): - return ("ANDROID_SDK_ROOT" in os.environ) or ("ANDROID_HOME" in os.environ) - - -def get_platform(platform): - return int(platform.split("-")[1]) + return os.path.exists(get_env_android_sdk_root()) def get_opts(): from SCons.Variables import BoolVariable, EnumVariable return [ - ("ANDROID_NDK_ROOT", "Path to the Android NDK", get_android_ndk_root()), - ("ANDROID_SDK_ROOT", "Path to the Android SDK", get_android_sdk_root()), + ("ANDROID_SDK_ROOT", "Path to the Android SDK", get_env_android_sdk_root()), ("ndk_platform", 'Target platform (android-<api>, e.g. "android-24")', "android-24"), EnumVariable("android_arch", "Target architecture", "arm64v8", ("armv7", "arm64v8", "x86", "x86_64")), ] # Return the ANDROID_SDK_ROOT environment variable. -# While ANDROID_HOME has been deprecated, it's used as a fallback for backward -# compatibility purposes. -def get_android_sdk_root(): - if "ANDROID_SDK_ROOT" in os.environ: - return os.environ.get("ANDROID_SDK_ROOT", 0) - else: - return os.environ.get("ANDROID_HOME", 0) +def get_env_android_sdk_root(): + return os.environ.get("ANDROID_SDK_ROOT", -1) -# Return the ANDROID_NDK_ROOT environment variable. -# We generate one for this build using the ANDROID_SDK_ROOT env -# variable and the project ndk version. -# If the env variable is already defined, we override it with -# our own to match what the project expects. -def get_android_ndk_root(): - return get_android_sdk_root() + "/ndk/" + get_project_ndk_version() +def get_min_sdk_version(platform): + return int(platform.split("-")[1]) + + +def get_android_ndk_root(env): + return env["ANDROID_SDK_ROOT"] + "/ndk/" + get_ndk_version() + + +# This is kept in sync with the value in 'platform/android/java/app/config.gradle'. +def get_ndk_version(): + return "23.2.8568313" def get_flags(): @@ -56,133 +50,70 @@ def get_flags(): ] -def create(env): - tools = env["TOOLS"] - if "mingw" in tools: - tools.remove("mingw") - if "applelink" in tools: - tools.remove("applelink") - env.Tool("gcc") - return env.Clone(tools=tools) - - -# Check if ANDROID_NDK_ROOT is valid. -# If not, install the ndk using ANDROID_SDK_ROOT and sdkmanager. +# Check if Android NDK version is installed +# If not, install it. def install_ndk_if_needed(env): print("Checking for Android NDK...") - env_ndk_version = get_env_ndk_version(env["ANDROID_NDK_ROOT"]) - if env_ndk_version is None: - # Reinstall the ndk and update ANDROID_NDK_ROOT. - print("Installing Android NDK...") - if env["ANDROID_SDK_ROOT"] is None: - raise Exception("Invalid ANDROID_SDK_ROOT environment variable.") - - import subprocess - + sdk_root = env["ANDROID_SDK_ROOT"] + if not os.path.exists(get_android_ndk_root(env)): extension = ".bat" if os.name == "nt" else "" - sdkmanager_path = env["ANDROID_SDK_ROOT"] + "/cmdline-tools/latest/bin/sdkmanager" + extension - ndk_download_args = "ndk;" + get_project_ndk_version() - subprocess.check_call([sdkmanager_path, ndk_download_args]) - - env["ANDROID_NDK_ROOT"] = env["ANDROID_SDK_ROOT"] + "/ndk/" + get_project_ndk_version() - print("ANDROID_NDK_ROOT: " + env["ANDROID_NDK_ROOT"]) + sdkmanager = sdk_root + "/cmdline-tools/latest/bin/sdkmanager" + extension + if os.path.exists(sdkmanager): + # Install the Android NDK + print("Installing Android NDK...") + ndk_download_args = "ndk;" + get_ndk_version() + subprocess.check_call([sdkmanager, ndk_download_args]) + else: + print("Cannot find " + sdkmanager) + print( + "Please ensure ANDROID_SDK_ROOT is correct and cmdline-tools are installed, or install NDK version " + + get_ndk_version() + + " manually." + ) + sys.exit() + env["ANDROID_NDK_ROOT"] = get_android_ndk_root(env) def configure(env): install_ndk_if_needed(env) - - # Workaround for MinGW. See: - # https://www.scons.org/wiki/LongCmdLinesOnWin32 - if os.name == "nt": - - import subprocess - - def mySubProcess(cmdline, env): - # print("SPAWNED : " + cmdline) - startupinfo = subprocess.STARTUPINFO() - startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW - proc = subprocess.Popen( - cmdline, - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - startupinfo=startupinfo, - shell=False, - env=env, - ) - data, err = proc.communicate() - rv = proc.wait() - if rv: - print("=====") - print(err) - print("=====") - return rv - - def mySpawn(sh, escape, cmd, args, env): - - newargs = " ".join(args[1:]) - cmdline = cmd + " " + newargs - - rv = 0 - if len(cmdline) > 32000 and cmd.endswith("ar"): - cmdline = cmd + " " + args[1] + " " + args[2] + " " - for i in range(3, len(args)): - rv = mySubProcess(cmdline + args[i], env) - if rv: - break - else: - rv = mySubProcess(cmdline, env) - - return rv - - env["SPAWN"] = mySpawn + ndk_root = env["ANDROID_NDK_ROOT"] # Architecture if env["android_arch"] not in ["armv7", "arm64v8", "x86", "x86_64"]: - env["android_arch"] = "armv7" + env["android_arch"] = "arm64v8" print("Building for Android, platform " + env["ndk_platform"] + " (" + env["android_arch"] + ")") - can_vectorize = True - if env["android_arch"] == "x86": - env["ARCH"] = "arch-x86" - env.extra_suffix = ".x86" + env.extra_suffix - target_subpath = "x86-4.9" - abi_subpath = "i686-linux-android" - arch_subpath = "x86" - env["x86_libtheora_opt_gcc"] = True - elif env["android_arch"] == "x86_64": - if get_platform(env["ndk_platform"]) < 21: + if get_min_sdk_version(env["ndk_platform"]) < 21: + if env["android_arch"] == "x86_64" or env["android_arch"] == "arm64v8": print( - "WARNING: android_arch=x86_64 is not supported by ndk_platform lower than android-21; setting" - " ndk_platform=android-21" + "WARNING: android_arch=" + + env["android_arch"] + + " is not supported by ndk_platform lower than android-21; setting ndk_platform=android-21" ) env["ndk_platform"] = "android-21" - env["ARCH"] = "arch-x86_64" - env.extra_suffix = ".x86_64" + env.extra_suffix - target_subpath = "x86_64-4.9" - abi_subpath = "x86_64-linux-android" - arch_subpath = "x86_64" - env["x86_libtheora_opt_gcc"] = True - elif env["android_arch"] == "armv7": - env["ARCH"] = "arch-arm" - target_subpath = "arm-linux-androideabi-4.9" - abi_subpath = "arm-linux-androideabi" - arch_subpath = "armeabi-v7a" + + if env["android_arch"] == "armv7": + target_triple = "armv7a-linux-androideabi" + bin_utils = "arm-linux-androideabi" env.extra_suffix = ".armv7" + env.extra_suffix elif env["android_arch"] == "arm64v8": - if get_platform(env["ndk_platform"]) < 21: - print( - "WARNING: android_arch=arm64v8 is not supported by ndk_platform lower than android-21; setting" - " ndk_platform=android-21" - ) - env["ndk_platform"] = "android-21" - env["ARCH"] = "arch-arm64" - target_subpath = "aarch64-linux-android-4.9" - abi_subpath = "aarch64-linux-android" - arch_subpath = "arm64-v8a" + target_triple = "aarch64-linux-android" + bin_utils = target_triple env.extra_suffix = ".armv8" + env.extra_suffix + elif env["android_arch"] == "x86": + target_triple = "i686-linux-android" + bin_utils = target_triple + env.extra_suffix = ".x86" + env.extra_suffix + elif env["android_arch"] == "x86_64": + target_triple = "x86_64-linux-android" + bin_utils = target_triple + env.extra_suffix = ".x86_64" + env.extra_suffix + + target_option = ["-target", target_triple + str(get_min_sdk_version(env["ndk_platform"]))] + env.Append(CCFLAGS=target_option) + env.Append(LINKFLAGS=target_option) # Build type @@ -191,15 +122,11 @@ def configure(env): # `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces # when using `target=release_debug`. opt = "-O3" if env["target"] == "release" else "-O2" - env.Append(LINKFLAGS=[opt]) env.Append(CCFLAGS=[opt, "-fomit-frame-pointer"]) elif env["optimize"] == "size": # optimize for size - env.Append(CCFLAGS=["-Os"]) - env.Append(LINKFLAGS=["-Os"]) - + env.Append(CCFLAGS=["-Oz"]) env.Append(CPPDEFINES=["NDEBUG"]) - if can_vectorize: - env.Append(CCFLAGS=["-ftree-vectorize"]) + env.Append(CCFLAGS=["-ftree-vectorize"]) elif env["target"] == "debug": env.Append(LINKFLAGS=["-O0"]) env.Append(CCFLAGS=["-O0", "-g", "-fno-limit-debug-info"]) @@ -211,7 +138,6 @@ def configure(env): env["SHLIBSUFFIX"] = ".so" if env["PLATFORM"] == "win32": - env.Tool("gcc") env.use_windows_spawn_fix() if sys.platform.startswith("linux"): @@ -224,32 +150,15 @@ def configure(env): else: host_subpath = "windows" - compiler_path = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/" + host_subpath + "/bin" - gcc_toolchain_path = env["ANDROID_NDK_ROOT"] + "/toolchains/" + target_subpath + "/prebuilt/" + host_subpath - tools_path = gcc_toolchain_path + "/" + abi_subpath + "/bin" - - # For Clang to find NDK tools in preference of those system-wide - env.PrependENVPath("PATH", tools_path) - - ccache_path = os.environ.get("CCACHE") - if ccache_path is None: - env["CC"] = compiler_path + "/clang" - env["CXX"] = compiler_path + "/clang++" - else: - # there aren't any ccache wrappers available for Android, - # to enable caching we need to prepend the path to the ccache binary - env["CC"] = ccache_path + " " + compiler_path + "/clang" - env["CXX"] = ccache_path + " " + compiler_path + "/clang++" - env["AR"] = tools_path + "/ar" - env["RANLIB"] = tools_path + "/ranlib" - env["AS"] = tools_path + "/as" + toolchain_path = ndk_root + "/toolchains/llvm/prebuilt/" + host_subpath + compiler_path = toolchain_path + "/bin" + bin_utils_path = toolchain_path + "/" + bin_utils + "/bin" - common_opts = ["-gcc-toolchain", gcc_toolchain_path] - - # Compile flags - - env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/include"]) - env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++abi/include"]) + env["CC"] = compiler_path + "/clang" + env["CXX"] = compiler_path + "/clang++" + env["AR"] = compiler_path + "/llvm-ar" + env["RANLIB"] = compiler_path + "/llvm-ranlib" + env["AS"] = bin_utils_path + "/as" # Disable exceptions and rtti on non-tools (template) builds if env["tools"]: @@ -261,100 +170,31 @@ def configure(env): # Don't use dynamic_cast, necessary with no-rtti. env.Append(CPPDEFINES=["NO_SAFE_CAST"]) - lib_sysroot = env["ANDROID_NDK_ROOT"] + "/platforms/" + env["ndk_platform"] + "/" + env["ARCH"] - - # Using NDK unified headers (NDK r15+) - sysroot = env["ANDROID_NDK_ROOT"] + "/sysroot" - env.Append(CPPFLAGS=["--sysroot=" + sysroot]) - env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include/" + abi_subpath]) - env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/android/support/include"]) - # For unified headers this define has to be set manually - env.Append(CPPDEFINES=[("__ANDROID_API__", str(get_platform(env["ndk_platform"])))]) - env.Append( CCFLAGS=( - "-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden" - " -fno-strict-aliasing".split() + "-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing".split() ) ) env.Append(CPPDEFINES=["NO_STATVFS", "GLES_ENABLED"]) - if get_platform(env["ndk_platform"]) >= 24: + if get_min_sdk_version(env["ndk_platform"]) >= 24: env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)]) if env["android_arch"] == "x86": - target_opts = ["-target", "i686-none-linux-android"] - # The NDK adds this if targeting API < 21, so we can drop it when Godot targets it at least + # The NDK adds this if targeting API < 24, so we can drop it when Godot targets it at least env.Append(CCFLAGS=["-mstackrealign"]) - - elif env["android_arch"] == "x86_64": - target_opts = ["-target", "x86_64-none-linux-android"] - elif env["android_arch"] == "armv7": - target_opts = ["-target", "armv7-none-linux-androideabi"] env.Append(CCFLAGS="-march=armv7-a -mfloat-abi=softfp".split()) env.Append(CPPDEFINES=["__ARM_ARCH_7__", "__ARM_ARCH_7A__"]) - # Enable ARM NEON instructions to compile more optimized code. - env.Append(CCFLAGS=["-mfpu=neon"]) env.Append(CPPDEFINES=["__ARM_NEON__"]) - elif env["android_arch"] == "arm64v8": - target_opts = ["-target", "aarch64-none-linux-android"] env.Append(CCFLAGS=["-mfix-cortex-a53-835769"]) env.Append(CPPDEFINES=["__ARM_ARCH_8A__"]) - env.Append(CCFLAGS=target_opts) - env.Append(CCFLAGS=common_opts) - # Link flags - ndk_version = get_env_ndk_version(env["ANDROID_NDK_ROOT"]) - if ndk_version != None and LooseVersion(ndk_version) >= LooseVersion("17.1.4828580"): - env.Append(LINKFLAGS=["-Wl,--exclude-libs,libgcc.a", "-Wl,--exclude-libs,libatomic.a", "-nostdlib++"]) - else: - env.Append( - LINKFLAGS=[ - env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/libandroid_support.a" - ] - ) - env.Append(LINKFLAGS=["-shared", "--sysroot=" + lib_sysroot, "-Wl,--warn-shared-textrel"]) - env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/"]) - env.Append( - LINKFLAGS=[env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++/libs/" + arch_subpath + "/libc++_shared.so"] - ) - - if env["android_arch"] == "armv7": - env.Append(LINKFLAGS="-Wl,--fix-cortex-a8".split()) - env.Append(LINKFLAGS="-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now".split()) - env.Append(LINKFLAGS="-Wl,-soname,libgodot_android.so -Wl,--gc-sections".split()) - - env.Append(LINKFLAGS=target_opts) - env.Append(LINKFLAGS=common_opts) - - env.Append( - LIBPATH=[ - env["ANDROID_NDK_ROOT"] - + "/toolchains/" - + target_subpath - + "/prebuilt/" - + host_subpath - + "/lib/gcc/" - + abi_subpath - + "/4.9.x" - ] - ) - env.Append( - LIBPATH=[ - env["ANDROID_NDK_ROOT"] - + "/toolchains/" - + target_subpath - + "/prebuilt/" - + host_subpath - + "/" - + abi_subpath - + "/lib" - ] - ) + env.Append(LINKFLAGS="-Wl,--gc-sections -Wl,--no-undefined -Wl,-z,now".split()) + env.Append(LINKFLAGS="-Wl,-soname,libgodot_android.so") env.Prepend(CPPPATH=["#platform/android"]) env.Append(CPPDEFINES=["ANDROID_ENABLED", "UNIX_ENABLED", "NO_FCNTL"]) @@ -364,25 +204,3 @@ def configure(env): env.Append(CPPDEFINES=["VULKAN_ENABLED"]) if not env["use_volk"]: env.Append(LIBS=["vulkan"]) - - -# Return the project NDK version. -# This is kept in sync with the value in 'platform/android/java/app/config.gradle'. -def get_project_ndk_version(): - return "21.4.7075529" - - -# Return NDK version string in source.properties (adapted from the Chromium project). -def get_env_ndk_version(path): - if path is None: - return None - prop_file_path = os.path.join(path, "source.properties") - try: - with open(prop_file_path) as prop_file: - for line in prop_file: - key_value = list(map(lambda x: x.strip(), line.split("="))) - if key_value[0] == "Pkg.Revision": - return key_value[1] - except Exception: - print("Could not read source prop file '%s'" % prop_file_path) - return None diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle index c343b48ca3..3daf628e63 100644 --- a/platform/android/java/app/config.gradle +++ b/platform/android/java/app/config.gradle @@ -8,7 +8,7 @@ ext.versions = [ fragmentVersion : '1.3.6', nexusPublishVersion: '1.1.0', javaVersion : 11, - ndkVersion : '21.4.7075529' // Also update 'platform/android/detect.py#get_project_ndk_version()' when this is updated. + ndkVersion : '23.2.8568313' // Also update 'platform/android/detect.py#get_ndk_version()' when this is updated. ] diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java index 1f8f8c82a6..3182ab0666 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java @@ -114,11 +114,6 @@ public class GodotLib { public static native void doubleTap(int buttonMask, int x, int y); /** - * Forward scroll events from the main thread to the GL thread. - */ - public static native void scroll(int x, int y); - - /** * Forward accelerometer sensor events from the main thread to the GL thread. * @see android.hardware.SensorEventListener#onSensorChanged(SensorEvent) */ diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java index ac13cad23e..778efa914a 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java @@ -80,15 +80,6 @@ public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener } @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - //Log.i("GodotGesture", "onScroll"); - final int x = Math.round(distanceX); - final int y = Math.round(distanceY); - GodotLib.scroll(x, y); - return true; - } - - @Override public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { //Log.i("GodotGesture", "onFling"); return true; diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index de666f1b11..eaffe14b13 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -306,15 +306,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env } // Called on the UI thread -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y) { - if (step.get() <= 0) { - return; - } - - input_handler->process_scroll(Point2(p_x, p_y)); -} - -// Called on the UI thread JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed) { if (step.get() <= 0) { return; diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h index e1d30eea77..aa8d67cf46 100644 --- a/platform/android/java_godot_lib_jni.h +++ b/platform/android/java_godot_lib_jni.h @@ -51,7 +51,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FI(JNIEn JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch__IIII_3FIFF(JNIEnv *env, jclass clazz, jint input_device, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jint buttons_mask, jfloat vertical_factor, jfloat horizontal_factor); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hover(JNIEnv *env, jclass clazz, jint p_type, jfloat p_x, jfloat p_y); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_doubleTap(JNIEnv *env, jclass clazz, jint p_button_mask, jint p_x, jint p_y); -JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_scroll(JNIEnv *env, jclass clazz, jint p_x, jint p_y); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv *env, jclass clazz, jint p_keycode, jint p_scancode, jint p_unicode_char, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv *env, jclass clazz, jint p_device, jint p_button, jboolean p_pressed); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv *env, jclass clazz, jint p_device, jint p_axis, jfloat p_value); diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index b2b848d380..4599785ce4 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -437,7 +437,7 @@ void Node2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent); ADD_GROUP("Transform", ""); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_lesser,or_greater,noslider,suffix:px"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_lesser,or_greater,no_slider,suffix:px"), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew"); diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp index a8eec4b1f3..abe942b97a 100644 --- a/scene/3d/lightmap_gi.cpp +++ b/scene/3d/lightmap_gi.cpp @@ -116,7 +116,7 @@ void LightmapGIData::_set_light_textures_data(const Array &p_data) { Array LightmapGIData::_get_light_textures_data() const { Array ret; - if (light_texture.is_null()) { + if (light_texture.is_null() || light_texture->get_layers() == 0) { return ret; } @@ -979,13 +979,13 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa Color linear_color = light->get_color().srgb_to_linear(); if (Object::cast_to<DirectionalLight3D>(light)) { DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light); - lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_SIZE)); + lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } else if (Object::cast_to<OmniLight3D>(light)) { OmniLight3D *l = Object::cast_to<OmniLight3D>(light); - lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE)); + lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } else if (Object::cast_to<SpotLight3D>(light)) { SpotLight3D *l = Object::cast_to<SpotLight3D>(light); - lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE)); + lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR)); } } for (int i = 0; i < probes_found.size(); i++) { diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h index 4e6f76e360..9b973fd6bc 100644 --- a/scene/3d/lightmapper.h +++ b/scene/3d/lightmapper.h @@ -176,9 +176,9 @@ public: }; virtual void add_mesh(const MeshData &p_mesh) = 0; - virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance) = 0; - virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size) = 0; - virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size) = 0; + virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance, float p_shadow_blur) = 0; + virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) = 0; + virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) = 0; virtual void add_probe(const Vector3 &p_position) = 0; virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr) = 0; diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 6e36815f2b..60858b00b1 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -980,7 +980,7 @@ void Node3D::_bind_methods() { ADD_GROUP("Transform", ""); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NO_EDITOR), "set_transform", "get_transform"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_lesser,noslider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_lesser,no_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion"); ADD_PROPERTY(PropertyInfo(Variant::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis"); diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp index a54e728c1b..e9c33b1839 100644 --- a/scene/debugger/scene_debugger.cpp +++ b/scene/debugger/scene_debugger.cpp @@ -701,7 +701,7 @@ void LiveEditor::_res_set_func(int p_id, const StringName &p_prop, const Variant return; } - Ref<Resource> r = ResourceCache::get(resp); + Ref<Resource> r = ResourceCache::get_ref(resp); if (!r.is_valid()) { return; } @@ -728,7 +728,7 @@ void LiveEditor::_res_call_func(int p_id, const StringName &p_method, const Vari return; } - Ref<Resource> r = ResourceCache::get(resp); + Ref<Resource> r = ResourceCache::get_ref(resp); if (!r.is_valid()) { return; } diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 036d00345d..7b97b0fa47 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -3286,7 +3286,7 @@ void Control::_bind_methods() { ADD_GROUP("Layout", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction"); ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode"); ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION); diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 192d214262..a2b05ee50d 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -262,7 +262,7 @@ Button *AcceptDialog::add_button(const String &p_text, bool p_right, const Strin Button *AcceptDialog::add_cancel_button(const String &p_cancel) { String c = p_cancel; if (p_cancel.is_empty()) { - c = TTRC("Cancel"); + c = RTR("Cancel"); } Button *b = swap_cancel_ok ? add_button(c, true) : add_button(c); b->connect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed)); @@ -349,7 +349,7 @@ AcceptDialog::AcceptDialog() { hbc->add_spacer(); ok = memnew(Button); - ok->set_text(TTRC("OK")); + ok->set_text(RTR("OK")); hbc->add_child(ok); hbc->add_spacer(); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 1725816c31..0e0f8bde83 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -337,7 +337,7 @@ void FileDialog::_action_pressed() { } if (dir_access->file_exists(f)) { - confirm_save->set_text(TTRC("File exists, overwrite?")); + confirm_save->set_text(RTR("File exists, overwrite?")); confirm_save->popup_centered(Size2(200, 80)); } else { emit_signal(SNAME("file_selected"), f); @@ -423,10 +423,10 @@ void FileDialog::deselect_all() { switch (mode) { case FILE_MODE_OPEN_FILE: case FILE_MODE_OPEN_FILES: - get_ok_button()->set_text(TTRC("Open")); + get_ok_button()->set_text(RTR("Open")); break; case FILE_MODE_OPEN_DIR: - get_ok_button()->set_text(TTRC("Select Current Folder")); + get_ok_button()->set_text(RTR("Select Current Folder")); break; case FILE_MODE_OPEN_ANY: case FILE_MODE_SAVE_FILE: @@ -450,7 +450,7 @@ void FileDialog::_tree_selected() { if (!d["dir"]) { file->set_text(d["name"]); } else if (mode == FILE_MODE_OPEN_DIR) { - get_ok_button()->set_text(TTRC("Select This Folder")); + get_ok_button()->set_text(RTR("Select This Folder")); } get_ok_button()->set_disabled(_is_open_should_be_disabled()); @@ -502,7 +502,7 @@ void FileDialog::update_file_list() { if (dir_access->is_readable(dir_access->get_current_dir().utf8().get_data())) { message->hide(); } else { - message->set_text(TTRC("You don't have permission to access contents of this folder.")); + message->set_text(RTR("You don't have permission to access contents of this folder.")); message->show(); } @@ -746,35 +746,35 @@ void FileDialog::set_file_mode(FileMode p_mode) { mode = p_mode; switch (mode) { case FILE_MODE_OPEN_FILE: - get_ok_button()->set_text(TTRC("Open")); + get_ok_button()->set_text(RTR("Open")); if (mode_overrides_title) { set_title(TTRC("Open a File")); } makedir->hide(); break; case FILE_MODE_OPEN_FILES: - get_ok_button()->set_text(TTRC("Open")); + get_ok_button()->set_text(RTR("Open")); if (mode_overrides_title) { set_title(TTRC("Open File(s)")); } makedir->hide(); break; case FILE_MODE_OPEN_DIR: - get_ok_button()->set_text(TTRC("Select Current Folder")); + get_ok_button()->set_text(RTR("Select Current Folder")); if (mode_overrides_title) { set_title(TTRC("Open a Directory")); } makedir->show(); break; case FILE_MODE_OPEN_ANY: - get_ok_button()->set_text(TTRC("Open")); + get_ok_button()->set_text(RTR("Open")); if (mode_overrides_title) { set_title(TTRC("Open a File or Directory")); } makedir->show(); break; case FILE_MODE_SAVE_FILE: - get_ok_button()->set_text(TTRC("Save")); + get_ok_button()->set_text(RTR("Save")); if (mode_overrides_title) { set_title(TTRC("Save a File")); } @@ -964,13 +964,13 @@ FileDialog::FileDialog() { dir_prev = memnew(Button); dir_prev->set_flat(true); - dir_prev->set_tooltip(TTRC("Go to previous folder.")); + dir_prev->set_tooltip(RTR("Go to previous folder.")); dir_next = memnew(Button); dir_next->set_flat(true); - dir_next->set_tooltip(TTRC("Go to next folder.")); + dir_next->set_tooltip(RTR("Go to next folder.")); dir_up = memnew(Button); dir_up->set_flat(true); - dir_up->set_tooltip(TTRC("Go to parent folder.")); + dir_up->set_tooltip(RTR("Go to parent folder.")); hbc->add_child(dir_prev); hbc->add_child(dir_next); hbc->add_child(dir_up); @@ -978,7 +978,7 @@ FileDialog::FileDialog() { dir_next->connect("pressed", callable_mp(this, &FileDialog::_go_forward)); dir_up->connect("pressed", callable_mp(this, &FileDialog::_go_up)); - hbc->add_child(memnew(Label(TTRC("Path:")))); + hbc->add_child(memnew(Label(RTR("Path:")))); drives_container = memnew(HBoxContainer); hbc->add_child(drives_container); @@ -994,7 +994,7 @@ FileDialog::FileDialog() { refresh = memnew(Button); refresh->set_flat(true); - refresh->set_tooltip(TTRC("Refresh files.")); + refresh->set_tooltip(RTR("Refresh files.")); refresh->connect("pressed", callable_mp(this, &FileDialog::update_file_list)); hbc->add_child(refresh); @@ -1002,7 +1002,7 @@ FileDialog::FileDialog() { show_hidden->set_flat(true); show_hidden->set_toggle_mode(true); show_hidden->set_pressed(is_showing_hidden_files()); - show_hidden->set_tooltip(TTRC("Toggle the visibility of hidden files.")); + show_hidden->set_tooltip(RTR("Toggle the visibility of hidden files.")); show_hidden->connect("toggled", callable_mp(this, &FileDialog::set_show_hidden_files)); hbc->add_child(show_hidden); @@ -1010,14 +1010,14 @@ FileDialog::FileDialog() { hbc->add_child(shortcuts_container); makedir = memnew(Button); - makedir->set_text(TTRC("Create Folder")); + makedir->set_text(RTR("Create Folder")); makedir->connect("pressed", callable_mp(this, &FileDialog::_make_dir)); hbc->add_child(makedir); vbox->add_child(hbc); tree = memnew(Tree); tree->set_hide_root(true); - vbox->add_margin_child(TTRC("Directories & Files:"), tree, true); + vbox->add_margin_child(RTR("Directories & Files:"), tree, true); message = memnew(Label); message->hide(); @@ -1027,7 +1027,7 @@ FileDialog::FileDialog() { tree->add_child(message); file_box = memnew(HBoxContainer); - file_box->add_child(memnew(Label(TTRC("File:")))); + file_box->add_child(memnew(Label(RTR("File:")))); file = memnew(LineEdit); file->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE); file->set_stretch_ratio(4); @@ -1058,22 +1058,22 @@ FileDialog::FileDialog() { confirm_save->connect("confirmed", callable_mp(this, &FileDialog::_save_confirm_pressed)); makedialog = memnew(ConfirmationDialog); - makedialog->set_title(TTRC("Create Folder")); + makedialog->set_title(RTR("Create Folder")); VBoxContainer *makevb = memnew(VBoxContainer); makedialog->add_child(makevb); makedirname = memnew(LineEdit); makedirname->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE); - makevb->add_margin_child(TTRC("Name:"), makedirname); + makevb->add_margin_child(RTR("Name:"), makedirname); add_child(makedialog, false, INTERNAL_MODE_FRONT); makedialog->register_text_enter(makedirname); makedialog->connect("confirmed", callable_mp(this, &FileDialog::_make_dir_confirm)); mkdirerr = memnew(AcceptDialog); - mkdirerr->set_text(TTRC("Could not create folder.")); + mkdirerr->set_text(RTR("Could not create folder.")); add_child(mkdirerr, false, INTERNAL_MODE_FRONT); exterr = memnew(AcceptDialog); - exterr->set_text(TTRC("Must use a valid extension.")); + exterr->set_text(RTR("Must use a valid extension.")); add_child(exterr, false, INTERNAL_MODE_FRONT); update_filters(); diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp index f36682942f..80859e8eb9 100644 --- a/scene/gui/progress_bar.cpp +++ b/scene/gui/progress_bar.cpp @@ -126,7 +126,11 @@ int ProgressBar::get_fill_mode() { } void ProgressBar::set_percent_visible(bool p_visible) { + if (percent_visible == p_visible) { + return; + } percent_visible = p_visible; + update_minimum_size(); update(); } diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 8299d73b68..fa929344d4 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -727,6 +727,7 @@ void TabContainer::set_tab_hidden(int p_tab, bool p_hidden) { if (!get_clip_tabs()) { update_minimum_size(); } + call_deferred(SNAME("_repaint")); } bool TabContainer::is_tab_hidden(int p_tab) const { diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index d9a91590f7..5506616b7a 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1723,7 +1723,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { update(); } - } else if (is_mouse_over_selection()) { + } else if (drag_and_drop_selection_enabled && is_mouse_over_selection()) { selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE; selection.drag_attempt = true; } else { @@ -4163,6 +4163,14 @@ bool TextEdit::is_deselect_on_focus_loss_enabled() const { return deselect_on_focus_loss_enabled; } +void TextEdit::set_drag_and_drop_selection_enabled(const bool p_enabled) { + drag_and_drop_selection_enabled = p_enabled; +} + +bool TextEdit::is_drag_and_drop_selection_enabled() const { + return drag_and_drop_selection_enabled; +} + void TextEdit::set_override_selected_font_color(bool p_override_selected_font_color) { override_selected_font_color = p_override_selected_font_color; } @@ -5243,6 +5251,9 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_deselect_on_focus_loss_enabled", "enable"), &TextEdit::set_deselect_on_focus_loss_enabled); ClassDB::bind_method(D_METHOD("is_deselect_on_focus_loss_enabled"), &TextEdit::is_deselect_on_focus_loss_enabled); + ClassDB::bind_method(D_METHOD("set_drag_and_drop_selection_enabled", "enable"), &TextEdit::set_drag_and_drop_selection_enabled); + ClassDB::bind_method(D_METHOD("is_drag_and_drop_selection_enabled"), &TextEdit::is_drag_and_drop_selection_enabled); + ClassDB::bind_method(D_METHOD("set_override_selected_font_color", "override"), &TextEdit::set_override_selected_font_color); ClassDB::bind_method(D_METHOD("is_overriding_selected_font_color"), &TextEdit::is_overriding_selected_font_color); @@ -5405,6 +5416,7 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_and_drop_selection_enabled"), "set_drag_and_drop_selection_enabled", "is_drag_and_drop_selection_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_mode", PROPERTY_HINT_ENUM, "None,Boundary"), "set_line_wrapping_mode", "get_line_wrapping_mode"); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 993203bee6..9de2982d0a 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -422,6 +422,7 @@ private: bool selecting_enabled = true; bool deselect_on_focus_loss_enabled = true; + bool drag_and_drop_selection_enabled = true; Color font_selected_color = Color(1, 1, 1); Color selection_color = Color(1, 1, 1); @@ -795,6 +796,9 @@ public: void set_deselect_on_focus_loss_enabled(const bool p_enabled); bool is_deselect_on_focus_loss_enabled() const; + void set_drag_and_drop_selection_enabled(const bool p_enabled); + bool is_drag_and_drop_selection_enabled() const; + void set_override_selected_font_color(bool p_override_selected_font_color); bool is_overriding_selected_font_color() const; diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index 1ecdd4d9d1..96cf7bb708 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -54,12 +54,12 @@ void Curve::set_point_count(int p_count) { if (_points.size() >= p_count) { _points.resize(p_count); mark_dirty(); - notify_property_list_changed(); } else { for (int i = p_count - _points.size(); i > 0; i--) { - add_point(Vector2()); + _add_point(Vector2()); } } + notify_property_list_changed(); } int Curve::_add_point(Vector2 p_position, real_t p_left_tangent, real_t p_right_tangent, TangentMode p_left_mode, TangentMode p_right_mode) { @@ -650,16 +650,15 @@ void Curve2D::set_point_count(int p_count) { if (points.size() >= p_count) { points.resize(p_count); mark_dirty(); - baked_cache_dirty = true; - emit_signal(CoreStringNames::get_singleton()->changed); } else { for (int i = p_count - points.size(); i > 0; i--) { - add_point(Vector2()); + _add_point(Vector2()); } } + notify_property_list_changed(); } -void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) { +void Curve2D::_add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) { Point n; n.position = p_position; n.in = p_in; @@ -673,6 +672,11 @@ void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Ve mark_dirty(); } +void Curve2D::add_point(const Vector2 &p_position, const Vector2 &p_in, const Vector2 &p_out, int p_atpos) { + _add_point(p_position, p_in, p_out, p_atpos); + notify_property_list_changed(); +} + void Curve2D::set_point_position(int p_index, const Vector2 &p_position) { ERR_FAIL_INDEX(p_index, points.size()); @@ -709,16 +713,22 @@ Vector2 Curve2D::get_point_out(int p_index) const { return points[p_index].out; } -void Curve2D::remove_point(int p_index) { +void Curve2D::_remove_point(int p_index) { ERR_FAIL_INDEX(p_index, points.size()); points.remove_at(p_index); mark_dirty(); } +void Curve2D::remove_point(int p_index) { + _remove_point(p_index); + notify_property_list_changed(); +} + void Curve2D::clear_points() { if (!points.is_empty()) { points.clear(); mark_dirty(); + notify_property_list_changed(); } } @@ -753,7 +763,6 @@ Vector2 Curve2D::interpolatef(real_t p_findex) const { void Curve2D::mark_dirty() { baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); - notify_property_list_changed(); } void Curve2D::_bake_segment2d(RBMap<real_t, Vector2> &r_bake, real_t p_begin, real_t p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, real_t p_tol) const { @@ -1068,7 +1077,8 @@ void Curve2D::_set_data(const Dictionary &p_data) { points.write[i].position = r[i * 3 + 2]; } - baked_cache_dirty = true; + mark_dirty(); + notify_property_list_changed(); } PackedVector2Array Curve2D::tessellate(int p_max_stages, real_t p_tolerance) const { @@ -1219,12 +1229,13 @@ void Curve3D::set_point_count(int p_count) { mark_dirty(); } else { for (int i = p_count - points.size(); i > 0; i--) { - add_point(Vector3()); + _add_point(Vector3()); } } + notify_property_list_changed(); } -void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) { +void Curve3D::_add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) { Point n; n.position = p_position; n.in = p_in; @@ -1238,6 +1249,11 @@ void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Ve mark_dirty(); } +void Curve3D::add_point(const Vector3 &p_position, const Vector3 &p_in, const Vector3 &p_out, int p_atpos) { + _add_point(p_position, p_in, p_out, p_atpos); + notify_property_list_changed(); +} + void Curve3D::set_point_position(int p_index, const Vector3 &p_position) { ERR_FAIL_INDEX(p_index, points.size()); @@ -1286,16 +1302,22 @@ Vector3 Curve3D::get_point_out(int p_index) const { return points[p_index].out; } -void Curve3D::remove_point(int p_index) { +void Curve3D::_remove_point(int p_index) { ERR_FAIL_INDEX(p_index, points.size()); points.remove_at(p_index); mark_dirty(); } +void Curve3D::remove_point(int p_index) { + _remove_point(p_index); + notify_property_list_changed(); +} + void Curve3D::clear_points() { if (!points.is_empty()) { points.clear(); mark_dirty(); + notify_property_list_changed(); } } @@ -1330,7 +1352,6 @@ Vector3 Curve3D::interpolatef(real_t p_findex) const { void Curve3D::mark_dirty() { baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); - notify_property_list_changed(); } void Curve3D::_bake_segment3d(RBMap<real_t, Vector3> &r_bake, real_t p_begin, real_t p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, real_t p_tol) const { @@ -1853,7 +1874,8 @@ void Curve3D::_set_data(const Dictionary &p_data) { points.write[i].tilt = rt[i]; } - baked_cache_dirty = true; + mark_dirty(); + notify_property_list_changed(); } PackedVector3Array Curve3D::tessellate(int p_max_stages, real_t p_tolerance) const { diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 862a60f464..08807b1b6e 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -189,6 +189,9 @@ class Curve2D : public Resource { bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + void _add_point(const Vector2 &p_position, const Vector2 &p_in = Vector2(), const Vector2 &p_out = Vector2(), int p_atpos = -1); + void _remove_point(int p_index); + protected: static void _bind_methods(); @@ -261,6 +264,9 @@ class Curve3D : public Resource { bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + void _add_point(const Vector3 &p_position, const Vector3 &p_in = Vector3(), const Vector3 &p_out = Vector3(), int p_atpos = -1); + void _remove_point(int p_index); + protected: static void _bind_methods(); diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index 784ecc3a4d..a808ead66b 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -272,6 +272,24 @@ bool NavigationMesh::get_filter_walkable_low_height_spans() const { return filter_walkable_low_height_spans; } +void NavigationMesh::set_filter_baking_aabb(const AABB &p_aabb) { + filter_baking_aabb = p_aabb; + notify_property_list_changed(); +} + +AABB NavigationMesh::get_filter_baking_aabb() const { + return filter_baking_aabb; +} + +void NavigationMesh::set_filter_baking_aabb_offset(const Vector3 &p_aabb_offset) { + filter_baking_aabb_offset = p_aabb_offset; + notify_property_list_changed(); +} + +Vector3 NavigationMesh::get_filter_baking_aabb_offset() const { + return filter_baking_aabb_offset; +} + void NavigationMesh::set_vertices(const Vector<Vector3> &p_vertices) { vertices = p_vertices; notify_property_list_changed(); @@ -469,6 +487,10 @@ void NavigationMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_filter_walkable_low_height_spans", "filter_walkable_low_height_spans"), &NavigationMesh::set_filter_walkable_low_height_spans); ClassDB::bind_method(D_METHOD("get_filter_walkable_low_height_spans"), &NavigationMesh::get_filter_walkable_low_height_spans); + ClassDB::bind_method(D_METHOD("set_filter_baking_aabb", "baking_aabb"), &NavigationMesh::set_filter_baking_aabb); + ClassDB::bind_method(D_METHOD("get_filter_baking_aabb"), &NavigationMesh::get_filter_baking_aabb); + ClassDB::bind_method(D_METHOD("set_filter_baking_aabb_offset", "baking_aabb_offset"), &NavigationMesh::set_filter_baking_aabb_offset); + ClassDB::bind_method(D_METHOD("get_filter_baking_aabb_offset"), &NavigationMesh::get_filter_baking_aabb_offset); ClassDB::bind_method(D_METHOD("set_vertices", "vertices"), &NavigationMesh::set_vertices); ClassDB::bind_method(D_METHOD("get_vertices"), &NavigationMesh::get_vertices); @@ -516,6 +538,8 @@ void NavigationMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_low_hanging_obstacles"), "set_filter_low_hanging_obstacles", "get_filter_low_hanging_obstacles"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_ledge_spans"), "set_filter_ledge_spans", "get_filter_ledge_spans"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "filter_walkable_low_height_spans"), "set_filter_walkable_low_height_spans", "get_filter_walkable_low_height_spans"); + ADD_PROPERTY(PropertyInfo(Variant::AABB, "filter_baking_aabb"), "set_filter_baking_aabb", "get_filter_baking_aabb"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "filter_baking_aabb_offset"), "set_filter_baking_aabb_offset", "get_filter_baking_aabb_offset"); BIND_ENUM_CONSTANT(SAMPLE_PARTITION_WATERSHED); BIND_ENUM_CONSTANT(SAMPLE_PARTITION_MONOTONE); diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h index 93c1c11876..40b275c792 100644 --- a/scene/resources/navigation_mesh.h +++ b/scene/resources/navigation_mesh.h @@ -117,6 +117,8 @@ protected: bool filter_low_hanging_obstacles = false; bool filter_ledge_spans = false; bool filter_walkable_low_height_spans = false; + AABB filter_baking_aabb; + Vector3 filter_baking_aabb_offset; public: // Recast settings @@ -186,6 +188,12 @@ public: void set_filter_walkable_low_height_spans(bool p_value); bool get_filter_walkable_low_height_spans() const; + void set_filter_baking_aabb(const AABB &p_aabb); + AABB get_filter_baking_aabb() const; + + void set_filter_baking_aabb_offset(const Vector3 &p_aabb_offset); + Vector3 get_filter_baking_aabb_offset() const; + void create_from_mesh(const Ref<Mesh> &p_mesh); void set_vertices(const Vector<Vector3> &p_vertices); diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index b2fd8eb895..f4fd81b25f 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -439,12 +439,15 @@ void CapsuleMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_height", "get_height"); ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings"); + + ADD_LINKED_PROPERTY("radius", "height"); + ADD_LINKED_PROPERTY("height", "radius"); } void CapsuleMesh::set_radius(const float p_radius) { radius = p_radius; if (radius > height * 0.5) { - radius = height * 0.5; + height = radius * 2.0; } _request_update(); } @@ -456,7 +459,7 @@ float CapsuleMesh::get_radius() const { void CapsuleMesh::set_height(const float p_height) { height = p_height; if (radius > height * 0.5) { - height = radius * 2; + radius = height * 0.5; } _request_update(); } diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 217b7d6d1a..66afb001fb 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -536,9 +536,9 @@ Error ResourceLoaderText::load() { if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) { //reuse existing - Resource *r = ResourceCache::get(path); - if (r && r->get_class() == type) { - res = Ref<Resource>(r); + Ref<Resource> cache = ResourceCache::get_ref(path); + if (cache.is_valid() && cache->get_class() == type) { + res = cache; res->reset_state(); do_assign = true; } @@ -547,10 +547,10 @@ Error ResourceLoaderText::load() { MissingResource *missing_resource = nullptr; if (res.is_null()) { //not reuse - if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && ResourceCache::has(path)) { //only if it doesn't exist + Ref<Resource> cache = ResourceCache::get_ref(path); + if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && cache.is_valid()) { //only if it doesn't exist //cached, do not assign - Resource *r = ResourceCache::get(path); - res = Ref<Resource>(r); + res = cache; } else { //create @@ -660,12 +660,10 @@ Error ResourceLoaderText::load() { return error; } - if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(local_path)) { - Resource *r = ResourceCache::get(local_path); - if (r->get_class() == res_type) { - r->reset_state(); - resource = Ref<Resource>(r); - } + Ref<Resource> cache = ResourceCache::get_ref(local_path); + if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && cache.is_valid() && cache->get_class() == res_type) { + cache->reset_state(); + resource = cache; } MissingResource *missing_resource = nullptr; diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp index 0442089503..5e9f1c824a 100644 --- a/servers/navigation_server_2d.cpp +++ b/servers/navigation_server_2d.cpp @@ -159,6 +159,8 @@ void NavigationServer2D::_emit_map_changed(RID p_map) { } void NavigationServer2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_maps"), &NavigationServer2D::get_maps); + ClassDB::bind_method(D_METHOD("map_create"), &NavigationServer2D::map_create); ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &NavigationServer2D::map_set_active); ClassDB::bind_method(D_METHOD("map_is_active", "nap"), &NavigationServer2D::map_is_active); @@ -173,11 +175,14 @@ void NavigationServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("map_get_regions", "map"), &NavigationServer2D::map_get_regions); ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer2D::map_get_agents); + ClassDB::bind_method(D_METHOD("map_force_update", "map"), &NavigationServer2D::map_force_update); + ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer2D::region_create); ClassDB::bind_method(D_METHOD("region_set_enter_cost", "region", "enter_cost"), &NavigationServer2D::region_set_enter_cost); ClassDB::bind_method(D_METHOD("region_get_enter_cost", "region"), &NavigationServer2D::region_get_enter_cost); ClassDB::bind_method(D_METHOD("region_set_travel_cost", "region", "travel_cost"), &NavigationServer2D::region_set_travel_cost); ClassDB::bind_method(D_METHOD("region_get_travel_cost", "region"), &NavigationServer2D::region_get_travel_cost); + ClassDB::bind_method(D_METHOD("region_owns_point", "region", "point"), &NavigationServer2D::region_owns_point); ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer2D::region_set_map); ClassDB::bind_method(D_METHOD("region_get_map", "region"), &NavigationServer2D::region_get_map); ClassDB::bind_method(D_METHOD("region_set_navigation_layers", "region", "navigation_layers"), &NavigationServer2D::region_set_navigation_layers); @@ -217,6 +222,8 @@ NavigationServer2D::~NavigationServer2D() { singleton = nullptr; } +Array FORWARD_0_C(get_maps); + Array FORWARD_1_C(map_get_regions, RID, p_map, rid_to_rid); Array FORWARD_1_C(map_get_agents, RID, p_map, rid_to_rid); @@ -231,6 +238,10 @@ void FORWARD_2_C(map_set_active, RID, p_map, bool, p_active, rid_to_rid, bool_to bool FORWARD_1_C(map_is_active, RID, p_map, rid_to_rid); +void NavigationServer2D::map_force_update(RID p_map) { + NavigationServer3D::get_singleton_mut()->map_force_update(p_map); +} + void FORWARD_2_C(map_set_cell_size, RID, p_map, real_t, p_cell_size, rid_to_rid, real_to_real); real_t FORWARD_1_C(map_get_cell_size, RID, p_map, rid_to_rid); @@ -248,6 +259,7 @@ void FORWARD_2_C(region_set_enter_cost, RID, p_region, real_t, p_enter_cost, rid real_t FORWARD_1_C(region_get_enter_cost, RID, p_region, rid_to_rid); void FORWARD_2_C(region_set_travel_cost, RID, p_region, real_t, p_travel_cost, rid_to_rid, real_to_real); real_t FORWARD_1_C(region_get_travel_cost, RID, p_region, rid_to_rid); +bool FORWARD_2_C(region_owns_point, RID, p_region, const Vector2 &, p_point, rid_to_rid, v2_to_v3); void FORWARD_2_C(region_set_map, RID, p_region, RID, p_map, rid_to_rid, rid_to_rid); void FORWARD_2_C(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers, rid_to_rid, uint32_to_uint32); diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h index 30f553d10b..1b15c7ff37 100644 --- a/servers/navigation_server_2d.h +++ b/servers/navigation_server_2d.h @@ -53,6 +53,8 @@ public: /// MUST be used in single thread! static NavigationServer2D *get_singleton_mut() { return singleton; } + virtual Array get_maps() const; + /// Create a new map. virtual RID map_create() const; @@ -83,6 +85,8 @@ public: virtual Array map_get_regions(RID p_map) const; virtual Array map_get_agents(RID p_map) const; + virtual void map_force_update(RID p_map); + /// Creates a new region. virtual RID region_create() const; @@ -94,6 +98,8 @@ public: virtual void region_set_travel_cost(RID p_region, real_t p_travel_cost) const; virtual real_t region_get_travel_cost(RID p_region) const; + virtual bool region_owns_point(RID p_region, const Vector2 &p_point) const; + /// Set the map of this region. virtual void region_set_map(RID p_region, RID p_map) const; virtual RID region_get_map(RID p_region) const; diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 60bbcec8d4..6c48c4a8de 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -33,6 +33,8 @@ NavigationServer3D *NavigationServer3D::singleton = nullptr; void NavigationServer3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_maps"), &NavigationServer3D::get_maps); + ClassDB::bind_method(D_METHOD("map_create"), &NavigationServer3D::map_create); ClassDB::bind_method(D_METHOD("map_set_active", "map", "active"), &NavigationServer3D::map_set_active); ClassDB::bind_method(D_METHOD("map_is_active", "nap"), &NavigationServer3D::map_is_active); @@ -51,11 +53,14 @@ void NavigationServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("map_get_regions", "map"), &NavigationServer3D::map_get_regions); ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer3D::map_get_agents); + ClassDB::bind_method(D_METHOD("map_force_update", "map"), &NavigationServer3D::map_force_update); + ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer3D::region_create); ClassDB::bind_method(D_METHOD("region_set_enter_cost", "region", "enter_cost"), &NavigationServer3D::region_set_enter_cost); ClassDB::bind_method(D_METHOD("region_get_enter_cost", "region"), &NavigationServer3D::region_get_enter_cost); ClassDB::bind_method(D_METHOD("region_set_travel_cost", "region", "travel_cost"), &NavigationServer3D::region_set_travel_cost); ClassDB::bind_method(D_METHOD("region_get_travel_cost", "region"), &NavigationServer3D::region_get_travel_cost); + ClassDB::bind_method(D_METHOD("region_owns_point", "region", "point"), &NavigationServer3D::region_owns_point); ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer3D::region_set_map); ClassDB::bind_method(D_METHOD("region_get_map", "region"), &NavigationServer3D::region_get_map); ClassDB::bind_method(D_METHOD("region_set_navigation_layers", "region", "navigation_layers"), &NavigationServer3D::region_set_navigation_layers); diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index 9c04d68622..cf91596604 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -56,6 +56,8 @@ public: /// MUST be used in single thread! static NavigationServer3D *get_singleton_mut(); + virtual Array get_maps() const = 0; + /// Create a new map. virtual RID map_create() const = 0; @@ -94,6 +96,8 @@ public: virtual Array map_get_regions(RID p_map) const = 0; virtual Array map_get_agents(RID p_map) const = 0; + virtual void map_force_update(RID p_map) = 0; + /// Creates a new region. virtual RID region_create() const = 0; @@ -105,6 +109,8 @@ public: virtual void region_set_travel_cost(RID p_region, real_t p_travel_cost) const = 0; virtual real_t region_get_travel_cost(RID p_region) const = 0; + virtual bool region_owns_point(RID p_region, const Vector3 &p_point) const = 0; + /// Set the map of this region. virtual void region_set_map(RID p_region, RID p_map) const = 0; virtual RID region_get_map(RID p_region) const = 0; diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp index 6b786fdf16..c30e8ed58f 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.cpp +++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp @@ -29,9 +29,11 @@ /*************************************************************************/ #include "copy_effects.h" +#include "core/config/project_settings.h" #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #include "servers/rendering/renderer_rd/storage_rd/material_storage.h" #include "servers/rendering/renderer_rd/uniform_set_cache_rd.h" +#include "thirdparty/misc/cubemap_coeffs.h" using namespace RendererRD; @@ -123,16 +125,157 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) { } } } + + { + // Initialize copier + Vector<String> copy_modes; + copy_modes.push_back("\n"); + + cube_to_dp.shader.initialize(copy_modes); + + cube_to_dp.shader_version = cube_to_dp.shader.version_create(); + RID shader = cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0); + RD::PipelineDepthStencilState dss; + dss.enable_depth_test = true; + dss.depth_compare_operator = RD::COMPARE_OP_ALWAYS; + dss.enable_depth_write = true; + cube_to_dp.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), dss, RD::PipelineColorBlendState(), 0); + } + + { + //Initialize cubemap downsampler + Vector<String> cubemap_downsampler_modes; + cubemap_downsampler_modes.push_back(""); + + if (prefer_raster_effects) { + cubemap_downsampler.raster_shader.initialize(cubemap_downsampler_modes); + + cubemap_downsampler.shader_version = cubemap_downsampler.raster_shader.version_create(); + + cubemap_downsampler.raster_pipeline.setup(cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } else { + cubemap_downsampler.compute_shader.initialize(cubemap_downsampler_modes); + + cubemap_downsampler.shader_version = cubemap_downsampler.compute_shader.version_create(); + + cubemap_downsampler.compute_pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0)); + cubemap_downsampler.raster_pipeline.clear(); + } + } + + { + // Initialize cubemap filter + filter.use_high_quality = GLOBAL_GET("rendering/reflections/sky_reflections/fast_filter_high_quality"); + + Vector<String> cubemap_filter_modes; + cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n"); + cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n"); + cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n#define USE_TEXTURE_ARRAY\n"); + cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n#define USE_TEXTURE_ARRAY\n"); + + if (filter.use_high_quality) { + filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs)); + RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(high_quality_coeffs), &high_quality_coeffs[0]); + } else { + filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(low_quality_coeffs)); + RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0]); + } + + if (prefer_raster_effects) { + filter.raster_shader.initialize(cubemap_filter_modes); + + // array variants are not supported in raster + filter.raster_shader.set_variant_enabled(FILTER_MODE_HIGH_QUALITY_ARRAY, false); + filter.raster_shader.set_variant_enabled(FILTER_MODE_LOW_QUALITY_ARRAY, false); + + filter.shader_version = filter.raster_shader.version_create(); + + for (int i = 0; i < FILTER_MODE_MAX; i++) { + if (filter.raster_shader.is_variant_enabled(i)) { + filter.raster_pipelines[i].setup(filter.raster_shader.version_get_shader(filter.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + } else { + filter.raster_pipelines[i].clear(); + } + } + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.append_id(filter.coefficient_buffer); + uniforms.push_back(u); + } + filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.raster_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1); + } else { + filter.compute_shader.initialize(cubemap_filter_modes); + filter.shader_version = filter.compute_shader.version_create(); + + for (int i = 0; i < FILTER_MODE_MAX; i++) { + filter.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.compute_shader.version_get_shader(filter.shader_version, i)); + filter.raster_pipelines[i].clear(); + } + + Vector<RD::Uniform> uniforms; + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 0; + u.append_id(filter.coefficient_buffer); + uniforms.push_back(u); + } + filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1); + } + } + + { + // Initialize roughness + Vector<String> cubemap_roughness_modes; + cubemap_roughness_modes.push_back(""); + + if (prefer_raster_effects) { + roughness.raster_shader.initialize(cubemap_roughness_modes); + + roughness.shader_version = roughness.raster_shader.version_create(); + + roughness.raster_pipeline.setup(roughness.raster_shader.version_get_shader(roughness.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); + + } else { + roughness.compute_shader.initialize(cubemap_roughness_modes); + + roughness.shader_version = roughness.compute_shader.version_create(); + + roughness.compute_pipeline = RD::get_singleton()->compute_pipeline_create(roughness.compute_shader.version_get_shader(roughness.shader_version, 0)); + roughness.raster_pipeline.clear(); + } + } } CopyEffects::~CopyEffects() { if (prefer_raster_effects) { blur_raster.shader.version_free(blur_raster.shader_version); + cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version); + filter.raster_shader.version_free(filter.shader_version); + roughness.raster_shader.version_free(roughness.shader_version); } else { copy.shader.version_free(copy.shader_version); + cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version); + filter.compute_shader.version_free(filter.shader_version); + roughness.compute_shader.version_free(roughness.shader_version); + } + + RD::get_singleton()->free(filter.coefficient_buffer); + + if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) { + RD::get_singleton()->free(filter.image_uniform_set); + } + + if (RD::get_singleton()->uniform_set_is_valid(filter.uniform_set)) { + RD::get_singleton()->free(filter.uniform_set); } copy_to_fb.shader.version_free(copy_to_fb.shader_version); + cube_to_dp.shader.version_free(cube_to_dp.shader_version); singleton = nullptr; } @@ -681,3 +824,262 @@ void CopyEffects::set_color(RID p_dest_texture, const Color &p_color, const Rect RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_region.size.width, p_region.size.height, 1); RD::get_singleton()->compute_list_end(); } + +void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip) { + UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); + ERR_FAIL_NULL(uniform_set_cache); + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + + CopyToDPPushConstant push_constant; + push_constant.screen_rect[0] = p_rect.position.x; + push_constant.screen_rect[1] = p_rect.position.y; + push_constant.screen_rect[2] = p_rect.size.width; + push_constant.screen_rect[3] = p_rect.size.height; + push_constant.z_far = p_z_far; + push_constant.z_near = p_z_near; + push_constant.texel_size[0] = 1.0f / p_dst_size.x; + push_constant.texel_size[1] = 1.0f / p_dst_size.y; + push_constant.texel_size[0] *= p_dp_flip ? -1.0f : 1.0f; // Encode dp flip as x size sign + + // setup our uniforms + RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + + RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_rd_texture })); + + RID shader = cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0); + ERR_FAIL_COND(shader.is_null()); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_dp.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CopyToDPPushConstant)); + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_TRANSFER); +} + +void CopyEffects::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) { + ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap downsample with the mobile renderer."); + + UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); + ERR_FAIL_NULL(uniform_set_cache); + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + + cubemap_downsampler.push_constant.face_size = p_size.x; + cubemap_downsampler.push_constant.face_id = 0; // we render all 6 sides to each layer in one call + + // setup our uniforms + RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + + RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_cubemap })); + RD::Uniform u_dest_cubemap(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_dest_cubemap })); + + RID shader = cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0); + ERR_FAIL_COND(shader.is_null()); + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.compute_pipeline); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_cubemap), 1); + + int x_groups = (p_size.x - 1) / 8 + 1; + int y_groups = (p_size.y - 1) / 8 + 1; + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant)); + + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 6); // one z_group for each face + + RD::get_singleton()->compute_list_end(); +} + +void CopyEffects::cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size) { + ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap downsample with the clustered renderer."); + ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap downsample must process one side at a time."); + + UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); + ERR_FAIL_NULL(uniform_set_cache); + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + + cubemap_downsampler.push_constant.face_size = p_size.x; + cubemap_downsampler.push_constant.face_id = p_face_id; + + // setup our uniforms + RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + + RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_cubemap })); + + RID shader = cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0); + ERR_FAIL_COND(shader.is_null()); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cubemap_downsampler.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + +void CopyEffects::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) { + ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap filter with the mobile renderer."); + + UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); + ERR_FAIL_NULL(uniform_set_cache); + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + + Vector<RD::Uniform> uniforms; + for (int i = 0; i < p_dest_cubemap.size(); i++) { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = i; + u.append_id(p_dest_cubemap[i]); + uniforms.push_back(u); + } + if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) { + RD::get_singleton()->free(filter.image_uniform_set); + } + filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, 0), 2); + + // setup our uniforms + RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + + RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_mipmap_sampler, p_source_cubemap })); + + int mode = p_use_array ? FILTER_MODE_HIGH_QUALITY_ARRAY : FILTER_MODE_HIGH_QUALITY; + mode = filter.use_high_quality ? mode : mode + 1; + + RID shader = filter.compute_shader.version_get_shader(filter.shader_version, mode); + ERR_FAIL_COND(shader.is_null()); + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.compute_pipelines[mode]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2); + + int x_groups = p_use_array ? 1792 : 342; // (128 * 128 * 7) / 64 : (128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) / 64 + + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, 6, 1); // one y_group for each face + + RD::get_singleton()->compute_list_end(); +} + +void CopyEffects::cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level) { + ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap filter with the clustered renderer."); + ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap filter must process one side at a time."); + + UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); + ERR_FAIL_NULL(uniform_set_cache); + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + + // TODO implement! + CubemapFilterRasterPushConstant push_constant; + push_constant.mip_level = p_mip_level; + push_constant.face_id = p_face_id; + + // setup our uniforms + RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + + RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_mipmap_sampler, p_source_cubemap })); + + CubemapFilterMode mode = filter.use_high_quality ? FILTER_MODE_HIGH_QUALITY : FILTER_MODE_LOW_QUALITY; + + RID shader = filter.raster_shader.version_get_shader(filter.shader_version, mode); + ERR_FAIL_COND(shader.is_null()); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, filter.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, filter.uniform_set, 1); + RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CubemapFilterRasterPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} + +void CopyEffects::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { + ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap roughness with the mobile renderer."); + + UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); + ERR_FAIL_NULL(uniform_set_cache); + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + + memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant)); + + roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id; + roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in. + roughness.push_constant.sample_count = p_sample_count; + roughness.push_constant.use_direct_write = p_roughness == 0.0; + roughness.push_constant.face_size = p_size; + + // setup our uniforms + RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + + RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_mipmap_sampler, p_source_rd_texture })); + RD::Uniform u_dest_texture(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_dest_texture })); + + RID shader = roughness.compute_shader.version_get_shader(roughness.shader_version, 0); + ERR_FAIL_COND(shader.is_null()); + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.compute_pipeline); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_texture), 1); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); + + int x_groups = (p_size - 1) / 8 + 1; + int y_groups = (p_size - 1) / 8 + 1; + + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, p_face_id > 9 ? 6 : 1); + + RD::get_singleton()->compute_list_end(); +} + +void CopyEffects::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { + ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap roughness with the clustered renderer."); + ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap roughness must process one side at a time."); + + UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); + ERR_FAIL_NULL(uniform_set_cache); + MaterialStorage *material_storage = MaterialStorage::get_singleton(); + ERR_FAIL_NULL(material_storage); + + memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant)); + + roughness.push_constant.face_id = p_face_id; + roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in. + roughness.push_constant.sample_count = p_sample_count; + roughness.push_constant.use_direct_write = p_roughness == 0.0; + roughness.push_constant.face_size = p_size; + + // setup our uniforms + RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + + RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_rd_texture })); + + RID shader = roughness.raster_shader.version_get_shader(roughness.shader_version, 0); + ERR_FAIL_COND(shader.is_null()); + + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); + RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); + RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); + + RD::get_singleton()->draw_list_set_push_constant(draw_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); + + RD::get_singleton()->draw_list_draw(draw_list, true); + RD::get_singleton()->draw_list_end(); +} diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h index e522408d20..882b446964 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.h +++ b/servers/rendering/renderer_rd/effects/copy_effects.h @@ -35,6 +35,13 @@ #include "servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/effects/copy.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl.gen.h" #include "servers/rendering/renderer_scene_render.h" #include "servers/rendering_server.h" @@ -189,6 +196,84 @@ private: } copy_to_fb; + // Copy to DP + + struct CopyToDPPushConstant { + float z_far; + float z_near; + float texel_size[2]; + float screen_rect[4]; + }; + + struct CopyToDP { + CubeToDpShaderRD shader; + RID shader_version; + PipelineCacheRD pipeline; + } cube_to_dp; + + // Cubemap effects + + struct CubemapDownsamplerPushConstant { + uint32_t face_size; + uint32_t face_id; + float pad[2]; + }; + + struct CubemapDownsampler { + CubemapDownsamplerPushConstant push_constant; + CubemapDownsamplerShaderRD compute_shader; + CubemapDownsamplerRasterShaderRD raster_shader; + RID shader_version; + RID compute_pipeline; + PipelineCacheRD raster_pipeline; + } cubemap_downsampler; + + enum CubemapFilterMode { + FILTER_MODE_HIGH_QUALITY, + FILTER_MODE_LOW_QUALITY, + FILTER_MODE_HIGH_QUALITY_ARRAY, + FILTER_MODE_LOW_QUALITY_ARRAY, + FILTER_MODE_MAX, + }; + + struct CubemapFilterRasterPushConstant { + uint32_t mip_level; + uint32_t face_id; + float pad[2]; + }; + + struct CubemapFilter { + CubemapFilterShaderRD compute_shader; + CubemapFilterRasterShaderRD raster_shader; + RID shader_version; + RID compute_pipelines[FILTER_MODE_MAX]; + PipelineCacheRD raster_pipelines[FILTER_MODE_MAX]; + + RID uniform_set; + RID image_uniform_set; + RID coefficient_buffer; + bool use_high_quality; + + } filter; + + struct CubemapRoughnessPushConstant { + uint32_t face_id; + uint32_t sample_count; + float roughness; + uint32_t use_direct_write; + float face_size; + float pad[3]; + }; + + struct CubemapRoughness { + CubemapRoughnessPushConstant push_constant; + CubemapRoughnessShaderRD compute_shader; + CubemapRoughnessRasterShaderRD raster_shader; + RID shader_version; + RID compute_pipeline; + PipelineCacheRD raster_pipeline; + } roughness; + static CopyEffects *singleton; public: @@ -197,6 +282,8 @@ public: CopyEffects(bool p_prefer_raster_effects); ~CopyEffects(); + bool get_prefer_raster_effects() { return prefer_raster_effects; } + void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false); void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array); void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false); @@ -213,6 +300,15 @@ public: void make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebuffer, const Size2i &p_size); void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false); + + void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip); + void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size); + void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size); + void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array); + void cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level); + + void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); + void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); }; } // namespace RendererRD diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 4c542fa2e2..d45ddbc392 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -86,7 +86,7 @@ RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps) u.append_id(p_texture); uniforms.push_back(u); // anything with the same configuration (one texture in binding 0 for set 0), is good - RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0), 0); + RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, specular_merge.shader.version_get_shader(specular_merge.shader_version, 0), 0); texture_to_uniform_set_cache[p_texture] = uniform_set; @@ -473,28 +473,6 @@ void EffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_bas RD::get_singleton()->draw_list_end(); } -void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip) { - CopyToDPPushConstant push_constant; - push_constant.screen_rect[0] = p_rect.position.x; - push_constant.screen_rect[1] = p_rect.position.y; - push_constant.screen_rect[2] = p_rect.size.width; - push_constant.screen_rect[3] = p_rect.size.height; - push_constant.z_far = p_z_far; - push_constant.z_near = p_z_near; - push_constant.texel_size[0] = 1.0f / p_dst_size.x; - push_constant.texel_size[1] = 1.0f / p_dst_size.y; - push_constant.texel_size[0] *= p_dp_flip ? -1.0f : 1.0f; // Encode dp flip as x size sign - - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_dp.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - - RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CopyToDPPushConstant)); - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_TRANSFER); -} - void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) { ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of luminance reduction with the mobile renderer."); @@ -1253,149 +1231,6 @@ void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size RD::get_singleton()->compute_list_end(); } -void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap roughness with the mobile renderer."); - - memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant)); - - roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id; - roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in. - roughness.push_constant.sample_count = p_sample_count; - roughness.push_constant.use_direct_write = p_roughness == 0.0; - roughness.push_constant.face_size = p_size; - - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.compute_pipeline); - - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture, true), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 1); - - RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); - - int x_groups = (p_size - 1) / 8 + 1; - int y_groups = (p_size - 1) / 8 + 1; - - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, p_face_id > 9 ? 6 : 1); - - RD::get_singleton()->compute_list_end(); -} - -void EffectsRD::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) { - ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap roughness with the clustered renderer."); - ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap roughness must process one side at a time."); - - memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant)); - - roughness.push_constant.face_id = p_face_id; - roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in. - roughness.push_constant.sample_count = p_sample_count; - roughness.push_constant.use_direct_write = p_roughness == 0.0; - roughness.push_constant.face_size = p_size; - - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - - RD::get_singleton()->draw_list_set_push_constant(draw_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant)); - - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); -} - -void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap downsample with the mobile renderer."); - - cubemap_downsampler.push_constant.face_size = p_size.x; - cubemap_downsampler.push_constant.face_id = 0; // we render all 6 sides to each layer in one call - - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.compute_pipeline); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_cubemap), 1); - - int x_groups = (p_size.x - 1) / 8 + 1; - int y_groups = (p_size.y - 1) / 8 + 1; - - RD::get_singleton()->compute_list_set_push_constant(compute_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant)); - - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 6); // one z_group for each face - - RD::get_singleton()->compute_list_end(); -} - -void EffectsRD::cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size) { - ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap downsample with the clustered renderer."); - ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap downsample must process one side at a time."); - - cubemap_downsampler.push_constant.face_size = p_size.x; - cubemap_downsampler.push_constant.face_id = p_face_id; - - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cubemap_downsampler.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_cubemap), 0); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - - RD::get_singleton()->draw_list_set_push_constant(draw_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant)); - - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); -} - -void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) { - ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap filter with the mobile renderer."); - - Vector<RD::Uniform> uniforms; - for (int i = 0; i < p_dest_cubemap.size(); i++) { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_IMAGE; - u.binding = i; - u.append_id(p_dest_cubemap[i]); - uniforms.push_back(u); - } - if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) { - RD::get_singleton()->free(filter.image_uniform_set); - } - filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, 0), 2); - - int pipeline = p_use_array ? FILTER_MODE_HIGH_QUALITY_ARRAY : FILTER_MODE_HIGH_QUALITY; - pipeline = filter.use_high_quality ? pipeline : pipeline + 1; - RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.compute_pipelines[pipeline]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap, true), 0); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2); - - int x_groups = p_use_array ? 1792 : 342; // (128 * 128 * 7) / 64 : (128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) / 64 - - RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, 6, 1); // one y_group for each face - - RD::get_singleton()->compute_list_end(); -} - -void EffectsRD::cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level) { - ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap filter with the clustered renderer."); - ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap filter must process one side at a time."); - - // TODO implement! - CubemapFilterRasterPushConstant push_constant; - push_constant.mip_level = p_mip_level; - push_constant.face_id = p_face_id; - - CubemapFilterMode mode = filter.use_high_quality ? FILTER_MODE_HIGH_QUALITY : FILTER_MODE_LOW_QUALITY; - - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD); - RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, filter.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_cubemap), 0); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, filter.uniform_set, 1); - RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); - - RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CubemapFilterRasterPushConstant)); - - RD::get_singleton()->draw_list_draw(draw_list, true); - RD::get_singleton()->draw_list_end(); -} - void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) { Sort::PushConstant push_constant; push_constant.total_elements = p_size; @@ -1489,28 +1324,6 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { prefer_raster_effects = p_prefer_raster_effects; - { - // Initialize roughness - Vector<String> cubemap_roughness_modes; - cubemap_roughness_modes.push_back(""); - - if (prefer_raster_effects) { - roughness.raster_shader.initialize(cubemap_roughness_modes); - - roughness.shader_version = roughness.raster_shader.version_create(); - - roughness.raster_pipeline.setup(roughness.raster_shader.version_get_shader(roughness.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); - - } else { - roughness.compute_shader.initialize(cubemap_roughness_modes); - - roughness.shader_version = roughness.compute_shader.version_create(); - - roughness.compute_pipeline = RD::get_singleton()->compute_pipeline_create(roughness.compute_shader.version_get_shader(roughness.shader_version, 0)); - roughness.raster_pipeline.clear(); - } - } - if (prefer_raster_effects) { Vector<String> luminance_reduce_modes; luminance_reduce_modes.push_back("\n#define FIRST_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FIRST @@ -1544,22 +1357,6 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { } } - { - // Initialize copier - Vector<String> copy_modes; - copy_modes.push_back("\n"); - - cube_to_dp.shader.initialize(copy_modes); - - cube_to_dp.shader_version = cube_to_dp.shader.version_create(); - RID shader = cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0); - RD::PipelineDepthStencilState dss; - dss.enable_depth_test = true; - dss.depth_compare_operator = RD::COMPARE_OP_ALWAYS; - dss.enable_depth_write = true; - cube_to_dp.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), dss, RD::PipelineColorBlendState(), 0); - } - if (!prefer_raster_effects) { { // Initialize depth buffer for screen space effects @@ -1720,92 +1517,6 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { roughness_limiter.pipeline = RD::get_singleton()->compute_pipeline_create(roughness_limiter.shader.version_get_shader(roughness_limiter.shader_version, 0)); } - { - //Initialize cubemap downsampler - Vector<String> cubemap_downsampler_modes; - cubemap_downsampler_modes.push_back(""); - - if (prefer_raster_effects) { - cubemap_downsampler.raster_shader.initialize(cubemap_downsampler_modes); - - cubemap_downsampler.shader_version = cubemap_downsampler.raster_shader.version_create(); - - cubemap_downsampler.raster_pipeline.setup(cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); - } else { - cubemap_downsampler.compute_shader.initialize(cubemap_downsampler_modes); - - cubemap_downsampler.shader_version = cubemap_downsampler.compute_shader.version_create(); - - cubemap_downsampler.compute_pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0)); - cubemap_downsampler.raster_pipeline.clear(); - } - } - - { - // Initialize cubemap filter - filter.use_high_quality = GLOBAL_GET("rendering/reflections/sky_reflections/fast_filter_high_quality"); - - Vector<String> cubemap_filter_modes; - cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n"); - cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n"); - cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n#define USE_TEXTURE_ARRAY\n"); - cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n#define USE_TEXTURE_ARRAY\n"); - - if (filter.use_high_quality) { - filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs)); - RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(high_quality_coeffs), &high_quality_coeffs[0]); - } else { - filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(low_quality_coeffs)); - RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0]); - } - - if (prefer_raster_effects) { - filter.raster_shader.initialize(cubemap_filter_modes); - - // array variants are not supported in raster - filter.raster_shader.set_variant_enabled(FILTER_MODE_HIGH_QUALITY_ARRAY, false); - filter.raster_shader.set_variant_enabled(FILTER_MODE_LOW_QUALITY_ARRAY, false); - - filter.shader_version = filter.raster_shader.version_create(); - - for (int i = 0; i < FILTER_MODE_MAX; i++) { - if (filter.raster_shader.is_variant_enabled(i)) { - filter.raster_pipelines[i].setup(filter.raster_shader.version_get_shader(filter.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0); - } else { - filter.raster_pipelines[i].clear(); - } - } - - Vector<RD::Uniform> uniforms; - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 0; - u.append_id(filter.coefficient_buffer); - uniforms.push_back(u); - } - filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.raster_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1); - } else { - filter.compute_shader.initialize(cubemap_filter_modes); - filter.shader_version = filter.compute_shader.version_create(); - - for (int i = 0; i < FILTER_MODE_MAX; i++) { - filter.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.compute_shader.version_get_shader(filter.shader_version, i)); - filter.raster_pipelines[i].clear(); - } - - Vector<RD::Uniform> uniforms; - { - RD::Uniform u; - u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; - u.binding = 0; - u.append_id(filter.coefficient_buffer); - uniforms.push_back(u); - } - filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1); - } - } - if (!prefer_raster_effects) { Vector<String> specular_modes; specular_modes.push_back("\n#define MODE_MERGE\n"); @@ -2028,31 +1739,16 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) { } EffectsRD::~EffectsRD() { - if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) { - RD::get_singleton()->free(filter.image_uniform_set); - } - - if (RD::get_singleton()->uniform_set_is_valid(filter.uniform_set)) { - RD::get_singleton()->free(filter.uniform_set); - } - RD::get_singleton()->free(default_sampler); RD::get_singleton()->free(default_mipmap_sampler); RD::get_singleton()->free(index_buffer); //array gets freed as dependency - RD::get_singleton()->free(filter.coefficient_buffer); FSR_upscale.shader.version_free(FSR_upscale.shader_version); TAA_resolve.shader.version_free(TAA_resolve.shader_version); if (prefer_raster_effects) { luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version); - roughness.raster_shader.version_free(roughness.shader_version); - cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version); - filter.raster_shader.version_free(filter.shader_version); } else { luminance_reduce.shader.version_free(luminance_reduce.shader_version); - roughness.compute_shader.version_free(roughness.shader_version); - cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version); - filter.compute_shader.version_free(filter.shader_version); } if (!prefer_raster_effects) { specular_merge.shader.version_free(specular_merge.shader_version); @@ -2077,6 +1773,5 @@ EffectsRD::~EffectsRD() { RD::get_singleton()->free(ssil.importance_map_load_counter); RD::get_singleton()->free(ssil.projection_uniform_buffer); } - cube_to_dp.shader.version_free(cube_to_dp.shader_version); sort.shader.version_free(sort.shader_version); } diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index af4ed5a6ae..76627a8d7d 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -33,13 +33,6 @@ #include "core/math/camera_matrix.h" #include "servers/rendering/renderer_rd/pipeline_cache_rd.h" -#include "servers/rendering/renderer_rd/shaders/cube_to_dp.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/cubemap_filter.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl.gen.h" -#include "servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/fsr_upscale.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl.gen.h" @@ -104,24 +97,6 @@ private: RID pipeline; } TAA_resolve; - struct CubemapRoughnessPushConstant { - uint32_t face_id; - uint32_t sample_count; - float roughness; - uint32_t use_direct_write; - float face_size; - float pad[3]; - }; - - struct CubemapRoughness { - CubemapRoughnessPushConstant push_constant; - CubemapRoughnessShaderRD compute_shader; - CubemapRoughnessRasterShaderRD raster_shader; - RID shader_version; - RID compute_pipeline; - PipelineCacheRD raster_pipeline; - } roughness; - enum LuminanceReduceMode { LUMINANCE_REDUCE_READ, LUMINANCE_REDUCE, @@ -167,19 +142,6 @@ private: PipelineCacheRD pipelines[LUMINANCE_REDUCE_FRAGMENT_MAX]; } luminance_reduce_raster; - struct CopyToDPPushConstant { - float z_far; - float z_near; - float texel_size[2]; - float screen_rect[4]; - }; - - struct CoptToDP { - CubeToDpShaderRD shader; - RID shader_version; - PipelineCacheRD pipeline; - } cube_to_dp; - struct SSEffectsDownsamplePushConstant { float pixel_size[2]; float z_far; @@ -419,49 +381,6 @@ private: } roughness_limiter; - struct CubemapDownsamplerPushConstant { - uint32_t face_size; - uint32_t face_id; - float pad[2]; - }; - - struct CubemapDownsampler { - CubemapDownsamplerPushConstant push_constant; - CubemapDownsamplerShaderRD compute_shader; - CubemapDownsamplerRasterShaderRD raster_shader; - RID shader_version; - RID compute_pipeline; - PipelineCacheRD raster_pipeline; - } cubemap_downsampler; - - enum CubemapFilterMode { - FILTER_MODE_HIGH_QUALITY, - FILTER_MODE_LOW_QUALITY, - FILTER_MODE_HIGH_QUALITY_ARRAY, - FILTER_MODE_LOW_QUALITY_ARRAY, - FILTER_MODE_MAX, - }; - - struct CubemapFilterRasterPushConstant { - uint32_t mip_level; - uint32_t face_id; - float pad[2]; - }; - - struct CubemapFilter { - CubemapFilterShaderRD compute_shader; - CubemapFilterRasterShaderRD raster_shader; - RID shader_version; - RID compute_pipelines[FILTER_MODE_MAX]; - PipelineCacheRD raster_pipelines[FILTER_MODE_MAX]; - - RID uniform_set; - RID image_uniform_set; - RID coefficient_buffer; - bool use_high_quality; - - } filter; - enum SpecularMergeMode { SPECULAR_MERGE_ADD, SPECULAR_MERGE_SSR, @@ -650,9 +569,6 @@ public: void fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness); void taa_resolve(RID p_frame, RID p_temp, RID p_depth, RID p_velocity, RID p_prev_velocity, RID p_history, Size2 p_resolution, float p_z_near, float p_z_far); - void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); - void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); - void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip); void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); void luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false); @@ -703,10 +619,6 @@ public: void screen_space_indirect_lighting(RID p_diffuse, RID p_destination, RID p_normal_buffer, RID p_depth_mipmaps_texture, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_importance_map, RID p_importance_map_pong, RID p_edges, const Vector<RID> p_edges_slices, const CameraMatrix &p_projection, const CameraMatrix &p_last_projection, const SSILSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set, RID &r_projection_uniform_set); void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve); - void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size); - void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size); - void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array); - void cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level); void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera); void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 6f16c0972e..90a7394344 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -5438,9 +5438,9 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, Rect2 atlas_rect_norm = atlas_rect; atlas_rect_norm.position /= float(atlas_size); atlas_rect_norm.size /= float(atlas_size); - storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false); + copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false); atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size; - storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true); + copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true); //restore transform so it can be properly used light_instance_set_shadow_transform(p_light, CameraMatrix(), light_instance->transform, zfar, 0, 0, 0); diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index 3a237dbd8c..b3b9b86aa8 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -438,19 +438,19 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageR } void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays) { - EffectsRD *effects = p_storage->get_effects(); - ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised"); - bool prefer_raster_effects = effects->get_prefer_raster_effects(); + RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); + ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialised"); + bool prefer_raster_effects = copy_effects->get_prefer_raster_effects(); if (prefer_raster_effects) { RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); for (int k = 0; k < 6; k++) { - effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size); + copy_effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size); } for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { for (int k = 0; k < 6; k++) { - effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size); + copy_effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size); } } RD::get_singleton()->draw_command_end_label(); // Downsample Radiance @@ -459,24 +459,24 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererS RD::get_singleton()->draw_command_begin_label("filter radiance map into array heads"); for (int i = 0; i < layers.size(); i++) { for (int k = 0; k < 6; k++) { - effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[i].mipmaps[0].framebuffers[k], k, i); + copy_effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[i].mipmaps[0].framebuffers[k], k, i); } } } else { RD::get_singleton()->draw_command_begin_label("filter radiance map into mipmaps directly"); for (int j = 0; j < layers[0].mipmaps.size(); j++) { for (int k = 0; k < 6; k++) { - effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[0].mipmaps[j].framebuffers[k], k, j); + copy_effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[0].mipmaps[j].framebuffers[k], k, j); } } } RD::get_singleton()->draw_command_end_label(); // Filter radiance } else { RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); - effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); + copy_effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { - effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); + copy_effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); } RD::get_singleton()->draw_command_end_label(); // Downsample Radiance Vector<RID> views; @@ -490,26 +490,26 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererS } } RD::get_singleton()->draw_command_begin_label("Fast filter radiance"); - effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays); + copy_effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays); RD::get_singleton()->draw_command_end_label(); // Filter radiance } } void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) { - EffectsRD *effects = p_storage->get_effects(); - ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised"); - bool prefer_raster_effects = effects->get_prefer_raster_effects(); + RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); + ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialised"); + bool prefer_raster_effects = copy_effects->get_prefer_raster_effects(); if (prefer_raster_effects) { if (p_base_layer == 1) { RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); for (int k = 0; k < 6; k++) { - effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size); + copy_effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size); } for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { for (int k = 0; k < 6; k++) { - effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size); + copy_effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size); } } RD::get_singleton()->draw_command_end_label(); // Downsample Radiance @@ -518,7 +518,7 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren RD::get_singleton()->draw_command_begin_label("High Quality filter radiance"); if (p_use_arrays) { for (int k = 0; k < 6; k++) { - effects->cubemap_roughness_raster( + copy_effects->cubemap_roughness_raster( downsampled_radiance_cubemap, layers[p_base_layer].mipmaps[0].framebuffers[k], k, @@ -528,7 +528,7 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren } } else { for (int k = 0; k < 6; k++) { - effects->cubemap_roughness_raster( + copy_effects->cubemap_roughness_raster( downsampled_radiance_cubemap, layers[0].mipmaps[p_base_layer].framebuffers[k], k, @@ -540,19 +540,19 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren } else { if (p_base_layer == 1) { RD::get_singleton()->draw_command_begin_label("Downsample radiance map"); - effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); + copy_effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size); for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) { - effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); + copy_effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size); } RD::get_singleton()->draw_command_end_label(); // Downsample Radiance } RD::get_singleton()->draw_command_begin_label("High Quality filter radiance"); if (p_use_arrays) { - effects->cubemap_roughness(downsampled_radiance_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x); + copy_effects->cubemap_roughness(downsampled_radiance_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x); } else { - effects->cubemap_roughness( + copy_effects->cubemap_roughness( downsampled_radiance_cubemap, layers[0].views[p_base_layer], p_cube_side, @@ -565,9 +565,9 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren } void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end) { - EffectsRD *effects = p_storage->get_effects(); - ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised"); - bool prefer_raster_effects = effects->get_prefer_raster_effects(); + RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton(); + ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialised"); + bool prefer_raster_effects = copy_effects->get_prefer_raster_effects(); RD::get_singleton()->draw_command_begin_label("Update Radiance Cubemap Array Mipmaps"); for (int i = p_start; i < p_end; i++) { @@ -577,11 +577,11 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStora if (prefer_raster_effects) { for (int k = 0; k < 6; k++) { RID framebuffer = layers[i].mipmaps[j + 1].framebuffers[k]; - effects->cubemap_downsample_raster(view, framebuffer, k, size); + copy_effects->cubemap_downsample_raster(view, framebuffer, k, size); } } else { RID texture = layers[i].views[j + 1]; - effects->cubemap_downsample(view, texture, size); + copy_effects->cubemap_downsample(view, texture, size); } } } diff --git a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl index e77d0de719..e77d0de719 100644 --- a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl index 63f0ce690e..63f0ce690e 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_inc.glsl index 641e0906f5..641e0906f5 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_inc.glsl diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl index 0828ffd921..0828ffd921 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl diff --git a/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl index 2a774b0eb4..2a774b0eb4 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl diff --git a/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl index 0990dc7c2f..0990dc7c2f 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl index 1d46f59408..1d46f59408 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_inc.glsl index 1bee428a6f..1bee428a6f 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_inc.glsl diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl index c29accd8a7..c29accd8a7 100644 --- a/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl |