summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.pre-commit-config.yaml23
-rw-r--r--SConstruct24
-rw-r--r--core/SCsub12
-rw-r--r--core/core_builders.py12
-rw-r--r--core/extension/SCsub2
-rw-r--r--core/extension/make_wrappers.py2
-rw-r--r--core/input/SCsub1
-rw-r--r--core/math/geometry_2d.h2
-rw-r--r--core/object/class_db.cpp2
-rw-r--r--doc/classes/@GlobalScope.xml3
-rw-r--r--doc/classes/Geometry2D.xml1
-rwxr-xr-xdoc/tools/doc_status.py8
-rwxr-xr-xdoc/tools/make_rst.py11
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h11
-rw-r--r--drivers/gles3/shaders/sky.glsl2
-rw-r--r--editor/SCsub5
-rw-r--r--editor/animation_track_editor.cpp6
-rw-r--r--editor/doc_tools.cpp19
-rw-r--r--editor/editor_builders.py1
-rw-r--r--editor/editor_node.cpp5
-rw-r--r--editor/gui/scene_tree_editor.cpp21
-rw-r--r--editor/icons/SCsub2
-rw-r--r--editor/import/3d/resource_importer_scene.cpp3
-rw-r--r--editor/import/resource_importer_texture.cpp6
-rw-r--r--editor/import_dock.cpp14
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp374
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h20
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp156
-rw-r--r--editor/plugins/node_3d_editor_plugin.h3
-rw-r--r--editor/plugins/script_editor_plugin.cpp24
-rw-r--r--editor/plugins/script_text_editor.cpp11
-rw-r--r--editor/plugins/text_editor.cpp6
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp4
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp19
-rw-r--r--editor/plugins/tiles/tile_map_layer_editor.cpp31
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp4
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp13
-rw-r--r--editor/project_manager/project_list.cpp59
-rw-r--r--editor/project_manager/project_list.h7
-rw-r--r--editor/project_settings_editor.cpp2
-rw-r--r--editor/rename_dialog.cpp1
-rw-r--r--editor/scene_tree_dock.cpp120
-rw-r--r--editor/scene_tree_dock.h3
-rw-r--r--editor/themes/SCsub2
-rw-r--r--gles3_builders.py13
-rw-r--r--glsl_builders.py9
-rw-r--r--methods.py51
-rwxr-xr-xmisc/scripts/install_d3d12_sdk_windows.py4
-rw-r--r--modules/SCsub3
-rw-r--r--modules/fbx/editor/editor_scene_importer_ufbx.cpp2
-rwxr-xr-xmodules/mono/build_scripts/build_assemblies.py10
-rw-r--r--modules/mono/build_scripts/mono_configure.py4
-rw-r--r--modules/mono/config.py2
-rw-r--r--modules/mono/doc_classes/CSharpScript.xml1
-rw-r--r--modules/mono/doc_classes/GodotSharp.xml20
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs6
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp11
-rw-r--r--modules/mono/mono_gd/gd_mono.h8
-rw-r--r--modules/mono/register_types.cpp3
-rw-r--r--modules/navigation/3d/nav_mesh_generator_3d.cpp26
-rw-r--r--modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml6
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper.h1
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper_extension.cpp5
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper_extension.h2
-rw-r--r--modules/openxr/extensions/openxr_fb_foveation_extension.cpp37
-rw-r--r--modules/openxr/extensions/openxr_fb_foveation_extension.h12
-rw-r--r--modules/openxr/openxr_api.cpp4
-rw-r--r--modules/openxr/scene/openxr_composition_layer.cpp4
-rw-r--r--modules/text_server_adv/gdextension_build/SConstruct7
-rw-r--r--modules/text_server_adv/gdextension_build/methods.py62
-rw-r--r--modules/text_server_fb/gdextension_build/SConstruct5
-rw-r--r--modules/text_server_fb/gdextension_build/methods.py62
-rw-r--r--platform/SCsub3
-rw-r--r--platform/android/SCsub3
-rw-r--r--platform/android/detect.py5
-rw-r--r--platform/android/java/app/config.gradle3
-rw-r--r--platform/android/java/build.gradle5
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt24
-rw-r--r--platform/ios/SCsub6
-rw-r--r--platform/ios/detect.py4
-rw-r--r--platform/linuxbsd/detect.py6
-rw-r--r--platform/macos/SCsub10
-rw-r--r--platform/macos/detect.py8
-rw-r--r--platform/web/SCsub3
-rw-r--r--platform/web/detect.py11
-rw-r--r--platform/web/emscripten_helpers.py7
-rwxr-xr-xplatform/web/serve.py8
-rw-r--r--platform/windows/SCsub1
-rw-r--r--platform/windows/detect.py14
-rw-r--r--platform/windows/platform_windows_builders.py4
-rw-r--r--platform/windows/windows_terminal_logger.cpp28
-rw-r--r--platform_methods.py16
-rw-r--r--pyproject.toml17
-rw-r--r--scene/2d/tile_map.cpp85
-rw-r--r--scene/2d/tile_map.h4
-rw-r--r--scene/2d/tile_map_layer.cpp96
-rw-r--r--scene/2d/tile_map_layer.h4
-rw-r--r--scene/3d/skeleton_3d.cpp11
-rw-r--r--scene/resources/portable_compressed_texture.cpp6
-rw-r--r--scene/resources/shader.cpp2
-rw-r--r--scene/theme/SCsub1
-rw-r--r--scene/theme/icons/SCsub1
-rw-r--r--scu_builders.py21
-rw-r--r--servers/rendering/rendering_light_culler.h4
-rw-r--r--tests/python_build/test_gles3_builder.py2
-rw-r--r--tests/python_build/test_glsl_builder.py2
107 files changed, 1134 insertions, 730 deletions
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 5a0e919c47..dd51d7b419 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -17,12 +17,12 @@ repos:
platform/android/java/lib/src/com/.*
)
- - repo: https://github.com/psf/black-pre-commit-mirror
- rev: 24.2.0
+ - repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.4.4
hooks:
- - id: black
- files: (\.py$|SConstruct|SCsub)
- types_or: [text]
+ - id: ruff
+ args: [--fix]
+ - id: ruff-format
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.971
@@ -146,6 +146,7 @@ repos:
exclude: |
(?x)^(
core/math/bvh_.*\.inc$|
+ platform/(?!android|ios|linuxbsd|macos|web|windows)\w+/.*|
platform/android/java/lib/src/com/.*|
platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView\.java$|
platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper\.java$|
@@ -186,3 +187,15 @@ repos:
language: python
entry: python3 misc/scripts/dotnet_format.py
types_or: [c#]
+
+# End of upstream Godot pre-commit hooks.
+#
+# Keep this separation to let downstream forks add their own hooks to this file,
+# without running into merge conflicts when rebasing on latest upstream.
+#
+# Start of downstream pre-commit hooks.
+#
+# This is still the "repo: local" scope, so new local hooks can be defined directly at this indentation:
+# - id: new-local-hook
+# To add external repo hooks, bring the indentation back to:
+# - repo: my-remote-hook
diff --git a/SConstruct b/SConstruct
index afa44fef4a..7e51ef4fc4 100644
--- a/SConstruct
+++ b/SConstruct
@@ -10,11 +10,11 @@ import os
import pickle
import sys
import time
-from types import ModuleType
from collections import OrderedDict
-from importlib.util import spec_from_file_location, module_from_spec
-from SCons import __version__ as scons_raw_version
+from importlib.util import module_from_spec, spec_from_file_location
+from types import ModuleType
+from SCons import __version__ as scons_raw_version
# Explicitly resolve the helper modules, this is done to avoid clash with
# modules of the same name that might be randomly added (e.g. someone adding
@@ -53,12 +53,12 @@ _helper_module("core.core_builders", "core/core_builders.py")
_helper_module("main.main_builders", "main/main_builders.py")
# Local
-import methods
-import glsl_builders
import gles3_builders
+import glsl_builders
+import methods
import scu_builders
-from methods import print_warning, print_error
-from platform_methods import architectures, architecture_aliases
+from methods import print_error, print_warning
+from platform_methods import architecture_aliases, architectures
if ARGUMENTS.get("target", "editor") == "editor":
_helper_module("editor.editor_builders", "editor/editor_builders.py")
@@ -68,7 +68,7 @@ if ARGUMENTS.get("target", "editor") == "editor":
# <https://github.com/python/cpython/issues/73245>
if sys.stdout.isatty() and sys.platform == "win32":
try:
- from ctypes import windll, byref, WinError # type: ignore
+ from ctypes import WinError, byref, windll # type: ignore
from ctypes.wintypes import DWORD # type: ignore
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
@@ -562,7 +562,7 @@ if env["build_profile"] != "":
dbo = ft["disabled_build_options"]
for c in dbo:
env[c] = dbo[c]
- except:
+ except json.JSONDecodeError:
print_error('Failed to open feature build profile: "{}"'.format(env["build_profile"]))
Exit(255)
@@ -570,7 +570,7 @@ if env["build_profile"] != "":
# These can sometimes override default options.
flag_list = platform_flags[env["platform"]]
for f in flag_list:
- if not (f[0] in ARGUMENTS) or ARGUMENTS[f[0]] == "auto": # Allow command line to override platform flags
+ if f[0] not in ARGUMENTS or ARGUMENTS[f[0]] == "auto": # Allow command line to override platform flags
env[f[0]] = f[1]
# 'dev_mode' and 'production' are aliases to set default options if they haven't been
@@ -591,7 +591,7 @@ if env["production"]:
# Run SCU file generation script if in a SCU build.
if env["scu_build"]:
max_includes_per_scu = 8
- if env.dev_build == True:
+ if env.dev_build:
max_includes_per_scu = 1024
read_scu_limit = int(env["scu_limit"])
@@ -984,7 +984,7 @@ GLSL_BUILDERS = {
env.Append(BUILDERS=GLSL_BUILDERS)
scons_cache_path = os.environ.get("SCONS_CACHE")
-if scons_cache_path != None:
+if scons_cache_path is not None:
CacheDir(scons_cache_path)
print("Scons cache enabled... (path: '" + scons_cache_path + "')")
diff --git a/core/SCsub b/core/SCsub
index a61c0b5fc2..52f3506416 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -2,9 +2,11 @@
Import("env")
+import os
+
import core_builders
+
import methods
-import os
env.core_sources = []
@@ -188,9 +190,7 @@ def version_info_builder(target, source, env):
#define VERSION_WEBSITE "{website}"
#define VERSION_DOCS_BRANCH "{docs_branch}"
#define VERSION_DOCS_URL "https://docs.godotengine.org/en/" VERSION_DOCS_BRANCH
-""".format(
- **env.version_info
- )
+""".format(**env.version_info)
)
@@ -206,9 +206,7 @@ def version_hash_builder(target, source, env):
const char *const VERSION_HASH = "{git_hash}";
const uint64_t VERSION_TIMESTAMP = {git_timestamp};
-""".format(
- **env.version_info
- )
+""".format(**env.version_info)
)
diff --git a/core/core_builders.py b/core/core_builders.py
index a401f03693..a3dc935b79 100644
--- a/core/core_builders.py
+++ b/core/core_builders.py
@@ -180,7 +180,7 @@ def make_license_header(target, source, env):
return line
def next_tag(self):
- if not ":" in self.current:
+ if ":" not in self.current:
return ("", [])
tag, line = self.current.split(":", 1)
lines = [line.strip()]
@@ -206,7 +206,7 @@ def make_license_header(target, source, env):
if not tag or not reader.current:
# end of a paragraph start a new part
- if "License" in part and not "Files" in part:
+ if "License" in part and "Files" not in part:
# no Files tag in this one, so assume standalone license
license_list.append(part["License"])
part = {}
@@ -298,13 +298,13 @@ def make_license_header(target, source, env):
f.write("const int LICENSE_COUNT = " + str(len(license_list)) + ";\n")
f.write("const char *const LICENSE_NAMES[] = {\n")
- for l in license_list:
- f.write('\t"' + escape_string(l[0]) + '",\n')
+ for license in license_list:
+ f.write('\t"' + escape_string(license[0]) + '",\n')
f.write("};\n\n")
f.write("const char *const LICENSE_BODIES[] = {\n\n")
- for l in license_list:
- for line in l[1:]:
+ for license in license_list:
+ for line in license[1:]:
if line == ".":
f.write('\t"\\n"\n')
else:
diff --git a/core/extension/SCsub b/core/extension/SCsub
index 901ceec1e8..6ab2d2b0a6 100644
--- a/core/extension/SCsub
+++ b/core/extension/SCsub
@@ -2,8 +2,8 @@
Import("env")
-import make_wrappers
import make_interface_dumper
+import make_wrappers
env.CommandNoCache(["ext_wrappers.gen.inc"], "make_wrappers.py", env.Run(make_wrappers.run))
env.CommandNoCache(
diff --git a/core/extension/make_wrappers.py b/core/extension/make_wrappers.py
index 655b90d2b1..54f4fd5579 100644
--- a/core/extension/make_wrappers.py
+++ b/core/extension/make_wrappers.py
@@ -10,7 +10,6 @@ _FORCE_INLINE_ virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
def generate_mod_version(argcount, const=False, returns=False):
s = proto_mod
sproto = str(argcount)
- method_info = ""
if returns:
sproto += "R"
s = s.replace("$RETTYPE", "m_ret, ")
@@ -68,7 +67,6 @@ virtual $RETVAL m_name($FUNCARGS) $CONST override { \\
def generate_ex_version(argcount, const=False, returns=False):
s = proto_ex
sproto = str(argcount)
- method_info = ""
if returns:
sproto += "R"
s = s.replace("$RETTYPE", "m_ret, ")
diff --git a/core/input/SCsub b/core/input/SCsub
index da29637135..d8e6f33156 100644
--- a/core/input/SCsub
+++ b/core/input/SCsub
@@ -4,7 +4,6 @@ Import("env")
import input_builders
-
# Order matters here. Higher index controller database files write on top of lower index database files.
controller_databases = [
"gamecontrollerdb.txt",
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index 1502b2807c..83ebdc5a84 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -350,6 +350,8 @@ public:
return triangles;
}
+ // Assumes cartesian coordinate system with +x to the right, +y up.
+ // If using screen coordinates (+x to the right, +y down) the result will need to be flipped.
static bool is_polygon_clockwise(const Vector<Vector2> &p_polygon) {
int c = p_polygon.size();
if (c < 3) {
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index e25703b93f..3d93ce8e73 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -522,7 +522,7 @@ Object *ClassDB::_instantiate_internal(const StringName &p_class, bool p_require
#ifdef TOOLS_ENABLED
if (!p_require_real_class && ti->is_runtime && Engine::get_singleton()->is_editor_hint()) {
if (!ti->inherits_ptr || !ti->inherits_ptr->creation_func) {
- ERR_PRINT_ONCE(vformat("Cannot make a placeholder instance of runtime class %s because its parent cannot be constructed.", ti->name));
+ ERR_PRINT(vformat("Cannot make a placeholder instance of runtime class %s because its parent cannot be constructed.", ti->name));
} else {
ObjectGDExtension *extension = get_placeholder_extension(ti->name);
return (Object *)extension->create_instance(extension->class_userdata);
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 4b32acaaa0..bcab80ea94 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1571,9 +1571,6 @@
<member name="Geometry3D" type="Geometry3D" setter="" getter="">
The [Geometry3D] singleton.
</member>
- <member name="GodotSharp" type="GodotSharp" setter="" getter="">
- The [GodotSharp] singleton.
- </member>
<member name="IP" type="IP" setter="" getter="">
The [IP] singleton.
</member>
diff --git a/doc/classes/Geometry2D.xml b/doc/classes/Geometry2D.xml
index dfcf299fe6..f21696d02c 100644
--- a/doc/classes/Geometry2D.xml
+++ b/doc/classes/Geometry2D.xml
@@ -116,6 +116,7 @@
<param index="0" name="polygon" type="PackedVector2Array" />
<description>
Returns [code]true[/code] if [param polygon]'s vertices are ordered in clockwise order, otherwise returns [code]false[/code].
+ [b]Note:[/b] Assumes a Cartesian coordinate system where [code]+x[/code] is right and [code]+y[/code] is up. If using screen coordinates ([code]+y[/code] is down), the result will need to be flipped (i.e. a [code]true[/code] result will indicate counter-clockwise).
</description>
</method>
<method name="line_intersects_line">
diff --git a/doc/tools/doc_status.py b/doc/tools/doc_status.py
index a23c11b585..57c03bfdee 100755
--- a/doc/tools/doc_status.py
+++ b/doc/tools/doc_status.py
@@ -1,11 +1,11 @@
#!/usr/bin/env python3
import fnmatch
-import os
-import sys
-import re
import math
+import os
import platform
+import re
+import sys
import xml.etree.ElementTree as ET
from typing import Dict, List, Set
@@ -286,7 +286,7 @@ class ClassStatus:
status.progresses[tag.tag].increment(is_deprecated or is_experimental or has_descr)
elif tag.tag in ["constants", "members", "theme_items"]:
for sub_tag in list(tag):
- if not sub_tag.text is None:
+ if sub_tag.text is not None:
is_deprecated = "deprecated" in sub_tag.attrib
is_experimental = "experimental" in sub_tag.attrib
has_descr = len(sub_tag.text.strip()) > 0
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index 43e1afe720..bc379f8553 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -4,17 +4,16 @@
import argparse
import os
-import platform
import re
import sys
import xml.etree.ElementTree as ET
from collections import OrderedDict
-from typing import List, Dict, TextIO, Tuple, Optional, Any, Union
+from typing import Any, Dict, List, Optional, TextIO, Tuple, Union
# Import hardcoded version information from version.py
root_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../")
sys.path.append(root_directory) # Include the root directory
-import version
+import version # noqa: E402
# $DOCS_URL/path/to/page.html(#fragment-tag)
GODOT_DOCS_PATTERN = re.compile(r"^\$DOCS_URL/(.*)\.html(#.*)?$")
@@ -706,7 +705,7 @@ def main() -> None:
# <https://github.com/python/cpython/issues/73245>
if should_color and sys.stdout.isatty() and sys.platform == "win32":
try:
- from ctypes import windll, byref, WinError # type: ignore
+ from ctypes import WinError, byref, windll # type: ignore
from ctypes.wintypes import DWORD # type: ignore
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
@@ -1413,7 +1412,7 @@ def make_rst_class(class_def: ClassDef, state: State, dry_run: bool, output_dir:
operator_anchor = f".. _class_{class_name}_operator_{sanitize_operator_name(m.name, state)}"
for parameter in m.parameters:
operator_anchor += f"_{parameter.type_name.type_name}"
- operator_anchor += f":\n\n"
+ operator_anchor += ":\n\n"
f.write(operator_anchor)
f.write(".. rst-class:: classref-operator\n\n")
@@ -1553,7 +1552,7 @@ def make_method_signature(
out += f":ref:`{op_name}<class_{class_def.name}_{ref_type}_{sanitize_operator_name(definition.name, state)}"
for parameter in definition.parameters:
out += f"_{parameter.type_name.type_name}"
- out += f">`"
+ out += ">`"
elif ref_type == "method":
ref_type_qualifier = ""
if definition.name.startswith("_"):
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index c656ee3cc7..5cde4ee9de 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -70,21 +70,28 @@ enum SceneUniformLocation {
SCENE_GLOBALS_UNIFORM_LOCATION,
SCENE_DATA_UNIFORM_LOCATION,
SCENE_MATERIAL_UNIFORM_LOCATION,
- SCENE_EMPTY, // Unused, put here to avoid conflicts with SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION.
+ SCENE_EMPTY1, // Unused, put here to avoid conflicts with SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION.
SCENE_OMNILIGHT_UNIFORM_LOCATION,
SCENE_SPOTLIGHT_UNIFORM_LOCATION,
SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
SCENE_MULTIVIEW_UNIFORM_LOCATION,
SCENE_POSITIONAL_SHADOW_UNIFORM_LOCATION,
SCENE_DIRECTIONAL_SHADOW_UNIFORM_LOCATION,
+ SCENE_EMPTY2, // Unused, put here to avoid conflicts with SKY_MULTIVIEW_UNIFORM_LOCATION.
};
enum SkyUniformLocation {
SKY_TONEMAP_UNIFORM_LOCATION,
SKY_GLOBALS_UNIFORM_LOCATION,
- SKY_EMPTY, // Unused, put here to avoid conflicts with SCENE_DATA_UNIFORM_LOCATION.
+ SKY_EMPTY1, // Unused, put here to avoid conflicts with SCENE_DATA_UNIFORM_LOCATION.
SKY_MATERIAL_UNIFORM_LOCATION,
SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
+ SKY_EMPTY2, // Unused, put here to avoid conflicts with SCENE_OMNILIGHT_UNIFORM_LOCATION.
+ SKY_EMPTY3, // Unused, put here to avoid conflicts with SCENE_SPOTLIGHT_UNIFORM_LOCATION.
+ SKY_EMPTY4, // Unused, put here to avoid conflicts with SCENE_DIRECTIONAL_LIGHT_UNIFORM_LOCATION.
+ SKY_EMPTY5, // Unused, put here to avoid conflicts with SCENE_MULTIVIEW_UNIFORM_LOCATION.
+ SKY_EMPTY6, // Unused, put here to avoid conflicts with SCENE_POSITIONAL_SHADOW_UNIFORM_LOCATION.
+ SKY_EMPTY7, // Unused, put here to avoid conflicts with SCENE_DIRECTIONAL_SHADOW_UNIFORM_LOCATION.
SKY_MULTIVIEW_UNIFORM_LOCATION,
};
diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl
index 26549901a6..9de65ba960 100644
--- a/drivers/gles3/shaders/sky.glsl
+++ b/drivers/gles3/shaders/sky.glsl
@@ -116,7 +116,7 @@ uniform float z_far;
uniform uint directional_light_count;
#ifdef USE_MULTIVIEW
-layout(std140) uniform MultiviewData { // ubo:5
+layout(std140) uniform MultiviewData { // ubo:11
highp mat4 projection_matrix_view[MAX_VIEWS];
highp mat4 inv_projection_matrix_view[MAX_VIEWS];
highp vec4 eye_offset[MAX_VIEWS];
diff --git a/editor/SCsub b/editor/SCsub
index e613a71238..029048969a 100644
--- a/editor/SCsub
+++ b/editor/SCsub
@@ -4,11 +4,12 @@ Import("env")
env.editor_sources = []
-import os
import glob
+import os
+
import editor_builders
-import methods
+import methods
if env.editor_build:
# Generate doc data paths
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index ebb63dd57c..045774080c 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -7312,17 +7312,19 @@ AnimationTrackEditor::AnimationTrackEditor() {
bottom_hb->add_child(zoom);
timeline->set_zoom(zoom);
+ ED_SHORTCUT("animation_editor/auto_fit", TTR("Fit to panel"), KeyModifierMask::ALT | Key::F);
+
auto_fit = memnew(Button);
auto_fit->set_flat(true);
auto_fit->connect(SceneStringName(pressed), callable_mp(this, &AnimationTrackEditor::_auto_fit));
- auto_fit->set_shortcut(ED_SHORTCUT("animation_editor/auto_fit", TTR("Fit to panel"), KeyModifierMask::ALT | Key::F));
+ auto_fit->set_shortcut(ED_GET_SHORTCUT("animation_editor/auto_fit"));
bottom_hb->add_child(auto_fit);
auto_fit_bezier = memnew(Button);
auto_fit_bezier->set_flat(true);
auto_fit_bezier->set_visible(false);
auto_fit_bezier->connect(SceneStringName(pressed), callable_mp(this, &AnimationTrackEditor::_auto_fit_bezier));
- auto_fit_bezier->set_shortcut(ED_SHORTCUT("animation_editor/auto_fit", TTR("Fit to panel"), KeyModifierMask::ALT | Key::F));
+ auto_fit_bezier->set_shortcut(ED_GET_SHORTCUT("animation_editor/auto_fit"));
bottom_hb->add_child(auto_fit_bezier);
edit = memnew(MenuButton);
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index b58e82b7e7..331dacf6ad 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -344,25 +344,6 @@ void DocTools::merge_from(const DocTools &p_data) {
merge_theme_properties(c.theme_properties, cf.theme_properties);
merge_operators(c.operators, cf.operators);
-
-#ifndef MODULE_MONO_ENABLED
- // The Mono module defines some properties that we want to keep when
- // re-generating docs with a non-Mono build, to prevent pointless diffs
- // (and loss of descriptions) depending on the config of the doc writer.
- // We use a horrible hack to force keeping the relevant properties,
- // hardcoded below. At least it's an ad hoc hack... ¯\_(ツ)_/¯
- // Don't show this to your kids.
- if (c.name == "@GlobalScope") {
- // Retrieve GodotSharp singleton.
- for (int j = 0; j < cf.properties.size(); j++) {
- if (cf.properties[j].name == "GodotSharp") {
- c.properties.push_back(cf.properties[j]);
- c.properties.sort();
- break;
- }
- }
- }
-#endif
}
}
diff --git a/editor/editor_builders.py b/editor/editor_builders.py
index cfe6e56b49..625d570666 100644
--- a/editor/editor_builders.py
+++ b/editor/editor_builders.py
@@ -7,6 +7,7 @@ import subprocess
import tempfile
import uuid
import zlib
+
from methods import print_warning
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 68fcc613ee..581294d677 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -6297,6 +6297,11 @@ EditorNode::EditorNode() {
EditorSettings::create();
}
+ ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::L);
+ ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::L);
+ ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::G);
+ ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::G);
+
FileAccess::set_backup_save(EDITOR_GET("filesystem/on_save/safe_save_on_backup_then_rename"));
_update_vsync_mode();
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index a06dd310ea..fa0dad41dc 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -1368,22 +1368,35 @@ bool SceneTreeEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_d
}
bool scene_drop = true;
+ bool audio_drop = true;
for (int i = 0; i < files.size(); i++) {
String ftype = EditorFileSystem::get_singleton()->get_file_type(files[i]);
if (ftype != "PackedScene") {
scene_drop = false;
- break;
+ }
+ if (audio_drop && !ClassDB::is_parent_class(ftype, "AudioStream")) {
+ audio_drop = false;
}
}
if (scene_drop) {
tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN | Tree::DROP_MODE_ON_ITEM);
- } else {
+ return true;
+ }
+
+ if (audio_drop) {
if (files.size() > 1) {
- return false;
+ tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);
+ } else {
+ tree->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN | Tree::DROP_MODE_ON_ITEM);
}
- tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
+ return true;
+ }
+
+ if (files.size() > 1) {
+ return false;
}
+ tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
return true;
}
diff --git a/editor/icons/SCsub b/editor/icons/SCsub
index d2d752cff4..0d9ac43c46 100644
--- a/editor/icons/SCsub
+++ b/editor/icons/SCsub
@@ -3,8 +3,8 @@
Import("env")
import os
-import editor_icons_builders
+import editor_icons_builders
env["BUILDERS"]["MakeEditorIconsBuilder"] = Builder(
action=env.Run(editor_icons_builders.make_editor_icons_action),
diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp
index 070c44419a..23c22a8049 100644
--- a/editor/import/3d/resource_importer_scene.cpp
+++ b/editor/import/3d/resource_importer_scene.cpp
@@ -2329,6 +2329,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import
}
script_ext_hint += "*." + E;
}
+ bool trimming_defaults_on = p_path.get_extension().to_lower() == "fbx";
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "nodes/apply_root_scale"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "nodes/root_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001"), 1.0));
@@ -2342,7 +2343,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 30));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/trimming"), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/trimming"), trimming_defaults_on));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/remove_immutable_tracks"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import_rest_as_RESET"), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "import_script/path", PROPERTY_HINT_FILE, script_ext_hint), ""));
diff --git a/editor/import/resource_importer_texture.cpp b/editor/import/resource_importer_texture.cpp
index 8cf104725a..487b8fc175 100644
--- a/editor/import/resource_importer_texture.cpp
+++ b/editor/import/resource_importer_texture.cpp
@@ -269,9 +269,9 @@ void ResourceImporterTexture::save_to_ctex_format(Ref<FileAccess> f, const Ref<I
for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
Vector<uint8_t> data;
if (use_webp) {
- data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i));
+ data = Image::webp_lossless_packer(i ? p_image->get_image_from_mipmap(i) : p_image);
} else {
- data = Image::png_packer(p_image->get_image_from_mipmap(i));
+ data = Image::png_packer(i ? p_image->get_image_from_mipmap(i) : p_image);
}
int data_len = data.size();
f->store_32(data_len);
@@ -289,7 +289,7 @@ void ResourceImporterTexture::save_to_ctex_format(Ref<FileAccess> f, const Ref<I
f->store_32(p_image->get_format());
for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
- Vector<uint8_t> data = Image::webp_lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality);
+ Vector<uint8_t> data = Image::webp_lossy_packer(i ? p_image->get_image_from_mipmap(i) : p_image, p_lossy_quality);
int data_len = data.size();
f->store_32(data_len);
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index fbe76e1d5c..2d87e6592f 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -188,10 +188,20 @@ void ImportDock::_update_options(const String &p_path, const Ref<ConfigFile> &p_
params->checked.clear();
params->base_options_path = p_path;
+ HashMap<StringName, Variant> import_options;
+ List<String> section_keys;
+ p_config->get_section_keys("params", &section_keys);
+ for (const String &section_key : section_keys) {
+ import_options[section_key] = p_config->get_value("params", section_key);
+ }
+ if (params->importer.is_valid()) {
+ params->importer->handle_compatibility_options(import_options);
+ }
+
for (const ResourceImporter::ImportOption &E : options) {
params->properties.push_back(E.option);
- if (p_config.is_valid() && p_config->has_section_key("params", E.option.name)) {
- params->values[E.option.name] = p_config->get_value("params", E.option.name);
+ if (p_config.is_valid() && import_options.has(E.option.name)) {
+ params->values[E.option.name] = import_options[E.option.name];
} else {
params->values[E.option.name] = E.default_value;
}
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index a44430ca7f..ee96de8f23 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -46,10 +46,12 @@
#include "editor/scene_tree_dock.h"
#include "editor/themes/editor_scale.h"
#include "editor/themes/editor_theme_manager.h"
+#include "scene/2d/audio_stream_player_2d.h"
#include "scene/2d/polygon_2d.h"
#include "scene/2d/skeleton_2d.h"
#include "scene/2d/sprite_2d.h"
#include "scene/2d/touch_screen_button.h"
+#include "scene/gui/base_button.h"
#include "scene/gui/flow_container.h"
#include "scene/gui/grid_container.h"
#include "scene/gui/separator.h"
@@ -966,7 +968,7 @@ void CanvasItemEditor::_add_node_pressed(int p_result) {
}
}
-void CanvasItemEditor::_node_created(Node *p_node) {
+void CanvasItemEditor::_adjust_new_node_position(Node *p_node) {
if (node_create_position == Point2()) {
return;
}
@@ -5161,7 +5163,7 @@ CanvasItemEditor::CanvasItemEditor() {
editor_selection->connect("selection_changed", callable_mp((CanvasItem *)this, &CanvasItem::queue_redraw));
editor_selection->connect("selection_changed", callable_mp(this, &CanvasItemEditor::_selection_changed));
- SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_node_created));
+ SceneTreeDock::get_singleton()->connect("node_created", callable_mp(this, &CanvasItemEditor::_adjust_new_node_position));
SceneTreeDock::get_singleton()->connect("add_node_used", callable_mp(this, &CanvasItemEditor::_reset_create_position));
// Add some margin to the sides for better esthetics.
@@ -5417,7 +5419,7 @@ CanvasItemEditor::CanvasItemEditor() {
lock_button->connect(SceneStringName(pressed), callable_mp(this, &CanvasItemEditor::_popup_callback).bind(LOCK_SELECTED));
lock_button->set_tooltip_text(TTR("Lock selected node, preventing selection and movement."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- lock_button->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::L));
+ lock_button->set_shortcut(ED_GET_SHORTCUT("editor/lock_selected_nodes"));
unlock_button = memnew(Button);
unlock_button->set_theme_type_variation("FlatButton");
@@ -5425,7 +5427,7 @@ CanvasItemEditor::CanvasItemEditor() {
unlock_button->connect(SceneStringName(pressed), callable_mp(this, &CanvasItemEditor::_popup_callback).bind(UNLOCK_SELECTED));
unlock_button->set_tooltip_text(TTR("Unlock selected node, allowing selection and movement."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- unlock_button->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::L));
+ unlock_button->set_shortcut(ED_GET_SHORTCUT("editor/unlock_selected_nodes"));
group_button = memnew(Button);
group_button->set_theme_type_variation("FlatButton");
@@ -5433,7 +5435,7 @@ CanvasItemEditor::CanvasItemEditor() {
group_button->connect(SceneStringName(pressed), callable_mp(this, &CanvasItemEditor::_popup_callback).bind(GROUP_SELECTED));
group_button->set_tooltip_text(TTR("Groups the selected node with its children. This causes the parent to be selected when any child node is clicked in 2D and 3D view."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- group_button->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::G));
+ group_button->set_shortcut(ED_GET_SHORTCUT("editor/group_selected_nodes"));
ungroup_button = memnew(Button);
ungroup_button->set_theme_type_variation("FlatButton");
@@ -5441,7 +5443,7 @@ CanvasItemEditor::CanvasItemEditor() {
ungroup_button->connect(SceneStringName(pressed), callable_mp(this, &CanvasItemEditor::_popup_callback).bind(UNGROUP_SELECTED));
ungroup_button->set_tooltip_text(TTR("Ungroups the selected node from its children. Child nodes will be individual items in 2D and 3D view."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- ungroup_button->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::G));
+ ungroup_button->set_shortcut(ED_GET_SHORTCUT("editor/ungroup_selected_nodes"));
main_menu_hbox->add_child(memnew(VSeparator));
@@ -5697,15 +5699,15 @@ CanvasItemEditorPlugin::~CanvasItemEditorPlugin() {
}
void CanvasItemEditorViewport::_on_mouse_exit() {
- if (!selector->is_visible()) {
+ if (!texture_node_type_selector->is_visible()) {
_remove_preview();
}
}
-void CanvasItemEditorViewport::_on_select_type(Object *selected) {
+void CanvasItemEditorViewport::_on_select_texture_node_type(Object *selected) {
CheckBox *check = Object::cast_to<CheckBox>(selected);
String type = check->get_text();
- selector->set_title(vformat(TTR("Add %s"), type));
+ texture_node_type_selector->set_title(vformat(TTR("Add %s"), type));
label->set_text(vformat(TTR("Adding %s..."), type));
}
@@ -5717,7 +5719,7 @@ void CanvasItemEditorViewport::_on_change_type_confirmed() {
CheckBox *check = Object::cast_to<CheckBox>(button_group->get_pressed_button());
default_texture_node_type = check->get_text();
_perform_drop_data();
- selector->hide();
+ texture_node_type_selector->hide();
}
void CanvasItemEditorViewport::_on_change_type_closed() {
@@ -5728,35 +5730,35 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons
bool add_preview = false;
for (int i = 0; i < files.size(); i++) {
Ref<Resource> res = ResourceLoader::load(files[i]);
- ERR_FAIL_COND(res.is_null());
- Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res));
- Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
- if (texture != nullptr || scene != nullptr) {
- String desc = TTR("Drag and drop to add as sibling of selected node (except when root is selected).") +
- "\n" + TTR("Hold Shift when dropping to add as child of selected node.") +
- "\n" + TTR("Hold Alt when dropping to add as child of root node.");
-
- if (texture != nullptr) {
- Sprite2D *sprite = memnew(Sprite2D);
- sprite->set_texture(texture);
- sprite->set_modulate(Color(1, 1, 1, 0.7f));
- preview_node->add_child(sprite);
- label->show();
- label_desc->show();
- desc += "\n" + TTR("Hold Alt + Shift when dropping to add as a different node type.");
- label_desc->set_text(desc);
- } else {
- if (scene.is_valid()) {
- Node *instance = scene->instantiate();
- if (instance) {
- preview_node->add_child(instance);
- label_desc->show();
- label_desc->set_text(desc);
- }
- }
+ ERR_CONTINUE(res.is_null());
+
+ Ref<Texture2D> texture = res;
+ if (texture.is_valid()) {
+ Sprite2D *sprite = memnew(Sprite2D);
+ sprite->set_texture(texture);
+ sprite->set_modulate(Color(1, 1, 1, 0.7f));
+ preview_node->add_child(sprite);
+ add_preview = true;
+ }
+
+ Ref<PackedScene> scene = res;
+ if (scene.is_valid()) {
+ Node *instance = scene->instantiate();
+ if (instance) {
+ preview_node->add_child(instance);
}
add_preview = true;
}
+
+ Ref<AudioStream> audio = res;
+ if (audio.is_valid()) {
+ Sprite2D *sprite = memnew(Sprite2D);
+ sprite->set_texture(get_editor_theme_icon(SNAME("AudioStreamPlayer2D")));
+ sprite->set_modulate(Color(1, 1, 1, 0.7f));
+ sprite->set_position(Vector2(0, -sprite->get_texture()->get_size().height) * EDSCALE);
+ preview_node->add_child(sprite);
+ add_preview = true;
+ }
}
if (add_preview) {
@@ -5797,44 +5799,46 @@ bool CanvasItemEditorViewport::_cyclical_dependency_exists(const String &p_targe
return false;
}
-void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point) {
+void CanvasItemEditorViewport::_create_texture_node(Node *p_parent, Node *p_child, const String &p_path, const Point2 &p_point) {
// Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
- String name = path.get_file().get_basename();
- child->set_name(Node::adjust_name_casing(name));
+ const String &node_name = Node::adjust_name_casing(p_path.get_file().get_basename());
+ if (!node_name.is_empty()) {
+ p_child->set_name(node_name);
+ }
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- Ref<Texture2D> texture = ResourceCache::get_ref(path);
+ Ref<Texture2D> texture = ResourceCache::get_ref(p_path);
- if (parent) {
- undo_redo->add_do_method(parent, "add_child", child, true);
- undo_redo->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
- undo_redo->add_do_reference(child);
- undo_redo->add_undo_method(parent, "remove_child", child);
+ if (p_parent) {
+ undo_redo->add_do_method(p_parent, "add_child", p_child, true);
+ undo_redo->add_do_method(p_child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_reference(p_child);
+ undo_redo->add_undo_method(p_parent, "remove_child", p_child);
} else { // If no parent is selected, set as root node of the scene.
- undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
- undo_redo->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
- undo_redo->add_do_reference(child);
+ undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_child);
+ undo_redo->add_do_method(p_child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_reference(p_child);
undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
}
- if (parent) {
- String new_name = parent->validate_child_name(child);
+ if (p_parent) {
+ String new_name = p_parent->validate_child_name(p_child);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- undo_redo->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), child->get_class(), new_name);
- undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
+ undo_redo->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), p_child->get_class(), new_name);
+ undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent)) + "/" + new_name));
}
- if (Object::cast_to<TouchScreenButton>(child) || Object::cast_to<TextureButton>(child)) {
- undo_redo->add_do_property(child, "texture_normal", texture);
+ if (Object::cast_to<TouchScreenButton>(p_child) || Object::cast_to<TextureButton>(p_child)) {
+ undo_redo->add_do_property(p_child, "texture_normal", texture);
} else {
- undo_redo->add_do_property(child, "texture", texture);
+ undo_redo->add_do_property(p_child, "texture", texture);
}
// make visible for certain node type
- if (Object::cast_to<Control>(child)) {
+ if (Object::cast_to<Control>(p_child)) {
Size2 texture_size = texture->get_size();
- undo_redo->add_do_property(child, "size", texture_size);
- } else if (Object::cast_to<Polygon2D>(child)) {
+ undo_redo->add_do_property(p_child, "size", texture_size);
+ } else if (Object::cast_to<Polygon2D>(p_child)) {
Size2 texture_size = texture->get_size();
Vector<Vector2> list = {
Vector2(0, 0),
@@ -5842,7 +5846,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
Vector2(texture_size.width, texture_size.height),
Vector2(0, texture_size.height)
};
- undo_redo->add_do_property(child, "polygon", list);
+ undo_redo->add_do_property(p_child, "polygon", list);
}
// Compute the global position
@@ -5850,21 +5854,68 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
Point2 target_position = xform.affine_inverse().xform(p_point);
// Adjust position for Control and TouchScreenButton
- if (Object::cast_to<Control>(child) || Object::cast_to<TouchScreenButton>(child)) {
+ if (Object::cast_to<Control>(p_child) || Object::cast_to<TouchScreenButton>(p_child)) {
target_position -= texture->get_size() / 2;
}
- // there's nothing to be used as source position so snapping will work as absolute if enabled
+ // There's nothing to be used as source position, so snapping will work as absolute if enabled.
+ target_position = canvas_item_editor->snap_point(target_position);
+
+ CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_parent);
+ Point2 local_target_pos = parent_ci ? parent_ci->get_global_transform().affine_inverse().xform(target_position) : target_position;
+
+ undo_redo->add_do_method(p_child, "set_position", local_target_pos);
+}
+
+void CanvasItemEditorViewport::_create_audio_node(Node *p_parent, const String &p_path, const Point2 &p_point) {
+ AudioStreamPlayer2D *child = memnew(AudioStreamPlayer2D);
+ child->set_stream(ResourceCache::get_ref(p_path));
+
+ // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
+ const String &node_name = Node::adjust_name_casing(p_path.get_file().get_basename());
+ if (!node_name.is_empty()) {
+ child->set_name(node_name);
+ }
+
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+
+ if (p_parent) {
+ undo_redo->add_do_method(p_parent, "add_child", child, true);
+ undo_redo->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_reference(child);
+ undo_redo->add_undo_method(p_parent, "remove_child", child);
+ } else { // If no parent is selected, set as root node of the scene.
+ undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", child);
+ undo_redo->add_do_method(child, "set_owner", EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_reference(child);
+ undo_redo->add_undo_method(EditorNode::get_singleton(), "set_edited_scene", (Object *)nullptr);
+ }
+
+ if (p_parent) {
+ String new_name = p_parent->validate_child_name(child);
+ EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
+ undo_redo->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), child->get_class(), new_name);
+ undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent)) + "/" + new_name));
+ }
+
+ // Compute the global position
+ Transform2D xform = canvas_item_editor->get_canvas_transform();
+ Point2 target_position = xform.affine_inverse().xform(p_point);
+
+ // There's nothing to be used as source position, so snapping will work as absolute if enabled.
target_position = canvas_item_editor->snap_point(target_position);
- CanvasItem *parent_ci = Object::cast_to<CanvasItem>(parent);
+ CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_parent);
Point2 local_target_pos = parent_ci ? parent_ci->get_global_transform().affine_inverse().xform(target_position) : target_position;
undo_redo->add_do_method(child, "set_position", local_target_pos);
+
+ EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
+ undo_redo->add_do_method(editor_selection, "add_node", child);
}
-bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) {
- Ref<PackedScene> sdata = ResourceLoader::load(path);
+bool CanvasItemEditorViewport::_create_instance(Node *p_parent, const String &p_path, const Point2 &p_point) {
+ Ref<PackedScene> sdata = ResourceLoader::load(p_path);
if (!sdata.is_valid()) { // invalid scene
return false;
}
@@ -5883,27 +5934,27 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
}
}
- instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path));
+ instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(p_path));
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
- undo_redo->add_do_method(parent, "add_child", instantiated_scene, true);
+ undo_redo->add_do_method(p_parent, "add_child", instantiated_scene, true);
undo_redo->add_do_method(instantiated_scene, "set_owner", edited_scene);
undo_redo->add_do_reference(instantiated_scene);
- undo_redo->add_undo_method(parent, "remove_child", instantiated_scene);
+ undo_redo->add_undo_method(p_parent, "remove_child", instantiated_scene);
undo_redo->add_do_method(editor_selection, "add_node", instantiated_scene);
- String new_name = parent->validate_child_name(instantiated_scene);
+ String new_name = p_parent->validate_child_name(instantiated_scene);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- undo_redo->add_do_method(ed, "live_debug_instantiate_node", edited_scene->get_path_to(parent), path, new_name);
- undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)) + "/" + new_name));
+ undo_redo->add_do_method(ed, "live_debug_instantiate_node", edited_scene->get_path_to(p_parent), p_path, new_name);
+ undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)) + "/" + new_name));
CanvasItem *instance_ci = Object::cast_to<CanvasItem>(instantiated_scene);
if (instance_ci) {
Vector2 target_pos = canvas_item_editor->get_canvas_transform().affine_inverse().xform(p_point);
target_pos = canvas_item_editor->snap_point(target_pos);
- CanvasItem *parent_ci = Object::cast_to<CanvasItem>(parent);
+ CanvasItem *parent_ci = Object::cast_to<CanvasItem>(p_parent);
if (parent_ci) {
target_pos = parent_ci->get_global_transform_with_canvas().affine_inverse().xform(target_pos);
}
@@ -5922,12 +5973,8 @@ void CanvasItemEditorViewport::_perform_drop_data() {
_remove_preview();
if (!target_node) {
- // Without root dropping multiple files is not allowed
- if (selected_files.size() > 1) {
- accept->set_text(TTR("Cannot instantiate multiple nodes without root."));
- accept->popup_centered();
- return;
- }
+ // Should already be handled by `can_drop_data`.
+ ERR_FAIL_COND_MSG(selected_files.size() > 1, "Can't instantiate multiple nodes without root.");
const String &path = selected_files[0];
Ref<Resource> res = ResourceLoader::load(path);
@@ -5973,9 +6020,14 @@ void CanvasItemEditorViewport::_perform_drop_data() {
Ref<Texture2D> texture = res;
if (texture.is_valid()) {
Node *child = Object::cast_to<Node>(ClassDB::instantiate(default_texture_node_type));
- _create_nodes(target_node, child, path, drop_pos);
+ _create_texture_node(target_node, child, path, drop_pos);
undo_redo->add_do_method(editor_selection, "add_node", child);
}
+
+ Ref<AudioStream> audio = res;
+ if (audio.is_valid()) {
+ _create_audio_node(target_node, path, drop_pos);
+ }
}
undo_redo->commit_action();
@@ -5994,71 +6046,108 @@ bool CanvasItemEditorViewport::can_drop_data(const Point2 &p_point, const Varian
}
Vector<String> files = d["files"];
- bool can_instantiate = false;
- bool is_cyclical_dep = false;
- String error_file;
- // Check if at least one of the dragged files is a texture or scene.
- for (int i = 0; i < files.size(); i++) {
- bool is_scene = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "PackedScene");
- bool is_texture = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "Texture2D");
+ const Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
+ if (!edited_scene && files.size() > 1) {
+ canvas_item_editor->message = TTR("Can't instantiate multiple nodes without root.");
+ canvas_item_editor->update_viewport();
+ return false;
+ }
+
+ enum {
+ SCENE = 1 << 0,
+ TEXTURE = 1 << 1,
+ AUDIO = 1 << 2,
+ };
+ int instantiate_type = 0;
- if (is_scene || is_texture) {
- Ref<Resource> res = ResourceLoader::load(files[i]);
- if (res.is_null()) {
+ for (const String &path : files) {
+ const String &res_type = ResourceLoader::get_resource_type(path);
+ String error_message;
+
+ if (ClassDB::is_parent_class(res_type, "PackedScene")) {
+ Ref<PackedScene> scn = ResourceLoader::load(path);
+ ERR_CONTINUE(scn.is_null());
+
+ Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
+ if (!instantiated_scene) {
continue;
}
- Ref<PackedScene> scn = res;
- if (scn.is_valid()) {
- Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
- if (!instantiated_scene) {
- continue;
- }
-
- Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
- if (edited_scene && !edited_scene->get_scene_file_path().is_empty() && _cyclical_dependency_exists(edited_scene->get_scene_file_path(), instantiated_scene)) {
- memdelete(instantiated_scene);
- can_instantiate = false;
- is_cyclical_dep = true;
- error_file = files[i].get_file();
- break;
- }
- memdelete(instantiated_scene);
+ if (edited_scene && !edited_scene->get_scene_file_path().is_empty() && _cyclical_dependency_exists(edited_scene->get_scene_file_path(), instantiated_scene)) {
+ error_message = vformat(TTR("Circular dependency found at %s."), path.get_file());
}
- can_instantiate = true;
+ memdelete(instantiated_scene);
+ instantiate_type |= SCENE;
+ }
+ if (ClassDB::is_parent_class(res_type, "Texture2D")) {
+ instantiate_type |= TEXTURE;
+ }
+ if (ClassDB::is_parent_class(res_type, "AudioStream")) {
+ instantiate_type |= AUDIO;
+ }
+
+ if (!error_message.is_empty()) {
+ // TRANSLATORS: The placeholder is the error message.
+ canvas_item_editor->message = vformat(TTR("Can't instantiate: %s"), error_message);
+ canvas_item_editor->update_viewport();
+ return false;
}
}
- if (is_cyclical_dep) {
- canvas_item_editor->message = vformat(TTR("Can't instantiate: %s."), vformat(TTR("Circular dependency found at %s"), error_file));
- canvas_item_editor->update_viewport();
+ if (instantiate_type == 0) {
return false;
}
- if (can_instantiate) {
- if (!preview_node->get_parent()) { // create preview only once
- _create_preview(files);
- }
- ERR_FAIL_COND_V(preview_node->get_child_count() == 0, false);
- Transform2D trans = canvas_item_editor->get_canvas_transform();
- preview_node->set_position((p_point - trans.get_origin()) / trans.get_scale().x);
+ if (!preview_node->get_parent()) { // create preview only once
+ _create_preview(files);
+ }
+ ERR_FAIL_COND_V(preview_node->get_child_count() == 0, false);
+
+ const Transform2D trans = canvas_item_editor->get_canvas_transform();
+ preview_node->set_position((p_point - trans.get_origin()) / trans.get_scale().x);
+
+ if (!edited_scene && instantiate_type & SCENE) {
String scene_file_path = preview_node->get_child(0)->get_scene_file_path();
- if (scene_file_path.is_empty() || preview_node->get_tree()->get_edited_scene_root()) {
- double snap = EDITOR_GET("interface/inspector/default_float_step");
- int snap_step_decimals = Math::range_step_decimals(snap);
+ // TRANSLATORS: The placeholder is the file path of the scene being instantiated.
+ canvas_item_editor->message = vformat(TTR("Creating inherited scene from: %s"), scene_file_path);
+ } else {
+ double snap = EDITOR_GET("interface/inspector/default_float_step");
+ int snap_step_decimals = Math::range_step_decimals(snap);
#define FORMAT(value) (TS->format_number(String::num(value, snap_step_decimals)))
- Vector2 preview_node_pos = preview_node->get_global_position();
- canvas_item_editor->message = TTR("Instantiating:") + " (" + FORMAT(preview_node_pos.x) + ", " + FORMAT(preview_node_pos.y) + ") px";
- label->set_text(vformat(TTR("Adding %s..."), default_texture_node_type));
- } else {
- canvas_item_editor->message = TTR("Creating inherited scene from: ") + scene_file_path;
+ Vector2 preview_node_pos = preview_node->get_global_position();
+ canvas_item_editor->message = TTR("Instantiating: ") + "(" + FORMAT(preview_node_pos.x) + ", " + FORMAT(preview_node_pos.y) + ") px";
+ }
+ canvas_item_editor->update_viewport();
+
+ if (instantiate_type & TEXTURE && instantiate_type & AUDIO) {
+ // TRANSLATORS: The placeholders are the types of nodes being instantiated.
+ label->set_text(vformat(TTR("Adding %s and %s..."), default_texture_node_type, "AudioStreamPlayer2D"));
+ } else {
+ String node_type;
+ if (instantiate_type & TEXTURE) {
+ node_type = default_texture_node_type;
+ } else if (instantiate_type & AUDIO) {
+ node_type = "AudioStreamPlayer2D";
+ }
+ if (!node_type.is_empty()) {
+ // TRANSLATORS: The placeholder is the type of node being instantiated.
+ label->set_text(vformat(TTR("Adding %s..."), node_type));
}
+ }
+ label->set_visible(instantiate_type & ~SCENE);
- canvas_item_editor->update_viewport();
+ String desc = TTR("Drag and drop to add as sibling of selected node (except when root is selected).") +
+ "\n" + TTR("Hold Shift when dropping to add as child of selected node.") +
+ "\n" + TTR("Hold Alt when dropping to add as child of root node.");
+ if (instantiate_type & TEXTURE) {
+ desc += "\n" + TTR("Hold Alt + Shift when dropping to add as different node type.");
}
- return can_instantiate;
+ label_desc->set_text(desc);
+ label_desc->show();
+
+ return true;
}
-void CanvasItemEditorViewport::_show_resource_type_selector() {
+void CanvasItemEditorViewport::_show_texture_node_type_selector() {
_remove_preview();
List<BaseButton *> btn_list;
button_group->get_buttons(&btn_list);
@@ -6067,18 +6156,17 @@ void CanvasItemEditorViewport::_show_resource_type_selector() {
CheckBox *check = Object::cast_to<CheckBox>(btn);
check->set_pressed(check->get_text() == default_texture_node_type);
}
- selector->set_title(vformat(TTR("Add %s"), default_texture_node_type));
- selector->popup_centered();
+ texture_node_type_selector->set_title(vformat(TTR("Add %s"), default_texture_node_type));
+ texture_node_type_selector->popup_centered();
}
-bool CanvasItemEditorViewport::_only_packed_scenes_selected() const {
+bool CanvasItemEditorViewport::_is_any_texture_selected() const {
for (int i = 0; i < selected_files.size(); ++i) {
- if (ResourceLoader::load(selected_files[i])->get_class() != "PackedScene") {
- return false;
+ if (ClassDB::is_parent_class(ResourceLoader::get_resource_type(selected_files[i]), "Texture2D")) {
+ return true;
}
}
-
- return true;
+ return false;
}
void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) {
@@ -6115,8 +6203,8 @@ void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p
drop_pos = p_point;
- if (is_alt && is_shift && !_only_packed_scenes_selected()) {
- _show_resource_type_selector();
+ if (is_alt && is_shift && _is_any_texture_selected()) {
+ _show_texture_node_type_selector();
} else {
_perform_drop_data();
}
@@ -6176,19 +6264,19 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_it
accept = memnew(AcceptDialog);
EditorNode::get_singleton()->get_gui_base()->add_child(accept);
- selector = memnew(AcceptDialog);
- EditorNode::get_singleton()->get_gui_base()->add_child(selector);
- selector->set_title(TTR("Change Default Type"));
- selector->connect("confirmed", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_confirmed));
- selector->connect("canceled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed));
+ texture_node_type_selector = memnew(AcceptDialog);
+ EditorNode::get_singleton()->get_gui_base()->add_child(texture_node_type_selector);
+ texture_node_type_selector->set_title(TTR("Change Default Type"));
+ texture_node_type_selector->connect("confirmed", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_confirmed));
+ texture_node_type_selector->connect("canceled", callable_mp(this, &CanvasItemEditorViewport::_on_change_type_closed));
VBoxContainer *vbc = memnew(VBoxContainer);
- selector->add_child(vbc);
+ texture_node_type_selector->add_child(vbc);
vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
vbc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
vbc->set_custom_minimum_size(Size2(240, 260) * EDSCALE);
- btn_group = memnew(VBoxContainer);
+ VBoxContainer *btn_group = memnew(VBoxContainer);
vbc->add_child(btn_group);
btn_group->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -6197,7 +6285,7 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(CanvasItemEditor *p_canvas_it
CheckBox *check = memnew(CheckBox);
btn_group->add_child(check);
check->set_text(texture_node_types[i]);
- check->connect("button_down", callable_mp(this, &CanvasItemEditorViewport::_on_select_type).bind(check));
+ check->connect("button_down", callable_mp(this, &CanvasItemEditorViewport::_on_select_texture_node_type).bind(check));
check->set_button_group(button_group);
}
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 6d951a77ec..a9de5e9a0b 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -32,10 +32,11 @@
#define CANVAS_ITEM_EDITOR_PLUGIN_H
#include "editor/plugins/editor_plugin.h"
-#include "scene/gui/base_button.h"
#include "scene/gui/box_container.h"
class AcceptDialog;
+class Button;
+class ButtonGroup;
class CanvasItemEditorViewport;
class ConfirmationDialog;
class EditorData;
@@ -409,7 +410,7 @@ private:
void _selection_result_pressed(int);
void _selection_menu_hide();
void _add_node_pressed(int p_result);
- void _node_created(Node *p_node);
+ void _adjust_new_node_position(Node *p_node);
void _reset_create_position();
void _update_editor_settings();
bool _is_grid_visible() const;
@@ -634,15 +635,13 @@ class CanvasItemEditorViewport : public Control {
CanvasItemEditor *canvas_item_editor = nullptr;
Control *preview_node = nullptr;
AcceptDialog *accept = nullptr;
- AcceptDialog *selector = nullptr;
- Label *selector_label = nullptr;
+ AcceptDialog *texture_node_type_selector = nullptr;
Label *label = nullptr;
Label *label_desc = nullptr;
- VBoxContainer *btn_group = nullptr;
Ref<ButtonGroup> button_group;
void _on_mouse_exit();
- void _on_select_type(Object *selected);
+ void _on_select_texture_node_type(Object *selected);
void _on_change_type_confirmed();
void _on_change_type_closed();
@@ -650,11 +649,12 @@ class CanvasItemEditorViewport : public Control {
void _remove_preview();
bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) const;
- bool _only_packed_scenes_selected() const;
- void _create_nodes(Node *parent, Node *child, String &path, const Point2 &p_point);
- bool _create_instance(Node *parent, String &path, const Point2 &p_point);
+ bool _is_any_texture_selected() const;
+ void _create_texture_node(Node *p_parent, Node *p_child, const String &p_path, const Point2 &p_point);
+ void _create_audio_node(Node *p_parent, const String &p_path, const Point2 &p_point);
+ bool _create_instance(Node *p_parent, const String &p_path, const Point2 &p_point);
void _perform_drop_data();
- void _show_resource_type_selector();
+ void _show_texture_node_type_selector();
void _update_theme();
protected:
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index ca7ea821e8..e9e5b2294f 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -78,12 +78,14 @@
#include "editor/plugins/gizmos/voxel_gi_gizmo_plugin.h"
#include "editor/plugins/node_3d_editor_gizmos.h"
#include "editor/scene_tree_dock.h"
+#include "scene/3d/audio_stream_player_3d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/decal.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/physics/collision_shape_3d.h"
#include "scene/3d/physics/physics_body_3d.h"
+#include "scene/3d/sprite_3d.h"
#include "scene/3d/visual_instance_3d.h"
#include "scene/3d/world_environment.h"
#include "scene/gui/center_container.h"
@@ -4192,27 +4194,37 @@ Node *Node3DEditorViewport::_sanitize_preview_node(Node *p_node) const {
void Node3DEditorViewport::_create_preview_node(const Vector<String> &files) const {
bool add_preview = false;
- for (int i = 0; i < files.size(); i++) {
- Ref<Resource> res = ResourceLoader::load(files[i]);
+ for (const String &path : files) {
+ Ref<Resource> res = ResourceLoader::load(path);
ERR_CONTINUE(res.is_null());
- Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
- Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
- if (mesh != nullptr || scene != nullptr) {
- if (mesh != nullptr) {
- MeshInstance3D *mesh_instance = memnew(MeshInstance3D);
- mesh_instance->set_mesh(mesh);
- preview_node->add_child(mesh_instance);
- } else {
- if (scene.is_valid()) {
- Node *instance = scene->instantiate();
- if (instance) {
- instance = _sanitize_preview_node(instance);
- preview_node->add_child(instance);
- }
- }
+
+ Ref<PackedScene> scene = res;
+ if (scene.is_valid()) {
+ Node *instance = scene->instantiate();
+ if (instance) {
+ instance = _sanitize_preview_node(instance);
+ preview_node->add_child(instance);
}
add_preview = true;
}
+
+ Ref<Mesh> mesh = res;
+ if (mesh.is_valid()) {
+ MeshInstance3D *mesh_instance = memnew(MeshInstance3D);
+ mesh_instance->set_mesh(mesh);
+ preview_node->add_child(mesh_instance);
+ add_preview = true;
+ }
+
+ Ref<AudioStream> audio = res;
+ if (audio.is_valid()) {
+ Sprite3D *sprite = memnew(Sprite3D);
+ sprite->set_texture(get_editor_theme_icon(SNAME("Gizmo3DSamplePlayer")));
+ sprite->set_billboard_mode(StandardMaterial3D::BILLBOARD_ENABLED);
+ sprite->set_pixel_size(0.005);
+ preview_node->add_child(sprite);
+ add_preview = true;
+ }
}
if (add_preview) {
EditorNode::get_singleton()->get_scene_root()->add_child(preview_node);
@@ -4346,12 +4358,12 @@ bool Node3DEditorViewport::_cyclical_dependency_exists(const String &p_target_sc
return false;
}
-bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Point2 &p_point) {
- Ref<Resource> res = ResourceLoader::load(path);
+bool Node3DEditorViewport::_create_instance(Node *p_parent, const String &p_path, const Point2 &p_point) {
+ Ref<Resource> res = ResourceLoader::load(p_path);
ERR_FAIL_COND_V(res.is_null(), false);
- Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
- Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
+ Ref<PackedScene> scene = res;
+ Ref<Mesh> mesh = res;
Node *instantiated_scene = nullptr;
@@ -4361,8 +4373,10 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
mesh_instance->set_mesh(mesh);
// Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
- String name = path.get_file().get_basename();
- mesh_instance->set_name(Node::adjust_name_casing(name));
+ const String &node_name = Node::adjust_name_casing(p_path.get_file().get_basename());
+ if (!node_name.is_empty()) {
+ mesh_instance->set_name(node_name);
+ }
instantiated_scene = mesh_instance;
} else {
@@ -4386,25 +4400,25 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
}
if (scene != nullptr) {
- instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path));
+ instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(p_path));
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->add_do_method(parent, "add_child", instantiated_scene, true);
+ undo_redo->add_do_method(p_parent, "add_child", instantiated_scene, true);
undo_redo->add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene());
undo_redo->add_do_reference(instantiated_scene);
- undo_redo->add_undo_method(parent, "remove_child", instantiated_scene);
+ undo_redo->add_undo_method(p_parent, "remove_child", instantiated_scene);
undo_redo->add_do_method(editor_selection, "add_node", instantiated_scene);
- String new_name = parent->validate_child_name(instantiated_scene);
+ String new_name = p_parent->validate_child_name(instantiated_scene);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- undo_redo->add_do_method(ed, "live_debug_instantiate_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent), path, new_name);
- undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(parent)) + "/" + new_name));
+ undo_redo->add_do_method(ed, "live_debug_instantiate_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), p_path, new_name);
+ undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent)) + "/" + new_name));
Node3D *node3d = Object::cast_to<Node3D>(instantiated_scene);
if (node3d) {
Transform3D parent_tf;
- Node3D *parent_node3d = Object::cast_to<Node3D>(parent);
+ Node3D *parent_node3d = Object::cast_to<Node3D>(p_parent);
if (parent_node3d) {
parent_tf = parent_node3d->get_global_gizmo_transform();
}
@@ -4419,6 +4433,46 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
return true;
}
+bool Node3DEditorViewport::_create_audio_node(Node *p_parent, const String &p_path, const Point2 &p_point) {
+ Ref<AudioStream> audio = ResourceLoader::load(p_path);
+ ERR_FAIL_COND_V(audio.is_null(), false);
+
+ AudioStreamPlayer3D *audio_player = memnew(AudioStreamPlayer3D);
+ audio_player->set_stream(audio);
+
+ // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
+ const String &node_name = Node::adjust_name_casing(p_path.get_file().get_basename());
+ if (!node_name.is_empty()) {
+ audio_player->set_name(node_name);
+ }
+
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->add_do_method(p_parent, "add_child", audio_player, true);
+ undo_redo->add_do_method(audio_player, "set_owner", EditorNode::get_singleton()->get_edited_scene());
+ undo_redo->add_do_reference(audio_player);
+ undo_redo->add_undo_method(p_parent, "remove_child", audio_player);
+ undo_redo->add_do_method(editor_selection, "add_node", audio_player);
+
+ const String new_name = p_parent->validate_child_name(audio_player);
+ EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
+ undo_redo->add_do_method(ed, "live_debug_create_node", EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent), audio_player->get_class(), new_name);
+ undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(EditorNode::get_singleton()->get_edited_scene()->get_path_to(p_parent)) + "/" + new_name));
+
+ Transform3D parent_tf;
+ Node3D *parent_node3d = Object::cast_to<Node3D>(p_parent);
+ if (parent_node3d) {
+ parent_tf = parent_node3d->get_global_gizmo_transform();
+ }
+
+ Transform3D new_tf = audio_player->get_transform();
+ new_tf.origin = parent_tf.affine_inverse().xform(preview_node_pos + audio_player->get_position());
+ new_tf.basis = parent_tf.affine_inverse().basis * new_tf.basis;
+
+ undo_redo->add_do_method(audio_player, "set_transform", new_tf);
+
+ return true;
+}
+
void Node3DEditorViewport::_perform_drop_data() {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (spatial_editor->get_preview_material_target().is_valid()) {
@@ -4453,11 +4507,18 @@ void Node3DEditorViewport::_perform_drop_data() {
if (res.is_null()) {
continue;
}
- Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
- Ref<Mesh> mesh = Ref<Mesh>(Object::cast_to<Mesh>(*res));
- if (mesh != nullptr || scene != nullptr) {
- bool success = _create_instance(target_node, path, drop_pos);
- if (!success) {
+
+ Ref<PackedScene> scene = res;
+ Ref<Mesh> mesh = res;
+ if (mesh.is_valid() || scene.is_valid()) {
+ if (!_create_instance(target_node, path, drop_pos)) {
+ error_files.push_back(path.get_file());
+ }
+ }
+
+ Ref<AudioStream> audio = res;
+ if (audio.is_valid()) {
+ if (!_create_audio_node(target_node, path, drop_pos)) {
error_files.push_back(path.get_file());
}
}
@@ -4488,12 +4549,14 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
bool is_other_valid = false;
// Check if at least one of the dragged files is a mesh, material, texture or scene.
for (int i = 0; i < files.size(); i++) {
- bool is_scene = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "PackedScene");
- bool is_mesh = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "Mesh");
- bool is_material = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "Material");
- bool is_texture = ClassDB::is_parent_class(ResourceLoader::get_resource_type(files[i]), "Texture");
-
- if (is_mesh || is_scene || is_material || is_texture) {
+ const String &res_type = ResourceLoader::get_resource_type(files[i]);
+ bool is_scene = ClassDB::is_parent_class(res_type, "PackedScene");
+ bool is_mesh = ClassDB::is_parent_class(res_type, "Mesh");
+ bool is_material = ClassDB::is_parent_class(res_type, "Material");
+ bool is_texture = ClassDB::is_parent_class(res_type, "Texture");
+ bool is_audio = ClassDB::is_parent_class(res_type, "AudioStream");
+
+ if (is_mesh || is_scene || is_material || is_texture || is_audio) {
Ref<Resource> res = ResourceLoader::load(files[i]);
if (res.is_null()) {
continue;
@@ -4502,6 +4565,7 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
Ref<Mesh> mesh = res;
Ref<Material> mat = res;
Ref<Texture2D> tex = res;
+ Ref<AudioStream> audio = res;
if (scn.is_valid()) {
Node *instantiated_scene = scn->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
if (!instantiated_scene) {
@@ -4537,6 +4601,8 @@ bool Node3DEditorViewport::can_drop_data_fw(const Point2 &p_point, const Variant
spatial_editor->set_preview_material(new_mat);
is_other_valid = true;
continue;
+ } else if (!is_other_valid && audio.is_valid()) {
+ is_other_valid = true;
} else {
continue;
}
@@ -8410,7 +8476,7 @@ Node3DEditor::Node3DEditor() {
tool_button[TOOL_LOCK_SELECTED]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_LOCK_SELECTED));
tool_button[TOOL_LOCK_SELECTED]->set_tooltip_text(TTR("Lock selected node, preventing selection and movement."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/lock_selected_nodes", TTR("Lock Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::L));
+ tool_button[TOOL_LOCK_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/lock_selected_nodes"));
tool_button[TOOL_UNLOCK_SELECTED] = memnew(Button);
main_menu_hbox->add_child(tool_button[TOOL_UNLOCK_SELECTED]);
@@ -8418,7 +8484,7 @@ Node3DEditor::Node3DEditor() {
tool_button[TOOL_UNLOCK_SELECTED]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNLOCK_SELECTED));
tool_button[TOOL_UNLOCK_SELECTED]->set_tooltip_text(TTR("Unlock selected node, allowing selection and movement."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_SHORTCUT("editor/unlock_selected_nodes", TTR("Unlock Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::L));
+ tool_button[TOOL_UNLOCK_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/unlock_selected_nodes"));
tool_button[TOOL_GROUP_SELECTED] = memnew(Button);
main_menu_hbox->add_child(tool_button[TOOL_GROUP_SELECTED]);
@@ -8426,7 +8492,7 @@ Node3DEditor::Node3DEditor() {
tool_button[TOOL_GROUP_SELECTED]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_GROUP_SELECTED));
tool_button[TOOL_GROUP_SELECTED]->set_tooltip_text(TTR("Groups the selected node with its children. This selects the parent when any child node is clicked in 2D and 3D view."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/group_selected_nodes", TTR("Group Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | Key::G));
+ tool_button[TOOL_GROUP_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/group_selected_nodes"));
tool_button[TOOL_UNGROUP_SELECTED] = memnew(Button);
main_menu_hbox->add_child(tool_button[TOOL_UNGROUP_SELECTED]);
@@ -8434,7 +8500,7 @@ Node3DEditor::Node3DEditor() {
tool_button[TOOL_UNGROUP_SELECTED]->connect(SceneStringName(pressed), callable_mp(this, &Node3DEditor::_menu_item_pressed).bind(MENU_UNGROUP_SELECTED));
tool_button[TOOL_UNGROUP_SELECTED]->set_tooltip_text(TTR("Ungroups the selected node from its children. Child nodes will be individual items in 2D and 3D view."));
// Define the shortcut globally (without a context) so that it works if the Scene tree dock is currently focused.
- tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_SHORTCUT("editor/ungroup_selected_nodes", TTR("Ungroup Selected Node(s)"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::G));
+ tool_button[TOOL_UNGROUP_SELECTED]->set_shortcut(ED_GET_SHORTCUT("editor/ungroup_selected_nodes"));
main_menu_hbox->add_child(memnew(VSeparator));
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index a3e1224cb8..4990b11a47 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -443,7 +443,8 @@ private:
void _reset_preview_material() const;
void _remove_preview_material();
bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node) const;
- bool _create_instance(Node *parent, String &path, const Point2 &p_point);
+ bool _create_instance(Node *p_parent, const String &p_path, const Point2 &p_point);
+ bool _create_audio_node(Node *p_parent, const String &p_path, const Point2 &p_point);
void _perform_drop_data();
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 63eecd357d..22dbb6e9f2 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -765,7 +765,7 @@ void ScriptEditor::_update_recent_scripts() {
}
recent_scripts->add_separator();
- recent_scripts->add_shortcut(ED_SHORTCUT("script_editor/clear_recent", TTR("Clear Recent Files")));
+ recent_scripts->add_shortcut(ED_GET_SHORTCUT("script_editor/clear_recent"));
recent_scripts->set_item_disabled(recent_scripts->get_item_id(recent_scripts->get_item_count() - 1), rc.is_empty());
recent_scripts->reset_size();
@@ -3591,13 +3591,13 @@ void ScriptEditor::_update_selected_editor_menu() {
script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), Key::F3), HELP_SEARCH_FIND_NEXT);
script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_previous", TTR("Find Previous"), KeyModifierMask::SHIFT | Key::F3), HELP_SEARCH_FIND_PREVIOUS);
script_search_menu->get_popup()->add_separator();
- script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::F), SEARCH_IN_FILES);
- script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/replace_in_files", TTR("Replace in Files"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::R), REPLACE_IN_FILES);
+ script_search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_editor/find_in_files"), SEARCH_IN_FILES);
+ script_search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_editor/replace_in_files"), REPLACE_IN_FILES);
script_search_menu->show();
} else {
if (tab_container->get_tab_count() == 0) {
- script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::F), SEARCH_IN_FILES);
- script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/replace_in_files", TTR("Replace in Files"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::R), REPLACE_IN_FILES);
+ script_search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_editor/find_in_files"), SEARCH_IN_FILES);
+ script_search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_editor/replace_in_files"), REPLACE_IN_FILES);
script_search_menu->show();
} else {
script_search_menu->hide();
@@ -4101,7 +4101,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new", TTR("New Script..."), KeyModifierMask::CMD_OR_CTRL | Key::N), FILE_NEW);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new_textfile", TTR("New Text File..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::N), FILE_NEW_TEXTFILE);
file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/open", TTR("Open...")), FILE_OPEN);
- file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reopen_closed_script", TTR("Reopen Closed Script"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::T), FILE_REOPEN_CLOSED);
+ file_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_editor/reopen_closed_script"), FILE_REOPEN_CLOSED);
recent_scripts = memnew(PopupMenu);
file_menu->get_popup()->add_submenu_node_item(TTR("Open Recent"), recent_scripts, FILE_OPEN_RECENT);
@@ -4502,6 +4502,15 @@ void ScriptEditorPlugin::edited_scene_changed() {
}
ScriptEditorPlugin::ScriptEditorPlugin() {
+ ED_SHORTCUT("script_editor/reopen_closed_script", TTR("Reopen Closed Script"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::T);
+ ED_SHORTCUT("script_editor/clear_recent", TTR("Clear Recent Scripts"));
+ ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::F);
+ ED_SHORTCUT("script_editor/replace_in_files", TTR("Replace in Files"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::R);
+
+ ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KeyModifierMask::SHIFT | Key::F4);
+ ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase"), KeyModifierMask::SHIFT | Key::F5);
+ ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KeyModifierMask::SHIFT | Key::F6);
+
window_wrapper = memnew(WindowWrapper);
window_wrapper->set_window_title(vformat(TTR("%s - Godot Engine"), TTR("Script Editor")));
window_wrapper->set_margins_enabled(true);
@@ -4530,9 +4539,6 @@ ScriptEditorPlugin::ScriptEditorPlugin() {
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "text_editor/external/exec_path", PROPERTY_HINT_GLOBAL_FILE));
EDITOR_DEF("text_editor/external/exec_flags", "{file}");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "text_editor/external/exec_flags", PROPERTY_HINT_PLACEHOLDER_TEXT, "Call flags with placeholders: {project}, {file}, {col}, {line}."));
-
- ED_SHORTCUT("script_editor/reopen_closed_script", TTR("Reopen Closed Script"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::T);
- ED_SHORTCUT("script_editor/clear_recent", TTR("Clear Recent Scripts"));
}
ScriptEditorPlugin::~ScriptEditorPlugin() {
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 191d58228b..a5d89ff54c 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -2133,10 +2133,11 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
void ScriptTextEditor::_color_changed(const Color &p_color) {
String new_args;
+ const int decimals = 3;
if (p_color.a == 1.0f) {
- new_args = String("(" + rtos(p_color.r) + ", " + rtos(p_color.g) + ", " + rtos(p_color.b) + ")");
+ new_args = String("(" + String::num(p_color.r, decimals) + ", " + String::num(p_color.g, decimals) + ", " + String::num(p_color.b, decimals) + ")");
} else {
- new_args = String("(" + rtos(p_color.r) + ", " + rtos(p_color.g) + ", " + rtos(p_color.b) + ", " + rtos(p_color.a) + ")");
+ new_args = String("(" + String::num(p_color.r, decimals) + ", " + String::num(p_color.g, decimals) + ", " + String::num(p_color.b, decimals) + ", " + String::num(p_color.a, decimals) + ")");
}
String line = code_editor->get_text_editor()->get_line(color_position.x);
@@ -2311,9 +2312,9 @@ void ScriptTextEditor::_enable_code_editor() {
edit_menu->get_popup()->add_separator();
{
PopupMenu *sub_menu = memnew(PopupMenu);
- sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KeyModifierMask::SHIFT | Key::F4), EDIT_TO_UPPERCASE);
- sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase"), KeyModifierMask::SHIFT | Key::F5), EDIT_TO_LOWERCASE);
- sub_menu->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KeyModifierMask::SHIFT | Key::F6), EDIT_CAPITALIZE);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/capitalize"), EDIT_CAPITALIZE);
sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
edit_menu->get_popup()->add_submenu_node_item(TTR("Convert Case"), sub_menu);
}
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 2aa04d7874..5bc3cafe19 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -647,9 +647,9 @@ TextEditor::TextEditor() {
edit_menu->get_popup()->add_separator();
PopupMenu *convert_case = memnew(PopupMenu);
edit_menu->get_popup()->add_submenu_node_item(TTR("Convert Case"), convert_case);
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase")), EDIT_TO_UPPERCASE);
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase")), EDIT_TO_LOWERCASE);
- convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize")), EDIT_CAPITALIZE);
+ convert_case->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE);
+ convert_case->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE);
+ convert_case->add_shortcut(ED_GET_SHORTCUT("script_text_editor/capitalize"), EDIT_CAPITALIZE);
convert_case->connect("id_pressed", callable_mp(this, &TextEditor::_edit_option));
highlighter_menu = memnew(PopupMenu);
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index 2ee0dc0316..2b86268414 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -250,7 +250,7 @@ void TileAtlasView::_draw_base_tiles() {
Vector2 offset_pos = Rect2(base_frame_rect).get_center() + Vector2(tile_set_atlas_source->get_tile_data(atlas_coords, 0)->get_texture_origin());
// Draw the tile.
- TileMap::draw_tile(ci_rid, offset_pos, tile_set, source_id, atlas_coords, 0, frame);
+ TileMapLayer::draw_tile(ci_rid, offset_pos, tile_set, source_id, atlas_coords, 0, frame);
}
}
@@ -411,7 +411,7 @@ void TileAtlasView::_draw_alternatives() {
}
// Draw the tile.
- TileMap::draw_tile(ci_rid, offset_pos, tile_set, source_id, atlas_coords, alternative_id);
+ TileMapLayer::draw_tile(ci_rid, offset_pos, tile_set, source_id, atlas_coords, alternative_id);
// Increment the x position.
current_pos.x += transposed ? texture_region_size.y : texture_region_size.x;
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index 2d0e5214db..a94080e253 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -144,7 +144,8 @@ void GenericTilePolygonEditor::_base_control_draw() {
}
// Draw tile-related things.
- Size2 tile_size = tile_set->get_tile_size();
+ const Size2 base_tile_size = tile_set->get_tile_size();
+ const Size2 tile_size = background_region.size;
Transform2D xform;
xform.set_origin(base_control->get_size() / 2 + panning);
@@ -170,12 +171,16 @@ void GenericTilePolygonEditor::_base_control_draw() {
// Draw grid.
if (current_snap_option == SNAP_GRID) {
- Vector2 spacing = tile_size / snap_subdivision->get_value();
+ Vector2 spacing = base_tile_size / snap_subdivision->get_value();
Vector2 offset = -tile_size / 2;
+ int w = snap_subdivision->get_value() * (tile_size / base_tile_size).x;
+ int h = snap_subdivision->get_value() * (tile_size / base_tile_size).y;
- for (int i = 1; i < snap_subdivision->get_value(); i++) {
- base_control->draw_line(Vector2(spacing.x * i, 0) + offset, Vector2(spacing.x * i, tile_size.y) + offset, Color(1, 1, 1, 0.33));
- base_control->draw_line(Vector2(0, spacing.y * i) + offset, Vector2(tile_size.x, spacing.y * i) + offset, Color(1, 1, 1, 0.33));
+ for (int y = 1; y < h; y++) {
+ for (int x = 1; x < w; x++) {
+ base_control->draw_line(Vector2(spacing.x * x, 0) + offset, Vector2(spacing.x * x, tile_size.y) + offset, Color(1, 1, 1, 0.33));
+ base_control->draw_line(Vector2(0, spacing.y * y) + offset, Vector2(tile_size.x, spacing.y * y) + offset, Color(1, 1, 1, 0.33));
+ }
}
}
@@ -1320,7 +1325,7 @@ TileDataDefaultEditor::TileDataDefaultEditor() {
picker_button = memnew(Button);
picker_button->set_theme_type_variation("FlatButton");
picker_button->set_toggle_mode(true);
- picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", TTR("Picker"), Key::P));
+ picker_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/picker"));
toolbar->add_child(picker_button);
}
@@ -2807,7 +2812,7 @@ TileDataTerrainsEditor::TileDataTerrainsEditor() {
picker_button = memnew(Button);
picker_button->set_theme_type_variation("FlatButton");
picker_button->set_toggle_mode(true);
- picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", TTR("Picker"), Key::P));
+ picker_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/picker"));
toolbar->add_child(picker_button);
// Setup
diff --git a/editor/plugins/tiles/tile_map_layer_editor.cpp b/editor/plugins/tiles/tile_map_layer_editor.cpp
index 98c05e9b15..5fd4fb3602 100644
--- a/editor/plugins/tiles/tile_map_layer_editor.cpp
+++ b/editor/plugins/tiles/tile_map_layer_editor.cpp
@@ -2183,13 +2183,6 @@ TileMapLayerEditorTilesPlugin::TileMapLayerEditorTilesPlugin() {
->get_viewport_control()
->connect(SceneStringName(mouse_exited), callable_mp(this, &TileMapLayerEditorTilesPlugin::_mouse_exited_viewport));
- // --- Shortcuts ---
- ED_SHORTCUT("tiles_editor/cut", TTR("Cut"), KeyModifierMask::CMD_OR_CTRL | Key::X);
- ED_SHORTCUT("tiles_editor/copy", TTR("Copy"), KeyModifierMask::CMD_OR_CTRL | Key::C);
- ED_SHORTCUT("tiles_editor/paste", TTR("Paste"), KeyModifierMask::CMD_OR_CTRL | Key::V);
- ED_SHORTCUT("tiles_editor/cancel", TTR("Cancel"), Key::ESCAPE);
- ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), Key::KEY_DELETE);
-
// --- Initialize references ---
tile_map_clipboard.instantiate();
selection_pattern.instantiate();
@@ -2217,7 +2210,7 @@ TileMapLayerEditorTilesPlugin::TileMapLayerEditorTilesPlugin() {
paint_tool_button->set_theme_type_variation("FlatButton");
paint_tool_button->set_toggle_mode(true);
paint_tool_button->set_button_group(tool_buttons_group);
- paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", TTR("Paint"), Key::D));
+ paint_tool_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/paint_tool"));
paint_tool_button->set_tooltip_text(TTR("Shift: Draw line.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Shift: Draw rectangle."));
paint_tool_button->connect(SceneStringName(pressed), callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(paint_tool_button);
@@ -2228,7 +2221,7 @@ TileMapLayerEditorTilesPlugin::TileMapLayerEditorTilesPlugin() {
line_tool_button->set_toggle_mode(true);
line_tool_button->set_button_group(tool_buttons_group);
// TRANSLATORS: This refers to the line tool in the tilemap editor.
- line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", TTR("Line", "Tool"), Key::L));
+ line_tool_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/line_tool"));
line_tool_button->connect(SceneStringName(pressed), callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(line_tool_button);
viewport_shortcut_buttons.push_back(line_tool_button);
@@ -2237,7 +2230,7 @@ TileMapLayerEditorTilesPlugin::TileMapLayerEditorTilesPlugin() {
rect_tool_button->set_theme_type_variation("FlatButton");
rect_tool_button->set_toggle_mode(true);
rect_tool_button->set_button_group(tool_buttons_group);
- rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", TTR("Rect"), Key::R));
+ rect_tool_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/rect_tool"));
rect_tool_button->connect(SceneStringName(pressed), callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(rect_tool_button);
viewport_shortcut_buttons.push_back(rect_tool_button);
@@ -2246,7 +2239,7 @@ TileMapLayerEditorTilesPlugin::TileMapLayerEditorTilesPlugin() {
bucket_tool_button->set_theme_type_variation("FlatButton");
bucket_tool_button->set_toggle_mode(true);
bucket_tool_button->set_button_group(tool_buttons_group);
- bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", TTR("Bucket"), Key::B));
+ bucket_tool_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/bucket_tool"));
bucket_tool_button->connect(SceneStringName(pressed), callable_mp(this, &TileMapLayerEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(bucket_tool_button);
toolbar->add_child(tilemap_tiles_tools_buttons);
@@ -2263,7 +2256,7 @@ TileMapLayerEditorTilesPlugin::TileMapLayerEditorTilesPlugin() {
picker_button = memnew(Button);
picker_button->set_theme_type_variation("FlatButton");
picker_button->set_toggle_mode(true);
- picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", TTR("Picker"), Key::P));
+ picker_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/picker"));
Key key = (OS::get_singleton()->has_feature("macos") || OS::get_singleton()->has_feature("web_macos") || OS::get_singleton()->has_feature("web_ios")) ? Key::META : Key::CTRL;
picker_button->set_tooltip_text(vformat(TTR("Alternatively hold %s with other tools to pick tile."), find_keycode_name(key)));
picker_button->connect(SceneStringName(pressed), callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
@@ -2274,7 +2267,7 @@ TileMapLayerEditorTilesPlugin::TileMapLayerEditorTilesPlugin() {
erase_button = memnew(Button);
erase_button->set_theme_type_variation("FlatButton");
erase_button->set_toggle_mode(true);
- erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", TTR("Eraser"), Key::E));
+ erase_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/eraser"));
erase_button->set_tooltip_text(TTR("Alternatively use RMB to erase tiles."));
erase_button->connect(SceneStringName(pressed), callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(erase_button);
@@ -3552,7 +3545,7 @@ TileMapLayerEditorTerrainsPlugin::TileMapLayerEditorTerrainsPlugin() {
paint_tool_button->set_toggle_mode(true);
paint_tool_button->set_button_group(tool_buttons_group);
paint_tool_button->set_pressed(true);
- paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", TTR("Paint"), Key::D));
+ paint_tool_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/paint_tool"));
paint_tool_button->connect(SceneStringName(pressed), callable_mp(this, &TileMapLayerEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(paint_tool_button);
viewport_shortcut_buttons.push_back(paint_tool_button);
@@ -3561,7 +3554,7 @@ TileMapLayerEditorTerrainsPlugin::TileMapLayerEditorTerrainsPlugin() {
line_tool_button->set_theme_type_variation("FlatButton");
line_tool_button->set_toggle_mode(true);
line_tool_button->set_button_group(tool_buttons_group);
- line_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/line_tool", TTR("Line"), Key::L));
+ line_tool_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/line_tool"));
line_tool_button->connect(SceneStringName(pressed), callable_mp(this, &TileMapLayerEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(line_tool_button);
viewport_shortcut_buttons.push_back(line_tool_button);
@@ -3570,7 +3563,7 @@ TileMapLayerEditorTerrainsPlugin::TileMapLayerEditorTerrainsPlugin() {
rect_tool_button->set_theme_type_variation("FlatButton");
rect_tool_button->set_toggle_mode(true);
rect_tool_button->set_button_group(tool_buttons_group);
- rect_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/rect_tool", TTR("Rect"), Key::R));
+ rect_tool_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/rect_tool"));
rect_tool_button->connect(SceneStringName(pressed), callable_mp(this, &TileMapLayerEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(rect_tool_button);
viewport_shortcut_buttons.push_back(rect_tool_button);
@@ -3579,7 +3572,7 @@ TileMapLayerEditorTerrainsPlugin::TileMapLayerEditorTerrainsPlugin() {
bucket_tool_button->set_theme_type_variation("FlatButton");
bucket_tool_button->set_toggle_mode(true);
bucket_tool_button->set_button_group(tool_buttons_group);
- bucket_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/bucket_tool", TTR("Bucket"), Key::B));
+ bucket_tool_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/bucket_tool"));
bucket_tool_button->connect(SceneStringName(pressed), callable_mp(this, &TileMapLayerEditorTerrainsPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(bucket_tool_button);
viewport_shortcut_buttons.push_back(bucket_tool_button);
@@ -3597,7 +3590,7 @@ TileMapLayerEditorTerrainsPlugin::TileMapLayerEditorTerrainsPlugin() {
picker_button = memnew(Button);
picker_button->set_theme_type_variation("FlatButton");
picker_button->set_toggle_mode(true);
- picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", TTR("Picker"), Key::P));
+ picker_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/picker"));
picker_button->connect(SceneStringName(pressed), callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(picker_button);
viewport_shortcut_buttons.push_back(picker_button);
@@ -3606,7 +3599,7 @@ TileMapLayerEditorTerrainsPlugin::TileMapLayerEditorTerrainsPlugin() {
erase_button = memnew(Button);
erase_button->set_theme_type_variation("FlatButton");
erase_button->set_toggle_mode(true);
- erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", TTR("Eraser"), Key::E));
+ erase_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/eraser"));
erase_button->connect(SceneStringName(pressed), callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(erase_button);
viewport_shortcut_buttons.push_back(erase_button);
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index e4fd32a637..1daba1f665 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -2627,7 +2627,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tools_settings_erase_button = memnew(Button);
tools_settings_erase_button->set_theme_type_variation("FlatButton");
tools_settings_erase_button->set_toggle_mode(true);
- tools_settings_erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", TTR("Eraser"), Key::E));
+ tools_settings_erase_button->set_shortcut(ED_GET_SHORTCUT("tiles_editor/eraser"));
tools_settings_erase_button->set_shortcut_context(this);
tool_settings->add_child(tools_settings_erase_button);
@@ -2687,7 +2687,7 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
tile_create_help->set_grow_direction_preset(Control::PRESET_BOTTOM_LEFT);
base_tile_popup_menu = memnew(PopupMenu);
- base_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), Key::KEY_DELETE), TILE_DELETE);
+ base_tile_popup_menu->add_shortcut(ED_GET_SHORTCUT("tiles_editor/delete"), TILE_DELETE);
base_tile_popup_menu->add_item(TTR("Create an Alternative Tile"), TILE_CREATE_ALTERNATIVE);
base_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
tile_atlas_view->add_child(base_tile_popup_menu);
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index 6833a36138..f1cc69ce18 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -303,6 +303,19 @@ TilesEditorUtils::TilesEditorUtils() {
singleton = this;
// Pattern preview generation thread.
pattern_preview_thread.start(_thread_func, this);
+
+ ED_SHORTCUT("tiles_editor/cut", TTR("Cut"), KeyModifierMask::CMD_OR_CTRL | Key::X);
+ ED_SHORTCUT("tiles_editor/copy", TTR("Copy"), KeyModifierMask::CMD_OR_CTRL | Key::C);
+ ED_SHORTCUT("tiles_editor/paste", TTR("Paste"), KeyModifierMask::CMD_OR_CTRL | Key::V);
+ ED_SHORTCUT("tiles_editor/cancel", TTR("Cancel"), Key::ESCAPE);
+ ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), Key::KEY_DELETE);
+
+ ED_SHORTCUT("tiles_editor/paint_tool", TTR("Paint"), Key::D);
+ ED_SHORTCUT("tiles_editor/line_tool", TTR("Line", "Tool"), Key::L);
+ ED_SHORTCUT("tiles_editor/rect_tool", TTR("Rect"), Key::R);
+ ED_SHORTCUT("tiles_editor/bucket_tool", TTR("Bucket"), Key::B);
+ ED_SHORTCUT("tiles_editor/eraser", TTR("Eraser"), Key::E);
+ ED_SHORTCUT("tiles_editor/picker", TTR("Picker"), Key::P);
}
TilesEditorUtils::~TilesEditorUtils() {
diff --git a/editor/project_manager/project_list.cpp b/editor/project_manager/project_list.cpp
index 32f088ec60..f474464f6c 100644
--- a/editor/project_manager/project_list.cpp
+++ b/editor/project_manager/project_list.cpp
@@ -32,6 +32,8 @@
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
+#include "core/os/time.h"
+#include "core/version.h"
#include "editor/editor_paths.h"
#include "editor/editor_settings.h"
#include "editor/editor_string_names.h"
@@ -130,12 +132,29 @@ void ProjectListItemControl::set_project_icon(const Ref<Texture2D> &p_icon) {
project_icon->set_texture(p_icon);
}
+void ProjectListItemControl::set_last_edited_info(const String &p_info) {
+ last_edited_info->set_text(p_info);
+}
+
+void ProjectListItemControl::set_project_version(const String &p_info) {
+ project_version->set_text(p_info);
+}
+
void ProjectListItemControl::set_unsupported_features(PackedStringArray p_features) {
if (p_features.size() > 0) {
String tooltip_text = "";
for (int i = 0; i < p_features.size(); i++) {
if (ProjectList::project_feature_looks_like_version(p_features[i])) {
- tooltip_text += TTR("This project was last edited in a different Godot version: ") + p_features[i] + "\n";
+ PackedStringArray project_version_split = p_features[i].split(".");
+ int project_version_major = 0, project_version_minor = 0;
+ if (project_version_split.size() >= 2) {
+ project_version_major = project_version_split[0].to_int();
+ project_version_minor = project_version_split[1].to_int();
+ }
+ if (VERSION_MAJOR != project_version_major || VERSION_MINOR <= project_version_minor) {
+ // Don't show a warning if the project was last edited in a previous minor version.
+ tooltip_text += TTR("This project was last edited in a different Godot version: ") + p_features[i] + "\n";
+ }
p_features.remove_at(i);
i--;
}
@@ -144,6 +163,10 @@ void ProjectListItemControl::set_unsupported_features(PackedStringArray p_featur
String unsupported_features_str = String(", ").join(p_features);
tooltip_text += TTR("This project uses features unsupported by the current build:") + "\n" + unsupported_features_str;
}
+ if (tooltip_text.is_empty()) {
+ return;
+ }
+ project_version->set_tooltip_text(tooltip_text);
project_unsupported_features->set_tooltip_text(tooltip_text);
project_unsupported_features->show();
} else {
@@ -272,12 +295,24 @@ ProjectListItemControl::ProjectListItemControl() {
project_path->set_modulate(Color(1, 1, 1, 0.5));
path_hb->add_child(project_path);
+ last_edited_info = memnew(Label);
+ last_edited_info->set_name("LastEditedInfo");
+ last_edited_info->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ last_edited_info->set_tooltip_text("Last edited timestamp");
+ last_edited_info->set_modulate(Color(1, 1, 1, 0.5));
+ path_hb->add_child(last_edited_info);
+
project_unsupported_features = memnew(TextureRect);
project_unsupported_features->set_name("ProjectUnsupportedFeatures");
project_unsupported_features->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
path_hb->add_child(project_unsupported_features);
project_unsupported_features->hide();
+ project_version = memnew(Label);
+ project_version->set_name("ProjectVersion");
+ project_version->set_mouse_filter(Control::MOUSE_FILTER_PASS);
+ path_hb->add_child(project_version);
+
Control *spacer = memnew(Control);
spacer->set_custom_minimum_size(Size2(10, 10));
path_hb->add_child(spacer);
@@ -409,6 +444,24 @@ ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_fa
PackedStringArray project_features = cf->get_value("application", "config/features", PackedStringArray());
PackedStringArray unsupported_features = ProjectSettings::get_unsupported_features(project_features);
+ String project_version = "?";
+ for (int i = 0; i < project_features.size(); i++) {
+ if (ProjectList::project_feature_looks_like_version(project_features[i])) {
+ project_version = project_features[i];
+ break;
+ }
+ }
+
+ if (config_version < ProjectSettings::CONFIG_VERSION) {
+ // Previous versions may not have unsupported features.
+ if (config_version == 4) {
+ unsupported_features.push_back("3.x");
+ project_version = "3.x";
+ } else {
+ unsupported_features.push_back("Unknown version");
+ }
+ }
+
uint64_t last_edited = 0;
if (cf_err == OK) {
// The modification date marks the date the project was last edited.
@@ -433,7 +486,7 @@ ProjectList::Item ProjectList::load_project_data(const String &p_path, bool p_fa
ProjectManager::get_singleton()->add_new_tag(tag);
}
- return Item(project_name, description, tags, p_path, icon, main_scene, unsupported_features, last_edited, p_favorite, grayed, missing, config_version);
+ return Item(project_name, description, project_version, tags, p_path, icon, main_scene, unsupported_features, last_edited, p_favorite, grayed, missing, config_version);
}
void ProjectList::_update_icons_async() {
@@ -706,6 +759,8 @@ void ProjectList::_create_project_item_control(int p_index) {
hb->set_tooltip_text(item.description);
hb->set_tags(item.tags, this);
hb->set_unsupported_features(item.unsupported_features.duplicate());
+ hb->set_project_version(item.project_version);
+ hb->set_last_edited_info(Time::get_singleton()->get_datetime_string_from_unix_time(item.last_edited, true));
hb->set_is_favorite(item.favorite);
hb->set_is_missing(item.missing);
diff --git a/editor/project_manager/project_list.h b/editor/project_manager/project_list.h
index 981df0f3a0..6e0f5830ac 100644
--- a/editor/project_manager/project_list.h
+++ b/editor/project_manager/project_list.h
@@ -51,6 +51,8 @@ class ProjectListItemControl : public HBoxContainer {
TextureRect *project_icon = nullptr;
Label *project_title = nullptr;
Label *project_path = nullptr;
+ Label *last_edited_info = nullptr;
+ Label *project_version = nullptr;
TextureRect *project_unsupported_features = nullptr;
HBoxContainer *tag_container = nullptr;
@@ -71,6 +73,8 @@ public:
void set_project_path(const String &p_path);
void set_tags(const PackedStringArray &p_tags, ProjectList *p_parent_list);
void set_project_icon(const Ref<Texture2D> &p_icon);
+ void set_last_edited_info(const String &p_info);
+ void set_project_version(const String &p_version);
void set_unsupported_features(PackedStringArray p_features);
bool should_load_project_icon() const;
@@ -100,6 +104,7 @@ public:
struct Item {
String project_name;
String description;
+ String project_version;
PackedStringArray tags;
String tag_sort_string;
String path;
@@ -118,6 +123,7 @@ public:
Item(const String &p_name,
const String &p_description,
+ const String &p_project_version,
const PackedStringArray &p_tags,
const String &p_path,
const String &p_icon,
@@ -130,6 +136,7 @@ public:
int p_version) {
project_name = p_name;
description = p_description;
+ project_version = p_project_version;
tags = p_tags;
path = p_path;
icon = p_icon;
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index cff95cadc8..dc9d1df4e8 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -54,7 +54,7 @@ void ProjectSettingsEditor::popup_project_settings(bool p_clear_filter) {
if (saved_size != Rect2()) {
popup(saved_size);
} else {
- popup_centered_clamped(Size2(900, 700) * EDSCALE, 0.8);
+ popup_centered_clamped(Size2(1200, 700) * EDSCALE, 0.8);
}
_add_feature_overrides();
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 51f9d319a6..edefaa61a8 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -289,6 +289,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor) {
vbc->add_child(lbl_preview_title);
lbl_preview = memnew(Label);
+ lbl_preview->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
lbl_preview->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
vbc->add_child(lbl_preview);
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 53145c3450..ec0380f964 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -56,6 +56,7 @@
#include "editor/shader_create_dialog.h"
#include "editor/themes/editor_scale.h"
#include "scene/animation/animation_tree.h"
+#include "scene/audio/audio_stream_player.h"
#include "scene/gui/check_box.h"
#include "scene/property_utils.h"
#include "scene/resources/packed_scene.h"
@@ -254,8 +255,8 @@ void SceneTreeDock::instantiate_scenes(const Vector<String> &p_files, Node *p_pa
_perform_instantiate_scenes(p_files, parent, -1);
}
-void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, Node *parent, int p_pos) {
- ERR_FAIL_NULL(parent);
+void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, Node *p_parent, int p_pos) {
+ ERR_FAIL_NULL(p_parent);
Vector<Node *> instances;
@@ -302,25 +303,25 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Instantiate Scene(s)"));
+ undo_redo->create_action_for_history(TTRN("Instantiate Scene", "Instantiate Scenes", instances.size()), editor_data->get_current_edited_scene_history_id());
+ undo_redo->add_do_method(editor_selection, "clear");
for (int i = 0; i < instances.size(); i++) {
Node *instantiated_scene = instances[i];
- undo_redo->add_do_method(parent, "add_child", instantiated_scene, true);
+ undo_redo->add_do_method(p_parent, "add_child", instantiated_scene, true);
if (p_pos >= 0) {
- undo_redo->add_do_method(parent, "move_child", instantiated_scene, p_pos + i);
+ undo_redo->add_do_method(p_parent, "move_child", instantiated_scene, p_pos + i);
}
undo_redo->add_do_method(instantiated_scene, "set_owner", edited_scene);
- undo_redo->add_do_method(editor_selection, "clear");
undo_redo->add_do_method(editor_selection, "add_node", instantiated_scene);
undo_redo->add_do_reference(instantiated_scene);
- undo_redo->add_undo_method(parent, "remove_child", instantiated_scene);
+ undo_redo->add_undo_method(p_parent, "remove_child", instantiated_scene);
- String new_name = parent->validate_child_name(instantiated_scene);
+ String new_name = p_parent->validate_child_name(instantiated_scene);
EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
- undo_redo->add_do_method(ed, "live_debug_instantiate_node", edited_scene->get_path_to(parent), p_files[i], new_name);
- undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(parent)).path_join(new_name)));
+ undo_redo->add_do_method(ed, "live_debug_instantiate_node", edited_scene->get_path_to(p_parent), p_files[i], new_name);
+ undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).path_join(new_name)));
}
undo_redo->commit_action();
@@ -330,6 +331,75 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N
}
}
+void SceneTreeDock::_perform_create_audio_stream_players(const Vector<String> &p_files, Node *p_parent, int p_pos) {
+ ERR_FAIL_NULL(p_parent);
+
+ StringName node_type = "AudioStreamPlayer";
+ if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
+ if (Object::cast_to<Node2D>(p_parent)) {
+ node_type = "AudioStreamPlayer2D";
+ } else if (Object::cast_to<Node3D>(p_parent)) {
+ node_type = "AudioStreamPlayer3D";
+ }
+ }
+
+ Vector<Node *> nodes;
+ bool error = false;
+
+ for (const String &path : p_files) {
+ Ref<AudioStream> stream = ResourceLoader::load(path);
+ if (stream.is_null()) {
+ current_option = -1;
+ accept->set_text(vformat(TTR("Error loading audio stream from %s"), path));
+ accept->popup_centered();
+ error = true;
+ break;
+ }
+
+ Node *player = Object::cast_to<Node>(ClassDB::instantiate(node_type));
+ player->set("stream", stream);
+
+ // Adjust casing according to project setting. The file name is expected to be in snake_case, but will work for others.
+ const String &node_name = Node::adjust_name_casing(path.get_file().get_basename());
+ if (!node_name.is_empty()) {
+ player->set_name(node_name);
+ }
+
+ nodes.push_back(player);
+ }
+
+ if (error) {
+ for (Node *node : nodes) {
+ memdelete(node);
+ }
+ return;
+ }
+
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action_for_history(TTRN("Create AudioStreamPlayer", "Create AudioStreamPlayers", nodes.size()), editor_data->get_current_edited_scene_history_id());
+ undo_redo->add_do_method(editor_selection, "clear");
+
+ for (int i = 0; i < nodes.size(); i++) {
+ Node *node = nodes[i];
+
+ undo_redo->add_do_method(p_parent, "add_child", node, true);
+ if (p_pos >= 0) {
+ undo_redo->add_do_method(p_parent, "move_child", node, p_pos + i);
+ }
+ undo_redo->add_do_method(node, "set_owner", edited_scene);
+ undo_redo->add_do_method(editor_selection, "add_node", node);
+ undo_redo->add_do_reference(node);
+ undo_redo->add_undo_method(p_parent, "remove_child", node);
+
+ String new_name = p_parent->validate_child_name(node);
+ EditorDebuggerNode *ed = EditorDebuggerNode::get_singleton();
+ undo_redo->add_do_method(ed, "live_debug_create_node", edited_scene->get_path_to(p_parent), node->get_class(), new_name);
+ undo_redo->add_undo_method(ed, "live_debug_remove_node", NodePath(String(edited_scene->get_path_to(p_parent)).path_join(new_name)));
+ }
+
+ undo_redo->commit_action();
+}
+
void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base) {
// `move_child` + `get_index` doesn't really work for internal nodes.
ERR_FAIL_COND_MSG(base->get_internal_mode() != INTERNAL_MODE_DISABLED, "Trying to replace internal node, this is not supported.");
@@ -3196,15 +3266,13 @@ void SceneTreeDock::_normalize_drop(Node *&to_node, int &to_pos, int p_type) {
void SceneTreeDock::_files_dropped(const Vector<String> &p_files, NodePath p_to, int p_type) {
Node *node = get_node(p_to);
ERR_FAIL_NULL(node);
+ ERR_FAIL_COND(p_files.is_empty());
- if (scene_tree->get_scene_tree()->get_drop_mode_flags() & Tree::DROP_MODE_INBETWEEN) {
- // Dropped PackedScene, instance it.
- int to_pos = -1;
- _normalize_drop(node, to_pos, p_type);
- _perform_instantiate_scenes(p_files, node, to_pos);
- } else {
- const String &res_path = p_files[0];
- StringName res_type = EditorFileSystem::get_singleton()->get_file_type(res_path);
+ const String &res_path = p_files[0];
+ const StringName res_type = EditorFileSystem::get_singleton()->get_file_type(res_path);
+
+ // Dropping as property when possible.
+ if (p_type == 0 && p_files.size() == 1) {
List<String> valid_properties;
List<PropertyInfo> pinfo;
@@ -3238,10 +3306,22 @@ void SceneTreeDock::_files_dropped(const Vector<String> &p_files, NodePath p_to,
menu_properties->reset_size();
menu_properties->set_position(get_screen_position() + get_local_mouse_position());
menu_properties->popup();
- } else if (!valid_properties.is_empty()) {
+ return;
+ }
+ if (!valid_properties.is_empty()) {
_perform_property_drop(node, valid_properties.front()->get(), ResourceLoader::load(res_path));
+ return;
}
}
+
+ // Either instantiate scenes or create AudioStreamPlayers.
+ int to_pos = -1;
+ _normalize_drop(node, to_pos, p_type);
+ if (res_type == "PackedScene") {
+ _perform_instantiate_scenes(p_files, node, to_pos);
+ } else {
+ _perform_create_audio_stream_players(p_files, node, to_pos);
+ }
}
void SceneTreeDock::_script_dropped(const String &p_file, NodePath p_to) {
@@ -3571,7 +3651,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (profile_allow_editing) {
menu->add_separator();
- menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Remove")), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), Key::KEY_DELETE), TOOL_ERASE);
+ menu->add_icon_shortcut(get_editor_theme_icon(SNAME("Remove")), ED_GET_SHORTCUT("scene_tree/delete"), TOOL_ERASE);
}
menu->reset_size();
menu->set_position(p_menu_pos);
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index 21e1b00f93..abef990995 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -272,7 +272,8 @@ class SceneTreeDock : public VBoxContainer {
void _filter_option_selected(int option);
void _append_filter_options_to(PopupMenu *p_menu, bool p_include_separator = true);
- void _perform_instantiate_scenes(const Vector<String> &p_files, Node *parent, int p_pos);
+ void _perform_instantiate_scenes(const Vector<String> &p_files, Node *p_parent, int p_pos);
+ void _perform_create_audio_stream_players(const Vector<String> &p_files, Node *p_parent, int p_pos);
void _replace_with_branch_scene(const String &p_file, Node *base);
void _remote_tree_selected();
diff --git a/editor/themes/SCsub b/editor/themes/SCsub
index 65cfb6a8be..e8f96e4299 100644
--- a/editor/themes/SCsub
+++ b/editor/themes/SCsub
@@ -3,8 +3,8 @@
Import("env")
import glob
-import editor_theme_builders
+import editor_theme_builders
# Fonts
flist = glob.glob(env.Dir("#thirdparty").abspath + "/fonts/*.ttf")
diff --git a/gles3_builders.py b/gles3_builders.py
index 1491927feb..a4928c81c5 100644
--- a/gles3_builders.py
+++ b/gles3_builders.py
@@ -1,9 +1,10 @@
"""Functions used to generate source files during build time"""
import os.path
-from methods import print_error
from typing import Optional
+from methods import print_error
+
class GLES3HeaderStruct:
def __init__(self):
@@ -91,11 +92,11 @@ def include_file_in_gles3_header(filename: str, header_data: GLES3HeaderStruct,
includeline = line.replace("#include ", "").strip()[1:-1]
included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline)
- if not included_file in header_data.vertex_included_files and header_data.reading == "vertex":
+ if included_file not in header_data.vertex_included_files and header_data.reading == "vertex":
header_data.vertex_included_files += [included_file]
if include_file_in_gles3_header(included_file, header_data, depth + 1) is None:
print_error(f'In file "{filename}": #include "{includeline}" could not be found!"')
- elif not included_file in header_data.fragment_included_files and header_data.reading == "fragment":
+ elif included_file not in header_data.fragment_included_files and header_data.reading == "fragment":
header_data.fragment_included_files += [included_file]
if include_file_in_gles3_header(included_file, header_data, depth + 1) is None:
print_error(f'In file "{filename}": #include "{includeline}" could not be found!"')
@@ -121,7 +122,7 @@ def include_file_in_gles3_header(filename: str, header_data: GLES3HeaderStruct,
# unfiorm array
x = x[: x.find("[")]
- if not x in header_data.texunit_names:
+ if x not in header_data.texunit_names:
header_data.texunits += [(x, texunit)]
header_data.texunit_names += [x]
@@ -142,7 +143,7 @@ def include_file_in_gles3_header(filename: str, header_data: GLES3HeaderStruct,
# unfiorm array
x = x[: x.find("[")]
- if not x in header_data.ubo_names:
+ if x not in header_data.ubo_names:
header_data.ubos += [(x, ubo)]
header_data.ubo_names += [x]
@@ -157,7 +158,7 @@ def include_file_in_gles3_header(filename: str, header_data: GLES3HeaderStruct,
# unfiorm array
x = x[: x.find("[")]
- if not x in header_data.uniforms:
+ if x not in header_data.uniforms:
header_data.uniforms += [x]
if (line.strip().find("out ") == 0 or line.strip().find("flat ") == 0) and line.find("tfb:") != -1:
diff --git a/glsl_builders.py b/glsl_builders.py
index 22f4de74b1..05aab3acbb 100644
--- a/glsl_builders.py
+++ b/glsl_builders.py
@@ -1,8 +1,9 @@
"""Functions used to generate source files during build time"""
import os.path
+from typing import Iterable, Optional
+
from methods import print_error
-from typing import Optional, Iterable
def generate_inline_code(input_lines: Iterable[str], insert_newline: bool = True):
@@ -77,15 +78,15 @@ def include_file_in_rd_header(filename: str, header_data: RDHeaderStruct, depth:
else:
included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline)
- if not included_file in header_data.vertex_included_files and header_data.reading == "vertex":
+ if included_file not in header_data.vertex_included_files and header_data.reading == "vertex":
header_data.vertex_included_files += [included_file]
if include_file_in_rd_header(included_file, header_data, depth + 1) is None:
print_error(f'In file "{filename}": #include "{includeline}" could not be found!"')
- elif not included_file in header_data.fragment_included_files and header_data.reading == "fragment":
+ elif included_file not in header_data.fragment_included_files and header_data.reading == "fragment":
header_data.fragment_included_files += [included_file]
if include_file_in_rd_header(included_file, header_data, depth + 1) is None:
print_error(f'In file "{filename}": #include "{includeline}" could not be found!"')
- elif not included_file in header_data.compute_included_files and header_data.reading == "compute":
+ elif included_file not in header_data.compute_included_files and header_data.reading == "compute":
header_data.compute_included_files += [included_file]
if include_file_in_rd_header(included_file, header_data, depth + 1) is None:
print_error(f'In file "{filename}": #include "{includeline}" could not be found!"')
diff --git a/methods.py b/methods.py
index da221cc0ea..7600e6d445 100644
--- a/methods.py
+++ b/methods.py
@@ -1,17 +1,14 @@
+import contextlib
+import glob
import os
-import sys
import re
-import glob
import subprocess
-import contextlib
+import sys
from collections import OrderedDict
-from collections.abc import Mapping
from enum import Enum
-from typing import Generator, Optional
-from io import TextIOWrapper, StringIO
+from io import StringIO, TextIOWrapper
from pathlib import Path
-from os.path import normpath, basename
-
+from typing import Generator, Optional
# Get the "Godot" folder name ahead of time
base_folder_path = str(os.path.abspath(Path(__file__).parent)) + "/"
@@ -199,7 +196,7 @@ def add_module_version_string(self, s):
def get_version_info(module_version_string="", silent=False):
build_name = "custom_build"
- if os.getenv("BUILD_NAME") != None:
+ if os.getenv("BUILD_NAME") is not None:
build_name = str(os.getenv("BUILD_NAME"))
if not silent:
print(f"Using custom build name: '{build_name}'.")
@@ -221,7 +218,7 @@ def get_version_info(module_version_string="", silent=False):
# For dev snapshots (alpha, beta, RC, etc.) we do not commit status change to Git,
# so this define provides a way to override it without having to modify the source.
- if os.getenv("GODOT_VERSION_STATUS") != None:
+ if os.getenv("GODOT_VERSION_STATUS") is not None:
version_info["status"] = str(os.getenv("GODOT_VERSION_STATUS"))
if not silent:
print(f"Using version status '{version_info['status']}', overriding the original '{version.status}'.")
@@ -435,7 +432,7 @@ def module_check_dependencies(self, module):
required_deps = self.module_dependencies[module][0] if module in self.module_dependencies else []
for dep in required_deps:
opt = "module_{}_enabled".format(dep)
- if not opt in self or not self[opt]:
+ if opt not in self or not self[opt]:
missing_deps.append(dep)
if missing_deps != []:
@@ -450,7 +447,6 @@ def module_check_dependencies(self, module):
def sort_module_list(env):
- out = OrderedDict()
deps = {k: v[0] + list(filter(lambda x: x in env.module_list, v[1])) for k, v in env.module_dependencies.items()}
frontier = list(env.module_list.keys())
@@ -650,7 +646,7 @@ def detect_visual_c_compiler_version(tools_env):
def find_visual_c_batch_file(env):
- from SCons.Tool.MSCommon.vc import get_default_version, get_host_target, find_batch_file, find_vc_pdir
+ from SCons.Tool.MSCommon.vc import find_batch_file, find_vc_pdir, get_default_version, get_host_target
msvc_version = get_default_version(env)
@@ -696,10 +692,7 @@ def glob_recursive(pattern, node="."):
def add_to_vs_project(env, sources):
for x in sources:
- if type(x) == type(""):
- fname = env.File(x).path
- else:
- fname = env.File(x)[0].path
+ fname = env.File(x).path if isinstance(x, str) else env.File(x)[0].path
pieces = fname.split(".")
if len(pieces) > 0:
basename = pieces[0]
@@ -884,7 +877,8 @@ def show_progress(env):
return
import sys
- from SCons.Script import Progress, Command, AlwaysBuild
+
+ from SCons.Script import AlwaysBuild, Command, Progress
screen = sys.stdout
# Progress reporting is not available in non-TTY environments since it
@@ -895,7 +889,8 @@ def show_progress(env):
node_count_interval = 1
node_count_fname = str(env.Dir("#")) + "/.scons_node_count"
- import time, math
+ import math
+ import time
class cache_progress:
# The default is 1 GB cache and 12 hours half life
@@ -903,7 +898,7 @@ def show_progress(env):
self.path = path
self.limit = limit
self.exponent_scale = math.log(2) / half_life
- if env["verbose"] and path != None:
+ if env["verbose"] and path is not None:
screen.write(
"Current cache limit is {} (used: {})\n".format(
self.convert_size(limit), self.convert_size(self.get_size(path))
@@ -1049,11 +1044,11 @@ def generate_vs_project(env, original_args, project_name="godot"):
if type(f) is Node.FS.Dir:
results += glob_recursive_2(pattern, dirs, f)
r = Glob(str(node) + "/" + pattern, source=True)
- if len(r) > 0 and not str(node) in dirs:
+ if len(r) > 0 and str(node) not in dirs:
d = ""
for part in str(node).split("\\"):
d += part
- if not d in dirs:
+ if d not in dirs:
dirs.append(d)
d += "\\"
results += r
@@ -1066,7 +1061,7 @@ def generate_vs_project(env, original_args, project_name="godot"):
if val is not None:
try:
return _text2bool(val)
- except:
+ except (ValueError, AttributeError):
return default
else:
return default
@@ -1239,13 +1234,13 @@ def generate_vs_project(env, original_args, project_name="godot"):
others_active = []
for x in envsources:
fname = ""
- if type(x) == type(""):
+ if isinstance(x, str):
fname = env.File(x).path
else:
# Some object files might get added directly as a File object and not a list.
try:
fname = env.File(x)[0].path
- except:
+ except Exception:
fname = x.path
pass
@@ -1324,7 +1319,7 @@ def generate_vs_project(env, original_args, project_name="godot"):
itemlist = {}
for item in activeItems:
key = os.path.dirname(item).replace("\\", "_")
- if not key in itemlist:
+ if key not in itemlist:
itemlist[key] = [item]
else:
itemlist[key] += [item]
@@ -1465,14 +1460,14 @@ def generate_vs_project(env, original_args, project_name="godot"):
if godot_platform != "windows":
configurations += [
f'<ProjectConfiguration Include="editor|{proj_plat}">',
- f" <Configuration>editor</Configuration>",
+ " <Configuration>editor</Configuration>",
f" <Platform>{proj_plat}</Platform>",
"</ProjectConfiguration>",
]
properties += [
f"<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='editor|{proj_plat}'\">",
- f" <GodotConfiguration>editor</GodotConfiguration>",
+ " <GodotConfiguration>editor</GodotConfiguration>",
f" <GodotPlatform>{proj_plat}</GodotPlatform>",
"</PropertyGroup>",
]
diff --git a/misc/scripts/install_d3d12_sdk_windows.py b/misc/scripts/install_d3d12_sdk_windows.py
index aed80d81a4..d7574e6222 100755
--- a/misc/scripts/install_d3d12_sdk_windows.py
+++ b/misc/scripts/install_d3d12_sdk_windows.py
@@ -1,15 +1,15 @@
#!/usr/bin/env python
import os
-import urllib.request
import shutil
import subprocess
import sys
+import urllib.request
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
# <https://github.com/python/cpython/issues/73245>
if sys.platform == "win32":
- from ctypes import windll, c_int, byref
+ from ctypes import byref, c_int, windll
stdout_handle = windll.kernel32.GetStdHandle(c_int(-11))
mode = c_int(0)
diff --git a/modules/SCsub b/modules/SCsub
index 739c5de0b5..db0e563dc4 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -1,8 +1,9 @@
#!/usr/bin/env python
-import methods
import os
+import methods
+
Import("env")
env_modules = env.Clone()
diff --git a/modules/fbx/editor/editor_scene_importer_ufbx.cpp b/modules/fbx/editor/editor_scene_importer_ufbx.cpp
index 3cc919fae2..e0f60fe998 100644
--- a/modules/fbx/editor/editor_scene_importer_ufbx.cpp
+++ b/modules/fbx/editor/editor_scene_importer_ufbx.cpp
@@ -111,7 +111,7 @@ void EditorSceneFormatImporterUFBX::get_import_options(const String &p_path,
void EditorSceneFormatImporterUFBX::handle_compatibility_options(HashMap<StringName, Variant> &p_import_params) const {
if (!p_import_params.has("fbx/importer")) {
- p_import_params["fbx/importer"] = EditorSceneFormatImporterUFBX::FBX_IMPORTER_UFBX;
+ p_import_params["fbx/importer"] = EditorSceneFormatImporterUFBX::FBX_IMPORTER_FBX2GLTF;
}
}
diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py
index f9709362eb..efbf298f99 100755
--- a/modules/mono/build_scripts/build_assemblies.py
+++ b/modules/mono/build_scripts/build_assemblies.py
@@ -5,7 +5,7 @@ import os.path
import shlex
import subprocess
from dataclasses import dataclass
-from typing import Optional, List
+from typing import List, Optional
def find_dotnet_cli():
@@ -304,9 +304,7 @@ def generate_sdk_package_versions():
<GodotVersionConstants>{1}</GodotVersionConstants>
</PropertyGroup>
</Project>
-""".format(
- version_str, ";".join(version_defines)
- )
+""".format(version_str, ";".join(version_defines))
# We write in ../SdkPackageVersions.props.
with open(os.path.join(dirname(script_path), "SdkPackageVersions.props"), "w", encoding="utf-8", newline="\n") as f:
@@ -323,9 +321,7 @@ def generate_sdk_package_versions():
public const string VersionDocsUrl = "https://docs.godotengine.org/en/{docs_branch}";
}}
}}
-""".format(
- **version_info
- )
+""".format(**version_info)
generators_dir = os.path.join(
dirname(script_path),
diff --git a/modules/mono/build_scripts/mono_configure.py b/modules/mono/build_scripts/mono_configure.py
index e5469c4980..98c50dcc22 100644
--- a/modules/mono/build_scripts/mono_configure.py
+++ b/modules/mono/build_scripts/mono_configure.py
@@ -1,7 +1,3 @@
-import os
-import os.path
-
-
def is_desktop(platform):
return platform in ["windows", "macos", "linuxbsd"]
diff --git a/modules/mono/config.py b/modules/mono/config.py
index 3d087c9e27..5ebdb83b36 100644
--- a/modules/mono/config.py
+++ b/modules/mono/config.py
@@ -12,7 +12,7 @@ def configure(env):
# Check if the platform has marked mono as supported.
supported = env.get("supported", [])
- if not "mono" in supported:
+ if "mono" not in supported:
raise RuntimeError("This module does not currently support building for this platform")
env.add_module_version_string("mono")
diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml
index b559ca20b2..7e14259d5a 100644
--- a/modules/mono/doc_classes/CSharpScript.xml
+++ b/modules/mono/doc_classes/CSharpScript.xml
@@ -5,7 +5,6 @@
</brief_description>
<description>
This class represents a C# script. It is the C# equivalent of the [GDScript] class and is only available in Mono-enabled Godot builds.
- See also [GodotSharp].
</description>
<tutorials>
<link title="C# documentation index">$DOCS_URL/tutorials/scripting/c_sharp/index.html</link>
diff --git a/modules/mono/doc_classes/GodotSharp.xml b/modules/mono/doc_classes/GodotSharp.xml
deleted file mode 100644
index 969ca14350..0000000000
--- a/modules/mono/doc_classes/GodotSharp.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="GodotSharp" inherits="Object" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
- <brief_description>
- Bridge between Godot and the Mono runtime (Mono-enabled builds only).
- </brief_description>
- <description>
- This class is a bridge between Godot and the Mono runtime. It exposes several low-level operations and is only available in Mono-enabled Godot builds.
- See also [CSharpScript].
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="is_runtime_initialized">
- <return type="bool" />
- <description>
- Returns [code]true[/code] if the .NET runtime is initialized, [code]false[/code] otherwise.
- </description>
- </method>
- </methods>
-</class>
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 05dacd28fb..03d8b4eab6 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -143,7 +143,7 @@ bool godot_icall_Internal_IsAssembliesReloadingNeeded() {
void godot_icall_Internal_ReloadAssemblies(bool p_soft_reload) {
#ifdef GD_MONO_HOT_RELOAD
- mono_bind::GodotSharp::get_singleton()->call_deferred(SNAME("_reload_assemblies"), (bool)p_soft_reload);
+ callable_mp(mono_bind::GodotSharp::get_singleton(), &mono_bind::GodotSharp::reload_assemblies).call_deferred(p_soft_reload);
#endif
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs
index ab7f8ede44..33f0850a8d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs
@@ -318,9 +318,9 @@ namespace Godot
Vector3 ofs = _position + halfExtents;
return ofs + new Vector3(
- dir.X > 0f ? -halfExtents.X : halfExtents.X,
- dir.Y > 0f ? -halfExtents.Y : halfExtents.Y,
- dir.Z > 0f ? -halfExtents.Z : halfExtents.Z);
+ dir.X > 0f ? halfExtents.X : -halfExtents.X,
+ dir.Y > 0f ? halfExtents.Y : -halfExtents.Y,
+ dir.Z > 0f ? halfExtents.Z : -halfExtents.Z);
}
/// <summary>
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 0e34616951..48caae8523 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -564,11 +564,7 @@ namespace mono_bind {
GodotSharp *GodotSharp::singleton = nullptr;
-bool GodotSharp::_is_runtime_initialized() {
- return GDMono::get_singleton() != nullptr && GDMono::get_singleton()->is_runtime_initialized();
-}
-
-void GodotSharp::_reload_assemblies(bool p_soft_reload) {
+void GodotSharp::reload_assemblies(bool p_soft_reload) {
#ifdef GD_MONO_HOT_RELOAD
CRASH_COND(CSharpLanguage::get_singleton() == nullptr);
// This method may be called more than once with `call_deferred`, so we need to check
@@ -579,11 +575,6 @@ void GodotSharp::_reload_assemblies(bool p_soft_reload) {
#endif
}
-void GodotSharp::_bind_methods() {
- ClassDB::bind_method(D_METHOD("is_runtime_initialized"), &GodotSharp::_is_runtime_initialized);
- ClassDB::bind_method(D_METHOD("_reload_assemblies"), &GodotSharp::_reload_assemblies);
-}
-
GodotSharp::GodotSharp() {
singleton = this;
}
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index 0cb087db57..614bfc63fb 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -167,18 +167,14 @@ namespace mono_bind {
class GodotSharp : public Object {
GDCLASS(GodotSharp, Object);
- friend class GDMono;
-
- void _reload_assemblies(bool p_soft_reload);
- bool _is_runtime_initialized();
-
protected:
static GodotSharp *singleton;
- static void _bind_methods();
public:
static GodotSharp *get_singleton() { return singleton; }
+ void reload_assemblies(bool p_soft_reload);
+
GodotSharp();
~GodotSharp();
};
diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp
index beaa50ecb2..4d5426d96f 100644
--- a/modules/mono/register_types.cpp
+++ b/modules/mono/register_types.cpp
@@ -49,9 +49,6 @@ void initialize_mono_module(ModuleInitializationLevel p_level) {
_godotsharp = memnew(mono_bind::GodotSharp);
- GDREGISTER_CLASS(mono_bind::GodotSharp);
- Engine::get_singleton()->add_singleton(Engine::Singleton("GodotSharp", mono_bind::GodotSharp::get_singleton()));
-
script_language_cs = memnew(CSharpLanguage);
script_language_cs->set_language_index(ScriptServer::get_language_count());
ScriptServer::register_language(script_language_cs);
diff --git a/modules/navigation/3d/nav_mesh_generator_3d.cpp b/modules/navigation/3d/nav_mesh_generator_3d.cpp
index cc3bbdbf01..df0bdc9537 100644
--- a/modules/navigation/3d/nav_mesh_generator_3d.cpp
+++ b/modules/navigation/3d/nav_mesh_generator_3d.cpp
@@ -895,9 +895,22 @@ void NavMeshGenerator3D::generator_bake_from_source_geometry_data(Ref<Navigation
Vector<Vector3> nav_vertices;
+ HashMap<Vector3, int> recast_vertex_to_native_index;
+ LocalVector<int> recast_index_to_native_index;
+ recast_index_to_native_index.resize(detail_mesh->nverts);
+
for (int i = 0; i < detail_mesh->nverts; i++) {
const float *v = &detail_mesh->verts[i * 3];
- nav_vertices.push_back(Vector3(v[0], v[1], v[2]));
+ const Vector3 vertex = Vector3(v[0], v[1], v[2]);
+ int *existing_index_ptr = recast_vertex_to_native_index.getptr(vertex);
+ if (!existing_index_ptr) {
+ int new_index = recast_vertex_to_native_index.size();
+ recast_index_to_native_index[i] = new_index;
+ recast_vertex_to_native_index[vertex] = new_index;
+ nav_vertices.push_back(vertex);
+ } else {
+ recast_index_to_native_index[i] = *existing_index_ptr;
+ }
}
p_navigation_mesh->set_vertices(nav_vertices);
p_navigation_mesh->clear_polygons();
@@ -912,9 +925,14 @@ void NavMeshGenerator3D::generator_bake_from_source_geometry_data(Ref<Navigation
Vector<int> nav_indices;
nav_indices.resize(3);
// Polygon order in recast is opposite than godot's
- nav_indices.write[0] = ((int)(detail_mesh_bverts + detail_mesh_tris[j * 4 + 0]));
- nav_indices.write[1] = ((int)(detail_mesh_bverts + detail_mesh_tris[j * 4 + 2]));
- nav_indices.write[2] = ((int)(detail_mesh_bverts + detail_mesh_tris[j * 4 + 1]));
+ int index1 = ((int)(detail_mesh_bverts + detail_mesh_tris[j * 4 + 0]));
+ int index2 = ((int)(detail_mesh_bverts + detail_mesh_tris[j * 4 + 2]));
+ int index3 = ((int)(detail_mesh_bverts + detail_mesh_tris[j * 4 + 1]));
+
+ nav_indices.write[0] = recast_index_to_native_index[index1];
+ nav_indices.write[1] = recast_index_to_native_index[index2];
+ nav_indices.write[2] = recast_index_to_native_index[index3];
+
p_navigation_mesh->add_polygon(nav_indices);
}
}
diff --git a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml
index 79aa547c52..338d632524 100644
--- a/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml
+++ b/modules/openxr/doc_classes/OpenXRExtensionWrapperExtension.xml
@@ -84,6 +84,12 @@
Called right before the OpenXR instance is destroyed.
</description>
</method>
+ <method name="_on_main_swapchains_created" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ Called right after the main swapchains are (re)created.
+ </description>
+ </method>
<method name="_on_pre_render" qualifiers="virtual">
<return type="void" />
<description>
diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h
index ce03df0b30..8d05657afc 100644
--- a/modules/openxr/extensions/openxr_extension_wrapper.h
+++ b/modules/openxr/extensions/openxr_extension_wrapper.h
@@ -84,6 +84,7 @@ public:
// This is when controller data is queried and made available to game logic.
virtual void on_process() {}
virtual void on_pre_render() {} // `on_pre_render` is called right before we start rendering our XR viewports.
+ virtual void on_main_swapchains_created() {} // `on_main_swapchains_created` is called right after our main swapchains are (re)created.
virtual void on_pre_draw_viewport(RID p_render_target) {} // `on_pre_draw_viewport` is called right before we start rendering this viewport
virtual void on_post_draw_viewport(RID p_render_target) {} // `on_port_draw_viewport` is called right after we start rendering this viewport (note that on Vulkan draw commands may only be queued)
diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp
index 3b31e1b1f6..e09ca484d5 100644
--- a/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp
+++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.cpp
@@ -50,6 +50,7 @@ void OpenXRExtensionWrapperExtension::_bind_methods() {
GDVIRTUAL_BIND(_on_session_created, "session");
GDVIRTUAL_BIND(_on_process);
GDVIRTUAL_BIND(_on_pre_render);
+ GDVIRTUAL_BIND(_on_main_swapchains_created);
GDVIRTUAL_BIND(_on_session_destroyed);
GDVIRTUAL_BIND(_on_state_idle);
GDVIRTUAL_BIND(_on_state_ready);
@@ -198,6 +199,10 @@ void OpenXRExtensionWrapperExtension::on_pre_render() {
GDVIRTUAL_CALL(_on_pre_render);
}
+void OpenXRExtensionWrapperExtension::on_main_swapchains_created() {
+ GDVIRTUAL_CALL(_on_main_swapchains_created);
+}
+
void OpenXRExtensionWrapperExtension::on_session_destroyed() {
GDVIRTUAL_CALL(_on_session_destroyed);
}
diff --git a/modules/openxr/extensions/openxr_extension_wrapper_extension.h b/modules/openxr/extensions/openxr_extension_wrapper_extension.h
index 71d2a57ff8..e37853903b 100644
--- a/modules/openxr/extensions/openxr_extension_wrapper_extension.h
+++ b/modules/openxr/extensions/openxr_extension_wrapper_extension.h
@@ -86,6 +86,7 @@ public:
virtual void on_session_created(const XrSession p_session) override;
virtual void on_process() override;
virtual void on_pre_render() override;
+ virtual void on_main_swapchains_created() override;
virtual void on_session_destroyed() override;
GDVIRTUAL0(_on_register_metadata);
@@ -95,6 +96,7 @@ public:
GDVIRTUAL1(_on_session_created, uint64_t);
GDVIRTUAL0(_on_process);
GDVIRTUAL0(_on_pre_render);
+ GDVIRTUAL0(_on_main_swapchains_created);
GDVIRTUAL0(_on_session_destroyed);
virtual void on_state_idle() override;
diff --git a/modules/openxr/extensions/openxr_fb_foveation_extension.cpp b/modules/openxr/extensions/openxr_fb_foveation_extension.cpp
index bbdd2e3c8a..8ce808dd3c 100644
--- a/modules/openxr/extensions/openxr_fb_foveation_extension.cpp
+++ b/modules/openxr/extensions/openxr_fb_foveation_extension.cpp
@@ -101,7 +101,7 @@ void *OpenXRFBFoveationExtension::set_swapchain_create_info_and_get_next_pointer
}
}
-void OpenXRFBFoveationExtension::on_state_ready() {
+void OpenXRFBFoveationExtension::on_main_swapchains_created() {
update_profile();
}
@@ -127,26 +127,41 @@ void OpenXRFBFoveationExtension::set_foveation_dynamic(XrFoveationDynamicFB p_fo
update_profile();
}
-void OpenXRFBFoveationExtension::update_profile() {
- if (!is_enabled()) {
+void OpenXRFBFoveationExtension::_update_profile() {
+ // Must be called from rendering thread!
+ ERR_NOT_ON_RENDER_THREAD;
+
+ OpenXRFBFoveationExtension *fov_ext = OpenXRFBFoveationExtension::get_singleton();
+ ERR_FAIL_NULL(fov_ext);
+
+ if (!fov_ext->is_enabled()) {
+ return;
+ }
+
+ OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();
+ ERR_FAIL_NULL(openxr_api);
+
+ XrSwapchain main_color_swapchain = openxr_api->get_color_swapchain();
+ if (main_color_swapchain == XR_NULL_HANDLE) {
+ // Our swapchain hasn't been created yet, we'll call this again once it has.
return;
}
XrFoveationLevelProfileCreateInfoFB level_profile_create_info;
level_profile_create_info.type = XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB;
level_profile_create_info.next = nullptr;
- level_profile_create_info.level = foveation_level;
+ level_profile_create_info.level = fov_ext->foveation_level;
level_profile_create_info.verticalOffset = 0.0f;
- level_profile_create_info.dynamic = foveation_dynamic;
+ level_profile_create_info.dynamic = fov_ext->foveation_dynamic;
XrFoveationProfileCreateInfoFB profile_create_info;
profile_create_info.type = XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB;
profile_create_info.next = &level_profile_create_info;
XrFoveationProfileFB foveation_profile;
- XrResult result = xrCreateFoveationProfileFB(OpenXRAPI::get_singleton()->get_session(), &profile_create_info, &foveation_profile);
+ XrResult result = fov_ext->xrCreateFoveationProfileFB(openxr_api->get_session(), &profile_create_info, &foveation_profile);
if (XR_FAILED(result)) {
- print_line("OpenXR: Unable to create the foveation profile [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
+ print_line("OpenXR: Unable to create the foveation profile [", openxr_api->get_error_string(result), "]");
return;
}
@@ -154,15 +169,15 @@ void OpenXRFBFoveationExtension::update_profile() {
foveation_update_state.type = XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB;
foveation_update_state.profile = foveation_profile;
- result = swapchain_update_state_ext->xrUpdateSwapchainFB(OpenXRAPI::get_singleton()->get_color_swapchain(), (XrSwapchainStateBaseHeaderFB *)&foveation_update_state);
+ result = fov_ext->swapchain_update_state_ext->xrUpdateSwapchainFB(main_color_swapchain, (XrSwapchainStateBaseHeaderFB *)&foveation_update_state);
if (XR_FAILED(result)) {
- print_line("OpenXR: Unable to update the swapchain [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
+ print_line("OpenXR: Unable to update the swapchain [", openxr_api->get_error_string(result), "]");
// We still want to destroy our profile so keep going...
}
- result = xrDestroyFoveationProfileFB(foveation_profile);
+ result = fov_ext->xrDestroyFoveationProfileFB(foveation_profile);
if (XR_FAILED(result)) {
- print_line("OpenXR: Unable to destroy the foveation profile [", OpenXRAPI::get_singleton()->get_error_string(result), "]");
+ print_line("OpenXR: Unable to destroy the foveation profile [", openxr_api->get_error_string(result), "]");
}
}
diff --git a/modules/openxr/extensions/openxr_fb_foveation_extension.h b/modules/openxr/extensions/openxr_fb_foveation_extension.h
index 1c5e722731..84bd7011b5 100644
--- a/modules/openxr/extensions/openxr_fb_foveation_extension.h
+++ b/modules/openxr/extensions/openxr_fb_foveation_extension.h
@@ -60,7 +60,7 @@ public:
virtual void *set_swapchain_create_info_and_get_next_pointer(void *p_next_pointer) override;
- virtual void on_state_ready() override;
+ virtual void on_main_swapchains_created() override;
bool is_enabled() const;
@@ -82,7 +82,15 @@ private:
XrFoveationLevelFB foveation_level = XR_FOVEATION_LEVEL_NONE_FB;
XrFoveationDynamicFB foveation_dynamic = XR_FOVEATION_DYNAMIC_DISABLED_FB;
- void update_profile();
+ static void _update_profile();
+
+ void update_profile() {
+ // If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready...
+ RenderingServer *rendering_server = RenderingServer::get_singleton();
+ ERR_FAIL_NULL(rendering_server);
+
+ rendering_server->call_on_render_thread(callable_mp_static(&OpenXRFBFoveationExtension::_update_profile));
+ }
// Enable foveation on this swapchain
XrSwapchainCreateInfoFoveationFB swapchain_create_info_foveation_fb;
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 32512070d6..541e369925 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -1220,6 +1220,10 @@ bool OpenXRAPI::create_main_swapchains(Size2i p_size) {
}
};
+ for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
+ wrapper->on_main_swapchains_created();
+ }
+
return true;
};
diff --git a/modules/openxr/scene/openxr_composition_layer.cpp b/modules/openxr/scene/openxr_composition_layer.cpp
index 50cc7b9e7b..b02f3082ab 100644
--- a/modules/openxr/scene/openxr_composition_layer.cpp
+++ b/modules/openxr/scene/openxr_composition_layer.cpp
@@ -165,7 +165,9 @@ void OpenXRCompositionLayer::set_layer_viewport(SubViewport *p_viewport) {
return;
}
- ERR_FAIL_COND_EDMSG(is_viewport_in_use(p_viewport), RTR("Cannot use the same SubViewport with multiple OpenXR composition layers. Clear it from its current layer first."));
+ if (p_viewport != nullptr) {
+ ERR_FAIL_COND_EDMSG(is_viewport_in_use(p_viewport), RTR("Cannot use the same SubViewport with multiple OpenXR composition layers. Clear it from its current layer first."));
+ }
layer_viewport = p_viewport;
diff --git a/modules/text_server_adv/gdextension_build/SConstruct b/modules/text_server_adv/gdextension_build/SConstruct
index 58e1868e31..2f7a175d91 100644
--- a/modules/text_server_adv/gdextension_build/SConstruct
+++ b/modules/text_server_adv/gdextension_build/SConstruct
@@ -1,14 +1,15 @@
#!/usr/bin/env python
import atexit
import sys
-import methods
import time
+import methods
+
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
# <https://github.com/python/cpython/issues/73245>
if sys.stdout.isatty() and sys.platform == "win32":
try:
- from ctypes import windll, byref, WinError # type: ignore
+ from ctypes import WinError, byref, windll # type: ignore
from ctypes.wintypes import DWORD # type: ignore
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
@@ -720,7 +721,7 @@ if env["static_icu_data"]:
env.Append(CXXFLAGS=["-DICU_STATIC_DATA"])
env.Append(CPPPATH=["../../../thirdparty/icu4c/"])
else:
- thirdparty_sources += ["../icu_data/icudata_stub.cpp"]
+ thirdparty_icu_sources += ["../icu_data/icudata_stub.cpp"]
env_icu.Append(CPPPATH=["../../../thirdparty/icu4c/common/", "../../../thirdparty/icu4c/i18n/"])
env_icu.Append(
diff --git a/modules/text_server_adv/gdextension_build/methods.py b/modules/text_server_adv/gdextension_build/methods.py
index 3453c3e8f0..43bf56abfe 100644
--- a/modules/text_server_adv/gdextension_build/methods.py
+++ b/modules/text_server_adv/gdextension_build/methods.py
@@ -81,9 +81,9 @@ def disable_warnings(self):
self.Append(CCFLAGS=["/w"])
self.Append(CFLAGS=["/w"])
self.Append(CXXFLAGS=["/w"])
- self["CCFLAGS"] = [x for x in self["CCFLAGS"] if not x in warn_flags]
- self["CFLAGS"] = [x for x in self["CFLAGS"] if not x in warn_flags]
- self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if not x in warn_flags]
+ self["CCFLAGS"] = [x for x in self["CCFLAGS"] if x not in warn_flags]
+ self["CFLAGS"] = [x for x in self["CFLAGS"] if x not in warn_flags]
+ self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if x not in warn_flags]
else:
self.Append(CCFLAGS=["-w"])
self.Append(CFLAGS=["-w"])
@@ -117,31 +117,31 @@ def make_icu_data(target, source, env):
def write_macos_plist(target, binary_name, identifier, name):
os.makedirs(f"{target}/Resource/", exist_ok=True)
with open(f"{target}/Resource/Info.plist", "w", encoding="utf-8", newline="\n") as f:
- f.write(f'<?xml version="1.0" encoding="UTF-8"?>\n')
- f.write(
- f'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n'
- )
- f.write(f'<plist version="1.0">\n')
- f.write(f"<dict>\n")
- f.write(f"\t<key>CFBundleExecutable</key>\n")
- f.write(f"\t<string>{binary_name}</string>\n")
- f.write(f"\t<key>CFBundleIdentifier</key>\n")
- f.write(f"\t<string>{identifier}</string>\n")
- f.write(f"\t<key>CFBundleInfoDictionaryVersion</key>\n")
- f.write(f"\t<string>6.0</string>\n")
- f.write(f"\t<key>CFBundleName</key>\n")
- f.write(f"\t<string>{name}</string>\n")
- f.write(f"\t<key>CFBundlePackageType</key>\n")
- f.write(f"\t<string>FMWK</string>\n")
- f.write(f"\t<key>CFBundleShortVersionString</key>\n")
- f.write(f"\t<string>1.0.0</string>\n")
- f.write(f"\t<key>CFBundleSupportedPlatforms</key>\n")
- f.write(f"\t<array>\n")
- f.write(f"\t\t<string>MacOSX</string>\n")
- f.write(f"\t</array>\n")
- f.write(f"\t<key>CFBundleVersion</key>\n")
- f.write(f"\t<string>1.0.0</string>\n")
- f.write(f"\t<key>LSMinimumSystemVersion</key>\n")
- f.write(f"\t<string>10.14</string>\n")
- f.write(f"</dict>\n")
- f.write(f"</plist>\n")
+ f.write(f"""\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>{binary_name}</string>
+ <key>CFBundleIdentifier</key>
+ <string>{identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>{name}</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0.0</string>
+ <key>CFBundleSupportedPlatforms</key>
+ <array>
+ <string>MacOSX</string>
+ </array>
+ <key>CFBundleVersion</key>
+ <string>1.0.0</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.14</string>
+</dict>
+</plist>
+""")
diff --git a/modules/text_server_fb/gdextension_build/SConstruct b/modules/text_server_fb/gdextension_build/SConstruct
index 9326a53026..f6ae7149be 100644
--- a/modules/text_server_fb/gdextension_build/SConstruct
+++ b/modules/text_server_fb/gdextension_build/SConstruct
@@ -1,14 +1,15 @@
#!/usr/bin/env python
import atexit
import sys
-import methods
import time
+import methods
+
# Enable ANSI escape code support on Windows 10 and later (for colored console output).
# <https://github.com/python/cpython/issues/73245>
if sys.stdout.isatty() and sys.platform == "win32":
try:
- from ctypes import windll, byref, WinError # type: ignore
+ from ctypes import WinError, byref, windll # type: ignore
from ctypes.wintypes import DWORD # type: ignore
stdout_handle = windll.kernel32.GetStdHandle(DWORD(-11))
diff --git a/modules/text_server_fb/gdextension_build/methods.py b/modules/text_server_fb/gdextension_build/methods.py
index 3453c3e8f0..43bf56abfe 100644
--- a/modules/text_server_fb/gdextension_build/methods.py
+++ b/modules/text_server_fb/gdextension_build/methods.py
@@ -81,9 +81,9 @@ def disable_warnings(self):
self.Append(CCFLAGS=["/w"])
self.Append(CFLAGS=["/w"])
self.Append(CXXFLAGS=["/w"])
- self["CCFLAGS"] = [x for x in self["CCFLAGS"] if not x in warn_flags]
- self["CFLAGS"] = [x for x in self["CFLAGS"] if not x in warn_flags]
- self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if not x in warn_flags]
+ self["CCFLAGS"] = [x for x in self["CCFLAGS"] if x not in warn_flags]
+ self["CFLAGS"] = [x for x in self["CFLAGS"] if x not in warn_flags]
+ self["CXXFLAGS"] = [x for x in self["CXXFLAGS"] if x not in warn_flags]
else:
self.Append(CCFLAGS=["-w"])
self.Append(CFLAGS=["-w"])
@@ -117,31 +117,31 @@ def make_icu_data(target, source, env):
def write_macos_plist(target, binary_name, identifier, name):
os.makedirs(f"{target}/Resource/", exist_ok=True)
with open(f"{target}/Resource/Info.plist", "w", encoding="utf-8", newline="\n") as f:
- f.write(f'<?xml version="1.0" encoding="UTF-8"?>\n')
- f.write(
- f'<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n'
- )
- f.write(f'<plist version="1.0">\n')
- f.write(f"<dict>\n")
- f.write(f"\t<key>CFBundleExecutable</key>\n")
- f.write(f"\t<string>{binary_name}</string>\n")
- f.write(f"\t<key>CFBundleIdentifier</key>\n")
- f.write(f"\t<string>{identifier}</string>\n")
- f.write(f"\t<key>CFBundleInfoDictionaryVersion</key>\n")
- f.write(f"\t<string>6.0</string>\n")
- f.write(f"\t<key>CFBundleName</key>\n")
- f.write(f"\t<string>{name}</string>\n")
- f.write(f"\t<key>CFBundlePackageType</key>\n")
- f.write(f"\t<string>FMWK</string>\n")
- f.write(f"\t<key>CFBundleShortVersionString</key>\n")
- f.write(f"\t<string>1.0.0</string>\n")
- f.write(f"\t<key>CFBundleSupportedPlatforms</key>\n")
- f.write(f"\t<array>\n")
- f.write(f"\t\t<string>MacOSX</string>\n")
- f.write(f"\t</array>\n")
- f.write(f"\t<key>CFBundleVersion</key>\n")
- f.write(f"\t<string>1.0.0</string>\n")
- f.write(f"\t<key>LSMinimumSystemVersion</key>\n")
- f.write(f"\t<string>10.14</string>\n")
- f.write(f"</dict>\n")
- f.write(f"</plist>\n")
+ f.write(f"""\
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleExecutable</key>
+ <string>{binary_name}</string>
+ <key>CFBundleIdentifier</key>
+ <string>{identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>{name}</string>
+ <key>CFBundlePackageType</key>
+ <string>FMWK</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0.0</string>
+ <key>CFBundleSupportedPlatforms</key>
+ <array>
+ <string>MacOSX</string>
+ </array>
+ <key>CFBundleVersion</key>
+ <string>1.0.0</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>10.14</string>
+</dict>
+</plist>
+""")
diff --git a/platform/SCsub b/platform/SCsub
index b24c189848..b07023efed 100644
--- a/platform/SCsub
+++ b/platform/SCsub
@@ -1,9 +1,10 @@
#!/usr/bin/env python
-import methods
from glob import glob
from pathlib import Path
+import methods
+
Import("env")
env.platform_sources = []
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 4d76ffb180..bc1b5e9200 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -1,7 +1,8 @@
#!/usr/bin/env python
-import sys
import subprocess
+import sys
+
from methods import print_warning
Import("env")
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 6a8c4ed86d..485f31dee2 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -1,10 +1,11 @@
import os
-import sys
import platform
import subprocess
-from methods import print_warning, print_error
+import sys
from typing import TYPE_CHECKING
+from methods import print_error, print_warning
+
if TYPE_CHECKING:
from SCons.Script.SConscript import SConsEnvironment
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index d27e75b07a..c404af34d8 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -330,8 +330,7 @@ ext.getReleaseKeyAlias = { ->
}
ext.isAndroidStudio = { ->
- def sysProps = System.getProperties()
- return sysProps != null && sysProps['idea.platform.prefix'] != null
+ return project.hasProperty('android.injected.invoked.from.ide')
}
ext.shouldZipAlign = { ->
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index c609b33ef4..b91b023ce6 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -232,11 +232,6 @@ def generateBuildTasks(String flavor = "template") {
return tasks
}
-def isAndroidStudio() {
- def sysProps = System.getProperties()
- return sysProps != null && sysProps['idea.platform.prefix'] != null
-}
-
task copyEditorReleaseApkToBin(type: Copy) {
dependsOn ':editor:assembleRelease'
from('editor/build/outputs/apk/release')
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
index 89fbb9f580..cfbbcf7d0e 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
@@ -61,6 +61,9 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
private var contextClickInProgress = false
private var pointerCaptureInProgress = false
+ private var lastDragX: Float = 0.0f
+ private var lastDragY: Float = 0.0f
+
override fun onDown(event: MotionEvent): Boolean {
GodotInputHandler.handleMotionEvent(event.source, MotionEvent.ACTION_DOWN, event.buttonState, event.x, event.y, nextDownIsDoubleTap)
nextDownIsDoubleTap = false
@@ -165,6 +168,8 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
pointerCaptureInProgress = false
dragInProgress = false
contextClickInProgress = false
+ lastDragX = 0.0f
+ lastDragY = 0.0f
return true
}
@@ -189,6 +194,17 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
sourceMouseRelative
)
return true
+ } else if (!scaleInProgress) {
+ // The 'onScroll' event is triggered with a long delay.
+ // Force the 'InputEventScreenDrag' event earlier here.
+ // We don't toggle 'dragInProgress' here so that the scaling logic can override the drag operation if needed.
+ // Once the 'onScroll' event kicks-in, 'dragInProgress' will be properly set.
+ if (lastDragX != event.getX(0) || lastDragY != event.getY(0)) {
+ lastDragX = event.getX(0)
+ lastDragY = event.getY(0)
+ GodotInputHandler.handleMotionEvent(event)
+ return true
+ }
}
return false
}
@@ -216,7 +232,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
distanceY: Float
): Boolean {
if (scaleInProgress) {
- if (dragInProgress) {
+ if (dragInProgress || lastDragX != 0.0f || lastDragY != 0.0f) {
if (originEvent != null) {
// Cancel the drag
GodotInputHandler.handleMotionEvent(
@@ -228,6 +244,8 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
)
}
dragInProgress = false
+ lastDragX = 0.0f
+ lastDragY = 0.0f
}
}
@@ -235,8 +253,10 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
val y = terminusEvent.y
if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled && !pointerCaptureInProgress && !dragInProgress) {
GodotLib.pan(x, y, distanceX / 5f, distanceY / 5f)
- } else if (!scaleInProgress){
+ } else if (!scaleInProgress) {
dragInProgress = true
+ lastDragX = terminusEvent.getX(0)
+ lastDragY = terminusEvent.getY(0)
GodotInputHandler.handleMotionEvent(terminusEvent)
}
return true
diff --git a/platform/ios/SCsub b/platform/ios/SCsub
index f38914434b..cff7dcc1fd 100644
--- a/platform/ios/SCsub
+++ b/platform/ios/SCsub
@@ -2,11 +2,11 @@
Import("env")
-import os, json
-from platform_methods import architectures, lipo, get_build_version, detect_mvk
-import subprocess
+import os
import shutil
+from platform_methods import detect_mvk, lipo
+
def generate_bundle(target, source, env):
bin_dir = Dir("#bin").abspath
diff --git a/platform/ios/detect.py b/platform/ios/detect.py
index e3bac4ec5c..eb233a5d54 100644
--- a/platform/ios/detect.py
+++ b/platform/ios/detect.py
@@ -1,9 +1,9 @@
import os
import sys
-from methods import print_error, detect_darwin_sdk_path
-
from typing import TYPE_CHECKING
+from methods import detect_darwin_sdk_path, print_error
+
if TYPE_CHECKING:
from SCons.Script.SConscript import SConsEnvironment
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 47f3bcadc9..28825038ca 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -1,11 +1,11 @@
import os
import platform
import sys
-from methods import print_warning, print_error, get_compiler_version, using_gcc
-from platform_methods import detect_arch
-
from typing import TYPE_CHECKING
+from methods import get_compiler_version, print_error, print_warning, using_gcc
+from platform_methods import detect_arch
+
if TYPE_CHECKING:
from SCons.Script.SConscript import SConsEnvironment
diff --git a/platform/macos/SCsub b/platform/macos/SCsub
index 59ef4ee85c..eb8524826f 100644
--- a/platform/macos/SCsub
+++ b/platform/macos/SCsub
@@ -2,11 +2,13 @@
Import("env")
-import os, json
-from platform_methods import architectures, lipo, get_build_version
-import platform_macos_builders
-import subprocess
+import os
import shutil
+import subprocess
+
+import platform_macos_builders
+
+from platform_methods import get_build_version, lipo
def generate_bundle(target, source, env):
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index a5ef29e34f..f02f693dd9 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -1,10 +1,10 @@
import os
import sys
-from methods import print_error, detect_darwin_sdk_path, get_compiler_version, is_vanilla_clang
-from platform_methods import detect_arch, detect_mvk
-
from typing import TYPE_CHECKING
+from methods import detect_darwin_sdk_path, get_compiler_version, is_vanilla_clang, print_error
+from platform_methods import detect_arch, detect_mvk
+
if TYPE_CHECKING:
from SCons.Script.SConscript import SConsEnvironment
@@ -107,7 +107,7 @@ def configure(env: "SConsEnvironment"):
env.Append(CCFLAGS=["-fobjc-arc"])
- if not "osxcross" in env: # regular native build
+ if "osxcross" not in env: # regular native build
if env["macports_clang"] != "no":
mpprefix = os.environ.get("MACPORTS_PREFIX", "/opt/local")
mpclangver = env["macports_clang"]
diff --git a/platform/web/SCsub b/platform/web/SCsub
index bc5893ab3a..fea2fa7df9 100644
--- a/platform/web/SCsub
+++ b/platform/web/SCsub
@@ -6,9 +6,10 @@ Import("env")
# The HTTP server "targets". Run with "scons p=web serve", or "scons p=web run"
if "serve" in COMMAND_LINE_TARGETS or "run" in COMMAND_LINE_TARGETS:
- from serve import serve
import os
+ from serve import serve
+
port = os.environ.get("GODOT_WEB_TEST_PORT", 8060)
try:
port = int(port)
diff --git a/platform/web/detect.py b/platform/web/detect.py
index ccd884b225..524ff44f4d 100644
--- a/platform/web/detect.py
+++ b/platform/web/detect.py
@@ -1,18 +1,19 @@
import os
import sys
+from typing import TYPE_CHECKING
from emscripten_helpers import (
- run_closure_compiler,
- create_engine_file,
+ add_js_externs,
add_js_libraries,
add_js_pre,
- add_js_externs,
+ create_engine_file,
create_template_zip,
get_template_zip_path,
+ run_closure_compiler,
)
-from methods import print_warning, print_error, get_compiler_version
from SCons.Util import WhereIs
-from typing import TYPE_CHECKING
+
+from methods import get_compiler_version, print_error, print_warning
if TYPE_CHECKING:
from SCons.Script.SConscript import SConsEnvironment
diff --git a/platform/web/emscripten_helpers.py b/platform/web/emscripten_helpers.py
index 3ba133c9a1..745b2457fa 100644
--- a/platform/web/emscripten_helpers.py
+++ b/platform/web/emscripten_helpers.py
@@ -1,4 +1,5 @@
-import os, json
+import json
+import os
from SCons.Util import WhereIs
@@ -24,13 +25,13 @@ def get_build_version():
import version
name = "custom_build"
- if os.getenv("BUILD_NAME") != None:
+ if os.getenv("BUILD_NAME") is not None:
name = os.getenv("BUILD_NAME")
v = "%d.%d" % (version.major, version.minor)
if version.patch > 0:
v += ".%d" % version.patch
status = version.status
- if os.getenv("GODOT_VERSION_STATUS") != None:
+ if os.getenv("GODOT_VERSION_STATUS") is not None:
status = str(os.getenv("GODOT_VERSION_STATUS"))
v += ".%s.%s" % (status, name)
return v
diff --git a/platform/web/serve.py b/platform/web/serve.py
index 89dff63ca3..f0b0ec9622 100755
--- a/platform/web/serve.py
+++ b/platform/web/serve.py
@@ -1,13 +1,13 @@
#!/usr/bin/env python3
-from http.server import HTTPServer, SimpleHTTPRequestHandler, test # type: ignore
-from pathlib import Path
-import os
-import sys
import argparse
import contextlib
+import os
import socket
import subprocess
+import sys
+from http.server import HTTPServer, SimpleHTTPRequestHandler, test # type: ignore
+from pathlib import Path
# See cpython GH-17851 and GH-17864.
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 435c501956..1c2bfb9b75 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -4,6 +4,7 @@ Import("env")
import os
from pathlib import Path
+
import platform_windows_builders
sources = []
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 93eb34001e..b66cdadc41 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -1,12 +1,12 @@
-import methods
import os
import subprocess
import sys
-from methods import print_warning, print_error
-from platform_methods import detect_arch
-
from typing import TYPE_CHECKING
+import methods
+from methods import print_error, print_warning
+from platform_methods import detect_arch
+
if TYPE_CHECKING:
from SCons.Script.SConscript import SConsEnvironment
@@ -178,7 +178,7 @@ def get_opts():
caller_frame = inspect.stack()[1]
caller_script_dir = os.path.dirname(os.path.abspath(caller_frame[1]))
d3d12_deps_folder = os.path.join(caller_script_dir, "bin", "build_deps")
- except: # Give up.
+ except Exception: # Give up.
d3d12_deps_folder = ""
return [
@@ -523,7 +523,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
env.Append(CXXFLAGS=["/bigobj"])
# PIX
- if not env["arch"] in ["x86_64", "arm64"] or env["pix_path"] == "" or not os.path.exists(env["pix_path"]):
+ if env["arch"] not in ["x86_64", "arm64"] or env["pix_path"] == "" or not os.path.exists(env["pix_path"]):
env["use_pix"] = False
if env["use_pix"]:
@@ -750,7 +750,7 @@ def configure_mingw(env: "SConsEnvironment"):
env.Append(LIBS=["dxgi", "dxguid"])
# PIX
- if not env["arch"] in ["x86_64", "arm64"] or env["pix_path"] == "" or not os.path.exists(env["pix_path"]):
+ if env["arch"] not in ["x86_64", "arm64"] or env["pix_path"] == "" or not os.path.exists(env["pix_path"]):
env["use_pix"] = False
if env["use_pix"]:
diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py
index 729d55cea6..3fd9e1a581 100644
--- a/platform/windows/platform_windows_builders.py
+++ b/platform/windows/platform_windows_builders.py
@@ -1,8 +1,8 @@
"""Functions used to generate source files during build time"""
import os
-from detect import get_mingw_bin_prefix
-from detect import try_cmd
+
+from detect import get_mingw_bin_prefix, try_cmd
def make_debug_mingw(target, source, env):
diff --git a/platform/windows/windows_terminal_logger.cpp b/platform/windows/windows_terminal_logger.cpp
index 6fc33afe99..6c54faa13a 100644
--- a/platform/windows/windows_terminal_logger.cpp
+++ b/platform/windows/windows_terminal_logger.cpp
@@ -42,20 +42,30 @@ void WindowsTerminalLogger::logv(const char *p_format, va_list p_list, bool p_er
return;
}
- const unsigned int BUFFER_SIZE = 16384;
- char buf[BUFFER_SIZE + 1]; // +1 for the terminating character
- int len = vsnprintf(buf, BUFFER_SIZE, p_format, p_list);
- if (len <= 0) {
- return;
+ const int static_buffer_size = 1024;
+ char static_buf[static_buffer_size];
+ char *buf = static_buf;
+ va_list list_copy;
+ va_copy(list_copy, p_list);
+ int len = vsnprintf(buf, static_buffer_size, p_format, p_list);
+ if (len >= static_buffer_size) {
+ buf = (char *)memalloc(len + 1);
+ len = vsnprintf(buf, len + 1, p_format, list_copy);
+ }
+ va_end(list_copy);
+
+ String str_buf = String::utf8(buf, len).replace("\r\n", "\n").replace("\n", "\r\n");
+ if (len >= static_buffer_size) {
+ memfree(buf);
}
- if ((unsigned int)len >= BUFFER_SIZE) {
- len = BUFFER_SIZE; // Output is too big, will be truncated
+ CharString cstr_buf = str_buf.utf8();
+ if (cstr_buf.length() == 0) {
+ return;
}
- buf[len] = 0;
DWORD written = 0;
HANDLE h = p_err ? GetStdHandle(STD_ERROR_HANDLE) : GetStdHandle(STD_OUTPUT_HANDLE);
- WriteFile(h, &buf[0], len, &written, nullptr);
+ WriteFile(h, cstr_buf.ptr(), cstr_buf.length(), &written, nullptr);
#ifdef DEBUG_ENABLED
FlushFileBuffers(h);
diff --git a/platform_methods.py b/platform_methods.py
index 5326e36077..2b157da22b 100644
--- a/platform_methods.py
+++ b/platform_methods.py
@@ -1,10 +1,7 @@
import os
-import sys
-import json
import platform
-import uuid
-import functools
import subprocess
+
import methods
# NOTE: The multiprocessing module is not compatible with SCons due to conflict on cPickle
@@ -47,14 +44,14 @@ def get_build_version(short):
import version
name = "custom_build"
- if os.getenv("BUILD_NAME") != None:
+ if os.getenv("BUILD_NAME") is not None:
name = os.getenv("BUILD_NAME")
v = "%d.%d" % (version.major, version.minor)
if version.patch > 0:
v += ".%d" % version.patch
status = version.status
if not short:
- if os.getenv("GODOT_VERSION_STATUS") != None:
+ if os.getenv("GODOT_VERSION_STATUS") is not None:
status = str(os.getenv("GODOT_VERSION_STATUS"))
v += ".%s.%s" % (status, name)
return v
@@ -86,7 +83,7 @@ def get_mvk_sdk_path(osname):
def int_or_zero(i):
try:
return int(i)
- except:
+ except (TypeError, ValueError):
return 0
def ver_parse(a):
@@ -140,9 +137,8 @@ def detect_mvk(env, osname):
)
for mvk_path in mvk_list:
- if mvk_path and os.path.isfile(os.path.join(mvk_path, osname + "/libMoltenVK.a")):
- mvk_found = True
- print("MoltenVK found at: " + mvk_path)
+ if mvk_path and os.path.isfile(os.path.join(mvk_path, f"{osname}/libMoltenVK.a")):
+ print(f"MoltenVK found at: {mvk_path}")
return mvk_path
return ""
diff --git a/pyproject.toml b/pyproject.toml
index f1ea10fbae..34ae075f2b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,6 +11,19 @@ namespace_packages = true
explicit_package_bases = true
exclude = ["thirdparty/"]
-[tool.black]
+[tool.ruff]
+extend-exclude = ["thirdparty"]
+extend-include = ["SConstruct", "SCsub"]
line-length = 120
-extend-exclude = ".*thirdparty/.*"
+target-version = "py37"
+
+[tool.ruff.lint]
+extend-select = [
+ "I", # isort
+]
+
+[tool.ruff.lint.per-file-ignores]
+"{SConstruct,SCsub}" = [
+ "E402", # Module level import not at top of file
+ "F821", # Undefined name
+]
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 523d81e874..f7d672620d 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -225,91 +225,6 @@ int TileMap::get_rendering_quadrant_size() const {
return rendering_quadrant_size;
}
-void TileMap::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation, const TileData *p_tile_data_override, real_t p_normalized_animation_offset) {
- ERR_FAIL_COND(!p_tile_set.is_valid());
- ERR_FAIL_COND(!p_tile_set->has_source(p_atlas_source_id));
- ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_tile(p_atlas_coords));
- ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_alternative_tile(p_atlas_coords, p_alternative_tile));
- TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id);
- TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
- if (atlas_source) {
- // Check for the frame.
- if (p_frame >= 0) {
- ERR_FAIL_INDEX(p_frame, atlas_source->get_tile_animation_frames_count(p_atlas_coords));
- }
-
- // Get the texture.
- Ref<Texture2D> tex = atlas_source->get_runtime_texture();
- if (!tex.is_valid()) {
- return;
- }
-
- // Check if we are in the texture, return otherwise.
- Vector2i grid_size = atlas_source->get_atlas_grid_size();
- if (p_atlas_coords.x >= grid_size.x || p_atlas_coords.y >= grid_size.y) {
- return;
- }
-
- // Get tile data.
- const TileData *tile_data = p_tile_data_override ? p_tile_data_override : atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile);
-
- // Get the tile modulation.
- Color modulate = tile_data->get_modulate() * p_modulation;
-
- // Compute the offset.
- Vector2 tile_offset = tile_data->get_texture_origin();
-
- // Get destination rect.
- Rect2 dest_rect;
- dest_rect.size = atlas_source->get_runtime_tile_texture_region(p_atlas_coords).size;
- dest_rect.size.x += FP_ADJUST;
- dest_rect.size.y += FP_ADJUST;
-
- bool transpose = tile_data->get_transpose() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
- if (transpose) {
- dest_rect.position = (p_position - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
- } else {
- dest_rect.position = (p_position - dest_rect.size / 2 - tile_offset);
- }
-
- if (tile_data->get_flip_h() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H)) {
- dest_rect.size.x = -dest_rect.size.x;
- }
-
- if (tile_data->get_flip_v() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V)) {
- dest_rect.size.y = -dest_rect.size.y;
- }
-
- // Draw the tile.
- if (p_frame >= 0) {
- Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, p_frame);
- tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
- } else if (atlas_source->get_tile_animation_frames_count(p_atlas_coords) == 1) {
- Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, 0);
- tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
- } else {
- real_t speed = atlas_source->get_tile_animation_speed(p_atlas_coords);
- real_t animation_duration = atlas_source->get_tile_animation_total_duration(p_atlas_coords) / speed;
- real_t animation_offset = p_normalized_animation_offset * animation_duration;
- // Accumulate durations unaffected by the speed to avoid accumulating floating point division errors.
- // Aka do `sum(duration[i]) / speed` instead of `sum(duration[i] / speed)`.
- real_t time_unscaled = 0.0;
- for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(p_atlas_coords); frame++) {
- real_t frame_duration_unscaled = atlas_source->get_tile_animation_frame_duration(p_atlas_coords, frame);
- real_t slice_start = time_unscaled / speed;
- real_t slice_end = (time_unscaled + frame_duration_unscaled) / speed;
- RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, animation_duration, slice_start, slice_end, animation_offset);
-
- Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, frame);
- tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
-
- time_unscaled += frame_duration_unscaled;
- }
- RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, 1.0, 0.0, 1.0, 0.0);
- }
- }
-}
-
void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
if (p_tileset == tile_set) {
return;
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 45604bfb8a..690102f730 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -63,8 +63,6 @@ private:
// A compatibility enum to specify how is the data if formatted.
mutable TileMapDataFormat format = TileMapDataFormat::TILE_MAP_DATA_FORMAT_3;
- static constexpr float FP_ADJUST = 0.00001;
-
// Properties.
Ref<TileSet> tile_set;
int rendering_quadrant_size = 16;
@@ -123,8 +121,6 @@ public:
void set_rendering_quadrant_size(int p_size);
int get_rendering_quadrant_size() const;
- static void draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0), const TileData *p_tile_data_override = nullptr, real_t p_normalized_animation_offset = 0.0);
-
// Accessors.
void set_tileset(const Ref<TileSet> &p_tileset);
Ref<TileSet> get_tileset() const;
diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp
index 03fd7364c0..0ac236eaa7 100644
--- a/scene/2d/tile_map_layer.cpp
+++ b/scene/2d/tile_map_layer.cpp
@@ -340,7 +340,7 @@ void TileMapLayer::_rendering_update(bool p_force_cleanup) {
}
// Drawing the tile in the canvas item.
- TileMap::draw_tile(ci, local_tile_pos - rendering_quadrant->canvas_items_position, tile_set, cell_data.cell.source_id, cell_data.cell.get_atlas_coords(), cell_data.cell.alternative_tile, -1, get_self_modulate(), tile_data, random_animation_offset);
+ draw_tile(ci, local_tile_pos - rendering_quadrant->canvas_items_position, tile_set, cell_data.cell.source_id, cell_data.cell.get_atlas_coords(), cell_data.cell.alternative_tile, -1, get_self_modulate(), tile_data, random_animation_offset);
}
// Reset physics interpolation for any recreated canvas items.
@@ -603,6 +603,7 @@ void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) {
rs->canvas_light_occluder_set_polygon(occluder, tile_data->get_occluder(occlusion_layer_index, flip_h, flip_v, transpose)->get_rid());
rs->canvas_light_occluder_attach_to_canvas(occluder, get_canvas());
rs->canvas_light_occluder_set_light_mask(occluder, tile_set->get_occlusion_layer_light_mask(occlusion_layer_index));
+ rs->canvas_light_occluder_set_as_sdf_collision(occluder, tile_set->get_occlusion_layer_sdf_collision(occlusion_layer_index));
} else {
// Clear occluder.
if (occluder.is_valid()) {
@@ -1695,18 +1696,18 @@ void TileMapLayer::_notification(int p_what) {
_internal_update(true);
} break;
- case TileMap::NOTIFICATION_ENTER_CANVAS: {
+ case NOTIFICATION_ENTER_CANVAS: {
dirty.flags[DIRTY_FLAGS_LAYER_IN_CANVAS] = true;
_queue_internal_update();
} break;
- case TileMap::NOTIFICATION_EXIT_CANVAS: {
+ case NOTIFICATION_EXIT_CANVAS: {
dirty.flags[DIRTY_FLAGS_LAYER_IN_CANVAS] = true;
// Update immediately on exiting, and force cleanup.
_internal_update(true);
} break;
- case TileMap::NOTIFICATION_VISIBILITY_CHANGED: {
+ case NOTIFICATION_VISIBILITY_CHANGED: {
dirty.flags[DIRTY_FLAGS_LAYER_VISIBILITY] = true;
_queue_internal_update();
} break;
@@ -2161,6 +2162,91 @@ TileMapCell TileMapLayer::get_cell(const Vector2i &p_coords) const {
}
}
+void TileMapLayer::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame, Color p_modulation, const TileData *p_tile_data_override, real_t p_normalized_animation_offset) {
+ ERR_FAIL_COND(p_tile_set.is_null());
+ ERR_FAIL_COND(!p_tile_set->has_source(p_atlas_source_id));
+ ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_tile(p_atlas_coords));
+ ERR_FAIL_COND(!p_tile_set->get_source(p_atlas_source_id)->has_alternative_tile(p_atlas_coords, p_alternative_tile));
+ TileSetSource *source = *p_tile_set->get_source(p_atlas_source_id);
+ TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
+ if (atlas_source) {
+ // Check for the frame.
+ if (p_frame >= 0) {
+ ERR_FAIL_INDEX(p_frame, atlas_source->get_tile_animation_frames_count(p_atlas_coords));
+ }
+
+ // Get the texture.
+ Ref<Texture2D> tex = atlas_source->get_runtime_texture();
+ if (tex.is_null()) {
+ return;
+ }
+
+ // Check if we are in the texture, return otherwise.
+ Vector2i grid_size = atlas_source->get_atlas_grid_size();
+ if (p_atlas_coords.x >= grid_size.x || p_atlas_coords.y >= grid_size.y) {
+ return;
+ }
+
+ // Get tile data.
+ const TileData *tile_data = p_tile_data_override ? p_tile_data_override : atlas_source->get_tile_data(p_atlas_coords, p_alternative_tile);
+
+ // Get the tile modulation.
+ Color modulate = tile_data->get_modulate() * p_modulation;
+
+ // Compute the offset.
+ Vector2 tile_offset = tile_data->get_texture_origin();
+
+ // Get destination rect.
+ Rect2 dest_rect;
+ dest_rect.size = atlas_source->get_runtime_tile_texture_region(p_atlas_coords).size;
+ dest_rect.size.x += FP_ADJUST;
+ dest_rect.size.y += FP_ADJUST;
+
+ bool transpose = tile_data->get_transpose() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
+ if (transpose) {
+ dest_rect.position = (p_position - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
+ } else {
+ dest_rect.position = (p_position - dest_rect.size / 2 - tile_offset);
+ }
+
+ if (tile_data->get_flip_h() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H)) {
+ dest_rect.size.x = -dest_rect.size.x;
+ }
+
+ if (tile_data->get_flip_v() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V)) {
+ dest_rect.size.y = -dest_rect.size.y;
+ }
+
+ // Draw the tile.
+ if (p_frame >= 0) {
+ Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, p_frame);
+ tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+ } else if (atlas_source->get_tile_animation_frames_count(p_atlas_coords) == 1) {
+ Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, 0);
+ tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+ } else {
+ real_t speed = atlas_source->get_tile_animation_speed(p_atlas_coords);
+ real_t animation_duration = atlas_source->get_tile_animation_total_duration(p_atlas_coords) / speed;
+ real_t animation_offset = p_normalized_animation_offset * animation_duration;
+ // Accumulate durations unaffected by the speed to avoid accumulating floating point division errors.
+ // Aka do `sum(duration[i]) / speed` instead of `sum(duration[i] / speed)`.
+ real_t time_unscaled = 0.0;
+ for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(p_atlas_coords); frame++) {
+ real_t frame_duration_unscaled = atlas_source->get_tile_animation_frame_duration(p_atlas_coords, frame);
+ real_t slice_start = time_unscaled / speed;
+ real_t slice_end = (time_unscaled + frame_duration_unscaled) / speed;
+ RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, animation_duration, slice_start, slice_end, animation_offset);
+
+ Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, frame);
+ tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());
+
+ time_unscaled += frame_duration_unscaled;
+ }
+ RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, 1.0, 0.0, 1.0, 0.0);
+ }
+ }
+}
+
void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile) {
// Set the current cell tile (using integer position).
Vector2i pk(p_coords);
@@ -2211,7 +2297,7 @@ void TileMapLayer::erase_cell(const Vector2i &p_coords) {
}
void TileMapLayer::fix_invalid_tiles() {
- ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot call fix_invalid_tiles() on a TileMap without a valid TileSet.");
+ ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot call fix_invalid_tiles() on a TileMapLayer without a valid TileSet.");
RBSet<Vector2i> coords;
for (const KeyValue<Vector2i, CellData> &E : tile_map_layer_data) {
diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h
index 5861433c8a..57c83d7c4c 100644
--- a/scene/2d/tile_map_layer.h
+++ b/scene/2d/tile_map_layer.h
@@ -269,6 +269,8 @@ public:
};
private:
+ static constexpr float FP_ADJUST = 0.00001;
+
// Properties.
HashMap<Vector2i, CellData> tile_map_layer_data;
@@ -407,6 +409,8 @@ public:
// Not exposed to users.
TileMapCell get_cell(const Vector2i &p_coords) const;
+ static void draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0), const TileData *p_tile_data_override = nullptr, real_t p_normalized_animation_offset = 0.0);
+
////////////// Exposed functions //////////////
// --- Cells manipulation ---
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 498e101b3c..a4804e928a 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -847,12 +847,13 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
ERR_FAIL_INDEX(p_bone_idx, bone_size);
Bone *bonesptr = bones.ptrw();
- List<int> bones_to_process = List<int>();
+ thread_local LocalVector<int> bones_to_process;
+ bones_to_process.clear();
bones_to_process.push_back(p_bone_idx);
- while (bones_to_process.size() > 0) {
- int current_bone_idx = bones_to_process.front()->get();
- bones_to_process.erase(current_bone_idx);
+ uint32_t index = 0;
+ while (index < bones_to_process.size()) {
+ int current_bone_idx = bones_to_process[index];
Bone &b = bonesptr[current_bone_idx];
bool bone_enabled = b.enabled && !show_rest_only;
@@ -905,6 +906,8 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
for (int i = 0; i < child_bone_size; i++) {
bones_to_process.push_back(b.child_bones[i]);
}
+
+ index++;
}
}
diff --git a/scene/resources/portable_compressed_texture.cpp b/scene/resources/portable_compressed_texture.cpp
index 918b5c0b41..002db30379 100644
--- a/scene/resources/portable_compressed_texture.cpp
+++ b/scene/resources/portable_compressed_texture.cpp
@@ -153,14 +153,14 @@ void PortableCompressedTexture2D::create_from_image(const Ref<Image> &p_image, C
for (int i = 0; i < p_image->get_mipmap_count() + 1; i++) {
Vector<uint8_t> data;
if (p_compression_mode == COMPRESSION_MODE_LOSSY) {
- data = Image::webp_lossy_packer(p_image->get_image_from_mipmap(i), p_lossy_quality);
+ data = Image::webp_lossy_packer(i ? p_image->get_image_from_mipmap(i) : p_image, p_lossy_quality);
encode_uint16(DATA_FORMAT_WEBP, buffer.ptrw() + 2);
} else {
if (use_webp) {
- data = Image::webp_lossless_packer(p_image->get_image_from_mipmap(i));
+ data = Image::webp_lossless_packer(i ? p_image->get_image_from_mipmap(i) : p_image);
encode_uint16(DATA_FORMAT_WEBP, buffer.ptrw() + 2);
} else {
- data = Image::png_packer(p_image->get_image_from_mipmap(i));
+ data = Image::png_packer(i ? p_image->get_image_from_mipmap(i) : p_image);
encode_uint16(DATA_FORMAT_PNG, buffer.ptrw() + 2);
}
}
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 8267e958b4..dfe5bd4a47 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -173,7 +173,7 @@ void Shader::get_shader_uniform_list(List<PropertyInfo> *p_params, bool p_get_gr
}
}
#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint() && !class_doc.name.is_empty() && p_params) {
+ if (EditorHelp::get_doc_data() != nullptr && Engine::get_singleton()->is_editor_hint() && !class_doc.name.is_empty() && p_params) {
EditorHelp::get_doc_data()->add_doc(class_doc);
}
#endif
diff --git a/scene/theme/SCsub b/scene/theme/SCsub
index 5f62ae4b05..2372d1820a 100644
--- a/scene/theme/SCsub
+++ b/scene/theme/SCsub
@@ -4,7 +4,6 @@ Import("env")
import default_theme_builders
-
env.add_source_files(env.scene_sources, "*.cpp")
SConscript("icons/SCsub")
diff --git a/scene/theme/icons/SCsub b/scene/theme/icons/SCsub
index 46133ccceb..1f3b7f6d17 100644
--- a/scene/theme/icons/SCsub
+++ b/scene/theme/icons/SCsub
@@ -4,7 +4,6 @@ Import("env")
import default_theme_icons_builders
-
env["BUILDERS"]["MakeDefaultThemeIconsBuilder"] = Builder(
action=env.Run(default_theme_icons_builders.make_default_theme_icons_action),
suffix=".h",
diff --git a/scu_builders.py b/scu_builders.py
index a9ae428222..fc5461196f 100644
--- a/scu_builders.py
+++ b/scu_builders.py
@@ -1,11 +1,11 @@
-"""Functions used to generate scu build source files during build time
-"""
+"""Functions used to generate scu build source files during build time"""
-import glob, os
+import glob
import math
-from methods import print_error
+import os
from pathlib import Path
-from os.path import normpath, basename
+
+from methods import print_error
base_folder_path = str(Path(__file__).parent) + "/"
base_folder_only = os.path.basename(os.path.normpath(base_folder_path))
@@ -25,7 +25,7 @@ def clear_out_stale_files(output_folder, extension, fresh_files):
for file in glob.glob(output_folder + "/*." + extension):
file = Path(file)
- if not file in fresh_files:
+ if file not in fresh_files:
# print("removed stale file: " + str(file))
os.remove(file)
@@ -56,7 +56,7 @@ def find_files_in_folder(folder, sub_folder, include_list, extension, sought_exc
li = '#include "' + folder + "/" + sub_folder_slashed + file + '"'
- if not simple_name in sought_exceptions:
+ if simple_name not in sought_exceptions:
include_list.append(li)
else:
found_exceptions.append(li)
@@ -78,9 +78,9 @@ def write_output_file(file_count, include_list, start_line, end_line, output_fol
file_text = ""
- for l in range(start_line, end_line):
- if l < len(include_list):
- line = include_list[l]
+ for i in range(start_line, end_line):
+ if i < len(include_list):
+ line = include_list[i]
li = line + "\n"
file_text += li
@@ -221,7 +221,6 @@ def process_folder(folders, sought_exceptions=[], includes_per_scu=0, extension=
lines_per_file = max(lines_per_file, 1)
start_line = 0
- file_number = 0
# These do not vary throughout the loop
output_folder = abs_main_folder + "/scu/"
diff --git a/servers/rendering/rendering_light_culler.h b/servers/rendering/rendering_light_culler.h
index 0bf975430b..b0437d2310 100644
--- a/servers/rendering/rendering_light_culler.h
+++ b/servers/rendering/rendering_light_culler.h
@@ -181,14 +181,14 @@ private:
}
// Prevent divide by zero.
- if (lc > 0.00001f) {
+ if (lc > 0.001f) {
// If the summed length of the smaller two
// sides is close to the length of the longest side,
// the points are colinear, and the triangle is near degenerate.
float ld = ((la + lb) - lc) / lc;
// ld will be close to zero for colinear tris.
- return ld < 0.00001f;
+ return ld < 0.001f;
}
// Don't create planes from tiny triangles,
diff --git a/tests/python_build/test_gles3_builder.py b/tests/python_build/test_gles3_builder.py
index 6f16139eb9..b34d33bde7 100644
--- a/tests/python_build/test_gles3_builder.py
+++ b/tests/python_build/test_gles3_builder.py
@@ -2,7 +2,7 @@ import json
import pytest
-from gles3_builders import build_gles3_header, GLES3HeaderStruct
+from gles3_builders import GLES3HeaderStruct, build_gles3_header
@pytest.mark.parametrize(
diff --git a/tests/python_build/test_glsl_builder.py b/tests/python_build/test_glsl_builder.py
index 348ef8441c..9f548855ff 100644
--- a/tests/python_build/test_glsl_builder.py
+++ b/tests/python_build/test_glsl_builder.py
@@ -2,7 +2,7 @@ import json
import pytest
-from glsl_builders import build_raw_header, RAWHeaderStruct, build_rd_header, RDHeaderStruct
+from glsl_builders import RAWHeaderStruct, RDHeaderStruct, build_raw_header, build_rd_header
@pytest.mark.parametrize(