diff options
-rw-r--r-- | core/core_bind.cpp | 20 | ||||
-rw-r--r-- | core/core_bind.h | 4 | ||||
-rw-r--r-- | core/debugger/remote_debugger.cpp | 8 | ||||
-rw-r--r-- | core/error/error_macros.cpp | 8 | ||||
-rw-r--r-- | core/extension/native_extension.cpp | 28 | ||||
-rw-r--r-- | core/io/marshalls.cpp | 45 | ||||
-rw-r--r-- | core/object/object.cpp | 2 | ||||
-rw-r--r-- | core/object/object.h | 8 | ||||
-rw-r--r-- | core/object/script_language_extension.h | 6 | ||||
-rw-r--r-- | core/templates/vector.h | 3 | ||||
-rw-r--r-- | core/variant/variant_call.cpp | 32 | ||||
-rw-r--r-- | doc/classes/PackedByteArray.xml | 10 | ||||
-rw-r--r-- | doc/classes/ResourceLoader.xml | 16 | ||||
-rw-r--r-- | doc/classes/ResourceSaver.xml | 16 | ||||
-rw-r--r-- | drivers/vulkan/rendering_device_vulkan.cpp | 30 | ||||
-rw-r--r-- | editor/debugger/script_editor_debugger.cpp | 3 | ||||
-rw-r--r-- | editor/editor_properties.cpp | 62 | ||||
-rw-r--r-- | editor/editor_properties.h | 27 | ||||
-rw-r--r-- | editor/plugins/texture_editor_plugin.cpp | 52 | ||||
-rw-r--r-- | main/main.cpp | 7 | ||||
-rw-r--r-- | scene/gui/control.cpp | 18 |
21 files changed, 316 insertions, 89 deletions
diff --git a/core/core_bind.cpp b/core/core_bind.cpp index fc91f83462..b5f4a1c0f6 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -83,6 +83,14 @@ Vector<String> ResourceLoader::get_recognized_extensions_for_type(const String & return ret; } +void ResourceLoader::add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front) { + ::ResourceLoader::add_resource_format_loader(p_format_loader, p_at_front); +} + +void ResourceLoader::remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader) { + ::ResourceLoader::remove_resource_format_loader(p_format_loader); +} + void ResourceLoader::set_abort_on_missing_resources(bool p_abort) { ::ResourceLoader::set_abort_on_missing_resources(p_abort); } @@ -119,6 +127,8 @@ void ResourceLoader::_bind_methods() { ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "cache_mode"), &ResourceLoader::load, DEFVAL(""), DEFVAL(CACHE_MODE_REUSE)); ClassDB::bind_method(D_METHOD("get_recognized_extensions_for_type", "type"), &ResourceLoader::get_recognized_extensions_for_type); + ClassDB::bind_method(D_METHOD("add_resource_format_loader", "format_loader", "at_front"), &ResourceLoader::add_resource_format_loader, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("remove_resource_format_loader", "format_loader"), &ResourceLoader::remove_resource_format_loader); ClassDB::bind_method(D_METHOD("set_abort_on_missing_resources", "abort"), &ResourceLoader::set_abort_on_missing_resources); ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &ResourceLoader::get_dependencies); ClassDB::bind_method(D_METHOD("has_cached", "path"), &ResourceLoader::has_cached); @@ -153,11 +163,21 @@ Vector<String> ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_r return ret; } +void ResourceSaver::add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front) { + ::ResourceSaver::add_resource_format_saver(p_format_saver, p_at_front); +} + +void ResourceSaver::remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver) { + ::ResourceSaver::remove_resource_format_saver(p_format_saver); +} + ResourceSaver *ResourceSaver::singleton = nullptr; void ResourceSaver::_bind_methods() { ClassDB::bind_method(D_METHOD("save", "path", "resource", "flags"), &ResourceSaver::save, DEFVAL((uint32_t)FLAG_NONE)); ClassDB::bind_method(D_METHOD("get_recognized_extensions", "type"), &ResourceSaver::get_recognized_extensions); + ClassDB::bind_method(D_METHOD("add_resource_format_saver", "format_saver", "at_front"), &ResourceSaver::add_resource_format_saver, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("remove_resource_format_saver", "format_saver"), &ResourceSaver::remove_resource_format_saver); BIND_ENUM_CONSTANT(FLAG_NONE); BIND_ENUM_CONSTANT(FLAG_RELATIVE_PATHS); diff --git a/core/core_bind.h b/core/core_bind.h index ec9bcdbc02..99e14a75f5 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -77,6 +77,8 @@ public: Ref<Resource> load(const String &p_path, const String &p_type_hint = "", CacheMode p_cache_mode = CACHE_MODE_REUSE); Vector<String> get_recognized_extensions_for_type(const String &p_type); + void add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front); + void remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader); void set_abort_on_missing_resources(bool p_abort); PackedStringArray get_dependencies(const String &p_path); bool has_cached(const String &p_path); @@ -109,6 +111,8 @@ public: Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags); Vector<String> get_recognized_extensions(const Ref<Resource> &p_resource); + void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front); + void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver); ResourceSaver() { singleton = this; } }; diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp index 508a71ece9..c73e2eb3fb 100644 --- a/core/debugger/remote_debugger.cpp +++ b/core/debugger/remote_debugger.cpp @@ -297,6 +297,14 @@ void RemoteDebugger::flush_output() { } strings.push_back(output_string.message); types.push_back(MESSAGE_TYPE_ERROR); + } else if (output_string.type == MESSAGE_TYPE_LOG_RICH) { + if (!joined_log_strings.is_empty()) { + strings.push_back(String("\n").join(joined_log_strings)); + types.push_back(MESSAGE_TYPE_LOG_RICH); + joined_log_strings.clear(); + } + strings.push_back(output_string.message); + types.push_back(MESSAGE_TYPE_LOG_RICH); } else { joined_log_strings.push_back(output_string.message); } diff --git a/core/error/error_macros.cpp b/core/error/error_macros.cpp index 8add4b9a3a..f71a642b23 100644 --- a/core/error/error_macros.cpp +++ b/core/error/error_macros.cpp @@ -83,7 +83,13 @@ void _err_print_error(const char *p_function, const char *p_file, int p_line, co // Main error printing function. void _err_print_error(const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_message, bool p_editor_notify, ErrorHandlerType p_type) { - OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, p_message, p_editor_notify, (Logger::ErrorType)p_type); + if (OS::get_singleton()) { + OS::get_singleton()->print_error(p_function, p_file, p_line, p_error, p_message, p_editor_notify, (Logger::ErrorType)p_type); + } else { + // Fallback if errors happen before OS init or after it's destroyed. + const char *err_details = (p_message && *p_message) ? p_message : p_error; + fprintf(stderr, "ERROR: %s\n at: %s (%s:%i)\n", err_details, p_function, p_file, p_line); + } _global_lock(); ErrorHandlerList *l = error_handler_list; diff --git a/core/extension/native_extension.cpp b/core/extension/native_extension.cpp index ebdfa20725..262e28b442 100644 --- a/core/extension/native_extension.cpp +++ b/core/extension/native_extension.cpp @@ -55,14 +55,7 @@ protected: virtual PropertyInfo _gen_argument_type_info(int p_arg) const override { GDNativePropertyInfo pinfo; get_argument_info_func(method_userdata, p_arg, &pinfo); - PropertyInfo ret; - ret.type = Variant::Type(pinfo.type); - ret.name = pinfo.name; - ret.class_name = pinfo.class_name; - ret.hint = PropertyHint(pinfo.hint); - ret.usage = pinfo.usage; - ret.class_name = pinfo.class_name; - return ret; + return PropertyInfo(pinfo); } public: @@ -204,16 +197,11 @@ void NativeExtension::_register_extension_class_property(const GDNativeExtension NativeExtension *self = static_cast<NativeExtension *>(p_library); StringName class_name = p_class_name; - ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property '" + String(p_info->name) + "' for unexisting class '" + class_name + "'."); + String property_name = p_info->name; + ERR_FAIL_COND_MSG(!self->extension_classes.has(class_name), "Attempt to register extension class property '" + property_name + "' for unexisting class '" + class_name + "'."); //Extension *extension = &self->extension_classes[class_name]; - PropertyInfo pinfo; - pinfo.type = Variant::Type(p_info->type); - pinfo.name = p_info->name; - pinfo.class_name = p_info->class_name; - pinfo.hint = PropertyHint(p_info->hint); - pinfo.hint_string = p_info->hint_string; - pinfo.usage = p_info->usage; + PropertyInfo pinfo(*p_info); ClassDB::add_property(class_name, pinfo, p_setter, p_getter); } @@ -245,13 +233,7 @@ void NativeExtension::_register_extension_class_signal(const GDNativeExtensionCl MethodInfo s; s.name = p_signal_name; for (int i = 0; i < p_argument_count; i++) { - PropertyInfo arg; - arg.type = Variant::Type(p_argument_info[i].type); - arg.name = p_argument_info[i].name; - arg.class_name = p_argument_info[i].class_name; - arg.hint = PropertyHint(p_argument_info[i].hint); - arg.hint_string = p_argument_info[i].hint_string; - arg.usage = p_argument_info[i].usage; + PropertyInfo arg(p_argument_info[i]); s.arguments.push_back(arg); } ClassDB::add_signal(class_name, s); diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index bb9606c94b..f71ea5c39e 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -532,7 +532,13 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::RID: { - r_variant = RID(); + ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA); + uint64_t id = decode_uint64(buf); + if (r_len) { + (*r_len) += 8; + } + + r_variant = RID::from_uint64(id); } break; case Variant::OBJECT: { if (type & ENCODE_FLAG_OBJECT_AS_ID) { @@ -614,9 +620,20 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int r_variant = Callable(); } break; case Variant::SIGNAL: { - r_variant = Signal(); - } break; + String name; + Error err = _decode_string(buf, len, r_len, name); + if (err) { + return err; + } + ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA); + ObjectID id = ObjectID(decode_uint64(buf)); + if (r_len) { + (*r_len) += 8; + } + + r_variant = Signal(id, StringName(name)); + } break; case Variant::DICTIONARY: { ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); int32_t count = decode_uint32(buf); @@ -1352,10 +1369,12 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } break; case Variant::RID: { - } break; - case Variant::CALLABLE: { - } break; - case Variant::SIGNAL: { + RID rid = p_variant; + + if (buf) { + encode_uint64(rid.get_id(), buf); + } + r_len += 8; } break; case Variant::OBJECT: { if (p_full_objects) { @@ -1419,6 +1438,18 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } } break; + case Variant::CALLABLE: { + } break; + case Variant::SIGNAL: { + Signal signal = p_variant; + + _encode_string(signal.get_name(), buf, r_len); + + if (buf) { + encode_uint64(signal.get_object_id(), buf); + } + r_len += 8; + } break; case Variant::DICTIONARY: { Dictionary d = p_variant; diff --git a/core/object/object.cpp b/core/object/object.cpp index 440da00c17..5f2287c9d3 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -493,7 +493,7 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons uint32_t pcount; const GDNativePropertyInfo *pinfo = _extension->get_property_list(_extension_instance, &pcount); for (uint32_t i = 0; i < pcount; i++) { - p_list->push_back(PropertyInfo(Variant::Type(pinfo[i].type), pinfo[i].class_name, PropertyHint(pinfo[i].hint), pinfo[i].hint_string, pinfo[i].usage, pinfo[i].class_name)); + p_list->push_back(PropertyInfo(pinfo[i])); } if (_extension->free_property_list) { _extension->free_property_list(_extension_instance, pinfo); diff --git a/core/object/object.h b/core/object/object.h index e065634000..1f6386e6b4 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -190,6 +190,14 @@ struct PropertyInfo { type(Variant::OBJECT), class_name(p_class_name) {} + explicit PropertyInfo(const GDNativePropertyInfo &pinfo) : + type((Variant::Type)pinfo.type), + name(pinfo.name), + class_name(pinfo.class_name), // can be null + hint((PropertyHint)pinfo.hint), + hint_string(pinfo.hint_string), // can be null + usage(pinfo.usage) {} + bool operator==(const PropertyInfo &p_info) const { return ((type == p_info.type) && (name == p_info.name) && diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h index 406a431a11..7eea48370e 100644 --- a/core/object/script_language_extension.h +++ b/core/object/script_language_extension.h @@ -671,7 +671,7 @@ public: uint32_t pcount; const GDNativePropertyInfo *pinfo = native_info->get_property_list_func(instance, &pcount); for (uint32_t i = 0; i < pcount; i++) { - p_list->push_back(PropertyInfo(Variant::Type(pinfo[i].type), pinfo[i].class_name, PropertyHint(pinfo[i].hint), pinfo[i].hint_string, pinfo[i].usage, pinfo[i].class_name)); + p_list->push_back(PropertyInfo(pinfo[i])); } if (native_info->free_property_list_func) { native_info->free_property_list_func(instance, pinfo); @@ -716,9 +716,9 @@ public: m.name = minfo[i].name; m.flags = minfo[i].flags; m.id = minfo[i].id; - m.return_val = PropertyInfo(Variant::Type(minfo[i].return_value.type), minfo[i].return_value.class_name, PropertyHint(minfo[i].return_value.hint), minfo[i].return_value.hint_string, minfo[i].return_value.usage, minfo[i].return_value.class_name); + m.return_val = PropertyInfo(minfo[i].return_value); for (uint32_t j = 0; j < minfo[i].argument_count; j++) { - m.arguments.push_back(PropertyInfo(Variant::Type(minfo[i].arguments[j].type), minfo[i].arguments[j].class_name, PropertyHint(minfo[i].arguments[j].hint), minfo[i].arguments[j].hint_string, minfo[i].arguments[j].usage, minfo[i].arguments[j].class_name)); + m.arguments.push_back(PropertyInfo(minfo[i].arguments[j])); } const Variant *def_values = (const Variant *)minfo[i].default_arguments; for (uint32_t j = 0; j < minfo[i].default_argument_count; j++) { diff --git a/core/templates/vector.h b/core/templates/vector.h index 2ac7c7630a..f3f5ed76a7 100644 --- a/core/templates/vector.h +++ b/core/templates/vector.h @@ -145,6 +145,9 @@ public: Vector<uint8_t> to_byte_array() const { Vector<uint8_t> ret; + if (is_empty()) { + return ret; + } ret.resize(size() * sizeof(T)); memcpy(ret.ptrw(), ptr(), sizeof(T) * size()); return ret; diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index a4bb7630d6..c14de74af7 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -753,40 +753,56 @@ struct _VariantCall { static PackedInt32Array func_PackedByteArray_decode_s32_array(PackedByteArray *p_instance) { uint64_t size = p_instance->size(); PackedInt32Array dest; - ERR_FAIL_COND_V_MSG(size < sizeof(int32_t), dest, "Size didn't match array of size int32_t, maybe you are trying to convert to the wrong type?"); + if (size == 0) { + return dest; + } + ERR_FAIL_COND_V_MSG(size % sizeof(int32_t), dest, "PackedByteArray size must be a multiple of 4 (size of 32-bit integer) to convert to PackedInt32Array."); const uint8_t *r = p_instance->ptr(); dest.resize(size / sizeof(int32_t)); - memcpy(dest.ptrw(), r, size); + ERR_FAIL_COND_V(dest.size() == 0, dest); // Avoid UB in case resize failed. + memcpy(dest.ptrw(), r, dest.size() * sizeof(int32_t)); return dest; } static PackedInt64Array func_PackedByteArray_decode_s64_array(PackedByteArray *p_instance) { uint64_t size = p_instance->size(); PackedInt64Array dest; - ERR_FAIL_COND_V_MSG(size < sizeof(int64_t), dest, "Size didn't match array of size int64_t, maybe you are trying to convert to the wrong type?"); + if (size == 0) { + return dest; + } + ERR_FAIL_COND_V_MSG(size % sizeof(int64_t), dest, "PackedByteArray size must be a multiple of 8 (size of 64-bit integer) to convert to PackedInt64Array."); const uint8_t *r = p_instance->ptr(); dest.resize(size / sizeof(int64_t)); - memcpy(dest.ptrw(), r, size); + ERR_FAIL_COND_V(dest.size() == 0, dest); // Avoid UB in case resize failed. + memcpy(dest.ptrw(), r, dest.size() * sizeof(int64_t)); return dest; } static PackedFloat32Array func_PackedByteArray_decode_float_array(PackedByteArray *p_instance) { uint64_t size = p_instance->size(); PackedFloat32Array dest; - ERR_FAIL_COND_V_MSG(size < sizeof(float), dest, "Size didn't match array of size float, maybe you are trying to convert to the wrong type?"); + if (size == 0) { + return dest; + } + ERR_FAIL_COND_V_MSG(size % sizeof(float), dest, "PackedByteArray size must be a multiple of 4 (size of 32-bit float) to convert to PackedFloat32Array."); const uint8_t *r = p_instance->ptr(); dest.resize(size / sizeof(float)); - memcpy(dest.ptrw(), r, size); + ERR_FAIL_COND_V(dest.size() == 0, dest); // Avoid UB in case resize failed. + memcpy(dest.ptrw(), r, dest.size() * sizeof(float)); return dest; } static PackedFloat64Array func_PackedByteArray_decode_double_array(PackedByteArray *p_instance) { uint64_t size = p_instance->size(); PackedFloat64Array dest; - ERR_FAIL_COND_V_MSG(size < sizeof(double), dest, "Size didn't match array of size double, maybe you are trying to convert to the wrong type?"); + if (size == 0) { + return dest; + } + ERR_FAIL_COND_V_MSG(size % sizeof(double), dest, "PackedByteArray size must be a multiple of 8 (size of 64-bit double) to convert to PackedFloat64Array."); const uint8_t *r = p_instance->ptr(); dest.resize(size / sizeof(double)); - memcpy(dest.ptrw(), r, size); + ERR_FAIL_COND_V(dest.size() == 0, dest); // Avoid UB in case resize failed. + memcpy(dest.ptrw(), r, dest.size() * sizeof(double)); return dest; } diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml index 5d0861bcf3..3af3bb8697 100644 --- a/doc/classes/PackedByteArray.xml +++ b/doc/classes/PackedByteArray.xml @@ -409,7 +409,7 @@ <return type="PackedFloat32Array" /> <description> Returns a copy of the data converted to a [PackedFloat32Array], where each block of 4 bytes has been converted to a 32-bit float (C++ [code]float[/code]). - The size of the new array will be [code]byte_array.size() / 4[/code]. + The size of the input array must be a multiple of 4 (size of 32-bit float). The size of the new array will be [code]byte_array.size() / 4[/code]. If the original data can't be converted to 32-bit floats, the resulting data is undefined. </description> </method> @@ -417,7 +417,7 @@ <return type="PackedFloat64Array" /> <description> Returns a copy of the data converted to a [PackedFloat64Array], where each block of 8 bytes has been converted to a 64-bit float (C++ [code]double[/code], Godot [float]). - The size of the new array will be [code]byte_array.size() / 8[/code]. + The size of the input array must be a multiple of 8 (size of 64-bit double). The size of the new array will be [code]byte_array.size() / 8[/code]. If the original data can't be converted to 64-bit floats, the resulting data is undefined. </description> </method> @@ -425,15 +425,15 @@ <return type="PackedInt32Array" /> <description> Returns a copy of the data converted to a [PackedInt32Array], where each block of 4 bytes has been converted to a signed 32-bit integer (C++ [code]int32_t[/code]). - The size of the new array will be [code]byte_array.size() / 4[/code]. + The size of the input array must be a multiple of 4 (size of 32-bit integer). The size of the new array will be [code]byte_array.size() / 4[/code]. If the original data can't be converted to signed 32-bit integers, the resulting data is undefined. </description> </method> <method name="to_int64_array" qualifiers="const"> <return type="PackedInt64Array" /> <description> - Returns a copy of the data converted to a [PackedInt64Array], where each block of 4 bytes has been converted to a signed 64-bit integer (C++ [code]int64_t[/code], Godot [int]). - The size of the new array will be [code]byte_array.size() / 8[/code]. + Returns a copy of the data converted to a [PackedInt64Array], where each block of 8 bytes has been converted to a signed 64-bit integer (C++ [code]int64_t[/code], Godot [int]). + The size of the input array must be a multiple of 8 (size of 64-bit integer). The size of the new array will be [code]byte_array.size() / 8[/code]. If the original data can't be converted to signed 64-bit integers, the resulting data is undefined. </description> </method> diff --git a/doc/classes/ResourceLoader.xml b/doc/classes/ResourceLoader.xml index 1ffb0dba5c..d6e9a233b0 100644 --- a/doc/classes/ResourceLoader.xml +++ b/doc/classes/ResourceLoader.xml @@ -11,6 +11,15 @@ <link title="OS Test Demo">https://godotengine.org/asset-library/asset/677</link> </tutorials> <methods> + <method name="add_resource_format_loader"> + <return type="void" /> + <argument index="0" name="format_loader" type="ResourceFormatLoader" /> + <argument index="1" name="at_front" type="bool" default="false" /> + <description> + Registers a new [ResourceFormatLoader]. The ResourceLoader will use the ResourceFormatLoader as described in [method load]. + This method is performed implictly for ResourceFormatLoaders written in GDScript (see [ResourceFormatLoader] for more information). + </description> + </method> <method name="exists"> <return type="bool" /> <argument index="0" name="path" type="String" /> @@ -89,6 +98,13 @@ Loads the resource using threads. If [code]use_sub_threads[/code] is [code]true[/code], multiple threads will be used to load the resource, which makes loading faster, but may affect the main thread (and thus cause game slowdowns). </description> </method> + <method name="remove_resource_format_loader"> + <return type="void" /> + <argument index="0" name="format_loader" type="ResourceFormatLoader" /> + <description> + Unregisters the given [ResourceFormatLoader]. + </description> + </method> <method name="set_abort_on_missing_resources"> <return type="void" /> <argument index="0" name="abort" type="bool" /> diff --git a/doc/classes/ResourceSaver.xml b/doc/classes/ResourceSaver.xml index a029fb9acf..815c7e8813 100644 --- a/doc/classes/ResourceSaver.xml +++ b/doc/classes/ResourceSaver.xml @@ -10,6 +10,15 @@ <tutorials> </tutorials> <methods> + <method name="add_resource_format_saver"> + <return type="void" /> + <argument index="0" name="format_saver" type="ResourceFormatSaver" /> + <argument index="1" name="at_front" type="bool" default="false" /> + <description> + Registers a new [ResourceFormatSaver]. The ResourceSaver will use the ResourceFormatSaver as described in [method save]. + This method is performed implictly for ResourceFormatSavers written in GDScript (see [ResourceFormatSaver] for more information). + </description> + </method> <method name="get_recognized_extensions"> <return type="PackedStringArray" /> <argument index="0" name="type" type="Resource" /> @@ -17,6 +26,13 @@ Returns the list of extensions available for saving a resource of a given type. </description> </method> + <method name="remove_resource_format_saver"> + <return type="void" /> + <argument index="0" name="format_saver" type="ResourceFormatSaver" /> + <description> + Unregisters the given [ResourceFormatSaver]. + </description> + </method> <method name="save"> <return type="int" enum="Error" /> <argument index="0" name="path" type="String" /> diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp index 10250bddb5..9b491be128 100644 --- a/drivers/vulkan/rendering_device_vulkan.cpp +++ b/drivers/vulkan/rendering_device_vulkan.cpp @@ -4647,18 +4647,6 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(), "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed getting descriptor bindings."); - uint32_t interface_vars_count = 0; - result = spvReflectEnumerateInterfaceVariables(&module, &interface_vars_count, nullptr); - ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(), - "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed enumerating interface variables."); - - Vector<SpvReflectInterfaceVariable *> interface_vars; - interface_vars.resize(interface_vars_count); - result = spvReflectEnumerateInterfaceVariables(&module, &interface_vars_count, interface_vars.ptrw()); - - ERR_FAIL_COND_V_MSG(result != SPV_REFLECT_RESULT_SUCCESS, Vector<uint8_t>(), - "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed getting interface variables."); - for (uint32_t j = 0; j < binding_count; j++) { const SpvReflectDescriptorBinding &binding = *bindings[j]; @@ -4666,6 +4654,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve bool need_array_dimensions = false; bool need_block_size = false; + bool may_be_writable = false; switch (binding.descriptor_type) { case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER: { @@ -4683,6 +4672,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: { info.type = UNIFORM_TYPE_IMAGE; need_array_dimensions = true; + may_be_writable = true; } break; case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER: { info.type = UNIFORM_TYPE_TEXTURE_BUFFER; @@ -4691,6 +4681,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER: { info.type = UNIFORM_TYPE_IMAGE_BUFFER; need_array_dimensions = true; + may_be_writable = true; } break; case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { info.type = UNIFORM_TYPE_UNIFORM_BUFFER; @@ -4699,6 +4690,7 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_BUFFER: { info.type = UNIFORM_TYPE_STORAGE_BUFFER; need_block_size = true; + may_be_writable = true; } break; case SPV_REFLECT_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC: { ERR_PRINT("Dynamic uniform buffer not supported."); @@ -4737,17 +4729,11 @@ Vector<uint8_t> RenderingDeviceVulkan::shader_compile_binary_from_spirv(const Ve info.length = 0; } - SpvReflectInterfaceVariable *interface_var = nullptr; - for (uint32_t k = 0; k < interface_vars_count; k++) { - if (interface_vars[k]->spirv_id == binding.spirv_id) { - interface_var = interface_vars[k]; - break; - } + if (may_be_writable) { + info.writable = !(bool)(binding.type_description->decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE); + } else { + info.writable = false; } - ERR_FAIL_COND_V_MSG(!interface_var, Vector<uint8_t>(), - "Reflection of SPIR-V shader stage '" + String(shader_stage_names[p_spirv[i].shader_stage]) + "' failed finding interface variable."); - - info.writable = !(bool)(interface_var->decoration_flags & SPV_REFLECT_DECORATION_NON_WRITABLE); info.binding = binding.binding; uint32_t set = binding.set; diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index c209c67dcb..408d6af022 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -428,6 +428,9 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da case RemoteDebugger::MESSAGE_TYPE_LOG: { msg_type = EditorLog::MSG_TYPE_STD; } break; + case RemoteDebugger::MESSAGE_TYPE_LOG_RICH: { + msg_type = EditorLog::MSG_TYPE_STD_RICH; + } break; case RemoteDebugger::MESSAGE_TYPE_ERROR: { msg_type = EditorLog::MSG_TYPE_ERROR; } break; diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index aff328bba7..70622e85ff 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -1304,7 +1304,7 @@ void EditorPropertyObjectID::update_property() { ObjectID id = get_edited_object()->get(get_edited_property()); if (id.is_valid()) { - edit->set_text(type + " ID: " + itos(id)); + edit->set_text(type + " ID: " + uitos(id)); edit->set_disabled(false); edit->set_icon(EditorNode::get_singleton()->get_class_icon(type)); } else { @@ -1328,6 +1328,54 @@ EditorPropertyObjectID::EditorPropertyObjectID() { edit->connect("pressed", callable_mp(this, &EditorPropertyObjectID::_edit_pressed)); } +///////////////////// SIGNAL ///////////////////////// + +void EditorPropertySignal::_edit_pressed() { + Signal signal = get_edited_object()->get(get_edited_property()); + emit_signal(SNAME("object_id_selected"), get_edited_property(), signal.get_object_id()); +} + +void EditorPropertySignal::update_property() { + String type = base_type; + + Signal signal = get_edited_object()->get(get_edited_property()); + + edit->set_text("Signal: " + signal.get_name()); + edit->set_disabled(false); + edit->set_icon(get_theme_icon(SNAME("Signals"), SNAME("EditorIcons"))); +} + +void EditorPropertySignal::_bind_methods() { +} + +EditorPropertySignal::EditorPropertySignal() { + edit = memnew(Button); + add_child(edit); + add_focusable(edit); + edit->connect("pressed", callable_mp(this, &EditorPropertySignal::_edit_pressed)); +} + +///////////////////// CALLABLE ///////////////////////// + +void EditorPropertyCallable::update_property() { + String type = base_type; + + Callable callable = get_edited_object()->get(get_edited_property()); + + edit->set_text("Callable"); + edit->set_disabled(true); + edit->set_icon(get_theme_icon(SNAME("Callable"), SNAME("EditorIcons"))); +} + +void EditorPropertyCallable::_bind_methods() { +} + +EditorPropertyCallable::EditorPropertyCallable() { + edit = memnew(Button); + add_child(edit); + add_focusable(edit); +} + ///////////////////// FLOAT ///////////////////////// void EditorPropertyFloat::_set_read_only(bool p_read_only) { @@ -3222,8 +3270,8 @@ EditorPropertyNodePath::EditorPropertyNodePath() { void EditorPropertyRID::update_property() { RID rid = get_edited_object()->get(get_edited_property()); if (rid.is_valid()) { - int id = rid.get_id(); - label->set_text("RID: " + itos(id)); + uint64_t id = rid.get_id(); + label->set_text("RID: " + uitos(id)); } else { label->set_text(TTR("Invalid RID")); } @@ -4002,6 +4050,14 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_ } } break; + case Variant::CALLABLE: { + EditorPropertyCallable *editor = memnew(EditorPropertyCallable); + return editor; + } break; + case Variant::SIGNAL: { + EditorPropertySignal *editor = memnew(EditorPropertySignal); + return editor; + } break; case Variant::DICTIONARY: { if (p_hint == PROPERTY_HINT_LOCALIZABLE_STRING) { EditorPropertyLocalizableString *editor = memnew(EditorPropertyLocalizableString); diff --git a/editor/editor_properties.h b/editor/editor_properties.h index 7cd6ea4f6b..7bec2d0013 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -389,6 +389,33 @@ public: EditorPropertyObjectID(); }; +class EditorPropertySignal : public EditorProperty { + GDCLASS(EditorPropertySignal, EditorProperty); + Button *edit = nullptr; + String base_type; + void _edit_pressed(); + +protected: + static void _bind_methods(); + +public: + virtual void update_property() override; + EditorPropertySignal(); +}; + +class EditorPropertyCallable : public EditorProperty { + GDCLASS(EditorPropertyCallable, EditorProperty); + Button *edit = nullptr; + String base_type; + +protected: + static void _bind_methods(); + +public: + virtual void update_property() override; + EditorPropertyCallable(); +}; + class EditorPropertyFloat : public EditorProperty { GDCLASS(EditorPropertyFloat, EditorProperty); EditorSpinSlider *spin = nullptr; diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index 15f03fd46d..98e80c5513 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -59,7 +59,7 @@ void TexturePreview::_notification(int p_what) { } void TexturePreview::_update_metadata_label_text() { - Ref<Texture2D> texture = texture_display->get_texture(); + const Ref<Texture2D> texture = texture_display->get_texture(); String format; if (Object::cast_to<ImageTexture>(*texture)) { @@ -70,7 +70,49 @@ void TexturePreview::_update_metadata_label_text() { format = texture->get_class(); } - metadata_label->set_text(vformat(String::utf8("%s×%s %s"), itos(texture->get_width()), itos(texture->get_height()), format)); + const Ref<Image> image = texture->get_image(); + if (image.is_valid()) { + const int mipmaps = image->get_mipmap_count(); + // Avoid signed integer overflow that could occur with huge texture sizes by casting everything to uint64_t. + uint64_t memory = uint64_t(image->get_width()) * uint64_t(image->get_height()) * uint64_t(Image::get_format_pixel_size(image->get_format())); + // Handle VRAM-compressed formats that are stored with 4 bpp. + memory >>= Image::get_format_pixel_rshift(image->get_format()); + + float mipmaps_multiplier = 1.0; + float mipmap_increase = 0.25; + for (int i = 0; i < mipmaps; i++) { + // Each mip adds 25% memory usage of the previous one. + // With a complete mipmap chain, memory usage increases by ~33%. + mipmaps_multiplier += mipmap_increase; + mipmap_increase *= 0.25; + } + memory *= mipmaps_multiplier; + + if (mipmaps >= 1) { + metadata_label->set_text( + vformat(String::utf8("%d×%d %s\n") + TTR("%s Mipmaps") + "\n" + TTR("Memory: %s"), + texture->get_width(), + texture->get_height(), + format, + mipmaps, + String::humanize_size(memory))); + } else { + // "No Mipmaps" is easier to distinguish than "0 Mipmaps", + // especially since 0, 6, and 8 look quite close with the default code font. + metadata_label->set_text( + vformat(String::utf8("%d×%d %s\n") + TTR("No Mipmaps") + "\n" + TTR("Memory: %s"), + texture->get_width(), + texture->get_height(), + format, + String::humanize_size(memory))); + } + } else { + metadata_label->set_text( + vformat(String::utf8("%d×%d %s"), + texture->get_width(), + texture->get_height(), + format)); + } } TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) { @@ -97,11 +139,9 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) { metadata_label->add_theme_color_override("font_color", Color::named("white")); metadata_label->add_theme_color_override("font_color_shadow", Color::named("black")); - metadata_label->add_theme_font_size_override("font_size", 16 * EDSCALE); + metadata_label->add_theme_font_size_override("font_size", 14 * EDSCALE); metadata_label->add_theme_color_override("font_outline_color", Color::named("black")); - metadata_label->add_theme_constant_override("outline_size", 2 * EDSCALE); - - metadata_label->add_theme_constant_override("shadow_outline_size", 1); + metadata_label->add_theme_constant_override("outline_size", 8 * EDSCALE); metadata_label->set_h_size_flags(Control::SIZE_SHRINK_END); metadata_label->set_v_size_flags(Control::SIZE_SHRINK_END); diff --git a/main/main.cpp b/main/main.cpp index f3c56c7205..00b7483406 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -673,6 +673,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph packed_data->add_pack_source(zip_packed_data); #endif + // Default exit code, can be modified for certain errors. + Error exit_code = ERR_INVALID_PARAMETER; + I = args.front(); while (I) { #ifdef OSX_ENABLED @@ -688,10 +691,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph if (I->get() == "-h" || I->get() == "--help" || I->get() == "/?") { // display help show_help = true; + exit_code = OK; goto error; } else if (I->get() == "--version") { print_line(get_full_version_string()); + exit_code = OK; goto error; } else if (I->get() == "-v" || I->get() == "--verbose") { // verbose output @@ -1636,7 +1641,7 @@ error: OS::get_singleton()->finalize_core(); locale = String(); - return ERR_INVALID_PARAMETER; + return exit_code; } Error Main::setup2(Thread::ID p_main_tid_override) { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 118e77c009..6e2db68db0 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -2344,7 +2344,7 @@ void Control::set_focus_mode(FocusMode p_focus_mode) { static Control *_next_control(Control *p_from) { if (p_from->is_set_as_top_level()) { - return nullptr; // can't go above + return nullptr; // Can't go above. } Control *parent = Object::cast_to<Control>(p_from->get_parent()); @@ -2364,7 +2364,7 @@ static Control *_next_control(Control *p_from) { return c; } - //no next in parent, try the same in parent + // No next in parent, try the same in parent. return _next_control(parent); } @@ -2388,7 +2388,7 @@ Control *Control::find_next_valid_focus() const { } } - // find next child + // Find next child. Control *next_child = nullptr; @@ -2404,7 +2404,7 @@ Control *Control::find_next_valid_focus() const { if (!next_child) { next_child = _next_control(from); - if (!next_child) { //nothing else.. go up and find either window or subwindow + if (!next_child) { // Nothing else. Go up and find either window or subwindow. next_child = const_cast<Control *>(this); while (next_child && !next_child->is_set_as_top_level()) { next_child = cast_to<Control>(next_child->get_parent()); @@ -2422,7 +2422,7 @@ Control *Control::find_next_valid_focus() const { } } - if (next_child == this) { // no next control-> + if (next_child == from || next_child == this) { // No next control. return (get_focus_mode() == FOCUS_ALL) ? next_child : nullptr; } if (next_child) { @@ -2454,7 +2454,7 @@ static Control *_prev_control(Control *p_from) { return p_from; } - //no prev in parent, try the same in parent + // No prev in parent, try the same in parent. return _prev_control(child); } @@ -2478,12 +2478,12 @@ Control *Control::find_prev_valid_focus() const { } } - // find prev child + // Find prev child. Control *prev_child = nullptr; if (from->is_set_as_top_level() || !Object::cast_to<Control>(from->get_parent())) { - //find last of the children + // Find last of the children. prev_child = _prev_control(from); @@ -2506,7 +2506,7 @@ Control *Control::find_prev_valid_focus() const { } } - if (prev_child == this) { // no prev control-> + if (prev_child == from || prev_child == this) { // No prev control. return (get_focus_mode() == FOCUS_ALL) ? prev_child : nullptr; } |