summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/io/image.cpp4
-rw-r--r--core/io/image.h2
-rw-r--r--core/io/resource.cpp96
-rw-r--r--core/io/resource.h4
-rw-r--r--core/io/resource_format_binary.cpp10
-rw-r--r--core/io/resource_loader.cpp51
-rw-r--r--core/object/object.h2
-rw-r--r--doc/classes/@GlobalScope.xml2
-rw-r--r--doc/classes/ColorPickerButton.xml2
-rw-r--r--doc/classes/Control.xml16
-rw-r--r--doc/classes/HTTPRequest.xml30
-rw-r--r--doc/classes/Image.xml8
-rw-r--r--doc/classes/NavigationMeshGenerator.xml1
-rw-r--r--doc/classes/NavigationServer2D.xml20
-rw-r--r--doc/classes/NavigationServer3D.xml20
-rw-r--r--doc/classes/ScrollContainer.xml2
-rw-r--r--editor/dependency_editor.cpp2
-rw-r--r--editor/editor_file_system.cpp9
-rw-r--r--editor/editor_folding.cpp5
-rw-r--r--editor/editor_node.cpp10
-rw-r--r--editor/editor_properties.cpp2
-rw-r--r--editor/editor_property_name_processor.cpp1
-rw-r--r--editor/editor_themes.cpp18
-rw-r--r--editor/import/resource_importer_scene.cpp4
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp6
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp2
-rw-r--r--modules/gdscript/gdscript.cpp20
-rw-r--r--modules/gdscript/gdscript.h1
-rw-r--r--modules/gdscript/gdscript_compiler.cpp31
-rw-r--r--modules/gdscript/gdscript_editor.cpp2
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp45
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.h9
-rw-r--r--modules/lightmapper_rd/lm_common_inc.glsl3
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl86
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs2
-rw-r--r--modules/navigation/godot_navigation_server.cpp19
-rw-r--r--modules/navigation/godot_navigation_server.h4
-rw-r--r--modules/visual_script/visual_script_flow_control.cpp2
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp12
-rw-r--r--scene/2d/node_2d.cpp2
-rw-r--r--scene/3d/lightmap_gi.cpp6
-rw-r--r--scene/3d/lightmapper.h6
-rw-r--r--scene/3d/node_3d.cpp2
-rw-r--r--scene/debugger/scene_debugger.cpp4
-rw-r--r--scene/gui/control.cpp2
-rw-r--r--scene/gui/dialogs.cpp4
-rw-r--r--scene/gui/file_dialog.cpp46
-rw-r--r--scene/gui/progress_bar.cpp4
-rw-r--r--scene/resources/primitive_meshes.cpp7
-rw-r--r--scene/resources/resource_format_text.cpp22
-rw-r--r--servers/navigation_server_2d.cpp8
-rw-r--r--servers/navigation_server_2d.h4
-rw-r--r--servers/navigation_server_3d.cpp3
-rw-r--r--servers/navigation_server_3d.h4
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.cpp402
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.h96
-rw-r--r--servers/rendering/renderer_rd/effects_rd.cpp307
-rw-r--r--servers/rendering/renderer_rd/effects_rd.h88
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp4
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp52
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl (renamed from servers/rendering/renderer_rd/shaders/cube_to_dp.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl (renamed from servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_inc.glsl (renamed from servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl (renamed from servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl (renamed from servers/rendering/renderer_rd/shaders/cubemap_filter.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl (renamed from servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl (renamed from servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_inc.glsl (renamed from servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl)0
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl (renamed from servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl)0
69 files changed, 966 insertions, 672 deletions
diff --git a/core/io/image.cpp b/core/io/image.cpp
index 97a46c29db..f065dac212 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -2324,11 +2324,11 @@ Error Image::save_exr(const String &p_path, bool p_grayscale) const {
return save_exr_func(p_path, Ref<Image>((Image *)this), p_grayscale);
}
-Vector<uint8_t> Image::save_exr_to_buffer() const {
+Vector<uint8_t> Image::save_exr_to_buffer(bool p_grayscale) const {
if (save_exr_buffer_func == nullptr) {
return Vector<uint8_t>();
}
- return save_exr_buffer_func(Ref<Image>((Image *)this), false);
+ return save_exr_buffer_func(Ref<Image>((Image *)this), p_grayscale);
}
Error Image::save_webp(const String &p_path, const bool p_lossy, const float p_quality) const {
diff --git a/core/io/image.h b/core/io/image.h
index 10c1156dae..2cad26f3e9 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -294,7 +294,7 @@ public:
Error save_jpg(const String &p_path, float p_quality = 0.75) const;
Vector<uint8_t> save_png_to_buffer() const;
Vector<uint8_t> save_jpg_to_buffer(float p_quality = 0.75) const;
- Vector<uint8_t> save_exr_to_buffer() const;
+ Vector<uint8_t> save_exr_to_buffer(bool p_grayscale) const;
Error save_exr(const String &p_path, bool p_grayscale) const;
Error save_webp(const String &p_path, const bool p_lossy = false, const float p_quality = 0.75f) const;
Vector<uint8_t> save_webp_to_buffer(const bool p_lossy = false, const float p_quality = 0.75f) const;
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index ed7228d0b9..fec5ca5c7b 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -52,41 +52,36 @@ void Resource::set_path(const String &p_path, bool p_take_over) {
return;
}
+ if (p_path.is_empty()) {
+ p_take_over = false; // Can't take over an empty path
+ }
+
+ ResourceCache::lock.lock();
+
if (!path_cache.is_empty()) {
- ResourceCache::lock.write_lock();
ResourceCache::resources.erase(path_cache);
- ResourceCache::lock.write_unlock();
}
path_cache = "";
- ResourceCache::lock.read_lock();
- bool has_path = ResourceCache::resources.has(p_path);
- ResourceCache::lock.read_unlock();
+ Ref<Resource> existing = ResourceCache::get_ref(p_path);
- if (has_path) {
+ if (existing.is_valid()) {
if (p_take_over) {
- ResourceCache::lock.write_lock();
- Resource **res = ResourceCache::resources.getptr(p_path);
- if (res) {
- (*res)->set_name("");
- }
- ResourceCache::lock.write_unlock();
+ existing->path_cache = String();
+ ResourceCache::resources.erase(p_path);
} else {
- ResourceCache::lock.read_lock();
- bool exists = ResourceCache::resources.has(p_path);
- ResourceCache::lock.read_unlock();
-
- ERR_FAIL_COND_MSG(exists, "Another resource is loaded from path '" + p_path + "' (possible cyclic resource inclusion).");
+ ResourceCache::lock.unlock();
+ ERR_FAIL_MSG("Another resource is loaded from path '" + p_path + "' (possible cyclic resource inclusion).");
}
}
+
path_cache = p_path;
if (!path_cache.is_empty()) {
- ResourceCache::lock.write_lock();
ResourceCache::resources[path_cache] = this;
- ResourceCache::lock.write_unlock();
}
+ ResourceCache::lock.unlock();
_resource_path_changed();
}
@@ -380,7 +375,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) {
return;
}
- ResourceCache::lock.write_lock();
+ ResourceCache::lock.lock();
if (p_remapped) {
ResourceLoader::remapped_list.add(&remapped_list);
@@ -388,7 +383,7 @@ void Resource::set_as_translation_remapped(bool p_remapped) {
ResourceLoader::remapped_list.remove(&remapped_list);
}
- ResourceCache::lock.write_unlock();
+ ResourceCache::lock.unlock();
}
bool Resource::is_translation_remapped() const {
@@ -455,9 +450,9 @@ Resource::Resource() :
Resource::~Resource() {
if (!path_cache.is_empty()) {
- ResourceCache::lock.write_lock();
+ ResourceCache::lock.lock();
ResourceCache::resources.erase(path_cache);
- ResourceCache::lock.write_unlock();
+ ResourceCache::lock.unlock();
}
if (owners.size()) {
WARN_PRINT("Resource is still owned.");
@@ -469,7 +464,7 @@ HashMap<String, Resource *> ResourceCache::resources;
HashMap<String, HashMap<String, String>> ResourceCache::resource_path_cache;
#endif
-RWLock ResourceCache::lock;
+Mutex ResourceCache::lock;
#ifdef TOOLS_ENABLED
RWLock ResourceCache::path_cache_lock;
#endif
@@ -491,46 +486,67 @@ void ResourceCache::reload_externals() {
}
bool ResourceCache::has(const String &p_path) {
- lock.read_lock();
- bool b = resources.has(p_path);
- lock.read_unlock();
+ lock.lock();
+
+ Resource **res = resources.getptr(p_path);
- return b;
+ if (res && (*res)->reference_get_count() == 0) {
+ // This resource is in the process of being deleted, ignore its existence.
+ (*res)->path_cache = String();
+ resources.erase(p_path);
+ res = nullptr;
+ }
+
+ lock.unlock();
+
+ if (!res) {
+ return false;
+ }
+
+ return true;
}
-Resource *ResourceCache::get(const String &p_path) {
- lock.read_lock();
+Ref<Resource> ResourceCache::get_ref(const String &p_path) {
+ Ref<Resource> ref;
+ lock.lock();
Resource **res = resources.getptr(p_path);
- lock.read_unlock();
+ if (res) {
+ ref = Ref<Resource>(*res);
+ }
- if (!res) {
- return nullptr;
+ if (res && !ref.is_valid()) {
+ // This resource is in the process of being deleted, ignore its existence
+ (*res)->path_cache = String();
+ resources.erase(p_path);
+ res = nullptr;
}
- return *res;
+ lock.unlock();
+
+ return ref;
}
void ResourceCache::get_cached_resources(List<Ref<Resource>> *p_resources) {
- lock.read_lock();
+ lock.lock();
for (KeyValue<String, Resource *> &E : resources) {
p_resources->push_back(Ref<Resource>(E.value));
}
- lock.read_unlock();
+ lock.unlock();
}
int ResourceCache::get_cached_resource_count() {
- lock.read_lock();
+ lock.lock();
int rc = resources.size();
- lock.read_unlock();
+ lock.unlock();
return rc;
}
void ResourceCache::dump(const char *p_file, bool p_short) {
#ifdef DEBUG_ENABLED
- lock.read_lock();
+ lock.lock();
HashMap<String, int> type_count;
@@ -562,7 +578,7 @@ void ResourceCache::dump(const char *p_file, bool p_short) {
}
}
- lock.read_unlock();
+ lock.unlock();
#else
WARN_PRINT("ResourceCache::dump only with in debug builds.");
#endif
diff --git a/core/io/resource.h b/core/io/resource.h
index a45bc6e1e4..a2cde87990 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -153,7 +153,7 @@ public:
class ResourceCache {
friend class Resource;
friend class ResourceLoader; //need the lock
- static RWLock lock;
+ static Mutex lock;
static HashMap<String, Resource *> resources;
#ifdef TOOLS_ENABLED
static HashMap<String, HashMap<String, String>> resource_path_cache; // Each tscn has a set of resource paths and IDs.
@@ -166,7 +166,7 @@ class ResourceCache {
public:
static void reload_externals();
static bool has(const String &p_path);
- static Resource *get(const String &p_path);
+ static Ref<Resource> get_ref(const String &p_path);
static void dump(const char *p_file = nullptr, bool p_short = false);
static void get_cached_resources(List<Ref<Resource>> *p_resources);
static int get_cached_resource_count();
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 2469e1a4be..b1c50e829c 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -693,7 +693,7 @@ Error ResourceLoaderBinary::load() {
}
if (cache_mode == ResourceFormatLoader::CACHE_MODE_REUSE && ResourceCache::has(path)) {
- Ref<Resource> cached = ResourceCache::get(path);
+ Ref<Resource> cached = ResourceCache::get_ref(path);
if (cached.is_valid()) {
//already loaded, don't do anything
error = OK;
@@ -717,10 +717,10 @@ Error ResourceLoaderBinary::load() {
if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
//use the existing one
- Resource *r = ResourceCache::get(path);
- if (r->get_class() == t) {
- r->reset_state();
- res = Ref<Resource>(r);
+ Ref<Resource> cached = ResourceCache::get_ref(path);
+ if (cached->get_class() == t) {
+ cached->reset_state();
+ res = cached;
}
}
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index fb21db1a19..2cd455475c 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -335,23 +335,15 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
thread_load_mutex->unlock();
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Attempted to load a resource already being loaded from this thread, cyclic reference?");
}
- //lock first if possible
- ResourceCache::lock.read_lock();
-
- //get ptr
- Resource **rptr = ResourceCache::resources.getptr(local_path);
-
- if (rptr) {
- Ref<Resource> res(*rptr);
- //it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached
- if (res.is_valid()) {
- //referencing is fine
- load_task.resource = res;
- load_task.status = THREAD_LOAD_LOADED;
- load_task.progress = 1.0;
- }
+
+ Ref<Resource> existing = ResourceCache::get_ref(local_path);
+
+ if (existing.is_valid()) {
+ //referencing is fine
+ load_task.resource = existing;
+ load_task.status = THREAD_LOAD_LOADED;
+ load_task.progress = 1.0;
}
- ResourceCache::lock.read_unlock();
}
if (!p_source_resource.is_empty()) {
@@ -530,27 +522,18 @@ Ref<Resource> ResourceLoader::load(const String &p_path, const String &p_type_hi
}
//Is it cached?
- ResourceCache::lock.read_lock();
-
- Resource **rptr = ResourceCache::resources.getptr(local_path);
- if (rptr) {
- Ref<Resource> res(*rptr);
+ Ref<Resource> existing = ResourceCache::get_ref(local_path);
- //it is possible this resource was just freed in a thread. If so, this referencing will not work and resource is considered not cached
- if (res.is_valid()) {
- ResourceCache::lock.read_unlock();
- thread_load_mutex->unlock();
-
- if (r_error) {
- *r_error = OK;
- }
+ if (existing.is_valid()) {
+ thread_load_mutex->unlock();
- return res; //use cached
+ if (r_error) {
+ *r_error = OK;
}
- }
- ResourceCache::lock.read_unlock();
+ return existing; //use cached
+ }
//load using task (but this thread)
ThreadLoadTask load_task;
@@ -867,7 +850,7 @@ String ResourceLoader::path_remap(const String &p_path) {
}
void ResourceLoader::reload_translation_remaps() {
- ResourceCache::lock.read_lock();
+ ResourceCache::lock.lock();
List<Resource *> to_reload;
SelfList<Resource> *E = remapped_list.first();
@@ -877,7 +860,7 @@ void ResourceLoader::reload_translation_remaps() {
E = E->next();
}
- ResourceCache::lock.read_unlock();
+ ResourceCache::lock.unlock();
//now just make sure to not delete any of these resources while changing locale..
while (to_reload.front()) {
diff --git a/core/object/object.h b/core/object/object.h
index fe9231cfd8..2a9f2ebf93 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -47,7 +47,7 @@
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
- PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,noslider][,radians][,degrees][,exp][,suffix:<keyword>] range.
+ PROPERTY_HINT_RANGE, ///< hint_text = "min,max[,step][,or_greater][,or_lesser][,no_slider][,radians][,degrees][,exp][,suffix:<keyword>] range.
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_ENUM_SUGGESTION, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_EXP_EASING, /// exponential easing function (Math::ease) use "attenuation" hint string to revert (flip h), "full" to also include in/out. (ie: "attenuation,inout")
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 4048b483e8..475d166925 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -2460,7 +2460,7 @@
</constant>
<constant name="PROPERTY_HINT_RANGE" value="1" enum="PropertyHint">
Hints that an integer or float property should be within a range specified via the hint string [code]"min,max"[/code] or [code]"min,max,step"[/code]. The hint string can optionally include [code]"or_greater"[/code] and/or [code]"or_lesser"[/code] to allow manual input going respectively above the max or below the min values. Example: [code]"-360,360,1,or_greater,or_lesser"[/code].
- Additionally, other keywords can be included: "exp" for exponential range editing, "radians" for editing radian angles in degrees, "degrees" to hint at an angle and "noslider" to hide the slider.
+ Additionally, other keywords can be included: "exp" for exponential range editing, "radians" for editing radian angles in degrees, "degrees" to hint at an angle and "no_slider" to hide the slider.
</constant>
<constant name="PROPERTY_HINT_ENUM" value="2" enum="PropertyHint">
Hints that an integer, float or string property is an enumerated value to pick in a list specified via a hint string.
diff --git a/doc/classes/ColorPickerButton.xml b/doc/classes/ColorPickerButton.xml
index 53d35c1a3d..75a715789c 100644
--- a/doc/classes/ColorPickerButton.xml
+++ b/doc/classes/ColorPickerButton.xml
@@ -6,7 +6,7 @@
<description>
Encapsulates a [ColorPicker] making it accessible by pressing a button. Pressing the button will toggle the [ColorPicker] visibility.
See also [BaseButton] which contains common properties and methods associated with this node.
- [b]Note:[/b] By default, the button may not be wide enough for the color preview swatch to be visible. Make sure to set [member Control.minimum_size] to a big enough value to give the button enough space.
+ [b]Note:[/b] By default, the button may not be wide enough for the color preview swatch to be visible. Make sure to set [member Control.custom_minimum_size] to a big enough value to give the button enough space.
</description>
<tutorials>
<link title="GUI Drag And Drop Demo">https://godotengine.org/asset-library/asset/133</link>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 2828896eac..2846b564b4 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -100,7 +100,7 @@
<method name="_get_minimum_size" qualifiers="virtual const">
<return type="Vector2" />
<description>
- Virtual method to be implemented by the user. Returns the minimum size for this control. Alternative to [member minimum_size] for controlling minimum size via code. The actual minimum size will be the max value of these two (in each axis separately).
+ Virtual method to be implemented by the user. Returns the minimum size for this control. Alternative to [member custom_minimum_size] for controlling minimum size via code. The actual minimum size will be the max value of these two (in each axis separately).
If not overridden, defaults to [constant Vector2.ZERO].
[b]Note:[/b] This method will not be called when the script is attached to a [Control] node that already overrides its minimum size (e.g. [Label], [Button], [PanelContainer] etc.). It can only be used with most basic GUI nodes, like [Control], [Container], [Panel] etc.
</description>
@@ -157,7 +157,7 @@
Virtual method to be implemented by the user. Returns a [Control] node that should be used as a tooltip instead of the default one. The [code]for_text[/code] includes the contents of the [member hint_tooltip] property.
The returned node must be of type [Control] or Control-derived. It can have child nodes of any type. It is freed when the tooltip disappears, so make sure you always provide a new instance (if you want to use a pre-existing node from your scene tree, you can duplicate it and pass the duplicated instance). When [code]null[/code] or a non-Control node is returned, the default tooltip will be used instead.
The returned node will be added as child to a [PopupPanel], so you should only provide the contents of that panel. That [PopupPanel] can be themed using [method Theme.set_stylebox] for the type [code]"TooltipPanel"[/code] (see [member hint_tooltip] for an example).
- [b]Note:[/b] The tooltip is shrunk to minimal size. If you want to ensure it's fully visible, you might want to set its [member minimum_size] to some non-zero value.
+ [b]Note:[/b] The tooltip is shrunk to minimal size. If you want to ensure it's fully visible, you might want to set its [member custom_minimum_size] to some non-zero value.
[b]Note:[/b] The node (and any relevant children) should be [member CanvasItem.visible] when returned, otherwise, the viewport that instantiates it will not be able to calculate its minimum size reliably.
Example of usage with a custom-constructed node:
[codeblocks]
@@ -357,7 +357,7 @@
<method name="get_combined_minimum_size" qualifiers="const">
<return type="Vector2" />
<description>
- Returns combined minimum size from [member minimum_size] and [method get_minimum_size].
+ Returns combined minimum size from [member custom_minimum_size] and [method get_minimum_size].
</description>
</method>
<method name="get_cursor_shape" qualifiers="const">
@@ -389,7 +389,7 @@
<method name="get_minimum_size" qualifiers="const">
<return type="Vector2" />
<description>
- Returns the minimum size for this control. See [member minimum_size].
+ Returns the minimum size for this control. See [member custom_minimum_size].
</description>
</method>
<method name="get_offset" qualifiers="const">
@@ -939,7 +939,7 @@
<method name="update_minimum_size">
<return type="void" />
<description>
- Invalidates the size cache in this node and in parent nodes up to top level. Intended to be used with [method get_minimum_size] when the return value is changed. Setting [member minimum_size] directly calls this method automatically.
+ Invalidates the size cache in this node and in parent nodes up to top level. Intended to be used with [method get_minimum_size] when the return value is changed. Setting [member custom_minimum_size] directly calls this method automatically.
</description>
</method>
<method name="warp_mouse">
@@ -970,6 +970,9 @@
<member name="clip_contents" type="bool" setter="set_clip_contents" getter="is_clipping_contents" default="false">
Enables whether rendering of [CanvasItem] based children should be clipped to this control's rectangle. If [code]true[/code], parts of a child which would be visibly outside of this control's rectangle will not be rendered and won't receive input.
</member>
+ <member name="custom_minimum_size" type="Vector2" setter="set_custom_minimum_size" getter="get_custom_minimum_size" default="Vector2(0, 0)">
+ The minimum size of the node's bounding rectangle. If you set it to a value greater than (0, 0), the node's bounding rectangle will always have at least this size, even if its content is smaller. If it's set to (0, 0), the node sizes automatically to fit its content, be it a texture or child nodes.
+ </member>
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" enum="Control.FocusMode" default="0">
The focus access mode for the control (None, Click or All). Only one Control can be focused at the same time, and it will receive keyboard signals.
</member>
@@ -1027,9 +1030,6 @@
<member name="layout_direction" type="int" setter="set_layout_direction" getter="get_layout_direction" enum="Control.LayoutDirection" default="0">
Controls layout direction and text writing direction. Right-to-left layouts are necessary for certain languages (e.g. Arabic and Hebrew).
</member>
- <member name="minimum_size" type="Vector2" setter="set_custom_minimum_size" getter="get_custom_minimum_size" default="Vector2(0, 0)">
- The minimum size of the node's bounding rectangle. If you set it to a value greater than (0, 0), the node's bounding rectangle will always have at least this size, even if its content is smaller. If it's set to (0, 0), the node sizes automatically to fit its content, be it a texture or child nodes.
- </member>
<member name="mouse_default_cursor_shape" type="int" setter="set_default_cursor_shape" getter="get_default_cursor_shape" enum="Control.CursorShape" default="0">
The default cursor shape for this control. Useful for Godot plugins and applications or games that use the system's mouse cursors.
[b]Note:[/b] On Linux, shapes may vary depending on the cursor theme of the system.
diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml
index 641d73e333..166923314f 100644
--- a/doc/classes/HTTPRequest.xml
+++ b/doc/classes/HTTPRequest.xml
@@ -15,7 +15,7 @@
# Create an HTTP request node and connect its completion signal.
var http_request = HTTPRequest.new()
add_child(http_request)
- http_request.connect("request_completed", self, "_http_request_completed")
+ http_request.request_completed.connect(self._http_request_completed)
# Perform a GET request. The URL below returns JSON as of writing.
var error = http_request.request("https://httpbin.org/get")
@@ -25,7 +25,7 @@
# Perform a POST request. The URL below returns JSON as of writing.
# Note: Don't make simultaneous requests using a single HTTPRequest node.
# The snippet below is provided for reference only.
- var body = {"name": "Godette"}
+ var body = JSON.new().stringify({"name": "Godette"})
error = http_request.request("https://httpbin.org/post", [], true, HTTPClient.METHOD_POST, body)
if error != OK:
push_error("An error occurred in the HTTP request.")
@@ -33,7 +33,9 @@
# Called when the HTTP request is completed.
func _http_request_completed(result, response_code, headers, body):
- var response = parse_json(body.get_string_from_utf8())
+ var json = JSON.new()
+ json.parse(body.get_string_from_utf8())
+ var response = json.get_data()
# Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org).
print(response.headers["User-Agent"])
@@ -44,7 +46,7 @@
// Create an HTTP request node and connect its completion signal.
var httpRequest = new HTTPRequest();
AddChild(httpRequest);
- httpRequest.Connect("request_completed", this, nameof(HttpRequestCompleted));
+ httpRequest.RequestCompleted += HttpRequestCompleted;
// Perform a GET request. The URL below returns JSON as of writing.
Error error = httpRequest.Request("https://httpbin.org/get");
@@ -56,21 +58,24 @@
// Perform a POST request. The URL below returns JSON as of writing.
// Note: Don't make simultaneous requests using a single HTTPRequest node.
// The snippet below is provided for reference only.
- string[] body = { "name", "Godette" };
- // GDScript to_json is non existent, so we use JSON.Print() here.
- error = httpRequest.Request("https://httpbin.org/post", null, true, HTTPClient.Method.Post, JSON.Print(body));
+ string body = new JSON().Stringify(new Godot.Collections.Dictionary
+ {
+ { "name", "Godette" }
+ });
+ error = httpRequest.Request("https://httpbin.org/post", null, true, HTTPClient.Method.Post, body);
if (error != Error.Ok)
{
GD.PushError("An error occurred in the HTTP request.");
}
}
-
// Called when the HTTP request is completed.
private void HttpRequestCompleted(int result, int response_code, string[] headers, byte[] body)
{
- // GDScript parse_json is non existent so we have to use JSON.parse, which has a slightly different syntax.
- var response = JSON.Parse(body.GetStringFromUTF8()).Result as Godot.Collections.Dictionary;
+ var json = new JSON();
+ json.Parse(body.GetStringFromUTF8());
+ var response = json.GetData() as Godot.Collections.Dictionary;
+
// Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org).
GD.Print((response["headers"] as Godot.Collections.Dictionary)["User-Agent"]);
}
@@ -83,7 +88,7 @@
# Create an HTTP request node and connect its completion signal.
var http_request = HTTPRequest.new()
add_child(http_request)
- http_request.connect("request_completed", self, "_http_request_completed")
+ http_request.request_completed.connect(self._http_request_completed)
# Perform the HTTP request. The URL below returns a PNG image as of writing.
var error = http_request.request("https://via.placeholder.com/512")
@@ -115,7 +120,7 @@
// Create an HTTP request node and connect its completion signal.
var httpRequest = new HTTPRequest();
AddChild(httpRequest);
- httpRequest.Connect("request_completed", this, nameof(HttpRequestCompleted));
+ httpRequest.RequestCompleted += HttpRequestCompleted;
// Perform the HTTP request. The URL below returns a PNG image as of writing.
Error error = httpRequest.Request("https://via.placeholder.com/512");
@@ -125,7 +130,6 @@
}
}
-
// Called when the HTTP request is completed.
private void HttpRequestCompleted(int result, int response_code, string[] headers, byte[] body)
{
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index d2baf78a9e..43b03ce65e 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -380,6 +380,14 @@
[b]Note:[/b] The TinyEXR module is disabled in non-editor builds, which means [method save_exr] will return [constant ERR_UNAVAILABLE] when it is called from an exported project.
</description>
</method>
+ <method name="save_exr_to_buffer" qualifiers="const">
+ <return type="PackedByteArray" />
+ <argument index="0" name="grayscale" type="bool" default="false" />
+ <description>
+ Saves the image as an EXR file to a byte array. If [code]grayscale[/code] is [code]true[/code] and the image has only one channel, it will be saved explicitly as monochrome rather than one red channel. This function will return an empty byte array if Godot was compiled without the TinyEXR module.
+ [b]Note:[/b] The TinyEXR module is disabled in non-editor builds, which means [method save_exr] will return an empty byte array when it is called from an exported project.
+ </description>
+ </method>
<method name="save_jpg" qualifiers="const">
<return type="int" enum="Error" />
<argument index="0" name="path" type="String" />
diff --git a/doc/classes/NavigationMeshGenerator.xml b/doc/classes/NavigationMeshGenerator.xml
index b92183fda0..612ce54d34 100644
--- a/doc/classes/NavigationMeshGenerator.xml
+++ b/doc/classes/NavigationMeshGenerator.xml
@@ -8,6 +8,7 @@
The entire navigation mesh baking is best done in a separate thread as the voxelization, collision tests and mesh optimization steps involved are very performance and time hungry operations.
Navigation mesh baking happens in multiple steps and the result depends on 3D source geometry and properties of the [NavigationMesh] resource. In the first step, starting from a root node and depending on [NavigationMesh] properties all valid 3D source geometry nodes are collected from the [SceneTree]. Second, all collected nodes are parsed for their relevant 3D geometry data and a combined 3D mesh is build. Due to the many different types of parsable objects, from normal [MeshInstance3D]s to [CSGShape3D]s or various [CollisionObject3D]s, some operations to collect geometry data can trigger [RenderingServer] and [PhysicsServer3D] synchronizations. Server synchronization can have a negative effect on baking time or framerate as it often involves [Mutex] locking for thread security. Many parsable objects and the continuous synchronization with other threaded Servers can increase the baking time significantly. On the other hand only a few but very large and complex objects will take some time to prepare for the Servers which can noticeably stall the next frame render. As a general rule the total amount of parsable objects and their individual size and complexity should be balanced to avoid framerate issues or very long baking times. The combined mesh is then passed to the Recast Navigation Object to test the source geometry for walkable terrain suitable to [NavigationMesh] agent properties by creating a voxel world around the meshes bounding area.
The finalized navigation mesh is then returned and stored inside the [NavigationMesh] for use as a resource inside [NavigationRegion3D] nodes.
+ [b]Note:[/b] Using meshes to not only define walkable surfaces but also obstruct navigation baking does not always work. The navigation baking has no concept of what is a geometry "inside" when dealing with mesh source geometry and this is intentional. Depending on current baking parameters, as soon as the obstructing mesh is large enough to fit a navigation mesh area inside, the baking will generate navigation mesh areas that are inside the obstructing source geometry mesh.
</description>
<tutorials>
</tutorials>
diff --git a/doc/classes/NavigationServer2D.xml b/doc/classes/NavigationServer2D.xml
index 187d916fba..36379d2531 100644
--- a/doc/classes/NavigationServer2D.xml
+++ b/doc/classes/NavigationServer2D.xml
@@ -139,6 +139,16 @@
Create a new map.
</description>
</method>
+ <method name="map_force_update">
+ <return type="void" />
+ <argument index="0" name="map" type="RID" />
+ <description>
+ This function immediately forces synchronization of the specified navigation [code]map[/code] [RID]. By default navigation maps are only synchronized at the end of each physics frame. This function can be used to immediately (re)calculate all the navigation meshes and region connections of the navigation map. This makes it possible to query a navigation path for a changed map immediately and in the same frame (multiple times if needed).
+ Due to technical restrictions the current NavigationServer command queue will be flushed. This means all already queued update commands for this physics frame will be executed, even those intended for other maps, regions and agents not part of the specified map. The expensive computation of the navigation meshes and region connections of a map will only be done for the specified map. Other maps will receive the normal synchronization at the end of the physics frame. Should the specified map receive changes after the forced update it will update again as well when the other maps receive their update.
+ Avoidance processing and dispatch of the [code]safe_velocity[/code] signals is untouched by this function and continues to happen for all maps and agents at the end of the physics frame.
+ [b]Note:[/b] With great power comes great responsibility. This function should only be used by users that really know what they are doing and have a good reason for it. Forcing an immediate update of a navigation map requires locking the NavigationServer and flushing the entire NavigationServer command queue. Not only can this severely impact the performance of a game but it can also introduce bugs if used inappropriately without much foresight.
+ </description>
+ </method>
<method name="map_get_agents" qualifiers="const">
<return type="Array" />
<argument index="0" name="map" type="RID" />
@@ -282,6 +292,16 @@
Returns the [code]travel_cost[/code] of this [code]region[/code].
</description>
</method>
+ <method name="region_owns_point" qualifiers="const">
+ <return type="bool" />
+ <argument index="0" name="region" type="RID" />
+ <argument index="1" name="point" type="Vector2" />
+ <description>
+ Returns [code]true[/code] if the provided [code]point[/code] in world space is currently owned by the provided navigation [code]region[/code]. Owned in this context means that one of the region's navigation mesh polygon faces has a possible position at the closest distance to this point compared to all other navigation meshes from other navigation regions that are also registered on the navigation map of the provided region.
+ If multiple navigation meshes have positions at equal distance the navigation region whose polygons are processed first wins the ownership. Polygons are processed in the same order that navigation regions were registered on the NavigationServer.
+ [b]Note:[/b] If navigation meshes from different navigation regions overlap (which should be avoided in general) the result might not be what is expected.
+ </description>
+ </method>
<method name="region_set_enter_cost" qualifiers="const">
<return type="void" />
<argument index="0" name="region" type="RID" />
diff --git a/doc/classes/NavigationServer3D.xml b/doc/classes/NavigationServer3D.xml
index e605cf6645..5185b353bc 100644
--- a/doc/classes/NavigationServer3D.xml
+++ b/doc/classes/NavigationServer3D.xml
@@ -139,6 +139,16 @@
Create a new map.
</description>
</method>
+ <method name="map_force_update">
+ <return type="void" />
+ <argument index="0" name="map" type="RID" />
+ <description>
+ This function immediately forces synchronization of the specified navigation [code]map[/code] [RID]. By default navigation maps are only synchronized at the end of each physics frame. This function can be used to immediately (re)calculate all the navigation meshes and region connections of the navigation map. This makes it possible to query a navigation path for a changed map immediately and in the same frame (multiple times if needed).
+ Due to technical restrictions the current NavigationServer command queue will be flushed. This means all already queued update commands for this physics frame will be executed, even those intended for other maps, regions and agents not part of the specified map. The expensive computation of the navigation meshes and region connections of a map will only be done for the specified map. Other maps will receive the normal synchronization at the end of the physics frame. Should the specified map receive changes after the forced update it will update again as well when the other maps receive their update.
+ Avoidance processing and dispatch of the [code]safe_velocity[/code] signals is untouched by this function and continues to happen for all maps and agents at the end of the physics frame.
+ [b]Note:[/b] With great power comes great responsibility. This function should only be used by users that really know what they are doing and have a good reason for it. Forcing an immediate update of a navigation map requires locking the NavigationServer and flushing the entire NavigationServer command queue. Not only can this severely impact the performance of a game but it can also introduce bugs if used inappropriately without much foresight.
+ </description>
+ </method>
<method name="map_get_agents" qualifiers="const">
<return type="Array" />
<argument index="0" name="map" type="RID" />
@@ -332,6 +342,16 @@
Returns the [code]travel_cost[/code] of this [code]region[/code].
</description>
</method>
+ <method name="region_owns_point" qualifiers="const">
+ <return type="bool" />
+ <argument index="0" name="region" type="RID" />
+ <argument index="1" name="point" type="Vector3" />
+ <description>
+ Returns [code]true[/code] if the provided [code]point[/code] in world space is currently owned by the provided navigation [code]region[/code]. Owned in this context means that one of the region's navigation mesh polygon faces has a possible position at the closest distance to this point compared to all other navigation meshes from other navigation regions that are also registered on the navigation map of the provided region.
+ If multiple navigation meshes have positions at equal distance the navigation region whose polygons are processed first wins the ownership. Polygons are processed in the same order that navigation regions were registered on the NavigationServer.
+ [b]Note:[/b] If navigation meshes from different navigation regions overlap (which should be avoided in general) the result might not be what is expected.
+ </description>
+ </method>
<method name="region_set_enter_cost" qualifiers="const">
<return type="void" />
<argument index="0" name="region" type="RID" />
diff --git a/doc/classes/ScrollContainer.xml b/doc/classes/ScrollContainer.xml
index 658793c4c0..1bbf5cb91b 100644
--- a/doc/classes/ScrollContainer.xml
+++ b/doc/classes/ScrollContainer.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
A ScrollContainer node meant to contain a [Control] child.
- ScrollContainers will automatically create a scrollbar child ([HScrollBar], [VScrollBar], or both) when needed and will only draw the Control within the ScrollContainer area. Scrollbars will automatically be drawn at the right (for vertical) or bottom (for horizontal) and will enable dragging to move the viewable Control (and its children) within the ScrollContainer. Scrollbars will also automatically resize the grabber based on the [member Control.minimum_size] of the Control relative to the ScrollContainer.
+ ScrollContainers will automatically create a scrollbar child ([HScrollBar], [VScrollBar], or both) when needed and will only draw the Control within the ScrollContainer area. Scrollbars will automatically be drawn at the right (for vertical) or bottom (for horizontal) and will enable dragging to move the viewable Control (and its children) within the ScrollContainer. Scrollbars will also automatically resize the grabber based on the [member Control.custom_minimum_size] of the Control relative to the ScrollContainer.
Works great with a [Panel] control. You can set [code]EXPAND[/code] on the children's size flags, so they will upscale to the ScrollContainer's size if it's larger (scroll is invisible for the chosen dimension).
</description>
<tutorials>
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index 97699d0349..9a1b2b5ff5 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -487,7 +487,7 @@ void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector<
void DependencyRemoveDialog::ok_pressed() {
for (int i = 0; i < files_to_delete.size(); ++i) {
if (ResourceCache::has(files_to_delete[i])) {
- Resource *res = ResourceCache::get(files_to_delete[i]);
+ Ref<Resource> res = ResourceCache::get_ref(files_to_delete[i]);
res->set_path("");
}
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index f9a4c14c48..adbba98897 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -1792,9 +1792,9 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector
//if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it
//to reload properly
- if (ResourceCache::has(file)) {
- Resource *r = ResourceCache::get(file);
+ Ref<Resource> r = ResourceCache::get_ref(file);
+ if (r.is_valid()) {
if (!r->get_import_path().is_empty()) {
String dst_path = ResourceFormatImporter::get_singleton()->get_internal_resource_path(file);
r->set_import_path(dst_path);
@@ -2034,9 +2034,8 @@ void EditorFileSystem::_reimport_file(const String &p_file, const HashMap<String
//if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it
//to reload properly
- if (ResourceCache::has(p_file)) {
- Resource *r = ResourceCache::get(p_file);
-
+ Ref<Resource> r = ResourceCache::get_ref(p_file);
+ if (r.is_valid()) {
if (!r->get_import_path().is_empty()) {
String dst_path = ResourceFormatImporter::get_singleton()->get_internal_resource_path(p_file);
r->set_import_path(dst_path);
diff --git a/editor/editor_folding.cpp b/editor/editor_folding.cpp
index 9e1b361f64..8c508494c0 100644
--- a/editor/editor_folding.cpp
+++ b/editor/editor_folding.cpp
@@ -193,10 +193,7 @@ void EditorFolding::load_scene_folding(Node *p_scene, const String &p_path) {
for (int i = 0; i < res_unfolds.size(); i += 2) {
String path2 = res_unfolds[i];
- Ref<Resource> res;
- if (ResourceCache::has(path2)) {
- res = Ref<Resource>(ResourceCache::get(path2));
- }
+ Ref<Resource> res = ResourceCache::get_ref(path2);
if (res.is_null()) {
continue;
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 93caf7944c..9b0ac305d1 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -881,7 +881,7 @@ void EditorNode::_resources_changed(const Vector<String> &p_resources) {
int rc = p_resources.size();
for (int i = 0; i < rc; i++) {
- Ref<Resource> res(ResourceCache::get(p_resources.get(i)));
+ Ref<Resource> res = ResourceCache::get_ref(p_resources.get(i));
if (res.is_null()) {
continue;
}
@@ -1011,8 +1011,8 @@ void EditorNode::_resources_reimported(const Vector<String> &p_resources) {
continue;
}
// Reload normally.
- Resource *resource = ResourceCache::get(p_resources[i]);
- if (resource) {
+ Ref<Resource> resource = ResourceCache::get_ref(p_resources[i]);
+ if (resource.is_valid()) {
resource->reload_from_file();
}
}
@@ -1725,7 +1725,7 @@ void EditorNode::_save_scene(String p_file, int idx) {
// We must update it, but also let the previous scene state go, as
// old version still work for referencing changes in instantiated or inherited scenes.
- sdata = Ref<PackedScene>(Object::cast_to<PackedScene>(ResourceCache::get(p_file)));
+ sdata = ResourceCache::get_ref(p_file);
if (sdata.is_valid()) {
sdata->recreate_state();
} else {
@@ -3717,7 +3717,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
if (ResourceCache::has(lpath)) {
// Used from somewhere else? No problem! Update state and replace sdata.
- Ref<PackedScene> ps = Ref<PackedScene>(Object::cast_to<PackedScene>(ResourceCache::get(lpath)));
+ Ref<PackedScene> ps = ResourceCache::get_ref(lpath);
if (ps.is_valid()) {
ps->replace_state(sdata->get_state());
ps->set_last_modified_time(sdata->get_last_modified_time());
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 61b434a240..2562c740aa 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -3601,7 +3601,7 @@ static EditorPropertyRangeHint _parse_range_hint(PropertyHint p_hint, const Stri
hint.greater = true;
} else if (slice == "or_lesser") {
hint.lesser = true;
- } else if (slice == "noslider") {
+ } else if (slice == "no_slider") {
hint.hide_slider = true;
} else if (slice == "exp") {
hint.exp_range = true;
diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp
index 397afc0653..09d2992e07 100644
--- a/editor/editor_property_name_processor.cpp
+++ b/editor/editor_property_name_processor.cpp
@@ -176,6 +176,7 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() {
capitalize_string_remaps["lowpass"] = "Low-pass";
capitalize_string_remaps["macos"] = "macOS";
capitalize_string_remaps["mb"] = "(MB)"; // Unit.
+ capitalize_string_remaps["mjpeg"] = "MJPEG";
capitalize_string_remaps["mms"] = "MMS";
capitalize_string_remaps["ms"] = "(ms)"; // Unit
capitalize_string_remaps["msaa"] = "MSAA";
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 7a80cf36a8..10412eac41 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -464,6 +464,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Color icon_hover_color = icon_normal_color * (dark_theme ? 1.15 : 1.45);
icon_hover_color.a = 1.0;
Color icon_focus_color = icon_hover_color;
+ Color icon_disabled_color = Color(icon_normal_color, 0.4);
// Make the pressed icon color overbright because icons are not completely white on a dark theme.
// On a light theme, icons are dark, so we need to modulate them with an even brighter color.
Color icon_pressed_color = accent_color * (dark_theme ? 1.15 : 3.5);
@@ -738,10 +739,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_focus_color", "Button", font_focus_color);
theme->set_color("font_pressed_color", "Button", accent_color);
theme->set_color("font_disabled_color", "Button", font_disabled_color);
+
theme->set_color("icon_normal_color", "Button", icon_normal_color);
theme->set_color("icon_hover_color", "Button", icon_hover_color);
theme->set_color("icon_focus_color", "Button", icon_focus_color);
theme->set_color("icon_pressed_color", "Button", icon_pressed_color);
+ theme->set_color("icon_disabled_color", "Button", icon_disabled_color);
const float ACTION_BUTTON_EXTRA_MARGIN = 32 * EDSCALE;
@@ -768,7 +771,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// When pressed, don't tint the icons with the accent color, just leave them normal.
theme->set_color("icon_pressed_color", "EditorLogFilterButton", icon_normal_color);
// When unpressed, dim the icons.
- theme->set_color("icon_normal_color", "EditorLogFilterButton", font_disabled_color);
+ theme->set_color("icon_normal_color", "EditorLogFilterButton", icon_disabled_color);
// When pressed, add a small bottom border to the buttons to better show their active state,
// similar to active tabs.
Ref<StyleBoxFlat> editor_log_button_pressed = style_widget_pressed->duplicate();
@@ -805,8 +808,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_focus_color", "OptionButton", font_focus_color);
theme->set_color("font_pressed_color", "OptionButton", accent_color);
theme->set_color("font_disabled_color", "OptionButton", font_disabled_color);
+
+ theme->set_color("icon_normal_color", "OptionButton", icon_normal_color);
theme->set_color("icon_hover_color", "OptionButton", icon_hover_color);
theme->set_color("icon_focus_color", "OptionButton", icon_focus_color);
+ theme->set_color("icon_pressed_color", "OptionButton", icon_pressed_color);
+ theme->set_color("icon_disabled_color", "OptionButton", icon_disabled_color);
+
theme->set_icon("arrow", "OptionButton", theme->get_icon(SNAME("GuiOptionArrow"), SNAME("EditorIcons")));
theme->set_constant("arrow_margin", "OptionButton", widget_default_margin.x - 2 * EDSCALE);
theme->set_constant("modulate_arrow", "OptionButton", true);
@@ -833,8 +841,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_focus_color", "CheckButton", font_focus_color);
theme->set_color("font_pressed_color", "CheckButton", accent_color);
theme->set_color("font_disabled_color", "CheckButton", font_disabled_color);
+
+ theme->set_color("icon_normal_color", "CheckButton", icon_normal_color);
theme->set_color("icon_hover_color", "CheckButton", icon_hover_color);
theme->set_color("icon_focus_color", "CheckButton", icon_focus_color);
+ theme->set_color("icon_pressed_color", "CheckButton", icon_pressed_color);
+ theme->set_color("icon_disabled_color", "CheckButton", icon_disabled_color);
theme->set_constant("h_separation", "CheckButton", 8 * EDSCALE);
theme->set_constant("check_v_adjust", "CheckButton", 0 * EDSCALE);
@@ -864,8 +876,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_focus_color", "CheckBox", font_focus_color);
theme->set_color("font_pressed_color", "CheckBox", accent_color);
theme->set_color("font_disabled_color", "CheckBox", font_disabled_color);
+
+ theme->set_color("icon_normal_color", "CheckBox", icon_normal_color);
theme->set_color("icon_hover_color", "CheckBox", icon_hover_color);
theme->set_color("icon_focus_color", "CheckBox", icon_focus_color);
+ theme->set_color("icon_pressed_color", "CheckBox", icon_pressed_color);
+ theme->set_color("icon_disabled_color", "CheckBox", icon_disabled_color);
theme->set_constant("h_separation", "CheckBox", 8 * EDSCALE);
theme->set_constant("check_v_adjust", "CheckBox", 0 * EDSCALE);
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index f2975b1d7a..171ef5bf4c 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -1115,7 +1115,7 @@ Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> ani
}
if (ResourceCache::has(p_save_to_path)) {
- Ref<Animation> old_anim = Ref<Resource>(ResourceCache::get(p_save_to_path));
+ Ref<Animation> old_anim = ResourceCache::get_ref(p_save_to_path);
if (old_anim.is_valid()) {
old_anim->copy_from(anim);
anim = old_anim;
@@ -1711,7 +1711,7 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m
}
if (!save_to_file.is_empty()) {
- Ref<Mesh> existing = Ref<Resource>(ResourceCache::get(save_to_file));
+ Ref<Mesh> existing = ResourceCache::get_ref(save_to_file);
if (existing.is_valid()) {
//if somehow an existing one is useful, create
existing->reset_state();
diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp
index aa338a6c0d..e5fe99890e 100644
--- a/editor/import/resource_importer_texture_atlas.cpp
+++ b/editor/import/resource_importer_texture_atlas.cpp
@@ -306,10 +306,8 @@ Error ResourceImporterTextureAtlas::import_group_file(const String &p_group_file
//update cache if existing, else create
Ref<Texture2D> cache;
- if (ResourceCache::has(p_group_file)) {
- Resource *resptr = ResourceCache::get(p_group_file);
- cache.reference_ptr(resptr);
- } else {
+ cache = ResourceCache::get_ref(p_group_file);
+ if (!cache.is_valid()) {
Ref<ImageTexture> res_cache;
res_cache.instantiate();
res_cache->create_from_image(new_atlas);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 1ea0299d4e..dea4aaded7 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -5455,7 +5455,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
}
child->set_name(name);
- Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(ResourceCache::get(path)));
+ Ref<Texture2D> texture = ResourceCache::get_ref(path);
if (parent) {
editor_data->get_undo_redo().add_do_method(parent, "add_child", child, true);
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 617db883f8..e6aeef2fd1 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -1254,6 +1254,14 @@ GDScript::~GDScript() {
memdelete(E.value);
}
+ if (implicit_initializer) {
+ memdelete(implicit_initializer);
+ }
+
+ if (implicit_ready) {
+ memdelete(implicit_ready);
+ }
+
if (GDScriptCache::singleton) { // Cache may have been already destroyed at engine shutdown.
GDScriptCache::remove_script(get_path());
}
@@ -1541,6 +1549,18 @@ bool GDScriptInstance::has_method(const StringName &p_method) const {
Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
GDScript *sptr = script.ptr();
+ if (unlikely(p_method == SNAME("_ready"))) {
+ // Call implicit ready first, including for the super classes.
+ while (sptr) {
+ if (sptr->implicit_ready) {
+ sptr->implicit_ready->call(this, nullptr, 0, r_error);
+ }
+ sptr = sptr->_base;
+ }
+
+ // Reset this back for the regular call.
+ sptr = script.ptr();
+ }
while (sptr) {
HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method);
if (E) {
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 0057962d5e..feb0a237df 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -120,6 +120,7 @@ class GDScript : public Script {
GDScriptFunction *implicit_initializer = nullptr;
GDScriptFunction *initializer = nullptr; //direct pointer to new , faster to locate
+ GDScriptFunction *implicit_ready = nullptr;
int subclass_count = 0;
RBSet<Object *> instances;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 25454030b1..16a0b17d61 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -1990,18 +1990,18 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
// Parse initializer if applies.
bool is_implicit_initializer = !p_for_ready && !p_func && !p_for_lambda;
- bool is_initializer = p_func && !p_for_lambda && String(p_func->identifier->name) == GDScriptLanguage::get_singleton()->strings._init;
- bool is_for_ready = p_for_ready || (p_func && !p_for_lambda && String(p_func->identifier->name) == "_ready");
+ bool is_initializer = p_func && !p_for_lambda && p_func->identifier->name == GDScriptLanguage::get_singleton()->strings._init;
+ bool is_implicit_ready = !p_func && p_for_ready;
- if (!p_for_lambda && (is_implicit_initializer || is_for_ready)) {
+ if (!p_for_lambda && (is_implicit_initializer || is_implicit_ready)) {
// Initialize class fields.
for (int i = 0; i < p_class->members.size(); i++) {
if (p_class->members[i].type != GDScriptParser::ClassNode::Member::VARIABLE) {
continue;
}
const GDScriptParser::VariableNode *field = p_class->members[i].variable;
- if (field->onready != is_for_ready) {
- // Only initialize in _ready.
+ if (field->onready != is_implicit_ready) {
+ // Only initialize in @implicit_ready.
continue;
}
@@ -2123,6 +2123,8 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
p_script->initializer = gd_function;
} else if (is_implicit_initializer) {
p_script->implicit_initializer = gd_function;
+ } else if (is_implicit_ready) {
+ p_script->implicit_ready = gd_function;
}
if (p_func) {
@@ -2140,7 +2142,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
#endif
}
- if (!p_for_lambda) {
+ if (!is_implicit_initializer && !is_implicit_ready && !p_for_lambda) {
p_script->member_functions[func_name] = gd_function;
}
@@ -2208,11 +2210,19 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
for (const KeyValue<StringName, GDScriptFunction *> &E : p_script->member_functions) {
memdelete(E.value);
}
+ if (p_script->implicit_initializer) {
+ memdelete(p_script->implicit_initializer);
+ }
+ if (p_script->implicit_ready) {
+ memdelete(p_script->implicit_ready);
+ }
p_script->member_functions.clear();
p_script->member_indices.clear();
p_script->member_info.clear();
p_script->_signals.clear();
p_script->initializer = nullptr;
+ p_script->implicit_initializer = nullptr;
+ p_script->implicit_ready = nullptr;
p_script->tool = parser->is_tool();
p_script->name = p_class->identifier ? p_class->identifier->name : "";
@@ -2456,15 +2466,10 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
//parse methods
- bool has_ready = false;
-
for (int i = 0; i < p_class->members.size(); i++) {
const GDScriptParser::ClassNode::Member &member = p_class->members[i];
if (member.type == member.FUNCTION) {
const GDScriptParser::FunctionNode *function = member.function;
- if (!has_ready && function->identifier->name == "_ready") {
- has_ready = true;
- }
Error err = OK;
_parse_function(err, p_script, p_class, function);
if (err) {
@@ -2498,8 +2503,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
}
}
- if (!has_ready && p_class->onready_used) {
- //create a _ready constructor
+ if (p_class->onready_used) {
+ // Create an implicit_ready constructor.
Error err = OK;
_parse_function(err, p_script, p_class, nullptr, true);
if (err) {
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 5345143271..474c8094f2 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -746,7 +746,7 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
ScriptLanguage::CodeCompletionOption slider2("or_lesser", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
slider2.insert_text = slider2.display.quote(p_quote_style);
r_result.insert(slider2.display, slider2);
- ScriptLanguage::CodeCompletionOption slider3("noslider", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
+ ScriptLanguage::CodeCompletionOption slider3("no_slider", ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
slider3.insert_text = slider3.display.quote(p_quote_style);
r_result.insert(slider3.display, slider3);
}
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 214c60091c..2ce3715bea 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -51,7 +51,7 @@ void LightmapperRD::add_mesh(const MeshData &p_mesh) {
mesh_instances.push_back(mi);
}
-void LightmapperRD::add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance) {
+void LightmapperRD::add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance, float p_shadow_blur) {
Light l;
l.type = LIGHT_TYPE_DIRECTIONAL;
l.direction[0] = p_direction.x;
@@ -62,11 +62,12 @@ void LightmapperRD::add_directional_light(bool p_static, const Vector3 &p_direct
l.color[2] = p_color.b;
l.energy = p_energy;
l.static_bake = p_static;
- l.size = p_angular_distance;
+ l.size = Math::tan(Math::deg2rad(p_angular_distance));
+ l.shadow_blur = p_shadow_blur;
lights.push_back(l);
}
-void LightmapperRD::add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size) {
+void LightmapperRD::add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) {
Light l;
l.type = LIGHT_TYPE_OMNI;
l.position[0] = p_position.x;
@@ -80,10 +81,11 @@ void LightmapperRD::add_omni_light(bool p_static, const Vector3 &p_position, con
l.energy = p_energy;
l.static_bake = p_static;
l.size = p_size;
+ l.shadow_blur = p_shadow_blur;
lights.push_back(l);
}
-void LightmapperRD::add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size) {
+void LightmapperRD::add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) {
Light l;
l.type = LIGHT_TYPE_SPOT;
l.position[0] = p_position.x;
@@ -102,6 +104,7 @@ void LightmapperRD::add_spot_light(bool p_static, const Vector3 &p_position, con
l.energy = p_energy;
l.static_bake = p_static;
l.size = p_size;
+ l.shadow_blur = p_shadow_blur;
lights.push_back(l);
}
@@ -1140,6 +1143,23 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
RID light_uniform_set = rd->uniform_set_create(uniforms, compute_shader_primary, 1);
+ switch (p_quality) {
+ case BAKE_QUALITY_LOW: {
+ push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/low_quality_ray_count");
+ } break;
+ case BAKE_QUALITY_MEDIUM: {
+ push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/medium_quality_ray_count");
+ } break;
+ case BAKE_QUALITY_HIGH: {
+ push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/high_quality_ray_count");
+ } break;
+ case BAKE_QUALITY_ULTRA: {
+ push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/ultra_quality_ray_count");
+ } break;
+ }
+
+ push_constant.ray_count = CLAMP(push_constant.ray_count, 16u, 8192u);
+
RD::ComputeListID compute_list = rd->compute_list_begin();
rd->compute_list_bind_compute_pipeline(compute_list, compute_shader_primary_pipeline);
rd->compute_list_bind_uniform_set(compute_list, compute_base_uniform_set, 0);
@@ -1230,23 +1250,6 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
uniforms.write[1].set_id(0, light_dest_tex);
secondary_uniform_set[1] = rd->uniform_set_create(uniforms, compute_shader_secondary, 1);
- switch (p_quality) {
- case BAKE_QUALITY_LOW: {
- push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/low_quality_ray_count");
- } break;
- case BAKE_QUALITY_MEDIUM: {
- push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/medium_quality_ray_count");
- } break;
- case BAKE_QUALITY_HIGH: {
- push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/high_quality_ray_count");
- } break;
- case BAKE_QUALITY_ULTRA: {
- push_constant.ray_count = GLOBAL_GET("rendering/lightmapping/bake_quality/ultra_quality_ray_count");
- } break;
- }
-
- push_constant.ray_count = CLAMP(push_constant.ray_count, 16u, 8192u);
-
int max_region_size = nearest_power_of_2_templated(int(GLOBAL_GET("rendering/lightmapping/bake_performance/region_size")));
int max_rays = GLOBAL_GET("rendering/lightmapping/bake_performance/max_rays_per_pass");
diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h
index bf9f9b5954..8cb4b58a18 100644
--- a/modules/lightmapper_rd/lightmapper_rd.h
+++ b/modules/lightmapper_rd/lightmapper_rd.h
@@ -57,8 +57,9 @@ class LightmapperRD : public Lightmapper {
float attenuation = 0.0;
float cos_spot_angle = 0.0;
float inv_spot_attenuation = 0.0;
+ float shadow_blur = 0.0;
uint32_t static_bake = 0;
- uint32_t pad[3] = {};
+ uint32_t pad[2] = {};
bool operator<(const Light &p_light) const {
return type < p_light.type;
@@ -236,9 +237,9 @@ class LightmapperRD : public Lightmapper {
public:
virtual void add_mesh(const MeshData &p_mesh) override;
- virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance) override;
- virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size) override;
- virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size) override;
+ virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance, float p_shadow_blur) override;
+ virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) override;
+ virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) override;
virtual void add_probe(const Vector3 &p_position) override;
virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr) override;
diff --git a/modules/lightmapper_rd/lm_common_inc.glsl b/modules/lightmapper_rd/lm_common_inc.glsl
index 58523dc1f8..e0e8000f56 100644
--- a/modules/lightmapper_rd/lm_common_inc.glsl
+++ b/modules/lightmapper_rd/lm_common_inc.glsl
@@ -51,8 +51,9 @@ struct Light {
float cos_spot_angle;
float inv_spot_attenuation;
+ float shadow_blur;
bool static_bake;
- uint pad[3];
+ uint pad[2];
};
layout(set = 0, binding = 4, std430) restrict readonly buffer Lights {
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index 0b6b72a310..efa6cd50b4 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -316,19 +316,24 @@ void main() {
for (uint i = 0; i < params.light_count; i++) {
vec3 light_pos;
+ float dist;
float attenuation;
+ float soft_shadowing_disk_size;
if (lights.data[i].type == LIGHT_TYPE_DIRECTIONAL) {
vec3 light_vec = lights.data[i].direction;
light_pos = position - light_vec * length(params.world_size);
+ dist = length(params.world_size);
attenuation = 1.0;
+ soft_shadowing_disk_size = lights.data[i].size;
} else {
light_pos = lights.data[i].position;
- float d = distance(position, light_pos);
- if (d > lights.data[i].range) {
+ dist = distance(position, light_pos);
+ if (dist > lights.data[i].range) {
continue;
}
+ soft_shadowing_disk_size = lights.data[i].size / dist;
- attenuation = get_omni_attenuation(d, 1.0 / lights.data[i].range, lights.data[i].attenuation);
+ attenuation = get_omni_attenuation(dist, 1.0 / lights.data[i].range, lights.data[i].attenuation);
if (lights.data[i].type == LIGHT_TYPE_SPOT) {
vec3 rel = normalize(position - light_pos);
@@ -352,27 +357,70 @@ void main() {
continue; //no need to do anything
}
- if (trace_ray(position + light_dir * params.bias, light_pos) == RAY_MISS) {
- vec3 light = lights.data[i].color * lights.data[i].energy * attenuation;
- if (lights.data[i].static_bake) {
- static_light += light;
-#ifdef USE_SH_LIGHTMAPS
+ float penumbra = 0.0;
+ if (lights.data[i].size > 0.0) {
+ vec3 light_to_point = -light_dir;
+ vec3 aux = light_to_point.y < 0.777 ? vec3(0.0, 1.0, 0.0) : vec3(1.0, 0.0, 0.0);
+ vec3 light_to_point_tan = normalize(cross(light_to_point, aux));
+ vec3 light_to_point_bitan = normalize(cross(light_to_point, light_to_point_tan));
+
+ const uint shadowing_rays_check_penumbra_denom = 2;
+ uint shadowing_ray_count = params.ray_count;
+
+ uint hits = 0;
+ uint noise = random_seed(ivec3(atlas_pos, 43573547 /* some prime */));
+ vec3 light_disk_to_point = light_to_point;
+ for (uint j = 0; j < shadowing_ray_count; j++) {
+ // Optimization:
+ // Once already traced an important proportion of rays, if all are hits or misses,
+ // assume we're not in the penumbra so we can infer the rest would have the same result
+ if (j == shadowing_ray_count / shadowing_rays_check_penumbra_denom) {
+ if (hits == j) {
+ // Assume totally lit
+ hits = shadowing_ray_count;
+ break;
+ } else if (hits == 0) {
+ // Assume totally dark
+ hits = 0;
+ break;
+ }
+ }
- float c[4] = float[](
- 0.282095, //l0
- 0.488603 * light_dir.y, //l1n1
- 0.488603 * light_dir.z, //l1n0
- 0.488603 * light_dir.x //l1p1
- );
+ float r = randomize(noise);
+ float a = randomize(noise) * 2.0 * PI;
+ vec2 disk_sample = (r * vec2(cos(a), sin(a))) * soft_shadowing_disk_size * lights.data[i].shadow_blur;
+ light_disk_to_point = normalize(light_to_point + disk_sample.x * light_to_point_tan + disk_sample.y * light_to_point_bitan);
- for (uint j = 0; j < 4; j++) {
- sh_accum[j].rgb += light * c[j] * (1.0 / 3.0);
+ if (trace_ray(position - light_disk_to_point * params.bias, position - light_disk_to_point * dist) == RAY_MISS) {
+ hits++;
}
-#endif
+ }
+ penumbra = float(hits) / float(shadowing_ray_count);
+ } else {
+ if (trace_ray(position + light_dir * params.bias, light_pos) == RAY_MISS) {
+ penumbra = 1.0;
+ }
+ }
- } else {
- dynamic_light += light;
+ vec3 light = lights.data[i].color * lights.data[i].energy * attenuation * penumbra;
+ if (lights.data[i].static_bake) {
+ static_light += light;
+#ifdef USE_SH_LIGHTMAPS
+
+ float c[4] = float[](
+ 0.282095, //l0
+ 0.488603 * light_dir.y, //l1n1
+ 0.488603 * light_dir.z, //l1n0
+ 0.488603 * light_dir.x //l1p1
+ );
+
+ for (uint j = 0; j < 4; j++) {
+ sh_accum[j].rgb += light * c[j] * (1.0 / 3.0);
}
+#endif
+
+ } else {
+ dynamic_light += light;
}
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
index 9e8f7ef1b1..3c020a2589 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MSBuildPanel.cs
@@ -126,7 +126,7 @@ namespace GodotTools.Build
{
base._Ready();
- MinimumSize = new Vector2(0, 228) * EditorScale;
+ CustomMinimumSize = new Vector2(0, 228) * EditorScale;
SizeFlagsVertical = (int)SizeFlags.ExpandFill;
var toolBarHBox = new HBoxContainer { SizeFlagsHorizontal = (int)SizeFlags.ExpandFill };
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index 927748dbd9..bcbc721dbb 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -351,6 +351,16 @@ real_t GodotNavigationServer::region_get_travel_cost(RID p_region) const {
return region->get_travel_cost();
}
+bool GodotNavigationServer::region_owns_point(RID p_region, const Vector3 &p_point) const {
+ const NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND_V(region == nullptr, false);
+ if (region->get_map()) {
+ RID closest_point_owner = map_get_closest_point_owner(region->get_map()->get_self(), p_point);
+ return closest_point_owner == region->get_self();
+ }
+ return false;
+}
+
COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers) {
NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND(region == nullptr);
@@ -592,6 +602,15 @@ void GodotNavigationServer::flush_queries() {
commands.clear();
}
+void GodotNavigationServer::map_force_update(RID p_map) {
+ NavMap *map = map_owner.get_or_null(p_map);
+ ERR_FAIL_COND(map == nullptr);
+
+ flush_queries();
+
+ map->sync();
+}
+
void GodotNavigationServer::process(real_t p_delta_time) {
flush_queries();
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index d4306e7931..8e7e99888c 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -110,6 +110,8 @@ public:
virtual Array map_get_regions(RID p_map) const override;
virtual Array map_get_agents(RID p_map) const override;
+ virtual void map_force_update(RID p_map) override;
+
virtual RID region_create() const override;
COMMAND_2(region_set_enter_cost, RID, p_region, real_t, p_enter_cost);
@@ -117,6 +119,8 @@ public:
COMMAND_2(region_set_travel_cost, RID, p_region, real_t, p_travel_cost);
virtual real_t region_get_travel_cost(RID p_region) const override;
+ virtual bool region_owns_point(RID p_region, const Vector3 &p_point) const override;
+
COMMAND_2(region_set_map, RID, p_region, RID, p_map);
virtual RID region_get_map(RID p_region) const override;
COMMAND_2(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers);
diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp
index bbbb995635..19bbd834cc 100644
--- a/modules/visual_script/visual_script_flow_control.cpp
+++ b/modules/visual_script/visual_script_flow_control.cpp
@@ -803,7 +803,7 @@ public:
//if the script is not in use by anyone, we can safely assume whatever we got is not casting to it.
return 1;
}
- Ref<Script> cast_script = Ref<Resource>(ResourceCache::get(script));
+ Ref<Script> cast_script = ResourceCache::get_ref(script);
if (!cast_script.is_valid()) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str = "Script path is not a script: " + script;
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index 483fc8b6c3..b16358ae38 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -377,7 +377,7 @@ void VisualScriptFunctionCall::_update_method_cache() {
}
if (ResourceCache::has(base_script)) {
- script = Ref<Resource>(ResourceCache::get(base_script));
+ script = ResourceCache::get_ref(base_script);
} else {
return;
}
@@ -587,7 +587,7 @@ void VisualScriptFunctionCall::_validate_property(PropertyInfo &property) const
}
if (ResourceCache::has(base_script)) {
- Ref<Script> script = Ref<Resource>(ResourceCache::get(base_script));
+ Ref<Script> script = ResourceCache::get_ref(base_script);
if (script.is_valid()) {
property.hint = PROPERTY_HINT_METHOD_OF_SCRIPT;
property.hint_string = itos(script->get_instance_id());
@@ -1178,7 +1178,7 @@ void VisualScriptPropertySet::_update_cache() {
}
if (ResourceCache::has(base_script)) {
- script = Ref<Resource>(ResourceCache::get(base_script));
+ script = ResourceCache::get_ref(base_script);
} else {
return;
}
@@ -1338,7 +1338,7 @@ void VisualScriptPropertySet::_validate_property(PropertyInfo &property) const {
}
if (ResourceCache::has(base_script)) {
- Ref<Script> script = Ref<Resource>(ResourceCache::get(base_script));
+ Ref<Script> script = ResourceCache::get_ref(base_script);
if (script.is_valid()) {
property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT;
property.hint_string = itos(script->get_instance_id());
@@ -1864,7 +1864,7 @@ void VisualScriptPropertyGet::_update_cache() {
}
if (ResourceCache::has(base_script)) {
- script = Ref<Resource>(ResourceCache::get(base_script));
+ script = ResourceCache::get_ref(base_script);
} else {
return;
}
@@ -2044,7 +2044,7 @@ void VisualScriptPropertyGet::_validate_property(PropertyInfo &property) const {
}
if (ResourceCache::has(base_script)) {
- Ref<Script> script = Ref<Resource>(ResourceCache::get(base_script));
+ Ref<Script> script = ResourceCache::get_ref(base_script);
if (script.is_valid()) {
property.hint = PROPERTY_HINT_PROPERTY_OF_SCRIPT;
property.hint_string = itos(script->get_instance_id());
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index b2b848d380..4599785ce4 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -437,7 +437,7 @@ void Node2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_relative_transform_to_parent", "parent"), &Node2D::get_relative_transform_to_parent);
ADD_GROUP("Transform", "");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_lesser,or_greater,noslider,suffix:px"), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_lesser,or_greater,no_slider,suffix:px"), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians"), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale", PROPERTY_HINT_LINK), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "skew", PROPERTY_HINT_RANGE, "-89.9,89.9,0.1,radians"), "set_skew", "get_skew");
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index a8eec4b1f3..74ac96c6cc 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -979,13 +979,13 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
Color linear_color = light->get_color().srgb_to_linear();
if (Object::cast_to<DirectionalLight3D>(light)) {
DirectionalLight3D *l = Object::cast_to<DirectionalLight3D>(light);
- lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_SIZE));
+ lightmapper->add_directional_light(light->get_bake_mode() == Light3D::BAKE_STATIC, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
} else if (Object::cast_to<OmniLight3D>(light)) {
OmniLight3D *l = Object::cast_to<OmniLight3D>(light);
- lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE));
+ lightmapper->add_omni_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
} else if (Object::cast_to<SpotLight3D>(light)) {
SpotLight3D *l = Object::cast_to<SpotLight3D>(light);
- lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE));
+ lightmapper->add_spot_light(light->get_bake_mode() == Light3D::BAKE_STATIC, xf.origin, -xf.basis.get_column(Vector3::AXIS_Z).normalized(), linear_color, l->get_param(Light3D::PARAM_ENERGY), l->get_param(Light3D::PARAM_RANGE), l->get_param(Light3D::PARAM_ATTENUATION), l->get_param(Light3D::PARAM_SPOT_ANGLE), l->get_param(Light3D::PARAM_SPOT_ATTENUATION), l->get_param(Light3D::PARAM_SIZE), l->get_param(Light3D::PARAM_SHADOW_BLUR));
}
}
for (int i = 0; i < probes_found.size(); i++) {
diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h
index 4e6f76e360..9b973fd6bc 100644
--- a/scene/3d/lightmapper.h
+++ b/scene/3d/lightmapper.h
@@ -176,9 +176,9 @@ public:
};
virtual void add_mesh(const MeshData &p_mesh) = 0;
- virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance) = 0;
- virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size) = 0;
- virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size) = 0;
+ virtual void add_directional_light(bool p_static, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_angular_distance, float p_shadow_blur) = 0;
+ virtual void add_omni_light(bool p_static, const Vector3 &p_position, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_size, float p_shadow_blur) = 0;
+ virtual void add_spot_light(bool p_static, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size, float p_shadow_blur) = 0;
virtual void add_probe(const Vector3 &p_position) = 0;
virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, int p_max_texture_size, bool p_bake_sh, GenerateProbes p_generate_probes, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr) = 0;
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index 6e36815f2b..60858b00b1 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -980,7 +980,7 @@ void Node3D::_bind_methods() {
ADD_GROUP("Transform", "");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NO_EDITOR), "set_transform", "get_transform");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "global_transform", PROPERTY_HINT_NONE, "suffix:m", PROPERTY_USAGE_NONE), "set_global_transform", "get_global_transform");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_lesser,noslider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position", PROPERTY_HINT_RANGE, "-99999,99999,0.001,or_greater,or_lesser,no_slider,suffix:m", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater,radians", PROPERTY_USAGE_EDITOR), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "quaternion", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_quaternion", "get_quaternion");
ADD_PROPERTY(PropertyInfo(Variant::BASIS, "basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_basis", "get_basis");
diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp
index a54e728c1b..e9c33b1839 100644
--- a/scene/debugger/scene_debugger.cpp
+++ b/scene/debugger/scene_debugger.cpp
@@ -701,7 +701,7 @@ void LiveEditor::_res_set_func(int p_id, const StringName &p_prop, const Variant
return;
}
- Ref<Resource> r = ResourceCache::get(resp);
+ Ref<Resource> r = ResourceCache::get_ref(resp);
if (!r.is_valid()) {
return;
}
@@ -728,7 +728,7 @@ void LiveEditor::_res_call_func(int p_id, const StringName &p_method, const Vari
return;
}
- Ref<Resource> r = ResourceCache::get(resp);
+ Ref<Resource> r = ResourceCache::get_ref(resp);
if (!r.is_valid()) {
return;
}
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 036d00345d..7b97b0fa47 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -3286,7 +3286,7 @@ void Control::_bind_methods() {
ADD_GROUP("Layout", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_contents"), "set_clip_contents", "is_clipping_contents");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "custom_minimum_size", PROPERTY_HINT_NONE, "suffix:px"), "set_custom_minimum_size", "get_custom_minimum_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_direction", PROPERTY_HINT_ENUM, "Inherited,Locale,Left-to-Right,Right-to-Left"), "set_layout_direction", "get_layout_direction");
ADD_PROPERTY(PropertyInfo(Variant::INT, "layout_mode", PROPERTY_HINT_ENUM, "Position,Anchors,Container,Uncontrolled", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_layout_mode", "_get_layout_mode");
ADD_PROPERTY_DEFAULT("layout_mode", LayoutMode::LAYOUT_MODE_POSITION);
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 192d214262..a2b05ee50d 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -262,7 +262,7 @@ Button *AcceptDialog::add_button(const String &p_text, bool p_right, const Strin
Button *AcceptDialog::add_cancel_button(const String &p_cancel) {
String c = p_cancel;
if (p_cancel.is_empty()) {
- c = TTRC("Cancel");
+ c = RTR("Cancel");
}
Button *b = swap_cancel_ok ? add_button(c, true) : add_button(c);
b->connect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed));
@@ -349,7 +349,7 @@ AcceptDialog::AcceptDialog() {
hbc->add_spacer();
ok = memnew(Button);
- ok->set_text(TTRC("OK"));
+ ok->set_text(RTR("OK"));
hbc->add_child(ok);
hbc->add_spacer();
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 1725816c31..0e0f8bde83 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -337,7 +337,7 @@ void FileDialog::_action_pressed() {
}
if (dir_access->file_exists(f)) {
- confirm_save->set_text(TTRC("File exists, overwrite?"));
+ confirm_save->set_text(RTR("File exists, overwrite?"));
confirm_save->popup_centered(Size2(200, 80));
} else {
emit_signal(SNAME("file_selected"), f);
@@ -423,10 +423,10 @@ void FileDialog::deselect_all() {
switch (mode) {
case FILE_MODE_OPEN_FILE:
case FILE_MODE_OPEN_FILES:
- get_ok_button()->set_text(TTRC("Open"));
+ get_ok_button()->set_text(RTR("Open"));
break;
case FILE_MODE_OPEN_DIR:
- get_ok_button()->set_text(TTRC("Select Current Folder"));
+ get_ok_button()->set_text(RTR("Select Current Folder"));
break;
case FILE_MODE_OPEN_ANY:
case FILE_MODE_SAVE_FILE:
@@ -450,7 +450,7 @@ void FileDialog::_tree_selected() {
if (!d["dir"]) {
file->set_text(d["name"]);
} else if (mode == FILE_MODE_OPEN_DIR) {
- get_ok_button()->set_text(TTRC("Select This Folder"));
+ get_ok_button()->set_text(RTR("Select This Folder"));
}
get_ok_button()->set_disabled(_is_open_should_be_disabled());
@@ -502,7 +502,7 @@ void FileDialog::update_file_list() {
if (dir_access->is_readable(dir_access->get_current_dir().utf8().get_data())) {
message->hide();
} else {
- message->set_text(TTRC("You don't have permission to access contents of this folder."));
+ message->set_text(RTR("You don't have permission to access contents of this folder."));
message->show();
}
@@ -746,35 +746,35 @@ void FileDialog::set_file_mode(FileMode p_mode) {
mode = p_mode;
switch (mode) {
case FILE_MODE_OPEN_FILE:
- get_ok_button()->set_text(TTRC("Open"));
+ get_ok_button()->set_text(RTR("Open"));
if (mode_overrides_title) {
set_title(TTRC("Open a File"));
}
makedir->hide();
break;
case FILE_MODE_OPEN_FILES:
- get_ok_button()->set_text(TTRC("Open"));
+ get_ok_button()->set_text(RTR("Open"));
if (mode_overrides_title) {
set_title(TTRC("Open File(s)"));
}
makedir->hide();
break;
case FILE_MODE_OPEN_DIR:
- get_ok_button()->set_text(TTRC("Select Current Folder"));
+ get_ok_button()->set_text(RTR("Select Current Folder"));
if (mode_overrides_title) {
set_title(TTRC("Open a Directory"));
}
makedir->show();
break;
case FILE_MODE_OPEN_ANY:
- get_ok_button()->set_text(TTRC("Open"));
+ get_ok_button()->set_text(RTR("Open"));
if (mode_overrides_title) {
set_title(TTRC("Open a File or Directory"));
}
makedir->show();
break;
case FILE_MODE_SAVE_FILE:
- get_ok_button()->set_text(TTRC("Save"));
+ get_ok_button()->set_text(RTR("Save"));
if (mode_overrides_title) {
set_title(TTRC("Save a File"));
}
@@ -964,13 +964,13 @@ FileDialog::FileDialog() {
dir_prev = memnew(Button);
dir_prev->set_flat(true);
- dir_prev->set_tooltip(TTRC("Go to previous folder."));
+ dir_prev->set_tooltip(RTR("Go to previous folder."));
dir_next = memnew(Button);
dir_next->set_flat(true);
- dir_next->set_tooltip(TTRC("Go to next folder."));
+ dir_next->set_tooltip(RTR("Go to next folder."));
dir_up = memnew(Button);
dir_up->set_flat(true);
- dir_up->set_tooltip(TTRC("Go to parent folder."));
+ dir_up->set_tooltip(RTR("Go to parent folder."));
hbc->add_child(dir_prev);
hbc->add_child(dir_next);
hbc->add_child(dir_up);
@@ -978,7 +978,7 @@ FileDialog::FileDialog() {
dir_next->connect("pressed", callable_mp(this, &FileDialog::_go_forward));
dir_up->connect("pressed", callable_mp(this, &FileDialog::_go_up));
- hbc->add_child(memnew(Label(TTRC("Path:"))));
+ hbc->add_child(memnew(Label(RTR("Path:"))));
drives_container = memnew(HBoxContainer);
hbc->add_child(drives_container);
@@ -994,7 +994,7 @@ FileDialog::FileDialog() {
refresh = memnew(Button);
refresh->set_flat(true);
- refresh->set_tooltip(TTRC("Refresh files."));
+ refresh->set_tooltip(RTR("Refresh files."));
refresh->connect("pressed", callable_mp(this, &FileDialog::update_file_list));
hbc->add_child(refresh);
@@ -1002,7 +1002,7 @@ FileDialog::FileDialog() {
show_hidden->set_flat(true);
show_hidden->set_toggle_mode(true);
show_hidden->set_pressed(is_showing_hidden_files());
- show_hidden->set_tooltip(TTRC("Toggle the visibility of hidden files."));
+ show_hidden->set_tooltip(RTR("Toggle the visibility of hidden files."));
show_hidden->connect("toggled", callable_mp(this, &FileDialog::set_show_hidden_files));
hbc->add_child(show_hidden);
@@ -1010,14 +1010,14 @@ FileDialog::FileDialog() {
hbc->add_child(shortcuts_container);
makedir = memnew(Button);
- makedir->set_text(TTRC("Create Folder"));
+ makedir->set_text(RTR("Create Folder"));
makedir->connect("pressed", callable_mp(this, &FileDialog::_make_dir));
hbc->add_child(makedir);
vbox->add_child(hbc);
tree = memnew(Tree);
tree->set_hide_root(true);
- vbox->add_margin_child(TTRC("Directories & Files:"), tree, true);
+ vbox->add_margin_child(RTR("Directories & Files:"), tree, true);
message = memnew(Label);
message->hide();
@@ -1027,7 +1027,7 @@ FileDialog::FileDialog() {
tree->add_child(message);
file_box = memnew(HBoxContainer);
- file_box->add_child(memnew(Label(TTRC("File:"))));
+ file_box->add_child(memnew(Label(RTR("File:"))));
file = memnew(LineEdit);
file->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
file->set_stretch_ratio(4);
@@ -1058,22 +1058,22 @@ FileDialog::FileDialog() {
confirm_save->connect("confirmed", callable_mp(this, &FileDialog::_save_confirm_pressed));
makedialog = memnew(ConfirmationDialog);
- makedialog->set_title(TTRC("Create Folder"));
+ makedialog->set_title(RTR("Create Folder"));
VBoxContainer *makevb = memnew(VBoxContainer);
makedialog->add_child(makevb);
makedirname = memnew(LineEdit);
makedirname->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
- makevb->add_margin_child(TTRC("Name:"), makedirname);
+ makevb->add_margin_child(RTR("Name:"), makedirname);
add_child(makedialog, false, INTERNAL_MODE_FRONT);
makedialog->register_text_enter(makedirname);
makedialog->connect("confirmed", callable_mp(this, &FileDialog::_make_dir_confirm));
mkdirerr = memnew(AcceptDialog);
- mkdirerr->set_text(TTRC("Could not create folder."));
+ mkdirerr->set_text(RTR("Could not create folder."));
add_child(mkdirerr, false, INTERNAL_MODE_FRONT);
exterr = memnew(AcceptDialog);
- exterr->set_text(TTRC("Must use a valid extension."));
+ exterr->set_text(RTR("Must use a valid extension."));
add_child(exterr, false, INTERNAL_MODE_FRONT);
update_filters();
diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp
index f36682942f..80859e8eb9 100644
--- a/scene/gui/progress_bar.cpp
+++ b/scene/gui/progress_bar.cpp
@@ -126,7 +126,11 @@ int ProgressBar::get_fill_mode() {
}
void ProgressBar::set_percent_visible(bool p_visible) {
+ if (percent_visible == p_visible) {
+ return;
+ }
percent_visible = p_visible;
+ update_minimum_size();
update();
}
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index b2fd8eb895..f4fd81b25f 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -439,12 +439,15 @@ void CapsuleMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001,or_greater,suffix:m"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1,or_greater"), "set_rings", "get_rings");
+
+ ADD_LINKED_PROPERTY("radius", "height");
+ ADD_LINKED_PROPERTY("height", "radius");
}
void CapsuleMesh::set_radius(const float p_radius) {
radius = p_radius;
if (radius > height * 0.5) {
- radius = height * 0.5;
+ height = radius * 2.0;
}
_request_update();
}
@@ -456,7 +459,7 @@ float CapsuleMesh::get_radius() const {
void CapsuleMesh::set_height(const float p_height) {
height = p_height;
if (radius > height * 0.5) {
- height = radius * 2;
+ radius = height * 0.5;
}
_request_update();
}
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index dba53338eb..3cda2f05b2 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -526,9 +526,9 @@ Error ResourceLoaderText::load() {
if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) {
//reuse existing
- Resource *r = ResourceCache::get(path);
- if (r && r->get_class() == type) {
- res = Ref<Resource>(r);
+ Ref<Resource> cache = ResourceCache::get_ref(path);
+ if (cache.is_valid() && cache->get_class() == type) {
+ res = cache;
res->reset_state();
do_assign = true;
}
@@ -537,10 +537,10 @@ Error ResourceLoaderText::load() {
MissingResource *missing_resource = nullptr;
if (res.is_null()) { //not reuse
- if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && ResourceCache::has(path)) { //only if it doesn't exist
+ Ref<Resource> cache = ResourceCache::get_ref(path);
+ if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && cache.is_valid()) { //only if it doesn't exist
//cached, do not assign
- Resource *r = ResourceCache::get(path);
- res = Ref<Resource>(r);
+ res = cache;
} else {
//create
@@ -650,12 +650,10 @@ Error ResourceLoaderText::load() {
return error;
}
- if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(local_path)) {
- Resource *r = ResourceCache::get(local_path);
- if (r->get_class() == res_type) {
- r->reset_state();
- resource = Ref<Resource>(r);
- }
+ Ref<Resource> cache = ResourceCache::get_ref(local_path);
+ if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && cache.is_valid() && cache->get_class() == res_type) {
+ cache->reset_state();
+ resource = cache;
}
MissingResource *missing_resource = nullptr;
diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp
index ba64dc607e..5e9f1c824a 100644
--- a/servers/navigation_server_2d.cpp
+++ b/servers/navigation_server_2d.cpp
@@ -175,11 +175,14 @@ void NavigationServer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_regions", "map"), &NavigationServer2D::map_get_regions);
ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer2D::map_get_agents);
+ ClassDB::bind_method(D_METHOD("map_force_update", "map"), &NavigationServer2D::map_force_update);
+
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer2D::region_create);
ClassDB::bind_method(D_METHOD("region_set_enter_cost", "region", "enter_cost"), &NavigationServer2D::region_set_enter_cost);
ClassDB::bind_method(D_METHOD("region_get_enter_cost", "region"), &NavigationServer2D::region_get_enter_cost);
ClassDB::bind_method(D_METHOD("region_set_travel_cost", "region", "travel_cost"), &NavigationServer2D::region_set_travel_cost);
ClassDB::bind_method(D_METHOD("region_get_travel_cost", "region"), &NavigationServer2D::region_get_travel_cost);
+ ClassDB::bind_method(D_METHOD("region_owns_point", "region", "point"), &NavigationServer2D::region_owns_point);
ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer2D::region_set_map);
ClassDB::bind_method(D_METHOD("region_get_map", "region"), &NavigationServer2D::region_get_map);
ClassDB::bind_method(D_METHOD("region_set_navigation_layers", "region", "navigation_layers"), &NavigationServer2D::region_set_navigation_layers);
@@ -235,6 +238,10 @@ void FORWARD_2_C(map_set_active, RID, p_map, bool, p_active, rid_to_rid, bool_to
bool FORWARD_1_C(map_is_active, RID, p_map, rid_to_rid);
+void NavigationServer2D::map_force_update(RID p_map) {
+ NavigationServer3D::get_singleton_mut()->map_force_update(p_map);
+}
+
void FORWARD_2_C(map_set_cell_size, RID, p_map, real_t, p_cell_size, rid_to_rid, real_to_real);
real_t FORWARD_1_C(map_get_cell_size, RID, p_map, rid_to_rid);
@@ -252,6 +259,7 @@ void FORWARD_2_C(region_set_enter_cost, RID, p_region, real_t, p_enter_cost, rid
real_t FORWARD_1_C(region_get_enter_cost, RID, p_region, rid_to_rid);
void FORWARD_2_C(region_set_travel_cost, RID, p_region, real_t, p_travel_cost, rid_to_rid, real_to_real);
real_t FORWARD_1_C(region_get_travel_cost, RID, p_region, rid_to_rid);
+bool FORWARD_2_C(region_owns_point, RID, p_region, const Vector2 &, p_point, rid_to_rid, v2_to_v3);
void FORWARD_2_C(region_set_map, RID, p_region, RID, p_map, rid_to_rid, rid_to_rid);
void FORWARD_2_C(region_set_navigation_layers, RID, p_region, uint32_t, p_navigation_layers, rid_to_rid, uint32_to_uint32);
diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h
index 23d833ddcb..1b15c7ff37 100644
--- a/servers/navigation_server_2d.h
+++ b/servers/navigation_server_2d.h
@@ -85,6 +85,8 @@ public:
virtual Array map_get_regions(RID p_map) const;
virtual Array map_get_agents(RID p_map) const;
+ virtual void map_force_update(RID p_map);
+
/// Creates a new region.
virtual RID region_create() const;
@@ -96,6 +98,8 @@ public:
virtual void region_set_travel_cost(RID p_region, real_t p_travel_cost) const;
virtual real_t region_get_travel_cost(RID p_region) const;
+ virtual bool region_owns_point(RID p_region, const Vector2 &p_point) const;
+
/// Set the map of this region.
virtual void region_set_map(RID p_region, RID p_map) const;
virtual RID region_get_map(RID p_region) const;
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index da675133c9..6c48c4a8de 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -53,11 +53,14 @@ void NavigationServer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("map_get_regions", "map"), &NavigationServer3D::map_get_regions);
ClassDB::bind_method(D_METHOD("map_get_agents", "map"), &NavigationServer3D::map_get_agents);
+ ClassDB::bind_method(D_METHOD("map_force_update", "map"), &NavigationServer3D::map_force_update);
+
ClassDB::bind_method(D_METHOD("region_create"), &NavigationServer3D::region_create);
ClassDB::bind_method(D_METHOD("region_set_enter_cost", "region", "enter_cost"), &NavigationServer3D::region_set_enter_cost);
ClassDB::bind_method(D_METHOD("region_get_enter_cost", "region"), &NavigationServer3D::region_get_enter_cost);
ClassDB::bind_method(D_METHOD("region_set_travel_cost", "region", "travel_cost"), &NavigationServer3D::region_set_travel_cost);
ClassDB::bind_method(D_METHOD("region_get_travel_cost", "region"), &NavigationServer3D::region_get_travel_cost);
+ ClassDB::bind_method(D_METHOD("region_owns_point", "region", "point"), &NavigationServer3D::region_owns_point);
ClassDB::bind_method(D_METHOD("region_set_map", "region", "map"), &NavigationServer3D::region_set_map);
ClassDB::bind_method(D_METHOD("region_get_map", "region"), &NavigationServer3D::region_get_map);
ClassDB::bind_method(D_METHOD("region_set_navigation_layers", "region", "navigation_layers"), &NavigationServer3D::region_set_navigation_layers);
diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h
index 5bf5d8ecdb..cf91596604 100644
--- a/servers/navigation_server_3d.h
+++ b/servers/navigation_server_3d.h
@@ -96,6 +96,8 @@ public:
virtual Array map_get_regions(RID p_map) const = 0;
virtual Array map_get_agents(RID p_map) const = 0;
+ virtual void map_force_update(RID p_map) = 0;
+
/// Creates a new region.
virtual RID region_create() const = 0;
@@ -107,6 +109,8 @@ public:
virtual void region_set_travel_cost(RID p_region, real_t p_travel_cost) const = 0;
virtual real_t region_get_travel_cost(RID p_region) const = 0;
+ virtual bool region_owns_point(RID p_region, const Vector3 &p_point) const = 0;
+
/// Set the map of this region.
virtual void region_set_map(RID p_region, RID p_map) const = 0;
virtual RID region_get_map(RID p_region) const = 0;
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp
index 6b786fdf16..aa42643699 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp
@@ -29,9 +29,11 @@
/*************************************************************************/
#include "copy_effects.h"
+#include "core/config/project_settings.h"
#include "servers/rendering/renderer_rd/renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/uniform_set_cache_rd.h"
+#include "thirdparty/misc/cubemap_coeffs.h"
using namespace RendererRD;
@@ -123,16 +125,157 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
}
}
}
+
+ {
+ // Initialize copier
+ Vector<String> copy_modes;
+ copy_modes.push_back("\n");
+
+ cube_to_dp.shader.initialize(copy_modes);
+
+ cube_to_dp.shader_version = cube_to_dp.shader.version_create();
+ RID shader = cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0);
+ RD::PipelineDepthStencilState dss;
+ dss.enable_depth_test = true;
+ dss.depth_compare_operator = RD::COMPARE_OP_ALWAYS;
+ dss.enable_depth_write = true;
+ cube_to_dp.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), dss, RD::PipelineColorBlendState(), 0);
+ }
+
+ {
+ //Initialize cubemap downsampler
+ Vector<String> cubemap_downsampler_modes;
+ cubemap_downsampler_modes.push_back("");
+
+ if (prefer_raster_effects) {
+ cubemap_downsampler.raster_shader.initialize(cubemap_downsampler_modes);
+
+ cubemap_downsampler.shader_version = cubemap_downsampler.raster_shader.version_create();
+
+ cubemap_downsampler.raster_pipeline.setup(cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ } else {
+ cubemap_downsampler.compute_shader.initialize(cubemap_downsampler_modes);
+
+ cubemap_downsampler.shader_version = cubemap_downsampler.compute_shader.version_create();
+
+ cubemap_downsampler.compute_pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0));
+ cubemap_downsampler.raster_pipeline.clear();
+ }
+ }
+
+ {
+ // Initialize cubemap filter
+ filter.use_high_quality = GLOBAL_GET("rendering/reflections/sky_reflections/fast_filter_high_quality");
+
+ Vector<String> cubemap_filter_modes;
+ cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n");
+ cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n");
+ cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n#define USE_TEXTURE_ARRAY\n");
+ cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n#define USE_TEXTURE_ARRAY\n");
+
+ if (filter.use_high_quality) {
+ filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs));
+ RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(high_quality_coeffs), &high_quality_coeffs[0]);
+ } else {
+ filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(low_quality_coeffs));
+ RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0]);
+ }
+
+ if (prefer_raster_effects) {
+ filter.raster_shader.initialize(cubemap_filter_modes);
+
+ // array variants are not supported in raster
+ filter.raster_shader.set_variant_enabled(FILTER_MODE_HIGH_QUALITY_ARRAY, false);
+ filter.raster_shader.set_variant_enabled(FILTER_MODE_LOW_QUALITY_ARRAY, false);
+
+ filter.shader_version = filter.raster_shader.version_create();
+
+ for (int i = 0; i < FILTER_MODE_MAX; i++) {
+ if (filter.raster_shader.is_variant_enabled(i)) {
+ filter.raster_pipelines[i].setup(filter.raster_shader.version_get_shader(filter.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+ } else {
+ filter.raster_pipelines[i].clear();
+ }
+ }
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.append_id(filter.coefficient_buffer);
+ uniforms.push_back(u);
+ }
+ filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.raster_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
+ } else {
+ filter.compute_shader.initialize(cubemap_filter_modes);
+ filter.shader_version = filter.compute_shader.version_create();
+
+ for (int i = 0; i < FILTER_MODE_MAX; i++) {
+ filter.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.compute_shader.version_get_shader(filter.shader_version, i));
+ filter.raster_pipelines[i].clear();
+ }
+
+ Vector<RD::Uniform> uniforms;
+ {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+ u.binding = 0;
+ u.append_id(filter.coefficient_buffer);
+ uniforms.push_back(u);
+ }
+ filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
+ }
+ }
+
+ {
+ // Initialize roughness
+ Vector<String> cubemap_roughness_modes;
+ cubemap_roughness_modes.push_back("");
+
+ if (prefer_raster_effects) {
+ roughness.raster_shader.initialize(cubemap_roughness_modes);
+
+ roughness.shader_version = roughness.raster_shader.version_create();
+
+ roughness.raster_pipeline.setup(roughness.raster_shader.version_get_shader(roughness.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
+
+ } else {
+ roughness.compute_shader.initialize(cubemap_roughness_modes);
+
+ roughness.shader_version = roughness.compute_shader.version_create();
+
+ roughness.compute_pipeline = RD::get_singleton()->compute_pipeline_create(roughness.compute_shader.version_get_shader(roughness.shader_version, 0));
+ roughness.raster_pipeline.clear();
+ }
+ }
}
CopyEffects::~CopyEffects() {
if (prefer_raster_effects) {
blur_raster.shader.version_free(blur_raster.shader_version);
+ cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version);
+ filter.raster_shader.version_free(filter.shader_version);
+ roughness.raster_shader.version_free(roughness.shader_version);
} else {
copy.shader.version_free(copy.shader_version);
+ cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version);
+ filter.compute_shader.version_free(filter.shader_version);
+ roughness.compute_shader.version_free(roughness.shader_version);
+ }
+
+ RD::get_singleton()->free(filter.coefficient_buffer);
+
+ if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
+ RD::get_singleton()->free(filter.image_uniform_set);
+ }
+
+ if (RD::get_singleton()->uniform_set_is_valid(filter.uniform_set)) {
+ RD::get_singleton()->free(filter.uniform_set);
}
copy_to_fb.shader.version_free(copy_to_fb.shader_version);
+ cube_to_dp.shader.version_free(cube_to_dp.shader_version);
singleton = nullptr;
}
@@ -681,3 +824,262 @@ void CopyEffects::set_color(RID p_dest_texture, const Color &p_color, const Rect
RD::get_singleton()->compute_list_dispatch_threads(compute_list, p_region.size.width, p_region.size.height, 1);
RD::get_singleton()->compute_list_end();
}
+
+void CopyEffects::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip) {
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL(uniform_set_cache);
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ ERR_FAIL_NULL(material_storage);
+
+ CopyToDPPushConstant push_constant;
+ push_constant.screen_rect[0] = p_rect.position.x;
+ push_constant.screen_rect[1] = p_rect.position.y;
+ push_constant.screen_rect[2] = p_rect.size.width;
+ push_constant.screen_rect[3] = p_rect.size.height;
+ push_constant.z_far = p_z_far;
+ push_constant.z_near = p_z_near;
+ push_constant.texel_size[0] = 1.0f / p_dst_size.x;
+ push_constant.texel_size[1] = 1.0f / p_dst_size.y;
+ push_constant.texel_size[0] *= p_dp_flip ? -1.0f : 1.0f; // Encode dp flip as x size sign
+
+ // setup our uniforms
+ RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+ RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_rd_texture }));
+
+ RID shader = cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0);
+ ERR_FAIL_COND(shader.is_null());
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_dp.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CopyToDPPushConstant));
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_TRANSFER);
+}
+
+void CopyEffects::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap downsample with the mobile renderer.");
+
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL(uniform_set_cache);
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ ERR_FAIL_NULL(material_storage);
+
+ cubemap_downsampler.push_constant.face_size = p_size.x;
+ cubemap_downsampler.push_constant.face_id = 0; // we render all 6 sides to each layer in one call
+
+ // setup our uniforms
+ RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+ RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_cubemap }));
+ RD::Uniform u_dest_cubemap(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_dest_cubemap }));
+
+ RID shader = cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0);
+ ERR_FAIL_COND(shader.is_null());
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.compute_pipeline);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_cubemap), 1);
+
+ int x_groups = (p_size.x - 1) / 8 + 1;
+ int y_groups = (p_size.y - 1) / 8 + 1;
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 6); // one z_group for each face
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void CopyEffects::cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap downsample with the clustered renderer.");
+ ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap downsample must process one side at a time.");
+
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL(uniform_set_cache);
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ ERR_FAIL_NULL(material_storage);
+
+ cubemap_downsampler.push_constant.face_size = p_size.x;
+ cubemap_downsampler.push_constant.face_id = p_face_id;
+
+ // setup our uniforms
+ RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+ RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_cubemap }));
+
+ RID shader = cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0);
+ ERR_FAIL_COND(shader.is_null());
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cubemap_downsampler.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
+void CopyEffects::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap filter with the mobile renderer.");
+
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL(uniform_set_cache);
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ ERR_FAIL_NULL(material_storage);
+
+ Vector<RD::Uniform> uniforms;
+ for (int i = 0; i < p_dest_cubemap.size(); i++) {
+ RD::Uniform u;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.binding = i;
+ u.append_id(p_dest_cubemap[i]);
+ uniforms.push_back(u);
+ }
+ if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
+ RD::get_singleton()->free(filter.image_uniform_set);
+ }
+ filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, 0), 2);
+
+ // setup our uniforms
+ RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+ RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_mipmap_sampler, p_source_cubemap }));
+
+ int mode = p_use_array ? FILTER_MODE_HIGH_QUALITY_ARRAY : FILTER_MODE_HIGH_QUALITY;
+ mode = filter.use_high_quality ? mode : mode + 1;
+
+ RID shader = filter.compute_shader.version_get_shader(filter.shader_version, mode);
+ ERR_FAIL_COND(shader.is_null());
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.compute_pipelines[mode]);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2);
+
+ int x_groups = p_use_array ? 1792 : 342; // (128 * 128 * 7) / 64 : (128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) / 64
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, 6, 1); // one y_group for each face
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void CopyEffects::cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap filter with the clustered renderer.");
+ ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap filter must process one side at a time.");
+
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL(uniform_set_cache);
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ ERR_FAIL_NULL(material_storage);
+
+ // TODO implement!
+ CubemapFilterRasterPushConstant push_constant;
+ push_constant.mip_level = p_mip_level;
+ push_constant.face_id = p_face_id;
+
+ // setup our uniforms
+ RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+ RD::Uniform u_source_cubemap(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_mipmap_sampler, p_source_cubemap }));
+
+ CubemapFilterMode mode = filter.use_high_quality ? FILTER_MODE_HIGH_QUALITY : FILTER_MODE_LOW_QUALITY;
+
+ RID shader = filter.raster_shader.version_get_shader(filter.shader_version, mode);
+ ERR_FAIL_COND(shader.is_null());
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, filter.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_cubemap), 0);
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, filter.uniform_set, 1);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CubemapFilterRasterPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
+
+void CopyEffects::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
+ ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap roughness with the mobile renderer.");
+
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL(uniform_set_cache);
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ ERR_FAIL_NULL(material_storage);
+
+ memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
+
+ roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id;
+ roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in.
+ roughness.push_constant.sample_count = p_sample_count;
+ roughness.push_constant.use_direct_write = p_roughness == 0.0;
+ roughness.push_constant.face_size = p_size;
+
+ // setup our uniforms
+ RID default_mipmap_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+ RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_mipmap_sampler, p_source_rd_texture }));
+ RD::Uniform u_dest_texture(RD::UNIFORM_TYPE_IMAGE, 0, Vector<RID>({ p_dest_texture }));
+
+ RID shader = roughness.compute_shader.version_get_shader(filter.shader_version, 0);
+ ERR_FAIL_COND(shader.is_null());
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.compute_pipeline);
+
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set_cache->get_cache(shader, 1, u_dest_texture), 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
+
+ int x_groups = (p_size - 1) / 8 + 1;
+ int y_groups = (p_size - 1) / 8 + 1;
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, p_face_id > 9 ? 6 : 1);
+
+ RD::get_singleton()->compute_list_end();
+}
+
+void CopyEffects::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
+ ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap roughness with the clustered renderer.");
+ ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap roughness must process one side at a time.");
+
+ UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
+ ERR_FAIL_NULL(uniform_set_cache);
+ MaterialStorage *material_storage = MaterialStorage::get_singleton();
+ ERR_FAIL_NULL(material_storage);
+
+ memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
+
+ roughness.push_constant.face_id = p_face_id;
+ roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in.
+ roughness.push_constant.sample_count = p_sample_count;
+ roughness.push_constant.use_direct_write = p_roughness == 0.0;
+ roughness.push_constant.face_size = p_size;
+
+ // setup our uniforms
+ RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+
+ RD::Uniform u_source_rd_texture(RD::UNIFORM_TYPE_SAMPLER_WITH_TEXTURE, 0, Vector<RID>({ default_sampler, p_source_rd_texture }));
+
+ RID shader = roughness.raster_shader.version_get_shader(filter.shader_version, 0);
+ ERR_FAIL_COND(shader.is_null());
+
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
+ RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
+ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
+ RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
+
+ RD::get_singleton()->draw_list_set_push_constant(draw_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
+
+ RD::get_singleton()->draw_list_draw(draw_list, true);
+ RD::get_singleton()->draw_list_end();
+}
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h
index e522408d20..882b446964 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.h
+++ b/servers/rendering/renderer_rd/effects/copy_effects.h
@@ -35,6 +35,13 @@
#include "servers/rendering/renderer_rd/shaders/effects/blur_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/copy.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl.gen.h"
+#include "servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl.gen.h"
#include "servers/rendering/renderer_scene_render.h"
#include "servers/rendering_server.h"
@@ -189,6 +196,84 @@ private:
} copy_to_fb;
+ // Copy to DP
+
+ struct CopyToDPPushConstant {
+ float z_far;
+ float z_near;
+ float texel_size[2];
+ float screen_rect[4];
+ };
+
+ struct CopyToDP {
+ CubeToDpShaderRD shader;
+ RID shader_version;
+ PipelineCacheRD pipeline;
+ } cube_to_dp;
+
+ // Cubemap effects
+
+ struct CubemapDownsamplerPushConstant {
+ uint32_t face_size;
+ uint32_t face_id;
+ float pad[2];
+ };
+
+ struct CubemapDownsampler {
+ CubemapDownsamplerPushConstant push_constant;
+ CubemapDownsamplerShaderRD compute_shader;
+ CubemapDownsamplerRasterShaderRD raster_shader;
+ RID shader_version;
+ RID compute_pipeline;
+ PipelineCacheRD raster_pipeline;
+ } cubemap_downsampler;
+
+ enum CubemapFilterMode {
+ FILTER_MODE_HIGH_QUALITY,
+ FILTER_MODE_LOW_QUALITY,
+ FILTER_MODE_HIGH_QUALITY_ARRAY,
+ FILTER_MODE_LOW_QUALITY_ARRAY,
+ FILTER_MODE_MAX,
+ };
+
+ struct CubemapFilterRasterPushConstant {
+ uint32_t mip_level;
+ uint32_t face_id;
+ float pad[2];
+ };
+
+ struct CubemapFilter {
+ CubemapFilterShaderRD compute_shader;
+ CubemapFilterRasterShaderRD raster_shader;
+ RID shader_version;
+ RID compute_pipelines[FILTER_MODE_MAX];
+ PipelineCacheRD raster_pipelines[FILTER_MODE_MAX];
+
+ RID uniform_set;
+ RID image_uniform_set;
+ RID coefficient_buffer;
+ bool use_high_quality;
+
+ } filter;
+
+ struct CubemapRoughnessPushConstant {
+ uint32_t face_id;
+ uint32_t sample_count;
+ float roughness;
+ uint32_t use_direct_write;
+ float face_size;
+ float pad[3];
+ };
+
+ struct CubemapRoughness {
+ CubemapRoughnessPushConstant push_constant;
+ CubemapRoughnessShaderRD compute_shader;
+ CubemapRoughnessRasterShaderRD raster_shader;
+ RID shader_version;
+ RID compute_pipeline;
+ PipelineCacheRD raster_pipeline;
+ } roughness;
+
static CopyEffects *singleton;
public:
@@ -197,6 +282,8 @@ public:
CopyEffects(bool p_prefer_raster_effects);
~CopyEffects();
+ bool get_prefer_raster_effects() { return prefer_raster_effects; }
+
void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false);
void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array);
void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false);
@@ -213,6 +300,15 @@ public:
void make_mipmap_raster(RID p_source_rd_texture, RID p_dest_framebuffer, const Size2i &p_size);
void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false);
+
+ void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip);
+ void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
+ void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size);
+ void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
+ void cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level);
+
+ void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
+ void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
};
} // namespace RendererRD
diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp
index 4c542fa2e2..d45ddbc392 100644
--- a/servers/rendering/renderer_rd/effects_rd.cpp
+++ b/servers/rendering/renderer_rd/effects_rd.cpp
@@ -86,7 +86,7 @@ RID EffectsRD::_get_uniform_set_from_texture(RID p_texture, bool p_use_mipmaps)
u.append_id(p_texture);
uniforms.push_back(u);
// anything with the same configuration (one texture in binding 0 for set 0), is good
- RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0), 0);
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, specular_merge.shader.version_get_shader(specular_merge.shader_version, 0), 0);
texture_to_uniform_set_cache[p_texture] = uniform_set;
@@ -473,28 +473,6 @@ void EffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_bas
RD::get_singleton()->draw_list_end();
}
-void EffectsRD::copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip) {
- CopyToDPPushConstant push_constant;
- push_constant.screen_rect[0] = p_rect.position.x;
- push_constant.screen_rect[1] = p_rect.position.y;
- push_constant.screen_rect[2] = p_rect.size.width;
- push_constant.screen_rect[3] = p_rect.size.height;
- push_constant.z_far = p_z_far;
- push_constant.z_near = p_z_near;
- push_constant.texel_size[0] = 1.0f / p_dst_size.x;
- push_constant.texel_size[1] = 1.0f / p_dst_size.y;
- push_constant.texel_size[0] *= p_dp_flip ? -1.0f : 1.0f; // Encode dp flip as x size sign
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dst_framebuffer, RD::INITIAL_ACTION_DROP, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cube_to_dp.pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dst_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
-
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CopyToDPPushConstant));
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end(RD::BARRIER_MASK_RASTER | RD::BARRIER_MASK_TRANSFER);
-}
-
void EffectsRD::luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set) {
ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute version of luminance reduction with the mobile renderer.");
@@ -1253,149 +1231,6 @@ void EffectsRD::roughness_limit(RID p_source_normal, RID p_roughness, const Size
RD::get_singleton()->compute_list_end();
}
-void EffectsRD::cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
- ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap roughness with the mobile renderer.");
-
- memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
-
- roughness.push_constant.face_id = p_face_id > 9 ? 0 : p_face_id;
- roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in.
- roughness.push_constant.sample_count = p_sample_count;
- roughness.push_constant.use_direct_write = p_roughness == 0.0;
- roughness.push_constant.face_size = p_size;
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, roughness.compute_pipeline);
-
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture, true), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_texture), 1);
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
-
- int x_groups = (p_size - 1) / 8 + 1;
- int y_groups = (p_size - 1) / 8 + 1;
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, p_face_id > 9 ? 6 : 1);
-
- RD::get_singleton()->compute_list_end();
-}
-
-void EffectsRD::cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size) {
- ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap roughness with the clustered renderer.");
- ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap roughness must process one side at a time.");
-
- memset(&roughness.push_constant, 0, sizeof(CubemapRoughnessPushConstant));
-
- roughness.push_constant.face_id = p_face_id;
- roughness.push_constant.roughness = p_roughness * p_roughness; // Shader expects roughness, not perceptual roughness, so multiply before passing in.
- roughness.push_constant.sample_count = p_sample_count;
- roughness.push_constant.use_direct_write = p_roughness == 0.0;
- roughness.push_constant.face_size = p_size;
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, roughness.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_rd_texture), 0);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
-
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &roughness.push_constant, sizeof(CubemapRoughnessPushConstant));
-
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
-}
-
-void EffectsRD::cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size) {
- ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap downsample with the mobile renderer.");
-
- cubemap_downsampler.push_constant.face_size = p_size.x;
- cubemap_downsampler.push_constant.face_id = 0; // we render all 6 sides to each layer in one call
-
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, cubemap_downsampler.compute_pipeline);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_dest_cubemap), 1);
-
- int x_groups = (p_size.x - 1) / 8 + 1;
- int y_groups = (p_size.y - 1) / 8 + 1;
-
- RD::get_singleton()->compute_list_set_push_constant(compute_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant));
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 6); // one z_group for each face
-
- RD::get_singleton()->compute_list_end();
-}
-
-void EffectsRD::cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size) {
- ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap downsample with the clustered renderer.");
- ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap downsample must process one side at a time.");
-
- cubemap_downsampler.push_constant.face_size = p_size.x;
- cubemap_downsampler.push_constant.face_id = p_face_id;
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, cubemap_downsampler.raster_pipeline.get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_cubemap), 0);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
-
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &cubemap_downsampler.push_constant, sizeof(CubemapDownsamplerPushConstant));
-
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
-}
-
-void EffectsRD::cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array) {
- ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use compute based cubemap filter with the mobile renderer.");
-
- Vector<RD::Uniform> uniforms;
- for (int i = 0; i < p_dest_cubemap.size(); i++) {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
- u.binding = i;
- u.append_id(p_dest_cubemap[i]);
- uniforms.push_back(u);
- }
- if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
- RD::get_singleton()->free(filter.image_uniform_set);
- }
- filter.image_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, 0), 2);
-
- int pipeline = p_use_array ? FILTER_MODE_HIGH_QUALITY_ARRAY : FILTER_MODE_HIGH_QUALITY;
- pipeline = filter.use_high_quality ? pipeline : pipeline + 1;
- RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
- RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, filter.compute_pipelines[pipeline]);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_cubemap, true), 0);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.uniform_set, 1);
- RD::get_singleton()->compute_list_bind_uniform_set(compute_list, filter.image_uniform_set, 2);
-
- int x_groups = p_use_array ? 1792 : 342; // (128 * 128 * 7) / 64 : (128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) / 64
-
- RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, 6, 1); // one y_group for each face
-
- RD::get_singleton()->compute_list_end();
-}
-
-void EffectsRD::cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level) {
- ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use raster based cubemap filter with the clustered renderer.");
- ERR_FAIL_COND_MSG(p_face_id >= 6, "Raster implementation of cubemap filter must process one side at a time.");
-
- // TODO implement!
- CubemapFilterRasterPushConstant push_constant;
- push_constant.mip_level = p_mip_level;
- push_constant.face_id = p_face_id;
-
- CubemapFilterMode mode = filter.use_high_quality ? FILTER_MODE_HIGH_QUALITY : FILTER_MODE_LOW_QUALITY;
-
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD);
- RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, filter.raster_pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, _get_uniform_set_from_texture(p_source_cubemap), 0);
- RD::get_singleton()->draw_list_bind_uniform_set(draw_list, filter.uniform_set, 1);
- RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array);
-
- RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(CubemapFilterRasterPushConstant));
-
- RD::get_singleton()->draw_list_draw(draw_list, true);
- RD::get_singleton()->draw_list_end();
-}
-
void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) {
Sort::PushConstant push_constant;
push_constant.total_elements = p_size;
@@ -1489,28 +1324,6 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
prefer_raster_effects = p_prefer_raster_effects;
- {
- // Initialize roughness
- Vector<String> cubemap_roughness_modes;
- cubemap_roughness_modes.push_back("");
-
- if (prefer_raster_effects) {
- roughness.raster_shader.initialize(cubemap_roughness_modes);
-
- roughness.shader_version = roughness.raster_shader.version_create();
-
- roughness.raster_pipeline.setup(roughness.raster_shader.version_get_shader(roughness.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
-
- } else {
- roughness.compute_shader.initialize(cubemap_roughness_modes);
-
- roughness.shader_version = roughness.compute_shader.version_create();
-
- roughness.compute_pipeline = RD::get_singleton()->compute_pipeline_create(roughness.compute_shader.version_get_shader(roughness.shader_version, 0));
- roughness.raster_pipeline.clear();
- }
- }
-
if (prefer_raster_effects) {
Vector<String> luminance_reduce_modes;
luminance_reduce_modes.push_back("\n#define FIRST_PASS\n"); // LUMINANCE_REDUCE_FRAGMENT_FIRST
@@ -1544,22 +1357,6 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
}
}
- {
- // Initialize copier
- Vector<String> copy_modes;
- copy_modes.push_back("\n");
-
- cube_to_dp.shader.initialize(copy_modes);
-
- cube_to_dp.shader_version = cube_to_dp.shader.version_create();
- RID shader = cube_to_dp.shader.version_get_shader(cube_to_dp.shader_version, 0);
- RD::PipelineDepthStencilState dss;
- dss.enable_depth_test = true;
- dss.depth_compare_operator = RD::COMPARE_OP_ALWAYS;
- dss.enable_depth_write = true;
- cube_to_dp.pipeline.setup(shader, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), dss, RD::PipelineColorBlendState(), 0);
- }
-
if (!prefer_raster_effects) {
{
// Initialize depth buffer for screen space effects
@@ -1720,92 +1517,6 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
roughness_limiter.pipeline = RD::get_singleton()->compute_pipeline_create(roughness_limiter.shader.version_get_shader(roughness_limiter.shader_version, 0));
}
- {
- //Initialize cubemap downsampler
- Vector<String> cubemap_downsampler_modes;
- cubemap_downsampler_modes.push_back("");
-
- if (prefer_raster_effects) {
- cubemap_downsampler.raster_shader.initialize(cubemap_downsampler_modes);
-
- cubemap_downsampler.shader_version = cubemap_downsampler.raster_shader.version_create();
-
- cubemap_downsampler.raster_pipeline.setup(cubemap_downsampler.raster_shader.version_get_shader(cubemap_downsampler.shader_version, 0), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
- } else {
- cubemap_downsampler.compute_shader.initialize(cubemap_downsampler_modes);
-
- cubemap_downsampler.shader_version = cubemap_downsampler.compute_shader.version_create();
-
- cubemap_downsampler.compute_pipeline = RD::get_singleton()->compute_pipeline_create(cubemap_downsampler.compute_shader.version_get_shader(cubemap_downsampler.shader_version, 0));
- cubemap_downsampler.raster_pipeline.clear();
- }
- }
-
- {
- // Initialize cubemap filter
- filter.use_high_quality = GLOBAL_GET("rendering/reflections/sky_reflections/fast_filter_high_quality");
-
- Vector<String> cubemap_filter_modes;
- cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n");
- cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n");
- cubemap_filter_modes.push_back("\n#define USE_HIGH_QUALITY\n#define USE_TEXTURE_ARRAY\n");
- cubemap_filter_modes.push_back("\n#define USE_LOW_QUALITY\n#define USE_TEXTURE_ARRAY\n");
-
- if (filter.use_high_quality) {
- filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(high_quality_coeffs));
- RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(high_quality_coeffs), &high_quality_coeffs[0]);
- } else {
- filter.coefficient_buffer = RD::get_singleton()->storage_buffer_create(sizeof(low_quality_coeffs));
- RD::get_singleton()->buffer_update(filter.coefficient_buffer, 0, sizeof(low_quality_coeffs), &low_quality_coeffs[0]);
- }
-
- if (prefer_raster_effects) {
- filter.raster_shader.initialize(cubemap_filter_modes);
-
- // array variants are not supported in raster
- filter.raster_shader.set_variant_enabled(FILTER_MODE_HIGH_QUALITY_ARRAY, false);
- filter.raster_shader.set_variant_enabled(FILTER_MODE_LOW_QUALITY_ARRAY, false);
-
- filter.shader_version = filter.raster_shader.version_create();
-
- for (int i = 0; i < FILTER_MODE_MAX; i++) {
- if (filter.raster_shader.is_variant_enabled(i)) {
- filter.raster_pipelines[i].setup(filter.raster_shader.version_get_shader(filter.shader_version, i), RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), RD::PipelineColorBlendState::create_disabled(), 0);
- } else {
- filter.raster_pipelines[i].clear();
- }
- }
-
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 0;
- u.append_id(filter.coefficient_buffer);
- uniforms.push_back(u);
- }
- filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.raster_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
- } else {
- filter.compute_shader.initialize(cubemap_filter_modes);
- filter.shader_version = filter.compute_shader.version_create();
-
- for (int i = 0; i < FILTER_MODE_MAX; i++) {
- filter.compute_pipelines[i] = RD::get_singleton()->compute_pipeline_create(filter.compute_shader.version_get_shader(filter.shader_version, i));
- filter.raster_pipelines[i].clear();
- }
-
- Vector<RD::Uniform> uniforms;
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 0;
- u.append_id(filter.coefficient_buffer);
- uniforms.push_back(u);
- }
- filter.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, filter.compute_shader.version_get_shader(filter.shader_version, filter.use_high_quality ? 0 : 1), 1);
- }
- }
-
if (!prefer_raster_effects) {
Vector<String> specular_modes;
specular_modes.push_back("\n#define MODE_MERGE\n");
@@ -2028,31 +1739,16 @@ EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
}
EffectsRD::~EffectsRD() {
- if (RD::get_singleton()->uniform_set_is_valid(filter.image_uniform_set)) {
- RD::get_singleton()->free(filter.image_uniform_set);
- }
-
- if (RD::get_singleton()->uniform_set_is_valid(filter.uniform_set)) {
- RD::get_singleton()->free(filter.uniform_set);
- }
-
RD::get_singleton()->free(default_sampler);
RD::get_singleton()->free(default_mipmap_sampler);
RD::get_singleton()->free(index_buffer); //array gets freed as dependency
- RD::get_singleton()->free(filter.coefficient_buffer);
FSR_upscale.shader.version_free(FSR_upscale.shader_version);
TAA_resolve.shader.version_free(TAA_resolve.shader_version);
if (prefer_raster_effects) {
luminance_reduce_raster.shader.version_free(luminance_reduce_raster.shader_version);
- roughness.raster_shader.version_free(roughness.shader_version);
- cubemap_downsampler.raster_shader.version_free(cubemap_downsampler.shader_version);
- filter.raster_shader.version_free(filter.shader_version);
} else {
luminance_reduce.shader.version_free(luminance_reduce.shader_version);
- roughness.compute_shader.version_free(roughness.shader_version);
- cubemap_downsampler.compute_shader.version_free(cubemap_downsampler.shader_version);
- filter.compute_shader.version_free(filter.shader_version);
}
if (!prefer_raster_effects) {
specular_merge.shader.version_free(specular_merge.shader_version);
@@ -2077,6 +1773,5 @@ EffectsRD::~EffectsRD() {
RD::get_singleton()->free(ssil.importance_map_load_counter);
RD::get_singleton()->free(ssil.projection_uniform_buffer);
}
- cube_to_dp.shader.version_free(cube_to_dp.shader_version);
sort.shader.version_free(sort.shader_version);
}
diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h
index af4ed5a6ae..76627a8d7d 100644
--- a/servers/rendering/renderer_rd/effects_rd.h
+++ b/servers/rendering/renderer_rd/effects_rd.h
@@ -33,13 +33,6 @@
#include "core/math/camera_matrix.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
-#include "servers/rendering/renderer_rd/shaders/cube_to_dp.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/cubemap_filter.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl.gen.h"
-#include "servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/fsr_upscale.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl.gen.h"
@@ -104,24 +97,6 @@ private:
RID pipeline;
} TAA_resolve;
- struct CubemapRoughnessPushConstant {
- uint32_t face_id;
- uint32_t sample_count;
- float roughness;
- uint32_t use_direct_write;
- float face_size;
- float pad[3];
- };
-
- struct CubemapRoughness {
- CubemapRoughnessPushConstant push_constant;
- CubemapRoughnessShaderRD compute_shader;
- CubemapRoughnessRasterShaderRD raster_shader;
- RID shader_version;
- RID compute_pipeline;
- PipelineCacheRD raster_pipeline;
- } roughness;
-
enum LuminanceReduceMode {
LUMINANCE_REDUCE_READ,
LUMINANCE_REDUCE,
@@ -167,19 +142,6 @@ private:
PipelineCacheRD pipelines[LUMINANCE_REDUCE_FRAGMENT_MAX];
} luminance_reduce_raster;
- struct CopyToDPPushConstant {
- float z_far;
- float z_near;
- float texel_size[2];
- float screen_rect[4];
- };
-
- struct CoptToDP {
- CubeToDpShaderRD shader;
- RID shader_version;
- PipelineCacheRD pipeline;
- } cube_to_dp;
-
struct SSEffectsDownsamplePushConstant {
float pixel_size[2];
float z_far;
@@ -419,49 +381,6 @@ private:
} roughness_limiter;
- struct CubemapDownsamplerPushConstant {
- uint32_t face_size;
- uint32_t face_id;
- float pad[2];
- };
-
- struct CubemapDownsampler {
- CubemapDownsamplerPushConstant push_constant;
- CubemapDownsamplerShaderRD compute_shader;
- CubemapDownsamplerRasterShaderRD raster_shader;
- RID shader_version;
- RID compute_pipeline;
- PipelineCacheRD raster_pipeline;
- } cubemap_downsampler;
-
- enum CubemapFilterMode {
- FILTER_MODE_HIGH_QUALITY,
- FILTER_MODE_LOW_QUALITY,
- FILTER_MODE_HIGH_QUALITY_ARRAY,
- FILTER_MODE_LOW_QUALITY_ARRAY,
- FILTER_MODE_MAX,
- };
-
- struct CubemapFilterRasterPushConstant {
- uint32_t mip_level;
- uint32_t face_id;
- float pad[2];
- };
-
- struct CubemapFilter {
- CubemapFilterShaderRD compute_shader;
- CubemapFilterRasterShaderRD raster_shader;
- RID shader_version;
- RID compute_pipelines[FILTER_MODE_MAX];
- PipelineCacheRD raster_pipelines[FILTER_MODE_MAX];
-
- RID uniform_set;
- RID image_uniform_set;
- RID coefficient_buffer;
- bool use_high_quality;
-
- } filter;
-
enum SpecularMergeMode {
SPECULAR_MERGE_ADD,
SPECULAR_MERGE_SSR,
@@ -650,9 +569,6 @@ public:
void fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness);
void taa_resolve(RID p_frame, RID p_temp, RID p_depth, RID p_velocity, RID p_prev_velocity, RID p_history, Size2 p_resolution, float p_z_near, float p_z_far);
- void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
- void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size);
- void copy_cubemap_to_dp(RID p_source_rd_texture, RID p_dst_framebuffer, const Rect2 &p_rect, const Vector2 &p_dst_size, float p_z_near, float p_z_far, bool p_dp_flip);
void luminance_reduction(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
void luminance_reduction_raster(RID p_source_texture, const Size2i p_source_size, const Vector<RID> p_reduce, Vector<RID> p_fb, RID p_prev_luminance, float p_min_luminance, float p_max_luminance, float p_adjust, bool p_set = false);
@@ -703,10 +619,6 @@ public:
void screen_space_indirect_lighting(RID p_diffuse, RID p_destination, RID p_normal_buffer, RID p_depth_mipmaps_texture, RID p_ao, const Vector<RID> p_ao_slices, RID p_ao_pong, const Vector<RID> p_ao_pong_slices, RID p_importance_map, RID p_importance_map_pong, RID p_edges, const Vector<RID> p_edges_slices, const CameraMatrix &p_projection, const CameraMatrix &p_last_projection, const SSILSettings &p_settings, bool p_invalidate_uniform_sets, RID &r_gather_uniform_set, RID &r_importance_map_uniform_set, RID &r_projection_uniform_set);
void roughness_limit(RID p_source_normal, RID p_roughness, const Size2i &p_size, float p_curve);
- void cubemap_downsample(RID p_source_cubemap, RID p_dest_cubemap, const Size2i &p_size);
- void cubemap_downsample_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, const Size2i &p_size);
- void cubemap_filter(RID p_source_cubemap, Vector<RID> p_dest_cubemap, bool p_use_array);
- void cubemap_filter_raster(RID p_source_cubemap, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_mip_level);
void screen_space_reflection(RID p_diffuse, RID p_normal_roughness, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera);
void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection);
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 6f16c0972e..90a7394344 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -5438,9 +5438,9 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas,
Rect2 atlas_rect_norm = atlas_rect;
atlas_rect_norm.position /= float(atlas_size);
atlas_rect_norm.size /= float(atlas_size);
- storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false);
+ copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false);
atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size;
- storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true);
+ copy_effects->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true);
//restore transform so it can be properly used
light_instance_set_shadow_transform(p_light, CameraMatrix(), light_instance->transform, zfar, 0, 0, 0);
diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
index 3a237dbd8c..b3b9b86aa8 100644
--- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp
@@ -438,19 +438,19 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_data(RendererStorageR
}
void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererStorageRD *p_storage, bool p_use_arrays) {
- EffectsRD *effects = p_storage->get_effects();
- ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
- bool prefer_raster_effects = effects->get_prefer_raster_effects();
+ RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton();
+ ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialised");
+ bool prefer_raster_effects = copy_effects->get_prefer_raster_effects();
if (prefer_raster_effects) {
RD::get_singleton()->draw_command_begin_label("Downsample radiance map");
for (int k = 0; k < 6; k++) {
- effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size);
+ copy_effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size);
}
for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
for (int k = 0; k < 6; k++) {
- effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size);
+ copy_effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size);
}
}
RD::get_singleton()->draw_command_end_label(); // Downsample Radiance
@@ -459,24 +459,24 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererS
RD::get_singleton()->draw_command_begin_label("filter radiance map into array heads");
for (int i = 0; i < layers.size(); i++) {
for (int k = 0; k < 6; k++) {
- effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[i].mipmaps[0].framebuffers[k], k, i);
+ copy_effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[i].mipmaps[0].framebuffers[k], k, i);
}
}
} else {
RD::get_singleton()->draw_command_begin_label("filter radiance map into mipmaps directly");
for (int j = 0; j < layers[0].mipmaps.size(); j++) {
for (int k = 0; k < 6; k++) {
- effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[0].mipmaps[j].framebuffers[k], k, j);
+ copy_effects->cubemap_filter_raster(downsampled_radiance_cubemap, layers[0].mipmaps[j].framebuffers[k], k, j);
}
}
}
RD::get_singleton()->draw_command_end_label(); // Filter radiance
} else {
RD::get_singleton()->draw_command_begin_label("Downsample radiance map");
- effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);
+ copy_effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);
for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
- effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
+ copy_effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
}
RD::get_singleton()->draw_command_end_label(); // Downsample Radiance
Vector<RID> views;
@@ -490,26 +490,26 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_fast_filter(RendererS
}
}
RD::get_singleton()->draw_command_begin_label("Fast filter radiance");
- effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays);
+ copy_effects->cubemap_filter(downsampled_radiance_cubemap, views, p_use_arrays);
RD::get_singleton()->draw_command_end_label(); // Filter radiance
}
}
void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(RendererStorageRD *p_storage, bool p_use_arrays, int p_cube_side, int p_base_layer, uint32_t p_sky_ggx_samples_quality) {
- EffectsRD *effects = p_storage->get_effects();
- ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
- bool prefer_raster_effects = effects->get_prefer_raster_effects();
+ RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton();
+ ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialised");
+ bool prefer_raster_effects = copy_effects->get_prefer_raster_effects();
if (prefer_raster_effects) {
if (p_base_layer == 1) {
RD::get_singleton()->draw_command_begin_label("Downsample radiance map");
for (int k = 0; k < 6; k++) {
- effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size);
+ copy_effects->cubemap_downsample_raster(radiance_base_cubemap, downsampled_layer.mipmaps[0].framebuffers[k], k, downsampled_layer.mipmaps[0].size);
}
for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
for (int k = 0; k < 6; k++) {
- effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size);
+ copy_effects->cubemap_downsample_raster(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].framebuffers[k], k, downsampled_layer.mipmaps[i].size);
}
}
RD::get_singleton()->draw_command_end_label(); // Downsample Radiance
@@ -518,7 +518,7 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren
RD::get_singleton()->draw_command_begin_label("High Quality filter radiance");
if (p_use_arrays) {
for (int k = 0; k < 6; k++) {
- effects->cubemap_roughness_raster(
+ copy_effects->cubemap_roughness_raster(
downsampled_radiance_cubemap,
layers[p_base_layer].mipmaps[0].framebuffers[k],
k,
@@ -528,7 +528,7 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren
}
} else {
for (int k = 0; k < 6; k++) {
- effects->cubemap_roughness_raster(
+ copy_effects->cubemap_roughness_raster(
downsampled_radiance_cubemap,
layers[0].mipmaps[p_base_layer].framebuffers[k],
k,
@@ -540,19 +540,19 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren
} else {
if (p_base_layer == 1) {
RD::get_singleton()->draw_command_begin_label("Downsample radiance map");
- effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);
+ copy_effects->cubemap_downsample(radiance_base_cubemap, downsampled_layer.mipmaps[0].view, downsampled_layer.mipmaps[0].size);
for (int i = 1; i < downsampled_layer.mipmaps.size(); i++) {
- effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
+ copy_effects->cubemap_downsample(downsampled_layer.mipmaps[i - 1].view, downsampled_layer.mipmaps[i].view, downsampled_layer.mipmaps[i].size);
}
RD::get_singleton()->draw_command_end_label(); // Downsample Radiance
}
RD::get_singleton()->draw_command_begin_label("High Quality filter radiance");
if (p_use_arrays) {
- effects->cubemap_roughness(downsampled_radiance_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x);
+ copy_effects->cubemap_roughness(downsampled_radiance_cubemap, layers[p_base_layer].views[0], p_cube_side, p_sky_ggx_samples_quality, float(p_base_layer) / (layers.size() - 1.0), layers[p_base_layer].mipmaps[0].size.x);
} else {
- effects->cubemap_roughness(
+ copy_effects->cubemap_roughness(
downsampled_radiance_cubemap,
layers[0].views[p_base_layer],
p_cube_side,
@@ -565,9 +565,9 @@ void RendererSceneSkyRD::ReflectionData::create_reflection_importance_sample(Ren
}
void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStorageRD *p_storage, int p_start, int p_end) {
- EffectsRD *effects = p_storage->get_effects();
- ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialised");
- bool prefer_raster_effects = effects->get_prefer_raster_effects();
+ RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton();
+ ERR_FAIL_NULL_MSG(copy_effects, "Effects haven't been initialised");
+ bool prefer_raster_effects = copy_effects->get_prefer_raster_effects();
RD::get_singleton()->draw_command_begin_label("Update Radiance Cubemap Array Mipmaps");
for (int i = p_start; i < p_end; i++) {
@@ -577,11 +577,11 @@ void RendererSceneSkyRD::ReflectionData::update_reflection_mipmaps(RendererStora
if (prefer_raster_effects) {
for (int k = 0; k < 6; k++) {
RID framebuffer = layers[i].mipmaps[j + 1].framebuffers[k];
- effects->cubemap_downsample_raster(view, framebuffer, k, size);
+ copy_effects->cubemap_downsample_raster(view, framebuffer, k, size);
}
} else {
RID texture = layers[i].views[j + 1];
- effects->cubemap_downsample(view, texture, size);
+ copy_effects->cubemap_downsample(view, texture, size);
}
}
}
diff --git a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl
index e77d0de719..e77d0de719 100644
--- a/servers/rendering/renderer_rd/shaders/cube_to_dp.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl
index 63f0ce690e..63f0ce690e 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler.glsl
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_inc.glsl
index 641e0906f5..641e0906f5 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_inc.glsl
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl
index 0828ffd921..0828ffd921 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_downsampler_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_downsampler_raster.glsl
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl
index 2a774b0eb4..2a774b0eb4 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_filter.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_filter.glsl
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl
index 0990dc7c2f..0990dc7c2f 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_filter_raster.glsl
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl
index 1d46f59408..1d46f59408 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness.glsl
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_inc.glsl
index 1bee428a6f..1bee428a6f 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_roughness_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_inc.glsl
diff --git a/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl
index c29accd8a7..c29accd8a7 100644
--- a/servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cubemap_roughness_raster.glsl