Merge pull request #75786 from YuriSizov/4.0-cherrypicks

Cherry-picks for the 4.0 branch (future 4.0.3) - 1st batch
This commit is contained in:
Rémi Verschelde 2023-04-11 21:01:58 +02:00 committed by GitHub
commit 16a6bdd423
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
109 changed files with 873 additions and 307 deletions

View File

@ -1,5 +1,6 @@
name: 🤖 Android Builds
on: [push, pull_request]
on:
workflow_call:
# Global Settings
env:

View File

@ -1,5 +1,6 @@
name: 🍏 iOS Builds
on: [push, pull_request]
on:
workflow_call:
# Global Settings
env:

View File

@ -1,5 +1,6 @@
name: 🐧 Linux Builds
on: [push, pull_request]
on:
workflow_call:
# Global Settings
env:

View File

@ -1,5 +1,6 @@
name: 🍎 macOS Builds
on: [push, pull_request]
on:
workflow_call:
# Global Settings
env:

41
.github/workflows/runner.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: 🔗 GHA
on: [push, pull_request]
concurrency:
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-runner
cancel-in-progress: true
jobs:
static-checks:
name: 📊 Static
uses: ./.github/workflows/static_checks.yml
android-build:
name: 🤖 Android
needs: static-checks
uses: ./.github/workflows/android_builds.yml
ios-build:
name: 🍏 iOS
needs: static-checks
uses: ./.github/workflows/ios_builds.yml
linux-build:
name: 🐧 Linux
needs: static-checks
uses: ./.github/workflows/linux_builds.yml
macos-build:
name: 🍎 macOS
needs: static-checks
uses: ./.github/workflows/macos_builds.yml
windows-build:
name: 🏁 Windows
needs: static-checks
uses: ./.github/workflows/windows_builds.yml
web-build:
name: 🌐 Web
needs: static-checks
uses: ./.github/workflows/web_builds.yml

View File

@ -1,5 +1,6 @@
name: 📊 Static Checks
on: [push, pull_request]
on:
workflow_call:
concurrency:
group: ci-${{github.actor}}-${{github.head_ref || github.run_number}}-${{github.ref}}-static
@ -21,7 +22,8 @@ jobs:
sudo apt-get install -qq dos2unix clang-format-15 libxml2-utils python3-pip moreutils
sudo update-alternatives --remove-all clang-format || true
sudo update-alternatives --install /usr/bin/clang-format clang-format /usr/bin/clang-format-15 100
sudo pip3 install black==22.3.0 pygments pytest==7.1.2 mypy==0.971
sudo pip3 install black==22.3.0 pytest==7.1.2 mypy==0.971
git config diff.wsErrorHighlight all
- name: File formatting checks (file_format.sh)
run: |

View File

@ -1,5 +1,6 @@
name: 🌐 Web Builds
on: [push, pull_request]
on:
workflow_call:
# Global Settings
env:

View File

@ -1,5 +1,6 @@
name: 🏁 Windows Builds
on: [push, pull_request]
on:
workflow_call:
# Global Settings
# SCONS_CACHE for windows must be set in the build environment
@ -30,7 +31,7 @@ jobs:
sconsflags: debug_symbols=no vsproj=yes
bin: "./bin/godot.windows.editor.x86_64.exe"
- name: Template (target=template_release, tools=no)
- name: Template (target=template_release)
cache-name: windows-template
target: template_release
tests: false

View File

@ -4,6 +4,123 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [4.0.3] - TBD
See the [release announcement](https://godotengine.org/article/maintenance-release-godot-4-0-3) for details.
### Added
#### Editor
- Properly remember snapping options per-project ([GH-74682](https://github.com/godotengine/godot/pull/74682)).
- Remember directory when installing templates file ([GH-74735](https://github.com/godotengine/godot/pull/74735)).
- Improve editor state initialization ([GH-75563](https://github.com/godotengine/godot/pull/75563)).
#### Navigation
- Navigation: Expose NavigationAgent path postprocessing and pathfinding algorithm options ([GH-75326](https://github.com/godotengine/godot/pull/75326)).
#### Physics
- Warn when a concave polygon is assigned to ConvexPolygonShape2D ([GH-56671](https://github.com/godotengine/godot/pull/56671)).
### Changed
#### 3D
- Use physical shortcuts for freelook navigation in the editor ([GH-73651](https://github.com/godotengine/godot/pull/73651)).
#### Buildsystem
- Wait for static check results before starting other CI builds ([GH-65232](https://github.com/godotengine/godot/pull/65232)).
- Remove obsolete 'tools' in a CI workflow name ([GH-75687](https://github.com/godotengine/godot/pull/75687)).
- Visibly print trailing whitespace when static checks fail ([GH-75700](https://github.com/godotengine/godot/pull/75700)).
#### C#/.NET
- Truncate instead of round in Vector2/3/4 to Vector2I/3I/4I conversion ([GH-75477](https://github.com/godotengine/godot/pull/75477)).
#### Editor
- Prevent off-screen controls in editor ([GH-73646](https://github.com/godotengine/godot/pull/73646)).
- Re-enable script editor File menu shortcuts when the menu is hidden ([GH-74319](https://github.com/godotengine/godot/pull/74319)).
- Prevent color conversion of the big Godot logo ([GH-75653](https://github.com/godotengine/godot/pull/75653)).
#### GUI
- Ignore invisible children of GraphNode for minimum size ([GH-72240](https://github.com/godotengine/godot/pull/72240)).
- Update `TextureProgressBar` upon texture changes ([GH-75532](https://github.com/godotengine/godot/pull/75532)).
- Keep a copy of UTF-8 XML source string during the SVG font processing ([GH-75675](https://github.com/godotengine/godot/pull/75675)).
#### Import
- gltf: Remove obsolete hack to embed gltf textures in advanced import ([GH-75636](https://github.com/godotengine/godot/pull/75636)).
#### Physics
- Modify contact_max_allowed_penetration precision to 3 significant digits ([GH-75665](https://github.com/godotengine/godot/pull/75665)).
#### Rendering
- Recreate swap chain when suboptimal to avoid error spam ([GH-72859](https://github.com/godotengine/godot/pull/72859)).
#### Thirdparty
- thorvg updated to 0.8.4.
### Fixed
#### 2D
- Fix RemoteTransform2D could fail to update AnimatableBody2D's position or rotation ([GH-75487](https://github.com/godotengine/godot/pull/75487)).
#### Audio
- Fix AudioStreamPlayer2D crash when PhysicsServer2D runs on thread ([GH-75728](https://github.com/godotengine/godot/pull/75728)).
#### Buildsystem
- Fix the Python type error when creating the .sln file ([GH-75309](https://github.com/godotengine/godot/pull/75309)).
#### Core
- Fix moving position indicator out of bounds in FileAccessMemory ([GH-75641](https://github.com/godotengine/godot/pull/75641)).
#### Editor
- Fix off-by-one issue where "Go to Line" dialog shows the incorrect line number ([GH-75523](https://github.com/godotengine/godot/pull/75523)).
#### GUI
- Fix commenting collapsed function issue ([GH-75070](https://github.com/godotengine/godot/pull/75070)).
- Fix fill align and trim with enabled dropcap in `RichTextLabel` ([GH-75504](https://github.com/godotengine/godot/pull/75504)).
- Fix descriptions not showing for theme properties ([GH-75559](https://github.com/godotengine/godot/pull/75559)).
- Fix some theme values affect the editor by setting a default value for them ([GH-75566](https://github.com/godotengine/godot/pull/75566)).
- Fix several GraphEdit operations at zoom levels other than 100% ([GH-75595](https://github.com/godotengine/godot/pull/75595)).
#### Import
- SVG: fix tvg::Picture->size() and scale based errors. ([GH-75034](https://github.com/godotengine/godot/pull/75034)).
#### Input
- Fix guide button detection with XInput and Xbox Series controllers ([GH-73200](https://github.com/godotengine/godot/pull/73200)).
- Fix the issue preventing dragging in the 2D editor ([GH-75113](https://github.com/godotengine/godot/pull/75113)).
- Fix keycode/physical keycode mix up on web ([GH-75738](https://github.com/godotengine/godot/pull/75738)).
#### Navigation
- Navigation: Fix NavigationObstacles not being added to avoidance simulation ([GH-75756](https://github.com/godotengine/godot/pull/75756)).
#### Porting
- Windows: Fix clipboard relying on focused window ([GH-73878](https://github.com/godotengine/godot/pull/73878)).
#### Rendering
- Fix interpolation of R0 for metallic and calculation of the Fresnel Shlick term in SSR ([GH-75368](https://github.com/godotengine/godot/pull/75368)).
## [4.0.2] - 2023-04-04
See the [release announcement](https://godotengine.org/article/maintenance-release-godot-4-0-2) for details.
@ -2817,6 +2934,7 @@ See the [release announcement](https://godotengine.org/article/godot-3-3-has-arr
- Only WebAssembly is supported now, since all browsers supporting WebGL 2.0 also support WebAssembly.
[4.0.3]: https://github.com/godotengine/godot/compare/4.0.2-stable...4.0.3-stable
[4.0.2]: https://github.com/godotengine/godot/compare/4.0.1-stable...4.0.2-stable
[4.0.1]: https://github.com/godotengine/godot/compare/4.0-stable...4.0.1-stable
[4.0]: https://github.com/godotengine/godot/compare/3.2-stable...4.0-stable

View File

@ -2,7 +2,7 @@
# Source: https://github.com/godotengine/godot
# Windows
__XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpdown:b1,dpleft:b2,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Windows,
__XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,guide:b10,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpdown:b1,dpleft:b2,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Windows,
# Android
Default Android Gamepad,Default Controller,leftx:a0,lefty:a1,dpdown:h0.4,rightstick:b8,rightshoulder:b10,rightx:a2,start:b6,righty:a3,dpleft:h0.8,lefttrigger:a4,x:b2,dpup:h0.1,back:b4,leftstick:b7,leftshoulder:b9,y:b3,a:b0,dpright:h0.2,righttrigger:a5,b:b1,platform:Android,

View File

@ -474,10 +474,15 @@ String InputEventKey::to_string() {
return vformat("InputEventKey: keycode=%s, mods=%s, physical=%s, pressed=%s, echo=%s", kc, mods, physical, p, e);
}
Ref<InputEventKey> InputEventKey::create_reference(Key p_keycode) {
Ref<InputEventKey> InputEventKey::create_reference(Key p_keycode, bool p_physical) {
Ref<InputEventKey> ie;
ie.instantiate();
ie->set_keycode(p_keycode & KeyModifierMask::CODE_MASK);
if (p_physical) {
ie->set_physical_keycode(p_keycode & KeyModifierMask::CODE_MASK);
} else {
ie->set_keycode(p_keycode & KeyModifierMask::CODE_MASK);
}
ie->set_unicode(char32_t(p_keycode & KeyModifierMask::CODE_MASK));
if ((p_keycode & KeyModifierMask::SHIFT) != Key::NONE) {

View File

@ -195,7 +195,7 @@ public:
virtual String as_text() const override;
virtual String to_string() override;
static Ref<InputEventKey> create_reference(Key p_keycode_with_modifier_masks);
static Ref<InputEventKey> create_reference(Key p_keycode_with_modifier_masks, bool p_physical = false);
InputEventKey() {}
};

View File

@ -144,7 +144,7 @@ uint64_t FileAccessMemory::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
}
memcpy(p_dst, &data[pos], read);
pos += p_length;
pos += read;
return read;
}
@ -172,5 +172,5 @@ void FileAccessMemory::store_buffer(const uint8_t *p_src, uint64_t p_length) {
}
memcpy(&data[pos], p_src, write);
pos += p_length;
pos += write;
}

View File

@ -5,10 +5,11 @@
</brief_description>
<description>
A cubemap that is loaded from a [code].ccube[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedCubemap] can use one of 4 compresson methods:
- Uncompressed (uncompressed on the GPU)
- Lossless (WebP or PNG, uncompressed on the GPU)
- Lossy (WebP, uncompressed on the GPU)
- VRAM Compressed (compressed on the GPU)
- VRAM Uncompressed (uncompressed on the GPU)
- Basis Universal (compressed on the GPU. Lower file sizes than VRAM Compressed, but slower to compress and lower quality than VRAM Compressed)
Only [b]VRAM Compressed[/b] actually reduces the memory usage on the GPU. The [b]Lossless[/b] and [b]Lossy[/b] compression methods will reduce the required storage on disk, but they will not reduce memory usage on the GPU as the texture is sent to the GPU uncompressed.
Using [b]VRAM Compressed[/b] also improves loading times, as VRAM-compressed textures are faster to load compared to textures using lossless or lossy compression. VRAM compression can exhibit noticeable artifacts and is intended to be used for 3D rendering, not 2D.
See [Cubemap] for a general description of cubemaps.

View File

@ -5,10 +5,11 @@
</brief_description>
<description>
A cubemap array that is loaded from a [code].ccubearray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedCubemapArray] can use one of 4 compresson methods:
- Uncompressed (uncompressed on the GPU)
- Lossless (WebP or PNG, uncompressed on the GPU)
- Lossy (WebP, uncompressed on the GPU)
- VRAM Compressed (compressed on the GPU)
- VRAM Uncompressed (uncompressed on the GPU)
- Basis Universal (compressed on the GPU. Lower file sizes than VRAM Compressed, but slower to compress and lower quality than VRAM Compressed)
Only [b]VRAM Compressed[/b] actually reduces the memory usage on the GPU. The [b]Lossless[/b] and [b]Lossy[/b] compression methods will reduce the required storage on disk, but they will not reduce memory usage on the GPU as the texture is sent to the GPU uncompressed.
Using [b]VRAM Compressed[/b] also improves loading times, as VRAM-compressed textures are faster to load compared to textures using lossless or lossy compression. VRAM compression can exhibit noticeable artifacts and is intended to be used for 3D rendering, not 2D.
See [CubemapArray] for a general description of cubemap arrays.

View File

@ -5,10 +5,11 @@
</brief_description>
<description>
A texture that is loaded from a [code].ctex[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedTexture2D] can use one of 4 compression methods (including a lack of any compression):
- Uncompressed (uncompressed on the GPU)
- Lossless (WebP or PNG, uncompressed on the GPU)
- Lossy (WebP, uncompressed on the GPU)
- VRAM Compressed (compressed on the GPU)
- VRAM Uncompressed (uncompressed on the GPU)
- Basis Universal (compressed on the GPU. Lower file sizes than VRAM Compressed, but slower to compress and lower quality than VRAM Compressed)
Only [b]VRAM Compressed[/b] actually reduces the memory usage on the GPU. The [b]Lossless[/b] and [b]Lossy[/b] compression methods will reduce the required storage on disk, but they will not reduce memory usage on the GPU as the texture is sent to the GPU uncompressed.
Using [b]VRAM Compressed[/b] also improves loading times, as VRAM-compressed textures are faster to load compared to textures using lossless or lossy compression. VRAM compression can exhibit noticeable artifacts and is intended to be used for 3D rendering, not 2D.
</description>

View File

@ -5,10 +5,11 @@
</brief_description>
<description>
A texture array that is loaded from a [code].ctexarray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedTexture2DArray] can use one of 4 compresson methods:
- Uncompressed (uncompressed on the GPU)
- Lossless (WebP or PNG, uncompressed on the GPU)
- Lossy (WebP, uncompressed on the GPU)
- VRAM Compressed (compressed on the GPU)
- VRAM Uncompressed (uncompressed on the GPU)
- Basis Universal (compressed on the GPU. Lower file sizes than VRAM Compressed, but slower to compress and lower quality than VRAM Compressed)
Only [b]VRAM Compressed[/b] actually reduces the memory usage on the GPU. The [b]Lossless[/b] and [b]Lossy[/b] compression methods will reduce the required storage on disk, but they will not reduce memory usage on the GPU as the texture is sent to the GPU uncompressed.
Using [b]VRAM Compressed[/b] also improves loading times, as VRAM-compressed textures are faster to load compared to textures using lossless or lossy compression. VRAM compression can exhibit noticeable artifacts and is intended to be used for 3D rendering, not 2D.
See [Texture2DArray] for a general description of texture arrays.

View File

@ -4,13 +4,7 @@
Base class for texture arrays that can optionally be compressed.
</brief_description>
<description>
A texture array that is loaded from a [code].ctexarray[/code] file. This file format is internal to Godot; it is created by importing other image formats with the import system. [CompressedTexture2D] can use one of 4 compresson methods:
- Uncompressed (uncompressed on the GPU)
- Lossless (WebP or PNG, uncompressed on the GPU)
- Lossy (WebP, uncompressed on the GPU)
- VRAM Compressed (compressed on the GPU)
Only [b]VRAM Compressed[/b] actually reduces the memory usage on the GPU. The [b]Lossless[/b] and [b]Lossy[/b] compression methods will reduce the required storage on disk, but they will not reduce memory usage on the GPU as the texture is sent to the GPU uncompressed.
Using [b]VRAM Compressed[/b] also improves loading times, as VRAM-compressed textures are faster to load compared to textures using lossless or lossy compression. VRAM compression can exhibit noticeable artifacts and is intended to be used for 3D rendering, not 2D.
Base class for [CompressedTexture2DArray] and [CompressedTexture3D]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types. See also [TextureLayered].
</description>
<tutorials>
</tutorials>

View File

@ -147,6 +147,12 @@
<member name="path_metadata_flags" type="int" setter="set_path_metadata_flags" getter="get_path_metadata_flags" enum="NavigationPathQueryParameters2D.PathMetadataFlags" default="7">
Additional information to return with the navigation path.
</member>
<member name="path_postprocessing" type="int" setter="set_path_postprocessing" getter="get_path_postprocessing" enum="NavigationPathQueryParameters2D.PathPostProcessing" default="0">
The path postprocessing applied to the raw path corridor found by the [member pathfinding_algorithm].
</member>
<member name="pathfinding_algorithm" type="int" setter="set_pathfinding_algorithm" getter="get_pathfinding_algorithm" enum="NavigationPathQueryParameters2D.PathfindingAlgorithm" default="0">
The pathfinding algorithm used in the path query.
</member>
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="10.0">
The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_distance]).
Does not affect normal pathfinding. To change an actor's pathfinding radius bake [NavigationMesh] resources with a different [member NavigationMesh.agent_radius] property and use different navigation maps for each actor size.

View File

@ -150,6 +150,12 @@
<member name="path_metadata_flags" type="int" setter="set_path_metadata_flags" getter="get_path_metadata_flags" enum="NavigationPathQueryParameters3D.PathMetadataFlags" default="7">
Additional information to return with the navigation path.
</member>
<member name="path_postprocessing" type="int" setter="set_path_postprocessing" getter="get_path_postprocessing" enum="NavigationPathQueryParameters3D.PathPostProcessing" default="0">
The path postprocessing applied to the raw path corridor found by the [member pathfinding_algorithm].
</member>
<member name="pathfinding_algorithm" type="int" setter="set_pathfinding_algorithm" getter="get_pathfinding_algorithm" enum="NavigationPathQueryParameters3D.PathfindingAlgorithm" default="0">
The pathfinding algorithm used in the path query.
</member>
<member name="radius" type="float" setter="set_radius" getter="get_radius" default="0.5">
The radius of the avoidance agent. This is the "body" of the avoidance agent and not the avoidance maneuver starting radius (which is controlled by [member neighbor_distance]).
Does not affect normal pathfinding. To change an actor's pathfinding radius bake [NavigationMesh] resources with a different [member NavigationMesh.agent_radius] property and use different navigation maps for each actor size.

View File

@ -4,7 +4,7 @@
Base class for texture types which contain the data of multiple [Image]s. Each image is of the same size and format.
</brief_description>
<description>
Base class for [ImageTextureLayered]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types. See also [Texture3D].
Base class for [ImageTextureLayered] and [CompressedTextureLayered]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types. See also [Texture3D].
Data is set on a per-layer basis. For [Texture2DArray]s, the layer specifies the array layer.
All images need to have the same width, height and number of mipmap levels.
A [TextureLayered] can be loaded with [method ResourceLoader.load].

View File

@ -31,7 +31,7 @@
<return type="Vector2i" />
<param index="0" name="from" type="Vector2" />
<description>
Constructs a new [Vector2i] from [Vector2]. The floating point coordinates will be truncated.
Constructs a new [Vector2i] from the given [Vector2] by truncating components' fractional parts (rounding towards zero). For a different behavior consider passing the result of [method Vector2.ceil], [method Vector2.floor] or [method Vector2.round] to this constructor instead.
</description>
</constructor>
<constructor name="Vector2i">

View File

@ -31,7 +31,7 @@
<return type="Vector3i" />
<param index="0" name="from" type="Vector3" />
<description>
Constructs a new [Vector3i] from [Vector3]. The floating point coordinates will be truncated.
Constructs a new [Vector3i] from the given [Vector3] by truncating components' fractional parts (rounding towards zero). For a different behavior consider passing the result of [method Vector3.ceil], [method Vector3.floor] or [method Vector3.round] to this constructor instead.
</description>
</constructor>
<constructor name="Vector3i">

View File

@ -27,7 +27,7 @@
<return type="Vector4i" />
<param index="0" name="from" type="Vector4" />
<description>
Constructs a new [Vector4i] from the given [Vector4].
Constructs a new [Vector4i] from the given [Vector4] by truncating components' fractional parts (rounding towards zero). For a different behavior consider passing the result of [method Vector4.ceil], [method Vector4.floor] or [method Vector4.round] to this constructor instead.
</description>
</constructor>
<constructor name="Vector4i">

View File

@ -2274,8 +2274,8 @@ Error VulkanContext::prepare_buffers() {
} else if (err == VK_SUBOPTIMAL_KHR) {
// Swapchain is not as optimal as it could be, but the platform's
// presentation engine will still present the image correctly.
print_verbose("Vulkan: Early suboptimal swapchain.");
break;
print_verbose("Vulkan: Early suboptimal swapchain, recreating.");
_update_swap_chain(w);
} else if (err != VK_SUCCESS) {
ERR_BREAK_MSG(err != VK_SUCCESS, "Vulkan: Did not create swapchain successfully. Error code: " + String(string_VkResult(err)));
} else {

View File

@ -42,7 +42,8 @@
void GotoLineDialog::popup_find_line(CodeEdit *p_edit) {
text_editor = p_edit;
line->set_text(itos(text_editor->get_caret_line()));
// Add 1 because text_editor->get_caret_line() starts from 0, but the editor user interface starts from 1.
line->set_text(itos(text_editor->get_caret_line() + 1));
line->select_all();
popup_centered(Size2(180, 80) * EDSCALE);
line->grab_focus();
@ -53,12 +54,14 @@ int GotoLineDialog::get_line() const {
}
void GotoLineDialog::ok_pressed() {
if (get_line() < 1 || get_line() > text_editor->get_line_count()) {
// Subtract 1 because the editor user interface starts from 1, but text_editor->set_caret_line(n) starts from 0.
const int line_number = get_line() - 1;
if (line_number < 0 || line_number >= text_editor->get_line_count()) {
return;
}
text_editor->remove_secondary_carets();
text_editor->unfold_line(get_line() - 1);
text_editor->set_caret_line(get_line() - 1);
text_editor->unfold_line(line_number);
text_editor->set_caret_line(line_number);
hide();
}
@ -1092,13 +1095,13 @@ void CodeTextEditor::remove_find_replace_bar() {
}
void CodeTextEditor::trim_trailing_whitespace() {
bool trimed_whitespace = false;
bool trimmed_whitespace = false;
for (int i = 0; i < text_editor->get_line_count(); i++) {
String line = text_editor->get_line(i);
if (line.ends_with(" ") || line.ends_with("\t")) {
if (!trimed_whitespace) {
if (!trimmed_whitespace) {
text_editor->begin_complex_operation();
trimed_whitespace = true;
trimmed_whitespace = true;
}
int end = 0;
@ -1112,7 +1115,7 @@ void CodeTextEditor::trim_trailing_whitespace() {
}
}
if (trimed_whitespace) {
if (trimmed_whitespace) {
text_editor->merge_overlapping_carets();
text_editor->end_complex_operation();
text_editor->queue_redraw();
@ -1584,11 +1587,17 @@ void CodeTextEditor::toggle_inline_comment(const String &delimiter) {
Vector<int> caret_edit_order = text_editor->get_caret_index_edit_order();
caret_edit_order.reverse();
int last_line = -1;
int folded_to = 0;
for (const int &c1 : caret_edit_order) {
int from = _get_affected_lines_from(c1);
from += from == last_line ? 1 : 0;
from += from == last_line ? 1 + folded_to : 0;
int to = _get_affected_lines_to(c1);
last_line = to;
// If last line is folded, extends to the end of the folded section
if (text_editor->is_line_folded(to)) {
folded_to = text_editor->get_next_visible_line_offset_from(to + 1, 1) - 1;
to += folded_to;
}
// Check first if there's any uncommented lines in selection.
bool is_commented = true;
for (int line = from; line <= to; line++) {

View File

@ -293,6 +293,13 @@ Dictionary EditorData::get_scene_editor_states(int p_idx) const {
}
void EditorData::set_editor_states(const Dictionary &p_states) {
if (p_states.is_empty()) {
for (EditorPlugin *ep : editor_plugins) {
ep->clear();
}
return;
}
List<Variant> keys;
p_states.get_key_list(&keys);

View File

@ -3133,6 +3133,11 @@ void EditorInspector::update_tree() {
StringName propname = property_prefix + p.name;
bool found = false;
// Small hack for theme_overrides. They are listed under Control, but come from another class.
if (classname == "Control" && p.name.begins_with("theme_override_")) {
classname = get_edited_object()->get_class();
}
// Search for the property description in the cache.
HashMap<StringName, HashMap<StringName, PropertyDocInfo>>::Iterator E = doc_info_cache.find(classname);
if (E) {

View File

@ -1468,7 +1468,7 @@ Ref<Shortcut> ED_GET_SHORTCUT(const String &p_path) {
return sc;
}
void ED_SHORTCUT_OVERRIDE(const String &p_path, const String &p_feature, Key p_keycode) {
void ED_SHORTCUT_OVERRIDE(const String &p_path, const String &p_feature, Key p_keycode, bool p_physical) {
ERR_FAIL_NULL_MSG(EditorSettings::get_singleton(), "EditorSettings not instantiated yet.");
Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);
@ -1477,10 +1477,10 @@ void ED_SHORTCUT_OVERRIDE(const String &p_path, const String &p_feature, Key p_k
PackedInt32Array arr;
arr.push_back((int32_t)p_keycode);
ED_SHORTCUT_OVERRIDE_ARRAY(p_path, p_feature, arr);
ED_SHORTCUT_OVERRIDE_ARRAY(p_path, p_feature, arr, p_physical);
}
void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, const PackedInt32Array &p_keycodes) {
void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, const PackedInt32Array &p_keycodes, bool p_physical) {
ERR_FAIL_NULL_MSG(EditorSettings::get_singleton(), "EditorSettings not instantiated yet.");
Ref<Shortcut> sc = EditorSettings::get_singleton()->get_shortcut(p_path);
@ -1505,7 +1505,7 @@ void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, c
Ref<InputEventKey> ie;
if (keycode != Key::NONE) {
ie = InputEventKey::create_reference(keycode);
ie = InputEventKey::create_reference(keycode, p_physical);
events.push_back(ie);
}
}
@ -1518,13 +1518,13 @@ void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, c
sc->set_meta("original", events.duplicate(true));
}
Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, Key p_keycode) {
Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, Key p_keycode, bool p_physical) {
PackedInt32Array arr;
arr.push_back((int32_t)p_keycode);
return ED_SHORTCUT_ARRAY(p_path, p_name, arr);
return ED_SHORTCUT_ARRAY(p_path, p_name, arr, p_physical);
}
Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, const PackedInt32Array &p_keycodes) {
Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, const PackedInt32Array &p_keycodes, bool p_physical) {
Array events;
for (int i = 0; i < p_keycodes.size(); i++) {
@ -1539,7 +1539,7 @@ Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, cons
Ref<InputEventKey> ie;
if (keycode != Key::NONE) {
ie = InputEventKey::create_reference(keycode);
ie = InputEventKey::create_reference(keycode, p_physical);
events.push_back(ie);
}
}

View File

@ -195,10 +195,10 @@ Variant _EDITOR_DEF(const String &p_setting, const Variant &p_default, bool p_re
Variant _EDITOR_GET(const String &p_setting);
#define ED_IS_SHORTCUT(p_name, p_ev) (EditorSettings::get_singleton()->is_shortcut(p_name, p_ev))
Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, Key p_keycode = Key::NONE);
Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, const PackedInt32Array &p_keycodes);
void ED_SHORTCUT_OVERRIDE(const String &p_path, const String &p_feature, Key p_keycode = Key::NONE);
void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, const PackedInt32Array &p_keycodes);
Ref<Shortcut> ED_SHORTCUT(const String &p_path, const String &p_name, Key p_keycode = Key::NONE, bool p_physical = false);
Ref<Shortcut> ED_SHORTCUT_ARRAY(const String &p_path, const String &p_name, const PackedInt32Array &p_keycodes, bool p_physical = false);
void ED_SHORTCUT_OVERRIDE(const String &p_path, const String &p_feature, Key p_keycode = Key::NONE, bool p_physical = false);
void ED_SHORTCUT_OVERRIDE_ARRAY(const String &p_path, const String &p_feature, const PackedInt32Array &p_keycodes, bool p_physical = false);
Ref<Shortcut> ED_GET_SHORTCUT(const String &p_path);
#endif // EDITOR_SETTINGS_H

View File

@ -859,6 +859,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("icon_pressed_color", "Button", icon_pressed_color);
theme->set_color("icon_disabled_color", "Button", icon_disabled_color);
theme->set_constant("h_separation", "Button", 2 * EDSCALE);
theme->set_constant("outline_size", "Button", 0 * EDSCALE);
const float ACTION_BUTTON_EXTRA_MARGIN = 32 * EDSCALE;
@ -915,6 +916,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("icon_pressed_color", "MenuBar", icon_pressed_color);
theme->set_color("icon_disabled_color", "MenuBar", icon_disabled_color);
theme->set_constant("h_separation", "MenuBar", 4 * EDSCALE);
theme->set_constant("outline_size", "MenuBar", 0 * EDSCALE);
// OptionButton
@ -1450,6 +1452,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_outline_color", "TextEdit", font_outline_color);
theme->set_color("caret_color", "TextEdit", font_color);
theme->set_color("selection_color", "TextEdit", selection_color);
theme->set_color("background_color", "TextEdit", Color(0, 0, 0, 0));
theme->set_constant("line_spacing", "TextEdit", 4 * EDSCALE);
theme->set_constant("outline_size", "TextEdit", 0 * EDSCALE);

View File

@ -529,6 +529,7 @@ bool ExportTemplateManager::_install_file_selected(const String &p_file, bool p_
unzClose(pkg);
_update_template_status();
EditorSettings::get_singleton()->set_meta("export_template_download_directory", p_file.get_base_dir());
return true;
}
@ -992,6 +993,7 @@ ExportTemplateManager::ExportTemplateManager() {
install_file_dialog->set_title(TTR("Select Template File"));
install_file_dialog->set_access(FileDialog::ACCESS_FILESYSTEM);
install_file_dialog->set_file_mode(FileDialog::FILE_MODE_OPEN_FILE);
install_file_dialog->set_current_dir(EditorSettings::get_singleton()->get_meta("export_template_download_directory", ""));
install_file_dialog->add_filter("*.tpz", TTR("Godot Export Templates"));
install_file_dialog->connect("file_selected", callable_mp(this, &ExportTemplateManager::_install_file_selected).bind(false));
add_child(install_file_dialog);

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -2302,11 +2302,6 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file, const HashM
Error err = OK;
HashMap<StringName, Variant> options_dupe = p_options;
// By default, the GLTF importer will extract embedded images into files on disk
// However, we do not want the advanced settings dialog to be able to write files on disk.
// To avoid this and also avoid compressing to basis every time, we are using the uncompressed option.
options_dupe["gltf/embedded_image_handling"] = 3; // Embed as Uncompressed defined in GLTFState::GLTFHandleBinary::HANDLE_BINARY_EMBED_AS_UNCOMPRESSED
Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, options_dupe, nullptr, &err);
if (!scene || err != OK) {
return nullptr;

View File

@ -895,6 +895,14 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite
void CanvasItemEditor::_snap_changed() {
static_cast<SnapDialog *>(snap_dialog)->get_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step);
EditorSettings::get_singleton()->set_project_metadata("2d_editor", "grid_offset", grid_offset);
EditorSettings::get_singleton()->set_project_metadata("2d_editor", "grid_step", grid_step);
EditorSettings::get_singleton()->set_project_metadata("2d_editor", "primary_grid_steps", primary_grid_steps);
EditorSettings::get_singleton()->set_project_metadata("2d_editor", "snap_rotation_offset", snap_rotation_offset);
EditorSettings::get_singleton()->set_project_metadata("2d_editor", "snap_rotation_step", snap_rotation_step);
EditorSettings::get_singleton()->set_project_metadata("2d_editor", "snap_scale_step", snap_scale_step);
grid_step_multiplier = 0;
viewport->queue_redraw();
}
@ -4683,7 +4691,6 @@ void CanvasItemEditor::_reset_drag() {
void CanvasItemEditor::_bind_methods() {
ClassDB::bind_method("_get_editor_data", &CanvasItemEditor::_get_editor_data);
ClassDB::bind_method(D_METHOD("set_state"), &CanvasItemEditor::set_state);
ClassDB::bind_method(D_METHOD("update_viewport"), &CanvasItemEditor::update_viewport);
ClassDB::bind_method(D_METHOD("center_at", "position"), &CanvasItemEditor::center_at);
@ -4896,6 +4903,22 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
viewport->queue_redraw();
}
void CanvasItemEditor::clear() {
zoom = 1.0 / MAX(1, EDSCALE);
zoom_widget->set_zoom(zoom);
view_offset = Point2(-150 - RULER_WIDTH, -95 - RULER_WIDTH);
previous_update_view_offset = view_offset; // Moves the view a little bit to the left so that (0,0) is visible. The values a relative to a 16/10 screen.
_update_scrollbars();
grid_offset = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "grid_offset", Vector2());
grid_step = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "grid_step", Vector2(8, 8));
primary_grid_steps = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "primary_grid_steps", 8);
snap_rotation_step = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "snap_rotation_step", Math::deg_to_rad(15.0));
snap_rotation_offset = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "snap_rotation_offset", 0.0);
snap_scale_step = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "snap_scale_step", 0.1);
}
void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
ERR_FAIL_COND(!p_control);
@ -4939,10 +4962,6 @@ void CanvasItemEditor::center_at(const Point2 &p_pos) {
}
CanvasItemEditor::CanvasItemEditor() {
zoom = 1.0 / MAX(1, EDSCALE);
view_offset = Point2(-150 - RULER_WIDTH, -95 - RULER_WIDTH);
previous_update_view_offset = view_offset; // Moves the view a little bit to the left so that (0,0) is visible. The values a relative to a 16/10 screen
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
@ -5388,9 +5407,10 @@ CanvasItemEditor::CanvasItemEditor() {
singleton = this;
set_process_shortcut_input(true);
clear(); // Make sure values are initialized.
// Update the menus' checkboxes
call_deferred(SNAME("set_state"), get_state());
// Update the menus' checkboxes.
callable_mp(this, &CanvasItemEditor::set_state).bind(get_state()).call_deferred();
}
CanvasItemEditor *CanvasItemEditor::singleton = nullptr;
@ -5426,6 +5446,10 @@ void CanvasItemEditorPlugin::set_state(const Dictionary &p_state) {
canvas_item_editor->set_state(p_state);
}
void CanvasItemEditorPlugin::clear() {
canvas_item_editor->clear();
}
void CanvasItemEditorPlugin::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {

View File

@ -211,15 +211,15 @@ private:
bool selected_from_canvas = false;
// Defaults are defined in clear().
Point2 grid_offset;
// A power-of-two value works better as a default grid size.
Point2 grid_step = Point2(8, 8);
int primary_grid_steps = 8;
Point2 grid_step;
int primary_grid_steps = 0;
int grid_step_multiplier = 0;
real_t snap_rotation_step = Math::deg_to_rad(15.0);
real_t snap_rotation_step = 0.0;
real_t snap_rotation_offset = 0.0;
real_t snap_scale_step = 0.1f;
real_t snap_scale_step = 0.0;
bool smart_snap_active = false;
bool grid_snap_active = false;
@ -526,6 +526,7 @@ public:
static CanvasItemEditor *get_singleton() { return singleton; }
Dictionary get_state() const;
void set_state(const Dictionary &p_state);
void clear();
void add_control_to_menu_panel(Control *p_control);
void remove_control_from_menu_panel(Control *p_control);
@ -575,6 +576,7 @@ public:
virtual void make_visible(bool p_visible) override;
virtual Dictionary get_state() const override;
virtual void set_state(const Dictionary &p_state) override;
virtual void clear() override;
CanvasItemEditor *get_canvas_item_editor() { return canvas_item_editor; }

View File

@ -4872,8 +4872,8 @@ void Node3DEditorViewport::finish_transform() {
}
// Register a shortcut and also add it as an input action with the same events.
void Node3DEditorViewport::register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode) {
Ref<Shortcut> sc = ED_SHORTCUT(p_path, p_name, p_keycode);
void Node3DEditorViewport::register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode, bool p_physical) {
Ref<Shortcut> sc = ED_SHORTCUT(p_path, p_name, p_keycode, p_physical);
shortcut_changed_callback(sc, p_path);
// Connect to the change event on the shortcut so the input binding can be updated.
sc->connect("changed", callable_mp(this, &Node3DEditorViewport::shortcut_changed_callback).bind(sc, p_path));
@ -5054,12 +5054,12 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
view_menu->get_popup()->set_item_tooltip(shadeless_idx, unsupported_tooltip);
}
register_shortcut_action("spatial_editor/freelook_left", TTR("Freelook Left"), Key::A);
register_shortcut_action("spatial_editor/freelook_right", TTR("Freelook Right"), Key::D);
register_shortcut_action("spatial_editor/freelook_forward", TTR("Freelook Forward"), Key::W);
register_shortcut_action("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), Key::S);
register_shortcut_action("spatial_editor/freelook_up", TTR("Freelook Up"), Key::E);
register_shortcut_action("spatial_editor/freelook_down", TTR("Freelook Down"), Key::Q);
register_shortcut_action("spatial_editor/freelook_left", TTR("Freelook Left"), Key::A, true);
register_shortcut_action("spatial_editor/freelook_right", TTR("Freelook Right"), Key::D, true);
register_shortcut_action("spatial_editor/freelook_forward", TTR("Freelook Forward"), Key::W, true);
register_shortcut_action("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), Key::S, true);
register_shortcut_action("spatial_editor/freelook_up", TTR("Freelook Up"), Key::E, true);
register_shortcut_action("spatial_editor/freelook_down", TTR("Freelook Down"), Key::Q, true);
register_shortcut_action("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), Key::SHIFT);
register_shortcut_action("spatial_editor/freelook_slow_modifier", TTR("Freelook Slow Modifier"), Key::ALT);
@ -5995,6 +5995,10 @@ void Node3DEditor::_snap_changed() {
snap_translate_value = snap_translate->get_text().to_float();
snap_rotate_value = snap_rotate->get_text().to_float();
snap_scale_value = snap_scale->get_text().to_float();
EditorSettings::get_singleton()->set_project_metadata("3d_editor", "snap_translate_value", snap_translate_value);
EditorSettings::get_singleton()->set_project_metadata("3d_editor", "snap_rotate_value", snap_rotate_value);
EditorSettings::get_singleton()->set_project_metadata("3d_editor", "snap_scale_value", snap_scale_value);
}
void Node3DEditor::_snap_update() {
@ -7853,11 +7857,19 @@ void Node3DEditor::clear() {
settings_znear->set_value(EDITOR_GET("editors/3d/default_z_near"));
settings_zfar->set_value(EDITOR_GET("editors/3d/default_z_far"));
snap_translate_value = EditorSettings::get_singleton()->get_project_metadata("3d_editor", "snap_translate_value", 1);
snap_rotate_value = EditorSettings::get_singleton()->get_project_metadata("3d_editor", "snap_rotate_value", 15);
snap_scale_value = EditorSettings::get_singleton()->get_project_metadata("3d_editor", "snap_scale_value", 10);
_snap_update();
for (uint32_t i = 0; i < VIEWPORTS_COUNT; i++) {
viewports[i]->reset();
}
RenderingServer::get_singleton()->instance_set_visible(origin_instance, true);
if (origin_instance.is_valid()) {
RenderingServer::get_singleton()->instance_set_visible(origin_instance, true);
}
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_ORIGIN), true);
for (int i = 0; i < 3; ++i) {
if (grid_enable[i]) {
@ -8307,10 +8319,6 @@ Node3DEditor::Node3DEditor() {
/* SNAP DIALOG */
snap_translate_value = 1;
snap_rotate_value = 15;
snap_scale_value = 10;
snap_dialog = memnew(ConfirmationDialog);
snap_dialog->set_title(TTR("Snap Settings"));
add_child(snap_dialog);
@ -8649,6 +8657,7 @@ void fragment() {
_load_default_preview_settings();
_preview_settings_changed();
}
clear(); // Make sure values are initialized.
}
Node3DEditor::~Node3DEditor() {
memdelete(preview_node);

View File

@ -441,7 +441,7 @@ private:
void update_transform(Point2 p_mousepos, bool p_shift);
void finish_transform();
void register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode);
void register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode, bool p_physical = false);
void shortcut_changed_callback(const Ref<Shortcut> p_shortcut, const String &p_shortcut_path);
protected:

View File

@ -1561,6 +1561,30 @@ void ScriptEditor::_prepare_file_menu() {
menu->set_item_disabled(menu->get_item_index(FILE_RUN), current_is_doc);
}
void ScriptEditor::_file_menu_closed() {
PopupMenu *menu = file_menu->get_popup();
menu->set_item_disabled(menu->get_item_index(FILE_REOPEN_CLOSED), false);
menu->set_item_disabled(menu->get_item_index(FILE_SAVE), false);
menu->set_item_disabled(menu->get_item_index(FILE_SAVE_AS), false);
menu->set_item_disabled(menu->get_item_index(FILE_SAVE_ALL), false);
menu->set_item_disabled(menu->get_item_index(FILE_TOOL_RELOAD_SOFT), false);
menu->set_item_disabled(menu->get_item_index(FILE_COPY_PATH), false);
menu->set_item_disabled(menu->get_item_index(SHOW_IN_FILE_SYSTEM), false);
menu->set_item_disabled(menu->get_item_index(WINDOW_PREV), false);
menu->set_item_disabled(menu->get_item_index(WINDOW_NEXT), false);
menu->set_item_disabled(menu->get_item_index(FILE_CLOSE), false);
menu->set_item_disabled(menu->get_item_index(CLOSE_ALL), false);
menu->set_item_disabled(menu->get_item_index(CLOSE_OTHER_TABS), false);
menu->set_item_disabled(menu->get_item_index(CLOSE_DOCS), false);
menu->set_item_disabled(menu->get_item_index(FILE_RUN), false);
}
void ScriptEditor::_tab_changed(int p_which) {
ensure_select_current();
}
@ -3916,6 +3940,7 @@ ScriptEditor::ScriptEditor() {
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/toggle_scripts_panel", TTR("Toggle Scripts Panel"), KeyModifierMask::CMD_OR_CTRL | Key::BACKSLASH), TOGGLE_SCRIPTS_PANEL);
file_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptEditor::_menu_option));
file_menu->get_popup()->connect("about_to_popup", callable_mp(this, &ScriptEditor::_prepare_file_menu));
file_menu->get_popup()->connect("popup_hide", callable_mp(this, &ScriptEditor::_file_menu_closed));
script_search_menu = memnew(MenuButton);
script_search_menu->set_text(TTR("Search"));

View File

@ -336,6 +336,7 @@ class ScriptEditor : public PanelContainer {
bool _has_docs_tab() const;
bool _has_script_tab() const;
void _prepare_file_menu();
void _file_menu_closed();
Tree *disk_changed_list = nullptr;
ConfirmationDialog *disk_changed = nullptr;

View File

@ -848,6 +848,12 @@ void TextureRegionEditor::_notification(int p_what) {
if (snap_mode == SNAP_AUTOSLICE && is_visible() && autoslice_is_dirty) {
_update_autoslice();
}
if (!is_visible()) {
EditorSettings::get_singleton()->set_project_metadata("texture_region_editor", "snap_step", snap_step);
EditorSettings::get_singleton()->set_project_metadata("texture_region_editor", "snap_separation", snap_separation);
EditorSettings::get_singleton()->set_project_metadata("texture_region_editor", "snap_mode", snap_mode);
}
} break;
case NOTIFICATION_WM_WINDOW_FOCUS_IN: {
@ -1076,9 +1082,9 @@ TextureRegionEditor::TextureRegionEditor() {
preview_tex = Ref<CanvasTexture>(memnew(CanvasTexture));
// A power-of-two value works better as a default grid size.
snap_step = Vector2(8, 8);
snap_separation = Vector2(0, 0);
snap_mode = SNAP_NONE;
snap_step = EditorSettings::get_singleton()->get_project_metadata("texture_region_editor", "snap_step", Vector2(8, 8));
snap_separation = EditorSettings::get_singleton()->get_project_metadata("texture_region_editor", "snap_separation", Vector2());
snap_mode = EditorSettings::get_singleton()->get_project_metadata("texture_region_editor", "snap_mode", SNAP_NONE);
edited_margin = -1;
drag_index = -1;
drag = false;

View File

@ -783,7 +783,7 @@ def generate_vs_project(env, num_jobs, project_name="godot"):
for plat_id in ModuleConfigs.PLATFORM_IDS
]
self.arg_dict["cpppaths"] += ModuleConfigs.for_every_variant(env["CPPPATH"] + [includes])
self.arg_dict["cppdefines"] += ModuleConfigs.for_every_variant(env["CPPDEFINES"] + defines)
self.arg_dict["cppdefines"] += ModuleConfigs.for_every_variant(list(env["CPPDEFINES"]) + defines)
self.arg_dict["cmdargs"] += ModuleConfigs.for_every_variant(cli_args)
def build_commandline(self, commands):

View File

@ -13,13 +13,14 @@ diff=$(git diff --color)
# If no diff has been generated all is OK, clean up, and exit.
if [ -z "$diff" ] ; then
printf "Files in this commit comply with the black style rules.\n"
printf "\e[1;32m*** Files in this commit comply with the black style rules.\e[0m\n"
exit 0
fi
# A diff has been created, notify the user, clean up, and exit.
printf "\n*** The following differences were found between the code "
printf "and the formatting rules:\n\n"
echo "$diff"
printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n"
# Perl commands replace trailing spaces with `·` and tabs with `<TAB>`.
printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge'
printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n"
exit 1

View File

@ -33,12 +33,14 @@ diff=$(git diff --color)
# If no diff has been generated all is OK, clean up, and exit.
if [ -z "$diff" ] ; then
printf "Files in this commit comply with the clang-format style rules.\n"
printf "\e[1;32m*** Files in this commit comply with the clang-format style rules.\e[0m\n"
exit 0
fi
# A diff has been created, notify the user, clean up, and exit.
printf "\n*** The following changes have been made to comply with the formatting rules:\n\n"
echo "$diff"
printf "\n*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n"
# Perl commands replace trailing spaces with `·` and tabs with `<TAB>`.
printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge'
printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n"
exit 1

View File

@ -20,12 +20,14 @@ diff=$(git diff --color)
# If no diff has been generated all is OK, clean up, and exit.
if [ -z "$diff" ] ; then
printf "Files in this commit comply with the clang-tidy style rules.\n"
printf "\e[1;32m*** Files in this commit comply with the clang-tidy style rules.\e[0m\n"
exit 0
fi
# A diff has been created, notify the user, clean up, and exit.
printf "\n*** The following changes have been made to comply with the formatting rules:\n\n"
echo "$diff"
printf "\n*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n"
# Perl commands replace trailing spaces with `·` and tabs with `<TAB>`.
printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge'
printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n"
exit 1

View File

@ -24,12 +24,14 @@ diff=$(git diff --color)
# If no diff has been generated all is OK, clean up, and exit.
if [ -z "$diff" ] ; then
printf "Files in this commit comply with the dotnet format style rules.\n"
printf "\e[1;32m*** Files in this commit comply with the dotnet format style rules.\e[0m\n"
exit 0
fi
# A diff has been created, notify the user, clean up, and exit.
printf "\n*** The following changes have been made to comply with the formatting rules:\n\n"
echo "$diff"
printf "\n*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n"
# Perl commands replace trailing spaces with `·` and tabs with `<TAB>`.
printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge'
printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n"
exit 1

View File

@ -56,7 +56,7 @@ diff=$(git diff --color)
if [ ! -s utf8-validation.txt ] && [ -z "$diff" ] ; then
# If no UTF-8 violations were collected (the file is empty) and
# no diff has been generated all is OK, clean up, and exit.
printf "Files in this commit comply with the formatting rules.\n"
printf "\e[1;32m*** Files in this commit comply with the file formatting rules.\e[0m\n"
rm -f utf8-validation.txt
exit 0
fi
@ -65,7 +65,7 @@ if [ -s utf8-validation.txt ]
then
# If the file has content and is not empty, violations
# detected, notify the user, clean up, and exit.
printf "\n*** The following files contain invalid UTF-8 character sequences:\n\n"
printf "\n\e[1;33m*** The following files contain invalid UTF-8 character sequences:\e[0m\n\n"
cat utf8-validation.txt
fi
@ -73,10 +73,11 @@ rm -f utf8-validation.txt
if [ ! -z "$diff" ]
then
printf "\n*** The following differences were found between the code "
printf "and the formatting rules:\n\n"
echo "$diff"
# A diff has been created, notify the user, clean up, and exit.
printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n"
# Perl commands replace trailing spaces with `·` and tabs with `<TAB>`.
printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge'
fi
printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n"
exit 1

View File

@ -66,13 +66,14 @@ diff=$(git diff --color)
# If no diff has been generated all is OK, clean up, and exit.
if [ -z "$diff" ] ; then
printf "Files in this commit comply with the header guards formatting rules.\n"
printf "\e[1;32m*** Files in this commit comply with the header guards formatting rules.\e[0m\n"
exit 0
fi
# A diff has been created, notify the user, clean up, and exit.
printf "\n*** The following differences were found between the code "
printf "and the header guards formatting rules:\n\n"
echo "$diff"
printf "\n*** Aborting, please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\n"
printf "\n\e[1;33m*** The following changes must be made to comply with the formatting rules:\e[0m\n\n"
# Perl commands replace trailing spaces with `·` and tabs with `<TAB>`.
printf "$diff\n" | perl -pe 's/(.*[^ ])( +)(\e\[m)$/my $spaces="·" x length($2); sprintf("$1$spaces$3")/ge' | perl -pe 's/(.*[^\t])(\t+)(\e\[m)$/my $tabs="<TAB>" x length($2); sprintf("$1$tabs$3")/ge'
printf "\n\e[1;91m*** Please fix your commit(s) with 'git commit --amend' or 'git rebase -i <hash>'\e[0m\n"
exit 1

View File

@ -504,15 +504,15 @@ namespace Godot
}
/// <summary>
/// Converts a <see cref="Vector2"/> to a <see cref="Vector2I"/>.
/// Converts a <see cref="Vector2"/> to a <see cref="Vector2I"/> by truncating
/// components' fractional parts (rounding towards zero). For a different
/// behavior consider passing the result of <see cref="Vector2.Ceil"/>,
/// <see cref="Vector2.Floor"/> or <see cref="Vector2.Round"/> to this conversion operator instead.
/// </summary>
/// <param name="value">The vector to convert.</param>
public static explicit operator Vector2I(Vector2 value)
{
return new Vector2I(
Mathf.RoundToInt(value.X),
Mathf.RoundToInt(value.Y)
);
return new Vector2I((int)value.X, (int)value.Y);
}
/// <summary>

View File

@ -559,16 +559,15 @@ namespace Godot
}
/// <summary>
/// Converts a <see cref="Vector3"/> to a <see cref="Vector3I"/>.
/// Converts a <see cref="Vector3"/> to a <see cref="Vector3I"/> by truncating
/// components' fractional parts (rounding towards zero). For a different
/// behavior consider passing the result of <see cref="Vector3.Ceil"/>,
/// <see cref="Vector3.Floor"/> or <see cref="Vector3.Round"/> to this conversion operator instead.
/// </summary>
/// <param name="value">The vector to convert.</param>
public static explicit operator Vector3I(Vector3 value)
{
return new Vector3I(
Mathf.RoundToInt(value.X),
Mathf.RoundToInt(value.Y),
Mathf.RoundToInt(value.Z)
);
return new Vector3I((int)value.X, (int)value.Y, (int)value.Z);
}
/// <summary>

View File

@ -580,17 +580,15 @@ namespace Godot
}
/// <summary>
/// Converts a <see cref="Vector4"/> to a <see cref="Vector4I"/>.
/// Converts a <see cref="Vector4"/> to a <see cref="Vector4I"/> by truncating
/// components' fractional parts (rounding towards zero). For a different
/// behavior consider passing the result of <see cref="Vector4.Ceil"/>,
/// <see cref="Vector4.Floor"/> or <see cref="Vector4.Round"/> to this conversion operator instead.
/// </summary>
/// <param name="value">The vector to convert.</param>
public static explicit operator Vector4I(Vector4 value)
{
return new Vector4I(
Mathf.RoundToInt(value.X),
Mathf.RoundToInt(value.Y),
Mathf.RoundToInt(value.Z),
Mathf.RoundToInt(value.W)
);
return new Vector4I((int)value.X, (int)value.Y, (int)value.Z, (int)value.W);
}
/// <summary>

View File

@ -79,8 +79,8 @@ Error ImageLoaderSVG::create_image_from_utf8_buffer(Ref<Image> p_image, const Pa
float fw, fh;
picture->size(&fw, &fh);
uint32_t width = round(fw * p_scale);
uint32_t height = round(fh * p_scale);
uint32_t width = MAX(1, round(fw * p_scale));
uint32_t height = MAX(1, round(fh * p_scale));
const uint32_t max_dimension = 16384;
if (width > max_dimension || height > max_dimension) {

View File

@ -126,10 +126,11 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
xml_body += vformat("</%s>", parser->get_node_name());
}
}
String temp_xml = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body;
String temp_xml_str = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body;
CharString temp_xml = temp_xml_str.utf8();
std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen();
tvg::Result result = picture->load(temp_xml.utf8().get_data(), temp_xml.utf8().length(), "svg+xml", false);
tvg::Result result = picture->load(temp_xml.get_data(), temp_xml.length(), "svg+xml", false);
if (result != tvg::Result::Success) {
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (bounds detection).");
}
@ -146,10 +147,11 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
new_h = (new_w / aspect);
}
gl_state.xml_code = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
String xml_code_str = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
gl_state.xml_code = xml_code_str.utf8();
picture = tvg::Picture::gen();
result = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false);
result = picture->load(gl_state.xml_code.get_data(), gl_state.xml_code.length(), "svg+xml", false);
if (result != tvg::Result::Success) {
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph metrics).");
}
@ -237,7 +239,7 @@ FT_Error tvg_svg_in_ot_render(FT_GlyphSlot p_slot, FT_Pointer *p_state) {
ERR_FAIL_COND_V_MSG(!gl_state.ready, FT_Err_Invalid_SVG_Document, "SVG glyph not ready.");
std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen();
tvg::Result res = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false);
tvg::Result res = picture->load(gl_state.xml_code.get_data(), gl_state.xml_code.length(), "svg+xml", false);
if (res != tvg::Result::Success) {
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph rendering).");
}

View File

@ -65,7 +65,7 @@ struct GL_State {
float y = 0;
float w = 0;
float h = 0;
String xml_code;
CharString xml_code;
tvg::Matrix m;
};

View File

@ -126,10 +126,11 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
xml_body += vformat("</%s>", parser->get_node_name());
}
}
String temp_xml = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body;
String temp_xml_str = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body;
CharString temp_xml = temp_xml_str.utf8();
std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen();
tvg::Result result = picture->load(temp_xml.utf8().get_data(), temp_xml.utf8().length(), "svg+xml", false);
tvg::Result result = picture->load(temp_xml.get_data(), temp_xml.length(), "svg+xml", false);
if (result != tvg::Result::Success) {
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (bounds detection).");
}
@ -146,10 +147,11 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
new_h = (new_w / aspect);
}
gl_state.xml_code = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
String xml_code_str = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
gl_state.xml_code = xml_code_str.utf8();
picture = tvg::Picture::gen();
result = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false);
result = picture->load(gl_state.xml_code.get_data(), gl_state.xml_code.length(), "svg+xml", false);
if (result != tvg::Result::Success) {
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph metrics).");
}
@ -237,7 +239,7 @@ FT_Error tvg_svg_in_ot_render(FT_GlyphSlot p_slot, FT_Pointer *p_state) {
ERR_FAIL_COND_V_MSG(!gl_state.ready, FT_Err_Invalid_SVG_Document, "SVG glyph not ready.");
std::unique_ptr<tvg::Picture> picture = tvg::Picture::gen();
tvg::Result res = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false);
tvg::Result res = picture->load(gl_state.xml_code.get_data(), gl_state.xml_code.length(), "svg+xml", false);
if (res != tvg::Result::Success) {
ERR_FAIL_V_MSG(FT_Err_Invalid_SVG_Document, "Failed to load SVG document (glyph rendering).");
}

View File

@ -65,7 +65,7 @@ struct GL_State {
float y = 0;
float w = 0;
float h = 0;
String xml_code;
CharString xml_code;
tvg::Matrix m;
};

View File

@ -33,7 +33,7 @@
// See https://w3c.github.io/uievents-code/#code-value-tables
Key dom_code2godot_scancode(EM_UTF8 const p_code[32], EM_UTF8 const p_key[32], bool p_physical) {
#define DOM2GODOT(p_str, p_godot_code) \
if (memcmp((const void *)p_str, (void *)(p_physical ? p_key : p_code), strlen(p_str) + 1) == 0) { \
if (memcmp((const void *)p_str, (void *)(p_physical ? p_code : p_key), strlen(p_str) + 1) == 0) { \
return Key::p_godot_code; \
}

View File

@ -264,15 +264,15 @@ BitField<MouseButtonMask> DisplayServerWindows::mouse_get_button_state() const {
void DisplayServerWindows::clipboard_set(const String &p_text) {
_THREAD_SAFE_METHOD_
if (!windows.has(last_focused_window)) {
return; // No focused window?
if (!windows.has(MAIN_WINDOW_ID)) {
return;
}
// Convert LF line endings to CRLF in clipboard content.
// Otherwise, line endings won't be visible when pasted in other software.
String text = p_text.replace("\r\n", "\n").replace("\n", "\r\n"); // Avoid \r\r\n.
if (!OpenClipboard(windows[last_focused_window].hWnd)) {
if (!OpenClipboard(windows[MAIN_WINDOW_ID].hWnd)) {
ERR_FAIL_MSG("Unable to open clipboard.");
}
EmptyClipboard();
@ -305,12 +305,12 @@ void DisplayServerWindows::clipboard_set(const String &p_text) {
String DisplayServerWindows::clipboard_get() const {
_THREAD_SAFE_METHOD_
if (!windows.has(last_focused_window)) {
return String(); // No focused window?
if (!windows.has(MAIN_WINDOW_ID)) {
return String();
}
String ret;
if (!OpenClipboard(windows[last_focused_window].hWnd)) {
if (!OpenClipboard(windows[MAIN_WINDOW_ID].hWnd)) {
ERR_FAIL_V_MSG("", "Unable to open clipboard.");
}

View File

@ -516,11 +516,13 @@ void JoypadWindows::joypad_vibration_stop_xinput(int p_device, uint64_t p_timest
void JoypadWindows::load_xinput() {
xinput_get_state = &_xinput_get_state;
xinput_set_state = &_xinput_set_state;
bool legacy_xinput = false;
xinput_dll = LoadLibrary("XInput1_4.dll");
if (!xinput_dll) {
xinput_dll = LoadLibrary("XInput1_3.dll");
if (!xinput_dll) {
xinput_dll = LoadLibrary("XInput9_1_0.dll");
legacy_xinput = true;
}
}
@ -529,7 +531,9 @@ void JoypadWindows::load_xinput() {
return;
}
XInputGetState_t func = (XInputGetState_t)GetProcAddress((HMODULE)xinput_dll, "XInputGetState");
// (LPCSTR)100 is the magic number to get XInputGetStateEx, which also provides the state for the guide button
LPCSTR get_state_func_name = legacy_xinput ? "XInputGetState" : (LPCSTR)100;
XInputGetState_t func = (XInputGetState_t)GetProcAddress((HMODULE)xinput_dll, get_state_func_name);
XInputSetState_t set_func = (XInputSetState_t)GetProcAddress((HMODULE)xinput_dll, "XInputSetState");
if (!func || !set_func) {
unload_xinput();

View File

@ -68,7 +68,8 @@ void AudioStreamPlayer2D::_notification(int p_what) {
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
// Update anything related to position first, if possible of course.
if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count())) {
if (setplay.get() > 0 || (active.is_set() && last_mix_count != AudioServer::get_singleton()->get_mix_count()) || force_update_panning) {
force_update_panning = false;
_update_panning();
}
@ -109,6 +110,7 @@ void AudioStreamPlayer2D::_notification(int p_what) {
}
}
// Interacts with PhysicsServer2D, so can only be called during _physics_process
StringName AudioStreamPlayer2D::_get_actual_bus() {
Vector2 global_pos = get_global_position();
@ -117,6 +119,7 @@ StringName AudioStreamPlayer2D::_get_actual_bus() {
ERR_FAIL_COND_V(world_2d.is_null(), SNAME("Master"));
PhysicsDirectSpaceState2D *space_state = PhysicsServer2D::get_singleton()->space_get_direct_state(world_2d->get_space());
ERR_FAIL_COND_V(space_state == nullptr, SNAME("Master"));
PhysicsDirectSpaceState2D::ShapeResult sr[MAX_INTERSECT_AREAS];
PhysicsDirectSpaceState2D::PointParameters point_params;
@ -142,6 +145,7 @@ StringName AudioStreamPlayer2D::_get_actual_bus() {
return default_bus;
}
// Interacts with PhysicsServer2D, so can only be called during _physics_process
void AudioStreamPlayer2D::_update_panning() {
if (!active.is_set() || stream.is_null()) {
return;

View File

@ -61,6 +61,7 @@ private:
Vector<AudioFrame> volume_vector;
uint64_t last_mix_count = -1;
bool force_update_panning = false;
float volume_db = 0.0;
float pitch_scale = 1.0;
@ -75,7 +76,7 @@ private:
void _update_panning();
void _bus_layout_changed();
static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer2D *>(self)->_update_panning(); }
static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer2D *>(self)->force_update_panning = true; }
uint32_t area_mask = 1;

View File

@ -71,6 +71,12 @@ void NavigationAgent2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationAgent2D::set_navigation_layer_value);
ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationAgent2D::get_navigation_layer_value);
ClassDB::bind_method(D_METHOD("set_pathfinding_algorithm", "pathfinding_algorithm"), &NavigationAgent2D::set_pathfinding_algorithm);
ClassDB::bind_method(D_METHOD("get_pathfinding_algorithm"), &NavigationAgent2D::get_pathfinding_algorithm);
ClassDB::bind_method(D_METHOD("set_path_postprocessing", "path_postprocessing"), &NavigationAgent2D::set_path_postprocessing);
ClassDB::bind_method(D_METHOD("get_path_postprocessing"), &NavigationAgent2D::get_path_postprocessing);
ClassDB::bind_method(D_METHOD("set_path_metadata_flags", "flags"), &NavigationAgent2D::set_path_metadata_flags);
ClassDB::bind_method(D_METHOD("get_path_metadata_flags"), &NavigationAgent2D::get_path_metadata_flags);
@ -99,6 +105,8 @@ void NavigationAgent2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "target_desired_distance", PROPERTY_HINT_RANGE, "0.1,1000,0.01,or_greater,suffix:px"), "set_target_desired_distance", "get_target_desired_distance");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "10,1000,1,or_greater,suffix:px"), "set_path_max_distance", "get_path_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered"), "set_path_postprocessing", "get_path_postprocessing");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_path_metadata_flags", "get_path_metadata_flags");
ADD_GROUP("Avoidance", "");
@ -328,6 +336,26 @@ bool NavigationAgent2D::get_navigation_layer_value(int p_layer_number) const {
return get_navigation_layers() & (1 << (p_layer_number - 1));
}
void NavigationAgent2D::set_pathfinding_algorithm(const NavigationPathQueryParameters2D::PathfindingAlgorithm p_pathfinding_algorithm) {
if (pathfinding_algorithm == p_pathfinding_algorithm) {
return;
}
pathfinding_algorithm = p_pathfinding_algorithm;
navigation_query->set_pathfinding_algorithm(pathfinding_algorithm);
}
void NavigationAgent2D::set_path_postprocessing(const NavigationPathQueryParameters2D::PathPostProcessing p_path_postprocessing) {
if (path_postprocessing == p_path_postprocessing) {
return;
}
path_postprocessing = p_path_postprocessing;
navigation_query->set_path_postprocessing(path_postprocessing);
}
void NavigationAgent2D::set_path_metadata_flags(BitField<NavigationPathQueryParameters2D::PathMetadataFlags> p_path_metadata_flags) {
if (path_metadata_flags == p_path_metadata_flags) {
return;

View File

@ -48,6 +48,8 @@ class NavigationAgent2D : public Node {
bool avoidance_enabled = false;
uint32_t navigation_layers = 1;
NavigationPathQueryParameters2D::PathfindingAlgorithm pathfinding_algorithm = NavigationPathQueryParameters2D::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
NavigationPathQueryParameters2D::PathPostProcessing path_postprocessing = NavigationPathQueryParameters2D::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
BitField<NavigationPathQueryParameters2D::PathMetadataFlags> path_metadata_flags = NavigationPathQueryParameters2D::PathMetadataFlags::PATH_METADATA_INCLUDE_ALL;
real_t path_desired_distance = 20.0;
@ -112,6 +114,16 @@ public:
void set_navigation_layer_value(int p_layer_number, bool p_value);
bool get_navigation_layer_value(int p_layer_number) const;
void set_pathfinding_algorithm(const NavigationPathQueryParameters2D::PathfindingAlgorithm p_pathfinding_algorithm);
NavigationPathQueryParameters2D::PathfindingAlgorithm get_pathfinding_algorithm() const {
return pathfinding_algorithm;
}
void set_path_postprocessing(const NavigationPathQueryParameters2D::PathPostProcessing p_path_postprocessing);
NavigationPathQueryParameters2D::PathPostProcessing get_path_postprocessing() const {
return path_postprocessing;
}
void set_path_metadata_flags(BitField<NavigationPathQueryParameters2D::PathMetadataFlags> p_flags);
BitField<NavigationPathQueryParameters2D::PathMetadataFlags> get_path_metadata_flags() const {
return path_metadata_flags;

View File

@ -196,13 +196,20 @@ void NavigationObstacle2D::set_agent_parent(Node *p_agent_parent) {
} else {
NavigationServer2D::get_singleton()->agent_set_map(get_rid(), parent_node2d->get_world_2d()->get_navigation_map());
}
// Need to register Callback as obstacle requires a valid Callback to be added to avoidance simulation.
NavigationServer2D::get_singleton()->agent_set_callback(get_rid(), callable_mp(this, &NavigationObstacle2D::_avoidance_done));
reevaluate_agent_radius();
} else {
parent_node2d = nullptr;
NavigationServer2D::get_singleton()->agent_set_map(get_rid(), RID());
NavigationServer2D::get_singleton()->agent_set_callback(agent, Callable());
}
}
void NavigationObstacle2D::_avoidance_done(Vector3 p_new_velocity) {
// Dummy function as obstacle requires a valid Callback to be added to avoidance simulation.
}
void NavigationObstacle2D::set_navigation_map(RID p_navigation_map) {
if (map_override == p_navigation_map) {
return;

View File

@ -75,6 +75,8 @@ public:
PackedStringArray get_configuration_warnings() const override;
void _avoidance_done(Vector3 p_new_velocity); // Dummy
private:
void initialize_agent();
void reevaluate_agent_radius();

View File

@ -60,54 +60,51 @@ void RemoteTransform2D::_update_remote() {
return;
}
if (!(update_remote_position || update_remote_rotation || update_remote_scale)) {
return; // The transform data of the RemoteTransform2D is not used at all.
}
//todo make faster
if (use_global_coordinates) {
if (update_remote_position && update_remote_rotation && update_remote_scale) {
n->set_global_transform(get_global_transform());
} else {
Transform2D n_trans = n->get_global_transform();
Transform2D our_trans = get_global_transform();
Vector2 n_scale = n->get_scale();
if (!update_remote_position) {
our_trans.set_origin(n_trans.get_origin());
}
if (!update_remote_rotation) {
our_trans.set_rotation(n_trans.get_rotation());
}
n->set_global_transform(our_trans);
if (update_remote_scale) {
n->set_scale(get_global_scale());
} else {
n->set_scale(n_scale);
}
return;
}
Transform2D n_trans = n->get_global_transform();
Transform2D our_trans = get_global_transform();
// There are more steps in the operation of set_rotation, so avoid calling it.
Transform2D trans = update_remote_rotation ? our_trans : n_trans;
if (update_remote_rotation ^ update_remote_position) {
trans.set_origin(update_remote_position ? our_trans.get_origin() : n_trans.get_origin());
}
if (update_remote_rotation ^ update_remote_scale) {
trans.set_scale(update_remote_scale ? our_trans.get_scale() : n_trans.get_scale());
}
n->set_global_transform(trans);
} else {
if (update_remote_position && update_remote_rotation && update_remote_scale) {
n->set_transform(get_transform());
} else {
Transform2D n_trans = n->get_transform();
Transform2D our_trans = get_transform();
Vector2 n_scale = n->get_scale();
if (!update_remote_position) {
our_trans.set_origin(n_trans.get_origin());
}
if (!update_remote_rotation) {
our_trans.set_rotation(n_trans.get_rotation());
}
n->set_transform(our_trans);
if (update_remote_scale) {
n->set_scale(get_scale());
} else {
n->set_scale(n_scale);
}
return;
}
Transform2D n_trans = n->get_transform();
Transform2D our_trans = get_transform();
// There are more steps in the operation of set_rotation, so avoid calling it.
Transform2D trans = update_remote_rotation ? our_trans : n_trans;
if (update_remote_rotation ^ update_remote_position) {
trans.set_origin(update_remote_position ? our_trans.get_origin() : n_trans.get_origin());
}
if (update_remote_rotation ^ update_remote_scale) {
trans.set_scale(update_remote_scale ? our_trans.get_scale() : n_trans.get_scale());
}
n->set_transform(trans);
}
}

View File

@ -75,6 +75,12 @@ void NavigationAgent3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_navigation_layer_value", "layer_number", "value"), &NavigationAgent3D::set_navigation_layer_value);
ClassDB::bind_method(D_METHOD("get_navigation_layer_value", "layer_number"), &NavigationAgent3D::get_navigation_layer_value);
ClassDB::bind_method(D_METHOD("set_pathfinding_algorithm", "pathfinding_algorithm"), &NavigationAgent3D::set_pathfinding_algorithm);
ClassDB::bind_method(D_METHOD("get_pathfinding_algorithm"), &NavigationAgent3D::get_pathfinding_algorithm);
ClassDB::bind_method(D_METHOD("set_path_postprocessing", "path_postprocessing"), &NavigationAgent3D::set_path_postprocessing);
ClassDB::bind_method(D_METHOD("get_path_postprocessing"), &NavigationAgent3D::get_path_postprocessing);
ClassDB::bind_method(D_METHOD("set_path_metadata_flags", "flags"), &NavigationAgent3D::set_path_metadata_flags);
ClassDB::bind_method(D_METHOD("get_path_metadata_flags"), &NavigationAgent3D::get_path_metadata_flags);
@ -104,6 +110,8 @@ void NavigationAgent3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "agent_height_offset", PROPERTY_HINT_RANGE, "-100.0,100,0.01,or_greater,suffix:m"), "set_agent_height_offset", "get_agent_height_offset");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_max_distance", PROPERTY_HINT_RANGE, "0.01,100,0.1,or_greater,suffix:m"), "set_path_max_distance", "get_path_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_navigation_layers", "get_navigation_layers");
ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered"), "set_path_postprocessing", "get_path_postprocessing");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_path_metadata_flags", "get_path_metadata_flags");
ADD_GROUP("Avoidance", "");
@ -335,6 +343,26 @@ bool NavigationAgent3D::get_navigation_layer_value(int p_layer_number) const {
return get_navigation_layers() & (1 << (p_layer_number - 1));
}
void NavigationAgent3D::set_pathfinding_algorithm(const NavigationPathQueryParameters3D::PathfindingAlgorithm p_pathfinding_algorithm) {
if (pathfinding_algorithm == p_pathfinding_algorithm) {
return;
}
pathfinding_algorithm = p_pathfinding_algorithm;
navigation_query->set_pathfinding_algorithm(pathfinding_algorithm);
}
void NavigationAgent3D::set_path_postprocessing(const NavigationPathQueryParameters3D::PathPostProcessing p_path_postprocessing) {
if (path_postprocessing == p_path_postprocessing) {
return;
}
path_postprocessing = p_path_postprocessing;
navigation_query->set_path_postprocessing(path_postprocessing);
}
void NavigationAgent3D::set_path_metadata_flags(BitField<NavigationPathQueryParameters3D::PathMetadataFlags> p_path_metadata_flags) {
if (path_metadata_flags == p_path_metadata_flags) {
return;

View File

@ -48,6 +48,8 @@ class NavigationAgent3D : public Node {
bool avoidance_enabled = false;
uint32_t navigation_layers = 1;
NavigationPathQueryParameters3D::PathfindingAlgorithm pathfinding_algorithm = NavigationPathQueryParameters3D::PathfindingAlgorithm::PATHFINDING_ALGORITHM_ASTAR;
NavigationPathQueryParameters3D::PathPostProcessing path_postprocessing = NavigationPathQueryParameters3D::PathPostProcessing::PATH_POSTPROCESSING_CORRIDORFUNNEL;
BitField<NavigationPathQueryParameters3D::PathMetadataFlags> path_metadata_flags = NavigationPathQueryParameters3D::PathMetadataFlags::PATH_METADATA_INCLUDE_ALL;
real_t path_desired_distance = 1.0;
@ -116,6 +118,16 @@ public:
void set_navigation_layer_value(int p_layer_number, bool p_value);
bool get_navigation_layer_value(int p_layer_number) const;
void set_pathfinding_algorithm(const NavigationPathQueryParameters3D::PathfindingAlgorithm p_pathfinding_algorithm);
NavigationPathQueryParameters3D::PathfindingAlgorithm get_pathfinding_algorithm() const {
return pathfinding_algorithm;
}
void set_path_postprocessing(const NavigationPathQueryParameters3D::PathPostProcessing p_path_postprocessing);
NavigationPathQueryParameters3D::PathPostProcessing get_path_postprocessing() const {
return path_postprocessing;
}
void set_path_metadata_flags(BitField<NavigationPathQueryParameters3D::PathMetadataFlags> p_flags);
BitField<NavigationPathQueryParameters3D::PathMetadataFlags> get_path_metadata_flags() const {
return path_metadata_flags;

View File

@ -203,13 +203,20 @@ void NavigationObstacle3D::set_agent_parent(Node *p_agent_parent) {
} else {
NavigationServer3D::get_singleton()->agent_set_map(get_rid(), parent_node3d->get_world_3d()->get_navigation_map());
}
// Need to register Callback as obstacle requires a valid Callback to be added to avoidance simulation.
NavigationServer3D::get_singleton()->agent_set_callback(get_rid(), callable_mp(this, &NavigationObstacle3D::_avoidance_done));
reevaluate_agent_radius();
} else {
parent_node3d = nullptr;
NavigationServer3D::get_singleton()->agent_set_map(get_rid(), RID());
NavigationServer3D::get_singleton()->agent_set_callback(agent, Callable());
}
}
void NavigationObstacle3D::_avoidance_done(Vector3 p_new_velocity) {
// Dummy function as obstacle requires a valid Callback to be added to avoidance simulation.
}
void NavigationObstacle3D::set_navigation_map(RID p_navigation_map) {
if (map_override == p_navigation_map) {
return;

View File

@ -74,6 +74,8 @@ public:
PackedStringArray get_configuration_warnings() const override;
void _avoidance_done(Vector3 p_new_velocity); // Dummy
private:
void initialize_agent();
void reevaluate_agent_radius();

View File

@ -533,7 +533,6 @@ void GraphEdit::_notification(int p_what) {
void GraphEdit::_update_comment_enclosed_nodes_list(GraphNode *p_node, HashMap<StringName, Vector<GraphNode *>> &p_comment_enclosed_nodes) {
Rect2 comment_node_rect = p_node->get_rect();
comment_node_rect.size *= zoom;
Vector<GraphNode *> enclosed_nodes;
for (int i = 0; i < get_child_count(); i++) {
@ -543,7 +542,6 @@ void GraphEdit::_update_comment_enclosed_nodes_list(GraphNode *p_node, HashMap<S
}
Rect2 node_rect = gn->get_rect();
node_rect.size *= zoom;
bool included = comment_node_rect.encloses(node_rect);
if (included) {
@ -806,7 +804,6 @@ bool GraphEdit::_check_clickable_control(Control *p_control, const Vector2 &mpos
}
Rect2 control_rect = p_control->get_rect();
control_rect.size *= zoom;
control_rect.position *= zoom;
control_rect.position += p_offset;
@ -873,7 +870,6 @@ bool GraphEdit::is_in_port_hotzone(const Vector2 &p_pos, const Vector2 &p_mouse_
continue;
}
Rect2 child_rect = child->get_rect();
child_rect.size *= zoom;
if (child_rect.has_point(p_mouse_pos * zoom)) {
for (int j = 0; j < child->get_child_count(); j++) {
@ -1169,7 +1165,6 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
Rect2 r = gn->get_rect();
r.size *= zoom;
bool in_box = r.intersects(box_selecting_rect);
if (in_box) {
@ -1215,7 +1210,6 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
if (gn) {
Rect2 r = gn->get_rect();
r.size *= zoom;
if (r.has_point(mb->get_position())) {
gn->set_selected(false);
}

View File

@ -664,7 +664,7 @@ Size2 GraphNode::get_minimum_size() const {
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
if (!c) {
if (!c || !c->is_visible()) {
continue;
}
if (c->is_set_as_top_level()) {

View File

@ -31,15 +31,10 @@
#include "texture_progress_bar.h"
#include "core/config/engine.h"
#include "core/core_string_names.h"
void TextureProgressBar::set_under_texture(const Ref<Texture2D> &p_texture) {
if (under == p_texture) {
return;
}
under = p_texture;
queue_redraw();
update_minimum_size();
_set_texture(&under, p_texture);
}
Ref<Texture2D> TextureProgressBar::get_under_texture() const {
@ -47,15 +42,7 @@ Ref<Texture2D> TextureProgressBar::get_under_texture() const {
}
void TextureProgressBar::set_over_texture(const Ref<Texture2D> &p_texture) {
if (over == p_texture) {
return;
}
over = p_texture;
queue_redraw();
if (under.is_null()) {
update_minimum_size();
}
_set_texture(&over, p_texture);
}
Ref<Texture2D> TextureProgressBar::get_over_texture() const {
@ -108,13 +95,7 @@ Size2 TextureProgressBar::get_minimum_size() const {
}
void TextureProgressBar::set_progress_texture(const Ref<Texture2D> &p_texture) {
if (progress == p_texture) {
return;
}
progress = p_texture;
queue_redraw();
update_minimum_size();
_set_texture(&progress, p_texture);
}
Ref<Texture2D> TextureProgressBar::get_progress_texture() const {
@ -173,6 +154,28 @@ Color TextureProgressBar::get_tint_over() const {
return tint_over;
}
void TextureProgressBar::_set_texture(Ref<Texture2D> *p_destination, const Ref<Texture2D> &p_texture) {
DEV_ASSERT(p_destination);
Ref<Texture2D> &destination = *p_destination;
if (destination == p_texture) {
return;
}
if (destination.is_valid()) {
destination->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TextureProgressBar::_texture_changed));
}
destination = p_texture;
if (destination.is_valid()) {
// Pass `CONNECT_REFERENCE_COUNTED` to avoid early disconnect in case the same texture is assigned to different "slots".
destination->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TextureProgressBar::_texture_changed), CONNECT_REFERENCE_COUNTED);
}
_texture_changed();
}
void TextureProgressBar::_texture_changed() {
update_minimum_size();
queue_redraw();
}
Point2 TextureProgressBar::unit_val_to_uv(float val) {
if (progress.is_null()) {
return Point2();

View File

@ -113,6 +113,8 @@ private:
Color tint_progress = Color(1, 1, 1);
Color tint_over = Color(1, 1, 1);
void _set_texture(Ref<Texture2D> *p_destination, const Ref<Texture2D> &p_texture);
void _texture_changed();
Point2 unit_val_to_uv(float val);
Point2 get_relative_center();
void draw_nine_patch_stretched(const Ref<Texture2D> &p_texture, FillMode p_mode, double p_ratio, const Color &p_modulate);

View File

@ -130,7 +130,12 @@ bool ViewPanner::gui_input(const Ref<InputEvent> &p_event, Rect2 p_canvas_rect)
Ref<InputEventScreenDrag> screen_drag = p_event;
if (screen_drag.is_valid()) {
callback_helper(pan_callback, varray(screen_drag->get_relative(), p_event));
if (Input::get_singleton()->is_emulating_mouse_from_touch() || Input::get_singleton()->is_emulating_touch_from_mouse()) {
// This set of events also generates/is generated by
// InputEventMouseButton/InputEventMouseMotion events which will be processed instead.
} else {
callback_helper(pan_callback, varray(screen_drag->get_relative(), p_event));
}
}
Ref<InputEventKey> k = p_event;

View File

@ -1408,6 +1408,10 @@ SceneTree::SceneTree() {
root->set_name("root");
root->set_title(GLOBAL_GET("application/config/name"));
if (Engine::get_singleton()->is_editor_hint()) {
root->set_wrap_controls(true);
}
#ifndef _3D_DISABLED
if (!root->get_world_3d().is_valid()) {
root->set_world_3d(Ref<World3D>(memnew(World3D)));

View File

@ -38,11 +38,41 @@ bool ConvexPolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, dou
return Geometry2D::is_point_in_polygon(p_point, points);
}
#ifdef DEBUG_ENABLED
// Check if point p3 is to the left of [p1, p2] segment or on it.
bool left_test(const Vector2 &p1, const Vector2 &p2, const Vector2 &p3) {
Vector2 p12 = p2 - p1;
Vector2 p13 = p3 - p1;
// If the value of the cross product is positive or zero; p3 is to the left or on the segment, respectively.
return p12.cross(p13) >= 0;
}
bool is_convex(const Vector<Vector2> &p_points) {
// Pre-condition: Polygon is in counter-clockwise order.
int polygon_size = p_points.size();
for (int i = 0; i < polygon_size && polygon_size > 3; i++) {
int j = (i + 1) % polygon_size;
int k = (j + 1) % polygon_size;
// If any consecutive three points fail left-test, then there is a concavity.
if (!left_test(p_points[i], p_points[j], p_points[k])) {
return false;
}
}
return true;
}
#endif
void ConvexPolygonShape2D::_update_shape() {
Vector<Vector2> final_points = points;
if (Geometry2D::is_polygon_clockwise(final_points)) { //needs to be counter clockwise
final_points.reverse();
}
#ifdef DEBUG_ENABLED
if (!is_convex(final_points)) {
WARN_PRINT("Concave polygon is assigned to ConvexPolygonShape2D.");
}
#endif
PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), final_points);
emit_changed();
}

View File

@ -233,27 +233,27 @@ void TextParagraph::_shape_lines() {
}
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
for (int i = 0; i < (int)lines_rid.size(); i++) {
float line_w = (i <= dropcap_lines) ? (width - h_offset) : width;
if (i < visible_lines - 1 || (int)lines_rid.size() == 1) {
TS->shaped_text_fit_to_width(lines_rid[i], width, jst_flags);
TS->shaped_text_fit_to_width(lines_rid[i], line_w, jst_flags);
} else if (i == (visible_lines - 1)) {
TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], line_w, overrun_flags);
}
}
} else if (lines_hidden) {
TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], (visible_lines - 1 <= dropcap_lines) ? (width - h_offset) : width, overrun_flags);
}
} else {
// Autowrap disabled.
for (const RID &line_rid : lines_rid) {
for (int i = 0; i < (int)lines_rid.size(); i++) {
float line_w = (i <= dropcap_lines) ? (width - h_offset) : width;
if (alignment == HORIZONTAL_ALIGNMENT_FILL) {
TS->shaped_text_fit_to_width(line_rid, width, jst_flags);
TS->shaped_text_fit_to_width(lines_rid[i], line_w, jst_flags);
overrun_flags.set_flag(TextServer::OVERRUN_JUSTIFICATION_AWARE);
TS->shaped_text_overrun_trim_to_width(line_rid, width, overrun_flags);
TS->shaped_text_fit_to_width(line_rid, width, jst_flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
TS->shaped_text_overrun_trim_to_width(lines_rid[i], line_w, overrun_flags);
TS->shaped_text_fit_to_width(lines_rid[i], line_w, jst_flags | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
} else {
TS->shaped_text_overrun_trim_to_width(line_rid, width, overrun_flags);
TS->shaped_text_overrun_trim_to_width(lines_rid[i], line_w, overrun_flags);
}
}
}

View File

@ -893,7 +893,7 @@ PhysicsServer2D::PhysicsServer2D() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "physics/2d/solver/solver_iterations", PROPERTY_HINT_RANGE, "1,32,1,or_greater"), 16);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/2d/solver/contact_recycle_radius", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater"), 1.0);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/2d/solver/contact_max_separation", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater"), 1.5);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/2d/solver/contact_max_allowed_penetration", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater"), 0.3);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/2d/solver/contact_max_allowed_penetration", PROPERTY_HINT_RANGE, "0.01,10,0.01,or_greater"), 0.3);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/2d/solver/default_contact_bias", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.8);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/2d/solver/default_constraint_bias", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.2);
}

View File

@ -1059,9 +1059,9 @@ PhysicsServer3D::PhysicsServer3D() {
GLOBAL_DEF("physics/3d/sleep_threshold_angular", Math::deg_to_rad(8.0));
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/3d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater"), 0.5);
GLOBAL_DEF(PropertyInfo(Variant::INT, "physics/3d/solver/solver_iterations", PROPERTY_HINT_RANGE, "1,32,1,or_greater"), 16);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/3d/solver/contact_recycle_radius", PROPERTY_HINT_RANGE, "0,0.1,0.01,or_greater"), 0.01);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/3d/solver/contact_max_separation", PROPERTY_HINT_RANGE, "0,0.1,0.01,or_greater"), 0.05);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/3d/solver/contact_max_allowed_penetration", PROPERTY_HINT_RANGE, "0,0.1,0.01,or_greater"), 0.01);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/3d/solver/contact_recycle_radius", PROPERTY_HINT_RANGE, "0,0.1,0.001,or_greater"), 0.01);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/3d/solver/contact_max_separation", PROPERTY_HINT_RANGE, "0,0.1,0.001,or_greater"), 0.05);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/3d/solver/contact_max_allowed_penetration", PROPERTY_HINT_RANGE, "0.001,0.1,0.001,or_greater"), 0.01);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "physics/3d/solver/default_contact_bias", PROPERTY_HINT_RANGE, "0,1,0.01"), 0.8);
}

View File

@ -263,9 +263,8 @@ void main() {
// Schlick term.
float metallic = texelFetch(source_metallic, ssC << 1, 0).w;
float f0 = mix(0.04, 1.0, metallic); // Assume a "specular" amount of 0.5
normal.y = -normal.y;
float m = clamp(1.0 - dot(normalize(normal), -view_dir), 0.0, 1.0);
float f0 = mix(0.04, 0.37, metallic); // The default value of R0 is 0.04 and the maximum value is considered to be Germanium with R0 value of 0.37
float m = clamp(1.0 - dot(normal, -view_dir), 0.0, 1.0);
float m2 = m * m;
m = m2 * m2 * m; // pow(m,5)
final_color.a *= f0 + (1.0 - f0) * m; // Fresnel Schlick term.

View File

@ -686,7 +686,7 @@ instead of `miniz.h` as an external dependency.
## thorvg
- Upstream: https://github.com/Samsung/thorvg
- Version: 0.8.3 (a0fcf51f80a75f63a066df085f60cdaf715188b6, 2022)
- Version: 0.8.4 (b0b7f207c6235691d694fc3f76e0b96e4858e606, 2023)
- License: MIT
Files extracted from upstream source:

View File

@ -4,7 +4,7 @@ Junsu Choi <jsuya.choi@samsung.com>
Pranay Samanta <pranay.ks@samsung.com>
Mateusz Palkowski <m.palkowski@samsung.com>
Subhransu Mohanty <sub.mohanty@samsung.com>
Mira Grudzinska <m.grudzinska@samsung.com>
Mira Grudzinska <veleveta@gmail.com>
Michal Szczecinski <m.szczecinsk@partner.samsung.com>
Shinwoo Kim <cinoo.kim@samsung.com>
Piotr Kalota <p.kalota@samsung.com>

View File

@ -13,5 +13,5 @@
#define THORVG_JPG_LOADER_SUPPORT 1
#define THORVG_VERSION_STRING "0.8.3"
#define THORVG_VERSION_STRING "0.8.4"
#endif

View File

@ -335,6 +335,20 @@ public:
*/
CompositeMethod composite(const Paint** target) const noexcept;
/**
* @brief Gets the composition source object and the composition method.
*
* @param[out] source The paint of the composition source object.
* @param[out] method The method used to composite the source object with the target.
*
* @return Result::Success when the paint object used as a composition target, Result::InsufficientCondition otherwise.
*
* @warning Please do not use it, this API is not official one. It could be modified in the next version.
*
* @BETA_API
*/
Result composite(const Paint** source, CompositeMethod* method) const noexcept;
/**
* @brief Return the unique id value of the paint instance.
*

View File

@ -76,7 +76,9 @@ struct SwShapeTask : SwTask
void run(unsigned tid) override
{
if (opacity == 0) return; //Invisible
auto compMethod = CompositeMethod::None;
auto usedAsClip = (sdata->composite(nullptr, &compMethod) == Result::Success) && (compMethod == CompositeMethod::ClipPath);
if (opacity == 0 && !usedAsClip) return; //Invisible
uint8_t strokeAlpha = 0;
auto visibleStroke = false;
@ -98,7 +100,7 @@ struct SwShapeTask : SwTask
sdata->fillColor(nullptr, nullptr, nullptr, &alpha);
alpha = static_cast<uint8_t>(static_cast<uint32_t>(alpha) * opacity / 255);
visibleFill = (alpha > 0 || sdata->fill());
if (visibleFill || visibleStroke) {
if (visibleFill || visibleStroke || usedAsClip) {
shapeReset(&shape);
if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid, clips.count > 0 ? true : false)) goto err;
}
@ -110,7 +112,7 @@ struct SwShapeTask : SwTask
//Fill
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform | RenderUpdateFlag::Color)) {
if (visibleFill) {
if (visibleFill || usedAsClip) {
/* We assume that if stroke width is bigger than 2,
shape outline below stroke could be full covered by stroke drawing.
Thus it turns off antialising in that condition.
@ -291,7 +293,7 @@ bool SwRenderer::viewport(const RenderRegion& vp)
}
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs)
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t colorSpace)
{
if (!buffer || stride == 0 || w == 0 || h == 0 || w > stride) return false;
@ -301,7 +303,7 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
surface->stride = stride;
surface->w = w;
surface->h = h;
surface->cs = cs;
surface->cs = colorSpace;
vport.x = vport.y = 0;
vport.w = surface->w;
@ -644,6 +646,13 @@ SwRenderer::SwRenderer():mpool(globalMpool)
}
uint32_t SwRenderer::colorSpace()
{
if (surface) return surface->cs;
return tvg::SwCanvas::ARGB8888;
}
bool SwRenderer::init(uint32_t threads)
{
if ((initEngineCnt++) > 0) return true;

View File

@ -48,7 +48,7 @@ public:
bool clear() override;
bool sync() override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t colorSpace);
bool mempool(bool shared);
Compositor* target(const RenderRegion& region) override;
@ -56,6 +56,8 @@ public:
bool endComposite(Compositor* cmp) override;
void clearCompositors();
uint32_t colorSpace() override;
static SwRenderer* gen();
static bool init(uint32_t threads);
static int32_t init();

View File

@ -72,7 +72,7 @@ Accessor::~Accessor()
}
Accessor::Accessor()
Accessor::Accessor() : pImpl(nullptr)
{
}

View File

@ -36,6 +36,7 @@ public:
float vw = 0;
float vh = 0;
float w = 0, h = 0; //default image size
uint32_t colorSpace = SwCanvas::ARGB8888;
virtual ~LoadModule() {}
@ -48,7 +49,7 @@ public:
virtual bool read() = 0;
virtual bool close() = 0;
virtual unique_ptr<Surface> bitmap() { return nullptr; }
virtual unique_ptr<Surface> bitmap(uint32_t colorSpace) { return nullptr; }
virtual unique_ptr<Paint> paint() { return nullptr; }
};

View File

@ -53,6 +53,12 @@ static inline bool mathRightAngle(const Matrix* m)
}
static inline bool mathSkewed(const Matrix* m)
{
return (fabsf(m->e21 + m->e12) > FLT_EPSILON);
}
static inline bool mathIdentity(const Matrix* m)
{
if (!mathEqual(m->e11, 1.0f) || !mathZero(m->e12) || !mathZero(m->e13) ||

View File

@ -38,9 +38,9 @@ static bool _compFastTrack(Paint* cmpTarget, const RenderTransform* pTransform,
if (rTransform) rTransform->update();
//No rotational.
if (pTransform && !mathRightAngle(&pTransform->m)) return false;
if (rTransform && !mathRightAngle(&rTransform->m)) return false;
//No rotation and no skewing
if (pTransform && (!mathRightAngle(&pTransform->m) || mathSkewed(&pTransform->m))) return false;
if (rTransform && (!mathRightAngle(&rTransform->m) || mathSkewed(&rTransform->m))) return false;
//Perpendicular Rectangle?
auto pt1 = pts + 0;
@ -384,6 +384,19 @@ CompositeMethod Paint::composite(const Paint** target) const noexcept
}
Result Paint::composite(const Paint** source, CompositeMethod* method) const noexcept
{
if (source) *source = pImpl->compSource;
auto met = (pImpl->compSource && pImpl->compSource->pImpl->compData ?
pImpl->compSource->pImpl->compData->method : CompositeMethod::None);
if (method) *method = met;
if (pImpl->compSource != nullptr && met != CompositeMethod::None)
return Result::Success;
return Result::InsufficientCondition;
}
Result Paint::opacity(uint8_t o) noexcept
{
if (pImpl->opacity == o) return Result::Success;

View File

@ -62,6 +62,7 @@ namespace tvg
StrategyMethod* smethod = nullptr;
RenderTransform* rTransform = nullptr;
Composite* compData = nullptr;
Paint* compSource = nullptr;
uint32_t renderFlag = RenderUpdateFlag::None;
uint32_t ctxFlag = ContextFlag::Invalid;
uint32_t id;
@ -136,6 +137,7 @@ namespace tvg
if (!target && method == CompositeMethod::None) return true;
compData = static_cast<Composite*>(calloc(1, sizeof(Composite)));
}
target->pImpl->compSource = source;
compData->target = target;
compData->source = source;
compData->method = method;

View File

@ -66,6 +66,7 @@ struct Picture::Impl
void* rdata = nullptr; //engine data
float w = 0, h = 0;
bool resizing = false;
uint32_t rendererColorSpace = 0;
~Impl()
{
@ -100,7 +101,7 @@ struct Picture::Impl
}
}
free(surface);
if ((surface = loader->bitmap().release())) {
if ((surface = loader->bitmap(rendererColorSpace).release())) {
loader->close();
return RenderUpdateFlag::Image;
}
@ -124,6 +125,7 @@ struct Picture::Impl
void* update(RenderMethod &renderer, const RenderTransform* pTransform, uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag pFlag)
{
rendererColorSpace = renderer.colorSpace();
auto flag = reload();
if (surface) {

View File

@ -106,6 +106,8 @@ public:
virtual Compositor* target(const RenderRegion& region) = 0;
virtual bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) = 0;
virtual bool endComposite(Compositor* cmp) = 0;
virtual uint32_t colorSpace() = 0;
};
}

View File

@ -25,7 +25,7 @@
/* External Class Implementation */
/************************************************************************/
Scene::Scene() : pImpl(new Impl())
Scene::Scene() : pImpl(new Impl(this))
{
Paint::pImpl->id = TVG_CLASS_ID_SCENE;
Paint::pImpl->method(new PaintMethod<Scene::Impl>(pImpl));

View File

@ -60,6 +60,11 @@ struct Scene::Impl
Array<Paint*> paints;
uint8_t opacity; //for composition
RenderMethod* renderer = nullptr; //keep it for explicit clear
Scene* scene = nullptr;
Impl(Scene* s) : scene(s)
{
}
~Impl()
{
@ -81,8 +86,14 @@ struct Scene::Impl
bool needComposition(uint32_t opacity)
{
if (opacity == 0 || paints.count == 0) return false;
//Masking may require composition (even if opacity == 255)
auto compMethod = scene->composite(nullptr);
if (compMethod != CompositeMethod::None && compMethod != CompositeMethod::ClipPath) return true;
//Half translucent requires intermediate composition.
if (opacity == 255 || opacity == 0) return false;
if (opacity == 255) return false;
//If scene has several children or only scene, it may require composition.
if (paints.count > 1) return true;

View File

@ -42,6 +42,24 @@ static void _premultiply(uint32_t* data, uint32_t w, uint32_t h)
}
static inline uint32_t CHANGE_COLORSPACE(uint32_t c)
{
return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16);
}
static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h)
{
auto buffer = data;
for (uint32_t y = 0; y < h; ++y, buffer += w) {
auto src = buffer;
for (uint32_t x = 0; x < w; ++x, ++src) {
*src = CHANGE_COLORSPACE(*src);
}
}
}
PngLoader::PngLoader()
{
image = static_cast<png_imagep>(calloc(1, sizeof(png_image)));
@ -110,16 +128,21 @@ bool PngLoader::close()
return true;
}
unique_ptr<Surface> PngLoader::bitmap()
unique_ptr<Surface> PngLoader::bitmap(uint32_t colorSpace)
{
if (!content) return nullptr;
if (this->colorSpace != colorSpace) {
this->colorSpace = colorSpace;
_changeColorSpace(content, w, h);
}
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(content);
surface->buffer = content;
surface->stride = w;
surface->w = w;
surface->h = h;
surface->cs = SwCanvas::ARGB8888;
surface->cs = colorSpace;
return unique_ptr<Surface>(surface);
}

View File

@ -36,11 +36,11 @@ public:
bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override;
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
private:
png_imagep image = nullptr;
const uint32_t* content = nullptr;
uint32_t* content = nullptr;
};
#endif //_TVG_PNG_LOADER_H_

View File

@ -28,6 +28,24 @@
/* Internal Class Implementation */
/************************************************************************/
static inline uint32_t CHANGE_COLORSPACE(uint32_t c)
{
return (c & 0xff000000) + ((c & 0x00ff0000)>>16) + (c & 0x0000ff00) + ((c & 0x000000ff)<<16);
}
static void _changeColorSpace(uint32_t* data, uint32_t w, uint32_t h)
{
auto buffer = data;
for (uint32_t y = 0; y < h; ++y, buffer += w) {
auto src = buffer;
for (uint32_t x = 0; x < w; ++x, ++src) {
*src = CHANGE_COLORSPACE(*src);
}
}
}
void JpgLoader::clear()
{
jpgdDelete(decoder);
@ -110,18 +128,22 @@ bool JpgLoader::close()
}
unique_ptr<Surface> JpgLoader::bitmap()
unique_ptr<Surface> JpgLoader::bitmap(uint32_t colorSpace)
{
this->done();
if (!image) return nullptr;
if (this->colorSpace != colorSpace) {
this->colorSpace = colorSpace;
_changeColorSpace(reinterpret_cast<uint32_t*>(image), w, h);
}
auto surface = static_cast<Surface*>(malloc(sizeof(Surface)));
surface->buffer = (uint32_t*)(image);
surface->buffer = reinterpret_cast<uint32_t*>(image);
surface->stride = static_cast<uint32_t>(w);
surface->w = static_cast<uint32_t>(w);
surface->h = static_cast<uint32_t>(h);
surface->cs = SwCanvas::ARGB8888;
surface->cs = colorSpace;
return unique_ptr<Surface>(surface);
}

View File

@ -44,7 +44,7 @@ public:
bool read() override;
bool close() override;
unique_ptr<Surface> bitmap() override;
unique_ptr<Surface> bitmap(uint32_t colorSpace) override;
void run(unsigned tid) override;
};

Some files were not shown because too many files have changed in this diff Show More