diff options
55 files changed, 883 insertions, 380 deletions
diff --git a/core/SCsub b/core/SCsub index 3814c72877..df3e7a547a 100644 --- a/core/SCsub +++ b/core/SCsub @@ -129,9 +129,8 @@ if env["builtin_zstd"]: "decompress/zstd_decompress_block.c", "decompress/zstd_decompress.c", ] - if env["platform"] in ["android", "linuxbsd", "osx"]: + if env["platform"] in ["android", "iphone", "linuxbsd", "osx"]: # Match platforms with ZSTD_ASM_SUPPORTED in common/portability_macros.h - # iOS x86_64 should be supported in theory, but it fails arm64 build, seems to use host S_compiler. thirdparty_zstd_sources.append("decompress/huf_decompress_amd64.S") thirdparty_zstd_sources = [thirdparty_zstd_dir + file for file in thirdparty_zstd_sources] diff --git a/core/core_bind.cpp b/core/core_bind.cpp index fc91f83462..24b27d2692 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); @@ -1820,13 +1840,14 @@ void Thread::_start_func(void *ud) { ERR_FAIL_MSG(vformat("Could not call function '%s' on previously freed instance to start thread %s.", t->target_callable.get_method(), t->get_id())); } - ::Thread::set_name(t->target_callable.get_method()); + String func_name = t->target_callable.is_custom() ? t->target_callable.get_custom()->get_as_text() : String(t->target_callable.get_method()); + ::Thread::set_name(func_name); Callable::CallError ce; t->target_callable.call(nullptr, 0, t->ret, ce); if (ce.error != Callable::CallError::CALL_OK) { t->running.clear(); - ERR_FAIL_MSG("Could not call function '" + t->target_callable.get_method().operator String() + "' to start thread " + t->get_id() + ": " + Variant::get_callable_error_text(t->target_callable, nullptr, 0, ce) + "."); + ERR_FAIL_MSG("Could not call function '" + func_name + "' to start thread " + t->get_id() + ": " + Variant::get_callable_error_text(t->target_callable, nullptr, 0, ce) + "."); } t->running.clear(); 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/local_debugger.cpp b/core/debugger/local_debugger.cpp index 06e08081e9..58d239ccb9 100644 --- a/core/debugger/local_debugger.cpp +++ b/core/debugger/local_debugger.cpp @@ -31,7 +31,7 @@ #include "local_debugger.h" #include "core/debugger/script_debugger.h" -#include "scene/main/scene_tree.h" +#include "core/os/os.h" struct LocalDebugger::ScriptsProfiler { struct ProfileInfoSort { @@ -273,7 +273,10 @@ void LocalDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) { script_debugger->set_depth(-1); script_debugger->set_lines_left(-1); - SceneTree::get_singleton()->quit(); + MainLoop *main_loop = OS::get_singleton()->get_main_loop(); + if (main_loop->get_class() == "SceneTree") { + main_loop->call("quit"); + } break; } else if (line.begins_with("delete")) { if (line.get_slice_count(" ") <= 1) { 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 1a17d70e40..8e16a767cf 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/Decal.xml b/doc/classes/Decal.xml index c0ad61b77e..c38e1d1499 100644 --- a/doc/classes/Decal.xml +++ b/doc/classes/Decal.xml @@ -79,7 +79,7 @@ Sets the size of the [AABB] used by the decal. The AABB goes from [code]-extents[/code] to [code]extents[/code]. </member> <member name="lower_fade" type="float" setter="set_lower_fade" getter="get_lower_fade" default="0.3"> - Sets the curve over which the decal will fade as the surface gets further from the center of the [AABB]. + Sets the curve over which the decal will fade as the surface gets further from the center of the [AABB]. Only positive values are valid (negative values will be clamped to [code]0.0[/code]). </member> <member name="modulate" type="Color" setter="set_modulate" getter="get_modulate" default="Color(1, 1, 1, 1)"> Changes the [Color] of the Decal by multiplying it with this value. @@ -100,7 +100,7 @@ [Texture2D] storing ambient occlusion, roughness, and metallic for the decal. Use this to add extra detail to decals. </member> <member name="upper_fade" type="float" setter="set_upper_fade" getter="get_upper_fade" default="0.3"> - Sets the curve over which the decal will fade as the surface gets further from the center of the [AABB]. + Sets the curve over which the decal will fade as the surface gets further from the center of the [AABB]. Only positive values are valid (negative values will be clamped to [code]0.0[/code]). </member> </members> <constants> diff --git a/doc/classes/FileDialog.xml b/doc/classes/FileDialog.xml index 9d55704604..903f36d0ce 100644 --- a/doc/classes/FileDialog.xml +++ b/doc/classes/FileDialog.xml @@ -75,6 +75,9 @@ <member name="mode_overrides_title" type="bool" setter="set_mode_overrides_title" getter="is_mode_overriding_title" default="true"> If [code]true[/code], changing the [code]Mode[/code] property will set the window title accordingly (e.g. setting mode to [constant FILE_MODE_OPEN_FILE] will change the window title to "Open a File"). </member> + <member name="root_subfolder" type="String" setter="set_root_subfolder" getter="get_root_subfolder" default=""""> + If non-empty, the given sub-folder will be "root" of this [FileDialog], i.e. user won't be able to go to its parent directory. + </member> <member name="show_hidden_files" type="bool" setter="set_show_hidden_files" getter="is_showing_hidden_files" default="false"> If [code]true[/code], the dialog will show hidden files. </member> diff --git a/doc/classes/Node3D.xml b/doc/classes/Node3D.xml index ac434af4fa..ff2afd595a 100644 --- a/doc/classes/Node3D.xml +++ b/doc/classes/Node3D.xml @@ -281,6 +281,13 @@ <member name="basis" type="Basis" setter="set_basis" getter="get_basis"> Direct access to the 3x3 basis of the [Transform3D] property. </member> + <member name="global_position" type="Vector3" setter="set_global_position" getter="get_global_position"> + Global position of this node. This is equivalent to [code]global_transform.origin[/code]. + </member> + <member name="global_rotation" type="Vector3" setter="set_global_rotation" getter="get_global_rotation"> + Rotation part of the global transformation in radians, specified in terms of YXZ-Euler angles in the format (X angle, Y angle, Z angle). + [b]Note:[/b] In the mathematical sense, rotation is a matrix and not a vector. The three Euler angles, which are the three independent parameters of the Euler-angle parametrization of the rotation matrix, are stored in a [Vector3] data structure not because the rotation is a vector, but only because [Vector3] exists as a convenient data-structure to store 3 floating-point numbers. Therefore, applying affine operations on the rotation "vector" is not meaningful. + </member> <member name="global_transform" type="Transform3D" setter="set_global_transform" getter="get_global_transform"> World3D space (global) [Transform3D] of this node. </member> 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/ParticlesMaterial.xml b/doc/classes/ParticlesMaterial.xml index 885bedbc04..354fbd462c 100644 --- a/doc/classes/ParticlesMaterial.xml +++ b/doc/classes/ParticlesMaterial.xml @@ -77,28 +77,30 @@ Each particle's rotation will be animated along this [CurveTexture]. </member> <member name="angle_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0"> - Maximum angle. + Maximum initial rotation applied to each particle, in degrees. + Only applied when [member particle_flag_disable_z] or [member particle_flag_rotate_y] are [code]true[/code] or the [BaseMaterial3D] being used to draw the particle is using [constant BaseMaterial3D.BILLBOARD_PARTICLES]. </member> <member name="angle_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> - Minimum angle. + Minimum equivalent of [member angle_max]. </member> <member name="angular_velocity_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture"> Each particle's angular velocity (rotation speed) will vary along this [CurveTexture] over its lifetime. </member> <member name="angular_velocity_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0"> Maximum initial angular velocity (rotation speed) applied to each particle in [i]degrees[/i] per second. + Only applied when [member particle_flag_disable_z] or [member particle_flag_rotate_y] are [code]true[/code] or the [BaseMaterial3D] being used to draw the particle is using [constant BaseMaterial3D.BILLBOARD_PARTICLES]. </member> <member name="angular_velocity_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> - Minimum initial angular velocity (rotation speed) applied to each particle in [i]degrees[/i] per second. + Minimum equivalent of [member angular_velocity_max]. </member> <member name="anim_offset_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture"> Each particle's animation offset will vary along this [CurveTexture]. </member> <member name="anim_offset_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0"> - Maximum animation offset. + Maximum animation offset that corresponds to frame index in the texture. [code]0[/code] is the first frame, [code]1[/code] is the last one. See [member CanvasItemMaterial.particles_animation]. </member> <member name="anim_offset_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> - Minimum animation offset. + Minimum equivalent of [member anim_offset_max]. </member> <member name="anim_speed_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture"> Each particle's animation speed will vary along this [CurveTexture]. @@ -108,7 +110,7 @@ With animation speed greater than [code]1[/code], remember to enable [member CanvasItemMaterial.particles_anim_loop] property if you want the animation to repeat. </member> <member name="anim_speed_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> - Minimum particle animation speed. + Minimum equivalent of [member anim_speed_max]. </member> <member name="attractor_interaction_enabled" type="bool" setter="set_attractor_interaction_enabled" getter="is_attractor_interaction_enabled" default="true"> True if the interaction with particle attractors is enabled. @@ -138,8 +140,10 @@ Damping will vary along this [CurveTexture]. </member> <member name="damping_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0"> + The maximum rate at which particles lose velocity. For example value of [code]100[/code] means that the particle will go from [code]100[/code] velocity to [code]0[/code] in [code]1[/code] second. </member> <member name="damping_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> + Minimum equivalent of [member damping_max]. </member> <member name="direction" type="Vector3" setter="set_direction" getter="get_direction" default="Vector3(1, 0, 0)"> Unit vector specifying the particles' emission direction. @@ -187,16 +191,16 @@ Each particle's hue will vary along this [CurveTexture]. </member> <member name="hue_variation_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0"> - Maximum hue variation. + Maximum initial hue variation applied to each particle. It will shift the particle color's hue. </member> <member name="hue_variation_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> - Minimum hue variation. + Minimum equivalent of [member hue_variation_max]. </member> <member name="initial_velocity_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0"> - Maximum initial velocity. + Maximum initial velocity magnitude for each particle. Direction comes from [member direction] and [member spread]. </member> <member name="initial_velocity_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> - Minimum initial velocity. + Minimum equivalent of [member initial_velocity_max]. </member> <member name="lifetime_randomness" type="float" setter="set_lifetime_randomness" getter="get_lifetime_randomness" default="0.0"> Particle lifetime randomness ratio. The lifetime will be multiplied by a value interpolated between [code]1.0[/code] and a random number less than one. For example a random ratio of [code]0.4[/code] would scale the original lifetime between [code]0.4-1.0[/code] of its original value. @@ -205,19 +209,20 @@ Each particle's linear acceleration will vary along this [CurveTexture]. </member> <member name="linear_accel_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0"> - Maximum linear acceleration. + Maximum linear acceleration applied to each particle in the direction of motion. </member> <member name="linear_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> - Minimum linear acceleration. + Minimum equivalent of [member linear_accel_min]. </member> <member name="orbit_velocity_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture"> Each particle's orbital velocity will vary along this [CurveTexture]. </member> <member name="orbit_velocity_max" type="float" setter="set_param_max" getter="get_param_max"> - Maximum orbit velocity. + Maximum orbital velocity applied to each particle. Makes the particles circle around origin. Specified in number of full rotations around origin per second. + Only available when [member particle_flag_disable_z] is [code]true[/code]. </member> <member name="orbit_velocity_min" type="float" setter="set_param_min" getter="get_param_min"> - Minimum orbit velocity. + Minimum equivalent of [member orbit_velocity_max]. </member> <member name="particle_flag_align_y" type="bool" setter="set_particle_flag" getter="get_particle_flag" default="false"> Align Y axis of particle with the direction of its velocity. @@ -232,19 +237,19 @@ Each particle's radial acceleration will vary along this [CurveTexture]. </member> <member name="radial_accel_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0"> - Maximum radial acceleration. + Maximum radial acceleration applied to each particle. Makes particle accelerate away from the origin or towards it if negative. </member> <member name="radial_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> - Minimum radial acceleration. + Minimum equivalent of [member radial_accel_max]. </member> <member name="scale_curve" type="Texture2D" setter="set_param_texture" getter="get_param_texture"> Each particle's scale will vary along this [CurveTexture]. If a [CurveXYZTexture] is supplied instead, the scale will be separated per-axis. </member> <member name="scale_max" type="float" setter="set_param_max" getter="get_param_max" default="1.0"> - Maximum scale. + Maximum initial scale applied to each particle. </member> <member name="scale_min" type="float" setter="set_param_min" getter="get_param_min" default="1.0"> - Minimum scale. + Minimum equivalent of [member scale_max]. </member> <member name="spread" type="float" setter="set_spread" getter="get_spread" default="45.0"> Each particle's initial direction range from [code]+spread[/code] to [code]-spread[/code] degrees. @@ -261,10 +266,10 @@ Each particle's tangential acceleration will vary along this [CurveTexture]. </member> <member name="tangential_accel_max" type="float" setter="set_param_max" getter="get_param_max" default="0.0"> - Maximum tangential acceleration. + Maximum tangential acceleration applied to each particle. Tangential acceleration is perpendicular to the particle's velocity giving the particles a swirling motion. </member> <member name="tangential_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0"> - Minimum tangential acceleration. + Minimum equivalent of [member tangential_accel_max]. </member> </members> <constants> 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/doc/classes/String.xml b/doc/classes/String.xml index f4d453700c..9f197dae02 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -180,7 +180,22 @@ <argument index="0" name="values" type="Variant" /> <argument index="1" name="placeholder" type="String" default=""{_}"" /> <description> - Formats the string by replacing all occurrences of [code]placeholder[/code] with [code]values[/code]. + Formats the string by replacing all occurrences of [code]placeholder[/code] with the elements of [code]values[/code]. + [code]values[/code] can be a [Dictionary] or an [Array]. Any underscores in [code]placeholder[/code] will be replaced with the corresponding keys in advance. Array elements use their index as keys. + [codeblock] + # Prints: Waiting for Godot is a play by Samuel Beckett, and Godot Engine is named after it. + var use_array_values = "Waiting for {0} is a play by {1}, and {0} Engine is named after it." + print(use_array_values.format(["Godot", "Samuel Beckett"])) + + # Prints: User 42 is Godot. + print("User {id} is {name}.".format({"id": 42, "name": "Godot"})) + [/codeblock] + Some additional handling is performed when [code]values[/code] is an array. If [code]placeholder[/code] does not contain an underscore, the elements of the array will be used to replace one occurrence of the placeholder in turn; If an array element is another 2-element array, it'll be interpreted as a key-value pair. + [codeblock] + # Prints: User 42 is Godot. + print("User {} is {}.".format([42, "Godot"], "{}")) + print("User {id} is {name}.".format([["id", 42], ["name", "Godot"]])) + [/codeblock] </description> </method> <method name="get_base_dir" qualifiers="const"> 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_help.cpp b/editor/editor_help.cpp index b4325f09c5..36360954d9 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -63,6 +63,8 @@ void EditorHelp::_update_theme() { doc_bold_font = get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts")); doc_title_font = get_theme_font(SNAME("doc_title"), SNAME("EditorFonts")); doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts")); + + doc_title_font_size = get_theme_font_size(SNAME("doc_title_size"), SNAME("EditorFonts")); } void EditorHelp::_search(bool p_search_previous) { @@ -362,8 +364,9 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) { void EditorHelp::_update_method_list(const Vector<DocData::MethodDoc> p_methods, bool &r_method_descrpitons) { Ref<Font> doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts")); - class_desc->pop(); - class_desc->pop(); + class_desc->pop(); // title font size + class_desc->pop(); // title font + class_desc->pop(); // title color class_desc->add_newline(); class_desc->push_font(doc_code_font); @@ -431,8 +434,9 @@ void EditorHelp::_update_method_descriptions(const DocData::ClassDoc p_classdoc, Ref<Font> doc_bold_font = get_theme_font(SNAME("doc_bold"), SNAME("EditorFonts")); Ref<Font> doc_code_font = get_theme_font(SNAME("doc_source"), SNAME("EditorFonts")); String link_color_text = title_color.to_html(false); - class_desc->pop(); - class_desc->pop(); + class_desc->pop(); // title font size + class_desc->pop(); // title font + class_desc->pop(); // title color class_desc->add_newline(); class_desc->add_newline(); @@ -535,15 +539,17 @@ void EditorHelp::_update_doc() { // Class name section_line.push_back(Pair<String, int>(TTR("Top"), 0)); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->push_color(title_color); class_desc->add_text(TTR("Class:") + " "); class_desc->add_image(icon, icon->get_width(), icon->get_height()); class_desc->add_text(" "); class_desc->push_color(headline_color); _add_text(edited_class); - class_desc->pop(); - class_desc->pop(); - class_desc->pop(); + class_desc->pop(); // color + class_desc->pop(); // color + class_desc->pop(); // font size + class_desc->pop(); // font class_desc->add_newline(); // Inheritance tree @@ -624,9 +630,11 @@ void EditorHelp::_update_doc() { description_line = class_desc->get_paragraph_count() - 2; class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Description")); - class_desc->pop(); - class_desc->pop(); + class_desc->pop(); // font size + class_desc->pop(); // font + class_desc->pop(); // color class_desc->add_newline(); class_desc->add_newline(); @@ -646,9 +654,11 @@ void EditorHelp::_update_doc() { if (cd.tutorials.size()) { class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Online Tutorials")); - class_desc->pop(); - class_desc->pop(); + class_desc->pop(); // font size + class_desc->pop(); // font + class_desc->pop(); // color class_desc->push_indent(1); class_desc->push_font(doc_code_font); @@ -694,9 +704,11 @@ void EditorHelp::_update_doc() { section_line.push_back(Pair<String, int>(TTR("Properties"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Properties")); - class_desc->pop(); - class_desc->pop(); + class_desc->pop(); // font size + class_desc->pop(); // font + class_desc->pop(); // color class_desc->add_newline(); class_desc->push_font(doc_code_font); @@ -858,6 +870,7 @@ void EditorHelp::_update_doc() { section_line.push_back(Pair<String, int>(TTR("Constructors"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Constructors")); _update_method_list(cd.constructors, constructor_descriptions); } @@ -869,6 +882,7 @@ void EditorHelp::_update_doc() { section_line.push_back(Pair<String, int>(TTR("Methods"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Methods")); _update_method_list(methods, method_descriptions); } @@ -881,6 +895,7 @@ void EditorHelp::_update_doc() { section_line.push_back(Pair<String, int>(TTR("Operators"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Operators")); _update_method_list(cd.operators, operator_descriptions); } @@ -890,9 +905,11 @@ void EditorHelp::_update_doc() { section_line.push_back(Pair<String, int>(TTR("Theme Properties"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Theme Properties")); - class_desc->pop(); - class_desc->pop(); + class_desc->pop(); // font size + class_desc->pop(); // font + class_desc->pop(); // color class_desc->add_newline(); class_desc->add_newline(); @@ -916,13 +933,15 @@ void EditorHelp::_update_doc() { class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); if (data_type_names.has(theme_data_type)) { class_desc->add_text(data_type_names[theme_data_type]); } else { class_desc->add_text(""); } - class_desc->pop(); - class_desc->pop(); + class_desc->pop(); // font size + class_desc->pop(); // font + class_desc->pop(); // color class_desc->add_newline(); class_desc->add_newline(); @@ -984,9 +1003,11 @@ void EditorHelp::_update_doc() { section_line.push_back(Pair<String, int>(TTR("Signals"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Signals")); - class_desc->pop(); - class_desc->pop(); + class_desc->pop(); // font size + class_desc->pop(); // font + class_desc->pop(); // color class_desc->add_newline(); class_desc->add_newline(); @@ -1070,9 +1091,11 @@ void EditorHelp::_update_doc() { section_line.push_back(Pair<String, int>(TTR("Enumerations"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Enumerations")); - class_desc->pop(); - class_desc->pop(); + class_desc->pop(); // font size + class_desc->pop(); // font + class_desc->pop(); // color class_desc->push_indent(1); class_desc->add_newline(); @@ -1174,9 +1197,11 @@ void EditorHelp::_update_doc() { section_line.push_back(Pair<String, int>(TTR("Constants"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Constants")); - class_desc->pop(); - class_desc->pop(); + class_desc->pop(); // font size + class_desc->pop(); // font + class_desc->pop(); // color class_desc->push_indent(1); class_desc->add_newline(); @@ -1235,9 +1260,11 @@ void EditorHelp::_update_doc() { section_line.push_back(Pair<String, int>(TTR("Property Descriptions"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Property Descriptions")); - class_desc->pop(); - class_desc->pop(); + class_desc->pop(); // font size + class_desc->pop(); // font + class_desc->pop(); // color class_desc->add_newline(); class_desc->add_newline(); @@ -1401,6 +1428,7 @@ void EditorHelp::_update_doc() { section_line.push_back(Pair<String, int>(TTR("Constructor Descriptions"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Constructor Descriptions")); _update_method_descriptions(cd, cd.constructors, "constructor"); } @@ -1410,6 +1438,7 @@ void EditorHelp::_update_doc() { section_line.push_back(Pair<String, int>(TTR("Method Descriptions"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Method Descriptions")); _update_method_descriptions(cd, methods, "method"); } @@ -1419,6 +1448,7 @@ void EditorHelp::_update_doc() { section_line.push_back(Pair<String, int>(TTR("Operator Descriptions"), class_desc->get_paragraph_count() - 2)); class_desc->push_color(title_color); class_desc->push_font(doc_title_font); + class_desc->push_font_size(doc_title_font_size); class_desc->add_text(TTR("Operator Descriptions")); _update_method_descriptions(cd, cd.operators, "operator"); } diff --git a/editor/editor_help.h b/editor/editor_help.h index 766a09f485..7f91a8102d 100644 --- a/editor/editor_help.h +++ b/editor/editor_help.h @@ -140,6 +140,8 @@ class EditorHelp : public VBoxContainer { Ref<Font> doc_title_font; Ref<Font> doc_code_font; + int doc_title_font_size; + int scroll_to = -1; void _update_theme(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index bf0d126de4..7697bbfdf4 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -461,7 +461,7 @@ void EditorNode::shortcut_input(const Ref<InputEvent> &p_event) { _editor_select(EDITOR_SCRIPT); } else if (ED_IS_SHORTCUT("editor/editor_help", p_event)) { emit_signal(SNAME("request_help_search"), ""); - } else if (ED_IS_SHORTCUT("editor/editor_assetlib", p_event) && StreamPeerSSL::is_available()) { + } else if (ED_IS_SHORTCUT("editor/editor_assetlib", p_event) && AssetLibraryEditorPlugin::is_available()) { _editor_select(EDITOR_ASSETLIB); } else if (ED_IS_SHORTCUT("editor/editor_next", p_event)) { _editor_select_next(); @@ -5753,12 +5753,12 @@ void EditorNode::_feature_profile_changed() { main_editor_buttons[EDITOR_3D]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)); main_editor_buttons[EDITOR_SCRIPT]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT)); - if (StreamPeerSSL::is_available()) { + if (AssetLibraryEditorPlugin::is_available()) { main_editor_buttons[EDITOR_ASSETLIB]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_ASSET_LIB)); } if ((profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D) && singleton->main_editor_buttons[EDITOR_3D]->is_pressed()) || (profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT) && singleton->main_editor_buttons[EDITOR_SCRIPT]->is_pressed()) || - (StreamPeerSSL::is_available() && profile->is_feature_disabled(EditorFeatureProfile::FEATURE_ASSET_LIB) && singleton->main_editor_buttons[EDITOR_ASSETLIB]->is_pressed())) { + (AssetLibraryEditorPlugin::is_available() && profile->is_feature_disabled(EditorFeatureProfile::FEATURE_ASSET_LIB) && singleton->main_editor_buttons[EDITOR_ASSETLIB]->is_pressed())) { _editor_select(EDITOR_2D); } } else { @@ -5770,7 +5770,7 @@ void EditorNode::_feature_profile_changed() { FileSystemDock::get_singleton()->set_visible(true); main_editor_buttons[EDITOR_3D]->set_visible(true); main_editor_buttons[EDITOR_SCRIPT]->set_visible(true); - if (StreamPeerSSL::is_available()) { + if (AssetLibraryEditorPlugin::is_available()) { main_editor_buttons[EDITOR_ASSETLIB]->set_visible(true); } } @@ -7074,13 +7074,11 @@ EditorNode::EditorNode() { // Asset Library can't work on Web editor for now as most assets are sourced // directly from GitHub which does not set CORS. -#ifndef JAVASCRIPT_ENABLED - if (StreamPeerSSL::is_available()) { + if (AssetLibraryEditorPlugin::is_available()) { add_editor_plugin(memnew(AssetLibraryEditorPlugin)); } else { WARN_PRINT("Asset Library not available, as it requires SSL to work."); } -#endif // Add interface before adding plugins. 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/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 249b3a6d6a..e9547e02e8 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "core/input/input.h" #include "core/io/json.h" +#include "core/io/stream_peer_ssl.h" #include "core/os/keyboard.h" #include "core/version.h" #include "editor/editor_file_dialog.h" @@ -290,12 +291,15 @@ EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() { hbox->add_child(previews_vbox); previews_vbox->add_theme_constant_override("separation", 15 * EDSCALE); previews_vbox->set_v_size_flags(Control::SIZE_EXPAND_FILL); + previews_vbox->set_h_size_flags(Control::SIZE_EXPAND_FILL); preview = memnew(TextureRect); previews_vbox->add_child(preview); preview->set_ignore_texture_size(true); preview->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED); preview->set_custom_minimum_size(Size2(640 * EDSCALE, 345 * EDSCALE)); + preview->set_v_size_flags(Control::SIZE_EXPAND_FILL); + preview->set_h_size_flags(Control::SIZE_EXPAND_FILL); previews_bg = memnew(PanelContainer); previews_vbox->add_child(previews_bg); @@ -1588,6 +1592,16 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) { /////// +bool AssetLibraryEditorPlugin::is_available() { +#ifdef JAVASCRIPT_ENABLED + // Asset Library can't work on Web editor for now as most assets are sourced + // directly from GitHub which does not set CORS. + return false; +#else + return StreamPeerSSL::is_available(); +#endif +} + void AssetLibraryEditorPlugin::make_visible(bool p_visible) { if (p_visible) { addon_library->show(); diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h index e09700b646..2b43719cdd 100644 --- a/editor/plugins/asset_library_editor_plugin.h +++ b/editor/plugins/asset_library_editor_plugin.h @@ -322,6 +322,8 @@ class AssetLibraryEditorPlugin : public EditorPlugin { EditorAssetLibrary *addon_library = nullptr; public: + static bool is_available(); + virtual String get_name() const override { return "AssetLib"; } bool has_main_screen() const override { return true; } virtual void edit(Object *p_object) override {} 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/editor/project_manager.cpp b/editor/project_manager.cpp index 2e7b6f7476..ef91128146 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -2792,10 +2792,7 @@ ProjectManager::ProjectManager() { center_box->add_child(settings_hb); } - // Asset Library can't work on Web editor for now as most assets are sourced - // directly from GitHub which does not set CORS. -#ifndef JAVASCRIPT_ENABLED - if (StreamPeerSSL::is_available()) { + if (AssetLibraryEditorPlugin::is_available()) { asset_library = memnew(EditorAssetLibrary(true)); asset_library->set_name(TTR("Asset Library Projects")); tabs->add_child(asset_library); @@ -2803,7 +2800,6 @@ ProjectManager::ProjectManager() { } else { WARN_PRINT("Asset Library not available, as it requires SSL to work."); } -#endif { // Dialogs 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/platform/iphone/detect.py b/platform/iphone/detect.py index 392a0151be..862f1fe50b 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -98,10 +98,12 @@ def configure(env): if env["ios_simulator"]: detect_darwin_sdk_path("iphonesimulator", env) + env.Append(ASFLAGS=["-mios-simulator-version-min=13.0"]) env.Append(CCFLAGS=["-mios-simulator-version-min=13.0"]) env.extra_suffix = ".simulator" + env.extra_suffix else: detect_darwin_sdk_path("iphone", env) + env.Append(ASFLAGS=["-miphoneos-version-min=11.0"]) env.Append(CCFLAGS=["-miphoneos-version-min=11.0"]) if env["arch"] == "x86_64": @@ -113,6 +115,7 @@ def configure(env): " -fasm-blocks -isysroot $IPHONESDK" ).split() ) + env.Append(ASFLAGS=["-arch", "x86_64"]) elif env["arch"] == "arm64": env.Append( CCFLAGS=( @@ -122,6 +125,7 @@ def configure(env): " -isysroot $IPHONESDK".split() ) ) + env.Append(ASFLAGS=["-arch", "arm64"]) env.Append(CPPDEFINES=["NEED_LONG_INT"]) # Disable exceptions on non-tools (template) builds diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 4aec111022..ce32674c88 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -1817,6 +1817,52 @@ bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_a return retval; } +bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const { + ERR_FAIL_COND_V(!windows.has(p_window), false); + const WindowData &wd = windows[p_window]; + + // Using EWMH -- Extended Window Manager Hints + Atom property = XInternAtom(x11_display, "_NET_WM_STATE", False); + Atom type; + int format; + unsigned long len; + unsigned long remaining; + unsigned char *data = nullptr; + bool retval = false; + + if (property == None) { + return retval; + } + + int result = XGetWindowProperty( + x11_display, + wd.x11_window, + property, + 0, + 1024, + False, + XA_ATOM, + &type, + &format, + &len, + &remaining, + &data); + + if (result == Success) { + Atom *atoms = (Atom *)data; + Atom wm_fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False); + for (uint64_t i = 0; i < len; i++) { + if (atoms[i] == wm_fullscreen) { + retval = true; + break; + } + } + XFree(data); + } + + return retval; +} + bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const { _THREAD_SAFE_METHOD_ return _window_maximize_check(p_window, "_NET_WM_ALLOWED_ACTIONS"); @@ -3604,6 +3650,8 @@ void DisplayServerX11::process_events() { case Expose: { DEBUG_LOG_X11("[%u] Expose window=%lu (%u), count='%u' \n", frame, event.xexpose.window, window_id, event.xexpose.count); + windows[window_id].fullscreen = _window_fullscreen_check(window_id); + Main::force_redraw(); } break; diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index 4beeddd3a8..a87f2bb6e1 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -265,6 +265,7 @@ class DisplayServerX11 : public DisplayServer { void _update_real_mouse_position(const WindowData &wd); bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const; + bool _window_fullscreen_check(WindowID p_window) const; void _update_size_hints(WindowID p_window); void _set_wm_fullscreen(WindowID p_window, bool p_enabled); void _set_wm_maximized(WindowID p_window, bool p_enabled); diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 8d848d2094..67c2b9af7a 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -79,10 +79,12 @@ def configure(env): if env["arch"] == "arm64": print("Building for macOS 11.0+, platform arm64.") + env.Append(ASFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"]) env.Append(CCFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"]) env.Append(LINKFLAGS=["-arch", "arm64", "-mmacosx-version-min=11.0"]) else: print("Building for macOS 10.12+, platform x86_64.") + env.Append(ASFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) env.Append(CCFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) env.Append(LINKFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.12"]) diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp index 7010709123..00a7e54131 100644 --- a/platform/osx/export/export_plugin.cpp +++ b/platform/osx/export/export_plugin.cpp @@ -1086,6 +1086,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p Ref<FileAccess> f = FileAccess::open(file, FileAccess::WRITE); if (f.is_valid()) { f->store_buffer(data.ptr(), data.size()); + f.unref(); if (is_execute) { // chmod with 0755 if the file is executable. FileAccess::set_unix_permissions(file, 0755); diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index 5a451a6dab..a5f7faffef 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -87,16 +87,19 @@ void NavigationAgent2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent2D::_avoidance_done); + ADD_GROUP("Pathfinding", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:px"), "set_path_desired_distance", "get_path_desired_distance"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:px"), "set_target_desired_distance", "get_target_desired_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,100,1,suffix:px"), "set_path_max_distance", "get_path_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); + + ADD_GROUP("Avoidance", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,500,0.01,suffix:px"), "set_radius", "get_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,100000,0.01,suffix:px"), "set_neighbor_dist", "get_neighbor_dist"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1"), "set_max_neighbors", "get_max_neighbors"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:s"), "set_time_horizon", "get_time_horizon"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,100000,0.01,suffix:px/s"), "set_max_speed", "get_max_speed"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,100,1,suffix:px"), "set_path_max_distance", "get_path_max_distance"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); ADD_SIGNAL(MethodInfo("path_changed")); ADD_SIGNAL(MethodInfo("target_reached")); diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index ab07f33ace..01cab493ec 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -72,7 +72,7 @@ real_t Decal::get_albedo_mix() const { } void Decal::set_upper_fade(real_t p_fade) { - upper_fade = p_fade; + upper_fade = MAX(p_fade, 0.0); RS::get_singleton()->decal_set_fade(decal, upper_fade, lower_fade); } @@ -81,7 +81,7 @@ real_t Decal::get_upper_fade() const { } void Decal::set_lower_fade(real_t p_fade) { - lower_fade = p_fade; + lower_fade = MAX(p_fade, 0.0); RS::get_singleton()->decal_set_fade(decal, upper_fade, lower_fade); } diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index e5ec444335..3752713d6a 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -91,18 +91,21 @@ void NavigationAgent3D::_bind_methods() { ClassDB::bind_method(D_METHOD("_avoidance_done", "new_velocity"), &NavigationAgent3D::_avoidance_done); + ADD_GROUP("Pathfinding", ""); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_path_desired_distance", "get_path_desired_distance"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_target_desired_distance", "get_target_desired_distance"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_radius", "get_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01,suffix:m"), "set_agent_height_offset", "get_agent_height_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1,suffix:m"), "set_path_max_distance", "get_path_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); + + ADD_GROUP("Avoidance", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "radius", PROPERTY_HINT_RANGE, "0.1,100,0.01,suffix:m"), "set_radius", "get_radius"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "neighbor_dist", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m"), "set_neighbor_dist", "get_neighbor_dist"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_neighbors", PROPERTY_HINT_RANGE, "1,10000,1"), "set_max_neighbors", "get_max_neighbors"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "time_horizon", PROPERTY_HINT_RANGE, "0.01,100,0.01,suffix:s"), "set_time_horizon", "get_time_horizon"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_speed", PROPERTY_HINT_RANGE, "0.1,10000,0.01,suffix:m/s"), "set_max_speed", "get_max_speed"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1,suffix:m"), "set_path_max_distance", "get_path_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_y"), "set_ignore_y", "get_ignore_y"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "avoidance_enabled"), "set_avoidance_enabled", "get_avoidance_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers"); ADD_SIGNAL(MethodInfo("path_changed")); ADD_SIGNAL(MethodInfo("target_reached")); diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index 4c00250162..04b1081516 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -237,6 +237,28 @@ void Node3D::set_quaternion(const Quaternion &p_quaternion) { } } +Vector3 Node3D::get_global_position() const { + return get_global_transform().get_origin(); +} + +void Node3D::set_global_position(const Vector3 &p_position) { + Transform3D transform = get_global_transform(); + transform.set_origin(p_position); + set_global_transform(transform); +} + +Vector3 Node3D::get_global_rotation() const { + return get_global_transform().get_basis().get_euler(); +} + +void Node3D::set_global_rotation(const Vector3 &p_euler_rad) { + Transform3D transform = get_global_transform(); + Basis new_basis = transform.get_basis(); + new_basis.set_euler(p_euler_rad); + transform.set_basis(new_basis); + set_global_transform(transform); +} + void Node3D::set_transform(const Transform3D &p_transform) { data.local_transform = p_transform; data.dirty = DIRTY_EULER_ROTATION_AND_SCALE; // Make rot/scale dirty. @@ -950,8 +972,14 @@ void Node3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_quaternion"), &Node3D::get_quaternion); ClassDB::bind_method(D_METHOD("set_basis", "basis"), &Node3D::set_basis); ClassDB::bind_method(D_METHOD("get_basis"), &Node3D::get_basis); + ClassDB::bind_method(D_METHOD("set_global_transform", "global"), &Node3D::set_global_transform); ClassDB::bind_method(D_METHOD("get_global_transform"), &Node3D::get_global_transform); + ClassDB::bind_method(D_METHOD("set_global_position", "position"), &Node3D::set_global_position); + ClassDB::bind_method(D_METHOD("get_global_position"), &Node3D::get_global_position); + ClassDB::bind_method(D_METHOD("set_global_rotation", "radians"), &Node3D::set_global_rotation); + ClassDB::bind_method(D_METHOD("get_global_rotation"), &Node3D::get_global_rotation); + ClassDB::bind_method(D_METHOD("get_parent_node_3d"), &Node3D::get_parent_node_3d); ClassDB::bind_method(D_METHOD("set_ignore_transform_notification", "enabled"), &Node3D::set_ignore_transform_notification); ClassDB::bind_method(D_METHOD("set_as_top_level", "enable"), &Node3D::set_as_top_level); @@ -1034,6 +1062,9 @@ void Node3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_edit_mode", PROPERTY_HINT_ENUM, "Euler,Quaternion,Basis"), "set_rotation_edit_mode", "get_rotation_edit_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_order", PROPERTY_HINT_ENUM, "XYZ,XZY,YXZ,YZX,ZXY,ZYX"), "set_rotation_order", "get_rotation_order"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "top_level"), "set_as_top_level", "is_set_as_top_level"); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_position", "get_global_position"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "global_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_global_rotation", "get_global_rotation"); ADD_GROUP("Visibility", ""); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "visibility_parent", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GeometryInstance3D"), "set_visibility_parent", "get_visibility_parent"); diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index cfd88585e4..b1e129798d 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -182,12 +182,18 @@ public: void set_rotation(const Vector3 &p_euler_rad); void set_scale(const Vector3 &p_scale); + void set_global_position(const Vector3 &p_position); + void set_global_rotation(const Vector3 &p_euler_rad); + Vector3 get_position() const; RotationOrder get_rotation_order() const; Vector3 get_rotation() const; Vector3 get_scale() const; + Vector3 get_global_position() const; + Vector3 get_global_rotation() const; + void set_transform(const Transform3D &p_transform); void set_basis(const Basis &p_basis); void set_quaternion(const Quaternion &p_quaternion); 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; } diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 0e0f8bde83..73effa6c4b 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -170,7 +170,11 @@ Vector<String> FileDialog::get_selected_files() const { }; void FileDialog::update_dir() { - dir->set_text(dir_access->get_current_dir(false)); + if (root_prefix.is_empty()) { + dir->set_text(dir_access->get_current_dir(false)); + } else { + dir->set_text(dir_access->get_current_dir(false).trim_prefix(root_prefix).trim_prefix("/")); + } if (drives->is_visible()) { if (dir_access->get_current_dir().is_network_share_path()) { @@ -188,10 +192,8 @@ void FileDialog::update_dir() { } void FileDialog::_dir_submitted(String p_dir) { - dir_access->change_dir(p_dir); + _change_dir(root_prefix.plus_file(p_dir)); file->set_text(""); - invalidate(); - update_dir(); _push_history(); } @@ -378,9 +380,7 @@ bool FileDialog::_is_open_should_be_disabled() { } void FileDialog::_go_up() { - dir_access->change_dir(".."); - update_file_list(); - update_dir(); + _change_dir(".."); _push_history(); } @@ -390,9 +390,7 @@ void FileDialog::_go_back() { } local_history_pos--; - dir_access->change_dir(local_history[local_history_pos]); - update_file_list(); - update_dir(); + _change_dir(local_history[local_history_pos]); dir_prev->set_disabled(local_history_pos == 0); dir_next->set_disabled(local_history_pos == local_history.size() - 1); @@ -404,9 +402,7 @@ void FileDialog::_go_forward() { } local_history_pos++; - dir_access->change_dir(local_history[local_history_pos]); - update_file_list(); - update_dir(); + _change_dir(local_history[local_history_pos]); dir_prev->set_disabled(local_history_pos == 0); dir_next->set_disabled(local_history_pos == local_history.size() - 1); @@ -465,12 +461,10 @@ void FileDialog::_tree_item_activated() { Dictionary d = ti->get_metadata(0); if (d["dir"]) { - dir_access->change_dir(d["name"]); + _change_dir(d["name"]); if (mode == FILE_MODE_OPEN_FILE || mode == FILE_MODE_OPEN_FILES || mode == FILE_MODE_OPEN_DIR || mode == FILE_MODE_OPEN_ANY) { file->set_text(""); } - call_deferred(SNAME("_update_file_list")); - call_deferred(SNAME("_update_dir")); _push_history(); } else { _action_pressed(); @@ -704,9 +698,7 @@ String FileDialog::get_current_path() const { } void FileDialog::set_current_dir(const String &p_dir) { - dir_access->change_dir(p_dir); - update_dir(); - invalidate(); + _change_dir(p_dir); _push_history(); } @@ -732,6 +724,27 @@ void FileDialog::set_current_path(const String &p_path) { } } +void FileDialog::set_root_subfolder(const String &p_root) { + root_subfolder = p_root; + ERR_FAIL_COND_MSG(!dir_access->dir_exists(p_root), "root_subfolder must be an existing sub-directory."); + + local_history.clear(); + local_history_pos = -1; + + dir_access->change_dir(root_subfolder); + if (root_subfolder.is_empty()) { + root_prefix = ""; + } else { + root_prefix = dir_access->get_current_dir(); + } + invalidate(); + update_dir(); +} + +String FileDialog::get_root_subfolder() const { + return root_subfolder; +} + void FileDialog::set_mode_overrides_title(bool p_override) { mode_overrides_title = p_override; } @@ -810,6 +823,8 @@ void FileDialog::set_access(Access p_access) { } break; } access = p_access; + root_prefix = ""; + root_subfolder = ""; _update_drives(); invalidate(); update_filters(); @@ -832,10 +847,8 @@ FileDialog::Access FileDialog::get_access() const { void FileDialog::_make_dir_confirm() { Error err = dir_access->make_dir(makedirname->get_text().strip_edges()); if (err == OK) { - dir_access->change_dir(makedirname->get_text().strip_edges()); - invalidate(); + _change_dir(makedirname->get_text().strip_edges()); update_filters(); - update_dir(); _push_history(); } else { mkdirerr->popup_centered(Size2(250, 50)); @@ -850,11 +863,25 @@ void FileDialog::_make_dir() { void FileDialog::_select_drive(int p_idx) { String d = drives->get_item_text(p_idx); - dir_access->change_dir(d); + _change_dir(d); file->set_text(""); + _push_history(); +} + +void FileDialog::_change_dir(const String &p_new_dir) { + if (root_prefix.is_empty()) { + dir_access->change_dir(p_new_dir); + } else { + String old_dir = dir_access->get_current_dir(); + dir_access->change_dir(p_new_dir); + if (!dir_access->get_current_dir(false).begins_with(root_prefix)) { + dir_access->change_dir(old_dir); + return; + } + } + invalidate(); update_dir(); - _push_history(); } void FileDialog::_update_drives(bool p_select) { @@ -904,6 +931,8 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("get_line_edit"), &FileDialog::get_line_edit); ClassDB::bind_method(D_METHOD("set_access", "access"), &FileDialog::set_access); ClassDB::bind_method(D_METHOD("get_access"), &FileDialog::get_access); + ClassDB::bind_method(D_METHOD("set_root_subfolder", "dir"), &FileDialog::set_root_subfolder); + ClassDB::bind_method(D_METHOD("get_root_subfolder"), &FileDialog::get_root_subfolder); ClassDB::bind_method(D_METHOD("set_show_hidden_files", "show"), &FileDialog::set_show_hidden_files); ClassDB::bind_method(D_METHOD("is_showing_hidden_files"), &FileDialog::is_showing_hidden_files); ClassDB::bind_method(D_METHOD("_update_file_name"), &FileDialog::update_file_name); @@ -916,6 +945,7 @@ void FileDialog::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mode_overrides_title"), "set_mode_overrides_title", "is_mode_overriding_title"); ADD_PROPERTY(PropertyInfo(Variant::INT, "file_mode", PROPERTY_HINT_ENUM, "Open File,Open Files,Open Folder,Open Any,Save"), "set_file_mode", "get_file_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User Data,File System"), "set_access", "get_access"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "root_subfolder"), "set_root_subfolder", "get_root_subfolder"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "filters"), "set_filters", "get_filters"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir", PROPERTY_HINT_DIR, "", PROPERTY_USAGE_NONE), "set_current_dir", "get_current_dir"); diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 2e326d2949..8b8d93920c 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -101,6 +101,8 @@ private: void _push_history(); bool mode_overrides_title = true; + String root_subfolder; + String root_prefix; static bool default_show_hidden_files; bool show_hidden_files = false; @@ -131,6 +133,7 @@ private: void _go_back(); void _go_forward(); + void _change_dir(const String &p_new_dir); void _update_drives(bool p_select = true); virtual void shortcut_input(const Ref<InputEvent> &p_event) override; @@ -162,6 +165,9 @@ public: void set_current_file(const String &p_file); void set_current_path(const String &p_path); + void set_root_subfolder(const String &p_root); + String get_root_subfolder() const; + void set_mode_overrides_title(bool p_override); bool is_mode_overriding_title() const; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 545ff68b72..b4701637a4 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -439,9 +439,9 @@ void Node::set_physics_process(bool p_process) { data.physics_process = p_process; if (data.physics_process) { - add_to_group("physics_process", false); + add_to_group(SNAME("_physics_process"), false); } else { - remove_from_group("physics_process"); + remove_from_group(SNAME("_physics_process")); } } @@ -457,9 +457,9 @@ void Node::set_physics_process_internal(bool p_process_internal) { data.physics_process_internal = p_process_internal; if (data.physics_process_internal) { - add_to_group("physics_process_internal", false); + add_to_group(SNAME("_physics_process_internal"), false); } else { - remove_from_group("physics_process_internal"); + remove_from_group(SNAME("_physics_process_internal")); } } @@ -770,9 +770,9 @@ void Node::set_process(bool p_process) { data.process = p_process; if (data.process) { - add_to_group("process", false); + add_to_group(SNAME("_process"), false); } else { - remove_from_group("process"); + remove_from_group(SNAME("_process")); } } @@ -788,9 +788,9 @@ void Node::set_process_internal(bool p_process_internal) { data.process_internal = p_process_internal; if (data.process_internal) { - add_to_group("process_internal", false); + add_to_group(SNAME("_process_internal"), false); } else { - remove_from_group("process_internal"); + remove_from_group(SNAME("_process_internal")); } } @@ -807,19 +807,19 @@ void Node::set_process_priority(int p_priority) { } if (is_processing()) { - data.tree->make_group_changed("process"); + data.tree->make_group_changed(SNAME("_process")); } if (is_processing_internal()) { - data.tree->make_group_changed("process_internal"); + data.tree->make_group_changed(SNAME("_process_internal")); } if (is_physics_processing()) { - data.tree->make_group_changed("physics_process"); + data.tree->make_group_changed(SNAME("_physics_process")); } if (is_physics_processing_internal()) { - data.tree->make_group_changed("physics_process_internal"); + data.tree->make_group_changed(SNAME("_physics_process_internal")); } } diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 18f69ecc82..a76c00efcb 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -412,9 +412,9 @@ bool SceneTree::physics_process(double p_time) { emit_signal(SNAME("physics_frame")); - _notify_group_pause(SNAME("physics_process_internal"), Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS); + _notify_group_pause(SNAME("_physics_process_internal"), Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS); call_group(SNAME("_picking_viewports"), SNAME("_process_picking")); - _notify_group_pause(SNAME("physics_process"), Node::NOTIFICATION_PHYSICS_PROCESS); + _notify_group_pause(SNAME("_physics_process"), Node::NOTIFICATION_PHYSICS_PROCESS); _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack @@ -449,8 +449,8 @@ bool SceneTree::process(double p_time) { flush_transform_notifications(); - _notify_group_pause(SNAME("process_internal"), Node::NOTIFICATION_INTERNAL_PROCESS); - _notify_group_pause(SNAME("process"), Node::NOTIFICATION_PROCESS); + _notify_group_pause(SNAME("_process_internal"), Node::NOTIFICATION_INTERNAL_PROCESS); + _notify_group_pause(SNAME("_process"), Node::NOTIFICATION_PROCESS); _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack diff --git a/servers/movie_writer/movie_writer.cpp b/servers/movie_writer/movie_writer.cpp index 8560d92aa2..9f96b8cfda 100644 --- a/servers/movie_writer/movie_writer.cpp +++ b/servers/movie_writer/movie_writer.cpp @@ -30,7 +30,6 @@ #include "movie_writer.h" #include "core/config/project_settings.h" -#include "core/io/dir_access.h" MovieWriter *MovieWriter::writers[MovieWriter::MAX_WRITERS]; uint32_t MovieWriter::writer_count = 0; @@ -170,139 +169,3 @@ void MovieWriter::add_frame(const Ref<Image> &p_image) { void MovieWriter::end() { write_end(); } -///////////////////////////////////////// - -uint32_t MovieWriterPNGWAV::get_audio_mix_rate() const { - return mix_rate; -} -AudioServer::SpeakerMode MovieWriterPNGWAV::get_audio_speaker_mode() const { - return speaker_mode; -} - -void MovieWriterPNGWAV::get_supported_extensions(List<String> *r_extensions) const { - r_extensions->push_back("png"); -} - -bool MovieWriterPNGWAV::handles_file(const String &p_path) const { - return p_path.get_extension().to_lower() == "png"; -} - -String MovieWriterPNGWAV::zeros_str(uint32_t p_index) { - char zeros[MAX_TRAILING_ZEROS + 1]; - for (uint32_t i = 0; i < MAX_TRAILING_ZEROS; i++) { - uint32_t idx = MAX_TRAILING_ZEROS - i - 1; - uint32_t digit = (p_index / uint32_t(Math::pow(double(10), double(idx)))) % 10; - zeros[i] = '0' + digit; - } - zeros[MAX_TRAILING_ZEROS] = 0; - return zeros; -} - -Error MovieWriterPNGWAV::write_begin(const Size2i &p_movie_size, uint32_t p_fps, const String &p_base_path) { - // Quick & Dirty PNGWAV Code based on - https://docs.microsoft.com/en-us/windows/win32/directshow/avi-riff-file-reference - - base_path = p_base_path.get_basename(); - if (base_path.is_relative_path()) { - base_path = "res://" + base_path; - } - - { - //Remove existing files before writing anew - uint32_t idx = 0; - Ref<DirAccess> d = DirAccess::open(base_path.get_base_dir()); - String file = base_path.get_file(); - while (true) { - String path = file + zeros_str(idx) + ".png"; - if (d->remove(path) != OK) { - break; - } - } - } - - f_wav = FileAccess::open(base_path + ".wav", FileAccess::WRITE_READ); - ERR_FAIL_COND_V(f_wav.is_null(), ERR_CANT_OPEN); - - fps = p_fps; - - f_wav->store_buffer((const uint8_t *)"RIFF", 4); - int total_size = 4 /* WAVE */ + 8 /* fmt+size */ + 16 /* format */ + 8 /* data+size */; - f_wav->store_32(total_size); //will store final later - f_wav->store_buffer((const uint8_t *)"WAVE", 4); - - /* FORMAT CHUNK */ - - f_wav->store_buffer((const uint8_t *)"fmt ", 4); - - uint32_t channels = 2; - switch (speaker_mode) { - case AudioServer::SPEAKER_MODE_STEREO: - channels = 2; - break; - case AudioServer::SPEAKER_SURROUND_31: - channels = 4; - break; - case AudioServer::SPEAKER_SURROUND_51: - channels = 6; - break; - case AudioServer::SPEAKER_SURROUND_71: - channels = 8; - break; - } - - f_wav->store_32(16); //standard format, no extra fields - f_wav->store_16(1); // compression code, standard PCM - f_wav->store_16(channels); //CHANNELS: 2 - - f_wav->store_32(mix_rate); - - /* useless stuff the format asks for */ - - int bits_per_sample = 32; - int blockalign = bits_per_sample / 8 * channels; - int bytes_per_sec = mix_rate * blockalign; - - audio_block_size = (mix_rate / fps) * blockalign; - - f_wav->store_32(bytes_per_sec); - f_wav->store_16(blockalign); // block align (unused) - f_wav->store_16(bits_per_sample); - - /* DATA CHUNK */ - - f_wav->store_buffer((const uint8_t *)"data", 4); - - f_wav->store_32(0); //data size... wooh - wav_data_size_pos = f_wav->get_position(); - - return OK; -} - -Error MovieWriterPNGWAV::write_frame(const Ref<Image> &p_image, const int32_t *p_audio_data) { - ERR_FAIL_COND_V(!f_wav.is_valid(), ERR_UNCONFIGURED); - - Vector<uint8_t> png_buffer = p_image->save_png_to_buffer(); - - Ref<FileAccess> fi = FileAccess::open(base_path + zeros_str(frame_count) + ".png", FileAccess::WRITE); - fi->store_buffer(png_buffer.ptr(), png_buffer.size()); - f_wav->store_buffer((const uint8_t *)p_audio_data, audio_block_size); - - frame_count++; - - return OK; -} - -void MovieWriterPNGWAV::write_end() { - if (f_wav.is_valid()) { - uint32_t total_size = 4 /* WAVE */ + 8 /* fmt+size */ + 16 /* format */ + 8 /* data+size */; - uint32_t datasize = f_wav->get_position() - wav_data_size_pos; - f_wav->seek(4); - f_wav->store_32(total_size + datasize); - f_wav->seek(0x28); - f_wav->store_32(datasize); - } -} - -MovieWriterPNGWAV::MovieWriterPNGWAV() { - mix_rate = GLOBAL_GET("editor/movie_writer/mix_rate"); - speaker_mode = AudioServer::SpeakerMode(int(GLOBAL_GET("editor/movie_writer/speaker_mode"))); -} diff --git a/servers/movie_writer/movie_writer.h b/servers/movie_writer/movie_writer.h index 11e739df39..1ec6e93052 100644 --- a/servers/movie_writer/movie_writer.h +++ b/servers/movie_writer/movie_writer.h @@ -85,39 +85,4 @@ public: void end(); }; -class MovieWriterPNGWAV : public MovieWriter { - GDCLASS(MovieWriterPNGWAV, MovieWriter) - - enum { - MAX_TRAILING_ZEROS = 8 // more than 10 days at 60fps, no hard drive can put up with this anyway :) - }; - - uint32_t mix_rate = 48000; - AudioServer::SpeakerMode speaker_mode = AudioServer::SPEAKER_MODE_STEREO; - String base_path; - uint32_t frame_count = 0; - uint32_t fps = 0; - - uint32_t audio_block_size = 0; - - Ref<FileAccess> f_wav; - uint32_t wav_data_size_pos = 0; - - String zeros_str(uint32_t p_index); - -protected: - virtual uint32_t get_audio_mix_rate() const override; - virtual AudioServer::SpeakerMode get_audio_speaker_mode() const override; - virtual void get_supported_extensions(List<String> *r_extensions) const override; - - virtual Error write_begin(const Size2i &p_movie_size, uint32_t p_fps, const String &p_base_path) override; - virtual Error write_frame(const Ref<Image> &p_image, const int32_t *p_audio_data) override; - virtual void write_end() override; - - virtual bool handles_file(const String &p_path) const override; - -public: - MovieWriterPNGWAV(); -}; - -#endif // VIDEO_WRITER_H +#endif // MOVIE_WRITER_H diff --git a/servers/movie_writer/movie_writer_mjpeg.h b/servers/movie_writer/movie_writer_mjpeg.h index 822bedfedf..233267df30 100644 --- a/servers/movie_writer/movie_writer_mjpeg.h +++ b/servers/movie_writer/movie_writer_mjpeg.h @@ -70,4 +70,4 @@ public: MovieWriterMJPEG(); }; -#endif // MOVIE_WRITER_AVIJPEG_H +#endif // MOVIE_WRITER_MJPEG_H diff --git a/servers/movie_writer/movie_writer_pngwav.cpp b/servers/movie_writer/movie_writer_pngwav.cpp new file mode 100644 index 0000000000..bd79b0bd98 --- /dev/null +++ b/servers/movie_writer/movie_writer_pngwav.cpp @@ -0,0 +1,168 @@ +/*************************************************************************/ +/* movie_writer_pngwav.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "movie_writer_pngwav.h" +#include "core/config/project_settings.h" +#include "core/io/dir_access.h" + +uint32_t MovieWriterPNGWAV::get_audio_mix_rate() const { + return mix_rate; +} +AudioServer::SpeakerMode MovieWriterPNGWAV::get_audio_speaker_mode() const { + return speaker_mode; +} + +void MovieWriterPNGWAV::get_supported_extensions(List<String> *r_extensions) const { + r_extensions->push_back("png"); +} + +bool MovieWriterPNGWAV::handles_file(const String &p_path) const { + return p_path.get_extension().to_lower() == "png"; +} + +String MovieWriterPNGWAV::zeros_str(uint32_t p_index) { + char zeros[MAX_TRAILING_ZEROS + 1]; + for (uint32_t i = 0; i < MAX_TRAILING_ZEROS; i++) { + uint32_t idx = MAX_TRAILING_ZEROS - i - 1; + uint32_t digit = (p_index / uint32_t(Math::pow(double(10), double(idx)))) % 10; + zeros[i] = '0' + digit; + } + zeros[MAX_TRAILING_ZEROS] = 0; + return zeros; +} + +Error MovieWriterPNGWAV::write_begin(const Size2i &p_movie_size, uint32_t p_fps, const String &p_base_path) { + // Quick & Dirty PNGWAV Code based on - https://docs.microsoft.com/en-us/windows/win32/directshow/avi-riff-file-reference + + base_path = p_base_path.get_basename(); + if (base_path.is_relative_path()) { + base_path = "res://" + base_path; + } + + { + //Remove existing files before writing anew + uint32_t idx = 0; + Ref<DirAccess> d = DirAccess::open(base_path.get_base_dir()); + String file = base_path.get_file(); + while (true) { + String path = file + zeros_str(idx) + ".png"; + if (d->remove(path) != OK) { + break; + } + } + } + + f_wav = FileAccess::open(base_path + ".wav", FileAccess::WRITE_READ); + ERR_FAIL_COND_V(f_wav.is_null(), ERR_CANT_OPEN); + + fps = p_fps; + + f_wav->store_buffer((const uint8_t *)"RIFF", 4); + int total_size = 4 /* WAVE */ + 8 /* fmt+size */ + 16 /* format */ + 8 /* data+size */; + f_wav->store_32(total_size); //will store final later + f_wav->store_buffer((const uint8_t *)"WAVE", 4); + + /* FORMAT CHUNK */ + + f_wav->store_buffer((const uint8_t *)"fmt ", 4); + + uint32_t channels = 2; + switch (speaker_mode) { + case AudioServer::SPEAKER_MODE_STEREO: + channels = 2; + break; + case AudioServer::SPEAKER_SURROUND_31: + channels = 4; + break; + case AudioServer::SPEAKER_SURROUND_51: + channels = 6; + break; + case AudioServer::SPEAKER_SURROUND_71: + channels = 8; + break; + } + + f_wav->store_32(16); //standard format, no extra fields + f_wav->store_16(1); // compression code, standard PCM + f_wav->store_16(channels); //CHANNELS: 2 + + f_wav->store_32(mix_rate); + + /* useless stuff the format asks for */ + + int bits_per_sample = 32; + int blockalign = bits_per_sample / 8 * channels; + int bytes_per_sec = mix_rate * blockalign; + + audio_block_size = (mix_rate / fps) * blockalign; + + f_wav->store_32(bytes_per_sec); + f_wav->store_16(blockalign); // block align (unused) + f_wav->store_16(bits_per_sample); + + /* DATA CHUNK */ + + f_wav->store_buffer((const uint8_t *)"data", 4); + + f_wav->store_32(0); //data size... wooh + wav_data_size_pos = f_wav->get_position(); + + return OK; +} + +Error MovieWriterPNGWAV::write_frame(const Ref<Image> &p_image, const int32_t *p_audio_data) { + ERR_FAIL_COND_V(!f_wav.is_valid(), ERR_UNCONFIGURED); + + Vector<uint8_t> png_buffer = p_image->save_png_to_buffer(); + + Ref<FileAccess> fi = FileAccess::open(base_path + zeros_str(frame_count) + ".png", FileAccess::WRITE); + fi->store_buffer(png_buffer.ptr(), png_buffer.size()); + f_wav->store_buffer((const uint8_t *)p_audio_data, audio_block_size); + + frame_count++; + + return OK; +} + +void MovieWriterPNGWAV::write_end() { + if (f_wav.is_valid()) { + uint32_t total_size = 4 /* WAVE */ + 8 /* fmt+size */ + 16 /* format */ + 8 /* data+size */; + uint32_t datasize = f_wav->get_position() - wav_data_size_pos; + f_wav->seek(4); + f_wav->store_32(total_size + datasize); + f_wav->seek(0x28); + f_wav->store_32(datasize); + } +} + +MovieWriterPNGWAV::MovieWriterPNGWAV() { + mix_rate = GLOBAL_GET("editor/movie_writer/mix_rate"); + speaker_mode = AudioServer::SpeakerMode(int(GLOBAL_GET("editor/movie_writer/speaker_mode"))); +} diff --git a/servers/movie_writer/movie_writer_pngwav.h b/servers/movie_writer/movie_writer_pngwav.h new file mode 100644 index 0000000000..64608ce387 --- /dev/null +++ b/servers/movie_writer/movie_writer_pngwav.h @@ -0,0 +1,71 @@ +/*************************************************************************/ +/* movie_writer_pngwav.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef MOVIE_WRITER_PNGWAV_H +#define MOVIE_WRITER_PNGWAV_H + +#include "servers/movie_writer/movie_writer.h" + +class MovieWriterPNGWAV : public MovieWriter { + GDCLASS(MovieWriterPNGWAV, MovieWriter) + + enum { + MAX_TRAILING_ZEROS = 8 // more than 10 days at 60fps, no hard drive can put up with this anyway :) + }; + + uint32_t mix_rate = 48000; + AudioServer::SpeakerMode speaker_mode = AudioServer::SPEAKER_MODE_STEREO; + String base_path; + uint32_t frame_count = 0; + uint32_t fps = 0; + + uint32_t audio_block_size = 0; + + Ref<FileAccess> f_wav; + uint32_t wav_data_size_pos = 0; + + String zeros_str(uint32_t p_index); + +protected: + virtual uint32_t get_audio_mix_rate() const override; + virtual AudioServer::SpeakerMode get_audio_speaker_mode() const override; + virtual void get_supported_extensions(List<String> *r_extensions) const override; + + virtual Error write_begin(const Size2i &p_movie_size, uint32_t p_fps, const String &p_base_path) override; + virtual Error write_frame(const Ref<Image> &p_image, const int32_t *p_audio_data) override; + virtual void write_end() override; + + virtual bool handles_file(const String &p_path) const override; + +public: + MovieWriterPNGWAV(); +}; + +#endif // MOVIE_WRITER_PNGWAV_H diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index d7d2340119..db473f6296 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -59,6 +59,7 @@ #include "display_server.h" #include "movie_writer/movie_writer.h" #include "movie_writer/movie_writer_mjpeg.h" +#include "movie_writer/movie_writer_pngwav.h" #include "navigation_server_2d.h" #include "navigation_server_3d.h" #include "physics_2d/godot_physics_server_2d.h" diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index f3be4a7085..19c97eaeeb 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -3633,8 +3633,6 @@ void GI::process_gi(RID p_render_buffers, RID *p_normal_roughness_views, RID p_v RD::get_singleton()->free(rb->rbgi.reflection_buffer); } - print_line("Allocating GI buffers"); // TESTING REMOVE BEFORE MERGING - // Remember the view count we're using rb->rbgi.view_count = p_view_count; |