summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/object/class_db.cpp26
-rw-r--r--core/object/class_db.h2
-rw-r--r--core/object/object.h4
-rw-r--r--doc/classes/CPUParticles2D.xml4
-rw-r--r--doc/classes/CPUParticles3D.xml4
-rw-r--r--doc/classes/GPUParticles2D.xml4
-rw-r--r--doc/classes/GPUParticles3D.xml4
-rw-r--r--doc/classes/ProjectSettings.xml3
-rw-r--r--doc/classes/RenderingServer.xml28
-rw-r--r--editor/editor_inspector.cpp273
-rw-r--r--editor/editor_inspector.h12
-rw-r--r--scene/2d/cpu_particles_2d.cpp2
-rw-r--r--scene/2d/gpu_particles_2d.cpp2
-rw-r--r--scene/3d/cpu_particles_3d.h2
-rw-r--r--scene/3d/gpu_particles_3d.cpp2
-rw-r--r--scene/main/node.cpp15
-rw-r--r--scene/main/node.h18
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp28
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp28
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.h2
-rw-r--r--servers/rendering_server.cpp10
-rw-r--r--servers/rendering_server.h6
22 files changed, 361 insertions, 118 deletions
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index d67315f20d..9790cc44e3 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -963,8 +963,11 @@ void ClassDB::add_linked_property(const StringName &p_class, const String &p_pro
ERR_FAIL_COND(!type->property_map.has(p_property));
ERR_FAIL_COND(!type->property_map.has(p_linked_property));
- PropertyInfo &pinfo = type->property_map[p_property];
- pinfo.linked_properties.push_back(p_linked_property);
+ if (!type->linked_properties.has(p_property)) {
+ type->linked_properties.insert(p_property, List<StringName>());
+ }
+ type->linked_properties[p_property].push_back(p_linked_property);
+
#endif
}
@@ -992,6 +995,25 @@ void ClassDB::get_property_list(const StringName &p_class, List<PropertyInfo> *p
}
}
+void ClassDB::get_linked_properties_info(const StringName &p_class, const StringName &p_property, List<StringName> *r_properties, bool p_no_inheritance) {
+#ifdef TOOLS_ENABLED
+ ClassInfo *check = classes.getptr(p_class);
+ while (check) {
+ if (!check->linked_properties.has(p_property)) {
+ return;
+ }
+ for (const StringName &E : check->linked_properties[p_property]) {
+ r_properties->push_back(E);
+ }
+
+ if (p_no_inheritance) {
+ break;
+ }
+ check = check->inherits_ptr;
+ }
+#endif
+}
+
bool ClassDB::get_property_info(const StringName &p_class, const StringName &p_property, PropertyInfo *r_info, bool p_no_inheritance, const Object *p_validator) {
OBJTYPE_RLOCK;
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 8b6a260d86..5fba52e23e 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -120,6 +120,7 @@ public:
List<MethodInfo> virtual_methods;
HashMap<StringName, MethodInfo> virtual_methods_map;
HashMap<StringName, Vector<Error>> method_error_values;
+ HashMap<StringName, List<StringName>> linked_properties;
#endif
HashMap<StringName, PropertySetGet> property_setget;
@@ -312,6 +313,7 @@ public:
static void add_linked_property(const StringName &p_class, const String &p_property, const String &p_linked_property);
static void get_property_list(const StringName &p_class, List<PropertyInfo> *p_list, bool p_no_inheritance = false, const Object *p_validator = nullptr);
static bool get_property_info(const StringName &p_class, const StringName &p_property, PropertyInfo *r_info, bool p_no_inheritance = false, const Object *p_validator = nullptr);
+ static void get_linked_properties_info(const StringName &p_class, const StringName &p_property, List<StringName> *r_properties, bool p_no_inheritance = false);
static bool set_property(Object *p_object, const StringName &p_property, const Variant &p_value, bool *r_valid = nullptr);
static bool get_property(Object *p_object, const StringName &p_property, Variant &r_value);
static bool has_property(const StringName &p_class, const StringName &p_property, bool p_no_inheritance = false);
diff --git a/core/object/object.h b/core/object/object.h
index 649f42c9a0..35d0aaaa7d 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -154,9 +154,7 @@ struct PropertyInfo {
String hint_string;
uint32_t usage = PROPERTY_USAGE_DEFAULT;
-#ifdef TOOLS_ENABLED
- Vector<String> linked_properties;
-#endif
+ // If you are thinking about adding another member to this class, ask the maintainer (Juan) first.
_FORCE_INLINE_ PropertyInfo added_usage(uint32_t p_fl) const {
PropertyInfo pi = *this;
diff --git a/doc/classes/CPUParticles2D.xml b/doc/classes/CPUParticles2D.xml
index dacdca1cee..b0282e4107 100644
--- a/doc/classes/CPUParticles2D.xml
+++ b/doc/classes/CPUParticles2D.xml
@@ -192,8 +192,8 @@
</member>
<member name="linear_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
</member>
- <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
- If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
+ <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="false">
+ If [code]true[/code], particles use the parent node's coordinate space (known as local coordinates). This will cause particles to move and rotate along the [CPUParticles2D] node (and its parents) when it is moved or rotated. If [code]false[/code], particles use global coordinates; they will not move or rotate along the [CPUParticles2D] node (and its parents) when it is moved or rotated.
</member>
<member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
If [code]true[/code], only one emission cycle occurs. If set [code]true[/code] during a cycle, emission will stop at the cycle's end.
diff --git a/doc/classes/CPUParticles3D.xml b/doc/classes/CPUParticles3D.xml
index f2a0040ed4..d8faf8e91d 100644
--- a/doc/classes/CPUParticles3D.xml
+++ b/doc/classes/CPUParticles3D.xml
@@ -224,8 +224,8 @@
<member name="linear_accel_min" type="float" setter="set_param_min" getter="get_param_min" default="0.0">
Minimum linear acceleration.
</member>
- <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
- If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
+ <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="false">
+ If [code]true[/code], particles use the parent node's coordinate space (known as local coordinates). This will cause particles to move and rotate along the [CPUParticles3D] node (and its parents) when it is moved or rotated. If [code]false[/code], particles use global coordinates; they will not move or rotate along the [CPUParticles3D] node (and its parents) when it is moved or rotated.
</member>
<member name="mesh" type="Mesh" setter="set_mesh" getter="get_mesh">
The [Mesh] used for each particle. If [code]null[/code], particles will be spheres.
diff --git a/doc/classes/GPUParticles2D.xml b/doc/classes/GPUParticles2D.xml
index 53894bad87..e60ab094c6 100644
--- a/doc/classes/GPUParticles2D.xml
+++ b/doc/classes/GPUParticles2D.xml
@@ -63,8 +63,8 @@
<member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
Amount of time each particle will exist.
</member>
- <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
- If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
+ <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="false">
+ If [code]true[/code], particles use the parent node's coordinate space (known as local coordinates). This will cause particles to move and rotate along the [GPUParticles2D] node (and its parents) when it is moved or rotated. If [code]false[/code], particles use global coordinates; they will not move or rotate along the [GPUParticles2D] node (and its parents) when it is moved or rotated.
</member>
<member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
If [code]true[/code], only one emission cycle occurs. If set [code]true[/code] during a cycle, emission will stop at the cycle's end.
diff --git a/doc/classes/GPUParticles3D.xml b/doc/classes/GPUParticles3D.xml
index c4bd18db69..b415c56154 100644
--- a/doc/classes/GPUParticles3D.xml
+++ b/doc/classes/GPUParticles3D.xml
@@ -95,8 +95,8 @@
<member name="lifetime" type="float" setter="set_lifetime" getter="get_lifetime" default="1.0">
Amount of time each particle will exist.
</member>
- <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="true">
- If [code]true[/code], particles use the parent node's coordinate space. If [code]false[/code], they use global coordinates.
+ <member name="local_coords" type="bool" setter="set_use_local_coordinates" getter="get_use_local_coordinates" default="false">
+ If [code]true[/code], particles use the parent node's coordinate space (known as local coordinates). This will cause particles to move and rotate along the [GPUParticles3D] node (and its parents) when it is moved or rotated. If [code]false[/code], particles use global coordinates; they will not move or rotate along the [GPUParticles3D] node (and its parents) when it is moved or rotated.
</member>
<member name="one_shot" type="bool" setter="set_one_shot" getter="get_one_shot" default="false">
If [code]true[/code], only [code]amount[/code] particles will be emitted.
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index b1e3d2f628..ae0ec64c27 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1962,9 +1962,11 @@
Lower-end override for [member rendering/shadows/positional_shadow/soft_shadow_filter_quality] on mobile devices, due to performance concerns or driver support.
</member>
<member name="rendering/textures/decals/filter" type="int" setter="" getter="" default="3">
+ The filtering quality to use for [Decal] nodes. When using one of the anisotropic filtering modes, the anisotropic filtering level is controlled by [member rendering/textures/default_filters/anisotropic_filtering_level].
</member>
<member name="rendering/textures/default_filters/anisotropic_filtering_level" type="int" setter="" getter="" default="2">
Sets the maximum number of samples to take when using anisotropic filtering on textures (as a power of two). A higher sample count will result in sharper textures at oblique angles, but is more expensive to compute. A value of [code]0[/code] forcibly disables anisotropic filtering, even on materials where it is enabled.
+ The anisotropic filtering level also affects decals and light projectors if they are configured to use anisotropic filtering. See [member rendering/textures/decals/filter] and [member rendering/textures/light_projectors/filter].
[b]Note:[/b] This property is only read when the project starts. There is currently no way to change this setting at run-time.
</member>
<member name="rendering/textures/default_filters/texture_mipmap_bias" type="float" setter="" getter="" default="0.0">
@@ -1977,6 +1979,7 @@
[b]Note:[/b] This property is only read when the project starts. There is currently no way to change this setting at run-time.
</member>
<member name="rendering/textures/light_projectors/filter" type="int" setter="" getter="" default="3">
+ The filtering quality to use for [OmniLight3D] and [SpotLight3D] projectors. When using one of the anisotropic filtering modes, the anisotropic filtering level is controlled by [member rendering/textures/default_filters/anisotropic_filtering_level].
</member>
<member name="rendering/textures/lossless_compression/force_png" type="bool" setter="" getter="" default="false">
If [code]true[/code], the texture importer will import lossless textures using the PNG format. Otherwise, it will default to using WebP.
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 9616ab3515..9a398b1f33 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -3747,14 +3747,22 @@
Use [Transform3D] to store MultiMesh transform.
</constant>
<constant name="LIGHT_PROJECTOR_FILTER_NEAREST" value="0" enum="LightProjectorFilter">
+ Nearest-neighbor filter for light projectors (use for pixel art light projectors). No mipmaps are used for rendering, which means light projectors at a distance will look sharp but grainy. This has roughly the same performance cost as using mipmaps.
</constant>
- <constant name="LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS" value="1" enum="LightProjectorFilter">
+ <constant name="LIGHT_PROJECTOR_FILTER_LINEAR" value="1" enum="LightProjectorFilter">
+ Linear filter for light projectors (use for non-pixel art light projectors). No mipmaps are used for rendering, which means light projectors at a distance will look smooth but blurry. This has roughly the same performance cost as using mipmaps.
</constant>
- <constant name="LIGHT_PROJECTOR_FILTER_LINEAR" value="2" enum="LightProjectorFilter">
+ <constant name="LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS" value="2" enum="LightProjectorFilter">
+ Nearest-neighbor filter for light projectors (use for pixel art light projectors). Isotropic mipmaps are used for rendering, which means light projectors at a distance will look smooth but blurry. This has roughly the same performance cost as not using mipmaps.
</constant>
<constant name="LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS" value="3" enum="LightProjectorFilter">
+ Linear filter for light projectors (use for non-pixel art light projectors). Isotropic mipmaps are used for rendering, which means light projectors at a distance will look smooth but blurry. This has roughly the same performance cost as not using mipmaps.
</constant>
- <constant name="LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC" value="4" enum="LightProjectorFilter">
+ <constant name="LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC" value="4" enum="LightProjectorFilter">
+ Nearest-neighbor filter for light projectors (use for pixel art light projectors). Anisotropic mipmaps are used for rendering, which means light projectors at a distance will look smooth and sharp when viewed from oblique angles. This looks better compared to isotropic mipmaps, but is slower. The level of anisotropic filtering is defined by [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
+ </constant>
+ <constant name="LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC" value="5" enum="LightProjectorFilter">
+ Linear filter for light projectors (use for non-pixel art light projectors). Anisotropic mipmaps are used for rendering, which means light projectors at a distance will look smooth and sharp when viewed from oblique angles. This looks better compared to isotropic mipmaps, but is slower. The level of anisotropic filtering is defined by [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
</constant>
<constant name="LIGHT_DIRECTIONAL" value="0" enum="LightType">
Is a directional (sun) light.
@@ -3896,14 +3904,22 @@
<constant name="DECAL_TEXTURE_MAX" value="4" enum="DecalTexture">
</constant>
<constant name="DECAL_FILTER_NEAREST" value="0" enum="DecalFilter">
+ Nearest-neighbor filter for decals (use for pixel art decals). No mipmaps are used for rendering, which means decals at a distance will look sharp but grainy. This has roughly the same performance cost as using mipmaps.
</constant>
- <constant name="DECAL_FILTER_NEAREST_MIPMAPS" value="1" enum="DecalFilter">
+ <constant name="DECAL_FILTER_LINEAR" value="1" enum="DecalFilter">
+ Linear filter for decals (use for non-pixel art decals). No mipmaps are used for rendering, which means decals at a distance will look smooth but blurry. This has roughly the same performance cost as using mipmaps.
</constant>
- <constant name="DECAL_FILTER_LINEAR" value="2" enum="DecalFilter">
+ <constant name="DECAL_FILTER_NEAREST_MIPMAPS" value="2" enum="DecalFilter">
+ Nearest-neighbor filter for decals (use for pixel art decals). Isotropic mipmaps are used for rendering, which means decals at a distance will look smooth but blurry. This has roughly the same performance cost as not using mipmaps.
</constant>
<constant name="DECAL_FILTER_LINEAR_MIPMAPS" value="3" enum="DecalFilter">
+ Linear filter for decals (use for non-pixel art decals). Isotropic mipmaps are used for rendering, which means decals at a distance will look smooth but blurry. This has roughly the same performance cost as not using mipmaps.
+ </constant>
+ <constant name="DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC" value="4" enum="DecalFilter">
+ Nearest-neighbor filter for decals (use for pixel art decals). Anisotropic mipmaps are used for rendering, which means decals at a distance will look smooth and sharp when viewed from oblique angles. This looks better compared to isotropic mipmaps, but is slower. The level of anisotropic filtering is defined by [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
</constant>
- <constant name="DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC" value="4" enum="DecalFilter">
+ <constant name="DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC" value="5" enum="DecalFilter">
+ Linear filter for decals (use for non-pixel art decals). Anisotropic mipmaps are used for rendering, which means decals at a distance will look smooth and sharp when viewed from oblique angles. This looks better compared to isotropic mipmaps, but is slower. The level of anisotropic filtering is defined by [member ProjectSettings.rendering/textures/default_filters/anisotropic_filtering_level].
</constant>
<constant name="VOXEL_GI_QUALITY_LOW" value="0" enum="VoxelGIQuality">
</constant>
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index e06e3cbc5f..9f047c775e 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1677,7 +1677,7 @@ void EditorInspectorArray::_panel_gui_input(Ref<InputEvent> p_event, int p_index
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MouseButton::RIGHT) {
+ if (movable && mb->get_button_index() == MouseButton::RIGHT) {
popup_array_index_pressed = begin_array_index + p_index;
rmb_popup->set_item_disabled(OPTION_MOVE_UP, popup_array_index_pressed == 0);
rmb_popup->set_item_disabled(OPTION_MOVE_DOWN, popup_array_index_pressed == count - 1);
@@ -1712,43 +1712,112 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
}
} else if (mode == MODE_USE_COUNT_PROPERTY) {
ERR_FAIL_COND(p_to_pos < -1 || p_to_pos > count);
- List<PropertyInfo> object_property_list;
- object->get_property_list(&object_property_list);
- Array properties_as_array = _extract_properties_as_array(object_property_list);
- properties_as_array.resize(count);
+ if (!swap_method.is_empty()) {
+ ERR_FAIL_COND(!object->has_method(swap_method));
- // For undoing things
- undo_redo->add_undo_property(object, count_property, properties_as_array.size());
- for (int i = 0; i < (int)properties_as_array.size(); i++) {
- Dictionary d = Dictionary(properties_as_array[i]);
- Array keys = d.keys();
- for (int j = 0; j < keys.size(); j++) {
- String key = keys[j];
- undo_redo->add_undo_property(object, vformat(key, i), d[key]);
- }
- }
+ // Swap method was provided, use it.
+ if (p_element_index < 0) {
+ // Add an element at position
+ undo_redo->add_do_property(object, count_property, count + 1);
+ if (p_to_pos >= 0) {
+ for (int i = count; i > p_to_pos; i--) {
+ undo_redo->add_do_method(object, swap_method, i, i - 1);
+ }
+ for (int i = p_to_pos; i < count; i++) {
+ undo_redo->add_undo_method(object, swap_method, i, i + 1);
+ }
+ }
+ undo_redo->add_undo_property(object, count_property, count);
+
+ } else if (p_to_pos < 0) {
+ if (count > 0) {
+ // Remove element at position
+ undo_redo->add_undo_property(object, count_property, count);
+
+ List<PropertyInfo> object_property_list;
+ object->get_property_list(&object_property_list);
+
+ for (int i = p_element_index; i < count - 1; i++) {
+ undo_redo->add_do_method(object, swap_method, i, i + 1);
+ }
+
+ for (int i = count; i > p_element_index; i--) {
+ undo_redo->add_undo_method(object, swap_method, i, i - 1);
+ }
+
+ String erase_prefix = String(array_element_prefix) + itos(p_element_index);
+
+ for (const PropertyInfo &E : object_property_list) {
+ if (E.name.begins_with(erase_prefix)) {
+ undo_redo->add_undo_property(object, E.name, object->get(E.name));
+ }
+ }
- if (p_element_index < 0) {
- // Add an element.
- properties_as_array.insert(p_to_pos < 0 ? properties_as_array.size() : p_to_pos, Dictionary());
- } else if (p_to_pos < 0) {
- // Delete the element.
- properties_as_array.remove_at(p_element_index);
+ undo_redo->add_do_property(object, count_property, count - 1);
+ }
+ } else {
+ if (p_to_pos > p_element_index) {
+ p_to_pos--;
+ }
+
+ if (p_to_pos < p_element_index) {
+ for (int i = p_element_index; i > p_to_pos; i--) {
+ undo_redo->add_do_method(object, swap_method, i, i - 1);
+ }
+ for (int i = p_to_pos; i < p_element_index; i++) {
+ undo_redo->add_undo_method(object, swap_method, i, i + 1);
+ }
+ } else if (p_to_pos > p_element_index) {
+ for (int i = p_element_index; i < p_to_pos; i++) {
+ undo_redo->add_do_method(object, swap_method, i, i + 1);
+ }
+
+ for (int i = p_to_pos; i > p_element_index; i--) {
+ undo_redo->add_undo_method(object, swap_method, i, i - 1);
+ }
+ }
+ }
} else {
- // Move the element.
- properties_as_array.insert(p_to_pos, properties_as_array[p_element_index].duplicate());
- properties_as_array.remove_at(p_to_pos < p_element_index ? p_element_index + 1 : p_element_index);
- }
+ // Use standard properties.
+ List<PropertyInfo> object_property_list;
+ object->get_property_list(&object_property_list);
- // Change the array size then set the properties.
- undo_redo->add_do_property(object, count_property, properties_as_array.size());
- for (int i = 0; i < (int)properties_as_array.size(); i++) {
- Dictionary d = properties_as_array[i];
- Array keys = d.keys();
- for (int j = 0; j < keys.size(); j++) {
- String key = keys[j];
- undo_redo->add_do_property(object, vformat(key, i), d[key]);
+ Array properties_as_array = _extract_properties_as_array(object_property_list);
+ properties_as_array.resize(count);
+
+ // For undoing things
+ undo_redo->add_undo_property(object, count_property, properties_as_array.size());
+ for (int i = 0; i < (int)properties_as_array.size(); i++) {
+ Dictionary d = Dictionary(properties_as_array[i]);
+ Array keys = d.keys();
+ for (int j = 0; j < keys.size(); j++) {
+ String key = keys[j];
+ undo_redo->add_undo_property(object, vformat(key, i), d[key]);
+ }
+ }
+
+ if (p_element_index < 0) {
+ // Add an element.
+ properties_as_array.insert(p_to_pos < 0 ? properties_as_array.size() : p_to_pos, Dictionary());
+ } else if (p_to_pos < 0) {
+ // Delete the element.
+ properties_as_array.remove_at(p_element_index);
+ } else {
+ // Move the element.
+ properties_as_array.insert(p_to_pos, properties_as_array[p_element_index].duplicate());
+ properties_as_array.remove_at(p_to_pos < p_element_index ? p_element_index + 1 : p_element_index);
+ }
+
+ // Change the array size then set the properties.
+ undo_redo->add_do_property(object, count_property, properties_as_array.size());
+ for (int i = 0; i < (int)properties_as_array.size(); i++) {
+ Dictionary d = properties_as_array[i];
+ Array keys = d.keys();
+ for (int j = 0; j < keys.size(); j++) {
+ String key = keys[j];
+ undo_redo->add_do_property(object, vformat(key, i), d[key]);
+ }
}
}
}
@@ -1988,6 +2057,20 @@ void EditorInspectorArray::_setup() {
page = CLAMP(page, 0, max_page);
}
+ Ref<Font> numbers_font;
+ int numbers_min_w = 0;
+
+ if (numbered) {
+ numbers_font = get_theme_font(SNAME("bold"), SNAME("EditorFonts"));
+ int digits_found = count;
+ String test;
+ while (digits_found) {
+ test += "8";
+ digits_found /= 10;
+ }
+ numbers_min_w = numbers_font->get_string_size(test).width;
+ }
+
for (int i = 0; i < (int)array_elements.size(); i++) {
ArrayElement &ae = array_elements[i];
@@ -2022,19 +2105,38 @@ void EditorInspectorArray::_setup() {
ae.margin->add_child(ae.hbox);
// Move button.
- ae.move_texture_rect = memnew(TextureRect);
- ae.move_texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
- ae.move_texture_rect->set_default_cursor_shape(Control::CURSOR_MOVE);
- if (is_inside_tree()) {
- ae.move_texture_rect->set_texture(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons")));
+ if (movable) {
+ ae.move_texture_rect = memnew(TextureRect);
+ ae.move_texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
+ ae.move_texture_rect->set_default_cursor_shape(Control::CURSOR_MOVE);
+
+ if (is_inside_tree()) {
+ ae.move_texture_rect->set_texture(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons")));
+ }
+ ae.hbox->add_child(ae.move_texture_rect);
+ }
+
+ if (numbered) {
+ ae.number = memnew(Label);
+ ae.number->add_theme_font_override("font", numbers_font);
+ ae.number->set_custom_minimum_size(Size2(numbers_min_w, 0));
+ ae.number->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
+ ae.number->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
+ ae.number->set_text(itos(begin_array_index + i));
+ ae.hbox->add_child(ae.number);
}
- ae.hbox->add_child(ae.move_texture_rect);
// Right vbox.
ae.vbox = memnew(VBoxContainer);
ae.vbox->set_h_size_flags(SIZE_EXPAND_FILL);
ae.vbox->set_v_size_flags(SIZE_EXPAND_FILL);
ae.hbox->add_child(ae.vbox);
+
+ ae.erase = memnew(Button);
+ ae.erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ ae.erase->set_v_size_flags(SIZE_SHRINK_CENTER);
+ ae.erase->connect("pressed", callable_mp(this, &EditorInspectorArray::_remove_item).bind(begin_array_index + i));
+ ae.hbox->add_child(ae.erase);
}
// Hide/show the add button.
@@ -2049,7 +2151,14 @@ void EditorInspectorArray::_setup() {
}
}
+void EditorInspectorArray::_remove_item(int p_index) {
+ _move_element(p_index, -1);
+}
+
Variant EditorInspectorArray::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
+ if (!movable) {
+ return Variant();
+ }
int index = p_from->get_meta("index");
Dictionary dict;
dict["type"] = "property_array_element";
@@ -2071,6 +2180,9 @@ void EditorInspectorArray::drop_data_fw(const Point2 &p_point, const Variant &p_
}
bool EditorInspectorArray::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
+ if (!movable) {
+ return false;
+ }
// First, update drawing.
control_dropping->update();
@@ -2100,13 +2212,19 @@ void EditorInspectorArray::_notification(int p_what) {
for (int i = 0; i < (int)array_elements.size(); i++) {
ArrayElement &ae = array_elements[i];
- ae.move_texture_rect->set_texture(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons")));
+ if (ae.move_texture_rect) {
+ ae.move_texture_rect->set_texture(get_theme_icon(SNAME("TripleBar"), SNAME("EditorIcons")));
+ }
Size2 min_size = get_theme_stylebox(SNAME("Focus"), SNAME("EditorStyles"))->get_minimum_size();
ae.margin->add_theme_constant_override("margin_left", min_size.x / 2);
ae.margin->add_theme_constant_override("margin_top", min_size.y / 2);
ae.margin->add_theme_constant_override("margin_right", min_size.x / 2);
ae.margin->add_theme_constant_override("margin_bottom", min_size.y / 2);
+
+ if (ae.erase) {
+ ae.erase->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ }
}
add_button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
@@ -2142,23 +2260,31 @@ void EditorInspectorArray::set_undo_redo(UndoRedo *p_undo_redo) {
undo_redo = p_undo_redo;
}
-void EditorInspectorArray::setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable) {
+void EditorInspectorArray::setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable, bool p_numbered, int p_page_length, const String &p_add_item_text) {
count_property = "";
mode = MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION;
array_element_prefix = p_array_element_prefix;
page = p_page;
+ movable = p_movable;
+ page_length = p_page_length;
+ numbered = p_numbered;
EditorInspectorSection::setup(String(p_array_element_prefix) + "_array", p_label, p_object, p_bg_color, p_foldable, 0);
_setup();
}
-void EditorInspectorArray::setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable) {
+void EditorInspectorArray::setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable, bool p_numbered, int p_page_length, const String &p_add_item_text, const String &p_swap_method) {
count_property = p_count_property;
mode = MODE_USE_COUNT_PROPERTY;
array_element_prefix = p_array_element_prefix;
page = p_page;
+ movable = p_movable;
+ page_length = p_page_length;
+ numbered = p_numbered;
+ swap_method = p_swap_method;
+ add_button->set_text(p_add_item_text);
EditorInspectorSection::setup(String(count_property) + "_array", p_label, p_object, p_bg_color, p_foldable, 0);
_setup();
@@ -2887,9 +3013,35 @@ void EditorInspector::update_tree() {
StringName array_element_prefix;
Color c = sscolor;
c.a /= level;
+
+ Vector<String> class_name_components = String(p.class_name).split(",");
+
+ array_element_prefix = class_name_components[1];
+ int page_size = 5;
+ bool movable = true;
+ bool numbered = false;
+ bool foldable = use_folding;
+ String add_button_text;
+ String swap_method;
+ for (int i = (p.type == Variant::NIL ? 1 : 2); i < class_name_components.size(); i++) {
+ if (class_name_components[i].begins_with("page_size") && class_name_components[i].get_slice_count("=") == 2) {
+ page_size = class_name_components[i].get_slice("=", 1).to_int();
+ } else if (class_name_components[i].begins_with("add_button_text") && class_name_components[i].get_slice_count("=") == 2) {
+ add_button_text = class_name_components[i].get_slice("=", 1).strip_edges();
+ } else if (class_name_components[i] == "static") {
+ movable = false;
+ } else if (class_name_components[i] == "numbered") {
+ numbered = true;
+ } else if (class_name_components[i] == "unfoldable") {
+ foldable = false;
+ } else if (class_name_components[i].begins_with("swap_method") && class_name_components[i].get_slice_count("=") == 2) {
+ swap_method = class_name_components[i].get_slice("=", 1).strip_edges();
+ }
+ }
+
if (p.type == Variant::NIL) {
// Setup the array to use a method to create/move/delete elements.
- array_element_prefix = p.class_name;
+ array_element_prefix = class_name_components[0];
editor_inspector_array = memnew(EditorInspectorArray);
String array_label = path.contains("/") ? path.substr(path.rfind("/") + 1) : path;
@@ -2900,13 +3052,14 @@ void EditorInspector::update_tree() {
editor_inspector_array->set_undo_redo(undo_redo);
} else if (p.type == Variant::INT) {
// Setup the array to use the count property and built-in functions to create/move/delete elements.
- Vector<String> class_name_components = String(p.class_name).split(",");
- if (class_name_components.size() == 2) {
- array_element_prefix = class_name_components[1];
+
+ if (class_name_components.size() > 2) {
editor_inspector_array = memnew(EditorInspectorArray);
int page = per_array_page.has(array_element_prefix) ? per_array_page[array_element_prefix] : 0;
- editor_inspector_array->setup_with_count_property(object, class_name_components[0], p.name, array_element_prefix, page, c, use_folding);
+
+ editor_inspector_array->setup_with_count_property(object, class_name_components[0], p.name, array_element_prefix, page, c, foldable, movable, numbered, page_size, add_button_text, swap_method);
editor_inspector_array->connect("page_change_request", callable_mp(this, &EditorInspector::_page_change_request).bind(array_element_prefix));
+
editor_inspector_array->set_undo_redo(undo_redo);
}
}
@@ -2915,6 +3068,7 @@ void EditorInspector::update_tree() {
current_vbox->add_child(editor_inspector_array);
editor_inspector_array_per_prefix[array_element_prefix] = editor_inspector_array;
}
+
continue;
}
@@ -3396,14 +3550,23 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
undo_redo->add_undo_property(object, p_name, value);
}
- PropertyInfo prop_info;
- if (ClassDB::get_property_info(object->get_class_name(), p_name, &prop_info)) {
- for (const String &linked_prop : prop_info.linked_properties) {
- valid = false;
- value = object->get(linked_prop, &valid);
- if (valid) {
- undo_redo->add_undo_property(object, linked_prop, value);
- }
+ List<StringName> linked_properties;
+ ClassDB::get_linked_properties_info(object->get_class_name(), p_name, &linked_properties);
+
+ for (const StringName &linked_prop : linked_properties) {
+ valid = false;
+ Variant undo_value = object->get(linked_prop, &valid);
+ if (valid) {
+ undo_redo->add_undo_property(object, linked_prop, undo_value);
+ }
+ }
+
+ PackedStringArray linked_properties_dynamic = object->call("_get_linked_undo_properties", p_name, p_value);
+ for (int i = 0; i < linked_properties_dynamic.size(); i++) {
+ valid = false;
+ Variant undo_value = object->get(linked_properties_dynamic[i], &valid);
+ if (valid) {
+ undo_redo->add_undo_property(object, linked_properties_dynamic[i], undo_value);
}
}
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 54533de960..9b5e295854 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -321,6 +321,7 @@ class EditorInspectorArray : public EditorInspectorSection {
} mode;
StringName count_property;
StringName array_element_prefix;
+ String swap_method;
int count = 0;
@@ -342,6 +343,9 @@ class EditorInspectorArray : public EditorInspectorSection {
int begin_array_index = 0;
int end_array_index = 0;
+ bool movable = true;
+ bool numbered = false;
+
enum MenuOptions {
OPTION_MOVE_UP = 0,
OPTION_MOVE_DOWN,
@@ -359,7 +363,9 @@ class EditorInspectorArray : public EditorInspectorSection {
MarginContainer *margin = nullptr;
HBoxContainer *hbox = nullptr;
TextureRect *move_texture_rect = nullptr;
+ Label *number = nullptr;
VBoxContainer *vbox = nullptr;
+ Button *erase = nullptr;
};
LocalVector<ArrayElement> array_elements;
@@ -395,6 +401,8 @@ class EditorInspectorArray : public EditorInspectorSection {
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
+ void _remove_item(int p_index);
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -402,8 +410,8 @@ protected:
public:
void set_undo_redo(UndoRedo *p_undo_redo);
- void setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable);
- void setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable);
+ void setup_with_move_element_function(Object *p_object, String p_label, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "");
+ void setup_with_count_property(Object *p_object, String p_label, const StringName &p_count_property, const StringName &p_array_element_prefix, int p_page, const Color &p_bg_color, bool p_foldable, bool p_movable = true, bool p_numbered = false, int p_page_length = 5, const String &p_add_item_text = "", const String &p_swap_method = "");
VBoxContainer *get_vbox(int p_index);
EditorInspectorArray();
diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp
index 4155d0797f..26204a3b1a 100644
--- a/scene/2d/cpu_particles_2d.cpp
+++ b/scene/2d/cpu_particles_2d.cpp
@@ -1470,7 +1470,7 @@ CPUParticles2D::CPUParticles2D() {
set_emitting(true);
set_amount(8);
- set_use_local_coordinates(true);
+ set_use_local_coordinates(false);
set_param_min(PARAM_INITIAL_LINEAR_VELOCITY, 0);
set_param_min(PARAM_ANGULAR_VELOCITY, 0);
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index a869cf2525..075421a26d 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -660,7 +660,7 @@ GPUParticles2D::GPUParticles2D() {
set_explosiveness_ratio(0);
set_randomness_ratio(0);
set_visibility_rect(Rect2(Vector2(-100, -100), Vector2(200, 200)));
- set_use_local_coordinates(true);
+ set_use_local_coordinates(false);
set_draw_order(DRAW_ORDER_LIFETIME);
set_speed_scale(1);
set_fixed_fps(30);
diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h
index 4cb693f494..e26c301038 100644
--- a/scene/3d/cpu_particles_3d.h
+++ b/scene/3d/cpu_particles_3d.h
@@ -138,7 +138,7 @@ private:
real_t randomness_ratio = 0.0;
double lifetime_randomness = 0.0;
double speed_scale = 1.0;
- bool local_coords = true;
+ bool local_coords = false;
int fixed_fps = 0;
bool fractional_delta = true;
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index 01aff32954..2ee126e161 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -631,7 +631,7 @@ GPUParticles3D::GPUParticles3D() {
set_randomness_ratio(0);
set_trail_length(0.3);
set_visibility_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)));
- set_use_local_coordinates(true);
+ set_use_local_coordinates(false);
set_draw_passes(1);
set_draw_order(DRAW_ORDER_INDEX);
set_speed_scale(1);
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 6617bd1726..ea9788de27 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -653,21 +653,6 @@ Error Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::CallE
return err;
}
-template <typename... VarArgs>
-Error Node::rpc(const StringName &p_method, VarArgs... p_args) {
- return rpc_id(0, p_method, p_args...);
-}
-
-template <typename... VarArgs>
-Error Node::rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args) {
- Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
- const Variant *argptrs[sizeof...(p_args) + 1];
- for (uint32_t i = 0; i < sizeof...(p_args); i++) {
- argptrs[i] = &args[i];
- }
- return rpcp(p_peer_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
-}
-
Error Node::rpcp(int p_peer_id, const StringName &p_method, const Variant **p_arg, int p_argcount) {
ERR_FAIL_COND_V(!is_inside_tree(), ERR_UNCONFIGURED);
return get_multiplayer()->rpcp(this, p_peer_id, p_method, p_arg, p_argcount);
diff --git a/scene/main/node.h b/scene/main/node.h
index 0645c68eb9..ccd1d561d2 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -512,4 +512,22 @@ VARIANT_ENUM_CAST(Node::DuplicateFlags);
typedef HashSet<Node *, Node::Comparator> NodeSet;
+// Template definitions must be in the header so they are always fully initialized before their usage.
+// See this StackOverflow question for more information: https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file
+
+template <typename... VarArgs>
+Error Node::rpc(const StringName &p_method, VarArgs... p_args) {
+ return rpc_id(0, p_method, p_args...);
+}
+
+template <typename... VarArgs>
+Error Node::rpc_id(int p_peer_id, const StringName &p_method, VarArgs... p_args) {
+ Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
+ const Variant *argptrs[sizeof...(p_args) + 1];
+ for (uint32_t i = 0; i < sizeof...(p_args); i++) {
+ argptrs[i] = &args[i];
+ }
+ return rpcp(p_peer_id, p_method, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
+}
+
#endif // NODE_H
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 827cce6047..c3af0868e0 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -2265,15 +2265,18 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
case RS::DECAL_FILTER_NEAREST: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
- case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
case RS::DECAL_FILTER_LINEAR: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
+ sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
@@ -2292,15 +2295,18 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
- case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
+ sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
sampler = material_storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
@@ -3275,12 +3281,18 @@ void RenderForwardClustered::_update_shader_quality_settings() {
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
sc.constant_id = SPEC_CONSTANT_DECAL_FILTER;
- sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+ sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS ||
+ decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS ||
+ decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC ||
+ decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
spec_constants.push_back(sc);
sc.constant_id = SPEC_CONSTANT_PROJECTOR_FILTER;
- sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+ sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS ||
+ light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS ||
+ light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC ||
+ light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
spec_constants.push_back(sc);
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 15f810fb3b..f74ad7617d 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -1214,15 +1214,18 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
case RS::DECAL_FILTER_NEAREST: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
- case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
case RS::DECAL_FILTER_LINEAR: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS: {
+ sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
@@ -1241,15 +1244,18 @@ void RenderForwardMobile::_update_render_base_uniform_set() {
case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
- case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
- sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- } break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: {
+ sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
+ case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC: {
+ sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ } break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
@@ -2558,12 +2564,18 @@ void RenderForwardMobile::_update_shader_quality_settings() {
sc.type = RD::PIPELINE_SPECIALIZATION_CONSTANT_TYPE_BOOL;
sc.constant_id = SPEC_CONSTANT_DECAL_USE_MIPMAPS;
- sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS || decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+ sc.bool_value = decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS ||
+ decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS ||
+ decals_get_filter() == RS::DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC ||
+ decals_get_filter() == RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
spec_constants.push_back(sc);
sc.constant_id = SPEC_CONSTANT_PROJECTOR_USE_MIPMAPS;
- sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS || light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
+ sc.bool_value = light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS ||
+ light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS ||
+ light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC ||
+ light_projectors_get_filter() == RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC;
spec_constants.push_back(sc);
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.h b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
index 04ecfcfdce..8a69ee45f9 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.h
@@ -159,7 +159,7 @@ private:
real_t randomness = 0.0;
bool restart_request = false;
AABB custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8));
- bool use_local_coords = true;
+ bool use_local_coords = false;
bool has_collision_cache = false;
bool has_sdf_collision = false;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index bb76281782..e02d82fbc3 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -1885,9 +1885,10 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("light_projectors_set_filter", "filter"), &RenderingServer::light_projectors_set_filter);
BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_NEAREST);
- BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS);
BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_LINEAR);
+ BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS);
BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS);
+ BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC);
BIND_ENUM_CONSTANT(LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC);
BIND_ENUM_CONSTANT(LIGHT_DIRECTIONAL);
@@ -1989,9 +1990,10 @@ void RenderingServer::_bind_methods() {
BIND_ENUM_CONSTANT(DECAL_TEXTURE_MAX);
BIND_ENUM_CONSTANT(DECAL_FILTER_NEAREST);
- BIND_ENUM_CONSTANT(DECAL_FILTER_NEAREST_MIPMAPS);
BIND_ENUM_CONSTANT(DECAL_FILTER_LINEAR);
+ BIND_ENUM_CONSTANT(DECAL_FILTER_NEAREST_MIPMAPS);
BIND_ENUM_CONSTANT(DECAL_FILTER_LINEAR_MIPMAPS);
+ BIND_ENUM_CONSTANT(DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC);
BIND_ENUM_CONSTANT(DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC);
/* GI API (affects VoxelGI and SDFGI) */
@@ -2956,9 +2958,9 @@ void RenderingServer::init() {
PROPERTY_HINT_RANGE, "-2,2,0.001"));
GLOBAL_DEF("rendering/textures/decals/filter", DECAL_FILTER_LINEAR_MIPMAPS);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/decals/filter", PropertyInfo(Variant::INT, "rendering/textures/decals/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Nearest+Mipmaps,Linear,Linear+Mipmaps,Linear+Mipmaps Anisotropic (Slow)"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/decals/filter", PropertyInfo(Variant::INT, "rendering/textures/decals/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Linear (Fast),Nearest Mipmap (Fast),Linear Mipmap (Fast),Nearest Mipmap Anisotropic (Average),Linear Mipmap Anisotropic (Average)"));
GLOBAL_DEF("rendering/textures/light_projectors/filter", LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/light_projectors/filter", PropertyInfo(Variant::INT, "rendering/textures/light_projectors/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Nearest+Mipmaps,Linear,Linear+Mipmaps,Linear+Mipmaps Anisotropic (Slow)"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/light_projectors/filter", PropertyInfo(Variant::INT, "rendering/textures/light_projectors/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Linear (Fast),Nearest Mipmap (Fast),Linear Mipmap (Fast),Nearest Mipmap Anisotropic (Average),Linear Mipmap Anisotropic (Average)"));
GLOBAL_DEF_RST("rendering/occlusion_culling/occlusion_rays_per_thread", 512);
GLOBAL_DEF_RST("rendering/occlusion_culling/bvh_build_quality", 2);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 1f2012ac8d..845a4a7a3e 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -495,9 +495,10 @@ public:
enum LightProjectorFilter {
LIGHT_PROJECTOR_FILTER_NEAREST,
- LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS,
LIGHT_PROJECTOR_FILTER_LINEAR,
+ LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS,
LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS,
+ LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS_ANISOTROPIC,
LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC,
};
@@ -557,9 +558,10 @@ public:
enum DecalFilter {
DECAL_FILTER_NEAREST,
- DECAL_FILTER_NEAREST_MIPMAPS,
DECAL_FILTER_LINEAR,
+ DECAL_FILTER_NEAREST_MIPMAPS,
DECAL_FILTER_LINEAR_MIPMAPS,
+ DECAL_FILTER_NEAREST_MIPMAPS_ANISOTROPIC,
DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC,
};