summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/core_bind.cpp10
-rw-r--r--core/core_bind.h2
-rw-r--r--core/extension/gdnative_interface.cpp24
-rw-r--r--core/extension/gdnative_interface.h3
-rw-r--r--core/io/json.cpp86
-rw-r--r--core/io/json.h20
-rw-r--r--core/math/basis.cpp51
-rw-r--r--core/os/os.h2
-rw-r--r--core/register_core_types.cpp14
-rw-r--r--core/variant/variant.cpp30
-rw-r--r--core/variant/variant.h20
-rw-r--r--core/variant/variant_setget.cpp566
-rw-r--r--doc/class.xsd8
-rw-r--r--doc/classes/AESContext.xml1
-rw-r--r--doc/classes/AnimatedSprite2D.xml11
-rw-r--r--doc/classes/AnimatedSprite3D.xml13
-rw-r--r--doc/classes/AnimationNodeBlendTree.xml8
-rw-r--r--doc/classes/AnimationPlayer.xml5
-rw-r--r--doc/classes/AnimationTree.xml7
-rw-r--r--doc/classes/BaseMaterial3D.xml2
-rw-r--r--doc/classes/BoneAttachment3D.xml10
-rw-r--r--doc/classes/CanvasItem.xml12
-rw-r--r--doc/classes/Cubemap.xml4
-rw-r--r--doc/classes/CubemapArray.xml5
-rw-r--r--doc/classes/EditorPlugin.xml4
-rw-r--r--doc/classes/Environment.xml18
-rw-r--r--doc/classes/FogMaterial.xml13
-rw-r--r--doc/classes/FogVolume.xml9
-rw-r--r--doc/classes/HMACContext.xml18
-rw-r--r--doc/classes/ImageTextureLayered.xml6
-rw-r--r--doc/classes/JSON.xml18
-rw-r--r--doc/classes/LightmapGI.xml6
-rw-r--r--doc/classes/MultiMesh.xml22
-rw-r--r--doc/classes/OS.xml21
-rw-r--r--doc/classes/PanoramaSkyMaterial.xml4
-rw-r--r--doc/classes/ProjectSettings.xml2
-rw-r--r--doc/classes/Skeleton3D.xml28
-rw-r--r--doc/classes/SkeletonIK3D.xml37
-rw-r--r--doc/classes/SkeletonModification2D.xml2
-rw-r--r--doc/classes/SkeletonModification2DCCDIK.xml2
-rw-r--r--doc/classes/SkeletonModification2DFABRIK.xml2
-rw-r--r--doc/classes/SkeletonModification2DJiggle.xml2
-rw-r--r--doc/classes/SkeletonModification2DLookAt.xml2
-rw-r--r--doc/classes/SkeletonModification2DPhysicalBones.xml3
-rw-r--r--doc/classes/SkeletonModification2DStackHolder.xml2
-rw-r--r--doc/classes/SkeletonModification2DTwoBoneIK.xml2
-rw-r--r--doc/classes/SkeletonModification3D.xml2
-rw-r--r--doc/classes/SkeletonModification3DCCDIK.xml2
-rw-r--r--doc/classes/SkeletonModification3DFABRIK.xml2
-rw-r--r--doc/classes/SkeletonModification3DJiggle.xml2
-rw-r--r--doc/classes/SkeletonModification3DLookAt.xml2
-rw-r--r--doc/classes/SkeletonModification3DStackHolder.xml2
-rw-r--r--doc/classes/SkeletonModification3DTwoBoneIK.xml2
-rw-r--r--doc/classes/SkeletonModificationStack2D.xml2
-rw-r--r--doc/classes/SkeletonModificationStack3D.xml2
-rw-r--r--doc/classes/TextServer.xml1
-rw-r--r--doc/classes/Texture2DArray.xml3
-rw-r--r--doc/classes/TextureLayered.xml11
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp18
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp1
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h13
-rw-r--r--drivers/gles3/storage/material_storage.cpp8
-rw-r--r--drivers/unix/os_unix.cpp8
-rw-r--r--drivers/unix/os_unix.h2
-rw-r--r--editor/animation_track_editor.cpp5
-rw-r--r--editor/doc_tools.cpp28
-rw-r--r--editor/editor_file_system.cpp5
-rw-r--r--editor/editor_file_system.h1
-rw-r--r--editor/editor_fonts.cpp10
-rw-r--r--editor/editor_inspector.cpp80
-rw-r--r--editor/editor_inspector.h5
-rw-r--r--editor/editor_node.cpp8
-rw-r--r--editor/editor_node.h2
-rw-r--r--editor/editor_properties.cpp8
-rw-r--r--editor/editor_properties_array_dict.cpp26
-rw-r--r--editor/editor_resource_picker.cpp2
-rw-r--r--editor/editor_settings_dialog.cpp4
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp55
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h5
-rw-r--r--editor/plugins/animation_tree_editor_plugin.cpp15
-rw-r--r--editor/plugins/animation_tree_editor_plugin.h1
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp12
-rw-r--r--editor/plugins/node_3d_editor_plugin.h2
-rw-r--r--editor/plugins/shader_editor_plugin.cpp1
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp31
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.h2
-rw-r--r--editor/project_manager.cpp54
-rw-r--r--editor/project_manager.h1
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp2
-rwxr-xr-xmodules/mono/build_scripts/build_assemblies.py4
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets7
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs18
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs125
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs4
-rw-r--r--modules/mono/editor/bindings_generator.cpp34
-rw-r--r--modules/multiplayer/multiplayer_spawner.cpp12
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp3
-rw-r--r--modules/openxr/openxr_api.cpp2
-rw-r--r--platform/android/os_android.cpp74
-rw-r--r--platform/android/os_android.h4
-rw-r--r--platform/ios/os_ios.h2
-rw-r--r--platform/ios/os_ios.mm9
-rw-r--r--platform/linuxbsd/display_server_x11.cpp26
-rw-r--r--platform/linuxbsd/display_server_x11.h2
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp37
-rw-r--r--platform/linuxbsd/os_linuxbsd.h4
-rw-r--r--platform/macos/display_server_macos.h4
-rw-r--r--platform/macos/display_server_macos.mm21
-rw-r--r--platform/macos/godot_content_view.mm18
-rw-r--r--platform/macos/godot_window_delegate.mm4
-rw-r--r--platform/macos/os_macos.h2
-rw-r--r--platform/macos/os_macos.mm9
-rw-r--r--platform/uwp/os_uwp.cpp10
-rw-r--r--platform/uwp/os_uwp.h2
-rw-r--r--platform/windows/display_server_windows.cpp182
-rw-r--r--platform/windows/display_server_windows.h4
-rw-r--r--platform/windows/os_windows.cpp18
-rw-r--r--platform/windows/os_windows.h2
-rw-r--r--scene/2d/animated_sprite_2d.cpp54
-rw-r--r--scene/2d/animated_sprite_2d.h3
-rw-r--r--scene/3d/lightmap_gi.cpp5
-rw-r--r--scene/3d/lightmap_gi.h8
-rw-r--r--scene/3d/sprite_3d.cpp52
-rw-r--r--scene/3d/sprite_3d.h3
-rw-r--r--scene/animation/animation_blend_tree.cpp3
-rw-r--r--scene/animation/animation_player.cpp10
-rw-r--r--scene/animation/animation_tree.cpp58
-rw-r--r--scene/animation/animation_tree.h2
-rw-r--r--scene/animation/tween.cpp272
-rw-r--r--scene/animation/tween.h1
-rw-r--r--scene/gui/graph_edit.cpp8
-rw-r--r--scene/gui/graph_edit.h2
-rw-r--r--scene/main/viewport.cpp47
-rw-r--r--scene/main/viewport.h2
-rw-r--r--scene/main/window.cpp18
-rw-r--r--scene/main/window.h2
-rw-r--r--scene/resources/animation.cpp464
-rw-r--r--scene/resources/animation.h6
-rw-r--r--scene/resources/material.cpp79
-rw-r--r--scene/resources/material.h11
-rw-r--r--scene/resources/shader.h37
-rw-r--r--scene/resources/skeleton_modification_stack_2d.cpp6
-rw-r--r--servers/physics_2d/godot_collision_solver_2d.cpp8
-rw-r--r--servers/physics_2d/godot_collision_solver_2d.h2
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp2
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp1
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp649
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h92
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h2
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp320
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h84
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h2
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp21
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp123
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h35
-rw-r--r--servers/rendering/renderer_rd/shaders/SCsub2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl5
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl9
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/SCsub17
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl (renamed from servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl)60
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl (renamed from servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl)143
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/SCsub17
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl (renamed from servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl)8
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl (renamed from servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl)73
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_data_inc.glsl69
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp209
-rw-r--r--servers/rendering/renderer_rd/storage_rd/mesh_storage.h11
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp246
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h157
-rw-r--r--servers/rendering/renderer_viewport.cpp75
-rw-r--r--servers/rendering/renderer_viewport.h5
-rw-r--r--servers/rendering/shader_types.cpp6
-rw-r--r--servers/rendering_server.cpp14
-rw-r--r--tests/core/math/test_basis.h57
-rw-r--r--version.py2
176 files changed, 3194 insertions, 2715 deletions
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index 9daf58cb71..ba48adff6a 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -322,6 +322,14 @@ String OS::get_name() const {
return ::OS::get_singleton()->get_name();
}
+String OS::get_distribution_name() const {
+ return ::OS::get_singleton()->get_distribution_name();
+}
+
+String OS::get_version() const {
+ return ::OS::get_singleton()->get_version();
+}
+
Vector<String> OS::get_cmdline_args() {
List<String> cmdline = ::OS::get_singleton()->get_cmdline_args();
Vector<String> cmdlinev;
@@ -535,6 +543,8 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_environment", "variable"), &OS::has_environment);
ClassDB::bind_method(D_METHOD("get_name"), &OS::get_name);
+ ClassDB::bind_method(D_METHOD("get_distribution_name"), &OS::get_distribution_name);
+ ClassDB::bind_method(D_METHOD("get_version"), &OS::get_version);
ClassDB::bind_method(D_METHOD("get_cmdline_args"), &OS::get_cmdline_args);
ClassDB::bind_method(D_METHOD("get_cmdline_user_args"), &OS::get_cmdline_user_args);
diff --git a/core/core_bind.h b/core/core_bind.h
index cd382d2915..0f85e473a5 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -193,6 +193,8 @@ public:
bool set_environment(const String &p_var, const String &p_value) const;
String get_name() const;
+ String get_distribution_name() const;
+ String get_version() const;
Vector<String> get_cmdline_args();
Vector<String> get_cmdline_user_args();
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index ef0b590030..6c680e82c9 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -251,27 +251,6 @@ static GDNativeBool gdnative_variant_booleanize(const GDNativeVariantPtr p_self)
return self->booleanize();
}
-static void gdnative_variant_sub(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst) {
- const Variant *a = (const Variant *)p_a;
- const Variant *b = (const Variant *)p_b;
- memnew_placement(r_dst, Variant);
- Variant::sub(*a, *b, *(Variant *)r_dst);
-}
-
-static void gdnative_variant_blend(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) {
- const Variant *a = (const Variant *)p_a;
- const Variant *b = (const Variant *)p_b;
- memnew_placement(r_dst, Variant);
- Variant::blend(*a, *b, p_c, *(Variant *)r_dst);
-}
-
-static void gdnative_variant_interpolate(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst) {
- const Variant *a = (const Variant *)p_a;
- const Variant *b = (const Variant *)p_b;
- memnew_placement(r_dst, Variant);
- Variant::interpolate(*a, *b, p_c, *(Variant *)r_dst);
-}
-
static void gdnative_variant_duplicate(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep) {
const Variant *self = (const Variant *)p_self;
memnew_placement(r_ret, Variant(self->duplicate(p_deep)));
@@ -970,9 +949,6 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.variant_recursive_hash = gdnative_variant_recursive_hash;
gdni.variant_hash_compare = gdnative_variant_hash_compare;
gdni.variant_booleanize = gdnative_variant_booleanize;
- gdni.variant_sub = gdnative_variant_sub;
- gdni.variant_blend = gdnative_variant_blend;
- gdni.variant_interpolate = gdnative_variant_interpolate;
gdni.variant_duplicate = gdnative_variant_duplicate;
gdni.variant_stringify = gdnative_variant_stringify;
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index cb2adcb562..39378d8261 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -427,9 +427,6 @@ typedef struct {
GDNativeInt (*variant_recursive_hash)(const GDNativeVariantPtr p_self, GDNativeInt p_recursion_count);
GDNativeBool (*variant_hash_compare)(const GDNativeVariantPtr p_self, const GDNativeVariantPtr p_other);
GDNativeBool (*variant_booleanize)(const GDNativeVariantPtr p_self);
- void (*variant_sub)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, GDNativeVariantPtr r_dst);
- void (*variant_blend)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst);
- void (*variant_interpolate)(const GDNativeVariantPtr p_a, const GDNativeVariantPtr p_b, float p_c, GDNativeVariantPtr r_dst);
void (*variant_duplicate)(const GDNativeVariantPtr p_self, GDNativeVariantPtr r_ret, GDNativeBool p_deep);
void (*variant_stringify)(const GDNativeVariantPtr p_self, GDNativeStringPtr r_ret);
diff --git a/core/io/json.cpp b/core/io/json.cpp
index 91500ff3d5..a685fcb718 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -497,6 +497,10 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index,
return ERR_PARSE_ERROR;
}
+void JSON::set_data(const Variant &p_data) {
+ data = p_data;
+}
+
Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) {
const char32_t *str = p_json.ptr();
int idx = 0;
@@ -557,6 +561,88 @@ void JSON::_bind_methods() {
ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse);
ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data);
+ ClassDB::bind_method(D_METHOD("set_data", "data"), &JSON::set_data);
ClassDB::bind_method(D_METHOD("get_error_line"), &JSON::get_error_line);
ClassDB::bind_method(D_METHOD("get_error_message"), &JSON::get_error_message);
+
+ ADD_PROPERTY(PropertyInfo(Variant::NIL, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), "set_data", "get_data"); // Ensures that it can be serialized as binary.
+}
+
+////
+
+////////////
+
+Ref<Resource> ResourceFormatLoaderJSON::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ if (r_error) {
+ *r_error = ERR_FILE_CANT_OPEN;
+ }
+
+ if (!FileAccess::exists(p_path)) {
+ *r_error = ERR_FILE_NOT_FOUND;
+ return Ref<Resource>();
+ }
+
+ Ref<JSON> json;
+ json.instantiate();
+
+ Error err = json->parse(FileAccess::get_file_as_string(p_path));
+ if (err != OK) {
+ if (r_error) {
+ *r_error = err;
+ }
+ ERR_PRINT("Error parsing JSON file at '" + p_path + "', on line " + itos(json->get_error_line()) + ": " + json->get_error_message());
+ return Ref<Resource>();
+ }
+
+ if (r_error) {
+ *r_error = OK;
+ }
+
+ return json;
+}
+
+void ResourceFormatLoaderJSON::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("json");
+}
+
+bool ResourceFormatLoaderJSON::handles_type(const String &p_type) const {
+ return (p_type == "JSON");
+}
+
+String ResourceFormatLoaderJSON::get_resource_type(const String &p_path) const {
+ String el = p_path.get_extension().to_lower();
+ if (el == "json") {
+ return "JSON";
+ }
+ return "";
+}
+
+Error ResourceFormatSaverJSON::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) {
+ Ref<JSON> json = p_resource;
+ ERR_FAIL_COND_V(json.is_null(), ERR_INVALID_PARAMETER);
+
+ String source = JSON::stringify(json->get_data(), "\t", false, true);
+
+ Error err;
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+
+ ERR_FAIL_COND_V_MSG(err, err, "Cannot save json '" + p_path + "'.");
+
+ file->store_string(source);
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ return ERR_CANT_CREATE;
+ }
+
+ return OK;
+}
+
+void ResourceFormatSaverJSON::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
+ Ref<JSON> json = p_resource;
+ if (json.is_valid()) {
+ p_extensions->push_back("json");
+ }
+}
+
+bool ResourceFormatSaverJSON::recognize(const Ref<Resource> &p_resource) const {
+ return p_resource->get_class_name() == "JSON"; //only json, not inherited
}
diff --git a/core/io/json.h b/core/io/json.h
index 840b1cc08a..208d4ad625 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -31,7 +31,9 @@
#ifndef JSON_H
#define JSON_H
-#include "core/object/ref_counted.h"
+#include "core/io/resource.h"
+#include "core/io/resource_loader.h"
+#include "core/io/resource_saver.h"
#include "core/variant/variant.h"
class JSON : public RefCounted {
@@ -86,8 +88,24 @@ public:
static Variant parse_string(const String &p_json_string);
inline Variant get_data() const { return data; }
+ void set_data(const Variant &p_data);
inline int get_error_line() const { return err_line; }
inline String get_error_message() const { return err_str; }
};
+class ResourceFormatLoaderJSON : public ResourceFormatLoader {
+public:
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+class ResourceFormatSaverJSON : public ResourceFormatSaver {
+public:
+ virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0);
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize(const Ref<Resource> &p_resource) const;
+};
+
#endif // JSON_H
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 0eb6320ac6..4b163409ce 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -754,29 +754,28 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
#ifdef MATH_CHECKS
ERR_FAIL_COND(!is_rotation());
#endif
-*/
- real_t angle, x, y, z; // variables for result
- real_t angle_epsilon = 0.1; // margin to distinguish between 0 and 180 degrees
-
- if ((Math::abs(rows[1][0] - rows[0][1]) < CMP_EPSILON) && (Math::abs(rows[2][0] - rows[0][2]) < CMP_EPSILON) && (Math::abs(rows[2][1] - rows[1][2]) < CMP_EPSILON)) {
- // singularity found
- // first check for identity matrix which must have +1 for all terms
- // in leading diagonal and zero in other terms
- if ((Math::abs(rows[1][0] + rows[0][1]) < angle_epsilon) && (Math::abs(rows[2][0] + rows[0][2]) < angle_epsilon) && (Math::abs(rows[2][1] + rows[1][2]) < angle_epsilon) && (Math::abs(rows[0][0] + rows[1][1] + rows[2][2] - 3) < angle_epsilon)) {
- // this singularity is identity matrix so angle = 0
+ */
+
+ // https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
+ real_t x, y, z; // Variables for result.
+ if (Math::is_zero_approx(rows[0][1] - rows[1][0]) && Math::is_zero_approx(rows[0][2] - rows[2][0]) && Math::is_zero_approx(rows[1][2] - rows[2][1])) {
+ // Singularity found.
+ // First check for identity matrix which must have +1 for all terms in leading diagonal and zero in other terms.
+ if (is_diagonal() && (Math::abs(rows[0][0] + rows[1][1] + rows[2][2] - 3) < 3 * CMP_EPSILON)) {
+ // This singularity is identity matrix so angle = 0.
r_axis = Vector3(0, 1, 0);
r_angle = 0;
return;
}
- // otherwise this singularity is angle = 180
- angle = Math_PI;
+ // Otherwise this singularity is angle = 180.
real_t xx = (rows[0][0] + 1) / 2;
real_t yy = (rows[1][1] + 1) / 2;
real_t zz = (rows[2][2] + 1) / 2;
- real_t xy = (rows[1][0] + rows[0][1]) / 4;
- real_t xz = (rows[2][0] + rows[0][2]) / 4;
- real_t yz = (rows[2][1] + rows[1][2]) / 4;
- if ((xx > yy) && (xx > zz)) { // rows[0][0] is the largest diagonal term
+ real_t xy = (rows[0][1] + rows[1][0]) / 4;
+ real_t xz = (rows[0][2] + rows[2][0]) / 4;
+ real_t yz = (rows[1][2] + rows[2][1]) / 4;
+
+ if ((xx > yy) && (xx > zz)) { // rows[0][0] is the largest diagonal term.
if (xx < CMP_EPSILON) {
x = 0;
y = Math_SQRT12;
@@ -786,7 +785,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
y = xy / x;
z = xz / x;
}
- } else if (yy > zz) { // rows[1][1] is the largest diagonal term
+ } else if (yy > zz) { // rows[1][1] is the largest diagonal term.
if (yy < CMP_EPSILON) {
x = Math_SQRT12;
y = 0;
@@ -796,7 +795,7 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
x = xy / y;
z = yz / y;
}
- } else { // rows[2][2] is the largest diagonal term so base result on this
+ } else { // rows[2][2] is the largest diagonal term so base result on this.
if (zz < CMP_EPSILON) {
x = Math_SQRT12;
y = Math_SQRT12;
@@ -808,22 +807,24 @@ void Basis::get_axis_angle(Vector3 &r_axis, real_t &r_angle) const {
}
}
r_axis = Vector3(x, y, z);
- r_angle = angle;
+ r_angle = Math_PI;
return;
}
- // as we have reached here there are no singularities so we can handle normally
- real_t s = Math::sqrt((rows[1][2] - rows[2][1]) * (rows[1][2] - rows[2][1]) + (rows[2][0] - rows[0][2]) * (rows[2][0] - rows[0][2]) + (rows[0][1] - rows[1][0]) * (rows[0][1] - rows[1][0])); // s=|axis||sin(angle)|, used to normalise
+ // As we have reached here there are no singularities so we can handle normally.
+ double s = Math::sqrt((rows[2][1] - rows[1][2]) * (rows[2][1] - rows[1][2]) + (rows[0][2] - rows[2][0]) * (rows[0][2] - rows[2][0]) + (rows[1][0] - rows[0][1]) * (rows[1][0] - rows[0][1])); // Used to normalise.
- angle = Math::acos((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2);
- if (angle < 0) {
- s = -s;
+ if (Math::abs(s) < CMP_EPSILON) {
+ // Prevent divide by zero, should not happen if matrix is orthogonal and should be caught by singularity test above.
+ s = 1;
}
+
x = (rows[2][1] - rows[1][2]) / s;
y = (rows[0][2] - rows[2][0]) / s;
z = (rows[1][0] - rows[0][1]) / s;
r_axis = Vector3(x, y, z);
- r_angle = angle;
+ // CLAMP to avoid NaN if the value passed to acos is not in [0,1].
+ r_angle = Math::acos(CLAMP((rows[0][0] + rows[1][1] + rows[2][2] - 1) / 2, (real_t)0.0, (real_t)1.0));
}
void Basis::set_quaternion(const Quaternion &p_quaternion) {
diff --git a/core/os/os.h b/core/os/os.h
index 363697ea30..6944d29eeb 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -161,6 +161,8 @@ public:
virtual bool set_environment(const String &p_var, const String &p_value) const = 0;
virtual String get_name() const = 0;
+ virtual String get_distribution_name() const = 0;
+ virtual String get_version() const = 0;
virtual List<String> get_cmdline_args() const { return _cmdline; }
virtual List<String> get_cmdline_user_args() const { return _user_args; }
virtual List<String> get_cmdline_platform_args() const { return List<String>(); }
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 6650d9be23..6dfb0f82e0 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -87,6 +87,8 @@ static Ref<TranslationLoaderPO> resource_format_po;
static Ref<ResourceFormatSaverCrypto> resource_format_saver_crypto;
static Ref<ResourceFormatLoaderCrypto> resource_format_loader_crypto;
static Ref<NativeExtensionResourceLoader> resource_loader_native_extension;
+static Ref<ResourceFormatSaverJSON> resource_saver_json;
+static Ref<ResourceFormatLoaderJSON> resource_loader_json;
static core_bind::ResourceLoader *_resource_loader = nullptr;
static core_bind::ResourceSaver *_resource_saver = nullptr;
@@ -211,6 +213,12 @@ void register_core_types() {
resource_format_loader_crypto.instantiate();
ResourceLoader::add_resource_format_loader(resource_format_loader_crypto);
+ resource_loader_json.instantiate();
+ ResourceLoader::add_resource_format_loader(resource_loader_json);
+
+ resource_saver_json.instantiate();
+ ResourceSaver::add_resource_format_saver(resource_saver_json);
+
GDREGISTER_CLASS(MainLoop);
GDREGISTER_CLASS(Translation);
GDREGISTER_CLASS(OptimizedTranslation);
@@ -387,6 +395,12 @@ void unregister_core_types() {
ResourceLoader::remove_resource_format_loader(resource_format_loader_crypto);
resource_format_loader_crypto.unref();
+ ResourceSaver::remove_resource_format_saver(resource_saver_json);
+ resource_saver_json.unref();
+
+ ResourceLoader::remove_resource_format_loader(resource_loader_json);
+ resource_loader_json.unref();
+
if (ip) {
memdelete(ip);
}
diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp
index b280fc9fe3..f24ffeb1a9 100644
--- a/core/variant/variant.cpp
+++ b/core/variant/variant.cpp
@@ -3727,36 +3727,6 @@ String Variant::get_callable_error_text(const Callable &p_callable, const Varian
return get_call_error_text(p_callable.get_object(), p_callable.get_method(), p_argptrs, p_argcount, ce);
}
-String vformat(const String &p_text, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) {
- Array args;
- if (p1.get_type() != Variant::NIL) {
- args.push_back(p1);
-
- if (p2.get_type() != Variant::NIL) {
- args.push_back(p2);
-
- if (p3.get_type() != Variant::NIL) {
- args.push_back(p3);
-
- if (p4.get_type() != Variant::NIL) {
- args.push_back(p4);
-
- if (p5.get_type() != Variant::NIL) {
- args.push_back(p5);
- }
- }
- }
- }
- }
-
- bool error = false;
- String fmt = p_text.sprintf(args, &error);
-
- ERR_FAIL_COND_V_MSG(error, String(), fmt);
-
- return fmt;
-}
-
void Variant::register_types() {
_register_variant_operators();
_register_variant_methods();
diff --git a/core/variant/variant.h b/core/variant/variant.h
index 212f94a9a8..b0738e7d44 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -552,9 +552,6 @@ public:
void zero();
Variant duplicate(bool p_deep = false) const;
Variant recursive_duplicate(bool p_deep, int recursion_count) const;
- static void blend(const Variant &a, const Variant &b, float c, Variant &r_dst);
- static void interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst);
- static void sub(const Variant &a, const Variant &b, Variant &r_dst);
/* Built-In Methods */
@@ -807,7 +804,22 @@ const Variant::ObjData &Variant::_get_obj() const {
return *reinterpret_cast<const ObjData *>(&_data._mem[0]);
}
-String vformat(const String &p_text, const Variant &p1 = Variant(), const Variant &p2 = Variant(), const Variant &p3 = Variant(), const Variant &p4 = Variant(), const Variant &p5 = Variant());
+template <typename... VarArgs>
+String vformat(const String &p_text, const VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ Array args_array;
+ args_array.resize(sizeof...(p_args));
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ args_array[i] = args[i];
+ }
+
+ bool error = false;
+ String fmt = p_text.sprintf(args_array, &error);
+
+ ERR_FAIL_COND_V_MSG(error, String(), fmt);
+
+ return fmt;
+}
template <typename... VarArgs>
Callable Callable::bind(VarArgs... p_args) {
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index 57b953f7f0..ff67b187ef 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -1911,572 +1911,6 @@ Variant Variant::recursive_duplicate(bool p_deep, int recursion_count) const {
}
}
-void Variant::sub(const Variant &a, const Variant &b, Variant &r_dst) {
- if (a.type != b.type) {
- return;
- }
-
- switch (a.type) {
- case NIL: {
- r_dst = Variant();
- }
- return;
- case INT: {
- int64_t va = a._data._int;
- int64_t vb = b._data._int;
- r_dst = int(va - vb);
- }
- return;
- case FLOAT: {
- double ra = a._data._float;
- double rb = b._data._float;
- r_dst = ra - rb;
- }
- return;
- case VECTOR2: {
- r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) - *reinterpret_cast<const Vector2 *>(b._data._mem);
- }
- return;
- case VECTOR2I: {
- int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
- r_dst = Vector2i(int32_t(vax - vbx), int32_t(vay - vby));
- }
- return;
- case RECT2: {
- const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem);
- const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem);
- r_dst = Rect2(ra->position - rb->position, ra->size - rb->size);
- }
- return;
- case RECT2I: {
- const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
- const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
-
- int32_t vax = ra->position.x;
- int32_t vay = ra->position.y;
- int32_t vbx = ra->size.x;
- int32_t vby = ra->size.y;
- int32_t vcx = rb->position.x;
- int32_t vcy = rb->position.y;
- int32_t vdx = rb->size.x;
- int32_t vdy = rb->size.y;
-
- r_dst = Rect2i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vcx - vdx), int32_t(vcy - vdy));
- }
- return;
- case VECTOR3: {
- r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) - *reinterpret_cast<const Vector3 *>(b._data._mem);
- }
- return;
- case VECTOR3I: {
- int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
- int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
- int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
- r_dst = Vector3i(int32_t(vax - vbx), int32_t(vay - vby), int32_t(vaz - vbz));
- }
- return;
- case AABB: {
- const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem);
- const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem);
- r_dst = ::AABB(ra->position - rb->position, ra->size - rb->size);
- }
- return;
- case QUATERNION: {
- Quaternion empty_rot;
- const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem);
- const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem);
- r_dst = (*qb).inverse() * *qa;
- }
- return;
- case COLOR: {
- const Color *ca = reinterpret_cast<const Color *>(a._data._mem);
- const Color *cb = reinterpret_cast<const Color *>(b._data._mem);
- float new_r = ca->r - cb->r;
- float new_g = ca->g - cb->g;
- float new_b = ca->b - cb->b;
- float new_a = ca->a - cb->a;
- new_r = new_r > 1.0 ? 1.0 : new_r;
- new_g = new_g > 1.0 ? 1.0 : new_g;
- new_b = new_b > 1.0 ? 1.0 : new_b;
- new_a = new_a > 1.0 ? 1.0 : new_a;
- r_dst = Color(new_r, new_g, new_b, new_a);
- }
- return;
- default: {
- r_dst = a;
- }
- return;
- }
-}
-
-void Variant::blend(const Variant &a, const Variant &b, float c, Variant &r_dst) {
- if (a.type != b.type) {
- if (a.is_num() && b.is_num()) {
- real_t va = a;
- real_t vb = b;
- r_dst = va + vb * c;
- } else {
- r_dst = a;
- }
- return;
- }
-
- switch (a.type) {
- case NIL: {
- r_dst = Variant();
- }
- return;
- case INT: {
- int64_t va = a._data._int;
- int64_t vb = b._data._int;
- r_dst = int(va + vb * c + 0.5);
- }
- return;
- case FLOAT: {
- double ra = a._data._float;
- double rb = b._data._float;
- r_dst = ra + rb * c;
- }
- return;
- case VECTOR2: {
- r_dst = *reinterpret_cast<const Vector2 *>(a._data._mem) + *reinterpret_cast<const Vector2 *>(b._data._mem) * c;
- }
- return;
- case VECTOR2I: {
- int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
- r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5));
- }
- return;
- case RECT2: {
- const Rect2 *ra = reinterpret_cast<const Rect2 *>(a._data._mem);
- const Rect2 *rb = reinterpret_cast<const Rect2 *>(b._data._mem);
- r_dst = Rect2(ra->position + rb->position * c, ra->size + rb->size * c);
- }
- return;
- case RECT2I: {
- const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
- const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
-
- int32_t vax = ra->position.x;
- int32_t vay = ra->position.y;
- int32_t vbx = ra->size.x;
- int32_t vby = ra->size.y;
- int32_t vcx = rb->position.x;
- int32_t vcy = rb->position.y;
- int32_t vdx = rb->size.x;
- int32_t vdy = rb->size.y;
-
- r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5));
- }
- return;
- case VECTOR3: {
- r_dst = *reinterpret_cast<const Vector3 *>(a._data._mem) + *reinterpret_cast<const Vector3 *>(b._data._mem) * c;
- }
- return;
- case VECTOR3I: {
- int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
- int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
- int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
- r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5));
- }
- return;
- case AABB: {
- const ::AABB *ra = reinterpret_cast<const ::AABB *>(a._data._mem);
- const ::AABB *rb = reinterpret_cast<const ::AABB *>(b._data._mem);
- r_dst = ::AABB(ra->position + rb->position * c, ra->size + rb->size * c);
- }
- return;
- case QUATERNION: {
- Quaternion empty_rot;
- const Quaternion *qa = reinterpret_cast<const Quaternion *>(a._data._mem);
- const Quaternion *qb = reinterpret_cast<const Quaternion *>(b._data._mem);
- r_dst = *qa * empty_rot.slerp(*qb, c);
- }
- return;
- case COLOR: {
- const Color *ca = reinterpret_cast<const Color *>(a._data._mem);
- const Color *cb = reinterpret_cast<const Color *>(b._data._mem);
- float new_r = ca->r + cb->r * c;
- float new_g = ca->g + cb->g * c;
- float new_b = ca->b + cb->b * c;
- float new_a = ca->a + cb->a * c;
- new_r = new_r > 1.0 ? 1.0 : new_r;
- new_g = new_g > 1.0 ? 1.0 : new_g;
- new_b = new_b > 1.0 ? 1.0 : new_b;
- new_a = new_a > 1.0 ? 1.0 : new_a;
- r_dst = Color(new_r, new_g, new_b, new_a);
- }
- return;
- default: {
- r_dst = c < 0.5 ? a : b;
- }
- return;
- }
-}
-
-void Variant::interpolate(const Variant &a, const Variant &b, float c, Variant &r_dst) {
- if (a.type != b.type) {
- if (a.is_num() && b.is_num()) {
- //not as efficient but..
- real_t va = a;
- real_t vb = b;
- r_dst = va + (vb - va) * c;
-
- } else {
- r_dst = a;
- }
- return;
- }
-
- switch (a.type) {
- case NIL: {
- r_dst = Variant();
- }
- return;
- case BOOL: {
- r_dst = a;
- }
- return;
- case INT: {
- int64_t va = a._data._int;
- int64_t vb = b._data._int;
- r_dst = int(va + (vb - va) * c);
- }
- return;
- case FLOAT: {
- real_t va = a._data._float;
- real_t vb = b._data._float;
- r_dst = va + (vb - va) * c;
- }
- return;
- case STRING: {
- //this is pretty funny and bizarre, but artists like to use it for typewriter effects
- String sa = *reinterpret_cast<const String *>(a._data._mem);
- String sb = *reinterpret_cast<const String *>(b._data._mem);
- String dst;
- int sa_len = sa.length();
- int sb_len = sb.length();
- int csize = sa_len + (sb_len - sa_len) * c;
- if (csize == 0) {
- r_dst = "";
- return;
- }
- dst.resize(csize + 1);
- dst[csize] = 0;
- int split = csize / 2;
-
- for (int i = 0; i < csize; i++) {
- char32_t chr = ' ';
-
- if (i < split) {
- if (i < sa.length()) {
- chr = sa[i];
- } else if (i < sb.length()) {
- chr = sb[i];
- }
-
- } else {
- if (i < sb.length()) {
- chr = sb[i];
- } else if (i < sa.length()) {
- chr = sa[i];
- }
- }
-
- dst[i] = chr;
- }
-
- r_dst = dst;
- }
- return;
- case VECTOR2: {
- r_dst = reinterpret_cast<const Vector2 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector2 *>(b._data._mem), c);
- }
- return;
- case VECTOR2I: {
- int32_t vax = reinterpret_cast<const Vector2i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector2i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector2i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector2i *>(b._data._mem)->y;
- r_dst = Vector2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5));
- }
- return;
-
- case RECT2: {
- r_dst = Rect2(reinterpret_cast<const Rect2 *>(a._data._mem)->position.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->position, c), reinterpret_cast<const Rect2 *>(a._data._mem)->size.lerp(reinterpret_cast<const Rect2 *>(b._data._mem)->size, c));
- }
- return;
- case RECT2I: {
- const Rect2i *ra = reinterpret_cast<const Rect2i *>(a._data._mem);
- const Rect2i *rb = reinterpret_cast<const Rect2i *>(b._data._mem);
-
- int32_t vax = ra->position.x;
- int32_t vay = ra->position.y;
- int32_t vbx = ra->size.x;
- int32_t vby = ra->size.y;
- int32_t vcx = rb->position.x;
- int32_t vcy = rb->position.y;
- int32_t vdx = rb->size.x;
- int32_t vdy = rb->size.y;
-
- r_dst = Rect2i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vcx + vdx * c + 0.5), int32_t(vcy + vdy * c + 0.5));
- }
- return;
-
- case VECTOR3: {
- r_dst = reinterpret_cast<const Vector3 *>(a._data._mem)->lerp(*reinterpret_cast<const Vector3 *>(b._data._mem), c);
- }
- return;
- case VECTOR3I: {
- int32_t vax = reinterpret_cast<const Vector3i *>(a._data._mem)->x;
- int32_t vbx = reinterpret_cast<const Vector3i *>(b._data._mem)->x;
- int32_t vay = reinterpret_cast<const Vector3i *>(a._data._mem)->y;
- int32_t vby = reinterpret_cast<const Vector3i *>(b._data._mem)->y;
- int32_t vaz = reinterpret_cast<const Vector3i *>(a._data._mem)->z;
- int32_t vbz = reinterpret_cast<const Vector3i *>(b._data._mem)->z;
- r_dst = Vector3i(int32_t(vax + vbx * c + 0.5), int32_t(vay + vby * c + 0.5), int32_t(vaz + vbz * c + 0.5));
- }
- return;
-
- case TRANSFORM2D: {
- r_dst = a._data._transform2d->interpolate_with(*b._data._transform2d, c);
- }
- return;
- case PLANE: {
- r_dst = a;
- }
- return;
- case QUATERNION: {
- r_dst = reinterpret_cast<const Quaternion *>(a._data._mem)->slerp(*reinterpret_cast<const Quaternion *>(b._data._mem), c);
- }
- return;
- case AABB: {
- r_dst = ::AABB(a._data._aabb->position.lerp(b._data._aabb->position, c), a._data._aabb->size.lerp(b._data._aabb->size, c));
- }
- return;
- case BASIS: {
- r_dst = a._data._basis->lerp(*b._data._basis, c);
- }
- return;
- case TRANSFORM3D: {
- r_dst = a._data._transform3d->interpolate_with(*b._data._transform3d, c);
- }
- return;
- case COLOR: {
- r_dst = reinterpret_cast<const Color *>(a._data._mem)->lerp(*reinterpret_cast<const Color *>(b._data._mem), c);
- }
- return;
- case STRING_NAME: {
- r_dst = a;
- }
- return;
- case NODE_PATH: {
- r_dst = a;
- }
- return;
- case RID: {
- r_dst = a;
- }
- return;
- case OBJECT: {
- r_dst = a;
- }
- return;
- case DICTIONARY: {
- }
- return;
- case ARRAY: {
- r_dst = a;
- }
- return;
- case PACKED_BYTE_ARRAY: {
- r_dst = a;
- }
- return;
- case PACKED_INT32_ARRAY: {
- const Vector<int32_t> *arr_a = &PackedArrayRef<int32_t>::get_array(a._data.packed_array);
- const Vector<int32_t> *arr_b = &PackedArrayRef<int32_t>::get_array(b._data.packed_array);
- int32_t sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<int32_t> v;
- v.resize(sz);
- {
- int32_t *vw = v.ptrw();
- const int32_t *ar = arr_a->ptr();
- const int32_t *br = arr_b->ptr();
-
- Variant va;
- for (int32_t i = 0; i < sz; i++) {
- Variant::interpolate(ar[i], br[i], c, va);
- vw[i] = va;
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_INT64_ARRAY: {
- const Vector<int64_t> *arr_a = &PackedArrayRef<int64_t>::get_array(a._data.packed_array);
- const Vector<int64_t> *arr_b = &PackedArrayRef<int64_t>::get_array(b._data.packed_array);
- int64_t sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<int64_t> v;
- v.resize(sz);
- {
- int64_t *vw = v.ptrw();
- const int64_t *ar = arr_a->ptr();
- const int64_t *br = arr_b->ptr();
-
- Variant va;
- for (int64_t i = 0; i < sz; i++) {
- Variant::interpolate(ar[i], br[i], c, va);
- vw[i] = va;
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_FLOAT32_ARRAY: {
- const Vector<float> *arr_a = &PackedArrayRef<float>::get_array(a._data.packed_array);
- const Vector<float> *arr_b = &PackedArrayRef<float>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<float> v;
- v.resize(sz);
- {
- float *vw = v.ptrw();
- const float *ar = arr_a->ptr();
- const float *br = arr_b->ptr();
-
- Variant va;
- for (int i = 0; i < sz; i++) {
- Variant::interpolate(ar[i], br[i], c, va);
- vw[i] = va;
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_FLOAT64_ARRAY: {
- const Vector<double> *arr_a = &PackedArrayRef<double>::get_array(a._data.packed_array);
- const Vector<double> *arr_b = &PackedArrayRef<double>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<double> v;
- v.resize(sz);
- {
- double *vw = v.ptrw();
- const double *ar = arr_a->ptr();
- const double *br = arr_b->ptr();
-
- Variant va;
- for (int i = 0; i < sz; i++) {
- Variant::interpolate(ar[i], br[i], c, va);
- vw[i] = va;
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_STRING_ARRAY: {
- r_dst = a;
- }
- return;
- case PACKED_VECTOR2_ARRAY: {
- const Vector<Vector2> *arr_a = &PackedArrayRef<Vector2>::get_array(a._data.packed_array);
- const Vector<Vector2> *arr_b = &PackedArrayRef<Vector2>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<Vector2> v;
- v.resize(sz);
- {
- Vector2 *vw = v.ptrw();
- const Vector2 *ar = arr_a->ptr();
- const Vector2 *br = arr_b->ptr();
-
- for (int i = 0; i < sz; i++) {
- vw[i] = ar[i].lerp(br[i], c);
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_VECTOR3_ARRAY: {
- const Vector<Vector3> *arr_a = &PackedArrayRef<Vector3>::get_array(a._data.packed_array);
- const Vector<Vector3> *arr_b = &PackedArrayRef<Vector3>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<Vector3> v;
- v.resize(sz);
- {
- Vector3 *vw = v.ptrw();
- const Vector3 *ar = arr_a->ptr();
- const Vector3 *br = arr_b->ptr();
-
- for (int i = 0; i < sz; i++) {
- vw[i] = ar[i].lerp(br[i], c);
- }
- }
- r_dst = v;
- }
- }
- return;
- case PACKED_COLOR_ARRAY: {
- const Vector<Color> *arr_a = &PackedArrayRef<Color>::get_array(a._data.packed_array);
- const Vector<Color> *arr_b = &PackedArrayRef<Color>::get_array(b._data.packed_array);
- int sz = arr_a->size();
- if (sz == 0 || arr_b->size() != sz) {
- r_dst = a;
- } else {
- Vector<Color> v;
- v.resize(sz);
- {
- Color *vw = v.ptrw();
- const Color *ar = arr_a->ptr();
- const Color *br = arr_b->ptr();
-
- for (int i = 0; i < sz; i++) {
- vw[i] = ar[i].lerp(br[i], c);
- }
- }
- r_dst = v;
- }
- }
- return;
- default: {
- r_dst = a;
- }
- }
-}
-
void Variant::_register_variant_setters_getters() {
register_named_setters_getters();
register_indexed_setters_getters();
diff --git a/doc/class.xsd b/doc/class.xsd
index 7681ddad3d..d29d053006 100644
--- a/doc/class.xsd
+++ b/doc/class.xsd
@@ -95,6 +95,8 @@
</xs:sequence>
<xs:attribute type="xs:string" name="name" use="optional" />
<xs:attribute type="xs:string" name="qualifiers" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
</xs:complexType>
</xs:element>
</xs:sequence>
@@ -114,6 +116,8 @@
<xs:attribute type="xs:string" name="overrides" use="optional" />
<xs:attribute type="xs:string" name="enum" use="optional" />
<xs:attribute type="xs:string" name="default" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
@@ -156,6 +160,8 @@
<xs:attribute type="xs:string" name="value" />
<xs:attribute type="xs:string" name="enum" use="optional" />
<xs:attribute type="xs:boolean" name="is_bitfield" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
@@ -256,6 +262,8 @@
</xs:sequence>
<xs:attribute type="xs:string" name="name" />
<xs:attribute type="xs:string" name="inherits" />
+ <xs:attribute type="xs:boolean" name="is_deprecated" use="optional" />
+ <xs:attribute type="xs:boolean" name="is_experimental" use="optional" />
<xs:attribute type="xs:float" name="version" />
</xs:complexType>
</xs:element>
diff --git a/doc/classes/AESContext.xml b/doc/classes/AESContext.xml
index 69cd54a79b..7f582e4be7 100644
--- a/doc/classes/AESContext.xml
+++ b/doc/classes/AESContext.xml
@@ -45,6 +45,7 @@
public class Example : Node
{
public AESContext Aes = new AESContext();
+
public override void _Ready()
{
string key = "My secret key!!!"; // Key must be either 16 or 32 bytes.
diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml
index b207eda27f..afbe34816a 100644
--- a/doc/classes/AnimatedSprite2D.xml
+++ b/doc/classes/AnimatedSprite2D.xml
@@ -5,6 +5,8 @@
</brief_description>
<description>
[AnimatedSprite2D] is similar to the [Sprite2D] node, except it carries multiple textures as animation frames. Animations are created using a [SpriteFrames] resource, which allows you to import image files (or a folder containing said files) to provide the animation frames for the sprite. The [SpriteFrames] resource can be configured in the editor via the SpriteFrames bottom panel.
+ After setting up [member frames], [method play] may be called. It's also possible to select an [member animation] and toggle [member playing], even within the editor.
+ To pause the current animation, call [method stop] or set [member playing] to [code]false[/code]. Alternatively, setting [member speed_scale] to [code]0[/code] also preserves the current frame's elapsed time.
[b]Note:[/b] You can associate a set of normal or specular maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] or [code]_specular[/code] suffix. For example, having 3 [SpriteFrames] resources [code]run[/code], [code]run_normal[/code], and [code]run_specular[/code] will make it so the [code]run[/code] animation uses normal and specular maps.
</description>
<tutorials>
@@ -17,13 +19,14 @@
<param index="0" name="anim" type="StringName" default="&amp;&quot;&quot;" />
<param index="1" name="backwards" type="bool" default="false" />
<description>
- Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [code]backwards[/code] is [code]true[/code], the animation will be played in reverse.
+ Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [param backwards] is [code]true[/code], the animation is played in reverse.
</description>
</method>
<method name="stop">
<return type="void" />
<description>
- Stops the current animation (does not reset the frame counter).
+ Stops the current [member animation] at the current [member frame].
+ [b]Note:[/b] This method resets the current frame's elapsed time. If this behavior is undesired, consider setting [member speed_scale] to [code]0[/code], instead.
</description>
</method>
</methods>
@@ -50,10 +53,10 @@
The texture's drawing offset.
</member>
<member name="playing" type="bool" setter="set_playing" getter="is_playing" default="false">
- If [code]true[/code], the [member animation] is currently playing.
+ If [code]true[/code], the [member animation] is currently playing. Setting this property to [code]false[/code] is the equivalent of calling [method stop].
</member>
<member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
- The animation speed is multiplied by this value.
+ The animation speed is multiplied by this value. If set to a negative value, the animation is played in reverse. If set to [code]0[/code], the animation is paused, preserving the current frame's elapsed time.
</member>
</members>
<signals>
diff --git a/doc/classes/AnimatedSprite3D.xml b/doc/classes/AnimatedSprite3D.xml
index 58d3ca6ad3..09baf882fb 100644
--- a/doc/classes/AnimatedSprite3D.xml
+++ b/doc/classes/AnimatedSprite3D.xml
@@ -4,7 +4,9 @@
2D sprite node in 3D world, that can use multiple 2D textures for animation.
</brief_description>
<description>
- Animations are created using a [SpriteFrames] resource, which can be configured in the editor via the SpriteFrames panel.
+ [AnimatedSprite3D] is similar to the [Sprite3D] node, except it carries multiple textures as animation [member frames]. Animations are created using a [SpriteFrames] resource, which allows you to import image files (or a folder containing said files) to provide the animation frames for the sprite. The [SpriteFrames] resource can be configured in the editor via the SpriteFrames bottom panel.
+ After setting up [member frames], [method play] may be called. It's also possible to select an [member animation] and toggle [member playing], even within the editor.
+ To pause the current animation, call [method stop] or set [member playing] to [code]false[/code]. Alternatively, setting [member speed_scale] to [code]0[/code] also preserves the current frame's elapsed time.
</description>
<tutorials>
<link title="2D Sprite animation (also applies to 3D)">$DOCS_URL/tutorials/2d/2d_sprite_animation.html</link>
@@ -15,13 +17,14 @@
<param index="0" name="anim" type="StringName" default="&amp;&quot;&quot;" />
<param index="1" name="backwards" type="bool" default="false" />
<description>
- Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [param backwards] is [code]true[/code], the animation will be played in reverse.
+ Plays the animation named [param anim]. If no [param anim] is provided, the current animation is played. If [param backwards] is [code]true[/code], the animation is played in reverse.
</description>
</method>
<method name="stop">
<return type="void" />
<description>
- Stops the current animation (does not reset the frame counter).
+ Stops the current [member animation] at the current [member frame].
+ [b]Note:[/b] This method resets the current frame's elapsed time. If this behavior is undesired, consider setting [member speed_scale] to [code]0[/code], instead.
</description>
</method>
</methods>
@@ -36,10 +39,10 @@
The [SpriteFrames] resource containing the animation(s).
</member>
<member name="playing" type="bool" setter="set_playing" getter="is_playing" default="false">
- If [code]true[/code], the [member animation] is currently playing.
+ If [code]true[/code], the [member animation] is currently playing. Setting this property to [code]false[/code] is the equivalent of calling [method stop].
</member>
<member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
- The animation speed is multiplied by this value.
+ The animation speed is multiplied by this value. If set to a negative value, the animation is played in reverse. If set to [code]0[/code], the animation is paused, preserving the current frame's elapsed time.
</member>
</members>
<signals>
diff --git a/doc/classes/AnimationNodeBlendTree.xml b/doc/classes/AnimationNodeBlendTree.xml
index 4c7943ece3..2a765ac8d6 100644
--- a/doc/classes/AnimationNodeBlendTree.xml
+++ b/doc/classes/AnimationNodeBlendTree.xml
@@ -87,6 +87,14 @@
The global offset of all sub-nodes.
</member>
</members>
+ <signals>
+ <signal name="node_changed">
+ <param index="0" name="node_name" type="StringName" />
+ <description>
+ Emitted when the input port information is changed.
+ </description>
+ </signal>
+ </signals>
<constants>
<constant name="CONNECTION_OK" value="0">
The connection was successful.
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index 710dc55a4b..d24703203b 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -268,6 +268,11 @@
[b]Note:[/b] This signal is not emitted if an animation is looping.
</description>
</signal>
+ <signal name="animation_list_changed">
+ <description>
+ Notifies when an animation list is changed.
+ </description>
+ </signal>
<signal name="animation_started">
<param index="0" name="anim_name" type="StringName" />
<description>
diff --git a/doc/classes/AnimationTree.xml b/doc/classes/AnimationTree.xml
index f2bf74f495..27797b00b5 100644
--- a/doc/classes/AnimationTree.xml
+++ b/doc/classes/AnimationTree.xml
@@ -54,6 +54,13 @@
The root animation node of this [AnimationTree]. See [AnimationNode].
</member>
</members>
+ <signals>
+ <signal name="animation_player_changed">
+ <description>
+ Emitted when the [member anim_player] is changed.
+ </description>
+ </signal>
+ </signals>
<constants>
<constant name="ANIMATION_PROCESS_PHYSICS" value="0" enum="AnimationProcessCallback">
The animations will progress during the physics frame (i.e. [method Node._physics_process]).
diff --git a/doc/classes/BaseMaterial3D.xml b/doc/classes/BaseMaterial3D.xml
index ee28675d89..cbb58a3e1e 100644
--- a/doc/classes/BaseMaterial3D.xml
+++ b/doc/classes/BaseMaterial3D.xml
@@ -28,7 +28,7 @@
<return type="Texture2D" />
<param index="0" name="param" type="int" enum="BaseMaterial3D.TextureParam" />
<description>
- Returns the [Texture] associated with the specified [enum TextureParam].
+ Returns the [Texture2D] associated with the specified [enum TextureParam].
</description>
</method>
<method name="set_feature">
diff --git a/doc/classes/BoneAttachment3D.xml b/doc/classes/BoneAttachment3D.xml
index dc3d448621..f29525038e 100644
--- a/doc/classes/BoneAttachment3D.xml
+++ b/doc/classes/BoneAttachment3D.xml
@@ -16,10 +16,11 @@
Returns the [NodePath] to the external [Skeleton3D] node, if one has been set.
</description>
</method>
- <method name="get_override_mode" qualifiers="const">
+ <method name="get_override_mode" qualifiers="const" is_deprecated="true">
<return type="int" />
<description>
- Returns the override mode for the BoneAttachment3D node.
+ Deprecated. Local pose overrides will be removed.
+ Returns the override mode for the BoneAttachment3D node (0=global / 1=local).
</description>
</method>
<method name="get_override_pose" qualifiers="const">
@@ -48,11 +49,12 @@
Sets the [NodePath] to the external skeleton that the BoneAttachment3D node should use. The external [Skeleton3D] node is only used when [code]use_external_skeleton[/code] is set to [code]true[/code].
</description>
</method>
- <method name="set_override_mode">
+ <method name="set_override_mode" is_deprecated="true">
<return type="void" />
<param index="0" name="override_mode" type="int" />
<description>
- Sets the override mode for the BoneAttachment3D node. The override mode defines which of the bone poses the BoneAttachment3D node will override.
+ Deprecated. Local pose overrides will be removed.
+ Sets the override mode for the BoneAttachment3D node (0=global / 1=local). The override mode defines which of the bone poses the BoneAttachment3D node will override.
</description>
</method>
<method name="set_override_pose">
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index 70d825efac..d74f49c897 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -310,16 +310,16 @@
# If using this method in a script that redraws constantly, move the
# `default_font` declaration to a member variable assigned in `_ready()`
# so the Control is only created once.
- var default_font = Control.new().get_font("font")
- var default_font_size = Control.new().get_font_size("font_size")
- draw_string(default_font, Vector2(64, 64), "Hello world", HORIZONTAL_ALIGNMENT_LEFT, -1, font_size)
+ var default_font = ThemeDB.fallback_font
+ var default_font_size = ThemeDB.fallback_font_size
+ draw_string(default_font, Vector2(64, 64), "Hello world", HORIZONTAL_ALIGNMENT_LEFT, -1, default_font_size)
[/gdscript]
[csharp]
// If using this method in a script that redraws constantly, move the
- // `default_font` declaration to a member variable assigned in `_ready()`
+ // `default_font` declaration to a member variable assigned in `_Ready()`
// so the Control is only created once.
- Font defaultFont = new Control().GetFont("font");
- int defaultFontSize = new Control().GetFontSize("font_size");
+ Font defaultFont = ThemeDB.FallbackFont;
+ int defaultFontSize = ThemeDB.FallbackFontSize;
DrawString(defaultFont, new Vector2(64, 64), "Hello world", HORIZONTAL_ALIGNMENT_LEFT, -1, defaultFontSize);
[/csharp]
[/codeblocks]
diff --git a/doc/classes/Cubemap.xml b/doc/classes/Cubemap.xml
index 7173388027..0cdebeda95 100644
--- a/doc/classes/Cubemap.xml
+++ b/doc/classes/Cubemap.xml
@@ -4,9 +4,9 @@
6-sided texture typically used in 3D rendering.
</brief_description>
<description>
- A cubemap is a 6-sided texture typically used for faking reflections in 3D rendering. It can be used to make an object look as if it's reflecting its surroundings. This usually delivers much better performance than other reflection methods.
+ A cubemap is made of 6 textures organized in layers. They are typically used for faking reflections (see [ReflectionProbe]) in 3D rendering. It can be used to make an object look as if it's reflecting its surroundings. This usually delivers much better performance than other reflection methods.
This resource is typically used as a uniform in custom shaders. Few core Godot methods make use of Cubemap resources.
- [b]Note:[/b] Godot doesn't support using cubemaps as a [PanoramaSkyMaterial]. You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cube map to an equirectangular sky map.
+ [b]Note:[/b] Godot doesn't support using cubemaps in a [PanoramaSkyMaterial]. You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cubemap to an equirectangular sky map.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/CubemapArray.xml b/doc/classes/CubemapArray.xml
index 4fca842b5a..7f001155e4 100644
--- a/doc/classes/CubemapArray.xml
+++ b/doc/classes/CubemapArray.xml
@@ -1,8 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="CubemapArray" inherits="ImageTextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ A single composite texture resource which consists of multiple [Cubemap]s.
</brief_description>
<description>
+ [CubemapArray]s are made of an array of [Cubemap]s. Accordingly, like [Cubemap]s they are made of multiple textures the amount of which must be divisible by 6 (one image for each face of the cube). The primary benefit of [CubemapArray]s is that they can be accessed in shader code using a single texture reference. In other words, you can pass multiple [Cubemap]s into a shader using a single [CubemapArray].
+ Generally, [CubemapArray]s provide a more efficent way for storing multiple [Cubemap]s, than storing multiple [Cubemap]s themselves in an array.
+ Internally Godot, uses [CubemapArray]s for many effects including the [Sky], if you set [member ProjectSettings.rendering/reflections/sky_reflections/texture_array_reflections] to [code]true[/code].
+ [b]Note:[/b] [CubemapArray] is not supported in the OpenGL 3 rendering backend.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 8f4c848041..27cf410c15 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -237,7 +237,7 @@
# You can use a custom icon:
return preload("res://addons/my_plugin/my_plugin_icon.svg")
# Or use a built-in icon:
- return get_editor_interface().get_base_control().get_icon("Node", "EditorIcons")
+ return get_editor_interface().get_base_control().get_theme_icon("Node", "EditorIcons")
[/gdscript]
[csharp]
public override Texture2D GetPluginIcon()
@@ -245,7 +245,7 @@
// You can use a custom icon:
return ResourceLoader.Load&lt;Texture2D&gt;("res://addons/my_plugin/my_plugin_icon.svg");
// Or use a built-in icon:
- return GetEditorInterface().GetBaseControl().GetIcon("Node", "EditorIcons");
+ return GetEditorInterface().GetBaseControl().GetThemeIcon("Node", "EditorIcons");
}
[/csharp]
[/codeblocks]
diff --git a/doc/classes/Environment.xml b/doc/classes/Environment.xml
index 695f2cbc66..34a639d2de 100644
--- a/doc/classes/Environment.xml
+++ b/doc/classes/Environment.xml
@@ -86,7 +86,7 @@
This is useful to simulate [url=https://en.wikipedia.org/wiki/Aerial_perspective]aerial perspective[/url] in large scenes with low density fog. However, it is not very useful for high-density fog, as the sky will shine through. When set to [code]1.0[/code], the fog color comes completely from the [Sky]. If set to [code]0.0[/code], aerial perspective is disabled.
</member>
<member name="fog_density" type="float" setter="set_fog_density" getter="get_fog_density" default="0.01">
- The exponential fog density to use. Higher values result in a more dense fog.
+ The [i]exponential[/i] fog density to use. Higher values result in a more dense fog. Fog rendering is exponential as in real life.
</member>
<member name="fog_enabled" type="bool" setter="set_fog_enabled" getter="is_fog_enabled" default="false">
If [code]true[/code], fog effects are enabled.
@@ -292,13 +292,15 @@
The [Color] of the volumetric fog when interacting with lights. Mist and fog have an albedo close to [code]Color(1, 1, 1, 1)[/code] while smoke has a darker albedo.
</member>
<member name="volumetric_fog_ambient_inject" type="float" setter="set_volumetric_fog_ambient_inject" getter="get_volumetric_fog_ambient_inject" default="0.0">
- Scales the strength of ambient light used in the volumetric fog. A value of [code]0[/code] means that ambient light will not impact the volumetric fog.
+ Scales the strength of ambient light used in the volumetric fog. A value of [code]0.0[/code] means that ambient light will not impact the volumetric fog. [member volumetric_fog_ambient_inject] has a small performance cost when set above [code]0.0[/code].
+ [b]Note:[/b] This has no visible effect if [member volumetric_fog_density] is [code]0.0[/code] or if [member volumetric_fog_albedo] is a fully black color.
</member>
<member name="volumetric_fog_anisotropy" type="float" setter="set_volumetric_fog_anisotropy" getter="get_volumetric_fog_anisotropy" default="0.2">
- The direction of scattered light as it goes through the volumetric fog. A value close [code]1[/code] means almost all light is scattered forward. A value close to [code]0[/code] means light is scattered equally in all directions. A value close to [code]-1[/code] means light is scattered mostly backward. Fog and mist scatter light slightly forward, while smoke scatters light equally in all directions.
+ The direction of scattered light as it goes through the volumetric fog. A value close to [code]1.0[/code] means almost all light is scattered forward. A value close to [code]0.0[/code] means light is scattered equally in all directions. A value close to [code]-1.0[/code] means light is scattered mostly backward. Fog and mist scatter light slightly forward, while smoke scatters light equally in all directions.
</member>
<member name="volumetric_fog_density" type="float" setter="set_volumetric_fog_density" getter="get_volumetric_fog_density" default="0.05">
- The base density of the volumetric fog. Set this to the lowest density you want to have globally.
+ The base [i]exponential[/i] density of the volumetric fog. Set this to the lowest density you want to have globally. [FogVolume]s can be used to add to or subtract from this density in specific areas. Fog rendering is exponential as in real life.
+ A value of [code]0.0[/code] disables global volumetric fog while allowing [FogVolume]s to display volumetric fog in specific areas.
</member>
<member name="volumetric_fog_detail_spread" type="float" setter="set_volumetric_fog_detail_spread" getter="get_volumetric_fog_detail_spread" default="2.0">
The distribution of size down the length of the froxel buffer. A higher value compresses the froxels closer to the camera and places more detail closer to the camera.
@@ -313,20 +315,22 @@
Enables the volumetric fog effect. Volumetric fog uses a screen-aligned froxel buffer to calculate accurate volumetric scattering in the short to medium range. Volumetric fog interacts with [FogVolume]s and lights to calculate localized and global fog. Volumetric fog uses a PBR single-scattering model based on extinction, scattering, and emission which it exposes to users as density, albedo, and emission.
</member>
<member name="volumetric_fog_gi_inject" type="float" setter="set_volumetric_fog_gi_inject" getter="get_volumetric_fog_gi_inject" default="1.0">
- Scales the strength of Global Illumination used in the volumetric fog. A value of [code]0.0[/code] means that Global Illumination will not impact the volumetric fog.
+ Scales the strength of Global Illumination used in the volumetric fog's albedo color. A value of [code]0.0[/code] means that Global Illumination will not impact the volumetric fog. [member volumetric_fog_gi_inject] has a small performance cost when set above [code]0.0[/code].
+ [b]Note:[/b] This has no visible effect if [member volumetric_fog_density] is [code]0.0[/code] or if [member volumetric_fog_albedo] is a fully black color.
[b]Note:[/b] Only [VoxelGI] and SDFGI ([member Environment.sdfgi_enabled]) are taken into account when using [member volumetric_fog_gi_inject]. Global illumination from [LightmapGI], [ReflectionProbe] and SSIL (see [member ssil_enabled]) will be ignored by volumetric fog.
</member>
<member name="volumetric_fog_length" type="float" setter="set_volumetric_fog_length" getter="get_volumetric_fog_length" default="64.0">
- The distance over which the volumetric fog is computed. Increase to compute fog over a greater range, decrease to add more detail when a long range is not needed. For best quality fog, keep this as low as possible.
+ The distance over which the volumetric fog is computed. Increase to compute fog over a greater range, decrease to add more detail when a long range is not needed. For best quality fog, keep this as low as possible. See also [member ProjectSettings.rendering/environment/volumetric_fog/volume_depth].
</member>
<member name="volumetric_fog_sky_affect" type="float" setter="set_volumetric_fog_sky_affect" getter="get_volumetric_fog_sky_affect" default="1.0">
The factor to use when affecting the sky with volumetric fog. [code]1.0[/code] means that volumetric fog can fully obscure the sky. Lower values reduce the impact of volumetric fog on sky rendering, with [code]0.0[/code] not affecting sky rendering at all.
+ [b]Note:[/b] [member volumetric_fog_sky_affect] also affects [FogVolume]s, even if [member volumetric_fog_density] is [code]0.0[/code]. If you notice [FogVolume]s are disappearing when looking towards the sky, set [member volumetric_fog_sky_affect] to [code]1.0[/code].
</member>
<member name="volumetric_fog_temporal_reprojection_amount" type="float" setter="set_volumetric_fog_temporal_reprojection_amount" getter="get_volumetric_fog_temporal_reprojection_amount" default="0.9">
The amount by which to blend the last frame with the current frame. A higher number results in smoother volumetric fog, but makes "ghosting" much worse. A lower value reduces ghosting but can result in the per-frame temporal jitter becoming visible.
</member>
<member name="volumetric_fog_temporal_reprojection_enabled" type="bool" setter="set_volumetric_fog_temporal_reprojection_enabled" getter="is_volumetric_fog_temporal_reprojection_enabled" default="true">
- Enables temporal reprojection in the volumetric fog. Temporal reprojection blends the current frame's volumetric fog with the last frame's volumetric fog to smooth out jagged edges. The performance cost is minimal, however it does lead to moving [FogVolume]s and [Light3D]s "ghosting" and leaving a trail behind them. When temporal reprojection is enabled, try to avoid moving [FogVolume]s or [Light3D]s too fast.
+ Enables temporal reprojection in the volumetric fog. Temporal reprojection blends the current frame's volumetric fog with the last frame's volumetric fog to smooth out jagged edges. The performance cost is minimal; however, it leads to moving [FogVolume]s and [Light3D]s "ghosting" and leaving a trail behind them. When temporal reprojection is enabled, try to avoid moving [FogVolume]s or [Light3D]s too fast. Short-lived dynamic lighting effects should have [member Light3D.light_volumetric_fog_energy] set to [code]0.0[/code] to avoid ghosting.
</member>
</members>
<constants>
diff --git a/doc/classes/FogMaterial.xml b/doc/classes/FogMaterial.xml
index e63d4ddf3e..7428d6169a 100644
--- a/doc/classes/FogMaterial.xml
+++ b/doc/classes/FogMaterial.xml
@@ -5,27 +5,28 @@
</brief_description>
<description>
A [Material] resource that can be used by [FogVolume]s to draw volumetric effects.
+ If you need more advanced effects, use a custom [url=$DOCS_URL/tutorials/shaders/shader_reference/fog_shader.html]fog shader[/url].
</description>
<tutorials>
</tutorials>
<members>
<member name="albedo" type="Color" setter="set_albedo" getter="get_albedo" default="Color(1, 1, 1, 1)">
- Sets the single-scattering [Color] of the [FogVolume]. Internally [member albedo] is converted into single-scattering which is additively blended with other [FogVolume]s and the [member Environment.volumetric_fog_albedo].
+ The single-scattering [Color] of the [FogVolume]. Internally, [member albedo] is converted into single-scattering, which is additively blended with other [FogVolume]s and the [member Environment.volumetric_fog_albedo].
</member>
<member name="density" type="float" setter="set_density" getter="get_density" default="1.0">
- Sets the density of the [FogVolume]. Denser objects are more opaque, but may suffer from under-sampling artifacts that look like stripes.
+ The density of the [FogVolume]. Denser objects are more opaque, but may suffer from under-sampling artifacts that look like stripes. Negative values can be used to subtract fog from other [FogVolume]s or global volumetric fog.
</member>
<member name="density_texture" type="Texture3D" setter="set_density_texture" getter="get_density_texture">
- Sets a 3D texture that is used to scale the [member density] of the [FogVolume].
+ The 3D texture that is used to scale the [member density] of the [FogVolume]. This can be used to vary fog density within the [FogVolume] with any kind of static pattern. For animated effects, consider using a custom [url=$DOCS_URL/tutorials/shaders/shader_reference/fog_shader.html]fog shader[/url].
</member>
<member name="edge_fade" type="float" setter="set_edge_fade" getter="get_edge_fade" default="0.1">
- Sets the hardness of the edges of the [FogVolume]. A higher number will result in softer edges while a lower number will result in harder edges.
+ The hardness of the edges of the [FogVolume]. A higher value will result in softer edges, while a lower value will result in harder edges.
</member>
<member name="emission" type="Color" setter="set_emission" getter="get_emission" default="Color(0, 0, 0, 1)">
- Sets the [Color] of the light emitted by the [FogVolume]. Emitted light will not cast light or shadows on other objects, but can be useful for modulating the [Color] of the [FogVolume] independently from light sources.
+ The [Color] of the light emitted by the [FogVolume]. Emitted light will not cast light or shadows on other objects, but can be useful for modulating the [Color] of the [FogVolume] independently from light sources.
</member>
<member name="height_falloff" type="float" setter="set_height_falloff" getter="get_height_falloff" default="0.0">
- Sets the rate by which the height-based fog decreases in density as height increases in world space. A high falloff will result in a sharp transition, while a low falloff will result in a smoother transition. A value of [code]0[/code] results in uniform-density fog. The height threshold is determined by the height of the associated [FogVolume].
+ The rate by which the height-based fog decreases in density as height increases in world space. A high falloff will result in a sharp transition, while a low falloff will result in a smoother transition. A value of [code]0.0[/code] results in uniform-density fog. The height threshold is determined by the height of the associated [FogVolume].
</member>
</members>
</class>
diff --git a/doc/classes/FogVolume.xml b/doc/classes/FogVolume.xml
index 3f2ee3035c..d9fa2e6ebb 100644
--- a/doc/classes/FogVolume.xml
+++ b/doc/classes/FogVolume.xml
@@ -4,22 +4,23 @@
A node used to add local fog with the volumetric fog effect.
</brief_description>
<description>
- [FogVolume]s are used to add localized fog into the global volumetric fog effect.
+ [FogVolume]s are used to add localized fog into the global volumetric fog effect. [FogVolume]s can also remove volumetric fog from specific areas if using a [FogMaterial] with a negative [member FogMaterial.density].
Performance of [FogVolume]s is directly related to their relative size on the screen and the complexity of their attached [FogMaterial]. It is best to keep [FogVolume]s relatively small and simple where possible.
+ [b]Note:[/b] [FogVolume]s only have a visible effect if [member Environment.volumetric_fog_enabled] is [code]true[/code]. If you don't want fog to be globally visible (but only within [FogVolume] nodes), set [member Environment.volumetric_fog_density] to [code]0.0[/code].
</description>
<tutorials>
</tutorials>
<members>
<member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)">
- Sets the size of the [FogVolume] when [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX].
+ The size of the [FogVolume] when [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER] or [constant RenderingServer.FOG_VOLUME_SHAPE_BOX].
[b]Note:[/b] Thin fog volumes may appear to flicker when the camera moves or rotates. This can be alleviated by increasing [member ProjectSettings.rendering/environment/volumetric_fog/volume_depth] (at a performance cost) or by decreasing [member Environment.volumetric_fog_length] (at no performance cost, but at the cost of lower fog range). Alternatively, the [FogVolume] can be made thicker and use a lower density in the [member material].
[b]Note:[/b] If [member shape] is [constant RenderingServer.FOG_VOLUME_SHAPE_CONE] or [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], the cone/cylinder will be adjusted to fit within the extents. Non-uniform scaling of cone/cylinder shapes via the [member extents] property is not supported, but you can scale the [FogVolume] node instead.
</member>
<member name="material" type="Material" setter="set_material" getter="get_material">
- Sets the [Material] to be used by the [FogVolume]. Can be either a [FogMaterial] or a custom [ShaderMaterial].
+ The [Material] used by the [FogVolume]. Can be either a built-in [FogMaterial] or a custom [ShaderMaterial].
</member>
<member name="shape" type="int" setter="set_shape" getter="get_shape" enum="RenderingServer.FogVolumeShape" default="3">
- Sets the shape of the [FogVolume] to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD].
+ The shape of the [FogVolume]. This can be set to either [constant RenderingServer.FOG_VOLUME_SHAPE_ELLIPSOID], [constant RenderingServer.FOG_VOLUME_SHAPE_CONE], [constant RenderingServer.FOG_VOLUME_SHAPE_CYLINDER], [constant RenderingServer.FOG_VOLUME_SHAPE_BOX] or [constant RenderingServer.FOG_VOLUME_SHAPE_WORLD].
</member>
</members>
</class>
diff --git a/doc/classes/HMACContext.xml b/doc/classes/HMACContext.xml
index 52d4fce28f..706ee30963 100644
--- a/doc/classes/HMACContext.xml
+++ b/doc/classes/HMACContext.xml
@@ -32,22 +32,22 @@
public class CryptoNode : Node
{
private HMACContext ctx = new HMACContext();
+
public override void _Ready()
{
- PackedByteArray key = String("supersecret").to_utf8();
- Error err = ctx.Start(HashingContext.HASH_SHA256, key);
- GD.Assert(err == OK);
- PackedByteArray msg1 = String("this is ").to_utf8();
- PackedByteArray msg2 = String("super duper secret").to_utf8();
+ byte[] key = "supersecret".ToUTF8();
+ Error err = ctx.Start(HashingContext.HashType.Sha256, key);
+ Debug.Assert(err == Error.Ok);
+ byte[] msg1 = "this is ".ToUTF8();
+ byte[] msg2 = "super duper secret".ToUTF8();
err = ctx.Update(msg1);
- GD.Assert(err == OK);
+ Debug.Assert(err == Error.Ok);
err = ctx.Update(msg2);
- GD.Assert(err == OK);
- PackedByteArray hmac = ctx.Finish();
+ Debug.Assert(err == Error.Ok);
+ byte[] hmac = ctx.Finish();
GD.Print(hmac.HexEncode());
}
}
-
[/csharp]
[/codeblocks]
</description>
diff --git a/doc/classes/ImageTextureLayered.xml b/doc/classes/ImageTextureLayered.xml
index f5b338542b..f5786f070a 100644
--- a/doc/classes/ImageTextureLayered.xml
+++ b/doc/classes/ImageTextureLayered.xml
@@ -11,6 +11,8 @@
<return type="int" enum="Error" />
<param index="0" name="images" type="Image[]" />
<description>
+ Creates an [ImageTextureLayered] from an array of [Image]s. The first image decides the width, height, image format and mipmapping setting. The other images must have the same width, height, image format and mipmapping setting.
+ Each [Image] represents one [code]layer[/code].
</description>
</method>
<method name="update_layer">
@@ -18,6 +20,10 @@
<param index="0" name="image" type="Image" />
<param index="1" name="layer" type="int" />
<description>
+ Replaces the existing [Image] data at the given [code]layer[/code] with this new image.
+ The given [Image] must have the same width, height, image format and mipmapping setting (a [code]bool[/code] value) as the rest of the referenced images.
+ If the image format is unsupported, it will be decompressed and converted to a similar and supported [enum Image.Format].
+ The update is immediate: synced with the draw.
</description>
</method>
</methods>
diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml
index 46e46cc164..38ddca2727 100644
--- a/doc/classes/JSON.xml
+++ b/doc/classes/JSON.xml
@@ -6,7 +6,7 @@
<description>
The [JSON] enables all data types to be converted to and from a JSON string. This useful for serializing data to save to a file or send over the network.
[method stringify] is used to convert any data type into a JSON string.
- [method parse] is used to convert any existing JSON data into a [Variant] that can be used within Godot. If successfully parsed, use [method get_data] to retrieve the [Variant], and use [code]typeof[/code] to check if the Variant's type is what you expect. JSON Objects are converted into a [Dictionary], but JSON data can be used to store [Array]s, numbers, [String]s and even just a boolean.
+ [method parse] is used to convert any existing JSON data into a [Variant] that can be used within Godot. If successfully parsed, use [member data] to retrieve the [Variant], and use [code]typeof[/code] to check if the Variant's type is what you expect. JSON Objects are converted into a [Dictionary], but JSON data can be used to store [Array]s, numbers, [String]s and even just a boolean.
[b]Example[/b]
[codeblock]
var data_to_send = ["a", "b", "c"]
@@ -16,7 +16,7 @@
# Retrieve data
var error = json.parse(json_string)
if error == OK:
- var data_received = json.get_data()
+ var data_received = json.data
if typeof(data_received) == TYPE_ARRAY:
print(data_received) # Prints array
else:
@@ -32,13 +32,6 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_data" qualifiers="const">
- <return type="Variant" />
- <description>
- Returns the [Variant] containing the data of a successful [method parse].
- [b]Note:[/b] It will return [code]Null[/code] if the last call to parse was unsuccessful or [method parse] has not yet been called.
- </description>
- </method>
<method name="get_error_line" qualifiers="const">
<return type="int" />
<description>
@@ -56,7 +49,7 @@
<param index="0" name="json_string" type="String" />
<description>
Attempts to parse the [param json_string] provided.
- Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] and the result can be retrieved using [method get_data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure.
+ Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] and the result can be retrieved using [member data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure.
Non-static variant of [method parse_string], if you want custom error handling.
</description>
</method>
@@ -118,4 +111,9 @@
</description>
</method>
</methods>
+ <members>
+ <member name="data" type="Variant" setter="set_data" getter="get_data" default="null">
+ Contains the parsed JSON data in [Variant] form.
+ </member>
+ </members>
</class>
diff --git a/doc/classes/LightmapGI.xml b/doc/classes/LightmapGI.xml
index dd8c7be489..53dae1a8e6 100644
--- a/doc/classes/LightmapGI.xml
+++ b/doc/classes/LightmapGI.xml
@@ -17,7 +17,7 @@
<member name="bias" type="float" setter="set_bias" getter="get_bias" default="0.0005">
The bias to use when computing shadows. Increasing [member bias] can fix shadow acne on the resulting baked lightmap, but can introduce peter-panning (shadows not connecting to their casters). Real-time [Light3D] shadows are not affected by this [member bias] property.
</member>
- <member name="bounces" type="int" setter="set_bounces" getter="get_bounces" default="1">
+ <member name="bounces" type="int" setter="set_bounces" getter="get_bounces" default="3">
Number of light bounces that are taken into account during baking. Higher values result in brighter, more realistic lighting, at the cost of longer bake times. If set to [code]0[/code], only environment lighting, direct light and emissive lighting is baked.
</member>
<member name="camera_attributes" type="CameraAttributes" setter="set_camera_attributes" getter="get_camera_attributes">
@@ -36,10 +36,10 @@
<member name="environment_custom_sky" type="Sky" setter="set_environment_custom_sky" getter="get_environment_custom_sky">
The sky to use as a source of environment lighting. Only effective if [member environment_mode] is [constant ENVIRONMENT_MODE_CUSTOM_SKY].
</member>
- <member name="environment_mode" type="int" setter="set_environment_mode" getter="get_environment_mode" enum="LightmapGI.EnvironmentMode" default="0">
+ <member name="environment_mode" type="int" setter="set_environment_mode" getter="get_environment_mode" enum="LightmapGI.EnvironmentMode" default="1">
The environment mode to use when baking lightmaps.
</member>
- <member name="generate_probes_subdiv" type="int" setter="set_generate_probes" getter="get_generate_probes" enum="LightmapGI.GenerateProbes" default="0">
+ <member name="generate_probes_subdiv" type="int" setter="set_generate_probes" getter="get_generate_probes" enum="LightmapGI.GenerateProbes" default="2">
The level of subdivision to use when automatically generating [LightmapProbe]s for dynamic object lighting. Higher values result in more accurate indirect lighting on dynamic objects, at the cost of longer bake times and larger file sizes.
[b]Note:[/b] Automatically generated [LightmapProbe]s are not visible as nodes in the Scene tree dock, and cannot be modified this way after they are generated.
[b]Note:[/b] Regardless of [member generate_probes_subdiv], direct lighting on dynamic objects is always applied using [Light3D] nodes in real-time.
diff --git a/doc/classes/MultiMesh.xml b/doc/classes/MultiMesh.xml
index bae2335cfb..ce2b5f2584 100644
--- a/doc/classes/MultiMesh.xml
+++ b/doc/classes/MultiMesh.xml
@@ -1,13 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="MultiMesh" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Provides high-performance mesh instancing.
+ Provides high-performance drawing of a mesh multiple times using GPU instancing.
</brief_description>
<description>
MultiMesh provides low-level mesh instancing. Drawing thousands of [MeshInstance3D] nodes can be slow, since each object is submitted to the GPU then drawn individually.
MultiMesh is much faster as it can draw thousands of instances with a single draw call, resulting in less API overhead.
As a drawback, if the instances are too far away from each other, performance may be reduced as every single instance will always render (they are spatially indexed as one, for the whole object).
Since instances may have any behavior, the AABB used for visibility must be provided by the user.
+ [b]Note:[/b] A MultiMesh is a single object, therefore the same maximum lights per object restriction applies. This means, that once the maximum lights are consumed by one or more instances, the rest of the MultiMesh instances will [b]not[/b] receive any lighting.
+ [b]Note:[/b] Blend Shapes will be ignored if used in a MultiMesh.
</description>
<tutorials>
<link title="Animating thousands of fish with MultiMeshInstance">$DOCS_URL/tutorials/performance/vertex_animation/animating_thousands_of_fish.html</link>
@@ -24,7 +26,7 @@
<return type="Color" />
<param index="0" name="instance" type="int" />
<description>
- Gets a specific instance's color.
+ Gets a specific instance's color multiplier.
</description>
</method>
<method name="get_instance_custom_data" qualifiers="const">
@@ -53,8 +55,8 @@
<param index="0" name="instance" type="int" />
<param index="1" name="color" type="Color" />
<description>
- Sets the color of a specific instance by [i]multiplying[/i] the mesh's existing vertex colors.
- For the color to take effect, ensure that [member use_colors] is [code]true[/code] on the [MultiMesh] and [member BaseMaterial3D.vertex_color_use_as_albedo] is [code]true[/code] on the material. If the color doesn't look as expected, make sure the material's albedo color is set to pure white ([code]Color(1, 1, 1)[/code]).
+ Sets the color of a specific instance by [i]multiplying[/i] the mesh's existing vertex colors. This allows for different color tinting per instance.
+ For the color to take effect, ensure that [member use_colors] is [code]true[/code] on the [MultiMesh] and [member BaseMaterial3D.vertex_color_use_as_albedo] is [code]true[/code] on the material. If you intend to set an absolute color instead of tinting, make sure the material's albedo color is set to pure white ([code]Color(1, 1, 1)[/code]).
</description>
</method>
<method name="set_instance_custom_data">
@@ -64,6 +66,7 @@
<description>
Sets custom data for a specific instance. Although [Color] is used, it is just a container for 4 floating point numbers.
For the custom data to be used, ensure that [member use_custom_data] is [code]true[/code].
+ This custom instance data has to be manually accessed in your custom shader using [code]INSTANCE_CUSTOM[/code].
</description>
</method>
<method name="set_instance_transform">
@@ -87,28 +90,33 @@
<member name="buffer" type="PackedFloat32Array" setter="set_buffer" getter="get_buffer" default="PackedFloat32Array()">
</member>
<member name="color_array" type="PackedColorArray" setter="_set_color_array" getter="_get_color_array">
+ See [method set_instance_color].
</member>
<member name="custom_data_array" type="PackedColorArray" setter="_set_custom_data_array" getter="_get_custom_data_array">
+ See [method set_instance_custom_data].
</member>
<member name="instance_count" type="int" setter="set_instance_count" getter="get_instance_count" default="0">
Number of instances that will get drawn. This clears and (re)sizes the buffers. Setting data format or flags afterwards will have no effect.
By default, all instances are drawn but you can limit this with [member visible_instance_count].
</member>
<member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
- Mesh to be drawn.
+ [Mesh] resource to be instanced.
+ The looks of the individual instances can be modified using [method set_instance_color] and [method set_instance_custom_data].
</member>
<member name="transform_2d_array" type="PackedVector2Array" setter="_set_transform_2d_array" getter="_get_transform_2d_array">
+ See [method set_instance_transform_2d].
</member>
<member name="transform_array" type="PackedVector3Array" setter="_set_transform_array" getter="_get_transform_array">
+ See [method set_instance_transform].
</member>
<member name="transform_format" type="int" setter="set_transform_format" getter="get_transform_format" enum="MultiMesh.TransformFormat" default="0">
Format of transform used to transform mesh, either 2D or 3D.
</member>
<member name="use_colors" type="bool" setter="set_use_colors" getter="is_using_colors" default="false">
- If [code]true[/code], the [MultiMesh] will use color data (see [member color_array]).
+ If [code]true[/code], the [MultiMesh] will use color data (see [method set_instance_color]). Can only be set when [member instance_count] is [code]0[/code] or less. This means that you need to call this method before setting the instance count, or temporarily reset it to [code]0[/code].
</member>
<member name="use_custom_data" type="bool" setter="set_use_custom_data" getter="is_using_custom_data" default="false">
- If [code]true[/code], the [MultiMesh] will use custom data (see [member custom_data_array]).
+ If [code]true[/code], the [MultiMesh] will use custom data (see [method set_instance_custom_data]). Can only be set when [member instance_count] is [code]0[/code] or less. This means that you need to call this method before setting the instance count, or temporarily reset it to [code]0[/code].
</member>
<member name="visible_instance_count" type="int" setter="set_visible_instance_count" getter="get_visible_instance_count" default="-1">
Limits the number of instances drawn, -1 draws all instances. Changing this does not change the sizes of the buffers.
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 059766656f..54f31d7918 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -216,6 +216,15 @@
Not to be confused with [method get_user_data_dir], which returns the [i]project-specific[/i] user data path.
</description>
</method>
+ <method name="get_distribution_name" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the name of the distribution for Linux and BSD platforms (e.g. Ubuntu, Manjaro, OpenBSD, etc.).
+ Returns the same value as [method get_name] for stock Android ROMs, but attempts to return the custom ROM name for popular Android derivatives such as LineageOS.
+ Returns the same value as [method get_name] for other platforms.
+ [b]Note:[/b] This method is not supported on the web platform. It returns an empty string.
+ </description>
+ </method>
<method name="get_environment" qualifiers="const">
<return type="String" />
<param index="0" name="variable" type="String" />
@@ -430,6 +439,18 @@
Not to be confused with [method get_data_dir], which returns the [i]global[/i] (non-project-specific) user home directory.
</description>
</method>
+ <method name="get_version" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the exact production and build version of the operating system. This is different from the branded version used in marketing. This helps to distinguish between different releases of operating systems, including minor versions, and insider and custom builds.
+ For Windows, the major and minor version are returned, as well as the build number. For example, the returned string can look like [code]10.0.9926[/code] for a build of Windows 10, and it can look like [code]6.1.7601[/code] for a build of Windows 7 SP1.
+ For rolling distributions, such as Arch Linux, an empty string is returned.
+ For macOS and iOS, the major and minor version are returned, as well as the patch number.
+ For UWP, the device family version is returned.
+ For Android, the SDK version and the incremental build number are returned. If it's a custom ROM, it attempts to return its version instead.
+ [b]Note:[/b] This method is not supported on the web platform. It returns an empty string.
+ </description>
+ </method>
<method name="has_environment" qualifiers="const">
<return type="bool" />
<param index="0" name="variable" type="String" />
diff --git a/doc/classes/PanoramaSkyMaterial.xml b/doc/classes/PanoramaSkyMaterial.xml
index 21c7f29585..0c27037f28 100644
--- a/doc/classes/PanoramaSkyMaterial.xml
+++ b/doc/classes/PanoramaSkyMaterial.xml
@@ -4,9 +4,9 @@
A [Material] used with [Sky] to draw a background texture.
</brief_description>
<description>
- A resource referenced in a [Sky] that is used to draw a background. The Panorama sky material functions similar to skyboxes in other engines, except it uses an equirectangular sky map instead of a cube map.
+ A resource referenced in a [Sky] that is used to draw a background. The Panorama sky material functions similar to skyboxes in other engines, except it uses an equirectangular sky map instead of a cubemap.
Using an HDR panorama is strongly recommended for accurate, high-quality reflections. Godot supports the Radiance HDR ([code].hdr[/code]) and OpenEXR ([code].exr[/code]) image formats for this purpose.
- You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cube map to an equirectangular sky map.
+ You can use [url=https://danilw.github.io/GLSL-howto/cubemap_to_panorama_js/cubemap_to_panorama.html]this tool[/url] to convert a cubemap to an equirectangular sky map.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 1f07a13c94..ffd3dbaf80 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1782,7 +1782,7 @@
Enables filtering of the volumetric fog effect prior to integration. This substantially blurs the fog which reduces fine details but also smooths out harsh edges and aliasing artifacts. Disable when more detail is required.
</member>
<member name="rendering/environment/volumetric_fog/volume_depth" type="int" setter="" getter="" default="64">
- Number of slices to use along the depth of the froxel buffer for volumetric fog. A lower number will be more efficient but may result in artifacts appearing during camera movement.
+ Number of slices to use along the depth of the froxel buffer for volumetric fog. A lower number will be more efficient but may result in artifacts appearing during camera movement. See also [member Environment.volumetric_fog_length].
</member>
<member name="rendering/environment/volumetric_fog/volume_size" type="int" setter="" getter="" default="64">
Base size used to determine size of froxel buffer in the camera X-axis and Y-axis. The final size is scaled by the aspect ratio of the screen, so actual values may differ from what is set. Set a larger size for more detailed fog, set a smaller size for better performance.
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index 5a0766263a..3bd0e04b92 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -32,9 +32,10 @@
Removes the global pose override on all bones in the skeleton.
</description>
</method>
- <method name="clear_bones_local_pose_override">
+ <method name="clear_bones_local_pose_override" is_deprecated="true">
<return type="void" />
<description>
+ Deprecated. Local pose overrides will be removed.
Removes the local pose override on all bones in the skeleton.
</description>
</method>
@@ -43,7 +44,7 @@
<description>
</description>
</method>
- <method name="execute_modifications">
+ <method name="execute_modifications" is_deprecated="true">
<return type="void" />
<param index="0" name="delta" type="float" />
<param index="1" name="execution_mode" type="int" />
@@ -58,7 +59,7 @@
Returns the bone index that matches [param name] as its name.
</description>
</method>
- <method name="force_update_all_bone_transforms">
+ <method name="force_update_all_bone_transforms" is_deprecated="true">
<return type="void" />
<description>
Force updates the bone transforms/poses for all bones in the skeleton.
@@ -166,7 +167,7 @@
Returns the rest transform for a bone [param bone_idx].
</description>
</method>
- <method name="get_modification_stack">
+ <method name="get_modification_stack" is_deprecated="true">
<return type="SkeletonModificationStack3D" />
<description>
Returns the modification stack attached to this skeleton, if one exists.
@@ -178,7 +179,7 @@
Returns an array with all of the bones that are parentless. Another way to look at this is that it returns the indexes of all the bones that are not dependent or modified by other bones in the Skeleton.
</description>
</method>
- <method name="global_pose_to_local_pose">
+ <method name="global_pose_to_local_pose" is_deprecated="true">
<return type="Transform3D" />
<param index="0" name="bone_idx" type="int" />
<param index="1" name="global_pose" type="Transform3D" />
@@ -187,15 +188,16 @@
This can be used to easily convert a global pose from [method get_bone_global_pose] to a global transform in [method set_bone_local_pose_override].
</description>
</method>
- <method name="global_pose_to_world_transform">
+ <method name="global_pose_to_world_transform" is_deprecated="true">
<return type="Transform3D" />
<param index="0" name="global_pose" type="Transform3D" />
<description>
+ Deprecated. Use [Node3D] apis instead.
Takes the passed-in global pose and converts it to a world transform.
This can be used to easily convert a global pose from [method get_bone_global_pose] to a global transform usable with a node's transform, like [member Node3D.global_transform] for example.
</description>
</method>
- <method name="global_pose_z_forward_to_bone_forward">
+ <method name="global_pose_z_forward_to_bone_forward" is_deprecated="true">
<return type="Basis" />
<param index="0" name="bone_idx" type="int" />
<param index="1" name="basis" type="Basis" />
@@ -211,7 +213,7 @@
Returns whether the bone pose for the bone at [param bone_idx] is enabled.
</description>
</method>
- <method name="local_pose_to_global_pose">
+ <method name="local_pose_to_global_pose" is_deprecated="true">
<return type="Transform3D" />
<param index="0" name="bone_idx" type="int" />
<param index="1" name="local_pose" type="Transform3D" />
@@ -293,16 +295,17 @@
<description>
Sets the global pose transform, [param pose], for the bone at [param bone_idx].
[param amount] is the interpolation strength that will be used when applying the pose, and [param persistent] determines if the applied pose will remain.
- [b]Note:[/b] The pose transform needs to be a global pose! Use [method world_transform_to_global_pose] to convert a world transform, like one you can get from a [Node3D], to a global pose.
+ [b]Note:[/b] The pose transform needs to be a global pose! To convert a world transform from a [Node3D] to a global bone pose, multiply the [method Transform3D.affine_inverse] of the node's [member Node3D.global_transform] by the desired world transform
</description>
</method>
- <method name="set_bone_local_pose_override">
+ <method name="set_bone_local_pose_override" is_deprecated="true">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
<param index="1" name="pose" type="Transform3D" />
<param index="2" name="amount" type="float" />
<param index="3" name="persistent" type="bool" default="false" />
<description>
+ Deprecated. Local pose overrides will be removed.
Sets the local pose transform, [param pose], for the bone at [param bone_idx].
[param amount] is the interpolation strength that will be used when applying the pose, and [param persistent] determines if the applied pose will remain.
[b]Note:[/b] The pose transform needs to be a local pose! Use [method global_pose_to_local_pose] to convert a global pose to a local pose.
@@ -353,7 +356,7 @@
Sets the rest transform for bone [param bone_idx].
</description>
</method>
- <method name="set_modification_stack">
+ <method name="set_modification_stack" is_deprecated="true">
<return type="void" />
<param index="0" name="modification_stack" type="SkeletonModificationStack3D" />
<description>
@@ -367,10 +370,11 @@
Unparents the bone at [param bone_idx] and sets its rest position to that of its parent prior to being reset.
</description>
</method>
- <method name="world_transform_to_global_pose">
+ <method name="world_transform_to_global_pose" is_deprecated="true">
<return type="Transform3D" />
<param index="0" name="world_transform" type="Transform3D" />
<description>
+ Deprecated. Use [Node3D] apis instead.
Takes the passed-in global transform and converts it to a global pose.
This can be used to easily convert a global transform from [member Node3D.global_transform] to a global pose usable with [method set_bone_global_pose_override], for example.
</description>
diff --git a/doc/classes/SkeletonIK3D.xml b/doc/classes/SkeletonIK3D.xml
index 788ba3e248..1d50a97954 100644
--- a/doc/classes/SkeletonIK3D.xml
+++ b/doc/classes/SkeletonIK3D.xml
@@ -1,8 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonIK3D" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonIK3D" inherits="Node" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ SkeletonIK3D is used to place the end bone of a [Skeleton3D] bone chain at a certain point in 3D by rotating all bones in the chain accordingly.
</brief_description>
<description>
+ SkeletonIK3D is used to place the end bone of a [Skeleton3D] bone chain at a certain point in 3D by rotating all bones in the chain accordingly. A typical scenario for IK in games is to place a characters feet on the ground or a characters hands on a currently hold object. SkeletonIK uses FabrikInverseKinematic internally to solve the bone chain and applies the results to the [Skeleton3D] [code]bones_global_pose_override[/code] property for all affected bones in the chain. If fully applied this overwrites any bone transform from [Animation]s or bone custom poses set by users. The applied amount can be controlled with the [code]interpolation[/code] property.
+ [codeblock]
+ # Apply IK effect automatically on every new frame (not the current)
+ skeleton_ik_node.start()
+
+ # Apply IK effect only on the current frame
+ skeleton_ik_node.start(true)
+
+ # Stop IK effect and reset bones_global_pose_override on Skeleton
+ skeleton_ik_node.stop()
+
+ # Apply full IK effect
+ skeleton_ik_node.set_interpolation(1.0)
+
+ # Apply half IK effect
+ skeleton_ik_node.set_interpolation(0.5)
+
+ # Apply zero IK effect (a value at or below 0.01 also removes bones_global_pose_override on Skeleton)
+ skeleton_ik_node.set_interpolation(0.0)
+ [/codeblock]
</description>
<tutorials>
<link title="3D Inverse Kinematics Demo">https://godotengine.org/asset-library/asset/523</link>
@@ -11,45 +32,59 @@
<method name="get_parent_skeleton" qualifiers="const">
<return type="Skeleton3D" />
<description>
+ Returns the parent [Skeleton3D] Node that was present when SkeletonIK entered the [SceneTree]. Returns null if the parent node was not a [Skeleton3D] Node when SkeletonIK3D entered the [SceneTree].
</description>
</method>
<method name="is_running">
<return type="bool" />
<description>
+ Returns [code]true[/code] if SkeletonIK is applying IK effects on continues frames to the [Skeleton3D] bones. Returns [code]false[/code] if SkeletonIK is stopped or [method start] was used with the [code]one_time[/code] parameter set to [code]true[/code].
</description>
</method>
<method name="start">
<return type="void" />
<param index="0" name="one_time" type="bool" default="false" />
<description>
+ Starts applying IK effects on each frame to the [Skeleton3D] bones but will only take effect starting on the next frame. If [code]one_time[/code] is [code]true[/code], this will take effect immediately but also reset on the next frame.
</description>
</method>
<method name="stop">
<return type="void" />
<description>
+ Stops applying IK effects on each frame to the [Skeleton3D] bones and also calls [method Skeleton3D.clear_bones_global_pose_override] to remove existing overrides on all bones.
</description>
</method>
</methods>
<members>
<member name="interpolation" type="float" setter="set_interpolation" getter="get_interpolation" default="1.0">
+ Interpolation value for how much the IK results are applied to the current skeleton bone chain. A value of [code]1.0[/code] will overwrite all skeleton bone transforms completely while a value of [code]0.0[/code] will visually disable the SkeletonIK. A value at or below [code]0.01[/code] also calls [method Skeleton3D.clear_bones_global_pose_override].
</member>
<member name="magnet" type="Vector3" setter="set_magnet_position" getter="get_magnet_position" default="Vector3(0, 0, 0)">
+ Secondary target position (first is [member target] property or [member target_node]) for the IK chain. Use magnet position (pole target) to control the bending of the IK chain. Only works if the bone chain has more than 2 bones. The middle chain bone position will be linearly interpolated with the magnet position.
</member>
<member name="max_iterations" type="int" setter="set_max_iterations" getter="get_max_iterations" default="10">
+ Number of iteration loops used by the IK solver to produce more accurate (and elegant) bone chain results.
</member>
<member name="min_distance" type="float" setter="set_min_distance" getter="get_min_distance" default="0.01">
+ The minimum distance between bone and goal target. If the distance is below this value, the IK solver stops further iterations.
</member>
<member name="override_tip_basis" type="bool" setter="set_override_tip_basis" getter="is_override_tip_basis" default="true">
+ If [code]true[/code] overwrites the rotation of the tip bone with the rotation of the [member target] (or [member target_node] if defined).
</member>
<member name="root_bone" type="StringName" setter="set_root_bone" getter="get_root_bone" default="&amp;&quot;&quot;">
+ The name of the current root bone, the first bone in the IK chain.
</member>
<member name="target" type="Transform3D" setter="set_target_transform" getter="get_target_transform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)">
+ First target of the IK chain where the tip bone is placed and, if [member override_tip_basis] is [code]true[/code], how the tip bone is rotated. If a [member target_node] path is available the nodes transform is used instead and this property is ignored.
</member>
<member name="target_node" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
+ Target node [NodePath] for the IK chain. If available, the node's current [Transform3D] is used instead of the [member target] property.
</member>
<member name="tip_bone" type="StringName" setter="set_tip_bone" getter="get_tip_bone" default="&amp;&quot;&quot;">
+ The name of the current tip bone, the last bone in the IK chain placed at the [member target] transform (or [member target_node] if defined).
</member>
<member name="use_magnet" type="bool" setter="set_use_magnet" getter="is_using_magnet" default="false">
+ If [code]true[/code], instructs the IK solver to consider the secondary magnet target (pole target) when calculating the bone chain. Use the magnet position (pole target) to control the bending of the IK chain.
</member>
</members>
</class>
diff --git a/doc/classes/SkeletonModification2D.xml b/doc/classes/SkeletonModification2D.xml
index 46d32aef41..77aaf0213b 100644
--- a/doc/classes/SkeletonModification2D.xml
+++ b/doc/classes/SkeletonModification2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2D" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2D" inherits="Resource" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A resource that operates on [Bone2D] nodes in a [Skeleton2D].
</brief_description>
diff --git a/doc/classes/SkeletonModification2DCCDIK.xml b/doc/classes/SkeletonModification2DCCDIK.xml
index c8fee3f94d..0d80b1b914 100644
--- a/doc/classes/SkeletonModification2DCCDIK.xml
+++ b/doc/classes/SkeletonModification2DCCDIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DCCDIK" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DCCDIK" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that uses CCDIK to manipulate a series of bones to reach a target in 2D.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DFABRIK.xml b/doc/classes/SkeletonModification2DFABRIK.xml
index ff3a65fe1a..8d1cd4b4d4 100644
--- a/doc/classes/SkeletonModification2DFABRIK.xml
+++ b/doc/classes/SkeletonModification2DFABRIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DFABRIK" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DFABRIK" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that uses FABRIK to manipulate a series of [Bone2D] nodes to reach a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DJiggle.xml b/doc/classes/SkeletonModification2DJiggle.xml
index 7329b2d865..3321fffe1b 100644
--- a/doc/classes/SkeletonModification2DJiggle.xml
+++ b/doc/classes/SkeletonModification2DJiggle.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DJiggle" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DJiggle" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that jiggles [Bone2D] nodes as they move towards a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DLookAt.xml b/doc/classes/SkeletonModification2DLookAt.xml
index 4747b06056..136fed37de 100644
--- a/doc/classes/SkeletonModification2DLookAt.xml
+++ b/doc/classes/SkeletonModification2DLookAt.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DLookAt" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DLookAt" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that rotates a [Bone2D] node to look at a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification2DPhysicalBones.xml b/doc/classes/SkeletonModification2DPhysicalBones.xml
index d5f46b2ea0..209602e974 100644
--- a/doc/classes/SkeletonModification2DPhysicalBones.xml
+++ b/doc/classes/SkeletonModification2DPhysicalBones.xml
@@ -1,10 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DPhysicalBones" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DPhysicalBones" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that applies the transforms of [PhysicalBone2D] nodes to [Bone2D] nodes.
</brief_description>
<description>
This modification takes the transforms of [PhysicalBone2D] nodes and applies them to [Bone2D] nodes. This allows the [Bone2D] nodes to react to physics thanks to the linked [PhysicalBone2D] nodes.
+ Experimental. Physical bones may be changed in the future to perform the position update of [Bone2D] on their own.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/SkeletonModification2DStackHolder.xml b/doc/classes/SkeletonModification2DStackHolder.xml
index 791dea2fb1..85df111c0d 100644
--- a/doc/classes/SkeletonModification2DStackHolder.xml
+++ b/doc/classes/SkeletonModification2DStackHolder.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DStackHolder" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DStackHolder" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that holds and executes a [SkeletonModificationStack2D].
</brief_description>
diff --git a/doc/classes/SkeletonModification2DTwoBoneIK.xml b/doc/classes/SkeletonModification2DTwoBoneIK.xml
index edd5431a0c..c476d71d44 100644
--- a/doc/classes/SkeletonModification2DTwoBoneIK.xml
+++ b/doc/classes/SkeletonModification2DTwoBoneIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification2DTwoBoneIK" inherits="SkeletonModification2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification2DTwoBoneIK" inherits="SkeletonModification2D" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that rotates two bones using the law of cosigns to reach the target.
</brief_description>
diff --git a/doc/classes/SkeletonModification3D.xml b/doc/classes/SkeletonModification3D.xml
index 8457179651..25431ea96f 100644
--- a/doc/classes/SkeletonModification3D.xml
+++ b/doc/classes/SkeletonModification3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3D" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3D" inherits="Resource" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A resource that operates on bones in a [Skeleton3D].
</brief_description>
diff --git a/doc/classes/SkeletonModification3DCCDIK.xml b/doc/classes/SkeletonModification3DCCDIK.xml
index dec0fbe99f..90b2e78449 100644
--- a/doc/classes/SkeletonModification3DCCDIK.xml
+++ b/doc/classes/SkeletonModification3DCCDIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DCCDIK" inherits="SkeletonModification3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3DCCDIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that uses CCDIK to manipulate a series of bones to reach a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification3DFABRIK.xml b/doc/classes/SkeletonModification3DFABRIK.xml
index 325cc2a12e..a2bec2b559 100644
--- a/doc/classes/SkeletonModification3DFABRIK.xml
+++ b/doc/classes/SkeletonModification3DFABRIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DFABRIK" inherits="SkeletonModification3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3DFABRIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that uses FABRIK to manipulate a series of bones to reach a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification3DJiggle.xml b/doc/classes/SkeletonModification3DJiggle.xml
index ef469d42ea..304f08bb20 100644
--- a/doc/classes/SkeletonModification3DJiggle.xml
+++ b/doc/classes/SkeletonModification3DJiggle.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DJiggle" inherits="SkeletonModification3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3DJiggle" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that jiggles bones as they move towards a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification3DLookAt.xml b/doc/classes/SkeletonModification3DLookAt.xml
index 3602cfad95..aeed953ca9 100644
--- a/doc/classes/SkeletonModification3DLookAt.xml
+++ b/doc/classes/SkeletonModification3DLookAt.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DLookAt" inherits="SkeletonModification3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3DLookAt" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that rotates a bone to look at a target.
</brief_description>
diff --git a/doc/classes/SkeletonModification3DStackHolder.xml b/doc/classes/SkeletonModification3DStackHolder.xml
index 24240236a4..9448e2c783 100644
--- a/doc/classes/SkeletonModification3DStackHolder.xml
+++ b/doc/classes/SkeletonModification3DStackHolder.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DStackHolder" inherits="SkeletonModification3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3DStackHolder" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that holds and executes a [SkeletonModificationStack3D].
</brief_description>
diff --git a/doc/classes/SkeletonModification3DTwoBoneIK.xml b/doc/classes/SkeletonModification3DTwoBoneIK.xml
index 6618ebbcfb..0e7ffd5c80 100644
--- a/doc/classes/SkeletonModification3DTwoBoneIK.xml
+++ b/doc/classes/SkeletonModification3DTwoBoneIK.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DTwoBoneIK" inherits="SkeletonModification3D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModification3DTwoBoneIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A modification that moves two bones to reach the target.
</brief_description>
diff --git a/doc/classes/SkeletonModificationStack2D.xml b/doc/classes/SkeletonModificationStack2D.xml
index 950e52e622..d96833e335 100644
--- a/doc/classes/SkeletonModificationStack2D.xml
+++ b/doc/classes/SkeletonModificationStack2D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModificationStack2D" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModificationStack2D" inherits="Resource" is_experimental="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A resource that holds a stack of [SkeletonModification2D]s.
</brief_description>
diff --git a/doc/classes/SkeletonModificationStack3D.xml b/doc/classes/SkeletonModificationStack3D.xml
index 34c7099bca..9eaeeefd8e 100644
--- a/doc/classes/SkeletonModificationStack3D.xml
+++ b/doc/classes/SkeletonModificationStack3D.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModificationStack3D" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="SkeletonModificationStack3D" inherits="Resource" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
A resource that holds a stack of [SkeletonModification3D]s.
</brief_description>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index 0db16b491d..2e67c61e54 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -1720,6 +1720,7 @@
</constant>
<constant name="HINTING_NORMAL" value="2" enum="Hinting">
Use the default font hinting mode (crisper but less smooth).
+ [b]Note:[/b] This hinting mode changes both horizontal and vertical glyph metrics. If applied to monospace font, some glyphs might have different width.
</constant>
<constant name="SUBPIXEL_POSITIONING_DISABLED" value="0" enum="SubpixelPositioning">
Glyph horizontal position is rounded to the whole pixel size, each glyph is rasterized once.
diff --git a/doc/classes/Texture2DArray.xml b/doc/classes/Texture2DArray.xml
index 6f059b5fbf..113f37f974 100644
--- a/doc/classes/Texture2DArray.xml
+++ b/doc/classes/Texture2DArray.xml
@@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="Texture2DArray" inherits="ImageTextureLayered" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ A single texture resource which consists of multiple, separate images. Each image has the same dimensions and number of mipmap levels.
</brief_description>
<description>
+ A Texture2DArray is different from a Texture3D: The Texture2DArray does not support trilinear interpolation between the [Image]s, i.e. no blending.
+ A Texture2DArray is also different from an [AtlasTexture]: In a Texture2DArray, all images are treated separately. In an atlas, the regions (i.e. the single images) can be of different sizes. Furthermore, you usually need to add a padding around the regions, to prevent accidental UV mapping to more than one region. The same goes for mipmapping: Mipmap chains are handled separately for each layer. In an atlas, the slicing has to be done manually in the fragment shader.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/TextureLayered.xml b/doc/classes/TextureLayered.xml
index 7b528e2082..5e6afcbc5c 100644
--- a/doc/classes/TextureLayered.xml
+++ b/doc/classes/TextureLayered.xml
@@ -1,10 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="TextureLayered" inherits="Texture" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Base class for 3D texture types.
+ Base class for texture types which contain the data of multiple [Image]s. Each image is of the same size and format.
</brief_description>
<description>
- Base class for [Texture2DArray], [Cubemap] and [CubemapArray]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types. Data is set on a per-layer basis. For [Texture2DArray]s, the layer specifies the array layer.
+ Base class for [Texture2DArray], [Cubemap] and [CubemapArray]. Cannot be used directly, but contains all the functions necessary for accessing the derived resource types.
+ Data is set on a per-layer basis. For [Texture2DArray]s, the layer specifies the array layer.
+ All images need to have the same width, height and number of mipmap levels.
+ A [TextureLayered] can be loaded with [code]method ResourceFormatLoader.load[/code].
+ To create such a texture file yourself, re-import your image files using the Godot Editor import presets.
+ Internally, Godot maps these files to their respective counterparts in the target rendering driver (GLES3, Vulkan).
</description>
<tutorials>
</tutorials>
@@ -72,6 +77,7 @@
<method name="get_layers" qualifiers="const">
<return type="int" />
<description>
+ Returns the number of referenced [Image]s.
</description>
</method>
<method name="get_width" qualifiers="const">
@@ -83,6 +89,7 @@
<method name="has_mipmaps" qualifiers="const">
<return type="bool" />
<description>
+ Returns [code]true[/code] if the layers have generated mipmaps.
</description>
</method>
</methods>
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 8d4954136e..0ffede0992 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -198,7 +198,8 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
int item_count = 0;
bool backbuffer_cleared = false;
bool time_used = false;
- bool material_screen_texture_found = false;
+ bool material_screen_texture_cached = false;
+ bool material_screen_texture_mipmaps_cached = false;
Rect2 back_buffer_rect;
bool backbuffer_copy = false;
bool backbuffer_gen_mipmaps = false;
@@ -223,10 +224,12 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
GLES3::CanvasMaterialData *md = static_cast<GLES3::CanvasMaterialData *>(material_storage->material_get_data(material, RS::SHADER_CANVAS_ITEM));
if (md && md->shader_data->valid) {
if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) {
- if (!material_screen_texture_found) {
+ if (!material_screen_texture_cached) {
backbuffer_copy = true;
back_buffer_rect = Rect2();
backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps;
+ } else if (!material_screen_texture_mipmaps_cached) {
+ backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps;
}
}
@@ -287,7 +290,16 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
texture_storage->render_target_copy_to_back_buffer(p_to_render_target, back_buffer_rect, backbuffer_gen_mipmaps);
backbuffer_copy = false;
- material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
+ backbuffer_gen_mipmaps = false;
+ material_screen_texture_cached = true; // After a backbuffer copy, screen texture makes no further copies.
+ material_screen_texture_mipmaps_cached = backbuffer_gen_mipmaps;
+ }
+
+ if (backbuffer_gen_mipmaps) {
+ texture_storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, back_buffer_rect);
+
+ backbuffer_gen_mipmaps = false;
+ material_screen_texture_mipmaps_cached = true;
}
// just add all items for now
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index dae26b1e5f..1952efff0e 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -683,6 +683,7 @@ void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, cons
light_data_dirty = true;
for (uint32_t i = sky_globals.directional_light_count; i < sky_globals.max_directional_lights; i++) {
sky_globals.directional_lights[i].enabled = false;
+ sky_globals.last_frame_directional_lights[i].enabled = false;
}
}
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index 881fc5615c..d264284ef7 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -304,12 +304,13 @@ private:
};
enum {
- INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5,
- INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6,
- INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
- INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
- INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
- INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11,
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
+ INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 8,
+ INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 9,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 10,
+ INSTANCE_DATA_FLAG_PARTICLES = 1 << 11,
INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index 523c9dd8e6..687e98ba58 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1379,9 +1379,9 @@ MaterialStorage::MaterialStorage() {
actions.renames["POINT_SIZE"] = "gl_PointSize";
actions.renames["MODEL_MATRIX"] = "model_matrix";
- actions.renames["CANVAS_MATRIX"] = "canvas_data.canvas_transform";
- actions.renames["SCREEN_MATRIX"] = "canvas_data.screen_transform";
- actions.renames["TIME"] = "canvas_data.time";
+ actions.renames["CANVAS_MATRIX"] = "canvas_transform";
+ actions.renames["SCREEN_MATRIX"] = "screen_transform";
+ actions.renames["TIME"] = "time";
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
@@ -1399,7 +1399,7 @@ MaterialStorage::MaterialStorage() {
actions.renames["SPECULAR_SHININESS"] = "specular_shininess";
actions.renames["SCREEN_UV"] = "screen_uv";
actions.renames["SCREEN_TEXTURE"] = "screen_texture";
- actions.renames["SCREEN_PIXEL_SIZE"] = "canvas_data.screen_pixel_size";
+ actions.renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
actions.renames["POINT_COORD"] = "gl_PointCoord";
actions.renames["INSTANCE_ID"] = "gl_InstanceIndex";
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index beb2812999..ab298a0e49 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -194,6 +194,14 @@ String OS_Unix::get_name() const {
return "Unix";
}
+String OS_Unix::get_distribution_name() const {
+ return "";
+}
+
+String OS_Unix::get_version() const {
+ return "";
+}
+
double OS_Unix::get_unix_time() const {
struct timeval tv_now;
gettimeofday(&tv_now, nullptr);
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index b4c844bfef..8ef650f28b 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -62,6 +62,8 @@ public:
virtual Error set_cwd(const String &p_cwd) override;
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual DateTime get_datetime(bool p_utc) const override;
virtual TimeZoneInfo get_time_zone_info() const override;
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 70b5501692..c2e04e4be9 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -6050,10 +6050,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
real_t to_diff = fmod(b - a, Math_TAU);
to_v = a + fmod(2.0 * to_diff, Math_TAU) - to_diff;
}
- Variant delta_v;
- Variant::sub(to_v, from_v, delta_v);
+ Variant delta_v = Animation::subtract_variant(to_v, from_v);
double duration = to_t - from_t;
- double fixed_duration = duration - 0.01; // Prevent to overwrap keys...
+ double fixed_duration = duration - UNIT_EPSILON; // Prevent to overwrap keys...
for (double delta_t = dur_step; delta_t < fixed_duration; delta_t += dur_step) {
Pair<real_t, Variant> keydata;
keydata.first = from_t + delta_t;
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index 9f655ab00a..7d6eb186dc 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -1162,13 +1162,11 @@ Error DocTools::_load(Ref<XMLParser> parser) {
}
if (parser->has_attribute("is_deprecated")) {
- String result = parser->get_attribute_value("is_deprecated");
- c.is_deprecated = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ c.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- String result = parser->get_attribute_value("is_experimental");
- c.is_experimental = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ c.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
}
while (parser->read() == OK) {
@@ -1315,12 +1313,10 @@ Error DocTools::_load(Ref<XMLParser> parser) {
constant2.is_bitfield = parser->get_attribute_value("is_bitfield").to_lower() == "true";
}
if (parser->has_attribute("is_deprecated")) {
- String result = parser->get_attribute_value("is_deprecated");
- constant2.is_deprecated = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ constant2.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- String result = parser->get_attribute_value("is_experimental");
- constant2.is_experimental = (result == "true" || result == "True" || result == "TRUE" || result == "1");
+ constant2.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
}
if (!parser->is_empty()) {
parser->read();
@@ -1376,10 +1372,10 @@ static void _write_method_doc(Ref<FileAccess> f, const String &p_name, Vector<Do
String additional_attributes;
if (m.is_deprecated) {
- additional_attributes += " is_deprecated=\"True\"";
+ additional_attributes += " is_deprecated=\"true\"";
}
if (m.is_experimental) {
- additional_attributes += " is_experimental=\"True\"";
+ additional_attributes += " is_experimental=\"true\"";
}
_write_string(f, 2, "<" + p_name + " name=\"" + m.name.xml_escape() + "\"" + qualifiers + additional_attributes + ">");
@@ -1446,10 +1442,10 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
if (!c.inherits.is_empty()) {
header += " inherits=\"" + c.inherits + "\"";
if (c.is_deprecated) {
- header += " is_deprecated=\"True\"";
+ header += " is_deprecated=\"true\"";
}
if (c.is_experimental) {
- header += " is_experimental=\"True\"";
+ header += " is_experimental=\"true\"";
}
}
header += String(" version=\"") + VERSION_BRANCH + "\"";
@@ -1495,10 +1491,10 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
additional_attributes += " default=\"" + c.properties[i].default_value.xml_escape(true) + "\"";
}
if (c.properties[i].is_deprecated) {
- additional_attributes += " is_deprecated=\"True\"";
+ additional_attributes += " is_deprecated=\"true\"";
}
if (c.properties[i].is_experimental) {
- additional_attributes += " is_experimental=\"True\"";
+ additional_attributes += " is_experimental=\"true\"";
}
const DocData::PropertyDoc &p = c.properties[i];
@@ -1523,10 +1519,10 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String,
String additional_attributes;
if (c.constants[i].is_deprecated) {
- additional_attributes += " is_deprecated=\"True\"";
+ additional_attributes += " is_deprecated=\"true\"";
}
if (c.constants[i].is_experimental) {
- additional_attributes += " is_experimental=\"True\"";
+ additional_attributes += " is_experimental=\"true\"";
}
if (k.is_value_valid) {
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 177bc6d2b2..b89bd23859 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -690,7 +690,6 @@ void EditorFileSystem::scan() {
_update_extensions();
- abort_scan = false;
if (!use_threads) {
scanning = true;
scan_total = 0;
@@ -1162,8 +1161,6 @@ void EditorFileSystem::scan_changes() {
scanning_changes = true;
scanning_changes_done = false;
- abort_scan = false;
-
if (!use_threads) {
if (filesystem) {
EditorProgressBG pr("sources", TTR("ScanSources"), 1000);
@@ -1195,8 +1192,6 @@ void EditorFileSystem::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
Thread &active_thread = thread.is_started() ? thread : thread_sources;
if (use_threads && active_thread.is_started()) {
- //abort thread if in progress
- abort_scan = true;
while (scanning) {
OS::get_singleton()->delay_usec(1000);
}
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index f4e69b95e7..e06c6e4593 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -168,7 +168,6 @@ class EditorFileSystem : public Node {
EditorFileSystemDirectory *new_filesystem = nullptr;
- bool abort_scan = false;
bool scanning = false;
bool importing = false;
bool first_scan = true;
diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp
index fffe77f1c4..c31d13d122 100644
--- a/editor/editor_fonts.cpp
+++ b/editor/editor_fonts.cpp
@@ -96,6 +96,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)EditorSettings::get_singleton()->get("interface/editor/font_subpixel_positioning");
TextServer::Hinting font_hinting;
+ TextServer::Hinting font_mono_hinting;
switch (font_hinting_setting) {
case 0:
// The "Auto" setting uses the setting that best matches the OS' font rendering:
@@ -104,18 +105,23 @@ void editor_register_fonts(Ref<Theme> p_theme) {
// - Linux has configurable font hinting, but most distributions including Ubuntu default to "Light".
#ifdef MACOS_ENABLED
font_hinting = TextServer::HINTING_NONE;
+ font_mono_hinting = TextServer::HINTING_NONE;
#else
font_hinting = TextServer::HINTING_LIGHT;
+ font_mono_hinting = TextServer::HINTING_LIGHT;
#endif
break;
case 1:
font_hinting = TextServer::HINTING_NONE;
+ font_mono_hinting = TextServer::HINTING_NONE;
break;
case 2:
font_hinting = TextServer::HINTING_LIGHT;
+ font_mono_hinting = TextServer::HINTING_LIGHT;
break;
default:
font_hinting = TextServer::HINTING_NORMAL;
+ font_mono_hinting = TextServer::HINTING_LIGHT;
break;
}
@@ -163,7 +169,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
default_font_bold->set_fallbacks(fallbacks_bold);
default_font_bold_msdf->set_fallbacks(fallbacks_bold);
- Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_hinting, font_antialiasing, true, font_subpixel_positioning);
+ Ref<FontFile> default_font_mono = load_internal_font(_font_JetBrainsMono_Regular, _font_JetBrainsMono_Regular_size, font_mono_hinting, font_antialiasing, true, font_subpixel_positioning);
default_font_mono->set_fallbacks(fallbacks);
// Init base font configs and load custom fonts.
@@ -260,7 +266,7 @@ void editor_register_fonts(Ref<Theme> p_theme) {
Ref<FontVariation> mono_fc;
mono_fc.instantiate();
if (custom_font_path_source.length() > 0 && dir->file_exists(custom_font_path_source)) {
- Ref<FontFile> custom_font = load_external_font(custom_font_path_source, font_hinting, font_antialiasing, true, font_subpixel_positioning);
+ Ref<FontFile> custom_font = load_external_font(custom_font_path_source, font_mono_hinting, font_antialiasing, true, font_subpixel_positioning);
{
TypedArray<Font> fallback_custom;
fallback_custom.push_back(default_font_mono);
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index f001887ef9..413eb52556 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -458,7 +458,7 @@ StringName EditorProperty::_get_revert_property() const {
return property;
}
-void EditorProperty::update_revert_and_pin_status() {
+void EditorProperty::update_editor_property_status() {
if (property == StringName()) {
return; //no property, so nothing to do
}
@@ -469,15 +469,26 @@ void EditorProperty::update_revert_and_pin_status() {
CRASH_COND(!node);
new_pinned = node->is_property_pinned(property);
}
+
Variant current = object->get(_get_revert_property());
bool new_can_revert = EditorPropertyRevert::can_property_revert(object, property, &current) && !is_read_only();
- if (new_can_revert != can_revert || new_pinned != pinned) {
+ bool new_checked = checked;
+ if (checkable) { // for properties like theme overrides.
+ bool valid = false;
+ Variant value = object->get(property, &valid);
+ if (valid) {
+ new_checked = value.get_type() != Variant::NIL;
+ }
+ }
+
+ if (new_can_revert != can_revert || new_pinned != pinned || new_checked != checked) {
if (new_can_revert != can_revert) {
emit_signal(SNAME("property_can_revert_changed"), property, new_can_revert);
}
can_revert = new_can_revert;
pinned = new_pinned;
+ checked = new_checked;
queue_redraw();
}
}
@@ -974,7 +985,7 @@ void EditorProperty::_bind_methods() {
ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "focusable_idx")));
GDVIRTUAL_BIND(_update_property)
- ClassDB::bind_method(D_METHOD("_update_revert_and_pin_status"), &EditorProperty::update_revert_and_pin_status);
+ ClassDB::bind_method(D_METHOD("_update_editor_property_status"), &EditorProperty::update_editor_property_status);
}
EditorProperty::EditorProperty() {
@@ -1651,6 +1662,10 @@ void EditorInspectorArray::_panel_draw(int p_index) {
void EditorInspectorArray::_panel_gui_input(Ref<InputEvent> p_event, int p_index) {
ERR_FAIL_INDEX(p_index, (int)array_elements.size());
+ if (read_only) {
+ return;
+ }
+
Ref<InputEventKey> key_ref = p_event;
if (key_ref.is_valid()) {
const InputEventKey &key = **key_ref;
@@ -2151,7 +2166,7 @@ void EditorInspectorArray::drop_data_fw(const Point2 &p_point, const Variant &p_
}
bool EditorInspectorArray::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
- if (!movable) {
+ if (!movable || read_only) {
return false;
}
// First, update drawing.
@@ -2271,7 +2286,9 @@ VBoxContainer *EditorInspectorArray::get_vbox(int p_index) {
}
}
-EditorInspectorArray::EditorInspectorArray() {
+EditorInspectorArray::EditorInspectorArray(bool p_read_only) {
+ read_only = p_read_only;
+
set_mouse_filter(Control::MOUSE_FILTER_STOP);
odd_style.instantiate();
@@ -2297,6 +2314,7 @@ EditorInspectorArray::EditorInspectorArray() {
add_button = EditorInspector::create_inspector_action_button(TTR("Add Element"));
add_button->connect("pressed", callable_mp(this, &EditorInspectorArray::_add_button_pressed));
+ add_button->set_disabled(read_only);
vbox->add_child(add_button);
control_dropping = memnew(Control);
@@ -2317,6 +2335,7 @@ EditorInspectorArray::EditorInspectorArray() {
new_size_spin_box->set_max(16384);
new_size_spin_box->connect("value_changed", callable_mp(this, &EditorInspectorArray::_new_size_spin_box_value_changed));
new_size_spin_box->get_line_edit()->connect("text_submitted", callable_mp(this, &EditorInspectorArray::_new_size_spin_box_text_submitted));
+ new_size_spin_box->set_editable(!read_only);
resize_dialog_vbox->add_margin_child(TTRC("New Size:"), new_size_spin_box);
vbox->connect("visibility_changed", callable_mp(this, &EditorInspectorArray::_vbox_visibility_changed));
@@ -2544,7 +2563,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, EditorIn
ep->set_read_only(read_only);
ep->update_property();
ep->_update_pin_flags();
- ep->update_revert_and_pin_status();
+ ep->update_editor_property_status();
ep->set_deletable(deletable_properties);
ep->update_cache();
}
@@ -3030,7 +3049,7 @@ void EditorInspector::update_tree() {
bool movable = true;
bool numbered = false;
bool foldable = use_folding;
- String add_button_text;
+ String add_button_text = TTR("Add Element");
String swap_method;
for (int i = (p.type == Variant::NIL ? 1 : 2); i < class_name_components.size(); i++) {
if (class_name_components[i].begins_with("page_size") && class_name_components[i].get_slice_count("=") == 2) {
@@ -3051,7 +3070,7 @@ void EditorInspector::update_tree() {
if (p.type == Variant::NIL) {
// Setup the array to use a method to create/move/delete elements.
array_element_prefix = class_name_components[0];
- editor_inspector_array = memnew(EditorInspectorArray);
+ editor_inspector_array = memnew(EditorInspectorArray(all_read_only));
String array_label = path.contains("/") ? path.substr(path.rfind("/") + 1) : path;
array_label = EditorPropertyNameProcessor::get_singleton()->process_name(property_label_string, property_name_style);
@@ -3063,7 +3082,7 @@ void EditorInspector::update_tree() {
// Setup the array to use the count property and built-in functions to create/move/delete elements.
if (class_name_components.size() >= 2) {
array_element_prefix = class_name_components[1];
- editor_inspector_array = memnew(EditorInspectorArray);
+ editor_inspector_array = memnew(EditorInspectorArray(all_read_only));
int page = per_array_page.has(array_element_prefix) ? per_array_page[array_element_prefix] : 0;
editor_inspector_array->setup_with_count_property(object, class_name_components[0], p.name, array_element_prefix, page, c, foldable, movable, numbered, page_size, add_button_text, swap_method);
@@ -3203,6 +3222,7 @@ void EditorInspector::update_tree() {
// Use the existing one.
ep->set_label(property_label_string);
}
+
for (int j = 0; j < properties.size(); j++) {
String prop = properties[j];
@@ -3250,7 +3270,7 @@ void EditorInspector::update_tree() {
ep->set_doc_path(doc_info.path);
ep->update_property();
ep->_update_pin_flags();
- ep->update_revert_and_pin_status();
+ ep->update_editor_property_status();
ep->update_cache();
if (current_selected && ep->property == current_selected) {
@@ -3289,7 +3309,7 @@ void EditorInspector::update_property(const String &p_prop) {
for (EditorProperty *E : editor_property_map[p_prop]) {
E->update_property();
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
E->update_cache();
}
}
@@ -3632,7 +3652,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
if (editor_property_map.has(p_name)) {
for (EditorProperty *E : editor_property_map[p_name]) {
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
}
}
}
@@ -3746,7 +3766,7 @@ void EditorInspector::_property_checked(const String &p_path, bool p_checked) {
for (EditorProperty *E : editor_property_map[p_path]) {
E->set_checked(p_checked);
E->update_property();
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
E->update_cache();
}
}
@@ -3770,8 +3790,8 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) {
undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned);
if (editor_property_map.has(p_path)) {
for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
- undo_redo->add_do_method(E->get(), "_update_revert_and_pin_status");
- undo_redo->add_undo_method(E->get(), "_update_revert_and_pin_status");
+ undo_redo->add_do_method(E->get(), "_update_editor_property_status");
+ undo_redo->add_undo_method(E->get(), "_update_editor_property_status");
}
}
undo_redo->commit_action();
@@ -3779,7 +3799,7 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) {
node->set_property_pinned(p_path, p_pinned);
if (editor_property_map.has(p_path)) {
for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
- E->get()->update_revert_and_pin_status();
+ E->get()->update_editor_property_status();
}
}
}
@@ -3860,7 +3880,7 @@ void EditorInspector::_notification(int p_what) {
for (EditorProperty *E : F.value) {
if (E && !E->is_cache_valid()) {
E->update_property();
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
E->update_cache();
}
}
@@ -3882,7 +3902,7 @@ void EditorInspector::_notification(int p_what) {
if (editor_property_map.has(prop)) {
for (EditorProperty *E : editor_property_map[prop]) {
E->update_property();
- E->update_revert_and_pin_status();
+ E->update_editor_property_status();
E->update_cache();
}
}
@@ -3975,13 +3995,7 @@ void EditorInspector::_check_meta_name(const String &p_name) {
} else if (!p_name.is_valid_identifier()) {
error = TTR("Metadata name must be a valid identifier.");
} else if (object->has_meta(p_name)) {
- Node *node = Object::cast_to<Node>(object);
- if (node) {
- error = vformat(TTR("Metadata with name \"%s\" already exists on \"%s\"."), p_name, node->get_name());
- } else {
- // This should normally never be reached, but the error is set just in case.
- error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name, node->get_name());
- }
+ error = vformat(TTR("Metadata with name \"%s\" already exists."), p_name);
} else if (p_name[0] == '_') {
error = TTR("Names starting with _ are reserved for editor-only metadata.");
}
@@ -4001,14 +4015,6 @@ void EditorInspector::_show_add_meta_dialog() {
if (!add_meta_dialog) {
add_meta_dialog = memnew(ConfirmationDialog);
- Node *node = Object::cast_to<Node>(object);
- if (node) {
- add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), node->get_name()));
- } else {
- // This should normally never be reached, but the title is set just in case.
- add_meta_dialog->set_title(vformat(TTR("Add Metadata Property"), node->get_name()));
- }
-
VBoxContainer *vbc = memnew(VBoxContainer);
add_meta_dialog->add_child(vbc);
HBoxContainer *hbc = memnew(HBoxContainer);
@@ -4038,6 +4044,14 @@ void EditorInspector::_show_add_meta_dialog() {
add_meta_name->connect("text_changed", callable_mp(this, &EditorInspector::_check_meta_name));
}
+ Node *node = Object::cast_to<Node>(object);
+ if (node) {
+ add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), node->get_name()));
+ } else {
+ // This should normally be reached when the object is derived from Resource.
+ add_meta_dialog->set_title(vformat(TTR("Add Metadata Property for \"%s\""), object->get_class()));
+ }
+
add_meta_dialog->popup_centered();
add_meta_name->set_text("");
_check_meta_name("");
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index d634eae23f..b7df5a8037 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -151,7 +151,7 @@ public:
void set_doc_path(const String &p_doc_path);
virtual void update_property();
- void update_revert_and_pin_status();
+ void update_editor_property_status();
virtual bool use_keying_next() const;
@@ -333,6 +333,7 @@ class EditorInspectorArray : public EditorInspectorSection {
int begin_array_index = 0;
int end_array_index = 0;
+ bool read_only = false;
bool movable = true;
bool numbered = false;
@@ -404,7 +405,7 @@ public:
void setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = "");
VBoxContainer *get_vbox(int p_index);
- EditorInspectorArray();
+ EditorInspectorArray(bool p_read_only);
};
class EditorPaginator : public HBoxContainer {
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 804722299c..8eaddcb7e1 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -3932,7 +3932,7 @@ void EditorNode::edit_foreign_resource(Ref<Resource> p_resource) {
InspectorDock::get_singleton()->call_deferred("edit_resource", p_resource);
}
-bool EditorNode::is_resource_read_only(Ref<Resource> p_resource) {
+bool EditorNode::is_resource_read_only(Ref<Resource> p_resource, bool p_foreign_resources_are_writable) {
ERR_FAIL_COND_V(p_resource.is_null(), false);
String path = p_resource->get_path();
@@ -3944,7 +3944,11 @@ bool EditorNode::is_resource_read_only(Ref<Resource> p_resource) {
// If the base resource is a packed scene, we treat it as read-only if it is not the currently edited scene.
if (ResourceLoader::get_resource_type(base) == "PackedScene") {
if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
- return true;
+ // If we have not flagged foreign resources as writable or the base scene the resource is
+ // part was imported, it can be considered read-only.
+ if (!p_foreign_resources_are_writable || FileAccess::exists(base + ".import")) {
+ return true;
+ }
}
} else {
// If a corresponding .import file exists for the base file, we assume it to be imported and should therefore treated as read-only.
diff --git a/editor/editor_node.h b/editor/editor_node.h
index df3d2ae0f8..200d68908c 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -784,7 +784,7 @@ public:
void open_request(const String &p_path);
void edit_foreign_resource(Ref<Resource> p_resource);
- bool is_resource_read_only(Ref<Resource> p_resource);
+ bool is_resource_read_only(Ref<Resource> p_resource, bool p_foreign_resources_are_writable = false);
bool is_changing_scene() const;
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 7364258a07..3b99962435 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -1758,7 +1758,7 @@ void EditorPropertyVector2::_value_changed(double val, const String &p_name) {
Vector2 v2;
v2.x = spin[0]->get_value();
v2.y = spin[1]->get_value();
- emit_changed(get_edited_property(), v2, p_name);
+ emit_changed(get_edited_property(), v2, linked->is_pressed() ? "" : p_name);
}
void EditorPropertyVector2::update_property() {
@@ -2005,7 +2005,7 @@ void EditorPropertyVector3::_value_changed(double val, const String &p_name) {
v3.y = Math::deg_to_rad(v3.y);
v3.z = Math::deg_to_rad(v3.z);
}
- emit_changed(get_edited_property(), v3, p_name);
+ emit_changed(get_edited_property(), v3, linked->is_pressed() ? "" : p_name);
}
void EditorPropertyVector3::update_property() {
@@ -2171,7 +2171,7 @@ void EditorPropertyVector2i::_value_changed(double val, const String &p_name) {
Vector2i v2;
v2.x = spin[0]->get_value();
v2.y = spin[1]->get_value();
- emit_changed(get_edited_property(), v2, p_name);
+ emit_changed(get_edited_property(), v2, linked->is_pressed() ? "" : p_name);
}
void EditorPropertyVector2i::update_property() {
@@ -2413,7 +2413,7 @@ void EditorPropertyVector3i::_value_changed(double val, const String &p_name) {
v3.x = spin[0]->get_value();
v3.y = spin[1]->get_value();
v3.z = spin[2]->get_value();
- emit_changed(get_edited_property(), v3, p_name);
+ emit_changed(get_edited_property(), v3, linked->is_pressed() ? "" : p_name);
}
void EditorPropertyVector3i::update_property() {
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index ad84b30689..728a3b0f80 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -268,6 +268,7 @@ void EditorPropertyArray::update_property() {
size_slider->set_step(1);
size_slider->set_max(1000000);
size_slider->set_h_size_flags(SIZE_EXPAND_FILL);
+ size_slider->set_read_only(is_read_only());
size_slider->connect("value_changed", callable_mp(this, &EditorPropertyArray::_length_changed));
hbox->add_child(size_slider);
@@ -278,6 +279,7 @@ void EditorPropertyArray::update_property() {
button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Element"));
button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
button_add_item->connect(SNAME("pressed"), callable_mp(this, &EditorPropertyArray::_add_element));
+ button_add_item->set_disabled(is_read_only());
vbox->add_child(button_add_item);
paginator = memnew(EditorPaginator);
@@ -328,6 +330,7 @@ void EditorPropertyArray::update_property() {
Button *reorder_button = memnew(Button);
reorder_button->set_icon(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons")));
reorder_button->set_default_cursor_shape(Control::CURSOR_MOVE);
+ reorder_button->set_disabled(is_read_only());
reorder_button->connect("gui_input", callable_mp(this, &EditorPropertyArray::_reorder_button_gui_input));
reorder_button->connect("button_down", callable_mp(this, &EditorPropertyArray::_reorder_button_down).bind(i + offset));
reorder_button->connect("button_up", callable_mp(this, &EditorPropertyArray::_reorder_button_up));
@@ -358,6 +361,7 @@ void EditorPropertyArray::update_property() {
prop->connect("property_changed", callable_mp(this, &EditorPropertyArray::_property_changed));
prop->connect("object_id_selected", callable_mp(this, &EditorPropertyArray::_object_id_selected));
prop->set_h_size_flags(SIZE_EXPAND_FILL);
+ prop->set_read_only(is_read_only());
hbox->add_child(prop);
bool is_untyped_array = array.get_type() == Variant::ARRAY && subtype == Variant::NIL;
@@ -366,10 +370,12 @@ void EditorPropertyArray::update_property() {
Button *edit = memnew(Button);
edit->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
hbox->add_child(edit);
+ edit->set_disabled(is_read_only());
edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_change_type).bind(edit, i + offset));
} else {
Button *remove = memnew(Button);
remove->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ remove->set_disabled(is_read_only());
remove->connect("pressed", callable_mp(this, &EditorPropertyArray::_remove_pressed).bind(i + offset));
hbox->add_child(remove);
}
@@ -409,6 +415,10 @@ void EditorPropertyArray::_button_draw() {
}
bool EditorPropertyArray::_is_drop_valid(const Dictionary &p_drag_data) const {
+ if (is_read_only()) {
+ return false;
+ }
+
String allowed_type = Variant::get_type_name(subtype);
// When the subtype is of type Object, an additional subtype may be specified in the hint string
@@ -609,7 +619,7 @@ void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint
}
void EditorPropertyArray::_reorder_button_gui_input(const Ref<InputEvent> &p_event) {
- if (reorder_from_index < 0) {
+ if (reorder_from_index < 0 || is_read_only()) {
return;
}
@@ -646,6 +656,10 @@ void EditorPropertyArray::_reorder_button_gui_input(const Ref<InputEvent> &p_eve
}
void EditorPropertyArray::_reorder_button_down(int p_index) {
+ if (is_read_only()) {
+ return;
+ }
+
reorder_from_index = p_index;
reorder_to_index = p_index;
reorder_selected_element_hbox = Object::cast_to<HBoxContainer>(property_vbox->get_child(p_index % page_length));
@@ -656,6 +670,10 @@ void EditorPropertyArray::_reorder_button_down(int p_index) {
}
void EditorPropertyArray::_reorder_button_up() {
+ if (is_read_only()) {
+ return;
+ }
+
if (reorder_from_index != reorder_to_index) {
// Move the element.
Variant array = object->get_array();
@@ -1097,6 +1115,10 @@ void EditorPropertyDictionary::update_property() {
}
}
+ ERR_FAIL_COND(!prop);
+
+ prop->set_read_only(is_read_only());
+
if (i == amount) {
PanelContainer *pc = memnew(PanelContainer);
property_vbox->add_child(pc);
@@ -1135,6 +1157,7 @@ void EditorPropertyDictionary::update_property() {
prop->set_h_size_flags(SIZE_EXPAND_FILL);
Button *edit = memnew(Button);
edit->set_icon(get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")));
+ edit->set_disabled(is_read_only());
hbox->add_child(edit);
edit->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_change_type).bind(edit, change_index));
@@ -1143,6 +1166,7 @@ void EditorPropertyDictionary::update_property() {
if (i == amount + 1) {
button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Key/Value Pair"));
button_add_item->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ button_add_item->set_disabled(is_read_only());
button_add_item->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_add_key_value));
add_vbox->add_child(button_add_item);
}
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 5346052f4d..84cb085551 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -186,7 +186,7 @@ void EditorResourcePicker::_update_menu_items() {
// Add options for changing existing value of the resource.
if (edited_resource.is_valid()) {
// Determine if the edited resource is part of another scene (foreign) which was imported
- bool is_edited_resource_foreign_import = EditorNode::get_singleton()->is_resource_read_only(edited_resource);
+ bool is_edited_resource_foreign_import = EditorNode::get_singleton()->is_resource_read_only(edited_resource, true);
// If the resource is determined to be foreign and imported, change the menu entry's description to 'inspect' rather than 'edit'
// since will only be able to view its properties in read-only mode.
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index ec67cde112..8062b6f756 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -552,6 +552,10 @@ void EditorSettingsDialog::_shortcut_cell_double_clicked() {
const ShortcutButton edit_btn_id = EditorSettingsDialog::SHORTCUT_EDIT;
const int edit_btn_col = 1;
TreeItem *ti = shortcuts->get_selected();
+ if (ti == nullptr) {
+ return;
+ }
+
String type = ti->get_meta("type");
int col = shortcuts->get_selected_column();
if (type == "shortcut" && col == 0) {
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index f4b8646e18..ca7b2d0015 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -101,13 +101,13 @@ void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_propert
undo_redo->create_action(TTR("Parameter Changed:") + " " + String(p_property), UndoRedo::MERGE_ENDS);
undo_redo->add_do_property(tree, p_property, p_value);
undo_redo->add_undo_property(tree, p_property, tree->get(p_property));
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
updating = false;
}
-void AnimationNodeBlendTreeEditor::_update_graph() {
+void AnimationNodeBlendTreeEditor::update_graph() {
if (updating || blend_tree.is_null()) {
return;
}
@@ -364,8 +364,8 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
to_slot = -1;
}
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
}
@@ -416,8 +416,8 @@ void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Ve
undo_redo->create_action(TTR("Node Moved"));
undo_redo->add_do_method(blend_tree.ptr(), "set_node_position", p_which, p_to / EDSCALE);
undo_redo->add_undo_method(blend_tree.ptr(), "set_node_position", p_which, p_from / EDSCALE);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
updating = false;
}
@@ -437,8 +437,8 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int
undo_redo->create_action(TTR("Nodes Connected"));
undo_redo->add_do_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from);
undo_redo->add_undo_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
}
@@ -453,8 +453,8 @@ void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from,
undo_redo->create_action(TTR("Nodes Disconnected"));
undo_redo->add_do_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index);
undo_redo->add_undo_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
updating = false;
}
@@ -468,8 +468,8 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options,
undo_redo->create_action(TTR("Set Animation"));
undo_redo->add_do_method(anim.ptr(), "set_animation", option);
undo_redo->add_undo_method(anim.ptr(), "set_animation", anim->get_animation());
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
}
@@ -491,8 +491,8 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
}
}
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
}
@@ -819,7 +819,7 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) {
_update_theme();
if (is_visible_in_tree()) {
- _update_graph();
+ update_graph();
}
} break;
@@ -900,12 +900,23 @@ void AnimationNodeBlendTreeEditor::_scroll_changed(const Vector2 &p_scroll) {
}
void AnimationNodeBlendTreeEditor::_bind_methods() {
- ClassDB::bind_method("_update_graph", &AnimationNodeBlendTreeEditor::_update_graph);
+ ClassDB::bind_method("update_graph", &AnimationNodeBlendTreeEditor::update_graph);
ClassDB::bind_method("_update_filters", &AnimationNodeBlendTreeEditor::_update_filters);
}
AnimationNodeBlendTreeEditor *AnimationNodeBlendTreeEditor::singleton = nullptr;
+// AnimationNode's "node_changed" signal means almost update_input.
+void AnimationNodeBlendTreeEditor::_node_changed(const StringName &p_node_name) {
+ // TODO:
+ // Here is executed during the commit of EditorNode::undo_redo, it is not possible to create an undo_redo action here.
+ // The disconnect when the number of enabled inputs decreases is done in AnimationNodeBlendTree and update_graph().
+ // This means that there is no place to register undo_redo actions.
+ // In order to implement undo_redo correctly, we may need to implement AnimationNodeEdit such as AnimationTrackKeyEdit
+ // and add it to _node_selected() with EditorNode::get_singleton()->push_item(AnimationNodeEdit).
+ update_graph();
+}
+
void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<AnimationNode> p_node) {
if (blend_tree.is_null()) {
return;
@@ -940,8 +951,8 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name);
undo_redo->add_do_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + prev_name, base_path + name);
undo_redo->add_undo_method(AnimationTreeEditor::get_singleton()->get_tree(), "rename_parameter", base_path + name, base_path + prev_name);
- undo_redo->add_do_method(this, "_update_graph");
- undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->add_do_method(this, "update_graph");
+ undo_redo->add_undo_method(this, "update_graph");
undo_redo->commit_action();
updating = false;
gn->set_name(new_name);
@@ -979,7 +990,7 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
}
}
- _update_graph(); // Needed to update the signal connections with the new name.
+ update_graph(); // Needed to update the signal connections with the new name.
}
void AnimationNodeBlendTreeEditor::_node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node) {
@@ -996,6 +1007,7 @@ bool AnimationNodeBlendTreeEditor::can_edit(const Ref<AnimationNode> &p_node) {
void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
if (blend_tree.is_valid()) {
+ blend_tree->disconnect("node_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_changed));
blend_tree->disconnect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph));
}
@@ -1008,9 +1020,10 @@ void AnimationNodeBlendTreeEditor::edit(const Ref<AnimationNode> &p_node) {
} else {
read_only = EditorNode::get_singleton()->is_resource_read_only(blend_tree);
+ blend_tree->connect("node_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_node_changed));
blend_tree->connect("removed_from_graph", callable_mp(this, &AnimationNodeBlendTreeEditor::_removed_from_graph));
- _update_graph();
+ update_graph();
}
add_node->set_disabled(read_only);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index 30a54930a2..46e0d18c69 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -71,8 +71,6 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
int to_slot = -1;
String from_node = "";
- void _update_graph();
-
struct AddOption {
String name;
String type;
@@ -95,6 +93,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which);
void _node_renamed(const String &p_text, Ref<AnimationNode> p_node);
void _node_renamed_focus_out(Node *le, Ref<AnimationNode> p_node);
+ void _node_changed(const StringName &p_node_name);
bool updating;
@@ -150,6 +149,8 @@ public:
virtual bool can_edit(const Ref<AnimationNode> &p_node) override;
virtual void edit(const Ref<AnimationNode> &p_node) override;
+ void update_graph();
+
AnimationNodeBlendTreeEditor();
};
diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp
index ed231c446b..1de4fbaabc 100644
--- a/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_tree_editor_plugin.cpp
@@ -50,10 +50,18 @@
#include "scene/scene_string_names.h"
void AnimationTreeEditor::edit(AnimationTree *p_tree) {
+ if (p_tree && !p_tree->is_connected("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) {
+ p_tree->connect("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed), CONNECT_DEFERRED);
+ }
+
if (tree == p_tree) {
return;
}
+ if (tree && tree->is_connected("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed))) {
+ tree->disconnect("animation_player_changed", callable_mp(this, &AnimationTreeEditor::_animation_list_changed));
+ }
+
tree = p_tree;
Vector<String> path;
@@ -73,6 +81,13 @@ void AnimationTreeEditor::_path_button_pressed(int p_path) {
}
}
+void AnimationTreeEditor::_animation_list_changed() {
+ AnimationNodeBlendTreeEditor *bte = AnimationNodeBlendTreeEditor::get_singleton();
+ if (bte) {
+ bte->update_graph();
+ }
+}
+
void AnimationTreeEditor::_update_path() {
while (path_hb->get_child_count() > 1) {
memdelete(path_hb->get_child(1));
diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h
index a33d97f62f..9ef9fff8cd 100644
--- a/editor/plugins/animation_tree_editor_plugin.h
+++ b/editor/plugins/animation_tree_editor_plugin.h
@@ -65,6 +65,7 @@ class AnimationTreeEditor : public VBoxContainer {
ObjectID current_root;
void _path_button_pressed(int p_path);
+ void _animation_list_changed();
static Vector<String> get_animation_list();
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index c8b49678d2..33aad0ac61 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -7645,6 +7645,7 @@ void Node3DEditor::_update_preview_environment() {
preview_sun->get_parent()->remove_child(preview_sun);
sun_state->show();
sun_vb->hide();
+ preview_sun_dangling = true;
}
if (directional_light_count > 0) {
@@ -7658,6 +7659,7 @@ void Node3DEditor::_update_preview_environment() {
add_child(preview_sun, true);
sun_state->hide();
sun_vb->show();
+ preview_sun_dangling = false;
}
}
@@ -7673,6 +7675,7 @@ void Node3DEditor::_update_preview_environment() {
preview_environment->get_parent()->remove_child(preview_environment);
environ_state->show();
environ_vb->hide();
+ preview_env_dangling = true;
}
if (world_env_count > 0) {
environ_state->set_text(TTR("Scene contains\nWorldEnvironment.\nPreview disabled."));
@@ -7685,6 +7688,7 @@ void Node3DEditor::_update_preview_environment() {
add_child(preview_environment);
environ_state->hide();
environ_vb->show();
+ preview_env_dangling = false;
}
}
}
@@ -7854,7 +7858,6 @@ Node3DEditor::Node3DEditor() {
sun_button->set_toggle_mode(true);
sun_button->set_flat(true);
sun_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED);
- sun_button->set_disabled(true);
// Preview is enabled by default - ensure this applies on editor startup when there is no state yet.
sun_button->set_pressed(true);
@@ -7865,7 +7868,6 @@ Node3DEditor::Node3DEditor() {
environ_button->set_toggle_mode(true);
environ_button->set_flat(true);
environ_button->connect("pressed", callable_mp(this, &Node3DEditor::_update_preview_environment), CONNECT_DEFERRED);
- environ_button->set_disabled(true);
// Preview is enabled by default - ensure this applies on editor startup when there is no state yet.
environ_button->set_pressed(true);
@@ -8333,6 +8335,12 @@ void fragment() {
}
Node3DEditor::~Node3DEditor() {
memdelete(preview_node);
+ if (preview_sun_dangling && preview_sun) {
+ memdelete(preview_sun);
+ }
+ if (preview_env_dangling && preview_environment) {
+ memdelete(preview_environment);
+ }
}
void Node3DEditorPlugin::make_visible(bool p_visible) {
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index 580cb878ce..c76f534c22 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -763,7 +763,9 @@ private:
Button *sun_environ_settings = nullptr;
DirectionalLight3D *preview_sun = nullptr;
+ bool preview_sun_dangling = false;
WorldEnvironment *preview_environment = nullptr;
+ bool preview_env_dangling = false;
Ref<Environment> environment;
Ref<CameraAttributesPhysical> camera_attributes;
Ref<ProceduralSkyMaterial> sky_material;
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 246bc4b183..815a61f8ac 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -1366,6 +1366,7 @@ void ShaderEditorPlugin::_shader_selected(int p_index) {
edited_shaders[p_index].shader_editor->validate_script();
}
shader_tabs->set_current_tab(p_index);
+ shader_list->select(p_index);
}
void ShaderEditorPlugin::_shader_list_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index) {
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index ae21aad337..d0a1ddafa1 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -984,11 +984,17 @@ void SpriteFramesEditor::_update_library(bool p_skip_selector) {
}
void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
- if (frames == p_frames) {
+ bool new_read_only_state = false;
+ if (p_frames) {
+ new_read_only_state = EditorNode::get_singleton()->is_resource_read_only(p_frames);
+ }
+
+ if (frames == p_frames && new_read_only_state == read_only) {
return;
}
frames = p_frames;
+ read_only = new_read_only_state;
if (p_frames) {
if (!p_frames->has_animation(edited_anim)) {
@@ -1009,6 +1015,20 @@ void SpriteFramesEditor::edit(SpriteFrames *p_frames) {
} else {
hide();
}
+
+ new_anim->set_disabled(read_only);
+ remove_anim->set_disabled(read_only);
+ anim_speed->set_editable(!read_only);
+ anim_loop->set_disabled(read_only);
+ load->set_disabled(read_only);
+ load_sheet->set_disabled(read_only);
+ copy->set_disabled(read_only);
+ paste->set_disabled(read_only);
+ empty->set_disabled(read_only);
+ empty2->set_disabled(read_only);
+ move_up->set_disabled(read_only);
+ move_down->set_disabled(read_only);
+ _delete->set_disabled(read_only);
}
void SpriteFramesEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
@@ -1016,6 +1036,10 @@ void SpriteFramesEditor::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
}
Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+ if (read_only) {
+ return false;
+ }
+
if (!frames->has_animation(edited_anim)) {
return false;
}
@@ -1038,6 +1062,10 @@ Variant SpriteFramesEditor::get_drag_data_fw(const Point2 &p_point, Control *p_f
}
bool SpriteFramesEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ if (read_only) {
+ return false;
+ }
+
Dictionary d = p_data;
if (!d.has("type")) {
@@ -1169,6 +1197,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
remove_anim->set_flat(true);
remove_anim->set_tooltip_text(TTR("Remove Animation"));
hbc_animlist->add_child(remove_anim);
+ remove_anim->set_disabled(true);
remove_anim->connect("pressed", callable_mp(this, &SpriteFramesEditor::_animation_remove));
anim_search_box = memnew(LineEdit);
diff --git a/editor/plugins/sprite_frames_editor_plugin.h b/editor/plugins/sprite_frames_editor_plugin.h
index f2530b732f..092f556c63 100644
--- a/editor/plugins/sprite_frames_editor_plugin.h
+++ b/editor/plugins/sprite_frames_editor_plugin.h
@@ -57,6 +57,8 @@ class SpriteFramesEditor : public HSplitContainer {
};
int dominant_param = PARAM_FRAME_COUNT;
+ bool read_only = false;
+
Button *load = nullptr;
Button *load_sheet = nullptr;
Button *_delete = nullptr;
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index f11874a994..69a2670418 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -2164,9 +2164,11 @@ void ProjectManager::_open_selected_projects_ask() {
return;
}
+ const Size2i popup_min_width = Size2i(600.0 * EDSCALE, 0);
+
if (selected_list.size() > 1) {
- multi_open_ask->set_text(TTR("Are you sure to open more than one project?"));
- multi_open_ask->popup_centered();
+ multi_open_ask->set_text(vformat(TTR("You requested to open %d projects in parallel. Do you confirm?\nNote that usual checks for engine version compatibility will be bypassed."), selected_list.size()));
+ multi_open_ask->popup_centered(popup_min_width);
return;
}
@@ -2175,8 +2177,7 @@ void ProjectManager::_open_selected_projects_ask() {
return;
}
- // Update the project settings or don't open
- const String conf = project.path.path_join("project.godot");
+ // Update the project settings or don't open.
const int config_version = project.version;
PackedStringArray unsupported_features = project.unsupported_features;
@@ -2186,26 +2187,30 @@ void ProjectManager::_open_selected_projects_ask() {
ask_update_settings->get_ok_button()->set_text("OK");
- // Check if the config_version property was empty or 0
+ // Check if the config_version property was empty or 0.
if (config_version == 0) {
- ask_update_settings->set_text(vformat(TTR("The following project settings file does not specify the version of Godot through which it was created.\n\n%s\n\nIf you proceed with opening it, it will be converted to Godot's current configuration file format.\nWarning: You won't be able to open the project with previous versions of the engine anymore."), conf));
- ask_update_settings->popup_centered();
+ ask_update_settings->set_text(vformat(TTR("The selected project \"%s\" does not specify its supported Godot version in its configuration file (\"project.godot\").\n\nProject path: %s\n\nIf you proceed with opening it, it will be converted to Godot's current configuration file format.\n\nWarning: You won't be able to open the project with previous versions of the engine anymore."), project.project_name, project.path));
+ ask_update_settings->popup_centered(popup_min_width);
return;
}
- // Check if we need to convert project settings from an earlier engine version
+ // Check if we need to convert project settings from an earlier engine version.
if (config_version < ProjectSettings::CONFIG_VERSION) {
if (config_version == GODOT4_CONFIG_VERSION - 1 && ProjectSettings::CONFIG_VERSION == GODOT4_CONFIG_VERSION) { // Conversion from Godot 3 to 4.
full_convert_button->show();
+ ask_update_settings->set_text(vformat(TTR("The selected project \"%s\" was generated by Godot 3.x, and needs to be converted for Godot 4.x.\n\nProject path: %s\n\nYou have three options:\n- Convert only the configuration file (\"project.godot\"). Use this to open the project without attempting to convert its scenes, resources and scripts.\n- Convert the entire project including its scenes, resources and scripts (recommended if you are upgrading).\n- Do nothing and go back.\n\nWarning: If you select a conversion option, you won't be able to open the project with previous versions of the engine anymore."), project.project_name, project.path));
+ ask_update_settings->get_ok_button()->set_text(TTR("Convert project.godot Only"));
+ } else {
+ ask_update_settings->set_text(vformat(TTR("The selected project \"%s\" was generated by an older engine version, and needs to be converted for this version.\n\nProject path: %s\n\nDo you want to convert it?\n\nWarning: You won't be able to open the project with previous versions of the engine anymore."), project.project_name, project.path));
+ ask_update_settings->get_ok_button()->set_text(TTR("Convert project.godot"));
}
- ask_update_settings->set_text(vformat(TTR("The following project settings file was generated by an older engine version, and needs to be converted for this version:\n\n%s\n\nDo you want to convert it? You can also convert the entire project (recommended if you are upgrading).\nWarning: You won't be able to open the project with previous versions of the engine anymore."), conf));
- ask_update_settings->get_ok_button()->set_text(TTR("Convert project.godot"));
- ask_update_settings->popup_centered();
+ ask_update_settings->popup_centered(popup_min_width);
+ ask_update_settings->get_cancel_button()->grab_focus(); // To prevent accidents.
return;
}
- // Check if the file was generated by a newer, incompatible engine version
+ // Check if the file was generated by a newer, incompatible engine version.
if (config_version > ProjectSettings::CONFIG_VERSION) {
- dialog_error->set_text(vformat(TTR("Can't open project at '%s'.") + "\n" + TTR("The project settings were created by a newer engine version, whose settings are not compatible with this version."), project.path));
- dialog_error->popup_centered();
+ dialog_error->set_text(vformat(TTR("Can't open project \"%s\" at the following path:\n\n%s\n\nThe project settings were created by a newer engine version, whose settings are not compatible with this version."), project.project_name, project.path));
+ dialog_error->popup_centered(popup_min_width);
return;
}
// Check if the project is using features not supported by this build of Godot.
@@ -2234,14 +2239,20 @@ void ProjectManager::_open_selected_projects_ask() {
warning_message += TTR("Open anyway? Project will be modified.");
ask_update_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
ask_update_settings->set_text(warning_message);
- ask_update_settings->popup_centered();
+ ask_update_settings->popup_centered(popup_min_width);
return;
}
- // Open if the project is up-to-date
+ // Open if the project is up-to-date.
_open_selected_projects();
}
+void ProjectManager::_full_convert_button_pressed() {
+ ask_update_settings->hide();
+ ask_full_convert_dialog->popup_centered(Size2i(600.0 * EDSCALE, 0));
+ ask_full_convert_dialog->get_cancel_button()->grab_focus();
+}
+
void ProjectManager::_perform_full_project_conversion() {
Vector<ProjectList::Item> selected_list = _project_list->get_selected_projects();
if (selected_list.is_empty()) {
@@ -2869,21 +2880,18 @@ ProjectManager::ProjectManager() {
add_child(multi_scan_ask);
ask_update_settings = memnew(ConfirmationDialog);
+ ask_update_settings->set_autowrap(true);
ask_update_settings->get_ok_button()->connect("pressed", callable_mp(this, &ProjectManager::_confirm_update_settings));
- full_convert_button = ask_update_settings->add_button("Perform Full Project Conversion", false);
+ full_convert_button = ask_update_settings->add_button("Convert Full Project", !GLOBAL_GET("gui/common/swap_cancel_ok"));
+ full_convert_button->connect("pressed", callable_mp(this, &ProjectManager::_full_convert_button_pressed));
add_child(ask_update_settings);
ask_full_convert_dialog = memnew(ConfirmationDialog);
ask_full_convert_dialog->set_autowrap(true);
- ask_full_convert_dialog->set_text(TTR(R"(This option will perform full project conversion, updating scenes and scripts from Godot 3.x to work in Godot 4.0. Note that this is a best-effort conversion, i.e. it makes upgrading the project easier, but it will not open out-of-the-box and will still require manual adjustments.
-
-IMPORTANT: Make sure to backup your project before converting, as this operation makes it impossible to open in older versions of Godot.)"));
+ ask_full_convert_dialog->set_text(TTR("This option will perform full project conversion, updating scenes, resources and scripts from Godot 3.x to work in Godot 4.0.\n\nNote that this is a best-effort conversion, i.e. it makes upgrading the project easier, but it will not open out-of-the-box and will still require manual adjustments.\n\nIMPORTANT: Make sure to backup your project before converting, as this operation makes it impossible to open it in older versions of Godot."));
ask_full_convert_dialog->connect("confirmed", callable_mp(this, &ProjectManager::_perform_full_project_conversion));
add_child(ask_full_convert_dialog);
- full_convert_button->connect("pressed", callable_mp((Window *)ask_update_settings, &ConfirmationDialog::hide));
- full_convert_button->connect("pressed", callable_mp((Window *)ask_full_convert_dialog, &ConfirmationDialog::popup_centered_ratio).bind(0.2));
-
npdialog = memnew(ProjectDialog);
npdialog->connect("projects_updated", callable_mp(this, &ProjectManager::_on_projects_updated));
npdialog->connect("project_created", callable_mp(this, &ProjectManager::_on_project_created));
diff --git a/editor/project_manager.h b/editor/project_manager.h
index 0831a63e68..7c05429dde 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -108,6 +108,7 @@ class ProjectManager : public Control {
void _run_project_confirm();
void _open_selected_projects();
void _open_selected_projects_ask();
+ void _full_convert_button_pressed();
void _perform_full_project_conversion();
void _import_project();
void _new_project();
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index e37ac1dc3b..b6e7dc397a 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -3189,7 +3189,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
p_preload->resolved_path = parser->script_path.get_base_dir().path_join(p_preload->resolved_path);
}
p_preload->resolved_path = p_preload->resolved_path.simplify_path();
- if (!FileAccess::exists(p_preload->resolved_path)) {
+ if (!ResourceLoader::exists(p_preload->resolved_path)) {
push_error(vformat(R"(Preload file "%s" does not exist.)", p_preload->resolved_path), p_preload->path);
} else {
// TODO: Don't load if validating: use completion cache.
diff --git a/modules/mono/build_scripts/build_assemblies.py b/modules/mono/build_scripts/build_assemblies.py
index 6f66ce9efa..d78a9c7db8 100755
--- a/modules/mono/build_scripts/build_assemblies.py
+++ b/modules/mono/build_scripts/build_assemblies.py
@@ -315,6 +315,8 @@ def main():
output_dir = os.path.abspath(args.godot_output_dir)
+ push_nupkgs_local = os.path.abspath(args.push_nupkgs_local) if args.push_nupkgs_local else None
+
msbuild_tool = find_any_msbuild_tool(args.mono_prefix)
if msbuild_tool is None:
@@ -327,7 +329,7 @@ def main():
output_dir,
args.godot_platform,
args.dev_debug,
- args.push_nupkgs_local,
+ push_nupkgs_local,
args.float,
)
sys.exit(exit_code)
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
index bff9760b32..859ea52c93 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.targets
@@ -17,7 +17,7 @@
<!-- C# source generators -->
<ItemGroup Condition=" '$(DisableImplicitGodotGeneratorReferences)' != 'true' ">
- <PackageReference Include="Godot.SourceGenerators" Version="$(PackageFloatingVersion_Godot)" />
+ <PackageReference Include="Godot.SourceGenerators" Version="$(PackageVersion_Godot_SourceGenerators)" />
</ItemGroup>
<!-- Godot API references -->
diff --git a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
index 4baae77b34..37bd4a0be0 100644
--- a/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
+++ b/modules/mono/editor/GodotTools/GodotTools.Shared/GenerateGodotNupkgsVersions.targets
@@ -21,10 +21,13 @@
Outputs="$(GeneratedGodotNupkgsVersionsFile)">
<PropertyGroup>
<GenerateGodotNupkgsVersionsCode><![CDATA[
-namespace $(RootNamespace) {
- public class GeneratedGodotNupkgsVersions {
+namespace $(RootNamespace)
+{
+ public class GeneratedGodotNupkgsVersions
+ {
public const string GodotNETSdk = "$(PackageVersion_Godot_NET_Sdk)"%3b
public const string GodotSourceGenerators = "$(PackageVersion_Godot_SourceGenerators)"%3b
+ public const string GodotSharp = "$(PackageVersion_GodotSharp)"%3b
}
}
]]></GenerateGodotNupkgsVersionsCode>
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs
index 7bce53308c..b437c7e742 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/DotNetFinder.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
+using System.Runtime.InteropServices;
using JetBrains.Annotations;
using OS = GodotTools.Utils.OS;
@@ -16,6 +17,23 @@ namespace GodotTools.Build
// In the future, this method may do more than just search in PATH. We could look in
// known locations or use Godot's linked nethost to search from the hostfxr location.
+ if (OS.IsMacOS)
+ {
+ if (RuntimeInformation.OSArchitecture == Architecture.X64)
+ {
+ string dotnet_x64 = "/usr/local/share/dotnet/x64/dotnet"; // Look for x64 version, when running under Rosetta 2.
+ if (File.Exists(dotnet_x64))
+ {
+ return dotnet_x64;
+ }
+ }
+ string dotnet = "/usr/local/share/dotnet/dotnet"; // Look for native version.
+ if (File.Exists(dotnet))
+ {
+ return dotnet;
+ }
+ }
+
return OS.PathWhich("dotnet");
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
index d2e0e128b5..fe309b8102 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/NuGetUtils.cs
@@ -22,71 +22,13 @@ namespace GodotTools.Build
public static string GodotFallbackFolderPath
=> Path.Combine(GodotSharpDirs.MonoUserDir, "GodotNuGetFallbackFolder");
- private static void AddFallbackFolderToNuGetConfig(string nuGetConfigPath, string name, string path)
- {
- var xmlDoc = new XmlDocument();
- xmlDoc.Load(nuGetConfigPath);
-
- const string nuGetConfigRootName = "configuration";
-
- var rootNode = xmlDoc.DocumentElement;
-
- if (rootNode == null)
- {
- // No root node, create it
- rootNode = xmlDoc.CreateElement(nuGetConfigRootName);
- xmlDoc.AppendChild(rootNode);
-
- // Since this can be considered pretty much a new NuGet.Config, add the default nuget.org source as well
- XmlElement nugetOrgSourceEntry = xmlDoc.CreateElement("add");
- nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("key")).Value = "nuget.org";
- nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("value")).Value =
- "https://api.nuget.org/v3/index.json";
- nugetOrgSourceEntry.Attributes.Append(xmlDoc.CreateAttribute("protocolVersion")).Value = "3";
- rootNode.AppendChild(xmlDoc.CreateElement("packageSources")).AppendChild(nugetOrgSourceEntry);
- }
- else
- {
- // Check that the root node is the expected one
- if (rootNode.Name != nuGetConfigRootName)
- throw new FormatException("Invalid root Xml node for NuGet.Config. " +
- $"Expected '{nuGetConfigRootName}' got '{rootNode.Name}'.");
- }
-
- var fallbackFoldersNode = rootNode["fallbackPackageFolders"] ??
- rootNode.AppendChild(xmlDoc.CreateElement("fallbackPackageFolders"));
-
- // Check if it already has our fallback package folder
- for (var xmlNode = fallbackFoldersNode.FirstChild; xmlNode != null; xmlNode = xmlNode.NextSibling)
- {
- if (xmlNode.NodeType != XmlNodeType.Element)
- continue;
-
- var xmlElement = (XmlElement)xmlNode;
- if (xmlElement.Name == "add" &&
- xmlElement.Attributes["key"]?.Value == name &&
- xmlElement.Attributes["value"]?.Value == path)
- {
- return;
- }
- }
-
- XmlElement newEntry = xmlDoc.CreateElement("add");
- newEntry.Attributes.Append(xmlDoc.CreateAttribute("key")).Value = name;
- newEntry.Attributes.Append(xmlDoc.CreateAttribute("value")).Value = path;
-
- fallbackFoldersNode.AppendChild(newEntry);
-
- xmlDoc.Save(nuGetConfigPath);
- }
-
/// <summary>
- /// Returns all the paths where the user NuGet.Config files can be found.
+ /// Returns all the paths where the Godot.Offline.Config files can be found.
/// Does not determine whether the returned files exist or not.
/// </summary>
- private static string[] GetAllUserNuGetConfigFilePaths()
+ private static string[] GetAllGodotNuGetConfigFilePaths()
{
- // Where to find 'NuGet/NuGet.Config':
+ // Where to find 'NuGet/config/Godot.Offline.Config':
//
// - Mono/.NETFramework (standalone NuGet):
// Uses Environment.SpecialFolder.ApplicationData
@@ -98,10 +40,12 @@ namespace GodotTools.Build
string applicationData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
+ const string configFileName = "Godot.Offline.Config";
+
if (Utils.OS.IsWindows)
{
// %APPDATA% for both
- return new[] { Path.Combine(applicationData, "NuGet", "NuGet.Config") };
+ return new[] { Path.Combine(applicationData, "NuGet", "config", configFileName) };
}
var paths = new string[2];
@@ -111,20 +55,20 @@ namespace GodotTools.Build
string dotnetCliHome = Environment.GetEnvironmentVariable("DOTNET_CLI_HOME");
if (!string.IsNullOrEmpty(dotnetCliHome))
{
- paths[0] = Path.Combine(dotnetCliHome, ".nuget", "NuGet", "NuGet.Config");
+ paths[0] = Path.Combine(dotnetCliHome, ".nuget", "NuGet", "config", configFileName);
}
else
{
string home = Environment.GetEnvironmentVariable("HOME");
if (string.IsNullOrEmpty(home))
throw new InvalidOperationException("Required environment variable 'HOME' is not set.");
- paths[0] = Path.Combine(home, ".nuget", "NuGet", "NuGet.Config");
+ paths[0] = Path.Combine(home, ".nuget", "NuGet", "config", configFileName);
}
// Mono/.NETFramework (standalone NuGet)
// ApplicationData is $HOME/.config on Linux/macOS
- paths[1] = Path.Combine(applicationData, "NuGet", "NuGet.Config");
+ paths[1] = Path.Combine(applicationData, "NuGet", "config", configFileName);
return paths;
}
@@ -141,28 +85,26 @@ namespace GodotTools.Build
// The nuspec is not lower case inside the nupkg but must be made lower case when extracted.
/// <summary>
- /// Adds the specified fallback folder to the user NuGet.Config files,
+ /// Adds the specified fallback folder to the Godot.Offline.Config files,
/// for both standalone NuGet (Mono/.NETFramework) and dotnet CLI NuGet.
/// </summary>
- public static void AddFallbackFolderToUserNuGetConfigs(string name, string path)
+ public static void AddFallbackFolderToGodotNuGetConfigs(string name, string path)
{
- foreach (string nuGetConfigPath in GetAllUserNuGetConfigFilePaths())
+ // Make sure the fallback folder exists to avoid error:
+ // MSB4018: The "ResolvePackageAssets" task failed unexpectedly.
+ System.IO.Directory.CreateDirectory(path);
+
+ foreach (string nuGetConfigPath in GetAllGodotNuGetConfigFilePaths())
{
- if (!System.IO.File.Exists(nuGetConfigPath))
- {
- // It doesn't exist, so we create a default one
- const string defaultConfig = @"<?xml version=""1.0"" encoding=""utf-8""?>
+ string defaultConfig = @$"<?xml version=""1.0"" encoding=""utf-8""?>
<configuration>
- <packageSources>
- <add key=""nuget.org"" value=""https://api.nuget.org/v3/index.json"" protocolVersion=""3"" />
- </packageSources>
+ <fallbackPackageFolders>
+ <add key=""{name}"" value=""{path}"" />
+ </fallbackPackageFolders>
</configuration>
";
- System.IO.Directory.CreateDirectory(Path.GetDirectoryName(nuGetConfigPath));
- System.IO.File.WriteAllText(nuGetConfigPath, defaultConfig, Encoding.UTF8); // UTF-8 with BOM
- }
-
- AddFallbackFolderToNuGetConfig(nuGetConfigPath, name, path);
+ System.IO.Directory.CreateDirectory(Path.GetDirectoryName(nuGetConfigPath));
+ System.IO.File.WriteAllText(nuGetConfigPath, defaultConfig, Encoding.UTF8); // UTF-8 with BOM
}
}
@@ -189,6 +131,7 @@ namespace GodotTools.Build
string destDir = Path.Combine(fallbackFolder, packageIdLower, packageVersionLower);
string nupkgDestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg");
string nupkgSha512DestPath = Path.Combine(destDir, $"{packageIdLower}.{packageVersionLower}.nupkg.sha512");
+ string nupkgMetadataDestPath = Path.Combine(destDir, ".nupkg.metadata");
if (File.Exists(nupkgDestPath) && File.Exists(nupkgSha512DestPath))
return; // Already added (for speed we don't check if every file is properly extracted)
@@ -197,12 +140,18 @@ namespace GodotTools.Build
// Generate .nupkg.sha512 file
- using (var alg = SHA512.Create())
- {
- alg.ComputeHash(File.ReadAllBytes(nupkgPath));
- string base64Hash = Convert.ToBase64String(alg.Hash);
- File.WriteAllText(nupkgSha512DestPath, base64Hash);
- }
+ byte[] hash = SHA512.HashData(File.ReadAllBytes(nupkgPath));
+ string base64Hash = Convert.ToBase64String(hash);
+ File.WriteAllText(nupkgSha512DestPath, base64Hash);
+
+ // Generate .nupkg.metadata file
+ // Spec: https://github.com/NuGet/Home/wiki/Nupkg-Metadata-File
+
+ File.WriteAllText(nupkgMetadataDestPath, @$"{{
+ ""version"": 2,
+ ""contentHash"": ""{base64Hash}"",
+ ""source"": null
+}}");
// Extract nupkg
ExtractNupkg(destDir, nupkgPath, packageId, packageVersion);
@@ -251,7 +200,7 @@ namespace GodotTools.Build
entryFullName.EndsWith(".nupkg.sha512", StringComparison.OrdinalIgnoreCase) ||
entryFullName.EndsWith(".nupkg.metadata", StringComparison.OrdinalIgnoreCase) ||
// Nuspec at root level. We already extracted it previously but in lower case.
- entryFullName.IndexOf('/') == -1 && entryFullName.EndsWith(".nuspec"))
+ !entryFullName.Contains('/') && entryFullName.EndsWith(".nuspec"))
{
continue;
}
@@ -297,6 +246,8 @@ namespace GodotTools.Build
{
("Godot.NET.Sdk", GeneratedGodotNupkgsVersions.GodotNETSdk),
("Godot.SourceGenerators", GeneratedGodotNupkgsVersions.GodotSourceGenerators),
+ ("GodotSharp", GeneratedGodotNupkgsVersions.GodotSharp),
+ ("GodotSharpEditor", GeneratedGodotNupkgsVersions.GodotSharp),
};
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 1cfaea3ec9..89364d1c02 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -123,7 +123,7 @@ namespace GodotTools
try
{
string fallbackFolder = NuGetUtils.GodotFallbackFolderPath;
- NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
+ NuGetUtils.AddFallbackFolderToGodotNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
fallbackFolder);
NuGetUtils.AddBundledPackagesToFallbackFolder(fallbackFolder);
}
@@ -497,7 +497,7 @@ namespace GodotTools
try
{
// At startup we make sure NuGet.Config files have our Godot NuGet fallback folder included
- NuGetUtils.AddFallbackFolderToUserNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
+ NuGetUtils.AddFallbackFolderToGodotNuGetConfigs(NuGetUtils.GodotFallbackFolderName,
NuGetUtils.GodotFallbackFolderPath);
}
catch (Exception e)
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index c27bb959fe..ce4ac9b796 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -2229,6 +2229,26 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
// Generate signal
{
+ if (p_isignal.is_deprecated) {
+ if (p_isignal.deprecation_message.is_empty()) {
+ WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + p_isignal.proxy_name + "'.");
+ }
+
+ p_output.append(MEMBER_BEGIN "[Obsolete(\"");
+ p_output.append(p_isignal.deprecation_message);
+ p_output.append("\")]");
+ }
+
+ String delegate_name = p_isignal.proxy_name;
+ delegate_name += "EventHandler"; // Delegate name is [SignalName]EventHandler
+
+ // Generate delegate
+ p_output.append(MEMBER_BEGIN "public delegate void ");
+ p_output.append(delegate_name);
+ p_output.append("(");
+ p_output.append(arguments_sig);
+ p_output.append(");\n");
+
if (p_isignal.method_doc && p_isignal.method_doc->description.size()) {
String xml_summary = bbcode_to_xml(fix_doc_description(p_isignal.method_doc->description), &p_itype);
Vector<String> summary_lines = xml_summary.length() ? xml_summary.split("\n") : Vector<String>();
@@ -2247,25 +2267,11 @@ Error BindingsGenerator::_generate_cs_signal(const BindingsGenerator::TypeInterf
}
if (p_isignal.is_deprecated) {
- if (p_isignal.deprecation_message.is_empty()) {
- WARN_PRINT("An empty deprecation message is discouraged. Signal: '" + p_isignal.proxy_name + "'.");
- }
-
p_output.append(MEMBER_BEGIN "[Obsolete(\"");
p_output.append(p_isignal.deprecation_message);
p_output.append("\")]");
}
- String delegate_name = p_isignal.proxy_name;
- delegate_name += "EventHandler"; // Delegate name is [SignalName]EventHandler
-
- // Generate delegate
- p_output.append(MEMBER_BEGIN "public delegate void ");
- p_output.append(delegate_name);
- p_output.append("(");
- p_output.append(arguments_sig);
- p_output.append(");\n");
-
// TODO:
// Could we assume the StringName instance of signal name will never be freed (it's stored in ClassDB) before the managed world is unloaded?
// If so, we could store the pointer we get from `data_unique_pointer()` instead of allocating StringName here.
diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp
index 9d0864e4d5..d46972ffb6 100644
--- a/modules/multiplayer/multiplayer_spawner.cpp
+++ b/modules/multiplayer/multiplayer_spawner.cpp
@@ -91,9 +91,6 @@ void MultiplayerSpawner::add_spawnable_scene(const String &p_path) {
sc.path = p_path;
if (Engine::get_singleton()->is_editor_hint()) {
ERR_FAIL_COND(!FileAccess::exists(p_path));
- } else {
- sc.cache = ResourceLoader::load(p_path);
- ERR_FAIL_COND_MSG(sc.cache.is_null(), "Invalid spawnable scene: " + p_path);
}
spawnable_scenes.push_back(sc);
}
@@ -271,9 +268,12 @@ const Variant MultiplayerSpawner::get_spawn_argument(const ObjectID &p_id) const
Node *MultiplayerSpawner::instantiate_scene(int p_id) {
ERR_FAIL_COND_V_MSG(spawn_limit && spawn_limit <= tracked_nodes.size(), nullptr, "Spawn limit reached!");
ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_id, spawnable_scenes.size(), nullptr);
- Ref<PackedScene> scene = spawnable_scenes[p_id].cache;
- ERR_FAIL_COND_V(scene.is_null(), nullptr);
- return scene->instantiate();
+ SpawnableScene &sc = spawnable_scenes[p_id];
+ if (sc.cache.is_null()) {
+ sc.cache = ResourceLoader::load(sc.path);
+ }
+ ERR_FAIL_COND_V_MSG(sc.cache.is_null(), nullptr, "Invalid spawnable scene: " + sc.path);
+ return sc.cache->instantiate();
}
Node *MultiplayerSpawner::instantiate_custom(const Variant &p_data) {
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index cfb8e0cd42..f989fc45a5 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -209,6 +209,9 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
for (uint32_t shape_owner : shape_owners) {
const int shape_count = static_body->shape_owner_get_shape_count(shape_owner);
for (int i = 0; i < shape_count; i++) {
+ if (static_body->is_shape_owner_disabled(i)) {
+ continue;
+ }
Ref<Shape3D> s = static_body->shape_owner_get_shape(shape_owner, i);
if (s.is_null()) {
continue;
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 92d074cb75..94095eb61c 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -1557,7 +1557,7 @@ void OpenXRAPI::end_frame() {
XrCompositionLayerProjection projection_layer = {
XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type
nullptr, // next
- layers_list.size() > 1 ? XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT : XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, // layerFlags
+ layers_list.size() > 0 ? XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT : XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, // layerFlags
play_space, // space
view_count, // viewCount
projection_views, // views
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 142dc54c45..4469c7a0f7 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -44,6 +44,7 @@
#include "net_socket_android.h"
#include <dlfcn.h>
+#include <sys/system_properties.h>
#include "java_godot_io_wrapper.h"
#include "java_godot_wrapper.h"
@@ -175,6 +176,79 @@ String OS_Android::get_name() const {
return "Android";
}
+String OS_Android::get_system_property(const char *key) const {
+ static String value;
+ char value_str[PROP_VALUE_MAX];
+ if (__system_property_get(key, value_str)) {
+ value = String(value_str);
+ }
+ return value;
+}
+
+String OS_Android::get_distribution_name() const {
+ if (!get_system_property("ro.havoc.version").is_empty()) {
+ return "Havoc OS";
+ } else if (!get_system_property("org.pex.version").is_empty()) { // Putting before "Pixel Experience", because it's derivating from it.
+ return "Pixel Extended";
+ } else if (!get_system_property("org.pixelexperience.version").is_empty()) {
+ return "Pixel Experience";
+ } else if (!get_system_property("ro.potato.version").is_empty()) {
+ return "POSP";
+ } else if (!get_system_property("ro.xtended.version").is_empty()) {
+ return "Project-Xtended";
+ } else if (!get_system_property("org.evolution.version").is_empty()) {
+ return "Evolution X";
+ } else if (!get_system_property("ro.corvus.version").is_empty()) {
+ return "Corvus-Q";
+ } else if (!get_system_property("ro.pa.version").is_empty()) {
+ return "Paranoid Android";
+ } else if (!get_system_property("ro.crdroid.version").is_empty()) {
+ return "crDroid Android";
+ } else if (!get_system_property("ro.syberia.version").is_empty()) {
+ return "Syberia Project";
+ } else if (!get_system_property("ro.arrow.version").is_empty()) {
+ return "ArrowOS";
+ } else if (!get_system_property("ro.lineage.version").is_empty()) { // Putting LineageOS last, just in case any derivative writes to "ro.lineage.version".
+ return "LineageOS";
+ }
+
+ if (!get_system_property("ro.modversion").is_empty()) { // Handles other Android custom ROMs.
+ return vformat("%s %s", get_name(), "Custom ROM");
+ }
+
+ // Handles stock Android.
+ return get_name();
+}
+
+String OS_Android::get_version() const {
+ const Vector<const char *> roms = { "ro.havoc.version", "org.pex.version", "org.pixelexperience.version",
+ "ro.potato.version", "ro.xtended.version", "org.evolution.version", "ro.corvus.version", "ro.pa.version",
+ "ro.crdroid.version", "ro.syberia.version", "ro.arrow.version", "ro.lineage.version" };
+ for (int i = 0; i < roms.size(); i++) {
+ static String rom_version = get_system_property(roms[i]);
+ if (!rom_version.is_empty()) {
+ return rom_version;
+ }
+ }
+
+ static String mod_version = get_system_property("ro.modversion"); // Handles other Android custom ROMs.
+ if (!mod_version.is_empty()) {
+ return mod_version;
+ }
+
+ // Handles stock Android.
+ static String sdk_version = get_system_property("ro.build.version.sdk_int");
+ static String build = get_system_property("ro.build.version.incremental");
+ if (!sdk_version.is_empty()) {
+ if (!build.is_empty()) {
+ return vformat("%s.%s", sdk_version, build);
+ }
+ return sdk_version;
+ }
+
+ return "";
+}
+
MainLoop *OS_Android::get_main_loop() const {
return main_loop;
}
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 96c06d715c..d6546a3507 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -65,6 +65,8 @@ private:
GodotJavaWrapper *godot_java = nullptr;
GodotIOJavaWrapper *godot_io_java = nullptr;
+ String get_system_property(const char *key) const;
+
public:
static const char *ANDROID_EXEC_PATH;
@@ -93,6 +95,8 @@ public:
virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override;
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual MainLoop *get_main_loop() const override;
void main_loop_begin();
diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h
index 3b88f53b6a..00d91da771 100644
--- a/platform/ios/os_ios.h
+++ b/platform/ios/os_ios.h
@@ -100,6 +100,8 @@ public:
virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override;
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual String get_model_name() const override;
virtual Error shell_open(String p_uri) override;
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index b9d186f355..a674498620 100644
--- a/platform/ios/os_ios.mm
+++ b/platform/ios/os_ios.mm
@@ -240,6 +240,15 @@ String OS_IOS::get_name() const {
return "iOS";
}
+String OS_IOS::get_distribution_name() const {
+ return get_name();
+}
+
+String OS_IOS::get_version() const {
+ NSOperatingSystemVersion ver = [NSProcessInfo processInfo].operatingSystemVersion;
+ return vformat("%d.%d.%d", (int64_t)ver.majorVersion, (int64_t)ver.minorVersion, (int64_t)ver.patchVersion);
+}
+
String OS_IOS::get_model_name() const {
String model = ios->get_model();
if (model != "") {
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 0236e134fb..66dea6cf1b 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -397,7 +397,10 @@ void DisplayServerX11::mouse_set_mode(MouseMode p_mode) {
if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
//flush pending motion events
_flush_mouse_motion();
- WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
WindowData &window = windows[window_id];
if (XGrabPointer(
@@ -433,7 +436,11 @@ void DisplayServerX11::warp_mouse(const Point2i &p_position) {
if (mouse_mode == MOUSE_MODE_CAPTURED) {
last_mouse_pos = p_position;
} else {
- WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
+
XWarpPointer(x11_display, None, windows[window_id].x11_window,
0, 0, 0, 0, (int)p_position.x, (int)p_position.y);
}
@@ -3181,6 +3188,15 @@ void DisplayServerX11::_window_changed(XEvent *event) {
}
}
+DisplayServer::WindowID DisplayServerX11::_get_focused_window_or_popup() const {
+ const List<WindowID>::Element *E = popup_list.back();
+ if (E) {
+ return E->get();
+ }
+
+ return last_focused_window;
+}
+
void DisplayServerX11::_dispatch_input_events(const Ref<InputEvent> &p_event) {
static_cast<DisplayServerX11 *>(get_singleton())->_dispatch_input_event(p_event);
}
@@ -3936,7 +3952,11 @@ void DisplayServerX11::process_events() {
// The X11 API requires filtering one-by-one through the motion
// notify events, in order to figure out which event is the one
// generated by warping the mouse pointer.
- WindowID focused_window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID focused_window_id = _get_focused_window_or_popup();
+ if (!windows.has(focused_window_id)) {
+ focused_window_id = MAIN_WINDOW_ID;
+ }
+
while (true) {
if (mouse_mode == MOUSE_MODE_CAPTURED && event.xmotion.x == windows[focused_window_id].size.width / 2 && event.xmotion.y == windows[focused_window_id].size.height / 2) {
//this is likely the warp event since it was warped here
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index ea03b2328c..a5fa7613bc 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -284,6 +284,8 @@ class DisplayServerX11 : public DisplayServer {
Context context = CONTEXT_ENGINE;
+ WindowID _get_focused_window_or_popup() const;
+
void _send_window_event(const WindowData &wd, WindowEvent p_event);
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
void _dispatch_input_event(const Ref<InputEvent> &p_event);
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index f0d7b6ede5..f4e94f1a91 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -50,6 +50,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/utsname.h>
#include <unistd.h>
#ifdef FONTCONFIG_ENABLED
@@ -205,6 +206,42 @@ String OS_LinuxBSD::get_name() const {
#endif
}
+String OS_LinuxBSD::get_systemd_os_release_info_value(const String &key) const {
+ static String info;
+ if (info.is_empty()) {
+ Ref<FileAccess> f = FileAccess::open("/etc/os-release", FileAccess::READ);
+ if (f.is_valid()) {
+ while (!f->eof_reached()) {
+ const String line = f->get_line();
+ if (line.find(key) != -1) {
+ return line.split("=")[1].strip_edges();
+ }
+ }
+ }
+ }
+ return info;
+}
+
+String OS_LinuxBSD::get_distribution_name() const {
+ static String systemd_name = get_systemd_os_release_info_value("NAME"); // returns a value for systemd users, otherwise an empty string.
+ if (!systemd_name.is_empty()) {
+ return systemd_name;
+ }
+ struct utsname uts; // returns a decent value for BSD family.
+ uname(&uts);
+ return uts.sysname;
+}
+
+String OS_LinuxBSD::get_version() const {
+ static String systemd_version = get_systemd_os_release_info_value("VERSION"); // returns a value for systemd users, otherwise an empty string.
+ if (!systemd_version.is_empty()) {
+ return systemd_version;
+ }
+ struct utsname uts; // returns a decent value for BSD family.
+ uname(&uts);
+ return uts.version;
+}
+
Error OS_LinuxBSD::shell_open(String p_uri) {
Error ok;
int err_code;
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index d5b2321316..722d83ba19 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -67,6 +67,8 @@ class OS_LinuxBSD : public OS_Unix {
MainLoop *main_loop = nullptr;
+ String get_systemd_os_release_info_value(const String &key) const;
+
protected:
virtual void initialize() override;
virtual void finalize() override;
@@ -77,6 +79,8 @@ protected:
public:
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual MainLoop *get_main_loop() const override;
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index 769cba2de5..da377c9171 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -85,6 +85,8 @@ public:
Size2i max_size;
Size2i size;
+ NSRect last_frame_rect;
+
bool im_active = false;
Size2i im_position;
@@ -187,6 +189,8 @@ private:
Point2i _get_native_screen_position(int p_screen) const;
static void _displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info);
+ WindowID _get_focused_window_or_popup() const;
+
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
void _dispatch_input_event(const Ref<InputEvent> &p_event);
void _push_input(const Ref<InputEvent> &p_event);
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 91c6da5d13..05f89c70aa 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -317,6 +317,15 @@ void DisplayServerMacOS::_displays_arrangement_changed(CGDirectDisplayID display
}
}
+DisplayServer::WindowID DisplayServerMacOS::_get_focused_window_or_popup() const {
+ const List<WindowID>::Element *E = popup_list.back();
+ if (E) {
+ return E->get();
+ }
+
+ return last_focused_window;
+}
+
void DisplayServerMacOS::_dispatch_input_events(const Ref<InputEvent> &p_event) {
((DisplayServerMacOS *)(get_singleton()))->_dispatch_input_event(p_event);
}
@@ -1828,7 +1837,10 @@ void DisplayServerMacOS::mouse_set_mode(MouseMode p_mode) {
return;
}
- WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
WindowData &wd = windows[window_id];
if (p_mode == MOUSE_MODE_CAPTURED) {
// Apple Docs state that the display parameter is not used.
@@ -1943,7 +1955,10 @@ void DisplayServerMacOS::warp_mouse(const Point2i &p_position) {
_THREAD_SAFE_METHOD_
if (mouse_mode != MOUSE_MODE_CAPTURED) {
- WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
WindowData &wd = windows[window_id];
// Local point in window coords.
@@ -3537,7 +3552,7 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
[apple_menu addItem:[NSMenuItem separatorItem]];
- title = [NSString stringWithFormat:NSLocalizedString(@"\t\tQuit %@", nil), nsappname];
+ title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname];
[apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
// Add items to the menu bar.
diff --git a/platform/macos/godot_content_view.mm b/platform/macos/godot_content_view.mm
index f93ef48f6c..cb70a5db86 100644
--- a/platform/macos/godot_content_view.mm
+++ b/platform/macos/godot_content_view.mm
@@ -61,6 +61,24 @@
@implementation GodotContentView
- (void)setFrameSize:(NSSize)newSize {
+ DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
+ if (ds && ds->has_window(window_id)) {
+ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ NSRect frameRect = [wd.window_object frame];
+ bool left = (wd.last_frame_rect.origin.x != frameRect.origin.x);
+ bool top = (wd.last_frame_rect.origin.y == frameRect.origin.y);
+ if (left && top) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementBottomRight;
+ } else if (left && !top) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementTopRight;
+ } else if (!left && top) {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementBottomLeft;
+ } else {
+ self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
+ }
+ wd.last_frame_rect = frameRect;
+ }
+
[super setFrameSize:newSize];
[self.layer setNeedsDisplay]; // Force "drawRect" call.
}
diff --git a/platform/macos/godot_window_delegate.mm b/platform/macos/godot_window_delegate.mm
index 2d9329ab3c..e1034c9993 100644
--- a/platform/macos/godot_window_delegate.mm
+++ b/platform/macos/godot_window_delegate.mm
@@ -151,7 +151,9 @@
- (void)windowWillStartLiveResize:(NSNotification *)notification {
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
- if (ds) {
+ if (ds && ds->has_window(window_id)) {
+ DisplayServerMacOS::WindowData &wd = ds->get_window(window_id);
+ wd.last_frame_rect = [wd.window_object frame];
ds->set_is_resizing(true);
}
}
diff --git a/platform/macos/os_macos.h b/platform/macos/os_macos.h
index 61db99689c..46e7c17ebe 100644
--- a/platform/macos/os_macos.h
+++ b/platform/macos/os_macos.h
@@ -75,6 +75,8 @@ public:
virtual List<String> get_cmdline_platform_args() const override;
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override;
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index c250a9d71a..ae8534f6ab 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -134,6 +134,15 @@ String OS_MacOS::get_name() const {
return "macOS";
}
+String OS_MacOS::get_distribution_name() const {
+ return get_name();
+}
+
+String OS_MacOS::get_version() const {
+ NSOperatingSystemVersion ver = [NSProcessInfo processInfo].operatingSystemVersion;
+ return vformat("%d.%d.%d", (int64_t)ver.majorVersion, (int64_t)ver.minorVersion, (int64_t)ver.patchVersion);
+}
+
void OS_MacOS::alert(const String &p_alert, const String &p_title) {
NSAlert *window = [[NSAlert alloc] init];
NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()];
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 791328964b..8050d299f0 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -444,6 +444,16 @@ String OS_UWP::get_name() const {
return "UWP";
}
+String OS_UWP::get_distribution_name() const {
+ return get_name();
+}
+
+String OS_UWP::get_version() const {
+ winrt::hstring df_version = VersionInfo().DeviceFamilyVersion();
+ static String version = String(winrt::to_string(df_version).c_str());
+ return version;
+}
+
OS::DateTime OS_UWP::get_datetime(bool p_utc) const {
SYSTEMTIME systemtime;
if (p_utc) {
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index 7d4224cf74..0c1c4a793a 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -183,6 +183,8 @@ public:
virtual MainLoop *get_main_loop() const;
virtual String get_name() const;
+ virtual String get_distribution_name() const;
+ virtual String get_version() const;
virtual DateTime get_datetime(bool p_utc) const;
virtual TimeZoneInfo get_time_zone_info() const;
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index a14170525d..4553f31480 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -104,7 +104,10 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
if (windows.has(MAIN_WINDOW_ID) && (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN)) {
// Mouse is grabbed (captured or confined).
- WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
+ WindowID window_id = _get_focused_window_or_popup();
+ if (!windows.has(window_id)) {
+ window_id = MAIN_WINDOW_ID;
+ }
WindowData &wd = windows[window_id];
@@ -119,11 +122,15 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
ClientToScreen(wd.hWnd, &pos);
SetCursorPos(pos.x, pos.y);
SetCapture(wd.hWnd);
+
+ _register_raw_input_devices(window_id);
}
} else {
// Mouse is free to move around (not captured or confined).
ReleaseCapture();
ClipCursor(nullptr);
+
+ _register_raw_input_devices(INVALID_WINDOW_ID);
}
if (p_mode == MOUSE_MODE_HIDDEN || p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED_HIDDEN) {
@@ -139,6 +146,37 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
}
}
+DisplayServer::WindowID DisplayServerWindows::_get_focused_window_or_popup() const {
+ const List<WindowID>::Element *E = popup_list.back();
+ if (E) {
+ return E->get();
+ }
+
+ return last_focused_window;
+}
+
+void DisplayServerWindows::_register_raw_input_devices(WindowID p_target_window) {
+ use_raw_input = true;
+
+ RAWINPUTDEVICE rid[1] = {};
+ rid[0].usUsagePage = 0x01;
+ rid[0].usUsage = 0x02;
+ rid[0].dwFlags = 0;
+
+ if (p_target_window != INVALID_WINDOW_ID && windows.has(p_target_window)) {
+ // Follow the defined window
+ rid[0].hwndTarget = windows[p_target_window].hWnd;
+ } else {
+ // Follow the keyboard focus
+ rid[0].hwndTarget = 0;
+ }
+
+ if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == FALSE) {
+ // Registration failed.
+ use_raw_input = false;
+ }
+}
+
bool DisplayServerWindows::tts_is_speaking() const {
ERR_FAIL_COND_V(!tts, false);
return tts->is_speaking();
@@ -194,7 +232,9 @@ DisplayServer::MouseMode DisplayServerWindows::mouse_get_mode() const {
void DisplayServerWindows::warp_mouse(const Point2i &p_position) {
_THREAD_SAFE_METHOD_
- if (!windows.has(last_focused_window)) {
+ WindowID window_id = _get_focused_window_or_popup();
+
+ if (!windows.has(window_id)) {
return; // No focused window?
}
@@ -205,7 +245,7 @@ void DisplayServerWindows::warp_mouse(const Point2i &p_position) {
POINT p;
p.x = p_position.x;
p.y = p_position.y;
- ClientToScreen(windows[last_focused_window].hWnd, &p);
+ ClientToScreen(windows[window_id].hWnd, &p);
SetCursorPos(p.x, p.y);
}
@@ -1496,7 +1536,7 @@ void DisplayServerWindows::cursor_set_shape(CursorShape p_shape) {
IDC_HELP
};
- if (cursors[p_shape] != nullptr) {
+ if (cursors_cache.has(p_shape)) {
SetCursor(cursors[p_shape]);
} else {
SetCursor(LoadCursor(hInstance, win_cursors[p_shape]));
@@ -1509,55 +1549,6 @@ DisplayServer::CursorShape DisplayServerWindows::cursor_get_shape() const {
return cursor_shape;
}
-void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap) {
- // Get the system display DC.
- HDC hDC = GetDC(nullptr);
-
- // Create helper DC.
- HDC hMainDC = CreateCompatibleDC(hDC);
- HDC hAndMaskDC = CreateCompatibleDC(hDC);
- HDC hXorMaskDC = CreateCompatibleDC(hDC);
-
- // Get the dimensions of the source bitmap.
- BITMAP bm;
- GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
-
- // Create the mask bitmaps.
- hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // Color.
- hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // Color.
-
- // Release the system display DC.
- ReleaseDC(nullptr, hDC);
-
- // Select the bitmaps to helper DC.
- HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap);
- HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap);
- HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap);
-
- // Assign the monochrome AND mask bitmap pixels so that the pixels of the source bitmap
- // with 'clrTransparent' will be white pixels of the monochrome bitmap.
- SetBkColor(hMainDC, clrTransparent);
- BitBlt(hAndMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCCOPY);
-
- // Assign the color XOR mask bitmap pixels so that the pixels of the source bitmap
- // with 'clrTransparent' will be black and rest the pixels same as corresponding
- // pixels of the source bitmap.
- SetBkColor(hXorMaskDC, RGB(0, 0, 0));
- SetTextColor(hXorMaskDC, RGB(255, 255, 255));
- BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hAndMaskDC, 0, 0, SRCCOPY);
- BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCAND);
-
- // Deselect bitmaps from the helper DC.
- SelectObject(hMainDC, hOldMainBitmap);
- SelectObject(hAndMaskDC, hOldAndMaskBitmap);
- SelectObject(hXorMaskDC, hOldXorMaskBitmap);
-
- // Delete the helper DC.
- DeleteDC(hXorMaskDC);
- DeleteDC(hAndMaskDC);
- DeleteDC(hMainDC);
-}
-
void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
_THREAD_SAFE_METHOD_
@@ -1610,8 +1601,26 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
UINT image_size = texture_size.width * texture_size.height;
// Create the BITMAP with alpha channel.
- COLORREF *buffer = (COLORREF *)memalloc(sizeof(COLORREF) * image_size);
-
+ COLORREF *buffer = nullptr;
+
+ BITMAPV5HEADER bi;
+ ZeroMemory(&bi, sizeof(bi));
+ bi.bV5Size = sizeof(bi);
+ bi.bV5Width = texture_size.width;
+ bi.bV5Height = -texture_size.height;
+ bi.bV5Planes = 1;
+ bi.bV5BitCount = 32;
+ bi.bV5Compression = BI_BITFIELDS;
+ bi.bV5RedMask = 0x00ff0000;
+ bi.bV5GreenMask = 0x0000ff00;
+ bi.bV5BlueMask = 0x000000ff;
+ bi.bV5AlphaMask = 0xff000000;
+
+ HDC dc = GetDC(nullptr);
+ HBITMAP bitmap = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO *>(&bi), DIB_RGB_COLORS, reinterpret_cast<void **>(&buffer), nullptr, 0);
+ HBITMAP mask = CreateBitmap(texture_size.width, texture_size.height, 1, 1, nullptr);
+
+ bool fully_transparent = true;
for (UINT index = 0; index < image_size; index++) {
int row_index = floor(index / texture_size.width) + atlas_rect.position.y;
int column_index = (index % int(texture_size.width)) + atlas_rect.position.x;
@@ -1620,39 +1629,28 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
column_index = MIN(column_index, atlas_rect.size.width - 1);
row_index = MIN(row_index, atlas_rect.size.height - 1);
}
+ const Color &c = image->get_pixel(column_index, row_index);
+ fully_transparent = fully_transparent && (c.a == 0.f);
- *(buffer + index) = image->get_pixel(column_index, row_index).to_argb32();
- }
-
- // Using 4 channels, so 4 * 8 bits.
- HBITMAP bitmap = CreateBitmap(texture_size.width, texture_size.height, 1, 4 * 8, buffer);
- COLORREF clrTransparent = -1;
-
- // Create the AND and XOR masks for the bitmap.
- HBITMAP hAndMask = nullptr;
- HBITMAP hXorMask = nullptr;
-
- GetMaskBitmaps(bitmap, clrTransparent, hAndMask, hXorMask);
-
- if (nullptr == hAndMask || nullptr == hXorMask) {
- memfree(buffer);
- DeleteObject(bitmap);
- return;
+ *(buffer + index) = c.to_argb32();
}
// Finally, create the icon.
- ICONINFO iconinfo;
- iconinfo.fIcon = FALSE;
- iconinfo.xHotspot = p_hotspot.x;
- iconinfo.yHotspot = p_hotspot.y;
- iconinfo.hbmMask = hAndMask;
- iconinfo.hbmColor = hXorMask;
-
if (cursors[p_shape]) {
DestroyIcon(cursors[p_shape]);
}
- cursors[p_shape] = CreateIconIndirect(&iconinfo);
+ if (fully_transparent) {
+ cursors[p_shape] = nullptr;
+ } else {
+ ICONINFO iconinfo;
+ iconinfo.fIcon = FALSE;
+ iconinfo.xHotspot = p_hotspot.x;
+ iconinfo.yHotspot = p_hotspot.y;
+ iconinfo.hbmMask = mask;
+ iconinfo.hbmColor = bitmap;
+ cursors[p_shape] = CreateIconIndirect(&iconinfo);
+ }
Vector<Variant> params;
params.push_back(p_cursor);
@@ -1665,17 +1663,15 @@ void DisplayServerWindows::cursor_set_custom_image(const Ref<Resource> &p_cursor
}
}
- DeleteObject(hAndMask);
- DeleteObject(hXorMask);
-
- memfree(buffer);
+ DeleteObject(mask);
DeleteObject(bitmap);
+ ReleaseDC(nullptr, dc);
} else {
// Reset to default system cursor.
if (cursors[p_shape]) {
DestroyIcon(cursors[p_shape]);
- cursors[p_shape] = nullptr;
}
+ cursors[p_shape] = nullptr;
CursorShape c = cursor_shape;
cursor_shape = CURSOR_MAX;
@@ -2527,7 +2523,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
old_y = coords.y;
}
- if (windows[window_id].window_has_focus && mm->get_relative() != Vector2()) {
+ if ((windows[window_id].window_has_focus || windows[window_id].is_popup) && mm->get_relative() != Vector2()) {
Input::get_singleton()->parse_input_event(mm);
}
}
@@ -3817,19 +3813,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
return;
}
- use_raw_input = true;
-
- RAWINPUTDEVICE Rid[1];
-
- Rid[0].usUsagePage = 0x01;
- Rid[0].usUsage = 0x02;
- Rid[0].dwFlags = 0;
- Rid[0].hwndTarget = 0;
-
- if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
- // Registration failed.
- use_raw_input = false;
- }
+ _register_raw_input_devices(INVALID_WINDOW_ID);
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index b0ad7e36c0..d85d6364bd 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -311,8 +311,6 @@ class DisplayServerWindows : public DisplayServer {
String tablet_driver;
Vector<String> tablet_drivers;
- void GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap);
-
enum {
KEY_EVENT_BUFFER_SIZE = 512
};
@@ -468,6 +466,8 @@ class DisplayServerWindows : public DisplayServer {
void _update_real_mouse_position(WindowID p_window);
void _set_mouse_mode_impl(MouseMode p_mode);
+ WindowID _get_focused_window_or_popup() const;
+ void _register_raw_input_devices(WindowID p_target_window);
void _process_activate_event(WindowID p_window_id, WPARAM wParam, LPARAM lParam);
void _process_key_events();
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 2c268ff3d5..1978ec5ab6 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -290,6 +290,24 @@ String OS_Windows::get_name() const {
return "Windows";
}
+String OS_Windows::get_distribution_name() const {
+ return get_name();
+}
+
+String OS_Windows::get_version() const {
+ typedef LONG NTSTATUS, *PNTSTATUS;
+ typedef NTSTATUS(WINAPI * RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
+ RtlGetVersionPtr version_ptr = (RtlGetVersionPtr)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion");
+ if (version_ptr != nullptr) {
+ RTL_OSVERSIONINFOW fow = { 0 };
+ fow.dwOSVersionInfoSize = sizeof(fow);
+ if (version_ptr(&fow) == 0x00000000) {
+ return vformat("%d.%d.%d", (int64_t)fow.dwMajorVersion, (int64_t)fow.dwMinorVersion, (int64_t)fow.dwBuildNumber);
+ }
+ }
+ return "";
+}
+
OS::DateTime OS_Windows::get_datetime(bool p_utc) const {
SYSTEMTIME systemtime;
if (p_utc) {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 53451b780e..491de2266f 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -143,6 +143,8 @@ public:
virtual MainLoop *get_main_loop() const override;
virtual String get_name() const override;
+ virtual String get_distribution_name() const override;
+ virtual String get_version() const override;
virtual void initialize_joypads() override {}
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index 7fe464d2f4..afa4633848 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -63,9 +63,13 @@ Rect2 AnimatedSprite2D::_edit_get_rect() const {
}
bool AnimatedSprite2D::_edit_use_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return false;
}
+ if (frame < 0 || frame >= frames->get_frame_count(animation)) {
+ return false;
+ }
+
Ref<Texture2D> t;
if (animation) {
t = frames->get_frame(animation, frame);
@@ -79,7 +83,10 @@ Rect2 AnimatedSprite2D::get_anchorable_rect() const {
}
Rect2 AnimatedSprite2D::_get_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
+ return Rect2();
+ }
+ if (frame < 0 || frame >= frames->get_frame_count(animation)) {
return Rect2();
}
@@ -161,29 +168,22 @@ void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const {
void AnimatedSprite2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
- if (frames.is_null()) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
- if (!frames->has_animation(animation)) {
- return;
- }
- if (frame < 0) {
- return;
+
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
+ if (speed == 0) {
+ return; // Do nothing.
}
+ int last_frame = frames->get_frame_count(animation) - 1;
double remaining = get_process_delta_time();
-
while (remaining) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
- if (speed == 0) {
- return; // Do nothing.
- }
-
if (timeout <= 0) {
timeout = _get_frame_duration();
- int last_frame = frames->get_frame_count(animation) - 1;
- if (!backwards) {
+ if (!playing_backwards) {
// Forward.
if (frame >= last_frame) {
if (frames->get_animation_loop(animation)) {
@@ -229,13 +229,7 @@ void AnimatedSprite2D::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
- if (frames.is_null()) {
- return;
- }
- if (frame < 0) {
- return;
- }
- if (!frames->has_animation(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
@@ -327,9 +321,14 @@ int AnimatedSprite2D::get_frame() const {
}
void AnimatedSprite2D::set_speed_scale(double p_speed_scale) {
+ if (speed_scale == p_speed_scale) {
+ return;
+ }
+
double elapsed = _get_frame_duration() - timeout;
- speed_scale = MAX(p_speed_scale, 0.0f);
+ speed_scale = p_speed_scale;
+ playing_backwards = signbit(speed_scale) != backwards;
// We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed.
_reset_timeout();
@@ -398,12 +397,13 @@ bool AnimatedSprite2D::is_playing() const {
return playing;
}
-void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backwards) {
+void AnimatedSprite2D::play(const StringName &p_animation, bool p_backwards) {
backwards = p_backwards;
+ playing_backwards = signbit(speed_scale) != backwards;
if (p_animation) {
set_animation(p_animation);
- if (frames.is_valid() && backwards && get_frame() == 0) {
+ if (frames.is_valid() && playing_backwards && get_frame() == 0) {
set_frame(frames->get_frame_count(p_animation) - 1);
}
}
@@ -418,7 +418,7 @@ void AnimatedSprite2D::stop() {
double AnimatedSprite2D::_get_frame_duration() {
if (frames.is_valid() && frames->has_animation(animation)) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
if (speed > 0) {
return 1.0 / speed;
}
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
index 0a19e250d8..be1cc5353e 100644
--- a/scene/2d/animated_sprite_2d.h
+++ b/scene/2d/animated_sprite_2d.h
@@ -39,6 +39,7 @@ class AnimatedSprite2D : public Node2D {
Ref<SpriteFrames> frames;
bool playing = false;
+ bool playing_backwards = false;
bool backwards = false;
StringName animation = "default";
int frame = 0;
@@ -81,7 +82,7 @@ public:
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
Ref<SpriteFrames> get_sprite_frames() const;
- void play(const StringName &p_animation = StringName(), const bool p_backwards = false);
+ void play(const StringName &p_animation = StringName(), bool p_backwards = false);
void stop();
void set_playing(bool p_playing);
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index b0bccc4571..555884f445 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -1418,7 +1418,8 @@ float LightmapGI::get_bias() const {
}
void LightmapGI::set_max_texture_size(int p_size) {
- ERR_FAIL_COND(p_size < 2048);
+ ERR_FAIL_COND_MSG(p_size < 2048, vformat("The LightmapGI maximum texture size supplied (%d) is too small. The minimum allowed value is 2048.", p_size));
+ ERR_FAIL_COND_MSG(p_size > 16384, vformat("The LightmapGI maximum texture size supplied (%d) is too large. The maximum allowed value is 16384.", p_size));
max_texture_size = p_size;
}
@@ -1506,7 +1507,7 @@ void LightmapGI::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_denoiser"), "set_use_denoiser", "is_using_denoiser");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0.00001,0.1,0.00001,or_greater"), "set_bias", "get_bias");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "max_texture_size"), "set_max_texture_size", "get_max_texture_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "max_texture_size", PROPERTY_HINT_RANGE, "2048,16384,1"), "set_max_texture_size", "get_max_texture_size");
ADD_GROUP("Environment", "environment_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "environment_mode", PROPERTY_HINT_ENUM, "Disabled,Scene,Custom Sky,Custom Color"), "set_environment_mode", "get_environment_mode");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment_custom_sky", PROPERTY_HINT_RESOURCE_TYPE, "Sky"), "set_environment_custom_sky", "get_environment_custom_sky");
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index 0062a4a093..1d282e92c8 100644
--- a/scene/3d/lightmap_gi.h
+++ b/scene/3d/lightmap_gi.h
@@ -142,16 +142,16 @@ public:
private:
BakeQuality bake_quality = BAKE_QUALITY_MEDIUM;
bool use_denoiser = true;
- int bounces = 1;
+ int bounces = 3;
float bias = 0.0005;
int max_texture_size = 16384;
bool interior = false;
- EnvironmentMode environment_mode = ENVIRONMENT_MODE_DISABLED;
+ EnvironmentMode environment_mode = ENVIRONMENT_MODE_SCENE;
Ref<Sky> environment_custom_sky;
- Color environment_custom_color = Color(0.2, 0.7, 1.0);
+ Color environment_custom_color = Color(1, 1, 1);
float environment_custom_energy = 1.0;
bool directional = false;
- GenerateProbes gen_probes = GENERATE_PROBES_DISABLED;
+ GenerateProbes gen_probes = GENERATE_PROBES_SUBDIV_8;
Ref<CameraAttributes> camera_attributes;
Ref<LightmapGIData> light_data;
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 7a89bf81bb..380172f396 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -447,7 +447,7 @@ void Sprite3D::_draw() {
if (get_base() != get_mesh()) {
set_base(get_mesh());
}
- if (!texture.is_valid()) {
+ if (texture.is_null()) {
set_base(RID());
return;
}
@@ -807,15 +807,7 @@ void AnimatedSprite3D::_draw() {
set_base(get_mesh());
}
- if (frames.is_null()) {
- return;
- }
-
- if (frame < 0) {
- return;
- }
-
- if (!frames->has_animation(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
@@ -1050,29 +1042,22 @@ void AnimatedSprite3D::_validate_property(PropertyInfo &p_property) const {
void AnimatedSprite3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
- if (frames.is_null()) {
- return;
- }
- if (!frames->has_animation(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
- if (frame < 0) {
- return;
+
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
+ if (speed == 0) {
+ return; // Do nothing.
}
+ int last_frame = frames->get_frame_count(animation) - 1;
double remaining = get_process_delta_time();
-
while (remaining) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
- if (speed == 0) {
- return; // Do nothing.
- }
-
if (timeout <= 0) {
timeout = _get_frame_duration();
- int last_frame = frames->get_frame_count(animation) - 1;
- if (!backwards) {
+ if (!playing_backwards) {
// Forward.
if (frame >= last_frame) {
if (frames->get_animation_loop(animation)) {
@@ -1177,9 +1162,14 @@ int AnimatedSprite3D::get_frame() const {
}
void AnimatedSprite3D::set_speed_scale(double p_speed_scale) {
+ if (speed_scale == p_speed_scale) {
+ return;
+ }
+
double elapsed = _get_frame_duration() - timeout;
- speed_scale = MAX(p_speed_scale, 0.0f);
+ speed_scale = p_speed_scale;
+ playing_backwards = signbit(speed_scale) != backwards;
// We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed.
_reset_timeout();
@@ -1191,7 +1181,10 @@ double AnimatedSprite3D::get_speed_scale() const {
}
Rect2 AnimatedSprite3D::get_item_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
+ return Rect2(0, 0, 1, 1);
+ }
+ if (frame < 0 || frame >= frames->get_frame_count(animation)) {
return Rect2(0, 0, 1, 1);
}
@@ -1236,12 +1229,13 @@ bool AnimatedSprite3D::is_playing() const {
return playing;
}
-void AnimatedSprite3D::play(const StringName &p_animation, const bool p_backwards) {
+void AnimatedSprite3D::play(const StringName &p_animation, bool p_backwards) {
backwards = p_backwards;
+ playing_backwards = signbit(speed_scale) != backwards;
if (p_animation) {
set_animation(p_animation);
- if (frames.is_valid() && backwards && get_frame() == 0) {
+ if (frames.is_valid() && playing_backwards && get_frame() == 0) {
set_frame(frames->get_frame_count(p_animation) - 1);
}
}
@@ -1256,7 +1250,7 @@ void AnimatedSprite3D::stop() {
double AnimatedSprite3D::_get_frame_duration() {
if (frames.is_valid() && frames->has_animation(animation)) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
if (speed > 0) {
return 1.0 / speed;
}
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index e6a546a76d..f6ad1bbdb8 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -209,6 +209,7 @@ class AnimatedSprite3D : public SpriteBase3D {
Ref<SpriteFrames> frames;
bool playing = false;
+ bool playing_backwards = false;
bool backwards = false;
StringName animation = "default";
int frame = 0;
@@ -237,7 +238,7 @@ public:
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
Ref<SpriteFrames> get_sprite_frames() const;
- void play(const StringName &p_animation = StringName(), const bool p_backwards = false);
+ void play(const StringName &p_animation = StringName(), bool p_backwards = false);
void stop();
void set_playing(bool p_playing);
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 99f17a1eef..1efbaacb3b 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -1175,6 +1175,7 @@ void AnimationNodeBlendTree::_tree_changed() {
void AnimationNodeBlendTree::_node_changed(const StringName &p_node) {
ERR_FAIL_COND(!nodes.has(p_node));
nodes[p_node].connections.resize(nodes[p_node].node->get_input_count());
+ emit_signal(SNAME("node_changed"), p_node);
}
void AnimationNodeBlendTree::_bind_methods() {
@@ -1200,6 +1201,8 @@ void AnimationNodeBlendTree::_bind_methods() {
BIND_CONSTANT(CONNECTION_ERROR_NO_OUTPUT);
BIND_CONSTANT(CONNECTION_ERROR_SAME_NODE);
BIND_CONSTANT(CONNECTION_ERROR_CONNECTION_EXISTS);
+
+ ADD_SIGNAL(MethodInfo("node_changed", PropertyInfo(Variant::STRING_NAME, "node_name")));
}
void AnimationNodeBlendTree::_initialize_node_tree() {
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 096f4edee2..ce9406883d 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -650,15 +650,14 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
double c = Math::ease(p_time / first_key_time, transition);
Variant first_value = a->track_get_key_value(i, first_key);
first_value = _post_process_key_value(a, i, first_value, nc->node);
- Variant interp_value;
- Variant::interpolate(pa->capture, first_value, c, interp_value);
+ Variant interp_value = Animation::interpolate_variant(pa->capture, first_value, c);
if (pa->accum_pass != accum_pass) {
ERR_CONTINUE(cache_update_prop_size >= NODE_CACHE_UPDATE_MAX);
cache_update_prop[cache_update_prop_size++] = pa;
pa->value_accum = interp_value;
pa->accum_pass = accum_pass;
} else {
- Variant::interpolate(pa->value_accum, interp_value, p_interp, pa->value_accum);
+ pa->value_accum = Animation::interpolate_variant(pa->value_accum, interp_value, p_interp);
}
continue; //handled
@@ -679,7 +678,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
pa->value_accum = value;
pa->accum_pass = accum_pass;
} else {
- Variant::interpolate(pa->value_accum, value, p_interp, pa->value_accum);
+ pa->value_accum = Animation::interpolate_variant(pa->value_accum, value, p_interp);
}
} else if (p_is_current && p_delta != 0) {
@@ -1270,6 +1269,8 @@ void AnimationPlayer::_animation_set_cache_update() {
// If something was modified or removed, caches need to be cleared
clear_caches();
}
+
+ emit_signal(SNAME("animation_list_changed"));
}
void AnimationPlayer::_animation_added(const StringName &p_name, const StringName &p_library) {
@@ -2150,6 +2151,7 @@ void AnimationPlayer::_bind_methods() {
ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING_NAME, "anim_name")));
ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING_NAME, "old_name"), PropertyInfo(Variant::STRING_NAME, "new_name")));
ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING_NAME, "anim_name")));
+ ADD_SIGNAL(MethodInfo("animation_list_changed"));
ADD_SIGNAL(MethodInfo("caches_cleared"));
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index d06324f0aa..776706d7f3 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -847,6 +847,11 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) {
return true;
}
+void AnimationTree::_animation_player_changed() {
+ emit_signal(SNAME("animation_player_changed"));
+ _clear_caches();
+}
+
void AnimationTree::_clear_caches() {
for (KeyValue<NodePath, TrackCache *> &K : track_cache) {
memdelete(K.value);
@@ -1378,8 +1383,13 @@ void AnimationTree::_process_graph(double p_delta) {
}
t->value = Math::fposmod(rot_a + (rot_b - rot_init) * (float)blend, (float)Math_TAU);
} else {
- Variant::sub(value, t->init_value, value);
- Variant::blend(t->value, value, blend, t->value);
+ if (t->init_value.get_type() == Variant::BOOL) {
+ value = Animation::subtract_variant(value.operator real_t(), t->init_value.operator real_t());
+ t->value = Animation::blend_variant(t->value.operator real_t(), value.operator real_t(), blend);
+ } else {
+ value = Animation::subtract_variant(value, t->init_value);
+ t->value = Animation::blend_variant(t->value, value, blend);
+ }
}
} else {
if (blend < CMP_EPSILON) {
@@ -1698,7 +1708,11 @@ void AnimationTree::_process_graph(double p_delta) {
case Animation::TYPE_VALUE: {
TrackCacheValue *t = static_cast<TrackCacheValue *>(track);
- t->object->set_indexed(t->subpath, t->value);
+ if (t->init_value.get_type() == Variant::BOOL) {
+ t->object->set_indexed(t->subpath, t->value.operator real_t() >= 0.5);
+ } else {
+ t->object->set_indexed(t->subpath, t->value);
+ }
} break;
case Animation::TYPE_BEZIER: {
@@ -1738,6 +1752,7 @@ void AnimationTree::advance(real_t p_time) {
void AnimationTree::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
+ _setup_animation_player();
if (last_animation_player.is_valid()) {
Object *player = ObjectDB::get_instance(last_animation_player);
if (player) {
@@ -1770,8 +1785,43 @@ void AnimationTree::_notification(int p_what) {
}
}
+void AnimationTree::_setup_animation_player() {
+ if (!is_inside_tree()) {
+ return;
+ }
+
+ AnimationPlayer *new_player = nullptr;
+ if (!animation_player.is_empty()) {
+ new_player = Object::cast_to<AnimationPlayer>(get_node(animation_player));
+ if (new_player && !new_player->is_connected("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed))) {
+ new_player->connect("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed));
+ }
+ }
+
+ if (new_player) {
+ if (!last_animation_player.is_valid()) {
+ // Animation player set newly.
+ emit_signal(SNAME("animation_player_changed"));
+ return;
+ } else if (last_animation_player == new_player->get_instance_id()) {
+ // Animation player isn't changed.
+ return;
+ }
+ } else if (!last_animation_player.is_valid()) {
+ // Animation player is being empty.
+ return;
+ }
+
+ AnimationPlayer *old_player = Object::cast_to<AnimationPlayer>(ObjectDB::get_instance(last_animation_player));
+ if (old_player && old_player->is_connected("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed))) {
+ old_player->disconnect("animation_list_changed", callable_mp(this, &AnimationTree::_animation_player_changed));
+ }
+ emit_signal(SNAME("animation_player_changed"));
+}
+
void AnimationTree::set_animation_player(const NodePath &p_player) {
animation_player = p_player;
+ _setup_animation_player();
update_configuration_warnings();
}
@@ -2008,6 +2058,8 @@ void AnimationTree::_bind_methods() {
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS);
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE);
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_MANUAL);
+
+ ADD_SIGNAL(MethodInfo("animation_player_changed"));
}
AnimationTree::AnimationTree() {
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index ee0c0303dc..573448be93 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -282,6 +282,8 @@ private:
bool cache_valid = false;
void _node_removed(Node *p_node);
+ void _setup_animation_player();
+ void _animation_player_changed();
void _clear_caches();
bool _update_caches(AnimationPlayer *player);
void _process_graph(double p_delta);
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 5b18d4e457..b02f1959b7 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -32,6 +32,7 @@
#include "scene/animation/easing_equations.h"
#include "scene/main/node.h"
+#include "scene/resources/animation.h"
Tween::interpolater Tween::interpolaters[Tween::TRANS_MAX][Tween::EASE_MAX] = {
{ &linear::in, &linear::in, &linear::in, &linear::in }, // Linear is the same for each easing.
@@ -314,6 +315,7 @@ bool Tween::step(float p_delta) {
running = false;
dead = true;
emit_signal(SNAME("finished"));
+ break;
} else {
emit_signal(SNAME("loop_finished"), loops_done);
current_step = 0;
@@ -375,264 +377,14 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, f
ERR_FAIL_INDEX_V(p_trans, TransitionType::TRANS_MAX, Variant());
ERR_FAIL_INDEX_V(p_ease, EaseType::EASE_MAX, Variant());
-// Helper macro to run equation on sub-elements of the value (e.g. x and y of Vector2).
-#define APPLY_EQUATION(element) \
- r.element = run_equation(p_trans, p_ease, p_time, i.element, d.element, p_duration);
-
- switch (p_initial_val.get_type()) {
- case Variant::BOOL: {
- return (run_equation(p_trans, p_ease, p_time, p_initial_val, p_delta_val, p_duration)) >= 0.5;
- }
-
- case Variant::INT: {
- return (int)run_equation(p_trans, p_ease, p_time, (int)p_initial_val, (int)p_delta_val, p_duration);
- }
-
- case Variant::FLOAT: {
- return run_equation(p_trans, p_ease, p_time, (real_t)p_initial_val, (real_t)p_delta_val, p_duration);
- }
-
- case Variant::VECTOR2: {
- Vector2 i = p_initial_val;
- Vector2 d = p_delta_val;
- Vector2 r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- return r;
- }
-
- case Variant::VECTOR2I: {
- Vector2i i = p_initial_val;
- Vector2i d = p_delta_val;
- Vector2i r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- return r;
- }
-
- case Variant::RECT2: {
- Rect2 i = p_initial_val;
- Rect2 d = p_delta_val;
- Rect2 r;
-
- APPLY_EQUATION(position.x);
- APPLY_EQUATION(position.y);
- APPLY_EQUATION(size.x);
- APPLY_EQUATION(size.y);
- return r;
- }
-
- case Variant::RECT2I: {
- Rect2i i = p_initial_val;
- Rect2i d = p_delta_val;
- Rect2i r;
-
- APPLY_EQUATION(position.x);
- APPLY_EQUATION(position.y);
- APPLY_EQUATION(size.x);
- APPLY_EQUATION(size.y);
- return r;
- }
-
- case Variant::VECTOR3: {
- Vector3 i = p_initial_val;
- Vector3 d = p_delta_val;
- Vector3 r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- APPLY_EQUATION(z);
- return r;
- }
-
- case Variant::VECTOR3I: {
- Vector3i i = p_initial_val;
- Vector3i d = p_delta_val;
- Vector3i r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- APPLY_EQUATION(z);
- return r;
- }
-
- case Variant::TRANSFORM2D: {
- Transform2D i = p_initial_val;
- Transform2D d = p_delta_val;
- Transform2D r;
-
- APPLY_EQUATION(columns[0][0]);
- APPLY_EQUATION(columns[0][1]);
- APPLY_EQUATION(columns[1][0]);
- APPLY_EQUATION(columns[1][1]);
- APPLY_EQUATION(columns[2][0]);
- APPLY_EQUATION(columns[2][1]);
- return r;
- }
- case Variant::VECTOR4: {
- Vector4 i = p_initial_val;
- Vector4 d = p_delta_val;
- Vector4 r;
-
- APPLY_EQUATION(x);
- APPLY_EQUATION(y);
- APPLY_EQUATION(z);
- APPLY_EQUATION(w);
- return r;
- }
-
- case Variant::QUATERNION: {
- Quaternion i = p_initial_val;
- Quaternion d = p_delta_val;
- Quaternion r = i * d;
- r = i.slerp(r, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration));
- return r;
- }
-
- case Variant::AABB: {
- AABB i = p_initial_val;
- AABB d = p_delta_val;
- AABB r;
-
- APPLY_EQUATION(position.x);
- APPLY_EQUATION(position.y);
- APPLY_EQUATION(position.z);
- APPLY_EQUATION(size.x);
- APPLY_EQUATION(size.y);
- APPLY_EQUATION(size.z);
- return r;
- }
-
- case Variant::BASIS: {
- Basis i = p_initial_val;
- Basis d = p_delta_val;
- Basis r;
-
- APPLY_EQUATION(rows[0][0]);
- APPLY_EQUATION(rows[0][1]);
- APPLY_EQUATION(rows[0][2]);
- APPLY_EQUATION(rows[1][0]);
- APPLY_EQUATION(rows[1][1]);
- APPLY_EQUATION(rows[1][2]);
- APPLY_EQUATION(rows[2][0]);
- APPLY_EQUATION(rows[2][1]);
- APPLY_EQUATION(rows[2][2]);
- return r;
- }
-
- case Variant::TRANSFORM3D: {
- Transform3D i = p_initial_val;
- Transform3D d = p_delta_val;
- Transform3D r;
-
- APPLY_EQUATION(basis.rows[0][0]);
- APPLY_EQUATION(basis.rows[0][1]);
- APPLY_EQUATION(basis.rows[0][2]);
- APPLY_EQUATION(basis.rows[1][0]);
- APPLY_EQUATION(basis.rows[1][1]);
- APPLY_EQUATION(basis.rows[1][2]);
- APPLY_EQUATION(basis.rows[2][0]);
- APPLY_EQUATION(basis.rows[2][1]);
- APPLY_EQUATION(basis.rows[2][2]);
- APPLY_EQUATION(origin.x);
- APPLY_EQUATION(origin.y);
- APPLY_EQUATION(origin.z);
- return r;
- }
-
- case Variant::COLOR: {
- Color i = p_initial_val;
- Color d = p_delta_val;
- Color r;
-
- APPLY_EQUATION(r);
- APPLY_EQUATION(g);
- APPLY_EQUATION(b);
- APPLY_EQUATION(a);
- return r;
- }
-
- default: {
- return p_initial_val;
- }
- };
-#undef APPLY_EQUATION
-}
-
-Variant Tween::calculate_delta_value(Variant p_intial_val, Variant p_final_val) {
- ERR_FAIL_COND_V_MSG(p_intial_val.get_type() != p_final_val.get_type(), p_intial_val, "Type mismatch between initial and final value: " + Variant::get_type_name(p_intial_val.get_type()) + " and " + Variant::get_type_name(p_final_val.get_type()));
-
- switch (p_intial_val.get_type()) {
- case Variant::BOOL: {
- return (int)p_final_val - (int)p_intial_val;
- }
-
- case Variant::RECT2: {
- Rect2 i = p_intial_val;
- Rect2 f = p_final_val;
- return Rect2(f.position - i.position, f.size - i.size);
- }
-
- case Variant::RECT2I: {
- Rect2i i = p_intial_val;
- Rect2i f = p_final_val;
- return Rect2i(f.position - i.position, f.size - i.size);
- }
-
- case Variant::TRANSFORM2D: {
- Transform2D i = p_intial_val;
- Transform2D f = p_final_val;
- return Transform2D(f.columns[0][0] - i.columns[0][0],
- f.columns[0][1] - i.columns[0][1],
- f.columns[1][0] - i.columns[1][0],
- f.columns[1][1] - i.columns[1][1],
- f.columns[2][0] - i.columns[2][0],
- f.columns[2][1] - i.columns[2][1]);
- }
-
- case Variant::AABB: {
- AABB i = p_intial_val;
- AABB f = p_final_val;
- return AABB(f.position - i.position, f.size - i.size);
- }
-
- case Variant::BASIS: {
- Basis i = p_intial_val;
- Basis f = p_final_val;
- return Basis(f.rows[0][0] - i.rows[0][0],
- f.rows[0][1] - i.rows[0][1],
- f.rows[0][2] - i.rows[0][2],
- f.rows[1][0] - i.rows[1][0],
- f.rows[1][1] - i.rows[1][1],
- f.rows[1][2] - i.rows[1][2],
- f.rows[2][0] - i.rows[2][0],
- f.rows[2][1] - i.rows[2][1],
- f.rows[2][2] - i.rows[2][2]);
- }
-
- case Variant::TRANSFORM3D: {
- Transform3D i = p_intial_val;
- Transform3D f = p_final_val;
- return Transform3D(f.basis.rows[0][0] - i.basis.rows[0][0],
- f.basis.rows[0][1] - i.basis.rows[0][1],
- f.basis.rows[0][2] - i.basis.rows[0][2],
- f.basis.rows[1][0] - i.basis.rows[1][0],
- f.basis.rows[1][1] - i.basis.rows[1][1],
- f.basis.rows[1][2] - i.basis.rows[1][2],
- f.basis.rows[2][0] - i.basis.rows[2][0],
- f.basis.rows[2][1] - i.basis.rows[2][1],
- f.basis.rows[2][2] - i.basis.rows[2][2],
- f.origin.x - i.origin.x,
- f.origin.y - i.origin.y,
- f.origin.z - i.origin.z);
- }
+ // Special case for bool.
+ if (p_initial_val.get_type() == Variant::BOOL) {
+ return run_equation(p_trans, p_ease, p_time, p_initial_val, p_delta_val, p_duration) >= 0.5;
+ }
- default: {
- return Variant::evaluate(Variant::OP_SUBTRACT, p_final_val, p_intial_val);
- }
- };
+ Variant ret = Animation::add_variant(p_initial_val, p_delta_val);
+ ret = Animation::interpolate_variant(p_initial_val, ret, run_equation(p_trans, p_ease, p_time, 0.0, 1.0, p_duration));
+ return ret;
}
void Tween::_bind_methods() {
@@ -748,10 +500,10 @@ void PropertyTweener::start() {
}
if (relative) {
- final_val = Variant::evaluate(Variant::Operator::OP_ADD, initial_val, base_final_val);
+ final_val = Animation::add_variant(initial_val, base_final_val);
}
- delta_val = tween->calculate_delta_value(initial_val, final_val);
+ delta_val = Animation::subtract_variant(final_val, initial_val);
}
bool PropertyTweener::step(float &r_delta) {
@@ -973,7 +725,7 @@ void MethodTweener::_bind_methods() {
MethodTweener::MethodTweener(Callable p_callback, Variant p_from, Variant p_to, float p_duration) {
callback = p_callback;
initial_val = p_from;
- delta_val = tween->calculate_delta_value(p_from, p_to);
+ delta_val = Animation::subtract_variant(p_to, p_from);
final_val = p_to;
duration = p_duration;
}
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index b57ec2e5e7..da7a8b5d71 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -164,7 +164,6 @@ public:
static real_t run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d);
static Variant interpolate_variant(Variant p_initial_val, Variant p_delta_val, float p_time, float p_duration, Tween::TransitionType p_trans, Tween::EaseType p_ease);
- Variant calculate_delta_value(Variant p_intial_val, Variant p_final_val);
bool step(float p_delta);
bool can_process(bool p_tree_paused) const;
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 69512903b4..5a0236268b 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -190,6 +190,14 @@ void GraphEditMinimap::_adjust_graph_scroll(const Vector2 &p_offset) {
ge->set_scroll_ofs(p_offset + graph_offset - camera_size / 2);
}
+TypedArray<String> GraphEdit::get_configuration_warnings() const {
+ TypedArray<String> warnings = Control::get_configuration_warnings();
+
+ warnings.push_back(RTR("Please be aware that GraphEdit and GraphNode will undergo extensive refactoring in a future beta version involving compatibility-breaking API changes."));
+
+ return warnings;
+}
+
Error GraphEdit::connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port) {
if (is_node_connected(p_from, p_from_port, p_to, p_to_port)) {
return OK;
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 9371ed3df4..0fe9e7c555 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -287,6 +287,8 @@ protected:
GDVIRTUAL4R(bool, _is_node_hover_valid, StringName, int, StringName, int);
public:
+ TypedArray<String> get_configuration_warnings() const override;
+
Error connect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
bool is_node_connected(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
void disconnect_node(const StringName &p_from, int p_from_port, const StringName &p_to, int p_to_port);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 5295de5c09..879d494909 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -795,11 +795,20 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override,
stretch_transform = p_stretch_transform;
to_screen_rect = p_to_screen_rect;
- if (p_allocated) {
- RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
- } else {
- RS::get_singleton()->viewport_set_size(viewport, 0, 0);
- }
+#ifndef _3D_DISABLED
+ if (!use_xr) {
+#endif
+
+ if (p_allocated) {
+ RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
+ } else {
+ RS::get_singleton()->viewport_set_size(viewport, 0, 0);
+ }
+
+#ifndef _3D_DISABLED
+ } // if (!use_xr)
+#endif
+
_update_global_transform();
update_configuration_warnings();
@@ -813,6 +822,19 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override,
}
Size2i Viewport::_get_size() const {
+#ifndef _3D_DISABLED
+ if (use_xr) {
+ if (XRServer::get_singleton() != nullptr) {
+ Ref<XRInterface> xr_interface = XRServer::get_singleton()->get_primary_interface();
+ if (xr_interface.is_valid() && xr_interface->is_initialized()) {
+ Size2 xr_size = xr_interface->get_render_target_size();
+ return (Size2i)xr_size;
+ }
+ }
+ return Size2i();
+ }
+#endif // _3D_DISABLED
+
return size;
}
@@ -3612,9 +3634,20 @@ void Viewport::_propagate_exit_world_3d(Node *p_node) {
}
void Viewport::set_use_xr(bool p_use_xr) {
- use_xr = p_use_xr;
+ if (use_xr != p_use_xr) {
+ use_xr = p_use_xr;
- RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
+ RS::get_singleton()->viewport_set_use_xr(viewport, use_xr);
+
+ if (!use_xr) {
+ // Set viewport to previous size when exiting XR.
+ if (size_allocated) {
+ RS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
+ } else {
+ RS::get_singleton()->viewport_set_size(viewport, 0, 0);
+ }
+ }
+ }
}
bool Viewport::is_using_xr() {
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index afea3ea56c..c7c474c70f 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -568,7 +568,7 @@ public:
bool is_input_disabled() const;
Vector2 get_mouse_position() const;
- virtual void warp_mouse(const Vector2 &p_position);
+ void warp_mouse(const Vector2 &p_position);
void set_physics_object_picking(bool p_enable);
bool get_physics_object_picking();
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 04f56bb874..ebe9587b31 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -986,18 +986,6 @@ DisplayServer::WindowID Window::get_window_id() const {
return window_id;
}
-void Window::warp_mouse(const Vector2 &p_position) {
- Transform2D xform = get_screen_transform();
- Vector2 gpos = xform.xform(p_position);
-
- if (transient_parent && !transient_parent->is_embedding_subwindows()) {
- Transform2D window_trans = Transform2D().translated(get_position() + (transient_parent->get_visible_rect().size - transient_parent->get_real_size()));
- gpos = window_trans.xform(gpos);
- }
-
- Input::get_singleton()->warp_mouse(gpos);
-}
-
void Window::set_wrap_controls(bool p_enable) {
wrap_controls = p_enable;
if (wrap_controls) {
@@ -1153,7 +1141,7 @@ void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio
Rect2 parent_rect;
if (is_embedded()) {
- parent_rect = get_parent_viewport()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
@@ -1179,7 +1167,7 @@ void Window::popup_centered(const Size2i &p_minsize) {
Rect2 parent_rect;
if (is_embedded()) {
- parent_rect = get_parent_viewport()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
@@ -1207,7 +1195,7 @@ void Window::popup_centered_ratio(float p_ratio) {
Rect2 parent_rect;
if (is_embedded()) {
- parent_rect = get_parent_viewport()->get_visible_rect();
+ parent_rect = _get_embedder()->get_visible_rect();
} else {
DisplayServer::WindowID parent_id = get_parent_visible_window()->get_window_id();
int parent_screen = DisplayServer::get_singleton()->window_get_current_screen(parent_id);
diff --git a/scene/main/window.h b/scene/main/window.h
index 8113117103..8c6ca65436 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -254,8 +254,6 @@ public:
void set_use_font_oversampling(bool p_oversampling);
bool is_using_font_oversampling() const;
- void warp_mouse(const Vector2 &p_position) override;
-
void set_wrap_controls(bool p_enable);
bool is_wrapping_controls() const;
void child_controls_changed();
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 9d5bc18c96..4f16f75389 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -2317,9 +2317,7 @@ Quaternion Animation::_interpolate(const Quaternion &p_a, const Quaternion &p_b,
}
Variant Animation::_interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const {
- Variant dst;
- Variant::interpolate(p_a, p_b, p_c, dst);
- return dst;
+ return interpolate_variant(p_a, p_b, p_c);
}
real_t Animation::_interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const {
@@ -5563,6 +5561,466 @@ bool Animation::_fetch_compressed_by_index(uint32_t p_compressed_track, int p_in
return false;
}
+// Helper math fuctions for Variant.
+Variant Animation::add_variant(const Variant &a, const Variant &b) {
+ if (a.get_type() != b.get_type()) {
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::BOOL: {
+ return (a.operator real_t()) + (b.operator real_t()); // It is cast for interpolation.
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position + rb.position, ra.size + rb.size);
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(ra.position + rb.position, ra.size + rb.size);
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal + pb.normal, pa.d + pb.d);
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position + ab.position, aa.size + ab.size);
+ }
+ case Variant::QUATERNION: {
+ return (a.operator Quaternion()) * (b.operator Quaternion());
+ }
+ case Variant::TRANSFORM2D: {
+ return (a.operator Transform2D()) * (b.operator Transform2D());
+ }
+ case Variant::TRANSFORM3D: {
+ return (a.operator Transform3D()) * (b.operator Transform3D());
+ }
+ default: {
+ return Variant::evaluate(Variant::OP_ADD, a, b);
+ }
+ }
+}
+
+Variant Animation::subtract_variant(const Variant &a, const Variant &b) {
+ if (a.get_type() != b.get_type()) {
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::BOOL: {
+ return (a.operator real_t()) - (b.operator real_t()); // It is cast for interpolation.
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position - rb.position, ra.size - rb.size);
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(ra.position - rb.position, ra.size - rb.size);
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal - pb.normal, pa.d - pb.d);
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position - ab.position, aa.size - ab.size);
+ }
+ case Variant::QUATERNION: {
+ return (b.operator Quaternion()).inverse() * (a.operator Quaternion());
+ }
+ case Variant::TRANSFORM2D: {
+ return (b.operator Transform2D()).inverse() * (a.operator Transform2D());
+ }
+ case Variant::TRANSFORM3D: {
+ return (b.operator Transform3D()).inverse() * (a.operator Transform3D());
+ }
+ default: {
+ return Variant::evaluate(Variant::OP_SUBTRACT, a, b);
+ }
+ }
+}
+
+Variant Animation::blend_variant(const Variant &a, const Variant &b, float c) {
+ if (a.get_type() != b.get_type()) {
+ if (a.is_num() && b.is_num()) {
+ real_t va = a;
+ real_t vb = b;
+ return va + vb * c;
+ }
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::INT: {
+ return int((a.operator int64_t()) + (b.operator int64_t()) * c + 0.5);
+ }
+ case Variant::FLOAT: {
+ return (a.operator double()) + (b.operator double()) * c;
+ }
+ case Variant::VECTOR2: {
+ return (a.operator Vector2()) + (b.operator Vector2()) * c;
+ }
+ case Variant::VECTOR2I: {
+ const Vector2i va = a.operator Vector2i();
+ const Vector2i vb = b.operator Vector2i();
+ return Vector2i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5));
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position + rb.position * c, ra.size + rb.size * c);
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(int32_t(ra.position.x + rb.position.x * c + 0.5), int32_t(ra.position.y + rb.position.y * c + 0.5), int32_t(ra.size.x + rb.size.x * c + 0.5), int32_t(ra.size.y + rb.size.y * c + 0.5));
+ }
+ case Variant::VECTOR3: {
+ return (a.operator Vector3()) + (b.operator Vector3()) * c;
+ }
+ case Variant::VECTOR3I: {
+ const Vector3i va = a.operator Vector3i();
+ const Vector3i vb = b.operator Vector3i();
+ return Vector3i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5), int32_t(va.z + vb.z * c + 0.5));
+ }
+ case Variant::VECTOR4: {
+ return (a.operator Vector4()) + (b.operator Vector4()) * c;
+ }
+ case Variant::VECTOR4I: {
+ const Vector4i va = a.operator Vector4i();
+ const Vector4i vb = b.operator Vector4i();
+ return Vector4i(int32_t(va.x + vb.x * c + 0.5), int32_t(va.y + vb.y * c + 0.5), int32_t(va.z + vb.z * c + 0.5), int32_t(va.w + vb.w * c + 0.5));
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal + pb.normal * c, pa.d + pb.d * c);
+ }
+ case Variant::COLOR: {
+ return (a.operator Color()) + (b.operator Color()) * c;
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position + ab.position * c, aa.size + ab.size * c);
+ }
+ case Variant::BASIS: {
+ return (a.operator Basis()) + (b.operator Basis()) * c;
+ }
+ case Variant::QUATERNION: {
+ return (a.operator Quaternion()) * Quaternion().slerp((b.operator Quaternion()), c);
+ }
+ case Variant::TRANSFORM2D: {
+ return (a.operator Transform2D()) * Transform2D().interpolate_with((b.operator Transform2D()), c);
+ }
+ case Variant::TRANSFORM3D: {
+ return (a.operator Transform3D()) * Transform3D().interpolate_with((b.operator Transform3D()), c);
+ }
+ default: {
+ return c < 0.5 ? a : b;
+ }
+ }
+}
+
+Variant Animation::interpolate_variant(const Variant &a, const Variant &b, float c) {
+ if (a.get_type() != b.get_type()) {
+ if (a.is_num() && b.is_num()) {
+ real_t va = a;
+ real_t vb = b;
+ return va + (vb - va) * c;
+ }
+ return a;
+ }
+
+ switch (a.get_type()) {
+ case Variant::NIL: {
+ return Variant();
+ }
+ case Variant::INT: {
+ const int64_t va = a.operator int64_t();
+ return int(va + ((b.operator int64_t()) - va) * c);
+ }
+ case Variant::FLOAT: {
+ const real_t va = a.operator real_t();
+ return va + ((b.operator real_t()) - va) * c;
+ }
+ case Variant::VECTOR2: {
+ return (a.operator Vector2()).lerp(b.operator Vector2(), c);
+ }
+ case Variant::VECTOR2I: {
+ const Vector2i va = a.operator Vector2i();
+ const Vector2i vb = b.operator Vector2i();
+ return Vector2i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c));
+ }
+ case Variant::RECT2: {
+ const Rect2 ra = a.operator Rect2();
+ const Rect2 rb = b.operator Rect2();
+ return Rect2(ra.position.lerp(rb.position, c), ra.size.lerp(rb.size, c));
+ }
+ case Variant::RECT2I: {
+ const Rect2i ra = a.operator Rect2i();
+ const Rect2i rb = b.operator Rect2i();
+ return Rect2i(int32_t(ra.position.x + (rb.position.x - ra.position.x) * c), int32_t(ra.position.y + (rb.position.y - ra.position.y) * c), int32_t(ra.size.x + (rb.size.x - ra.size.x) * c), int32_t(ra.size.y + (rb.size.y - ra.size.y) * c));
+ }
+ case Variant::VECTOR3: {
+ return (a.operator Vector3()).lerp(b.operator Vector3(), c);
+ }
+ case Variant::VECTOR3I: {
+ const Vector3i va = a.operator Vector3i();
+ const Vector3i vb = b.operator Vector3i();
+ return Vector3i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c), int32_t(va.z + (vb.z - va.z) * c));
+ }
+ case Variant::VECTOR4: {
+ return (a.operator Vector4()).lerp(b.operator Vector4(), c);
+ }
+ case Variant::VECTOR4I: {
+ const Vector4i va = a.operator Vector4i();
+ const Vector4i vb = b.operator Vector4i();
+ return Vector4i(int32_t(va.x + (vb.x - va.x) * c), int32_t(va.y + (vb.y - va.y) * c), int32_t(va.z + (vb.z - va.z) * c), int32_t(va.w + (vb.w - va.w) * c));
+ }
+ case Variant::PLANE: {
+ const Plane pa = a.operator Plane();
+ const Plane pb = b.operator Plane();
+ return Plane(pa.normal.lerp(pb.normal, c), pa.d + (pb.d - pa.d) * c);
+ }
+ case Variant::COLOR: {
+ return (a.operator Color()).lerp(b.operator Color(), c);
+ }
+ case Variant::AABB: {
+ const ::AABB aa = a.operator ::AABB();
+ const ::AABB ab = b.operator ::AABB();
+ return ::AABB(aa.position.lerp(ab.position, c), aa.size.lerp(ab.size, c));
+ }
+ case Variant::BASIS: {
+ return (a.operator Basis()).lerp(b.operator Basis(), c);
+ }
+ case Variant::QUATERNION: {
+ return (a.operator Quaternion()).slerp(b.operator Quaternion(), c);
+ }
+ case Variant::TRANSFORM2D: {
+ return (a.operator Transform2D()).interpolate_with(b.operator Transform2D(), c);
+ }
+ case Variant::TRANSFORM3D: {
+ return (a.operator Transform3D()).interpolate_with(b.operator Transform3D(), c);
+ }
+ case Variant::STRING: {
+ // This is pretty funny and bizarre, but artists like to use it for typewriter effects.
+ const String sa = a.operator String();
+ const String sb = b.operator String();
+ String dst;
+ int sa_len = sa.length();
+ int sb_len = sb.length();
+ int csize = sa_len + (sb_len - sa_len) * c;
+ if (csize == 0) {
+ return "";
+ }
+ dst.resize(csize + 1);
+ dst[csize] = 0;
+ int split = csize / 2;
+
+ for (int i = 0; i < csize; i++) {
+ char32_t chr = ' ';
+
+ if (i < split) {
+ if (i < sa.length()) {
+ chr = sa[i];
+ } else if (i < sb.length()) {
+ chr = sb[i];
+ }
+
+ } else {
+ if (i < sb.length()) {
+ chr = sb[i];
+ } else if (i < sa.length()) {
+ chr = sa[i];
+ }
+ }
+
+ dst[i] = chr;
+ }
+
+ return dst;
+ }
+ case Variant::PACKED_INT32_ARRAY: {
+ const Vector<int32_t> *arr_a = Object::cast_to<Vector<int32_t>>(a);
+ const Vector<int32_t> *arr_b = Object::cast_to<Vector<int32_t>>(b);
+ int32_t sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<int32_t> v;
+ v.resize(sz);
+ {
+ int32_t *vw = v.ptrw();
+ const int32_t *ar = arr_a->ptr();
+ const int32_t *br = arr_b->ptr();
+
+ Variant va;
+ for (int32_t i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_INT64_ARRAY: {
+ const Vector<int64_t> *arr_a = Object::cast_to<Vector<int64_t>>(a);
+ const Vector<int64_t> *arr_b = Object::cast_to<Vector<int64_t>>(b);
+ int64_t sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<int64_t> v;
+ v.resize(sz);
+ {
+ int64_t *vw = v.ptrw();
+ const int64_t *ar = arr_a->ptr();
+ const int64_t *br = arr_b->ptr();
+
+ Variant va;
+ for (int64_t i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_FLOAT32_ARRAY: {
+ const Vector<float> *arr_a = Object::cast_to<Vector<float>>(a);
+ const Vector<float> *arr_b = Object::cast_to<Vector<float>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<float> v;
+ v.resize(sz);
+ {
+ float *vw = v.ptrw();
+ const float *ar = arr_a->ptr();
+ const float *br = arr_b->ptr();
+
+ Variant va;
+ for (int i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_FLOAT64_ARRAY: {
+ const Vector<double> *arr_a = Object::cast_to<Vector<double>>(a);
+ const Vector<double> *arr_b = Object::cast_to<Vector<double>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<double> v;
+ v.resize(sz);
+ {
+ double *vw = v.ptrw();
+ const double *ar = arr_a->ptr();
+ const double *br = arr_b->ptr();
+
+ Variant va;
+ for (int i = 0; i < sz; i++) {
+ va = interpolate_variant(ar[i], br[i], c);
+ vw[i] = va;
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_VECTOR2_ARRAY: {
+ const Vector<Vector2> *arr_a = Object::cast_to<Vector<Vector2>>(a);
+ const Vector<Vector2> *arr_b = Object::cast_to<Vector<Vector2>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<Vector2> v;
+ v.resize(sz);
+ {
+ Vector2 *vw = v.ptrw();
+ const Vector2 *ar = arr_a->ptr();
+ const Vector2 *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_VECTOR3_ARRAY: {
+ const Vector<Vector3> *arr_a = Object::cast_to<Vector<Vector3>>(a);
+ const Vector<Vector3> *arr_b = Object::cast_to<Vector<Vector3>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<Vector3> v;
+ v.resize(sz);
+ {
+ Vector3 *vw = v.ptrw();
+ const Vector3 *ar = arr_a->ptr();
+ const Vector3 *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ return v;
+ }
+ }
+ case Variant::PACKED_COLOR_ARRAY: {
+ const Vector<Color> *arr_a = Object::cast_to<Vector<Color>>(a);
+ const Vector<Color> *arr_b = Object::cast_to<Vector<Color>>(b);
+ int sz = arr_a->size();
+ if (sz == 0 || arr_b->size() != sz) {
+ return a;
+ } else {
+ Vector<Color> v;
+ v.resize(sz);
+ {
+ Color *vw = v.ptrw();
+ const Color *ar = arr_a->ptr();
+ const Color *br = arr_b->ptr();
+
+ for (int i = 0; i < sz; i++) {
+ vw[i] = ar[i].lerp(br[i], c);
+ }
+ }
+ return v;
+ }
+ }
+ default: {
+ return c < 0.5 ? a : b;
+ }
+ }
+}
+
Animation::Animation() {}
Animation::~Animation() {
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 46a88df130..112a6c28aa 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -496,6 +496,12 @@ public:
void optimize(real_t p_allowed_velocity_err = 0.01, real_t p_allowed_angular_err = 0.01, int p_precision = 3);
void compress(uint32_t p_page_size = 8192, uint32_t p_fps = 120, float p_split_tolerance = 4.0); // 4.0 seems to be the split tolerance sweet spot from many tests
+ // Helper math fuctions for Variant.
+ static Variant add_variant(const Variant &a, const Variant &b);
+ static Variant subtract_variant(const Variant &a, const Variant &b);
+ static Variant blend_variant(const Variant &a, const Variant &b, float c);
+ static Variant interpolate_variant(const Variant &a, const Variant &b, float c);
+
Animation();
~Animation();
};
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 448ff74a53..c1e30dd93c 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -156,17 +156,7 @@ Material::~Material() {
bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
if (shader.is_valid()) {
- StringName pr = shader->remap_uniform(p_name);
- if (!pr) {
- String n = p_name;
- if (n.find("shader_parameter/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_parameter/", "");
- } else if (n.find("shader_uniform/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_uniform/", "");
- } else if (n.find("param/") == 0) { //backwards compatibility
- pr = n.substr(6, n.length());
- }
- }
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
set_shader_parameter(pr, p_value);
return true;
@@ -178,25 +168,9 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_uniform(p_name);
- if (!pr) {
- String n = p_name;
- if (n.find("shader_parameter/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_parameter/", "");
- } else if (n.find("shader_uniform/") == 0) { //backwards compatibility
- pr = n.replace_first("shader_uniform/", "");
- } else if (n.find("param/") == 0) { //backwards compatibility
- pr = n.substr(6, n.length());
- }
- }
-
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
- HashMap<StringName, Variant>::ConstIterator E = param_cache.find(pr);
- if (E) {
- r_ret = E->value;
- } else {
- r_ret = Variant();
- }
+ r_ret = get_shader_parameter(pr);
return true;
}
}
@@ -238,6 +212,7 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
PropertyInfo info;
info.usage = PROPERTY_USAGE_GROUP;
info.name = last_group.capitalize();
+ info.hint_string = "shader_parameter/";
List<PropertyInfo> none_subgroup;
none_subgroup.push_back(info);
@@ -252,6 +227,7 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
PropertyInfo info;
info.usage = PROPERTY_USAGE_SUBGROUP;
info.name = last_subgroup.capitalize();
+ info.hint_string = "shader_parameter/";
List<PropertyInfo> subgroup;
subgroup.push_back(info);
@@ -271,39 +247,42 @@ void ShaderMaterial::_get_property_list(List<PropertyInfo> *p_list) const {
PropertyInfo info;
info.usage = PROPERTY_USAGE_GROUP;
- info.name = "Shader Param";
+ info.name = "Shader Parameters";
+ info.hint_string = "shader_parameter/";
groups["<None>"]["<None>"].push_back(info);
}
PropertyInfo info = E->get();
- info.name = info.name;
+ info.name = "shader_parameter/" + info.name;
groups[last_group][last_subgroup].push_back(info);
}
- // Sort groups alphabetically.
- List<UniformProp> props;
+ List<String> group_names;
for (HashMap<String, HashMap<String, List<PropertyInfo>>>::Iterator group = groups.begin(); group; ++group) {
- for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = group->value.begin(); subgroup; ++subgroup) {
- for (List<PropertyInfo>::Element *item = subgroup->value.front(); item; item = item->next()) {
- if (subgroup->key == "<None>") {
- props.push_back({ group->key, item->get() });
- } else {
- props.push_back({ group->key + "::" + subgroup->key, item->get() });
- }
- }
- }
+ group_names.push_back(group->key);
}
- props.sort_custom<UniformPropComparator>();
+ group_names.sort();
- for (List<UniformProp>::Element *E = props.front(); E; E = E->next()) {
- p_list->push_back(E->get().info);
+ for (const String &group_name : group_names) {
+ List<String> subgroup_names;
+ HashMap<String, List<PropertyInfo>> &subgroups = groups[group_name];
+ for (HashMap<String, List<PropertyInfo>>::Iterator subgroup = subgroups.begin(); subgroup; ++subgroup) {
+ subgroup_names.push_back(subgroup->key);
+ }
+ subgroup_names.sort();
+ for (const String &subgroup_name : subgroup_names) {
+ List<PropertyInfo> &prop_infos = subgroups[subgroup_name];
+ for (List<PropertyInfo>::Element *item = prop_infos.front(); item; item = item->next()) {
+ p_list->push_back(item->get());
+ }
+ }
}
}
}
bool ShaderMaterial::_property_can_revert(const StringName &p_name) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_uniform(p_name);
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
Variant default_value = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr);
Variant current_value;
@@ -316,7 +295,7 @@ bool ShaderMaterial::_property_can_revert(const StringName &p_name) const {
bool ShaderMaterial::_property_get_revert(const StringName &p_name, Variant &r_property) const {
if (shader.is_valid()) {
- StringName pr = shader->remap_uniform(p_name);
+ StringName pr = shader->remap_parameter(p_name);
if (pr) {
r_property = RenderingServer::get_singleton()->shader_get_parameter_default(shader->get_rid(), pr);
return true;
@@ -924,6 +903,7 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_BILLBOARD_KEEP_SCALE]) {
code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
}
+ code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n";
} break;
case BILLBOARD_FIXED_Y: {
code += " MODELVIEW_MATRIX = VIEW_MATRIX * mat4(vec4(normalize(cross(vec3(0.0, 1.0, 0.0), INV_VIEW_MATRIX[2].xyz)), 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(normalize(cross(INV_VIEW_MATRIX[0].xyz, vec3(0.0, 1.0, 0.0))), 0.0), MODEL_MATRIX[3]);\n";
@@ -931,6 +911,7 @@ void BaseMaterial3D::_update_shader() {
if (flags[FLAG_BILLBOARD_KEEP_SCALE]) {
code += " MODELVIEW_MATRIX = MODELVIEW_MATRIX * mat4(vec4(length(MODEL_MATRIX[0].xyz), 0.0, 0.0, 0.0),vec4(0.0, length(MODEL_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(MODEL_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
}
+ code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n";
} break;
case BILLBOARD_PARTICLES: {
//make billboard
@@ -939,6 +920,8 @@ void BaseMaterial3D::_update_shader() {
code += " mat_world = mat_world * mat4(vec4(cos(INSTANCE_CUSTOM.x), -sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
//set modelview
code += " MODELVIEW_MATRIX = VIEW_MATRIX * mat_world;\n";
+ //set modelview normal
+ code += " MODELVIEW_NORMAL_MATRIX = mat3(MODELVIEW_MATRIX);\n";
//handle animation
code += " float h_frames = float(particles_anim_h_frames);\n";
@@ -949,7 +932,7 @@ void BaseMaterial3D::_update_shader() {
code += " particle_frame = clamp(particle_frame, 0.0, particle_total_frames - 1.0);\n";
code += " } else {\n";
code += " particle_frame = mod(particle_frame, particle_total_frames);\n";
- code += " }";
+ code += " }\n";
code += " UV /= vec2(h_frames, v_frames);\n";
code += " UV += vec2(mod(particle_frame, h_frames) / h_frames, floor((particle_frame + 0.5) / h_frames) / v_frames);\n";
} break;
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 6c81293ee3..dd9589c577 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -84,17 +84,6 @@ class ShaderMaterial : public Material {
HashMap<StringName, Variant> param_cache;
- struct UniformProp {
- String str;
- PropertyInfo info;
- };
-
- struct UniformPropComparator {
- bool operator()(const UniformProp &p_a, const UniformProp &p_b) const {
- return p_a.str.naturalnocasecmp_to(p_b.str) < 0;
- }
- };
-
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index d267e6520e..57be142a95 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -87,15 +87,44 @@ public:
virtual bool is_text_shader() const;
- _FORCE_INLINE_ StringName remap_uniform(const StringName &p_uniform) const {
+ // Finds the shader parameter name for the given property name, which should start with "shader_parameter/".
+ _FORCE_INLINE_ StringName remap_parameter(const StringName &p_property) const {
if (params_cache_dirty) {
get_shader_uniform_list(nullptr);
}
- const HashMap<StringName, StringName>::Iterator E = params_cache.find(p_uniform);
- if (E) {
- return E->value;
+ String n = p_property;
+
+ // Backwards compatibility with old shader parameter names.
+ // Note: The if statements are important to make sure we are only replacing text exactly at index 0.
+ if (n.find("param/") == 0) {
+ n = n.replace_first("param/", "shader_parameter/");
+ }
+ if (n.find("shader_param/") == 0) {
+ n = n.replace_first("shader_param/", "shader_parameter/");
+ }
+ if (n.find("shader_uniform/") == 0) {
+ n = n.replace_first("shader_uniform/", "shader_parameter/");
+ }
+
+ {
+ // Additional backwards compatibility for projects between #62972 and #64092 (about a month of v4.0 development).
+ // These projects did not have any prefix for shader uniforms due to a bug.
+ // This code should be removed during beta or rc of 4.0.
+ const HashMap<StringName, StringName>::Iterator E = params_cache.find(n);
+ if (E) {
+ return E->value;
+ }
+ }
+
+ if (n.begins_with("shader_parameter/")) {
+ n = n.replace_first("shader_parameter/", "");
+ const HashMap<StringName, StringName>::Iterator E = params_cache.find(n);
+ if (E) {
+ return E->value;
+ }
}
+
return StringName();
}
diff --git a/scene/resources/skeleton_modification_stack_2d.cpp b/scene/resources/skeleton_modification_stack_2d.cpp
index 068c756849..56234a8a14 100644
--- a/scene/resources/skeleton_modification_stack_2d.cpp
+++ b/scene/resources/skeleton_modification_stack_2d.cpp
@@ -182,11 +182,11 @@ void SkeletonModificationStack2D::delete_modification(int p_mod_idx) {
void SkeletonModificationStack2D::set_modification(int p_mod_idx, Ref<SkeletonModification2D> p_mod) {
ERR_FAIL_INDEX(p_mod_idx, modifications.size());
- if (p_mod == nullptr) {
- modifications.insert(p_mod_idx, nullptr);
+ if (p_mod.is_null()) {
+ modifications.write[p_mod_idx] = Ref<SkeletonModification2D>();
} else {
+ modifications.write[p_mod_idx] = p_mod;
p_mod->_setup_modification(this);
- modifications.insert(p_mod_idx, p_mod);
}
#ifdef TOOLS_ENABLED
diff --git a/servers/physics_2d/godot_collision_solver_2d.cpp b/servers/physics_2d/godot_collision_solver_2d.cpp
index 0d7b42b80d..761a1c33e2 100644
--- a/servers/physics_2d/godot_collision_solver_2d.cpp
+++ b/servers/physics_2d/godot_collision_solver_2d.cpp
@@ -34,7 +34,7 @@
#define collision_solver sat_2d_calculate_penetration
//#define collision_solver gjk_epa_calculate_penetration
-bool GodotCollisionSolver2D::solve_static_world_boundary(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) {
+bool GodotCollisionSolver2D::solve_static_world_boundary(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin) {
const GodotWorldBoundaryShape2D *world_boundary = static_cast<const GodotWorldBoundaryShape2D *>(p_shape_A);
if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) {
return false;
@@ -52,7 +52,9 @@ bool GodotCollisionSolver2D::solve_static_world_boundary(const GodotShape2D *p_s
bool found = false;
for (int i = 0; i < support_count; i++) {
+ supports[i] += p_margin * supports[i].normalized();
supports[i] = p_transform_B.xform(supports[i]);
+ supports[i] += p_motion_B;
real_t pd = n.dot(supports[i]);
if (pd >= d) {
continue;
@@ -231,9 +233,9 @@ bool GodotCollisionSolver2D::solve(const GodotShape2D *p_shape_A, const Transfor
}
if (swap) {
- return solve_static_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true);
+ return solve_static_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_motion_A, p_result_callback, p_userdata, true, p_margin_A);
} else {
- return solve_static_world_boundary(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false);
+ return solve_static_world_boundary(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_motion_B, p_result_callback, p_userdata, false, p_margin_B);
}
} else if (type_A == PhysicsServer2D::SHAPE_SEPARATION_RAY) {
diff --git a/servers/physics_2d/godot_collision_solver_2d.h b/servers/physics_2d/godot_collision_solver_2d.h
index bd90641f04..3aac2751e0 100644
--- a/servers/physics_2d/godot_collision_solver_2d.h
+++ b/servers/physics_2d/godot_collision_solver_2d.h
@@ -38,7 +38,7 @@ public:
typedef void (*CallbackResult)(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata);
private:
- static bool solve_static_world_boundary(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result);
+ static bool solve_static_world_boundary(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0);
static bool concave_callback(void *p_userdata, GodotShape2D *p_convex);
static bool solve_concave(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0);
static bool solve_separation_ray(const GodotShape2D *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis = nullptr, real_t p_margin = 0);
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index aa9772a483..c5818d9290 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -189,7 +189,7 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item *
RenderingServerDefault::redraw_request();
}
- if (ci->commands != nullptr) {
+ if (ci->commands != nullptr || ci->copy_back_buffer) {
ci->final_transform = xform;
ci->final_modulate = modulate * ci->self_modulate;
ci->global_rect_cache = global_rect;
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index ceba43ae8f..307af99e91 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -1261,6 +1261,7 @@ void SkyRD::setup(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, const P
light_data_dirty = true;
for (uint32_t i = sky_scene_state.ubo.directional_light_count; i < sky_scene_state.max_directional_lights; i++) {
sky_scene_state.directional_lights[i].enabled = false;
+ sky_scene_state.last_frame_directional_lights[i].enabled = false;
}
}
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index dec5e23558..2ad73960a0 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -477,6 +477,10 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
prev_material_uniform_set = material_uniform_set;
}
+ if ((surf->owner->base_flags & (INSTANCE_DATA_FLAG_MULTIMESH | INSTANCE_DATA_FLAG_PARTICLES)) == INSTANCE_DATA_FLAG_MULTIMESH) {
+ mesh_storage->_multimesh_get_motion_vectors_offsets(surf->owner->data->base, push_constant.multimesh_motion_vectors_current_offset, push_constant.multimesh_motion_vectors_previous_offset);
+ }
+
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(SceneState::PushConstant));
uint32_t instance_count = surf->owner->instance_count > 1 ? surf->owner->instance_count : element_info.repeat;
@@ -574,47 +578,21 @@ void RenderForwardClustered::_render_list_with_threads(RenderListParameters *p_p
void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers;
+ RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID();
+ RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID();
- //Projection projection = p_render_data->cam_projection;
- //projection.flip_y(); // Vulkan and modern APIs use Y-Down
- Projection correction;
- correction.set_depth_correction(p_flip_y);
- correction.add_jitter_offset(p_render_data->taa_jitter);
- Projection projection = correction * p_render_data->cam_projection;
-
- //store camera into ubo
- RendererRD::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix);
- RendererRD::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
- RendererRD::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix);
- RendererRD::MaterialStorage::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.view_matrix);
-
- for (uint32_t v = 0; v < p_render_data->view_count; v++) {
- projection = correction * p_render_data->view_projection[v];
- RendererRD::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix_view[v]);
- RendererRD::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix_view[v]);
-
- scene_state.ubo.eye_offset[v][0] = p_render_data->view_eye_offset[v].x;
- scene_state.ubo.eye_offset[v][1] = p_render_data->view_eye_offset[v].y;
- scene_state.ubo.eye_offset[v][2] = p_render_data->view_eye_offset[v].z;
- scene_state.ubo.eye_offset[v][3] = 0.0;
+ // May do this earlier in RenderSceneRenderRD::render_scene
+ if (p_index >= (int)scene_state.uniform_buffers.size()) {
+ uint32_t from = scene_state.uniform_buffers.size();
+ scene_state.uniform_buffers.resize(p_index + 1);
+ for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) {
+ scene_state.uniform_buffers[i] = p_render_data->scene_data->create_uniform_buffer();
+ }
}
- scene_state.ubo.taa_jitter[0] = p_render_data->taa_jitter.x;
- scene_state.ubo.taa_jitter[1] = p_render_data->taa_jitter.y;
-
- scene_state.ubo.z_far = p_render_data->z_far;
- scene_state.ubo.z_near = p_render_data->z_near;
-
- scene_state.ubo.pancake_shadows = p_pancake_shadows;
+ p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel);
-
- Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
- scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
- scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
+ // now do implementation UBO
scene_state.ubo.cluster_shift = get_shift_from_power_of_2(p_render_data->cluster_size);
scene_state.ubo.max_cluster_element_count_div_32 = p_render_data->cluster_max_elements / 32;
@@ -625,22 +603,8 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
scene_state.ubo.cluster_width = cluster_screen_width;
}
- if (p_render_data->shadow_atlas.is_valid()) {
- Vector2 sas = shadow_atlas_get_size(p_render_data->shadow_atlas);
- scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x;
- scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y;
- }
- {
- Vector2 dss = directional_shadow_get_size();
- scene_state.ubo.directional_shadow_pixel_size[0] = 1.0 / dss.x;
- scene_state.ubo.directional_shadow_pixel_size[1] = 1.0 / dss.y;
- }
- //time global variables
- scene_state.ubo.time = time;
-
scene_state.ubo.gi_upscale_for_msaa = false;
scene_state.ubo.volumetric_fog_enabled = false;
- scene_state.ubo.fog_enabled = false;
if (rd.is_valid()) {
if (rd->get_msaa_3d() != RS::VIEWPORT_MSAA_DISABLED) {
@@ -668,59 +632,8 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
}
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
- scene_state.ubo.use_ambient_light = true;
- scene_state.ubo.ambient_light_color_energy[0] = 1;
- scene_state.ubo.ambient_light_color_energy[1] = 1;
- scene_state.ubo.ambient_light_color_energy[2] = 1;
- scene_state.ubo.ambient_light_color_energy[3] = 1.0;
- scene_state.ubo.use_ambient_cubemap = false;
- scene_state.ubo.use_reflection_cubemap = false;
scene_state.ubo.ss_effects_flags = 0;
-
} else if (is_environment(p_render_data->environment)) {
- RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
- RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
-
- float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
-
- scene_state.ubo.ambient_light_color_energy[3] = bg_energy_multiplier;
-
- scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment);
-
- //ambient
- if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
- Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
- color = color.srgb_to_linear();
-
- scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier;
- scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier;
- scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier;
- scene_state.ubo.use_ambient_light = true;
- scene_state.ubo.use_ambient_cubemap = false;
- } else {
- float energy = environment_get_ambient_light_energy(p_render_data->environment);
- Color color = environment_get_ambient_light(p_render_data->environment);
- color = color.srgb_to_linear();
- scene_state.ubo.ambient_light_color_energy[0] = color.r * energy;
- scene_state.ubo.ambient_light_color_energy[1] = color.g * energy;
- scene_state.ubo.ambient_light_color_energy[2] = color.b * energy;
-
- Basis sky_transform = environment_get_sky_orientation(p_render_data->environment);
- sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis;
- RendererRD::MaterialStorage::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
-
- scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
- scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
- }
-
- //specular
- RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->environment);
- if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) {
- scene_state.ubo.use_reflection_cubemap = true;
- } else {
- scene_state.ubo.use_reflection_cubemap = false;
- }
-
scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_channel_affect(p_render_data->environment);
scene_state.ubo.ssao_light_affect = environment_get_ssao_direct_light_affect(p_render_data->environment);
uint32_t ss_flags = 0;
@@ -729,97 +642,19 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat
ss_flags |= environment_get_ssil_enabled(p_render_data->environment) ? 2 : 0;
}
scene_state.ubo.ss_effects_flags = ss_flags;
-
- scene_state.ubo.fog_enabled = environment_get_fog_enabled(p_render_data->environment);
- scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment);
- scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment);
- scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
- scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);
-
- Color fog_color = environment_get_fog_light_color(p_render_data->environment).srgb_to_linear();
- float fog_energy = environment_get_fog_light_energy(p_render_data->environment);
-
- scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
- scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
- scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
-
- scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment);
-
} else {
- if (p_render_data->reflection_probe.is_valid() && RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
- scene_state.ubo.use_ambient_light = false;
- } else {
- scene_state.ubo.use_ambient_light = true;
- Color clear_color = p_default_bg_color;
- clear_color = clear_color.srgb_to_linear();
- scene_state.ubo.ambient_light_color_energy[0] = clear_color.r;
- scene_state.ubo.ambient_light_color_energy[1] = clear_color.g;
- scene_state.ubo.ambient_light_color_energy[2] = clear_color.b;
- scene_state.ubo.ambient_light_color_energy[3] = 1.0;
- }
-
- scene_state.ubo.use_ambient_cubemap = false;
- scene_state.ubo.use_reflection_cubemap = false;
scene_state.ubo.ss_effects_flags = 0;
}
- if (p_render_data->camera_attributes.is_valid()) {
- scene_state.ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
- scene_state.ubo.IBL_exposure_normalization = 1.0;
- if (is_environment(p_render_data->environment)) {
- RID sky_rid = environment_get_sky(p_render_data->environment);
- if (sky_rid.is_valid()) {
- float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes) * environment_get_bg_intensity(p_render_data->environment) / _render_buffers_get_luminance_multiplier();
- scene_state.ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, sky.sky_get_baked_exposure(sky_rid));
- }
- }
- } else if (scene_state.ubo.emissive_exposure_normalization > 0.0) {
- // This branch is triggered when using render_material().
- // Emissive is set outside the function, so don't set it.
- // IBL isn't used don't set it.
- } else {
- scene_state.ubo.emissive_exposure_normalization = 1.0;
- scene_state.ubo.IBL_exposure_normalization = 1.0;
- }
-
- scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active();
- scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount();
- scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit();
-
- if (rd.is_valid()) {
- if (rd->get_use_taa() || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
- memcpy(&scene_state.prev_ubo, &scene_state.ubo, sizeof(SceneState::UBO));
-
- Projection prev_correction;
- prev_correction.set_depth_correction(true);
- prev_correction.add_jitter_offset(p_render_data->prev_taa_jitter);
- Projection prev_projection = prev_correction * p_render_data->prev_cam_projection;
-
- //store camera into ubo
- RendererRD::MaterialStorage::store_camera(prev_projection, scene_state.prev_ubo.projection_matrix);
- RendererRD::MaterialStorage::store_camera(prev_projection.inverse(), scene_state.prev_ubo.inv_projection_matrix);
- RendererRD::MaterialStorage::store_transform(p_render_data->prev_cam_transform, scene_state.prev_ubo.inv_view_matrix);
- RendererRD::MaterialStorage::store_transform(p_render_data->prev_cam_transform.affine_inverse(), scene_state.prev_ubo.view_matrix);
-
- for (uint32_t v = 0; v < p_render_data->view_count; v++) {
- prev_projection = prev_correction * p_render_data->view_projection[v];
- RendererRD::MaterialStorage::store_camera(prev_projection, scene_state.prev_ubo.projection_matrix_view[v]);
- RendererRD::MaterialStorage::store_camera(prev_projection.inverse(), scene_state.prev_ubo.inv_projection_matrix_view[v]);
- }
- scene_state.prev_ubo.taa_jitter[0] = p_render_data->prev_taa_jitter.x;
- scene_state.prev_ubo.taa_jitter[1] = p_render_data->prev_taa_jitter.y;
- scene_state.prev_ubo.time -= time_step;
+ if (p_index >= (int)scene_state.implementation_uniform_buffers.size()) {
+ uint32_t from = scene_state.implementation_uniform_buffers.size();
+ scene_state.implementation_uniform_buffers.resize(p_index + 1);
+ for (uint32_t i = from; i < scene_state.implementation_uniform_buffers.size(); i++) {
+ scene_state.implementation_uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO));
}
}
- if (p_index >= (int)scene_state.uniform_buffers.size()) {
- uint32_t from = scene_state.uniform_buffers.size();
- scene_state.uniform_buffers.resize(p_index + 1);
- for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) {
- scene_state.uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO) * 2);
- }
- }
- RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO) * 2, &scene_state.ubo_data, RD::BARRIER_MASK_RASTER);
+ RD::get_singleton()->buffer_update(scene_state.implementation_uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
}
void RenderForwardClustered::_update_instance_data_buffer(RenderListType p_render_list) {
@@ -924,7 +759,7 @@ _FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primit
static const uint32_t subtractor[RS::PRIMITIVE_MAX] = { 0, 0, 1, 0, 1 };
return (p_indices - subtractor[p_primitive]) / divisor[p_primitive];
}
-void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi, bool p_using_opaque_gi, bool p_append) {
+void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, uint32_t p_color_pass_flags = 0, bool p_using_sdfgi, bool p_using_opaque_gi, bool p_append) {
RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton();
if (p_render_list == RENDER_LIST_OPAQUE) {
@@ -935,9 +770,9 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
}
uint32_t lightmap_captures_used = 0;
- Plane near_plane = Plane(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->cam_transform.origin);
- near_plane.d += p_render_data->cam_projection.get_z_near();
- float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near();
+ Plane near_plane = Plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin);
+ near_plane.d += p_render_data->scene_data->cam_projection.get_z_near();
+ float z_max = p_render_data->scene_data->cam_projection.get_z_far() - p_render_data->scene_data->cam_projection.get_z_near();
RenderList *rl = &render_list[p_render_list];
_update_dirty_geometry_instances();
@@ -968,7 +803,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
float fade_alpha = 1.0;
if (inst->fade_near || inst->fade_far) {
- float fade_dist = inst->transform.origin.distance_to(p_render_data->cam_transform.origin);
+ float fade_dist = inst->transform.origin.distance_to(p_render_data->scene_data->cam_transform.origin);
// Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
if (inst->fade_far && fade_dist > inst->fade_far_begin) {
fade_alpha = Math::smoothstep(0.0f, 1.0f, 1.0f - (fade_dist - inst->fade_far_begin) / (inst->fade_far_end - inst->fade_far_begin));
@@ -1063,13 +898,13 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
// LOD
- if (p_render_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
+ if (p_render_data->scene_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
//lod
- Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal);
- Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal);
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->scene_data->lod_camera_plane.normal);
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->scene_data->lod_camera_plane.normal);
- float distance_min = p_render_data->lod_camera_plane.distance_to(lod_support_min);
- float distance_max = p_render_data->lod_camera_plane.distance_to(lod_support_max);
+ float distance_min = p_render_data->scene_data->lod_camera_plane.distance_to(lod_support_min);
+ float distance_max = p_render_data->scene_data->lod_camera_plane.distance_to(lod_support_max);
float distance = 0.0;
@@ -1082,12 +917,12 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
distance = -distance_max;
}
- if (p_render_data->cam_orthogonal) {
+ if (p_render_data->scene_data->cam_orthogonal) {
distance = 1.0;
}
uint32_t indices;
- surf->sort.lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices);
+ surf->sort.lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, &indices);
if (p_render_data->render_info) {
indices = _indices_to_primitives(surf->primitive, indices);
if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
@@ -1149,6 +984,12 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
scene_state.used_depth_texture = true;
}
+ if (p_color_pass_flags & COLOR_PASS_FLAG_MOTION_VECTORS) {
+ if ((flags & (INSTANCE_DATA_FLAG_MULTIMESH | INSTANCE_DATA_FLAG_PARTICLES)) == INSTANCE_DATA_FLAG_MULTIMESH && RendererRD::MeshStorage::get_singleton()->_multimesh_enable_motion_vectors(inst->data->base)) {
+ inst->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(inst->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+ }
+ }
+
} else if (p_pass_mode == PASS_MODE_SHADOW || p_pass_mode == PASS_MODE_SHADOW_DP) {
if (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_SHADOW) {
rl->add_element(surf);
@@ -1220,9 +1061,18 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RENDER_TIMESTAMP("Setup 3D Scene");
- //scene_state.ubo.subsurface_scatter_width = subsurface_scatter_size;
- scene_state.ubo.directional_light_count = 0;
- scene_state.ubo.opaque_prepass_threshold = 0.99f;
+ // check if we need motion vectors
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
+ p_render_data->scene_data->calculate_motion_vectors = true;
+ } else if (rb.is_valid() && rb->get_use_taa()) {
+ p_render_data->scene_data->calculate_motion_vectors = true;
+ } else {
+ p_render_data->scene_data->calculate_motion_vectors = false;
+ }
+
+ //p_render_data->scene_data->subsurface_scatter_width = subsurface_scatter_size;
+ p_render_data->scene_data->directional_light_count = 0;
+ p_render_data->scene_data->opaque_prepass_threshold = 0.99f;
Size2i screen_size;
RID color_framebuffer;
@@ -1285,7 +1135,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
};
}
- if (p_render_data->view_count > 1) {
+ if (p_render_data->scene_data->view_count > 1) {
color_pass_flags |= COLOR_PASS_FLAG_MULTIVIEW;
}
@@ -1309,20 +1159,17 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
ERR_FAIL(); //bug?
}
- scene_state.ubo.viewport_size[0] = screen_size.x;
- scene_state.ubo.viewport_size[1] = screen_size.y;
-
- scene_state.ubo.emissive_exposure_normalization = -1.0;
+ p_render_data->scene_data->emissive_exposure_normalization = -1.0;
RD::get_singleton()->draw_command_begin_label("Render Setup");
- _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->cam_transform);
+ _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->scene_data->cam_transform);
_setup_voxelgis(*p_render_data->voxel_gi_instances);
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
_update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
- _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, using_sdfgi, using_sdfgi || using_voxelgi);
+ _fill_render_list(RENDER_LIST_OPAQUE, p_render_data, PASS_MODE_COLOR, color_pass_flags, using_sdfgi, using_sdfgi || using_voxelgi);
render_list[RENDER_LIST_OPAQUE].sort_by_key();
render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
_fill_instance_data(RENDER_LIST_OPAQUE, p_render_data->render_info ? p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE] : (int *)nullptr);
@@ -1396,20 +1243,20 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
RENDER_TIMESTAMP("Setup Sky");
RD::get_singleton()->draw_command_begin_label("Setup Sky");
- Projection projection = p_render_data->cam_projection;
+ Projection projection = p_render_data->scene_data->cam_projection;
if (p_render_data->reflection_probe.is_valid()) {
Projection correction;
correction.set_depth_correction(true);
- projection = correction * p_render_data->cam_projection;
+ projection = correction * p_render_data->scene_data->cam_projection;
}
- sky.setup(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->cam_transform, screen_size, this);
+ sky.setup(p_render_data->environment, rb, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->scene_data->cam_transform, screen_size, this);
sky_energy_multiplier *= bg_energy_multiplier;
RID sky_rid = environment_get_sky(p_render_data->environment);
if (sky_rid.is_valid()) {
- sky.update(p_render_data->environment, projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ sky.update(p_render_data->environment, projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
} else {
// do not try to draw sky if invalid
@@ -1448,7 +1295,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, nullptr, RID());
bool finish_depth = using_ssao || using_sdfgi || using_voxelgi;
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, depth_pass_mode, 0, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
_render_list_with_threads(&render_list_params, depth_framebuffer, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, needs_pre_resolve ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_CLEAR, finish_depth ? RD::FINAL_ACTION_READ : RD::FINAL_ACTION_CONTINUE, needs_pre_resolve ? Vector<Color>() : depth_pass_clear);
RD::get_singleton()->draw_command_end_label();
@@ -1488,8 +1335,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_begin_label("Render Opaque Pass");
- scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
- scene_state.ubo.opaque_prepass_threshold = 0.0f;
+ p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count;
+ p_render_data->scene_data->opaque_prepass_threshold = 0.0f;
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, rb.is_valid());
@@ -1518,7 +1365,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
}
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
_render_list_with_threads(&render_list_params, color_framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0);
if (will_continue_color && using_separate_specular) {
// close the specular framebuffer, as it's no longer used
@@ -1536,7 +1383,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
Projection dc;
dc.set_depth_correction(true);
- Projection cm = (dc * p_render_data->cam_projection) * Projection(p_render_data->cam_transform.affine_inverse());
+ Projection cm = (dc * p_render_data->scene_data->cam_projection) * Projection(p_render_data->scene_data->cam_transform.affine_inverse());
RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(color_only_framebuffer, RD::INITIAL_ACTION_CONTINUE, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CONTINUE, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ);
RD::get_singleton()->draw_command_begin_label("Debug VoxelGIs");
for (int i = 0; i < (int)p_render_data->voxel_gi_instances->size(); i++) {
@@ -1554,10 +1401,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
Projection dc;
dc.set_depth_correction(true);
Projection cms[RendererSceneRender::MAX_RENDER_VIEWS];
- for (uint32_t v = 0; v < p_render_data->view_count; v++) {
- cms[v] = (dc * p_render_data->view_projection[v]) * Projection(p_render_data->cam_transform.affine_inverse());
+ for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) {
+ cms[v] = (dc * p_render_data->scene_data->view_projection[v]) * Projection(p_render_data->scene_data->cam_transform.affine_inverse());
}
- _debug_sdfgi_probes(rb, color_only_framebuffer, p_render_data->view_count, cms, will_continue_color, will_continue_depth);
+ _debug_sdfgi_probes(rb, color_only_framebuffer, p_render_data->scene_data->view_count, cms, will_continue_color, will_continue_depth);
}
if (draw_sky || draw_sky_fog_only) {
@@ -1568,10 +1415,10 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (p_render_data->reflection_probe.is_valid()) {
Projection correction;
correction.set_depth_correction(true);
- Projection projection = correction * p_render_data->cam_projection;
- sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, 1, &projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ Projection projection = correction * p_render_data->scene_data->cam_projection;
+ sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
} else {
- sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ sky.draw(p_render_data->environment, can_continue_color, can_continue_depth, color_only_framebuffer, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
}
RD::get_singleton()->draw_command_end_label();
}
@@ -1598,7 +1445,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (using_sss) {
RENDER_TIMESTAMP("Sub-Surface Scattering");
RD::get_singleton()->draw_command_begin_label("Process Sub-Surface Scattering");
- _process_sss(rb, p_render_data->cam_projection);
+ _process_sss(rb, p_render_data->scene_data->cam_projection);
RD::get_singleton()->draw_command_end_label();
}
@@ -1606,15 +1453,15 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RENDER_TIMESTAMP("Screen-Space Reflections");
RD::get_singleton()->draw_command_begin_label("Process Screen-Space Reflections");
RID specular_views[RendererSceneRender::MAX_RENDER_VIEWS];
- for (uint32_t v = 0; v < p_render_data->view_count; v++) {
+ for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) {
specular_views[v] = rb_data->get_specular(v);
}
- _process_ssr(rb, color_only_framebuffer, normal_roughness_views, rb_data->get_specular(), specular_views, p_render_data->environment, p_render_data->view_projection, p_render_data->view_eye_offset, rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED);
+ _process_ssr(rb, color_only_framebuffer, normal_roughness_views, rb_data->get_specular(), specular_views, p_render_data->environment, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED);
RD::get_singleton()->draw_command_end_label();
} else {
//just mix specular back
RENDER_TIMESTAMP("Merge Specular");
- copy_effects->merge_specular(color_only_framebuffer, rb_data->get_specular(), rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED ? RID() : rb->get_internal_texture(), RID(), p_render_data->view_count);
+ copy_effects->merge_specular(color_only_framebuffer, rb_data->get_specular(), rb->get_msaa_3d() == RS::VIEWPORT_MSAA_DISABLED ? RID() : rb->get_internal_texture(), RID(), p_render_data->scene_data->view_count);
}
}
@@ -1639,7 +1486,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
{
uint32_t transparent_color_pass_flags = (color_pass_flags | COLOR_PASS_FLAG_TRANSPARENT) & ~(COLOR_PASS_FLAG_SEPARATE_SPECULAR);
RID alpha_framebuffer = rb_data.is_valid() ? rb_data->get_color_pass_fb(transparent_color_pass_flags) : color_only_framebuffer;
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, transparent_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, transparent_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
_render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
}
@@ -1670,7 +1517,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
if (rb.is_valid() && taa && rb->get_use_taa()) {
RENDER_TIMESTAMP("TAA")
- taa->process(rb, _render_buffers_get_color_format(), p_render_data->z_near, p_render_data->z_far);
+ taa->process(rb, _render_buffers_get_color_format(), p_render_data->scene_data->z_near, p_render_data->scene_data->z_far);
}
if (rb.is_valid()) {
@@ -1696,34 +1543,36 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
SceneState::ShadowPass shadow_pass;
+ RenderSceneDataRD scene_data;
+ scene_data.cam_projection = p_projection;
+ scene_data.cam_transform = p_transform;
+ scene_data.view_projection[0] = p_projection;
+ scene_data.z_far = p_zfar;
+ scene_data.z_near = 0.0;
+ scene_data.lod_camera_plane = p_camera_plane;
+ scene_data.lod_distance_multiplier = p_lod_distance_multiplier;
+ scene_data.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
+ scene_data.opaque_prepass_threshold = 0.1f;
+
RenderDataRD render_data;
- render_data.cam_projection = p_projection;
- render_data.cam_transform = p_transform;
- render_data.view_projection[0] = p_projection;
- render_data.z_far = p_zfar;
- render_data.z_near = 0.0;
+ render_data.scene_data = &scene_data;
render_data.cluster_size = 1;
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
- render_data.lod_camera_plane = p_camera_plane;
- render_data.lod_distance_multiplier = p_lod_distance_multiplier;
render_data.render_info = p_render_info;
- scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
- scene_state.ubo.opaque_prepass_threshold = 0.1f;
-
_setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index);
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
- render_data.screen_mesh_lod_threshold = 0.0;
+ scene_data.screen_mesh_lod_threshold = 0.0;
} else {
- render_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
+ scene_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
}
PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW;
uint32_t render_list_from = render_list[RENDER_LIST_SECONDARY].elements.size();
- _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, false, false, true);
+ _fill_render_list(RENDER_LIST_SECONDARY, &render_data, pass_mode, 0, false, false, true);
uint32_t render_list_size = render_list[RENDER_LIST_SECONDARY].elements.size() - render_list_from;
render_list[RENDER_LIST_SECONDARY].sort_by_key_range(render_list_from, render_list_size);
_fill_instance_data(RENDER_LIST_SECONDARY, p_render_info ? p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW] : (int *)nullptr, render_list_from, render_list_size, false);
@@ -1742,8 +1591,8 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page
shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete
shadow_pass.camera_plane = p_camera_plane;
- shadow_pass.screen_mesh_lod_threshold = render_data.screen_mesh_lod_threshold;
- shadow_pass.lod_distance_multiplier = render_data.lod_distance_multiplier;
+ shadow_pass.screen_mesh_lod_threshold = scene_data.screen_mesh_lod_threshold;
+ shadow_pass.lod_distance_multiplier = scene_data.lod_distance_multiplier;
shadow_pass.framebuffer = p_framebuffer;
shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE);
@@ -1786,19 +1635,22 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
+ RenderSceneDataRD scene_data;
+ scene_data.cam_projection = p_cam_projection;
+ scene_data.cam_transform = p_cam_transform;
+ scene_data.view_projection[0] = p_cam_projection;
+ scene_data.z_near = 0.0;
+ scene_data.z_far = p_cam_projection.get_z_far();
+ scene_data.dual_paraboloid_side = 0;
+ scene_data.opaque_prepass_threshold = 0.0;
+
RenderDataRD render_data;
- render_data.cam_projection = p_cam_projection;
- render_data.cam_transform = p_cam_transform;
- render_data.view_projection[0] = p_cam_projection;
- render_data.z_near = 0.0;
- render_data.z_far = p_cam_projection.get_z_far();
+ render_data.scene_data = &scene_data;
render_data.cluster_size = 1;
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
_update_render_base_uniform_set();
- scene_state.ubo.dual_paraboloid_side = 0;
- scene_state.ubo.opaque_prepass_threshold = 0.0;
_setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false);
@@ -1825,21 +1677,23 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform
RD::get_singleton()->draw_command_begin_label("Render 3D Material");
+ RenderSceneDataRD scene_data;
+ scene_data.cam_projection = p_cam_projection;
+ scene_data.cam_transform = p_cam_transform;
+ scene_data.view_projection[0] = p_cam_projection;
+ scene_data.dual_paraboloid_side = 0;
+ scene_data.material_uv2_mode = false;
+ scene_data.opaque_prepass_threshold = 0.0f;
+ scene_data.emissive_exposure_normalization = p_exposure_normalization;
+
RenderDataRD render_data;
- render_data.cam_projection = p_cam_projection;
- render_data.cam_transform = p_cam_transform;
- render_data.view_projection[0] = p_cam_projection;
+ render_data.scene_data = &scene_data;
render_data.cluster_size = 1;
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
_update_render_base_uniform_set();
- scene_state.ubo.dual_paraboloid_side = 0;
- scene_state.ubo.material_uv2_mode = false;
- scene_state.ubo.opaque_prepass_threshold = 0.0f;
- scene_state.ubo.emissive_exposure_normalization = p_exposure_normalization;
-
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
@@ -1875,18 +1729,20 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance
RD::get_singleton()->draw_command_begin_label("Render UV2");
+ RenderSceneDataRD scene_data;
+ scene_data.dual_paraboloid_side = 0;
+ scene_data.material_uv2_mode = true;
+ scene_data.opaque_prepass_threshold = 0.0;
+ scene_data.emissive_exposure_normalization = -1.0;
+
RenderDataRD render_data;
+ render_data.scene_data = &scene_data;
render_data.cluster_size = 1;
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
_update_render_base_uniform_set();
- scene_state.ubo.dual_paraboloid_side = 0;
- scene_state.ubo.material_uv2_mode = true;
- scene_state.ubo.opaque_prepass_threshold = 0.0;
- scene_state.ubo.emissive_exposure_normalization = -1.0;
-
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
PassMode pass_mode = PASS_MODE_DEPTH_MATERIAL;
@@ -1946,7 +1802,10 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
RD::get_singleton()->draw_command_begin_label("Render SDFGI Voxel");
+ RenderSceneDataRD scene_data;
+
RenderDataRD render_data;
+ render_data.scene_data = &scene_data;
render_data.cluster_size = 1;
render_data.cluster_max_elements = 32;
render_data.instances = &p_instances;
@@ -1987,26 +1846,26 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
fb_size.x = p_size[right_axis];
fb_size.y = p_size[up_axis];
- render_data.cam_transform.origin = center + axis * half_extents;
- render_data.cam_transform.basis.set_column(0, right);
- render_data.cam_transform.basis.set_column(1, up);
- render_data.cam_transform.basis.set_column(2, axis);
+ scene_data.cam_transform.origin = center + axis * half_extents;
+ scene_data.cam_transform.basis.set_column(0, right);
+ scene_data.cam_transform.basis.set_column(1, up);
+ scene_data.cam_transform.basis.set_column(2, axis);
- //print_line("pass: " + itos(i) + " xform " + render_data.cam_transform);
+ //print_line("pass: " + itos(i) + " xform " + scene_data.cam_transform);
float h_size = half_extents[right_axis];
float v_size = half_extents[up_axis];
float d_size = half_extents[i] * 2.0;
- render_data.cam_projection.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size);
+ scene_data.cam_projection.set_orthogonal(-h_size, h_size, -v_size, v_size, 0, d_size);
//print_line("pass: " + itos(i) + " cam hsize: " + rtos(h_size) + " vsize: " + rtos(v_size) + " dsize " + rtos(d_size));
Transform3D to_bounds;
to_bounds.origin = p_bounds.position;
to_bounds.basis.scale(p_bounds.size);
- RendererRD::MaterialStorage::store_transform(to_bounds.affine_inverse() * render_data.cam_transform, scene_state.ubo.sdf_to_bounds);
+ RendererRD::MaterialStorage::store_transform(to_bounds.affine_inverse() * scene_data.cam_transform, scene_state.ubo.sdf_to_bounds);
- scene_state.ubo.emissive_exposure_normalization = p_exposure_normalization;
+ scene_data.emissive_exposure_normalization = p_exposure_normalization;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
RID rp_uniform_set = _setup_sdfgi_render_pass_uniform_set(p_albedo_texture, p_emission_texture, p_emission_aniso_texture, p_geom_facing_texture);
@@ -2248,6 +2107,13 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
{
RD::Uniform u;
u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.append_id(scene_state.implementation_uniform_buffers[p_index]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
RID instance_buffer = scene_state.instance_buffer[p_render_list];
if (instance_buffer == RID()) {
@@ -2264,16 +2130,15 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
}
RD::Uniform u;
- u.binding = 2;
+ u.binding = 3;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.append_id(radiance_texture);
uniforms.push_back(u);
}
-
{
RID ref_texture = (p_render_data && p_render_data->reflection_atlas.is_valid()) ? reflection_atlas_get_texture(p_render_data->reflection_atlas) : RID();
RD::Uniform u;
- u.binding = 3;
+ u.binding = 4;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
if (ref_texture.is_valid()) {
u.append_id(ref_texture);
@@ -2282,10 +2147,9 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
uniforms.push_back(u);
}
-
{
RD::Uniform u;
- u.binding = 4;
+ u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture;
if (p_render_data && p_render_data->shadow_atlas.is_valid()) {
@@ -2299,7 +2163,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 5;
+ u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
if (p_use_directional_shadow_atlas && directional_shadow_get_texture().is_valid()) {
u.append_id(directional_shadow_get_texture());
@@ -2310,7 +2174,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 6;
+ u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
@@ -2329,7 +2193,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 7;
+ u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
for (int i = 0; i < MAX_VOXEL_GI_INSTANCESS; i++) {
@@ -2349,7 +2213,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
{
RD::Uniform u;
- u.binding = 8;
+ u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
RID cb = (p_render_data && p_render_data->cluster_buffer.is_valid()) ? p_render_data->cluster_buffer : scene_shader.default_vec4_xform_buffer;
u.append_id(cb);
@@ -2358,7 +2222,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
{
RD::Uniform u;
- u.binding = 9;
+ u.binding = 10;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture;
if (rb.is_valid() && rb->has_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH)) {
@@ -2371,7 +2235,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
RD::Uniform u;
- u.binding = 10;
+ u.binding = 11;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID bbt = rb_data.is_valid() ? rb->get_back_buffer_texture() : RID();
RID texture = bbt.is_valid() ? bbt : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
@@ -2380,110 +2244,108 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
}
{
- {
- RD::Uniform u;
- u.binding = 11;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = rb_data.is_valid() && rb_data->has_normal_roughness() ? rb_data->get_normal_roughness() : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_NORMAL);
- u.append_id(texture);
- uniforms.push_back(u);
- }
+ RD::Uniform u;
+ u.binding = 12;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = rb_data.is_valid() && rb_data->has_normal_roughness() ? rb_data->get_normal_roughness() : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_NORMAL);
+ u.append_id(texture);
+ uniforms.push_back(u);
+ }
- {
- RD::Uniform u;
- u.binding = 12;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID aot = rb_data.is_valid() ? rb->get_ao_texture() : RID();
- RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
- u.append_id(texture);
- uniforms.push_back(u);
- }
+ {
+ RD::Uniform u;
+ u.binding = 13;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID aot = rb_data.is_valid() ? rb->get_ao_texture() : RID();
+ RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ u.append_id(texture);
+ uniforms.push_back(u);
+ }
- {
- RD::Uniform u;
- u.binding = 13;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
- u.append_id(texture);
- uniforms.push_back(u);
- }
+ {
+ RD::Uniform u;
+ u.binding = 14;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ u.append_id(texture);
+ uniforms.push_back(u);
+ }
- {
- RD::Uniform u;
- u.binding = 14;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
- u.append_id(texture);
- uniforms.push_back(u);
+ {
+ RD::Uniform u;
+ u.binding = 15;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ u.append_id(texture);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 16;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID t;
+ if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ t = sdfgi->lightprobe_texture;
}
- {
- RD::Uniform u;
- u.binding = 15;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID t;
- if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
- Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
- t = sdfgi->lightprobe_texture;
- }
- if (t.is_null()) {
- t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
- }
- u.append_id(t);
- uniforms.push_back(u);
+ if (t.is_null()) {
+ t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
}
- {
- RD::Uniform u;
- u.binding = 16;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID t;
- if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
- Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
- t = sdfgi->occlusion_texture;
- }
- if (t.is_null()) {
- t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
- }
- u.append_id(t);
- uniforms.push_back(u);
+ u.append_id(t);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 17;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID t;
+ if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
+ t = sdfgi->occlusion_texture;
}
- {
- RD::Uniform u;
- u.binding = 17;
- u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
- RID voxel_gi;
- if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_GI)) {
- Ref<RendererRD::GI::RenderBuffersGI> rbgi = rb->get_custom_data(RB_SCOPE_GI);
- voxel_gi = rbgi->get_voxel_gi_buffer();
- }
- u.append_id(voxel_gi.is_valid() ? voxel_gi : render_buffers_get_default_voxel_gi_buffer());
- uniforms.push_back(u);
+ if (t.is_null()) {
+ t = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
}
- {
- RD::Uniform u;
- u.binding = 18;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID vfog = RID();
- if (rb_data.is_valid() && rb->has_custom_data(RB_SCOPE_FOG)) {
- Ref<RendererRD::Fog::VolumetricFog> fog = rb->get_custom_data(RB_SCOPE_FOG);
- vfog = fog->fog_map;
- if (vfog.is_null()) {
- vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
- }
- } else {
+ u.append_id(t);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 18;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ RID voxel_gi;
+ if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_GI)) {
+ Ref<RendererRD::GI::RenderBuffersGI> rbgi = rb->get_custom_data(RB_SCOPE_GI);
+ voxel_gi = rbgi->get_voxel_gi_buffer();
+ }
+ u.append_id(voxel_gi.is_valid() ? voxel_gi : render_buffers_get_default_voxel_gi_buffer());
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 19;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID vfog = RID();
+ if (rb_data.is_valid() && rb->has_custom_data(RB_SCOPE_FOG)) {
+ Ref<RendererRD::Fog::VolumetricFog> fog = rb->get_custom_data(RB_SCOPE_FOG);
+ vfog = fog->fog_map;
+ if (vfog.is_null()) {
vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
}
- u.append_id(vfog);
- uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.binding = 19;
- u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID ssil = rb_data.is_valid() ? rb->get_ssil_texture() : RID();
- RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
- u.append_id(texture);
- uniforms.push_back(u);
+ } else {
+ vfog = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
}
+ u.append_id(vfog);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 20;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ RID ssil = rb_data.is_valid() ? rb->get_ssil_texture() : RID();
+ RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ u.append_id(texture);
+ uniforms.push_back(u);
}
return UniformSetCacheRD::get_singleton()->get_cache_vec(scene_shader.default_shader_rd, RENDER_PASS_UNIFORM_SET, uniforms);
@@ -2503,6 +2365,13 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
RD::Uniform u;
u.binding = 1;
+ u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER;
+ u.append_id(scene_state.implementation_uniform_buffers[0]);
+ uniforms.push_back(u);
+ }
+ {
+ RD::Uniform u;
+ u.binding = 2;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
RID instance_buffer = scene_state.instance_buffer[RENDER_LIST_SECONDARY];
if (instance_buffer == RID()) {
@@ -2515,7 +2384,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
// No radiance texture.
RID radiance_texture = texture_storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK);
RD::Uniform u;
- u.binding = 2;
+ u.binding = 3;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.append_id(radiance_texture);
uniforms.push_back(u);
@@ -2525,7 +2394,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
// No reflection atlas.
RID ref_texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK);
RD::Uniform u;
- u.binding = 3;
+ u.binding = 4;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
u.append_id(ref_texture);
uniforms.push_back(u);
@@ -2534,7 +2403,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
// No shadow atlas.
RD::Uniform u;
- u.binding = 4;
+ u.binding = 5;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
u.append_id(texture);
@@ -2544,7 +2413,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
// No directional shadow atlas.
RD::Uniform u;
- u.binding = 5;
+ u.binding = 6;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
u.append_id(texture);
@@ -2554,7 +2423,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
// No Lightmaps
RD::Uniform u;
- u.binding = 6;
+ u.binding = 7;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE);
@@ -2568,7 +2437,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
// No VoxelGIs
RD::Uniform u;
- u.binding = 7;
+ u.binding = 8;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID default_tex = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_3D_WHITE);
@@ -2581,7 +2450,7 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
RD::Uniform u;
- u.binding = 8;
+ u.binding = 9;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
RID cb = scene_shader.default_vec4_xform_buffer;
u.append_id(cb);
@@ -2593,28 +2462,28 @@ RID RenderForwardClustered::_setup_sdfgi_render_pass_uniform_set(RID p_albedo_te
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 9;
+ u.binding = 10;
u.append_id(p_albedo_texture);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 10;
+ u.binding = 11;
u.append_id(p_emission_texture);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 11;
+ u.binding = 12;
u.append_id(p_emission_aniso_texture);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = 12;
+ u.binding = 13;
u.append_id(p_geom_facing_texture);
uniforms.push_back(u);
}
@@ -2925,6 +2794,7 @@ void RenderForwardClustered::_geometry_instance_update(RenderGeometryInstance *p
ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_shader.default_shader_rd, TRANSFORMS_UNIFORM_SET);
} else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_PARTICLES;
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
@@ -3195,6 +3065,9 @@ RenderForwardClustered::~RenderForwardClustered() {
for (uint32_t i = 0; i < scene_state.uniform_buffers.size(); i++) {
RD::get_singleton()->free(scene_state.uniform_buffers[i]);
}
+ for (uint32_t i = 0; i < scene_state.implementation_uniform_buffers.size(); i++) {
+ RD::get_singleton()->free(scene_state.implementation_uniform_buffers[i]);
+ }
RD::get_singleton()->free(scene_state.lightmap_buffer);
RD::get_singleton()->free(scene_state.lightmap_capture_buffer);
for (uint32_t i = 0; i < RENDER_LIST_MAX; i++) {
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index 35379cd69b..16f6da34f8 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -37,7 +37,7 @@
#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
-#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/utilities.h"
#define RB_SCOPE_FORWARD_CLUSTERED SNAME("forward_clustered")
@@ -231,13 +231,14 @@ class RenderForwardClustered : public RendererSceneRenderRD {
};
enum {
- INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5,
- INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6,
- INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7,
- INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
- INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
- INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
- INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11,
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
+ INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
+ INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 6,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 8,
+ INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 9,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 10,
+ INSTANCE_DATA_FLAG_PARTICLES = 1 << 11,
INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
@@ -249,61 +250,22 @@ class RenderForwardClustered : public RendererSceneRenderRD {
};
struct SceneState {
- // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code
+ // This struct is loaded into Set 1 - Binding 1, populated at start of rendering a frame, must match with shader code
struct UBO {
- float projection_matrix[16];
- float inv_projection_matrix[16];
- float inv_view_matrix[16];
- float view_matrix[16];
-
- float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
- float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
- float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4];
-
- float viewport_size[2];
- float screen_pixel_size[2];
-
uint32_t cluster_shift;
uint32_t cluster_width;
uint32_t cluster_type_size;
uint32_t max_cluster_element_count_div_32;
- float directional_penumbra_shadow_kernel[128]; //32 vec4s
- float directional_soft_shadow_kernel[128];
- float penumbra_shadow_kernel[128];
- float soft_shadow_kernel[128];
-
- float ambient_light_color_energy[4];
-
- float ambient_color_sky_mix;
- uint32_t use_ambient_light;
- uint32_t use_ambient_cubemap;
- uint32_t use_reflection_cubemap;
-
- float radiance_inverse_xform[12];
-
- float shadow_atlas_pixel_size[2];
- float directional_shadow_pixel_size[2];
-
- uint32_t directional_light_count;
- float dual_paraboloid_side;
- float z_far;
- float z_near;
-
uint32_t ss_effects_flags;
float ssao_light_affect;
float ssao_ao_affect;
- uint32_t roughness_limiter_enabled;
-
- float roughness_limiter_amount;
- float roughness_limiter_limit;
- float opaque_prepass_threshold;
- uint32_t roughness_limiter_pad;
+ uint32_t pad1;
float sdf_to_bounds[16];
int32_t sdf_offset[3];
- uint32_t material_uv2_mode;
+ uint32_t pad2;
int32_t sdf_size[3];
uint32_t gi_upscale_for_msaa;
@@ -312,32 +274,13 @@ class RenderForwardClustered : public RendererSceneRenderRD {
float volumetric_fog_inv_length;
float volumetric_fog_detail_spread;
uint32_t volumetric_fog_pad;
-
- // Fog
- uint32_t fog_enabled;
- float fog_density;
- float fog_height;
- float fog_height_density;
-
- float fog_light_color[3];
- float fog_sun_scatter;
-
- float fog_aerial_perspective;
-
- float time;
- float reflection_multiplier;
-
- uint32_t pancake_shadows;
-
- float taa_jitter[2];
- float emissive_exposure_normalization; // Needed to normalize emissive when using physical units.
- float IBL_exposure_normalization;
};
struct PushConstant {
uint32_t base_index; //
uint32_t uv_offset; //packed
- uint32_t pad[2];
+ uint32_t multimesh_motion_vectors_current_offset;
+ uint32_t multimesh_motion_vectors_previous_offset;
};
struct InstanceData {
@@ -350,11 +293,10 @@ class RenderForwardClustered : public RendererSceneRenderRD {
float lightmap_uv_scale[4];
};
- UBO ubo_data[2];
- UBO &ubo = ubo_data[0];
- UBO &prev_ubo = ubo_data[1];
+ UBO ubo;
LocalVector<RID> uniform_buffers;
+ LocalVector<RID> implementation_uniform_buffers;
LightmapData lightmaps[MAX_LIGHTMAPS];
RID lightmap_ids[MAX_LIGHTMAPS];
@@ -429,7 +371,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
void _update_instance_data_buffer(RenderListType p_render_list);
void _fill_instance_data(RenderListType p_render_list, int *p_render_info = nullptr, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
- void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, bool p_append = false);
+ void _fill_render_list(RenderListType p_render_list, const RenderDataRD *p_render_data, PassMode p_pass_mode, uint32_t p_color_pass_flags, bool p_using_sdfgi = false, bool p_using_opaque_gi = false, bool p_append = false);
HashMap<Size2i, RID> sdfgi_framebuffer_size_cache;
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
index c2f56eb164..a9a9fa94de 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -32,7 +32,7 @@
#define SCENE_SHADER_FORWARD_CLUSTERED_H
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
-#include "servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl.gen.h"
namespace RendererSceneRenderImplementation {
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 46d90e75fb..a6512497a3 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -504,8 +504,20 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RENDER_TIMESTAMP("Setup 3D Scene");
- scene_state.ubo.directional_light_count = 0;
- scene_state.ubo.opaque_prepass_threshold = 0.0;
+ /* TODO
+ // check if we need motion vectors
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_MOTION_VECTORS) {
+ p_render_data->scene_data->calculate_motion_vectors = true;
+ } else if (render target has velocity override) { // TODO
+ p_render_data->scene_data->calculate_motion_vectors = true;
+ } else {
+ p_render_data->scene_data->calculate_motion_vectors = false;
+ }
+ */
+ p_render_data->scene_data->calculate_motion_vectors = false; // for now, not yet supported...
+
+ p_render_data->scene_data->directional_light_count = 0;
+ p_render_data->scene_data->opaque_prepass_threshold = 0.0;
// We can only use our full subpass approach if we're:
// - not reading from SCREEN_TEXTURE/DEPTH_TEXTURE
@@ -581,13 +593,11 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
ERR_FAIL(); //bug?
}
- scene_state.ubo.viewport_size[0] = screen_size.x;
- scene_state.ubo.viewport_size[1] = screen_size.y;
- scene_state.ubo.emissive_exposure_normalization = -1.0;
+ p_render_data->scene_data->emissive_exposure_normalization = -1.0;
RD::get_singleton()->draw_command_begin_label("Render Setup");
- _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->cam_transform);
+ _setup_lightmaps(p_render_data, *p_render_data->lightmaps, p_render_data->scene_data->cam_transform);
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
_update_render_base_uniform_set(); //may have changed due to the above (light buffer enlarged, as an example)
@@ -658,20 +668,20 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (draw_sky || draw_sky_fog_only || environment_get_reflection_source(p_render_data->environment) == RS::ENV_REFLECTION_SOURCE_SKY || environment_get_ambient_source(p_render_data->environment) == RS::ENV_AMBIENT_SOURCE_SKY) {
RENDER_TIMESTAMP("Setup Sky");
RD::get_singleton()->draw_command_begin_label("Setup Sky");
- Projection projection = p_render_data->cam_projection;
+ Projection projection = p_render_data->scene_data->cam_projection;
if (p_render_data->reflection_probe.is_valid()) {
Projection correction;
correction.set_depth_correction(true);
- projection = correction * p_render_data->cam_projection;
+ projection = correction * p_render_data->scene_data->cam_projection;
}
- sky.setup(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->cam_transform, screen_size, this);
+ sky.setup(p_render_data->environment, p_render_data->render_buffers, *p_render_data->lights, p_render_data->camera_attributes, projection, p_render_data->scene_data->cam_transform, screen_size, this);
sky_energy_multiplier *= bg_energy_multiplier;
RID sky_rid = environment_get_sky(p_render_data->environment);
if (sky_rid.is_valid()) {
- sky.update(p_render_data->environment, projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ sky.update(p_render_data->environment, projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
radiance_texture = sky.sky_get_radiance_texture_rd(sky_rid);
} else {
// do not try to draw sky if invalid
@@ -694,10 +704,10 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (p_render_data->reflection_probe.is_valid()) {
Projection correction;
correction.set_depth_correction(true);
- Projection projection = correction * p_render_data->cam_projection;
- sky.update_res_buffers(p_render_data->environment, 1, &projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ Projection projection = correction * p_render_data->scene_data->cam_projection;
+ sky.update_res_buffers(p_render_data->environment, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
} else {
- sky.update_res_buffers(p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ sky.update_res_buffers(p_render_data->environment, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
}
RD::get_singleton()->draw_command_end_label(); // Setup Sky resolution buffers
@@ -734,7 +744,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
RD::get_singleton()->draw_command_begin_label("Render Opaque Subpass");
- scene_state.ubo.directional_light_count = p_render_data->directional_light_count;
+ p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count;
_setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid());
@@ -765,7 +775,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
render_list_params.framebuffer_format = fb_format;
if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
// secondary command buffers need more testing at this time
@@ -793,10 +803,10 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (p_render_data->reflection_probe.is_valid()) {
Projection correction;
correction.set_depth_correction(true);
- Projection projection = correction * p_render_data->cam_projection;
- sky.draw(draw_list, p_render_data->environment, framebuffer, 1, &projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ Projection projection = correction * p_render_data->scene_data->cam_projection;
+ sky.draw(draw_list, p_render_data->environment, framebuffer, 1, &projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
} else {
- sky.draw(draw_list, p_render_data->environment, framebuffer, p_render_data->view_count, p_render_data->view_projection, p_render_data->cam_transform, time, sky_energy_multiplier);
+ sky.draw(draw_list, p_render_data->environment, framebuffer, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->cam_transform, time, sky_energy_multiplier);
}
RD::get_singleton()->draw_command_end_label(); // Draw Sky Subpass
@@ -832,7 +842,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (using_subpass_transparent) {
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR_TRANSPARENT, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR_TRANSPARENT, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
render_list_params.framebuffer_format = fb_format;
if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
// secondary command buffers need more testing at this time
@@ -871,7 +881,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false);
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
- RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, p_render_data->view_count);
+ RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_camera_plane, p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count);
render_list_params.framebuffer_format = fb_format;
if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) {
// secondary command buffers need more testing at this time
@@ -928,26 +938,29 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME] = p_instances.size();
p_render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_OBJECTS_IN_FRAME] = p_instances.size();
}
+
+ RenderSceneDataRD scene_data;
+ scene_data.cam_projection = p_projection;
+ scene_data.cam_transform = p_transform;
+ scene_data.view_projection[0] = p_projection;
+ scene_data.z_near = 0.0;
+ scene_data.z_far = p_zfar;
+ scene_data.lod_camera_plane = p_camera_plane;
+ scene_data.lod_distance_multiplier = p_lod_distance_multiplier;
+ scene_data.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
+ scene_data.opaque_prepass_threshold = 0.1;
+
RenderDataRD render_data;
- render_data.cam_projection = p_projection;
- render_data.cam_transform = p_transform;
- render_data.view_projection[0] = p_projection;
- render_data.z_near = 0.0;
- render_data.z_far = p_zfar;
+ render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
render_data.render_info = p_render_info;
- render_data.lod_camera_plane = p_camera_plane;
- render_data.lod_distance_multiplier = p_lod_distance_multiplier;
-
- scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1;
- scene_state.ubo.opaque_prepass_threshold = 0.1;
_setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index);
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
- render_data.screen_mesh_lod_threshold = 0.0;
+ scene_data.screen_mesh_lod_threshold = 0.0;
} else {
- render_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
+ scene_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
}
PassMode pass_mode = p_use_dp ? PASS_MODE_SHADOW_DP : PASS_MODE_SHADOW;
@@ -972,8 +985,8 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr
shadow_pass.rp_uniform_set = RID(); //will be filled later when instance buffer is complete
shadow_pass.camera_plane = p_camera_plane;
- shadow_pass.screen_mesh_lod_threshold = render_data.screen_mesh_lod_threshold;
- shadow_pass.lod_distance_multiplier = render_data.lod_distance_multiplier;
+ shadow_pass.screen_mesh_lod_threshold = scene_data.screen_mesh_lod_threshold;
+ shadow_pass.lod_distance_multiplier = scene_data.lod_distance_multiplier;
shadow_pass.framebuffer = p_framebuffer;
shadow_pass.initial_depth_action = p_begin ? (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION : RD::INITIAL_ACTION_CLEAR) : (p_clear_region ? RD::INITIAL_ACTION_CLEAR_REGION_CONTINUE : RD::INITIAL_ACTION_CONTINUE);
@@ -1020,15 +1033,17 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
_update_render_base_uniform_set();
- scene_state.ubo.dual_paraboloid_side = 0;
- scene_state.ubo.material_uv2_mode = false;
- scene_state.ubo.opaque_prepass_threshold = 0.0f;
- scene_state.ubo.emissive_exposure_normalization = p_exposure_normalization;
+ RenderSceneDataRD scene_data;
+ scene_data.cam_projection = p_cam_projection;
+ scene_data.cam_transform = p_cam_transform;
+ scene_data.view_projection[0] = p_cam_projection;
+ scene_data.dual_paraboloid_side = 0;
+ scene_data.material_uv2_mode = false;
+ scene_data.opaque_prepass_threshold = 0.0f;
+ scene_data.emissive_exposure_normalization = p_exposure_normalization;
RenderDataRD render_data;
- render_data.cam_projection = p_cam_projection;
- render_data.cam_transform = p_cam_transform;
- render_data.view_projection[0] = p_cam_projection;
+ render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -1067,11 +1082,13 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
_update_render_base_uniform_set();
- scene_state.ubo.dual_paraboloid_side = 0;
- scene_state.ubo.material_uv2_mode = true;
- scene_state.ubo.emissive_exposure_normalization = -1.0;
+ RenderSceneDataRD scene_data;
+ scene_data.dual_paraboloid_side = 0;
+ scene_data.material_uv2_mode = true;
+ scene_data.emissive_exposure_normalization = -1.0;
RenderDataRD render_data;
+ render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
_setup_environment(&render_data, true, Vector2(1, 1), false, Color());
@@ -1138,15 +1155,18 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const
RD::get_singleton()->draw_command_begin_label("Render Collider Heightfield");
_update_render_base_uniform_set();
- scene_state.ubo.dual_paraboloid_side = 0;
- scene_state.ubo.opaque_prepass_threshold = 0.0;
+
+ RenderSceneDataRD scene_data;
+ scene_data.cam_projection = p_cam_projection;
+ scene_data.cam_transform = p_cam_transform;
+ scene_data.view_projection[0] = p_cam_projection;
+ scene_data.z_near = 0.0;
+ scene_data.z_far = p_cam_projection.get_z_far();
+ scene_data.dual_paraboloid_side = 0;
+ scene_data.opaque_prepass_threshold = 0.0;
RenderDataRD render_data;
- render_data.cam_projection = p_cam_projection;
- render_data.cam_transform = p_cam_transform;
- render_data.view_projection[0] = p_cam_projection;
- render_data.z_near = 0.0;
- render_data.z_far = p_cam_projection.get_z_far();
+ render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
_setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false);
@@ -1385,9 +1405,9 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
}
uint32_t lightmap_captures_used = 0;
- Plane near_plane(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->cam_transform.origin);
- near_plane.d += p_render_data->cam_projection.get_z_near();
- float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near();
+ Plane near_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin);
+ near_plane.d += p_render_data->scene_data->cam_projection.get_z_near();
+ float z_max = p_render_data->scene_data->cam_projection.get_z_far() - p_render_data->scene_data->cam_projection.get_z_near();
RenderList *rl = &render_list[p_render_list];
@@ -1466,13 +1486,13 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
// LOD
- if (p_render_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
+ if (p_render_data->scene_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
//lod
- Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal);
- Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal);
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->scene_data->lod_camera_plane.normal);
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->scene_data->lod_camera_plane.normal);
- float distance_min = p_render_data->lod_camera_plane.distance_to(lod_support_min);
- float distance_max = p_render_data->lod_camera_plane.distance_to(lod_support_max);
+ float distance_min = p_render_data->scene_data->lod_camera_plane.distance_to(lod_support_min);
+ float distance_max = p_render_data->scene_data->lod_camera_plane.distance_to(lod_support_max);
float distance = 0.0;
@@ -1485,12 +1505,12 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
distance = -distance_max;
}
- if (p_render_data->cam_orthogonal) {
+ if (p_render_data->scene_data->cam_orthogonal) {
distance = 1.0;
}
uint32_t indices;
- surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices);
+ surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, &indices);
if (p_render_data->render_info) {
indices = _indices_to_primitives(surf->primitive, indices);
if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
@@ -1562,184 +1582,20 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const
}
void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_opaque_render_buffers, bool p_pancake_shadows, int p_index) {
- //!BAS! need to go through this and find out what we don't need anymore
-
- // This populates our UBO with main scene data that is pushed into set 1
-
- //Projection projection = p_render_data->cam_projection;
- //projection.flip_y(); // Vulkan and modern APIs use Y-Down
- Projection correction;
- correction.set_depth_correction(p_flip_y);
- Projection projection = correction * p_render_data->cam_projection;
-
- //store camera into ubo
- RendererRD::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix);
- RendererRD::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
- RendererRD::MaterialStorage::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix);
- RendererRD::MaterialStorage::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.view_matrix);
-
- for (uint32_t v = 0; v < p_render_data->view_count; v++) {
- projection = correction * p_render_data->view_projection[v];
- RendererRD::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix_view[v]);
- RendererRD::MaterialStorage::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix_view[v]);
-
- scene_state.ubo.eye_offset[v][0] = p_render_data->view_eye_offset[v].x;
- scene_state.ubo.eye_offset[v][1] = p_render_data->view_eye_offset[v].y;
- scene_state.ubo.eye_offset[v][2] = p_render_data->view_eye_offset[v].z;
- scene_state.ubo.eye_offset[v][3] = 0.0;
- }
-
- scene_state.ubo.z_far = p_render_data->z_far;
- scene_state.ubo.z_near = p_render_data->z_near;
-
- scene_state.ubo.pancake_shadows = p_pancake_shadows;
-
- RendererRD::MaterialStorage::store_soft_shadow_kernel(directional_penumbra_shadow_kernel_get(), scene_state.ubo.directional_penumbra_shadow_kernel);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(directional_soft_shadow_kernel_get(), scene_state.ubo.directional_soft_shadow_kernel);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(penumbra_shadow_kernel_get(), scene_state.ubo.penumbra_shadow_kernel);
- RendererRD::MaterialStorage::store_soft_shadow_kernel(soft_shadow_kernel_get(), scene_state.ubo.soft_shadow_kernel);
-
- Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
- scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
- scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
-
- if (p_render_data->shadow_atlas.is_valid()) {
- Vector2 sas = shadow_atlas_get_size(p_render_data->shadow_atlas);
- scene_state.ubo.shadow_atlas_pixel_size[0] = 1.0 / sas.x;
- scene_state.ubo.shadow_atlas_pixel_size[1] = 1.0 / sas.y;
- }
- {
- Vector2 dss = directional_shadow_get_size();
- scene_state.ubo.directional_shadow_pixel_size[0] = 1.0 / dss.x;
- scene_state.ubo.directional_shadow_pixel_size[1] = 1.0 / dss.y;
- }
-
- //time global variables
- scene_state.ubo.time = time;
-
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
- scene_state.ubo.use_ambient_light = true;
- scene_state.ubo.ambient_light_color_energy[0] = 1;
- scene_state.ubo.ambient_light_color_energy[1] = 1;
- scene_state.ubo.ambient_light_color_energy[2] = 1;
- scene_state.ubo.ambient_light_color_energy[3] = 1.0;
- scene_state.ubo.use_ambient_cubemap = false;
- scene_state.ubo.use_reflection_cubemap = false;
- scene_state.ubo.ssao_enabled = false;
-
- } else if (is_environment(p_render_data->environment)) {
- RS::EnvironmentBG env_bg = environment_get_background(p_render_data->environment);
- RS::EnvironmentAmbientSource ambient_src = environment_get_ambient_source(p_render_data->environment);
-
- float bg_energy_multiplier = environment_get_bg_energy_multiplier(p_render_data->environment);
-
- scene_state.ubo.ambient_light_color_energy[3] = bg_energy_multiplier;
-
- scene_state.ubo.ambient_color_sky_mix = environment_get_ambient_sky_contribution(p_render_data->environment);
-
- //ambient
- if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
- Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : environment_get_bg_color(p_render_data->environment);
- color = color.srgb_to_linear();
-
- scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier;
- scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier;
- scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier;
- scene_state.ubo.use_ambient_light = true;
- scene_state.ubo.use_ambient_cubemap = false;
- } else {
- float energy = environment_get_ambient_light_energy(p_render_data->environment);
- Color color = environment_get_ambient_light(p_render_data->environment);
- color = color.srgb_to_linear();
- scene_state.ubo.ambient_light_color_energy[0] = color.r * energy;
- scene_state.ubo.ambient_light_color_energy[1] = color.g * energy;
- scene_state.ubo.ambient_light_color_energy[2] = color.b * energy;
-
- Basis sky_transform = environment_get_sky_orientation(p_render_data->environment);
- sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis;
- RendererRD::MaterialStorage::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
-
- scene_state.ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
- scene_state.ubo.use_ambient_light = scene_state.ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
- }
-
- //specular
- RS::EnvironmentReflectionSource ref_src = environment_get_reflection_source(p_render_data->environment);
- if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) {
- scene_state.ubo.use_reflection_cubemap = true;
- } else {
- scene_state.ubo.use_reflection_cubemap = false;
- }
-
- scene_state.ubo.ssao_enabled = p_opaque_render_buffers && environment_get_ssao_enabled(p_render_data->environment);
- scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_channel_affect(p_render_data->environment);
- scene_state.ubo.ssao_light_affect = environment_get_ssao_direct_light_affect(p_render_data->environment);
-
- scene_state.ubo.fog_enabled = environment_get_fog_enabled(p_render_data->environment);
- scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment);
- scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment);
- scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment);
- scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment);
-
- Color fog_color = environment_get_fog_light_color(p_render_data->environment).srgb_to_linear();
- float fog_energy = environment_get_fog_light_energy(p_render_data->environment);
-
- scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
- scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
- scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
-
- scene_state.ubo.fog_sun_scatter = environment_get_fog_sun_scatter(p_render_data->environment);
-
- } else {
- if (p_render_data->reflection_probe.is_valid() && RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(reflection_probe_instance_get_probe(p_render_data->reflection_probe))) {
- scene_state.ubo.use_ambient_light = false;
- } else {
- scene_state.ubo.use_ambient_light = true;
- Color clear_color = p_default_bg_color;
- clear_color = clear_color.srgb_to_linear();
- scene_state.ubo.ambient_light_color_energy[0] = clear_color.r;
- scene_state.ubo.ambient_light_color_energy[1] = clear_color.g;
- scene_state.ubo.ambient_light_color_energy[2] = clear_color.b;
- scene_state.ubo.ambient_light_color_energy[3] = 1.0;
- }
-
- scene_state.ubo.use_ambient_cubemap = false;
- scene_state.ubo.use_reflection_cubemap = false;
- scene_state.ubo.ssao_enabled = false;
- }
-
- if (p_render_data->camera_attributes.is_valid()) {
- scene_state.ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes);
- scene_state.ubo.IBL_exposure_normalization = 1.0;
- if (is_environment(p_render_data->environment)) {
- RID sky_rid = environment_get_sky(p_render_data->environment);
- if (sky_rid.is_valid()) {
- float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_render_data->camera_attributes) * environment_get_bg_intensity(p_render_data->environment) / _render_buffers_get_luminance_multiplier();
- scene_state.ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, sky.sky_get_baked_exposure(sky_rid));
- }
- }
- } else if (scene_state.ubo.emissive_exposure_normalization > 0.0) {
- // This branch is triggered when using render_material().
- // Emissive is set outside the function, so don't set it.
- // IBL isn't used don't set it.
- } else {
- scene_state.ubo.emissive_exposure_normalization = 1.0;
- scene_state.ubo.IBL_exposure_normalization = 1.0;
- }
-
- scene_state.ubo.roughness_limiter_enabled = p_opaque_render_buffers && screen_space_roughness_limiter_is_active();
- scene_state.ubo.roughness_limiter_amount = screen_space_roughness_limiter_get_amount();
- scene_state.ubo.roughness_limiter_limit = screen_space_roughness_limiter_get_limit();
+ Ref<RenderSceneBuffersRD> rd = p_render_data->render_buffers;
+ RID env = is_environment(p_render_data->environment) ? p_render_data->environment : RID();
+ RID reflection_probe_instance = p_render_data->reflection_probe.is_valid() ? reflection_probe_instance_get_probe(p_render_data->reflection_probe) : RID();
+ // May do this earlier in RenderSceneRenderRD::render_scene
if (p_index >= (int)scene_state.uniform_buffers.size()) {
uint32_t from = scene_state.uniform_buffers.size();
scene_state.uniform_buffers.resize(p_index + 1);
- render_pass_uniform_sets.resize(p_index + 1);
for (uint32_t i = from; i < scene_state.uniform_buffers.size(); i++) {
- scene_state.uniform_buffers[i] = RD::get_singleton()->uniform_buffer_create(sizeof(SceneState::UBO));
+ scene_state.uniform_buffers[i] = p_render_data->scene_data->create_uniform_buffer();
}
}
- RD::get_singleton()->buffer_update(scene_state.uniform_buffers[p_index], 0, sizeof(SceneState::UBO), &scene_state.ubo, RD::BARRIER_MASK_RASTER);
+
+ p_render_data->scene_data->update_ubo(scene_state.uniform_buffers[p_index], get_debug_draw_mode(), env, reflection_probe_instance, p_render_data->camera_attributes, p_flip_y, p_pancake_shadows, p_screen_size, p_default_bg_color, _render_buffers_get_luminance_multiplier(), p_opaque_render_buffers);
}
void RenderForwardMobile::_fill_element_info(RenderListType p_render_list, uint32_t p_offset, int32_t p_max_elements) {
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index da1cd85fb3..04b2b3ce18 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -252,75 +252,6 @@ protected:
/* Scene state */
struct SceneState {
- // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code
- struct UBO {
- float projection_matrix[16];
- float inv_projection_matrix[16];
- float inv_view_matrix[16];
- float view_matrix[16];
-
- float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
- float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
- float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4];
-
- float viewport_size[2];
- float screen_pixel_size[2];
-
- float directional_penumbra_shadow_kernel[128]; //32 vec4s
- float directional_soft_shadow_kernel[128];
- float penumbra_shadow_kernel[128];
- float soft_shadow_kernel[128];
-
- float ambient_light_color_energy[4];
-
- float ambient_color_sky_mix;
- uint32_t use_ambient_light;
- uint32_t use_ambient_cubemap;
- uint32_t use_reflection_cubemap;
-
- float radiance_inverse_xform[12];
-
- float shadow_atlas_pixel_size[2];
- float directional_shadow_pixel_size[2];
-
- uint32_t directional_light_count;
- float dual_paraboloid_side;
- float z_far;
- float z_near;
-
- uint32_t ssao_enabled;
- float ssao_light_affect;
- float ssao_ao_affect;
- uint32_t roughness_limiter_enabled;
-
- float roughness_limiter_amount;
- float roughness_limiter_limit;
- float opaque_prepass_threshold;
- uint32_t roughness_limiter_pad;
-
- // Fog
- uint32_t fog_enabled;
- float fog_density;
- float fog_height;
- float fog_height_density;
-
- float fog_light_color[3];
- float fog_sun_scatter;
-
- float fog_aerial_perspective;
- uint32_t material_uv2_mode;
-
- float time;
- float reflection_multiplier;
-
- uint32_t pancake_shadows;
- float emissive_exposure_normalization; // Needed to normalize emissive when using physical units.
- float IBL_exposure_normalization; // Adjusts for baked exposure.
- uint32_t pad3;
- };
-
- UBO ubo;
-
LocalVector<RID> uniform_buffers;
// !BAS! We need to change lightmaps, we're not going to do this with a buffer but pushing the used lightmap in
@@ -442,13 +373,14 @@ protected:
// check which ones of these apply, probably all except GI and SDFGI
enum {
- INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5,
- INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6,
- INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 7,
- INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
- INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
- INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
- INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11,
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
+ INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
+ INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 6,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 8,
+ INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 9,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 10,
+ INSTANCE_DATA_FLAG_PARTICLES = 1 << 11,
INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index 21270d7c62..f67665a02f 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -32,7 +32,7 @@
#define SCENE_SHADER_FORWARD_MOBILE_H
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
-#include "servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl.gen.h"
namespace RendererSceneRenderImplementation {
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index ab3e3ebe51..0210151420 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -1362,9 +1362,12 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
default_repeat = p_default_repeat;
}
- //fill the list until rendering is possible.
- bool material_screen_texture_found = false;
Item *ci = p_item_list;
+
+ //fill the list until rendering is possible.
+ bool material_screen_texture_cached = false;
+ bool material_screen_texture_mipmaps_cached = false;
+
Rect2 back_buffer_rect;
bool backbuffer_copy = false;
bool backbuffer_gen_mipmaps = false;
@@ -1393,10 +1396,12 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
CanvasMaterialData *md = static_cast<CanvasMaterialData *>(material_storage->material_get_data(material, RendererRD::MaterialStorage::SHADER_TYPE_2D));
if (md && md->shader_data->valid) {
if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) {
- if (!material_screen_texture_found) {
+ if (!material_screen_texture_cached) {
backbuffer_copy = true;
back_buffer_rect = Rect2();
backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps;
+ } else if (!material_screen_texture_mipmaps_cached) {
+ backbuffer_gen_mipmaps = md->shader_data->uses_screen_texture_mipmaps;
}
}
@@ -1486,7 +1491,15 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
backbuffer_copy = false;
backbuffer_gen_mipmaps = false;
- material_screen_texture_found = true; //after a backbuffer copy, screen texture makes no further copies
+ material_screen_texture_cached = true; // After a backbuffer copy, screen texture makes no further copies.
+ material_screen_texture_mipmaps_cached = backbuffer_gen_mipmaps;
+ }
+
+ if (backbuffer_gen_mipmaps) {
+ texture_storage->render_target_gen_back_buffer_mipmaps(p_to_render_target, back_buffer_rect);
+
+ backbuffer_gen_mipmaps = false;
+ material_screen_texture_mipmaps_cached = true;
}
items[item_count++] = ci;
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index e2b06bc92f..7841e36244 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -1492,7 +1492,7 @@ void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataR
bool can_use_storage = _render_buffers_can_be_storage();
Size2i size = rb->get_internal_size();
- for (uint32_t v = 0; v < p_render_data->view_count; v++) {
+ for (uint32_t v = 0; v < p_render_data->scene_data->view_count; v++) {
RID depth_texture = rb->get_depth_texture(v);
RID depth_back_texture = rb->get_texture_slice(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH, v, 0);
@@ -1544,9 +1544,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
buffers.depth_texture = rb->get_depth_texture(i);
// In stereo p_render_data->z_near and p_render_data->z_far can be offset for our combined frustrum
- float z_near = p_render_data->view_projection[i].get_z_near();
- float z_far = p_render_data->view_projection[i].get_z_far();
- bokeh_dof->bokeh_dof_compute(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->cam_orthogonal);
+ float z_near = p_render_data->scene_data->view_projection[i].get_z_near();
+ float z_far = p_render_data->scene_data->view_projection[i].get_z_far();
+ bokeh_dof->bokeh_dof_compute(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->scene_data->cam_orthogonal);
};
} else {
// Set framebuffers.
@@ -1567,9 +1567,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
buffers.base_fb = FramebufferCacheRD::get_singleton()->get_cache(buffers.base_texture); // TODO move this into bokeh_dof_raster, we can do this internally
// In stereo p_render_data->z_near and p_render_data->z_far can be offset for our combined frustrum
- float z_near = p_render_data->view_projection[i].get_z_near();
- float z_far = p_render_data->view_projection[i].get_z_far();
- bokeh_dof->bokeh_dof_raster(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->cam_orthogonal);
+ float z_near = p_render_data->scene_data->view_projection[i].get_z_near();
+ float z_far = p_render_data->scene_data->view_projection[i].get_z_far();
+ bokeh_dof->bokeh_dof_raster(buffers, p_render_data->camera_attributes, z_near, z_far, p_render_data->scene_data->cam_orthogonal);
}
}
RD::get_singleton()->draw_command_end_label();
@@ -2901,8 +2901,8 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
render_state.shadows.clear();
render_state.directional_shadows.clear();
- Plane camera_plane(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->cam_transform.origin);
- float lod_distance_multiplier = p_render_data->cam_projection.get_lod_multiplier();
+ Plane camera_plane(-p_render_data->scene_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->scene_data->cam_transform.origin);
+ float lod_distance_multiplier = p_render_data->scene_data->cam_projection.get_lod_multiplier();
{
for (int i = 0; i < render_state.render_shadow_count; i++) {
LightInstance *li = light_instance_owner.get_or_null(render_state.render_shadows[i].light);
@@ -2918,7 +2918,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//cube shadows are rendered in their own way
for (uint32_t i = 0; i < render_state.cube_shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info);
+ _render_shadow_pass(render_state.render_shadows[render_state.cube_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.cube_shadows[i]].pass, render_state.render_shadows[render_state.cube_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info);
}
if (render_state.directional_shadows.size()) {
@@ -2948,11 +2948,11 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//render directional shadows
for (uint32_t i = 0; i < render_state.directional_shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false, p_render_data->render_info);
+ _render_shadow_pass(render_state.render_shadows[render_state.directional_shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.directional_shadows[i]].pass, render_state.render_shadows[render_state.directional_shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, false, i == render_state.directional_shadows.size() - 1, false, p_render_data->render_info);
}
//render positional shadows
for (uint32_t i = 0; i < render_state.shadows.size(); i++) {
- _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true, p_render_data->render_info);
+ _render_shadow_pass(render_state.render_shadows[render_state.shadows[i]].light, p_render_data->shadow_atlas, render_state.render_shadows[render_state.shadows[i]].pass, render_state.render_shadows[render_state.shadows[i]].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, i == 0, i == render_state.shadows.size() - 1, true, p_render_data->render_info);
}
_render_shadow_process();
@@ -2960,7 +2960,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
//start GI
if (render_gi) {
- gi.process_gi(p_render_data->render_buffers, p_normal_roughness_slices, p_voxel_gi_buffer, p_render_data->environment, p_render_data->view_count, p_render_data->view_projection, p_render_data->view_eye_offset, p_render_data->cam_transform, *p_render_data->voxel_gi_instances);
+ gi.process_gi(p_render_data->render_buffers, p_normal_roughness_slices, p_voxel_gi_buffer, p_render_data->environment, p_render_data->scene_data->view_count, p_render_data->scene_data->view_projection, p_render_data->scene_data->view_eye_offset, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances);
}
//Do shadow rendering (in parallel with GI)
@@ -2999,17 +2999,17 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
}
RID depth_texture = rb->get_depth_texture();
- ss_effects->downsample_depth(depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, size, p_render_data->cam_projection);
+ ss_effects->downsample_depth(depth_texture, rb->ss_effects.linear_depth_slices, ssao_quality, ssil_quality, invalidate_uniform_set, ssao_half_size, ssil_half_size, size, p_render_data->scene_data->cam_projection);
}
if (p_use_ssao) {
// TODO make these proper stereo
- _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->cam_projection);
+ _process_ssao(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection);
}
if (p_use_ssil) {
// TODO make these proper stereo
- _process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->cam_projection, p_render_data->cam_transform);
+ _process_ssil(p_render_data->render_buffers, p_render_data->environment, p_normal_roughness_slices[0], p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform);
}
}
@@ -3017,7 +3017,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
RD::get_singleton()->barrier(RD::BARRIER_MASK_ALL, RD::BARRIER_MASK_ALL);
if (current_cluster_builder) {
- current_cluster_builder->begin(p_render_data->cam_transform, p_render_data->cam_projection, !p_render_data->reflection_probe.is_valid());
+ current_cluster_builder->begin(p_render_data->scene_data->cam_transform, p_render_data->scene_data->cam_projection, !p_render_data->reflection_probe.is_valid());
}
bool using_shadows = true;
@@ -3028,13 +3028,13 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
}
} else {
//do not render reflections when rendering a reflection probe
- _setup_reflections(p_render_data, *p_render_data->reflection_probes, p_render_data->cam_transform.affine_inverse(), p_render_data->environment);
+ _setup_reflections(p_render_data, *p_render_data->reflection_probes, p_render_data->scene_data->cam_transform.affine_inverse(), p_render_data->environment);
}
uint32_t directional_light_count = 0;
uint32_t positional_light_count = 0;
- _setup_lights(p_render_data, *p_render_data->lights, p_render_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
- _setup_decals(*p_render_data->decals, p_render_data->cam_transform.affine_inverse());
+ _setup_lights(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
+ _setup_decals(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse());
p_render_data->directional_light_count = directional_light_count;
@@ -3051,7 +3051,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool
}
}
if (is_volumetric_supported()) {
- _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count, *p_render_data->fog_volumes);
+ _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count, *p_render_data->fog_volumes);
}
}
}
@@ -3066,33 +3066,62 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
ERR_FAIL_COND(rb.is_null());
}
- //assign render data
- RenderDataRD render_data;
+ // setup scene data
+ RenderSceneDataRD scene_data;
{
- render_data.render_buffers = rb;
-
// Our first camera is used by default
- render_data.cam_transform = p_camera_data->main_transform;
- render_data.cam_projection = p_camera_data->main_projection;
- render_data.cam_orthogonal = p_camera_data->is_orthogonal;
- render_data.taa_jitter = p_camera_data->taa_jitter;
+ scene_data.cam_transform = p_camera_data->main_transform;
+ scene_data.cam_projection = p_camera_data->main_projection;
+ scene_data.cam_orthogonal = p_camera_data->is_orthogonal;
+ scene_data.taa_jitter = p_camera_data->taa_jitter;
- render_data.view_count = p_camera_data->view_count;
+ scene_data.view_count = p_camera_data->view_count;
for (uint32_t v = 0; v < p_camera_data->view_count; v++) {
- render_data.view_eye_offset[v] = p_camera_data->view_offset[v].origin;
- render_data.view_projection[v] = p_camera_data->view_projection[v];
+ scene_data.view_eye_offset[v] = p_camera_data->view_offset[v].origin;
+ scene_data.view_projection[v] = p_camera_data->view_projection[v];
}
- render_data.prev_cam_transform = p_prev_camera_data->main_transform;
- render_data.prev_cam_projection = p_prev_camera_data->main_projection;
- render_data.prev_taa_jitter = p_prev_camera_data->taa_jitter;
+ scene_data.prev_cam_transform = p_prev_camera_data->main_transform;
+ scene_data.prev_cam_projection = p_prev_camera_data->main_projection;
+ scene_data.prev_taa_jitter = p_prev_camera_data->taa_jitter;
for (uint32_t v = 0; v < p_camera_data->view_count; v++) {
- render_data.prev_view_projection[v] = p_prev_camera_data->view_projection[v];
+ scene_data.prev_view_projection[v] = p_prev_camera_data->view_projection[v];
+ }
+
+ scene_data.z_near = p_camera_data->main_projection.get_z_near();
+ scene_data.z_far = p_camera_data->main_projection.get_z_far();
+
+ // this should be the same for all cameras..
+ scene_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier();
+ scene_data.lod_camera_plane = Plane(-p_camera_data->main_transform.basis.get_column(Vector3::AXIS_Z), p_camera_data->main_transform.get_origin());
+
+ if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
+ scene_data.screen_mesh_lod_threshold = 0.0;
+ } else {
+ scene_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
+ }
+
+ if (p_shadow_atlas.is_valid()) {
+ Vector2 sas = shadow_atlas_get_size(p_shadow_atlas);
+ scene_data.shadow_atlas_pixel_size.x = 1.0 / sas.x;
+ scene_data.shadow_atlas_pixel_size.y = 1.0 / sas.y;
}
+ {
+ Vector2 dss = directional_shadow_get_size();
+ scene_data.directional_shadow_pixel_size.x = 1.0 / dss.x;
+ scene_data.directional_shadow_pixel_size.y = 1.0 / dss.y;
+ }
+
+ scene_data.time = time;
+ scene_data.time_step = time_step;
+ }
- render_data.z_near = p_camera_data->main_projection.get_z_near();
- render_data.z_far = p_camera_data->main_projection.get_z_far();
+ //assign render data
+ RenderDataRD render_data;
+ {
+ render_data.render_buffers = rb;
+ render_data.scene_data = &scene_data;
render_data.instances = &p_instances;
render_data.lights = &p_lights;
@@ -3108,16 +3137,6 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
render_data.reflection_probe = p_reflection_probe;
render_data.reflection_probe_pass = p_reflection_probe_pass;
- // this should be the same for all cameras..
- render_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier();
- render_data.lod_camera_plane = Plane(-p_camera_data->main_transform.basis.get_column(Vector3::AXIS_Z), p_camera_data->main_transform.get_origin());
-
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) {
- render_data.screen_mesh_lod_threshold = 0.0;
- } else {
- render_data.screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
- }
-
render_state.render_shadows = p_render_shadows;
render_state.render_shadow_count = p_render_shadow_count;
render_state.render_sdfgi_regions = p_render_sdfgi_regions;
@@ -3134,7 +3153,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
render_data.voxel_gi_instances = &empty;
}
- //sdfgi first
+ // sdfgi first
if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
float exposure_normalization = 1.0;
@@ -3191,12 +3210,12 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
if (sdfgi.is_valid()) {
sdfgi->update_cascades();
- sdfgi->pre_process_gi(render_data.cam_transform, &render_data, this);
+ sdfgi->pre_process_gi(scene_data.cam_transform, &render_data, this);
sdfgi->update_light();
}
}
- gi.setup_voxel_gi_instances(&render_data, render_data.render_buffers, render_data.cam_transform, *render_data.voxel_gi_instances, render_state.voxel_gi_count, this);
+ gi.setup_voxel_gi_instances(&render_data, render_data.render_buffers, scene_data.cam_transform, *render_data.voxel_gi_instances, render_state.voxel_gi_count, this);
}
render_state.depth_prepass_used = false;
@@ -3246,7 +3265,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render
view_rids.push_back(rb->get_internal_texture(v));
}
- sdfgi->debug_draw(render_data.view_count, render_data.view_projection, render_data.cam_transform, size.x, size.y, rb->get_render_target(), source_texture, view_rids);
+ sdfgi->debug_draw(scene_data.view_count, scene_data.view_projection, scene_data.cam_transform, size.x, size.y, rb->get_render_target(), source_texture, view_rids);
}
}
}
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index d47394989f..b3a355f42f 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -46,30 +46,14 @@
#include "servers/rendering/renderer_rd/environment/sky.h"
#include "servers/rendering/renderer_rd/framebuffer_cache_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h"
#include "servers/rendering/renderer_scene.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering/rendering_device.h"
struct RenderDataRD {
Ref<RenderSceneBuffersRD> render_buffers;
-
- Transform3D cam_transform;
- Projection cam_projection;
- Vector2 taa_jitter;
- bool cam_orthogonal = false;
-
- // For stereo rendering
- uint32_t view_count = 1;
- Vector3 view_eye_offset[RendererSceneRender::MAX_RENDER_VIEWS];
- Projection view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
-
- Transform3D prev_cam_transform;
- Projection prev_cam_projection;
- Vector2 prev_taa_jitter;
- Projection prev_view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
-
- float z_near = 0.0;
- float z_far = 0.0;
+ RenderSceneDataRD *scene_data;
const PagedArray<RenderGeometryInstance *> *instances = nullptr;
const PagedArray<RID> *lights = nullptr;
@@ -85,10 +69,6 @@ struct RenderDataRD {
RID reflection_probe;
int reflection_probe_pass = 0;
- float lod_distance_multiplier = 0.0;
- Plane lod_camera_plane;
- float screen_mesh_lod_threshold = 0.0;
-
RID cluster_buffer;
uint32_t cluster_size = 0;
uint32_t cluster_max_elements = 0;
@@ -598,13 +578,6 @@ private:
uint64_t scene_pass = 0;
uint64_t shadow_atlas_realloc_tolerance_msec = 500;
- /* !BAS! is this used anywhere?
- struct SDFGICosineNeighbour {
- uint32_t neighbour;
- float weight;
- };
- */
-
uint32_t max_cluster_elements = 512;
void _render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<RenderGeometryInstance *> &p_instances, const Plane &p_camera_plane = Plane(), float p_lod_distance_multiplier = 0, float p_screen_mesh_lod_threshold = 0.0, bool p_open_pass = true, bool p_close_pass = true, bool p_clear_region = true, RendererScene::RenderInfo *p_render_info = nullptr);
@@ -627,6 +600,10 @@ public:
RendererRD::GI *get_gi() { return &gi; }
+ /* SKY */
+
+ RendererRD::SkyRD *get_sky() { return &sky; }
+
/* SHADOW ATLAS API */
virtual RID shadow_atlas_create() override;
diff --git a/servers/rendering/renderer_rd/shaders/SCsub b/servers/rendering/renderer_rd/shaders/SCsub
index d352743908..5405985741 100644
--- a/servers/rendering/renderer_rd/shaders/SCsub
+++ b/servers/rendering/renderer_rd/shaders/SCsub
@@ -18,3 +18,5 @@ if "RD_GLSL" in env["BUILDERS"]:
SConscript("effects/SCsub")
SConscript("environment/SCsub")
+SConscript("forward_clustered/SCsub")
+SConscript("forward_mobile/SCsub")
diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
index bdf84bb03a..fe770ac065 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
@@ -186,6 +186,7 @@ void main() {
uv += pixel_size * 0.5; //half pixel to read centers
vec4 color = texture(color_texture, uv);
+ float initial_blur = color.a;
float accum = 1.0;
float radius = params.blur_scale;
@@ -193,8 +194,8 @@ void main() {
vec2 suv = uv + vec2(cos(ang), sin(ang)) * pixel_size * radius;
vec4 sample_color = texture(color_texture, suv);
float sample_size = abs(sample_color.a);
- if (sample_color.a > color.a) {
- sample_size = clamp(sample_size, 0.0, abs(color.a) * 2.0);
+ if (sample_color.a > initial_blur) {
+ sample_size = clamp(sample_size, 0.0, abs(initial_blur) * 2.0);
}
float m = smoothstep(radius - 0.5, radius + 0.5, sample_size);
diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
index a2bdc2e90e..1b487835d2 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
@@ -221,12 +221,9 @@ void main() {
vec4 sample_color = texture(source_color, uv_adj);
sample_color.a = texture(source_weight, uv_adj).r;
- float limit;
-
- if (sample_color.a < color.a) {
- limit = abs(sample_color.a);
- } else {
- limit = abs(color.a);
+ float limit = abs(sample_color.a);
+ if (sample_color.a > color.a) {
+ limit = clamp(limit, 0.0, abs(color.a) * 2.0);
}
limit -= DEPTH_GAP;
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub b/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub
new file mode 100644
index 0000000000..741da8fe69
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/SCsub
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+Import("env")
+
+if "RD_GLSL" in env["BUILDERS"]:
+ # find all include files
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+
+ # find all shader code(all glsl files excluding our include files)
+ glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
+
+ # make sure we recompile shaders if include files change
+ env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#glsl_builders.py"])
+
+ # compile shaders
+ for glsl_file in glsl_files:
+ env.RD_GLSL(glsl_file)
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index 26b96b358f..d41474118d 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -129,7 +129,7 @@ invariant gl_Position;
#GLOBALS
-void vertex_shader(in uint instance_index, in bool is_multimesh, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) {
+void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) {
vec4 instance_custom = vec4(0.0);
#if defined(COLOR_USED)
color_interp = color_attrib;
@@ -208,7 +208,7 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in SceneData sc
}
}
- uint offset = stride * gl_InstanceIndex;
+ uint offset = stride * (gl_InstanceIndex + multimesh_offset);
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH_FORMAT_2D)) {
matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));
@@ -326,10 +326,6 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in SceneData sc
vertex_interp = vertex;
-#ifdef MOTION_VECTORS
- screen_pos = projection_matrix * vec4(vertex_interp, 1.0);
-#endif
-
#ifdef NORMAL_USED
normal_interp = normal;
#endif
@@ -367,6 +363,10 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in SceneData sc
gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
#endif
+#ifdef MOTION_VECTORS
+ screen_pos = gl_Position;
+#endif
+
#ifdef MODE_RENDER_DEPTH
if (scene_data.pancake_shadows) {
if (gl_Position.z <= 0.00001) {
@@ -397,13 +397,13 @@ void main() {
mat4 model_matrix = instances.data[instance_index].transform;
#if defined(MOTION_VECTORS)
global_time = scene_data_block.prev_data.time;
- vertex_shader(instance_index, is_multimesh, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position);
+ vertex_shader(instance_index, is_multimesh, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position);
global_time = scene_data_block.data.time;
- vertex_shader(instance_index, is_multimesh, scene_data_block.data, model_matrix, screen_position);
+ vertex_shader(instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
#else
global_time = scene_data_block.data.time;
vec4 screen_position;
- vertex_shader(instance_index, is_multimesh, scene_data_block.data, model_matrix, screen_position);
+ vertex_shader(instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
#endif
}
@@ -553,7 +553,7 @@ layout(location = 0) out vec4 frag_color;
layout(location = 2) out vec2 motion_vector;
#endif
-#include "scene_forward_aa_inc.glsl"
+#include "../scene_forward_aa_inc.glsl"
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
@@ -562,20 +562,20 @@ layout(location = 2) out vec2 motion_vector;
#define SPECULAR_SCHLICK_GGX
#endif
-#include "scene_forward_lights_inc.glsl"
+#include "../scene_forward_lights_inc.glsl"
-#include "scene_forward_gi_inc.glsl"
+#include "../scene_forward_gi_inc.glsl"
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
#ifndef MODE_RENDER_DEPTH
vec4 volumetric_fog_process(vec2 screen_uv, float z) {
- vec3 fog_pos = vec3(screen_uv, z * scene_data_block.data.volumetric_fog_inv_length);
+ vec3 fog_pos = vec3(screen_uv, z * implementation_data.volumetric_fog_inv_length);
if (fog_pos.z < 0.0) {
return vec4(0.0);
} else if (fog_pos.z < 1.0) {
- fog_pos.z = pow(fog_pos.z, scene_data_block.data.volumetric_fog_detail_spread);
+ fog_pos.z = pow(fog_pos.z, implementation_data.volumetric_fog_detail_spread);
}
return texture(sampler3D(volumetric_fog_texture, material_samplers[SAMPLER_LINEAR_CLAMP]), fog_pos);
@@ -821,7 +821,7 @@ void fragment_shader(in SceneData scene_data) {
fog = fog_process(vertex);
}
- if (scene_data.volumetric_fog_enabled) {
+ if (implementation_data.volumetric_fog_enabled) {
vec4 volumetric_fog = volumetric_fog_process(screen_uv, -vertex.z);
if (scene_data.fog_enabled) {
//must use the full blending equation here to blend fogs
@@ -849,8 +849,8 @@ void fragment_shader(in SceneData scene_data) {
#ifndef MODE_RENDER_DEPTH
- uvec2 cluster_pos = uvec2(gl_FragCoord.xy) >> scene_data.cluster_shift;
- uint cluster_offset = (scene_data.cluster_width * cluster_pos.y + cluster_pos.x) * (scene_data.max_cluster_element_count_div_32 + 32);
+ uvec2 cluster_pos = uvec2(gl_FragCoord.xy) >> implementation_data.cluster_shift;
+ uint cluster_offset = (implementation_data.cluster_width * cluster_pos.y + cluster_pos.x) * (implementation_data.max_cluster_element_count_div_32 + 32);
uint cluster_z = uint(clamp((-vertex.z / scene_data.z_far) * 32.0, 0.0, 31.0));
@@ -860,14 +860,14 @@ void fragment_shader(in SceneData scene_data) {
{ // process decals
- uint cluster_decal_offset = cluster_offset + scene_data.cluster_type_size * 2;
+ uint cluster_decal_offset = cluster_offset + implementation_data.cluster_type_size * 2;
uint item_min;
uint item_max;
uint item_from;
uint item_to;
- cluster_get_item_range(cluster_decal_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+ cluster_get_item_range(cluster_decal_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
item_from = subgroupBroadcastFirst(subgroupMin(item_from));
@@ -1256,7 +1256,7 @@ void fragment_shader(in SceneData scene_data) {
vec2 coord;
- if (scene_data.gi_upscale_for_msaa) {
+ if (implementation_data.gi_upscale_for_msaa) {
vec2 base_coord = screen_uv;
vec2 closest_coord = base_coord;
#ifdef USE_MULTIVIEW
@@ -1298,10 +1298,10 @@ void fragment_shader(in SceneData scene_data) {
}
#endif // !USE_LIGHTMAP
- if (bool(scene_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO)) {
+ if (bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSAO)) {
float ssao = texture(sampler2D(ao_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv).r;
ao = min(ao, ssao);
- ao_light_affect = mix(ao_light_affect, max(ao_light_affect, scene_data.ssao_light_affect), scene_data.ssao_ao_affect);
+ ao_light_affect = mix(ao_light_affect, max(ao_light_affect, implementation_data.ssao_light_affect), implementation_data.ssao_ao_affect);
}
{ // process reflections
@@ -1309,14 +1309,14 @@ void fragment_shader(in SceneData scene_data) {
vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
- uint cluster_reflection_offset = cluster_offset + scene_data.cluster_type_size * 3;
+ uint cluster_reflection_offset = cluster_offset + implementation_data.cluster_type_size * 3;
uint item_min;
uint item_max;
uint item_from;
uint item_to;
- cluster_get_item_range(cluster_reflection_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+ cluster_get_item_range(cluster_reflection_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
item_from = subgroupBroadcastFirst(subgroupMin(item_from));
@@ -1380,7 +1380,7 @@ void fragment_shader(in SceneData scene_data) {
// convert ao to direct light ao
ao = mix(1.0, ao, ao_light_affect);
- if (bool(scene_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL)) {
+ if (bool(implementation_data.ss_effects_flags & SCREEN_SPACE_EFFECTS_FLAGS_USE_SSIL)) {
vec4 ssil = textureLod(sampler2D(ssil_buffer, material_samplers[SAMPLER_LINEAR_CLAMP]), screen_uv, 0.0);
ambient_light *= 1.0 - ssil.a;
ambient_light += ssil.rgb * albedo.rgb;
@@ -1748,7 +1748,7 @@ void fragment_shader(in SceneData scene_data) {
uint item_from;
uint item_to;
- cluster_get_item_range(cluster_omni_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+ cluster_get_item_range(cluster_omni_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
item_from = subgroupBroadcastFirst(subgroupMin(item_from));
@@ -1812,14 +1812,14 @@ void fragment_shader(in SceneData scene_data) {
{ //spot lights
- uint cluster_spot_offset = cluster_offset + scene_data.cluster_type_size;
+ uint cluster_spot_offset = cluster_offset + implementation_data.cluster_type_size;
uint item_min;
uint item_max;
uint item_from;
uint item_to;
- cluster_get_item_range(cluster_spot_offset + scene_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
+ cluster_get_item_range(cluster_spot_offset + implementation_data.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to);
#ifdef USE_SUBGROUPS
item_from = subgroupBroadcastFirst(subgroupMin(item_from));
@@ -1909,8 +1909,8 @@ void fragment_shader(in SceneData scene_data) {
#ifdef MODE_RENDER_SDF
{
- vec3 local_pos = (scene_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz;
- ivec3 grid_pos = scene_data.sdf_offset + ivec3(local_pos * vec3(scene_data.sdf_size));
+ vec3 local_pos = (implementation_data.sdf_to_bounds * vec4(vertex, 1.0)).xyz;
+ ivec3 grid_pos = implementation_data.sdf_offset + ivec3(local_pos * vec3(implementation_data.sdf_size));
uint albedo16 = 0x1; //solid flag
albedo16 |= clamp(uint(albedo.r * 31.0), 0, 31) << 11;
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
index 45484b8c47..e8e2dce990 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
@@ -17,8 +17,9 @@
#extension GL_EXT_multiview : enable
#endif
-#include "cluster_data_inc.glsl"
-#include "decal_data_inc.glsl"
+#include "../cluster_data_inc.glsl"
+#include "../decal_data_inc.glsl"
+#include "../scene_data_inc.glsl"
#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(MODE_RENDER_SDF) || defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_VOXEL_GI) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
#ifndef NORMAL_USED
@@ -29,8 +30,8 @@
layout(push_constant, std430) uniform DrawCall {
uint instance_index;
uint uv_offset;
- uint pad0;
- uint pad1;
+ uint multimesh_motion_vectors_current_offset;
+ uint multimesh_motion_vectors_previous_offset;
}
draw_call;
@@ -38,7 +39,7 @@ draw_call;
/* Set 0: Base Pass (never changes) */
-#include "light_data_inc.glsl"
+#include "../light_data_inc.glsl"
#define SAMPLER_NEAREST_CLAMP 0
#define SAMPLER_LINEAR_CLAMP 1
@@ -175,62 +176,27 @@ sdfgi;
/* Set 1: Render Pass (changes per render pass) */
-struct SceneData {
- mat4 projection_matrix;
- mat4 inv_projection_matrix;
- mat4 inv_view_matrix;
- mat4 view_matrix;
-
- // only used for multiview
- mat4 projection_matrix_view[MAX_VIEWS];
- mat4 inv_projection_matrix_view[MAX_VIEWS];
- vec4 eye_offset[MAX_VIEWS];
-
- vec2 viewport_size;
- vec2 screen_pixel_size;
+layout(set = 1, binding = 0, std140) uniform SceneDataBlock {
+ SceneData data;
+ SceneData prev_data;
+}
+scene_data_block;
+struct ImplementationData {
uint cluster_shift;
uint cluster_width;
uint cluster_type_size;
uint max_cluster_element_count_div_32;
- // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted.
- vec4 directional_penumbra_shadow_kernel[32];
- vec4 directional_soft_shadow_kernel[32];
- vec4 penumbra_shadow_kernel[32];
- vec4 soft_shadow_kernel[32];
-
- vec4 ambient_light_color_energy;
-
- float ambient_color_sky_mix;
- bool use_ambient_light;
- bool use_ambient_cubemap;
- bool use_reflection_cubemap;
-
- mat3 radiance_inverse_xform;
-
- vec2 shadow_atlas_pixel_size;
- vec2 directional_shadow_pixel_size;
-
- uint directional_light_count;
- float dual_paraboloid_side;
- float z_far;
- float z_near;
-
uint ss_effects_flags;
float ssao_light_affect;
float ssao_ao_affect;
- bool roughness_limiter_enabled;
-
- float roughness_limiter_amount;
- float roughness_limiter_limit;
- float opaque_prepass_threshold;
- uint roughness_limiter_pad;
+ uint pad1;
mat4 sdf_to_bounds;
ivec3 sdf_offset;
- bool material_uv2_mode;
+ uint pad2;
ivec3 sdf_size;
bool gi_upscale_for_msaa;
@@ -239,31 +205,14 @@ struct SceneData {
float volumetric_fog_inv_length;
float volumetric_fog_detail_spread;
uint volumetric_fog_pad;
-
- bool fog_enabled;
- float fog_density;
- float fog_height;
- float fog_height_density;
-
- vec3 fog_light_color;
- float fog_sun_scatter;
-
- float fog_aerial_perspective;
-
- float time;
- float reflection_multiplier; // one normally, zero when rendering reflections
-
- bool pancake_shadows;
- vec2 taa_jitter;
- float emissive_exposure_normalization;
- float IBL_exposure_normalization;
};
-layout(set = 1, binding = 0, std140) uniform SceneDataBlock {
- SceneData data;
- SceneData prev_data;
+layout(set = 1, binding = 1, std140) uniform ImplementationDataBlock {
+ ImplementationData data;
}
-scene_data_block;
+implementation_data_block;
+
+#define implementation_data implementation_data_block.data
struct InstanceData {
mat4 transform;
@@ -275,42 +224,42 @@ struct InstanceData {
vec4 lightmap_uv_scale;
};
-layout(set = 1, binding = 1, std430) buffer restrict readonly InstanceDataBuffer {
+layout(set = 1, binding = 2, std430) buffer restrict readonly InstanceDataBuffer {
InstanceData data[];
}
instances;
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
-layout(set = 1, binding = 2) uniform textureCubeArray radiance_cubemap;
+layout(set = 1, binding = 3) uniform textureCubeArray radiance_cubemap;
#else
-layout(set = 1, binding = 2) uniform textureCube radiance_cubemap;
+layout(set = 1, binding = 3) uniform textureCube radiance_cubemap;
#endif
-layout(set = 1, binding = 3) uniform textureCubeArray reflection_atlas;
+layout(set = 1, binding = 4) uniform textureCubeArray reflection_atlas;
-layout(set = 1, binding = 4) uniform texture2D shadow_atlas;
+layout(set = 1, binding = 5) uniform texture2D shadow_atlas;
-layout(set = 1, binding = 5) uniform texture2D directional_shadow_atlas;
+layout(set = 1, binding = 6) uniform texture2D directional_shadow_atlas;
-layout(set = 1, binding = 6) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
+layout(set = 1, binding = 7) uniform texture2DArray lightmap_textures[MAX_LIGHTMAP_TEXTURES];
-layout(set = 1, binding = 7) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
+layout(set = 1, binding = 8) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES];
-layout(set = 1, binding = 8, std430) buffer restrict readonly ClusterBuffer {
+layout(set = 1, binding = 9, std430) buffer restrict readonly ClusterBuffer {
uint data[];
}
cluster_buffer;
#ifdef MODE_RENDER_SDF
-layout(r16ui, set = 1, binding = 9) uniform restrict writeonly uimage3D albedo_volume_grid;
-layout(r32ui, set = 1, binding = 10) uniform restrict writeonly uimage3D emission_grid;
-layout(r32ui, set = 1, binding = 11) uniform restrict writeonly uimage3D emission_aniso_grid;
-layout(r32ui, set = 1, binding = 12) uniform restrict uimage3D geom_facing_grid;
+layout(r16ui, set = 1, binding = 10) uniform restrict writeonly uimage3D albedo_volume_grid;
+layout(r32ui, set = 1, binding = 11) uniform restrict writeonly uimage3D emission_grid;
+layout(r32ui, set = 1, binding = 12) uniform restrict writeonly uimage3D emission_aniso_grid;
+layout(r32ui, set = 1, binding = 13) uniform restrict uimage3D geom_facing_grid;
//still need to be present for shaders that use it, so remap them to something
#define depth_buffer shadow_atlas
@@ -319,21 +268,21 @@ layout(r32ui, set = 1, binding = 12) uniform restrict uimage3D geom_facing_grid;
#else
-layout(set = 1, binding = 9) uniform texture2D depth_buffer;
-layout(set = 1, binding = 10) uniform texture2D color_buffer;
+layout(set = 1, binding = 10) uniform texture2D depth_buffer;
+layout(set = 1, binding = 11) uniform texture2D color_buffer;
#ifdef USE_MULTIVIEW
-layout(set = 1, binding = 11) uniform texture2DArray normal_roughness_buffer;
-layout(set = 1, binding = 13) uniform texture2DArray ambient_buffer;
-layout(set = 1, binding = 14) uniform texture2DArray reflection_buffer;
+layout(set = 1, binding = 12) uniform texture2DArray normal_roughness_buffer;
+layout(set = 1, binding = 14) uniform texture2DArray ambient_buffer;
+layout(set = 1, binding = 15) uniform texture2DArray reflection_buffer;
#else // USE_MULTIVIEW
-layout(set = 1, binding = 11) uniform texture2D normal_roughness_buffer;
-layout(set = 1, binding = 13) uniform texture2D ambient_buffer;
-layout(set = 1, binding = 14) uniform texture2D reflection_buffer;
+layout(set = 1, binding = 12) uniform texture2D normal_roughness_buffer;
+layout(set = 1, binding = 14) uniform texture2D ambient_buffer;
+layout(set = 1, binding = 15) uniform texture2D reflection_buffer;
#endif
-layout(set = 1, binding = 12) uniform texture2D ao_buffer;
-layout(set = 1, binding = 15) uniform texture2DArray sdfgi_lightprobe_texture;
-layout(set = 1, binding = 16) uniform texture3D sdfgi_occlusion_cascades;
+layout(set = 1, binding = 13) uniform texture2D ao_buffer;
+layout(set = 1, binding = 16) uniform texture2DArray sdfgi_lightprobe_texture;
+layout(set = 1, binding = 17) uniform texture3D sdfgi_occlusion_cascades;
struct VoxelGIData {
mat4 xform; // 64 - 64
@@ -350,14 +299,14 @@ struct VoxelGIData {
float exposure_normalization; // 4 - 112
};
-layout(set = 1, binding = 17, std140) uniform VoxelGIs {
+layout(set = 1, binding = 18, std140) uniform VoxelGIs {
VoxelGIData data[MAX_VOXEL_GI_INSTANCES];
}
voxel_gi_instances;
-layout(set = 1, binding = 18) uniform texture3D volumetric_fog_texture;
+layout(set = 1, binding = 19) uniform texture3D volumetric_fog_texture;
-layout(set = 1, binding = 19) uniform texture2D ssil_buffer;
+layout(set = 1, binding = 20) uniform texture2D ssil_buffer;
#endif
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub b/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub
new file mode 100644
index 0000000000..741da8fe69
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/SCsub
@@ -0,0 +1,17 @@
+#!/usr/bin/env python
+
+Import("env")
+
+if "RD_GLSL" in env["BUILDERS"]:
+ # find all include files
+ gl_include_files = [str(f) for f in Glob("*_inc.glsl")]
+
+ # find all shader code(all glsl files excluding our include files)
+ glsl_files = [str(f) for f in Glob("*.glsl") if str(f) not in gl_include_files]
+
+ # make sure we recompile shaders if include files change
+ env.Depends([f + ".gen.h" for f in glsl_files], gl_include_files + ["#glsl_builders.py"])
+
+ # compile shaders
+ for glsl_file in glsl_files:
+ env.RD_GLSL(glsl_file)
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index 5a5ada7231..a109fd4d75 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -101,7 +101,7 @@ layout(set = MATERIAL_UNIFORM_SET, binding = 0, std140) uniform MaterialUniforms
#ifdef MODE_DUAL_PARABOLOID
-layout(location = 8) out highp float dp_clip;
+layout(location = 9) out highp float dp_clip;
#endif
@@ -450,7 +450,7 @@ layout(location = 6) mediump in vec3 binormal_interp;
#ifdef MODE_DUAL_PARABOLOID
-layout(location = 8) highp in float dp_clip;
+layout(location = 9) highp in float dp_clip;
#endif
@@ -519,7 +519,7 @@ layout(location = 0) out mediump vec4 frag_color;
#endif // RENDER DEPTH
-#include "scene_forward_aa_inc.glsl"
+#include "../scene_forward_aa_inc.glsl"
#if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
@@ -528,7 +528,7 @@ layout(location = 0) out mediump vec4 frag_color;
#define SPECULAR_SCHLICK_GGX
#endif
-#include "scene_forward_lights_inc.glsl"
+#include "../scene_forward_lights_inc.glsl"
#endif //!defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED)
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
index 3a9c52f5bc..5e4999fa0f 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
@@ -5,7 +5,8 @@
#extension GL_EXT_multiview : enable
#endif
-#include "decal_data_inc.glsl"
+#include "../decal_data_inc.glsl"
+#include "../scene_data_inc.glsl"
#if !defined(MODE_RENDER_DEPTH) || defined(MODE_RENDER_MATERIAL) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
#ifndef NORMAL_USED
@@ -32,7 +33,7 @@ draw_call;
/* Set 0: Base Pass (never changes) */
-#include "light_data_inc.glsl"
+#include "../light_data_inc.glsl"
#define SAMPLER_NEAREST_CLAMP 0
#define SAMPLER_LINEAR_CLAMP 1
@@ -127,75 +128,9 @@ global_shader_uniforms;
/* Set 1: Render Pass (changes per render pass) */
-struct SceneData {
- highp mat4 projection_matrix;
- highp mat4 inv_projection_matrix;
- highp mat4 inv_view_matrix;
- highp mat4 view_matrix;
-
- // only used for multiview
- highp mat4 projection_matrix_view[MAX_VIEWS];
- highp mat4 inv_projection_matrix_view[MAX_VIEWS];
- highp vec4 eye_offset[MAX_VIEWS];
-
- highp vec2 viewport_size;
- highp vec2 screen_pixel_size;
-
- // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted.
- highp vec4 directional_penumbra_shadow_kernel[32];
- highp vec4 directional_soft_shadow_kernel[32];
- highp vec4 penumbra_shadow_kernel[32];
- highp vec4 soft_shadow_kernel[32];
-
- mediump vec4 ambient_light_color_energy;
-
- mediump float ambient_color_sky_mix;
- bool use_ambient_light;
- bool use_ambient_cubemap;
- bool use_reflection_cubemap;
-
- mediump mat3 radiance_inverse_xform;
-
- highp vec2 shadow_atlas_pixel_size;
- highp vec2 directional_shadow_pixel_size;
-
- uint directional_light_count;
- mediump float dual_paraboloid_side;
- highp float z_far;
- highp float z_near;
-
- bool ssao_enabled;
- mediump float ssao_light_affect;
- mediump float ssao_ao_affect;
- bool roughness_limiter_enabled;
-
- mediump float roughness_limiter_amount;
- mediump float roughness_limiter_limit;
- mediump float opaque_prepass_threshold;
- uint roughness_limiter_pad;
-
- bool fog_enabled;
- highp float fog_density;
- highp float fog_height;
- highp float fog_height_density;
-
- mediump vec3 fog_light_color;
- mediump float fog_sun_scatter;
-
- mediump float fog_aerial_perspective;
- bool material_uv2_mode;
-
- highp float time;
- mediump float reflection_multiplier; // one normally, zero when rendering reflections
-
- bool pancake_shadows;
- float emissive_exposure_normalization;
- float IBL_exposure_normalization;
- uint pad3;
-};
-
layout(set = 1, binding = 0, std140) uniform SceneDataBlock {
SceneData data;
+ SceneData prev_data;
}
scene_data_block;
diff --git a/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl
new file mode 100644
index 0000000000..048257e9ef
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/scene_data_inc.glsl
@@ -0,0 +1,69 @@
+// Scene data stores all our 3D rendering globals for a frame such as our matrices
+// where this information is independent of the different RD implementations.
+// This enables us to use this UBO in our main scene render shaders but also in
+// effects that need access to this data.
+
+struct SceneData {
+ highp mat4 projection_matrix;
+ highp mat4 inv_projection_matrix;
+ highp mat4 inv_view_matrix;
+ highp mat4 view_matrix;
+
+ // only used for multiview
+ highp mat4 projection_matrix_view[MAX_VIEWS];
+ highp mat4 inv_projection_matrix_view[MAX_VIEWS];
+ highp vec4 eye_offset[MAX_VIEWS];
+
+ highp vec2 viewport_size;
+ highp vec2 screen_pixel_size;
+
+ // Use vec4s because std140 doesn't play nice with vec2s, z and w are wasted.
+ highp vec4 directional_penumbra_shadow_kernel[32];
+ highp vec4 directional_soft_shadow_kernel[32];
+ highp vec4 penumbra_shadow_kernel[32];
+ highp vec4 soft_shadow_kernel[32];
+
+ mediump mat3 radiance_inverse_xform;
+
+ mediump vec4 ambient_light_color_energy;
+
+ mediump float ambient_color_sky_mix;
+ bool use_ambient_light;
+ bool use_ambient_cubemap;
+ bool use_reflection_cubemap;
+
+ highp vec2 shadow_atlas_pixel_size;
+ highp vec2 directional_shadow_pixel_size;
+
+ uint directional_light_count;
+ mediump float dual_paraboloid_side;
+ highp float z_far;
+ highp float z_near;
+
+ bool roughness_limiter_enabled;
+ mediump float roughness_limiter_amount;
+ mediump float roughness_limiter_limit;
+ mediump float opaque_prepass_threshold;
+
+ bool fog_enabled;
+ highp float fog_density;
+ highp float fog_height;
+ highp float fog_height_density;
+
+ mediump vec3 fog_light_color;
+ mediump float fog_sun_scatter;
+
+ mediump float fog_aerial_perspective;
+ highp float time;
+ mediump float reflection_multiplier; // one normally, zero when rendering reflections
+ bool material_uv2_mode;
+
+ vec2 taa_jitter;
+ float emissive_exposure_normalization;
+ float IBL_exposure_normalization;
+
+ bool pancake_shadows;
+ uint pad1;
+ uint pad2;
+ uint pad3;
+};
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
index 49e3543ba5..1827b73507 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "mesh_storage.h"
+#include "../../rendering_server_globals.h"
using namespace RendererRD;
@@ -1211,7 +1212,13 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
if (multimesh->data_cache_dirty_regions) {
memdelete_arr(multimesh->data_cache_dirty_regions);
multimesh->data_cache_dirty_regions = nullptr;
- multimesh->data_cache_used_dirty_regions = 0;
+ multimesh->data_cache_dirty_region_count = 0;
+ }
+
+ if (multimesh->previous_data_cache_dirty_regions) {
+ memdelete_arr(multimesh->previous_data_cache_dirty_regions);
+ multimesh->previous_data_cache_dirty_regions = nullptr;
+ multimesh->previous_data_cache_dirty_region_count = 0;
}
multimesh->instances = p_instances;
@@ -1228,14 +1235,67 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
multimesh->aabb = AABB();
multimesh->aabb_dirty = false;
multimesh->visible_instances = MIN(multimesh->visible_instances, multimesh->instances);
+ multimesh->motion_vectors_current_offset = 0;
+ multimesh->motion_vectors_previous_offset = 0;
+ multimesh->motion_vectors_last_change = -1;
if (multimesh->instances) {
- multimesh->buffer = RD::get_singleton()->storage_buffer_create(multimesh->instances * multimesh->stride_cache * 4);
+ uint32_t buffer_size = multimesh->instances * multimesh->stride_cache * sizeof(float);
+ if (multimesh->motion_vectors_enabled) {
+ buffer_size *= 2;
+ }
+ multimesh->buffer = RD::get_singleton()->storage_buffer_create(buffer_size);
}
multimesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_MULTIMESH);
}
+bool MeshStorage::_multimesh_enable_motion_vectors(RID p_multimesh) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, false);
+
+ if (multimesh->motion_vectors_enabled) {
+ return false;
+ }
+
+ multimesh->motion_vectors_enabled = true;
+
+ multimesh->motion_vectors_current_offset = 0;
+ multimesh->motion_vectors_previous_offset = 0;
+ multimesh->motion_vectors_last_change = -1;
+
+ if (!multimesh->data_cache.is_empty()) {
+ multimesh->data_cache.append_array(multimesh->data_cache);
+ }
+
+ if (multimesh->buffer_set) {
+ RD::get_singleton()->barrier();
+ Vector<uint8_t> buffer_data = RD::get_singleton()->buffer_get_data(multimesh->buffer);
+ if (!multimesh->data_cache.is_empty()) {
+ memcpy(buffer_data.ptrw(), multimesh->data_cache.ptr(), buffer_data.size());
+ }
+
+ RD::get_singleton()->free(multimesh->buffer);
+ uint32_t buffer_size = multimesh->instances * multimesh->stride_cache * sizeof(float) * 2;
+ multimesh->buffer = RD::get_singleton()->storage_buffer_create(buffer_size);
+ RD::get_singleton()->buffer_update(multimesh->buffer, 0, buffer_data.size(), buffer_data.ptr(), RD::BARRIER_MASK_NO_BARRIER);
+ RD::get_singleton()->buffer_update(multimesh->buffer, buffer_data.size(), buffer_data.size(), buffer_data.ptr());
+ multimesh->uniform_set_3d = RID(); // Cleared by dependency
+ return true;
+ }
+ return false; // Update the transforms uniform set cache
+}
+
+void MeshStorage::_multimesh_get_motion_vectors_offsets(RID p_multimesh, uint32_t &r_current_offset, uint32_t &r_prev_offset) {
+ MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ r_current_offset = multimesh->motion_vectors_current_offset;
+ if (RSG::rasterizer->get_frame_number() - multimesh->motion_vectors_last_change >= 2) {
+ multimesh->motion_vectors_previous_offset = multimesh->motion_vectors_current_offset;
+ }
+ r_prev_offset = multimesh->motion_vectors_previous_offset;
+}
+
int MeshStorage::multimesh_get_instance_count(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
ERR_FAIL_COND_V(!multimesh, 0);
@@ -1261,7 +1321,7 @@ void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
//need to re-create AABB unfortunately, calling this has a penalty
if (multimesh->buffer_set) {
Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
- const uint8_t *r = buffer.ptr();
+ const uint8_t *r = buffer.ptr() + multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float);
const float *data = reinterpret_cast<const float *>(r);
_multimesh_re_create_aabb(multimesh, data, multimesh->instances);
}
@@ -1276,10 +1336,14 @@ void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const {
if (multimesh->data_cache.size() > 0) {
return; //already local
}
- ERR_FAIL_COND(multimesh->data_cache.size() > 0);
+
// this means that the user wants to load/save individual elements,
// for this, the data must reside on CPU, so just copy it there.
- multimesh->data_cache.resize(multimesh->instances * multimesh->stride_cache);
+ uint32_t buffer_size = multimesh->instances * multimesh->stride_cache;
+ if (multimesh->motion_vectors_enabled) {
+ buffer_size *= 2;
+ }
+ multimesh->data_cache.resize(buffer_size);
{
float *w = multimesh->data_cache.ptrw();
@@ -1290,15 +1354,48 @@ void MeshStorage::_multimesh_make_local(MultiMesh *multimesh) const {
memcpy(w, r, buffer.size());
}
} else {
- memset(w, 0, (size_t)multimesh->instances * multimesh->stride_cache * sizeof(float));
+ memset(w, 0, buffer_size * sizeof(float));
}
}
uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
multimesh->data_cache_dirty_regions = memnew_arr(bool, data_cache_dirty_region_count);
- for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
- multimesh->data_cache_dirty_regions[i] = false;
+ memset(multimesh->data_cache_dirty_regions, 0, data_cache_dirty_region_count * sizeof(bool));
+ multimesh->data_cache_dirty_region_count = 0;
+
+ multimesh->previous_data_cache_dirty_regions = memnew_arr(bool, data_cache_dirty_region_count);
+ memset(multimesh->previous_data_cache_dirty_regions, 0, data_cache_dirty_region_count * sizeof(bool));
+ multimesh->previous_data_cache_dirty_region_count = 0;
+}
+
+void MeshStorage::_multimesh_update_motion_vectors_data_cache(MultiMesh *multimesh) {
+ ERR_FAIL_COND(multimesh->data_cache.is_empty());
+
+ if (!multimesh->motion_vectors_enabled) {
+ return;
+ }
+
+ uint32_t frame = RSG::rasterizer->get_frame_number();
+ if (multimesh->motion_vectors_last_change != frame) {
+ multimesh->motion_vectors_previous_offset = multimesh->motion_vectors_current_offset;
+ multimesh->motion_vectors_current_offset = multimesh->instances - multimesh->motion_vectors_current_offset;
+ multimesh->motion_vectors_last_change = frame;
+
+ if (multimesh->previous_data_cache_dirty_region_count > 0) {
+ uint8_t *data = (uint8_t *)multimesh->data_cache.ptrw();
+ uint32_t current_ofs = multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float);
+ uint32_t previous_ofs = multimesh->motion_vectors_previous_offset * multimesh->stride_cache * sizeof(float);
+ uint32_t visible_instances = multimesh->visible_instances >= 0 ? multimesh->visible_instances : multimesh->instances;
+ uint32_t visible_region_count = visible_instances == 0 ? 0 : (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
+ uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float);
+ uint32_t size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float);
+ for (uint32_t i = 0; i < visible_region_count; i++) {
+ if (multimesh->previous_data_cache_dirty_regions[i]) {
+ uint32_t offset = i * region_size;
+ memcpy(data + current_ofs + offset, data + previous_ofs + offset, MIN(region_size, size - offset));
+ }
+ }
+ }
}
- multimesh->data_cache_used_dirty_regions = 0;
}
void MeshStorage::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb) {
@@ -1309,7 +1406,7 @@ void MeshStorage::_multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool
#endif
if (!multimesh->data_cache_dirty_regions[region_index]) {
multimesh->data_cache_dirty_regions[region_index] = true;
- multimesh->data_cache_used_dirty_regions++;
+ multimesh->data_cache_dirty_region_count++;
}
if (p_aabb) {
@@ -1330,7 +1427,7 @@ void MeshStorage::_multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, b
for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
if (!multimesh->data_cache_dirty_regions[i]) {
multimesh->data_cache_dirty_regions[i] = true;
- multimesh->data_cache_used_dirty_regions++;
+ multimesh->data_cache_dirty_region_count++;
}
}
}
@@ -1395,11 +1492,12 @@ void MeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index,
ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D);
_multimesh_make_local(multimesh);
+ _multimesh_update_motion_vectors_data_cache(multimesh);
{
float *w = multimesh->data_cache.ptrw();
- float *dataptr = w + p_index * multimesh->stride_cache;
+ float *dataptr = w + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache;
dataptr[0] = p_transform.basis.rows[0][0];
dataptr[1] = p_transform.basis.rows[0][1];
@@ -1425,11 +1523,12 @@ void MeshStorage::multimesh_instance_set_transform_2d(RID p_multimesh, int p_ind
ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D);
_multimesh_make_local(multimesh);
+ _multimesh_update_motion_vectors_data_cache(multimesh);
{
float *w = multimesh->data_cache.ptrw();
- float *dataptr = w + p_index * multimesh->stride_cache;
+ float *dataptr = w + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache;
dataptr[0] = p_transform.columns[0][0];
dataptr[1] = p_transform.columns[1][0];
@@ -1451,11 +1550,12 @@ void MeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, con
ERR_FAIL_COND(!multimesh->uses_colors);
_multimesh_make_local(multimesh);
+ _multimesh_update_motion_vectors_data_cache(multimesh);
{
float *w = multimesh->data_cache.ptrw();
- float *dataptr = w + p_index * multimesh->stride_cache + multimesh->color_offset_cache;
+ float *dataptr = w + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache + multimesh->color_offset_cache;
dataptr[0] = p_color.r;
dataptr[1] = p_color.g;
@@ -1473,11 +1573,12 @@ void MeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_inde
ERR_FAIL_COND(!multimesh->uses_custom_data);
_multimesh_make_local(multimesh);
+ _multimesh_update_motion_vectors_data_cache(multimesh);
{
float *w = multimesh->data_cache.ptrw();
- float *dataptr = w + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache;
+ float *dataptr = w + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache + multimesh->custom_data_offset_cache;
dataptr[0] = p_color.r;
dataptr[1] = p_color.g;
@@ -1514,7 +1615,7 @@ Transform3D MeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p
{
const float *r = multimesh->data_cache.ptr();
- const float *dataptr = r + p_index * multimesh->stride_cache;
+ const float *dataptr = r + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache;
t.basis.rows[0][0] = dataptr[0];
t.basis.rows[0][1] = dataptr[1];
@@ -1545,7 +1646,7 @@ Transform2D MeshStorage::multimesh_instance_get_transform_2d(RID p_multimesh, in
{
const float *r = multimesh->data_cache.ptr();
- const float *dataptr = r + p_index * multimesh->stride_cache;
+ const float *dataptr = r + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache;
t.columns[0][0] = dataptr[0];
t.columns[1][0] = dataptr[1];
@@ -1570,7 +1671,7 @@ Color MeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) co
{
const float *r = multimesh->data_cache.ptr();
- const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->color_offset_cache;
+ const float *dataptr = r + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache + multimesh->color_offset_cache;
c.r = dataptr[0];
c.g = dataptr[1];
@@ -1593,7 +1694,7 @@ Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_ind
{
const float *r = multimesh->data_cache.ptr();
- const float *dataptr = r + p_index * multimesh->stride_cache + multimesh->custom_data_offset_cache;
+ const float *dataptr = r + (multimesh->motion_vectors_current_offset + p_index) * multimesh->stride_cache + multimesh->custom_data_offset_cache;
c.r = dataptr[0];
c.g = dataptr[1];
@@ -1609,25 +1710,26 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b
ERR_FAIL_COND(!multimesh);
ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache));
+ if (multimesh->motion_vectors_enabled) {
+ uint32_t frame = RSG::rasterizer->get_frame_number();
+
+ if (multimesh->motion_vectors_last_change != frame) {
+ multimesh->motion_vectors_previous_offset = multimesh->motion_vectors_current_offset;
+ multimesh->motion_vectors_current_offset = multimesh->instances - multimesh->motion_vectors_current_offset;
+ multimesh->motion_vectors_last_change = frame;
+ }
+ }
+
{
const float *r = p_buffer.ptr();
- RD::get_singleton()->buffer_update(multimesh->buffer, 0, p_buffer.size() * sizeof(float), r);
+ RD::get_singleton()->buffer_update(multimesh->buffer, multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float), p_buffer.size() * sizeof(float), r);
multimesh->buffer_set = true;
}
if (multimesh->data_cache.size()) {
- //if we have a data cache, just update it
- multimesh->data_cache = p_buffer;
- {
- //clear dirty since nothing will be dirty anymore
- uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
- for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
- multimesh->data_cache_dirty_regions[i] = false;
- }
- multimesh->data_cache_used_dirty_regions = 0;
- }
-
- _multimesh_mark_all_dirty(multimesh, false, true); //update AABB
+ float *cache_data = multimesh->data_cache.ptrw();
+ memcpy(cache_data + (multimesh->motion_vectors_current_offset * multimesh->stride_cache), p_buffer.ptr(), p_buffer.size() * sizeof(float));
+ _multimesh_mark_all_dirty(multimesh, true, true); //update AABB
} else if (multimesh->mesh.is_valid()) {
//if we have a mesh set, we need to re-generate the AABB from the new data
const float *data = p_buffer.ptr();
@@ -1642,20 +1744,19 @@ Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
ERR_FAIL_COND_V(!multimesh, Vector<float>());
if (multimesh->buffer.is_null()) {
return Vector<float>();
- } else if (multimesh->data_cache.size()) {
- return multimesh->data_cache;
} else {
- //get from memory
-
- Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
Vector<float> ret;
ret.resize(multimesh->instances * multimesh->stride_cache);
- {
- float *w = ret.ptrw();
- const uint8_t *r = buffer.ptr();
- memcpy(w, r, buffer.size());
- }
+ float *w = ret.ptrw();
+ if (multimesh->data_cache.size()) {
+ const uint8_t *r = (uint8_t *)multimesh->data_cache.ptr() + multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float);
+ memcpy(w, r, ret.size() * sizeof(float));
+ } else {
+ Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(multimesh->buffer);
+ const uint8_t *r = buffer.ptr() + multimesh->motion_vectors_current_offset * multimesh->stride_cache * sizeof(float);
+ memcpy(w, r, ret.size() * sizeof(float));
+ }
return ret;
}
}
@@ -1698,36 +1799,38 @@ void MeshStorage::_update_dirty_multimeshes() {
MultiMesh *multimesh = multimesh_dirty_list;
if (multimesh->data_cache.size()) { //may have been cleared, so only process if it exists
- const float *data = multimesh->data_cache.ptr();
uint32_t visible_instances = multimesh->visible_instances >= 0 ? multimesh->visible_instances : multimesh->instances;
+ uint32_t buffer_offset = multimesh->motion_vectors_current_offset * multimesh->stride_cache;
+ const float *data = multimesh->data_cache.ptr() + buffer_offset;
- if (multimesh->data_cache_used_dirty_regions) {
+ uint32_t total_dirty_regions = multimesh->data_cache_dirty_region_count + multimesh->previous_data_cache_dirty_region_count;
+ if (total_dirty_regions != 0) {
uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
uint32_t visible_region_count = visible_instances == 0 ? 0 : (visible_instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1;
uint32_t region_size = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * sizeof(float);
-
- if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) {
+ if (total_dirty_regions > 32 || total_dirty_regions > visible_region_count / 2) {
//if there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much
- RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * (uint32_t)multimesh->stride_cache * (uint32_t)sizeof(float)), data);
+ RD::get_singleton()->buffer_update(multimesh->buffer, buffer_offset * sizeof(float), MIN(visible_region_count * region_size, multimesh->instances * (uint32_t)multimesh->stride_cache * (uint32_t)sizeof(float)), data);
} else {
//not that many regions? update them all
for (uint32_t i = 0; i < visible_region_count; i++) {
- if (multimesh->data_cache_dirty_regions[i]) {
+ if (multimesh->data_cache_dirty_regions[i] || multimesh->previous_data_cache_dirty_regions[i]) {
uint32_t offset = i * region_size;
uint32_t size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float);
uint32_t region_start_index = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * i;
- RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[region_start_index]);
+ RD::get_singleton()->buffer_update(multimesh->buffer, buffer_offset * sizeof(float) + offset, MIN(region_size, size - offset), &data[region_start_index], RD::BARRIER_MASK_NO_BARRIER);
}
}
+ RD::get_singleton()->barrier(RD::BARRIER_MASK_NO_BARRIER, RD::BARRIER_MASK_ALL);
}
- for (uint32_t i = 0; i < data_cache_dirty_region_count; i++) {
- multimesh->data_cache_dirty_regions[i] = false;
- }
+ memcpy(multimesh->previous_data_cache_dirty_regions, multimesh->data_cache_dirty_regions, data_cache_dirty_region_count * sizeof(bool));
+ memset(multimesh->data_cache_dirty_regions, 0, data_cache_dirty_region_count * sizeof(bool));
- multimesh->data_cache_used_dirty_regions = 0;
+ multimesh->previous_data_cache_dirty_region_count = multimesh->data_cache_dirty_region_count;
+ multimesh->data_cache_dirty_region_count = 0;
}
if (multimesh->aabb_dirty) {
diff --git a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
index 5c0d019c15..622f3911c7 100644
--- a/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/mesh_storage.h
@@ -205,13 +205,19 @@ private:
AABB aabb;
bool aabb_dirty = false;
bool buffer_set = false;
+ bool motion_vectors_enabled = false;
+ uint32_t motion_vectors_current_offset = 0;
+ uint32_t motion_vectors_previous_offset = 0;
+ uint64_t motion_vectors_last_change = -1;
uint32_t stride_cache = 0;
uint32_t color_offset_cache = 0;
uint32_t custom_data_offset_cache = 0;
Vector<float> data_cache; //used if individual setting is used
bool *data_cache_dirty_regions = nullptr;
- uint32_t data_cache_used_dirty_regions = 0;
+ uint32_t data_cache_dirty_region_count = 0;
+ bool *previous_data_cache_dirty_regions = nullptr;
+ uint32_t previous_data_cache_dirty_region_count = 0;
RID buffer; //storage buffer
RID uniform_set_3d;
@@ -228,6 +234,7 @@ private:
MultiMesh *multimesh_dirty_list = nullptr;
_FORCE_INLINE_ void _multimesh_make_local(MultiMesh *multimesh) const;
+ _FORCE_INLINE_ void _multimesh_update_motion_vectors_data_cache(MultiMesh *multimesh);
_FORCE_INLINE_ void _multimesh_mark_dirty(MultiMesh *multimesh, int p_index, bool p_aabb);
_FORCE_INLINE_ void _multimesh_mark_all_dirty(MultiMesh *multimesh, bool p_data, bool p_aabb);
_FORCE_INLINE_ void _multimesh_re_create_aabb(MultiMesh *multimesh, const float *p_data, int p_instances);
@@ -579,6 +586,8 @@ public:
virtual AABB multimesh_get_aabb(RID p_multimesh) const override;
void _update_dirty_multimeshes();
+ bool _multimesh_enable_motion_vectors(RID p_multimesh);
+ void _multimesh_get_motion_vectors_offsets(RID p_multimesh, uint32_t &r_current_offset, uint32_t &r_prev_offset);
_FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
new file mode 100644
index 0000000000..f925f87cbe
--- /dev/null
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.cpp
@@ -0,0 +1,246 @@
+/*************************************************************************/
+/* render_scene_data_rd.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "render_scene_data_rd.h"
+#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/light_storage.h"
+#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
+#include "servers/rendering/rendering_server_default.h"
+
+RID RenderSceneDataRD::create_uniform_buffer() {
+ return RD::get_singleton()->uniform_buffer_create(sizeof(UBODATA));
+}
+
+void RenderSceneDataRD::update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_flip_y, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers) {
+ RendererSceneRenderRD *render_scene_render = RendererSceneRenderRD::get_singleton();
+
+ UBODATA ubo_data;
+ memset(&ubo_data, 0, sizeof(UBODATA));
+
+ // just for easy access..
+ UBO &ubo = ubo_data.ubo;
+ UBO &prev_ubo = ubo_data.prev_ubo;
+
+ Projection correction;
+ correction.set_depth_correction(p_flip_y);
+ correction.add_jitter_offset(taa_jitter);
+ Projection projection = correction * cam_projection;
+
+ //store camera into ubo
+ RendererRD::MaterialStorage::store_camera(projection, ubo.projection_matrix);
+ RendererRD::MaterialStorage::store_camera(projection.inverse(), ubo.inv_projection_matrix);
+ RendererRD::MaterialStorage::store_transform(cam_transform, ubo.inv_view_matrix);
+ RendererRD::MaterialStorage::store_transform(cam_transform.affine_inverse(), ubo.view_matrix);
+
+ for (uint32_t v = 0; v < view_count; v++) {
+ projection = correction * view_projection[v];
+ RendererRD::MaterialStorage::store_camera(projection, ubo.projection_matrix_view[v]);
+ RendererRD::MaterialStorage::store_camera(projection.inverse(), ubo.inv_projection_matrix_view[v]);
+
+ ubo.eye_offset[v][0] = view_eye_offset[v].x;
+ ubo.eye_offset[v][1] = view_eye_offset[v].y;
+ ubo.eye_offset[v][2] = view_eye_offset[v].z;
+ ubo.eye_offset[v][3] = 0.0;
+ }
+
+ ubo.taa_jitter[0] = taa_jitter.x;
+ ubo.taa_jitter[1] = taa_jitter.y;
+
+ ubo.z_far = z_far;
+ ubo.z_near = z_near;
+
+ ubo.pancake_shadows = p_pancake_shadows;
+
+ RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->directional_penumbra_shadow_kernel_get(), ubo.directional_penumbra_shadow_kernel);
+ RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->directional_soft_shadow_kernel_get(), ubo.directional_soft_shadow_kernel);
+ RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->penumbra_shadow_kernel_get(), ubo.penumbra_shadow_kernel);
+ RendererRD::MaterialStorage::store_soft_shadow_kernel(render_scene_render->soft_shadow_kernel_get(), ubo.soft_shadow_kernel);
+
+ ubo.viewport_size[0] = p_screen_size.x;
+ ubo.viewport_size[1] = p_screen_size.y;
+
+ Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
+ ubo.screen_pixel_size[0] = screen_pixel_size.x;
+ ubo.screen_pixel_size[1] = screen_pixel_size.y;
+
+ ubo.shadow_atlas_pixel_size[0] = shadow_atlas_pixel_size.x;
+ ubo.shadow_atlas_pixel_size[1] = shadow_atlas_pixel_size.y;
+
+ ubo.directional_shadow_pixel_size[0] = directional_shadow_pixel_size.x;
+ ubo.directional_shadow_pixel_size[1] = directional_shadow_pixel_size.y;
+
+ ubo.time = time;
+
+ ubo.directional_light_count = directional_light_count;
+ ubo.dual_paraboloid_side = dual_paraboloid_side;
+ ubo.opaque_prepass_threshold = opaque_prepass_threshold;
+ ubo.material_uv2_mode = material_uv2_mode;
+
+ ubo.fog_enabled = false;
+
+ if (p_debug_mode == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) {
+ ubo.use_ambient_light = true;
+ ubo.ambient_light_color_energy[0] = 1;
+ ubo.ambient_light_color_energy[1] = 1;
+ ubo.ambient_light_color_energy[2] = 1;
+ ubo.ambient_light_color_energy[3] = 1.0;
+ ubo.use_ambient_cubemap = false;
+ ubo.use_reflection_cubemap = false;
+ } else if (p_env.is_valid()) {
+ RS::EnvironmentBG env_bg = render_scene_render->environment_get_background(p_env);
+ RS::EnvironmentAmbientSource ambient_src = render_scene_render->environment_get_ambient_source(p_env);
+
+ float bg_energy_multiplier = render_scene_render->environment_get_bg_energy_multiplier(p_env);
+
+ ubo.ambient_light_color_energy[3] = bg_energy_multiplier;
+
+ ubo.ambient_color_sky_mix = render_scene_render->environment_get_ambient_sky_contribution(p_env);
+
+ //ambient
+ if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
+ Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : render_scene_render->environment_get_bg_color(p_env);
+ color = color.srgb_to_linear();
+
+ ubo.ambient_light_color_energy[0] = color.r * bg_energy_multiplier;
+ ubo.ambient_light_color_energy[1] = color.g * bg_energy_multiplier;
+ ubo.ambient_light_color_energy[2] = color.b * bg_energy_multiplier;
+ ubo.use_ambient_light = true;
+ ubo.use_ambient_cubemap = false;
+ } else {
+ float energy = render_scene_render->environment_get_ambient_light_energy(p_env);
+ Color color = render_scene_render->environment_get_ambient_light(p_env);
+ color = color.srgb_to_linear();
+ ubo.ambient_light_color_energy[0] = color.r * energy;
+ ubo.ambient_light_color_energy[1] = color.g * energy;
+ ubo.ambient_light_color_energy[2] = color.b * energy;
+
+ Basis sky_transform = render_scene_render->environment_get_sky_orientation(p_env);
+ sky_transform = sky_transform.inverse() * cam_transform.basis;
+ RendererRD::MaterialStorage::store_transform_3x3(sky_transform, ubo.radiance_inverse_xform);
+
+ ubo.use_ambient_cubemap = (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ambient_src == RS::ENV_AMBIENT_SOURCE_SKY;
+ ubo.use_ambient_light = ubo.use_ambient_cubemap || ambient_src == RS::ENV_AMBIENT_SOURCE_COLOR;
+ }
+
+ //specular
+ RS::EnvironmentReflectionSource ref_src = render_scene_render->environment_get_reflection_source(p_env);
+ if ((ref_src == RS::ENV_REFLECTION_SOURCE_BG && env_bg == RS::ENV_BG_SKY) || ref_src == RS::ENV_REFLECTION_SOURCE_SKY) {
+ ubo.use_reflection_cubemap = true;
+ } else {
+ ubo.use_reflection_cubemap = false;
+ }
+
+ ubo.fog_enabled = render_scene_render->environment_get_fog_enabled(p_env);
+ ubo.fog_density = render_scene_render->environment_get_fog_density(p_env);
+ ubo.fog_height = render_scene_render->environment_get_fog_height(p_env);
+ ubo.fog_height_density = render_scene_render->environment_get_fog_height_density(p_env);
+ ubo.fog_aerial_perspective = render_scene_render->environment_get_fog_aerial_perspective(p_env);
+
+ Color fog_color = render_scene_render->environment_get_fog_light_color(p_env).srgb_to_linear();
+ float fog_energy = render_scene_render->environment_get_fog_light_energy(p_env);
+
+ ubo.fog_light_color[0] = fog_color.r * fog_energy;
+ ubo.fog_light_color[1] = fog_color.g * fog_energy;
+ ubo.fog_light_color[2] = fog_color.b * fog_energy;
+
+ ubo.fog_sun_scatter = render_scene_render->environment_get_fog_sun_scatter(p_env);
+ } else {
+ if (p_reflection_probe_instance.is_valid() && RendererRD::LightStorage::get_singleton()->reflection_probe_is_interior(p_reflection_probe_instance)) {
+ ubo.use_ambient_light = false;
+ } else {
+ ubo.use_ambient_light = true;
+ Color clear_color = p_default_bg_color;
+ clear_color = clear_color.srgb_to_linear();
+ ubo.ambient_light_color_energy[0] = clear_color.r;
+ ubo.ambient_light_color_energy[1] = clear_color.g;
+ ubo.ambient_light_color_energy[2] = clear_color.b;
+ ubo.ambient_light_color_energy[3] = 1.0;
+ }
+
+ ubo.use_ambient_cubemap = false;
+ ubo.use_reflection_cubemap = false;
+ }
+
+ if (p_camera_attributes.is_valid()) {
+ ubo.emissive_exposure_normalization = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes);
+ ubo.IBL_exposure_normalization = 1.0;
+ if (p_env.is_valid()) {
+ RID sky_rid = render_scene_render->environment_get_sky(p_env);
+ if (sky_rid.is_valid()) {
+ float current_exposure = RSG::camera_attributes->camera_attributes_get_exposure_normalization_factor(p_camera_attributes) * render_scene_render->environment_get_bg_intensity(p_env) / p_luminance_multiplier;
+ ubo.IBL_exposure_normalization = current_exposure / MAX(0.001, render_scene_render->get_sky()->sky_get_baked_exposure(sky_rid));
+ }
+ }
+ } else if (emissive_exposure_normalization > 0.0) {
+ // This branch is triggered when using render_material().
+ // Emissive is set outside the function.
+ ubo.emissive_exposure_normalization = emissive_exposure_normalization;
+ // IBL isn't used don't set it.
+ } else {
+ ubo.emissive_exposure_normalization = 1.0;
+ ubo.IBL_exposure_normalization = 1.0;
+ }
+
+ ubo.roughness_limiter_enabled = p_opaque_render_buffers && render_scene_render->screen_space_roughness_limiter_is_active();
+ ubo.roughness_limiter_amount = render_scene_render->screen_space_roughness_limiter_get_amount();
+ ubo.roughness_limiter_limit = render_scene_render->screen_space_roughness_limiter_get_limit();
+
+ if (calculate_motion_vectors) {
+ // Q : Should we make a complete copy or should we define a separate UBO with just the components we need?
+ memcpy(&prev_ubo, &ubo, sizeof(UBO));
+
+ Projection prev_correction;
+ prev_correction.set_depth_correction(true);
+ prev_correction.add_jitter_offset(prev_taa_jitter);
+ Projection prev_projection = prev_correction * prev_cam_projection;
+
+ //store camera into ubo
+ RendererRD::MaterialStorage::store_camera(prev_projection, prev_ubo.projection_matrix);
+ RendererRD::MaterialStorage::store_camera(prev_projection.inverse(), prev_ubo.inv_projection_matrix);
+ RendererRD::MaterialStorage::store_transform(prev_cam_transform, prev_ubo.inv_view_matrix);
+ RendererRD::MaterialStorage::store_transform(prev_cam_transform.affine_inverse(), prev_ubo.view_matrix);
+
+ for (uint32_t v = 0; v < view_count; v++) {
+ prev_projection = prev_correction * view_projection[v];
+ RendererRD::MaterialStorage::store_camera(prev_projection, prev_ubo.projection_matrix_view[v]);
+ RendererRD::MaterialStorage::store_camera(prev_projection.inverse(), prev_ubo.inv_projection_matrix_view[v]);
+ }
+ prev_ubo.taa_jitter[0] = prev_taa_jitter.x;
+ prev_ubo.taa_jitter[1] = prev_taa_jitter.y;
+ prev_ubo.time -= time_step;
+ }
+
+ uniform_buffer = p_uniform_buffer;
+ RD::get_singleton()->buffer_update(uniform_buffer, 0, sizeof(UBODATA), &ubo, RD::BARRIER_MASK_RASTER);
+}
+
+RID RenderSceneDataRD::get_uniform_buffer() {
+ return uniform_buffer;
+}
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
new file mode 100644
index 0000000000..c2dc7d5f4c
--- /dev/null
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_data_rd.h
@@ -0,0 +1,157 @@
+/*************************************************************************/
+/* render_scene_data_rd.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 RENDER_SCENE_DATA_RD_H
+#define RENDER_SCENE_DATA_RD_H
+
+#include "render_scene_buffers_rd.h"
+#include "servers/rendering/renderer_scene_render.h"
+#include "servers/rendering/rendering_device.h"
+
+// This is a container for data related to rendering a single frame of a viewport where we load this data into a UBO
+// that can be used by the main scene shader but also by various effects.
+
+class RenderSceneDataRD {
+public:
+ bool calculate_motion_vectors = false;
+
+ Transform3D cam_transform;
+ Projection cam_projection;
+ Vector2 taa_jitter;
+ bool cam_orthogonal = false;
+
+ // For stereo rendering
+ uint32_t view_count = 1;
+ Vector3 view_eye_offset[RendererSceneRender::MAX_RENDER_VIEWS];
+ Projection view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
+
+ Transform3D prev_cam_transform;
+ Projection prev_cam_projection;
+ Vector2 prev_taa_jitter;
+ Projection prev_view_projection[RendererSceneRender::MAX_RENDER_VIEWS];
+
+ float z_near = 0.0;
+ float z_far = 0.0;
+
+ float lod_distance_multiplier = 0.0;
+ Plane lod_camera_plane;
+ float screen_mesh_lod_threshold = 0.0;
+
+ uint32_t directional_light_count = 0;
+ float dual_paraboloid_side = 0.0;
+ float opaque_prepass_threshold = 0.0;
+ bool material_uv2_mode = false;
+ float emissive_exposure_normalization = 0.0;
+
+ Size2 shadow_atlas_pixel_size;
+ Size2 directional_shadow_pixel_size;
+
+ float time;
+ float time_step;
+
+ RID create_uniform_buffer();
+ void update_ubo(RID p_uniform_buffer, RS::ViewportDebugDraw p_debug_mode, RID p_env, RID p_reflection_probe_instance, RID p_camera_attributes, bool p_flip_y, bool p_pancake_shadows, const Size2i &p_screen_size, const Color &p_default_bg_color, float p_luminance_multiplier, bool p_opaque_render_buffers);
+ RID get_uniform_buffer();
+
+private:
+ RID uniform_buffer; // loaded into this uniform buffer (supplied externally)
+
+ // This struct is loaded into Set 1 - Binding 0, populated at start of rendering a frame, must match with shader code
+ struct UBO {
+ float projection_matrix[16];
+ float inv_projection_matrix[16];
+ float inv_view_matrix[16];
+ float view_matrix[16];
+
+ float projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
+ float inv_projection_matrix_view[RendererSceneRender::MAX_RENDER_VIEWS][16];
+ float eye_offset[RendererSceneRender::MAX_RENDER_VIEWS][4];
+
+ float viewport_size[2];
+ float screen_pixel_size[2];
+
+ float directional_penumbra_shadow_kernel[128]; //32 vec4s
+ float directional_soft_shadow_kernel[128];
+ float penumbra_shadow_kernel[128];
+ float soft_shadow_kernel[128];
+
+ float radiance_inverse_xform[12];
+
+ float ambient_light_color_energy[4];
+
+ float ambient_color_sky_mix;
+ uint32_t use_ambient_light;
+ uint32_t use_ambient_cubemap;
+ uint32_t use_reflection_cubemap;
+
+ float shadow_atlas_pixel_size[2];
+ float directional_shadow_pixel_size[2];
+
+ uint32_t directional_light_count;
+ float dual_paraboloid_side;
+ float z_far;
+ float z_near;
+
+ uint32_t roughness_limiter_enabled;
+ float roughness_limiter_amount;
+ float roughness_limiter_limit;
+ float opaque_prepass_threshold;
+
+ // Fog
+ uint32_t fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
+
+ float fog_light_color[3];
+ float fog_sun_scatter;
+
+ float fog_aerial_perspective;
+ float time;
+ float reflection_multiplier;
+ uint32_t material_uv2_mode;
+
+ float taa_jitter[2];
+ float emissive_exposure_normalization; // Needed to normalize emissive when using physical units.
+ float IBL_exposure_normalization; // Adjusts for baked exposure.
+
+ uint32_t pancake_shadows;
+ uint32_t pad1;
+ uint32_t pad2;
+ uint32_t pad3;
+ };
+
+ struct UBODATA {
+ UBO ubo;
+ UBO prev_ubo;
+ };
+};
+
+#endif // RENDER_SCENE_DATA_RD_H
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index eacd9bbbc2..54d07dd3e1 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -179,7 +179,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
// to compensate for the loss of sharpness.
const float texture_mipmap_bias = log2f(MIN(scaling_3d_scale, 1.0)) + p_viewport->texture_mipmap_bias;
- p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->get_view_count());
+ p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->view_count);
}
}
}
@@ -616,14 +616,7 @@ void RendererViewport::draw_viewports() {
if (xr_interface.is_valid()) {
// Override our size, make sure it matches our required size and is created as a stereo target
Size2 xr_size = xr_interface->get_render_target_size();
-
- // Would have been nice if we could call viewport_set_size here,
- // but alas that takes our RID and we now have our pointer,
- // also we only check if view_count changes in render_target_set_size so we need to call that for this to reliably change
- vp->occlusion_buffer_dirty = vp->occlusion_buffer_dirty || (vp->size != xr_size);
- vp->size = xr_size;
- uint32_t view_count = xr_interface->get_view_count();
- RSG::texture_storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count);
+ _viewport_set_size(vp, xr_size.width, xr_size.height, xr_interface->get_view_count());
// Inform xr interface we're about to render its viewport, if this returns false we don't render
visible = xr_interface->pre_draw_viewport(vp->render_target);
@@ -686,12 +679,17 @@ void RendererViewport::draw_viewports() {
// commit our eyes
Vector<BlitToScreen> blits = xr_interface->post_draw_viewport(vp->render_target, vp->viewport_to_screen_rect);
if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID && blits.size() > 0) {
- if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
- blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
- }
+ if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") {
+ RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blits.ptr(), blits.size());
+ RSG::rasterizer->end_frame(true);
+ } else {
+ if (!blit_to_screen_list.has(vp->viewport_to_screen)) {
+ blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
+ }
- for (int b = 0; b < blits.size(); b++) {
- blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]);
+ for (int b = 0; b < blits.size(); b++) {
+ blit_to_screen_list[vp->viewport_to_screen].push_back(blits[b]);
+ }
}
}
} else {
@@ -777,7 +775,13 @@ void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
}
viewport->use_xr = p_use_xr;
- _configure_3d_render_buffers(viewport);
+
+ // Re-configure the 3D render buffers when disabling XR. They'll get
+ // re-configured when enabling XR in draw_viewports().
+ if (!p_use_xr) {
+ viewport->view_count = 1;
+ _configure_3d_render_buffers(viewport);
+ }
}
void RendererViewport::viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode) {
@@ -823,34 +827,27 @@ void RendererViewport::viewport_set_scaling_3d_scale(RID p_viewport, float p_sca
_configure_3d_render_buffers(viewport);
}
-uint32_t RendererViewport::Viewport::get_view_count() {
- uint32_t view_count = 1;
-
- if (use_xr && XRServer::get_singleton() != nullptr) {
- Ref<XRInterface> xr_interface;
-
- xr_interface = XRServer::get_singleton()->get_primary_interface();
- if (xr_interface.is_valid()) {
- view_count = xr_interface->get_view_count();
- }
- }
-
- return view_count;
-}
-
void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) {
ERR_FAIL_COND(p_width < 0 && p_height < 0);
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
+ ERR_FAIL_COND_MSG(viewport->use_xr, "Cannot set viewport size when using XR");
- viewport->size = Size2(p_width, p_height);
+ _viewport_set_size(viewport, p_width, p_height, 1);
+}
- uint32_t view_count = viewport->get_view_count();
- RSG::texture_storage->render_target_set_size(viewport->render_target, p_width, p_height, view_count);
- _configure_3d_render_buffers(viewport);
+void RendererViewport::_viewport_set_size(Viewport *p_viewport, int p_width, int p_height, uint32_t p_view_count) {
+ Size2i new_size(p_width, p_height);
+ if (p_viewport->size != new_size || p_viewport->view_count != p_view_count) {
+ p_viewport->size = new_size;
+ p_viewport->view_count = p_view_count;
- viewport->occlusion_buffer_dirty = true;
+ RSG::texture_storage->render_target_set_size(p_viewport->render_target, p_width, p_height, p_view_count);
+ _configure_3d_render_buffers(p_viewport);
+
+ p_viewport->occlusion_buffer_dirty = true;
+ }
}
void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) {
@@ -890,7 +887,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_
// If using OpenGL we can optimize this operation by rendering directly to system_fbo
// instead of rendering to fbo and copying to system_fbo after
if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
- RSG::texture_storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->get_view_count());
+ RSG::texture_storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->view_count);
RSG::texture_storage->render_target_set_position(viewport->render_target, p_rect.position.x, p_rect.position.y);
}
@@ -900,7 +897,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_
// if render_direct_to_screen was used, reset size and position
if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
RSG::texture_storage->render_target_set_position(viewport->render_target, 0, 0);
- RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count());
+ RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->view_count);
}
viewport->viewport_to_screen_rect = Rect2();
@@ -919,7 +916,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool
// if disabled, reset render_target size and position
if (!p_enable) {
RSG::texture_storage->render_target_set_position(viewport->render_target, 0, 0);
- RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count());
+ RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->view_count);
}
RSG::texture_storage->render_target_set_direct_to_screen(viewport->render_target, p_enable);
@@ -927,7 +924,7 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool
// if attached to screen already, setup screen size and position, this needs to happen after setting flag to avoid an unnecessary buffer allocation
if (RSG::rasterizer->is_low_end() && viewport->viewport_to_screen_rect != Rect2() && p_enable) {
- RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y, viewport->get_view_count());
+ RSG::texture_storage->render_target_set_size(viewport->render_target, viewport->viewport_to_screen_rect.size.x, viewport->viewport_to_screen_rect.size.y, viewport->view_count);
RSG::texture_storage->render_target_set_position(viewport->render_target, viewport->viewport_to_screen_rect.position.x, viewport->viewport_to_screen_rect.position.y);
}
}
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index a123c70372..08ba6abc74 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -54,6 +54,7 @@ public:
Size2i internal_size;
Size2i size;
+ uint32_t view_count;
RID camera;
RID scenario;
@@ -150,6 +151,7 @@ public:
RendererScene::RenderInfo render_info;
Viewport() {
+ view_count = 1;
update_mode = RS::VIEWPORT_UPDATE_WHEN_VISIBLE;
clear_mode = RS::VIEWPORT_CLEAR_ALWAYS;
transparent_bg = false;
@@ -176,8 +178,6 @@ public:
time_gpu_begin = 0;
time_gpu_end = 0;
}
-
- uint32_t get_view_count();
};
HashMap<String, RID> timestamp_vp_map;
@@ -196,6 +196,7 @@ public:
private:
Vector<Viewport *> _sort_active_viewports();
+ void _viewport_set_size(Viewport *p_viewport, int p_width, int p_height, uint32_t p_view_count);
void _configure_3d_render_buffers(Viewport *p_viewport);
void _draw_3d(Viewport *p_viewport);
void _draw_viewport(Viewport *p_viewport);
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 47cb38f268..cd063f91ac 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -340,6 +340,11 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["INDEX"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["EMISSION_TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RANDOM_SEED"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_POSITION"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_ROT_SCALE"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_VELOCITY"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_COLOR"] = constt(ShaderLanguage::TYPE_UINT);
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["FLAG_EMIT_CUSTOM"] = constt(ShaderLanguage::TYPE_UINT);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_POSITION"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_ROT_SCALE"] = constt(ShaderLanguage::TYPE_BOOL);
shader_modes[RS::SHADER_PARTICLES].functions["start"].built_ins["RESTART_VELOCITY"] = constt(ShaderLanguage::TYPE_BOOL);
@@ -385,6 +390,7 @@ ShaderTypes::ShaderTypes() {
emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("custom", ShaderLanguage::TYPE_VEC4));
emit_vertex_func.arguments.push_back(ShaderLanguage::StageFunctionInfo::Argument("flags", ShaderLanguage::TYPE_UINT));
emit_vertex_func.return_type = ShaderLanguage::TYPE_BOOL; //whether it could emit
+ shader_modes[RS::SHADER_PARTICLES].functions["start"].stage_functions["emit_subparticle"] = emit_vertex_func;
shader_modes[RS::SHADER_PARTICLES].functions["process"].stage_functions["emit_subparticle"] = emit_vertex_func;
}
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index aa3351c815..cbcfc8fe49 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -1114,7 +1114,8 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
for (int j = 0; j < p_vertex_len; j++) {
const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]];
- w[j] = Vector3((v & 0x3FF) / 1023.0, ((v >> 10) & 0x3FF) / 1023.0, ((v >> 20) & 0x3FF) / 1023.0) * Vector3(2, 2, 2) - Vector3(1, 1, 1);
+
+ w[j] = Vector3::octahedron_decode(Vector2((v & 0xFFFF) / 65535.0, ((v >> 16) & 0xFFFF) / 65535.0));
}
ret[i] = arr;
@@ -1129,11 +1130,12 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t
for (int j = 0; j < p_vertex_len; j++) {
const uint32_t v = *(const uint32_t *)&r[j * vertex_elem_size + offsets[i]];
-
- w[j * 4 + 0] = ((v & 0x3FF) / 1023.0) * 2.0 - 1.0;
- w[j * 4 + 1] = (((v >> 10) & 0x3FF) / 1023.0) * 2.0 - 1.0;
- w[j * 4 + 2] = (((v >> 20) & 0x3FF) / 1023.0) * 2.0 - 1.0;
- w[j * 4 + 3] = ((v >> 30) / 3.0) * 2.0 - 1.0;
+ float tangent_sign;
+ Vector3 res = Vector3::octahedron_tangent_decode(Vector2((v & 0xFFFF) / 65535.0, ((v >> 16) & 0xFFFF) / 65535.0), &tangent_sign);
+ w[j * 4 + 0] = res.x;
+ w[j * 4 + 1] = res.y;
+ w[j * 4 + 2] = res.z;
+ w[j * 4 + 3] = tangent_sign;
}
ret[i] = arr;
diff --git a/tests/core/math/test_basis.h b/tests/core/math/test_basis.h
index ae8ca4acde..b6493c5726 100644
--- a/tests/core/math/test_basis.h
+++ b/tests/core/math/test_basis.h
@@ -47,7 +47,7 @@ enum RotOrder {
EulerZYX
};
-Vector3 deg2rad(const Vector3 &p_rotation) {
+Vector3 deg_to_rad(const Vector3 &p_rotation) {
return p_rotation / 180.0 * Math_PI;
}
@@ -155,7 +155,7 @@ void test_rotation(Vector3 deg_original_euler, RotOrder rot_order) {
// are correct.
// Euler to rotation
- const Vector3 original_euler = deg2rad(deg_original_euler);
+ const Vector3 original_euler = deg_to_rad(deg_original_euler);
const Basis to_rotation = EulerToBasis(rot_order, original_euler);
// Euler from rotation
@@ -281,6 +281,59 @@ TEST_CASE("[Stress][Basis] Euler conversions") {
}
}
}
+
+TEST_CASE("[Basis] Set axis angle") {
+ Vector3 axis;
+ real_t angle;
+ real_t pi = (real_t)Math_PI;
+
+ // Testing the singularity when the angle is 0°.
+ Basis identity(1, 0, 0, 0, 1, 0, 0, 0, 1);
+ identity.get_axis_angle(axis, angle);
+ CHECK(angle == 0);
+
+ // Testing the singularity when the angle is 180°.
+ Basis singularityPi(-1, 0, 0, 0, 1, 0, 0, 0, -1);
+ singularityPi.get_axis_angle(axis, angle);
+ CHECK(Math::is_equal_approx(angle, pi));
+
+ // Testing reversing the an axis (of an 30° angle).
+ float cos30deg = Math::cos(Math::deg_to_rad((real_t)30.0));
+ Basis z_positive(cos30deg, -0.5, 0, 0.5, cos30deg, 0, 0, 0, 1);
+ Basis z_negative(cos30deg, 0.5, 0, -0.5, cos30deg, 0, 0, 0, 1);
+
+ z_positive.get_axis_angle(axis, angle);
+ CHECK(Math::is_equal_approx(angle, Math::deg_to_rad((real_t)30.0)));
+ CHECK(axis == Vector3(0, 0, 1));
+
+ z_negative.get_axis_angle(axis, angle);
+ CHECK(Math::is_equal_approx(angle, Math::deg_to_rad((real_t)30.0)));
+ CHECK(axis == Vector3(0, 0, -1));
+
+ // Testing a rotation of 90° on x-y-z.
+ Basis x90deg(1, 0, 0, 0, 0, -1, 0, 1, 0);
+ x90deg.get_axis_angle(axis, angle);
+ CHECK(Math::is_equal_approx(angle, pi / (real_t)2));
+ CHECK(axis == Vector3(1, 0, 0));
+
+ Basis y90deg(0, 0, 1, 0, 1, 0, -1, 0, 0);
+ y90deg.get_axis_angle(axis, angle);
+ CHECK(axis == Vector3(0, 1, 0));
+
+ Basis z90deg(0, -1, 0, 1, 0, 0, 0, 0, 1);
+ z90deg.get_axis_angle(axis, angle);
+ CHECK(axis == Vector3(0, 0, 1));
+
+ // Regression test: checks that the method returns a small angle (not 0).
+ Basis tiny(1, 0, 0, 0, 0.9999995, -0.001, 0, 001, 0.9999995); // The min angle possible with float is 0.001rad.
+ tiny.get_axis_angle(axis, angle);
+ CHECK(Math::is_equal_approx(angle, (real_t)0.001, (real_t)0.0001));
+
+ // Regression test: checks that the method returns an angle which is a number (not NaN)
+ Basis bugNan(1.00000024, 0, 0.000100001693, 0, 1, 0, -0.000100009143, 0, 1.00000024);
+ bugNan.get_axis_angle(axis, angle);
+ CHECK(!Math::is_nan(angle));
+}
} // namespace TestBasis
#endif // TEST_BASIS_H
diff --git a/version.py b/version.py
index f9aa1dd0f4..cfa1773b85 100644
--- a/version.py
+++ b/version.py
@@ -3,7 +3,7 @@ name = "Godot Engine"
major = 4
minor = 0
patch = 0
-status = "alpha"
+status = "beta"
module_config = ""
year = 2022
website = "https://godotengine.org"