diff options
62 files changed, 882 insertions, 121 deletions
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 3b9b1f9094..d358a8d2a0 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -535,6 +535,13 @@ TypedArray<int> ScriptLanguage::CodeCompletionOption::get_option_cached_characte return charac; } +void ScriptLanguage::_bind_methods() { + BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_AUTO); + BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_PASCAL_CASE); + BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_SNAKE_CASE); + BIND_ENUM_CONSTANT(SCRIPT_NAME_CASING_KEBAB_CASE); +} + bool PlaceHolderScriptInstance::set(const StringName &p_name, const Variant &p_value) { if (script->is_placeholder_fallback_enabled()) { return false; diff --git a/core/object/script_language.h b/core/object/script_language.h index 4217bc9f96..95e9d2b4af 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -193,6 +193,10 @@ public: class ScriptLanguage : public Object { GDCLASS(ScriptLanguage, Object) + +protected: + static void _bind_methods(); + public: virtual String get_name() const = 0; @@ -224,6 +228,13 @@ public: TEMPLATE_PROJECT }; + enum ScriptNameCasing { + SCRIPT_NAME_CASING_AUTO, + SCRIPT_NAME_CASING_PASCAL_CASE, + SCRIPT_NAME_CASING_SNAKE_CASE, + SCRIPT_NAME_CASING_KEBAB_CASE, + }; + struct ScriptTemplate { String inherit = "Object"; String name; @@ -260,6 +271,7 @@ public: virtual bool can_make_function() const { return true; } virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; } virtual bool overrides_external_editor() { return false; } + virtual ScriptNameCasing preferred_file_name_casing() const { return SCRIPT_NAME_CASING_SNAKE_CASE; } // Keep enums in sync with: // scene/gui/code_edit.h - CodeEdit::CodeCompletionKind @@ -405,6 +417,8 @@ public: virtual ~ScriptLanguage() {} }; +VARIANT_ENUM_CAST(ScriptLanguage::ScriptNameCasing); + extern uint8_t script_encryption_key[32]; class PlaceHolderScriptInstance : public ScriptInstance { diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp index 3a9b171f28..ec99c7cf4e 100644 --- a/core/object/script_language_extension.cpp +++ b/core/object/script_language_extension.cpp @@ -112,6 +112,7 @@ void ScriptLanguageExtension::_bind_methods() { GDVIRTUAL_BIND(_can_make_function); GDVIRTUAL_BIND(_open_in_external_editor, "script", "line", "column"); GDVIRTUAL_BIND(_overrides_external_editor); + GDVIRTUAL_BIND(_preferred_file_name_casing); GDVIRTUAL_BIND(_complete_code, "code", "path", "owner"); GDVIRTUAL_BIND(_lookup_code, "code", "symbol", "path", "owner"); diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h index aa0788b8bf..18105ec8cd 100644 --- a/core/object/script_language_extension.h +++ b/core/object/script_language_extension.h @@ -376,6 +376,7 @@ public: EXBIND0RC(bool, can_make_function) EXBIND3R(Error, open_in_external_editor, const Ref<Script> &, int, int) EXBIND0R(bool, overrides_external_editor) + EXBIND0RC(ScriptNameCasing, preferred_file_name_casing) GDVIRTUAL3RC(Dictionary, _complete_code, const String &, const String &, Object *) diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 9d36e548a2..d3c76737db 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -102,8 +102,8 @@ <param index="2" name="existing_text" type="String" /> <param index="3" name="callback" type="Callable" /> <description> - Shows a text input dialog which uses the operating system's native look-and-feel. [param callback] will be called with a [String] argument equal to the text field's contents when the dialog is closed for any reason. - [b]Note:[/b] This method is implemented only on macOS. + Shows a text input dialog which uses the operating system's native look-and-feel. [param callback] should accept a single [String] parameter which contains the text field's contents. + [b]Note:[/b] This method is implemented only on macOS and Windows. </description> </method> <method name="dialog_show"> @@ -113,8 +113,8 @@ <param index="2" name="buttons" type="PackedStringArray" /> <param index="3" name="callback" type="Callable" /> <description> - Shows a text dialog which uses the operating system's native look-and-feel. [param callback] will be called when the dialog is closed for any reason. - [b]Note:[/b] This method is implemented only on macOS. + Shows a text dialog which uses the operating system's native look-and-feel. [param callback] should accept a single [int] parameter which corresponds to the index of the pressed button. + [b]Note:[/b] This method is implemented only on macOS and Windows. </description> </method> <method name="enable_for_stealing_focus"> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index 8a8955e95b..923c22e871 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -995,6 +995,9 @@ <member name="text_editor/behavior/indent/auto_indent" type="bool" setter="" getter=""> If [code]true[/code], automatically indents code when pressing the [kbd]Enter[/kbd] key based on blocks above the new line. </member> + <member name="text_editor/behavior/indent/indent_wrapped_lines" type="bool" setter="" getter=""> + If [code]true[/code], all wrapped lines are indented to the same amount as the unwrapped line. + </member> <member name="text_editor/behavior/indent/size" type="int" setter="" getter=""> When using tab indentation, determines the length of each tab. When using space indentation, determines how many spaces are inserted when pressing [kbd]Tab[/kbd] and when automatic indentation is performed. </member> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 7c3dfeda4c..6e864316f1 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -948,13 +948,16 @@ The format of the default signal callback name when a signal connects to the same node that emits it (in the Signal Connection Dialog). The following substitutions are available: [code]{NodeName}[/code], [code]{nodeName}[/code], [code]{node_name}[/code], [code]{SignalName}[/code], [code]{signalName}[/code], and [code]{signal_name}[/code]. </member> <member name="editor/naming/node_name_casing" type="int" setter="" getter="" default="0"> - When creating node names automatically, set the type of casing in this project. This is mostly an editor setting. + When creating node names automatically, set the type of casing to use in this project. This is mostly an editor setting. </member> <member name="editor/naming/node_name_num_separator" type="int" setter="" getter="" default="0"> What to use to separate node name from number. This is mostly an editor setting. </member> <member name="editor/naming/scene_name_casing" type="int" setter="" getter="" default="2"> - When generating file names from scene root node, set the type of casing in this project. This is mostly an editor setting. + When generating scene file names from scene root node, set the type of casing to use in this project. This is mostly an editor setting. + </member> + <member name="editor/naming/script_name_casing" type="int" setter="" getter="" default="0"> + When generating script file names from the selected node, set the type of casing to use in this project. This is mostly an editor setting. </member> <member name="editor/run/main_run_args" type="String" setter="" getter="" default=""""> The command-line arguments to append to Godot's own command line when running the project. This doesn't affect the editor itself. diff --git a/doc/classes/ScriptLanguage.xml b/doc/classes/ScriptLanguage.xml index 51134012c7..0a1b801f9b 100644 --- a/doc/classes/ScriptLanguage.xml +++ b/doc/classes/ScriptLanguage.xml @@ -6,4 +6,14 @@ </description> <tutorials> </tutorials> + <constants> + <constant name="SCRIPT_NAME_CASING_AUTO" value="0" enum="ScriptNameCasing"> + </constant> + <constant name="SCRIPT_NAME_CASING_PASCAL_CASE" value="1" enum="ScriptNameCasing"> + </constant> + <constant name="SCRIPT_NAME_CASING_SNAKE_CASE" value="2" enum="ScriptNameCasing"> + </constant> + <constant name="SCRIPT_NAME_CASING_KEBAB_CASE" value="3" enum="ScriptNameCasing"> + </constant> + </constants> </class> diff --git a/doc/classes/ScriptLanguageExtension.xml b/doc/classes/ScriptLanguageExtension.xml index 87d82d8af7..a453866e27 100644 --- a/doc/classes/ScriptLanguageExtension.xml +++ b/doc/classes/ScriptLanguageExtension.xml @@ -267,6 +267,11 @@ <description> </description> </method> + <method name="_preferred_file_name_casing" qualifiers="virtual const"> + <return type="int" enum="ScriptLanguage.ScriptNameCasing" /> + <description> + </description> + </method> <method name="_profiling_get_accumulated_data" qualifiers="virtual"> <return type="int" /> <param index="0" name="info_array" type="ScriptLanguageExtensionProfilingInfo*" /> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index b8a838208b..04d05e7860 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -1154,6 +1154,9 @@ <member name="highlight_current_line" type="bool" setter="set_highlight_current_line" getter="is_highlight_current_line_enabled" default="false"> If [code]true[/code], the line containing the cursor is highlighted. </member> + <member name="indent_wrapped_lines" type="bool" setter="set_indent_wrapped_lines" getter="is_indent_wrapped_lines" default="false"> + If [code]true[/code], all wrapped lines are indented to the same amount as the unwrapped line. + </member> <member name="language" type="String" setter="set_language" getter="get_language" default=""""> Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead. </member> diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml index d4b341b700..9a17fb3def 100644 --- a/doc/classes/TextServer.xml +++ b/doc/classes/TextServer.xml @@ -1837,6 +1837,9 @@ <constant name="BREAK_TRIM_EDGE_SPACES" value="16" enum="LineBreakFlag" is_bitfield="true"> Remove edge spaces from the broken line segments. </constant> + <constant name="BREAK_TRIM_INDENT" value="32" enum="LineBreakFlag" is_bitfield="true"> + Subtract first line indentation width from all lines after the first one. + </constant> <constant name="VC_CHARS_BEFORE_SHAPING" value="0" enum="VisibleCharactersBehavior"> Trims text before the shaping. e.g, increasing [member Label.visible_characters] or [member RichTextLabel.visible_characters] value is visually identical to typing the text. </constant> diff --git a/drivers/d3d12/rendering_context_driver_d3d12.cpp b/drivers/d3d12/rendering_context_driver_d3d12.cpp index ad3b793305..726be064bd 100644 --- a/drivers/d3d12/rendering_context_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_context_driver_d3d12.cpp @@ -58,9 +58,10 @@ #endif // Note: symbols are not available in MinGW and old MSVC import libraries. -const CLSID CLSID_D3D12DeviceFactoryGodot = __uuidof(ID3D12DeviceFactory); -const CLSID CLSID_D3D12DebugGodot = __uuidof(ID3D12Debug); -const CLSID CLSID_D3D12SDKConfigurationGodot = __uuidof(ID3D12SDKConfiguration); +// GUID values from https://github.com/microsoft/DirectX-Headers/blob/7a9f4d06911d30eecb56a4956dab29dcca2709ed/include/directx/d3d12.idl#L5877-L5881 +const GUID CLSID_D3D12DeviceFactoryGodot = { 0x114863bf, 0xc386, 0x4aee, { 0xb3, 0x9d, 0x8f, 0x0b, 0xbb, 0x06, 0x29, 0x55 } }; +const GUID CLSID_D3D12DebugGodot = { 0xf2352aeb, 0xdd84, 0x49fe, { 0xb9, 0x7b, 0xa9, 0xdc, 0xfd, 0xcc, 0x1b, 0x4f } }; +const GUID CLSID_D3D12SDKConfigurationGodot = { 0x7cda6aca, 0xa03e, 0x49c8, { 0x94, 0x58, 0x03, 0x34, 0xd2, 0x0e, 0x07, 0xce } }; extern "C" { char godot_nir_arch_name[32]; @@ -83,17 +84,28 @@ RenderingContextDriverD3D12::RenderingContextDriverD3D12() { } RenderingContextDriverD3D12::~RenderingContextDriverD3D12() { + if (lib_d3d12) { + FreeLibrary(lib_d3d12); + } + if (lib_dxgi) { + FreeLibrary(lib_dxgi); + } } Error RenderingContextDriverD3D12::_init_device_factory() { uint32_t agility_sdk_version = GLOBAL_GET("rendering/rendering_device/d3d12/agility_sdk_version"); String agility_sdk_path = String(".\\") + Engine::get_singleton()->get_architecture_name(); + lib_d3d12 = LoadLibraryW(L"D3D12.dll"); + ERR_FAIL_NULL_V(lib_d3d12, ERR_CANT_CREATE); + + lib_dxgi = LoadLibraryW(L"DXGI.dll"); + ERR_FAIL_NULL_V(lib_dxgi, ERR_CANT_CREATE); + // Note: symbol is not available in MinGW import library. - PFN_D3D12_GET_INTERFACE d3d_D3D12GetInterface = (PFN_D3D12_GET_INTERFACE)GetProcAddress(LoadLibraryW(L"D3D12.dll"), "D3D12GetInterface"); - if (d3d_D3D12GetInterface == nullptr) { - // FIXME: Is it intended for this to silently return when it fails to find the symbol? - return OK; + PFN_D3D12_GET_INTERFACE d3d_D3D12GetInterface = (PFN_D3D12_GET_INTERFACE)(void *)GetProcAddress(lib_d3d12, "D3D12GetInterface"); + if (!d3d_D3D12GetInterface) { + return OK; // Fallback to the system loader. } ID3D12SDKConfiguration *sdk_config = nullptr; @@ -109,18 +121,22 @@ Error RenderingContextDriverD3D12::_init_device_factory() { } sdk_config->Release(); } - return OK; } Error RenderingContextDriverD3D12::_initialize_debug_layers() { ComPtr<ID3D12Debug> debug_controller; HRESULT res; + if (device_factory) { res = device_factory->GetConfigurationInterface(CLSID_D3D12DebugGodot, IID_PPV_ARGS(&debug_controller)); } else { - res = D3D12GetDebugInterface(IID_PPV_ARGS(&debug_controller)); + PFN_D3D12_GET_DEBUG_INTERFACE d3d_D3D12GetDebugInterface = (PFN_D3D12_GET_DEBUG_INTERFACE)(void *)GetProcAddress(lib_d3d12, "D3D12GetDebugInterface"); + ERR_FAIL_NULL_V(d3d_D3D12GetDebugInterface, ERR_CANT_CREATE); + + res = d3d_D3D12GetDebugInterface(IID_PPV_ARGS(&debug_controller)); } + ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_QUERY_FAILED); debug_controller->EnableDebugLayer(); return OK; @@ -128,7 +144,12 @@ Error RenderingContextDriverD3D12::_initialize_debug_layers() { Error RenderingContextDriverD3D12::_initialize_devices() { const UINT dxgi_factory_flags = use_validation_layers() ? DXGI_CREATE_FACTORY_DEBUG : 0; - HRESULT res = CreateDXGIFactory2(dxgi_factory_flags, IID_PPV_ARGS(&dxgi_factory)); + + typedef HRESULT(WINAPI * PFN_DXGI_CREATE_DXGI_FACTORY2)(UINT, REFIID, void **); + PFN_DXGI_CREATE_DXGI_FACTORY2 dxgi_CreateDXGIFactory2 = (PFN_DXGI_CREATE_DXGI_FACTORY2)(void *)GetProcAddress(lib_dxgi, "CreateDXGIFactory2"); + ERR_FAIL_NULL_V(dxgi_CreateDXGIFactory2, ERR_CANT_CREATE); + + HRESULT res = dxgi_CreateDXGIFactory2(dxgi_factory_flags, IID_PPV_ARGS(&dxgi_factory)); ERR_FAIL_COND_V(!SUCCEEDED(res), ERR_CANT_CREATE); // Enumerate all possible adapters. diff --git a/drivers/d3d12/rendering_context_driver_d3d12.h b/drivers/d3d12/rendering_context_driver_d3d12.h index 694d0b3e4c..f74105ed3d 100644 --- a/drivers/d3d12/rendering_context_driver_d3d12.h +++ b/drivers/d3d12/rendering_context_driver_d3d12.h @@ -107,6 +107,9 @@ public: bool needs_resize = false; }; + HMODULE lib_d3d12 = nullptr; + HMODULE lib_dxgi = nullptr; + IDXGIAdapter1 *create_adapter(uint32_t p_adapter_index) const; ID3D12DeviceFactory *device_factory_get() const; IDXGIFactory2 *dxgi_factory_get() const; diff --git a/drivers/d3d12/rendering_device_driver_d3d12.cpp b/drivers/d3d12/rendering_device_driver_d3d12.cpp index b4bbc44d93..287726f4db 100644 --- a/drivers/d3d12/rendering_device_driver_d3d12.cpp +++ b/drivers/d3d12/rendering_device_driver_d3d12.cpp @@ -3222,7 +3222,7 @@ Vector<uint8_t> RenderingDeviceDriverD3D12::shader_compile_binary_from_spirv(Vec root_sig_desc.Init_1_1(root_params.size(), root_params.ptr(), 0, nullptr, root_sig_flags); ComPtr<ID3DBlob> error_blob; - HRESULT res = D3DX12SerializeVersionedRootSignature(&root_sig_desc, D3D_ROOT_SIGNATURE_VERSION_1_1, root_sig_blob.GetAddressOf(), error_blob.GetAddressOf()); + HRESULT res = D3DX12SerializeVersionedRootSignature(context_driver->lib_d3d12, &root_sig_desc, D3D_ROOT_SIGNATURE_VERSION_1_1, root_sig_blob.GetAddressOf(), error_blob.GetAddressOf()); ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), Vector<uint8_t>(), "Serialization of root signature failed with error " + vformat("0x%08ux", (uint64_t)res) + " and the following message:\n" + String((char *)error_blob->GetBufferPointer(), error_blob->GetBufferSize())); @@ -3483,7 +3483,10 @@ RDD::ShaderID RenderingDeviceDriverD3D12::shader_create_from_bytecode(const Vect const uint8_t *root_sig_data_ptr = binptr + read_offset; - HRESULT res = D3D12CreateRootSignatureDeserializer(root_sig_data_ptr, binary_data.root_signature_len, IID_PPV_ARGS(shader_info_in.root_signature_deserializer.GetAddressOf())); + PFN_D3D12_CREATE_ROOT_SIGNATURE_DESERIALIZER d3d_D3D12CreateRootSignatureDeserializer = (PFN_D3D12_CREATE_ROOT_SIGNATURE_DESERIALIZER)(void *)GetProcAddress(context_driver->lib_d3d12, "D3D12CreateRootSignatureDeserializer"); + ERR_FAIL_NULL_V(d3d_D3D12CreateRootSignatureDeserializer, ShaderID()); + + HRESULT res = d3d_D3D12CreateRootSignatureDeserializer(root_sig_data_ptr, binary_data.root_signature_len, IID_PPV_ARGS(shader_info_in.root_signature_deserializer.GetAddressOf())); ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ShaderID(), "D3D12CreateRootSignatureDeserializer failed with error " + vformat("0x%08ux", (uint64_t)res) + "."); read_offset += binary_data.root_signature_len; @@ -6033,17 +6036,23 @@ Error RenderingDeviceDriverD3D12::_initialize_device() { HRESULT res; if (is_in_developer_mode()) { + typedef HRESULT(WINAPI * PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES)(_In_ UINT, _In_count_(NumFeatures) const IID *, _In_opt_count_(NumFeatures) void *, _In_opt_count_(NumFeatures) UINT *); + PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES d3d_D3D12EnableExperimentalFeatures = (PFN_D3D12_ENABLE_EXPERIMENTAL_FEATURES)(void *)GetProcAddress(context_driver->lib_d3d12, "D3D12EnableExperimentalFeatures"); + ERR_FAIL_NULL_V(d3d_D3D12EnableExperimentalFeatures, ERR_CANT_CREATE); + UUID experimental_features[] = { D3D12ExperimentalShaderModels }; - D3D12EnableExperimentalFeatures(1, experimental_features, nullptr, nullptr); + d3d_D3D12EnableExperimentalFeatures(1, experimental_features, nullptr, nullptr); } ID3D12DeviceFactory *device_factory = context_driver->device_factory_get(); if (device_factory != nullptr) { res = device_factory->CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.GetAddressOf())); } else { - res = D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.GetAddressOf())); - } + PFN_D3D12_CREATE_DEVICE d3d_D3D12CreateDevice = (PFN_D3D12_CREATE_DEVICE)(void *)GetProcAddress(context_driver->lib_d3d12, "D3D12CreateDevice"); + ERR_FAIL_NULL_V(d3d_D3D12CreateDevice, ERR_CANT_CREATE); + res = d3d_D3D12CreateDevice(adapter.Get(), D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(device.GetAddressOf())); + } ERR_FAIL_COND_V_MSG(!SUCCEEDED(res), ERR_CANT_CREATE, "D3D12CreateDevice failed with error " + vformat("0x%08ux", (uint64_t)res) + "."); if (context_driver->use_validation_layers()) { diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index a6db90c3f5..d73407d674 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -913,8 +913,7 @@ ivec2 multiview_uv(ivec2 uv) { uniform highp mat4 world_transform; uniform mediump float opaque_prepass_threshold; -#ifndef MODE_RENDER_DEPTH -#ifdef RENDER_MATERIAL +#if defined(RENDER_MATERIAL) layout(location = 0) out vec4 albedo_output_buffer; layout(location = 1) out vec4 normal_output_buffer; layout(location = 2) out vec4 orm_output_buffer; @@ -925,7 +924,6 @@ layout(location = 3) out vec4 emission_output_buffer; layout(location = 0) out vec4 frag_color; #endif // !RENDER_MATERIAL -#endif // !MODE_RENDER_DEPTH vec3 F0(float metallic, float specular, vec3 albedo) { float dielectric = 0.16 * specular * specular; diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index 2259c61e5b..f5d1f8dabd 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -541,6 +541,10 @@ void LightStorage::reflection_probe_instance_free(RID p_instance) { void LightStorage::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) { } +bool LightStorage::reflection_probe_has_atlas_index(RID p_instance) { + return false; +} + void LightStorage::reflection_probe_release_atlas_index(RID p_instance) { } diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h index a6b236f3ec..51c5c48106 100644 --- a/drivers/gles3/storage/light_storage.h +++ b/drivers/gles3/storage/light_storage.h @@ -601,6 +601,7 @@ public: virtual RID reflection_probe_instance_create(RID p_probe) override; virtual void reflection_probe_instance_free(RID p_instance) override; virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override; + virtual bool reflection_probe_has_atlas_index(RID p_instance) override; virtual void reflection_probe_release_atlas_index(RID p_instance) override; virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override; virtual bool reflection_probe_instance_has_reflection(RID p_instance) override; diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index ffbad4c83b..5d2bc44377 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -1183,7 +1183,7 @@ Ref<Image> TextureStorage::texture_2d_layer_get(RID p_texture, int p_layer) cons return image; } -Vector<Ref<Image>> TextureStorage::_texture_3d_read_framebuffer(Texture *p_texture) const { +Vector<Ref<Image>> TextureStorage::_texture_3d_read_framebuffer(GLES3::Texture *p_texture) const { ERR_FAIL_NULL_V(p_texture, Vector<Ref<Image>>()); Vector<Ref<Image>> ret; @@ -1610,7 +1610,7 @@ void TextureStorage::_texture_set_3d_data(RID p_texture, const Vector<Ref<Image> #endif } -void TextureStorage::_texture_set_swizzle(Texture *p_texture, Image::Format p_real_format) { +void TextureStorage::_texture_set_swizzle(GLES3::Texture *p_texture, Image::Format p_real_format) { #ifndef WEB_ENABLED switch (p_texture->format) { case Image::FORMAT_L8: { diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp index 5154d2e0e0..7856d454d0 100644 --- a/editor/action_map_editor.cpp +++ b/editor/action_map_editor.cpp @@ -380,6 +380,10 @@ LineEdit *ActionMapEditor::get_search_box() const { return action_list_search; } +LineEdit *ActionMapEditor::get_path_box() const { + return add_edit; +} + InputEventConfigurationDialog *ActionMapEditor::get_configuration_dialog() { return event_config_dialog; } diff --git a/editor/action_map_editor.h b/editor/action_map_editor.h index 2848d23e83..2b329f2fca 100644 --- a/editor/action_map_editor.h +++ b/editor/action_map_editor.h @@ -118,6 +118,7 @@ protected: public: LineEdit *get_search_box() const; + LineEdit *get_path_box() const; InputEventConfigurationDialog *get_configuration_dialog(); // Dictionary represents an Action with "events" (Array) and "deadzone" (float) items. Pass with no param to update list from cached action map. diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 08299da260..6c16951186 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1036,6 +1036,7 @@ void CodeTextEditor::update_editor_settings() { set_indent_using_spaces(EDITOR_GET("text_editor/behavior/indent/type")); text_editor->set_indent_size(EDITOR_GET("text_editor/behavior/indent/size")); text_editor->set_auto_indent_enabled(EDITOR_GET("text_editor/behavior/indent/auto_indent")); + text_editor->set_indent_wrapped_lines(EDITOR_GET("text_editor/behavior/indent/indent_wrapped_lines")); // Completion text_editor->set_auto_brace_completion_enabled(EDITOR_GET("text_editor/completion/auto_brace_complete")); diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 0e46990b41..a7b15e50d7 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -166,7 +166,7 @@ void EditorAutoloadSettings::_autoload_add() { if (!fpath.ends_with("/")) { fpath = fpath.get_base_dir(); } - dialog->config("Node", fpath.path_join(vformat("%s.gd", autoload_add_name->get_text().to_snake_case())), false, false); + dialog->config("Node", fpath.path_join(vformat("%s.gd", autoload_add_name->get_text())), false, false); dialog->popup_centered(); } else { if (autoload_add(autoload_add_name->get_text(), autoload_add_path->get_text())) { @@ -587,6 +587,10 @@ void EditorAutoloadSettings::_script_created(Ref<Script> p_script) { _autoload_add(); } +LineEdit *EditorAutoloadSettings::get_path_box() const { + return autoload_add_path; +} + Variant EditorAutoloadSettings::get_drag_data_fw(const Point2 &p_point, Control *p_control) { if (autoload_cache.size() <= 1) { return false; diff --git a/editor/editor_autoload_settings.h b/editor/editor_autoload_settings.h index 11d7cdbe4d..e4ac62e700 100644 --- a/editor/editor_autoload_settings.h +++ b/editor/editor_autoload_settings.h @@ -108,6 +108,8 @@ public: bool autoload_add(const String &p_name, const String &p_path); void autoload_remove(const String &p_name); + LineEdit *get_path_box() const; + EditorAutoloadSettings(); ~EditorAutoloadSettings(); }; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 44c9afebb6..7de3f58997 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -3089,17 +3089,40 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } } -String EditorNode::adjust_scene_name_casing(const String &root_name) { +String EditorNode::adjust_scene_name_casing(const String &p_root_name) { switch (GLOBAL_GET("editor/naming/scene_name_casing").operator int()) { case SCENE_NAME_CASING_AUTO: // Use casing of the root node. break; case SCENE_NAME_CASING_PASCAL_CASE: - return root_name.to_pascal_case(); + return p_root_name.replace("-", "_").to_pascal_case(); case SCENE_NAME_CASING_SNAKE_CASE: - return root_name.replace("-", "_").to_snake_case(); + return p_root_name.replace("-", "_").to_snake_case(); + case SCENE_NAME_CASING_KEBAB_CASE: + return p_root_name.to_snake_case().replace("_", "-"); } - return root_name; + return p_root_name; +} + +String EditorNode::adjust_script_name_casing(const String &p_file_name, ScriptLanguage::ScriptNameCasing p_auto_casing) { + int editor_casing = GLOBAL_GET("editor/naming/script_name_casing"); + if (editor_casing == ScriptLanguage::SCRIPT_NAME_CASING_AUTO) { + // Use the script language's preferred casing. + editor_casing = p_auto_casing; + } + + switch (editor_casing) { + case ScriptLanguage::SCRIPT_NAME_CASING_AUTO: + // Script language has no preference, so do not adjust. + break; + case ScriptLanguage::SCRIPT_NAME_CASING_PASCAL_CASE: + return p_file_name.replace("-", "_").to_pascal_case(); + case ScriptLanguage::SCRIPT_NAME_CASING_SNAKE_CASE: + return p_file_name.replace("-", "_").to_snake_case(); + case ScriptLanguage::SCRIPT_NAME_CASING_KEBAB_CASE: + return p_file_name.to_snake_case().replace("_", "-"); + } + return p_file_name; } void EditorNode::_request_screenshot() { diff --git a/editor/editor_node.h b/editor/editor_node.h index d44f7b3bb4..b479626648 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -31,6 +31,7 @@ #ifndef EDITOR_NODE_H #define EDITOR_NODE_H +#include "core/object/script_language.h" #include "core/templates/safe_refcount.h" #include "editor/editor_data.h" #include "editor/editor_folding.h" @@ -135,7 +136,8 @@ public: enum SceneNameCasing { SCENE_NAME_CASING_AUTO, SCENE_NAME_CASING_PASCAL_CASE, - SCENE_NAME_CASING_SNAKE_CASE + SCENE_NAME_CASING_SNAKE_CASE, + SCENE_NAME_CASING_KEBAB_CASE, }; struct ExecuteThreadArgs { @@ -689,7 +691,8 @@ public: static VSplitContainer *get_top_split() { return singleton->top_split; } static EditorBottomPanel *get_bottom_panel() { return singleton->bottom_panel; } - static String adjust_scene_name_casing(const String &root_name); + static String adjust_scene_name_casing(const String &p_root_name); + static String adjust_script_name_casing(const String &p_file_name, ScriptLanguage::ScriptNameCasing p_auto_casing); static bool has_unsaved_changes() { return singleton->unsaved_cache; } static void disambiguate_filenames(const Vector<String> p_full_paths, Vector<String> &r_filenames); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index c39912d772..d0b633b136 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -631,6 +631,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "text_editor/behavior/indent/type", 0, "Tabs,Spaces") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "text_editor/behavior/indent/size", 4, "1,64,1") // size of 0 crashes. _initial_set("text_editor/behavior/indent/auto_indent", true); + _initial_set("text_editor/behavior/indent/indent_wrapped_lines", true); // Behavior: Files _initial_set("text_editor/behavior/files/trim_trailing_whitespace_on_save", false); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index a7e40ce5b9..88fed16db1 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -2575,6 +2575,11 @@ void FileSystemDock::fix_dependencies(const String &p_for_file) { deps_editor->edit(p_for_file); } +void FileSystemDock::focus_on_path() { + current_path_line_edit->grab_focus(); + current_path_line_edit->select_all(); +} + void FileSystemDock::focus_on_filter() { LineEdit *current_search_box = nullptr; if (display_mode == DISPLAY_MODE_TREE_ONLY) { @@ -3398,6 +3403,8 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) { _tree_rmb_option(FILE_OPEN_EXTERNAL); } else if (ED_IS_SHORTCUT("filesystem_dock/open_in_terminal", p_event)) { _tree_rmb_option(FILE_OPEN_IN_TERMINAL); + } else if (ED_IS_SHORTCUT("file_dialog/focus_path", p_event)) { + focus_on_path(); } else if (ED_IS_SHORTCUT("editor/open_search", p_event)) { focus_on_filter(); } else { diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 06bf3eda52..acb7ca017b 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -386,6 +386,7 @@ public: String get_current_directory() const; void navigate_to_path(const String &p_path); + void focus_on_path(); void focus_on_filter(); ScriptCreateDialog *get_script_create_dialog() const; diff --git a/editor/group_settings_editor.cpp b/editor/group_settings_editor.cpp index 634192ab50..da169b36b2 100644 --- a/editor/group_settings_editor.cpp +++ b/editor/group_settings_editor.cpp @@ -483,6 +483,10 @@ void GroupSettingsEditor::_show_rename_dialog() { rename_group->grab_focus(); } +LineEdit *GroupSettingsEditor::get_name_box() const { + return group_name; +} + GroupSettingsEditor::GroupSettingsEditor() { ProjectSettings::get_singleton()->add_hidden_prefix("global_group/"); diff --git a/editor/group_settings_editor.h b/editor/group_settings_editor.h index 660c15865e..5be0013e96 100644 --- a/editor/group_settings_editor.h +++ b/editor/group_settings_editor.h @@ -90,6 +90,7 @@ protected: static void _bind_methods(); public: + LineEdit *get_name_box() const; void show_message(const String &p_message); void remove_references(const StringName &p_name); diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp index d0b78a35cf..fe86ac442b 100644 --- a/editor/gui/editor_file_dialog.cpp +++ b/editor/gui/editor_file_dialog.cpp @@ -224,6 +224,7 @@ void EditorFileDialog::shortcut_input(const Ref<InputEvent> &p_event) { } if (ED_IS_SHORTCUT("file_dialog/focus_path", p_event)) { dir->grab_focus(); + dir->select_all(); handled = true; } if (ED_IS_SHORTCUT("file_dialog/move_favorite_up", p_event)) { @@ -1783,7 +1784,10 @@ EditorFileDialog::EditorFileDialog() { ED_SHORTCUT("file_dialog/toggle_mode", TTR("Toggle Mode"), KeyModifierMask::ALT | Key::V); ED_SHORTCUT("file_dialog/create_folder", TTR("Create Folder"), KeyModifierMask::CMD_OR_CTRL | Key::N); ED_SHORTCUT("file_dialog/delete", TTR("Delete"), Key::KEY_DELETE); - ED_SHORTCUT("file_dialog/focus_path", TTR("Focus Path"), KeyModifierMask::CMD_OR_CTRL | Key::D); + ED_SHORTCUT("file_dialog/focus_path", TTR("Focus Path"), KeyModifierMask::CMD_OR_CTRL | Key::L); + // Allow both Cmd + L and Cmd + Shift + G to match Safari's and Finder's shortcuts respectively. + ED_SHORTCUT_OVERRIDE_ARRAY("file_dialog/focus_path", "macos", + { int32_t(KeyModifierMask::META | Key::L), int32_t(KeyModifierMask::META | KeyModifierMask::SHIFT | Key::G) }); ED_SHORTCUT("file_dialog/move_favorite_up", TTR("Move Favorite Up"), KeyModifierMask::CMD_OR_CTRL | Key::UP); ED_SHORTCUT("file_dialog/move_favorite_down", TTR("Move Favorite Down"), KeyModifierMask::CMD_OR_CTRL | Key::DOWN); diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index b7f28068b7..57fbbecb60 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -256,11 +256,16 @@ void ProjectSettingsEditor::shortcut_input(const Ref<InputEvent> &p_event) { handled = true; } - if (k->is_match(InputEventKey::create_reference(KeyModifierMask::CMD_OR_CTRL | Key::F))) { + if (ED_IS_SHORTCUT("editor/open_search", p_event)) { _focus_current_search_box(); handled = true; } + if (ED_IS_SHORTCUT("file_dialog/focus_path", p_event)) { + _focus_current_path_box(); + handled = true; + } + if (handled) { set_input_as_handled(); } @@ -347,6 +352,27 @@ void ProjectSettingsEditor::_focus_current_search_box() { } } +void ProjectSettingsEditor::_focus_current_path_box() { + Control *tab = tab_container->get_current_tab_control(); + LineEdit *current_path_box = nullptr; + if (tab == general_editor) { + current_path_box = property_box; + } else if (tab == action_map_editor) { + current_path_box = action_map_editor->get_path_box(); + } else if (tab == autoload_settings) { + current_path_box = autoload_settings->get_path_box(); + } else if (tab == shaders_global_shader_uniforms_editor) { + current_path_box = shaders_global_shader_uniforms_editor->get_name_box(); + } else if (tab == group_settings) { + current_path_box = group_settings->get_name_box(); + } + + if (current_path_box) { + current_path_box->grab_focus(); + current_path_box->select_all(); + } +} + void ProjectSettingsEditor::_editor_restart() { ProjectSettings::get_singleton()->save(); EditorNode::get_singleton()->save_all_scenes(); diff --git a/editor/project_settings_editor.h b/editor/project_settings_editor.h index 7771bdda61..3107c18406 100644 --- a/editor/project_settings_editor.h +++ b/editor/project_settings_editor.h @@ -97,6 +97,7 @@ class ProjectSettingsEditor : public AcceptDialog { void _tabs_tab_changed(int p_tab); void _focus_current_search_box(); + void _focus_current_path_box(); void _editor_restart_request(); void _editor_restart(); diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp index ab8aa4b68f..610ad3efdf 100644 --- a/editor/register_editor_types.cpp +++ b/editor/register_editor_types.cpp @@ -30,6 +30,7 @@ #include "register_editor_types.h" +#include "core/object/script_language.h" #include "editor/debugger/debug_adapter/debug_adapter_server.h" #include "editor/editor_command_palette.h" #include "editor/editor_feature_profile.h" @@ -269,7 +270,8 @@ void register_editor_types() { GLOBAL_DEF("editor/naming/default_signal_callback_name", "_on_{node_name}_{signal_name}"); GLOBAL_DEF("editor/naming/default_signal_callback_to_self_name", "_on_{signal_name}"); - GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/scene_name_casing", PROPERTY_HINT_ENUM, "Auto,PascalCase,snake_case"), EditorNode::SCENE_NAME_CASING_SNAKE_CASE); + GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/scene_name_casing", PROPERTY_HINT_ENUM, "Auto,PascalCase,snake_case,kebab-case"), EditorNode::SCENE_NAME_CASING_SNAKE_CASE); + GLOBAL_DEF(PropertyInfo(Variant::INT, "editor/naming/script_name_casing", PROPERTY_HINT_ENUM, "Auto,PascalCase,snake_case,kebab-case"), ScriptLanguage::SCRIPT_NAME_CASING_AUTO); GLOBAL_DEF("editor/import/reimport_missing_imported_files", true); GLOBAL_DEF("editor/import/use_multiple_threads", true); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index d111fe8f36..6ca128138e 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -125,7 +125,6 @@ void ScriptCreateDialog::_notification(int p_what) { for (int i = 0; i < language_menu->get_item_count(); i++) { if (language_menu->get_item_text(i) == last_language) { language_menu->select(i); - current_language = i; break; } } @@ -146,8 +145,8 @@ void ScriptCreateDialog::_notification(int p_what) { void ScriptCreateDialog::_path_hbox_sorted() { if (is_visible()) { - int filename_start_pos = initial_bp.rfind("/") + 1; - int filename_end_pos = initial_bp.length(); + int filename_start_pos = file_path->get_text().rfind("/") + 1; + int filename_end_pos = file_path->get_text().length(); if (!is_built_in) { file_path->select(filename_start_pos, filename_end_pos); @@ -166,26 +165,30 @@ bool ScriptCreateDialog::_can_be_built_in() { return (supports_built_in && built_in_enabled); } +String ScriptCreateDialog::_adjust_file_path(const String &p_base_path) const { + if (p_base_path.is_empty()) { + return p_base_path; + } + + String base_dir = p_base_path.get_base_dir(); + String file_name = p_base_path.get_file().get_basename(); + file_name = EditorNode::adjust_script_name_casing(file_name, language->preferred_file_name_casing()); + String extension = language->get_extension(); + return base_dir.path_join(file_name + "." + extension); +} + void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_path, bool p_built_in_enabled, bool p_load_enabled) { parent_name->set_text(p_base_name); parent_name->deselect(); built_in_name->set_text(""); - if (!p_base_path.is_empty()) { - initial_bp = p_base_path.get_basename(); - file_path->set_text(initial_bp + "." + ScriptServer::get_language(language_menu->get_selected())->get_extension()); - current_language = language_menu->get_selected(); - } else { - initial_bp = ""; - file_path->set_text(""); - } + file_path->set_text(p_base_path); file_path->deselect(); built_in_enabled = p_built_in_enabled; load_enabled = p_load_enabled; - _language_changed(current_language); - _path_changed(file_path->get_text()); + _language_changed(language_menu->get_selected()); } void ScriptCreateDialog::set_inheritance_base_type(const String &p_base) { @@ -388,38 +391,9 @@ void ScriptCreateDialog::_language_changed(int l) { is_built_in = false; } - String selected_ext = "." + language->get_extension(); String path = file_path->get_text(); - String extension = ""; - if (!path.is_empty()) { - if (path.contains(".")) { - extension = path.get_extension(); - } - - if (extension.length() == 0) { - // Add extension if none. - path += selected_ext; - _path_changed(path); - } else { - // Change extension by selected language. - List<String> extensions; - // Get all possible extensions for script. - for (int m = 0; m < language_menu->get_item_count(); m++) { - ScriptServer::get_language(m)->get_recognized_extensions(&extensions); - } - - for (const String &E : extensions) { - if (E.nocasecmp_to(extension) == 0) { - path = path.get_basename() + selected_ext; - _path_changed(path); - break; - } - } - } - } else { - path = "class" + selected_ext; - _path_changed(path); - } + path = _adjust_file_path(path); + _path_changed(path); file_path->set_text(path); EditorSettings::get_singleton()->set_project_metadata("script_setup", "last_selected_language", language_menu->get_item_text(language_menu->get_selected())); @@ -896,7 +870,6 @@ ScriptCreateDialog::ScriptCreateDialog() { if (default_language >= 0) { language_menu->select(default_language); } - current_language = default_language; language_menu->connect("item_selected", callable_mp(this, &ScriptCreateDialog::_language_changed)); diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index 66301ea3b9..c8f043b420 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -71,7 +71,6 @@ class ScriptCreateDialog : public ConfirmationDialog { bool is_browsing_parent = false; String path_error; String template_inactive_message; - String initial_bp; bool is_new_script_created = true; bool is_path_valid = false; bool supports_built_in = false; @@ -82,7 +81,6 @@ class ScriptCreateDialog : public ConfirmationDialog { bool is_using_templates = true; bool built_in_enabled = true; bool load_enabled = true; - int current_language; int default_language; bool re_check_path = false; @@ -117,6 +115,7 @@ class ScriptCreateDialog : public ConfirmationDialog { Vector<ScriptLanguage::ScriptTemplate> _get_user_templates(const ScriptLanguage *p_language, const StringName &p_object, const String &p_dir, const ScriptLanguage::TemplateLocation &p_origin) const; ScriptLanguage::ScriptTemplate _parse_template(const ScriptLanguage *p_language, const String &p_path, const String &p_filename, const ScriptLanguage::TemplateLocation &p_origin, const String &p_inherits) const; String _get_script_origin_label(const ScriptLanguage::TemplateLocation &p_origin) const; + String _adjust_file_path(const String &p_base_path) const; protected: void _notification(int p_what); diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp index 46f520df45..97f6ce2215 100644 --- a/editor/shader_globals_editor.cpp +++ b/editor/shader_globals_editor.cpp @@ -356,6 +356,10 @@ String ShaderGlobalsEditor::_check_new_variable_name(const String &p_variable_na return ""; } +LineEdit *ShaderGlobalsEditor::get_name_box() const { + return variable_name; +} + void ShaderGlobalsEditor::_variable_name_text_changed(const String &p_variable_name) { const String &warning = _check_new_variable_name(p_variable_name.strip_edges()); variable_add->set_tooltip_text(warning); diff --git a/editor/shader_globals_editor.h b/editor/shader_globals_editor.h index fc50564aae..de871f76bf 100644 --- a/editor/shader_globals_editor.h +++ b/editor/shader_globals_editor.h @@ -61,6 +61,8 @@ protected: void _notification(int p_what); public: + LineEdit *get_name_box() const; + ShaderGlobalsEditor(); ~ShaderGlobalsEditor(); }; diff --git a/godot.manifest b/godot.manifest new file mode 100644 index 0000000000..30b80aff25 --- /dev/null +++ b/godot.manifest @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <dependency> + <dependentAssembly> + <assemblyIdentity + type='win32' + name='Microsoft.Windows.Common-Controls' + version='6.0.0.0' processorArchitecture='*' + publicKeyToken='6595b64144ccf1df' + language='*'/> + </dependentAssembly> + </dependency> +</assembly> diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 9ccaa27e84..93fb5f1dc6 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -405,6 +405,10 @@ bool CSharpLanguage::supports_builtin_mode() const { return false; } +ScriptLanguage::ScriptNameCasing CSharpLanguage::preferred_file_name_casing() const { + return SCRIPT_NAME_CASING_PASCAL_CASE; +} + #ifdef TOOLS_ENABLED struct VariantCsName { Variant::Type variant_type; diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 99e6ebf2e3..7821420620 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -518,6 +518,7 @@ public: virtual String _get_indentation() const; /* TODO? */ void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const override {} /* TODO */ void add_global_constant(const StringName &p_variable, const Variant &p_value) override {} + virtual ScriptNameCasing preferred_file_name_casing() const override; /* SCRIPT GLOBAL CLASS FUNCTIONS */ virtual bool handles_global_class_type(const String &p_type) const override; diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index ea88278a17..3da19aaee8 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -5360,11 +5360,14 @@ bool TextServerAdvanced::_shaped_text_update_breaks(const RID &p_shaped) { // No data loaded - use fallback. for (int j = r_start; j < r_end; j++) { char32_t c = sd->text[j - sd->start]; + char32_t c_next = (j < r_end) ? sd->text[j - sd->start + 1] : 0x0000; if (is_whitespace(c)) { sd->breaks[j + 1] = false; } if (is_linebreak(c)) { - sd->breaks[j + 1] = true; + if (c != 0x000D || c_next != 0x000A) { // Skip first hard break in CR-LF pair. + sd->breaks[j + 1] = true; + } } } } else { diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index f2d70db7a4..7e34de0bbc 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -3617,6 +3617,7 @@ bool TextServerFallback::_shaped_text_update_breaks(const RID &p_shaped) { for (int i = 0; i < sd_size; i++) { if (sd_glyphs[i].count > 0) { char32_t c = sd->text[sd_glyphs[i].start - sd->start]; + char32_t c_next = i < sd_size ? sd->text[sd_glyphs[i].start - sd->start + 1] : 0x0000; if (c_punct_size == 0) { if (is_punct(c) && c != 0x005F && c != ' ') { sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION; @@ -3640,7 +3641,9 @@ bool TextServerFallback::_shaped_text_update_breaks(const RID &p_shaped) { } if (is_linebreak(c)) { sd_glyphs[i].flags |= GRAPHEME_IS_SPACE; - sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; + if (c != 0x000D || c_next != 0x000A) { // Skip first hard break in CR-LF pair. + sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_HARD; + } } if (c == 0x0009 || c == 0x000b) { sd_glyphs[i].flags |= GRAPHEME_IS_TAB; diff --git a/platform/windows/detect.py b/platform/windows/detect.py index ca81bb615e..196beb423f 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -202,7 +202,9 @@ def get_opts(): BoolVariable("use_asan", "Use address sanitizer (ASAN)", False), BoolVariable("debug_crt", "Compile with MSVC's debug CRT (/MDd)", False), BoolVariable("incremental_link", "Use MSVC incremental linking. May increase or decrease build times.", False), - BoolVariable("silence_msvc", "Silence MSVC's stdout. Decreases output log bloat by roughly half.", True), + BoolVariable( + "silence_msvc", "Silence MSVC's stdout to decrease output log bloat. May hide error messages.", False + ), ("angle_libs", "Path to the ANGLE static libraries", ""), # Direct3D 12 support. ( @@ -437,6 +439,10 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): else: print("Missing environment variable: WindowsSdkDir") + if int(env["target_win_version"], 16) < 0x0601: + print("`target_win_version` should be 0x0601 or higher (Windows 7).") + sys.exit(255) + env.AppendUnique( CPPDEFINES=[ "WINDOWS_ENABLED", @@ -501,7 +507,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config): sys.exit(255) env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"]) - LIBS += ["d3d12", "dxgi", "dxguid"] + LIBS += ["dxgi", "dxguid"] LIBS += ["version"] # Mesa dependency. # Needed for avoiding C1128. @@ -666,6 +672,10 @@ def configure_mingw(env: "SConsEnvironment"): ## Compile flags + if int(env["target_win_version"], 16) < 0x0601: + print("`target_win_version` should be 0x0601 or higher (Windows 7).") + sys.exit(255) + if not env["use_llvm"]: env.Append(CCFLAGS=["-mwindows"]) @@ -726,7 +736,7 @@ def configure_mingw(env: "SConsEnvironment"): sys.exit(255) env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"]) - env.Append(LIBS=["d3d12", "dxgi", "dxguid"]) + env.Append(LIBS=["dxgi", "dxguid"]) # PIX if not env["arch"] in ["x86_64", "arm64"] or env["pix_path"] == "" or not os.path.exists(env["pix_path"]): diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index ced8dce65a..ada9202207 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -2490,6 +2490,299 @@ void DisplayServerWindows::enable_for_stealing_focus(OS::ProcessID pid) { AllowSetForegroundWindow(pid); } +static HRESULT CALLBACK win32_task_dialog_callback(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, LONG_PTR lpRefData) { + if (msg == TDN_CREATED) { + // To match the input text dialog. + SendMessageW(hwnd, WM_SETICON, ICON_BIG, 0); + SendMessageW(hwnd, WM_SETICON, ICON_SMALL, 0); + } + + return 0; +} + +Error DisplayServerWindows::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) { + _THREAD_SAFE_METHOD_ + + TASKDIALOGCONFIG config; + ZeroMemory(&config, sizeof(TASKDIALOGCONFIG)); + config.cbSize = sizeof(TASKDIALOGCONFIG); + + Char16String title = p_title.utf16(); + Char16String message = p_description.utf16(); + List<Char16String> buttons; + for (String s : p_buttons) { + buttons.push_back(s.utf16()); + } + + config.pszWindowTitle = (LPCWSTR)(title.get_data()); + config.pszContent = (LPCWSTR)(message.get_data()); + + const int button_count = MIN(buttons.size(), 8); + config.cButtons = button_count; + + // No dynamic stack array size :( + TASKDIALOG_BUTTON *tbuttons = button_count != 0 ? (TASKDIALOG_BUTTON *)alloca(sizeof(TASKDIALOG_BUTTON) * button_count) : nullptr; + if (tbuttons) { + for (int i = 0; i < button_count; i++) { + tbuttons[i].nButtonID = i; + tbuttons[i].pszButtonText = (LPCWSTR)(buttons[i].get_data()); + } + } + config.pButtons = tbuttons; + config.pfCallback = win32_task_dialog_callback; + + HMODULE comctl = LoadLibraryW(L"comctl32.dll"); + if (comctl) { + typedef HRESULT(WINAPI * TaskDialogIndirectPtr)(const TASKDIALOGCONFIG *pTaskConfig, int *pnButton, int *pnRadioButton, BOOL *pfVerificationFlagChecked); + + TaskDialogIndirectPtr task_dialog_indirect = (TaskDialogIndirectPtr)GetProcAddress(comctl, "TaskDialogIndirect"); + if (task_dialog_indirect) { + int button_pressed; + if (FAILED(task_dialog_indirect(&config, &button_pressed, nullptr, nullptr))) { + return FAILED; + } + + if (!p_callback.is_null()) { + Variant button = button_pressed; + const Variant *args[1] = { &button }; + Variant ret; + Callable::CallError ce; + p_callback.callp(args, 1, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute dialog callback: %s.", Variant::get_callable_error_text(p_callback, args, 1, ce))); + } + } + + return OK; + } + FreeLibrary(comctl); + } + + ERR_PRINT("Unable to create native dialog."); + return FAILED; +} + +struct Win32InputTextDialogInit { + const char16_t *title; + const char16_t *description; + const char16_t *partial; + const Callable &callback; +}; + +static constexpr int scale_with_dpi(int p_pos, int p_dpi) { + return IsProcessDPIAware() ? (p_pos * p_dpi / 96) : p_pos; +} + +static INT_PTR input_text_dialog_init(HWND hWnd, UINT code, WPARAM wParam, LPARAM lParam) { + Win32InputTextDialogInit init = *(Win32InputTextDialogInit *)lParam; + SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)&init.callback); // Set dialog callback. + + SetWindowTextW(hWnd, (LPCWSTR)init.title); + + const int dpi = DisplayServerWindows::get_singleton()->screen_get_dpi(); + + const int margin = scale_with_dpi(7, dpi); + const SIZE dlg_size = { scale_with_dpi(300, dpi), scale_with_dpi(50, dpi) }; + + int str_len = lstrlenW((LPCWSTR)init.description); + SIZE str_size = { dlg_size.cx, 0 }; + if (str_len > 0) { + HDC hdc = GetDC(nullptr); + RECT trect = { margin, margin, margin + dlg_size.cx, margin + dlg_size.cy }; + SelectObject(hdc, (HFONT)SendMessageW(hWnd, WM_GETFONT, 0, 0)); + + // `+ margin` adds some space between the static text and the edit field. + // Don't scale this with DPI because DPI is already handled by DrawText. + str_size.cy = DrawTextW(hdc, (LPCWSTR)init.description, str_len, &trect, DT_LEFT | DT_WORDBREAK | DT_CALCRECT) + margin; + + ReleaseDC(nullptr, hdc); + } + + RECT crect, wrect; + GetClientRect(hWnd, &crect); + GetWindowRect(hWnd, &wrect); + int sw = GetSystemMetrics(SM_CXSCREEN); + int sh = GetSystemMetrics(SM_CYSCREEN); + int new_width = dlg_size.cx + margin * 2 + wrect.right - wrect.left - crect.right; + int new_height = dlg_size.cy + margin * 2 + wrect.bottom - wrect.top - crect.bottom + str_size.cy; + + MoveWindow(hWnd, (sw - new_width) / 2, (sh - new_height) / 2, new_width, new_height, true); + + HWND ok_button = GetDlgItem(hWnd, 1); + MoveWindow(ok_button, + dlg_size.cx + margin - scale_with_dpi(65, dpi), + dlg_size.cy + str_size.cy + margin - scale_with_dpi(20, dpi), + scale_with_dpi(65, dpi), scale_with_dpi(20, dpi), true); + + HWND description = GetDlgItem(hWnd, 3); + MoveWindow(description, margin, margin, dlg_size.cx, str_size.cy, true); + SetWindowTextW(description, (LPCWSTR)init.description); + + HWND text_edit = GetDlgItem(hWnd, 2); + MoveWindow(text_edit, margin, str_size.cy + margin, dlg_size.cx, scale_with_dpi(20, dpi), true); + SetWindowTextW(text_edit, (LPCWSTR)init.partial); + + return TRUE; +} + +static INT_PTR input_text_dialog_cmd_proc(HWND hWnd, UINT code, WPARAM wParam, LPARAM lParam) { + if (LOWORD(wParam) == 1) { + HWND text_edit = GetDlgItem(hWnd, 2); + ERR_FAIL_NULL_V(text_edit, false); + + Char16String text; + text.resize(GetWindowTextLengthW(text_edit) + 1); + GetWindowTextW(text_edit, (LPWSTR)text.get_data(), text.size()); + + const Callable *callback = (const Callable *)GetWindowLongPtrW(hWnd, GWLP_USERDATA); + if (callback && callback->is_valid()) { + Variant v_result = String((const wchar_t *)text.get_data()); + Variant ret; + Callable::CallError ce; + const Variant *args[1] = { &v_result }; + + callback->callp(args, 1, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat("Failed to execute input dialog callback: %s.", Variant::get_callable_error_text(*callback, args, 1, ce))); + } + } + + return EndDialog(hWnd, 0); + } + + return false; +} + +static INT_PTR CALLBACK input_text_dialog_proc(HWND hWnd, UINT code, WPARAM wParam, LPARAM lParam) { + switch (code) { + case WM_INITDIALOG: + return input_text_dialog_init(hWnd, code, wParam, lParam); + + case WM_COMMAND: + return input_text_dialog_cmd_proc(hWnd, code, wParam, lParam); + + default: + return FALSE; + } +} + +Error DisplayServerWindows::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) { +#pragma pack(push, 1) + + // NOTE: Use default/placeholder coordinates here. Windows uses its own coordinate system + // specifically for dialogs which relies on font sizes instead of pixels. + const struct { + WORD dlgVer; // must be 1 + WORD signature; // must be 0xFFFF + DWORD helpID; + DWORD exStyle; + DWORD style; + WORD cDlgItems; + short x; + short y; + short cx; + short cy; + WCHAR menu[1]; // must be 0 + WCHAR windowClass[7]; // must be "#32770" -- the default window class for dialogs + WCHAR title[1]; // must be 0 + WORD pointsize; + WORD weight; + BYTE italic; + BYTE charset; + WCHAR font[13]; // must be "MS Shell Dlg" + } template_base = { + 1, 0xFFFF, 0, 0, + DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU, + 3, 0, 0, 20, 20, L"", L"#32770", L"", 8, FW_NORMAL, 0, DEFAULT_CHARSET, L"MS Shell Dlg" + }; + + const struct { + DWORD helpID; + DWORD exStyle; + DWORD style; + short x; + short y; + short cx; + short cy; + DWORD id; + WCHAR windowClass[7]; // must be "Button" + WCHAR title[3]; // must be "OK" + WORD extraCount; + } ok_button = { + 0, 0, WS_VISIBLE | BS_DEFPUSHBUTTON, 0, 0, 50, 14, 1, WC_BUTTONW, L"OK", 0 + }; + const struct { + DWORD helpID; + DWORD exStyle; + DWORD style; + short x; + short y; + short cx; + short cy; + DWORD id; + WCHAR windowClass[5]; // must be "Edit" + WCHAR title[1]; // must be 0 + WORD extraCount; + } text_field = { + 0, 0, WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 0, 0, 250, 14, 2, WC_EDITW, L"", 0 + }; + const struct { + DWORD helpID; + DWORD exStyle; + DWORD style; + short x; + short y; + short cx; + short cy; + DWORD id; + WCHAR windowClass[7]; // must be "Static" + WCHAR title[1]; // must be 0 + WORD extraCount; + } static_text = { + 0, 0, WS_VISIBLE, 0, 0, 250, 14, 3, WC_STATICW, L"", 0 + }; + +#pragma pack(pop) + + // Dialog template + const size_t data_size = sizeof(template_base) + (sizeof(template_base) % 4) + + sizeof(ok_button) + (sizeof(ok_button) % 4) + + sizeof(text_field) + (sizeof(text_field) % 4) + + sizeof(static_text) + (sizeof(static_text) % 4); + + void *data_template = memalloc(data_size); + ERR_FAIL_NULL_V_MSG(data_template, FAILED, "Unable to allocate memory for the dialog template."); + ZeroMemory(data_template, data_size); + + char *current_block = (char *)data_template; + CopyMemory(current_block, &template_base, sizeof(template_base)); + current_block += sizeof(template_base) + (sizeof(template_base) % 4); + CopyMemory(current_block, &ok_button, sizeof(ok_button)); + current_block += sizeof(ok_button) + (sizeof(ok_button) % 4); + CopyMemory(current_block, &text_field, sizeof(text_field)); + current_block += sizeof(text_field) + (sizeof(text_field) % 4); + CopyMemory(current_block, &static_text, sizeof(static_text)); + + Char16String title16 = p_title.utf16(); + Char16String description16 = p_description.utf16(); + Char16String partial16 = p_partial.utf16(); + + Win32InputTextDialogInit init = { + title16.get_data(), description16.get_data(), partial16.get_data(), p_callback + }; + + // No modal dialogs for specific windows? Assume main window here. + INT_PTR ret = DialogBoxIndirectParamW(hInstance, (LPDLGTEMPLATEW)data_template, nullptr, (DLGPROC)input_text_dialog_proc, (LPARAM)(&init)); + + Error result = ret != -1 ? OK : FAILED; + memfree(data_template); + + if (result == FAILED) { + ERR_PRINT("Unable to create native dialog."); + } + return result; +} + int DisplayServerWindows::keyboard_get_layout_count() const { return GetKeyboardLayoutList(0, nullptr); } @@ -5256,6 +5549,23 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } } + HMODULE comctl32 = LoadLibraryW(L"comctl32.dll"); + if (comctl32) { + typedef BOOL(WINAPI * InitCommonControlsExPtr)(_In_ const INITCOMMONCONTROLSEX *picce); + InitCommonControlsExPtr init_common_controls_ex = (InitCommonControlsExPtr)GetProcAddress(comctl32, "InitCommonControlsEx"); + + // Fails if the incorrect version was loaded. Probably not a big enough deal to print an error about. + if (init_common_controls_ex) { + INITCOMMONCONTROLSEX icc = {}; + icc.dwICC = ICC_STANDARD_CLASSES; + icc.dwSize = sizeof(INITCOMMONCONTROLSEX); + if (!init_common_controls_ex(&icc)) { + WARN_PRINT("Unable to initialize Windows common controls. Native dialogs may not work properly."); + } + } + FreeLibrary(comctl32); + } + memset(&wc, 0, sizeof(WNDCLASSEXW)); wc.cbSize = sizeof(WNDCLASSEXW); wc.style = CS_OWNDC | CS_DBLCLKS; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 81cddec49f..f749185080 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -192,6 +192,7 @@ typedef UINT32 PEN_MASK; #define POINTER_MESSAGE_FLAG_FIRSTBUTTON 0x00000010 #endif +#if WINVER < 0x0602 enum tagPOINTER_INPUT_TYPE { PT_POINTER = 0x00000001, PT_TOUCH = 0x00000002, @@ -242,6 +243,7 @@ typedef struct tagPOINTER_PEN_INFO { INT32 tiltX; INT32 tiltY; } POINTER_PEN_INFO; +#endif #endif //POINTER_STRUCTURES @@ -642,6 +644,9 @@ public: virtual void enable_for_stealing_focus(OS::ProcessID pid) override; + virtual Error dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) override; + virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) override; + virtual int keyboard_get_layout_count() const override; virtual int keyboard_get_current_layout() const override; virtual void keyboard_set_current_layout(int p_index) override; diff --git a/platform/windows/godot_res.rc b/platform/windows/godot_res.rc index 8187c0c936..86191ad9d9 100644 --- a/platform/windows/godot_res.rc +++ b/platform/windows/godot_res.rc @@ -1,6 +1,11 @@ #include "core/version.h" +#ifndef RT_MANIFEST +#define RT_MANIFEST 24 +#endif + GODOT_ICON ICON platform/windows/godot.ico +1 RT_MANIFEST "godot.manifest" 1 VERSIONINFO FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0 diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp index 718ddd4982..02f40713bf 100644 --- a/scene/3d/label_3d.cpp +++ b/scene/3d/label_3d.cpp @@ -422,12 +422,6 @@ void Label3D::_generate_glyph_surfaces(const Glyph &p_glyph, Vector2 &r_offset, s.mesh_tangents.write[(s.offset * 16) + (i * 4) + 3] = 1.0; s.mesh_colors.write[(s.offset * 4) + i] = p_modulate; s.mesh_uvs.write[(s.offset * 4) + i] = Vector2(); - - if (aabb == AABB()) { - aabb.position = s.mesh_vertices[(s.offset * 4) + i]; - } else { - aabb.expand_to(s.mesh_vertices[(s.offset * 4) + i]); - } } if (tex.is_valid()) { @@ -598,6 +592,13 @@ void Label3D::_shape() { } break; } offset.x += lbl_offset.x * pixel_size; + if (aabb == AABB()) { + aabb.position = Vector3(offset.x, offset.y, 0); + aabb.expand_to(Vector3(offset.x + line_width, offset.y - (TS->shaped_text_get_size(lines_rid[i]).y + line_spacing) * pixel_size, 0)); + } else { + aabb.expand_to(Vector3(offset.x, offset.y, 0)); + aabb.expand_to(Vector3(offset.x + line_width, offset.y - (TS->shaped_text_get_size(lines_rid[i]).y + line_spacing) * pixel_size, 0)); + } offset.y -= TS->shaped_text_get_ascent(lines_rid[i]) * pixel_size; if (outline_modulate.a != 0.0 && outline_size > 0) { diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index abed3cf594..a53dffd0d2 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -263,6 +263,27 @@ void FileDialog::shortcut_input(const Ref<InputEvent> &p_event) { case Key::BACKSPACE: { _dir_submitted(".."); } break; +#ifdef MACOS_ENABLED + // Cmd + Shift + G (matches Finder's "Go To" shortcut). + case Key::G: { + if (k->is_command_or_control_pressed() && k->is_shift_pressed()) { + dir->grab_focus(); + dir->select_all(); + } else { + handled = false; + } + } break; +#endif + // Ctrl + L (matches most Windows/Linux file managers' "focus on path bar" shortcut, + // plus macOS Safari's "focus on address bar" shortcut). + case Key::L: { + if (k->is_command_or_control_pressed()) { + dir->grab_focus(); + dir->select_all(); + } else { + handled = false; + } + } break; default: { handled = false; } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 7230f87359..5fe26aac06 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -2261,6 +2261,7 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) { queue_redraw(); } + _find_click(main, m->get_position(), nullptr, nullptr, &c_item, nullptr, &outside, true); Variant meta; ItemMeta *item_meta; ItemMeta *prev_meta = meta_hovering; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index c2716c9ef6..40bc87846a 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -74,6 +74,18 @@ int TextEdit::Text::get_tab_size() const { return tab_size; } +void TextEdit::Text::set_indent_wrapped_lines(bool p_enabled) { + if (indent_wrapped_lines == p_enabled) { + return; + } + indent_wrapped_lines = p_enabled; + tab_size_dirty = true; +} + +bool TextEdit::Text::is_indent_wrapped_lines() const { + return indent_wrapped_lines; +} + void TextEdit::Text::set_direction_and_language(TextServer::Direction p_direction, const String &p_language) { if (direction == p_direction && language == p_language) { return; @@ -185,9 +197,14 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, bool p_text_chan text.write[p_line].data_buf->clear(); } + BitField<TextServer::LineBreakFlag> flags = brk_flags; + if (indent_wrapped_lines) { + flags.set_flag(TextServer::BREAK_TRIM_INDENT); + } + text.write[p_line].data_buf->set_width(width); text.write[p_line].data_buf->set_direction((TextServer::Direction)direction); - text.write[p_line].data_buf->set_break_flags(brk_flags); + text.write[p_line].data_buf->set_break_flags(flags); text.write[p_line].data_buf->set_preserve_control(draw_control_chars); if (p_ime_text.length() > 0) { if (p_text_changed) { @@ -251,8 +268,12 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, bool p_text_chan void TextEdit::Text::invalidate_all_lines() { for (int i = 0; i < text.size(); i++) { + BitField<TextServer::LineBreakFlag> flags = brk_flags; + if (indent_wrapped_lines) { + flags.set_flag(TextServer::BREAK_TRIM_INDENT); + } text.write[i].data_buf->set_width(width); - text.write[i].data_buf->set_break_flags(brk_flags); + text.write[i].data_buf->set_break_flags(flags); if (tab_size_dirty) { if (tab_size > 0) { Vector<float> tabs; @@ -1075,9 +1096,12 @@ void TextEdit::_notification(int p_what) { // Draw line. RID rid = ldata->get_line_rid(line_wrap_index); float text_height = TS->shaped_text_get_size(rid).y; + float wrap_indent = (text.is_indent_wrapped_lines() && line_wrap_index > 0) ? get_indent_level(line) * theme_cache.font->get_char_size(' ', theme_cache.font_size).width : 0.0; if (rtl) { - char_margin = size.width - char_margin - TS->shaped_text_get_size(rid).x; + char_margin = size.width - char_margin - (TS->shaped_text_get_size(rid).x + wrap_indent); + } else { + char_margin += wrap_indent; } // Draw selections. @@ -2935,7 +2959,11 @@ void TextEdit::_update_placeholder() { // Placeholder is generally smaller then text documents, and updates less so this should be fast enough for now. placeholder_data_buf->clear(); placeholder_data_buf->set_width(text.get_width()); - placeholder_data_buf->set_break_flags(text.get_brk_flags()); + BitField<TextServer::LineBreakFlag> flags = text.get_brk_flags(); + if (text.is_indent_wrapped_lines()) { + flags.set_flag(TextServer::BREAK_TRIM_INDENT); + } + placeholder_data_buf->set_break_flags(flags); if (text_direction == Control::TEXT_DIRECTION_INHERITED) { placeholder_data_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); } else { @@ -3331,6 +3359,20 @@ int TextEdit::get_tab_size() const { return text.get_tab_size(); } +void TextEdit::set_indent_wrapped_lines(bool p_enabled) { + if (text.is_indent_wrapped_lines() == p_enabled) { + return; + } + text.set_indent_wrapped_lines(p_enabled); + text.invalidate_all_lines(); + _update_placeholder(); + queue_redraw(); +} + +bool TextEdit::is_indent_wrapped_lines() const { + return text.is_indent_wrapped_lines(); +} + // User controls void TextEdit::set_overtype_mode_enabled(const bool p_enabled) { if (overtype_mode == p_enabled) { @@ -4336,8 +4378,11 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_ } RID text_rid = text.get_line_data(row)->get_line_rid(wrap_index); + float wrap_indent = (text.is_indent_wrapped_lines() && wrap_index > 0) ? get_indent_level(row) * theme_cache.font->get_char_size(' ', theme_cache.font_size).width : 0.0; if (is_layout_rtl()) { - colx = TS->shaped_text_get_size(text_rid).x - colx; + colx = TS->shaped_text_get_size(text_rid).x - colx + wrap_indent; + } else { + colx -= wrap_indent; } col = TS->shaped_text_hit_test_position(text_rid, colx); if (!caret_mid_grapheme_enabled) { @@ -6073,6 +6118,9 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tab_size", "size"), &TextEdit::set_tab_size); ClassDB::bind_method(D_METHOD("get_tab_size"), &TextEdit::get_tab_size); + ClassDB::bind_method(D_METHOD("set_indent_wrapped_lines", "enabled"), &TextEdit::set_indent_wrapped_lines); + ClassDB::bind_method(D_METHOD("is_indent_wrapped_lines"), &TextEdit::is_indent_wrapped_lines); + // User controls ClassDB::bind_method(D_METHOD("set_overtype_mode_enabled", "enabled"), &TextEdit::set_overtype_mode_enabled); ClassDB::bind_method(D_METHOD("is_overtype_mode_enabled"), &TextEdit::is_overtype_mode_enabled); @@ -6451,6 +6499,7 @@ void TextEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled"), "set_middle_mouse_paste_enabled", "is_middle_mouse_paste_enabled"); ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_mode", PROPERTY_HINT_ENUM, "None,Boundary"), "set_line_wrapping_mode", "get_line_wrapping_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Arbitrary:1,Word:2,Word (Smart):3"), "set_autowrap_mode", "get_autowrap_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "indent_wrapped_lines"), "set_indent_wrapped_lines", "is_indent_wrapped_lines"); ADD_GROUP("Scroll", "scroll_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_smooth"), "set_smooth_scroll_enabled", "is_smooth_scroll_enabled"); @@ -7075,8 +7124,11 @@ int TextEdit::_get_char_pos_for_line(int p_px, int p_line, int p_wrap_index) con p_wrap_index = MIN(p_wrap_index, text.get_line_data(p_line)->get_line_count() - 1); RID text_rid = text.get_line_data(p_line)->get_line_rid(p_wrap_index); + float wrap_indent = (text.is_indent_wrapped_lines() && p_wrap_index > 0) ? get_indent_level(p_line) * theme_cache.font->get_char_size(' ', theme_cache.font_size).width : 0.0; if (is_layout_rtl()) { - p_px = TS->shaped_text_get_size(text_rid).x - p_px; + p_px = TS->shaped_text_get_size(text_rid).x - p_px + wrap_indent; + } else { + p_px -= wrap_indent; } int ofs = TS->shaped_text_hit_test_position(text_rid, p_px); if (!caret_mid_grapheme_enabled) { @@ -7125,11 +7177,12 @@ int TextEdit::_get_column_x_offset_for_line(int p_char, int p_line, int p_column } RID text_rid = text.get_line_data(p_line)->get_line_rid(row); + float wrap_indent = (text.is_indent_wrapped_lines() && row > 0) ? get_indent_level(p_line) * theme_cache.font->get_char_size(' ', theme_cache.font_size).width : 0.0; CaretInfo ts_caret = TS->shaped_text_get_carets(text_rid, p_column); if ((ts_caret.l_caret != Rect2() && (ts_caret.l_dir == TextServer::DIRECTION_AUTO || ts_caret.l_dir == (TextServer::Direction)input_direction)) || (ts_caret.t_caret == Rect2())) { - return ts_caret.l_caret.position.x; + return ts_caret.l_caret.position.x + (is_layout_rtl() ? -wrap_indent : wrap_indent); } else { - return ts_caret.t_caret.position.x; + return ts_caret.t_caret.position.x + (is_layout_rtl() ? -wrap_indent : wrap_indent); } } diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index d49be860a9..b8e30c7900 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -181,6 +181,7 @@ private: int tab_size = 4; int gutter_count = 0; + bool indent_wrapped_lines = false; void _calculate_line_height(); void _calculate_max_line_width(); @@ -188,6 +189,9 @@ private: public: void set_tab_size(int p_tab_size); int get_tab_size() const; + void set_indent_wrapped_lines(bool p_enabled); + bool is_indent_wrapped_lines() const; + void set_font(const Ref<Font> &p_font); void set_font_size(int p_font_size); void set_direction_and_language(TextServer::Direction p_direction, const String &p_language); @@ -720,6 +724,9 @@ public: void set_tab_size(const int p_size); int get_tab_size() const; + void set_indent_wrapped_lines(bool p_enabled); + bool is_indent_wrapped_lines() const; + // User controls void set_overtype_mode_enabled(const bool p_enabled); bool is_overtype_mode_enabled() const; diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h index 61a825f8c5..a76305cdaa 100644 --- a/servers/rendering/dummy/storage/light_storage.h +++ b/servers/rendering/dummy/storage/light_storage.h @@ -135,6 +135,7 @@ public: virtual RID reflection_probe_instance_create(RID p_probe) override { return RID(); } virtual void reflection_probe_instance_free(RID p_instance) override {} virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override {} + virtual bool reflection_probe_has_atlas_index(RID p_instance) override { return false; } virtual void reflection_probe_release_atlas_index(RID p_instance) override {} virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; } virtual bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; } diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index fa6e78750b..33bb5459f2 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1615,15 +1615,16 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co gi.setup_voxel_gi_instances(p_render_data, p_render_data->render_buffers, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances, p_render_data->voxel_gi_count); } else { - ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash + ERR_PRINT("No render buffer nor reflection atlas, bug"); // Should never happen! current_cluster_builder = nullptr; + return; // No point in continuing, we'll just crash. } - if (current_cluster_builder != nullptr) { - p_render_data->cluster_buffer = current_cluster_builder->get_cluster_buffer(); - p_render_data->cluster_size = current_cluster_builder->get_cluster_size(); - p_render_data->cluster_max_elements = current_cluster_builder->get_max_cluster_elements(); - } + ERR_FAIL_NULL(current_cluster_builder); + + p_render_data->cluster_buffer = current_cluster_builder->get_cluster_buffer(); + p_render_data->cluster_size = current_cluster_builder->get_cluster_size(); + p_render_data->cluster_max_elements = current_cluster_builder->get_max_cluster_elements(); _update_vrs(rb); diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 2786af65eb..cf8c29e624 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -1370,6 +1370,17 @@ void LightStorage::reflection_probe_instance_set_transform(RID p_instance, const rpi->dirty = true; } +bool LightStorage::reflection_probe_has_atlas_index(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_NULL_V(rpi, false); + + if (rpi->atlas.is_null()) { + return false; + } + + return rpi->atlas_index >= 0; +} + void LightStorage::reflection_probe_release_atlas_index(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_NULL(rpi); @@ -1384,6 +1395,14 @@ void LightStorage::reflection_probe_release_atlas_index(RID p_instance) { // TODO investigate if this is enough? shouldn't we be freeing our textures and framebuffers? + if (rpi->rendering) { + // We were cancelled mid rendering, trigger refresh. + rpi->rendering = false; + rpi->dirty = true; + rpi->processing_layer = 1; + rpi->processing_side = 0; + } + rpi->atlas_index = -1; rpi->atlas = RID(); } @@ -1535,11 +1554,10 @@ bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_NULL_V(rpi, false); ERR_FAIL_COND_V(!rpi->rendering, false); - ERR_FAIL_COND_V(rpi->atlas.is_null(), false); ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); if (!atlas || rpi->atlas_index == -1) { - //does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering) + // Does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering). rpi->rendering = false; return false; } diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h index b3d27cc6ed..b3d6bf5254 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h @@ -277,7 +277,6 @@ private: int processing_layer = 1; int processing_side = 0; - uint32_t render_step = 0; uint64_t last_pass = 0; uint32_t cull_mask = 0; @@ -848,6 +847,7 @@ public: virtual RID reflection_probe_instance_create(RID p_probe) override; virtual void reflection_probe_instance_free(RID p_instance) override; virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override; + virtual bool reflection_probe_has_atlas_index(RID p_instance) override; virtual void reflection_probe_release_atlas_index(RID p_instance) override; virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override; virtual bool reflection_probe_instance_has_reflection(RID p_instance) override; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 59d70958f1..4e5539e6a4 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -3482,8 +3482,13 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int if (p_step == 0) { if (!RSG::light_storage->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) { - return true; //all full + return true; // All full, no atlas entry to render to. } + } else if (!RSG::light_storage->reflection_probe_has_atlas_index(reflection_probe->instance)) { + // We don't have an atlas to render to, just round off. + // This is likely due to the atlas being reset. + // If so the probe will be marked as dirty and start over. + return true; } if (p_step >= 0 && p_step < 6) { @@ -3558,6 +3563,7 @@ void RendererSceneCull::render_probes() { /* REFLECTION PROBES */ SelfList<InstanceReflectionProbeData> *ref_probe = reflection_probe_render_list.first(); + Vector<SelfList<InstanceReflectionProbeData> *> done_list; bool busy = false; @@ -3573,7 +3579,7 @@ void RendererSceneCull::render_probes() { bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step); if (done) { - reflection_probe_render_list.remove(ref_probe); + done_list.push_back(ref_probe); } else { ref_probe->self()->render_step++; } @@ -3588,13 +3594,18 @@ void RendererSceneCull::render_probes() { step++; } - reflection_probe_render_list.remove(ref_probe); + done_list.push_back(ref_probe); } break; } ref_probe = next; } + // Now remove from our list + for (SelfList<InstanceReflectionProbeData> *rp : done_list) { + reflection_probe_render_list.remove(rp); + } + /* VOXEL GIS */ SelfList<InstanceVoxelGIData> *voxel_gi = voxel_gi_update_list.first(); diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h index 27407305d1..d439598f3d 100644 --- a/servers/rendering/storage/light_storage.h +++ b/servers/rendering/storage/light_storage.h @@ -143,6 +143,7 @@ public: virtual RID reflection_probe_instance_create(RID p_probe) = 0; virtual void reflection_probe_instance_free(RID p_instance) = 0; virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0; + virtual bool reflection_probe_has_atlas_index(RID p_instance) = 0; virtual void reflection_probe_release_atlas_index(RID p_instance) = 0; virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0; virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0; diff --git a/servers/text_server.cpp b/servers/text_server.cpp index b67a698615..d1dadbc839 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -535,6 +535,7 @@ void TextServer::_bind_methods() { BIND_BITFIELD_FLAG(BREAK_GRAPHEME_BOUND); BIND_BITFIELD_FLAG(BREAK_ADAPTIVE); BIND_BITFIELD_FLAG(BREAK_TRIM_EDGE_SPACES); + BIND_BITFIELD_FLAG(BREAK_TRIM_INDENT); /* VisibleCharactersBehavior */ BIND_ENUM_CONSTANT(VC_CHARS_BEFORE_SHAPING); @@ -750,13 +751,28 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks_adv(const RID &p_shaped int l_size = shaped_text_get_glyph_count(p_shaped); const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); + double indent = 0.0; + if (p_break_flags.has_flag(BREAK_TRIM_INDENT)) { + for (int i = 0; i < l_size; i++) { + if ((l_gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB || (l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { + indent += l_gl[i].advance * l_gl[i].repeat; + } else { + break; + } + } + } + for (int i = 0; i < l_size; i++) { + double l_width = p_width[chunk]; + if (l_width > indent) { + l_width -= indent; + } if (l_gl[i].start < p_start) { prev_safe_break = i + 1; continue; } if (l_gl[i].count > 0) { - if ((p_width[chunk] > 0) && (width + l_gl[i].advance > p_width[chunk]) && (last_safe_break >= 0)) { + if ((l_width > 0) && (width + l_gl[i].advance > l_width) && (last_safe_break >= 0)) { if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) { int start_pos = prev_safe_break; int end_pos = last_safe_break; @@ -891,13 +907,25 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do int l_size = shaped_text_get_glyph_count(p_shaped); const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); + double indent = 0.0; + if (p_break_flags.has_flag(BREAK_TRIM_INDENT)) { + for (int i = 0; i < l_size; i++) { + if ((l_gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB || (l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { + indent += l_gl[i].advance * l_gl[i].repeat; + } else { + break; + } + } + } + + double l_width = p_width; for (int i = 0; i < l_size; i++) { if (l_gl[i].start < p_start) { prev_safe_break = i + 1; continue; } if (l_gl[i].count > 0) { - if ((p_width > 0) && (width + l_gl[i].advance * l_gl[i].repeat > p_width) && (last_safe_break >= 0)) { + if ((l_width > 0) && (width + l_gl[i].advance * l_gl[i].repeat > l_width) && (last_safe_break >= 0)) { if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) { int start_pos = prev_safe_break; int end_pos = last_safe_break; @@ -910,6 +938,9 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do if (last_end <= l_gl[start_pos].start) { lines.push_back(l_gl[start_pos].start); lines.push_back(l_gl[end_pos].end); + if (p_width > indent) { + l_width = p_width - indent; + } last_end = l_gl[end_pos].end; } trim_next = true; @@ -917,6 +948,9 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do if (last_end <= line_start) { lines.push_back(line_start); lines.push_back(l_gl[last_safe_break].end); + if (p_width > indent) { + l_width = p_width - indent; + } last_end = l_gl[last_safe_break].end; } } @@ -943,12 +977,18 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do if (last_end <= l_gl[start_pos].start) { lines.push_back(l_gl[start_pos].start); lines.push_back(l_gl[end_pos].end); + if (p_width > indent) { + l_width = p_width - indent; + } last_end = l_gl[end_pos].end; } } else { if (last_end <= line_start) { lines.push_back(line_start); lines.push_back(l_gl[i].end); + if (p_width > indent) { + l_width = p_width - indent; + } last_end = l_gl[i].end; } } diff --git a/servers/text_server.h b/servers/text_server.h index c2cc444646..dfd6140fde 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -108,6 +108,7 @@ public: BREAK_GRAPHEME_BOUND = 1 << 2, BREAK_ADAPTIVE = 1 << 3, BREAK_TRIM_EDGE_SPACES = 1 << 4, + BREAK_TRIM_INDENT = 1 << 5, }; enum OverrunBehavior { diff --git a/thirdparty/directx_headers/include/directx/d3dx12_root_signature.h b/thirdparty/directx_headers/include/directx/d3dx12_root_signature.h index 572efed852..a83d9d017c 100644 --- a/thirdparty/directx_headers/include/directx/d3dx12_root_signature.h +++ b/thirdparty/directx_headers/include/directx/d3dx12_root_signature.h @@ -996,6 +996,9 @@ struct CD3DX12_GPU_DESCRIPTOR_HANDLE : public D3D12_GPU_DESCRIPTOR_HANDLE // two code paths for building root signatures, this helper method reconstructs a 1.0 signature when // 1.1 is not supported. inline HRESULT D3DX12SerializeVersionedRootSignature( +/* GODOT start */ + _In_ HMODULE pLibD3D12, +/* GODOT end */ _In_ const D3D12_VERSIONED_ROOT_SIGNATURE_DESC* pRootSignatureDesc, D3D_ROOT_SIGNATURE_VERSION MaxVersion, _Outptr_ ID3DBlob** ppBlob, @@ -1006,13 +1009,22 @@ inline HRESULT D3DX12SerializeVersionedRootSignature( *ppErrorBlob = nullptr; } + /* GODOT start */ + PFN_D3D12_SERIALIZE_ROOT_SIGNATURE d3d_D3D12SerializeRootSignature = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)(void *)GetProcAddress(pLibD3D12, "D3D12SerializeRootSignature"); + if (d3d_D3D12SerializeRootSignature == nullptr) { + return E_INVALIDARG; + } + PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE d3d_D3D12SerializeVersionedRootSignature = (PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)(void *)GetProcAddress(pLibD3D12, "D3D12SerializeVersionedRootSignature"); + /* GODOT end */ switch (MaxVersion) { case D3D_ROOT_SIGNATURE_VERSION_1_0: switch (pRootSignatureDesc->Version) { case D3D_ROOT_SIGNATURE_VERSION_1_0: - return D3D12SerializeRootSignature(&pRootSignatureDesc->Desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob); +/* GODOT start */ + return d3d_D3D12SerializeRootSignature(&pRootSignatureDesc->Desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob); +/* GODOT end */ case D3D_ROOT_SIGNATURE_VERSION_1_1: #if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609) @@ -1114,7 +1126,9 @@ inline HRESULT D3DX12SerializeVersionedRootSignature( if (SUCCEEDED(hr)) { const CD3DX12_ROOT_SIGNATURE_DESC desc_1_0(desc_1_1.NumParameters, pParameters_1_0, desc_1_1.NumStaticSamplers, pStaticSamplers == nullptr ? desc_1_1.pStaticSamplers : pStaticSamplers, desc_1_1.Flags); - hr = D3D12SerializeRootSignature(&desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob); +/* GODOT start */ + hr = d3d_D3D12SerializeRootSignature(&desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob); +/* GODOT end */ } if (pParameters) @@ -1145,7 +1159,9 @@ inline HRESULT D3DX12SerializeVersionedRootSignature( { case D3D_ROOT_SIGNATURE_VERSION_1_0: case D3D_ROOT_SIGNATURE_VERSION_1_1: - return D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob); +/* GODOT start */ + return d3d_D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob); +/* GODOT end */ #if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609) case D3D_ROOT_SIGNATURE_VERSION_1_2: @@ -1181,7 +1197,9 @@ inline HRESULT D3DX12SerializeVersionedRootSignature( if (SUCCEEDED(hr)) { const CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC desc(desc_1_1.NumParameters, desc_1_1.pParameters, desc_1_1.NumStaticSamplers, pStaticSamplers == nullptr ? desc_1_1.pStaticSamplers : pStaticSamplers, desc_1_1.Flags); - hr = D3D12SerializeVersionedRootSignature(&desc, ppBlob, ppErrorBlob); +/* GODOT start */ + hr = d3d_D3D12SerializeVersionedRootSignature(&desc, ppBlob, ppErrorBlob); +/* GODOT end */ } if (pStaticSamplers) @@ -1197,7 +1215,9 @@ inline HRESULT D3DX12SerializeVersionedRootSignature( #if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609) case D3D_ROOT_SIGNATURE_VERSION_1_2: #endif - return D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob); +/* GODOT start */ + return d3d_D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob); +/* GODOT end */ } return E_INVALIDARG; diff --git a/thirdparty/directx_headers/patches/patch_d3d12_dynamic_load.diff b/thirdparty/directx_headers/patches/patch_d3d12_dynamic_load.diff new file mode 100644 index 0000000000..d520a44172 --- /dev/null +++ b/thirdparty/directx_headers/patches/patch_d3d12_dynamic_load.diff @@ -0,0 +1,82 @@ +diff --git a/thirdparty/directx_headers/include/directx/d3dx12_root_signature.h b/thirdparty/directx_headers/include/directx/d3dx12_root_signature.h +index 572efed852..18efa7a0cb 100644 +--- a/thirdparty/directx_headers/include/directx/d3dx12_root_signature.h ++++ b/thirdparty/directx_headers/include/directx/d3dx12_root_signature.h +@@ -996,6 +996,9 @@ struct CD3DX12_GPU_DESCRIPTOR_HANDLE : public D3D12_GPU_DESCRIPTOR_HANDLE + // two code paths for building root signatures, this helper method reconstructs a 1.0 signature when + // 1.1 is not supported. + inline HRESULT D3DX12SerializeVersionedRootSignature( ++/* GODOT start */ ++ _In_ HMODULE pLibD3D12, ++/* GODOT end */ + _In_ const D3D12_VERSIONED_ROOT_SIGNATURE_DESC* pRootSignatureDesc, + D3D_ROOT_SIGNATURE_VERSION MaxVersion, + _Outptr_ ID3DBlob** ppBlob, +@@ -1006,13 +1009,22 @@ inline HRESULT D3DX12SerializeVersionedRootSignature( + *ppErrorBlob = nullptr; + } + ++ /* GODOT start */ ++ PFN_D3D12_SERIALIZE_ROOT_SIGNATURE d3d_D3D12SerializeRootSignature = (PFN_D3D12_SERIALIZE_ROOT_SIGNATURE)(void *)GetProcAddress(pLibD3D12, "D3D12SerializeRootSignature"); ++ if (d3d_D3D12SerializeRootSignature == nullptr) { ++ return E_INVALIDARG; ++ } ++ PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE d3d_D3D12SerializeVersionedRootSignature = (PFN_D3D12_SERIALIZE_VERSIONED_ROOT_SIGNATURE)(void *)GetProcAddress(pLibD3D12, "D3D12SerializeVersionedRootSignature"); ++ /* GODOT end */ + switch (MaxVersion) + { + case D3D_ROOT_SIGNATURE_VERSION_1_0: + switch (pRootSignatureDesc->Version) + { + case D3D_ROOT_SIGNATURE_VERSION_1_0: +- return D3D12SerializeRootSignature(&pRootSignatureDesc->Desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob); ++/* GODOT start */ ++ return d3d_D3D12SerializeRootSignature(&pRootSignatureDesc->Desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob); ++/* GODOT end */ + + case D3D_ROOT_SIGNATURE_VERSION_1_1: + #if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609) +@@ -1114,7 +1126,9 @@ inline HRESULT D3DX12SerializeVersionedRootSignature( + if (SUCCEEDED(hr)) + { + const CD3DX12_ROOT_SIGNATURE_DESC desc_1_0(desc_1_1.NumParameters, pParameters_1_0, desc_1_1.NumStaticSamplers, pStaticSamplers == nullptr ? desc_1_1.pStaticSamplers : pStaticSamplers, desc_1_1.Flags); +- hr = D3D12SerializeRootSignature(&desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob); ++/* GODOT start */ ++ hr = d3d_D3D12SerializeRootSignature(&desc_1_0, D3D_ROOT_SIGNATURE_VERSION_1, ppBlob, ppErrorBlob); ++/* GODOT end */ + } + + if (pParameters) +@@ -1145,7 +1159,9 @@ inline HRESULT D3DX12SerializeVersionedRootSignature( + { + case D3D_ROOT_SIGNATURE_VERSION_1_0: + case D3D_ROOT_SIGNATURE_VERSION_1_1: +- return D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob); ++/* GODOT start */ ++ return d3d_D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob); ++/* GODOT end */ + + #if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609) + case D3D_ROOT_SIGNATURE_VERSION_1_2: +@@ -1181,7 +1197,9 @@ inline HRESULT D3DX12SerializeVersionedRootSignature( + if (SUCCEEDED(hr)) + { + const CD3DX12_VERSIONED_ROOT_SIGNATURE_DESC desc(desc_1_1.NumParameters, desc_1_1.pParameters, desc_1_1.NumStaticSamplers, pStaticSamplers == nullptr ? desc_1_1.pStaticSamplers : pStaticSamplers, desc_1_1.Flags); +- hr = D3D12SerializeVersionedRootSignature(&desc, ppBlob, ppErrorBlob); ++/* GODOT start */ ++ hr = d3d_D3D12SerializeVersionedRootSignature(&desc, ppBlob, ppErrorBlob); ++/* GODOT end */ + } + + if (pStaticSamplers) +@@ -1197,7 +1215,9 @@ inline HRESULT D3DX12SerializeVersionedRootSignature( + #if defined(D3D12_SDK_VERSION) && (D3D12_SDK_VERSION >= 609) + case D3D_ROOT_SIGNATURE_VERSION_1_2: + #endif +- return D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob); ++/* GODOT start */ ++ return d3d_D3D12SerializeVersionedRootSignature(pRootSignatureDesc, ppBlob, ppErrorBlob); ++/* GODOT end */ + } + + return E_INVALIDARG; |