diff options
44 files changed, 908 insertions, 514 deletions
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml index 48939db1f7..74825493a1 100644 --- a/doc/classes/EditorInterface.xml +++ b/doc/classes/EditorInterface.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="EditorInterface" inherits="Node" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="EditorInterface" inherits="Object" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Godot editor's interface. </brief_description> @@ -34,7 +34,7 @@ Edits the given [Script]. The line and column on which to open the script can also be specified. The script will be open with the user-configured editor for the script's language which may be an external editor. </description> </method> - <method name="get_base_control"> + <method name="get_base_control" qualifiers="const"> <return type="Control" /> <description> Returns the main container of Godot editor's window. For example, you can use it to retrieve the size of the container and place your controls accordingly. @@ -60,20 +60,20 @@ Returns the current path being viewed in the [FileSystemDock]. </description> </method> - <method name="get_edited_scene_root"> + <method name="get_edited_scene_root" qualifiers="const"> <return type="Node" /> <description> Returns the edited (current) scene's root [Node]. </description> </method> - <method name="get_editor_main_screen"> + <method name="get_editor_main_screen" qualifiers="const"> <return type="VBoxContainer" /> <description> Returns the editor control responsible for main screen plugins and tools. Use it with plugins that implement [method EditorPlugin._has_main_screen]. [b]Warning:[/b] Removing and freeing this node will render a part of the editor useless and may cause a crash. </description> </method> - <method name="get_editor_paths"> + <method name="get_editor_paths" qualifiers="const"> <return type="EditorPaths" /> <description> Returns the [EditorPaths] singleton. @@ -86,13 +86,13 @@ [b]Note:[/b] This value is set via the [code]interface/editor/display_scale[/code] and [code]interface/editor/custom_display_scale[/code] editor settings. Editor must be restarted for changes to be properly applied. </description> </method> - <method name="get_editor_settings"> + <method name="get_editor_settings" qualifiers="const"> <return type="EditorSettings" /> <description> Returns the editor's [EditorSettings] instance. </description> </method> - <method name="get_file_system_dock"> + <method name="get_file_system_dock" qualifiers="const"> <return type="FileSystemDock" /> <description> Returns the editor's [FileSystemDock] instance. @@ -118,19 +118,19 @@ Returns the name of the scene that is being played. If no scene is currently being played, returns an empty string. </description> </method> - <method name="get_resource_filesystem"> + <method name="get_resource_filesystem" qualifiers="const"> <return type="EditorFileSystem" /> <description> Returns the editor's [EditorFileSystem] instance. </description> </method> - <method name="get_resource_previewer"> + <method name="get_resource_previewer" qualifiers="const"> <return type="EditorResourcePreview" /> <description> Returns the editor's [EditorResourcePreview] instance. </description> </method> - <method name="get_script_editor"> + <method name="get_script_editor" qualifiers="const"> <return type="ScriptEditor" /> <description> Returns the editor's [ScriptEditor] instance. @@ -143,7 +143,7 @@ Returns an array containing the paths of the currently selected files (and directories) in the [FileSystemDock]. </description> </method> - <method name="get_selection"> + <method name="get_selection" qualifiers="const"> <return type="EditorSelection" /> <description> Returns the editor's [EditorSelection] instance. @@ -158,12 +158,6 @@ Shows the given property on the given [param object] in the editor's Inspector dock. If [param inspector_only] is [code]true[/code], plugins will not attempt to edit [param object]. </description> </method> - <method name="is_movie_maker_enabled" qualifiers="const"> - <return type="bool" /> - <description> - Returns [code]true[/code] if Movie Maker mode is enabled in the editor. See also [method set_movie_maker_enabled]. See [MovieWriter] for more information. - </description> - </method> <method name="is_playing_scene" qualifiers="const"> <return type="bool" /> <description> @@ -253,13 +247,6 @@ Sets the editor's current main screen to the one specified in [param name]. [param name] must match the text of the tab in question exactly ([code]2D[/code], [code]3D[/code], [code]Script[/code], [code]AssetLib[/code]). </description> </method> - <method name="set_movie_maker_enabled"> - <return type="void" /> - <param index="0" name="enabled" type="bool" /> - <description> - Sets whether Movie Maker mode is enabled in the editor. See also [method is_movie_maker_enabled]. See [MovieWriter] for more information. - </description> - </method> <method name="set_plugin_enabled"> <return type="void" /> <param index="0" name="plugin" type="String" /> @@ -279,5 +266,8 @@ <member name="distraction_free_mode" type="bool" setter="set_distraction_free_mode" getter="is_distraction_free_mode_enabled"> If [code]true[/code], enables distraction-free mode which hides side docks to increase the space available for the main view. </member> + <member name="movie_maker_enabled" type="bool" setter="set_movie_maker_enabled" getter="is_movie_maker_enabled"> + If [code]true[/code], the Movie Maker mode is enabled in the editor. See [MovieWriter] for more information. + </member> </members> </class> diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml index a8ee5cdc19..1f3f028bbe 100644 --- a/doc/classes/EditorPlugin.xml +++ b/doc/classes/EditorPlugin.xml @@ -532,7 +532,7 @@ <method name="get_editor_interface"> <return type="EditorInterface" /> <description> - Returns the [EditorInterface] object that gives you control over Godot editor's window and its functionalities. + Returns the [EditorInterface] singleton. It provides access to some parts of the editor GUI as well as various inner states and tools. </description> </method> <method name="get_export_as_menu"> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 996af71c3b..85d5f7dd55 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -9,7 +9,7 @@ Accessing the settings can be done using the following methods, such as: [codeblocks] [gdscript] - var settings = EditorInterface.get_editor_settings() + var settings = get_editor_interface().get_editor_settings() # `settings.set("some/property", 10)` also works as this class overrides `_set()` internally. settings.set_setting("some/property", 10) # `settings.get("some/property")` also works as this class overrides `_get()` internally. diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index 689f76389b..6095fef035 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -169,6 +169,18 @@ Error AudioDriverALSA::init() { return ERR_CANT_OPEN; } #endif + bool ver_ok = false; + String version = String::utf8(snd_asoundlib_version()); + Vector<String> ver_parts = version.split("."); + if (ver_parts.size() >= 2) { + ver_ok = ((ver_parts[0].to_int() == 1 && ver_parts[1].to_int() >= 1)) || (ver_parts[0].to_int() > 1); // 1.1.0 + } + print_verbose(vformat("ALSA %s detected.", version)); + if (!ver_ok) { + print_verbose("Unsupported ALSA library version!"); + return ERR_CANT_OPEN; + } + active.clear(); exit_thread.clear(); diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 797ffd67fe..9ae74a8906 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -290,6 +290,18 @@ Error AudioDriverPulseAudio::init() { return ERR_CANT_OPEN; } #endif + bool ver_ok = false; + String version = String::utf8(pa_get_library_version()); + Vector<String> ver_parts = version.split("."); + if (ver_parts.size() >= 2) { + ver_ok = (ver_parts[0].to_int() >= 8); // 8.0.0 + } + print_verbose(vformat("PulseAudio %s detected.", version)); + if (!ver_ok) { + print_verbose("Unsupported PulseAudio library version!"); + return ERR_CANT_OPEN; + } + active.clear(); exit_thread.clear(); diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 72ec0c19ab..805528b8c7 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -206,8 +206,6 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_i IMMDeviceEnumerator *enumerator = nullptr; IMMDevice *output_device = nullptr; - CoInitialize(nullptr); - HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); @@ -582,8 +580,6 @@ PackedStringArray AudioDriverWASAPI::audio_device_get_list(bool p_input) { list.push_back(String("Default")); - CoInitialize(nullptr); - HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, nullptr, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator); ERR_FAIL_COND_V(hr != S_OK, PackedStringArray()); @@ -702,6 +698,8 @@ void AudioDriverWASAPI::write_sample(WORD format_tag, int bits_per_sample, BYTE } void AudioDriverWASAPI::thread_func(void *p_udata) { + CoInitializeEx(nullptr, COINIT_MULTITHREADED); + AudioDriverWASAPI *ad = static_cast<AudioDriverWASAPI *>(p_udata); uint32_t avail_frames = 0; uint32_t write_ofs = 0; @@ -908,6 +906,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { OS::get_singleton()->delay_usec(1000); } } + CoUninitialize(); } void AudioDriverWASAPI::start() { diff --git a/editor/editor_interface.cpp b/editor/editor_interface.cpp new file mode 100644 index 0000000000..99803fd82d --- /dev/null +++ b/editor/editor_interface.cpp @@ -0,0 +1,437 @@ +/**************************************************************************/ +/* editor_interface.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "editor_interface.h" + +#include "editor/editor_command_palette.h" +#include "editor/editor_node.h" +#include "editor/editor_paths.h" +#include "editor/editor_resource_preview.h" +#include "editor/editor_scale.h" +#include "editor/editor_settings.h" +#include "editor/filesystem_dock.h" +#include "editor/inspector_dock.h" +#include "main/main.h" +#include "scene/gui/box_container.h" +#include "scene/gui/control.h" + +EditorInterface *EditorInterface::singleton = nullptr; + +void EditorInterface::restart_editor(bool p_save) { + if (p_save) { + EditorNode::get_singleton()->save_all_scenes(); + } + EditorNode::get_singleton()->restart_editor(); +} + +// Editor tools. + +EditorCommandPalette *EditorInterface::get_command_palette() const { + return EditorCommandPalette::get_singleton(); +} + +EditorFileSystem *EditorInterface::get_resource_file_system() const { + return EditorFileSystem::get_singleton(); +} + +EditorPaths *EditorInterface::get_editor_paths() const { + return EditorPaths::get_singleton(); +} + +EditorResourcePreview *EditorInterface::get_resource_previewer() const { + return EditorResourcePreview::get_singleton(); +} + +EditorSelection *EditorInterface::get_selection() const { + return EditorNode::get_singleton()->get_editor_selection(); +} + +Ref<EditorSettings> EditorInterface::get_editor_settings() const { + return EditorSettings::get_singleton(); +} + +TypedArray<Texture2D> EditorInterface::_make_mesh_previews(const TypedArray<Mesh> &p_meshes, int p_preview_size) { + Vector<Ref<Mesh>> meshes; + + for (int i = 0; i < p_meshes.size(); i++) { + meshes.push_back(p_meshes[i]); + } + + Vector<Ref<Texture2D>> textures = make_mesh_previews(meshes, nullptr, p_preview_size); + TypedArray<Texture2D> ret; + for (int i = 0; i < textures.size(); i++) { + ret.push_back(textures[i]); + } + + return ret; +} + +Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform3D> *p_transforms, int p_preview_size) { + int size = p_preview_size; + + RID scenario = RS::get_singleton()->scenario_create(); + + RID viewport = RS::get_singleton()->viewport_create(); + RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ALWAYS); + RS::get_singleton()->viewport_set_scenario(viewport, scenario); + RS::get_singleton()->viewport_set_size(viewport, size, size); + RS::get_singleton()->viewport_set_transparent_background(viewport, true); + RS::get_singleton()->viewport_set_active(viewport, true); + RID viewport_texture = RS::get_singleton()->viewport_get_texture(viewport); + + RID camera = RS::get_singleton()->camera_create(); + RS::get_singleton()->viewport_attach_camera(viewport, camera); + + RID light = RS::get_singleton()->directional_light_create(); + RID light_instance = RS::get_singleton()->instance_create2(light, scenario); + + RID light2 = RS::get_singleton()->directional_light_create(); + RS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7)); + RID light_instance2 = RS::get_singleton()->instance_create2(light2, scenario); + + EditorProgress ep("mlib", TTR("Creating Mesh Previews"), p_meshes.size()); + + Vector<Ref<Texture2D>> textures; + + for (int i = 0; i < p_meshes.size(); i++) { + Ref<Mesh> mesh = p_meshes[i]; + if (!mesh.is_valid()) { + textures.push_back(Ref<Texture2D>()); + continue; + } + + Transform3D mesh_xform; + if (p_transforms != nullptr) { + mesh_xform = (*p_transforms)[i]; + } + + RID inst = RS::get_singleton()->instance_create2(mesh->get_rid(), scenario); + RS::get_singleton()->instance_set_transform(inst, mesh_xform); + + AABB aabb = mesh->get_aabb(); + Vector3 ofs = aabb.get_center(); + aabb.position -= ofs; + Transform3D xform; + xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI / 6); + xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI / 6) * xform.basis; + AABB rot_aabb = xform.xform(aabb); + float m = MAX(rot_aabb.size.x, rot_aabb.size.y) * 0.5; + if (m == 0) { + textures.push_back(Ref<Texture2D>()); + continue; + } + xform.origin = -xform.basis.xform(ofs); //-ofs*m; + xform.origin.z -= rot_aabb.size.z * 2; + xform.invert(); + xform = mesh_xform * xform; + + RS::get_singleton()->camera_set_transform(camera, xform * Transform3D(Basis(), Vector3(0, 0, 3))); + RS::get_singleton()->camera_set_orthogonal(camera, m * 2, 0.01, 1000.0); + + RS::get_singleton()->instance_set_transform(light_instance, xform * Transform3D().looking_at(Vector3(-2, -1, -1), Vector3(0, 1, 0))); + RS::get_singleton()->instance_set_transform(light_instance2, xform * Transform3D().looking_at(Vector3(+1, -1, -2), Vector3(0, 1, 0))); + + ep.step(TTR("Thumbnail..."), i); + DisplayServer::get_singleton()->process_events(); + Main::iteration(); + Main::iteration(); + Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture); + ERR_CONTINUE(!img.is_valid() || img->is_empty()); + Ref<ImageTexture> it = ImageTexture::create_from_image(img); + + RS::get_singleton()->free(inst); + + textures.push_back(it); + } + + RS::get_singleton()->free(viewport); + RS::get_singleton()->free(light); + RS::get_singleton()->free(light_instance); + RS::get_singleton()->free(light2); + RS::get_singleton()->free(light_instance2); + RS::get_singleton()->free(camera); + RS::get_singleton()->free(scenario); + + return textures; +} + +void EditorInterface::set_plugin_enabled(const String &p_plugin, bool p_enabled) { + EditorNode::get_singleton()->set_addon_plugin_enabled(p_plugin, p_enabled, true); +} + +bool EditorInterface::is_plugin_enabled(const String &p_plugin) const { + return EditorNode::get_singleton()->is_addon_plugin_enabled(p_plugin); +} + +// Editor GUI. + +Control *EditorInterface::get_base_control() const { + return EditorNode::get_singleton()->get_gui_base(); +} + +VBoxContainer *EditorInterface::get_editor_main_screen() const { + return EditorNode::get_singleton()->get_main_screen_control(); +} + +ScriptEditor *EditorInterface::get_script_editor() const { + return ScriptEditor::get_singleton(); +} + +void EditorInterface::set_main_screen_editor(const String &p_name) { + EditorNode::get_singleton()->select_editor_by_name(p_name); +} + +void EditorInterface::set_distraction_free_mode(bool p_enter) { + EditorNode::get_singleton()->set_distraction_free_mode(p_enter); +} + +bool EditorInterface::is_distraction_free_mode_enabled() const { + return EditorNode::get_singleton()->is_distraction_free_mode_enabled(); +} + +float EditorInterface::get_editor_scale() const { + return EDSCALE; +} + +// Editor docks. + +FileSystemDock *EditorInterface::get_file_system_dock() const { + return FileSystemDock::get_singleton(); +} + +void EditorInterface::select_file(const String &p_file) { + FileSystemDock::get_singleton()->select_file(p_file); +} + +Vector<String> EditorInterface::get_selected_paths() const { + return FileSystemDock::get_singleton()->get_selected_paths(); +} + +String EditorInterface::get_current_path() const { + return FileSystemDock::get_singleton()->get_current_path(); +} + +String EditorInterface::get_current_directory() const { + return FileSystemDock::get_singleton()->get_current_directory(); +} + +EditorInspector *EditorInterface::get_inspector() const { + return InspectorDock::get_inspector_singleton(); +} + +// Object/Resource/Node editing. + +void EditorInterface::inspect_object(Object *p_obj, const String &p_for_property, bool p_inspector_only) { + EditorNode::get_singleton()->push_item(p_obj, p_for_property, p_inspector_only); +} + +void EditorInterface::edit_resource(const Ref<Resource> &p_resource) { + EditorNode::get_singleton()->edit_resource(p_resource); +} + +void EditorInterface::edit_node(Node *p_node) { + EditorNode::get_singleton()->edit_node(p_node); +} + +void EditorInterface::edit_script(const Ref<Script> &p_script, int p_line, int p_col, bool p_grab_focus) { + ScriptEditor::get_singleton()->edit(p_script, p_line, p_col, p_grab_focus); +} + +void EditorInterface::open_scene_from_path(const String &scene_path) { + if (EditorNode::get_singleton()->is_changing_scene()) { + return; + } + + EditorNode::get_singleton()->open_request(scene_path); +} + +void EditorInterface::reload_scene_from_path(const String &scene_path) { + if (EditorNode::get_singleton()->is_changing_scene()) { + return; + } + + EditorNode::get_singleton()->reload_scene(scene_path); +} + +Node *EditorInterface::get_edited_scene_root() const { + return EditorNode::get_singleton()->get_edited_scene(); +} + +PackedStringArray EditorInterface::get_open_scenes() const { + PackedStringArray ret; + Vector<EditorData::EditedScene> scenes = EditorNode::get_editor_data().get_edited_scenes(); + + int scns_amount = scenes.size(); + for (int idx_scn = 0; idx_scn < scns_amount; idx_scn++) { + if (scenes[idx_scn].root == nullptr) { + continue; + } + ret.push_back(scenes[idx_scn].root->get_scene_file_path()); + } + return ret; +} + +Error EditorInterface::save_scene() { + if (!get_edited_scene_root()) { + return ERR_CANT_CREATE; + } + if (get_edited_scene_root()->get_scene_file_path().is_empty()) { + return ERR_CANT_CREATE; + } + + save_scene_as(get_edited_scene_root()->get_scene_file_path()); + return OK; +} + +void EditorInterface::save_scene_as(const String &p_scene, bool p_with_preview) { + EditorNode::get_singleton()->save_scene_to_path(p_scene, p_with_preview); +} + +// Scene playback. + +void EditorInterface::play_main_scene() { + EditorNode::get_singleton()->run_play(); +} + +void EditorInterface::play_current_scene() { + EditorNode::get_singleton()->run_play_current(); +} + +void EditorInterface::play_custom_scene(const String &scene_path) { + EditorNode::get_singleton()->run_play_custom(scene_path); +} + +void EditorInterface::stop_playing_scene() { + EditorNode::get_singleton()->run_stop(); +} + +bool EditorInterface::is_playing_scene() const { + return EditorNode::get_singleton()->is_run_playing(); +} + +String EditorInterface::get_playing_scene() const { + return EditorNode::get_singleton()->get_run_playing_scene(); +} + +void EditorInterface::set_movie_maker_enabled(bool p_enabled) { + EditorNode::get_singleton()->set_movie_maker_enabled(p_enabled); +} + +bool EditorInterface::is_movie_maker_enabled() const { + return EditorNode::get_singleton()->is_movie_maker_enabled(); +} + +// Base. + +void EditorInterface::_bind_methods() { + ClassDB::bind_method(D_METHOD("restart_editor", "save"), &EditorInterface::restart_editor, DEFVAL(true)); + + // Editor tools. + + ClassDB::bind_method(D_METHOD("get_command_palette"), &EditorInterface::get_command_palette); + ClassDB::bind_method(D_METHOD("get_resource_filesystem"), &EditorInterface::get_resource_file_system); + ClassDB::bind_method(D_METHOD("get_editor_paths"), &EditorInterface::get_editor_paths); + ClassDB::bind_method(D_METHOD("get_resource_previewer"), &EditorInterface::get_resource_previewer); + ClassDB::bind_method(D_METHOD("get_selection"), &EditorInterface::get_selection); + ClassDB::bind_method(D_METHOD("get_editor_settings"), &EditorInterface::get_editor_settings); + + ClassDB::bind_method(D_METHOD("make_mesh_previews", "meshes", "preview_size"), &EditorInterface::_make_mesh_previews); + + ClassDB::bind_method(D_METHOD("set_plugin_enabled", "plugin", "enabled"), &EditorInterface::set_plugin_enabled); + ClassDB::bind_method(D_METHOD("is_plugin_enabled", "plugin"), &EditorInterface::is_plugin_enabled); + + // Editor GUI. + + ClassDB::bind_method(D_METHOD("get_base_control"), &EditorInterface::get_base_control); + ClassDB::bind_method(D_METHOD("get_editor_main_screen"), &EditorInterface::get_editor_main_screen); + ClassDB::bind_method(D_METHOD("get_script_editor"), &EditorInterface::get_script_editor); + + ClassDB::bind_method(D_METHOD("set_main_screen_editor", "name"), &EditorInterface::set_main_screen_editor); + ClassDB::bind_method(D_METHOD("set_distraction_free_mode", "enter"), &EditorInterface::set_distraction_free_mode); + ClassDB::bind_method(D_METHOD("is_distraction_free_mode_enabled"), &EditorInterface::is_distraction_free_mode_enabled); + + ClassDB::bind_method(D_METHOD("get_editor_scale"), &EditorInterface::get_editor_scale); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distraction_free_mode"), "set_distraction_free_mode", "is_distraction_free_mode_enabled"); + + // Editor docks. + + ClassDB::bind_method(D_METHOD("get_file_system_dock"), &EditorInterface::get_file_system_dock); + ClassDB::bind_method(D_METHOD("select_file", "file"), &EditorInterface::select_file); + ClassDB::bind_method(D_METHOD("get_selected_paths"), &EditorInterface::get_selected_paths); + ClassDB::bind_method(D_METHOD("get_current_path"), &EditorInterface::get_current_path); + ClassDB::bind_method(D_METHOD("get_current_directory"), &EditorInterface::get_current_directory); + + ClassDB::bind_method(D_METHOD("get_inspector"), &EditorInterface::get_inspector); + + // Object/Resource/Node editing. + + ClassDB::bind_method(D_METHOD("inspect_object", "object", "for_property", "inspector_only"), &EditorInterface::inspect_object, DEFVAL(String()), DEFVAL(false)); + + ClassDB::bind_method(D_METHOD("edit_resource", "resource"), &EditorInterface::edit_resource); + ClassDB::bind_method(D_METHOD("edit_node", "node"), &EditorInterface::edit_node); + ClassDB::bind_method(D_METHOD("edit_script", "script", "line", "column", "grab_focus"), &EditorInterface::edit_script, DEFVAL(-1), DEFVAL(0), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("open_scene_from_path", "scene_filepath"), &EditorInterface::open_scene_from_path); + ClassDB::bind_method(D_METHOD("reload_scene_from_path", "scene_filepath"), &EditorInterface::reload_scene_from_path); + + ClassDB::bind_method(D_METHOD("get_open_scenes"), &EditorInterface::get_open_scenes); + ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &EditorInterface::get_edited_scene_root); + + ClassDB::bind_method(D_METHOD("save_scene"), &EditorInterface::save_scene); + ClassDB::bind_method(D_METHOD("save_scene_as", "path", "with_preview"), &EditorInterface::save_scene_as, DEFVAL(true)); + + // Scene playback. + + ClassDB::bind_method(D_METHOD("play_main_scene"), &EditorInterface::play_main_scene); + ClassDB::bind_method(D_METHOD("play_current_scene"), &EditorInterface::play_current_scene); + ClassDB::bind_method(D_METHOD("play_custom_scene", "scene_filepath"), &EditorInterface::play_custom_scene); + ClassDB::bind_method(D_METHOD("stop_playing_scene"), &EditorInterface::stop_playing_scene); + ClassDB::bind_method(D_METHOD("is_playing_scene"), &EditorInterface::is_playing_scene); + ClassDB::bind_method(D_METHOD("get_playing_scene"), &EditorInterface::get_playing_scene); + + ClassDB::bind_method(D_METHOD("set_movie_maker_enabled", "enabled"), &EditorInterface::set_movie_maker_enabled); + ClassDB::bind_method(D_METHOD("is_movie_maker_enabled"), &EditorInterface::is_movie_maker_enabled); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "movie_maker_enabled"), "set_movie_maker_enabled", "is_movie_maker_enabled"); +} + +void EditorInterface::create() { + memnew(EditorInterface); +} + +void EditorInterface::free() { + ERR_FAIL_COND(singleton == nullptr); + memdelete(singleton); +} + +EditorInterface::EditorInterface() { + ERR_FAIL_COND(singleton != nullptr); + singleton = this; +} diff --git a/editor/editor_interface.h b/editor/editor_interface.h new file mode 100644 index 0000000000..9a64969e88 --- /dev/null +++ b/editor/editor_interface.h @@ -0,0 +1,143 @@ +/**************************************************************************/ +/* editor_interface.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 EDITOR_INTERFACE_H +#define EDITOR_INTERFACE_H + +#include "core/io/resource.h" +#include "core/object/class_db.h" +#include "core/object/object.h" +#include "core/object/script_language.h" + +class Control; +class EditorCommandPalette; +class EditorFileSystem; +class EditorInspector; +class EditorPaths; +class EditorResourcePreview; +class EditorSelection; +class EditorSettings; +class FileSystemDock; +class Mesh; +class Node; +class ScriptEditor; +class Texture2D; +class VBoxContainer; + +class EditorInterface : public Object { + GDCLASS(EditorInterface, Object); + + static EditorInterface *singleton; + + // Editor tools. + + TypedArray<Texture2D> _make_mesh_previews(const TypedArray<Mesh> &p_meshes, int p_preview_size); + +protected: + static void _bind_methods(); + +public: + static EditorInterface *get_singleton() { return singleton; } + + void restart_editor(bool p_save = true); + + // Editor tools. + + EditorCommandPalette *get_command_palette() const; + EditorFileSystem *get_resource_file_system() const; + EditorPaths *get_editor_paths() const; + EditorResourcePreview *get_resource_previewer() const; + EditorSelection *get_selection() const; + Ref<EditorSettings> get_editor_settings() const; + + Vector<Ref<Texture2D>> make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform3D> *p_transforms, int p_preview_size); + + void set_plugin_enabled(const String &p_plugin, bool p_enabled); + bool is_plugin_enabled(const String &p_plugin) const; + + // Editor GUI. + + Control *get_base_control() const; + VBoxContainer *get_editor_main_screen() const; + ScriptEditor *get_script_editor() const; + + void set_main_screen_editor(const String &p_name); + void set_distraction_free_mode(bool p_enter); + bool is_distraction_free_mode_enabled() const; + + float get_editor_scale() const; + + // Editor docks. + + FileSystemDock *get_file_system_dock() const; + void select_file(const String &p_file); + Vector<String> get_selected_paths() const; + String get_current_path() const; + String get_current_directory() const; + + EditorInspector *get_inspector() const; + + // Object/Resource/Node editing. + + void inspect_object(Object *p_obj, const String &p_for_property = String(), bool p_inspector_only = false); + + void edit_resource(const Ref<Resource> &p_resource); + void edit_node(Node *p_node); + void edit_script(const Ref<Script> &p_script, int p_line = -1, int p_col = 0, bool p_grab_focus = true); + void open_scene_from_path(const String &scene_path); + void reload_scene_from_path(const String &scene_path); + + PackedStringArray get_open_scenes() const; + Node *get_edited_scene_root() const; + + Error save_scene(); + void save_scene_as(const String &p_scene, bool p_with_preview = true); + + // Scene playback. + + void play_main_scene(); + void play_current_scene(); + void play_custom_scene(const String &scene_path); + void stop_playing_scene(); + bool is_playing_scene() const; + String get_playing_scene() const; + + void set_movie_maker_enabled(bool p_enabled); + bool is_movie_maker_enabled() const; + + // Base. + + static void create(); + static void free(); + + EditorInterface(); +}; + +#endif // EDITOR_INTERFACE_H diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 057f8e4ce4..f2f1285799 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -75,6 +75,7 @@ #include "editor/editor_folding.h" #include "editor/editor_help.h" #include "editor/editor_inspector.h" +#include "editor/editor_interface.h" #include "editor/editor_layouts_dialog.h" #include "editor/editor_log.h" #include "editor/editor_native_shader_source_visualizer.h" @@ -7901,11 +7902,6 @@ EditorNode::EditorNode() { print_verbose("Asset Library not available (due to using Web editor, or SSL support disabled)."); } - // Add interface before adding plugins. - - editor_interface = memnew(EditorInterface); - add_child(editor_interface); - // More visually meaningful to have this later. raise_bottom_panel_item(AnimationPlayerEditor::get_singleton()); diff --git a/editor/editor_node.h b/editor/editor_node.h index 8f17932cb0..831e2989f5 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -65,6 +65,7 @@ class TabContainer; class TextureRect; class TextureProgressBar; class Tree; +class VBoxContainer; class VSplitContainer; class Window; @@ -269,7 +270,6 @@ private: EditorCommandPalette *command_palette = nullptr; EditorExport *editor_export = nullptr; - EditorInterface *editor_interface = nullptr; EditorLog *log = nullptr; EditorNativeShaderSourceVisualizer *native_shader_source_visualizer = nullptr; EditorPlugin *editor_plugin_screen = nullptr; diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp index d5ba841801..610f66cff9 100644 --- a/editor/editor_paths.cpp +++ b/editor/editor_paths.cpp @@ -91,8 +91,7 @@ String EditorPaths::get_feature_profiles_dir() const { } void EditorPaths::create() { - ERR_FAIL_COND(singleton != nullptr); - memnew(EditorPaths()); + memnew(EditorPaths); } void EditorPaths::free() { @@ -111,6 +110,7 @@ void EditorPaths::_bind_methods() { } EditorPaths::EditorPaths() { + ERR_FAIL_COND(singleton != nullptr); singleton = this; project_data_dir = ProjectSettings::get_singleton()->get_project_data_path(); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 9281965e6f..8ac5e77d35 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -31,15 +31,13 @@ #include "editor_plugin.h" #include "editor/debugger/editor_debugger_node.h" -#include "editor/editor_command_palette.h" +#include "editor/editor_file_system.h" +#include "editor/editor_inspector.h" +#include "editor/editor_interface.h" #include "editor/editor_node.h" -#include "editor/editor_paths.h" -#include "editor/editor_resource_preview.h" -#include "editor/editor_settings.h" #include "editor/editor_translation_parser.h" #include "editor/editor_undo_redo_manager.h" #include "editor/export/editor_export.h" -#include "editor/filesystem_dock.h" #include "editor/gui/editor_title_bar.h" #include "editor/import/editor_import_plugin.h" #include "editor/import/resource_importer_scene.h" @@ -51,362 +49,10 @@ #include "editor/plugins/script_editor_plugin.h" #include "editor/project_settings_editor.h" #include "editor/scene_tree_dock.h" -#include "main/main.h" #include "scene/3d/camera_3d.h" #include "scene/gui/popup_menu.h" #include "servers/rendering_server.h" -TypedArray<Texture2D> EditorInterface::_make_mesh_previews(const TypedArray<Mesh> &p_meshes, int p_preview_size) { - Vector<Ref<Mesh>> meshes; - - for (int i = 0; i < p_meshes.size(); i++) { - meshes.push_back(p_meshes[i]); - } - - Vector<Ref<Texture2D>> textures = make_mesh_previews(meshes, nullptr, p_preview_size); - TypedArray<Texture2D> ret; - for (int i = 0; i < textures.size(); i++) { - ret.push_back(textures[i]); - } - - return ret; -} - -Vector<Ref<Texture2D>> EditorInterface::make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform3D> *p_transforms, int p_preview_size) { - int size = p_preview_size; - - RID scenario = RS::get_singleton()->scenario_create(); - - RID viewport = RS::get_singleton()->viewport_create(); - RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ALWAYS); - RS::get_singleton()->viewport_set_scenario(viewport, scenario); - RS::get_singleton()->viewport_set_size(viewport, size, size); - RS::get_singleton()->viewport_set_transparent_background(viewport, true); - RS::get_singleton()->viewport_set_active(viewport, true); - RID viewport_texture = RS::get_singleton()->viewport_get_texture(viewport); - - RID camera = RS::get_singleton()->camera_create(); - RS::get_singleton()->viewport_attach_camera(viewport, camera); - - RID light = RS::get_singleton()->directional_light_create(); - RID light_instance = RS::get_singleton()->instance_create2(light, scenario); - - RID light2 = RS::get_singleton()->directional_light_create(); - RS::get_singleton()->light_set_color(light2, Color(0.7, 0.7, 0.7)); - RID light_instance2 = RS::get_singleton()->instance_create2(light2, scenario); - - EditorProgress ep("mlib", TTR("Creating Mesh Previews"), p_meshes.size()); - - Vector<Ref<Texture2D>> textures; - - for (int i = 0; i < p_meshes.size(); i++) { - Ref<Mesh> mesh = p_meshes[i]; - if (!mesh.is_valid()) { - textures.push_back(Ref<Texture2D>()); - continue; - } - - Transform3D mesh_xform; - if (p_transforms != nullptr) { - mesh_xform = (*p_transforms)[i]; - } - - RID inst = RS::get_singleton()->instance_create2(mesh->get_rid(), scenario); - RS::get_singleton()->instance_set_transform(inst, mesh_xform); - - AABB aabb = mesh->get_aabb(); - Vector3 ofs = aabb.get_center(); - aabb.position -= ofs; - Transform3D xform; - xform.basis = Basis().rotated(Vector3(0, 1, 0), -Math_PI / 6); - xform.basis = Basis().rotated(Vector3(1, 0, 0), Math_PI / 6) * xform.basis; - AABB rot_aabb = xform.xform(aabb); - float m = MAX(rot_aabb.size.x, rot_aabb.size.y) * 0.5; - if (m == 0) { - textures.push_back(Ref<Texture2D>()); - continue; - } - xform.origin = -xform.basis.xform(ofs); //-ofs*m; - xform.origin.z -= rot_aabb.size.z * 2; - xform.invert(); - xform = mesh_xform * xform; - - RS::get_singleton()->camera_set_transform(camera, xform * Transform3D(Basis(), Vector3(0, 0, 3))); - RS::get_singleton()->camera_set_orthogonal(camera, m * 2, 0.01, 1000.0); - - RS::get_singleton()->instance_set_transform(light_instance, xform * Transform3D().looking_at(Vector3(-2, -1, -1), Vector3(0, 1, 0))); - RS::get_singleton()->instance_set_transform(light_instance2, xform * Transform3D().looking_at(Vector3(+1, -1, -2), Vector3(0, 1, 0))); - - ep.step(TTR("Thumbnail..."), i); - DisplayServer::get_singleton()->process_events(); - Main::iteration(); - Main::iteration(); - Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture); - ERR_CONTINUE(!img.is_valid() || img->is_empty()); - Ref<ImageTexture> it = ImageTexture::create_from_image(img); - - RS::get_singleton()->free(inst); - - textures.push_back(it); - } - - RS::get_singleton()->free(viewport); - RS::get_singleton()->free(light); - RS::get_singleton()->free(light_instance); - RS::get_singleton()->free(light2); - RS::get_singleton()->free(light_instance2); - RS::get_singleton()->free(camera); - RS::get_singleton()->free(scenario); - - return textures; -} - -void EditorInterface::set_main_screen_editor(const String &p_name) { - EditorNode::get_singleton()->select_editor_by_name(p_name); -} - -VBoxContainer *EditorInterface::get_editor_main_screen() { - return EditorNode::get_singleton()->get_main_screen_control(); -} - -void EditorInterface::edit_resource(const Ref<Resource> &p_resource) { - EditorNode::get_singleton()->edit_resource(p_resource); -} - -void EditorInterface::edit_node(Node *p_node) { - EditorNode::get_singleton()->edit_node(p_node); -} - -void EditorInterface::edit_script(const Ref<Script> &p_script, int p_line, int p_col, bool p_grab_focus) { - ScriptEditor::get_singleton()->edit(p_script, p_line, p_col, p_grab_focus); -} - -void EditorInterface::open_scene_from_path(const String &scene_path) { - if (EditorNode::get_singleton()->is_changing_scene()) { - return; - } - - EditorNode::get_singleton()->open_request(scene_path); -} - -void EditorInterface::reload_scene_from_path(const String &scene_path) { - if (EditorNode::get_singleton()->is_changing_scene()) { - return; - } - - EditorNode::get_singleton()->reload_scene(scene_path); -} - -void EditorInterface::play_main_scene() { - EditorNode::get_singleton()->run_play(); -} - -void EditorInterface::play_current_scene() { - EditorNode::get_singleton()->run_play_current(); -} - -void EditorInterface::play_custom_scene(const String &scene_path) { - EditorNode::get_singleton()->run_play_custom(scene_path); -} - -void EditorInterface::stop_playing_scene() { - EditorNode::get_singleton()->run_stop(); -} - -bool EditorInterface::is_playing_scene() const { - return EditorNode::get_singleton()->is_run_playing(); -} - -String EditorInterface::get_playing_scene() const { - return EditorNode::get_singleton()->get_run_playing_scene(); -} - -Node *EditorInterface::get_edited_scene_root() { - return EditorNode::get_singleton()->get_edited_scene(); -} - -PackedStringArray EditorInterface::get_open_scenes() const { - PackedStringArray ret; - Vector<EditorData::EditedScene> scenes = EditorNode::get_editor_data().get_edited_scenes(); - - int scns_amount = scenes.size(); - for (int idx_scn = 0; idx_scn < scns_amount; idx_scn++) { - if (scenes[idx_scn].root == nullptr) { - continue; - } - ret.push_back(scenes[idx_scn].root->get_scene_file_path()); - } - return ret; -} - -ScriptEditor *EditorInterface::get_script_editor() { - return ScriptEditor::get_singleton(); -} - -void EditorInterface::select_file(const String &p_file) { - FileSystemDock::get_singleton()->select_file(p_file); -} - -Vector<String> EditorInterface::get_selected_paths() const { - return FileSystemDock::get_singleton()->get_selected_paths(); -} - -String EditorInterface::get_current_path() const { - return FileSystemDock::get_singleton()->get_current_path(); -} - -String EditorInterface::get_current_directory() const { - return FileSystemDock::get_singleton()->get_current_directory(); -} - -void EditorInterface::inspect_object(Object *p_obj, const String &p_for_property, bool p_inspector_only) { - EditorNode::get_singleton()->push_item(p_obj, p_for_property, p_inspector_only); -} - -EditorFileSystem *EditorInterface::get_resource_file_system() { - return EditorFileSystem::get_singleton(); -} - -FileSystemDock *EditorInterface::get_file_system_dock() { - return FileSystemDock::get_singleton(); -} - -EditorSelection *EditorInterface::get_selection() { - return EditorNode::get_singleton()->get_editor_selection(); -} - -Ref<EditorSettings> EditorInterface::get_editor_settings() { - return EditorSettings::get_singleton(); -} -EditorPaths *EditorInterface::get_editor_paths() { - return EditorPaths::get_singleton(); -} - -EditorResourcePreview *EditorInterface::get_resource_previewer() { - return EditorResourcePreview::get_singleton(); -} - -Control *EditorInterface::get_base_control() { - return EditorNode::get_singleton()->get_gui_base(); -} - -float EditorInterface::get_editor_scale() const { - return EDSCALE; -} - -void EditorInterface::set_plugin_enabled(const String &p_plugin, bool p_enabled) { - EditorNode::get_singleton()->set_addon_plugin_enabled(p_plugin, p_enabled, true); -} - -bool EditorInterface::is_plugin_enabled(const String &p_plugin) const { - return EditorNode::get_singleton()->is_addon_plugin_enabled(p_plugin); -} - -void EditorInterface::set_movie_maker_enabled(bool p_enabled) { - EditorNode::get_singleton()->set_movie_maker_enabled(p_enabled); -} - -bool EditorInterface::is_movie_maker_enabled() const { - return EditorNode::get_singleton()->is_movie_maker_enabled(); -} - -EditorInspector *EditorInterface::get_inspector() const { - return InspectorDock::get_inspector_singleton(); -} - -Error EditorInterface::save_scene() { - if (!get_edited_scene_root()) { - return ERR_CANT_CREATE; - } - if (get_edited_scene_root()->get_scene_file_path().is_empty()) { - return ERR_CANT_CREATE; - } - - save_scene_as(get_edited_scene_root()->get_scene_file_path()); - return OK; -} - -void EditorInterface::save_scene_as(const String &p_scene, bool p_with_preview) { - EditorNode::get_singleton()->save_scene_to_path(p_scene, p_with_preview); -} - -void EditorInterface::set_distraction_free_mode(bool p_enter) { - EditorNode::get_singleton()->set_distraction_free_mode(p_enter); -} - -void EditorInterface::restart_editor(bool p_save) { - if (p_save) { - EditorNode::get_singleton()->save_all_scenes(); - } - EditorNode::get_singleton()->restart_editor(); -} - -bool EditorInterface::is_distraction_free_mode_enabled() const { - return EditorNode::get_singleton()->is_distraction_free_mode_enabled(); -} - -EditorCommandPalette *EditorInterface::get_command_palette() const { - return EditorCommandPalette::get_singleton(); -} - -EditorInterface *EditorInterface::singleton = nullptr; - -void EditorInterface::_bind_methods() { - ClassDB::bind_method(D_METHOD("inspect_object", "object", "for_property", "inspector_only"), &EditorInterface::inspect_object, DEFVAL(String()), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_selection"), &EditorInterface::get_selection); - ClassDB::bind_method(D_METHOD("get_editor_settings"), &EditorInterface::get_editor_settings); - ClassDB::bind_method(D_METHOD("get_script_editor"), &EditorInterface::get_script_editor); - ClassDB::bind_method(D_METHOD("get_base_control"), &EditorInterface::get_base_control); - ClassDB::bind_method(D_METHOD("get_editor_scale"), &EditorInterface::get_editor_scale); - ClassDB::bind_method(D_METHOD("edit_resource", "resource"), &EditorInterface::edit_resource); - ClassDB::bind_method(D_METHOD("edit_node", "node"), &EditorInterface::edit_node); - ClassDB::bind_method(D_METHOD("edit_script", "script", "line", "column", "grab_focus"), &EditorInterface::edit_script, DEFVAL(-1), DEFVAL(0), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("open_scene_from_path", "scene_filepath"), &EditorInterface::open_scene_from_path); - ClassDB::bind_method(D_METHOD("reload_scene_from_path", "scene_filepath"), &EditorInterface::reload_scene_from_path); - ClassDB::bind_method(D_METHOD("play_main_scene"), &EditorInterface::play_main_scene); - ClassDB::bind_method(D_METHOD("play_current_scene"), &EditorInterface::play_current_scene); - ClassDB::bind_method(D_METHOD("play_custom_scene", "scene_filepath"), &EditorInterface::play_custom_scene); - ClassDB::bind_method(D_METHOD("stop_playing_scene"), &EditorInterface::stop_playing_scene); - ClassDB::bind_method(D_METHOD("is_playing_scene"), &EditorInterface::is_playing_scene); - ClassDB::bind_method(D_METHOD("get_playing_scene"), &EditorInterface::get_playing_scene); - ClassDB::bind_method(D_METHOD("get_open_scenes"), &EditorInterface::get_open_scenes); - ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &EditorInterface::get_edited_scene_root); - ClassDB::bind_method(D_METHOD("get_resource_previewer"), &EditorInterface::get_resource_previewer); - ClassDB::bind_method(D_METHOD("get_resource_filesystem"), &EditorInterface::get_resource_file_system); - ClassDB::bind_method(D_METHOD("get_editor_main_screen"), &EditorInterface::get_editor_main_screen); - ClassDB::bind_method(D_METHOD("make_mesh_previews", "meshes", "preview_size"), &EditorInterface::_make_mesh_previews); - ClassDB::bind_method(D_METHOD("select_file", "file"), &EditorInterface::select_file); - ClassDB::bind_method(D_METHOD("get_selected_paths"), &EditorInterface::get_selected_paths); - ClassDB::bind_method(D_METHOD("get_current_path"), &EditorInterface::get_current_path); - ClassDB::bind_method(D_METHOD("get_current_directory"), &EditorInterface::get_current_directory); - ClassDB::bind_method(D_METHOD("get_file_system_dock"), &EditorInterface::get_file_system_dock); - ClassDB::bind_method(D_METHOD("get_editor_paths"), &EditorInterface::get_editor_paths); - ClassDB::bind_method(D_METHOD("get_command_palette"), &EditorInterface::get_command_palette); - - ClassDB::bind_method(D_METHOD("set_plugin_enabled", "plugin", "enabled"), &EditorInterface::set_plugin_enabled); - ClassDB::bind_method(D_METHOD("is_plugin_enabled", "plugin"), &EditorInterface::is_plugin_enabled); - - ClassDB::bind_method(D_METHOD("set_movie_maker_enabled", "enabled"), &EditorInterface::set_movie_maker_enabled); - ClassDB::bind_method(D_METHOD("is_movie_maker_enabled"), &EditorInterface::is_movie_maker_enabled); - - ClassDB::bind_method(D_METHOD("get_inspector"), &EditorInterface::get_inspector); - - ClassDB::bind_method(D_METHOD("save_scene"), &EditorInterface::save_scene); - ClassDB::bind_method(D_METHOD("save_scene_as", "path", "with_preview"), &EditorInterface::save_scene_as, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("restart_editor", "save"), &EditorInterface::restart_editor, DEFVAL(true)); - - ClassDB::bind_method(D_METHOD("set_main_screen_editor", "name"), &EditorInterface::set_main_screen_editor); - ClassDB::bind_method(D_METHOD("set_distraction_free_mode", "enter"), &EditorInterface::set_distraction_free_mode); - ClassDB::bind_method(D_METHOD("is_distraction_free_mode_enabled"), &EditorInterface::is_distraction_free_mode_enabled); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distraction_free_mode"), "set_distraction_free_mode", "is_distraction_free_mode_enabled"); -} - -EditorInterface::EditorInterface() { - singleton = this; -} - -/////////////////////////////////////////// void EditorPlugin::add_custom_type(const String &p_type, const String &p_base, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon) { EditorNode::get_editor_data().add_custom_type(p_type, p_base, p_script, p_icon); } diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 74f46b2d0b..69789a4d4f 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -38,101 +38,20 @@ class Node3D; class Button; class PopupMenu; -class EditorCommandPalette; class EditorDebuggerPlugin; class EditorExport; class EditorExportPlugin; -class EditorFileSystem; class EditorImportPlugin; -class EditorInspector; class EditorInspectorPlugin; +class EditorInterface; class EditorNode3DGizmoPlugin; -class EditorPaths; class EditorResourceConversionPlugin; -class EditorResourcePreview; class EditorSceneFormatImporter; class EditorScenePostImportPlugin; -class EditorSelection; -class EditorSettings; class EditorToolAddons; class EditorTranslationParserPlugin; class EditorUndoRedoManager; -class FileSystemDock; class ScriptCreateDialog; -class ScriptEditor; -class VBoxContainer; - -class EditorInterface : public Node { - GDCLASS(EditorInterface, Node); - -protected: - static void _bind_methods(); - static EditorInterface *singleton; - - TypedArray<Texture2D> _make_mesh_previews(const TypedArray<Mesh> &p_meshes, int p_preview_size); - -public: - static EditorInterface *get_singleton() { return singleton; } - - VBoxContainer *get_editor_main_screen(); - void edit_resource(const Ref<Resource> &p_resource); - void edit_node(Node *p_node); - void edit_script(const Ref<Script> &p_script, int p_line = -1, int p_col = 0, bool p_grab_focus = true); - void open_scene_from_path(const String &scene_path); - void reload_scene_from_path(const String &scene_path); - - void play_main_scene(); - void play_current_scene(); - void play_custom_scene(const String &scene_path); - void stop_playing_scene(); - bool is_playing_scene() const; - String get_playing_scene() const; - - Node *get_edited_scene_root(); - PackedStringArray get_open_scenes() const; - ScriptEditor *get_script_editor(); - - EditorCommandPalette *get_command_palette() const; - - void select_file(const String &p_file); - Vector<String> get_selected_paths() const; - String get_current_path() const; - String get_current_directory() const; - - void inspect_object(Object *p_obj, const String &p_for_property = String(), bool p_inspector_only = false); - - EditorSelection *get_selection(); - //EditorImportExport *get_import_export(); - Ref<EditorSettings> get_editor_settings(); - EditorPaths *get_editor_paths(); - EditorResourcePreview *get_resource_previewer(); - EditorFileSystem *get_resource_file_system(); - - FileSystemDock *get_file_system_dock(); - - Control *get_base_control(); - float get_editor_scale() const; - - void set_plugin_enabled(const String &p_plugin, bool p_enabled); - bool is_plugin_enabled(const String &p_plugin) const; - - void set_movie_maker_enabled(bool p_enabled); - bool is_movie_maker_enabled() const; - - EditorInspector *get_inspector() const; - - Error save_scene(); - void save_scene_as(const String &p_scene, bool p_with_preview = true); - void restart_editor(bool p_save = true); - - Vector<Ref<Texture2D>> make_mesh_previews(const Vector<Ref<Mesh>> &p_meshes, Vector<Transform3D> *p_transforms, int p_preview_size); - - void set_main_screen_editor(const String &p_name); - void set_distraction_free_mode(bool p_enter); - bool is_distraction_free_mode_enabled() const; - - EditorInterface(); -}; class EditorPlugin : public Node { GDCLASS(EditorPlugin, Node); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index be66fbafac..bb0434a1bf 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -203,8 +203,7 @@ void EditorPropertyArray::_property_changed(const String &p_property, Variant p_ index = p_property.get_slice("/", 1).to_int(); } - Array array; - array.assign(object->get_array().duplicate()); + Variant array = object->get_array().duplicate(); array.set(index, p_value); object->set_array(array); emit_changed(get_edited_property(), array, "", true); diff --git a/editor/editor_run_script.cpp b/editor/editor_run_script.cpp index c87947d96b..a459943656 100644 --- a/editor/editor_run_script.cpp +++ b/editor/editor_run_script.cpp @@ -30,6 +30,7 @@ #include "editor_run_script.h" +#include "editor/editor_interface.h" #include "editor/editor_node.h" void EditorScript::add_root_node(Node *p_node) { diff --git a/editor/editor_run_script.h b/editor/editor_run_script.h index ea2fb1fd77..8284d59110 100644 --- a/editor/editor_run_script.h +++ b/editor/editor_run_script.h @@ -31,9 +31,11 @@ #ifndef EDITOR_RUN_SCRIPT_H #define EDITOR_RUN_SCRIPT_H +#include "core/object/gdvirtual.gen.inc" #include "core/object/ref_counted.h" -#include "editor/editor_plugin.h" +#include "core/object/script_language.h" +class EditorInterface; class EditorNode; class EditorScript : public RefCounted { diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h index 6a3213f8e4..20cc62d675 100644 --- a/editor/gui/scene_tree_editor.h +++ b/editor/gui/scene_tree_editor.h @@ -31,10 +31,11 @@ #ifndef SCENE_TREE_EDITOR_H #define SCENE_TREE_EDITOR_H -#include "editor/editor_data.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" +class EditorSelection; + class SceneTreeEditor : public Control { GDCLASS(SceneTreeEditor, Control); diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp index e6ba84294a..cbd00f0f6b 100644 --- a/editor/import/resource_importer_imagefont.cpp +++ b/editor/import/resource_importer_imagefont.cpp @@ -151,7 +151,7 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin int x = pos % columns; int y = pos / columns; font->set_glyph_advance(0, chr_height, idx, Vector2(chr_width, 0)); - font->set_glyph_offset(0, Vector2i(chr_height, 0), idx, Vector2(0, -0.5 * chr_height)); + font->set_glyph_offset(0, Vector2i(chr_height, 0), idx, Vector2i(0, -0.5 * chr_height)); font->set_glyph_size(0, Vector2i(chr_height, 0), idx, Vector2(chr_width, chr_height)); font->set_glyph_uv_rect(0, Vector2i(chr_height, 0), idx, Rect2(img_margin.position.x + chr_cell_width * x + char_margin.position.x, img_margin.position.y + chr_cell_height * y + char_margin.position.y, chr_width, chr_height)); font->set_glyph_texture_idx(0, Vector2i(chr_height, 0), idx, 0); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index e5f9b7b567..6d8c6842b2 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -40,6 +40,7 @@ class CanvasItemEditorViewport; class ConfirmationDialog; class EditorData; class EditorZoomWidget; +class EditorSelection; class HScrollBar; class HSplitContainer; class MenuButton; diff --git a/editor/plugins/control_editor_plugin.h b/editor/plugins/control_editor_plugin.h index 19e004a390..4a411c0241 100644 --- a/editor/plugins/control_editor_plugin.h +++ b/editor/plugins/control_editor_plugin.h @@ -45,6 +45,7 @@ #include "scene/gui/separator.h" #include "scene/gui/texture_rect.h" +class EditorSelection; class GridContainer; // Inspector controls. diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 20710bac19..a7ec4bfe33 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "core/core_string_names.h" #include "core/input/input.h" #include "core/os/keyboard.h" +#include "editor/editor_interface.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" @@ -780,7 +781,7 @@ CurveEditorPlugin::CurveEditorPlugin() { curve_plugin.instantiate(); EditorInspector::add_inspector_plugin(curve_plugin); - get_editor_interface()->get_resource_previewer()->add_preview_generator(memnew(CurvePreviewGenerator)); + EditorInterface::get_singleton()->get_resource_previewer()->add_preview_generator(memnew(CurvePreviewGenerator)); } //----------------------------------- diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp index abecba144c..9582f0caa5 100644 --- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp @@ -30,6 +30,7 @@ #include "gpu_particles_collision_sdf_editor_plugin.h" +#include "editor/editor_interface.h" #include "editor/editor_node.h" #include "editor/gui/editor_file_dialog.h" @@ -193,7 +194,7 @@ GPUParticlesCollisionSDF3DEditorPlugin::GPUParticlesCollisionSDF3DEditorPlugin() probe_file->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); probe_file->add_filter("*.exr"); probe_file->connect("file_selected", callable_mp(this, &GPUParticlesCollisionSDF3DEditorPlugin::_sdf_save_path_and_bake)); - get_editor_interface()->get_base_control()->add_child(probe_file); + EditorInterface::get_singleton()->get_base_control()->add_child(probe_file); probe_file->set_title(TTR("Select path for SDF Texture")); GPUParticlesCollisionSDF3D::bake_begin_function = bake_func_begin; diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 3959ed2976..7bee4d01ee 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -30,6 +30,7 @@ #include "mesh_library_editor_plugin.h" +#include "editor/editor_interface.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/gui/editor_file_dialog.h" diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index c4193f0420..c4e1070d84 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -44,6 +44,7 @@ class ColorPickerButton; class ConfirmationDialog; class DirectionalLight3D; class EditorData; +class EditorSelection; class EditorSpinSlider; class HSplitContainer; class LineEdit; diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index a057bbe05e..b59bf3a37b 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/io/resource_loader.h" +#include "editor/editor_interface.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index 1682d07e13..719de9dc81 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "core/os/mutex.h" +#include "editor/editor_interface.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" @@ -209,7 +210,7 @@ void TilesEditorPlugin::make_visible(bool p_visible) { } bool TilesEditorPlugin::is_tile_map_selected() { - TypedArray<Node> selection = get_editor_interface()->get_selection()->get_selected_nodes(); + TypedArray<Node> selection = EditorInterface::get_singleton()->get_selection()->get_selected_nodes(); if (selection.size() == 1 && Object::cast_to<TileMap>(selection[0])) { return true; } diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp index 9906399d67..5ae5468e4b 100644 --- a/editor/plugins/voxel_gi_editor_plugin.cpp +++ b/editor/plugins/voxel_gi_editor_plugin.cpp @@ -30,6 +30,7 @@ #include "voxel_gi_editor_plugin.h" +#include "editor/editor_interface.h" #include "editor/editor_node.h" #include "editor/gui/editor_file_dialog.h" @@ -190,7 +191,7 @@ VoxelGIEditorPlugin::VoxelGIEditorPlugin() { probe_file->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); probe_file->add_filter("*.res"); probe_file->connect("file_selected", callable_mp(this, &VoxelGIEditorPlugin::_voxel_gi_save_path_and_bake)); - get_editor_interface()->get_base_control()->add_child(probe_file); + EditorInterface::get_singleton()->get_base_control()->add_child(probe_file); probe_file->set_title(TTR("Select path for VoxelGI Data File")); VoxelGI::bake_begin_function = bake_func_begin; diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp index d0c441b027..66d6eb4923 100644 --- a/editor/register_editor_types.cpp +++ b/editor/register_editor_types.cpp @@ -35,6 +35,7 @@ #include "editor/editor_command_palette.h" #include "editor/editor_feature_profile.h" #include "editor/editor_file_system.h" +#include "editor/editor_interface.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" #include "editor/editor_resource_picker.h" @@ -230,10 +231,14 @@ void register_editor_types() { GLOBAL_DEF("editor/version_control/plugin_name", ""); GLOBAL_DEF("editor/version_control/autoload_on_startup", false); + + EditorInterface::create(); } void unregister_editor_types() { EditorNode::cleanup(); + EditorInterface::free(); + if (EditorPaths::get_singleton()) { EditorPaths::free(); } diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 779bfd53e3..75acb37973 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -31,12 +31,13 @@ #ifndef SCENE_TREE_DOCK_H #define SCENE_TREE_DOCK_H -#include "editor/editor_data.h" #include "editor/gui/scene_tree_editor.h" #include "editor/script_create_dialog.h" #include "scene/gui/box_container.h" #include "scene/resources/animation.h" +class EditorData; +class EditorSelection; class EditorQuickOpen; class MenuButton; class ReparentDialog; diff --git a/modules/multiplayer/editor/multiplayer_editor_plugin.cpp b/modules/multiplayer/editor/multiplayer_editor_plugin.cpp index 28d05e1dee..af2db543c0 100644 --- a/modules/multiplayer/editor/multiplayer_editor_plugin.cpp +++ b/modules/multiplayer/editor/multiplayer_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "editor_network_profiler.h" #include "replication_editor.h" +#include "editor/editor_interface.h" #include "editor/editor_node.h" void MultiplayerEditorDebugger::_bind_methods() { @@ -119,7 +120,7 @@ MultiplayerEditorPlugin::MultiplayerEditorPlugin() { } void MultiplayerEditorPlugin::_open_request(const String &p_path) { - get_editor_interface()->open_scene_from_path(p_path); + EditorInterface::get_singleton()->open_scene_from_path(p_path); } void MultiplayerEditorPlugin::_notification(int p_what) { diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp index ec1fcf6698..b45b7e676d 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.cpp +++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp @@ -138,6 +138,17 @@ FreeDesktopPortalDesktop::FreeDesktopPortalDesktop() { #else unsupported = false; #endif + bool ver_ok = false; + int version_major = 0; + int version_minor = 0; + int version_rev = 0; + dbus_get_version(&version_major, &version_minor, &version_rev); + ver_ok = (version_major == 1 && version_minor >= 10) || (version_major > 1); // 1.10.0 + print_verbose(vformat("PortalDesktop: DBus %d.%d.%d detected.", version_major, version_minor, version_rev)); + if (!ver_ok) { + print_verbose("PortalDesktop: Unsupported DBus library version!"); + unsupported = true; + } } #endif // DBUS_ENABLED diff --git a/platform/linuxbsd/freedesktop_screensaver.cpp b/platform/linuxbsd/freedesktop_screensaver.cpp index d07e781a5f..78f2337599 100644 --- a/platform/linuxbsd/freedesktop_screensaver.cpp +++ b/platform/linuxbsd/freedesktop_screensaver.cpp @@ -141,6 +141,17 @@ FreeDesktopScreenSaver::FreeDesktopScreenSaver() { #else unsupported = false; #endif + bool ver_ok = false; + int version_major = 0; + int version_minor = 0; + int version_rev = 0; + dbus_get_version(&version_major, &version_minor, &version_rev); + ver_ok = (version_major == 1 && version_minor >= 10) || (version_major > 1); // 1.10.0 + print_verbose(vformat("ScreenSaver: DBus %d.%d.%d detected.", version_major, version_minor, version_rev)); + if (!ver_ok) { + print_verbose("ScreenSaver:: Unsupported DBus library version!"); + unsupported = true; + } } #endif // DBUS_ENABLED diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index 0256af0a59..5c623b8ba2 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -82,7 +82,13 @@ JoypadLinux::JoypadLinux(Input *in) { #endif use_udev = initialize_libudev(dylibloader_verbose) == 0; if (use_udev) { - print_verbose("JoypadLinux: udev enabled and loaded successfully."); + if (!udev_new || !udev_unref || !udev_enumerate_new || !udev_enumerate_add_match_subsystem || !udev_enumerate_scan_devices || !udev_enumerate_get_list_entry || !udev_list_entry_get_next || !udev_list_entry_get_name || !udev_device_new_from_syspath || !udev_device_get_devnode || !udev_device_get_action || !udev_device_unref || !udev_enumerate_unref || !udev_monitor_new_from_netlink || !udev_monitor_filter_add_match_subsystem_devtype || !udev_monitor_enable_receiving || !udev_monitor_get_fd || !udev_monitor_receive_device || !udev_monitor_unref) { + // There's no API to check version, check if functions are available instead. + use_udev = false; + print_verbose("JoypadLinux: Unsupported udev library version!"); + } else { + print_verbose("JoypadLinux: udev enabled and loaded successfully."); + } } else { print_verbose("JoypadLinux: udev enabled, but couldn't be loaded. Falling back to /dev/input to detect joypads."); } diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index 88c3d2cc14..11c81be4a9 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -1103,6 +1103,16 @@ OS_LinuxBSD::OS_LinuxBSD() { font_config_initialized = true; #endif if (font_config_initialized) { + bool ver_ok = false; + int version = FcGetVersion(); + ver_ok = ((version / 100 / 100) == 2 && (version / 100 % 100) >= 11) || ((version / 100 / 100) > 2); // 2.11.0 + print_verbose(vformat("FontConfig %d.%d.%d detected.", version / 100 / 100, version / 100 % 100, version % 100)); + if (!ver_ok) { + font_config_initialized = false; + } + } + + if (font_config_initialized) { config = FcInitLoadConfigAndFonts(); if (!config) { font_config_initialized = false; diff --git a/platform/linuxbsd/tts_linux.cpp b/platform/linuxbsd/tts_linux.cpp index ce0199e87f..a0cb4f5c6c 100644 --- a/platform/linuxbsd/tts_linux.cpp +++ b/platform/linuxbsd/tts_linux.cpp @@ -48,6 +48,11 @@ void TTS_Linux::speech_init_thread_func(void *p_userdata) { if (initialize_speechd(dylibloader_verbose) != 0) { print_verbose("Text-to-Speech: Cannot load Speech Dispatcher library!"); } else { + if (!spd_open || !spd_set_notification_on || !spd_list_synthesis_voices || !free_spd_voices || !spd_set_synthesis_voice || !spd_set_volume || !spd_set_voice_pitch || !spd_set_voice_rate || !spd_set_data_mode || !spd_say || !spd_pause || !spd_resume || !spd_cancel) { + // There's no API to check version, check if functions are available instead. + print_verbose("Text-to-Speech: Unsupported Speech Dispatcher library version!"); + return; + } #else { #endif diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 52ee9e8e6f..48d4e078df 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -1354,7 +1354,7 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) { } XDestroyWindow(x11_display, wd.x11_xim_window); #ifdef XKB_ENABLED - if (xkb_loaded) { + if (xkb_loaded_v05p) { if (wd.xkb_state) { xkb_compose_state_unref(wd.xkb_state); wd.xkb_state = nullptr; @@ -2982,7 +2982,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, String keysym; #ifdef XKB_ENABLED - if (xkb_loaded) { + if (xkb_loaded_v08p) { KeySym keysym_unicode_nm = 0; // keysym used to find unicode XLookupString(&xkeyevent_no_mod, nullptr, 0, &keysym_unicode_nm, nullptr); keysym = String::chr(xkb_keysym_to_utf32(xkb_keysym_to_upper(keysym_unicode_nm))); @@ -3077,7 +3077,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, } while (status == XBufferOverflow); #endif #ifdef XKB_ENABLED - } else if (xkeyevent->type == KeyPress && wd.xkb_state && xkb_loaded) { + } else if (xkeyevent->type == KeyPress && wd.xkb_state && xkb_loaded_v05p) { xkb_compose_feed_result res = xkb_compose_state_feed(wd.xkb_state, keysym_unicode); if (res == XKB_COMPOSE_FEED_ACCEPTED) { if (xkb_compose_state_get_status(wd.xkb_state) == XKB_COMPOSE_COMPOSED) { @@ -5004,7 +5004,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V wd.x11_xim_window = XCreateWindow(x11_display, wd.x11_window, 0, 0, 1, 1, 0, CopyFromParent, InputOnly, CopyFromParent, CWEventMask, &window_attributes_ime); #ifdef XKB_ENABLED - if (dead_tbl && xkb_loaded) { + if (dead_tbl && xkb_loaded_v05p) { wd.xkb_state = xkb_compose_state_new(dead_tbl, XKB_COMPOSE_STATE_NO_FLAGS); } #endif @@ -5288,9 +5288,16 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode ERR_FAIL_MSG("Can't load XCursor dynamically."); } #ifdef XKB_ENABLED - xkb_loaded = (initialize_xkbcommon(dylibloader_verbose) == 0); - if (!xkb_context_new || !xkb_compose_table_new_from_locale || !xkb_compose_table_unref || !xkb_context_unref || !xkb_compose_state_feed || !xkb_compose_state_unref || !xkb_compose_state_new || !xkb_compose_state_get_status || !xkb_compose_state_get_utf8 || !xkb_keysym_to_utf32 || !xkb_keysym_to_upper) { - xkb_loaded = false; + bool xkb_loaded = (initialize_xkbcommon(dylibloader_verbose) == 0); + xkb_loaded_v05p = xkb_loaded; + if (!xkb_context_new || !xkb_compose_table_new_from_locale || !xkb_compose_table_unref || !xkb_context_unref || !xkb_compose_state_feed || !xkb_compose_state_unref || !xkb_compose_state_new || !xkb_compose_state_get_status || !xkb_compose_state_get_utf8) { + xkb_loaded_v05p = false; + print_verbose("Detected XKBcommon library version older than 0.5, dead key composition and Unicode key labels disabled."); + } + xkb_loaded_v08p = xkb_loaded; + if (!xkb_keysym_to_utf32 || !xkb_keysym_to_upper) { + xkb_loaded_v08p = false; + print_verbose("Detected XKBcommon library version older than 0.8, Unicode key labels disabled."); } #endif if (initialize_xext(dylibloader_verbose) != 0) { @@ -5346,6 +5353,15 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode r_error = OK; + { + if (!XcursorImageCreate || !XcursorImageLoadCursor || !XcursorImageDestroy || !XcursorGetDefaultSize || !XcursorGetTheme || !XcursorLibraryLoadImage) { + // There's no API to check version, check if functions are available instead. + ERR_PRINT("Unsupported Xcursor library version."); + r_error = ERR_UNAVAILABLE; + return; + } + } + for (int i = 0; i < CURSOR_MAX; i++) { cursors[i] = None; img[i] = nullptr; @@ -5362,6 +5378,71 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode return; } + { + int version_major = 0; + int version_minor = 0; + int rc = XShapeQueryVersion(x11_display, &version_major, &version_minor); + print_verbose(vformat("Xshape %d.%d detected.", version_major, version_minor)); + if (rc != 1 || version_major < 1) { + ERR_PRINT("Unsupported Xshape library version."); + r_error = ERR_UNAVAILABLE; + XCloseDisplay(x11_display); + return; + } + } + + { + int version_major = 0; + int version_minor = 0; + int rc = XineramaQueryVersion(x11_display, &version_major, &version_minor); + print_verbose(vformat("Xinerama %d.%d detected.", version_major, version_minor)); + if (rc != 1 || version_major < 1) { + ERR_PRINT("Unsupported Xinerama library version."); + r_error = ERR_UNAVAILABLE; + XCloseDisplay(x11_display); + return; + } + } + + { + int version_major = 0; + int version_minor = 0; + int rc = XRRQueryVersion(x11_display, &version_major, &version_minor); + print_verbose(vformat("Xrandr %d.%d detected.", version_major, version_minor)); + if (rc != 1 || (version_major == 1 && version_minor < 3) || (version_major < 1)) { + ERR_PRINT("Unsupported Xrandr library version."); + r_error = ERR_UNAVAILABLE; + XCloseDisplay(x11_display); + return; + } + } + + { + int version_major = 0; + int version_minor = 0; + int rc = XRenderQueryVersion(x11_display, &version_major, &version_minor); + print_verbose(vformat("Xrender %d.%d detected.", version_major, version_minor)); + if (rc != 1 || (version_major == 0 && version_minor < 11)) { + ERR_PRINT("Unsupported Xrender library version."); + r_error = ERR_UNAVAILABLE; + XCloseDisplay(x11_display); + return; + } + } + + { + int version_major = 2; // Report 2.2 as supported by engine, but should work with 2.1 or 2.0 library as well. + int version_minor = 2; + int rc = XIQueryVersion(x11_display, &version_major, &version_minor); + print_verbose(vformat("Xinput %d.%d detected.", version_major, version_minor)); + if (rc != Success || (version_major < 2)) { + ERR_PRINT("Unsupported Xinput2 library version."); + r_error = ERR_UNAVAILABLE; + XCloseDisplay(x11_display); + return; + } + } + char *modifiers = nullptr; Bool xkb_dar = False; XAutoRepeatOn(x11_display); @@ -5784,7 +5865,7 @@ DisplayServerX11::~DisplayServerX11() { } XDestroyWindow(x11_display, wd.x11_xim_window); #ifdef XKB_ENABLED - if (xkb_loaded) { + if (xkb_loaded_v05p) { if (wd.xkb_state) { xkb_compose_state_unref(wd.xkb_state); wd.xkb_state = nullptr; @@ -5796,7 +5877,7 @@ DisplayServerX11::~DisplayServerX11() { } #ifdef XKB_ENABLED - if (xkb_loaded) { + if (xkb_loaded_v05p) { if (dead_tbl) { xkb_compose_table_unref(dead_tbl); } diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index c19d2f441a..f6a1bc8012 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -212,7 +212,8 @@ class DisplayServerX11 : public DisplayServer { String im_text; #ifdef XKB_ENABLED - bool xkb_loaded = false; + bool xkb_loaded_v05p = false; + bool xkb_loaded_v08p = false; xkb_context *xkb_ctx = nullptr; xkb_compose_table *dead_tbl = nullptr; #endif diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp index 867f1d537c..e32fbd47dd 100644 --- a/platform/windows/crash_handler_windows.cpp +++ b/platform/windows/crash_handler_windows.cpp @@ -47,9 +47,6 @@ #include <psapi.h> -#pragma comment(lib, "psapi.lib") -#pragma comment(lib, "dbghelp.lib") - // Some versions of imagehlp.dll lack the proper packing directives themselves // so we need to do it. #pragma pack(push, before_imagehlp, 8) diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 1b55574b19..ba8d27bba5 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -409,6 +409,9 @@ def configure_msvc(env, vcvars_msvc_config): "wbemuuid", ] + if env.debug_features: + LIBS += ["psapi", "dbghelp"] + if env["vulkan"]: env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"]) if not env["use_volk"]: @@ -587,6 +590,9 @@ def configure_mingw(env): ] ) + if env.debug_features: + env.Append(LIBS=["psapi", "dbghelp"]) + if env["vulkan"]: env.Append(CPPDEFINES=["VULKAN_ENABLED"]) if not env["use_volk"]: diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 6ff928580a..4c2d7ee5cc 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -4406,5 +4406,4 @@ DisplayServerWindows::~DisplayServerWindows() { if (tts) { memdelete(tts); } - CoUninitialize(); } diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 6e219fb929..456240ba2d 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -55,6 +55,12 @@ #include <shlobj.h> #include <wbemcli.h> +#ifdef DEBUG_ENABLED +#pragma pack(push, before_imagehlp, 8) +#include <imagehlp.h> +#pragma pack(pop, before_imagehlp) +#endif + extern "C" { __declspec(dllexport) DWORD NvOptimusEnablement = 1; __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; @@ -88,7 +94,7 @@ static String format_error_message(DWORD id) { LocalFree(messageBuffer); - return msg; + return msg.replace("\r", "").replace("\n", ""); } void RedirectStream(const char *p_file_name, const char *p_mode, FILE *p_cpp_stream, const DWORD p_std_handle) { @@ -195,7 +201,6 @@ void OS_Windows::initialize() { IPUnix::make_default(); main_loop = nullptr; - CoInitialize(nullptr); HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), reinterpret_cast<IUnknown **>(&dwrite_factory)); if (SUCCEEDED(hr)) { hr = dwrite_factory->GetSystemFontCollection(&font_collection, false); @@ -277,6 +282,73 @@ Error OS_Windows::get_entropy(uint8_t *r_buffer, int p_bytes) { return OK; } +#ifdef DEBUG_ENABLED +void debug_dynamic_library_check_dependencies(const String &p_root_path, const String &p_path, HashSet<String> &r_checked, HashSet<String> &r_missing) { + if (r_checked.has(p_path)) { + return; + } + r_checked.insert(p_path); + + LOADED_IMAGE loaded_image; + HANDLE file = CreateFileW((LPCWSTR)p_path.utf16().get_data(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr); + if (file != INVALID_HANDLE_VALUE) { + HANDLE file_mapping = CreateFileMappingW(file, nullptr, PAGE_READONLY | SEC_COMMIT, 0, 0, nullptr); + if (file_mapping != INVALID_HANDLE_VALUE) { + PVOID mapping = MapViewOfFile(file_mapping, FILE_MAP_READ, 0, 0, 0); + if (mapping) { + PIMAGE_DOS_HEADER dos_header = (PIMAGE_DOS_HEADER)mapping; + PIMAGE_NT_HEADERS nt_header = nullptr; + if (dos_header->e_magic == IMAGE_DOS_SIGNATURE) { + PCHAR nt_header_ptr; + nt_header_ptr = ((PCHAR)mapping) + dos_header->e_lfanew; + nt_header = (PIMAGE_NT_HEADERS)nt_header_ptr; + if (nt_header->Signature != IMAGE_NT_SIGNATURE) { + nt_header = nullptr; + } + } + if (nt_header) { + loaded_image.ModuleName = nullptr; + loaded_image.hFile = file; + loaded_image.MappedAddress = (PUCHAR)mapping; + loaded_image.FileHeader = nt_header; + loaded_image.Sections = (PIMAGE_SECTION_HEADER)((LPBYTE)&nt_header->OptionalHeader + nt_header->FileHeader.SizeOfOptionalHeader); + loaded_image.NumberOfSections = nt_header->FileHeader.NumberOfSections; + loaded_image.SizeOfImage = GetFileSize(file, nullptr); + loaded_image.Characteristics = nt_header->FileHeader.Characteristics; + loaded_image.LastRvaSection = loaded_image.Sections; + loaded_image.fSystemImage = false; + loaded_image.fDOSImage = false; + loaded_image.Links.Flink = &loaded_image.Links; + loaded_image.Links.Blink = &loaded_image.Links; + + ULONG size = 0; + const IMAGE_IMPORT_DESCRIPTOR *import_desc = (const IMAGE_IMPORT_DESCRIPTOR *)ImageDirectoryEntryToData((HMODULE)loaded_image.MappedAddress, false, IMAGE_DIRECTORY_ENTRY_IMPORT, &size); + if (import_desc) { + for (; import_desc->Name && import_desc->FirstThunk; import_desc++) { + char16_t full_name_wc[MAX_PATH]; + const char *name_cs = (const char *)ImageRvaToVa(loaded_image.FileHeader, loaded_image.MappedAddress, import_desc->Name, 0); + String name = String(name_cs); + if (name.begins_with("api-ms-win-")) { + r_checked.insert(name); + } else if (SearchPathW(nullptr, (LPCWSTR)name.utf16().get_data(), nullptr, MAX_PATH, (LPWSTR)full_name_wc, nullptr)) { + debug_dynamic_library_check_dependencies(p_root_path, String::utf16(full_name_wc), r_checked, r_missing); + } else if (SearchPathW((LPCWSTR)(p_path.get_base_dir().utf16().get_data()), (LPCWSTR)name.utf16().get_data(), nullptr, MAX_PATH, (LPWSTR)full_name_wc, nullptr)) { + debug_dynamic_library_check_dependencies(p_root_path, String::utf16(full_name_wc), r_checked, r_missing); + } else { + r_missing.insert(name); + } + } + } + } + UnmapViewOfFile(mapping); + } + CloseHandle(file_mapping); + } + CloseHandle(file); + } +} +#endif + Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) { String path = p_path.replace("/", "\\"); @@ -299,7 +371,29 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han } p_library_handle = (void *)LoadLibraryExW((LPCWSTR)(path.utf16().get_data()), nullptr, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0); - ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + format_error_message(GetLastError()) + "."); +#ifdef DEBUG_ENABLED + if (!p_library_handle) { + DWORD err_code = GetLastError(); + + HashSet<String> checekd_libs; + HashSet<String> missing_libs; + debug_dynamic_library_check_dependencies(path, path, checekd_libs, missing_libs); + if (!missing_libs.is_empty()) { + String missing; + for (const String &E : missing_libs) { + if (!missing.is_empty()) { + missing += ", "; + } + missing += E; + } + ERR_FAIL_V_MSG(ERR_CANT_OPEN, vformat("Can't open dynamic library: %s, missing dependencies: (%s), error: \"%s\".", p_path, missing, format_error_message(err_code))); + } else { + ERR_FAIL_V_MSG(ERR_CANT_OPEN, vformat("Can't open dynamic library: %s, error: \"%s\"." + p_path, format_error_message(err_code))); + } + } +#else + ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s, error: \"%s\"." + p_path, format_error_message(GetLastError()))); +#endif if (cookie) { remove_dll_directory(cookie); @@ -323,7 +417,7 @@ Error OS_Windows::get_dynamic_library_symbol_handle(void *p_library_handle, cons p_symbol_handle = (void *)GetProcAddress((HMODULE)p_library_handle, p_name.utf8().get_data()); if (!p_symbol_handle) { if (!p_optional) { - ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Can't resolve symbol " + p_name + ", error: " + String::num(GetLastError()) + "."); + ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, vformat("Can't resolve symbol %s, error: \"%s\".", p_name, format_error_message(GetLastError()))); } else { return ERR_CANT_RESOLVE; } @@ -373,8 +467,6 @@ Vector<String> OS_Windows::get_video_adapter_driver_info() const { return Vector<String>(); } - CoInitialize(nullptr); - HRESULT hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, uuid, (LPVOID *)&wbemLocator); if (hr != S_OK) { return Vector<String>(); @@ -1505,6 +1597,8 @@ Error OS_Windows::move_to_trash(const String &p_path) { OS_Windows::OS_Windows(HINSTANCE _hInstance) { hInstance = _hInstance; + CoInitializeEx(nullptr, COINIT_MULTITHREADED); + #ifdef WASAPI_ENABLED AudioDriverManager::add_driver(&driver_wasapi); #endif @@ -1532,4 +1626,5 @@ OS_Windows::OS_Windows(HINSTANCE _hInstance) { } OS_Windows::~OS_Windows() { + CoUninitialize(); } diff --git a/platform/windows/tts_windows.cpp b/platform/windows/tts_windows.cpp index 54ab93ee01..907096d890 100644 --- a/platform/windows/tts_windows.cpp +++ b/platform/windows/tts_windows.cpp @@ -118,7 +118,7 @@ bool TTS_Windows::is_speaking() const { SPVOICESTATUS status; synth->GetStatus(&status, nullptr); - return (status.dwRunningState == SPRS_IS_SPEAKING); + return (status.dwRunningState == SPRS_IS_SPEAKING || status.dwRunningState == 0 /* Waiting To Speak */); } bool TTS_Windows::is_paused() const { @@ -251,7 +251,6 @@ TTS_Windows *TTS_Windows::get_singleton() { TTS_Windows::TTS_Windows() { singleton = this; - CoInitialize(nullptr); if (SUCCEEDED(CoCreateInstance(CLSID_SpVoice, nullptr, CLSCTX_ALL, IID_ISpVoice, (void **)&synth))) { ULONGLONG event_mask = SPFEI(SPEI_END_INPUT_STREAM) | SPFEI(SPEI_START_INPUT_STREAM) | SPFEI(SPEI_WORD_BOUNDARY); diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index ba361c2656..c678b4bf02 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1036,7 +1036,7 @@ void RigidBody2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "linear_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_linear_damp_mode", "get_linear_damp_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_linear_damp", "get_linear_damp"); ADD_GROUP("Angular", "angular_"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_velocity", PROPERTY_HINT_NONE, "suffix:rad/s"), "set_angular_velocity", "get_angular_velocity"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_velocity", PROPERTY_HINT_NONE, U"radians,suffix:\u00B0/s"), "set_angular_velocity", "get_angular_velocity"); ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_angular_damp_mode", "get_angular_damp_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); ADD_GROUP("Constant Forces", "constant_"); diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 89bb1b5c65..b7d63258db 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -1108,8 +1108,8 @@ void RigidBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "angular_damp_mode", PROPERTY_HINT_ENUM, "Combine,Replace"), "set_angular_damp_mode", "get_angular_damp_mode"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), "set_angular_damp", "get_angular_damp"); ADD_GROUP("Constant Forces", "constant_"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_force"), "set_constant_force", "get_constant_force"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_torque"), "set_constant_torque", "get_constant_torque"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_force", PROPERTY_HINT_NONE, U"suffix:kg\u22C5m/s\u00B2 (N)"), "set_constant_force", "get_constant_force"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "constant_torque", PROPERTY_HINT_NONE, U"suffix:kg\u22C5m\u00B2/s\u00B2/rad"), "set_constant_torque", "get_constant_torque"); ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::RID, "body_rid"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape_index"), PropertyInfo(Variant::INT, "local_shape_index"))); |