summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/core_bind.cpp20
-rw-r--r--core/core_bind.h4
-rw-r--r--core/debugger/local_debugger.cpp7
-rw-r--r--core/debugger/remote_debugger.cpp8
-rw-r--r--core/error/error_macros.cpp8
-rw-r--r--core/extension/native_extension.cpp28
-rw-r--r--core/object/object.cpp2
-rw-r--r--core/object/object.h8
-rw-r--r--core/object/script_language_extension.h6
-rw-r--r--doc/classes/ProjectSettings.xml6
-rw-r--r--doc/classes/ResourceLoader.xml16
-rw-r--r--doc/classes/ResourceSaver.xml16
-rw-r--r--doc/classes/SceneTree.xml3
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp30
-rw-r--r--editor/debugger/script_editor_debugger.cpp3
-rw-r--r--editor/editor_help.cpp80
-rw-r--r--editor/editor_help.h2
-rw-r--r--editor/editor_node.cpp12
-rw-r--r--editor/editor_run.cpp5
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp11
-rw-r--r--editor/plugins/asset_library_editor_plugin.h2
-rw-r--r--editor/plugins/debugger_editor_plugin.cpp13
-rw-r--r--editor/plugins/debugger_editor_plugin.h1
-rw-r--r--editor/plugins/texture_editor_plugin.cpp52
-rw-r--r--editor/project_manager.cpp6
-rw-r--r--main/main.cpp14
-rw-r--r--scene/2d/navigation_agent_2d.cpp9
-rw-r--r--scene/2d/path_2d.cpp14
-rw-r--r--scene/3d/navigation_agent_3d.cpp11
-rw-r--r--scene/3d/path_3d.cpp90
-rw-r--r--scene/3d/path_3d.h11
-rw-r--r--scene/gui/control.cpp18
-rw-r--r--scene/main/scene_tree.cpp46
-rw-r--r--scene/main/scene_tree.h17
-rw-r--r--servers/movie_writer/movie_writer.cpp137
-rw-r--r--servers/movie_writer/movie_writer.h37
-rw-r--r--servers/movie_writer/movie_writer_mjpeg.h2
-rw-r--r--servers/movie_writer/movie_writer_pngwav.cpp168
-rw-r--r--servers/movie_writer/movie_writer_pngwav.h71
-rw-r--r--servers/register_server_types.cpp1
40 files changed, 700 insertions, 295 deletions
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index fc91f83462..b5f4a1c0f6 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -83,6 +83,14 @@ Vector<String> ResourceLoader::get_recognized_extensions_for_type(const String &
return ret;
}
+void ResourceLoader::add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front) {
+ ::ResourceLoader::add_resource_format_loader(p_format_loader, p_at_front);
+}
+
+void ResourceLoader::remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader) {
+ ::ResourceLoader::remove_resource_format_loader(p_format_loader);
+}
+
void ResourceLoader::set_abort_on_missing_resources(bool p_abort) {
::ResourceLoader::set_abort_on_missing_resources(p_abort);
}
@@ -119,6 +127,8 @@ void ResourceLoader::_bind_methods() {
ClassDB::bind_method(D_METHOD("load", "path", "type_hint", "cache_mode"), &ResourceLoader::load, DEFVAL(""), DEFVAL(CACHE_MODE_REUSE));
ClassDB::bind_method(D_METHOD("get_recognized_extensions_for_type", "type"), &ResourceLoader::get_recognized_extensions_for_type);
+ ClassDB::bind_method(D_METHOD("add_resource_format_loader", "format_loader", "at_front"), &ResourceLoader::add_resource_format_loader, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("remove_resource_format_loader", "format_loader"), &ResourceLoader::remove_resource_format_loader);
ClassDB::bind_method(D_METHOD("set_abort_on_missing_resources", "abort"), &ResourceLoader::set_abort_on_missing_resources);
ClassDB::bind_method(D_METHOD("get_dependencies", "path"), &ResourceLoader::get_dependencies);
ClassDB::bind_method(D_METHOD("has_cached", "path"), &ResourceLoader::has_cached);
@@ -153,11 +163,21 @@ Vector<String> ResourceSaver::get_recognized_extensions(const Ref<Resource> &p_r
return ret;
}
+void ResourceSaver::add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front) {
+ ::ResourceSaver::add_resource_format_saver(p_format_saver, p_at_front);
+}
+
+void ResourceSaver::remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver) {
+ ::ResourceSaver::remove_resource_format_saver(p_format_saver);
+}
+
ResourceSaver *ResourceSaver::singleton = nullptr;
void ResourceSaver::_bind_methods() {
ClassDB::bind_method(D_METHOD("save", "path", "resource", "flags"), &ResourceSaver::save, DEFVAL((uint32_t)FLAG_NONE));
ClassDB::bind_method(D_METHOD("get_recognized_extensions", "type"), &ResourceSaver::get_recognized_extensions);
+ ClassDB::bind_method(D_METHOD("add_resource_format_saver", "format_saver", "at_front"), &ResourceSaver::add_resource_format_saver, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("remove_resource_format_saver", "format_saver"), &ResourceSaver::remove_resource_format_saver);
BIND_ENUM_CONSTANT(FLAG_NONE);
BIND_ENUM_CONSTANT(FLAG_RELATIVE_PATHS);
diff --git a/core/core_bind.h b/core/core_bind.h
index ec9bcdbc02..99e14a75f5 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -77,6 +77,8 @@ public:
Ref<Resource> load(const String &p_path, const String &p_type_hint = "", CacheMode p_cache_mode = CACHE_MODE_REUSE);
Vector<String> get_recognized_extensions_for_type(const String &p_type);
+ void add_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader, bool p_at_front);
+ void remove_resource_format_loader(Ref<ResourceFormatLoader> p_format_loader);
void set_abort_on_missing_resources(bool p_abort);
PackedStringArray get_dependencies(const String &p_path);
bool has_cached(const String &p_path);
@@ -109,6 +111,8 @@ public:
Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags);
Vector<String> get_recognized_extensions(const Ref<Resource> &p_resource);
+ void add_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver, bool p_at_front);
+ void remove_resource_format_saver(Ref<ResourceFormatSaver> p_format_saver);
ResourceSaver() { singleton = this; }
};
diff --git a/core/debugger/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/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/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 2391cb892c..553005c4c4 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -494,6 +494,12 @@
<member name="debug/shapes/navigation/geometry_color" type="Color" setter="" getter="" default="Color(0.1, 1, 0.7, 0.4)">
Color of the navigation geometry, visible when "Visible Navigation" is enabled in the Debug menu.
</member>
+ <member name="debug/shapes/paths/geometry_color" type="Color" setter="" getter="" default="Color(0.1, 1, 0.7, 0.4)">
+ Color of the curve path geometry, visible when "Visible Paths" is enabled in the Debug menu.
+ </member>
+ <member name="debug/shapes/paths/geometry_width" type="float" setter="" getter="" default="2.0">
+ Line width of the curve path geometry, visible when "Visible Paths" is enabled in the Debug menu.
+ </member>
<member name="display/mouse_cursor/custom_image" type="String" setter="" getter="" default="&quot;&quot;">
Custom image for the mouse cursor (limited to 256×256).
</member>
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/SceneTree.xml b/doc/classes/SceneTree.xml
index c6b80f171a..cf6ab977db 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -221,6 +221,9 @@
<member name="debug_navigation_hint" type="bool" setter="set_debug_navigation_hint" getter="is_debugging_navigation_hint" default="false">
If [code]true[/code], navigation polygons will be visible when running the game from the editor for debugging purposes.
</member>
+ <member name="debug_paths_hint" type="bool" setter="set_debug_paths_hint" getter="is_debugging_paths_hint" default="false">
+ If [code]true[/code], curves from [Path2D] and [Path3D] nodes will be visible when running the game from the editor for debugging purposes.
+ </member>
<member name="edited_scene_root" type="Node" setter="set_edited_scene_root" getter="get_edited_scene_root">
The root of the edited scene.
</member>
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 b196cadcb1..e3caaf93c6 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -460,7 +460,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();
@@ -5752,12 +5752,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 {
@@ -5769,7 +5769,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);
}
}
@@ -7073,13 +7073,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_run.cpp b/editor/editor_run.cpp
index 04a3bf2915..ba49c6dc5f 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -59,11 +59,16 @@ Error EditorRun::run(const String &p_scene, const String &p_write_movie) {
args.push_back(itos(OS::get_singleton()->get_process_id()));
bool debug_collisions = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_collisons", false);
+ bool debug_paths = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_paths", false);
bool debug_navigation = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_navigation", false);
if (debug_collisions) {
args.push_back("--debug-collisions");
}
+ if (debug_paths) {
+ args.push_back("--debug-paths");
+ }
+
if (debug_navigation) {
args.push_back("--debug-navigation");
}
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 249b3a6d6a..e9435faae1 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"
@@ -1588,6 +1589,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/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp
index 8ea50c4529..5c90d70982 100644
--- a/editor/plugins/debugger_editor_plugin.cpp
+++ b/editor/plugins/debugger_editor_plugin.cpp
@@ -72,6 +72,9 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(MenuButton *p_debug_menu) {
p->add_check_shortcut(ED_SHORTCUT("editor/visible_collision_shapes", TTR("Visible Collision Shapes")), RUN_DEBUG_COLLISONS);
p->set_item_tooltip(-1,
TTR("When this option is enabled, collision shapes and raycast nodes (for 2D and 3D) will be visible in the running project."));
+ p->add_check_shortcut(ED_SHORTCUT("editor/visible_paths", TTR("Visible Paths")), RUN_DEBUG_PATHS);
+ p->set_item_tooltip(-1,
+ TTR("When this option is enabled, curve resources used by path nodes will be visible in the running project."));
p->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION);
p->set_item_tooltip(-1,
TTR("When this option is enabled, navigation meshes and polygons will be visible in the running project."));
@@ -153,6 +156,12 @@ void DebuggerEditorPlugin::_menu_option(int p_option) {
EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_collisons", !ischecked);
} break;
+ case RUN_DEBUG_PATHS: {
+ bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_PATHS));
+ debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_PATHS), !ischecked);
+ EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_debug_paths", !ischecked);
+
+ } break;
case RUN_DEBUG_NAVIGATION: {
bool ischecked = debug_menu->get_popup()->is_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_NAVIGATION));
debug_menu->get_popup()->set_item_checked(debug_menu->get_popup()->get_item_index(RUN_DEBUG_NAVIGATION), !ischecked);
@@ -182,6 +191,7 @@ void DebuggerEditorPlugin::_update_debug_options() {
bool check_deploy_remote = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_deploy_remote_debug", false);
bool check_file_server = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_file_server", false);
bool check_debug_collisions = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_collisons", false);
+ bool check_debug_paths = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_paths", false);
bool check_debug_navigation = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_navigation", false);
bool check_live_debug = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_live_debug", true);
bool check_reload_scripts = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_reload_scripts", true);
@@ -196,6 +206,9 @@ void DebuggerEditorPlugin::_update_debug_options() {
if (check_debug_collisions) {
_menu_option(RUN_DEBUG_COLLISONS);
}
+ if (check_debug_paths) {
+ _menu_option(RUN_DEBUG_PATHS);
+ }
if (check_debug_navigation) {
_menu_option(RUN_DEBUG_NAVIGATION);
}
diff --git a/editor/plugins/debugger_editor_plugin.h b/editor/plugins/debugger_editor_plugin.h
index 10e1a27933..fb963385cd 100644
--- a/editor/plugins/debugger_editor_plugin.h
+++ b/editor/plugins/debugger_editor_plugin.h
@@ -49,6 +49,7 @@ private:
RUN_FILE_SERVER,
RUN_LIVE_DEBUG,
RUN_DEBUG_COLLISONS,
+ RUN_DEBUG_PATHS,
RUN_DEBUG_NAVIGATION,
RUN_DEPLOY_REMOTE_DEBUG,
RUN_RELOAD_SCRIPTS,
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 bfb0eacdfc..00b7483406 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -175,6 +175,7 @@ static Vector2 init_custom_pos;
static bool use_debug_profiler = false;
#ifdef DEBUG_ENABLED
static bool debug_collisions = false;
+static bool debug_paths = false;
static bool debug_navigation = false;
#endif
static int frame_delay = 0;
@@ -357,6 +358,7 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" --remote-debug <uri> Remote debug (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007).\n");
#if defined(DEBUG_ENABLED)
OS::get_singleton()->print(" --debug-collisions Show collision shapes when running the scene.\n");
+ OS::get_singleton()->print(" --debug-paths Show path lines when running the scene.\n");
OS::get_singleton()->print(" --debug-navigation Show navigation polygons when running the scene.\n");
OS::get_singleton()->print(" --debug-stringnames Print all StringName allocations to stdout when the engine quits.\n");
#endif
@@ -671,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
@@ -686,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
@@ -1107,6 +1114,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
#if defined(DEBUG_ENABLED)
} else if (I->get() == "--debug-collisions") {
debug_collisions = true;
+ } else if (I->get() == "--debug-paths") {
+ debug_paths = true;
} else if (I->get() == "--debug-navigation") {
debug_navigation = true;
} else if (I->get() == "--debug-stringnames") {
@@ -1632,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) {
@@ -2375,6 +2384,9 @@ bool Main::start() {
if (debug_collisions) {
sml->set_debug_collisions_hint(true);
}
+ if (debug_paths) {
+ sml->set_debug_paths_hint(true);
+ }
if (debug_navigation) {
sml->set_debug_navigation_hint(true);
}
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/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index ba90a275e6..8eb48ffb30 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -87,13 +87,13 @@ bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc
void Path2D::_notification(int p_what) {
switch (p_what) {
- // Draw the curve if navigation debugging is enabled.
+ // Draw the curve if path debugging is enabled.
case NOTIFICATION_DRAW: {
if (!curve.is_valid()) {
break;
}
- if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_navigation_hint()) {
+ if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_paths_hint()) {
return;
}
@@ -102,12 +102,10 @@ void Path2D::_notification(int p_what) {
}
#ifdef TOOLS_ENABLED
- const real_t line_width = 2 * EDSCALE;
+ const real_t line_width = get_tree()->get_debug_paths_width() * EDSCALE;
#else
- const real_t line_width = 2;
+ const real_t line_width = get_tree()->get_debug_paths_width();
#endif
- const Color color = Color(0.5, 0.6, 1.0, 0.7);
-
_cached_draw_pts.resize(curve->get_point_count() * 8);
int count = 0;
@@ -119,7 +117,7 @@ void Path2D::_notification(int p_what) {
}
}
- draw_polyline(_cached_draw_pts, color, line_width, true);
+ draw_polyline(_cached_draw_pts, get_tree()->get_debug_paths_color(), line_width, true);
} break;
}
}
@@ -129,7 +127,7 @@ void Path2D::_curve_changed() {
return;
}
- if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_navigation_hint()) {
+ if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_paths_hint()) {
return;
}
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/path_3d.cpp b/scene/3d/path_3d.cpp
index e13cf6f9c8..f53e783fbd 100644
--- a/scene/3d/path_3d.cpp
+++ b/scene/3d/path_3d.cpp
@@ -30,6 +30,92 @@
#include "path_3d.h"
+Path3D::Path3D() {
+ SceneTree *st = SceneTree::get_singleton();
+ if (st && st->is_debugging_paths_hint()) {
+ debug_instance = RS::get_singleton()->instance_create();
+ set_notify_transform(true);
+ _update_debug_mesh();
+ }
+}
+
+Path3D::~Path3D() {
+ if (debug_instance.is_valid()) {
+ RS::get_singleton()->free(debug_instance);
+ }
+ if (debug_mesh.is_valid()) {
+ RS::get_singleton()->free(debug_mesh->get_rid());
+ }
+}
+
+void Path3D::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ SceneTree *st = SceneTree::get_singleton();
+ if (st && st->is_debugging_paths_hint()) {
+ _update_debug_mesh();
+ }
+ } break;
+
+ case NOTIFICATION_EXIT_TREE: {
+ SceneTree *st = SceneTree::get_singleton();
+ if (st && st->is_debugging_paths_hint()) {
+ RS::get_singleton()->instance_set_visible(debug_instance, false);
+ }
+ } break;
+
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+ if (is_inside_tree() && debug_instance.is_valid()) {
+ RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform());
+ }
+ } break;
+ }
+}
+
+void Path3D::_update_debug_mesh() {
+ SceneTree *st = SceneTree::get_singleton();
+ if (!(st && st->is_debugging_paths_hint())) {
+ return;
+ }
+
+ if (!debug_mesh.is_valid()) {
+ debug_mesh = Ref<ArrayMesh>(memnew(ArrayMesh));
+ }
+
+ if (!(curve.is_valid())) {
+ RS::get_singleton()->instance_set_visible(debug_instance, false);
+ return;
+ }
+ if (curve->get_point_count() < 2) {
+ RS::get_singleton()->instance_set_visible(debug_instance, false);
+ return;
+ }
+
+ Vector<Vector3> vertex_array;
+
+ for (int i = 1; i < curve->get_point_count(); i++) {
+ Vector3 line_end = curve->get_point_position(i);
+ Vector3 line_start = curve->get_point_position(i - 1);
+ vertex_array.push_back(line_start);
+ vertex_array.push_back(line_end);
+ }
+
+ Array mesh_array;
+ mesh_array.resize(Mesh::ARRAY_MAX);
+ mesh_array[Mesh::ARRAY_VERTEX] = vertex_array;
+
+ debug_mesh->clear_surfaces();
+ debug_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, mesh_array);
+
+ RS::get_singleton()->instance_set_base(debug_instance, debug_mesh->get_rid());
+ RS::get_singleton()->mesh_surface_set_material(debug_mesh->get_rid(), 0, st->get_debug_paths_material()->get_rid());
+ if (is_inside_tree()) {
+ RS::get_singleton()->instance_set_scenario(debug_instance, get_world_3d()->get_scenario());
+ RS::get_singleton()->instance_set_transform(debug_instance, get_global_transform());
+ RS::get_singleton()->instance_set_visible(debug_instance, is_visible_in_tree());
+ }
+}
+
void Path3D::_curve_changed() {
if (is_inside_tree() && Engine::get_singleton()->is_editor_hint()) {
update_gizmos();
@@ -48,6 +134,10 @@ void Path3D::_curve_changed() {
}
}
}
+ SceneTree *st = SceneTree::get_singleton();
+ if (st && st->is_debugging_paths_hint()) {
+ _update_debug_mesh();
+ }
}
void Path3D::set_curve(const Ref<Curve3D> &p_curve) {
diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h
index cb67a044d1..7c7284534e 100644
--- a/scene/3d/path_3d.h
+++ b/scene/3d/path_3d.h
@@ -41,14 +41,23 @@ class Path3D : public Node3D {
void _curve_changed();
+ RID debug_instance;
+ Ref<ArrayMesh> debug_mesh;
+
+private:
+ void _update_debug_mesh();
+
protected:
+ void _notification(int p_what);
+
static void _bind_methods();
public:
void set_curve(const Ref<Curve3D> &p_curve);
Ref<Curve3D> get_curve() const;
- Path3D() {}
+ Path3D();
+ ~Path3D();
};
class PathFollow3D : public Node3D {
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 118e77c009..b7b0571c07 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) { // 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) { // No prev control.
return (get_focus_mode() == FOCUS_ALL) ? prev_child : nullptr;
}
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index dd77877c7d..18f69ecc82 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -659,6 +659,14 @@ bool SceneTree::is_debugging_collisions_hint() const {
return debug_collisions_hint;
}
+void SceneTree::set_debug_paths_hint(bool p_enabled) {
+ debug_paths_hint = p_enabled;
+}
+
+bool SceneTree::is_debugging_paths_hint() const {
+ return debug_paths_hint;
+}
+
void SceneTree::set_debug_navigation_hint(bool p_enabled) {
debug_navigation_hint = p_enabled;
}
@@ -684,6 +692,22 @@ Color SceneTree::get_debug_collision_contact_color() const {
return debug_collision_contact_color;
}
+void SceneTree::set_debug_paths_color(const Color &p_color) {
+ debug_paths_color = p_color;
+}
+
+Color SceneTree::get_debug_paths_color() const {
+ return debug_paths_color;
+}
+
+void SceneTree::set_debug_paths_width(float p_width) {
+ debug_paths_width = p_width;
+}
+
+float SceneTree::get_debug_paths_width() const {
+ return debug_paths_width;
+}
+
void SceneTree::set_debug_navigation_color(const Color &p_color) {
debug_navigation_color = p_color;
}
@@ -700,6 +724,23 @@ Color SceneTree::get_debug_navigation_disabled_color() const {
return debug_navigation_disabled_color;
}
+Ref<Material> SceneTree::get_debug_paths_material() {
+ if (debug_paths_material.is_valid()) {
+ return debug_paths_material;
+ }
+
+ Ref<StandardMaterial3D> _debug_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D));
+ _debug_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
+ _debug_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
+ _debug_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
+ _debug_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ _debug_material->set_albedo(get_debug_paths_color());
+
+ debug_paths_material = _debug_material;
+
+ return debug_paths_material;
+}
+
Ref<Material> SceneTree::get_debug_navigation_material() {
if (navigation_material.is_valid()) {
return navigation_material;
@@ -1207,6 +1248,8 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_debug_collisions_hint", "enable"), &SceneTree::set_debug_collisions_hint);
ClassDB::bind_method(D_METHOD("is_debugging_collisions_hint"), &SceneTree::is_debugging_collisions_hint);
+ ClassDB::bind_method(D_METHOD("set_debug_paths_hint", "enable"), &SceneTree::set_debug_paths_hint);
+ ClassDB::bind_method(D_METHOD("is_debugging_paths_hint"), &SceneTree::is_debugging_paths_hint);
ClassDB::bind_method(D_METHOD("set_debug_navigation_hint", "enable"), &SceneTree::set_debug_navigation_hint);
ClassDB::bind_method(D_METHOD("is_debugging_navigation_hint"), &SceneTree::is_debugging_navigation_hint);
@@ -1268,6 +1311,7 @@ void SceneTree::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_accept_quit"), "set_auto_accept_quit", "is_auto_accept_quit");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "quit_on_go_back"), "set_quit_on_go_back", "is_quit_on_go_back");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_collisions_hint"), "set_debug_collisions_hint", "is_debugging_collisions_hint");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_paths_hint"), "set_debug_paths_hint", "is_debugging_paths_hint");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_navigation_hint"), "set_debug_navigation_hint", "is_debugging_navigation_hint");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_pause", "is_paused");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_edited_scene_root", "get_edited_scene_root");
@@ -1344,6 +1388,8 @@ SceneTree::SceneTree() {
}
debug_collisions_color = GLOBAL_DEF("debug/shapes/collision/shape_color", Color(0.0, 0.6, 0.7, 0.42));
debug_collision_contact_color = GLOBAL_DEF("debug/shapes/collision/contact_color", Color(1.0, 0.2, 0.1, 0.8));
+ debug_paths_color = GLOBAL_DEF("debug/shapes/paths/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
+ debug_paths_width = GLOBAL_DEF("debug/shapes/paths/geometry_width", 2.0);
debug_navigation_color = GLOBAL_DEF("debug/shapes/navigation/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
debug_navigation_disabled_color = GLOBAL_DEF("debug/shapes/navigation/disabled_geometry_color", Color(1.0, 0.7, 0.1, 0.4));
collision_debug_contacts = GLOBAL_DEF("debug/shapes/collision/max_contacts_displayed", 10000);
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 67a17a69f2..a34aa8e2cd 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -97,6 +97,7 @@ private:
#ifdef DEBUG_ENABLED
bool debug_collisions_hint = false;
+ bool debug_paths_hint = false;
bool debug_navigation_hint = false;
#endif
bool paused = false;
@@ -146,9 +147,12 @@ private:
Color debug_collisions_color;
Color debug_collision_contact_color;
+ Color debug_paths_color;
+ float debug_paths_width = 1.0f;
Color debug_navigation_color;
Color debug_navigation_disabled_color;
Ref<ArrayMesh> debug_contact_mesh;
+ Ref<Material> debug_paths_material;
Ref<Material> navigation_material;
Ref<Material> navigation_disabled_material;
Ref<Material> collision_material;
@@ -297,12 +301,18 @@ public:
void set_debug_collisions_hint(bool p_enabled);
bool is_debugging_collisions_hint() const;
+ void set_debug_paths_hint(bool p_enabled);
+ bool is_debugging_paths_hint() const;
+
void set_debug_navigation_hint(bool p_enabled);
bool is_debugging_navigation_hint() const;
#else
void set_debug_collisions_hint(bool p_enabled) {}
bool is_debugging_collisions_hint() const { return false; }
+ void set_debug_paths_hint(bool p_enabled) {}
+ bool is_debugging_paths_hint() const { return false; }
+
void set_debug_navigation_hint(bool p_enabled) {}
bool is_debugging_navigation_hint() const { return false; }
#endif
@@ -313,12 +323,19 @@ public:
void set_debug_collision_contact_color(const Color &p_color);
Color get_debug_collision_contact_color() const;
+ void set_debug_paths_color(const Color &p_color);
+ Color get_debug_paths_color() const;
+
+ void set_debug_paths_width(float p_width);
+ float get_debug_paths_width() const;
+
void set_debug_navigation_color(const Color &p_color);
Color get_debug_navigation_color() const;
void set_debug_navigation_disabled_color(const Color &p_color);
Color get_debug_navigation_disabled_color() const;
+ Ref<Material> get_debug_paths_material();
Ref<Material> get_debug_navigation_material();
Ref<Material> get_debug_navigation_disabled_material();
Ref<Material> get_debug_collision_material();
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"