summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYRIGHT.txt5
-rw-r--r--SConstruct7
-rw-r--r--core/config/project_settings.cpp125
-rw-r--r--core/config/project_settings.h13
-rw-r--r--core/extension/gdnative_interface.cpp17
-rw-r--r--core/extension/gdnative_interface.h5
-rw-r--r--core/input/input.cpp16
-rw-r--r--core/input/input.h2
-rw-r--r--core/io/config_file.cpp4
-rw-r--r--core/io/image.cpp72
-rw-r--r--core/io/image.h9
-rw-r--r--core/io/packed_data_container.cpp4
-rw-r--r--core/math/a_star.cpp4
-rw-r--r--core/math/bvh.h2
-rw-r--r--core/math/bvh_pair.inc2
-rw-r--r--core/math/convex_hull.cpp2
-rw-r--r--core/math/delaunay_2d.h4
-rw-r--r--core/math/expression.cpp6
-rw-r--r--core/object/undo_redo.cpp2
-rw-r--r--core/string/node_path.cpp6
-rw-r--r--core/string/ustring.cpp8
-rw-r--r--core/string/ustring.h2
-rw-r--r--core/templates/bin_sorted_array.h2
-rw-r--r--core/templates/cowdata.h2
-rw-r--r--core/templates/local_vector.h6
-rw-r--r--core/templates/vector.h4
-rw-r--r--core/templates/vmap.h2
-rw-r--r--core/templates/vset.h2
-rw-r--r--core/variant/array.cpp8
-rw-r--r--core/variant/array.h2
-rw-r--r--core/variant/variant_call.cpp20
-rw-r--r--core/variant/variant_setget.cpp6
-rw-r--r--doc/classes/@GlobalScope.xml10
-rw-r--r--doc/classes/Array.xml4
-rw-r--r--doc/classes/Control.xml6
-rw-r--r--doc/classes/Image.xml10
-rw-r--r--doc/classes/Input.xml7
-rw-r--r--doc/classes/Node.xml13
-rw-r--r--doc/classes/Object.xml1
-rw-r--r--doc/classes/PackedByteArray.xml2
-rw-r--r--doc/classes/PackedColorArray.xml2
-rw-r--r--doc/classes/PackedFloat32Array.xml2
-rw-r--r--doc/classes/PackedFloat64Array.xml2
-rw-r--r--doc/classes/PackedInt32Array.xml2
-rw-r--r--doc/classes/PackedInt64Array.xml2
-rw-r--r--doc/classes/PackedScene.xml4
-rw-r--r--doc/classes/PackedStringArray.xml2
-rw-r--r--doc/classes/PackedVector2Array.xml2
-rw-r--r--doc/classes/PackedVector3Array.xml2
-rw-r--r--doc/classes/ProjectSettings.xml31
-rw-r--r--doc/classes/ReferenceRect.xml2
-rw-r--r--doc/classes/RenderingServer.xml37
-rw-r--r--doc/classes/TextEdit.xml18
-rw-r--r--doc/classes/TextServer.xml8
-rw-r--r--doc/classes/TextServerExtension.xml8
-rw-r--r--doc/classes/Viewport.xml30
-rw-r--r--doc/classes/Window.xml6
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h2
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp1
-rw-r--r--drivers/vulkan/vulkan_context.cpp18
-rw-r--r--drivers/vulkan/vulkan_context.h12
-rw-r--r--editor/action_map_editor.cpp2
-rw-r--r--editor/connections_dialog.cpp6
-rw-r--r--editor/create_dialog.cpp2
-rw-r--r--editor/debugger/script_editor_debugger.cpp2
-rw-r--r--editor/dependency_editor.cpp4
-rw-r--r--editor/editor_autoload_settings.cpp12
-rw-r--r--editor/editor_data.cpp8
-rw-r--r--editor/editor_export.cpp2
-rw-r--r--editor/editor_file_dialog.cpp10
-rw-r--r--editor/editor_file_system.cpp4
-rw-r--r--editor/editor_inspector.cpp8
-rw-r--r--editor/editor_node.cpp18
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_properties_array_dict.cpp2
-rw-r--r--editor/editor_run.cpp2
-rw-r--r--editor/editor_spin_slider.cpp2
-rw-r--r--editor/editor_vcs_interface.cpp21
-rw-r--r--editor/editor_vcs_interface.h6
-rw-r--r--editor/filesystem_dock.cpp18
-rw-r--r--editor/import/collada.cpp8
-rw-r--r--editor/import/dynamicfont_import_settings.cpp4
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp2
-rw-r--r--editor/localization_editor.cpp8
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp4
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp4
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp77
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h10
-rw-r--r--editor/plugins/collision_polygon_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/curve_editor_plugin.cpp2
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp6
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/script_editor_plugin.cpp12
-rw-r--r--editor/plugins/script_text_editor.cpp6
-rw-r--r--editor/plugins/shader_editor_plugin.cpp2
-rw-r--r--editor/plugins/text_editor.cpp2
-rw-r--r--editor/plugins/theme_editor_preview.cpp3
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp6
-rw-r--r--editor/plugins/tiles/tile_proxies_manager_dialog.cpp2
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp33
-rw-r--r--editor/plugins/version_control_editor_plugin.h4
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp28
-rw-r--r--editor/project_manager.cpp247
-rw-r--r--editor/property_editor.cpp2
-rw-r--r--editor/scene_tree_dock.cpp12
-rw-r--r--editor/settings_config_dialog.cpp4
-rw-r--r--glsl_builders.py13
-rw-r--r--main/main.cpp28
-rw-r--r--modules/bullet/area_bullet.cpp4
-rw-r--r--modules/bullet/collision_object_bullet.cpp4
-rw-r--r--modules/bullet/soft_body_bullet.cpp2
-rw-r--r--modules/csg/csg.cpp16
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml4
-rw-r--r--modules/gdscript/gdscript.cpp4
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.cpp55
-rw-r--r--modules/gdscript/gdscript_warning.cpp5
-rw-r--r--modules/gdscript/gdscript_warning.h1
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp2
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out9
-rw-r--r--modules/gltf/gltf_document.cpp5
-rw-r--r--modules/mono/csharp_script.cpp6
-rw-r--r--modules/mono/glue/collections_glue.cpp4
-rw-r--r--modules/navigation/godot_navigation_server.cpp8
-rw-r--r--modules/text_server_adv/text_server_adv.cpp2
-rw-r--r--modules/text_server_fb/text_server_fb.cpp2
-rw-r--r--modules/upnp/upnp.cpp2
-rw-r--r--modules/visual_script/editor/visual_script_editor.cpp41
-rw-r--r--modules/visual_script/visual_script.cpp2
-rw-r--r--modules/visual_script/visual_script_expression.cpp6
-rw-r--r--modules/visual_script/visual_script_nodes.cpp6
-rw-r--r--platform/android/android_input_handler.cpp2
-rw-r--r--platform/android/export/export_plugin.cpp2
-rw-r--r--platform/linuxbsd/display_server_x11.cpp2
-rw-r--r--platform/linuxbsd/joypad_linux.cpp2
-rw-r--r--platform/osx/gl_manager_osx.mm2
-rw-r--r--platform/osx/joypad_osx.cpp2
-rw-r--r--platform/uwp/export/export_plugin.cpp2
-rw-r--r--platform/windows/gl_manager_windows.cpp4
-rw-r--r--scene/2d/audio_stream_player_2d.cpp2
-rw-r--r--scene/2d/collision_object_2d.cpp2
-rw-r--r--scene/2d/line_2d.cpp2
-rw-r--r--scene/2d/navigation_region_2d.cpp2
-rw-r--r--scene/2d/polygon_2d.cpp2
-rw-r--r--scene/2d/skeleton_2d.cpp2
-rw-r--r--scene/2d/tile_map.cpp6
-rw-r--r--scene/3d/audio_stream_player_3d.cpp2
-rw-r--r--scene/3d/collision_object_3d.cpp2
-rw-r--r--scene/3d/node_3d.cpp2
-rw-r--r--scene/3d/physics_body_3d.cpp28
-rw-r--r--scene/3d/skeleton_3d.cpp2
-rw-r--r--scene/3d/soft_dynamic_body_3d.cpp2
-rw-r--r--scene/animation/animation_blend_space_2d.cpp4
-rw-r--r--scene/animation/animation_node_state_machine.cpp8
-rw-r--r--scene/animation/animation_tree.cpp2
-rw-r--r--scene/audio/audio_stream_player.cpp2
-rw-r--r--scene/gui/code_edit.cpp6
-rw-r--r--scene/gui/control.cpp5
-rw-r--r--scene/gui/control.h1
-rw-r--r--scene/gui/gradient_edit.cpp4
-rw-r--r--scene/gui/item_list.cpp4
-rw-r--r--scene/gui/line_edit.cpp4
-rw-r--r--scene/gui/popup_menu.cpp2
-rw-r--r--scene/gui/rich_text_label.cpp6
-rw-r--r--scene/gui/tab_bar.cpp4
-rw-r--r--scene/gui/text_edit.cpp98
-rw-r--r--scene/gui/text_edit.h23
-rw-r--r--scene/gui/tree.cpp2
-rw-r--r--scene/gui/tree.h2
-rw-r--r--scene/main/node.cpp10
-rw-r--r--scene/main/node.h2
-rw-r--r--scene/main/viewport.cpp96
-rw-r--r--scene/main/viewport.h28
-rw-r--r--scene/main/window.cpp5
-rw-r--r--scene/main/window.h1
-rw-r--r--scene/resources/animation.cpp48
-rw-r--r--scene/resources/curve.cpp8
-rw-r--r--scene/resources/font.cpp6
-rw-r--r--scene/resources/gradient.cpp2
-rw-r--r--scene/resources/packed_scene.cpp2
-rw-r--r--scene/resources/resource_format_text.cpp2
-rw-r--r--scene/resources/skeleton_modification_stack_2d.cpp2
-rw-r--r--scene/resources/skeleton_modification_stack_3d.cpp4
-rw-r--r--scene/resources/sprite_frames.cpp2
-rw-r--r--scene/resources/syntax_highlighter.cpp2
-rw-r--r--scene/resources/tile_set.cpp44
-rw-r--r--scene/resources/visual_shader.cpp2
-rw-r--r--servers/audio_server.cpp6
-rw-r--r--servers/camera_server.cpp2
-rw-r--r--servers/physics_2d/godot_body_2d.cpp3
-rw-r--r--servers/physics_2d/godot_body_2d.h2
-rw-r--r--servers/physics_2d/godot_collision_object_2d.cpp2
-rw-r--r--servers/physics_3d/godot_body_3d.cpp3
-rw-r--r--servers/physics_3d/godot_body_3d.h2
-rw-r--r--servers/physics_3d/godot_collision_object_3d.cpp2
-rw-r--r--servers/physics_3d/godot_soft_body_3d.cpp2
-rw-r--r--servers/physics_3d/godot_soft_body_3d.h2
-rw-r--r--servers/rendering/rasterizer_dummy.h2
-rw-r--r--servers/rendering/renderer_canvas_cull.h2
-rw-r--r--servers/rendering/renderer_compositor.h3
-rw-r--r--servers/rendering/renderer_rd/cluster_builder_rd.cpp8
-rw-r--r--servers/rendering/renderer_rd/effects_rd.cpp59
-rw-r--r--servers/rendering/renderer_rd/effects_rd.h24
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp48
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h6
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.cpp6
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h2
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp16
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp195
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.h15
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.cpp106
-rw-r--r--servers/rendering/renderer_rd/renderer_storage_rd.h8
-rw-r--r--servers/rendering/renderer_rd/shader_rd.cpp3
-rw-r--r--servers/rendering/renderer_rd/shaders/fsr_upscale.glsl173
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/volumetric_fog.glsl38
-rw-r--r--servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl35
-rw-r--r--servers/rendering/renderer_scene.h2
-rw-r--r--servers/rendering/renderer_scene_cull.cpp2
-rw-r--r--servers/rendering/renderer_scene_cull.h2
-rw-r--r--servers/rendering/renderer_scene_render.h2
-rw-r--r--servers/rendering/renderer_viewport.cpp110
-rw-r--r--servers/rendering/renderer_viewport.h15
-rw-r--r--servers/rendering/rendering_device.h1
-rw-r--r--servers/rendering/rendering_server_default.h6
-rw-r--r--servers/rendering/shader_language.cpp36
-rw-r--r--servers/rendering_server.cpp38
-rw-r--r--servers/rendering_server.h13
-rw-r--r--servers/text/text_server_extension.cpp9
-rw-r--r--servers/text/text_server_extension.h2
-rw-r--r--servers/text_server.cpp28
-rw-r--r--servers/text_server.h1
-rw-r--r--servers/xr_server.cpp4
-rw-r--r--tests/core/io/test_image.h50
-rw-r--r--tests/core/templates/test_local_vector.h24
-rw-r--r--tests/core/templates/test_vector.h34
-rw-r--r--tests/core/variant/test_array.h10
-rw-r--r--thirdparty/README.md12
-rw-r--r--thirdparty/amd-fsr/ffx_a.h2656
-rw-r--r--thirdparty/amd-fsr/ffx_fsr1.h1199
-rw-r--r--thirdparty/amd-fsr/license.txt19
-rw-r--r--thirdparty/embree/common/sys/platform.h2
-rw-r--r--thirdparty/embree/kernels/common/rtcore.h2
-rw-r--r--thirdparty/embree/patches/godot-changes-noexcept.patch4
246 files changed, 6222 insertions, 841 deletions
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 7b212485ba..07b5d4042d 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -120,6 +120,11 @@ Copyright: 2007, Starbreeze Studios
2014-2021, Godot Engine contributors.
License: Expat and Zlib
+Files: ./thirdparty/amd-fsr/
+Comment: AMD FidelityFX Super Resolution
+Copyright: 2021, Advanced Micro Devices, Inc.
+License: Expat
+
Files: ./thirdparty/basis_universal/
Comment: Basis Universal
Copyright: 2019, Binomial LLC.
diff --git a/SConstruct b/SConstruct
index f7d589e799..83bd1560ff 100644
--- a/SConstruct
+++ b/SConstruct
@@ -300,6 +300,13 @@ opts.Update(env_base)
env_base["platform"] = selected_platform # Must always be re-set after calling opts.Update().
Help(opts.GenerateHelpText(env_base))
+# Detect and print a warning listing unknown SCons variables to ease troubleshooting.
+unknown = opts.UnknownVariables()
+if unknown:
+ print("WARNING: Unknown SCons variables were passed and will be ignored:")
+ for item in unknown.items():
+ print(" " + item[0] + "=" + item[1])
+
# add default include paths
env_base.Prepend(CPPPATH=["#"])
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index f37e7f5956..0e15edc29f 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -41,6 +41,9 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/variant/variant_parser.h"
+#include "core/version.h"
+
+#include "modules/modules_enabled.gen.h" // For mono.
const String ProjectSettings::PROJECT_DATA_DIR_NAME_SUFFIX = "godot";
@@ -62,10 +65,81 @@ String ProjectSettings::get_resource_path() const {
return resource_path;
}
+String ProjectSettings::get_safe_project_name() const {
+ String safe_name = OS::get_singleton()->get_safe_dir_name(get("application/config/name"));
+ if (safe_name.is_empty()) {
+ safe_name = "UnnamedProject";
+ }
+ return safe_name;
+}
+
String ProjectSettings::get_imported_files_path() const {
return get_project_data_path().plus_file("imported");
}
+// Returns the features that a project must have when opened with this build of Godot.
+// This is used by the project manager to provide the initial_settings for config/features.
+const PackedStringArray ProjectSettings::get_required_features() {
+ PackedStringArray features = PackedStringArray();
+ features.append(VERSION_BRANCH);
+#ifdef REAL_T_IS_DOUBLE
+ features.append("Double Precision");
+#endif
+ return features;
+}
+
+// Returns the features supported by this build of Godot. Includes all required features.
+const PackedStringArray ProjectSettings::_get_supported_features() {
+ PackedStringArray features = get_required_features();
+#ifdef MODULE_MONO_ENABLED
+ features.append("C#");
+#endif
+ // Allow pinning to a specific patch number or build type by marking
+ // them as supported. They're only used if the user adds them manually.
+ features.append(VERSION_BRANCH "." _MKSTR(VERSION_PATCH));
+ features.append(VERSION_FULL_CONFIG);
+ features.append(VERSION_FULL_BUILD);
+ // For now, assume Vulkan is always supported.
+ // This should be removed if it's possible to build the editor without Vulkan.
+ features.append("Vulkan Clustered");
+ features.append("Vulkan Mobile");
+ return features;
+}
+
+// Returns the features that this project needs but this build of Godot lacks.
+const PackedStringArray ProjectSettings::get_unsupported_features(const PackedStringArray &p_project_features) {
+ PackedStringArray unsupported_features = PackedStringArray();
+ PackedStringArray supported_features = singleton->_get_supported_features();
+ for (int i = 0; i < p_project_features.size(); i++) {
+ if (!supported_features.has(p_project_features[i])) {
+ unsupported_features.append(p_project_features[i]);
+ }
+ }
+ unsupported_features.sort();
+ return unsupported_features;
+}
+
+// Returns the features that both this project has and this build of Godot has, ensuring required features exist.
+const PackedStringArray ProjectSettings::_trim_to_supported_features(const PackedStringArray &p_project_features) {
+ // Remove unsupported features if present.
+ PackedStringArray features = PackedStringArray(p_project_features);
+ PackedStringArray supported_features = _get_supported_features();
+ for (int i = p_project_features.size() - 1; i > -1; i--) {
+ if (!supported_features.has(p_project_features[i])) {
+ features.remove_at(i);
+ }
+ }
+ // Add required features if not present.
+ PackedStringArray required_features = get_required_features();
+ for (int i = 0; i < required_features.size(); i++) {
+ if (!features.has(required_features[i])) {
+ features.append(required_features[i]);
+ }
+ }
+ features.sort();
+ return features;
+}
+
String ProjectSettings::localize_path(const String &p_path) const {
if (resource_path.is_empty() || p_path.begins_with("res://") || p_path.begins_with("user://") ||
(p_path.is_absolute_path() && !p_path.begins_with(resource_path))) {
@@ -368,12 +442,12 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) {
* If a project file is found, load it or fail.
* If nothing was found, error out.
*/
-Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, bool p_upwards) {
+Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, bool p_upwards, bool p_ignore_override) {
// If looking for files in a network client, use it directly
if (FileAccessNetworkClient::get_singleton()) {
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
- if (err == OK) {
+ if (err == OK && !p_ignore_override) {
// Optional, we don't mind if it fails
_load_settings_text("res://override.cfg");
}
@@ -387,7 +461,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
ERR_FAIL_COND_V_MSG(!ok, ERR_CANT_OPEN, "Cannot open resource pack '" + p_main_pack + "'.");
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
- if (err == OK) {
+ if (err == OK && !p_ignore_override) {
// Load override from location of the main pack
// Optional, we don't mind if it fails
_load_settings_text(p_main_pack.get_base_dir().plus_file("override.cfg"));
@@ -437,7 +511,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
// If we opened our package, try and load our project.
if (found) {
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
- if (err == OK) {
+ if (err == OK && !p_ignore_override) {
// Load override from location of the executable.
// Optional, we don't mind if it fails.
_load_settings_text(exec_path.get_base_dir().plus_file("override.cfg"));
@@ -458,7 +532,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
}
Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary");
- if (err == OK) {
+ if (err == OK && !p_ignore_override) {
// Optional, we don't mind if it fails.
_load_settings_text("res://override.cfg");
}
@@ -481,7 +555,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
resource_path = current_dir;
resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case.
err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary"));
- if (err == OK) {
+ if (err == OK && !p_ignore_override) {
// Optional, we don't mind if it fails.
_load_settings_text(current_dir.plus_file("override.cfg"));
found = true;
@@ -513,8 +587,8 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b
return OK;
}
-Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bool p_upwards) {
- Error err = _setup(p_path, p_main_pack, p_upwards);
+Error ProjectSettings::setup(const String &p_path, const String &p_main_pack, bool p_upwards, bool p_ignore_override) {
+ Error err = _setup(p_path, p_main_pack, p_upwards, p_ignore_override);
if (err == OK) {
String custom_settings = GLOBAL_DEF("application/config/project_settings_override", "");
if (custom_settings != "") {
@@ -666,6 +740,13 @@ Error ProjectSettings::_load_settings_text_or_binary(const String &p_text_path,
return err;
}
+Error ProjectSettings::load_custom(const String &p_path) {
+ if (p_path.ends_with(".binary")) {
+ return _load_settings_binary(p_path);
+ }
+ return _load_settings_text(p_path);
+}
+
int ProjectSettings::get_order(const String &p_name) const {
ERR_FAIL_COND_V_MSG(!props.has(p_name), -1, "Request for nonexistent project setting: " + p_name + ".");
return props[p_name].order;
@@ -845,6 +926,34 @@ Error ProjectSettings::_save_custom_bnd(const String &p_file) { // add other par
Error ProjectSettings::save_custom(const String &p_path, const CustomMap &p_custom, const Vector<String> &p_custom_features, bool p_merge_with_current) {
ERR_FAIL_COND_V_MSG(p_path == "", ERR_INVALID_PARAMETER, "Project settings save path cannot be empty.");
+ PackedStringArray project_features = has_setting("application/config/features") ? (PackedStringArray)get_setting("application/config/features") : PackedStringArray();
+ // If there is no feature list currently present, force one to generate.
+ if (project_features.is_empty()) {
+ project_features = ProjectSettings::get_required_features();
+ }
+ // Check the rendering API.
+ const String rendering_api = has_setting("rendering/quality/driver/driver_name") ? (String)get_setting("rendering/quality/driver/driver_name") : String();
+ if (rendering_api != "") {
+ // Add the rendering API as a project feature if it doesn't already exist.
+ if (!project_features.has(rendering_api)) {
+ project_features.append(rendering_api);
+ }
+ }
+ // Check for the existence of a csproj file.
+ if (FileAccess::exists(get_resource_path().plus_file(get_safe_project_name() + ".csproj"))) {
+ // If there is a csproj file, add the C# feature if it doesn't already exist.
+ if (!project_features.has("C#")) {
+ project_features.append("C#");
+ }
+ } else {
+ // If there isn't a csproj file, remove the C# feature if it exists.
+ if (project_features.has("C#")) {
+ project_features.remove_at(project_features.find("C#"));
+ }
+ }
+ project_features = _trim_to_supported_features(project_features);
+ set_setting("application/config/features", project_features);
+
Set<_VCSort> vclist;
if (p_merge_with_current) {
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index ca37401751..5b74356337 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -48,6 +48,8 @@ public:
//properties that are not for built in values begin from this value, so builtin ones are displayed first
NO_BUILTIN_ORDER_BASE = 1 << 16
};
+ const static PackedStringArray get_required_features();
+ const static PackedStringArray get_unsupported_features(const PackedStringArray &p_project_features);
struct AutoloadInfo {
StringName name;
@@ -111,13 +113,16 @@ protected:
Error _save_custom_bnd(const String &p_file);
+ const static PackedStringArray _get_supported_features();
+ const static PackedStringArray _trim_to_supported_features(const PackedStringArray &p_project_features);
+
void _convert_to_last_version(int p_from_version);
bool _load_resource_pack(const String &p_pack, bool p_replace_files = true, int p_offset = 0);
void _add_property_info_bind(const Dictionary &p_info);
- Error _setup(const String &p_path, const String &p_main_pack, bool p_upwards = false);
+ Error _setup(const String &p_path, const String &p_main_pack, bool p_upwards = false, bool p_ignore_override = false);
void _add_builtin_input_map();
@@ -125,7 +130,7 @@ protected:
static void _bind_methods();
public:
- static const int CONFIG_VERSION = 4;
+ static const int CONFIG_VERSION = 5;
void set_setting(const String &p_setting, const Variant &p_value);
Variant get_setting(const String &p_setting) const;
@@ -146,6 +151,7 @@ public:
String get_project_data_dir_name() const;
String get_project_data_path() const;
String get_resource_path() const;
+ String get_safe_project_name() const;
String get_imported_files_path() const;
static ProjectSettings *get_singleton();
@@ -156,8 +162,9 @@ public:
void set_builtin_order(const String &p_name);
bool is_builtin_setting(const String &p_name) const;
- Error setup(const String &p_path, const String &p_main_pack, bool p_upwards = false);
+ Error setup(const String &p_path, const String &p_main_pack, bool p_upwards = false, bool p_ignore_override = false);
+ Error load_custom(const String &p_path);
Error save_custom(const String &p_path = "", const CustomMap &p_custom = CustomMap(), const Vector<String> &p_custom_features = Vector<String>(), bool p_merge_with_current = true);
Error save();
void set_custom_property_info(const String &p_prop, const PropertyInfo &p_info);
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index a65408fdda..19988a26cb 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -783,6 +783,18 @@ static GDNativeVariantPtr gdnative_array_operator_index_const(const GDNativeType
return (GDNativeVariantPtr)&self->operator[](p_index);
}
+/* Dictionary functions */
+
+static GDNativeVariantPtr gdnative_dictionary_operator_index(GDNativeTypePtr p_self, const GDNativeVariantPtr p_key) {
+ Dictionary *self = (Dictionary *)p_self;
+ return (GDNativeVariantPtr)&self->operator[](*(const Variant *)p_key);
+}
+
+static GDNativeVariantPtr gdnative_dictionary_operator_index_const(const GDNativeTypePtr p_self, const GDNativeVariantPtr p_key) {
+ const Dictionary *self = (const Dictionary *)p_self;
+ return (GDNativeVariantPtr)&self->operator[](*(const Variant *)p_key);
+}
+
/* OBJECT API */
static void gdnative_object_method_bind_call(const GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeVariantPtr *p_args, GDNativeInt p_arg_count, GDNativeVariantPtr r_return, GDNativeCallError *r_error) {
@@ -1001,6 +1013,11 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.array_operator_index = gdnative_array_operator_index;
gdni.array_operator_index_const = gdnative_array_operator_index_const;
+ /* Dictionary functions */
+
+ gdni.dictionary_operator_index = gdnative_dictionary_operator_index;
+ gdni.dictionary_operator_index_const = gdnative_dictionary_operator_index_const;
+
/* OBJECT */
gdni.object_method_bind_call = gdnative_object_method_bind_call;
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index 8f8cb5a3e0..e411a9d85b 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -417,6 +417,11 @@ typedef struct {
GDNativeVariantPtr (*array_operator_index)(GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be an Array ptr
GDNativeVariantPtr (*array_operator_index_const)(const GDNativeTypePtr p_self, GDNativeInt p_index); // p_self should be an Array ptr
+ /* Dictionary functions */
+
+ GDNativeVariantPtr (*dictionary_operator_index)(GDNativeTypePtr p_self, const GDNativeVariantPtr p_key); // p_self should be an Dictionary ptr
+ GDNativeVariantPtr (*dictionary_operator_index_const)(const GDNativeTypePtr p_self, const GDNativeVariantPtr p_key); // p_self should be an Dictionary ptr
+
/* OBJECT */
void (*object_method_bind_call)(const GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeVariantPtr *p_args, GDNativeInt p_arg_count, GDNativeVariantPtr r_ret, GDNativeCallError *r_error);
diff --git a/core/input/input.cpp b/core/input/input.cpp
index 6fd8aca01b..342ab3b704 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -91,6 +91,7 @@ Input::MouseMode Input::get_mouse_mode() const {
void Input::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_key_pressed", "keycode"), &Input::is_key_pressed);
+ ClassDB::bind_method(D_METHOD("is_physical_key_pressed", "keycode"), &Input::is_physical_key_pressed);
ClassDB::bind_method(D_METHOD("is_mouse_button_pressed", "button"), &Input::is_mouse_button_pressed);
ClassDB::bind_method(D_METHOD("is_joy_button_pressed", "device", "button"), &Input::is_joy_button_pressed);
ClassDB::bind_method(D_METHOD("is_action_pressed", "action", "exact_match"), &Input::is_action_pressed, DEFVAL(false));
@@ -223,6 +224,11 @@ bool Input::is_key_pressed(Key p_keycode) const {
return keys_pressed.has(p_keycode);
}
+bool Input::is_physical_key_pressed(Key p_keycode) const {
+ _THREAD_SAFE_METHOD_
+ return physical_keys_pressed.has(p_keycode);
+}
+
bool Input::is_mouse_button_pressed(MouseButton p_button) const {
_THREAD_SAFE_METHOD_
return (mouse_button_mask & mouse_button_to_mask(p_button)) != MouseButton::NONE;
@@ -465,6 +471,13 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
keys_pressed.erase(k->get_keycode());
}
}
+ if (k.is_valid() && !k->is_echo() && k->get_physical_keycode() != Key::NONE) {
+ if (k->is_pressed()) {
+ physical_keys_pressed.insert(k->get_physical_keycode());
+ } else {
+ physical_keys_pressed.erase(k->get_physical_keycode());
+ }
+ }
Ref<InputEventMouseButton> mb = p_event;
@@ -862,6 +875,7 @@ void Input::release_pressed_events() {
flush_buffered_events(); // this is needed to release actions strengths
keys_pressed.clear();
+ physical_keys_pressed.clear();
joy_buttons_pressed.clear();
_joy_axis.clear();
@@ -1337,7 +1351,7 @@ void Input::add_joy_mapping(String p_mapping, bool p_update_existing) {
void Input::remove_joy_mapping(String p_guid) {
for (int i = map_db.size() - 1; i >= 0; i--) {
if (p_guid == map_db[i].uid) {
- map_db.remove(i);
+ map_db.remove_at(i);
}
}
for (KeyValue<int, Joypad> &E : joy_names) {
diff --git a/core/input/input.h b/core/input/input.h
index dd57ebb563..faec654a3c 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -87,6 +87,7 @@ public:
private:
MouseButton mouse_button_mask = MouseButton::NONE;
+ Set<Key> physical_keys_pressed;
Set<Key> keys_pressed;
Set<JoyButton> joy_buttons_pressed;
Map<JoyAxis, float> _joy_axis;
@@ -247,6 +248,7 @@ public:
static Input *get_singleton();
bool is_key_pressed(Key p_keycode) const;
+ bool is_physical_key_pressed(Key p_keycode) const;
bool is_mouse_button_pressed(MouseButton p_button) const;
bool is_joy_button_pressed(int p_device, JoyButton p_button) const;
bool is_action_pressed(const StringName &p_action, bool p_exact = false) const;
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
index 49fa73dab2..33f992e153 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -183,7 +183,9 @@ Error ConfigFile::_internal_save(FileAccess *file) {
if (E != values.front()) {
file->store_string("\n");
}
- file->store_string("[" + E.key() + "]\n\n");
+ if (E.key() != "") {
+ file->store_string("[" + E.key() + "]\n\n");
+ }
for (OrderedHashMap<String, Variant>::Element F = E.get().front(); F; F = F.next()) {
String vstr;
diff --git a/core/io/image.cpp b/core/io/image.cpp
index b82e6637b4..3f34de132f 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -86,20 +86,14 @@ SaveEXRFunc Image::save_exr_func = nullptr;
SavePNGBufferFunc Image::save_png_buffer_func = nullptr;
-void Image::_put_pixelb(int p_x, int p_y, uint32_t p_pixelsize, uint8_t *p_data, const uint8_t *p_pixel) {
- uint32_t ofs = (p_y * width + p_x) * p_pixelsize;
-
- for (uint32_t i = 0; i < p_pixelsize; i++) {
- p_data[ofs + i] = p_pixel[i];
- }
+void Image::_put_pixelb(int p_x, int p_y, uint32_t p_pixel_size, uint8_t *p_data, const uint8_t *p_pixel) {
+ uint32_t ofs = (p_y * width + p_x) * p_pixel_size;
+ memcpy(p_data + ofs, p_pixel, p_pixel_size);
}
-void Image::_get_pixelb(int p_x, int p_y, uint32_t p_pixelsize, const uint8_t *p_data, uint8_t *p_pixel) {
- uint32_t ofs = (p_y * width + p_x) * p_pixelsize;
-
- for (uint32_t i = 0; i < p_pixelsize; i++) {
- p_pixel[i] = p_data[ofs + i];
- }
+void Image::_get_pixelb(int p_x, int p_y, uint32_t p_pixel_size, const uint8_t *p_data, uint8_t *p_pixel) {
+ uint32_t ofs = (p_y * width + p_x) * p_pixel_size;
+ memcpy(p_pixel, p_data + ofs, p_pixel_size);
}
int Image::get_format_pixel_size(Format p_format) {
@@ -2697,24 +2691,55 @@ void Image::blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, c
}
}
-void Image::fill(const Color &c) {
+// Repeats `p_pixel` `p_count` times in consecutive memory.
+// Results in the original pixel and `p_count - 1` subsequent copies of it.
+void Image::_repeat_pixel_over_subsequent_memory(uint8_t *p_pixel, int p_pixel_size, int p_count) {
+ int offset = 1;
+ for (int stride = 1; offset + stride <= p_count; stride *= 2) {
+ memcpy(p_pixel + offset * p_pixel_size, p_pixel, stride * p_pixel_size);
+ offset += stride;
+ }
+ if (offset < p_count) {
+ memcpy(p_pixel + offset * p_pixel_size, p_pixel, (p_count - offset) * p_pixel_size);
+ }
+}
+
+void Image::fill(const Color &p_color) {
ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill in compressed or custom image formats.");
- uint8_t *wp = data.ptrw();
- uint8_t *dst_data_ptr = wp;
+ uint8_t *dst_data_ptr = data.ptrw();
int pixel_size = get_format_pixel_size(format);
- // put first pixel with the format-aware API
- set_pixel(0, 0, c);
+ // Put first pixel with the format-aware API.
+ _set_color_at_ofs(dst_data_ptr, 0, p_color);
- for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- uint8_t *dst = &dst_data_ptr[(y * width + x) * pixel_size];
+ _repeat_pixel_over_subsequent_memory(dst_data_ptr, pixel_size, width * height);
+}
- for (int k = 0; k < pixel_size; k++) {
- dst[k] = dst_data_ptr[k];
- }
+void Image::fill_rect(const Rect2 &p_rect, const Color &p_color) {
+ ERR_FAIL_COND_MSG(!_can_modify(format), "Cannot fill rect in compressed or custom image formats.");
+
+ Rect2i r = Rect2i(0, 0, width, height).intersection(p_rect.abs());
+ if (r.has_no_area()) {
+ return;
+ }
+
+ uint8_t *dst_data_ptr = data.ptrw();
+
+ int pixel_size = get_format_pixel_size(format);
+
+ // Put first pixel with the format-aware API.
+ uint8_t *rect_first_pixel_ptr = &dst_data_ptr[(r.position.y * width + r.position.x) * pixel_size];
+ _set_color_at_ofs(rect_first_pixel_ptr, 0, p_color);
+
+ if (r.size.x == width) {
+ // No need to fill rows separately.
+ _repeat_pixel_over_subsequent_memory(rect_first_pixel_ptr, pixel_size, width * r.size.y);
+ } else {
+ _repeat_pixel_over_subsequent_memory(rect_first_pixel_ptr, pixel_size, r.size.x);
+ for (int y = 1; y < r.size.y; y++) {
+ memcpy(rect_first_pixel_ptr + y * width * pixel_size, rect_first_pixel_ptr, r.size.x * pixel_size);
}
}
}
@@ -3160,6 +3185,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("blend_rect", "src", "src_rect", "dst"), &Image::blend_rect);
ClassDB::bind_method(D_METHOD("blend_rect_mask", "src", "mask", "src_rect", "dst"), &Image::blend_rect_mask);
ClassDB::bind_method(D_METHOD("fill", "color"), &Image::fill);
+ ClassDB::bind_method(D_METHOD("fill_rect", "rect", "color"), &Image::fill_rect);
ClassDB::bind_method(D_METHOD("get_used_rect"), &Image::get_used_rect);
ClassDB::bind_method(D_METHOD("get_rect", "rect"), &Image::get_rect);
diff --git a/core/io/image.h b/core/io/image.h
index d31a065aa7..9023463b08 100644
--- a/core/io/image.h
+++ b/core/io/image.h
@@ -190,8 +190,10 @@ private:
static int _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1, int *r_mm_width = nullptr, int *r_mm_height = nullptr);
bool _can_modify(Format p_format) const;
- _FORCE_INLINE_ void _put_pixelb(int p_x, int p_y, uint32_t p_pixelsize, uint8_t *p_data, const uint8_t *p_pixel);
- _FORCE_INLINE_ void _get_pixelb(int p_x, int p_y, uint32_t p_pixelsize, const uint8_t *p_data, uint8_t *p_pixel);
+ _FORCE_INLINE_ void _put_pixelb(int p_x, int p_y, uint32_t p_pixel_size, uint8_t *p_data, const uint8_t *p_pixel);
+ _FORCE_INLINE_ void _get_pixelb(int p_x, int p_y, uint32_t p_pixel_size, const uint8_t *p_data, uint8_t *p_pixel);
+
+ _FORCE_INLINE_ void _repeat_pixel_over_subsequent_memory(uint8_t *p_pixel, int p_pixel_size, int p_count);
void _set_data(const Dictionary &p_data);
Dictionary _get_data() const;
@@ -362,7 +364,8 @@ public:
void blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest);
void blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Point2 &p_dest);
void blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Point2 &p_dest);
- void fill(const Color &c);
+ void fill(const Color &p_color);
+ void fill_rect(const Rect2 &p_rect, const Color &p_color);
Rect2 get_used_rect() const;
Ref<Image> get_rect(const Rect2 &p_area) const;
diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp
index 4a76f0191d..d34b5b6fe3 100644
--- a/core/io/packed_data_container.cpp
+++ b/core/io/packed_data_container.cpp
@@ -100,6 +100,7 @@ Variant PackedDataContainer::_iter_get_ofs(const Variant &p_iter, uint32_t p_off
}
Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, bool &err) const {
+ ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), Variant());
uint32_t type = decode_uint32(p_buf + p_ofs);
if (type == TYPE_ARRAY || type == TYPE_DICT) {
@@ -122,6 +123,7 @@ Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, b
}
uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const {
+ ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), 0);
const uint8_t *rd = data.ptr();
ERR_FAIL_COND_V(!rd, 0);
const uint8_t *r = &rd[p_ofs];
@@ -131,6 +133,7 @@ uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const {
}
int PackedDataContainer::_size(uint32_t p_ofs) const {
+ ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), 0);
const uint8_t *rd = data.ptr();
ERR_FAIL_COND_V(!rd, 0);
const uint8_t *r = &rd[p_ofs];
@@ -149,6 +152,7 @@ int PackedDataContainer::_size(uint32_t p_ofs) const {
}
Variant PackedDataContainer::_key_at_ofs(uint32_t p_ofs, const Variant &p_key, bool &err) const {
+ ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), Variant());
const uint8_t *rd = data.ptr();
if (!rd) {
err = true;
diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp
index 1079da75ef..8a44646ef9 100644
--- a/core/math/a_star.cpp
+++ b/core/math/a_star.cpp
@@ -344,7 +344,7 @@ bool AStar::_solve(Point *begin_point, Point *end_point) {
}
sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list
- open_list.remove(open_list.size() - 1);
+ open_list.remove_at(open_list.size() - 1);
p->closed_pass = pass; // Mark the point as closed
for (OAHashMap<int, Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
@@ -812,7 +812,7 @@ bool AStar2D::_solve(AStar::Point *begin_point, AStar::Point *end_point) {
}
sorter.pop_heap(0, open_list.size(), open_list.ptrw()); // Remove the current point from the open list
- open_list.remove(open_list.size() - 1);
+ open_list.remove_at(open_list.size() - 1);
p->closed_pass = astar.pass; // Mark the point as closed
for (OAHashMap<int, AStar::Point *>::Iterator it = p->neighbours.iter(); it.valid; it = p->neighbours.next_iter(it)) {
diff --git a/core/math/bvh.h b/core/math/bvh.h
index 65b8b102a3..c1eff02178 100644
--- a/core/math/bvh.h
+++ b/core/math/bvh.h
@@ -654,7 +654,7 @@ private:
// remove from changed items (not very efficient yet)
for (int n = 0; n < (int)changed_items.size(); n++) {
if (changed_items[n] == p_handle) {
- changed_items.remove_unordered(n);
+ changed_items.remove_at_unordered(n);
// because we are using an unordered remove,
// the last changed item will now be at spot 'n',
diff --git a/core/math/bvh_pair.inc b/core/math/bvh_pair.inc
index 839db59a3a..a12acec2b6 100644
--- a/core/math/bvh_pair.inc
+++ b/core/math/bvh_pair.inc
@@ -51,7 +51,7 @@ struct ItemPairs {
for (int n = 0; n < num_pairs; n++) {
if (extended_pairs[n].handle == h) {
userdata = extended_pairs[n].userdata;
- extended_pairs.remove_unordered(n);
+ extended_pairs.remove_at_unordered(n);
num_pairs--;
break;
}
diff --git a/core/math/convex_hull.cpp b/core/math/convex_hull.cpp
index f6560f1bea..2956e0cf09 100644
--- a/core/math/convex_hull.cpp
+++ b/core/math/convex_hull.cpp
@@ -1688,7 +1688,7 @@ real_t ConvexHullInternal::shrink(real_t p_amount, real_t p_clamp_amount) {
while (stack.size() > 0) {
Vertex *v = stack[stack.size() - 1];
- stack.remove(stack.size() - 1);
+ stack.remove_at(stack.size() - 1);
Edge *e = v->edges;
if (e) {
do {
diff --git a/core/math/delaunay_2d.h b/core/math/delaunay_2d.h
index 2f80cb5634..779ac96b79 100644
--- a/core/math/delaunay_2d.h
+++ b/core/math/delaunay_2d.h
@@ -123,7 +123,7 @@ public:
for (int j = 0; j < triangles.size(); j++) {
if (triangles[j].bad) {
- triangles.remove(j);
+ triangles.remove_at(j);
j--;
}
}
@@ -154,7 +154,7 @@ public:
}
}
if (invalid) {
- triangles.remove(i);
+ triangles.remove_at(i);
i--;
}
}
diff --git a/core/math/expression.cpp b/core/math/expression.cpp
index 05f2c8dac9..f366fd0499 100644
--- a/core/math/expression.cpp
+++ b/core/math/expression.cpp
@@ -1087,7 +1087,7 @@ Expression::ENode *Expression::_parse_expression() {
op->nodes[1] = nullptr;
expression.write[i].is_op = false;
expression.write[i].node = op;
- expression.remove(i + 1);
+ expression.remove_at(i + 1);
}
} else {
@@ -1119,8 +1119,8 @@ Expression::ENode *Expression::_parse_expression() {
//replace all 3 nodes by this operator and make it an expression
expression.write[next_op - 1].node = op;
- expression.remove(next_op);
- expression.remove(next_op);
+ expression.remove_at(next_op);
+ expression.remove_at(next_op);
}
}
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index 07006e7968..3459506860 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -282,7 +282,7 @@ void UndoRedo::_pop_history_tail() {
}
}
- actions.remove(0);
+ actions.remove_at(0);
if (current_action >= 0) {
current_action--;
}
diff --git a/core/string/node_path.cpp b/core/string/node_path.cpp
index 5fae13779e..7ab85ac9d0 100644
--- a/core/string/node_path.cpp
+++ b/core/string/node_path.cpp
@@ -293,12 +293,12 @@ void NodePath::simplify() {
break;
}
if (data->path[i].operator String() == ".") {
- data->path.remove(i);
+ data->path.remove_at(i);
i--;
} else if (i > 0 && data->path[i].operator String() == ".." && data->path[i - 1].operator String() != "." && data->path[i - 1].operator String() != "..") {
//remove both
- data->path.remove(i - 1);
- data->path.remove(i - 1);
+ data->path.remove_at(i - 1);
+ data->path.remove_at(i - 1);
i -= 2;
if (data->path.size() == 0) {
data->path.push_back(".");
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 70236231a2..320aae2ba4 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -3670,15 +3670,15 @@ String String::simplify_path() const {
for (int i = 0; i < dirs.size(); i++) {
String d = dirs[i];
if (d == ".") {
- dirs.remove(i);
+ dirs.remove_at(i);
i--;
} else if (d == "..") {
if (i == 0) {
- dirs.remove(i);
+ dirs.remove_at(i);
i--;
} else {
- dirs.remove(i);
- dirs.remove(i - 1);
+ dirs.remove_at(i);
+ dirs.remove_at(i - 1);
i -= 2;
}
}
diff --git a/core/string/ustring.h b/core/string/ustring.h
index 1d80ccf58d..f25c36f66c 100644
--- a/core/string/ustring.h
+++ b/core/string/ustring.h
@@ -209,7 +209,7 @@ public:
_FORCE_INLINE_ char32_t *ptrw() { return _cowdata.ptrw(); }
_FORCE_INLINE_ const char32_t *ptr() const { return _cowdata.ptr(); }
- void remove(int p_index) { _cowdata.remove(p_index); }
+ void remove_at(int p_index) { _cowdata.remove_at(p_index); }
_FORCE_INLINE_ void clear() { resize(0); }
diff --git a/core/templates/bin_sorted_array.h b/core/templates/bin_sorted_array.h
index be9d0b5475..8db3e7aeb8 100644
--- a/core/templates/bin_sorted_array.h
+++ b/core/templates/bin_sorted_array.h
@@ -112,7 +112,7 @@ public:
return current_idx;
}
- void remove(uint64_t p_idx) {
+ void remove_at(uint64_t p_idx) {
ERR_FAIL_COND(p_idx >= array.size());
uint64_t new_idx = move(p_idx, 0);
uint64_t swap_idx = array.size() - 1;
diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h
index 9b8c0eb528..e79ca037db 100644
--- a/core/templates/cowdata.h
+++ b/core/templates/cowdata.h
@@ -167,7 +167,7 @@ public:
Error resize(int p_size);
- _FORCE_INLINE_ void remove(int p_index) {
+ _FORCE_INLINE_ void remove_at(int p_index) {
ERR_FAIL_INDEX(p_index, size());
T *p = ptrw();
int len = size();
diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h
index 5704b8f230..3854e1e94c 100644
--- a/core/templates/local_vector.h
+++ b/core/templates/local_vector.h
@@ -70,7 +70,7 @@ public:
}
}
- void remove(U p_index) {
+ void remove_at(U p_index) {
ERR_FAIL_UNSIGNED_INDEX(p_index, count);
count--;
for (U i = p_index; i < count; i++) {
@@ -83,7 +83,7 @@ public:
/// Removes the item copying the last value into the position of the one to
/// remove. It's generally faster than `remove`.
- void remove_unordered(U p_index) {
+ void remove_at_unordered(U p_index) {
ERR_FAIL_INDEX(p_index, count);
count--;
if (count > p_index) {
@@ -97,7 +97,7 @@ public:
void erase(const T &p_val) {
int64_t idx = find(p_val);
if (idx >= 0) {
- remove(idx);
+ remove_at(idx);
}
}
diff --git a/core/templates/vector.h b/core/templates/vector.h
index 98982c80d3..a955d49101 100644
--- a/core/templates/vector.h
+++ b/core/templates/vector.h
@@ -68,11 +68,11 @@ public:
_FORCE_INLINE_ bool append(const T &p_elem) { return push_back(p_elem); } //alias
void fill(T p_elem);
- void remove(int p_index) { _cowdata.remove(p_index); }
+ void remove_at(int p_index) { _cowdata.remove_at(p_index); }
void erase(const T &p_val) {
int idx = find(p_val);
if (idx >= 0) {
- remove(idx);
+ remove_at(idx);
}
}
void reverse();
diff --git a/core/templates/vmap.h b/core/templates/vmap.h
index 520e0b3720..2aa22f97cf 100644
--- a/core/templates/vmap.h
+++ b/core/templates/vmap.h
@@ -134,7 +134,7 @@ public:
if (pos < 0) {
return;
}
- _cowdata.remove(pos);
+ _cowdata.remove_at(pos);
}
int find(const T &p_val) const {
diff --git a/core/templates/vset.h b/core/templates/vset.h
index 6665651d42..94e7a17061 100644
--- a/core/templates/vset.h
+++ b/core/templates/vset.h
@@ -119,7 +119,7 @@ public:
if (pos < 0) {
return;
}
- _data.remove(pos);
+ _data.remove_at(pos);
}
int find(const T &p_val) const {
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 69a0fff1a1..b049c29688 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -322,8 +322,8 @@ bool Array::has(const Variant &p_value) const {
return _p->array.find(p_value, 0) != -1;
}
-void Array::remove(int p_pos) {
- _p->array.remove(p_pos);
+void Array::remove_at(int p_pos) {
+ _p->array.remove_at(p_pos);
}
void Array::set(int p_idx, const Variant &p_value) {
@@ -576,7 +576,7 @@ Variant Array::pop_back() {
Variant Array::pop_front() {
if (!_p->array.is_empty()) {
const Variant ret = _p->array.get(0);
- _p->array.remove(0);
+ _p->array.remove_at(0);
return ret;
}
return Variant();
@@ -603,7 +603,7 @@ Variant Array::pop_at(int p_pos) {
_p->array.size()));
const Variant ret = _p->array.get(p_pos);
- _p->array.remove(p_pos);
+ _p->array.remove_at(p_pos);
return ret;
}
diff --git a/core/variant/array.h b/core/variant/array.h
index bd39b8e0b1..5d2839dda7 100644
--- a/core/variant/array.h
+++ b/core/variant/array.h
@@ -75,7 +75,7 @@ public:
Error resize(int p_new_size);
Error insert(int p_pos, const Variant &p_value);
- void remove(int p_pos);
+ void remove_at(int p_pos);
void fill(const Variant &p_value);
Variant front() const;
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 65ea969146..34b8b782d2 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1808,7 +1808,7 @@ static void _register_variant_builtin_methods() {
bind_method(Array, append_array, sarray("array"), varray());
bind_method(Array, resize, sarray("size"), varray());
bind_method(Array, insert, sarray("position", "value"), varray());
- bind_method(Array, remove, sarray("position"), varray());
+ bind_method(Array, remove_at, sarray("position"), varray());
bind_method(Array, fill, sarray("value"), varray());
bind_method(Array, erase, sarray("value"), varray());
bind_method(Array, front, sarray(), varray());
@@ -1842,7 +1842,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedByteArray, push_back, sarray("value"), varray());
bind_method(PackedByteArray, append, sarray("value"), varray());
bind_method(PackedByteArray, append_array, sarray("array"), varray());
- bind_method(PackedByteArray, remove, sarray("index"), varray());
+ bind_method(PackedByteArray, remove_at, sarray("index"), varray());
bind_method(PackedByteArray, insert, sarray("at_index", "value"), varray());
bind_method(PackedByteArray, fill, sarray("value"), varray());
bind_method(PackedByteArray, resize, sarray("new_size"), varray());
@@ -1903,7 +1903,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt32Array, push_back, sarray("value"), varray());
bind_method(PackedInt32Array, append, sarray("value"), varray());
bind_method(PackedInt32Array, append_array, sarray("array"), varray());
- bind_method(PackedInt32Array, remove, sarray("index"), varray());
+ bind_method(PackedInt32Array, remove_at, sarray("index"), varray());
bind_method(PackedInt32Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedInt32Array, fill, sarray("value"), varray());
bind_method(PackedInt32Array, resize, sarray("new_size"), varray());
@@ -1923,7 +1923,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedInt64Array, push_back, sarray("value"), varray());
bind_method(PackedInt64Array, append, sarray("value"), varray());
bind_method(PackedInt64Array, append_array, sarray("array"), varray());
- bind_method(PackedInt64Array, remove, sarray("index"), varray());
+ bind_method(PackedInt64Array, remove_at, sarray("index"), varray());
bind_method(PackedInt64Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedInt64Array, fill, sarray("value"), varray());
bind_method(PackedInt64Array, resize, sarray("new_size"), varray());
@@ -1943,7 +1943,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat32Array, push_back, sarray("value"), varray());
bind_method(PackedFloat32Array, append, sarray("value"), varray());
bind_method(PackedFloat32Array, append_array, sarray("array"), varray());
- bind_method(PackedFloat32Array, remove, sarray("index"), varray());
+ bind_method(PackedFloat32Array, remove_at, sarray("index"), varray());
bind_method(PackedFloat32Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedFloat32Array, fill, sarray("value"), varray());
bind_method(PackedFloat32Array, resize, sarray("new_size"), varray());
@@ -1963,7 +1963,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedFloat64Array, push_back, sarray("value"), varray());
bind_method(PackedFloat64Array, append, sarray("value"), varray());
bind_method(PackedFloat64Array, append_array, sarray("array"), varray());
- bind_method(PackedFloat64Array, remove, sarray("index"), varray());
+ bind_method(PackedFloat64Array, remove_at, sarray("index"), varray());
bind_method(PackedFloat64Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedFloat64Array, fill, sarray("value"), varray());
bind_method(PackedFloat64Array, resize, sarray("new_size"), varray());
@@ -1983,7 +1983,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedStringArray, push_back, sarray("value"), varray());
bind_method(PackedStringArray, append, sarray("value"), varray());
bind_method(PackedStringArray, append_array, sarray("array"), varray());
- bind_method(PackedStringArray, remove, sarray("index"), varray());
+ bind_method(PackedStringArray, remove_at, sarray("index"), varray());
bind_method(PackedStringArray, insert, sarray("at_index", "value"), varray());
bind_method(PackedStringArray, fill, sarray("value"), varray());
bind_method(PackedStringArray, resize, sarray("new_size"), varray());
@@ -2003,7 +2003,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector2Array, push_back, sarray("value"), varray());
bind_method(PackedVector2Array, append, sarray("value"), varray());
bind_method(PackedVector2Array, append_array, sarray("array"), varray());
- bind_method(PackedVector2Array, remove, sarray("index"), varray());
+ bind_method(PackedVector2Array, remove_at, sarray("index"), varray());
bind_method(PackedVector2Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedVector2Array, fill, sarray("value"), varray());
bind_method(PackedVector2Array, resize, sarray("new_size"), varray());
@@ -2023,7 +2023,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedVector3Array, push_back, sarray("value"), varray());
bind_method(PackedVector3Array, append, sarray("value"), varray());
bind_method(PackedVector3Array, append_array, sarray("array"), varray());
- bind_method(PackedVector3Array, remove, sarray("index"), varray());
+ bind_method(PackedVector3Array, remove_at, sarray("index"), varray());
bind_method(PackedVector3Array, insert, sarray("at_index", "value"), varray());
bind_method(PackedVector3Array, fill, sarray("value"), varray());
bind_method(PackedVector3Array, resize, sarray("new_size"), varray());
@@ -2043,7 +2043,7 @@ static void _register_variant_builtin_methods() {
bind_method(PackedColorArray, push_back, sarray("value"), varray());
bind_method(PackedColorArray, append, sarray("value"), varray());
bind_method(PackedColorArray, append_array, sarray("array"), varray());
- bind_method(PackedColorArray, remove, sarray("index"), varray());
+ bind_method(PackedColorArray, remove_at, sarray("index"), varray());
bind_method(PackedColorArray, insert, sarray("at_index", "value"), varray());
bind_method(PackedColorArray, fill, sarray("value"), varray());
bind_method(PackedColorArray, resize, sarray("new_size"), varray());
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index 2530d77c62..b6ad2d870e 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -704,7 +704,7 @@ struct VariantIndexedSetGet_String {
String *b = VariantGetInternalPtr<String>::get_ptr(base);
const String *v = VariantInternal::get_string(value);
if (v->length() == 0) {
- b->remove(index);
+ b->remove_at(index);
} else {
b->set(index, v->get(0));
}
@@ -723,7 +723,7 @@ struct VariantIndexedSetGet_String {
String *b = VariantGetInternalPtr<String>::get_ptr(base);
const String *v = VariantInternal::get_string(value);
if (v->length() == 0) {
- b->remove(index);
+ b->remove_at(index);
} else {
b->set(index, v->get(0));
}
@@ -738,7 +738,7 @@ struct VariantIndexedSetGet_String {
OOB_TEST(index, v.length());
const String &m = *reinterpret_cast<const String *>(member);
if (unlikely(m.length() == 0)) {
- v.remove(index);
+ v.remove_at(index);
} else {
v.set(index, m.unicode_at(0));
}
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 9cfe494b7f..41cc043a74 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1,13 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="@GlobalScope" version="4.0">
<brief_description>
- Global scope constants and variables.
+ Global scope constants and functions.
</brief_description>
<description>
- Global scope constants and variables. This is all that resides in the globals, constants regarding error codes, keycodes, property hints, etc.
+ A list of global scope enumerated constants and built-in functions. This is all that resides in the globals, constants regarding error codes, keycodes, property hints, etc.
Singletons are also documented here, since they can be accessed from anywhere.
+ For the entries related to GDScript which can be accessed in any script see [@GDScript].
</description>
<tutorials>
+ <link title="Random number generation">$DOCS_URL/tutorials/math/random_number_generation.html</link>
</tutorials>
<methods>
<method name="abs">
@@ -248,9 +250,9 @@
- 1.0: Linear
- Between -1.0 and 0.0 (exclusive): Ease out-in
- 0.0: Constant
- - Between 0.0 to 1.0 (exclusive): Ease in
+ - Between 0.0 to 1.0 (exclusive): Ease out
- 1.0: Linear
- - Greater than 1.0 (exclusive): Ease out
+ - Greater than 1.0 (exclusive): Ease in
[/codeblock]
[url=https://raw.githubusercontent.com/godotengine/godot-docs/master/img/ease_cheatsheet.png]ease() curve values cheatsheet[/url]
See also [method smoothstep]. If you need to perform more advanced transitions, use [Tween] or [AnimationPlayer].
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index b74d4c1d3d..d505ee98cc 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -194,7 +194,7 @@
<return type="void" />
<argument index="0" name="value" type="Variant" />
<description>
- Removes the first occurrence of a value from the array. To remove an element by index, use [method remove] instead.
+ Removes the first occurrence of a value from the array. To remove an element by index, use [method remove_at] instead.
[b]Note:[/b] This method acts in-place and doesn't return a value.
[b]Note:[/b] On large arrays, this method will be slower if the removed element is close to the beginning of the array (index 0). This is because all elements placed after the removed element have to be reindexed.
</description>
@@ -400,7 +400,7 @@
[/codeblock]
</description>
</method>
- <method name="remove">
+ <method name="remove_at">
<return type="void" />
<argument index="0" name="position" type="int" />
<description>
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 668912b6bd..8739e0157d 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -720,6 +720,12 @@
Removes a local override for a theme [StyleBox] with the specified [code]name[/code] previously added by [method add_theme_stylebox_override] or via the Inspector dock.
</description>
</method>
+ <method name="reset_size">
+ <return type="void" />
+ <description>
+ Resets the size to [method get_combined_minimum_size]. This is equivalent to calling [code]set_size(Vector2())[/code] (or any size below the minimum).
+ </description>
+ </method>
<method name="set_anchor">
<return type="void" />
<argument index="0" name="side" type="int" enum="Side" />
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index d2b1b5c004..8a4bbee0fa 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -154,7 +154,15 @@
<return type="void" />
<argument index="0" name="color" type="Color" />
<description>
- Fills the image with a given [Color].
+ Fills the image with [code]color[/code].
+ </description>
+ </method>
+ <method name="fill_rect">
+ <return type="void" />
+ <argument index="0" name="rect" type="Rect2" />
+ <argument index="1" name="color" type="Color" />
+ <description>
+ Fills [code]rect[/code] with [code]color[/code].
</description>
</method>
<method name="fix_alpha_edges">
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index 4ee319f554..cd5ba2e17f 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -236,6 +236,13 @@
Returns [code]true[/code] if you are pressing the mouse button specified with [enum MouseButton].
</description>
</method>
+ <method name="is_physical_key_pressed" qualifiers="const">
+ <return type="bool" />
+ <argument index="0" name="keycode" type="int" enum="Key" />
+ <description>
+ Returns [code]true[/code] if you are pressing the key in the physical location on the 101/102-key US QWERTY keyboard. You can pass a [enum Key] constant.
+ </description>
+ </method>
<method name="joy_connection_changed">
<return type="void" />
<argument index="0" name="device" type="int" />
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 423002d058..c75b2e305e 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -233,6 +233,14 @@
<description>
Returns an array listing the groups that the node is a member of.
[b]Note:[/b] For performance reasons, the order of node groups is [i]not[/i] guaranteed. The order of node groups should not be relied upon as it can vary across project runs.
+ [b]Note:[/b] The engine uses some group names internally (all starting with an underscore). To avoid conflicts with internal groups, do not add custom groups whose name starts with an underscore. To exclude internal groups while looping over [method get_groups], use the following snippet:
+ [codeblock]
+ # Stores the node's non-internal groups only (as an array of Strings).
+ var non_internal_groups = []
+ for group in get_groups():
+ if not group.begins_with("_"):
+ non_internal_groups.push_back(group)
+ [/codeblock]
</description>
</method>
<method name="get_index" qualifiers="const">
@@ -563,6 +571,7 @@
<description>
Replaces a node in a scene by the given one. Subscriptions that pass through this node will be lost.
If [code]keep_groups[/code] is [code]true[/code], the [code]node[/code] is added to the same groups that the replaced node is in.
+ Note that the replaced node is not automatically freed, so you either need to keep it in a variable for later use or free it using [method Object.free].
</description>
</method>
<method name="request_ready">
@@ -782,8 +791,8 @@
<constant name="NOTIFICATION_DRAG_END" value="22">
Notification received when a drag ends.
</constant>
- <constant name="NOTIFICATION_PATH_CHANGED" value="23">
- Notification received when the node's [NodePath] changed.
+ <constant name="NOTIFICATION_PATH_RENAMED" value="23">
+ Notification received when the node's name or one of its parents' name is changed. This notification is [i]not[/i] received when the node is removed from the scene tree to be added to another parent later on.
</constant>
<constant name="NOTIFICATION_INTERNAL_PROCESS" value="25">
Notification received every frame when the internal process flag is set (see [method set_process_internal]).
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index df9da7561e..860e252805 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -350,6 +350,7 @@
<argument index="0" name="property" type="NodePath" />
<description>
Gets the object's property indexed by the given [NodePath]. The node path should be relative to the current object and can use the colon character ([code]:[/code]) to access nested properties. Examples: [code]"position:x"[/code] or [code]"material:next_pass:blend_mode"[/code].
+ [b]Note:[/b] Even though the method takes [NodePath] argument, it doesn't support actual paths to [Node]s in the scene tree, only colon-separated sub-property paths. For the purpose of nodes, use [method Node.get_node_and_resource] instead.
</description>
</method>
<method name="get_instance_id" qualifiers="const">
diff --git a/doc/classes/PackedByteArray.xml b/doc/classes/PackedByteArray.xml
index f951df1eb7..fd098481e4 100644
--- a/doc/classes/PackedByteArray.xml
+++ b/doc/classes/PackedByteArray.xml
@@ -332,7 +332,7 @@
Appends an element at the end of the array.
</description>
</method>
- <method name="remove">
+ <method name="remove_at">
<return type="void" />
<argument index="0" name="index" type="int" />
<description>
diff --git a/doc/classes/PackedColorArray.xml b/doc/classes/PackedColorArray.xml
index 4aa8a19630..f69c5504da 100644
--- a/doc/classes/PackedColorArray.xml
+++ b/doc/classes/PackedColorArray.xml
@@ -95,7 +95,7 @@
Appends a value to the array.
</description>
</method>
- <method name="remove">
+ <method name="remove_at">
<return type="void" />
<argument index="0" name="index" type="int" />
<description>
diff --git a/doc/classes/PackedFloat32Array.xml b/doc/classes/PackedFloat32Array.xml
index 68fb45a62a..ccac607386 100644
--- a/doc/classes/PackedFloat32Array.xml
+++ b/doc/classes/PackedFloat32Array.xml
@@ -96,7 +96,7 @@
Appends an element at the end of the array.
</description>
</method>
- <method name="remove">
+ <method name="remove_at">
<return type="void" />
<argument index="0" name="index" type="int" />
<description>
diff --git a/doc/classes/PackedFloat64Array.xml b/doc/classes/PackedFloat64Array.xml
index 740591a0c0..b164283b3e 100644
--- a/doc/classes/PackedFloat64Array.xml
+++ b/doc/classes/PackedFloat64Array.xml
@@ -96,7 +96,7 @@
Appends an element at the end of the array.
</description>
</method>
- <method name="remove">
+ <method name="remove_at">
<return type="void" />
<argument index="0" name="index" type="int" />
<description>
diff --git a/doc/classes/PackedInt32Array.xml b/doc/classes/PackedInt32Array.xml
index 7a01bb6c7c..c6ff31ebdd 100644
--- a/doc/classes/PackedInt32Array.xml
+++ b/doc/classes/PackedInt32Array.xml
@@ -96,7 +96,7 @@
Appends a value to the array.
</description>
</method>
- <method name="remove">
+ <method name="remove_at">
<return type="void" />
<argument index="0" name="index" type="int" />
<description>
diff --git a/doc/classes/PackedInt64Array.xml b/doc/classes/PackedInt64Array.xml
index c7b69d4ad5..ff48eb1aad 100644
--- a/doc/classes/PackedInt64Array.xml
+++ b/doc/classes/PackedInt64Array.xml
@@ -96,7 +96,7 @@
Appends a value to the array.
</description>
</method>
- <method name="remove">
+ <method name="remove_at">
<return type="void" />
<argument index="0" name="index" type="int" />
<description>
diff --git a/doc/classes/PackedScene.xml b/doc/classes/PackedScene.xml
index d0579c6f6f..d3a770b35b 100644
--- a/doc/classes/PackedScene.xml
+++ b/doc/classes/PackedScene.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
A simplified interface to a scene file. Provides access to operations and checks that can be performed on the scene resource itself.
- Can be used to save a node to a file. When saving, the node as well as all the nodes it owns get saved (see [code]owner[/code] property on [Node]).
+ Can be used to save a node to a file. When saving, the node as well as all the nodes it owns get saved (see [member Node.owner] property).
[b]Note:[/b] The node doesn't need to own itself.
[b]Example of loading a saved scene:[/b]
[codeblocks]
@@ -22,7 +22,7 @@
AddChild(scene);
[/csharp]
[/codeblocks]
- [b]Example of saving a node with different owners:[/b] The following example creates 3 objects: [code]Node2D[/code] ([code]node[/code]), [code]RigidDynamicBody2D[/code] ([code]body[/code]) and [code]CollisionObject2D[/code] ([code]collision[/code]). [code]collision[/code] is a child of [code]body[/code] which is a child of [code]node[/code]. Only [code]body[/code] is owned by [code]node[/code] and [code]pack[/code] will therefore only save those two nodes, but not [code]collision[/code].
+ [b]Example of saving a node with different owners:[/b] The following example creates 3 objects: [Node2D] ([code]node[/code]), [RigidDynamicBody2D] ([code]body[/code]) and [CollisionObject2D] ([code]collision[/code]). [code]collision[/code] is a child of [code]body[/code] which is a child of [code]node[/code]. Only [code]body[/code] is owned by [code]node[/code] and [code]pack[/code] will therefore only save those two nodes, but not [code]collision[/code].
[codeblocks]
[gdscript]
# Create the objects.
diff --git a/doc/classes/PackedStringArray.xml b/doc/classes/PackedStringArray.xml
index dfebfb718b..4204277ea2 100644
--- a/doc/classes/PackedStringArray.xml
+++ b/doc/classes/PackedStringArray.xml
@@ -96,7 +96,7 @@
Appends a string element at end of the array.
</description>
</method>
- <method name="remove">
+ <method name="remove_at">
<return type="void" />
<argument index="0" name="index" type="int" />
<description>
diff --git a/doc/classes/PackedVector2Array.xml b/doc/classes/PackedVector2Array.xml
index bf9b7e97d4..e6a7b2fa41 100644
--- a/doc/classes/PackedVector2Array.xml
+++ b/doc/classes/PackedVector2Array.xml
@@ -96,7 +96,7 @@
Inserts a [Vector2] at the end.
</description>
</method>
- <method name="remove">
+ <method name="remove_at">
<return type="void" />
<argument index="0" name="index" type="int" />
<description>
diff --git a/doc/classes/PackedVector3Array.xml b/doc/classes/PackedVector3Array.xml
index b439f8f217..6992bbca01 100644
--- a/doc/classes/PackedVector3Array.xml
+++ b/doc/classes/PackedVector3Array.xml
@@ -95,7 +95,7 @@
Inserts a [Vector3] at the end.
</description>
</method>
- <method name="remove">
+ <method name="remove_at">
<return type="void" />
<argument index="0" name="index" type="int" />
<description>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index cb26d8d445..7fdac7ccd4 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -196,13 +196,17 @@
Background color for the boot splash.
</member>
<member name="application/boot_splash/fullsize" type="bool" setter="" getter="" default="true">
- If [code]true[/code], scale the boot splash image to the full window length when engine starts. If [code]false[/code], the engine will leave it at the default pixel size.
+ If [code]true[/code], scale the boot splash image to the full window size (preserving the aspect ratio) when the engine starts. If [code]false[/code], the engine will leave it at the default pixel size.
</member>
<member name="application/boot_splash/image" type="String" setter="" getter="" default="&quot;&quot;">
- Path to an image used as the boot splash.
+ Path to an image used as the boot splash. If left empty, the default Godot Engine splash will be displayed instead.
+ [b]Note:[/b] Only effective if [member application/boot_splash/show_image] is [code]true[/code].
+ </member>
+ <member name="application/boot_splash/show_image" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], displays the image specified in [member application/boot_splash/image] when the engine starts. If [code]false[/code], only displays the plain color specified in [member application/boot_splash/bg_color].
</member>
<member name="application/boot_splash/use_filter" type="bool" setter="" getter="" default="true">
- If [code]true[/code], applies linear filtering when scaling the image (recommended for high resolution artwork). If [code]false[/code], uses nearest-neighbor interpolation (recommended for pixel art).
+ If [code]true[/code], applies linear filtering when scaling the image (recommended for high-resolution artwork). If [code]false[/code], uses nearest-neighbor interpolation (recommended for pixel art).
</member>
<member name="application/config/custom_user_dir_name" type="String" setter="" getter="" default="&quot;&quot;">
This user directory is used for storing persistent data ([code]user://[/code] filesystem). If left empty, [code]user://[/code] resolves to a project-specific folder in Godot's own configuration folder (see [method OS.get_user_data_dir]). If a custom directory name is defined, this name will be used instead and appended to the system-specific user data directory (same parent folder as the Godot configuration folder documented in [method OS.get_user_data_dir]).
@@ -368,6 +372,9 @@
<member name="debug/gdscript/warnings/return_value_discarded" type="bool" setter="" getter="" default="true">
If [code]true[/code], enables warnings when calling a function without using its return value (by assigning it to a variable or using it as a function argument). Such return values are sometimes used to denote possible errors using the [enum Error] enum.
</member>
+ <member name="debug/gdscript/warnings/shadowed_global_identifier" type="bool" setter="" getter="" default="true">
+ If [code]true[/code], enables warnings when defining a local or subclass member variable, signal, or enum that would have the same name as a built-in function or global class name, which possibly shadow it.
+ </member>
<member name="debug/gdscript/warnings/shadowed_variable" type="bool" setter="" getter="" default="true">
If [code]true[/code], enables warnings when defining a local or subclass member variable that would shadow a variable at an upper level (such as a member variable).
</member>
@@ -1499,12 +1506,8 @@
</member>
<member name="rendering/2d/snap/snap_2d_vertices_to_pixel" type="bool" setter="" getter="" default="false">
</member>
- <member name="rendering/3d/viewport/scale" type="float" setter="" getter="" default="1.0">
- Scales the 3D render buffer based on the viewport size and displays the result with linear filtering. Values lower than [code]1.0[/code] can be used to speed up 3D rendering at the cost of quality (undersampling). Values greater than [code]1.0[/code] can be used to improve 3D rendering quality at a high performance cost (supersampling). See also [member rendering/anti_aliasing/quality/msaa] for multi-sample antialiasing, which is significantly cheaper but only smoothens the edges of polygons.
- [b]Note:[/b] This property is only read when the project starts. To change the 3D rendering resolution scale at runtime, set [member Viewport.scale_3d] instead.
- </member>
<member name="rendering/anti_aliasing/quality/msaa" type="int" setter="" getter="" default="0">
- Sets the number of MSAA samples to use (as a power of two). MSAA is used to reduce aliasing around the edges of polygons. A higher MSAA value results in smoother edges but can be significantly slower on some hardware. See also [member rendering/3d/viewport/scale] for supersampling, which provides higher quality but is much more expensive.
+ Sets the number of MSAA samples to use (as a power of two). MSAA is used to reduce aliasing around the edges of polygons. A higher MSAA value results in smoother edges but can be significantly slower on some hardware. See also bilinear scaling 3d [member rendering/scaling_3d/mode] for supersampling, which provides higher quality but is much more expensive.
</member>
<member name="rendering/anti_aliasing/quality/screen_space_aa" type="int" setter="" getter="" default="0">
Sets the screen-space antialiasing mode for the default screen [Viewport]. Screen-space antialiasing works by selectively blurring edges in a post-process shader. It differs from MSAA which takes multiple coverage samples while rendering objects. Screen-space AA methods are typically faster than MSAA and will smooth out specular aliasing, but tend to make scenes appear blurry.
@@ -1711,6 +1714,18 @@
<member name="rendering/reflections/sky_reflections/texture_array_reflections.mobile" type="bool" setter="" getter="" default="false">
Lower-end override for [member rendering/reflections/sky_reflections/texture_array_reflections] on mobile devices, due to performance concerns or driver support.
</member>
+ <member name="rendering/scaling_3d/fsr_mipmap_bias" type="float" setter="" getter="" default="0.0">
+ Affects the final texture sharpness by reading from a lower or higher mipmap. Negative values make textures sharper, while positive values make textures blurrier. When using FSR, this value is used to adjust the mipmap bias calculated internally which is based on the selected quality. The formula for this is [code]-log2(1.0 / scale) + mipmap_bias[/code]
+ </member>
+ <member name="rendering/scaling_3d/fsr_sharpness" type="float" setter="" getter="" default="0.2">
+ Determines how sharp the upscaled image will be when using the FSR upscaling mode. Sharpness halves with every whole number. Values go from 0.0 (sharpest) to 2.0. Values above 2.0 won't make a visible difference.
+ </member>
+ <member name="rendering/scaling_3d/mode" type="int" setter="" getter="" default="0">
+ Sets the scaling 3D mode. Bilinear scaling renders at different resolution to either undersample or supersample the viewport. FidelityFX Super Resolution 1.0, abbreviated to FSR, is an upscaling technology that produces high quality images at fast framerates by using a spatially aware upscaling algorithm. FSR is slightly more expensive than bilinear, but it produces significantly higher image quality. FSR should be used where possible.
+ </member>
+ <member name="rendering/scaling_3d/scale" type="float" setter="" getter="" default="1.0">
+ Scales the 3D render buffer based on the viewport size uses an image filter specified in [member rendering/scaling_3d/mode] to scale the output image to the full viewport size. Values lower than [code]1.0[/code] can be used to speed up 3D rendering at the cost of quality (undersampling). Values greater than [code]1.0[/code] are only valid for bilinear mode and can be used to improve 3D rendering quality at a high performance cost (supersampling). See also [member rendering/anti_aliasing/quality/msaa] for multi-sample antialiasing, which is significantly cheaper but only smoothens the edges of polygons.
+ </member>
<member name="rendering/shader_compiler/shader_cache/compress" type="bool" setter="" getter="" default="true">
</member>
<member name="rendering/shader_compiler/shader_cache/enabled" type="bool" setter="" getter="" default="true">
diff --git a/doc/classes/ReferenceRect.xml b/doc/classes/ReferenceRect.xml
index 1db6879b45..99ad067469 100644
--- a/doc/classes/ReferenceRect.xml
+++ b/doc/classes/ReferenceRect.xml
@@ -16,7 +16,7 @@
Sets the border width of the [ReferenceRect]. The border grows both inwards and outwards with respect to the rectangle box.
</member>
<member name="editor_only" type="bool" setter="set_editor_only" getter="get_editor_only" default="true">
- If set to [code]true[/code], the [ReferenceRect] will only be visible while in editor. Otherwise, [ReferenceRect] will be visible in game.
+ If [code]true[/code], the [ReferenceRect] will only be visible while in editor. Otherwise, [ReferenceRect] will be visible in the running project.
</member>
</members>
</class>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 7f4d5cf1cd..0700650a91 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -3100,6 +3100,22 @@
If [code]true[/code], rendering of a viewport's environment is disabled.
</description>
</method>
+ <method name="viewport_set_fsr_mipmap_bias">
+ <return type="void" />
+ <argument index="0" name="viewport" type="RID" />
+ <argument index="1" name="mipmap_bias" type="float" />
+ <description>
+ Affects the final texture sharpness by reading from a lower or higher mipmap. Negative values make textures sharper, while positive values make textures blurrier. When using FSR, this value is used to adjust the mipmap bias calculated internally which is based on the selected quality. The formula for this is [code]-log2(1.0 / scale) + mipmap_bias[/code]
+ </description>
+ </method>
+ <method name="viewport_set_fsr_sharpness">
+ <return type="void" />
+ <argument index="0" name="viewport" type="RID" />
+ <argument index="1" name="sharpness" type="float" />
+ <description>
+ Determines how sharp the upscaled image will be when using the FSR upscaling mode. Sharpness halves with every whole number. Values go from 0.0 (sharpest) to 2.0. Values above 2.0 won't make a visible difference.
+ </description>
+ </method>
<method name="viewport_set_global_canvas_transform">
<return type="void" />
<argument index="0" name="viewport" type="RID" />
@@ -3151,12 +3167,21 @@
If [code]true[/code], render the contents of the viewport directly to screen. This allows a low-level optimization where you can skip drawing a viewport to the root viewport. While this optimization can result in a significant increase in speed (especially on older devices), it comes at a cost of usability. When this is enabled, you cannot read from the viewport or from the [code]SCREEN_TEXTURE[/code]. You also lose the benefit of certain window settings, such as the various stretch modes. Another consequence to be aware of is that in 2D the rendering happens in window coordinates, so if you have a viewport that is double the size of the window, and you set this, then only the portion that fits within the window will be drawn, no automatic scaling is possible, even if your game scene is significantly larger than the window size.
</description>
</method>
- <method name="viewport_set_scale_3d">
+ <method name="viewport_set_scaling_3d_mode">
+ <return type="void" />
+ <argument index="0" name="viewport" type="RID" />
+ <argument index="1" name="scaling_3d_mode" type="int" enum="RenderingServer.ViewportScaling3DMode" />
+ <description>
+ Sets scaling 3d mode. Bilinear scaling renders at different resolution to either undersample or supersample the viewport. FidelityFX Super Resolution 1.0, abbreviated to FSR, is an upscaling technology that produces high quality images at fast framerates by using a spatially aware upscaling algorithm. FSR is slightly more expensive than bilinear, but it produces significantly higher image quality. FSR should be used where possible.
+ </description>
+ </method>
+ <method name="viewport_set_scaling_3d_scale">
<return type="void" />
<argument index="0" name="viewport" type="RID" />
<argument index="1" name="scale" type="float" />
<description>
- Sets the scale at which we render 3D contents.
+ Scales the 3D render buffer based on the viewport size uses an image filter specified in [enum ViewportScaling3DMode] to scale the output image to the full viewport size. Values lower than [code]1.0[/code] can be used to speed up 3D rendering at the cost of quality (undersampling). Values greater than [code]1.0[/code] are only valid for bilinear mode and can be used to improve 3D rendering quality at a high performance cost (supersampling). See also [enum ViewportMSAA] for multi-sample antialiasing, which is significantly cheaper but only smoothens the edges of polygons.
+ When using FSR upscaling, AMD recommends exposing the following values as preset options to users "Ultra Quality: 0.77", "Quality: 0.67", "Balanced: 0.59", "Performance: 0.5" instead of exposing the entire scale.
</description>
</method>
<method name="viewport_set_scenario">
@@ -3844,6 +3869,14 @@
<constant name="FOG_VOLUME_SHAPE_WORLD" value="2" enum="FogVolumeShape">
[FogVolume] will have no shape, will cover the whole world and will not be culled.
</constant>
+ <constant name="VIEWPORT_SCALING_3D_MODE_BILINEAR" value="0" enum="ViewportScaling3DMode">
+ Enables bilinear scaling on 3D viewports. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less then [code]1.0[/code] will result in undersampling while values greater than [code]1.0[/code] will result in supersampling. A value of [code]1.0[/code] disables scaling.
+ </constant>
+ <constant name="VIEWPORT_SCALING_3D_MODE_FSR" value="1" enum="ViewportScaling3DMode">
+ Enables FSR upscaling on 3D viewports. The amount of scaling can be set using [member Viewport.scaling_3d_scale]. Values less then [code]1.0[/code] will be result in the viewport being upscaled using FSR. Values greater than [code]1.0[/code] are not supported and bilinear supersampling will be used instead. A value of [code]1.0[/code] disables scaling.
+ </constant>
+ <constant name="VIEWPORT_SCALING_3D_MODE_MAX" value="2" enum="ViewportScaling3DMode">
+ </constant>
<constant name="VIEWPORT_UPDATE_DISABLED" value="0" enum="ViewportUpdateMode">
Do not update the viewport.
</constant>
diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 400fae4aad..16d8595b4e 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -362,6 +362,24 @@
Returns OpenType feature [code]tag[/code].
</description>
</method>
+ <method name="get_pos_at_line_column" qualifiers="const">
+ <return type="Vector2i" />
+ <argument index="0" name="line" type="int" />
+ <argument index="1" name="column" type="int" />
+ <description>
+ Returns the local position for the given [code]line[/code] and [code]column[/code]. If [code]x[/code] or [code]y[/code] of the returned vector equal [code]-1[/code], the position is outside of the viewable area of the control.
+ [b]Note:[/b] The Y position corresponds to the bottom side of the line. Use [method get_rect_at_line_column] to get the top side position.
+ </description>
+ </method>
+ <method name="get_rect_at_line_column" qualifiers="const">
+ <return type="Rect2i" />
+ <argument index="0" name="line" type="int" />
+ <argument index="1" name="column" type="int" />
+ <description>
+ Returns the local position and size for the grapheme at the given [code]line[/code] and [code]column[/code]. If [code]x[/code] or [code]y[/code] position of the returned rect equal [code]-1[/code], the position is outside of the viewable area of the control.
+ [b]Note:[/b] The Y position of the returned rect corresponds to the top side of the line, unlike [method get_pos_at_line_column] which returns the bottom side.
+ </description>
+ </method>
<method name="get_saved_version" qualifiers="const">
<return type="int" />
<description>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index e1c05165de..512078c56c 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -1028,6 +1028,14 @@
Returns text glyphs in the visual order.
</description>
</method>
+ <method name="shaped_text_get_grapheme_bounds" qualifiers="const">
+ <return type="Vector2" />
+ <argument index="0" name="shaped" type="RID" />
+ <argument index="1" name="pos" type="int" />
+ <description>
+ Returns composite character's bounds as offsets from the start of the line.
+ </description>
+ </method>
<method name="shaped_text_get_line_breaks" qualifiers="const">
<return type="PackedInt32Array" />
<argument index="0" name="shaped" type="RID" />
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index 684a1aa755..32f8107e0a 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -1037,6 +1037,14 @@
Copies text glyphs in the visual order, into preallocated array of the size returned by [method _shaped_text_get_glyph_count].
</description>
</method>
+ <method name="_shaped_text_get_grapheme_bounds" qualifiers="virtual const">
+ <return type="Vector2" />
+ <argument index="0" name="shaped" type="RID" />
+ <argument index="1" name="pos" type="int" />
+ <description>
+ Returns composite character's bounds as offsets from the start of the line.
+ </description>
+ </method>
<method name="_shaped_text_get_line_breaks" qualifiers="virtual const">
<return type="PackedInt32Array" />
<argument index="0" name="shaped" type="RID" />
diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml
index d83645a8af..0418f29808 100644
--- a/doc/classes/Viewport.xml
+++ b/doc/classes/Viewport.xml
@@ -194,6 +194,14 @@
<member name="disable_3d" type="bool" setter="set_disable_3d" getter="is_3d_disabled" default="false">
Disable 3D rendering (but keep 2D rendering).
</member>
+ <member name="fsr_mipmap_bias" type="float" setter="set_fsr_mipmap_bias" getter="get_fsr_mipmap_bias" default="0.0">
+ Affects the final texture sharpness by reading from a lower or higher mipmap when using FSR. Mipmap bias does nothing when FSR is not being used. Negative values make textures sharper, while positive values make textures blurrier. This value is used to adjust the mipmap bias calculated internally which is based on the selected quality. The formula for this is [code]-log2(1.0 / scale) + mipmap_bias[/code]. This updates the rendering server's mipmap bias when called
+ To control this property on the root viewport, set the [member ProjectSettings.rendering/scaling_3d/fsr_mipmap_bias] project setting.
+ </member>
+ <member name="fsr_sharpness" type="float" setter="set_fsr_sharpness" getter="get_fsr_sharpness" default="0.2">
+ Determines how sharp the upscaled image will be when using the FSR upscaling mode. Sharpness halves with every whole number. Values go from 0.0 (sharpest) to 2.0. Values above 2.0 won't make a visible difference.
+ To control this property on the root viewport, set the [member ProjectSettings.rendering/scaling_3d/fsr_sharpness] project setting.
+ </member>
<member name="global_canvas_transform" type="Transform2D" setter="set_global_canvas_transform" getter="get_global_canvas_transform">
The global canvas transform of the viewport. The canvas transform is relative to this.
</member>
@@ -210,7 +218,7 @@
<member name="lod_threshold" type="float" setter="set_lod_threshold" getter="get_lod_threshold" default="1.0">
</member>
<member name="msaa" type="int" setter="set_msaa" getter="get_msaa" enum="Viewport.MSAA" default="0">
- The multisample anti-aliasing mode. A higher number results in smoother edges at the cost of significantly worse performance. A value of 2 or 4 is best unless targeting very high-end systems. See also [member scale_3d] for supersampling, which provides higher quality but is much more expensive.
+ The multisample anti-aliasing mode. A higher number results in smoother edges at the cost of significantly worse performance. A value of 2 or 4 is best unless targeting very high-end systems. See also bilinear scaling 3d [member scaling_3d_mode] for supersampling, which provides higher quality but is much more expensive.
</member>
<member name="own_world_3d" type="bool" setter="set_use_own_world_3d" getter="is_using_own_world_3d" default="false">
If [code]true[/code], the viewport will use the [World3D] defined in [member world_3d].
@@ -218,9 +226,14 @@
<member name="physics_object_picking" type="bool" setter="set_physics_object_picking" getter="get_physics_object_picking" default="false">
If [code]true[/code], the objects rendered by viewport become subjects of mouse picking process.
</member>
- <member name="scale_3d" type="float" setter="set_scale_3d" getter="get_scale_3d" default="1.0">
- Scales the 3D render buffer based on the viewport size and displays the result with linear filtering. Values lower than [code]1.0[/code] can be used to speed up 3D rendering at the cost of quality (undersampling). Values greater than [code]1.0[/code] can be used to improve 3D rendering quality at a high performance cost (supersampling). See also [member msaa] for multi-sample antialiasing, which is significantly cheaper but only smoothens the edges of polygons.
- To control this property on the root viewport, set the [member ProjectSettings.rendering/3d/viewport/scale] project setting.
+ <member name="scaling_3d_mode" type="int" setter="set_scaling_3d_mode" getter="get_scaling_3d_mode" enum="Viewport.Scaling3DMode" default="0">
+ Sets scaling 3d mode. Bilinear scaling renders at different resolution to either undersample or supersample the viewport. FidelityFX Super Resolution 1.0, abbreviated to FSR, is an upscaling technology that produces high quality images at fast framerates by using a spatially aware upscaling algorithm. FSR is slightly more expensive than bilinear, but it produces significantly higher image quality. FSR should be used where possible.
+ To control this property on the root viewport, set the [member ProjectSettings.rendering/scaling_3d/mode] project setting.
+ </member>
+ <member name="scaling_3d_scale" type="float" setter="set_scaling_3d_scale" getter="get_scaling_3d_scale" default="1.0">
+ Scales the 3D render buffer based on the viewport size uses an image filter specified in [member ProjectSettings.rendering/scaling_3d/mode] to scale the output image to the full viewport size. Values lower than [code]1.0[/code] can be used to speed up 3D rendering at the cost of quality (undersampling). Values greater than [code]1.0[/code] are only valid for bilinear mode and can be used to improve 3D rendering quality at a high performance cost (supersampling). See also [member ProjectSettings.rendering/anti_aliasing/quality/msaa] for multi-sample antialiasing, which is significantly cheaper but only smoothens the edges of polygons.
+ When using FSR upscaling, AMD recommends exposing the following values as preset options to users "Ultra Quality: 0.77", "Quality: 0.67", "Balanced: 0.59", "Performance: 0.5" instead of exposing the entire scale.
+ To control this property on the root viewport, set the [member ProjectSettings.rendering/scaling_3d/scale] project setting.
</member>
<member name="screen_space_aa" type="int" setter="set_screen_space_aa" getter="get_screen_space_aa" enum="Viewport.ScreenSpaceAA" default="0">
Sets the screen-space antialiasing method used. Screen-space antialiasing works by selectively blurring edges in a post-process shader. It differs from MSAA which takes multiple coverage samples while rendering objects. Screen-space AA methods are typically faster than MSAA and will smooth out specular aliasing, but tend to make scenes appear blurry.
@@ -306,6 +319,15 @@
<constant name="SHADOW_ATLAS_QUADRANT_SUBDIV_MAX" value="7" enum="ShadowAtlasQuadrantSubdiv">
Represents the size of the [enum ShadowAtlasQuadrantSubdiv] enum.
</constant>
+ <constant name="SCALING_3D_MODE_BILINEAR" value="0" enum="Scaling3DMode">
+ Enables bilinear scaling on 3D viewports. The amount of scaling can be set using [member scaling_3d_scale]. Values less then [code]1.0[/code] will result in undersampling while values greater than [code]1.0[/code] will result in supersampling. A value of [code]1.0[/code] disables scaling.
+ </constant>
+ <constant name="SCALING_3D_MODE_FSR" value="1" enum="Scaling3DMode">
+ Enables FSR upscaling on 3D viewports. The amount of scaling can be set using [member scaling_3d_scale]. Values less then [code]1.0[/code] will be result in the viewport being upscaled using FSR. Values greater than [code]1.0[/code] are not supported and bilinear supersampling will be used instead. A value of [code]1.0[/code] disables scaling.
+ </constant>
+ <constant name="SCALING_3D_MODE_MAX" value="2" enum="Scaling3DMode">
+ Represents the size of the [enum Scaling3DMode] enum.
+ </constant>
<constant name="MSAA_DISABLED" value="0" enum="MSAA">
Multisample antialiasing mode disabled. This is the default value, and is also the fastest setting.
</constant>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index f36b926bef..3fee1feae8 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -230,6 +230,12 @@
<description>
</description>
</method>
+ <method name="reset_size">
+ <return type="void" />
+ <description>
+ Resets the size to the minimum size, which is the max of [member min_size] and (if [member wrap_controls] is enabled) [method get_contents_minimum_size]. This is equivalent to calling [code]set_size(Vector2i())[/code] (or any size below the minimum).
+ </description>
+ </method>
<method name="set_flag">
<return type="void" />
<argument index="0" name="flag" type="int" enum="Window.Flags" />
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index e66bde90fe..c7753e2c5c 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -421,7 +421,7 @@ RID RasterizerSceneGLES3::render_buffers_create() {
return RID();
}
-void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) {
+void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) {
}
void RasterizerSceneGLES3::gi_set_use_half_resolution(bool p_enable) {
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index e8d257087f..14ab0eaa4a 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -203,7 +203,7 @@ public:
void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override;
RID render_buffers_create() override;
- void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override;
+ void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override;
void gi_set_use_half_resolution(bool p_enable) override;
void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override;
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 4cae051302..952ee50074 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -8822,6 +8822,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
// get info about further features
VulkanContext::MultiviewCapabilities multiview_capabilies = p_context->get_multiview_capabilities();
device_capabilities.supports_multiview = multiview_capabilies.is_supported && multiview_capabilies.max_view_count > 1;
+ device_capabilities.supports_fsr_half_float = p_context->get_shader_capabilities().shader_float16_is_supported && p_context->get_storage_buffer_capabilities().storage_buffer_16_bit_access_is_supported;
}
context = p_context;
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index c178a68236..5912f481ec 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -535,6 +535,24 @@ Error VulkanContext::_check_capabilities() {
multiview_capabilities.is_supported = multiview_features.multiview;
multiview_capabilities.geometry_shader_is_supported = multiview_features.multiviewGeometryShader;
multiview_capabilities.tessellation_shader_is_supported = multiview_features.multiviewTessellationShader;
+
+ VkPhysicalDeviceShaderFloat16Int8FeaturesKHR shader_features;
+ shader_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES_KHR;
+ shader_features.pNext = NULL;
+
+ device_features.pNext = &shader_features;
+
+ device_features_func(gpu, &device_features);
+ shader_capabilities.shader_float16_is_supported = shader_features.shaderFloat16;
+
+ VkPhysicalDevice16BitStorageFeaturesKHR storage_feature;
+ storage_feature.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR;
+ storage_feature.pNext = NULL;
+
+ device_features.pNext = &storage_feature;
+
+ device_features_func(gpu, &device_features);
+ storage_buffer_capabilities.storage_buffer_16_bit_access_is_supported = storage_feature.storageBuffer16BitAccess;
}
// check extended properties
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index ae7c697be8..ab2f6a3eb5 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -66,6 +66,14 @@ public:
uint32_t max_instance_count;
};
+ struct ShaderCapabilities {
+ bool shader_float16_is_supported;
+ };
+
+ struct StorageBufferCapabilities {
+ bool storage_buffer_16_bit_access_is_supported;
+ };
+
private:
enum {
MAX_EXTENSIONS = 128,
@@ -88,6 +96,8 @@ private:
uint32_t vulkan_patch = 0;
SubgroupCapabilities subgroup_capabilities;
MultiviewCapabilities multiview_capabilities;
+ ShaderCapabilities shader_capabilities;
+ StorageBufferCapabilities storage_buffer_capabilities;
String device_vendor;
String device_name;
@@ -239,6 +249,8 @@ public:
uint32_t get_vulkan_minor() const { return vulkan_minor; };
SubgroupCapabilities get_subgroup_capabilities() const { return subgroup_capabilities; };
MultiviewCapabilities get_multiview_capabilities() const { return multiview_capabilities; };
+ ShaderCapabilities get_shader_capabilities() const { return shader_capabilities; };
+ StorageBufferCapabilities get_storage_buffer_capabilities() const { return storage_buffer_capabilities; };
VkDevice get_device();
VkPhysicalDevice get_physical_device();
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 3ca3576de6..dc0c62fbc9 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -847,7 +847,7 @@ void ActionMapEditor::_tree_button_pressed(Object *p_item, int p_column, int p_i
int event_index = item->get_meta("__index");
Array events = action["events"];
- events.remove(event_index);
+ events.remove_at(event_index);
action["events"] = events;
emit_signal(SNAME("action_edited"), action_name, action);
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index c773f51342..d00fdd0ce7 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -240,7 +240,7 @@ void ConnectDialog::_remove_bind() {
int idx = st.get_slice("/", 1).to_int() - 1;
ERR_FAIL_INDEX(idx, cdbinds->params.size());
- cdbinds->params.remove(idx);
+ cdbinds->params.remove_at(idx);
cdbinds->notify_changed();
}
@@ -378,7 +378,7 @@ void ConnectDialog::_advanced_pressed() {
error_label->hide();
} else {
set_min_size(Size2(600, 500) * EDSCALE);
- set_size(Size2());
+ reset_size();
connect_to_label->set_text(TTR("Connect to Script:"));
tree->set_connect_to_script_mode(true);
@@ -723,7 +723,7 @@ void ConnectionsDock::_open_connection_dialog(TreeItem &item) {
c = '_';
} else {
// Remove any other characters.
- midname.remove(i);
+ midname.remove_at(i);
i--;
continue;
}
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 72aea9b630..dec4f50f03 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -576,7 +576,7 @@ void CreateDialog::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
drop_idx--;
}
- favorite_list.remove(from_idx);
+ favorite_list.remove_at(from_idx);
if (ds < 0) {
favorite_list.insert(drop_idx, type);
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index e0d32756ca..b18c225f23 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/editor/debugger/script_editor_debugger.cpp
@@ -1420,7 +1420,7 @@ void ScriptEditorDebugger::_clear_errors_list() {
// Right click on specific file(s) or folder(s).
void ScriptEditorDebugger::_error_tree_item_rmb_selected(const Vector2 &p_pos) {
item_menu->clear();
- item_menu->set_size(Size2(1, 1));
+ item_menu->reset_size();
if (error_tree->is_anything_selected()) {
item_menu->add_icon_item(get_theme_icon(SNAME("ActionCopy"), SNAME("EditorIcons")), TTR("Copy Error"), ACTION_COPY_ERROR);
diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp
index d07d77c112..f18284638f 100644
--- a/editor/dependency_editor.cpp
+++ b/editor/dependency_editor.cpp
@@ -270,7 +270,7 @@ DependencyEditor::DependencyEditor() {
/////////////////////////////////////
void DependencyEditorOwners::_list_rmb_select(int p_item, const Vector2 &p_pos) {
file_options->clear();
- file_options->set_size(Size2(1, 1));
+ file_options->reset_size();
if (p_item >= 0) {
file_options->add_item(TTR("Open"), FILE_OPEN);
}
@@ -464,7 +464,7 @@ void DependencyRemoveDialog::show(const Vector<String> &p_folders, const Vector<
if (removed_deps.is_empty()) {
owners->hide();
text->set_text(TTR("Remove the selected files from the project? (Cannot be undone.)\nDepending on your filesystem configuration, the files will either be moved to the system trash or deleted permanently."));
- set_size(Size2());
+ reset_size();
popup_centered();
} else {
_build_removed_dependency_tree(removed_deps);
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 0840c3b6a8..25e76c2262 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -117,7 +117,7 @@ bool EditorAutoloadSettings::_autoload_name_is_valid(const String &p_name, Strin
for (const String &E : keywords) {
if (E == p_name) {
if (r_error) {
- *r_error = TTR("Invalid name.") + " " + TTR("Keyword cannot be used as an autoload name.");
+ *r_error = TTR("Invalid name.") + " " + TTR("Keyword cannot be used as an AutoLoad name.");
}
return false;
@@ -373,13 +373,13 @@ Node *EditorAutoloadSettings::_create_autoload(const String &p_path) {
Object *obj = ClassDB::instantiate(ibt);
- ERR_FAIL_COND_V_MSG(obj == nullptr, nullptr, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt) + ".");
+ ERR_FAIL_COND_V_MSG(obj == nullptr, nullptr, "Cannot instance script for AutoLoad, expected 'Node' inheritance, got: " + String(ibt) + ".");
n = Object::cast_to<Node>(obj);
n->set_script(s);
}
- ERR_FAIL_COND_V_MSG(!n, nullptr, "Path in autoload not a node or script: " + p_path + ".");
+ ERR_FAIL_COND_V_MSG(!n, nullptr, "Path in AutoLoad not a node or script: " + p_path + ".");
return n;
}
@@ -692,18 +692,18 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
String error;
if (!_autoload_name_is_valid(name, &error)) {
- EditorNode::get_singleton()->show_warning(TTR("Can't add autoload:") + "\n" + error);
+ EditorNode::get_singleton()->show_warning(TTR("Can't add AutoLoad:") + "\n" + error);
return false;
}
const String &path = p_path;
if (!FileAccess::exists(path)) {
- EditorNode::get_singleton()->show_warning(TTR("Can't add autoload:") + "\n" + vformat(TTR("%s is an invalid path. File does not exist."), path));
+ EditorNode::get_singleton()->show_warning(TTR("Can't add AutoLoad:") + "\n" + vformat(TTR("%s is an invalid path. File does not exist."), path));
return false;
}
if (!path.begins_with("res://")) {
- EditorNode::get_singleton()->show_warning(TTR("Can't add autoload:") + "\n" + vformat(TTR("%s is an invalid path. Not in resource path (res://)."), path));
+ EditorNode::get_singleton()->show_warning(TTR("Can't add AutoLoad:") + "\n" + vformat(TTR("%s is an invalid path. Not in resource path (res://)."), path));
return false;
}
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index aee9c21007..a163b468e6 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -70,7 +70,7 @@ void EditorHistory::cleanup_history() {
}
if (fail) {
- history.remove(i);
+ history.remove_at(i);
i--;
}
}
@@ -510,7 +510,7 @@ void EditorData::remove_custom_type(const String &p_type) {
for (Map<String, Vector<CustomType>>::Element *E = custom_types.front(); E; E = E->next()) {
for (int i = 0; i < E->get().size(); i++) {
if (E->get()[i].name == p_type) {
- E->get().remove(i);
+ E->get().remove_at(i);
if (E->get().is_empty()) {
custom_types.erase(E->key());
}
@@ -570,7 +570,7 @@ void EditorData::remove_scene(int p_idx) {
ScriptEditor::get_singleton()->close_builtin_scripts_from_scene(edited_scene[p_idx].path);
}
- edited_scene.remove(p_idx);
+ edited_scene.remove_at(p_idx);
}
bool EditorData::_find_updated_instances(Node *p_root, Node *p_node, Set<String> &checked_paths) {
@@ -751,7 +751,7 @@ void EditorData::move_edited_scene_to_index(int p_idx) {
ERR_FAIL_INDEX(p_idx, edited_scene.size());
EditedScene es = edited_scene[current_edited_scene];
- edited_scene.remove(current_edited_scene);
+ edited_scene.remove_at(current_edited_scene);
edited_scene.insert(p_idx, es);
current_edited_scene = p_idx;
}
diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp
index e78ca7cd64..03d91ebcba 100644
--- a/editor/editor_export.cpp
+++ b/editor/editor_export.cpp
@@ -1534,7 +1534,7 @@ Ref<EditorExportPreset> EditorExport::get_export_preset(int p_idx) {
}
void EditorExport::remove_export_preset(int p_idx) {
- export_presets.remove(p_idx);
+ export_presets.remove_at(p_idx);
save_presets();
}
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 021ab8b93b..bea5c99c1a 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -302,7 +302,7 @@ void EditorFileDialog::_post_popup() {
bool exists = dir_access->dir_exists(recentd[i]);
if (!exists) {
// Remove invalid directory from the list of Recent directories.
- recentd.remove(i--);
+ recentd.remove_at(i--);
} else {
recent->add_item(name, folder);
recent->set_item_metadata(recent->get_item_count() - 1, recentd[i]);
@@ -576,7 +576,7 @@ void EditorFileDialog::_item_dc_selected(int p_item) {
void EditorFileDialog::_item_list_item_rmb_selected(int p_item, const Vector2 &p_pos) {
// Right click on specific file(s) or folder(s).
item_menu->clear();
- item_menu->set_size(Size2(1, 1));
+ item_menu->reset_size();
// Allow specific actions only on one item.
bool single_item_selected = item_list->get_selected_items().size() == 1;
@@ -620,7 +620,7 @@ void EditorFileDialog::_item_list_rmb_clicked(const Vector2 &p_pos) {
}
item_menu->clear();
- item_menu->set_size(Size2(1, 1));
+ item_menu->reset_size();
if (can_create_dir) {
item_menu->add_icon_item(item_list->get_theme_icon(SNAME("folder"), SNAME("FileDialog")), TTR("New Folder..."), ITEM_MENU_NEW_FOLDER, KeyModifierMask::CMD | Key::N);
@@ -1117,7 +1117,7 @@ void EditorFileDialog::_delete_items() {
}
}
if (folders.size() + files.size() > 0) {
- remove_dialog->set_size(Size2(1, 1));
+ remove_dialog->reset_size();
remove_dialog->show(folders, files);
}
}
@@ -1445,7 +1445,7 @@ void EditorFileDialog::_save_to_recent() {
for (int i = 0; i < recent.size(); i++) {
bool cres = recent[i].begins_with("res://");
if (recent[i] == dir || (res == cres && count > max)) {
- recent.remove(i);
+ recent.remove_at(i);
i--;
} else {
count++;
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index d141447044..4f02a82fb5 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -577,7 +577,7 @@ bool EditorFileSystem::_update_scan_actions() {
ERR_CONTINUE(idx == -1);
_delete_internal_files(ia.dir->files[idx]->file);
memdelete(ia.dir->files[idx]);
- ia.dir->files.remove(idx);
+ ia.dir->files.remove_at(idx);
fs_changed = true;
@@ -1536,7 +1536,7 @@ void EditorFileSystem::update_file(const String &p_file) {
}
}
memdelete(fs->files[cpos]);
- fs->files.remove(cpos);
+ fs->files.remove_at(cpos);
}
call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 07e505adb4..e1fae47057 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -650,7 +650,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
} else if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) {
_update_popup();
menu->set_position(get_screen_position() + get_local_mouse_position());
- menu->set_size(Vector2(1, 1));
+ menu->reset_size();
menu->popup();
select();
return;
@@ -1556,7 +1556,7 @@ void EditorInspectorArray::_panel_gui_input(Ref<InputEvent> p_event, int 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);
rmb_popup->set_position(mb->get_global_position());
- rmb_popup->set_size(Vector2());
+ rmb_popup->reset_size();
rmb_popup->popup();
}
}
@@ -1608,11 +1608,11 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
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(p_element_index);
+ 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(p_to_pos < p_element_index ? p_element_index + 1 : p_element_index);
+ 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.
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index dc175a3148..6aaf0b063f 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -383,6 +383,9 @@ void EditorNode::_update_scene_tabs() {
void EditorNode::_version_control_menu_option(int p_idx) {
switch (vcs_actions_menu->get_item_id(p_idx)) {
+ case RUN_VCS_METADATA: {
+ VersionControlEditorPlugin::get_singleton()->popup_vcs_metadata_dialog();
+ } break;
case RUN_VCS_SETTINGS: {
VersionControlEditorPlugin::get_singleton()->popup_vcs_set_up_dialog(gui_base);
} break;
@@ -828,7 +831,7 @@ void EditorNode::_remove_plugin_from_enabled(const String &p_name) {
PackedStringArray enabled_plugins = ps->get("editor_plugins/enabled");
for (int i = 0; i < enabled_plugins.size(); ++i) {
if (enabled_plugins.get(i) == p_name) {
- enabled_plugins.remove(i);
+ enabled_plugins.remove_at(i);
break;
}
}
@@ -3196,7 +3199,7 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_chan
}
memdelete(singleton->main_editor_buttons[i]);
- singleton->main_editor_buttons.remove(i);
+ singleton->main_editor_buttons.remove_at(i);
break;
}
@@ -3755,7 +3758,7 @@ void EditorNode::_open_recent_scene(int p_idx) {
ERR_FAIL_INDEX(p_idx, rc.size());
if (load_scene(rc[p_idx]) != OK) {
- rc.remove(p_idx);
+ rc.remove_at(p_idx);
EditorSettings::get_singleton()->set_project_metadata("recent_files", "scenes", rc);
_update_recent_scenes();
}
@@ -4903,7 +4906,7 @@ void EditorNode::_update_layouts_menu() {
editor_layouts->clear();
overridden_default_layout = -1;
- editor_layouts->set_size(Vector2());
+ editor_layouts->reset_size();
editor_layouts->add_shortcut(ED_SHORTCUT("layout/save", TTR("Save Layout")), SETTINGS_LAYOUT_SAVE);
editor_layouts->add_shortcut(ED_SHORTCUT("layout/delete", TTR("Delete Layout")), SETTINGS_LAYOUT_DELETE);
editor_layouts->add_separator();
@@ -5030,7 +5033,7 @@ void EditorNode::_scene_tab_input(const Ref<InputEvent> &p_input) {
if (mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
// context menu
scene_tabs_context_menu->clear();
- scene_tabs_context_menu->set_size(Size2(1, 1));
+ scene_tabs_context_menu->reset_size();
scene_tabs_context_menu->add_shortcut(ED_GET_SHORTCUT("editor/new_scene"), FILE_NEW_SCENE);
if (scene_tabs->get_hovered_tab() >= 0) {
@@ -5174,7 +5177,7 @@ void EditorNode::remove_bottom_panel_item(Control *p_item) {
bottom_panel_vb->remove_child(bottom_panel_items[i].control);
bottom_panel_hb_editors->remove_child(bottom_panel_items[i].button);
memdelete(bottom_panel_items[i].button);
- bottom_panel_items.remove(i);
+ bottom_panel_items.remove_at(i);
break;
}
}
@@ -6432,6 +6435,7 @@ EditorNode::EditorNode() {
p->add_separator();
p->add_child(vcs_actions_menu);
p->add_submenu_item(TTR("Version Control"), "Version Control");
+ vcs_actions_menu->add_item(TTR("Create Version Control Metadata"), RUN_VCS_METADATA);
vcs_actions_menu->add_item(TTR("Set Up Version Control"), RUN_VCS_SETTINGS);
vcs_actions_menu->add_item(TTR("Shut Down Version Control"), RUN_VCS_SHUT_DOWN);
@@ -6844,7 +6848,7 @@ EditorNode::EditorNode() {
gui_base->add_child(custom_build_manage_templates);
file_android_build_source = memnew(EditorFileDialog);
- file_android_build_source->set_title(TTR("Select android sources file"));
+ file_android_build_source->set_title(TTR("Select Android sources file"));
file_android_build_source->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
file_android_build_source->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
file_android_build_source->add_filter("*.zip");
diff --git a/editor/editor_node.h b/editor/editor_node.h
index 98aa4b697c..d74ec33f25 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -170,6 +170,7 @@ private:
RUN_PROJECT_DATA_FOLDER,
RUN_RELOAD_CURRENT_PROJECT,
RUN_PROJECT_MANAGER,
+ RUN_VCS_METADATA,
RUN_VCS_SETTINGS,
RUN_VCS_SHUT_DOWN,
SETTINGS_UPDATE_CONTINUOUSLY,
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index a3b6f6e59b..0f59c8281f 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -413,7 +413,7 @@ void EditorPropertyArray::update_property() {
void EditorPropertyArray::_remove_pressed(int p_index) {
Variant array = object->get_array();
- array.call("remove", p_index);
+ array.call("remove_at", p_index);
emit_changed(get_edited_property(), array, "", false);
update_property();
diff --git a/editor/editor_run.cpp b/editor/editor_run.cpp
index d7daa0c750..0a77a8b0bb 100644
--- a/editor/editor_run.cpp
+++ b/editor/editor_run.cpp
@@ -201,7 +201,7 @@ Error EditorRun::run(const String &p_scene, const String &p_custom_args, const L
Vector<String> exec_args = p_custom_args.substr(0, placeholder_pos).split(" ", false);
if (exec_args.size() >= 1) {
exec = exec_args[0];
- exec_args.remove(0);
+ exec_args.remove_at(0);
// Append the Godot executable name before we append executable arguments
// (since the order is reversed when using `push_front()`).
diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp
index 2942ece409..f07a5ab523 100644
--- a/editor/editor_spin_slider.cpp
+++ b/editor/editor_spin_slider.cpp
@@ -409,7 +409,7 @@ void EditorSpinSlider::_draw_spin_slider() {
Vector2 scale = get_global_transform_with_canvas().get_scale();
grabber->set_scale(scale);
- grabber->set_size(Size2(0, 0));
+ grabber->reset_size();
grabber->set_position(get_global_position() + (grabber_rect.get_center() - grabber->get_size() * 0.5) * scale);
if (mousewheel_over_grabber) {
diff --git a/editor/editor_vcs_interface.cpp b/editor/editor_vcs_interface.cpp
index eaa8f891ec..b4b740d7c6 100644
--- a/editor/editor_vcs_interface.cpp
+++ b/editor/editor_vcs_interface.cpp
@@ -166,3 +166,24 @@ EditorVCSInterface *EditorVCSInterface::get_singleton() {
void EditorVCSInterface::set_singleton(EditorVCSInterface *p_singleton) {
singleton = p_singleton;
}
+
+void EditorVCSInterface::create_vcs_metadata_files(VCSMetadata p_vcs_metadata_type, String &p_dir) {
+ if (p_vcs_metadata_type == VCSMetadata::GIT) {
+ FileAccess *f = FileAccess::open(p_dir.plus_file(".gitignore"), FileAccess::WRITE);
+ if (!f) {
+ ERR_FAIL_MSG(TTR("Couldn't create .gitignore in project path."));
+ } else {
+ f->store_line("# Godot 4+ specific ignores");
+ f->store_line(".godot/");
+ memdelete(f);
+ }
+ f = FileAccess::open(p_dir.plus_file(".gitattributes"), FileAccess::WRITE);
+ if (!f) {
+ ERR_FAIL_MSG(TTR("Couldn't create .gitattributes in project path."));
+ } else {
+ f->store_line("# Normalize EOL for all files that Git considers text files.");
+ f->store_line("* text=auto eol=lf");
+ memdelete(f);
+ }
+ }
+}
diff --git a/editor/editor_vcs_interface.h b/editor/editor_vcs_interface.h
index 52ab6d68ee..1a2adeb148 100644
--- a/editor/editor_vcs_interface.h
+++ b/editor/editor_vcs_interface.h
@@ -61,6 +61,12 @@ public:
static EditorVCSInterface *get_singleton();
static void set_singleton(EditorVCSInterface *p_singleton);
+ enum class VCSMetadata {
+ NONE,
+ GIT,
+ };
+ static void create_vcs_metadata_files(VCSMetadata p_vcs_metadata_type, String &p_dir);
+
bool is_addon_ready();
// Proxy functions to the editor for use
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 1dde157527..f40a048b75 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -197,7 +197,7 @@ Vector<String> FileSystemDock::_compute_uncollapsed_paths() {
child = child->get_next();
}
}
- needs_check.remove(0);
+ needs_check.remove_at(0);
}
}
}
@@ -1093,7 +1093,7 @@ void FileSystemDock::_push_to_history() {
history_pos++;
if (history.size() > history_max_size) {
- history.remove(0);
+ history.remove_at(0);
history_pos = history_max_size - 1;
}
}
@@ -1670,7 +1670,7 @@ Vector<String> FileSystemDock::_remove_self_included_paths(Vector<String> select
String last_path = "";
for (int i = 0; i < selected_strings.size(); i++) {
if (last_path != "" && selected_strings[i].begins_with(last_path)) {
- selected_strings.remove(i);
+ selected_strings.remove_at(i);
i--;
}
if (selected_strings[i].ends_with("/")) {
@@ -1704,7 +1704,7 @@ void FileSystemDock::_tree_rmb_option(int p_option) {
child = child->get_next();
}
- needs_check.remove(0);
+ needs_check.remove_at(0);
}
}
} break;
@@ -2229,7 +2229,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
drop_position -= offset;
to_remove.sort();
for (int i = 0; i < to_remove.size(); i++) {
- dirs.remove(to_remove[i] - i);
+ dirs.remove_at(to_remove[i] - i);
}
// Re-add them at the right position.
@@ -2507,7 +2507,7 @@ void FileSystemDock::_tree_rmb_select(const Vector2 &p_pos) {
// Popup.
if (!paths.is_empty()) {
- tree_popup->set_size(Size2(1, 1));
+ tree_popup->reset_size();
_file_and_folders_fill_popup(tree_popup, paths);
tree_popup->set_position(tree->get_screen_position() + p_pos);
tree_popup->popup();
@@ -2518,7 +2518,7 @@ void FileSystemDock::_tree_rmb_empty(const Vector2 &p_pos) {
// Right click is pressed in the empty space of the tree.
path = "res://";
tree_popup->clear();
- tree_popup->set_size(Size2(1, 1));
+ tree_popup->reset_size();
tree_popup->add_icon_item(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), TTR("New Folder..."), FILE_NEW_FOLDER);
tree_popup->add_icon_item(get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")), TTR("New Scene..."), FILE_NEW_SCENE);
tree_popup->add_icon_item(get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), TTR("New Script..."), FILE_NEW_SCRIPT);
@@ -2549,7 +2549,7 @@ void FileSystemDock::_file_list_rmb_select(int p_item, const Vector2 &p_pos) {
// Popup.
if (!paths.is_empty()) {
file_list_popup->clear();
- file_list_popup->set_size(Size2(1, 1));
+ file_list_popup->reset_size();
_file_and_folders_fill_popup(file_list_popup, paths, searched_string.length() == 0);
file_list_popup->set_position(files->get_global_position() + p_pos);
file_list_popup->popup();
@@ -2563,7 +2563,7 @@ void FileSystemDock::_file_list_rmb_pressed(const Vector2 &p_pos) {
}
file_list_popup->clear();
- file_list_popup->set_size(Size2(1, 1));
+ file_list_popup->reset_size();
file_list_popup->add_icon_item(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), TTR("New Folder..."), FILE_NEW_FOLDER);
file_list_popup->add_icon_item(get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")), TTR("New Scene..."), FILE_NEW_SCENE);
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
index 19b4943e6d..c34379f1ec 100644
--- a/editor/import/collada.cpp
+++ b/editor/import/collada.cpp
@@ -2024,7 +2024,7 @@ void Collada::_create_skeletons(Collada::Node **p_node, NodeSkeleton *p_skeleton
bool Collada::_remove_node(Node *p_parent, Node *p_node) {
for (int i = 0; i < p_parent->children.size(); i++) {
if (p_parent->children[i] == p_node) {
- p_parent->children.remove(i);
+ p_parent->children.remove_at(i);
return true;
}
if (_remove_node(p_parent->children[i], p_node)) {
@@ -2038,7 +2038,7 @@ bool Collada::_remove_node(Node *p_parent, Node *p_node) {
void Collada::_remove_node(VisualScene *p_vscene, Node *p_node) {
for (int i = 0; i < p_vscene->root_nodes.size(); i++) {
if (p_vscene->root_nodes[i] == p_node) {
- p_vscene->root_nodes.remove(i);
+ p_vscene->root_nodes.remove_at(i);
return;
}
if (_remove_node(p_vscene->root_nodes[i], p_node)) {
@@ -2271,7 +2271,7 @@ bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, L
for (int i = 0; i < p_node->children.size(); i++) {
if (_move_geometry_to_skeletons(p_vscene, p_node->children[i], p_mgeom)) {
- p_node->children.remove(i);
+ p_node->children.remove_at(i);
i--;
}
}
@@ -2325,7 +2325,7 @@ void Collada::_optimize() {
for (int i = 0; i < vs.root_nodes.size(); i++) {
List<Node *> mgeom;
if (_move_geometry_to_skeletons(&vs, vs.root_nodes[i], &mgeom)) {
- vs.root_nodes.remove(i);
+ vs.root_nodes.remove_at(i);
i--;
}
diff --git a/editor/import/dynamicfont_import_settings.cpp b/editor/import/dynamicfont_import_settings.cpp
index 474c9d5296..45937e20bc 100644
--- a/editor/import/dynamicfont_import_settings.cpp
+++ b/editor/import/dynamicfont_import_settings.cpp
@@ -1160,7 +1160,7 @@ void DynamicFontImportSettings::_range_update(int32_t p_start, int32_t p_end) {
void DynamicFontImportSettings::_lang_add() {
menu_langs->set_position(lang_list->get_screen_transform().xform(lang_list->get_local_mouse_position()));
- menu_langs->set_size(Vector2(1, 1));
+ menu_langs->reset_size();
menu_langs->popup();
}
@@ -1187,7 +1187,7 @@ void DynamicFontImportSettings::_lang_remove(Object *p_item, int p_column, int p
void DynamicFontImportSettings::_script_add() {
menu_scripts->set_position(script_list->get_screen_transform().xform(script_list->get_local_mouse_position()));
- menu_scripts->set_size(Vector2(1, 1));
+ menu_scripts->reset_size();
menu_scripts->popup();
}
diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp
index 3fdf5dd9db..048d84d1f9 100644
--- a/editor/import/resource_importer_texture_atlas.cpp
+++ b/editor/import/resource_importer_texture_atlas.cpp
@@ -134,7 +134,7 @@ static void _plot_triangle(Vector2i *vertices, const Vector2i &p_offset, bool p_
int max_y = MIN(y[2], height - p_offset.y - 1);
for (int yi = y[0]; yi < max_y; yi++) {
if (yi >= 0) {
- for (int xi = (xf > 0 ? int(xf) : 0); xi < (xt < src_width ? xt : src_width - 1); xi++) {
+ for (int xi = (xf > 0 ? int(xf) : 0); xi < (xt <= src_width ? xt : src_width); xi++) {
int px = xi, py = yi;
int sx = px, sy = py;
sx = CLAMP(sx, 0, src_width - 1);
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index 3fe1aa557d..5c25e6aae9 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -98,7 +98,7 @@ void LocalizationEditor::_translation_delete(Object *p_item, int p_column, int p
ERR_FAIL_INDEX(idx, translations.size());
- translations.remove(idx);
+ translations.remove_at(idx);
undo_redo->create_action(TTR("Remove Translation"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", translations);
@@ -276,7 +276,7 @@ void LocalizationEditor::_translation_res_option_delete(Object *p_item, int p_co
ERR_FAIL_COND(!remaps.has(key));
PackedStringArray r = remaps[key];
ERR_FAIL_INDEX(idx, r.size());
- r.remove(idx);
+ r.remove_at(idx);
remaps[key] = r;
undo_redo->create_action(TTR("Remove Resource Remap Option"));
@@ -321,7 +321,7 @@ void LocalizationEditor::_translation_filter_option_changed() {
}
} else {
if (l_idx != -1) {
- f_locales.remove(l_idx);
+ f_locales.remove_at(l_idx);
}
}
@@ -397,7 +397,7 @@ void LocalizationEditor::_pot_delete(Object *p_item, int p_column, int p_button)
ERR_FAIL_INDEX(idx, pot_translations.size());
- pot_translations.remove(idx);
+ pot_translations.remove_at(idx);
undo_redo->create_action(TTR("Remove file from POT generation"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", pot_translations);
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 7cafbbc1c4..58f92a98a6 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -446,7 +446,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
if (k->get_keycode() == Key::KEY_DELETE || k->get_keycode() == Key::BACKSPACE) {
if (wip_active && selected_point.polygon == -1) {
if (wip.size() > selected_point.vertex) {
- wip.remove(selected_point.vertex);
+ wip.remove_at(selected_point.vertex);
_wip_changed();
selected_point = wip.size() - 1;
canvas_item_editor->update_viewport();
@@ -599,7 +599,7 @@ void AbstractPolygon2DEditor::remove_point(const Vertex &p_vertex) {
Vector<Vector2> vertices = _get_polygon(p_vertex.polygon);
if (vertices.size() > (_is_line() ? 2 : 3)) {
- vertices.remove(p_vertex.vertex);
+ vertices.remove_at(p_vertex.vertex);
undo_redo->create_action(TTR("Edit Polygon (Remove Point)"));
_action_set_polygon(p_vertex.polygon, vertices);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 55ffbf9477..75d2bed1b2 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -58,7 +58,7 @@ void AnimationNodeBlendTreeEditor::add_custom_type(const String &p_name, const R
void AnimationNodeBlendTreeEditor::remove_custom_type(const Ref<Script> &p_script) {
for (int i = 0; i < add_options.size(); i++) {
if (add_options[i].script == p_script) {
- add_options.remove(i);
+ add_options.remove_at(i);
return;
}
}
@@ -68,7 +68,7 @@ void AnimationNodeBlendTreeEditor::remove_custom_type(const Ref<Script> &p_scrip
void AnimationNodeBlendTreeEditor::_update_options_menu(bool p_has_input_ports) {
add_node->get_popup()->clear();
- add_node->get_popup()->set_size(Size2i(-1, -1));
+ add_node->get_popup()->reset_size();
for (int i = 0; i < add_options.size(); i++) {
if (p_has_input_ports && add_options[i].input_port_count == 0) {
continue;
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 02756916a5..a3378d1550 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -242,7 +242,7 @@ bool CanvasItemEditor::_is_node_movable(const Node *p_node, bool p_popup_warning
}
if (Object::cast_to<Control>(p_node) && Object::cast_to<Container>(p_node->get_parent())) {
if (p_popup_warning) {
- _popup_warning_temporarily(warning_child_of_container, 3.0);
+ EditorToaster::get_singleton()->popup_str("Children of a container get their position and size determined only by their parent.", EditorToaster::SEVERITY_WARNING);
}
return false;
}
@@ -658,7 +658,7 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel
//Remove the item if invalid
if (!canvas_item || duplicate || (canvas_item != scene && canvas_item->get_owner() != scene && !scene->is_editable_instance(canvas_item->get_owner())) || (!p_allow_locked && _is_node_locked(canvas_item))) {
- r_items.remove(i);
+ r_items.remove_at(i);
i--;
} else {
r_items.write[i].item = canvas_item;
@@ -877,7 +877,7 @@ void CanvasItemEditor::_selection_result_pressed(int p_result) {
void CanvasItemEditor::_selection_menu_hide() {
selection_results.clear();
selection_menu->clear();
- selection_menu->set_size(Vector2(0, 0));
+ selection_menu->reset_size();
}
void CanvasItemEditor::_add_node_pressed(int p_result) {
@@ -1045,7 +1045,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
} else {
if (dragged_guide_index >= 0) {
- vguides.remove(dragged_guide_index);
+ vguides.remove_at(dragged_guide_index);
undo_redo->create_action(TTR("Remove Vertical Guide"));
if (vguides.is_empty()) {
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "remove_meta", "_edit_vertical_guides_");
@@ -1078,7 +1078,7 @@ bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_eve
}
} else {
if (dragged_guide_index >= 0) {
- hguides.remove(dragged_guide_index);
+ hguides.remove_at(dragged_guide_index);
undo_redo->create_action(TTR("Remove Horizontal Guide"));
if (hguides.is_empty()) {
undo_redo->add_do_method(EditorNode::get_singleton()->get_edited_scene(), "remove_meta", "_edit_horizontal_guides_");
@@ -2265,7 +2265,7 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
if (b.is_valid() && b->is_pressed() && b->get_button_index() == MouseButton::RIGHT) {
- add_node_menu->set_size(Vector2(1, 1));
+ add_node_menu->reset_size();
add_node_menu->set_position(get_screen_position() + b->get_position());
add_node_menu->popup();
node_create_position = transform.affine_inverse().xform((get_local_mouse_position()));
@@ -3665,8 +3665,6 @@ void CanvasItemEditor::_draw_viewport() {
group_button->set_disabled(selection.is_empty());
ungroup_button->set_visible(all_group);
- info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
-
_draw_grid();
_draw_ruler_tool();
_draw_axis();
@@ -3919,11 +3917,6 @@ void CanvasItemEditor::_notification(int p_what) {
anchors_popup->add_icon_item(get_theme_icon(SNAME("ControlAlignWide"), SNAME("EditorIcons")), TTR("Full Rect"), ANCHORS_PRESET_WIDE);
anchor_mode_button->set_icon(get_theme_icon(SNAME("Anchor"), SNAME("EditorIcons")));
-
- info_overlay->get_theme()->set_stylebox("normal", "Label", get_theme_stylebox(SNAME("CanvasItemInfoOverlay"), SNAME("EditorStyles")));
- warning_child_of_container->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
- warning_child_of_container->add_theme_font_override("font", get_theme_font(SNAME("main"), SNAME("EditorFonts")));
- warning_child_of_container->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("main_size"), SNAME("EditorFonts")));
}
if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
@@ -4079,34 +4072,6 @@ void CanvasItemEditor::_update_scrollbars() {
updating_scroll = false;
}
-void CanvasItemEditor::_popup_warning_depop(Control *p_control) {
- ERR_FAIL_COND(!popup_temporarily_timers.has(p_control));
-
- Timer *timer = popup_temporarily_timers[p_control];
- timer->queue_delete();
- p_control->hide();
- popup_temporarily_timers.erase(p_control);
- info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
-}
-
-void CanvasItemEditor::_popup_warning_temporarily(Control *p_control, const double p_duration) {
- Timer *timer;
- if (!popup_temporarily_timers.has(p_control)) {
- timer = memnew(Timer);
- timer->connect("timeout", callable_mp(this, &CanvasItemEditor::_popup_warning_depop), varray(p_control));
- timer->set_one_shot(true);
- add_child(timer);
-
- popup_temporarily_timers[p_control] = timer;
- } else {
- timer = popup_temporarily_timers[p_control];
- }
-
- timer->start(p_duration);
- p_control->show();
- info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
-}
-
void CanvasItemEditor::_update_scroll(real_t) {
if (updating_scroll) {
return;
@@ -5136,19 +5101,6 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
viewport->update();
}
-void CanvasItemEditor::add_control_to_info_overlay(Control *p_control) {
- ERR_FAIL_COND(!p_control);
-
- p_control->set_h_size_flags(p_control->get_h_size_flags() & ~Control::SIZE_EXPAND_FILL);
- info_overlay->add_child(p_control);
- info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
-}
-
-void CanvasItemEditor::remove_control_from_info_overlay(Control *p_control) {
- info_overlay->remove_child(p_control);
- info_overlay->set_offset(SIDE_LEFT, (show_rulers ? RULER_WIDTH : 0) + 10);
-}
-
void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
ERR_FAIL_COND(!p_control);
@@ -5281,23 +5233,6 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
viewport->connect("draw", callable_mp(this, &CanvasItemEditor::_draw_viewport));
viewport->connect("gui_input", callable_mp(this, &CanvasItemEditor::_gui_input_viewport));
- info_overlay = memnew(VBoxContainer);
- info_overlay->set_anchors_and_offsets_preset(Control::PRESET_BOTTOM_LEFT);
- info_overlay->set_offset(SIDE_LEFT, 10);
- info_overlay->set_offset(SIDE_BOTTOM, -15);
- info_overlay->set_v_grow_direction(Control::GROW_DIRECTION_BEGIN);
- info_overlay->add_theme_constant_override("separation", 10);
- viewport_scrollable->add_child(info_overlay);
-
- // Make sure all labels inside of the container are styled the same.
- Theme *info_overlay_theme = memnew(Theme);
- info_overlay->set_theme(info_overlay_theme);
-
- warning_child_of_container = memnew(Label);
- warning_child_of_container->hide();
- warning_child_of_container->set_text(TTR("Warning: Children of a container get their position and size determined only by their parent."));
- add_control_to_info_overlay(warning_child_of_container);
-
h_scroll = memnew(HScrollBar);
viewport->add_child(h_scroll);
h_scroll->connect("value_changed", callable_mp(this, &CanvasItemEditor::_update_scroll));
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 286771ee08..b6576b7144 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -235,11 +235,6 @@ private:
PanelContainer *context_menu_container;
HBoxContainer *hbc_context_menu;
- Map<Control *, Timer *> popup_temporarily_timers;
-
- Label *warning_child_of_container;
- VBoxContainer *info_overlay;
-
Transform2D transform;
bool show_grid;
bool show_rulers;
@@ -536,8 +531,6 @@ private:
VSplitContainer *bottom_split;
void _update_context_menu_stylebox();
- void _popup_warning_temporarily(Control *p_control, const double p_duration);
- void _popup_warning_depop(Control *p_control);
void _set_owner_for_node_and_children(Node *p_node, Node *p_owner);
@@ -578,9 +571,6 @@ public:
void add_control_to_menu_panel(Control *p_control);
void remove_control_from_menu_panel(Control *p_control);
- void add_control_to_info_overlay(Control *p_control);
- void remove_control_from_info_overlay(Control *p_control);
-
HSplitContainer *get_palette_split();
VSplitContainer *get_bottom_split();
diff --git a/editor/plugins/collision_polygon_3d_editor_plugin.cpp b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
index 7a8680c4dd..4c728ff757 100644
--- a/editor/plugins/collision_polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/collision_polygon_3d_editor_plugin.cpp
@@ -285,7 +285,7 @@ EditorPlugin::AfterGUIInput CollisionPolygon3DEditor::forward_spatial_gui_input(
if (closest_idx >= 0) {
undo_redo->create_action(TTR("Edit Poly (Remove Point)"));
undo_redo->add_undo_method(node, "set_polygon", poly);
- poly.remove(closest_idx);
+ poly.remove_at(closest_idx);
undo_redo->add_do_method(node, "set_polygon", poly);
undo_redo->add_do_method(this, "_polygon_draw");
undo_redo->add_undo_method(this, "_polygon_draw");
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 005cf27e8a..daf34903e6 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -383,7 +383,7 @@ void CurveEditor::open_context_menu(Vector2 pos) {
_context_menu->add_submenu_item(TTR("Load Preset"), _presets_menu->get_name());
- _context_menu->set_size(Size2(0, 0));
+ _context_menu->reset_size();
_context_menu->popup();
}
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index b74d229d3e..d3b462cda5 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -860,7 +860,7 @@ void Node3DEditorViewport::_update_name() {
}
view_menu->set_text(name);
- view_menu->set_size(Vector2(0, 0)); // resets the button size
+ view_menu->reset_size();
}
void Node3DEditorViewport::_compute_edit(const Point2 &p_point) {
@@ -1238,7 +1238,7 @@ void Node3DEditorViewport::_list_select(Ref<InputEventMouseButton> b) {
Node3D *item = selection_results[i].item;
if (item != scene && item->get_owner() != scene && item != scene->get_deepest_editable_node(item)) {
//invalid result
- selection_results.remove(i);
+ selection_results.remove_at(i);
i--;
}
}
@@ -3620,7 +3620,7 @@ void Node3DEditorViewport::_selection_result_pressed(int p_result) {
void Node3DEditorViewport::_selection_menu_hide() {
selection_results.clear();
selection_menu->clear();
- selection_menu->set_size(Vector2(0, 0));
+ selection_menu->reset_size();
}
void Node3DEditorViewport::set_can_preview(Camera3D *p_preview) {
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 6ffe99d4d0..79cfcbec64 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -584,10 +584,10 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
return;
}
- uv_create_poly_prev.remove(closest);
- uv_create_uv_prev.remove(closest);
+ uv_create_poly_prev.remove_at(closest);
+ uv_create_uv_prev.remove_at(closest);
if (uv_create_colors_prev.size()) {
- uv_create_colors_prev.remove(closest);
+ uv_create_colors_prev.remove_at(closest);
}
undo_redo->create_action(TTR("Remove Internal Vertex"));
@@ -599,7 +599,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
undo_redo->add_undo_method(node, "set_vertex_colors", node->get_vertex_colors());
for (int i = 0; i < node->get_bone_count(); i++) {
Vector<float> bonew = node->get_bone_weights(i);
- bonew.remove(closest);
+ bonew.remove_at(closest);
undo_redo->add_do_method(node, "set_bone_weights", i, bonew);
undo_redo->add_undo_method(node, "set_bone_weights", i, node->get_bone_weights(i));
}
@@ -702,7 +702,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
}
if (erase_index != -1) {
- polygons.remove(erase_index);
+ polygons.remove_at(erase_index);
undo_redo->create_action(TTR("Remove Custom Polygon"));
undo_redo->add_do_method(node, "set_polygons", polygons);
undo_redo->add_undo_method(node, "set_polygons", node->get_polygons());
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index e87d31f018..aeb6ba13d5 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -733,7 +733,7 @@ void ScriptEditor::_open_recent_script(int p_idx) {
return;
}
- rc.remove(p_idx);
+ rc.remove_at(p_idx);
EditorSettings::get_singleton()->set_project_metadata("recent_files", "scripts", rc);
_update_recent_scripts();
_show_error_dialog(path);
@@ -785,7 +785,7 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
for (int i = 0; i < history.size(); i++) {
if (history[i].control == tselected) {
- history.remove(i);
+ history.remove_at(i);
i--;
history_pos--;
}
@@ -1415,8 +1415,12 @@ void ScriptEditor::_menu_option(int p_option) {
} break;
case SHOW_IN_FILE_SYSTEM: {
const RES script = current->get_edited_resource();
- const String path = script->get_path();
+ String path = script->get_path();
if (!path.is_empty()) {
+ if (script->is_built_in()) {
+ path = path.get_slice("::", 0); // Show the scene instead.
+ }
+
FileSystemDock *file_system_dock = EditorNode::get_singleton()->get_filesystem_dock();
file_system_dock->navigate_to_path(path);
// Ensure that the FileSystem dock is visible.
@@ -3052,7 +3056,7 @@ void ScriptEditor::_make_script_list_context_menu() {
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/toggle_scripts_panel"), TOGGLE_SCRIPTS_PANEL);
context_menu->set_position(get_global_transform().xform(get_local_mouse_position()));
- context_menu->set_size(Vector2(1, 1));
+ context_menu->reset_size();
context_menu->popup();
}
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 93adced59d..30a4cef8ca 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -550,7 +550,7 @@ void ScriptTextEditor::_validate_script() {
void ScriptTextEditor::_update_bookmark_list() {
bookmarks_menu->clear();
- bookmarks_menu->set_size(Size2(1, 1));
+ bookmarks_menu->reset_size();
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE);
bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_bookmarks"), BOOKMARK_REMOVE_ALL);
@@ -702,7 +702,7 @@ void ScriptTextEditor::_code_complete_script(const String &p_code, List<ScriptCo
void ScriptTextEditor::_update_breakpoint_list() {
breakpoints_menu->clear();
- breakpoints_menu->set_size(Size2(1, 1));
+ breakpoints_menu->reset_size();
breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_breakpoint"), DEBUG_TOGGLE_BREAKPOINT);
breakpoints_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_breakpoints"), DEBUG_REMOVE_ALL_BREAKPOINTS);
@@ -1689,7 +1689,7 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p
context_menu->set_item_disabled(context_menu->get_item_index(EDIT_REDO), !tx->has_redo());
context_menu->set_position(get_global_transform().xform(p_pos));
- context_menu->set_size(Vector2(1, 1));
+ context_menu->reset_size();
context_menu->popup();
}
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 6032267717..7c1fda77bb 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -646,7 +646,7 @@ void ShaderEditor::_make_context_menu(bool p_selection, Vector2 p_position) {
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE);
context_menu->set_position(get_global_transform().xform(p_position));
- context_menu->set_size(Vector2(1, 1));
+ context_menu->reset_size();
context_menu->popup();
}
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index ebfe6c9ee3..e252792c43 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -508,7 +508,7 @@ void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is
context_menu->set_item_disabled(context_menu->get_item_index(EDIT_REDO), !tx->has_redo());
context_menu->set_position(get_global_transform().xform(p_position));
- context_menu->set_size(Vector2(1, 1));
+ context_menu->reset_size();
context_menu->popup();
}
diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp
index df0b35908b..f13fcb005f 100644
--- a/editor/plugins/theme_editor_preview.cpp
+++ b/editor/plugins/theme_editor_preview.cpp
@@ -71,6 +71,9 @@ void ThemeEditorPreview::_preview_visibility_changed() {
void ThemeEditorPreview::_picker_button_cbk() {
picker_overlay->set_visible(picker_button->is_pressed());
+ if (picker_button->is_pressed()) {
+ _reset_picker_overlay();
+ }
}
Control *ThemeEditorPreview::_find_hovered_control(Control *p_parent, Vector2 p_mouse_position) {
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index d165f44334..44cf6b42bc 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -516,7 +516,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
_grab_polygon_point(mb->get_position(), xform, closest_polygon, closest_point);
if (closest_polygon >= 0) {
PackedVector2Array old_polygon = polygons[closest_polygon];
- polygons[closest_polygon].remove(closest_point);
+ polygons[closest_polygon].remove_at(closest_point);
undo_redo->create_action(TTR("Edit Polygons"));
if (polygons[closest_polygon].size() < 3) {
remove_polygon(closest_polygon);
@@ -563,7 +563,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
_grab_polygon_point(mb->get_position(), xform, closest_polygon, closest_point);
if (closest_polygon >= 0) {
PackedVector2Array old_polygon = polygons[closest_polygon];
- polygons[closest_polygon].remove(closest_point);
+ polygons[closest_polygon].remove_at(closest_point);
undo_redo->create_action(TTR("Edit Polygons"));
if (polygons[closest_polygon].size() < 3) {
remove_polygon(closest_polygon);
@@ -676,7 +676,7 @@ int GenericTilePolygonEditor::add_polygon(Vector<Point2> p_polygon, int p_index)
void GenericTilePolygonEditor::remove_polygon(int p_index) {
ERR_FAIL_INDEX(p_index, (int)polygons.size());
- polygons.remove(p_index);
+ polygons.remove_at(p_index);
if (polygons.size() == 0) {
button_create->set_pressed(true);
diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
index 9e47a44b34..60a66ab954 100644
--- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
+++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
@@ -34,7 +34,7 @@
void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, Object *p_item_list) {
ItemList *item_list = Object::cast_to<ItemList>(p_item_list);
- popup_menu->set_size(Vector2(1, 1));
+ popup_menu->reset_size();
popup_menu->set_position(get_position() + item_list->get_global_mouse_position());
popup_menu->popup();
}
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index b97095ef39..28352d25eb 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -49,6 +49,11 @@ void VersionControlEditorPlugin::_bind_methods() {
BIND_ENUM_CONSTANT(CHANGE_TYPE_TYPECHANGE);
}
+void VersionControlEditorPlugin::_create_vcs_metadata_files() {
+ String dir = "res://";
+ EditorVCSInterface::create_vcs_metadata_files(EditorVCSInterface::VCSMetadata(metadata_selection->get_selected()), dir);
+}
+
void VersionControlEditorPlugin::_selected_a_vcs(int p_id) {
List<StringName> available_addons = get_available_vcs_names();
const StringName selected_vcs = set_up_choice->get_item_text(p_id);
@@ -71,6 +76,10 @@ VersionControlEditorPlugin *VersionControlEditorPlugin::get_singleton() {
return singleton ? singleton : memnew(VersionControlEditorPlugin);
}
+void VersionControlEditorPlugin::popup_vcs_metadata_dialog() {
+ metadata_dialog->popup_centered();
+}
+
void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_base) {
fetch_available_vcs_addon_names();
List<StringName> available_addons = get_available_vcs_names();
@@ -374,6 +383,30 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
version_control_actions = memnew(PopupMenu);
+ metadata_dialog = memnew(ConfirmationDialog);
+ metadata_dialog->set_title(TTR("Create Version Control Metadata"));
+ metadata_dialog->set_min_size(Size2(200, 40));
+ version_control_actions->add_child(metadata_dialog);
+
+ VBoxContainer *metadata_vb = memnew(VBoxContainer);
+ HBoxContainer *metadata_hb = memnew(HBoxContainer);
+ metadata_hb->set_custom_minimum_size(Size2(200, 20));
+ Label *l = memnew(Label);
+ l->set_text(TTR("Create VCS metadata files for:"));
+ metadata_hb->add_child(l);
+ metadata_selection = memnew(OptionButton);
+ metadata_selection->set_custom_minimum_size(Size2(100, 20));
+ metadata_selection->add_item("None", (int)EditorVCSInterface::VCSMetadata::NONE);
+ metadata_selection->add_item("Git", (int)EditorVCSInterface::VCSMetadata::GIT);
+ metadata_selection->select((int)EditorVCSInterface::VCSMetadata::GIT);
+ metadata_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VersionControlEditorPlugin::_create_vcs_metadata_files));
+ metadata_hb->add_child(metadata_selection);
+ metadata_vb->add_child(metadata_hb);
+ l = memnew(Label);
+ l->set_text(TTR("Existing VCS metadata files will be overwritten."));
+ metadata_vb->add_child(l);
+ metadata_dialog->add_child(metadata_vb);
+
set_up_dialog = memnew(AcceptDialog);
set_up_dialog->set_title(TTR("Set Up Version Control"));
set_up_dialog->set_min_size(Size2(400, 100));
diff --git a/editor/plugins/version_control_editor_plugin.h b/editor/plugins/version_control_editor_plugin.h
index d2ba63c86c..2782c1d9dc 100644
--- a/editor/plugins/version_control_editor_plugin.h
+++ b/editor/plugins/version_control_editor_plugin.h
@@ -57,6 +57,8 @@ private:
List<StringName> available_addons;
PopupMenu *version_control_actions;
+ ConfirmationDialog *metadata_dialog;
+ OptionButton *metadata_selection;
AcceptDialog *set_up_dialog;
VBoxContainer *set_up_vbc;
HBoxContainer *set_up_hbc;
@@ -98,6 +100,7 @@ private:
RichTextLabel *diff;
void _populate_available_vcs_names();
+ void _create_vcs_metadata_files();
void _selected_a_vcs(int p_id);
void _initialize_vcs();
void _send_commit_msg();
@@ -121,6 +124,7 @@ protected:
public:
static VersionControlEditorPlugin *get_singleton();
+ void popup_vcs_metadata_dialog();
void popup_vcs_set_up_dialog(const Control *p_gui_base);
void set_version_control_tool_button(Button *p_button) { version_control_dock_button = p_button; }
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index a4706bf0d9..da73fc093c 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -132,7 +132,7 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p
if (links[p_node_id].preview_visible && !is_dirty() && links[p_node_id].preview_box != nullptr) {
links[p_node_id].graph_node->remove_child(links[p_node_id].preview_box);
memdelete(links[p_node_id].preview_box);
- links[p_node_id].graph_node->set_size(Vector2(-1, -1));
+ links[p_node_id].graph_node->reset_size();
links[p_node_id].preview_visible = false;
}
@@ -256,7 +256,7 @@ void VisualShaderGraphPlugin::update_node_size(int p_node_id) {
if (!links.has(p_node_id)) {
return;
}
- links[p_node_id].graph_node->set_size(Size2(-1, -1));
+ links[p_node_id].graph_node->reset_size();
}
void VisualShaderGraphPlugin::register_default_input_button(int p_node_id, int p_port_id, Button *p_button) {
@@ -1061,7 +1061,7 @@ void VisualShaderEditor::remove_plugin(const Ref<VisualShaderNodePlugin> &p_plug
void VisualShaderEditor::clear_custom_types() {
for (int i = 0; i < add_options.size(); i++) {
if (add_options[i].is_custom) {
- add_options.remove(i);
+ add_options.remove_at(i);
i--;
}
}
@@ -1976,7 +1976,7 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p
}
gn->set_custom_minimum_size(size);
- gn->set_size(Size2(1, 1));
+ gn->reset_size();
if (!expression_node.is_null() && text_box) {
Size2 box_size = size;
@@ -1990,7 +1990,7 @@ void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p
box_size.y -= text_box->get_offset(SIDE_TOP);
box_size.y -= 28 * EDSCALE;
text_box->set_custom_minimum_size(box_size);
- text_box->set_size(Size2(1, 1));
+ text_box->reset_size();
}
}
}
@@ -2038,8 +2038,8 @@ void VisualShaderEditor::_comment_title_popup_show(const Point2 &p_position, int
}
void VisualShaderEditor::_comment_title_text_changed(const String &p_new_text) {
- comment_title_change_edit->set_size(Size2(-1, -1));
- comment_title_change_popup->set_size(Size2(-1, -1));
+ comment_title_change_edit->reset_size();
+ comment_title_change_popup->reset_size();
}
void VisualShaderEditor::_comment_title_text_submitted(const String &p_new_text) {
@@ -2083,8 +2083,8 @@ void VisualShaderEditor::_comment_desc_popup_show(const Point2 &p_position, int
}
void VisualShaderEditor::_comment_desc_text_changed() {
- comment_desc_change_edit->set_size(Size2(-1, -1));
- comment_desc_change_popup->set_size(Size2(-1, -1));
+ comment_desc_change_edit->reset_size();
+ comment_desc_change_popup->reset_size();
}
void VisualShaderEditor::_comment_desc_confirm() {
@@ -3167,7 +3167,7 @@ void VisualShaderEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {
menu_point = graph->get_local_mouse_position();
Point2 gpos = Input::get_singleton()->get_mouse_position();
popup_menu->set_position(gpos);
- popup_menu->set_size(Size2(-1, -1));
+ popup_menu->reset_size();
popup_menu->popup();
}
}
@@ -4258,8 +4258,8 @@ VisualShaderEditor::VisualShaderEditor() {
comment_title_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_title_text_changed));
comment_title_change_edit->connect("text_submitted", callable_mp(this, &VisualShaderEditor::_comment_title_text_submitted));
comment_title_change_popup->add_child(comment_title_change_edit);
- comment_title_change_edit->set_size(Size2(-1, -1));
- comment_title_change_popup->set_size(Size2(-1, -1));
+ comment_title_change_edit->reset_size();
+ comment_title_change_popup->reset_size();
comment_title_change_popup->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_comment_title_popup_focus_out));
comment_title_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_comment_title_popup_hide));
add_child(comment_title_change_popup);
@@ -4271,8 +4271,8 @@ VisualShaderEditor::VisualShaderEditor() {
comment_desc_change_edit->connect("text_changed", callable_mp(this, &VisualShaderEditor::_comment_desc_text_changed));
comment_desc_vbox->add_child(comment_desc_change_edit);
comment_desc_change_edit->set_custom_minimum_size(Size2(300 * EDSCALE, 150 * EDSCALE));
- comment_desc_change_edit->set_size(Size2(-1, -1));
- comment_desc_change_popup->set_size(Size2(-1, -1));
+ comment_desc_change_edit->reset_size();
+ comment_desc_change_popup->reset_size();
comment_desc_change_popup->connect("focus_exited", callable_mp(this, &VisualShaderEditor::_comment_desc_confirm));
comment_desc_change_popup->connect("popup_hide", callable_mp(this, &VisualShaderEditor::_comment_desc_popup_hide));
Button *comment_desc_confirm_button = memnew(Button);
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 7b942adb54..372a77f67d 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -41,6 +41,7 @@
#include "core/string/translation.h"
#include "core/version.h"
#include "core/version_hash.gen.h"
+#include "editor/editor_vcs_interface.h"
#include "editor_scale.h"
#include "editor_settings.h"
#include "editor_themes.h"
@@ -67,19 +68,19 @@ public:
MODE_NEW,
MODE_IMPORT,
MODE_INSTALL,
- MODE_RENAME
+ MODE_RENAME,
};
private:
enum MessageType {
MESSAGE_ERROR,
MESSAGE_WARNING,
- MESSAGE_SUCCESS
+ MESSAGE_SUCCESS,
};
enum InputType {
PROJECT_PATH,
- INSTALL_PATH
+ INSTALL_PATH,
};
Mode mode;
@@ -90,6 +91,7 @@ private:
Container *path_container;
Container *install_path_container;
Container *rasterizer_container;
+ HBoxContainer *default_files_container;
Ref<ButtonGroup> rasterizer_button_group;
Label *msg;
LineEdit *project_path;
@@ -99,6 +101,8 @@ private:
TextureRect *install_status_rect;
FileDialog *fdialog;
FileDialog *fdialog_install;
+ OptionButton *vcs_metadata_selection;
+ CheckBox *create_default_environment;
String zip_path;
String zip_title;
AcceptDialog *dialog_error;
@@ -474,32 +478,50 @@ private:
cd->grab_focus();
return;
}
+ PackedStringArray project_features = ProjectSettings::get_required_features();
ProjectSettings::CustomMap initial_settings;
- initial_settings["rendering/vulkan/rendering/back_end"] = rasterizer_button_group->get_pressed_button()->get_meta(SNAME("driver_name"));
+ // Be sure to change this code if/when renderers are changed.
+ int renderer_type = rasterizer_button_group->get_pressed_button()->get_meta(SNAME("driver_name"));
+ initial_settings["rendering/vulkan/rendering/back_end"] = renderer_type;
+ if (renderer_type == 0) {
+ project_features.push_back("Vulkan Clustered");
+ } else if (renderer_type == 1) {
+ project_features.push_back("Vulkan Mobile");
+ } else {
+ WARN_PRINT("Unknown renderer type. Please report this as a bug on GitHub.");
+ }
+ project_features.sort();
+ initial_settings["application/config/features"] = project_features;
initial_settings["application/config/name"] = project_name->get_text().strip_edges();
initial_settings["application/config/icon"] = "res://icon.png";
- initial_settings["rendering/environment/defaults/default_environment"] = "res://default_env.tres";
+
+ if (create_default_environment->is_pressed()) {
+ initial_settings["rendering/environment/defaults/default_environment"] = "res://default_env.tres";
+ }
if (ProjectSettings::get_singleton()->save_custom(dir.plus_file("project.godot"), initial_settings, Vector<String>(), false) != OK) {
set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR);
} else {
ResourceSaver::save(dir.plus_file("icon.png"), create_unscaled_default_project_icon());
-
- FileAccess *f = FileAccess::open(dir.plus_file("default_env.tres"), FileAccess::WRITE);
- if (!f) {
- set_message(TTR("Couldn't create project.godot in project path."), MESSAGE_ERROR);
- } else {
- f->store_line("[gd_resource type=\"Environment\" load_steps=2 format=3]");
- f->store_line("");
- f->store_line("[sub_resource type=\"Sky\" id=\"1\"]");
- f->store_line("");
- f->store_line("[resource]");
- f->store_line("background_mode = 2");
- f->store_line("sky = SubResource( \"1\" )");
- memdelete(f);
+ FileAccess *f;
+ if (create_default_environment->is_pressed()) {
+ f = FileAccess::open(dir.plus_file("default_env.tres"), FileAccess::WRITE);
+ if (!f) {
+ set_message(TTR("Couldn't create default_env.tres in project path."), MESSAGE_ERROR);
+ } else {
+ f->store_line("[gd_resource type=\"Environment\" load_steps=2 format=2]");
+ f->store_line("");
+ f->store_line("[sub_resource type=\"Sky\" id=\"1\"]");
+ f->store_line("");
+ f->store_line("[resource]");
+ f->store_line("background_mode = 2");
+ f->store_line("sky = SubResource( \"1\" )");
+ memdelete(f);
+ }
}
- }
+ EditorVCSInterface::create_vcs_metadata_files(EditorVCSInterface::VCSMetadata(vcs_metadata_selection->get_selected()), dir);
+ }
} else if (mode == MODE_INSTALL) {
if (project_path->get_text().ends_with(".zip")) {
dir = install_path->get_text();
@@ -694,6 +716,7 @@ public:
install_path_container->hide();
install_status_rect->hide();
rasterizer_container->hide();
+ default_files_container->hide();
get_ok_button()->set_disabled(false);
ProjectSettings *current = memnew(ProjectSettings);
@@ -745,6 +768,7 @@ public:
name_container->hide();
install_path_container->hide();
rasterizer_container->hide();
+ default_files_container->hide();
project_path->grab_focus();
} else if (mode == MODE_NEW) {
@@ -753,6 +777,7 @@ public:
name_container->show();
install_path_container->hide();
rasterizer_container->show();
+ default_files_container->show();
project_name->call_deferred(SNAME("grab_focus"));
project_name->call_deferred(SNAME("select_all"));
@@ -763,6 +788,7 @@ public:
name_container->show();
install_path_container->hide();
rasterizer_container->hide();
+ default_files_container->hide();
project_path->grab_focus();
}
@@ -905,6 +931,25 @@ public:
l->set_modulate(Color(1, 1, 1, 0.7));
rasterizer_container->add_child(l);
+ default_files_container = memnew(HBoxContainer);
+ vb->add_child(default_files_container);
+ l = memnew(Label);
+ l->set_text(TTR("Version Control Metadata:"));
+ default_files_container->add_child(l);
+ vcs_metadata_selection = memnew(OptionButton);
+ vcs_metadata_selection->set_custom_minimum_size(Size2(100, 20));
+ vcs_metadata_selection->add_item("None", (int)EditorVCSInterface::VCSMetadata::NONE);
+ vcs_metadata_selection->add_item("Git", (int)EditorVCSInterface::VCSMetadata::GIT);
+ vcs_metadata_selection->select((int)EditorVCSInterface::VCSMetadata::GIT);
+ default_files_container->add_child(vcs_metadata_selection);
+ Control *spacer = memnew(Control);
+ spacer->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ default_files_container->add_child(spacer);
+ create_default_environment = memnew(CheckBox);
+ create_default_environment->set_text("Create Default Environment");
+ create_default_environment->set_pressed(true);
+ default_files_container->add_child(create_default_environment);
+
fdialog = memnew(FileDialog);
fdialog->set_access(FileDialog::ACCESS_FILESYSTEM);
fdialog_install = memnew(FileDialog);
@@ -986,6 +1031,7 @@ public:
String path;
String icon;
String main_scene;
+ PackedStringArray unsupported_features;
uint64_t last_edited = 0;
bool favorite = false;
bool grayed = false;
@@ -1002,6 +1048,7 @@ public:
const String &p_path,
const String &p_icon,
const String &p_main_scene,
+ const PackedStringArray &p_unsupported_features,
uint64_t p_last_edited,
bool p_favorite,
bool p_grayed,
@@ -1013,6 +1060,7 @@ public:
path = p_path;
icon = p_icon;
main_scene = p_main_scene;
+ unsupported_features = p_unsupported_features;
last_edited = p_last_edited;
favorite = p_favorite;
grayed = p_grayed;
@@ -1064,8 +1112,7 @@ private:
void remove_project(int p_index, bool p_update_settings);
void update_icons_async();
void load_project_icon(int p_index);
-
- static void load_project_data(const String &p_property_key, Item &p_item, bool p_favorite);
+ static Item load_project_data(const String &p_property_key, bool p_favorite);
String _search_term;
FilterOption _order_option;
@@ -1156,7 +1203,8 @@ void ProjectList::load_project_icon(int p_index) {
item.control->icon_needs_reload = false;
}
-void ProjectList::load_project_data(const String &p_property_key, Item &p_item, bool p_favorite) {
+// Load project data from p_property_key and return it in a ProjectList::Item. p_favorite is passed directly into the Item.
+ProjectList::Item ProjectList::load_project_data(const String &p_property_key, bool p_favorite) {
String path = EditorSettings::get_singleton()->get(p_property_key);
String conf = path.plus_file("project.godot");
bool grayed = false;
@@ -1176,13 +1224,16 @@ void ProjectList::load_project_data(const String &p_property_key, Item &p_item,
}
if (config_version > ProjectSettings::CONFIG_VERSION) {
- // Comes from an incompatible (more recent) Godot version, grey it out
+ // Comes from an incompatible (more recent) Godot version, gray it out.
grayed = true;
}
- String description = cf->get_value("application", "config/description", "");
- String icon = cf->get_value("application", "config/icon", "");
- String main_scene = cf->get_value("application", "run/main_scene", "");
+ const String description = cf->get_value("application", "config/description", "");
+ const String icon = cf->get_value("application", "config/icon", "");
+ const String main_scene = cf->get_value("application", "run/main_scene", "");
+
+ PackedStringArray project_features = cf->get_value("application", "config/features", PackedStringArray());
+ PackedStringArray unsupported_features = ProjectSettings::get_unsupported_features(project_features);
uint64_t last_edited = 0;
if (FileAccess::exists(conf)) {
@@ -1204,9 +1255,9 @@ void ProjectList::load_project_data(const String &p_property_key, Item &p_item,
print_line("Project is missing: " + conf);
}
- String project_key = p_property_key.get_slice("/", 1);
+ const String project_key = p_property_key.get_slice("/", 1);
- p_item = Item(project_key, project_name, description, path, icon, main_scene, last_edited, p_favorite, grayed, missing, config_version);
+ return Item(project_key, project_name, description, path, icon, main_scene, unsupported_features, last_edited, p_favorite, grayed, missing, config_version);
}
void ProjectList::load_projects() {
@@ -1249,8 +1300,7 @@ void ProjectList::load_projects() {
String project_key = property_key.get_slice("/", 1);
bool favorite = favorites.has("favorite_projects/" + project_key);
- Item item;
- load_project_data(property_key, item, favorite);
+ Item item = load_project_data(property_key, favorite);
_projects.push_back(item);
}
@@ -1333,7 +1383,7 @@ void ProjectList::create_project_item_control(int p_index) {
TextureButton *favorite = memnew(TextureButton);
favorite->set_name("FavoriteButton");
favorite->set_normal_texture(favorite_icon);
- // This makes the project's "hover" style display correctly when hovering the favorite icon
+ // This makes the project's "hover" style display correctly when hovering the favorite icon.
favorite->set_mouse_filter(MOUSE_FILTER_PASS);
favorite->connect("pressed", callable_mp(this, &ProjectList::_favorite_pressed), varray(hb));
favorite_box->add_child(favorite);
@@ -1363,40 +1413,65 @@ void ProjectList::create_project_item_control(int p_index) {
ec->set_custom_minimum_size(Size2(0, 1));
ec->set_mouse_filter(MOUSE_FILTER_PASS);
vb->add_child(ec);
- Label *title = memnew(Label(!item.missing ? item.project_name : TTR("Missing Project")));
- title->add_theme_font_override("font", get_theme_font(SNAME("title"), SNAME("EditorFonts")));
- title->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("title_size"), SNAME("EditorFonts")));
- title->add_theme_color_override("font_color", font_color);
- title->set_clip_text(true);
- vb->add_child(title);
-
- HBoxContainer *path_hb = memnew(HBoxContainer);
- path_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- vb->add_child(path_hb);
-
- Button *show = memnew(Button);
- // Display a folder icon if the project directory can be opened, or a "broken file" icon if it can't.
- show->set_icon(get_theme_icon(!item.missing ? "Load" : "FileBroken", "EditorIcons"));
- if (!item.grayed) {
- // Don't make the icon less prominent if the parent is already grayed out.
- show->set_modulate(Color(1, 1, 1, 0.5));
- }
- path_hb->add_child(show);
-
- if (!item.missing) {
- show->connect("pressed", callable_mp(this, &ProjectList::_show_project), varray(item.path));
- show->set_tooltip(TTR("Show in File Manager"));
- } else {
- show->set_tooltip(TTR("Error: Project is missing on the filesystem."));
- }
- Label *fpath = memnew(Label(item.path));
- fpath->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE);
- path_hb->add_child(fpath);
- fpath->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- fpath->set_modulate(Color(1, 1, 1, 0.5));
- fpath->add_theme_color_override("font_color", font_color);
- fpath->set_clip_text(true);
+ { // Top half, title and unsupported features labels.
+ HBoxContainer *title_hb = memnew(HBoxContainer);
+ vb->add_child(title_hb);
+
+ Label *title = memnew(Label(!item.missing ? item.project_name : TTR("Missing Project")));
+ title->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ title->add_theme_font_override("font", get_theme_font(SNAME("title"), SNAME("EditorFonts")));
+ title->add_theme_font_size_override("font_size", get_theme_font_size(SNAME("title_size"), SNAME("EditorFonts")));
+ title->add_theme_color_override("font_color", font_color);
+ title->set_clip_text(true);
+ title_hb->add_child(title);
+
+ String unsupported_features_str = Variant(item.unsupported_features).operator String().trim_prefix("[").trim_suffix("]");
+ int length = unsupported_features_str.length();
+ if (length > 0) {
+ Label *unsupported_label = memnew(Label(unsupported_features_str));
+ unsupported_label->set_custom_minimum_size(Size2(length * 15, 10) * EDSCALE);
+ unsupported_label->add_theme_font_override("font", get_theme_font(SNAME("title"), SNAME("EditorFonts")));
+ unsupported_label->add_theme_color_override("font_color", get_theme_color(SNAME("warning_color"), SNAME("Editor")));
+ unsupported_label->set_clip_text(true);
+ unsupported_label->set_align(Label::ALIGN_RIGHT);
+ title_hb->add_child(unsupported_label);
+ Control *spacer = memnew(Control());
+ spacer->set_custom_minimum_size(Size2(10, 10));
+ title_hb->add_child(spacer);
+ }
+ }
+
+ { // Bottom half, containing the path and view folder button.
+ HBoxContainer *path_hb = memnew(HBoxContainer);
+ path_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ vb->add_child(path_hb);
+
+ Button *show = memnew(Button);
+ // Display a folder icon if the project directory can be opened, or a "broken file" icon if it can't.
+ show->set_icon(get_theme_icon(!item.missing ? "Load" : "FileBroken", "EditorIcons"));
+ show->set_flat(true);
+ if (!item.grayed) {
+ // Don't make the icon less prominent if the parent is already grayed out.
+ show->set_modulate(Color(1, 1, 1, 0.5));
+ }
+ path_hb->add_child(show);
+
+ if (!item.missing) {
+ show->connect("pressed", callable_mp(this, &ProjectList::_show_project), varray(item.path));
+ show->set_tooltip(TTR("Show in File Manager"));
+ } else {
+ show->set_tooltip(TTR("Error: Project is missing on the filesystem."));
+ }
+
+ Label *fpath = memnew(Label(item.path));
+ fpath->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE);
+ path_hb->add_child(fpath);
+ fpath->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ fpath->set_modulate(Color(1, 1, 1, 0.5));
+ fpath->add_theme_color_override("font_color", font_color);
+ fpath->set_clip_text(true);
+ }
_scroll_children->add_child(hb);
item.control = hb;
@@ -1510,7 +1585,7 @@ void ProjectList::remove_project(int p_index, bool p_update_settings) {
}
memdelete(item.control);
- _projects.remove(p_index);
+ _projects.remove_at(p_index);
if (p_update_settings) {
EditorSettings::get_singleton()->erase("projects/" + item.project_key);
@@ -1601,8 +1676,7 @@ int ProjectList::refresh_project(const String &dir_path) {
if (should_be_in_list) {
// Recreate it with updated info
- Item item;
- load_project_data(property_key, item, is_favourite);
+ Item item = load_project_data(property_key, is_favourite);
_projects.push_back(item);
create_project_item_control(_projects.size() - 1);
@@ -1700,7 +1774,7 @@ void ProjectList::erase_selected_projects(bool p_delete_project_contents) {
}
memdelete(item.control);
- _projects.remove(i);
+ _projects.remove_at(i);
--i;
}
}
@@ -2081,8 +2155,12 @@ void ProjectManager::_open_selected_projects_ask() {
}
// Update the project settings or don't open
- String conf = project.path.plus_file("project.godot");
- int config_version = project.version;
+ const String conf = project.path.plus_file("project.godot");
+ const int config_version = project.version;
+ PackedStringArray unsupported_features = project.unsupported_features;
+
+ Label *ask_update_label = ask_update_settings->get_label();
+ ask_update_label->set_align(Label::ALIGN_LEFT); // Reset in case of previous center align.
// Check if the config_version property was empty or 0
if (config_version == 0) {
@@ -2102,6 +2180,35 @@ void ProjectManager::_open_selected_projects_ask() {
dialog_error->popup_centered();
return;
}
+ // Check if the project is using features not supported by this build of Godot.
+ if (!unsupported_features.is_empty()) {
+ String warning_message = "";
+ for (int i = 0; i < unsupported_features.size(); i++) {
+ String feature = unsupported_features[i];
+ if (feature == "Double Precision") {
+ warning_message += TTR("Warning: This project uses double precision floats, but this version of\nGodot uses single precision floats. Opening this project may cause data loss.\n\n");
+ unsupported_features.remove_at(i);
+ i--;
+ } else if (feature == "C#") {
+ warning_message += TTR("Warning: This project uses C#, but this build of Godot does not have\nthe Mono module. If you proceed you will not be able to use any C# scripts.\n\n");
+ unsupported_features.remove_at(i);
+ i--;
+ } else if (feature.substr(0, 3).is_numeric()) {
+ warning_message += vformat(TTR("Warning: This project was built in Godot %s.\nOpening will upgrade or downgrade the project to Godot %s.\n\n"), Variant(feature), Variant(VERSION_BRANCH));
+ unsupported_features.remove_at(i);
+ i--;
+ }
+ }
+ if (!unsupported_features.is_empty()) {
+ String unsupported_features_str = Variant(unsupported_features).operator String().trim_prefix("[").trim_suffix("]");
+ warning_message += vformat(TTR("Warning: This project uses the following features not supported by this build of Godot:\n\n%s\n\n"), unsupported_features_str);
+ }
+ warning_message += TTR("Open anyway? Project will be modified.");
+ ask_update_label->set_align(Label::ALIGN_CENTER);
+ ask_update_settings->set_text(warning_message);
+ ask_update_settings->popup_centered();
+ return;
+ }
// Open if the project is up-to-date
_open_selected_projects();
diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp
index f10ecab34e..061f4d218a 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -312,7 +312,7 @@ bool CustomPropertyEditor::edit(Object *p_owner, const String &p_name, Variant::
spinbox->hide();
slider->hide();
menu->clear();
- menu->set_size(Size2(1, 1) * EDSCALE);
+ menu->reset_size();
for (int i = 0; i < MAX_VALUE_EDITORS; i++) {
if (i < MAX_VALUE_EDITORS / 4) {
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 0b293c9caf..611038a947 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -899,7 +899,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
// Resize the dialog to its minimum size.
// This prevents the dialog from being too wide after displaying
// a deletion confirmation for a node with a long name.
- delete_dialog->set_size(Size2());
+ delete_dialog->reset_size();
delete_dialog->popup_centered();
}
@@ -2575,7 +2575,7 @@ void SceneTreeDock::_files_dropped(Vector<String> p_files, NodePath p_to, int p_
menu_properties->set_item_metadata(menu_properties->get_item_count() - 1, p);
}
- menu_properties->set_size(Size2(1, 1));
+ menu_properties->reset_size();
menu_properties->set_position(get_screen_position() + get_local_mouse_position());
menu_properties->popup();
} else if (!valid_properties.is_empty()) {
@@ -2667,7 +2667,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->add_icon_shortcut(get_theme_icon(SNAME("Instance"), SNAME("EditorIcons")), ED_GET_SHORTCUT("scene_tree/instance_scene"), TOOL_INSTANTIATE);
}
- menu->set_size(Size2(1, 1));
+ menu->reset_size();
menu->set_position(get_screen_position() + p_menu_pos);
menu->popup();
return;
@@ -2690,7 +2690,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
if (profile_allow_editing) {
subresources.clear();
menu_subresources->clear();
- menu_subresources->set_size(Size2(1, 1));
+ menu_subresources->reset_size();
_add_children_to_popup(selection.front()->get(), 0);
if (menu->get_item_count() > 0) {
menu->add_separator();
@@ -2831,7 +2831,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->add_separator();
menu->add_icon_shortcut(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), Key::KEY_DELETE), TOOL_ERASE);
}
- menu->set_size(Size2(1, 1));
+ menu->reset_size();
menu->set_position(p_menu_pos);
menu->popup();
}
@@ -2843,7 +2843,7 @@ void SceneTreeDock::_open_tree_menu() {
menu->add_check_item(TTR("Auto Expand to Selected"), TOOL_AUTO_EXPAND);
menu->set_item_checked(menu->get_item_idx_from_text(TTR("Auto Expand to Selected")), EditorSettings::get_singleton()->get("docks/scene_tree/auto_expand_to_selected"));
- menu->set_size(Size2(1, 1));
+ menu->reset_size();
menu->set_position(get_screen_position() + get_local_mouse_position());
menu->popup();
}
diff --git a/editor/settings_config_dialog.cpp b/editor/settings_config_dialog.cpp
index 684f8aa37e..e1229729ac 100644
--- a/editor/settings_config_dialog.cpp
+++ b/editor/settings_config_dialog.cpp
@@ -486,7 +486,7 @@ void EditorSettingsDialog::_shortcut_button_pressed(Object *p_item, int p_column
_update_shortcut_events(current_edited_identifier, Array());
}
} else if (type == "event") {
- current_events.remove(current_event_index);
+ current_events.remove_at(current_event_index);
if (is_editing_action) {
_update_builtin_action(current_edited_identifier, current_events);
@@ -564,7 +564,7 @@ void EditorSettingsDialog::drop_data_fw(const Point2 &p_point, const Variant &p_
Array events = selected->get_parent()->get_meta("events");
Variant event_moved = events[index_moving_from];
- events.remove(index_moving_from);
+ events.remove_at(index_moving_from);
events.insert(target_event_index, event_moved);
String ident = selected->get_parent()->get_meta("shortcut_identifier");
diff --git a/glsl_builders.py b/glsl_builders.py
index 57aaed5f9f..0926212e50 100644
--- a/glsl_builders.py
+++ b/glsl_builders.py
@@ -29,6 +29,10 @@ def include_file_in_rd_header(filename, header_data, depth):
while line:
+ index = line.find("//")
+ if index != -1:
+ line = line[:index]
+
if line.find("#[vertex]") != -1:
header_data.reading = "vertex"
line = fs.readline()
@@ -55,7 +59,14 @@ def include_file_in_rd_header(filename, header_data, depth):
import os.path
- included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline)
+ included_file = ""
+
+ if includeline.startswith("thirdparty/"):
+ included_file = os.path.relpath(includeline)
+
+ else:
+ included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline)
+
if not included_file in header_data.vertex_included_files and header_data.reading == "vertex":
header_data.vertex_included_files += [included_file]
if include_file_in_rd_header(included_file, header_data, depth + 1) is None:
diff --git a/main/main.cpp b/main/main.cpp
index f0f8c01592..b4fbc1929c 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1136,7 +1136,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
FileAccess::make_default<FileAccessNetwork>(FileAccess::ACCESS_RESOURCES);
}
- if (globals->setup(project_path, main_pack, upwards) == OK) {
+ if (globals->setup(project_path, main_pack, upwards, editor) == OK) {
#ifdef TOOLS_ENABLED
found_project = true;
#endif
@@ -1700,9 +1700,10 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
RenderingServer::get_singleton()->set_default_clear_color(clear);
if (show_logo) { //boot logo!
- String boot_logo_path = GLOBAL_DEF("application/boot_splash/image", String());
- bool boot_logo_scale = GLOBAL_DEF("application/boot_splash/fullsize", true);
- bool boot_logo_filter = GLOBAL_DEF("application/boot_splash/use_filter", true);
+ const bool boot_logo_image = GLOBAL_DEF("application/boot_splash/show_image", true);
+ const String boot_logo_path = String(GLOBAL_DEF("application/boot_splash/image", String())).strip_edges();
+ const bool boot_logo_scale = GLOBAL_DEF("application/boot_splash/fullsize", true);
+ const bool boot_logo_filter = GLOBAL_DEF("application/boot_splash/use_filter", true);
ProjectSettings::get_singleton()->set_custom_property_info("application/boot_splash/image",
PropertyInfo(Variant::STRING,
"application/boot_splash/image",
@@ -1710,14 +1711,19 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
Ref<Image> boot_logo;
- boot_logo_path = boot_logo_path.strip_edges();
-
- if (boot_logo_path != String()) {
- boot_logo.instantiate();
- Error load_err = ImageLoader::load_image(boot_logo_path, boot_logo);
- if (load_err) {
- ERR_PRINT("Non-existing or invalid boot splash at '" + boot_logo_path + "'. Loading default splash.");
+ if (boot_logo_image) {
+ if (boot_logo_path != String()) {
+ boot_logo.instantiate();
+ Error load_err = ImageLoader::load_image(boot_logo_path, boot_logo);
+ if (load_err) {
+ ERR_PRINT("Non-existing or invalid boot splash at '" + boot_logo_path + "'. Loading default splash.");
+ }
}
+ } else {
+ // Create a 1×1 transparent image. This will effectively hide the splash image.
+ boot_logo.instantiate();
+ boot_logo->create(1, 1, false, Image::FORMAT_RGBA8);
+ boot_logo->set_pixel(0, 0, Color(0, 0, 0, 0));
}
#if defined(TOOLS_ENABLED) && !defined(NO_EDITOR_SPLASH)
diff --git a/modules/bullet/area_bullet.cpp b/modules/bullet/area_bullet.cpp
index 435069e25c..10a71d65df 100644
--- a/modules/bullet/area_bullet.cpp
+++ b/modules/bullet/area_bullet.cpp
@@ -89,7 +89,7 @@ void AreaBullet::dispatch_callbacks() {
// This object's last shape being removed.
overlapping_shape.other_object->on_exit_area(this);
}
- overlapping_shapes.remove(i); // Remove after callback
+ overlapping_shapes.remove_at(i); // Remove after callback
break;
case OVERLAP_STATE_INSIDE: {
if (overlapping_shape.other_object->getType() == TYPE_RIGID_BODY) {
@@ -188,7 +188,7 @@ void AreaBullet::remove_object_overlaps(CollisionObjectBullet *p_object) {
// Reverse order so items can be removed.
for (int i = overlapping_shapes.size() - 1; i >= 0; i--) {
if (overlapping_shapes[i].other_object == p_object) {
- overlapping_shapes.remove(i);
+ overlapping_shapes.remove_at(i);
}
}
}
diff --git a/modules/bullet/collision_object_bullet.cpp b/modules/bullet/collision_object_bullet.cpp
index 987a45ad5f..cbb746800d 100644
--- a/modules/bullet/collision_object_bullet.cpp
+++ b/modules/bullet/collision_object_bullet.cpp
@@ -273,7 +273,7 @@ void RigidCollisionObjectBullet::remove_shape_full(ShapeBullet *p_shape) {
for (int i = shapes.size() - 1; 0 <= i; --i) {
if (p_shape == shapes[i].shape) {
internal_shape_destroy(i);
- shapes.remove(i);
+ shapes.remove_at(i);
}
}
reload_shapes();
@@ -282,7 +282,7 @@ void RigidCollisionObjectBullet::remove_shape_full(ShapeBullet *p_shape) {
void RigidCollisionObjectBullet::remove_shape_full(int p_index) {
ERR_FAIL_INDEX(p_index, get_shape_count());
internal_shape_destroy(p_index);
- shapes.remove(p_index);
+ shapes.remove_at(p_index);
reload_shapes();
}
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp
index 3a2370ff31..c0ffffa364 100644
--- a/modules/bullet/soft_body_bullet.cpp
+++ b/modules/bullet/soft_body_bullet.cpp
@@ -442,7 +442,7 @@ void SoftBodyBullet::unpin_node(int p_node_index) {
}
const int id = search_node_pinned(p_node_index);
if (-1 != id) {
- pinned_nodes.remove(id);
+ pinned_nodes.remove_at(id);
}
}
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index a7742ef415..a70e153abd 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -933,7 +933,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
merge_faces_idx.sort();
merge_faces_idx.reverse();
for (int i = 0; i < merge_faces_idx.size(); ++i) {
- faces.remove(merge_faces_idx[i]);
+ faces.remove_at(merge_faces_idx[i]);
}
if (degenerate_points.size() == 0) {
@@ -983,7 +983,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
// If new vertex snaps to degenerate vertex, just delete this face.
if (degenerate_idx == opposite_vertex_idx) {
- faces.remove(face_idx);
+ faces.remove_at(face_idx);
// Update index.
--face_idx;
break;
@@ -999,7 +999,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
right_face.vertex_idx[0] = opposite_vertex_idx;
right_face.vertex_idx[1] = face.vertex_idx[face_edge_idx];
right_face.vertex_idx[2] = degenerate_idx;
- faces.remove(face_idx);
+ faces.remove_at(face_idx);
faces.insert(face_idx, right_face);
faces.insert(face_idx, left_face);
@@ -1070,7 +1070,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
// If new vertex snaps to opposite vertex, just delete this face.
if (new_vertex_idx == opposite_vertex_idx) {
- faces.remove(face_idx);
+ faces.remove_at(face_idx);
// Update index.
--face_idx;
break;
@@ -1092,7 +1092,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
right_face.vertex_idx[0] = opposite_vertex_idx;
right_face.vertex_idx[1] = face.vertex_idx[face_edge_idx];
right_face.vertex_idx[2] = new_vertex_idx;
- faces.remove(face_idx);
+ faces.remove_at(face_idx);
faces.insert(face_idx, right_face);
faces.insert(face_idx, left_face);
@@ -1162,7 +1162,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
// If new vertex snaps to opposite vertex, just delete this face.
if (new_vertex_idx == opposite_vertex_idx) {
- faces.remove(face_idx);
+ faces.remove_at(face_idx);
// Update index.
--face_idx;
break;
@@ -1187,7 +1187,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
right_face.vertex_idx[0] = opposite_vertex_idx;
right_face.vertex_idx[1] = face.vertex_idx[face_edge_idx];
right_face.vertex_idx[2] = new_vertex_idx;
- faces.remove(face_idx);
+ faces.remove_at(face_idx);
faces.insert(face_idx, right_face);
faces.insert(face_idx, left_face);
@@ -1222,7 +1222,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
new_face.vertex_idx[2] = new_vertex_idx;
faces.push_back(new_face);
}
- faces.remove(face_idx);
+ faces.remove_at(face_idx);
// No need to check other faces.
break;
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 9c8adb4cf1..33f4198ac1 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -4,10 +4,10 @@
Built-in GDScript functions.
</brief_description>
<description>
- List of core built-in GDScript functions. Math functions and other utilities. Everything else is provided by objects. (Keywords: builtin, built in, global functions.)
+ A list of GDScript-specific utility functions accessed in any script.
+ For the list of the global functions and constants see [@GlobalScope].
</description>
<tutorials>
- <link title="Random number generation">$DOCS_URL/tutorials/math/random_number_generation.html</link>
</tutorials>
<methods>
<method name="Color8">
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 68da588c3d..b76c2c0437 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -427,7 +427,7 @@ void GDScript::_add_doc(const DocData::ClassDoc &p_inner_class) {
} else {
for (int i = 0; i < docs.size(); i++) {
if (docs[i].name == p_inner_class.name) {
- docs.remove(i);
+ docs.remove_at(i);
break;
}
}
@@ -2131,7 +2131,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
const GDScriptParser::ClassNode *inner_class = subclass->members[i].m_class;
if (inner_class->identifier->name == extend_classes[0]) {
- extend_classes.remove(0);
+ extend_classes.remove_at(0);
found = true;
subclass = inner_class;
break;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index cd8fd361c5..1ecde53dd0 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -3001,7 +3001,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
// TODO: Don't load if validating: use completion cache.
p_preload->resource = ResourceLoader::load(p_preload->resolved_path);
if (p_preload->resource.is_null()) {
- push_error(vformat(R"(Could not p_preload resource file "%s".)", p_preload->resolved_path), p_preload->path);
+ push_error(vformat(R"(Could not preload resource file "%s".)", p_preload->resolved_path), p_preload->path);
}
}
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index bde6783322..41b2d2191c 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -741,20 +741,22 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
if (member->identifier != nullptr) {
if (!((String)member->identifier->name).is_empty()) { // Enums may be unnamed.
+
+#ifdef DEBUG_ENABLED
List<MethodInfo> gdscript_funcs;
GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
for (MethodInfo &info : gdscript_funcs) {
if (info.name == member->identifier->name) {
- push_error(vformat(R"(%s "%s" has the same name as a built-in function.)", p_member_kind.capitalize(), member->identifier->name), member->identifier);
- return;
+ push_warning(member->identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_member_kind, member->identifier->name, "built-in function");
}
}
+ if (Variant::has_utility_function(member->identifier->name)) {
+ push_warning(member->identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_member_kind, member->identifier->name, "built-in function");
+ }
+#endif
+
if (current_class->members_indices.has(member->identifier->name)) {
push_error(vformat(R"(%s "%s" has the same name as a previously declared %s.)", p_member_kind.capitalize(), member->identifier->name, current_class->get_member(member->identifier->name).get_type_name()), member->identifier);
- } else if (Variant::has_utility_function(member->identifier->name)) {
- push_error(vformat(R"(%s "%s" has the same name as a built-in function.)", p_member_kind.capitalize(), member->identifier->name), member->identifier);
- } else if (ClassDB::class_exists(member->identifier->name)) {
- push_error(vformat(R"(%s "%s" has the same name as a global class.)", p_member_kind.capitalize(), member->identifier->name), member->identifier);
} else {
current_class->add_member(member);
}
@@ -827,21 +829,18 @@ GDScriptParser::VariableNode *GDScriptParser::parse_variable(bool p_allow_proper
GDScriptParser::IdentifierNode *identifier = parse_identifier();
+#ifdef DEBUG_ENABLED
List<MethodInfo> gdscript_funcs;
GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
for (MethodInfo &info : gdscript_funcs) {
if (info.name == identifier->name) {
- push_error(vformat(R"(Local var "%s" has the same name as a built-in function.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "local variable", identifier->name, "built-in function");
}
}
if (Variant::has_utility_function(identifier->name)) {
- push_error(vformat(R"(Local var "%s" has the same name as a built-in function.)", identifier->name), identifier);
- return nullptr;
- } else if (ClassDB::class_exists(identifier->name)) {
- push_error(vformat(R"(Local var "%s" has the same name as a global class.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "local variable", identifier->name, "built-in function");
}
+#endif
VariableNode *variable = alloc_node<VariableNode>();
variable->identifier = identifier;
@@ -1099,22 +1098,20 @@ GDScriptParser::ParameterNode *GDScriptParser::parse_parameter() {
}
GDScriptParser::IdentifierNode *identifier = parse_identifier();
-
+#ifdef DEBUG_ENABLED
List<MethodInfo> gdscript_funcs;
GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
for (MethodInfo &info : gdscript_funcs) {
if (info.name == identifier->name) {
- push_error(vformat(R"(Parameter "%s" has the same name as a built-in function.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "parameter", identifier->name, "built-in function");
}
}
if (Variant::has_utility_function(identifier->name)) {
- push_error(vformat(R"(Parameter "%s" has the same name as a built-in function.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "parameter", identifier->name, "built-in function");
} else if (ClassDB::class_exists(identifier->name)) {
- push_error(vformat(R"(Parameter "%s" has the same name as a global class.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "parameter", identifier->name, "global class");
}
+#endif
ParameterNode *parameter = alloc_node<ParameterNode>();
parameter->identifier = identifier;
@@ -1195,8 +1192,10 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
HashMap<StringName, int> elements;
+#ifdef DEBUG_ENABLED
List<MethodInfo> gdscript_funcs;
GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
+#endif
do {
if (check(GDScriptTokenizer::Token::BRACE_CLOSE)) {
@@ -1205,20 +1204,18 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected identifier for enum key.)")) {
EnumNode::Value item;
GDScriptParser::IdentifierNode *identifier = parse_identifier();
-
+#ifdef DEBUG_ENABLED
for (MethodInfo &info : gdscript_funcs) {
if (info.name == identifier->name) {
- push_error(vformat(R"(Enum member "%s" has the same name as a built-in function.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "built-in function");
}
}
if (Variant::has_utility_function(identifier->name)) {
- push_error(vformat(R"(Enum member "%s" has the same name as a built-in function.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "built-in function");
} else if (ClassDB::class_exists(identifier->name)) {
- push_error(vformat(R"(Enum member "%s" has the same name as a global class.)", identifier->name), identifier);
- return nullptr;
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "global class");
}
+#endif
item.identifier = identifier;
item.parent_enum = enum_node;
item.line = previous.start_line;
@@ -3417,7 +3414,7 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)
p_annotation->resolved_arguments.push_back(r);
if (error.error != Callable::CallError::CALL_OK) {
push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
- p_annotation->resolved_arguments.remove(p_annotation->resolved_arguments.size() - 1);
+ p_annotation->resolved_arguments.remove_at(p_annotation->resolved_arguments.size() - 1);
return false;
}
break;
@@ -3441,7 +3438,7 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)
p_annotation->resolved_arguments.push_back(r);
if (error.error != Callable::CallError::CALL_OK) {
push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
- p_annotation->resolved_arguments.remove(p_annotation->resolved_arguments.size() - 1);
+ p_annotation->resolved_arguments.remove_at(p_annotation->resolved_arguments.size() - 1);
return false;
}
break;
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index 7a483a16ba..a351bd6dad 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -148,6 +148,10 @@ String GDScriptWarning::get_message() const {
case EMPTY_FILE: {
return "Empty script file.";
}
+ case SHADOWED_GLOBAL_IDENTIFIER: {
+ CHECK_SYMBOLS(3);
+ return vformat(R"(The %s '%s' has the same name as a %s.)", symbols[0], symbols[1], symbols[2]);
+ }
case WARNING_MAX:
break; // Can't happen, but silences warning
}
@@ -194,6 +198,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"ASSERT_ALWAYS_FALSE",
"REDUNDANT_AWAIT",
"EMPTY_FILE",
+ "SHADOWED_GLOBAL_IDENTIFIER",
};
static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names.");
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index 8de46b08c1..d05f47efe7 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -69,6 +69,7 @@ public:
ASSERT_ALWAYS_FALSE, // Expression for assert argument is always false.
REDUNDANT_AWAIT, // await is used but expression is synchronous (not a signal nor a coroutine).
EMPTY_FILE, // A script file is empty.
+ SHADOWED_GLOBAL_IDENTIFIER, // A global class or function has the same name as variable.
WARNING_MAX,
};
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index 5cf1e0fc5f..578943696e 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -115,7 +115,7 @@ Error GDScriptLanguageProtocol::LSPeer::send_data() {
// Response sent
if (res_sent >= c_res.size() - 1) {
res_sent = 0;
- res_queue.remove(0);
+ res_queue.remove_at(0);
}
}
return OK;
diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.gd b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.gd
new file mode 100644
index 0000000000..3c64be571b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.gd
@@ -0,0 +1,2 @@
+func test():
+ var abs = "This variable has the same name as the built-in function."
diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out
new file mode 100644
index 0000000000..f2b29e5bad
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out
@@ -0,0 +1,9 @@
+GDTEST_OK
+>> WARNING
+>> Line: 2
+>> SHADOWED_GLOBAL_IDENTIFIER
+>> The local variable 'abs' has the same name as a built-in function.
+>> WARNING
+>> Line: 2
+>> UNUSED_VARIABLE
+>> The local variable 'abs' is declared but never used in the block. If this is intended, prefix it with an underscore: '_abs'
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index fac1e61b18..f3317aeada 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -6115,7 +6115,10 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
int bone_cnt = skeleton->get_bone_count();
ERR_FAIL_COND(bone_cnt != gltf_skeleton->joints.size());
- ObjectID gltf_skin_key = skin->get_instance_id();
+ ObjectID gltf_skin_key;
+ if (skin.is_valid()) {
+ gltf_skin_key = skin->get_instance_id();
+ }
ObjectID gltf_skel_key = godot_skeleton->get_instance_id();
GLTFSkinIndex skin_gltf_i = -1;
GLTFNodeIndex root_gltf_i = -1;
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 544f2a7584..0ceb45d425 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -788,11 +788,7 @@ bool CSharpLanguage::is_assembly_reloading_needed() {
GDMonoAssembly *proj_assembly = gdmono->get_project_assembly();
- String appname = ProjectSettings::get_singleton()->get("application/config/name");
- String appname_safe = OS::get_singleton()->get_safe_dir_name(appname);
- if (appname_safe.is_empty()) {
- appname_safe = "UnnamedProject";
- }
+ String appname_safe = ProjectSettings::get_singleton()->get_safe_project_name();
appname_safe += ".dll";
diff --git a/modules/mono/glue/collections_glue.cpp b/modules/mono/glue/collections_glue.cpp
index 86976de244..e367ecb7d6 100644
--- a/modules/mono/glue/collections_glue.cpp
+++ b/modules/mono/glue/collections_glue.cpp
@@ -144,7 +144,7 @@ void godot_icall_Array_Insert(Array *ptr, int32_t index, MonoObject *item) {
MonoBoolean godot_icall_Array_Remove(Array *ptr, MonoObject *item) {
int idx = ptr->find(GDMonoMarshal::mono_object_to_variant(item));
if (idx >= 0) {
- ptr->remove(idx);
+ ptr->remove_at(idx);
return true;
}
return false;
@@ -155,7 +155,7 @@ void godot_icall_Array_RemoveAt(Array *ptr, int32_t index) {
GDMonoUtils::set_pending_exception(mono_get_exception_index_out_of_range());
return;
}
- ptr->remove(index);
+ ptr->remove_at(index);
}
int32_t godot_icall_Array_Resize(Array *ptr, int32_t new_size) {
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index f600f07c87..ac3422187f 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -150,8 +150,8 @@ COMMAND_2(map_set_active, RID, p_map, bool, p_active) {
} else {
int map_index = active_maps.find(map);
ERR_FAIL_COND(map_index < 0);
- active_maps.remove(map_index);
- active_maps_update_id.remove(map_index);
+ active_maps.remove_at(map_index);
+ active_maps_update_id.remove_at(map_index);
}
}
@@ -469,8 +469,8 @@ COMMAND_1(free, RID, p_object) {
}
int map_index = active_maps.find(map);
- active_maps.remove(map_index);
- active_maps_update_id.remove(map_index);
+ active_maps.remove_at(map_index);
+ active_maps_update_id.remove_at(map_index);
map_owner.free(p_object);
} else if (region_owner.owns(p_object)) {
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 1adaef4d84..f480c86088 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -2148,7 +2148,7 @@ void TextServerAdvanced::font_remove_texture(RID p_font_rid, const Vector2i &p_s
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
ERR_FAIL_INDEX(p_texture_index, fd->cache[size]->textures.size());
- fd->cache[size]->textures.remove(p_texture_index);
+ fd->cache[size]->textures.remove_at(p_texture_index);
}
void TextServerAdvanced::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 80ae10c005..5c06051211 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -1326,7 +1326,7 @@ void TextServerFallback::font_remove_texture(RID p_font_rid, const Vector2i &p_s
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
ERR_FAIL_INDEX(p_texture_index, fd->cache[size]->textures.size());
- fd->cache[size]->textures.remove(p_texture_index);
+ fd->cache[size]->textures.remove_at(p_texture_index);
}
void TextServerFallback::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
diff --git a/modules/upnp/upnp.cpp b/modules/upnp/upnp.cpp
index 88d92b0083..64823deaba 100644
--- a/modules/upnp/upnp.cpp
+++ b/modules/upnp/upnp.cpp
@@ -257,7 +257,7 @@ void UPNP::set_device(int index, Ref<UPNPDevice> device) {
void UPNP::remove_device(int index) {
ERR_FAIL_INDEX(index, devices.size());
- devices.remove(index);
+ devices.remove_at(index);
}
void UPNP::clear_devices() {
diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp
index 2096487235..13dd1f7bc7 100644
--- a/modules/visual_script/editor/visual_script_editor.cpp
+++ b/modules/visual_script/editor/visual_script_editor.cpp
@@ -998,7 +998,7 @@ void VisualScriptEditor::_change_port_type(int p_select, int p_id, int p_port, b
void VisualScriptEditor::_update_node_size(int p_id) {
Node *node = graph->get_node(itos(p_id));
if (Object::cast_to<Control>(node)) {
- Object::cast_to<Control>(node)->set_size(Vector2(1, 1)); // Shrink if text is smaller.
+ Object::cast_to<Control>(node)->reset_size(); // Shrink if text is smaller.
}
}
@@ -1262,6 +1262,23 @@ void VisualScriptEditor::_member_edited() {
undo_redo->create_action(TTR("Rename Variable"));
undo_redo->add_do_method(script.ptr(), "rename_variable", name, new_name);
undo_redo->add_undo_method(script.ptr(), "rename_variable", new_name, name);
+
+ // Also fix all variable setter & getter calls
+ List<int> lst;
+ script->get_node_list(&lst);
+ for (int &P : lst) {
+ Ref<VisualScriptPropertySet> pset = script->get_node(P);
+ if (pset.is_valid() && pset->get_property() == name) {
+ undo_redo->add_do_method(pset.ptr(), "set_property", new_name);
+ undo_redo->add_undo_method(pset.ptr(), "set_property", name);
+ }
+ Ref<VisualScriptPropertyGet> pget = script->get_node(P);
+ if (pget.is_valid() && pget->get_property() == name) {
+ undo_redo->add_do_method(pget.ptr(), "set_property", new_name);
+ undo_redo->add_undo_method(pget.ptr(), "set_property", name);
+ }
+ }
+
undo_redo->add_do_method(this, "_update_members");
undo_redo->add_undo_method(this, "_update_members");
undo_redo->add_do_method(this, "_update_graph");
@@ -1278,6 +1295,18 @@ void VisualScriptEditor::_member_edited() {
undo_redo->create_action(TTR("Rename Signal"));
undo_redo->add_do_method(script.ptr(), "rename_custom_signal", name, new_name);
undo_redo->add_undo_method(script.ptr(), "rename_custom_signal", new_name, name);
+
+ // Also fix all signal emitting nodes
+ List<int> lst;
+ script->get_node_list(&lst);
+ for (int &P : lst) {
+ Ref<VisualScriptEmitSignal> psig = script->get_node(P);
+ if (psig.is_valid() && psig->get_signal() == name) {
+ undo_redo->add_do_method(psig.ptr(), "set_signal", new_name);
+ undo_redo->add_undo_method(psig.ptr(), "set_signal", name);
+ }
+ }
+
undo_redo->add_do_method(this, "_update_members");
undo_redo->add_undo_method(this, "_update_members");
undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");
@@ -1616,7 +1645,7 @@ void VisualScriptEditor::_expression_text_changed(const String &p_text, int p_id
Node *node = graph->get_node(itos(p_id));
if (Object::cast_to<Control>(node)) {
- Object::cast_to<Control>(node)->set_size(Vector2(1, 1)); // Shrink if text is smaller.
+ Object::cast_to<Control>(node)->reset_size(); // Shrink if text is smaller.
}
updating_graph = false;
@@ -3676,7 +3705,7 @@ void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_i
}
default_value_edit->set_position(Object::cast_to<Control>(p_button)->get_global_position() + Vector2(0, Object::cast_to<Control>(p_button)->get_size().y));
- default_value_edit->set_size(Size2(1, 1));
+ default_value_edit->reset_size();
if (pinfo.type == Variant::NODE_PATH) {
Node *edited_scene = get_tree()->get_edited_scene_root();
@@ -3832,7 +3861,7 @@ void VisualScriptEditor::_comment_node_resized(const Vector2 &p_new_size, int p_
undo_redo->commit_action();
gn->set_custom_minimum_size(new_size);
- gn->set_size(Size2(1, 1));
+ gn->reset_size();
graph->set_block_minimum_size_adjust(false);
updating_graph = false;
}
@@ -4132,10 +4161,10 @@ void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) {
member_popup->clear();
member_popup->set_position(members->get_global_position() + p_pos);
- member_popup->set_size(Vector2());
+ member_popup->reset_size();
function_name_edit->set_position(members->get_global_position() + p_pos);
- function_name_edit->set_size(Vector2());
+ function_name_edit->reset_size();
TreeItem *root = members->get_root();
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 700cc85672..34d8c0b1e6 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -661,7 +661,7 @@ void VisualScript::custom_signal_remove_argument(const StringName &p_func, int p
ERR_FAIL_COND(instances.size());
ERR_FAIL_COND(!custom_signals.has(p_func));
ERR_FAIL_INDEX(p_argidx, custom_signals[p_func].size());
- custom_signals[p_func].remove(p_argidx);
+ custom_signals[p_func].remove_at(p_argidx);
}
int VisualScript::custom_signal_get_argument_count(const StringName &p_func) const {
diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp
index 55c707890f..699042ffa6 100644
--- a/modules/visual_script/visual_script_expression.cpp
+++ b/modules/visual_script/visual_script_expression.cpp
@@ -1190,7 +1190,7 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
op->nodes[1] = nullptr;
expression.write[i].is_op = false;
expression.write[i].node = op;
- expression.remove(i + 1);
+ expression.remove_at(i + 1);
}
} else {
@@ -1222,8 +1222,8 @@ VisualScriptExpression::ENode *VisualScriptExpression::_parse_expression() {
//replace all 3 nodes by this operator and make it an expression
expression.write[next_op - 1].node = op;
- expression.remove(next_op);
- expression.remove(next_op);
+ expression.remove_at(next_op);
+ expression.remove_at(next_op);
}
}
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index 471d8ef0ae..b0af030981 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -253,7 +253,7 @@ String VisualScriptFunction::get_argument_name(int p_argidx) const {
void VisualScriptFunction::remove_argument(int p_argidx) {
ERR_FAIL_INDEX(p_argidx, arguments.size());
- arguments.remove(p_argidx);
+ arguments.remove_at(p_argidx);
ports_changed_notify();
}
@@ -623,7 +623,7 @@ void VisualScriptLists::remove_input_data_port(int p_argidx) {
ERR_FAIL_INDEX(p_argidx, inputports.size());
- inputports.remove(p_argidx);
+ inputports.remove_at(p_argidx);
ports_changed_notify();
notify_property_list_changed();
@@ -679,7 +679,7 @@ void VisualScriptLists::remove_output_data_port(int p_argidx) {
ERR_FAIL_INDEX(p_argidx, outputports.size());
- outputports.remove(p_argidx);
+ outputports.remove_at(p_argidx);
ports_changed_notify();
notify_property_list_changed();
diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp
index dc259da886..52f80b3080 100644
--- a/platform/android/android_input_handler.cpp
+++ b/platform/android/android_input_handler.cpp
@@ -223,7 +223,7 @@ void AndroidInputHandler::process_touch(int p_event, int p_pointer, const Vector
ev->set_pressed(false);
ev->set_position(touch[i].pos);
Input::get_singleton()->parse_input_event(ev);
- touch.remove(i);
+ touch.remove_at(i);
break;
}
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 05cd63d935..c5d3cbd966 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -2212,7 +2212,7 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportP
Vector<String> command_line_strings = cmdline.strip_edges().split(" ");
for (int i = 0; i < command_line_strings.size(); i++) {
if (command_line_strings[i].strip_edges().length() == 0) {
- command_line_strings.remove(i);
+ command_line_strings.remove_at(i);
i--;
}
}
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 2a62780410..74ec8b652f 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -286,7 +286,7 @@ void DisplayServerX11::_flush_mouse_motion() {
XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data;
if (event_data->evtype == XI_RawMotion) {
XFreeEventData(x11_display, &event.xcookie);
- polled_events.remove(event_index--);
+ polled_events.remove_at(event_index--);
continue;
}
XFreeEventData(x11_display, &event.xcookie);
diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp
index 1c6afabfab..55cc21cc6c 100644
--- a/platform/linuxbsd/joypad_linux.cpp
+++ b/platform/linuxbsd/joypad_linux.cpp
@@ -253,7 +253,7 @@ void JoypadLinux::close_joypad(int p_id) {
if (joy.fd != -1) {
close(joy.fd);
joy.fd = -1;
- attached_devices.remove(attached_devices.find(joy.devpath));
+ attached_devices.remove_at(attached_devices.find(joy.devpath));
input->joy_connection_changed(p_id, false, "");
};
}
diff --git a/platform/osx/gl_manager_osx.mm b/platform/osx/gl_manager_osx.mm
index cce58530ee..60e0706fc0 100644
--- a/platform/osx/gl_manager_osx.mm
+++ b/platform/osx/gl_manager_osx.mm
@@ -75,7 +75,7 @@ Error GLManager_OSX::window_create(DisplayServer::WindowID p_window_id, id p_vie
win.window_view = p_view;
if (_create_context(win) != OK) {
- _windows.remove(_windows.size() - 1);
+ _windows.remove_at(_windows.size() - 1);
return FAILED;
}
diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp
index 8405ed1da1..48d165d30b 100644
--- a/platform/osx/joypad_osx.cpp
+++ b/platform/osx/joypad_osx.cpp
@@ -264,7 +264,7 @@ void JoypadOSX::_device_removed(IOReturn p_res, IOHIDDeviceRef p_device) {
input->joy_connection_changed(device_list[device].id, false, "");
device_list.write[device].free();
- device_list.remove(device);
+ device_list.remove_at(device);
}
static String _hex_str(uint8_t p_byte) {
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
index a54b85a803..192814efe4 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -376,7 +376,7 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p
Vector<String> cl = ((String)p_preset->get("command_line/extra_args")).strip_edges().split(" ");
for (int i = 0; i < cl.size(); i++) {
if (cl[i].strip_edges().length() == 0) {
- cl.remove(i);
+ cl.remove_at(i);
i--;
}
}
diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows.cpp
index 1ce8b0b040..fe98f8b0ba 100644
--- a/platform/windows/gl_manager_windows.cpp
+++ b/platform/windows/gl_manager_windows.cpp
@@ -77,7 +77,7 @@ int GLManager_Windows::_find_or_create_display(GLWindow &win) {
if (err != OK) {
// not good
// delete the _display?
- _displays.remove(new_display_id);
+ _displays.remove_at(new_display_id);
return -1;
}
@@ -193,7 +193,7 @@ Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND
if (win.gldisplay_id == -1) {
// release DC?
- _windows.remove(_windows.size() - 1);
+ _windows.remove_at(_windows.size() - 1);
return FAILED;
}
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 24da2ce9ce..8bf95e6965 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -97,7 +97,7 @@ void AudioStreamPlayer2D::_notification(int p_what) {
while (stream_playbacks.size() > max_polyphony) {
AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]);
- stream_playbacks.remove(0);
+ stream_playbacks.remove_at(0);
}
}
}
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 4b348f12e6..bd13d96b01 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -434,7 +434,7 @@ void CollisionObject2D::shape_owner_remove_shape(uint32_t p_owner, int p_shape)
PhysicsServer2D::get_singleton()->body_remove_shape(rid, index_to_remove);
}
- shapes[p_owner].shapes.remove(p_shape);
+ shapes[p_owner].shapes.remove_at(p_shape);
for (KeyValue<uint32_t, ShapeData> &E : shapes) {
for (int i = 0; i < E.value.shapes.size(); i++) {
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 37eb45c21d..00767ec22c 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -148,7 +148,7 @@ void Line2D::add_point(Vector2 p_pos, int p_atpos) {
}
void Line2D::remove_point(int i) {
- _points.remove(i);
+ _points.remove_at(i);
update();
}
diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp
index 204ed72878..ecd79c23a7 100644
--- a/scene/2d/navigation_region_2d.cpp
+++ b/scene/2d/navigation_region_2d.cpp
@@ -207,7 +207,7 @@ void NavigationPolygon::set_outline(int p_idx, const Vector<Vector2> &p_outline)
void NavigationPolygon::remove_outline(int p_idx) {
ERR_FAIL_INDEX(p_idx, outlines.size());
- outlines.remove(p_idx);
+ outlines.remove_at(p_idx);
rect_cache_dirty = true;
}
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index f00959bbb6..7a237bf557 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -532,7 +532,7 @@ Vector<float> Polygon2D::get_bone_weights(int p_index) const {
void Polygon2D::erase_bone(int p_idx) {
ERR_FAIL_INDEX(p_idx, bone_weights.size());
- bone_weights.remove(p_idx);
+ bone_weights.remove_at(p_idx);
}
void Polygon2D::clear_bones() {
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
index 63a0fb9b89..b558f0aa21 100644
--- a/scene/2d/skeleton_2d.cpp
+++ b/scene/2d/skeleton_2d.cpp
@@ -165,7 +165,7 @@ void Bone2D::_notification(int p_what) {
if (skeleton) {
for (int i = 0; i < skeleton->bones.size(); i++) {
if (skeleton->bones[i].bone == this) {
- skeleton->bones.remove(i);
+ skeleton->bones.remove_at(i);
break;
}
}
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 96c4164721..084a5a520d 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -576,7 +576,7 @@ void TileMap::move_layer(int p_layer, int p_to_pos) {
TileMapLayer tl = layers[p_layer];
layers.insert(p_to_pos, tl);
- layers.remove(p_to_pos < p_layer ? p_layer + 1 : p_layer);
+ layers.remove_at(p_to_pos < p_layer ? p_layer + 1 : p_layer);
_recreate_internals();
notify_property_list_changed();
@@ -595,7 +595,7 @@ void TileMap::remove_layer(int p_layer) {
// Clear before removing the layer.
_clear_internals();
- layers.remove(p_layer);
+ layers.remove_at(p_layer);
_recreate_internals();
notify_property_list_changed();
@@ -1928,7 +1928,7 @@ void TileMap::set_cell(int p_layer, const Vector2i &p_coords, int p_source_id, c
if ((source_id == TileSet::INVALID_SOURCE || atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE) &&
(source_id != TileSet::INVALID_SOURCE || atlas_coords != TileSetSource::INVALID_ATLAS_COORDS || alternative_tile != TileSetSource::INVALID_TILE_ALTERNATIVE)) {
- WARN_PRINT("Setting a cell a cell as empty requires both source_id, atlas_coord and alternative_tile to be set to their respective \"invalid\" values. Values were thus changes accordingly.");
+ WARN_PRINT("Setting a cell as empty requires both source_id, atlas_coord and alternative_tile to be set to their respective \"invalid\" values. Values were thus changes accordingly.");
source_id = TileSet::INVALID_SOURCE;
atlas_coords = TileSetSource::INVALID_ATLAS_COORDS;
alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE;
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 34f748b197..efe23c6102 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -311,7 +311,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
while (stream_playbacks.size() > max_polyphony) {
AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]);
- stream_playbacks.remove(0);
+ stream_playbacks.remove_at(0);
}
}
}
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index a166a05c71..085f1ade66 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -628,7 +628,7 @@ void CollisionObject3D::shape_owner_remove_shape(uint32_t p_owner, int p_shape)
--debug_shapes_count;
}
- shapes[p_owner].shapes.remove(p_shape);
+ shapes[p_owner].shapes.remove_at(p_shape);
for (KeyValue<uint32_t, ShapeData> &E : shapes) {
for (int i = 0; i < E.value.shapes.size(); i++) {
diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp
index b7b88c7135..ddd9d2da8a 100644
--- a/scene/3d/node_3d.cpp
+++ b/scene/3d/node_3d.cpp
@@ -478,7 +478,7 @@ void Node3D::remove_gizmo(Ref<Node3DGizmo> p_gizmo) {
int idx = data.gizmos.find(p_gizmo);
if (idx != -1) {
p_gizmo->free();
- data.gizmos.remove(idx);
+ data.gizmos.remove_at(idx);
}
#endif
}
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 5cb7f431e3..393e29e398 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -1299,7 +1299,6 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
// in order to avoid blocking lateral motion along a wall.
if (motion_angle < .5 * Math_PI) {
apply_default_sliding = false;
-
if (p_was_on_floor && !vel_dir_facing_up) {
// Cancel the motion.
Transform3D gt = get_global_transform();
@@ -1307,14 +1306,18 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
real_t cancel_dist_max = MIN(0.1, margin * 20);
if (travel_total <= margin + CMP_EPSILON) {
gt.origin -= result.travel;
+ result.travel = Vector3(); // Cancel for constant speed computation.
} else if (travel_total < cancel_dist_max) { // If the movement is large the body can be prevented from reaching the walls.
gt.origin -= result.travel.slide(up_direction);
// Keep remaining motion in sync with amount canceled.
motion = motion.slide(up_direction);
+ result.travel = Vector3();
+ } else {
+ // Travel is too high to be safely cancelled, we take it into account.
+ result.travel = result.travel.slide(up_direction);
+ motion = motion.normalized() * result.travel.length();
}
set_global_transform(gt);
- result.travel = Vector3(); // Cancel for constant speed computation.
-
// Determines if you are on the ground, and limits the possibility of climbing on the walls because of the approximations.
_snap_on_floor(true, false);
} else {
@@ -1325,8 +1328,15 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
// Apply slide on forward in order to allow only lateral motion on next step.
Vector3 forward = wall_normal.slide(up_direction).normalized();
motion = motion.slide(forward);
- // Avoid accelerating when you jump on the wall and smooth falling.
- motion_velocity = motion_velocity.slide(forward);
+
+ // Scales the horizontal velocity according to the wall slope.
+ if (vel_dir_facing_up) {
+ Vector3 slide_motion = motion_velocity.slide(result.collisions[0].normal);
+ // Keeps the vertical motion from motion_velocity and add the horizontal motion of the projection.
+ motion_velocity = up_direction * up_direction.dot(motion_velocity) + slide_motion.slide(up_direction);
+ } else {
+ motion_velocity = motion_velocity.slide(forward);
+ }
// Allow only lateral motion along previous floor when already on floor.
// Fixes slowing down when moving in diagonal against an inclined wall.
@@ -1584,6 +1594,7 @@ void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResu
Vector3 prev_wall_normal = wall_normal;
int wall_collision_count = 0;
Vector3 combined_wall_normal;
+ Vector3 tmp_wall_col; // Avoid duplicate on average calculation.
for (int i = p_result.collision_count - 1; i >= 0; i--) {
const PhysicsServer3D::MotionCollision &collision = p_result.collisions[i];
@@ -1630,8 +1641,11 @@ void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResu
}
// Collect normal for calculating average.
- combined_wall_normal += collision.normal;
- wall_collision_count++;
+ if (!collision.normal.is_equal_approx(tmp_wall_col)) {
+ tmp_wall_col = collision.normal;
+ combined_wall_normal += collision.normal;
+ wall_collision_count++;
+ }
}
if (r_state.wall) {
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index d4d3c0ebe1..04b5b88ef8 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -633,7 +633,7 @@ void Skeleton3D::remove_bone_child(int p_bone, int p_child) {
int child_idx = bones[p_bone].child_bones.find(p_child);
if (child_idx >= 0) {
- bones.write[p_bone].child_bones.remove(child_idx);
+ bones.write[p_bone].child_bones.remove_at(child_idx);
} else {
WARN_PRINT("Cannot remove child bone: Child bone not found.");
}
diff --git a/scene/3d/soft_dynamic_body_3d.cpp b/scene/3d/soft_dynamic_body_3d.cpp
index 903eedb58b..5546b88fb1 100644
--- a/scene/3d/soft_dynamic_body_3d.cpp
+++ b/scene/3d/soft_dynamic_body_3d.cpp
@@ -773,7 +773,7 @@ void SoftDynamicBody3D::_reset_points_offsets() {
void SoftDynamicBody3D::_remove_pinned_point(int p_point_index) {
const int id(_has_pinned_point(p_point_index));
if (-1 != id) {
- pinned_points.remove(id);
+ pinned_points.remove_at(id);
}
}
diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp
index e621f06ce9..8b5203961f 100644
--- a/scene/animation/animation_blend_space_2d.cpp
+++ b/scene/animation/animation_blend_space_2d.cpp
@@ -134,7 +134,7 @@ void AnimationNodeBlendSpace2D::remove_blend_point(int p_point) {
}
}
if (erase) {
- triangles.remove(i);
+ triangles.remove_at(i);
i--;
}
@@ -224,7 +224,7 @@ int AnimationNodeBlendSpace2D::get_triangle_point(int p_triangle, int p_point) {
void AnimationNodeBlendSpace2D::remove_triangle(int p_triangle) {
ERR_FAIL_INDEX(p_triangle, triangles.size());
- triangles.remove(p_triangle);
+ triangles.remove_at(p_triangle);
}
int AnimationNodeBlendSpace2D::get_triangle_count() const {
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index b5d7a0555e..c8fa8bf395 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -464,7 +464,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
}
if (path.size()) { //if it came from path, remove path
- path.remove(0);
+ path.remove_at(0);
}
current = next;
if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) {
@@ -624,7 +624,7 @@ void AnimationNodeStateMachine::remove_node(const StringName &p_name) {
for (int i = 0; i < transitions.size(); i++) {
if (transitions[i].from == p_name || transitions[i].to == p_name) {
transitions.write[i].transition->disconnect("advance_condition_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed));
- transitions.remove(i);
+ transitions.remove_at(i);
i--;
}
}
@@ -751,7 +751,7 @@ void AnimationNodeStateMachine::remove_transition(const StringName &p_from, cons
for (int i = 0; i < transitions.size(); i++) {
if (transitions[i].from == p_from && transitions[i].to == p_to) {
transitions.write[i].transition->disconnect("advance_condition_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed));
- transitions.remove(i);
+ transitions.remove_at(i);
return;
}
}
@@ -764,7 +764,7 @@ void AnimationNodeStateMachine::remove_transition(const StringName &p_from, cons
void AnimationNodeStateMachine::remove_transition_by_index(int p_transition) {
ERR_FAIL_INDEX(p_transition, transitions.size());
transitions.write[p_transition].transition->disconnect("advance_condition_changed", callable_mp(this, &AnimationNodeStateMachine::_tree_changed));
- transitions.remove(p_transition);
+ transitions.remove_at(p_transition);
/*if (playing) {
path.clear();
}*/
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index 37e754148c..57c615a6ab 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -329,7 +329,7 @@ void AnimationNode::set_input_name(int p_input, const String &p_name) {
void AnimationNode::remove_input(int p_index) {
ERR_FAIL_INDEX(p_index, inputs.size());
- inputs.remove(p_index);
+ inputs.remove_at(p_index);
emit_changed();
}
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index 43c4ce4c82..3da4f23a08 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -143,7 +143,7 @@ void AudioStreamPlayer::play(float p_from_pos) {
set_process_internal(true);
while (stream_playbacks.size() > max_polyphony) {
AudioServer::get_singleton()->stop_playback_stream(stream_playbacks[0]);
- stream_playbacks.remove(0);
+ stream_playbacks.remove_at(0);
}
}
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index e187b19c3c..a8c5966569 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -2378,7 +2378,7 @@ void CodeEdit::_update_delimiter_cache(int p_from_line, int p_to_line) {
if (start_line != end_line) {
if (p_to_line < p_from_line) {
for (int i = end_line; i > start_line; i--) {
- delimiter_cache.remove(i);
+ delimiter_cache.remove_at(i);
}
} else {
for (int i = start_line; i < end_line; i++) {
@@ -2615,7 +2615,7 @@ void CodeEdit::_remove_delimiter(const String &p_start_key, DelimiterType p_type
break;
}
- delimiters.remove(i);
+ delimiters.remove_at(i);
if (!setting_delimiters) {
delimiter_cache.clear();
_update_delimiter_cache();
@@ -2656,7 +2656,7 @@ void CodeEdit::_set_delimiters(const TypedArray<String> &p_delimiters, Delimiter
void CodeEdit::_clear_delimiters(DelimiterType p_type) {
for (int i = delimiters.size() - 1; i >= 0; i--) {
if (delimiters[i].type == p_type) {
- delimiters.remove(i);
+ delimiters.remove_at(i);
}
}
delimiter_cache.clear();
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index fdf10e2f42..9f715be155 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -1825,6 +1825,10 @@ Size2 Control::get_size() const {
return data.size_cache;
}
+void Control::reset_size() {
+ set_size(Size2());
+}
+
Rect2 Control::get_global_rect() const {
return Rect2(get_global_position(), get_size());
}
@@ -2845,6 +2849,7 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_position", "position", "keep_offsets"), &Control::set_position, DEFVAL(false));
ClassDB::bind_method(D_METHOD("_set_position", "position"), &Control::_set_position);
ClassDB::bind_method(D_METHOD("set_size", "size", "keep_offsets"), &Control::set_size, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("reset_size"), &Control::reset_size);
ClassDB::bind_method(D_METHOD("_set_size", "size"), &Control::_set_size);
ClassDB::bind_method(D_METHOD("set_custom_minimum_size", "size"), &Control::set_custom_minimum_size);
ClassDB::bind_method(D_METHOD("set_global_position", "position", "keep_offsets"), &Control::set_global_position, DEFVAL(false));
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 2eb714eae6..1a94cc68a6 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -401,6 +401,7 @@ public:
void set_size(const Size2 &p_size, bool p_keep_offsets = false);
Size2 get_size() const;
+ void reset_size();
Rect2 get_rect() const;
Rect2 get_global_rect() const;
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index ae15b021a5..1210be15ce 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -89,7 +89,7 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && grabbed != -1) {
- points.remove(grabbed);
+ points.remove_at(grabbed);
grabbed = -1;
grabbing = false;
update();
@@ -109,7 +109,7 @@ void GradientEdit::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
grabbed = _get_point_from_pos(mb->get_position().x);
if (grabbed != -1) {
- points.remove(grabbed);
+ points.remove_at(grabbed);
grabbed = -1;
grabbing = false;
update();
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index c0f2cdbef1..408ef53e89 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -381,7 +381,7 @@ void ItemList::move_item(int p_from_idx, int p_to_idx) {
}
Item item = items[p_from_idx];
- items.remove(p_from_idx);
+ items.remove_at(p_from_idx);
items.insert(p_to_idx, item);
update();
@@ -404,7 +404,7 @@ int ItemList::get_item_count() const {
void ItemList::remove_item(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
- items.remove(p_idx);
+ items.remove_at(p_idx);
if (current == p_idx) {
current = -1;
}
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 4a85cf2c45..69b08fda3c 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -228,7 +228,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
if (b->is_pressed() && b->get_button_index() == MouseButton::RIGHT && context_menu_enabled) {
_ensure_menu();
menu->set_position(get_screen_transform().xform(get_local_mouse_position()));
- menu->set_size(Vector2(1, 1));
+ menu->reset_size();
menu->popup();
grab_focus();
accept_event();
@@ -393,7 +393,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
_ensure_menu();
Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size")))) / 2);
menu->set_position(get_global_transform().xform(pos));
- menu->set_size(Vector2(1, 1));
+ menu->reset_size();
menu->popup();
menu->grab_focus();
}
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 7e9b545776..2e854abb76 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -1403,7 +1403,7 @@ void PopupMenu::remove_item(int p_idx) {
_unref_shortcut(items[p_idx].shortcut);
}
- items.remove(p_idx);
+ items.remove_at(p_idx);
control->update();
child_controls_changed();
}
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index f191dfecb4..fd19fad667 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -2334,7 +2334,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
p_item->parent->subitems.erase(p_item);
// If a newline was erased, all lines AFTER the newline need to be decremented.
if (p_item->type == ITEM_NEWLINE) {
- current_frame->lines.remove(p_line);
+ current_frame->lines.remove_at(p_line);
for (int i = 0; i < current->subitems.size(); i++) {
if (current->subitems[i]->line > p_subitem_line) {
current->subitems[i]->line--;
@@ -2423,7 +2423,7 @@ bool RichTextLabel::remove_line(const int p_line) {
}
if (!had_newline) {
- current_frame->lines.remove(p_line);
+ current_frame->lines.remove_at(p_line);
if (current_frame->lines.size() == 0) {
current_frame->lines.resize(1);
}
@@ -3527,7 +3527,7 @@ void RichTextLabel::append_text(const String &p_bbcode) {
pos = brk_pos + 1;
} else {
String identifier = expr[0];
- expr.remove(0);
+ expr.remove_at(0);
Dictionary properties = parse_expressions_for_values(expr);
Ref<RichTextEffect> effect = _get_custom_effect_by_code(identifier);
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index 1dda29f668..57ee7fd494 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -790,7 +790,7 @@ void TabBar::clear_tabs() {
void TabBar::remove_tab(int p_idx) {
ERR_FAIL_INDEX(p_idx, tabs.size());
- tabs.remove(p_idx);
+ tabs.remove_at(p_idx);
if (current >= p_idx) {
current--;
}
@@ -961,7 +961,7 @@ void TabBar::move_tab(int from, int to) {
ERR_FAIL_INDEX(to, tabs.size());
Tab tab_from = tabs[from];
- tabs.remove(from);
+ tabs.remove_at(from);
tabs.insert(to, tab_from);
_update_cache();
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 74268707ff..2cb9d10fca 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -300,11 +300,11 @@ void TextEdit::Text::insert(int p_at, const String &p_text, const Array &p_bidi_
invalidate_cache(p_at);
}
-void TextEdit::Text::remove(int p_at) {
- int height = text[p_at].height;
- int width = text[p_at].width;
+void TextEdit::Text::remove_at(int p_index) {
+ int height = text[p_index].height;
+ int width = text[p_index].width;
- text.remove(p_at);
+ text.remove_at(p_index);
// If this is the tallest line, we need to get the next tallest.
if (height == line_height) {
@@ -330,7 +330,7 @@ void TextEdit::Text::add_gutter(int p_at) {
void TextEdit::Text::remove_gutter(int p_gutter) {
for (int i = 0; i < text.size(); i++) {
- text.write[i].gutters.remove(p_gutter);
+ text.write[i].gutters.remove_at(p_gutter);
}
gutter_count--;
}
@@ -608,7 +608,7 @@ void TextEdit::_notification(int p_what) {
int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0);
draw_amount += get_line_wrap_count(first_visible_line + 1);
- // minimap
+ // Draw minimap.
if (draw_minimap) {
int minimap_visible_lines = get_minimap_visible_lines();
int minimap_line_height = (minimap_char_size.y + minimap_line_spacing);
@@ -788,8 +788,9 @@ void TextEdit::_notification(int p_what) {
bottom_limit_y -= style_normal->get_margin(SIDE_BOTTOM);
}
- // draw main text
+ // Draw main text.
caret.visible = false;
+ line_drawing_cache.clear();
int row_height = get_line_height();
int line = first_visible_line;
for (int i = 0; i < draw_amount; i++) {
@@ -810,6 +811,8 @@ void TextEdit::_notification(int p_what) {
continue;
}
+ LineDrawingCache cache_entry;
+
Dictionary color_map = _get_line_syntax_highlighting(line);
// Ensure we at least use the font color.
@@ -899,6 +902,8 @@ void TextEdit::_notification(int p_what) {
if (line_wrap_index == 0) {
// Only do these if we are on the first wrapped part of a line.
+ cache_entry.y_offset = ofs_y;
+
int gutter_offset = style_normal->get_margin(SIDE_LEFT);
for (int g = 0; g < gutters.size(); g++) {
const GutterInfo gutter = gutters[g];
@@ -1076,6 +1081,10 @@ void TextEdit::_notification(int p_what) {
int gl_size = TS->shaped_text_get_glyph_count(rid);
ofs_y += ldata->get_line_ascent(line_wrap_index);
+
+ int first_visible_char = TS->shaped_text_get_range(rid).y;
+ int last_visible_char = TS->shaped_text_get_range(rid).x;
+
int char_ofs = 0;
if (outline_size > 0 && outline_color.a > 0) {
for (int j = 0; j < gl_size; j++) {
@@ -1143,21 +1152,36 @@ void TextEdit::_notification(int p_what) {
}
}
+ bool had_glyphs_drawn = false;
for (int k = 0; k < glyphs[j].repeat; k++) {
if (!clipped && (char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) {
if (glyphs[j].font_rid != RID()) {
TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color);
+ had_glyphs_drawn = true;
} else if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
TS->draw_hex_code_box(ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color);
+ had_glyphs_drawn = true;
}
}
char_ofs += glyphs[j].advance;
}
+
+ if (had_glyphs_drawn) {
+ if (first_visible_char > glyphs[j].start) {
+ first_visible_char = glyphs[j].start;
+ } else if (last_visible_char < glyphs[j].end) {
+ last_visible_char = glyphs[j].end;
+ }
+ }
+
if ((char_ofs + char_margin) >= xmargin_end) {
break;
}
}
+ cache_entry.first_visible_chars.push_back(first_visible_char);
+ cache_entry.last_visible_chars.push_back(last_visible_char);
+
// is_line_folded
if (line_wrap_index == line_wrap_amount && line < text.size() - 1 && _is_line_hidden(line + 1)) {
int xofs = char_ofs + char_margin + ofs_x + (folded_eol_icon->get_width() / 2);
@@ -1308,6 +1332,8 @@ void TextEdit::_notification(int p_what) {
}
}
}
+
+ line_drawing_cache[line] = cache_entry;
}
if (has_focus()) {
@@ -1569,7 +1595,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
_generate_context_menu();
menu->set_position(get_screen_transform().xform(mpos));
- menu->set_size(Vector2(1, 1));
+ menu->reset_size();
menu->popup();
grab_focus();
}
@@ -1802,7 +1828,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
_generate_context_menu();
adjust_viewport_to_caret();
menu->set_position(get_screen_transform().xform(get_caret_draw_pos()));
- menu->set_size(Vector2(1, 1));
+ menu->reset_size();
menu->popup();
menu->grab_focus();
}
@@ -3457,6 +3483,49 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_
return Point2i(col, row);
}
+Point2i TextEdit::get_pos_at_line_column(int p_line, int p_column) const {
+ Rect2i rect = get_rect_at_line_column(p_line, p_column);
+ return rect.position + Vector2i(0, get_line_height());
+}
+
+Rect2i TextEdit::get_rect_at_line_column(int p_line, int p_column) const {
+ ERR_FAIL_INDEX_V(p_line, text.size(), Rect2i(-1, -1, 0, 0));
+ ERR_FAIL_COND_V(p_column < 0, Rect2i(-1, -1, 0, 0));
+ ERR_FAIL_COND_V(p_column > text[p_line].length(), Rect2i(-1, -1, 0, 0));
+
+ if (line_drawing_cache.size() == 0 || !line_drawing_cache.has(p_line)) {
+ // Line is not in the cache, which means it's outside of the viewing area.
+ return Rect2i(-1, -1, 0, 0);
+ }
+ LineDrawingCache cache_entry = line_drawing_cache[p_line];
+
+ int wrap_index = get_line_wrap_index_at_column(p_line, p_column);
+ if (wrap_index >= cache_entry.first_visible_chars.size()) {
+ // Line seems to be wrapped beyond the viewable area.
+ return Rect2i(-1, -1, 0, 0);
+ }
+
+ int first_visible_char = cache_entry.first_visible_chars[wrap_index];
+ int last_visible_char = cache_entry.last_visible_chars[wrap_index];
+ if (p_column < first_visible_char || p_column > last_visible_char) {
+ // Character is outside of the viewing area, no point calculating its position.
+ return Rect2i(-1, -1, 0, 0);
+ }
+
+ Point2i pos, size;
+ pos.y = cache_entry.y_offset + get_line_height() * wrap_index;
+ pos.x = get_total_gutter_width() + style_normal->get_margin(SIDE_LEFT) - get_h_scroll();
+
+ RID text_rid = text.get_line_data(p_line)->get_line_rid(wrap_index);
+ Vector2 col_bounds = TS->shaped_text_get_grapheme_bounds(text_rid, p_column);
+ pos.x += col_bounds.x;
+ size.x = col_bounds.y - col_bounds.x;
+
+ size.y = get_line_height();
+
+ return Rect2i(pos, size);
+}
+
int TextEdit::get_minimap_line_at_pos(const Point2i &p_pos) const {
float rows = p_pos.y;
rows -= style_normal->get_margin(SIDE_TOP);
@@ -3897,7 +3966,7 @@ void TextEdit::delete_selection() {
update();
}
-/* line wrapping. */
+/* Line wrapping. */
void TextEdit::set_line_wrapping_mode(LineWrappingMode p_wrapping_mode) {
if (line_wrapping_mode != p_wrapping_mode) {
line_wrapping_mode = p_wrapping_mode;
@@ -4278,7 +4347,7 @@ void TextEdit::add_gutter(int p_at) {
void TextEdit::remove_gutter(int p_gutter) {
ERR_FAIL_INDEX(p_gutter, gutters.size());
- gutters.remove(p_gutter);
+ gutters.remove_at(p_gutter);
for (int i = 0; i < text.size() + 1; i++) {
text.remove_gutter(p_gutter);
@@ -4701,6 +4770,9 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_word_at_pos", "position"), &TextEdit::get_word_at_pos);
ClassDB::bind_method(D_METHOD("get_line_column_at_pos", "position", "allow_out_of_bounds"), &TextEdit::get_line_column_at_pos, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("get_pos_at_line_column", "line", "column"), &TextEdit::get_pos_at_line_column);
+ ClassDB::bind_method(D_METHOD("get_rect_at_line_column", "line", "column"), &TextEdit::get_rect_at_line_column);
+
ClassDB::bind_method(D_METHOD("get_minimap_line_at_pos", "position"), &TextEdit::get_minimap_line_at_pos);
ClassDB::bind_method(D_METHOD("is_dragging_cursor"), &TextEdit::is_dragging_cursor);
@@ -4778,7 +4850,7 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("deselect"), &TextEdit::deselect);
ClassDB::bind_method(D_METHOD("delete_selection"), &TextEdit::delete_selection);
- /* line wrapping. */
+ /* Line wrapping. */
BIND_ENUM_CONSTANT(LINE_WRAPPING_NONE);
BIND_ENUM_CONSTANT(LINE_WRAPPING_BOUNDARY);
@@ -6177,7 +6249,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
String post_text = text[p_to_line].substr(p_to_column, text[p_to_line].length());
for (int i = p_from_line; i < p_to_line; i++) {
- text.remove(p_from_line + 1);
+ text.remove_at(p_from_line + 1);
}
text.set(p_from_line, pre_text + post_text, structured_text_parser(st_parser, st_args, pre_text + post_text));
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 09315ae395..42b21cbe9c 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -205,7 +205,7 @@ private:
}
bool is_hidden(int p_line) const { return text[p_line].hidden; }
void insert(int p_at, const String &p_text, const Array &p_bidi_override);
- void remove(int p_at);
+ void remove_at(int p_index);
int size() const { return text.size(); }
void clear();
@@ -271,7 +271,7 @@ private:
bool virtual_keyboard_enabled = true;
bool middle_mouse_paste_enabled = true;
- // Overridable actions
+ // Overridable actions.
String cut_copy_line = "";
// Context menu.
@@ -336,6 +336,14 @@ private:
Variant tooltip_ud;
/* Mouse */
+ struct LineDrawingCache {
+ int y_offset = 0;
+ Vector<int> first_visible_chars;
+ Vector<int> last_visible_chars;
+ };
+
+ Map<int, LineDrawingCache> line_drawing_cache;
+
int _get_char_pos_for_line(int p_px, int p_line, int p_wrap_index = 0) const;
/* Caret. */
@@ -415,7 +423,7 @@ private:
void _pre_shift_selection();
void _post_shift_selection();
- /* line wrapping. */
+ /* Line wrapping. */
LineWrappingMode line_wrapping_mode = LineWrappingMode::LINE_WRAPPING_NONE;
int wrap_at_column = 0;
@@ -455,14 +463,14 @@ private:
void _scroll_lines_up();
void _scroll_lines_down();
- // Minimap
+ // Minimap.
bool draw_minimap = false;
int minimap_width = 80;
Point2 minimap_char_size = Point2(1, 2);
int minimap_line_spacing = 1;
- // minimap scroll
+ // Minimap scroll.
bool minimap_clicked = false;
bool hovering_minimap = false;
bool dragging_minimap = false;
@@ -717,6 +725,9 @@ public:
String get_word_at_pos(const Vector2 &p_pos) const;
Point2i get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_of_bounds = true) const;
+ Point2i get_pos_at_line_column(int p_line, int p_column) const;
+ Rect2i get_rect_at_line_column(int p_line, int p_column) const;
+
int get_minimap_line_at_pos(const Point2i &p_pos) const;
bool is_dragging_cursor() const;
@@ -782,7 +793,7 @@ public:
void deselect();
void delete_selection();
- /* line wrapping. */
+ /* Line wrapping. */
void set_line_wrapping_mode(LineWrappingMode p_wrapping_mode);
LineWrappingMode get_line_wrapping_mode() const;
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 27e617bdd0..89caaaafd0 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -848,7 +848,7 @@ String TreeItem::get_button_tooltip(int p_column, int p_idx) const {
void TreeItem::erase_button(int p_column, int p_idx) {
ERR_FAIL_INDEX(p_column, cells.size());
ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
- cells.write[p_column].buttons.remove(p_idx);
+ cells.write[p_column].buttons.remove_at(p_idx);
_changed_notify(p_column);
}
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 2e4e1bd364..d4caec614a 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -171,7 +171,7 @@ private:
}
if (parent) {
if (!parent->children_cache.is_empty()) {
- parent->children_cache.remove(get_index());
+ parent->children_cache.remove_at(get_index());
}
if (parent->first_child == this) {
parent->first_child = next;
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index 44420fcc31..0d646ff2a9 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -114,7 +114,7 @@ void Node::_notification(int p_notification) {
get_multiplayer()->scene_enter_exit_notify(data.scene_file_path, this, false);
}
} break;
- case NOTIFICATION_PATH_CHANGED: {
+ case NOTIFICATION_PATH_RENAMED: {
if (data.path_cache) {
memdelete(data.path_cache);
data.path_cache = nullptr;
@@ -332,7 +332,7 @@ void Node::_move_child(Node *p_child, int p_pos, bool p_ignore_end) {
int motion_from = MIN(p_pos, p_child->data.pos);
int motion_to = MAX(p_pos, p_child->data.pos);
- data.children.remove(p_child->data.pos);
+ data.children.remove_at(p_child->data.pos);
data.children.insert(p_pos, p_child);
if (data.tree) {
@@ -899,7 +899,7 @@ void Node::set_name(const String &p_name) {
data.parent->_validate_child_name(this);
}
- propagate_notification(NOTIFICATION_PATH_CHANGED);
+ propagate_notification(NOTIFICATION_PATH_RENAMED);
if (is_inside_tree()) {
emit_signal(SNAME("renamed"));
@@ -1208,7 +1208,7 @@ void Node::remove_child(Node *p_child) {
remove_child_notify(p_child);
p_child->notification(NOTIFICATION_UNPARENTED);
- data.children.remove(idx);
+ data.children.remove_at(idx);
//update pointer and size
child_count = data.children.size();
@@ -2829,7 +2829,7 @@ void Node::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_INSTANCED);
BIND_CONSTANT(NOTIFICATION_DRAG_BEGIN);
BIND_CONSTANT(NOTIFICATION_DRAG_END);
- BIND_CONSTANT(NOTIFICATION_PATH_CHANGED);
+ BIND_CONSTANT(NOTIFICATION_PATH_RENAMED);
BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS);
BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS);
BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE);
diff --git a/scene/main/node.h b/scene/main/node.h
index 2dd32a2e1d..dc74a33580 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -256,7 +256,7 @@ public:
NOTIFICATION_INSTANCED = 20,
NOTIFICATION_DRAG_BEGIN = 21,
NOTIFICATION_DRAG_END = 22,
- NOTIFICATION_PATH_CHANGED = 23,
+ NOTIFICATION_PATH_RENAMED = 23,
//NOTIFICATION_TRANSLATION_CHANGED = 24, moved below
NOTIFICATION_INTERNAL_PROCESS = 25,
NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26,
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 48a672b310..f9e96a0784 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -55,6 +55,7 @@
#include "scene/resources/world_2d.h"
#include "scene/scene_string_names.h"
#include "servers/audio_server.h"
+#include "servers/rendering/rendering_server_globals.h"
void ViewportTexture::setup_local_to_scene() {
Node *local_scene = get_local_scene();
@@ -290,7 +291,7 @@ void Viewport::_sub_window_grab_focus(Window *p_window) {
if (p_window->get_flag(Window::FLAG_NO_FOCUS)) {
// Can only move to foreground, but no focus granted.
SubWindow sw = gui.sub_windows[index];
- gui.sub_windows.remove(index);
+ gui.sub_windows.remove_at(index);
gui.sub_windows.push_back(sw);
index = gui.sub_windows.size() - 1;
_sub_window_update_order();
@@ -318,7 +319,7 @@ void Viewport::_sub_window_grab_focus(Window *p_window) {
{ // Move to foreground.
SubWindow sw = gui.sub_windows[index];
- gui.sub_windows.remove(index);
+ gui.sub_windows.remove_at(index);
gui.sub_windows.push_back(sw);
index = gui.sub_windows.size() - 1;
_sub_window_update_order();
@@ -335,7 +336,7 @@ void Viewport::_sub_window_remove(Window *p_window) {
for (int i = 0; i < gui.sub_windows.size(); i++) {
if (gui.sub_windows[i].window == p_window) {
RS::get_singleton()->free(gui.sub_windows[i].canvas_item);
- gui.sub_windows.remove(i);
+ gui.sub_windows.remove_at(i);
break;
}
}
@@ -3473,17 +3474,60 @@ bool Viewport::is_using_xr() {
return use_xr;
}
-void Viewport::set_scale_3d(float p_scale_3d) {
+void Viewport::set_scaling_3d_mode(Scaling3DMode p_scaling_3d_mode) {
+ if (scaling_3d_mode == p_scaling_3d_mode) {
+ return;
+ }
+
+ scaling_3d_mode = p_scaling_3d_mode;
+ RS::get_singleton()->viewport_set_scaling_3d_mode(viewport, (RS::ViewportScaling3DMode)(int)p_scaling_3d_mode);
+}
+
+Viewport::Scaling3DMode Viewport::get_scaling_3d_mode() const {
+ return scaling_3d_mode;
+}
+
+void Viewport::set_scaling_3d_scale(float p_scaling_3d_scale) {
// Clamp to reasonable values that are actually useful.
// Values above 2.0 don't serve a practical purpose since the viewport
// isn't displayed with mipmaps.
- scale_3d = CLAMP(p_scale_3d, 0.1, 2.0);
+ scaling_3d_scale = CLAMP(p_scaling_3d_scale, 0.1, 2.0);
+
+ RS::get_singleton()->viewport_set_scaling_3d_scale(viewport, scaling_3d_scale);
+}
+
+float Viewport::get_scaling_3d_scale() const {
+ return scaling_3d_scale;
+}
+
+void Viewport::set_fsr_sharpness(float p_fsr_sharpness) {
+ if (fsr_sharpness == p_fsr_sharpness) {
+ return;
+ }
+
+ if (p_fsr_sharpness < 0.0f) {
+ p_fsr_sharpness = 0.0f;
+ }
- RS::get_singleton()->viewport_set_scale_3d(viewport, scale_3d);
+ fsr_sharpness = p_fsr_sharpness;
+ RS::get_singleton()->viewport_set_fsr_sharpness(viewport, p_fsr_sharpness);
}
-float Viewport::get_scale_3d() const {
- return scale_3d;
+float Viewport::get_fsr_sharpness() const {
+ return fsr_sharpness;
+}
+
+void Viewport::set_fsr_mipmap_bias(float p_fsr_mipmap_bias) {
+ if (fsr_mipmap_bias == p_fsr_mipmap_bias) {
+ return;
+ }
+
+ fsr_mipmap_bias = p_fsr_mipmap_bias;
+ RS::get_singleton()->viewport_set_fsr_mipmap_bias(viewport, p_fsr_mipmap_bias);
+}
+
+float Viewport::get_fsr_mipmap_bias() const {
+ return fsr_mipmap_bias;
}
#endif // _3D_DISABLED
@@ -3611,12 +3655,20 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_xr", "use"), &Viewport::set_use_xr);
ClassDB::bind_method(D_METHOD("is_using_xr"), &Viewport::is_using_xr);
- ClassDB::bind_method(D_METHOD("set_scale_3d", "scale"), &Viewport::set_scale_3d);
- ClassDB::bind_method(D_METHOD("get_scale_3d"), &Viewport::get_scale_3d);
+ ClassDB::bind_method(D_METHOD("set_scaling_3d_mode", "scaling_3d_mode"), &Viewport::set_scaling_3d_mode);
+ ClassDB::bind_method(D_METHOD("get_scaling_3d_mode"), &Viewport::get_scaling_3d_mode);
+
+ ClassDB::bind_method(D_METHOD("set_scaling_3d_scale", "scale"), &Viewport::set_scaling_3d_scale);
+ ClassDB::bind_method(D_METHOD("get_scaling_3d_scale"), &Viewport::get_scaling_3d_scale);
+
+ ClassDB::bind_method(D_METHOD("set_fsr_sharpness", "fsr_sharpness"), &Viewport::set_fsr_sharpness);
+ ClassDB::bind_method(D_METHOD("get_fsr_sharpness"), &Viewport::get_fsr_sharpness);
+
+ ClassDB::bind_method(D_METHOD("set_fsr_mipmap_bias", "fsr_mipmap_bias"), &Viewport::set_fsr_mipmap_bias);
+ ClassDB::bind_method(D_METHOD("get_fsr_mipmap_bias"), &Viewport::get_fsr_mipmap_bias);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_xr"), "set_use_xr", "is_using_xr");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scale_3d", PROPERTY_HINT_RANGE, "0.25,2.0,0.01"), "set_scale_3d", "get_scale_3d");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "audio_listener_enable_3d"), "set_as_audio_listener_3d", "is_audio_listener_3d");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_3d", PROPERTY_HINT_RESOURCE_TYPE, "World3D"), "set_world_3d", "get_world_3d");
@@ -3633,6 +3685,13 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_lod_threshold", "get_lod_threshold");
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
+#ifndef _3D_DISABLED
+ ADD_GROUP("Scaling 3D", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "scaling_3d_mode", PROPERTY_HINT_ENUM, "Disabled (Slowest),Bilinear (Fastest),FSR (Fast)"), "set_scaling_3d_mode", "get_scaling_3d_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scaling_3d_scale", PROPERTY_HINT_RANGE, "0.25,2.0,0.01"), "set_scaling_3d_scale", "get_scaling_3d_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fsr_mipmap_bias", PROPERTY_HINT_RANGE, "-2,2,0.1"), "set_fsr_mipmap_bias", "get_fsr_mipmap_bias");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fsr_sharpness", PROPERTY_HINT_RANGE, "0,2,0.1"), "set_fsr_sharpness", "get_fsr_sharpness");
+#endif
ADD_GROUP("Canvas Items", "canvas_item_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_repeat", PROPERTY_HINT_ENUM, "Disabled,Enabled,Mirror"), "set_default_canvas_item_texture_repeat", "get_default_canvas_item_texture_repeat");
@@ -3669,6 +3728,10 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_1024);
BIND_ENUM_CONSTANT(SHADOW_ATLAS_QUADRANT_SUBDIV_MAX);
+ BIND_ENUM_CONSTANT(SCALING_3D_MODE_BILINEAR);
+ BIND_ENUM_CONSTANT(SCALING_3D_MODE_FSR);
+ BIND_ENUM_CONSTANT(SCALING_3D_MODE_MAX);
+
BIND_ENUM_CONSTANT(MSAA_DISABLED);
BIND_ENUM_CONSTANT(MSAA_2X);
BIND_ENUM_CONSTANT(MSAA_4X);
@@ -3772,7 +3835,16 @@ Viewport::Viewport() {
ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::FLOAT, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
#ifndef _3D_DISABLED
- set_scale_3d(GLOBAL_GET("rendering/3d/viewport/scale"));
+ Viewport::Scaling3DMode scaling_3d_mode = (Viewport::Scaling3DMode)(int)GLOBAL_GET("rendering/scaling_3d/mode");
+ set_scaling_3d_mode(scaling_3d_mode);
+
+ set_scaling_3d_scale(GLOBAL_GET("rendering/scaling_3d/scale"));
+
+ float fsr_sharpness = GLOBAL_GET("rendering/scaling_3d/fsr_sharpness");
+ set_fsr_sharpness(fsr_sharpness);
+
+ float fsr_mipmap_bias = GLOBAL_GET("rendering/scaling_3d/fsr_mipmap_bias");
+ set_fsr_mipmap_bias(fsr_mipmap_bias);
#endif // _3D_DISABLED
set_sdf_oversize(sdf_oversize); // Set to server.
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 11b76b32eb..38d43e1e59 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -89,6 +89,12 @@ class Viewport : public Node {
GDCLASS(Viewport, Node);
public:
+ enum Scaling3DMode {
+ SCALING_3D_MODE_BILINEAR,
+ SCALING_3D_MODE_FSR,
+ SCALING_3D_MODE_MAX
+ };
+
enum ShadowAtlasQuadrantSubdiv {
SHADOW_ATLAS_QUADRANT_SUBDIV_DISABLED,
SHADOW_ATLAS_QUADRANT_SUBDIV_1,
@@ -284,6 +290,11 @@ private:
MSAA msaa = MSAA_DISABLED;
ScreenSpaceAA screen_space_aa = SCREEN_SPACE_AA_DISABLED;
+
+ Scaling3DMode scaling_3d_mode = SCALING_3D_MODE_BILINEAR;
+ float scaling_3d_scale = 1.0;
+ float fsr_sharpness = 0.2f;
+ float fsr_mipmap_bias = 0.0f;
bool use_debanding = false;
float lod_threshold = 1.0;
bool use_occlusion_culling = false;
@@ -504,6 +515,18 @@ public:
void set_screen_space_aa(ScreenSpaceAA p_screen_space_aa);
ScreenSpaceAA get_screen_space_aa() const;
+ void set_scaling_3d_mode(Scaling3DMode p_scaling_3d_mode);
+ Scaling3DMode get_scaling_3d_mode() const;
+
+ void set_scaling_3d_scale(float p_scaling_3d_scale);
+ float get_scaling_3d_scale() const;
+
+ void set_fsr_sharpness(float p_fsr_sharpness);
+ float get_fsr_sharpness() const;
+
+ void set_fsr_mipmap_bias(float p_fsr_mipmap_bias);
+ float get_fsr_mipmap_bias() const;
+
void set_use_debanding(bool p_use_debanding);
bool is_using_debanding() const;
@@ -586,7 +609,6 @@ public:
#ifndef _3D_DISABLED
bool use_xr = false;
- float scale_3d = 1.0;
friend class AudioListener3D;
AudioListener3D *audio_listener_3d = nullptr;
Set<AudioListener3D *> audio_listener_3d_set;
@@ -657,9 +679,6 @@ public:
void set_use_xr(bool p_use_xr);
bool is_using_xr();
-
- void set_scale_3d(float p_scale_3d);
- float get_scale_3d() const;
#endif // _3D_DISABLED
Viewport();
@@ -714,6 +733,7 @@ public:
SubViewport();
~SubViewport();
};
+VARIANT_ENUM_CAST(Viewport::Scaling3DMode);
VARIANT_ENUM_CAST(SubViewport::UpdateMode);
VARIANT_ENUM_CAST(Viewport::ShadowAtlasQuadrantSubdiv);
VARIANT_ENUM_CAST(Viewport::MSAA);
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 5da5a183f7..20f8b30dc6 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -88,6 +88,10 @@ Size2i Window::get_size() const {
return size;
}
+void Window::reset_size() {
+ set_size(Size2i());
+}
+
Size2i Window::get_real_size() const {
if (window_id != DisplayServer::INVALID_WINDOW_ID) {
return DisplayServer::get_singleton()->window_get_real_size(window_id);
@@ -1410,6 +1414,7 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "size"), &Window::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &Window::get_size);
+ ClassDB::bind_method(D_METHOD("reset_size"), &Window::reset_size);
ClassDB::bind_method(D_METHOD("get_real_size"), &Window::get_real_size);
diff --git a/scene/main/window.h b/scene/main/window.h
index def6eab7b8..0b1075ff76 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -178,6 +178,7 @@ public:
void set_size(const Size2i &p_size);
Size2i get_size() const;
+ void reset_size();
Size2i get_real_size() const;
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index d31771e71a..e3cf9183a0 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -930,7 +930,7 @@ void Animation::remove_track(int p_track) {
}
memdelete(t);
- tracks.remove(p_track);
+ tracks.remove_at(p_track);
emit_changed();
emit_signal(SceneStringNames::get_singleton()->tracks_changed);
}
@@ -1320,7 +1320,7 @@ void Animation::track_remove_key(int p_track, int p_idx) {
ERR_FAIL_COND(tt->compressed_track >= 0);
ERR_FAIL_INDEX(p_idx, tt->positions.size());
- tt->positions.remove(p_idx);
+ tt->positions.remove_at(p_idx);
} break;
case TYPE_ROTATION_3D: {
@@ -1329,7 +1329,7 @@ void Animation::track_remove_key(int p_track, int p_idx) {
ERR_FAIL_COND(rt->compressed_track >= 0);
ERR_FAIL_INDEX(p_idx, rt->rotations.size());
- rt->rotations.remove(p_idx);
+ rt->rotations.remove_at(p_idx);
} break;
case TYPE_SCALE_3D: {
@@ -1338,7 +1338,7 @@ void Animation::track_remove_key(int p_track, int p_idx) {
ERR_FAIL_COND(st->compressed_track >= 0);
ERR_FAIL_INDEX(p_idx, st->scales.size());
- st->scales.remove(p_idx);
+ st->scales.remove_at(p_idx);
} break;
case TYPE_BLEND_SHAPE: {
@@ -1347,37 +1347,37 @@ void Animation::track_remove_key(int p_track, int p_idx) {
ERR_FAIL_COND(bst->compressed_track >= 0);
ERR_FAIL_INDEX(p_idx, bst->blend_shapes.size());
- bst->blend_shapes.remove(p_idx);
+ bst->blend_shapes.remove_at(p_idx);
} break;
case TYPE_VALUE: {
ValueTrack *vt = static_cast<ValueTrack *>(t);
ERR_FAIL_INDEX(p_idx, vt->values.size());
- vt->values.remove(p_idx);
+ vt->values.remove_at(p_idx);
} break;
case TYPE_METHOD: {
MethodTrack *mt = static_cast<MethodTrack *>(t);
ERR_FAIL_INDEX(p_idx, mt->methods.size());
- mt->methods.remove(p_idx);
+ mt->methods.remove_at(p_idx);
} break;
case TYPE_BEZIER: {
BezierTrack *bz = static_cast<BezierTrack *>(t);
ERR_FAIL_INDEX(p_idx, bz->values.size());
- bz->values.remove(p_idx);
+ bz->values.remove_at(p_idx);
} break;
case TYPE_AUDIO: {
AudioTrack *ad = static_cast<AudioTrack *>(t);
ERR_FAIL_INDEX(p_idx, ad->values.size());
- ad->values.remove(p_idx);
+ ad->values.remove_at(p_idx);
} break;
case TYPE_ANIMATION: {
AnimationTrack *an = static_cast<AnimationTrack *>(t);
ERR_FAIL_INDEX(p_idx, an->values.size());
- an->values.remove(p_idx);
+ an->values.remove_at(p_idx);
} break;
}
@@ -1905,7 +1905,7 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) {
ERR_FAIL_INDEX(p_key_idx, tt->positions.size());
TKey<Vector3> key = tt->positions[p_key_idx];
key.time = p_time;
- tt->positions.remove(p_key_idx);
+ tt->positions.remove_at(p_key_idx);
_insert(p_time, tt->positions, key);
return;
}
@@ -1915,7 +1915,7 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) {
ERR_FAIL_INDEX(p_key_idx, tt->rotations.size());
TKey<Quaternion> key = tt->rotations[p_key_idx];
key.time = p_time;
- tt->rotations.remove(p_key_idx);
+ tt->rotations.remove_at(p_key_idx);
_insert(p_time, tt->rotations, key);
return;
}
@@ -1925,7 +1925,7 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) {
ERR_FAIL_INDEX(p_key_idx, tt->scales.size());
TKey<Vector3> key = tt->scales[p_key_idx];
key.time = p_time;
- tt->scales.remove(p_key_idx);
+ tt->scales.remove_at(p_key_idx);
_insert(p_time, tt->scales, key);
return;
}
@@ -1935,7 +1935,7 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) {
ERR_FAIL_INDEX(p_key_idx, tt->blend_shapes.size());
TKey<float> key = tt->blend_shapes[p_key_idx];
key.time = p_time;
- tt->blend_shapes.remove(p_key_idx);
+ tt->blend_shapes.remove_at(p_key_idx);
_insert(p_time, tt->blend_shapes, key);
return;
}
@@ -1944,7 +1944,7 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) {
ERR_FAIL_INDEX(p_key_idx, vt->values.size());
TKey<Variant> key = vt->values[p_key_idx];
key.time = p_time;
- vt->values.remove(p_key_idx);
+ vt->values.remove_at(p_key_idx);
_insert(p_time, vt->values, key);
return;
}
@@ -1953,7 +1953,7 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) {
ERR_FAIL_INDEX(p_key_idx, mt->methods.size());
MethodKey key = mt->methods[p_key_idx];
key.time = p_time;
- mt->methods.remove(p_key_idx);
+ mt->methods.remove_at(p_key_idx);
_insert(p_time, mt->methods, key);
return;
}
@@ -1962,7 +1962,7 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) {
ERR_FAIL_INDEX(p_key_idx, bt->values.size());
TKey<BezierKey> key = bt->values[p_key_idx];
key.time = p_time;
- bt->values.remove(p_key_idx);
+ bt->values.remove_at(p_key_idx);
_insert(p_time, bt->values, key);
return;
}
@@ -1971,7 +1971,7 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) {
ERR_FAIL_INDEX(p_key_idx, at->values.size());
TKey<AudioKey> key = at->values[p_key_idx];
key.time = p_time;
- at->values.remove(p_key_idx);
+ at->values.remove_at(p_key_idx);
_insert(p_time, at->values, key);
return;
}
@@ -1980,7 +1980,7 @@ void Animation::track_set_key_time(int p_track, int p_key_idx, double p_time) {
ERR_FAIL_INDEX(p_key_idx, at->values.size());
TKey<StringName> key = at->values[p_key_idx];
key.time = p_time;
- at->values.remove(p_key_idx);
+ at->values.remove_at(p_key_idx);
_insert(p_time, at->values, key);
return;
}
@@ -3679,7 +3679,7 @@ void Animation::track_move_to(int p_track, int p_to_index) {
}
Track *track = tracks.get(p_track);
- tracks.remove(p_track);
+ tracks.remove_at(p_track);
// Take into account that the position of the tracks that come after the one removed will change.
tracks.insert(p_to_index > p_track ? p_to_index - 1 : p_to_index, track);
@@ -4058,7 +4058,7 @@ void Animation::_position_track_optimize(int p_idx, real_t p_allowed_linear_err,
prev_erased = true;
}
- tt->positions.remove(i);
+ tt->positions.remove_at(i);
i--;
} else {
@@ -4093,7 +4093,7 @@ void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_angular_err
prev_erased = true;
}
- tt->rotations.remove(i);
+ tt->rotations.remove_at(i);
i--;
} else {
@@ -4127,7 +4127,7 @@ void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_linear_err) {
prev_erased = true;
}
- tt->scales.remove(i);
+ tt->scales.remove_at(i);
i--;
} else {
@@ -4162,7 +4162,7 @@ void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_linear_e
prev_erased = true;
}
- tt->blend_shapes.remove(i);
+ tt->blend_shapes.remove_at(i);
i--;
} else {
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index b530a72033..b87639de6a 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -136,7 +136,7 @@ void Curve::clean_dupes() {
for (int i = 1; i < _points.size(); ++i) {
real_t diff = _points[i - 1].pos.x - _points[i].pos.x;
if (diff <= CMP_EPSILON) {
- _points.remove(i);
+ _points.remove_at(i);
--i;
dirty = true;
}
@@ -207,7 +207,7 @@ Curve::TangentMode Curve::get_point_right_mode(int i) const {
void Curve::remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, _points.size());
- _points.remove(p_index);
+ _points.remove_at(p_index);
mark_dirty();
}
@@ -591,7 +591,7 @@ Vector2 Curve2D::get_point_out(int p_index) const {
void Curve2D::remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, points.size());
- points.remove(p_index);
+ points.remove_at(p_index);
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
}
@@ -1095,7 +1095,7 @@ Vector3 Curve3D::get_point_out(int p_index) const {
void Curve3D::remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, points.size());
- points.remove(p_index);
+ points.remove_at(p_index);
baked_cache_dirty = true;
emit_signal(CoreStringNames::get_singleton()->changed);
}
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 6cd42e1456..d88a2c557b 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -752,7 +752,7 @@ void FontData::remove_cache(int p_cache_index) {
if (cache[p_cache_index].is_valid()) {
TS->free(cache.write[p_cache_index]);
}
- cache.remove(p_cache_index);
+ cache.remove_at(p_cache_index);
emit_changed();
}
@@ -1356,8 +1356,8 @@ void Font::remove_data(int p_idx) {
data.write[p_idx]->disconnect(SNAME("changed"), callable_mp(this, &Font::_data_changed));
}
- data.remove(p_idx);
- rids.remove(p_idx);
+ data.remove_at(p_idx);
+ rids.remove_at(p_idx);
cache.clear();
cache_wrap.clear();
diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp
index 4559b4ce0a..95ec141df6 100644
--- a/scene/resources/gradient.cpp
+++ b/scene/resources/gradient.cpp
@@ -144,7 +144,7 @@ void Gradient::add_point(float p_offset, const Color &p_color) {
void Gradient::remove_point(int p_index) {
ERR_FAIL_INDEX(p_index, points.size());
ERR_FAIL_COND(points.size() <= 1);
- points.remove(p_index);
+ points.remove_at(p_index);
emit_signal(CoreStringNames::get_singleton()->changed);
}
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 3f4765d20f..c39f59d535 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -62,7 +62,7 @@ static Array _sanitize_node_pinned_properties(Node *p_node) {
if (storable_properties.has(pinned[i])) {
i++;
} else {
- pinned.remove(i);
+ pinned.remove_at(i);
}
} while (i < pinned.size());
if (pinned.is_empty()) {
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index ea3b72af1b..cead42b4e2 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -350,7 +350,7 @@ Ref<PackedScene> ResourceLoaderText::_parse_node_tag(VariantParser::ResourcePars
} else if (next_tag.name == "editable") {
if (!next_tag.fields.has("path")) {
error = ERR_FILE_CORRUPT;
- error_text = "missing 'path' field from connection tag";
+ error_text = "missing 'path' field from editable tag";
_printerr();
return Ref<PackedScene>();
}
diff --git a/scene/resources/skeleton_modification_stack_2d.cpp b/scene/resources/skeleton_modification_stack_2d.cpp
index 25c3e9d2ef..e596390f78 100644
--- a/scene/resources/skeleton_modification_stack_2d.cpp
+++ b/scene/resources/skeleton_modification_stack_2d.cpp
@@ -172,7 +172,7 @@ void SkeletonModificationStack2D::add_modification(Ref<SkeletonModification2D> p
void SkeletonModificationStack2D::delete_modification(int p_mod_idx) {
ERR_FAIL_INDEX(p_mod_idx, modifications.size());
- modifications.remove(p_mod_idx);
+ modifications.remove_at(p_mod_idx);
#ifdef TOOLS_ENABLED
set_editor_gizmos_dirty(true);
diff --git a/scene/resources/skeleton_modification_stack_3d.cpp b/scene/resources/skeleton_modification_stack_3d.cpp
index 301811f0b6..e5b7771251 100644
--- a/scene/resources/skeleton_modification_stack_3d.cpp
+++ b/scene/resources/skeleton_modification_stack_3d.cpp
@@ -133,7 +133,7 @@ void SkeletonModificationStack3D::add_modification(Ref<SkeletonModification3D> p
void SkeletonModificationStack3D::delete_modification(int p_mod_idx) {
const int modifications_size = modifications.size();
ERR_FAIL_INDEX(p_mod_idx, modifications_size);
- modifications.remove(p_mod_idx);
+ modifications.remove_at(p_mod_idx);
}
void SkeletonModificationStack3D::set_modification(int p_mod_idx, Ref<SkeletonModification3D> p_mod) {
@@ -141,7 +141,7 @@ void SkeletonModificationStack3D::set_modification(int p_mod_idx, Ref<SkeletonMo
ERR_FAIL_INDEX(p_mod_idx, modifications_size);
if (p_mod == nullptr) {
- modifications.remove(p_mod_idx);
+ modifications.remove_at(p_mod_idx);
} else {
p_mod->_setup_modification(this);
modifications[p_mod_idx] = p_mod;
diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp
index 5524d59dc7..71ed96cf15 100644
--- a/scene/resources/sprite_frames.cpp
+++ b/scene/resources/sprite_frames.cpp
@@ -56,7 +56,7 @@ void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) {
Map<StringName, Anim>::Element *E = animations.find(p_anim);
ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- E->get().frames.remove(p_idx);
+ E->get().frames.remove_at(p_idx);
emit_changed();
}
diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp
index 52a3abf74d..cfb5ac2ca6 100644
--- a/scene/resources/syntax_highlighter.cpp
+++ b/scene/resources/syntax_highlighter.cpp
@@ -501,7 +501,7 @@ void CodeHighlighter::add_color_region(const String &p_start_key, const String &
void CodeHighlighter::remove_color_region(const String &p_start_key) {
for (int i = 0; i < color_regions.size(); i++) {
if (color_regions[i].start_key == p_start_key) {
- color_regions.remove(i);
+ color_regions.remove_at(i);
break;
}
}
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 8c92445338..34fe7c0b87 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -560,7 +560,7 @@ void TileSet::move_occlusion_layer(int p_from_index, int p_to_pos) {
ERR_FAIL_INDEX(p_from_index, occlusion_layers.size());
ERR_FAIL_INDEX(p_to_pos, occlusion_layers.size() + 1);
occlusion_layers.insert(p_to_pos, occlusion_layers[p_from_index]);
- occlusion_layers.remove(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
+ occlusion_layers.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
source.value->move_occlusion_layer(p_from_index, p_to_pos);
}
@@ -570,7 +570,7 @@ void TileSet::move_occlusion_layer(int p_from_index, int p_to_pos) {
void TileSet::remove_occlusion_layer(int p_index) {
ERR_FAIL_INDEX(p_index, occlusion_layers.size());
- occlusion_layers.remove(p_index);
+ occlusion_layers.remove_at(p_index);
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
source.value->remove_occlusion_layer(p_index);
}
@@ -623,7 +623,7 @@ void TileSet::move_physics_layer(int p_from_index, int p_to_pos) {
ERR_FAIL_INDEX(p_from_index, physics_layers.size());
ERR_FAIL_INDEX(p_to_pos, physics_layers.size() + 1);
physics_layers.insert(p_to_pos, physics_layers[p_from_index]);
- physics_layers.remove(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
+ physics_layers.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
source.value->move_physics_layer(p_from_index, p_to_pos);
}
@@ -633,7 +633,7 @@ void TileSet::move_physics_layer(int p_from_index, int p_to_pos) {
void TileSet::remove_physics_layer(int p_index) {
ERR_FAIL_INDEX(p_index, physics_layers.size());
- physics_layers.remove(p_index);
+ physics_layers.remove_at(p_index);
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
source.value->remove_physics_layer(p_index);
}
@@ -698,7 +698,7 @@ void TileSet::move_terrain_set(int p_from_index, int p_to_pos) {
ERR_FAIL_INDEX(p_from_index, terrain_sets.size());
ERR_FAIL_INDEX(p_to_pos, terrain_sets.size() + 1);
terrain_sets.insert(p_to_pos, terrain_sets[p_from_index]);
- terrain_sets.remove(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
+ terrain_sets.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
source.value->move_terrain_set(p_from_index, p_to_pos);
}
@@ -709,7 +709,7 @@ void TileSet::move_terrain_set(int p_from_index, int p_to_pos) {
void TileSet::remove_terrain_set(int p_index) {
ERR_FAIL_INDEX(p_index, terrain_sets.size());
- terrain_sets.remove(p_index);
+ terrain_sets.remove_at(p_index);
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
source.value->remove_terrain_set(p_index);
}
@@ -772,7 +772,7 @@ void TileSet::move_terrain(int p_terrain_set, int p_from_index, int p_to_pos) {
ERR_FAIL_INDEX(p_from_index, terrains.size());
ERR_FAIL_INDEX(p_to_pos, terrains.size() + 1);
terrains.insert(p_to_pos, terrains[p_from_index]);
- terrains.remove(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
+ terrains.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
source.value->move_terrain(p_terrain_set, p_from_index, p_to_pos);
}
@@ -786,7 +786,7 @@ void TileSet::remove_terrain(int p_terrain_set, int p_index) {
Vector<Terrain> &terrains = terrain_sets.write[p_terrain_set].terrains;
ERR_FAIL_INDEX(p_index, terrains.size());
- terrains.remove(p_index);
+ terrains.remove_at(p_index);
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
source.value->remove_terrain(p_terrain_set, p_index);
}
@@ -941,7 +941,7 @@ void TileSet::move_navigation_layer(int p_from_index, int p_to_pos) {
ERR_FAIL_INDEX(p_from_index, navigation_layers.size());
ERR_FAIL_INDEX(p_to_pos, navigation_layers.size() + 1);
navigation_layers.insert(p_to_pos, navigation_layers[p_from_index]);
- navigation_layers.remove(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
+ navigation_layers.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
source.value->move_navigation_layer(p_from_index, p_to_pos);
}
@@ -951,7 +951,7 @@ void TileSet::move_navigation_layer(int p_from_index, int p_to_pos) {
void TileSet::remove_navigation_layer(int p_index) {
ERR_FAIL_INDEX(p_index, navigation_layers.size());
- navigation_layers.remove(p_index);
+ navigation_layers.remove_at(p_index);
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
source.value->remove_navigation_layer(p_index);
}
@@ -994,7 +994,7 @@ void TileSet::move_custom_data_layer(int p_from_index, int p_to_pos) {
ERR_FAIL_INDEX(p_from_index, custom_data_layers.size());
ERR_FAIL_INDEX(p_to_pos, custom_data_layers.size() + 1);
custom_data_layers.insert(p_to_pos, custom_data_layers[p_from_index]);
- custom_data_layers.remove(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
+ custom_data_layers.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
for (KeyValue<int, Ref<TileSetSource>> source : sources) {
source.value->move_custom_data_layer(p_from_index, p_to_pos);
}
@@ -1004,7 +1004,7 @@ void TileSet::move_custom_data_layer(int p_from_index, int p_to_pos) {
void TileSet::remove_custom_data_layer(int p_index) {
ERR_FAIL_INDEX(p_index, custom_data_layers.size());
- custom_data_layers.remove(p_index);
+ custom_data_layers.remove_at(p_index);
for (KeyValue<String, int> E : custom_data_layers_by_name) {
if (E.value == p_index) {
custom_data_layers_by_name.erase(E.key);
@@ -1340,7 +1340,7 @@ Ref<TileMapPattern> TileSet::get_pattern(int p_index) {
void TileSet::remove_pattern(int p_index) {
ERR_FAIL_INDEX(p_index, (int)patterns.size());
- patterns.remove(p_index);
+ patterns.remove_at(p_index);
emit_changed();
}
@@ -4707,12 +4707,12 @@ void TileData::move_occlusion_layer(int p_from_index, int p_to_pos) {
ERR_FAIL_INDEX(p_from_index, occluders.size());
ERR_FAIL_INDEX(p_to_pos, occluders.size() + 1);
occluders.insert(p_to_pos, occluders[p_from_index]);
- occluders.remove(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
+ occluders.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
}
void TileData::remove_occlusion_layer(int p_index) {
ERR_FAIL_INDEX(p_index, occluders.size());
- occluders.remove(p_index);
+ occluders.remove_at(p_index);
}
void TileData::add_physics_layer(int p_to_pos) {
@@ -4727,12 +4727,12 @@ void TileData::move_physics_layer(int p_from_index, int p_to_pos) {
ERR_FAIL_INDEX(p_from_index, physics.size());
ERR_FAIL_INDEX(p_to_pos, physics.size() + 1);
physics.insert(p_to_pos, physics[p_from_index]);
- physics.remove(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
+ physics.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
}
void TileData::remove_physics_layer(int p_index) {
ERR_FAIL_INDEX(p_index, physics.size());
- physics.remove(p_index);
+ physics.remove_at(p_index);
}
void TileData::add_terrain_set(int p_to_pos) {
@@ -4816,12 +4816,12 @@ void TileData::move_navigation_layer(int p_from_index, int p_to_pos) {
ERR_FAIL_INDEX(p_from_index, navigation.size());
ERR_FAIL_INDEX(p_to_pos, navigation.size() + 1);
navigation.insert(p_to_pos, navigation[p_from_index]);
- navigation.remove(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
+ navigation.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
}
void TileData::remove_navigation_layer(int p_index) {
ERR_FAIL_INDEX(p_index, navigation.size());
- navigation.remove(p_index);
+ navigation.remove_at(p_index);
}
void TileData::add_custom_data_layer(int p_to_pos) {
@@ -4836,12 +4836,12 @@ void TileData::move_custom_data_layer(int p_from_index, int p_to_pos) {
ERR_FAIL_INDEX(p_from_index, custom_data.size());
ERR_FAIL_INDEX(p_to_pos, custom_data.size() + 1);
custom_data.insert(p_to_pos, navigation[p_from_index]);
- custom_data.remove(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
+ custom_data.remove_at(p_to_pos < p_from_index ? p_from_index + 1 : p_from_index);
}
void TileData::remove_custom_data_layer(int p_index) {
ERR_FAIL_INDEX(p_index, custom_data.size());
- custom_data.remove(p_index);
+ custom_data.remove_at(p_index);
}
void TileData::reset_state() {
@@ -5019,7 +5019,7 @@ void TileData::add_collision_polygon(int p_layer_id) {
void TileData::remove_collision_polygon(int p_layer_id, int p_polygon_index) {
ERR_FAIL_INDEX(p_layer_id, physics.size());
ERR_FAIL_INDEX(p_polygon_index, physics[p_layer_id].polygons.size());
- physics.write[p_layer_id].polygons.remove(p_polygon_index);
+ physics.write[p_layer_id].polygons.remove_at(p_polygon_index);
emit_signal(SNAME("changed"));
}
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 87ff225de9..41e78e0bc8 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -367,7 +367,7 @@ String VisualShaderNodeCustom::generate_code(Shader::Mode p_mode, VisualShader::
if (!nend) {
code += "\n }";
} else {
- code.remove(code.size() - 1);
+ code.remove_at(code.size() - 1);
code += "}";
}
code += "\n";
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 774a5b1da0..f7c8f0921c 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -762,7 +762,7 @@ void AudioServer::remove_bus(int p_index) {
lock();
bus_map.erase(buses[p_index]->name);
memdelete(buses[p_index]);
- buses.remove(p_index);
+ buses.remove_at(p_index);
unlock();
emit_signal(SNAME("bus_layout_changed"));
@@ -833,7 +833,7 @@ void AudioServer::move_bus(int p_bus, int p_to_pos) {
}
Bus *bus = buses[p_bus];
- buses.remove(p_bus);
+ buses.remove_at(p_bus);
if (p_to_pos == -1) {
buses.push_back(bus);
@@ -1026,7 +1026,7 @@ void AudioServer::remove_bus_effect(int p_bus, int p_effect) {
lock();
- buses[p_bus]->effects.remove(p_effect);
+ buses[p_bus]->effects.remove_at(p_effect);
_update_bus_effects(p_bus);
unlock();
diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp
index 6f506d0f7a..8391a2ee2e 100644
--- a/servers/camera_server.cpp
+++ b/servers/camera_server.cpp
@@ -124,7 +124,7 @@ void CameraServer::remove_feed(const Ref<CameraFeed> &p_feed) {
#endif
// remove it from our array, if this results in our feed being unreferenced it will be destroyed
- feeds.remove(i);
+ feeds.remove_at(i);
// let whomever is interested know
emit_signal(SNAME("camera_feed_removed"), feed_id);
diff --git a/servers/physics_2d/godot_body_2d.cpp b/servers/physics_2d/godot_body_2d.cpp
index 9b97583300..6d1c5539aa 100644
--- a/servers/physics_2d/godot_body_2d.cpp
+++ b/servers/physics_2d/godot_body_2d.cpp
@@ -185,6 +185,9 @@ void GodotBody2D::set_param(PhysicsServer2D::BodyParameter p_param, const Varian
_update_transform_dependent();
} break;
case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: {
+ if (Math::is_zero_approx(gravity_scale)) {
+ wakeup();
+ }
gravity_scale = p_value;
} break;
case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP_MODE: {
diff --git a/servers/physics_2d/godot_body_2d.h b/servers/physics_2d/godot_body_2d.h
index d1dbf92c1b..0df93482dc 100644
--- a/servers/physics_2d/godot_body_2d.h
+++ b/servers/physics_2d/godot_body_2d.h
@@ -169,7 +169,7 @@ public:
if (index > -1) {
areas.write[index].refCount -= 1;
if (areas[index].refCount < 1) {
- areas.remove(index);
+ areas.remove_at(index);
}
}
}
diff --git a/servers/physics_2d/godot_collision_object_2d.cpp b/servers/physics_2d/godot_collision_object_2d.cpp
index 3d4ebbedcd..719d9c874a 100644
--- a/servers/physics_2d/godot_collision_object_2d.cpp
+++ b/servers/physics_2d/godot_collision_object_2d.cpp
@@ -121,7 +121,7 @@ void GodotCollisionObject2D::remove_shape(int p_index) {
shapes.write[i].bpid = 0;
}
shapes[p_index].shape->remove_owner(this);
- shapes.remove(p_index);
+ shapes.remove_at(p_index);
if (!pending_shape_update_list.in_list()) {
GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list);
diff --git a/servers/physics_3d/godot_body_3d.cpp b/servers/physics_3d/godot_body_3d.cpp
index 0e21dd303f..40d946655d 100644
--- a/servers/physics_3d/godot_body_3d.cpp
+++ b/servers/physics_3d/godot_body_3d.cpp
@@ -227,6 +227,9 @@ void GodotBody3D::set_param(PhysicsServer3D::BodyParameter p_param, const Varian
_update_transform_dependent();
} break;
case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {
+ if (Math::is_zero_approx(gravity_scale)) {
+ wakeup();
+ }
gravity_scale = p_value;
} break;
case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: {
diff --git a/servers/physics_3d/godot_body_3d.h b/servers/physics_3d/godot_body_3d.h
index ac3131ab44..bba9ec6c3a 100644
--- a/servers/physics_3d/godot_body_3d.h
+++ b/servers/physics_3d/godot_body_3d.h
@@ -163,7 +163,7 @@ public:
if (index > -1) {
areas.write[index].refCount -= 1;
if (areas[index].refCount < 1) {
- areas.remove(index);
+ areas.remove_at(index);
}
}
}
diff --git a/servers/physics_3d/godot_collision_object_3d.cpp b/servers/physics_3d/godot_collision_object_3d.cpp
index deb058b3ac..421291011b 100644
--- a/servers/physics_3d/godot_collision_object_3d.cpp
+++ b/servers/physics_3d/godot_collision_object_3d.cpp
@@ -118,7 +118,7 @@ void GodotCollisionObject3D::remove_shape(int p_index) {
shapes.write[i].bpid = 0;
}
shapes[p_index].shape->remove_owner(this);
- shapes.remove(p_index);
+ shapes.remove_at(p_index);
if (!pending_shape_update_list.in_list()) {
GodotPhysicsServer3D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list);
diff --git a/servers/physics_3d/godot_soft_body_3d.cpp b/servers/physics_3d/godot_soft_body_3d.cpp
index 231b8686f5..43d4433302 100644
--- a/servers/physics_3d/godot_soft_body_3d.cpp
+++ b/servers/physics_3d/godot_soft_body_3d.cpp
@@ -374,7 +374,7 @@ void GodotSoftBody3D::unpin_vertex(int p_index) {
uint32_t pinned_count = pinned_vertices.size();
for (uint32_t i = 0; i < pinned_count; ++i) {
if (p_index == pinned_vertices[i]) {
- pinned_vertices.remove(i);
+ pinned_vertices.remove_at(i);
if (!soft_mesh.is_null()) {
ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size());
diff --git a/servers/physics_3d/godot_soft_body_3d.h b/servers/physics_3d/godot_soft_body_3d.h
index 5198186b5d..14ddc419cf 100644
--- a/servers/physics_3d/godot_soft_body_3d.h
+++ b/servers/physics_3d/godot_soft_body_3d.h
@@ -148,7 +148,7 @@ public:
if (index > -1) {
areas.write[index].refCount -= 1;
if (areas[index].refCount < 1) {
- areas.remove(index);
+ areas.remove_at(index);
}
}
}
diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h
index cecb009aa0..3451ea2d39 100644
--- a/servers/rendering/rasterizer_dummy.h
+++ b/servers/rendering/rasterizer_dummy.h
@@ -195,7 +195,7 @@ public:
void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override {}
RID render_buffers_create() override { return RID(); }
- void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override {}
+ void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override {}
void gi_set_use_half_resolution(bool p_enable) override {}
void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override {}
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index a2fdf95c76..bdd61123df 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -152,7 +152,7 @@ public:
void erase_item(Item *p_item) {
int idx = find_item(p_item);
if (idx >= 0) {
- child_items.remove(idx);
+ child_items.remove_at(idx);
}
}
diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h
index 1971c3e781..4526354d17 100644
--- a/servers/rendering/renderer_compositor.h
+++ b/servers/rendering/renderer_compositor.h
@@ -67,6 +67,7 @@ private:
protected:
static RendererCompositor *(*_create_func)();
+ bool back_end = false;
public:
static RendererCompositor *create();
@@ -88,7 +89,7 @@ public:
virtual uint64_t get_frame_number() const = 0;
virtual double get_frame_delta_time() const = 0;
- virtual bool is_low_end() const = 0;
+ _FORCE_INLINE_ virtual bool is_low_end() const { return back_end; };
virtual bool is_xr_enabled() const;
RendererCompositor();
diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp
index b952ecbff0..4a98cf0831 100644
--- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp
+++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp
@@ -460,14 +460,6 @@ void ClusterBuilderRD::bake_cluster() {
RD::get_singleton()->draw_list_set_push_constant(draw_list, &push_constant, sizeof(ClusterBuilderSharedDataRD::ClusterRender::PushConstant));
uint32_t instances = 1;
-#if 0
- for (uint32_t j = i+1; j < element_count; j++) {
- if (elements[i].type!=elements[j].type) {
- break;
- }
- instances++;
- }
-#endif
RD::get_singleton()->draw_list_draw(draw_list, true, instances);
i += instances;
}
diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp
index fdd6939a8b..cf943901d4 100644
--- a/servers/rendering/renderer_rd/effects_rd.cpp
+++ b/servers/rendering/renderer_rd/effects_rd.cpp
@@ -237,6 +237,43 @@ RID EffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_te
return uniform_set;
}
+void EffectsRD::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) {
+ memset(&FSR_upscale.push_constant, 0, sizeof(FSRUpscalePushConstant));
+
+ int dispatch_x = (p_size.x + 15) / 16;
+ int dispatch_y = (p_size.y + 15) / 16;
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, FSR_upscale.pipeline);
+
+ FSR_upscale.push_constant.resolution_width = p_internal_size.width;
+ FSR_upscale.push_constant.resolution_height = p_internal_size.height;
+ FSR_upscale.push_constant.upscaled_width = p_size.width;
+ FSR_upscale.push_constant.upscaled_height = p_size.height;
+ FSR_upscale.push_constant.sharpness = p_fsr_upscale_sharpness;
+
+ //FSR Easc
+ FSR_upscale.push_constant.pass = FSR_UPSCALE_PASS_EASU;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_secondary_texture), 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &FSR_upscale.push_constant, sizeof(FSRUpscalePushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1);
+ RD::get_singleton()->compute_list_add_barrier(compute_list);
+
+ //FSR Rcas
+ FSR_upscale.push_constant.pass = FSR_UPSCALE_PASS_RCAS;
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_secondary_texture), 0);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_destination_texture), 1);
+
+ RD::get_singleton()->compute_list_set_push_constant(compute_list, &FSR_upscale.push_constant, sizeof(FSRUpscalePushConstant));
+
+ RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1);
+
+ RD::get_singleton()->compute_list_end(compute_list);
+}
+
void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) {
memset(&copy_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant));
@@ -1888,6 +1925,27 @@ void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) {
}
EffectsRD::EffectsRD(bool p_prefer_raster_effects) {
+ {
+ Vector<String> FSR_upscale_modes;
+
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ // MoltenVK does not support some of the operations used by the normal mode of FSR. Fallback works just fine though.
+ FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");
+#else
+ // Everyone else can use normal mode when available.
+ if (RD::get_singleton()->get_device_capabilities()->supports_fsr_half_float) {
+ FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_NORMAL\n");
+ } else {
+ FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n");
+ }
+#endif
+
+ FSR_upscale.shader.initialize(FSR_upscale_modes);
+
+ FSR_upscale.shader_version = FSR_upscale.shader.version_create();
+ FSR_upscale.pipeline = RD::get_singleton()->compute_pipeline_create(FSR_upscale.shader.version_get_shader(FSR_upscale.shader_version, 0));
+ }
+
prefer_raster_effects = p_prefer_raster_effects;
if (prefer_raster_effects) {
@@ -2523,6 +2581,7 @@ EffectsRD::~EffectsRD() {
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);
if (prefer_raster_effects) {
blur_raster.shader.version_free(blur_raster.shader_version);
bokeh.raster_shader.version_free(blur_raster.shader_version);
diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h
index 551e50ed25..6037127e82 100644
--- a/servers/rendering/renderer_rd/effects_rd.h
+++ b/servers/rendering/renderer_rd/effects_rd.h
@@ -45,6 +45,7 @@
#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"
#include "servers/rendering/renderer_rd/shaders/resolve.glsl.gen.h"
@@ -69,6 +70,28 @@ class EffectsRD {
private:
bool prefer_raster_effects;
+ enum FSRUpscalePass {
+ FSR_UPSCALE_PASS_EASU = 0,
+ FSR_UPSCALE_PASS_RCAS = 1
+ };
+
+ struct FSRUpscalePushConstant {
+ float resolution_width;
+ float resolution_height;
+ float upscaled_width;
+ float upscaled_height;
+ float sharpness;
+ int pass;
+ int _unused0, _unused1;
+ };
+
+ struct FSRUpscale {
+ FSRUpscalePushConstant push_constant;
+ FsrUpscaleShaderRD shader;
+ RID shader_version;
+ RID pipeline;
+ } FSR_upscale;
+
enum BlurRasterMode {
BLUR_MIPMAP,
@@ -754,6 +777,7 @@ private:
public:
bool get_prefer_raster_effects();
+ 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 copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID());
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);
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 6d85c1f4c1..03ce2690bf 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -1954,7 +1954,9 @@ void RenderForwardClustered::_base_uniforms_changed() {
}
void RenderForwardClustered::_update_render_base_uniform_set() {
- if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) {
+ if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version()) || base_uniform_set_updated) {
+ base_uniform_set_updated = false;
+
if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) {
RD::get_singleton()->free(render_base_uniform_set);
}
@@ -1969,18 +1971,18 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
u.binding = 1;
u.ids.resize(12);
RID *ids_ptr = u.ids.ptrw();
- ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
- ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
- ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[0] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[1] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[2] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[3] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[4] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[5] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ ids_ptr[6] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[7] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[8] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[9] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[10] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ ids_ptr[11] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
uniforms.push_back(u);
}
@@ -1999,19 +2001,19 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
RID sampler;
switch (decals_get_filter()) {
case RS::DECAL_FILTER_NEAREST: {
- sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = 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 = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = 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 = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS: {
- sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: {
- sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
}
@@ -2026,19 +2028,19 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
RID sampler;
switch (light_projectors_get_filter()) {
case RS::LIGHT_PROJECTOR_FILTER_NEAREST: {
- sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = 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 = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = 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 = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: {
- sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = 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_LINEAR_MIPMAPS_ANISOTROPIC: {
- sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
} break;
}
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index 7707d77296..d6ab4d1db2 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -129,6 +129,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
virtual void _base_uniforms_changed() override;
virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) override;
+ bool base_uniform_set_updated = false;
void _update_render_base_uniform_set();
RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture);
RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0);
@@ -603,6 +604,11 @@ protected:
virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) override;
public:
+ _FORCE_INLINE_ virtual void update_uniform_sets() override {
+ base_uniform_set_updated = true;
+ _update_render_base_uniform_set();
+ }
+
virtual GeometryInstance *geometry_instance_create(RID p_base) override;
virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override;
virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override;
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
index 559e6d5ad7..522a8e8112 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp
@@ -281,12 +281,12 @@ RendererCompositorRD::RendererCompositorRD() {
storage = memnew(RendererStorageRD);
canvas = memnew(RendererCanvasRenderRD(storage));
- uint32_t back_end = GLOBAL_GET("rendering/vulkan/rendering/back_end");
+ back_end = (bool)(int)GLOBAL_GET("rendering/vulkan/rendering/back_end");
uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE);
- if (back_end == 1 || textures_per_stage < 48) {
+ if (back_end || textures_per_stage < 48) {
scene = memnew(RendererSceneRenderImplementation::RenderForwardMobile(storage));
- } else { // back_end == 0
+ } else { // back_end == false
// default to our high end renderer
scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage));
}
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 0230c46800..f69e40e0ff 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -116,8 +116,6 @@ public:
_create_func = _create_current;
}
- virtual bool is_low_end() const { return false; }
-
static RendererCompositorRD *singleton;
RendererCompositorRD();
~RendererCompositorRD();
diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
index 807af00c8e..b6b5c90b39 100644
--- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp
@@ -3132,8 +3132,8 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = rb->width;
- tf.height = rb->height;
+ tf.width = rb->internal_width;
+ tf.height = rb->internal_height;
if (half_resolution) {
tf.width >>= 1;
tf.height >>= 1;
@@ -3146,13 +3146,13 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
PushConstant push_constant;
- push_constant.screen_size[0] = rb->width;
- push_constant.screen_size[1] = rb->height;
+ push_constant.screen_size[0] = rb->internal_width;
+ push_constant.screen_size[1] = rb->internal_height;
push_constant.z_near = p_projection.get_z_near();
push_constant.z_far = p_projection.get_z_far();
push_constant.orthogonal = p_projection.is_orthogonal();
- push_constant.proj_info[0] = -2.0f / (rb->width * p_projection.matrix[0][0]);
- push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]);
+ push_constant.proj_info[0] = -2.0f / (rb->internal_width * p_projection.matrix[0][0]);
+ push_constant.proj_info[1] = -2.0f / (rb->internal_height * p_projection.matrix[1][1]);
push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0];
push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1];
push_constant.max_voxel_gi_instances = MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size());
@@ -3344,9 +3344,9 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_
RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant));
if (rb->gi.using_half_size_gi) {
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->internal_width >> 1, rb->internal_height >> 1, 1);
} else {
- RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->internal_width, rb->internal_height, 1);
}
//do barrier later to allow oeverlap
//RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index b8e9f40bc4..ae8d91a73b 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -1503,8 +1503,8 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) {
RD::TextureFormat tf;
tf.format = _render_buffers_get_color_format(); // RD::DATA_FORMAT_R16G16B16A16_SFLOAT;
- tf.width = rb->width;
- tf.height = rb->height;
+ tf.width = rb->internal_width;
+ tf.height = rb->internal_height;
tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D;
tf.array_layers = rb->view_count;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
@@ -1515,6 +1515,10 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) {
}
tf.mipmaps = mipmaps_required;
+ rb->sss_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ tf.width = rb->internal_width;
+ tf.height = rb->internal_height;
rb->blur[0].texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
//the second one is smaller (only used for separatable part of blur)
tf.width >>= 1;
@@ -1522,8 +1526,8 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) {
tf.mipmaps--;
rb->blur[1].texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
- int base_width = rb->width;
- int base_height = rb->height;
+ int base_width = rb->internal_width;
+ int base_height = rb->internal_height;
for (uint32_t i = 0; i < mipmaps_required; i++) {
RenderBuffers::Blur::Mipmap mm;
@@ -1577,8 +1581,8 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) {
// create 4 weight textures, 2 full size, 2 half size
tf.format = RD::DATA_FORMAT_R16_SFLOAT; // We could probably use DATA_FORMAT_R8_SNORM if we don't pre-multiply by blur_size but that depends on whether we can remove DEPTH_GAP
- tf.width = rb->width;
- tf.height = rb->height;
+ tf.width = rb->internal_width;
+ tf.height = rb->internal_height;
tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D;
tf.array_layers = rb->view_count;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
@@ -1656,8 +1660,8 @@ void RendererSceneRenderRD::_allocate_depth_backbuffer_textures(RenderBuffers *r
void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) {
ERR_FAIL_COND(!rb->luminance.current.is_null());
- int w = rb->width;
- int h = rb->height;
+ int w = rb->internal_width;
+ int h = rb->internal_height;
while (true) {
w = MAX(w / 8, 1);
@@ -1709,9 +1713,26 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) {
rb->texture_fb = RID();
}
- if (rb->texture.is_valid()) {
- RD::get_singleton()->free(rb->texture);
+ if (rb->internal_texture == rb->texture && rb->internal_texture.is_valid()) {
+ RD::get_singleton()->free(rb->internal_texture);
rb->texture = RID();
+ rb->internal_texture = RID();
+ rb->upscale_texture = RID();
+ } else {
+ if (rb->texture.is_valid()) {
+ RD::get_singleton()->free(rb->texture);
+ rb->texture = RID();
+ }
+
+ if (rb->internal_texture.is_valid()) {
+ RD::get_singleton()->free(rb->internal_texture);
+ rb->internal_texture = RID();
+ }
+
+ if (rb->upscale_texture.is_valid()) {
+ RD::get_singleton()->free(rb->upscale_texture);
+ rb->upscale_texture = RID();
+ }
}
if (rb->depth_texture.is_valid()) {
@@ -1729,6 +1750,11 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) {
rb->depth_back_texture = RID();
}
+ if (rb->sss_texture.is_valid()) {
+ RD::get_singleton()->free(rb->sss_texture);
+ rb->sss_texture = RID();
+ }
+
for (int i = 0; i < 2; i++) {
for (int m = 0; m < rb->blur[i].mipmaps.size(); m++) {
// do we free the texture slice here? or is it enough to free the main texture?
@@ -1818,7 +1844,7 @@ void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatri
RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(!rb);
- bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+ bool can_use_effects = rb->internal_width >= 8 && rb->internal_height >= 8;
if (!can_use_effects) {
//just copy
@@ -1829,18 +1855,18 @@ void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatri
_allocate_blur_textures(rb);
}
- storage->get_effects()->sub_surface_scattering(rb->texture, rb->blur[0].mipmaps[0].texture, rb->depth_texture, p_camera, Size2i(rb->width, rb->height), sss_scale, sss_depth_scale, sss_quality);
+ storage->get_effects()->sub_surface_scattering(rb->internal_texture, rb->sss_texture, rb->depth_texture, p_camera, Size2i(rb->internal_width, rb->internal_height), sss_scale, sss_depth_scale, sss_quality);
}
void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive) {
RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
ERR_FAIL_COND(!rb);
- bool can_use_effects = rb->width >= 8 && rb->height >= 8;
+ bool can_use_effects = rb->internal_width >= 8 && rb->internal_height >= 8;
if (!can_use_effects) {
//just copy
- storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, RID());
+ storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, RID());
return;
}
@@ -1852,8 +1878,8 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
if (rb->ssr.depth_scaled.is_null()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
- tf.width = rb->width / 2;
- tf.height = rb->height / 2;
+ tf.width = rb->internal_width / 2;
+ tf.height = rb->internal_height / 2;
tf.texture_type = RD::TEXTURE_TYPE_2D;
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT;
@@ -1867,8 +1893,8 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
if (ssr_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED && !rb->ssr.blur_radius[0].is_valid()) {
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8_UNORM;
- tf.width = rb->width / 2;
- tf.height = rb->height / 2;
+ tf.width = rb->internal_width / 2;
+ tf.height = rb->internal_height / 2;
tf.texture_type = RD::TEXTURE_TYPE_2D;
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT;
@@ -1880,8 +1906,8 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb
_allocate_blur_textures(rb);
}
- storage->get_effects()->screen_space_reflection(rb->texture, p_normal_buffer, ssr_roughness_quality, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].mipmaps[1].texture, rb->blur[1].mipmaps[0].texture, Size2i(rb->width / 2, rb->height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection);
- storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, rb->blur[0].mipmaps[1].texture);
+ storage->get_effects()->screen_space_reflection(rb->internal_texture, p_normal_buffer, ssr_roughness_quality, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].mipmaps[1].texture, rb->blur[1].mipmaps[0].texture, Size2i(rb->internal_width / 2, rb->internal_height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection);
+ storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, rb->blur[0].mipmaps[1].texture);
}
void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection) {
@@ -1918,15 +1944,15 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
int half_width;
int half_height;
if (ssao_half_size) {
- buffer_width = (rb->width + 3) / 4;
- buffer_height = (rb->height + 3) / 4;
- half_width = (rb->width + 7) / 8;
- half_height = (rb->height + 7) / 8;
+ buffer_width = (rb->internal_width + 3) / 4;
+ buffer_height = (rb->internal_height + 3) / 4;
+ half_width = (rb->internal_width + 7) / 8;
+ half_height = (rb->internal_height + 7) / 8;
} else {
- buffer_width = (rb->width + 1) / 2;
- buffer_height = (rb->height + 1) / 2;
- half_width = (rb->width + 3) / 4;
- half_height = (rb->height + 3) / 4;
+ buffer_width = (rb->internal_width + 1) / 2;
+ buffer_height = (rb->internal_height + 1) / 2;
+ half_width = (rb->internal_width + 3) / 4;
+ half_height = (rb->internal_height + 3) / 4;
}
bool uniform_sets_are_invalid = false;
if (rb->ssao.depth.is_null()) {
@@ -1998,8 +2024,8 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
{
RD::TextureFormat tf;
tf.format = RD::DATA_FORMAT_R8_UNORM;
- tf.width = rb->width;
- tf.height = rb->height;
+ tf.width = rb->internal_width;
+ tf.height = rb->internal_height;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
rb->ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->ssao.ao_final, "SSAO Final");
@@ -2022,7 +2048,7 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen
settings.blur_passes = ssao_blur_passes;
settings.fadeout_from = ssao_fadeout_from;
settings.fadeout_to = ssao_fadeout_to;
- settings.full_screen_size = Size2i(rb->width, rb->height);
+ settings.full_screen_size = Size2i(rb->internal_width, rb->internal_height);
settings.half_screen_size = Size2i(buffer_width, buffer_height);
settings.quarter_screen_size = Size2i(half_width, half_height);
@@ -2102,9 +2128,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
EffectsRD::BokehBuffers buffers;
- // Textures we use.
- buffers.base_texture_size = Size2i(rb->width, rb->height);
- buffers.base_texture = rb->texture;
+ // Textures we use
+ buffers.base_texture_size = Size2i(rb->internal_width, rb->internal_height);
+ buffers.base_texture = rb->internal_texture;
buffers.depth_texture = rb->depth_texture;
buffers.secondary_texture = rb->blur[0].mipmaps[0].texture;
buffers.half_texture[0] = rb->blur[1].mipmaps[0].texture;
@@ -2143,9 +2169,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
double step = env->auto_exp_speed * time_step;
if (can_use_storage) {
- storage->get_effects()->luminance_reduction(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate);
+ storage->get_effects()->luminance_reduction(rb->internal_texture, Size2i(rb->internal_width, rb->internal_height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate);
} else {
- storage->get_effects()->luminance_reduction_raster(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.fb, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate);
+ storage->get_effects()->luminance_reduction_raster(rb->internal_texture, Size2i(rb->internal_width, rb->internal_height), rb->luminance.reduce, rb->luminance.fb, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate);
}
// Swap final reduce with prev luminance.
SWAP(rb->luminance.current, rb->luminance.reduce.write[rb->luminance.reduce.size() - 1]);
@@ -2188,9 +2214,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
luminance_texture = rb->luminance.current;
}
if (can_use_storage) {
- storage->get_effects()->gaussian_glow(rb->texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale);
+ storage->get_effects()->gaussian_glow(rb->internal_texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale);
} else {
- storage->get_effects()->gaussian_glow_raster(rb->texture, rb->blur[1].mipmaps[i].half_fb, rb->blur[1].mipmaps[i].half_texture, rb->blur[1].mipmaps[i].fb, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale);
+ storage->get_effects()->gaussian_glow_raster(rb->internal_texture, rb->blur[1].mipmaps[i].half_fb, rb->blur[1].mipmaps[i].half_texture, rb->blur[1].mipmaps[i].fb, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale);
}
} else {
if (can_use_storage) {
@@ -2237,7 +2263,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
}
tonemap.use_debanding = rb->use_debanding;
- tonemap.texture_size = Vector2i(rb->width, rb->height);
+ tonemap.texture_size = Vector2i(rb->internal_width, rb->internal_height);
if (env) {
tonemap.tonemap_mode = env->tone_mapper;
@@ -2268,7 +2294,15 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier();
tonemap.view_count = p_render_data->view_count;
- storage->get_effects()->tonemapper(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap);
+ storage->get_effects()->tonemapper(rb->internal_texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap);
+
+ RD::get_singleton()->draw_command_end_label();
+ }
+
+ if (can_use_effects && can_use_storage && (rb->internal_width != rb->width || rb->internal_height != rb->height)) {
+ RD::get_singleton()->draw_command_begin_label("FSR Upscale");
+
+ storage->get_effects()->fsr_upscale(rb->internal_texture, rb->upscale_texture, rb->texture, Size2i(rb->internal_width, rb->internal_height), Size2i(rb->width, rb->height), rb->fsr_sharpness);
RD::get_singleton()->draw_command_end_label();
}
@@ -2628,14 +2662,28 @@ bool RendererSceneRenderRD::_render_buffers_can_be_storage() {
return true;
}
-void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) {
+void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) {
ERR_FAIL_COND_MSG(p_view_count == 0, "Must have at least 1 view");
+ if (!_render_buffers_can_be_storage()) {
+ p_internal_height = p_height;
+ p_internal_width = p_width;
+ }
+
+ if (p_width != p_internal_width) {
+ float fsr_mipmap_bias = -log2f(p_width / p_internal_width) + p_fsr_mipmap_bias;
+ storage->sampler_rd_configure_custom(fsr_mipmap_bias);
+ update_uniform_sets();
+ }
+
RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers);
// Should we add an overrule per viewport?
+ rb->internal_width = p_internal_width;
+ rb->internal_height = p_internal_height;
rb->width = p_width;
rb->height = p_height;
+ rb->fsr_sharpness = p_fsr_sharpness;
rb->render_target = p_render_target;
rb->msaa = p_msaa;
rb->screen_space_aa = p_screen_space_aa;
@@ -2657,8 +2705,8 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
}
tf.format = _render_buffers_get_color_format();
- tf.width = rb->width;
- tf.height = rb->height;
+ tf.width = rb->internal_width; // If set to rb->width, msaa won't crash
+ tf.height = rb->internal_height; // If set to rb->width, msaa won't crash
tf.array_layers = rb->view_count; // create a layer for every view
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0) | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT;
if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) {
@@ -2666,7 +2714,17 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
}
tf.usage_bits |= RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT; // only needed when using subpasses in the mobile renderer
- rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ rb->internal_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+
+ if ((p_internal_width != p_width || p_internal_height != p_height)) {
+ tf.width = rb->width;
+ tf.height = rb->height;
+ rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ rb->upscale_texture = RD::get_singleton()->texture_create(tf, RD::TextureView());
+ } else {
+ rb->texture = rb->internal_texture;
+ rb->upscale_texture = rb->internal_texture;
+ }
}
{
@@ -2680,8 +2738,8 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
tf.format = RD::DATA_FORMAT_R32_SFLOAT;
}
- tf.width = rb->width;
- tf.height = rb->height;
+ tf.width = rb->internal_width;
+ tf.height = rb->internal_height;
tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT;
tf.array_layers = rb->view_count; // create a layer for every view
@@ -2697,16 +2755,16 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p
if (!_render_buffers_can_be_storage()) {
// ONLY USED ON MOBILE RENDERER, ONLY USED FOR POST EFFECTS!
Vector<RID> fb;
- fb.push_back(rb->texture);
+ fb.push_back(rb->internal_texture);
rb->texture_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, rb->view_count);
}
RID target_texture = storage->render_target_get_rd_texture(rb->render_target);
- rb->data->configure(rb->texture, rb->depth_texture, target_texture, rb->width, rb->height, p_msaa, p_view_count);
+ rb->data->configure(rb->internal_texture, rb->depth_texture, target_texture, p_internal_width, p_internal_height, p_msaa, p_view_count);
if (is_clustered_enabled()) {
- rb->cluster_builder->setup(Size2i(rb->width, rb->height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture);
+ rb->cluster_builder->setup(Size2i(p_internal_width, p_internal_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->internal_texture);
}
}
@@ -3796,6 +3854,18 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->volumetric_fog->fog_map, "Fog map");
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ Vector<uint8_t> dm;
+ dm.resize(target_width * target_height * volumetric_fog_depth * 4);
+ dm.fill(0);
+
+ rb->volumetric_fog->density_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm);
+ RD::get_singleton()->set_resource_name(rb->volumetric_fog->density_map, "Fog density map");
+ rb->volumetric_fog->light_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm);
+ RD::get_singleton()->set_resource_name(rb->volumetric_fog->light_map, "Fog light map");
+ rb->volumetric_fog->emissive_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm);
+ RD::get_singleton()->set_resource_name(rb->volumetric_fog->emissive_map, "Fog emissive map");
+#else
tf.format = RD::DATA_FORMAT_R32_UINT;
tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT;
rb->volumetric_fog->density_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
@@ -3807,6 +3877,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
rb->volumetric_fog->emissive_map = RD::get_singleton()->texture_create(tf, RD::TextureView());
RD::get_singleton()->set_resource_name(rb->volumetric_fog->emissive_map, "Fog emissive map");
RD::get_singleton()->texture_clear(rb->volumetric_fog->emissive_map, Color(0, 0, 0, 0), 0, 1, 0, 1);
+#endif
Vector<RD::Uniform> uniforms;
{
@@ -3872,7 +3943,11 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
{
RD::Uniform u;
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+#endif
u.binding = 1;
u.ids.push_back(rb->volumetric_fog->emissive_map);
uniforms.push_back(u);
@@ -3888,7 +3963,11 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
{
RD::Uniform u;
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+#endif
u.binding = 3;
u.ids.push_back(rb->volumetric_fog->density_map);
uniforms.push_back(u);
@@ -3896,7 +3975,11 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
{
RD::Uniform u;
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+#endif
u.binding = 4;
u.ids.push_back(rb->volumetric_fog->light_map);
uniforms.push_back(u);
@@ -4163,14 +4246,22 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
}
{
RD::Uniform u;
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+#endif
u.binding = 16;
u.ids.push_back(rb->volumetric_fog->density_map);
uniforms.push_back(u);
}
{
RD::Uniform u;
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+#endif
u.binding = 17;
u.ids.push_back(rb->volumetric_fog->light_map);
uniforms.push_back(u);
@@ -4178,7 +4269,11 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e
{
RD::Uniform u;
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
+#else
u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+#endif
u.binding = 18;
u.ids.push_back(rb->volumetric_fog->emissive_map);
uniforms.push_back(u);
@@ -4704,9 +4799,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData
if (p_render_buffers.is_valid()) {
/*
_debug_draw_cluster(p_render_buffers);
-
RENDER_TIMESTAMP("Tonemap");
-
_render_buffers_post_process_and_tonemap(&render_data);
*/
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
index 740e0e75ce..98ab1a2c3c 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h
@@ -456,7 +456,11 @@ private:
struct RenderBuffers {
RenderBufferData *data = nullptr;
- int width = 0, height = 0;
+ int internal_width = 0;
+ int internal_height = 0;
+ int width = 0;
+ int height = 0;
+ float fsr_sharpness = 0.2f;
RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED;
RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
bool use_debanding = false;
@@ -466,9 +470,12 @@ private:
uint64_t auto_exposure_version = 1;
- RID texture; //main texture for rendering to, must be filled after done rendering
+ RID sss_texture; //texture for sss. This needs to be a different resolution than blur[0]
+ RID internal_texture; //main texture for rendering to, must be filled after done rendering
+ RID texture; //upscaled version of main texture (This uses the same resource as internal_texture if there is no upscaling)
RID depth_texture; //main depth texture
RID texture_fb; // framebuffer for the main texture, ONLY USED FOR MOBILE RENDERER POST EFFECTS, DO NOT USE FOR RENDERING 3D!!!
+ RID upscale_texture; //used when upscaling internal_texture (This uses the same resource as internal_texture if there is no upscaling)
RendererSceneGIRD::SDFGI *sdfgi = nullptr;
VolumetricFog *volumetric_fog = nullptr;
@@ -1332,7 +1339,7 @@ public:
virtual RD::DataFormat _render_buffers_get_color_format();
virtual bool _render_buffers_can_be_storage();
virtual RID render_buffers_create() override;
- virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override;
+ virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override;
virtual void gi_set_use_half_resolution(bool p_enable) override;
RID render_buffers_get_depth_texture(RID p_render_buffers);
@@ -1363,6 +1370,8 @@ public:
float render_buffers_get_volumetric_fog_end(RID p_render_buffers);
float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers);
+ virtual void update_uniform_sets(){};
+
virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override;
virtual void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override;
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
index 04753d7a9b..04acc871b4 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp
@@ -1227,6 +1227,100 @@ RendererStorageRD::CanvasTexture::~CanvasTexture() {
clear_sets();
}
+void RendererStorageRD::sampler_rd_configure_custom(float p_mipmap_bias) {
+ for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
+ for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
+ RD::SamplerState sampler_state;
+ switch (i) {
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.max_lod = 0;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.max_lod = 0;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
+ sampler_state.lod_bias = p_mipmap_bias;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
+ sampler_state.lod_bias = p_mipmap_bias;
+
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
+ sampler_state.lod_bias = p_mipmap_bias;
+ sampler_state.use_anisotropy = true;
+ sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: {
+ sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR;
+ sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR;
+ if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST;
+ } else {
+ sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR;
+ }
+ sampler_state.lod_bias = p_mipmap_bias;
+ sampler_state.use_anisotropy = true;
+ sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level"));
+
+ } break;
+ default: {
+ }
+ }
+ switch (j) {
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+ sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE;
+
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_REPEAT;
+ } break;
+ case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: {
+ sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT;
+ } break;
+ default: {
+ }
+ }
+
+ if (custom_rd_samplers[i][j].is_valid()) {
+ RD::get_singleton()->free(custom_rd_samplers[i][j]);
+ }
+
+ custom_rd_samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state);
+ }
+ }
+}
+
RID RendererStorageRD::canvas_texture_allocate() {
return canvas_texture_owner.allocate_rid();
}
@@ -9774,6 +9868,9 @@ RendererStorageRD::RendererStorageRD() {
}
}
+ //custom sampler
+ sampler_rd_configure_custom(0.0f);
+
//default rd buffers
{
Vector<uint8_t> buffer;
@@ -10104,6 +10201,15 @@ RendererStorageRD::~RendererStorageRD() {
}
}
+ //custom samplers
+ for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) {
+ for (int j = 0; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) {
+ if (custom_rd_samplers[i][j].is_valid()) {
+ RD::get_singleton()->free(custom_rd_samplers[i][j]);
+ }
+ }
+ }
+
//def buffers
for (int i = 0; i < DEFAULT_RD_BUFFER_MAX; i++) {
RD::get_singleton()->free(mesh_default_rd_buffers[i]);
diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h
index 2cd3a01c66..9a64480c3e 100644
--- a/servers/rendering/renderer_rd/renderer_storage_rd.h
+++ b/servers/rendering/renderer_rd/renderer_storage_rd.h
@@ -320,6 +320,7 @@ private:
RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX];
RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
+ RID custom_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX];
RID default_rd_storage_buffer;
/* DECAL ATLAS */
@@ -1391,6 +1392,13 @@ public:
_FORCE_INLINE_ RID sampler_rd_get_default(RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat) {
return default_rd_samplers[p_filter][p_repeat];
}
+ _FORCE_INLINE_ RID sampler_rd_get_custom(RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat) {
+ return custom_rd_samplers[p_filter][p_repeat];
+ }
+
+ void sampler_rd_configure_custom(float mipmap_bias);
+
+ void sampler_rd_set_default(float p_mipmap_bias);
/* CANVAS TEXTURE API */
diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp
index b9a8947fa2..2568090918 100644
--- a/servers/rendering/renderer_rd/shader_rd.cpp
+++ b/servers/rendering/renderer_rd/shader_rd.cpp
@@ -177,6 +177,9 @@ void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, c
for (const KeyValue<StringName, CharString> &E : p_version->code_sections) {
builder.append(String("#define ") + String(E.key) + "_CODE_USED\n");
}
+#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED)
+ builder.append("#define MOLTENVK_USED\n");
+#endif
} break;
case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: {
builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment)
diff --git a/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl
new file mode 100644
index 0000000000..4e2ba84033
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl
@@ -0,0 +1,173 @@
+/*************************************************************************/
+/* fsr_upscale.glsl */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+#define A_GPU
+#define A_GLSL
+
+#ifdef MODE_FSR_UPSCALE_NORMAL
+
+#define A_HALF
+
+#endif
+
+#include "thirdparty/amd-fsr/ffx_a.h"
+
+layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in;
+
+layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D fsr_image;
+layout(set = 0, binding = 0) uniform sampler2D source_image;
+
+#define FSR_UPSCALE_PASS_TYPE_EASU 0
+#define FSR_UPSCALE_PASS_TYPE_RCAS 1
+
+layout(push_constant, binding = 1, std430) uniform Params {
+ float resolution_width;
+ float resolution_height;
+ float upscaled_width;
+ float upscaled_height;
+ float sharpness;
+ int pass;
+}
+params;
+
+AU4 Const0, Const1, Const2, Const3;
+
+#ifdef MODE_FSR_UPSCALE_FALLBACK
+
+#define FSR_EASU_F
+AF4 FsrEasuRF(AF2 p) {
+ AF4 res = textureGather(source_image, p, 0);
+ return res;
+}
+AF4 FsrEasuGF(AF2 p) {
+ AF4 res = textureGather(source_image, p, 1);
+ return res;
+}
+AF4 FsrEasuBF(AF2 p) {
+ AF4 res = textureGather(source_image, p, 2);
+ return res;
+}
+
+#define FSR_RCAS_F
+AF4 FsrRcasLoadF(ASU2 p) {
+ return AF4(texelFetch(source_image, ASU2(p), 0));
+}
+void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {}
+
+#else
+
+#define FSR_EASU_H
+AH4 FsrEasuRH(AF2 p) {
+ AH4 res = AH4(textureGather(source_image, p, 0));
+ return res;
+}
+AH4 FsrEasuGH(AF2 p) {
+ AH4 res = AH4(textureGather(source_image, p, 1));
+ return res;
+}
+AH4 FsrEasuBH(AF2 p) {
+ AH4 res = AH4(textureGather(source_image, p, 2));
+ return res;
+}
+
+#define FSR_RCAS_H
+AH4 FsrRcasLoadH(ASW2 p) {
+ return AH4(texelFetch(source_image, ASU2(p), 0));
+}
+void FsrRcasInputH(inout AH1 r, inout AH1 g, inout AH1 b) {}
+
+#endif
+
+#include "thirdparty/amd-fsr/ffx_fsr1.h"
+
+void fsr_easu_pass(AU2 pos) {
+#ifdef MODE_FSR_UPSCALE_NORMAL
+
+ AH3 Gamma2Color = AH3(0, 0, 0);
+ FsrEasuH(Gamma2Color, pos, Const0, Const1, Const2, Const3);
+ imageStore(fsr_image, ASU2(pos), AH4(Gamma2Color, 1));
+
+#else
+
+ AF3 Gamma2Color = AF3(0, 0, 0);
+ FsrEasuF(Gamma2Color, pos, Const0, Const1, Const2, Const3);
+ imageStore(fsr_image, ASU2(pos), AF4(Gamma2Color, 1));
+
+#endif
+}
+
+void fsr_rcas_pass(AU2 pos) {
+#ifdef MODE_FSR_UPSCALE_NORMAL
+
+ AH3 Gamma2Color = AH3(0, 0, 0);
+ FsrRcasH(Gamma2Color.r, Gamma2Color.g, Gamma2Color.b, pos, Const0);
+ imageStore(fsr_image, ASU2(pos), AH4(Gamma2Color, 1));
+
+#else
+
+ AF3 Gamma2Color = AF3(0, 0, 0);
+ FsrRcasF(Gamma2Color.r, Gamma2Color.g, Gamma2Color.b, pos, Const0);
+ imageStore(fsr_image, ASU2(pos), AF4(Gamma2Color, 1));
+
+#endif
+}
+
+void fsr_pass(AU2 pos) {
+ if (params.pass == FSR_UPSCALE_PASS_TYPE_EASU) {
+ fsr_easu_pass(pos);
+ } else if (params.pass == FSR_UPSCALE_PASS_TYPE_RCAS) {
+ fsr_rcas_pass(pos);
+ }
+}
+
+void main() {
+ // Clang does not like unused functions. If ffx_a.h is included in the binary, clang will throw a fit and not compile so we must configure FSR in this shader
+ if (params.pass == FSR_UPSCALE_PASS_TYPE_EASU) {
+ FsrEasuCon(Const0, Const1, Const2, Const3, params.resolution_width, params.resolution_height, params.resolution_width, params.resolution_height, params.upscaled_width, params.upscaled_height);
+ } else if (params.pass == FSR_UPSCALE_PASS_TYPE_RCAS) {
+ FsrRcasCon(Const0, params.sharpness);
+ }
+
+ AU2 gxy = ARmp8x8(gl_LocalInvocationID.x) + AU2(gl_WorkGroupID.x << 4u, gl_WorkGroupID.y << 4u);
+
+ fsr_pass(gxy);
+ gxy.x += 8u;
+ fsr_pass(gxy);
+ gxy.y += 8u;
+ fsr_pass(gxy);
+ gxy.x -= 8u;
+ fsr_pass(gxy);
+}
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
index 8e33610ae2..e4628b2d5a 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl
@@ -1757,7 +1757,11 @@ void main() {
}
}
+#ifdef MOLTENVK_USED
+ imageStore(geom_facing_grid, grid_pos, uvec4(imageLoad(geom_facing_grid, grid_pos).r | facing_bits)); //store facing bits
+#else
imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits
+#endif
if (length(emission) > 0.001) {
float lumas[6];
diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
index afc5d68776..181d3b272f 100644
--- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
+++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl
@@ -47,7 +47,13 @@ layout(push_constant, binding = 0, std430) uniform Params {
}
params;
+#ifdef MOLTENVK_USED
+layout(set = 1, binding = 1) volatile buffer emissive_only_map_buffer {
+ uint emissive_only_map[];
+};
+#else
layout(r32ui, set = 1, binding = 1) uniform volatile uimage3D emissive_only_map;
+#endif
layout(set = 1, binding = 2, std140) uniform SceneParams {
vec2 fog_frustum_size_begin;
@@ -71,8 +77,17 @@ layout(set = 1, binding = 2, std140) uniform SceneParams {
}
scene_params;
+#ifdef MOLTENVK_USED
+layout(set = 1, binding = 3) volatile buffer density_only_map_buffer {
+ uint density_only_map[];
+};
+layout(set = 1, binding = 4) volatile buffer light_only_map_buffer {
+ uint light_only_map[];
+};
+#else
layout(r32ui, set = 1, binding = 3) uniform volatile uimage3D density_only_map;
layout(r32ui, set = 1, binding = 4) uniform volatile uimage3D light_only_map;
+#endif
#ifdef MATERIAL_UNIFORMS_USED
layout(set = 2, binding = 0, std140) uniform MaterialUniforms{
@@ -115,6 +130,9 @@ void main() {
if (any(greaterThanEqual(pos, scene_params.fog_volume_size))) {
return; //do not compute
}
+#ifdef MOLTENVK_USED
+ uint lpos = pos.z * scene_params.fog_volume_size.x * scene_params.fog_volume_size.y + pos.y * scene_params.fog_volume_size.x + pos.x;
+#endif
vec3 posf = vec3(pos);
@@ -197,7 +215,11 @@ void main() {
density *= cull_mask;
if (abs(density) > 0.001) {
int final_density = int(density * DENSITY_SCALE);
+#ifdef MOLTENVK_USED
+ atomicAdd(density_only_map[lpos], uint(final_density));
+#else
imageAtomicAdd(density_only_map, pos, uint(final_density));
+#endif
#ifdef EMISSION_USED
{
@@ -207,7 +229,11 @@ void main() {
uvec3 emission_u = uvec3(emission.r * 511.0, emission.g * 511.0, emission.b * 255.0);
// R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint
uint final_emission = emission_u.r << 21 | emission_u.g << 10 | emission_u.b;
+#ifdef MOLTENVK_USED
+ uint prev_emission = atomicAdd(emissive_only_map[lpos], final_emission);
+#else
uint prev_emission = imageAtomicAdd(emissive_only_map, pos, final_emission);
+#endif
// Adding can lead to colors overflowing, so validate
uvec3 prev_emission_u = uvec3(prev_emission >> 21, (prev_emission << 11) >> 21, prev_emission % 1024);
@@ -219,7 +245,11 @@ void main() {
if (any(overflowing)) {
uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing);
uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b;
+#ifdef MOLTENVK_USED
+ atomicOr(emissive_only_map[lpos], force_max);
+#else
imageAtomicOr(emissive_only_map, pos, force_max);
+#endif
}
}
#endif
@@ -230,7 +260,11 @@ void main() {
uvec3 scattering_u = uvec3(scattering.r * 2047.0, scattering.g * 2047.0, scattering.b * 1023.0);
// R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint
uint final_scattering = scattering_u.r << 21 | scattering_u.g << 10 | scattering_u.b;
+#ifdef MOLTENVK_USED
+ uint prev_scattering = atomicAdd(light_only_map[lpos], final_scattering);
+#else
uint prev_scattering = imageAtomicAdd(light_only_map, pos, final_scattering);
+#endif
// Adding can lead to colors overflowing, so validate
uvec3 prev_scattering_u = uvec3(prev_scattering >> 21, (prev_scattering << 11) >> 21, prev_scattering % 1024);
@@ -242,7 +276,11 @@ void main() {
if (any(overflowing)) {
uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing);
uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b;
+#ifdef MOLTENVK_USED
+ atomicOr(light_only_map[lpos], force_max);
+#else
imageAtomicOr(light_only_map, pos, force_max);
+#endif
}
}
#endif // ALBEDO_USED
diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl
index 3d6fbb5653..747f88960c 100644
--- a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl
+++ b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl
@@ -190,9 +190,22 @@ params;
#ifndef MODE_COPY
layout(set = 0, binding = 15) uniform texture3D prev_density_texture;
+#ifdef MOLTENVK_USED
+layout(set = 0, binding = 16) buffer density_only_map_buffer {
+ uint density_only_map[];
+};
+layout(set = 0, binding = 17) buffer light_only_map_buffer {
+ uint light_only_map[];
+};
+layout(set = 0, binding = 18) buffer emissive_only_map_buffer {
+ uint emissive_only_map[];
+};
+#else
layout(r32ui, set = 0, binding = 16) uniform uimage3D density_only_map;
layout(r32ui, set = 0, binding = 17) uniform uimage3D light_only_map;
layout(r32ui, set = 0, binding = 18) uniform uimage3D emissive_only_map;
+#endif
+
#ifdef USE_RADIANCE_CUBEMAP_ARRAY
layout(set = 0, binding = 19) uniform textureCubeArray sky_texture;
#else
@@ -272,6 +285,9 @@ void main() {
if (any(greaterThanEqual(pos, params.fog_volume_size))) {
return; //do not compute
}
+#ifdef MOLTENVK_USED
+ uint lpos = pos.z * params.fog_volume_size.x * params.fog_volume_size.y + pos.y * params.fog_volume_size.x + pos.x;
+#endif
vec3 posf = vec3(pos);
@@ -335,15 +351,28 @@ void main() {
vec3 total_light = vec3(0.0);
float total_density = params.base_density;
+#ifdef MOLTENVK_USED
+ uint local_density = density_only_map[lpos];
+#else
uint local_density = imageLoad(density_only_map, pos).x;
+#endif
+
total_density += float(int(local_density)) / DENSITY_SCALE;
total_density = max(0.0, total_density);
+#ifdef MOLTENVK_USED
+ uint scattering_u = light_only_map[lpos];
+#else
uint scattering_u = imageLoad(light_only_map, pos).x;
+#endif
vec3 scattering = vec3(scattering_u >> 21, (scattering_u << 11) >> 21, scattering_u % 1024) / vec3(2047.0, 2047.0, 1023.0);
scattering += params.base_scattering * params.base_density;
+#ifdef MOLTENVK_USED
+ uint emission_u = emissive_only_map[lpos];
+#else
uint emission_u = imageLoad(emissive_only_map, pos).x;
+#endif
vec3 emission = vec3(emission_u >> 21, (emission_u << 11) >> 21, emission_u % 1024) / vec3(511.0, 511.0, 255.0);
emission += params.base_emission * params.base_density;
@@ -673,10 +702,16 @@ void main() {
final_density = mix(final_density, reprojected_density, reproject_amount);
imageStore(density_map, pos, final_density);
+#ifdef MOLTENVK_USED
+ density_only_map[lpos] = 0;
+ light_only_map[lpos] = 0;
+ emissive_only_map[lpos] = 0;
+#else
imageStore(density_only_map, pos, uvec4(0));
imageStore(light_only_map, pos, uvec4(0));
imageStore(emissive_only_map, pos, uvec4(0));
#endif
+#endif
#ifdef MODE_FOG
diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h
index b6e99e4be5..02c845581c 100644
--- a/servers/rendering/renderer_scene.h
+++ b/servers/rendering/renderer_scene.h
@@ -191,7 +191,7 @@ public:
virtual RID render_buffers_create() = 0;
- virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0;
+ virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0;
virtual void gi_set_use_half_resolution(bool p_enable) = 0;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 7b4e2d34df..5b834db178 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -1313,7 +1313,7 @@ void RendererSceneCull::_update_instance_visibility_dependencies(Instance *p_ins
bool needs_visibility_cull = has_visibility_range && is_geometry_instance && p_instance->array_index != -1;
if (!needs_visibility_cull && p_instance->visibility_index != -1) {
- p_instance->scenario->instance_visibility.remove(p_instance->visibility_index);
+ p_instance->scenario->instance_visibility.remove_at(p_instance->visibility_index);
p_instance->visibility_index = -1;
} else if (needs_visibility_cull && p_instance->visibility_index == -1) {
InstanceVisibilityData vd;
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index 2bfcfd462c..e51a1fc02e 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -1155,7 +1155,7 @@ public:
/* Render Buffers */
PASS0R(RID, render_buffers_create)
- PASS8(render_buffers_configure, RID, RID, int, int, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool, uint32_t)
+ PASS12(render_buffers_configure, RID, RID, int, int, int, int, float, float, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool, uint32_t)
PASS1(gi_set_use_half_resolution, bool)
/* Shadow Atlas */
diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h
index 200ddc55d4..0d71ea22da 100644
--- a/servers/rendering/renderer_scene_render.h
+++ b/servers/rendering/renderer_scene_render.h
@@ -256,7 +256,7 @@ public:
virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0;
virtual RID render_buffers_create() = 0;
- virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0;
+ virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0;
virtual void gi_set_use_half_resolution(bool p_enable) = 0;
virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0;
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index c3d57a13ad..8a14834569 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -77,18 +77,69 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
RSG::scene->free(p_viewport->render_buffers);
p_viewport->render_buffers = RID();
} else {
- float scale_3d = p_viewport->scale_3d;
- if (Engine::get_singleton()->is_editor_hint()) {
- // Ignore the 3D viewport render scaling inside of the editor.
- // The Half Resolution 3D editor viewport option should be used instead.
- scale_3d = 1.0;
+ float scaling_3d_scale = p_viewport->scaling_3d_scale;
+
+ RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode;
+ bool scaling_enabled = true;
+
+ if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && (scaling_3d_scale > 1.0)) {
+ // FSR is not design for downsampling.
+ // Throw a warning and fallback to VIEWPORT_SCALING_3D_MODE_BILINEAR
+ print_error("FSR does not support supersampling. Falling back to bilinear mode.");
+ scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR;
}
- // Clamp 3D rendering resolution to reasonable values supported on most hardware.
- // This prevents freezing the engine or outright crashing on lower-end GPUs.
- const int width = CLAMP(p_viewport->size.width * scale_3d, 1, 16384);
- const int height = CLAMP(p_viewport->size.height * scale_3d, 1, 16384);
- RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, width, height, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding, p_viewport->get_view_count());
+ if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && !p_viewport->fsr_enabled) {
+ // FSR is not actually available.
+ // Throw a warning and fallback to disable scaling
+ print_error("FSR is not available. Disabled FSR scaling 3D. Try bilinear mode.");
+ scaling_enabled = false;
+ }
+
+ if (scaling_3d_scale == 1.0) {
+ scaling_enabled = false;
+ }
+
+ int width;
+ int height;
+ int render_width;
+ int render_height;
+
+ if (scaling_enabled) {
+ switch (scaling_3d_mode) {
+ case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR:
+ // Clamp 3D rendering resolution to reasonable values supported on most hardware.
+ // This prevents freezing the engine or outright crashing on lower-end GPUs.
+ width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384);
+ height = CLAMP(p_viewport->size.height * scaling_3d_scale, 1, 16384);
+ render_width = width;
+ render_height = height;
+ break;
+ case RS::VIEWPORT_SCALING_3D_MODE_FSR:
+ width = p_viewport->size.width;
+ height = p_viewport->size.height;
+ render_width = MAX(width * scaling_3d_scale, 1.0); // width / (width * scaling)
+ render_height = MAX(height * scaling_3d_scale, 1.0);
+ break;
+ default:
+ // This is an unknown mode.
+ print_error(vformat("Unknown scaling mode: %d, disabling scaling 3D", scaling_3d_mode));
+ width = p_viewport->size.width;
+ height = p_viewport->size.height;
+ render_width = width;
+ render_height = height;
+ break;
+ }
+ } else {
+ width = p_viewport->size.width;
+ height = p_viewport->size.height;
+ render_width = width;
+ render_height = height;
+ }
+
+ p_viewport->internal_size = Size2(render_width, render_height);
+
+ RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, render_width, render_height, width, height, p_viewport->fsr_sharpness, p_viewport->fsr_mipmap_bias, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding, p_viewport->get_view_count());
}
}
}
@@ -117,7 +168,7 @@ void RendererViewport::_draw_3d(Viewport *p_viewport) {
}
float screen_lod_threshold = p_viewport->lod_threshold / float(p_viewport->size.width);
- RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas, xr_interface, &p_viewport->render_info);
+ RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->internal_size, screen_lod_threshold, p_viewport->shadow_atlas, xr_interface, &p_viewport->render_info);
RENDER_TIMESTAMP("<End Rendering 3D Scene");
}
@@ -571,7 +622,7 @@ void RendererViewport::draw_viewports() {
// override our size, make sure it matches our required size and is created as a stereo target
vp->size = xr_interface->get_render_target_size();
uint32_t view_count = xr_interface->get_view_count();
- RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count);
+ RSG::storage->render_target_set_size(vp->render_target, vp->internal_size.x, vp->internal_size.y, view_count);
// check for an external texture destination (disabled for now, not yet supported)
// RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono));
@@ -662,6 +713,8 @@ void RendererViewport::viewport_initialize(RID p_rid) {
viewport->render_target = RSG::storage->render_target_create();
viewport->shadow_atlas = RSG::scene->shadow_atlas_create();
viewport->viewport_render_direct_to_screen = false;
+
+ viewport->fsr_enabled = !RSG::rasterizer->is_low_end() && !viewport->disable_3d;
}
void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
@@ -676,18 +729,42 @@ void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) {
_configure_3d_render_buffers(viewport);
}
-void RendererViewport::viewport_set_scale_3d(RID p_viewport, float p_scale_3d) {
+void RendererViewport::viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->scaling_3d_mode = p_mode;
+ _configure_3d_render_buffers(viewport);
+}
+
+void RendererViewport::viewport_set_fsr_sharpness(RID p_viewport, float p_sharpness) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->fsr_sharpness = p_sharpness;
+ _configure_3d_render_buffers(viewport);
+}
+
+void RendererViewport::viewport_set_fsr_mipmap_bias(RID p_viewport, float p_mipmap_bias) {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+ ERR_FAIL_COND(!viewport);
+
+ viewport->fsr_mipmap_bias = p_mipmap_bias;
+ _configure_3d_render_buffers(viewport);
+}
+
+void RendererViewport::viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
// Clamp to reasonable values that are actually useful.
// Values above 2.0 don't serve a practical purpose since the viewport
// isn't displayed with mipmaps.
- if (viewport->scale_3d == CLAMP(p_scale_3d, 0.1, 2.0)) {
+ if (viewport->scaling_3d_scale == CLAMP(p_scaling_3d_scale, 0.1, 2.0)) {
return;
}
- viewport->scale_3d = CLAMP(p_scale_3d, 0.1, 2.0);
+ viewport->scaling_3d_scale = CLAMP(p_scaling_3d_scale, 0.1, 2.0);
_configure_3d_render_buffers(viewport);
}
@@ -713,6 +790,7 @@ void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_heig
ERR_FAIL_COND(!viewport);
viewport->size = Size2(p_width, p_height);
+
uint32_t view_count = viewport->get_view_count();
RSG::storage->render_target_set_size(viewport->render_target, p_width, p_height, view_count);
_configure_3d_render_buffers(viewport);
@@ -765,7 +843,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_
// if render_direct_to_screen was used, reset size and position
if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) {
RSG::storage->render_target_set_position(viewport->render_target, 0, 0);
- RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count());
+ RSG::storage->render_target_set_size(viewport->render_target, viewport->internal_size.x, viewport->internal_size.y, viewport->get_view_count());
}
viewport->viewport_to_screen_rect = Rect2();
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index f6e6cc8e84..5bb4dbbc6f 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -49,12 +49,16 @@ public:
bool use_xr; /* use xr interface to override camera positioning and projection matrices and control output */
- float scale_3d = 1.0;
-
+ Size2i internal_size;
Size2i size;
RID camera;
RID scenario;
+ RS::ViewportScaling3DMode scaling_3d_mode;
+ float scaling_3d_scale = 1.0;
+ float fsr_sharpness = 0.2f;
+ float fsr_mipmap_bias = 0.0f;
+ bool fsr_enabled;
RS::ViewportUpdateMode update_mode;
RID render_target;
RID render_target_texture;
@@ -207,7 +211,6 @@ public:
void viewport_initialize(RID p_rid);
void viewport_set_use_xr(RID p_viewport, bool p_use_xr);
- void viewport_set_scale_3d(RID p_viewport, float p_scale_3d);
void viewport_set_size(RID p_viewport, int p_width, int p_height);
@@ -216,6 +219,12 @@ public:
void viewport_set_active(RID p_viewport, bool p_active);
void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport);
+
+ void viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode);
+ void viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale);
+ void viewport_set_fsr_sharpness(RID p_viewport, float p_sharpness);
+ void viewport_set_fsr_mipmap_bias(RID p_viewport, float p_mipmap_bias);
+
void viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode);
void viewport_set_vflip(RID p_viewport, bool p_enable);
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 5eb8f1cead..563a80c12c 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -120,6 +120,7 @@ public:
// features
bool supports_multiview = false; // If true this device supports multiview options
+ bool supports_fsr_half_float = false; // If true this device supports FSR scaling 3D in half float mode, otherwise use the fallback mode
};
typedef String (*ShaderSPIRVGetCacheKeyFunction)(const Capabilities *p_capabilities);
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index f75bca600e..b50631bb21 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -528,7 +528,6 @@ public:
FUNCRIDSPLIT(viewport)
FUNC2(viewport_set_use_xr, RID, bool)
- FUNC2(viewport_set_scale_3d, RID, float)
FUNC3(viewport_set_size, RID, int, int)
FUNC2(viewport_set_active, RID, bool)
@@ -539,6 +538,11 @@ public:
FUNC3(viewport_attach_to_screen, RID, const Rect2 &, int)
FUNC2(viewport_set_render_direct_to_screen, RID, bool)
+ FUNC2(viewport_set_scaling_3d_mode, RID, ViewportScaling3DMode)
+ FUNC2(viewport_set_scaling_3d_scale, RID, float)
+ FUNC2(viewport_set_fsr_sharpness, RID, float)
+ FUNC2(viewport_set_fsr_mipmap_bias, RID, float)
+
FUNC2(viewport_set_update_mode, RID, ViewportUpdateMode)
FUNC1RC(RID, viewport_get_texture, RID)
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 1a994548d8..50719ecfc3 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -6073,7 +6073,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
_set_error("Invalid arguments to unary operator '" + get_operator_text(op->op) + "' :" + at);
return nullptr;
}
- expression.remove(i + 1);
+ expression.remove_at(i + 1);
}
} else if (is_ternary) {
@@ -6113,7 +6113,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
for (int i = 0; i < 4; i++) {
- expression.remove(next_op);
+ expression.remove_at(next_op);
}
} else {
@@ -6174,8 +6174,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
- expression.remove(next_op);
- expression.remove(next_op);
+ expression.remove_at(next_op);
+ expression.remove_at(next_op);
}
}
@@ -7190,11 +7190,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
//check return type
BlockNode *b = p_block;
- if (b && b->parent_function && p_function_info.main_function) {
- _set_error(vformat("Using 'return' in '%s' processor function results in undefined behavior!", b->parent_function->name));
- return ERR_PARSE_ERROR;
- }
-
while (b && !b->parent_function) {
b = b->parent_block;
}
@@ -7204,6 +7199,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun
return ERR_BUG;
}
+ if (b && b->parent_function && p_function_info.main_function) {
+ _set_error(vformat("Using 'return' in '%s' processor function results in undefined behavior!", b->parent_function->name));
+ return ERR_PARSE_ERROR;
+ }
+
String return_struct_name = String(b->parent_function->return_struct_name);
String array_size_string;
@@ -7441,6 +7441,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
int texture_uniforms = 0;
int texture_binding = 0;
+ int uniforms = 0;
int instance_index = 0;
ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL;
@@ -7791,6 +7792,9 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
return ERR_PARSE_ERROR;
}
uniform2.texture_order = -1;
+ if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) {
+ uniform2.order = uniforms++;
+ }
}
if (uniform2.array_size > 0) {
@@ -8769,20 +8773,6 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct
tk = _get_token();
}
- int uniforms = 0;
-
- // Need to push arrays to first place in a uniform buffer in order to correct work.
- for (Map<StringName, ShaderNode::Uniform>::Element *E = shader->uniforms.front(); E; E = E->next()) {
- if (E->get().texture_order == -1 && E->get().scope != ShaderNode::Uniform::SCOPE_INSTANCE && E->get().array_size > 0) {
- E->get().order = uniforms++;
- }
- }
- for (Map<StringName, ShaderNode::Uniform>::Element *E = shader->uniforms.front(); E; E = E->next()) {
- if (E->get().texture_order == -1 && E->get().scope != ShaderNode::Uniform::SCOPE_INSTANCE && E->get().array_size == 0) {
- E->get().order = uniforms++;
- }
- }
-
int error_line;
String error_message;
if (!_check_varying_usages(&error_line, &error_message)) {
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index ae72f47a44..7a958546b6 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2165,13 +2165,16 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("viewport_create"), &RenderingServer::viewport_create);
ClassDB::bind_method(D_METHOD("viewport_set_use_xr", "viewport", "use_xr"), &RenderingServer::viewport_set_use_xr);
- ClassDB::bind_method(D_METHOD("viewport_set_scale_3d", "viewport", "scale"), &RenderingServer::viewport_set_scale_3d);
ClassDB::bind_method(D_METHOD("viewport_set_size", "viewport", "width", "height"), &RenderingServer::viewport_set_size);
ClassDB::bind_method(D_METHOD("viewport_set_active", "viewport", "active"), &RenderingServer::viewport_set_active);
ClassDB::bind_method(D_METHOD("viewport_set_parent_viewport", "viewport", "parent_viewport"), &RenderingServer::viewport_set_parent_viewport);
ClassDB::bind_method(D_METHOD("viewport_attach_to_screen", "viewport", "rect", "screen"), &RenderingServer::viewport_attach_to_screen, DEFVAL(Rect2()), DEFVAL(DisplayServer::MAIN_WINDOW_ID));
ClassDB::bind_method(D_METHOD("viewport_set_render_direct_to_screen", "viewport", "enabled"), &RenderingServer::viewport_set_render_direct_to_screen);
+ ClassDB::bind_method(D_METHOD("viewport_set_scaling_3d_mode", "viewport", "scaling_3d_mode"), &RenderingServer::viewport_set_scaling_3d_mode);
+ ClassDB::bind_method(D_METHOD("viewport_set_scaling_3d_scale", "viewport", "scale"), &RenderingServer::viewport_set_scaling_3d_scale);
+ ClassDB::bind_method(D_METHOD("viewport_set_fsr_sharpness", "viewport", "sharpness"), &RenderingServer::viewport_set_fsr_sharpness);
+ ClassDB::bind_method(D_METHOD("viewport_set_fsr_mipmap_bias", "viewport", "mipmap_bias"), &RenderingServer::viewport_set_fsr_mipmap_bias);
ClassDB::bind_method(D_METHOD("viewport_set_update_mode", "viewport", "update_mode"), &RenderingServer::viewport_set_update_mode);
ClassDB::bind_method(D_METHOD("viewport_set_clear_mode", "viewport", "clear_mode"), &RenderingServer::viewport_set_clear_mode);
ClassDB::bind_method(D_METHOD("viewport_get_texture", "viewport"), &RenderingServer::viewport_get_texture);
@@ -2213,6 +2216,10 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("viewport_get_measured_render_time_gpu", "viewport"), &RenderingServer::viewport_get_measured_render_time_gpu);
+ BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_BILINEAR);
+ BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_FSR);
+ BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_MAX);
+
BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_DISABLED);
BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ONCE); //then goes to disabled); must be manually updated
BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_VISIBLE); // default
@@ -2837,12 +2844,6 @@ RenderingServer::RenderingServer() {
GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64);
GLOBAL_DEF("rendering/vulkan/descriptor_pools/max_descriptors_per_pool", 64);
- GLOBAL_DEF("rendering/3d/viewport/scale", 1.0);
- ProjectSettings::get_singleton()->set_custom_property_info("rendering/3d/viewport/scale",
- PropertyInfo(Variant::FLOAT,
- "rendering/3d/viewport/scale",
- PROPERTY_HINT_RANGE, "0.25,2.0,0.01"));
-
GLOBAL_DEF("rendering/shader_compiler/shader_cache/enabled", true);
GLOBAL_DEF("rendering/shader_compiler/shader_cache/compress", true);
GLOBAL_DEF("rendering/shader_compiler/shader_cache/use_zstd_compression", true);
@@ -2903,6 +2904,29 @@ RenderingServer::RenderingServer() {
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/amount", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/amount", PROPERTY_HINT_RANGE, "0.01,4.0,0.01"));
ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/limit", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/limit", PROPERTY_HINT_RANGE, "0.01,1.0,0.01"));
+ GLOBAL_DEF_RST("rendering/scaling_3d/mode", 0);
+ GLOBAL_DEF_RST("rendering/scaling_3d/scale", 1.0);
+ GLOBAL_DEF_RST("rendering/scaling_3d/fsr_sharpness", 0.2f);
+ GLOBAL_DEF_RST("rendering/scaling_3d/fsr_mipmap_bias", 0.0f);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/scaling_3d/mode",
+ PropertyInfo(Variant::INT,
+ "rendering/scaling_3d/mode",
+ PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR (Fast)"));
+
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/scaling_3d/scale",
+ PropertyInfo(Variant::FLOAT,
+ "rendering/scaling_3d/scale",
+ PROPERTY_HINT_RANGE, "0.25,2.0,0.01"));
+
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/scaling_3d/fsr_sharpness",
+ PropertyInfo(Variant::FLOAT,
+ "rendering/scaling_3d/fsr_sharpness",
+ PROPERTY_HINT_RANGE, "0,2,0.1"));
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/scaling_3d/fsr_mipmap_bias",
+ PropertyInfo(Variant::FLOAT,
+ "rendering/scaling_3d/fsr_mipmap_bias",
+ PROPERTY_HINT_RANGE, "-2,2,0.1"));
+
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)"));
GLOBAL_DEF("rendering/textures/light_projectors/filter", LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 32ec0197ee..85f92bc003 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -770,8 +770,13 @@ public:
virtual RID viewport_create() = 0;
+ enum ViewportScaling3DMode {
+ VIEWPORT_SCALING_3D_MODE_BILINEAR,
+ VIEWPORT_SCALING_3D_MODE_FSR,
+ VIEWPORT_SCALING_3D_MODE_MAX
+ };
+
virtual void viewport_set_use_xr(RID p_viewport, bool p_use_xr) = 0;
- virtual void viewport_set_scale_3d(RID p_viewport, float p_scale_3d) = 0;
virtual void viewport_set_size(RID p_viewport, int p_width, int p_height) = 0;
virtual void viewport_set_active(RID p_viewport, bool p_active) = 0;
virtual void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) = 0;
@@ -779,6 +784,11 @@ public:
virtual void viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect = Rect2(), DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) = 0;
virtual void viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) = 0;
+ virtual void viewport_set_scaling_3d_mode(RID p_viewport, ViewportScaling3DMode p_scaling_3d_mode) = 0;
+ virtual void viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale) = 0;
+ virtual void viewport_set_fsr_sharpness(RID p_viewport, float p_fsr_sharpness) = 0;
+ virtual void viewport_set_fsr_mipmap_bias(RID p_viewport, float p_fsr_mipmap_bias) = 0;
+
enum ViewportUpdateMode {
VIEWPORT_UPDATE_DISABLED,
VIEWPORT_UPDATE_ONCE, //then goes to disabled, must be manually updated
@@ -1561,6 +1571,7 @@ VARIANT_ENUM_CAST(RenderingServer::ParticlesEmitFlags);
VARIANT_ENUM_CAST(RenderingServer::ParticlesCollisionType);
VARIANT_ENUM_CAST(RenderingServer::ParticlesCollisionHeightfieldResolution);
VARIANT_ENUM_CAST(RenderingServer::FogVolumeShape);
+VARIANT_ENUM_CAST(RenderingServer::ViewportScaling3DMode);
VARIANT_ENUM_CAST(RenderingServer::ViewportUpdateMode);
VARIANT_ENUM_CAST(RenderingServer::ViewportClearMode);
VARIANT_ENUM_CAST(RenderingServer::ViewportMSAA);
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index 0a7523e33a..d6d98b4f8f 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -260,6 +260,7 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(_shaped_text_draw, "shaped", "canvas", "pos", "clip_l", "clip_r", "color");
GDVIRTUAL_BIND(_shaped_text_draw_outline, "shaped", "canvas", "pos", "clip_l", "clip_r", "outline_size", "color");
+ GDVIRTUAL_BIND(_shaped_text_get_grapheme_bounds, "shaped", "pos");
GDVIRTUAL_BIND(_shaped_text_next_grapheme_pos, "shaped", "pos");
GDVIRTUAL_BIND(_shaped_text_prev_grapheme_pos, "shaped", "pos");
@@ -1292,6 +1293,14 @@ void TextServerExtension::shaped_text_draw_outline(RID p_shaped, RID p_canvas, c
shaped_text_draw_outline(p_shaped, p_canvas, p_pos, p_clip_l, p_clip_r, p_outline_size, p_color);
}
+Vector2 TextServerExtension::shaped_text_get_grapheme_bounds(RID p_shaped, int p_pos) const {
+ Vector2 ret;
+ if (GDVIRTUAL_CALL(_shaped_text_get_grapheme_bounds, p_shaped, p_pos, ret)) {
+ return ret;
+ }
+ return TextServer::shaped_text_get_grapheme_bounds(p_shaped, p_pos);
+}
+
int TextServerExtension::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const {
int ret;
if (GDVIRTUAL_CALL(_shaped_text_next_grapheme_pos, p_shaped, p_pos, ret)) {
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index e419b4055d..a2dbd25e05 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -428,8 +428,10 @@ public:
GDVIRTUAL6C(_shaped_text_draw, RID, RID, const Vector2 &, float, float, const Color &);
GDVIRTUAL7C(_shaped_text_draw_outline, RID, RID, const Vector2 &, float, float, int, const Color &);
+ virtual Vector2 shaped_text_get_grapheme_bounds(RID p_shaped, int p_pos) const override;
virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const override;
virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) const override;
+ GDVIRTUAL2RC(Vector2, _shaped_text_get_grapheme_bounds, RID, int);
GDVIRTUAL2RC(int, _shaped_text_next_grapheme_pos, RID, int);
GDVIRTUAL2RC(int, _shaped_text_prev_grapheme_pos, RID, int);
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 9034239fe0..3b71dc1d92 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -78,7 +78,7 @@ void TextServerManager::remove_interface(const Ref<TextServer> &p_interface) {
ERR_FAIL_COND(idx == -1);
print_verbose("TextServer: Removed interface \"" + p_interface->get_name() + "\"");
emit_signal(SNAME("interface_removed"), p_interface->get_name());
- interfaces.remove(idx);
+ interfaces.remove_at(idx);
}
int TextServerManager::get_interface_count() const {
@@ -141,7 +141,7 @@ TextServerManager::~TextServerManager() {
primary_interface.unref();
}
while (interfaces.size() > 0) {
- interfaces.remove(0);
+ interfaces.remove_at(0);
}
singleton = nullptr;
}
@@ -403,6 +403,7 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("shaped_text_hit_test_grapheme", "shaped", "coords"), &TextServer::shaped_text_hit_test_grapheme);
ClassDB::bind_method(D_METHOD("shaped_text_hit_test_position", "shaped", "coords"), &TextServer::shaped_text_hit_test_position);
+ ClassDB::bind_method(D_METHOD("shaped_text_get_grapheme_bounds", "shaped", "pos"), &TextServer::shaped_text_get_grapheme_bounds);
ClassDB::bind_method(D_METHOD("shaped_text_next_grapheme_pos", "shaped", "pos"), &TextServer::shaped_text_next_grapheme_pos);
ClassDB::bind_method(D_METHOD("shaped_text_prev_grapheme_pos", "shaped", "pos"), &TextServer::shaped_text_prev_grapheme_pos);
@@ -1023,7 +1024,7 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start,
while (j < ranges.size()) {
if (Math::is_equal_approx(ranges[i].y, ranges[j].x, (real_t)UNIT_EPSILON)) {
ranges.write[i].y = ranges[j].y;
- ranges.remove(j);
+ ranges.remove_at(j);
continue;
}
j++;
@@ -1120,6 +1121,27 @@ int TextServer::shaped_text_hit_test_position(RID p_shaped, real_t p_coords) con
return 0;
}
+Vector2 TextServer::shaped_text_get_grapheme_bounds(RID p_shaped, int p_pos) const {
+ int v_size = shaped_text_get_glyph_count(p_shaped);
+ const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
+
+ real_t off = 0.0f;
+ for (int i = 0; i < v_size; i++) {
+ if ((glyphs[i].count > 0) && ((glyphs[i].index != 0) || ((glyphs[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE))) {
+ if (glyphs[i].start <= p_pos && glyphs[i].end >= p_pos) {
+ real_t advance = 0.f;
+ for (int j = 0; j < glyphs[i].count; j++) {
+ advance += glyphs[i + j].advance;
+ }
+ return Vector2(off, off + advance);
+ }
+ }
+ off += glyphs[i].advance * glyphs[i].repeat;
+ }
+
+ return Vector2();
+}
+
int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const {
int v_size = shaped_text_get_glyph_count(p_shaped);
const Glyph *glyphs = shaped_text_get_glyphs(p_shaped);
diff --git a/servers/text_server.h b/servers/text_server.h
index 4f55f881e6..5c994feaae 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -438,6 +438,7 @@ public:
virtual int shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const; // Return grapheme index.
virtual int shaped_text_hit_test_position(RID p_shaped, float p_coords) const; // Return caret/selection position.
+ virtual Vector2 shaped_text_get_grapheme_bounds(RID p_shaped, int p_pos) const;
virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const;
virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) const;
diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp
index d0367ba95e..959288497d 100644
--- a/servers/xr_server.cpp
+++ b/servers/xr_server.cpp
@@ -193,7 +193,7 @@ void XRServer::remove_interface(const Ref<XRInterface> &p_interface) {
print_verbose("XR: Removed interface" + p_interface->get_name());
emit_signal(SNAME("interface_removed"), p_interface->get_name());
- interfaces.remove(idx);
+ interfaces.remove_at(idx);
};
int XRServer::get_interface_count() const {
@@ -396,7 +396,7 @@ XRServer::~XRServer() {
primary_interface.unref();
while (interfaces.size() > 0) {
- interfaces.remove(0);
+ interfaces.remove_at(0);
}
// TODO pretty sure there is a clear function or something...
diff --git a/tests/core/io/test_image.h b/tests/core/io/test_image.h
index c4c5f1e18b..643d2f31ec 100644
--- a/tests/core/io/test_image.h
+++ b/tests/core/io/test_image.h
@@ -52,6 +52,13 @@ TEST_CASE("[Image] Instantiation") {
"A newly created image should not be compressed.");
CHECK(!image->has_mipmaps());
+ PackedByteArray image_data = image->get_data();
+ for (int i = 0; i < image_data.size(); i++) {
+ CHECK_MESSAGE(
+ image_data[i] == 0,
+ "An image created without data specified should have its data zeroed out.");
+ }
+
Ref<Image> image_copy = memnew(Image());
CHECK_MESSAGE(
image_copy->is_empty(),
@@ -62,7 +69,7 @@ TEST_CASE("[Image] Instantiation") {
image->get_data() == image_copy->get_data(),
"Duplicated images should have the same data.");
- PackedByteArray image_data = image->get_data();
+ image_data = image->get_data();
Ref<Image> image_from_data = memnew(Image(8, 4, false, Image::FORMAT_RGBA8, image_data));
CHECK_MESSAGE(
image->get_data() == image_from_data->get_data(),
@@ -214,14 +221,51 @@ TEST_CASE("[Image] Modifying pixels of an image") {
// Fill image with color
image2->fill(Color(0.5, 0.5, 0.5, 0.5));
- for (int x = 0; x < image2->get_width(); x++) {
- for (int y = 0; y < image2->get_height(); y++) {
+ for (int y = 0; y < image2->get_height(); y++) {
+ for (int x = 0; x < image2->get_width(); x++) {
CHECK_MESSAGE(
image2->get_pixel(x, y).r > 0.49,
"fill() should colorize all pixels of the image.");
}
}
+ // Fill rect with color
+ {
+ const int img_width = 3;
+ const int img_height = 3;
+ Vector<Rect2> rects;
+ rects.push_back(Rect2());
+ rects.push_back(Rect2(-5, -5, 3, 3));
+ rects.push_back(Rect2(img_width, 0, 12, 12));
+ rects.push_back(Rect2(0, img_height, 12, 12));
+ rects.push_back(Rect2(img_width + 1, img_height + 2, 12, 12));
+ rects.push_back(Rect2(1, 1, 1, 1));
+ rects.push_back(Rect2(0, 1, 2, 3));
+ rects.push_back(Rect2(-5, 0, img_width + 10, 2));
+ rects.push_back(Rect2(0, -5, 2, img_height + 10));
+ rects.push_back(Rect2(-1, -1, img_width + 1, img_height + 1));
+
+ for (const Rect2 &rect : rects) {
+ Ref<Image> img = memnew(Image(img_width, img_height, false, Image::FORMAT_RGBA8));
+ CHECK_NOTHROW_MESSAGE(
+ img->fill_rect(rect, Color(1, 1, 1, 1)),
+ "fill_rect() shouldn't throw for any rect.");
+ for (int y = 0; y < img->get_height(); y++) {
+ for (int x = 0; x < img->get_width(); x++) {
+ if (rect.abs().has_point(Point2(x, y))) {
+ CHECK_MESSAGE(
+ img->get_pixel(x, y).is_equal_approx(Color(1, 1, 1, 1)),
+ "fill_rect() should colorize all image pixels within rect bounds.");
+ } else {
+ CHECK_MESSAGE(
+ !img->get_pixel(x, y).is_equal_approx(Color(1, 1, 1, 1)),
+ "fill_rect() shouldn't colorize any image pixel out of rect bounds.");
+ }
+ }
+ }
+ }
+ }
+
// Blend two images together
image->blend_rect(image2, Rect2(Vector2(0, 0), image2->get_size()), Vector2(0, 0));
CHECK_MESSAGE(
diff --git a/tests/core/templates/test_local_vector.h b/tests/core/templates/test_local_vector.h
index eff2a16abc..67bcf515f9 100644
--- a/tests/core/templates/test_local_vector.h
+++ b/tests/core/templates/test_local_vector.h
@@ -84,25 +84,25 @@ TEST_CASE("[LocalVector] Remove.") {
vector.push_back(3);
vector.push_back(4);
- vector.remove(0);
+ vector.remove_at(0);
CHECK(vector[0] == 1);
CHECK(vector[1] == 2);
CHECK(vector[2] == 3);
CHECK(vector[3] == 4);
- vector.remove(2);
+ vector.remove_at(2);
CHECK(vector[0] == 1);
CHECK(vector[1] == 2);
CHECK(vector[2] == 4);
- vector.remove(1);
+ vector.remove_at(1);
CHECK(vector[0] == 1);
CHECK(vector[1] == 4);
- vector.remove(0);
+ vector.remove_at(0);
CHECK(vector[0] == 4);
}
@@ -117,7 +117,7 @@ TEST_CASE("[LocalVector] Remove Unordered.") {
CHECK(vector.size() == 5);
- vector.remove_unordered(0);
+ vector.remove_at_unordered(0);
CHECK(vector.size() == 4);
@@ -128,7 +128,7 @@ TEST_CASE("[LocalVector] Remove Unordered.") {
CHECK(vector.find(4) != -1);
// Now the vector is no more ordered.
- vector.remove_unordered(vector.find(3));
+ vector.remove_at_unordered(vector.find(3));
CHECK(vector.size() == 3);
@@ -137,7 +137,7 @@ TEST_CASE("[LocalVector] Remove Unordered.") {
CHECK(vector.find(2) != -1);
CHECK(vector.find(4) != -1);
- vector.remove_unordered(vector.find(2));
+ vector.remove_at_unordered(vector.find(2));
CHECK(vector.size() == 2);
@@ -145,7 +145,7 @@ TEST_CASE("[LocalVector] Remove Unordered.") {
CHECK(vector.find(1) != -1);
CHECK(vector.find(4) != -1);
- vector.remove_unordered(vector.find(4));
+ vector.remove_at_unordered(vector.find(4));
CHECK(vector.size() == 1);
@@ -153,7 +153,7 @@ TEST_CASE("[LocalVector] Remove Unordered.") {
CHECK(vector.find(1) != -1);
// Remove the last one.
- vector.remove_unordered(0);
+ vector.remove_at_unordered(0);
CHECK(vector.is_empty());
CHECK(vector.size() == 0);
@@ -193,9 +193,9 @@ TEST_CASE("[LocalVector] Size / Resize / Reserve.") {
// Capacity is supposed to change only when the size increase.
CHECK(vector.get_capacity() >= 10);
- vector.remove(0);
- vector.remove(0);
- vector.remove(0);
+ vector.remove_at(0);
+ vector.remove_at(0);
+ vector.remove_at(0);
CHECK(vector.size() == 2);
// Capacity is supposed to change only when the size increase.
diff --git a/tests/core/templates/test_vector.h b/tests/core/templates/test_vector.h
index bfdf389aa7..658ca5adf1 100644
--- a/tests/core/templates/test_vector.h
+++ b/tests/core/templates/test_vector.h
@@ -129,7 +129,7 @@ TEST_CASE("[Vector] Fill large array and modify it") {
CHECK(vector[200] == 0);
CHECK(vector[499'999] == 0x60d07);
CHECK(vector[999'999] == 0x60d07);
- vector.remove(200);
+ vector.remove_at(200);
CHECK(vector[200] == 0x60d07);
vector.clear();
@@ -145,7 +145,7 @@ TEST_CASE("[Vector] Copy creation") {
vector.push_back(4);
Vector<int> vector_other = Vector<int>(vector);
- vector_other.remove(0);
+ vector_other.remove_at(0);
CHECK(vector_other[0] == 1);
CHECK(vector_other[1] == 2);
CHECK(vector_other[2] == 3);
@@ -168,7 +168,7 @@ TEST_CASE("[Vector] Duplicate") {
vector.push_back(4);
Vector<int> vector_other = vector.duplicate();
- vector_other.remove(0);
+ vector_other.remove_at(0);
CHECK(vector_other[0] == 1);
CHECK(vector_other[1] == 2);
CHECK(vector_other[2] == 3);
@@ -302,7 +302,7 @@ TEST_CASE("[Vector] Find, has") {
CHECK(!vector.has(5));
}
-TEST_CASE("[Vector] Remove") {
+TEST_CASE("[Vector] Remove at") {
Vector<int> vector;
vector.push_back(0);
vector.push_back(1);
@@ -310,30 +310,30 @@ TEST_CASE("[Vector] Remove") {
vector.push_back(3);
vector.push_back(4);
- vector.remove(0);
+ vector.remove_at(0);
CHECK(vector[0] == 1);
CHECK(vector[1] == 2);
CHECK(vector[2] == 3);
CHECK(vector[3] == 4);
- vector.remove(2);
+ vector.remove_at(2);
CHECK(vector[0] == 1);
CHECK(vector[1] == 2);
CHECK(vector[2] == 4);
- vector.remove(1);
+ vector.remove_at(1);
CHECK(vector[0] == 1);
CHECK(vector[1] == 4);
- vector.remove(0);
+ vector.remove_at(0);
CHECK(vector[0] == 4);
}
-TEST_CASE("[Vector] Remove and find") {
+TEST_CASE("[Vector] Remove at and find") {
Vector<int> vector;
vector.push_back(0);
vector.push_back(1);
@@ -343,7 +343,7 @@ TEST_CASE("[Vector] Remove and find") {
CHECK(vector.size() == 5);
- vector.remove(0);
+ vector.remove_at(0);
CHECK(vector.size() == 4);
@@ -353,7 +353,7 @@ TEST_CASE("[Vector] Remove and find") {
CHECK(vector.find(3) != -1);
CHECK(vector.find(4) != -1);
- vector.remove(vector.find(3));
+ vector.remove_at(vector.find(3));
CHECK(vector.size() == 3);
@@ -362,7 +362,7 @@ TEST_CASE("[Vector] Remove and find") {
CHECK(vector.find(2) != -1);
CHECK(vector.find(4) != -1);
- vector.remove(vector.find(2));
+ vector.remove_at(vector.find(2));
CHECK(vector.size() == 2);
@@ -370,14 +370,14 @@ TEST_CASE("[Vector] Remove and find") {
CHECK(vector.find(1) != -1);
CHECK(vector.find(4) != -1);
- vector.remove(vector.find(4));
+ vector.remove_at(vector.find(4));
CHECK(vector.size() == 1);
CHECK(vector.find(4) == -1);
CHECK(vector.find(1) != -1);
- vector.remove(0);
+ vector.remove_at(0);
CHECK(vector.is_empty());
CHECK(vector.size() == 0);
@@ -412,9 +412,9 @@ TEST_CASE("[Vector] Size, resize, reserve") {
CHECK(vector.size() == 5);
- vector.remove(0);
- vector.remove(0);
- vector.remove(0);
+ vector.remove_at(0);
+ vector.remove_at(0);
+ vector.remove_at(0);
CHECK(vector.size() == 2);
diff --git a/tests/core/variant/test_array.h b/tests/core/variant/test_array.h
index 298bd2ff63..e2e84f2962 100644
--- a/tests/core/variant/test_array.h
+++ b/tests/core/variant/test_array.h
@@ -129,20 +129,20 @@ TEST_CASE("[Array] has() and count()") {
CHECK(arr.count(2) == 0);
}
-TEST_CASE("[Array] remove()") {
+TEST_CASE("[Array] remove_at()") {
Array arr;
arr.push_back(1);
arr.push_back(2);
- arr.remove(0);
+ arr.remove_at(0);
CHECK(arr.size() == 1);
CHECK(int(arr[0]) == 2);
- arr.remove(0);
+ arr.remove_at(0);
CHECK(arr.size() == 0);
- // The array is now empty; try to use `remove()` again.
+ // The array is now empty; try to use `remove_at()` again.
// Normally, this prints an error message so we silence it.
ERR_PRINT_OFF;
- arr.remove(0);
+ arr.remove_at(0);
ERR_PRINT_ON;
CHECK(arr.size() == 0);
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 6ebcffb7ae..03e9885bd0 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -5,6 +5,18 @@ respective folder names. Use two empty lines to separate categories for
readability.
+## amd-fsr
+
+Upstream: https://github.com/GPUOpen-Effects/FidelityFX-FSR
+Version: 1.0.2 (a21ffb8f6c13233ba336352bdff293894c706575, 2021)
+License: MIT
+
+Files extracted from upstream source:
+
+- `ffx_a.h` and `ffx_fsr1.h` from `ffx-fsr`
+- `license.txt`
+
+
## basis_universal
- Upstream: https://github.com/BinomialLLC/basis_universal
diff --git a/thirdparty/amd-fsr/ffx_a.h b/thirdparty/amd-fsr/ffx_a.h
new file mode 100644
index 0000000000..d04bff55cb
--- /dev/null
+++ b/thirdparty/amd-fsr/ffx_a.h
@@ -0,0 +1,2656 @@
+//==============================================================================================================================
+//
+// [A] SHADER PORTABILITY 1.20210629
+//
+//==============================================================================================================================
+// FidelityFX Super Resolution Sample
+//
+// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//------------------------------------------------------------------------------------------------------------------------------
+// MIT LICENSE
+// ===========
+// Copyright (c) 2014 Michal Drobot (for concepts used in "FLOAT APPROXIMATIONS").
+// -----------
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+// -----------
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
+// Software.
+// -----------
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//------------------------------------------------------------------------------------------------------------------------------
+// ABOUT
+// =====
+// Common central point for high-level shading language and C portability for various shader headers.
+//------------------------------------------------------------------------------------------------------------------------------
+// DEFINES
+// =======
+// A_CPU ..... Include the CPU related code.
+// A_GPU ..... Include the GPU related code.
+// A_GLSL .... Using GLSL.
+// A_HLSL .... Using HLSL.
+// A_HLSL_6_2 Using HLSL 6.2 with new 'uint16_t' and related types (requires '-enable-16bit-types').
+// A_NO_16_BIT_CAST Don't use instructions that are not availabe in SPIR-V (needed for running A_HLSL_6_2 on Vulkan)
+// A_GCC ..... Using a GCC compatible compiler (else assume MSVC compatible compiler by default).
+// =======
+// A_BYTE .... Support 8-bit integer.
+// A_HALF .... Support 16-bit integer and floating point.
+// A_LONG .... Support 64-bit integer.
+// A_DUBL .... Support 64-bit floating point.
+// =======
+// A_WAVE .... Support wave-wide operations.
+//------------------------------------------------------------------------------------------------------------------------------
+// To get #include "ffx_a.h" working in GLSL use '#extension GL_GOOGLE_include_directive:require'.
+//------------------------------------------------------------------------------------------------------------------------------
+// SIMPLIFIED TYPE SYSTEM
+// ======================
+// - All ints will be unsigned with exception of when signed is required.
+// - Type naming simplified and shortened "A<type><#components>",
+// - H = 16-bit float (half)
+// - F = 32-bit float (float)
+// - D = 64-bit float (double)
+// - P = 1-bit integer (predicate, not using bool because 'B' is used for byte)
+// - B = 8-bit integer (byte)
+// - W = 16-bit integer (word)
+// - U = 32-bit integer (unsigned)
+// - L = 64-bit integer (long)
+// - Using "AS<type><#components>" for signed when required.
+//------------------------------------------------------------------------------------------------------------------------------
+// TODO
+// ====
+// - Make sure 'ALerp*(a,b,m)' does 'b*m+(-a*m+a)' (2 ops).
+//------------------------------------------------------------------------------------------------------------------------------
+// CHANGE LOG
+// ==========
+// 20200914 - Expanded wave ops and prx code.
+// 20200713 - Added [ZOL] section, fixed serious bugs in sRGB and Rec.709 color conversion code, etc.
+//==============================================================================================================================
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// COMMON
+//==============================================================================================================================
+#define A_2PI 6.28318530718
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+//
+// CPU
+//
+//
+//==============================================================================================================================
+#ifdef A_CPU
+ // Supporting user defined overrides.
+ #ifndef A_RESTRICT
+ #define A_RESTRICT __restrict
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifndef A_STATIC
+ #define A_STATIC static
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ // Same types across CPU and GPU.
+ // Predicate uses 32-bit integer (C friendly bool).
+ typedef uint32_t AP1;
+ typedef float AF1;
+ typedef double AD1;
+ typedef uint8_t AB1;
+ typedef uint16_t AW1;
+ typedef uint32_t AU1;
+ typedef uint64_t AL1;
+ typedef int8_t ASB1;
+ typedef int16_t ASW1;
+ typedef int32_t ASU1;
+ typedef int64_t ASL1;
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AD1_(a) ((AD1)(a))
+ #define AF1_(a) ((AF1)(a))
+ #define AL1_(a) ((AL1)(a))
+ #define AU1_(a) ((AU1)(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ASL1_(a) ((ASL1)(a))
+ #define ASU1_(a) ((ASU1)(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC AU1 AU1_AF1(AF1 a){union{AF1 f;AU1 u;}bits;bits.f=a;return bits.u;}
+//------------------------------------------------------------------------------------------------------------------------------
+ #define A_TRUE 1
+ #define A_FALSE 0
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+// CPU/GPU PORTING
+//
+//------------------------------------------------------------------------------------------------------------------------------
+// Get CPU and GPU to share all setup code, without duplicate code paths.
+// This uses a lower-case prefix for special vector constructs.
+// - In C restrict pointers are used.
+// - In the shading language, in/inout/out arguments are used.
+// This depends on the ability to access a vector value in both languages via array syntax (aka color[2]).
+//==============================================================================================================================
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// VECTOR ARGUMENT/RETURN/INITIALIZATION PORTABILITY
+//==============================================================================================================================
+ #define retAD2 AD1 *A_RESTRICT
+ #define retAD3 AD1 *A_RESTRICT
+ #define retAD4 AD1 *A_RESTRICT
+ #define retAF2 AF1 *A_RESTRICT
+ #define retAF3 AF1 *A_RESTRICT
+ #define retAF4 AF1 *A_RESTRICT
+ #define retAL2 AL1 *A_RESTRICT
+ #define retAL3 AL1 *A_RESTRICT
+ #define retAL4 AL1 *A_RESTRICT
+ #define retAU2 AU1 *A_RESTRICT
+ #define retAU3 AU1 *A_RESTRICT
+ #define retAU4 AU1 *A_RESTRICT
+//------------------------------------------------------------------------------------------------------------------------------
+ #define inAD2 AD1 *A_RESTRICT
+ #define inAD3 AD1 *A_RESTRICT
+ #define inAD4 AD1 *A_RESTRICT
+ #define inAF2 AF1 *A_RESTRICT
+ #define inAF3 AF1 *A_RESTRICT
+ #define inAF4 AF1 *A_RESTRICT
+ #define inAL2 AL1 *A_RESTRICT
+ #define inAL3 AL1 *A_RESTRICT
+ #define inAL4 AL1 *A_RESTRICT
+ #define inAU2 AU1 *A_RESTRICT
+ #define inAU3 AU1 *A_RESTRICT
+ #define inAU4 AU1 *A_RESTRICT
+//------------------------------------------------------------------------------------------------------------------------------
+ #define inoutAD2 AD1 *A_RESTRICT
+ #define inoutAD3 AD1 *A_RESTRICT
+ #define inoutAD4 AD1 *A_RESTRICT
+ #define inoutAF2 AF1 *A_RESTRICT
+ #define inoutAF3 AF1 *A_RESTRICT
+ #define inoutAF4 AF1 *A_RESTRICT
+ #define inoutAL2 AL1 *A_RESTRICT
+ #define inoutAL3 AL1 *A_RESTRICT
+ #define inoutAL4 AL1 *A_RESTRICT
+ #define inoutAU2 AU1 *A_RESTRICT
+ #define inoutAU3 AU1 *A_RESTRICT
+ #define inoutAU4 AU1 *A_RESTRICT
+//------------------------------------------------------------------------------------------------------------------------------
+ #define outAD2 AD1 *A_RESTRICT
+ #define outAD3 AD1 *A_RESTRICT
+ #define outAD4 AD1 *A_RESTRICT
+ #define outAF2 AF1 *A_RESTRICT
+ #define outAF3 AF1 *A_RESTRICT
+ #define outAF4 AF1 *A_RESTRICT
+ #define outAL2 AL1 *A_RESTRICT
+ #define outAL3 AL1 *A_RESTRICT
+ #define outAL4 AL1 *A_RESTRICT
+ #define outAU2 AU1 *A_RESTRICT
+ #define outAU3 AU1 *A_RESTRICT
+ #define outAU4 AU1 *A_RESTRICT
+//------------------------------------------------------------------------------------------------------------------------------
+ #define varAD2(x) AD1 x[2]
+ #define varAD3(x) AD1 x[3]
+ #define varAD4(x) AD1 x[4]
+ #define varAF2(x) AF1 x[2]
+ #define varAF3(x) AF1 x[3]
+ #define varAF4(x) AF1 x[4]
+ #define varAL2(x) AL1 x[2]
+ #define varAL3(x) AL1 x[3]
+ #define varAL4(x) AL1 x[4]
+ #define varAU2(x) AU1 x[2]
+ #define varAU3(x) AU1 x[3]
+ #define varAU4(x) AU1 x[4]
+//------------------------------------------------------------------------------------------------------------------------------
+ #define initAD2(x,y) {x,y}
+ #define initAD3(x,y,z) {x,y,z}
+ #define initAD4(x,y,z,w) {x,y,z,w}
+ #define initAF2(x,y) {x,y}
+ #define initAF3(x,y,z) {x,y,z}
+ #define initAF4(x,y,z,w) {x,y,z,w}
+ #define initAL2(x,y) {x,y}
+ #define initAL3(x,y,z) {x,y,z}
+ #define initAL4(x,y,z,w) {x,y,z,w}
+ #define initAU2(x,y) {x,y}
+ #define initAU3(x,y,z) {x,y,z}
+ #define initAU4(x,y,z,w) {x,y,z,w}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// SCALAR RETURN OPS
+//------------------------------------------------------------------------------------------------------------------------------
+// TODO
+// ====
+// - Replace transcendentals with manual versions.
+//==============================================================================================================================
+ #ifdef A_GCC
+ A_STATIC AD1 AAbsD1(AD1 a){return __builtin_fabs(a);}
+ A_STATIC AF1 AAbsF1(AF1 a){return __builtin_fabsf(a);}
+ A_STATIC AU1 AAbsSU1(AU1 a){return AU1_(__builtin_abs(ASU1_(a)));}
+ A_STATIC AL1 AAbsSL1(AL1 a){return AL1_(__builtin_llabs(ASL1_(a)));}
+ #else
+ A_STATIC AD1 AAbsD1(AD1 a){return fabs(a);}
+ A_STATIC AF1 AAbsF1(AF1 a){return fabsf(a);}
+ A_STATIC AU1 AAbsSU1(AU1 a){return AU1_(abs(ASU1_(a)));}
+ A_STATIC AL1 AAbsSL1(AL1 a){return AL1_(labs((long)ASL1_(a)));}
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifdef A_GCC
+ A_STATIC AD1 ACosD1(AD1 a){return __builtin_cos(a);}
+ A_STATIC AF1 ACosF1(AF1 a){return __builtin_cosf(a);}
+ #else
+ A_STATIC AD1 ACosD1(AD1 a){return cos(a);}
+ A_STATIC AF1 ACosF1(AF1 a){return cosf(a);}
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC AD1 ADotD2(inAD2 a,inAD2 b){return a[0]*b[0]+a[1]*b[1];}
+ A_STATIC AD1 ADotD3(inAD3 a,inAD3 b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];}
+ A_STATIC AD1 ADotD4(inAD4 a,inAD4 b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3];}
+ A_STATIC AF1 ADotF2(inAF2 a,inAF2 b){return a[0]*b[0]+a[1]*b[1];}
+ A_STATIC AF1 ADotF3(inAF3 a,inAF3 b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2];}
+ A_STATIC AF1 ADotF4(inAF4 a,inAF4 b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3];}
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifdef A_GCC
+ A_STATIC AD1 AExp2D1(AD1 a){return __builtin_exp2(a);}
+ A_STATIC AF1 AExp2F1(AF1 a){return __builtin_exp2f(a);}
+ #else
+ A_STATIC AD1 AExp2D1(AD1 a){return exp2(a);}
+ A_STATIC AF1 AExp2F1(AF1 a){return exp2f(a);}
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifdef A_GCC
+ A_STATIC AD1 AFloorD1(AD1 a){return __builtin_floor(a);}
+ A_STATIC AF1 AFloorF1(AF1 a){return __builtin_floorf(a);}
+ #else
+ A_STATIC AD1 AFloorD1(AD1 a){return floor(a);}
+ A_STATIC AF1 AFloorF1(AF1 a){return floorf(a);}
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC AD1 ALerpD1(AD1 a,AD1 b,AD1 c){return b*c+(-a*c+a);}
+ A_STATIC AF1 ALerpF1(AF1 a,AF1 b,AF1 c){return b*c+(-a*c+a);}
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifdef A_GCC
+ A_STATIC AD1 ALog2D1(AD1 a){return __builtin_log2(a);}
+ A_STATIC AF1 ALog2F1(AF1 a){return __builtin_log2f(a);}
+ #else
+ A_STATIC AD1 ALog2D1(AD1 a){return log2(a);}
+ A_STATIC AF1 ALog2F1(AF1 a){return log2f(a);}
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC AD1 AMaxD1(AD1 a,AD1 b){return a>b?a:b;}
+ A_STATIC AF1 AMaxF1(AF1 a,AF1 b){return a>b?a:b;}
+ A_STATIC AL1 AMaxL1(AL1 a,AL1 b){return a>b?a:b;}
+ A_STATIC AU1 AMaxU1(AU1 a,AU1 b){return a>b?a:b;}
+//------------------------------------------------------------------------------------------------------------------------------
+ // These follow the convention that A integer types don't have signage, until they are operated on.
+ A_STATIC AL1 AMaxSL1(AL1 a,AL1 b){return (ASL1_(a)>ASL1_(b))?a:b;}
+ A_STATIC AU1 AMaxSU1(AU1 a,AU1 b){return (ASU1_(a)>ASU1_(b))?a:b;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC AD1 AMinD1(AD1 a,AD1 b){return a<b?a:b;}
+ A_STATIC AF1 AMinF1(AF1 a,AF1 b){return a<b?a:b;}
+ A_STATIC AL1 AMinL1(AL1 a,AL1 b){return a<b?a:b;}
+ A_STATIC AU1 AMinU1(AU1 a,AU1 b){return a<b?a:b;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC AL1 AMinSL1(AL1 a,AL1 b){return (ASL1_(a)<ASL1_(b))?a:b;}
+ A_STATIC AU1 AMinSU1(AU1 a,AU1 b){return (ASU1_(a)<ASU1_(b))?a:b;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC AD1 ARcpD1(AD1 a){return 1.0/a;}
+ A_STATIC AF1 ARcpF1(AF1 a){return 1.0f/a;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC AL1 AShrSL1(AL1 a,AL1 b){return AL1_(ASL1_(a)>>ASL1_(b));}
+ A_STATIC AU1 AShrSU1(AU1 a,AU1 b){return AU1_(ASU1_(a)>>ASU1_(b));}
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifdef A_GCC
+ A_STATIC AD1 ASinD1(AD1 a){return __builtin_sin(a);}
+ A_STATIC AF1 ASinF1(AF1 a){return __builtin_sinf(a);}
+ #else
+ A_STATIC AD1 ASinD1(AD1 a){return sin(a);}
+ A_STATIC AF1 ASinF1(AF1 a){return sinf(a);}
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifdef A_GCC
+ A_STATIC AD1 ASqrtD1(AD1 a){return __builtin_sqrt(a);}
+ A_STATIC AF1 ASqrtF1(AF1 a){return __builtin_sqrtf(a);}
+ #else
+ A_STATIC AD1 ASqrtD1(AD1 a){return sqrt(a);}
+ A_STATIC AF1 ASqrtF1(AF1 a){return sqrtf(a);}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// SCALAR RETURN OPS - DEPENDENT
+//==============================================================================================================================
+ A_STATIC AD1 AClampD1(AD1 x,AD1 n,AD1 m){return AMaxD1(n,AMinD1(x,m));}
+ A_STATIC AF1 AClampF1(AF1 x,AF1 n,AF1 m){return AMaxF1(n,AMinF1(x,m));}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC AD1 AFractD1(AD1 a){return a-AFloorD1(a);}
+ A_STATIC AF1 AFractF1(AF1 a){return a-AFloorF1(a);}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC AD1 APowD1(AD1 a,AD1 b){return AExp2D1(b*ALog2D1(a));}
+ A_STATIC AF1 APowF1(AF1 a,AF1 b){return AExp2F1(b*ALog2F1(a));}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC AD1 ARsqD1(AD1 a){return ARcpD1(ASqrtD1(a));}
+ A_STATIC AF1 ARsqF1(AF1 a){return ARcpF1(ASqrtF1(a));}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC AD1 ASatD1(AD1 a){return AMinD1(1.0,AMaxD1(0.0,a));}
+ A_STATIC AF1 ASatF1(AF1 a){return AMinF1(1.0f,AMaxF1(0.0f,a));}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// VECTOR OPS
+//------------------------------------------------------------------------------------------------------------------------------
+// These are added as needed for production or prototyping, so not necessarily a complete set.
+// They follow a convention of taking in a destination and also returning the destination value to increase utility.
+//==============================================================================================================================
+ A_STATIC retAD2 opAAbsD2(outAD2 d,inAD2 a){d[0]=AAbsD1(a[0]);d[1]=AAbsD1(a[1]);return d;}
+ A_STATIC retAD3 opAAbsD3(outAD3 d,inAD3 a){d[0]=AAbsD1(a[0]);d[1]=AAbsD1(a[1]);d[2]=AAbsD1(a[2]);return d;}
+ A_STATIC retAD4 opAAbsD4(outAD4 d,inAD4 a){d[0]=AAbsD1(a[0]);d[1]=AAbsD1(a[1]);d[2]=AAbsD1(a[2]);d[3]=AAbsD1(a[3]);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC retAF2 opAAbsF2(outAF2 d,inAF2 a){d[0]=AAbsF1(a[0]);d[1]=AAbsF1(a[1]);return d;}
+ A_STATIC retAF3 opAAbsF3(outAF3 d,inAF3 a){d[0]=AAbsF1(a[0]);d[1]=AAbsF1(a[1]);d[2]=AAbsF1(a[2]);return d;}
+ A_STATIC retAF4 opAAbsF4(outAF4 d,inAF4 a){d[0]=AAbsF1(a[0]);d[1]=AAbsF1(a[1]);d[2]=AAbsF1(a[2]);d[3]=AAbsF1(a[3]);return d;}
+//==============================================================================================================================
+ A_STATIC retAD2 opAAddD2(outAD2 d,inAD2 a,inAD2 b){d[0]=a[0]+b[0];d[1]=a[1]+b[1];return d;}
+ A_STATIC retAD3 opAAddD3(outAD3 d,inAD3 a,inAD3 b){d[0]=a[0]+b[0];d[1]=a[1]+b[1];d[2]=a[2]+b[2];return d;}
+ A_STATIC retAD4 opAAddD4(outAD4 d,inAD4 a,inAD4 b){d[0]=a[0]+b[0];d[1]=a[1]+b[1];d[2]=a[2]+b[2];d[3]=a[3]+b[3];return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC retAF2 opAAddF2(outAF2 d,inAF2 a,inAF2 b){d[0]=a[0]+b[0];d[1]=a[1]+b[1];return d;}
+ A_STATIC retAF3 opAAddF3(outAF3 d,inAF3 a,inAF3 b){d[0]=a[0]+b[0];d[1]=a[1]+b[1];d[2]=a[2]+b[2];return d;}
+ A_STATIC retAF4 opAAddF4(outAF4 d,inAF4 a,inAF4 b){d[0]=a[0]+b[0];d[1]=a[1]+b[1];d[2]=a[2]+b[2];d[3]=a[3]+b[3];return d;}
+//==============================================================================================================================
+ A_STATIC retAD2 opAAddOneD2(outAD2 d,inAD2 a,AD1 b){d[0]=a[0]+b;d[1]=a[1]+b;return d;}
+ A_STATIC retAD3 opAAddOneD3(outAD3 d,inAD3 a,AD1 b){d[0]=a[0]+b;d[1]=a[1]+b;d[2]=a[2]+b;return d;}
+ A_STATIC retAD4 opAAddOneD4(outAD4 d,inAD4 a,AD1 b){d[0]=a[0]+b;d[1]=a[1]+b;d[2]=a[2]+b;d[3]=a[3]+b;return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC retAF2 opAAddOneF2(outAF2 d,inAF2 a,AF1 b){d[0]=a[0]+b;d[1]=a[1]+b;return d;}
+ A_STATIC retAF3 opAAddOneF3(outAF3 d,inAF3 a,AF1 b){d[0]=a[0]+b;d[1]=a[1]+b;d[2]=a[2]+b;return d;}
+ A_STATIC retAF4 opAAddOneF4(outAF4 d,inAF4 a,AF1 b){d[0]=a[0]+b;d[1]=a[1]+b;d[2]=a[2]+b;d[3]=a[3]+b;return d;}
+//==============================================================================================================================
+ A_STATIC retAD2 opACpyD2(outAD2 d,inAD2 a){d[0]=a[0];d[1]=a[1];return d;}
+ A_STATIC retAD3 opACpyD3(outAD3 d,inAD3 a){d[0]=a[0];d[1]=a[1];d[2]=a[2];return d;}
+ A_STATIC retAD4 opACpyD4(outAD4 d,inAD4 a){d[0]=a[0];d[1]=a[1];d[2]=a[2];d[3]=a[3];return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC retAF2 opACpyF2(outAF2 d,inAF2 a){d[0]=a[0];d[1]=a[1];return d;}
+ A_STATIC retAF3 opACpyF3(outAF3 d,inAF3 a){d[0]=a[0];d[1]=a[1];d[2]=a[2];return d;}
+ A_STATIC retAF4 opACpyF4(outAF4 d,inAF4 a){d[0]=a[0];d[1]=a[1];d[2]=a[2];d[3]=a[3];return d;}
+//==============================================================================================================================
+ A_STATIC retAD2 opALerpD2(outAD2 d,inAD2 a,inAD2 b,inAD2 c){d[0]=ALerpD1(a[0],b[0],c[0]);d[1]=ALerpD1(a[1],b[1],c[1]);return d;}
+ A_STATIC retAD3 opALerpD3(outAD3 d,inAD3 a,inAD3 b,inAD3 c){d[0]=ALerpD1(a[0],b[0],c[0]);d[1]=ALerpD1(a[1],b[1],c[1]);d[2]=ALerpD1(a[2],b[2],c[2]);return d;}
+ A_STATIC retAD4 opALerpD4(outAD4 d,inAD4 a,inAD4 b,inAD4 c){d[0]=ALerpD1(a[0],b[0],c[0]);d[1]=ALerpD1(a[1],b[1],c[1]);d[2]=ALerpD1(a[2],b[2],c[2]);d[3]=ALerpD1(a[3],b[3],c[3]);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC retAF2 opALerpF2(outAF2 d,inAF2 a,inAF2 b,inAF2 c){d[0]=ALerpF1(a[0],b[0],c[0]);d[1]=ALerpF1(a[1],b[1],c[1]);return d;}
+ A_STATIC retAF3 opALerpF3(outAF3 d,inAF3 a,inAF3 b,inAF3 c){d[0]=ALerpF1(a[0],b[0],c[0]);d[1]=ALerpF1(a[1],b[1],c[1]);d[2]=ALerpF1(a[2],b[2],c[2]);return d;}
+ A_STATIC retAF4 opALerpF4(outAF4 d,inAF4 a,inAF4 b,inAF4 c){d[0]=ALerpF1(a[0],b[0],c[0]);d[1]=ALerpF1(a[1],b[1],c[1]);d[2]=ALerpF1(a[2],b[2],c[2]);d[3]=ALerpF1(a[3],b[3],c[3]);return d;}
+//==============================================================================================================================
+ A_STATIC retAD2 opALerpOneD2(outAD2 d,inAD2 a,inAD2 b,AD1 c){d[0]=ALerpD1(a[0],b[0],c);d[1]=ALerpD1(a[1],b[1],c);return d;}
+ A_STATIC retAD3 opALerpOneD3(outAD3 d,inAD3 a,inAD3 b,AD1 c){d[0]=ALerpD1(a[0],b[0],c);d[1]=ALerpD1(a[1],b[1],c);d[2]=ALerpD1(a[2],b[2],c);return d;}
+ A_STATIC retAD4 opALerpOneD4(outAD4 d,inAD4 a,inAD4 b,AD1 c){d[0]=ALerpD1(a[0],b[0],c);d[1]=ALerpD1(a[1],b[1],c);d[2]=ALerpD1(a[2],b[2],c);d[3]=ALerpD1(a[3],b[3],c);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC retAF2 opALerpOneF2(outAF2 d,inAF2 a,inAF2 b,AF1 c){d[0]=ALerpF1(a[0],b[0],c);d[1]=ALerpF1(a[1],b[1],c);return d;}
+ A_STATIC retAF3 opALerpOneF3(outAF3 d,inAF3 a,inAF3 b,AF1 c){d[0]=ALerpF1(a[0],b[0],c);d[1]=ALerpF1(a[1],b[1],c);d[2]=ALerpF1(a[2],b[2],c);return d;}
+ A_STATIC retAF4 opALerpOneF4(outAF4 d,inAF4 a,inAF4 b,AF1 c){d[0]=ALerpF1(a[0],b[0],c);d[1]=ALerpF1(a[1],b[1],c);d[2]=ALerpF1(a[2],b[2],c);d[3]=ALerpF1(a[3],b[3],c);return d;}
+//==============================================================================================================================
+ A_STATIC retAD2 opAMaxD2(outAD2 d,inAD2 a,inAD2 b){d[0]=AMaxD1(a[0],b[0]);d[1]=AMaxD1(a[1],b[1]);return d;}
+ A_STATIC retAD3 opAMaxD3(outAD3 d,inAD3 a,inAD3 b){d[0]=AMaxD1(a[0],b[0]);d[1]=AMaxD1(a[1],b[1]);d[2]=AMaxD1(a[2],b[2]);return d;}
+ A_STATIC retAD4 opAMaxD4(outAD4 d,inAD4 a,inAD4 b){d[0]=AMaxD1(a[0],b[0]);d[1]=AMaxD1(a[1],b[1]);d[2]=AMaxD1(a[2],b[2]);d[3]=AMaxD1(a[3],b[3]);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC retAF2 opAMaxF2(outAF2 d,inAF2 a,inAF2 b){d[0]=AMaxF1(a[0],b[0]);d[1]=AMaxF1(a[1],b[1]);return d;}
+ A_STATIC retAF3 opAMaxF3(outAF3 d,inAF3 a,inAF3 b){d[0]=AMaxF1(a[0],b[0]);d[1]=AMaxF1(a[1],b[1]);d[2]=AMaxF1(a[2],b[2]);return d;}
+ A_STATIC retAF4 opAMaxF4(outAF4 d,inAF4 a,inAF4 b){d[0]=AMaxF1(a[0],b[0]);d[1]=AMaxF1(a[1],b[1]);d[2]=AMaxF1(a[2],b[2]);d[3]=AMaxF1(a[3],b[3]);return d;}
+//==============================================================================================================================
+ A_STATIC retAD2 opAMinD2(outAD2 d,inAD2 a,inAD2 b){d[0]=AMinD1(a[0],b[0]);d[1]=AMinD1(a[1],b[1]);return d;}
+ A_STATIC retAD3 opAMinD3(outAD3 d,inAD3 a,inAD3 b){d[0]=AMinD1(a[0],b[0]);d[1]=AMinD1(a[1],b[1]);d[2]=AMinD1(a[2],b[2]);return d;}
+ A_STATIC retAD4 opAMinD4(outAD4 d,inAD4 a,inAD4 b){d[0]=AMinD1(a[0],b[0]);d[1]=AMinD1(a[1],b[1]);d[2]=AMinD1(a[2],b[2]);d[3]=AMinD1(a[3],b[3]);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC retAF2 opAMinF2(outAF2 d,inAF2 a,inAF2 b){d[0]=AMinF1(a[0],b[0]);d[1]=AMinF1(a[1],b[1]);return d;}
+ A_STATIC retAF3 opAMinF3(outAF3 d,inAF3 a,inAF3 b){d[0]=AMinF1(a[0],b[0]);d[1]=AMinF1(a[1],b[1]);d[2]=AMinF1(a[2],b[2]);return d;}
+ A_STATIC retAF4 opAMinF4(outAF4 d,inAF4 a,inAF4 b){d[0]=AMinF1(a[0],b[0]);d[1]=AMinF1(a[1],b[1]);d[2]=AMinF1(a[2],b[2]);d[3]=AMinF1(a[3],b[3]);return d;}
+//==============================================================================================================================
+ A_STATIC retAD2 opAMulD2(outAD2 d,inAD2 a,inAD2 b){d[0]=a[0]*b[0];d[1]=a[1]*b[1];return d;}
+ A_STATIC retAD3 opAMulD3(outAD3 d,inAD3 a,inAD3 b){d[0]=a[0]*b[0];d[1]=a[1]*b[1];d[2]=a[2]*b[2];return d;}
+ A_STATIC retAD4 opAMulD4(outAD4 d,inAD4 a,inAD4 b){d[0]=a[0]*b[0];d[1]=a[1]*b[1];d[2]=a[2]*b[2];d[3]=a[3]*b[3];return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC retAF2 opAMulF2(outAF2 d,inAF2 a,inAF2 b){d[0]=a[0]*b[0];d[1]=a[1]*b[1];return d;}
+ A_STATIC retAF3 opAMulF3(outAF3 d,inAF3 a,inAF3 b){d[0]=a[0]*b[0];d[1]=a[1]*b[1];d[2]=a[2]*b[2];return d;}
+ A_STATIC retAF4 opAMulF4(outAF4 d,inAF4 a,inAF4 b){d[0]=a[0]*b[0];d[1]=a[1]*b[1];d[2]=a[2]*b[2];d[3]=a[3]*b[3];return d;}
+//==============================================================================================================================
+ A_STATIC retAD2 opAMulOneD2(outAD2 d,inAD2 a,AD1 b){d[0]=a[0]*b;d[1]=a[1]*b;return d;}
+ A_STATIC retAD3 opAMulOneD3(outAD3 d,inAD3 a,AD1 b){d[0]=a[0]*b;d[1]=a[1]*b;d[2]=a[2]*b;return d;}
+ A_STATIC retAD4 opAMulOneD4(outAD4 d,inAD4 a,AD1 b){d[0]=a[0]*b;d[1]=a[1]*b;d[2]=a[2]*b;d[3]=a[3]*b;return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC retAF2 opAMulOneF2(outAF2 d,inAF2 a,AF1 b){d[0]=a[0]*b;d[1]=a[1]*b;return d;}
+ A_STATIC retAF3 opAMulOneF3(outAF3 d,inAF3 a,AF1 b){d[0]=a[0]*b;d[1]=a[1]*b;d[2]=a[2]*b;return d;}
+ A_STATIC retAF4 opAMulOneF4(outAF4 d,inAF4 a,AF1 b){d[0]=a[0]*b;d[1]=a[1]*b;d[2]=a[2]*b;d[3]=a[3]*b;return d;}
+//==============================================================================================================================
+ A_STATIC retAD2 opANegD2(outAD2 d,inAD2 a){d[0]=-a[0];d[1]=-a[1];return d;}
+ A_STATIC retAD3 opANegD3(outAD3 d,inAD3 a){d[0]=-a[0];d[1]=-a[1];d[2]=-a[2];return d;}
+ A_STATIC retAD4 opANegD4(outAD4 d,inAD4 a){d[0]=-a[0];d[1]=-a[1];d[2]=-a[2];d[3]=-a[3];return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC retAF2 opANegF2(outAF2 d,inAF2 a){d[0]=-a[0];d[1]=-a[1];return d;}
+ A_STATIC retAF3 opANegF3(outAF3 d,inAF3 a){d[0]=-a[0];d[1]=-a[1];d[2]=-a[2];return d;}
+ A_STATIC retAF4 opANegF4(outAF4 d,inAF4 a){d[0]=-a[0];d[1]=-a[1];d[2]=-a[2];d[3]=-a[3];return d;}
+//==============================================================================================================================
+ A_STATIC retAD2 opARcpD2(outAD2 d,inAD2 a){d[0]=ARcpD1(a[0]);d[1]=ARcpD1(a[1]);return d;}
+ A_STATIC retAD3 opARcpD3(outAD3 d,inAD3 a){d[0]=ARcpD1(a[0]);d[1]=ARcpD1(a[1]);d[2]=ARcpD1(a[2]);return d;}
+ A_STATIC retAD4 opARcpD4(outAD4 d,inAD4 a){d[0]=ARcpD1(a[0]);d[1]=ARcpD1(a[1]);d[2]=ARcpD1(a[2]);d[3]=ARcpD1(a[3]);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ A_STATIC retAF2 opARcpF2(outAF2 d,inAF2 a){d[0]=ARcpF1(a[0]);d[1]=ARcpF1(a[1]);return d;}
+ A_STATIC retAF3 opARcpF3(outAF3 d,inAF3 a){d[0]=ARcpF1(a[0]);d[1]=ARcpF1(a[1]);d[2]=ARcpF1(a[2]);return d;}
+ A_STATIC retAF4 opARcpF4(outAF4 d,inAF4 a){d[0]=ARcpF1(a[0]);d[1]=ARcpF1(a[1]);d[2]=ARcpF1(a[2]);d[3]=ARcpF1(a[3]);return d;}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// HALF FLOAT PACKING
+//==============================================================================================================================
+ // Convert float to half (in lower 16-bits of output).
+ // Same fast technique as documented here: ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf
+ // Supports denormals.
+ // Conversion rules are to make computations possibly "safer" on the GPU,
+ // -INF & -NaN -> -65504
+ // +INF & +NaN -> +65504
+ A_STATIC AU1 AU1_AH1_AF1(AF1 f){
+ static AW1 base[512]={
+ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
+ 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0001,0x0002,0x0004,0x0008,0x0010,0x0020,0x0040,0x0080,0x0100,
+ 0x0200,0x0400,0x0800,0x0c00,0x1000,0x1400,0x1800,0x1c00,0x2000,0x2400,0x2800,0x2c00,0x3000,0x3400,0x3800,0x3c00,
+ 0x4000,0x4400,0x4800,0x4c00,0x5000,0x5400,0x5800,0x5c00,0x6000,0x6400,0x6800,0x6c00,0x7000,0x7400,0x7800,0x7bff,
+ 0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,
+ 0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,
+ 0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,
+ 0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,
+ 0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,
+ 0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,
+ 0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,0x7bff,
+ 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,
+ 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,
+ 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,
+ 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,
+ 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,
+ 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,
+ 0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8000,0x8001,0x8002,0x8004,0x8008,0x8010,0x8020,0x8040,0x8080,0x8100,
+ 0x8200,0x8400,0x8800,0x8c00,0x9000,0x9400,0x9800,0x9c00,0xa000,0xa400,0xa800,0xac00,0xb000,0xb400,0xb800,0xbc00,
+ 0xc000,0xc400,0xc800,0xcc00,0xd000,0xd400,0xd800,0xdc00,0xe000,0xe400,0xe800,0xec00,0xf000,0xf400,0xf800,0xfbff,
+ 0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,
+ 0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,
+ 0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,
+ 0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,
+ 0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,
+ 0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,
+ 0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff,0xfbff};
+ static AB1 shift[512]={
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,
+ 0x0e,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,
+ 0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x17,0x16,0x15,0x14,0x13,0x12,0x11,0x10,0x0f,
+ 0x0e,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,
+ 0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
+ 0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18};
+ union{AF1 f;AU1 u;}bits;bits.f=f;AU1 u=bits.u;AU1 i=u>>23;return (AU1)(base[i])+((u&0x7fffff)>>shift[i]);}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Used to output packed constant.
+ A_STATIC AU1 AU1_AH2_AF2(inAF2 a){return AU1_AH1_AF1(a[0])+(AU1_AH1_AF1(a[1])<<16);}
+#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+//
+// GLSL
+//
+//
+//==============================================================================================================================
+#if defined(A_GLSL) && defined(A_GPU)
+ #ifndef A_SKIP_EXT
+ #ifdef A_HALF
+ #extension GL_EXT_shader_16bit_storage:require
+ #extension GL_EXT_shader_explicit_arithmetic_types:require
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifdef A_LONG
+ #extension GL_ARB_gpu_shader_int64:require
+ #extension GL_NV_shader_atomic_int64:require
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifdef A_WAVE
+ #extension GL_KHR_shader_subgroup_arithmetic:require
+ #extension GL_KHR_shader_subgroup_ballot:require
+ #extension GL_KHR_shader_subgroup_quad:require
+ #extension GL_KHR_shader_subgroup_shuffle:require
+ #endif
+ #endif
+//==============================================================================================================================
+ #define AP1 bool
+ #define AP2 bvec2
+ #define AP3 bvec3
+ #define AP4 bvec4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AF1 float
+ #define AF2 vec2
+ #define AF3 vec3
+ #define AF4 vec4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AU1 uint
+ #define AU2 uvec2
+ #define AU3 uvec3
+ #define AU4 uvec4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ASU1 int
+ #define ASU2 ivec2
+ #define ASU3 ivec3
+ #define ASU4 ivec4
+//==============================================================================================================================
+ #define AF1_AU1(x) uintBitsToFloat(AU1(x))
+ #define AF2_AU2(x) uintBitsToFloat(AU2(x))
+ #define AF3_AU3(x) uintBitsToFloat(AU3(x))
+ #define AF4_AU4(x) uintBitsToFloat(AU4(x))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AU1_AF1(x) floatBitsToUint(AF1(x))
+ #define AU2_AF2(x) floatBitsToUint(AF2(x))
+ #define AU3_AF3(x) floatBitsToUint(AF3(x))
+ #define AU4_AF4(x) floatBitsToUint(AF4(x))
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AU1_AH1_AF1_x(AF1 a){return packHalf2x16(AF2(a,0.0));}
+ #define AU1_AH1_AF1(a) AU1_AH1_AF1_x(AF1(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AU1_AH2_AF2 packHalf2x16
+ #define AU1_AW2Unorm_AF2 packUnorm2x16
+ #define AU1_AB4Unorm_AF4 packUnorm4x8
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AF2_AH2_AU1 unpackHalf2x16
+ #define AF2_AW2Unorm_AU1 unpackUnorm2x16
+ #define AF4_AB4Unorm_AU1 unpackUnorm4x8
+//==============================================================================================================================
+ AF1 AF1_x(AF1 a){return AF1(a);}
+ AF2 AF2_x(AF1 a){return AF2(a,a);}
+ AF3 AF3_x(AF1 a){return AF3(a,a,a);}
+ AF4 AF4_x(AF1 a){return AF4(a,a,a,a);}
+ #define AF1_(a) AF1_x(AF1(a))
+ #define AF2_(a) AF2_x(AF1(a))
+ #define AF3_(a) AF3_x(AF1(a))
+ #define AF4_(a) AF4_x(AF1(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AU1_x(AU1 a){return AU1(a);}
+ AU2 AU2_x(AU1 a){return AU2(a,a);}
+ AU3 AU3_x(AU1 a){return AU3(a,a,a);}
+ AU4 AU4_x(AU1 a){return AU4(a,a,a,a);}
+ #define AU1_(a) AU1_x(AU1(a))
+ #define AU2_(a) AU2_x(AU1(a))
+ #define AU3_(a) AU3_x(AU1(a))
+ #define AU4_(a) AU4_x(AU1(a))
+//==============================================================================================================================
+ AU1 AAbsSU1(AU1 a){return AU1(abs(ASU1(a)));}
+ AU2 AAbsSU2(AU2 a){return AU2(abs(ASU2(a)));}
+ AU3 AAbsSU3(AU3 a){return AU3(abs(ASU3(a)));}
+ AU4 AAbsSU4(AU4 a){return AU4(abs(ASU4(a)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 ABfe(AU1 src,AU1 off,AU1 bits){return bitfieldExtract(src,ASU1(off),ASU1(bits));}
+ AU1 ABfi(AU1 src,AU1 ins,AU1 mask){return (ins&mask)|(src&(~mask));}
+ // Proxy for V_BFI_B32 where the 'mask' is set as 'bits', 'mask=(1<<bits)-1', and 'bits' needs to be an immediate.
+ AU1 ABfiM(AU1 src,AU1 ins,AU1 bits){return bitfieldInsert(src,ins,0,ASU1(bits));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // V_MED3_F32.
+ AF1 AClampF1(AF1 x,AF1 n,AF1 m){return clamp(x,n,m);}
+ AF2 AClampF2(AF2 x,AF2 n,AF2 m){return clamp(x,n,m);}
+ AF3 AClampF3(AF3 x,AF3 n,AF3 m){return clamp(x,n,m);}
+ AF4 AClampF4(AF4 x,AF4 n,AF4 m){return clamp(x,n,m);}
+//------------------------------------------------------------------------------------------------------------------------------
+ // V_FRACT_F32 (note DX frac() is different).
+ AF1 AFractF1(AF1 x){return fract(x);}
+ AF2 AFractF2(AF2 x){return fract(x);}
+ AF3 AFractF3(AF3 x){return fract(x);}
+ AF4 AFractF4(AF4 x){return fract(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ALerpF1(AF1 x,AF1 y,AF1 a){return mix(x,y,a);}
+ AF2 ALerpF2(AF2 x,AF2 y,AF2 a){return mix(x,y,a);}
+ AF3 ALerpF3(AF3 x,AF3 y,AF3 a){return mix(x,y,a);}
+ AF4 ALerpF4(AF4 x,AF4 y,AF4 a){return mix(x,y,a);}
+//------------------------------------------------------------------------------------------------------------------------------
+ // V_MAX3_F32.
+ AF1 AMax3F1(AF1 x,AF1 y,AF1 z){return max(x,max(y,z));}
+ AF2 AMax3F2(AF2 x,AF2 y,AF2 z){return max(x,max(y,z));}
+ AF3 AMax3F3(AF3 x,AF3 y,AF3 z){return max(x,max(y,z));}
+ AF4 AMax3F4(AF4 x,AF4 y,AF4 z){return max(x,max(y,z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AMax3SU1(AU1 x,AU1 y,AU1 z){return AU1(max(ASU1(x),max(ASU1(y),ASU1(z))));}
+ AU2 AMax3SU2(AU2 x,AU2 y,AU2 z){return AU2(max(ASU2(x),max(ASU2(y),ASU2(z))));}
+ AU3 AMax3SU3(AU3 x,AU3 y,AU3 z){return AU3(max(ASU3(x),max(ASU3(y),ASU3(z))));}
+ AU4 AMax3SU4(AU4 x,AU4 y,AU4 z){return AU4(max(ASU4(x),max(ASU4(y),ASU4(z))));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AMax3U1(AU1 x,AU1 y,AU1 z){return max(x,max(y,z));}
+ AU2 AMax3U2(AU2 x,AU2 y,AU2 z){return max(x,max(y,z));}
+ AU3 AMax3U3(AU3 x,AU3 y,AU3 z){return max(x,max(y,z));}
+ AU4 AMax3U4(AU4 x,AU4 y,AU4 z){return max(x,max(y,z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AMaxSU1(AU1 a,AU1 b){return AU1(max(ASU1(a),ASU1(b)));}
+ AU2 AMaxSU2(AU2 a,AU2 b){return AU2(max(ASU2(a),ASU2(b)));}
+ AU3 AMaxSU3(AU3 a,AU3 b){return AU3(max(ASU3(a),ASU3(b)));}
+ AU4 AMaxSU4(AU4 a,AU4 b){return AU4(max(ASU4(a),ASU4(b)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Clamp has an easier pattern match for med3 when some ordering is known.
+ // V_MED3_F32.
+ AF1 AMed3F1(AF1 x,AF1 y,AF1 z){return max(min(x,y),min(max(x,y),z));}
+ AF2 AMed3F2(AF2 x,AF2 y,AF2 z){return max(min(x,y),min(max(x,y),z));}
+ AF3 AMed3F3(AF3 x,AF3 y,AF3 z){return max(min(x,y),min(max(x,y),z));}
+ AF4 AMed3F4(AF4 x,AF4 y,AF4 z){return max(min(x,y),min(max(x,y),z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // V_MIN3_F32.
+ AF1 AMin3F1(AF1 x,AF1 y,AF1 z){return min(x,min(y,z));}
+ AF2 AMin3F2(AF2 x,AF2 y,AF2 z){return min(x,min(y,z));}
+ AF3 AMin3F3(AF3 x,AF3 y,AF3 z){return min(x,min(y,z));}
+ AF4 AMin3F4(AF4 x,AF4 y,AF4 z){return min(x,min(y,z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AMin3SU1(AU1 x,AU1 y,AU1 z){return AU1(min(ASU1(x),min(ASU1(y),ASU1(z))));}
+ AU2 AMin3SU2(AU2 x,AU2 y,AU2 z){return AU2(min(ASU2(x),min(ASU2(y),ASU2(z))));}
+ AU3 AMin3SU3(AU3 x,AU3 y,AU3 z){return AU3(min(ASU3(x),min(ASU3(y),ASU3(z))));}
+ AU4 AMin3SU4(AU4 x,AU4 y,AU4 z){return AU4(min(ASU4(x),min(ASU4(y),ASU4(z))));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AMin3U1(AU1 x,AU1 y,AU1 z){return min(x,min(y,z));}
+ AU2 AMin3U2(AU2 x,AU2 y,AU2 z){return min(x,min(y,z));}
+ AU3 AMin3U3(AU3 x,AU3 y,AU3 z){return min(x,min(y,z));}
+ AU4 AMin3U4(AU4 x,AU4 y,AU4 z){return min(x,min(y,z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AMinSU1(AU1 a,AU1 b){return AU1(min(ASU1(a),ASU1(b)));}
+ AU2 AMinSU2(AU2 a,AU2 b){return AU2(min(ASU2(a),ASU2(b)));}
+ AU3 AMinSU3(AU3 a,AU3 b){return AU3(min(ASU3(a),ASU3(b)));}
+ AU4 AMinSU4(AU4 a,AU4 b){return AU4(min(ASU4(a),ASU4(b)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Normalized trig. Valid input domain is {-256 to +256}. No GLSL compiler intrinsic exists to map to this currently.
+ // V_COS_F32.
+ AF1 ANCosF1(AF1 x){return cos(x*AF1_(A_2PI));}
+ AF2 ANCosF2(AF2 x){return cos(x*AF2_(A_2PI));}
+ AF3 ANCosF3(AF3 x){return cos(x*AF3_(A_2PI));}
+ AF4 ANCosF4(AF4 x){return cos(x*AF4_(A_2PI));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Normalized trig. Valid input domain is {-256 to +256}. No GLSL compiler intrinsic exists to map to this currently.
+ // V_SIN_F32.
+ AF1 ANSinF1(AF1 x){return sin(x*AF1_(A_2PI));}
+ AF2 ANSinF2(AF2 x){return sin(x*AF2_(A_2PI));}
+ AF3 ANSinF3(AF3 x){return sin(x*AF3_(A_2PI));}
+ AF4 ANSinF4(AF4 x){return sin(x*AF4_(A_2PI));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ARcpF1(AF1 x){return AF1_(1.0)/x;}
+ AF2 ARcpF2(AF2 x){return AF2_(1.0)/x;}
+ AF3 ARcpF3(AF3 x){return AF3_(1.0)/x;}
+ AF4 ARcpF4(AF4 x){return AF4_(1.0)/x;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ARsqF1(AF1 x){return AF1_(1.0)/sqrt(x);}
+ AF2 ARsqF2(AF2 x){return AF2_(1.0)/sqrt(x);}
+ AF3 ARsqF3(AF3 x){return AF3_(1.0)/sqrt(x);}
+ AF4 ARsqF4(AF4 x){return AF4_(1.0)/sqrt(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ASatF1(AF1 x){return clamp(x,AF1_(0.0),AF1_(1.0));}
+ AF2 ASatF2(AF2 x){return clamp(x,AF2_(0.0),AF2_(1.0));}
+ AF3 ASatF3(AF3 x){return clamp(x,AF3_(0.0),AF3_(1.0));}
+ AF4 ASatF4(AF4 x){return clamp(x,AF4_(0.0),AF4_(1.0));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AShrSU1(AU1 a,AU1 b){return AU1(ASU1(a)>>ASU1(b));}
+ AU2 AShrSU2(AU2 a,AU2 b){return AU2(ASU2(a)>>ASU2(b));}
+ AU3 AShrSU3(AU3 a,AU3 b){return AU3(ASU3(a)>>ASU3(b));}
+ AU4 AShrSU4(AU4 a,AU4 b){return AU4(ASU4(a)>>ASU4(b));}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// GLSL BYTE
+//==============================================================================================================================
+ #ifdef A_BYTE
+ #define AB1 uint8_t
+ #define AB2 u8vec2
+ #define AB3 u8vec3
+ #define AB4 u8vec4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ASB1 int8_t
+ #define ASB2 i8vec2
+ #define ASB3 i8vec3
+ #define ASB4 i8vec4
+//------------------------------------------------------------------------------------------------------------------------------
+ AB1 AB1_x(AB1 a){return AB1(a);}
+ AB2 AB2_x(AB1 a){return AB2(a,a);}
+ AB3 AB3_x(AB1 a){return AB3(a,a,a);}
+ AB4 AB4_x(AB1 a){return AB4(a,a,a,a);}
+ #define AB1_(a) AB1_x(AB1(a))
+ #define AB2_(a) AB2_x(AB1(a))
+ #define AB3_(a) AB3_x(AB1(a))
+ #define AB4_(a) AB4_x(AB1(a))
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// GLSL HALF
+//==============================================================================================================================
+ #ifdef A_HALF
+ #define AH1 float16_t
+ #define AH2 f16vec2
+ #define AH3 f16vec3
+ #define AH4 f16vec4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AW1 uint16_t
+ #define AW2 u16vec2
+ #define AW3 u16vec3
+ #define AW4 u16vec4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ASW1 int16_t
+ #define ASW2 i16vec2
+ #define ASW3 i16vec3
+ #define ASW4 i16vec4
+//==============================================================================================================================
+ #define AH2_AU1(x) unpackFloat2x16(AU1(x))
+ AH4 AH4_AU2_x(AU2 x){return AH4(unpackFloat2x16(x.x),unpackFloat2x16(x.y));}
+ #define AH4_AU2(x) AH4_AU2_x(AU2(x))
+ #define AW2_AU1(x) unpackUint2x16(AU1(x))
+ #define AW4_AU2(x) unpackUint4x16(pack64(AU2(x)))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AU1_AH2(x) packFloat2x16(AH2(x))
+ AU2 AU2_AH4_x(AH4 x){return AU2(packFloat2x16(x.xy),packFloat2x16(x.zw));}
+ #define AU2_AH4(x) AU2_AH4_x(AH4(x))
+ #define AU1_AW2(x) packUint2x16(AW2(x))
+ #define AU2_AW4(x) unpack32(packUint4x16(AW4(x)))
+//==============================================================================================================================
+ #define AW1_AH1(x) halfBitsToUint16(AH1(x))
+ #define AW2_AH2(x) halfBitsToUint16(AH2(x))
+ #define AW3_AH3(x) halfBitsToUint16(AH3(x))
+ #define AW4_AH4(x) halfBitsToUint16(AH4(x))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AH1_AW1(x) uint16BitsToHalf(AW1(x))
+ #define AH2_AW2(x) uint16BitsToHalf(AW2(x))
+ #define AH3_AW3(x) uint16BitsToHalf(AW3(x))
+ #define AH4_AW4(x) uint16BitsToHalf(AW4(x))
+//==============================================================================================================================
+ AH1 AH1_x(AH1 a){return AH1(a);}
+ AH2 AH2_x(AH1 a){return AH2(a,a);}
+ AH3 AH3_x(AH1 a){return AH3(a,a,a);}
+ AH4 AH4_x(AH1 a){return AH4(a,a,a,a);}
+ #define AH1_(a) AH1_x(AH1(a))
+ #define AH2_(a) AH2_x(AH1(a))
+ #define AH3_(a) AH3_x(AH1(a))
+ #define AH4_(a) AH4_x(AH1(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ AW1 AW1_x(AW1 a){return AW1(a);}
+ AW2 AW2_x(AW1 a){return AW2(a,a);}
+ AW3 AW3_x(AW1 a){return AW3(a,a,a);}
+ AW4 AW4_x(AW1 a){return AW4(a,a,a,a);}
+ #define AW1_(a) AW1_x(AW1(a))
+ #define AW2_(a) AW2_x(AW1(a))
+ #define AW3_(a) AW3_x(AW1(a))
+ #define AW4_(a) AW4_x(AW1(a))
+//==============================================================================================================================
+ AW1 AAbsSW1(AW1 a){return AW1(abs(ASW1(a)));}
+ AW2 AAbsSW2(AW2 a){return AW2(abs(ASW2(a)));}
+ AW3 AAbsSW3(AW3 a){return AW3(abs(ASW3(a)));}
+ AW4 AAbsSW4(AW4 a){return AW4(abs(ASW4(a)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AClampH1(AH1 x,AH1 n,AH1 m){return clamp(x,n,m);}
+ AH2 AClampH2(AH2 x,AH2 n,AH2 m){return clamp(x,n,m);}
+ AH3 AClampH3(AH3 x,AH3 n,AH3 m){return clamp(x,n,m);}
+ AH4 AClampH4(AH4 x,AH4 n,AH4 m){return clamp(x,n,m);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AFractH1(AH1 x){return fract(x);}
+ AH2 AFractH2(AH2 x){return fract(x);}
+ AH3 AFractH3(AH3 x){return fract(x);}
+ AH4 AFractH4(AH4 x){return fract(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 ALerpH1(AH1 x,AH1 y,AH1 a){return mix(x,y,a);}
+ AH2 ALerpH2(AH2 x,AH2 y,AH2 a){return mix(x,y,a);}
+ AH3 ALerpH3(AH3 x,AH3 y,AH3 a){return mix(x,y,a);}
+ AH4 ALerpH4(AH4 x,AH4 y,AH4 a){return mix(x,y,a);}
+//------------------------------------------------------------------------------------------------------------------------------
+ // No packed version of max3.
+ AH1 AMax3H1(AH1 x,AH1 y,AH1 z){return max(x,max(y,z));}
+ AH2 AMax3H2(AH2 x,AH2 y,AH2 z){return max(x,max(y,z));}
+ AH3 AMax3H3(AH3 x,AH3 y,AH3 z){return max(x,max(y,z));}
+ AH4 AMax3H4(AH4 x,AH4 y,AH4 z){return max(x,max(y,z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AW1 AMaxSW1(AW1 a,AW1 b){return AW1(max(ASU1(a),ASU1(b)));}
+ AW2 AMaxSW2(AW2 a,AW2 b){return AW2(max(ASU2(a),ASU2(b)));}
+ AW3 AMaxSW3(AW3 a,AW3 b){return AW3(max(ASU3(a),ASU3(b)));}
+ AW4 AMaxSW4(AW4 a,AW4 b){return AW4(max(ASU4(a),ASU4(b)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // No packed version of min3.
+ AH1 AMin3H1(AH1 x,AH1 y,AH1 z){return min(x,min(y,z));}
+ AH2 AMin3H2(AH2 x,AH2 y,AH2 z){return min(x,min(y,z));}
+ AH3 AMin3H3(AH3 x,AH3 y,AH3 z){return min(x,min(y,z));}
+ AH4 AMin3H4(AH4 x,AH4 y,AH4 z){return min(x,min(y,z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AW1 AMinSW1(AW1 a,AW1 b){return AW1(min(ASU1(a),ASU1(b)));}
+ AW2 AMinSW2(AW2 a,AW2 b){return AW2(min(ASU2(a),ASU2(b)));}
+ AW3 AMinSW3(AW3 a,AW3 b){return AW3(min(ASU3(a),ASU3(b)));}
+ AW4 AMinSW4(AW4 a,AW4 b){return AW4(min(ASU4(a),ASU4(b)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 ARcpH1(AH1 x){return AH1_(1.0)/x;}
+ AH2 ARcpH2(AH2 x){return AH2_(1.0)/x;}
+ AH3 ARcpH3(AH3 x){return AH3_(1.0)/x;}
+ AH4 ARcpH4(AH4 x){return AH4_(1.0)/x;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 ARsqH1(AH1 x){return AH1_(1.0)/sqrt(x);}
+ AH2 ARsqH2(AH2 x){return AH2_(1.0)/sqrt(x);}
+ AH3 ARsqH3(AH3 x){return AH3_(1.0)/sqrt(x);}
+ AH4 ARsqH4(AH4 x){return AH4_(1.0)/sqrt(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 ASatH1(AH1 x){return clamp(x,AH1_(0.0),AH1_(1.0));}
+ AH2 ASatH2(AH2 x){return clamp(x,AH2_(0.0),AH2_(1.0));}
+ AH3 ASatH3(AH3 x){return clamp(x,AH3_(0.0),AH3_(1.0));}
+ AH4 ASatH4(AH4 x){return clamp(x,AH4_(0.0),AH4_(1.0));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AW1 AShrSW1(AW1 a,AW1 b){return AW1(ASW1(a)>>ASW1(b));}
+ AW2 AShrSW2(AW2 a,AW2 b){return AW2(ASW2(a)>>ASW2(b));}
+ AW3 AShrSW3(AW3 a,AW3 b){return AW3(ASW3(a)>>ASW3(b));}
+ AW4 AShrSW4(AW4 a,AW4 b){return AW4(ASW4(a)>>ASW4(b));}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// GLSL DOUBLE
+//==============================================================================================================================
+ #ifdef A_DUBL
+ #define AD1 double
+ #define AD2 dvec2
+ #define AD3 dvec3
+ #define AD4 dvec4
+//------------------------------------------------------------------------------------------------------------------------------
+ AD1 AD1_x(AD1 a){return AD1(a);}
+ AD2 AD2_x(AD1 a){return AD2(a,a);}
+ AD3 AD3_x(AD1 a){return AD3(a,a,a);}
+ AD4 AD4_x(AD1 a){return AD4(a,a,a,a);}
+ #define AD1_(a) AD1_x(AD1(a))
+ #define AD2_(a) AD2_x(AD1(a))
+ #define AD3_(a) AD3_x(AD1(a))
+ #define AD4_(a) AD4_x(AD1(a))
+//==============================================================================================================================
+ AD1 AFractD1(AD1 x){return fract(x);}
+ AD2 AFractD2(AD2 x){return fract(x);}
+ AD3 AFractD3(AD3 x){return fract(x);}
+ AD4 AFractD4(AD4 x){return fract(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD1 ALerpD1(AD1 x,AD1 y,AD1 a){return mix(x,y,a);}
+ AD2 ALerpD2(AD2 x,AD2 y,AD2 a){return mix(x,y,a);}
+ AD3 ALerpD3(AD3 x,AD3 y,AD3 a){return mix(x,y,a);}
+ AD4 ALerpD4(AD4 x,AD4 y,AD4 a){return mix(x,y,a);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD1 ARcpD1(AD1 x){return AD1_(1.0)/x;}
+ AD2 ARcpD2(AD2 x){return AD2_(1.0)/x;}
+ AD3 ARcpD3(AD3 x){return AD3_(1.0)/x;}
+ AD4 ARcpD4(AD4 x){return AD4_(1.0)/x;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD1 ARsqD1(AD1 x){return AD1_(1.0)/sqrt(x);}
+ AD2 ARsqD2(AD2 x){return AD2_(1.0)/sqrt(x);}
+ AD3 ARsqD3(AD3 x){return AD3_(1.0)/sqrt(x);}
+ AD4 ARsqD4(AD4 x){return AD4_(1.0)/sqrt(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD1 ASatD1(AD1 x){return clamp(x,AD1_(0.0),AD1_(1.0));}
+ AD2 ASatD2(AD2 x){return clamp(x,AD2_(0.0),AD2_(1.0));}
+ AD3 ASatD3(AD3 x){return clamp(x,AD3_(0.0),AD3_(1.0));}
+ AD4 ASatD4(AD4 x){return clamp(x,AD4_(0.0),AD4_(1.0));}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// GLSL LONG
+//==============================================================================================================================
+ #ifdef A_LONG
+ #define AL1 uint64_t
+ #define AL2 u64vec2
+ #define AL3 u64vec3
+ #define AL4 u64vec4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ASL1 int64_t
+ #define ASL2 i64vec2
+ #define ASL3 i64vec3
+ #define ASL4 i64vec4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AL1_AU2(x) packUint2x32(AU2(x))
+ #define AU2_AL1(x) unpackUint2x32(AL1(x))
+//------------------------------------------------------------------------------------------------------------------------------
+ AL1 AL1_x(AL1 a){return AL1(a);}
+ AL2 AL2_x(AL1 a){return AL2(a,a);}
+ AL3 AL3_x(AL1 a){return AL3(a,a,a);}
+ AL4 AL4_x(AL1 a){return AL4(a,a,a,a);}
+ #define AL1_(a) AL1_x(AL1(a))
+ #define AL2_(a) AL2_x(AL1(a))
+ #define AL3_(a) AL3_x(AL1(a))
+ #define AL4_(a) AL4_x(AL1(a))
+//==============================================================================================================================
+ AL1 AAbsSL1(AL1 a){return AL1(abs(ASL1(a)));}
+ AL2 AAbsSL2(AL2 a){return AL2(abs(ASL2(a)));}
+ AL3 AAbsSL3(AL3 a){return AL3(abs(ASL3(a)));}
+ AL4 AAbsSL4(AL4 a){return AL4(abs(ASL4(a)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AL1 AMaxSL1(AL1 a,AL1 b){return AL1(max(ASU1(a),ASU1(b)));}
+ AL2 AMaxSL2(AL2 a,AL2 b){return AL2(max(ASU2(a),ASU2(b)));}
+ AL3 AMaxSL3(AL3 a,AL3 b){return AL3(max(ASU3(a),ASU3(b)));}
+ AL4 AMaxSL4(AL4 a,AL4 b){return AL4(max(ASU4(a),ASU4(b)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AL1 AMinSL1(AL1 a,AL1 b){return AL1(min(ASU1(a),ASU1(b)));}
+ AL2 AMinSL2(AL2 a,AL2 b){return AL2(min(ASU2(a),ASU2(b)));}
+ AL3 AMinSL3(AL3 a,AL3 b){return AL3(min(ASU3(a),ASU3(b)));}
+ AL4 AMinSL4(AL4 a,AL4 b){return AL4(min(ASU4(a),ASU4(b)));}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// WAVE OPERATIONS
+//==============================================================================================================================
+ #ifdef A_WAVE
+ // Where 'x' must be a compile time literal.
+ AF1 AWaveXorF1(AF1 v,AU1 x){return subgroupShuffleXor(v,x);}
+ AF2 AWaveXorF2(AF2 v,AU1 x){return subgroupShuffleXor(v,x);}
+ AF3 AWaveXorF3(AF3 v,AU1 x){return subgroupShuffleXor(v,x);}
+ AF4 AWaveXorF4(AF4 v,AU1 x){return subgroupShuffleXor(v,x);}
+ AU1 AWaveXorU1(AU1 v,AU1 x){return subgroupShuffleXor(v,x);}
+ AU2 AWaveXorU2(AU2 v,AU1 x){return subgroupShuffleXor(v,x);}
+ AU3 AWaveXorU3(AU3 v,AU1 x){return subgroupShuffleXor(v,x);}
+ AU4 AWaveXorU4(AU4 v,AU1 x){return subgroupShuffleXor(v,x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifdef A_HALF
+ AH2 AWaveXorH2(AH2 v,AU1 x){return AH2_AU1(subgroupShuffleXor(AU1_AH2(v),x));}
+ AH4 AWaveXorH4(AH4 v,AU1 x){return AH4_AU2(subgroupShuffleXor(AU2_AH4(v),x));}
+ AW2 AWaveXorW2(AW2 v,AU1 x){return AW2_AU1(subgroupShuffleXor(AU1_AW2(v),x));}
+ AW4 AWaveXorW4(AW4 v,AU1 x){return AW4_AU2(subgroupShuffleXor(AU2_AW4(v),x));}
+ #endif
+ #endif
+//==============================================================================================================================
+#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+//
+// HLSL
+//
+//
+//==============================================================================================================================
+#if defined(A_HLSL) && defined(A_GPU)
+ #ifdef A_HLSL_6_2
+ #define AP1 bool
+ #define AP2 bool2
+ #define AP3 bool3
+ #define AP4 bool4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AF1 float32_t
+ #define AF2 float32_t2
+ #define AF3 float32_t3
+ #define AF4 float32_t4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AU1 uint32_t
+ #define AU2 uint32_t2
+ #define AU3 uint32_t3
+ #define AU4 uint32_t4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ASU1 int32_t
+ #define ASU2 int32_t2
+ #define ASU3 int32_t3
+ #define ASU4 int32_t4
+ #else
+ #define AP1 bool
+ #define AP2 bool2
+ #define AP3 bool3
+ #define AP4 bool4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AF1 float
+ #define AF2 float2
+ #define AF3 float3
+ #define AF4 float4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AU1 uint
+ #define AU2 uint2
+ #define AU3 uint3
+ #define AU4 uint4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ASU1 int
+ #define ASU2 int2
+ #define ASU3 int3
+ #define ASU4 int4
+ #endif
+//==============================================================================================================================
+ #define AF1_AU1(x) asfloat(AU1(x))
+ #define AF2_AU2(x) asfloat(AU2(x))
+ #define AF3_AU3(x) asfloat(AU3(x))
+ #define AF4_AU4(x) asfloat(AU4(x))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AU1_AF1(x) asuint(AF1(x))
+ #define AU2_AF2(x) asuint(AF2(x))
+ #define AU3_AF3(x) asuint(AF3(x))
+ #define AU4_AF4(x) asuint(AF4(x))
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AU1_AH1_AF1_x(AF1 a){return f32tof16(a);}
+ #define AU1_AH1_AF1(a) AU1_AH1_AF1_x(AF1(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AU1_AH2_AF2_x(AF2 a){return f32tof16(a.x)|(f32tof16(a.y)<<16);}
+ #define AU1_AH2_AF2(a) AU1_AH2_AF2_x(AF2(a))
+ #define AU1_AB4Unorm_AF4(x) D3DCOLORtoUBYTE4(AF4(x))
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 AF2_AH2_AU1_x(AU1 x){return AF2(f16tof32(x&0xFFFF),f16tof32(x>>16));}
+ #define AF2_AH2_AU1(x) AF2_AH2_AU1_x(AU1(x))
+//==============================================================================================================================
+ AF1 AF1_x(AF1 a){return AF1(a);}
+ AF2 AF2_x(AF1 a){return AF2(a,a);}
+ AF3 AF3_x(AF1 a){return AF3(a,a,a);}
+ AF4 AF4_x(AF1 a){return AF4(a,a,a,a);}
+ #define AF1_(a) AF1_x(AF1(a))
+ #define AF2_(a) AF2_x(AF1(a))
+ #define AF3_(a) AF3_x(AF1(a))
+ #define AF4_(a) AF4_x(AF1(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AU1_x(AU1 a){return AU1(a);}
+ AU2 AU2_x(AU1 a){return AU2(a,a);}
+ AU3 AU3_x(AU1 a){return AU3(a,a,a);}
+ AU4 AU4_x(AU1 a){return AU4(a,a,a,a);}
+ #define AU1_(a) AU1_x(AU1(a))
+ #define AU2_(a) AU2_x(AU1(a))
+ #define AU3_(a) AU3_x(AU1(a))
+ #define AU4_(a) AU4_x(AU1(a))
+//==============================================================================================================================
+ AU1 AAbsSU1(AU1 a){return AU1(abs(ASU1(a)));}
+ AU2 AAbsSU2(AU2 a){return AU2(abs(ASU2(a)));}
+ AU3 AAbsSU3(AU3 a){return AU3(abs(ASU3(a)));}
+ AU4 AAbsSU4(AU4 a){return AU4(abs(ASU4(a)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 ABfe(AU1 src,AU1 off,AU1 bits){AU1 mask=(1u<<bits)-1;return (src>>off)&mask;}
+ AU1 ABfi(AU1 src,AU1 ins,AU1 mask){return (ins&mask)|(src&(~mask));}
+ AU1 ABfiM(AU1 src,AU1 ins,AU1 bits){AU1 mask=(1u<<bits)-1;return (ins&mask)|(src&(~mask));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AClampF1(AF1 x,AF1 n,AF1 m){return max(n,min(x,m));}
+ AF2 AClampF2(AF2 x,AF2 n,AF2 m){return max(n,min(x,m));}
+ AF3 AClampF3(AF3 x,AF3 n,AF3 m){return max(n,min(x,m));}
+ AF4 AClampF4(AF4 x,AF4 n,AF4 m){return max(n,min(x,m));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AFractF1(AF1 x){return x-floor(x);}
+ AF2 AFractF2(AF2 x){return x-floor(x);}
+ AF3 AFractF3(AF3 x){return x-floor(x);}
+ AF4 AFractF4(AF4 x){return x-floor(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ALerpF1(AF1 x,AF1 y,AF1 a){return lerp(x,y,a);}
+ AF2 ALerpF2(AF2 x,AF2 y,AF2 a){return lerp(x,y,a);}
+ AF3 ALerpF3(AF3 x,AF3 y,AF3 a){return lerp(x,y,a);}
+ AF4 ALerpF4(AF4 x,AF4 y,AF4 a){return lerp(x,y,a);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AMax3F1(AF1 x,AF1 y,AF1 z){return max(x,max(y,z));}
+ AF2 AMax3F2(AF2 x,AF2 y,AF2 z){return max(x,max(y,z));}
+ AF3 AMax3F3(AF3 x,AF3 y,AF3 z){return max(x,max(y,z));}
+ AF4 AMax3F4(AF4 x,AF4 y,AF4 z){return max(x,max(y,z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AMax3SU1(AU1 x,AU1 y,AU1 z){return AU1(max(ASU1(x),max(ASU1(y),ASU1(z))));}
+ AU2 AMax3SU2(AU2 x,AU2 y,AU2 z){return AU2(max(ASU2(x),max(ASU2(y),ASU2(z))));}
+ AU3 AMax3SU3(AU3 x,AU3 y,AU3 z){return AU3(max(ASU3(x),max(ASU3(y),ASU3(z))));}
+ AU4 AMax3SU4(AU4 x,AU4 y,AU4 z){return AU4(max(ASU4(x),max(ASU4(y),ASU4(z))));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AMax3U1(AU1 x,AU1 y,AU1 z){return max(x,max(y,z));}
+ AU2 AMax3U2(AU2 x,AU2 y,AU2 z){return max(x,max(y,z));}
+ AU3 AMax3U3(AU3 x,AU3 y,AU3 z){return max(x,max(y,z));}
+ AU4 AMax3U4(AU4 x,AU4 y,AU4 z){return max(x,max(y,z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AMaxSU1(AU1 a,AU1 b){return AU1(max(ASU1(a),ASU1(b)));}
+ AU2 AMaxSU2(AU2 a,AU2 b){return AU2(max(ASU2(a),ASU2(b)));}
+ AU3 AMaxSU3(AU3 a,AU3 b){return AU3(max(ASU3(a),ASU3(b)));}
+ AU4 AMaxSU4(AU4 a,AU4 b){return AU4(max(ASU4(a),ASU4(b)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AMed3F1(AF1 x,AF1 y,AF1 z){return max(min(x,y),min(max(x,y),z));}
+ AF2 AMed3F2(AF2 x,AF2 y,AF2 z){return max(min(x,y),min(max(x,y),z));}
+ AF3 AMed3F3(AF3 x,AF3 y,AF3 z){return max(min(x,y),min(max(x,y),z));}
+ AF4 AMed3F4(AF4 x,AF4 y,AF4 z){return max(min(x,y),min(max(x,y),z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AMin3F1(AF1 x,AF1 y,AF1 z){return min(x,min(y,z));}
+ AF2 AMin3F2(AF2 x,AF2 y,AF2 z){return min(x,min(y,z));}
+ AF3 AMin3F3(AF3 x,AF3 y,AF3 z){return min(x,min(y,z));}
+ AF4 AMin3F4(AF4 x,AF4 y,AF4 z){return min(x,min(y,z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AMin3SU1(AU1 x,AU1 y,AU1 z){return AU1(min(ASU1(x),min(ASU1(y),ASU1(z))));}
+ AU2 AMin3SU2(AU2 x,AU2 y,AU2 z){return AU2(min(ASU2(x),min(ASU2(y),ASU2(z))));}
+ AU3 AMin3SU3(AU3 x,AU3 y,AU3 z){return AU3(min(ASU3(x),min(ASU3(y),ASU3(z))));}
+ AU4 AMin3SU4(AU4 x,AU4 y,AU4 z){return AU4(min(ASU4(x),min(ASU4(y),ASU4(z))));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AMin3U1(AU1 x,AU1 y,AU1 z){return min(x,min(y,z));}
+ AU2 AMin3U2(AU2 x,AU2 y,AU2 z){return min(x,min(y,z));}
+ AU3 AMin3U3(AU3 x,AU3 y,AU3 z){return min(x,min(y,z));}
+ AU4 AMin3U4(AU4 x,AU4 y,AU4 z){return min(x,min(y,z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AMinSU1(AU1 a,AU1 b){return AU1(min(ASU1(a),ASU1(b)));}
+ AU2 AMinSU2(AU2 a,AU2 b){return AU2(min(ASU2(a),ASU2(b)));}
+ AU3 AMinSU3(AU3 a,AU3 b){return AU3(min(ASU3(a),ASU3(b)));}
+ AU4 AMinSU4(AU4 a,AU4 b){return AU4(min(ASU4(a),ASU4(b)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ANCosF1(AF1 x){return cos(x*AF1_(A_2PI));}
+ AF2 ANCosF2(AF2 x){return cos(x*AF2_(A_2PI));}
+ AF3 ANCosF3(AF3 x){return cos(x*AF3_(A_2PI));}
+ AF4 ANCosF4(AF4 x){return cos(x*AF4_(A_2PI));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ANSinF1(AF1 x){return sin(x*AF1_(A_2PI));}
+ AF2 ANSinF2(AF2 x){return sin(x*AF2_(A_2PI));}
+ AF3 ANSinF3(AF3 x){return sin(x*AF3_(A_2PI));}
+ AF4 ANSinF4(AF4 x){return sin(x*AF4_(A_2PI));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ARcpF1(AF1 x){return rcp(x);}
+ AF2 ARcpF2(AF2 x){return rcp(x);}
+ AF3 ARcpF3(AF3 x){return rcp(x);}
+ AF4 ARcpF4(AF4 x){return rcp(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ARsqF1(AF1 x){return rsqrt(x);}
+ AF2 ARsqF2(AF2 x){return rsqrt(x);}
+ AF3 ARsqF3(AF3 x){return rsqrt(x);}
+ AF4 ARsqF4(AF4 x){return rsqrt(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ASatF1(AF1 x){return saturate(x);}
+ AF2 ASatF2(AF2 x){return saturate(x);}
+ AF3 ASatF3(AF3 x){return saturate(x);}
+ AF4 ASatF4(AF4 x){return saturate(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AShrSU1(AU1 a,AU1 b){return AU1(ASU1(a)>>ASU1(b));}
+ AU2 AShrSU2(AU2 a,AU2 b){return AU2(ASU2(a)>>ASU2(b));}
+ AU3 AShrSU3(AU3 a,AU3 b){return AU3(ASU3(a)>>ASU3(b));}
+ AU4 AShrSU4(AU4 a,AU4 b){return AU4(ASU4(a)>>ASU4(b));}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// HLSL BYTE
+//==============================================================================================================================
+ #ifdef A_BYTE
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// HLSL HALF
+//==============================================================================================================================
+ #ifdef A_HALF
+ #ifdef A_HLSL_6_2
+ #define AH1 float16_t
+ #define AH2 float16_t2
+ #define AH3 float16_t3
+ #define AH4 float16_t4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AW1 uint16_t
+ #define AW2 uint16_t2
+ #define AW3 uint16_t3
+ #define AW4 uint16_t4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ASW1 int16_t
+ #define ASW2 int16_t2
+ #define ASW3 int16_t3
+ #define ASW4 int16_t4
+ #else
+ #define AH1 min16float
+ #define AH2 min16float2
+ #define AH3 min16float3
+ #define AH4 min16float4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AW1 min16uint
+ #define AW2 min16uint2
+ #define AW3 min16uint3
+ #define AW4 min16uint4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ASW1 min16int
+ #define ASW2 min16int2
+ #define ASW3 min16int3
+ #define ASW4 min16int4
+ #endif
+//==============================================================================================================================
+ // Need to use manual unpack to get optimal execution (don't use packed types in buffers directly).
+ // Unpack requires this pattern: https://gpuopen.com/first-steps-implementing-fp16/
+ AH2 AH2_AU1_x(AU1 x){AF2 t=f16tof32(AU2(x&0xFFFF,x>>16));return AH2(t);}
+ AH4 AH4_AU2_x(AU2 x){return AH4(AH2_AU1_x(x.x),AH2_AU1_x(x.y));}
+ AW2 AW2_AU1_x(AU1 x){AU2 t=AU2(x&0xFFFF,x>>16);return AW2(t);}
+ AW4 AW4_AU2_x(AU2 x){return AW4(AW2_AU1_x(x.x),AW2_AU1_x(x.y));}
+ #define AH2_AU1(x) AH2_AU1_x(AU1(x))
+ #define AH4_AU2(x) AH4_AU2_x(AU2(x))
+ #define AW2_AU1(x) AW2_AU1_x(AU1(x))
+ #define AW4_AU2(x) AW4_AU2_x(AU2(x))
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AU1_AH2_x(AH2 x){return f32tof16(x.x)+(f32tof16(x.y)<<16);}
+ AU2 AU2_AH4_x(AH4 x){return AU2(AU1_AH2_x(x.xy),AU1_AH2_x(x.zw));}
+ AU1 AU1_AW2_x(AW2 x){return AU1(x.x)+(AU1(x.y)<<16);}
+ AU2 AU2_AW4_x(AW4 x){return AU2(AU1_AW2_x(x.xy),AU1_AW2_x(x.zw));}
+ #define AU1_AH2(x) AU1_AH2_x(AH2(x))
+ #define AU2_AH4(x) AU2_AH4_x(AH4(x))
+ #define AU1_AW2(x) AU1_AW2_x(AW2(x))
+ #define AU2_AW4(x) AU2_AW4_x(AW4(x))
+//==============================================================================================================================
+ #if defined(A_HLSL_6_2) && !defined(A_NO_16_BIT_CAST)
+ #define AW1_AH1(x) asuint16(x)
+ #define AW2_AH2(x) asuint16(x)
+ #define AW3_AH3(x) asuint16(x)
+ #define AW4_AH4(x) asuint16(x)
+ #else
+ #define AW1_AH1(a) AW1(f32tof16(AF1(a)))
+ #define AW2_AH2(a) AW2(AW1_AH1((a).x),AW1_AH1((a).y))
+ #define AW3_AH3(a) AW3(AW1_AH1((a).x),AW1_AH1((a).y),AW1_AH1((a).z))
+ #define AW4_AH4(a) AW4(AW1_AH1((a).x),AW1_AH1((a).y),AW1_AH1((a).z),AW1_AH1((a).w))
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ #if defined(A_HLSL_6_2) && !defined(A_NO_16_BIT_CAST)
+ #define AH1_AW1(x) asfloat16(x)
+ #define AH2_AW2(x) asfloat16(x)
+ #define AH3_AW3(x) asfloat16(x)
+ #define AH4_AW4(x) asfloat16(x)
+ #else
+ #define AH1_AW1(a) AH1(f16tof32(AU1(a)))
+ #define AH2_AW2(a) AH2(AH1_AW1((a).x),AH1_AW1((a).y))
+ #define AH3_AW3(a) AH3(AH1_AW1((a).x),AH1_AW1((a).y),AH1_AW1((a).z))
+ #define AH4_AW4(a) AH4(AH1_AW1((a).x),AH1_AW1((a).y),AH1_AW1((a).z),AH1_AW1((a).w))
+ #endif
+//==============================================================================================================================
+ AH1 AH1_x(AH1 a){return AH1(a);}
+ AH2 AH2_x(AH1 a){return AH2(a,a);}
+ AH3 AH3_x(AH1 a){return AH3(a,a,a);}
+ AH4 AH4_x(AH1 a){return AH4(a,a,a,a);}
+ #define AH1_(a) AH1_x(AH1(a))
+ #define AH2_(a) AH2_x(AH1(a))
+ #define AH3_(a) AH3_x(AH1(a))
+ #define AH4_(a) AH4_x(AH1(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ AW1 AW1_x(AW1 a){return AW1(a);}
+ AW2 AW2_x(AW1 a){return AW2(a,a);}
+ AW3 AW3_x(AW1 a){return AW3(a,a,a);}
+ AW4 AW4_x(AW1 a){return AW4(a,a,a,a);}
+ #define AW1_(a) AW1_x(AW1(a))
+ #define AW2_(a) AW2_x(AW1(a))
+ #define AW3_(a) AW3_x(AW1(a))
+ #define AW4_(a) AW4_x(AW1(a))
+//==============================================================================================================================
+ AW1 AAbsSW1(AW1 a){return AW1(abs(ASW1(a)));}
+ AW2 AAbsSW2(AW2 a){return AW2(abs(ASW2(a)));}
+ AW3 AAbsSW3(AW3 a){return AW3(abs(ASW3(a)));}
+ AW4 AAbsSW4(AW4 a){return AW4(abs(ASW4(a)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AClampH1(AH1 x,AH1 n,AH1 m){return max(n,min(x,m));}
+ AH2 AClampH2(AH2 x,AH2 n,AH2 m){return max(n,min(x,m));}
+ AH3 AClampH3(AH3 x,AH3 n,AH3 m){return max(n,min(x,m));}
+ AH4 AClampH4(AH4 x,AH4 n,AH4 m){return max(n,min(x,m));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // V_FRACT_F16 (note DX frac() is different).
+ AH1 AFractH1(AH1 x){return x-floor(x);}
+ AH2 AFractH2(AH2 x){return x-floor(x);}
+ AH3 AFractH3(AH3 x){return x-floor(x);}
+ AH4 AFractH4(AH4 x){return x-floor(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 ALerpH1(AH1 x,AH1 y,AH1 a){return lerp(x,y,a);}
+ AH2 ALerpH2(AH2 x,AH2 y,AH2 a){return lerp(x,y,a);}
+ AH3 ALerpH3(AH3 x,AH3 y,AH3 a){return lerp(x,y,a);}
+ AH4 ALerpH4(AH4 x,AH4 y,AH4 a){return lerp(x,y,a);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AMax3H1(AH1 x,AH1 y,AH1 z){return max(x,max(y,z));}
+ AH2 AMax3H2(AH2 x,AH2 y,AH2 z){return max(x,max(y,z));}
+ AH3 AMax3H3(AH3 x,AH3 y,AH3 z){return max(x,max(y,z));}
+ AH4 AMax3H4(AH4 x,AH4 y,AH4 z){return max(x,max(y,z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AW1 AMaxSW1(AW1 a,AW1 b){return AW1(max(ASU1(a),ASU1(b)));}
+ AW2 AMaxSW2(AW2 a,AW2 b){return AW2(max(ASU2(a),ASU2(b)));}
+ AW3 AMaxSW3(AW3 a,AW3 b){return AW3(max(ASU3(a),ASU3(b)));}
+ AW4 AMaxSW4(AW4 a,AW4 b){return AW4(max(ASU4(a),ASU4(b)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AMin3H1(AH1 x,AH1 y,AH1 z){return min(x,min(y,z));}
+ AH2 AMin3H2(AH2 x,AH2 y,AH2 z){return min(x,min(y,z));}
+ AH3 AMin3H3(AH3 x,AH3 y,AH3 z){return min(x,min(y,z));}
+ AH4 AMin3H4(AH4 x,AH4 y,AH4 z){return min(x,min(y,z));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AW1 AMinSW1(AW1 a,AW1 b){return AW1(min(ASU1(a),ASU1(b)));}
+ AW2 AMinSW2(AW2 a,AW2 b){return AW2(min(ASU2(a),ASU2(b)));}
+ AW3 AMinSW3(AW3 a,AW3 b){return AW3(min(ASU3(a),ASU3(b)));}
+ AW4 AMinSW4(AW4 a,AW4 b){return AW4(min(ASU4(a),ASU4(b)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 ARcpH1(AH1 x){return rcp(x);}
+ AH2 ARcpH2(AH2 x){return rcp(x);}
+ AH3 ARcpH3(AH3 x){return rcp(x);}
+ AH4 ARcpH4(AH4 x){return rcp(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 ARsqH1(AH1 x){return rsqrt(x);}
+ AH2 ARsqH2(AH2 x){return rsqrt(x);}
+ AH3 ARsqH3(AH3 x){return rsqrt(x);}
+ AH4 ARsqH4(AH4 x){return rsqrt(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 ASatH1(AH1 x){return saturate(x);}
+ AH2 ASatH2(AH2 x){return saturate(x);}
+ AH3 ASatH3(AH3 x){return saturate(x);}
+ AH4 ASatH4(AH4 x){return saturate(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AW1 AShrSW1(AW1 a,AW1 b){return AW1(ASW1(a)>>ASW1(b));}
+ AW2 AShrSW2(AW2 a,AW2 b){return AW2(ASW2(a)>>ASW2(b));}
+ AW3 AShrSW3(AW3 a,AW3 b){return AW3(ASW3(a)>>ASW3(b));}
+ AW4 AShrSW4(AW4 a,AW4 b){return AW4(ASW4(a)>>ASW4(b));}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// HLSL DOUBLE
+//==============================================================================================================================
+ #ifdef A_DUBL
+ #ifdef A_HLSL_6_2
+ #define AD1 float64_t
+ #define AD2 float64_t2
+ #define AD3 float64_t3
+ #define AD4 float64_t4
+ #else
+ #define AD1 double
+ #define AD2 double2
+ #define AD3 double3
+ #define AD4 double4
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ AD1 AD1_x(AD1 a){return AD1(a);}
+ AD2 AD2_x(AD1 a){return AD2(a,a);}
+ AD3 AD3_x(AD1 a){return AD3(a,a,a);}
+ AD4 AD4_x(AD1 a){return AD4(a,a,a,a);}
+ #define AD1_(a) AD1_x(AD1(a))
+ #define AD2_(a) AD2_x(AD1(a))
+ #define AD3_(a) AD3_x(AD1(a))
+ #define AD4_(a) AD4_x(AD1(a))
+//==============================================================================================================================
+ AD1 AFractD1(AD1 a){return a-floor(a);}
+ AD2 AFractD2(AD2 a){return a-floor(a);}
+ AD3 AFractD3(AD3 a){return a-floor(a);}
+ AD4 AFractD4(AD4 a){return a-floor(a);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD1 ALerpD1(AD1 x,AD1 y,AD1 a){return lerp(x,y,a);}
+ AD2 ALerpD2(AD2 x,AD2 y,AD2 a){return lerp(x,y,a);}
+ AD3 ALerpD3(AD3 x,AD3 y,AD3 a){return lerp(x,y,a);}
+ AD4 ALerpD4(AD4 x,AD4 y,AD4 a){return lerp(x,y,a);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD1 ARcpD1(AD1 x){return rcp(x);}
+ AD2 ARcpD2(AD2 x){return rcp(x);}
+ AD3 ARcpD3(AD3 x){return rcp(x);}
+ AD4 ARcpD4(AD4 x){return rcp(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD1 ARsqD1(AD1 x){return rsqrt(x);}
+ AD2 ARsqD2(AD2 x){return rsqrt(x);}
+ AD3 ARsqD3(AD3 x){return rsqrt(x);}
+ AD4 ARsqD4(AD4 x){return rsqrt(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD1 ASatD1(AD1 x){return saturate(x);}
+ AD2 ASatD2(AD2 x){return saturate(x);}
+ AD3 ASatD3(AD3 x){return saturate(x);}
+ AD4 ASatD4(AD4 x){return saturate(x);}
+ #endif
+//==============================================================================================================================
+// HLSL WAVE
+//==============================================================================================================================
+ #ifdef A_WAVE
+ // Where 'x' must be a compile time literal.
+ AF1 AWaveXorF1(AF1 v,AU1 x){return WaveReadLaneAt(v,WaveGetLaneIndex()^x);}
+ AF2 AWaveXorF2(AF2 v,AU1 x){return WaveReadLaneAt(v,WaveGetLaneIndex()^x);}
+ AF3 AWaveXorF3(AF3 v,AU1 x){return WaveReadLaneAt(v,WaveGetLaneIndex()^x);}
+ AF4 AWaveXorF4(AF4 v,AU1 x){return WaveReadLaneAt(v,WaveGetLaneIndex()^x);}
+ AU1 AWaveXorU1(AU1 v,AU1 x){return WaveReadLaneAt(v,WaveGetLaneIndex()^x);}
+ AU2 AWaveXorU1(AU2 v,AU1 x){return WaveReadLaneAt(v,WaveGetLaneIndex()^x);}
+ AU3 AWaveXorU1(AU3 v,AU1 x){return WaveReadLaneAt(v,WaveGetLaneIndex()^x);}
+ AU4 AWaveXorU1(AU4 v,AU1 x){return WaveReadLaneAt(v,WaveGetLaneIndex()^x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifdef A_HALF
+ AH2 AWaveXorH2(AH2 v,AU1 x){return AH2_AU1(WaveReadLaneAt(AU1_AH2(v),WaveGetLaneIndex()^x));}
+ AH4 AWaveXorH4(AH4 v,AU1 x){return AH4_AU2(WaveReadLaneAt(AU2_AH4(v),WaveGetLaneIndex()^x));}
+ AW2 AWaveXorW2(AW2 v,AU1 x){return AW2_AU1(WaveReadLaneAt(AU1_AW2(v),WaveGetLaneIndex()^x));}
+ AW4 AWaveXorW4(AW4 v,AU1 x){return AW4_AU1(WaveReadLaneAt(AU1_AW4(v),WaveGetLaneIndex()^x));}
+ #endif
+ #endif
+//==============================================================================================================================
+#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+//
+// GPU COMMON
+//
+//
+//==============================================================================================================================
+#ifdef A_GPU
+ // Negative and positive infinity.
+ #define A_INFP_F AF1_AU1(0x7f800000u)
+ #define A_INFN_F AF1_AU1(0xff800000u)
+//------------------------------------------------------------------------------------------------------------------------------
+ // Copy sign from 's' to positive 'd'.
+ AF1 ACpySgnF1(AF1 d,AF1 s){return AF1_AU1(AU1_AF1(d)|(AU1_AF1(s)&AU1_(0x80000000u)));}
+ AF2 ACpySgnF2(AF2 d,AF2 s){return AF2_AU2(AU2_AF2(d)|(AU2_AF2(s)&AU2_(0x80000000u)));}
+ AF3 ACpySgnF3(AF3 d,AF3 s){return AF3_AU3(AU3_AF3(d)|(AU3_AF3(s)&AU3_(0x80000000u)));}
+ AF4 ACpySgnF4(AF4 d,AF4 s){return AF4_AU4(AU4_AF4(d)|(AU4_AF4(s)&AU4_(0x80000000u)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Single operation to return (useful to create a mask to use in lerp for branch free logic),
+ // m=NaN := 0
+ // m>=0 := 0
+ // m<0 := 1
+ // Uses the following useful floating point logic,
+ // saturate(+a*(-INF)==-INF) := 0
+ // saturate( 0*(-INF)== NaN) := 0
+ // saturate(-a*(-INF)==+INF) := 1
+ AF1 ASignedF1(AF1 m){return ASatF1(m*AF1_(A_INFN_F));}
+ AF2 ASignedF2(AF2 m){return ASatF2(m*AF2_(A_INFN_F));}
+ AF3 ASignedF3(AF3 m){return ASatF3(m*AF3_(A_INFN_F));}
+ AF4 ASignedF4(AF4 m){return ASatF4(m*AF4_(A_INFN_F));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AGtZeroF1(AF1 m){return ASatF1(m*AF1_(A_INFP_F));}
+ AF2 AGtZeroF2(AF2 m){return ASatF2(m*AF2_(A_INFP_F));}
+ AF3 AGtZeroF3(AF3 m){return ASatF3(m*AF3_(A_INFP_F));}
+ AF4 AGtZeroF4(AF4 m){return ASatF4(m*AF4_(A_INFP_F));}
+//==============================================================================================================================
+ #ifdef A_HALF
+ #ifdef A_HLSL_6_2
+ #define A_INFP_H AH1_AW1((uint16_t)0x7c00u)
+ #define A_INFN_H AH1_AW1((uint16_t)0xfc00u)
+ #else
+ #define A_INFP_H AH1_AW1(0x7c00u)
+ #define A_INFN_H AH1_AW1(0xfc00u)
+ #endif
+
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 ACpySgnH1(AH1 d,AH1 s){return AH1_AW1(AW1_AH1(d)|(AW1_AH1(s)&AW1_(0x8000u)));}
+ AH2 ACpySgnH2(AH2 d,AH2 s){return AH2_AW2(AW2_AH2(d)|(AW2_AH2(s)&AW2_(0x8000u)));}
+ AH3 ACpySgnH3(AH3 d,AH3 s){return AH3_AW3(AW3_AH3(d)|(AW3_AH3(s)&AW3_(0x8000u)));}
+ AH4 ACpySgnH4(AH4 d,AH4 s){return AH4_AW4(AW4_AH4(d)|(AW4_AH4(s)&AW4_(0x8000u)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 ASignedH1(AH1 m){return ASatH1(m*AH1_(A_INFN_H));}
+ AH2 ASignedH2(AH2 m){return ASatH2(m*AH2_(A_INFN_H));}
+ AH3 ASignedH3(AH3 m){return ASatH3(m*AH3_(A_INFN_H));}
+ AH4 ASignedH4(AH4 m){return ASatH4(m*AH4_(A_INFN_H));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AGtZeroH1(AH1 m){return ASatH1(m*AH1_(A_INFP_H));}
+ AH2 AGtZeroH2(AH2 m){return ASatH2(m*AH2_(A_INFP_H));}
+ AH3 AGtZeroH3(AH3 m){return ASatH3(m*AH3_(A_INFP_H));}
+ AH4 AGtZeroH4(AH4 m){return ASatH4(m*AH4_(A_INFP_H));}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// [FIS] FLOAT INTEGER SORTABLE
+//------------------------------------------------------------------------------------------------------------------------------
+// Float to integer sortable.
+// - If sign bit=0, flip the sign bit (positives).
+// - If sign bit=1, flip all bits (negatives).
+// Integer sortable to float.
+// - If sign bit=1, flip the sign bit (positives).
+// - If sign bit=0, flip all bits (negatives).
+// Has nice side effects.
+// - Larger integers are more positive values.
+// - Float zero is mapped to center of integers (so clear to integer zero is a nice default for atomic max usage).
+// Burns 3 ops for conversion {shift,or,xor}.
+//==============================================================================================================================
+ AU1 AFisToU1(AU1 x){return x^(( AShrSU1(x,AU1_(31)))|AU1_(0x80000000));}
+ AU1 AFisFromU1(AU1 x){return x^((~AShrSU1(x,AU1_(31)))|AU1_(0x80000000));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Just adjust high 16-bit value (useful when upper part of 32-bit word is a 16-bit float value).
+ AU1 AFisToHiU1(AU1 x){return x^(( AShrSU1(x,AU1_(15)))|AU1_(0x80000000));}
+ AU1 AFisFromHiU1(AU1 x){return x^((~AShrSU1(x,AU1_(15)))|AU1_(0x80000000));}
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifdef A_HALF
+ AW1 AFisToW1(AW1 x){return x^(( AShrSW1(x,AW1_(15)))|AW1_(0x8000));}
+ AW1 AFisFromW1(AW1 x){return x^((~AShrSW1(x,AW1_(15)))|AW1_(0x8000));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AW2 AFisToW2(AW2 x){return x^(( AShrSW2(x,AW2_(15)))|AW2_(0x8000));}
+ AW2 AFisFromW2(AW2 x){return x^((~AShrSW2(x,AW2_(15)))|AW2_(0x8000));}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// [PERM] V_PERM_B32
+//------------------------------------------------------------------------------------------------------------------------------
+// Support for V_PERM_B32 started in the 3rd generation of GCN.
+//------------------------------------------------------------------------------------------------------------------------------
+// yyyyxxxx - The 'i' input.
+// 76543210
+// ========
+// HGFEDCBA - Naming on permutation.
+//------------------------------------------------------------------------------------------------------------------------------
+// TODO
+// ====
+// - Make sure compiler optimizes this.
+//==============================================================================================================================
+ #ifdef A_HALF
+ AU1 APerm0E0A(AU2 i){return((i.x )&0xffu)|((i.y<<16)&0xff0000u);}
+ AU1 APerm0F0B(AU2 i){return((i.x>> 8)&0xffu)|((i.y<< 8)&0xff0000u);}
+ AU1 APerm0G0C(AU2 i){return((i.x>>16)&0xffu)|((i.y )&0xff0000u);}
+ AU1 APerm0H0D(AU2 i){return((i.x>>24)&0xffu)|((i.y>> 8)&0xff0000u);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 APermHGFA(AU2 i){return((i.x )&0x000000ffu)|(i.y&0xffffff00u);}
+ AU1 APermHGFC(AU2 i){return((i.x>>16)&0x000000ffu)|(i.y&0xffffff00u);}
+ AU1 APermHGAE(AU2 i){return((i.x<< 8)&0x0000ff00u)|(i.y&0xffff00ffu);}
+ AU1 APermHGCE(AU2 i){return((i.x>> 8)&0x0000ff00u)|(i.y&0xffff00ffu);}
+ AU1 APermHAFE(AU2 i){return((i.x<<16)&0x00ff0000u)|(i.y&0xff00ffffu);}
+ AU1 APermHCFE(AU2 i){return((i.x )&0x00ff0000u)|(i.y&0xff00ffffu);}
+ AU1 APermAGFE(AU2 i){return((i.x<<24)&0xff000000u)|(i.y&0x00ffffffu);}
+ AU1 APermCGFE(AU2 i){return((i.x<< 8)&0xff000000u)|(i.y&0x00ffffffu);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 APermGCEA(AU2 i){return((i.x)&0x00ff00ffu)|((i.y<<8)&0xff00ff00u);}
+ AU1 APermGECA(AU2 i){return(((i.x)&0xffu)|((i.x>>8)&0xff00u)|((i.y<<16)&0xff0000u)|((i.y<<8)&0xff000000u));}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// [BUC] BYTE UNSIGNED CONVERSION
+//------------------------------------------------------------------------------------------------------------------------------
+// Designed to use the optimal conversion, enables the scaling to possibly be factored into other computation.
+// Works on a range of {0 to A_BUC_<32,16>}, for <32-bit, and 16-bit> respectively.
+//------------------------------------------------------------------------------------------------------------------------------
+// OPCODE NOTES
+// ============
+// GCN does not do UNORM or SNORM for bytes in opcodes.
+// - V_CVT_F32_UBYTE{0,1,2,3} - Unsigned byte to float.
+// - V_CVT_PKACC_U8_F32 - Float to unsigned byte (does bit-field insert into 32-bit integer).
+// V_PERM_B32 does byte packing with ability to zero fill bytes as well.
+// - Can pull out byte values from two sources, and zero fill upper 8-bits of packed hi and lo.
+//------------------------------------------------------------------------------------------------------------------------------
+// BYTE : FLOAT - ABuc{0,1,2,3}{To,From}U1() - Designed for V_CVT_F32_UBYTE* and V_CVT_PKACCUM_U8_F32 ops.
+// ==== =====
+// 0 : 0
+// 1 : 1
+// ...
+// 255 : 255
+// : 256 (just outside the encoding range)
+//------------------------------------------------------------------------------------------------------------------------------
+// BYTE : FLOAT - ABuc{0,1,2,3}{To,From}U2() - Designed for 16-bit denormal tricks and V_PERM_B32.
+// ==== =====
+// 0 : 0
+// 1 : 1/512
+// 2 : 1/256
+// ...
+// 64 : 1/8
+// 128 : 1/4
+// 255 : 255/512
+// : 1/2 (just outside the encoding range)
+//------------------------------------------------------------------------------------------------------------------------------
+// OPTIMAL IMPLEMENTATIONS ON AMD ARCHITECTURES
+// ============================================
+// r=ABuc0FromU1(i)
+// V_CVT_F32_UBYTE0 r,i
+// --------------------------------------------
+// r=ABuc0ToU1(d,i)
+// V_CVT_PKACCUM_U8_F32 r,i,0,d
+// --------------------------------------------
+// d=ABuc0FromU2(i)
+// Where 'k0' is an SGPR with 0x0E0A
+// Where 'k1' is an SGPR with {32768.0} packed into the lower 16-bits
+// V_PERM_B32 d,i.x,i.y,k0
+// V_PK_FMA_F16 d,d,k1.x,0
+// --------------------------------------------
+// r=ABuc0ToU2(d,i)
+// Where 'k0' is an SGPR with {1.0/32768.0} packed into the lower 16-bits
+// Where 'k1' is an SGPR with 0x????
+// Where 'k2' is an SGPR with 0x????
+// V_PK_FMA_F16 i,i,k0.x,0
+// V_PERM_B32 r.x,i,i,k1
+// V_PERM_B32 r.y,i,i,k2
+//==============================================================================================================================
+ // Peak range for 32-bit and 16-bit operations.
+ #define A_BUC_32 (255.0)
+ #define A_BUC_16 (255.0/512.0)
+//==============================================================================================================================
+ #if 1
+ // Designed to be one V_CVT_PKACCUM_U8_F32.
+ // The extra min is required to pattern match to V_CVT_PKACCUM_U8_F32.
+ AU1 ABuc0ToU1(AU1 d,AF1 i){return (d&0xffffff00u)|((min(AU1(i),255u) )&(0x000000ffu));}
+ AU1 ABuc1ToU1(AU1 d,AF1 i){return (d&0xffff00ffu)|((min(AU1(i),255u)<< 8)&(0x0000ff00u));}
+ AU1 ABuc2ToU1(AU1 d,AF1 i){return (d&0xff00ffffu)|((min(AU1(i),255u)<<16)&(0x00ff0000u));}
+ AU1 ABuc3ToU1(AU1 d,AF1 i){return (d&0x00ffffffu)|((min(AU1(i),255u)<<24)&(0xff000000u));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Designed to be one V_CVT_F32_UBYTE*.
+ AF1 ABuc0FromU1(AU1 i){return AF1((i )&255u);}
+ AF1 ABuc1FromU1(AU1 i){return AF1((i>> 8)&255u);}
+ AF1 ABuc2FromU1(AU1 i){return AF1((i>>16)&255u);}
+ AF1 ABuc3FromU1(AU1 i){return AF1((i>>24)&255u);}
+ #endif
+//==============================================================================================================================
+ #ifdef A_HALF
+ // Takes {x0,x1} and {y0,y1} and builds {{x0,y0},{x1,y1}}.
+ AW2 ABuc01ToW2(AH2 x,AH2 y){x*=AH2_(1.0/32768.0);y*=AH2_(1.0/32768.0);
+ return AW2_AU1(APermGCEA(AU2(AU1_AW2(AW2_AH2(x)),AU1_AW2(AW2_AH2(y)))));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Designed for 3 ops to do SOA to AOS and conversion.
+ AU2 ABuc0ToU2(AU2 d,AH2 i){AU1 b=AU1_AW2(AW2_AH2(i*AH2_(1.0/32768.0)));
+ return AU2(APermHGFA(AU2(d.x,b)),APermHGFC(AU2(d.y,b)));}
+ AU2 ABuc1ToU2(AU2 d,AH2 i){AU1 b=AU1_AW2(AW2_AH2(i*AH2_(1.0/32768.0)));
+ return AU2(APermHGAE(AU2(d.x,b)),APermHGCE(AU2(d.y,b)));}
+ AU2 ABuc2ToU2(AU2 d,AH2 i){AU1 b=AU1_AW2(AW2_AH2(i*AH2_(1.0/32768.0)));
+ return AU2(APermHAFE(AU2(d.x,b)),APermHCFE(AU2(d.y,b)));}
+ AU2 ABuc3ToU2(AU2 d,AH2 i){AU1 b=AU1_AW2(AW2_AH2(i*AH2_(1.0/32768.0)));
+ return AU2(APermAGFE(AU2(d.x,b)),APermCGFE(AU2(d.y,b)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Designed for 2 ops to do both AOS to SOA, and conversion.
+ AH2 ABuc0FromU2(AU2 i){return AH2_AW2(AW2_AU1(APerm0E0A(i)))*AH2_(32768.0);}
+ AH2 ABuc1FromU2(AU2 i){return AH2_AW2(AW2_AU1(APerm0F0B(i)))*AH2_(32768.0);}
+ AH2 ABuc2FromU2(AU2 i){return AH2_AW2(AW2_AU1(APerm0G0C(i)))*AH2_(32768.0);}
+ AH2 ABuc3FromU2(AU2 i){return AH2_AW2(AW2_AU1(APerm0H0D(i)))*AH2_(32768.0);}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// [BSC] BYTE SIGNED CONVERSION
+//------------------------------------------------------------------------------------------------------------------------------
+// Similar to [BUC].
+// Works on a range of {-/+ A_BSC_<32,16>}, for <32-bit, and 16-bit> respectively.
+//------------------------------------------------------------------------------------------------------------------------------
+// ENCODING (without zero-based encoding)
+// ========
+// 0 = unused (can be used to mean something else)
+// 1 = lowest value
+// 128 = exact zero center (zero based encoding
+// 255 = highest value
+//------------------------------------------------------------------------------------------------------------------------------
+// Zero-based [Zb] flips the MSB bit of the byte (making 128 "exact zero" actually zero).
+// This is useful if there is a desire for cleared values to decode as zero.
+//------------------------------------------------------------------------------------------------------------------------------
+// BYTE : FLOAT - ABsc{0,1,2,3}{To,From}U2() - Designed for 16-bit denormal tricks and V_PERM_B32.
+// ==== =====
+// 0 : -127/512 (unused)
+// 1 : -126/512
+// 2 : -125/512
+// ...
+// 128 : 0
+// ...
+// 255 : 127/512
+// : 1/4 (just outside the encoding range)
+//==============================================================================================================================
+ // Peak range for 32-bit and 16-bit operations.
+ #define A_BSC_32 (127.0)
+ #define A_BSC_16 (127.0/512.0)
+//==============================================================================================================================
+ #if 1
+ AU1 ABsc0ToU1(AU1 d,AF1 i){return (d&0xffffff00u)|((min(AU1(i+128.0),255u) )&(0x000000ffu));}
+ AU1 ABsc1ToU1(AU1 d,AF1 i){return (d&0xffff00ffu)|((min(AU1(i+128.0),255u)<< 8)&(0x0000ff00u));}
+ AU1 ABsc2ToU1(AU1 d,AF1 i){return (d&0xff00ffffu)|((min(AU1(i+128.0),255u)<<16)&(0x00ff0000u));}
+ AU1 ABsc3ToU1(AU1 d,AF1 i){return (d&0x00ffffffu)|((min(AU1(i+128.0),255u)<<24)&(0xff000000u));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 ABsc0ToZbU1(AU1 d,AF1 i){return ((d&0xffffff00u)|((min(AU1(trunc(i)+128.0),255u) )&(0x000000ffu)))^0x00000080u;}
+ AU1 ABsc1ToZbU1(AU1 d,AF1 i){return ((d&0xffff00ffu)|((min(AU1(trunc(i)+128.0),255u)<< 8)&(0x0000ff00u)))^0x00008000u;}
+ AU1 ABsc2ToZbU1(AU1 d,AF1 i){return ((d&0xff00ffffu)|((min(AU1(trunc(i)+128.0),255u)<<16)&(0x00ff0000u)))^0x00800000u;}
+ AU1 ABsc3ToZbU1(AU1 d,AF1 i){return ((d&0x00ffffffu)|((min(AU1(trunc(i)+128.0),255u)<<24)&(0xff000000u)))^0x80000000u;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ABsc0FromU1(AU1 i){return AF1((i )&255u)-128.0;}
+ AF1 ABsc1FromU1(AU1 i){return AF1((i>> 8)&255u)-128.0;}
+ AF1 ABsc2FromU1(AU1 i){return AF1((i>>16)&255u)-128.0;}
+ AF1 ABsc3FromU1(AU1 i){return AF1((i>>24)&255u)-128.0;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ABsc0FromZbU1(AU1 i){return AF1(((i )&255u)^0x80u)-128.0;}
+ AF1 ABsc1FromZbU1(AU1 i){return AF1(((i>> 8)&255u)^0x80u)-128.0;}
+ AF1 ABsc2FromZbU1(AU1 i){return AF1(((i>>16)&255u)^0x80u)-128.0;}
+ AF1 ABsc3FromZbU1(AU1 i){return AF1(((i>>24)&255u)^0x80u)-128.0;}
+ #endif
+//==============================================================================================================================
+ #ifdef A_HALF
+ // Takes {x0,x1} and {y0,y1} and builds {{x0,y0},{x1,y1}}.
+ AW2 ABsc01ToW2(AH2 x,AH2 y){x=x*AH2_(1.0/32768.0)+AH2_(0.25/32768.0);y=y*AH2_(1.0/32768.0)+AH2_(0.25/32768.0);
+ return AW2_AU1(APermGCEA(AU2(AU1_AW2(AW2_AH2(x)),AU1_AW2(AW2_AH2(y)))));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU2 ABsc0ToU2(AU2 d,AH2 i){AU1 b=AU1_AW2(AW2_AH2(i*AH2_(1.0/32768.0)+AH2_(0.25/32768.0)));
+ return AU2(APermHGFA(AU2(d.x,b)),APermHGFC(AU2(d.y,b)));}
+ AU2 ABsc1ToU2(AU2 d,AH2 i){AU1 b=AU1_AW2(AW2_AH2(i*AH2_(1.0/32768.0)+AH2_(0.25/32768.0)));
+ return AU2(APermHGAE(AU2(d.x,b)),APermHGCE(AU2(d.y,b)));}
+ AU2 ABsc2ToU2(AU2 d,AH2 i){AU1 b=AU1_AW2(AW2_AH2(i*AH2_(1.0/32768.0)+AH2_(0.25/32768.0)));
+ return AU2(APermHAFE(AU2(d.x,b)),APermHCFE(AU2(d.y,b)));}
+ AU2 ABsc3ToU2(AU2 d,AH2 i){AU1 b=AU1_AW2(AW2_AH2(i*AH2_(1.0/32768.0)+AH2_(0.25/32768.0)));
+ return AU2(APermAGFE(AU2(d.x,b)),APermCGFE(AU2(d.y,b)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU2 ABsc0ToZbU2(AU2 d,AH2 i){AU1 b=AU1_AW2(AW2_AH2(i*AH2_(1.0/32768.0)+AH2_(0.25/32768.0)))^0x00800080u;
+ return AU2(APermHGFA(AU2(d.x,b)),APermHGFC(AU2(d.y,b)));}
+ AU2 ABsc1ToZbU2(AU2 d,AH2 i){AU1 b=AU1_AW2(AW2_AH2(i*AH2_(1.0/32768.0)+AH2_(0.25/32768.0)))^0x00800080u;
+ return AU2(APermHGAE(AU2(d.x,b)),APermHGCE(AU2(d.y,b)));}
+ AU2 ABsc2ToZbU2(AU2 d,AH2 i){AU1 b=AU1_AW2(AW2_AH2(i*AH2_(1.0/32768.0)+AH2_(0.25/32768.0)))^0x00800080u;
+ return AU2(APermHAFE(AU2(d.x,b)),APermHCFE(AU2(d.y,b)));}
+ AU2 ABsc3ToZbU2(AU2 d,AH2 i){AU1 b=AU1_AW2(AW2_AH2(i*AH2_(1.0/32768.0)+AH2_(0.25/32768.0)))^0x00800080u;
+ return AU2(APermAGFE(AU2(d.x,b)),APermCGFE(AU2(d.y,b)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH2 ABsc0FromU2(AU2 i){return AH2_AW2(AW2_AU1(APerm0E0A(i)))*AH2_(32768.0)-AH2_(0.25);}
+ AH2 ABsc1FromU2(AU2 i){return AH2_AW2(AW2_AU1(APerm0F0B(i)))*AH2_(32768.0)-AH2_(0.25);}
+ AH2 ABsc2FromU2(AU2 i){return AH2_AW2(AW2_AU1(APerm0G0C(i)))*AH2_(32768.0)-AH2_(0.25);}
+ AH2 ABsc3FromU2(AU2 i){return AH2_AW2(AW2_AU1(APerm0H0D(i)))*AH2_(32768.0)-AH2_(0.25);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH2 ABsc0FromZbU2(AU2 i){return AH2_AW2(AW2_AU1(APerm0E0A(i)^0x00800080u))*AH2_(32768.0)-AH2_(0.25);}
+ AH2 ABsc1FromZbU2(AU2 i){return AH2_AW2(AW2_AU1(APerm0F0B(i)^0x00800080u))*AH2_(32768.0)-AH2_(0.25);}
+ AH2 ABsc2FromZbU2(AU2 i){return AH2_AW2(AW2_AU1(APerm0G0C(i)^0x00800080u))*AH2_(32768.0)-AH2_(0.25);}
+ AH2 ABsc3FromZbU2(AU2 i){return AH2_AW2(AW2_AU1(APerm0H0D(i)^0x00800080u))*AH2_(32768.0)-AH2_(0.25);}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// HALF APPROXIMATIONS
+//------------------------------------------------------------------------------------------------------------------------------
+// These support only positive inputs.
+// Did not see value yet in specialization for range.
+// Using quick testing, ended up mostly getting the same "best" approximation for various ranges.
+// With hardware that can co-execute transcendentals, the value in approximations could be less than expected.
+// However from a latency perspective, if execution of a transcendental is 4 clk, with no packed support, -> 8 clk total.
+// And co-execution would require a compiler interleaving a lot of independent work for packed usage.
+//------------------------------------------------------------------------------------------------------------------------------
+// The one Newton Raphson iteration form of rsq() was skipped (requires 6 ops total).
+// Same with sqrt(), as this could be x*rsq() (7 ops).
+//==============================================================================================================================
+ #ifdef A_HALF
+ // Minimize squared error across full positive range, 2 ops.
+ // The 0x1de2 based approximation maps {0 to 1} input maps to < 1 output.
+ AH1 APrxLoSqrtH1(AH1 a){return AH1_AW1((AW1_AH1(a)>>AW1_(1))+AW1_(0x1de2));}
+ AH2 APrxLoSqrtH2(AH2 a){return AH2_AW2((AW2_AH2(a)>>AW2_(1))+AW2_(0x1de2));}
+ AH3 APrxLoSqrtH3(AH3 a){return AH3_AW3((AW3_AH3(a)>>AW3_(1))+AW3_(0x1de2));}
+ AH4 APrxLoSqrtH4(AH4 a){return AH4_AW4((AW4_AH4(a)>>AW4_(1))+AW4_(0x1de2));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Lower precision estimation, 1 op.
+ // Minimize squared error across {smallest normal to 16384.0}.
+ AH1 APrxLoRcpH1(AH1 a){return AH1_AW1(AW1_(0x7784)-AW1_AH1(a));}
+ AH2 APrxLoRcpH2(AH2 a){return AH2_AW2(AW2_(0x7784)-AW2_AH2(a));}
+ AH3 APrxLoRcpH3(AH3 a){return AH3_AW3(AW3_(0x7784)-AW3_AH3(a));}
+ AH4 APrxLoRcpH4(AH4 a){return AH4_AW4(AW4_(0x7784)-AW4_AH4(a));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Medium precision estimation, one Newton Raphson iteration, 3 ops.
+ AH1 APrxMedRcpH1(AH1 a){AH1 b=AH1_AW1(AW1_(0x778d)-AW1_AH1(a));return b*(-b*a+AH1_(2.0));}
+ AH2 APrxMedRcpH2(AH2 a){AH2 b=AH2_AW2(AW2_(0x778d)-AW2_AH2(a));return b*(-b*a+AH2_(2.0));}
+ AH3 APrxMedRcpH3(AH3 a){AH3 b=AH3_AW3(AW3_(0x778d)-AW3_AH3(a));return b*(-b*a+AH3_(2.0));}
+ AH4 APrxMedRcpH4(AH4 a){AH4 b=AH4_AW4(AW4_(0x778d)-AW4_AH4(a));return b*(-b*a+AH4_(2.0));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Minimize squared error across {smallest normal to 16384.0}, 2 ops.
+ AH1 APrxLoRsqH1(AH1 a){return AH1_AW1(AW1_(0x59a3)-(AW1_AH1(a)>>AW1_(1)));}
+ AH2 APrxLoRsqH2(AH2 a){return AH2_AW2(AW2_(0x59a3)-(AW2_AH2(a)>>AW2_(1)));}
+ AH3 APrxLoRsqH3(AH3 a){return AH3_AW3(AW3_(0x59a3)-(AW3_AH3(a)>>AW3_(1)));}
+ AH4 APrxLoRsqH4(AH4 a){return AH4_AW4(AW4_(0x59a3)-(AW4_AH4(a)>>AW4_(1)));}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// FLOAT APPROXIMATIONS
+//------------------------------------------------------------------------------------------------------------------------------
+// Michal Drobot has an excellent presentation on these: "Low Level Optimizations For GCN",
+// - Idea dates back to SGI, then to Quake 3, etc.
+// - https://michaldrobot.files.wordpress.com/2014/05/gcn_alu_opt_digitaldragons2014.pdf
+// - sqrt(x)=rsqrt(x)*x
+// - rcp(x)=rsqrt(x)*rsqrt(x) for positive x
+// - https://github.com/michaldrobot/ShaderFastLibs/blob/master/ShaderFastMathLib.h
+//------------------------------------------------------------------------------------------------------------------------------
+// These below are from perhaps less complete searching for optimal.
+// Used FP16 normal range for testing with +4096 32-bit step size for sampling error.
+// So these match up well with the half approximations.
+//==============================================================================================================================
+ AF1 APrxLoSqrtF1(AF1 a){return AF1_AU1((AU1_AF1(a)>>AU1_(1))+AU1_(0x1fbc4639));}
+ AF1 APrxLoRcpF1(AF1 a){return AF1_AU1(AU1_(0x7ef07ebb)-AU1_AF1(a));}
+ AF1 APrxMedRcpF1(AF1 a){AF1 b=AF1_AU1(AU1_(0x7ef19fff)-AU1_AF1(a));return b*(-b*a+AF1_(2.0));}
+ AF1 APrxLoRsqF1(AF1 a){return AF1_AU1(AU1_(0x5f347d74)-(AU1_AF1(a)>>AU1_(1)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 APrxLoSqrtF2(AF2 a){return AF2_AU2((AU2_AF2(a)>>AU2_(1))+AU2_(0x1fbc4639));}
+ AF2 APrxLoRcpF2(AF2 a){return AF2_AU2(AU2_(0x7ef07ebb)-AU2_AF2(a));}
+ AF2 APrxMedRcpF2(AF2 a){AF2 b=AF2_AU2(AU2_(0x7ef19fff)-AU2_AF2(a));return b*(-b*a+AF2_(2.0));}
+ AF2 APrxLoRsqF2(AF2 a){return AF2_AU2(AU2_(0x5f347d74)-(AU2_AF2(a)>>AU2_(1)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF3 APrxLoSqrtF3(AF3 a){return AF3_AU3((AU3_AF3(a)>>AU3_(1))+AU3_(0x1fbc4639));}
+ AF3 APrxLoRcpF3(AF3 a){return AF3_AU3(AU3_(0x7ef07ebb)-AU3_AF3(a));}
+ AF3 APrxMedRcpF3(AF3 a){AF3 b=AF3_AU3(AU3_(0x7ef19fff)-AU3_AF3(a));return b*(-b*a+AF3_(2.0));}
+ AF3 APrxLoRsqF3(AF3 a){return AF3_AU3(AU3_(0x5f347d74)-(AU3_AF3(a)>>AU3_(1)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF4 APrxLoSqrtF4(AF4 a){return AF4_AU4((AU4_AF4(a)>>AU4_(1))+AU4_(0x1fbc4639));}
+ AF4 APrxLoRcpF4(AF4 a){return AF4_AU4(AU4_(0x7ef07ebb)-AU4_AF4(a));}
+ AF4 APrxMedRcpF4(AF4 a){AF4 b=AF4_AU4(AU4_(0x7ef19fff)-AU4_AF4(a));return b*(-b*a+AF4_(2.0));}
+ AF4 APrxLoRsqF4(AF4 a){return AF4_AU4(AU4_(0x5f347d74)-(AU4_AF4(a)>>AU4_(1)));}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// PQ APPROXIMATIONS
+//------------------------------------------------------------------------------------------------------------------------------
+// PQ is very close to x^(1/8). The functions below Use the fast float approximation method to do
+// PQ<~>Gamma2 (4th power and fast 4th root) and PQ<~>Linear (8th power and fast 8th root). Maximum error is ~0.2%.
+//==============================================================================================================================
+// Helpers
+ AF1 Quart(AF1 a) { a = a * a; return a * a;}
+ AF1 Oct(AF1 a) { a = a * a; a = a * a; return a * a; }
+ AF2 Quart(AF2 a) { a = a * a; return a * a; }
+ AF2 Oct(AF2 a) { a = a * a; a = a * a; return a * a; }
+ AF3 Quart(AF3 a) { a = a * a; return a * a; }
+ AF3 Oct(AF3 a) { a = a * a; a = a * a; return a * a; }
+ AF4 Quart(AF4 a) { a = a * a; return a * a; }
+ AF4 Oct(AF4 a) { a = a * a; a = a * a; return a * a; }
+ //------------------------------------------------------------------------------------------------------------------------------
+ AF1 APrxPQToGamma2(AF1 a) { return Quart(a); }
+ AF1 APrxPQToLinear(AF1 a) { return Oct(a); }
+ AF1 APrxLoGamma2ToPQ(AF1 a) { return AF1_AU1((AU1_AF1(a) >> AU1_(2)) + AU1_(0x2F9A4E46)); }
+ AF1 APrxMedGamma2ToPQ(AF1 a) { AF1 b = AF1_AU1((AU1_AF1(a) >> AU1_(2)) + AU1_(0x2F9A4E46)); AF1 b4 = Quart(b); return b - b * (b4 - a) / (AF1_(4.0) * b4); }
+ AF1 APrxHighGamma2ToPQ(AF1 a) { return sqrt(sqrt(a)); }
+ AF1 APrxLoLinearToPQ(AF1 a) { return AF1_AU1((AU1_AF1(a) >> AU1_(3)) + AU1_(0x378D8723)); }
+ AF1 APrxMedLinearToPQ(AF1 a) { AF1 b = AF1_AU1((AU1_AF1(a) >> AU1_(3)) + AU1_(0x378D8723)); AF1 b8 = Oct(b); return b - b * (b8 - a) / (AF1_(8.0) * b8); }
+ AF1 APrxHighLinearToPQ(AF1 a) { return sqrt(sqrt(sqrt(a))); }
+ //------------------------------------------------------------------------------------------------------------------------------
+ AF2 APrxPQToGamma2(AF2 a) { return Quart(a); }
+ AF2 APrxPQToLinear(AF2 a) { return Oct(a); }
+ AF2 APrxLoGamma2ToPQ(AF2 a) { return AF2_AU2((AU2_AF2(a) >> AU2_(2)) + AU2_(0x2F9A4E46)); }
+ AF2 APrxMedGamma2ToPQ(AF2 a) { AF2 b = AF2_AU2((AU2_AF2(a) >> AU2_(2)) + AU2_(0x2F9A4E46)); AF2 b4 = Quart(b); return b - b * (b4 - a) / (AF1_(4.0) * b4); }
+ AF2 APrxHighGamma2ToPQ(AF2 a) { return sqrt(sqrt(a)); }
+ AF2 APrxLoLinearToPQ(AF2 a) { return AF2_AU2((AU2_AF2(a) >> AU2_(3)) + AU2_(0x378D8723)); }
+ AF2 APrxMedLinearToPQ(AF2 a) { AF2 b = AF2_AU2((AU2_AF2(a) >> AU2_(3)) + AU2_(0x378D8723)); AF2 b8 = Oct(b); return b - b * (b8 - a) / (AF1_(8.0) * b8); }
+ AF2 APrxHighLinearToPQ(AF2 a) { return sqrt(sqrt(sqrt(a))); }
+ //------------------------------------------------------------------------------------------------------------------------------
+ AF3 APrxPQToGamma2(AF3 a) { return Quart(a); }
+ AF3 APrxPQToLinear(AF3 a) { return Oct(a); }
+ AF3 APrxLoGamma2ToPQ(AF3 a) { return AF3_AU3((AU3_AF3(a) >> AU3_(2)) + AU3_(0x2F9A4E46)); }
+ AF3 APrxMedGamma2ToPQ(AF3 a) { AF3 b = AF3_AU3((AU3_AF3(a) >> AU3_(2)) + AU3_(0x2F9A4E46)); AF3 b4 = Quart(b); return b - b * (b4 - a) / (AF1_(4.0) * b4); }
+ AF3 APrxHighGamma2ToPQ(AF3 a) { return sqrt(sqrt(a)); }
+ AF3 APrxLoLinearToPQ(AF3 a) { return AF3_AU3((AU3_AF3(a) >> AU3_(3)) + AU3_(0x378D8723)); }
+ AF3 APrxMedLinearToPQ(AF3 a) { AF3 b = AF3_AU3((AU3_AF3(a) >> AU3_(3)) + AU3_(0x378D8723)); AF3 b8 = Oct(b); return b - b * (b8 - a) / (AF1_(8.0) * b8); }
+ AF3 APrxHighLinearToPQ(AF3 a) { return sqrt(sqrt(sqrt(a))); }
+ //------------------------------------------------------------------------------------------------------------------------------
+ AF4 APrxPQToGamma2(AF4 a) { return Quart(a); }
+ AF4 APrxPQToLinear(AF4 a) { return Oct(a); }
+ AF4 APrxLoGamma2ToPQ(AF4 a) { return AF4_AU4((AU4_AF4(a) >> AU4_(2)) + AU4_(0x2F9A4E46)); }
+ AF4 APrxMedGamma2ToPQ(AF4 a) { AF4 b = AF4_AU4((AU4_AF4(a) >> AU4_(2)) + AU4_(0x2F9A4E46)); AF4 b4 = Quart(b); return b - b * (b4 - a) / (AF1_(4.0) * b4); }
+ AF4 APrxHighGamma2ToPQ(AF4 a) { return sqrt(sqrt(a)); }
+ AF4 APrxLoLinearToPQ(AF4 a) { return AF4_AU4((AU4_AF4(a) >> AU4_(3)) + AU4_(0x378D8723)); }
+ AF4 APrxMedLinearToPQ(AF4 a) { AF4 b = AF4_AU4((AU4_AF4(a) >> AU4_(3)) + AU4_(0x378D8723)); AF4 b8 = Oct(b); return b - b * (b8 - a) / (AF1_(8.0) * b8); }
+ AF4 APrxHighLinearToPQ(AF4 a) { return sqrt(sqrt(sqrt(a))); }
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// PARABOLIC SIN & COS
+//------------------------------------------------------------------------------------------------------------------------------
+// Approximate answers to transcendental questions.
+//------------------------------------------------------------------------------------------------------------------------------
+//==============================================================================================================================
+ #if 1
+ // Valid input range is {-1 to 1} representing {0 to 2 pi}.
+ // Output range is {-1/4 to 1/4} representing {-1 to 1}.
+ AF1 APSinF1(AF1 x){return x*abs(x)-x;} // MAD.
+ AF2 APSinF2(AF2 x){return x*abs(x)-x;}
+ AF1 APCosF1(AF1 x){x=AFractF1(x*AF1_(0.5)+AF1_(0.75));x=x*AF1_(2.0)-AF1_(1.0);return APSinF1(x);} // 3x MAD, FRACT
+ AF2 APCosF2(AF2 x){x=AFractF2(x*AF2_(0.5)+AF2_(0.75));x=x*AF2_(2.0)-AF2_(1.0);return APSinF2(x);}
+ AF2 APSinCosF1(AF1 x){AF1 y=AFractF1(x*AF1_(0.5)+AF1_(0.75));y=y*AF1_(2.0)-AF1_(1.0);return APSinF2(AF2(x,y));}
+ #endif
+//------------------------------------------------------------------------------------------------------------------------------
+ #ifdef A_HALF
+ // For a packed {sin,cos} pair,
+ // - Native takes 16 clocks and 4 issue slots (no packed transcendentals).
+ // - Parabolic takes 8 clocks and 8 issue slots (only fract is non-packed).
+ AH1 APSinH1(AH1 x){return x*abs(x)-x;}
+ AH2 APSinH2(AH2 x){return x*abs(x)-x;} // AND,FMA
+ AH1 APCosH1(AH1 x){x=AFractH1(x*AH1_(0.5)+AH1_(0.75));x=x*AH1_(2.0)-AH1_(1.0);return APSinH1(x);}
+ AH2 APCosH2(AH2 x){x=AFractH2(x*AH2_(0.5)+AH2_(0.75));x=x*AH2_(2.0)-AH2_(1.0);return APSinH2(x);} // 3x FMA, 2xFRACT, AND
+ AH2 APSinCosH1(AH1 x){AH1 y=AFractH1(x*AH1_(0.5)+AH1_(0.75));y=y*AH1_(2.0)-AH1_(1.0);return APSinH2(AH2(x,y));}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// [ZOL] ZERO ONE LOGIC
+//------------------------------------------------------------------------------------------------------------------------------
+// Conditional free logic designed for easy 16-bit packing, and backwards porting to 32-bit.
+//------------------------------------------------------------------------------------------------------------------------------
+// 0 := false
+// 1 := true
+//------------------------------------------------------------------------------------------------------------------------------
+// AndNot(x,y) -> !(x&y) .... One op.
+// AndOr(x,y,z) -> (x&y)|z ... One op.
+// GtZero(x) -> x>0.0 ..... One op.
+// Sel(x,y,z) -> x?y:z ..... Two ops, has no precision loss.
+// Signed(x) -> x<0.0 ..... One op.
+// ZeroPass(x,y) -> x?0:y ..... Two ops, 'y' is a pass through safe for aliasing as integer.
+//------------------------------------------------------------------------------------------------------------------------------
+// OPTIMIZATION NOTES
+// ==================
+// - On Vega to use 2 constants in a packed op, pass in as one AW2 or one AH2 'k.xy' and use as 'k.xx' and 'k.yy'.
+// For example 'a.xy*k.xx+k.yy'.
+//==============================================================================================================================
+ #if 1
+ AU1 AZolAndU1(AU1 x,AU1 y){return min(x,y);}
+ AU2 AZolAndU2(AU2 x,AU2 y){return min(x,y);}
+ AU3 AZolAndU3(AU3 x,AU3 y){return min(x,y);}
+ AU4 AZolAndU4(AU4 x,AU4 y){return min(x,y);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AZolNotU1(AU1 x){return x^AU1_(1);}
+ AU2 AZolNotU2(AU2 x){return x^AU2_(1);}
+ AU3 AZolNotU3(AU3 x){return x^AU3_(1);}
+ AU4 AZolNotU4(AU4 x){return x^AU4_(1);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AU1 AZolOrU1(AU1 x,AU1 y){return max(x,y);}
+ AU2 AZolOrU2(AU2 x,AU2 y){return max(x,y);}
+ AU3 AZolOrU3(AU3 x,AU3 y){return max(x,y);}
+ AU4 AZolOrU4(AU4 x,AU4 y){return max(x,y);}
+//==============================================================================================================================
+ AU1 AZolF1ToU1(AF1 x){return AU1(x);}
+ AU2 AZolF2ToU2(AF2 x){return AU2(x);}
+ AU3 AZolF3ToU3(AF3 x){return AU3(x);}
+ AU4 AZolF4ToU4(AF4 x){return AU4(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ // 2 ops, denormals don't work in 32-bit on PC (and if they are enabled, OMOD is disabled).
+ AU1 AZolNotF1ToU1(AF1 x){return AU1(AF1_(1.0)-x);}
+ AU2 AZolNotF2ToU2(AF2 x){return AU2(AF2_(1.0)-x);}
+ AU3 AZolNotF3ToU3(AF3 x){return AU3(AF3_(1.0)-x);}
+ AU4 AZolNotF4ToU4(AF4 x){return AU4(AF4_(1.0)-x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AZolU1ToF1(AU1 x){return AF1(x);}
+ AF2 AZolU2ToF2(AU2 x){return AF2(x);}
+ AF3 AZolU3ToF3(AU3 x){return AF3(x);}
+ AF4 AZolU4ToF4(AU4 x){return AF4(x);}
+//==============================================================================================================================
+ AF1 AZolAndF1(AF1 x,AF1 y){return min(x,y);}
+ AF2 AZolAndF2(AF2 x,AF2 y){return min(x,y);}
+ AF3 AZolAndF3(AF3 x,AF3 y){return min(x,y);}
+ AF4 AZolAndF4(AF4 x,AF4 y){return min(x,y);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 ASolAndNotF1(AF1 x,AF1 y){return (-x)*y+AF1_(1.0);}
+ AF2 ASolAndNotF2(AF2 x,AF2 y){return (-x)*y+AF2_(1.0);}
+ AF3 ASolAndNotF3(AF3 x,AF3 y){return (-x)*y+AF3_(1.0);}
+ AF4 ASolAndNotF4(AF4 x,AF4 y){return (-x)*y+AF4_(1.0);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AZolAndOrF1(AF1 x,AF1 y,AF1 z){return ASatF1(x*y+z);}
+ AF2 AZolAndOrF2(AF2 x,AF2 y,AF2 z){return ASatF2(x*y+z);}
+ AF3 AZolAndOrF3(AF3 x,AF3 y,AF3 z){return ASatF3(x*y+z);}
+ AF4 AZolAndOrF4(AF4 x,AF4 y,AF4 z){return ASatF4(x*y+z);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AZolGtZeroF1(AF1 x){return ASatF1(x*AF1_(A_INFP_F));}
+ AF2 AZolGtZeroF2(AF2 x){return ASatF2(x*AF2_(A_INFP_F));}
+ AF3 AZolGtZeroF3(AF3 x){return ASatF3(x*AF3_(A_INFP_F));}
+ AF4 AZolGtZeroF4(AF4 x){return ASatF4(x*AF4_(A_INFP_F));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AZolNotF1(AF1 x){return AF1_(1.0)-x;}
+ AF2 AZolNotF2(AF2 x){return AF2_(1.0)-x;}
+ AF3 AZolNotF3(AF3 x){return AF3_(1.0)-x;}
+ AF4 AZolNotF4(AF4 x){return AF4_(1.0)-x;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AZolOrF1(AF1 x,AF1 y){return max(x,y);}
+ AF2 AZolOrF2(AF2 x,AF2 y){return max(x,y);}
+ AF3 AZolOrF3(AF3 x,AF3 y){return max(x,y);}
+ AF4 AZolOrF4(AF4 x,AF4 y){return max(x,y);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AZolSelF1(AF1 x,AF1 y,AF1 z){AF1 r=(-x)*z+z;return x*y+r;}
+ AF2 AZolSelF2(AF2 x,AF2 y,AF2 z){AF2 r=(-x)*z+z;return x*y+r;}
+ AF3 AZolSelF3(AF3 x,AF3 y,AF3 z){AF3 r=(-x)*z+z;return x*y+r;}
+ AF4 AZolSelF4(AF4 x,AF4 y,AF4 z){AF4 r=(-x)*z+z;return x*y+r;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AZolSignedF1(AF1 x){return ASatF1(x*AF1_(A_INFN_F));}
+ AF2 AZolSignedF2(AF2 x){return ASatF2(x*AF2_(A_INFN_F));}
+ AF3 AZolSignedF3(AF3 x){return ASatF3(x*AF3_(A_INFN_F));}
+ AF4 AZolSignedF4(AF4 x){return ASatF4(x*AF4_(A_INFN_F));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AZolZeroPassF1(AF1 x,AF1 y){return AF1_AU1((AU1_AF1(x)!=AU1_(0))?AU1_(0):AU1_AF1(y));}
+ AF2 AZolZeroPassF2(AF2 x,AF2 y){return AF2_AU2((AU2_AF2(x)!=AU2_(0))?AU2_(0):AU2_AF2(y));}
+ AF3 AZolZeroPassF3(AF3 x,AF3 y){return AF3_AU3((AU3_AF3(x)!=AU3_(0))?AU3_(0):AU3_AF3(y));}
+ AF4 AZolZeroPassF4(AF4 x,AF4 y){return AF4_AU4((AU4_AF4(x)!=AU4_(0))?AU4_(0):AU4_AF4(y));}
+ #endif
+//==============================================================================================================================
+ #ifdef A_HALF
+ AW1 AZolAndW1(AW1 x,AW1 y){return min(x,y);}
+ AW2 AZolAndW2(AW2 x,AW2 y){return min(x,y);}
+ AW3 AZolAndW3(AW3 x,AW3 y){return min(x,y);}
+ AW4 AZolAndW4(AW4 x,AW4 y){return min(x,y);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AW1 AZolNotW1(AW1 x){return x^AW1_(1);}
+ AW2 AZolNotW2(AW2 x){return x^AW2_(1);}
+ AW3 AZolNotW3(AW3 x){return x^AW3_(1);}
+ AW4 AZolNotW4(AW4 x){return x^AW4_(1);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AW1 AZolOrW1(AW1 x,AW1 y){return max(x,y);}
+ AW2 AZolOrW2(AW2 x,AW2 y){return max(x,y);}
+ AW3 AZolOrW3(AW3 x,AW3 y){return max(x,y);}
+ AW4 AZolOrW4(AW4 x,AW4 y){return max(x,y);}
+//==============================================================================================================================
+ // Uses denormal trick.
+ AW1 AZolH1ToW1(AH1 x){return AW1_AH1(x*AH1_AW1(AW1_(1)));}
+ AW2 AZolH2ToW2(AH2 x){return AW2_AH2(x*AH2_AW2(AW2_(1)));}
+ AW3 AZolH3ToW3(AH3 x){return AW3_AH3(x*AH3_AW3(AW3_(1)));}
+ AW4 AZolH4ToW4(AH4 x){return AW4_AH4(x*AH4_AW4(AW4_(1)));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // AMD arch lacks a packed conversion opcode.
+ AH1 AZolW1ToH1(AW1 x){return AH1_AW1(x*AW1_AH1(AH1_(1.0)));}
+ AH2 AZolW2ToH2(AW2 x){return AH2_AW2(x*AW2_AH2(AH2_(1.0)));}
+ AH3 AZolW1ToH3(AW3 x){return AH3_AW3(x*AW3_AH3(AH3_(1.0)));}
+ AH4 AZolW2ToH4(AW4 x){return AH4_AW4(x*AW4_AH4(AH4_(1.0)));}
+//==============================================================================================================================
+ AH1 AZolAndH1(AH1 x,AH1 y){return min(x,y);}
+ AH2 AZolAndH2(AH2 x,AH2 y){return min(x,y);}
+ AH3 AZolAndH3(AH3 x,AH3 y){return min(x,y);}
+ AH4 AZolAndH4(AH4 x,AH4 y){return min(x,y);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 ASolAndNotH1(AH1 x,AH1 y){return (-x)*y+AH1_(1.0);}
+ AH2 ASolAndNotH2(AH2 x,AH2 y){return (-x)*y+AH2_(1.0);}
+ AH3 ASolAndNotH3(AH3 x,AH3 y){return (-x)*y+AH3_(1.0);}
+ AH4 ASolAndNotH4(AH4 x,AH4 y){return (-x)*y+AH4_(1.0);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AZolAndOrH1(AH1 x,AH1 y,AH1 z){return ASatH1(x*y+z);}
+ AH2 AZolAndOrH2(AH2 x,AH2 y,AH2 z){return ASatH2(x*y+z);}
+ AH3 AZolAndOrH3(AH3 x,AH3 y,AH3 z){return ASatH3(x*y+z);}
+ AH4 AZolAndOrH4(AH4 x,AH4 y,AH4 z){return ASatH4(x*y+z);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AZolGtZeroH1(AH1 x){return ASatH1(x*AH1_(A_INFP_H));}
+ AH2 AZolGtZeroH2(AH2 x){return ASatH2(x*AH2_(A_INFP_H));}
+ AH3 AZolGtZeroH3(AH3 x){return ASatH3(x*AH3_(A_INFP_H));}
+ AH4 AZolGtZeroH4(AH4 x){return ASatH4(x*AH4_(A_INFP_H));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AZolNotH1(AH1 x){return AH1_(1.0)-x;}
+ AH2 AZolNotH2(AH2 x){return AH2_(1.0)-x;}
+ AH3 AZolNotH3(AH3 x){return AH3_(1.0)-x;}
+ AH4 AZolNotH4(AH4 x){return AH4_(1.0)-x;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AZolOrH1(AH1 x,AH1 y){return max(x,y);}
+ AH2 AZolOrH2(AH2 x,AH2 y){return max(x,y);}
+ AH3 AZolOrH3(AH3 x,AH3 y){return max(x,y);}
+ AH4 AZolOrH4(AH4 x,AH4 y){return max(x,y);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AZolSelH1(AH1 x,AH1 y,AH1 z){AH1 r=(-x)*z+z;return x*y+r;}
+ AH2 AZolSelH2(AH2 x,AH2 y,AH2 z){AH2 r=(-x)*z+z;return x*y+r;}
+ AH3 AZolSelH3(AH3 x,AH3 y,AH3 z){AH3 r=(-x)*z+z;return x*y+r;}
+ AH4 AZolSelH4(AH4 x,AH4 y,AH4 z){AH4 r=(-x)*z+z;return x*y+r;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AZolSignedH1(AH1 x){return ASatH1(x*AH1_(A_INFN_H));}
+ AH2 AZolSignedH2(AH2 x){return ASatH2(x*AH2_(A_INFN_H));}
+ AH3 AZolSignedH3(AH3 x){return ASatH3(x*AH3_(A_INFN_H));}
+ AH4 AZolSignedH4(AH4 x){return ASatH4(x*AH4_(A_INFN_H));}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// COLOR CONVERSIONS
+//------------------------------------------------------------------------------------------------------------------------------
+// These are all linear to/from some other space (where 'linear' has been shortened out of the function name).
+// So 'ToGamma' is 'LinearToGamma', and 'FromGamma' is 'LinearFromGamma'.
+// These are branch free implementations.
+// The AToSrgbF1() function is useful for stores for compute shaders for GPUs without hardware linear->sRGB store conversion.
+//------------------------------------------------------------------------------------------------------------------------------
+// TRANSFER FUNCTIONS
+// ==================
+// 709 ..... Rec709 used for some HDTVs
+// Gamma ... Typically 2.2 for some PC displays, or 2.4-2.5 for CRTs, or 2.2 FreeSync2 native
+// Pq ...... PQ native for HDR10
+// Srgb .... The sRGB output, typical of PC displays, useful for 10-bit output, or storing to 8-bit UNORM without SRGB type
+// Two ..... Gamma 2.0, fastest conversion (useful for intermediate pass approximations)
+// Three ... Gamma 3.0, less fast, but good for HDR.
+//------------------------------------------------------------------------------------------------------------------------------
+// KEEPING TO SPEC
+// ===============
+// Both Rec.709 and sRGB have a linear segment which as spec'ed would intersect the curved segment 2 times.
+// (a.) For 8-bit sRGB, steps {0 to 10.3} are in the linear region (4% of the encoding range).
+// (b.) For 8-bit 709, steps {0 to 20.7} are in the linear region (8% of the encoding range).
+// Also there is a slight step in the transition regions.
+// Precision of the coefficients in the spec being the likely cause.
+// Main usage case of the sRGB code is to do the linear->sRGB converstion in a compute shader before store.
+// This is to work around lack of hardware (typically only ROP does the conversion for free).
+// To "correct" the linear segment, would be to introduce error, because hardware decode of sRGB->linear is fixed (and free).
+// So this header keeps with the spec.
+// For linear->sRGB transforms, the linear segment in some respects reduces error, because rounding in that region is linear.
+// Rounding in the curved region in hardware (and fast software code) introduces error due to rounding in non-linear.
+//------------------------------------------------------------------------------------------------------------------------------
+// FOR PQ
+// ======
+// Both input and output is {0.0-1.0}, and where output 1.0 represents 10000.0 cd/m^2.
+// All constants are only specified to FP32 precision.
+// External PQ source reference,
+// - https://github.com/ampas/aces-dev/blob/master/transforms/ctl/utilities/ACESlib.Utilities_Color.a1.0.1.ctl
+//------------------------------------------------------------------------------------------------------------------------------
+// PACKED VERSIONS
+// ===============
+// These are the A*H2() functions.
+// There is no PQ functions as FP16 seemed to not have enough precision for the conversion.
+// The remaining functions are "good enough" for 8-bit, and maybe 10-bit if not concerned about a few 1-bit errors.
+// Precision is lowest in the 709 conversion, higher in sRGB, higher still in Two and Gamma (when using 2.2 at least).
+//------------------------------------------------------------------------------------------------------------------------------
+// NOTES
+// =====
+// Could be faster for PQ conversions to be in ALU or a texture lookup depending on usage case.
+//==============================================================================================================================
+ #if 1
+ AF1 ATo709F1(AF1 c){AF3 j=AF3(0.018*4.5,4.5,0.45);AF2 k=AF2(1.099,-0.099);
+ return clamp(j.x ,c*j.y ,pow(c,j.z )*k.x +k.y );}
+ AF2 ATo709F2(AF2 c){AF3 j=AF3(0.018*4.5,4.5,0.45);AF2 k=AF2(1.099,-0.099);
+ return clamp(j.xx ,c*j.yy ,pow(c,j.zz )*k.xx +k.yy );}
+ AF3 ATo709F3(AF3 c){AF3 j=AF3(0.018*4.5,4.5,0.45);AF2 k=AF2(1.099,-0.099);
+ return clamp(j.xxx,c*j.yyy,pow(c,j.zzz)*k.xxx+k.yyy);}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Note 'rcpX' is '1/x', where the 'x' is what would be used in AFromGamma().
+ AF1 AToGammaF1(AF1 c,AF1 rcpX){return pow(c,AF1_(rcpX));}
+ AF2 AToGammaF2(AF2 c,AF1 rcpX){return pow(c,AF2_(rcpX));}
+ AF3 AToGammaF3(AF3 c,AF1 rcpX){return pow(c,AF3_(rcpX));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AToPqF1(AF1 x){AF1 p=pow(x,AF1_(0.159302));
+ return pow((AF1_(0.835938)+AF1_(18.8516)*p)/(AF1_(1.0)+AF1_(18.6875)*p),AF1_(78.8438));}
+ AF2 AToPqF1(AF2 x){AF2 p=pow(x,AF2_(0.159302));
+ return pow((AF2_(0.835938)+AF2_(18.8516)*p)/(AF2_(1.0)+AF2_(18.6875)*p),AF2_(78.8438));}
+ AF3 AToPqF1(AF3 x){AF3 p=pow(x,AF3_(0.159302));
+ return pow((AF3_(0.835938)+AF3_(18.8516)*p)/(AF3_(1.0)+AF3_(18.6875)*p),AF3_(78.8438));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AToSrgbF1(AF1 c){AF3 j=AF3(0.0031308*12.92,12.92,1.0/2.4);AF2 k=AF2(1.055,-0.055);
+ return clamp(j.x ,c*j.y ,pow(c,j.z )*k.x +k.y );}
+ AF2 AToSrgbF2(AF2 c){AF3 j=AF3(0.0031308*12.92,12.92,1.0/2.4);AF2 k=AF2(1.055,-0.055);
+ return clamp(j.xx ,c*j.yy ,pow(c,j.zz )*k.xx +k.yy );}
+ AF3 AToSrgbF3(AF3 c){AF3 j=AF3(0.0031308*12.92,12.92,1.0/2.4);AF2 k=AF2(1.055,-0.055);
+ return clamp(j.xxx,c*j.yyy,pow(c,j.zzz)*k.xxx+k.yyy);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AToTwoF1(AF1 c){return sqrt(c);}
+ AF2 AToTwoF2(AF2 c){return sqrt(c);}
+ AF3 AToTwoF3(AF3 c){return sqrt(c);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AToThreeF1(AF1 c){return pow(c,AF1_(1.0/3.0));}
+ AF2 AToThreeF2(AF2 c){return pow(c,AF2_(1.0/3.0));}
+ AF3 AToThreeF3(AF3 c){return pow(c,AF3_(1.0/3.0));}
+ #endif
+//==============================================================================================================================
+ #if 1
+ // Unfortunately median won't work here.
+ AF1 AFrom709F1(AF1 c){AF3 j=AF3(0.081/4.5,1.0/4.5,1.0/0.45);AF2 k=AF2(1.0/1.099,0.099/1.099);
+ return AZolSelF1(AZolSignedF1(c-j.x ),c*j.y ,pow(c*k.x +k.y ,j.z ));}
+ AF2 AFrom709F2(AF2 c){AF3 j=AF3(0.081/4.5,1.0/4.5,1.0/0.45);AF2 k=AF2(1.0/1.099,0.099/1.099);
+ return AZolSelF2(AZolSignedF2(c-j.xx ),c*j.yy ,pow(c*k.xx +k.yy ,j.zz ));}
+ AF3 AFrom709F3(AF3 c){AF3 j=AF3(0.081/4.5,1.0/4.5,1.0/0.45);AF2 k=AF2(1.0/1.099,0.099/1.099);
+ return AZolSelF3(AZolSignedF3(c-j.xxx),c*j.yyy,pow(c*k.xxx+k.yyy,j.zzz));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AFromGammaF1(AF1 c,AF1 x){return pow(c,AF1_(x));}
+ AF2 AFromGammaF2(AF2 c,AF1 x){return pow(c,AF2_(x));}
+ AF3 AFromGammaF3(AF3 c,AF1 x){return pow(c,AF3_(x));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AFromPqF1(AF1 x){AF1 p=pow(x,AF1_(0.0126833));
+ return pow(ASatF1(p-AF1_(0.835938))/(AF1_(18.8516)-AF1_(18.6875)*p),AF1_(6.27739));}
+ AF2 AFromPqF1(AF2 x){AF2 p=pow(x,AF2_(0.0126833));
+ return pow(ASatF2(p-AF2_(0.835938))/(AF2_(18.8516)-AF2_(18.6875)*p),AF2_(6.27739));}
+ AF3 AFromPqF1(AF3 x){AF3 p=pow(x,AF3_(0.0126833));
+ return pow(ASatF3(p-AF3_(0.835938))/(AF3_(18.8516)-AF3_(18.6875)*p),AF3_(6.27739));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Unfortunately median won't work here.
+ AF1 AFromSrgbF1(AF1 c){AF3 j=AF3(0.04045/12.92,1.0/12.92,2.4);AF2 k=AF2(1.0/1.055,0.055/1.055);
+ return AZolSelF1(AZolSignedF1(c-j.x ),c*j.y ,pow(c*k.x +k.y ,j.z ));}
+ AF2 AFromSrgbF2(AF2 c){AF3 j=AF3(0.04045/12.92,1.0/12.92,2.4);AF2 k=AF2(1.0/1.055,0.055/1.055);
+ return AZolSelF2(AZolSignedF2(c-j.xx ),c*j.yy ,pow(c*k.xx +k.yy ,j.zz ));}
+ AF3 AFromSrgbF3(AF3 c){AF3 j=AF3(0.04045/12.92,1.0/12.92,2.4);AF2 k=AF2(1.0/1.055,0.055/1.055);
+ return AZolSelF3(AZolSignedF3(c-j.xxx),c*j.yyy,pow(c*k.xxx+k.yyy,j.zzz));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AFromTwoF1(AF1 c){return c*c;}
+ AF2 AFromTwoF2(AF2 c){return c*c;}
+ AF3 AFromTwoF3(AF3 c){return c*c;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF1 AFromThreeF1(AF1 c){return c*c*c;}
+ AF2 AFromThreeF2(AF2 c){return c*c*c;}
+ AF3 AFromThreeF3(AF3 c){return c*c*c;}
+ #endif
+//==============================================================================================================================
+ #ifdef A_HALF
+ AH1 ATo709H1(AH1 c){AH3 j=AH3(0.018*4.5,4.5,0.45);AH2 k=AH2(1.099,-0.099);
+ return clamp(j.x ,c*j.y ,pow(c,j.z )*k.x +k.y );}
+ AH2 ATo709H2(AH2 c){AH3 j=AH3(0.018*4.5,4.5,0.45);AH2 k=AH2(1.099,-0.099);
+ return clamp(j.xx ,c*j.yy ,pow(c,j.zz )*k.xx +k.yy );}
+ AH3 ATo709H3(AH3 c){AH3 j=AH3(0.018*4.5,4.5,0.45);AH2 k=AH2(1.099,-0.099);
+ return clamp(j.xxx,c*j.yyy,pow(c,j.zzz)*k.xxx+k.yyy);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AToGammaH1(AH1 c,AH1 rcpX){return pow(c,AH1_(rcpX));}
+ AH2 AToGammaH2(AH2 c,AH1 rcpX){return pow(c,AH2_(rcpX));}
+ AH3 AToGammaH3(AH3 c,AH1 rcpX){return pow(c,AH3_(rcpX));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AToSrgbH1(AH1 c){AH3 j=AH3(0.0031308*12.92,12.92,1.0/2.4);AH2 k=AH2(1.055,-0.055);
+ return clamp(j.x ,c*j.y ,pow(c,j.z )*k.x +k.y );}
+ AH2 AToSrgbH2(AH2 c){AH3 j=AH3(0.0031308*12.92,12.92,1.0/2.4);AH2 k=AH2(1.055,-0.055);
+ return clamp(j.xx ,c*j.yy ,pow(c,j.zz )*k.xx +k.yy );}
+ AH3 AToSrgbH3(AH3 c){AH3 j=AH3(0.0031308*12.92,12.92,1.0/2.4);AH2 k=AH2(1.055,-0.055);
+ return clamp(j.xxx,c*j.yyy,pow(c,j.zzz)*k.xxx+k.yyy);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AToTwoH1(AH1 c){return sqrt(c);}
+ AH2 AToTwoH2(AH2 c){return sqrt(c);}
+ AH3 AToTwoH3(AH3 c){return sqrt(c);}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AToThreeF1(AH1 c){return pow(c,AH1_(1.0/3.0));}
+ AH2 AToThreeF2(AH2 c){return pow(c,AH2_(1.0/3.0));}
+ AH3 AToThreeF3(AH3 c){return pow(c,AH3_(1.0/3.0));}
+ #endif
+//==============================================================================================================================
+ #ifdef A_HALF
+ AH1 AFrom709H1(AH1 c){AH3 j=AH3(0.081/4.5,1.0/4.5,1.0/0.45);AH2 k=AH2(1.0/1.099,0.099/1.099);
+ return AZolSelH1(AZolSignedH1(c-j.x ),c*j.y ,pow(c*k.x +k.y ,j.z ));}
+ AH2 AFrom709H2(AH2 c){AH3 j=AH3(0.081/4.5,1.0/4.5,1.0/0.45);AH2 k=AH2(1.0/1.099,0.099/1.099);
+ return AZolSelH2(AZolSignedH2(c-j.xx ),c*j.yy ,pow(c*k.xx +k.yy ,j.zz ));}
+ AH3 AFrom709H3(AH3 c){AH3 j=AH3(0.081/4.5,1.0/4.5,1.0/0.45);AH2 k=AH2(1.0/1.099,0.099/1.099);
+ return AZolSelH3(AZolSignedH3(c-j.xxx),c*j.yyy,pow(c*k.xxx+k.yyy,j.zzz));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AFromGammaH1(AH1 c,AH1 x){return pow(c,AH1_(x));}
+ AH2 AFromGammaH2(AH2 c,AH1 x){return pow(c,AH2_(x));}
+ AH3 AFromGammaH3(AH3 c,AH1 x){return pow(c,AH3_(x));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AHromSrgbF1(AH1 c){AH3 j=AH3(0.04045/12.92,1.0/12.92,2.4);AH2 k=AH2(1.0/1.055,0.055/1.055);
+ return AZolSelH1(AZolSignedH1(c-j.x ),c*j.y ,pow(c*k.x +k.y ,j.z ));}
+ AH2 AHromSrgbF2(AH2 c){AH3 j=AH3(0.04045/12.92,1.0/12.92,2.4);AH2 k=AH2(1.0/1.055,0.055/1.055);
+ return AZolSelH2(AZolSignedH2(c-j.xx ),c*j.yy ,pow(c*k.xx +k.yy ,j.zz ));}
+ AH3 AHromSrgbF3(AH3 c){AH3 j=AH3(0.04045/12.92,1.0/12.92,2.4);AH2 k=AH2(1.0/1.055,0.055/1.055);
+ return AZolSelH3(AZolSignedH3(c-j.xxx),c*j.yyy,pow(c*k.xxx+k.yyy,j.zzz));}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AFromTwoH1(AH1 c){return c*c;}
+ AH2 AFromTwoH2(AH2 c){return c*c;}
+ AH3 AFromTwoH3(AH3 c){return c*c;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AH1 AFromThreeH1(AH1 c){return c*c*c;}
+ AH2 AFromThreeH2(AH2 c){return c*c*c;}
+ AH3 AFromThreeH3(AH3 c){return c*c*c;}
+ #endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// CS REMAP
+//==============================================================================================================================
+ // Simple remap 64x1 to 8x8 with rotated 2x2 pixel quads in quad linear.
+ // 543210
+ // ======
+ // ..xxx.
+ // yy...y
+ AU2 ARmp8x8(AU1 a){return AU2(ABfe(a,1u,3u),ABfiM(ABfe(a,3u,3u),a,1u));}
+//==============================================================================================================================
+ // More complex remap 64x1 to 8x8 which is necessary for 2D wave reductions.
+ // 543210
+ // ======
+ // .xx..x
+ // y..yy.
+ // Details,
+ // LANE TO 8x8 MAPPING
+ // ===================
+ // 00 01 08 09 10 11 18 19
+ // 02 03 0a 0b 12 13 1a 1b
+ // 04 05 0c 0d 14 15 1c 1d
+ // 06 07 0e 0f 16 17 1e 1f
+ // 20 21 28 29 30 31 38 39
+ // 22 23 2a 2b 32 33 3a 3b
+ // 24 25 2c 2d 34 35 3c 3d
+ // 26 27 2e 2f 36 37 3e 3f
+ AU2 ARmpRed8x8(AU1 a){return AU2(ABfiM(ABfe(a,2u,3u),a,1u),ABfiM(ABfe(a,3u,3u),ABfe(a,1u,2u),2u));}
+//==============================================================================================================================
+ #ifdef A_HALF
+ AW2 ARmp8x8H(AU1 a){return AW2(ABfe(a,1u,3u),ABfiM(ABfe(a,3u,3u),a,1u));}
+ AW2 ARmpRed8x8H(AU1 a){return AW2(ABfiM(ABfe(a,2u,3u),a,1u),ABfiM(ABfe(a,3u,3u),ABfe(a,1u,2u),2u));}
+ #endif
+#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+// REFERENCE
+//
+//------------------------------------------------------------------------------------------------------------------------------
+// IEEE FLOAT RULES
+// ================
+// - saturate(NaN)=0, saturate(-INF)=0, saturate(+INF)=1
+// - {+/-}0 * {+/-}INF = NaN
+// - -INF + (+INF) = NaN
+// - {+/-}0 / {+/-}0 = NaN
+// - {+/-}INF / {+/-}INF = NaN
+// - a<(-0) := sqrt(a) = NaN (a=-0.0 won't NaN)
+// - 0 == -0
+// - 4/0 = +INF
+// - 4/-0 = -INF
+// - 4+INF = +INF
+// - 4-INF = -INF
+// - 4*(+INF) = +INF
+// - 4*(-INF) = -INF
+// - -4*(+INF) = -INF
+// - sqrt(+INF) = +INF
+//------------------------------------------------------------------------------------------------------------------------------
+// FP16 ENCODING
+// =============
+// fedcba9876543210
+// ----------------
+// ......mmmmmmmmmm 10-bit mantissa (encodes 11-bit 0.5 to 1.0 except for denormals)
+// .eeeee.......... 5-bit exponent
+// .00000.......... denormals
+// .00001.......... -14 exponent
+// .11110.......... 15 exponent
+// .111110000000000 infinity
+// .11111nnnnnnnnnn NaN with n!=0
+// s............... sign
+//------------------------------------------------------------------------------------------------------------------------------
+// FP16/INT16 ALIASING DENORMAL
+// ============================
+// 11-bit unsigned integers alias with half float denormal/normal values,
+// 1 = 2^(-24) = 1/16777216 ....................... first denormal value
+// 2 = 2^(-23)
+// ...
+// 1023 = 2^(-14)*(1-2^(-10)) = 2^(-14)*(1-1/1024) ... last denormal value
+// 1024 = 2^(-14) = 1/16384 .......................... first normal value that still maps to integers
+// 2047 .............................................. last normal value that still maps to integers
+// Scaling limits,
+// 2^15 = 32768 ...................................... largest power of 2 scaling
+// Largest pow2 conversion mapping is at *32768,
+// 1 : 2^(-9) = 1/512
+// 2 : 1/256
+// 4 : 1/128
+// 8 : 1/64
+// 16 : 1/32
+// 32 : 1/16
+// 64 : 1/8
+// 128 : 1/4
+// 256 : 1/2
+// 512 : 1
+// 1024 : 2
+// 2047 : a little less than 4
+//==============================================================================================================================
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+//
+// GPU/CPU PORTABILITY
+//
+//
+//------------------------------------------------------------------------------------------------------------------------------
+// This is the GPU implementation.
+// See the CPU implementation for docs.
+//==============================================================================================================================
+#ifdef A_GPU
+ #define A_TRUE true
+ #define A_FALSE false
+ #define A_STATIC
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// VECTOR ARGUMENT/RETURN/INITIALIZATION PORTABILITY
+//==============================================================================================================================
+ #define retAD2 AD2
+ #define retAD3 AD3
+ #define retAD4 AD4
+ #define retAF2 AF2
+ #define retAF3 AF3
+ #define retAF4 AF4
+ #define retAL2 AL2
+ #define retAL3 AL3
+ #define retAL4 AL4
+ #define retAU2 AU2
+ #define retAU3 AU3
+ #define retAU4 AU4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define inAD2 in AD2
+ #define inAD3 in AD3
+ #define inAD4 in AD4
+ #define inAF2 in AF2
+ #define inAF3 in AF3
+ #define inAF4 in AF4
+ #define inAL2 in AL2
+ #define inAL3 in AL3
+ #define inAL4 in AL4
+ #define inAU2 in AU2
+ #define inAU3 in AU3
+ #define inAU4 in AU4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define inoutAD2 inout AD2
+ #define inoutAD3 inout AD3
+ #define inoutAD4 inout AD4
+ #define inoutAF2 inout AF2
+ #define inoutAF3 inout AF3
+ #define inoutAF4 inout AF4
+ #define inoutAL2 inout AL2
+ #define inoutAL3 inout AL3
+ #define inoutAL4 inout AL4
+ #define inoutAU2 inout AU2
+ #define inoutAU3 inout AU3
+ #define inoutAU4 inout AU4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define outAD2 out AD2
+ #define outAD3 out AD3
+ #define outAD4 out AD4
+ #define outAF2 out AF2
+ #define outAF3 out AF3
+ #define outAF4 out AF4
+ #define outAL2 out AL2
+ #define outAL3 out AL3
+ #define outAL4 out AL4
+ #define outAU2 out AU2
+ #define outAU3 out AU3
+ #define outAU4 out AU4
+//------------------------------------------------------------------------------------------------------------------------------
+ #define varAD2(x) AD2 x
+ #define varAD3(x) AD3 x
+ #define varAD4(x) AD4 x
+ #define varAF2(x) AF2 x
+ #define varAF3(x) AF3 x
+ #define varAF4(x) AF4 x
+ #define varAL2(x) AL2 x
+ #define varAL3(x) AL3 x
+ #define varAL4(x) AL4 x
+ #define varAU2(x) AU2 x
+ #define varAU3(x) AU3 x
+ #define varAU4(x) AU4 x
+//------------------------------------------------------------------------------------------------------------------------------
+ #define initAD2(x,y) AD2(x,y)
+ #define initAD3(x,y,z) AD3(x,y,z)
+ #define initAD4(x,y,z,w) AD4(x,y,z,w)
+ #define initAF2(x,y) AF2(x,y)
+ #define initAF3(x,y,z) AF3(x,y,z)
+ #define initAF4(x,y,z,w) AF4(x,y,z,w)
+ #define initAL2(x,y) AL2(x,y)
+ #define initAL3(x,y,z) AL3(x,y,z)
+ #define initAL4(x,y,z,w) AL4(x,y,z,w)
+ #define initAU2(x,y) AU2(x,y)
+ #define initAU3(x,y,z) AU3(x,y,z)
+ #define initAU4(x,y,z,w) AU4(x,y,z,w)
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// SCALAR RETURN OPS
+//==============================================================================================================================
+ #define AAbsD1(a) abs(AD1(a))
+ #define AAbsF1(a) abs(AF1(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ACosD1(a) cos(AD1(a))
+ #define ACosF1(a) cos(AF1(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ADotD2(a,b) dot(AD2(a),AD2(b))
+ #define ADotD3(a,b) dot(AD3(a),AD3(b))
+ #define ADotD4(a,b) dot(AD4(a),AD4(b))
+ #define ADotF2(a,b) dot(AF2(a),AF2(b))
+ #define ADotF3(a,b) dot(AF3(a),AF3(b))
+ #define ADotF4(a,b) dot(AF4(a),AF4(b))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AExp2D1(a) exp2(AD1(a))
+ #define AExp2F1(a) exp2(AF1(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AFloorD1(a) floor(AD1(a))
+ #define AFloorF1(a) floor(AF1(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ALog2D1(a) log2(AD1(a))
+ #define ALog2F1(a) log2(AF1(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AMaxD1(a,b) max(a,b)
+ #define AMaxF1(a,b) max(a,b)
+ #define AMaxL1(a,b) max(a,b)
+ #define AMaxU1(a,b) max(a,b)
+//------------------------------------------------------------------------------------------------------------------------------
+ #define AMinD1(a,b) min(a,b)
+ #define AMinF1(a,b) min(a,b)
+ #define AMinL1(a,b) min(a,b)
+ #define AMinU1(a,b) min(a,b)
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ASinD1(a) sin(AD1(a))
+ #define ASinF1(a) sin(AF1(a))
+//------------------------------------------------------------------------------------------------------------------------------
+ #define ASqrtD1(a) sqrt(AD1(a))
+ #define ASqrtF1(a) sqrt(AF1(a))
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// SCALAR RETURN OPS - DEPENDENT
+//==============================================================================================================================
+ #define APowD1(a,b) pow(AD1(a),AF1(b))
+ #define APowF1(a,b) pow(AF1(a),AF1(b))
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// VECTOR OPS
+//------------------------------------------------------------------------------------------------------------------------------
+// These are added as needed for production or prototyping, so not necessarily a complete set.
+// They follow a convention of taking in a destination and also returning the destination value to increase utility.
+//==============================================================================================================================
+ #ifdef A_DUBL
+ AD2 opAAbsD2(outAD2 d,inAD2 a){d=abs(a);return d;}
+ AD3 opAAbsD3(outAD3 d,inAD3 a){d=abs(a);return d;}
+ AD4 opAAbsD4(outAD4 d,inAD4 a){d=abs(a);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD2 opAAddD2(outAD2 d,inAD2 a,inAD2 b){d=a+b;return d;}
+ AD3 opAAddD3(outAD3 d,inAD3 a,inAD3 b){d=a+b;return d;}
+ AD4 opAAddD4(outAD4 d,inAD4 a,inAD4 b){d=a+b;return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD2 opAAddOneD2(outAD2 d,inAD2 a,AD1 b){d=a+AD2_(b);return d;}
+ AD3 opAAddOneD3(outAD3 d,inAD3 a,AD1 b){d=a+AD3_(b);return d;}
+ AD4 opAAddOneD4(outAD4 d,inAD4 a,AD1 b){d=a+AD4_(b);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD2 opACpyD2(outAD2 d,inAD2 a){d=a;return d;}
+ AD3 opACpyD3(outAD3 d,inAD3 a){d=a;return d;}
+ AD4 opACpyD4(outAD4 d,inAD4 a){d=a;return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD2 opALerpD2(outAD2 d,inAD2 a,inAD2 b,inAD2 c){d=ALerpD2(a,b,c);return d;}
+ AD3 opALerpD3(outAD3 d,inAD3 a,inAD3 b,inAD3 c){d=ALerpD3(a,b,c);return d;}
+ AD4 opALerpD4(outAD4 d,inAD4 a,inAD4 b,inAD4 c){d=ALerpD4(a,b,c);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD2 opALerpOneD2(outAD2 d,inAD2 a,inAD2 b,AD1 c){d=ALerpD2(a,b,AD2_(c));return d;}
+ AD3 opALerpOneD3(outAD3 d,inAD3 a,inAD3 b,AD1 c){d=ALerpD3(a,b,AD3_(c));return d;}
+ AD4 opALerpOneD4(outAD4 d,inAD4 a,inAD4 b,AD1 c){d=ALerpD4(a,b,AD4_(c));return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD2 opAMaxD2(outAD2 d,inAD2 a,inAD2 b){d=max(a,b);return d;}
+ AD3 opAMaxD3(outAD3 d,inAD3 a,inAD3 b){d=max(a,b);return d;}
+ AD4 opAMaxD4(outAD4 d,inAD4 a,inAD4 b){d=max(a,b);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD2 opAMinD2(outAD2 d,inAD2 a,inAD2 b){d=min(a,b);return d;}
+ AD3 opAMinD3(outAD3 d,inAD3 a,inAD3 b){d=min(a,b);return d;}
+ AD4 opAMinD4(outAD4 d,inAD4 a,inAD4 b){d=min(a,b);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD2 opAMulD2(outAD2 d,inAD2 a,inAD2 b){d=a*b;return d;}
+ AD3 opAMulD3(outAD3 d,inAD3 a,inAD3 b){d=a*b;return d;}
+ AD4 opAMulD4(outAD4 d,inAD4 a,inAD4 b){d=a*b;return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD2 opAMulOneD2(outAD2 d,inAD2 a,AD1 b){d=a*AD2_(b);return d;}
+ AD3 opAMulOneD3(outAD3 d,inAD3 a,AD1 b){d=a*AD3_(b);return d;}
+ AD4 opAMulOneD4(outAD4 d,inAD4 a,AD1 b){d=a*AD4_(b);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD2 opANegD2(outAD2 d,inAD2 a){d=-a;return d;}
+ AD3 opANegD3(outAD3 d,inAD3 a){d=-a;return d;}
+ AD4 opANegD4(outAD4 d,inAD4 a){d=-a;return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AD2 opARcpD2(outAD2 d,inAD2 a){d=ARcpD2(a);return d;}
+ AD3 opARcpD3(outAD3 d,inAD3 a){d=ARcpD3(a);return d;}
+ AD4 opARcpD4(outAD4 d,inAD4 a){d=ARcpD4(a);return d;}
+ #endif
+//==============================================================================================================================
+ AF2 opAAbsF2(outAF2 d,inAF2 a){d=abs(a);return d;}
+ AF3 opAAbsF3(outAF3 d,inAF3 a){d=abs(a);return d;}
+ AF4 opAAbsF4(outAF4 d,inAF4 a){d=abs(a);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 opAAddF2(outAF2 d,inAF2 a,inAF2 b){d=a+b;return d;}
+ AF3 opAAddF3(outAF3 d,inAF3 a,inAF3 b){d=a+b;return d;}
+ AF4 opAAddF4(outAF4 d,inAF4 a,inAF4 b){d=a+b;return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 opAAddOneF2(outAF2 d,inAF2 a,AF1 b){d=a+AF2_(b);return d;}
+ AF3 opAAddOneF3(outAF3 d,inAF3 a,AF1 b){d=a+AF3_(b);return d;}
+ AF4 opAAddOneF4(outAF4 d,inAF4 a,AF1 b){d=a+AF4_(b);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 opACpyF2(outAF2 d,inAF2 a){d=a;return d;}
+ AF3 opACpyF3(outAF3 d,inAF3 a){d=a;return d;}
+ AF4 opACpyF4(outAF4 d,inAF4 a){d=a;return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 opALerpF2(outAF2 d,inAF2 a,inAF2 b,inAF2 c){d=ALerpF2(a,b,c);return d;}
+ AF3 opALerpF3(outAF3 d,inAF3 a,inAF3 b,inAF3 c){d=ALerpF3(a,b,c);return d;}
+ AF4 opALerpF4(outAF4 d,inAF4 a,inAF4 b,inAF4 c){d=ALerpF4(a,b,c);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 opALerpOneF2(outAF2 d,inAF2 a,inAF2 b,AF1 c){d=ALerpF2(a,b,AF2_(c));return d;}
+ AF3 opALerpOneF3(outAF3 d,inAF3 a,inAF3 b,AF1 c){d=ALerpF3(a,b,AF3_(c));return d;}
+ AF4 opALerpOneF4(outAF4 d,inAF4 a,inAF4 b,AF1 c){d=ALerpF4(a,b,AF4_(c));return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 opAMaxF2(outAF2 d,inAF2 a,inAF2 b){d=max(a,b);return d;}
+ AF3 opAMaxF3(outAF3 d,inAF3 a,inAF3 b){d=max(a,b);return d;}
+ AF4 opAMaxF4(outAF4 d,inAF4 a,inAF4 b){d=max(a,b);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 opAMinF2(outAF2 d,inAF2 a,inAF2 b){d=min(a,b);return d;}
+ AF3 opAMinF3(outAF3 d,inAF3 a,inAF3 b){d=min(a,b);return d;}
+ AF4 opAMinF4(outAF4 d,inAF4 a,inAF4 b){d=min(a,b);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 opAMulF2(outAF2 d,inAF2 a,inAF2 b){d=a*b;return d;}
+ AF3 opAMulF3(outAF3 d,inAF3 a,inAF3 b){d=a*b;return d;}
+ AF4 opAMulF4(outAF4 d,inAF4 a,inAF4 b){d=a*b;return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 opAMulOneF2(outAF2 d,inAF2 a,AF1 b){d=a*AF2_(b);return d;}
+ AF3 opAMulOneF3(outAF3 d,inAF3 a,AF1 b){d=a*AF3_(b);return d;}
+ AF4 opAMulOneF4(outAF4 d,inAF4 a,AF1 b){d=a*AF4_(b);return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 opANegF2(outAF2 d,inAF2 a){d=-a;return d;}
+ AF3 opANegF3(outAF3 d,inAF3 a){d=-a;return d;}
+ AF4 opANegF4(outAF4 d,inAF4 a){d=-a;return d;}
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 opARcpF2(outAF2 d,inAF2 a){d=ARcpF2(a);return d;}
+ AF3 opARcpF3(outAF3 d,inAF3 a){d=ARcpF3(a);return d;}
+ AF4 opARcpF4(outAF4 d,inAF4 a){d=ARcpF4(a);return d;}
+#endif
diff --git a/thirdparty/amd-fsr/ffx_fsr1.h b/thirdparty/amd-fsr/ffx_fsr1.h
new file mode 100644
index 0000000000..4e0b3d5485
--- /dev/null
+++ b/thirdparty/amd-fsr/ffx_fsr1.h
@@ -0,0 +1,1199 @@
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+//
+// AMD FidelityFX SUPER RESOLUTION [FSR 1] ::: SPATIAL SCALING & EXTRAS - v1.20210629
+//
+//
+//------------------------------------------------------------------------------------------------------------------------------
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//------------------------------------------------------------------------------------------------------------------------------
+// FidelityFX Super Resolution Sample
+//
+// Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files(the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions :
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//------------------------------------------------------------------------------------------------------------------------------
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//------------------------------------------------------------------------------------------------------------------------------
+// ABOUT
+// =====
+// FSR is a collection of algorithms relating to generating a higher resolution image.
+// This specific header focuses on single-image non-temporal image scaling, and related tools.
+//
+// The core functions are EASU and RCAS:
+// [EASU] Edge Adaptive Spatial Upsampling ....... 1x to 4x area range spatial scaling, clamped adaptive elliptical filter.
+// [RCAS] Robust Contrast Adaptive Sharpening .... A non-scaling variation on CAS.
+// RCAS needs to be applied after EASU as a separate pass.
+//
+// Optional utility functions are:
+// [LFGA] Linear Film Grain Applicator ........... Tool to apply film grain after scaling.
+// [SRTM] Simple Reversible Tone-Mapper .......... Linear HDR {0 to FP16_MAX} to {0 to 1} and back.
+// [TEPD] Temporal Energy Preserving Dither ...... Temporally energy preserving dithered {0 to 1} linear to gamma 2.0 conversion.
+// See each individual sub-section for inline documentation.
+//------------------------------------------------------------------------------------------------------------------------------
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//------------------------------------------------------------------------------------------------------------------------------
+// FUNCTION PERMUTATIONS
+// =====================
+// *F() ..... Single item computation with 32-bit.
+// *H() ..... Single item computation with 16-bit, with packing (aka two 16-bit ops in parallel) when possible.
+// *Hx2() ... Processing two items in parallel with 16-bit, easier packing.
+// Not all interfaces in this file have a *Hx2() form.
+//==============================================================================================================================
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+// FSR - [EASU] EDGE ADAPTIVE SPATIAL UPSAMPLING
+//
+//------------------------------------------------------------------------------------------------------------------------------
+// EASU provides a high quality spatial-only scaling at relatively low cost.
+// Meaning EASU is appropiate for laptops and other low-end GPUs.
+// Quality from 1x to 4x area scaling is good.
+//------------------------------------------------------------------------------------------------------------------------------
+// The scalar uses a modified fast approximation to the standard lanczos(size=2) kernel.
+// EASU runs in a single pass, so it applies a directionally and anisotropically adaptive radial lanczos.
+// This is also kept as simple as possible to have minimum runtime.
+//------------------------------------------------------------------------------------------------------------------------------
+// The lanzcos filter has negative lobes, so by itself it will introduce ringing.
+// To remove all ringing, the algorithm uses the nearest 2x2 input texels as a neighborhood,
+// and limits output to the minimum and maximum of that neighborhood.
+//------------------------------------------------------------------------------------------------------------------------------
+// Input image requirements:
+//
+// Color needs to be encoded as 3 channel[red, green, blue](e.g.XYZ not supported)
+// Each channel needs to be in the range[0, 1]
+// Any color primaries are supported
+// Display / tonemapping curve needs to be as if presenting to sRGB display or similar(e.g.Gamma 2.0)
+// There should be no banding in the input
+// There should be no high amplitude noise in the input
+// There should be no noise in the input that is not at input pixel granularity
+// For performance purposes, use 32bpp formats
+//------------------------------------------------------------------------------------------------------------------------------
+// Best to apply EASU at the end of the frame after tonemapping
+// but before film grain or composite of the UI.
+//------------------------------------------------------------------------------------------------------------------------------
+// Example of including this header for D3D HLSL :
+//
+// #define A_GPU 1
+// #define A_HLSL 1
+// #define A_HALF 1
+// #include "ffx_a.h"
+// #define FSR_EASU_H 1
+// #define FSR_RCAS_H 1
+// //declare input callbacks
+// #include "ffx_fsr1.h"
+//
+// Example of including this header for Vulkan GLSL :
+//
+// #define A_GPU 1
+// #define A_GLSL 1
+// #define A_HALF 1
+// #include "ffx_a.h"
+// #define FSR_EASU_H 1
+// #define FSR_RCAS_H 1
+// //declare input callbacks
+// #include "ffx_fsr1.h"
+//
+// Example of including this header for Vulkan HLSL :
+//
+// #define A_GPU 1
+// #define A_HLSL 1
+// #define A_HLSL_6_2 1
+// #define A_NO_16_BIT_CAST 1
+// #define A_HALF 1
+// #include "ffx_a.h"
+// #define FSR_EASU_H 1
+// #define FSR_RCAS_H 1
+// //declare input callbacks
+// #include "ffx_fsr1.h"
+//
+// Example of declaring the required input callbacks for GLSL :
+// The callbacks need to gather4 for each color channel using the specified texture coordinate 'p'.
+// EASU uses gather4 to reduce position computation logic and for free Arrays of Structures to Structures of Arrays conversion.
+//
+// AH4 FsrEasuRH(AF2 p){return AH4(textureGather(sampler2D(tex,sam),p,0));}
+// AH4 FsrEasuGH(AF2 p){return AH4(textureGather(sampler2D(tex,sam),p,1));}
+// AH4 FsrEasuBH(AF2 p){return AH4(textureGather(sampler2D(tex,sam),p,2));}
+// ...
+// The FsrEasuCon function needs to be called from the CPU or GPU to set up constants.
+// The difference in viewport and input image size is there to support Dynamic Resolution Scaling.
+// To use FsrEasuCon() on the CPU, define A_CPU before including ffx_a and ffx_fsr1.
+// Including a GPU example here, the 'con0' through 'con3' values would be stored out to a constant buffer.
+// AU4 con0,con1,con2,con3;
+// FsrEasuCon(con0,con1,con2,con3,
+// 1920.0,1080.0, // Viewport size (top left aligned) in the input image which is to be scaled.
+// 3840.0,2160.0, // The size of the input image.
+// 2560.0,1440.0); // The output resolution.
+//==============================================================================================================================
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// CONSTANT SETUP
+//==============================================================================================================================
+// Call to setup required constant values (works on CPU or GPU).
+A_STATIC void FsrEasuCon(
+outAU4 con0,
+outAU4 con1,
+outAU4 con2,
+outAU4 con3,
+// This the rendered image resolution being upscaled
+AF1 inputViewportInPixelsX,
+AF1 inputViewportInPixelsY,
+// This is the resolution of the resource containing the input image (useful for dynamic resolution)
+AF1 inputSizeInPixelsX,
+AF1 inputSizeInPixelsY,
+// This is the display resolution which the input image gets upscaled to
+AF1 outputSizeInPixelsX,
+AF1 outputSizeInPixelsY){
+ // Output integer position to a pixel position in viewport.
+ con0[0]=AU1_AF1(inputViewportInPixelsX*ARcpF1(outputSizeInPixelsX));
+ con0[1]=AU1_AF1(inputViewportInPixelsY*ARcpF1(outputSizeInPixelsY));
+ con0[2]=AU1_AF1(AF1_(0.5)*inputViewportInPixelsX*ARcpF1(outputSizeInPixelsX)-AF1_(0.5));
+ con0[3]=AU1_AF1(AF1_(0.5)*inputViewportInPixelsY*ARcpF1(outputSizeInPixelsY)-AF1_(0.5));
+ // Viewport pixel position to normalized image space.
+ // This is used to get upper-left of 'F' tap.
+ con1[0]=AU1_AF1(ARcpF1(inputSizeInPixelsX));
+ con1[1]=AU1_AF1(ARcpF1(inputSizeInPixelsY));
+ // Centers of gather4, first offset from upper-left of 'F'.
+ // +---+---+
+ // | | |
+ // +--(0)--+
+ // | b | c |
+ // +---F---+---+---+
+ // | e | f | g | h |
+ // +--(1)--+--(2)--+
+ // | i | j | k | l |
+ // +---+---+---+---+
+ // | n | o |
+ // +--(3)--+
+ // | | |
+ // +---+---+
+ con1[2]=AU1_AF1(AF1_( 1.0)*ARcpF1(inputSizeInPixelsX));
+ con1[3]=AU1_AF1(AF1_(-1.0)*ARcpF1(inputSizeInPixelsY));
+ // These are from (0) instead of 'F'.
+ con2[0]=AU1_AF1(AF1_(-1.0)*ARcpF1(inputSizeInPixelsX));
+ con2[1]=AU1_AF1(AF1_( 2.0)*ARcpF1(inputSizeInPixelsY));
+ con2[2]=AU1_AF1(AF1_( 1.0)*ARcpF1(inputSizeInPixelsX));
+ con2[3]=AU1_AF1(AF1_( 2.0)*ARcpF1(inputSizeInPixelsY));
+ con3[0]=AU1_AF1(AF1_( 0.0)*ARcpF1(inputSizeInPixelsX));
+ con3[1]=AU1_AF1(AF1_( 4.0)*ARcpF1(inputSizeInPixelsY));
+ con3[2]=con3[3]=0;}
+
+//If the an offset into the input image resource
+A_STATIC void FsrEasuConOffset(
+ outAU4 con0,
+ outAU4 con1,
+ outAU4 con2,
+ outAU4 con3,
+ // This the rendered image resolution being upscaled
+ AF1 inputViewportInPixelsX,
+ AF1 inputViewportInPixelsY,
+ // This is the resolution of the resource containing the input image (useful for dynamic resolution)
+ AF1 inputSizeInPixelsX,
+ AF1 inputSizeInPixelsY,
+ // This is the display resolution which the input image gets upscaled to
+ AF1 outputSizeInPixelsX,
+ AF1 outputSizeInPixelsY,
+ // This is the input image offset into the resource containing it (useful for dynamic resolution)
+ AF1 inputOffsetInPixelsX,
+ AF1 inputOffsetInPixelsY) {
+ FsrEasuCon(con0, con1, con2, con3, inputViewportInPixelsX, inputViewportInPixelsY, inputSizeInPixelsX, inputSizeInPixelsY, outputSizeInPixelsX, outputSizeInPixelsY);
+ con0[2] = AU1_AF1(AF1_(0.5) * inputViewportInPixelsX * ARcpF1(outputSizeInPixelsX) - AF1_(0.5) + inputOffsetInPixelsX);
+ con0[3] = AU1_AF1(AF1_(0.5) * inputViewportInPixelsY * ARcpF1(outputSizeInPixelsY) - AF1_(0.5) + inputOffsetInPixelsY);
+}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// NON-PACKED 32-BIT VERSION
+//==============================================================================================================================
+#if defined(A_GPU)&&defined(FSR_EASU_F)
+ // Input callback prototypes, need to be implemented by calling shader
+ AF4 FsrEasuRF(AF2 p);
+ AF4 FsrEasuGF(AF2 p);
+ AF4 FsrEasuBF(AF2 p);
+//------------------------------------------------------------------------------------------------------------------------------
+ // Filtering for a given tap for the scalar.
+ void FsrEasuTapF(
+ inout AF3 aC, // Accumulated color, with negative lobe.
+ inout AF1 aW, // Accumulated weight.
+ AF2 off, // Pixel offset from resolve position to tap.
+ AF2 dir, // Gradient direction.
+ AF2 len, // Length.
+ AF1 lob, // Negative lobe strength.
+ AF1 clp, // Clipping point.
+ AF3 c){ // Tap color.
+ // Rotate offset by direction.
+ AF2 v;
+ v.x=(off.x*( dir.x))+(off.y*dir.y);
+ v.y=(off.x*(-dir.y))+(off.y*dir.x);
+ // Anisotropy.
+ v*=len;
+ // Compute distance^2.
+ AF1 d2=v.x*v.x+v.y*v.y;
+ // Limit to the window as at corner, 2 taps can easily be outside.
+ d2=min(d2,clp);
+ // Approximation of lancos2 without sin() or rcp(), or sqrt() to get x.
+ // (25/16 * (2/5 * x^2 - 1)^2 - (25/16 - 1)) * (1/4 * x^2 - 1)^2
+ // |_______________________________________| |_______________|
+ // base window
+ // The general form of the 'base' is,
+ // (a*(b*x^2-1)^2-(a-1))
+ // Where 'a=1/(2*b-b^2)' and 'b' moves around the negative lobe.
+ AF1 wB=AF1_(2.0/5.0)*d2+AF1_(-1.0);
+ AF1 wA=lob*d2+AF1_(-1.0);
+ wB*=wB;
+ wA*=wA;
+ wB=AF1_(25.0/16.0)*wB+AF1_(-(25.0/16.0-1.0));
+ AF1 w=wB*wA;
+ // Do weighted average.
+ aC+=c*w;aW+=w;}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Accumulate direction and length.
+ void FsrEasuSetF(
+ inout AF2 dir,
+ inout AF1 len,
+ AF2 pp,
+ AP1 biS,AP1 biT,AP1 biU,AP1 biV,
+ AF1 lA,AF1 lB,AF1 lC,AF1 lD,AF1 lE){
+ // Compute bilinear weight, branches factor out as predicates are compiler time immediates.
+ // s t
+ // u v
+ AF1 w = AF1_(0.0);
+ if(biS)w=(AF1_(1.0)-pp.x)*(AF1_(1.0)-pp.y);
+ if(biT)w= pp.x *(AF1_(1.0)-pp.y);
+ if(biU)w=(AF1_(1.0)-pp.x)* pp.y ;
+ if(biV)w= pp.x * pp.y ;
+ // Direction is the '+' diff.
+ // a
+ // b c d
+ // e
+ // Then takes magnitude from abs average of both sides of 'c'.
+ // Length converts gradient reversal to 0, smoothly to non-reversal at 1, shaped, then adding horz and vert terms.
+ AF1 dc=lD-lC;
+ AF1 cb=lC-lB;
+ AF1 lenX=max(abs(dc),abs(cb));
+ lenX=APrxLoRcpF1(lenX);
+ AF1 dirX=lD-lB;
+ dir.x+=dirX*w;
+ lenX=ASatF1(abs(dirX)*lenX);
+ lenX*=lenX;
+ len+=lenX*w;
+ // Repeat for the y axis.
+ AF1 ec=lE-lC;
+ AF1 ca=lC-lA;
+ AF1 lenY=max(abs(ec),abs(ca));
+ lenY=APrxLoRcpF1(lenY);
+ AF1 dirY=lE-lA;
+ dir.y+=dirY*w;
+ lenY=ASatF1(abs(dirY)*lenY);
+ lenY*=lenY;
+ len+=lenY*w;}
+//------------------------------------------------------------------------------------------------------------------------------
+ void FsrEasuF(
+ out AF3 pix,
+ AU2 ip, // Integer pixel position in output.
+ AU4 con0, // Constants generated by FsrEasuCon().
+ AU4 con1,
+ AU4 con2,
+ AU4 con3){
+//------------------------------------------------------------------------------------------------------------------------------
+ // Get position of 'f'.
+ AF2 pp=AF2(ip)*AF2_AU2(con0.xy)+AF2_AU2(con0.zw);
+ AF2 fp=floor(pp);
+ pp-=fp;
+//------------------------------------------------------------------------------------------------------------------------------
+ // 12-tap kernel.
+ // b c
+ // e f g h
+ // i j k l
+ // n o
+ // Gather 4 ordering.
+ // a b
+ // r g
+ // For packed FP16, need either {rg} or {ab} so using the following setup for gather in all versions,
+ // a b <- unused (z)
+ // r g
+ // a b a b
+ // r g r g
+ // a b
+ // r g <- unused (z)
+ // Allowing dead-code removal to remove the 'z's.
+ AF2 p0=fp*AF2_AU2(con1.xy)+AF2_AU2(con1.zw);
+ // These are from p0 to avoid pulling two constants on pre-Navi hardware.
+ AF2 p1=p0+AF2_AU2(con2.xy);
+ AF2 p2=p0+AF2_AU2(con2.zw);
+ AF2 p3=p0+AF2_AU2(con3.xy);
+ AF4 bczzR=FsrEasuRF(p0);
+ AF4 bczzG=FsrEasuGF(p0);
+ AF4 bczzB=FsrEasuBF(p0);
+ AF4 ijfeR=FsrEasuRF(p1);
+ AF4 ijfeG=FsrEasuGF(p1);
+ AF4 ijfeB=FsrEasuBF(p1);
+ AF4 klhgR=FsrEasuRF(p2);
+ AF4 klhgG=FsrEasuGF(p2);
+ AF4 klhgB=FsrEasuBF(p2);
+ AF4 zzonR=FsrEasuRF(p3);
+ AF4 zzonG=FsrEasuGF(p3);
+ AF4 zzonB=FsrEasuBF(p3);
+//------------------------------------------------------------------------------------------------------------------------------
+ // Simplest multi-channel approximate luma possible (luma times 2, in 2 FMA/MAD).
+ AF4 bczzL=bczzB*AF4_(0.5)+(bczzR*AF4_(0.5)+bczzG);
+ AF4 ijfeL=ijfeB*AF4_(0.5)+(ijfeR*AF4_(0.5)+ijfeG);
+ AF4 klhgL=klhgB*AF4_(0.5)+(klhgR*AF4_(0.5)+klhgG);
+ AF4 zzonL=zzonB*AF4_(0.5)+(zzonR*AF4_(0.5)+zzonG);
+ // Rename.
+ AF1 bL=bczzL.x;
+ AF1 cL=bczzL.y;
+ AF1 iL=ijfeL.x;
+ AF1 jL=ijfeL.y;
+ AF1 fL=ijfeL.z;
+ AF1 eL=ijfeL.w;
+ AF1 kL=klhgL.x;
+ AF1 lL=klhgL.y;
+ AF1 hL=klhgL.z;
+ AF1 gL=klhgL.w;
+ AF1 oL=zzonL.z;
+ AF1 nL=zzonL.w;
+ // Accumulate for bilinear interpolation.
+ AF2 dir=AF2_(0.0);
+ AF1 len=AF1_(0.0);
+ FsrEasuSetF(dir,len,pp,true, false,false,false,bL,eL,fL,gL,jL);
+ FsrEasuSetF(dir,len,pp,false,true ,false,false,cL,fL,gL,hL,kL);
+ FsrEasuSetF(dir,len,pp,false,false,true ,false,fL,iL,jL,kL,nL);
+ FsrEasuSetF(dir,len,pp,false,false,false,true ,gL,jL,kL,lL,oL);
+//------------------------------------------------------------------------------------------------------------------------------
+ // Normalize with approximation, and cleanup close to zero.
+ AF2 dir2=dir*dir;
+ AF1 dirR=dir2.x+dir2.y;
+ AP1 zro=dirR<AF1_(1.0/32768.0);
+ dirR=APrxLoRsqF1(dirR);
+ dirR=zro?AF1_(1.0):dirR;
+ dir.x=zro?AF1_(1.0):dir.x;
+ dir*=AF2_(dirR);
+ // Transform from {0 to 2} to {0 to 1} range, and shape with square.
+ len=len*AF1_(0.5);
+ len*=len;
+ // Stretch kernel {1.0 vert|horz, to sqrt(2.0) on diagonal}.
+ AF1 stretch=(dir.x*dir.x+dir.y*dir.y)*APrxLoRcpF1(max(abs(dir.x),abs(dir.y)));
+ // Anisotropic length after rotation,
+ // x := 1.0 lerp to 'stretch' on edges
+ // y := 1.0 lerp to 2x on edges
+ AF2 len2=AF2(AF1_(1.0)+(stretch-AF1_(1.0))*len,AF1_(1.0)+AF1_(-0.5)*len);
+ // Based on the amount of 'edge',
+ // the window shifts from +/-{sqrt(2.0) to slightly beyond 2.0}.
+ AF1 lob=AF1_(0.5)+AF1_((1.0/4.0-0.04)-0.5)*len;
+ // Set distance^2 clipping point to the end of the adjustable window.
+ AF1 clp=APrxLoRcpF1(lob);
+//------------------------------------------------------------------------------------------------------------------------------
+ // Accumulation mixed with min/max of 4 nearest.
+ // b c
+ // e f g h
+ // i j k l
+ // n o
+ AF3 min4=min(AMin3F3(AF3(ijfeR.z,ijfeG.z,ijfeB.z),AF3(klhgR.w,klhgG.w,klhgB.w),AF3(ijfeR.y,ijfeG.y,ijfeB.y)),
+ AF3(klhgR.x,klhgG.x,klhgB.x));
+ AF3 max4=max(AMax3F3(AF3(ijfeR.z,ijfeG.z,ijfeB.z),AF3(klhgR.w,klhgG.w,klhgB.w),AF3(ijfeR.y,ijfeG.y,ijfeB.y)),
+ AF3(klhgR.x,klhgG.x,klhgB.x));
+ // Accumulation.
+ AF3 aC=AF3_(0.0);
+ AF1 aW=AF1_(0.0);
+ FsrEasuTapF(aC,aW,AF2( 0.0,-1.0)-pp,dir,len2,lob,clp,AF3(bczzR.x,bczzG.x,bczzB.x)); // b
+ FsrEasuTapF(aC,aW,AF2( 1.0,-1.0)-pp,dir,len2,lob,clp,AF3(bczzR.y,bczzG.y,bczzB.y)); // c
+ FsrEasuTapF(aC,aW,AF2(-1.0, 1.0)-pp,dir,len2,lob,clp,AF3(ijfeR.x,ijfeG.x,ijfeB.x)); // i
+ FsrEasuTapF(aC,aW,AF2( 0.0, 1.0)-pp,dir,len2,lob,clp,AF3(ijfeR.y,ijfeG.y,ijfeB.y)); // j
+ FsrEasuTapF(aC,aW,AF2( 0.0, 0.0)-pp,dir,len2,lob,clp,AF3(ijfeR.z,ijfeG.z,ijfeB.z)); // f
+ FsrEasuTapF(aC,aW,AF2(-1.0, 0.0)-pp,dir,len2,lob,clp,AF3(ijfeR.w,ijfeG.w,ijfeB.w)); // e
+ FsrEasuTapF(aC,aW,AF2( 1.0, 1.0)-pp,dir,len2,lob,clp,AF3(klhgR.x,klhgG.x,klhgB.x)); // k
+ FsrEasuTapF(aC,aW,AF2( 2.0, 1.0)-pp,dir,len2,lob,clp,AF3(klhgR.y,klhgG.y,klhgB.y)); // l
+ FsrEasuTapF(aC,aW,AF2( 2.0, 0.0)-pp,dir,len2,lob,clp,AF3(klhgR.z,klhgG.z,klhgB.z)); // h
+ FsrEasuTapF(aC,aW,AF2( 1.0, 0.0)-pp,dir,len2,lob,clp,AF3(klhgR.w,klhgG.w,klhgB.w)); // g
+ FsrEasuTapF(aC,aW,AF2( 1.0, 2.0)-pp,dir,len2,lob,clp,AF3(zzonR.z,zzonG.z,zzonB.z)); // o
+ FsrEasuTapF(aC,aW,AF2( 0.0, 2.0)-pp,dir,len2,lob,clp,AF3(zzonR.w,zzonG.w,zzonB.w)); // n
+//------------------------------------------------------------------------------------------------------------------------------
+ // Normalize and dering.
+ pix=min(max4,max(min4,aC*AF3_(ARcpF1(aW))));}
+#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// PACKED 16-BIT VERSION
+//==============================================================================================================================
+#if defined(A_GPU)&&defined(A_HALF)&&defined(FSR_EASU_H)
+// Input callback prototypes, need to be implemented by calling shader
+ AH4 FsrEasuRH(AF2 p);
+ AH4 FsrEasuGH(AF2 p);
+ AH4 FsrEasuBH(AF2 p);
+//------------------------------------------------------------------------------------------------------------------------------
+ // This runs 2 taps in parallel.
+ void FsrEasuTapH(
+ inout AH2 aCR,inout AH2 aCG,inout AH2 aCB,
+ inout AH2 aW,
+ AH2 offX,AH2 offY,
+ AH2 dir,
+ AH2 len,
+ AH1 lob,
+ AH1 clp,
+ AH2 cR,AH2 cG,AH2 cB){
+ AH2 vX,vY;
+ vX=offX* dir.xx +offY*dir.yy;
+ vY=offX*(-dir.yy)+offY*dir.xx;
+ vX*=len.x;vY*=len.y;
+ AH2 d2=vX*vX+vY*vY;
+ d2=min(d2,AH2_(clp));
+ AH2 wB=AH2_(2.0/5.0)*d2+AH2_(-1.0);
+ AH2 wA=AH2_(lob)*d2+AH2_(-1.0);
+ wB*=wB;
+ wA*=wA;
+ wB=AH2_(25.0/16.0)*wB+AH2_(-(25.0/16.0-1.0));
+ AH2 w=wB*wA;
+ aCR+=cR*w;aCG+=cG*w;aCB+=cB*w;aW+=w;}
+//------------------------------------------------------------------------------------------------------------------------------
+ // This runs 2 taps in parallel.
+ void FsrEasuSetH(
+ inout AH2 dirPX,inout AH2 dirPY,
+ inout AH2 lenP,
+ AH2 pp,
+ AP1 biST,AP1 biUV,
+ AH2 lA,AH2 lB,AH2 lC,AH2 lD,AH2 lE){
+ AH2 w = AH2_(0.0);
+ if(biST)w=(AH2(1.0,0.0)+AH2(-pp.x,pp.x))*AH2_(AH1_(1.0)-pp.y);
+ if(biUV)w=(AH2(1.0,0.0)+AH2(-pp.x,pp.x))*AH2_( pp.y);
+ // ABS is not free in the packed FP16 path.
+ AH2 dc=lD-lC;
+ AH2 cb=lC-lB;
+ AH2 lenX=max(abs(dc),abs(cb));
+ lenX=ARcpH2(lenX);
+ AH2 dirX=lD-lB;
+ dirPX+=dirX*w;
+ lenX=ASatH2(abs(dirX)*lenX);
+ lenX*=lenX;
+ lenP+=lenX*w;
+ AH2 ec=lE-lC;
+ AH2 ca=lC-lA;
+ AH2 lenY=max(abs(ec),abs(ca));
+ lenY=ARcpH2(lenY);
+ AH2 dirY=lE-lA;
+ dirPY+=dirY*w;
+ lenY=ASatH2(abs(dirY)*lenY);
+ lenY*=lenY;
+ lenP+=lenY*w;}
+//------------------------------------------------------------------------------------------------------------------------------
+ void FsrEasuH(
+ out AH3 pix,
+ AU2 ip,
+ AU4 con0,
+ AU4 con1,
+ AU4 con2,
+ AU4 con3){
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 pp=AF2(ip)*AF2_AU2(con0.xy)+AF2_AU2(con0.zw);
+ AF2 fp=floor(pp);
+ pp-=fp;
+ AH2 ppp=AH2(pp);
+//------------------------------------------------------------------------------------------------------------------------------
+ AF2 p0=fp*AF2_AU2(con1.xy)+AF2_AU2(con1.zw);
+ AF2 p1=p0+AF2_AU2(con2.xy);
+ AF2 p2=p0+AF2_AU2(con2.zw);
+ AF2 p3=p0+AF2_AU2(con3.xy);
+ AH4 bczzR=FsrEasuRH(p0);
+ AH4 bczzG=FsrEasuGH(p0);
+ AH4 bczzB=FsrEasuBH(p0);
+ AH4 ijfeR=FsrEasuRH(p1);
+ AH4 ijfeG=FsrEasuGH(p1);
+ AH4 ijfeB=FsrEasuBH(p1);
+ AH4 klhgR=FsrEasuRH(p2);
+ AH4 klhgG=FsrEasuGH(p2);
+ AH4 klhgB=FsrEasuBH(p2);
+ AH4 zzonR=FsrEasuRH(p3);
+ AH4 zzonG=FsrEasuGH(p3);
+ AH4 zzonB=FsrEasuBH(p3);
+//------------------------------------------------------------------------------------------------------------------------------
+ AH4 bczzL=bczzB*AH4_(0.5)+(bczzR*AH4_(0.5)+bczzG);
+ AH4 ijfeL=ijfeB*AH4_(0.5)+(ijfeR*AH4_(0.5)+ijfeG);
+ AH4 klhgL=klhgB*AH4_(0.5)+(klhgR*AH4_(0.5)+klhgG);
+ AH4 zzonL=zzonB*AH4_(0.5)+(zzonR*AH4_(0.5)+zzonG);
+ AH1 bL=bczzL.x;
+ AH1 cL=bczzL.y;
+ AH1 iL=ijfeL.x;
+ AH1 jL=ijfeL.y;
+ AH1 fL=ijfeL.z;
+ AH1 eL=ijfeL.w;
+ AH1 kL=klhgL.x;
+ AH1 lL=klhgL.y;
+ AH1 hL=klhgL.z;
+ AH1 gL=klhgL.w;
+ AH1 oL=zzonL.z;
+ AH1 nL=zzonL.w;
+ // This part is different, accumulating 2 taps in parallel.
+ AH2 dirPX=AH2_(0.0);
+ AH2 dirPY=AH2_(0.0);
+ AH2 lenP=AH2_(0.0);
+ FsrEasuSetH(dirPX,dirPY,lenP,ppp,true, false,AH2(bL,cL),AH2(eL,fL),AH2(fL,gL),AH2(gL,hL),AH2(jL,kL));
+ FsrEasuSetH(dirPX,dirPY,lenP,ppp,false,true ,AH2(fL,gL),AH2(iL,jL),AH2(jL,kL),AH2(kL,lL),AH2(nL,oL));
+ AH2 dir=AH2(dirPX.r+dirPX.g,dirPY.r+dirPY.g);
+ AH1 len=lenP.r+lenP.g;
+//------------------------------------------------------------------------------------------------------------------------------
+ AH2 dir2=dir*dir;
+ AH1 dirR=dir2.x+dir2.y;
+ AP1 zro=dirR<AH1_(1.0/32768.0);
+ dirR=APrxLoRsqH1(dirR);
+ dirR=zro?AH1_(1.0):dirR;
+ dir.x=zro?AH1_(1.0):dir.x;
+ dir*=AH2_(dirR);
+ len=len*AH1_(0.5);
+ len*=len;
+ AH1 stretch=(dir.x*dir.x+dir.y*dir.y)*APrxLoRcpH1(max(abs(dir.x),abs(dir.y)));
+ AH2 len2=AH2(AH1_(1.0)+(stretch-AH1_(1.0))*len,AH1_(1.0)+AH1_(-0.5)*len);
+ AH1 lob=AH1_(0.5)+AH1_((1.0/4.0-0.04)-0.5)*len;
+ AH1 clp=APrxLoRcpH1(lob);
+//------------------------------------------------------------------------------------------------------------------------------
+ // FP16 is different, using packed trick to do min and max in same operation.
+ AH2 bothR=max(max(AH2(-ijfeR.z,ijfeR.z),AH2(-klhgR.w,klhgR.w)),max(AH2(-ijfeR.y,ijfeR.y),AH2(-klhgR.x,klhgR.x)));
+ AH2 bothG=max(max(AH2(-ijfeG.z,ijfeG.z),AH2(-klhgG.w,klhgG.w)),max(AH2(-ijfeG.y,ijfeG.y),AH2(-klhgG.x,klhgG.x)));
+ AH2 bothB=max(max(AH2(-ijfeB.z,ijfeB.z),AH2(-klhgB.w,klhgB.w)),max(AH2(-ijfeB.y,ijfeB.y),AH2(-klhgB.x,klhgB.x)));
+ // This part is different for FP16, working pairs of taps at a time.
+ AH2 pR=AH2_(0.0);
+ AH2 pG=AH2_(0.0);
+ AH2 pB=AH2_(0.0);
+ AH2 pW=AH2_(0.0);
+ FsrEasuTapH(pR,pG,pB,pW,AH2( 0.0, 1.0)-ppp.xx,AH2(-1.0,-1.0)-ppp.yy,dir,len2,lob,clp,bczzR.xy,bczzG.xy,bczzB.xy);
+ FsrEasuTapH(pR,pG,pB,pW,AH2(-1.0, 0.0)-ppp.xx,AH2( 1.0, 1.0)-ppp.yy,dir,len2,lob,clp,ijfeR.xy,ijfeG.xy,ijfeB.xy);
+ FsrEasuTapH(pR,pG,pB,pW,AH2( 0.0,-1.0)-ppp.xx,AH2( 0.0, 0.0)-ppp.yy,dir,len2,lob,clp,ijfeR.zw,ijfeG.zw,ijfeB.zw);
+ FsrEasuTapH(pR,pG,pB,pW,AH2( 1.0, 2.0)-ppp.xx,AH2( 1.0, 1.0)-ppp.yy,dir,len2,lob,clp,klhgR.xy,klhgG.xy,klhgB.xy);
+ FsrEasuTapH(pR,pG,pB,pW,AH2( 2.0, 1.0)-ppp.xx,AH2( 0.0, 0.0)-ppp.yy,dir,len2,lob,clp,klhgR.zw,klhgG.zw,klhgB.zw);
+ FsrEasuTapH(pR,pG,pB,pW,AH2( 1.0, 0.0)-ppp.xx,AH2( 2.0, 2.0)-ppp.yy,dir,len2,lob,clp,zzonR.zw,zzonG.zw,zzonB.zw);
+ AH3 aC=AH3(pR.x+pR.y,pG.x+pG.y,pB.x+pB.y);
+ AH1 aW=pW.x+pW.y;
+//------------------------------------------------------------------------------------------------------------------------------
+ // Slightly different for FP16 version due to combined min and max.
+ pix=min(AH3(bothR.y,bothG.y,bothB.y),max(-AH3(bothR.x,bothG.x,bothB.x),aC*AH3_(ARcpH1(aW))));}
+#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+// FSR - [RCAS] ROBUST CONTRAST ADAPTIVE SHARPENING
+//
+//------------------------------------------------------------------------------------------------------------------------------
+// CAS uses a simplified mechanism to convert local contrast into a variable amount of sharpness.
+// RCAS uses a more exact mechanism, solving for the maximum local sharpness possible before clipping.
+// RCAS also has a built in process to limit sharpening of what it detects as possible noise.
+// RCAS sharper does not support scaling, as it should be applied after EASU scaling.
+// Pass EASU output straight into RCAS, no color conversions necessary.
+//------------------------------------------------------------------------------------------------------------------------------
+// RCAS is based on the following logic.
+// RCAS uses a 5 tap filter in a cross pattern (same as CAS),
+// w n
+// w 1 w for taps w m e
+// w s
+// Where 'w' is the negative lobe weight.
+// output = (w*(n+e+w+s)+m)/(4*w+1)
+// RCAS solves for 'w' by seeing where the signal might clip out of the {0 to 1} input range,
+// 0 == (w*(n+e+w+s)+m)/(4*w+1) -> w = -m/(n+e+w+s)
+// 1 == (w*(n+e+w+s)+m)/(4*w+1) -> w = (1-m)/(n+e+w+s-4*1)
+// Then chooses the 'w' which results in no clipping, limits 'w', and multiplies by the 'sharp' amount.
+// This solution above has issues with MSAA input as the steps along the gradient cause edge detection issues.
+// So RCAS uses 4x the maximum and 4x the minimum (depending on equation)in place of the individual taps.
+// As well as switching from 'm' to either the minimum or maximum (depending on side), to help in energy conservation.
+// This stabilizes RCAS.
+// RCAS does a simple highpass which is normalized against the local contrast then shaped,
+// 0.25
+// 0.25 -1 0.25
+// 0.25
+// This is used as a noise detection filter, to reduce the effect of RCAS on grain, and focus on real edges.
+//
+// GLSL example for the required callbacks :
+//
+// AH4 FsrRcasLoadH(ASW2 p){return AH4(imageLoad(imgSrc,ASU2(p)));}
+// void FsrRcasInputH(inout AH1 r,inout AH1 g,inout AH1 b)
+// {
+// //do any simple input color conversions here or leave empty if none needed
+// }
+//
+// FsrRcasCon need to be called from the CPU or GPU to set up constants.
+// Including a GPU example here, the 'con' value would be stored out to a constant buffer.
+//
+// AU4 con;
+// FsrRcasCon(con,
+// 0.0); // The scale is {0.0 := maximum sharpness, to N>0, where N is the number of stops (halving) of the reduction of sharpness}.
+// ---------------
+// RCAS sharpening supports a CAS-like pass-through alpha via,
+// #define FSR_RCAS_PASSTHROUGH_ALPHA 1
+// RCAS also supports a define to enable a more expensive path to avoid some sharpening of noise.
+// Would suggest it is better to apply film grain after RCAS sharpening (and after scaling) instead of using this define,
+// #define FSR_RCAS_DENOISE 1
+//==============================================================================================================================
+// This is set at the limit of providing unnatural results for sharpening.
+#define FSR_RCAS_LIMIT (0.25-(1.0/16.0))
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// CONSTANT SETUP
+//==============================================================================================================================
+// Call to setup required constant values (works on CPU or GPU).
+A_STATIC void FsrRcasCon(
+outAU4 con,
+// The scale is {0.0 := maximum, to N>0, where N is the number of stops (halving) of the reduction of sharpness}.
+AF1 sharpness){
+ // Transform from stops to linear value.
+ sharpness=AExp2F1(-sharpness);
+ varAF2(hSharp)=initAF2(sharpness,sharpness);
+ con[0]=AU1_AF1(sharpness);
+ con[1]=AU1_AH2_AF2(hSharp);
+ con[2]=0;
+ con[3]=0;}
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// NON-PACKED 32-BIT VERSION
+//==============================================================================================================================
+#if defined(A_GPU)&&defined(FSR_RCAS_F)
+ // Input callback prototypes that need to be implemented by calling shader
+ AF4 FsrRcasLoadF(ASU2 p);
+ void FsrRcasInputF(inout AF1 r,inout AF1 g,inout AF1 b);
+//------------------------------------------------------------------------------------------------------------------------------
+ void FsrRcasF(
+ out AF1 pixR, // Output values, non-vector so port between RcasFilter() and RcasFilterH() is easy.
+ out AF1 pixG,
+ out AF1 pixB,
+ #ifdef FSR_RCAS_PASSTHROUGH_ALPHA
+ out AF1 pixA,
+ #endif
+ AU2 ip, // Integer pixel position in output.
+ AU4 con){ // Constant generated by RcasSetup().
+ // Algorithm uses minimal 3x3 pixel neighborhood.
+ // b
+ // d e f
+ // h
+ ASU2 sp=ASU2(ip);
+ AF3 b=FsrRcasLoadF(sp+ASU2( 0,-1)).rgb;
+ AF3 d=FsrRcasLoadF(sp+ASU2(-1, 0)).rgb;
+ #ifdef FSR_RCAS_PASSTHROUGH_ALPHA
+ AF4 ee=FsrRcasLoadF(sp);
+ AF3 e=ee.rgb;pixA=ee.a;
+ #else
+ AF3 e=FsrRcasLoadF(sp).rgb;
+ #endif
+ AF3 f=FsrRcasLoadF(sp+ASU2( 1, 0)).rgb;
+ AF3 h=FsrRcasLoadF(sp+ASU2( 0, 1)).rgb;
+ // Rename (32-bit) or regroup (16-bit).
+ AF1 bR=b.r;
+ AF1 bG=b.g;
+ AF1 bB=b.b;
+ AF1 dR=d.r;
+ AF1 dG=d.g;
+ AF1 dB=d.b;
+ AF1 eR=e.r;
+ AF1 eG=e.g;
+ AF1 eB=e.b;
+ AF1 fR=f.r;
+ AF1 fG=f.g;
+ AF1 fB=f.b;
+ AF1 hR=h.r;
+ AF1 hG=h.g;
+ AF1 hB=h.b;
+ // Run optional input transform.
+ FsrRcasInputF(bR,bG,bB);
+ FsrRcasInputF(dR,dG,dB);
+ FsrRcasInputF(eR,eG,eB);
+ FsrRcasInputF(fR,fG,fB);
+ FsrRcasInputF(hR,hG,hB);
+ // Luma times 2.
+ AF1 bL=bB*AF1_(0.5)+(bR*AF1_(0.5)+bG);
+ AF1 dL=dB*AF1_(0.5)+(dR*AF1_(0.5)+dG);
+ AF1 eL=eB*AF1_(0.5)+(eR*AF1_(0.5)+eG);
+ AF1 fL=fB*AF1_(0.5)+(fR*AF1_(0.5)+fG);
+ AF1 hL=hB*AF1_(0.5)+(hR*AF1_(0.5)+hG);
+ // Noise detection.
+ AF1 nz=AF1_(0.25)*bL+AF1_(0.25)*dL+AF1_(0.25)*fL+AF1_(0.25)*hL-eL;
+ nz=ASatF1(abs(nz)*APrxMedRcpF1(AMax3F1(AMax3F1(bL,dL,eL),fL,hL)-AMin3F1(AMin3F1(bL,dL,eL),fL,hL)));
+ nz=AF1_(-0.5)*nz+AF1_(1.0);
+ // Min and max of ring.
+ AF1 mn4R=min(AMin3F1(bR,dR,fR),hR);
+ AF1 mn4G=min(AMin3F1(bG,dG,fG),hG);
+ AF1 mn4B=min(AMin3F1(bB,dB,fB),hB);
+ AF1 mx4R=max(AMax3F1(bR,dR,fR),hR);
+ AF1 mx4G=max(AMax3F1(bG,dG,fG),hG);
+ AF1 mx4B=max(AMax3F1(bB,dB,fB),hB);
+ // Immediate constants for peak range.
+ AF2 peakC=AF2(1.0,-1.0*4.0);
+ // Limiters, these need to be high precision RCPs.
+ AF1 hitMinR=min(mn4R,eR)*ARcpF1(AF1_(4.0)*mx4R);
+ AF1 hitMinG=min(mn4G,eG)*ARcpF1(AF1_(4.0)*mx4G);
+ AF1 hitMinB=min(mn4B,eB)*ARcpF1(AF1_(4.0)*mx4B);
+ AF1 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpF1(AF1_(4.0)*mn4R+peakC.y);
+ AF1 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpF1(AF1_(4.0)*mn4G+peakC.y);
+ AF1 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpF1(AF1_(4.0)*mn4B+peakC.y);
+ AF1 lobeR=max(-hitMinR,hitMaxR);
+ AF1 lobeG=max(-hitMinG,hitMaxG);
+ AF1 lobeB=max(-hitMinB,hitMaxB);
+ AF1 lobe=max(AF1_(-FSR_RCAS_LIMIT),min(AMax3F1(lobeR,lobeG,lobeB),AF1_(0.0)))*AF1_AU1(con.x);
+ // Apply noise removal.
+ #ifdef FSR_RCAS_DENOISE
+ lobe*=nz;
+ #endif
+ // Resolve, which needs the medium precision rcp approximation to avoid visible tonality changes.
+ AF1 rcpL=APrxMedRcpF1(AF1_(4.0)*lobe+AF1_(1.0));
+ pixR=(lobe*bR+lobe*dR+lobe*hR+lobe*fR+eR)*rcpL;
+ pixG=(lobe*bG+lobe*dG+lobe*hG+lobe*fG+eG)*rcpL;
+ pixB=(lobe*bB+lobe*dB+lobe*hB+lobe*fB+eB)*rcpL;
+ return;}
+#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// NON-PACKED 16-BIT VERSION
+//==============================================================================================================================
+#if defined(A_GPU)&&defined(A_HALF)&&defined(FSR_RCAS_H)
+ // Input callback prototypes that need to be implemented by calling shader
+ AH4 FsrRcasLoadH(ASW2 p);
+ void FsrRcasInputH(inout AH1 r,inout AH1 g,inout AH1 b);
+//------------------------------------------------------------------------------------------------------------------------------
+ void FsrRcasH(
+ out AH1 pixR, // Output values, non-vector so port between RcasFilter() and RcasFilterH() is easy.
+ out AH1 pixG,
+ out AH1 pixB,
+ #ifdef FSR_RCAS_PASSTHROUGH_ALPHA
+ out AH1 pixA,
+ #endif
+ AU2 ip, // Integer pixel position in output.
+ AU4 con){ // Constant generated by RcasSetup().
+ // Sharpening algorithm uses minimal 3x3 pixel neighborhood.
+ // b
+ // d e f
+ // h
+ ASW2 sp=ASW2(ip);
+ AH3 b=FsrRcasLoadH(sp+ASW2( 0,-1)).rgb;
+ AH3 d=FsrRcasLoadH(sp+ASW2(-1, 0)).rgb;
+ #ifdef FSR_RCAS_PASSTHROUGH_ALPHA
+ AH4 ee=FsrRcasLoadH(sp);
+ AH3 e=ee.rgb;pixA=ee.a;
+ #else
+ AH3 e=FsrRcasLoadH(sp).rgb;
+ #endif
+ AH3 f=FsrRcasLoadH(sp+ASW2( 1, 0)).rgb;
+ AH3 h=FsrRcasLoadH(sp+ASW2( 0, 1)).rgb;
+ // Rename (32-bit) or regroup (16-bit).
+ AH1 bR=b.r;
+ AH1 bG=b.g;
+ AH1 bB=b.b;
+ AH1 dR=d.r;
+ AH1 dG=d.g;
+ AH1 dB=d.b;
+ AH1 eR=e.r;
+ AH1 eG=e.g;
+ AH1 eB=e.b;
+ AH1 fR=f.r;
+ AH1 fG=f.g;
+ AH1 fB=f.b;
+ AH1 hR=h.r;
+ AH1 hG=h.g;
+ AH1 hB=h.b;
+ // Run optional input transform.
+ FsrRcasInputH(bR,bG,bB);
+ FsrRcasInputH(dR,dG,dB);
+ FsrRcasInputH(eR,eG,eB);
+ FsrRcasInputH(fR,fG,fB);
+ FsrRcasInputH(hR,hG,hB);
+ // Luma times 2.
+ AH1 bL=bB*AH1_(0.5)+(bR*AH1_(0.5)+bG);
+ AH1 dL=dB*AH1_(0.5)+(dR*AH1_(0.5)+dG);
+ AH1 eL=eB*AH1_(0.5)+(eR*AH1_(0.5)+eG);
+ AH1 fL=fB*AH1_(0.5)+(fR*AH1_(0.5)+fG);
+ AH1 hL=hB*AH1_(0.5)+(hR*AH1_(0.5)+hG);
+ // Noise detection.
+ AH1 nz=AH1_(0.25)*bL+AH1_(0.25)*dL+AH1_(0.25)*fL+AH1_(0.25)*hL-eL;
+ nz=ASatH1(abs(nz)*APrxMedRcpH1(AMax3H1(AMax3H1(bL,dL,eL),fL,hL)-AMin3H1(AMin3H1(bL,dL,eL),fL,hL)));
+ nz=AH1_(-0.5)*nz+AH1_(1.0);
+ // Min and max of ring.
+ AH1 mn4R=min(AMin3H1(bR,dR,fR),hR);
+ AH1 mn4G=min(AMin3H1(bG,dG,fG),hG);
+ AH1 mn4B=min(AMin3H1(bB,dB,fB),hB);
+ AH1 mx4R=max(AMax3H1(bR,dR,fR),hR);
+ AH1 mx4G=max(AMax3H1(bG,dG,fG),hG);
+ AH1 mx4B=max(AMax3H1(bB,dB,fB),hB);
+ // Immediate constants for peak range.
+ AH2 peakC=AH2(1.0,-1.0*4.0);
+ // Limiters, these need to be high precision RCPs.
+ AH1 hitMinR=min(mn4R,eR)*ARcpH1(AH1_(4.0)*mx4R);
+ AH1 hitMinG=min(mn4G,eG)*ARcpH1(AH1_(4.0)*mx4G);
+ AH1 hitMinB=min(mn4B,eB)*ARcpH1(AH1_(4.0)*mx4B);
+ AH1 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpH1(AH1_(4.0)*mn4R+peakC.y);
+ AH1 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpH1(AH1_(4.0)*mn4G+peakC.y);
+ AH1 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpH1(AH1_(4.0)*mn4B+peakC.y);
+ AH1 lobeR=max(-hitMinR,hitMaxR);
+ AH1 lobeG=max(-hitMinG,hitMaxG);
+ AH1 lobeB=max(-hitMinB,hitMaxB);
+ AH1 lobe=max(AH1_(-FSR_RCAS_LIMIT),min(AMax3H1(lobeR,lobeG,lobeB),AH1_(0.0)))*AH2_AU1(con.y).x;
+ // Apply noise removal.
+ #ifdef FSR_RCAS_DENOISE
+ lobe*=nz;
+ #endif
+ // Resolve, which needs the medium precision rcp approximation to avoid visible tonality changes.
+ AH1 rcpL=APrxMedRcpH1(AH1_(4.0)*lobe+AH1_(1.0));
+ pixR=(lobe*bR+lobe*dR+lobe*hR+lobe*fR+eR)*rcpL;
+ pixG=(lobe*bG+lobe*dG+lobe*hG+lobe*fG+eG)*rcpL;
+ pixB=(lobe*bB+lobe*dB+lobe*hB+lobe*fB+eB)*rcpL;}
+#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+// PACKED 16-BIT VERSION
+//==============================================================================================================================
+#if defined(A_GPU)&&defined(A_HALF)&&defined(FSR_RCAS_HX2)
+ // Input callback prototypes that need to be implemented by the calling shader
+ AH4 FsrRcasLoadHx2(ASW2 p);
+ void FsrRcasInputHx2(inout AH2 r,inout AH2 g,inout AH2 b);
+//------------------------------------------------------------------------------------------------------------------------------
+ // Can be used to convert from packed Structures of Arrays to Arrays of Structures for store.
+ void FsrRcasDepackHx2(out AH4 pix0,out AH4 pix1,AH2 pixR,AH2 pixG,AH2 pixB){
+ #ifdef A_HLSL
+ // Invoke a slower path for DX only, since it won't allow uninitialized values.
+ pix0.a=pix1.a=0.0;
+ #endif
+ pix0.rgb=AH3(pixR.x,pixG.x,pixB.x);
+ pix1.rgb=AH3(pixR.y,pixG.y,pixB.y);}
+//------------------------------------------------------------------------------------------------------------------------------
+ void FsrRcasHx2(
+ // Output values are for 2 8x8 tiles in a 16x8 region.
+ // pix<R,G,B>.x = left 8x8 tile
+ // pix<R,G,B>.y = right 8x8 tile
+ // This enables later processing to easily be packed as well.
+ out AH2 pixR,
+ out AH2 pixG,
+ out AH2 pixB,
+ #ifdef FSR_RCAS_PASSTHROUGH_ALPHA
+ out AH2 pixA,
+ #endif
+ AU2 ip, // Integer pixel position in output.
+ AU4 con){ // Constant generated by RcasSetup().
+ // No scaling algorithm uses minimal 3x3 pixel neighborhood.
+ ASW2 sp0=ASW2(ip);
+ AH3 b0=FsrRcasLoadHx2(sp0+ASW2( 0,-1)).rgb;
+ AH3 d0=FsrRcasLoadHx2(sp0+ASW2(-1, 0)).rgb;
+ #ifdef FSR_RCAS_PASSTHROUGH_ALPHA
+ AH4 ee0=FsrRcasLoadHx2(sp0);
+ AH3 e0=ee0.rgb;pixA.r=ee0.a;
+ #else
+ AH3 e0=FsrRcasLoadHx2(sp0).rgb;
+ #endif
+ AH3 f0=FsrRcasLoadHx2(sp0+ASW2( 1, 0)).rgb;
+ AH3 h0=FsrRcasLoadHx2(sp0+ASW2( 0, 1)).rgb;
+ ASW2 sp1=sp0+ASW2(8,0);
+ AH3 b1=FsrRcasLoadHx2(sp1+ASW2( 0,-1)).rgb;
+ AH3 d1=FsrRcasLoadHx2(sp1+ASW2(-1, 0)).rgb;
+ #ifdef FSR_RCAS_PASSTHROUGH_ALPHA
+ AH4 ee1=FsrRcasLoadHx2(sp1);
+ AH3 e1=ee1.rgb;pixA.g=ee1.a;
+ #else
+ AH3 e1=FsrRcasLoadHx2(sp1).rgb;
+ #endif
+ AH3 f1=FsrRcasLoadHx2(sp1+ASW2( 1, 0)).rgb;
+ AH3 h1=FsrRcasLoadHx2(sp1+ASW2( 0, 1)).rgb;
+ // Arrays of Structures to Structures of Arrays conversion.
+ AH2 bR=AH2(b0.r,b1.r);
+ AH2 bG=AH2(b0.g,b1.g);
+ AH2 bB=AH2(b0.b,b1.b);
+ AH2 dR=AH2(d0.r,d1.r);
+ AH2 dG=AH2(d0.g,d1.g);
+ AH2 dB=AH2(d0.b,d1.b);
+ AH2 eR=AH2(e0.r,e1.r);
+ AH2 eG=AH2(e0.g,e1.g);
+ AH2 eB=AH2(e0.b,e1.b);
+ AH2 fR=AH2(f0.r,f1.r);
+ AH2 fG=AH2(f0.g,f1.g);
+ AH2 fB=AH2(f0.b,f1.b);
+ AH2 hR=AH2(h0.r,h1.r);
+ AH2 hG=AH2(h0.g,h1.g);
+ AH2 hB=AH2(h0.b,h1.b);
+ // Run optional input transform.
+ FsrRcasInputHx2(bR,bG,bB);
+ FsrRcasInputHx2(dR,dG,dB);
+ FsrRcasInputHx2(eR,eG,eB);
+ FsrRcasInputHx2(fR,fG,fB);
+ FsrRcasInputHx2(hR,hG,hB);
+ // Luma times 2.
+ AH2 bL=bB*AH2_(0.5)+(bR*AH2_(0.5)+bG);
+ AH2 dL=dB*AH2_(0.5)+(dR*AH2_(0.5)+dG);
+ AH2 eL=eB*AH2_(0.5)+(eR*AH2_(0.5)+eG);
+ AH2 fL=fB*AH2_(0.5)+(fR*AH2_(0.5)+fG);
+ AH2 hL=hB*AH2_(0.5)+(hR*AH2_(0.5)+hG);
+ // Noise detection.
+ AH2 nz=AH2_(0.25)*bL+AH2_(0.25)*dL+AH2_(0.25)*fL+AH2_(0.25)*hL-eL;
+ nz=ASatH2(abs(nz)*APrxMedRcpH2(AMax3H2(AMax3H2(bL,dL,eL),fL,hL)-AMin3H2(AMin3H2(bL,dL,eL),fL,hL)));
+ nz=AH2_(-0.5)*nz+AH2_(1.0);
+ // Min and max of ring.
+ AH2 mn4R=min(AMin3H2(bR,dR,fR),hR);
+ AH2 mn4G=min(AMin3H2(bG,dG,fG),hG);
+ AH2 mn4B=min(AMin3H2(bB,dB,fB),hB);
+ AH2 mx4R=max(AMax3H2(bR,dR,fR),hR);
+ AH2 mx4G=max(AMax3H2(bG,dG,fG),hG);
+ AH2 mx4B=max(AMax3H2(bB,dB,fB),hB);
+ // Immediate constants for peak range.
+ AH2 peakC=AH2(1.0,-1.0*4.0);
+ // Limiters, these need to be high precision RCPs.
+ AH2 hitMinR=min(mn4R,eR)*ARcpH2(AH2_(4.0)*mx4R);
+ AH2 hitMinG=min(mn4G,eG)*ARcpH2(AH2_(4.0)*mx4G);
+ AH2 hitMinB=min(mn4B,eB)*ARcpH2(AH2_(4.0)*mx4B);
+ AH2 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpH2(AH2_(4.0)*mn4R+peakC.y);
+ AH2 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpH2(AH2_(4.0)*mn4G+peakC.y);
+ AH2 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpH2(AH2_(4.0)*mn4B+peakC.y);
+ AH2 lobeR=max(-hitMinR,hitMaxR);
+ AH2 lobeG=max(-hitMinG,hitMaxG);
+ AH2 lobeB=max(-hitMinB,hitMaxB);
+ AH2 lobe=max(AH2_(-FSR_RCAS_LIMIT),min(AMax3H2(lobeR,lobeG,lobeB),AH2_(0.0)))*AH2_(AH2_AU1(con.y).x);
+ // Apply noise removal.
+ #ifdef FSR_RCAS_DENOISE
+ lobe*=nz;
+ #endif
+ // Resolve, which needs the medium precision rcp approximation to avoid visible tonality changes.
+ AH2 rcpL=APrxMedRcpH2(AH2_(4.0)*lobe+AH2_(1.0));
+ pixR=(lobe*bR+lobe*dR+lobe*hR+lobe*fR+eR)*rcpL;
+ pixG=(lobe*bG+lobe*dG+lobe*hG+lobe*fG+eG)*rcpL;
+ pixB=(lobe*bB+lobe*dB+lobe*hB+lobe*fB+eB)*rcpL;}
+#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+// FSR - [LFGA] LINEAR FILM GRAIN APPLICATOR
+//
+//------------------------------------------------------------------------------------------------------------------------------
+// Adding output-resolution film grain after scaling is a good way to mask both rendering and scaling artifacts.
+// Suggest using tiled blue noise as film grain input, with peak noise frequency set for a specific look and feel.
+// The 'Lfga*()' functions provide a convenient way to introduce grain.
+// These functions limit grain based on distance to signal limits.
+// This is done so that the grain is temporally energy preserving, and thus won't modify image tonality.
+// Grain application should be done in a linear colorspace.
+// The grain should be temporally changing, but have a temporal sum per pixel that adds to zero (non-biased).
+//------------------------------------------------------------------------------------------------------------------------------
+// Usage,
+// FsrLfga*(
+// color, // In/out linear colorspace color {0 to 1} ranged.
+// grain, // Per pixel grain texture value {-0.5 to 0.5} ranged, input is 3-channel to support colored grain.
+// amount); // Amount of grain (0 to 1} ranged.
+//------------------------------------------------------------------------------------------------------------------------------
+// Example if grain texture is monochrome: 'FsrLfgaF(color,AF3_(grain),amount)'
+//==============================================================================================================================
+#if defined(A_GPU)
+ // Maximum grain is the minimum distance to the signal limit.
+ void FsrLfgaF(inout AF3 c,AF3 t,AF1 a){c+=(t*AF3_(a))*min(AF3_(1.0)-c,c);}
+#endif
+//==============================================================================================================================
+#if defined(A_GPU)&&defined(A_HALF)
+ // Half precision version (slower).
+ void FsrLfgaH(inout AH3 c,AH3 t,AH1 a){c+=(t*AH3_(a))*min(AH3_(1.0)-c,c);}
+//------------------------------------------------------------------------------------------------------------------------------
+ // Packed half precision version (faster).
+ void FsrLfgaHx2(inout AH2 cR,inout AH2 cG,inout AH2 cB,AH2 tR,AH2 tG,AH2 tB,AH1 a){
+ cR+=(tR*AH2_(a))*min(AH2_(1.0)-cR,cR);cG+=(tG*AH2_(a))*min(AH2_(1.0)-cG,cG);cB+=(tB*AH2_(a))*min(AH2_(1.0)-cB,cB);}
+#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+// FSR - [SRTM] SIMPLE REVERSIBLE TONE-MAPPER
+//
+//------------------------------------------------------------------------------------------------------------------------------
+// This provides a way to take linear HDR color {0 to FP16_MAX} and convert it into a temporary {0 to 1} ranged post-tonemapped linear.
+// The tonemapper preserves RGB ratio, which helps maintain HDR color bleed during filtering.
+//------------------------------------------------------------------------------------------------------------------------------
+// Reversible tonemapper usage,
+// FsrSrtm*(color); // {0 to FP16_MAX} converted to {0 to 1}.
+// FsrSrtmInv*(color); // {0 to 1} converted into {0 to 32768, output peak safe for FP16}.
+//==============================================================================================================================
+#if defined(A_GPU)
+ void FsrSrtmF(inout AF3 c){c*=AF3_(ARcpF1(AMax3F1(c.r,c.g,c.b)+AF1_(1.0)));}
+ // The extra max solves the c=1.0 case (which is a /0).
+ void FsrSrtmInvF(inout AF3 c){c*=AF3_(ARcpF1(max(AF1_(1.0/32768.0),AF1_(1.0)-AMax3F1(c.r,c.g,c.b))));}
+#endif
+//==============================================================================================================================
+#if defined(A_GPU)&&defined(A_HALF)
+ void FsrSrtmH(inout AH3 c){c*=AH3_(ARcpH1(AMax3H1(c.r,c.g,c.b)+AH1_(1.0)));}
+ void FsrSrtmInvH(inout AH3 c){c*=AH3_(ARcpH1(max(AH1_(1.0/32768.0),AH1_(1.0)-AMax3H1(c.r,c.g,c.b))));}
+//------------------------------------------------------------------------------------------------------------------------------
+ void FsrSrtmHx2(inout AH2 cR,inout AH2 cG,inout AH2 cB){
+ AH2 rcp=ARcpH2(AMax3H2(cR,cG,cB)+AH2_(1.0));cR*=rcp;cG*=rcp;cB*=rcp;}
+ void FsrSrtmInvHx2(inout AH2 cR,inout AH2 cG,inout AH2 cB){
+ AH2 rcp=ARcpH2(max(AH2_(1.0/32768.0),AH2_(1.0)-AMax3H2(cR,cG,cB)));cR*=rcp;cG*=rcp;cB*=rcp;}
+#endif
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//_____________________________________________________________/\_______________________________________________________________
+//==============================================================================================================================
+//
+// FSR - [TEPD] TEMPORAL ENERGY PRESERVING DITHER
+//
+//------------------------------------------------------------------------------------------------------------------------------
+// Temporally energy preserving dithered {0 to 1} linear to gamma 2.0 conversion.
+// Gamma 2.0 is used so that the conversion back to linear is just to square the color.
+// The conversion comes in 8-bit and 10-bit modes, designed for output to 8-bit UNORM or 10:10:10:2 respectively.
+// Given good non-biased temporal blue noise as dither input,
+// the output dither will temporally conserve energy.
+// This is done by choosing the linear nearest step point instead of perceptual nearest.
+// See code below for details.
+//------------------------------------------------------------------------------------------------------------------------------
+// DX SPEC RULES FOR FLOAT->UNORM 8-BIT CONVERSION
+// ===============================================
+// - Output is 'uint(floor(saturate(n)*255.0+0.5))'.
+// - Thus rounding is to nearest.
+// - NaN gets converted to zero.
+// - INF is clamped to {0.0 to 1.0}.
+//==============================================================================================================================
+#if defined(A_GPU)
+ // Hand tuned integer position to dither value, with more values than simple checkerboard.
+ // Only 32-bit has enough precision for this compddation.
+ // Output is {0 to <1}.
+ AF1 FsrTepdDitF(AU2 p,AU1 f){
+ AF1 x=AF1_(p.x+f);
+ AF1 y=AF1_(p.y);
+ // The 1.61803 golden ratio.
+ AF1 a=AF1_((1.0+sqrt(5.0))/2.0);
+ // Number designed to provide a good visual pattern.
+ AF1 b=AF1_(1.0/3.69);
+ x=x*a+(y*b);
+ return AFractF1(x);}
+//------------------------------------------------------------------------------------------------------------------------------
+ // This version is 8-bit gamma 2.0.
+ // The 'c' input is {0 to 1}.
+ // Output is {0 to 1} ready for image store.
+ void FsrTepdC8F(inout AF3 c,AF1 dit){
+ AF3 n=sqrt(c);
+ n=floor(n*AF3_(255.0))*AF3_(1.0/255.0);
+ AF3 a=n*n;
+ AF3 b=n+AF3_(1.0/255.0);b=b*b;
+ // Ratio of 'a' to 'b' required to produce 'c'.
+ // APrxLoRcpF1() won't work here (at least for very high dynamic ranges).
+ // APrxMedRcpF1() is an IADD,FMA,MUL.
+ AF3 r=(c-b)*APrxMedRcpF3(a-b);
+ // Use the ratio as a cutoff to choose 'a' or 'b'.
+ // AGtZeroF1() is a MUL.
+ c=ASatF3(n+AGtZeroF3(AF3_(dit)-r)*AF3_(1.0/255.0));}
+//------------------------------------------------------------------------------------------------------------------------------
+ // This version is 10-bit gamma 2.0.
+ // The 'c' input is {0 to 1}.
+ // Output is {0 to 1} ready for image store.
+ void FsrTepdC10F(inout AF3 c,AF1 dit){
+ AF3 n=sqrt(c);
+ n=floor(n*AF3_(1023.0))*AF3_(1.0/1023.0);
+ AF3 a=n*n;
+ AF3 b=n+AF3_(1.0/1023.0);b=b*b;
+ AF3 r=(c-b)*APrxMedRcpF3(a-b);
+ c=ASatF3(n+AGtZeroF3(AF3_(dit)-r)*AF3_(1.0/1023.0));}
+#endif
+//==============================================================================================================================
+#if defined(A_GPU)&&defined(A_HALF)
+ AH1 FsrTepdDitH(AU2 p,AU1 f){
+ AF1 x=AF1_(p.x+f);
+ AF1 y=AF1_(p.y);
+ AF1 a=AF1_((1.0+sqrt(5.0))/2.0);
+ AF1 b=AF1_(1.0/3.69);
+ x=x*a+(y*b);
+ return AH1(AFractF1(x));}
+//------------------------------------------------------------------------------------------------------------------------------
+ void FsrTepdC8H(inout AH3 c,AH1 dit){
+ AH3 n=sqrt(c);
+ n=floor(n*AH3_(255.0))*AH3_(1.0/255.0);
+ AH3 a=n*n;
+ AH3 b=n+AH3_(1.0/255.0);b=b*b;
+ AH3 r=(c-b)*APrxMedRcpH3(a-b);
+ c=ASatH3(n+AGtZeroH3(AH3_(dit)-r)*AH3_(1.0/255.0));}
+//------------------------------------------------------------------------------------------------------------------------------
+ void FsrTepdC10H(inout AH3 c,AH1 dit){
+ AH3 n=sqrt(c);
+ n=floor(n*AH3_(1023.0))*AH3_(1.0/1023.0);
+ AH3 a=n*n;
+ AH3 b=n+AH3_(1.0/1023.0);b=b*b;
+ AH3 r=(c-b)*APrxMedRcpH3(a-b);
+ c=ASatH3(n+AGtZeroH3(AH3_(dit)-r)*AH3_(1.0/1023.0));}
+//==============================================================================================================================
+ // This computes dither for positions 'p' and 'p+{8,0}'.
+ AH2 FsrTepdDitHx2(AU2 p,AU1 f){
+ AF2 x;
+ x.x=AF1_(p.x+f);
+ x.y=x.x+AF1_(8.0);
+ AF1 y=AF1_(p.y);
+ AF1 a=AF1_((1.0+sqrt(5.0))/2.0);
+ AF1 b=AF1_(1.0/3.69);
+ x=x*AF2_(a)+AF2_(y*b);
+ return AH2(AFractF2(x));}
+//------------------------------------------------------------------------------------------------------------------------------
+ void FsrTepdC8Hx2(inout AH2 cR,inout AH2 cG,inout AH2 cB,AH2 dit){
+ AH2 nR=sqrt(cR);
+ AH2 nG=sqrt(cG);
+ AH2 nB=sqrt(cB);
+ nR=floor(nR*AH2_(255.0))*AH2_(1.0/255.0);
+ nG=floor(nG*AH2_(255.0))*AH2_(1.0/255.0);
+ nB=floor(nB*AH2_(255.0))*AH2_(1.0/255.0);
+ AH2 aR=nR*nR;
+ AH2 aG=nG*nG;
+ AH2 aB=nB*nB;
+ AH2 bR=nR+AH2_(1.0/255.0);bR=bR*bR;
+ AH2 bG=nG+AH2_(1.0/255.0);bG=bG*bG;
+ AH2 bB=nB+AH2_(1.0/255.0);bB=bB*bB;
+ AH2 rR=(cR-bR)*APrxMedRcpH2(aR-bR);
+ AH2 rG=(cG-bG)*APrxMedRcpH2(aG-bG);
+ AH2 rB=(cB-bB)*APrxMedRcpH2(aB-bB);
+ cR=ASatH2(nR+AGtZeroH2(dit-rR)*AH2_(1.0/255.0));
+ cG=ASatH2(nG+AGtZeroH2(dit-rG)*AH2_(1.0/255.0));
+ cB=ASatH2(nB+AGtZeroH2(dit-rB)*AH2_(1.0/255.0));}
+//------------------------------------------------------------------------------------------------------------------------------
+ void FsrTepdC10Hx2(inout AH2 cR,inout AH2 cG,inout AH2 cB,AH2 dit){
+ AH2 nR=sqrt(cR);
+ AH2 nG=sqrt(cG);
+ AH2 nB=sqrt(cB);
+ nR=floor(nR*AH2_(1023.0))*AH2_(1.0/1023.0);
+ nG=floor(nG*AH2_(1023.0))*AH2_(1.0/1023.0);
+ nB=floor(nB*AH2_(1023.0))*AH2_(1.0/1023.0);
+ AH2 aR=nR*nR;
+ AH2 aG=nG*nG;
+ AH2 aB=nB*nB;
+ AH2 bR=nR+AH2_(1.0/1023.0);bR=bR*bR;
+ AH2 bG=nG+AH2_(1.0/1023.0);bG=bG*bG;
+ AH2 bB=nB+AH2_(1.0/1023.0);bB=bB*bB;
+ AH2 rR=(cR-bR)*APrxMedRcpH2(aR-bR);
+ AH2 rG=(cG-bG)*APrxMedRcpH2(aG-bG);
+ AH2 rB=(cB-bB)*APrxMedRcpH2(aB-bB);
+ cR=ASatH2(nR+AGtZeroH2(dit-rR)*AH2_(1.0/1023.0));
+ cG=ASatH2(nG+AGtZeroH2(dit-rG)*AH2_(1.0/1023.0));
+ cB=ASatH2(nB+AGtZeroH2(dit-rB)*AH2_(1.0/1023.0));}
+#endif
diff --git a/thirdparty/amd-fsr/license.txt b/thirdparty/amd-fsr/license.txt
new file mode 100644
index 0000000000..324cba594d
--- /dev/null
+++ b/thirdparty/amd-fsr/license.txt
@@ -0,0 +1,19 @@
+Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/thirdparty/embree/common/sys/platform.h b/thirdparty/embree/common/sys/platform.h
index 697e07bb86..3e386c4944 100644
--- a/thirdparty/embree/common/sys/platform.h
+++ b/thirdparty/embree/common/sys/platform.h
@@ -183,7 +183,7 @@
// #define THROW_RUNTIME_ERROR(str)
// throw std::runtime_error(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
#define THROW_RUNTIME_ERROR(str) \
- printf(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)), abort();
+ printf("%s (%d): %s", __FILE__, __LINE__, std::string(str).c_str()), abort();
// -- GODOT end --
#else
// -- GODOT start --
diff --git a/thirdparty/embree/kernels/common/rtcore.h b/thirdparty/embree/kernels/common/rtcore.h
index 373e49a689..f8aad7c7cb 100644
--- a/thirdparty/embree/kernels/common/rtcore.h
+++ b/thirdparty/embree/kernels/common/rtcore.h
@@ -126,7 +126,7 @@ namespace embree
// #define throw_RTCError(error,str) \
// throw rtcore_error(error,std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
#define throw_RTCError(error,str) \
- printf(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)), abort();
+ printf("%s (%d): %s", __FILE__, __LINE__, std::string(str).c_str()), abort();
// -- GODOT end --
#else
// -- GODOT begin --
diff --git a/thirdparty/embree/patches/godot-changes-noexcept.patch b/thirdparty/embree/patches/godot-changes-noexcept.patch
index c587a0e2be..598a7f2ddc 100644
--- a/thirdparty/embree/patches/godot-changes-noexcept.patch
+++ b/thirdparty/embree/patches/godot-changes-noexcept.patch
@@ -259,7 +259,7 @@ index 8a6d9fa0a9..697e07bb86 100644
+ // throw std::runtime_error(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
#define THROW_RUNTIME_ERROR(str) \
- throw std::runtime_error(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
-+ printf(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)), abort();
++ printf("%s (%d): %s", __FILE__, __LINE__, std::string(str).c_str()), abort();
+ // -- GODOT end --
#else
+ // -- GODOT start --
@@ -583,7 +583,7 @@ index 4e4b24e9c2..373e49a689 100644
+ // throw rtcore_error(error,std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
#define throw_RTCError(error,str) \
- throw rtcore_error(error,std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str));
-+ printf(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)), abort();
++ printf("%s (%d): %s", __FILE__, __LINE__, std::string(str).c_str()), abort();
+ // -- GODOT end --
#else
+ // -- GODOT begin --