summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYRIGHT.txt2
-rw-r--r--core/input/input.cpp10
-rw-r--r--core/os/os.cpp1
-rw-r--r--core/string/translation.cpp1
-rw-r--r--core/string/ustring.h16
-rw-r--r--doc/classes/Camera3D.xml8
-rw-r--r--doc/classes/ClippedCamera3D.xml93
-rw-r--r--doc/classes/Control.xml21
-rw-r--r--doc/classes/ImporterMesh.xml (renamed from doc/classes/EditorSceneImporterMesh.xml)10
-rw-r--r--doc/classes/ImporterMeshInstance3D.xml (renamed from doc/classes/EditorSceneImporterMeshNode3D.xml)4
-rw-r--r--doc/classes/Material.xml5
-rw-r--r--doc/classes/Theme.xml28
-rw-r--r--doc/classes/Window.xml15
-rw-r--r--editor/editor_node.cpp4
-rw-r--r--editor/editor_themes.cpp5
-rw-r--r--editor/import/editor_import_collada.cpp27
-rw-r--r--editor/import/editor_importer_bake_reset.cpp4
-rw-r--r--editor/import/resource_importer_obj.cpp8
-rw-r--r--editor/import/resource_importer_scene.cpp63
-rw-r--r--editor/import/resource_importer_scene.h6
-rw-r--r--editor/import/scene_import_settings.cpp7
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp41
-rw-r--r--editor/plugins/script_text_editor.cpp6
-rw-r--r--modules/bullet/soft_body_bullet.cpp26
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp7
-rw-r--r--modules/fbx/data/fbx_mesh_data.h6
-rw-r--r--modules/fbx/editor_scene_importer_fbx.cpp6
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp11
-rw-r--r--modules/gdscript/gdscript_compiler.cpp23
-rw-r--r--modules/gdscript/gdscript_editor.cpp28
-rw-r--r--modules/gdscript/gdscript_parser.cpp4
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.gd13
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.out5
-rw-r--r--modules/gltf/config.py4
-rw-r--r--modules/gltf/doc_classes/GLTFDocument.xml4
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtension.xml73
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml9
-rw-r--r--modules/gltf/doc_classes/GLTFMesh.xml2
-rw-r--r--modules/gltf/editor_scene_exporter_gltf_plugin.cpp3
-rw-r--r--modules/gltf/editor_scene_exporter_gltf_plugin.h4
-rw-r--r--modules/gltf/editor_scene_importer_gltf.cpp3
-rw-r--r--modules/gltf/editor_scene_importer_gltf.h7
-rw-r--r--modules/gltf/gltf_accessor.cpp2
-rw-r--r--modules/gltf/gltf_accessor.h2
-rw-r--r--modules/gltf/gltf_buffer_view.cpp2
-rw-r--r--modules/gltf/gltf_document.cpp322
-rw-r--r--modules/gltf/gltf_document.h24
-rw-r--r--modules/gltf/gltf_document_extension.cpp88
-rw-r--r--modules/gltf/gltf_document_extension.h63
-rw-r--r--modules/gltf/gltf_document_extension_convert_importer_mesh.cpp79
-rw-r--r--modules/gltf/gltf_document_extension_convert_importer_mesh.h55
-rw-r--r--modules/gltf/gltf_mesh.cpp6
-rw-r--r--modules/gltf/gltf_mesh.h9
-rw-r--r--modules/gltf/gltf_state.h1
-rw-r--r--modules/gltf/register_types.cpp4
-rw-r--r--scene/3d/camera_3d.cpp244
-rw-r--r--scene/3d/camera_3d.h64
-rw-r--r--scene/3d/importer_mesh_instance_3d.cpp (renamed from editor/import/scene_importer_mesh_node_3d.cpp)38
-rw-r--r--scene/3d/importer_mesh_instance_3d.h (renamed from editor/import/scene_importer_mesh_node_3d.h)20
-rw-r--r--scene/3d/spring_arm_3d.cpp32
-rw-r--r--scene/animation/animation_player.cpp9
-rw-r--r--scene/gui/color_picker.cpp53
-rw-r--r--scene/gui/color_picker.h1
-rw-r--r--scene/gui/control.cpp164
-rw-r--r--scene/gui/control.h8
-rw-r--r--scene/gui/dialogs.cpp6
-rw-r--r--scene/gui/gradient_edit.cpp41
-rw-r--r--scene/gui/gradient_edit.h7
-rw-r--r--scene/gui/graph_edit.cpp16
-rw-r--r--scene/gui/line_edit.cpp7
-rw-r--r--scene/gui/rich_text_label.cpp14
-rw-r--r--scene/gui/tabs.cpp1
-rw-r--r--scene/gui/text_edit.cpp27
-rw-r--r--scene/gui/tree.cpp18
-rw-r--r--scene/gui/tree.h2
-rw-r--r--scene/main/node.cpp12
-rw-r--r--scene/main/window.cpp16
-rw-r--r--scene/main/window.h4
-rw-r--r--scene/register_scene_types.cpp5
-rw-r--r--scene/resources/default_theme/default_theme.cpp9
-rw-r--r--scene/resources/importer_mesh.cpp (renamed from editor/import/scene_importer_mesh.cpp)122
-rw-r--r--scene/resources/importer_mesh.h (renamed from editor/import/scene_importer_mesh.h)16
-rw-r--r--scene/resources/material.cpp20
-rw-r--r--scene/resources/material.h3
-rw-r--r--scene/resources/sky_material.cpp12
-rw-r--r--scene/resources/sky_material.h3
-rw-r--r--scene/resources/theme.cpp936
-rw-r--r--scene/resources/theme.h17
-rw-r--r--servers/physics_3d/soft_body_3d_sw.cpp24
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp4
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp4
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp4
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp765
-rw-r--r--servers/rendering/renderer_rd/shader_compiler_rd.cpp126
-rw-r--r--servers/rendering/renderer_rd/shader_compiler_rd.h1
-rw-r--r--servers/rendering/shader_language.cpp515
-rw-r--r--servers/rendering/shader_language.h4
-rw-r--r--servers/rendering_server.cpp2
-rw-r--r--tests/test_shader_lang.cpp37
-rw-r--r--thirdparty/doctest/LICENSE.txt2
-rw-r--r--thirdparty/doctest/doctest.h586
102 files changed, 3395 insertions, 1910 deletions
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 86a575a48c..8ad6997463 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -143,7 +143,7 @@ License: Expat
Files: ./thirdparty/doctest/
Comment: doctest
-Copyright: 2016-2020, Viktor Kirilov
+Copyright: 2016-2021, Viktor Kirilov
License: Expat
Files: ./thirdparty/embree/
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 05b02408a1..f9a361c761 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -35,10 +35,6 @@
#include "core/input/input_map.h"
#include "core/os/os.h"
-#ifdef TOOLS_ENABLED
-#include "editor/editor_settings.h"
-#endif
-
static const char *_joy_buttons[JOY_BUTTON_SDL_MAX] = {
"a",
"b",
@@ -162,9 +158,6 @@ void Input::_bind_methods() {
}
void Input::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
-#ifdef TOOLS_ENABLED
- const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
-
String pf = p_function;
if (p_idx == 0 && (pf == "is_action_pressed" || pf == "action_press" || pf == "action_release" ||
pf == "is_action_just_pressed" || pf == "is_action_just_released" ||
@@ -179,10 +172,9 @@ void Input::get_argument_options(const StringName &p_function, int p_idx, List<S
}
String name = pi.name.substr(pi.name.find("/") + 1, pi.name.length());
- r_options->push_back(name.quote(quote_style));
+ r_options->push_back(name.quote());
}
}
-#endif
}
void Input::SpeedTrack::update(const Vector2 &p_delta_p) {
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 69366f688c..12f85858c3 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -36,7 +36,6 @@
#include "core/io/file_access.h"
#include "core/os/midi_driver.h"
#include "core/version_generated.gen.h"
-#include "servers/audio_server.h"
#include <stdarg.h>
diff --git a/core/string/translation.cpp b/core/string/translation.cpp
index 5e3b8297aa..37dc8915ab 100644
--- a/core/string/translation.cpp
+++ b/core/string/translation.cpp
@@ -35,7 +35,6 @@
#include "core/os/os.h"
#ifdef TOOLS_ENABLED
-#include "editor/editor_settings.h"
#include "main/main.h"
#endif
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 24da6b82af..1d80ccf58d 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -51,11 +51,15 @@ class CharProxy {
CowData<T> &_cowdata;
static const T _null = 0;
- _FORCE_INLINE_ CharProxy(const int &p_index, CowData<T> &cowdata) :
+ _FORCE_INLINE_ CharProxy(const int &p_index, CowData<T> &p_cowdata) :
_index(p_index),
- _cowdata(cowdata) {}
+ _cowdata(p_cowdata) {}
public:
+ _FORCE_INLINE_ CharProxy(const CharProxy<T> &p_other) :
+ _index(p_other._index),
+ _cowdata(p_other._cowdata) {}
+
_FORCE_INLINE_ operator T() const {
if (unlikely(_index == _cowdata.size())) {
return _null;
@@ -68,12 +72,12 @@ public:
return _cowdata.ptr() + _index;
}
- _FORCE_INLINE_ void operator=(const T &other) const {
- _cowdata.set(_index, other);
+ _FORCE_INLINE_ void operator=(const T &p_other) const {
+ _cowdata.set(_index, p_other);
}
- _FORCE_INLINE_ void operator=(const CharProxy<T> &other) const {
- _cowdata.set(_index, other.operator T());
+ _FORCE_INLINE_ void operator=(const CharProxy<T> &p_other) const {
+ _cowdata.set(_index, p_other.operator T());
}
};
diff --git a/doc/classes/Camera3D.xml b/doc/classes/Camera3D.xml
index cd17a31e23..06e2f83f05 100644
--- a/doc/classes/Camera3D.xml
+++ b/doc/classes/Camera3D.xml
@@ -26,7 +26,7 @@
<method name="get_camera_transform" qualifiers="const">
<return type="Transform3D" />
<description>
- Returns the transform of the camera plus the vertical ([member v_offset]) and horizontal ([member h_offset]) offsets; and any other adjustments made to the position and orientation of the camera by subclassed cameras such as [ClippedCamera3D] and [XRCamera3D].
+ Returns the transform of the camera plus the vertical ([member v_offset]) and horizontal ([member h_offset]) offsets; and any other adjustments made to the position and orientation of the camera by subclassed cameras such as [XRCamera3D].
</description>
</method>
<method name="get_cull_mask_value" qualifiers="const">
@@ -42,6 +42,12 @@
Returns the camera's frustum planes in world space units as an array of [Plane]s in the following order: near, far, left, top, right, bottom. Not to be confused with [member frustum_offset].
</description>
</method>
+ <method name="get_pyramid_shape_rid">
+ <return type="RID" />
+ <description>
+ Returns the RID of a pyramid shape encompassing the camera's view frustum, ignoring the camera's near plane. The tip of the pyramid represents the position of the camera.
+ </description>
+ </method>
<method name="is_position_behind" qualifiers="const">
<return type="bool" />
<argument index="0" name="world_point" type="Vector3" />
diff --git a/doc/classes/ClippedCamera3D.xml b/doc/classes/ClippedCamera3D.xml
deleted file mode 100644
index 1a0d3499cd..0000000000
--- a/doc/classes/ClippedCamera3D.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="ClippedCamera3D" inherits="Camera3D" version="4.0">
- <brief_description>
- A [Camera3D] that includes collision.
- </brief_description>
- <description>
- This node extends [Camera3D] to add collisions with [Area3D] and/or [PhysicsBody3D] nodes. The camera cannot move through colliding objects.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_exception">
- <return type="void" />
- <argument index="0" name="node" type="Object" />
- <description>
- Adds a collision exception so the camera does not collide with the specified node.
- </description>
- </method>
- <method name="add_exception_rid">
- <return type="void" />
- <argument index="0" name="rid" type="RID" />
- <description>
- Adds a collision exception so the camera does not collide with the specified [RID].
- </description>
- </method>
- <method name="clear_exceptions">
- <return type="void" />
- <description>
- Removes all collision exceptions.
- </description>
- </method>
- <method name="get_clip_offset" qualifiers="const">
- <return type="float" />
- <description>
- Returns the distance the camera has been offset due to a collision.
- </description>
- </method>
- <method name="get_collision_mask_value" qualifiers="const">
- <return type="bool" />
- <argument index="0" name="layer_number" type="int" />
- <description>
- Returns whether or not the specified layer of the [member collision_mask] is enabled, given a [code]layer_number[/code] between 1 and 32.
- </description>
- </method>
- <method name="remove_exception">
- <return type="void" />
- <argument index="0" name="node" type="Object" />
- <description>
- Removes a collision exception with the specified node.
- </description>
- </method>
- <method name="remove_exception_rid">
- <return type="void" />
- <argument index="0" name="rid" type="RID" />
- <description>
- Removes a collision exception with the specified [RID].
- </description>
- </method>
- <method name="set_collision_mask_value">
- <return type="void" />
- <argument index="0" name="layer_number" type="int" />
- <argument index="1" name="value" type="bool" />
- <description>
- Based on [code]value[/code], enables or disables the specified layer in the [member collision_mask], given a [code]layer_number[/code] between 1 and 32.
- </description>
- </method>
- </methods>
- <members>
- <member name="clip_to_areas" type="bool" setter="set_clip_to_areas" getter="is_clip_to_areas_enabled" default="false">
- If [code]true[/code], the camera stops on contact with [Area3D]s.
- </member>
- <member name="clip_to_bodies" type="bool" setter="set_clip_to_bodies" getter="is_clip_to_bodies_enabled" default="true">
- If [code]true[/code], the camera stops on contact with [PhysicsBody3D]s.
- </member>
- <member name="collision_mask" type="int" setter="set_collision_mask" getter="get_collision_mask" default="1">
- The camera's collision mask. Only objects in at least one collision layer matching the mask will be detected. See [url=https://docs.godotengine.org/en/latest/tutorials/physics/physics_introduction.html#collision-layers-and-masks]Collision layers and masks[/url] in the documentation for more information.
- </member>
- <member name="margin" type="float" setter="set_margin" getter="get_margin" default="0.0">
- The camera's collision margin. The camera can't get closer than this distance to a colliding object.
- </member>
- <member name="process_callback" type="int" setter="set_process_callback" getter="get_process_callback" enum="ClippedCamera3D.ClipProcessCallback" default="0">
- The camera's process callback. See [enum ClipProcessCallback].
- </member>
- </members>
- <constants>
- <constant name="CLIP_PROCESS_PHYSICS" value="0" enum="ClipProcessCallback">
- The camera updates with the [code]_physics_process[/code] callback.
- </constant>
- <constant name="CLIP_PROCESS_IDLE" value="1" enum="ClipProcessCallback">
- The camera updates with the [code]_process[/code] callback.
- </constant>
- </constants>
-</class>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index b00bf1c250..6fa59a15ac 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -458,6 +458,27 @@
See [method get_theme_color] for details.
</description>
</method>
+ <method name="get_theme_default_base_scale" qualifiers="const">
+ <return type="float" />
+ <description>
+ Returns the default base scale value from the first matching [Theme] in the tree if that [Theme] has a valid [member Theme.default_base_scale] value.
+ See [method get_theme_color] for details.
+ </description>
+ </method>
+ <method name="get_theme_default_font" qualifiers="const">
+ <return type="Font" />
+ <description>
+ Returns the default font from the first matching [Theme] in the tree if that [Theme] has a valid [member Theme.default_font] value.
+ See [method get_theme_color] for details.
+ </description>
+ </method>
+ <method name="get_theme_default_font_size" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the default font size value from the first matching [Theme] in the tree if that [Theme] has a valid [member Theme.default_font_size] value.
+ See [method get_theme_color] for details.
+ </description>
+ </method>
<method name="get_theme_font" qualifiers="const">
<return type="Font" />
<argument index="0" name="name" type="StringName" />
diff --git a/doc/classes/EditorSceneImporterMesh.xml b/doc/classes/ImporterMesh.xml
index 5d57a76d5f..ab344f908c 100644
--- a/doc/classes/EditorSceneImporterMesh.xml
+++ b/doc/classes/ImporterMesh.xml
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSceneImporterMesh" inherits="Resource" version="4.0">
+<class name="ImporterMesh" inherits="Resource" version="4.0">
<brief_description>
A [Resource] that contains vertex array-based geometry during the import process.
</brief_description>
<description>
- EditorSceneImporterMesh is a type of [Resource] analogous to [ArrayMesh]. It contains vertex array-based geometry, divided in [i]surfaces[/i]. Each surface contains a completely separate array and a material used to draw it. Design wise, a mesh with multiple surfaces is preferred to a single surface, because objects created in 3D editing software commonly contain multiple materials.
+ ImporterMesh is a type of [Resource] analogous to [ArrayMesh]. It contains vertex array-based geometry, divided in [i]surfaces[/i]. Each surface contains a completely separate array and a material used to draw it. Design wise, a mesh with multiple surfaces is preferred to a single surface, because objects created in 3D editing software commonly contain multiple materials.
- Unlike its runtime counterpart, [EditorSceneImporterMesh] contains mesh data before various import steps, such as lod and shadow mesh generation, have taken place. Modify surface data by calling [method clear], followed by [method add_surface] for each surface.
+ Unlike its runtime counterpart, [ImporterMesh] contains mesh data before various import steps, such as lod and shadow mesh generation, have taken place. Modify surface data by calling [method clear], followed by [method add_surface] for each surface.
</description>
<tutorials>
</tutorials>
@@ -37,7 +37,7 @@
<method name="clear">
<return type="void" />
<description>
- Removes all surfaces and blend shapes from this [EditorSceneImporterMesh].
+ Removes all surfaces and blend shapes from this [ImporterMesh].
</description>
</method>
<method name="get_blend_shape_count" qualifiers="const">
@@ -69,7 +69,7 @@
<return type="ArrayMesh" />
<argument index="0" name="base_mesh" type="ArrayMesh" default="null" />
<description>
- Returns the mesh data represented by this [EditorSceneImporterMesh] as a usable [ArrayMesh].
+ Returns the mesh data represented by this [ImporterMesh] as a usable [ArrayMesh].
This method caches the returned mesh, and subsequent calls will return the cached data until [method clear] is called.
If not yet cached and [code]base_mesh[/code] is provided, [code]base_mesh[/code] will be used and mutated.
</description>
diff --git a/doc/classes/EditorSceneImporterMeshNode3D.xml b/doc/classes/ImporterMeshInstance3D.xml
index 848448110e..6d572f543b 100644
--- a/doc/classes/EditorSceneImporterMeshNode3D.xml
+++ b/doc/classes/ImporterMeshInstance3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorSceneImporterMeshNode3D" inherits="Node3D" version="4.0">
+<class name="ImporterMeshInstance3D" inherits="Node3D" version="4.0">
<brief_description>
</brief_description>
<description>
@@ -7,7 +7,7 @@
<tutorials>
</tutorials>
<members>
- <member name="mesh" type="EditorSceneImporterMesh" setter="set_mesh" getter="get_mesh">
+ <member name="mesh" type="ImporterMesh" setter="set_mesh" getter="get_mesh">
</member>
<member name="skeleton_path" type="NodePath" setter="set_skeleton_path" getter="get_skeleton_path" default="NodePath(&quot;&quot;)">
</member>
diff --git a/doc/classes/Material.xml b/doc/classes/Material.xml
index a3e98228c6..f77b69b1f9 100644
--- a/doc/classes/Material.xml
+++ b/doc/classes/Material.xml
@@ -20,11 +20,12 @@
<members>
<member name="next_pass" type="Material" setter="set_next_pass" getter="get_next_pass">
Sets the [Material] to be used for the next pass. This renders the object again using a different material.
- [b]Note:[/b] only applies to [StandardMaterial3D]s and [ShaderMaterial]s with type "Spatial".
+ [b]Note:[/b] This only applies to [StandardMaterial3D]s and [ShaderMaterial]s with type "Spatial".
</member>
<member name="render_priority" type="int" setter="set_render_priority" getter="get_render_priority" default="0">
Sets the render priority for transparent objects in 3D scenes. Higher priority objects will be sorted in front of lower priority objects.
- [b]Note:[/b] this only applies to sorting of transparent objects. This will not impact how transparent objects are sorted relative to opaque objects. This is because opaque objects are not sorted, while transparent objects are sorted from back to front (subject to priority).
+ [b]Note:[/b] This only applies to [StandardMaterial3D]s and [ShaderMaterial]s with type "Spatial".
+ [b]Note:[/b] This only applies to sorting of transparent objects. This will not impact how transparent objects are sorted relative to opaque objects. This is because opaque objects are not sorted, while transparent objects are sorted from back to front (subject to priority).
</member>
</members>
<constants>
diff --git a/doc/classes/Theme.xml b/doc/classes/Theme.xml
index edf5874432..2f5648dda9 100644
--- a/doc/classes/Theme.xml
+++ b/doc/classes/Theme.xml
@@ -273,6 +273,24 @@
Returns [code]false[/code] if the theme does not have [code]theme_type[/code].
</description>
</method>
+ <method name="has_default_base_scale" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this theme has a valid [member default_base_scale] value.
+ </description>
+ </method>
+ <method name="has_default_font" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this theme has a valid [member default_font] value.
+ </description>
+ </method>
+ <method name="has_default_font_size" qualifiers="const">
+ <return type="bool" />
+ <description>
+ Returns [code]true[/code] if this theme has a valid [member default_font_size] value.
+ </description>
+ </method>
<method name="has_font" qualifiers="const">
<return type="bool" />
<argument index="0" name="name" type="StringName" />
@@ -484,11 +502,17 @@
</method>
</methods>
<members>
+ <member name="default_base_scale" type="float" setter="set_default_base_scale" getter="get_default_base_scale" default="0.0">
+ The default base scale factor of this [Theme] resource. Used by some controls to scale their visual properties based on a global scale factor. If this value is set to [code]0.0[/code], the global scale factor is used.
+ Use [method has_default_base_scale] to check if this value is valid.
+ </member>
<member name="default_font" type="Font" setter="set_default_font" getter="get_default_font">
- The theme's default font.
+ The default font of this [Theme] resource. Used as a fallback value for font items defined in this theme, but having invalid values. If this value is also invalid, the global default value is used.
+ Use [method has_default_font] to check if this value is valid.
</member>
<member name="default_font_size" type="int" setter="set_default_font_size" getter="get_default_font_size" default="-1">
- The theme's default font size. Set to [code]-1[/code] to ignore and use global default.
+ The default font size of this [Theme] resource. Used as a fallback value for font size items defined in this theme, but having invalid values. If this value is set to [code]-1[/code], the global default value is used.
+ Use [method has_default_font_size] to check if this value is valid.
</member>
</members>
<constants>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index 15d844aacb..0653c8b453 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -59,6 +59,21 @@
<description>
</description>
</method>
+ <method name="get_theme_default_base_scale" qualifiers="const">
+ <return type="float" />
+ <description>
+ </description>
+ </method>
+ <method name="get_theme_default_font" qualifiers="const">
+ <return type="Font" />
+ <description>
+ </description>
+ </method>
+ <method name="get_theme_default_font_size" qualifiers="const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
<method name="get_theme_font" qualifiers="const">
<return type="Font" />
<argument index="0" name="name" type="StringName" />
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 8bc87b7f81..a8fdca1b20 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -49,6 +49,7 @@
#include "core/version.h"
#include "core/version_hash.gen.h"
#include "main/main.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/gui/center_container.h"
#include "scene/gui/control.h"
#include "scene/gui/dialogs.h"
@@ -113,7 +114,6 @@
#include "editor/import/resource_importer_texture_atlas.h"
#include "editor/import/resource_importer_wav.h"
#include "editor/import/scene_import_settings.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
#include "editor/import_dock.h"
#include "editor/multi_node_edit.h"
#include "editor/node_dock.h"
@@ -3852,8 +3852,6 @@ void EditorNode::register_editor_types() {
GDREGISTER_CLASS(EditorSpinSlider);
GDREGISTER_CLASS(EditorResourcePicker);
GDREGISTER_CLASS(EditorScriptPicker);
- GDREGISTER_CLASS(EditorSceneImporterMesh);
- GDREGISTER_CLASS(EditorSceneImporterMeshNode3D);
GDREGISTER_VIRTUAL_CLASS(FileSystemDock);
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 0579fb4cbd..6efbcbc61e 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -292,7 +292,8 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Ref<Theme> theme = Ref<Theme>(memnew(Theme));
- const float default_contrast = 0.3;
+ // Controls may rely on the scale for their internal drawing logic.
+ theme->set_default_theme_base_scale(EDSCALE);
// Theme settings
Color accent_color = EDITOR_GET("interface/theme/accent_color");
@@ -310,6 +311,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Color preset_base_color;
float preset_contrast = 0;
+ const float default_contrast = 0.3;
+
// Please use alphabetical order if you're adding a new theme here
// (after "Custom")
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 3de7426302..4b01595028 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -33,8 +33,8 @@
#include "core/os/os.h"
#include "editor/editor_node.h"
#include "editor/import/collada.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
#include "scene/3d/camera_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/node_3d.h"
@@ -42,6 +42,7 @@
#include "scene/3d/skeleton_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
+#include "scene/resources/importer_mesh.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/surface_tool.h"
@@ -68,7 +69,7 @@ struct ColladaImport {
Map<String, NodeMap> node_map; //map from collada node to engine node
Map<String, String> node_name_map; //map from collada node to engine node
- Map<String, Ref<EditorSceneImporterMesh>> mesh_cache;
+ Map<String, Ref<ImporterMesh>> mesh_cache;
Map<String, Ref<Curve3D>> curve_cache;
Map<String, Ref<Material>> material_cache;
Map<Collada::Node *, Skeleton3D *> skeleton_map;
@@ -87,7 +88,7 @@ struct ColladaImport {
Error _create_scene(Collada::Node *p_node, Node3D *p_parent);
Error _create_resources(Collada::Node *p_node, bool p_use_compression);
Error _create_material(const String &p_target);
- Error _create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes = Vector<Ref<EditorSceneImporterMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false);
+ Error _create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ImporterMesh>> p_morph_meshes = Vector<Ref<ImporterMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false);
Error load(const String &p_path, int p_flags, bool p_force_make_tangents = false, bool p_use_compression = false);
void _fix_param_animation_tracks();
void create_animation(int p_clip, bool p_make_tracks_in_all_bones, bool p_import_value_tracks);
@@ -282,8 +283,8 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) {
node = memnew(Path3D);
} else {
//mesh since nothing else
- node = memnew(EditorSceneImporterMeshNode3D);
- //Object::cast_to<EditorSceneImporterMeshNode3D>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true);
+ node = memnew(ImporterMeshInstance3D);
+ //Object::cast_to<ImporterMeshInstance3D>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true);
}
} break;
case Collada::Node::TYPE_SKELETON: {
@@ -457,7 +458,7 @@ Error ColladaImport::_create_material(const String &p_target) {
return OK;
}
-Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) {
+Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform3D &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ImporterMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) {
bool local_xform_mirror = p_local_xform.basis.determinant() < 0;
if (p_morph_data) {
@@ -1087,10 +1088,10 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
}
}
- if (Object::cast_to<EditorSceneImporterMeshNode3D>(node)) {
+ if (Object::cast_to<ImporterMeshInstance3D>(node)) {
Collada::NodeGeometry *ng2 = static_cast<Collada::NodeGeometry *>(p_node);
- EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(node);
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(node);
ERR_FAIL_COND_V(!mi, ERR_BUG);
@@ -1099,7 +1100,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
String meshid;
Transform3D apply_xform;
Vector<int> bone_remap;
- Vector<Ref<EditorSceneImporterMesh>> morphs;
+ Vector<Ref<ImporterMesh>> morphs;
if (ng2->controller) {
String ngsource = ng2->source;
@@ -1168,10 +1169,10 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
for (int i = 0; i < names.size(); i++) {
String meshid2 = names[i];
if (collada.state.mesh_data_map.has(meshid2)) {
- Ref<EditorSceneImporterMesh> mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh));
+ Ref<ImporterMesh> mesh = Ref<ImporterMesh>(memnew(ImporterMesh));
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid2];
mesh->set_name(meshdata.name);
- Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, nullptr, Vector<Ref<EditorSceneImporterMesh>>(), false);
+ Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, nullptr, Vector<Ref<ImporterMesh>>(), false);
ERR_FAIL_COND_V(err, err);
morphs.push_back(mesh);
@@ -1194,7 +1195,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
meshid = ng2->source;
}
- Ref<EditorSceneImporterMesh> mesh;
+ Ref<ImporterMesh> mesh;
if (mesh_cache.has(meshid)) {
mesh = mesh_cache[meshid];
} else {
@@ -1202,7 +1203,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
//bleh, must ignore invalid
ERR_FAIL_COND_V(!collada.state.mesh_data_map.has(meshid), ERR_INVALID_DATA);
- mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh));
+ mesh = Ref<ImporterMesh>(memnew(ImporterMesh));
const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid];
String name = meshdata.name;
if (name == "") {
diff --git a/editor/import/editor_importer_bake_reset.cpp b/editor/import/editor_importer_bake_reset.cpp
index fb5de941ae..451a07351c 100644
--- a/editor/import/editor_importer_bake_reset.cpp
+++ b/editor/import/editor_importer_bake_reset.cpp
@@ -33,8 +33,8 @@
#include "core/error/error_list.h"
#include "core/error/error_macros.h"
#include "core/math/transform_3d.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
#include "resource_importer_scene.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/node_3d.h"
#include "scene/3d/skeleton_3d.h"
@@ -71,7 +71,7 @@ void BakeReset::_bake_animation_pose(Node *scene, const String &p_bake_anim) {
while (!queue.is_empty()) {
List<Node *>::Element *E = queue.front();
Node *node = E->get();
- EditorSceneImporterMeshNode3D *editor_mesh_3d = scene->cast_to<EditorSceneImporterMeshNode3D>(node);
+ ImporterMeshInstance3D *editor_mesh_3d = scene->cast_to<ImporterMeshInstance3D>(node);
MeshInstance3D *mesh_3d = scene->cast_to<MeshInstance3D>(node);
if (scene->cast_to<Skeleton3D>(node)) {
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index 34bc0a7d8d..4f75faedcb 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -32,10 +32,10 @@
#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
-#include "editor/import/scene_importer_mesh.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/node_3d.h"
+#include "scene/resources/importer_mesh.h"
#include "scene/resources/mesh.h"
#include "scene/resources/surface_tool.h"
@@ -439,13 +439,13 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in
Node3D *scene = memnew(Node3D);
for (const Ref<Mesh> &m : meshes) {
- Ref<EditorSceneImporterMesh> mesh;
+ Ref<ImporterMesh> mesh;
mesh.instantiate();
for (int i = 0; i < m->get_surface_count(); i++) {
mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i));
}
- EditorSceneImporterMeshNode3D *mi = memnew(EditorSceneImporterMeshNode3D);
+ ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D);
mi->set_mesh(mesh);
mi->set_name(m->get_name());
scene->add_child(mi);
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 2c9bc7dadf..1e93113488 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -34,9 +34,9 @@
#include "editor/editor_node.h"
#include "editor/import/editor_importer_bake_reset.h"
#include "editor/import/scene_import_settings.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
#include "scene/3d/area_3d.h"
#include "scene/3d/collision_shape_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/navigation_region_3d.h"
#include "scene/3d/physics_body_3d.h"
@@ -44,6 +44,7 @@
#include "scene/animation/animation_player.h"
#include "scene/resources/animation.h"
#include "scene/resources/box_shape_3d.h"
+#include "scene/resources/importer_mesh.h"
#include "scene/resources/packed_scene.h"
#include "scene/resources/resource_format_text.h"
#include "scene/resources/separation_ray_shape_3d.h"
@@ -233,7 +234,7 @@ static String _fixstr(const String &p_what, const String &p_str) {
return what;
}
-static void _pre_gen_shape_list(Ref<EditorSceneImporterMesh> &mesh, Vector<Ref<Shape3D>> &r_shape_list, bool p_convex) {
+static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r_shape_list, bool p_convex) {
ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value");
if (!p_convex) {
Ref<Shape3D> shape = mesh->create_trimesh_shape();
@@ -249,7 +250,7 @@ static void _pre_gen_shape_list(Ref<EditorSceneImporterMesh> &mesh, Vector<Ref<S
}
}
-Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> &collision_map) {
+Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map) {
// children first
for (int i = 0; i < p_node->get_child_count(); i++) {
Node *r = _pre_fix_node(p_node->get_child(i), p_root, collision_map);
@@ -267,10 +268,10 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
return nullptr;
}
- if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
- EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+ if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
- Ref<EditorSceneImporterMesh> m = mi->get_mesh();
+ Ref<ImporterMesh> m = mi->get_mesh();
if (m.is_valid()) {
for (int i = 0; i < m->get_surface_count(); i++) {
@@ -331,9 +332,9 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
if (isroot) {
return p_node;
}
- EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
if (mi) {
- Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
+ Ref<ImporterMesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
Vector<Ref<Shape3D>> shapes;
@@ -398,13 +399,13 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
colshape->set_owner(sb->get_owner());
}
- } else if (_teststr(name, "rigid") && Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+ } else if (_teststr(name, "rigid") && Object::cast_to<ImporterMeshInstance3D>(p_node)) {
if (isroot) {
return p_node;
}
- EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
- Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
+ Ref<ImporterMesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
Vector<Ref<Shape3D>> shapes;
@@ -426,10 +427,10 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
_add_shapes(rigid_body, shapes);
}
- } else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
- EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+ } else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<ImporterMeshInstance3D>(p_node)) {
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
- Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
+ Ref<ImporterMesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
Vector<Ref<Shape3D>> shapes;
@@ -465,14 +466,14 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
}
}
- } else if (_teststr(name, "navmesh") && Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+ } else if (_teststr(name, "navmesh") && Object::cast_to<ImporterMeshInstance3D>(p_node)) {
if (isroot) {
return p_node;
}
- EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
- Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
+ Ref<ImporterMesh> mesh = mi->get_mesh();
ERR_FAIL_COND_V(mesh.is_null(), nullptr);
NavigationRegion3D *nmi = memnew(NavigationRegion3D);
@@ -484,12 +485,12 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
memdelete(p_node);
p_node = nmi;
- } else if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
+ } else if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
//last attempt, maybe collision inside the mesh data
- EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
- Ref<EditorSceneImporterMesh> mesh = mi->get_mesh();
+ Ref<ImporterMesh> mesh = mi->get_mesh();
if (!mesh.is_null()) {
Vector<Ref<Shape3D>> shapes;
if (collision_map.has(mesh)) {
@@ -517,7 +518,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<E
return p_node;
}
-Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Set<Ref<EditorSceneImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps) {
+Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Set<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps) {
// children first
for (int i = 0; i < p_node->get_child_count(); i++) {
Node *r = _post_fix_node(p_node->get_child(i), p_root, collision_map, r_scanned_meshes, p_node_data, p_material_data, p_animation_data, p_animation_fps);
@@ -546,10 +547,10 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<
return nullptr;
}
- if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
- EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+ if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
- Ref<EditorSceneImporterMesh> m = mi->get_mesh();
+ Ref<ImporterMesh> m = mi->get_mesh();
if (m.is_valid()) {
if (!r_scanned_meshes.has(m)) {
@@ -669,10 +670,10 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<
}
//navmesh (node may have changed type above)
- if (Object::cast_to<EditorSceneImporterMeshNode3D>(p_node)) {
- EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+ if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
- Ref<EditorSceneImporterMesh> m = mi->get_mesh();
+ Ref<ImporterMesh> m = mi->get_mesh();
if (m.is_valid()) {
if (node_settings.has("generate/navmesh")) {
@@ -1247,7 +1248,7 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito
}
void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_mesh_data, bool p_generate_lods, bool p_create_shadow_meshes, LightBakeMode p_light_bake_mode, float p_lightmap_texel_size, const Vector<uint8_t> &p_src_lightmap_cache, Vector<Vector<uint8_t>> &r_lightmap_caches) {
- EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+ ImporterMeshInstance3D *src_mesh_node = Object::cast_to<ImporterMeshInstance3D>(p_node);
if (src_mesh_node) {
//is mesh
MeshInstance3D *mesh_node = memnew(MeshInstance3D);
@@ -1452,7 +1453,7 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file) {
return nullptr;
}
- Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
+ Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
_pre_fix_node(scene, scene, collision_map);
@@ -1527,8 +1528,8 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
animation_data = subresources["animations"];
}
- Set<Ref<EditorSceneImporterMesh>> scanned_meshes;
- Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
+ Set<Ref<ImporterMesh>> scanned_meshes;
+ Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map;
_pre_fix_node(scene, scene, collision_map);
_post_fix_node(scene, scene, collision_map, scanned_meshes, node_data, material_data, animation_data, fps);
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index e232b715be..2a67fa9aae 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -41,7 +41,7 @@
class Material;
class AnimationPlayer;
-class EditorSceneImporterMesh;
+class ImporterMesh;
class EditorSceneImporter : public RefCounted {
GDCLASS(EditorSceneImporter, RefCounted);
@@ -181,8 +181,8 @@ public:
// Import scenes *after* everything else (such as textures).
virtual int get_import_order() const override { return ResourceImporter::IMPORT_ORDER_SCENE; }
- Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> &collision_map);
- Node *_post_fix_node(Node *p_node, Node *p_root, Map<Ref<EditorSceneImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Set<Ref<EditorSceneImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps);
+ Node *_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map);
+ Node *_post_fix_node(Node *p_node, Node *p_root, Map<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Set<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps);
Ref<Animation> _save_animation_to_file(Ref<Animation> anim, bool p_save_to_file, String p_save_to_path, bool p_keep_custom_tracks);
void _create_clips(AnimationPlayer *anim, const Array &p_clips, bool p_bake_all);
diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp
index 7ab5308a47..95a96f9e26 100644
--- a/editor/import/scene_import_settings.cpp
+++ b/editor/import/scene_import_settings.cpp
@@ -31,7 +31,8 @@
#include "scene_import_settings.h"
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
+#include "scene/resources/importer_mesh.h"
#include "scene/resources/surface_tool.h"
class SceneImportSettingsData : public Object {
@@ -240,7 +241,7 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
p_node->set_meta("import_id", import_id);
}
- EditorSceneImporterMeshNode3D *src_mesh_node = Object::cast_to<EditorSceneImporterMeshNode3D>(p_node);
+ ImporterMeshInstance3D *src_mesh_node = Object::cast_to<ImporterMeshInstance3D>(p_node);
if (src_mesh_node) {
MeshInstance3D *mesh_node = memnew(MeshInstance3D);
@@ -249,7 +250,7 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
mesh_node->set_skin(src_mesh_node->get_skin());
mesh_node->set_skeleton_path(src_mesh_node->get_skeleton_path());
if (src_mesh_node->get_mesh().is_valid()) {
- Ref<EditorSceneImporterMesh> editor_mesh = src_mesh_node->get_mesh();
+ Ref<ImporterMesh> editor_mesh = src_mesh_node->get_mesh();
mesh_node->set_mesh(editor_mesh->get_mesh());
}
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index fb92359818..7b0fc07fe7 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -1840,47 +1840,6 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_lines(lines, material);
p_gizmo->add_handles(handles, get_material("handles"));
-
- ClippedCamera3D *clipcam = Object::cast_to<ClippedCamera3D>(camera);
- if (clipcam) {
- Node3D *parent = Object::cast_to<Node3D>(camera->get_parent());
- if (!parent) {
- return;
- }
- Vector3 cam_normal = -camera->get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized();
- Vector3 cam_x = camera->get_global_transform().basis.get_axis(Vector3::AXIS_X).normalized();
- Vector3 cam_y = camera->get_global_transform().basis.get_axis(Vector3::AXIS_Y).normalized();
- Vector3 cam_pos = camera->get_global_transform().origin;
- Vector3 parent_pos = parent->get_global_transform().origin;
-
- Plane parent_plane(parent_pos, cam_normal);
- Vector3 ray_from = parent_plane.project(cam_pos);
-
- lines.clear();
- lines.push_back(ray_from + cam_x * 0.5 + cam_y * 0.5);
- lines.push_back(ray_from + cam_x * 0.5 + cam_y * -0.5);
-
- lines.push_back(ray_from + cam_x * 0.5 + cam_y * -0.5);
- lines.push_back(ray_from + cam_x * -0.5 + cam_y * -0.5);
-
- lines.push_back(ray_from + cam_x * -0.5 + cam_y * -0.5);
- lines.push_back(ray_from + cam_x * -0.5 + cam_y * 0.5);
-
- lines.push_back(ray_from + cam_x * -0.5 + cam_y * 0.5);
- lines.push_back(ray_from + cam_x * 0.5 + cam_y * 0.5);
-
- if (parent_plane.distance_to(cam_pos) < 0) {
- lines.push_back(ray_from);
- lines.push_back(cam_pos);
- }
-
- Transform3D local = camera->get_global_transform().affine_inverse();
- for (int i = 0; i < lines.size(); i++) {
- lines.write[i] = local.xform(lines[i]);
- }
-
- p_gizmo->add_lines(lines, material);
- }
}
//////
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 2b1ca068ee..701d75fb08 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -433,10 +433,12 @@ void ScriptTextEditor::_validate_script() {
int warning_nb = warnings.size();
warnings_panel->clear();
+ bool has_connections_table = false;
// Add missing connections.
if (GLOBAL_GET("debug/gdscript/warnings/enable").booleanize()) {
Node *base = get_tree()->get_edited_scene_root();
if (base && missing_connections.size() > 0) {
+ has_connections_table = true;
warnings_panel->push_table(1);
for (const Connection &connection : missing_connections) {
String base_path = base->get_name();
@@ -458,6 +460,10 @@ void ScriptTextEditor::_validate_script() {
code_editor->set_error_count(errors.size());
code_editor->set_warning_count(warning_nb);
+ if (has_connections_table) {
+ warnings_panel->add_newline();
+ }
+
// Add script warnings.
warnings_panel->push_table(3);
for (const ScriptLanguage::Warning &w : warnings) {
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp
index 94b7e0ce38..371800d8f3 100644
--- a/modules/bullet/soft_body_bullet.cpp
+++ b/modules/bullet/soft_body_bullet.cpp
@@ -190,22 +190,24 @@ void SoftBodyBullet::get_node_position(int p_node_index, Vector3 &r_position) co
}
}
-void SoftBodyBullet::set_node_mass(int node_index, btScalar p_mass) {
+void SoftBodyBullet::set_node_mass(int p_node_index, btScalar p_mass) {
if (0 >= p_mass) {
- pin_node(node_index);
+ pin_node(p_node_index);
} else {
- unpin_node(node_index);
+ unpin_node(p_node_index);
}
if (bt_soft_body) {
- bt_soft_body->setMass(node_index, p_mass);
+ ERR_FAIL_INDEX(p_node_index, bt_soft_body->m_nodes.size());
+ bt_soft_body->setMass(p_node_index, p_mass);
}
}
-btScalar SoftBodyBullet::get_node_mass(int node_index) const {
+btScalar SoftBodyBullet::get_node_mass(int p_node_index) const {
if (bt_soft_body) {
- return bt_soft_body->getMass(node_index);
+ ERR_FAIL_INDEX_V(p_node_index, bt_soft_body->m_nodes.size(), 1);
+ return bt_soft_body->getMass(p_node_index);
} else {
- return -1 == search_node_pinned(node_index) ? 1 : 0;
+ return -1 == search_node_pinned(p_node_index) ? 1 : 0;
}
}
@@ -418,17 +420,25 @@ void SoftBodyBullet::setup_soft_body() {
// Set pinned nodes
for (int i = pinned_nodes.size() - 1; 0 <= i; --i) {
- bt_soft_body->setMass(pinned_nodes[i], 0);
+ const int node_index = pinned_nodes[i];
+ ERR_CONTINUE(0 > node_index || bt_soft_body->m_nodes.size() <= node_index);
+ bt_soft_body->setMass(node_index, 0);
}
}
void SoftBodyBullet::pin_node(int p_node_index) {
+ if (bt_soft_body) {
+ ERR_FAIL_INDEX(p_node_index, bt_soft_body->m_nodes.size());
+ }
if (-1 == search_node_pinned(p_node_index)) {
pinned_nodes.push_back(p_node_index);
}
}
void SoftBodyBullet::unpin_node(int p_node_index) {
+ if (bt_soft_body) {
+ ERR_FAIL_INDEX(p_node_index, bt_soft_body->m_nodes.size());
+ }
const int id = search_node_pinned(p_node_index);
if (-1 != id) {
pinned_nodes.remove(id);
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp
index dcea476275..7343bf87af 100644
--- a/modules/fbx/data/fbx_mesh_data.cpp
+++ b/modules/fbx/data/fbx_mesh_data.cpp
@@ -31,6 +31,7 @@
#include "fbx_mesh_data.h"
#include "core/templates/local_vector.h"
+#include "scene/resources/importer_mesh.h"
#include "scene/resources/mesh.h"
#include "scene/resources/surface_tool.h"
@@ -101,7 +102,7 @@ HashMap<int, Vector2> collect_uv(const Vector<VertexData<Vector2>> *p_data, Hash
return collection;
}
-EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) {
+ImporterMeshInstance3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) {
mesh_geometry = p_mesh_geometry;
// todo: make this just use a uint64_t FBX ID this is a copy of our original materials unfortunately.
const std::vector<const FBXDocParser::Material *> &material_lookup = model->GetMaterials();
@@ -344,7 +345,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
}
// Phase 6. Compose the mesh and return it.
- Ref<EditorSceneImporterMesh> mesh;
+ Ref<ImporterMesh> mesh;
mesh.instantiate();
// Add blend shape info.
@@ -380,7 +381,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
in_mesh_surface_id += 1;
}
- EditorSceneImporterMeshNode3D *godot_mesh = memnew(EditorSceneImporterMeshNode3D);
+ ImporterMeshInstance3D *godot_mesh = memnew(ImporterMeshInstance3D);
godot_mesh->set_mesh(mesh);
const String name = ImportUtils::FBXNodeToName(model->Name());
godot_mesh->set_name(name); // hurry up compiling >.<
diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h
index 24db4a5469..eec7f38cd6 100644
--- a/modules/fbx/data/fbx_mesh_data.h
+++ b/modules/fbx/data/fbx_mesh_data.h
@@ -35,7 +35,7 @@
#include "core/templates/local_vector.h"
#include "core/templates/ordered_hash_map.h"
#include "editor/import/resource_importer_scene.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/resources/surface_tool.h"
@@ -98,7 +98,7 @@ struct FBXMeshData : RefCounted {
// translate fbx mesh data from document context to FBX Mesh Geometry Context
bool valid_weight_indexes = false;
- EditorSceneImporterMeshNode3D *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression);
+ ImporterMeshInstance3D *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression);
void gen_weight_info(Ref<SurfaceTool> st, int vertex_id) const;
@@ -107,7 +107,7 @@ struct FBXMeshData : RefCounted {
int max_weight_count = 0;
uint64_t armature_id = 0;
bool valid_armature_id = false;
- EditorSceneImporterMeshNode3D *godot_mesh_instance = nullptr;
+ ImporterMeshInstance3D *godot_mesh_instance = nullptr;
private:
void sanitize_vertex_weights(const ImportState &state);
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
index e0663ab49d..e4de204cf1 100644
--- a/modules/fbx/editor_scene_importer_fbx.cpp
+++ b/modules/fbx/editor_scene_importer_fbx.cpp
@@ -40,9 +40,9 @@
#include "editor/editor_log.h"
#include "editor/editor_node.h"
#include "editor/import/resource_importer_scene.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
#include "scene/3d/bone_attachment_3d.h"
#include "scene/3d/camera_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/main/node.h"
#include "scene/resources/material.h"
@@ -627,7 +627,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
node_element;
node_element = node_element->next()) {
Ref<FBXNode> fbx_node = node_element->get();
- EditorSceneImporterMeshNode3D *mesh_node = nullptr;
+ ImporterMeshInstance3D *mesh_node = nullptr;
Ref<FBXMeshData> mesh_data_precached;
// check for valid geometry
@@ -768,7 +768,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
for (KeyValue<uint64_t, Ref<FBXMeshData>> &mesh_data : state.renderer_mesh_data) {
Ref<FBXMeshData> mesh = mesh_data.value;
const uint64_t mesh_id = mesh_data.key;
- EditorSceneImporterMeshNode3D *mesh_instance = mesh->godot_mesh_instance;
+ ImporterMeshInstance3D *mesh_instance = mesh->godot_mesh_instance;
const int mesh_weights = mesh->max_weight_count;
Ref<FBXSkeleton> skeleton;
const bool valid_armature = mesh->valid_armature_id;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index c35af9ca5b..ac031baa8c 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -1035,7 +1035,10 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
return_type.is_meta_type = false;
p_function->set_datatype(return_type);
if (p_function->return_type) {
- push_error("Constructor cannot have an explicit return type.", p_function->return_type);
+ GDScriptParser::DataType declared_return = resolve_datatype(p_function->return_type);
+ if (declared_return.kind != GDScriptParser::DataType::BUILTIN || declared_return.builtin_type != Variant::NIL) {
+ push_error("Constructor cannot have an explicit return type.", p_function->return_type);
+ }
}
} else {
GDScriptParser::DataType return_type = resolve_datatype(p_function->return_type);
@@ -1198,7 +1201,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
variable_type.kind = GDScriptParser::DataType::BUILTIN;
variable_type.builtin_type = Variant::INT; // Can this ever be a float or something else?
p_for->variable->set_datatype(variable_type);
- } else {
+ } else if (p_for->list) {
resolve_node(p_for->list);
if (p_for->list->datatype.has_container_element_type()) {
variable_type = p_for->list->datatype.get_container_element_type();
@@ -1213,7 +1216,9 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
variable_type.kind = GDScriptParser::DataType::VARIANT;
}
}
- p_for->variable->set_datatype(variable_type);
+ if (p_for->variable) {
+ p_for->variable->set_datatype(variable_type);
+ }
resolve_suite(p_for->loop);
p_for->set_datatype(p_for->loop->get_datatype());
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 2c02291795..9eee0b57f3 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1019,25 +1019,32 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
} else if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER && _is_class_member_property(codegen, static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name)) {
// Assignment to member property.
- GDScriptCodeGenerator::Address assigned = _parse_expression(codegen, r_error, assignment->assigned_value);
+ GDScriptCodeGenerator::Address assigned_value = _parse_expression(codegen, r_error, assignment->assigned_value);
if (r_error) {
return GDScriptCodeGenerator::Address();
}
- GDScriptCodeGenerator::Address assign_temp = assigned;
+
+ GDScriptCodeGenerator::Address to_assign = assigned_value;
+ bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE;
StringName name = static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
- if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
+ if (has_operation) {
+ GDScriptCodeGenerator::Address op_result = codegen.add_temporary();
GDScriptCodeGenerator::Address member = codegen.add_temporary();
gen->write_get_member(member, name);
- gen->write_binary_operator(assigned, assignment->variant_op, member, assigned);
- gen->pop_temporary();
+ gen->write_binary_operator(op_result, assignment->variant_op, member, assigned_value);
+ gen->pop_temporary(); // Pop member temp.
+ to_assign = op_result;
}
- gen->write_set_member(assigned, name);
+ gen->write_set_member(to_assign, name);
- if (assign_temp.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- gen->pop_temporary();
+ if (to_assign.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary(); // Pop the assigned expression or the temp result if it has operation.
+ }
+ if (has_operation && assigned_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary(); // Pop the assigned expression if not done before.
}
} else {
// Regular assignment.
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 83805f626a..e49bf518a2 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -2222,8 +2222,11 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
if (obj) {
List<String> options;
obj->get_argument_options(p_method, p_argidx, &options);
- for (const String &F : options) {
- ScriptCodeCompletionOption option(F, ScriptCodeCompletionOption::KIND_FUNCTION);
+ for (String &opt : options) {
+ if (opt.is_quoted()) {
+ opt = opt.unquote().quote(quote_style); // Handle user preference.
+ }
+ ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_FUNCTION);
r_result.insert(option.display, option);
}
}
@@ -2643,23 +2646,26 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
} break;
case GDScriptParser::COMPLETION_GET_NODE: {
+ // Handles the `$Node/Path` or `$"Some NodePath"` syntax specifically.
if (p_owner) {
List<String> opts;
p_owner->get_argument_options("get_node", 0, &opts);
for (const String &E : opts) {
+ r_forced = true;
String opt = E.strip_edges();
if (opt.is_quoted()) {
- r_forced = true;
- String idopt = opt.unquote();
- if (idopt.replace("/", "_").is_valid_identifier()) {
- ScriptCodeCompletionOption option(idopt, ScriptCodeCompletionOption::KIND_NODE_PATH);
- options.insert(option.display, option);
- } else {
- ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH);
- options.insert(option.display, option);
- }
+ // Remove quotes so that we can handle user preferred quote style,
+ // or handle NodePaths which are valid identifiers and don't need quotes.
+ opt = opt.unquote();
}
+ // The path needs quotes if it's not a valid identifier (with an exception
+ // for "/" as path separator, which also doesn't require quotes).
+ if (!opt.replace("/", "_").is_valid_identifier()) {
+ opt = opt.quote(quote_style); // Handle user preference.
+ }
+ ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH);
+ options.insert(option.display, option);
}
// Get autoloads.
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 63817e970a..ad75e8174c 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -1620,6 +1620,10 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() {
n_for->list = parse_expression(false);
+ if (!n_for->list) {
+ push_error(R"(Expected a list or range after "in".)");
+ }
+
consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "for" condition.)");
// Save break/continue state.
diff --git a/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.gd b/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.gd
new file mode 100644
index 0000000000..f6526aefb4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.gd
@@ -0,0 +1,13 @@
+extends Node
+
+func test():
+ process_priority = 10
+ var change = 20
+
+ print(process_priority)
+ print(change)
+
+ process_priority += change
+
+ print(process_priority)
+ print(change)
diff --git a/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.out b/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.out
new file mode 100644
index 0000000000..c9e6b34c77
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+10
+20
+30
+20
diff --git a/modules/gltf/config.py b/modules/gltf/config.py
index 52a97c93aa..a4736321fa 100644
--- a/modules/gltf/config.py
+++ b/modules/gltf/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return env["tools"] and not env["disable_3d"]
+ return not env["disable_3d"]
def configure(env):
@@ -22,6 +22,8 @@ def get_doc_classes():
"GLTFSpecGloss",
"GLTFState",
"GLTFTexture",
+ "GLTFDocumentExtension",
+ "GLTFDocumentExtensionConvertImporterMesh",
]
diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml
index 16e649f390..8d8e25e8b3 100644
--- a/modules/gltf/doc_classes/GLTFDocument.xml
+++ b/modules/gltf/doc_classes/GLTFDocument.xml
@@ -30,4 +30,8 @@
</description>
</method>
</methods>
+ <members>
+ <member name="extensions" type="GLTFDocumentExtension[]" setter="set_extensions" getter="get_extensions" default="[]">
+ </member>
+ </members>
</class>
diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
new file mode 100644
index 0000000000..390bd3b30b
--- /dev/null
+++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GLTFDocumentExtension" inherits="Resource" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="export_post">
+ <return type="int" enum="Error" />
+ <argument index="0" name="document" type="GLTFDocument" />
+ <description>
+ </description>
+ </method>
+ <method name="export_preflight">
+ <return type="int" enum="Error" />
+ <argument index="0" name="document" type="GLTFDocument" />
+ <argument index="1" name="node" type="Node" />
+ <description>
+ </description>
+ </method>
+ <method name="get_export_setting" qualifiers="const">
+ <return type="Variant" />
+ <argument index="0" name="key" type="StringName" />
+ <description>
+ </description>
+ </method>
+ <method name="get_export_setting_keys" qualifiers="const">
+ <return type="Array" />
+ <description>
+ </description>
+ </method>
+ <method name="get_import_setting" qualifiers="const">
+ <return type="Variant" />
+ <argument index="0" name="key" type="StringName" />
+ <description>
+ </description>
+ </method>
+ <method name="get_import_setting_keys" qualifiers="const">
+ <return type="Array" />
+ <description>
+ </description>
+ </method>
+ <method name="import_post">
+ <return type="int" enum="Error" />
+ <argument index="0" name="document" type="GLTFDocument" />
+ <argument index="1" name="node" type="Node" />
+ <description>
+ </description>
+ </method>
+ <method name="import_preflight">
+ <return type="int" enum="Error" />
+ <argument index="0" name="document" type="GLTFDocument" />
+ <description>
+ </description>
+ </method>
+ <method name="set_export_setting">
+ <return type="void" />
+ <argument index="0" name="key" type="StringName" />
+ <argument index="1" name="value" type="Variant" />
+ <description>
+ </description>
+ </method>
+ <method name="set_import_setting">
+ <return type="void" />
+ <argument index="0" name="key" type="StringName" />
+ <argument index="1" name="value" type="Variant" />
+ <description>
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml b/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml
new file mode 100644
index 0000000000..452eec5f4f
--- /dev/null
+++ b/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GLTFDocumentExtensionConvertImporterMesh" inherits="GLTFDocumentExtension" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/modules/gltf/doc_classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml
index 51e9fc032a..1e7199d229 100644
--- a/modules/gltf/doc_classes/GLTFMesh.xml
+++ b/modules/gltf/doc_classes/GLTFMesh.xml
@@ -9,7 +9,7 @@
<members>
<member name="blend_weights" type="PackedFloat32Array" setter="set_blend_weights" getter="get_blend_weights" default="PackedFloat32Array()">
</member>
- <member name="mesh" type="EditorSceneImporterMesh" setter="set_mesh" getter="get_mesh">
+ <member name="mesh" type="ImporterMesh" setter="set_mesh" getter="get_mesh">
</member>
</members>
</class>
diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp
index 3ce5ea23dc..25fda7ef3b 100644
--- a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp
+++ b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#if TOOLS_ENABLED
#include "editor_scene_exporter_gltf_plugin.h"
#include "core/config/project_settings.h"
#include "core/error/error_list.h"
@@ -93,3 +94,5 @@ void SceneExporterGLTFPlugin::convert_scene_to_gltf2() {
file_export_lib->set_current_file(filename + String(".gltf"));
file_export_lib->popup_centered_ratio();
}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.h b/modules/gltf/editor_scene_exporter_gltf_plugin.h
index c4f277fca2..89a8e27053 100644
--- a/modules/gltf/editor_scene_exporter_gltf_plugin.h
+++ b/modules/gltf/editor_scene_exporter_gltf_plugin.h
@@ -31,7 +31,9 @@
#ifndef EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
#define EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
+#if TOOLS_ENABLED
#include "editor/editor_plugin.h"
+
#include "editor_scene_importer_gltf.h"
class SceneExporterGLTFPlugin : public EditorPlugin {
@@ -47,5 +49,5 @@ public:
bool has_main_screen() const override;
SceneExporterGLTFPlugin(class EditorNode *p_node);
};
-
+#endif // TOOLS_ENABLED
#endif // EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp
index 12796c41d7..25875e7396 100644
--- a/modules/gltf/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor_scene_importer_gltf.cpp
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#if TOOLS_ENABLED
#include "editor_scene_importer_gltf.h"
#include "gltf_document.h"
@@ -60,3 +61,5 @@ Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path,
int p_bake_fps) {
return Ref<Animation>();
}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h
index eb8775b137..90663612a1 100644
--- a/modules/gltf/editor_scene_importer_gltf.h
+++ b/modules/gltf/editor_scene_importer_gltf.h
@@ -30,16 +30,17 @@
#ifndef EDITOR_SCENE_IMPORTER_GLTF_H
#define EDITOR_SCENE_IMPORTER_GLTF_H
-
+#ifdef TOOLS_ENABLED
#include "gltf_state.h"
+#include "gltf_document_extension.h"
+
#include "editor/import/resource_importer_scene.h"
#include "scene/main/node.h"
#include "scene/resources/packed_scene.h"
class Animation;
-#ifdef TOOLS_ENABLED
class EditorSceneImporterGLTF : public EditorSceneImporter {
GDCLASS(EditorSceneImporterGLTF, EditorSceneImporter);
@@ -50,5 +51,5 @@ public:
virtual Ref<Animation> import_animation(const String &p_path,
uint32_t p_flags, int p_bake_fps) override;
};
-#endif
+#endif // TOOLS_ENABLED
#endif // EDITOR_SCENE_IMPORTER_GLTF_H
diff --git a/modules/gltf/gltf_accessor.cpp b/modules/gltf/gltf_accessor.cpp
index daeb084916..85cec3fec4 100644
--- a/modules/gltf/gltf_accessor.cpp
+++ b/modules/gltf/gltf_accessor.cpp
@@ -30,6 +30,8 @@
#include "gltf_accessor.h"
+#include "gltf_document_extension.h"
+
void GLTFAccessor::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_buffer_view"), &GLTFAccessor::get_buffer_view);
ClassDB::bind_method(D_METHOD("set_buffer_view", "buffer_view"), &GLTFAccessor::set_buffer_view);
diff --git a/modules/gltf/gltf_accessor.h b/modules/gltf/gltf_accessor.h
index 57aea1026c..bec511f974 100644
--- a/modules/gltf/gltf_accessor.h
+++ b/modules/gltf/gltf_accessor.h
@@ -32,7 +32,9 @@
#define GLTF_ACCESSOR_H
#include "core/io/resource.h"
+
#include "gltf_document.h"
+#include "gltf_document_extension.h"
struct GLTFAccessor : public Resource {
GDCLASS(GLTFAccessor, Resource);
diff --git a/modules/gltf/gltf_buffer_view.cpp b/modules/gltf/gltf_buffer_view.cpp
index ba38a11c4c..d00e0f040f 100644
--- a/modules/gltf/gltf_buffer_view.cpp
+++ b/modules/gltf/gltf_buffer_view.cpp
@@ -30,6 +30,8 @@
#include "gltf_buffer_view.h"
+#include "gltf_document_extension.h"
+
void GLTFBufferView::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_buffer"), &GLTFBufferView::get_buffer);
ClassDB::bind_method(D_METHOD("set_buffer", "buffer"), &GLTFBufferView::set_buffer);
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 3f1f218e78..ba98592600 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -33,6 +33,8 @@
#include "gltf_accessor.h"
#include "gltf_animation.h"
#include "gltf_camera.h"
+#include "gltf_document_extension.h"
+#include "gltf_document_extension_convert_importer_mesh.h"
#include "gltf_light.h"
#include "gltf_mesh.h"
#include "gltf_node.h"
@@ -49,6 +51,7 @@
#include "core/io/json.h"
#include "core/math/disjoint_set.h"
#include "core/math/vector2.h"
+#include "core/variant/dictionary.h"
#include "core/variant/typed_array.h"
#include "core/variant/variant.h"
#include "core/version.h"
@@ -57,8 +60,12 @@
#include "editor/import/resource_importer_scene.h"
#include "scene/2d/node_2d.h"
#include "scene/3d/camera_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
#include "scene/animation/animation_player.h"
+#include "scene/resources/importer_mesh.h"
+#include "scene/resources/mesh.h"
+#include "scene/resources/multimesh.h"
#include "scene/resources/surface_tool.h"
#include "modules/modules_enabled.gen.h"
@@ -2101,7 +2108,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
Array meshes;
for (GLTFMeshIndex gltf_mesh_i = 0; gltf_mesh_i < state->meshes.size(); gltf_mesh_i++) {
print_verbose("glTF: Serializing mesh: " + itos(gltf_mesh_i));
- Ref<EditorSceneImporterMesh> import_mesh = state->meshes.write[gltf_mesh_i]->get_mesh();
+ Ref<ImporterMesh> import_mesh = state->meshes.write[gltf_mesh_i]->get_mesh();
if (import_mesh.is_null()) {
continue;
}
@@ -2493,7 +2500,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
Array primitives = d["primitives"];
const Dictionary &extras = d.has("extras") ? (Dictionary)d["extras"] :
Dictionary();
- Ref<EditorSceneImporterMesh> import_mesh;
+ Ref<ImporterMesh> import_mesh;
import_mesh.instantiate();
String mesh_name = "mesh";
if (d.has("name") && !String(d["name"]).is_empty()) {
@@ -2732,17 +2739,18 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
bool generate_tangents = (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL"));
+ Ref<SurfaceTool> mesh_surface_tool;
+ mesh_surface_tool.instantiate();
+ mesh_surface_tool->create_from_triangle_arrays(array);
+ if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
+ mesh_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
+ }
+ mesh_surface_tool->index();
if (generate_tangents) {
//must generate mikktspace tangents.. ergh..
- Ref<SurfaceTool> st;
- st.instantiate();
- st->create_from_triangle_arrays(array);
- if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
- st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
- }
- st->generate_tangents();
- array = st->commit_to_arrays();
+ mesh_surface_tool->generate_tangents();
}
+ array = mesh_surface_tool->commit_to_arrays();
Array morphs;
//blend shapes
@@ -2772,8 +2780,6 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
array_copy[l] = array[l];
}
- array_copy[Mesh::ARRAY_INDEX] = Variant();
-
if (t.has("POSITION")) {
Vector<Vector3> varr = _decode_accessor_as_vec3(state, t["POSITION"], true);
const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
@@ -2852,17 +2858,17 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
array_copy[Mesh::ARRAY_TANGENT] = tangents_v4;
}
+ Ref<SurfaceTool> blend_surface_tool;
+ blend_surface_tool.instantiate();
+ blend_surface_tool->create_from_triangle_arrays(array_copy);
+ if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
+ blend_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
+ }
+ blend_surface_tool->index();
if (generate_tangents) {
- Ref<SurfaceTool> st;
- st.instantiate();
- st->create_from_triangle_arrays(array_copy);
- if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
- st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
- }
- st->deindex();
- st->generate_tangents();
- array_copy = st->commit_to_arrays();
+ blend_surface_tool->generate_tangents();
}
+ array_copy = blend_surface_tool->commit_to_arrays();
morphs.push_back(array_copy);
}
@@ -2875,19 +2881,23 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
const int material = p["material"];
ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT);
Ref<BaseMaterial3D> mat3d = state->materials[material];
+ ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT);
if (has_vertex_color) {
mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
}
mat = mat3d;
- } else if (has_vertex_color) {
+ } else {
Ref<StandardMaterial3D> mat3d;
mat3d.instantiate();
- mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ if (has_vertex_color) {
+ mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ }
mat = mat3d;
}
-
- import_mesh->add_surface(primitive, array, morphs, Dictionary(), mat, mat.is_valid() ? mat->get_name() : String(), flags);
+ ERR_FAIL_NULL_V(mat, ERR_FILE_CORRUPT);
+ import_mesh->add_surface(primitive, array, morphs,
+ Dictionary(), mat, mat->get_name(), flags);
}
Vector<float> blend_weights;
@@ -3610,7 +3620,6 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
material->set_cull_mode(BaseMaterial3D::CULL_DISABLED);
}
}
-
if (d.has("alphaMode")) {
const String &am = d["alphaMode"];
if (am == "BLEND") {
@@ -5007,72 +5016,65 @@ GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInst
if (p_mesh_instance->get_mesh().is_null()) {
return -1;
}
- Ref<EditorSceneImporterMesh> import_mesh;
- import_mesh.instantiate();
- Ref<Mesh> godot_mesh = p_mesh_instance->get_mesh();
- if (godot_mesh.is_null()) {
- return -1;
- }
+ Ref<ImporterMesh> current_mesh;
+ current_mesh.instantiate();
Vector<float> blend_weights;
- Vector<String> blend_names;
- int32_t blend_count = godot_mesh->get_blend_shape_count();
- blend_names.resize(blend_count);
- blend_weights.resize(blend_count);
- for (int32_t blend_i = 0; blend_i < godot_mesh->get_blend_shape_count(); blend_i++) {
- String blend_name = godot_mesh->get_blend_shape_name(blend_i);
- blend_names.write[blend_i] = blend_name;
- import_mesh->add_blend_shape(blend_name);
- }
- for (int32_t surface_i = 0; surface_i < godot_mesh->get_surface_count(); surface_i++) {
- Mesh::PrimitiveType primitive_type = godot_mesh->surface_get_primitive_type(surface_i);
- Array arrays = godot_mesh->surface_get_arrays(surface_i);
- Array blend_shape_arrays = godot_mesh->surface_get_blend_shape_arrays(surface_i);
- Ref<Material> mat = godot_mesh->surface_get_material(surface_i);
- Ref<ArrayMesh> godot_array_mesh = godot_mesh;
- String surface_name;
- if (godot_array_mesh.is_valid()) {
- surface_name = godot_array_mesh->surface_get_name(surface_i);
- }
- if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) {
- mat = p_mesh_instance->get_surface_override_material(surface_i);
- }
- if (p_mesh_instance->get_material_override().is_valid()) {
- mat = p_mesh_instance->get_material_override();
- }
- import_mesh->add_surface(primitive_type, arrays, blend_shape_arrays, Dictionary(), mat, surface_name, godot_mesh->surface_get_format(surface_i));
- }
- for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) {
- blend_weights.write[blend_i] = 0.0f;
+ {
+ Ref<Mesh> import_mesh = p_mesh_instance->get_mesh();
+ Ref<ArrayMesh> import_array_mesh = p_mesh_instance->get_mesh();
+ if (import_mesh->get_blend_shape_count()) {
+ ArrayMesh::BlendShapeMode shape_mode = ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED;
+ if (import_array_mesh.is_valid()) {
+ shape_mode = import_array_mesh->get_blend_shape_mode();
+ }
+ current_mesh->set_blend_shape_mode(shape_mode);
+ for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) {
+ current_mesh->add_blend_shape(import_mesh->get_blend_shape_name(morph_i));
+ }
+ }
+ for (int32_t surface_i = 0; surface_i < import_mesh->get_surface_count(); surface_i++) {
+ Array array = import_mesh->surface_get_arrays(surface_i);
+ Ref<Material> mat = import_mesh->surface_get_material(surface_i);
+ String mat_name;
+ if (mat.is_valid()) {
+ mat_name = mat->get_name();
+ }
+ current_mesh->add_surface(import_mesh->surface_get_primitive_type(surface_i),
+ array, import_mesh->surface_get_blend_shape_arrays(surface_i), import_mesh->surface_get_lods(surface_i), mat,
+ mat_name, import_mesh->surface_get_format(surface_i));
+ }
+ int32_t blend_count = import_mesh->get_blend_shape_count();
+ blend_weights.resize(blend_count);
+ for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) {
+ blend_weights.write[blend_i] = 0.0f;
+ }
}
Ref<GLTFMesh> gltf_mesh;
gltf_mesh.instantiate();
- gltf_mesh->set_mesh(import_mesh);
+ gltf_mesh->set_mesh(current_mesh);
gltf_mesh->set_blend_weights(blend_weights);
GLTFMeshIndex mesh_i = state->meshes.size();
state->meshes.push_back(gltf_mesh);
return mesh_i;
}
-EditorSceneImporterMeshNode3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) {
+ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index) {
Ref<GLTFNode> gltf_node = state->nodes[node_index];
ERR_FAIL_INDEX_V(gltf_node->mesh, state->meshes.size(), nullptr);
- EditorSceneImporterMeshNode3D *mi = memnew(EditorSceneImporterMeshNode3D);
+ ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D);
print_verbose("glTF: Creating mesh for: " + gltf_node->get_name());
Ref<GLTFMesh> mesh = state->meshes.write[gltf_node->mesh];
if (mesh.is_null()) {
return mi;
}
- Ref<EditorSceneImporterMesh> import_mesh = mesh->get_mesh();
+ Ref<ImporterMesh> import_mesh = mesh->get_mesh();
if (import_mesh.is_null()) {
return mi;
}
mi->set_mesh(import_mesh);
- for (int i = 0; i < mesh->get_blend_weights().size(); i++) {
- mi->set("blend_shapes/" + mesh->get_mesh()->get_blend_shape_name(i), mesh->get_blend_weights()[i]);
- }
return mi;
}
@@ -5241,7 +5243,7 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, co
return;
} else if (cast_to<MultiMeshInstance3D>(p_current)) {
MultiMeshInstance3D *multi = cast_to<MultiMeshInstance3D>(p_current);
- _convert_mult_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, state);
+ _convert_multi_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, state);
#ifdef MODULE_CSG_ENABLED
} else if (cast_to<CSGShape3D>(p_current)) {
CSGShape3D *shape = cast_to<CSGShape3D>(p_current);
@@ -5292,13 +5294,8 @@ void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeInd
}
Ref<GLTFMesh> gltf_mesh;
gltf_mesh.instantiate();
- Ref<EditorSceneImporterMesh> import_mesh;
- import_mesh.instantiate();
- Ref<ArrayMesh> array_mesh = csg->get_meshes()[1];
- for (int32_t surface_i = 0; surface_i < array_mesh->get_surface_count(); surface_i++) {
- import_mesh->add_surface(Mesh::PrimitiveType::PRIMITIVE_TRIANGLES, array_mesh->surface_get_arrays(surface_i), Array(), Dictionary(), mat, array_mesh->surface_get_name(surface_i));
- }
- gltf_mesh->set_mesh(import_mesh);
+ Ref<ImporterMesh> array_mesh = csg->get_meshes()[1];
+ gltf_mesh->set_mesh(array_mesh);
GLTFMeshIndex mesh_i = state->meshes.size();
state->meshes.push_back(gltf_mesh);
gltf_node->mesh = mesh_i;
@@ -5364,7 +5361,7 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex
Vector3 cell_location = cells[k];
int32_t cell = p_grid_map->get_cell_item(
Vector3(cell_location.x, cell_location.y, cell_location.z));
- EditorSceneImporterMeshNode3D *import_mesh_node = memnew(EditorSceneImporterMeshNode3D);
+ ImporterMeshInstance3D *import_mesh_node = memnew(ImporterMeshInstance3D);
import_mesh_node->set_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell));
Transform3D cell_xform;
cell_xform.basis.set_orthogonal_index(
@@ -5386,49 +5383,72 @@ void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex
}
#endif // MODULE_GRIDMAP_ENABLED
-void GLTFDocument::_convert_mult_mesh_instance_to_gltf(MultiMeshInstance3D *p_multi_mesh_instance, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
+void GLTFDocument::_convert_multi_mesh_instance_to_gltf(
+ MultiMeshInstance3D *p_multi_mesh_instance,
+ GLTFNodeIndex p_parent_node_index,
+ GLTFNodeIndex p_root_node_index,
+ Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
+ ERR_FAIL_COND(!p_multi_mesh_instance);
Ref<MultiMesh> multi_mesh = p_multi_mesh_instance->get_multimesh();
- if (multi_mesh.is_valid()) {
- for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count();
- instance_i++) {
- GLTFNode *new_gltf_node = memnew(GLTFNode);
- Transform3D transform;
- if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) {
- Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i);
- transform.origin =
- Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y);
- real_t rotation = xform_2d.get_rotation();
- Quaternion quaternion(Vector3(0, 1, 0), rotation);
- Size2 scale = xform_2d.get_scale();
- transform.basis.set_quaternion_scale(quaternion,
- Vector3(scale.x, 0, scale.y));
- transform =
- p_multi_mesh_instance->get_transform() * transform;
- } else if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_3D) {
- transform = p_multi_mesh_instance->get_transform() *
- multi_mesh->get_instance_transform(instance_i);
- }
- Ref<ArrayMesh> mm = multi_mesh->get_mesh();
- if (mm.is_valid()) {
- Ref<EditorSceneImporterMesh> mesh;
- mesh.instantiate();
- for (int32_t surface_i = 0; surface_i < mm->get_surface_count(); surface_i++) {
- Array surface = mm->surface_get_arrays(surface_i);
- mesh->add_surface(mm->surface_get_primitive_type(surface_i), surface, Array(), Dictionary(),
- mm->surface_get_material(surface_i), mm->get_name());
- }
- Ref<GLTFMesh> gltf_mesh;
- gltf_mesh.instantiate();
- gltf_mesh->set_name(multi_mesh->get_name());
- gltf_mesh->set_mesh(mesh);
- new_gltf_node->mesh = state->meshes.size();
- state->meshes.push_back(gltf_mesh);
- }
- new_gltf_node->xform = transform;
- new_gltf_node->set_name(_gen_unique_name(state, p_multi_mesh_instance->get_name()));
- gltf_node->children.push_back(state->nodes.size());
- state->nodes.push_back(new_gltf_node);
+ if (multi_mesh.is_null()) {
+ return;
+ }
+ Ref<GLTFMesh> gltf_mesh;
+ gltf_mesh.instantiate();
+ Ref<Mesh> mesh = multi_mesh->get_mesh();
+ if (mesh.is_null()) {
+ return;
+ }
+ gltf_mesh->set_name(multi_mesh->get_name());
+ Ref<ImporterMesh> importer_mesh;
+ importer_mesh.instantiate();
+ Ref<ArrayMesh> array_mesh = multi_mesh->get_mesh();
+ if (array_mesh.is_valid()) {
+ importer_mesh->set_blend_shape_mode(array_mesh->get_blend_shape_mode());
+ for (int32_t blend_i = 0; blend_i < array_mesh->get_blend_shape_count(); blend_i++) {
+ importer_mesh->add_blend_shape(array_mesh->get_blend_shape_name(blend_i));
+ }
+ }
+ for (int32_t surface_i = 0; surface_i < mesh->get_surface_count(); surface_i++) {
+ Ref<Material> mat = mesh->surface_get_material(surface_i);
+ String material_name;
+ if (mat.is_valid()) {
+ material_name = mat->get_name();
}
+ Array blend_arrays;
+ if (array_mesh.is_valid()) {
+ blend_arrays = array_mesh->surface_get_blend_shape_arrays(surface_i);
+ }
+ importer_mesh->add_surface(mesh->surface_get_primitive_type(surface_i), mesh->surface_get_arrays(surface_i),
+ blend_arrays, mesh->surface_get_lods(surface_i), mat, material_name, mesh->surface_get_format(surface_i));
+ }
+ gltf_mesh->set_mesh(importer_mesh);
+ GLTFMeshIndex mesh_index = state->meshes.size();
+ state->meshes.push_back(gltf_mesh);
+ for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count();
+ instance_i++) {
+ Transform3D transform;
+ if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) {
+ Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i);
+ transform.origin =
+ Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y);
+ real_t rotation = xform_2d.get_rotation();
+ Quaternion quaternion(Vector3(0, 1, 0), rotation);
+ Size2 scale = xform_2d.get_scale();
+ transform.basis.set_quaternion_scale(quaternion,
+ Vector3(scale.x, 0, scale.y));
+ transform = p_multi_mesh_instance->get_transform() * transform;
+ } else if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_3D) {
+ transform = p_multi_mesh_instance->get_transform() *
+ multi_mesh->get_instance_transform(instance_i);
+ }
+ Ref<GLTFNode> new_gltf_node;
+ new_gltf_node.instantiate();
+ new_gltf_node->mesh = mesh_index;
+ new_gltf_node->xform = transform;
+ new_gltf_node->set_name(_gen_unique_name(state, p_multi_mesh_instance->get_name()));
+ gltf_node->children.push_back(state->nodes.size());
+ state->nodes.push_back(new_gltf_node);
}
}
@@ -6106,8 +6126,8 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo
Map<GLTFNodeIndex, Node *>::Element *mi_element = state->scene_nodes.find(node_i);
ERR_CONTINUE_MSG(mi_element == nullptr, vformat("Unable to find node %d", node_i));
- EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(mi_element->get());
- ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to EditorSceneImporterMeshNode3D", node_i, mi_element->get()->get_class_name()));
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(mi_element->get());
+ ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to ImporterMeshInstance3D", node_i, mi_element->get()->get_class_name()));
const GLTFSkeletonIndex skel_i = state->skins.write[node->skin]->skeleton;
Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i];
@@ -6748,10 +6768,25 @@ Error GLTFDocument::save_scene(Node *p_node, const String &p_path,
Ref<GLTFDocument> gltf_document;
gltf_document.instantiate();
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ Error err = ext->export_preflight(this, p_node);
+ ERR_FAIL_COND_V(err != OK, err);
+ }
+
if (r_state == Ref<GLTFState>()) {
r_state.instantiate();
}
- return gltf_document->serialize(r_state, p_node, p_path);
+ Error err = gltf_document->serialize(r_state, p_node, p_path);
+ ERR_FAIL_COND_V(err != OK, err);
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ err = ext->export_post(this);
+ ERR_FAIL_COND_V(err != OK, err);
+ }
+ return OK;
}
Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state, List<String> *r_missing_deps, Error *r_err) {
@@ -6764,6 +6799,15 @@ Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, in
Ref<GLTFDocument> gltf_document;
gltf_document.instantiate();
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ Error err = ext->import_preflight(this);
+ if (r_err) {
+ *r_err = err;
+ }
+ ERR_FAIL_COND_V(err != OK, nullptr);
+ }
Error err = gltf_document->parse(r_state, p_path);
if (r_err) {
*r_err = err;
@@ -6783,7 +6827,15 @@ Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, in
gltf_document->_import_animation(r_state, ap, i, p_bake_fps);
}
}
-
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ err = ext->import_post(this, root);
+ if (r_err) {
+ *r_err = err;
+ }
+ ERR_FAIL_COND_V(err != OK, nullptr);
+ }
return root;
}
@@ -6792,6 +6844,14 @@ void GLTFDocument::_bind_methods() {
&GLTFDocument::save_scene, DEFVAL(0), DEFVAL(30), DEFVAL(Ref<GLTFState>()));
ClassDB::bind_method(D_METHOD("import_scene", "path", "flags", "bake_fps", "state"),
&GLTFDocument::import_scene, DEFVAL(0), DEFVAL(30), DEFVAL(Ref<GLTFState>()));
+ ClassDB::bind_method(D_METHOD("set_extensions", "extensions"),
+ &GLTFDocument::set_extensions);
+ ClassDB::bind_method(D_METHOD("get_extensions"),
+ &GLTFDocument::get_extensions);
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "extensions", PROPERTY_HINT_ARRAY_TYPE,
+ vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "GLTFDocumentExtension"),
+ PROPERTY_USAGE_DEFAULT),
+ "set_extensions", "get_extensions");
}
void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> state) {
@@ -6817,3 +6877,21 @@ Node *GLTFDocument::import_scene(const String &p_path, uint32_t p_flags, int32_t
}
return node;
}
+
+void GLTFDocument::set_extensions(TypedArray<GLTFDocumentExtension> p_extensions) {
+ document_extensions = p_extensions;
+}
+
+TypedArray<GLTFDocumentExtension> GLTFDocument::get_extensions() const {
+ return document_extensions;
+}
+
+GLTFDocument::GLTFDocument() {
+ bool is_editor = ::Engine::get_singleton()->is_editor_hint();
+ if (is_editor) {
+ return;
+ }
+ Ref<GLTFDocumentExtensionConvertImporterMesh> extension_editor;
+ extension_editor.instantiate();
+ document_extensions.push_back(extension_editor);
+}
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 18aeb81bc0..7317c6a9a3 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -33,8 +33,11 @@
#include "gltf_animation.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "core/variant/dictionary.h"
+#include "core/variant/variant.h"
+#include "gltf_document_extension_convert_importer_mesh.h"
#include "scene/3d/bone_attachment_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/node_3d.h"
@@ -54,6 +57,7 @@ class GLTFSkeleton;
class CSGShape3D;
class GridMap;
class MultiMeshInstance3D;
+class GLTFDocumentExtension;
using GLTFAccessorIndex = int;
using GLTFAnimationIndex = int;
@@ -74,11 +78,13 @@ class GLTFDocument : public Resource {
friend class GLTFState;
friend class GLTFSkin;
friend class GLTFSkeleton;
+ TypedArray<GLTFDocumentExtension> document_extensions;
private:
const float BAKE_FPS = 30.0f;
public:
+ GLTFDocument();
const int32_t JOINT_GROUP_SIZE = 4;
enum GLTFType {
TYPE_SCALAR,
@@ -118,6 +124,8 @@ public:
Error save_scene(Node *p_node, const String &p_path,
const String &p_src_path, uint32_t p_flags,
float p_bake_fps, Ref<GLTFState> r_state);
+ void set_extensions(TypedArray<GLTFDocumentExtension> p_extensions);
+ TypedArray<GLTFDocumentExtension> get_extensions() const;
private:
template <class T>
@@ -280,12 +288,10 @@ private:
Skeleton3D *skeleton,
const GLTFNodeIndex node_index,
const GLTFNodeIndex bone_index);
- EditorSceneImporterMeshNode3D *_generate_mesh_instance(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index);
- Camera3D *_generate_camera(Ref<GLTFState> state, Node *scene_parent,
- const GLTFNodeIndex node_index);
- Node3D *_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index);
- Node3D *_generate_spatial(Ref<GLTFState> state, Node *scene_parent,
- const GLTFNodeIndex node_index);
+ ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index);
+ Camera3D *_generate_camera(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index);
+ Node3D *_generate_light(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index);
+ Node3D *_generate_spatial(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index);
void _assign_scene_names(Ref<GLTFState> state);
template <class T>
T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values,
@@ -420,8 +426,8 @@ public:
GLTFNodeIndex p_root_node_index,
Ref<GLTFNode> gltf_node, Ref<GLTFState> state);
#endif // MODULE_GRIDMAP_ENABLED
- void _convert_mult_mesh_instance_to_gltf(
- MultiMeshInstance3D *p_scene_parent,
+ void _convert_multi_mesh_instance_to_gltf(
+ MultiMeshInstance3D *p_multi_mesh_instance,
GLTFNodeIndex p_parent_node_index,
GLTFNodeIndex p_root_node_index,
Ref<GLTFNode> gltf_node, Ref<GLTFState> state);
diff --git a/modules/gltf/gltf_document_extension.cpp b/modules/gltf/gltf_document_extension.cpp
new file mode 100644
index 0000000000..a423059a9c
--- /dev/null
+++ b/modules/gltf/gltf_document_extension.cpp
@@ -0,0 +1,88 @@
+/*************************************************************************/
+/* gltf_document_extension.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_document_extension.h"
+
+#include "gltf_document.h"
+
+void GLTFDocumentExtension::_bind_methods() {
+ // Import
+ ClassDB::bind_method(D_METHOD("get_import_setting_keys"),
+ &GLTFDocumentExtension::get_import_setting_keys);
+ ClassDB::bind_method(D_METHOD("import_preflight", "document"),
+ &GLTFDocumentExtension::import_preflight);
+ ClassDB::bind_method(D_METHOD("get_import_setting", "key"),
+ &GLTFDocumentExtension::get_import_setting);
+ ClassDB::bind_method(D_METHOD("set_import_setting", "key", "value"),
+ &GLTFDocumentExtension::set_import_setting);
+ ClassDB::bind_method(D_METHOD("import_post", "document", "node"),
+ &GLTFDocumentExtension::import_post);
+ // Export
+ ClassDB::bind_method(D_METHOD("get_export_setting_keys"),
+ &GLTFDocumentExtension::get_export_setting_keys);
+ ClassDB::bind_method(D_METHOD("get_export_setting", "key"),
+ &GLTFDocumentExtension::get_export_setting);
+ ClassDB::bind_method(D_METHOD("set_export_setting", "key", "value"),
+ &GLTFDocumentExtension::set_export_setting);
+ ClassDB::bind_method(D_METHOD("export_preflight", "document", "node"),
+ &GLTFDocumentExtension::export_preflight);
+ ClassDB::bind_method(D_METHOD("export_post", "document"),
+ &GLTFDocumentExtension::export_post);
+}
+
+Array GLTFDocumentExtension::get_import_setting_keys() const {
+ return import_settings.keys();
+}
+
+Variant GLTFDocumentExtension::get_import_setting(const StringName &p_key) const {
+ if (!import_settings.has(p_key)) {
+ return Variant();
+ }
+ return import_settings[p_key];
+}
+
+void GLTFDocumentExtension::set_import_setting(const StringName &p_key, Variant p_var) {
+ import_settings[p_key] = p_var;
+}
+
+Array GLTFDocumentExtension::get_export_setting_keys() const {
+ return import_settings.keys();
+}
+
+Variant GLTFDocumentExtension::get_export_setting(const StringName &p_key) const {
+ if (!import_settings.has(p_key)) {
+ return Variant();
+ }
+ return import_settings[p_key];
+}
+
+void GLTFDocumentExtension::set_export_setting(const StringName &p_key, Variant p_var) {
+ import_settings[p_key] = p_var;
+}
diff --git a/modules/gltf/gltf_document_extension.h b/modules/gltf/gltf_document_extension.h
new file mode 100644
index 0000000000..622a65708c
--- /dev/null
+++ b/modules/gltf/gltf_document_extension.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* gltf_document_extension.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_DOCUMENT_EXTENSION_H
+#define GLTF_DOCUMENT_EXTENSION_H
+
+#include "core/io/resource.h"
+#include "core/variant/dictionary.h"
+#include "core/variant/typed_array.h"
+#include "core/variant/variant.h"
+class GLTFDocument;
+class GLTFDocumentExtension : public Resource {
+ GDCLASS(GLTFDocumentExtension, Resource);
+
+ Dictionary import_settings;
+ Dictionary export_settings;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual Array get_import_setting_keys() const;
+ virtual Variant get_import_setting(const StringName &p_key) const;
+ virtual void set_import_setting(const StringName &p_key, Variant p_var);
+ virtual Error import_preflight(Ref<GLTFDocument> p_document) { return OK; }
+ virtual Error import_post(Ref<GLTFDocument> p_document, Node *p_node) { return OK; }
+
+public:
+ virtual Array get_export_setting_keys() const;
+ virtual Variant get_export_setting(const StringName &p_key) const;
+ virtual void set_export_setting(const StringName &p_key, Variant p_var);
+ virtual Error export_preflight(Ref<GLTFDocument> p_document, Node *p_node) { return OK; }
+ virtual Error export_post(Ref<GLTFDocument> p_document) { return OK; }
+};
+
+#endif // GLTF_DOCUMENT_EXTENSION_H
diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp
new file mode 100644
index 0000000000..78a98dfa3e
--- /dev/null
+++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* gltf_document_extension_convert_importer_mesh.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "gltf_document_extension_convert_importer_mesh.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/resources/importer_mesh.h"
+
+#include <cstddef>
+
+void GLTFDocumentExtensionConvertImporterMesh::_bind_methods() {
+}
+
+Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFDocument> p_document, Node *p_node) {
+ List<Node *> queue;
+ queue.push_back(p_node);
+ List<Node *> delete_queue;
+ while (!queue.is_empty()) {
+ List<Node *>::Element *E = queue.front();
+ Node *node = E->get();
+ {
+ ImporterMeshInstance3D *mesh_3d = cast_to<ImporterMeshInstance3D>(node);
+ if (mesh_3d) {
+ MeshInstance3D *mesh_instance_node_3d = memnew(MeshInstance3D);
+ Ref<ImporterMesh> mesh = mesh_3d->get_mesh();
+ if (mesh.is_valid()) {
+ Ref<ArrayMesh> array_mesh = mesh->get_mesh();
+ mesh_instance_node_3d->set_name(node->get_name());
+ mesh_instance_node_3d->set_transform(mesh_3d->get_transform());
+ mesh_instance_node_3d->set_mesh(array_mesh);
+ mesh_instance_node_3d->set_skin(mesh_3d->get_skin());
+ mesh_instance_node_3d->set_skeleton_path(mesh_3d->get_skeleton_path());
+ node->replace_by(mesh_instance_node_3d);
+ delete_queue.push_back(node);
+ } else {
+ memdelete(mesh_instance_node_3d);
+ }
+ }
+ }
+ int child_count = node->get_child_count();
+ for (int i = 0; i < child_count; i++) {
+ queue.push_back(node->get_child(i));
+ }
+ queue.pop_front();
+ }
+ while (!queue.is_empty()) {
+ List<Node *>::Element *E = delete_queue.front();
+ Node *node = E->get();
+ memdelete(node);
+ delete_queue.pop_front();
+ }
+ return OK;
+}
diff --git a/modules/gltf/gltf_document_extension_convert_importer_mesh.h b/modules/gltf/gltf_document_extension_convert_importer_mesh.h
new file mode 100644
index 0000000000..85ddb4d250
--- /dev/null
+++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.h
@@ -0,0 +1,55 @@
+/*************************************************************************/
+/* gltf_document_extension_convert_importer_mesh.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef GLTF_EXTENSION_EDITOR_H
+#define GLTF_EXTENSION_EDITOR_H
+
+#include "core/io/resource.h"
+#include "core/variant/dictionary.h"
+
+#include "gltf_document.h"
+#include "gltf_document_extension.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/main/node.h"
+#include "scene/resources/importer_mesh.h"
+
+class GLTFDocumentExtension;
+class GLTFDocument;
+class GLTFDocumentExtensionConvertImporterMesh : public GLTFDocumentExtension {
+ GDCLASS(GLTFDocumentExtensionConvertImporterMesh, GLTFDocumentExtension);
+
+protected:
+ static void _bind_methods();
+
+public:
+ Error import_post(Ref<GLTFDocument> p_document, Node *p_node) override;
+};
+#endif // GLTF_EXTENSION_EDITOR_H
diff --git a/modules/gltf/gltf_mesh.cpp b/modules/gltf/gltf_mesh.cpp
index 8c10e42c89..747820521a 100644
--- a/modules/gltf/gltf_mesh.cpp
+++ b/modules/gltf/gltf_mesh.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "gltf_mesh.h"
-#include "editor/import/scene_importer_mesh.h"
+#include "scene/resources/importer_mesh.h"
void GLTFMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mesh"), &GLTFMesh::get_mesh);
@@ -41,11 +41,11 @@ void GLTFMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "blend_weights"), "set_blend_weights", "get_blend_weights"); // Vector<float>
}
-Ref<EditorSceneImporterMesh> GLTFMesh::get_mesh() {
+Ref<ImporterMesh> GLTFMesh::get_mesh() {
return mesh;
}
-void GLTFMesh::set_mesh(Ref<EditorSceneImporterMesh> p_mesh) {
+void GLTFMesh::set_mesh(Ref<ImporterMesh> p_mesh) {
mesh = p_mesh;
}
diff --git a/modules/gltf/gltf_mesh.h b/modules/gltf/gltf_mesh.h
index 0fc750fc9f..3aba0ede32 100644
--- a/modules/gltf/gltf_mesh.h
+++ b/modules/gltf/gltf_mesh.h
@@ -33,22 +33,23 @@
#include "core/io/resource.h"
#include "editor/import/resource_importer_scene.h"
-#include "editor/import/scene_importer_mesh.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
+#include "scene/resources/importer_mesh.h"
#include "scene/resources/mesh.h"
class GLTFMesh : public Resource {
GDCLASS(GLTFMesh, Resource);
private:
- Ref<EditorSceneImporterMesh> mesh;
+ Ref<ImporterMesh> mesh;
Vector<float> blend_weights;
protected:
static void _bind_methods();
public:
- Ref<EditorSceneImporterMesh> get_mesh();
- void set_mesh(Ref<EditorSceneImporterMesh> p_mesh);
+ Ref<ImporterMesh> get_mesh();
+ void set_mesh(Ref<ImporterMesh> p_mesh);
Vector<float> get_blend_weights();
void set_blend_weights(Vector<float> p_blend_weights);
};
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index d6614da804..61faba0dc5 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -36,6 +36,7 @@
#include "gltf_buffer_view.h"
#include "gltf_camera.h"
#include "gltf_document.h"
+#include "gltf_document_extension.h"
#include "gltf_light.h"
#include "gltf_mesh.h"
#include "gltf_node.h"
diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp
index d6020f50f0..0aceb838f7 100644
--- a/modules/gltf/register_types.cpp
+++ b/modules/gltf/register_types.cpp
@@ -38,6 +38,8 @@
#include "gltf_buffer_view.h"
#include "gltf_camera.h"
#include "gltf_document.h"
+#include "gltf_document_extension.h"
+#include "gltf_document_extension_convert_importer_mesh.h"
#include "gltf_light.h"
#include "gltf_mesh.h"
#include "gltf_node.h"
@@ -79,6 +81,8 @@ void register_gltf_types() {
GDREGISTER_CLASS(GLTFCamera);
GDREGISTER_CLASS(GLTFLight);
GDREGISTER_CLASS(GLTFState);
+ GDREGISTER_CLASS(GLTFDocumentExtensionConvertImporterMesh);
+ GDREGISTER_CLASS(GLTFDocumentExtension);
GDREGISTER_CLASS(GLTFDocument);
#endif
}
diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp
index 9aad338d15..61d73ff1e2 100644
--- a/scene/3d/camera_3d.cpp
+++ b/scene/3d/camera_3d.cpp
@@ -492,6 +492,7 @@ void Camera3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_frustum"), &Camera3D::get_frustum);
ClassDB::bind_method(D_METHOD("is_position_in_frustum", "world_point"), &Camera3D::is_position_in_frustum);
ClassDB::bind_method(D_METHOD("get_camera_rid"), &Camera3D::get_camera);
+ ClassDB::bind_method(D_METHOD("get_pyramid_shape_rid"), &Camera3D::get_pyramid_shape_rid);
ClassDB::bind_method(D_METHOD("set_cull_mask_value", "layer_number", "value"), &Camera3D::set_cull_mask_value);
ClassDB::bind_method(D_METHOD("get_cull_mask_value", "layer_number"), &Camera3D::get_cull_mask_value);
@@ -654,233 +655,46 @@ Vector3 Camera3D::get_doppler_tracked_velocity() const {
}
}
-Camera3D::Camera3D() {
- camera = RenderingServer::get_singleton()->camera_create();
- set_perspective(75.0, 0.05, 4000.0);
- RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers);
- //active=false;
- velocity_tracker.instantiate();
- set_notify_transform(true);
- set_disable_scale(true);
-}
-
-Camera3D::~Camera3D() {
- RenderingServer::get_singleton()->free(camera);
-}
+RID Camera3D::get_pyramid_shape_rid() {
+ if (pyramid_shape == RID()) {
+ pyramid_shape_points = get_near_plane_points();
+ pyramid_shape = PhysicsServer3D::get_singleton()->convex_polygon_shape_create();
+ PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, pyramid_shape_points);
-////////////////////////////////////////
+ } else { //check if points changed
+ Vector<Vector3> local_points = get_near_plane_points();
-void ClippedCamera3D::set_margin(real_t p_margin) {
- margin = p_margin;
-}
-
-real_t ClippedCamera3D::get_margin() const {
- return margin;
-}
-
-void ClippedCamera3D::set_process_callback(ClipProcessCallback p_mode) {
- if (process_callback == p_mode) {
- return;
- }
- process_callback = p_mode;
- set_process_internal(process_callback == CLIP_PROCESS_IDLE);
- set_physics_process_internal(process_callback == CLIP_PROCESS_PHYSICS);
-}
-
-ClippedCamera3D::ClipProcessCallback ClippedCamera3D::get_process_callback() const {
- return process_callback;
-}
-
-Transform3D ClippedCamera3D::get_camera_transform() const {
- Transform3D t = Camera3D::get_camera_transform();
- t.origin += -t.basis.get_axis(Vector3::AXIS_Z).normalized() * clip_offset;
- return t;
-}
-
-void ClippedCamera3D::_notification(int p_what) {
- if (p_what == NOTIFICATION_INTERNAL_PROCESS || p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
- Node3D *parent = Object::cast_to<Node3D>(get_parent());
- if (!parent) {
- return;
- }
+ bool all_equal = true;
- PhysicsDirectSpaceState3D *dspace = get_world_3d()->get_direct_space_state();
- ERR_FAIL_COND(!dspace); // most likely physics set to threads
-
- Vector3 cam_fw = -get_global_transform().basis.get_axis(Vector3::AXIS_Z).normalized();
- Vector3 cam_pos = get_global_transform().origin;
- Vector3 parent_pos = parent->get_global_transform().origin;
-
- Plane parent_plane(parent_pos, cam_fw);
-
- if (parent_plane.is_point_over(cam_pos)) {
- //cam is beyond parent plane
- return;
- }
-
- Vector3 ray_from = parent_plane.project(cam_pos);
-
- clip_offset = 0; //reset by default
-
- { //check if points changed
- Vector<Vector3> local_points = get_near_plane_points();
-
- bool all_equal = true;
-
- for (int i = 0; i < 5; i++) {
- if (points[i] != local_points[i]) {
- all_equal = false;
- break;
- }
- }
-
- if (!all_equal) {
- PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, local_points);
- points = local_points;
+ for (int i = 0; i < 5; i++) {
+ if (local_points[i] != pyramid_shape_points[i]) {
+ all_equal = false;
+ break;
}
}
- Transform3D xf = get_global_transform();
- xf.origin = ray_from;
- xf.orthonormalize();
-
- real_t closest_safe = 1.0f, closest_unsafe = 1.0f;
- if (dspace->cast_motion(pyramid_shape, xf, cam_pos - ray_from, margin, closest_safe, closest_unsafe, exclude, collision_mask, clip_to_bodies, clip_to_areas)) {
- clip_offset = cam_pos.distance_to(ray_from + (cam_pos - ray_from) * closest_safe);
+ if (!all_equal) {
+ PhysicsServer3D::get_singleton()->shape_set_data(pyramid_shape, local_points);
+ pyramid_shape_points = local_points;
}
-
- _update_camera();
- }
-
- if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
- update_gizmos();
}
-}
-
-void ClippedCamera3D::set_collision_mask(uint32_t p_mask) {
- collision_mask = p_mask;
-}
-uint32_t ClippedCamera3D::get_collision_mask() const {
- return collision_mask;
+ return pyramid_shape;
}
-void ClippedCamera3D::set_collision_mask_value(int p_layer_number, bool p_value) {
- ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
- ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
- uint32_t mask = get_collision_mask();
- if (p_value) {
- mask |= 1 << (p_layer_number - 1);
- } else {
- mask &= ~(1 << (p_layer_number - 1));
- }
- set_collision_mask(mask);
-}
-
-bool ClippedCamera3D::get_collision_mask_value(int p_layer_number) const {
- ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
- ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
- return get_collision_mask() & (1 << (p_layer_number - 1));
-}
-
-void ClippedCamera3D::add_exception_rid(const RID &p_rid) {
- exclude.insert(p_rid);
-}
-
-void ClippedCamera3D::add_exception(const Object *p_object) {
- ERR_FAIL_NULL(p_object);
- const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object);
- if (!co) {
- return;
- }
- add_exception_rid(co->get_rid());
-}
-
-void ClippedCamera3D::remove_exception_rid(const RID &p_rid) {
- exclude.erase(p_rid);
+Camera3D::Camera3D() {
+ camera = RenderingServer::get_singleton()->camera_create();
+ set_perspective(75.0, 0.05, 4000.0);
+ RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers);
+ //active=false;
+ velocity_tracker.instantiate();
+ set_notify_transform(true);
+ set_disable_scale(true);
}
-void ClippedCamera3D::remove_exception(const Object *p_object) {
- ERR_FAIL_NULL(p_object);
- const CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_object);
- if (!co) {
- return;
+Camera3D::~Camera3D() {
+ RenderingServer::get_singleton()->free(camera);
+ if (pyramid_shape.is_valid()) {
+ PhysicsServer3D::get_singleton()->free(pyramid_shape);
}
- remove_exception_rid(co->get_rid());
-}
-
-void ClippedCamera3D::clear_exceptions() {
- exclude.clear();
-}
-
-real_t ClippedCamera3D::get_clip_offset() const {
- return clip_offset;
-}
-
-void ClippedCamera3D::set_clip_to_areas(bool p_clip) {
- clip_to_areas = p_clip;
-}
-
-bool ClippedCamera3D::is_clip_to_areas_enabled() const {
- return clip_to_areas;
-}
-
-void ClippedCamera3D::set_clip_to_bodies(bool p_clip) {
- clip_to_bodies = p_clip;
-}
-
-bool ClippedCamera3D::is_clip_to_bodies_enabled() const {
- return clip_to_bodies;
-}
-
-void ClippedCamera3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ClippedCamera3D::set_margin);
- ClassDB::bind_method(D_METHOD("get_margin"), &ClippedCamera3D::get_margin);
-
- ClassDB::bind_method(D_METHOD("set_process_callback", "process_callback"), &ClippedCamera3D::set_process_callback);
- ClassDB::bind_method(D_METHOD("get_process_callback"), &ClippedCamera3D::get_process_callback);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ClippedCamera3D::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera3D::get_collision_mask);
-
- ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &ClippedCamera3D::set_collision_mask_value);
- ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &ClippedCamera3D::get_collision_mask_value);
-
- ClassDB::bind_method(D_METHOD("add_exception_rid", "rid"), &ClippedCamera3D::add_exception_rid);
- ClassDB::bind_method(D_METHOD("add_exception", "node"), &ClippedCamera3D::add_exception);
-
- ClassDB::bind_method(D_METHOD("remove_exception_rid", "rid"), &ClippedCamera3D::remove_exception_rid);
- ClassDB::bind_method(D_METHOD("remove_exception", "node"), &ClippedCamera3D::remove_exception);
-
- ClassDB::bind_method(D_METHOD("set_clip_to_areas", "enable"), &ClippedCamera3D::set_clip_to_areas);
- ClassDB::bind_method(D_METHOD("is_clip_to_areas_enabled"), &ClippedCamera3D::is_clip_to_areas_enabled);
-
- ClassDB::bind_method(D_METHOD("get_clip_offset"), &ClippedCamera3D::get_clip_offset);
-
- ClassDB::bind_method(D_METHOD("set_clip_to_bodies", "enable"), &ClippedCamera3D::set_clip_to_bodies);
- ClassDB::bind_method(D_METHOD("is_clip_to_bodies_enabled"), &ClippedCamera3D::is_clip_to_bodies_enabled);
-
- ClassDB::bind_method(D_METHOD("clear_exceptions"), &ClippedCamera3D::clear_exceptions);
-
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_margin", "get_margin");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
-
- ADD_GROUP("Clip To", "clip_to");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_areas", "is_clip_to_areas_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_to_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_clip_to_bodies", "is_clip_to_bodies_enabled");
-
- BIND_ENUM_CONSTANT(CLIP_PROCESS_PHYSICS);
- BIND_ENUM_CONSTANT(CLIP_PROCESS_IDLE);
-}
-
-ClippedCamera3D::ClippedCamera3D() {
- set_physics_process_internal(true);
- set_notify_local_transform(Engine::get_singleton()->is_editor_hint());
- points.resize(5);
- pyramid_shape = PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON);
-}
-
-ClippedCamera3D::~ClippedCamera3D() {
- PhysicsServer3D::get_singleton()->free(pyramid_shape);
}
diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h
index c1af7fa4f7..6006a2ea3f 100644
--- a/scene/3d/camera_3d.h
+++ b/scene/3d/camera_3d.h
@@ -86,6 +86,9 @@ private:
DopplerTracking doppler_tracking = DOPPLER_TRACKING_DISABLED;
Ref<VelocityTracker3D> velocity_tracker;
+ RID pyramid_shape;
+ Vector<Vector3> pyramid_shape_points;
+
protected:
void _update_camera();
virtual void _request_camera_update();
@@ -168,6 +171,8 @@ public:
Vector3 get_doppler_tracked_velocity() const;
+ RID get_pyramid_shape_rid();
+
Camera3D();
~Camera3D();
};
@@ -176,63 +181,4 @@ VARIANT_ENUM_CAST(Camera3D::Projection);
VARIANT_ENUM_CAST(Camera3D::KeepAspect);
VARIANT_ENUM_CAST(Camera3D::DopplerTracking);
-class ClippedCamera3D : public Camera3D {
- GDCLASS(ClippedCamera3D, Camera3D);
-
-public:
- enum ClipProcessCallback {
- CLIP_PROCESS_PHYSICS,
- CLIP_PROCESS_IDLE,
- };
-
-private:
- ClipProcessCallback process_callback = CLIP_PROCESS_PHYSICS;
- RID pyramid_shape;
- real_t margin = 0.0;
- real_t clip_offset = 0.0;
- uint32_t collision_mask = 1;
- bool clip_to_areas = false;
- bool clip_to_bodies = true;
-
- Set<RID> exclude;
-
- Vector<Vector3> points;
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
- virtual Transform3D get_camera_transform() const override;
-
-public:
- void set_clip_to_areas(bool p_clip);
- bool is_clip_to_areas_enabled() const;
-
- void set_clip_to_bodies(bool p_clip);
- bool is_clip_to_bodies_enabled() const;
-
- void set_margin(real_t p_margin);
- real_t get_margin() const;
-
- void set_process_callback(ClipProcessCallback p_mode);
- ClipProcessCallback get_process_callback() const;
-
- void set_collision_mask(uint32_t p_mask);
- uint32_t get_collision_mask() const;
-
- void set_collision_mask_value(int p_layer_number, bool p_value);
- bool get_collision_mask_value(int p_layer_number) const;
-
- void add_exception_rid(const RID &p_rid);
- void add_exception(const Object *p_object);
- void remove_exception_rid(const RID &p_rid);
- void remove_exception(const Object *p_object);
- void clear_exceptions();
-
- real_t get_clip_offset() const;
-
- ClippedCamera3D();
- ~ClippedCamera3D();
-};
-
-VARIANT_ENUM_CAST(ClippedCamera3D::ClipProcessCallback);
#endif
diff --git a/editor/import/scene_importer_mesh_node_3d.cpp b/scene/3d/importer_mesh_instance_3d.cpp
index 3c201cf674..748a2e5092 100644
--- a/editor/import/scene_importer_mesh_node_3d.cpp
+++ b/scene/3d/importer_mesh_instance_3d.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* scene_importer_mesh_node_3d.cpp */
+/* importer_mesh_instance_3d.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,23 +28,25 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "scene_importer_mesh_node_3d.h"
+#include "importer_mesh_instance_3d.h"
-void EditorSceneImporterMeshNode3D::set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh) {
+#include "scene/resources/importer_mesh.h"
+
+void ImporterMeshInstance3D::set_mesh(const Ref<ImporterMesh> &p_mesh) {
mesh = p_mesh;
}
-Ref<EditorSceneImporterMesh> EditorSceneImporterMeshNode3D::get_mesh() const {
+Ref<ImporterMesh> ImporterMeshInstance3D::get_mesh() const {
return mesh;
}
-void EditorSceneImporterMeshNode3D::set_skin(const Ref<Skin> &p_skin) {
+void ImporterMeshInstance3D::set_skin(const Ref<Skin> &p_skin) {
skin = p_skin;
}
-Ref<Skin> EditorSceneImporterMeshNode3D::get_skin() const {
+Ref<Skin> ImporterMeshInstance3D::get_skin() const {
return skin;
}
-void EditorSceneImporterMeshNode3D::set_surface_material(int p_idx, const Ref<Material> &p_material) {
+void ImporterMeshInstance3D::set_surface_material(int p_idx, const Ref<Material> &p_material) {
ERR_FAIL_COND(p_idx < 0);
if (p_idx >= surface_materials.size()) {
surface_materials.resize(p_idx + 1);
@@ -52,7 +54,7 @@ void EditorSceneImporterMeshNode3D::set_surface_material(int p_idx, const Ref<Ma
surface_materials.write[p_idx] = p_material;
}
-Ref<Material> EditorSceneImporterMeshNode3D::get_surface_material(int p_idx) const {
+Ref<Material> ImporterMeshInstance3D::get_surface_material(int p_idx) const {
ERR_FAIL_COND_V(p_idx < 0, Ref<Material>());
if (p_idx >= surface_materials.size()) {
return Ref<Material>();
@@ -60,24 +62,24 @@ Ref<Material> EditorSceneImporterMeshNode3D::get_surface_material(int p_idx) con
return surface_materials[p_idx];
}
-void EditorSceneImporterMeshNode3D::set_skeleton_path(const NodePath &p_path) {
+void ImporterMeshInstance3D::set_skeleton_path(const NodePath &p_path) {
skeleton_path = p_path;
}
-NodePath EditorSceneImporterMeshNode3D::get_skeleton_path() const {
+NodePath ImporterMeshInstance3D::get_skeleton_path() const {
return skeleton_path;
}
-void EditorSceneImporterMeshNode3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &EditorSceneImporterMeshNode3D::set_mesh);
- ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMeshNode3D::get_mesh);
+void ImporterMeshInstance3D::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &ImporterMeshInstance3D::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &ImporterMeshInstance3D::get_mesh);
- ClassDB::bind_method(D_METHOD("set_skin", "skin"), &EditorSceneImporterMeshNode3D::set_skin);
- ClassDB::bind_method(D_METHOD("get_skin"), &EditorSceneImporterMeshNode3D::get_skin);
+ ClassDB::bind_method(D_METHOD("set_skin", "skin"), &ImporterMeshInstance3D::set_skin);
+ ClassDB::bind_method(D_METHOD("get_skin"), &ImporterMeshInstance3D::get_skin);
- ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &EditorSceneImporterMeshNode3D::set_skeleton_path);
- ClassDB::bind_method(D_METHOD("get_skeleton_path"), &EditorSceneImporterMeshNode3D::get_skeleton_path);
+ ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &ImporterMeshInstance3D::set_skeleton_path);
+ ClassDB::bind_method(D_METHOD("get_skeleton_path"), &ImporterMeshInstance3D::get_skeleton_path);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "EditorSceneImporterMesh"), "set_mesh", "get_mesh");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "ImporterMesh"), "set_mesh", "get_mesh");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path");
}
diff --git a/editor/import/scene_importer_mesh_node_3d.h b/scene/3d/importer_mesh_instance_3d.h
index dec1717c99..0cf7dbe86b 100644
--- a/editor/import/scene_importer_mesh_node_3d.h
+++ b/scene/3d/importer_mesh_instance_3d.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* scene_importer_mesh_node_3d.h */
+/* importer_mesh_instance_3d.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,19 +28,19 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef EDITOR_SCENE_IMPORTER_MESH_NODE_3D_H
-#define EDITOR_SCENE_IMPORTER_MESH_NODE_3D_H
+#ifndef SCENE_IMPORTER_MESH_INSTANCE_3D_H
+#define SCENE_IMPORTER_MESH_INSTANCE_3D_H
-#include "editor/import/scene_importer_mesh.h"
#include "scene/3d/node_3d.h"
+#include "scene/resources/immediate_mesh.h"
#include "scene/resources/skin.h"
-class EditorSceneImporterMesh;
+class ImporterMesh;
-class EditorSceneImporterMeshNode3D : public Node3D {
- GDCLASS(EditorSceneImporterMeshNode3D, Node3D)
+class ImporterMeshInstance3D : public Node3D {
+ GDCLASS(ImporterMeshInstance3D, Node3D)
- Ref<EditorSceneImporterMesh> mesh;
+ Ref<ImporterMesh> mesh;
Ref<Skin> skin;
NodePath skeleton_path;
Vector<Ref<Material>> surface_materials;
@@ -49,8 +49,8 @@ protected:
static void _bind_methods();
public:
- void set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh);
- Ref<EditorSceneImporterMesh> get_mesh() const;
+ void set_mesh(const Ref<ImporterMesh> &p_mesh);
+ Ref<ImporterMesh> get_mesh() const;
void set_skin(const Ref<Skin> &p_skin);
Ref<Skin> get_skin() const;
diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp
index 4748a9d889..116cab19b1 100644
--- a/scene/3d/spring_arm_3d.cpp
+++ b/scene/3d/spring_arm_3d.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "spring_arm_3d.h"
+#include "scene/3d/camera_3d.h"
void SpringArm3D::_notification(int p_what) {
switch (p_what) {
@@ -133,17 +134,32 @@ void SpringArm3D::process_spring() {
Vector3 motion;
const Vector3 cast_direction(get_global_transform().basis.xform(Vector3(0, 0, 1)));
+ motion = Vector3(cast_direction * (spring_length));
+
if (shape.is_null()) {
- motion = Vector3(cast_direction * (spring_length));
- PhysicsDirectSpaceState3D::RayResult r;
- bool intersected = get_world_3d()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask);
- if (intersected) {
- real_t dist = get_global_transform().origin.distance_to(r.position);
- dist -= margin;
- motion_delta = dist / (spring_length);
+ Camera3D *camera = nullptr;
+ for (int i = get_child_count() - 1; 0 <= i; --i) {
+ camera = Object::cast_to<Camera3D>(get_child(i));
+ if (camera) {
+ break;
+ }
+ }
+
+ if (camera != nullptr) {
+ //use camera rotation, but spring arm position
+ Transform3D base_transform = camera->get_global_transform();
+ base_transform.origin = get_global_transform().origin;
+ get_world_3d()->get_direct_space_state()->cast_motion(camera->get_pyramid_shape_rid(), base_transform, motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask);
+ } else {
+ PhysicsDirectSpaceState3D::RayResult r;
+ bool intersected = get_world_3d()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask);
+ if (intersected) {
+ real_t dist = get_global_transform().origin.distance_to(r.position);
+ dist -= margin;
+ motion_delta = dist / (spring_length);
+ }
}
} else {
- motion = Vector3(cast_direction * spring_length);
get_world_3d()->get_direct_space_state()->cast_motion(shape->get_rid(), get_global_transform(), motion, 0, motion_delta, motion_delta_unsafe, excluded_objects, mask);
}
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index a8d46eac6e..2c8c4ee788 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -37,7 +37,6 @@
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
-#include "editor/editor_settings.h"
#include "scene/2d/skeleton_2d.h"
void AnimatedValuesBackup::update_skeletons() {
@@ -1493,18 +1492,12 @@ NodePath AnimationPlayer::get_root() const {
}
void AnimationPlayer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
-#ifdef TOOLS_ENABLED
- const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
-#else
- const String quote_style = "\"";
-#endif
-
String pf = p_function;
if (p_idx == 0 && (p_function == "play" || p_function == "play_backwards" || p_function == "remove_animation" || p_function == "has_animation" || p_function == "queue")) {
List<StringName> al;
get_animation_list(&al);
for (const StringName &name : al) {
- r_options->push_back(String(name).quote(quote_style));
+ r_options->push_back(String(name).quote());
}
}
Node::get_argument_options(p_function, p_idx, r_options);
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 611035fff9..54548e1941 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -35,7 +35,6 @@
#include "core/os/os.h"
#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#endif
#include "scene/main/window.h"
@@ -44,17 +43,7 @@ List<Color> ColorPicker::preset_cache;
void ColorPicker::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_THEME_CHANGED: {
- btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker")));
- btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset")));
- _update_presets();
- _update_controls();
- } break;
case NOTIFICATION_ENTER_TREE: {
- btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker")));
- btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset")));
-
- _update_controls();
_update_color();
#ifdef TOOLS_ENABLED
@@ -71,18 +60,39 @@ void ColorPicker::_notification(int p_what) {
}
}
#endif
- } break;
- case NOTIFICATION_PARENTED: {
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
+ btn_pick->set_icon(get_theme_icon(SNAME("screen_picker"), SNAME("ColorPicker")));
+ btn_add_preset->set_icon(get_theme_icon(SNAME("add_preset")));
+
+ uv_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height"))));
+ w_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("h_width")), 0));
+
+ wheel_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height"))));
+ wheel_margin->add_theme_constant_override("margin_bottom", 8 * get_theme_default_base_scale());
+
for (int i = 0; i < 4; i++) {
+ labels[i]->set_custom_minimum_size(Size2(get_theme_constant(SNAME("label_width")), 0));
set_offset((Side)i, get_offset((Side)i) + get_theme_constant(SNAME("margin")));
}
+
+ if (Engine::get_singleton()->is_editor_hint()) {
+ // Adjust for the width of the "Script" icon.
+ text_type->set_custom_minimum_size(Size2(28 * get_theme_default_base_scale(), 0));
+ }
+
+ _update_presets();
+ _update_controls();
} break;
+
case NOTIFICATION_VISIBILITY_CHANGED: {
Popup *p = Object::cast_to<Popup>(get_parent());
if (p) {
p->set_size(Size2(get_combined_minimum_size().width + get_theme_constant(SNAME("margin")) * 2, get_combined_minimum_size().height + get_theme_constant(SNAME("margin")) * 2));
}
} break;
+
case NOTIFICATION_WM_CLOSE_REQUEST: {
if (screen != nullptr && screen->is_visible()) {
screen->hide();
@@ -762,11 +772,7 @@ void ColorPicker::_slider_draw(int p_which) {
Size2 size = scroll[p_which]->get_size();
Color left_color;
Color right_color;
-#ifdef TOOLS_ENABLED
- const real_t margin = 4 * EDSCALE;
-#else
- const real_t margin = 4;
-#endif
+ const real_t margin = 4 * get_theme_default_base_scale();
if (p_which == 3) {
scroll[p_which]->draw_texture_rect(get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, margin), Size2(size.x, margin)), true);
@@ -1147,7 +1153,6 @@ ColorPicker::ColorPicker() :
uv_edit->set_mouse_filter(MOUSE_FILTER_PASS);
uv_edit->set_h_size_flags(SIZE_EXPAND_FILL);
uv_edit->set_v_size_flags(SIZE_EXPAND_FILL);
- uv_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height"))));
uv_edit->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, uv_edit));
HBoxContainer *hb_smpl = memnew(HBoxContainer);
@@ -1219,9 +1224,6 @@ ColorPicker::ColorPicker() :
text_type->set_text("#");
text_type->set_tooltip(TTR("Switch between hexadecimal and code values."));
if (Engine::get_singleton()->is_editor_hint()) {
-#ifdef TOOLS_ENABLED
- text_type->set_custom_minimum_size(Size2(28 * EDSCALE, 0)); // Adjust for the width of the "Script" icon.
-#endif
text_type->connect("pressed", callable_mp(this, &ColorPicker::_text_type_toggled));
} else {
text_type->set_flat(true);
@@ -1236,7 +1238,6 @@ ColorPicker::ColorPicker() :
wheel_edit->set_h_size_flags(SIZE_EXPAND_FILL);
wheel_edit->set_v_size_flags(SIZE_EXPAND_FILL);
- wheel_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("sv_width")), get_theme_constant(SNAME("sv_height"))));
hb_edit->add_child(wheel_edit);
wheel_mat.instantiate();
@@ -1244,12 +1245,7 @@ ColorPicker::ColorPicker() :
circle_mat.instantiate();
circle_mat->set_shader(circle_shader);
- MarginContainer *wheel_margin(memnew(MarginContainer));
-#ifdef TOOLS_ENABLED
- wheel_margin->add_theme_constant_override("margin_bottom", 8 * EDSCALE);
-#else
wheel_margin->add_theme_constant_override("margin_bottom", 8);
-#endif
wheel_edit->add_child(wheel_margin);
wheel_margin->add_child(wheel);
@@ -1261,7 +1257,6 @@ ColorPicker::ColorPicker() :
wheel_uv->connect("draw", callable_mp(this, &ColorPicker::_hsv_draw), make_binds(0, wheel_uv));
hb_edit->add_child(w_edit);
- w_edit->set_custom_minimum_size(Size2(get_theme_constant(SNAME("h_width")), 0));
w_edit->set_h_size_flags(SIZE_FILL);
w_edit->set_v_size_flags(SIZE_EXPAND_FILL);
w_edit->connect("gui_input", callable_mp(this, &ColorPicker::_w_input));
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 67ca007eb5..ad4f5ad5b1 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -81,6 +81,7 @@ private:
Control *uv_edit = memnew(Control);
Control *w_edit = memnew(Control);
AspectRatioContainer *wheel_edit = memnew(AspectRatioContainer);
+ MarginContainer *wheel_margin = memnew(MarginContainer);
Ref<ShaderMaterial> wheel_mat;
Ref<ShaderMaterial> circle_mat;
Control *wheel = memnew(Control);
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 1b8b5e17ed..38da40a402 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -38,7 +38,6 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
-
#include "scene/gui/label.h"
#include "scene/gui/panel.h"
#include "scene/main/canvas_layer.h"
@@ -48,7 +47,6 @@
#include "servers/text_server.h"
#ifdef TOOLS_ENABLED
-#include "editor/editor_settings.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#endif
@@ -833,11 +831,12 @@ T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner
ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, T(), "At least one theme type must be specified.");
// First, look through each control or window node in the branch, until no valid parent can be found.
- // For each control iterate through its inheritance chain and see if p_name exists in any of them.
+ // Only nodes with a theme resource attached are considered.
Control *theme_owner = p_theme_owner;
Window *theme_owner_window = p_theme_owner_window;
while (theme_owner || theme_owner_window) {
+ // For each theme resource check the theme types provided and see if p_name exists with any of them.
for (const StringName &E : p_theme_types) {
if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
return theme_owner->data.theme->get_theme_item(p_data_type, p_name, E);
@@ -888,11 +887,12 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow
ERR_FAIL_COND_V_MSG(p_theme_types.size() == 0, false, "At least one theme type must be specified.");
// First, look through each control or window node in the branch, until no valid parent can be found.
- // For each control iterate through its inheritance chain and see if p_name exists in any of them.
+ // Only nodes with a theme resource attached are considered.
Control *theme_owner = p_theme_owner;
Window *theme_owner_window = p_theme_owner_window;
while (theme_owner || theme_owner_window) {
+ // For each theme resource check the theme types provided and see if p_name exists with any of them.
for (const StringName &E : p_theme_types) {
if (theme_owner && theme_owner->data.theme->has_theme_item(p_data_type, p_name, E)) {
return true;
@@ -1130,6 +1130,150 @@ bool Control::has_theme_constant(const StringName &p_name, const StringName &p_t
return has_theme_item_in_types(data.theme_owner, data.theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
+float Control::fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window) {
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ // For each theme resource see if their assigned theme has the default value defined and valid.
+ Control *theme_owner = p_theme_owner;
+ Window *theme_owner_window = p_theme_owner_window;
+
+ while (theme_owner || theme_owner_window) {
+ if (theme_owner && theme_owner->data.theme->has_default_theme_base_scale()) {
+ return theme_owner->data.theme->get_default_theme_base_scale();
+ }
+
+ if (theme_owner_window && theme_owner_window->theme->has_default_theme_base_scale()) {
+ return theme_owner_window->theme->get_default_theme_base_scale();
+ }
+
+ Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
+ Control *parent_c = Object::cast_to<Control>(parent);
+ if (parent_c) {
+ theme_owner = parent_c->data.theme_owner;
+ theme_owner_window = parent_c->data.theme_owner_window;
+ } else {
+ Window *parent_w = Object::cast_to<Window>(parent);
+ if (parent_w) {
+ theme_owner = parent_w->theme_owner;
+ theme_owner_window = parent_w->theme_owner_window;
+ } else {
+ theme_owner = nullptr;
+ theme_owner_window = nullptr;
+ }
+ }
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ if (Theme::get_project_default().is_valid()) {
+ if (Theme::get_project_default()->has_default_theme_base_scale()) {
+ return Theme::get_project_default()->get_default_theme_base_scale();
+ }
+ }
+
+ // Lastly, fall back on the default Theme.
+ return Theme::get_default()->get_default_theme_base_scale();
+}
+
+float Control::get_theme_default_base_scale() const {
+ return fetch_theme_default_base_scale(data.theme_owner, data.theme_owner_window);
+}
+
+Ref<Font> Control::fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window) {
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ // For each theme resource see if their assigned theme has the default value defined and valid.
+ Control *theme_owner = p_theme_owner;
+ Window *theme_owner_window = p_theme_owner_window;
+
+ while (theme_owner || theme_owner_window) {
+ if (theme_owner && theme_owner->data.theme->has_default_theme_font()) {
+ return theme_owner->data.theme->get_default_theme_font();
+ }
+
+ if (theme_owner_window && theme_owner_window->theme->has_default_theme_font()) {
+ return theme_owner_window->theme->get_default_theme_font();
+ }
+
+ Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
+ Control *parent_c = Object::cast_to<Control>(parent);
+ if (parent_c) {
+ theme_owner = parent_c->data.theme_owner;
+ theme_owner_window = parent_c->data.theme_owner_window;
+ } else {
+ Window *parent_w = Object::cast_to<Window>(parent);
+ if (parent_w) {
+ theme_owner = parent_w->theme_owner;
+ theme_owner_window = parent_w->theme_owner_window;
+ } else {
+ theme_owner = nullptr;
+ theme_owner_window = nullptr;
+ }
+ }
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ if (Theme::get_project_default().is_valid()) {
+ if (Theme::get_project_default()->has_default_theme_font()) {
+ return Theme::get_project_default()->get_default_theme_font();
+ }
+ }
+
+ // Lastly, fall back on the default Theme.
+ return Theme::get_default()->get_default_theme_font();
+}
+
+Ref<Font> Control::get_theme_default_font() const {
+ return fetch_theme_default_font(data.theme_owner, data.theme_owner_window);
+}
+
+int Control::fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window) {
+ // First, look through each control or window node in the branch, until no valid parent can be found.
+ // Only nodes with a theme resource attached are considered.
+ // For each theme resource see if their assigned theme has the default value defined and valid.
+ Control *theme_owner = p_theme_owner;
+ Window *theme_owner_window = p_theme_owner_window;
+
+ while (theme_owner || theme_owner_window) {
+ if (theme_owner && theme_owner->data.theme->has_default_theme_font_size()) {
+ return theme_owner->data.theme->get_default_theme_font_size();
+ }
+
+ if (theme_owner_window && theme_owner_window->theme->has_default_theme_font_size()) {
+ return theme_owner_window->theme->get_default_theme_font_size();
+ }
+
+ Node *parent = theme_owner ? theme_owner->get_parent() : theme_owner_window->get_parent();
+ Control *parent_c = Object::cast_to<Control>(parent);
+ if (parent_c) {
+ theme_owner = parent_c->data.theme_owner;
+ theme_owner_window = parent_c->data.theme_owner_window;
+ } else {
+ Window *parent_w = Object::cast_to<Window>(parent);
+ if (parent_w) {
+ theme_owner = parent_w->theme_owner;
+ theme_owner_window = parent_w->theme_owner_window;
+ } else {
+ theme_owner = nullptr;
+ theme_owner_window = nullptr;
+ }
+ }
+ }
+
+ // Secondly, check the project-defined Theme resource.
+ if (Theme::get_project_default().is_valid()) {
+ if (Theme::get_project_default()->has_default_theme_font_size()) {
+ return Theme::get_project_default()->get_default_theme_font_size();
+ }
+ }
+
+ // Lastly, fall back on the default Theme.
+ return Theme::get_default()->get_default_theme_font_size();
+}
+
+int Control::get_theme_default_font_size() const {
+ return fetch_theme_default_font_size(data.theme_owner, data.theme_owner_window);
+}
+
Rect2 Control::get_parent_anchorable_rect() const {
if (!is_inside_tree()) {
return Rect2();
@@ -2616,12 +2760,6 @@ bool Control::is_visibility_clip_disabled() const {
}
void Control::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
-#ifdef TOOLS_ENABLED
- const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
-#else
- const String quote_style = "\"";
-#endif
-
Node::get_argument_options(p_function, p_idx, r_options);
if (p_idx == 0) {
@@ -2641,7 +2779,7 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
sn.sort_custom<StringName::AlphCompare>();
for (const StringName &name : sn) {
- r_options->push_back(String(name).quote(quote_style));
+ r_options->push_back(String(name).quote());
}
}
}
@@ -2789,6 +2927,10 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Control::has_theme_color, DEFVAL(""));
ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Control::has_theme_constant, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_default_base_scale"), &Control::get_theme_default_base_scale);
+ ClassDB::bind_method(D_METHOD("get_theme_default_font"), &Control::get_theme_default_font);
+ ClassDB::bind_method(D_METHOD("get_theme_default_font_size"), &Control::get_theme_default_font_size);
+
ClassDB::bind_method(D_METHOD("get_parent_control"), &Control::get_parent_control);
ClassDB::bind_method(D_METHOD("set_h_grow_direction", "direction"), &Control::set_h_grow_direction);
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 87ff3918cb..bdc06319ea 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -509,6 +509,14 @@ public:
bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ static float fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_theme_owner_window);
+ static Ref<Font> fetch_theme_default_font(Control *p_theme_owner, Window *p_theme_owner_window);
+ static int fetch_theme_default_font_size(Control *p_theme_owner, Window *p_theme_owner_window);
+
+ float get_theme_default_base_scale() const;
+ Ref<Font> get_theme_default_font() const;
+ int get_theme_default_font_size() const;
+
/* TOOLTIP */
void set_tooltip(const String &p_tooltip);
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 5d98aaa698..71d2778cc3 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -37,7 +37,6 @@
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
-#include "editor/editor_scale.h"
#include "scene/main/window.h" // Only used to check for more modals when dimming the editor.
#endif
@@ -363,8 +362,7 @@ Button *ConfirmationDialog::get_cancel_button() {
ConfirmationDialog::ConfirmationDialog() {
set_title(TTRC("Please Confirm..."));
-#ifdef TOOLS_ENABLED
- set_min_size(Size2(200, 70) * EDSCALE);
-#endif
+ set_min_size(Size2(200, 70));
+
cancel = add_cancel_button();
}
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index 56b8a936e1..5d024d3be7 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -32,15 +32,6 @@
#include "core/os/keyboard.h"
-#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
-#define SPACING (3 * EDSCALE)
-#define POINT_WIDTH (8 * EDSCALE)
-#else
-#define SPACING 3
-#define POINT_WIDTH 8
-#endif
-
GradientEdit::GradientEdit() {
set_focus_mode(FOCUS_ALL);
@@ -53,12 +44,12 @@ GradientEdit::GradientEdit() {
int GradientEdit::_get_point_from_pos(int x) {
int result = -1;
- int total_w = get_size().width - get_size().height - SPACING;
+ int total_w = get_size().width - get_size().height - draw_spacing;
float min_distance = 1e20;
for (int i = 0; i < points.size(); i++) {
//Check if we clicked at point
float distance = ABS(x - points[i].offset * total_w);
- float min = (POINT_WIDTH / 2 * 1.7); //make it easier to grab
+ float min = (draw_point_width / 2 * 1.7); //make it easier to grab
if (distance <= min && distance < min_distance) {
result = i;
min_distance = distance;
@@ -129,7 +120,7 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
grabbed = _get_point_from_pos(x);
if (grabbed != -1) {
- int total_w = get_size().width - get_size().height - SPACING;
+ int total_w = get_size().width - get_size().height - draw_spacing;
Gradient::Point newPoint = points[grabbed];
newPoint.offset = CLAMP(x / float(total_w), 0, 1);
@@ -151,10 +142,10 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) {
update();
int x = mb->get_position().x;
- int total_w = get_size().width - get_size().height - SPACING;
+ int total_w = get_size().width - get_size().height - draw_spacing;
//Check if color selector was clicked.
- if (x > total_w + SPACING) {
+ if (x > total_w + draw_spacing) {
_show_color_picker();
return;
}
@@ -225,7 +216,7 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid() && grabbing) {
- int total_w = get_size().width - get_size().height - SPACING;
+ int total_w = get_size().width - get_size().height - draw_spacing;
int x = mm->get_position().x;
@@ -297,6 +288,12 @@ void GradientEdit::_notification(int p_what) {
picker->connect("color_changed", callable_mp(this, &GradientEdit::_color_changed));
}
}
+
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
+ draw_spacing = BASE_SPACING * get_theme_default_base_scale();
+ draw_point_width = BASE_POINT_WIDTH * get_theme_default_base_scale();
+ }
+
if (p_what == NOTIFICATION_DRAW) {
int w = get_size().x;
int h = get_size().y;
@@ -305,7 +302,7 @@ void GradientEdit::_notification(int p_what) {
return; //Safety check. We have division by 'h'. And in any case there is nothing to draw with such size
}
- int total_w = get_size().width - get_size().height - SPACING;
+ int total_w = get_size().width - get_size().height - draw_spacing;
//Draw checker pattern for ramp
draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(0, 0, total_w, h), true);
@@ -358,7 +355,7 @@ void GradientEdit::_notification(int p_what) {
col.a = 0.9;
draw_line(Vector2(points[i].offset * total_w, 0), Vector2(points[i].offset * total_w, h / 2), col);
- Rect2 rect = Rect2(points[i].offset * total_w - POINT_WIDTH / 2, h / 2, POINT_WIDTH, h / 2);
+ Rect2 rect = Rect2(points[i].offset * total_w - draw_point_width / 2, h / 2, draw_point_width, h / 2);
draw_rect(rect, points[i].color, true);
draw_rect(rect, col, false);
if (grabbed == i) {
@@ -375,15 +372,15 @@ void GradientEdit::_notification(int p_what) {
}
//Draw "button" for color selector
- draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(total_w + SPACING, 0, h, h), true);
+ draw_texture_rect(get_theme_icon(SNAME("GuiMiniCheckerboard"), SNAME("EditorIcons")), Rect2(total_w + draw_spacing, 0, h, h), true);
if (grabbed != -1) {
//Draw with selection color
- draw_rect(Rect2(total_w + SPACING, 0, h, h), points[grabbed].color);
+ draw_rect(Rect2(total_w + draw_spacing, 0, h, h), points[grabbed].color);
} else {
//if no color selected draw grey color with 'X' on top.
- draw_rect(Rect2(total_w + SPACING, 0, h, h), Color(0.5, 0.5, 0.5, 1));
- draw_line(Vector2(total_w + SPACING, 0), Vector2(total_w + SPACING + h, h), Color(1, 1, 1, 0.6));
- draw_line(Vector2(total_w + SPACING, h), Vector2(total_w + SPACING + h, 0), Color(1, 1, 1, 0.6));
+ draw_rect(Rect2(total_w + draw_spacing, 0, h, h), Color(0.5, 0.5, 0.5, 1));
+ draw_line(Vector2(total_w + draw_spacing, 0), Vector2(total_w + draw_spacing + h, h), Color(1, 1, 1, 0.6));
+ draw_line(Vector2(total_w + draw_spacing, h), Vector2(total_w + draw_spacing + h, 0), Color(1, 1, 1, 0.6));
}
//Draw borders around color ramp if in focus
diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h
index a173631963..f3a39daaf6 100644
--- a/scene/gui/gradient_edit.h
+++ b/scene/gui/gradient_edit.h
@@ -46,6 +46,13 @@ class GradientEdit : public Control {
int grabbed = -1;
Vector<Gradient::Point> points;
+ // Make sure to use the scaled value below.
+ const int BASE_SPACING = 3;
+ const int BASE_POINT_WIDTH = 8;
+
+ int draw_spacing = BASE_SPACING;
+ int draw_point_width = BASE_POINT_WIDTH;
+
void _draw_checker(int x, int y, int w, int h);
void _color_changed(const Color &p_color);
int _get_point_from_pos(int x);
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index d9c08ec272..35e31be9af 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -36,10 +36,6 @@
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
-#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
-#endif
-
constexpr int MINIMAP_OFFSET = 12;
constexpr int MINIMAP_PADDING = 5;
@@ -436,6 +432,8 @@ void GraphEdit::_notification(int p_what) {
snap_button->set_icon(get_theme_icon(SNAME("snap")));
minimap_button->set_icon(get_theme_icon(SNAME("minimap")));
layout_button->set_icon(get_theme_icon(SNAME("layout")));
+
+ zoom_label->set_custom_minimum_size(Size2(48, 0) * get_theme_default_base_scale());
}
if (p_what == NOTIFICATION_READY) {
Size2 hmin = h_scroll->get_combined_minimum_size();
@@ -816,11 +814,7 @@ void GraphEdit::_draw_connection_line(CanvasItem *p_where, const Vector2 &p_from
scaled_points.push_back(points[i] * p_zoom);
}
-#ifdef TOOLS_ENABLED
- p_where->draw_polyline_colors(scaled_points, colors, Math::floor(p_width * EDSCALE), lines_antialiased);
-#else
- p_where->draw_polyline_colors(scaled_points, colors, p_width, lines_antialiased);
-#endif
+ p_where->draw_polyline_colors(scaled_points, colors, Math::floor(p_width * get_theme_default_base_scale()), lines_antialiased);
}
void GraphEdit::_connections_layer_draw() {
@@ -2272,11 +2266,7 @@ GraphEdit::GraphEdit() {
zoom_label->set_visible(false);
zoom_label->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
zoom_label->set_align(Label::ALIGN_CENTER);
-#ifdef TOOLS_ENABLED
- zoom_label->set_custom_minimum_size(Size2(48, 0) * EDSCALE);
-#else
zoom_label->set_custom_minimum_size(Size2(48, 0));
-#endif
_update_zoom_label();
zoom_minus = memnew(Button);
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 2c1092d8f9..653885aa08 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -40,7 +40,6 @@
#include "servers/display_server.h"
#include "servers/text_server.h"
#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#endif
#include "scene/main/window.h"
@@ -713,11 +712,7 @@ void LineEdit::_notification(int p_what) {
ofs_max -= r_icon->get_width();
}
-#ifdef TOOLS_ENABLED
- int caret_width = Math::round(EDSCALE);
-#else
- int caret_width = 1;
-#endif
+ int caret_width = Math::round(1 * get_theme_default_base_scale());
// Draw selections rects.
Vector2 ofs = Point2(x_ofs + scroll_offset, y_ofs);
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index bc25177275..4588966d88 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -41,10 +41,6 @@
#include "modules/regex/regex.h"
#endif
-#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
-#endif
-
RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) const {
if (p_free) {
if (p_item->subitems.size()) {
@@ -995,19 +991,13 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
Color uc = font_color;
uc.a *= 0.5;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid);
-#ifdef TOOLS_ENABLED
- underline_width *= EDSCALE;
-#endif
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width);
} else if (_find_strikethrough(it)) {
Color uc = font_color;
uc.a *= 0.5;
float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
- float underline_width = TS->shaped_text_get_underline_thickness(rid);
-#ifdef TOOLS_ENABLED
- underline_width *= EDSCALE;
-#endif
+ float underline_width = TS->shaped_text_get_underline_thickness(rid) * get_theme_default_base_scale();
draw_line(p_ofs + Vector2(off.x, off.y + y_off), p_ofs + Vector2(off.x + glyphs[i].advance * glyphs[i].repeat, off.y + y_off), uc, underline_width);
}
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index ba8dba847c..f305bf7013 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -156,6 +156,7 @@ void Tabs::gui_input(const Ref<InputEvent> &p_event) {
if (scrolling_enabled && buttons_visible) {
if (missing_right) {
offset++;
+ _ensure_no_over_offset(); // Avoid overreaching when scrolling fast.
update();
}
}
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index e2ddc761b8..57bcbb7c2d 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -42,10 +42,6 @@
#include "scene/main/window.h"
-#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
-#endif
-
static bool _is_text_char(char32_t c) {
return !is_symbol(c);
}
@@ -1173,12 +1169,8 @@ void TextEdit::_notification(int p_what) {
}
}
- // Carets
-#ifdef TOOLS_ENABLED
- int caret_width = Math::round(EDSCALE);
-#else
- int caret_width = 1;
-#endif
+ // Carets.
+ int caret_width = Math::round(1 * get_theme_default_base_scale());
if (!clipped && caret.line == line && line_wrap_index == caret_wrap_index) {
caret.draw_pos.y = ofs_y + ldata->get_line_descent(line_wrap_index);
@@ -5080,10 +5072,12 @@ void TextEdit::_cut_internal() {
}
int cl = get_caret_line();
+ int cc = get_caret_column();
+ int indent_level = get_indent_level(cl);
+ double hscroll = get_h_scroll();
String clipboard = text[cl];
DisplayServer::get_singleton()->clipboard_set(clipboard);
- set_caret_line(cl);
set_caret_column(0);
if (cl == 0 && get_line_count() > 1) {
@@ -5094,6 +5088,17 @@ void TextEdit::_cut_internal() {
set_caret_line(get_caret_line() + 1);
}
+ // Correct the visualy perceived caret column taking care of identation level of the lines.
+ int diff_indent = indent_level - get_indent_level(get_caret_line());
+ cc += diff_indent;
+ if (diff_indent != 0) {
+ cc += diff_indent > 0 ? -1 : 1;
+ }
+
+ // Restore horizontal scroll and caret column modified by the backspace() call.
+ set_h_scroll(hscroll);
+ set_caret_column(cc);
+
cut_copy_line = clipboard;
}
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 7d7596635c..3f041bf65a 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -41,10 +41,6 @@
#include "box_container.h"
-#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
-#endif
-
#include <limits.h>
Size2 TreeItem::Cell::get_icon_size() const {
@@ -1377,6 +1373,8 @@ void Tree::update_cache() {
cache.title_button_hover = get_theme_stylebox(SNAME("title_button_hover"));
cache.title_button_color = get_theme_color(SNAME("title_button_color"));
+ cache.base_scale = get_theme_default_base_scale();
+
v_scroll->set_custom_step(cache.font->get_height(cache.font_size));
}
@@ -2046,15 +2044,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
root_pos -= Point2i(cache.arrow->get_width(), 0);
}
- float line_width = cache.relationship_line_width;
- float parent_line_width = cache.parent_hl_line_width;
- float children_line_width = cache.children_hl_line_width;
-
-#ifdef TOOLS_ENABLED
- line_width *= Math::round(EDSCALE);
- parent_line_width *= Math::round(EDSCALE);
- children_line_width *= Math::round(EDSCALE);
-#endif
+ float line_width = cache.relationship_line_width * Math::round(cache.base_scale);
+ float parent_line_width = cache.parent_hl_line_width * Math::round(cache.base_scale);
+ float children_line_width = cache.children_hl_line_width * Math::round(cache.base_scale);
Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs;
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index c4a6b6b058..6ca9458e9b 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -516,6 +516,8 @@ private:
Color custom_button_font_highlight;
Color font_outline_color;
+ float base_scale = 1.0;
+
int hseparation = 0;
int vseparation = 0;
int item_margin = 0;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index b1ba9de85c..0876c30dd1 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -41,10 +41,6 @@
#include "scene/scene_string_names.h"
#include "viewport.h"
-#ifdef TOOLS_ENABLED
-#include "editor/editor_settings.h"
-#endif
-
#include <stdint.h>
VARIANT_ENUM_CAST(Node::ProcessMode);
@@ -2536,17 +2532,11 @@ NodePath Node::get_import_path() const {
}
static void _add_nodes_to_options(const Node *p_base, const Node *p_node, List<String> *r_options) {
-#ifdef TOOLS_ENABLED
- const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
-#else
- const String quote_style = "\"";
-#endif
-
if (p_node != p_base && !p_node->get_owner()) {
return;
}
String n = p_base->get_path_to(p_node);
- r_options->push_back(n.quote(quote_style));
+ r_options->push_back(n.quote());
for (int i = 0; i < p_node->get_child_count(); i++) {
_add_nodes_to_options(p_base, p_node->get_child(i), r_options);
}
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index ca5a3915d0..a0f62c853f 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -1266,6 +1266,18 @@ bool Window::has_theme_constant(const StringName &p_name, const StringName &p_th
return Control::has_theme_item_in_types(theme_owner, theme_owner_window, Theme::DATA_TYPE_CONSTANT, p_name, theme_types);
}
+float Window::get_theme_default_base_scale() const {
+ return Control::fetch_theme_default_base_scale(theme_owner, theme_owner_window);
+}
+
+Ref<Font> Window::get_theme_default_font() const {
+ return Control::fetch_theme_default_font(theme_owner, theme_owner_window);
+}
+
+int Window::get_theme_default_font_size() const {
+ return Control::fetch_theme_default_font_size(theme_owner, theme_owner_window);
+}
+
Rect2i Window::get_parent_rect() const {
ERR_FAIL_COND_V(!is_inside_tree(), Rect2i());
if (is_embedded()) {
@@ -1480,6 +1492,10 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_theme_color", "name", "theme_type"), &Window::has_theme_color, DEFVAL(""));
ClassDB::bind_method(D_METHOD("has_theme_constant", "name", "theme_type"), &Window::has_theme_constant, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("get_theme_default_base_scale"), &Window::get_theme_default_base_scale);
+ ClassDB::bind_method(D_METHOD("get_theme_default_font"), &Window::get_theme_default_font);
+ ClassDB::bind_method(D_METHOD("get_theme_default_font_size"), &Window::get_theme_default_font_size);
+
ClassDB::bind_method(D_METHOD("set_layout_direction", "direction"), &Window::set_layout_direction);
ClassDB::bind_method(D_METHOD("get_layout_direction"), &Window::get_layout_direction);
ClassDB::bind_method(D_METHOD("is_layout_rtl"), &Window::is_layout_rtl);
diff --git a/scene/main/window.h b/scene/main/window.h
index 4f31d9cd1f..def6eab7b8 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -280,6 +280,10 @@ public:
bool has_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
bool has_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ float get_theme_default_base_scale() const;
+ Ref<Font> get_theme_default_font() const;
+ int get_theme_default_font_size() const;
+
Rect2i get_parent_rect() const;
virtual DisplayServer::WindowID get_window_id() const override;
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 56dd9c6b06..bf8f7291be 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -215,6 +215,7 @@
#include "scene/3d/decal.h"
#include "scene/3d/gpu_particles_3d.h"
#include "scene/3d/gpu_particles_collision_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/joint_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/lightmap_gi.h"
@@ -244,6 +245,7 @@
#include "scene/3d/world_environment.h"
#include "scene/3d/xr_nodes.h"
#include "scene/resources/environment.h"
+#include "scene/resources/importer_mesh.h"
#include "scene/resources/mesh_library.h"
#endif
@@ -441,10 +443,11 @@ void register_scene_types() {
GDREGISTER_CLASS(Skin);
GDREGISTER_VIRTUAL_CLASS(SkinReference);
GDREGISTER_CLASS(Skeleton3D);
+ GDREGISTER_CLASS(ImporterMesh);
+ GDREGISTER_CLASS(ImporterMeshInstance3D);
GDREGISTER_VIRTUAL_CLASS(VisualInstance3D);
GDREGISTER_VIRTUAL_CLASS(GeometryInstance3D);
GDREGISTER_CLASS(Camera3D);
- GDREGISTER_CLASS(ClippedCamera3D);
GDREGISTER_CLASS(AudioListener3D);
GDREGISTER_CLASS(XRCamera3D);
GDREGISTER_CLASS(XRController3D);
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 94cf826477..54bb7a82cf 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -1036,9 +1036,16 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) {
}
Ref<Font> large_font = default_font;
- fill_default_theme(t, default_font, large_font, default_icon, default_style, p_hidpi ? 2.0 : 1.0);
+
+ float default_scale = 1.0;
+ if (p_hidpi) {
+ default_scale = 2.0;
+ }
+
+ fill_default_theme(t, default_font, large_font, default_icon, default_style, default_scale);
Theme::set_default(t);
+ Theme::set_default_base_scale(default_scale);
Theme::set_default_icon(default_icon);
Theme::set_default_style(default_style);
Theme::set_default_font(default_font);
diff --git a/editor/import/scene_importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index 63d1525d4f..af69b799cc 100644
--- a/editor/import/scene_importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* scene_importer_mesh.cpp */
+/* importer_mesh.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "scene_importer_mesh.h"
+#include "importer_mesh.h"
#include "core/math/random_pcg.h"
#include "core/math/static_raycaster.h"
@@ -36,7 +36,7 @@
#include <cstdint>
-void EditorSceneImporterMesh::Surface::split_normals(const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals) {
+void ImporterMesh::Surface::split_normals(const LocalVector<int> &p_indices, const LocalVector<Vector3> &p_normals) {
ERR_FAIL_COND(arrays.size() != RS::ARRAY_MAX);
const PackedVector3Array &vertices = arrays[RS::ARRAY_VERTEX];
@@ -124,29 +124,29 @@ void EditorSceneImporterMesh::Surface::split_normals(const LocalVector<int> &p_i
}
}
-void EditorSceneImporterMesh::add_blend_shape(const String &p_name) {
+void ImporterMesh::add_blend_shape(const String &p_name) {
ERR_FAIL_COND(surfaces.size() > 0);
blend_shapes.push_back(p_name);
}
-int EditorSceneImporterMesh::get_blend_shape_count() const {
+int ImporterMesh::get_blend_shape_count() const {
return blend_shapes.size();
}
-String EditorSceneImporterMesh::get_blend_shape_name(int p_blend_shape) const {
+String ImporterMesh::get_blend_shape_name(int p_blend_shape) const {
ERR_FAIL_INDEX_V(p_blend_shape, blend_shapes.size(), String());
return blend_shapes[p_blend_shape];
}
-void EditorSceneImporterMesh::set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode) {
+void ImporterMesh::set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode) {
blend_shape_mode = p_blend_shape_mode;
}
-Mesh::BlendShapeMode EditorSceneImporterMesh::get_blend_shape_mode() const {
+Mesh::BlendShapeMode ImporterMesh::get_blend_shape_mode() const {
return blend_shape_mode;
}
-void EditorSceneImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name, const uint32_t p_flags) {
+void ImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name, const uint32_t p_flags) {
ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size());
ERR_FAIL_COND(p_arrays.size() != Mesh::ARRAY_MAX);
Surface s;
@@ -186,67 +186,67 @@ void EditorSceneImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const
mesh.unref();
}
-int EditorSceneImporterMesh::get_surface_count() const {
+int ImporterMesh::get_surface_count() const {
return surfaces.size();
}
-Mesh::PrimitiveType EditorSceneImporterMesh::get_surface_primitive_type(int p_surface) {
+Mesh::PrimitiveType ImporterMesh::get_surface_primitive_type(int p_surface) {
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Mesh::PRIMITIVE_MAX);
return surfaces[p_surface].primitive;
}
-Array EditorSceneImporterMesh::get_surface_arrays(int p_surface) const {
+Array ImporterMesh::get_surface_arrays(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array());
return surfaces[p_surface].arrays;
}
-String EditorSceneImporterMesh::get_surface_name(int p_surface) const {
+String ImporterMesh::get_surface_name(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), String());
return surfaces[p_surface].name;
}
-void EditorSceneImporterMesh::set_surface_name(int p_surface, const String &p_name) {
+void ImporterMesh::set_surface_name(int p_surface, const String &p_name) {
ERR_FAIL_INDEX(p_surface, surfaces.size());
surfaces.write[p_surface].name = p_name;
mesh.unref();
}
-Array EditorSceneImporterMesh::get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const {
+Array ImporterMesh::get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const {
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array());
ERR_FAIL_INDEX_V(p_blend_shape, surfaces[p_surface].blend_shape_data.size(), Array());
return surfaces[p_surface].blend_shape_data[p_blend_shape].arrays;
}
-int EditorSceneImporterMesh::get_surface_lod_count(int p_surface) const {
+int ImporterMesh::get_surface_lod_count(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0);
return surfaces[p_surface].lods.size();
}
-Vector<int> EditorSceneImporterMesh::get_surface_lod_indices(int p_surface, int p_lod) const {
+Vector<int> ImporterMesh::get_surface_lod_indices(int p_surface, int p_lod) const {
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Vector<int>());
ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), Vector<int>());
return surfaces[p_surface].lods[p_lod].indices;
}
-float EditorSceneImporterMesh::get_surface_lod_size(int p_surface, int p_lod) const {
+float ImporterMesh::get_surface_lod_size(int p_surface, int p_lod) const {
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0);
ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), 0);
return surfaces[p_surface].lods[p_lod].distance;
}
-uint32_t EditorSceneImporterMesh::get_surface_format(int p_surface) const {
+uint32_t ImporterMesh::get_surface_format(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0);
return surfaces[p_surface].flags;
}
-Ref<Material> EditorSceneImporterMesh::get_surface_material(int p_surface) const {
+Ref<Material> ImporterMesh::get_surface_material(int p_surface) const {
ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Ref<Material>());
return surfaces[p_surface].material;
}
-void EditorSceneImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_material) {
+void ImporterMesh::set_surface_material(int p_surface, const Ref<Material> &p_material) {
ERR_FAIL_INDEX(p_surface, surfaces.size());
surfaces.write[p_surface].material = p_material;
mesh.unref();
}
-void EditorSceneImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle) {
+void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_split_angle) {
if (!SurfaceTool::simplify_scale_func) {
return;
}
@@ -608,11 +608,11 @@ void EditorSceneImporterMesh::generate_lods(float p_normal_merge_angle, float p_
}
}
-bool EditorSceneImporterMesh::has_mesh() const {
+bool ImporterMesh::has_mesh() const {
return mesh.is_valid();
}
-Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh(const Ref<ArrayMesh> &p_base) {
+Ref<ArrayMesh> ImporterMesh::get_mesh(const Ref<ArrayMesh> &p_base) {
ERR_FAIL_COND_V(surfaces.size() == 0, Ref<ArrayMesh>());
if (mesh.is_null()) {
@@ -664,13 +664,13 @@ Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh(const Ref<ArrayMesh> &p_base) {
return mesh;
}
-void EditorSceneImporterMesh::clear() {
+void ImporterMesh::clear() {
surfaces.clear();
blend_shapes.clear();
mesh.unref();
}
-void EditorSceneImporterMesh::create_shadow_mesh() {
+void ImporterMesh::create_shadow_mesh() {
if (shadow_mesh.is_valid()) {
shadow_mesh.unref();
}
@@ -763,11 +763,11 @@ void EditorSceneImporterMesh::create_shadow_mesh() {
}
}
-Ref<EditorSceneImporterMesh> EditorSceneImporterMesh::get_shadow_mesh() const {
+Ref<ImporterMesh> ImporterMesh::get_shadow_mesh() const {
return shadow_mesh;
}
-void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) {
+void ImporterMesh::_set_data(const Dictionary &p_data) {
clear();
if (p_data.has("blend_shape_names")) {
blend_shapes = p_data["blend_shape_names"];
@@ -805,7 +805,7 @@ void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) {
}
}
}
-Dictionary EditorSceneImporterMesh::_get_data() const {
+Dictionary ImporterMesh::_get_data() const {
Dictionary data;
if (blend_shapes.size()) {
data["blend_shape_names"] = blend_shapes;
@@ -848,7 +848,7 @@ Dictionary EditorSceneImporterMesh::_get_data() const {
return data;
}
-Vector<Face3> EditorSceneImporterMesh::get_faces() const {
+Vector<Face3> ImporterMesh::get_faces() const {
Vector<Face3> faces;
for (int i = 0; i < surfaces.size(); i++) {
if (surfaces[i].primitive == Mesh::PRIMITIVE_TRIANGLES) {
@@ -877,7 +877,7 @@ Vector<Face3> EditorSceneImporterMesh::get_faces() const {
return faces;
}
-Vector<Ref<Shape3D>> EditorSceneImporterMesh::convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const {
+Vector<Ref<Shape3D>> ImporterMesh::convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const {
ERR_FAIL_COND_V(!Mesh::convex_decomposition_function, Vector<Ref<Shape3D>>());
const Vector<Face3> faces = get_faces();
@@ -924,7 +924,7 @@ Vector<Ref<Shape3D>> EditorSceneImporterMesh::convex_decompose(const Mesh::Conve
return ret;
}
-Ref<Shape3D> EditorSceneImporterMesh::create_trimesh_shape() const {
+Ref<Shape3D> ImporterMesh::create_trimesh_shape() const {
Vector<Face3> faces = get_faces();
if (faces.size() == 0) {
return Ref<Shape3D>();
@@ -945,7 +945,7 @@ Ref<Shape3D> EditorSceneImporterMesh::create_trimesh_shape() const {
return shape;
}
-Ref<NavigationMesh> EditorSceneImporterMesh::create_navigation_mesh() {
+Ref<NavigationMesh> ImporterMesh::create_navigation_mesh() {
Vector<Face3> faces = get_faces();
if (faces.size() == 0) {
return Ref<NavigationMesh>();
@@ -1000,7 +1000,7 @@ struct EditorSceneImporterMeshLightmapSurface {
String name;
};
-Error EditorSceneImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache) {
+Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform, float p_texel_size, const Vector<uint8_t> &p_src_cache, Vector<uint8_t> &r_dst_cache) {
ERR_FAIL_COND_V(!array_mesh_lightmap_unwrap_callback, ERR_UNCONFIGURED);
ERR_FAIL_COND_V_MSG(blend_shapes.size() != 0, ERR_UNAVAILABLE, "Can't unwrap mesh with blend shapes.");
@@ -1197,46 +1197,46 @@ Error EditorSceneImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_
return OK;
}
-void EditorSceneImporterMesh::set_lightmap_size_hint(const Size2i &p_size) {
+void ImporterMesh::set_lightmap_size_hint(const Size2i &p_size) {
lightmap_size_hint = p_size;
}
-Size2i EditorSceneImporterMesh::get_lightmap_size_hint() const {
+Size2i ImporterMesh::get_lightmap_size_hint() const {
return lightmap_size_hint;
}
-void EditorSceneImporterMesh::_bind_methods() {
- ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &EditorSceneImporterMesh::add_blend_shape);
- ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &EditorSceneImporterMesh::get_blend_shape_count);
- ClassDB::bind_method(D_METHOD("get_blend_shape_name", "blend_shape_idx"), &EditorSceneImporterMesh::get_blend_shape_name);
+void ImporterMesh::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &ImporterMesh::add_blend_shape);
+ ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &ImporterMesh::get_blend_shape_count);
+ ClassDB::bind_method(D_METHOD("get_blend_shape_name", "blend_shape_idx"), &ImporterMesh::get_blend_shape_name);
- ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &EditorSceneImporterMesh::set_blend_shape_mode);
- ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &EditorSceneImporterMesh::get_blend_shape_mode);
+ ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &ImporterMesh::set_blend_shape_mode);
+ ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &ImporterMesh::get_blend_shape_mode);
- ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material", "name", "flags"), &EditorSceneImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material", "name", "flags"), &ImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String()), DEFVAL(0));
- ClassDB::bind_method(D_METHOD("get_surface_count"), &EditorSceneImporterMesh::get_surface_count);
- ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &EditorSceneImporterMesh::get_surface_primitive_type);
- ClassDB::bind_method(D_METHOD("get_surface_name", "surface_idx"), &EditorSceneImporterMesh::get_surface_name);
- ClassDB::bind_method(D_METHOD("get_surface_arrays", "surface_idx"), &EditorSceneImporterMesh::get_surface_arrays);
- ClassDB::bind_method(D_METHOD("get_surface_blend_shape_arrays", "surface_idx", "blend_shape_idx"), &EditorSceneImporterMesh::get_surface_blend_shape_arrays);
- ClassDB::bind_method(D_METHOD("get_surface_lod_count", "surface_idx"), &EditorSceneImporterMesh::get_surface_lod_count);
- ClassDB::bind_method(D_METHOD("get_surface_lod_size", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_size);
- ClassDB::bind_method(D_METHOD("get_surface_lod_indices", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_indices);
- ClassDB::bind_method(D_METHOD("get_surface_material", "surface_idx"), &EditorSceneImporterMesh::get_surface_material);
- ClassDB::bind_method(D_METHOD("get_surface_format", "surface_idx"), &EditorSceneImporterMesh::get_surface_format);
+ ClassDB::bind_method(D_METHOD("get_surface_count"), &ImporterMesh::get_surface_count);
+ ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &ImporterMesh::get_surface_primitive_type);
+ ClassDB::bind_method(D_METHOD("get_surface_name", "surface_idx"), &ImporterMesh::get_surface_name);
+ ClassDB::bind_method(D_METHOD("get_surface_arrays", "surface_idx"), &ImporterMesh::get_surface_arrays);
+ ClassDB::bind_method(D_METHOD("get_surface_blend_shape_arrays", "surface_idx", "blend_shape_idx"), &ImporterMesh::get_surface_blend_shape_arrays);
+ ClassDB::bind_method(D_METHOD("get_surface_lod_count", "surface_idx"), &ImporterMesh::get_surface_lod_count);
+ ClassDB::bind_method(D_METHOD("get_surface_lod_size", "surface_idx", "lod_idx"), &ImporterMesh::get_surface_lod_size);
+ ClassDB::bind_method(D_METHOD("get_surface_lod_indices", "surface_idx", "lod_idx"), &ImporterMesh::get_surface_lod_indices);
+ ClassDB::bind_method(D_METHOD("get_surface_material", "surface_idx"), &ImporterMesh::get_surface_material);
+ ClassDB::bind_method(D_METHOD("get_surface_format", "surface_idx"), &ImporterMesh::get_surface_format);
- ClassDB::bind_method(D_METHOD("set_surface_name", "surface_idx", "name"), &EditorSceneImporterMesh::set_surface_name);
- ClassDB::bind_method(D_METHOD("set_surface_material", "surface_idx", "material"), &EditorSceneImporterMesh::set_surface_material);
+ ClassDB::bind_method(D_METHOD("set_surface_name", "surface_idx", "name"), &ImporterMesh::set_surface_name);
+ ClassDB::bind_method(D_METHOD("set_surface_material", "surface_idx", "material"), &ImporterMesh::set_surface_material);
- ClassDB::bind_method(D_METHOD("get_mesh", "base_mesh"), &EditorSceneImporterMesh::get_mesh, DEFVAL(Ref<ArrayMesh>()));
- ClassDB::bind_method(D_METHOD("clear"), &EditorSceneImporterMesh::clear);
+ ClassDB::bind_method(D_METHOD("get_mesh", "base_mesh"), &ImporterMesh::get_mesh, DEFVAL(Ref<ArrayMesh>()));
+ ClassDB::bind_method(D_METHOD("clear"), &ImporterMesh::clear);
- ClassDB::bind_method(D_METHOD("_set_data", "data"), &EditorSceneImporterMesh::_set_data);
- ClassDB::bind_method(D_METHOD("_get_data"), &EditorSceneImporterMesh::_get_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &ImporterMesh::_set_data);
+ ClassDB::bind_method(D_METHOD("_get_data"), &ImporterMesh::_get_data);
- ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &EditorSceneImporterMesh::set_lightmap_size_hint);
- ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &EditorSceneImporterMesh::get_lightmap_size_hint);
+ ClassDB::bind_method(D_METHOD("set_lightmap_size_hint", "size"), &ImporterMesh::set_lightmap_size_hint);
+ ClassDB::bind_method(D_METHOD("get_lightmap_size_hint"), &ImporterMesh::get_lightmap_size_hint);
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
}
diff --git a/editor/import/scene_importer_mesh.h b/scene/resources/importer_mesh.h
index 111b191cae..89909f17f0 100644
--- a/editor/import/scene_importer_mesh.h
+++ b/scene/resources/importer_mesh.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* scene_importer_mesh.h */
+/* importer_mesh.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef EDITOR_SCENE_IMPORTER_MESH_H
-#define EDITOR_SCENE_IMPORTER_MESH_H
+#ifndef SCENE_IMPORTER_MESH_H
+#define SCENE_IMPORTER_MESH_H
#include "core/io/resource.h"
#include "core/templates/local_vector.h"
@@ -44,8 +44,8 @@
// so the data is not registered (hence, quality loss), importing happens faster and
// its easier to modify before saving
-class EditorSceneImporterMesh : public Resource {
- GDCLASS(EditorSceneImporterMesh, Resource)
+class ImporterMesh : public Resource {
+ GDCLASS(ImporterMesh, Resource)
struct Surface {
Mesh::PrimitiveType primitive;
@@ -77,7 +77,7 @@ class EditorSceneImporterMesh : public Resource {
Ref<ArrayMesh> mesh;
- Ref<EditorSceneImporterMesh> shadow_mesh;
+ Ref<ImporterMesh> shadow_mesh;
Size2i lightmap_size_hint;
@@ -114,7 +114,7 @@ public:
void generate_lods(float p_normal_merge_angle, float p_normal_split_angle);
void create_shadow_mesh();
- Ref<EditorSceneImporterMesh> get_shadow_mesh() const;
+ Ref<ImporterMesh> get_shadow_mesh() const;
Vector<Face3> get_faces() const;
Vector<Ref<Shape3D>> convex_decompose(const Mesh::ConvexDecompositionSettings &p_settings) const;
@@ -129,4 +129,4 @@ public:
Ref<ArrayMesh> get_mesh(const Ref<ArrayMesh> &p_base = Ref<ArrayMesh>());
void clear();
};
-#endif // EDITOR_SCENE_IMPORTER_MESH_H
+#endif // SCENE_IMPORTER_MESH_H
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 3a6af3afb0..66f04f0292 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -32,11 +32,6 @@
#include "core/config/engine.h"
#include "core/version.h"
-
-#ifdef TOOLS_ENABLED
-#include "editor/editor_settings.h"
-#endif
-
#include "scene/main/scene_tree.h"
#include "scene/scene_string_names.h"
@@ -80,6 +75,9 @@ void Material::_validate_property(PropertyInfo &property) const {
if (!_can_do_next_pass() && property.name == "next_pass") {
property.usage = PROPERTY_USAGE_NONE;
}
+ if (!_can_use_render_priority() && property.name == "render_priority") {
+ property.usage = PROPERTY_USAGE_NONE;
+ }
}
void Material::inspect_native_shader_code() {
@@ -268,19 +266,13 @@ void ShaderMaterial::_bind_methods() {
}
void ShaderMaterial::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
-#ifdef TOOLS_ENABLED
- const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
-#else
- const String quote_style = "\"";
-#endif
-
String f = p_function.operator String();
if ((f == "get_shader_param" || f == "set_shader_param") && p_idx == 0) {
if (shader.is_valid()) {
List<PropertyInfo> pl;
shader->get_param_list(&pl);
for (const PropertyInfo &E : pl) {
- r_options->push_back(E.name.replace_first("shader_param/", "").quote(quote_style));
+ r_options->push_back(E.name.replace_first("shader_param/", "").quote());
}
}
}
@@ -291,6 +283,10 @@ bool ShaderMaterial::_can_do_next_pass() const {
return shader.is_valid() && shader->get_mode() == Shader::MODE_SPATIAL;
}
+bool ShaderMaterial::_can_use_render_priority() const {
+ return shader.is_valid() && shader->get_mode() == Shader::MODE_SPATIAL;
+}
+
Shader::Mode ShaderMaterial::get_shader_mode() const {
if (shader.is_valid()) {
return shader->get_mode();
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 5d7a5324ca..798f7568df 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -53,6 +53,7 @@ protected:
_FORCE_INLINE_ RID _get_material() const { return material; }
static void _bind_methods();
virtual bool _can_do_next_pass() const { return false; }
+ virtual bool _can_use_render_priority() const { return false; }
void _validate_property(PropertyInfo &property) const override;
@@ -93,6 +94,7 @@ protected:
void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override;
virtual bool _can_do_next_pass() const override;
+ virtual bool _can_use_render_priority() const override;
void _shader_changed();
@@ -535,6 +537,7 @@ protected:
static void _bind_methods();
void _validate_property(PropertyInfo &property) const override;
virtual bool _can_do_next_pass() const override { return true; }
+ virtual bool _can_use_render_priority() const override { return true; }
public:
void set_albedo(const Color &p_albedo);
diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp
index 39082b6f7a..b6d3c96cb7 100644
--- a/scene/resources/sky_material.cpp
+++ b/scene/resources/sky_material.cpp
@@ -125,10 +125,6 @@ float ProceduralSkyMaterial::get_sun_curve() const {
return sun_curve;
}
-bool ProceduralSkyMaterial::_can_do_next_pass() const {
- return false;
-}
-
Shader::Mode ProceduralSkyMaterial::get_shader_mode() const {
return Shader::MODE_SKY;
}
@@ -312,10 +308,6 @@ Ref<Texture2D> PanoramaSkyMaterial::get_panorama() const {
return panorama;
}
-bool PanoramaSkyMaterial::_can_do_next_pass() const {
- return false;
-}
-
Shader::Mode PanoramaSkyMaterial::get_shader_mode() const {
return Shader::MODE_SKY;
}
@@ -482,10 +474,6 @@ Ref<Texture2D> PhysicalSkyMaterial::get_night_sky() const {
return night_sky;
}
-bool PhysicalSkyMaterial::_can_do_next_pass() const {
- return false;
-}
-
Shader::Mode PhysicalSkyMaterial::get_shader_mode() const {
return Shader::MODE_SKY;
}
diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h
index 63e730617b..daeda212d4 100644
--- a/scene/resources/sky_material.h
+++ b/scene/resources/sky_material.h
@@ -58,7 +58,6 @@ private:
protected:
static void _bind_methods();
- virtual bool _can_do_next_pass() const override;
public:
void set_sky_top_color(const Color &p_sky_top);
@@ -117,7 +116,6 @@ private:
protected:
static void _bind_methods();
- virtual bool _can_do_next_pass() const override;
public:
void set_panorama(const Ref<Texture2D> &p_panorama);
@@ -159,7 +157,6 @@ private:
protected:
static void _bind_methods();
- virtual bool _can_do_next_pass() const override;
public:
void set_rayleigh_coefficient(float p_rayleigh);
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index e49d883ba4..1486b433f0 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -29,270 +29,20 @@
/*************************************************************************/
#include "theme.h"
-#include "core/io/file_access.h"
#include "core/string/print_string.h"
-void Theme::_emit_theme_changed() {
- if (no_change_propagation) {
- return;
- }
-
- notify_property_list_changed();
- emit_changed();
-}
-
-Vector<String> Theme::_get_icon_list(const String &p_theme_type) const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_icon_list(p_theme_type, &il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_icon_type_list() const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_icon_type_list(&il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_stylebox_list(const String &p_theme_type) const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_stylebox_list(p_theme_type, &il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_stylebox_type_list() const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_stylebox_type_list(&il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_font_list(const String &p_theme_type) const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_font_list(p_theme_type, &il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_font_type_list() const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_font_type_list(&il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_font_size_list(const String &p_theme_type) const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_font_size_list(p_theme_type, &il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_font_size_type_list() const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_font_size_type_list(&il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_color_list(const String &p_theme_type) const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_color_list(p_theme_type, &il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_color_type_list() const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_color_type_list(&il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_constant_list(const String &p_theme_type) const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_constant_list(p_theme_type, &il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_constant_type_list() const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_constant_type_list(&il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_theme_item_list(DataType p_data_type, const String &p_theme_type) const {
- switch (p_data_type) {
- case DATA_TYPE_COLOR:
- return _get_color_list(p_theme_type);
- case DATA_TYPE_CONSTANT:
- return _get_constant_list(p_theme_type);
- case DATA_TYPE_FONT:
- return _get_font_list(p_theme_type);
- case DATA_TYPE_FONT_SIZE:
- return _get_font_size_list(p_theme_type);
- case DATA_TYPE_ICON:
- return _get_icon_list(p_theme_type);
- case DATA_TYPE_STYLEBOX:
- return _get_stylebox_list(p_theme_type);
- case DATA_TYPE_MAX:
- break; // Can't happen, but silences warning.
- }
-
- return Vector<String>();
-}
-
-Vector<String> Theme::_get_theme_item_type_list(DataType p_data_type) const {
- switch (p_data_type) {
- case DATA_TYPE_COLOR:
- return _get_color_type_list();
- case DATA_TYPE_CONSTANT:
- return _get_constant_type_list();
- case DATA_TYPE_FONT:
- return _get_font_type_list();
- case DATA_TYPE_FONT_SIZE:
- return _get_font_size_type_list();
- case DATA_TYPE_ICON:
- return _get_icon_type_list();
- case DATA_TYPE_STYLEBOX:
- return _get_stylebox_type_list();
- case DATA_TYPE_MAX:
- break; // Can't happen, but silences warning.
- }
-
- return Vector<String>();
-}
-
-Vector<String> Theme::_get_type_variation_list(const StringName &p_theme_type) const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_type_variation_list(p_theme_type, &il);
- ilret.resize(il.size());
-
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
-
-Vector<String> Theme::_get_type_list() const {
- Vector<String> ilret;
- List<StringName> il;
-
- get_type_list(&il);
- ilret.resize(il.size());
+// Universal Theme resources used when no other theme has the item.
+Ref<Theme> Theme::default_theme;
+Ref<Theme> Theme::project_default_theme;
- int i = 0;
- String *w = ilret.ptrw();
- for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
- w[i] = E->get();
- }
- return ilret;
-}
+// Universal default values, final fallback for every theme.
+float Theme::default_base_scale = 1.0;
+Ref<Texture2D> Theme::default_icon;
+Ref<StyleBox> Theme::default_style;
+Ref<Font> Theme::default_font;
+int Theme::default_font_size = 16;
+// Dynamic properties.
bool Theme::_set(const StringName &p_name, const Variant &p_value) {
String sname = p_name;
@@ -452,6 +202,63 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
+// Universal fallback Theme resources.
+Ref<Theme> Theme::get_default() {
+ return default_theme;
+}
+
+void Theme::set_default(const Ref<Theme> &p_default) {
+ default_theme = p_default;
+}
+
+Ref<Theme> Theme::get_project_default() {
+ return project_default_theme;
+}
+
+void Theme::set_project_default(const Ref<Theme> &p_project_default) {
+ project_default_theme = p_project_default;
+}
+
+// Universal fallback values for theme item types.
+void Theme::set_default_base_scale(float p_base_scale) {
+ default_base_scale = p_base_scale;
+}
+
+void Theme::set_default_icon(const Ref<Texture2D> &p_icon) {
+ default_icon = p_icon;
+}
+
+void Theme::set_default_style(const Ref<StyleBox> &p_style) {
+ default_style = p_style;
+}
+
+void Theme::set_default_font(const Ref<Font> &p_font) {
+ default_font = p_font;
+}
+
+void Theme::set_default_font_size(int p_font_size) {
+ default_font_size = p_font_size;
+}
+
+// Fallback values for theme item types, configurable per theme.
+void Theme::set_default_theme_base_scale(float p_base_scale) {
+ if (default_theme_base_scale == p_base_scale) {
+ return;
+ }
+
+ default_theme_base_scale = p_base_scale;
+
+ _emit_theme_changed();
+}
+
+float Theme::get_default_theme_base_scale() const {
+ return default_theme_base_scale;
+}
+
+bool Theme::has_default_theme_base_scale() const {
+ return default_theme_base_scale > 0.0;
+}
+
void Theme::set_default_theme_font(const Ref<Font> &p_default_font) {
if (default_theme_font == p_default_font) {
return;
@@ -474,6 +281,10 @@ Ref<Font> Theme::get_default_theme_font() const {
return default_theme_font;
}
+bool Theme::has_default_theme_font() const {
+ return default_theme_font.is_valid();
+}
+
void Theme::set_default_theme_font_size(int p_font_size) {
if (default_theme_font_size == p_font_size) {
return;
@@ -488,47 +299,15 @@ int Theme::get_default_theme_font_size() const {
return default_theme_font_size;
}
-Ref<Theme> Theme::project_default_theme;
-Ref<Theme> Theme::default_theme;
-Ref<Texture2D> Theme::default_icon;
-Ref<StyleBox> Theme::default_style;
-Ref<Font> Theme::default_font;
-int Theme::default_font_size = 16;
-
-Ref<Theme> Theme::get_default() {
- return default_theme;
-}
-
-void Theme::set_default(const Ref<Theme> &p_default) {
- default_theme = p_default;
-}
-
-Ref<Theme> Theme::get_project_default() {
- return project_default_theme;
-}
-
-void Theme::set_project_default(const Ref<Theme> &p_project_default) {
- project_default_theme = p_project_default;
-}
-
-void Theme::set_default_icon(const Ref<Texture2D> &p_icon) {
- default_icon = p_icon;
-}
-
-void Theme::set_default_style(const Ref<StyleBox> &p_style) {
- default_style = p_style;
-}
-
-void Theme::set_default_font(const Ref<Font> &p_font) {
- default_font = p_font;
-}
-
-void Theme::set_default_font_size(int p_font_size) {
- default_font_size = p_font_size;
+bool Theme::has_default_theme_font_size() const {
+ return default_theme_font_size > 0;
}
+// Icons.
void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref<Texture2D> &p_icon) {
+ bool existing = false;
if (icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) {
+ existing = true;
icon_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
@@ -538,7 +317,7 @@ void Theme::set_icon(const StringName &p_name, const StringName &p_theme_type, c
icon_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED);
}
- _emit_theme_changed();
+ _emit_theme_changed(!existing);
}
Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_theme_type) const {
@@ -565,7 +344,7 @@ void Theme::rename_icon(const StringName &p_old_name, const StringName &p_name,
icon_map[p_theme_type][p_name] = icon_map[p_theme_type][p_old_name];
icon_map[p_theme_type].erase(p_old_name);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type) {
@@ -578,7 +357,7 @@ void Theme::clear_icon(const StringName &p_name, const StringName &p_theme_type)
icon_map[p_theme_type].erase(p_name);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
void Theme::get_icon_list(StringName p_theme_type, List<StringName> *p_list) const {
@@ -611,8 +390,11 @@ void Theme::get_icon_type_list(List<StringName> *p_list) const {
}
}
+// Styleboxes.
void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref<StyleBox> &p_style) {
+ bool existing = false;
if (style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) {
+ existing = true;
style_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
@@ -622,7 +404,7 @@ void Theme::set_stylebox(const StringName &p_name, const StringName &p_theme_typ
style_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED);
}
- _emit_theme_changed();
+ _emit_theme_changed(!existing);
}
Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
@@ -649,7 +431,7 @@ void Theme::rename_stylebox(const StringName &p_old_name, const StringName &p_na
style_map[p_theme_type][p_name] = style_map[p_theme_type][p_old_name];
style_map[p_theme_type].erase(p_old_name);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_type) {
@@ -662,7 +444,7 @@ void Theme::clear_stylebox(const StringName &p_name, const StringName &p_theme_t
style_map[p_theme_type].erase(p_name);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
void Theme::get_stylebox_list(StringName p_theme_type, List<StringName> *p_list) const {
@@ -695,8 +477,11 @@ void Theme::get_stylebox_type_list(List<StringName> *p_list) const {
}
}
+// Fonts.
void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, const Ref<Font> &p_font) {
+ bool existing = false;
if (font_map[p_theme_type][p_name].is_valid()) {
+ existing = true;
font_map[p_theme_type][p_name]->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
}
@@ -706,13 +491,13 @@ void Theme::set_font(const StringName &p_name, const StringName &p_theme_type, c
font_map[p_theme_type][p_name]->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED);
}
- _emit_theme_changed();
+ _emit_theme_changed(!existing);
}
Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_theme_type) const {
if (font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) {
return font_map[p_theme_type][p_name];
- } else if (default_theme_font.is_valid()) {
+ } else if (has_default_theme_font()) {
return default_theme_font;
} else {
return default_font;
@@ -720,7 +505,7 @@ Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_theme_ty
}
bool Theme::has_font(const StringName &p_name, const StringName &p_theme_type) const {
- return ((font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) || default_theme_font.is_valid());
+ return ((font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) || has_default_theme_font());
}
bool Theme::has_font_nocheck(const StringName &p_name, const StringName &p_theme_type) const {
@@ -735,7 +520,7 @@ void Theme::rename_font(const StringName &p_old_name, const StringName &p_name,
font_map[p_theme_type][p_name] = font_map[p_theme_type][p_old_name];
font_map[p_theme_type].erase(p_old_name);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type) {
@@ -748,7 +533,7 @@ void Theme::clear_font(const StringName &p_name, const StringName &p_theme_type)
font_map[p_theme_type].erase(p_name);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
void Theme::get_font_list(StringName p_theme_type, List<StringName> *p_list) const {
@@ -781,16 +566,18 @@ void Theme::get_font_type_list(List<StringName> *p_list) const {
}
}
+// Font sizes.
void Theme::set_font_size(const StringName &p_name, const StringName &p_theme_type, int p_font_size) {
+ bool existing = has_font_size_nocheck(p_name, p_theme_type);
font_size_map[p_theme_type][p_name] = p_font_size;
- _emit_theme_changed();
+ _emit_theme_changed(!existing);
}
int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_type) const {
if (font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name) && (font_size_map[p_theme_type][p_name] > 0)) {
return font_size_map[p_theme_type][p_name];
- } else if (default_theme_font_size > 0) {
+ } else if (has_default_theme_font_size()) {
return default_theme_font_size;
} else {
return default_font_size;
@@ -798,7 +585,7 @@ int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_typ
}
bool Theme::has_font_size(const StringName &p_name, const StringName &p_theme_type) const {
- return ((font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name) && (font_size_map[p_theme_type][p_name] > 0)) || (default_theme_font_size > 0));
+ return ((font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name) && (font_size_map[p_theme_type][p_name] > 0)) || has_default_theme_font_size());
}
bool Theme::has_font_size_nocheck(const StringName &p_name, const StringName &p_theme_type) const {
@@ -813,7 +600,7 @@ void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_n
font_size_map[p_theme_type][p_name] = font_size_map[p_theme_type][p_old_name];
font_size_map[p_theme_type].erase(p_old_name);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_type) {
@@ -822,7 +609,7 @@ void Theme::clear_font_size(const StringName &p_name, const StringName &p_theme_
font_size_map[p_theme_type].erase(p_name);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
void Theme::get_font_size_list(StringName p_theme_type, List<StringName> *p_list) const {
@@ -855,10 +642,12 @@ void Theme::get_font_size_type_list(List<StringName> *p_list) const {
}
}
+// Colors.
void Theme::set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color) {
+ bool existing = has_color_nocheck(p_name, p_theme_type);
color_map[p_theme_type][p_name] = p_color;
- _emit_theme_changed();
+ _emit_theme_changed(!existing);
}
Color Theme::get_color(const StringName &p_name, const StringName &p_theme_type) const {
@@ -885,7 +674,7 @@ void Theme::rename_color(const StringName &p_old_name, const StringName &p_name,
color_map[p_theme_type][p_name] = color_map[p_theme_type][p_old_name];
color_map[p_theme_type].erase(p_old_name);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type) {
@@ -894,7 +683,7 @@ void Theme::clear_color(const StringName &p_name, const StringName &p_theme_type
color_map[p_theme_type].erase(p_name);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
void Theme::get_color_list(StringName p_theme_type, List<StringName> *p_list) const {
@@ -927,10 +716,12 @@ void Theme::get_color_type_list(List<StringName> *p_list) const {
}
}
+// Theme constants.
void Theme::set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant) {
+ bool existing = has_constant_nocheck(p_name, p_theme_type);
constant_map[p_theme_type][p_name] = p_constant;
- _emit_theme_changed();
+ _emit_theme_changed(!existing);
}
int Theme::get_constant(const StringName &p_name, const StringName &p_theme_type) const {
@@ -957,7 +748,7 @@ void Theme::rename_constant(const StringName &p_old_name, const StringName &p_na
constant_map[p_theme_type][p_name] = constant_map[p_theme_type][p_old_name];
constant_map[p_theme_type].erase(p_old_name);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_type) {
@@ -966,7 +757,7 @@ void Theme::clear_constant(const StringName &p_name, const StringName &p_theme_t
constant_map[p_theme_type].erase(p_name);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
void Theme::get_constant_list(StringName p_theme_type, List<StringName> *p_list) const {
@@ -999,6 +790,7 @@ void Theme::get_constant_type_list(List<StringName> *p_list) const {
}
}
+// Generic methods for managing theme items.
void Theme::set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_theme_type, const Variant &p_value) {
switch (p_data_type) {
case DATA_TYPE_COLOR: {
@@ -1230,6 +1022,7 @@ void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_l
}
}
+// Theme type variations.
void Theme::set_type_variation(const StringName &p_theme_type, const StringName &p_base_type) {
ERR_FAIL_COND_MSG(p_theme_type == StringName(), "An empty theme type cannot be marked as a variation of another type.");
ERR_FAIL_COND_MSG(ClassDB::class_exists(p_theme_type), "A type associated with a built-in class cannot be marked as a variation of another type.");
@@ -1243,7 +1036,7 @@ void Theme::set_type_variation(const StringName &p_theme_type, const StringName
variation_map[p_theme_type] = p_base_type;
variation_base_map[p_base_type].push_back(p_theme_type);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
bool Theme::is_type_variation(const StringName &p_theme_type, const StringName &p_base_type) const {
@@ -1257,7 +1050,7 @@ void Theme::clear_type_variation(const StringName &p_theme_type) {
variation_base_map[base_type].erase(p_theme_type);
variation_map.erase(p_theme_type);
- _emit_theme_changed();
+ _emit_theme_changed(true);
}
StringName Theme::get_type_variation_base(const StringName &p_theme_type) const {
@@ -1287,67 +1080,355 @@ void Theme::get_type_variation_list(const StringName &p_base_type, List<StringNa
}
}
-void Theme::_freeze_change_propagation() {
- no_change_propagation = true;
-}
+// Theme types.
+void Theme::get_type_list(List<StringName> *p_list) const {
+ ERR_FAIL_NULL(p_list);
-void Theme::_unfreeze_and_propagate_changes() {
- no_change_propagation = false;
- _emit_theme_changed();
+ Set<StringName> types;
+ const StringName *key = nullptr;
+
+ // Icons.
+ while ((key = icon_map.next(key))) {
+ types.insert(*key);
+ }
+
+ key = nullptr;
+
+ // StyleBoxes.
+ while ((key = style_map.next(key))) {
+ types.insert(*key);
+ }
+
+ key = nullptr;
+
+ // Fonts.
+ while ((key = font_map.next(key))) {
+ types.insert(*key);
+ }
+
+ key = nullptr;
+
+ // Font sizes.
+ while ((key = font_size_map.next(key))) {
+ types.insert(*key);
+ }
+
+ key = nullptr;
+
+ // Colors.
+ while ((key = color_map.next(key))) {
+ types.insert(*key);
+ }
+
+ key = nullptr;
+
+ // Constants.
+ while ((key = constant_map.next(key))) {
+ types.insert(*key);
+ }
+
+ for (Set<StringName>::Element *E = types.front(); E; E = E->next()) {
+ p_list->push_back(E->get());
+ }
}
-void Theme::clear() {
- // These items need disconnecting.
- {
- const StringName *K = nullptr;
- while ((K = icon_map.next(K))) {
- const StringName *L = nullptr;
- while ((L = icon_map[*K].next(L))) {
- Ref<Texture2D> icon = icon_map[*K][*L];
- if (icon.is_valid()) {
- icon->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
- }
+void Theme::get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variation, List<StringName> *p_list) {
+ ERR_FAIL_NULL(p_list);
+
+ // Build the dependency chain for type variations.
+ if (p_type_variation != StringName()) {
+ StringName variation_name = p_type_variation;
+ while (variation_name != StringName()) {
+ p_list->push_back(variation_name);
+ variation_name = get_type_variation_base(variation_name);
+
+ // If we have reached the base type dependency, it's safe to stop (assuming no funny business was done to the Theme).
+ if (variation_name == p_base_type) {
+ break;
}
}
}
- {
- const StringName *K = nullptr;
- while ((K = style_map.next(K))) {
- const StringName *L = nullptr;
- while ((L = style_map[*K].next(L))) {
- Ref<StyleBox> style = style_map[*K][*L];
- if (style.is_valid()) {
- style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
- }
- }
- }
+ // Continue building the chain using native class hierarchy.
+ StringName class_name = p_base_type;
+ while (class_name != StringName()) {
+ p_list->push_back(class_name);
+ class_name = ClassDB::get_parent_class_nocheck(class_name);
}
+}
- {
- const StringName *K = nullptr;
- while ((K = font_map.next(K))) {
- const StringName *L = nullptr;
- while ((L = font_map[*K].next(L))) {
- Ref<Font> font = font_map[*K][*L];
- if (font.is_valid()) {
- font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
- }
- }
- }
+// Internal methods for getting lists as a Vector of String (compatible with public API).
+Vector<String> Theme::_get_icon_list(const String &p_theme_type) const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_icon_list(p_theme_type, &il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
}
+ return ilret;
+}
- icon_map.clear();
- style_map.clear();
- font_map.clear();
- font_size_map.clear();
- color_map.clear();
- constant_map.clear();
+Vector<String> Theme::_get_icon_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
- variation_map.clear();
- variation_base_map.clear();
+ get_icon_type_list(&il);
+ ilret.resize(il.size());
- _emit_theme_changed();
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_stylebox_list(const String &p_theme_type) const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_stylebox_list(p_theme_type, &il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_stylebox_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_stylebox_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_font_list(const String &p_theme_type) const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_font_list(p_theme_type, &il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_font_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_font_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_font_size_list(const String &p_theme_type) const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_font_size_list(p_theme_type, &il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_font_size_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_font_size_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_color_list(const String &p_theme_type) const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_color_list(p_theme_type, &il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_color_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_color_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_constant_list(const String &p_theme_type) const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_constant_list(p_theme_type, &il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_constant_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_constant_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_theme_item_list(DataType p_data_type, const String &p_theme_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return _get_color_list(p_theme_type);
+ case DATA_TYPE_CONSTANT:
+ return _get_constant_list(p_theme_type);
+ case DATA_TYPE_FONT:
+ return _get_font_list(p_theme_type);
+ case DATA_TYPE_FONT_SIZE:
+ return _get_font_size_list(p_theme_type);
+ case DATA_TYPE_ICON:
+ return _get_icon_list(p_theme_type);
+ case DATA_TYPE_STYLEBOX:
+ return _get_stylebox_list(p_theme_type);
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return Vector<String>();
+}
+
+Vector<String> Theme::_get_theme_item_type_list(DataType p_data_type) const {
+ switch (p_data_type) {
+ case DATA_TYPE_COLOR:
+ return _get_color_type_list();
+ case DATA_TYPE_CONSTANT:
+ return _get_constant_type_list();
+ case DATA_TYPE_FONT:
+ return _get_font_type_list();
+ case DATA_TYPE_FONT_SIZE:
+ return _get_font_size_type_list();
+ case DATA_TYPE_ICON:
+ return _get_icon_type_list();
+ case DATA_TYPE_STYLEBOX:
+ return _get_stylebox_type_list();
+ case DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return Vector<String>();
+}
+
+Vector<String> Theme::_get_type_variation_list(const StringName &p_theme_type) const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_type_variation_list(p_theme_type, &il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+Vector<String> Theme::_get_type_list() const {
+ Vector<String> ilret;
+ List<StringName> il;
+
+ get_type_list(&il);
+ ilret.resize(il.size());
+
+ int i = 0;
+ String *w = ilret.ptrw();
+ for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) {
+ w[i] = E->get();
+ }
+ return ilret;
+}
+
+// Theme bulk manipulations.
+void Theme::_emit_theme_changed(bool p_notify_list_changed) {
+ if (no_change_propagation) {
+ return;
+ }
+
+ if (p_notify_list_changed) {
+ notify_property_list_changed();
+ }
+ emit_changed();
+}
+
+void Theme::_freeze_change_propagation() {
+ no_change_propagation = true;
+}
+
+void Theme::_unfreeze_and_propagate_changes() {
+ no_change_propagation = false;
+ _emit_theme_changed(true);
}
void Theme::merge_with(const Ref<Theme> &p_other) {
@@ -1434,80 +1515,58 @@ void Theme::merge_with(const Ref<Theme> &p_other) {
_unfreeze_and_propagate_changes();
}
-void Theme::get_type_list(List<StringName> *p_list) const {
- ERR_FAIL_NULL(p_list);
-
- Set<StringName> types;
- const StringName *key = nullptr;
-
- // Icons.
- while ((key = icon_map.next(key))) {
- types.insert(*key);
- }
-
- key = nullptr;
-
- // StyleBoxes.
- while ((key = style_map.next(key))) {
- types.insert(*key);
- }
-
- key = nullptr;
-
- // Fonts.
- while ((key = font_map.next(key))) {
- types.insert(*key);
- }
-
- key = nullptr;
-
- // Font sizes.
- while ((key = font_size_map.next(key))) {
- types.insert(*key);
- }
-
- key = nullptr;
-
- // Colors.
- while ((key = color_map.next(key))) {
- types.insert(*key);
- }
-
- key = nullptr;
-
- // Constants.
- while ((key = constant_map.next(key))) {
- types.insert(*key);
+void Theme::clear() {
+ // These items need disconnecting.
+ {
+ const StringName *K = nullptr;
+ while ((K = icon_map.next(K))) {
+ const StringName *L = nullptr;
+ while ((L = icon_map[*K].next(L))) {
+ Ref<Texture2D> icon = icon_map[*K][*L];
+ if (icon.is_valid()) {
+ icon->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ }
+ }
+ }
}
- for (Set<StringName>::Element *E = types.front(); E; E = E->next()) {
- p_list->push_back(E->get());
+ {
+ const StringName *K = nullptr;
+ while ((K = style_map.next(K))) {
+ const StringName *L = nullptr;
+ while ((L = style_map[*K].next(L))) {
+ Ref<StyleBox> style = style_map[*K][*L];
+ if (style.is_valid()) {
+ style->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ }
+ }
+ }
}
-}
-void Theme::get_type_dependencies(const StringName &p_base_type, const StringName &p_type_variation, List<StringName> *p_list) {
- ERR_FAIL_NULL(p_list);
-
- // Build the dependency chain for type variations.
- if (p_type_variation != StringName()) {
- StringName variation_name = p_type_variation;
- while (variation_name != StringName()) {
- p_list->push_back(variation_name);
- variation_name = get_type_variation_base(variation_name);
-
- // If we have reached the base type dependency, it's safe to stop (assuming no funny business was done to the Theme).
- if (variation_name == p_base_type) {
- break;
+ {
+ const StringName *K = nullptr;
+ while ((K = font_map.next(K))) {
+ const StringName *L = nullptr;
+ while ((L = font_map[*K].next(L))) {
+ Ref<Font> font = font_map[*K][*L];
+ if (font.is_valid()) {
+ font->disconnect("changed", callable_mp(this, &Theme::_emit_theme_changed));
+ }
}
}
}
- // Continue building the chain using native class hierarchy.
- StringName class_name = p_base_type;
- while (class_name != StringName()) {
- p_list->push_back(class_name);
- class_name = ClassDB::get_parent_class_nocheck(class_name);
- }
+ icon_map.clear();
+ style_map.clear();
+ font_map.clear();
+ font_size_map.clear();
+ color_map.clear();
+ constant_map.clear();
+
+ variation_map.clear();
+ variation_base_map.clear();
+
+ _emit_theme_changed(true);
}
void Theme::reset_state() {
@@ -1563,11 +1622,17 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_constant_list", "theme_type"), &Theme::_get_constant_list);
ClassDB::bind_method(D_METHOD("get_constant_type_list"), &Theme::_get_constant_type_list);
+ ClassDB::bind_method(D_METHOD("set_default_base_scale", "font_size"), &Theme::set_default_theme_base_scale);
+ ClassDB::bind_method(D_METHOD("get_default_base_scale"), &Theme::get_default_theme_base_scale);
+ ClassDB::bind_method(D_METHOD("has_default_base_scale"), &Theme::has_default_theme_base_scale);
+
ClassDB::bind_method(D_METHOD("set_default_font", "font"), &Theme::set_default_theme_font);
ClassDB::bind_method(D_METHOD("get_default_font"), &Theme::get_default_theme_font);
+ ClassDB::bind_method(D_METHOD("has_default_font"), &Theme::has_default_theme_font);
ClassDB::bind_method(D_METHOD("set_default_font_size", "font_size"), &Theme::set_default_theme_font_size);
ClassDB::bind_method(D_METHOD("get_default_font_size"), &Theme::get_default_theme_font_size);
+ ClassDB::bind_method(D_METHOD("has_default_font_size"), &Theme::has_default_theme_font_size);
ClassDB::bind_method(D_METHOD("set_theme_item", "data_type", "name", "theme_type", "value"), &Theme::set_theme_item);
ClassDB::bind_method(D_METHOD("get_theme_item", "data_type", "name", "theme_type"), &Theme::get_theme_item);
@@ -1588,6 +1653,7 @@ void Theme::_bind_methods() {
ClassDB::bind_method(D_METHOD("merge_with", "other"), &Theme::merge_with);
ClassDB::bind_method(D_METHOD("clear"), &Theme::clear);
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "default_base_scale", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,or_greater"), "set_default_base_scale", "get_default_base_scale");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "default_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_default_font", "get_default_font");
ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size"), "set_default_font_size", "get_default_font_size");
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index 15f21b91b8..d170d53ae3 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -61,7 +61,7 @@ public:
private:
bool no_change_propagation = false;
- void _emit_theme_changed();
+ void _emit_theme_changed(bool p_notify_list_changed = false);
HashMap<StringName, HashMap<StringName, Ref<Texture2D>>> icon_map;
HashMap<StringName, HashMap<StringName, Ref<StyleBox>>> style_map;
@@ -96,13 +96,19 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- static Ref<Theme> project_default_theme;
+ // Universal Theme resources used when no other theme has the item.
static Ref<Theme> default_theme;
+ static Ref<Theme> project_default_theme;
+
+ // Universal default values, final fallback for every theme.
+ static float default_base_scale;
static Ref<Texture2D> default_icon;
static Ref<StyleBox> default_style;
static Ref<Font> default_font;
static int default_font_size;
+ // Default values configurable for each individual theme.
+ float default_theme_base_scale = 0.0;
Ref<Font> default_theme_font;
int default_theme_font_size = -1;
@@ -120,16 +126,23 @@ public:
static Ref<Theme> get_project_default();
static void set_project_default(const Ref<Theme> &p_project_default);
+ static void set_default_base_scale(float p_base_scale);
static void set_default_icon(const Ref<Texture2D> &p_icon);
static void set_default_style(const Ref<StyleBox> &p_style);
static void set_default_font(const Ref<Font> &p_font);
static void set_default_font_size(int p_font_size);
+ void set_default_theme_base_scale(float p_base_scale);
+ float get_default_theme_base_scale() const;
+ bool has_default_theme_base_scale() const;
+
void set_default_theme_font(const Ref<Font> &p_default_font);
Ref<Font> get_default_theme_font() const;
+ bool has_default_theme_font() const;
void set_default_theme_font_size(int p_font_size);
int get_default_theme_font_size() const;
+ bool has_default_theme_font_size() const;
void set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref<Texture2D> &p_icon);
Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_theme_type) const;
diff --git a/servers/physics_3d/soft_body_3d_sw.cpp b/servers/physics_3d/soft_body_3d_sw.cpp
index 5e8f8692ba..c9166810fe 100644
--- a/servers/physics_3d/soft_body_3d_sw.cpp
+++ b/servers/physics_3d/soft_body_3d_sw.cpp
@@ -318,11 +318,13 @@ void SoftBody3DSW::apply_nodes_transform(const Transform3D &p_transform) {
}
Vector3 SoftBody3DSW::get_vertex_position(int p_index) const {
+ ERR_FAIL_COND_V(p_index < 0, Vector3());
+
if (soft_mesh.is_null()) {
return Vector3();
}
- ERR_FAIL_INDEX_V(p_index, (int)map_visual_to_physics.size(), Vector3());
+ ERR_FAIL_COND_V(p_index >= (int)map_visual_to_physics.size(), Vector3());
uint32_t node_index = map_visual_to_physics[p_index];
ERR_FAIL_COND_V(node_index >= nodes.size(), Vector3());
@@ -330,11 +332,13 @@ Vector3 SoftBody3DSW::get_vertex_position(int p_index) const {
}
void SoftBody3DSW::set_vertex_position(int p_index, const Vector3 &p_position) {
+ ERR_FAIL_COND(p_index < 0);
+
if (soft_mesh.is_null()) {
return;
}
- ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size());
+ ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size());
uint32_t node_index = map_visual_to_physics[p_index];
ERR_FAIL_COND(node_index >= nodes.size());
@@ -344,6 +348,8 @@ void SoftBody3DSW::set_vertex_position(int p_index, const Vector3 &p_position) {
}
void SoftBody3DSW::pin_vertex(int p_index) {
+ ERR_FAIL_COND(p_index < 0);
+
if (is_vertex_pinned(p_index)) {
return;
}
@@ -351,7 +357,7 @@ void SoftBody3DSW::pin_vertex(int p_index) {
pinned_vertices.push_back(p_index);
if (!soft_mesh.is_null()) {
- ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size());
+ ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size());
uint32_t node_index = map_visual_to_physics[p_index];
ERR_FAIL_COND(node_index >= nodes.size());
@@ -361,13 +367,15 @@ void SoftBody3DSW::pin_vertex(int p_index) {
}
void SoftBody3DSW::unpin_vertex(int p_index) {
+ ERR_FAIL_COND(p_index < 0);
+
uint32_t pinned_count = pinned_vertices.size();
for (uint32_t i = 0; i < pinned_count; ++i) {
if (p_index == pinned_vertices[i]) {
pinned_vertices.remove(i);
if (!soft_mesh.is_null()) {
- ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size());
+ ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size());
uint32_t node_index = map_visual_to_physics[p_index];
ERR_FAIL_COND(node_index >= nodes.size());
@@ -387,10 +395,10 @@ void SoftBody3DSW::unpin_all_vertices() {
real_t inv_node_mass = nodes.size() * inv_total_mass;
uint32_t pinned_count = pinned_vertices.size();
for (uint32_t i = 0; i < pinned_count; ++i) {
- uint32_t vertex_index = pinned_vertices[i];
+ int pinned_vertex = pinned_vertices[i];
- ERR_CONTINUE(vertex_index >= map_visual_to_physics.size());
- uint32_t node_index = map_visual_to_physics[vertex_index];
+ ERR_CONTINUE(pinned_vertex >= (int)map_visual_to_physics.size());
+ uint32_t node_index = map_visual_to_physics[pinned_vertex];
ERR_CONTINUE(node_index >= nodes.size());
Node &node = nodes[node_index];
@@ -402,6 +410,8 @@ void SoftBody3DSW::unpin_all_vertices() {
}
bool SoftBody3DSW::is_vertex_pinned(int p_index) const {
+ ERR_FAIL_COND_V(p_index < 0, false);
+
uint32_t pinned_count = pinned_vertices.size();
for (uint32_t i = 0; i < pinned_count; ++i) {
if (p_index == pinned_vertices[i]) {
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 0416b06d0d..a1c3481ed6 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -373,7 +373,7 @@ void SceneShaderForwardClustered::ShaderData::get_instance_param_list(List<Rende
p.info = ShaderLanguage::uniform_to_property_info(E.value);
p.info.name = E.key; //supply name
p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.hint);
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
p_param_list->push_back(p);
}
}
@@ -398,7 +398,7 @@ Variant SceneShaderForwardClustered::ShaderData::get_default_parameter(const Str
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index 4118735cf2..16d650a540 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -365,7 +365,7 @@ void SceneShaderForwardMobile::ShaderData::get_instance_param_list(List<Renderer
p.info = ShaderLanguage::uniform_to_property_info(E.value);
p.info.name = E.key; //supply name
p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.hint);
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
p_param_list->push_back(p);
}
}
@@ -390,7 +390,7 @@ Variant SceneShaderForwardMobile::ShaderData::get_default_parameter(const String
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();
}
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index b792ec9971..c69c9eeadf 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -2161,7 +2161,7 @@ void RendererCanvasRenderRD::ShaderData::get_instance_param_list(List<RendererSt
p.info = ShaderLanguage::uniform_to_property_info(E.value);
p.info.name = E.key; //supply name
p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.hint);
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
p_param_list->push_back(p);
}
}
@@ -2186,7 +2186,7 @@ Variant RendererCanvasRenderRD::ShaderData::get_default_parameter(const StringNa
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
index 830b0e7bae..7925e735a0 100644
--- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
@@ -177,7 +177,7 @@ void RendererSceneSkyRD::SkyShaderData::get_instance_param_list(List<RendererSto
p.info = ShaderLanguage::uniform_to_property_info(E.value);
p.info.name = E.key; //supply name
p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.hint);
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
p_param_list->push_back(p);
}
}
@@ -202,7 +202,7 @@ Variant RendererSceneSkyRD::SkyShaderData::get_default_parameter(const StringNam
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();
}
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index 5ef1f46742..771be4bb3d 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -1691,73 +1691,183 @@ void RendererStorageRD::material_set_data_request_function(ShaderType p_shader_t
material_data_request_func[p_shader_type] = p_function;
}
-_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant &value, uint8_t *data, bool p_linear_color) {
+_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_array_size, const Variant &value, uint8_t *data, bool p_linear_color) {
switch (type) {
case ShaderLanguage::TYPE_BOOL: {
- bool v = value;
-
uint32_t *gui = (uint32_t *)data;
- *gui = v ? 1 : 0;
+
+ if (p_array_size > 0) {
+ const PackedInt32Array &ba = value;
+ int s = ba.size();
+ const int *r = ba.ptr();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = (r[i] != 0) ? 1 : 0;
+ } else {
+ gui[j] = 0;
+ }
+ gui[j + 1] = 0; // ignored
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ bool v = value;
+ gui[0] = v ? 1 : 0;
+ }
} break;
case ShaderLanguage::TYPE_BVEC2: {
- int v = value;
uint32_t *gui = (uint32_t *)data;
- gui[0] = v & 1 ? 1 : 0;
- gui[1] = v & 2 ? 1 : 0;
+ if (p_array_size > 0) {
+ const PackedInt32Array &ba = value;
+ int s = ba.size();
+ const int *r = ba.ptr();
+ int count = 2 * p_array_size;
+
+ for (int i = 0, j = 0; i < count; i += 2, j += 4) {
+ if (i < s) {
+ gui[j] = r[i] ? 1 : 0;
+ gui[j + 1] = r[i + 1] ? 1 : 0;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ }
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ int v = value;
+ gui[0] = v & 1 ? 1 : 0;
+ gui[1] = v & 2 ? 1 : 0;
+ }
} break;
case ShaderLanguage::TYPE_BVEC3: {
- int v = value;
uint32_t *gui = (uint32_t *)data;
- gui[0] = (v & 1) ? 1 : 0;
- gui[1] = (v & 2) ? 1 : 0;
- gui[2] = (v & 4) ? 1 : 0;
+ if (p_array_size > 0) {
+ const PackedInt32Array &ba = value;
+ int s = ba.size();
+ const int *r = ba.ptr();
+ int count = 3 * p_array_size;
+
+ for (int i = 0, j = 0; i < count; i += 3, j += 4) {
+ if (i < s) {
+ gui[j] = r[i] ? 1 : 0;
+ gui[j + 1] = r[i + 1] ? 1 : 0;
+ gui[j + 2] = r[i + 2] ? 1 : 0;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+ }
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ int v = value;
+ gui[0] = (v & 1) ? 1 : 0;
+ gui[1] = (v & 2) ? 1 : 0;
+ gui[2] = (v & 4) ? 1 : 0;
+ }
} break;
case ShaderLanguage::TYPE_BVEC4: {
- int v = value;
uint32_t *gui = (uint32_t *)data;
- gui[0] = (v & 1) ? 1 : 0;
- gui[1] = (v & 2) ? 1 : 0;
- gui[2] = (v & 4) ? 1 : 0;
- gui[3] = (v & 8) ? 1 : 0;
+ if (p_array_size > 0) {
+ const PackedInt32Array &ba = value;
+ int s = ba.size();
+ const int *r = ba.ptr();
+ int count = 4 * p_array_size;
+
+ for (int i = 0; i < count; i += 4) {
+ if (i < s) {
+ gui[i] = r[i] ? 1 : 0;
+ gui[i + 1] = r[i + 1] ? 1 : 0;
+ gui[i + 2] = r[i + 2] ? 1 : 0;
+ gui[i + 3] = r[i + 3] ? 1 : 0;
+ } else {
+ gui[i] = 0;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
+ }
+ }
+ } else {
+ int v = value;
+ gui[0] = (v & 1) ? 1 : 0;
+ gui[1] = (v & 2) ? 1 : 0;
+ gui[2] = (v & 4) ? 1 : 0;
+ gui[3] = (v & 8) ? 1 : 0;
+ }
} break;
case ShaderLanguage::TYPE_INT: {
- int v = value;
int32_t *gui = (int32_t *)data;
- gui[0] = v;
+ if (p_array_size > 0) {
+ Vector<int> iv = value;
+ int s = iv.size();
+ const int *r = iv.ptr();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = r[i];
+ } else {
+ gui[j] = 0;
+ }
+ gui[j + 1] = 0; // ignored
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ int v = value;
+ gui[0] = v;
+ }
} break;
case ShaderLanguage::TYPE_IVEC2: {
Vector<int> iv = value;
int s = iv.size();
int32_t *gui = (int32_t *)data;
- const int *r = iv.ptr();
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+ int count = 2 * p_array_size;
- for (int i = 0; i < 2; i++) {
+ const int *r = iv.ptr();
+ for (int i = 0, j = 0; i < count; i += 2, j += 4) {
if (i < s) {
- gui[i] = r[i];
+ gui[j] = r[i];
+ gui[j + 1] = r[i + 1];
} else {
- gui[i] = 0;
+ gui[j] = 0;
+ gui[j + 1] = 0;
}
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
}
-
} break;
case ShaderLanguage::TYPE_IVEC3: {
Vector<int> iv = value;
int s = iv.size();
int32_t *gui = (int32_t *)data;
- const int *r = iv.ptr();
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+ int count = 3 * p_array_size;
- for (int i = 0; i < 3; i++) {
+ const int *r = iv.ptr();
+ for (int i = 0, j = 0; i < count; i += 3, j += 4) {
if (i < s) {
- gui[i] = r[i];
+ gui[j] = r[i];
+ gui[j + 1] = r[i + 1];
+ gui[j + 2] = r[i + 2];
} else {
- gui[i] = 0;
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
}
+ gui[j + 3] = 0; // ignored
}
} break;
case ShaderLanguage::TYPE_IVEC4: {
@@ -1765,35 +1875,70 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
int s = iv.size();
int32_t *gui = (int32_t *)data;
- const int *r = iv.ptr();
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+ int count = 4 * p_array_size;
- for (int i = 0; i < 4; i++) {
+ const int *r = iv.ptr();
+ for (int i = 0; i < count; i += 4) {
if (i < s) {
gui[i] = r[i];
+ gui[i + 1] = r[i + 1];
+ gui[i + 2] = r[i + 2];
+ gui[i + 3] = r[i + 3];
} else {
gui[i] = 0;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
}
}
} break;
case ShaderLanguage::TYPE_UINT: {
- int v = value;
uint32_t *gui = (uint32_t *)data;
- gui[0] = v;
+ if (p_array_size > 0) {
+ Vector<int> iv = value;
+ int s = iv.size();
+ const int *r = iv.ptr();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = r[i];
+ } else {
+ gui[j] = 0;
+ }
+ gui[j + 1] = 0; // ignored
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ int v = value;
+ gui[0] = v;
+ }
} break;
case ShaderLanguage::TYPE_UVEC2: {
Vector<int> iv = value;
int s = iv.size();
uint32_t *gui = (uint32_t *)data;
- const int *r = iv.ptr();
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+ int count = 2 * p_array_size;
- for (int i = 0; i < 2; i++) {
+ const int *r = iv.ptr();
+ for (int i = 0, j = 0; i < count; i += 2, j += 4) {
if (i < s) {
- gui[i] = r[i];
+ gui[j] = r[i];
+ gui[j + 1] = r[i + 1];
} else {
- gui[i] = 0;
+ gui[j] = 0;
+ gui[j + 1] = 0;
}
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
}
} break;
case ShaderLanguage::TYPE_UVEC3: {
@@ -1801,141 +1946,370 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
int s = iv.size();
uint32_t *gui = (uint32_t *)data;
- const int *r = iv.ptr();
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+ int count = 3 * p_array_size;
- for (int i = 0; i < 3; i++) {
+ const int *r = iv.ptr();
+ for (int i = 0, j = 0; i < count; i += 3, j += 4) {
if (i < s) {
- gui[i] = r[i];
+ gui[j] = r[i];
+ gui[j + 1] = r[i + 1];
+ gui[j + 2] = r[i + 2];
} else {
- gui[i] = 0;
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
}
+ gui[j + 3] = 0; // ignored
}
-
} break;
case ShaderLanguage::TYPE_UVEC4: {
Vector<int> iv = value;
int s = iv.size();
uint32_t *gui = (uint32_t *)data;
- const int *r = iv.ptr();
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+ int count = 4 * p_array_size;
- for (int i = 0; i < 4; i++) {
+ const int *r = iv.ptr();
+ for (int i = 0; i < count; i++) {
if (i < s) {
gui[i] = r[i];
+ gui[i + 1] = r[i + 1];
+ gui[i + 2] = r[i + 2];
+ gui[i + 3] = r[i + 3];
} else {
gui[i] = 0;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
}
}
} break;
case ShaderLanguage::TYPE_FLOAT: {
- float v = value;
float *gui = (float *)data;
- gui[0] = v;
+ if (p_array_size > 0) {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = a[i];
+ } else {
+ gui[j] = 0;
+ }
+ gui[j + 1] = 0; // ignored
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ float v = value;
+ gui[0] = v;
+ }
} break;
case ShaderLanguage::TYPE_VEC2: {
- Vector2 v = value;
float *gui = (float *)data;
- gui[0] = v.x;
- gui[1] = v.y;
+ if (p_array_size > 0) {
+ const PackedVector2Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = a[i].x;
+ gui[j + 1] = a[i].y;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ }
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ Vector2 v = value;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ }
} break;
case ShaderLanguage::TYPE_VEC3: {
- Vector3 v = value;
float *gui = (float *)data;
- gui[0] = v.x;
- gui[1] = v.y;
- gui[2] = v.z;
+ if (p_array_size > 0) {
+ const PackedVector3Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ gui[j] = a[i].x;
+ gui[j + 1] = a[i].y;
+ gui[j + 2] = a[i].z;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+ }
+ gui[j + 3] = 0; // ignored
+ }
+ } else {
+ Vector3 v = value;
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+ }
} break;
case ShaderLanguage::TYPE_VEC4: {
float *gui = (float *)data;
- if (value.get_type() == Variant::COLOR) {
- Color v = value;
+ if (p_array_size > 0) {
+ if (value.get_type() == Variant::PACKED_COLOR_ARRAY) {
+ const PackedColorArray &a = value;
+ int s = a.size();
- if (p_linear_color) {
- v = v.to_linear();
+ for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
+ if (i < s) {
+ Color color = a[i];
+ if (p_linear_color) {
+ color = color.to_linear();
+ }
+ gui[j] = color.r;
+ gui[j + 1] = color.g;
+ gui[j + 2] = color.b;
+ gui[j + 3] = color.a;
+ } else {
+ gui[j] = 0;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+ gui[j + 3] = 0;
+ }
+ }
+ } else {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+ int count = 4 * p_array_size;
+
+ for (int i = 0; i < count; i += 4) {
+ if (i + 3 < s) {
+ gui[i] = a[i];
+ gui[i + 1] = a[i + 1];
+ gui[i + 2] = a[i + 2];
+ gui[i + 3] = a[i + 3];
+ } else {
+ gui[i] = 0;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
+ }
+ }
}
+ } else {
+ if (value.get_type() == Variant::COLOR) {
+ Color v = value;
- gui[0] = v.r;
- gui[1] = v.g;
- gui[2] = v.b;
- gui[3] = v.a;
- } else if (value.get_type() == Variant::RECT2) {
- Rect2 v = value;
-
- gui[0] = v.position.x;
- gui[1] = v.position.y;
- gui[2] = v.size.x;
- gui[3] = v.size.y;
- } else if (value.get_type() == Variant::QUATERNION) {
- Quaternion v = value;
+ if (p_linear_color) {
+ v = v.to_linear();
+ }
- gui[0] = v.x;
- gui[1] = v.y;
- gui[2] = v.z;
- gui[3] = v.w;
- } else {
- Plane v = value;
+ gui[0] = v.r;
+ gui[1] = v.g;
+ gui[2] = v.b;
+ gui[3] = v.a;
+ } else if (value.get_type() == Variant::RECT2) {
+ Rect2 v = value;
+
+ gui[0] = v.position.x;
+ gui[1] = v.position.y;
+ gui[2] = v.size.x;
+ gui[3] = v.size.y;
+ } else if (value.get_type() == Variant::QUATERNION) {
+ Quaternion v = value;
+
+ gui[0] = v.x;
+ gui[1] = v.y;
+ gui[2] = v.z;
+ gui[3] = v.w;
+ } else {
+ Plane v = value;
- gui[0] = v.normal.x;
- gui[1] = v.normal.y;
- gui[2] = v.normal.z;
- gui[3] = v.d;
+ gui[0] = v.normal.x;
+ gui[1] = v.normal.y;
+ gui[2] = v.normal.z;
+ gui[3] = v.d;
+ }
}
} break;
case ShaderLanguage::TYPE_MAT2: {
- Transform2D v = value;
float *gui = (float *)data;
- //in std140 members of mat2 are treated as vec4s
- gui[0] = v.elements[0][0];
- gui[1] = v.elements[0][1];
- gui[2] = 0;
- gui[3] = 0;
- gui[4] = v.elements[1][0];
- gui[5] = v.elements[1][1];
- gui[6] = 0;
- gui[7] = 0;
+ if (p_array_size > 0) {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size * 4; i += 4, j += 8) {
+ if (i + 3 < s) {
+ gui[j] = a[i];
+ gui[j + 1] = a[i + 1];
+
+ gui[j + 4] = a[i + 2];
+ gui[j + 5] = a[i + 3];
+ } else {
+ gui[j] = 1;
+ gui[j + 1] = 0;
+
+ gui[j + 4] = 0;
+ gui[j + 5] = 1;
+ }
+ gui[j + 2] = 0; // ignored
+ gui[j + 3] = 0; // ignored
+ gui[j + 6] = 0; // ignored
+ gui[j + 7] = 0; // ignored
+ }
+ } else {
+ Transform2D v = value;
+
+ //in std140 members of mat2 are treated as vec4s
+ gui[0] = v.elements[0][0];
+ gui[1] = v.elements[0][1];
+ gui[2] = 0; // ignored
+ gui[3] = 0; // ignored
+
+ gui[4] = v.elements[1][0];
+ gui[5] = v.elements[1][1];
+ gui[6] = 0; // ignored
+ gui[7] = 0; // ignored
+ }
} break;
case ShaderLanguage::TYPE_MAT3: {
- Basis v = value;
float *gui = (float *)data;
- gui[0] = v.elements[0][0];
- gui[1] = v.elements[1][0];
- gui[2] = v.elements[2][0];
- gui[3] = 0;
- gui[4] = v.elements[0][1];
- gui[5] = v.elements[1][1];
- gui[6] = v.elements[2][1];
- gui[7] = 0;
- gui[8] = v.elements[0][2];
- gui[9] = v.elements[1][2];
- gui[10] = v.elements[2][2];
- gui[11] = 0;
+ if (p_array_size > 0) {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+
+ for (int i = 0, j = 0; i < p_array_size * 9; i += 9, j += 12) {
+ if (i + 8 < s) {
+ gui[j] = a[i];
+ gui[j + 1] = a[i + 1];
+ gui[j + 2] = a[i + 2];
+
+ gui[j + 4] = a[i + 3];
+ gui[j + 5] = a[i + 4];
+ gui[j + 6] = a[i + 5];
+
+ gui[j + 8] = a[i + 6];
+ gui[j + 9] = a[i + 7];
+ gui[j + 10] = a[i + 8];
+ } else {
+ gui[j] = 1;
+ gui[j + 1] = 0;
+ gui[j + 2] = 0;
+
+ gui[j + 4] = 0;
+ gui[j + 5] = 1;
+ gui[j + 6] = 0;
+
+ gui[j + 8] = 0;
+ gui[j + 9] = 0;
+ gui[j + 10] = 1;
+ }
+ gui[j + 3] = 0; // ignored
+ gui[j + 7] = 0; // ignored
+ gui[j + 11] = 0; // ignored
+ }
+ } else {
+ Basis v = value;
+ gui[0] = v.elements[0][0];
+ gui[1] = v.elements[1][0];
+ gui[2] = v.elements[2][0];
+ gui[3] = 0; // ignored
+
+ gui[4] = v.elements[0][1];
+ gui[5] = v.elements[1][1];
+ gui[6] = v.elements[2][1];
+ gui[7] = 0; // ignored
+
+ gui[8] = v.elements[0][2];
+ gui[9] = v.elements[1][2];
+ gui[10] = v.elements[2][2];
+ gui[11] = 0; // ignored
+ }
} break;
case ShaderLanguage::TYPE_MAT4: {
- Transform3D v = value;
float *gui = (float *)data;
- gui[0] = v.basis.elements[0][0];
- gui[1] = v.basis.elements[1][0];
- gui[2] = v.basis.elements[2][0];
- gui[3] = 0;
- gui[4] = v.basis.elements[0][1];
- gui[5] = v.basis.elements[1][1];
- gui[6] = v.basis.elements[2][1];
- gui[7] = 0;
- gui[8] = v.basis.elements[0][2];
- gui[9] = v.basis.elements[1][2];
- gui[10] = v.basis.elements[2][2];
- gui[11] = 0;
- gui[12] = v.origin.x;
- gui[13] = v.origin.y;
- gui[14] = v.origin.z;
- gui[15] = 1;
+ if (p_array_size > 0) {
+ const PackedFloat32Array &a = value;
+ int s = a.size();
+
+ for (int i = 0; i < p_array_size * 16; i += 16) {
+ if (i + 15 < s) {
+ gui[i] = a[i];
+ gui[i + 1] = a[i + 1];
+ gui[i + 2] = a[i + 2];
+ gui[i + 3] = a[i + 3];
+
+ gui[i + 4] = a[i + 4];
+ gui[i + 5] = a[i + 5];
+ gui[i + 6] = a[i + 6];
+ gui[i + 7] = a[i + 7];
+
+ gui[i + 8] = a[i + 8];
+ gui[i + 9] = a[i + 9];
+ gui[i + 10] = a[i + 10];
+ gui[i + 11] = a[i + 11];
+
+ gui[i + 12] = a[i + 12];
+ gui[i + 13] = a[i + 13];
+ gui[i + 14] = a[i + 14];
+ gui[i + 15] = a[i + 15];
+ } else {
+ gui[i] = 1;
+ gui[i + 1] = 0;
+ gui[i + 2] = 0;
+ gui[i + 3] = 0;
+
+ gui[i + 4] = 0;
+ gui[i + 5] = 1;
+ gui[i + 6] = 0;
+ gui[i + 7] = 0;
+
+ gui[i + 8] = 0;
+ gui[i + 9] = 0;
+ gui[i + 10] = 1;
+ gui[i + 11] = 0;
+
+ gui[i + 12] = 0;
+ gui[i + 13] = 0;
+ gui[i + 14] = 0;
+ gui[i + 15] = 1;
+ }
+ }
+ } else {
+ Transform3D v = value;
+ gui[0] = v.basis.elements[0][0];
+ gui[1] = v.basis.elements[1][0];
+ gui[2] = v.basis.elements[2][0];
+ gui[3] = 0;
+
+ gui[4] = v.basis.elements[0][1];
+ gui[5] = v.basis.elements[1][1];
+ gui[6] = v.basis.elements[2][1];
+ gui[7] = 0;
+
+ gui[8] = v.basis.elements[0][2];
+ gui[9] = v.basis.elements[1][2];
+ gui[10] = v.basis.elements[2][2];
+ gui[11] = 0;
+
+ gui[12] = v.origin.x;
+ gui[13] = v.origin.y;
+ gui[14] = v.origin.z;
+ gui[15] = 1;
+ }
} break;
default: {
}
@@ -2094,19 +2468,23 @@ _FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type,
}
}
-_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, uint8_t *data) {
+_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, int p_array_size, uint8_t *data) {
+ if (p_array_size <= 0) {
+ p_array_size = 1;
+ }
+
switch (type) {
case ShaderLanguage::TYPE_BOOL:
case ShaderLanguage::TYPE_INT:
case ShaderLanguage::TYPE_UINT:
case ShaderLanguage::TYPE_FLOAT: {
- memset(data, 0, 4);
+ memset(data, 0, 4 * p_array_size);
} break;
case ShaderLanguage::TYPE_BVEC2:
case ShaderLanguage::TYPE_IVEC2:
case ShaderLanguage::TYPE_UVEC2:
case ShaderLanguage::TYPE_VEC2: {
- memset(data, 0, 8);
+ memset(data, 0, 8 * p_array_size);
} break;
case ShaderLanguage::TYPE_BVEC3:
case ShaderLanguage::TYPE_IVEC3:
@@ -2116,16 +2494,16 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
case ShaderLanguage::TYPE_IVEC4:
case ShaderLanguage::TYPE_UVEC4:
case ShaderLanguage::TYPE_VEC4: {
- memset(data, 0, 16);
+ memset(data, 0, 16 * p_array_size);
} break;
case ShaderLanguage::TYPE_MAT2: {
- memset(data, 0, 32);
+ memset(data, 0, 32 * p_array_size);
} break;
case ShaderLanguage::TYPE_MAT3: {
- memset(data, 0, 48);
+ memset(data, 0, 48 * p_array_size);
} break;
case ShaderLanguage::TYPE_MAT4: {
- memset(data, 0, 64);
+ memset(data, 0, 64 * p_array_size);
} break;
default: {
@@ -2175,7 +2553,7 @@ void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName
if (V) {
//user provided
- _fill_std140_variant_ubo_value(E.value.type, V->get(), data, p_use_linear_color);
+ _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, V->get(), data, p_use_linear_color);
} else if (E.value.default_value.size()) {
//default value
@@ -2185,10 +2563,10 @@ void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName
//zero because it was not provided
if (E.value.type == ShaderLanguage::TYPE_VEC4 && E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
//colors must be set as black, with alpha as 1.0
- _fill_std140_variant_ubo_value(E.value.type, Color(0, 0, 0, 1), data, p_use_linear_color);
+ _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, Color(0, 0, 0, 1), data, p_use_linear_color);
} else {
//else just zero it out
- _fill_std140_ubo_empty(E.value.type, data);
+ _fill_std140_ubo_empty(E.value.type, E.value.array_size, data);
}
}
}
@@ -2241,10 +2619,11 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari
bool uses_global_textures = false;
global_textures_pass++;
- for (int i = 0; i < p_texture_uniforms.size(); i++) {
+ for (int i = 0, k = 0; i < p_texture_uniforms.size(); i++) {
const StringName &uniform_name = p_texture_uniforms[i].name;
+ int uniform_array_size = p_texture_uniforms[i].array_size;
- RID texture;
+ Vector<RID> textures;
if (p_texture_uniforms[i].global) {
RendererStorageRD *rs = base_singleton;
@@ -2265,31 +2644,51 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari
E->get() = global_textures_pass;
}
- texture = v->override.get_type() != Variant::NIL ? v->override : v->value;
+ textures.push_back(v->override.get_type() != Variant::NIL ? v->override : v->value);
}
} else {
WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it was removed at some point. Material will not display correctly.");
}
} else {
- if (!texture.is_valid()) {
- const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name);
- if (V) {
- texture = V->get();
+ const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name);
+ if (V) {
+ if (V->get().is_array()) {
+ Array array = (Array)V->get();
+ if (uniform_array_size > 0) {
+ for (int j = 0; j < array.size(); j++) {
+ textures.push_back(array[j]);
+ }
+ } else {
+ if (array.size() > 0) {
+ textures.push_back(array[0]);
+ }
+ }
+ } else {
+ textures.push_back(V->get());
}
}
- if (!texture.is_valid()) {
+ if (uniform_array_size > 0) {
+ if (textures.size() < uniform_array_size) {
+ const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name);
+ if (W) {
+ for (int j = textures.size(); j < uniform_array_size; j++) {
+ textures.push_back(W->get());
+ }
+ }
+ }
+ } else if (textures.is_empty()) {
const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name);
if (W) {
- texture = W->get();
+ textures.push_back(W->get());
}
}
}
RID rd_texture;
- if (texture.is_null()) {
+ if (textures.is_empty()) {
//check default usage
switch (p_texture_uniforms[i].hint) {
case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK:
@@ -2306,45 +2705,56 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari
rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
} break;
}
+#ifdef TOOLS_ENABLED
+ if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) {
+ roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel);
+ }
+#endif
+ if (uniform_array_size > 0) {
+ for (int j = 0; j < uniform_array_size; j++) {
+ p_textures[k++] = rd_texture;
+ }
+ } else {
+ p_textures[k] = rd_texture;
+ ++k;
+ }
} else {
bool srgb = p_use_linear_color && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO);
- Texture *tex = singleton->texture_owner.get_or_null(texture);
+ for (int j = 0; j < textures.size(); j++) {
+ Texture *tex = singleton->texture_owner.get_or_null(textures[j]);
- if (tex) {
- rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture;
+ if (tex) {
+ rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture;
#ifdef TOOLS_ENABLED
- if (tex->detect_3d_callback && p_use_linear_color) {
- tex->detect_3d_callback(tex->detect_3d_callback_ud);
- }
- if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) {
- if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL) {
- normal_detect_texture = tex;
+ if (tex->detect_3d_callback && p_use_linear_color) {
+ tex->detect_3d_callback(tex->detect_3d_callback_ud);
+ }
+ if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) {
+ if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL) {
+ normal_detect_texture = tex;
+ }
+ tex->detect_normal_callback(tex->detect_normal_callback_ud);
+ }
+ if (tex->detect_roughness_callback && (p_texture_uniforms[i].hint >= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R || p_texture_uniforms[i].hint <= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_GRAY)) {
+ //find the normal texture
+ roughness_detect_texture = tex;
+ roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R);
}
- tex->detect_normal_callback(tex->detect_normal_callback_ud);
+#endif
}
- if (tex->detect_roughness_callback && (p_texture_uniforms[i].hint >= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R || p_texture_uniforms[i].hint <= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_GRAY)) {
- //find the normal texture
- roughness_detect_texture = tex;
- roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R);
+ if (rd_texture.is_null()) {
+ rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+ }
+#ifdef TOOLS_ENABLED
+ if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) {
+ roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel);
}
-
#endif
- }
-
- if (rd_texture.is_null()) {
- //wtf
- rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE);
+ p_textures[k++] = rd_texture;
}
}
-
- p_textures[i] = rd_texture;
- }
-#ifdef TOOLS_ENABLED
- if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) {
- roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel);
}
-#endif
{
//for textures no longer used, unregister them
List<Map<StringName, uint64_t>::Element *> to_delete;
@@ -2412,7 +2822,10 @@ bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<St
RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), p_barrier);
}
- uint32_t tex_uniform_count = p_texture_uniforms.size();
+ uint32_t tex_uniform_count = 0U;
+ for (int i = 0; i < p_texture_uniforms.size(); i++) {
+ tex_uniform_count += uint32_t(p_texture_uniforms[i].array_size > 0 ? p_texture_uniforms[i].array_size : 1);
+ }
if ((uint32_t)texture_cache.size() != tex_uniform_count || p_textures_dirty) {
texture_cache.resize(tex_uniform_count);
@@ -2452,11 +2865,19 @@ bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<St
}
const RID *textures = texture_cache.ptrw();
- for (uint32_t i = 0; i < tex_uniform_count; i++) {
+ for (int i = 0, k = 0; i < p_texture_uniforms.size(); i++) {
+ const int array_size = p_texture_uniforms[i].array_size;
+
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 1 + i;
- u.ids.push_back(textures[i]);
+ u.binding = 1 + k;
+ if (array_size > 0) {
+ for (int j = 0; j < array_size; j++) {
+ u.ids.push_back(textures[k++]);
+ }
+ } else {
+ u.ids.push_back(textures[k++]);
+ }
uniforms.push_back(u);
}
}
@@ -5327,7 +5748,7 @@ void RendererStorageRD::ParticlesShaderData::get_instance_param_list(List<Render
p.info = ShaderLanguage::uniform_to_property_info(E.value);
p.info.name = E.key; //supply name
p.index = E.value.instance_index;
- p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.hint);
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
p_param_list->push_back(p);
}
}
@@ -5352,7 +5773,7 @@ Variant RendererStorageRD::ParticlesShaderData::get_default_parameter(const Stri
if (uniforms.has(p_parameter)) {
ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
- return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint);
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
}
return Variant();
}
@@ -8551,7 +8972,7 @@ void RendererStorageRD::global_variables_instance_update(RID p_instance, int p_i
pos += p_index;
- _fill_std140_variant_ubo_value(datatype, p_value, (uint8_t *)&global_variables.buffer_values[pos], true); //instances always use linear color in this renderer
+ _fill_std140_variant_ubo_value(datatype, 0, p_value, (uint8_t *)&global_variables.buffer_values[pos], true); //instances always use linear color in this renderer
_global_variable_mark_buffer_dirty(pos, 1);
}
diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
index cddb679eba..2f4671785a 100644
--- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp
@@ -91,7 +91,7 @@ static int _get_datatype_size(SL::DataType p_type) {
case SL::TYPE_VEC4:
return 16;
case SL::TYPE_MAT2:
- return 32; //4 * 4 + 4 * 4
+ return 32; // 4 * 4 + 4 * 4
case SL::TYPE_MAT3:
return 48; // 4 * 4 + 4 * 4 + 4 * 4
case SL::TYPE_MAT4:
@@ -608,7 +608,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
continue; // Instances are indexed directly, don't need index uniforms.
}
if (SL::is_sampler_type(uniform.type)) {
- ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_order) + ") uniform ";
+ ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_binding) + ") uniform ";
}
bool is_buffer_global = !SL::is_sampler_type(uniform.type) && uniform.scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL;
@@ -622,6 +622,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
}
ucode += " " + _mkid(uniform_name);
+ if (uniform.array_size > 0) {
+ ucode += "[";
+ ucode += itos(uniform.array_size);
+ ucode += "]";
+ }
ucode += ";\n";
if (SL::is_sampler_type(uniform.type)) {
for (int j = 0; j < STAGE_MAX; j++) {
@@ -635,6 +640,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
texture.filter = uniform.filter;
texture.repeat = uniform.repeat;
texture.global = uniform.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL;
+ texture.array_size = uniform.array_size;
if (texture.global) {
r_gen_code.uses_global_textures = true;
}
@@ -650,7 +656,16 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
uniform_sizes.write[uniform.order] = _get_datatype_size(ShaderLanguage::TYPE_UINT);
uniform_alignments.write[uniform.order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT);
} else {
- uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type);
+ if (uniform.array_size > 0) {
+ int size = _get_datatype_size(uniform.type) * uniform.array_size;
+ int m = (16 * uniform.array_size);
+ if ((size % m) != 0) {
+ size += m - (size % m);
+ }
+ uniform_sizes.write[uniform.order] = size;
+ } else {
+ uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type);
+ }
uniform_alignments.write[uniform.order] = _get_datatype_alignment(uniform.type);
}
}
@@ -1074,10 +1089,32 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
if (p_default_actions.renames.has(anode->name)) {
code = p_default_actions.renames[anode->name];
} else {
- if (use_fragment_varying) {
- code = "frag_to_light.";
+ if (shader->uniforms.has(anode->name)) {
+ //its a uniform!
+ const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[anode->name];
+ if (u.texture_order >= 0) {
+ code = _mkid(anode->name); //texture, use as is
+ } else {
+ //a scalar or vector
+ if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
+ code = actions.base_uniform_string + _mkid(anode->name); //texture, use as is
+ //global variable, this means the code points to an index to the global table
+ code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type);
+ } else if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ //instance variable, index it as such
+ code = "(" + p_default_actions.instance_uniform_index_variable + "+" + itos(u.instance_index) + ")";
+ code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type);
+ } else {
+ //regular uniform, index from UBO
+ code = actions.base_uniform_string + _mkid(anode->name);
+ }
+ }
+ } else {
+ if (use_fragment_varying) {
+ code = "frag_to_light.";
+ }
+ code += _mkid(anode->name);
}
- code += _mkid(anode->name);
}
if (anode->call_expression != nullptr) {
@@ -1193,46 +1230,63 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge
code += ", ";
}
String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- if (is_texture_func && i == 1 && onode->arguments[i]->type == SL::Node::TYPE_VARIABLE) {
+ if (is_texture_func && i == 1 && (onode->arguments[i]->type == SL::Node::TYPE_VARIABLE || onode->arguments[i]->type == SL::Node::TYPE_OPERATOR)) {
//need to map from texture to sampler in order to sample
- const SL::VariableNode *varnode = static_cast<const SL::VariableNode *>(onode->arguments[i]);
+ StringName texture_uniform;
+ bool correct_texture_uniform = false;
+
+ if (onode->arguments[i]->type == SL::Node::TYPE_VARIABLE) {
+ const SL::VariableNode *varnode = static_cast<const SL::VariableNode *>(onode->arguments[i]);
+ texture_uniform = varnode->name;
+ correct_texture_uniform = true;
+ } else { // array indexing operator handling
+ const SL::OperatorNode *opnode = static_cast<const SL::OperatorNode *>(onode->arguments[i]);
+ if (opnode->op == SL::Operator::OP_INDEX && opnode->arguments[0]->type == SL::Node::TYPE_ARRAY) {
+ const SL::ArrayNode *anode = static_cast<const SL::ArrayNode *>(opnode->arguments[0]);
+ texture_uniform = anode->name;
+ correct_texture_uniform = true;
+ }
+ }
- StringName texture_uniform = varnode->name;
- is_screen_texture = (texture_uniform == "SCREEN_TEXTURE");
+ if (correct_texture_uniform) {
+ is_screen_texture = (texture_uniform == "SCREEN_TEXTURE");
- String sampler_name;
+ String sampler_name;
- if (actions.custom_samplers.has(texture_uniform)) {
- sampler_name = actions.custom_samplers[texture_uniform];
- } else {
- if (shader->uniforms.has(texture_uniform)) {
- sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat);
+ if (actions.custom_samplers.has(texture_uniform)) {
+ sampler_name = actions.custom_samplers[texture_uniform];
} else {
- bool found = false;
-
- for (int j = 0; j < function->arguments.size(); j++) {
- if (function->arguments[j].name == texture_uniform) {
- if (function->arguments[j].tex_builtin_check) {
- ERR_CONTINUE(!actions.custom_samplers.has(function->arguments[j].tex_builtin));
- sampler_name = actions.custom_samplers[function->arguments[j].tex_builtin];
- found = true;
- break;
- }
- if (function->arguments[j].tex_argument_check) {
- sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat);
- found = true;
- break;
+ if (shader->uniforms.has(texture_uniform)) {
+ sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat);
+ } else {
+ bool found = false;
+
+ for (int j = 0; j < function->arguments.size(); j++) {
+ if (function->arguments[j].name == texture_uniform) {
+ if (function->arguments[j].tex_builtin_check) {
+ ERR_CONTINUE(!actions.custom_samplers.has(function->arguments[j].tex_builtin));
+ sampler_name = actions.custom_samplers[function->arguments[j].tex_builtin];
+ found = true;
+ break;
+ }
+ if (function->arguments[j].tex_argument_check) {
+ sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat);
+ found = true;
+ break;
+ }
}
}
- }
- if (!found) {
- //function was most likely unused, so use anything (compiler will remove it anyway)
- sampler_name = _get_sampler_name(ShaderLanguage::FILTER_DEFAULT, ShaderLanguage::REPEAT_DEFAULT);
+ if (!found) {
+ //function was most likely unused, so use anything (compiler will remove it anyway)
+ sampler_name = _get_sampler_name(ShaderLanguage::FILTER_DEFAULT, ShaderLanguage::REPEAT_DEFAULT);
+ }
}
}
- }
- code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")";
+ code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")";
+ } else {
+ code += node_code;
+ }
} else {
code += node_code;
}
diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.h b/servers/rendering/renderer_rd/shader_compiler_rd.h
index 0fe9047967..2ab689c27c 100644
--- a/servers/rendering/renderer_rd/shader_compiler_rd.h
+++ b/servers/rendering/renderer_rd/shader_compiler_rd.h
@@ -65,6 +65,7 @@ public:
ShaderLanguage::TextureFilter filter;
ShaderLanguage::TextureRepeat repeat;
bool global;
+ int array_size;
};
Vector<Texture> texture_uniforms;
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index f960d4af5f..c887195d1c 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -1078,6 +1078,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea
if (r_data_type) {
*r_data_type = shader->uniforms[p_identifier].type;
}
+ if (r_array_size) {
+ *r_array_size = shader->uniforms[p_identifier].array_size;
+ }
if (r_type) {
*r_type = IDENTIFIER_UNIFORM;
}
@@ -2921,86 +2924,294 @@ bool ShaderLanguage::is_sampler_type(DataType p_type) {
p_type == TYPE_SAMPLERCUBEARRAY;
}
-Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) {
+Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) {
+ int array_size = p_array_size;
+
if (p_value.size() > 0) {
Variant value;
switch (p_type) {
case ShaderLanguage::TYPE_BOOL:
- value = Variant(p_value[0].boolean);
+ if (array_size > 0) {
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].boolean);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].boolean);
+ }
break;
case ShaderLanguage::TYPE_BVEC2:
+ array_size *= 2;
+
+ if (array_size > 0) {
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].boolean);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].boolean);
+ }
+ break;
case ShaderLanguage::TYPE_BVEC3:
+ array_size *= 3;
+
+ if (array_size > 0) {
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].boolean);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].boolean);
+ }
+ break;
case ShaderLanguage::TYPE_BVEC4:
+ array_size *= 4;
+
+ if (array_size > 0) {
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].boolean);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].boolean);
+ }
+ break;
case ShaderLanguage::TYPE_INT:
- value = Variant(p_value[0].sint);
+ if (array_size > 0) {
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].sint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].sint);
+ }
break;
case ShaderLanguage::TYPE_IVEC2:
- value = Variant(Vector2(p_value[0].sint, p_value[1].sint));
+ if (array_size > 0) {
+ array_size *= 2;
+
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].sint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Vector2(p_value[0].sint, p_value[1].sint));
+ }
break;
case ShaderLanguage::TYPE_IVEC3:
- value = Variant(Vector3(p_value[0].sint, p_value[1].sint, p_value[2].sint));
+ if (array_size > 0) {
+ array_size *= 3;
+
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].sint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Vector3(p_value[0].sint, p_value[1].sint, p_value[2].sint));
+ }
break;
case ShaderLanguage::TYPE_IVEC4:
- value = Variant(Plane(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint));
+ if (array_size > 0) {
+ array_size *= 4;
+
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].sint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Plane(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint));
+ }
break;
case ShaderLanguage::TYPE_UINT:
- value = Variant(p_value[0].uint);
+ if (array_size > 0) {
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].uint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].uint);
+ }
break;
case ShaderLanguage::TYPE_UVEC2:
- value = Variant(Vector2(p_value[0].uint, p_value[1].uint));
+ if (array_size > 0) {
+ array_size *= 2;
+
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].uint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Vector2(p_value[0].uint, p_value[1].uint));
+ }
break;
case ShaderLanguage::TYPE_UVEC3:
- value = Variant(Vector3(p_value[0].uint, p_value[1].uint, p_value[2].uint));
+ if (array_size > 0) {
+ array_size *= 3;
+
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].uint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Vector3(p_value[0].uint, p_value[1].uint, p_value[2].uint));
+ }
break;
case ShaderLanguage::TYPE_UVEC4:
- value = Variant(Plane(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint));
+ if (array_size > 0) {
+ array_size *= 4;
+
+ PackedInt32Array array = PackedInt32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].uint);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Plane(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint));
+ }
break;
case ShaderLanguage::TYPE_FLOAT:
- value = Variant(p_value[0].real);
+ if (array_size > 0) {
+ PackedFloat32Array array = PackedFloat32Array();
+ for (int i = 0; i < array_size; i++) {
+ array.push_back(p_value[i].real);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(p_value[0].real);
+ }
break;
case ShaderLanguage::TYPE_VEC2:
- value = Variant(Vector2(p_value[0].real, p_value[1].real));
+ if (array_size > 0) {
+ array_size *= 2;
+
+ PackedVector2Array array = PackedVector2Array();
+ for (int i = 0; i < array_size; i += 2) {
+ array.push_back(Vector2(p_value[i].real, p_value[i + 1].real));
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Vector2(p_value[0].real, p_value[1].real));
+ }
break;
case ShaderLanguage::TYPE_VEC3:
- value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real));
+ if (array_size > 0) {
+ array_size *= 3;
+
+ PackedVector3Array array = PackedVector3Array();
+ for (int i = 0; i < array_size; i += 3) {
+ array.push_back(Vector3(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real));
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real));
+ }
break;
case ShaderLanguage::TYPE_VEC4:
- if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
- value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
+ if (array_size > 0) {
+ array_size *= 4;
+
+ if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ PackedColorArray array = PackedColorArray();
+ for (int i = 0; i < array_size; i += 4) {
+ array.push_back(Color(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real, p_value[i + 3].real));
+ }
+ value = Variant(array);
+ } else {
+ PackedFloat32Array array = PackedFloat32Array();
+ for (int i = 0; i < array_size; i += 4) {
+ array.push_back(p_value[i].real);
+ array.push_back(p_value[i + 1].real);
+ array.push_back(p_value[i + 2].real);
+ array.push_back(p_value[i + 3].real);
+ }
+ value = Variant(array);
+ }
} else {
- value = Variant(Plane(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
+ if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ value = Variant(Color(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
+ } else {
+ value = Variant(Plane(p_value[0].real, p_value[1].real, p_value[2].real, p_value[3].real));
+ }
}
break;
case ShaderLanguage::TYPE_MAT2:
- value = Variant(Transform2D(p_value[0].real, p_value[2].real, p_value[1].real, p_value[3].real, 0.0, 0.0));
+ if (array_size > 0) {
+ array_size *= 4;
+
+ PackedFloat32Array array = PackedFloat32Array();
+ for (int i = 0; i < array_size; i += 4) {
+ array.push_back(p_value[i].real);
+ array.push_back(p_value[i + 1].real);
+ array.push_back(p_value[i + 2].real);
+ array.push_back(p_value[i + 3].real);
+ }
+ value = Variant(array);
+ } else {
+ value = Variant(Transform2D(p_value[0].real, p_value[2].real, p_value[1].real, p_value[3].real, 0.0, 0.0));
+ }
break;
case ShaderLanguage::TYPE_MAT3: {
- Basis p;
- p[0][0] = p_value[0].real;
- p[0][1] = p_value[1].real;
- p[0][2] = p_value[2].real;
- p[1][0] = p_value[3].real;
- p[1][1] = p_value[4].real;
- p[1][2] = p_value[5].real;
- p[2][0] = p_value[6].real;
- p[2][1] = p_value[7].real;
- p[2][2] = p_value[8].real;
- value = Variant(p);
+ if (array_size > 0) {
+ array_size *= 9;
+
+ PackedFloat32Array array = PackedFloat32Array();
+ for (int i = 0; i < array_size; i += 9) {
+ for (int j = 0; j < 9; j++) {
+ array.push_back(p_value[i + j].real);
+ }
+ }
+ value = Variant(array);
+ } else {
+ Basis p;
+ p[0][0] = p_value[0].real;
+ p[0][1] = p_value[1].real;
+ p[0][2] = p_value[2].real;
+ p[1][0] = p_value[3].real;
+ p[1][1] = p_value[4].real;
+ p[1][2] = p_value[5].real;
+ p[2][0] = p_value[6].real;
+ p[2][1] = p_value[7].real;
+ p[2][2] = p_value[8].real;
+ value = Variant(p);
+ }
break;
}
case ShaderLanguage::TYPE_MAT4: {
- Basis p;
- p[0][0] = p_value[0].real;
- p[0][1] = p_value[1].real;
- p[0][2] = p_value[2].real;
- p[1][0] = p_value[4].real;
- p[1][1] = p_value[5].real;
- p[1][2] = p_value[6].real;
- p[2][0] = p_value[8].real;
- p[2][1] = p_value[9].real;
- p[2][2] = p_value[10].real;
- Transform3D t = Transform3D(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real));
- value = Variant(t);
+ if (array_size > 0) {
+ array_size *= 16;
+
+ PackedFloat32Array array = PackedFloat32Array();
+ for (int i = 0; i < array_size; i += 16) {
+ for (int j = 0; j < 16; j++) {
+ array.push_back(p_value[i + j].real);
+ }
+ }
+ value = Variant(array);
+ } else {
+ Basis p;
+ p[0][0] = p_value[0].real;
+ p[0][1] = p_value[1].real;
+ p[0][2] = p_value[2].real;
+ p[1][0] = p_value[4].real;
+ p[1][1] = p_value[5].real;
+ p[1][2] = p_value[6].real;
+ p[2][0] = p_value[8].real;
+ p[2][1] = p_value[9].real;
+ p[2][2] = p_value[10].real;
+ Transform3D t = Transform3D(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real));
+ value = Variant(t);
+ }
break;
}
case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
@@ -3036,31 +3247,50 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform
pi.type = Variant::NIL;
break;
case ShaderLanguage::TYPE_BOOL:
- pi.type = Variant::BOOL;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_INT32_ARRAY;
+ } else {
+ pi.type = Variant::BOOL;
+ }
break;
case ShaderLanguage::TYPE_BVEC2:
- pi.type = Variant::INT;
- pi.hint = PROPERTY_HINT_FLAGS;
- pi.hint_string = "x,y";
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_INT32_ARRAY;
+ } else {
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_FLAGS;
+ pi.hint_string = "x,y";
+ }
break;
case ShaderLanguage::TYPE_BVEC3:
- pi.type = Variant::INT;
- pi.hint = PROPERTY_HINT_FLAGS;
- pi.hint_string = "x,y,z";
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_INT32_ARRAY;
+ } else {
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_FLAGS;
+ pi.hint_string = "x,y,z";
+ }
break;
case ShaderLanguage::TYPE_BVEC4:
- pi.type = Variant::INT;
- pi.hint = PROPERTY_HINT_FLAGS;
- pi.hint_string = "x,y,z,w";
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_INT32_ARRAY;
+ } else {
+ pi.type = Variant::INT;
+ pi.hint = PROPERTY_HINT_FLAGS;
+ pi.hint_string = "x,y,z,w";
+ }
break;
case ShaderLanguage::TYPE_UINT:
case ShaderLanguage::TYPE_INT: {
- pi.type = Variant::INT;
- if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
- pi.hint = PROPERTY_HINT_RANGE;
- pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_INT32_ARRAY;
+ } else {
+ pi.type = Variant::INT;
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
+ pi.hint = PROPERTY_HINT_RANGE;
+ pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
+ }
}
-
} break;
case ShaderLanguage::TYPE_IVEC2:
case ShaderLanguage::TYPE_IVEC3:
@@ -3071,59 +3301,106 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform
pi.type = Variant::PACKED_INT32_ARRAY;
} break;
case ShaderLanguage::TYPE_FLOAT: {
- pi.type = Variant::FLOAT;
- if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
- pi.hint = PROPERTY_HINT_RANGE;
- pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_FLOAT32_ARRAY;
+ } else {
+ pi.type = Variant::FLOAT;
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) {
+ pi.hint = PROPERTY_HINT_RANGE;
+ pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]);
+ }
}
-
} break;
case ShaderLanguage::TYPE_VEC2:
- pi.type = Variant::VECTOR2;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_VECTOR2_ARRAY;
+ } else {
+ pi.type = Variant::VECTOR2;
+ }
break;
case ShaderLanguage::TYPE_VEC3:
- pi.type = Variant::VECTOR3;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_VECTOR3_ARRAY;
+ } else {
+ pi.type = Variant::VECTOR3;
+ }
break;
case ShaderLanguage::TYPE_VEC4: {
- if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
- pi.type = Variant::COLOR;
+ if (p_uniform.array_size > 0) {
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ pi.type = Variant::PACKED_COLOR_ARRAY;
+ } else {
+ pi.type = Variant::PACKED_FLOAT32_ARRAY;
+ }
} else {
- pi.type = Variant::PLANE;
+ if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
+ pi.type = Variant::COLOR;
+ } else {
+ pi.type = Variant::PLANE;
+ }
}
} break;
case ShaderLanguage::TYPE_MAT2:
- pi.type = Variant::TRANSFORM2D;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_FLOAT32_ARRAY;
+ } else {
+ pi.type = Variant::TRANSFORM2D;
+ }
break;
case ShaderLanguage::TYPE_MAT3:
- pi.type = Variant::BASIS;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_FLOAT32_ARRAY;
+ } else {
+ pi.type = Variant::BASIS;
+ }
break;
case ShaderLanguage::TYPE_MAT4:
- pi.type = Variant::TRANSFORM3D;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::PACKED_FLOAT32_ARRAY;
+ } else {
+ pi.type = Variant::TRANSFORM3D;
+ }
break;
case ShaderLanguage::TYPE_SAMPLER2D:
case ShaderLanguage::TYPE_ISAMPLER2D:
case ShaderLanguage::TYPE_USAMPLER2D: {
- pi.type = Variant::OBJECT;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::ARRAY;
+ } else {
+ pi.type = Variant::OBJECT;
+ }
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
pi.hint_string = "Texture2D";
} break;
case ShaderLanguage::TYPE_SAMPLER2DARRAY:
case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
case ShaderLanguage::TYPE_USAMPLER2DARRAY: {
- pi.type = Variant::OBJECT;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::ARRAY;
+ } else {
+ pi.type = Variant::OBJECT;
+ }
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
pi.hint_string = "TextureLayered";
} break;
case ShaderLanguage::TYPE_SAMPLER3D:
case ShaderLanguage::TYPE_ISAMPLER3D:
case ShaderLanguage::TYPE_USAMPLER3D: {
- pi.type = Variant::OBJECT;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::ARRAY;
+ } else {
+ pi.type = Variant::OBJECT;
+ }
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
pi.hint_string = "Texture3D";
} break;
case ShaderLanguage::TYPE_SAMPLERCUBE:
case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: {
- pi.type = Variant::OBJECT;
+ if (p_uniform.array_size > 0) {
+ pi.type = Variant::ARRAY;
+ } else {
+ pi.type = Variant::OBJECT;
+ }
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
pi.hint_string = "TextureLayered";
} break;
@@ -6694,6 +6971,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
int texture_uniforms = 0;
+ int texture_binding = 0;
int uniforms = 0;
int instance_index = 0;
ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
@@ -6903,6 +7181,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
}
+ bool precision_defined = false;
DataPrecision precision = PRECISION_DEFAULT;
DataInterpolation interpolation = INTERPOLATION_SMOOTH;
DataType type;
@@ -6911,15 +7190,34 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (is_token_interpolation(tk.type)) {
+ if (uniform) {
+ _set_error("Interpolation qualifiers are not supported for uniforms!");
+ return ERR_PARSE_ERROR;
+ }
interpolation = get_token_interpolation(tk.type);
tk = _get_token();
}
if (is_token_precision(tk.type)) {
precision = get_token_precision(tk.type);
+ precision_defined = true;
tk = _get_token();
}
+ if (shader->structs.has(tk.text)) {
+ if (uniform) {
+ if (precision_defined) {
+ _set_error("Precision modifier cannot be used on structs.");
+ return ERR_PARSE_ERROR;
+ }
+ _set_error("struct datatype is not yet supported for uniforms!");
+ return ERR_PARSE_ERROR;
+ } else {
+ _set_error("struct datatype not allowed here");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
if (!is_token_datatype(tk.type)) {
_set_error("Expected datatype. ");
return ERR_PARSE_ERROR;
@@ -6996,12 +7294,47 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
}
ShaderNode::Uniform uniform2;
+ uniform2.type = type;
+ uniform2.scope = uniform_scope;
+ uniform2.precision = precision;
+ uniform2.array_size = array_size;
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_OPEN) {
+ if (uniform2.array_size > 0) {
+ _set_error("Array size is already defined!");
+ return ERR_PARSE_ERROR;
+ }
+ tk = _get_token();
+
+ if (tk.type == TK_INT_CONSTANT && tk.constant > 0) {
+ uniform2.array_size = (int)tk.constant;
+
+ tk = _get_token();
+ if (tk.type == TK_BRACKET_CLOSE) {
+ tk = _get_token();
+ } else {
+ _set_error("Expected ']'");
+ return ERR_PARSE_ERROR;
+ }
+ } else {
+ _set_error("Expected integer constant > 0");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
if (is_sampler_type(type)) {
if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) {
_set_error("Uniforms with 'instance' qualifiers can't be of sampler type.");
return ERR_PARSE_ERROR;
}
uniform2.texture_order = texture_uniforms++;
+ uniform2.texture_binding = texture_binding;
+ if (uniform2.array_size > 0) {
+ texture_binding += uniform2.array_size;
+ } else {
+ ++texture_binding;
+ }
uniform2.order = -1;
if (_validate_datatype(type) != OK) {
return ERR_PARSE_ERROR;
@@ -7011,19 +7344,22 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
_set_error("Uniforms with 'instance' qualifiers can't be of matrix type.");
return ERR_PARSE_ERROR;
}
-
uniform2.texture_order = -1;
if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) {
uniform2.order = uniforms++;
}
}
- uniform2.type = type;
- uniform2.scope = uniform_scope;
- uniform2.precision = precision;
-
- //todo parse default value
- tk = _get_token();
+ if (uniform2.array_size > 0) {
+ if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) {
+ _set_error("'SCOPE_GLOBAL' qualifier is not yet supported for uniform array!");
+ return ERR_PARSE_ERROR;
+ }
+ if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) {
+ _set_error("'SCOPE_INSTANCE' qualifier is not yet supported for uniform array!");
+ return ERR_PARSE_ERROR;
+ }
+ }
int custom_instance_index = -1;
@@ -7031,6 +7367,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
//hint
do {
tk = _get_token();
+
+ if (uniform2.array_size > 0) {
+ if (tk.type != TK_HINT_COLOR) {
+ _set_error("This hint is not yet supported for uniform arrays!");
+ return ERR_PARSE_ERROR;
+ }
+ }
+
if (tk.type == TK_HINT_WHITE_TEXTURE) {
uniform2.hint = ShaderNode::Uniform::HINT_WHITE;
} else if (tk.type == TK_HINT_BLACK_TEXTURE) {
@@ -7221,6 +7565,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
//reset scope for next uniform
if (tk.type == TK_OP_ASSIGN) {
+ if (uniform2.array_size > 0) {
+ _set_error("Setting default value to a uniform array is not yet supported!");
+ return ERR_PARSE_ERROR;
+ }
+
Node *expr = _parse_and_reduce_expression(nullptr, FunctionInfo());
if (!expr) {
return ERR_PARSE_ERROR;
@@ -7265,7 +7614,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) {
- _set_error("Expected ';' or '['");
+ if (array_size == 0) {
+ _set_error("Expected ';' or '['");
+ } else {
+ _set_error("Expected ';'");
+ }
return ERR_PARSE_ERROR;
}
@@ -7290,7 +7643,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
} else {
- _set_error("Expected single integer constant > 0");
+ _set_error("Expected integer constant > 0");
return ERR_PARSE_ERROR;
}
}
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index 18525e054e..7908658028 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -692,8 +692,10 @@ public:
int order = 0;
int texture_order = 0;
+ int texture_binding = 0;
DataType type = TYPE_VOID;
DataPrecision precision = PRECISION_DEFAULT;
+ int array_size = 0;
Vector<ConstantNode::Value> default_value;
Scope scope = SCOPE_LOCAL;
Hint hint = HINT_NONE;
@@ -776,7 +778,7 @@ public:
static bool is_scalar_type(DataType p_type);
static bool is_float_type(DataType p_type);
static bool is_sampler_type(DataType p_type);
- static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
+ static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE);
static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform);
static uint32_t get_type_size(DataType p_type);
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 58e99f0e91..847f29f6ba 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -934,7 +934,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
}
}
- ERR_FAIL_COND_V((bsformat) != (format & (RS::ARRAY_FORMAT_INDEX - 1)), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V_MSG((bsformat) != (format & (ARRAY_FORMAT_VERTEX | ARRAY_FORMAT_NORMAL | ARRAY_FORMAT_TANGENT)), ERR_INVALID_PARAMETER, "Blend shape format must match the main array format for Vertex, Normal and Tangent arrays.");
}
}
diff --git a/tests/test_shader_lang.cpp b/tests/test_shader_lang.cpp
index 6d58eb63cc..5598852f29 100644
--- a/tests/test_shader_lang.cpp
+++ b/tests/test_shader_lang.cpp
@@ -125,23 +125,28 @@ static String dump_node_code(SL::Node *p_node, int p_level) {
ucode += _prestr(E.value.precision);
ucode += _typestr(E.value.type);
ucode += " " + String(E.key);
+ if (E.value.array_size > 0) {
+ ucode += "[";
+ ucode += itos(E.value.array_size);
+ ucode += "]";
+ } else {
+ if (E.value.default_value.size()) {
+ ucode += " = " + get_constant_text(E.value.type, E.value.default_value);
+ }
- if (E.value.default_value.size()) {
- ucode += " = " + get_constant_text(E.value.type, E.value.default_value);
- }
-
- static const char *hint_name[SL::ShaderNode::Uniform::HINT_MAX] = {
- "",
- "color",
- "range",
- "albedo",
- "normal",
- "black",
- "white"
- };
-
- if (E.value.hint) {
- ucode += " : " + String(hint_name[E.value.hint]);
+ static const char *hint_name[SL::ShaderNode::Uniform::HINT_MAX] = {
+ "",
+ "color",
+ "range",
+ "albedo",
+ "normal",
+ "black",
+ "white"
+ };
+
+ if (E.value.hint) {
+ ucode += " : " + String(hint_name[E.value.hint]);
+ }
}
code += ucode + "\n";
diff --git a/thirdparty/doctest/LICENSE.txt b/thirdparty/doctest/LICENSE.txt
index 50a358cd1b..d67bb64f9d 100644
--- a/thirdparty/doctest/LICENSE.txt
+++ b/thirdparty/doctest/LICENSE.txt
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2016-2020 Viktor Kirilov
+Copyright (c) 2016-2021 Viktor Kirilov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/thirdparty/doctest/doctest.h b/thirdparty/doctest/doctest.h
index 7712dd6b63..42eb039979 100644
--- a/thirdparty/doctest/doctest.h
+++ b/thirdparty/doctest/doctest.h
@@ -4,7 +4,7 @@
//
// doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD
//
-// Copyright (c) 2016-2020 Viktor Kirilov
+// Copyright (c) 2016-2021 Viktor Kirilov
//
// Distributed under the MIT Software License
// See accompanying file LICENSE.txt or copy at
@@ -48,8 +48,8 @@
#define DOCTEST_VERSION_MAJOR 2
#define DOCTEST_VERSION_MINOR 4
-#define DOCTEST_VERSION_PATCH 4
-#define DOCTEST_VERSION_STR "2.4.4"
+#define DOCTEST_VERSION_PATCH 6
+#define DOCTEST_VERSION_STR "2.4.6"
#define DOCTEST_VERSION \
(DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH)
@@ -354,7 +354,7 @@ DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum'
#define DOCTEST_GLOBAL_NO_WARNINGS(var) \
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wglobal-constructors") \
DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-variable") \
- static int var DOCTEST_UNUSED // NOLINT(fuchsia-statically-constructed-objects,cert-err58-cpp)
+ static const int var DOCTEST_UNUSED // NOLINT(fuchsia-statically-constructed-objects,cert-err58-cpp)
#define DOCTEST_GLOBAL_NO_WARNINGS_END() DOCTEST_CLANG_SUPPRESS_WARNING_POP
#ifndef DOCTEST_BREAK_INTO_DEBUGGER
@@ -362,16 +362,16 @@ DOCTEST_MSVC_SUPPRESS_WARNING(26812) // Prefer 'enum class' over 'enum'
#ifdef DOCTEST_PLATFORM_LINUX
#if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
// Break at the location of the failing check if possible
-#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :)
+#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT (hicpp-no-assembler)
#else
#include <signal.h>
#define DOCTEST_BREAK_INTO_DEBUGGER() raise(SIGTRAP)
#endif
#elif defined(DOCTEST_PLATFORM_MAC)
#if defined(__x86_64) || defined(__x86_64__) || defined(__amd64__) || defined(__i386)
-#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :)
+#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) // NOLINT (hicpp-no-assembler)
#else
-#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0");
+#define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("brk #0"); // NOLINT (hicpp-no-assembler)
#endif
#elif DOCTEST_MSVC
#define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak()
@@ -656,12 +656,14 @@ DOCTEST_INTERFACE const char* skipPathFromFilename(const char* file);
struct DOCTEST_INTERFACE TestCaseData
{
- String m_file; // the file in which the test was registered
+ String m_file; // the file in which the test was registered (using String - see #350)
unsigned m_line; // the line where the test was registered
const char* m_name; // name of the test case
const char* m_test_suite; // the test suite in which the test was added
const char* m_description;
bool m_skip;
+ bool m_no_breaks;
+ bool m_no_output;
bool m_may_fail;
bool m_should_fail;
int m_expected_failures;
@@ -715,12 +717,18 @@ struct DOCTEST_INTERFACE IContextScope
virtual void stringify(std::ostream*) const = 0;
};
+namespace detail {
+ struct DOCTEST_INTERFACE TestCase;
+} // namespace detail
+
struct ContextOptions //!OCLINT too many fields
{
std::ostream* cout; // stdout stream - std::cout by default
std::ostream* cerr; // stderr stream - std::cerr by default
String binary_name; // the test binary name
+ const detail::TestCase* currentTest = nullptr;
+
// == parameters from the command line
String out; // output filename
String order_by; // how tests should be ordered
@@ -773,6 +781,29 @@ namespace detail {
template<class T> struct remove_reference<T&> { typedef T type; };
template<class T> struct remove_reference<T&&> { typedef T type; };
+ template<typename T, typename U = T&&> U declval(int);
+
+ template<typename T> T declval(long);
+
+ template<typename T> auto declval() DOCTEST_NOEXCEPT -> decltype(declval<T>(0)) ;
+
+ template<class T> struct is_lvalue_reference { const static bool value=false; };
+ template<class T> struct is_lvalue_reference<T&> { const static bool value=true; };
+
+ template <class T>
+ inline T&& forward(typename remove_reference<T>::type& t) DOCTEST_NOEXCEPT
+ {
+ return static_cast<T&&>(t);
+ }
+
+ template <class T>
+ inline T&& forward(typename remove_reference<T>::type&& t) DOCTEST_NOEXCEPT
+ {
+ static_assert(!is_lvalue_reference<T>::value,
+ "Can not forward an rvalue as an lvalue.");
+ return static_cast<T&&>(t);
+ }
+
template<class T> struct remove_const { typedef T type; };
template<class T> struct remove_const<const T> { typedef T type; };
#ifdef DOCTEST_CONFIG_INCLUDE_TYPE_TRAITS
@@ -1040,10 +1071,20 @@ namespace detail {
return toString(lhs) + op + toString(rhs);
}
+#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0)
+DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wunused-comparison")
+#endif
+
+// This will check if there is any way it could find a operator like member or friend and uses it.
+// If not it doesn't find the operator or if the operator at global scope is defined after
+// this template, the template won't be instantiated due to SFINAE. Once the template is not
+// instantiated it can look for global operator using normal conversions.
+#define SFINAE_OP(ret,op) decltype(doctest::detail::declval<L>() op doctest::detail::declval<R>(),static_cast<ret>(0))
+
#define DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(op, op_str, op_macro) \
template <typename R> \
- DOCTEST_NOINLINE Result operator op(const DOCTEST_REF_WRAP(R) rhs) { \
- bool res = op_macro(lhs, rhs); \
+ DOCTEST_NOINLINE SFINAE_OP(Result,op) operator op(R&& rhs) { \
+ bool res = op_macro(doctest::detail::forward<L>(lhs), doctest::detail::forward<R>(rhs)); \
if(m_at & assertType::is_false) \
res = !res; \
if(!res || doctest::getContextOptions()->success) \
@@ -1171,12 +1212,16 @@ namespace detail {
L lhs;
assertType::Enum m_at;
- explicit Expression_lhs(L in, assertType::Enum at)
- : lhs(in)
+ explicit Expression_lhs(L&& in, assertType::Enum at)
+ : lhs(doctest::detail::forward<L>(in))
, m_at(at) {}
DOCTEST_NOINLINE operator Result() {
- bool res = !!lhs;
+// this is needed only foc MSVC 2015:
+// https://ci.appveyor.com/project/onqtam/doctest/builds/38181202
+DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4800) // 'int': forcing value to bool
+ bool res = static_cast<bool>(lhs);
+DOCTEST_MSVC_SUPPRESS_WARNING_POP
if(m_at & assertType::is_false) //!OCLINT bitwise operator in conditional
res = !res;
@@ -1185,6 +1230,10 @@ namespace detail {
return Result(res);
}
+ /* This is required for user-defined conversions from Expression_lhs to L */
+ //operator L() const { return lhs; }
+ operator L() const { return lhs; }
+
// clang-format off
DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(==, " == ", DOCTEST_CMP_EQ) //!OCLINT bitwise operator in conditional
DOCTEST_DO_BINARY_EXPRESSION_COMPARISON(!=, " != ", DOCTEST_CMP_NE) //!OCLINT bitwise operator in conditional
@@ -1225,6 +1274,10 @@ namespace detail {
#endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION
+#if DOCTEST_CLANG && DOCTEST_CLANG < DOCTEST_COMPILER(3, 6, 0)
+DOCTEST_CLANG_SUPPRESS_WARNING_POP
+#endif
+
struct DOCTEST_INTERFACE ExpressionDecomposer
{
assertType::Enum m_at;
@@ -1236,8 +1289,8 @@ namespace detail {
// https://github.com/catchorg/Catch2/issues/870
// https://github.com/catchorg/Catch2/issues/565
template <typename L>
- Expression_lhs<const DOCTEST_REF_WRAP(L)> operator<<(const DOCTEST_REF_WRAP(L) operand) {
- return Expression_lhs<const DOCTEST_REF_WRAP(L)>(operand, m_at);
+ Expression_lhs<L> operator<<(L &&operand) {
+ return Expression_lhs<L>(doctest::detail::forward<L>(operand), m_at);
}
};
@@ -1246,6 +1299,8 @@ namespace detail {
const char* m_test_suite;
const char* m_description;
bool m_skip;
+ bool m_no_breaks;
+ bool m_no_output;
bool m_may_fail;
bool m_should_fail;
int m_expected_failures;
@@ -1524,7 +1579,7 @@ namespace detail {
template <typename L> class ContextScope : public ContextScopeBase
{
- const L &lambda_;
+ const L lambda_;
public:
explicit ContextScope(const L &lambda) : lambda_(lambda) {}
@@ -1585,6 +1640,8 @@ namespace detail {
DOCTEST_DEFINE_DECORATOR(test_suite, const char*, "");
DOCTEST_DEFINE_DECORATOR(description, const char*, "");
DOCTEST_DEFINE_DECORATOR(skip, bool, true);
+DOCTEST_DEFINE_DECORATOR(no_breaks, bool, true);
+DOCTEST_DEFINE_DECORATOR(no_output, bool, true);
DOCTEST_DEFINE_DECORATOR(timeout, double, 0);
DOCTEST_DEFINE_DECORATOR(may_fail, bool, true);
DOCTEST_DEFINE_DECORATOR(should_fail, bool, true);
@@ -1921,10 +1978,12 @@ int registerReporter(const char* name, int priority, bool isReporter) {
static DOCTEST_NOINLINE doctest::detail::TestSuite& getCurrentTestSuite() { \
DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4640) \
DOCTEST_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wexit-time-destructors") \
- static doctest::detail::TestSuite data; \
+ DOCTEST_GCC_SUPPRESS_WARNING_WITH_PUSH("-Wmissing-field-initializers") \
+ static doctest::detail::TestSuite data{}; \
static bool inited = false; \
DOCTEST_MSVC_SUPPRESS_WARNING_POP \
DOCTEST_CLANG_SUPPRESS_WARNING_POP \
+ DOCTEST_GCC_SUPPRESS_WARNING_POP \
if(!inited) { \
data* decorators; \
inited = true; \
@@ -1979,17 +2038,15 @@ int registerReporter(const char* name, int priority, bool isReporter) {
// for logging
#define DOCTEST_INFO(...) \
DOCTEST_INFO_IMPL(DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), \
- DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_), __VA_ARGS__)
+ __VA_ARGS__)
-#define DOCTEST_INFO_IMPL(lambda_name, mb_name, s_name, ...) \
- DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4626) \
- auto lambda_name = [&](std::ostream* s_name) { \
+#define DOCTEST_INFO_IMPL(mb_name, s_name, ...) \
+ auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope( \
+ [&](std::ostream* s_name) { \
doctest::detail::MessageBuilder mb_name(__FILE__, __LINE__, doctest::assertType::is_warn); \
mb_name.m_stream = s_name; \
mb_name * __VA_ARGS__; \
- }; \
- DOCTEST_MSVC_SUPPRESS_WARNING_POP \
- auto DOCTEST_ANONYMOUS(_DOCTEST_CAPTURE_) = doctest::detail::MakeContextScope(lambda_name)
+ })
#define DOCTEST_CAPTURE(x) DOCTEST_INFO(#x " := ", x)
@@ -2461,7 +2518,7 @@ int registerReporter(const char* name, int priority, bool isReporter) {
#define DOCTEST_FAST_CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE
#define DOCTEST_FAST_REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE
-#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INVOKE
+#define DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id,__VA_ARGS__)
// clang-format on
// BDD style macros
@@ -2481,138 +2538,138 @@ int registerReporter(const char* name, int priority, bool isReporter) {
// == SHORT VERSIONS OF THE MACROS
#if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES)
-#define TEST_CASE DOCTEST_TEST_CASE
-#define TEST_CASE_CLASS DOCTEST_TEST_CASE_CLASS
-#define TEST_CASE_FIXTURE DOCTEST_TEST_CASE_FIXTURE
-#define TYPE_TO_STRING DOCTEST_TYPE_TO_STRING
-#define TEST_CASE_TEMPLATE DOCTEST_TEST_CASE_TEMPLATE
-#define TEST_CASE_TEMPLATE_DEFINE DOCTEST_TEST_CASE_TEMPLATE_DEFINE
-#define TEST_CASE_TEMPLATE_INVOKE DOCTEST_TEST_CASE_TEMPLATE_INVOKE
-#define TEST_CASE_TEMPLATE_APPLY DOCTEST_TEST_CASE_TEMPLATE_APPLY
-#define SUBCASE DOCTEST_SUBCASE
-#define TEST_SUITE DOCTEST_TEST_SUITE
-#define TEST_SUITE_BEGIN DOCTEST_TEST_SUITE_BEGIN
+#define TEST_CASE(name) DOCTEST_TEST_CASE(name)
+#define TEST_CASE_CLASS(name) DOCTEST_TEST_CASE_CLASS(name)
+#define TEST_CASE_FIXTURE(x, name) DOCTEST_TEST_CASE_FIXTURE(x, name)
+#define TYPE_TO_STRING(...) DOCTEST_TYPE_TO_STRING(__VA_ARGS__)
+#define TEST_CASE_TEMPLATE(name, T, ...) DOCTEST_TEST_CASE_TEMPLATE(name, T, __VA_ARGS__)
+#define TEST_CASE_TEMPLATE_DEFINE(name, T, id) DOCTEST_TEST_CASE_TEMPLATE_DEFINE(name, T, id)
+#define TEST_CASE_TEMPLATE_INVOKE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INVOKE(id, __VA_ARGS__)
+#define TEST_CASE_TEMPLATE_APPLY(id, ...) DOCTEST_TEST_CASE_TEMPLATE_APPLY(id, __VA_ARGS__)
+#define SUBCASE(name) DOCTEST_SUBCASE(name)
+#define TEST_SUITE(decorators) DOCTEST_TEST_SUITE(decorators)
+#define TEST_SUITE_BEGIN(name) DOCTEST_TEST_SUITE_BEGIN(name)
#define TEST_SUITE_END DOCTEST_TEST_SUITE_END
-#define REGISTER_EXCEPTION_TRANSLATOR DOCTEST_REGISTER_EXCEPTION_TRANSLATOR
-#define REGISTER_REPORTER DOCTEST_REGISTER_REPORTER
-#define REGISTER_LISTENER DOCTEST_REGISTER_LISTENER
-#define INFO DOCTEST_INFO
-#define CAPTURE DOCTEST_CAPTURE
-#define ADD_MESSAGE_AT DOCTEST_ADD_MESSAGE_AT
-#define ADD_FAIL_CHECK_AT DOCTEST_ADD_FAIL_CHECK_AT
-#define ADD_FAIL_AT DOCTEST_ADD_FAIL_AT
-#define MESSAGE DOCTEST_MESSAGE
-#define FAIL_CHECK DOCTEST_FAIL_CHECK
-#define FAIL DOCTEST_FAIL
-#define TO_LVALUE DOCTEST_TO_LVALUE
-
-#define WARN DOCTEST_WARN
-#define WARN_FALSE DOCTEST_WARN_FALSE
-#define WARN_THROWS DOCTEST_WARN_THROWS
-#define WARN_THROWS_AS DOCTEST_WARN_THROWS_AS
-#define WARN_THROWS_WITH DOCTEST_WARN_THROWS_WITH
-#define WARN_THROWS_WITH_AS DOCTEST_WARN_THROWS_WITH_AS
-#define WARN_NOTHROW DOCTEST_WARN_NOTHROW
-#define CHECK DOCTEST_CHECK
-#define CHECK_FALSE DOCTEST_CHECK_FALSE
-#define CHECK_THROWS DOCTEST_CHECK_THROWS
-#define CHECK_THROWS_AS DOCTEST_CHECK_THROWS_AS
-#define CHECK_THROWS_WITH DOCTEST_CHECK_THROWS_WITH
-#define CHECK_THROWS_WITH_AS DOCTEST_CHECK_THROWS_WITH_AS
-#define CHECK_NOTHROW DOCTEST_CHECK_NOTHROW
-#define REQUIRE DOCTEST_REQUIRE
-#define REQUIRE_FALSE DOCTEST_REQUIRE_FALSE
-#define REQUIRE_THROWS DOCTEST_REQUIRE_THROWS
-#define REQUIRE_THROWS_AS DOCTEST_REQUIRE_THROWS_AS
-#define REQUIRE_THROWS_WITH DOCTEST_REQUIRE_THROWS_WITH
-#define REQUIRE_THROWS_WITH_AS DOCTEST_REQUIRE_THROWS_WITH_AS
-#define REQUIRE_NOTHROW DOCTEST_REQUIRE_NOTHROW
-
-#define WARN_MESSAGE DOCTEST_WARN_MESSAGE
-#define WARN_FALSE_MESSAGE DOCTEST_WARN_FALSE_MESSAGE
-#define WARN_THROWS_MESSAGE DOCTEST_WARN_THROWS_MESSAGE
-#define WARN_THROWS_AS_MESSAGE DOCTEST_WARN_THROWS_AS_MESSAGE
-#define WARN_THROWS_WITH_MESSAGE DOCTEST_WARN_THROWS_WITH_MESSAGE
-#define WARN_THROWS_WITH_AS_MESSAGE DOCTEST_WARN_THROWS_WITH_AS_MESSAGE
-#define WARN_NOTHROW_MESSAGE DOCTEST_WARN_NOTHROW_MESSAGE
-#define CHECK_MESSAGE DOCTEST_CHECK_MESSAGE
-#define CHECK_FALSE_MESSAGE DOCTEST_CHECK_FALSE_MESSAGE
-#define CHECK_THROWS_MESSAGE DOCTEST_CHECK_THROWS_MESSAGE
-#define CHECK_THROWS_AS_MESSAGE DOCTEST_CHECK_THROWS_AS_MESSAGE
-#define CHECK_THROWS_WITH_MESSAGE DOCTEST_CHECK_THROWS_WITH_MESSAGE
-#define CHECK_THROWS_WITH_AS_MESSAGE DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE
-#define CHECK_NOTHROW_MESSAGE DOCTEST_CHECK_NOTHROW_MESSAGE
-#define REQUIRE_MESSAGE DOCTEST_REQUIRE_MESSAGE
-#define REQUIRE_FALSE_MESSAGE DOCTEST_REQUIRE_FALSE_MESSAGE
-#define REQUIRE_THROWS_MESSAGE DOCTEST_REQUIRE_THROWS_MESSAGE
-#define REQUIRE_THROWS_AS_MESSAGE DOCTEST_REQUIRE_THROWS_AS_MESSAGE
-#define REQUIRE_THROWS_WITH_MESSAGE DOCTEST_REQUIRE_THROWS_WITH_MESSAGE
-#define REQUIRE_THROWS_WITH_AS_MESSAGE DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE
-#define REQUIRE_NOTHROW_MESSAGE DOCTEST_REQUIRE_NOTHROW_MESSAGE
-
-#define SCENARIO DOCTEST_SCENARIO
-#define SCENARIO_CLASS DOCTEST_SCENARIO_CLASS
-#define SCENARIO_TEMPLATE DOCTEST_SCENARIO_TEMPLATE
-#define SCENARIO_TEMPLATE_DEFINE DOCTEST_SCENARIO_TEMPLATE_DEFINE
-#define GIVEN DOCTEST_GIVEN
-#define WHEN DOCTEST_WHEN
-#define AND_WHEN DOCTEST_AND_WHEN
-#define THEN DOCTEST_THEN
-#define AND_THEN DOCTEST_AND_THEN
-
-#define WARN_EQ DOCTEST_WARN_EQ
-#define CHECK_EQ DOCTEST_CHECK_EQ
-#define REQUIRE_EQ DOCTEST_REQUIRE_EQ
-#define WARN_NE DOCTEST_WARN_NE
-#define CHECK_NE DOCTEST_CHECK_NE
-#define REQUIRE_NE DOCTEST_REQUIRE_NE
-#define WARN_GT DOCTEST_WARN_GT
-#define CHECK_GT DOCTEST_CHECK_GT
-#define REQUIRE_GT DOCTEST_REQUIRE_GT
-#define WARN_LT DOCTEST_WARN_LT
-#define CHECK_LT DOCTEST_CHECK_LT
-#define REQUIRE_LT DOCTEST_REQUIRE_LT
-#define WARN_GE DOCTEST_WARN_GE
-#define CHECK_GE DOCTEST_CHECK_GE
-#define REQUIRE_GE DOCTEST_REQUIRE_GE
-#define WARN_LE DOCTEST_WARN_LE
-#define CHECK_LE DOCTEST_CHECK_LE
-#define REQUIRE_LE DOCTEST_REQUIRE_LE
-#define WARN_UNARY DOCTEST_WARN_UNARY
-#define CHECK_UNARY DOCTEST_CHECK_UNARY
-#define REQUIRE_UNARY DOCTEST_REQUIRE_UNARY
-#define WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE
-#define CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE
-#define REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE
+#define REGISTER_EXCEPTION_TRANSLATOR(signature) DOCTEST_REGISTER_EXCEPTION_TRANSLATOR(signature)
+#define REGISTER_REPORTER(name, priority, reporter) DOCTEST_REGISTER_REPORTER(name, priority, reporter)
+#define REGISTER_LISTENER(name, priority, reporter) DOCTEST_REGISTER_LISTENER(name, priority, reporter)
+#define INFO(...) DOCTEST_INFO(__VA_ARGS__)
+#define CAPTURE(x) DOCTEST_CAPTURE(x)
+#define ADD_MESSAGE_AT(file, line, ...) DOCTEST_ADD_MESSAGE_AT(file, line, __VA_ARGS__)
+#define ADD_FAIL_CHECK_AT(file, line, ...) DOCTEST_ADD_FAIL_CHECK_AT(file, line, __VA_ARGS__)
+#define ADD_FAIL_AT(file, line, ...) DOCTEST_ADD_FAIL_AT(file, line, __VA_ARGS__)
+#define MESSAGE(...) DOCTEST_MESSAGE(__VA_ARGS__)
+#define FAIL_CHECK(...) DOCTEST_FAIL_CHECK(__VA_ARGS__)
+#define FAIL(...) DOCTEST_FAIL(__VA_ARGS__)
+#define TO_LVALUE(...) DOCTEST_TO_LVALUE(__VA_ARGS__)
+
+#define WARN(...) DOCTEST_WARN(__VA_ARGS__)
+#define WARN_FALSE(...) DOCTEST_WARN_FALSE(__VA_ARGS__)
+#define WARN_THROWS(...) DOCTEST_WARN_THROWS(__VA_ARGS__)
+#define WARN_THROWS_AS(expr, ...) DOCTEST_WARN_THROWS_AS(expr, __VA_ARGS__)
+#define WARN_THROWS_WITH(expr, ...) DOCTEST_WARN_THROWS_WITH(expr, __VA_ARGS__)
+#define WARN_THROWS_WITH_AS(expr, with, ...) DOCTEST_WARN_THROWS_WITH_AS(expr, with, __VA_ARGS__)
+#define WARN_NOTHROW(...) DOCTEST_WARN_NOTHROW(__VA_ARGS__)
+#define CHECK(...) DOCTEST_CHECK(__VA_ARGS__)
+#define CHECK_FALSE(...) DOCTEST_CHECK_FALSE(__VA_ARGS__)
+#define CHECK_THROWS(...) DOCTEST_CHECK_THROWS(__VA_ARGS__)
+#define CHECK_THROWS_AS(expr, ...) DOCTEST_CHECK_THROWS_AS(expr, __VA_ARGS__)
+#define CHECK_THROWS_WITH(expr, ...) DOCTEST_CHECK_THROWS_WITH(expr, __VA_ARGS__)
+#define CHECK_THROWS_WITH_AS(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_AS(expr, with, __VA_ARGS__)
+#define CHECK_NOTHROW(...) DOCTEST_CHECK_NOTHROW(__VA_ARGS__)
+#define REQUIRE(...) DOCTEST_REQUIRE(__VA_ARGS__)
+#define REQUIRE_FALSE(...) DOCTEST_REQUIRE_FALSE(__VA_ARGS__)
+#define REQUIRE_THROWS(...) DOCTEST_REQUIRE_THROWS(__VA_ARGS__)
+#define REQUIRE_THROWS_AS(expr, ...) DOCTEST_REQUIRE_THROWS_AS(expr, __VA_ARGS__)
+#define REQUIRE_THROWS_WITH(expr, ...) DOCTEST_REQUIRE_THROWS_WITH(expr, __VA_ARGS__)
+#define REQUIRE_THROWS_WITH_AS(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_AS(expr, with, __VA_ARGS__)
+#define REQUIRE_NOTHROW(...) DOCTEST_REQUIRE_NOTHROW(__VA_ARGS__)
+
+#define WARN_MESSAGE(cond, ...) DOCTEST_WARN_MESSAGE(cond, __VA_ARGS__)
+#define WARN_FALSE_MESSAGE(cond, ...) DOCTEST_WARN_FALSE_MESSAGE(cond, __VA_ARGS__)
+#define WARN_THROWS_MESSAGE(expr, ...) DOCTEST_WARN_THROWS_MESSAGE(expr, __VA_ARGS__)
+#define WARN_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_WARN_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)
+#define WARN_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_WARN_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)
+#define WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_WARN_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)
+#define WARN_NOTHROW_MESSAGE(expr, ...) DOCTEST_WARN_NOTHROW_MESSAGE(expr, __VA_ARGS__)
+#define CHECK_MESSAGE(cond, ...) DOCTEST_CHECK_MESSAGE(cond, __VA_ARGS__)
+#define CHECK_FALSE_MESSAGE(cond, ...) DOCTEST_CHECK_FALSE_MESSAGE(cond, __VA_ARGS__)
+#define CHECK_THROWS_MESSAGE(expr, ...) DOCTEST_CHECK_THROWS_MESSAGE(expr, __VA_ARGS__)
+#define CHECK_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_CHECK_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)
+#define CHECK_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_CHECK_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)
+#define CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_CHECK_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)
+#define CHECK_NOTHROW_MESSAGE(expr, ...) DOCTEST_CHECK_NOTHROW_MESSAGE(expr, __VA_ARGS__)
+#define REQUIRE_MESSAGE(cond, ...) DOCTEST_REQUIRE_MESSAGE(cond, __VA_ARGS__)
+#define REQUIRE_FALSE_MESSAGE(cond, ...) DOCTEST_REQUIRE_FALSE_MESSAGE(cond, __VA_ARGS__)
+#define REQUIRE_THROWS_MESSAGE(expr, ...) DOCTEST_REQUIRE_THROWS_MESSAGE(expr, __VA_ARGS__)
+#define REQUIRE_THROWS_AS_MESSAGE(expr, ex, ...) DOCTEST_REQUIRE_THROWS_AS_MESSAGE(expr, ex, __VA_ARGS__)
+#define REQUIRE_THROWS_WITH_MESSAGE(expr, with, ...) DOCTEST_REQUIRE_THROWS_WITH_MESSAGE(expr, with, __VA_ARGS__)
+#define REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, ...) DOCTEST_REQUIRE_THROWS_WITH_AS_MESSAGE(expr, with, ex, __VA_ARGS__)
+#define REQUIRE_NOTHROW_MESSAGE(expr, ...) DOCTEST_REQUIRE_NOTHROW_MESSAGE(expr, __VA_ARGS__)
+
+#define SCENARIO(name) DOCTEST_SCENARIO(name)
+#define SCENARIO_CLASS(name) DOCTEST_SCENARIO_CLASS(name)
+#define SCENARIO_TEMPLATE(name, T, ...) DOCTEST_SCENARIO_TEMPLATE(name, T, __VA_ARGS__)
+#define SCENARIO_TEMPLATE_DEFINE(name, T, id) DOCTEST_SCENARIO_TEMPLATE_DEFINE(name, T, id)
+#define GIVEN(name) DOCTEST_GIVEN(name)
+#define WHEN(name) DOCTEST_WHEN(name)
+#define AND_WHEN(name) DOCTEST_AND_WHEN(name)
+#define THEN(name) DOCTEST_THEN(name)
+#define AND_THEN(name) DOCTEST_AND_THEN(name)
+
+#define WARN_EQ(...) DOCTEST_WARN_EQ(__VA_ARGS__)
+#define CHECK_EQ(...) DOCTEST_CHECK_EQ(__VA_ARGS__)
+#define REQUIRE_EQ(...) DOCTEST_REQUIRE_EQ(__VA_ARGS__)
+#define WARN_NE(...) DOCTEST_WARN_NE(__VA_ARGS__)
+#define CHECK_NE(...) DOCTEST_CHECK_NE(__VA_ARGS__)
+#define REQUIRE_NE(...) DOCTEST_REQUIRE_NE(__VA_ARGS__)
+#define WARN_GT(...) DOCTEST_WARN_GT(__VA_ARGS__)
+#define CHECK_GT(...) DOCTEST_CHECK_GT(__VA_ARGS__)
+#define REQUIRE_GT(...) DOCTEST_REQUIRE_GT(__VA_ARGS__)
+#define WARN_LT(...) DOCTEST_WARN_LT(__VA_ARGS__)
+#define CHECK_LT(...) DOCTEST_CHECK_LT(__VA_ARGS__)
+#define REQUIRE_LT(...) DOCTEST_REQUIRE_LT(__VA_ARGS__)
+#define WARN_GE(...) DOCTEST_WARN_GE(__VA_ARGS__)
+#define CHECK_GE(...) DOCTEST_CHECK_GE(__VA_ARGS__)
+#define REQUIRE_GE(...) DOCTEST_REQUIRE_GE(__VA_ARGS__)
+#define WARN_LE(...) DOCTEST_WARN_LE(__VA_ARGS__)
+#define CHECK_LE(...) DOCTEST_CHECK_LE(__VA_ARGS__)
+#define REQUIRE_LE(...) DOCTEST_REQUIRE_LE(__VA_ARGS__)
+#define WARN_UNARY(...) DOCTEST_WARN_UNARY(__VA_ARGS__)
+#define CHECK_UNARY(...) DOCTEST_CHECK_UNARY(__VA_ARGS__)
+#define REQUIRE_UNARY(...) DOCTEST_REQUIRE_UNARY(__VA_ARGS__)
+#define WARN_UNARY_FALSE(...) DOCTEST_WARN_UNARY_FALSE(__VA_ARGS__)
+#define CHECK_UNARY_FALSE(...) DOCTEST_CHECK_UNARY_FALSE(__VA_ARGS__)
+#define REQUIRE_UNARY_FALSE(...) DOCTEST_REQUIRE_UNARY_FALSE(__VA_ARGS__)
// KEPT FOR BACKWARDS COMPATIBILITY
-#define FAST_WARN_EQ DOCTEST_FAST_WARN_EQ
-#define FAST_CHECK_EQ DOCTEST_FAST_CHECK_EQ
-#define FAST_REQUIRE_EQ DOCTEST_FAST_REQUIRE_EQ
-#define FAST_WARN_NE DOCTEST_FAST_WARN_NE
-#define FAST_CHECK_NE DOCTEST_FAST_CHECK_NE
-#define FAST_REQUIRE_NE DOCTEST_FAST_REQUIRE_NE
-#define FAST_WARN_GT DOCTEST_FAST_WARN_GT
-#define FAST_CHECK_GT DOCTEST_FAST_CHECK_GT
-#define FAST_REQUIRE_GT DOCTEST_FAST_REQUIRE_GT
-#define FAST_WARN_LT DOCTEST_FAST_WARN_LT
-#define FAST_CHECK_LT DOCTEST_FAST_CHECK_LT
-#define FAST_REQUIRE_LT DOCTEST_FAST_REQUIRE_LT
-#define FAST_WARN_GE DOCTEST_FAST_WARN_GE
-#define FAST_CHECK_GE DOCTEST_FAST_CHECK_GE
-#define FAST_REQUIRE_GE DOCTEST_FAST_REQUIRE_GE
-#define FAST_WARN_LE DOCTEST_FAST_WARN_LE
-#define FAST_CHECK_LE DOCTEST_FAST_CHECK_LE
-#define FAST_REQUIRE_LE DOCTEST_FAST_REQUIRE_LE
-
-#define FAST_WARN_UNARY DOCTEST_FAST_WARN_UNARY
-#define FAST_CHECK_UNARY DOCTEST_FAST_CHECK_UNARY
-#define FAST_REQUIRE_UNARY DOCTEST_FAST_REQUIRE_UNARY
-#define FAST_WARN_UNARY_FALSE DOCTEST_FAST_WARN_UNARY_FALSE
-#define FAST_CHECK_UNARY_FALSE DOCTEST_FAST_CHECK_UNARY_FALSE
-#define FAST_REQUIRE_UNARY_FALSE DOCTEST_FAST_REQUIRE_UNARY_FALSE
-
-#define TEST_CASE_TEMPLATE_INSTANTIATE DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE
+#define FAST_WARN_EQ(...) DOCTEST_FAST_WARN_EQ(__VA_ARGS__)
+#define FAST_CHECK_EQ(...) DOCTEST_FAST_CHECK_EQ(__VA_ARGS__)
+#define FAST_REQUIRE_EQ(...) DOCTEST_FAST_REQUIRE_EQ(__VA_ARGS__)
+#define FAST_WARN_NE(...) DOCTEST_FAST_WARN_NE(__VA_ARGS__)
+#define FAST_CHECK_NE(...) DOCTEST_FAST_CHECK_NE(__VA_ARGS__)
+#define FAST_REQUIRE_NE(...) DOCTEST_FAST_REQUIRE_NE(__VA_ARGS__)
+#define FAST_WARN_GT(...) DOCTEST_FAST_WARN_GT(__VA_ARGS__)
+#define FAST_CHECK_GT(...) DOCTEST_FAST_CHECK_GT(__VA_ARGS__)
+#define FAST_REQUIRE_GT(...) DOCTEST_FAST_REQUIRE_GT(__VA_ARGS__)
+#define FAST_WARN_LT(...) DOCTEST_FAST_WARN_LT(__VA_ARGS__)
+#define FAST_CHECK_LT(...) DOCTEST_FAST_CHECK_LT(__VA_ARGS__)
+#define FAST_REQUIRE_LT(...) DOCTEST_FAST_REQUIRE_LT(__VA_ARGS__)
+#define FAST_WARN_GE(...) DOCTEST_FAST_WARN_GE(__VA_ARGS__)
+#define FAST_CHECK_GE(...) DOCTEST_FAST_CHECK_GE(__VA_ARGS__)
+#define FAST_REQUIRE_GE(...) DOCTEST_FAST_REQUIRE_GE(__VA_ARGS__)
+#define FAST_WARN_LE(...) DOCTEST_FAST_WARN_LE(__VA_ARGS__)
+#define FAST_CHECK_LE(...) DOCTEST_FAST_CHECK_LE(__VA_ARGS__)
+#define FAST_REQUIRE_LE(...) DOCTEST_FAST_REQUIRE_LE(__VA_ARGS__)
+
+#define FAST_WARN_UNARY(...) DOCTEST_FAST_WARN_UNARY(__VA_ARGS__)
+#define FAST_CHECK_UNARY(...) DOCTEST_FAST_CHECK_UNARY(__VA_ARGS__)
+#define FAST_REQUIRE_UNARY(...) DOCTEST_FAST_REQUIRE_UNARY(__VA_ARGS__)
+#define FAST_WARN_UNARY_FALSE(...) DOCTEST_FAST_WARN_UNARY_FALSE(__VA_ARGS__)
+#define FAST_CHECK_UNARY_FALSE(...) DOCTEST_FAST_CHECK_UNARY_FALSE(__VA_ARGS__)
+#define FAST_REQUIRE_UNARY_FALSE(...) DOCTEST_FAST_REQUIRE_UNARY_FALSE(__VA_ARGS__)
+
+#define TEST_CASE_TEMPLATE_INSTANTIATE(id, ...) DOCTEST_TEST_CASE_TEMPLATE_INSTANTIATE(id, __VA_ARGS__)
#endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES
@@ -2689,6 +2746,7 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wmissing-field-initializers")
DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat")
DOCTEST_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic")
DOCTEST_CLANG_SUPPRESS_WARNING("-Wunused-member-function")
+DOCTEST_CLANG_SUPPRESS_WARNING("-Wnonportable-system-include-path")
DOCTEST_GCC_SUPPRESS_WARNING_PUSH
DOCTEST_GCC_SUPPRESS_WARNING("-Wunknown-pragmas")
@@ -2794,11 +2852,7 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN
#ifdef __AFXDLL
#include <AfxWin.h>
#else
-#if defined(__MINGW32__) || defined(__MINGW64__)
#include <windows.h>
-#else // MINGW
-#include <Windows.h>
-#endif // MINGW
#endif
#include <io.h>
@@ -2834,12 +2888,24 @@ DOCTEST_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END
#define DOCTEST_THREAD_LOCAL thread_local
#endif
+#ifndef DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES
+#define DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES 32
+#endif
+
+#ifndef DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE
+#define DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE 64
+#endif
+
#ifdef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS
#define DOCTEST_OPTIONS_PREFIX_DISPLAY DOCTEST_CONFIG_OPTIONS_PREFIX
#else
#define DOCTEST_OPTIONS_PREFIX_DISPLAY ""
#endif
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
+#define DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
+#endif
+
namespace doctest {
bool is_running_in_test = false;
@@ -2972,18 +3038,105 @@ typedef timer_large_integer::type ticks_t;
ticks_t m_ticks = 0;
};
+#ifdef DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
+ template <typename T>
+ using AtomicOrMultiLaneAtomic = std::atomic<T>;
+#else // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
+ // Provides a multilane implementation of an atomic variable that supports add, sub, load,
+ // store. Instead of using a single atomic variable, this splits up into multiple ones,
+ // each sitting on a separate cache line. The goal is to provide a speedup when most
+ // operations are modifying. It achieves this with two properties:
+ //
+ // * Multiple atomics are used, so chance of congestion from the same atomic is reduced.
+ // * Each atomic sits on a separate cache line, so false sharing is reduced.
+ //
+ // The disadvantage is that there is a small overhead due to the use of TLS, and load/store
+ // is slower because all atomics have to be accessed.
+ template <typename T>
+ class MultiLaneAtomic
+ {
+ struct CacheLineAlignedAtomic
+ {
+ std::atomic<T> atomic{};
+ char padding[DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE - sizeof(std::atomic<T>)];
+ };
+ CacheLineAlignedAtomic m_atomics[DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES];
+
+ static_assert(sizeof(CacheLineAlignedAtomic) == DOCTEST_MULTI_LANE_ATOMICS_CACHE_LINE_SIZE,
+ "guarantee one atomic takes exactly one cache line");
+
+ public:
+ T operator++() DOCTEST_NOEXCEPT { return fetch_add(1) + 1; }
+
+ T operator++(int) DOCTEST_NOEXCEPT { return fetch_add(1); }
+
+ T fetch_add(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
+ return myAtomic().fetch_add(arg, order);
+ }
+
+ T fetch_sub(T arg, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
+ return myAtomic().fetch_sub(arg, order);
+ }
+
+ operator T() const DOCTEST_NOEXCEPT { return load(); }
+
+ T load(std::memory_order order = std::memory_order_seq_cst) const DOCTEST_NOEXCEPT {
+ auto result = T();
+ for(auto const& c : m_atomics) {
+ result += c.atomic.load(order);
+ }
+ return result;
+ }
+
+ T operator=(T desired) DOCTEST_NOEXCEPT {
+ store(desired);
+ return desired;
+ }
+
+ void store(T desired, std::memory_order order = std::memory_order_seq_cst) DOCTEST_NOEXCEPT {
+ // first value becomes desired", all others become 0.
+ for(auto& c : m_atomics) {
+ c.atomic.store(desired, order);
+ desired = {};
+ }
+ }
+
+ private:
+ // Each thread has a different atomic that it operates on. If more than NumLanes threads
+ // use this, some will use the same atomic. So performance will degrate a bit, but still
+ // everything will work.
+ //
+ // The logic here is a bit tricky. The call should be as fast as possible, so that there
+ // is minimal to no overhead in determining the correct atomic for the current thread.
+ //
+ // 1. A global static counter laneCounter counts continuously up.
+ // 2. Each successive thread will use modulo operation of that counter so it gets an atomic
+ // assigned in a round-robin fashion.
+ // 3. This tlsLaneIdx is stored in the thread local data, so it is directly available with
+ // little overhead.
+ std::atomic<T>& myAtomic() DOCTEST_NOEXCEPT {
+ static std::atomic<size_t> laneCounter;
+ DOCTEST_THREAD_LOCAL size_t tlsLaneIdx =
+ laneCounter++ % DOCTEST_MULTI_LANE_ATOMICS_THREAD_LANES;
+
+ return m_atomics[tlsLaneIdx].atomic;
+ }
+ };
+
+ template <typename T>
+ using AtomicOrMultiLaneAtomic = MultiLaneAtomic<T>;
+#endif // DOCTEST_CONFIG_NO_MULTI_LANE_ATOMICS
+
// this holds both parameters from the command line and runtime data for tests
struct ContextState : ContextOptions, TestRunStats, CurrentTestCaseStats
{
- std::atomic<int> numAssertsCurrentTest_atomic;
- std::atomic<int> numAssertsFailedCurrentTest_atomic;
+ AtomicOrMultiLaneAtomic<int> numAssertsCurrentTest_atomic;
+ AtomicOrMultiLaneAtomic<int> numAssertsFailedCurrentTest_atomic;
std::vector<std::vector<String>> filters = decltype(filters)(9); // 9 different filters
std::vector<IReporter*> reporters_currently_used;
- const TestCase* currentTest = nullptr;
-
assert_handler ah = nullptr;
Timer timer;
@@ -3093,14 +3246,16 @@ String::String(const char* in)
String::String(const char* in, unsigned in_size) {
using namespace std;
if(in_size <= last) {
- memcpy(buf, in, in_size + 1);
+ memcpy(buf, in, in_size);
+ buf[in_size] = '\0';
setLast(last - in_size);
} else {
setOnHeap();
data.size = in_size;
data.capacity = data.size + 1;
data.ptr = new char[data.capacity];
- memcpy(data.ptr, in, in_size + 1);
+ memcpy(data.ptr, in, in_size);
+ data.ptr[in_size] = '\0';
}
}
@@ -3471,7 +3626,7 @@ int registerReporter(const char*, int, IReporter*) { return 0; }
namespace doctest_detail_test_suite_ns {
// holds the current test suite
doctest::detail::TestSuite& getCurrentTestSuite() {
- static doctest::detail::TestSuite data;
+ static doctest::detail::TestSuite data{};
return data;
}
} // namespace doctest_detail_test_suite_ns
@@ -3583,7 +3738,7 @@ namespace detail {
Subcase::Subcase(const String& name, const char* file, int line)
: m_signature({name, file, line}) {
- ContextState* s = g_cs;
+ auto* s = g_cs;
// check subcase filters
if(s->subcasesStack.size() < size_t(s->subcase_filter_levels)) {
@@ -3625,7 +3780,7 @@ namespace detail {
g_cs->subcasesPassed.insert(g_cs->subcasesStack);
g_cs->subcasesStack.pop_back();
-#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L
+#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
if(std::uncaught_exceptions() > 0
#else
if(std::uncaught_exception()
@@ -3660,6 +3815,8 @@ namespace detail {
// clear state
m_description = nullptr;
m_skip = false;
+ m_no_breaks = false;
+ m_no_output = false;
m_may_fail = false;
m_should_fail = false;
m_expected_failures = 0;
@@ -3675,6 +3832,8 @@ namespace detail {
m_test_suite = test_suite.m_test_suite;
m_description = test_suite.m_description;
m_skip = test_suite.m_skip;
+ m_no_breaks = test_suite.m_no_breaks;
+ m_no_output = test_suite.m_no_output;
m_may_fail = test_suite.m_may_fail;
m_should_fail = test_suite.m_should_fail;
m_expected_failures = test_suite.m_expected_failures;
@@ -3721,14 +3880,20 @@ namespace detail {
// this will be used only to differentiate between test cases - not relevant for sorting
if(m_line != other.m_line)
return m_line < other.m_line;
- const int file_cmp = m_file.compare(other.m_file);
- if(file_cmp != 0)
- return file_cmp < 0;
const int name_cmp = strcmp(m_name, other.m_name);
if(name_cmp != 0)
return name_cmp < 0;
+ const int file_cmp = m_file.compare(other.m_file);
+ if(file_cmp != 0)
+ return file_cmp < 0;
return m_template_id < other.m_template_id;
}
+
+ // all the registered tests
+ std::set<TestCase>& getRegisteredTests() {
+ static std::set<TestCase> data;
+ return data;
+ }
} // namespace detail
namespace {
using namespace detail;
@@ -3760,12 +3925,6 @@ namespace {
return suiteOrderComparator(lhs, rhs);
}
- // all the registered tests
- std::set<TestCase>& getRegisteredTests() {
- static std::set<TestCase> data;
- return data;
- }
-
#ifdef DOCTEST_CONFIG_COLORS_WINDOWS
HANDLE g_stdoutHandle;
WORD g_origFgAttrs;
@@ -3994,7 +4153,7 @@ namespace detail {
// ContextScope has been destroyed (base class destructors run after derived class destructors).
// Instead, ContextScope calls this method directly from its destructor.
void ContextScopeBase::destroy() {
-#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L
+#if defined(__cpp_lib_uncaught_exceptions) && __cpp_lib_uncaught_exceptions >= 201411L && (!defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200)
if(std::uncaught_exceptions() > 0) {
#else
if(std::uncaught_exception()) {
@@ -4016,7 +4175,9 @@ namespace {
#if !defined(DOCTEST_CONFIG_POSIX_SIGNALS) && !defined(DOCTEST_CONFIG_WINDOWS_SEH)
struct FatalConditionHandler
{
- void reset() {}
+ static void reset() {}
+ static void allocateAltStackMem() {}
+ static void freeAltStackMem() {}
};
#else // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH
@@ -4069,6 +4230,9 @@ namespace {
std::exit(EXIT_FAILURE);
}
+ static void allocateAltStackMem() {}
+ static void freeAltStackMem() {}
+
FatalConditionHandler() {
isSet = true;
// 32k seems enough for doctest to handle stack overflow,
@@ -4086,7 +4250,7 @@ namespace {
// - std::terminate is called FROM THE TEST RUNNER THREAD
// - an exception is thrown from a destructor FROM THE TEST RUNNER THREAD
original_terminate_handler = std::get_terminate();
- std::set_terminate([]() noexcept {
+ std::set_terminate([]() DOCTEST_NOEXCEPT {
reportFatal("Terminate handler called");
if(isDebuggerActive() && !g_cs->no_breaks)
DOCTEST_BREAK_INTO_DEBUGGER();
@@ -4097,7 +4261,7 @@ namespace {
// - std::terminate is called FROM A DIFFERENT THREAD
// - an exception is thrown from a destructor FROM A DIFFERENT THREAD
// - an uncaught exception is thrown FROM A DIFFERENT THREAD
- prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) noexcept {
+ prev_sigabrt_handler = std::signal(SIGABRT, [](int signal) DOCTEST_NOEXCEPT {
if(signal == SIGABRT) {
reportFatal("SIGABRT - Abort (abnormal termination) signal");
if(isDebuggerActive() && !g_cs->no_breaks)
@@ -4135,8 +4299,8 @@ namespace {
SetErrorMode(prev_error_mode_1);
_set_error_mode(prev_error_mode_2);
_set_abort_behavior(prev_abort_behavior, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
- _CrtSetReportMode(_CRT_ASSERT, prev_report_mode);
- _CrtSetReportFile(_CRT_ASSERT, prev_report_file);
+ static_cast<void>(_CrtSetReportMode(_CRT_ASSERT, prev_report_mode));
+ static_cast<void>(_CrtSetReportFile(_CRT_ASSERT, prev_report_file));
isSet = false;
}
}
@@ -4186,7 +4350,8 @@ namespace {
static bool isSet;
static struct sigaction oldSigActions[DOCTEST_COUNTOF(signalDefs)];
static stack_t oldSigStack;
- static char altStackMem[4 * SIGSTKSZ];
+ static size_t altStackSize;
+ static char* altStackMem;
static void handleSignal(int sig) {
const char* name = "<unknown signal>";
@@ -4202,11 +4367,19 @@ namespace {
raise(sig);
}
+ static void allocateAltStackMem() {
+ altStackMem = new char[altStackSize];
+ }
+
+ static void freeAltStackMem() {
+ delete[] altStackMem;
+ }
+
FatalConditionHandler() {
isSet = true;
stack_t sigStack;
sigStack.ss_sp = altStackMem;
- sigStack.ss_size = sizeof(altStackMem);
+ sigStack.ss_size = altStackSize;
sigStack.ss_flags = 0;
sigaltstack(&sigStack, &oldSigStack);
struct sigaction sa = {};
@@ -4231,10 +4404,11 @@ namespace {
}
};
- bool FatalConditionHandler::isSet = false;
+ bool FatalConditionHandler::isSet = false;
struct sigaction FatalConditionHandler::oldSigActions[DOCTEST_COUNTOF(signalDefs)] = {};
- stack_t FatalConditionHandler::oldSigStack = {};
- char FatalConditionHandler::altStackMem[] = {};
+ stack_t FatalConditionHandler::oldSigStack = {};
+ size_t FatalConditionHandler::altStackSize = 4 * SIGSTKSZ;
+ char* FatalConditionHandler::altStackMem = nullptr;
#endif // DOCTEST_PLATFORM_WINDOWS
#endif // DOCTEST_CONFIG_POSIX_SIGNALS || DOCTEST_CONFIG_WINDOWS_SEH
@@ -4336,8 +4510,8 @@ namespace detail {
failed_out_of_a_testing_context(*this);
}
- return m_failed && isDebuggerActive() &&
- !getContextOptions()->no_breaks; // break into debugger
+ return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks &&
+ (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger
}
void ResultBuilder::react() const {
@@ -4387,7 +4561,8 @@ namespace detail {
addFailedAssert(m_severity);
}
- return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn; // break
+ return isDebuggerActive() && !getContextOptions()->no_breaks && !isWarn &&
+ (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger
}
void MessageBuilder::react() {
@@ -5495,7 +5670,7 @@ namespace {
<< Whitespace(sizePrefixDisplay*1) << "output filename\n";
s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "ob, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "order-by=<string> "
<< Whitespace(sizePrefixDisplay*1) << "how the tests should be ordered\n";
- s << Whitespace(sizePrefixDisplay*3) << " <string> - by [file/suite/name/rand]\n";
+ s << Whitespace(sizePrefixDisplay*3) << " <string> - [file/suite/name/rand/none]\n";
s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "rs, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "rand-seed=<int> "
<< Whitespace(sizePrefixDisplay*1) << "seed for random ordering\n";
s << " -" DOCTEST_OPTIONS_PREFIX_DISPLAY "f, --" DOCTEST_OPTIONS_PREFIX_DISPLAY "first=<int> "
@@ -5668,6 +5843,9 @@ namespace {
}
void test_case_end(const CurrentTestCaseStats& st) override {
+ if(tc->m_no_output)
+ return;
+
// log the preamble of the test case only if there is something
// else to print - something other than that an assert has failed
if(opt.duration ||
@@ -5702,6 +5880,9 @@ namespace {
}
void test_case_exception(const TestCaseException& e) override {
+ if(tc->m_no_output)
+ return;
+
logTestStart();
file_line_to_stream(tc->m_file.c_str(), tc->m_line, " ");
@@ -5736,7 +5917,7 @@ namespace {
}
void log_assert(const AssertData& rb) override {
- if(!rb.m_failed && !opt.success)
+ if((!rb.m_failed && !opt.success) || tc->m_no_output)
return;
std::lock_guard<std::mutex> lock(mutex);
@@ -5752,6 +5933,9 @@ namespace {
}
void log_message(const MessageData& mb) override {
+ if(tc->m_no_output)
+ return;
+
std::lock_guard<std::mutex> lock(mutex);
logTestStart();
@@ -5782,8 +5966,10 @@ namespace {
bool with_col = g_no_colors; \
g_no_colors = false; \
ConsoleReporter::func(arg); \
- DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \
- oss.str(""); \
+ if(oss.tellp() != std::streampos{}) { \
+ DOCTEST_OUTPUT_DEBUG_STRING(oss.str().c_str()); \
+ oss.str(""); \
+ } \
g_no_colors = with_col; \
}
@@ -5970,7 +6156,7 @@ void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) {
#define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \
if(parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name "=", option_bool, intRes) || \
parseIntOption(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname "=", option_bool, intRes)) \
- p->var = !!intRes; \
+ p->var = static_cast<bool>(intRes); \
else if(parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX name) || \
parseFlag(argc, argv, DOCTEST_CONFIG_OPTIONS_PREFIX sname)) \
p->var = true; \
@@ -6115,7 +6301,11 @@ int Context::run() {
p->cout = &fstr;
}
+ FatalConditionHandler::allocateAltStackMem();
+
auto cleanup_and_return = [&]() {
+ FatalConditionHandler::freeAltStackMem();
+
if(fstr.is_open())
fstr.close();
@@ -6187,6 +6377,9 @@ int Context::run() {
first[i] = first[idxToSwap];
first[idxToSwap] = temp;
}
+ } else if(p->order_by.compare("none", true) == 0) {
+ // means no sorting - beneficial for death tests which call into the executable
+ // with a specific test case in mind - we don't want to slow down the startup times
}
}
@@ -6286,10 +6479,13 @@ int Context::run() {
#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
try {
#endif // DOCTEST_CONFIG_NO_EXCEPTIONS
+// MSVC 2015 diagnoses fatalConditionHandler as unused (because reset() is a static method)
+DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4101) // unreferenced local variable
FatalConditionHandler fatalConditionHandler; // Handle signals
// execute the test
tc.m_test();
fatalConditionHandler.reset();
+DOCTEST_MSVC_SUPPRESS_WARNING_POP
#ifndef DOCTEST_CONFIG_NO_EXCEPTIONS
} catch(const TestFailureException&) {
p->failure_flags |= TestCaseFailureReason::AssertFailure;